Merge pull request 'master' (#6) from master into v1.0.2

Reviewed-on: #6
This commit is contained in:
nestict 2025-06-06 17:05:41 +02:00
commit 190767288c
173 changed files with 56780 additions and 0 deletions

652
sql/prodnew_db.sql Normal file
View File

@ -0,0 +1,652 @@
-- phpMyAdmin SQL Dump
-- version 5.2.1deb3
-- https://www.phpmyadmin.net/
--
-- Host: localhost:3306
-- Generation Time: Jun 06, 2025 at 11:27 AM
-- Server version: 8.0.42-0ubuntu0.24.04.1
-- PHP Version: 8.3.6
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
START TRANSACTION;
SET time_zone = "+00:00";
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8mb4 */;
--
-- Database: `prodnew_db`
--
-- --------------------------------------------------------
--
-- Table structure for table `sms_topups`
--
CREATE TABLE `sms_topups` (
`id` int NOT NULL,
`phone_number` varchar(20) NOT NULL,
`sms_units` int NOT NULL,
`reference` varchar(255) NOT NULL,
`status` enum('completed','pending','failed') NOT NULL DEFAULT 'pending',
`created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
-- --------------------------------------------------------
--
-- Table structure for table `tbl_appconfig`
--
CREATE TABLE `tbl_appconfig` (
`id` int NOT NULL,
`setting` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`value` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-- --------------------------------------------------------
--
-- Table structure for table `tbl_bandwidth`
--
CREATE TABLE `tbl_bandwidth` (
`id` int UNSIGNED NOT NULL,
`name_bw` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`rate_down` int UNSIGNED NOT NULL,
`rate_down_unit` enum('Kbps','Mbps') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`rate_up` int UNSIGNED NOT NULL,
`rate_up_unit` enum('Kbps','Mbps') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`burst` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT ''
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-- --------------------------------------------------------
--
-- Table structure for table `tbl_banks`
--
CREATE TABLE `tbl_banks` (
`id` int NOT NULL,
`name` varchar(50) NOT NULL,
`paybill` int NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
--
-- Dumping data for table `tbl_banks`
--
INSERT INTO `tbl_banks` (`id`, `name`, `paybill`) VALUES
(1, 'Equity', 247247),
(2, 'KCB', 522522),
(3, 'Coop', 400200),
(4, 'DTB', 516600),
(5, 'NCBA', 880100),
(6, 'Absa', 303030),
(1, '', 247247),
(2, 'KCB', 522522),
(3, 'Coop', 400200),
(4, 'DTB', 516600),
(5, 'NCBA', 880100),
(6, 'Absa', 303030);
-- --------------------------------------------------------
--
-- Table structure for table `tbl_customers`
--
CREATE TABLE `tbl_customers` (
`id` int NOT NULL,
`username` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`password` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`pppoe_password` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'For PPPOE Login',
`fullname` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`address` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci,
`city` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
`district` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
`state` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
`zip` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
`phonenumber` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '0',
`email` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '1',
`coordinates` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'Latitude and Longitude coordinates',
`balance` decimal(15,2) NOT NULL DEFAULT '0.00' COMMENT 'For Money Deposit',
`router_id` int DEFAULT '1',
`service_type` enum('Hotspot','PPPoE','Others') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'Others' COMMENT 'For selecting user type',
`account_type` enum('Business','Personal') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'Personal' COMMENT 'For selecting account type',
`auto_renewal` tinyint(1) NOT NULL DEFAULT '1' COMMENT 'Auto renewall using balance',
`status` enum('Active','Banned','Disabled','Inactive','Limited','Suspended') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'Active',
`created_by` int NOT NULL DEFAULT '0',
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`last_login` datetime DEFAULT NULL,
`account` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-- --------------------------------------------------------
--
-- Table structure for table `tbl_customers_fields`
--
CREATE TABLE `tbl_customers_fields` (
`id` int NOT NULL,
`customer_id` int NOT NULL,
`field_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`field_value` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-- --------------------------------------------------------
--
-- Table structure for table `tbl_logs`
--
CREATE TABLE `tbl_logs` (
`id` int NOT NULL,
`date` datetime DEFAULT NULL,
`type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`description` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`userid` int NOT NULL,
`ip` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-- --------------------------------------------------------
--
-- Table structure for table `tbl_message`
--
CREATE TABLE `tbl_message` (
`id` int NOT NULL,
`from_user` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`to_user` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`title` varchar(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`message` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`status` enum('0','1') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '0',
`date` datetime NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-- --------------------------------------------------------
--
-- Table structure for table `tbl_mpesa_transactions`
--
CREATE TABLE `tbl_mpesa_transactions` (
`id` int NOT NULL,
`TransID` varchar(255) NOT NULL,
`TransactionType` varchar(255) NOT NULL,
`TransTime` varchar(255) NOT NULL,
`TransAmount` decimal(10,2) NOT NULL,
`BusinessShortCode` varchar(255) NOT NULL,
`BillRefNumber` varchar(255) NOT NULL,
`OrgAccountBalance` decimal(10,2) NOT NULL,
`MSISDN` varchar(255) NOT NULL,
`FirstName` varchar(255) NOT NULL,
`CustomerID` varchar(255) NOT NULL,
`PackageName` varchar(255) NOT NULL,
`PackagePrice` varchar(255) NOT NULL,
`TransactionStatus` varchar(255) NOT NULL,
`CreatedAt` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
-- --------------------------------------------------------
--
-- Table structure for table `tbl_payment_gateway`
--
CREATE TABLE `tbl_payment_gateway` (
`id` int NOT NULL,
`username` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`gateway` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'xendit | midtrans',
`checkout` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
`gateway_trx_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
`plan_id` int NOT NULL,
`plan_name` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`routers_id` int NOT NULL,
`routers` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`price` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`pg_url_payment` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
`payment_method` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
`payment_channel` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
`pg_request` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci,
`pg_paid_response` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci,
`expired_date` datetime DEFAULT NULL,
`created_date` datetime NOT NULL,
`paid_date` datetime DEFAULT NULL,
`trx_invoice` varchar(25) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'from tbl_transactions',
`status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '1 unpaid 2 paid 3 failed 4 canceled'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-- --------------------------------------------------------
--
-- Table structure for table `tbl_plans`
--
CREATE TABLE `tbl_plans` (
`id` int NOT NULL,
`name_plan` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`id_bw` int NOT NULL,
`price` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`type` enum('Hotspot','PPPOE','Balance') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`typebp` enum('Unlimited','Limited') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
`limit_type` enum('Time_Limit','Data_Limit','Both_Limit') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
`time_limit` int UNSIGNED DEFAULT NULL,
`time_unit` enum('Mins','Hrs') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
`data_limit` int UNSIGNED DEFAULT NULL,
`data_unit` enum('MB','GB') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
`validity` int NOT NULL,
`validity_unit` enum('Mins','Hrs','Days','Months','Period') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`shared_users` int DEFAULT NULL,
`routers` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`is_radius` tinyint(1) NOT NULL DEFAULT '0' COMMENT '1 is radius',
`pool` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
`pool_expired` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
`list_expired` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'address list',
`enabled` tinyint(1) NOT NULL DEFAULT '1' COMMENT '0 disabled',
`allow_purchase` enum('yes','no') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'yes' COMMENT 'allow to show package in buy package page',
`prepaid` enum('yes','no') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'yes' COMMENT 'is prepaid',
`plan_type` enum('Business','Personal') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'Personal' COMMENT 'For switching plan according to user type'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-- --------------------------------------------------------
--
-- Table structure for table `tbl_pool`
--
CREATE TABLE `tbl_pool` (
`id` int NOT NULL,
`pool_name` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`range_ip` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`routers` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-- --------------------------------------------------------
--
-- Table structure for table `tbl_routers`
--
CREATE TABLE `tbl_routers` (
`id` int NOT NULL,
`name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`ip_address` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`username` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`password` varchar(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`description` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
`enabled` tinyint(1) NOT NULL DEFAULT '1' COMMENT '0 disabled',
`status` enum('Online','Offline') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'Offline',
`last_check` datetime DEFAULT NULL,
`offline_since` datetime DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-- --------------------------------------------------------
--
-- Table structure for table `tbl_transactions`
--
CREATE TABLE `tbl_transactions` (
`id` int NOT NULL,
`invoice` varchar(25) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`username` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`plan_name` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`price` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`recharged_on` date NOT NULL,
`recharged_time` time NOT NULL DEFAULT '00:00:00',
`expiration` date NOT NULL,
`time` time NOT NULL,
`method` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`routers` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`type` enum('Hotspot','PPPOE','Balance') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`note` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'for note',
`admin_id` int NOT NULL DEFAULT '1'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-- --------------------------------------------------------
--
-- Table structure for table `tbl_users`
--
CREATE TABLE `tbl_users` (
`id` int UNSIGNED NOT NULL,
`root` int NOT NULL DEFAULT '0' COMMENT 'for sub account',
`username` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
`fullname` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
`password` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`phone` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
`email` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
`city` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'kota',
`subdistrict` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'kecamatan',
`ward` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'kelurahan',
`user_type` enum('SuperAdmin','Admin','Report','Agent','Sales') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`status` enum('Active','Inactive') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'Active',
`last_login` datetime DEFAULT NULL,
`creationdate` datetime NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
--
-- Dumping data for table `tbl_users`
--
INSERT INTO `tbl_users` (`id`, `root`, `username`, `fullname`, `password`, `phone`, `email`, `city`, `subdistrict`, `ward`, `user_type`, `status`, `last_login`, `creationdate`) VALUES
(4, 0, 'demo', 'demo', '6ea7ccdcf642953a24672d10b0d32cef576e0329', '1234567890', 'demo@example.com', '', '', '', 'Admin', 'Active', '2025-06-04 12:06:36', '2025-05-26 09:24:13');
-- --------------------------------------------------------
--
-- Table structure for table `tbl_user_data_usage`
--
CREATE TABLE `tbl_user_data_usage` (
`id` int NOT NULL,
`username` varchar(255) NOT NULL,
`bytes_in` bigint NOT NULL,
`bytes_out` bigint NOT NULL,
`connection_type` enum('hotspot','pppoe') NOT NULL,
`timestamp` datetime NOT NULL,
`last_updated` datetime NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
-- --------------------------------------------------------
--
-- Table structure for table `tbl_user_recharges`
--
CREATE TABLE `tbl_user_recharges` (
`id` int NOT NULL,
`customer_id` int NOT NULL,
`username` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`plan_id` int NOT NULL,
`namebp` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`recharged_on` date NOT NULL,
`recharged_time` time NOT NULL DEFAULT '00:00:00',
`expiration` date NOT NULL,
`time` time NOT NULL,
`status` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`method` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
`routers` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`type` varchar(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`admin_id` int NOT NULL DEFAULT '1'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-- --------------------------------------------------------
--
-- Table structure for table `tbl_voucher`
--
CREATE TABLE `tbl_voucher` (
`id` int NOT NULL,
`type` enum('Hotspot','PPPOE') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`routers` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`id_plan` int NOT NULL,
`code` varchar(55) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`user` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`status` varchar(25) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`generated_by` int NOT NULL DEFAULT '0' COMMENT 'id admin'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-- --------------------------------------------------------
--
-- Table structure for table `tb_languages`
--
CREATE TABLE `tb_languages` (
`id` int NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-- --------------------------------------------------------
--
-- Table structure for table `user_sms_balance`
--
CREATE TABLE `user_sms_balance` (
`id` int NOT NULL,
`phone_number` varchar(20) NOT NULL,
`sms_balance` int NOT NULL DEFAULT '0',
`updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
--
-- Indexes for dumped tables
--
--
-- Indexes for table `sms_topups`
--
ALTER TABLE `sms_topups`
ADD PRIMARY KEY (`id`);
--
-- Indexes for table `tbl_appconfig`
--
ALTER TABLE `tbl_appconfig`
ADD PRIMARY KEY (`id`);
--
-- Indexes for table `tbl_bandwidth`
--
ALTER TABLE `tbl_bandwidth`
ADD PRIMARY KEY (`id`);
--
-- Indexes for table `tbl_customers`
--
ALTER TABLE `tbl_customers`
ADD PRIMARY KEY (`id`);
--
-- Indexes for table `tbl_customers_fields`
--
ALTER TABLE `tbl_customers_fields`
ADD PRIMARY KEY (`id`),
ADD KEY `customer_id` (`customer_id`);
--
-- Indexes for table `tbl_logs`
--
ALTER TABLE `tbl_logs`
ADD PRIMARY KEY (`id`);
--
-- Indexes for table `tbl_message`
--
ALTER TABLE `tbl_message`
ADD PRIMARY KEY (`id`);
--
-- Indexes for table `tbl_mpesa_transactions`
--
ALTER TABLE `tbl_mpesa_transactions`
ADD PRIMARY KEY (`id`);
--
-- Indexes for table `tbl_payment_gateway`
--
ALTER TABLE `tbl_payment_gateway`
ADD PRIMARY KEY (`id`);
--
-- Indexes for table `tbl_plans`
--
ALTER TABLE `tbl_plans`
ADD PRIMARY KEY (`id`);
--
-- Indexes for table `tbl_pool`
--
ALTER TABLE `tbl_pool`
ADD PRIMARY KEY (`id`);
--
-- Indexes for table `tbl_routers`
--
ALTER TABLE `tbl_routers`
ADD PRIMARY KEY (`id`);
--
-- Indexes for table `tbl_transactions`
--
ALTER TABLE `tbl_transactions`
ADD PRIMARY KEY (`id`);
--
-- Indexes for table `tbl_users`
--
ALTER TABLE `tbl_users`
ADD PRIMARY KEY (`id`);
--
-- Indexes for table `tbl_user_data_usage`
--
ALTER TABLE `tbl_user_data_usage`
ADD PRIMARY KEY (`id`),
ADD KEY `username` (`username`,`connection_type`,`timestamp`);
--
-- Indexes for table `tbl_user_recharges`
--
ALTER TABLE `tbl_user_recharges`
ADD PRIMARY KEY (`id`);
--
-- Indexes for table `tbl_voucher`
--
ALTER TABLE `tbl_voucher`
ADD PRIMARY KEY (`id`);
--
-- Indexes for table `user_sms_balance`
--
ALTER TABLE `user_sms_balance`
ADD PRIMARY KEY (`id`),
ADD UNIQUE KEY `phone_number` (`phone_number`);
--
-- AUTO_INCREMENT for dumped tables
--
--
-- AUTO_INCREMENT for table `sms_topups`
--
ALTER TABLE `sms_topups`
MODIFY `id` int NOT NULL AUTO_INCREMENT;
--
-- AUTO_INCREMENT for table `tbl_appconfig`
--
ALTER TABLE `tbl_appconfig`
MODIFY `id` int NOT NULL AUTO_INCREMENT;
--
-- AUTO_INCREMENT for table `tbl_bandwidth`
--
ALTER TABLE `tbl_bandwidth`
MODIFY `id` int UNSIGNED NOT NULL AUTO_INCREMENT;
--
-- AUTO_INCREMENT for table `tbl_customers`
--
ALTER TABLE `tbl_customers`
MODIFY `id` int NOT NULL AUTO_INCREMENT;
--
-- AUTO_INCREMENT for table `tbl_customers_fields`
--
ALTER TABLE `tbl_customers_fields`
MODIFY `id` int NOT NULL AUTO_INCREMENT;
--
-- AUTO_INCREMENT for table `tbl_logs`
--
ALTER TABLE `tbl_logs`
MODIFY `id` int NOT NULL AUTO_INCREMENT;
--
-- AUTO_INCREMENT for table `tbl_message`
--
ALTER TABLE `tbl_message`
MODIFY `id` int NOT NULL AUTO_INCREMENT;
--
-- AUTO_INCREMENT for table `tbl_mpesa_transactions`
--
ALTER TABLE `tbl_mpesa_transactions`
MODIFY `id` int NOT NULL AUTO_INCREMENT;
--
-- AUTO_INCREMENT for table `tbl_payment_gateway`
--
ALTER TABLE `tbl_payment_gateway`
MODIFY `id` int NOT NULL AUTO_INCREMENT;
--
-- AUTO_INCREMENT for table `tbl_plans`
--
ALTER TABLE `tbl_plans`
MODIFY `id` int NOT NULL AUTO_INCREMENT;
--
-- AUTO_INCREMENT for table `tbl_pool`
--
ALTER TABLE `tbl_pool`
MODIFY `id` int NOT NULL AUTO_INCREMENT;
--
-- AUTO_INCREMENT for table `tbl_routers`
--
ALTER TABLE `tbl_routers`
MODIFY `id` int NOT NULL AUTO_INCREMENT;
--
-- AUTO_INCREMENT for table `tbl_transactions`
--
ALTER TABLE `tbl_transactions`
MODIFY `id` int NOT NULL AUTO_INCREMENT;
--
-- AUTO_INCREMENT for table `tbl_users`
--
ALTER TABLE `tbl_users`
MODIFY `id` int UNSIGNED NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=5;
--
-- AUTO_INCREMENT for table `tbl_user_data_usage`
--
ALTER TABLE `tbl_user_data_usage`
MODIFY `id` int NOT NULL AUTO_INCREMENT;
--
-- AUTO_INCREMENT for table `tbl_user_recharges`
--
ALTER TABLE `tbl_user_recharges`
MODIFY `id` int NOT NULL AUTO_INCREMENT;
--
-- AUTO_INCREMENT for table `tbl_voucher`
--
ALTER TABLE `tbl_voucher`
MODIFY `id` int NOT NULL AUTO_INCREMENT;
--
-- AUTO_INCREMENT for table `user_sms_balance`
--
ALTER TABLE `user_sms_balance`
MODIFY `id` int NOT NULL AUTO_INCREMENT;
COMMIT;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;

59
system/lan/country.json Normal file
View File

@ -0,0 +1,59 @@
{
"english": "en",
"indonesia": "id",
"spanish": "es",
"turkish": "tr",
"amharic": "am",
"arabic": "ar",
"basque": "eu",
"bengali": "bn",
"english-uk": "en-gb",
"portuguese-brazil": "pt-br",
"bulgarian": "bg",
"catalan": "ca",
"cherokee": "chr",
"croatian": "hr",
"czech": "cs",
"danish": "da",
"dutch": "nl",
"estonian": "et",
"filipino": "fil",
"finnish": "fi",
"french": "fr",
"german": "de",
"greek": "el",
"gujarati": "gu",
"hebrew": "iw",
"hindi": "hi",
"hungarian": "hu",
"iran": "ir",
"icelandic": "is",
"italian": "it",
"japanese": "ja",
"kannada": "kn",
"korean": "ko",
"latvian": "lv",
"lithuanian": "lt",
"malay": "ms",
"malayalam": "ml",
"marathi": "mr",
"norwegian": "no",
"polish": "pl",
"portuguese (portugal)": "pt-pt",
"romanian": "ro",
"russian": "ru",
"serbian": "sr",
"chinese (prc)": "zh-cn",
"slovak": "sk",
"slovenian": "sl",
"swahili": "sw",
"swedish": "sv",
"tamil": "ta",
"telugu": "te",
"thai": "th",
"chinese-taiwan": "zh-tw",
"urdu": "ur",
"ukrainian": "uk",
"vietnamese": "vi",
"welsh": "cy"
}

803
system/lan/english.json Normal file
View File

@ -0,0 +1,803 @@
{
"Log_in": "Login",
"Register": "Register",
"Announcement": "Announcement",
"Registration_Info": "Registration Info",
"Voucher_not_found__please_buy_voucher_befor_register": "Voucher not found, please buy voucher befor register",
"Register_Success__You_can_login_now": "Register Success! You can login now",
"Log_in_to_Member_Panel": "Log in to Member Panel",
"Register_as_Member": "Register as Member",
"Enter_Admin_Area": "Enter Admin Area",
"PHPNuxBill": "PHPNuxBill",
"Username": "Username",
"Password": "Password",
"Passwords_does_not_match": "Passwords does not match",
"Account_already_axist": "Account already axist",
"Manage": "Manage",
"Submit": "Submit",
"Save_Changes": "Save Changes",
"Cancel": "Cancel",
"Edit": "Edit",
"Delete": "Delete",
"Welcome": "Welcome",
"Data_Created_Successfully": "Data Created Successfully",
"Data_Updated_Successfully": "Data Updated Successfully",
"Data_Deleted_Successfully": "Data Deleted Successfully",
"Static_Pages": "Static Pages",
"Failed_to_save_page__make_sure_i_can_write_to_folder_pages___i_chmod_664_pages___html_i_": "Failed to save page, make sure i can write to folder pages, <i>chmod 664 pages\/*.html<i>",
"Saving_page_success": "Saving page success",
"Sometimes_you_need_to_refresh_3_times_until_content_change": "Sometimes you need to refresh 3 times until content change",
"Dashboard": "Dashboard",
"Search_Customers___": "Search Customers...",
"My_Account": "My Account",
"My_Profile": "My Profile",
"Settings": "Settings",
"Edit_Profile": "Edit Profile",
"Change_Password": "Change Password",
"Logout": "Logout",
"Services": "Services",
"Bandwidth_Plans": "Bandwidth Plans",
"Bandwidth_Name": "Bandwidth Name",
"New_Bandwidth": "New Bandwidth",
"Edit_Bandwidth": "Edit Bandwidth",
"Add_New_Bandwidth": "Add New Bandwidth",
"Rate_Download": "Rate Download",
"Rate_Upload": "Rate Upload",
"Name_Bandwidth_Already_Exist": "Name Bandwidth Already Exist",
"Hotspot_Plans": "Hotspot Plans",
"PPPOE_Plans": "PPPOE Plans",
"Plan_Name": "Plan Name",
"New_Service_Plan": "New Service Plan",
"Add_Service_Plan": "Add Service Plan",
"Edit_Service_Plan": "Edit Service Plan",
"Name_Plan_Already_Exist": "Name Plan Already Exist",
"Plan_Type": "Plan Type",
"Plan_Price": "Plan Price",
"Limit_Type": "Limit Type",
"Unlimited": "Unlimited",
"Limited": "Limited",
"Time_Limit": "Time Limit",
"Data_Limit": "Data Limit",
"Both_Limit": "Both Limit",
"Plan_Validity": "Plan Validity",
"Select_Bandwidth": "Select Bandwidth",
"Shared_Users": "Shared Users",
"Choose_User_Type_Sales_to_disable_access_to_Settings": "Choose User Type Sales to disable access to Settings",
"Current_Password": "Current Password",
"New_Password": "New Password",
"Administrator": "Administrator",
"Sales": "Sales",
"Member": "Member",
"Confirm_New_Password": "Confirm New Password",
"Confirm_Password": "Confirm Password",
"Full_Name": "Full Name",
"User_Type": "User Type",
"Address": "Address",
"Created_On": "Created On",
"Expires_On": "Expires On",
"Phone_Number": "Phone Number",
"User_deleted_Successfully": "User deleted Successfully",
"Full_Administrator": "Full Administrator",
"Keep_Blank_to_do_not_change_Password": "Keep Blank to do not change Password",
"Keep_it_blank_if_you_do_not_want_to_show_currency_code": "Keep it blank if you do not want to show currency code",
"Theme_Style": "Theme Style",
"Theme_Color": "Theme Color",
"Default_Language": "Default Language",
"Network": "Network",
"Routers": "Routers",
"IP_Pool": "IP Pool",
"New_Router": "New Router",
"Add_Router": "Add Router",
"Edit_Router": "Edit Router",
"Router_Name": "Router Name",
"IP_Address": "IP Address",
"Router_Secret": "Router Secret",
"Description": "Description",
"IP_Router_Already_Exist": "IP Router Already Exist",
"Name_Pool": "Name Pool",
"Range_IP": "Range IP",
"New_Pool": "New Pool",
"Add_Pool": "Add Pool",
"Edit_Pool": "Edit Pool",
"Pool_Name_Already_Exist": "Pool Name Already Exist",
"Refill_Account": "Refill Account",
"Recharge_Account": "Recharge Account",
"Select_Account": "Select Account",
"Service_Plan": "Service Plan",
"Recharge": "Recharge",
"Method": "Method",
"Account_Created_Successfully": "Account Created Successfully",
"Database_Status": "Database Status",
"Total_Database_Size": "Total Database Size",
"Download_Database_Backup": "Download Database Backup",
"Table_Name": "Table Name",
"Rows": "Rows",
"Size": "Size",
"Customer": "Customer",
"Add_New_Contact": "Add New Contact",
"Edit_Contact": "Edit Contact",
"List_Contact": "List Contact",
"Manage_Contact": "Manage Contact",
"Reports": "Reports",
"Daily_Reports": "Daily Reports",
"Period_Reports": "Period Reports",
"All_Transactions": "All Transactions",
"Total_Income": "Total Income",
"All_Transactions_at_Date": "All Transactions at Date",
"Export_for_Print": "Export for Print",
"Print": "Print",
"Export_to_PDF": "Export to PDF",
"Click_Here_to_Print": "Click Here to Print",
"You_can_use_html_tag": "You can use html tag",
"Date_Format": "Date Format",
"Income_Today": "Income Today",
"Income_This_Month": "Income This Month",
"Users_Active": "Users Active",
"Total_Users": "Total Users",
"Users": "Users",
"Edit_User": "Edit User",
"Last_Login": "Last Login",
"Administrator_Users": "Administrator Users",
"Manage_Administrator": "Manage Administrator",
"Add_New_Administrator": "Add New Administrator",
"Localisation": "Localisation",
"Backup_Restore": "Backup\/Restore",
"General_Settings": "General Settings",
"Date": "Date",
"Login_Successful": "Login Successful",
"Failed_Login": "Failed Login",
"Settings_Saved_Successfully": "Settings Saved Successfully",
"User_Updated_Successfully": "User Updated Successfully",
"User_Expired__Today": "User Expired, Today",
"Activity_Log": "Activity Log",
"View_Reports": "View Reports",
"View_All": "View All",
"Number_of_Vouchers": "Number of Vouchers",
"Length_Code": "Length Code",
"Code_Voucher": "Code Voucher",
"Voucher": "Voucher",
"Hotspot_Voucher": "Hotspot Voucher",
"Status_Voucher": "Status Voucher",
"Add_Vouchers": "Add Vouchers",
"Create_Vouchers_Successfully": "Create Vouchers Successfully",
"Generate": "Generate",
"Print_side_by_side__it_will_easy_to_cut": "Print side by side, it will easy to cut",
"From_Date": "From Date",
"To_Date": "To Date",
"New_Service": "New Service",
"Type": "Type",
"Finish": "Finish",
"Application_Name__Company_Name": "Application Name\/ Company Name",
"This_Name_will_be_shown_on_the_Title": "This Name will be shown on the Title",
"Next": "Next",
"Last": "Last",
"Timezone": "Timezone",
"Decimal_Point": "Decimal Point",
"Thousands_Separator": "Thousands Separator",
"Currency_Code": "Currency Code",
"Order_Voucher": "Order Voucher",
"Voucher_Activation": "Voucher Activation",
"List_Activated_Voucher": "List Activated Voucher",
"Enter_voucher_code_here": "Enter voucher code here",
"Private_Message": "Private Message",
"Inbox": "Inbox",
"Outbox": "Outbox",
"Compose": "Compose",
"Send_to": "Send to",
"Title": "Title",
"Message": "Message",
"Your_Account_Information": "Your Account Information",
"Welcome_to_the_Panel_Members_page__on_this_page_you_can_": "Welcome to the Panel Members page, on this page you can:",
"Invalid_Username_or_Password": "Invalid Username or Password",
"You_do_not_have_permission_to_access_this_page": "You do not have permission to access this page",
"Incorrect_Current_Password": "Incorrect Current Password",
"Password_changed_successfully__Please_login_again": "Password changed successfully, Please login again",
"All_field_is_required": "All field is required",
"Voucher_Not_Valid": "Voucher Not Valid",
"Activation_Vouchers_Successfully": "Activation Vouchers Successfully",
"Data_Not_Found": "Data Not Found",
"Search_by_Username": "Search by Username",
"Search_by_Name": "Search by Name",
"Search_by_Code_Voucher": "Search by Code Voucher",
"Search": "Search",
"Select_a_customer": "Select a customer",
"Select_Routers": "Select Routers",
"Select_Plans": "Select Plans",
"Select_Pool": "Select Pool",
"Hrs": "Hrs",
"Mins": "Mins",
"Days": "Days",
"Months": "Months",
"Add_Language": "Add Language",
"Language_Name": "Language Name",
"Folder_Name": "Folder Name",
"Translator": "Translator",
"Language_Name_Already_Exist": "Language Name Already Exist",
"Payment_Gateway": "Payment Gateway",
"Community": "Community",
"1_user_can_be_used_for_many_devices_": "1 user can be used for many devices?",
"Cannot_be_change_after_saved": "Cannot be change after saved",
"Explain_Coverage_of_router": "Explain Coverage of router",
"Name_of_Area_that_router_operated": "Name of Area that router operated",
"Payment_Notification_URL__Recurring_Notification_URL__Pay_Account_Notification_URL": "Payment Notification URL, Recurring Notification URL, Pay Account Notification URL",
"Finish_Redirect_URL__Unfinish_Redirect_URL__Error_Redirect_URL": "Finish Redirect URL, Unfinish Redirect URL, Error Redirect URL",
"Status": "Status",
"Plan_Not_found": "Plan Not found",
"Failed_to_create_transaction_": "Failed to create transaction.",
"Seller_has_not_yet_setup_Xendit_payment_gateway": "Seller has not yet setup Xendit payment gateway",
"Admin_has_not_yet_setup_Xendit_payment_gateway__please_tell_admin": "Admin has not yet setup Xendit payment gateway, please tell admin",
"You_already_have_unpaid_transaction__cancel_it_or_pay_it_": "You already have unpaid transaction, cancel it or pay it.",
"Transaction_Not_found": "Transaction Not found",
"Cancel_it_": "Cancel it?",
"expired": "expired",
"Check_for_Payment": "Check for Payment",
"Transaction_still_unpaid_": "Transaction still unpaid.",
"Paid_Date": "Paid Date",
"Transaction_has_been_paid_": "Transaction has been paid.",
"PAID": "PAID",
"CANCELED": "CANCELED",
"UNPAID": "UNPAID",
"PAY_NOW": "PAY NOW",
"Buy_Hotspot_Plan": "Buy Hotspot Plan",
"Buy_PPOE_Plan": "Buy PPOE Plan",
"Package": "Package",
"Order_Internet_Package": "Order Internet Package",
"Unknown_Command_": "Unknown Command.",
"Checking_payment": "Checking payment",
"Create_Transaction_Success": "Create Transaction Success",
"You_have_unpaid_transaction": "You have unpaid transaction",
"TripayPayment_Channel": "TripayPayment Channel",
"Payment_Channel": "Payment Channel",
"Payment_check_failed_": "Payment check failed.",
"Order_Package": "Order Package",
"Transactions": "Transactions",
"Payments": "Payments",
"History": "History",
"Order_History": "Order History",
"Gateway": "Gateway",
"Date_Done": "Date Done",
"Unpaid_Order": "Unpaid Order",
"Payment_Gateway_Not_Found": "Payment Gateway Not Found",
"Payment_Gateway_saved_successfully": "Payment Gateway saved successfully",
"ORDER": "ORDER",
"Package_History": "Package History",
"Buy_History": "Buy History",
"Activation_History": "Activation History",
"Buy_Package": "Buy Package",
"Email": "Email",
"Company_Footer": "Company Footer",
"Will_show_below_user_pages": "Will show below user pages",
"Request_OTP": "Request OTP",
"Verification_Code": "Verification Code",
"SMS_Verification_Code": "SMS Verification Code",
"Please_enter_your_email_address": "Please enter your email address",
"Failed_to_create_Paypal_transaction_": "Failed to create Paypal transaction.",
"Plugin": "Plugin",
"Plugin_Manager": "Plugin Manager",
"User_Notification": "User Notification",
"Expired_Notification": "Expired Notification",
"User_will_get_notification_when_package_expired": "User will get notification when package expired",
"Expired_Notification_Message": "Expired Notification Message",
"Payment_Notification": "Payment Notification",
"User_will_get_invoice_notification_when_buy_package_or_package_refilled": "User will get invoice notification when buy package or package refilled",
"Current_IP": "Current IP",
"Current_MAC": "Current MAC",
"Login_Status": "Login Status",
"Login_Request_successfully": "Login Request successfully",
"Logout_Request_successfully": "Logout Request successfully",
"Disconnect_Internet_": "Disconnect Internet?",
"Not_Online__Login_now_": "Not Online, Login now?",
"You_are_Online__Logout_": "You are Online, Logout?",
"Connect_to_Internet_": "Connect to Internet?",
"Your_account_not_connected_to_internet": "Your account not connected to internet",
"Failed_to_create_transaction__": "Failed to create transaction. ",
"Failed_to_check_status_transaction__": "Failed to check status transaction. ",
"Disable_Voucher": "Disable Voucher",
"Balance": "Balance",
"Balance_System": "Balance System",
"Enable_System": "Enable System",
"Allow_Transfer": "Allow Transfer",
"Telegram_Notification": "Telegram Notification",
"SMS_OTP_Registration": "SMS OTP Registration",
"Whatsapp_Notification": "Whatsapp Notification",
"Tawk_to_Chat_Widget": "Tawk.to Chat Widget",
"Invoice": "Invoice",
"Country_Code_Phone": "Country Code Phone",
"Voucher_activation_menu_will_be_hidden": "Voucher activation menu will be hidden",
"Customer_can_deposit_money_to_buy_voucher": "Customer can deposit money to buy voucher",
"Allow_balance_transfer_between_customers": "Allow balance transfer between customers",
"Reminder_Notification": "Reminder Notification",
"Reminder_Notification_Message": "Reminder Notification Message",
"Reminder_7_days": "Reminder 7 days",
"Reminder_3_days": "Reminder 3 days",
"Reminder_1_day": "Reminder 1 day",
"PPPOE_Password": "PPPOE Password",
"User_Cannot_change_this__only_admin__if_it_Empty_it_will_use_user_password": "User Cannot change this, only admin. if it Empty it will use user password",
"Invoice_Balance_Message": "Invoice Balance Message",
"Invoice_Notification_Payment": "Invoice Notification Payment",
"Balance_Notification_Payment": "Balance Notification Payment",
"Balance_Plans": "Balance Plans",
"Buy_Balance": "Buy Balance",
"Price": "Price",
"Validity": "Validity",
"Disable_auto_renewal_": "Disable auto renewal?",
"Auto_Renewal_On": "Auto Renewal On",
"Enable_auto_renewal_": "Enable auto renewal?",
"Auto_Renewal_Off": "Auto Renewal Off",
"Refill_Balance": "Refill Balance",
"Invoice_Footer": "Invoice Footer",
"Pay_With_Balance": "Pay With Balance",
"Pay_this_with_Balance__your_active_package_will_be_overwrite": "Pay this with Balance? your active package will be overwrite",
"Success_to_buy_package": "Success to buy package",
"Auto_Renewal": "Auto Renewal",
"View": "View",
"Back": "Back",
"Active": "Active",
"Transfer_Balance": "Transfer Balance",
"Send_your_balance_": "Send your balance?",
"Send": "Send",
"Cannot_send_to_yourself": "Cannot send to yourself",
"Sending_balance_success": "Sending balance success",
"From": "From",
"To": "To",
"insufficient_balance": "insufficient balance",
"Send_Balance": "Send Balance",
"Received_Balance": "Received Balance",
"Minimum_Balance_Transfer": "Minimum Balance Transfer",
"Minimum_Transfer": "Minimum Transfer",
"Company_Logo": "Company Logo",
"Expired_IP_Pool": "Expired IP Pool",
"Proxy": "Proxy",
"Proxy_Server": "Proxy Server",
"Proxy_Server_Login": "Proxy Server Login",
"Hotspot_Plan": "Hotspot Plan",
"PPPOE_Plan": "PPPOE Plan",
"UNKNOWN": "UNKNOWN",
"Are_You_Sure_": "Are You Sure?",
"Success_to_send_package": "Success to send package",
"Target_has_active_plan__different_with_current_plant_": "Target has active plan, different with current plant.",
"Recharge_a_friend": "Recharge a friend",
"Buy_for_friend": "Buy for friend",
"Buy_this_for_friend_account_": "Buy this for friend account?",
"Review_package_before_recharge": "Review package before recharge",
"Activate": "Activate",
"Deactivate": "Deactivate",
"Sync": "Sync",
"Failed_to_create_PaymeTrust_transaction_": "Failed to create PaymeTrust transaction.",
"Location": "Location",
"Radius_Plans": "Radius Plans",
"Change_title_in_user_Plan_order": "Change title in user Plan order",
"Logs": "Logs",
"Voucher_Format": "Voucher Format",
"Resend_To_Customer": "Resend To Customer",
"Your_friend_do_not_have_active_package": "Your friend do not have active package",
"Service_Type": "Service Type",
"Others": "Others",
"PPPoE": "PPPoE",
"Hotspot": "Hotspot",
"Disable_Registration": "Disable Registration",
"Customer_just_Login_with_Phone_number_and_Voucher_Code__Voucher_will_be_password": "Customer just Login with Phone number and Voucher Code, Voucher will be password",
"Login___Activate_Voucher": "Login \/ Activate Voucher",
"After_Customer_activate_voucher_or_login__customer_will_be_redirected_to_this_url": "After Customer activate voucher or login, customer will be redirected to this url",
"Voucher_Prefix": "Voucher Prefix",
"Voucher_activation_success__now_you_can_login": "Voucher activation success, now you can login",
"Buy_this__your_active_package_will_be_overwritten": "Buy this? your active package will be overwritten",
"Pay_this_with_Balance__your_active_package_will_be_overwritten": "Pay this with Balance? your active package will be overwritten",
"Buy_this__your_active_package_will_be_overwrite": "Buy this? your active package will be overwrite",
"Monthly_Registered_Customers": "Monthly Registered Customers",
"Total_Monthly_Sales": "Total Monthly Sales",
"Active_Users": "Active Users",
"All_Users_Insights": "All Users Insights",
"SuperAdmin": "Super Admin",
"Radius": "Radius",
"Radius_NAS": "Radius NAS",
"Translation": "Translation",
"Translation_saved_Successfully": "Translation saved Successfully",
"Language_Editor": "Language Editor",
"year": "year",
"month": "month",
"week": "week",
"day": "day",
"hour": "hour",
"minute": "minute",
"second": "second",
"Attributes": "Attributes",
"Profile": "Profile",
"Phone": "Phone",
"City": "City",
"Sub_District": "Sub District",
"Ward": "Ward",
"Credentials": "Credentials",
"Agent": "Agent",
"This_Token_will_act_as_SuperAdmin_Admin": "This Token will act as SuperAdmin\/Admin",
"Login": "Login",
"Expired_Action": "Expired Action",
"Expired_Address_List_Name": "Expired Address List Name",
"Address_List": "Address List",
"Optional": "Optional",
"Generated_By": "Generated By",
"Admin": "Admin",
"Password_should_be_minimum_6_characters": "Password should be minimum 6 characters",
"Add_User": "Add User",
"Send_Notification": "Send Notification",
"Code": "Code",
"Send_To_Customer": "Send To Customer",
"Prev": "Prev",
"Voucher_Not_Found": "Voucher Not Found",
"Miscellaneous": "Miscellaneous",
"OTP_Required": "OTP Required",
"Change": "Change",
"Change_Phone_Number": "Change Phone Number",
"Current_Number": "Current Number",
"New_Number": "New Number",
"Input_your_phone_number": "Input your phone number",
"OTP": "OTP",
"Enter_OTP_that_was_sent_to_your_phone": "Enter OTP that was sent to your phone",
"Update": "Update",
"OTP_is_required_when_user_want_to_change_phone_number": "OTP is required when user want to change phone number",
"Rate": "Rate",
"Burst": "Burst",
"Editing_Bandwidth_will_not_automatically_update_the_plan__you_need_to_edit_the_plan_then_save_again": "Editing Bandwidth will not automatically update the plan, you need to edit the plan then save again",
"OTP_Method": "OTP Method",
"SMS": "SMS",
"WhatsApp": "WhatsApp",
"SMS_and_WhatsApp": "SMS and WhatsApp",
"The_method_which_OTP_will_be_sent_to_user": "The method which OTP will be sent to user",
"Report_Viewer": "Report Viewer",
"Super_Administrator": "Super Administrator",
"Send_To": "Send To",
"Resend": "Resend",
"Alert": "Alert",
"success": "success",
"Click_Here": "Click Here",
"danger": "danger",
"Logout_Successful": "Logout Successful",
"warning": "warning",
"Users_Announcement": "Users Announcement",
"Customer_Announcement": "Customer Announcement",
"1_Period___1_Month__Expires_the_20th_of_each_month": "1 Period = 1 Month, Expires the 20th of each month",
"Period": "Period",
"Add": "Add",
"Select_Payment_Gateway": "Select Payment Gateway",
"Available_Payment_Gateway": "Available Payment Gateway",
"Pay_Now": "Pay Now",
"Please_select_Payment_Gateway": "Please select Payment Gateway",
"Payment_Gateway_Deleted": "Payment Gateway Deleted",
"Payment_Gateway_not_set__please_set_it_in_Settings": "Payment Gateway not set, please set it in Settings",
"Failed_to_create_Transaction__": "Failed to create Transaction..",
"Show_To_Customer": "Type",
"Using": "Using",
"Default": "Default",
"Customer_Balance": "Customer Balance",
"Vouchers": "Vouchers",
"Refill_Customer": "Refill Customer",
"Recharge_Customer": "Recharge Customer",
"Plans": "Plans",
"PPPOE": "PPPOE",
"Bandwidth": "Bandwidth",
"Customers": "Customers",
"Actives": "Actives",
"Name": "Name",
"Confirm": "Confirm",
"Plan": "Plan",
"Total": "Total",
"Current_Cycle": "Current Cycle",
"Additional_Cost": "Additional Cost",
"Remaining": "Remaining",
"Not_Found": "Not Found",
"Cash": "Cash",
"Payment_not_found": "Payment not found",
"If_your_friend_have_Additional_Cost__you_will_pay_for_that_too": "If your friend have Additional Cost, you will pay for that too",
"Cache_cleared_successfully_": "Cache cleared successfully!",
"Paid": "Paid",
"Send_Message": "Send Message",
"Send_Personal_Message": "Send Personal Message",
"Send_Via": "Send Via",
"Compose_your_message___": "Compose your message...",
"Use_placeholders_": "Use placeholders:",
"Customer_Name": "Customer Name",
"Customer_Username": "Customer Username",
"Customer_Phone": "Customer Phone",
"Your_Company_Name": "Your Company Name",
"Message_Sent_Successfully": "Message Sent Successfully",
"Send_Bulk_Message": "Send Bulk Message",
"Group": "Group",
"All_Customers": "All Customers",
"New_Customers": "New Customers",
"Expired_Customers": "Expired Customers",
"Active_Customers": "Active Customers",
"Map": "Map",
"Customer_Location": "Customer Location",
"Account_Type": "Account Type",
"Coordinates": "Coordinates",
"Latitude_and_Longitude_coordinates_for_map_must_be_separate_with_comma____": "Latitude and Longitude coordinates for map must be separate with comma &quot;,&quot;",
"Customer_Geo_Location_Information": "Customer Geo Location Information",
"List": "List",
"Lists": "Lists",
"Single_Customer": "Single Customer",
"Bulk_Customers": "Bulk Customers",
"Message_per_time": "Message per time",
"5_Messages": "5 Messages",
"10_Messages": "10 Messages",
"15_Messages": "15 Messages",
"20_Messages": "20 Messages",
"30_Messages": "30 Messages",
"40_Messages": "40 Messages",
"50_Messages": "50 Messages",
"60_Messages": "60 Messages",
"Use_20_and_above_if_you_are_sending_to_all_customers_to_avoid_server_time_out": "Use 20 and above if you are sending to all customers to avoid server time out",
"Delay": "Delay",
"No_Delay": "No Delay",
"5_Seconds": "5 Seconds",
"10_Seconds": "10 Seconds",
"15_Seconds": "15 Seconds",
"20_Seconds": "20 Seconds",
"Use_at_least_5_secs_if_you_are_sending_to_all_customers_to_avoid_being_banned_by_your_message_provider": "Use at least 5 secs if you are sending to all customers to avoid being banned by your message provider",
"Testing__if_checked_no_real_message_is_sent_": "Testing [if checked no real message is sent]",
"All_fields_are_required": "All fields are required",
"Personal": "Personal",
"Email_Notification": "Email Notification",
"Router_Name___Location": "Router Name \/ Location",
"Plan_Category": "Plan Category",
"ID": "ID",
"Internet_Plan": "Internet Plan",
"Privacy_Policy": "Privacy Policy",
"Terms_and_Conditions": "Terms and Conditions",
"Contact": "Contact",
"will_be_replaced_with_Customer_Name": "will be replaced with Customer Name",
"will_be_replaced_with_Customer_username": "will be replaced with Customer username",
"will_be_replaced_with_Package_name": "will be replaced with Package name",
"will_be_replaced_with_Package_price": "will be replaced with Package price",
"additional_bills_for_customers": "additional bills for customers",
"will_be_replaced_with_Expiration_date": "will be replaced with Expiration date",
"Your_Company_Name_at_Settings": "Your Company Name at Settings",
"Your_Company_Address_at_Settings": "Your Company Address at Settings",
"Your_Company_Phone_at_Settings": "Your Company Phone at Settings",
"Invoice_number": "Invoice number",
"Date_invoice_created": "Date invoice created",
"Payment_gateway_user_paid_from": "Payment gateway user paid from",
"Payment_channel_user_paid_from": "Payment channel user paid from",
"is_Hotspot_or_PPPOE": "is Hotspot or PPPOE",
"Internet_Package": "Internet Package",
"Internet_Package_Prices": "Internet Package Prices",
"Receiver_name": "Receiver name",
"Username_internet": "Username internet",
"User_password": "User password",
"Expired_datetime": "Expired datetime",
"For_Notes_by_admin": "For Notes by admin",
"Transaction_datetime": "Transaction datetime",
"Balance_Before": "Balance Before",
"Balance_After": "Balance After",
"how_much_balance_have_been_send": "how much balance have been send",
"Current_Balance": "Current Balance",
"Sender_name": "Sender name",
"how_much_balance_have_been_received": "how much balance have been received",
"Extend_Postpaid_Expiration": "Extend Postpaid Expiration",
"Allow_Extend": "Allow Extend",
"Extend_Days": "Extend Days",
"Confirmation_Message": "Confirmation Message",
"You_are_already_logged_in": "You are already logged in",
"Extend": "Extend",
"Created___Expired": "Created \/ Expired",
"Bank_Transfer": "Bank Transfer",
"Recharge_Using": "Recharge Using",
"ago": "ago",
"Disabled": "Disabled",
"Banned": "Banned",
"Customer_cannot_login_again": "Customer cannot login again",
"Customer_can_login_but_cannot_buy_internet_plan__Admin_cannot_recharge_customer": "Customer can login but cannot buy internet plan, Admin cannot recharge customer",
"Don_t_forget_to_deactivate_all_active_plan_too": "Don&#39;t forget to deactivate all active plan too",
"Ascending": "Ascending",
"Descending": "Descending",
"Created_Date": "Created Date",
"Inactive": "Inactive",
"Suspended": "Suspended",
"Query": "Query",
"Notes": "Notes",
"This_account_status": "This account status",
"Maintenance_Mode": "Maintenance Mode",
"Maintenance_Mode_Settings": "Maintenance Mode Settings",
"Status_": "Status:",
"End_Date_": "End Date:",
"Save": "Save",
"Site_is_temporarily_unavailable_": "Site is temporarily unavailable.",
"Scheduled_maintenance_is_currently_in_progress__Please_check_back_soon_": "Scheduled maintenance is currently in progress. Please check back soon.",
"We_apologize_for_any_inconvenience_": "We apologize for any inconvenience.",
"The": "The",
"Team": "Team",
"Extend_Package_Expiry": "Extend Package Expiry",
"No": "No",
"Yes": "Yes",
"If_user_buy_same_internet_plan__expiry_date_will_extend": "If user buy same internet plan, expiry date will extend",
"Tax_System": "Tax System",
"Enable_Tax_System": "Enable Tax System",
"Tax_will_be_calculated_in_Internet_Plan_Price": "Tax will be calculated in Internet Plan Price",
"Tax_Rate": "Tax Rate",
"0_5_": "0.5%",
"1_": "1%",
"1_5_": "1.5%",
"2_": "2%",
"5_": "5%",
"10_": "10%",
"Custom": "Custom",
"Tax_Rates_in_percentage": "Tax Rates in percentage",
"Custom_Tax_Rate": "Custom Tax Rate",
"Enter_Custom_Tax_Rate": "Enter Custom Tax Rate",
"Enter_the_custom_tax_rate__e_g___3_75_for_3_75__": "Enter the custom tax rate (e.g., 3.75 for 3.75%)",
"Additional_Information": "Additional Information",
"City_of_Resident": "City of Resident",
"District": "District",
"State": "State",
"State_of_Resident": "State of Resident",
"Zip": "Zip",
"Zip_Code": "Zip Code",
"M_Pesa": "M-Pesa",
"sales": "sales",
"Create_Transaction_Success__Please_click_pay_now_to_process_payment": "Create Transaction Success, Please click pay now to process payment",
"Failed_to_send_message": "Failed to send message",
"": "",
"just_now": "just now",
"Backup_Database": "Backup Database",
"Backup_not_found_": "Backup not found.",
"Add_Customer": "Add Customer",
"Clients": "Clients",
"All_Clients": "All Clients",
"New_Client": "New Client",
"Active_Clients": "Active Clients",
"Refill_Client": "Refill Client",
"Recharge_Client": "Recharge Client",
"Top_Up_Wallet": "Top-Up Wallet",
"_Internet_Packages": "Internet Packages",
"Communications": "Communications",
"Single_Client": "Single Client",
"Bulk_Clients": "Bulk Clients",
"Sent_Messages": "Sent Messages",
"Recharge_SMS": "Recharge SMS",
"User_Alerts": "User Alerts",
"Payment_Method": "Payment Method",
"System_Logs": "System Logs",
"Mpesa_Settings": "Mpesa Settings",
"SMS_Balance": "SMS Balance",
"View_Balance": "View Balance",
"Force_Logout_": "Force Logout:",
"Account_Not_Found": "Account Not Found",
"Enter_Username": "Enter Username",
"Enter_Full_Name": "Enter Full Name",
"Enter_Email": "Enter Email",
"Enter_Phone_Number": "Enter Phone Number",
"Enter_Password": "Enter Password",
"Enter_PPPOE_Password": "Enter PPPOE Password",
"Enter_Address": "Enter Address",
"Business": "Business",
"Messages": "Messages",
"Manage_Messages": "Manage Messages",
"Actions": "Actions",
"Download": "Download",
"Uptime": "Uptime",
"Memory_Used_Total": "Memory Used\/Total",
"CPU_Load": "CPU Load",
"Free_Memory": "Free Memory",
"Online_Users": "Online Users",
"Hotspot_Users": "Hotspot Users",
"New_Hotspot_User": "New Hotspot User",
"Server": "Server",
"MAC_Address": "MAC Address",
"Session_Time": "Session Time",
"Rx_Bytes": "Rx Bytes",
"Tx_Bytes": "Tx Bytes",
"Online_Clients": "Online Clients",
"Upload": "Upload",
"Action": "Action",
"Backup_File": "Backup File",
"Are_you_Sure_you_want_to_Restore_this_Database_": "Are you Sure you want to Restore this Database?",
"Restore": "Restore",
"Are_you_Sure_you_want_to_Delete_this_Database_": "Are you Sure you want to Delete this Database?",
"Hotspot_Client": "Hotspot Client",
"Pppoe_Clients": "Pppoe Clients",
"Reboot": "Reboot",
"Close": "Close",
"Today_s_Sales": "Today&#39;s Sales",
"Active_Accounts": "Active Accounts",
"Expired_Accounts": "Expired Accounts",
"Account": "Account",
"Enter_Account_Number": "Enter Account Number",
"Online_Hotspot_Users": "Online Hotspot Users",
"View_Hotspot_Users": "View Hotspot Users",
"Online_PPPoE_Users": "Online PPPoE Users",
"View_PPPoE_Users": "View PPPoE Users",
"Data_Usage": "Data Usage",
"View_Data_Usage": "View Data Usage",
"Amount": "Amount",
"Unused": "Unused",
"Used": "Used",
"Quotes": "Quotes",
"Recent_Orders": "Recent Orders",
"Order_ID": "Order ID",
"Add_Client": "Add Client",
"Clients_Map": "Clients Map",
"Admin_Users": "Admin Users",
"Payment_Setup": "Payment Setup",
"Add_New_Client": "Add New Client",
"Acc_Type": "Acc Type",
"Area": "Area",
"Service": "Service",
"Monthly_Customers": "Monthly Customers",
"This_Token_will_act_as_SuperAdmin_Admin_": "This Token will act as SuperAdmin\/Admin.",
"Expired_Users": "Expired Users",
"Fullname": "Fullname",
"Router": "Router",
"IT709": "IT709",
"IT794": "IT794",
"IT889": "IT889",
"Temperature": "Temperature",
"Voltage": "Voltage",
"Wireless_Status": "Wireless Status",
"Interface_Status": "Interface Status",
"Hotspot_Online_Users": "Hotspot Online Users",
"PPPoE_Online_Users": "PPPoE Online Users",
"Traffic_Monitor": "Traffic Monitor",
"Interface_Name": "Interface Name",
"Tx__bytes_Out_": "Tx (bytes Out)",
"Rx__bytes_In_": "Rx (bytes In)",
"Total_Usage": "Total Usage",
"Mac_Address": "Mac Address",
"Session_Time_Left": "Session Time Left",
"Upload__RX_": "Upload (RX)",
"Download__TX_": "Download (TX)",
"Caller_ID": "Caller ID",
"Interface": "Interface",
"Last_Ip": "Last Ip",
"Last_Activity": "Last Activity",
"Signal_Strength": "Signal Strength",
"Tx___Rx_CCQ": "Tx \/ Rx CCQ",
"Rx_Rate": "Rx Rate",
"Tx_Rate": "Tx Rate",
"Interace": "Interace",
"TX": "TX",
"RX": "RX",
"Date_Time": "Date\/Time",
"Topic": "Topic",
"Info": "Info",
"Success": "Success",
"Warning": "Warning",
"Error": "Error",
"IT983": "IT983",
"moha": "moss",
"Username_should_be_between_3_to_45_characters": "Username should be between 3 to 45 characters",
"Full_Name_should_be_between_3_to_45_characters": "Full Name should be between 3 to 45 characters",
"Mpesa_C2B_Settings__Offline_Payment_": "Mpesa C2B Settings [Offline Payment]",
"M_Pesa_C2B_Payment_Gateway": "M-Pesa C2B Payment Gateway",
"M_Pesa_C2B_Environment": "M-Pesa C2B Environment",
"SandBox_or_Testing": "SandBox or Testing",
"Live_or_Production": "Live or Production",
"Sandbox": "Sandbox",
"is_for_testing_purpose__please_switch_to": "is for testing purpose, please switch to",
"Live": "Live",
"in_production_": "in production.",
"Accept_Insufficient_Fee": "Accept Insufficient Fee",
"You_haven_t_registered_your_validation_and_verification_URLs__Please_register_URLs_by_clicking_": "You haven&#39;t registered your validation and verification URLs, Please register URLs by clicking",
"Payment_History": "Payment History",
"Transaction_Type": "Transaction Type",
"Transaction_Time": "Transaction Time",
"Amount_Paid": "Amount Paid",
"Package_Name": "Package Name",
"Package_Price": "Package Price",
"Bill_Ref_Number": "Bill Ref Number",
"Company_Balance": "Company Balance",
"_Cleared_the_system_cache_": "Cleared the system cache",
"taxip": "taxi",
"lessa": "lessa",
"brian": "brian",
"hussein": "hussein",
"lucy": "lucy",
"karis": "cook",
"taslim": "surrender",
"sofia": "sofia",
"cynthia": "cynthia",
"husein": "Hussein",
"shad": "shad",
"aliali": "face",
"briton": "briton",
"729632854": "729632854",
"oscar": "oscar"
}

8
system/lan/index.html Normal file
View File

@ -0,0 +1,8 @@
<html>
<head>
<title>403 Forbidden</title>
</head>
<body>
<p>Directory access is forbidden.</p>
</body>
</html>

480
system/lan/indonesia.json Normal file
View File

@ -0,0 +1,480 @@
{
"Log_in": "Masuk",
"Register": "Daftar",
"Announcement": "Pemberitahuan",
"Registration_Info": "Info Pendaftaran",
"Voucher_not_found__please_buy_voucher_befor_register": "Voucher tidak ditemukan, silakan beli voucher sebelum mendaftar",
"Register_Success__You_can_login_now": "Daftar Sukses! Anda dapat masuk sekarang",
"Log_in_to_Member_Panel": "Masuk ke Panel Anggota",
"Register_as_Member": "Daftar sebagai Anggota",
"Enter_Admin_Area": "Masuk ke Admin Panel",
"PHPNuxBill": "PHPNuxBill",
"Username": "Nama Pengguna",
"Password": "Kata Sandi",
"Passwords_does_not_match": "Kata sandi tidak cocok",
"Account_already_axist": "Akun telah ada",
"Manage": "Mengelola",
"Submit": "Kirim",
"Save_Changes": "Simpan Perubahan",
"Cancel": "Batal",
"Edit": "Sunting",
"Delete": "Hapus",
"Welcome": "Selamat Datang",
"Data_Created_Successfully": "Data Berhasil Dibuat",
"Data_Updated_Successfully": "Data Berhasil Diperbarui",
"Data_Deleted_Successfully": "Data Berhasil Dihapus",
"Static_Pages": "Halaman Statis",
"Failed_to_save_page__make_sure_i_can_write_to_folder_pages___i_chmod_664_pages___html_i_": "Gagal menyimpan halaman, pastikan diperbolehkan menulis file di folder pages, <i>chmod 664 pages\/*.html<i>",
"Saving_page_success": "Menyimpan halaman berhasil",
"Sometimes_you_need_to_refresh_3_times_until_content_change": "Terkadang Anda perlu menyegarkan 3 kali hingga konten berubah",
"Dashboard": "Dasbor",
"Search_Customers___": "Cari Member...",
"My_Account": "Akun Saya",
"My_Profile": "Profil Saya",
"Settings": "Pengaturan",
"Edit_Profile": "Sunting Profil",
"Change_Password": "Ganti kata sandi",
"Logout": "Keluar",
"Services": "Layanan",
"Bandwidth_Plans": "Paket Bandwidth",
"Bandwidth_Name": "Nama Bandwidth",
"New_Bandwidth": "Bandwidth Baru",
"Edit_Bandwidth": "Sunting Bandwidth",
"Add_New_Bandwidth": "Tambahkan Bandwidth Baru",
"Rate_Download": "Nilai Unduhan",
"Rate_Upload": "Nilai Unggahan",
"Name_Bandwidth_Already_Exist": "Nama Bandwidth sudah ada",
"Hotspot_Plans": "Paket Hotspot",
"PPPOE_Plans": "Paket PPPoE",
"Plan_Name": "Nama Paket",
"New_Service_Plan": "Paket Layanan Baru",
"Add_Service_Plan": "Tambah Paket Layanan",
"Edit_Service_Plan": "Sunting Paket Layanan",
"Name_Plan_Already_Exist": "Nama Paket sudah ada",
"Plan_Type": "Jenis Paket",
"Plan_Price": "Harga Paket",
"Limit_Type": "Tipe Batas",
"Unlimited": "Tak Terbatas",
"Limited": "Terbatas",
"Time_Limit": "Batas waktu",
"Data_Limit": "Batas Data",
"Both_Limit": "Membatasi keduanya",
"Plan_Validity": "Waktu Paket",
"Select_Bandwidth": "Pilih Bandwidth",
"Shared_Users": "Berbagi Pelanggan",
"Choose_User_Type_Sales_to_disable_access_to_Settings": "Pilih Sales untuk menonaktifkan akses ke Pengaturan",
"Current_Password": "Kata sandi saat ini",
"New_Password": "Kata sandi baru",
"Administrator": "Administrator",
"Sales": "Sales",
"Member": "Anggota",
"Confirm_New_Password": "Konfirmasi sandi baru",
"Confirm_Password": "Konfirmasi sandi",
"Full_Name": "Nama Lengkap",
"User_Type": "Tipe Pelanggan",
"Address": "Alamat",
"Created_On": "Dibuat pada",
"Expires_On": "Kedaluwarsa pada",
"Phone_Number": "Nomor telepon",
"User_deleted_Successfully": "Pelanggan berhasil dihapus",
"Full_Administrator": "Administrator Penuh",
"Keep_Blank_to_do_not_change_Password": "Biarkan kosong apabila tidak ingin mengubah kata sandi",
"Keep_it_blank_if_you_do_not_want_to_show_currency_code": "Kosongkan jika Anda tidak ingin menampilkan kode mata uang",
"Theme_Style": "Gaya Tema",
"Theme_Color": "Warna Tema",
"Default_Language": "Bahasa Bawaan",
"Network": "Jaringan",
"Routers": "Router",
"IP_Pool": "IP Pool",
"New_Router": "Router baru",
"Add_Router": "Tambahkan Router",
"Edit_Router": "Sunting Router",
"Router_Name": "Nama Router",
"IP_Address": "Alamat IP",
"Router_Secret": "Password Router",
"Description": "Deskrispi",
"IP_Router_Already_Exist": "IP Router sudah ada",
"Name_Pool": "Nama Pool",
"Range_IP": "Rentang IP",
"New_Pool": "Pool baru",
"Add_Pool": "Tambahkan Pool",
"Edit_Pool": "Sunting Pool",
"Pool_Name_Already_Exist": "Nama Pool sudah ada",
"Refill_Account": "Isi Ulang Akun",
"Recharge_Account": "Isi Ulang Akun",
"Select_Account": "Pilih Akun",
"Service_Plan": "Paket Layanan",
"Recharge": "Isi Ulang",
"Method": "Metode",
"Account_Created_Successfully": "Akun berhasil dibuat",
"Database_Status": "Status Database",
"Total_Database_Size": "Ukuran total database",
"Download_Database_Backup": "Unduh cadangan database",
"Table_Name": "Nama Tabel",
"Rows": "Baris",
"Size": "Ukuran",
"Customer": "Pelanggan",
"Add_New_Contact": "Tambahkan Kontak Baru",
"Edit_Contact": "Sunting Kontak",
"List_Contact": "Daftar Kontak",
"Manage_Contact": "Kelola Kontak",
"Reports": "Laporan",
"Daily_Reports": "Laporan Harian",
"Period_Reports": "Laporan Periode",
"All_Transactions": "Semua Transaksi",
"Total_Income": "Jumlah Pemasukan",
"All_Transactions_at_Date": "Semua transaksi pada ganggal",
"Export_for_Print": "Ekspor untuk cetak",
"Print": "Cetak",
"Export_to_PDF": "Ekspor ke PDF",
"Click_Here_to_Print": "Klik Disini untuk mencetak",
"You_can_use_html_tag": "Anda dapat menggunakan tag HTML",
"Date_Format": "Format tanggal",
"Income_Today": "Pendapatan hari ini",
"Income_This_Month": "Penghasilan bulan ini",
"Users_Active": "Pelanggan Aktif",
"Total_Users": "Total Pelanggan",
"Users": "Pelanggan",
"Edit_User": "Sunting Pelanggan",
"Last_Login": "Terakhir Masuk",
"Administrator_Users": "Pengguna Administrator",
"Manage_Administrator": "Kelola Administrator",
"Add_New_Administrator": "Tambahkan Administrator Baru",
"Localisation": "Lokalisasi",
"Backup_Restore": "Cadangkan\/Pulihkan",
"General_Settings": "Pengaturan Umum",
"Date": "Tanggal",
"Login_Successful": "Berhasil Masuk",
"Failed_Login": "Gagal Masuk",
"Settings_Saved_Successfully": "Pengaturan Berhasil Disimpan",
"User_Updated_Successfully": "Pengguna Berhasil Diperbarui",
"User_Expired__Today": "Pengguna Kedaluwarsa, Hari Ini",
"Activity_Log": "Log Aktivitas",
"View_Reports": "Lihat Laporan",
"View_All": "Lihat semua",
"Number_of_Vouchers": "Jumlah Voucher",
"Length_Code": "Panjang Kode",
"Code_Voucher": "Kode Voucher",
"Voucher": "Voucher",
"Hotspot_Voucher": "Voucher Hotspot",
"Status_Voucher": "Voucher Status",
"Add_Vouchers": "Tambah Voucher",
"Create_Vouchers_Successfully": "Buat Voucher Berhasil",
"Generate": "Menghasilkan",
"Print_side_by_side__it_will_easy_to_cut": "Info Cetak",
"From_Date": "Dari tanggal",
"To_Date": "Hingga saat ini",
"New_Service": "Layanan Baru",
"Type": "Jenis",
"Finish": "Menyelesaikan",
"Application_Name__Company_Name": "Nama Aplikasi\/ Nama Perusahaan",
"This_Name_will_be_shown_on_the_Title": "Nama ini akan ditampilkan pada Judul",
"Next": "Berikutnya",
"Last": "Terakhir",
"Timezone": "Zona waktu",
"Decimal_Point": "Titik Desimal",
"Thousands_Separator": "Pemisah Ribuan",
"Currency_Code": "Kode Mata Uang",
"Order_Voucher": "Pesan Voucher",
"Voucher_Activation": "Aktivasi Voucher",
"List_Activated_Voucher": "Daftar Voucher yang diaktifkan",
"Enter_voucher_code_here": "Masukkan kode voucher di sini",
"Private_Message": "Pesan Pribadi",
"Inbox": "Kotak Masuk",
"Outbox": "Kotak Keluar",
"Compose": "Menyusun",
"Send_to": "Kirim ke",
"Title": "Judul",
"Message": "Pesan",
"Your_Account_Information": "Informasi Akun Anda",
"Welcome_to_the_Panel_Members_page__on_this_page_you_can_": "Selamat datang di halaman Anggota Panel, di halaman ini Anda dapat:",
"Invalid_Username_or_Password": "Nama pengguna atau kata sandi salah",
"You_do_not_have_permission_to_access_this_page": "Anda tidak memiliki izin untuk mengakses halaman ini",
"Incorrect_Current_Password": "Kata sandi saat ini salah",
"Password_changed_successfully__Please_login_again": "Kata sandi berhasil diubah, silakan login kembali",
"All_field_is_required": "Semua bidang wajib diisi",
"Voucher_Not_Valid": "Voucher tidak berlaku",
"Activation_Vouchers_Successfully": "Aktivasi Voucher Berhasil",
"Data_Not_Found": "Data tidak ditemukan",
"Search_by_Username": "Cari berdasarkan nama pengguna",
"Search_by_Name": "Cari berdasarkan nama",
"Search_by_Code_Voucher": "Cari berdasarkan kode voucher",
"Search": "Mencari",
"Select_a_customer": "Pilih pelanggan",
"Select_Routers": "Pilih Router",
"Select_Plans": "Pilih Paket",
"Select_Pool": "Pilih Pool",
"Hrs": "Jam",
"Mins": "Menit",
"Days": "Hari",
"Months": "Bulan",
"Add_Language": "Tambahkan Bahasa",
"Language_Name": "Nama Bahasa",
"Folder_Name": "Nama Folder",
"Translator": "Penerjemah",
"Language_Name_Already_Exist": "Nama Bahasa sudah ada",
"Payment_Gateway": "Gerbang Pembayaran",
"Community": "Komunitas",
"1_user_can_be_used_for_many_devices_": "1 pengguna bisa digunakan untuk banyak perangkat?",
"Cannot_be_change_after_saved": "Tidak dapat diubah setelah disimpan",
"Explain_Coverage_of_router": "Jelaskan cakupan router",
"Name_of_Area_that_router_operated": "Nama area tempat router dioperasikan",
"Payment_Notification_URL__Recurring_Notification_URL__Pay_Account_Notification_URL": "URL notifikasi pembayaran, URL notifikasi berulang, URL notifikasi akun bayar",
"Finish_Redirect_URL__Unfinish_Redirect_URL__Error_Redirect_URL": "Selesaikan URL pengalihan, selesaikan URL pengalihan, URL pengalihan kesalahan",
"Status": "Status",
"Plan_Not_found": "Paket tidak ditemukan",
"Failed_to_create_transaction_": "Gagal membuat transaksi.",
"Seller_has_not_yet_setup_Xendit_payment_gateway": "Penjual belum menyiapkan gateway pembayaran Xendit",
"Admin_has_not_yet_setup_Xendit_payment_gateway__please_tell_admin": "Admin belum menyiapkan gerbang pembayaran Xendit, mohon beritahu Admin",
"Buy_this__your_active_package_will_be_overwrite": "Beli ini? Paket aktif Anda akan ditimpa",
"You_already_have_unpaid_transaction__cancel_it_or_pay_it_": "Anda sudah memiliki transaksi yang belum dibayar, batalkan atau bayar.",
"Transaction_Not_found": "Transaksi tidak ditemukan",
"Cancel_it_": "Batalkan itu?",
"expired": "Kedaluwarsa",
"Check_for_Payment": "Periksa Pembayaran",
"Transaction_still_unpaid_": "Transaksi masih belum dibayar.",
"Paid_Date": "Tanggal Pembayaran",
"Transaction_has_been_paid_": "Transaksi telah dibayar.",
"PAID": "DIBAYAR",
"CANCELED": "DIBATALKAN",
"UNPAID": "BELUM DIBAYAR",
"PAY_NOW": "BAYAR SEKARANG",
"Buy_Hotspot_Plan": "Beli Paket Hotspot",
"Buy_PPOE_Plan": "Beli Paket PPPoE",
"Package": "Paket",
"Order_Internet_Package": "Pesan Paket Internet",
"Unknown_Command_": "Perintah tidak diketahui.",
"Checking_payment": "Memeriksa pembayaran",
"Create_Transaction_Success": "Transaksi berhasil dibuat",
"You_have_unpaid_transaction": "Anda memiliki transaksi yang belum dibayar",
"TripayPayment_Channel": "Saluran Pembayaran Tripay",
"Payment_Channel": "Saluran Pembayaran",
"Payment_check_failed_": "Pemeriksaan pembayaran gagal.",
"Order_Package": "Pesan Paket",
"Transactions": "Transaksi",
"Payments": "Pembayaran",
"History": "Riwayat",
"Order_History": "Riwayat Pesanan",
"Gateway": "Gerbang",
"Date_Done": "Tanggal Selesai",
"Unpaid_Order": "Pesanan Belum Dibayar",
"Payment_Gateway_Not_Found": "Gerbang Pembayaran tidak ditemukan",
"Payment_Gateway_saved_successfully": "Gerbang Pembayaran berhasil disimpan",
"ORDER": "MEMESAN",
"Package_History": "Riwayat Paket",
"Buy_History": "Riwayat Beli",
"Activation_History": "Riwayat Aktivasi",
"Buy_Package": "Beli Paket",
"Email": "Email",
"Company_Footer": "Catatan Kaki Perusahaan",
"Will_show_below_user_pages": "Akan ditampilkan dibawah halaman pengguna",
"Request_OTP": "Minta OTP",
"Verification_Code": "Kode Verifikasi",
"SMS_Verification_Code": "Kode Verifikasi SMS",
"Please_enter_your_email_address": "Silakan masukkan alamat email Anda",
"Failed_to_create_Paypal_transaction_": "Gagal membuat transaksi Paypal.",
"Plugin": "Plugin",
"Plugin_Manager": "Manajer Plugin",
"User_Notification": "Pemberitahuan Pelanggan",
"Expired_Notification": "Pemberitahuan Kedaluwarsa",
"User_will_get_notification_when_package_expired": "Pengguna akan mendapat notifikasi ketika paket sudah habis masa berlakunya",
"Expired_Notification_Message": "Pesan Pemberitahuan Kedaluwarsa",
"Payment_Notification": "Notifikasi Pembayaran",
"User_will_get_invoice_notification_when_buy_package_or_package_refilled": "Pengguna akan mendapatkan notifikasi invoice saat membeli paket atau isi ulang paket",
"Current_IP": "IP saat ini",
"Current_MAC": "MAC saat ini",
"Login_Status": "Status Masuk",
"Login_Request_successfully": "Permintaan masuk berhasil",
"Logout_Request_successfully": "Permintaan keluar berhasil",
"Disconnect_Internet_": "Putuskan sambungan internet?",
"Not_Online__Login_now_": "Tidak, masuk sekarang?",
"You_are_Online__Logout_": "Kamu sedang aktif, ingin keluar?",
"Connect_to_Internet_": "Hubungkan ke Internet?",
"Your_account_not_connected_to_internet": "Akun Anda tidak terhubung ke internet",
"Failed_to_create_transaction__": "Gagal membuat transaksi. ",
"Failed_to_check_status_transaction__": "Gagal memeriksa status transaksi.",
"Disable_Voucher": "Nonaktifkan Voucher",
"Balance": "Saldo",
"Balance_System": "Saldo Sistem",
"Enable_System": "Aktifkan Sistem",
"Allow_Transfer": "Izinkan Transfer",
"Telegram_Notification": "Pemberitahuan Telegram",
"SMS_OTP_Registration": "Pendaftaran SMS OTP",
"Whatsapp_Notification": "Pemberitahuan WhatsApp",
"Tawk_to_Chat_Widget": "Widget Obrolan Tawk.to",
"Invoice": "Faktur",
"Country_Code_Phone": "Kode Negara Telepon",
"Voucher_activation_menu_will_be_hidden": "Menu aktivasi voucher akan disembunyikan",
"Customer_can_deposit_money_to_buy_voucher": "Pelanggan dapat menyetor uang untuk membeli voucher",
"Allow_balance_transfer_between_customers": "Izinkan transfer saldo antar pelanggan",
"Reminder_Notification": "Pemberitahuan Pengingat",
"Reminder_Notification_Message": "Pesan Pemberitahuan Pengingat",
"Reminder_7_days": "Pengingat 7 hari",
"Reminder_3_days": "Pengingat 3 hari",
"Reminder_1_day": "Pengingat 1 hari",
"PPPOE_Password": "Kata sandi PPPoE",
"User_Cannot_change_this__only_admin__if_it_Empty_it_will_use_user_password": "Pelanggan tidak dapat mengubah ini, hanya Admin. Jika kosong maka akan menggunakan kata sandi pelanggan",
"Invoice_Balance_Message": "Faktur Pesan Saldo",
"Invoice_Notification_Payment": "Faktur Pemberitahuan Pembayaran",
"Balance_Notification_Payment": "Saldo Pemberitahuan Pembayaran",
"Balance_Plans": "Paket Saldo",
"Buy_Balance": "Beli Saldo",
"Price": "Harga",
"Validity": "Waktu",
"Disable_auto_renewal_": "Nonaktifkan perpanjangan otomatis?",
"Auto_Renewal_On": "Perpanjangan otomatis aktif",
"Enable_auto_renewal_": "Aktifkan perpanjangan otomatis?",
"Auto_Renewal_Off": "Perpanjangan otomatis mati",
"Refill_Balance": "Isi Ulang Saldo",
"Invoice_Footer": "Catatan Kaki Faktur",
"Pay_With_Balance": "Bayar dengan Saldo",
"Pay_this_with_Balance__your_active_package_will_be_overwrite": "Bayar ini dengan Saldo? Paket aktif Anda akan ditimpa",
"Success_to_buy_package": "Berhasil membeli paket",
"Auto_Renewal": "Perpanjangan otomatis",
"View": "Melihat",
"Back": "Kembali",
"Active": "Aktif",
"Transfer_Balance": "Kirim saldo",
"Send_your_balance_": "Kirim saldo Anda?",
"Send": "Kirim",
"Cannot_send_to_yourself": "Tidak dapat mengirim ke diri Anda sendiri",
"Sending_balance_success": "Berhasil mengirim saldo",
"From": "Dari",
"To": "Ke",
"insufficient_balance": "Saldo tidak mencukupi",
"Send_Balance": "Kirim saldo",
"Received_Balance": "Saldo yang diterima",
"Minimum_Balance_Transfer": "Minimal transfer saldo",
"Minimum_Transfer": "Minimal Transfer",
"Company_Logo": "Logo Perusahaan",
"Expired_IP_Pool": "IP Pool Kedaluwarsa",
"Proxy": "Proksi",
"Proxy_Server": "Server Proksi",
"Proxy_Server_Login": "Masuk Server Proksi",
"Hotspot_Plan": "Paket Hotspot",
"PPPOE_Plan": "Paket PPPoE",
"UNKNOWN": "TIDAK DIKENAL",
"Are_You_Sure_": "Apa kamu yakin?",
"Success_to_send_package": "Berhasil mengirim paket",
"Target_has_active_plan__different_with_current_plant_": "Target mempunyai paket aktif, berbeda dengan paket saat ini.",
"Recharge_a_friend": "Isi ulang teman",
"Buy_for_friend": "Beli untuk teman",
"Buy_this_for_friend_account_": "Beli ini untuk akun teman?",
"Review_package_before_recharge": "Tinjau paket sebelum mengisi ulang",
"Activate": "Mengaktifkan paket",
"Deactivate": "Menonaktifkan paket",
"Sync": "Sinkronisasi",
"Failed_to_create_PaymeTrust_transaction_": "Gagal membuat transaksi PaymeTrust.",
"Location": "Lokasi",
"Radius_Plans": "Paket Radius",
"Change_title_in_user_Plan_order": "Ubah Judul dalam urutan paket pelanggan",
"Logs": "Log",
"Voucher_Format": "Format Voucher",
"Resend_To_Customer": "Kirim Ulang Ke Pelanggan",
"Service_Type": "Jenis Layanan",
"Others": "Lainnya",
"PPPoE": "PPPoE",
"Hotspot": "Hotspot",
"Monthly_Registered_Customers": "Pendaftaran Pelanggan perbulan",
"Total_Monthly_Sales": "Total penjualan perbulan",
"Active_Users": "Pelanggan Aktif",
"SuperAdmin": "Super Admin",
"Lists": "Daftar",
"Vouchers": "Voucher",
"Refill_Customer": "Isi Ulang Pelanggan",
"Recharge_Customer": "Isi Ulang Pelanggan",
"Plans": "Paket",
"PPPOE": "PPPOE",
"Bandwidth": "Bandwidth",
"Send_Message": "Mengirim pesan",
"Single_Customer": "Pelanggan Tunggal",
"Bulk_Customers": "Pelanggan Massal",
"Radius": "Radius",
"Radius_NAS": "Radius NAS",
"Customer_Announcement": "Pengumuman Pelanggan",
"Language_Editor": "Editor Bahasa",
"Plan_Category": "Kategori Paket",
"ID": "ID",
"Prev": "Sebelumnya",
"Internet_Plan": "Paket Internet",
"Generated_By": "Dihasilkan oleh",
"All_Users_Insights": "Semua Wawasan Pengguna",
"year": "Tahun",
"month": "Bulan",
"week": "Pekan",
"day": "Hari",
"hour": "Jam",
"minute": "Menit",
"second": "Kedua",
"Account_Type": "Jenis akun",
"Contact": "Kontak",
"Paid": "Dibayar",
"Personal": "Pribadi",
"Coordinates": "Koordinat",
"Confirm": "Mengonfirmasi",
"Name": "Nama",
"Plan": "Paket",
"Using": "Menggunakan",
"Total": "Total",
"Additional_Cost": "Biaya tambahan",
"Resend": "Kirim ulang",
"Login": "Masuk",
"success": "Sukses",
"Click_Here": "Klik disini",
"Your_friend_do_not_have_active_package": "Teman Anda tidak memiliki paket aktif",
"If_your_friend_have_Additional_Cost__you_will_pay_for_that_too": "Jika teman Anda memiliki biaya tambahan, Anda juga akan membayarnya",
"Select_Payment_Gateway": "Pilih Gerbang Pembayaran",
"Available_Payment_Gateway": "Gerbang Pembayaran yang tersedia",
"Pay_Now": "Bayar sekarang",
"Notes": "Catatan",
"will_be_replaced_with_Customer_Name": "akan diganti dengan nama Pelanggan",
"will_be_replaced_with_Customer_username": "akan diganti dengan nama pengguna Pelanggan",
"will_be_replaced_with_Package_name": "akan diganti dengan nama paket",
"will_be_replaced_with_Package_price": "akan diganti dengan harga Paket",
"will_be_replaced_with_Expiration_date": "akan diganti dengan tanggal kedaluwarsa",
"additional_bills_for_customers": "tagihan tambahan untuk pelanggan",
"Your_Company_Name_at_Settings": "Nama Perusahaan Anda di pengaturan",
"Your_Company_Address_at_Settings": "Alamat Perusahaan Anda di pengaturan",
"Your_Company_Phone_at_Settings": "Telepon Perusahaan Anda di pengaturan",
"Invoice_number": "Nomor faktur",
"Date_invoice_created": "Tanggal faktur dibuat",
"Payment_gateway_user_paid_from": "Pengguna gateway pembayaran membayar dari",
"Payment_channel_user_paid_from": "Pengguna saluran pembayaran membayar dari",
"is_Hotspot_or_PPPOE": "adalah Hotspot atau PPPOE",
"Internet_Package": "Paket internet",
"Internet_Package_Prices": "Harga paket internet",
"Receiver_name": "Nama penerima",
"Username_internet": "Nama pengguna internet",
"User_password": "Kata sandi pengguna",
"Transaction_datetime": "Tanggal waktu transaksi",
"Balance_Before": "Saldo sebelumnya",
"Balance_After": "Saldo setelahnya",
"For_Notes_by_admin": "Untuk catatan oleh Admin",
"how_much_balance_have_been_send": "berapa banyak saldo yang telah dikirim",
"Current_Balance": "Saldo saat ini",
"Sender_name": "Nama pengirim",
"Customer_Balance": "Saldo Pelanggan",
"Privacy_Policy": "Kebijakan Privasi",
"Terms_and_Conditions": "Syarat dan Ketentuan",
"Disable_Registration": "Nonaktifkan Pendaftaran",
"Customer_just_Login_with_Phone_number_and_Voucher_Code__Voucher_will_be_password": "Pelanggan cukup masuk dengan nomor telepon dan kode voucher, Voucher akan menjadi kata sandi",
"After_Customer_activate_voucher_or_login__customer_will_be_redirected_to_this_url": "Setelah Pelanggan mengaktifkan voucher atau masuk, Pelanggan akan diarahkan ke URL ini",
"Extend_Postpaid_Expiration": "Perpanjang masa kedaluwarsa pascabayar",
"Allow_Extend": "Izinkan Perpanjang",
"Extend_Days": "Perpanjang Hari",
"Confirmation_Message": "Pesan konfirmasi",
"Email_Notification": "Pemberitahuan Email",
"This_Token_will_act_as_SuperAdmin_Admin": "Token ini akan bertindak sebagai SuperAdmin\/Admin",
"Miscellaneous": "Aneka ragam",
"OTP_Required": "Diperlukan OTP",
"OTP_is_required_when_user_want_to_change_phone_number": "OTP diperlukan ketika pengguna ingin mengganti nomor telepon",
"OTP_Method": "Metode OTP",
"SMS": "SMS",
"WhatsApp": "WhatsApp",
"SMS_and_WhatsApp": "SMS dan WhatsApp",
"The_method_which_OTP_will_be_sent_to_user": "Metode OTP yang akan dikirimkan ke pengguna",
"Disabled": "Dinonaktifkan",
"Banned": "Dicekal",
"Inactive": "Tidak Aktif",
"Suspended": "Disuspend"
}

377
system/lan/spanish.json Normal file
View File

@ -0,0 +1,377 @@
{
"Log_in": "Entrar",
"Register": "Registro",
"Announcement": "Anuncio",
"Registration_Info": "Informaci\u00f3n de registro",
"Voucher_not_found__please_buy_voucher_befor_register": "Cup\u00f3n no encontrado, compre el cup\u00f3n antes de registrarse",
"Register_Success__You_can_login_now": "\u00a1Registro exitoso! Puedes iniciar sesi\u00f3n ahora",
"Log_in_to_Member_Panel": "Log in to Member Panel",
"Register_as_Member": "Reg\u00edstrese como miembro",
"Enter_Admin_Area": "Panel de administraci\u00f3n",
"PHPNuxBill": "DIGITAL-RED",
"Username": "Usuario",
"Password": "Contrase\u00f1a",
"Passwords_does_not_match": "Las contrase\u00f1as no coinciden",
"Account_already_axist": "La cuenta ya existe",
"Manage": "Administrar",
"Submit": "Enviar",
"Save_Changes": "Guardar cambios",
"Cancel": "Cancelar",
"Edit": "Editar",
"Delete": "Eliminar",
"Welcome": "Bienvenido",
"Data_Created_Successfully": "Datos creados con \u00e9xito",
"Data_Updated_Successfully": "Datos actualizados con \u00e9xito",
"Data_Deleted_Successfully": "Datos eliminados con \u00e9xito",
"Static_Pages": "P\u00e1ginas est\u00e1ticas",
"Failed_to_save_page__make_sure_i_can_write_to_folder_pages___i_chmod_664_pages___html_i_": "No se pudo guardar la p\u00e1gina, aseg\u00farese de que pueda escribir en las p\u00e1ginas de la carpeta, <i>chmod 664 pages\/*.html<i>",
"Saving_page_success": "Guardando el \u00e9xito de la p\u00e1gina",
"Sometimes_you_need_to_refresh_3_times_until_content_change": "A veces es necesario actualizar 3 veces hasta que cambie el contenido",
"Dashboard": "Dashboard",
"Search_Customers___": "Buscar clientes...",
"My_Account": "Mi cuenta",
"My_Profile": "Mi perfil",
"Settings": "Ajustes",
"Edit_Profile": "Editar perfil",
"Change_Password": "Cambia la contrase\u00f1a",
"Logout": "Cerrar sesi\u00f3n",
"Services": "Servicios",
"Bandwidth_Plans": "Planes de velocidad",
"Bandwidth_Name": "Nombre de ancho de banda",
"New_Bandwidth": "Nuevo ancho de banda",
"Edit_Bandwidth": "Editar ancho de banda",
"Add_New_Bandwidth": "Agregar nuevo ancho de banda",
"Rate_Download": "Tarifa Descarga",
"Rate_Upload": "Tasa de subida",
"Name_Bandwidth_Already_Exist": "El ancho de banda del nombre ya existe",
"Hotspot_Plans": "Planes de Hotspot",
"PPPOE_Plans": "Planes PPPOE",
"Plan_Name": "Nombre",
"New_Service_Plan": "Nuevo plan de servicio",
"Add_Service_Plan": "Agregar plan de servicio",
"Edit_Service_Plan": "Editar plan de servicio",
"Name_Plan_Already_Exist": "Nombre El plan ya existe",
"Plan_Type": "Tipo de plan",
"Plan_Price": "Precio del plan",
"Limit_Type": "Tipo de l\u00edmite",
"Unlimited": "Ilimitado",
"Limited": "Limitado",
"Time_Limit": "L\u00edmite de tiempo",
"Data_Limit": "L\u00edmite de datos",
"Both_Limit": "Ambos L\u00edmite",
"Plan_Validity": "Validez del Plan",
"Select_Bandwidth": "Seleccionar ancho de banda",
"Shared_Users": "Usuarios compartidos",
"Choose_User_Type_Sales_to_disable_access_to_Settings": "Elija Ventas de tipo de usuario para deshabilitar el acceso a la Configuraci\u00f3n",
"Current_Password": "Contrase\u00f1a actual",
"New_Password": "Nueva contrase\u00f1a",
"Administrator": "Administrador",
"Sales": "Ventas",
"Member": "Usuario",
"Confirm_New_Password": "Confirmar nueva contrase\u00f1a",
"Confirm_Password": "Confirmar contrase\u00f1a",
"Full_Name": "Nombre completo",
"User_Type": "Tipo de usuario",
"Address": "Direcci\u00f3n",
"Created_On": "Creado en",
"Expires_On": "Expira el",
"Phone_Number": "N\u00famero de tel\u00e9fono",
"User_deleted_Successfully": "Usuario eliminado con \u00e9xito",
"Full_Administrator": "Administrador completo",
"Keep_Blank_to_do_not_change_Password": "Mantener en blanco para no cambiar la contrase\u00f1a",
"Keep_it_blank_if_you_do_not_want_to_show_currency_code": "Mant\u00e9ngalo en blanco si no desea mostrar el c\u00f3digo de moneda",
"Theme_Style": "Estilo de tema",
"Theme_Color": "Color del tema",
"Default_Language": "Idioma predeterminado",
"Network": "Red",
"Routers": "Routers",
"IP_Pool": "IP Pool",
"New_Router": "Nuevo Router",
"Add_Router": "Agregar Router",
"Edit_Router": "Editar Router",
"Router_Name": "Nombre del Router",
"IP_Address": "Direccion IP",
"Router_Secret": "Contrase\u00f1a Router",
"Description": "Descripcion",
"IP_Router_Already_Exist": "El enrutador IP ya existe",
"Name_Pool": "Nombre del Pool",
"Range_IP": "Rango de IP",
"New_Pool": "Nuevo Pool",
"Add_Pool": "Agregar Pool",
"Edit_Pool": "Editar Pool",
"Pool_Name_Already_Exist": "Nombre del Pool ya existe",
"Refill_Account": "Recargar Ficha",
"Recharge_Account": "Recargar Cuenta",
"Select_Account": "Seleccionar cuenta",
"Service_Plan": "Plan de servicio",
"Recharge": "Recargar",
"Method": "M\u00e9todo",
"Account_Created_Successfully": "Cuenta creada con \u00e9xito",
"Database_Status": "Estado de la base de datos",
"Total_Database_Size": "Tama\u00f1o total de la base de datos",
"Download_Database_Backup": "Descargar copia de seguridad de la base de datos",
"Table_Name": "Nombre de la tabla",
"Rows": "Filas",
"Size": "Tama\u00f1o",
"Customer": "Clientes",
"Add_New_Contact": "A\u00f1adir nuevo contacto",
"Edit_Contact": "Editar contacto",
"List_Contact": "Lista de contactos",
"Manage_Contact": "Administrar contacto",
"Reports": "Reportes",
"Daily_Reports": "Reportes diarios",
"Period_Reports": "Informes del per\u00edodo",
"All_Transactions": "Todas las transacciones",
"Total_Income": "Ingresos totales",
"All_Transactions_at_Date": "Todas las transacciones en la fecha",
"Export_for_Print": "Exportar para imprimir",
"Print": "Impresi\u00f3n",
"Export_to_PDF": "Exportar a PDF",
"Click_Here_to_Print": "Haga clic aqu\u00ed para imprimir",
"You_can_use_html_tag": "Puedes usar la etiqueta html",
"Date_Format": "Formato de fecha",
"Income_Today": "Ingresos hoy",
"Income_This_Month": "Ingresos este mes",
"Users_Active": "Usuarios activos",
"Total_Users": "Total de usuarios",
"Users": "Usuarios",
"Edit_User": "Editar usuario",
"Last_Login": "\u00daltimo acceso",
"Administrator_Users": "Usuarios administradores",
"Manage_Administrator": "Administrar administrador",
"Add_New_Administrator": "Agregar nuevo administrador",
"Localisation": "Localizaci\u00f3n",
"Backup_Restore": "Copia de seguridad\/restauracion",
"General_Settings": "Configuraci\u00f3n general",
"Date": "Fecha",
"Login_Successful": "Inicio de sesi\u00f3n exitoso",
"Failed_Login": "Inicio de sesi\u00f3n fallido",
"Settings_Saved_Successfully": "Configuraci\u00f3n guardada con \u00e9xito",
"User_Updated_Successfully": "Usuario actualizado con \u00e9xito",
"User_Expired__Today": "Usuario vencido, hoy",
"Activity_Log": "Registro de actividades",
"View_Reports": "Ver los informes",
"View_All": "Ver todo",
"Number_of_Vouchers": "N\u00famero de Fichas",
"Length_Code": "Longitud de codigo",
"Code_Voucher": "Cup\u00f3n de Ficha",
"Voucher": "Ficha",
"Hotspot_Voucher": "Ficha Hotspot",
"Status_Voucher": "Estatado de Ficha",
"Add_Vouchers": "Agregar Ficha",
"Create_Vouchers_Successfully": "Crear Ficha con \u00e9xito",
"Generate": "Generar",
"Print_side_by_side__it_will_easy_to_cut": "Imprimir uno al lado del otro, ser\u00e1 f\u00e1cil de cortar",
"From_Date": "Partir de la fecha",
"To_Date": "Hasta la fecha",
"New_Service": "Nuevo servicio",
"Type": "Tipo",
"Finish": "Finalizar",
"Application_Name__Company_Name": "Nombre de la aplicaci\u00f3n\/ Nombre de la empresa",
"This_Name_will_be_shown_on_the_Title": "Este nombre se mostrar\u00e1 en el t\u00edtulo",
"Next": "Siguiente",
"Last": "Atras",
"Timezone": "Zona horaria",
"Decimal_Point": "Punto decimal",
"Thousands_Separator": "Separador de miles",
"Currency_Code": "C\u00f3digo de moneda",
"Order_Voucher": "Comprobante de pedido",
"Voucher_Activation": "Activaci\u00f3n de Fichas",
"List_Activated_Voucher": "Lista de Fichas activados",
"Enter_voucher_code_here": "Ingrese el c\u00f3digo de la Ficha aqu\u00ed",
"Private_Message": "Mensaje privado",
"Inbox": "Bandeja de entrada",
"Outbox": "Bandeja de salida",
"Compose": "Componer",
"Send_to": "Enviar a",
"Title": "T\u00edtulo",
"Message": "Mensaje",
"Your_Account_Information": "Informaci\u00f3n de su cuenta",
"Welcome_to_the_Panel_Members_page__on_this_page_you_can_": "Bienvenido a la p\u00e1gina de Miembros del Panel, en esta p\u00e1gina puede:",
"Invalid_Username_or_Password": "Usuario o contrase\u00f1a invalido",
"You_do_not_have_permission_to_access_this_page": "Usted no tiene permiso para acceder a esta p\u00e1gina",
"Incorrect_Current_Password": "IContrase\u00f1a actual incorrecta",
"Password_changed_successfully__Please_login_again": "Contrase\u00f1a cambiada con \u00e9xito, por favor inicie sesi\u00f3n de nuevo",
"All_field_is_required": "Todo el campo es requerido",
"Voucher_Not_Valid": "Ficha no v\u00e1lida",
"Activation_Vouchers_Successfully": "Fichas de activaci\u00f3n con \u00e9xito",
"Data_Not_Found": "Datos no encontrados",
"Search_by_Username": "Buscar por nombre de usuario",
"Search_by_Name": "Buscar por nombre",
"Search_by_Code_Voucher": "B\u00fasqueda por c\u00f3digo de Ficha",
"Search": "B\u00fasqueda",
"Select_a_customer": "Seleccione un cliente",
"Select_Routers": "Seleccionar enrutadores",
"Select_Plans": "Seleccionar planes",
"Select_Pool": "Seleccionar Pool",
"Hrs": "Hrs",
"Mins": "Mins",
"Days": "Dias",
"Months": "Meses",
"Add_Language": "Agregar idioma",
"Language_Name": "Nombre del lenguaje",
"Folder_Name": "Nombre de la carpeta",
"Translator": "Traducir",
"Language_Name_Already_Exist": "El nombre del idioma ya existe",
"Payment_Gateway": "Payment Gateway",
"Community": "Community",
"1_user_can_be_used_for_many_devices_": "1 user can be used for many devices?",
"Cannot_be_change_after_saved": "Cannot be change after saved",
"Explain_Coverage_of_router": "Jelaskan Cakupan wilayah hotspot",
"Name_of_Area_that_router_operated": "Nama Lokasi\/Wilayah Router beroperasi",
"Payment_Notification_URL__Recurring_Notification_URL__Pay_Account_Notification_URL": "Payment Notification URL, Recurring Notification URL, Pay Account Notification URL",
"Finish_Redirect_URL__Unfinish_Redirect_URL__Error_Redirect_URL": "Finish Redirect URL, Unfinish Redirect URL, Error Redirect URL",
"Status": "Status",
"Plan_Not_found": "Plan Not found",
"Failed_to_create_transaction_": "Failed to create transaction.",
"Seller_has_not_yet_setup_Xendit_payment_gateway": "Seller has not yet setup Xendit payment gateway",
"Admin_has_not_yet_setup_Xendit_payment_gateway__please_tell_admin": "Admin has not yet setup Xendit payment gateway, please tell admin",
"Buy_this__your_active_package_will_be_overwrite": "Buy this? your active package will be overwrite",
"You_already_have_unpaid_transaction__cancel_it_or_pay_it_": "You already have unpaid transaction, cancel it or pay it.",
"Transaction_Not_found": "Transaction Not found",
"Cancel_it_": "Cancel it?",
"expired": "expired",
"Check_for_Payment": "Check for Payment",
"Transaction_still_unpaid_": "Transaction still unpaid.",
"Paid_Date": "Paid Date",
"Transaction_has_been_paid_": "Transaction has been paid.",
"PAID": "PAID",
"CANCELED": "CANCELED",
"UNPAID": "UNPAID",
"PAY_NOW": "PAY NOW",
"Buy_Hotspot_Plan": "Buy Hotspot Plan",
"Buy_PPOE_Plan": "Buy PPOE Plan",
"Package": "Package",
"Order_Internet_Package": "Order Internet Package",
"Unknown_Command_": "Unknown Command.",
"Checking_payment": "Checking payment",
"Create_Transaction_Success": "Create Transaction Success",
"You_have_unpaid_transaction": "You have unpaid transaction",
"TripayPayment_Channel": "TripayPayment Channel",
"Payment_Channel": "Payment Channel",
"Payment_check_failed_": "Payment check failed.",
"Order_Package": "Order Package",
"Transactions": "Transactions",
"Payments": "Payments",
"History": "History",
"Order_History": "Order History",
"Gateway": "Gateway",
"Date_Done": "Date Done",
"Unpaid_Order": "Unpaid Order",
"Payment_Gateway_Not_Found": "Payment Gateway Not Found",
"Payment_Gateway_saved_successfully": "Payment Gateway saved successfully",
"ORDER": "ORDER",
"Package_History": "Package History",
"Buy_History": "Buy History",
"Activation_History": "Activation History",
"Buy_Package": "Buy Package",
"Email": "Email",
"Company_Footer": "Company Footer",
"Will_show_below_user_pages": "Will show below user pages",
"Request_OTP": "Request OTP",
"Verification_Code": "Verification Code",
"SMS_Verification_Code": "SMS Verification Code",
"Please_enter_your_email_address": "Please enter your email address",
"Failed_to_create_Paypal_transaction_": "Failed to create Paypal transaction.",
"Plugin": "Plugin",
"Plugin_Manager": "Plugin Manager",
"User_Notification": "User Notification",
"Expired_Notification": "Expired Notification",
"User_will_get_notification_when_package_expired": "User will get notification when package expired",
"Expired_Notification_Message": "Expired Notification Message",
"Payment_Notification": "Payment Notification",
"User_will_get_invoice_notification_when_buy_package_or_package_refilled": "User will get invoice notification when buy package or package refilled",
"Current_IP": "Current IP",
"Current_MAC": "Current MAC",
"Login_Status": "Login Status",
"Login_Request_successfully": "Login Request successfully",
"Logout_Request_successfully": "Logout Request successfully",
"Disconnect_Internet_": "Disconnect Internet?",
"Not_Online__Login_now_": "Not Online, Login now?",
"You_are_Online__Logout_": "You are Online, Logout?",
"Connect_to_Internet_": "Connect to Internet?",
"Your_account_not_connected_to_internet": "Your account not connected to internet",
"Balance": "Balance",
"Balance_System": "Balance System",
"Enable_System": "Enable System",
"Allow_Transfer": "Allow Transfer",
"Telegram_Notification": "Telegram Notification",
"SMS_OTP_Registration": "SMS OTP Registration",
"Whatsapp_Notification": "Whatsapp Notification",
"Tawk_to_Chat_Widget": "Tawk.to Chat Widget",
"Invoice": "Invoice",
"Country_Code_Phone": "Country Code Phone",
"Voucher_activation_menu_will_be_hidden": "Voucher activation menu will be hidden",
"Customer_can_deposit_money_to_buy_voucher": "Customer can deposit money to buy voucher",
"Allow_balance_transfer_between_customers": "Allow balance transfer between customers",
"Refill_Balance": "Refill Balance",
"Balance_Plans": "Balance Plans",
"Failed_to_create_transaction__": "Failed to create transaction. ",
"Failed_to_check_status_transaction__": "Failed to check status transaction. ",
"Disable_Voucher": "Disable Voucher",
"Reminder_Notification": "Reminder Notification",
"Reminder_Notification_Message": "Reminder Notification Message",
"Reminder_7_days": "Reminder 7 days",
"Reminder_3_days": "Reminder 3 days",
"Reminder_1_day": "Reminder 1 day",
"PPPOE_Password": "PPPOE Password",
"User_Cannot_change_this__only_admin__if_it_Empty_it_will_use_user_password": "User Cannot change this, only admin. if it Empty it will use user password",
"Invoice_Balance_Message": "Invoice Balance Message",
"Invoice_Notification_Payment": "Invoice Notification Payment",
"Balance_Notification_Payment": "Balance Notification Payment",
"Buy_Balance": "Buy Balance",
"Price": "Price",
"Validity": "Validity",
"Disable_auto_renewal_": "Disable auto renewal?",
"Auto_Renewal_On": "Auto Renewal On",
"Enable_auto_renewal_": "Enable auto renewal?",
"Auto_Renewal_Off": "Auto Renewal Off",
"Invoice_Footer": "Invoice Footer",
"Pay_With_Balance": "Pay With Balance",
"Pay_this_with_Balance__your_active_package_will_be_overwrite": "Pay this with Balance? your active package will be overwrite",
"Success_to_buy_package": "Success to buy package",
"Auto_Renewal": "Auto Renewal",
"View": "View",
"Back": "Back",
"Active": "Active",
"Transfer_Balance": "Transfer Balance",
"Send_your_balance_": "Send your balance?",
"Send": "Send",
"Cannot_send_to_yourself": "Cannot send to yourself",
"Sending_balance_success": "Sending balance success",
"From": "From",
"To": "To",
"insufficient_balance": "insufficient balance",
"Send_Balance": "Send Balance",
"Received_Balance": "Received Balance",
"Minimum_Balance_Transfer": "Minimum Balance Transfer",
"Minimum_Transfer": "Minimum Transfer",
"Company_Logo": "Company Logo",
"Expired_IP_Pool": "Expired IP Pool",
"Proxy": "Proxy",
"Proxy_Server": "Proxy Server",
"Proxy_Server_Login": "Proxy Server Login",
"Hotspot_Plan": "Hotspot Plan",
"PPPOE_Plan": "PPPOE Plan",
"UNKNOWN": "UNKNOWN",
"Are_You_Sure_": "Are You Sure?",
"Success_to_send_package": "Success to send package",
"Target_has_active_plan__different_with_current_plant_": "Target has active plan, different with current plant.",
"Recharge_a_friend": "Recharge a friend",
"Buy_for_friend": "Buy for friend",
"Buy_this_for_friend_account_": "Buy this for friend account?",
"Review_package_before_recharge": "Review package before recharge",
"Activate": "Activate",
"Deactivate": "Deactivate",
"Sync": "Sync",
"Failed_to_create_PaymeTrust_transaction_": "Failed to create PaymeTrust transaction.",
"Location": "Location",
"Voucher_Format": "Voucher Format",
"Service_Type": "Service Type",
"Others": "Others",
"PPPoE": "PPPoE",
"Hotspot": "Hotspot",
"Monthly_Registered_Customers": "Monthly Registered Customers",
"Total_Monthly_Sales": "Total Monthly Sales",
"Active_Users": "Active Users"
}

3
system/lan/swahili.json Normal file
View File

@ -0,0 +1,3 @@
{
"Settings_Saved_Successfully": "Mipangilio Imehifadhiwa Imefaulu"
}

372
system/lan/turkish.json Normal file
View File

@ -0,0 +1,372 @@
{
"Log_in": "Oturum a\u00e7",
"Register": "Kay\u0131t olmak",
"Announcement": "Duyuru",
"Registration_Info": "Kay\u0131t Bilgisi",
"Voucher_not_found__please_buy_voucher_befor_register": "Kupon bulunamad\u0131, l\u00fctfen kay\u0131t olun ve kay\u0131t olun",
"Register_Success__You_can_login_now": "Kay\u0131t Ba\u015far\u0131l\u0131! \u015eimdi giri\u015f yapabilirsiniz ",
"Log_in_to_Member_Panel": "\u00dcye Paneli'ne giri\u015f yap\u0131n",
"Register_as_Member": "\u00dcye olarak kay\u0131t ol",
"Enter_Admin_Area": "Y\u00f6netici Paneli Giri\u015fi",
"PHPNuxBill": "PHPNuxBill",
"Username": "Kullan\u0131c\u0131 ad\u0131",
"Password": "Parola",
"Passwords_does_not_match": "Parolalar e\u015fle\u015fmiyor",
"Account_already_axist": "Hesap zaten aksanl\u0131",
"Manage": "Y\u00f6net",
"Submit": "G\u00f6nder",
"Save_Changes": "De\u011fi\u015fiklikleri Kaydet",
"Cancel": "\u0130ptal etmek",
"Edit": "D\u00fczenle",
"Delete": "Sil",
"Welcome": "Ho\u015fgeldiniz",
"Data_Created_Successfully": "Veriler Ba\u015far\u0131yla Olu\u015fturuldu ",
"Data_Updated_Successfully": "Veriler Ba\u015far\u0131yla G\u00fcncellendi",
"Data_Deleted_Successfully": "Veri Ba\u015far\u0131yla Silindi",
"Dashboard": "Dashboard",
"Search_Customers___": "M\u00fc\u015fteri Ara ...",
"My_Account": "Hesab\u0131m",
"My_Profile": "Benim profilim",
"Settings": "Ayarlar",
"Edit_Profile": "Profili D\u00fczenle",
"Change_Password": "\u015eifre de\u011fi\u015ftir",
"Logout": "\u00c7\u0131k\u0131\u015f Yap",
"Services": "Hizmetler",
"Bandwidth_Plans": "Bant Geni\u015fli\u011fi Planlar\u0131",
"Bandwidth_Name": "Bant Geni\u015fli\u011fi Ad\u0131",
"New_Bandwidth": "Yeni Bant Geni\u015fli\u011fi",
"Edit_Bandwidth": "Bant Geni\u015fli\u011fini D\u00fczenle",
"Add_New_Bandwidth": "Yeni Bant Geni\u015fli\u011fi Ekle",
"Rate_Download": "\u0130ndirme Oran\u0131",
"Rate_Upload": "\u00dccret Y\u00fckleme",
"Name_Bandwidth_Already_Exist": "Bandwidth Ad\u0131 Zaten Var",
"Hotspot_Plans": "Hotspot Planlar\u0131",
"PPPOE_Plans": "PPPOE Planlar\u0131",
"Plan_Name": "Plan Ad\u0131",
"New_Service_Plan": "Yeni Hizmet Plan\u0131",
"Add_Service_Plan": "Hizmet Plan\u0131 Ekle",
"Edit_Service_Plan": "Hizmet Plan\u0131n\u0131 D\u00fczenle",
"Name_Plan_Already_Exist": "Plan\u0131 \u0130smi Zaten Var",
"Plan_Type": "Plan T\u00fcr\u00fc",
"Plan_Price": "Plan Fiyat\u0131",
"Limit_Type": "S\u0131n\u0131r Tipi",
"Unlimited": "S\u0131n\u0131rs\u0131z",
"Limited": "S\u0131n\u0131rl\u0131",
"Time_Limit": "Zaman s\u0131n\u0131r\u0131",
"Data_Limit": "Veri S\u0131n\u0131r\u0131",
"Both_Limit": "Her \u0130ki S\u0131n\u0131r",
"Plan_Validity": "Plan Ge\u00e7erlili\u011fi",
"Select_Bandwidth": "Bant Geni\u015fli\u011fini Se\u00e7",
"Shared_Users": "Payla\u015f\u0131lan Kullan\u0131c\u0131lar",
"Choose_User_Type_Sales_to_disable_access_to_Settings": "Ayarlar'a eri\u015fimi devre d\u0131\u015f\u0131 b\u0131rakmak i\u00e7in Kullan\u0131c\u0131 T\u00fcr\u00fc Sat\u0131\u015flar\u0131n\u0131 Se\u00e7",
"Current_Password": "\u015eimdiki \u015eifre",
"New_Password": "Yeni \u015eifre",
"Administrator": "Y\u00f6netici",
"Sales": "Sat\u0131\u015f",
"Member": "\u00dcye",
"Confirm_New_Password": "Yeni \u015fifreyi onayla",
"Confirm_Password": "\u015eifreyi Onayla",
"Full_Name": "Ad Soyad",
"User_Type": "Kullan\u0131c\u0131 tipi",
"Address": "Adres",
"Created_On": "Olu\u015fturuldu",
"Expires_On": "Tarihinde sona eriyor",
"Phone_Number": "Telefon numaras\u0131",
"User_deleted_Successfully": "Kullan\u0131c\u0131 Ba\u015far\u0131yla Silindi",
"Full_Administrator": "Tam Y\u00f6netici",
"Keep_Blank_to_do_not_change_Password": "\u015eifreyi de\u011fi\u015ftirmemek i\u00e7in bo\u015f tutun",
"Keep_it_blank_if_you_do_not_want_to_show_currency_code": "Para birimi kodunu g\u00f6stermek istemiyorsan\u0131z bo\u015f b\u0131rak\u0131n",
"Theme_Style": "Tema Stili",
"Theme_Color": "Tema Rengi",
"Default_Language": "Varsay\u0131lan dil",
"Network": "A\u011f",
"Routers": "Y\u00f6nlendiriciler",
"IP_Pool": "IP Havuzu",
"New_Router": "Yeni Y\u00f6nlendirici",
"Add_Router": "Router ekle",
"Edit_Router": "Y\u00f6nlendiriciyi D\u00fczenle",
"Router_Name": "Y\u00f6nlendirici Ad\u0131",
"IP_Address": "IP adresi",
"Router_Secret": "Y\u00f6nlendirici S\u0131rr\u0131",
"Description": "A\u00e7\u0131klama",
"IP_Router_Already_Exist": "IP Router Zaten Var",
"Name_Pool": "\u0130sim Havuzu",
"Range_IP": "Aral\u0131k \u0130P",
"New_Pool": "Yeni Havuz",
"Add_Pool": "Havuz ekle",
"Edit_Pool": "Havuzu D\u00fczenle",
"Pool_Name_Already_Exist": "Havuz Ad\u0131 \u200b\u200bZaten Var",
"Refill_Account": "Hesab\u0131 Yenile",
"Recharge_Account": "Hesab\u0131 Yeniden \u015earj Et",
"Select_Account": "Hesap Se\u00e7",
"Service_Plan": "Servis plan\u0131",
"Recharge": "\u015earj",
"Method": "Y\u00f6ntem",
"Account_Created_Successfully": "Hesap ba\u015far\u0131yla olu\u015fturuldu",
"Database_Status": "Veritaban\u0131 Durumu",
"Total_Database_Size": "Toplam Veritaban\u0131 Boyutu",
"Download_Database_Backup": "Veritaban\u0131 Yedekleme \u0130ndir",
"Table_Name": "Tablo ismi",
"Rows": "Sat\u0131r",
"Size": "Boyut",
"Customer": "M\u00fc\u015fteri",
"Add_New_Contact": "Yeni \u0130leti\u015fim Ekle",
"Edit_Contact": "\u0130leti\u015fim D\u00fczenle",
"List_Contact": "Liste \u0130rtibat",
"Manage_Contact": "Ki\u015fiyi Y\u00f6netin",
"Reports": "Raporlar",
"Daily_Reports": "G\u00fcnl\u00fck raporlar",
"Period_Reports": "D\u00f6nem Raporlar\u0131",
"All_Transactions": "T\u00fcm \u0130\u015flemler",
"Total_Income": "Toplam gelir",
"All_Transactions_at_Date": "Tarihte T\u00fcm \u0130\u015flemler",
"Export_for_Print": "Bask\u0131 i\u00e7in \u0130hracat",
"Print": "Bask\u0131",
"Export_to_PDF": "PDF'ye Aktar",
"Click_Here_to_Print": "Yazd\u0131rmak i\u00e7in Buraya T\u0131klay\u0131n",
"You_can_use_html_tag": "Html etiketini kullanabilirsiniz",
"Date_Format": "Tarih format\u0131",
"Income_Today": "Gelir Bug\u00fcn",
"Income_This_Month": "Bu Ay Gelir",
"Users_Active": "Kullan\u0131c\u0131lar Aktif",
"Total_Users": "Toplam Kullan\u0131c\u0131",
"Users": "Kullan\u0131c\u0131lar",
"Edit_User": "Kullan\u0131c\u0131y\u0131 d\u00fczenle",
"Last_Login": "Son giri\u015f",
"Administrator_Users": "Y\u00f6netici Kullan\u0131c\u0131lar\u0131",
"Manage_Administrator": "Y\u00f6netici Y\u00f6net",
"Add_New_Administrator": "Yeni Y\u00f6netici Ekleyin",
"Localisation": "Lokalizasyon",
"Backup_Restore": "Yedekleme \/ Geri",
"General_Settings": "Genel Ayarlar",
"Date": "Tarih",
"Login_Successful": "Giri\u015f ba\u015far\u0131l\u0131",
"Failed_Login": "Ba\u015far\u0131s\u0131z oturum a\u00e7ma",
"Settings_Saved_Successfully": "Ayarlar ba\u015far\u0131yla kaydedildi",
"User_Updated_Successfully": "Kullan\u0131c\u0131 Ba\u015far\u0131yla G\u00fcncellendi",
"User_Expired__Today": "Kullan\u0131c\u0131 S\u00fcresi Doldu, Bug\u00fcn",
"Activity_Log": "Etkinlik G\u00fcnl\u00fc\u011f\u00fc",
"View_Reports": "Raporlar\u0131 G\u00f6r\u00fcnt\u00fcle",
"View_All": "Hepsini g\u00f6r",
"Number_of_Vouchers": "Kuponlar\u0131n Say\u0131s\u0131",
"Length_Code": "Uzunluk Kodu",
"Code_Voucher": "Kod Makbuzu",
"Voucher": "Fi\u015f",
"Hotspot_Voucher": "Hotspot Kuponu",
"Status_Voucher": "Durum Makbuzu",
"Add_Vouchers": "Kupon Ekle",
"Create_Vouchers_Successfully": "Kuponlar\u0131 ba\u015far\u0131yla olu\u015ftur",
"Generate": "Genel",
"Print_side_by_side__it_will_easy_to_cut": "Yanyana yazd\u0131r\u0131rsan\u0131z, kesmesi daha kolay olacakt\u0131r.",
"From_Date": "\u0130tibaren",
"To_Date": "Bug\u00fcne kadar",
"New_Service": "Yeni Servis",
"Type": "T\u00fcr",
"Finish": "Biti\u015f",
"Application_Name__Company_Name": "Uygulama Ad\u0131 \/ \u015eirket Ad\u0131",
"This_Name_will_be_shown_on_the_Title": "Bu \u0130sim Ba\u015fl\u0131kta g\u00f6sterilecek",
"Next": "Sonraki",
"Last": "Son",
"Timezone": "Saat dilimi",
"Decimal_Point": "Ondal\u0131k nokta",
"Thousands_Separator": "Bin Ay\u0131r\u0131c\u0131",
"Currency_Code": "Para Birimi Kodu",
"Order_Voucher": "Sipari\u015f Makbuzu",
"Voucher_Activation": "Kupon Aktivasyonu",
"List_Activated_Voucher": "Aktif Fi\u015f Listesi",
"Enter_voucher_code_here": "Kupon kodunu buraya girin",
"Private_Message": "\u00d6zel mesaj",
"Inbox": "Gelen kutusu",
"Outbox": "Giden",
"Compose": "Olu\u015fturma",
"Send_to": "G\u00f6nderildi",
"Title": "Ba\u015fl\u0131k",
"Message": "Mesaj",
"Your_Account_Information": "Hesap Bilgileriniz",
"Invalid_Username_or_Password": "Ge\u00e7ersiz kullan\u0131c\u0131 ad\u0131 veya \u015fifre",
"You_do_not_have_permission_to_access_this_page": "Bu sayfaya eri\u015fim izniniz yok",
"Incorrect_Current_Password": "Yanl\u0131\u015f Ge\u00e7erli \u015eifre",
"Password_changed_successfully__Please_login_again": "\u015eifre ba\u015far\u0131yla de\u011fi\u015ftirildi, L\u00fctfen tekrar giri\u015f yap\u0131n",
"All_field_is_required": "T\u00fcm alan gerekli",
"Voucher_Not_Valid": "Kupon Ge\u00e7erli De\u011fil",
"Activation_Vouchers_Successfully": "Aktivasyon Kuponlar\u0131 Ba\u015far\u0131yla",
"Data_Not_Found": "Veri bulunamad\u0131",
"Search_by_Username": "Kullan\u0131c\u0131 Ad\u0131na G\u00f6re Ara",
"Search_by_Name": "\u0130sme G\u00f6re Ara",
"Search_by_Code_Voucher": "Kod Makbuzuna G\u00f6re Ara",
"Search": "Arama",
"Select_a_customer": "Bir m\u00fc\u015fteri se\u00e7in",
"Select_Routers": "Router'lar\u0131 Se\u00e7",
"Select_Plans": "Planlar\u0131 Se\u00e7",
"Select_Pool": "Havuz Se\u00e7",
"Hrs": "Saat",
"Mins": "Dk",
"Days": "G\u00fcn",
"Months": "Ay",
"Add_Language": "Dil Ekle",
"Language_Name": "Dil ad\u0131",
"Folder_Name": "Klas\u00f6r ad\u0131",
"Translator": "\u00c7evirmen",
"Language_Name_Already_Exist": "Dil Ad\u0131 Zaten Var",
"Payment_Gateway": "Payment Gateway",
"Community": "Community",
"1_user_can_be_used_for_many_devices_": "1 user can be used for many devices?",
"Cannot_be_change_after_saved": "Cannot be change after saved",
"Explain_Coverage_of_router": "Jelaskan Cakupan wilayah hotspot",
"Name_of_Area_that_router_operated": "Nama Lokasi\/Wilayah Router beroperasi",
"Payment_Notification_URL__Recurring_Notification_URL__Pay_Account_Notification_URL": "Payment Notification URL, Recurring Notification URL, Pay Account Notification URL",
"Finish_Redirect_URL__Unfinish_Redirect_URL__Error_Redirect_URL": "Finish Redirect URL, Unfinish Redirect URL, Error Redirect URL",
"Status": "Status",
"Plan_Not_found": "Plan Not found",
"Failed_to_create_transaction_": "Failed to create transaction.",
"Seller_has_not_yet_setup_Xendit_payment_gateway": "Seller has not yet setup Xendit payment gateway",
"Admin_has_not_yet_setup_Xendit_payment_gateway__please_tell_admin": "Admin has not yet setup Xendit payment gateway, please tell admin",
"Buy_this__your_active_package_will_be_overwrite": "Buy this? your active package will be overwrite",
"You_already_have_unpaid_transaction__cancel_it_or_pay_it_": "You already have unpaid transaction, cancel it or pay it.",
"Transaction_Not_found": "Transaction Not found",
"Cancel_it_": "Cancel it?",
"expired": "expired",
"Check_for_Payment": "Check for Payment",
"Transaction_still_unpaid_": "Transaction still unpaid.",
"Paid_Date": "Paid Date",
"Transaction_has_been_paid_": "Transaction has been paid.",
"PAID": "PAID",
"CANCELED": "CANCELED",
"UNPAID": "UNPAID",
"PAY_NOW": "PAY NOW",
"Buy_Hotspot_Plan": "Buy Hotspot Plan",
"Buy_PPOE_Plan": "Buy PPOE Plan",
"Package": "Package",
"Order_Internet_Package": "Order Internet Package",
"Unknown_Command_": "Unknown Command.",
"Checking_payment": "Checking payment",
"Create_Transaction_Success": "Create Transaction Success",
"You_have_unpaid_transaction": "You have unpaid transaction",
"TripayPayment_Channel": "TripayPayment Channel",
"Payment_Channel": "Payment Channel",
"Payment_check_failed_": "Payment check failed.",
"Order_Package": "Order Package",
"Transactions": "Transactions",
"Payments": "Payments",
"History": "History",
"Order_History": "Order History",
"Gateway": "Gateway",
"Date_Done": "Date Done",
"Unpaid_Order": "Unpaid Order",
"Payment_Gateway_Not_Found": "Payment Gateway Not Found",
"Payment_Gateway_saved_successfully": "Payment Gateway saved successfully",
"ORDER": "ORDER",
"Package_History": "Package History",
"Buy_History": "Buy History",
"Activation_History": "Activation History",
"Buy_Package": "Buy Package",
"Email": "Email",
"Company_Footer": "Company Footer",
"Will_show_below_user_pages": "Will show below user pages",
"Request_OTP": "Request OTP",
"Verification_Code": "Verification Code",
"SMS_Verification_Code": "SMS Verification Code",
"Please_enter_your_email_address": "Please enter your email address",
"Failed_to_create_Paypal_transaction_": "Failed to create Paypal transaction.",
"Plugin": "Plugin",
"Plugin_Manager": "Plugin Manager",
"User_Notification": "User Notification",
"Expired_Notification": "Expired Notification",
"User_will_get_notification_when_package_expired": "User will get notification when package expired",
"Expired_Notification_Message": "Expired Notification Message",
"Payment_Notification": "Payment Notification",
"User_will_get_invoice_notification_when_buy_package_or_package_refilled": "User will get invoice notification when buy package or package refilled",
"Current_IP": "Current IP",
"Current_MAC": "Current MAC",
"Login_Status": "Login Status",
"Login_Request_successfully": "Login Request successfully",
"Logout_Request_successfully": "Logout Request successfully",
"Disconnect_Internet_": "Disconnect Internet?",
"Not_Online__Login_now_": "Not Online, Login now?",
"You_are_Online__Logout_": "You are Online, Logout?",
"Connect_to_Internet_": "Connect to Internet?",
"Your_account_not_connected_to_internet": "Your account not connected to internet",
"Balance": "Balance",
"Balance_System": "Balance System",
"Enable_System": "Enable System",
"Allow_Transfer": "Allow Transfer",
"Telegram_Notification": "Telegram Notification",
"SMS_OTP_Registration": "SMS OTP Registration",
"Whatsapp_Notification": "Whatsapp Notification",
"Tawk_to_Chat_Widget": "Tawk.to Chat Widget",
"Invoice": "Invoice",
"Country_Code_Phone": "Country Code Phone",
"Voucher_activation_menu_will_be_hidden": "Voucher activation menu will be hidden",
"Customer_can_deposit_money_to_buy_voucher": "Customer can deposit money to buy voucher",
"Allow_balance_transfer_between_customers": "Allow balance transfer between customers",
"Failed_to_create_transaction__": "Failed to create transaction. ",
"Failed_to_check_status_transaction__": "Failed to check status transaction. ",
"Disable_Voucher": "Disable Voucher",
"Reminder_Notification": "Reminder Notification",
"Reminder_Notification_Message": "Reminder Notification Message",
"Reminder_7_days": "Reminder 7 days",
"Reminder_3_days": "Reminder 3 days",
"Reminder_1_day": "Reminder 1 day",
"PPPOE_Password": "PPPOE Password",
"User_Cannot_change_this__only_admin__if_it_Empty_it_will_use_user_password": "User Cannot change this, only admin. if it Empty it will use user password",
"Invoice_Balance_Message": "Invoice Balance Message",
"Invoice_Notification_Payment": "Invoice Notification Payment",
"Balance_Notification_Payment": "Balance Notification Payment",
"Balance_Plans": "Balance Plans",
"Buy_Balance": "Buy Balance",
"Price": "Price",
"Validity": "Validity",
"Disable_auto_renewal_": "Disable auto renewal?",
"Auto_Renewal_On": "Auto Renewal On",
"Enable_auto_renewal_": "Enable auto renewal?",
"Auto_Renewal_Off": "Auto Renewal Off",
"Refill_Balance": "Refill Balance",
"Invoice_Footer": "Invoice Footer",
"Pay_With_Balance": "Pay With Balance",
"Pay_this_with_Balance__your_active_package_will_be_overwrite": "Pay this with Balance? your active package will be overwrite",
"Success_to_buy_package": "Success to buy package",
"Auto_Renewal": "Auto Renewal",
"View": "View",
"Back": "Back",
"Active": "Active",
"Transfer_Balance": "Transfer Balance",
"Send_your_balance_": "Send your balance?",
"Send": "Send",
"Cannot_send_to_yourself": "Cannot send to yourself",
"Sending_balance_success": "Sending balance success",
"From": "From",
"To": "To",
"insufficient_balance": "insufficient balance",
"Send_Balance": "Send Balance",
"Received_Balance": "Received Balance",
"Minimum_Balance_Transfer": "Minimum Balance Transfer",
"Minimum_Transfer": "Minimum Transfer",
"Company_Logo": "Company Logo",
"Expired_IP_Pool": "Expired IP Pool",
"Proxy": "Proxy",
"Proxy_Server": "Proxy Server",
"Proxy_Server_Login": "Proxy Server Login",
"Hotspot_Plan": "Hotspot Plan",
"PPPOE_Plan": "PPPOE Plan",
"UNKNOWN": "UNKNOWN",
"Are_You_Sure_": "Are You Sure?",
"Success_to_send_package": "Success to send package",
"Target_has_active_plan__different_with_current_plant_": "Target has active plan, different with current plant.",
"Recharge_a_friend": "Recharge a friend",
"Buy_for_friend": "Buy for friend",
"Buy_this_for_friend_account_": "Buy this for friend account?",
"Review_package_before_recharge": "Review package before recharge",
"Activate": "Activate",
"Deactivate": "Deactivate",
"Sync": "Sync",
"Failed_to_create_PaymeTrust_transaction_": "Failed to create PaymeTrust transaction.",
"Location": "Location",
"Voucher_Format": "Voucher Format",
"Service_Type": "Service Type",
"Others": "Others",
"PPPoE": "PPPoE",
"Hotspot": "Hotspot",
"Monthly_Registered_Customers": "Monthly Registered Customers",
"Total_Monthly_Sales": "Total Monthly Sales",
"Active_Users": "Active Users"
}

View File

@ -0,0 +1,86 @@
<?php
function stkQuery()
{
header('Content-Type: application/json');
$rawData = file_get_contents('php://input');
$postData = json_decode($rawData, true);
// Check if CheckoutRequestID is set
if (!isset($postData['CheckoutRequestID'])) {
echo json_encode(['status' => 'error', 'code' => 400, 'message' => 'missing CheckoutRequestID fields']);
return;
}
$CheckoutRequestID = $postData['CheckoutRequestID'];
$consumerKey = '3AmVP1WFDQn7GrDH8GcSSKxcAvnJdZGC'; // Fill with your app Consumer Key
$consumerSecret = '71Lybl6jUtxM0F35'; // Fill with your app Secret
$headers = ['Content-Type:application/json; charset=utf8'];
$access_token_url = 'https://api.safaricom.co.ke/oauth/v1/generate?grant_type=client_credentials';
$curl = curl_init($access_token_url);
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($curl, CURLOPT_HEADER, FALSE);
curl_setopt($curl, CURLOPT_USERPWD, $consumerKey.':'.$consumerSecret);
$result = curl_exec($curl);
$status = curl_getinfo($curl, CURLINFO_HTTP_CODE);
$result = json_decode($result);
$access_token = $result->access_token;
date_default_timezone_set('Africa/Nairobi');
$query_url = 'https://api.safaricom.co.ke/mpesa/stkpushquery/v1/query';
$BusinessShortCode = '4122323';
$Passkey = 'aaebecea73082fa56af852606106b1316d5b4dfa2f12d0088800b0b88e4bb6e3';
$Timestamp = date('YmdHis');
// ENCRYPT DATA TO GET PASSWORD
$Password = base64_encode($BusinessShortCode . $Passkey . $Timestamp);
// THIS IS THE UNIQUE ID THAT WAS GENERATED WHEN STK REQUEST INITIATED SUCCESSFULLY
$queryheader = ['Content-Type:application/json', 'Authorization:Bearer ' . $access_token];
// Initiating the transaction
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $query_url);
curl_setopt($curl, CURLOPT_HTTPHEADER, $queryheader); // Setting custom header
$curl_post_data = array(
'BusinessShortCode' => $BusinessShortCode,
'Password' => $Password,
'Timestamp' => $Timestamp,
'CheckoutRequestID' => $CheckoutRequestID
);
$data_string = json_encode($curl_post_data);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data_string);
$curl_response = curl_exec($curl);
$data_to = json_decode($curl_response, true);
// Handle response
if (isset($data_to['ResultCode'])) {
$ResultCode = $data_to['ResultCode'];
if ($ResultCode == '1037') {
$message = "1037 Timeout in completing transaction";
} elseif ($ResultCode == '1032') {
$message = "1032 Transaction has been cancelled by user";
} elseif ($ResultCode == '1') {
$message = "1 The balance is insufficient for the transaction";
} elseif ($ResultCode == '0') {
$message = "0 The transaction is successful";
} else {
$message = "Unknown Result Code: $ResultCode";
}
} else {
$message = "Error in the response received from the M-Pesa API";
}
// Sending the response back
echo json_encode([
'message' => $message,
'result' => $data_to
]);
}
?>

View File

@ -0,0 +1,205 @@
<?php
function BankStkPush_validate_config()
{
global $config;
if (empty($config['Stkbankacc']) || empty($config['Stkbankname']) ) {
sendTelegram("Bank Stk payment gateway not configured");
r2(U . 'order/balance', 'w', Lang::T("Admin has not yet setup the payment gateway, please tell admin"));
}
}
function BankStkPush_show_config()
{
global $ui, $config;
$ui->assign('_title', 'Bank Stk Push - ' . $config['CompanyName']);
$ui->display('bankstkpush.tpl');
}
function BankStkPush_save_config()
{
global $admin, $_L;
$bankacc = _post('account');
$bankname = _post('bankname');
$d = ORM::for_table('tbl_appconfig')->where('setting', 'Stkbankacc')->find_one();
if ($d) {
$d->value = $bankacc;
$d->save();
} else {
$d = ORM::for_table('tbl_appconfig')->create();
$d->setting = 'Stkbankacc';
$d->value = $bankacc;
$d->save();
}
$d = ORM::for_table('tbl_appconfig')->where('setting', 'Stkbankname')->find_one();
if ($d) {
$d->value = $bankname;
$d->save();
} else {
$d = ORM::for_table('tbl_appconfig')->create();
$d->setting = 'Stkbankname';
$d->value = $bankname;
$d->save();
}
_log('[' . $admin['username'] . ']: Stk Bank details ' . $_L['Settings_Saved_Successfully'], 'Admin', $admin['id']);
r2(U . 'paymentgateway/BankStkPush', 's', $_L['Settings_Saved_Successfully']);
}
function BankStkPush_create_transaction($trx, $user )
{
$url=(U. "plugin/initiatebankstk");
$d = ORM::for_table('tbl_payment_gateway')
->where('username', $user['username'])
->where('status', 1)
->find_one();
$d->gateway_trx_id = '';
$d->payment_method = 'Bank Stk Push';
$d->pg_url_payment = $url;
$d->pg_request = '';
$d->expired_date = date('Y-m-d H:i:s', strtotime("+5 minutes"));
$d->save();
r2(U . "order/view/" . $d['id'], 's', Lang::T("Create Transaction Success, Please click pay now to process payment"));
die();
}
function BankStkPush_payment_notification()
{
$captureLogs = file_get_contents("php://input");
$analizzare = json_decode($captureLogs);
/// sleep(10);
file_put_contents('back.log',$captureLogs,FILE_APPEND);
$response_code = $analizzare->Body->stkCallback->ResultCode;
$resultDesc = ($analizzare->Body->stkCallback->ResultDesc);
$merchant_req_id = ($analizzare->Body->stkCallback->MerchantRequestID);
$checkout_req_id = ($analizzare->Body->stkCallback->CheckoutRequestID);
$amount_paid = ($analizzare->Body->stkCallback->CallbackMetadata->Item['0']->Value);//get the amount value
$mpesa_code = ($analizzare->Body->stkCallback->CallbackMetadata->Item['1']->Value);//mpesa transaction code..
$sender_phone = ($analizzare->Body->stkCallback->CallbackMetadata->Item['4']->Value);//Telephone Number
$PaymentGatewayRecord = ORM::for_table('tbl_payment_gateway')
->where('checkout', $checkout_req_id)
->where('status', 1) // Add this line to filter by status
->order_by_desc('id')
->find_one();
$uname=$PaymentGatewayRecord->username;
$plan_id=$PaymentGatewayRecord->plan_id;
$mac_address=$PaymentGatewayRecord->mac_address;
$user=$PaymentGatewayRecord;
$userid = ORM::for_table('tbl_customers')
->where('username', $uname)
->order_by_desc('id')
->find_one();
$userid->username=$uname;
$userid->save();
$plans = ORM::for_table('tbl_plans')
->where('id', $plan_id)
->order_by_desc('id')
->find_one();
if ($response_code=="1032")
{
$now = date('Y-m-d H:i:s');
$PaymentGatewayRecord->paid_date = $now;
$PaymentGatewayRecord->status = 4;
$PaymentGatewayRecord->save();
exit();
}
if($response_code=="1037"){
$PaymentGatewayRecord->status = 1;
$PaymentGatewayRecord->pg_paid_response = 'User failed to enter pin';
$PaymentGatewayRecord->save();
exit();
}
if($response_code=="1"){
$PaymentGatewayRecord->status = 1;
$PaymentGatewayRecord->pg_paid_response = 'Not enough balance';
$PaymentGatewayRecord->save();
exit();
}
if($response_code=="2001"){
$PaymentGatewayRecord->status = 1;
$PaymentGatewayRecord->pg_paid_response = 'Wrong Mpesa pin';
$PaymentGatewayRecord->save();
exit();
}
if($response_code=="0"){
$now = date('Y-m-d H:i:s');
$date = date('Y-m-d');
$time= date('H:i:s');
$check_mpesa = ORM::for_table('tbl_payment_gateway')
->where('gateway_trx_id', $mpesa_code)
->find_one();
if($check_mpesa){
echo "double callback, ignore one";
die;
}
$plan_type=$plans->type;
$UserId=$userid->id;
if (!Package::rechargeUser($UserId, $user['routers'], $user['plan_id'], $user['gateway'], $mpesa_code)){
$PaymentGatewayRecord->status = 2;
$PaymentGatewayRecord->paid_date = $now;
$PaymentGatewayRecord->gateway_trx_id = $mpesa_code;
$PaymentGatewayRecord->save();
$username = $PaymentGatewayRecord->username;
// Check if a transaction with the same gateway_trx_id already exists
$existingTransaction = ORM::for_table('tbl_transactions')
->where('mpesacode', $mpesa_code)
->find_one();
if (!$existingTransaction) {
// Save transaction data to tbl_transactions
$transaction = ORM::for_table('tbl_transactions')->create();
$transaction->invoice = $PaymentGatewayRecord->gateway_trx_id; // Set invoice to gateway_trx_id value
$transaction->username = $PaymentGatewayRecord->username;
$transaction->plan_name = $PaymentGatewayRecord->plan_name;
$transaction->price = $amount_paid;
$transaction->recharged_on = $date;
$transaction->recharged_time = $time;
$transaction->expiration = $now;
$transaction->time = $now;
$transaction->method = $PaymentGatewayRecord->payment_method;
$transaction->routers = 0;
$transaction->Type = 'Balance';
$transaction->mpesacode = $mpesa_code;
$transaction->save();
} else {
error_log("Duplicate transaction entry detected for gateway_trx_id: " . $PaymentGatewayRecord->gateway_trx_id);
}
} else {
// Update tbl_recharges
$PaymentGatewayRecord->status = 2;
$PaymentGatewayRecord->paid_date = $now;
$PaymentGatewayRecord->gateway_trx_id = $mpesa_code;
$PaymentGatewayRecord->save();
}
}
}

View File

@ -0,0 +1,423 @@
<?php
function MpesatillStk_validate_config()
{
global $config;
if (empty($config['mpesa_till_shortcode_code']) || empty($config['mpesa_till_consumer_key']) || empty($config['mpesa_till_consumer_secret']) || empty($config['mpesa_till_partyb']) ) {
sendTelegram("Bank Stk payment gateway not configured");
r2(U . 'order/balance', 'w', Lang::T("Admin has not yet setup the payment gateway, please tell admin"));
}
}
function MpesatillStk_show_config()
{
global $ui, $config;
$ui->assign('env', json_decode(file_get_contents('system/paymentgateway/mpesa_env.json'), true));
$ui->assign('_title', 'M-Pesa - Payment Gateway (for till number only) - ' . $config['CompanyName']);
$ui->display('mpesatill.tpl');
}
function MpesatillStk_save_config()
{
global $admin, $_L;
$mpesa_consumer_key = _post('mpesa_consumer_key');
$mpesa_consumer_secret = _post('mpesa_consumer_secret');
$mpesa_business_code = _post('mpesa_business_code');
$mpesa_till = _post('mpesa_till');
$mpesa_pass_key = _post('mpesa_pass_key');
$mpesa_env = _post('mpesa_env');
$d = ORM::for_table('tbl_appconfig')->where('setting', 'mpesa_till_consumer_key')->find_one();
if ($d) {
$d->value = $mpesa_consumer_key;
$d->save();
} else {
$d = ORM::for_table('tbl_appconfig')->create();
$d->setting = 'mpesa_till_consumer_key';
$d->value = $mpesa_consumer_key;
$d->save();
}
$d = ORM::for_table('tbl_appconfig')->where('setting', 'mpesa_till_consumer_secret')->find_one();
if ($d) {
$d->value = $mpesa_consumer_secret;
$d->save();
} else {
$d = ORM::for_table('tbl_appconfig')->create();
$d->setting = 'mpesa_till_consumer_secret';
$d->value = $mpesa_consumer_secret;
$d->save();
}
$d = ORM::for_table('tbl_appconfig')->where('setting', 'mpesa_till_shortcode_code')->find_one();
if ($d) {
$d->value = $mpesa_business_code;
$d->save();
} else {
$d = ORM::for_table('tbl_appconfig')->create();
$d->setting = 'mpesa_till_shortcode_code';
$d->value = $mpesa_business_code;
$d->save();
}
$d = ORM::for_table('tbl_appconfig')->where('setting', 'mpesa_till_partyb')->find_one();
if ($d) {
$d->value = $mpesa_till;
$d->save();
} else {
$d = ORM::for_table('tbl_appconfig')->create();
$d->setting = 'mpesa_till_partyb';
$d->value = $mpesa_till;
$d->save();
}
$d = ORM::for_table('tbl_appconfig')->where('setting', 'mpesa_till_pass_key')->find_one();
if ($d) {
$d->value = $mpesa_pass_key;
$d->save();
} else {
$d = ORM::for_table('tbl_appconfig')->create();
$d->setting = 'mpesa_till_pass_key';
$d->value = $mpesa_pass_key;
$d->save();
}
$d = ORM::for_table('tbl_appconfig')->where('setting', 'mpesa_env')->find_one();
if ($d) {
$d->value = $mpesa_env;
$d->save();
} else {
$d = ORM::for_table('tbl_appconfig')->create();
$d->setting = 'mpesa_env';
$d->value = $mpesa_env;
$d->save();
}
_log('[' . $admin['username'] . ']: M-Pesa ' . $_L['Settings_Saved_Successfully'] . json_encode($_POST['mpesa_channel']), 'Admin', $admin['id']);
r2(U . 'paymentgateway/MpesatillStk', 's', $_L['Settings_Saved_Successfully']);
}
function MpesatillStk_create_transaction($trx, $user )
{
$url=(U. "plugin/initiatetillstk");
$d = ORM::for_table('tbl_payment_gateway')
->where('username', $user['username'])
->where('status', 1)
->find_one();
$d->gateway_trx_id = '';
$d->payment_method = 'Mpesa till STK';
$d->pg_url_payment = $url;
$d->pg_request = '';
$d->expired_date = date('Y-m-d H:i:s', strtotime("+5 minutes"));
$d->save();
r2(U . "order/view/" . $d['id'], 's', Lang::T("Create Transaction Success, Please click pay now to process payment"));
die();
}
function MpesatillStk_payment_notification()
{
$captureLogs = file_get_contents("php://input");
$analizzare = json_decode($captureLogs);
/// sleep(10);
file_put_contents('back.log',$captureLogs,FILE_APPEND);
$response_code = $analizzare->Body->stkCallback->ResultCode;
$resultDesc = ($analizzare->Body->stkCallback->ResultDesc);
$merchant_req_id = ($analizzare->Body->stkCallback->MerchantRequestID);
$checkout_req_id = ($analizzare->Body->stkCallback->CheckoutRequestID);
$amount_paid = ($analizzare->Body->stkCallback->CallbackMetadata->Item['0']->Value);//get the amount value
$mpesa_code = ($analizzare->Body->stkCallback->CallbackMetadata->Item['1']->Value);//mpesa transaction code..
$sender_phone = ($analizzare->Body->stkCallback->CallbackMetadata->Item['4']->Value);//Telephone Number
$PaymentGatewayRecord = ORM::for_table('tbl_payment_gateway')
->where('checkout', $checkout_req_id)
->where('status', 1) // Add this line to filter by status
->order_by_desc('id')
->find_one();
$uname=$PaymentGatewayRecord->username;
$plan_id=$PaymentGatewayRecord->plan_id;
$mac_address=$PaymentGatewayRecord->mac_address;
$user=$PaymentGatewayRecord;
$userid = ORM::for_table('tbl_customers')
->where('username', $uname)
->order_by_desc('id')
->find_one();
$userid->username=$uname;
$userid->save();
$plans = ORM::for_table('tbl_plans')
->where('id', $plan_id)
->order_by_desc('id')
->find_one();
if ($response_code=="1032")
{
$now = date('Y-m-d H:i:s');
$PaymentGatewayRecord->paid_date = $now;
$PaymentGatewayRecord->status = 4;
$PaymentGatewayRecord->save();
exit();
}
if($response_code=="1037"){
$PaymentGatewayRecord->status = 1;
$PaymentGatewayRecord->pg_paid_response = 'User failed to enter pin';
$PaymentGatewayRecord->save();
exit();
}
if($response_code=="1"){
$PaymentGatewayRecord->status = 1;
$PaymentGatewayRecord->pg_paid_response = 'Not enough balance';
$PaymentGatewayRecord->save();
exit();
}
if($response_code=="2001"){
$PaymentGatewayRecord->status = 1;
$PaymentGatewayRecord->pg_paid_response = 'Wrong Mpesa pin';
$PaymentGatewayRecord->save();
exit();
}
if($response_code=="0"){
$now = date('Y-m-d H:i:s');
$date = date('Y-m-d');
$time= date('H:i:s');
$check_mpesa = ORM::for_table('tbl_payment_gateway')
->where('gateway_trx_id', $mpesa_code)
->find_one();
if($check_mpesa){
echo "double callback, ignore one";
die;
}
$plan_type=$plans->type;
$UserId=$userid->id;
if (!Package::rechargeUser($UserId, $user['routers'], $user['plan_id'], $user['gateway'], $mpesa_code)){
$PaymentGatewayRecord->status = 2;
$PaymentGatewayRecord->paid_date = $now;
$PaymentGatewayRecord->gateway_trx_id = $mpesa_code;
$PaymentGatewayRecord->save();
$username=$PaymentGatewayRecord->username;
// Save transaction data to tbl_transactions
$transaction = ORM::for_table('tbl_transactions')->create();
$transaction->invoice = $mpesa_code;
$transaction->username = $PaymentGatewayRecord->username;
$transaction->plan_name = $PaymentGatewayRecord->plan_name;
$transaction->price = $amount_paid;
$transaction->recharged_on = $date;
$transaction->recharged_time = $time;
$transaction->expiration = $now;
$transaction->time = $now;
$transaction->method = $PaymentGatewayRecord->payment_method;
$transaction->routers = 0;
$transaction->Type = 'Balance';
$transaction->save();
} else{
//lets update tbl_recharges
/*
$transaction = ORM::for_table('tbl_transactions')->create();
$transaction->invoice = $mpesa_code;
$transaction->username = $PaymentGatewayRecord->username;
$transaction->plan_name = $PaymentGatewayRecord->plan_name;
$transaction->price = $amount_paid;
$transaction->recharged_on = $date;
$transaction->recharged_time = $time;
$transaction->expiration = $now;
$transaction->time = $now;
$transaction->method = $PaymentGatewayRecord->payment_method;
$transaction->routers = 0;
$transaction->Type = $PaymentGatewayRecord->routers;
$transaction->save();
*/
$PaymentGatewayRecord->status = 2;
$PaymentGatewayRecord->paid_date = $now;
$PaymentGatewayRecord->gateway_trx_id = $mpesa_code;
$PaymentGatewayRecord->save();
}
/*
$checkid = ORM::for_table('tbl_customers')
->where('username', $username)
->find_one();
$customerid=$checkid->id;
$recharge = ORM::for_table('tbl_user_recharges')->create();
$recharge->customer_id = $customerid;
$recharge->username = $PaymentGatewayRecord->username;
$recharge->plan_id = $PaymentGatewayRecord->plan_id;
$recharge->price = $amount_paid;
$recharge->recharged_on = $date;
$recharge->recharged_time = $time;
$recharge->expiration = $now;
$recharge->time = $now;
$recharge->method = $PaymentGatewayRecord->payment_method;
$recharge->routers = 0;
$recharge->Type = 'Balance';
$recharge->save();
*/
// $user = ORM::for_table('tbl_customers')
// ->where('username', $username)
// ->find_one();
// $currentBalance = $user->balance;
// $user->balance = $currentBalance + $amount_paid;
// $user->save();
// exit();
}
}

View File

@ -0,0 +1,234 @@
<?php
/**
* PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/)
*
* Payment Gateway flutterwave.com
*
* created by @foculinkstech
*
**/
function flutterwave_validate_config()
{
global $config;
if (empty($config['flutterwave_secret_key'])) {
Message::sendTelegram("flutterwave payment gateway not configured");
r2(U . 'order/package', 'w', Lang::T("Admin has not yet setup flutterwave payment gateway, please tell admin"));
}
}
function flutterwave_show_config()
{
global $ui;
$ui->assign('_title', 'Flutterwave - Payment Gateway');
$ui->assign('cur', json_decode(file_get_contents('system/paymentgateway/flutterwave_currency.json'), true));
$ui->assign('channel', json_decode(file_get_contents('system/paymentgateway/flutterwave_channel.json'), true));
$ui->display('flutterwave.tpl');
}
function flutterwave_save_config()
{
global $admin, $_L;
$flutterwave_secret_key = _post('flutterwave_secret_key');
$flutterwave_currency = _post('flutterwave_currency');
$d = ORM::for_table('tbl_appconfig')->where('setting', 'flutterwave_secret_key')->find_one();
if ($d) {
$d->value = $flutterwave_secret_key;
$d->save();
} else {
$d = ORM::for_table('tbl_appconfig')->create();
$d->setting = 'flutterwave_secret_key';
$d->value = $flutterwave_secret_key;
$d->save();
}
$d = ORM::for_table('tbl_appconfig')->where('setting', 'flutterwave_currency')->find_one();
if ($d) {
$d->value = $flutterwave_currency;
$d->save();
} else {
$d = ORM::for_table('tbl_appconfig')->create();
$d->setting = 'flutterwave_currency';
$d->value = $flutterwave_currency;
$d->save();
}
$d = ORM::for_table('tbl_appconfig')->where('setting', 'flutterwave_channel')->find_one();
if ($d) {
$d->value = implode(',', $_POST['flutterwave_channel']);
$d->save();
} else {
$d = ORM::for_table('tbl_appconfig')->create();
$d->setting = 'flutterwave_channel';
$d->value = implode(',', $_POST['flutterwave_channel']);
$d->save();
}
_log('[' . $admin['username'] . ']: Flutterwave ' . $_L['Settings_Saved_Successfully'], 'Admin', $admin['id']);
r2(U . 'paymentgateway/flutterwave', 's', $_L['Settings_Saved_Successfully']);
}
function flutterwave_create_transaction($trx, $user)
{
global $config;
$txref = uniqid('trx');
$json = [
'tx_ref' => $txref,
'amount' => $trx['price'],
'currency' => $config['flutterwave_currency'],
'payment_options' => explode(',', $config['flutterwave_channel']),
'customer' => [
'email' => (empty($user['email'])) ? $user['username'] . '@' . $_SERVER['HTTP_HOST'] : $user['email'],
'name' => $user['fullname'],
'phonenumber' => $user['phonenumber']
],
'meta' => [
'price' => $trx['price'],
'username' => $user['username'],
'trxid' => $trx['id']
],
'customizations' => [
'title' => $trx['plan_name'],
'description' => $trx['plan_name'],
],
'redirect_url' => U . 'callback/flutterwave'
];
// die(json_encode($json,JSON_PRETTY_PRINT));
$result = json_decode(Http::postJsonData(flutterwave_get_server() . 'payments', $json,[
'Authorization: Bearer ' . $config['flutterwave_secret_key'],
'Cache-Control: no-cahe'
],
),
true);
//die(json_encode($result,JSON_PRETTY_PRINT));
if ($result['status'] == 'error') {
Message::sendTelegram("Flutterwave payment failed\n\n" . json_encode($result, JSON_PRETTY_PRINT));
r2(U . 'order/package', 'e', Lang::T("Failed to create transaction.\n".$result['message']));
}
$d = ORM::for_table('tbl_payment_gateway')
->where('username', $user['username'])
->where('status', 1)
->find_one();
$d->gateway_trx_id = $txref;
$d->pg_url_payment = $result['data']['link'];
$d->pg_request = json_encode($result);
$d->expired_date = date('Y-m-d H:i:s', strtotime("+ 6 HOUR"));
$d->save();
header('Location: ' . $result['data']['link']);
exit();
r2(U . "order/view/" . $d['id'], 's', Lang::T("Create Transaction Success"));
}
function flutterwave_payment_notification()
{
global $config;
if(isset($_GET['status']))
{
//* check payment status
if($_GET['status'] == 'cancelled')
{
// die(json_encode($txref,JSON_PRETTY_PRINT));
Message::sendTelegram("Flutterwave Payment Cancelled: \n\n");
r2(U . 'order/package', 'e', Lang::T("Flutterwave Payment Cancelled."));
}
elseif($_GET['status'] == 'successful')
{
$txid = $_GET['transaction_id'];
$result = json_decode(Http::getData(flutterwave_get_server() . 'transactions/' . $txid. '/verify', [
'Authorization: Bearer ' . $config['flutterwave_secret_key'],
'Cache-Control: no-cahe'
]), true);
//die(json_encode($result,JSON_PRETTY_PRINT));
{
$id = $result['data']['id'];
$amountPaid = $result['data']['charged_amount'];
$amountToPay = $result['data']['meta']['price'];
$username = $result['data']['meta']['username'];
$trxid = $result['data']['meta']['trxid'];
if($amountPaid >= $amountToPay)
{
// die(json_encode($trxid,JSON_PRETTY_PRINT));
// echo 'Payment successful';
$d = ORM::for_table('tbl_payment_gateway')
->where('username', $username)
->where('status', 1)
->find_one();
$d->gateway_trx_id = $id;
$d->save();
r2(U . 'order/view/'.$trxid.'/check');
// r2(U . 'order/package', 's', Lang::T("Flutterwave Payment Completed."));
exit();
//* Continue to give item to the user
}
else
{
// echo 'Fraud transactio detected';
r2(U . 'order/package', 'e', Lang::T("Fraud transactions detected."));
exit();
}
}
}
}
}
function flutterwave_get_status($trx, $user)
{
global $config;
$trans_id = $trx['gateway_trx_id'];
$result = json_decode(Http::getData(flutterwave_get_server() . 'transactions/' . $trx['gateway_trx_id']. '/verify', [
'Authorization: Bearer ' . $config['flutterwave_secret_key'],
'Cache-Control: no-cahe'
]), true);
//die(json_encode($result,JSON_PRETTY_PRINT));
if ($result['status'] == 'error') {
r2(U . "order/view/" . $trx['id'], 'w', Lang::T("Transaction still unpaid."));
} else if (in_array($result['status'], ['success']) && $trx['status'] != 2) {
if (!Package::rechargeUser($user['id'], $trx['routers'], $trx['plan_id'], $trx['gateway'], 'Flutterwave')) {
r2(U . "order/view/" . $trx['id'], 'd', Lang::T("Failed to activate your Package, please try again later."));
}
$trx->pg_paid_response = json_encode($result);
$trx->payment_method = 'Flutterwave';
$trx->payment_channel = $result['data']['payment_type'];
$trx->paid_date = date('Y-m-d H:i:s', strtotime( $result['data']['created_at']));
$trx->status = 2;
$trx->save();
r2(U . "order/view/" . $trx['id'], 's', Lang::T("Transaction successful."));
} else if ($result['status'] == 'EXPIRED') {
$trx->pg_paid_response = json_encode($result);
$trx->status = 3;
$trx->save();
r2(U . "order/view/" . $trx['id'], 'd', Lang::T("Transaction expired."));
} else if ($trx['status'] == 2) {
r2(U . "order/view/" . $trx['id'], 'd', Lang::T("Transaction has been paid.."));
}else{
Message::sendTelegram("flutterwave_get_status: unknown result\n\n".json_encode($result, JSON_PRETTY_PRINT));
r2(U . "order/view/" . $trx['id'], 'd', Lang::T("Unknown Command."));
}
}
function flutterwave_get_server()
{
global $_app_stage;
if ($_app_stage == 'Live') {
return 'https://api.flutterwave.com/v3/';
} else {
return 'https://api.flutterwave.com/v3/';
}
}

View File

@ -0,0 +1,35 @@
[
{
"id": "card",
"name": "Card Payment"
},
{
"id": "ussd",
"name": "USSD"
},
{
"id": "account",
"name": "Bank Account"
},
{
"id": "banktransfer",
"name": "Bank Transfer"
},
{
"id": "nqr",
"name": "QR payment"
},
{
"id": "mpesa",
"name": "M-Pesa"
},
{
"id": "mobilemoneyghana",
"name": "Mobile money Ghana"
},
{
"id": "credit",
"name": "Credit payment"
}
]

View File

@ -0,0 +1,30 @@
[
{
"id": "NGN",
"name": "Nigerian Naira"
},
{
"id": "GHC",
"name": "Ghana Cedis"
},
{
"id": "KES",
"name": "Kenyan Shilling"
},
{
"id": "ZAR",
"name": "South African Rand"
},
{
"id": "GBP",
"name": "British Pound Sterling"
},
{
"id": "USD",
"name": "United States Dollar"
},
{
"id": "TZS",
"name": "Tanzanian Shilling"
}
]

Binary file not shown.

View File

@ -0,0 +1,254 @@
<?php
/**
* PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/)
*
* Payment Gateway ioTec Pay
*
* Created for ioTec Pay v1 Collection API
*
**/
function iotec_validate_config()
{
global $config;
if (empty($config['iotec_client_id']) || empty($config['iotec_client_secret']) || empty($config['iotec_wallet_id'])) {
Message::sendTelegram("ioTec payment gateway not configured");
r2(U . 'order/package', 'w', Lang::T("Admin has not yet setup ioTec payment gateway, please tell admin"));
}
}
function iotec_show_config()
{
global $ui;
$ui->assign('_title', 'ioTec Pay - Payment Gateway');
$ui->assign('env', [
['id' => 'Sandbox', 'name' => 'Sandbox (Testing)'],
['id' => 'Live', 'name' => 'Live (Production)']
]);
$ui->display('iotec.tpl');
}
function iotec_save_config()
{
global $admin, $_L;
$iotec_client_id = _post('iotec_client_id');
$iotec_client_secret = _post('iotec_client_secret');
$iotec_wallet_id = _post('iotec_wallet_id');
$iotec_env = _post('iotec_env');
$d = ORM::for_table('tbl_appconfig')->where('setting', 'iotec_client_id')->find_one();
if ($d) {
$d->value = $iotec_client_id;
$d->save();
} else {
$d = ORM::for_table('tbl_appconfig')->create();
$d->setting = 'iotec_client_id';
$d->value = $iotec_client_id;
$d->save();
}
$d = ORM::for_table('tbl_appconfig')->where('setting', 'iotec_client_secret')->find_one();
if ($d) {
$d->value = $iotec_client_secret;
$d->save();
} else {
$d = ORM::for_table('tbl_appconfig')->create();
$d->setting = 'iotec_client_secret';
$d->value = $iotec_client_secret;
$d->save();
}
$d = ORM::for_table('tbl_appconfig')->where('setting', 'iotec_wallet_id')->find_one();
if ($d) {
$d->value = $iotec_wallet_id;
$d->save();
} else {
$d = ORM::for_table('tbl_appconfig')->create();
$d->setting = 'iotec_wallet_id';
$d->value = $iotec_wallet_id;
$d->save();
}
$d = ORM::for_table('tbl_appconfig')->where('setting', 'iotec_env')->find_one();
if ($d) {
$d->value = $iotec_env;
$d->save();
} else {
$d = ORM::for_table('tbl_appconfig')->create();
$d->setting = 'iotec_env';
$d->value = $iotec_env;
$d->save();
}
_log('[' . $admin['username'] . ']: ioTec Pay ' . $_L['Settings_Saved_Successfully'], 'Admin', $admin['id']);
r2(U . 'paymentgateway/iotec', 's', $_L['Settings_Saved_Successfully']);
}
function iotec_create_transaction($trx, $user)
{
global $config;
$externalId = uniqid('bill_');
// Obtain access token
$tokenResponse = json_decode(Http::postData(iotec_get_server('auth') . 'connect/token', [
'client_id' => $config['iotec_client_id'],
'client_secret' => $config['iotec_client_secret'],
'grant_type' => 'client_credentials'
], [
'Content-Type: application/x-www-form-urlencoded'
]), true);
if (empty($tokenResponse['access_token'])) {
Message::sendTelegram("ioTec payment failed: Failed to obtain access token\n\n" . json_encode($tokenResponse, JSON_PRETTY_PRINT));
r2(U . 'order/package', 'e', Lang::T("Failed to authenticate with ioTec."));
}
$json = [
'category' => 'MobileMoney',
'currency' => 'ITX',
'walletId' => $config['iotec_wallet_id'],
'externalId' => $externalId,
'payer' => $user['phonenumber'],
'amount' => $trx['price'],
'payerNote' => 'Payment for ' . $trx['plan_name'],
'payeeNote' => 'Hotspot billing',
'transactionChargesCategory' => 'ChargeCustomer'
];
$result = json_decode(Http::postJsonData(iotec_get_server('api') . 'api/collections/collect', $json, [
'Authorization: Bearer ' . $tokenResponse['access_token'],
'Content-Type: application/json'
]), true);
if (empty($result['id'])) {
Message::sendTelegram("ioTec payment failed\n\n" . json_encode($result, JSON_PRETTY_PRINT));
r2(U . 'order/package', 'e', Lang::T("Failed to create transaction.\n" . ($result['message'] ?? 'Unknown error')));
}
$d = ORM::for_table('tbl_payment_gateway')
->where('username', $user['username'])
->where('status', 1)
->find_one();
$d->gateway_trx_id = $result['id'];
$d->pg_url_payment = 'N/A'; // ioTec doesn't provide a payment URL
$d->pg_request = json_encode($result);
$d->expired_date = date('Y-m-d H:i:s', strtotime("+6 HOUR"));
$d->save();
r2(U . "order/view/" . $d['id'], 's', Lang::T("Transaction created. Please authorize the payment on your phone."));
}
function iotec_payment_notification()
{
global $config;
$headers = getallheaders();
$securityKey = $headers['X-Callback-Security-Key'] ?? '';
$expectedKey = $config['iotec_callback_security_key'] ?? 'your_callback_security_key';
if ($securityKey !== $expectedKey) {
Message::sendTelegram("ioTec callback failed: Invalid security key\n\n" . json_encode($headers, JSON_PRETTY_PRINT));
http_response_code(401);
exit(json_encode(['status' => 'error', 'message' => 'Invalid security key']));
}
$data = json_decode(file_get_contents('php://input'), true);
if (empty($data['id']) || empty($data['status'])) {
Message::sendTelegram("ioTec callback failed: Invalid data\n\n" . json_encode($data, JSON_PRETTY_PRINT));
http_response_code(400);
exit(json_encode(['status' => 'error', 'message' => 'Invalid callback data']));
}
$transactionId = $data['id'];
$status = $data['status'];
$externalId = $data['externalId'] ?? '';
$amountPaid = $data['amount'] ?? 0;
$username = $data['payer'] ?? ''; // Map to username via lookup if needed
$trxid = $data['externalId'] ?? ''; // Map to transaction ID
$d = ORM::for_table('tbl_payment_gateway')
->where('gateway_trx_id', $transactionId)
->where('status', 1)
->find_one();
if (!$d) {
Message::sendTelegram("ioTec callback failed: Transaction not found\n\n" . json_encode($data, JSON_PRETTY_PRINT));
http_response_code(404);
exit(json_encode(['status' => 'error', 'message' => 'Transaction not found']));
}
if ($status === 'Success') {
$d->gateway_trx_id = $transactionId;
$d->save();
r2(U . 'order/view/' . $d['id'] . '/check', 's', Lang::T("ioTec Payment Completed."));
} elseif ($status === 'Failed') {
Message::sendTelegram("ioTec Payment Failed: \n\n" . json_encode($data, JSON_PRETTY_PRINT));
r2(U . 'order/package', 'e', Lang::T("ioTec Payment Failed."));
} else {
Message::sendTelegram("ioTec Payment Pending: \n\n" . json_encode($data, JSON_PRETTY_PRINT));
r2(U . 'order/package', 'w', Lang::T("ioTec Payment Pending."));
}
}
function iotec_get_status($trx, $user)
{
global $config;
$trans_id = $trx['gateway_trx_id'];
// Obtain access token
$tokenResponse = json_decode(Http::postData(iotec_get_server('auth') . 'connect/token', [
'client_id' => $config['iotec_client_id'],
'client_secret' => $config['iotec_client_secret'],
'grant_type' => 'client_credentials'
], [
'Content-Type: application/x-www-form-urlencoded'
]), true);
if (empty($tokenResponse['access_token'])) {
Message::sendTelegram("ioTec status check failed: Failed to obtain access token\n\n" . json_encode($tokenResponse, JSON_PRETTY_PRINT));
r2(U . "order/view/" . $trx['id'], 'w', Lang::T("Failed to authenticate with ioTec."));
}
$result = json_decode(Http::getData(iotec_get_server('api') . 'api/collections/status/' . $trans_id, [
'Authorization: Bearer ' . $tokenResponse['access_token'],
'Content-Type: application/json'
]), true);
if (empty($result['status'])) {
Message::sendTelegram("ioTec status check failed\n\n" . json_encode($result, JSON_PRETTY_PRINT));
r2(U . "order/view/" . $trx['id'], 'w', Lang::T("Transaction still unpaid."));
} elseif ($result['status'] === 'Success' && $trx['status'] != 2) {
if (!Package::rechargeUser($user['id'], $trx['routers'], $trx['plan_id'], $trx['gateway'], 'ioTec')) {
r2(U . "order/view/" . $trx['id'], 'd', Lang::T("Failed to activate your Package, please try again later."));
}
$trx->pg_paid_response = json_encode($result);
$trx->payment_method = 'ioTec';
$trx->payment_channel = 'MobileMoney';
$trx->paid_date = date('Y-m-d H:i:s');
$trx->status = 2;
$trx->save();
r2(U . "order/view/" . $trx['id'], 's', Lang::T("Transaction successful."));
} elseif ($result['status'] === 'Failed') {
$trx->pg_paid_response = json_encode($result);
$trx->status = 3;
$trx->save();
r2(U . "order/view/" . $trx['id'], 'd', Lang::T("Transaction failed."));
} elseif ($trx['status'] == 2) {
r2(U . "order/view/" . $trx['id'], 'd', Lang::T("Transaction has been paid."));
} else {
Message::sendTelegram("ioTec get_status: unknown result\n\n" . json_encode($result, JSON_PRETTY_PRINT));
r2(U . "order/view/" . $trx['id'], 'w', Lang::T("Transaction still pending."));
}
}
function iotec_get_server($type = 'api')
{
global $_app_stage;
if ($_app_stage == 'Live' && $type == 'auth') {
return 'https://id.iotec.io/';
} elseif ($_app_stage == 'Live' && $type == 'api') {
return 'https://pay.iotec.io/';
} else {
return $type == 'auth' ? 'https://id.iotec.io/' : 'https://pay.iotec.io/';
}
}

View File

@ -0,0 +1,5 @@
{
"sandbox": {
"name": "iotecpay-sandbox"
}
}

View File

@ -0,0 +1,163 @@
<?php
/**
* PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/)
*
* Payment Gateway ioTec Pay
*
* Created for ioTec Pay v1 Collection API
*/
function iotec_validate_config()
{
global $config;
$config['iotec_client_id'] = $config['iotec_client_id'] ?? 'your_client_id_here';
$config['iotec_client_secret'] = $config['iotec_client_secret'] ?? 'your_client_secret_here';
$config['iotec_wallet_id'] = $config['iotec_wallet_id'] ?? 'your_wallet_id_here';
if (empty($config['iotec_client_id']) || empty($config['iotec_client_secret']) || empty($config['iotec_wallet_id'])) {
Message::sendTelegram("ioTec payment gateway not configured");
http_response_code(400);
header('Content-Type: application/json');
echo json_encode(['status' => 'error', 'message' => 'ioTec Pay not configured']);
exit;
}
}
function iotec_show_config()
{
global $ui;
$ui->assign('_title', 'ioTec Pay - Payment Gateway');
$ui->assign('env', [
['id' => 'Sandbox', 'name' => 'Sandbox (Testing)'],
['id' => 'Live', 'name' => 'Live (Production)']
]);
$ui->display('iotec.tpl');
}
function iotec_save_config()
{
global $admin, $_L;
$iotec_client_id = _post('iotec_client_id');
$iotec_client_secret = _post('iotec_client_secret');
$iotec_wallet_id = _post('iotec_wallet_id');
$iotec_env = _post('iotec_env');
$settings = [
'iotec_client_id' => $iotec_client_id,
'iotec_client_secret' => $iotec_client_secret,
'iotec_wallet_id' => $iotec_wallet_id,
'iotec_env' => $iotec_env
];
foreach ($settings as $key => $value) {
$d = ORM::for_table('tbl_appconfig')->where('setting', $key)->find_one();
if ($d) {
$d->value = $value;
$d->save();
} else {
$d = ORM::for_table('tbl_appconfig')->create();
$d->setting = $key;
$d->value = $value;
$d->save();
}
}
_log('[' . $admin['username'] . ']: ioTec Pay ' . $_L['Settings_Saved_Successfully'], 'Admin', $admin['id']);
header('Content-Type: application/json');
echo json_encode(['status' => 'success', 'message' => $_L['Settings_Saved_Successfully']]);
exit;
}
function iotec_create_transaction_json($trx, $user)
{
global $config;
header('Content-Type: application/json');
// Validate required inputs
if (empty($trx['price']) || empty($user['phonenumber']) || empty($user['username']) || empty($trx['plan_name'])) {
http_response_code(400);
echo json_encode([
'status' => 'error',
'message' => 'Missing required input: price, phonenumber, username, or plan_name'
]);
exit;
}
$externalId = uniqid('bill_');
$tokenResponse = json_decode(Http::postData(iotec_get_server('auth') . 'connect/token', [
'client_id' => $config['iotec_client_id'],
'client_secret' => $config['iotec_client_secret'],
'grant_type' => 'client_credentials'
], [
'Content-Type: application/x-www-form-urlencoded'
]), true);
if (empty($tokenResponse['access_token'])) {
http_response_code(500);
echo json_encode([
'status' => 'error',
'message' => 'Failed to authenticate with ioTec',
'response' => $tokenResponse
]);
exit;
}
$json = [
'category' => 'MobileMoney',
'currency' => 'ITX',
'walletId' => $config['iotec_wallet_id'],
'externalId' => $externalId,
'payer' => $user['phonenumber'],
'amount' => $trx['price'],
'payerNote' => 'Payment for ' . $trx['plan_name'],
'payeeNote' => 'Hotspot billing',
'transactionChargesCategory' => 'ChargeCustomer'
];
$result = json_decode(Http::postJsonData(iotec_get_server('api') . 'api/collections/collect', $json, [
'Authorization: Bearer ' . $tokenResponse['access_token'],
'Content-Type: application/json'
]), true);
if (empty($result['id'])) {
http_response_code(502);
echo json_encode([
'status' => 'error',
'message' => 'Failed to create transaction',
'response' => $result
]);
exit;
}
$d = ORM::for_table('tbl_payment_gateway')
->where('username', $user['username'])
->where('status', 1)
->find_one();
if (!$d) {
http_response_code(404);
echo json_encode([
'status' => 'error',
'message' => 'Active payment gateway record not found for user'
]);
exit;
}
$d->gateway_trx_id = $result['id'];
$d->pg_url_payment = 'N/A';
$d->pg_request = json_encode($result);
$d->expired_date = date('Y-m-d H:i:s', strtotime("+6 HOUR"));
$d->save();
echo json_encode([
'status' => 'success',
'message' => 'Transaction created. Authorize on phone.',
'transaction_id' => $result['id'],
'external_id' => $externalId
]);
exit;
}
// Other functions (iotec_payment_notification, iotec_get_status, iotec_get_server, etc.) remain unchanged.

View File

@ -0,0 +1,6 @@
[
{
"id": "MobileMoney",
"name": "Mobile Money"
}
]

View File

@ -0,0 +1,363 @@
<?php
/**
* PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/)
*
* Payment Gateway M-Pesa safaricom.co.ke
*
* created by @netXtreme
*
**/
function mpesa_validate_config()
{
global $config;
if (empty($config['mpesa_consumer_key']) || empty($config['mpesa_consumer_secret'])) {
sendTelegram("M-Pesa payment gateway not configured");
r2(U . 'order/package', 'w', Lang::T("Admin has not yet setup M-Pesa payment gateway, please tell admin"));
}
}
function mpesa_show_config()
{
global $ui, $config;
$ui->assign('env', json_decode(file_get_contents('system/paymentgateway/mpesa_env.json'), true));
$ui->assign('_title', 'M-Pesa - Payment Gateway - ' . $config['CompanyName']);
$ui->display('mpesa.tpl');
}
function mpesa_save_config()
{
global $admin, $_L;
$mpesa_consumer_key = _post('mpesa_consumer_key');
$mpesa_consumer_secret = _post('mpesa_consumer_secret');
$mpesa_business_code = _post('mpesa_business_code');
$mpesa_pass_key = _post('mpesa_pass_key');
$mpesa_env = _post('mpesa_env');
$d = ORM::for_table('tbl_appconfig')->where('setting', 'mpesa_consumer_key')->find_one();
if ($d) {
$d->value = $mpesa_consumer_key;
$d->save();
} else {
$d = ORM::for_table('tbl_appconfig')->create();
$d->setting = 'mpesa_consumer_key';
$d->value = $mpesa_consumer_key;
$d->save();
}
$d = ORM::for_table('tbl_appconfig')->where('setting', 'mpesa_consumer_secret')->find_one();
if ($d) {
$d->value = $mpesa_consumer_secret;
$d->save();
} else {
$d = ORM::for_table('tbl_appconfig')->create();
$d->setting = 'mpesa_consumer_secret';
$d->value = $mpesa_consumer_secret;
$d->save();
}
$d = ORM::for_table('tbl_appconfig')->where('setting', 'mpesa_business_code')->find_one();
if ($d) {
$d->value = $mpesa_business_code;
$d->save();
} else {
$d = ORM::for_table('tbl_appconfig')->create();
$d->setting = 'mpesa_business_code';
$d->value = $mpesa_business_code;
$d->save();
}
$d = ORM::for_table('tbl_appconfig')->where('setting', 'mpesa_pass_key')->find_one();
if ($d) {
$d->value = $mpesa_pass_key;
$d->save();
} else {
$d = ORM::for_table('tbl_appconfig')->create();
$d->setting = 'mpesa_pass_key';
$d->value = $mpesa_pass_key;
$d->save();
}
$d = ORM::for_table('tbl_appconfig')->where('setting', 'mpesa_env')->find_one();
if ($d) {
$d->value = $mpesa_env;
$d->save();
} else {
$d = ORM::for_table('tbl_appconfig')->create();
$d->setting = 'mpesa_env';
$d->value = $mpesa_env;
$d->save();
}
_log('[' . $admin['username'] . ']: M-Pesa ' . $_L['Settings_Saved_Successfully'] . json_encode($_POST['mpesa_channel']), 'Admin', $admin['id']);
r2(U . 'paymentgateway/mpesa', 's', $_L['Settings_Saved_Successfully']);
}
function mpesa_create_transaction($trx, $user)
{
global $config, $routes;
//select evironment
$environment = $config['mpesa_env'];
$consumer_key = $config['mpesa_consumer_key'];
$consumer_secret = $config['mpesa_consumer_secret'];
$Business_Code = $config['mpesa_business_code'];
$Passkey = $config['mpesa_pass_key'];
$Type_of_Transaction = 'CustomerPayBillOnline';
$phone_number = $user['phonenumber'];
$total_amount = $trx['price'];
//lets assume this is our callBack url
//$CallBackURL = 'http://alwayson.com.ng/phpnuxbill/index.php?_route=callback/mpesa';
$CallBackURL = U . 'callback/mpesa';
$Time_Stamp = date("Ymdhis");
//password required by api
$password = base64_encode($Business_Code . $Passkey . $Time_Stamp);
//depend on which environment selected
if ($environment == "live") {
$OnlinePayment = 'https://api.safaricom.co.ke/mpesa/stkpush/v1/processrequest';
$Token_URL = 'https://api.safaricom.co.ke/oauth/v1/generate?grant_type=client_credentials';
} elseif ($environment == "sandbox") {
$OnlinePayment = 'https://sandbox.safaricom.co.ke/mpesa/stkpush/v1/processrequest';
$Token_URL = 'https://sandbox.safaricom.co.ke/oauth/v1/generate?grant_type=client_credentials';
} else {
return json_encode(["Message" => "invalid application status"]);
};
//lets Create access_token as per required
$curl_Tranfer = curl_init();
curl_setopt($curl_Tranfer, CURLOPT_URL, $Token_URL);
$credentials = base64_encode($consumer_key . ':' . $consumer_secret);
curl_setopt($curl_Tranfer, CURLOPT_HTTPHEADER, array('Authorization: Basic ' . $credentials));
curl_setopt($curl_Tranfer, CURLOPT_HEADER, false);
curl_setopt($curl_Tranfer, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl_Tranfer, CURLOPT_SSL_VERIFYPEER, false);
$curl_Tranfer_response = curl_exec($curl_Tranfer);
$token = json_decode($curl_Tranfer_response)->access_token;
// die(json_encode($curl_Tranfer2_post_data,JSON_PRETTY_PRINT));
$curl_Tranfer2 = curl_init();
curl_setopt($curl_Tranfer2, CURLOPT_URL, $OnlinePayment);
curl_setopt($curl_Tranfer2, CURLOPT_HTTPHEADER, array('Content-Type:application/json', 'Authorization:Bearer ' . $token));
//lets initiate a Transaction
$curl_Tranfer2_post_data = [
'BusinessShortCode' => $Business_Code,
'Password' => $password,
'Timestamp' => $Time_Stamp,
'TransactionType' => $Type_of_Transaction,
'Amount' => $trx['price'],
'PartyA' => $phone_number,
'PartyB' => $Business_Code,
'PhoneNumber' => $phone_number,
'CallBackURL' => $CallBackURL,
'AccountReference' => $phone_number,
'TransactionDesc' => $trx['plan_name']
//'Trxid' => $trx['id'],
//'AmountToPay' => $trx['price'],
];
//lest check the data that we want to send for error
//die(json_encode($curl_Tranfer2_post_data,JSON_PRETTY_PRINT));
$data2_string = json_encode($curl_Tranfer2_post_data);
curl_setopt($curl_Tranfer2, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl_Tranfer2, CURLOPT_POST, true);
curl_setopt($curl_Tranfer2, CURLOPT_POSTFIELDS, $data2_string);
curl_setopt($curl_Tranfer2, CURLOPT_HEADER, false);
curl_setopt($curl_Tranfer2, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($curl_Tranfer2, CURLOPT_SSL_VERIFYHOST, 0);
$curl_Tranfer2_response = json_decode(curl_exec($curl_Tranfer2));
$status = $curl_Tranfer2_response->ResponseCode;
//die(json_encode($curl_Tranfer2_response,JSON_PRETTY_PRINT));
//die(json_encode($status,JSON_PRETTY_PRINT));
/**
* {
* "MerchantRequestID": "26309-129914760-1",
* "CheckoutRequestID": "ws_CO_22092023134957453718167262",
* "ResponseCode": "0", "ResponseDescription": "Success. Request accepted for processing",
* "CustomerMessage": "Success. Request accepted for processing"
* }
*
*
**/
if ($status == 1) {
sendTelegram("M-Pesa payment failed\n\n" . json_encode($curl_Tranfer2_response, JSON_PRETTY_PRINT));
r2(U . 'order/package', 'e', Lang::T("Failed to create transaction."));
}
$d = ORM::for_table('tbl_payment_gateway')
->where('username', $user['username'])
->where('status', 1)
->find_one();
$d->gateway_trx_id = $curl_Tranfer2_response->CheckoutRequestID;
//lets use this table "pg_url_payment" to save Timestamp because we will need it later to verify transaction
$d->pg_url_payment = $Time_Stamp;
$d->pg_request = $user['id'];
$d->expired_date = date('Y-m-d H:i:s', strtotime("+5 minutes"));
$d->save();
r2(U . "order/view/" . $d['id'], 's', Lang::T("Create Transaction Success, Please check your phone to process payment"));
}
function mpesa_payment_notification()
{
global $config;
//responce from mpesa server after payment is initiated and processed
$callbackJSONData = file_get_contents('php://input');
$callbackData = json_decode($callbackJSONData);
$resultCode = $callbackData->Body->stkCallback->ResultCode;
$resultDesc = $callbackData->Body->stkCallback->ResultDesc;
$merchantRequestID = $callbackData->Body->stkCallback->MerchantRequestID;
$checkoutRequestID = $callbackData->Body->stkCallback->CheckoutRequestID;
$amount = $callbackData->stkCallback->Body->CallbackMetadata->Item[0]->Value;
$mpesaReceiptNumber = $callbackData->Body->stkCallback->CallbackMetadata->Item[1]->Value;
$balance = $callbackData->stkCallback->Body->CallbackMetadata->Item[2]->Value;
$b2CUtilityAccountAvailableFunds = $callbackData->Body->stkCallback->CallbackMetadata->Item[3]->Value;
$transactionDate = $callbackData->Body->stkCallback->CallbackMetadata->Item[4]->Value;
$phoneNumber = $callbackData->Body->stkCallback->CallbackMetadata->Item[5]->Value;
//$trxid = $callbackData->Body->stkCallback->CallbackMetadata->Item[6]->Value;
//$amountToPay=$callbackData->Body->stkCallback->CallbackMetadata->Item[7]->Value;
$trx = ORM::for_table('tbl_payment_gateway')
->where('gateway_trx_id', $checkoutRequestID)
->find_one();
if (!$trx) {
return;
}
$user = ORM::for_table('tbl_customers')
->where('username', $trx['username'])
->find_one();
if (!$trx) {
return;
}
//lets check the status of the Payment sent back from mpesa
if ($resultDesc == "Confirmation Service not accepted" || $resultCode == 1) {
$trx->status = 3;
$trx->save();
exit();
}
//if Payment is confirmed and Successfull
//lets log the responce from mpesa for audit or any error
//lets save some value to database
elseif ($resultDesc == "The service request is processed successfully." && $resultCode == 0 && $trx['status'] != 2) {
if (!Package::rechargeUser($user['id'], $trx['routers'], $trx['plan_id'], $trx['gateway'], 'mpesa')) {
_log('[' . $resultDesc . ']: M-Pesa ' . "Payment Successfull,But Failed to activate your Package" . json_encode($callbackData));
}
_log('[' . $resultDesc . ']: M-Pesa ' . "Payment Successfull" . json_encode($callbackData));
$trx->pg_paid_response = json_encode($callbackData);
$trx->payment_method = 'M-Pesa';
$trx->payment_channel = 'M-Pesa StkPush';
$trx->paid_date = date('Y-m-d H:i:s');
$trx->status = 2;
$trx->save();
} else {
$trx->status = 1;
$trx->save();
exit();
}
}
function mpesa_get_status($trx, $user)
{
global $config, $routes;
function mpesa_get_status($trx, $user)
{
global $config, $routes;
if ($trx->status == 2){
r2(U . "order/view/" . $trx['id'], 's', Lang::T("Transaction has been completed."));
die();
}elseif ($trx->status == 1){
$environment = $config['mpesa_env'];
$consumer_key = $config['mpesa_consumer_key'];
$consumer_secret = $config['mpesa_consumer_secret'];
$Business_Code = $config['mpesa_business_code'];
$Passkey = $config['mpesa_pass_key'];
//Timestamp that we save earlier in pg_url_payment database
$Time_Stamp = $trx['pg_url_payment'];
$password = base64_encode($Business_Code . $Passkey . $Time_Stamp);
if ($environment == "live") {
$OnlinePayment = 'https://api.safaricom.co.ke/mpesa/stkpushquery/v1/query';
$Token_URL = 'https://api.safaricom.co.ke/oauth/v1/generate?grant_type=client_credentials';
} elseif ($environment == "sandbox") {
$OnlinePayment = 'https://sandbox.safaricom.co.ke/mpesa/stkpushquery/v1/query';
$Token_URL = 'https://sandbox.safaricom.co.ke/oauth/v1/generate?grant_type=client_credentials';
} else {
return json_encode(["Message" => "invalid application status"]);
};
$curl_Tranfer = curl_init();
curl_setopt($curl_Tranfer, CURLOPT_URL, $Token_URL);
$credentials = base64_encode($consumer_key . ':' . $consumer_secret);
curl_setopt($curl_Tranfer, CURLOPT_HTTPHEADER, array('Authorization: Basic ' . $credentials));
curl_setopt($curl_Tranfer, CURLOPT_HEADER, false);
curl_setopt($curl_Tranfer, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl_Tranfer, CURLOPT_SSL_VERIFYPEER, false);
$curl_Tranfer_response = curl_exec($curl_Tranfer);
$token = json_decode($curl_Tranfer_response)->access_token;
// die(json_encode($curl_Tranfer2_post_data,JSON_PRETTY_PRINT));
$curl_Tranfer2 = curl_init();
curl_setopt($curl_Tranfer2, CURLOPT_URL, $OnlinePayment);
curl_setopt($curl_Tranfer2, CURLOPT_HTTPHEADER, array('Content-Type:application/json', 'Authorization:Bearer ' . $token));
//lest verify the transaction by sending data to mpesa transaction query portal from nuxbil
$curl_Tranfer2_post_data = [
'BusinessShortCode' => $Business_Code,
'Password' => $password,
'Timestamp' => $Time_Stamp,
'CheckoutRequestID' => $trx['gateway_trx_id']
];
//die(json_encode($curl_Tranfer2_post_data,JSON_PRETTY_PRINT));
$data2_string = json_encode($curl_Tranfer2_post_data);
curl_setopt($curl_Tranfer2, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl_Tranfer2, CURLOPT_POST, true);
curl_setopt($curl_Tranfer2, CURLOPT_POSTFIELDS, $data2_string);
curl_setopt($curl_Tranfer2, CURLOPT_HEADER, false);
curl_setopt($curl_Tranfer2, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($curl_Tranfer2, CURLOPT_SSL_VERIFYHOST, 0);
$curl_Tranfer2_response = json_decode(curl_exec($curl_Tranfer2));
//server responce will be
/**
* {
* "ResponseCode":"0",
* "ResponseDescription": "The service request has been accepted successfully",
* "MerchantRequestID":"22205-34066-1",
* "CheckoutRequestID": "ws_CO_13012021093521236557",
* "ResultCode":"0",
* "ResultDesc":"The service request is processed successfully.",
* }
*
*
**/
$callbackJSONData = file_get_contents('php://input');
$callbackData = json_decode($callbackJSONData);
$responseCode = $callbackData->ResponseCode;
$responseDescription = $callbackData->ResponseDescription;
$merchantRequestID = $callbackData->MerchantRequestID;
$checkoutRequestID = $callbackData->CheckoutRequestID;
$resultCode = $callbackData->ResultCode;
$resultDesc = $callbackData->ResultDesc;
//if responce is Failed
if ($responseDescription === "The service request has failed" || $resultDesc === "Request canceled by the user" || $responseCode === 1) {
r2(U . "order/view/" . $trx['id'], 'w', Lang::T("Transaction still unpaid."));
//if responce is Successfull, activate the plan or balance
} elseif (($responseDescription === "The service request has been accepted successfully." || $resultDesc == "The service request is processed successfully" || $responseCode === 0) && $trx['status'] != 2) {
if (!Package::rechargeUser($user['id'], $trx['routers'], $trx['plan_id'], $trx['gateway'], 'M-Pesa')) {
r2(U . "order/view/" . $trx['id'], 'd', Lang::T("Failed to activate your Package, try again later."));
}
_log('[' . $checkoutRequestID . ']: M-Pesa ' . "Payment Successfull" . json_encode($callbackData));
$trx->pg_paid_response = json_encode($callbackData);
$trx->payment_method = 'M-Pesa';
$trx->payment_channel = 'M-Pesa StkPush';
$trx->paid_date = date('Y-m-d H:i:s');
$trx->status = 2;
$trx->save();
r2(U . "order/view/" . $trx['id'], 's', Lang::T("Transaction has been paid."));
} else if ($trx['status'] == 2) {
r2(U . "order/view/" . $trx['id'], 'd', Lang::T("Transaction has been paid.."));
}
}
}
}

View File

@ -0,0 +1,11 @@
[
{
"id": "sandbox",
"name": "SandBox or Testing"
},
{
"id": "live",
"name": "Live or Production"
}
]

View File

@ -0,0 +1,210 @@
<?php
/**
* PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/)
*
* Payment Gateway paypal.com
*
* created by @ibnux <me@ibnux.com>
*
**/
function paypal_validate_config()
{
global $config;
if (empty($config['paypal_client_id']) || empty($config['paypal_secret_key'])) {
sendTelegram("PayPal payment gateway not configured");
r2(U . 'order/package', 'w', "Admin has not yet setup Paypal payment gateway, please tell admin");
}
}
function paypal_show_config()
{
global $ui;
$ui->assign('_title', 'Paypal - Payment Gateway');
$ui->assign('currency', json_decode(file_get_contents('system/paymentgateway/paypal_currency.json'), true));
$ui->display('paypal.tpl');
}
function paypal_save_config()
{
global $admin, $_L;
$paypal_client_id = _post('paypal_client_id');
$paypal_secret_key = _post('paypal_secret_key');
$paypal_currency = _post('paypal_currency');
$d = ORM::for_table('tbl_appconfig')->where('setting', 'paypal_secret_key')->find_one();
if ($d) {
$d->value = $paypal_secret_key;
$d->save();
} else {
$d = ORM::for_table('tbl_appconfig')->create();
$d->setting = 'paypal_secret_key';
$d->value = $paypal_secret_key;
$d->save();
}
$d = ORM::for_table('tbl_appconfig')->where('setting', 'paypal_client_id')->find_one();
if ($d) {
$d->value = $paypal_client_id;
$d->save();
} else {
$d = ORM::for_table('tbl_appconfig')->create();
$d->setting = 'paypal_client_id';
$d->value = $paypal_client_id;
$d->save();
}
$d = ORM::for_table('tbl_appconfig')->where('setting', 'paypal_currency')->find_one();
if ($d) {
$d->value = $paypal_currency;
$d->save();
} else {
$d = ORM::for_table('tbl_appconfig')->create();
$d->setting = 'paypal_currency';
$d->value = $paypal_currency;
$d->save();
}
_log('[' . $admin['username'] . ']: Paypal ' . Lang::T('Settings_Saved_Successfully'), 'Admin', $admin['id']);
r2(U . 'paymentgateway/paypal', 's', Lang::T('Settings_Saved_Successfully'));
}
function paypal_create_transaction($trx, $user)
{
global $config;
$json = [
'intent' => 'CAPTURE',
'purchase_units' => [
[
'amount' => [
'currency_code' => $config['paypal_currency'],
'value' => strval($trx['price'])
]
]
],
"application_context" => [
"return_url" => U . "order/view/" . $trx['id'] . '/check',
"cancel_url" => U . "order/view/" . $trx['id'],
]
];
$result = json_decode(
Http::postJsonData(
paypal_get_server() . 'checkout/orders',
$json,
[
'Prefer: return=minimal',
'PayPal-Request-Id: paypal_' . $trx['id'],
'Authorization: Bearer ' . paypalGetAccessToken()
]
),
true
);
if (!$result['id']) {
sendTelegram("paypal_create_transaction FAILED: \n\n" . json_encode($result, JSON_PRETTY_PRINT));
r2(U . 'order/package', 'e', "Failed to create Paypal transaction.");
}
$urlPayment = "";
foreach ($result['links'] as $link) {
if ($link['rel'] == 'approve') {
$urlPayment = $link['href'];
break;
}
}
$d = ORM::for_table('tbl_payment_gateway')
->where('username', $user['username'])
->where('status', 1)
->find_one();
$d->gateway_trx_id = $result['id'];
$d->pg_url_payment = $urlPayment;
$d->pg_request = json_encode($result);
$d->expired_date = date('Y-m-d H:i:s', strtotime("+ 6 HOUR"));
$d->save();
header('Location: ' . $urlPayment);
exit();
}
/*
*/
function paypal_payment_notification()
{
// Not yet implemented
die('OK');
}
function paypal_get_status($trx, $user)
{
$capture = [];
if (empty($trx->pg_paid_response)) {
$capture = paypal_capture_transaction($trx['gateway_trx_id']);
} else {
$capture = json_decode($trx->pg_paid_response, true)['paypal_capture'];
if (empty($capture)) {
$capture = paypal_capture_transaction($trx['gateway_trx_id']);
}
}
$result = json_decode(Http::getData(paypal_get_server() . 'checkout/orders/' . $trx['gateway_trx_id'], ['Authorization: Bearer ' . paypalGetAccessToken()]), true);
if (in_array($result['status'], ['APPROVED', 'COMPLETED']) && $trx['status'] != 2) {
if ($capture['status'] == 'COMPLETED' || ($capture['name'] == 'UNPROCESSABLE_ENTITY' && $capture['details'][0]['issue'] == 'ORDER_ALREADY_CAPTURED')) {
if (!Package::rechargeUser($user['id'], $trx['routers'], $trx['plan_id'], $trx['gateway'], 'Paypal')) {
r2(U . "order/view/" . $trx['id'], 'd', "Failed to activate your Package, try again later.");
}
$result['paypal_capture'] = json_encode($capture);
$trx->pg_paid_response = json_encode($result);
$trx->payment_method = 'PAYPAL';
$trx->payment_channel = 'paypal';
$trx->paid_date = date('Y-m-d H:i:s', strtotime($result['updated']));
$trx->status = 2;
$trx->save();
r2(U . "order/view/" . $trx['id'], 's', "Transaction has been paid.");
} else {
r2(U . "order/view/" . $trx['id'], 'e', "Transaction Success, but not yet captured.");
}
} else if ($result['status'] == 'VOIDED') {
$trx->pg_paid_response = json_encode($result);
$trx->status = 3;
$trx->save();
r2(U . "order/view/" . $trx['id'], 'd', "Transaction expired.");
} else {
sendTelegram("xendit_get_status: unknown result\n\n" . json_encode($result, JSON_PRETTY_PRINT));
r2(U . "order/view/" . $trx['id'], 'w', "Transaction status :" . $result['status']);
}
}
function paypal_capture_transaction($trx_id)
{
return json_decode(
Http::postJsonData(
paypal_get_server() . 'checkout/orders/' . $trx_id . '/capture',
[],
[
'PayPal-Partner-Attribution-Id: &lt;BN-Code&gt;',
'Authorization: Bearer ' . paypalGetAccessToken()
]
),
true
);
}
function paypalGetAccessToken()
{
global $config;
$result = Http::postData(str_replace('v2', 'v1', paypal_get_server()) . 'oauth2/token', [
"grant_type" => "client_credentials"
], [], $config['paypal_client_id'] . ":" . $config['paypal_secret_key']);
$json = json_decode($result, true);
return $json['access_token'];
}
function paypal_get_server()
{
global $_app_stage;
if ($_app_stage == 'Live') {
return 'https://api-m.paypal.com/v2/';
} else {
return 'https://api-m.sandbox.paypal.com/v2/';
}
}

View File

@ -0,0 +1,103 @@
[
{
"id": "USD",
"name": "United States dollar"
},
{
"id": "AUD",
"name": "Australian dollar"
},
{
"id": "BRL",
"name": "Brazilian real **"
},
{
"id": "CAD",
"name": "Canadian dollar"
},
{
"id": "CNY",
"name": "Chinese Renmenbi ***"
},
{
"id": "CZK",
"name": "Czech koruna"
},
{
"id": "DKK",
"name": "Danish krone"
},
{
"id": "EUR",
"name": "Euro"
},
{
"id": "HKD",
"name": "Hong Kong dollar"
},
{
"id": "HUF",
"name": "Hungarian forint *"
},
{
"id": "ILS",
"name": "Israeli new shekel"
},
{
"id": "JPY",
"name": "Japanese yen *"
},
{
"id": "MYR",
"name": "Malaysian ringgit ***"
},
{
"id": "MXN",
"name": "Mexican peso"
},
{
"id": "TWD",
"name": "New Taiwan dollar *"
},
{
"id": "NZD",
"name": "New Zealand dollar"
},
{
"id": "NOK",
"name": "Norwegian krone"
},
{
"id": "PHP",
"name": "Philippine peso"
},
{
"id": "PLN",
"name": "Polish złoty"
},
{
"id": "GBP",
"name": "Pound sterling"
},
{
"id": "RUB",
"name": "Russian ruble"
},
{
"id": "SGD",
"name": "Singapore dollar"
},
{
"id": "SEK",
"name": "Swedish krona"
},
{
"id": "CHF",
"name": "Swiss franc"
},
{
"id": "THB",
"name": "Thai baht"
}
]

View File

@ -0,0 +1,184 @@
<?php
/**
* PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/)
*
* Payment Gateway paystack.com
*
* created by @foculinkstech
*
**/
function paystack_validate_config()
{
global $config;
if (empty($config['paystack_secret_key'])) {
Message::sendTelegram("paystack payment gateway not configured");
r2(U . 'order/package', 'w', Lang::T("Admin has not yet setup paystack payment gateway, please tell admin"));
}
}
function paystack_show_config()
{
global $ui;
$ui->assign('_title', 'Paystack - Payment Gateway');
$ui->assign('cur', json_decode(file_get_contents('system/paymentgateway/paystack_currency.json'), true));
$ui->assign('channel', json_decode(file_get_contents('system/paymentgateway/paystack_channel.json'), true));
$ui->display('paystack.tpl');
}
function paystack_save_config()
{
global $admin, $_L;
$paystack_secret_key = _post('paystack_secret_key');
$paystack_currency = _post('paystack_currency');
$d = ORM::for_table('tbl_appconfig')->where('setting', 'paystack_secret_key')->find_one();
if ($d) {
$d->value = $paystack_secret_key;
$d->save();
} else {
$d = ORM::for_table('tbl_appconfig')->create();
$d->setting = 'paystack_secret_key';
$d->value = $paystack_secret_key;
$d->save();
}
$d = ORM::for_table('tbl_appconfig')->where('setting', 'paystack_currency')->find_one();
if ($d) {
$d->value = $paystack_currency;
$d->save();
} else {
$d = ORM::for_table('tbl_appconfig')->create();
$d->setting = 'paystack_currency';
$d->value = $paystack_currency;
$d->save();
}
$d = ORM::for_table('tbl_appconfig')->where('setting', 'paystack_channel')->find_one();
if ($d) {
$d->value = implode(',', $_POST['paystack_channel']);
$d->save();
} else {
$d = ORM::for_table('tbl_appconfig')->create();
$d->setting = 'paystack_channel';
$d->value = implode(',', $_POST['paystack_channel']);
$d->save();
}
_log('[' . $admin['username'] . ']: paystack ' . $_L['Settings_Saved_Successfully'], 'Admin', $admin['id']);
r2(U . 'paymentgateway/paystack', 's', $_L['Settings_Saved_Successfully']);
}
function paystack_create_transaction($trx, $user)
{
global $config;
$txref = uniqid('trx');
$total = $trx['price']*100;
$json = [
'reference' => $txref,
'amount' => $total,
'currency' => $config['paystack_currency'],
'channels' => explode(',', $config['paystack_channel']),
'email' => (empty($user['email'])) ? $user['username'] . '@' . $_SERVER['HTTP_HOST'] : $user['email'],
'customer' => [
'firstname' => $user['fullname'],
'phone' => $user['phonenumber']
],
'meta' => [
'price' => $trx['price']
],
'customizations' => [
'title' => $trx['plan_name'],
'description' => $trx['plan_name']
],
'callback_url' => U . 'order/view/' . $trx['id'] . '/check'
];
// die(json_encode($json,JSON_PRETTY_PRINT));
$result = json_decode(Http::postJsonData(paystack_get_server() . 'initialize', $json,[
'Authorization: Bearer ' . $config['paystack_secret_key'],
'Cache-Control: no-cahe'
],
),
true);
//die(json_encode($result,JSON_PRETTY_PRINT));
if ($result['status'] == false) {
Message::sendTelegram("Paystack payment failed\n\n" . json_encode($result, JSON_PRETTY_PRINT));
r2(U . 'order/package', 'e', Lang::T("Failed to create transaction.\n".$result['message']));
}
$d = ORM::for_table('tbl_payment_gateway')
->where('username', $user['username'])
->where('status', 1)
->find_one();
$d->gateway_trx_id = $result['data']['reference'];
$d->pg_url_payment = $result['data']['authorization_url'];
$d->pg_request = json_encode($result);
$d->expired_date = date('Y-m-d H:i:s', strtotime("+ 6 HOUR"));
$d->save();
header('Location: ' . $result['data']['authorization_url']);
exit();
//r2(U . "order/view/" . $d['id'], 's', Lang::T("Create Transaction Success"));
}
function paystack_payment_notification()
{
//to be implemented
}
function paystack_get_status($trx, $user)
{
global $config;
$result = json_decode(Http::getData(paystack_get_server() . 'verify/' . $trx['gateway_trx_id'], [
'Authorization: Bearer ' . $config['paystack_secret_key'],
'Cache-Control: no-cahe'
]), true);
$amountPaid = $result['data']['amount'];
$amountToPay = $result['data']['requested_amount'];
if ($result['status'] == true && $result['data']['status'] === 'abandoned' || $result['data']['status'] ==='failed' || $amountPaid < $amountToPay ){
// die(json_encode($result,JSON_PRETTY_PRINT));
r2(U . "order/view/" . $trx['id'], 'w', Lang::T("Transaction still unpaid."));
}else if (in_array($result['status'] == true && $result['data']['status'], ['success']) && $trx['status'] != 2) {
if (!Package::rechargeUser($user['id'], $trx['routers'], $trx['plan_id'], $trx['gateway'], $result['data']['channel'])) {
r2(U . "order/view/" . $trx['id'], 'd', Lang::T("Failed to activate your Package, try again later."));
}
$trx->pg_paid_response = json_encode($result);
$trx->payment_method = 'Paystack';
$trx->payment_channel = $result['data']['channel'];
$trx->paid_date = date('Y-m-d H:i:s', strtotime( $result['data']['created_at']));
$trx->status = 2;
$trx->save();
r2(U . "order/view/" . $trx['id'], 's', Lang::T("Transaction successful."));
} else if ($result['status'] == 'EXPIRED') {
$trx->pg_paid_response = json_encode($result);
$trx->status = 3;
$trx->save();
r2(U . "order/view/" . $trx['id'], 'd', Lang::T("Transaction expired."));
} else if ($trx['status'] == 2) {
r2(U . "order/view/" . $trx['id'], 'd', Lang::T("Transaction has been paid.."));
}else{
Message::sendTelegram("flutterwave_get_status: unknown result\n\n".json_encode($result, JSON_PRETTY_PRINT));
r2(U . "order/view/" . $trx['id'], 'd', Lang::T("Unknown Command."));
}
}
function paystack_get_server()
{
global $_app_stage;
if ($_app_stage == 'Live') {
return 'https://api.paystack.co/transaction/';
} else {
return 'https://api.paystack.co/transaction/';
}
}

View File

@ -0,0 +1,27 @@
[
{
"id": "card",
"name": "Card Payment"
},
{
"id": "ussd",
"name": "USSD"
},
{
"id": "bank",
"name": "Bank Account"
},
{
"id": "bank_transfer",
"name": "Bank Transfer"
},
{
"id": "qr",
"name": "QR payment"
},
{
"id": "mobile_money",
"name": "Mobile Money"
}
]

View File

@ -0,0 +1,25 @@
[
{
"id": "NGN",
"name": "Nigerian Naira"
},
{
"id": "GHC",
"name": "Ghana Cedis"
},
{
"id": "KES",
"name": "Kenyan Shilling"
},
{
"id": "ZAR",
"name": "South African Rand"
},
{
"id": "USD",
"name": "United States Dollar"
}
]

View File

@ -0,0 +1,42 @@
{include file="sections/header.tpl"}
<div class="container-fluid">
<form class="form-horizontal" method="post" role="form" action="{$_url}paymentgateway/BankStkPush" >
<div class="row">
<div class="col-sm-12 col-md-12">
<div class="card card-primary card-hovered card-stacked mb30">
<div class="card-header">Fill the details below to complete the bank stk Push</div>
<div class="card-body">
<div class="form-group">
<label class="col-md-2 control-label">Enter Bank account number</label>
<div class="col-md-6">
<input type="text" class="form-control" id="kopokopo_app_key" name="account" placeholder="*************************" value="{$_c['Stkbankacc']}">
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">Bank Name</label>
<div class="col-md-6">
<select class="form-control" name="bankname" id="bankstk">
<option value="Equity" {if $_c['Stkbankname'] == 'Equity'}selected{/if}>Equity bank</option>
<option value="KCB" {if $_c['Stkbankname'] == 'KCB'}selected{/if}>Kenya Commercial Bank</option>
<option value="Coop" {if $_c['Stkbankname'] == 'Coop'}selected{/if}>Cooperative Bank of Kenya</option>
<option value="Absa" {if $_c['Stkbankname'] == 'Absa'}selected{/if}>Absa Bank Kenya</option>
<option value="DTB" {if $_c['Stkbankname'] == 'Dtb'}selected{/if}>Diamond Trust Bank (DTB)</option>
<option value="NCBA" {if $_c['Stkbankname'] == 'NCBA'}selected{/if}>NCBA Bank</option>
</select>
</div>
</div>
<pre>After aplying these changes, the funds shall be going to the saved bank account, please make sure the bank name and account matches</pre>
<div class="form-group">
<div class="col-lg-offset-2 col-lg-10">
<button class="btn btn-primary waves-effect waves-light" type="submit">Save</button>
</div>
</div>
</div>
</div>
</div>
</form>
</div>
{include file="sections/footer.tpl"}

View File

@ -0,0 +1,59 @@
{include file="sections/header.tpl"}
<form class="form-horizontal" method="post" role="form" action="{$_url}paymentgateway/flutterwave">
<div class="row">
<div class="col-sm-12 col-md-12">
<div class="panel panel-primary panel-hovered panel-stacked mb30">
<div class="panel-heading">Flutterwave Payment Gateway</div>
<div class="panel-body">
<div class="form-group">
<label class="col-md-2 control-label">Flutterwave Secret Key</label>
<div class="col-md-6">
<input type="text" class="form-control" id="flutterwave_secret_key" name="flutterwave_secret_key"
value="{$_c['flutterwave_secret_key']}">
<a href="https://app.flutterwave.com/dashboard/settings/apis/live" target="_blank"
class="help-block">https://app.flutterwave.com/dashboard/settings/apis/live</a>
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">Payment Channels</label>
<div class="col-md-6">
{foreach $channel as $payment_options}
<label class="checkbox-inline"><input type="checkbox" {if strpos($_c['flutterwave_channel'], $payment_options['id']) !== false}checked="true"{/if} id="flutterwave_channel" name="flutterwave_channel[]" value="{$payment_options['id']}"> {$payment_options['name']}</label>
{/foreach}
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">Currency</label>
<div class="col-md-6">
<select class="form-control" name="flutterwave_currency">
{foreach $cur as $currency}
<option value="{$currency['id']}"
{if $currency['id'] == $_c['flutterwave_currency']}selected{/if}
>{$currency['id']} - {$currency['name']}</option>
{/foreach}
</select>
<small class="form-text text-muted">Attention</small>
</div>
</div>
<div class="form-group">
<div class="col-lg-offset-2 col-lg-10">
<button class="btn btn-primary waves-effect waves-light"
type="submit">{$_L['Save']}</button>
</div>
</div>
<pre>/ip hotspot walled-garden
add dst-host=flutterwave.com
add dst-host=*.flutterwave.com</pre>
<small class="form-text text-muted">Set Telegram Bot to get any error and
notification</small>
</div>
</div>
</div>
</div>
</form>
{include file="sections/footer.tpl"}

Binary file not shown.

View File

@ -0,0 +1,63 @@
{include file="sections/header.tpl"}
<form class="form-horizontal" method="post" role="form" action="{$_url}paymentgateway/iotec">
<div class="row">
<div class="col-sm-12 col-md-12">
<div class="panel panel-primary panel-hovered panel-stacked mb30">
<div class="panel-heading">ioTec Pay</div>
<div class="panel-body">
<div class="form-group">
<label class="col-md-2 control-label">Client ID</label>
<div class="col-md-6">
<input type="text" class="form-control" id="iotec_client_id" name="iotec_client_id" placeholder="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" value="{$_c['iotec_client_id']}">
<small class="form-text text-muted"><a href="https://pay.iotec.io" target="_blank">Contact ioTec Support for credentials</a></small>
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">Client Secret</label>
<div class="col-md-6">
<input type="password" class="form-control" id="iotec_client_secret" name="iotec_client_secret" placeholder="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" value="{$_c['iotec_client_secret']}">
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">Wallet ID</label>
<div class="col-md-6">
<input type="text" class="form-control" id="iotec_wallet_id" name="iotec_wallet_id" placeholder="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" maxlength="36" value="{$_c['iotec_wallet_id']}">
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">ioTec Environment</label>
<div class="col-md-6">
<select class="form-control" name="iotec_env">
{foreach $env as $environment}
<option value="{$environment['id']}"
{if $environment['id'] == $_c['iotec_env']}selected{/if}
>{$environment['id']} - {$environment['name']}</option>
{/foreach}
</select>
<small class="form-text text-muted"><font color="red"><b>Sandbox</b></font> is for testing with test numbers. Switch to <font color="green"><b>Live</b></font> for production.</small>
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">Callback URL</label>
<div class="col-md-6">
<input type="text" readonly class="form-control" onclick="this.select()" value="{$_url}callback/iotec">
<p class="help-block">Register this URL with ioTec Support for transaction notifications</p>
</div>
</div>
<div class="form-group">
<div class="col-lg-offset-2 col-lg-10">
<button class="btn btn-primary waves-effect waves-light" type="submit">{$_L['Save']}</button>
</div>
</div>
<pre>Test Numbers for Sandbox:
0111777770 to 0111777779 (Success)
0111777780 to 0111777789 (Pending)
0111777790 to 0111777799 (SentToVendor)
0111777990 to 0111777999 (Failed)</pre>
</div>
</div>
</div>
</div>
</form>
{include file="sections/footer.tpl"}

View File

@ -0,0 +1,69 @@
{include file="sections/header.tpl"}
<form class="form-horizontal" method="post" role="form" action="{$_url}paymentgateway/mpesa" >
<div class="row">
<div class="col-sm-12 col-md-12">
<div class="panel panel-primary panel-hovered panel-stacked mb30">
<div class="panel-heading">M-Pesa</div>
<div class="panel-body">
<div class="form-group">
<label class="col-md-2 control-label">Consumer Key</label>
<div class="col-md-6">
<input type="text" class="form-control" id="mpesa_consumer_key" name="mpesa_consumer_key" placeholder="xxxxxxxxxxxxxxxxx" value="{$_c['mpesa_consumer_key']}">
<small class="form-text text-muted"><a href="https://developer.safaricom.co.ke/MyApps" target="_blank">https://developer.safaricom.co.ke/MyApps</a></small>
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">Consumer Secret</label>
<div class="col-md-6">
<input type="password" class="form-control" id="mpesa_consumer_secret" name="mpesa_consumer_secret" placeholder="xxxxxxxxxxxxxxxxx" value="{$_c['mpesa_consumer_secret']}">
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">Business Shortcode</label>
<div class="col-md-6">
<input type="text" class="form-control" id="mpesa_business_code" name="mpesa_business_code" placeholder="xxxxxxx" maxlength="7" value="{$_c['mpesa_business_code']}">
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">Pass Key</label>
<div class="col-md-6">
<input type="text" class="form-control" id="mpesa_pass_key" name="mpesa_pass_key" placeholder="bfb279f9aa9bdbcf158e97dd71a467cd2e0c893059b10f78e6b72ada1ed2c919" maxlength="" value="{$_c['mpesa_pass_key']}">
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">M-Pesa Environment</label>
<div class="col-md-6">
<select class="form-control" name="mpesa_env">
{foreach $env as $environment}
<option value="{$environment['id']}"
{if $environment['id'] == $_c['mpesa_env']}selected{/if}
>{$environment['id']} - {$environment['name']}</option>
{/foreach}
</select>
<small class="form-text text-muted"><font color="red"><b>Sandbox</b></font> is for testing purpose, please switch to <font color="green"><b>Live</b></font> in production.</small>
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">Url Notification</label>
<div class="col-md-6">
<input type="text" readonly class="form-control" onclick="this.select()" value="{$_url}callback/mpesa">
<p class="help-block">CallBack URL</p>
</div>
</div>
<div class="form-group">
<div class="col-lg-offset-2 col-lg-10">
<button class="btn btn-primary waves-effect waves-light" type="submit">{$_L['Save']}</button>
</div>
</div>
<pre>/ip hotspot walled-garden
add dst-host=safaricom.co.ke
add dst-host=*.safaricom.co.ke</pre>
</div>
</div>
</div>
</div>
</form>
{include file="sections/footer.tpl"}

View File

@ -0,0 +1,69 @@
{include file="sections/header.tpl"}
<form class="form-horizontal" method="post" role="form" action="{$_url}paymentgateway/MpesatillStk" >
<div class="row">
<div class="col-sm-12 col-md-12">
<div class="panel panel-primary panel-hovered panel-stacked mb30">
<div class="panel-heading">M-Pesa</div>
<div class="panel-body">
<div class="form-group">
<label class="col-md-2 control-label">Consumer Key</label>
<div class="col-md-6">
<input type="text" class="form-control" id="mpesa_consumer_key" name="mpesa_consumer_key" placeholder="xxxxxxxxxxxxxxxxx" value="{$_c['mpesa_till_consumer_key']}">
<small class="form-text text-muted"><a href="https://developer.safaricom.co.ke/MyApps" target="_blank">https://developer.safaricom.co.ke/MyApps</a></small>
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">Consumer Secret</label>
<div class="col-md-6">
<input type="text" class="form-control" id="mpesa_consumer_secret" name="mpesa_consumer_secret" placeholder="xxxxxxxxxxxxxxxxx" value="{$_c['mpesa_till_consumer_secret']}">
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">Business Shortcode(Store number/H.O)</label>
<div class="col-md-6">
<input type="text" class="form-control" id="mpesa_business_code" name="mpesa_business_code" placeholder="xxxxxxx" maxlength="7" value="{$_c['mpesa_till_shortcode_code']}">
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">Business Shortcode(Till number)</label>
<div class="col-md-6">
<input type="text" class="form-control" id="mpesa_business_code" name="mpesa_till" placeholder="xxxxxxx" maxlength="7" value="{$_c['mpesa_till_partyb']}">
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">Pass Key</label>
<div class="col-md-6">
<input type="text" class="form-control" id="mpesa_pass_key" name="mpesa_pass_key" placeholder="bfb279f9aa9bdbcf158e97dd71a467cd2e0c893059b10f78e6b72ada1ed2c919" maxlength="" value="{$_c['mpesa_till_pass_key']}">
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">M-Pesa Environment</label>
<div class="col-md-6">
<select class="form-control" name="mpesa_env">
{foreach $env as $environment}
<option value="{$environment['id']}"
{if $environment['id'] == $_c['mpesa_env']}selected{/if}
>{$environment['id']} - {$environment['name']}</option>
{/foreach}
</select>
<small class="form-text text-muted"><font color="red"><b>Sandbox</b></font> is for testing purpose, please switch to <font color="green"><b>Live</b></font> in production.</small>
</div>
</div>
<div class="form-group">
<div class="col-lg-offset-2 col-lg-10">
<button class="btn btn-primary waves-effect waves-light" type="submit">Save</button>
</div>
</div>
<pre>/ip hotspot walled-garden
add dst-host=safaricom.co.ke
add dst-host=*.safaricom.co.ke</pre>
</div>
</div>
</div>
</div>
</form>
{include file="sections/footer.tpl"}

View File

@ -0,0 +1,64 @@
{include file="sections/header.tpl"}
<form class="form-horizontal" method="post" role="form" action="{$_url}paymentgateway/paypal">
<div class="row">
<div class="col-sm-12 col-md-12">
<div class="panel panel-primary panel-hovered panel-stacked mb30">
<div class="panel-heading">PayPal Payment Gateway</div>
<div class="panel-body">
<div class="form-group">
<label class="col-md-2 control-label">Client ID</label>
<div class="col-md-6">
<input type="text" class="form-control" id="paypal_client_id" name="paypal_client_id"
value="{$_c['paypal_client_id']}">
<a href="https://developer.paypal.com/dashboard/applications/live" target="_blank"
class="help-block">https://developer.paypal.com/dashboard/applications/live</a>
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">Verification Token</label>
<div class="col-md-6">
<input type="text" class="form-control" id="paypal_secret_key" name="paypal_secret_key"
value="{$_c['paypal_secret_key']}">
<a href="https://developer.paypal.com/dashboard/applications/live" target="_blank"
class="help-block">https://developer.paypal.com/dashboard/applications/live</a>
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">Currency</label>
<div class="col-md-6">
<select class="form-control" name="paypal_currency">
{foreach $currency as $cur}
<option value="{$cur['id']}"
{if $cur['id'] == $_c['paypal_currency']}selected{/if}
>{$cur['id']} - {$cur['name']}</option>
{/foreach}
</select>
<small class="form-text text-muted">* This currency does not support decimals. If you pass a decimal amount, an error occurs.<br>
** This currency is supported as a payment currency and a currency balance for in-country PayPal
accounts only. If the receiver of funds is not from Brazil, then PayPal converts funds into the
primary holding currency of the account with the applicable currency conversion rate. The currency
conversion rate includes PayPal's applicable spread or fee.<br>
*** This currency is supported as a payment currency and a currency balance for in-country PayPal
accounts only.</small>
</div>
</div>
<div class="form-group">
<div class="col-lg-offset-2 col-lg-10">
<button class="btn btn-primary waves-effect waves-light"
type="submit">{Lang::T('Save')}</button>
</div>
</div>
<pre>/ip hotspot walled-garden
add dst-host=paypal.com
add dst-host=*.paypal.com</pre>
<small class="form-text text-muted">Set Telegram Bot to get any error and
notification</small>
</div>
</div>
</div>
</div>
</form>
{include file="sections/footer.tpl"}

View File

@ -0,0 +1,59 @@
{include file="sections/header.tpl"}
<form class="form-horizontal" method="post" role="form" action="{$_url}paymentgateway/paystack">
<div class="row">
<div class="col-sm-12 col-md-12">
<div class="panel panel-primary panel-hovered panel-stacked mb30">
<div class="panel-heading">Paystack Payment Gateway</div>
<div class="panel-body">
<div class="form-group">
<label class="col-md-2 control-label">Paystack Secret Key</label>
<div class="col-md-6">
<input type="text" class="form-control" id="paystack_secret_key" name="paystack_secret_key"
value="{$_c['paystack_secret_key']}">
<a href="https://dashboard.paystack.co/#/settings/developer" target="_blank"
class="help-block">https://dashboard.paystack.co/#/settings/developer</a>
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">Payment Channels</label>
<div class="col-md-6">
{foreach $channel as $payment_options}
<label class="checkbox-inline"><input type="checkbox" {if strpos($_c['paystack_channel'], $payment_options['id']) !== false}checked="true"{/if} id="paystack_channel" name="paystack_channel[]" value="{$payment_options['id']}"> {$payment_options['name']}</label>
{/foreach}
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">Currency</label>
<div class="col-md-6">
<select class="form-control" name="paystack_currency">
{foreach $cur as $currency}
<option value="{$currency['id']}"
{if $currency['id'] == $_c['paystack_currency']}selected{/if}
>{$currency['id']} - {$currency['name']}</option>
{/foreach}
</select>
<small class="form-text text-muted">Attention</small>
</div>
</div>
<div class="form-group">
<div class="col-lg-offset-2 col-lg-10">
<button class="btn btn-primary waves-effect waves-light"
type="submit">{$_L['Save']}</button>
</div>
</div>
<pre>/ip hotspot walled-garden
add dst-host=paystack.com
add dst-host=*.paystack.com</pre>
<small class="form-text text-muted">Set Telegram Bot to get any error and
notification</small>
</div>
</div>
</div>
</div>
</form>
{include file="sections/footer.tpl"}

BIN
system/plugin/.DS_Store vendored Normal file

Binary file not shown.

2
system/plugin/.gitattributes vendored Normal file
View File

@ -0,0 +1,2 @@
# Auto detect text files and perform LF normalization
* text=auto

View File

@ -0,0 +1,420 @@
<?php
function Alloworigins()
{
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: GET, POST, OPTIONS");
header("Access-Control-Allow-Headers: Content-Type");
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
exit;
}
$requestUri = $_SERVER['REQUEST_URI'];
$queryString = parse_url($requestUri, PHP_URL_QUERY);
$type = null;
if ($queryString) {
parse_str($queryString, $queryParameters);
if (isset($queryParameters['type'])) {
$type = $queryParameters['type'];
if ($type === "grant") {
CreateHostspotUser();
exit;
} elseif ($type === "verify") {
VerifyHotspot();
exit;
} elseif ($type === "reconnect") {
ReconnectUser();
exit;
} elseif ($type === "voucher") {
ReconnectVoucher();
exit;
} else {
echo json_encode(['status' => 'error', 'code' => 400, 'message' => 'The parameter is not present in the URL.']);
}
}
}
}
function ReconnectVoucher() {
header('Content-Type: application/json');
$rawData = file_get_contents('php://input');
$postData = json_decode($rawData, true);
if (!isset($postData['voucher_code'], $postData['account_id'])) {
echo json_encode(['status' => 'error', 'code' => 400, 'message' => 'Missing accountId or voucherCode field']);
return;
}
$accountId = $postData['account_id'];
$voucherCode = $postData['voucher_code'];
$voucher = ORM::for_table('tbl_voucher')
->where('code', $voucherCode)
->where('status', '0')
->find_one();
if (!$voucher) {
echo json_encode([
'status' => 'error',
'Resultcode' => '1',
'voucher' => 'Not Found',
'message' => 'Invalid Voucher code'
]);
exit();
}
if ($voucher['status'] == '1') {
echo json_encode([
'status' => 'error',
'Resultcode' => '3',
'voucher' => 'Used',
'message' => 'Voucher code is already used'
]);
exit();
}
$planId = $voucher['id_plan'];
$routername = $voucher['routers'];
$router = ORM::for_table('tbl_routers')
->where('name', $routername)
->find_one();
if (!$router) {
echo json_encode([
'status' => 'error',
'message' => 'Router not found'
]);
exit();
}
$routerId = $router['id'];
if (!ORM::for_table('tbl_plans')->where('id', $planId)->count() || !ORM::for_table('tbl_routers')->where('id', $routerId)->count()) {
echo json_encode([
'status' => 'error',
'message' => 'Unable to process your request, please refresh the page'
]);
exit();
}
$user = ORM::for_table('tbl_customers')->where('username', $accountId)->find_one();
if (!$user) {
// Create a new user if not exists
$user = ORM::for_table('tbl_customers')->create();
$user->username = $accountId;
$user->password = '1234';
$user->fullname = $accountId;
$user->email = $accountId . '@gmail.com';
$user->phonenumber = $accountId;
$user->pppoe_password = '1234';
$user->address = '';
$user->service_type = 'Hotspot';
}
$user->router_id = $routerId;
$user->save();
// Update the voucher with the user ID
$voucher->user = $user->id;
$voucher->status = '1'; // Mark as used
$voucher->save();
if (Package::rechargeUser($user->id, $routername, $planId, 'Voucher', $voucherCode)) {
echo json_encode([
'status' => 'success',
'Resultcode' => '2',
'voucher' => 'activated',
'message' => 'Voucher code has been activated',
'username' => $user->username
]);
} else {
echo json_encode([
'status' => 'error',
'message' => 'Failed to recharge user package'
]);
}
}
function ReconnectUser()
{
header('Content-Type: application/json');
$rawData = file_get_contents('php://input');
$postData = json_decode($rawData, true);
if (!$postData) {
echo json_encode(['status' => 'error', 'code' => 400, 'message' => 'Invalid JSON DATA']);
exit();
}
if (!isset($postData['mpesa_code'])) {
echo json_encode(['status' => 'error', 'code' => 400, 'message' => 'missing required fields']);
exit();
}
$mpesaCode = $postData['mpesa_code'];
// Query the payment gateway table
$payment = ORM::for_table('tbl_payment_gateway')
->where('gateway_trx_id', $mpesaCode)
->find_one();
if (!$payment) {
$data = array(['status' => 'error', "Resultcode" => "1", 'user' => "Not Found", 'message' => 'Invalid Mpesa Transaction code']);
echo json_encode($data);
exit();
}
$username = $payment['username'];
// Query the user recharges table
$recharge = ORM::for_table('tbl_user_recharges')
->where('username', $username)
->order_by_desc('id')
->find_one();
if ($recharge) {
$status = $recharge['status'];
if ($status == 'on') {
$data = array(
"Resultcode" => "2",
"user" => "Active User",
"username" => $username,
"tyhK" => "1234", // Replace with the actual password or token
"Message" => "We have verified your transaction under the Mpesa Transaction $mpesaCode. Please don't leave this page as we are redirecting you.",
"Status" => "success"
);
} elseif ($status == "off") {
$data = array(
"Resultcode" => "3",
"user" => "Expired User",
"Message" => "We have verified your transaction under the Mpesa Transaction $mpesaCode. But your Package is already Expired. Please buy a new Package.",
"Status" => "danger"
);
} else {
$data = array(
"Message" => "Unexpected status value",
"Status" => "error"
);
}
} else {
$data = array(
"Message" => "Recharge information not found",
"Status" => "error"
);
}
echo json_encode($data);
exit();
}
function VerifyHotspot() {
header('Content-Type: application/json');
$rawData = file_get_contents('php://input');
$postData = json_decode($rawData, true);
if (!$postData) {
echo json_encode(['Resultcode' => 'error', 'Message' => 'Invalid JSON data']);
return;
}
if (!isset($postData['account_id'])) {
echo json_encode(['Resultcode' => 'error', 'Message' => 'Missing required fields']);
return;
}
$accountId = $postData['account_id'];
$user = ORM::for_table('tbl_payment_gateway')
->where('username', $accountId)
->order_by_desc('id')
->find_one();
if ($user) {
$status = $user->status;
$mpesacode = $user->gateway_trx_id;
$res = $user->pg_paid_response;
if ($status == 2 && !empty($mpesacode)) {
echo json_encode([
"Resultcode" => "3",
"Message" => "We have received your transaction under the Mpesa Transaction $mpesacode. Please do not leave this page as we are redirecting you.",
"Status" => "success"
]);
} elseif ($res == "Not enough balance") {
echo json_encode([
"Resultcode" => "2",
"Message" => "Insufficient Balance for the transaction",
"Status" => "danger"
]);
} elseif ($res == "Wrong Mpesa pin") {
echo json_encode([
"Resultcode" => "2",
"Message" => "You entered Wrong Mpesa pin, please resubmit",
"Status" => "danger"
]);
} elseif ($status == 4) {
echo json_encode([
"Resultcode" => "2",
"Message" => "You cancelled the transaction, you can enter phone number again to activate",
"Status" => "info"
]);
} elseif (empty($mpesacode)) {
echo json_encode([
"Resultcode" => "1",
"Message" => "A payment pop up has been sent to your phone. Please enter PIN to continue (Please do not leave or reload the page until redirected).",
"Status" => "primary"
]);
}
} else {
echo json_encode([
"Resultcode" => "error",
"Message" => "User not found"
]);
}
}
function CreateHostspotUser()
{
header('Content-Type: application/json');
$rawData = file_get_contents('php://input');
$postData = json_decode($rawData, true);
if (!$postData) {
echo json_encode(['status' => 'error', 'code' => 400, 'message' => 'Invalid JSON DATA' . $postData . ' n tes ']);
} else {
$phone = $postData['phone_number'];
$planId = $postData['plan_id'];
$routerId = $postData['router_id'];
$accountId = $postData['account_id'];
if (!isset( $postData['phone_number'], $postData['plan_id'], $postData['router_id'], $postData['account_id'])) {
echo json_encode(['status' => 'error', 'code' => 400, 'message' => 'missing required fields' . $postData, 'phone' => $phone, 'planId' => $planId, 'routerId' => $routerId, 'accountId' => $accountId]);
} else {
$phone = (substr($phone, 0, 1) == '+') ? str_replace('+', '', $phone) : $phone;
$phone = (substr($phone, 0, 1) == '0') ? preg_replace('/^0/', '254', $phone) : $phone;
$phone = (substr($phone, 0, 1) == '7') ? preg_replace('/^7/', '2547', $phone) : $phone; //cater for phone number prefix 2547XXXX
$phone = (substr($phone, 0, 1) == '1') ? preg_replace('/^1/', '2541', $phone) : $phone; //cater for phone number prefix 2541XXXX
$phone = (substr($phone, 0, 1) == '0') ? preg_replace('/^01/', '2541', $phone) : $phone;
$phone = (substr($phone, 0, 1) == '0') ? preg_replace('/^07/', '2547', $phone) : $phone;
if (strlen($phone) !== 12) {
echo json_encode(['status' => 'error', 'code' => 1, 'message' => 'Phone number ' . $phone . ' is invalid. Please confirm.']);
}
if (strlen($phone) == 12 && !empty($planId) && !empty($routerId)) {
$PlanExist = ORM::for_table('tbl_plans')->where('id', $planId)->count() > 0;
$RouterExist = ORM::for_table('tbl_routers')->where('id', $routerId)->count() > 0;
if (!$PlanExist || !$RouterExist)
echo json_encode(["status" => "error", "message" => "Unable to process your request, please refresh the page."]);
}
$Userexist = ORM::for_table('tbl_customers')->where('username', $accountId)->find_one();
if ($Userexist) {
$Userexist->router_id = $routerId;
$Userexist->save();
InitiateStkpush($phone, $planId, $accountId, $routerId);
} else {
try {
$defpass = '1234';
$defaddr = 'netXtreme';
$defmail = $phone . '@gmail.com';
$createUser = ORM::for_table('tbl_customers')->create();
$createUser->username = $accountId;
$createUser->password = $defpass;
$createUser->fullname = $phone;
$createUser->router_id = $routerId;
$createUser->phonenumber = $phone;
$createUser->pppoe_password = $defpass;
$createUser->address = $defaddr;
$createUser->email = $defmail;
$createUser->service_type = 'Hotspot';
if ($createUser->save()) {
InitiateStkpush($phone, $planId, $accountId, $routerId);
} else {
echo json_encode(["status" => "error", "message" => "There was a system error when registering user, please contact support."]);
}
} catch (Exception $e) {
echo json_encode(["status" => "error", "message" => "Error creating user: " . $e->getMessage()]);
}
}
}
}
}
function InitiateStkpush($phone, $planId, $accountId, $routerId)
{
$gateway = ORM::for_table('tbl_appconfig')
->where('setting', 'payment_gateway')
->find_one();
$gateway = ($gateway) ? $gateway->value : null;
if ($gateway == "MpesatillStk") {
$url = U . "plugin/initiatetillstk";
} elseif ($gateway == "BankStkPush") {
$url = U . "plugin/initiatebankstk";
} elseif ($gateway == "mpesa") {
$url = U . "plugin/initiatempesa";
} else {
$url = null; // or handle the default case appropriately
}
$Planname = ORM::for_table('tbl_plans')
->where('id', $planId)
->order_by_desc('id')
->find_one();
$Findrouter = ORM::for_table('tbl_routers')
->where('id', $routerId)
->order_by_desc('id')
->find_one();
$rname = $Findrouter->name;
$price = $Planname->price;
$Planname = $Planname->name_plan;
$Checkorders = ORM::for_table('tbl_payment_gateway')
->where('username', $accountId)
->where('status', 1)
->order_by_desc('id')
->find_many();
if ($Checkorders) {
foreach ($Checkorders as $Dorder) {
$Dorder->delete();
}
}
try {
$d = ORM::for_table('tbl_payment_gateway')->create();
$d->username = $accountId;
$d->gateway = $gateway;
$d->plan_id = $planId;
$d->plan_name = $Planname;
$d->routers_id = $routerId;
$d->routers = $rname;
$d->price = $price;
$d->payment_method = $gateway;
$d->payment_channel = $gateway;
$d->created_date = date('Y-m-d H:i:s');
$d->paid_date = date('Y-m-d H:i:s');
$d->expired_date = date('Y-m-d H:i:s');
$d->pg_url_payment = $url;
$d->status = 1;
$d->save();
} catch (Exception $e) {
error_log('Error saving payment gateway record: ' . $e->getMessage());
throw $e;
}
SendSTKcred($phone, $url, $accountId);
}
function SendSTKcred($phone, $url, $accountId )
{
$link = $url;
$fields = array(
'username' => $accountId,
'phone' => $phone,
'channel' => 'Yes',
);
$postvars = http_build_query($fields);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $link);
curl_setopt($ch, CURLOPT_POST, count($fields));
curl_setopt($ch, CURLOPT_POSTFIELDS, $postvars);
$result = curl_exec($ch);
}
Alloworigins();

636
system/plugin/c2b.php Normal file
View File

@ -0,0 +1,636 @@
<?php
register_menu("Mpesa C2B Settings", true, "c2b_settings", 'SETTINGS', '', '', "");
register_menu("Mpesa Transactions", true, "c2b_overview", 'AFTER_MESSAGE', 'fa fa-paypal', '', "");
try {
$db = ORM::get_db();
$tableCheckQuery = "CREATE TABLE IF NOT EXISTS tbl_mpesa_transactions (
id INT AUTO_INCREMENT PRIMARY KEY,
TransID VARCHAR(255) NOT NULL,
TransactionType VARCHAR(255) NOT NULL,
TransTime VARCHAR(255) NOT NULL,
TransAmount DECIMAL(10, 2) NOT NULL,
BusinessShortCode VARCHAR(255) NOT NULL,
BillRefNumber VARCHAR(255) NOT NULL,
OrgAccountBalance DECIMAL(10, 2) NOT NULL,
MSISDN VARCHAR(255) NOT NULL,
FirstName VARCHAR(255) NOT NULL,
CustomerID VARCHAR(255) NOT NULL,
PackageName VARCHAR(255) NOT NULL,
PackagePrice VARCHAR(255) NOT NULL,
TransactionStatus VARCHAR(255) NOT NULL,
CreatedAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
)";
$db->exec($tableCheckQuery);
} catch (PDOException $e) {
echo "Error creating the table: " . $e->getMessage();
} catch (Exception $e) {
echo "An unexpected error occurred: " . $e->getMessage();
}
function c2b_overview()
{
global $ui, $config;
_admin();
$ui->assign('_title', 'Mpesa C2B Payment Overview');
$ui->assign('_system_menu', '');
$admin = Admin::_info();
$ui->assign('_admin', $admin);
// Check user type for access
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin', 'Sales'])) {
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
exit;
}
$query = ORM::for_table('tbl_mpesa_transactions')->order_by_desc('TransTime');
$payments = $query->find_many();
if (
(empty($config['mpesa_c2b_consumer_key']) || empty($config['mpesa_c2b_consumer_secret']) || empty($config['mpesa_c2b_business_code']))
&& !$config['c2b_registered']
) {
$ui->assign('message', '<em>' . Lang::T("You haven't registered your validation and verification URLs. Please register URLs by clicking ") . ' <a href="' . APP_URL . '/index.php?_route=plugin/c2b_settings"> Register URL </a>' . '</em>');
}
$ui->assign('payments', $payments);
$ui->assign('xheader', '<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.11.5/css/jquery.dataTables.css">');
$ui->display('c2b_overview.tpl');
}
function c2b_settings()
{
global $ui, $admin, $config;
$ui->assign('_title', Lang::T("Mpesa C2B Settings [Offline Payment]"));
$ui->assign('_system_menu', 'settings');
$admin = Admin::_info();
$ui->assign('_admin', $admin);
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
}
if (_post('save') == 'save') {
$mpesa_c2b_consumer_key = _post('mpesa_c2b_consumer_key');
$mpesa_c2b_consumer_secret = _post('mpesa_c2b_consumer_secret');
$mpesa_c2b_business_code = _post('mpesa_c2b_business_code');
$mpesa_c2b_env = _post('mpesa_c2b_env');
$mpesa_c2b_api = _post('mpesa_c2b_api');
$mpesa_c2b_low_fee = _post('mpesa_c2b_low_fee') ? 1 : 0;
$mpesa_c2b_bill_ref = _post('mpesa_c2b_bill_ref');
$errors = [];
if (empty($mpesa_c2b_consumer_key)) {
$errors[] = Lang::T('Mpesa C2B Consumer Key is required.');
}
if (empty($mpesa_c2b_consumer_secret)) {
$errors[] = Lang::T('Mpesa C2B Consumer Secret is required.');
}
if (empty($mpesa_c2b_business_code)) {
$errors[] = Lang::T('Mpesa C2B Business Code is required.');
}
if (empty($mpesa_c2b_env)) {
$errors[] = Lang::T('Mpesa C2B Environment is required.');
}
if (empty($mpesa_c2b_api)) {
$errors[] = Lang::T('Mpesa C2B API URL is required.');
}
if (empty($mpesa_c2b_bill_ref)) {
$errors[] = Lang::T('Mpesa Bill Ref Number Type is required.');
}
if (!empty($errors)) {
$ui->assign('message', implode('<br>', $errors));
$ui->display('c2b_settings.tpl');
return;
}
$settings = [
'mpesa_c2b_consumer_key' => $mpesa_c2b_consumer_key,
'mpesa_c2b_consumer_secret' => $mpesa_c2b_consumer_secret,
'mpesa_c2b_business_code' => $mpesa_c2b_business_code,
'mpesa_c2b_env' => $mpesa_c2b_env,
'mpesa_c2b_api' => $mpesa_c2b_api,
'mpesa_c2b_low_fee' => $mpesa_c2b_low_fee,
'mpesa_c2b_bill_ref' => $mpesa_c2b_bill_ref,
];
// Update or insert settings in the database
foreach ($settings as $key => $value) {
$d = ORM::for_table('tbl_appconfig')->where('setting', $key)->find_one();
if ($d) {
$d->value = $value;
$d->save();
} else {
$d = ORM::for_table('tbl_appconfig')->create();
$d->setting = $key;
$d->value = $value;
$d->save();
}
}
if ($admin) {
_log('[' . $admin['username'] . ']: ' . Lang::T('Settings Saved Successfully'));
}
r2(U . 'plugin/c2b_settings', 's', Lang::T('Settings Saved Successfully'));
}
if (!empty($config['mpesa_c2b_consumer_key'] && $config['mpesa_c2b_consumer_secret'] && $config['mpesa_c2b_business_code']) && !$config['c2b_registered']) {
$ui->assign('message', '<em>' . Lang::T("You haven't registered your validation and verification URLs, Please register URLs by clicking ") . ' <a href="' . APP_URL . '/index.php?_route=plugin/c2b_settings"> Register URL </a>' . '</em>');
}
$ui->assign('_c', $config);
$ui->assign('companyName', $config['CompanyName']);
$ui->display('c2b_settings.tpl');
}
function c2b_generateAccessToken()
{
global $config;
$mpesa_c2b_env = $config['mpesa_c2b_env'] ?? null;
$mpesa_c2b_consumer_key = $config['mpesa_c2b_consumer_key'] ?? null;
$mpesa_c2b_consumer_secret = $config['mpesa_c2b_consumer_secret'] ?? null;
$access_token_url = match ($mpesa_c2b_env) {
"live" => 'https://api.safaricom.co.ke/oauth/v1/generate?grant_type=client_credentials',
"sandbox" => 'https://sandbox.safaricom.co.ke/oauth/v1/generate?grant_type=client_credentials',
};
$headers = ['Content-Type:application/json; charset=utf8'];
$curl = curl_init($access_token_url);
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($curl, CURLOPT_HEADER, FALSE);
curl_setopt($curl, CURLOPT_USERPWD, "$mpesa_c2b_consumer_key:$mpesa_c2b_consumer_secret");
$result = curl_exec($curl);
$result = json_decode($result);
if (isset($result->access_token)) {
return $result->access_token;
} else {
return null;
}
}
function c2b_registerUrl()
{
global $config;
if (
(empty($config['mpesa_c2b_consumer_key']) || empty($config['mpesa_c2b_consumer_secret']) || empty($config['mpesa_c2b_business_code']))
&& !$config['c2b_registered']
) {
r2(U . 'plugin/c2b_settings', 'e', Lang::T('Please setup your M-Pesa C2B settings first'));
exit;
}
$access_token = c2b_generateAccessToken();
switch ($access_token) {
case null:
r2(U . 'plugin/c2b_settings', 'e', Lang::T('Failed to generate access token'));
exit;
default:
$BusinessShortCode = $config['mpesa_c2b_business_code'] ?? null;
$mpesa_c2b_env = $config['mpesa_c2b_env'] ?? null;
$confirmationUrl = U . 'plugin/c2b_confirmation';
$validationUrl = U . 'plugin/c2b_validation';
$mpesa_c2b_api = $config['mpesa_c2b_api'] ?? null;
$registerurl = match ($mpesa_c2b_env) {
"live" => match ($mpesa_c2b_api) {
"v1" => 'https://api.safaricom.co.ke/mpesa/c2b/v1/registerurl',
"v2" => 'https://api.safaricom.co.ke/mpesa/c2b/v2/registerurl',
},
"sandbox" => 'https://sandbox.safaricom.co.ke/mpesa/c2b/v1/registerurl',
};
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $registerurl);
curl_setopt($curl, CURLOPT_HTTPHEADER, [
'Content-Type:application/json',
"Authorization:Bearer $access_token"
]);
$data = [
'ShortCode' => $BusinessShortCode,
'ResponseType' => 'Completed',
'ConfirmationURL' => $confirmationUrl,
'ValidationURL' => $validationUrl
];
$data_string = json_encode($data);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data_string);
$curl_response = curl_exec($curl);
$data = json_decode($curl_response);
if (isset($data->ResponseCode) && $data->ResponseCode == 0) {
try {
$d = ORM::for_table('tbl_appconfig')->create();
$d->setting = 'c2b_registered';
$d->value = '1';
$d->save();
} catch (Exception $e) {
_log("Failed to save M-Pesa C2B URL to database.\n\n" . $e->getMessage());
sendTelegram("Failed to save M-Pesa C2B URL to database.\n\n" . $e->getMessage());
}
sendTelegram("M-Pesa C2B URL registered successfully");
r2(U . 'plugin/c2b_settings', 's', "M-Pesa C2B URL registered successfully");
} else {
$errorMessage = $data->errorMessage;
sendTelegram("Resister M-Pesa C2B URL Failed\n\n" . json_encode($curl_response, JSON_PRETTY_PRINT));
r2(U . 'plugin/c2b_settings', 'e', "Failed to register M-Pesa C2B URL Error $errorMessage");
}
break;
}
}
function c2b_webhook_log($data)
{
$logFile = 'pages/mpesa-webhook.html';
$logEntry = date('Y-m-d H:i:s') . "<pre>" . htmlspecialchars($data, ENT_QUOTES, 'UTF-8') . "</pre>\n";
if (file_put_contents($logFile, $logEntry, FILE_APPEND) === false) {
sendTelegram("Failed to write to log file: $logFile");
}
}
function c2b_isValidSafaricomIP($ip)
{
$config = c2b_config();
$safaricomIPs = [
'196.201.214.0/24',
'196.201.213.0/24',
'196.201.212.0/24',
'172.69.79.0/24',
'172.69.0.0/24',
'0.0.0.0/0',
];
if ($config['mpesa_c2b_env'] == 'sandbox') {
$safaricomIPs[] = '::1';
}
foreach ($safaricomIPs as $range) {
if (c2b_ipInRange($ip, $range)) {
return true;
}
}
return false;
}
function c2b_ipInRange($ip, $range)
{
list($subnet, $bits) = explode('/', $range);
$ip = ip2long($ip);
$subnet = ip2long($subnet);
$mask = -1 << (32 - $bits);
$subnet &= $mask;
return ($ip & $mask) == $subnet;
}
function c2b_confirmation()
{
global $config;
header("Content-Type: application/json");
$clientIP = $_SERVER['REMOTE_ADDR'];
if (!c2b_isValidSafaricomIP($clientIP)) {
c2b_logAndNotify("Unauthorized request from IP: {$clientIP}");
http_response_code(403);
echo json_encode(["ResultCode" => 1, "ResultDesc" => "Unauthorized"]);
return;
}
$mpesaResponse = file_get_contents('php://input');
if ($mpesaResponse === false) {
c2b_logAndNotify("Failed to get input stream.");
return;
}
c2b_webhook_log('Received webhook request');
c2b_webhook_log($mpesaResponse);
$content = json_decode($mpesaResponse);
if (json_last_error() !== JSON_ERROR_NONE) {
c2b_logAndNotify("Failed to decode JSON response: " . json_last_error_msg());
return;
}
c2b_webhook_log('Decoded JSON data successfully');
if (!class_exists('Package')) {
c2b_logAndNotify("Error: Package class does not exist.");
return;
}
if (isset($config['mpesa_c2b_bill_ref'])) {
switch ($config['mpesa_c2b_bill_ref']) {
case 'phone':
$customer = ORM::for_table('tbl_customers')
->where('phonenumber', $content->BillRefNumber)
->find_one();
break;
case 'username':
$customer = ORM::for_table('tbl_customers')
->where('username', $content->BillRefNumber)
->find_one();
break;
case 'id':
$customer = ORM::for_table('tbl_customers')
->where('id', $content->BillRefNumber)
->find_one();
break;
default:
$customer = null;
break;
}
if (!$customer) {
sendTelegram("Validation failed: No account found for BillRefNumber: $content->BillRefNumber");
_log("Validation failed: No account found for BillRefNumber: $content->BillRefNumber");
echo json_encode(["ResultCode" => "C2B00012", "ResultDesc" => "Invalid Account Number"]);
return;
}
} else {
_log("Configuration error: mpesa_c2b_bill_ref not set.");
sendTelegram("Configuration error: mpesa_c2b_bill_ref not set.");
}
$bills = c2b_billing($customer->id);
if (!$bills) {
c2b_logAndNotify("No matching bill found for BillRefNumber: {$content->BillRefNumber}");
return;
}
foreach ($bills as $bill) {
c2b_handleBillPayment($content, $customer, $bill);
}
echo json_encode(["ResultCode" => 0, "ResultDesc" => "Accepted"]);
}
function c2b_handleBillPayment($content, $customer, $bill)
{
$amountToPay = $bill['price'];
$amountPaid = $content->TransAmount;
$channel_mode = "Mpesa C2B - {$content->TransID}";
$customerBalance = $customer->balance;
$currentBalance = $customerBalance + $amountPaid;
$customerID = $customer->id;
try {
$transaction = c2b_storeTransaction($content, $bill['namebp'], $amountToPay, $customerID);
} catch (Exception $e) {
c2b_handleException("Failed to save transaction", $e);
exit;
}
if ($currentBalance >= $amountToPay) {
$excessAmount = $currentBalance - $amountToPay;
try {
$result = Package::rechargeUser($customer->id, $bill['routers'], $bill['plan_id'], 'mpesa', $channel_mode);
if (!$result) {
c2b_logAndNotify("Mpesa Payment Successful, but failed to activate the package for customer {$customer->username}.");
} else {
if ($excessAmount > 0) {
$customer->balance = $excessAmount;
$customer->save();
} else {
$customer->balance = 0;
$customer->save();
}
c2b_sendPaymentSuccessMessage($customer, $amountPaid, $bill['namebp']);
$transaction->transactionStatus = 'Completed';
$transaction->save();
}
} catch (Exception $e) {
c2b_handleException("Error during package activation", $e);
}
} else {
c2b_updateCustomerBalance($customer, $currentBalance, $amountPaid);
$neededToActivate = $amountToPay - $currentBalance;
c2b_sendBalanceUpdateMessage($customer, $amountPaid, $currentBalance, $neededToActivate);
$transaction->transactionStatus = 'Completed';
$transaction->save();
}
}
function c2b_storeTransaction($content, $packageName, $packagePrice, $customerID)
{
ORM::get_db()->beginTransaction();
try {
$transaction = ORM::for_table('tbl_mpesa_transactions')
->where('TransID', $content->TransID)
->find_one();
if ($transaction) {
// Update existing transaction
$transaction->TransactionType = $content->TransactionType;
$transaction->TransTime = $content->TransTime;
$transaction->TransAmount = $content->TransAmount;
$transaction->BusinessShortCode = $content->BusinessShortCode;
$transaction->BillRefNumber = $content->BillRefNumber;
$transaction->OrgAccountBalance = $content->OrgAccountBalance;
$transaction->MSISDN = $content->MSISDN;
$transaction->FirstName = $content->FirstName;
$transaction->PackageName = $packageName;
$transaction->PackagePrice = $packagePrice;
$transaction->customerID = $customerID;
$transaction->transactionStatus = 'Pending';
} else {
// Create new transaction
$transaction = ORM::for_table('tbl_mpesa_transactions')->create();
$transaction->TransID = $content->TransID;
$transaction->TransactionType = $content->TransactionType;
$transaction->TransTime = $content->TransTime;
$transaction->TransAmount = $content->TransAmount;
$transaction->BusinessShortCode = $content->BusinessShortCode;
$transaction->BillRefNumber = $content->BillRefNumber;
$transaction->OrgAccountBalance = $content->OrgAccountBalance;
$transaction->MSISDN = $content->MSISDN;
$transaction->FirstName = $content->FirstName;
$transaction->PackageName = $packageName;
$transaction->PackagePrice = $packagePrice;
$transaction->customerID = $customerID;
$transaction->transactionStatus = 'Pending';
}
$transaction->save();
ORM::get_db()->commit();
return $transaction;
} catch (Exception $e) {
ORM::get_db()->rollBack();
throw $e;
}
}
function c2b_logAndNotify($message)
{
_log($message);
sendTelegram($message);
}
function c2b_handleException($message, $e)
{
$fullMessage = "$message: " . $e->getMessage() . " in " . $e->getFile() . " on line " . $e->getLine();
c2b_logAndNotify($fullMessage);
}
function c2b_updateCustomerBalance($customer, $newBalance, $amountPaid)
{
try {
$customer->balance = $newBalance;
$customer->save();
c2b_logAndNotify("Payment of KES {$amountPaid} has been added to the balance of customer {$customer->username}.");
} catch (Exception $e) {
c2b_handleException("Failed to update customer balance", $e);
}
}
function c2b_sendPaymentSuccessMessage($customer, $amountPaid, $packageName)
{
$config = c2b_config();
$message = "Dear {$customer->fullname}, your payment of KES {$amountPaid} has been received and your plan {$packageName} has been successfully activated. Thank you for choosing {$config['CompanyName']}.";
c2b_sendNotification($customer, $message);
}
function c2b_sendBalanceUpdateMessage($customer, $amountPaid, $currentBalance, $neededToActivate)
{
$config = c2b_config();
$message = "Dear {$customer->fullname}, your payment of KES {$amountPaid} has been received and added to your account balance. Your current balance is KES {$currentBalance}.";
if ($neededToActivate > 0) {
$message .= " To activate your package, you need to add KES {$neededToActivate} more to your account.";
} else {
$message .= " Your current balance is sufficient to activate your package.";
}
$message .= "\n" . $config['CompanyName'];
c2b_sendNotification($customer, $message);
}
function c2b_sendNotification($customer, $message)
{
try {
Message::sendSMS($customer->phonenumber, $message);
Message::sendWhatsapp($customer->phonenumber, $message);
} catch (Exception $e) {
c2b_handleException("Failed to send SMS/WhatsApp message", $e);
}
}
function c2b_validation()
{
header("Content-Type: application/json");
$mpesaResponse = file_get_contents('php://input');
$config = c2b_config();
$content = json_decode($mpesaResponse);
if (json_last_error() !== JSON_ERROR_NONE) {
sendTelegram("Failed to decode JSON response.");
_log("Failed to decode JSON response.");
echo json_encode(["ResultCode" => "C2B00016", "ResultDesc" => "Invalid JSON format"]);
return;
}
$BillRefNumber = $content->BillRefNumber;
$TransAmount = $content->TransAmount;
if (isset($config['mpesa_c2b_bill_ref'])) {
switch ($config['mpesa_c2b_bill_ref']) {
case 'phone':
$customer = ORM::for_table('tbl_customers')
->where('phonenumber', $content->BillRefNumber)
->find_one();
break;
case 'username':
$customer = ORM::for_table('tbl_customers')
->where('username', $content->BillRefNumber)
->find_one();
break;
case 'id':
$customer = ORM::for_table('tbl_customers')
->where('id', $content->BillRefNumber)
->find_one();
break;
default:
$customer = null;
break;
}
if (!$customer) {
sendTelegram("Validation failed: No account found for BillRefNumber: $BillRefNumber");
_log("Validation failed: No account found for BillRefNumber: $BillRefNumber");
echo json_encode(["ResultCode" => "C2B00012", "ResultDesc" => "Invalid Account Number"]);
return;
}
} else {
_log("Configuration error: mpesa_c2b_bill_ref not set.");
sendTelegram("Configuration error: mpesa_c2b_bill_ref not set.");
}
$bills = c2b_billing($customer->id);
if (!$bills) {
sendTelegram("Validation failed: No bill found for BillRefNumber: $BillRefNumber");
_log("Validation failed: No bill found for BillRefNumber: $BillRefNumber");
echo json_encode(["ResultCode" => "C2B00012", "ResultDesc" => "Invalid Bill Reference"]);
return;
}
foreach ($bills as $bill) {
}
$billAmount = $bill['price'];
if (!$config['mpesa_c2b_low_fee']) {
if ($TransAmount < $billAmount) {
sendTelegram("Validation failed: Insufficient amount. Transferred: $TransAmount, Required: $billAmount");
_log("Validation failed: Insufficient amount. Transferred: $TransAmount, Required: $billAmount");
echo json_encode(["ResultCode" => "C2B00013", "ResultDesc" => "Invalid or Insufficient Amount"]);
return;
}
}
sendTelegram("Validation successful for BillRefNumber: $BillRefNumber with amount: $TransAmount");
_log("Validation successful for BillRefNumber: $BillRefNumber with amount: $TransAmount");
echo json_encode(["ResultCode" => 0, "ResultDesc" => "Accepted"]);
}
function c2b_billing($id)
{
$d = ORM::for_table('tbl_user_recharges')
->selects([
'customer_id',
'username',
'plan_id',
'namebp',
'recharged_on',
'recharged_time',
'expiration',
'time',
'status',
'method',
'plan_type',
['tbl_user_recharges.routers', 'routers'],
['tbl_user_recharges.type', 'type'],
'admin_id',
'prepaid'
])
->select('tbl_plans.price', 'price')
->left_outer_join('tbl_plans', array('tbl_plans.id', '=', 'tbl_user_recharges.plan_id'))
->where('customer_id', $id)
->find_many();
return $d;
}
function c2b_config()
{
$result = ORM::for_table('tbl_appconfig')->find_many();
foreach ($result as $value) {
$config[$value['setting']] = $value['value'];
}
return $config;
}

View File

@ -0,0 +1,48 @@
<?php
register_menu("Clear System Cache", true, "clear_cache", 'SETTINGS', '');
function clear_cache()
{
global $ui;
_admin();
$ui->assign('_title', 'Clear Cache');
$ui->assign('_system_menu', 'settings');
$admin = Admin::_info();
$ui->assign('_admin', $admin);
// Check user type for access
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
exit;
}
$compiledCacheDir = 'ui/compiled';
$templateCacheDir = 'system/cache';
try {
// Clear the compiled cache
$files = scandir($compiledCacheDir);
foreach ($files as $file) {
if ($file !== '.' && $file !== '..' && is_file($compiledCacheDir . '/' . $file)) {
unlink($compiledCacheDir . '/' . $file);
}
}
// Clear the template cache
$templateCacheFiles = glob($templateCacheDir . '/*.{json,temp}', GLOB_BRACE);
foreach ($templateCacheFiles as $file) {
if (is_file($file)) {
unlink($file);
}
}
// Cache cleared successfully
_log('[' . ($admin['fullname'] ?? 'Unknown Admin') . ']: ' . Lang::T(' Cleared the system cache '), $admin['user_type']);
r2(U . 'dashboard', 's', Lang::T("Cache cleared successfully!"));
} catch (Exception $e) {
// Error occurred while clearing the cache
_log('[' . ($admin['fullname'] ?? 'Unknown Admin') . ']: ' . Lang::T(' Error occurred while clearing the cache: ' . $e->getMessage()), $admin['user_type']);
r2(U . 'dashboard', 'e', Lang::T("Error occurred while clearing the cache: ") . $e->getMessage());
}
}

755
system/plugin/download.php Normal file
View File

@ -0,0 +1,755 @@
<?php
include '../../config.php';
$mysqli = new mysqli($db_host, $db_user, $db_password, $db_name);
if ($mysqli->connect_error) {
die("Connection failed: " . $mysqli->connect_error);
}
// Function to get a setting value
function getSettingValue($mysqli, $setting) {
$query = $mysqli->prepare("SELECT value FROM tbl_appconfig WHERE setting = ?");
$query->bind_param("s", $setting);
$query->execute();
$result = $query->get_result();
if ($row = $result->fetch_assoc()) {
return $row['value'];
}
return '';
}
// Fetch hotspot title and description from tbl_appconfig
$hotspotTitle = getSettingValue($mysqli, 'hotspot_title');
$description = getSettingValue($mysqli, 'description');
$phone = getSettingValue($mysqli, 'phone');
$company = getSettingValue($mysqli, 'CompanyName');
// Fetch router name and router ID from tbl_appconfig
$routerName = getSettingValue($mysqli, 'router_name');
$routerId = getSettingValue($mysqli, 'router_id');
// Fetch available plans
$planQuery = "SELECT id, type, name_plan, price, validity, validity_unit FROM tbl_plans WHERE routers = ? AND type = 'Hotspot'";
$planStmt = $mysqli->prepare($planQuery);
$planStmt->bind_param("s", $routerName);
$planStmt->execute();
$planResult = $planStmt->get_result();
$htmlContent = "";
$htmlContent .= "<!DOCTYPE html>\n";
$htmlContent .= "<html lang=\"en\">\n";
$htmlContent .= "<head>\n";
$htmlContent .= " <meta charset=\"UTF-8\">\n";
$htmlContent .= " <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n";
$htmlContent .= " <title>$company</title>\n";
$htmlContent .= " <script src=\"https://cdn.tailwindcss.com\"></script>\n";
$htmlContent .= " <link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css\">\n";
$htmlContent .= " <link rel=\"stylesheet\" href=\"https://cdn.jsdelivr.net/npm/glider-js@1.7.7/glider.min.css\" />\n";
$htmlContent .= " <script src=\"https://cdn.jsdelivr.net/npm/glider-js@1.7.7/glider.min.js\"></script>\n";
$htmlContent .= " <link rel=\"preconnect\" href=\"https://cdn.jsdelivr.net\">\n";
$htmlContent .= " <link rel=\"preconnect\" href=\"https://cdnjs.cloudflare.com\" crossorigin>\n";
$htmlContent .= " <link rel=\"stylesheet\" href=\"https://rsms.me/inter/inter.css\">\n";
$htmlContent .= " <!-- <link rel=\"stylesheet\" type=\"text/css\" href=\"styles.css\"> -->\n";
$htmlContent .= "</head>\n";
$htmlContent .= "<body class=\"font-sans antialiased text-gray-900 bg-gray-900 font-inter\">\n";
$htmlContent .= " <!-- Main Content -->\n";
$htmlContent .= " <div class=\"mx-auto max-w-screen-2xl px-4 md:px-4\">\n";
$htmlContent .= " <div class=\"max-h-34 relative mx-auto mt-4 flex max-w-lg flex-1 shrink-0 items-center justify-center overflow-hidden shadow-lg rounded-lg bg-blue-100\">\n";
$htmlContent .= " <!-- overlay - start -->\n";
$htmlContent .= " <!-- <div class=\"absolute inset-0 mix-blend-multiply\"></div> -->\n";
$htmlContent .= " <!-- overlay - end -->\n";
$htmlContent .= " <!-- text start -->\n";
$htmlContent .= " <div class=\"relative flex flex-col items-center p-4 sm:max-w-xl\">\n";
$htmlContent .= " <p class=\"mb-4 text-center text-2xl font-bold text-gray-800 sm:text-xl md:mb-2 \">$company HOTSPOT LOGIN </p>\n";
$htmlContent .= " <ol class=\"text-base text-left text-gray-800 mb-1 list-decimal pl-6\">\n";
$htmlContent .= " <li>Click on your preferred package</li>\n";
$htmlContent .= " <li>Enter Mpesa No.</li>\n";
$htmlContent .= " <li>Enter pin</li>\n";
$htmlContent .= " <li>Wait to be connected</li>\n";
$htmlContent .= " </ol>\n";
$htmlContent .= " <p class=\"mb-4 text-center text-lg font-medium text-gray-700 sm:text-1xl md:mb-1 md:text-xl\"> For any enquiries contact : $phone</p>\n";
$htmlContent .= " </div>\n";
$htmlContent .= " <!-- text end -->\n";
$htmlContent .= " </div>\n";
$htmlContent .= " </div>\n";
$htmlContent .= " <div class=\"py-2 sm:py-4 lg:py-4\">\n";
$htmlContent .= " <div class=\"mx-auto max-w-screen-2xl px-4 md:px-4\">\n";
$htmlContent .= " <div class=\"mx-auto max-w-lg\">\n";
$htmlContent .= " <div class=\"flex flex-col gap-4\">\n";
$htmlContent .= " <button type=\"button\" class=\"flex items-center justify-center gap-2 rounded-lg bg-blue-500 px-8 py-3 text-center text-sm font-semibold text-white outline-none ring-blue-300 transition duration-100 hover:bg-blue-600 focus-visible:ring active:bg-blue-700 md:text-base\" onclick=\"redeemVoucher()\">\n";
$htmlContent .= " <svg class=\"w-5 h-5 mr-2\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\">\n";
$htmlContent .= " <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M12 8v13m0-13V6a2 2 0 112 2h-2zm0 0V5.5A2.5 2.5 0 109.5 8H12zm-7 4h14M5 12a2 2 0 110-4h14a2 2 0 110 4M5 12v7a2 2 0 002 2h10a2 2 0 002-2v-7\"></path>\n";
$htmlContent .= " </svg>\n";
$htmlContent .= " Click here to Redeem Voucher\n";
$htmlContent .= " </button>\n";
$htmlContent .= " </div>\n";
$htmlContent .= " </div>\n";
$htmlContent .= " </div>\n";
$htmlContent .= " </div>\n";
$htmlContent .= " <div class=\"py-2 sm:py-4 lg:py-6\">\n";
$htmlContent .= " <div class=\"mx-auto max-w-screen-2xl px-4 md:px-8\">\n";
$htmlContent .= " <div class=\"mx-auto max-w-lg grid grid-cols-2 sm:grid-cols-3 gap-1 p-1\" id=\"cards-container\">\n";
$htmlContent .= " </div>\n";
$htmlContent .= " </div>\n";
$htmlContent .= " </div>\n";
// New HTML content added
$htmlContent .= " <div class=\"container mx-auto px-4 mb-2\">\n";
$htmlContent .= " <div class=\"max-w-md mx-auto bg-white rounded-lg overflow-hidden md:max-w-lg\">\n";
$htmlContent .= " <div class=\"p-3\">\n";
$htmlContent .= " <h3 class=\"text-2xl font-semibold text-gray-900 mb-3 text-center\">Enter code to reconnect</h3>\n";
$htmlContent .= " <div class=\"mb-6\">\n";
$htmlContent .= " <label for=\"mpesaCodeInput\" class=\"block text-gray-700 text-sm font-bold mb-2\">Code or
message:</label>\n";
$htmlContent .= " <input type=\"text\" id=\"mpesaCodeInput\" name=\"mpesa_code\" placeholder=\"Enter Code or Full Message\" class=\"w-full rounded-lg border bg-gray-50 px-3 py-2 text-gray-800 outline-none ring-indigo-300 transition duration-100 focus:ring\">\n";
$htmlContent .= " <button id=\"reconnectBtn\" class=\"w-full mt-3 rounded-lg bg-blue-500 px-4 py-2 text-white font-semibold hover:bg-red-600 transition duration-100\">Reconnect</button>\n";
$htmlContent .= " </div>\n";
$htmlContent .= " </div>\n";
$htmlContent .= " <div class=\"p-1\">\n";
$htmlContent .= " <div class=\"w-full p-3\">\n";
$htmlContent .= " <div class=\"text-center\">\n";
$htmlContent .= " <h3 class=\"text-2xl text-gray-900\">Already Have an Active Package?</h3>\n";
$htmlContent .= " </div>\n";
$htmlContent .= " <form id=\"loginForm\" class=\"form\" name=\"login\" action=\"$(link-login-only)\" method=\"post\" $(if chap-id)onSubmit=\"return doLogin()\" $(endif)>\n";
$htmlContent .= " <input type=\"hidden\" name=\"dst\" value=\"$(link-orig)\" />\n";
$htmlContent .= " <input type=\"hidden\" name=\"popup\" value=\"true\" />\n";
$htmlContent .= " <div class=\"mb-4\">\n";
$htmlContent .= " <label class=\"block text-gray-700 text-sm font-bold mb-2\" for=\"username\">enter username or account number.</label>\n";
$htmlContent .= " <div>\n";
$htmlContent .= " <input id=\"usernameInput\" name=\"username\" type=\"text\" value=\"\" placeholder=\"eg. ACC123456\" class=\"w-full rounded-lg border bg-gray-50 px-3 py-2 text-gray-800 outline-none ring-indigo-300 transition duration-100 focus:ring\" />\n";
$htmlContent .= " <button id=\"submitBtn\" class=\"w-full mt-3 flex items-center justify-center gap-2 rounded-lg bg-blue-500 px-8 py-3 text-center text-sm font-semibold text-white outline-none ring-red-300 transition duration-100 hover:bg-red-600 focus-visible:ring active:bg-red-700 md:text-base\" type=\"button\" onclick=\"submitLogin()\">\n";
$htmlContent .= " Connect\n";
$htmlContent .= " </button>\n";
$htmlContent .= " </div>\n";
$htmlContent .= " </div>\n";
$htmlContent .= " <input type=\"hidden\" name=\"password\" value=\"1234\">\n";
$htmlContent .= " </form>\n";
$htmlContent .= " </div>\n";
$htmlContent .= " </div>\n";
$htmlContent .= " </div>\n";
$htmlContent .= " </div>\n";
$htmlContent .= " <div class=\"mx-auto max-w-screen-2xl px-4 md:px-8\">\n";
$htmlContent .= " <div class=\"mx-auto mb-4 max-w-lg\">\n";
$htmlContent .= " <div class=\"border-t py-4\">\n";
$htmlContent .= " <p class=\"text-xs text-red-700 text-center\">&copy; " . date("Y") . ". Powered by NestICT</p>\n";
$htmlContent .= " </div>\n";
$htmlContent .= " </div>\n";
$htmlContent .= " </div>\n";
$htmlContent .= "</body>\n";
// Add the closing script section as well, if necessary
$htmlContent .= "<script>\n";
// Add any required JavaScript here
$htmlContent .= "</script>\n";
$htmlContent .= "<script>\n";
$htmlContent .= "function fetchData() {\n";
$htmlContent .= " let domain = '" . APP_URL . "/';\n";
$htmlContent .= " let siteUrl = domain + \"/index.php?_route=plugin/hotspot_plan\";\n";
$htmlContent .= " let request = new XMLHttpRequest();\n";
$htmlContent .= " const routerName = encodeURIComponent(\"$routerName\");\n";
$htmlContent .= " const dataparams = `routername=\${routerName}`;\n";
$htmlContent .= " request.open(\"POST\", siteUrl, true);\n";
$htmlContent .= " request.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');\n";
$htmlContent .= " request.onload = () => {\n";
$htmlContent .= " if (request.readyState === XMLHttpRequest.DONE) {\n";
$htmlContent .= " if (request.status === 200) {\n";
$htmlContent .= " let fetchedData = JSON.parse(request.responseText);\n";
$htmlContent .= " populateCards(fetchedData);\n";
$htmlContent .= " } else {\n";
$htmlContent .= " console.log(`Error \${request.status}: \${request.statusText}`);\n";
$htmlContent .= " }\n";
$htmlContent .= " }\n";
$htmlContent .= " };\n";
$htmlContent .= " request.onerror = () => {\n";
$htmlContent .= " console.error(\"Network error\");\n";
$htmlContent .= " };\n";
$htmlContent .= " request.send(dataparams);\n";
$htmlContent .= "}\n";
$htmlContent .= "function populateCards(data) {\n";
$htmlContent .= " var cardsContainer = document.getElementById('cards-container');\n";
$htmlContent .= " cardsContainer.innerHTML = ''; // Clear existing content\n";
$htmlContent .= " // Sort the plans by price in ascending order\n";
$htmlContent .= " data.data.forEach(router => {\n";
$htmlContent .= " // Sort hotspot plans by price\n";
$htmlContent .= " router.plans_hotspot.sort((a, b) => parseFloat(a.price) - parseFloat(b.price));\n";
$htmlContent .= " router.plans_hotspot.forEach(item => {\n";
$htmlContent .= " var cardDiv = document.createElement('div');\n";
$htmlContent .= " cardDiv.className = 'bg-white border border-black rounded-lg shadow-md overflow-hidden transition duration-300 hover:shadow-lg flex flex-col items-center justify-between mx-auto mb-4 w-40';\n";
$htmlContent .= " cardDiv.innerHTML = `\n";
$htmlContent .= " <div class=\"bg-red-500 text-white w-full py-1\">\n";
$htmlContent .= " <h2 class=\"text-sm font-medium uppercase text-center\" style=\"font-size: clamp(0.75rem, 1.5vw, 1rem); white-space: nowrap; overflow: hidden; text-overflow: ellipsis;\">\n";
$htmlContent .= " \${item.planname}\n";
$htmlContent .= " </h2>\n";
$htmlContent .= " </div>\n";
$htmlContent .= " <div class=\"px-4 py-2 flex-grow\">\n";
$htmlContent .= " <p class=\"text-2xl font-bold text-red-600 mb-1\">\n";
$htmlContent .= " <span class=\"text-lg font-medium text-black\">\${item.currency}</span>\n";
$htmlContent .= " \${item.price}\n";
$htmlContent .= " </p>\n";
$htmlContent .= " <p class=\"text-sm text-black mb-2\">\n";
$htmlContent .= " Valid for \${item.validity} \${item.timelimit}\n";
$htmlContent .= " </p>\n";
$htmlContent .= " <hr class=\"border-black mb-2\">\n";
$htmlContent .= " </div>\n";
$htmlContent .= " <div class=\"px-4 py-2 flex-shrink-0\">\n";
$htmlContent .= " <a href=\"#\" class=\"inline-block bg-gray-900 text-white hover:bg-red-600 font-semibold py-1 px-4 rounded-lg transition duration-300 text-md\"\n";
$htmlContent .= " onclick=\"handlePhoneNumberSubmission('\${item.planId}', '\${item.routerId}'); return false;\"\n";
$htmlContent .= " data-plan-id=\"\${item.planId}\"\n";
$htmlContent .= " data-router-id=\"\${item.routerId}\">\n";
$htmlContent .= " Buy\n";
$htmlContent .= " </a>\n";
$htmlContent .= " </div>\n";
$htmlContent .= " `;\n";
$htmlContent .= " cardsContainer.appendChild(cardDiv);\n";
$htmlContent .= " });\n";
$htmlContent .= " });\n";
$htmlContent .= "}\n";
$htmlContent .= "fetchData();\n";
$htmlContent .= "</script>\n";
$htmlContent .= "<script src=\"https://cdn.jsdelivr.net/npm/sweetalert2@11\"></script>\n";
$htmlContent .= "<script>\n";
$htmlContent .= " function formatPhoneNumber(phoneNumber) {\n";
$htmlContent .= " if (phoneNumber.startsWith('+')) {\n";
$htmlContent .= " phoneNumber = phoneNumber.substring(1);\n";
$htmlContent .= " }\n";
$htmlContent .= " if (phoneNumber.startsWith('0')) {\n";
$htmlContent .= " phoneNumber = '254' + phoneNumber.substring(1);\n";
$htmlContent .= " }\n";
$htmlContent .= " if (phoneNumber.match(/^(7|1)/)) {\n";
$htmlContent .= " phoneNumber = '254' + phoneNumber;\n";
$htmlContent .= " }\n";
$htmlContent .= " return phoneNumber;\n";
$htmlContent .= " }\n";
$htmlContent .= "\n";
$htmlContent .= " function setCookie(name, value, days) {\n";
$htmlContent .= " var expires = \"\";\n";
$htmlContent .= " if (days) {\n";
$htmlContent .= " var date = new Date();\n";
$htmlContent .= " date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));\n";
$htmlContent .= " expires = \"; expires=\" + date.toUTCString();\n";
$htmlContent .= " }\n";
$htmlContent .= " document.cookie = name + \"=\" + (value || \"\") + expires + \"; path=/\";\n";
$htmlContent .= " }\n";
$htmlContent .= "\n";
$htmlContent .= " function getCookie(name) {\n";
$htmlContent .= " var nameEQ = name + \"=\";\n";
$htmlContent .= " var ca = document.cookie.split(';');\n";
$htmlContent .= " for (var i = 0; i < ca.length; i++) {\n";
$htmlContent .= " var c = ca[i];\n";
$htmlContent .= " while (c.charAt(0) == ' ') c = c.substring(1, c.length);\n";
$htmlContent .= " if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length);\n";
$htmlContent .= " }\n";
$htmlContent .= " return null;\n";
$htmlContent .= " }\n";
$htmlContent .= "\n";
$htmlContent .= " function generateAccountId() {\n";
$htmlContent .= " return 'ACN' + Math.floor(10000 + Math.random() * 90000); // Generate a random number between 10000 and 99999\n";
$htmlContent .= " }\n";
$htmlContent .= "\n";
$htmlContent .= "var loginTimeout; // Variable to store the timeout ID\n";
$htmlContent .= "function handlePhoneNumberSubmission(planId, routerId, price) {\n";
$htmlContent .= ' var msg = "You are about to pay Kshs: ' . $item['price'] . '. Enter phone number below and click pay now to initialize payment";' . "\n";
$htmlContent .= " const regexp = /\\\${([^{}]+)}/g;\n";
$htmlContent .= " let result = msg.replace(regexp, function(ignore, key) {\n";
$htmlContent .= " return eval(key);\n";
$htmlContent .= " });\n";
$htmlContent .= " swal.fire({\n";
$htmlContent .= " title: 'Enter Your Number',\n";
$htmlContent .= " input: 'number',\n";
$htmlContent .= " inputAttributes: {\n";
$htmlContent .= " required: 'true'\n";
$htmlContent .= " },\n";
$htmlContent .= " inputValidator: function(value) {\n";
$htmlContent .= " if (value === '') {\n";
$htmlContent .= " return 'You need to write your phonenumber!';\n";
$htmlContent .= " }\n";
$htmlContent .= " },\n";
$htmlContent .= " text: result,\n";
$htmlContent .= " showCancelButton: true,\n";
$htmlContent .= " confirmButtonColor: '#3085d6',\n";
$htmlContent .= " cancelButtonColor: '#d33',\n";
$htmlContent .= " confirmButtonText: 'Pay Now',\n";
$htmlContent .= " showLoaderOnConfirm: true,\n";
$htmlContent .= " preConfirm: (phoneNumber) => {\n";
$htmlContent .= " var formattedPhoneNumber = formatPhoneNumber(phoneNumber);\n";
$htmlContent .= " var accountId = getCookie('accountId');\n";
$htmlContent .= " if (!accountId) {\n";
$htmlContent .= " accountId = generateAccountId(); // Generate a new account ID\n";
$htmlContent .= " setCookie('accountId', accountId, 7); // Set account ID as a cookie\n";
$htmlContent .= " }\n";
$htmlContent .= " document.getElementById('usernameInput').value = accountId; // Use account ID as the new username\n";
$htmlContent .= " console.log(\"Phone number for autofill:\", formattedPhoneNumber);\n";
$htmlContent .= "\n";
$htmlContent .= " return fetch('" . APP_URL . "/index.php?_route=plugin/CreateHotspotuser&type=grant', {\n";
$htmlContent .= " method: 'POST',\n";
$htmlContent .= " headers: {'Content-Type': 'application/json'},\n";
$htmlContent .= " body: JSON.stringify({phone_number: formattedPhoneNumber, plan_id: planId, router_id: routerId, account_id: accountId}),\n";
$htmlContent .= " })\n";
$htmlContent .= " .then(response => {\n";
$htmlContent .= " if (!response.ok) throw new Error('Network response was not ok');\n";
$htmlContent .= " return response.json();\n";
$htmlContent .= " })\n";
$htmlContent .= " .then(data => {\n";
$htmlContent .= " if (data.status === 'error') throw new Error(data.message);\n";
$htmlContent .= " Swal.fire({\n";
$htmlContent .= " icon: 'info',\n";
$htmlContent .= " title: 'Processing..',\n";
$htmlContent .= " html: `A payment request has been sent to your phone. Please wait while we process your payment.`,\n";
$htmlContent .= " showConfirmButton: false,\n";
$htmlContent .= " allowOutsideClick: false,\n";
$htmlContent .= " didOpen: () => {\n";
$htmlContent .= " Swal.showLoading();\n";
$htmlContent .= " checkPaymentStatus(formattedPhoneNumber);\n";
$htmlContent .= " }\n";
$htmlContent .= " });\n";
$htmlContent .= " return formattedPhoneNumber;\n";
$htmlContent .= " })\n";
$htmlContent .= " .catch(error => {\n";
$htmlContent .= " Swal.fire({\n";
$htmlContent .= " icon: 'error',\n";
$htmlContent .= " title: 'Oops...',\n";
$htmlContent .= " text: error.message,\n";
$htmlContent .= " });\n";
$htmlContent .= " });\n";
$htmlContent .= " },\n";
$htmlContent .= " allowOutsideClick: () => !Swal.isLoading()\n";
$htmlContent .= " });\n";
$htmlContent .= "}\n";
$htmlContent .= "\n";
$htmlContent .= "function checkPaymentStatus(phoneNumber) {\n";
$htmlContent .= " let checkInterval = setInterval(() => {\n";
$htmlContent .= " $.ajax({\n";
$htmlContent .= " url: '" . APP_URL . "/index.php?_route=plugin/CreateHotspotuser&type=verify',\n";
$htmlContent .= " method: 'POST',\n";
$htmlContent .= " data: JSON.stringify({account_id: document.getElementById('usernameInput').value}),\n";
$htmlContent .= " contentType: 'application/json',\n";
$htmlContent .= " dataType: 'json',\n";
$htmlContent .= " success: function(data) {\n";
$htmlContent .= " console.log('Raw Response:', data); // Debugging\n";
$htmlContent .= " if (data.Resultcode === '3') { // Success\n";
$htmlContent .= " clearInterval(checkInterval);\n";
$htmlContent .= " Swal.fire({\n";
$htmlContent .= " icon: 'success',\n";
$htmlContent .= " title: 'Payment Successful',\n";
$htmlContent .= " text: data.Message,\n";
$htmlContent .= " showConfirmButton: false\n";
$htmlContent .= " });\n";
$htmlContent .= " if (loginTimeout) {\n";
$htmlContent .= " clearTimeout(loginTimeout);\n";
$htmlContent .= " }\n";
$htmlContent .= " loginTimeout = setTimeout(function() {\n";
$htmlContent .= " document.getElementById('loginForm').submit();\n";
$htmlContent .= " }, 2000);\n";
$htmlContent .= " } else if (data.Resultcode === '2') { // Error\n";
$htmlContent .= " clearInterval(checkInterval);\n";
$htmlContent .= " let iconType = data.Status === 'danger' ? 'error' : data.Status;\n";
$htmlContent .= " Swal.fire({\n";
$htmlContent .= " icon: iconType,\n";
$htmlContent .= " title: 'Payment Issue',\n";
$htmlContent .= " text: data.Message,\n";
$htmlContent .= " });\n";
$htmlContent .= " } else if (data.Resultcode === '1') { // Primary\n";
$htmlContent .= " // Continue checking\n";
$htmlContent .= " }\n";
$htmlContent .= " },\n";
$htmlContent .= " error: function(xhr, textStatus, errorThrown) {\n";
$htmlContent .= " console.log('Error: ' + errorThrown);\n";
$htmlContent .= " }\n";
$htmlContent .= " });\n";
$htmlContent .= " }, 2000);\n";
$htmlContent .= "\n";
$htmlContent .= " setTimeout(() => {\n";
$htmlContent .= " clearInterval(checkInterval);\n";
$htmlContent .= " Swal.fire({\n";
$htmlContent .= " icon: 'warning',\n";
$htmlContent .= " title: 'Timeout',\n";
$htmlContent .= " text: 'Payment verification timed out. Please try again.',\n";
$htmlContent .= " });\n";
$htmlContent .= " }, 600000); // Stop checking after 60 seconds\n";
$htmlContent .= "}\n";
$htmlContent .= "</script>\n";
$htmlContent .= "</script>\n";
$htmlContent .= "<script>\n";
$htmlContent .= "var loginTimeout; // Variable to store the timeout ID\n";
$htmlContent .= "function redeemVoucher() {\n";
$htmlContent .= " Swal.fire({\n";
$htmlContent .= " title: 'Redeem Voucher',\n";
$htmlContent .= " input: 'text',\n";
$htmlContent .= " inputPlaceholder: 'Enter voucher code',\n";
$htmlContent .= " inputValidator: function(value) {\n";
$htmlContent .= " if (!value) {\n";
$htmlContent .= " return 'You need to enter a voucher code!';\n";
$htmlContent .= " }\n";
$htmlContent .= " },\n";
$htmlContent .= " confirmButtonColor: '#3085d6',\n";
$htmlContent .= " cancelButtonColor: '#d33',\n";
$htmlContent .= " confirmButtonText: 'Redeem',\n";
$htmlContent .= " showLoaderOnConfirm: true,\n";
$htmlContent .= " preConfirm: (voucherCode) => {\n";
$htmlContent .= " var accountId = voucherCode;\n";
$htmlContent .= " if (!accountId) {\n";
$htmlContent .= " accountId = voucherCode;\n";
$htmlContent .= " setCookie('accountId', accountId, 7);\n";
$htmlContent .= " }\n";
$htmlContent .= " return fetch('" . APP_URL . "/index.php?_route=plugin/CreateHotspotuser&type=voucher', {\n";
$htmlContent .= " method: 'POST',\n";
$htmlContent .= " headers: {'Content-Type': 'application/json'},\n";
$htmlContent .= " body: JSON.stringify({voucher_code: voucherCode, account_id: accountId}),\n";
$htmlContent .= " })\n";
$htmlContent .= " .then(response => {\n";
$htmlContent .= " if (!response.ok) throw new Error('Network response was not ok');\n";
$htmlContent .= " return response.json();\n";
$htmlContent .= " })\n";
$htmlContent .= " .then(data => {\n";
$htmlContent .= " if (data.status === 'error') throw new Error(data.message);\n";
$htmlContent .= " return data;\n";
$htmlContent .= " });\n";
$htmlContent .= " },\n";
$htmlContent .= " allowOutsideClick: () => !Swal.isLoading()\n";
$htmlContent .= " }).then((result) => {\n";
$htmlContent .= " if (result.isConfirmed) {\n";
$htmlContent .= " Swal.fire({\n";
$htmlContent .= " icon: 'success',\n";
$htmlContent .= " title: 'Voucher Redeemed',\n";
$htmlContent .= " text: result.value.message,\n";
$htmlContent .= " showConfirmButton: false,\n";
$htmlContent .= " allowOutsideClick: false,\n";
$htmlContent .= " didOpen: () => {\n";
$htmlContent .= " Swal.showLoading();\n";
$htmlContent .= " var username = result.value.username;\n";
$htmlContent .= " console.log('Received username from server:', username);\n";
$htmlContent .= " var usernameInput = document.querySelector('input[name=\"username\"]');\n";
$htmlContent .= " if (usernameInput) {\n";
$htmlContent .= " console.log('Found username input element.');\n";
$htmlContent .= " usernameInput.value = username;\n";
$htmlContent .= " loginTimeout = setTimeout(function() {\n";
$htmlContent .= " var loginForm = document.getElementById('loginForm');\n";
$htmlContent .= " if (loginForm) {\n";
$htmlContent .= " loginForm.submit();\n";
$htmlContent .= " } else {\n";
$htmlContent .= " console.error('Login form not found.');\n";
$htmlContent .= " Swal.fire({\n";
$htmlContent .= " icon: 'error',\n";
$htmlContent .= " title: 'Error',\n";
$htmlContent .= " text: 'Login form not found. Please try again.',\n";
$htmlContent .= " });\n";
$htmlContent .= " }\n";
$htmlContent .= " }, 2000);\n";
$htmlContent .= " } else {\n";
$htmlContent .= " console.error('Username input element not found.');\n";
$htmlContent .= " Swal.fire({\n";
$htmlContent .= " icon: 'error',\n";
$htmlContent .= " title: 'Error',\n";
$htmlContent .= " text: 'Username input not found. Please try again.',\n";
$htmlContent .= " });\n";
$htmlContent .= " }\n";
$htmlContent .= " }\n";
$htmlContent .= " });\n";
$htmlContent .= " }\n";
$htmlContent .= " }).catch(error => {\n";
$htmlContent .= " Swal.fire({\n";
$htmlContent .= " icon: 'error',\n";
$htmlContent .= " title: 'Oops...',\n";
$htmlContent .= " text: error.message,\n";
$htmlContent .= " });\n";
$htmlContent .= " });\n";
$htmlContent .= "}\n";
$htmlContent .= "</script>\n";
$htmlContent .= "<script>\n";
$htmlContent .= "var loginTimeout; // Variable to store the timeout ID\n";
$htmlContent .= "document.addEventListener('DOMContentLoaded', function() {\n";
$htmlContent .= " document.getElementById('reconnectBtn').addEventListener('click', function() {\n";
$htmlContent .= " var mpesaCode = document.getElementById('mpesaCodeInput').value;\n";
$htmlContent .= " var firstWord = mpesaCode.split(' ')[0]; // Get the first word in the MPESA code\n";
$htmlContent .= " fetch('" . APP_URL . "/index.php?_route=plugin/CreateHotspotuser&type=reconnect', {\n";
$htmlContent .= " method: 'POST',\n";
$htmlContent .= " headers: {'Content-Type': 'application/json'},\n";
$htmlContent .= " body: JSON.stringify({mpesa_code: firstWord}),\n"; // Sending only the first word of the MPESA code\n";
$htmlContent .= " })\n";
$htmlContent .= " .then(response => response.json())\n";
$htmlContent .= " .then(data => {\n";
$htmlContent .= " if (data.Status === 'success') {\n";
$htmlContent .= " Swal.fire({\n";
$htmlContent .= " icon: 'success',\n";
$htmlContent .= " title: 'Reconnection Successful',\n";
$htmlContent .= " text: data.Message,\n";
$htmlContent .= " showConfirmButton: false,\n";
$htmlContent .= " allowOutsideClick: false,\n";
$htmlContent .= " didOpen: () => {\n";
$htmlContent .= " Swal.showLoading();\n";
$htmlContent .= " var username = data.username; // Replace with actual JSON field name\n";
$htmlContent .= " console.log('Received username from server:', username);\n";
$htmlContent .= " var usernameInput = document.querySelector('input[name=\"username\"]');\n";
$htmlContent .= " if (usernameInput) {\n";
$htmlContent .= " console.log('Found username input element.');\n";
$htmlContent .= " usernameInput.value = username;\n";
$htmlContent .= " loginTimeout = setTimeout(function() {\n";
$htmlContent .= " var loginForm = document.getElementById('loginForm');\n";
$htmlContent .= " if (loginForm) {\n";
$htmlContent .= " loginForm.submit();\n";
$htmlContent .= " } else {\n";
$htmlContent .= " console.error('Login form not found.');\n";
$htmlContent .= " Swal.fire({\n";
$htmlContent .= " icon: 'error',\n";
$htmlContent .= " title: 'Error',\n";
$htmlContent .= " text: 'Login form not found. Please try again.',\n";
$htmlContent .= " });\n";
$htmlContent .= " }\n";
$htmlContent .= " }, 2000);\n";
$htmlContent .= " } else {\n";
$htmlContent .= " console.error('Username input element not found.');\n";
$htmlContent .= " Swal.fire({\n";
$htmlContent .= " icon: 'error',\n";
$htmlContent .= " title: 'Error',\n";
$htmlContent .= " text: 'Username input not found. Please try again.',\n";
$htmlContent .= " });\n";
$htmlContent .= " }\n";
$htmlContent .= " }\n";
$htmlContent .= " });\n";
$htmlContent .= " } else {\n";
$htmlContent .= " Swal.fire({\n";
$htmlContent .= " icon: 'error',\n";
$htmlContent .= " title: 'Reconnection Failed',\n";
$htmlContent .= " text: data.Message,\n";
$htmlContent .= " });\n";
$htmlContent .= " }\n";
$htmlContent .= " })\n";
$htmlContent .= " .catch(error => {\n";
$htmlContent .= " console.error('Error:', error);\n";
$htmlContent .= " Swal.fire({\n";
$htmlContent .= " icon: 'error',\n";
$htmlContent .= " title: 'Error',\n";
$htmlContent .= " text: 'Failed to reconnect. Please try again later.',\n";
$htmlContent .= " });\n";
$htmlContent .= " });\n";
$htmlContent .= " });\n";
$htmlContent .= "});\n";
$htmlContent .= "</script>\n";
$htmlContent .= "<script src=\"https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js\"></script>\n";
$htmlContent .= "<script>\n";
$htmlContent .= "document.addEventListener('DOMContentLoaded', function() {\n";
$htmlContent .= " // Ensure the button is correctly targeted by its ID.\n";
$htmlContent .= " var submitBtn = document.getElementById('submitBtn');\n";
$htmlContent .= " \n";
$htmlContent .= " // Add a click event listener to the \"Login Now\" button.\n";
$htmlContent .= " submitBtn.addEventListener('click', function(event) {\n";
$htmlContent .= " event.preventDefault(); // Prevent the default button action.\n";
$htmlContent .= " \n";
$htmlContent .= " // Optional: Log to console for debugging purposes.\n";
$htmlContent .= " console.log(\"Login Now button clicked.\");\n";
$htmlContent .= " \n";
$htmlContent .= " // Direct form submission, bypassing the doLogin function for simplicity.\n";
$htmlContent .= " var form = document.getElementById('loginForm');\n";
$htmlContent .= " form.submit(); // Submit the form directly.\n";
$htmlContent .= " });\n";
$htmlContent .= "});\n";
$htmlContent .= "</script>\n";
$htmlContent .= "</html>\n";
$planStmt->close();
$mysqli->close();
// Check if the download parameter is set
if (isset($_GET['download']) && $_GET['download'] == '1') {
// Prepare the HTML content for download
// ... build your HTML content ...
// Specify the filename for the download
$filename = "login.html";
// Send headers to force download
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.basename($filename));
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . strlen($htmlContent));
// Output the content
echo $htmlContent;
// Prevent any further output
exit;
}
// Regular page content goes here
// ... HTML and PHP code to display the page ...

12
system/plugin/error_log Normal file
View File

@ -0,0 +1,12 @@
[06-Jul-2024 15:05:25 UTC] PHP Fatal error: Uncaught Error: Undefined constant "request" in /home/codevibe/kejos.codevibeisp.co.ke/system/plugin/download.php:154
Stack trace:
#0 {main}
thrown in /home/codevibe/kejos.codevibeisp.co.ke/system/plugin/download.php on line 154
[06-Jul-2024 15:05:28 UTC] PHP Fatal error: Uncaught Error: Undefined constant "request" in /home/codevibe/kejos.codevibeisp.co.ke/system/plugin/download.php:154
Stack trace:
#0 {main}
thrown in /home/codevibe/kejos.codevibeisp.co.ke/system/plugin/download.php on line 154
[06-Jul-2024 17:35:47 UTC] PHP Fatal error: Uncaught Error: Undefined constant "request" in /home/codevibe/kejos.codevibeisp.co.ke/system/plugin/download.php:154
Stack trace:
#0 {main}
thrown in /home/codevibe/kejos.codevibeisp.co.ke/system/plugin/download.php on line 154

View File

@ -0,0 +1,79 @@
<?php
// Assuming you have ORM or database access configured correctly
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['routername'])) {
// Example of fetching data (simplified)
$routerName = $_POST['routername'];
// Fetch routers and plans from database (replace with your actual ORM or database queries)
$routers = ORM::for_table('tbl_routers')->find_many();
$plans_hotspot = ORM::for_table('tbl_plans')->where('type', 'Hotspot')->find_many();
// Fetch bandwidth limits for all plans
$bandwidth_limits = ORM::for_table('tbl_bandwidth')->find_many();
$bandwidth_map = [];
foreach ($bandwidth_limits as $limit) {
$bandwidth_map[$limit['plan_id']] = [
'downlimit' => $limit['rate_down'],
'uplimit' => $limit['rate_up'],
];
}
// Fetch currency from tbl_appconfig using the correct column names
$currency_config = ORM::for_table('tbl_appconfig')->where('setting', 'currency_code')->find_one();
$currency = $currency_config ? $currency_config->value : 'Ksh'; // Default to 'Ksh' if not found
// Initialize empty data array to store router-specific plans
$data = [];
// Process each router to filter and collect hotspot plans
foreach ($routers as $router) {
if ($router['name'] === $routerName) { // Check if router name matches POSTed routername
$routerData = [
'name' => $router['name'],
'router_id' => $router['id'],
'description' => $router['description'],
'plans_hotspot' => [],
];
// Filter and collect hotspot plans associated with the router
foreach ($plans_hotspot as $plan) {
if ($router['name'] == $plan['routers']) {
$plan_id = $plan['id'];
$bandwidth_data = isset($bandwidth_map[$plan_id]) ? $bandwidth_map[$plan_id] : [];
// Construct payment link using $_url
$paymentlink = "https://codevibeisp.co.ke/index.php?_route=plugin/hotspot_pay&routerName={$router['name']}&planId={$plan['id']}&routerId={$router['id']}";
// Prepare plan data to be sent in JSON response
$routerData['plans_hotspot'][] = [
'plantype' => $plan['type'],
'planname' => $plan['name_plan'],
'currency' => $currency,
'price' => $plan['price'],
'validity' => $plan['validity'],
'device' => $plan['shared_users'],
'datalimit' => $plan['data_limit'],
'timelimit' => $plan['validity_unit'] ?? null,
'downlimit' => $bandwidth_data['downlimit'] ?? null,
'uplimit' => $bandwidth_data['uplimit'] ?? null,
'paymentlink' => $paymentlink,
'planId' => $plan['id'],
'routerName' => $router['name'],
'routerId' => $router['id']
];
}
}
// Add router data to $data array
$data[] = $routerData;
}
}
// Respond with JSON data
// header('Content-Type: application/json');
// header('Access-Control-Allow-Origin: *'); // Adjust this based on your CORS requirements
echo json_encode(['data' => $data], JSON_PRETTY_PRINT);
exit();
}
?>

View File

@ -0,0 +1,229 @@
<?php
$conn = new PDO("mysql:host=$db_host;dbname=$db_name", $db_user, $db_password);
function hotspot_settings() {
global $ui, $conn;
_admin();
$admin = Admin::_info();
$ui->assign('_title', 'Hotspot Dashboard');
$ui->assign('_admin', $admin);
// Check if form is submitted
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// Update Hotspot Title
$newHotspotTitle = isset($_POST['hotspot_title']) ? trim($_POST['hotspot_title']) : '';
if (!empty($newHotspotTitle)) {
$updateStmt = $conn->prepare("UPDATE tbl_appconfig SET value = ? WHERE setting = 'hotspot_title'");
$updateStmt->execute([$newHotspotTitle]);
}
// Add similar logic for FAQ fields here
// FAQ Headline 1 Posting To Database
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$newFaqHeadline1 = isset($_POST['frequently_asked_questions_headline1']) ? trim($_POST['frequently_asked_questions_headline1']) : '';
if (!empty($newFaqHeadline1)) {
$updateFaqStmt1 = $conn->prepare("UPDATE tbl_appconfig SET value = ? WHERE setting = 'frequently_asked_questions_headline1'");
$updateFaqStmt1->execute([$newFaqHeadline1]);
}
}
// FAQ Headline 2 Posting To Database
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$newFaqHeadline1 = isset($_POST['frequently_asked_questions_headline2']) ? trim($_POST['frequently_asked_questions_headline2']) : '';
if (!empty($newFaqHeadline1)) {
$updateFaqStmt1 = $conn->prepare("UPDATE tbl_appconfig SET value = ? WHERE setting = 'frequently_asked_questions_headline2'");
$updateFaqStmt1->execute([$newFaqHeadline1]);
}
}
// FAQ Headline 3 Posting To Database
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$newFaqHeadline1 = isset($_POST['frequently_asked_questions_headline3']) ? trim($_POST['frequently_asked_questions_headline3']) : '';
if (!empty($newFaqHeadline1)) {
$updateFaqStmt1 = $conn->prepare("UPDATE tbl_appconfig SET value = ? WHERE setting = 'frequently_asked_questions_headline3'");
$updateFaqStmt1->execute([$newFaqHeadline1]);
}
}
// FAQ Answer 1 Posting To Database
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$newFaqHeadline1 = isset($_POST['frequently_asked_questions_answer1']) ? trim($_POST['frequently_asked_questions_answer1']) : '';
if (!empty($newFaqHeadline1)) {
$updateFaqStmt1 = $conn->prepare("UPDATE tbl_appconfig SET value = ? WHERE setting = 'frequently_asked_questions_answer1'");
$updateFaqStmt1->execute([$newFaqHeadline1]);
}
}
// FAQ Answer 2 Posting To Database
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$newFaqHeadline1 = isset($_POST['frequently_asked_questions_answer2']) ? trim($_POST['frequently_asked_questions_answer2']) : '';
if (!empty($newFaqHeadline1)) {
$updateFaqStmt1 = $conn->prepare("UPDATE tbl_appconfig SET value = ? WHERE setting = 'frequently_asked_questions_answer2'");
$updateFaqStmt1->execute([$newFaqHeadline1]);
}
}
// FAQ Answer 3 Posting To Database
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$newFaqHeadline1 = isset($_POST['frequently_asked_questions_answer3']) ? trim($_POST['frequently_asked_questions_answer3']) : '';
if (!empty($newFaqHeadline1)) {
$updateFaqStmt1 = $conn->prepare("UPDATE tbl_appconfig SET value = ? WHERE setting = 'frequently_asked_questions_answer3'");
$updateFaqStmt1->execute([$newFaqHeadline1]);
}
}
// FAQ Description Posting To Database
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$newFaqHeadline1 = isset($_POST['description']) ? trim($_POST['description']) : '';
if (!empty($newFaqHeadline1)) {
$updateFaqStmt1 = $conn->prepare("UPDATE tbl_appconfig SET value = ? WHERE setting = 'description'");
$updateFaqStmt1->execute([$newFaqHeadline1]);
}
}
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// Get router name from user input
$routerName = isset($_POST['router_name']) ? trim($_POST['router_name']) : '';
if (!empty($routerName)) {
// Fetch the router ID based on the router name
$routerStmt = $conn->prepare("SELECT id FROM tbl_routers WHERE name = :router_name");
$routerStmt->execute(['router_name' => $routerName]);
$router = $routerStmt->fetch(PDO::FETCH_ASSOC);
if ($router) {
// Update router_id in tbl_appconfig
$updateRouterIdStmt = $conn->prepare("UPDATE tbl_appconfig SET value = :router_id WHERE setting = 'router_id'");
$updateRouterIdStmt->execute(['router_id' => $router['id']]);
// Update router_name in tbl_appconfig
$updateRouterNameStmt = $conn->prepare("UPDATE tbl_appconfig SET value = :router_name WHERE setting = 'router_name'");
$updateRouterNameStmt->execute(['router_name' => $routerName]);
} else {
// Handle the case where no matching router is found
// For example, you can set an error message or take any other appropriate action
}
}
// Other form handling code (if any)
}
// Redirect with a success message
r2(U . "plugin/hotspot_settings", 's', "Settings Saved");
}
// Fetch the current hotspot title from the database
$stmt = $conn->prepare("SELECT value FROM tbl_appconfig WHERE setting = 'hotspot_title'");
$stmt->execute();
$result = $stmt->fetch(PDO::FETCH_ASSOC);
$hotspotTitle = $result ? $result['value'] : '';
// Assign the fetched title to the template
$ui->assign('hotspot_title', $hotspotTitle);
// Fetch the current faq headline 1 from the database
$stmt = $conn->prepare("SELECT value FROM tbl_appconfig WHERE setting = 'frequently_asked_questions_headline1'");
$stmt->execute();
$result = $stmt->fetch(PDO::FETCH_ASSOC);
$headline1 = $result ? $result['value'] : '';
// Assign the fetched title to the template
$ui->assign('frequently_asked_questions_headline1', $headline1);
// Fetch the current faq headline 2 from the database
$stmt = $conn->prepare("SELECT value FROM tbl_appconfig WHERE setting = 'frequently_asked_questions_headline2'");
$stmt->execute();
$result = $stmt->fetch(PDO::FETCH_ASSOC);
$headline2 = $result ? $result['value'] : '';
// Assign the fetched title to the template
$ui->assign('frequently_asked_questions_headline2', $headline2);
// Fetch the current faq headline 3 from the database
$stmt = $conn->prepare("SELECT value FROM tbl_appconfig WHERE setting = 'frequently_asked_questions_headline3'");
$stmt->execute();
$result = $stmt->fetch(PDO::FETCH_ASSOC);
$headline3 = $result ? $result['value'] : '';
// Assign the fetched title to the template
$ui->assign('frequently_asked_questions_headline3', $headline3);
// Fetch the current faq Answer1 from the database
$stmt = $conn->prepare("SELECT value FROM tbl_appconfig WHERE setting = 'frequently_asked_questions_answer1'");
$stmt->execute();
$result = $stmt->fetch(PDO::FETCH_ASSOC);
$answer1 = $result ? $result['value'] : '';
// Assign the fetched title to the template
$ui->assign('frequently_asked_questions_answer1', $answer1);
// Fetch the current faq Answer2 from the database
$stmt = $conn->prepare("SELECT value FROM tbl_appconfig WHERE setting = 'frequently_asked_questions_answer2'");
$stmt->execute();
$result = $stmt->fetch(PDO::FETCH_ASSOC);
$answer2 = $result ? $result['value'] : '';
// Assign the fetched title to the template
$ui->assign('frequently_asked_questions_answer2', $answer2);
// Fetch the current faq Answer 3 from the database
$stmt = $conn->prepare("SELECT value FROM tbl_appconfig WHERE setting = 'frequently_asked_questions_answer3'");
$stmt->execute();
$result = $stmt->fetch(PDO::FETCH_ASSOC);
$answer3 = $result ? $result['value'] : '';
// Assign the fetched title to the template
$ui->assign('frequently_asked_questions_answer3', $answer3);
// Fetch the current faq description from the database
$stmt = $conn->prepare("SELECT value FROM tbl_appconfig WHERE setting = 'description'");
$stmt->execute();
$result = $stmt->fetch(PDO::FETCH_ASSOC);
$description = $result ? $result['value'] : '';
// Assign the fetched title to the template
$ui->assign('description', $description);
/// Fetch the current router name from the database for display in the form
$routerIdStmt = $conn->prepare("SELECT value FROM tbl_appconfig WHERE setting = 'router_id'");
$routerIdStmt->execute();
$routerIdResult = $routerIdStmt->fetch(PDO::FETCH_ASSOC);
if ($routerIdResult) {
$routerStmt = $conn->prepare("SELECT name FROM tbl_routers WHERE id = :router_id");
$routerStmt->execute(['router_id' => $routerIdResult['value']]);
$router = $routerStmt->fetch(PDO::FETCH_ASSOC);
if ($router) {
$ui->assign('router_name', $router['name']);
}
}
// Render the template
$ui->display('hotspot_settings.tpl');
}

BIN
system/plugin/index.html Normal file

Binary file not shown.

View File

@ -0,0 +1,137 @@
<?php
function initiatePaybillPayment()
{
// Ensure POST variables are set and sanitize input
$username = isset($_POST['username']) ? filter_var($_POST['username'], FILTER_SANITIZE_STRING) : null;
$phone = isset($_POST['phone']) ? filter_var($_POST['phone'], FILTER_SANITIZE_STRING) : null;
if (!$username || !$phone) {
echo "<script>toastr.error('Invalid input data');</script>";
return;
}
// Normalize phone number
$phone = preg_replace(['/^\+/', '/^0/', '/^7/', '/^1/'], ['', '254', '2547', '2541'], $phone);
// Retrieve bank details from the database
$bankaccount = ORM::for_table('tbl_appconfig')->where('setting', 'PaybillAcc')->find_one();
$bankname = ORM::for_table('tbl_appconfig')->where('setting', 'PaybillName')->find_one();
$bankaccount = $bankaccount ? $bankaccount->value : null;
$bankname = $bankname ? $bankname->value : null;
if (!$bankaccount || !$bankname) {
echo "<script>toastr.error('Could not complete the payment req, please contact admin');</script>";
return;
}
// Check for existing user details
$CheckId = ORM::for_table('tbl_customers')->where('username', $username)->order_by_desc('id')->find_one();
$CheckUser = ORM::for_table('tbl_customers')->where('phonenumber', $phone)->find_many();
$UserId = $CheckId ? $CheckId->id : null;
if ($CheckUser) {
ORM::for_table('tbl_customers')->where('phonenumber', $phone)->where_not_equal('id', $UserId)->delete_many();
}
// Retrieve payment gateway record
$PaymentGatewayRecord = ORM::for_table('tbl_payment_gateway')
->where('username', $username)
->where('status', 1)
->order_by_desc('id')
->find_one();
if (!$PaymentGatewayRecord) {
echo "<script>toastr.error('Could not complete the payment req, please contact administrator');</script>";
return;
}
// Update user phone number
$ThisUser = ORM::for_table('tbl_customers')->where('username', $username)->order_by_desc('id')->find_one();
if ($ThisUser) {
$ThisUser->phonenumber = $phone;
$ThisUser->save();
}
$amount = $PaymentGatewayRecord->price;
// Safaricom API credentials
$consumerKey = 'YOUR_CONSUMER_KEY';
$consumerSecret = 'YOUR_CONSUMER_SECRET';
// Get access token
$access_token_url = 'https://api.safaricom.co.ke/oauth/v1/generate?grant_type=client_credentials';
$curl = curl_init($access_token_url);
curl_setopt($curl, CURLOPT_HTTPHEADER, ['Content-Type:application/json; charset=utf8']);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($curl, CURLOPT_USERPWD, "$consumerKey:$consumerSecret");
$result = curl_exec($curl);
$status = curl_getinfo($curl, CURLINFO_HTTP_CODE);
curl_close($curl);
if ($status !== 200) {
echo "<script>toastr.error('Failed to get access token');</script>";
return;
}
$result = json_decode($result);
$access_token = $result->access_token;
// Initiate Paybill payment
$paybill_url = 'https://api.safaricom.co.ke/mpesa/stkpush/v1/processrequest';
$Timestamp = date("YmdHis");
$BusinessShortCode = 'YOUR_BUSINESS_SHORTCODE';
$Passkey = 'YOUR_PASSKEY';
$Password = base64_encode($BusinessShortCode . $Passkey . $Timestamp);
$CallBackURL = U . 'callback/PaybillCallback';
$curl_post_data = [
'BusinessShortCode' => $BusinessShortCode,
'Password' => $Password,
'Timestamp' => $Timestamp,
'TransactionType' => 'CustomerPayBillOnline',
'Amount' => $amount,
'PartyA' => $phone,
'PartyB' => $BusinessShortCode,
'PhoneNumber' => $phone,
'CallBackURL' => $CallBackURL,
'AccountReference' => $bankaccount,
'TransactionDesc' => 'PayBill Payment'
];
$curl = curl_init($paybill_url);
curl_setopt($curl, CURLOPT_HTTPHEADER, ['Content-Type:application/json', 'Authorization:Bearer ' . $access_token]);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($curl_post_data));
$curl_response = curl_exec($curl);
curl_close($curl);
$mpesaResponse = json_decode($curl_response);
$responseCode = $mpesaResponse->ResponseCode;
$resultDesc = $mpesaResponse->resultDesc;
$MerchantRequestID = $mpesaResponse->MerchantRequestID;
$CheckoutRequestID = $mpesaResponse->CheckoutRequestID;
if ($responseCode == "0") {
date_default_timezone_set('Africa/Nairobi');
$now = date("Y-m-d H:i:s");
$PaymentGatewayRecord->pg_paid_response = $resultDesc;
$PaymentGatewayRecord->username = $username;
$PaymentGatewayRecord->checkout = $CheckoutRequestID;
$PaymentGatewayRecord->payment_method = 'Mpesa PayBill';
$PaymentGatewayRecord->payment_channel = 'Mpesa PayBill';
$PaymentGatewayRecord->save();
if (!empty($_POST['channel'])) {
echo json_encode(["status" => "success", "message" => "Enter Pin to complete"]);
} else {
echo "<script>toastr.success('Enter Mpesa Pin to complete');</script>";
}
} else {
echo "<script>toastr.error('We could not complete the payment for you, please contact administrator');</script>";
}
}
?>

View File

@ -0,0 +1,304 @@
<?php
function initiatebankstk()
{
$username=$_POST['username'];
$phone=$_POST['phone'];
$phone = (substr($phone, 0,1) == '+') ? str_replace('+', '', $phone) : $phone;
$phone = (substr($phone, 0,1) == '0') ? preg_replace('/^0/', '254', $phone) : $phone;
$phone = (substr($phone, 0,1) == '7') ? preg_replace('/^7/', '2547', $phone) : $phone; //cater for phone number prefix 2547XXXX
$phone = (substr($phone, 0,1) == '1') ? preg_replace('/^1/', '2541', $phone) : $phone; //cater for phone number prefix 2541XXXX
$phone = (substr($phone, 0,1) == '0') ? preg_replace('/^01/', '2541', $phone) : $phone;
$phone = (substr($phone, 0,1) == '0') ? preg_replace('/^07/', '2547', $phone) : $phone;
$bankaccount = ORM::for_table('tbl_appconfig')
->where('setting', 'Stkbankacc')
->find_one();
$bankname = ORM::for_table('tbl_appconfig')
->where('setting', 'Stkbankname')
->find_one();
$bankaccount = ($bankaccount) ? $bankaccount->value : null;
$bankname = ($bankname) ? $bankname->value : null;
// echo $bankname;
$CheckId = ORM::for_table('tbl_customers')
->where('username', $username)
->order_by_desc('id')
->find_one();
$CheckUser = ORM::for_table('tbl_customers')
->where('phonenumber', $phone)
->find_many();
$UserId=$CheckId->id;
if (empty($bankaccount) || empty($bankname)) {
echo $error="<script>toastr.error('Could not complete the payment req, please contact admin');</script>";
die();
}
$getpaybill = ORM::for_table('tbl_banks')
->where('name', $bankname)
->find_one();
$paybill=$getpaybill->paybill;
// echo $paybill;
$cburl = U . 'callback/BankStkPush' ;
$PaymentGatewayRecord = ORM::for_table('tbl_payment_gateway')
->where('username', $username)
->where('status', 1) // Add this line to filter by status
->order_by_desc('id')
->find_one();
$ThisUser= ORM::for_table('tbl_customers')
->where('username', $username)
->order_by_desc('id')
->find_one();
$ThisUser->phonenumber=$phone;
// $ThisUser->username=$phone;
$ThisUser->save();
$amount=$PaymentGatewayRecord->price;
if(!$PaymentGatewayRecord){
echo $error="<script>toastr.error('Could not complete the payment req, please contact administrator');</script>";
die();
}
$consumerKey = '3AmVP1WFDQn7GrDH8GcSSKxcAvnJdZGC'; //Fill with your app Consumer Key
$consumerSecret = '71Lybl6jUtxM0F35'; // Fill with your app Secret
$headers = ['Content-Type:application/json; charset=utf8'];
$access_token_url = 'https://api.safaricom.co.ke/oauth/v1/generate?grant_type=client_credentials';
$curl = curl_init($access_token_url);
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($curl, CURLOPT_HEADER, FALSE);('');
curl_setopt($curl, CURLOPT_USERPWD, $consumerKey.':'.$consumerSecret);
$result = curl_exec($curl);
$status = curl_getinfo($curl, CURLINFO_HTTP_CODE);
$result = json_decode($result);
$access_token = $result->access_token;
// echo $access_token;
curl_close($curl);
// Initiate Stk push
$stk_url = 'https://api.safaricom.co.ke/mpesa/stkpush/v1/processrequest';
$PartyA = $phone; // This is your phone number,
$AccountReference = $bankaccount;
$TransactionDesc = 'TestMapayment';
$Amount = $amount;
$BusinessShortCode='4122323';
$Passkey='aaebecea73082fa56af852606106b1316d5b4dfa2f12d0088800b0b88e4bb6e3';
$Timestamp = date("YmdHis",time());
$Password = base64_encode($BusinessShortCode.$Passkey.$Timestamp);
$CallBackURL = $cburl;
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $stk_url);
curl_setopt($curl, CURLOPT_HTTPHEADER, array('Content-Type:application/json','Authorization:Bearer '.$access_token)); //setting custom header
$curl_post_data = array(
//Fill in the request parameters with valid values
'BusinessShortCode' => $BusinessShortCode,
'Password' => $Password,
'Timestamp' => $Timestamp,
'TransactionType' => 'CustomerPayBillOnline',
'Amount' => $Amount,
'PartyA' => $PartyA,
'PartyB' => $paybill,
'PhoneNumber' => $PartyA,
'CallBackURL' => $CallBackURL,
'AccountReference' => $AccountReference,
'TransactionDesc' => $TransactionDesc
);
$data_string = json_encode($curl_post_data);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data_string);
$curl_response = curl_exec($curl);
//print_r($curl_response);
// echo $curl_response;
// die;
$mpesaResponse = json_decode($curl_response);
$responseCode = $mpesaResponse->ResponseCode;
$resultDesc = $mpesaResponse->resultDesc;
$MerchantRequestID = $mpesaResponse->MerchantRequestID;
$CheckoutRequestID = $mpesaResponse->CheckoutRequestID;
if($responseCode=="0"){
date_default_timezone_set('Africa/Nairobi');
$now=date("Y-m-d H:i:s");
// $username=$phone;
$PaymentGatewayRecord->pg_paid_response = $resultDesc;
$PaymentGatewayRecord->username = $username;
$PaymentGatewayRecord->checkout = $CheckoutRequestID;
$PaymentGatewayRecord->payment_method = 'Mpesa Stk Push';
$PaymentGatewayRecord->payment_channel = 'Mpesa Stk Push';
$PaymentGatewayRecord->save();
if(!empty($_POST['channel'])){
echo json_encode(["status" => "success", "message" => "Enter Pin to complete"]);
}else{
echo $error="<script>toastr.success('Enter Mpesa Pin to complete');</script>";
}
}else{
echo $error="<script>toastr.error('We could not complete the payment for you, please contact administrator');</script>";
}
}
?>

View File

@ -0,0 +1,148 @@
<?php
function initiatempesa()
{
$username = $_POST['username'];
$phone = $_POST['phone'];
$phone = (substr($phone, 0, 1) == '+') ? str_replace('+', '', $phone) : $phone;
$phone = (substr($phone, 0, 1) == '0') ? preg_replace('/^0/', '254', $phone) : $phone;
$phone = (substr($phone, 0, 1) == '7') ? preg_replace('/^7/', '2547', $phone) : $phone; //cater for phone number prefix 2547XXXX
$phone = (substr($phone, 0, 1) == '1') ? preg_replace('/^1/', '2541', $phone) : $phone; //cater for phone number prefix 2541XXXX
$phone = (substr($phone, 0, 1) == '0') ? preg_replace('/^01/', '2541', $phone) : $phone;
$phone = (substr($phone, 0, 1) == '0') ? preg_replace('/^07/', '2547', $phone) : $phone;
$CheckId = ORM::for_table('tbl_customers')
->where('username', $username)
->order_by_desc('id')
->find_one();
$CheckUser = ORM::for_table('tbl_customers')
->where('phonenumber', $phone)
->find_many();
$UserId = $CheckId->id;
$CallBackURL = U . 'callback/mpesa';
$PaymentGatewayRecord = ORM::for_table('tbl_payment_gateway')
->where('username', $username)
->where('status', 1) // Add this line to filter by status
->order_by_desc('id')
->find_one();
$ThisUser = ORM::for_table('tbl_customers')
->where('username', $username)
->order_by_desc('id')
->find_one();
$ThisUser->phonenumber = $phone;
$ThisUser->save();
$amount = $PaymentGatewayRecord->price;
if (!$PaymentGatewayRecord) {
echo json_encode(["status" => "error", "message" => "Could not complete the payment req, please contact administrator"]);
}
// Get the M-Pesa mpesa_env
$mpesa_env = ORM::for_table('tbl_appconfig')
->where('setting', 'mpesa_env')
->find_one();
$mpesa_env = ($mpesa_env) ? $mpesa_env->value : null;
// Get the M-Pesa consumer key
$mpesa_consumer_key = ORM::for_table('tbl_appconfig')
->where('setting', 'mpesa_consumer_key')
->find_one();
$mpesa_consumer_key = ($mpesa_consumer_key) ? $mpesa_consumer_key->value : null;
// Get the M-Pesa consumer secret
$mpesa_consumer_secret = ORM::for_table('tbl_appconfig')
->where('setting', 'mpesa_consumer_secret')
->find_one();
$mpesa_consumer_secret = ($mpesa_consumer_secret) ? $mpesa_consumer_secret->value : null;
$mpesa_business_code = ORM::for_table('tbl_appconfig')
->where('setting', 'mpesa_business_code')
->find_one();
$mpesa_business_code = ($mpesa_business_code) ? $mpesa_business_code->value : null;
$mpesa_shortcode_type = ORM::for_table('tbl_appconfig')
->where('setting', 'mpesa_shortcode_type')
->find_one();
if ($mpesa_shortcode_type == 'BuyGoods') {
$mpesa_buygoods_till_number = ORM::for_table('tbl_appconfig')
->where('setting', 'mpesa_buygoods_till_number')
->find_one();
$mpesa_buygoods_till_number = ($mpesa_buygoods_till_number) ? $mpesa_buygoods_till_number->value : null;
$PartyB = $mpesa_buygoods_till_number;
$Type_of_Transaction = 'CustomerBuyGoodsOnline';
} else {
$PartyB = $mpesa_business_code;
$Type_of_Transaction = 'CustomerPayBillOnline';
}
$Passkey = ORM::for_table('tbl_appconfig')
->where('setting', 'mpesa_pass_key')
->find_one();
$Passkey = ($Passkey) ? $Passkey->value : null;
$Time_Stamp = date("Ymdhis");
$password = base64_encode($mpesa_business_code . $Passkey . $Time_Stamp);
if ($mpesa_env == "live") {
$OnlinePayment = 'https://api.safaricom.co.ke/mpesa/stkpush/v1/processrequest';
$Token_URL = 'https://api.safaricom.co.ke/oauth/v1/generate?grant_type=client_credentials';
} elseif ($mpesa_env == "sandbox") {
$OnlinePayment = 'https://sandbox.safaricom.co.ke/mpesa/stkpush/v1/processrequest';
$Token_URL = 'https://sandbox.safaricom.co.ke/oauth/v1/generate?grant_type=client_credentials';
} else {
return json_encode(["Message" => "invalid application status"]);
};
$headers = ['Content-Type:application/json; charset=utf8'];
$curl = curl_init($Token_URL);
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($curl, CURLOPT_HEADER, FALSE);
curl_setopt($curl, CURLOPT_USERPWD, $mpesa_consumer_key . ':' . $mpesa_consumer_secret);
$result = curl_exec($curl);
$status = curl_getinfo($curl, CURLINFO_HTTP_CODE);
$result = json_decode($result);
$access_token = $result->access_token;
curl_close($curl);
$password = base64_encode($mpesa_business_code . $Passkey . $Time_Stamp);
$stkpushheader = ['Content-Type:application/json', 'Authorization:Bearer ' . $access_token];
//INITIATE CURL
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $OnlinePayment);
curl_setopt($curl, CURLOPT_HTTPHEADER, $stkpushheader); //setting custom header
$curl_post_data = array(
//Fill in the request parameters with valid values
'BusinessShortCode' => $mpesa_business_code,
'Password' => $password,
'Timestamp' => $Time_Stamp,
'TransactionType' => $Type_of_Transaction,
'Amount' => $amount,
'PartyA' => $phone,
'PartyB' => $PartyB,
'PhoneNumber' => $phone,
'CallBackURL' => $CallBackURL,
'AccountReference' => $username,
'TransactionDesc' => 'Payment for ' . $username
);
$data_string = json_encode($curl_post_data);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data_string);
$curl_response = curl_exec($curl);
$curl_Tranfer2_response = json_decode($curl_response);
if (isset($curl_Tranfer2_response->ResponseCode) && $curl_Tranfer2_response->ResponseCode == "0") {
$resultDesc = $curl_Tranfer2_response->resultDesc;
$CheckoutRequestID = $curl_Tranfer2_response->CheckoutRequestID;
date_default_timezone_set('Africa/Nairobi');
$now = date("Y-m-d H:i:s");
// $username=$phone;
$PaymentGatewayRecord->pg_paid_response = $resultDesc;
$PaymentGatewayRecord->username = $username;
$PaymentGatewayRecord->checkout = $CheckoutRequestID;
$PaymentGatewayRecord->payment_method = 'Mpesa Stk Push';
$PaymentGatewayRecord->payment_channel = 'Mpesa Stk Push';
$saveGateway = $PaymentGatewayRecord->save();
if ($saveGateway) {
if (!empty($_POST['channel'])) {
echo json_encode(["status" => "success", "message" => "Enter Mpesa Pin to complete $mpesa_business_code $Type_of_Transaction , Party B: $PartyB, Amount: $amount, Phone: $phone, CheckoutRequestID: $CheckoutRequestID"]);
} else {
echo "<script>toastr.success('Enter Mpesa Pin to complete');</script>";
}
} else {
echo json_encode(["status" => "error", "message" => "Failed to save the payment gateway record"]);
}
} else {
$errorMessage = $curl_Tranfer2_response->errorMessage;
echo json_encode(["status" => "error", "message" => $errorMessage]);
}
}

View File

@ -0,0 +1,232 @@
<?php
function initiatetillstk()
{
$username=$_POST['username'];
$phone=$_POST['phone'];
$phone = (substr($phone, 0,1) == '+') ? str_replace('+', '', $phone) : $phone;
$phone = (substr($phone, 0,1) == '0') ? preg_replace('/^0/', '254', $phone) : $phone;
$phone = (substr($phone, 0,1) == '7') ? preg_replace('/^7/', '2547', $phone) : $phone; //cater for phone number prefix 2547XXXX
$phone = (substr($phone, 0,1) == '1') ? preg_replace('/^1/', '2541', $phone) : $phone; //cater for phone number prefix 2541XXXX
$phone = (substr($phone, 0,1) == '0') ? preg_replace('/^01/', '2541', $phone) : $phone;
$phone = (substr($phone, 0,1) == '0') ? preg_replace('/^07/', '2547', $phone) : $phone;
$consumer_key = ORM::for_table('tbl_appconfig')
->where('setting', 'mpesa_till_consumer_key')
->find_one();
$consumer_secret = ORM::for_table('tbl_appconfig')
->where('setting', 'mpesa_till_consumer_secret')
->find_one();
$consumer_secret = ORM::for_table('tbl_appconfig')
->where('setting', 'mpesa_till_consumer_secret')
->find_one();
$BusinessShortCode= ORM::for_table('tbl_appconfig')
->where('setting', 'mpesa_till_shortcode_code')
->find_one();
$PartyB= ORM::for_table('tbl_appconfig')
->where('setting', 'mpesa_till_partyb')
->find_one();
$LipaNaMpesaPasskey= ORM::for_table('tbl_appconfig')
->where('setting', 'mpesa_till_pass_key')
->find_one();
$consumer_key = ($consumer_key) ? $consumer_key->value : null;
$consumer_secret = ($consumer_secret) ? $consumer_secret->value : null;
$BusinessShortCode = ($BusinessShortCode) ? $BusinessShortCode->value : null;
$PartyB = ($PartyB) ? $PartyB->value : null;
$LipaNaMpesaPasskey = ($LipaNaMpesaPasskey) ? $LipaNaMpesaPasskey->value : null;
$cburl = U . 'callback/MpesatillStk' ;
//
$CheckId = ORM::for_table('tbl_customers')
->where('username', $username)
->order_by_desc('id')
->find_one();
$CheckUser = ORM::for_table('tbl_customers')
->where('phonenumber', $phone)
->find_many();
$UserId=$CheckId->id;
$PaymentGatewayRecord = ORM::for_table('tbl_payment_gateway')
->where('username', $username)
->where('status', 1) // Add this line to filter by status
->order_by_desc('id')
->find_one();
$ThisUser= ORM::for_table('tbl_customers')
->where('username', $username)
->order_by_desc('id')
->find_one();
$ThisUser->phonenumber=$phone;
// $ThisUser->username=$phone;
$ThisUser->save();
$amount=$PaymentGatewayRecord->price;
if(!$PaymentGatewayRecord){
echo $error="<script>toastr.success('Unable to proess payment, please reload the page');</script>";
die();
}
$TransactionType = 'CustomerBuyGoodsOnline';
$tokenUrl = 'https://api.safaricom.co.ke/oauth/v1/generate?grant_type=client_credentials';
$phone= $phone;
$lipaOnlineUrl = 'https://api.safaricom.co.ke/mpesa/stkpush/v1/processrequest';
// $amount= '1';
$CallBackURL = $cburl;
date_default_timezone_set('Africa/Nairobi');
$timestamp = date("YmdHis");
$password = base64_encode($BusinessShortCode . $LipaNaMpesaPasskey . $timestamp);
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $tokenUrl);
$credentials = base64_encode($consumer_key . ':' . $consumer_secret);
curl_setopt($curl, CURLOPT_HTTPHEADER, array('Authorization: Basic ' . $credentials));
curl_setopt($curl, CURLOPT_HEADER, false);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
$curl_response = curl_exec($curl);
$token = json_decode($curl_response)->access_token;
$curl2 = curl_init();
curl_setopt($curl2, CURLOPT_URL, $lipaOnlineUrl);
curl_setopt($curl2, CURLOPT_HTTPHEADER, array('Content-Type:application/json', 'Authorization:Bearer ' . $token));
$curl2_post_data = [
'BusinessShortCode' => $BusinessShortCode,
'Password' => $password,
'Timestamp' => $timestamp,
'TransactionType' => $TransactionType,
'Amount' => $amount,
'PartyA' => $phone,
'PartyB' => $PartyB,
'PhoneNumber' => $phone,
'CallBackURL' => $CallBackURL,
'AccountReference' => 'Payment For Goods',
'TransactionDesc' => 'Payment for goods',
];
$data2_string = json_encode($curl2_post_data);
curl_setopt($curl2, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl2, CURLOPT_POST, true);
curl_setopt($curl2, CURLOPT_POSTFIELDS, $data2_string);
curl_setopt($curl2, CURLOPT_HEADER, false);
curl_setopt($curl2, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($curl2, CURLOPT_SSL_VERIFYHOST, 0);
$curl_response = curl_exec($curl2);
$curl_response1 = curl_exec($curl);
//($curl_response);
//echo $curl_response;
$mpesaResponse = json_decode($curl_response);
//echo $phone;
$responseCode = $mpesaResponse->ResponseCode;
$MerchantRequestID = $mpesaResponse->MerchantRequestID;
$CheckoutRequestID = $mpesaResponse->CheckoutRequestID;
$resultDesc = $mpesaResponse->CustomerMessage;
// file_put_contents('stk.log',$curl_response,FILE_APPEND);
// echo $cburl;
$responseCode = $responseCode;
if($responseCode=="0"){
date_default_timezone_set('Africa/Nairobi');
$now=date("Y-m-d H:i:s");
// $username=$phone;
$PaymentGatewayRecord->pg_paid_response = $resultDesc;
$PaymentGatewayRecord->checkout = $CheckoutRequestID;
$PaymentGatewayRecord->username = $username;
$PaymentGatewayRecord->payment_method = 'Mpesa Stk Push';
$PaymentGatewayRecord->payment_channel = 'Mpesa Stk Push';
$PaymentGatewayRecord->save();
if(!empty($_POST['channel'])){
echo json_encode(["status" => "success", "message" => "Enter Pin to complete","phone"=> $phone]);
}else{
echo $error="<script>toastr.success('Enter Mpesa Pin to complete');</script>";
}
}else{
echo "There is an issue with the transaction, please wait for 0 seconds then try again";
}
}

46
system/plugin/log.php Normal file
View File

@ -0,0 +1,46 @@
<?php
use PEAR2\Net\RouterOS;
use PEAR2\Net\RouterOS\Client;
use PEAR2\Net\RouterOS\Request;
// Fungsi untuk menampilkan log monitor
register_menu("Router Logs", true, "log_ui", 'NETWORK');
function log_ui() {
global $ui, $routes;
_admin();
$ui->assign('_title', 'Log Mikrotik');
$ui->assign('_system_menu', 'Log Mikrotik');
$admin = Admin::_info();
$ui->assign('_admin', $admin);
$routers = ORM::for_table('tbl_routers')->where('enabled', '1')->find_many();
$routerId = $routes['2'] ?? ($routers ? $routers[0]['id'] : null); // Memastikan ada router yang aktif
$logs = fetchLogs($routerId); // Mengambil log dari router yang dipilih
$ui->assign('logs', $logs);
$ui->display('log.tpl');
}
// Fungsi untuk mengambil logs dari MikroTik
function fetchLogs($routerId) {
if (!$routerId) {
return []; // Mengembalikan array kosong jika router tidak tersedia
}
$mikrotik = ORM::for_table('tbl_routers')->where('enabled', '1')->find_one($routerId);
if (!$mikrotik) {
return []; // Mengembalikan array kosong jika router tidak ditemukan
}
$client = Mikrotik::getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
$request = new Request('/log/print');
$response = $client->sendSync($request);
$logs = [];
foreach ($response as $entry) {
$logs[] = $entry->getIterator()->getArrayCopy(); // Mengumpulkan data dari setiap entry
}
return $logs;
}

View File

@ -0,0 +1,418 @@
<?php
use PEAR2\Net\RouterOS;
function pppoe()
{
global $ui, $routes;
_admin();
$ui->assign('_title', 'PPPoE Monitor');
$ui->assign('_system_menu', 'PPPoE Monitor');
$admin = Admin::_info();
$ui->assign('_admin', $admin);
$routers = ORM::for_table('tbl_routers')->where('enabled', '1')->find_many();
$router = $routes['2'] ?? $routers[0]['id'];
$ui->assign('routers', $routers);
$ui->assign('router', $router);
$ui->assign('interfaces', pppoe_monitor_router_getInterface());
$ui->display('pppoe_monitor.tpl');
}
function pppoe_monitor_router_getInterface()
{
global $routes;
$routerId = $routes['2'] ?? null;
if (!$routerId) {
return [];
}
$mikrotik = ORM::for_table('tbl_routers')->where('enabled', '1')->find_one($routerId);
if (!$mikrotik) {
return [];
}
$client = Mikrotik::getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
$interfaces = $client->sendSync(new RouterOS\Request('/interface/print'));
$interfaceList = [];
foreach ($interfaces as $interface) {
$name = $interface->getProperty('name');
$interfaceList[] = $name; // Jangan menghapus karakter < dan > dari nama interface
}
return $interfaceList;
}
function pppoe_get_combined_users() {
global $routes;
$router = $routes['2'];
$mikrotik = ORM::for_table('tbl_routers')->where('enabled', '1')->find_one($router);
if (!$mikrotik) {
header('Content-Type: application/json');
echo json_encode(['error' => 'Router not found']);
return;
}
try {
$client = Mikrotik::getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
// Fetch PPP online users
$pppUsers = $client->sendSync(new RouterOS\Request('/ppp/active/print'));
$interfaceTraffic = $client->sendSync(new RouterOS\Request('/interface/print'));
$pppSecrets = $client->sendSync(new RouterOS\Request('/ppp/secret/print'));
$interfaceData = [];
foreach ($interfaceTraffic as $interface) {
$name = $interface->getProperty('name');
if (empty($name)) {
continue;
}
$interfaceData[$name] = [
'status' => $interface->getProperty('running') === 'true' ? 'Connected' : 'Disconnected',
'txBytes' => intval($interface->getProperty('tx-byte')),
'rxBytes' => intval($interface->getProperty('rx-byte')),
];
}
$pppUserList = [];
foreach ($pppUsers as $pppUser) {
$username = $pppUser->getProperty('name');
if (empty($username)) {
continue;
}
$address = $pppUser->getProperty('address');
$uptime = $pppUser->getProperty('uptime');
$service = $pppUser->getProperty('service');
$callerid = $pppUser->getProperty('caller-id');
$bytes_in = $pppUser->getProperty('limit-bytes-in');
$bytes_out = $pppUser->getProperty('limit-bytes-out');
$id = $pppUser->getProperty('.id');
$interfaceName = "<pppoe-$username>";
if (isset($interfaceData[$interfaceName])) {
$trafficData = $interfaceData[$interfaceName];
$txBytes = $trafficData['txBytes'];
$rxBytes = $trafficData['rxBytes'];
$status = $trafficData['status'];
} else {
$txBytes = 0;
$rxBytes = 0;
$status = 'Disconnected';
}
// Get device information
$manufacturer = "Unknown";
if ($callerid) {
$manufacturer = get_manufacturer_from_mac($callerid);
}
// Check if MAC is bound in ppp secrets
$isBound = false;
foreach ($pppSecrets as $secret) {
if ($secret->getProperty('name') === $username && $secret->getProperty('caller-id') === $callerid) {
$isBound = true;
break;
}
}
$pppUserList[$username] = [
'id' => $id,
'username' => $username,
'address' => $address,
'uptime' => $uptime,
'service' => $service,
'caller_id' => $callerid,
'bytes_in' => $bytes_in,
'bytes_out' => $bytes_out,
'tx' => pppoe_monitor_router_formatBytes($txBytes),
'rx' => pppoe_monitor_router_formatBytes($rxBytes),
'total' => pppoe_monitor_router_formatBytes($txBytes + $rxBytes),
'status' => $status,
'manufacturer' => $manufacturer,
'is_bound' => $isBound
];
}
// Convert the user list to a regular array for JSON encoding
$userList = array_values($pppUserList);
// Return the combined user list as JSON
header('Content-Type: application/json');
echo json_encode($userList);
} catch (Exception $e) {
header('Content-Type: application/json');
echo json_encode(['error' => $e->getMessage()]);
}
}
function get_manufacturer_from_mac($mac_address) {
// Normalize the MAC address
$mac_address = strtoupper(preg_replace('/[^A-F0-9]/', '', $mac_address));
// Check if MAC address is valid (at least 6 hex characters required)
if (strlen($mac_address) < 6) {
return 'Invalid MAC address';
}
// Construct the API URL
$url = "https://www.macvendorlookup.com/api/v2/{$mac_address}";
// Initialize cURL session
$ch = curl_init();
// Set cURL options
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // For testing purposes, handle SSL properly in production
// Execute cURL request
$response = curl_exec($ch);
// Check for cURL errors
if (curl_errno($ch)) {
$error = curl_error($ch);
curl_close($ch);
return "Error: $error";
}
// Get HTTP response code
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
// Check if API returned a valid response
if ($http_code === 204) {
return 'Unknown';
}
// Decode JSON response
$data = json_decode($response, true);
// Check if the response contains manufacturer information
if (isset($data[0]['company'])) {
return trim($data[0]['company']);
} else {
return 'Unknown';
}
}
function pppoe_monitor_router_formatMaxLimit($max_limit) {
$limits = explode('/', $max_limit);
if (count($limits) == 2) {
$downloadLimit = intval($limits[0]);
$uploadLimit = intval($limits[1]);
$formattedDownloadLimit = ceil($downloadLimit / (1024 * 1024)) . ' MB';
$formattedUploadLimit = ceil($uploadLimit / (1024 * 1024)) . ' MB';
return $formattedDownloadLimit . '/' . $formattedUploadLimit;
}
return 'N/A';
}
// Fungsi untuk menghitung total data yang digunakan per harinya
function pppoe_monitor_router_formatBytes($bytes, $precision = 2)
{
$units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
$bytes = max($bytes, 0);
$pow = floor(($bytes ? log($bytes) : 0) / log(1024));
$pow = min($pow, count($units) - 1);
$bytes /= pow(1024, $pow);
return round($bytes, $precision) . ' ' . $units[$pow];
}
function pppoe_monitor_router_traffic()
{
$interface = $_GET["interface"]; // Ambil interface dari parameter GET
// Contoh koneksi ke MikroTik menggunakan library tertentu (misalnya menggunakan ORM dan MikroTik API wrapper)
global $routes;
$router = $routes['2'];
$mikrotik = ORM::for_table('tbl_routers')->where('enabled', '1')->find_one($router);
$client = Mikrotik::getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
try {
$results = $client->sendSync(
(new RouterOS\Request('/interface/monitor-traffic'))
->setArgument('interface', $interface)
->setArgument('once', '')
);
$rows = array();
$rows2 = array();
$labels = array();
foreach ($results as $result) {
$ftx = $result->getProperty('tx-bits-per-second');
$frx = $result->getProperty('rx-bits-per-second');
// Timestamp dalam milidetik (millisecond)
$timestamp = time() * 1000;
$rows[] = $ftx;
$rows2[] = $frx;
$labels[] = $timestamp; // Tambahkan timestamp ke dalam array labels
}
$result = array(
'labels' => $labels,
'rows' => array(
'tx' => $rows,
'rx' => $rows2
)
);
} catch (Exception $e) {
$result = array('error' => $e->getMessage());
}
// Set header untuk respons JSON
header('Content-Type: application/json');
echo json_encode($result);
}
function pppoe_monitor_router_online()
{
global $routes;
$router = $routes['2'];
$mikrotik = ORM::for_table('tbl_routers')->where('enabled', '1')->find_one($router);
$client = Mikrotik::getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
$pppUsers = $client->sendSync(new RouterOS\Request('/ppp/active/print'));
$pppoeInterfaces = [];
foreach ($pppUsers as $pppUser) {
$username = $pppUser->getProperty('name');
$interfaceName = "<pppoe-$username>"; // Tambahkan karakter < dan >
// Ensure interface name is not empty and it's not already in the list
if (!empty($interfaceName) && !in_array($interfaceName, $pppoeInterfaces)) {
$pppoeInterfaces[] = $interfaceName;
}
}
// Return the list of PPPoE interfaces
return $pppoeInterfaces;
}
function pppoe_monitor_router_delete_ppp_user()
{
global $routes;
$router = $routes['2'];
$id = $_POST['id']; // Ambil .id dari POST data
// Cek apakah ID ada di POST data
if (empty($id)) {
header('Content-Type: application/json');
echo json_encode(['success' => false, 'message' => 'ID is missing.']);
return;
}
// Ambil detail router dari database
$mikrotik = ORM::for_table('tbl_routers')->where('enabled', '1')->find_one($router);
if (!$mikrotik) {
header('Content-Type: application/json');
echo json_encode(['success' => false, 'message' => 'Router not found.']);
return;
}
// Dapatkan klien MikroTik
$client = Mikrotik::getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
if (!$client) {
header('Content-Type: application/json');
echo json_encode(['success' => false, 'message' => 'Failed to connect to the router.']);
return;
}
try {
// Buat permintaan untuk menghapus koneksi aktif PPPoE
$request = new RouterOS\Request('/ppp/active/remove');
$request->setArgument('.id', $id); // Gunakan .id yang sesuai
$client->sendSync($request);
header('Content-Type: application/json');
echo json_encode(['success' => true, 'message' => 'PPPoE user successfully deleted.']);
} catch (Exception $e) {
// Log error untuk debugging
error_log('Failed to delete PPPoE user: ' . $e->getMessage());
header('Content-Type: application/json');
echo json_encode(['success' => false, 'message' => 'Failed to delete PPPoE user: ' . $e->getMessage()]);
}
}
// ======================================================================
// NEW FUNCTIONS:
// Fungsi untuk menghitung total data yang digunakan per harinya
function pppoe_monitor_router_daily_data_usage()
{
global $routes;
$router = $routes['2'];
$mikrotik = ORM::for_table('tbl_routers')->where('enabled', '1')->find_one($router);
$client = Mikrotik::getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
// Ambil semua pengguna aktif PPPoE
$pppUsers = $client->sendSync(new RouterOS\Request('/ppp/active/print'));
$interfaceTraffic = $client->sendSync(new RouterOS\Request('/interface/print'));
// Array untuk menyimpan data penggunaan harian
$daily_usage = [];
// Looping untuk setiap pengguna PPPoE
foreach ($pppUsers as $pppUser) {
$username = $pppUser->getProperty('name');
$interfaceName = "<pppoe-$username>"; // Nama interface sesuai format PPPoE
// Ambil data traffic untuk interface ini
$interfaceData = [];
foreach ($interfaceTraffic as $interface) {
$name = $interface->getProperty('name');
if ($name === $interfaceName) {
$interfaceData = [
'txBytes' => intval($interface->getProperty('tx-byte')),
'rxBytes' => intval($interface->getProperty('rx-byte'))
];
break;
}
}
// Hitung total penggunaan harian
$txBytes = $interfaceData['txBytes'] ?? 0;
$rxBytes = $interfaceData['rxBytes'] ?? 0;
$totalDataMB = ($txBytes + $rxBytes) / (1024 * 1024); // Konversi ke MB
// Ambil tanggal dari waktu saat ini
$date = date('Y-m-d', time());
// Jika belum ada data untuk tanggal ini, inisialisasi
if (!isset($daily_usage[$date])) {
$daily_usage[$date] = [
'total' => 0,
'users' => []
];
}
// Tambahkan penggunaan harian untuk pengguna ini
$daily_usage[$date]['total'] += $totalDataMB;
$daily_usage[$date]['users'][] = [
'username' => $username,
'tx' => pppoe_monitor_router_formatBytes($txBytes),
'rx' => pppoe_monitor_router_formatBytes($rxBytes),
'total' => pppoe_monitor_router_formatBytes($txBytes + $rxBytes)
];
}
// Kembalikan hasil dalam format JSON
header('Content-Type: application/json');
echo json_encode($daily_usage); // $daily_usage adalah array yang berisi data harian dalam format yang sesuai
}
// Fungsi untuk mendapatkan pengguna terbatas pada MikroTik

BIN
system/plugin/ui/.DS_Store vendored Normal file

Binary file not shown.

View File

@ -0,0 +1,162 @@
{include file="sections/header.tpl"}
<style>
/* Styles for overall layout and responsiveness */
body {
background-color: #f8f9fa;
font-family: 'Arial', sans-serif;
}
.container {
margin-top: 20px;
background-color: #d8dfe5;
border-radius: 8px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
padding: 20px;
max-width: 98%;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
}
/* Styles for table and pagination */
.table {
width: 100%;
margin-bottom: 1rem;
background-color: #fff;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
.table th {
vertical-align: middle;
border-color: #dee2e6;
background-color: #343a40;
color: #fff;
}
.table td {
vertical-align: middle;
border-color: #dee2e6;
}
.table-striped tbody tr:nth-of-type(odd) {
background-color: rgba(0, 0, 0, 0.05);
}
.table-hover tbody tr:hover {
background-color: rgba(0, 0, 0, 0.075);
color: #333;
font-weight: bold;
transition: background-color 0.3s, color 0.3s;
}
.pagination .page-item .page-link {
color: #007bff;
background-color: #fff;
border: 1px solid #dee2e6;
margin: 0 2px;
padding: 6px 12px;
transition: background-color 0.3s, color 0.3s;
}
.pagination .page-item .page-link:hover {
background-color: #e9ecef;
color: #0056b3;
}
.pagination .page-item.active .page-link {
z-index: 1;
color: #fff;
background-color: #007bff;
border-color: #007bff;
}
.dataTables_wrapper .dataTables_paginate .paginate_button {
display: inline-block;
padding: 5px 10px;
margin-right: 5px;
border: 1px solid #ccc;
background-color: #fff;
color: #333;
cursor: pointer;
}
</style>
{if isset($message)}
<div class="alert alert-{if $notify_t == 's'}success{else}danger{/if}">
<button type="button" class="close" data-dismiss="alert">
<span aria-hidden="true">×</span>
</button>
<div>{$message}</div>
</div>
{/if}
<div class="col-md-14">
<!-- LINE CHART -->
<div class="box box-info">
<div class="box-header with-border">
<h3 class="box-title">{Lang::T('Payment History')}</h3>
<div class="box-tools pull-right">
<button type="button" class="btn bg-teal btn-sm" data-widget="collapse"><i class="fa fa-refresh"></i>
</button>
<a href="{$app_url}/pages/mpesa-webhook.html" class="btn bg-teal btn-sm"><i class="fa fa-file"></i>
</a>
</div>
</div>
<div class="box-body">
<div class="container">
<div class="table-responsive">
<table class="table table-bordered table-striped" id="payments-table">
<thead>
<tr>
<th>{Lang::T('Customer Name')}</th>
<th>{Lang::T('Transaction Type')}</th>
<th>{Lang::T('Transaction Time')}</th>
<th>{Lang::T('Amount Paid')}</th>
<th>{Lang::T('Package Name')}</th>
<th>{Lang::T('Package Price')}</th>
<th>{Lang::T('Status')}</th>
<th>{Lang::T('Bill Ref Number')}</th>
<th>{Lang::T('Company Balance')}</th>
<th>{Lang::T('Date')}</th>
</tr>
</thead>
<tbody>
{foreach $payments as $payment}
<tr>
<td><a href="{$app_url}/index.php?_route=customers/view/{$payment.CustomerID}">{$payment.FirstName}</a></td>
<td>{$payment.TransactionType}</td>
<td>{$payment.TransTime}</td>
<td>{$payment.TransAmount}</td>
<td>{$payment.PackageName}</td>
<td>{$payment.PackagePrice}</td>
<td><span
class="label {if $payment.TransactionStatus == Completed}label-success {elseif $payment.TransactionStatus == Pending}label-warning {/if}">{$payment.TransactionStatus}</span>
</td>
<td>{$payment.BillRefNumber}</td>
<td>{$payment.OrgAccountBalance}</td>
<td>{$payment.CreatedAt}</td>
</tr>
{/foreach}
</tbody>
</table>
</div>
</div>
</div>
<!-- /.box-body -->
</div>
<!-- /.box -->
</div>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdn.datatables.net/1.11.3/js/jquery.dataTables.min.js"></script>
<script>
var $j = jQuery.noConflict();
$j(document).ready(function () {
$j('#payments-table').DataTable({
"pagingType": "full_numbers"
});
});
</script>
{include file="sections/footer.tpl"}

View File

@ -0,0 +1,234 @@
{include file="sections/header.tpl"}
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<style>
.styled-form-group {
margin-bottom: 20px;
}
.styled-btn {
color: #28a745;
border: 1px solid #28a745;
background-color: #fff;
padding: 10px 20px;
font-size: 16px;
text-align: center;
text-decoration: none;
display: inline-block;
transition: all 0.3s ease;
}
.styled-btn:hover {
background-color: #28a745;
color: #fff;
}
.styled-small-text {
color: blue;
margin-top: 10px;
display: block;
font-size: 14px;
}
.switch {
position: relative;
display: inline-block;
width: 50px;
height: 24px;
}
/* Hidden checkbox */
.switch input {
opacity: 0;
width: 0;
height: 0;
}
/* Slider */
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #ccc;
-webkit-transition: .4s;
transition: .4s;
border-radius: 24px;
}
.slider:before {
position: absolute;
content: "";
height: 18px;
width: 18px;
left: 3px;
bottom: 3px;
background-color: white;
-webkit-transition: .4s;
transition: .4s;
border-radius: 50%;
}
input:checked+.slider {
background-color: #2196F3;
}
input:focus+.slider {
box-shadow: 0 0 1px #2196F3;
}
input:checked+.slider:before {
-webkit-transform: translateX(26px);
-ms-transform: translateX(26px);
transform: translateX(26px);
}
</style>
{if isset($message)}
<div class="alert alert-{if $notify_t == 's'}success{else}danger{/if}">
<button type="button" class="close" data-dismiss="alert">
<span aria-hidden="true">×</span>
</button>
<div>{$message}</div>
</div>
{/if}
<form class="form-horizontal" method="post" role="form" action="{$_url}plugin/c2b_settings">
<div class="row">
<div class="col-sm-12 col-md-12">
<div class="panel panel-primary panel-hovered panel-stacked mb30">
<div class="panel-heading">{Lang::T('M-Pesa C2B Payment Gateway')}</div>
<div class="panel-body">
<div class="form-group col-6">
<label class="col-md-3 control-label">{Lang::T('M-Pesa C2B Environment')}</label>
<div class="col-md-6">
<select class="form-control" name="mpesa_c2b_env" id="mpesa_c2b_env">
<option value="sandbox" {if $_c['mpesa_c2b_env']=='sandbox' }selected{/if}>
{Lang::T('SandBox or
Testing')}</option>
<option value="live" {if $_c['mpesa_c2b_env']=='live' }selected{/if}>{Lang::T('Live or
Production')}
</option>
</select>
<small class="form-text text-muted">
<font color="red"><b>{Lang::T('Sandbox')}</b></font> {Lang::T('is for testing purpose,
please switch to')} <font color="green"><b>{Lang::T('Live')}</b></font> {Lang::T('in
production.')}
</small>
</div>
</div>
<div class="form-group col-6">
<label class="col-md-3 control-label">M-Pesa C2B Consumer Key</label>
<div class="col-md-6">
<input type="text" class="form-control" id="mpesa_c2b_consumer_key"
name="mpesa_c2b_consumer_key" placeholder="xxxxxxxxxxxxxxxxx"
value="{$_c['mpesa_c2b_consumer_key']}">
<small class="form-text text-muted"><a href="https://developer.safaricom.co.ke/MyApps"
target="_blank">https://developer.safaricom.co.ke/MyApps</a></small>
</div>
</div>
<div class="form-group col-6">
<label class="col-md-3 control-label">M-Pesa C2B Consumer Secret</label>
<div class="col-md-6">
<input type="password" class="form-control" id="mpesa_c2b_consumer_secret"
name="mpesa_c2b_consumer_secret" placeholder="xxxxxxxxxxxxxxxxx"
value="{$_c['mpesa_c2b_consumer_secret']}">
</div>
</div>
<div class="form-group col-6">
<label class="col-md-3 control-label">M-Pesa C2B Business Shortcode</label>
<div class="col-md-6">
<input type="text" class="form-control" id="mpesa_c2b_business_code"
name="mpesa_c2b_business_code" placeholder="xxxxxxx" maxlength="7"
value="{$_c['mpesa_c2b_business_code']}">
</div>
</div>
<div class="form-group col-6">
<label class="col-md-3 control-label">M-Pesa C2B Version</label>
<div class="col-md-6">
<select class="form-control" name="mpesa_c2b_api">
<option value="v1" {if $_c['mpesa_c2b_api']=='v1' }selected{/if}>v1</option>
<option value="v2" {if $_c['mpesa_c2b_api']=='v2' }selected{/if}>v2</option>
</select>
<small class="form-text text-muted">Select the version of the API you want to
use.</small>
</div>
</div>
<div class="form-group col-6">
<label class="col-md-3 control-label">Bill Ref Number Type</label>
<div class="col-md-6">
<select class="form-control" name="mpesa_c2b_bill_ref">
<option value="phone" {if $_c['mpesa_c2b_bill_ref']=='phone' }selected{/if}>Phone Number</option>
<option value="username" {if $_c['mpesa_c2b_bill_ref']=='username' }selected{/if}>Username</option>
<option value="id" {if $_c['mpesa_c2b_bill_ref']=='id' }selected{/if}>Account ID</option>
</select>
<small class="form-text text-muted">How will the system identify your customers. BillRefNumber must be a unique identity</small>
</div>
</div>
<div class="form-group col-6">
<label class="col-md-3 control-label">{Lang::T('Accept Insufficient Fee')}</label>
<div class="col-md-6">
<label class="switch">
<input type="checkbox" id="mpesa_c2b_low_fee" value="1"
name="mpesa_c2b_low_fee" {if $_c['mpesa_c2b_low_fee']==1}checked{/if}>
<span class="slider"></span>
</label>
</div>
</div>
{if $_c['c2b_registered'] && $_c['mpesa_c2b_env']!='sandbox'}
<div class="form-group col-12 styled-form-group">
<label class="col-md-3 control-label">Register C2B URL</label>
<div class="col-md-6">
<button class="btn styled-btn">URLs Already Registered</button>
</div>
</div>
{else}
<div class="form-group col-12 styled-form-group">
<label class="col-md-3 control-label">Register C2B URL</label>
<div class="col-md-6">
<a href="{$_url}plugin/c2b_registerUrl" class="btn styled-btn">Click to Register Mpesa
C2B URL</a>
<small class="form-text text-muted styled-small-text">Click only after you have saved
the changes.</small>
</div>
</div>
{/if}
<div class="form-group col-6">
<div class="col-lg-offset-3 col-lg-10">
<button class="btn btn-primary waves-effect waves-light" name="save" value="save"
type="submit">Save Changes</button>
</div>
</div>
<div class="bs-callout bs-callout-info" id="callout-navbar-role">
<h4><b>Accept Insufficient Fee</b>:</h4>
<p> If Enable the money customer sent will be convert to customer balance, but if disabled the system will reject it. <br> It requires Validation URL</p>
<h4><b>Note</b>:</h4>
<p> Before click on Register URL <br>
Make sure you have fill the required fields <br>
</p>
</div>
</div>
</div>
</div>
</div>
</form>
<script>
$(document).ready(function () {
toggleTillNumberInput();
$('#mpesa_c2b_transaction').on('change', function () {
toggleTillNumberInput();
});
function toggleTillNumberInput() {
if ($('#mpesa_c2b_transaction').val() === 'BuyGoods') {
$('#tillNumberContainer').show();
} else {
$('#tillNumberContainer').hide();
}
}
});
</script>
{include file="sections/footer.tpl"}

View File

@ -0,0 +1,193 @@
{include file="sections/header.tpl"}
<section class="content-header">
<h1>
<div class="btn-group">
<button type="button" class="btn btn-success">
Captive Portal Settings
</button>
<button
type="button"
class="btn btn-success dropdown-toggle"
data-toggle="dropdown"
>
<span class="caret"></span>
<span class="sr-only">Toggle Dropdown</span>
</button>
<ul class="dropdown-menu" role="menu">
<li><a href="{$_url}plugin/captive_portal_settings">{Lang::T('General Settings')}</a></li>
<li>
<a href="{$_url}plugin/captive_portal_slider"
>{Lang::T('Manage Sliders')}</a
>
</li>
<li><a href="#">{Lang::T('Manage Advertisements')}</a></li>
<li><a href="#">{Lang::T('Manage Authorizations')}</a></li>
<li><a href="#">{Lang::T('Reports')}</a></li>
<li class="divider"></li>
<li>
<a
href="{$_url}plugin/captive_portal_login"
target="”_blank”"
>Preview Member Landing Page</a
>
</li>
<li>
<a
href="{$_url}plugin/captive_portal_download_login"
target="”_blank”"
> Download Login Page </a
>
</li>
</ul>
</div>
</h1>
<ol class="breadcrumb">
<li>
<a href="{$_url}plugin/captive_portal_overview"><i class="fa fa-dashboard"></i> Captive Portal</a>
</li>
<li class="active"> General Settings</li>
</ol>
</section>
<section class="content">
<div class="table-responsive">
<div class="nav-tabs-custom">
<ul class="nav nav-tabs">
<li class="active">
<a href="#tab_1" data-toggle="tab">{Lang::T('General Settings')}</a>
</li>
<li>
<a href="#tab_2" data-toggle="tab">{Lang::T('Customization')}</a>
</li>
<li>
<a href="#tab_3" data-toggle="tab">{Lang::T('Slider Settings')}</a>
</li>
<li>
<a href="#tab_4" data-toggle="tab">{Lang::T('Advertisement Settings')}</a>
</li>
<li>
<a href="#tab_5" data-toggle="tab">{Lang::T('Trial Authorization Settings')}</a>
</li>
<li>
<a href="#tab_6" data-toggle="tab">{Lang::T('Pages Settings')}</a>
</li>
</ul>
<div class="tab-content">
<div style="overflow-x:auto;" class="tab-pane active" id="tab_1">
<div class="box-body no-padding" id="">
<form method="POST" action="" enctype="multipart/form-data">
<div class="box-body">
<div class="form-group">
<label for="">Hotspot Page Title</label>
<input type="text" class="form-control" name="title" id="title" value="{$settings.hotspot_title}" required>
<small class="form-text text-muted">Hotspot Title will be display on Login Page Head Tag</small>
</div>
<div class="form-group">
<label for="">Hotspot Name</label>
<input type="text" class="form-control" name="name" id="name" value="{$settings.hotspot_name}" required>
<small class="form-text text-muted">Hotspot Name will be display on Login Page Nav Bar if Logo is not available</small>
</div>
<div class="form-group">
<label for="favicon">Favicon</label>
<input type="file" class="form-control" name="favicon" id="favicon" accept="image/x-icon, image/png, image/jpeg, image/gif" onchange="previewImage('favicon', 'favicon-preview')">
<small class="form-text text-muted">Favicon will be display on Login Page browser tab, its placed in head section</small>
<br>
<img id="favicon-preview" src="{$settings.favicon}" alt="Favicon Preview" style="max-width: 32px; max-height: 32px;">
</div>
<div class="form-group">
<label for="logo">Logo</label>
<input type="file" class="form-control" name="logo" id="logo" accept="image/png, image/jpeg, image/svg+xml" onchange="previewImage('logo', 'logo-preview')">
<small class="form-text text-muted">Logo will be display on Login Page Nav Bar section</small>
<br>
<img id="logo-preview" src="{$settings.logo}" alt="Logo Preview" style="max-width: 200px; max-height: 200px;">
</div>
<div class="form-group">
<label class="">{Lang::T('Allow Free Trial')}</label>
<div class="form-group">
<select name="trial" id="trial" class="form-control">
<option value="no" {if {$settings.hotspot_trial}=='no' }selected="selected" {/if}>No
</option>
<option value="yes" {if {$settings.hotspot_trial}=='yes' }selected="selected" {/if}>Yes
</option>
</select>
<small class="form-text text-muted"><ul>
<li>Choose No if you dont want to allow Free Trial </li>
<li>Make sure you enable free trial in Mikrotik Router</li>
<li>free trial button won't display
on captive portal preview, but will work if you connect from hotspot</li>
</ul></small>
</div>
</div>
<div class="form-group">
<label class="">{Lang::T('Allow Member Login')}</label>
<div class="form-group">
<select name="member" id="member" class="form-control">
<option value="no" {if {$settings.hotspot_member}=='no' }selected="selected" {/if}>No
</option>
<option value="yes" {if {$settings.hotspot_member}=='yes' }selected="selected" {/if}>Yes
</option>
</select>
<small class="form-text text-muted">Choose No If you want to disable Member Login</small>
</div>
</div>
</div>
<div class="box-footer">
<a href="{$_url}plugin/captive_portal_overview" class="btn btn-default">Cancel</a>
<button type="submit" class="btn btn-info pull-right">Save Changes</button>
</div>
</form>
</div>
</div>
<!-- /.tab-pane -->
<div class="tab-pane" style="overflow-x:auto;" id="tab_2">
<div class="box-body no-padding" id="">
This feature will be available on Pro Version
</div>
</div>
<!-- /.tab-pane -->
<div style="overflow-x:auto;" class="tab-pane" id="tab_3">
<div class="box-body no-padding" id="">
This feature will be available on Pro Version
</div>
</div>
<div style="overflow-x:auto;" class="tab-pane" id="tab_4">
<div class="box-body no-padding" id="">
This feature will be available on Pro Version
</div>
</div>
<div style="overflow-x:auto;" class="tab-pane" id="tab_5">
<div class="box-body no-padding" id="">
This feature will be available on Pro Version
</div>
</div>
<div style="overflow-x:auto;" class="tab-pane" id="tab_6">
<div class="box-body no-padding" id="">
This feature will be available on Pro Version
</div>
</div>
</div>
</div>
<div>
<pre><b>USAGE:</b>
<br>Upload your sliders in Slider Setting
<br>Go General Settings and setup as per your requirements
<br>Then download your the login.html by clicking on download login page
<br>Then upload the downloaded login.html file to your mikrotik router
<br>Make sure you add your webiste URL in mikrotik hotspot wall garden
<br>If your website is https i will suggest you to add certificate to your router
</pre>
</div>
</section>
<script>
window.addEventListener('DOMContentLoaded', function() {
var portalLink = "https://github.com/focuslinkstech";
$('#version').html('Captive Portal Plugin by: <a href="' + portalLink + '">Focuslinks Tech</a>');
});
</script>
{include file="sections/footer.tpl"}

View File

@ -0,0 +1,559 @@
<?php
include '../../config.php';
$mysqli = new mysqli($db_host, $db_user, $db_password, $db_name);
if ($mysqli->connect_error) {
die("Connection failed: " . $mysqli->connect_error);
}
// Function to get a setting value
function getSettingValue($mysqli, $setting) {
$query = $mysqli->prepare("SELECT value FROM tbl_appconfig WHERE setting = ?");
$query->bind_param("s", $setting);
$query->execute();
$result = $query->get_result();
if ($row = $result->fetch_assoc()) {
return $row['value'];
}
return '';
}
// Fetch hotspot title and description from tbl_appconfig
$hotspotTitle = getSettingValue($mysqli, 'hotspot_title');
$description = getSettingValue($mysqli, 'description');
$phone = getSettingValue($mysqli, 'phone');
$company = getSettingValue($mysqli, 'CompanyName');
// Fetch settings
$settings = [];
$settings['frequently_asked_questions_headline1'] = getSettingValue($mysqli, 'frequently_asked_questions_headline1');
$settings['frequently_asked_questions_answer1'] = getSettingValue($mysqli, 'frequently_asked_questions_answer1');
$settings['frequently_asked_questions_headline2'] = getSettingValue($mysqli, 'frequently_asked_questions_headline2');
$settings['frequently_asked_questions_answer2'] = getSettingValue($mysqli, 'frequently_asked_questions_answer2');
$settings['frequently_asked_questions_headline3'] = getSettingValue($mysqli, 'frequently_asked_questions_headline3');
$settings['frequently_asked_questions_answer3'] = getSettingValue($mysqli, 'frequently_asked_questions_answer3');
// Fetch router name and router ID from tbl_appconfig
$routerName = getSettingValue($mysqli, 'router_name');
$routerId = getSettingValue($mysqli, 'router_id');
// Fetch available plans
$planQuery = "SELECT id, name_plan, price, validity, validity_unit FROM tbl_plans WHERE routers = ? AND type = 'Hotspot'";
$planStmt = $mysqli->prepare($planQuery);
$planStmt->bind_param("s", $routerName);
$planStmt->execute();
$planResult = $planStmt->get_result();
// Initialize HTML content variable
$htmlContent = "<!DOCTYPE html>\n";
$htmlContent .= "<html lang=\"en\">\n";
$htmlContent .= "<head>\n";
$htmlContent .= " <meta charset=\"UTF-8\">\n";
$htmlContent .= " <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n";
$htmlContent .= " <title>" . htmlspecialchars($hotspotTitle) . " Hotspot Template - Index</title>\n";
$htmlContent .= " <script src=\"https://cdn.tailwindcss.com\"></script>\n";
$htmlContent .= " <link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css\">\n";
$htmlContent .= " <link rel=\"stylesheet\" href=\"https://cdn.jsdelivr.net/npm/glider-js@1.7.7/glider.min.css\" />\n";
$htmlContent .= " <script src=\"https://cdn.jsdelivr.net/npm/glider-js@1.7.7/glider.min.js\"></script>\n";
$htmlContent .= " <link rel=\"preconnect\" href=\"https://cdn.jsdelivr.net\">\n";
$htmlContent .= " <link rel=\"preconnect\" href=\"https://cdnjs.cloudflare.com\" crossorigin>\n";
$htmlContent .= " <link rel=\"stylesheet\" type=\"text/css\" href=\"styles.css\">\n";
$htmlContent .= "</head>\n";
$htmlContent .= "<body class=\"font-sans antialiased text-gray-900\">\n";
$htmlContent .= " <!-- Sticky Header -->\n";
$htmlContent .= " <header class=\"bg-pink-600 text-white fixed w-full z-10\">\n";
$htmlContent .= " <div class=\"max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-5\">\n";
$htmlContent .= " <div class=\"flex items-center justify-between h-16\">\n";
$htmlContent .= " <!-- Logo and title area -->\n";
$htmlContent .= " <div class=\"flex items-center\">\n";
$htmlContent .= " <img src=\"logo.png\" alt=\"Your Company Logo\" class=\"h-8 w-8 mr-2\">\n";
$htmlContent .= " <h1 class=\"text-xl font-bold\">" . htmlspecialchars($hotspotTitle) . " Hotspot Login Page</h1>\n";
$htmlContent .= " </div>\n";
$htmlContent .= " <!-- Navigation Links -->\n";
$htmlContent .= " <div class=\"block\">\n";
$htmlContent .= " <div class=\"ml-10 flex items-baseline space-x-4\">\n";
$htmlContent .= " <a href=\"#\" class=\"text-teal-200 hover:text-white px-3 py-2 rounded-md text-sm font-medium\">Already Have an Account? Login</a>\n";
$htmlContent .= " </div>\n";
$htmlContent .= " </div>\n";
$htmlContent .= " </div>\n";
$htmlContent .= " </div>\n";
$htmlContent .= " </header>\n";
$htmlContent .= " <!-- Main content -->\n";
$htmlContent .= " <main class=\"pt-24\">\n";
$htmlContent .= " <section class=\"bg-white\">\n";
$htmlContent .= " <div class=\"max-w-7xl mx-auto py-12 px-4 sm:px-6 lg:px-8\">\n";
$htmlContent .= " <h2 class=\"text-3xl font-extrabold text-gray-900 mb-6\">" . htmlspecialchars($description) . "</h2>\n";
$htmlContent .= " <!-- Pricing Section -->\n";
$htmlContent .= " <div class=\"mt-10\">\n";
$htmlContent .= " <div class=\"text-center\">\n";
$htmlContent .= " <h3 class=\"text-2xl leading-8 font-extrabold tracking-tight text-gray-900 sm:text-3xl sm:leading-9\">\n";
$htmlContent .= " CHECK OUR PRICING\n";
$htmlContent .= " </h3>\n";
$htmlContent .= " <p class=\"mt-4 max-w-2xl text-xl leading-7 text-gray-500 lg:mx-auto\">\n";
$htmlContent .= " Choose the plan that fits your needs.\n";
$htmlContent .= " </p>\n";
$htmlContent .= " </div>\n";
$htmlContent .= " </div>\n";
$htmlContent .= " </div>\n";
$htmlContent .= " </section>\n";
$htmlContent .= " </main>\n";
$htmlContent .= "<div class=\"mt-10 max-w-7xl mx-auto grid grid-cols-2 sm:grid-cols-2 md:grid-cols-2 lg:grid-cols-4 gap-5\">\n";
while ($plan = $planResult->fetch_assoc()) {
$htmlContent .= " <div class=\"flex flex-col rounded-lg shadow-xl overflow-hidden transform transition duration-500 hover:scale-105\">\n";
$htmlContent .= " <div class=\"px-4 py-5 bg-gradient-to-tr from-pink-50 to-pink-200 text-center\">\n";
$htmlContent .= " <span class=\"inline-flex px-3 py-1 rounded-full text-xs font-semibold tracking-wide uppercase bg-pink-800 text-pink-50\">\n";
$htmlContent .= htmlspecialchars($plan['name_plan']) . "\n";
$htmlContent .= " </span>\n";
$htmlContent .= " <div class=\"mt-4 text-4xl leading-none font-extrabold text-pink-800\">\n";
$htmlContent .= " <span class=\"text-lg font-medium text-pink-600\">ksh</span>\n";
$htmlContent .= htmlspecialchars($plan['price']) . "\n";
$htmlContent .= " </div>\n";
$htmlContent .= " <p class=\"mt-2 text-md leading-5 text-pink-700 text-center\">\n";
$htmlContent .= htmlspecialchars($plan['validity']) . " " . htmlspecialchars($plan['validity_unit']) . " Unlimited\n";
$htmlContent .= " </p>\n";
$htmlContent .= " </div>\n";
$htmlContent .= " <div class=\"px-4 pt-4 pb-6 bg-pink-500 text-center\">\n";
$htmlContent .= " <a href=\"#\" class=\"inline-block text-pink-800 bg-pink-50 hover:bg-pink-100 focus:outline-none focus:ring-4 focus:ring-pink-500 focus:ring-opacity-50 transform transition duration-150 ease-in-out rounded-lg font-semibold px-3 py-2 text-xs shadow-lg cursor-pointer\"\n";
$htmlContent .= " onclick=\"handlePhoneNumberSubmission(this.getAttribute('data-plan-id'), this.getAttribute('data-router-id')); return false;\" data-plan-id=\"" . $plan['id'] . "\" data-router-id=\"" . $routerId . "\">\n";
$htmlContent .= " Click Here To Connect\n";
$htmlContent .= " </a>\n";
$htmlContent .= " </div>\n";
$htmlContent .= " </div>\n";
}
$htmlContent .= "</div>\n";
$htmlContent .= "<!-- Testimonials Section -->\n";
$htmlContent .= "<div class=\"mt-10 mx-auto px-4 sm:px-6 lg:px-8\">\n";
$htmlContent .= " <h3 class=\"text-center text-2xl leading-8 font-extrabold tracking-tight text-gray-900 sm:text-3xl sm:leading-9\">\n";
$htmlContent .= " What Our Users Say\n";
$htmlContent .= " </h3>\n";
$htmlContent .= " <div class=\"glider-contain mt-6\">\n";
$htmlContent .= " <div class=\"glider\">\n";
// Testimonial 1
$htmlContent .= " <div class=\"bg-white rounded-lg shadow-md overflow-hidden\">\n";
$htmlContent .= " <img class=\"w-full h-48 object-cover object-center\" src=\"assets/img/testimonials/testimonials-3.jpg\" alt=\"Testimonial from Otieno Peter\">\n";
$htmlContent .= " <div class=\"p-4\">\n";
$htmlContent .= " <div class=\"uppercase tracking-wide text-sm text-indigo-500 font-semibold\">Otieno Peter</div>\n";
$htmlContent .= " <p class=\"mt-2 text-gray-500\">\"Switching to this service has been a game changer for me. The connection is reliable and fast, making my online work seamless and efficient.\"</p>\n";
$htmlContent .= " </div>\n";
$htmlContent .= " </div>\n";
// Testimonial 2
$htmlContent .= " <div class=\"bg-white rounded-lg shadow-md overflow-hidden\">\n";
$htmlContent .= " <img class=\"w-full h-48 object-cover object-center\" src=\"assets/img/testimonials/testimonials-2.jpg\" alt=\"Testimonial from Kiveu\">\n";
$htmlContent .= " <div class=\"p-4\">\n";
$htmlContent .= " <div class=\"uppercase tracking-wide text-sm text-indigo-500 font-semibold\">Kiveu</div>\n";
$htmlContent .= " <p class=\"mt-2 text-gray-500\">\"I've experienced unparalleled support and service. The team goes above and beyond to ensure customer satisfaction. Highly recommend!\"</p>\n";
$htmlContent .= " </div>\n";
$htmlContent .= " </div>\n";
// Testimonial 3
$htmlContent .= " <div class=\"bg-white rounded-lg shadow-md overflow-hidden\">\n";
$htmlContent .= " <img class=\"w-full h-48 object-cover object-center\" src=\"assets/img/testimonials/testimonials-1.jpg\" alt=\"Testimonial from Anonymous User\">\n";
$htmlContent .= " <div class=\"p-4\">\n";
$htmlContent .= " <div class=\"uppercase tracking-wide text-sm text-indigo-500 font-semibold\">Anonymous User</div>\n";
$htmlContent .= " <p class=\"mt-2 text-gray-500\">\"Their commitment to quality and speed is evident. My internet experience has been fantastic ever since I made the switch.\"</p>\n";
$htmlContent .= " </div>\n";
$htmlContent .= " </div>\n";
$htmlContent .= " </div>\n";
$htmlContent .= " <!-- Add Arrows -->\n";
$htmlContent .= " <button aria-label=\"Previous\" class=\"glider-prev\">«</button>\n";
$htmlContent .= " <button aria-label=\"Next\" class=\"glider-next\">»</button>\n";
$htmlContent .= " <div role=\"tablist\" class=\"dots\"></div>\n";
$htmlContent .= " </div>\n";
$htmlContent .= "</div>\n";
// Glider.js script for the Testimonials Section
$htmlContent .= "<script>\n";
$htmlContent .= " new Glider(document.querySelector('.glider'), {\n";
$htmlContent .= " slidesToShow: 1,\n";
$htmlContent .= " slidesToScroll: 1,\n";
$htmlContent .= " draggable: true,\n";
$htmlContent .= " dots: '.dots',\n";
$htmlContent .= " arrows: {\n";
$htmlContent .= " prev: '.glider-prev',\n";
$htmlContent .= " next: '.glider-next'\n";
$htmlContent .= " },\n";
$htmlContent .= " responsive: [\n";
$htmlContent .= " {\n";
$htmlContent .= " breakpoint: 775,\n";
$htmlContent .= " settings: {\n";
$htmlContent .= " slidesToShow: 2,\n";
$htmlContent .= " slidesToScroll: 2,\n";
$htmlContent .= " }\n";
$htmlContent .= " },\n";
$htmlContent .= " {\n";
$htmlContent .= " breakpoint: 1024,\n";
$htmlContent .= " settings: {\n";
$htmlContent .= " slidesToShow: 3,\n";
$htmlContent .= " slidesToScroll: 3,\n";
$htmlContent .= " }\n";
$htmlContent .= " }\n";
$htmlContent .= " ]\n";
$htmlContent .= " });\n";
$htmlContent .= "</script>\n";
$htmlContent .= "<!-- FAQ Section -->\n";
$htmlContent .= "<div class=\"mt-10 mx-auto px-4 sm:px-6 lg:px-8\">\n";
$htmlContent .= " <div class=\"text-center\">\n";
$htmlContent .= " <h3 class=\"text-2xl leading-8 font-extrabold tracking-tight text-gray-900 sm:text-3xl sm:leading-9\">\n";
$htmlContent .= " FREQUENTLY ASKED QUESTIONS Will Be Here\n";
$htmlContent .= " </h3>\n";
$htmlContent .= " <p class=\"mt-4 max-w-2xl text-xl leading-7 text-gray-500 lg:mx-auto\">\n";
$htmlContent .= " Everything you need to know before getting started.\n";
$htmlContent .= " </p>\n";
$htmlContent .= " </div>\n";
$htmlContent .= " <div class=\"mt-6\">\n";
$htmlContent .= " <dl class=\"space-y-6\">\n";
// FAQ 1
$htmlContent .= " <div class=\"bg-white rounded-lg shadow-md\">\n";
$htmlContent .= " <dt class=\"p-4 cursor-pointer text-lg leading-6 font-medium text-gray-900\" onclick=\"toggleFAQ('faq1')\">" . htmlspecialchars($settings['frequently_asked_questions_headline1']) . "</dt>\n";
$htmlContent .= " <dd id=\"faq1\" class=\"p-4 hidden text-base text-gray-500\">" . htmlspecialchars($settings['frequently_asked_questions_answer1']) . "</dd>\n";
$htmlContent .= " </div>\n";
// FAQ 2
$htmlContent .= " <div class=\"bg-white rounded-lg shadow-md\">\n";
$htmlContent .= " <dt class=\"p-4 cursor-pointer text-lg leading-6 font-medium text-gray-900\" onclick=\"toggleFAQ('faq2')\">" . htmlspecialchars($settings['frequently_asked_questions_headline2']) . "</dt>\n";
$htmlContent .= " <dd id=\"faq2\" class=\"p-4 hidden text-base text-gray-500\">" . htmlspecialchars($settings['frequently_asked_questions_answer2']) . "</dd>\n";
$htmlContent .= " </div>\n";
// FAQ 3
$htmlContent .= " <div class=\"bg-white rounded-lg shadow-md\">\n";
$htmlContent .= " <dt class=\"p-4 cursor-pointer text-lg leading-6 font-medium text-gray-900\" onclick=\"toggleFAQ('faq3')\">" . htmlspecialchars($settings['frequently_asked_questions_headline3']) . "</dt>\n";
$htmlContent .= " <dd id=\"faq3\" class=\"p-4 hidden text-base text-gray-500\">" . htmlspecialchars($settings['frequently_asked_questions_answer3']) . "</dd>\n";
$htmlContent .= " </div>\n";
$htmlContent .= " </dl>\n";
$htmlContent .= " </div>\n";
$htmlContent .= "</div>\n";
$htmlContent .= "<div class=\"container mx-auto px-4\">\n";
$htmlContent .= " <div class=\"max-w-md mx-auto bg-white rounded-lg overflow-hidden md:max-w-lg\">\n";
$htmlContent .= " <div class=\"md:flex\">\n";
$htmlContent .= " <div class=\"w-full p-5\">\n";
$htmlContent .= " <div class=\"text-center\">\n";
$htmlContent .= " <h3 class=\"text-2xl text-gray-900\">Already Have an Active Package?</h3>\n";
$htmlContent .= " </div>\n";
$htmlContent .= " <form id=\"loginForm\" class=\"form\" name=\"login\" action=\"$(link-login-only)\" method=\"post\" $(if chap-id)onSubmit=\"return doLogin()\"$(endif)>\n";
$htmlContent .= " <input type=\"hidden\" name=\"dst\" value=\"$(link-orig)\" />\n";
$htmlContent .= " <input type=\"hidden\" name=\"popup\" value=\"true\" />\n";
$htmlContent .= " <div class=\"mb-4\">\n";
$htmlContent .= " <label class=\"block text-gray-700 text-sm font-bold mb-2\" for=\"username\">Username</label>\n";
$htmlContent .= " <input id=\"usernameInput\" class=\"shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline\" name=\"username\" type=\"text\" value=\"\" placeholder=\"Username\">\n";
$htmlContent .= " </div>\n";
$htmlContent .= " <div class=\"mb-6\">\n";
$htmlContent .= " <label class=\"block text-gray-700 text-sm font-bold mb-2\" for=\"password\">Password</label>\n";
$htmlContent .= " <input id=\"passwordInput\" class=\"shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 mb-3 leading-tight focus:outline-none focus:shadow-outline\" name=\"password\" type=\"password\" placeholder=\"******************\">\n";
$htmlContent .= " </div>\n";
$htmlContent .= " <div class=\"flex items-center justify-between\">\n";
$htmlContent .= " <button id=\"submitBtn\" class=\"bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline\" type=\"button\">\n";
$htmlContent .= " Click Here To Connect\n";
$htmlContent .= " </button>\n";
$htmlContent .= " </div>\n";
$htmlContent .= " </form>\n";
$htmlContent .= " </div>\n";
$htmlContent .= " </div>\n";
$htmlContent .= " </div>\n";
$htmlContent .= "</div>\n";
$htmlContent .= "<script>\n";
$htmlContent .= "document.addEventListener('DOMContentLoaded', function() {\n";
$htmlContent .= " function autofillLogin() {\n";
$htmlContent .= " var phoneNumber = '2547xxxxxxx';\n";
$htmlContent .= " var password = '1234';\n";
$htmlContent .= " document.querySelector('input[name=\"username\"]').value = phoneNumber;\n";
$htmlContent .= " document.querySelector('input[name=\"password\"]').value = password;\n";
$htmlContent .= " setTimeout(function() {\n";
$htmlContent .= " document.querySelector('button[type=\"submit\"]').click();\n";
$htmlContent .= " }, 15000);\n";
$htmlContent .= " }\n";
$htmlContent .= " autofillLogin();\n";
$htmlContent .= "});\n";
$htmlContent .= "</script>\n";
$htmlContent .= "<script>\n";
$htmlContent .= "function toggleFAQ(faqId) {\n";
$htmlContent .= " var element = document.getElementById(faqId);\n";
$htmlContent .= " if (element.style.display === \"block\") {\n";
$htmlContent .= " element.style.display = \"none\";\n";
$htmlContent .= " } else {\n";
$htmlContent .= " element.style.display = \"block\";\n";
$htmlContent .= " }\n";
$htmlContent .= "}\n";
$htmlContent .= "</script>\n";
$htmlContent .= "</section>\n";
$htmlContent .= "</main>\n";
$htmlContent .= "<!-- Footer -->\n";
$htmlContent .= "<footer class=\"bg-blue-900 text-white\">\n";
$htmlContent .= " <div class=\"max-w-7xl mx-auto px-4 py-12 sm:px-6 lg:px-8\">\n";
$htmlContent .= " <div class=\"lg:grid lg:grid-cols-3 lg:gap-8\">\n";
$htmlContent .= " <div class=\"lg:col-span-1\">\n";
$htmlContent .= " <h2 class=\"text-sm font-semibold uppercase tracking-wider\">\n";
$htmlContent .= " Contact Us\n";
$htmlContent .= " </h2>\n";
$htmlContent .= " <ul class=\"mt-4 space-y-4\">\n";
$htmlContent .= " <li>\n";
$htmlContent .= " <span class=\"block\">Address</span>\n";
$htmlContent .= " </li>\n";
$htmlContent .= " <li>\n";
$htmlContent .= " <span class=\"block\">Email: contact@" . htmlspecialchars($company) . "</span>\n";
$htmlContent .= " </li>\n";
$htmlContent .= " <li>\n";
$htmlContent .= " <span class=\"block\">Phone: " . htmlspecialchars($phone) . "</span>\n";
$htmlContent .= " </li>\n";
$htmlContent .= " </ul>\n";
$htmlContent .= " </div>\n";
$htmlContent .= " <div class=\"lg:col-span-1\">\n";
$htmlContent .= " <h2 class=\"text-sm font-semibold uppercase tracking-wider\">\n";
$htmlContent .= " Quick Links\n";
$htmlContent .= " </h2>\n";
$htmlContent .= " <ul class=\"mt-4 space-y-4\">\n";
$htmlContent .= " <li><a href=\"#\" class=\"hover:underline\">About Us</a></li>\n";
$htmlContent .= " <li><a href=\"#\" class=\"hover:underline\">Our Services</a></li>\n";
$htmlContent .= " <li><a href=\"#\" class=\"hover:underline\">FAQ</a></li>\n";
$htmlContent .= " <li><a href=\"#\" class=\"hover:underline\">Support</a></li>\n";
$htmlContent .= " </ul>\n";
$htmlContent .= " </div>\n";
$htmlContent .= " <div class=\"lg:col-span-1\">\n";
$htmlContent .= " <h2 class=\"text-sm font-semibold uppercase tracking-wider\">\n";
$htmlContent .= " Follow Us\n";
$htmlContent .= " </h2>\n";
$htmlContent .= " <div class=\"mt-4 space-x-4\">\n";
$htmlContent .= " <a href=\"#\" class=\"hover:text-gray-400\"><i class=\"fab fa-facebook-f\"></i></a>\n";
$htmlContent .= " <a href=\"#\" class=\"hover:text-gray-400\"><i class=\"fab fa-twitter\"></i></a>\n";
$htmlContent .= " <a href=\"#\" class=\"hover:text-gray-400\"><i class=\"fab fa-instagram\"></i></a>\n";
$htmlContent .= " <a href=\"#\" class=\"hover:text-gray-400\"><i class=\"fab fa-linkedin-in\"></i></a>\n";
$htmlContent .= " </div>\n";
$htmlContent .= " </div>\n";
$htmlContent .= " </div>\n";
$htmlContent .= " <div class=\"mt-8 border-t border-gray-700 pt-8 md:flex md:items-center md:justify-between\">\n";
$htmlContent .= " <div class=\"flex space-x-6 md:order-2\">\n";
$htmlContent .= " <a href=\"#\" class=\"text-gray-400 hover:text-gray-300\"><span class=\"sr-only\">Facebook</span><i class=\"fab fa-facebook-f\"></i></a>\n";
$htmlContent .= " <a href=\"#\" class=\"text-gray-400 hover:text-gray-300\"><span class=\"sr-only\">Instagram</span><i class=\"fab fa-instagram\"></i></a>\n";
$htmlContent .= " <a href=\"#\" class=\"text-gray-400 hover:text-gray-300\"><span class=\"sr-only\">Twitter</span><i class=\"fab fa-twitter\"></i></a>\n";
$htmlContent .= " <a href=\"#\" class=\"text-gray-400 hover:text-gray-300\"><span class=\"sr-only\">LinkedIn</span><i class=\"fab fa-linkedin-in\"></i></a>\n";
$htmlContent .= " </div>\n";
$htmlContent .= "<p class=\"mt-8 text-base leading-6 text-gray-400 md:mt-0 md:order-1\">\n";
$htmlContent .= " &copy; 2024 " . htmlspecialchars($company) . " All rights reserved.\n";
$htmlContent .= " </p>\n";
$htmlContent .= " </div>\n";
$htmlContent .= " </div>\n";
$htmlContent .= "</footer>\n";
$htmlContent .= "<script src=\"https://cdn.jsdelivr.net/npm/sweetalert2@11\"></script>\n";
$htmlContent .= "<script>\n";
$htmlContent .= " function formatPhoneNumber(phoneNumber) {\n";
$htmlContent .= " if (phoneNumber.startsWith('+')) {\n";
$htmlContent .= " phoneNumber = phoneNumber.substring(1);\n";
$htmlContent .= " }\n";
$htmlContent .= " if (phoneNumber.startsWith('0')) {\n";
$htmlContent .= " phoneNumber = '254' + phoneNumber.substring(1);\n";
$htmlContent .= " }\n";
$htmlContent .= " if (phoneNumber.match(/^(7|1)/)) {\n";
$htmlContent .= " phoneNumber = '254' + phoneNumber;\n";
$htmlContent .= " }\n";
$htmlContent .= " return phoneNumber;\n";
$htmlContent .= " }\n";
$htmlContent .= "\n";
$htmlContent .= " function handlePhoneNumberSubmission(planId, routerId) {\n";
$htmlContent .= " Swal.fire({\n";
$htmlContent .= " title: 'Enter Your Phone Number',\n";
$htmlContent .= " input: 'text',\n";
$htmlContent .= " inputPlaceholder: 'Your phone number here',\n";
$htmlContent .= " inputAttributes: {\n";
$htmlContent .= " autocapitalize: 'off'\n";
$htmlContent .= " },\n";
$htmlContent .= " showCancelButton: true,\n";
$htmlContent .= " confirmButtonColor: '#3085d6',\n";
$htmlContent .= " cancelButtonColor: '#d33',\n";
$htmlContent .= " confirmButtonText: 'Submit',\n";
$htmlContent .= " showLoaderOnConfirm: true,\n";
$htmlContent .= " backdrop: `\n";
$htmlContent .= " rgba(0,0,123,0.4)\n";
$htmlContent .= " url(\"https://sweetalert2.github.io/images/nyan-cat.gif\")\n";
$htmlContent .= " center left\n";
$htmlContent .= " no-repeat\n";
$htmlContent .= " `,\n";
$htmlContent .= " preConfirm: (phoneNumber) => {\n";
$htmlContent .= " var formattedPhoneNumber = formatPhoneNumber(phoneNumber);\n";
$htmlContent .= " document.getElementById('usernameInput').value = formattedPhoneNumber;\n";
$htmlContent .= " console.log(\"Phone number for autofill:\", formattedPhoneNumber);\n";
$htmlContent .= "\n";
$htmlContent .= " return fetch('" . APP_URL . "/index.php?_route=plugin/CreateHotspotuser&type=grant', {\n";
$htmlContent .= " method: 'POST',\n";
$htmlContent .= " headers: {'Content-Type': 'application/json'},\n";
$htmlContent .= " body: JSON.stringify({phone_number: formattedPhoneNumber, plan_id: planId, router_id: routerId}),\n";
$htmlContent .= " })\n";
$htmlContent .= " .then(response => {\n";
$htmlContent .= " if (!response.ok) throw new Error('Network response was not ok');\n";
$htmlContent .= " return response.json();\n";
$htmlContent .= " })\n";
$htmlContent .= " .then(data => {\n";
$htmlContent .= " if (data.status === 'error') throw new Error(data.message);\n";
$htmlContent .= " Swal.fire({\n";
$htmlContent .= " title: 'Connecting in 35 Secs...',\n";
$htmlContent .= " html: `Remaining time is <b>\${formattedPhoneNumber}</b>.<br>A payment request has been sent to <b>\${formattedPhoneNumber}</b>. Dont click anything until you are connected. Still on this page after the timer ended? Scroll down and Click Login Now`,\n";
$htmlContent .= " timer: 35000, // Adjusted for 35 seconds\n";
$htmlContent .= " timerProgressBar: true,\n";
$htmlContent .= " didOpen: () => {\n";
$htmlContent .= " Swal.showLoading();\n";
$htmlContent .= " const timer = Swal.getPopup().querySelector(\"b\");\n";
$htmlContent .= " timerInterval = setInterval(() => {\n";
$htmlContent .= " timer.textContent = `\${Swal.getTimerLeft()}`;\n";
$htmlContent .= " }, 100);\n";
$htmlContent .= " },\n";
$htmlContent .= " willClose: () => {\n";
$htmlContent .= " clearInterval(timerInterval);\n";
$htmlContent .= " }\n";
$htmlContent .= " }).then((result) => {\n";
$htmlContent .= " if (result.dismiss === Swal.DismissReason.timer) {\n";
$htmlContent .= " console.log('I was closed by the timer');\n";
$htmlContent .= " document.getElementById('submitBtn').click();\n";
$htmlContent .= " }\n";
$htmlContent .= " });\n";
$htmlContent .= " return formattedPhoneNumber; \n";
$htmlContent .= " })\n";
$htmlContent .= " .catch(error => {\n";
$htmlContent .= " Swal.fire({\n";
$htmlContent .= " icon: 'error',\n";
$htmlContent .= " title: 'Oops...',\n";
$htmlContent .= " text: error.message,\n";
$htmlContent .= " });\n";
$htmlContent .= " });\n";
$htmlContent .= " },\n";
$htmlContent .= " allowOutsideClick: () => !Swal.isLoading()\n";
$htmlContent .= " });\n";
$htmlContent .= " }\n";
$htmlContent .= "\n";
$htmlContent .= " function FetchAjax(phoneNumber) {\n";
$htmlContent .= " refreshData();\n";
$htmlContent .= " }\n";
$htmlContent .= "\n";
$htmlContent .= " function refreshData() {\n";
$htmlContent .= " function refreshDataInternal() {\n";
$htmlContent .= " $.ajax({\n";
$htmlContent .= " url: '" . APP_URL . "/index.php?_route=plugin/CreateHotspotuser&type=verify',\n";
$htmlContent .= " method: \"POST\",\n";
$htmlContent .= " data: {phone_number: document.getElementById('usernameInput').value},\n";
$htmlContent .= " dataType: \"json\",\n";
$htmlContent .= " success: function(data) {\n";
$htmlContent .= " // Response handling code\n";
$htmlContent .= " },\n";
$htmlContent .= " error: function(xhr, textStatus, errorThrown) {\n";
$htmlContent .= " console.log(\"Error: \" + errorThrown);\n";
$htmlContent .= " }\n";
$htmlContent .= " });\n";
$htmlContent .= " }\n";
$htmlContent .= " var refreshInterval = setInterval(refreshDataInternal, 2000);\n";
$htmlContent .= " }\n";
$htmlContent .= "\n";
$htmlContent .= " document.addEventListener('DOMContentLoaded', function() {\n";
$htmlContent .= " var submitBtn = document.getElementById('submitBtn');\n";
$htmlContent .= " if (submitBtn) {\n";
$htmlContent .= " submitBtn.addEventListener('click', function(event) {\n";
$htmlContent .= " event.preventDefault();\n";
$htmlContent .= " document.getElementById('loginForm').submit();\n";
$htmlContent .= " });\n";
$htmlContent .= " }\n";
$htmlContent .= " });\n";
$htmlContent .= "</script>\n";
$htmlContent .= "<script src=\"https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js\"></script>\n";
$htmlContent .= "<script>\n";
$htmlContent .= "document.addEventListener('DOMContentLoaded', function() {\n";
$htmlContent .= " // Ensure the button is correctly targeted by its ID.\n";
$htmlContent .= " var submitBtn = document.getElementById('submitBtn');\n";
$htmlContent .= " \n";
$htmlContent .= " // Add a click event listener to the \"Login Now\" button.\n";
$htmlContent .= " submitBtn.addEventListener('click', function(event) {\n";
$htmlContent .= " event.preventDefault(); // Prevent the default button action.\n";
$htmlContent .= " \n";
$htmlContent .= " // Optional: Log to console for debugging purposes.\n";
$htmlContent .= " console.log(\"Login Now button clicked.\");\n";
$htmlContent .= " \n";
$htmlContent .= " // Direct form submission, bypassing the doLogin function for simplicity.\n";
$htmlContent .= " var form = document.getElementById('loginForm');\n";
$htmlContent .= " form.submit(); // Submit the form directly.\n";
$htmlContent .= " });\n";
$htmlContent .= "});\n";
$htmlContent .= "</script>\n";
$htmlContent .= "</html>\n";
$planStmt->close();
$mysqli->close();
// Check if the download parameter is set
if (isset($_GET['download']) && $_GET['download'] == '1') {
// Prepare the HTML content for download
// ... build your HTML content ...
// Specify the filename for the download
$filename = "login.html";
// Send headers to force download
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.basename($filename));
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . strlen($htmlContent));
// Output the content
echo $htmlContent;
// Prevent any further output
exit;
}
// Regular page content goes here
// ... HTML and PHP code to display the page ...

View File

@ -0,0 +1,117 @@
{include file="sections/header.tpl"}
<section class="content-header">
<h1>
<div class="btn-group">
<button type="button" class="btn btn-success">
Hotspot Settings
</button>
<button type="button" class="btn btn-success dropdown-toggle" data-toggle="dropdown">
<span class="caret"></span>
<span class="sr-only">Toggle Dropdown</span>
</button>
<ul class="dropdown-menu" role="menu">
<li><a href="{$_url}plugin/hotspot_settings">{Lang::T('General Settings')}</a></li>
<li class="divider"></li>
<li><a href="{$_url}plugin/captive_portal_login" target="_blank">Preview Hotspot Login Page</a></li>
<li><a href="{$app_url}/system/plugin/download.php?download=1" target="_blank">Download Login Page</a></li>
</ul>
</div>
</h1>
<ol class="breadcrumb">
<li><a href="{$app_url}/system/plugin/download.php?download=1"><i class="fa fa-dashboard"></i> Click Here To Download Login Page</a></li>
<li class="active">Hotspot Settings</li>
</ol>
</section>
<section class="content">
<div class="table-responsive">
<div class="nav-tabs-custom">
<ul class="nav nav-tabs">
<li class="active"><a href="#tab_1" data-toggle="tab">{Lang::T('General Settings')}</a></li>
</ul>
<div class="tab-content">
<div class="tab-pane active" id="tab_1" style="overflow-x:auto;">
<div class="box-body no-padding" id="">
<form method="POST" action="" enctype="multipart/form-data">
<div class="box-body">
<div class="form-group">
<label for="hotspot_title">Hotspot Page Title</label>
<input type="text" class="form-control" name="hotspot_title" id="hotspot_title" value="{$hotspot_title}" required>
<small class="form-text text-muted">In this field, you can enter the name of your ISP company. It will appear as the main title on the hotspot page.</small>
</div>
<div class="form-group">
<label for="description">Brief Description Of Company/Tagline</label>
<input type="text" class="form-control" name="description" id="description" value="{$description}" required>
</div>
<div class="form-group">
<label for="router_name">Router Name:</label>
<input type="text" class="form-control" name="router_name" id="router_name" value="{$router_name}" required>
<small class="form-text text-muted">This is the most important part of the form. Go to Network and then Routers, and copy the exact router name.</small>
</div>
<!-- FAQ fields -->
<div class="form-group">
<label for="frequently_asked_questions_headline1">FAQ Headline 1</label>
<input type="text" class="form-control" name="frequently_asked_questions_headline1" id="frequently_asked_questions_headline1" value="{$frequently_asked_questions_headline1}" required>
</div>
<div class="form-group">
<label for="frequently_asked_questions_answer1">FAQ Answer 1</label>
<textarea class="form-control" id="frequently_asked_questions_answer1" name="frequently_asked_questions_answer1" required>{$frequently_asked_questions_answer1}</textarea>
</div>
<div class="form-group">
<label for="frequently_asked_questions_headline2">FAQ Headline 2</label>
<input type="text" class="form-control" id="frequently_asked_questions_headline2" name="frequently_asked_questions_headline2" value="{$frequently_asked_questions_headline2}" required>
</div>
<div class="form-group">
<label for="frequently_asked_questions_answer2">FAQ Answer 2</label>
<textarea class="form-control" id="frequently_asked_questions_answer2" name="frequently_asked_questions_answer2" required>{$frequently_asked_questions_answer2}</textarea>
</div>
<div class="form-group">
<label for="frequently_asked_questions_headline3">FAQ Headline 3</label>
<input type="text" class="form-control" name="frequently_asked_questions_headline3" id="frequently_asked_questions_headline3" value="{$frequently_asked_questions_headline3}" required>
</div>
<div class="form-group">
<label for="frequently_asked_questions_answer3">FAQ Answer 3</label>
<textarea class="form-control" id="frequently_asked_questions_answer3" name="frequently_asked_questions_answer3" required>{$frequently_asked_questions_answer3}</textarea>
</div>
<!-- Save Changes button -->
<button type="submit" class="btn btn-info pull-right">Save Changes</button>
</form>
<div class="tab-pane" id="tab_6" style="overflow-x:auto;">
<div class="box-body no-padding" id="">
<!-- Content for Pages Settings tab -->
This feature will be Coming Soon
</div>
</div>
</div>
</div>
<div>
<pre><b>USAGE:</b>
<br>Make sure you change this custom Settings and personalize them.
<br>Then download the <strong style="color: black; background-color: yellow;">login.html</strong> by clicking on download login page.
<br>Then upload the downloaded <strong style="color: black; background-color: yellow;">login.html</strong> file to your Mikrotik router.
<br>Make sure you add your website URL in Mikrotik hotspot wall garden. <strong style="color: black; background-color: yellow;">login.html</strong>
</pre>
</div>
</section>
{include file="sections/footer.tpl"}

BIN
system/plugin/ui/index.html Normal file

Binary file not shown.

154
system/plugin/ui/log.tpl Normal file
View File

@ -0,0 +1,154 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Log UI</title>
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
</head>
{include file="sections/header.tpl"}
<body class="bg-gray-100 font-sans leading-normal tracking-normal">
<div class="container mx-auto mt-8 bg-white rounded-lg shadow-lg p-6">
<form class="mb-4" method="post" role="form" action="{$_url}plugin/log_ui">
<ul class="nav nav-tabs flex border-b">
{foreach $routers as $r}
<li class="mr-1" role="presentation" {if $r['id']==$router}class="active"{/if}>
<a class="bg-white inline-block py-2 px-4 text-blue-500 hover:text-blue-800 font-semibold" href="{$_url}plugin/log_ui/{$r['id']}">{$r['name']}</a>
</li>
{/foreach}
</ul>
</form>
<div class="flex flex-wrap mb-4">
<div class="w-full md:w-8/12">
<label class="block">
Show entries
<select name="data_length" aria-controls="data" class="form-control form-control-sm" onchange="updatePerPage(this.value)">
<option value="5" {if $per_page == 5}selected{/if}>5</option>
<option value="10" {if $per_page == 10}selected{/if}>10</option>
<option value="25" {if $per_page == 25}selected{/if}>25</option>
<option value="50" {if $per_page == 50}selected{/if}>50</option>
<option value="100" {if $per_page == 100}selected{/if}>100</option>
</select>
</label>
</div>
<div class="w-full md:w-4/12">
<label class="block">
Search:
<input type="search" id="logSearch" class="form-control form-control-sm" placeholder="Search logs" aria-controls="data" onkeyup="filterLogs()">
</label>
</div>
</div>
<table class="min-w-full bg-white table-auto">
<thead>
<tr class="bg-gray-200">
<th class="w-1/3 py-2 px-4">Time</th>
<th class="w-1/3 py-2 px-4">Topic</th>
<th class="w-1/3 py-2 px-4">Message</th>
</tr>
</thead>
<tbody id="logTableBody">
{assign var=current_page value=$smarty.get.page|default:1}
{assign var=per_page value=$smarty.get.per_page|default:10}
{assign var=start_index value=($current_page - 1) * $per_page}
{foreach from=$logs|array_reverse item=log name=logLoop}
{if $smarty.foreach.logLoop.index >= $start_index && $smarty.foreach.logLoop.index < ($start_index + $per_page)}
<tr class="log-entry">
<td class="border px-4 py-2">{$log.time}</td>
<td class="border px-4 py-2">{$log.topics}</td>
<td class="border px-4 py-2 log-message">
{if $log.message|lower|strpos:'failed' !== false}
<span class="text-red-700 text-bold">{$log.message}</span>
{elseif $log.message|lower|strpos:'trying' !== false}
<span class="text-yellow-700">{$log.message}</span>
{elseif $log.message|lower|strpos:'logged in' !== false}
<span class="text-green-700">{$log.message}</span>
{elseif $log.message|lower|strpos:'login failed' !== false}
<span class="text-blue-700">{$log.message}</span>
{else}
<span class="text-gray-700">{$log.message}</span>
{/if}
</td>
</tr>
{/if}
{/foreach}
</tbody>
</table>
{assign var=total_logs value=$logs|@count}
{assign var=last_page value=ceil($total_logs / $per_page)}
<nav class="mt-4">
<ul class="pagination flex justify-center">
{if $current_page > 1}
<li>
<a class="page-link border py-2 px-4 mx-1" href="index.php?_route=plugin/log_ui&page=1&per_page={$per_page}" aria-label="First">&laquo;&laquo;</a>
</li>
<li>
<a class="page-link border py-2 px-4 mx-1" href="index.php?_route=plugin/log_ui&page={$current_page-1}&per_page={$per_page}" aria-label="Previous">&laquo;</a>
</li>
{/if}
{assign var=max_links value=5}
{assign var=start_page value=max(1, $current_page - floor($max_links / 2))}
{assign var=end_page value=min($last_page, $start_page + $max_links - 1)}
{if $start_page > 1}
<li>
<a class="page-link border py-2 px-4 mx-1" href="index.php?_route=plugin/log_ui&page={$start_page-1}&per_page={$per_page}" aria-label="Previous">&hellip;</a>
</li>
{/if}
{foreach from=range($start_page, $end_page) item=page}
<li>
<a class="page-link border py-2 px-4 mx-1 {if $page == $current_page}bg-blue-500 text-white{/if}" href="index.php?_route=plugin/log_ui&page={$page}&per_page={$per_page}">{$page}</a>
</li>
{/foreach}
{if $end_page < $last_page}
<li>
<a class="page-link border py-2 px-4 mx-1" href="index.php?_route=plugin/log_ui&page={$end_page+1}&per_page={$per_page}" aria-label="Next">&hellip;</a>
</li>
{/if}
{if $current_page < $last_page}
<li>
<a class="page-link border py-2 px-4 mx-1" href="index.php?_route=plugin/log_ui&page={$current_page+1}&per_page={$per_page}" aria-label="Next">&raquo;</a>
</li>
<li>
<a class="page-link border py-2 px-4 mx-1" href="index.php?_route=plugin/log_ui&page={$last_page}&per_page={$per_page}" aria-label="Last">&raquo;&raquo;</a>
</li>
{/if}
</ul>
</nav>
</div>
<script>
function updatePerPage(value) {
var urlParams = new URLSearchParams(window.location.search);
urlParams.set('per_page', value);
urlParams.set('page', 1); // Reset to first page
window.location.search = urlParams.toString();
}
function filterLogs() {
var input = document.getElementById('logSearch').value.toLowerCase();
var table = document.getElementById('logTableBody');
var tr = table.getElementsByClassName('log-entry');
for (var i = 0; i < tr.length; i++) {
var logMessage = tr[i].getElementsByClassName('log-message')[0].textContent || tr[i].getElementsByClassName('log-message')[0].innerText;
if (logMessage.toLowerCase().indexOf(input) > -1) {
tr[i].style.display = '';
} else {
tr[i].style.display = 'none';
}
}
}
</script>
{include file="sections/footer.tpl"}
</body>
</html>

View File

@ -0,0 +1,34 @@
{include file="sections/header.tpl"}
<form class="form-horizontal" method="post" role="form" action="{$_url}plugin/port_tester">
<div class="row">
<div class="col-sm-12 col-md-12">
<div class="panel panel-primary panel-hovered panel-stacked mb30">
<div class="panel-heading">Testing port external</div>
<div class="panel-body">
<div class="form-group">
<label class="col-md-2 control-label">Port</label>
<div class="col-md-6">
<input type="text" id="port" name="port" value="{$port}" placeholder="8728" class="form-control">
</div>
</div>
<div class="form-group">
<div class="col-lg-offset-2 col-lg-10">
<button class="btn btn-success waves-effect waves-light" type="submit">Test It</button>
</div>
</div>
</div>
</div>
{if $result != ''}
<div class="panel panel-primary panel-hovered panel-stacked mb30">
<div class="panel-heading">Result</div>
<div class="panel-body">
{Lang::nl2br($result)}
</div>
</div>
{/if}
</div>
</div>
</form>
{include file="sections/footer.tpl"}

View File

@ -0,0 +1,943 @@
{include file="sections/header.tpl"}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script src="https://cdn.datatables.net/1.10.23/js/jquery.dataTables.min.js"></script>
<link rel="stylesheet" href="https://cdn.datatables.net/1.10.23/css/jquery.dataTables.min.css">
<link rel="stylesheet" href="https://cdn.datatables.net/buttons/1.7.1/css/buttons.dataTables.min.css">
<script src="https://cdn.datatables.net/buttons/1.7.1/js/dataTables.buttons.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/apexcharts"></script>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdn.datatables.net/1.11.3/js/jquery.dataTables.min.js"></script>
<script src="https://cdn.datatables.net/1.11.3/js/dataTables.bootstrap5.min.js"></script>
<style>
.modal {
display: none;
position: fixed;
z-index: 1;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: auto;
background-color: rgba(0, 0, 0, 0.4);
}
.modal-content {
background-color: #fefefe;
margin: 15% auto;
padding: 0px;
border: 1px solid #888;
width: 80%;
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
max-width: 600px;
}
.close {
color: #aaa;
float: right;
font-size: 28px;
font-weight: bold;
cursor: pointer;
}
.close:hover,
.close:focus {
color: black;
text-decoration: none;
}
.card-body {
padding: 1rem;
}
.card-header {
padding: .75rem 1.25rem;
margin-bottom: 0;
background-color: none;
border-bottom: 1px solid rgba(0,0,0,.125);
}
.card-title {
margin-bottom: .75rem;
}
.form-group {
margin-bottom: 1rem;
}
.table-responsive {
display: block;
width: 100%;
overflow-x: auto;
-webkit-overflow-scrolling: touch;
-ms-overflow-style: -ms-autohiding-scrollbar;
}
.table {
width: 100%;
margin-bottom: 1rem;
color: #212529;
}
.container {
padding-top: 20px;
}
#ppp-table_wrapper {
padding: 15px;
}
#ppp-table th, #ppp-table td {
text-align: center;
padding: 6px;
}
.table-striped tbody tr:nth-of-type(odd) {
background-color: #f9f9f9;
}
.panel-default {
border-color: #ddd;
}
.panel-heading {
background-color: #f5f5f5;
border-color: #ddd;
}
.nav-tabs {
margin-bottom: 15px;
}
.nav-tabs > li > a {
border-radius: 0;
color: #555;
background-color: #f9f9f9;
border-color: #ddd;
}
.nav-tabs > li.active > a,
.nav-tabs > li.active > a:focus,
.nav-tabs > li.active > a:hover {
background-color: #fff;
color: #333;
border: 1px solid #ddd;
border-bottom-color: transparent;
cursor: default;
}
.table-striped tbody tr:nth-of-type(odd) {
background-color: #f9f9f9;
}
.table th {
background-color: #f5f5f5;
color: #333;
font-weight: bold;
padding: 8px;
}
.table-striped > tbody > tr > td {
background-color: #fff;
}
.status-connect {
color: #5cb85c;
}
.status-disconnect {
color: #d9534f;
}
.modalsupport {
display: none;
position: fixed;
z-index: 1;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: auto;
background-color: rgb(0,0,0);
background-color: rgba(0,0,0,0.4);
justify-content: center;
align-items: center;
}
.modalsupport-content {
background-color: #fefefe;
margin: auto;
padding: 0px;
border: 1px solid #888;
width: 80%;
max-width: 500px;
box-shadow: 0 5px 15px rgba(0,0,0,0.3);
text-align: center;
}
.modalsupport-close {
color: #aaa;
float: right;
font-size: 28px;
font-weight: bold;
}
.modalsupport-close:hover,
.modalsupport-close:focus {
color: black;
text-decoration: none;
cursor: pointer;
}
.card {
border: none;
}
.card-header {
background-color: none;
border-bottom: none;
}
.card-body {
padding: 20px;
}
.donate-button {
margin-top: 10px;
}
.modalsupport img {
width: 100px;
height: auto;
margin-top: 15px;
}
.dataSize {
white-space: nowrap;
}
.action-icons i {
cursor: pointer;
margin-right: 10px;
color: #007bff;
}
.action-icons i:hover {
color: #0056b3;
}
.modal-title {
text-align: center;
width: 100%;
display: block;
font-size: 20px;
font-weight: bold;
margin-top: 20px;
}
.table-bordered {
width: 100%;
max-width: 100%;
table-layout: fixed;
}
.table-bordered th, .table-bordered td {
width: auto;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
background: none;
border: none;
padding: 5px;
vertical-align: middle;
text-align: center;
}
.advanced-search-container {
margin-bottom: 20px;
padding: 15px;
background-color: #f9f9f9;
border: 1px solid #ddd;
}
.form-inline .form-group {
margin-right: 10px;
}
.dataTables_filter {
display: none;
}
@media (max-width: 768px) {
.panel-default {
padding: 10px;
margin: 0;
}
.panel-heading {
padding: 5px 15px;
}
.panel-body {
padding: 5px 10px;
}
.table th, .table td {
font-size: 15px; /* Mengurangi ukuran font pada tabel */
}
}
.traffic-icon {
display: inline-block;
width: 10px;
height: 10px;
border-radius: 50%;
margin-right: 5px;
vertical-align: middle;
}
.traffic-icon-green {
background-color: green;
}
.traffic-icon-yellow {
background-color: yellow;
}
.traffic-icon-red {
background-color: red;
}
.text-left {
text-align: left !important;
}
</style>
<div class="container">
<div class="row">
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12">
<!-- Form dan navigasi tabs -->
<form class="form-horizontal" method="post" role="form" action="{$_url}plugin/pppoe">
<div class="form-group">
<label for="routerSelect" class="col-sm-2 control-label">Select Router</label>
<div class="col-sm-10">
<select id="routerSelect" name="router" class="form-control" onchange="window.location.href=this.value;">
{foreach $routers as $r}
<option value="{$_url}plugin/pppoe/{$r['id']}" {if $r['id'] == $router}selected{/if}>
{$r['name']}
</option>
{/foreach}
</select>
</div>
</div>
</form>
<div class="advanced-search-container">
<form id="advancedSearchForm" class="form-inline">
<div class="form-group">
<label for="searchUsername">Username:</label>
<input type="text" class="form-control" id="searchUsername" placeholder="Enter username">
</div>
<div class="form-group">
<label for="searchStatus">Status:</label>
<select class="form-control" id="searchStatus">
<option value="">Any</option>
<option value="Connected">Connected</option>
<option value="Disconnected">Disconnected</option>
</select>
</div>
</form>
</div>
<div class="panel panel-default">
<div class="table-responsive">
<div class="panel-body">
<table class="table table-striped" id="ppp-table">
<thead>
<tr>
<th>ID</th>
<th>Username</th>
<th>IP Address</th>
<th>Uptime</th>
<th>Service</th>
<th>Caller ID</th>
<th>Device</th>
<th>Download</th>
<th>Upload</th>
<th>Total Usage</th>
<th>Status</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<!-- Isi tabel akan dimasukkan melalui JavaScript -->
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
<div id="detailsModal" class="modal">
<div class="modal-content">
<span class="close">&times;</span>
<div class="container-fluid mt-5">
<div class="card">
<div class="card-header">
<h5 class="modal-title">Data Usage for <span id="modalUsername"></span></h5>
</div>
<div class="card-body">
<div class="table-responsive mt-4">
<table class="table table-bordered">
<thead>
<tr>
<input type="hidden" id="interface" value="">
<th id="tabletx"><i class="fa fa-download"></i></th>
<th id="tablerx"><i class="fa fa-upload"></i></th>
</tr>
</thead>
</table>
</div>
<div id="chart" class="mt-3"></div>
<div id="dailyChart" class="mt-3"></div>
</div>
</div>
</div>
</div>
</div>
<script>
var $j = jQuery.noConflict();
$j(document).ready(function() {
var table = $j('#ppp-table').DataTable({
responsive: true,
columns: [
{ data: 'id', visible: false },
{
data: 'username',
className: 'text-left',
render: function(data, type, row) {
return '<div style="width: 150px;"><i class="traffic-icon traffic-icon-green"></i> ' + data + '</div>';
}
},
{ data: 'address' },
{ data: 'uptime' },
{ data: 'service' },
{ data: 'caller_id' },
{ data: 'manufacturer' }, // New column for device/manufacturer
{ data: 'tx', className: 'dataSize' },
{ data: 'rx', className: 'dataSize' },
{ data: 'total', className: 'dataSize' },
{
data: 'status',
render: function(data) {
if (data === 'Connected') {
return '<small class="label bg-green">Connected</small>';
} else if (data === 'Disconnected') {
return '<small class="label bg-red">Disconnected</small>';
} else {
return '';
}
}
},
{
data: null,
render: function(data, type, row) {
return '<div class="action-icons" style="display: flex; align-items: center;">' +
'<i class="fa fa-area-chart view-details" style="color: blue; cursor: pointer;" title="View Traffic" data-username="' + row.username + '" data-id="' + row.id + '"></i> ' +
'<i class="fa fa-retweet reconnect-button" style="color: red; cursor: pointer;" title="Reconnect" data-username="' + row.username + '" data-id="' + row.id + '"></i> ' +
'<button class="btn btn-sm ' + (row.is_bound ? 'btn-danger' : 'btn-success') + ' bind-button" data-username="' + row.username + '" data-caller-id="' + row.caller_id + '" data-is-bound="' + row.is_bound + '">' +
(row.is_bound ? 'Unbind' : 'Bind') + '</button>' +
'</div>';
}
}
],
order: [[0, 'asc']],
pageLength: 10,
lengthMenu: [[10, 25, 50, -1], [10, 25, 50, 'All']],
dom: 'Bfrtip',
buttons: ['reset', 'pageLength'],
paging: true,
info: true,
searching: true,
ajax: {
url: '{$_url}plugin/pppoe_get_combined_users/{$router}',
dataSrc: ''
}
});
// Fungsi untuk mendapatkan batas maksimum
function getMaxLimit(data) {
if (data.hasOwnProperty('max_limit')) {
return data.max_limit.toString();
} else {
return 'N/A';
}
}
// Handle view details icon clicks
$j('#ppp-table tbody').on('click', '.view-details', function(e) {
e.preventDefault();
var username = $j(this).data('username');
var id = $j(this).data('id');
viewDetails(id, username);
});
// Handle reconnect icon clicks
$j('#ppp-table tbody').on('click', '.reconnect-button', function(e) {
e.preventDefault();
var username = $j(this).data('username');
var id = $j(this).data('id');
reconnect(id, username);
});
// Function to handle view details
function viewDetails(id, username) {
console.log("Viewing details for:", username);
$j('#modalUsername').text(username);
$j.ajax({
url: '{$_url}plugin/pppoe_get_combined_users',
method: 'GET',
dataType: 'json',
success: function(response) {
var user = response.find(function(item) {
return (item.username && item.username.toString().toLowerCase() === username.toString().toLowerCase());
});
if (username !== null && user !== null && user.username !== null) {
var interfaceValue = '<pppoe-' + user.username + '>';
$j('#interface').val(interfaceValue);
$j('#selectedInterface').text(interfaceValue);
$j('#detailsModal').css('display', 'block');
createChart();
createDailyChart(username); // Pass the username to createDailyChart
} else {
alert('User not found.');
}
},
error: function(xhr, textStatus, errorThrown) {
alert('Failed to retrieve user data.');
console.error('AJAX error:', textStatus, errorThrown);
}
});
}
// Function to handle reconnect
function reconnect(id, username) {
if (confirm('Are you sure you want to disconnect user ' + username + '?')) {
$.ajax({
url: '{$_url}plugin/pppoe_monitor_router_delete_ppp_user/{$router}', // Perbaiki URL AJAX
method: 'POST',
data: { id: id, username: username },
success: function(response) {
if (response.success) {
alert('User ' + username + ' has been disconnected.');
setTimeout(function() {
table.ajax.reload();
}, 2000);
} else {
alert('Failed to disconnect user ' + username + ': ' + (response.message || 'Unknown error'));
}
},
error: function(xhr, textStatus, errorThrown) {
alert('Failed to disconnect user ' + username + ': ' + (errorThrown || 'Unknown error'));
console.error('AJAX error:', textStatus, errorThrown);
}
});
}
}
// Close modal on click of close button
$j('.close').click(function() {
$j('#detailsModal').css('display', 'none');
});
// Close modal on click outside the modal
$j(window).click(function(event) {
if (event.target == document.getElementById('detailsModal')) {
$j('#detailsModal').css('display', 'none');
}
});
// Handle advanced search form submission
$j(document).ready(function() {
$j('#advancedSearchForm').on('submit', function(e) {
e.preventDefault(); // Mencegah pengiriman form secara default
// Mendapatkan nilai dari input
var username = $j('#searchUsername').val();
var status = $j('#searchStatus').val();
// Melakukan pencarian dan menggambar ulang tabel
table.column(1).search(username).draw(); // Kolom 1 untuk username
table.column(9).search(status).draw(); // Kolom 9 untuk status
});
// Menambahkan ikon search ke dalam tombol
var searchButton = $j('<button type="submit" class="btn btn-primary"><i class="fas fa-search"></i></button>');
$j('#advancedSearchForm').append(searchButton);
});
});
var chart;
var chartData = {
txData: [],
rxData: []
};
function createChart() {
var options = {
chart: {
height: 350,
type: 'area',
animations: {
enabled: true,
easing: 'linear',
speed: 200,
animateGradually: {
enabled: true,
delay: 150
},
dynamicAnimation: {
enabled: true,
speed: 200
}
},
events: {
mounted: function() {
updateTrafficValues();
setInterval(updateTrafficValues, 3000);
}
}
},
stroke: {
curve: 'smooth'
},
series: [
{ name: 'Download', data: chartData.txData },
{ name: 'Upload', data: chartData.rxData }
],
xaxis: {
type: 'datetime',
labels: {
formatter: function(value) {
return new Date(value).toLocaleTimeString();
}
}
},
yaxis: {
title: {
text: 'Real Time Data Usage'
},
labels: {
formatter: function(value) {
return formatBytes(value);
}
}
},
tooltip: {
x: {
format: 'HH:mm:ss'
},
y: {
formatter: function(value) {
return formatBytes(value) + 'ps';
}
}
},
dataLabels: {
enabled: false,
formatter: function(value) {
return formatBytes(value);
}
}
};
chart = new ApexCharts(document.querySelector("#chart"), options);
chart.render();
}
var dailyChart; // Declare dailyChart variable globally
function createDailyChart(username) {
var currentDate = new Date();
var startOfMonth = new Date(currentDate.getFullYear(), currentDate.getMonth(), 1).getTime();
var endOfMonth = new Date(currentDate.getFullYear(), currentDate.getMonth() + 1, 0).getTime();
generateDailyData(username)
.then(dailyData => {
var dailyTotals = dailyData.download.map((item, index) => ({
x: item.x,
y: item.y + dailyData.upload[index].y
}));
if (dailyChart) {
dailyChart.destroy();
}
var options = {
chart: {
height: 350,
type: 'bar',
animations: {
enabled: true,
easing: 'linear',
speed: 800,
animateGradually: {
enabled: true,
delay: 150
},
dynamicAnimation: {
enabled: true,
speed: 200
}
},
toolbar: {
show: true,
}
},
plotOptions: {
bar: {
horizontal: false,
columnWidth: '15%',
endingShape: 'rounded'
},
},
dataLabels: {
enabled: false
},
stroke: {
show: true,
width: 2,
colors: ['transparent']
},
series: [{
name: 'Download',
data: dailyData.upload
}, {
name: 'Upload',
data: dailyData.download
}, {
name: 'Daily Totals',
data: dailyTotals
}],
xaxis: {
type: 'datetime',
min: startOfMonth,
max: endOfMonth,
labels: {
formatter: function(value) {
return new Date(value).toLocaleDateString();
}
}
},
yaxis: {
title: {
text: 'Total Usage'
},
labels: {
formatter: function(value) {
return formatBytesPerSecond(value);
}
}
},
fill: {
opacity: 1
},
tooltip: {
y: {
formatter: function(val) {
return formatBytes(val);
}
}
},
responsive: [
{
breakpoint: 480,
options: {
plotOptions: {
bar: {
columnWidth: '100%'
}
}
}
}
]
};
dailyChart = new ApexCharts(document.querySelector("#dailyChart"), options);
dailyChart.render();
})
.catch(error => {
console.error("Failed to fetch daily usage data:", error);
});
}
// ========================================== NEW FITUR ==========================================//
function generateDailyData(username, startDate, endDate) {
return new Promise((resolve, reject) => {
$j.ajax({
url: '{$_url}plugin/pppoe_monitor_router_daily_data_usage/{$router}',
data: {
username: username,
start_date: startDate,
end_date: endDate
},
dataType: 'json',
success: function(data) {
console.log("Raw data from server for username", username, ":", data);
var dailyData = {
download: [],
upload: []
};
// Iterate over dates in data and find the correct user data
for (var date in data) {
var users = data[date].users;
// Handle username as number case
var userData = users.find(user => user.username === username || user.username == parseInt(username));
if (userData) {
var rxBytes = convertToBytes(userData.rx);
var txBytes = convertToBytes(userData.tx);
// Store data in dailyData based on date
dailyData.download.push({ x: new Date(date).getTime(), y: rxBytes });
dailyData.upload.push({ x: new Date(date).getTime(), y: txBytes });
}
}
console.log("Filtered daily data for username", username, ":", dailyData);
resolve(dailyData);
},
error: function(xhr, textStatus, errorThrown) {
console.error("AJAX Error in generateDailyData:", textStatus, errorThrown);
console.log("Status:", xhr.status);
console.log("Response Text:", xhr.responseText);
reject(errorThrown);
}
});
});
}
function convertToBytes(value) {
let [number, unit] = value.split(' ');
number = parseFloat(number);
switch (unit) {
case 'GB':
return number * 1024 * 1024 * 1024;
case 'MB':
return number * 1024 * 1024;
case 'KB':
return number * 1024;
default:
return number;
}
}
// ========================================== NEW FITUR ==========================================//
function formatBytesPerSecond(bytes) {
if (bytes === 0) {
return '0 Bps';
}
var k = 1024;
var sizes = ['Bps', 'KBps', 'MBps', 'GBps', 'TBps', 'PBps', 'EBps', 'ZBps', 'YBps'];
var i = Math.floor(Math.log(bytes) / Math.log(k));
var formattedValue = parseFloat((bytes / Math.pow(k, i)).toFixed(2));
return formattedValue + ' ' + sizes[i];
}
// Fungsi untuk mengubah ukuran dalam byte menjadi format yang lebih mudah dibaca
function formatBytes(bytes, decimals = 2) {
if (bytes === 0) return '0 Bytes';
const k = 1024;
const dm = decimals < 0 ? 0 : decimals;
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
}
// Function to update traffic values and icons
function updateTrafficValues() {
var username = $j('#modalUsername').text().trim();
var interfaceValue = $j('#interface').val();
if (!username || !interfaceValue) {
console.error("Username or interface is undefined or empty.");
return;
}
$j.ajax({
url: '{$_url}plugin/pppoe_monitor_router_traffic/{$router}',
dataType: 'json',
data: { username: username, interface: interfaceValue },
success: function(data) {
var timestamp = new Date().getTime();
var txData = parseInt(data.rows.tx[0]) || 0;
var rxData = parseInt(data.rows.rx[0]) || 0;
// Log data tx dan rx untuk debugging
console.log('txData:', txData, 'rxData:', rxData);
// Update chart data
chartData.txData.push({ x: timestamp, y: txData });
chartData.rxData.push({ x: timestamp, y: rxData });
var maxDataPoints = 10;
if (chartData.txData.length > maxDataPoints) {
chartData.txData.shift();
chartData.rxData.shift();
}
// Update series on the chart
chart.updateSeries([
{ name: 'Download', data: chartData.txData },
{ name: 'Upload', data: chartData.rxData }
]);
// Find the icon element for the specific user based on username
var userRow = $j('#ppp-table tbody tr').filter(function() {
return $j(this).find('td').eq(1).text().trim() === username;
});
var iconElement = userRow.find('.traffic-icon');
// Define thresholds for traffic levels
var thresholdHigh = 2000; // Adjust these values as needed
var thresholdMedium = 1500; // Adjust these values as needed
// Adjust icon color based on traffic levels
if (txData > thresholdHigh || rxData > thresholdHigh) {
iconElement.removeClass('traffic-icon-green traffic-icon-yellow').addClass('traffic-icon-red');
} else if (txData > thresholdMedium || rxData > thresholdMedium) {
iconElement.removeClass('traffic-icon-green traffic-icon-red').addClass('traffic-icon-yellow');
} else {
iconElement.removeClass('traffic-icon-yellow traffic-icon-red').addClass('traffic-icon-green');
}
},
error: function(xhr, textStatus, errorThrown) {
console.error("Status: " + textStatus);
console.error("Error: " + errorThrown);
}
});
}
// Function to update traffic icons based on table data
function updateTrafficIcons(response) {
$j('#ppp-table tbody tr').each(function(index) {
var row = table.row(this).data();
if (row) {
var txValue = parseInt(row.tx, 10);
var rxValue = parseInt(row.rx, 10);
var iconElement = $j(this).find('.traffic-icon');
var maxLimit = row.max_limit;
if (maxLimit === '1M/2M') {
if (txValue >= 2 * 1024 * 1024 || rxValue >= 2 * 1024 * 1024) {
iconElement.removeClass().addClass('traffic-icon traffic-icon-red');
} else if (txValue >= 1.5 * 1024 * 1024 || rxValue >= 1.5 * 1024 * 1024) {
iconElement.removeClass().addClass('traffic-icon traffic-icon-yellow');
} else {
iconElement.removeClass().addClass('traffic-icon traffic-icon-green');
}
} else {
// Default logic for other max limits
if (txValue >= 2 * 1024 * 1024 || rxValue >= 2 * 1024 * 1024) {
iconElement.removeClass().addClass('traffic-icon traffic-icon-red');
} else if (txValue >= 1.5 * 1024 * 1024 || rxValue >= 1.5 * 1024 * 1024) {
iconElement.removeClass().addClass('traffic-icon traffic-icon-yellow');
} else {
iconElement.removeClass().addClass('traffic-icon traffic-icon-green');
}
}
}
});
}
// Donation Popup
document.addEventListener('DOMContentLoaded', function() {
setTimeout(function() {
document.getElementById('donationPopup').style.display = 'flex';
}, 1000);
});
document.getElementById('donationPopup').querySelector('.modalsupport-close').addEventListener('click', function() {
document.getElementById('donationPopup').style.display = 'none';
});
window.addEventListener('click', function(event) {
if (event.target === document.getElementById('donationPopup')) {
document.getElementById('donationPopup').style.display = 'none';
}
});
document.getElementById('donationPopup').querySelector('.donate-button').addEventListener('click', function() {
window.open('https://buymeacoffee.com/kevindonisaputra', '_blank');
});
</script>
{include file="sections/footer.tpl"}

BIN
system/plugin/user.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 281 KiB

View File

@ -0,0 +1,8 @@
<html>
<head>
<title>403 Forbidden</title>
</head>
<body>
<p>Directory access is forbidden.</p>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -0,0 +1,8 @@
<html>
<head>
<title>403 Forbidden</title>
</head>
<body>
<p>Directory access is forbidden.</p>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
system/uploads/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

@ -0,0 +1,10 @@
{
"expired": "Hello [[name]], your internet package [[package]] has been expired.",
"balance_send": "You sent [[balance]] to [[name]].",
"balance_received": "You have received [[balance]] from [[name]].",
"reminder_7_day": "Hello *[[name]]*, \r\nyour internet package *[[package]]* will be expired in 7 days.",
"reminder_3_day": "Hello *[[name]]*, \r\nyour internet package *[[package]]* will be expired in 3 days.",
"reminder_1_day": "Hello *[[name]]*,\r\n your internet package *[[package]]* will be expired tomorrow.",
"invoice_paid": "*[[company_name]]*\r\n[[address]]\r\n[[phone]]\r\n\r\n\r\nINVOICE: *[[invoice]]*\r\nDate : [[date]]\r\n[[payment_gateway]] [[payment_channel]]\r\n\r\n\r\nType : *[[type]]*\r\nPackage : *[[plan_name]]*\r\nPrice : *[[plan_price]]*\r\n\r\nUsername : *[[user_name]]*\r\nPassword : ***********\r\n\r\nExpired : *[[expired_date]]*\r\n\r\n====================\r\n[[footer]]",
"invoice_balance": "*[[company_name]]*\r\n[[address]]\r\n[[phone]]\r\n\r\n\r\nINVOICE: *[[invoice]]*\r\nDate : [[date]]\r\n[[payment_gateway]] [[payment_channel]]\r\n\r\n\r\nType : *[[type]]*\r\nPackage : *[[plan_name]]*\r\nPrice : *[[plan_price]]*\r\n\r\n====================\r\n[[footer]]"
}

View File

@ -0,0 +1 @@
{"expired":"Dear Customer, your subscription of [[package]] has expired.\r\nONLY Home\/Office Users pay using:\r\nPay Bill:4355580\r\nAcc. No:[[username]]\r\nPrice:[[price]]","reminder_7_day":"","reminder_3_day":"","reminder_1_day":"Hello, Your Internet will Expire in 1 Day, Kindly make subscribe to continue using our Services. \r\n","invoice_paid":"Successfully Purchased [[plan_name]]. Expiry: [[expired_date]]. \r\nIf not connected use MPESA message or Account No.:[[user_name]] on the login page.","invoice_balance":""}

View File

@ -0,0 +1,205 @@
<?php
function BankStkPush_validate_config()
{
global $config;
if (empty($config['Stkbankacc']) || empty($config['Stkbankname']) ) {
sendTelegram("Bank Stk payment gateway not configured");
r2(U . 'order/balance', 'w', Lang::T("Admin has not yet setup the payment gateway, please tell admin"));
}
}
function BankStkPush_show_config()
{
global $ui, $config;
$ui->assign('_title', 'Bank Stk Push - ' . $config['CompanyName']);
$ui->display('bankstkpush.tpl');
}
function BankStkPush_save_config()
{
global $admin, $_L;
$bankacc = _post('account');
$bankname = _post('bankname');
$d = ORM::for_table('tbl_appconfig')->where('setting', 'Stkbankacc')->find_one();
if ($d) {
$d->value = $bankacc;
$d->save();
} else {
$d = ORM::for_table('tbl_appconfig')->create();
$d->setting = 'Stkbankacc';
$d->value = $bankacc;
$d->save();
}
$d = ORM::for_table('tbl_appconfig')->where('setting', 'Stkbankname')->find_one();
if ($d) {
$d->value = $bankname;
$d->save();
} else {
$d = ORM::for_table('tbl_appconfig')->create();
$d->setting = 'Stkbankname';
$d->value = $bankname;
$d->save();
}
_log('[' . $admin['username'] . ']: Stk Bank details ' . $_L['Settings_Saved_Successfully'], 'Admin', $admin['id']);
r2(U . 'paymentgateway/BankStkPush', 's', $_L['Settings_Saved_Successfully']);
}
function BankStkPush_create_transaction($trx, $user )
{
$url=(U. "plugin/initiatebankstk");
$d = ORM::for_table('tbl_payment_gateway')
->where('username', $user['username'])
->where('status', 1)
->find_one();
$d->gateway_trx_id = '';
$d->payment_method = 'Bank Stk Push';
$d->pg_url_payment = $url;
$d->pg_request = '';
$d->expired_date = date('Y-m-d H:i:s', strtotime("+5 minutes"));
$d->save();
r2(U . "order/view/" . $d['id'], 's', Lang::T("Create Transaction Success, Please click pay now to process payment"));
die();
}
function BankStkPush_payment_notification()
{
$captureLogs = file_get_contents("php://input");
$analizzare = json_decode($captureLogs);
/// sleep(10);
file_put_contents('back.log',$captureLogs,FILE_APPEND);
$response_code = $analizzare->Body->stkCallback->ResultCode;
$resultDesc = ($analizzare->Body->stkCallback->ResultDesc);
$merchant_req_id = ($analizzare->Body->stkCallback->MerchantRequestID);
$checkout_req_id = ($analizzare->Body->stkCallback->CheckoutRequestID);
$amount_paid = ($analizzare->Body->stkCallback->CallbackMetadata->Item['0']->Value);//get the amount value
$mpesa_code = ($analizzare->Body->stkCallback->CallbackMetadata->Item['1']->Value);//mpesa transaction code..
$sender_phone = ($analizzare->Body->stkCallback->CallbackMetadata->Item['4']->Value);//Telephone Number
$PaymentGatewayRecord = ORM::for_table('tbl_payment_gateway')
->where('checkout', $checkout_req_id)
->where('status', 1) // Add this line to filter by status
->order_by_desc('id')
->find_one();
$uname=$PaymentGatewayRecord->username;
$plan_id=$PaymentGatewayRecord->plan_id;
$mac_address=$PaymentGatewayRecord->mac_address;
$user=$PaymentGatewayRecord;
$userid = ORM::for_table('tbl_customers')
->where('username', $uname)
->order_by_desc('id')
->find_one();
$userid->username=$uname;
$userid->save();
$plans = ORM::for_table('tbl_plans')
->where('id', $plan_id)
->order_by_desc('id')
->find_one();
if ($response_code=="1032")
{
$now = date('Y-m-d H:i:s');
$PaymentGatewayRecord->paid_date = $now;
$PaymentGatewayRecord->status = 4;
$PaymentGatewayRecord->save();
exit();
}
if($response_code=="1037"){
$PaymentGatewayRecord->status = 1;
$PaymentGatewayRecord->pg_paid_response = 'User failed to enter pin';
$PaymentGatewayRecord->save();
exit();
}
if($response_code=="1"){
$PaymentGatewayRecord->status = 1;
$PaymentGatewayRecord->pg_paid_response = 'Not enough balance';
$PaymentGatewayRecord->save();
exit();
}
if($response_code=="2001"){
$PaymentGatewayRecord->status = 1;
$PaymentGatewayRecord->pg_paid_response = 'Wrong Mpesa pin';
$PaymentGatewayRecord->save();
exit();
}
if($response_code=="0"){
$now = date('Y-m-d H:i:s');
$date = date('Y-m-d');
$time= date('H:i:s');
$check_mpesa = ORM::for_table('tbl_payment_gateway')
->where('gateway_trx_id', $mpesa_code)
->find_one();
if($check_mpesa){
echo "double callback, ignore one";
die;
}
$plan_type=$plans->type;
$UserId=$userid->id;
if (!Package::rechargeUser($UserId, $user['routers'], $user['plan_id'], $user['gateway'], $mpesa_code)){
$PaymentGatewayRecord->status = 2;
$PaymentGatewayRecord->paid_date = $now;
$PaymentGatewayRecord->gateway_trx_id = $mpesa_code;
$PaymentGatewayRecord->save();
$username = $PaymentGatewayRecord->username;
// Check if a transaction with the same gateway_trx_id already exists
$existingTransaction = ORM::for_table('tbl_transactions')
->where('mpesacode', $mpesa_code)
->find_one();
if (!$existingTransaction) {
// Save transaction data to tbl_transactions
$transaction = ORM::for_table('tbl_transactions')->create();
$transaction->invoice = $PaymentGatewayRecord->gateway_trx_id; // Set invoice to gateway_trx_id value
$transaction->username = $PaymentGatewayRecord->username;
$transaction->plan_name = $PaymentGatewayRecord->plan_name;
$transaction->price = $amount_paid;
$transaction->recharged_on = $date;
$transaction->recharged_time = $time;
$transaction->expiration = $now;
$transaction->time = $now;
$transaction->method = $PaymentGatewayRecord->payment_method;
$transaction->routers = 0;
$transaction->Type = 'Balance';
$transaction->mpesacode = $mpesa_code;
$transaction->save();
} else {
error_log("Duplicate transaction entry detected for gateway_trx_id: " . $PaymentGatewayRecord->gateway_trx_id);
}
} else {
// Update tbl_recharges
$PaymentGatewayRecord->status = 2;
$PaymentGatewayRecord->paid_date = $now;
$PaymentGatewayRecord->gateway_trx_id = $mpesa_code;
$PaymentGatewayRecord->save();
}
}
}

View File

@ -0,0 +1,234 @@
<?php
/**
* PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/)
*
* Payment Gateway flutterwave.com
*
* created by @foculinkstech
*
**/
function flutterwave_validate_config()
{
global $config;
if (empty($config['flutterwave_secret_key'])) {
Message::sendTelegram("flutterwave payment gateway not configured");
r2(U . 'order/package', 'w', Lang::T("Admin has not yet setup flutterwave payment gateway, please tell admin"));
}
}
function flutterwave_show_config()
{
global $ui;
$ui->assign('_title', 'Flutterwave - Payment Gateway');
$ui->assign('cur', json_decode(file_get_contents('system/paymentgateway/flutterwave_currency.json'), true));
$ui->assign('channel', json_decode(file_get_contents('system/paymentgateway/flutterwave_channel.json'), true));
$ui->display('flutterwave.tpl');
}
function flutterwave_save_config()
{
global $admin, $_L;
$flutterwave_secret_key = _post('flutterwave_secret_key');
$flutterwave_currency = _post('flutterwave_currency');
$d = ORM::for_table('tbl_appconfig')->where('setting', 'flutterwave_secret_key')->find_one();
if ($d) {
$d->value = $flutterwave_secret_key;
$d->save();
} else {
$d = ORM::for_table('tbl_appconfig')->create();
$d->setting = 'flutterwave_secret_key';
$d->value = $flutterwave_secret_key;
$d->save();
}
$d = ORM::for_table('tbl_appconfig')->where('setting', 'flutterwave_currency')->find_one();
if ($d) {
$d->value = $flutterwave_currency;
$d->save();
} else {
$d = ORM::for_table('tbl_appconfig')->create();
$d->setting = 'flutterwave_currency';
$d->value = $flutterwave_currency;
$d->save();
}
$d = ORM::for_table('tbl_appconfig')->where('setting', 'flutterwave_channel')->find_one();
if ($d) {
$d->value = implode(',', $_POST['flutterwave_channel']);
$d->save();
} else {
$d = ORM::for_table('tbl_appconfig')->create();
$d->setting = 'flutterwave_channel';
$d->value = implode(',', $_POST['flutterwave_channel']);
$d->save();
}
_log('[' . $admin['username'] . ']: Flutterwave ' . $_L['Settings_Saved_Successfully'], 'Admin', $admin['id']);
r2(U . 'paymentgateway/flutterwave', 's', $_L['Settings_Saved_Successfully']);
}
function flutterwave_create_transaction($trx, $user)
{
global $config;
$txref = uniqid('trx');
$json = [
'tx_ref' => $txref,
'amount' => $trx['price'],
'currency' => $config['flutterwave_currency'],
'payment_options' => explode(',', $config['flutterwave_channel']),
'customer' => [
'email' => (empty($user['email'])) ? $user['username'] . '@' . $_SERVER['HTTP_HOST'] : $user['email'],
'name' => $user['fullname'],
'phonenumber' => $user['phonenumber']
],
'meta' => [
'price' => $trx['price'],
'username' => $user['username'],
'trxid' => $trx['id']
],
'customizations' => [
'title' => $trx['plan_name'],
'description' => $trx['plan_name'],
],
'redirect_url' => U . 'callback/flutterwave'
];
// die(json_encode($json,JSON_PRETTY_PRINT));
$result = json_decode(Http::postJsonData(flutterwave_get_server() . 'payments', $json,[
'Authorization: Bearer ' . $config['flutterwave_secret_key'],
'Cache-Control: no-cahe'
],
),
true);
//die(json_encode($result,JSON_PRETTY_PRINT));
if ($result['status'] == 'error') {
Message::sendTelegram("Flutterwave payment failed\n\n" . json_encode($result, JSON_PRETTY_PRINT));
r2(U . 'order/package', 'e', Lang::T("Failed to create transaction.\n".$result['message']));
}
$d = ORM::for_table('tbl_payment_gateway')
->where('username', $user['username'])
->where('status', 1)
->find_one();
$d->gateway_trx_id = $txref;
$d->pg_url_payment = $result['data']['link'];
$d->pg_request = json_encode($result);
$d->expired_date = date('Y-m-d H:i:s', strtotime("+ 6 HOUR"));
$d->save();
header('Location: ' . $result['data']['link']);
exit();
r2(U . "order/view/" . $d['id'], 's', Lang::T("Create Transaction Success"));
}
function flutterwave_payment_notification()
{
global $config;
if(isset($_GET['status']))
{
//* check payment status
if($_GET['status'] == 'cancelled')
{
// die(json_encode($txref,JSON_PRETTY_PRINT));
Message::sendTelegram("Flutterwave Payment Cancelled: \n\n");
r2(U . 'order/package', 'e', Lang::T("Flutterwave Payment Cancelled."));
}
elseif($_GET['status'] == 'successful')
{
$txid = $_GET['transaction_id'];
$result = json_decode(Http::getData(flutterwave_get_server() . 'transactions/' . $txid. '/verify', [
'Authorization: Bearer ' . $config['flutterwave_secret_key'],
'Cache-Control: no-cahe'
]), true);
//die(json_encode($result,JSON_PRETTY_PRINT));
{
$id = $result['data']['id'];
$amountPaid = $result['data']['charged_amount'];
$amountToPay = $result['data']['meta']['price'];
$username = $result['data']['meta']['username'];
$trxid = $result['data']['meta']['trxid'];
if($amountPaid >= $amountToPay)
{
// die(json_encode($trxid,JSON_PRETTY_PRINT));
// echo 'Payment successful';
$d = ORM::for_table('tbl_payment_gateway')
->where('username', $username)
->where('status', 1)
->find_one();
$d->gateway_trx_id = $id;
$d->save();
r2(U . 'order/view/'.$trxid.'/check');
// r2(U . 'order/package', 's', Lang::T("Flutterwave Payment Completed."));
exit();
//* Continue to give item to the user
}
else
{
// echo 'Fraud transactio detected';
r2(U . 'order/package', 'e', Lang::T("Fraud transactions detected."));
exit();
}
}
}
}
}
function flutterwave_get_status($trx, $user)
{
global $config;
$trans_id = $trx['gateway_trx_id'];
$result = json_decode(Http::getData(flutterwave_get_server() . 'transactions/' . $trx['gateway_trx_id']. '/verify', [
'Authorization: Bearer ' . $config['flutterwave_secret_key'],
'Cache-Control: no-cahe'
]), true);
//die(json_encode($result,JSON_PRETTY_PRINT));
if ($result['status'] == 'error') {
r2(U . "order/view/" . $trx['id'], 'w', Lang::T("Transaction still unpaid."));
} else if (in_array($result['status'], ['success']) && $trx['status'] != 2) {
if (!Package::rechargeUser($user['id'], $trx['routers'], $trx['plan_id'], $trx['gateway'], 'Flutterwave')) {
r2(U . "order/view/" . $trx['id'], 'd', Lang::T("Failed to activate your Package, please try again later."));
}
$trx->pg_paid_response = json_encode($result);
$trx->payment_method = 'Flutterwave';
$trx->payment_channel = $result['data']['payment_type'];
$trx->paid_date = date('Y-m-d H:i:s', strtotime( $result['data']['created_at']));
$trx->status = 2;
$trx->save();
r2(U . "order/view/" . $trx['id'], 's', Lang::T("Transaction successful."));
} else if ($result['status'] == 'EXPIRED') {
$trx->pg_paid_response = json_encode($result);
$trx->status = 3;
$trx->save();
r2(U . "order/view/" . $trx['id'], 'd', Lang::T("Transaction expired."));
} else if ($trx['status'] == 2) {
r2(U . "order/view/" . $trx['id'], 'd', Lang::T("Transaction has been paid.."));
}else{
Message::sendTelegram("flutterwave_get_status: unknown result\n\n".json_encode($result, JSON_PRETTY_PRINT));
r2(U . "order/view/" . $trx['id'], 'd', Lang::T("Unknown Command."));
}
}
function flutterwave_get_server()
{
global $_app_stage;
if ($_app_stage == 'Live') {
return 'https://api.flutterwave.com/v3/';
} else {
return 'https://api.flutterwave.com/v3/';
}
}

View File

@ -0,0 +1,35 @@
[
{
"id": "card",
"name": "Card Payment"
},
{
"id": "ussd",
"name": "USSD"
},
{
"id": "account",
"name": "Bank Account"
},
{
"id": "banktransfer",
"name": "Bank Transfer"
},
{
"id": "nqr",
"name": "QR payment"
},
{
"id": "mpesa",
"name": "M-Pesa"
},
{
"id": "mobilemoneyghana",
"name": "Mobile money Ghana"
},
{
"id": "credit",
"name": "Credit payment"
}
]

View File

@ -0,0 +1,30 @@
[
{
"id": "NGN",
"name": "Nigerian Naira"
},
{
"id": "GHC",
"name": "Ghana Cedis"
},
{
"id": "KES",
"name": "Kenyan Shilling"
},
{
"id": "ZAR",
"name": "South African Rand"
},
{
"id": "GBP",
"name": "British Pound Sterling"
},
{
"id": "USD",
"name": "United States Dollar"
},
{
"id": "TZS",
"name": "Tanzanian Shilling"
}
]

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,8 @@
<html>
<head>
<title>403 Forbidden</title>
</head>
<body>
<p>Directory access is forbidden.</p>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

25
system/vendor/autoload.php vendored Normal file
View File

@ -0,0 +1,25 @@
<?php
// autoload.php @generated by Composer
if (PHP_VERSION_ID < 50600) {
if (!headers_sent()) {
header('HTTP/1.1 500 Internal Server Error');
}
$err = 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
if (!ini_get('display_errors')) {
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
fwrite(STDERR, $err);
} elseif (!headers_sent()) {
echo $err;
}
}
trigger_error(
$err,
E_USER_ERROR
);
}
require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInit405fa5c7a0972c286ef93b1161b83367::getLoader();

1
system/vendor/smarty/index.html vendored Normal file
View File

@ -0,0 +1 @@
#

View File

@ -0,0 +1,318 @@
<?php
/**
* Smarty Internal Plugin Configfilelexer
*
* This is the lexer to break the config file source into tokens
* @package Smarty
* @subpackage Config
* @author Uwe Tews
*/
/**
* Smarty_Internal_Configfilelexer
*
* This is the config file lexer.
* It is generated from the smarty_internal_configfilelexer.plex file
*
* @package Smarty
* @subpackage Compiler
* @author Uwe Tews
*/
class Smarty_Internal_Configfilelexer
{
/**
* Source
*
* @var string
*/
public $data;
/**
* Source length
*
* @var int
*/
public $dataLength = null;
/**
* byte counter
*
* @var int
*/
public $counter;
/**
* token number
*
* @var int
*/
public $token;
/**
* token value
*
* @var string
*/
public $value;
/**
* current line
*
* @var int
*/
public $line;
/**
* state number
*
* @var int
*/
public $state = 1;
/**
* Smarty object
*
* @var Smarty
*/
public $smarty = null;
/**
* compiler object
*
* @var Smarty_Internal_Config_File_Compiler
*/
private $compiler = null;
/**
* copy of config_booleanize
*
* @var bool
*/
private $configBooleanize = false;
/**
* trace file
*
* @var resource
*/
public $yyTraceFILE;
/**
* trace prompt
*
* @var string
*/
public $yyTracePrompt;
/**
* state names
*
* @var array
*/
public $state_name = array(1 => 'START', 2 => 'VALUE', 3 => 'NAKED_STRING_VALUE', 4 => 'COMMENT', 5 => 'SECTION', 6 => 'TRIPPLE');
/**
* storage for assembled token patterns
*
* @var string
*/
private $yy_global_pattern1 = null;
private $yy_global_pattern2 = null;
private $yy_global_pattern3 = null;
private $yy_global_pattern4 = null;
private $yy_global_pattern5 = null;
private $yy_global_pattern6 = null;
/**
* token names
*
* @var array
*/
public $smarty_token_names = array( // Text for parser error messages
);
/**
* constructor
*
* @param string $data template source
* @param Smarty_Internal_Config_File_Compiler $compiler
*/
public function __construct($data, Smarty_Internal_Config_File_Compiler $compiler)
{
$this->data = $data . "\n"; //now all lines are \n-terminated
$this->dataLength = strlen($data);
$this->counter = 0;
if (preg_match('/^\xEF\xBB\xBF/', $this->data, $match)) {
$this->counter += strlen($match[0]);
}
$this->line = 1;
$this->compiler = $compiler;
$this->smarty = $compiler->smarty;
$this->configBooleanize = $this->smarty->config_booleanize;
}
public function replace ($input) {
return $input;
}
public function PrintTrace()
{
$this->yyTraceFILE = fopen('php://output', 'w');
$this->yyTracePrompt = '<br>';
}
/*!lex2php
%input $this->data
%counter $this->counter
%token $this->token
%value $this->value
%line $this->line
commentstart = /#|;/
openB = /\[/
closeB = /\]/
section = /.*?(?=[\.=\[\]\r\n])/
equal = /=/
whitespace = /[ \t\r]+/
dot = /\./
id = /[0-9]*[a-zA-Z_]\w*/
newline = /\n/
single_quoted_string = /'[^'\\]*(?:\\.[^'\\]*)*'(?=[ \t\r]*[\n#;])/
double_quoted_string = /"[^"\\]*(?:\\.[^"\\]*)*"(?=[ \t\r]*[\n#;])/
tripple_quotes = /"""/
tripple_quotes_end = /"""(?=[ \t\r]*[\n#;])/
text = /[\S\s]/
float = /\d+\.\d+(?=[ \t\r]*[\n#;])/
int = /\d+(?=[ \t\r]*[\n#;])/
maybe_bool = /[a-zA-Z]+(?=[ \t\r]*[\n#;])/
naked_string = /[^\n]+?(?=[ \t\r]*\n)/
*/
/*!lex2php
%statename START
commentstart {
$this->token = Smarty_Internal_Configfileparser::TPC_COMMENTSTART;
$this->yypushstate(self::COMMENT);
}
openB {
$this->token = Smarty_Internal_Configfileparser::TPC_OPENB;
$this->yypushstate(self::SECTION);
}
closeB {
$this->token = Smarty_Internal_Configfileparser::TPC_CLOSEB;
}
equal {
$this->token = Smarty_Internal_Configfileparser::TPC_EQUAL;
$this->yypushstate(self::VALUE);
}
whitespace {
return false;
}
newline {
$this->token = Smarty_Internal_Configfileparser::TPC_NEWLINE;
}
id {
$this->token = Smarty_Internal_Configfileparser::TPC_ID;
}
text {
$this->token = Smarty_Internal_Configfileparser::TPC_OTHER;
}
*/
/*!lex2php
%statename VALUE
whitespace {
return false;
}
float {
$this->token = Smarty_Internal_Configfileparser::TPC_FLOAT;
$this->yypopstate();
}
int {
$this->token = Smarty_Internal_Configfileparser::TPC_INT;
$this->yypopstate();
}
tripple_quotes {
$this->token = Smarty_Internal_Configfileparser::TPC_TRIPPLE_QUOTES;
$this->yypushstate(self::TRIPPLE);
}
single_quoted_string {
$this->token = Smarty_Internal_Configfileparser::TPC_SINGLE_QUOTED_STRING;
$this->yypopstate();
}
double_quoted_string {
$this->token = Smarty_Internal_Configfileparser::TPC_DOUBLE_QUOTED_STRING;
$this->yypopstate();
}
maybe_bool {
if (!$this->configBooleanize || !in_array(strtolower($this->value), array('true', 'false', 'on', 'off', 'yes', 'no')) ) {
$this->yypopstate();
$this->yypushstate(self::NAKED_STRING_VALUE);
return true; //reprocess in new state
} else {
$this->token = Smarty_Internal_Configfileparser::TPC_BOOL;
$this->yypopstate();
}
}
naked_string {
$this->token = Smarty_Internal_Configfileparser::TPC_NAKED_STRING;
$this->yypopstate();
}
newline {
$this->token = Smarty_Internal_Configfileparser::TPC_NAKED_STRING;
$this->value = '';
$this->yypopstate();
}
*/
/*!lex2php
%statename NAKED_STRING_VALUE
naked_string {
$this->token = Smarty_Internal_Configfileparser::TPC_NAKED_STRING;
$this->yypopstate();
}
*/
/*!lex2php
%statename COMMENT
whitespace {
return false;
}
naked_string {
$this->token = Smarty_Internal_Configfileparser::TPC_NAKED_STRING;
}
newline {
$this->token = Smarty_Internal_Configfileparser::TPC_NEWLINE;
$this->yypopstate();
}
*/
/*!lex2php
%statename SECTION
dot {
$this->token = Smarty_Internal_Configfileparser::TPC_DOT;
}
section {
$this->token = Smarty_Internal_Configfileparser::TPC_SECTION;
$this->yypopstate();
}
*/
/*!lex2php
%statename TRIPPLE
tripple_quotes_end {
$this->token = Smarty_Internal_Configfileparser::TPC_TRIPPLE_QUOTES_END;
$this->yypopstate();
$this->yypushstate(self::START);
}
text {
$to = strlen($this->data);
preg_match("/\"\"\"[ \t\r]*[\n#;]/",$this->data,$match,PREG_OFFSET_CAPTURE,$this->counter);
if (isset($match[0][1])) {
$to = $match[0][1];
} else {
$this->compiler->trigger_config_file_error ('missing or misspelled literal closing tag');
}
$this->value = substr($this->data,$this->counter,$to-$this->counter);
$this->token = Smarty_Internal_Configfileparser::TPC_TRIPPLE_TEXT;
}
*/
}

View File

@ -0,0 +1,346 @@
/**
* Smarty Internal Plugin Configfileparser
*
* This is the config file parser
*
*
* @package Smarty
* @subpackage Config
* @author Uwe Tews
*/
%name TPC_
%declare_class {
/**
* Smarty Internal Plugin Configfileparse
*
* This is the config file parser.
* It is generated from the smarty_internal_configfileparser.y file
* @package Smarty
* @subpackage Compiler
* @author Uwe Tews
*/
class Smarty_Internal_Configfileparser
}
%include_class
{
/**
* result status
*
* @var bool
*/
public $successful = true;
/**
* return value
*
* @var mixed
*/
public $retvalue = 0;
/**
* @var
*/
public $yymajor;
/**
* lexer object
*
* @var Smarty_Internal_Configfilelexer
*/
private $lex;
/**
* internal error flag
*
* @var bool
*/
private $internalError = false;
/**
* compiler object
*
* @var Smarty_Internal_Config_File_Compiler
*/
public $compiler = null;
/**
* smarty object
*
* @var Smarty
*/
public $smarty = null;
/**
* copy of config_overwrite property
*
* @var bool
*/
private $configOverwrite = false;
/**
* copy of config_read_hidden property
*
* @var bool
*/
private $configReadHidden = false;
/**
* helper map
*
* @var array
*/
private static $escapes_single = array('\\' => '\\',
'\'' => '\'');
/**
* constructor
*
* @param Smarty_Internal_Configfilelexer $lex
* @param Smarty_Internal_Config_File_Compiler $compiler
*/
public function __construct(Smarty_Internal_Configfilelexer $lex, Smarty_Internal_Config_File_Compiler $compiler)
{
$this->lex = $lex;
$this->smarty = $compiler->smarty;
$this->compiler = $compiler;
$this->configOverwrite = $this->smarty->config_overwrite;
$this->configReadHidden = $this->smarty->config_read_hidden;
}
/**
* parse optional boolean keywords
*
* @param string $str
*
* @return bool
*/
private function parse_bool($str)
{
$str = strtolower($str);
if (in_array($str, array('on', 'yes', 'true'))) {
$res = true;
} else {
$res = false;
}
return $res;
}
/**
* parse single quoted string
* remove outer quotes
* unescape inner quotes
*
* @param string $qstr
*
* @return string
*/
private static function parse_single_quoted_string($qstr)
{
$escaped_string = substr($qstr, 1, strlen($qstr) - 2); //remove outer quotes
$ss = preg_split('/(\\\\.)/', $escaped_string, - 1, PREG_SPLIT_DELIM_CAPTURE);
$str = '';
foreach ($ss as $s) {
if (strlen($s) === 2 && $s[0] === '\\') {
if (isset(self::$escapes_single[$s[1]])) {
$s = self::$escapes_single[$s[1]];
}
}
$str .= $s;
}
return $str;
}
/**
* parse double quoted string
*
* @param string $qstr
*
* @return string
*/
private static function parse_double_quoted_string($qstr)
{
$inner_str = substr($qstr, 1, strlen($qstr) - 2);
return stripcslashes($inner_str);
}
/**
* parse triple quoted string
*
* @param string $qstr
*
* @return string
*/
private static function parse_tripple_double_quoted_string($qstr)
{
return stripcslashes($qstr);
}
/**
* set a config variable in target array
*
* @param array $var
* @param array $target_array
*/
private function set_var(array $var, array &$target_array)
{
$key = $var['key'];
$value = $var['value'];
if ($this->configOverwrite || !isset($target_array['vars'][$key])) {
$target_array['vars'][$key] = $value;
} else {
settype($target_array['vars'][$key], 'array');
$target_array['vars'][$key][] = $value;
}
}
/**
* add config variable to global vars
*
* @param array $vars
*/
private function add_global_vars(array $vars)
{
if (!isset($this->compiler->config_data['vars'])) {
$this->compiler->config_data['vars'] = array();
}
foreach ($vars as $var) {
$this->set_var($var, $this->compiler->config_data);
}
}
/**
* add config variable to section
*
* @param string $section_name
* @param array $vars
*/
private function add_section_vars($section_name, array $vars)
{
if (!isset($this->compiler->config_data['sections'][$section_name]['vars'])) {
$this->compiler->config_data['sections'][$section_name]['vars'] = array();
}
foreach ($vars as $var) {
$this->set_var($var, $this->compiler->config_data['sections'][$section_name]);
}
}
}
%token_prefix TPC_
%parse_accept
{
$this->successful = !$this->internalError;
$this->internalError = false;
$this->retvalue = $this->_retvalue;
}
%syntax_error
{
$this->internalError = true;
$this->yymajor = $yymajor;
$this->compiler->trigger_config_file_error();
}
%stack_overflow
{
$this->internalError = true;
$this->compiler->trigger_config_file_error('Stack overflow in configfile parser');
}
// Complete config file
start(res) ::= global_vars sections. {
res = null;
}
// Global vars
global_vars(res) ::= var_list(vl). {
$this->add_global_vars(vl);
res = null;
}
// Sections
sections(res) ::= sections section. {
res = null;
}
sections(res) ::= . {
res = null;
}
section(res) ::= OPENB SECTION(i) CLOSEB newline var_list(vars). {
$this->add_section_vars(i, vars);
res = null;
}
section(res) ::= OPENB DOT SECTION(i) CLOSEB newline var_list(vars). {
if ($this->configReadHidden) {
$this->add_section_vars(i, vars);
}
res = null;
}
// Var list
var_list(res) ::= var_list(vl) newline. {
res = vl;
}
var_list(res) ::= var_list(vl) var(v). {
res = array_merge(vl, array(v));
}
var_list(res) ::= . {
res = array();
}
// Var
var(res) ::= ID(id) EQUAL value(v). {
res = array('key' => id, 'value' => v);
}
value(res) ::= FLOAT(i). {
res = (float) i;
}
value(res) ::= INT(i). {
res = (int) i;
}
value(res) ::= BOOL(i). {
res = $this->parse_bool(i);
}
value(res) ::= SINGLE_QUOTED_STRING(i). {
res = self::parse_single_quoted_string(i);
}
value(res) ::= DOUBLE_QUOTED_STRING(i). {
res = self::parse_double_quoted_string(i);
}
value(res) ::= TRIPPLE_QUOTES(i) TRIPPLE_TEXT(c) TRIPPLE_QUOTES_END(ii). {
res = self::parse_tripple_double_quoted_string(c);
}
value(res) ::= TRIPPLE_QUOTES(i) TRIPPLE_QUOTES_END(ii). {
res = '';
}
value(res) ::= NAKED_STRING(i). {
res = i;
}
// NOTE: this is not a valid rule
// It is added hier to produce a usefull error message on a missing '=';
value(res) ::= OTHER(i). {
res = i;
}
// Newline and comments
newline(res) ::= NEWLINE. {
res = null;
}
newline(res) ::= COMMENTSTART NEWLINE. {
res = null;
}
newline(res) ::= COMMENTSTART NAKED_STRING NEWLINE. {
res = null;
}

View File

@ -0,0 +1,687 @@
<?php
/*
* This file is part of Smarty.
*
* (c) 2015 Uwe Tews
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Smarty_Internal_Templatelexer
* This is the template file lexer.
* It is generated from the smarty_internal_templatelexer.plex file
*
*
* @author Uwe Tews <uwe.tews@googlemail.com>
*/
class Smarty_Internal_Templatelexer
{
/**
* Source
*
* @var string
*/
public $data;
/**
* Source length
*
* @var int
*/
public $dataLength = null;
/**
* byte counter
*
* @var int
*/
public $counter;
/**
* token number
*
* @var int
*/
public $token;
/**
* token value
*
* @var string
*/
public $value;
/**
* current line
*
* @var int
*/
public $line;
/**
* tag start line
*
* @var
*/
public $taglineno;
/**
* php code type
*
* @var string
*/
public $phpType = '';
/**
* state number
*
* @var int
*/
public $state = 1;
/**
* Smarty object
*
* @var Smarty
*/
public $smarty = null;
/**
* compiler object
*
* @var Smarty_Internal_TemplateCompilerBase
*/
public $compiler = null;
/**
* trace file
*
* @var resource
*/
public $yyTraceFILE;
/**
* trace prompt
*
* @var string
*/
public $yyTracePrompt;
/**
* XML flag true while processing xml
*
* @var bool
*/
public $is_xml = false;
/**
* state names
*
* @var array
*/
public $state_name = array(1 => 'TEXT', 2 => 'TAG', 3 => 'TAGBODY', 4 => 'LITERAL', 5 => 'DOUBLEQUOTEDSTRING',);
/**
* token names
*
* @var array
*/
public $smarty_token_names = array( // Text for parser error messages
'NOT' => '(!,not)',
'OPENP' => '(',
'CLOSEP' => ')',
'OPENB' => '[',
'CLOSEB' => ']',
'PTR' => '->',
'APTR' => '=>',
'EQUAL' => '=',
'NUMBER' => 'number',
'UNIMATH' => '+" , "-',
'MATH' => '*" , "/" , "%',
'INCDEC' => '++" , "--',
'SPACE' => ' ',
'DOLLAR' => '$',
'SEMICOLON' => ';',
'COLON' => ':',
'DOUBLECOLON' => '::',
'AT' => '@',
'HATCH' => '#',
'QUOTE' => '"',
'BACKTICK' => '`',
'VERT' => '"|" modifier',
'DOT' => '.',
'COMMA' => '","',
'QMARK' => '"?"',
'ID' => 'id, name',
'TEXT' => 'text',
'LDELSLASH' => '{/..} closing tag',
'LDEL' => '{...} Smarty tag',
'COMMENT' => 'comment',
'AS' => 'as',
'TO' => 'to',
'LOGOP' => '"<", "==" ... logical operator',
'TLOGOP' => '"lt", "eq" ... logical operator; "is div by" ... if condition',
'SCOND' => '"is even" ... if condition',
);
/**
* literal tag nesting level
*
* @var int
*/
private $literal_cnt = 0;
/**
* preg token pattern for state TEXT
*
* @var string
*/
private $yy_global_pattern1 = null;
/**
* preg token pattern for state TAG
*
* @var string
*/
private $yy_global_pattern2 = null;
/**
* preg token pattern for state TAGBODY
*
* @var string
*/
private $yy_global_pattern3 = null;
/**
* preg token pattern for state LITERAL
*
* @var string
*/
private $yy_global_pattern4 = null;
/**
* preg token pattern for state DOUBLEQUOTEDSTRING
*
* @var null
*/
private $yy_global_pattern5 = null;
/**
* preg token pattern for text
*
* @var null
*/
private $yy_global_text = null;
/**
* preg token pattern for literal
*
* @var null
*/
private $yy_global_literal = null;
/**
* constructor
*
* @param string $source template source
* @param Smarty_Internal_TemplateCompilerBase $compiler
*/
public function __construct($source, Smarty_Internal_TemplateCompilerBase $compiler)
{
$this->data = $source;
$this->dataLength = strlen($this->data);
$this->counter = 0;
if (preg_match('/^\xEF\xBB\xBF/i', $this->data, $match)) {
$this->counter += strlen($match[0]);
}
$this->line = 1;
$this->smarty = $compiler->template->smarty;
$this->compiler = $compiler;
$this->compiler->initDelimiterPreg();
$this->smarty_token_names['LDEL'] = $this->smarty->getLeftDelimiter();
$this->smarty_token_names['RDEL'] = $this->smarty->getRightDelimiter();
}
/**
* open lexer/parser trace file
*
*/
public function PrintTrace()
{
$this->yyTraceFILE = fopen('php://output', 'w');
$this->yyTracePrompt = '<br>';
}
/**
* replace placeholders with runtime preg code
*
* @param string $preg
*
* @return string
*/
public function replace($preg)
{
return $this->compiler->replaceDelimiter($preg);
}
/**
* check if current value is an autoliteral left delimiter
*
* @return bool
*/
public function isAutoLiteral()
{
return $this->smarty->getAutoLiteral() && isset($this->value[ $this->compiler->getLdelLength() ]) ?
strpos(" \n\t\r", $this->value[ $this->compiler->getLdelLength() ]) !== false : false;
}
/*!lex2php
%input $this->data
%counter $this->counter
%token $this->token
%value $this->value
%line $this->line
userliteral = ~(SMARTYldel)SMARTYautoliteral\s+SMARTYliteral~
char = ~[\S\s]~
textdoublequoted = ~([^"\\]*?)((?:\\.[^"\\]*?)*?)(?=((SMARTYldel)SMARTYal|\$|`\$|"SMARTYliteral))~
namespace = ~([0-9]*[a-zA-Z_]\w*)?(\\[0-9]*[a-zA-Z_]\w*)+~
emptyjava = ~[{][}]~
slash = ~[/]~
ldel = ~(SMARTYldel)SMARTYal~
rdel = ~\s*SMARTYrdel~
nocacherdel = ~(\s+nocache)?\s*SMARTYrdel~
smartyblockchildparent = ~[\$]smarty\.block\.(child|parent)~
integer = ~\d+~
hex = ~0[xX][0-9a-fA-F]+~
math = ~\s*([*]{1,2}|[%/^&]|[<>]{2})\s*~
comment = ~(SMARTYldel)SMARTYal[*]~
incdec = ~([+]|[-]){2}~
unimath = ~\s*([+]|[-])\s*~
openP = ~\s*[(]\s*~
closeP = ~\s*[)]~
openB = ~\[\s*~
closeB = ~\s*\]~
dollar = ~[$]~
dot = ~[.]~
comma = ~\s*[,]\s*~
doublecolon = ~[:]{2}~
colon = ~\s*[:]\s*~
at = ~[@]~
hatch = ~[#]~
semicolon = ~\s*[;]\s*~
equal = ~\s*[=]\s*~
space = ~\s+~
ptr = ~\s*[-][>]\s*~
aptr = ~\s*[=][>]\s*~
singlequotestring = ~'[^'\\]*(?:\\.[^'\\]*)*'~
backtick = ~[`]~
vert = ~[|][@]?~
qmark = ~\s*[?]\s*~
constant = ~[_]+[A-Z0-9][0-9A-Z_]*|[A-Z][0-9A-Z_]*(?![0-9A-Z_]*[a-z])~
attr = ~\s+[0-9]*[a-zA-Z_][a-zA-Z0-9_\-:]*\s*[=]\s*~
id = ~[0-9]*[a-zA-Z_]\w*~
literal = ~literal~
strip = ~strip~
lop = ~\s*([!=][=]{1,2}|[<][=>]?|[>][=]?|[&|]{2})\s*~
slop = ~\s+(eq|ne|neq|gt|ge|gte|lt|le|lte|mod|and|or|xor)\s+~
tlop = ~\s+is\s+(not\s+)?(odd|even|div)\s+by\s+~
scond = ~\s+is\s+(not\s+)?(odd|even)~
isin = ~\s+is\s+in\s+~
as = ~\s+as\s+~
to = ~\s+to\s+~
step = ~\s+step\s+~
if = ~(if|elseif|else if|while)\s+~
for = ~for\s+~
makenocache = ~make_nocache\s+~
array = ~array~
foreach = ~foreach(?![^\s])~
setfilter = ~setfilter\s+~
instanceof = ~\s+instanceof\s+~
not = ~[!]\s*|not\s+~
typecast = ~[(](int(eger)?|bool(ean)?|float|double|real|string|binary|array|object)[)]\s*~
double_quote = ~["]~
*/
/*!lex2php
%statename TEXT
emptyjava {
$this->token = Smarty_Internal_Templateparser::TP_TEXT;
}
comment {
$to = $this->dataLength;
preg_match("/[*]{$this->compiler->getRdelPreg()}[\n]?/",$this->data,$match,PREG_OFFSET_CAPTURE,$this->counter);
if (isset($match[0][1])) {
$to = $match[0][1] + strlen($match[0][0]);
} else {
$this->compiler->trigger_template_error ("missing or misspelled comment closing tag '{$this->smarty->getRightDelimiter()}'");
}
$this->value = substr($this->data,$this->counter,$to-$this->counter);
return false;
}
userliteral {
$this->token = Smarty_Internal_Templateparser::TP_TEXT;
}
ldel literal rdel {
$this->token = Smarty_Internal_Templateparser::TP_LITERALSTART;
$this->yypushstate(self::LITERAL);
}
ldel slash literal rdel {
$this->token = Smarty_Internal_Templateparser::TP_LITERALEND;
$this->yypushstate(self::LITERAL);
}
ldel {
$this->yypushstate(self::TAG);
return true;
}
char {
if (!isset($this->yy_global_text)) {
$this->yy_global_text = $this->replace('/(SMARTYldel)SMARTYal/isS');
}
$to = $this->dataLength;
preg_match($this->yy_global_text, $this->data,$match,PREG_OFFSET_CAPTURE,$this->counter);
if (isset($match[0][1])) {
$to = $match[0][1];
}
$this->value = substr($this->data,$this->counter,$to-$this->counter);
$this->token = Smarty_Internal_Templateparser::TP_TEXT;
}
*/
/*!lex2php
%statename TAG
ldel if {
$this->token = Smarty_Internal_Templateparser::TP_LDELIF;
$this->yybegin(self::TAGBODY);
$this->taglineno = $this->line;
}
ldel for {
$this->token = Smarty_Internal_Templateparser::TP_LDELFOR;
$this->yybegin(self::TAGBODY);
$this->taglineno = $this->line;
}
ldel foreach {
$this->token = Smarty_Internal_Templateparser::TP_LDELFOREACH;
$this->yybegin(self::TAGBODY);
$this->taglineno = $this->line;
}
ldel setfilter {
$this->token = Smarty_Internal_Templateparser::TP_LDELSETFILTER;
$this->yybegin(self::TAGBODY);
$this->taglineno = $this->line;
}
ldel makenocache {
$this->token = Smarty_Internal_Templateparser::TP_LDELMAKENOCACHE;
$this->yybegin(self::TAGBODY);
$this->taglineno = $this->line;
}
ldel id nocacherdel {
$this->yypopstate();
$this->token = Smarty_Internal_Templateparser::TP_SIMPLETAG;
$this->taglineno = $this->line;
}
ldel smartyblockchildparent rdel {
$this->yypopstate();
$this->token = Smarty_Internal_Templateparser::TP_SMARTYBLOCKCHILDPARENT;
$this->taglineno = $this->line;
}
ldel slash id rdel {
$this->yypopstate();
$this->token = Smarty_Internal_Templateparser::TP_CLOSETAG;
$this->taglineno = $this->line;
}
ldel dollar id nocacherdel {
if ($this->_yy_stack[count($this->_yy_stack)-1] === self::TEXT) {
$this->yypopstate();
$this->token = Smarty_Internal_Templateparser::TP_SIMPELOUTPUT;
$this->taglineno = $this->line;
} else {
$this->value = $this->smarty->getLeftDelimiter();
$this->token = Smarty_Internal_Templateparser::TP_LDEL;
$this->yybegin(self::TAGBODY);
$this->taglineno = $this->line;
}
}
ldel slash {
$this->token = Smarty_Internal_Templateparser::TP_LDELSLASH;
$this->yybegin(self::TAGBODY);
$this->taglineno = $this->line;
}
ldel {
$this->token = Smarty_Internal_Templateparser::TP_LDEL;
$this->yybegin(self::TAGBODY);
$this->taglineno = $this->line;
}
*/
/*!lex2php
%statename TAGBODY
rdel {
$this->token = Smarty_Internal_Templateparser::TP_RDEL;
$this->yypopstate();
}
ldel {
$this->yypushstate(self::TAG);
return true;
}
double_quote {
$this->token = Smarty_Internal_Templateparser::TP_QUOTE;
$this->yypushstate(self::DOUBLEQUOTEDSTRING);
$this->compiler->enterDoubleQuote();
}
singlequotestring {
$this->token = Smarty_Internal_Templateparser::TP_SINGLEQUOTESTRING;
}
dollar id {
$this->token = Smarty_Internal_Templateparser::TP_DOLLARID;
}
dollar {
$this->token = Smarty_Internal_Templateparser::TP_DOLLAR;
}
isin {
$this->token = Smarty_Internal_Templateparser::TP_ISIN;
}
as {
$this->token = Smarty_Internal_Templateparser::TP_AS;
}
to {
$this->token = Smarty_Internal_Templateparser::TP_TO;
}
step {
$this->token = Smarty_Internal_Templateparser::TP_STEP;
}
instanceof {
$this->token = Smarty_Internal_Templateparser::TP_INSTANCEOF;
}
lop {
$this->token = Smarty_Internal_Templateparser::TP_LOGOP;
}
slop {
$this->token = Smarty_Internal_Templateparser::TP_SLOGOP;
}
tlop {
$this->token = Smarty_Internal_Templateparser::TP_TLOGOP;
}
scond {
$this->token = Smarty_Internal_Templateparser::TP_SINGLECOND;
}
not{
$this->token = Smarty_Internal_Templateparser::TP_NOT;
}
typecast {
$this->token = Smarty_Internal_Templateparser::TP_TYPECAST;
}
openP {
$this->token = Smarty_Internal_Templateparser::TP_OPENP;
}
closeP {
$this->token = Smarty_Internal_Templateparser::TP_CLOSEP;
}
openB {
$this->token = Smarty_Internal_Templateparser::TP_OPENB;
}
closeB {
$this->token = Smarty_Internal_Templateparser::TP_CLOSEB;
}
ptr {
$this->token = Smarty_Internal_Templateparser::TP_PTR;
}
aptr {
$this->token = Smarty_Internal_Templateparser::TP_APTR;
}
equal {
$this->token = Smarty_Internal_Templateparser::TP_EQUAL;
}
incdec {
$this->token = Smarty_Internal_Templateparser::TP_INCDEC;
}
unimath {
$this->token = Smarty_Internal_Templateparser::TP_UNIMATH;
}
math {
$this->token = Smarty_Internal_Templateparser::TP_MATH;
}
at {
$this->token = Smarty_Internal_Templateparser::TP_AT;
}
array openP {
$this->token = Smarty_Internal_Templateparser::TP_ARRAYOPEN;
}
hatch {
$this->token = Smarty_Internal_Templateparser::TP_HATCH;
}
attr {
// resolve conflicts with shorttag and right_delimiter starting with '='
if (substr($this->data, $this->counter + strlen($this->value) - 1, $this->compiler->getRdelLength()) === $this->smarty->getRightDelimiter()) {
preg_match('/\s+/',$this->value,$match);
$this->value = $match[0];
$this->token = Smarty_Internal_Templateparser::TP_SPACE;
} else {
$this->token = Smarty_Internal_Templateparser::TP_ATTR;
}
}
namespace {
$this->token = Smarty_Internal_Templateparser::TP_NAMESPACE;
}
id {
$this->token = Smarty_Internal_Templateparser::TP_ID;
}
integer {
$this->token = Smarty_Internal_Templateparser::TP_INTEGER;
}
backtick {
$this->token = Smarty_Internal_Templateparser::TP_BACKTICK;
$this->yypopstate();
}
vert {
$this->token = Smarty_Internal_Templateparser::TP_VERT;
}
dot {
$this->token = Smarty_Internal_Templateparser::TP_DOT;
}
comma {
$this->token = Smarty_Internal_Templateparser::TP_COMMA;
}
semicolon {
$this->token = Smarty_Internal_Templateparser::TP_SEMICOLON;
}
doublecolon {
$this->token = Smarty_Internal_Templateparser::TP_DOUBLECOLON;
}
colon {
$this->token = Smarty_Internal_Templateparser::TP_COLON;
}
qmark {
$this->token = Smarty_Internal_Templateparser::TP_QMARK;
}
hex {
$this->token = Smarty_Internal_Templateparser::TP_HEX;
}
space {
$this->token = Smarty_Internal_Templateparser::TP_SPACE;
}
char {
$this->token = Smarty_Internal_Templateparser::TP_TEXT;
}
*/
/*!lex2php
%statename LITERAL
ldel literal rdel {
$this->literal_cnt++;
$this->token = Smarty_Internal_Templateparser::TP_LITERAL;
}
ldel slash literal rdel {
if ($this->literal_cnt) {
$this->literal_cnt--;
$this->token = Smarty_Internal_Templateparser::TP_LITERAL;
} else {
$this->token = Smarty_Internal_Templateparser::TP_LITERALEND;
$this->yypopstate();
}
}
char {
if (!isset($this->yy_global_literal)) {
$this->yy_global_literal = $this->replace('/(SMARTYldel)SMARTYal[\/]?literalSMARTYrdel/isS');
}
$to = $this->dataLength;
preg_match($this->yy_global_literal, $this->data,$match,PREG_OFFSET_CAPTURE,$this->counter);
if (isset($match[0][1])) {
$to = $match[0][1];
} else {
$this->compiler->trigger_template_error ("missing or misspelled literal closing tag");
}
$this->value = substr($this->data,$this->counter,$to-$this->counter);
$this->token = Smarty_Internal_Templateparser::TP_LITERAL;
}
*/
/*!lex2php
%statename DOUBLEQUOTEDSTRING
userliteral {
$this->token = Smarty_Internal_Templateparser::TP_TEXT;
}
ldel literal rdel {
$this->token = Smarty_Internal_Templateparser::TP_TEXT;
}
ldel slash literal rdel {
$this->token = Smarty_Internal_Templateparser::TP_TEXT;
}
ldel slash {
$this->yypushstate(self::TAG);
return true;
}
ldel id {
$this->yypushstate(self::TAG);
return true;
}
ldel {
$this->token = Smarty_Internal_Templateparser::TP_LDEL;
$this->taglineno = $this->line;
$this->yypushstate(self::TAGBODY);
}
double_quote {
$this->token = Smarty_Internal_Templateparser::TP_QUOTE;
$this->yypopstate();
}
backtick dollar {
$this->token = Smarty_Internal_Templateparser::TP_BACKTICK;
$this->value = substr($this->value,0,-1);
$this->yypushstate(self::TAGBODY);
$this->taglineno = $this->line;
}
dollar id {
$this->token = Smarty_Internal_Templateparser::TP_DOLLARID;
}
dollar {
$this->token = Smarty_Internal_Templateparser::TP_TEXT;
}
textdoublequoted {
$this->token = Smarty_Internal_Templateparser::TP_TEXT;
}
char {
$to = $this->dataLength;
$this->value = substr($this->data,$this->counter,$to-$this->counter);
$this->token = Smarty_Internal_Templateparser::TP_TEXT;
}
*/
}

File diff suppressed because it is too large Load Diff

111
system/vendor/smarty/libs/Autoloader.php vendored Normal file
View File

@ -0,0 +1,111 @@
<?php
/**
* Smarty Autoloader
*
* @package Smarty
*/
if (!defined('SMARTY_HELPER_FUNCTIONS_LOADED')) {
include __DIR__ . '/functions.php';
}
/**
* Smarty Autoloader
*
* @package Smarty
* @author Uwe Tews
* Usage:
* require_once '...path/Autoloader.php';
* Smarty_Autoloader::register();
* or
* include '...path/bootstrap.php';
*
* $smarty = new Smarty();
*/
class Smarty_Autoloader
{
/**
* Filepath to Smarty root
*
* @var string
*/
public static $SMARTY_DIR = null;
/**
* Filepath to Smarty internal plugins
*
* @var string
*/
public static $SMARTY_SYSPLUGINS_DIR = null;
/**
* Array with Smarty core classes and their filename
*
* @var array
*/
public static $rootClasses = array('smarty' => 'Smarty.class.php');
/**
* Registers Smarty_Autoloader backward compatible to older installations.
*
* @param bool $prepend Whether to prepend the autoloader or not.
*/
public static function registerBC($prepend = false)
{
/**
* register the class autoloader
*/
if (!defined('SMARTY_SPL_AUTOLOAD')) {
define('SMARTY_SPL_AUTOLOAD', 0);
}
if (SMARTY_SPL_AUTOLOAD
&& set_include_path(get_include_path() . PATH_SEPARATOR . SMARTY_SYSPLUGINS_DIR) !== false
) {
$registeredAutoLoadFunctions = spl_autoload_functions();
if (!isset($registeredAutoLoadFunctions[ 'spl_autoload' ])) {
spl_autoload_register();
}
} else {
self::register($prepend);
}
}
/**
* Registers Smarty_Autoloader as an SPL autoloader.
*
* @param bool $prepend Whether to prepend the autoloader or not.
*/
public static function register($prepend = false)
{
self::$SMARTY_DIR = defined('SMARTY_DIR') ? SMARTY_DIR : __DIR__ . DIRECTORY_SEPARATOR;
self::$SMARTY_SYSPLUGINS_DIR = defined('SMARTY_SYSPLUGINS_DIR') ? SMARTY_SYSPLUGINS_DIR :
self::$SMARTY_DIR . 'sysplugins' . DIRECTORY_SEPARATOR;
spl_autoload_register(array(__CLASS__, 'autoload'), true, $prepend);
}
/**
* Handles auto loading of classes.
*
* @param string $class A class name.
*/
public static function autoload($class)
{
if ($class[ 0 ] !== 'S' || strpos($class, 'Smarty') !== 0) {
return;
}
$_class = smarty_strtolower_ascii($class);
if (isset(self::$rootClasses[ $_class ])) {
$file = self::$SMARTY_DIR . self::$rootClasses[ $_class ];
if (is_file($file)) {
include $file;
}
} else {
$file = self::$SMARTY_SYSPLUGINS_DIR . $_class . '.php';
if (is_file($file)) {
include $file;
}
}
return;
}
}

1405
system/vendor/smarty/libs/Smarty.class.php vendored Normal file

File diff suppressed because it is too large Load Diff

16
system/vendor/smarty/libs/bootstrap.php vendored Normal file
View File

@ -0,0 +1,16 @@
<?php
/**
* This file is part of the Smarty package.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Load and register Smarty Autoloader
*/
if (!class_exists('Smarty_Autoloader')) {
include __DIR__ . '/Autoloader.php';
}
Smarty_Autoloader::register(true);

175
system/vendor/smarty/libs/debug.tpl vendored Normal file
View File

@ -0,0 +1,175 @@
{capture name='_smarty_debug' assign=debug_output}
<!DOCTYPE html>
<html lang="en">
<head>
<title>Smarty Debug Console</title>
<style>
{literal}
body, h1, h2, h3, td, th, p {
font-family: sans-serif;
font-weight: normal;
font-size: 0.9em;
margin: 1px;
padding: 0;
}
h1 {
margin: 0;
text-align: left;
padding: 2px;
background-color: #f0c040;
color: black;
font-weight: bold;
font-size: 1.2em;
}
h2 {
background-color: #9B410E;
color: white;
text-align: left;
font-weight: bold;
padding: 2px;
border-top: 1px solid black;
}
h3 {
text-align: left;
font-weight: bold;
color: black;
font-size: 0.7em;
padding: 2px;
}
body {
background: black;
}
p, table, div {
background: #f0ead8;
}
p {
margin: 0;
font-style: italic;
text-align: center;
}
table {
width: 100%;
}
th, td {
font-family: monospace;
vertical-align: top;
text-align: left;
}
td {
color: green;
}
tr:nth-child(odd) {
background-color: #eeeeee;
}
tr:nth-child(even) {
background-color: #fafafa;
}
.exectime {
font-size: 0.8em;
font-style: italic;
}
#bold div {
color: black;
font-weight: bold;
}
#blue h3 {
color: blue;
}
#normal div {
color: black;
font-weight: normal;
}
#table_assigned_vars th {
color: blue;
font-weight: bold;
}
#table_config_vars th {
color: maroon;
}
{/literal}
</style>
</head>
<body>
<h1>Smarty {Smarty::SMARTY_VERSION} Debug Console
- {if isset($template_name)}{$template_name|debug_print_var nofilter} {/if}{if !empty($template_data)}Total Time {$execution_time|string_format:"%.5f"}{/if}</h1>
{if !empty($template_data)}
<h2>included templates &amp; config files (load time in seconds)</h2>
<div>
{foreach $template_data as $template}
<span style="color: brown;">{$template.name}</span>
<br>&nbsp;&nbsp;<span class="exectime">
(compile {$template['compile_time']|string_format:"%.5f"}) (render {$template['render_time']|string_format:"%.5f"}) (cache {$template['cache_time']|string_format:"%.5f"})
</span>
<br>
{/foreach}
</div>
{/if}
<h2>assigned template variables</h2>
<table id="table_assigned_vars">
{foreach $assigned_vars as $vars}
<tr>
<td>
<h3 style="color: blue;">${$vars@key}</h3>
{if isset($vars['nocache'])}<strong>Nocache</strong><br>{/if}
{if isset($vars['scope'])}<strong>Origin:</strong> {$vars['scope']|debug_print_var nofilter}{/if}
</td>
<td>
<h3>Value</h3>
{$vars['value']|debug_print_var:10:80 nofilter}
</td>
<td>
{if isset($vars['attributes'])}
<h3>Attributes</h3>
{$vars['attributes']|debug_print_var nofilter}
{/if}
</td>
{/foreach}
</table>
<h2>assigned config file variables</h2>
<table id="table_config_vars">
{foreach $config_vars as $vars}
<tr>
<td>
<h3 style="color: blue;">#{$vars@key}#</h3>
{if isset($vars['scope'])}<strong>Origin:</strong> {$vars['scope']|debug_print_var nofilter}{/if}
</td>
<td>
{$vars['value']|debug_print_var:10:80 nofilter}
</td>
</tr>
{/foreach}
</table>
</body>
</html>
{/capture}
<script type="text/javascript">
{$id = '__Smarty__'}
{if $display_mode}{$id = "$offset$template_name"|md5}{/if}
_smarty_console = window.open("", "console{$id}", "width=1024,height=600,left={$offset},top={$offset},resizable,scrollbars=yes");
_smarty_console.document.write("{$debug_output|escape:'javascript' nofilter}");
_smarty_console.document.close();
</script>

51
system/vendor/smarty/libs/functions.php vendored Normal file
View File

@ -0,0 +1,51 @@
<?php
/**
* This file is part of the Smarty package.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Registers some helper/polyfill functions.
*/
const SMARTY_HELPER_FUNCTIONS_LOADED = true;
/**
* Converts the first characters in $string to uppercase (A-Z) if it is an ASCII lowercase character (a-z).
*
* May not be required when running PHP8.2+: https://wiki.php.net/rfc/strtolower-ascii
*
* @param $string
*
* @return string
*/
function smarty_ucfirst_ascii($string): string {
return smarty_strtoupper_ascii(substr($string, 0, 1)) . substr($string, 1);
}
/**
* Converts all uppercase ASCII characters (A-Z) in $string to lowercase (a-z).
*
* May not be required when running PHP8.2+: https://wiki.php.net/rfc/strtolower-ascii
*
* @param $string
*
* @return string
*/
function smarty_strtolower_ascii($string): string {
return strtr($string, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz');
}
/**
* Converts all lowercase ASCII characters (a-z) in $string to uppercase (A-Z).
*
* May not be required when running PHP8.2+: https://wiki.php.net/rfc/strtolower-ascii
*
* @param $string
*
* @return string
*/
function smarty_strtoupper_ascii($string): string {
return strtr($string, 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ');
}

View File

@ -0,0 +1,121 @@
<?php
/**
* Smarty plugin to format text blocks
*
* @package Smarty
* @subpackage PluginsBlock
*/
/**
* Smarty {textformat}{/textformat} block plugin
* Type: block function
* Name: textformat
* Purpose: format text a certain way with preset styles
* or custom wrap/indent settings
* Params:
*
* - style - string (email)
* - indent - integer (0)
* - wrap - integer (80)
* - wrap_char - string ("\n")
* - indent_char - string (" ")
* - wrap_boundary - boolean (true)
*
* @link https://www.smarty.net/manual/en/language.function.textformat.php {textformat}
* (Smarty online manual)
*
* @param array $params parameters
* @param string $content contents of the block
* @param Smarty_Internal_Template $template template object
* @param boolean &$repeat repeat flag
*
* @return string content re-formatted
* @author Monte Ohrt <monte at ohrt dot com>
* @throws \SmartyException
*/
function smarty_block_textformat($params, $content, Smarty_Internal_Template $template, &$repeat)
{
if (is_null($content)) {
return;
}
if (Smarty::$_MBSTRING) {
$template->_checkPlugins(
array(
array(
'function' => 'smarty_modifier_mb_wordwrap',
'file' => SMARTY_PLUGINS_DIR . 'modifier.mb_wordwrap.php'
)
)
);
}
$style = null;
$indent = 0;
$indent_first = 0;
$indent_char = ' ';
$wrap = 80;
$wrap_char = "\n";
$wrap_cut = false;
$assign = null;
foreach ($params as $_key => $_val) {
switch ($_key) {
case 'style':
case 'indent_char':
case 'wrap_char':
case 'assign':
$$_key = (string)$_val;
break;
case 'indent':
case 'indent_first':
case 'wrap':
$$_key = (int)$_val;
break;
case 'wrap_cut':
$$_key = (bool)$_val;
break;
default:
trigger_error("textformat: unknown attribute '{$_key}'");
}
}
if ($style === 'email') {
$wrap = 72;
}
// split into paragraphs
$_paragraphs = preg_split('![\r\n]{2}!', $content);
foreach ($_paragraphs as &$_paragraph) {
if (!$_paragraph) {
continue;
}
// convert mult. spaces & special chars to single space
$_paragraph =
preg_replace(
array(
'!\s+!' . Smarty::$_UTF8_MODIFIER,
'!(^\s+)|(\s+$)!' . Smarty::$_UTF8_MODIFIER
),
array(
' ',
''
),
$_paragraph
);
// indent first line
if ($indent_first > 0) {
$_paragraph = str_repeat($indent_char, $indent_first) . $_paragraph;
}
// wordwrap sentences
if (Smarty::$_MBSTRING) {
$_paragraph = smarty_modifier_mb_wordwrap($_paragraph, $wrap - $indent, $wrap_char, $wrap_cut);
} else {
$_paragraph = wordwrap($_paragraph, $wrap - $indent, $wrap_char, $wrap_cut);
}
// indent lines
if ($indent > 0) {
$_paragraph = preg_replace('!^!m', str_repeat($indent_char, $indent), $_paragraph);
}
}
$_output = implode($wrap_char . $wrap_char, $_paragraphs);
if ($assign) {
$template->assign($assign, $_output);
} else {
return $_output;
}
}

View File

@ -0,0 +1,62 @@
<?php
/**
* Smarty plugin
*
* @package Smarty
* @subpackage PluginsFunction
*/
/**
* Smarty {counter} function plugin
* Type: function
* Name: counter
* Purpose: print out a counter value
*
* @author Monte Ohrt <monte at ohrt dot com>
* @link https://www.smarty.net/manual/en/language.function.counter.php {counter}
* (Smarty online manual)
*
* @param array $params parameters
* @param Smarty_Internal_Template $template template object
*
* @return string|null
*/
function smarty_function_counter($params, $template)
{
static $counters = array();
$name = (isset($params[ 'name' ])) ? $params[ 'name' ] : 'default';
if (!isset($counters[ $name ])) {
$counters[ $name ] = array('start' => 1, 'skip' => 1, 'direction' => 'up', 'count' => 1);
}
$counter =& $counters[ $name ];
if (isset($params[ 'start' ])) {
$counter[ 'start' ] = $counter[ 'count' ] = (int)$params[ 'start' ];
}
if (!empty($params[ 'assign' ])) {
$counter[ 'assign' ] = $params[ 'assign' ];
}
if (isset($counter[ 'assign' ])) {
$template->assign($counter[ 'assign' ], $counter[ 'count' ]);
}
if (isset($params[ 'print' ])) {
$print = (bool)$params[ 'print' ];
} else {
$print = empty($counter[ 'assign' ]);
}
if ($print) {
$retval = $counter[ 'count' ];
} else {
$retval = null;
}
if (isset($params[ 'skip' ])) {
$counter[ 'skip' ] = $params[ 'skip' ];
}
if (isset($params[ 'direction' ])) {
$counter[ 'direction' ] = $params[ 'direction' ];
}
if ($counter[ 'direction' ] === 'down') {
$counter[ 'count' ] -= $counter[ 'skip' ];
} else {
$counter[ 'count' ] += $counter[ 'skip' ];
}
return $retval;
}

View File

@ -0,0 +1,92 @@
<?php
/**
* Smarty plugin
*
* @package Smarty
* @subpackage PluginsFunction
*/
/**
* Smarty {cycle} function plugin
* Type: function
* Name: cycle
* Date: May 3, 2002
* Purpose: cycle through given values
* Params:
*
* - name - name of cycle (optional)
* - values - comma separated list of values to cycle, or an array of values to cycle
* (this can be left out for subsequent calls)
* - reset - boolean - resets given var to true
* - print - boolean - print var or not. default is true
* - advance - boolean - whether or not to advance the cycle
* - delimiter - the value delimiter, default is ","
* - assign - boolean, assigns to template var instead of printed.
*
* Examples:
*
* {cycle values="#eeeeee,#d0d0d0d"}
* {cycle name=row values="one,two,three" reset=true}
* {cycle name=row}
*
* @link https://www.smarty.net/manual/en/language.function.cycle.php {cycle}
* (Smarty online manual)
* @author Monte Ohrt <monte at ohrt dot com>
* @author credit to Mark Priatel <mpriatel@rogers.com>
* @author credit to Gerard <gerard@interfold.com>
* @author credit to Jason Sweat <jsweat_php@yahoo.com>
* @version 1.3
*
* @param array $params parameters
* @param Smarty_Internal_Template $template template object
*
* @return string|null
*/
function smarty_function_cycle($params, $template)
{
static $cycle_vars;
$name = (empty($params[ 'name' ])) ? 'default' : $params[ 'name' ];
$print = (isset($params[ 'print' ])) ? (bool)$params[ 'print' ] : true;
$advance = (isset($params[ 'advance' ])) ? (bool)$params[ 'advance' ] : true;
$reset = (isset($params[ 'reset' ])) ? (bool)$params[ 'reset' ] : false;
if (!isset($params[ 'values' ])) {
if (!isset($cycle_vars[ $name ][ 'values' ])) {
trigger_error('cycle: missing \'values\' parameter');
return;
}
} else {
if (isset($cycle_vars[ $name ][ 'values' ]) && $cycle_vars[ $name ][ 'values' ] !== $params[ 'values' ]) {
$cycle_vars[ $name ][ 'index' ] = 0;
}
$cycle_vars[ $name ][ 'values' ] = $params[ 'values' ];
}
if (isset($params[ 'delimiter' ])) {
$cycle_vars[ $name ][ 'delimiter' ] = $params[ 'delimiter' ];
} elseif (!isset($cycle_vars[ $name ][ 'delimiter' ])) {
$cycle_vars[ $name ][ 'delimiter' ] = ',';
}
if (is_array($cycle_vars[ $name ][ 'values' ])) {
$cycle_array = $cycle_vars[ $name ][ 'values' ];
} else {
$cycle_array = explode($cycle_vars[ $name ][ 'delimiter' ], $cycle_vars[ $name ][ 'values' ]);
}
if (!isset($cycle_vars[ $name ][ 'index' ]) || $reset) {
$cycle_vars[ $name ][ 'index' ] = 0;
}
if (isset($params[ 'assign' ])) {
$print = false;
$template->assign($params[ 'assign' ], $cycle_array[ $cycle_vars[ $name ][ 'index' ] ]);
}
if ($print) {
$retval = $cycle_array[ $cycle_vars[ $name ][ 'index' ] ];
} else {
$retval = null;
}
if ($advance) {
if ($cycle_vars[ $name ][ 'index' ] >= count($cycle_array) - 1) {
$cycle_vars[ $name ][ 'index' ] = 0;
} else {
$cycle_vars[ $name ][ 'index' ]++;
}
}
return $retval;
}

View File

@ -0,0 +1,204 @@
<?php
/**
* Smarty plugin
*
* @package Smarty
* @subpackage PluginsFunction
*/
/**
* Smarty {fetch} plugin
* Type: function
* Name: fetch
* Purpose: fetch file, web or ftp data and display results
*
* @link https://www.smarty.net/manual/en/language.function.fetch.php {fetch}
* (Smarty online manual)
* @author Monte Ohrt <monte at ohrt dot com>
*
* @param array $params parameters
* @param Smarty_Internal_Template $template template object
*
* @throws SmartyException
* @return string|null if the assign parameter is passed, Smarty assigns the result to a template variable
*/
function smarty_function_fetch($params, $template)
{
if (empty($params[ 'file' ])) {
trigger_error('[plugin] fetch parameter \'file\' cannot be empty', E_USER_NOTICE);
return;
}
// strip file protocol
if (stripos($params[ 'file' ], 'file://') === 0) {
$params[ 'file' ] = substr($params[ 'file' ], 7);
}
$protocol = strpos($params[ 'file' ], '://');
if ($protocol !== false) {
$protocol = strtolower(substr($params[ 'file' ], 0, $protocol));
}
if (isset($template->smarty->security_policy)) {
if ($protocol) {
// remote resource (or php stream, …)
if (!$template->smarty->security_policy->isTrustedUri($params[ 'file' ])) {
return;
}
} else {
// local file
if (!$template->smarty->security_policy->isTrustedResourceDir($params[ 'file' ])) {
return;
}
}
}
$content = '';
if ($protocol === 'http') {
// http fetch
if ($uri_parts = parse_url($params[ 'file' ])) {
// set defaults
$host = $server_name = $uri_parts[ 'host' ];
$timeout = 30;
$accept = 'image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*';
$agent = 'Smarty Template Engine ' . Smarty::SMARTY_VERSION;
$referer = '';
$uri = !empty($uri_parts[ 'path' ]) ? $uri_parts[ 'path' ] : '/';
$uri .= !empty($uri_parts[ 'query' ]) ? '?' . $uri_parts[ 'query' ] : '';
$_is_proxy = false;
if (empty($uri_parts[ 'port' ])) {
$port = 80;
} else {
$port = $uri_parts[ 'port' ];
}
if (!empty($uri_parts[ 'user' ])) {
$user = $uri_parts[ 'user' ];
}
if (!empty($uri_parts[ 'pass' ])) {
$pass = $uri_parts[ 'pass' ];
}
// loop through parameters, setup headers
foreach ($params as $param_key => $param_value) {
switch ($param_key) {
case 'file':
case 'assign':
case 'assign_headers':
break;
case 'user':
if (!empty($param_value)) {
$user = $param_value;
}
break;
case 'pass':
if (!empty($param_value)) {
$pass = $param_value;
}
break;
case 'accept':
if (!empty($param_value)) {
$accept = $param_value;
}
break;
case 'header':
if (!empty($param_value)) {
if (!preg_match('![\w\d-]+: .+!', $param_value)) {
trigger_error("[plugin] invalid header format '{$param_value}'", E_USER_NOTICE);
return;
} else {
$extra_headers[] = $param_value;
}
}
break;
case 'proxy_host':
if (!empty($param_value)) {
$proxy_host = $param_value;
}
break;
case 'proxy_port':
if (!preg_match('!\D!', $param_value)) {
$proxy_port = (int)$param_value;
} else {
trigger_error("[plugin] invalid value for attribute '{$param_key }'", E_USER_NOTICE);
return;
}
break;
case 'agent':
if (!empty($param_value)) {
$agent = $param_value;
}
break;
case 'referer':
if (!empty($param_value)) {
$referer = $param_value;
}
break;
case 'timeout':
if (!preg_match('!\D!', $param_value)) {
$timeout = (int)$param_value;
} else {
trigger_error("[plugin] invalid value for attribute '{$param_key}'", E_USER_NOTICE);
return;
}
break;
default:
trigger_error("[plugin] unrecognized attribute '{$param_key}'", E_USER_NOTICE);
return;
}
}
if (!empty($proxy_host) && !empty($proxy_port)) {
$_is_proxy = true;
$fp = fsockopen($proxy_host, $proxy_port, $errno, $errstr, $timeout);
} else {
$fp = fsockopen($server_name, $port, $errno, $errstr, $timeout);
}
if (!$fp) {
trigger_error("[plugin] unable to fetch: $errstr ($errno)", E_USER_NOTICE);
return;
} else {
if ($_is_proxy) {
fputs($fp, 'GET ' . $params[ 'file' ] . " HTTP/1.0\r\n");
} else {
fputs($fp, "GET $uri HTTP/1.0\r\n");
}
if (!empty($host)) {
fputs($fp, "Host: $host\r\n");
}
if (!empty($accept)) {
fputs($fp, "Accept: $accept\r\n");
}
if (!empty($agent)) {
fputs($fp, "User-Agent: $agent\r\n");
}
if (!empty($referer)) {
fputs($fp, "Referer: $referer\r\n");
}
if (isset($extra_headers) && is_array($extra_headers)) {
foreach ($extra_headers as $curr_header) {
fputs($fp, $curr_header . "\r\n");
}
}
if (!empty($user) && !empty($pass)) {
fputs($fp, 'Authorization: BASIC ' . base64_encode("$user:$pass") . "\r\n");
}
fputs($fp, "\r\n");
while (!feof($fp)) {
$content .= fgets($fp, 4096);
}
fclose($fp);
$csplit = preg_split("!\r\n\r\n!", $content, 2);
$content = $csplit[ 1 ];
if (!empty($params[ 'assign_headers' ])) {
$template->assign($params[ 'assign_headers' ], preg_split("!\r\n!", $csplit[ 0 ]));
}
}
} else {
trigger_error("[plugin fetch] unable to parse URL, check syntax", E_USER_NOTICE);
return;
}
} else {
$content = @file_get_contents($params[ 'file' ]);
if ($content === false) {
throw new SmartyException("{fetch} cannot read resource '" . $params[ 'file' ] . "'");
}
}
if (!empty($params[ 'assign' ])) {
$template->assign($params[ 'assign' ], $content);
} else {
return $content;
}
}

View File

@ -0,0 +1,286 @@
<?php
/**
* Smarty plugin
*
* @package Smarty
* @subpackage PluginsFunction
*/
/**
* Smarty {html_checkboxes} function plugin
* File: function.html_checkboxes.php
* Type: function
* Name: html_checkboxes
* Date: 24.Feb.2003
* Purpose: Prints out a list of checkbox input types
* Examples:
*
* {html_checkboxes values=$ids output=$names}
* {html_checkboxes values=$ids name='box' separator='<br>' output=$names}
* {html_checkboxes values=$ids checked=$checked separator='<br>' output=$names}
*
* Params:
*
* - name (optional) - string default "checkbox"
* - values (required) - array
* - options (optional) - associative array
* - checked (optional) - array default not set
* - separator (optional) - ie <br> or &nbsp;
* - output (optional) - the output next to each checkbox
* - assign (optional) - assign the output as an array to this variable
* - escape (optional) - escape the content (not value), defaults to true
*
* @link https://www.smarty.net/manual/en/language.function.html.checkboxes.php {html_checkboxes}
* (Smarty online manual)
* @author Christopher Kvarme <christopher.kvarme@flashjab.com>
* @author credits to Monte Ohrt <monte at ohrt dot com>
* @version 1.0
*
* @param array $params parameters
* @param Smarty_Internal_Template $template template object
*
* @return string
* @uses smarty_function_escape_special_chars()
* @throws \SmartyException
*/
function smarty_function_html_checkboxes($params, Smarty_Internal_Template $template)
{
$template->_checkPlugins(
array(
array(
'function' => 'smarty_function_escape_special_chars',
'file' => SMARTY_PLUGINS_DIR . 'shared.escape_special_chars.php'
)
)
);
$name = 'checkbox';
$values = null;
$options = null;
$selected = array();
$separator = '';
$escape = true;
$labels = true;
$label_ids = false;
$output = null;
$extra = '';
foreach ($params as $_key => $_val) {
switch ($_key) {
case 'name':
case 'separator':
$$_key = (string)$_val;
break;
case 'escape':
case 'labels':
case 'label_ids':
$$_key = (bool)$_val;
break;
case 'options':
$$_key = (array)$_val;
break;
case 'values':
case 'output':
$$_key = array_values((array)$_val);
break;
case 'checked':
case 'selected':
if (is_array($_val)) {
$selected = array();
foreach ($_val as $_sel) {
if (is_object($_sel)) {
if (method_exists($_sel, '__toString')) {
$_sel = smarty_function_escape_special_chars((string)$_sel->__toString());
} else {
trigger_error(
'html_checkboxes: selected attribute contains an object of class \'' .
get_class($_sel) . '\' without __toString() method',
E_USER_NOTICE
);
continue;
}
} else {
$_sel = smarty_function_escape_special_chars((string)$_sel);
}
$selected[ $_sel ] = true;
}
} elseif (is_object($_val)) {
if (method_exists($_val, '__toString')) {
$selected = smarty_function_escape_special_chars((string)$_val->__toString());
} else {
trigger_error(
'html_checkboxes: selected attribute is an object of class \'' . get_class($_val) .
'\' without __toString() method',
E_USER_NOTICE
);
}
} else {
$selected = smarty_function_escape_special_chars((string)$_val);
}
break;
case 'checkboxes':
trigger_error(
'html_checkboxes: the use of the "checkboxes" attribute is deprecated, use "options" instead',
E_USER_WARNING
);
$options = (array)$_val;
break;
case 'assign':
break;
case 'strict':
break;
case 'disabled':
case 'readonly':
if (!empty($params[ 'strict' ])) {
if (!is_scalar($_val)) {
trigger_error(
"html_options: {$_key} attribute must be a scalar, only boolean true or string '{$_key}' will actually add the attribute",
E_USER_NOTICE
);
}
if ($_val === true || $_val === $_key) {
$extra .= ' ' . $_key . '="' . smarty_function_escape_special_chars($_key) . '"';
}
break;
}
// omit break; to fall through!
// no break
default:
if (!is_array($_val)) {
$extra .= ' ' . $_key . '="' . smarty_function_escape_special_chars($_val) . '"';
} else {
trigger_error("html_checkboxes: extra attribute '{$_key}' cannot be an array", E_USER_NOTICE);
}
break;
}
}
if (!isset($options) && !isset($values)) {
return '';
} /* raise error here? */
$_html_result = array();
if (isset($options)) {
foreach ($options as $_key => $_val) {
$_html_result[] =
smarty_function_html_checkboxes_output(
$name,
$_key,
$_val,
$selected,
$extra,
$separator,
$labels,
$label_ids,
$escape
);
}
} else {
foreach ($values as $_i => $_key) {
$_val = isset($output[ $_i ]) ? $output[ $_i ] : '';
$_html_result[] =
smarty_function_html_checkboxes_output(
$name,
$_key,
$_val,
$selected,
$extra,
$separator,
$labels,
$label_ids,
$escape
);
}
}
if (!empty($params[ 'assign' ])) {
$template->assign($params[ 'assign' ], $_html_result);
} else {
return implode("\n", $_html_result);
}
}
/**
* @param $name
* @param $value
* @param $output
* @param $selected
* @param $extra
* @param $separator
* @param $labels
* @param $label_ids
* @param bool $escape
*
* @return string
*/
function smarty_function_html_checkboxes_output(
$name,
$value,
$output,
$selected,
$extra,
$separator,
$labels,
$label_ids,
$escape = true
) {
$_output = '';
if (is_object($value)) {
if (method_exists($value, '__toString')) {
$value = (string)$value->__toString();
} else {
trigger_error(
'html_options: value is an object of class \'' . get_class($value) .
'\' without __toString() method',
E_USER_NOTICE
);
return '';
}
} else {
$value = (string)$value;
}
if (is_object($output)) {
if (method_exists($output, '__toString')) {
$output = (string)$output->__toString();
} else {
trigger_error(
'html_options: output is an object of class \'' . get_class($output) .
'\' without __toString() method',
E_USER_NOTICE
);
return '';
}
} else {
$output = (string)$output;
}
if ($labels) {
if ($label_ids) {
$_id = smarty_function_escape_special_chars(
preg_replace(
'![^\w\-\.]!' . Smarty::$_UTF8_MODIFIER,
'_',
$name . '_' . $value
)
);
$_output .= '<label for="' . $_id . '">';
} else {
$_output .= '<label>';
}
}
$name = smarty_function_escape_special_chars($name);
$value = smarty_function_escape_special_chars($value);
if ($escape) {
$output = smarty_function_escape_special_chars($output);
}
$_output .= '<input type="checkbox" name="' . $name . '[]" value="' . $value . '"';
if ($labels && $label_ids) {
$_output .= ' id="' . $_id . '"';
}
if (is_array($selected)) {
if (isset($selected[ $value ])) {
$_output .= ' checked="checked"';
}
} elseif ($value === $selected) {
$_output .= ' checked="checked"';
}
$_output .= $extra . ' />' . $output;
if ($labels) {
$_output .= '</label>';
}
$_output .= $separator;
return $_output;
}

BIN
ui/ui/Ass/.DS_Store vendored Normal file

Binary file not shown.

30929
ui/ui/Ass/css/style.css Normal file

File diff suppressed because it is too large Load Diff

BIN
ui/ui/Ass/icons/.DS_Store vendored Normal file

Binary file not shown.

258
ui/ui/hotspot-edit.tpl Normal file
View File

@ -0,0 +1,258 @@
{include file="sections/header.tpl"}
<div class="container-fluid">
<div class="row">
<div class="col-sm-12 col-md-12">
<div class="card card-primary card-hovered card-stacked mb30">
<div class="card-header">{Lang::T('Edit Service Plan')} || {$d['name_plan']}</div>
<div class="card-body">
<form class="form-horizontal" method="post" role="form" action="{$_url}services/edit-post">
<input type="hidden" name="id" value="{$d['id']}">
<div class="form-group row">
<label class="col-md-2 control-label">{Lang::T('Status')}</label>
<div class="col-md-10">
<input type="radio" name="enabled" value="1" {if $d['enabled'] == 1}checked{/if}> Enable
<input type="radio" name="enabled" value="0" {if $d['enabled'] == 0}checked{/if}> Disable
</div>
</div>
<div class="form-group row">
<label class="col-md-2 control-label">{Lang::T('Type')}</label>
<div class="col-md-10">
<input type="radio" name="prepaid" onclick="prePaid()" value="yes"
{if $d['prepaid'] == yes}checked{/if}>
Prepaid
<input type="radio" name="prepaid" onclick="postPaid()" value="no"
{if $d['prepaid'] == no}checked{/if}> Postpaid
</div>
</div>
<div class="form-group row">
<label class="col-md-2 control-label">{Lang::T('Plan Type')}</label>
<div class="col-md-10">
<input type="radio" name="plan_type" value="Personal"
{if $d['plan_type'] == 'Personal'}checked{/if}>
Personal
<input type="radio" name="plan_type" value="Business"
{if $d['plan_type'] == 'Business'}checked{/if}> Business
</div>
</div>
{if $_c['radius_enable'] and $d['is_radius']}
<div class="form-group row">
<label class="col-md-2 control-label">Radius</label>
<div class="col-md-10">
<label class="label label-primary">RADIUS</label>
</div>
</div>
{/if}
<div class="form-group row">
<label class="col-md-2 control-label">{Lang::T('Plan Name')}</label>
<div class="col-md-6">
<input type="text" class="form-control" id="name" name="name" maxlength="40"
value="{$d['name_plan']}">
</div>
</div>
<div class="form-group row">
<label class="col-md-2 control-label">{Lang::T('Plan Type')}</label>
<div class="col-md-10">
<input type="radio" id="Unlimited" name="typebp" value="Unlimited"
{if $d['typebp'] eq 'Unlimited'} checked {/if}> {Lang::T('Unlimited')}
<input type="radio" id="Limited" {if $_c['radius_enable'] and $d['is_radius']}disabled{/if}
name="typebp" value="Limited" {if $d['typebp'] eq 'Limited'} checked {/if}>
{Lang::T('Limited')}
</div>
</div>
<div {if $d['typebp'] eq 'Unlimited'} style="display:none;" {/if} id="Type">
<div class="form-group row">
<label class="col-md-2 control-label">{Lang::T('Limit Type')}</label>
<div class="col-md-10">
<input type="radio" id="Time_Limit" name="limit_type" value="Time_Limit"
{if $d['limit_type'] eq 'Time_Limit'} checked {/if}> {Lang::T('Time Limit')}
<input type="radio" id="Data_Limit" name="limit_type" value="Data_Limit"
{if $d['limit_type'] eq 'Data_Limit'} checked {/if}> {Lang::T('Data Limit')}
<input type="radio" id="Both_Limit" name="limit_type" value="Both_Limit"
{if $d['limit_type'] eq 'Both_Limit'} checked {/if}> {Lang::T('Both Limit')}
</div>
</div>
</div>
<div {if $d['typebp'] eq 'Unlimited'} style="display:none;"
{elseif ($d['time_limit']) eq '0'}
style="display:none;" {/if} id="TimeLimit">
<div class="form-group row">
<label class="col-md-2 control-label">{Lang::T('Time Limit')}</label>
<div class="col-md-4">
<input type="text" class="form-control" id="time_limit" name="time_limit"
value="{$d['time_limit']}">
</div>
<div class="col-md-2">
<select class="form-select" style="height: 52px; background-color: white;" id="time_unit" name="time_unit">
<option value="Hrs" {if $d['time_unit'] eq 'Hrs'} selected {/if}>{Lang::T('Hrs')}
</option>
<option value="Mins" {if $d['time_unit'] eq 'Mins'} selected {/if}>{Lang::T('Mins')}
</option>
</select>
</div>
</div>
</div>
<div {if $d['typebp'] eq 'Unlimited'} style="display:none;"
{elseif ($d['data_limit']) eq '0'}
style="display:none;" {/if} id="DataLimit">
<div class="form-group row">
<label class="col-md-2 control-label">{Lang::T('Data Limit')}</label>
<div class="col-md-4">
<input type="text" class="form-control" id="data_limit" name="data_limit"
value="{$d['data_limit']}">
</div>
<div class="col-md-2">
<select class="form-select" style="height: 52px; background-color: white;" id="data_unit" name="data_unit">
<option value="MB" {if $d['data_unit'] eq 'MB'} selected {/if}>MBs</option>
<option value="GB" {if $d['data_unit'] eq 'GB'} selected {/if}>GBs</option>
</select>
</div>
</div>
</div>
<div class="form-group row">
<label class="col-md-2 control-label"><a
href="{$_url}bandwidth/add">{Lang::T('Bandwidth Name')}</a></label>
<div class="col-md-6">
<select id="id_bw" name="id_bw" class="form-select" style="height: 52px; background-color: white;">
{foreach $b as $bs}
<option value="{$bs['id']}" {if $d['id_bw'] eq $bs['id']} selected {/if}>
{$bs['name_bw']}</option>
{/foreach}
</select>
</div>
</div>
<div class="form-group row">
<label class="col-md-2 control-label">{Lang::T('Plan Price')}</label>
<div class="col-md-6">
<div class="input-group">
<span class="input-group-text" id="basic-addon1">{$_c['currency_code']}</span>
<input type="number" class="form-control" name="price" value="{$d['price']}" required>
</div>
</div>
</div>
<div class="form-group row">
<label class="col-md-2 control-label">{Lang::T('Shared Users')}</label>
<div class="col-md-6">
<input type="text" class="form-control" id="sharedusers" name="sharedusers"
value="{$d['shared_users']}">
</div>
</div>
<div class="form-group row">
<label class="col-md-2 control-label">{Lang::T('Plan Validity')}</label>
<div class="col-md-4">
<input type="text" class="form-control" id="validity" name="validity"
value="{$d['validity']}">
</div>
<div class="col-md-2">
<select class="form-select" style="height: 52px; background-color: white;" id="validity_unit" name="validity_unit">
{if $d['prepaid'] == yes}
<option value="Mins" {if $d['validity_unit'] eq 'Mins'} selected {/if}>{Lang::T('Mins')}
</option>
<option value="Hrs" {if $d['validity_unit'] eq 'Hrs'} selected {/if}>{Lang::T('Hrs')}
</option>
<option value="Days" {if $d['validity_unit'] eq 'Days'} selected {/if}>{Lang::T('Days')}
</option>
<option value="Months" {if $d['validity_unit'] eq 'Months'} selected {/if}>
{Lang::T('Months')}</option>
{else}
<option value="Period" {if $d['validity_unit'] eq 'Period'} selected {/if}>
{Lang::T('Period')}</option>
{/if}
</select>
</div>
<p class="help-block col-md-4">{Lang::T('1 Period = 1 Month, Expires the 20th of each month')}
</p>
</div>
<span id="routerChoose" class="{if $d['is_radius']}hidden{/if}">
<div class="form-group row">
<label class="col-md-2 control-label"><a
href="{$_url}routers/add">{Lang::T('Router Name')}</a></label>
<div class="col-md-6">
<input type="text" class="form-control" id="routers" name="routers"
value="{$d['routers']}" readonly>
</div>
</div>
</span>
<legend>{Lang::T('Expired Action')} <sub>{Lang::T('Optional')}</sub></legend>
<div class="form-group row">
<label class="col-md-2 control-label"><a
href="{$_url}pool/add">{Lang::T('Expired IP Pool')}</a></label>
<div class="col-md-6">
<select id="pool_expired" name="pool_expired" class="form-select" style="height: 52px; background-color: white;">
<option value=''>{Lang::T('Select Pool')}</option>
{foreach $p as $ps}
<option value="{$ps['pool_name']}" {if $d['pool_expired'] eq $ps['pool_name']} selected
{/if}>{$ps['pool_name']}</option>
{/foreach}
</select>
</div>
</div>
{* <div class="form-group row" id="AddressList">
<label class="col-md-2 control-label">{Lang::T('Address List')}</label>
<div class="col-md-6">
<input type="text" class="form-control" name="list_expired" id="list_expired" value="{$d['list_expired']}">
</div>
</div> *}
<center>
<div class="form-group row">
<div class="col-md-offset-2 col-md-10">
<button class="btn btn-success" type="submit">{Lang::T('Save Changes')}</button>
Or <a href="{$_url}services/hotspot">{Lang::T('Cancel')}</a>
</div>
</div>
</center>
</form>
</div>
</div>
</div>
</div>
<script>
var preOpt = `<option value="Mins">{Lang::T('Mins')}</option>
<option value="Hrs">{Lang::T('Hrs')}</option>
<option value="Days">{Lang::T('Days')}</option>
<option value="Months">{Lang::T('Months')}</option>`;
var postOpt = `<option value="Period">{Lang::T('Period')}</option>`;
function prePaid() {
$("#validity_unit").html(preOpt);
}
function postPaid() {
$("#validity_unit").html(postOpt);
}
</script>
{if $_c['radius_enable'] && $d['is_radius']}
{literal}
<script>
function isRadius(cek) {
if (cek.checked) {
$("#routerChoose").addClass('hidden');
document.getElementById("routers").required = false;
document.getElementById("Limited").disabled = true;
} else {
document.getElementById("Limited").disabled = false;
document.getElementById("routers").required = true;
$("#routerChoose").removeClass('hidden');
}
}
setTimeout(() => {
$.ajax({
url: "index.php?_route=autoload/pool",
data: "routers=radius",
cache: false,
success: function(msg) {
$("#pool_expired").html(msg);
}
});
}, 2000);
</script>
{/literal}
{/if}
</div>
{include file="sections/footer.tpl"}

8
ui/ui/index.html Normal file
View File

@ -0,0 +1,8 @@
<html>
<head>
<title>403 Forbidden</title>
</head>
<body>
<p>Directory access is forbidden.</p>
</body>
</html>

815
ui/ui/indexmain.tpl Normal file
View File

@ -0,0 +1,815 @@
{include file="sections/header.tpl"}
<div class="container-fluid">
<!-- Add Project -->
<div class="modal fade" id="addProjectSidebar">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Create Project</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<form>
<div class="form-group">
<label class="text-black font-w500">Project Name</label>
<input type="text" class="form-control">
</div>
<div class="form-group">
<label class="text-black font-w500">Dadeline</label>
<div class="cal-icon"><input type="date" class="form-control"><i
class="far fa-calendar-alt"></i></div>
</div>
<div class="form-group">
<label class="text-black font-w500">Client Name</label>
<input type="text" class="form-control">
</div>
<div class="form-group">
<button type="button" class="btn btn-primary">CREATE</button>
</div>
</form>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-xl-3 col-xxl-3 col-lg-6 col-sm-6">
<div class="card card-bd">
<div class="bg-secondary card-border" style="background:#3444d5 !important;"></div>
<div class="card-body box-style">
<div class="media align-items-center">
<div class="media-body me-3">
<h2 class="count num-text text-black font-w700">78</h2>
<span class="fs-14">Total Project Handled</span>
</div>
<svg width="36" height="36" viewBox="0 0 36 36" fill="none"
xmlns="http://www.w3.org/2000/svg">
<path
d="M34.422 13.9831C34.3341 13.721 34.1756 13.4884 33.9638 13.3108C33.7521 13.1332 33.4954 13.0175 33.222 12.9766L23.649 11.5141L19.353 2.36408C19.2319 2.10638 19.0399 1.88849 18.7995 1.73587C18.5591 1.58325 18.2803 1.5022 17.9955 1.5022C17.7108 1.5022 17.4319 1.58325 17.1915 1.73587C16.9511 1.88849 16.7592 2.10638 16.638 2.36408L12.342 11.5141L2.76902 12.9766C2.49635 13.0181 2.24042 13.1341 2.02937 13.3117C1.81831 13.4892 1.6603 13.7215 1.57271 13.9831C1.48511 14.2446 1.47133 14.5253 1.53287 14.7941C1.59441 15.063 1.72889 15.3097 1.92152 15.5071L8.89802 22.6501L7.24802 32.7571C7.20299 33.0345 7.23679 33.3189 7.34555 33.578C7.45431 33.8371 7.63367 34.0605 7.86319 34.2226C8.09271 34.3847 8.36315 34.4791 8.64371 34.495C8.92426 34.5109 9.20365 34.4477 9.45002 34.3126L18 29.5906L26.55 34.3126C26.7964 34.4489 27.0761 34.5131 27.3573 34.4978C27.6384 34.4826 27.9096 34.3885 28.1398 34.2264C28.37 34.0643 28.5499 33.8406 28.659 33.5811C28.768 33.3215 28.8018 33.0365 28.7565 32.7586L27.1065 22.6516L34.0785 15.5071C34.2703 15.3091 34.4037 15.0622 34.4643 14.7933C34.5249 14.5245 34.5103 14.2441 34.422 13.9831Z"
fill="#864AD1" />
</svg>
</div>
</div>
</div>
</div>
<div class="col-xl-3 col-xxl-3 col-lg-6 col-sm-6">
<div class="card card-bd">
<div class="bg-warning card-border"></div>
<div class="card-body box-style">
<div class="media align-items-center">
<div class="media-body me-3">
<h2 class="count num-text text-black font-w700">214</h2>
<span class="fs-14">Contacts You Have</span>
</div>
<svg width="36" height="36" viewBox="0 0 36 36" fill="none"
xmlns="http://www.w3.org/2000/svg">
<path
d="M17.8935 22.5C23.6925 22.5 28.3935 17.799 28.3935 12C28.3935 6.20101 23.6925 1.5 17.8935 1.5C12.0945 1.5 7.39351 6.20101 7.39351 12C7.39351 17.799 12.0945 22.5 17.8935 22.5Z"
fill="#FFB930" />
<path
d="M29.5605 21.3344C29.217 20.9909 28.851 20.6699 28.476 20.3564C27.2159 21.96 25.6078 23.2562 23.7733 24.1472C21.9388 25.0382 19.9259 25.5007 17.8864 25.4996C15.847 25.4986 13.8345 25.0342 12.0009 24.1414C10.1673 23.2486 8.56051 21.9507 7.30199 20.3459C5.447 21.8906 3.95577 23.8256 2.9347 26.013C1.91364 28.2003 1.3879 30.586 1.39499 32.9999C1.39499 33.3978 1.55303 33.7793 1.83433 34.0606C2.11564 34.3419 2.49717 34.4999 2.89499 34.4999H32.895C33.2928 34.4999 33.6743 34.3419 33.9557 34.0606C34.237 33.7793 34.395 33.3978 34.395 32.9999C34.4004 30.8324 33.9759 28.6854 33.146 26.683C32.3162 24.6807 31.0975 22.8627 29.5605 21.3344Z"
fill="#FFB930" />
</svg>
</div>
</div>
</div>
</div>
<div class="col-xl-3 col-xxl-3 col-lg-6 col-sm-6">
<div class="card card-bd">
<div class="bg-primary card-border"></div>
<div class="card-body box-style">
<div class="media align-items-center">
<div class="media-body me-3">
<h2 class="count num-text text-black font-w700">93</h2>
<span class="fs-14">Total Unfinished Task</span>
</div>
<svg class="primary-icon" width="36" height="36" viewBox="0 0 36 36" fill="none"
xmlns="http://www.w3.org/2000/svg">
<path
d="M11.9999 1.5H5.99994C3.51466 1.5 1.49994 3.51472 1.49994 6V29.8125C1.49994 32.2977 3.51466 34.3125 5.99994 34.3125H11.9999C14.4852 34.3125 16.4999 32.2977 16.4999 29.8125V6C16.4999 3.51472 14.4852 1.5 11.9999 1.5Z"
fill="#20F174" />
<path
d="M30 1.5H24C21.5147 1.5 19.5 3.51472 19.5 6V12C19.5 14.4853 21.5147 16.5 24 16.5H30C32.4853 16.5 34.5 14.4853 34.5 12V6C34.5 3.51472 32.4853 1.5 30 1.5Z"
fill="#20F174" />
<path
d="M30 19.5H24C21.5147 19.5 19.5 21.5147 19.5 24V30C19.5 32.4853 21.5147 34.5 24 34.5H30C32.4853 34.5 34.5 32.4853 34.5 30V24C34.5 21.5147 32.4853 19.5 30 19.5Z"
fill="#20F174" />
</svg>
</div>
</div>
</div>
</div>
<div class="col-xl-3 col-xxl-3 col-lg-6 col-sm-6">
<div class="card card-bd">
<div class="bg-info card-border"></div>
<div class="card-body box-style">
<div class="media align-items-center">
<div class="media-body me-3">
<h2 class="count num-text text-black font-w700">12</h2>
<span class="fs-14">Unread Messages</span>
</div>
<svg width="46" height="46" viewBox="0 0 46 46" fill="none"
xmlns="http://www.w3.org/2000/svg">
<path
d="M34.4999 1.91663H11.4999C8.95917 1.91967 6.52338 2.93032 4.72682 4.72688C2.93026 6.52345 1.91961 8.95924 1.91656 11.5V26.8333C1.91935 29.0417 2.6834 31.1816 4.07994 32.8924C5.47648 34.6031 7.42011 35.7801 9.58323 36.225V42.1666C9.58318 42.5136 9.67733 42.8541 9.85564 43.1518C10.0339 43.4495 10.2897 43.6932 10.5957 43.8569C10.9016 44.0206 11.2463 44.0982 11.5929 44.0813C11.9395 44.0645 12.275 43.9539 12.5636 43.7613L23.5749 36.4166H34.4999C37.0406 36.4136 39.4764 35.4029 41.273 33.6064C43.0695 31.8098 44.0802 29.374 44.0832 26.8333V11.5C44.0802 8.95924 43.0695 6.52345 41.273 4.72688C39.4764 2.93032 37.0406 1.91967 34.4999 1.91663ZM30.6666 24.9166H15.3332C14.8249 24.9166 14.3374 24.7147 13.9779 24.3552C13.6185 23.9958 13.4166 23.5083 13.4166 23C13.4166 22.4916 13.6185 22.0041 13.9779 21.6447C14.3374 21.2852 14.8249 21.0833 15.3332 21.0833H30.6666C31.1749 21.0833 31.6624 21.2852 32.0219 21.6447C32.3813 22.0041 32.5832 22.4916 32.5832 23C32.5832 23.5083 32.3813 23.9958 32.0219 24.3552C31.6624 24.7147 31.1749 24.9166 30.6666 24.9166ZM34.4999 17.25H11.4999C10.9916 17.25 10.5041 17.048 10.1446 16.6886C9.78517 16.3291 9.58323 15.8416 9.58323 15.3333C9.58323 14.825 9.78517 14.3374 10.1446 13.978C10.5041 13.6186 10.9916 13.4166 11.4999 13.4166H34.4999C35.0082 13.4166 35.4957 13.6186 35.8552 13.978C36.2146 14.3374 36.4166 14.825 36.4166 15.3333C36.4166 15.8416 36.2146 16.3291 35.8552 16.6886C35.4957 17.048 35.0082 17.25 34.4999 17.25Z"
fill="#3ECDFF" />
</svg>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-xl-6 col-xxl-12">
<div class="card">
<div class="card-header d-block border-0 pb-0">
<div class="d-flex justify-content-between pb-3">
<h4 class="mb-0 text-black fs-20">Project Created</h4>
<div class="dropdown">
<a href="javascript:void(0)" data-bs-toggle="dropdown" aria-expanded="false">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none"
xmlns="http://www.w3.org/2000/svg">
<path
d="M12 13C12.5523 13 13 12.5523 13 12C13 11.4477 12.5523 11 12 11C11.4477 11 11 11.4477 11 12C11 12.5523 11.4477 13 12 13Z"
stroke="#575757" stroke-width="2" stroke-linecap="round"
stroke-linejoin="round"></path>
<path
d="M12 6C12.5523 6 13 5.55228 13 5C13 4.44772 12.5523 4 12 4C11.4477 4 11 4.44772 11 5C11 5.55228 11.4477 6 12 6Z"
stroke="#575757" stroke-width="2" stroke-linecap="round"
stroke-linejoin="round"></path>
<path
d="M12 20C12.5523 20 13 19.5523 13 19C13 18.4477 12.5523 18 12 18C11.4477 18 11 18.4477 11 19C11 19.5523 11.4477 20 12 20Z"
stroke="#575757" stroke-width="2" stroke-linecap="round"
stroke-linejoin="round"></path>
</svg>
</a>
<div class="dropdown-menu dropdown-menu-left">
<a class="dropdown-item" href="javascript:void(0);">Edit</a>
<a class="dropdown-item" href="javascript:void(0);">Delete</a>
</div>
</div>
</div>
<div class="d-flex align-items-center">
<span class="fs-36 text-black font-w600 me-4">25%</span>
<div>
<svg class="me-2" width="27" height="14" viewBox="0 0 27 14" fill="none"
xmlns="http://www.w3.org/2000/svg">
<path d="M0 13.435L13.435 0L26.8701 13.435H0Z" fill="#fc5130"></path>
</svg>
<span>last month $563,443</span>
</div>
</div>
</div>
<div class="card-body pb-0 px-2 pt-2">
<div id="chartTimeline" class="timeline-chart"></div>
</div>
</div>
</div>
<div class="col-xl-3 col-xxl-6 col-sm-6">
<div class="card">
<div class="card-header border-0 pb-0">
<h4 class="fs-20 mb-0 text-black">New Clients</h4>
<div class="dropdown">
<a href="javascript:void(0)" data-bs-toggle="dropdown" aria-expanded="false">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none"
xmlns="http://www.w3.org/2000/svg">
<path
d="M12 13C12.5523 13 13 12.5523 13 12C13 11.4477 12.5523 11 12 11C11.4477 11 11 11.4477 11 12C11 12.5523 11.4477 13 12 13Z"
stroke="#575757" stroke-width="2" stroke-linecap="round"
stroke-linejoin="round"></path>
<path
d="M12 6C12.5523 6 13 5.55228 13 5C13 4.44772 12.5523 4 12 4C11.4477 4 11 4.44772 11 5C11 5.55228 11.4477 6 12 6Z"
stroke="#575757" stroke-width="2" stroke-linecap="round"
stroke-linejoin="round"></path>
<path
d="M12 20C12.5523 20 13 19.5523 13 19C13 18.4477 12.5523 18 12 18C11.4477 18 11 18.4477 11 19C11 19.5523 11.4477 20 12 20Z"
stroke="#575757" stroke-width="2" stroke-linecap="round"
stroke-linejoin="round"></path>
</svg>
</a>
<div class="dropdown-menu dropdown-menu-left">
<a class="dropdown-item" href="javascript:void(0);">Edit</a>
<a class="dropdown-item" href="javascript:void(0);">Delete</a>
</div>
</div>
</div>
<div class="card-body text-center pb-0 px-2 pt-2">
<div id="widgetChart1" class="widgetChart1 dashboard-chart"></div>
</div>
</div>
</div>
<div class="col-xl-3 col-xxl-6 col-sm-6">
<div class="card">
<div class="card-header border-0 pb-0">
<h4 class="fs-20 mb-0 text-black">Monthly Target</h4>
<div class="dropdown">
<a href="javascript:void(0)" data-bs-toggle="dropdown" aria-expanded="false">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none"
xmlns="http://www.w3.org/2000/svg">
<path
d="M12 13C12.5523 13 13 12.5523 13 12C13 11.4477 12.5523 11 12 11C11.4477 11 11 11.4477 11 12C11 12.5523 11.4477 13 12 13Z"
stroke="#575757" stroke-width="2" stroke-linecap="round"
stroke-linejoin="round"></path>
<path
d="M12 6C12.5523 6 13 5.55228 13 5C13 4.44772 12.5523 4 12 4C11.4477 4 11 4.44772 11 5C11 5.55228 11.4477 6 12 6Z"
stroke="#575757" stroke-width="2" stroke-linecap="round"
stroke-linejoin="round"></path>
<path
d="M12 20C12.5523 20 13 19.5523 13 19C13 18.4477 12.5523 18 12 18C11.4477 18 11 18.4477 11 19C11 19.5523 11.4477 20 12 20Z"
stroke="#575757" stroke-width="2" stroke-linecap="round"
stroke-linejoin="round"></path>
</svg>
</a>
<div class="dropdown-menu dropdown-menu-left">
<a class="dropdown-item" href="javascript:void(0);">Edit</a>
<a class="dropdown-item" href="javascript:void(0);">Delete</a>
</div>
</div>
</div>
<div class="card-body text-center pt-0">
<div id="radialChart" class="monthly-project-chart"></div>
<span class="fs-14 text-black d-block op5">100 Projects/ monthy</span>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-xl-6 col-xxl-12">
<div class="row">
<div class="col-sm-6">
<div class="card">
<div class="card-header border-0">
<h4 class="fs-16 text-black font-w500">Project Released</h4>
<div class="d-flex align-items-center">
<svg width="14" height="8" viewBox="0 0 14 8" fill="none"
xmlns="http://www.w3.org/2000/svg">
<path d="M1.90735e-06 0.499999L7 7.5L14 0.5" fill="#FF6746" />
</svg>
<span class="fs-28 font-w600 ms-2 text-black">4%</span>
</div>
</div>
<div class="card-body text-center pb-0 p-0">
<div id="widgetChart2" class="dashboard-chart"></div>
</div>
</div>
</div>
<div class="col-sm-6">
<div class="card">
<div
class="card-body text-center d-flex align-items-center justify-content-between">
<div class="d-inline-block position-relative donut-chart-sale">
<span class="donut1"
data-peity='{ "fill": ["#fc5130", "rgba(241, 241, 241,1)"], "innerRadius": 33, "radius": 10}'>3/8</span>
<small class="text-primary">29%</small>
</div>
<div>
<h2 class="fs-28 font-w600 mb-0 text-end text-black">567</h2>
<p class="mb-0 fs-14 font-w400 text-black">Contacts Added</p>
</div>
</div>
</div>
</div>
<div class="col-xl-12">
<div class="card overflow-hidden">
<div class="card-body">
<div class="text-center">
<div class="profile-photo">
<img src="assets/img/man.png" width="100"
class="img-fluid rounded-circle" alt="">
</div>
<h3 class="mt-4 mb-1">Therichpost</h3>
<p class="text-muted">Youtuber</p>
<a class="btn btn-outline-primary btn-rounded mt-3 px-5"
href="javascript:void(0)">Folllow</a>
</div>
</div>
<div class="card-footer pt-0 pb-0 text-center">
<div class="row">
<div class="col-4 pt-3 pb-3 border-right">
<h3 class="mb-1">150</h3><span>Follower</span>
</div>
<div class="col-4 pt-3 pb-3 border-right">
<h3 class="mb-1">140</h3><span>Place Stay</span>
</div>
<div class="col-4 pt-3 pb-3">
<h3 class="mb-1">45</h3><span>Reviews</span>
</div>
</div>
</div>
</div>
</div>
<div class="col-xl-12">
<div class="card message-bx">
<div class="card-header border-0 d-sm-flex d-block pb-0">
<div>
<h4 class="fs-20 mb-0 text-black mb-sm-0 mb-2">Recent Messages</h4>
</div>
<a href="#" class="btn btn-primary shadow-primary btn-rounded text-white">+ New
Message</a>
</div>
<div class="card-body">
<div class="media mb-3 pb-3 border-bottom">
<div class="image-bx me-sm-4 me-2">
<img src="assets/img/hacker.png" alt="" class="rounded-circle img-1">
<span class="active"></span>
</div>
<div
class="media-body d-sm-flex justify-content-between d-block align-items-center">
<div class="me-sm-3 me-0">
<h6 class="fs-16 font-w600 mb-sm-2 mb-0"><a href="#"
class="text-black">Laura Chyan</a></h6>
<p class="text-black mb-1">Lorem ipsum dolor sit amet, consectetur
adipiscing elit, sed do eiusmod tempor incididunt ut</p>
<span class="fs-14">5m ago</span>
</div>
</div>
</div>
<div class="media mb-3 pb-3 border-bottom">
<div class="image-bx me-sm-4 me-2">
<img src="assets/img/gamer.png" alt="" class="rounded-circle img-1">
</div>
<div
class="media-body d-sm-flex justify-content-between d-block align-items-center">
<div class="me-sm-3 me-0">
<h6 class="fs-16 font-w600 mb-sm-2 mb-0"><a href="#"
class="text-black">Olivia Rellaq</a></h6>
<p class="text-black mb-1">Lorem ipsum dolor sit amet, consectetur
adipiscing elit, sed do eiusmod tempor incididunt ut</p>
<span class="fs-14">41m ago</span>
</div>
</div>
</div>
<div class="media">
<div class="image-bx me-sm-4 me-2">
<img src="assets/img/man (1).png" alt="" class="rounded-circle img-1">
<span class="active"></span>
</div>
<div
class="media-body d-sm-flex justify-content-between d-block align-items-center">
<div class="me-sm-3 me-0">
<h6 class="fs-16 font-w600 mb-sm-2 mb-0"><a href="#"
class="text-black">Keanu Tipes</a></h6>
<p class="text-black mb-1">Nisi ut aliquip ex ea commodo consequat.
Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum...</p>
<span class="fs-14">25m ago</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-xl-6 col-xxl-12">
<div class="row">
<div class="col-md-6">
<div class="card">
<div class="card-header border-0 pb-0">
<div class="me-2">
<h4 class="fs-20 mb-0 font-w500 text-black">Upcoming Projects</h4>
</div>
</div>
<div class="card-body">
<div class="border-bottom up-project-bx pb-4 mb-4">
<span class="fs-16 text-primary mb-2 d-block sub-title font-w500">Yoast
Esac</span>
<div class="d-flex">
<p class="font-w500 me-auto mb-2 title fs-20"><a href="#"
class="text-black">Redesign Kripton Mobile App</a></p>
<div class="dropdown mb-3">
<a href="javascript:void(0)" data-bs-toggle="dropdown"
aria-expanded="false">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none"
xmlns="http://www.w3.org/2000/svg">
<path
d="M12 13C12.5523 13 13 12.5523 13 12C13 11.4477 12.5523 11 12 11C11.4477 11 11 11.4477 11 12C11 12.5523 11.4477 13 12 13Z"
stroke="#575757" stroke-width="2" stroke-linecap="round"
stroke-linejoin="round" />
<path
d="M12 6C12.5523 6 13 5.55228 13 5C13 4.44772 12.5523 4 12 4C11.4477 4 11 4.44772 11 5C11 5.55228 11.4477 6 12 6Z"
stroke="#575757" stroke-width="2" stroke-linecap="round"
stroke-linejoin="round" />
<path
d="M12 20C12.5523 20 13 19.5523 13 19C13 18.4477 12.5523 18 12 18C11.4477 18 11 18.4477 11 19C11 19.5523 11.4477 20 12 20Z"
stroke="#575757" stroke-width="2" stroke-linecap="round"
stroke-linejoin="round" />
</svg>
</a>
<div class="dropdown-menu dropdown-menu-left">
<a class="dropdown-item" href="javascript:void(0);">Edit</a>
<a class="dropdown-item" href="javascript:void(0);">Delete</a>
</div>
</div>
</div>
<div class="mb-3"><i class="far fa-calendar me-3"
aria-hidden="true"></i>Created on Sep 8th, 2020</div>
<div class="media align-items-center">
<div class="power-ic me-3">
<i class="fa fa-bolt" aria-hidden="true"></i>
</div>
<div class="media-body">
<p class="mb-1">Deadline</p>
<span class="text-black font-w600">Tuesday, Sep 29th 2020</span>
</div>
</div>
</div>
<div class="border-bottom up-project-bx pb-4 mb-4">
<span class="fs-16 text-primary mb-2 d-block sub-title font-w500">Yoast
Esac</span>
<div class="d-flex">
<p class="font-w500 me-auto title mb-2 fs-20"><a href="#"
class="text-black">Build Branding Persona for Etza.id</a></p>
<div class="dropdown mb-3">
<a href="javascript:void(0)" data-bs-toggle="dropdown"
aria-expanded="false">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none"
xmlns="http://www.w3.org/2000/svg">
<path
d="M12 13C12.5523 13 13 12.5523 13 12C13 11.4477 12.5523 11 12 11C11.4477 11 11 11.4477 11 12C11 12.5523 11.4477 13 12 13Z"
stroke="#575757" stroke-width="2" stroke-linecap="round"
stroke-linejoin="round" />
<path
d="M12 6C12.5523 6 13 5.55228 13 5C13 4.44772 12.5523 4 12 4C11.4477 4 11 4.44772 11 5C11 5.55228 11.4477 6 12 6Z"
stroke="#575757" stroke-width="2" stroke-linecap="round"
stroke-linejoin="round" />
<path
d="M12 20C12.5523 20 13 19.5523 13 19C13 18.4477 12.5523 18 12 18C11.4477 18 11 18.4477 11 19C11 19.5523 11.4477 20 12 20Z"
stroke="#575757" stroke-width="2" stroke-linecap="round"
stroke-linejoin="round" />
</svg>
</a>
<div class="dropdown-menu dropdown-menu-left">
<a class="dropdown-item" href="javascript:void(0);">Edit</a>
<a class="dropdown-item" href="javascript:void(0);">Delete</a>
</div>
</div>
</div>
<div class="mb-3"><i class="far fa-calendar me-3"
aria-hidden="true"></i>Created on Sep 8th, 2020</div>
<div class="media align-items-center">
<div class="power-ic me-3">
<i class="fa fa-bolt" aria-hidden="true"></i>
</div>
<div class="media-body">
<p class="mb-1">Deadline</p>
<span class="text-black font-w600">Tuesday, Sep 29th 2020</span>
</div>
</div>
</div>
<div class="up-project-bx">
<span class="fs-16 text-primary sub-title mb-2 d-block font-w500">Yoast
Esac</span>
<div class="d-flex">
<p class="font-w500 me-auto title mb-2 fs-20"><a href="#"
class="text-black">Manage SEO for Eclan Company Profile</a></p>
<div class="dropdown mb-3">
<a href="javascript:void(0)" data-bs-toggle="dropdown"
aria-expanded="false">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none"
xmlns="http://www.w3.org/2000/svg">
<path
d="M12 13C12.5523 13 13 12.5523 13 12C13 11.4477 12.5523 11 12 11C11.4477 11 11 11.4477 11 12C11 12.5523 11.4477 13 12 13Z"
stroke="#575757" stroke-width="2" stroke-linecap="round"
stroke-linejoin="round" />
<path
d="M12 6C12.5523 6 13 5.55228 13 5C13 4.44772 12.5523 4 12 4C11.4477 4 11 4.44772 11 5C11 5.55228 11.4477 6 12 6Z"
stroke="#575757" stroke-width="2" stroke-linecap="round"
stroke-linejoin="round" />
<path
d="M12 20C12.5523 20 13 19.5523 13 19C13 18.4477 12.5523 18 12 18C11.4477 18 11 18.4477 11 19C11 19.5523 11.4477 20 12 20Z"
stroke="#575757" stroke-width="2" stroke-linecap="round"
stroke-linejoin="round" />
</svg>
</a>
<div class="dropdown-menu dropdown-menu-left">
<a class="dropdown-item" href="javascript:void(0);">Edit</a>
<a class="dropdown-item" href="javascript:void(0);">Delete</a>
</div>
</div>
</div>
<div class="mb-3"><i class="far fa-calendar me-3"
aria-hidden="true"></i>Created on Sep 8th, 2020</div>
<div class="media align-items-center">
<div class="power-ic me-3">
<i class="fa fa-bolt" aria-hidden="true"></i>
</div>
<div class="media-body">
<p class="mb-1">Deadline</p>
<span class="text-black font-w600">Tuesday, Sep 29th 2020</span>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-6">
<div class="card kanbanPreview-bx">
<div class="card-body">
<div class="sub-card bg-secondary d-flex text-white">
<div class="me-auto pe-2">
<h4 class="fs-20 mb-0 font-w600 text-white">Quick To-Do List</h4>
<span class="fs-14 op6 font-w200">Lorem ipsum dolor sit amet</span>
</div>
<a href="#" class="plus-icon"><i class="fa fa-plus"
aria-hidden="true"></i></a>
</div>
<div class="sub-card">
<span class="text-warning sub-title fs-14">Graphic Deisgner</span>
<p class="font-w500"><a href="#" class="text-black">Visual Graphic for
Presentation to Client</a></p>
<div class="row justify-content-between align-items-center">
<div class="col-6">
<span>Aug 4, 2021</span>
</div>
<ul class="users col-6">
<li><img src="assets/img/man (1).png" alt=""></li>
<li><img
src="https://cdn-icons-png.flaticon.com/512/921/921071.png">
</li>
<li><img
src="https://cdn-icons-png.flaticon.com/512/921/921071.png">
</li>
<li><img src="https://cdn-icons-png.flaticon.com/512/1154/1154448.png"
alt=""></li>
</ul>
</div>
</div>
<div class="sub-card">
<span class="text-primary sub-title fs-14">Database Engineer</span>
<p class="font-w500"><a href="#" class="text-black">Build Database Design
for Fasto Admin v2</a></p>
<div class="row justify-content-between align-items-center">
<div class="col-6">
<span>Aug 4, 2021</span>
</div>
<ul class="users col-6">
<li><img src="assets/img/man (1).png" alt=""></li>
<li><img
src="https://cdn-icons-png.flaticon.com/512/921/921071.png">
</li>
<li><img src="assets/img/man (1).png" alt=""></li>
</ul>
</div>
</div>
<div class="sub-card">
<span class="text-secondary sub-title fs-14">Digital Marketing</span>
<p class="font-w500"><a href="#" class="text-black">Make Promotional Ads for
Instagram Fastos</a></p>
<div class="row justify-content-between align-items-center mb-4">
<div class="col-6">
<span>Aug 4, 2021</span>
</div>
<ul class="users col-6">
<li><img src="assets/img/man (1).png" alt=""></li>
<li><img
src="https://cdn-icons-png.flaticon.com/512/921/921071.png">
</li>
<li><img src="assets/img/man (1).png" alt=""></li>
</ul>
</div>
<span><i class="far fa-comment me-2"></i>2 Comment</span>
</div>
</div>
</div>
</div>
<div class="col-md-6">
<div class="card">
<div class="card-header border-0 pb-0">
<h4 class="card-title">Timeline</h4>
</div>
<div class="card-body">
<div id="DZ_W_TimeLine"
class="widget-timeline dz-scroll height370 ps ps--active-y">
<ul class="timeline">
<li>
<div class="timeline-badge primary"></div>
<a class="timeline-panel text-muted" href="javascript:void(0);">
<span>10 minutes ago</span>
<h6 class="mb-0">Youtube, a video-sharing website, goes live
<strong class="text-primary">$500</strong>.</h6>
</a>
</li>
<li>
<div class="timeline-badge info">
</div>
<a class="timeline-panel text-muted" href="javascript:void(0);">
<span>20 minutes ago</span>
<h6 class="mb-0">New order placed <strong
class="text-info">#XF-2356.</strong></h6>
<p class="mb-0">Quisque a consequat ante Sit amet magna at
volutapt...</p>
</a>
</li>
<li>
<div class="timeline-badge danger">
</div>
<a class="timeline-panel text-muted" href="javascript:void(0);">
<span>30 minutes ago</span>
<h6 class="mb-0">john just buy your product <strong
class="text-warning">Sell $250</strong></h6>
</a>
</li>
<li>
<div class="timeline-badge success">
</div>
<a class="timeline-panel text-muted" href="javascript:void(0);">
<span>15 minutes ago</span>
<h6 class="mb-0">StumbleUpon is acquired by eBay. </h6>
</a>
</li>
<li>
<div class="timeline-badge warning">
</div>
<a class="timeline-panel text-muted" href="javascript:void(0);">
<span>20 minutes ago</span>
<h6 class="mb-0">Mashable, a news website and blog, goes live.
</h6>
</a>
</li>
<li>
<div class="timeline-badge dark">
</div>
<a class="timeline-panel text-muted" href="javascript:void(0);">
<span>20 minutes ago</span>
<h6 class="mb-0">Mashable, a news website and blog, goes live.
</h6>
</a>
</li>
<li>
<div class="timeline-badge primary"></div>
<a class="timeline-panel text-muted" href="javascript:void(0);">
<span>10 minutes ago</span>
<h6 class="mb-0">Youtube, a video-sharing website, goes live
<strong class="text-primary">$500</strong>.</h6>
</a>
</li>
<li>
<div class="timeline-badge info">
</div>
<a class="timeline-panel text-muted" href="javascript:void(0);">
<span>20 minutes ago</span>
<h6 class="mb-0">New order placed <strong
class="text-info">#XF-2356.</strong></h6>
<p class="mb-0">Quisque a consequat ante Sit amet magna at
volutapt...</p>
</a>
</li>
<li>
<div class="timeline-badge danger">
</div>
<a class="timeline-panel text-muted" href="javascript:void(0);">
<span>30 minutes ago</span>
<h6 class="mb-0">john just buy your product <strong
class="text-warning">Sell $250</strong></h6>
</a>
</li>
<li>
<div class="timeline-badge success">
</div>
<a class="timeline-panel text-muted" href="javascript:void(0);">
<span>15 minutes ago</span>
<h6 class="mb-0">StumbleUpon is acquired by eBay. </h6>
</a>
</li>
<li>
<div class="timeline-badge warning">
</div>
<a class="timeline-panel text-muted" href="javascript:void(0);">
<span>20 minutes ago</span>
<h6 class="mb-0">Mashable, a news website and blog, goes live.
</h6>
</a>
</li>
<li>
<div class="timeline-badge dark">
</div>
<a class="timeline-panel text-muted" href="javascript:void(0);">
<span>20 minutes ago</span>
<h6 class="mb-0">Mashable, a news website and blog, goes live.
</h6>
</a>
</li>
</ul>
<div class="ps__rail-x" style="left: 0px; bottom: 0px;">
<div class="ps__thumb-x" tabindex="0" style="left: 0px; width: 0px;">
</div>
</div>
<div class="ps__rail-y" style="top: 0px; height: 370px; right: 0px;">
<div class="ps__thumb-y" tabindex="0" style="top: 0px; height: 229px;">
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-6">
<div class="card" style="display: grid; align-content: center;">
<div class="card-body text-center ai-icon text-primary">
<svg id="rocket-icon" class="my-2" viewBox="0 0 24 24" width="80" height="80"
stroke="currentColor" stroke-width="1" fill="none" stroke-linecap="round"
stroke-linejoin="round">
<path d="M6 2L3 6v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V6l-3-4z"></path>
<line x1="3" y1="6" x2="21" y2="6"></line>
<path d="M16 10a4 4 0 0 1-8 0"></path>
</svg>
<h4 class="my-2">You dont have badges yet</h4>
<a href="javascript:void(0);" class="btn my-2 btn-primary btn-lg px-4"><i
class="fa fa-usd"></i> Earn Budges</a>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-xl-3 col-xxl-3 col-sm-6">
<div class="card">
<div class="social-graph-wrapper widget-facebook">
<span class="s-icon"><i class="fab fa-facebook-f"></i></span>
</div>
<div class="row">
<div class="col-6 border-end">
<div class="pt-3 pb-3 pl-0 pr-0 text-center">
<h4 class="m-1"><span class="count counter">89</span> k</h4>
<p class="m-0">Friends</p>
</div>
</div>
<div class="col-6">
<div class="pt-3 pb-3 pl-0 pr-0 text-center">
<h4 class="m-1"><span class="count counter">119</span> k</h4>
<p class="m-0">Followers</p>
</div>
</div>
</div>
</div>
</div>
<div class="col-xl-3 col-xxl-3 col-sm-6">
<div class="card">
<div class="social-graph-wrapper widget-linkedin">
<span class="s-icon"><i class="fab fa-linkedin-in"></i></span>
</div>
<div class="row">
<div class="col-6 border-end">
<div class="pt-3 pb-3 pl-0 pr-0 text-center">
<h4 class="m-1"><span class="count counter">89</span> k</h4>
<p class="m-0">Friends</p>
</div>
</div>
<div class="col-6">
<div class="pt-3 pb-3 pl-0 pr-0 text-center">
<h4 class="m-1"><span class="count counter">119</span> k</h4>
<p class="m-0">Followers</p>
</div>
</div>
</div>
</div>
</div>
<div class="col-xl-3 col-xxl-3 col-sm-6">
<div class="card">
<div class="social-graph-wrapper widget-googleplus">
<span class="s-icon"><i class="fab fa-google-plus-g"></i></span>
</div>
<div class="row">
<div class="col-6 border-end">
<div class="pt-3 pb-3 pl-0 pr-0 text-center">
<h4 class="m-1"><span class="count counter">89</span> k</h4>
<p class="m-0">Friends</p>
</div>
</div>
<div class="col-6">
<div class="pt-3 pb-3 pl-0 pr-0 text-center">
<h4 class="m-1"><span class="count counter">119</span> k</h4>
<p class="m-0">Followers</p>
</div>
</div>
</div>
</div>
</div>
<div class="col-xl-3 col-xxl-3 col-sm-6">
<div class="card">
<div class="social-graph-wrapper widget-twitter">
<span class="s-icon"><i class="fab fa-twitter"></i></span>
</div>
<div class="row">
<div class="col-6 border-end">
<div class="pt-3 pb-3 pl-0 pr-0 text-center">
<h4 class="m-1"><span class="count counter">89</span> k</h4>
<p class="m-0">Friends</p>
</div>
</div>
<div class="col-6">
<div class="pt-3 pb-3 pl-0 pr-0 text-center">
<h4 class="m-1"><span class="count counter">119</span> k</h4>
<p class="m-0">Followers</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{include file="sections/footer.tpl"}

View File

@ -0,0 +1,21 @@
{include file="sections/user-header.tpl"}
<div class="row">
<div class="col-md-4 col-md-offset-2">
<div class="card card-hovered card-primary card-stacked mb30">
<div class="card-header">{$in['invoice']}</div>
<div class="card-body">
<form class="form-horizontal" method="post" action="{$_url}plan/print" target="_blank">
<pre id="content">{$invoice}</pre>
<input type="hidden" name="id" value="{$in['id']}">
<a href="{$_url}voucher/list-activated" class="btn btn-default btn-sm"><i
class="ion-reply-all"></i>{Lang::T('Finish')}</a>
<a href="https://api.whatsapp.com/send/?text={$whatsapp}" target="_blank"
class="btn btn-primary btn-sm">
<i class="glyphicon glyphicon-share"></i> WhatsApp</a>
</form>
</div>
</div>
</div>
</div>
{include file="sections/user-footer.tpl"}

74
ui/ui/invoice-print.tpl Normal file
View File

@ -0,0 +1,74 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="shortcut icon" href="https://laravel.com/img/favicon/favicon-16x16.png" type='image/x-icon'>
<title>{Lang::T('Login')} - {$_c['CompanyName']}</title>
<link rel="stylesheet" href="assets/vendor/chartist/css/chartist.min.css">
<link href="assets/vendor/bootstrap-select/dist/css/bootstrap-select.min.css" rel="stylesheet">
<link href="assets/css/style.css" rel="stylesheet">
<meta http-equiv="refresh" content="{$time}; url={$url}">
<script type="text/javascript">
function printpage() {
window.print();
}
</script>
</head>
<body topmargin="0" leftmargin="0" {if !$nuxprint} onload="printpage()" {/if}>
<div class="row">
<div class="col-md-6">
<table width="200">
<tr>
<td>
{if $content}
<pre style="border-style: none; background-color: white;">{$content}</pre>{else}
<pre style="border-style: none; background-color: white;"><b>{Lang::pad($_c['CompanyName'],' ', 2)}</b>
{Lang::pad($_c['address'],' ', 2)}
{Lang::pad($_c['phone'],' ', 2)}
{Lang::pad("", '=')}
{Lang::pads("Invoice", $in['invoice'], ' ')}
{Lang::pads(Lang::T('Date'), $date, ' ')}
{Lang::pads(Lang::T('Sales'), $_admin['fullname'], ' ')}
{Lang::pad("", '=')}
{Lang::pads(Lang::T('Type'), $in['type'], ' ')}
{Lang::pads(Lang::T('Plan Name'), $in['plan_name'], ' ')}
{Lang::pads(Lang::T('Plan Price'), Lang::moneyFormat($in['price']), ' ')}
{Lang::pad($in['method'], ' ', 2)}
{Lang::pads(Lang::T('Username'), $in['username'], ' ')}
{Lang::pads(Lang::T('Password'), '**********', ' ')}
{if $in['type'] != 'Balance'}
{Lang::pads(Lang::T('Created On'), Lang::dateAndTimeFormat($in['recharged_on'],$in['recharged_time']), ' ')}
{Lang::pads(Lang::T('Expires On'), Lang::dateAndTimeFormat($in['expiration'],$in['time']), ' ')}
{/if}
{Lang::pad("", '=')}
{Lang::pad($_c['note'],' ', 2)}</pre>
{/if}
</td>
</tr>
</table>
{if $nuxprint}
<a href="{$nuxprint}" class="btn btn-success text-black btn-sm" name="nux" value="print">
<i class="fa fa-print"></i>
Print Invoice
<!-- <i class="fa fa-phone"></i> -->
</a>
<br>
<iframe src="{$nuxprint}" style="height: 2px;"><iframe>
{/if}
</div>
</div>
<script src="ui/ui/scripts/jquery.min.js"></script>
<script src="ui/ui/scripts/bootstrap.min.js"></script>
{if isset($xfooter)}
{$xfooter}
{/if}
</body>
</html>

Some files were not shown because too many files have changed in this diff Show More