Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
14.55% covered (danger)
14.55%
8 / 55
0.00% covered (danger)
0.00%
0 / 7
CRAP
0.00% covered (danger)
0.00%
0 / 1
CustomerController
14.55% covered (danger)
14.55%
8 / 55
0.00% covered (danger)
0.00%
0 / 7
86.51
0.00% covered (danger)
0.00%
0 / 1
 index
57.14% covered (warning)
57.14%
8 / 14
0.00% covered (danger)
0.00%
0 / 1
1.08
 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 / 26
0.00% covered (danger)
0.00%
0 / 1
20
 show
0.00% covered (danger)
0.00%
0 / 1
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 / 8
0.00% covered (danger)
0.00%
0 / 1
2
 destroy
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2
3namespace App\Http\Controllers\admin;
4
5use App\Http\Controllers\Controller;
6use App\Models\admin\Customer;
7use App\Service\PosService;
8use App\Traits\PosTrait;
9use Illuminate\Http\Request;
10use Illuminate\Http\Response;
11use Illuminate\Support\Facades\Auth;
12use Illuminate\Support\Facades\DB;
13use Illuminate\Support\Facades\Log;
14
15class CustomerController extends Controller
16{
17    use PosTrait;
18
19    /**
20     * Display a listing of the resource.
21     *
22     * @return Response
23     */
24    public function index(Request $request)
25    {
26        $search = trim((string) $request->input('search'));
27
28        $customers = Customer::query()
29            ->when($search !== '', function ($q) use ($search) {
30                $q->where(function ($q) use ($search) {
31                    $q->where('name', 'like', "%{$search}%")
32                        ->orWhere('phone', 'like', "%{$search}%")
33                        ->orWhere('email', 'like', "%{$search}%")
34                        ->orWhere('customer_code', 'like', "%{$search}%");
35                });
36            })
37            ->orderByDesc('id')
38            ->paginate(20)
39            ->withQueryString();
40
41        return view('admin.people.customer-list', compact('customers'));
42    }
43
44    /**
45     * Show the form for creating a new resource.
46     *
47     * @return Response
48     */
49    public function create()
50    {
51        return view('admin.people.add-customer');
52    }
53
54    /**
55     * Store a newly created resource in storage.
56     *
57     * @return Response
58     */
59    public function store(Request $request)
60    {
61        // BUG FIX: the "Add Customer" modal now only collects Name/Phone/Address
62        // (see admin.modal.customer-create) — 'email' => 'required' would have
63        // rejected every submission from that form since it no longer has an
64        // email field at all. `phone` matches the real DB constraint (NOT NULL
65        // on `customers.phone`), the rest stay nullable/back-compat for any
66        // other caller of this same route (e.g. admin/people/add-customer.blade.php).
67        $data['request'] = $request->validate([
68            'name' => 'required',
69            'phone' => 'required',
70            'email' => 'nullable|email',
71            'country_id' => 'nullable',
72            'city_id' => 'nullable',
73            'address' => 'nullable',
74            'description' => 'nullable',
75            'picture' => 'nullable',
76            // Wholesale/customer-group pricing (Phase 7) — only ever posted
77            // when the feature is on (see admin.modal.customer-create).
78            'customer_group_id' => 'nullable|exists:customer_groups,id',
79        ]);
80        try {
81            DB::beginTransaction();
82            $data['value'] = ['customer_code' => 'c-' . rand(0, 9999), 'created_by' => Auth::user()->id];
83            $data = array_merge($data['value'], $data['request']);
84            $customer = Customer::query()->create($data);
85            if ($request->hasFile('picture')) {
86                $data['picture'] = $this->FileProcessing($request->file('picture'), PosService::CUSTOMER_IMAGE, 429, 500);
87                $customer->update(['pictures' => $data['picture']]);
88            }
89            DB::commit();
90            if ($request->prev == 'admin.sale.create') {
91                // BUG FIX: this used to redirect to `admin.sale.back`
92                // (SaleController::saleBackPage) — a dead leftover from the old
93                // per-customer SaleCard cart system. It renders this exact same
94                // `admin.sales.create` view but never passes a `stocks` variable,
95                // which the redesigned POS page's product grid requires — so
96                // adding a customer from the POS page's "+" button crashed the
97                // page instead of just returning you to the POS with the new
98                // customer selected. Go back to the real POS route instead, with
99                // the new customer preselected via SaleController::create()'s
100                // `?customer=` support.
101                return redirect()->route('admin.sale.create', ['customer' => $customer->id]);
102            }
103
104            return redirect()->back()->with('success', 'Category Successfully Inserted');
105        } catch (\Throwable $e) {
106            DB::rollBack();
107
108            // BUG FIX: was `dd(...)` — crashed with a raw debug dump instead of
109            // a usable error, same pattern already fixed elsewhere in this app.
110            Log::error('Customer store failed: ' . $e->getMessage(), ['exception' => $e]);
111
112            return redirect()->back()->withInput()->with('error', 'Something went wrong while saving the customer. Please try again.');
113        }
114    }
115
116    /**
117     * Display the specified resource.
118     *
119     * @return Response
120     */
121    public function show(Customer $customer)
122    {
123        //
124    }
125
126    /**
127     * Show the form for editing the specified resource.
128     *
129     * @return Response
130     */
131    public function edit(Customer $customer)
132    {
133        //
134    }
135
136    /**
137     * Update the specified resource in storage.
138     *
139     * FIX: this used to be an empty stub — the "Edit" button on the
140     * customer list rendered but silently did nothing, since the form it
141     * points to (admin.modal.customer-create, in edit mode) submitted to
142     * this route and got a blank 200 response back. Implemented for real,
143     * matching the same validation as store().
144     *
145     * @return Response
146     */
147    public function update(Request $request, Customer $customer)
148    {
149        $data = $request->validate([
150            'name' => 'required|string|max:255',
151            'phone' => 'required|string|max:30',
152            'address' => 'nullable|string|max:500',
153            'customer_group_id' => 'nullable|exists:customer_groups,id',
154        ]);
155
156        $customer->update($data);
157
158        return redirect()->back()->with('success', 'Customer updated successfully.');
159    }
160
161    /**
162     * Remove the specified resource from storage.
163     *
164     * FIX: also an empty stub before — the "Delete" button did nothing.
165     * A customer with existing sales/orders is blocked from deletion
166     * (would otherwise orphan those records / break the FK) and gets an
167     * honest error instead of a silent no-op.
168     *
169     * @return Response
170     */
171    public function destroy(Customer $customer)
172    {
173        if ($customer->sales()->exists()) {
174            return redirect()->back()->with('error', 'This customer has existing orders and cannot be deleted.');
175        }
176
177        $customer->delete();
178
179        return redirect()->back()->with('success', 'Customer deleted successfully.');
180    }
181}