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') + + +
-
-

Welcome to the Admin customer page

-

Here you can manage all system modules.

-
+
+ +

Customer List

+ + {{-- SEARCH + STATUS FILTER ROW --}} +
+ + {{-- SEARCH BAR --}} +
+ + + + {{-- Preserve status on search --}} + @if(!empty($status)) + + @endif + + +
+ + {{-- STATUS FILTER --}} +
+ + Active + + + + Inactive + + + + All + +
+
+ +
+

Customer List

+ + Add Customer + +
+ + + {{-- TABLE --}} +
+ + + + + + + + + + + + + + @forelse($customers as $c) + + + {{-- CUSTOMER INFO --}} + + + {{-- CUSTOMER ID --}} + + + {{-- CREATED DATE --}} + + + {{-- STATUS --}} + + + {{-- ACTION BUTTONS --}} + + + + @empty + + + + @endforelse + + +
Customer InfoCustomer IDCreate DateStatusActions
+
+ + {{-- 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 +
+
+ +
+
{{ $c->customer_id }}{{ $c->created_at ? $c->created_at->format('d-m-Y') : '-' }} + @if($c->status === 'active') + Active + @else + Inactive + @endif + + + {{-- VIEW --}} + + + + + {{-- TOGGLE STATUS --}} +
+ @csrf + +
+ +
+ No customers found. +
+
+ +
+ @endsection diff --git a/resources/views/admin/customers_add.blade.php b/resources/views/admin/customers_add.blade.php new file mode 100644 index 0000000..880c33f --- /dev/null +++ b/resources/views/admin/customers_add.blade.php @@ -0,0 +1,95 @@ +@extends('admin.layouts.app') + +@section('page-title', 'Add Customer') + +@section('content') + +
+ +
+
+ Add New Customer +
+ +
+ +
+ @csrf + +
+ + {{-- CUSTOMER NAME --}} +
+ + +
+ + {{-- COMPANY NAME --}} +
+ + +
+ + {{-- DESIGNATION --}} +
+ + +
+ + {{-- EMAIL --}} +
+ + +
+ + {{-- MOBILE --}} +
+ + +
+ + {{-- PINCODE --}} +
+ + +
+ + {{-- ADDRESS --}} +
+ + +
+ + {{-- CUSTOMER TYPE --}} +
+ + +
+ + {{-- STATUS --}} +
+ + +
+ +
+ +
+ Cancel + +
+ +
+ +
+
+ +
+ +@endsection diff --git a/resources/views/admin/customers_view.blade.php b/resources/views/admin/customers_view.blade.php new file mode 100644 index 0000000..3315842 --- /dev/null +++ b/resources/views/admin/customers_view.blade.php @@ -0,0 +1,179 @@ +@extends('admin.layouts.app') + +@section('page-title', 'Customer Details') + +@section('content') + +
+ + {{-- HEADER --}} +
+

Customer Details

+ + Back + +
+ + {{-- CUSTOMER CARD --}} +
+
+ +
+ + {{-- Avatar --}} +
+ {{ strtoupper(substr($customer->customer_name,0,1)) }} +
+ +
+

{{ $customer->customer_name }}

+
{{ $customer->company_name }}
+ + {{-- Customer Type --}} + @if($customer->customer_type == 'premium') + Premium Customer + @else + Regular Customer + @endif +
+ +
+ {{-- Status --}} + @if($customer->status == 'active') + Active + @else + Inactive + @endif +
+ +
+ + {{-- BASIC INFO --}} +
+ +
+
+
Contact Information
+

Email: {{ $customer->email }}

+

Mobile: {{ $customer->mobile_no }}

+

Address: {{ $customer->address }}

+

Pincode: {{ $customer->pincode }}

+
+ +
+
Account Information
+

Customer ID: {{ $customer->customer_id }}

+

Registered On: + {{ $customer->created_at ? $customer->created_at->format('d-m-Y') : '-' }} +

+

Designation: + {{ $customer->designation ?? 'N/A' }}

+
+
+ +
+
+ + {{-- STATISTICS --}} +
+ + {{-- Total Orders --}} +
+
+
+
{{ $totalOrders }}
+

Total Orders

+
+
+
+ + {{-- Total Amount --}} +
+
+
+
₹{{ number_format($totalAmount, 2) }}
+

Total Amount Spent

+
+
+
+ + {{-- Mark Count --}} +
+
+
+
{{ $customer->marks->count() }}
+

Total Mark Numbers

+
+
+
+ +
+ + {{-- MARK LIST --}} +
+
+ Customer Mark Numbers +
+
+ @if($customer->marks->count() == 0) +

No mark numbers found.

+ @else +
    + @foreach($customer->marks as $mark) +
  • + {{ $mark->mark_no }} + ({{ $mark->origin }} → {{ $mark->destination }}) +
  • + @endforeach +
+ @endif +
+
+ + + +
+ +@endsection diff --git a/resources/views/admin/layouts/app.blade.php b/resources/views/admin/layouts/app.blade.php index 77a67ae..2bef871 100644 --- a/resources/views/admin/layouts/app.blade.php +++ b/resources/views/admin/layouts/app.blade.php @@ -181,7 +181,12 @@ Invoice - Customers + + Customers + + + Reports Chat Support