Files
kulakpos_web/Modules/Business/App/Http/Controllers/AcnooCashController.php

393 lines
14 KiB
PHP
Raw Normal View History

2026-03-15 17:08:23 +07:00
<?php
namespace Modules\Business\App\Http\Controllers;
use App\Helpers\HasUploader;
use App\Models\PaymentType;
use App\Models\Transaction;
use App\Http\Controllers\Controller;
2026-05-14 11:55:22 +07:00
use App\Services\PdfService;
use App\Traits\DateFilterTrait;
use App\Traits\DateRangeTrait;
2026-03-15 17:08:23 +07:00
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
2026-05-14 11:55:22 +07:00
use Maatwebsite\Excel\Facades\Excel;
use Modules\Business\App\Exports\ExportCashBalance;
2026-03-15 17:08:23 +07:00
class AcnooCashController extends Controller
{
use HasUploader;
2026-05-14 11:55:22 +07:00
use DateFilterTrait, DateRangeTrait;
2026-03-15 17:08:23 +07:00
public function index(Request $request)
{
$business_id = auth()->user()->business_id;
$banks = PaymentType::where('business_id', $business_id)->latest()->get();
$cash = Transaction::with('user:id,name')
->where('business_id', auth()->user()->business_id)
->whereIn('transaction_type', ['cash_payment', 'bank_to_cash', 'cash_to_bank', 'adjust_cash', 'cheque_to_cash']);
2026-05-14 11:55:22 +07:00
// Date Filter
$duration = $request->custom_days ?: 'today';
[$filter_from_date, $filter_to_date] = $this->applyDateRange($duration, $request->from_date, $request->to_date);
2026-03-15 17:08:23 +07:00
2026-05-14 11:55:22 +07:00
$this->applyDateFilter($cash, $duration, 'date', $request->from_date, $request->to_date);
2026-03-15 17:08:23 +07:00
$cashes = $cash->when(request('search'), function ($q) use ($request) {
$q->where(function ($q) use ($request) {
$q->where('date', 'like', '%' . $request->search . '%')
2026-05-14 11:55:22 +07:00
->orWhere('platform', 'like', '%' . $request->search . '%')
2026-03-15 17:08:23 +07:00
->orWhere('transaction_type', 'like', '%' . $request->search . '%')
->orWhere('amount', 'like', '%' . $request->search . '%')
->orWhereHas('user', function ($q) use ($request) {
$q->where('name', 'like', '%' . $request->search . '%');
});
});
})
->latest()
->paginate($request->per_page ?? 20)->appends($request->query());
2026-05-14 11:55:22 +07:00
// Sum of all credits and bank_to_cash
$totalCredit = (clone $cash)->where(function ($q) {
$q->where('type', 'credit')
->orWhere('transaction_type', 'bank_to_cash');
})
->sum('amount');
// Sum of all debits and cash_to_bank
$totalDebit = (clone $cash)->where(function ($q) {
$q->where('type', 'debit')
->orWhere('transaction_type', 'cash_to_bank');
})
->sum('amount');
$cash_balance = $totalCredit - $totalDebit;
2026-03-15 17:08:23 +07:00
if ($request->ajax()) {
return response()->json([
2026-05-14 11:55:22 +07:00
'data' => view('business::cashes.datas', compact('cashes', 'cash_balance', 'duration', 'filter_from_date', 'filter_to_date'))->render(),
'cash_balance' => currency_format($cash_balance, 'icon', 2, business_currency())
2026-03-15 17:08:23 +07:00
]);
}
2026-05-14 11:55:22 +07:00
return view('business::cashes.index', compact('cashes', 'banks', 'cash_balance', 'duration', 'filter_from_date', 'filter_to_date'));
2026-03-15 17:08:23 +07:00
}
public function store(Request $request)
{
$request->validate([
'to' => 'nullable|exists:payment_types,id',
'type' => 'nullable|in:credit,debit',
'transaction_type' => 'required|in:cash_to_bank,adjust_cash',
'amount' => 'required|numeric|min:0.01',
'date' => 'nullable|date',
'image' => 'nullable|image|mimes:jpg,png,jpeg,svg',
'note' => 'nullable|string',
]);
$business_id = auth()->user()->business_id;
$amount = $request->amount ?? 0;
$type = 'transfer';
DB::beginTransaction();
try {
// Cash to Bank
if ($request->transaction_type === 'cash_to_bank') {
$toBank = PaymentType::findOrFail($request->to);
// increase target bank balance
$toBank->increment('balance', $amount);
// Adjust Cash
} elseif ($request->transaction_type === 'adjust_cash') {
$type = $request->type;
}
// Store transaction record
Transaction::create([
'business_id' => $business_id,
'user_id' => auth()->id(),
'type' => $type,
'platform' => 'cash',
'transaction_type' => $request->transaction_type,
'amount' => $amount,
'from_bank' => null,
'to_bank' => ($request->transaction_type === 'cash_to_bank') ? $request->to : null,
'date' => $request->date ?? now(),
'image' => $request->image ? $this->upload($request, 'image') : NULL,
'note' => $request->note,
]);
DB::commit();
return response()->json([
'message' => __('Transaction completed successfully.'),
'redirect' => route('business.cashes.index'),
]);
} catch (\Exception $e) {
DB::rollBack();
return response()->json([
'message' => 'Error: ' . $e->getMessage(),
], 500);
}
}
public function update(Request $request, string $id)
{
$request->validate([
'to' => 'nullable|exists:payment_types,id',
'type' => 'nullable|in:credit,debit',
'transaction_type' => 'required|in:cash_to_bank,adjust_cash',
'amount' => 'required|numeric|min:0.01',
'date' => 'nullable|date',
'image' => 'nullable|image|mimes:jpg,png,jpeg,svg',
'note' => 'nullable|string',
]);
$transaction = Transaction::findOrFail($id);
$newAmount = $request->amount ?? 0;
$newTransactionType = $request->transaction_type;
$type = 'transfer';
DB::beginTransaction();
try {
// Transaction type is the same
if ($transaction->transaction_type === $newTransactionType) {
if ($newTransactionType === 'cash_to_bank') {
$toBank = PaymentType::findOrFail($request->to);
// Adjust balance difference
$diff = $newAmount - $transaction->amount;
// Prevent negative balance
if ($toBank->balance + $diff < 0) {
return response()->json([
'message' => 'Cannot update: updated bank balance would be negative.'
], 400);
}
$toBank->increment('balance', $diff);
} elseif ($newTransactionType === 'adjust_cash') {
$type = $request->type;
}
} // Transaction type changed
else {
// Reverse old transaction effect
if ($transaction->transaction_type === 'cash_to_bank' && $transaction->to_bank) {
$prevBank = PaymentType::find($transaction->to_bank);
if ($prevBank) {
if ($prevBank->balance < $transaction->amount) {
return response()->json([
'message' => 'Cannot update: insufficient balance in ' . $prevBank->name . ' to reverse previous transaction.'
], 400);
}
$prevBank->decrement('balance', $transaction->amount);
}
}
// Apply new transaction effect
if ($newTransactionType === 'cash_to_bank') {
$toBank = PaymentType::findOrFail($request->to);
$toBank->increment('balance', $newAmount);
$type = 'transfer';
} elseif ($newTransactionType === 'adjust_cash') {
$type = $request->type;
}
}
// Update transaction record
$transaction->update([
'type' => $type,
'transaction_type' => $newTransactionType,
'amount' => $newAmount,
'to_bank' => ($newTransactionType === 'cash_to_bank') ? $request->to : null,
'date' => $request->date ?? now(),
'image' => $request->image ? $this->upload($request, 'image') : $transaction->image,
'note' => $request->note,
]);
DB::commit();
return response()->json([
'message' => __('Transaction updated successfully.'),
'redirect' => route('business.cashes.index'),
]);
} catch (\Exception $e) {
DB::rollBack();
return response()->json([
'message' => 'Error: ' . $e->getMessage(),
], 500);
}
}
public function destroy(string $id)
{
$transaction = Transaction::findOrFail($id);
DB::beginTransaction();
try {
// Allow only "cash" platform transactions to be deleted
if ($transaction->platform !== 'cash') {
return response()->json([
'message' => 'Cannot delete here, please delete from ' . ucfirst($transaction->platform) . ' section.',
], 400);
}
$amount = $transaction->amount;
$toBank = $transaction->to_bank ? PaymentType::find($transaction->to_bank) : null;
// Reverse balance changes based on transaction type
switch ($transaction->transaction_type) {
case 'cash_to_bank':
if ($toBank) {
// Ensure bank has enough balance to reverse
if ($toBank->balance < $amount) {
return response()->json([
'message' => 'Cannot delete: bank balance would go negative.',
], 400);
}
$toBank->decrement('balance', $amount);
}
break;
case 'adjust_cash':
// Cash is static, so no bank adjustments needed
break;
}
if (file_exists($transaction->image)) {
Storage::delete($transaction->image);
}
$transaction->delete();
DB::commit();
return response()->json([
'message' => __('Cash transaction reversed and deleted successfully.'),
'redirect' => route('business.cashes.index'),
]);
} catch (\Exception $e) {
DB::rollBack();
return response()->json([
'message' => 'Error: ' . $e->getMessage(),
], 500);
}
}
2026-05-14 11:55:22 +07:00
public function deleteAll(Request $request)
{
$ids = $request->ids;
DB::beginTransaction();
try {
$transactions = Transaction::whereIn('id', $ids)->get();
foreach ($transactions as $transaction) {
// Allow only "cash" platform transactions
if ($transaction->platform !== 'cash') {
return response()->json([
'message' => 'Cannot delete here, please delete from ' . ucfirst($transaction->platform) . ' section.',
], 400);
}
$amount = $transaction->amount;
$toBank = $transaction->to_bank ? PaymentType::find($transaction->to_bank) : null;
switch ($transaction->transaction_type) {
case 'cash_to_bank':
if ($toBank) {
if ($toBank->balance < $amount) {
return response()->json([
'message' => 'Cannot delete: bank balance would go negative.',
], 400);
}
$toBank->decrement('balance', $amount);
}
break;
case 'adjust_cash':
// Cash is static, so no bank adjustments needed
break;
}
if ($transaction->image && file_exists($transaction->image)) {
Storage::delete($transaction->image);
}
$transaction->delete();
}
DB::commit();
return response()->json([
'message' => __('Cash transactions reversed and deleted successfully.'),
'redirect' => route('business.cashes.index'),
]);
} catch (\Exception $e) {
2026-03-15 17:08:23 +07:00
2026-05-14 11:55:22 +07:00
DB::rollBack();
return response()->json([
'message' => 'Error: ' . $e->getMessage(),
], 500);
}
}
public function exportExcel()
{
return Excel::download(new ExportCashBalance, 'cash-balances.xlsx');
}
public function exportCsv()
{
return Excel::download(new ExportCashBalance, 'cash-balances.csv');
}
public function exportPdf(Request $request)
{
$cash = Transaction::with('user:id,name')
->where('business_id', auth()->user()->business_id)
->whereIn('transaction_type', ['cash_payment', 'bank_to_cash', 'cash_to_bank', 'adjust_cash', 'cheque_to_cash']);
// Date Filter
$duration = $request->custom_days ?: 'today';
[$filter_from_date, $filter_to_date] = $this->applyDateRange($duration, $request->from_date, $request->to_date);
$this->applyDateFilter($cash, $duration, 'date', $request->from_date, $request->to_date);
$cashes = $cash->when(request('search'), function ($q) use ($request) {
$q->where(function ($q) use ($request) {
$q->where('date', 'like', '%' . $request->search . '%')
->orWhere('platform', 'like', '%' . $request->search . '%')
->orWhere('transaction_type', 'like', '%' . $request->search . '%')
->orWhere('amount', 'like', '%' . $request->search . '%')
->orWhereHas('user', function ($q) use ($request) {
$q->where('name', 'like', '%' . $request->search . '%');
});
});
})
->latest()
->limit($request->per_page ?? 20)->get();
return PdfService::render('business::cashes.pdf', compact('cashes', 'duration', 'filter_from_date', 'filter_to_date'), 'cash-balances.pdf');
}
2026-03-15 17:08:23 +07:00
}