Files
alrahma_sunday_school/app/Commands/RepairSchoolYearCarryForward.php
T
root 36e8ffe56d
Deploy to Shared Hosting / Shared hosting deploy (push) Failing after 49s
Tests / PHPUnit (push) Successful in 1m21s
fix the enrollement-carryover balance
2026-09-09 21:40:01 -04:00

104 lines
4.4 KiB
PHP

<?php
namespace App\Commands;
use CodeIgniter\CLI\BaseCommand;
use CodeIgniter\CLI\CLI;
final class RepairSchoolYearCarryForward extends BaseCommand
{
protected $group = 'School Year';
protected $name = 'school-year:repair-carry-forward';
protected $description = 'Find or repair family balances omitted from an executed school-year closing batch.';
protected $usage = 'php spark school-year:repair-carry-forward --source-year-id=1 [--actor-id=1 --commit]';
protected $options = [
'--source-year-id' => 'Required source school-year record ID.',
'--actor-id' => 'Administrator user ID recorded in the repair audit log.',
'--commit' => 'Create missing closing items and target-year opening-balance invoices.',
'--json' => 'Print machine-readable output.',
];
public function run(array $params)
{
$sourceYearId = (int) (CLI::getOption('source-year-id') ?? 0);
if ($sourceYearId <= 0) {
CLI::error('--source-year-id must be a positive integer.');
return;
}
try {
$closing = service('schoolYearClosing');
$batch = $closing->latestBatch($sourceYearId);
if ($batch === null) {
throw new \RuntimeException('No closing batch exists for the source school year.');
}
$preview = $closing->preview($sourceYearId, (int) ($batch['target_school_year_id'] ?? 0));
$db = \Config\Database::connect();
$existingRows = $db->table('school_year_closing_items')
->select('family_id')
->where('closing_batch_id', (int) $batch['id'])
->get()
->getResultArray();
$existing = array_fill_keys(array_map(
static fn (array $row): int => (int) ($row['family_id'] ?? 0),
$existingRows
), true);
$missing = array_values(array_filter(
$preview['carry_forward'] ?? [],
static fn (array $row): bool => ! isset($existing[(int) ($row['family_id'] ?? 0)])
));
$result = [
'mode' => CLI::getOption('commit') !== null ? 'commit' : 'dry-run',
'closing_batch_id' => (int) $batch['id'],
'missing_count' => count($missing),
'missing_amount' => round(array_sum(array_map(
static fn (array $row): float => (float) ($row['carry_forward_amount'] ?? 0),
$missing
)), 2),
'missing_items' => array_map(static fn (array $row): array => [
'family_id' => (int) ($row['family_id'] ?? 0),
'parent' => (string) ($row['parent'] ?? ''),
'carry_forward_amount' => round((float) ($row['carry_forward_amount'] ?? 0), 2),
], $missing),
];
if (CLI::getOption('commit') !== null) {
$actorId = (int) (CLI::getOption('actor-id') ?? 0);
if ($actorId <= 0) {
throw new \InvalidArgumentException('--actor-id must be a positive administrator user ID when using --commit.');
}
$result['repair'] = $closing->repairMissingCarryForward($sourceYearId, $actorId);
}
if (CLI::getOption('json') !== null) {
CLI::write(json_encode($result, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
return;
}
CLI::write(sprintf(
'%s: %d missing family balance(s), $%0.2f total.',
strtoupper((string) $result['mode']),
(int) $result['missing_count'],
(float) $result['missing_amount']
));
foreach ($result['missing_items'] as $item) {
CLI::write(sprintf(
'Family #%d (%s): $%0.2f',
(int) $item['family_id'],
(string) $item['parent'],
(float) $item['carry_forward_amount']
));
}
if (isset($result['repair'])) {
CLI::write('Repair completed and audited.', 'green');
} elseif ($missing !== []) {
CLI::write('Run again with --actor-id=<admin id> --commit to apply the repair.', 'yellow');
}
} catch (\Throwable $e) {
CLI::error($e->getMessage());
}
}
}