4 && substr($config['sms_url'], 0, 4) != "http") { if (strlen($txt) > 160) { $txts = str_split($txt, 160); try { $mikrotik = Mikrotik::info($config['sms_url']); $client = Mikrotik::getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']); foreach ($txts as $txt) { Mikrotik::sendSMS($client, $phone, $txt); } } catch (Exception $e) { // ignore, add to logs _log("Failed to send SMS using Mikrotik.\n" . $e->getMessage(), 'SMS', 0); } } else { try { $mikrotik = Mikrotik::info($config['sms_url']); $client = Mikrotik::getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']); Mikrotik::sendSMS($client, $phone, $txt); } catch (Exception $e) { // ignore, add to logs _log("Failed to send SMS using Mikrotik.\n" . $e->getMessage(), 'SMS', 0); } } } else { $smsurl = str_replace('[number]', urlencode($phone), $config['sms_url']); $smsurl = str_replace('[text]', urlencode($txt), $smsurl); return Http::getData($smsurl); } } } public static function sendWhatsapp($phone, $txt) { global $config; if(empty($txt)){ return ""; } run_hook('send_whatsapp'); #HOOK if (!empty($config['wa_url'])) { $waurl = str_replace('[number]', urlencode(Lang::phoneFormat($phone)), $config['wa_url']); $waurl = str_replace('[text]', urlencode($txt), $waurl); return Http::getData($waurl); } } public static function sendEmail($to, $subject, $body) { global $config; if(empty($body)){ return ""; } run_hook('send_email'); #HOOK if (empty($config['smtp_host'])) { $attr = ""; if (!empty($config['mail_from'])) { $attr .= "From: " . $config['mail_from'] . "\r\n"; } if (!empty($config['mail_reply_to'])) { $attr .= "Reply-To: " . $config['mail_reply_to'] . "\r\n"; } mail($to, $subject, $body, $attr); } else { $mail = new PHPMailer(); $mail->isSMTP(); $mail->SMTPDebug = SMTP::DEBUG_SERVER; $mail->Host = $config['smtp_host']; $mail->SMTPAuth = true; $mail->Username = $config['smtp_user']; $mail->Password = $config['smtp_pass']; $mail->SMTPSecure = $config['smtp_ssltls']; $mail->Port = $config['smtp_port']; if (!empty($config['mail_from'])) { $mail->setFrom($config['mail_from']); } if (!empty($config['mail_reply_to'])) { $mail->addReplyTo($config['mail_reply_to']); } $mail->isHTML(false); $mail->addAddress($to); $mail->Subject = $subject; $mail->Body = $body; $mail->send(); } } public static function sendPackageNotification($customer, $package, $price, $message, $via, $plan_type = null) { global $ds; if(empty($message)){ return ""; } // Get plan-specific template if plan_type is provided $template = self::getPlanSpecificTemplate($message, $plan_type); $msg = str_replace('[[name]]', $customer['fullname'], $template); $msg = str_replace('[[username]]', $customer['username'], $msg); $msg = str_replace('[[plan]]', $package, $msg); $msg = str_replace('[[package]]', $package, $msg); $msg = str_replace('[[price]]', Lang::moneyFormat($price), $msg); $msg = str_replace('[[plan_type]]', $plan_type ? ucfirst(strtolower($plan_type)) : 'Internet', $msg); // Add service-specific variables global $config; $msg = str_replace('[[service_portal]]', !empty($config['hotspot_url']) ? $config['hotspot_url'] : APP_URL, $msg); $msg = str_replace('[[support_contact]]', !empty($config['phone']) ? $config['phone'] : 'our support team', $msg); list($bills, $add_cost) = User::getBills($customer['id']); if($add_cost>0){ $note = ""; foreach ($bills as $k => $v) { $note .= $k . " : " . Lang::moneyFormat($v) . "\n"; } $note .= "Total : " . Lang::moneyFormat($add_cost+$price) . "\n"; $msg = str_replace('[[bills]]', $note, $msg); }else{ $msg = str_replace('[[bills]]', '', $msg); } if ($ds) { $msg = str_replace('[[expired_date]]', Lang::dateAndTimeFormat($ds['expiration'], $ds['time']), $msg); }else{ $msg = str_replace('[[expired_date]]', "", $msg); } if ( !empty($customer['phonenumber']) && strlen($customer['phonenumber']) > 5 && !empty($template) && in_array($via, ['sms', 'wa']) ) { if ($via == 'sms') { echo Message::sendSMS($customer['phonenumber'], $msg); } else if ($via == 'wa') { echo Message::sendWhatsapp($customer['phonenumber'], $msg); } } return "$via: $msg"; } public static function sendBalanceNotification($phone, $name, $balance, $balance_now, $message, $via) { $msg = str_replace('[[name]]', $name, $message); $msg = str_replace('[[current_balance]]', Lang::moneyFormat($balance_now), $msg); $msg = str_replace('[[balance]]', Lang::moneyFormat($balance), $msg); if ( !empty($phone) && strlen($phone) > 5 && !empty($message) && in_array($via, ['sms', 'wa']) ) { if ($via == 'sms') { Message::sendSMS($phone, $msg); } else if ($via == 'wa') { Message::sendWhatsapp($phone, $msg); } } return "$via: $msg"; } public static function sendInvoice($cust, $trx) { global $config; $textInvoice = Lang::getNotifText('invoice_paid'); $textInvoice = str_replace('[[company_name]]', $config['CompanyName'], $textInvoice); $textInvoice = str_replace('[[address]]', $config['address'], $textInvoice); $textInvoice = str_replace('[[phone]]', $config['phone'], $textInvoice); $textInvoice = str_replace('[[invoice]]', $trx['invoice'], $textInvoice); $textInvoice = str_replace('[[date]]', Lang::dateAndTimeFormat($trx['recharged_on'], $trx['recharged_time']), $textInvoice); if (!empty($trx['note'])) { $textInvoice = str_replace('[[note]]', $trx['note'], $textInvoice); } $gc = explode("-", $trx['method']); $textInvoice = str_replace('[[payment_gateway]]', trim($gc[0]), $textInvoice); $textInvoice = str_replace('[[payment_channel]]', trim($gc[1]), $textInvoice); $textInvoice = str_replace('[[type]]', $trx['type'], $textInvoice); $textInvoice = str_replace('[[plan_name]]', $trx['plan_name'], $textInvoice); $textInvoice = str_replace('[[plan_price]]', Lang::moneyFormat($trx['price']), $textInvoice); $textInvoice = str_replace('[[name]]', $cust['fullname'], $textInvoice); $textInvoice = str_replace('[[note]]', $cust['note'], $textInvoice); $textInvoice = str_replace('[[user_name]]', $trx['username'], $textInvoice); $textInvoice = str_replace('[[user_password]]', $cust['password'], $textInvoice); $textInvoice = str_replace('[[username]]', $trx['username'], $textInvoice); $textInvoice = str_replace('[[password]]', $cust['password'], $textInvoice); $textInvoice = str_replace('[[expired_date]]', Lang::dateAndTimeFormat($trx['expiration'], $trx['time']), $textInvoice); $textInvoice = str_replace('[[footer]]', $config['note'], $textInvoice); if ($config['user_notification_payment'] == 'sms') { Message::sendSMS($cust['phonenumber'], $textInvoice); } else if ($config['user_notification_payment'] == 'wa') { Message::sendWhatsapp($cust['phonenumber'], $textInvoice); } } public static function sendRegistrationNotification($customer) { global $config; if(empty($customer['phonenumber']) || strlen($customer['phonenumber']) < 5){ return ""; } $textRegistration = Lang::getNotifText('user_registration'); if(empty($textRegistration)) { return ""; } $textRegistration = str_replace('[[company_name]]', $config['CompanyName'], $textRegistration); $textRegistration = str_replace('[[name]]', $customer['fullname'], $textRegistration); $textRegistration = str_replace('[[user_name]]', $customer['username'], $textRegistration); $textRegistration = str_replace('[[username]]', $customer['username'], $textRegistration); $textRegistration = str_replace('[[password]]', $customer['password'], $textRegistration); $textRegistration = str_replace('[[service_type]]', $customer['service_type'], $textRegistration); $textRegistration = str_replace('[[footer]]', $config['note'], $textRegistration); // Use the same notification setting as recharge process if ($config['user_notification_payment'] == 'sms') { Message::sendSMS($customer['phonenumber'], $textRegistration); } else if ($config['user_notification_payment'] == 'wa') { Message::sendWhatsapp($customer['phonenumber'], $textRegistration); } return $textRegistration; } /** * Get plan-specific template based on plan type * @param string $message_key The message key (e.g., 'expired', 'reminder_7_day') * @param string $plan_type The plan type ('Hotspot', 'PPPOE', etc.) * @return string The appropriate template */ public static function getPlanSpecificTemplate($message_key, $plan_type = null) { global $config; // Load notification templates $notifications = self::loadNotificationTemplates(); // If no plan type provided or template doesn't exist, return original message if (empty($plan_type) || !isset($notifications[$message_key])) { return $message_key; } // Check if it's a new structure with plan-specific templates if (is_array($notifications[$message_key])) { $plan_type_lower = strtolower($plan_type); // Try to get plan-specific template if (isset($notifications[$message_key][$plan_type_lower])) { return $notifications[$message_key][$plan_type_lower]; } // Fallback to default template if (isset($notifications[$message_key]['default'])) { return $notifications[$message_key]['default']; } } // Fallback to original message for backward compatibility return $notifications[$message_key]; } /** * Load notification templates from file * @return array Notification templates */ public static function loadNotificationTemplates() { global $root_path; $notifications_file = $root_path . 'system/uploads/notifications.default.json'; if (file_exists($notifications_file)) { $content = file_get_contents($notifications_file); $notifications = json_decode($content, true); return $notifications ?: []; } return []; } /** * Detect plan type from customer and package information * @param array $customer Customer information * @param string $package Package name * @return string|null Plan type */ public static function detectPlanType($customer, $package) { // Try to get plan type from customer's service_type if (!empty($customer['service_type']) && in_array($customer['service_type'], ['Hotspot', 'PPPoE'])) { return $customer['service_type']; } // Try to detect from package name (basic detection) $package_lower = strtolower($package); if (strpos($package_lower, 'hotspot') !== false) { return 'Hotspot'; } elseif (strpos($package_lower, 'pppoe') !== false) { return 'PPPOE'; } return null; } }