diff --git a/app/Http/Controllers/Admin/AdminCustomerController.php b/app/Http/Controllers/Admin/AdminCustomerController.php new file mode 100644 index 0000000..393db9a --- /dev/null +++ b/app/Http/Controllers/Admin/AdminCustomerController.php @@ -0,0 +1,134 @@ +search; + $status = $request->status; + + $query = User::with(['marks', 'orders'])->orderBy('id', 'desc'); + + // SEARCH FILTER + if (!empty($search)) { + $query->where(function ($q) use ($search) { + $q->where('customer_name', 'like', "%$search%") + ->orWhere('email', 'like', "%$search%") + ->orWhere('mobile_no', 'like', "%$search%") + ->orWhere('customer_id', 'like', "%$search%"); + }); + } + + // STATUS FILTER + if (!empty($status) && in_array($status, ['active', 'inactive'])) { + $query->where('status', $status); + } + + $customers = $query->get(); + + return view('admin.customers', compact('customers', 'search', 'status')); + } + + // --------------------------------------------------------- + // SHOW ADD CUSTOMER FORM + // --------------------------------------------------------- + public function create() + { + return view('admin.customers_add'); + } + + // --------------------------------------------------------- + // STORE NEW CUSTOMER + // --------------------------------------------------------- + public function store(Request $request) + { + $request->validate([ + 'customer_name' => 'required|string|max:255', + 'company_name' => 'nullable|string|max:255', + 'designation' => 'nullable|string|max:255', + 'email' => 'required|email|unique:users,email', + 'mobile_no' => 'required|string|max:20', + 'address' => 'nullable|string', + 'pincode' => 'nullable|string|max:10', + 'customer_type' => 'required|in:regular,premium', + 'status' => 'required|in:active,inactive', + ]); + + // AUTO GENERATE CUSTOMER ID + $year = date('Y'); + $prefix = "CID-$year-"; + + $lastCustomer = User::whereYear('created_at', $year) + ->orderBy('id', 'DESC') + ->first(); + + $next = $lastCustomer ? intval(substr($lastCustomer->customer_id, -6)) + 1 : 1; + $customerId = $prefix . str_pad($next, 6, '0', STR_PAD_LEFT); + + // CREATE CUSTOMER + User::create([ + 'customer_id' => $customerId, + 'customer_name' => $request->customer_name, + 'company_name' => $request->company_name, + 'designation' => $request->designation, + 'email' => $request->email, + 'mobile_no' => $request->mobile_no, + 'address' => $request->address, + 'pincode' => $request->pincode, + 'date' => date('Y-m-d'), + 'customer_type' => $request->customer_type, + 'status' => $request->status, + 'password' => Hash::make('123456'), // DEFAULT PASSWORD + ]); + + return redirect() + ->route('admin.customers.index') + ->with('success', 'Customer added successfully!'); + } + + // --------------------------------------------------------- + // VIEW CUSTOMER FULL DETAILS + // --------------------------------------------------------- + public function view($id) + { + $customer = User::with(['marks', 'orders'])->findOrFail($id); + + $totalOrders = $customer->orders->count(); + $totalAmount = $customer->orders->sum('ttl_amount'); + $recentOrders = $customer->orders()->latest()->take(5)->get(); + + return view('admin.customers_view', compact( + 'customer', + 'totalOrders', + 'totalAmount', + 'recentOrders' + )); + } + + // --------------------------------------------------------- + // TOGGLE STATUS ACTIVE / INACTIVE + // --------------------------------------------------------- + public function toggleStatus($id) + { + $customer = User::findOrFail($id); + + $customer->status = $customer->status === 'active' + ? 'inactive' + : 'active'; + + $customer->save(); + + return back()->with('success', 'Customer status updated.'); + } + +} diff --git a/app/Models/User.php b/app/Models/User.php index d9f952d..b5df7a5 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -15,7 +15,7 @@ class User extends Authenticatable implements JWTSubject * The attributes that are mass assignable. */ protected $fillable = [ - 'customer_id', // CID-2025-000001 format + 'customer_id', 'customer_name', 'company_name', 'designation', @@ -25,10 +25,15 @@ class User extends Authenticatable implements JWTSubject 'pincode', 'date', 'password', + + // newly added customer fields + 'status', // active / inactive + 'customer_type', // premium / regular + 'profile_image', // optional image ]; /** - * The attributes that should be hidden for arrays. + * Attributes that should be hidden. */ protected $hidden = [ 'password', @@ -36,7 +41,7 @@ class User extends Authenticatable implements JWTSubject ]; /** - * The attributes that should be cast. + * Attribute casting. */ protected function casts(): array { @@ -47,7 +52,30 @@ class User extends Authenticatable implements JWTSubject } /** - * JWT Identifier. + * Relationship: User → MarkList (Many) + */ + public function marks() + { + return $this->hasMany(\App\Models\MarkList::class, 'customer_id', 'customer_id'); + } + + /** + * Relationship: User → Orders (Through MarkList) + */ + public function orders() + { + return $this->hasManyThrough( + \App\Models\Order::class, + \App\Models\MarkList::class, + 'customer_id', // MarkList.customer_id + 'mark_no', // Orders.mark_no + 'customer_id', // Users.customer_id + 'mark_no' // MarkList.mark_no + ); + } + + /** + * JWT Identifier */ public function getJWTIdentifier() { @@ -55,7 +83,7 @@ class User extends Authenticatable implements JWTSubject } /** - * JWT Custom Claims. + * JWT Custom Claims */ public function getJWTCustomClaims() { diff --git a/database/migrations/2025_11_17_071001_add_customer_fields_to_users_table.php b/database/migrations/2025_11_17_071001_add_customer_fields_to_users_table.php new file mode 100644 index 0000000..574464e --- /dev/null +++ b/database/migrations/2025_11_17_071001_add_customer_fields_to_users_table.php @@ -0,0 +1,31 @@ +enum('status', ['active', 'inactive'])->default('active')->after('pincode'); + + // premium / regular + $table->enum('customer_type', ['regular', 'premium'])->default('regular')->after('status'); + + // optional: profile image path + $table->string('profile_image')->nullable()->after('customer_type'); + }); + } + + public function down() + { + Schema::table('users', function (Blueprint $table) { + $table->dropColumn(['status', 'customer_type', 'profile_image']); + }); + } + +}; diff --git a/public/invoices/invoice-INV-2025-000001.pdf b/public/invoices/invoice-INV-2025-000001.pdf new file mode 100644 index 0000000..0a39663 Binary files /dev/null and b/public/invoices/invoice-INV-2025-000001.pdf differ diff --git a/public/invoices/invoice-INV-2025-000004.pdf b/public/invoices/invoice-INV-2025-000004.pdf new file mode 100644 index 0000000..c14d51b Binary files /dev/null and b/public/invoices/invoice-INV-2025-000004.pdf differ diff --git a/resources/views/admin/customers.blade.php b/resources/views/admin/customers.blade.php index 127e252..98935c4 100644 --- a/resources/views/admin/customers.blade.php +++ b/resources/views/admin/customers.blade.php @@ -1,12 +1,176 @@ @extends('admin.layouts.app') -@section('page-title', 'Dashboard') +@section('page-title', 'Customers') @section('content') + + +
Here you can manage all system modules.
-| Customer Info | +Customer ID | +Create Date | +Status | +Actions | +
|---|---|---|---|---|
|
+
+
+ {{-- Avatar --}}
+
+
+ {{ strtoupper(substr($c->customer_name,0,1)) }}
+
+
+
+ {{ $c->customer_name }}
+
+ + + {{-- Customer Type --}} + @if($c->customer_type == 'premium') + Premium Customer + @else + Regular Customer + @endif + + {{ $c->email }}
+ {{ $c->mobile_no }}
+
+ {{ $c->orders->count() }} orders
+
+ ₹{{ number_format($c->orders->sum('ttl_amount'), 2) }} total
+
+ |
+
+ {{-- CUSTOMER ID --}}
+ {{ $c->customer_id }} | + + {{-- CREATED DATE --}} +{{ $c->created_at ? $c->created_at->format('d-m-Y') : '-' }} | + + {{-- STATUS --}} ++ @if($c->status === 'active') + Active + @else + Inactive + @endif + | + + {{-- ACTION BUTTONS --}} ++ + {{-- VIEW --}} + + + + + {{-- TOGGLE STATUS --}} + + + | + +
| + No customers found. + | +||||
Email: {{ $customer->email }}
+Mobile: {{ $customer->mobile_no }}
+Address: {{ $customer->address }}
+Pincode: {{ $customer->pincode }}
+Customer ID: {{ $customer->customer_id }}
+Registered On: + {{ $customer->created_at ? $customer->created_at->format('d-m-Y') : '-' }} +
+Designation: + {{ $customer->designation ?? 'N/A' }}
+Total Orders
+Total Amount Spent
+Total Mark Numbers
+No mark numbers found.
+ @else +