fix logic and tests, update docker CI file

This commit is contained in:
root
2026-03-09 15:58:44 -04:00
parent 1cb3573d4b
commit 79e44fe037
188 changed files with 1776 additions and 524 deletions
@@ -3,13 +3,13 @@
namespace App\Http\Controllers\Api\Finance;
use App\Http\Controllers\Api\BaseApiController;
use App\Http\Requests\Fees\FeeRefundRequest;
use App\Http\Requests\Fees\FeeTuitionTotalRequest;
use App\Http\Resources\Fees\FeeRefundResource;
use App\Http\Resources\Fees\FeeTuitionTotalResource;
use App\Services\Fees\FeeRefundCalculatorService;
use App\Services\Fees\FeeStudentFeeService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
class FeeCalculationController extends BaseApiController
{
@@ -20,9 +20,26 @@ class FeeCalculationController extends BaseApiController
parent::__construct();
}
public function refund(FeeRefundRequest $request): JsonResponse
public function refund(Request $request): JsonResponse
{
$payload = $request->validated();
$validator = Validator::make($request->all(), [
'parent_id' => ['required', 'integer', 'min:1'],
'students' => ['required', 'array'],
'students.*.student_id' => ['nullable', 'integer'],
'students.*.class_section_id' => ['required', 'integer', 'min:1'],
'students.*.enrollment_status' => ['required', 'string', 'max:50'],
'students.*.admission_status' => ['required', 'string', 'max:50'],
'students.*.withdrawal_date' => ['nullable', 'date'],
]);
if ($validator->fails()) {
return response()->json([
'message' => 'Validation failed.',
'errors' => $validator->errors(),
], 422);
}
$payload = $validator->validated();
$result = $this->refunds->calculateRefund($payload['students'], (int) $payload['parent_id']);
return response()->json([
@@ -31,9 +48,22 @@ class FeeCalculationController extends BaseApiController
]);
}
public function tuitionTotal(FeeTuitionTotalRequest $request): JsonResponse
public function tuitionTotal(Request $request): JsonResponse
{
$payload = $request->validated();
$validator = Validator::make($request->all(), [
'students' => ['required', 'array'],
'students.*.class_section_id' => ['required', 'integer', 'min:1'],
'students.*.grade' => ['nullable', 'string', 'max:20'],
]);
if ($validator->fails()) {
return response()->json([
'message' => 'Validation failed.',
'errors' => $validator->errors(),
], 422);
}
$payload = $validator->validated();
$total = $this->tuition->totalTuitionFee($payload['students']);
return response()->json([
@@ -3,7 +3,6 @@
namespace App\Http\Controllers\Api\Finance;
use App\Http\Controllers\Api\BaseApiController;
use App\Http\Requests\Invoices\InvoiceGenerateRequest;
use App\Http\Requests\Invoices\InvoiceManagementRequest;
use App\Http\Requests\Invoices\InvoiceParentRequest;
use App\Http\Requests\Invoices\InvoiceStatusRequest;
@@ -15,6 +14,8 @@ use App\Services\Invoices\InvoiceManagementService;
use App\Services\Invoices\InvoicePaymentService;
use App\Services\Invoices\InvoicePdfService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use Symfony\Component\HttpFoundation\StreamedResponse;
class InvoiceController extends BaseApiController
@@ -44,9 +45,22 @@ class InvoiceController extends BaseApiController
]);
}
public function generate(InvoiceGenerateRequest $request): JsonResponse
public function generate(Request $request): JsonResponse
{
$payload = $request->validated();
$data = array_merge($request->query->all(), $request->all(), $request->json()->all());
$validator = Validator::make($data, [
'parent_id' => ['required', 'integer', 'exists:users,id'],
'school_year' => ['nullable', 'string', 'max:20'],
]);
if ($validator->fails()) {
return response()->json([
'message' => 'Validation failed.',
'errors' => $validator->errors(),
], 422);
}
$payload = $validator->validated();
$result = $this->generation->generateInvoice((int) $payload['parent_id'], $payload['school_year'] ?? null);
if (empty($result['ok'])) {
@@ -4,13 +4,13 @@ namespace App\Http\Controllers\Api\Finance;
use App\Http\Controllers\Api\BaseApiController;
use App\Http\Requests\Payments\PaymentByParentRequest;
use App\Http\Requests\Payments\PaymentCreateRequest;
use App\Http\Requests\Payments\PaymentUpdateBalanceRequest;
use App\Http\Resources\Payments\PaymentResource;
use App\Services\Payments\PaymentBalanceService;
use App\Services\Payments\PaymentLookupService;
use App\Services\Payments\PaymentPlanService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
class PaymentController extends BaseApiController
{
@@ -22,9 +22,30 @@ class PaymentController extends BaseApiController
parent::__construct();
}
public function store(PaymentCreateRequest $request): JsonResponse
public function store(Request $request): JsonResponse
{
$payload = $request->validated();
$data = array_merge($request->query->all(), $request->all(), $request->json()->all());
$validator = Validator::make($data, [
'parent_id' => ['required', 'integer', 'exists:users,id'],
'invoice_id' => ['nullable', 'integer', 'exists:invoices,id'],
'total_amount' => ['required', 'numeric', 'min:0.01'],
'number_of_installments' => ['required', 'integer', 'min:1'],
'payment_date' => ['nullable', 'date'],
'payment_method' => ['nullable', 'string', 'max:50'],
'payment_type' => ['nullable', 'string', 'max:50'],
'status' => ['nullable', 'string', 'max:50'],
'semester' => ['nullable', 'string', 'max:50'],
'school_year' => ['nullable', 'string', 'max:50'],
]);
if ($validator->fails()) {
return response()->json([
'message' => 'Validation failed.',
'errors' => $validator->errors(),
], 422);
}
$payload = $validator->validated();
$payment = $this->planService->createPlan($payload);
return response()->json([
@@ -44,9 +65,21 @@ class PaymentController extends BaseApiController
]);
}
public function updateBalance(PaymentUpdateBalanceRequest $request, int $paymentId): JsonResponse
public function updateBalance(Request $request, int $paymentId): JsonResponse
{
$payload = $request->validated();
$data = array_merge($request->query->all(), $request->all(), $request->json()->all());
$validator = Validator::make($data, [
'paid_amount' => ['required', 'numeric', 'min:0.01'],
]);
if ($validator->fails()) {
return response()->json([
'message' => 'Validation failed.',
'errors' => $validator->errors(),
], 422);
}
$payload = $validator->validated();
$updated = $this->balanceService->updateBalance($paymentId, (float) $payload['paid_amount']);
if (!$updated) {
@@ -4,9 +4,10 @@ namespace App\Http\Controllers\Api\Finance;
use App\Http\Controllers\Api\BaseApiController;
use App\Http\Requests\Payments\PaymentEventChargesListRequest;
use App\Http\Requests\Payments\PaymentEventChargesStoreRequest;
use App\Services\Payments\PaymentEventChargesService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
class PaymentEventChargesController extends BaseApiController
{
@@ -23,9 +24,29 @@ class PaymentEventChargesController extends BaseApiController
return response()->json(['ok' => true] + $data);
}
public function store(PaymentEventChargesStoreRequest $request): JsonResponse
public function store(Request $request): JsonResponse
{
$payload = $request->validated();
$data = array_merge($request->query->all(), $request->all(), $request->json()->all());
$validator = Validator::make($data, [
'parent_id' => ['required', 'integer', 'min:1'],
'event_name' => ['required', 'string', 'max:255'],
'description' => ['nullable', 'string', 'max:1000'],
'amount' => ['required', 'numeric', 'min:0'],
'semester' => ['required', 'string', 'max:50'],
'school_year' => ['required', 'string', 'max:50'],
'student_ids' => ['nullable', 'array'],
'student_ids.*' => ['integer', 'min:1'],
'student_id' => ['nullable', 'integer', 'min:1'],
]);
if ($validator->fails()) {
return response()->json([
'message' => 'Validation failed.',
'errors' => $validator->errors(),
], 422);
}
$payload = $validator->validated();
$userId = (int) (auth()->id() ?? 0);
$count = $this->service->addCharges($payload, $userId);
@@ -4,12 +4,11 @@ namespace App\Http\Controllers\Api\Finance;
use App\Http\Controllers\Api\BaseApiController;
use App\Http\Requests\Payments\PaymentManualEditRequest;
use App\Http\Requests\Payments\PaymentManualSearchRequest;
use App\Http\Requests\Payments\PaymentManualSuggestRequest;
use App\Http\Requests\Payments\PaymentManualUpdateRequest;
use App\Services\Payments\PaymentManualService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
class PaymentManualController extends BaseApiController
{
@@ -18,9 +17,22 @@ class PaymentManualController extends BaseApiController
parent::__construct();
}
public function search(PaymentManualSearchRequest $request): JsonResponse
public function search(Request $request): JsonResponse
{
$payload = $request->validated();
$data = array_merge($request->query->all(), $request->all(), $request->json()->all());
$validator = Validator::make($data, [
'search_term' => ['nullable', 'string', 'max:255'],
'school_year' => ['nullable', 'string', 'max:50'],
]);
if ($validator->fails()) {
return response()->json([
'message' => 'Validation failed.',
'errors' => $validator->errors(),
], 422);
}
$payload = $validator->validated();
$data = $this->service->search(
(string) ($payload['search_term'] ?? ''),
$payload['school_year'] ?? null
@@ -29,9 +41,21 @@ class PaymentManualController extends BaseApiController
return response()->json(['ok' => true] + $data);
}
public function suggest(PaymentManualSuggestRequest $request): JsonResponse
public function suggest(Request $request): JsonResponse
{
$payload = $request->validated();
$data = array_merge($request->query->all(), $request->all(), $request->json()->all());
$validator = Validator::make($data, [
'q' => ['required', 'string', 'max:255'],
]);
if ($validator->fails()) {
return response()->json([
'message' => 'Validation failed.',
'errors' => $validator->errors(),
], 422);
}
$payload = $validator->validated();
$items = $this->service->suggest((string) ($payload['q'] ?? ''));
return response()->json(['ok' => true, 'items' => $items]);
@@ -3,11 +3,11 @@
namespace App\Http\Controllers\Api\Finance;
use App\Http\Controllers\Api\BaseApiController;
use App\Http\Requests\Payments\PaymentTransactionCreateRequest;
use App\Http\Resources\Payments\PaymentTransactionResource;
use App\Services\Payments\PaymentTransactionService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
class PaymentTransactionController extends BaseApiController
{
@@ -16,9 +16,31 @@ class PaymentTransactionController extends BaseApiController
parent::__construct();
}
public function store(PaymentTransactionCreateRequest $request): JsonResponse
public function store(Request $request): JsonResponse
{
$payload = $request->validated();
$data = array_merge($request->query->all(), $request->all(), $request->json()->all());
$validator = Validator::make($data, [
'transaction_id' => ['required', 'string', 'max:100'],
'payment_id' => ['required', 'integer', 'min:1'],
'transaction_date' => ['nullable', 'date'],
'amount' => ['required', 'numeric', 'min:0.01'],
'payment_method' => ['required', 'string', 'max:50'],
'payment_status' => ['nullable', 'string', 'max:50'],
'transaction_fee' => ['nullable', 'numeric', 'min:0'],
'payment_reference' => ['nullable', 'string', 'max:100'],
'is_full_payment' => ['nullable', 'boolean'],
'school_year' => ['nullable', 'string', 'max:50'],
'semester' => ['nullable', 'string', 'max:50'],
]);
if ($validator->fails()) {
return response()->json([
'message' => 'Validation failed.',
'errors' => $validator->errors(),
], 422);
}
$payload = $validator->validated();
$transaction = $this->service->create($payload);
return response()->json([
@@ -4,8 +4,6 @@ namespace App\Http\Controllers\Api\Finance;
use App\Http\Controllers\Api\BaseApiController;
use App\Http\Requests\PurchaseOrders\PurchaseOrderIndexRequest;
use App\Http\Requests\PurchaseOrders\PurchaseOrderReceiveRequest;
use App\Http\Requests\PurchaseOrders\PurchaseOrderStoreRequest;
use App\Http\Resources\PurchaseOrders\PurchaseOrderItemResource;
use App\Http\Resources\PurchaseOrders\PurchaseOrderResource;
use App\Models\PurchaseOrder;
@@ -14,6 +12,8 @@ use App\Services\PurchaseOrders\PurchaseOrderQueryService;
use App\Services\PurchaseOrders\PurchaseOrderReceiveService;
use App\Services\PurchaseOrders\PurchaseOrderStatusService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use RuntimeException;
class PurchaseOrderController extends BaseApiController
@@ -63,9 +63,41 @@ class PurchaseOrderController extends BaseApiController
]);
}
public function store(PurchaseOrderStoreRequest $request): JsonResponse
public function store(Request $request): JsonResponse
{
$payload = $request->validated();
$data = array_merge($request->query->all(), $request->all(), $request->json()->all());
$validator = Validator::make($data, [
'po_number' => ['required', 'string', 'max:60'],
'supplier_id' => ['required', 'integer', 'min:1', 'exists:suppliers,id'],
'status' => ['nullable', 'string', 'in:' . implode(',', PurchaseOrder::allowedStatuses())],
'order_date' => ['nullable', 'date'],
'expected_date' => ['nullable', 'date'],
'notes' => ['nullable', 'string', 'max:5000'],
'items' => ['required', 'array', 'min:1'],
'items.*.supply_id' => ['required', 'integer', 'min:1', 'exists:supplies,id'],
'items.*.description' => ['nullable', 'string', 'max:1000'],
'items.*.quantity' => ['required', 'integer', 'min:1'],
'items.*.unit_cost' => ['required', 'numeric', 'min:0'],
]);
if ($validator->fails()) {
return response()->json([
'message' => 'Validation failed.',
'errors' => $validator->errors(),
], 422);
}
$payload = $validator->validated();
if (!empty($payload['order_date']) && !empty($payload['expected_date'])) {
$orderTs = strtotime((string) $payload['order_date']);
$expectedTs = strtotime((string) $payload['expected_date']);
if ($orderTs !== false && $expectedTs !== false && $expectedTs < $orderTs) {
return response()->json([
'message' => 'Validation failed.',
'errors' => ['expected_date' => ['The expected date must be on or after the order date.']],
], 422);
}
}
try {
$po = $this->createService->create($payload);
@@ -81,9 +113,23 @@ class PurchaseOrderController extends BaseApiController
], 201);
}
public function receive(PurchaseOrderReceiveRequest $request, int $id): JsonResponse
public function receive(Request $request, int $id): JsonResponse
{
$payload = $request->validated();
$data = array_merge($request->query->all(), $request->all(), $request->json()->all());
$validator = Validator::make($data, [
'items' => ['required', 'array', 'min:1'],
'items.*.id' => ['required', 'integer', 'min:1'],
'items.*.quantity' => ['required', 'integer', 'min:1'],
]);
if ($validator->fails()) {
return response()->json([
'message' => 'Validation failed.',
'errors' => $validator->errors(),
], 422);
}
$payload = $validator->validated();
$po = PurchaseOrder::query()->find($id);
if (!$po) {
@@ -6,17 +6,13 @@ use App\Http\Controllers\Api\BaseApiController;
use App\Http\Requests\Files\FileNameRequest;
use App\Http\Requests\Reimbursements\ReimbursementBatchAdminFileRequest;
use App\Http\Requests\Reimbursements\ReimbursementBatchAssignmentRequest;
use App\Http\Requests\Reimbursements\ReimbursementBatchCreateRequest;
use App\Http\Requests\Reimbursements\ReimbursementBatchEmailRequest;
use App\Http\Requests\Reimbursements\ReimbursementBatchLockRequest;
use App\Http\Requests\Reimbursements\ReimbursementExportBatchRequest;
use App\Http\Requests\Reimbursements\ReimbursementExportRequest;
use App\Http\Requests\Reimbursements\ReimbursementIndexRequest;
use App\Http\Requests\Reimbursements\ReimbursementMarkDonationRequest;
use App\Http\Requests\Reimbursements\ReimbursementProcessRequest;
use App\Http\Requests\Reimbursements\ReimbursementStoreRequest;
use App\Http\Requests\Reimbursements\ReimbursementUnderProcessingRequest;
use App\Http\Requests\Reimbursements\ReimbursementUpdateRequest;
use App\Http\Resources\Reimbursements\ReimbursementBatchResource;
use App\Http\Resources\Reimbursements\ReimbursementExpenseResource;
use App\Http\Resources\Reimbursements\ReimbursementRecipientResource;
@@ -37,6 +33,7 @@ use App\Services\Reimbursements\ReimbursementQueryService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Validator;
use RuntimeException;
class ReimbursementController extends BaseApiController
@@ -69,9 +66,21 @@ class ReimbursementController extends BaseApiController
]);
}
public function markDonation(ReimbursementMarkDonationRequest $request): JsonResponse
public function markDonation(Request $request): JsonResponse
{
$payload = $request->validated();
$data = array_merge($request->query->all(), $request->all(), $request->json()->all());
$validator = Validator::make($data, [
'expense_id' => ['required', 'integer', 'min:1'],
]);
if ($validator->fails()) {
return response()->json([
'message' => 'Validation failed.',
'errors' => $validator->errors(),
], 422);
}
$payload = $validator->validated();
$userId = (int) (auth()->id() ?? 0);
try {
@@ -87,9 +96,21 @@ class ReimbursementController extends BaseApiController
return response()->json(['ok' => true]);
}
public function createBatch(ReimbursementBatchCreateRequest $request): JsonResponse
public function createBatch(Request $request): JsonResponse
{
$payload = $request->validated();
$data = array_merge($request->query->all(), $request->all(), $request->json()->all());
$validator = Validator::make($data, [
'title' => ['nullable', 'string', 'max:255'],
]);
if ($validator->fails()) {
return response()->json([
'message' => 'Validation failed.',
'errors' => $validator->errors(),
], 422);
}
$payload = $validator->validated();
$userId = (int) (auth()->id() ?? 0);
$schoolYear = $this->context->getSchoolYear();
$semester = $this->context->getSemester();
@@ -289,9 +310,29 @@ class ReimbursementController extends BaseApiController
]);
}
public function store(ReimbursementStoreRequest $request): JsonResponse
public function store(Request $request): JsonResponse
{
$payload = $request->validated();
$data = array_merge($request->query->all(), $request->all(), $request->json()->all());
$validator = Validator::make($data, [
'amount' => ['required', 'numeric', 'gt:0'],
'reimbursed_to' => ['required', 'integer', 'min:1'],
'reimbursement_method' => ['required', 'in:Cash,Check'],
'check_number' => ['required_if:reimbursement_method,Check', 'nullable', 'string', 'max:50'],
'receipt' => ['required_if:reimbursement_method,Check', 'nullable', 'file', 'max:2048', 'mimes:jpg,jpeg,png,webp,gif,pdf'],
'expense_id' => ['nullable', 'integer', 'min:1'],
'description' => ['nullable', 'string'],
'school_year' => ['nullable', 'string', 'max:20'],
'semester' => ['nullable', 'string', 'max:20'],
]);
if ($validator->fails()) {
return response()->json([
'message' => 'Validation failed.',
'errors' => $validator->errors(),
], 422);
}
$payload = $validator->validated();
$userId = (int) (auth()->id() ?? 0);
$receiptName = null;
@@ -361,14 +402,32 @@ class ReimbursementController extends BaseApiController
]);
}
public function update(ReimbursementUpdateRequest $request, int $id): JsonResponse
public function update(Request $request, int $id): JsonResponse
{
$reimb = Reimbursement::query()->find($id);
if (!$reimb) {
return response()->json(['ok' => false, 'message' => 'Reimbursement not found.'], 404);
}
$payload = $request->validated();
$data = array_merge($request->query->all(), $request->all(), $request->json()->all());
$validator = Validator::make($data, [
'amount' => ['required', 'numeric', 'gt:0'],
'reimbursed_to' => ['required', 'integer', 'min:1'],
'reimbursement_method' => ['required', 'in:Cash,Check'],
'check_number' => ['required_if:reimbursement_method,Check', 'nullable', 'string', 'max:50'],
'receipt' => ['nullable', 'file', 'max:2048', 'mimes:jpg,jpeg,png,webp,gif,pdf'],
'remove_receipt' => ['nullable', 'boolean'],
'description' => ['nullable', 'string'],
]);
if ($validator->fails()) {
return response()->json([
'message' => 'Validation failed.',
'errors' => $validator->errors(),
], 422);
}
$payload = $validator->validated();
$userId = (int) (auth()->id() ?? 0);
$receiptName = $reimb->receipt_path;