fix the forecast tuition
This commit is contained in:
@@ -74,7 +74,7 @@ class InvoiceController extends ResourceController
|
||||
$this->dueDate = $this->configModel->getConfig('due_date');
|
||||
$this->firstStudentFee = (float) ($this->configModel->getConfig('first_student_fee') ?? 350);
|
||||
$this->secondStudentFee = (float) ($this->configModel->getConfig('second_student_fee') ?? 200);
|
||||
$this->youthFee = (float) ($this->configModel->getConfig('youth_fee') ?? 180);
|
||||
$this->youthFee = (float) ($this->configModel->getConfig('youth_fee') ?? 200);
|
||||
$this->refundDeadline = date('Y-m-d', strtotime($this->configModel->getConfig('refund_deadline')));
|
||||
$this->db = \Config\Database::connect();
|
||||
$this->request = \Config\Services::request();
|
||||
|
||||
@@ -71,12 +71,13 @@ class TuitionForecastController extends BaseController
|
||||
fputcsv($handle, ['Calculator Mode', $result['calculator_mode']]);
|
||||
fputcsv($handle, []);
|
||||
fputcsv($handle, ['Summary']);
|
||||
fputcsv($handle, ['Families', 'Students', 'Billable Students', 'Unit Price', 'Old Projected Income', 'New Projected Income', 'Difference']);
|
||||
fputcsv($handle, ['Families', 'Students', 'Billable Students', 'Grade Unit Price', 'Youth Unit Price', 'Old Projected Income', 'New Projected Income', 'Difference']);
|
||||
fputcsv($handle, [
|
||||
$result['summary']['family_count'],
|
||||
$result['summary']['student_count'],
|
||||
$result['summary']['billable_student_count'],
|
||||
$result['summary']['unit_price'],
|
||||
$result['summary']['youth_unit_price'],
|
||||
$result['summary']['old_projected_income'] ?? $result['summary']['old_projected_tuition'],
|
||||
$result['summary']['new_projected_income'] ?? $result['summary']['new_projected_tuition'],
|
||||
$result['summary']['difference'],
|
||||
@@ -132,6 +133,7 @@ class TuitionForecastController extends BaseController
|
||||
'include_event_only' => $this->request->{$source}('include_event_only') ?? '0',
|
||||
'include_paid_invoices' => $this->request->{$source}('include_paid_invoices') ?? '0',
|
||||
'unit_price' => $this->request->{$source}('unit_price') ?? '',
|
||||
'youth_unit_price' => $this->request->{$source}('youth_unit_price') ?? '',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,7 +94,9 @@ class FinancialSystemLedgerCleanup extends Migration
|
||||
|
||||
$defaults = [
|
||||
'tuition_calculator_version' => 'old',
|
||||
'youth_fee' => '200.00',
|
||||
'new_tuition_full_amount' => '370.00',
|
||||
'new_tuition_youth_amount' => '200.00',
|
||||
'new_tuition_second_student_discount' => '50.00',
|
||||
'new_tuition_third_student_discount' => '50.00',
|
||||
'new_tuition_fourth_plus_discount' => '100.00',
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class UpdateYouthTuitionDefaults extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
if (!$this->db->tableExists('configuration')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->upsertConfig('youth_fee', '200.00', ['180', '180.00']);
|
||||
$this->upsertConfig('new_tuition_youth_amount', '200.00', ['180', '180.00']);
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
if (!$this->db->tableExists('configuration')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->rollbackConfig('youth_fee', '180.00');
|
||||
$this->rollbackConfig('new_tuition_youth_amount', '180.00');
|
||||
}
|
||||
|
||||
protected function upsertConfig(string $key, string $value, array $legacyValues = []): void
|
||||
{
|
||||
$row = $this->db->table('configuration')
|
||||
->select('id, config_value')
|
||||
->where('config_key', $key)
|
||||
->orderBy('id', 'ASC')
|
||||
->get()
|
||||
->getRowArray();
|
||||
|
||||
if (!$row) {
|
||||
$this->db->table('configuration')->insert([
|
||||
'config_key' => $key,
|
||||
'config_value' => $value,
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
$current = trim((string) ($row['config_value'] ?? ''));
|
||||
if ($current === '' || in_array($current, $legacyValues, true)) {
|
||||
$this->db->table('configuration')
|
||||
->where('config_key', $key)
|
||||
->update(['config_value' => $value]);
|
||||
}
|
||||
}
|
||||
|
||||
protected function rollbackConfig(string $key, string $value): void
|
||||
{
|
||||
$this->db->table('configuration')
|
||||
->where('config_key', $key)
|
||||
->where('config_value', '200.00')
|
||||
->update(['config_value' => $value]);
|
||||
}
|
||||
}
|
||||
@@ -307,6 +307,7 @@ class InvoiceLedgerService
|
||||
'second_student_fee' => $this->configurationModel->getConfig('second_student_fee'),
|
||||
'youth_fee' => $this->configurationModel->getConfig('youth_fee'),
|
||||
'new_tuition_full_amount' => $this->configurationModel->getConfig('new_tuition_full_amount'),
|
||||
'new_tuition_youth_amount' => $this->configurationModel->getConfig('new_tuition_youth_amount'),
|
||||
'new_tuition_second_student_discount' => $this->configurationModel->getConfig('new_tuition_second_student_discount'),
|
||||
'new_tuition_third_student_discount' => $this->configurationModel->getConfig('new_tuition_third_student_discount'),
|
||||
'new_tuition_fourth_plus_discount' => $this->configurationModel->getConfig('new_tuition_fourth_plus_discount'),
|
||||
|
||||
@@ -10,6 +10,7 @@ final class NewTuitionCalculatorService implements TuitionCalculatorInterface
|
||||
{
|
||||
$gradeFee = (int) ($config['grade_fee'] ?? 9);
|
||||
$fullAmountCents = $this->toCents($config['new_tuition_full_amount'] ?? 370);
|
||||
$youthAmountCents = $this->toCents($config['new_tuition_youth_amount'] ?? $config['youth_fee'] ?? 200);
|
||||
$secondDiscountCents = $this->toCents($config['new_tuition_second_student_discount'] ?? 50);
|
||||
$thirdDiscountCents = $this->toCents($config['new_tuition_third_student_discount'] ?? 50);
|
||||
$fourthPlusDiscountCents = $this->toCents($config['new_tuition_fourth_plus_discount'] ?? 100);
|
||||
@@ -22,32 +23,45 @@ final class NewTuitionCalculatorService implements TuitionCalculatorInterface
|
||||
});
|
||||
|
||||
$details = [];
|
||||
$regularPosition = 0;
|
||||
|
||||
foreach (array_values($students) as $index => $student) {
|
||||
$position = $index + 1;
|
||||
foreach (array_values($students) as $student) {
|
||||
$level = GradeLevelParser::parse($student['grade_level'] ?? null, $gradeFee);
|
||||
|
||||
if ($position === 1) {
|
||||
if ($level > $gradeFee) {
|
||||
$position = null;
|
||||
$discountCents = 0;
|
||||
$rule = 'new_first_student_full_amount';
|
||||
} elseif ($position === 2) {
|
||||
$discountCents = $secondDiscountCents;
|
||||
$rule = 'new_second_student_discount';
|
||||
} elseif ($position === 3) {
|
||||
$discountCents = $thirdDiscountCents;
|
||||
$rule = 'new_third_student_discount';
|
||||
$rule = 'new_youth_unit_price';
|
||||
$baseAmountCents = $youthAmountCents;
|
||||
} else {
|
||||
$discountCents = $fourthPlusDiscountCents;
|
||||
$rule = 'new_fourth_plus_student_discount';
|
||||
$regularPosition++;
|
||||
$position = $regularPosition;
|
||||
|
||||
if ($position === 1) {
|
||||
$discountCents = 0;
|
||||
$rule = 'new_first_student_full_amount';
|
||||
} elseif ($position === 2) {
|
||||
$discountCents = $secondDiscountCents;
|
||||
$rule = 'new_second_student_discount';
|
||||
} elseif ($position === 3) {
|
||||
$discountCents = $thirdDiscountCents;
|
||||
$rule = 'new_third_student_discount';
|
||||
} else {
|
||||
$discountCents = $fourthPlusDiscountCents;
|
||||
$rule = 'new_fourth_plus_student_discount';
|
||||
}
|
||||
|
||||
$baseAmountCents = $fullAmountCents;
|
||||
}
|
||||
|
||||
$amountCents = max(0, $fullAmountCents - $discountCents);
|
||||
$amountCents = max(0, $baseAmountCents - $discountCents);
|
||||
|
||||
$details[] = [
|
||||
'student_id' => (int) ($student['student_id'] ?? 0),
|
||||
'student_name' => (string) ($student['student_name'] ?? ''),
|
||||
'grade_level' => $student['grade_level'] ?? null,
|
||||
'family_position' => $position,
|
||||
'full_amount' => $this->fromCents($fullAmountCents),
|
||||
'full_amount' => $this->fromCents($baseAmountCents),
|
||||
'discount' => $this->fromCents($discountCents),
|
||||
'rule' => $rule,
|
||||
'amount' => $this->fromCents($amountCents),
|
||||
|
||||
@@ -11,7 +11,7 @@ final class OldTuitionCalculatorService implements TuitionCalculatorInterface
|
||||
$gradeFee = (int) ($config['grade_fee'] ?? 9);
|
||||
$firstStudentFee = $this->toCents($config['first_student_fee'] ?? 370);
|
||||
$secondStudentFee = $this->toCents($config['second_student_fee'] ?? 200);
|
||||
$youthFee = $this->toCents($config['youth_fee'] ?? 180);
|
||||
$youthFee = $this->toCents($config['youth_fee'] ?? 200);
|
||||
|
||||
usort($students, function (array $left, array $right) use ($gradeFee): int {
|
||||
$leftLevel = GradeLevelParser::parse($left['grade_level'] ?? null, $gradeFee);
|
||||
|
||||
@@ -43,6 +43,7 @@ class TuitionForecastService
|
||||
$mode = $this->normalizeMode($mode);
|
||||
$options = $this->normalizeOptions($options);
|
||||
$this->unitPriceOverride = $options['unit_price'];
|
||||
$this->youthUnitPriceOverride = $options['youth_unit_price'];
|
||||
$tuitionConfig = $this->getTuitionConfig();
|
||||
$familyRows = [];
|
||||
$summary = [
|
||||
@@ -57,6 +58,7 @@ class TuitionForecastService
|
||||
'projected_tuition' => '0.00',
|
||||
'projected_income' => '0.00',
|
||||
'unit_price' => '0.00',
|
||||
'youth_unit_price' => '0.00',
|
||||
];
|
||||
|
||||
$oldProjectedCents = 0;
|
||||
@@ -117,6 +119,7 @@ class TuitionForecastService
|
||||
$summary['projected_tuition'] = $mode === 'old' ? $summary['old_projected_tuition'] : $summary['new_projected_tuition'];
|
||||
$summary['projected_income'] = $mode === 'old' ? $summary['old_projected_income'] : $summary['new_projected_income'];
|
||||
$summary['unit_price'] = number_format((float) ($tuitionConfig['new_tuition_full_amount'] ?? 0), 2, '.', '');
|
||||
$summary['youth_unit_price'] = number_format((float) ($tuitionConfig['new_tuition_youth_amount'] ?? 0), 2, '.', '');
|
||||
|
||||
return [
|
||||
'school_year' => $schoolYear,
|
||||
@@ -232,6 +235,7 @@ class TuitionForecastService
|
||||
'include_event_only' => $this->toBool($options['include_event_only'] ?? false),
|
||||
'include_paid_invoices' => $this->toBool($options['include_paid_invoices'] ?? true),
|
||||
'unit_price' => $this->normalizeMoney($options['unit_price'] ?? null),
|
||||
'youth_unit_price' => $this->normalizeMoney($options['youth_unit_price'] ?? null),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -541,8 +545,9 @@ class TuitionForecastService
|
||||
'grade_fee' => $this->configurationModel->getConfig('grade_fee'),
|
||||
'first_student_fee' => $this->configurationModel->getConfig('first_student_fee'),
|
||||
'second_student_fee' => $this->configurationModel->getConfig('second_student_fee'),
|
||||
'youth_fee' => $this->configurationModel->getConfig('youth_fee'),
|
||||
'youth_fee' => $this->configurationModel->getConfig('youth_fee') ?? '200.00',
|
||||
'new_tuition_full_amount' => $this->normalizedUnitPriceOverride(),
|
||||
'new_tuition_youth_amount' => $this->normalizedYouthUnitPriceOverride(),
|
||||
'new_tuition_second_student_discount' => $this->configurationModel->getConfig('new_tuition_second_student_discount'),
|
||||
'new_tuition_third_student_discount' => $this->configurationModel->getConfig('new_tuition_third_student_discount'),
|
||||
'new_tuition_fourth_plus_discount' => $this->configurationModel->getConfig('new_tuition_fourth_plus_discount'),
|
||||
@@ -550,6 +555,7 @@ class TuitionForecastService
|
||||
}
|
||||
|
||||
protected ?string $unitPriceOverride = null;
|
||||
protected ?string $youthUnitPriceOverride = null;
|
||||
|
||||
protected function normalizedUnitPriceOverride(): string
|
||||
{
|
||||
@@ -557,6 +563,16 @@ class TuitionForecastService
|
||||
?? (string) ($this->configurationModel->getConfig('new_tuition_full_amount') ?? '0.00');
|
||||
}
|
||||
|
||||
protected function normalizedYouthUnitPriceOverride(): string
|
||||
{
|
||||
return $this->youthUnitPriceOverride
|
||||
?? (string) (
|
||||
$this->configurationModel->getConfig('new_tuition_youth_amount')
|
||||
?? $this->configurationModel->getConfig('youth_fee')
|
||||
?? '200.00'
|
||||
);
|
||||
}
|
||||
|
||||
protected function normalizeMoney($value): ?string
|
||||
{
|
||||
if ($value === null || trim((string) $value) === '') {
|
||||
|
||||
@@ -61,7 +61,7 @@ class FeeCalculationService
|
||||
// Retrieve fee configs
|
||||
$firstStudentFee = (float) ($configModel->getConfig('first_student_fee') ?? 350);
|
||||
$secondStudentFee = (float) ($configModel->getConfig('second_student_fee') ?? 200);
|
||||
$youthFee = (float) ($configModel->getConfig('youth_fee') ?? 180);
|
||||
$youthFee = (float) ($configModel->getConfig('youth_fee') ?? 200);
|
||||
|
||||
// Assign tuition_fee to all students (before filtering refunds)
|
||||
$regularCount = 0;
|
||||
@@ -148,7 +148,7 @@ class FeeCalculationService
|
||||
|
||||
$firstStudentFee = (float) ($configModel->getConfig('first_student_fee') ?? 350);
|
||||
$secondStudentFee = (float) ($configModel->getConfig('second_student_fee') ?? 200);
|
||||
$youthFee = (float) ($configModel->getConfig('youth_fee') ?? 180);
|
||||
$youthFee = (float) ($configModel->getConfig('youth_fee') ?? 200);
|
||||
|
||||
// ✅ Pre-fetch and assign grade/class section names before sorting
|
||||
foreach ($students as &$student) {
|
||||
|
||||
@@ -30,6 +30,7 @@ $warningText = static function (array $warnings): string {
|
||||
'include_event_only' => !empty($filters['include_event_only']) ? '1' : '0',
|
||||
'include_paid_invoices' => !empty($filters['include_paid_invoices']) ? '1' : '0',
|
||||
'unit_price' => $filters['unit_price'] ?? '',
|
||||
'youth_unit_price' => $filters['youth_unit_price'] ?? '',
|
||||
]);
|
||||
?>
|
||||
<a href="<?= site_url('administrator/tuition-forecast/export?' . $exportQuery) ?>" class="btn btn-success">
|
||||
@@ -79,7 +80,7 @@ $warningText = static function (array $warnings): string {
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label for="unit_price" class="form-label">Unit Price</label>
|
||||
<label for="unit_price" class="form-label">Grades Unit Price</label>
|
||||
<input
|
||||
type="number"
|
||||
min="0"
|
||||
@@ -88,7 +89,19 @@ $warningText = static function (array $warnings): string {
|
||||
name="unit_price"
|
||||
class="form-control"
|
||||
value="<?= esc((string) ($filters['unit_price'] ?? ($summary['unit_price'] ?? ''))) ?>"
|
||||
placeholder="New tuition unit price">
|
||||
placeholder="New tuition unit price for grades">
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label for="youth_unit_price" class="form-label">Youth Unit Price</label>
|
||||
<input
|
||||
type="number"
|
||||
min="0"
|
||||
step="0.01"
|
||||
id="youth_unit_price"
|
||||
name="youth_unit_price"
|
||||
class="form-control"
|
||||
value="<?= esc((string) ($filters['youth_unit_price'] ?? ($summary['youth_unit_price'] ?? ''))) ?>"
|
||||
placeholder="New tuition unit price for youth">
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<div class="form-check">
|
||||
@@ -109,7 +122,7 @@ $warningText = static function (array $warnings): string {
|
||||
|
||||
<?php if ($result): ?>
|
||||
<div class="row g-3 mb-4">
|
||||
<div class="col-md-2">
|
||||
<div class="col-xl col-lg-3 col-md-4">
|
||||
<div class="card border-0 shadow-sm h-100">
|
||||
<div class="card-body">
|
||||
<div class="text-muted small">Total Parents</div>
|
||||
@@ -117,7 +130,7 @@ $warningText = static function (array $warnings): string {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<div class="col-xl col-lg-3 col-md-4">
|
||||
<div class="card border-0 shadow-sm h-100">
|
||||
<div class="card-body">
|
||||
<div class="text-muted small">Total Students</div>
|
||||
@@ -126,7 +139,7 @@ $warningText = static function (array $warnings): string {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<div class="col-xl col-lg-3 col-md-4">
|
||||
<div class="card border-0 shadow-sm h-100">
|
||||
<div class="card-body">
|
||||
<div class="text-muted small">Old Projected Income</div>
|
||||
@@ -134,7 +147,7 @@ $warningText = static function (array $warnings): string {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<div class="col-xl col-lg-3 col-md-4">
|
||||
<div class="card border-0 shadow-sm h-100">
|
||||
<div class="card-body">
|
||||
<div class="text-muted small">New Projected Income</div>
|
||||
@@ -142,15 +155,23 @@ $warningText = static function (array $warnings): string {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<div class="col-xl col-lg-3 col-md-4">
|
||||
<div class="card border-0 shadow-sm h-100">
|
||||
<div class="card-body">
|
||||
<div class="text-muted small">Unit Price</div>
|
||||
<div class="text-muted small">Grades Unit Price</div>
|
||||
<div class="fs-5 fw-semibold"><?= esc($fmtMoney($summary['unit_price'] ?? 0)) ?></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<div class="col-xl col-lg-3 col-md-4">
|
||||
<div class="card border-0 shadow-sm h-100">
|
||||
<div class="card-body">
|
||||
<div class="text-muted small">Youth Unit Price</div>
|
||||
<div class="fs-5 fw-semibold"><?= esc($fmtMoney($summary['youth_unit_price'] ?? 0)) ?></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl col-lg-3 col-md-4">
|
||||
<div class="card border-0 shadow-sm h-100">
|
||||
<div class="card-body">
|
||||
<div class="text-muted small">Difference</div>
|
||||
|
||||
@@ -65,6 +65,7 @@ class FakeForecastService extends TuitionForecastService
|
||||
'include_event_only' => $options['include_event_only'] ?? '0',
|
||||
'include_paid_invoices' => $options['include_paid_invoices'] ?? '0',
|
||||
'unit_price' => $options['unit_price'] ?? '370.00',
|
||||
'youth_unit_price' => $options['youth_unit_price'] ?? '200.00',
|
||||
],
|
||||
'summary' => [
|
||||
'family_count' => 1,
|
||||
@@ -75,6 +76,7 @@ class FakeForecastService extends TuitionForecastService
|
||||
'old_projected_income' => '550.00',
|
||||
'new_projected_income' => '650.00',
|
||||
'unit_price' => '370.00',
|
||||
'youth_unit_price' => '200.00',
|
||||
'difference' => '100.00',
|
||||
],
|
||||
'families' => [[
|
||||
@@ -160,6 +162,7 @@ class TuitionForecastControllerTest extends CIUnitTestCase
|
||||
'include_event_only' => '1',
|
||||
'include_paid_invoices' => '1',
|
||||
'unit_price' => '395.00',
|
||||
'youth_unit_price' => '200.00',
|
||||
]);
|
||||
|
||||
$result = $this->controller->setRequestObject($request)->index();
|
||||
@@ -170,6 +173,7 @@ class TuitionForecastControllerTest extends CIUnitTestCase
|
||||
$this->assertSame('new', $result['data']['filters']['calculator_mode']);
|
||||
$this->assertSame('1', $result['data']['filters']['include_payment_pending']);
|
||||
$this->assertSame('395.00', $result['data']['filters']['unit_price']);
|
||||
$this->assertSame('200.00', $result['data']['filters']['youth_unit_price']);
|
||||
$this->assertSame('always', $this->service->calls[0]['options']['include_withdrawn_mode']);
|
||||
}
|
||||
|
||||
@@ -184,6 +188,7 @@ class TuitionForecastControllerTest extends CIUnitTestCase
|
||||
'include_event_only' => '0',
|
||||
'include_paid_invoices' => '1',
|
||||
'unit_price' => '390.00',
|
||||
'youth_unit_price' => '210.00',
|
||||
]);
|
||||
|
||||
$response = $this->controller->setRequestObject($request)->calculate();
|
||||
@@ -193,6 +198,7 @@ class TuitionForecastControllerTest extends CIUnitTestCase
|
||||
$this->assertSame('Fall', $payload['semester']);
|
||||
$this->assertSame('compare', $payload['calculator_mode']);
|
||||
$this->assertSame('390.00', $payload['options']['unit_price']);
|
||||
$this->assertSame('210.00', $payload['options']['youth_unit_price']);
|
||||
}
|
||||
|
||||
public function testExportCsvBuildsDownloadWithSummaryAndFamilyRows(): void
|
||||
@@ -210,6 +216,7 @@ class TuitionForecastControllerTest extends CIUnitTestCase
|
||||
$this->assertStringContainsString('Summary', $body);
|
||||
$this->assertStringContainsString('All Year', $body);
|
||||
$this->assertStringContainsString('Old Projected Income', $body);
|
||||
$this->assertStringContainsString('Youth Unit Price', $body);
|
||||
$this->assertStringContainsString('Layla Yusuf', $body);
|
||||
$this->assertStringContainsString('Student One', $body);
|
||||
}
|
||||
|
||||
@@ -51,4 +51,29 @@ class NewTuitionCalculatorServiceTest extends CIUnitTestCase
|
||||
$this->assertSame('0.00', $result['details'][3]['amount']);
|
||||
$this->assertSame('0.00', $result['details'][4]['amount']);
|
||||
}
|
||||
|
||||
public function testYouthStudentsUseSeparateUnitPriceWithoutAffectingRegularDiscountOrder(): void
|
||||
{
|
||||
$service = new NewTuitionCalculatorService();
|
||||
$result = $service->calculateFamilyTuition([
|
||||
['student_id' => 3, 'student_name' => 'Youth', 'grade_level' => 'Youth 1'],
|
||||
['student_id' => 1, 'student_name' => 'Regular One', 'grade_level' => '2'],
|
||||
['student_id' => 2, 'student_name' => 'Regular Two', 'grade_level' => '5'],
|
||||
], [
|
||||
'grade_fee' => 9,
|
||||
'new_tuition_full_amount' => '370.00',
|
||||
'new_tuition_youth_amount' => '200.00',
|
||||
'new_tuition_second_student_discount' => '150.00',
|
||||
'new_tuition_third_student_discount' => '150.00',
|
||||
'new_tuition_fourth_plus_discount' => '150.00',
|
||||
]);
|
||||
|
||||
$this->assertSame('790.00', $result['total']);
|
||||
$this->assertSame('new_first_student_full_amount', $result['details'][0]['rule']);
|
||||
$this->assertSame('370.00', $result['details'][0]['amount']);
|
||||
$this->assertSame('new_second_student_discount', $result['details'][1]['rule']);
|
||||
$this->assertSame('220.00', $result['details'][1]['amount']);
|
||||
$this->assertSame('new_youth_unit_price', $result['details'][2]['rule']);
|
||||
$this->assertSame('200.00', $result['details'][2]['amount']);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,10 +38,12 @@ class TuitionForecastServiceTest extends CIUnitTestCase
|
||||
'students' => [
|
||||
['student_id' => 1, 'student_name' => 'Mariam', 'grade_level' => '1'],
|
||||
['student_id' => 2, 'student_name' => 'Yahya', 'grade_level' => '2'],
|
||||
['student_id' => 4, 'student_name' => 'Youth Student', 'grade_level' => 'Youth 1'],
|
||||
],
|
||||
'all_students' => [
|
||||
['student_id' => 1, 'student_name' => 'Mariam', 'grade_level' => '1', 'billable' => true, 'excluded_reason' => null],
|
||||
['student_id' => 2, 'student_name' => 'Yahya', 'grade_level' => '2', 'billable' => true, 'excluded_reason' => null],
|
||||
['student_id' => 4, 'student_name' => 'Youth Student', 'grade_level' => 'Youth 1', 'billable' => true, 'excluded_reason' => null],
|
||||
['student_id' => 3, 'student_name' => 'Event Only', 'grade_level' => '3', 'billable' => false, 'excluded_reason' => 'event_only'],
|
||||
],
|
||||
'warnings' => ['1 event-only student(s) excluded from tuition.'],
|
||||
@@ -54,8 +56,9 @@ class TuitionForecastServiceTest extends CIUnitTestCase
|
||||
'grade_fee' => 9,
|
||||
'first_student_fee' => '350.00',
|
||||
'second_student_fee' => '200.00',
|
||||
'youth_fee' => '180.00',
|
||||
'youth_fee' => '200.00',
|
||||
'new_tuition_full_amount' => $this->unitPriceOverride ?? '350.00',
|
||||
'new_tuition_youth_amount' => $this->youthUnitPriceOverride ?? '200.00',
|
||||
'new_tuition_second_student_discount' => '50.00',
|
||||
'new_tuition_third_student_discount' => '50.00',
|
||||
'new_tuition_fourth_plus_discount' => '100.00',
|
||||
@@ -67,16 +70,18 @@ class TuitionForecastServiceTest extends CIUnitTestCase
|
||||
'include_payment_pending' => true,
|
||||
'include_withdrawn_mode' => 'refund_deadline',
|
||||
'unit_price' => '400.00',
|
||||
'youth_unit_price' => '200.00',
|
||||
]);
|
||||
|
||||
$this->assertSame(1, $result['summary']['family_count']);
|
||||
$this->assertSame(3, $result['summary']['student_count']);
|
||||
$this->assertSame(2, $result['summary']['billable_student_count']);
|
||||
$this->assertSame('550.00', $result['summary']['old_projected_tuition']);
|
||||
$this->assertSame('750.00', $result['summary']['new_projected_tuition']);
|
||||
$this->assertSame('550.00', $result['summary']['old_projected_income']);
|
||||
$this->assertSame('750.00', $result['summary']['new_projected_income']);
|
||||
$this->assertSame(4, $result['summary']['student_count']);
|
||||
$this->assertSame(3, $result['summary']['billable_student_count']);
|
||||
$this->assertSame('750.00', $result['summary']['old_projected_tuition']);
|
||||
$this->assertSame('950.00', $result['summary']['new_projected_tuition']);
|
||||
$this->assertSame('750.00', $result['summary']['old_projected_income']);
|
||||
$this->assertSame('950.00', $result['summary']['new_projected_income']);
|
||||
$this->assertSame('400.00', $result['summary']['unit_price']);
|
||||
$this->assertSame('event_only', $result['families'][0]['student_details'][2]['excluded_reason']);
|
||||
$this->assertSame('200.00', $result['summary']['youth_unit_price']);
|
||||
$this->assertSame('event_only', $result['families'][0]['student_details'][3]['excluded_reason']);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user