add test batches
This commit is contained in:
@@ -7,7 +7,6 @@ class FeeGradeService
|
||||
public function normalizeGrade(?string $grade): string
|
||||
{
|
||||
$normalized = strtoupper(trim((string) $grade));
|
||||
|
||||
return str_replace([' ', '-'], '', $normalized);
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,8 @@ class FeeRefundCalculatorService
|
||||
public function __construct(
|
||||
private FeeConfigService $config,
|
||||
private FeeStudentFeeService $studentFees
|
||||
) {}
|
||||
) {
|
||||
}
|
||||
|
||||
public function calculateRefund(array $students, int $parentId): array
|
||||
{
|
||||
@@ -25,7 +26,6 @@ class FeeRefundCalculatorService
|
||||
'parent_id' => $parentId,
|
||||
'school_year' => $schoolYear,
|
||||
]);
|
||||
|
||||
return $this->resultPayload(0.0, $totalPaid, $refundDeadline, $schoolEndDate, $weeksOfStudy, 0, []);
|
||||
}
|
||||
|
||||
@@ -36,7 +36,6 @@ class FeeRefundCalculatorService
|
||||
'parent_id' => $parentId,
|
||||
'registered_count' => count($registered),
|
||||
]);
|
||||
|
||||
return $this->resultPayload(0.0, $totalPaid, $refundDeadline, $schoolEndDate, $weeksOfStudy, 0, []);
|
||||
}
|
||||
|
||||
@@ -58,7 +57,7 @@ class FeeRefundCalculatorService
|
||||
|
||||
$withdrawnWithFees = array_values(array_filter(
|
||||
$allStudents,
|
||||
fn (array $student): bool => ! empty($student['_is_withdrawn'])
|
||||
fn (array $student): bool => !empty($student['_is_withdrawn'])
|
||||
));
|
||||
|
||||
$refundAmount = 0.0;
|
||||
@@ -83,32 +82,29 @@ class FeeRefundCalculatorService
|
||||
'reason' => null,
|
||||
];
|
||||
|
||||
if (! $withdrawalDate) {
|
||||
if (!$withdrawalDate) {
|
||||
$entry['reason'] = 'missing_withdrawal_date';
|
||||
Log::warning('Refund skipped for student: missing withdrawal date', [
|
||||
'parent_id' => $parentId,
|
||||
'student_id' => $studentId,
|
||||
]);
|
||||
$studentBreakdown[] = $entry;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (! $refundDeadline || strtotime($withdrawalDate) > strtotime($refundDeadline)) {
|
||||
if (!$refundDeadline || strtotime($withdrawalDate) > strtotime($refundDeadline)) {
|
||||
$entry['reason'] = 'after_refund_deadline';
|
||||
$studentBreakdown[] = $entry;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (! $schoolEndDate) {
|
||||
if (!$schoolEndDate) {
|
||||
$entry['reason'] = 'missing_school_end_date';
|
||||
Log::warning('Refund skipped for student: missing school end date', [
|
||||
'parent_id' => $parentId,
|
||||
'student_id' => $studentId,
|
||||
]);
|
||||
$studentBreakdown[] = $entry;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -121,7 +117,6 @@ class FeeRefundCalculatorService
|
||||
'weeks_of_study' => $weeksOfStudy,
|
||||
]);
|
||||
$studentBreakdown[] = $entry;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -158,7 +153,7 @@ class FeeRefundCalculatorService
|
||||
if ($uncappedRefund > 0) {
|
||||
$ratio = $totalPaid / $uncappedRefund;
|
||||
foreach ($studentBreakdown as &$row) {
|
||||
if (! empty($row['eligible'])) {
|
||||
if (!empty($row['eligible'])) {
|
||||
$row['refund_amount'] = round($row['refund_amount'] * $ratio, 2);
|
||||
}
|
||||
}
|
||||
@@ -197,7 +192,6 @@ class FeeRefundCalculatorService
|
||||
foreach ($students as $student) {
|
||||
if ($this->studentFees->isWithdrawn($student)) {
|
||||
$withdrawn[] = $student;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -219,7 +213,6 @@ class FeeRefundCalculatorService
|
||||
}
|
||||
|
||||
$daysRemaining = $withdrawDateObj->diff($schoolEndDateObj)->days;
|
||||
|
||||
return (int) min($weeksOfStudy, max(0, (int) ceil($daysRemaining / 7)));
|
||||
}
|
||||
|
||||
|
||||
@@ -37,12 +37,11 @@ class FeeRefundDetailService
|
||||
$tuitionStudents = $registeredKids;
|
||||
foreach ($withdrawnKids as $kid) {
|
||||
$rawDate = $kid['withdrawal_date'] ?? null;
|
||||
if (empty($rawDate) || ! $deadline) {
|
||||
if (empty($rawDate) || !$deadline) {
|
||||
Log::warning('Missing withdrawal date or deadline; billing withdrawn student.', [
|
||||
'student_id' => $kid['student_id'] ?? null,
|
||||
]);
|
||||
$tuitionStudents[] = $kid;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -53,7 +52,6 @@ class FeeRefundDetailService
|
||||
'student_id' => $kid['student_id'] ?? null,
|
||||
]);
|
||||
$tuitionStudents[] = $kid;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -64,13 +62,12 @@ class FeeRefundDetailService
|
||||
|
||||
$tuitionStudents = array_values(array_filter($tuitionStudents, function ($student) use ($schoolYear) {
|
||||
$sid = (int) ($student['student_id'] ?? 0);
|
||||
|
||||
return $sid > 0 && StudentClass::hasNonEventAssignment($sid, $schoolYear);
|
||||
}));
|
||||
|
||||
foreach ($tuitionStudents as &$student) {
|
||||
$name = null;
|
||||
if (! empty($student['class_section_id'])) {
|
||||
if (!empty($student['class_section_id'])) {
|
||||
$name = ClassSection::getClassSectionNameBySectionId($student['class_section_id']);
|
||||
}
|
||||
$student['grade_name'] = is_string($name) ? strtoupper(trim($name)) : 'N/A';
|
||||
@@ -132,7 +129,7 @@ class FeeRefundDetailService
|
||||
if ($bookPriceRaw === null || $bookPriceRaw === '') {
|
||||
return ['ok' => false, 'error' => 'Book price is not configured.'];
|
||||
}
|
||||
if (! is_numeric($bookPriceRaw)) {
|
||||
if (!is_numeric($bookPriceRaw)) {
|
||||
return ['ok' => false, 'error' => 'Book price must be numeric.'];
|
||||
}
|
||||
$bookPrice = round((float) $bookPriceRaw, 2);
|
||||
@@ -149,10 +146,9 @@ class FeeRefundDetailService
|
||||
$status = (string) ($student['enrollment_status'] ?? '');
|
||||
if (in_array($status, ['enrolled', 'payment pending'], true)) {
|
||||
$registered[] = $student;
|
||||
|
||||
continue;
|
||||
}
|
||||
if (! in_array($status, ['withdrawn', 'refund pending', 'withdraw under review'], true)) {
|
||||
if (!in_array($status, ['withdrawn', 'refund pending', 'withdraw under review'], true)) {
|
||||
continue;
|
||||
}
|
||||
$hasWithdrawn = true;
|
||||
@@ -173,7 +169,7 @@ class FeeRefundDetailService
|
||||
}
|
||||
}
|
||||
|
||||
if (! $hasWithdrawn) {
|
||||
if (!$hasWithdrawn) {
|
||||
return ['ok' => false, 'error' => 'No withdrawn students found for refund evaluation.'];
|
||||
}
|
||||
|
||||
@@ -207,7 +203,7 @@ class FeeRefundDetailService
|
||||
}
|
||||
}
|
||||
|
||||
$eligible = ! empty($withdrawnEligible);
|
||||
$eligible = !empty($withdrawnEligible);
|
||||
|
||||
$refundAmount = 0.0;
|
||||
$debitAmount = 0.0;
|
||||
@@ -234,9 +230,9 @@ class FeeRefundDetailService
|
||||
|
||||
$refundableCash = min($totalPaid, $refundableTuition);
|
||||
$raw = round($refundableCash - $bookPrice, 2);
|
||||
if ($raw > 0 && ! $fullDiscount) {
|
||||
if ($raw > 0 && !$fullDiscount) {
|
||||
$refundAmount = $raw;
|
||||
} elseif ($raw < 0 && ! $fullDiscount) {
|
||||
} elseif ($raw < 0 && !$fullDiscount) {
|
||||
$debitAmount = abs($raw);
|
||||
}
|
||||
}
|
||||
@@ -263,7 +259,6 @@ class FeeRefundDetailService
|
||||
public function calculateRefund(array $students, int $parentId): float
|
||||
{
|
||||
$result = $this->calculateRefundDetails($students, $parentId);
|
||||
|
||||
return (float) ($result['refund_amount'] ?? 0.0);
|
||||
}
|
||||
|
||||
@@ -271,7 +266,6 @@ class FeeRefundDetailService
|
||||
{
|
||||
$resolvedGradeFee = $gradeFee ?? (int) (Configuration::getConfig('grade_fee') ?? 9);
|
||||
$grades = new InvoiceGradeService($resolvedGradeFee);
|
||||
|
||||
return $grades->getGradeLevel($grade);
|
||||
}
|
||||
|
||||
@@ -279,7 +273,6 @@ class FeeRefundDetailService
|
||||
{
|
||||
$resolvedGradeFee = $gradeFee ?? (int) (Configuration::getConfig('grade_fee') ?? 9);
|
||||
$grades = new InvoiceGradeService($resolvedGradeFee);
|
||||
|
||||
return $grades->compareGrades((string) $gradeA, (string) $gradeB);
|
||||
}
|
||||
|
||||
|
||||
@@ -8,23 +8,19 @@ use Illuminate\Support\Facades\Log;
|
||||
class FeeStudentFeeService
|
||||
{
|
||||
public const CATEGORY_FIRST_REGULAR = 'first_regular';
|
||||
|
||||
public const CATEGORY_ADDITIONAL_REGULAR = 'additional_regular';
|
||||
|
||||
public const CATEGORY_YOUTH = 'youth';
|
||||
|
||||
public const CATEGORY_NOT_BILLABLE = 'not_billable';
|
||||
|
||||
private const BILLABLE_ENROLLMENT_STATUSES = ['enrolled', 'payment pending'];
|
||||
|
||||
private const WITHDRAWN_ENROLLMENT_STATUSES = ['withdrawn', 'refund pending', 'withdraw under review'];
|
||||
|
||||
private const ACCEPTED_ADMISSION_STATUS = 'accepted';
|
||||
|
||||
public function __construct(
|
||||
private FeeGradeService $grades,
|
||||
private FeeConfigService $config
|
||||
) {}
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize grades, sort by grade level, and assign a tuition fee to each
|
||||
@@ -134,7 +130,6 @@ class FeeStudentFeeService
|
||||
$nonBillable = array_map(function (array $student): array {
|
||||
$student['fee_category'] = self::CATEGORY_NOT_BILLABLE;
|
||||
$student['tuition_fee'] = 0.0;
|
||||
|
||||
return $student;
|
||||
}, $nonBillable);
|
||||
|
||||
@@ -153,7 +148,7 @@ class FeeStudentFeeService
|
||||
|
||||
$studentRows[] = [
|
||||
'student_id' => $student['student_id'] ?? null,
|
||||
'student_name' => trim(($student['firstname'] ?? '').' '.($student['lastname'] ?? '')),
|
||||
'student_name' => trim(($student['firstname'] ?? '') . ' ' . ($student['lastname'] ?? '')),
|
||||
'grade' => $student['grade'] ?? null,
|
||||
'grade_level' => $student['grade_level'] ?? null,
|
||||
'enrollment_status' => $student['enrollment_status'] ?? null,
|
||||
@@ -197,7 +192,6 @@ class FeeStudentFeeService
|
||||
public function isWithdrawn(array $student): bool
|
||||
{
|
||||
$status = strtolower((string) ($student['enrollment_status'] ?? ''));
|
||||
|
||||
return in_array($status, self::WITHDRAWN_ENROLLMENT_STATUSES, true);
|
||||
}
|
||||
|
||||
|
||||
@@ -23,14 +23,16 @@ class TuitionCalculationService
|
||||
public function __construct(
|
||||
private FeeConfigService $config,
|
||||
private FeeStudentFeeService $studentFees
|
||||
) {}
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Produce a family + per-student tuition calculation.
|
||||
*
|
||||
* @param array $students Each item may include: student_id, firstname,
|
||||
* lastname, grade, class_section_id, enrollment_status,
|
||||
* admission_status, discount_amount.
|
||||
* @param array $students Each item may include: student_id, firstname,
|
||||
* lastname, grade, class_section_id, enrollment_status,
|
||||
* admission_status, discount_amount.
|
||||
*
|
||||
* @return array{
|
||||
* school_year: string,
|
||||
* fees: array<string, float>,
|
||||
|
||||
Reference in New Issue
Block a user