181 lines
6.3 KiB
PHP
181 lines
6.3 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Api\Expenses;
|
|
|
|
use App\Http\Controllers\Api\BaseApiController;
|
|
use App\Http\Requests\Expenses\StoreExpenseRequest;
|
|
use App\Http\Requests\Expenses\UpdateExpenseRequest;
|
|
use App\Http\Requests\Expenses\UpdateExpenseStatusRequest;
|
|
use App\Http\Resources\Expenses\ExpenseResource;
|
|
use App\Http\Resources\Expenses\ExpenseStaffResource;
|
|
use App\Models\Expense;
|
|
use App\Services\Expenses\ExpenseContextService;
|
|
use App\Services\Expenses\ExpenseQueryService;
|
|
use App\Services\Expenses\ExpenseReceiptService;
|
|
use App\Services\Expenses\ExpenseRetailorService;
|
|
use App\Services\Expenses\ExpenseStaffService;
|
|
use App\Services\Expenses\ExpenseStatusService;
|
|
use App\Services\Expenses\ExpenseWriteService;
|
|
use Illuminate\Http\JsonResponse;
|
|
|
|
class ExpenseController extends BaseApiController
|
|
{
|
|
public function __construct(
|
|
private ExpenseContextService $context,
|
|
private ExpenseRetailorService $retailors,
|
|
private ExpenseStaffService $staff,
|
|
private ExpenseQueryService $queryService,
|
|
private ExpenseReceiptService $receiptService,
|
|
private ExpenseWriteService $writeService,
|
|
private ExpenseStatusService $statusService
|
|
) {
|
|
parent::__construct();
|
|
}
|
|
|
|
public function options(): JsonResponse
|
|
{
|
|
$schoolYear = $this->context->getSchoolYear();
|
|
$semester = $this->context->getSemester();
|
|
|
|
return response()->json([
|
|
'ok' => true,
|
|
'schoolYear' => $schoolYear,
|
|
'semester' => $semester,
|
|
'retailors' => $this->retailors->listRetailors(),
|
|
'staff' => ExpenseStaffResource::collection($this->staff->listStaffUsers()),
|
|
]);
|
|
}
|
|
|
|
public function index(): JsonResponse
|
|
{
|
|
$rows = $this->queryService->listAll();
|
|
$rows = array_map(function ($row) {
|
|
$row['receipt_url'] = $this->receiptService->receiptUrl($row['receipt_path'] ?? null);
|
|
return $row;
|
|
}, $rows);
|
|
|
|
return response()->json([
|
|
'ok' => true,
|
|
'expenses' => ExpenseResource::collection($rows),
|
|
]);
|
|
}
|
|
|
|
public function show(int $id): JsonResponse
|
|
{
|
|
$row = $this->queryService->findById($id);
|
|
if (!$row) {
|
|
return response()->json(['ok' => false, 'message' => 'Expense not found.'], 404);
|
|
}
|
|
|
|
$row['receipt_url'] = $this->receiptService->receiptUrl($row['receipt_path'] ?? null);
|
|
|
|
return response()->json([
|
|
'ok' => true,
|
|
'expense' => new ExpenseResource($row),
|
|
]);
|
|
}
|
|
|
|
public function store(StoreExpenseRequest $request): JsonResponse
|
|
{
|
|
$payload = $request->validated();
|
|
$userId = (int) (auth()->id() ?? 0);
|
|
|
|
$receiptName = null;
|
|
if ($request->hasFile('receipt')) {
|
|
$receiptName = $this->receiptService->storeReceipt($request->file('receipt'));
|
|
}
|
|
|
|
$isDonation = $payload['category'] === 'Donation';
|
|
|
|
$expense = $this->writeService->store([
|
|
'category' => $payload['category'],
|
|
'amount' => $payload['amount'],
|
|
'receipt_path' => $receiptName,
|
|
'description' => $payload['description'] ?? null,
|
|
'retailor' => $payload['retailor'] ?? null,
|
|
'date_of_purchase' => $payload['date_of_purchase'],
|
|
'purchased_by' => (int) $payload['purchased_by'],
|
|
'added_by' => $userId,
|
|
'status' => $isDonation ? 'approved' : 'pending',
|
|
'status_reason' => $isDonation ? 'Marked as Donation (non-reimbursable).' : null,
|
|
'approved_by' => $isDonation ? $userId : null,
|
|
'school_year' => $payload['school_year'] ?? null,
|
|
'semester' => $payload['semester'] ?? null,
|
|
]);
|
|
|
|
return response()->json([
|
|
'ok' => true,
|
|
'expense' => new ExpenseResource($expense->toArray()),
|
|
], 201);
|
|
}
|
|
|
|
public function update(UpdateExpenseRequest $request, int $id): JsonResponse
|
|
{
|
|
$expense = Expense::query()->find($id);
|
|
if (!$expense) {
|
|
return response()->json(['ok' => false, 'message' => 'Expense not found.'], 404);
|
|
}
|
|
|
|
$payload = $request->validated();
|
|
$userId = (int) (auth()->id() ?? 0);
|
|
|
|
$receiptName = $expense->receipt_path;
|
|
if ($request->hasFile('receipt')) {
|
|
$receiptName = $this->receiptService->storeReceipt($request->file('receipt'));
|
|
}
|
|
if (!empty($payload['remove_receipt'])) {
|
|
$receiptName = null;
|
|
}
|
|
|
|
$category = $payload['category'];
|
|
$isDonation = $category === 'Donation';
|
|
|
|
$updateData = [
|
|
'category' => $category,
|
|
'amount' => $payload['amount'],
|
|
'description' => $payload['description'] ?? null,
|
|
'retailor' => $payload['retailor'] ?? null,
|
|
'date_of_purchase' => $payload['date_of_purchase'],
|
|
'purchased_by' => (int) $payload['purchased_by'],
|
|
'receipt_path' => $receiptName,
|
|
'updated_by' => $userId,
|
|
];
|
|
|
|
if ($isDonation) {
|
|
$updateData['status'] = 'approved';
|
|
$updateData['status_reason'] = 'Marked as Donation (non-reimbursable).';
|
|
$updateData['approved_by'] = $userId ?: null;
|
|
$updateData['reimbursement_id'] = null;
|
|
} elseif (($expense->category ?? '') === 'Donation') {
|
|
$updateData['status_reason'] = null;
|
|
$updateData['approved_by'] = $expense->approved_by;
|
|
$updateData['status'] = $expense->status ?? 'pending';
|
|
}
|
|
|
|
$updated = $this->writeService->update($expense, $updateData);
|
|
|
|
return response()->json([
|
|
'ok' => true,
|
|
'expense' => new ExpenseResource($updated->toArray()),
|
|
]);
|
|
}
|
|
|
|
public function updateStatus(UpdateExpenseStatusRequest $request, int $id): JsonResponse
|
|
{
|
|
$expense = Expense::query()->find($id);
|
|
if (!$expense) {
|
|
return response()->json(['ok' => false, 'message' => 'Expense not found.'], 404);
|
|
}
|
|
|
|
$payload = $request->validated();
|
|
$userId = (int) (auth()->id() ?? 0);
|
|
|
|
$updated = $this->statusService->updateStatus($expense, $payload['status'], $payload['reason'] ?? '', $userId);
|
|
|
|
return response()->json([
|
|
'ok' => true,
|
|
'expense' => new ExpenseResource($updated->toArray()),
|
|
]);
|
|
}
|
|
}
|