shipment
This commit is contained in:
157
app/Http/Controllers/Admin/ShipmentController.php
Normal file
157
app/Http/Controllers/Admin/ShipmentController.php
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Admin;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use App\Models\Shipment;
|
||||||
|
use App\Models\ShipmentItem;
|
||||||
|
use App\Models\Order;
|
||||||
|
use Carbon\Carbon;
|
||||||
|
|
||||||
|
class ShipmentController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Show shipment page (Create Shipment + Shipment List)
|
||||||
|
*/
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
// 1) Get all used order IDs
|
||||||
|
$usedOrderIds = ShipmentItem::pluck('order_id')->toArray();
|
||||||
|
|
||||||
|
// 2) Load available orders (not used in any shipment)
|
||||||
|
$availableOrders = Order::whereNotIn('id', $usedOrderIds)->get();
|
||||||
|
|
||||||
|
// 3) Load all shipments for listing
|
||||||
|
$shipments = Shipment::latest()->get();
|
||||||
|
|
||||||
|
// Return your file: resources/views/admin/shipment.blade.php
|
||||||
|
return view('admin.shipments', compact('availableOrders', 'shipments'));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store new shipment
|
||||||
|
*/
|
||||||
|
public function store(Request $request)
|
||||||
|
{
|
||||||
|
$request->validate([
|
||||||
|
'origin' => 'required|string',
|
||||||
|
'destination' => 'required|string',
|
||||||
|
'shipment_date' => 'required|date',
|
||||||
|
'order_ids' => 'required|array|min:1',
|
||||||
|
]);
|
||||||
|
|
||||||
|
// -----------------------------
|
||||||
|
// PREVENT DUPLICATE ORDERS
|
||||||
|
// -----------------------------
|
||||||
|
foreach ($request->order_ids as $id) {
|
||||||
|
if (ShipmentItem::where('order_id', $id)->exists()) {
|
||||||
|
return back()->with('error', "Order ID $id is already assigned to a shipment.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------
|
||||||
|
// GENERATE UNIQUE SHIPMENT ID
|
||||||
|
// -----------------------------
|
||||||
|
$year = date('y');
|
||||||
|
$prefix = "SHIP-$year-";
|
||||||
|
|
||||||
|
$lastShipment = Shipment::latest('id')->first();
|
||||||
|
$nextNumber = $lastShipment ? intval(substr($lastShipment->shipment_id, -8)) + 1 : 1;
|
||||||
|
|
||||||
|
$newShipmentId = $prefix . str_pad($nextNumber, 8, '0', STR_PAD_LEFT);
|
||||||
|
|
||||||
|
// -----------------------------
|
||||||
|
// CALCULATE TOTALS
|
||||||
|
// -----------------------------
|
||||||
|
$orders = Order::whereIn('id', $request->order_ids)->get();
|
||||||
|
|
||||||
|
$total_ctn = $orders->sum('ctn');
|
||||||
|
$total_qty = $orders->sum('qty');
|
||||||
|
$total_ttl_qty = $orders->sum('ttl_qty');
|
||||||
|
$total_amount = $orders->sum('ttl_amount');
|
||||||
|
$total_cbm = $orders->sum('cbm');
|
||||||
|
$total_ttl_cbm = $orders->sum('ttl_cbm');
|
||||||
|
$total_kg = $orders->sum('kg');
|
||||||
|
$total_ttl_kg = $orders->sum('ttl_kg');
|
||||||
|
|
||||||
|
// -----------------------------
|
||||||
|
// CREATE SHIPMENT
|
||||||
|
//-------------------------------
|
||||||
|
$shipment = Shipment::create([
|
||||||
|
'shipment_id' => $newShipmentId,
|
||||||
|
'origin' => $request->origin,
|
||||||
|
'destination' => $request->destination,
|
||||||
|
'status' => Shipment::STATUS_PENDING,
|
||||||
|
'shipment_date' => $request->shipment_date,
|
||||||
|
|
||||||
|
'total_ctn' => $total_ctn,
|
||||||
|
'total_qty' => $total_qty,
|
||||||
|
'total_ttl_qty' => $total_ttl_qty,
|
||||||
|
'total_amount' => $total_amount,
|
||||||
|
'total_cbm' => $total_cbm,
|
||||||
|
'total_ttl_cbm' => $total_ttl_cbm,
|
||||||
|
'total_kg' => $total_kg,
|
||||||
|
'total_ttl_kg' => $total_ttl_kg,
|
||||||
|
]);
|
||||||
|
|
||||||
|
// -----------------------------
|
||||||
|
// INSERT SHIPMENT ITEMS
|
||||||
|
// -----------------------------
|
||||||
|
foreach ($orders as $order) {
|
||||||
|
ShipmentItem::create([
|
||||||
|
'shipment_id' => $shipment->id,
|
||||||
|
'order_id' => $order->id,
|
||||||
|
'order_ctn' => $order->ctn,
|
||||||
|
'order_qty' => $order->qty,
|
||||||
|
'order_ttl_qty' => $order->ttl_qty,
|
||||||
|
'order_ttl_amount' => $order->ttl_amount,
|
||||||
|
'order_ttl_kg' => $order->ttl_kg,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect()->back()->with('success', "Shipment $newShipmentId created successfully!");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show shipment details (for modal popup)
|
||||||
|
*/
|
||||||
|
public function show($id)
|
||||||
|
{
|
||||||
|
$shipment = Shipment::findOrFail($id);
|
||||||
|
|
||||||
|
// Load full order data from orders table
|
||||||
|
$orders = Order::whereIn('id',
|
||||||
|
ShipmentItem::where('shipment_id', $id)->pluck('order_id')
|
||||||
|
)->get();
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'shipment' => $shipment,
|
||||||
|
'orders' => $orders
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update Shipment status from action button
|
||||||
|
*/
|
||||||
|
public function updateStatus(Request $request)
|
||||||
|
{
|
||||||
|
$request->validate([
|
||||||
|
'shipment_id' => 'required|exists:shipments,id',
|
||||||
|
'status' => 'required|string'
|
||||||
|
]);
|
||||||
|
|
||||||
|
$shipment = Shipment::findOrFail($request->shipment_id);
|
||||||
|
$shipment->status = $request->status;
|
||||||
|
$shipment->save();
|
||||||
|
|
||||||
|
return redirect()->back()->with('success', "Shipment status updated to {$shipment->statusLabel()}");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
80
app/Models/Shipment.php
Normal file
80
app/Models/Shipment.php
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class Shipment extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'shipment_id',
|
||||||
|
'origin',
|
||||||
|
'destination',
|
||||||
|
'total_ctn',
|
||||||
|
'total_qty',
|
||||||
|
'total_ttl_qty',
|
||||||
|
'total_amount',
|
||||||
|
'total_cbm',
|
||||||
|
'total_ttl_cbm',
|
||||||
|
'total_kg',
|
||||||
|
'total_ttl_kg',
|
||||||
|
'status',
|
||||||
|
'shipment_date',
|
||||||
|
'meta',
|
||||||
|
];
|
||||||
|
|
||||||
|
protected $casts = [
|
||||||
|
'meta' => 'array',
|
||||||
|
'shipment_date' => 'date',
|
||||||
|
];
|
||||||
|
|
||||||
|
// ---------------------------
|
||||||
|
// RELATIONSHIPS
|
||||||
|
// ---------------------------
|
||||||
|
|
||||||
|
public function items()
|
||||||
|
{
|
||||||
|
return $this->hasMany(ShipmentItem::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function orders()
|
||||||
|
{
|
||||||
|
return $this->belongsToMany(Order::class, 'shipment_items', 'shipment_id', 'order_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------
|
||||||
|
// STATUS CONSTANTS
|
||||||
|
// ---------------------------
|
||||||
|
|
||||||
|
const STATUS_PENDING = 'pending';
|
||||||
|
const STATUS_IN_TRANSIT = 'in_transit';
|
||||||
|
const STATUS_DISPATCHED = 'dispatched';
|
||||||
|
const STATUS_DELIVERED = 'delivered';
|
||||||
|
|
||||||
|
public static function statusOptions()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
self::STATUS_PENDING => 'Pending',
|
||||||
|
self::STATUS_IN_TRANSIT => 'In Transit',
|
||||||
|
self::STATUS_DISPATCHED => 'Dispatched',
|
||||||
|
self::STATUS_DELIVERED => 'Delivered',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------
|
||||||
|
// HELPERS
|
||||||
|
// ---------------------------
|
||||||
|
|
||||||
|
public function totalOrdersCount()
|
||||||
|
{
|
||||||
|
return $this->items()->count();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function statusLabel()
|
||||||
|
{
|
||||||
|
return self::statusOptions()[$this->status] ?? ucfirst($this->status);
|
||||||
|
}
|
||||||
|
}
|
||||||
46
app/Models/ShipmentItem.php
Normal file
46
app/Models/ShipmentItem.php
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class ShipmentItem extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'shipment_id',
|
||||||
|
'order_id',
|
||||||
|
'order_ctn',
|
||||||
|
'order_qty',
|
||||||
|
'order_ttl_qty',
|
||||||
|
'order_ttl_amount',
|
||||||
|
'order_ttl_kg',
|
||||||
|
];
|
||||||
|
|
||||||
|
// ---------------------------
|
||||||
|
// RELATIONSHIPS
|
||||||
|
// ---------------------------
|
||||||
|
|
||||||
|
public function shipment()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Shipment::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function order()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Order::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper: return order data with fallback to snapshot
|
||||||
|
public function getDisplayQty()
|
||||||
|
{
|
||||||
|
return $this->order->qty ?? $this->order_qty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDisplayAmount()
|
||||||
|
{
|
||||||
|
return $this->order->ttl_amount ?? $this->order_ttl_amount;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
class CreateShipmentsTable extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::create('shipments', function (Blueprint $table) {
|
||||||
|
$table->bigIncrements('id');
|
||||||
|
|
||||||
|
// Human-friendly auto-generated shipment id (e.g. SHIP-25-00000001)
|
||||||
|
$table->string('shipment_id')->unique();
|
||||||
|
|
||||||
|
// Basic details
|
||||||
|
$table->string('origin')->nullable();
|
||||||
|
$table->string('destination')->nullable();
|
||||||
|
|
||||||
|
// Totals (calculated when creating shipment)
|
||||||
|
$table->integer('total_ctn')->default(0)->comment('sum of CTN of selected orders');
|
||||||
|
$table->integer('total_qty')->default(0)->comment('sum of qty of selected orders');
|
||||||
|
$table->integer('total_ttl_qty')->default(0)->comment('sum of ttl_qty of selected orders');
|
||||||
|
$table->decimal('total_amount', 16, 2)->default(0.00)->comment('sum of ttl_amount of selected orders');
|
||||||
|
$table->decimal('total_cbm', 14, 3)->default(0.000)->comment('sum cbm');
|
||||||
|
$table->decimal('total_ttl_cbm', 14, 3)->default(0.000)->comment('sum ttl cbm');
|
||||||
|
$table->decimal('total_kg', 14, 3)->default(0.000)->comment('sum kg');
|
||||||
|
$table->decimal('total_ttl_kg', 14, 3)->default(0.000)->comment('sum ttl kg');
|
||||||
|
|
||||||
|
// status: pending (default), in_transit, dispatched, delivered, cancelled, etc.
|
||||||
|
$table->string('status')->default('pending');
|
||||||
|
|
||||||
|
// shipment date (admin can change)
|
||||||
|
$table->date('shipment_date')->nullable();
|
||||||
|
|
||||||
|
// optional meta (vehicle, driver etc)
|
||||||
|
$table->json('meta')->nullable();
|
||||||
|
|
||||||
|
$table->timestamps();
|
||||||
|
|
||||||
|
// Indexes for fast filtering
|
||||||
|
$table->index('shipment_id');
|
||||||
|
$table->index('status');
|
||||||
|
$table->index('shipment_date');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('shipments');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
class CreateShipmentItemsTable extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::create('shipment_items', function (Blueprint $table) {
|
||||||
|
$table->bigIncrements('id');
|
||||||
|
|
||||||
|
// Link to shipments
|
||||||
|
$table->foreignId('shipment_id')->constrained('shipments')->onDelete('cascade');
|
||||||
|
|
||||||
|
// Link to orders. assuming orders.id is bigIncrements
|
||||||
|
$table->foreignId('order_id')->constrained('orders')->onDelete('restrict');
|
||||||
|
|
||||||
|
// Snapshots (optional) — store basic order totals at time of assignment
|
||||||
|
$table->integer('order_ctn')->nullable()->default(0);
|
||||||
|
$table->integer('order_qty')->nullable()->default(0);
|
||||||
|
$table->integer('order_ttl_qty')->nullable()->default(0);
|
||||||
|
$table->decimal('order_ttl_amount', 16, 2)->nullable()->default(0.00);
|
||||||
|
$table->decimal('order_ttl_kg', 14, 3)->nullable()->default(0.000);
|
||||||
|
|
||||||
|
$table->timestamps();
|
||||||
|
|
||||||
|
// Prevent duplicate assignment of same order to the same shipment
|
||||||
|
$table->unique(['shipment_id', 'order_id']);
|
||||||
|
|
||||||
|
// We will check order_id uniqueness across shipments in app logic (see below)
|
||||||
|
$table->index('order_id');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('shipment_items');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,12 +1,320 @@
|
|||||||
@extends('admin.layouts.app')
|
@extends('admin.layouts.app')
|
||||||
|
|
||||||
@section('page-title', 'Dashboard')
|
@section('page-title', 'Shipment Management')
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
<div class="card shadow-sm">
|
|
||||||
<div class="card-body">
|
<div class="container-fluid py-4">
|
||||||
<h4>Welcome to the Admin shipment</h4>
|
|
||||||
<p>Here you can manage all system modules.</p>
|
{{-- SUCCESS / ERROR MESSAGES --}}
|
||||||
</div>
|
@if(session('success'))
|
||||||
|
<div class="alert alert-success">{{ session('success') }}</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
@if(session('error'))
|
||||||
|
<div class="alert alert-danger">{{ session('error') }}</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
|
||||||
|
<!-- ============================= -->
|
||||||
|
<!-- CREATE SHIPMENT BOX -->
|
||||||
|
<!-- ============================= -->
|
||||||
|
<div class="card shadow-sm mb-4">
|
||||||
|
<div class="card-header bg-light">
|
||||||
|
<h5 class="mb-0">
|
||||||
|
<i class="bi bi-truck"></i> Create Shipment
|
||||||
|
</h5>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card-body">
|
||||||
|
|
||||||
|
<form action="{{ route('admin.shipments.store') }}" method="POST">
|
||||||
|
@csrf
|
||||||
|
|
||||||
|
<div class="row g-3">
|
||||||
|
|
||||||
|
<div class="col-md-4">
|
||||||
|
<label class="form-label">Origin</label>
|
||||||
|
<input type="text" class="form-control" name="origin" required>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-4">
|
||||||
|
<label class="form-label">Destination</label>
|
||||||
|
<input type="text" class="form-control" name="destination" required>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-4">
|
||||||
|
<label class="form-label">Shipment Date</label>
|
||||||
|
<input type="date" name="shipment_date" class="form-control"
|
||||||
|
value="{{ date('Y-m-d') }}" required>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr class="my-3">
|
||||||
|
|
||||||
|
<h6 class="fw-bold text-primary mb-2">Select Orders for Shipment</h6>
|
||||||
|
|
||||||
|
{{-- Orders Table --}}
|
||||||
|
<div class="table-responsive" style="max-height: 350px; overflow-y:auto;">
|
||||||
|
<table class="table table-bordered table-striped text-center align-middle">
|
||||||
|
<thead class="table-light">
|
||||||
|
<tr>
|
||||||
|
<th>Select</th>
|
||||||
|
<th>Order ID</th>
|
||||||
|
<th>Mark No</th>
|
||||||
|
<th>Origin</th>
|
||||||
|
<th>Destination</th>
|
||||||
|
<th>CTN</th>
|
||||||
|
<th>QTY</th>
|
||||||
|
<th>TTL Qty</th>
|
||||||
|
<th>Amount</th>
|
||||||
|
<th>KG</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
@forelse($availableOrders as $order)
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<input type="checkbox" name="order_ids[]" value="{{ $order->id }}">
|
||||||
|
</td>
|
||||||
|
<td class="text-primary fw-bold">{{ $order->order_id }}</td>
|
||||||
|
<td>{{ $order->mark_no }}</td>
|
||||||
|
<td>{{ $order->origin }}</td>
|
||||||
|
<td>{{ $order->destination }}</td>
|
||||||
|
<td>{{ $order->ctn }}</td>
|
||||||
|
<td>{{ $order->qty }}</td>
|
||||||
|
<td>{{ $order->ttl_qty }}</td>
|
||||||
|
<td>₹{{ number_format($order->ttl_amount, 2) }}</td>
|
||||||
|
<td>{{ $order->ttl_kg }}</td>
|
||||||
|
</tr>
|
||||||
|
@empty
|
||||||
|
<tr>
|
||||||
|
<td colspan="10" class="text-muted">No available orders</td>
|
||||||
|
</tr>
|
||||||
|
@endforelse
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="text-end mt-3">
|
||||||
|
<button type="submit" class="btn btn-success btn-lg">
|
||||||
|
<i class="bi bi-check-circle"></i> Create Shipment
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- ============================= -->
|
||||||
|
<!-- SHIPMENT LIST TABLE -->
|
||||||
|
<!-- ============================= -->
|
||||||
|
<div class="card shadow-sm">
|
||||||
|
<div class="card-header bg-light">
|
||||||
|
<h5 class="mb-0"><i class="bi bi-table"></i> Shipments List</h5>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card-body table-responsive">
|
||||||
|
<table class="table table-striped table-bordered text-center align-middle">
|
||||||
|
<thead class="table-light">
|
||||||
|
<tr>
|
||||||
|
<th>#</th>
|
||||||
|
<th>Shipment ID</th>
|
||||||
|
<th>Origin</th>
|
||||||
|
<th>Destination</th>
|
||||||
|
|
||||||
|
<th>Total QTY</th>
|
||||||
|
<th>Total KG</th>
|
||||||
|
<th>Total Amount</th>
|
||||||
|
|
||||||
|
<th>Status</th>
|
||||||
|
<th>Date</th>
|
||||||
|
<th>Action</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
|
||||||
|
<tbody>
|
||||||
|
@forelse($shipments as $ship)
|
||||||
|
<tr>
|
||||||
|
<td>{{ $ship->id }}</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<a href="#" class="text-primary fw-bold"
|
||||||
|
onclick="openShipmentDetails({{ $ship->id }})">
|
||||||
|
{{ $ship->shipment_id }}
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>{{ $ship->origin }}</td>
|
||||||
|
<td>{{ $ship->destination }}</td>
|
||||||
|
|
||||||
|
<td>{{ $ship->total_qty }}</td>
|
||||||
|
<td>{{ $ship->total_kg }}</td>
|
||||||
|
<td>₹{{ number_format($ship->total_amount, 2) }}</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<span class="badge bg-info text-dark">{{ ucfirst($ship->status) }}</span>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>{{ $ship->shipment_date }}</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<form action="{{ route('admin.shipments.updateStatus') }}" method="POST" class="d-inline">
|
||||||
|
@csrf
|
||||||
|
<input type="hidden" name="shipment_id" value="{{ $ship->id }}">
|
||||||
|
|
||||||
|
<select name="status" class="form-select form-select-sm"
|
||||||
|
onchange="this.form.submit()">
|
||||||
|
<option value="pending" @selected($ship->status=='pending')>Pending</option>
|
||||||
|
<option value="in_transit" @selected($ship->status=='in_transit')>In Transit</option>
|
||||||
|
<option value="dispatched" @selected($ship->status=='dispatched')>Dispatched</option>
|
||||||
|
<option value="delivered" @selected($ship->status=='delivered')>Delivered</option>
|
||||||
|
</select>
|
||||||
|
</form>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
</tr>
|
||||||
|
@empty
|
||||||
|
<tr>
|
||||||
|
<td colspan="10" class="text-muted">No shipments found</td>
|
||||||
|
</tr>
|
||||||
|
@endforelse
|
||||||
|
</tbody>
|
||||||
|
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- ============================= -->
|
||||||
|
<!-- SHIPMENT DETAILS MODAL -->
|
||||||
|
<!-- ============================= -->
|
||||||
|
<div class="modal fade" id="shipmentDetailsModal" tabindex="-1">
|
||||||
|
<div class="modal-dialog modal-xl modal-dialog-scrollable">
|
||||||
|
<div class="modal-content">
|
||||||
|
|
||||||
|
<div class="modal-header bg-light">
|
||||||
|
<h5 class="modal-title fw-bold">Shipment Details</h5>
|
||||||
|
<button class="btn-close" data-bs-dismiss="modal"></button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="modal-body" id="shipmentDetailsContent">
|
||||||
|
<p class="text-center text-muted">Loading...</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- ========================= -->
|
||||||
|
<!-- MODAL LOAD SCRIPT (AJAX) -->
|
||||||
|
<!-- ========================= -->
|
||||||
|
<script>
|
||||||
|
function openShipmentDetails(id) {
|
||||||
|
let modal = new bootstrap.Modal(document.getElementById('shipmentDetailsModal'));
|
||||||
|
document.getElementById('shipmentDetailsContent').innerHTML =
|
||||||
|
"<p class='text-center text-muted'>Loading...</p>";
|
||||||
|
|
||||||
|
fetch(`/admin/shipments/${id}`)
|
||||||
|
.then(res => res.json())
|
||||||
|
.then(data => {
|
||||||
|
|
||||||
|
let html = `
|
||||||
|
<h5 class="text-primary mb-3">Shipment: ${data.shipment.shipment_id}</h5>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<strong>Origin:</strong> ${data.shipment.origin}
|
||||||
|
<strong>Destination:</strong> ${data.shipment.destination}
|
||||||
|
<strong>Status:</strong> ${data.shipment.status}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h6 class="fw-bold mt-4">Orders Inside Shipment</h6>
|
||||||
|
|
||||||
|
<table class="table table-bordered text-center">
|
||||||
|
<thead class="table-light">
|
||||||
|
<tr>
|
||||||
|
<th>Order ID</th>
|
||||||
|
<th>Mark No</th>
|
||||||
|
<th>Origin</th>
|
||||||
|
<th>Destination</th>
|
||||||
|
|
||||||
|
<th>CTN</th>
|
||||||
|
<th>QTY</th>
|
||||||
|
<th>TTL QTY</th>
|
||||||
|
|
||||||
|
<th>TTL Amount</th>
|
||||||
|
|
||||||
|
<th>CBM</th>
|
||||||
|
<th>TTL CBM</th>
|
||||||
|
|
||||||
|
<th>KG</th>
|
||||||
|
<th>TTL KG</th>
|
||||||
|
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
`;
|
||||||
|
|
||||||
|
data.orders.forEach(order => {
|
||||||
|
html += `
|
||||||
|
<tr>
|
||||||
|
<td class="fw-bold text-primary">${order.order_id}</td>
|
||||||
|
<td>${order.mark_no}</td>
|
||||||
|
<td>${order.origin}</td>
|
||||||
|
<td>${order.destination}</td>
|
||||||
|
|
||||||
|
<td>${order.ctn}</td>
|
||||||
|
<td>${order.qty}</td>
|
||||||
|
<td>${order.ttl_qty}</td>
|
||||||
|
|
||||||
|
<td>₹${order.ttl_amount}</td>
|
||||||
|
|
||||||
|
<td>${order.cbm ?? '-'}</td>
|
||||||
|
<td>${order.ttl_cbm ?? '-'}</td>
|
||||||
|
|
||||||
|
<td>${order.kg}</td>
|
||||||
|
<td>${order.ttl_kg}</td>
|
||||||
|
|
||||||
|
</tr>
|
||||||
|
`;
|
||||||
|
});
|
||||||
|
|
||||||
|
html += `
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<div class="mt-3">
|
||||||
|
<strong>Total CTN:</strong> ${data.shipment.total_ctn} <br>
|
||||||
|
<strong>Total QTY:</strong> ${data.shipment.total_qty} <br>
|
||||||
|
<strong>Total TTL QTY:</strong> ${data.shipment.total_ttl_qty} <br>
|
||||||
|
|
||||||
|
<strong>Total CBM:</strong> ${data.shipment.total_cbm} <br>
|
||||||
|
<strong>Total TTL CBM:</strong> ${data.shipment.total_ttl_cbm} <br>
|
||||||
|
|
||||||
|
<strong>Total KG:</strong> ${data.shipment.total_kg} <br>
|
||||||
|
<strong>Total TTL KG:</strong> ${data.shipment.total_ttl_kg} <br>
|
||||||
|
|
||||||
|
<strong>Total Amount:</strong> ₹${data.shipment.total_amount}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
document.getElementById('shipmentDetailsContent').innerHTML = html;
|
||||||
|
});
|
||||||
|
|
||||||
|
modal.show();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
@endsection
|
@endsection
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ use App\Http\Controllers\Admin\AdminAuthController;
|
|||||||
use App\Http\Controllers\Admin\UserRequestController;
|
use App\Http\Controllers\Admin\UserRequestController;
|
||||||
use App\Http\Controllers\Admin\AdminMarkListController;
|
use App\Http\Controllers\Admin\AdminMarkListController;
|
||||||
use App\Http\Controllers\Admin\AdminOrderController;
|
use App\Http\Controllers\Admin\AdminOrderController;
|
||||||
|
use App\Http\Controllers\Admin\ShipmentController;
|
||||||
|
|
||||||
// -------------------------
|
// -------------------------
|
||||||
// Default Front Page
|
// Default Front Page
|
||||||
@@ -29,7 +30,7 @@ Route::prefix('admin')->middleware('auth:admin')->group(function () {
|
|||||||
// Dashboard Pages
|
// Dashboard Pages
|
||||||
// Route::get('/dashboard', fn() => view('admin.dashboard'))->name('admin.dashboard');
|
// Route::get('/dashboard', fn() => view('admin.dashboard'))->name('admin.dashboard');
|
||||||
Route::get('/dashboard', [AdminOrderController::class, 'index'])->name('admin.dashboard');
|
Route::get('/dashboard', [AdminOrderController::class, 'index'])->name('admin.dashboard');
|
||||||
Route::get('/shipments', fn() => view('admin.shipments'))->name('admin.shipments');
|
//Route::get('/shipments', fn() => view('admin.shipments'))->name('admin.shipments');
|
||||||
Route::get('/invoice', fn() => view('admin.invoice'))->name('admin.invoice');
|
Route::get('/invoice', fn() => view('admin.invoice'))->name('admin.invoice');
|
||||||
Route::get('/customers', fn() => view('admin.customers'))->name('admin.customers');
|
Route::get('/customers', fn() => view('admin.customers'))->name('admin.customers');
|
||||||
Route::get('/reports', fn() => view('admin.reports'))->name('admin.reports');
|
Route::get('/reports', fn() => view('admin.reports'))->name('admin.reports');
|
||||||
@@ -77,4 +78,16 @@ Route::prefix('admin')->middleware('auth:admin')->group(function () {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Route::get('/shipments', [ShipmentController::class, 'index'])
|
||||||
|
->name('admin.shipments');
|
||||||
|
|
||||||
|
Route::post('/shipments/store', [ShipmentController::class, 'store'])
|
||||||
|
->name('admin.shipments.store');
|
||||||
|
|
||||||
|
Route::post('/shipments/update-status', [ShipmentController::class, 'updateStatus'])
|
||||||
|
->name('admin.shipments.updateStatus');
|
||||||
|
|
||||||
|
Route::get('/shipments/{id}', [ShipmentController::class, 'show'])
|
||||||
|
->name('admin.shipments.show');
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user