Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
3.47% covered (danger)
3.47%
5 / 144
10.00% covered (danger)
10.00%
1 / 10
CRAP
0.00% covered (danger)
0.00%
0 / 1
VendorController
3.47% covered (danger)
3.47%
5 / 144
10.00% covered (danger)
10.00%
1 / 10
309.41
0.00% covered (danger)
0.00%
0 / 1
 index
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 create
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 store
0.00% covered (danger)
0.00%
0 / 60
0.00% covered (danger)
0.00%
0 / 1
20
 show
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 edit
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 update
0.00% covered (danger)
0.00%
0 / 25
0.00% covered (danger)
0.00%
0 / 1
12
 destroy
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 applications
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 approveApplication
0.00% covered (danger)
0.00%
0 / 36
0.00% covered (danger)
0.00%
0 / 1
20
 rejectApplication
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3namespace App\Http\Controllers\admin;
4
5use App\Http\Controllers\Controller;
6use App\Models\Vendor;
7use App\Models\VendorApplication;
8use App\Models\User;
9use App\Services\Setting\SettingService;
10use Illuminate\Http\Request;
11use Illuminate\Support\Facades\DB;
12use Illuminate\Support\Facades\Hash;
13use Illuminate\Support\Str;
14
15/**
16 * Phase 12 — Admin Vendor Management.
17 * CRUD for marketplace vendors + application approval.
18 */
19class VendorController extends Controller
20{
21    public function index()
22    {
23        $vendors = Vendor::withCount('products')
24            ->latest()
25            ->paginate(20);
26
27        $pendingApps = VendorApplication::pending()->count();
28
29        return view('admin.vendors.index', compact('vendors', 'pendingApps'));
30    }
31
32    public function create()
33    {
34        return view('admin.vendors.create');
35    }
36
37    public function store(Request $request)
38    {
39        $data = $request->validate([
40            'name'          => 'required|string|max:255',
41            'email'         => 'required|email|unique:vendors,email',
42            'phone'         => 'nullable|string|max:20',
43            'store_name'    => 'nullable|string|max:255',
44            'address'       => 'nullable|string',
45            'commission_pct'=> 'nullable|numeric|min:0|max:100',
46            'bio'           => 'nullable|string',
47            'nid_number'    => 'nullable|string|max:50',
48            'bank_name'     => 'nullable|string|max:255',
49            'account_name'  => 'nullable|string|max:255',
50            'account_number'=> 'nullable|string|max:255',
51            'routing_number'=> 'nullable|string|max:255',
52            'mobile_banking'     => 'nullable|string|max:20',
53            'mobile_banking_type'=> 'nullable|in:bkash,nagad,rocket',
54            'password'      => 'nullable|string|min:6',
55            'logo'          => 'nullable|string',
56        ]);
57
58        DB::transaction(function () use ($data, $request) {
59            $slug = Str::slug($data['name']);
60            $originalSlug = $slug;
61            $i = 1;
62            while (Vendor::where('slug', $slug)->exists()) {
63                $slug = $originalSlug . '-' . $i++;
64            }
65
66            // Create user account for vendor login
67            $user = null;
68            if (!empty($data['email'])) {
69                $user = User::create([
70                    'name'     => $data['name'],
71                    'email'    => $data['email'],
72                    'password' => Hash::make($data['password'] ?? 'vendor123'),
73                    'role'     => 'vendor',
74                    'vendor_id' => null, // will update after vendor creation
75                ]);
76            }
77
78            $vendor = Vendor::create([
79                'name'          => $data['name'],
80                'slug'          => $slug,
81                'email'         => $data['email'],
82                'phone'         => $data['phone'] ?? null,
83                'store_name'    => $data['store_name'] ?? $data['name'],
84                'address'       => $data['address'] ?? null,
85                'commission_pct'=> $data['commission_pct'] ?? 0,
86                'bio'           => $data['bio'] ?? null,
87                'nid_number'    => $data['nid_number'] ?? null,
88                'bank_name'     => $data['bank_name'] ?? null,
89                'account_name'  => $data['account_name'] ?? null,
90                'account_number'=> $data['account_number'] ?? null,
91                'routing_number'=> $data['routing_number'] ?? null,
92                'mobile_banking'     => $data['mobile_banking'] ?? null,
93                'mobile_banking_type'=> $data['mobile_banking_type'] ?? null,
94                'logo'          => $data['logo'] ?? null,
95                'user_id'       => $user?->id,
96                'status'        => 'active',
97                'kyc_status'    => 'approved',
98                'approved_at'   => now(),
99            ]);
100
101            if ($user) {
102                $user->update(['vendor_id' => $vendor->id]);
103            }
104        });
105
106        return redirect()->route('admin.vendors.index')
107            ->with('success', 'Vendor created successfully!');
108    }
109
110    public function show(Vendor $vendor)
111    {
112        $vendor->loadCount('products');
113        $recentCommissions = $vendor->commissions()->latest()->take(10)->get();
114        $recentPayouts = $vendor->payouts()->latest()->take(5)->get();
115
116        return view('admin.vendors.show', compact('vendor', 'recentCommissions', 'recentPayouts'));
117    }
118
119    public function edit(Vendor $vendor)
120    {
121        return view('admin.vendors.edit', compact('vendor'));
122    }
123
124    public function update(Request $request, Vendor $vendor)
125    {
126        $data = $request->validate([
127            'name'          => 'required|string|max:255',
128            'email'         => 'required|email|unique:vendors,email,' . $vendor->id,
129            'phone'         => 'nullable|string|max:20',
130            'store_name'    => 'nullable|string|max:255',
131            'address'       => 'nullable|string',
132            'commission_pct'=> 'nullable|numeric|min:0|max:100',
133            'bio'           => 'nullable|string',
134            'status'        => 'nullable|in:active,suspended,pending',
135            'kyc_status'    => 'nullable|in:pending,approved,rejected',
136            'kyc_note'      => 'nullable|string',
137            'nid_number'    => 'nullable|string|max:50',
138            'bank_name'     => 'nullable|string|max:255',
139            'account_name'  => 'nullable|string|max:255',
140            'account_number'=> 'nullable|string|max:255',
141            'routing_number'=> 'nullable|string|max:255',
142            'mobile_banking'     => 'nullable|string|max:20',
143            'mobile_banking_type'=> 'nullable|in:bkash,nagad,rocket',
144            'logo'          => 'nullable|string',
145        ]);
146
147        $vendor->update($data);
148
149        // If KYC was just approved, set approved_at
150        if ($request->kyc_status === 'approved' && $vendor->wasChanged('kyc_status')) {
151            $vendor->update(['approved_at' => now()]);
152        }
153
154        return redirect()->route('admin.vendors.index')
155            ->with('success', 'Vendor updated successfully!');
156    }
157
158    public function destroy(Vendor $vendor)
159    {
160        $vendor->delete();
161
162        return redirect()->route('admin.vendors.index')
163            ->with('success', 'Vendor deleted successfully!');
164    }
165
166    /* ─── Vendor Applications ─── */
167
168    public function applications()
169    {
170        $applications = VendorApplication::latest()->paginate(20);
171
172        return view('admin.vendors.applications', compact('applications'));
173    }
174
175    public function approveApplication(VendorApplication $application)
176    {
177        if ($application->status !== 'pending') {
178            return back()->with('error', 'This application has already been processed.');
179        }
180
181        DB::transaction(function () use ($application) {
182            $slug = Str::slug($application->store_name ?: $application->name);
183            $originalSlug = $slug;
184            $i = 1;
185            while (Vendor::where('slug', $slug)->exists()) {
186                $slug = $originalSlug . '-' . $i++;
187            }
188
189            // Create user account
190            $user = User::create([
191                'name'     => $application->name,
192                'email'    => $application->email,
193                'password' => Hash::make('vendor123'), // Vendor must change on first login
194                'role'     => 'vendor',
195            ]);
196
197            // Create vendor
198            $vendor = Vendor::create([
199                'name'       => $application->name,
200                'slug'       => $slug,
201                'email'      => $application->email,
202                'phone'      => $application->phone,
203                'store_name' => $application->store_name,
204                'address'    => $application->address,
205                'nid_number' => $application->nid_number,
206                'bio'        => $application->bio,
207                'user_id'    => $user->id,
208                'status'     => 'active',
209                'kyc_status' => 'approved',
210                'approved_at'=> now(),
211            ]);
212
213            $user->update(['vendor_id' => $vendor->id]);
214
215            $application->update([
216                'status'      => 'approved',
217                'approved_by' => auth()->id(),
218                'vendor_id'   => $vendor->id,
219            ]);
220        });
221
222        return back()->with('success', 'Vendor application approved! Login credentials sent.');
223    }
224
225    public function rejectApplication(Request $request, VendorApplication $application)
226    {
227        $request->validate(['rejection_reason' => 'required|string']);
228
229        $application->update([
230            'status'           => 'rejected',
231            'rejection_reason' => $request->rejection_reason,
232            'approved_by'      => auth()->id(),
233        ]);
234
235        return back()->with('success', 'Vendor application rejected.');
236    }
237}