getDatabase(); $query = $db->getQuery(true) ->select('sa.*, cd.name AS customer_name, loc.address') ->from($db->quoteName('#__mokosuitefield_service_agreements', 'sa')) ->join('LEFT', $db->quoteName('#__contact_details', 'cd') . ' ON cd.id = sa.contact_id') ->join('LEFT', $db->quoteName('#__mokosuitefield_locations', 'loc') . ' ON loc.id = sa.location_id') ->order('sa.end_date ASC'); if ($status) $query->where($db->quoteName('sa.status') . ' = ' . $db->quote($status)); if ($search) $query->where($db->quoteName('cd.name') . ' LIKE ' . $db->quote('%' . $search . '%')); $db->setQuery($query, 0, $limit); return $db->loadObjectList() ?: []; } public function getExpiringSoon(int $days = 30): array { $db = $this->getDatabase(); $db->setQuery($db->getQuery(true) ->select('sa.*, cd.name AS customer_name') ->from($db->quoteName('#__mokosuitefield_service_agreements', 'sa')) ->join('LEFT', $db->quoteName('#__contact_details', 'cd') . ' ON cd.id = sa.contact_id') ->where($db->quoteName('sa.status') . ' = ' . $db->quote('active')) ->where($db->quoteName('sa.end_date') . ' BETWEEN CURDATE() AND DATE_ADD(CURDATE(), INTERVAL ' . $days . ' DAY)') ->order('sa.end_date ASC')); return $db->loadObjectList() ?: []; } }