middleware('check.permission:incomes.read')->only(['index']); $this->middleware('check.permission:incomes.create')->only(['store']); $this->middleware('check.permission:incomes.update')->only(['update']); $this->middleware('check.permission:incomes.delete')->only(['destroy', 'deleteAll']); } public function index(Request $request) { $income_categories = IncomeCategory::where('business_id', auth()->user()->business_id)->whereStatus(1)->latest()->get(); $payment_types = PaymentType::where('business_id', auth()->user()->business_id)->whereStatus(1)->latest()->get(); $branches = Branch::withTrashed()->where('business_id', auth()->user()->business_id)->latest()->get(); $incomeQuery = Income::with('category:id,categoryName', 'payment_type:id,name', 'branch:id,name', 'transactions')->where('business_id', auth()->user()->business_id); // Branch filter if ($request->branch_id) { $incomeQuery->where('branch_id', $request->branch_id); } // Date Filter $duration = $request->custom_days ?: 'today'; [$filter_from_date, $filter_to_date] = $this->applyDateRange($duration, $request->from_date, $request->to_date); $this->applyDateFilter($incomeQuery, $duration, 'incomeDate', $request->from_date, $request->to_date); // Search filter if ($request->filled('search')) { $search = $request->search; $incomeQuery->where(function ($query) use ($search) { $query->where('incomeFor', 'like', '%' . $search . '%') ->orWhere('paymentType', 'like', '%' . $search . '%') ->orWhere('amount', 'like', '%' . $search . '%') ->orWhere('referenceNo', 'like', '%' . $search . '%') ->orWhereHas('category', fn($q) => $q->where('categoryName', 'like', '%' . $search . '%')) ->orWhereHas('payment_type', fn($q) => $q->where('name', 'like', '%' . $search . '%')) ->orWhereHas('branch', fn($q) => $q->where('name', 'like', '%' . $search . '%')); }); } $perPage = $request->input('per_page', 20); $incomes = $incomeQuery->latest()->paginate($perPage)->appends($request->query()); if ($request->ajax()) { return response()->json([ 'data' => view('business::incomes.datas', compact('incomes', 'filter_from_date', 'filter_to_date', 'duration'))->render(), ]); } return view('business::incomes.index', compact('incomes', 'income_categories', 'payment_types', 'branches', 'filter_from_date', 'filter_to_date', 'duration')); } public function store(Request $request) { $request->validate([ 'income_category_id' => 'required|exists:income_categories,id', 'incomeFor' => 'nullable|string', 'referenceNo' => 'nullable|string', 'incomeDate' => 'nullable|string', 'note' => 'nullable|string', 'payments' => 'required|array|min:1', 'payments.*.type' => 'required|string', 'payments.*.amount' => 'nullable|numeric|min:0', 'payments.*.cheque_number' => 'nullable|string', ], [ 'payments.required' => 'At least one payment method is required.', 'payments.*.type.required' => 'Each payment must have a type.', 'payments.*.amount.numeric' => 'Each payment amount must be numeric.', ]); DB::beginTransaction(); try { $business_id = auth()->user()->business_id; $payments = $request->payments; if (isset($payments['main'])) { $mainPayment = $payments['main']; $mainPayment['amount'] = $request->amount ?? 0; $payments = [$mainPayment]; } $total_amount = collect($payments) ->reject(fn($p) => strtolower($p['type'] ?? '') === 'cheque') ->sum(fn($p) => $p['amount'] ?? 0); updateBalance($total_amount, 'increment'); $income = Income::create($request->except('status', 'amount', 'paymentType') + [ 'user_id' => auth()->id(), 'business_id' => auth()->user()->business_id, 'amount' => $total_amount, ]); // MultiPaymentProcessed Event event(new MultiPaymentProcessed( $payments ?? [], $income->id, 'income', $total_amount ?? 0, )); DB::commit(); sendNotifyToUser($income->id, route('business.incomes.index', ['id' => $income->id]), __('Income has been created.'), $business_id); return response()->json([ 'message' => __('Income saved successfully.'), 'redirect' => route('business.incomes.index') ]); } catch (\Exception $e) { return $e->getMessage(); DB::rollback(); return response()->json(['message' => __('Somethings went wrong!')], 404); } } public function update(Request $request, $id) { $request->validate([ 'income_category_id' => 'required|exists:income_categories,id', 'incomeFor' => 'nullable|string', 'referenceNo' => 'nullable|string', 'incomeDate' => 'nullable|string', 'note' => 'nullable|string', 'payments' => 'required|array|min:1', 'payments.*.type' => 'required|string', 'payments.*.amount' => 'nullable|numeric|min:0', 'payments.*.cheque_number' => 'nullable|string', ], [ 'payments.required' => 'At least one payment method is required.', 'payments.*.type.required' => 'Each payment must have a type.', 'payments.*.amount.numeric' => 'Each payment amount must be numeric.', ]); DB::beginTransaction(); try { $business_id = auth()->user()->business_id; $income = Income::findOrFail($id); // Normalize payments $payments = $request->payments ?? []; if (isset($payments['main'])) { $mainPayment = $payments['main']; $mainPayment['amount'] = $request->amount ?? 0; $payments = [$mainPayment]; } // Check if any old transaction type = deposit $hasDeposit = Transaction::where('business_id', $business_id) ->where('reference_id', $income->id) ->where('platform', 'income') ->where('type', 'deposit') ->exists(); // Calculate total amount $total_amount = collect($payments) ->reject(function ($p) use ($hasDeposit) { // exclude cheque only if not deposit return !$hasDeposit && strtolower($p['type'] ?? '') === 'cheque'; }) ->sum(fn($p) => $p['amount'] ?? 0); // Adjust balance difference updateBalance($total_amount - $income->amount, 'increment'); // Update income $income->update($request->except('status', 'amount', 'payments') + [ 'user_id' => auth()->id(), 'business_id' => $business_id, 'amount' => $total_amount, ]); // Revert old transactions $oldTransactions = Transaction::where('business_id', $business_id) ->where('reference_id', $income->id) ->where('platform', 'income') ->get(); foreach ($oldTransactions as $old) { if ($old->transaction_type === 'bank_payment' && $old->payment_type_id) { $paymentType = PaymentType::find($old->payment_type_id); if ($paymentType) { $paymentType->decrement('balance', $old->amount); } } } // Delete old transactions Transaction::where('business_id', $business_id) ->where('reference_id', $income->id) ->where('platform', 'income') ->delete(); // Process new payments event(new MultiPaymentProcessed( $payments ?? [], $income->id, 'income', $total_amount ?? 0, )); sendNotifyToUser($income->id, route('business.incomes.index', ['id' => $income->id]), __('Income has been updated.'), $business_id); DB::commit(); return response()->json([ 'message' => __('Income updated successfully.'), 'redirect' => route('business.incomes.index') ]); } catch (\Exception $e) { DB::rollback(); return response()->json(['message' => __('Somethings went wrong!')], 404); } } public function destroy($id) { DB::beginTransaction(); try { $income = Income::findOrFail($id); updateBalance($income->amount, 'decrement'); sendNotifyToUser($income->id, route('business.incomes.index', ['id' => $income->id]), __('Income has been deleted.'), $income->business_id); $income->delete(); DB::commit(); return response()->json([ 'message' => __('Income deleted successfully'), 'redirect' => route('business.incomes.index'), ]); } catch (\Exception $e) { DB::rollback(); return response()->json(['message' => __('Something went wrong!')], 404); } } public function deleteAll(Request $request) { DB::beginTransaction(); try { $incomes = Income::whereIn('id', $request->ids)->get(); $totalAmount = $incomes->sum('amount'); updateBalance($totalAmount, 'decrement'); foreach ($incomes as $income) { sendNotifyToUser($income->id, route('business.incomes.index', ['id' => $income->id]), __('Income has been deleted.'), $income->business_id); } Income::whereIn('id', $request->ids)->delete(); DB::commit(); return response()->json([ 'message' => __('Selected Items deleted successfully.'), 'redirect' => route('business.incomes.index'), ]); } catch (\Exception $e) { DB::rollback(); return response()->json(['message' => __('Something went wrong!')], 404); } } }