228 lines
7.4 KiB
PHP
228 lines
7.4 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Api\Finance;
|
|
|
|
use App\Http\Controllers\Api\Core\BaseApiController;
|
|
use App\Http\Requests\Refunds\RefundDecisionRequest;
|
|
use App\Http\Requests\Refunds\RefundIndexRequest;
|
|
use App\Http\Requests\Refunds\RefundPaymentRequest;
|
|
use App\Http\Requests\Refunds\RefundRecalculateRequest;
|
|
use App\Http\Requests\Refunds\RefundRejectRequest;
|
|
use App\Http\Requests\Refunds\RefundStoreRequest;
|
|
use App\Http\Resources\Refunds\RefundResource;
|
|
use App\Models\Configuration;
|
|
use App\Services\Refunds\RefundDecisionService;
|
|
use App\Services\Refunds\RefundOverpaymentService;
|
|
use App\Services\Refunds\RefundPayoutService;
|
|
use App\Services\Refunds\RefundQueryService;
|
|
use App\Services\Refunds\RefundRequestService;
|
|
use App\Services\Refunds\RefundSummaryService;
|
|
use Illuminate\Http\JsonResponse;
|
|
use Illuminate\Support\Facades\Log;
|
|
|
|
class RefundController extends BaseApiController
|
|
{
|
|
public function __construct(
|
|
private RefundQueryService $queryService,
|
|
private RefundRequestService $requestService,
|
|
private RefundDecisionService $decisionService,
|
|
private RefundPayoutService $payoutService,
|
|
private RefundOverpaymentService $overpaymentService,
|
|
private RefundSummaryService $summaryService
|
|
) {
|
|
parent::__construct();
|
|
}
|
|
|
|
public function index(RefundIndexRequest $request): JsonResponse
|
|
{
|
|
$payload = $request->validated();
|
|
$result = $this->queryService->list($payload);
|
|
|
|
return response()->json([
|
|
'ok' => true,
|
|
'refunds' => RefundResource::collection($result['refunds']),
|
|
'pagination' => $result['pagination'],
|
|
]);
|
|
}
|
|
|
|
public function show(int $refundId): JsonResponse
|
|
{
|
|
$refund = $this->queryService->find($refundId);
|
|
if (!$refund) {
|
|
return response()->json(['ok' => false, 'message' => 'Refund not found.'], 404);
|
|
}
|
|
|
|
return response()->json([
|
|
'ok' => true,
|
|
'refund' => new RefundResource($refund),
|
|
]);
|
|
}
|
|
|
|
public function store(RefundStoreRequest $request): JsonResponse
|
|
{
|
|
$guard = $this->authenticatedUserIdOrUnauthorized();
|
|
if ($guard instanceof JsonResponse) {
|
|
return $guard;
|
|
}
|
|
|
|
$payload = $request->validated();
|
|
|
|
try {
|
|
$result = $this->requestService->requestRefund($payload, $guard);
|
|
} catch (\Throwable $e) {
|
|
Log::error('Refund request failed.', ['error' => $e->getMessage()]);
|
|
return response()->json(['ok' => false, 'message' => 'Failed to submit refund request.'], 500);
|
|
}
|
|
|
|
if (empty($result['ok'])) {
|
|
return response()->json([
|
|
'ok' => false,
|
|
'message' => $result['message'] ?? 'Failed to submit refund request.',
|
|
'available' => $result['available'] ?? null,
|
|
], 422);
|
|
}
|
|
|
|
return response()->json([
|
|
'ok' => true,
|
|
'refund_id' => $result['refund_id'] ?? null,
|
|
'refund_amount' => $result['refund_amount'] ?? null,
|
|
'status' => $result['status'] ?? null,
|
|
], 201);
|
|
}
|
|
|
|
public function update(RefundDecisionRequest $request, int $refundId): JsonResponse
|
|
{
|
|
$guard = $this->authenticatedUserIdOrUnauthorized();
|
|
if ($guard instanceof JsonResponse) {
|
|
return $guard;
|
|
}
|
|
|
|
$payload = $request->validated();
|
|
|
|
$result = $this->decisionService->updateDecision(
|
|
$refundId,
|
|
(string) $payload['status'],
|
|
(string) $payload['reason'],
|
|
$guard
|
|
);
|
|
|
|
if (empty($result['ok'])) {
|
|
return response()->json(['ok' => false, 'message' => $result['message'] ?? 'Failed to update refund.'], 422);
|
|
}
|
|
|
|
return response()->json(['ok' => true]);
|
|
}
|
|
|
|
public function destroy(int $refundId): JsonResponse
|
|
{
|
|
$guard = $this->authenticatedUserIdOrUnauthorized();
|
|
if ($guard instanceof JsonResponse) {
|
|
return $guard;
|
|
}
|
|
|
|
$result = $this->decisionService->cancel($refundId, $guard);
|
|
|
|
if (empty($result['ok'])) {
|
|
return response()->json(['ok' => false, 'message' => $result['message'] ?? 'Failed to cancel refund.'], 404);
|
|
}
|
|
|
|
return response()->json(['ok' => true]);
|
|
}
|
|
|
|
public function approve(int $refundId): JsonResponse
|
|
{
|
|
$guard = $this->authenticatedUserIdOrUnauthorized();
|
|
if ($guard instanceof JsonResponse) {
|
|
return $guard;
|
|
}
|
|
|
|
$result = $this->decisionService->approve($refundId, $guard);
|
|
|
|
if (empty($result['ok'])) {
|
|
return response()->json(['ok' => false, 'message' => $result['message'] ?? 'Approve failed.'], 422);
|
|
}
|
|
|
|
return response()->json(['ok' => true]);
|
|
}
|
|
|
|
public function reject(RefundRejectRequest $request, int $refundId): JsonResponse
|
|
{
|
|
$guard = $this->authenticatedUserIdOrUnauthorized();
|
|
if ($guard instanceof JsonResponse) {
|
|
return $guard;
|
|
}
|
|
|
|
$payload = $request->validated();
|
|
$result = $this->decisionService->reject($refundId, (string) $payload['reason'], $guard);
|
|
|
|
if (empty($result['ok'])) {
|
|
return response()->json(['ok' => false, 'message' => $result['message'] ?? 'Reject failed.'], 422);
|
|
}
|
|
|
|
return response()->json(['ok' => true]);
|
|
}
|
|
|
|
public function recordPayment(RefundPaymentRequest $request, int $refundId): JsonResponse
|
|
{
|
|
$guard = $this->authenticatedUserIdOrUnauthorized();
|
|
if ($guard instanceof JsonResponse) {
|
|
return $guard;
|
|
}
|
|
|
|
$payload = $request->validated();
|
|
$payload['check_file'] = $request->file('check_file');
|
|
|
|
$result = $this->payoutService->recordPayment($refundId, $payload, $guard);
|
|
if (empty($result['ok'])) {
|
|
return response()->json(['ok' => false, 'message' => $result['message'] ?? 'Failed to update payment.'], 422);
|
|
}
|
|
|
|
return response()->json(['ok' => true]);
|
|
}
|
|
|
|
public function recalculateOverpayments(RefundRecalculateRequest $request): JsonResponse
|
|
{
|
|
$guard = $this->authenticatedUserIdOrUnauthorized();
|
|
if ($guard instanceof JsonResponse) {
|
|
return $guard;
|
|
}
|
|
|
|
$payload = $request->validated();
|
|
|
|
$result = $this->overpaymentService->recalculate(true, $payload['invoice_number'] ?? null, $guard);
|
|
|
|
return response()->json([
|
|
'ok' => true,
|
|
'created_ids' => $result['created_ids'] ?? null,
|
|
'updated_ids' => $result['updated_ids'] ?? null,
|
|
'message' => $result['message'] ?? null,
|
|
]);
|
|
}
|
|
|
|
public function parentBalances(int $parentId): JsonResponse
|
|
{
|
|
$termSchoolYear = (string) (Configuration::getConfig('school_year') ?? '');
|
|
$termSemester = (string) (Configuration::getConfig('semester') ?? '');
|
|
|
|
$summary = $this->summaryService->getParentFinancialSummary($parentId, $termSchoolYear, $termSemester);
|
|
|
|
return response()->json([
|
|
'ok' => true,
|
|
'summary' => $summary,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* @return int|JsonResponse
|
|
*/
|
|
private function authenticatedUserIdOrUnauthorized(): int|JsonResponse
|
|
{
|
|
$userId = (int) (auth()->id() ?? 0);
|
|
if ($userId <= 0) {
|
|
return response()->json(['ok' => false, 'message' => 'Unauthorized.'], 401);
|
|
}
|
|
|
|
return $userId;
|
|
}
|
|
}
|