diff --git a/source/packages/plg_system_mokosuitenpo/src/Helper/GrantReportingHelper.php b/source/packages/plg_system_mokosuitenpo/src/Helper/GrantReportingHelper.php new file mode 100644 index 0000000..81c7a89 --- /dev/null +++ b/source/packages/plg_system_mokosuitenpo/src/Helper/GrantReportingHelper.php @@ -0,0 +1,65 @@ +get(DatabaseInterface::class); + + $db->setQuery($db->getQuery(true) + ->select('g.*, cd.name AS funder_name') + ->from($db->quoteName('#__mokosuitenpo_grants', 'g')) + ->join('LEFT', $db->quoteName('#__contact_details', 'cd') . ' ON cd.id = g.funder_contact_id') + ->where('g.id = ' . (int) $grantId)); + $grant = $db->loadObject(); + + if (!$grant) return (object) ['found' => false]; + + // Get expenses charged to this grant's fund + $db->setQuery($db->getQuery(true) + ->select('category, COUNT(*) AS count, COALESCE(SUM(amount), 0) AS spent') + ->from('#__mokosuitenpo_fund_expenses') + ->where('fund_id = ' . (int) ($grant->fund_id ?? 0)) + ->group('category') + ->order('spent DESC')); + $grant->spending_by_category = $db->loadObjectList() ?: []; + + $grant->total_spent = array_sum(array_column($grant->spending_by_category, 'spent')); + $grant->remaining = max(0, (float) ($grant->amount ?? 0) - (float) $grant->total_spent); + $grant->utilization_pct = (float) ($grant->amount ?? 0) > 0 + ? round((float) $grant->total_spent / (float) $grant->amount * 100, 1) : 0; + + return $grant; + } + + /** + * Get grants requiring reports soon. + */ + public static function getUpcomingReportDeadlines(int $days = 30): array + { + $db = Factory::getContainer()->get(DatabaseInterface::class); + + $db->setQuery($db->getQuery(true) + ->select('g.id, g.title, g.funder, g.report_due_date, g.amount') + ->select('DATEDIFF(g.report_due_date, CURDATE()) AS days_until_due') + ->from($db->quoteName('#__mokosuitenpo_grants', 'g')) + ->where($db->quoteName('g.status') . ' IN (' . $db->quote('active') . ',' . $db->quote('reporting') . ')') + ->where($db->quoteName('g.report_due_date') . ' IS NOT NULL') + ->where($db->quoteName('g.report_due_date') . ' BETWEEN CURDATE() AND DATE_ADD(CURDATE(), INTERVAL ' . (int) $days . ' DAY)') + ->order('g.report_due_date ASC')); + + return $db->loadObjectList() ?: []; + } +}