Merge tag 'v25.03' into techbar

This commit is contained in:
ThaMunsta
2025-03-30 14:23:22 -04:00
588 changed files with 129200 additions and 5843 deletions

View File

@@ -2,7 +2,7 @@
require_once "../config.php";
require_once "../functions.php";
require_once "../check_login.php";
require_once "check_login.php";
header('Content-Type: application/json');

View File

@@ -5,4 +5,4 @@
* Update this file each time we merge develop into master. Format is YY.MM (add a .v if there is more than one release a month.
*/
DEFINE("APP_VERSION", "25.02.3");
DEFINE("APP_VERSION", "25.03");

117
includes/check_login.php Normal file
View File

@@ -0,0 +1,117 @@
<?php
if (!isset($_SESSION)) {
// HTTP Only cookies
ini_set("session.cookie_httponly", true);
if ($config_https_only) {
// Tell client to only send cookie(s) over HTTPS
ini_set("session.cookie_secure", true);
}
session_start();
}
// Check to see if setup is enabled
if (!isset($config_enable_setup) || $config_enable_setup == 1) {
header("Location: ../setup.php");
exit;
}
// Check user is logged in with a valid session
if (!isset($_SESSION['logged']) || !$_SESSION['logged']) {
if ($_SERVER["REQUEST_URI"] == "/") {
header("Location: ../login.php");
} else {
header("Location: ../login.php?last_visited=" . base64_encode($_SERVER["REQUEST_URI"]) );
}
exit;
}
// Set Timezone
require_once "inc_set_timezone.php";
// User Vars and User Settings
$session_ip = sanitizeInput(getIP());
$session_user_agent = sanitizeInput($_SERVER['HTTP_USER_AGENT']);
$session_user_id = intval($_SESSION['user_id']);
$sql = mysqli_query(
$mysqli,
"SELECT * FROM users
LEFT JOIN user_settings ON users.user_id = user_settings.user_id
LEFT JOIN user_roles ON user_role_id = role_id
WHERE users.user_id = $session_user_id");
$row = mysqli_fetch_array($sql);
$session_name = sanitizeInput($row['user_name']);
$session_email = $row['user_email'];
$session_avatar = $row['user_avatar'];
$session_token = $row['user_token']; // MFA Token
$session_user_type = intval($row['user_type']);
$session_user_role = intval($row['user_role_id']);
$session_user_role_display = sanitizeInput($row['role_name']);
if (isset($row['role_is_admin']) && $row['role_is_admin'] == 1) {
$session_is_admin = true;
} else {
$session_is_admin = false;
}
$session_user_config_force_mfa = intval($row['user_config_force_mfa']);
$user_config_records_per_page = intval($row['user_config_records_per_page']);
// Check user type
if ($session_user_type !== 1) {
session_unset();
session_destroy();
header("Location: login.php");
exit();
}
// Company Vars and Company Settings
$sql = mysqli_query($mysqli, "SELECT * FROM companies, settings WHERE settings.company_id = companies.company_id AND companies.company_id = 1");
$row = mysqli_fetch_array($sql);
$session_company_name = $row['company_name'];
$session_company_country = $row['company_country'];
$session_company_locale = $row['company_locale'];
$session_company_currency = $row['company_currency'];
// Set Currency Format
$currency_format = numfmt_create($session_company_locale, NumberFormatter::CURRENCY);
// Get User Client Access Permissions
$user_client_access_sql = "SELECT client_id FROM user_client_permissions WHERE user_id = $session_user_id";
$user_client_access_result = mysqli_query($mysqli, $user_client_access_sql);
$client_access_array = [];
while ($row = mysqli_fetch_assoc($user_client_access_result)) {
$client_access_array[] = $row['client_id'];
}
$client_access_string = implode(',', $client_access_array);
// Client access permission check
// Default allow, if a list of allowed clients is set & the user isn't an admin, restrict them
$access_permission_query = "";
if ($client_access_string && !$session_is_admin) {
$access_permission_query = "AND clients.client_id IN ($client_access_string)";
}
// Include the settings vars
require_once "get_settings.php";
//Detects if using an Apple device and uses Apple Maps instead of google
$iPod = stripos($_SERVER['HTTP_USER_AGENT'], "iPod");
$iPhone = stripos($_SERVER['HTTP_USER_AGENT'], "iPhone");
$iPad = stripos($_SERVER['HTTP_USER_AGENT'], "iPad");
if ($iPod || $iPhone || $iPad) {
$session_map_source = "apple";
} else {
$session_map_source = "google";
}
// Check if mobile device
$session_mobile = isMobile();

View File

@@ -74,14 +74,26 @@
<p>
Recurring Tickets
<?php
if ($num_scheduled_tickets) { ?>
<span class="right badge"><?php echo $num_scheduled_tickets; ?></span>
if ($num_recurring_tickets) { ?>
<span class="right badge"><?php echo $num_recurring_tickets; ?></span>
<?php } ?>
</p>
</a>
</li>
<li class="nav-item">
<a href="projects.php?client_id=<?php echo $client_id; ?>" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "projects.php" || basename($_SERVER["PHP_SELF"]) == "project_details.php") { echo "active"; } ?>">
<i class="nav-icon fas fa-project-diagram"></i>
<p>
Projects
<?php if ($num_active_projects) { ?>
<span class="right badge text-light" data-toggle="tooltip" title="Open Projects"><?php echo $num_active_projects; ?></span>
<?php } ?>
</p>
</a>
</li>
<?php } ?>
<li class="nav-item">
@@ -103,8 +115,8 @@
<p>
Calendar
<?php
if ($num_events > 0) { ?>
<span class="right badge text-light"><?php echo $num_events; ?></span>
if ($num_calendar_events > 0) { ?>
<span class="right badge text-light"><?php echo $num_calendar_events; ?></span>
<?php } ?>
</p>
</a>
@@ -147,8 +159,8 @@
<p>
Credentials
<?php
if ($num_logins > 0) { ?>
<span class="right badge text-light"><?php echo $num_logins; ?></span>
if ($num_credentials > 0) { ?>
<span class="right badge text-light"><?php echo $num_credentials; ?></span>
<?php } ?>
</p>
</a>
@@ -277,8 +289,8 @@
<p>
Recurring Invoices
<?php
if ($num_recurring > 0) { ?>
<span class="right badge"><?php echo $num_recurring; ?></span>
if ($num_recurring_invoices) { ?>
<span class="right badge"><?php echo $num_recurring_invoices; ?></span>
<?php } ?>
</p>
</a>

View File

@@ -5,4 +5,4 @@
* It is used in conjunction with database_updates.php
*/
DEFINE("LATEST_DATABASE_VERSION", "1.8.7");
DEFINE("LATEST_DATABASE_VERSION", "2.1.2");

View File

@@ -33,7 +33,7 @@ if (str_contains(basename($_SERVER["PHP_SELF"]), "admin_")) { ?>
<script src="plugins/clipboardjs/clipboard.min.js"></script>
<script src="js/keepalive.js"></script>
<script src="plugins/DataTables/datatables.min.js"></script>
<script src="plugins/intl-tel-input/js/intlTelInput.min.js"></script>
<!-- AdminLTE App -->
<script src="plugins/adminlte/js/adminlte.min.js"></script>

318
includes/get_settings.php Normal file
View File

@@ -0,0 +1,318 @@
<?php
// Query Settings
$sql_settings = mysqli_query($mysqli, "SELECT * FROM settings WHERE company_id = 1");
$row = mysqli_fetch_array($sql_settings);
// Database version
DEFINE("CURRENT_DATABASE_VERSION", $row['config_current_database_version']);
// Microsoft OAuth
$config_azure_client_id = $row['config_azure_client_id'];
$config_azure_client_secret = $row['config_azure_client_secret'];
// Mail - SMTP
$config_smtp_host = $row['config_smtp_host'];
$config_smtp_port = intval($row['config_smtp_port']);
$config_smtp_encryption = $row['config_smtp_encryption'];
$config_smtp_username = $row['config_smtp_username'];
$config_smtp_password = $row['config_smtp_password'];
$config_mail_from_email = $row['config_mail_from_email'];
$config_mail_from_name = $row['config_mail_from_name'];
// Mail - IMAP
$config_imap_host = $row['config_imap_host'];
$config_imap_port = intval($row['config_imap_port']);
$config_imap_encryption = $row['config_imap_encryption'];
$config_imap_username = $row['config_imap_username'];
$config_imap_password = $row['config_imap_password'];
// Defaults
$config_start_page = $row['config_start_page'];
$config_default_transfer_from_account = intval($row['config_default_transfer_from_account']);
$config_default_transfer_to_account = intval($row['config_default_transfer_to_account']);
$config_default_payment_account = intval($row['config_default_payment_account']);
$config_default_expense_account = intval($row['config_default_expense_account']);
$config_default_payment_method = $row['config_default_payment_method'];
$config_default_expense_payment_method = $row['config_default_expense_payment_method'];
$config_default_calendar = intval($row['config_default_calendar']);
$config_default_net_terms = intval($row['config_default_net_terms']);
$config_default_hourly_rate = floatval($row['config_default_hourly_rate']);
// Invoice
$config_invoice_prefix = $row['config_invoice_prefix'];
$config_invoice_next_number = intval($row['config_invoice_next_number']);
$config_invoice_footer = $row['config_invoice_footer'];
$config_invoice_from_name = $row['config_invoice_from_name'];
$config_invoice_from_email = $row['config_invoice_from_email'];
$config_invoice_late_fee_enable = intval($row['config_invoice_late_fee_enable']);
$config_invoice_late_fee_percent = floatval($row['config_invoice_late_fee_percent']);
$config_invoice_paid_notification_email = $row['config_invoice_paid_notification_email'];
// Recurring Invoices
$config_recurring_invoice_prefix = $row['config_recurring_invoice_prefix'];
$config_recurring_invoice_next_number = intval($row['config_recurring_invoice_next_number']);
// Quotes
$config_quote_prefix = $row['config_quote_prefix'];
$config_quote_next_number = intval($row['config_quote_next_number']);
$config_quote_footer = $row['config_quote_footer'];
$config_quote_from_name = $row['config_quote_from_name'];
$config_quote_from_email = $row['config_quote_from_email'];
$config_quote_notification_email = $row['config_quote_notification_email'];
// Projects
$config_project_prefix = $row['config_project_prefix'];
$config_project_next_number = intval($row['config_project_next_number']);
// Tickets
$config_ticket_prefix = $row['config_ticket_prefix'];
$config_ticket_next_number = intval($row['config_ticket_next_number']);
$config_ticket_from_name = $row['config_ticket_from_name'];
$config_ticket_from_email = $row['config_ticket_from_email'];
$config_ticket_email_parse = intval($row['config_ticket_email_parse']);
$config_ticket_email_parse_unknown_senders = intval($row['config_ticket_email_parse_unknown_senders']);
$config_ticket_client_general_notifications = intval($row['config_ticket_client_general_notifications']);
$config_ticket_autoclose_hours = intval($row['config_ticket_autoclose_hours']);
$config_ticket_new_ticket_notification_email = $row['config_ticket_new_ticket_notification_email'];
$config_ticket_default_billable = intval($row['config_ticket_default_billable']);
$config_ticket_default_view = intval($row['config_ticket_default_view']);
$config_ticket_moving_columns = intval($row['config_ticket_moving_columns']);
$config_ticket_ordering = intval($row['config_ticket_ordering']);
// Cron
$config_enable_cron = intval($row['config_enable_cron']);
// Alerts & Notifications
$config_recurring_auto_send_invoice = intval($row['config_recurring_auto_send_invoice']);
$config_enable_alert_domain_expire = intval($row['config_enable_alert_domain_expire']);
$config_send_invoice_reminders = intval($row['config_send_invoice_reminders']);
$config_invoice_overdue_reminders = intval($row['config_invoice_overdue_reminders']);
// Online Stripe Payment
$config_stripe_enable = intval($row['config_stripe_enable']);
$config_stripe_publishable = $row['config_stripe_publishable'];
$config_stripe_secret = $row['config_stripe_secret'];
$config_stripe_account = intval($row['config_stripe_account']);
$config_stripe_expense_vendor = intval($row['config_stripe_expense_vendor']);
$config_stripe_expense_category = intval($row['config_stripe_expense_category']);
$config_stripe_percentage_fee = floatval($row['config_stripe_percentage_fee']);
$config_stripe_flat_fee = floatval($row['config_stripe_flat_fee']);
// AI Provider Details
$config_ai_enable = intval($row['config_ai_enable']);
$config_ai_provider = $row['config_ai_provider'];
$config_ai_model = $row['config_ai_model'];
$config_ai_url = $row['config_ai_url'];
$config_ai_api_key = $row['config_ai_api_key'];
// Modules
$config_module_enable_itdoc = intval($row['config_module_enable_itdoc']);
$config_module_enable_ticketing = intval($row['config_module_enable_ticketing']);
$config_module_enable_accounting = intval($row['config_module_enable_accounting']);
$config_client_portal_enable = intval($row['config_client_portal_enable']);
// Login
$config_login_message = $row['config_login_message'];
$config_login_key_required = $row['config_login_key_required'];
$config_login_key_secret = $row['config_login_key_secret'];
$config_login_remember_me_expire = intval($row['config_login_remember_me_expire']);
$config_log_retention = intval($row['config_log_retention']);
// Locale
$config_currency_format = "US_en";
$config_timezone = $row['config_timezone'];
// Theme
$config_theme = $row['config_theme'];
$config_theme_mode = "dark_mode";
// Telemetry
$config_telemetry = intval($row['config_telemetry']);
// Destructive Deletes
$config_destructive_deletes_enable = intval($row['config_destructive_deletes_enable']);
// White label
$config_whitelabel_enabled = intval($row['config_whitelabel_enabled']);
$config_whitelabel_key = $row['config_whitelabel_key'];
// Select Arrays
$theme_colors_array = array (
'lightblue',
'blue',
'cyan',
'green',
'olive',
'teal',
'red',
'maroon',
'pink',
'purple',
'indigo',
'fuchsia',
'yellow',
'orange',
'yellow',
'black',
'navy',
'gray'
);
$colors_array = array (
'lightblue',
'blue',
'green',
'cyan',
'yellow',
'red',
'black',
'gray-dark',
'gray',
'light',
'indigo',
'navy',
'purple',
'fuchsia',
'pink',
'maroon',
'orange',
'lime',
'teal',
'olive'
);
$net_terms_array = array (
'0'=>'On Receipt',
'7'=>'7 Days',
'10'=>'10 Days',
'14'=>'14 Days',
'15'=>'15 Days',
'30'=>'30 Days',
'60'=>'60 Days',
'90'=>'90 Days'
);
$records_per_page_array = array ('5','10','15','20','30','50','100');
include_once "settings_localization_array.php";
$category_types_array = array (
'Expense',
'Income',
'Payment Method',
'Referral'
);
$asset_types_array = array (
'Laptop'=>'fa-laptop',
'Desktop'=>'fa-desktop',
'Server'=>'fa-server',
'Phone'=>'fa-phone',
'Mobile Phone'=>'fa-mobile-alt',
'Tablet'=>'fa-tablet-alt',
'Firewall/Router'=>'fa-fire-alt',
'Switch'=>'fa-network-wired',
'Access Point'=>'fa-wifi',
'Printer'=>'fa-print',
'Display'=>'fa-tv',
'Camera'=>'fa-video',
'Virtual Machine'=>'fa-cloud',
'Other'=>'fa-tag'
);
$software_types_array = array (
'Software as a Service (SaaS)',
'Productivity Suites',
'Web Application',
'Desktop Application',
'Mobile Application',
'Security Software',
'System Software',
'Operating System',
'Other'
);
$license_types_array = array (
'Device',
'User'
);
$document_types_array = array (
'0'=>'Document',
'1'=>'Template',
'2'=>'Global Template'
);
$asset_status_array = array (
'Ready to Deploy',
'Deployed',
'Out for Repair',
'Lost',
'Stolen',
'Retired'
);
$ticket_status_array = array (
'Open',
'On Hold',
'Auto Close',
'Closed'
);
$industry_select_array = array(
"Accounting",
"Agriculture",
"Automotive",
"Construction",
"Education",
"Entertainent",
"Finance",
"Government",
"Healthcare",
"Hospititality",
"Information Technology",
"Insurance",
"Pharmacy",
"Law",
"Manufacturing",
"Marketing & Advertising",
"Military",
"Non-Profit",
"Real Estate",
"Retail",
"Services",
"Transportation",
"Other" // An 'Other' option for industries not listed
);
$start_page_select_array = array (
'dashboard.php'=>'Dashboard',
'clients.php'=> 'Client Management',
'tickets.php'=> 'Support Tickets',
'invoices.php' => 'Invoices'
);
$rack_type_select_array = array(
"Open Wall-Mount",
"Enclosed Wall-Mount",
"Open Floor-Standing",
"Enclosed Floor-Standing",
"Other"
);
$note_types_array = array (
'Call'=>'fa-phone-alt',
'Email'=>'fa-envelope',
'Meeting'=>'fa-handshake',
'In Person'=>'fa-people-arrows',
'Note'=>'fa-sticky-note'
);
$interface_types_array = array (
'Ethernet',
'SFP',
'WiFi'
);

View File

@@ -10,7 +10,7 @@ $row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('ticket_id') AS nu
$num_active_tickets = $row['num'];
// Recurring Ticket Count
$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('scheduled_ticket_id') AS num FROM scheduled_tickets LEFT JOIN clients ON client_id = scheduled_ticket_client_id WHERE 1 = 1 $access_permission_query"));
$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('recurring_ticket_id') AS num FROM recurring_tickets LEFT JOIN clients ON client_id = recurring_ticket_client_id WHERE 1 = 1 $access_permission_query"));
$num_recurring_tickets = $row['num'];
// Active Project Count
@@ -22,7 +22,7 @@ $row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('invoice_id') AS n
$num_open_invoices = $row['num'];
// Recurring Invoice Count
$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('recurring_id') AS num FROM recurring WHERE recurring_archived_at IS NULL"));
$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('recurring_invoice_id') AS num FROM recurring_invoices WHERE recurring_invoice_archived_at IS NULL"));
$num_recurring_invoices = $row['num'];
// Open Quotes Count

View File

@@ -39,6 +39,7 @@ header("X-Frame-Options: DENY");
<link href='plugins/daterangepicker/daterangepicker.css' rel='stylesheet' />
<link href="plugins/toastr/toastr.min.css" rel="stylesheet">
<link href="plugins/DataTables/datatables.min.css" rel="stylesheet">
<link href="plugins/intl-tel-input/css/intlTelInput.min.css" rel="stylesheet">
<!-- CSS to allow regular button to show as block button in mobile response view using the class btn-responsive -->
<link href="css/itflow_custom.css" rel="stylesheet">

View File

@@ -61,9 +61,11 @@ if (isset($_GET['client_id'])) {
$contact_name = nullable_htmlentities($row['contact_name']);
$contact_title = nullable_htmlentities($row['contact_title']);
$contact_email = nullable_htmlentities($row['contact_email']);
$contact_phone = formatPhoneNumber($row['contact_phone']);
$contact_phone_country_code = nullable_htmlentities($row['contact_phone_country_code']);
$contact_phone = nullable_htmlentities(formatPhoneNumber($row['contact_phone'], $contact_phone_country_code));
$contact_extension = nullable_htmlentities($row['contact_extension']);
$contact_mobile = formatPhoneNumber($row['contact_mobile']);
$contact_mobile_country_code = nullable_htmlentities($row['contact_mobile_country_code']);
$contact_mobile = nullable_htmlentities(formatPhoneNumber($row['contact_mobile'], $contact_mobile_country_code));
$contact_primary = intval($row['contact_primary']);
$location_id = intval($row['location_id']);
$location_name = nullable_htmlentities($row['location_name']);
@@ -72,7 +74,8 @@ if (isset($_GET['client_id'])) {
$location_state = nullable_htmlentities($row['location_state']);
$location_zip = nullable_htmlentities($row['location_zip']);
$location_country = nullable_htmlentities($row['location_country']);
$location_phone = formatPhoneNumber($row['location_phone']);
$location_phone_country_code = nullable_htmlentities($row['location_phone_country_code']);
$location_phone = nullable_htmlentities(formatPhoneNumber($row['location_phone'], $location_phone_country_code));
$location_primary = intval($row['location_primary']);
// Tab Title // No Sanitizing needed
@@ -115,13 +118,13 @@ if (isset($_GET['client_id'])) {
$balance = $invoice_amounts - $amount_paid;
//Get Monthly Recurring Total
$sql_recurring_monthly_total = mysqli_query($mysqli, "SELECT SUM(recurring_amount) AS recurring_monthly_total FROM recurring WHERE recurring_status = 1 AND recurring_frequency = 'month' AND recurring_client_id = $client_id");
$sql_recurring_monthly_total = mysqli_query($mysqli, "SELECT SUM(recurring_invoice_amount) AS recurring_monthly_total FROM recurring_invoices WHERE recurring_invoice_status = 1 AND recurring_invoice_frequency = 'month' AND recurring_invoice_client_id = $client_id");
$row = mysqli_fetch_array($sql_recurring_monthly_total);
$recurring_monthly_total = floatval($row['recurring_monthly_total']);
//Get Yearly Recurring Total
$sql_recurring_yearly_total = mysqli_query($mysqli, "SELECT SUM(recurring_amount) AS recurring_yearly_total FROM recurring WHERE recurring_status = 1 AND recurring_frequency = 'year' AND recurring_client_id = $client_id");
$sql_recurring_yearly_total = mysqli_query($mysqli, "SELECT SUM(recurring_invoice_amount) AS recurring_yearly_total FROM recurring_invoices WHERE recurring_invoice_status = 1 AND recurring_invoice_frequency = 'year' AND recurring_invoice_client_id = $client_id");
$row = mysqli_fetch_array($sql_recurring_yearly_total);
$recurring_yearly_total = floatval($row['recurring_yearly_total']) / 12;
@@ -145,8 +148,12 @@ if (isset($_GET['client_id'])) {
$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('ticket_id') AS num FROM tickets WHERE ticket_archived_at IS NULL AND ticket_closed_at IS NOT NULL AND ticket_client_id = $client_id"));
$num_closed_tickets = $row['num'];
$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('scheduled_ticket_id') AS num FROM scheduled_tickets WHERE scheduled_ticket_client_id = $client_id"));
$num_scheduled_tickets = $row['num'];
$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('recurring_ticket_id') AS num FROM recurring_tickets WHERE recurring_ticket_client_id = $client_id"));
$num_recurring_tickets = $row['num'];
// Active Project Count
$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('project_id') AS num FROM projects WHERE project_archived_at IS NULL AND project_completed_at IS NULL AND project_client_id = $client_id"));
$num_active_projects = $row['num'];
$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('service_id') AS num FROM services WHERE service_client_id = $client_id"));
$num_services = $row['num'];
@@ -154,8 +161,8 @@ if (isset($_GET['client_id'])) {
$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('vendor_id') AS num FROM vendors WHERE vendor_archived_at IS NULL AND vendor_client_id = $client_id AND vendor_template = 0"));
$num_vendors = $row['num'];
$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('login_id') AS num FROM logins WHERE login_archived_at IS NULL AND login_client_id = $client_id"));
$num_logins = $row['num'];
$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('credential_id') AS num FROM credentials WHERE credential_archived_at IS NULL AND credential_client_id = $client_id"));
$num_credentials = $row['num'];
$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('network_id') AS num FROM networks WHERE network_archived_at IS NULL AND network_client_id = $client_id"));
$num_networks = $row['num'];
@@ -196,8 +203,8 @@ if (isset($_GET['client_id'])) {
$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('quote_id') AS num FROM quotes WHERE quote_archived_at IS NULL AND quote_client_id = $client_id"));
$num_quotes = $row['num'];
$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('recurring_id') AS num FROM recurring WHERE recurring_archived_at IS NULL AND recurring_client_id = $client_id"));
$num_recurring = $row['num'];
$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('recurring_invoice_id') AS num FROM recurring_invoices WHERE recurring_invoice_archived_at IS NULL AND recurring_invoice_client_id = $client_id"));
$num_recurring_invoices = $row['num'];
$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('payment_id') AS num FROM payments, invoices WHERE payment_invoice_id = invoice_id AND invoice_client_id = $client_id"));
$num_payments = $row['num'];
@@ -208,8 +215,8 @@ if (isset($_GET['client_id'])) {
$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('document_id') AS num FROM documents WHERE document_archived_at IS NULL AND document_client_id = $client_id"));
$num_documents = $row['num'];
$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('event_id') AS num FROM events WHERE event_client_id = $client_id"));
$num_events = $row['num'];
$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('event_id') AS num FROM calendar_events WHERE event_client_id = $client_id"));
$num_calendar_events = $row['num'];
$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('trip_id') AS num FROM trips WHERE trip_archived_at IS NULL AND trip_client_id = $client_id"));
$num_trips = $row['num'];
@@ -241,13 +248,13 @@ if (isset($_GET['client_id'])) {
));
$num_domains_urgent = intval($row['num']);
// Count Certificates Expiring within 45 Days
// Count Certificates Expiring within 7 Days
$row = mysqli_fetch_assoc(mysqli_query(
$mysqli,
"SELECT COUNT('certificate_id') AS num FROM certificates
WHERE certificate_client_id = $client_id
AND certificate_expire IS NOT NULL
AND certificate_expire < CURRENT_DATE + INTERVAL 45 DAY
AND certificate_expire < CURRENT_DATE + INTERVAL 7 DAY
AND certificate_archived_at IS NULL"
));
$num_certificates_expiring = intval($row['num']);
@@ -260,7 +267,7 @@ if (isset($_GET['client_id'])) {
AND certificate_expire IS NOT NULL
AND (
certificate_expire < CURRENT_DATE
OR certificate_expire < CURRENT_DATE + INTERVAL 7 DAY
OR certificate_expire < CURRENT_DATE + INTERVAL 1 DAY
)
AND certificate_archived_at IS NULL"
));

View File

@@ -0,0 +1,19 @@
<?php
$result = mysqli_query($mysqli, "SELECT config_timezone FROM settings WHERE company_id = 1");
$row = mysqli_fetch_array($result);
$_SESSION['session_timezone'] = $row['config_timezone'];
// Set PHP timezone
date_default_timezone_set($_SESSION['session_timezone']);
// Calculate UTC offset and store it in session
$session_datetime = new DateTime('now', new DateTimeZone($_SESSION['session_timezone']));
$_SESSION['session_utc_offset'] = $session_datetime->format('P');
// Use the stored timezone and offset
$session_timezone = $_SESSION['session_timezone'];
date_default_timezone_set($session_timezone);
// Set MySQL session time zone
mysqli_query($mysqli, "SET time_zone = '{$_SESSION['session_utc_offset']}'");

View File

@@ -96,6 +96,13 @@
<p>Tickets by Client</p>
</a>
</li>
<li class="nav-item">
<a href="report_time_by_tech.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "report_time_by_tech.php") { echo "active"; } ?>">
<i class="nav-icon fas fa-life-ring"></i>
<p>Time by Technician</p>
</a>
</li>
<?php } ?>
<?php if (lookupUserPermission("module_credential") >= 1) { ?>
<li class="nav-item">

View File

@@ -0,0 +1,775 @@
<?php
$countries_array = array(
"Afghanistan",
"Albania",
"Algeria",
"Andorra",
"Angola",
"Antigua and Barbuda",
"Argentina",
"Armenia",
"Australia",
"Austria",
"Azerbaijan",
"Bahamas",
"Bahrain",
"Bangladesh",
"Barbados",
"Belarus",
"Belgium",
"Belize",
"Benin",
"Bhutan",
"Bolivia",
"Bosnia and Herzegovina",
"Botswana",
"Brazil",
"Brunei",
"Bulgaria",
"Burkina Faso",
"Burundi",
"Cambodia",
"Cameroon",
"Canada",
"Cape Verde",
"Central African Republic",
"Chad",
"Chile",
"China",
"Colombi",
"Comoros",
"Congo (Brazzaville)",
"Congo",
"Costa Rica",
"Cote d'Ivoire",
"Croatia",
"Cuba",
"Cyprus",
"Czech Republic",
"Denmark",
"Djibouti",
"Dominica",
"Dominican Republic",
"East Timor (Timor Timur)",
"Ecuador",
"Egypt",
"El Salvador",
"Equatorial Guinea",
"Eritrea",
"Estonia",
"Ethiopia",
"Fiji",
"Finland",
"France",
"Gabon",
"Gambia, The",
"Georgia",
"Germany",
"Ghana",
"Greece",
"Grenada",
"Guatemala",
"Guinea",
"Guinea-Bissau",
"Guyana",
"Haiti",
"Honduras",
"Hungary",
"Iceland",
"India",
"Indonesia",
"Iran",
"Iraq",
"Ireland",
"Israel",
"Italy",
"Jamaica",
"Japan",
"Jordan",
"Kazakhstan",
"Kenya",
"Kiribati",
"Korea, North",
"Korea, South",
"Kuwait",
"Kyrgyzstan",
"Laos",
"Latvia",
"Lebanon",
"Lesotho",
"Liberia",
"Libya",
"Liechtenstein",
"Lithuania",
"Luxembourg",
"Macedonia",
"Madagascar",
"Malawi",
"Malaysia",
"Maldives",
"Mali",
"Malta",
"Marshall Islands",
"Mauritania",
"Mauritius",
"Mexico",
"Micronesia",
"Moldova",
"Monaco",
"Mongolia",
"Morocco",
"Mozambique",
"Myanmar",
"Namibia",
"Nauru",
"Nepal",
"Netherlands",
"New Zealand",
"Nicaragua",
"Niger",
"Nigeria",
"Norway",
"Oman",
"Pakistan",
"Palau",
"Panama",
"Papua New Guinea",
"Paraguay",
"Peru",
"Philippines",
"Poland",
"Portugal",
"Qatar",
"Romania",
"Russia",
"Rwanda",
"Saint Kitts and Nevis",
"Saint Lucia",
"Saint Vincent",
"Samoa",
"San Marino",
"Sao Tome and Principe",
"Saudi Arabia",
"Senegal",
"Serbia and Montenegro",
"Seychelles",
"Sierra Leone",
"Singapore",
"Slovakia",
"Slovenia",
"Solomon Islands",
"Somalia",
"South Africa",
"Spain",
"Sri Lanka",
"Sudan",
"Suriname",
"Swaziland",
"Sweden",
"Switzerland",
"Syria",
"Taiwan",
"Tajikistan",
"Tanzania",
"Thailand",
"Togo",
"Tonga",
"Trinidad and Tobago",
"Tunisia",
"Turkey",
"Turkmenistan",
"Tuvalu",
"Uganda",
"Ukraine",
"United Arab Emirates",
"United Kingdom",
"United States",
"Uruguay",
"Uzbekistan",
"Vanuatu",
"Vatican City",
"Venezuela",
"Vietnam",
"Yemen",
"Zambia",
"Zimbabwe"
);
$currencies_array = array(
'AED' => 'United Arab Emirates Dirham',
'ALL' => 'Albania Lek',
'AMD' => 'Armenian Dram',
'ANG' => 'Netherlands Antillean Guilder',
'AFN' => 'Afghanistan Afghani',
'ARS' => 'Argentina Peso',
'AWG' => 'Aruba Guilder',
'AUD' => 'Australia Dollar',
'AZN' => 'Azerbaijan New Manat',
'BHD' => 'Bahraini Dinar',
'BSD' => 'Bahamas Dollar',
'BBD' => 'Barbados Dollar',
'BDT' => 'Bangladeshi taka',
'BYR' => 'Belarus Ruble',
'BZD' => 'Belize Dollar',
'BMD' => 'Bermuda Dollar',
'BOB' => 'Bolivia Boliviano',
'BAM' => 'Bosnia and Herzegovina Convertible Marka',
'BWP' => 'Botswana Pula',
'BGN' => 'Bulgaria Lev',
'BRL' => 'Brazil Real',
'BND' => 'Brunei Darussalam Dollar',
'KHR' => 'Cambodia Riel',
'CAD' => 'Canada Dollar',
'KYD' => 'Cayman Islands Dollar',
'CLP' => 'Chile Peso',
'CNY' => 'China Yuan Renminbi',
'COP' => 'Colombia Peso',
'CRC' => 'Costa Rica Colon',
'HRK' => 'Croatia Kuna',
'CUP' => 'Cuba Peso',
'CZK' => 'Czech Republic Koruna',
'DKK' => 'Denmark Krone',
'DOP' => 'Dominican Republic Peso',
'DZD' => 'Algerian Dinar',
'XCD' => 'East Caribbean Dollar',
'EGP' => 'Egypt Pound',
'ERN' => 'Eritrean Nakfa',
'SVC' => 'El Salvador Colon',
'EEK' => 'Estonia Kroon',
'EUR' => 'Euro Member Countries',
'FKP' => 'Falkland Islands (Malvinas) Pound',
'FJD' => 'Fiji Dollar',
'GHC' => 'Ghana Cedis',
'GIP' => 'Gibraltar Pound',
'GTQ' => 'Guatemala Quetzal',
'GGP' => 'Guernsey Pound',
'GYD' => 'Guyana Dollar',
'HNL' => 'Honduras Lempira',
'HKD' => 'Hong Kong Dollar',
'HUF' => 'Hungary Forint',
'ISK' => 'Iceland Krona',
'INR' => 'India Rupee',
'IDR' => 'Indonesia Rupiah',
'KZT' => 'Kazakhstan Tenge',
'IRR' => 'Iran Rial',
'IMP' => 'Isle of Man Pound',
'KGS' => 'Kyrgyzstan Som',
'IQD' => 'Iraqi Dinar',
'ILS' => 'Israel Shekel',
'JMD' => 'Jamaica Dollar',
'JPY' => 'Japan Yen',
'JEP' => 'Jersey Pound',
'KMF' => 'Comorian Franc',
'KPW' => 'Korea (North) Won',
'KRW' => 'Korea (South) Won',
'KWD' => 'Kuwaiti Dinar',
'LAK' => 'Laos Kip',
'LVL' => 'Latvia Lat',
'LBP' => 'Lebanon Pound',
'LRD' => 'Liberia Dollar',
'LTL' => 'Lithuania Litas',
'LYD' => 'Libyan Dinar',
'MKD' => 'Macedonia Denar',
'MYR' => 'Malaysia Ringgit',
'MUR' => 'Mauritius Rupee',
'MXN' => 'Mexico Peso',
'MNT' => 'Mongolia Tughrik',
'MZN' => 'Mozambique Metical',
'MRO' => 'Mauritanian Ouguiya',
'MWK' => 'Malawian Kwacha',
'NAD' => 'Namibia Dollar',
'NPR' => 'Nepal Rupee',
'NZD' => 'New Zealand Dollar',
'NIO' => 'Nicaragua Cordoba',
'NGN' => 'Nigeria Naira',
'NOK' => 'Norway Krone',
'OMR' => 'Oman Rial',
'PAB' => 'Panamanian Balboa',
'PKR' => 'Pakistan Rupee',
'PYG' => 'Paraguay Guarani',
'PEN' => 'Peru Nuevo Sol',
'PHP' => 'Philippines Peso',
'PLN' => 'Poland Zloty',
'QAR' => 'Qatar Riyal',
'RON' => 'Romania New Leu',
'RUB' => 'Russia Ruble',
'RWF' => 'Rwandan Franc',
'SHP' => 'Saint Helena Pound',
'SAR' => 'Saudi Arabia Riyal',
'RSD' => 'Serbia Dinar',
'SCR' => 'Seychelles Rupee',
'SGD' => 'Singapore Dollar',
'SBD' => 'Solomon Islands Dollar',
'SLL' => 'Sierra Leonean Leone',
'SOS' => 'Somalia Shilling',
'SSP' => 'South Sudanese Pound',
'SZL' => 'Swazi Lilangeni',
'TND' => 'Tunisian Dinar',
'UYI' => 'Uruguayan Peso (Indexed Units)',
'VES' => 'Venezuelan Bolívar Soberano',
'VUV' => 'Vanuatu Vatu',
'WST' => 'Samoan Tala',
'XOF' => 'West African CFA Franc',
'XPF' => 'CFP Franc',
'ZAR' => 'South Africa Rand',
'LKR' => 'Sri Lanka Rupee',
'SEK' => 'Sweden Krona',
'CHF' => 'Switzerland Franc',
'SRD' => 'Suriname Dollar',
'SYP' => 'Syria Pound',
'TWD' => 'Taiwan New Dollar',
'THB' => 'Thailand Baht',
'TTD' => 'Trinidad and Tobago Dollar',
'TRY' => 'Turkey Lira',
'TRL' => 'Turkey Lira',
'TVD' => 'Tuvalu Dollar',
'UAH' => 'Ukraine Hryvna',
'GBP' => 'United Kingdom Pound',
'USD' => 'United States Dollar',
'UYU' => 'Uruguay Peso',
'UZS' => 'Uzbekistan Som',
'VEF' => 'Venezuela Bolivar',
'VND' => 'Viet Nam Dong',
'YER' => 'Yemen Rial',
'ZMW' => 'Zambian Kwacha',
'ZWD' => 'Zimbabwe Dollar'
);
// List of locales
$locales_array = [
'af_NA' => 'Afrikaans (Namibia)',
'af_ZA' => 'Afrikaans (South Africa)',
'af' => 'Afrikaans',
'ak_GH' => 'Akan (Ghana)',
'ak' => 'Akan',
'sq_AL' => 'Albanian (Albania)',
'sq' => 'Albanian',
'am_ET' => 'Amharic (Ethiopia)',
'am' => 'Amharic',
'ar_DZ' => 'Arabic (Algeria)',
'ar_BH' => 'Arabic (Bahrain)',
'ar_EG' => 'Arabic (Egypt)',
'ar_IQ' => 'Arabic (Iraq)',
'ar_JO' => 'Arabic (Jordan)',
'ar_KW' => 'Arabic (Kuwait)',
'ar_LB' => 'Arabic (Lebanon)',
'ar_LY' => 'Arabic (Libya)',
'ar_MA' => 'Arabic (Morocco)',
'ar_OM' => 'Arabic (Oman)',
'ar_QA' => 'Arabic (Qatar)',
'ar_SA' => 'Arabic (Saudi Arabia)',
'ar_SD' => 'Arabic (Sudan)',
'ar_SY' => 'Arabic (Syria)',
'ar_TN' => 'Arabic (Tunisia)',
'ar_AE' => 'Arabic (United Arab Emirates)',
'ar_YE' => 'Arabic (Yemen)',
'ar' => 'Arabic',
'hy_AM' => 'Armenian (Armenia)',
'hy' => 'Armenian',
'as_IN' => 'Assamese (India)',
'as' => 'Assamese',
'asa_TZ' => 'Asu (Tanzania)',
'asa' => 'Asu',
'az_Cyrl' => 'Azerbaijani (Cyrillic)',
'az_Cyrl_AZ' => 'Azerbaijani (Cyrillic, Azerbaijan)',
'az_Latn' => 'Azerbaijani (Latin)',
'az_Latn_AZ' => 'Azerbaijani (Latin, Azerbaijan)',
'az' => 'Azerbaijani',
'bm_ML' => 'Bambara (Mali)',
'bm' => 'Bambara',
'eu_ES' => 'Basque (Spain)',
'eu' => 'Basque',
'be_BY' => 'Belarusian (Belarus)',
'be' => 'Belarusian',
'bem_ZM' => 'Bemba (Zambia)',
'bem' => 'Bemba',
'bez_TZ' => 'Bena (Tanzania)',
'bez' => 'Bena',
'bn_BD' => 'Bengali (Bangladesh)',
'bn_IN' => 'Bengali (India)',
'bn' => 'Bengali',
'bs_BA' => 'Bosnian (Bosnia and Herzegovina)',
'bs' => 'Bosnian',
'bg_BG' => 'Bulgarian (Bulgaria)',
'bg' => 'Bulgarian',
'my_MM' => 'Burmese (Myanmar [Burma])',
'my' => 'Burmese',
'ca_ES' => 'Catalan (Spain)',
'ca' => 'Catalan',
'tzm_Latn' => 'Central Morocco Tamazight (Latin)',
'tzm_Latn_MA' => 'Central Morocco Tamazight (Latin, Morocco)',
'tzm' => 'Central Morocco Tamazight',
'chr_US' => 'Cherokee (United States)',
'chr' => 'Cherokee',
'cgg_UG' => 'Chiga (Uganda)',
'cgg' => 'Chiga',
'zh_Hans' => 'Chinese (Simplified Han)',
'zh_Hans_CN' => 'Chinese (Simplified Han, China)',
'zh_Hans_HK' => 'Chinese (Simplified Han, Hong Kong SAR China)',
'zh_Hans_MO' => 'Chinese (Simplified Han, Macau SAR China)',
'zh_Hans_SG' => 'Chinese (Simplified Han, Singapore)',
'zh_Hant' => 'Chinese (Traditional Han)',
'zh_Hant_HK' => 'Chinese (Traditional Han, Hong Kong SAR China)',
'zh_Hant_MO' => 'Chinese (Traditional Han, Macau SAR China)',
'zh_Hant_TW' => 'Chinese (Traditional Han, Taiwan)',
'zh' => 'Chinese',
'kw_GB' => 'Cornish (United Kingdom)',
'kw' => 'Cornish',
'hr_HR' => 'Croatian (Croatia)',
'hr' => 'Croatian',
'cs_CZ' => 'Czech (Czech Republic)',
'cs' => 'Czech',
'da_DK' => 'Danish (Denmark)',
'da' => 'Danish',
'nl_BE' => 'Dutch (Belgium)',
'nl_NL' => 'Dutch (Netherlands)',
'nl' => 'Dutch',
'ebu_KE' => 'Embu (Kenya)',
'ebu' => 'Embu',
'en_AS' => 'English (American Samoa)',
'en_AU' => 'English (Australia)',
'en_BE' => 'English (Belgium)',
'en_BZ' => 'English (Belize)',
'en_BW' => 'English (Botswana)',
'en_CA' => 'English (Canada)',
'en_GU' => 'English (Guam)',
'en_HK' => 'English (Hong Kong SAR China)',
'en_IN' => 'English (India)',
'en_IE' => 'English (Ireland)',
'en_JM' => 'English (Jamaica)',
'en_MT' => 'English (Malta)',
'en_MH' => 'English (Marshall Islands)',
'en_MU' => 'English (Mauritius)',
'en_NA' => 'English (Namibia)',
'en_NZ' => 'English (New Zealand)',
'en_MP' => 'English (Northern Mariana Islands)',
'en_PK' => 'English (Pakistan)',
'en_PH' => 'English (Philippines)',
'en_SG' => 'English (Singapore)',
'en_ZA' => 'English (South Africa)',
'en_TT' => 'English (Trinidad and Tobago)',
'en_UM' => 'English (U.S. Minor Outlying Islands)',
'en_VI' => 'English (U.S. Virgin Islands)',
'en_GB' => 'English (United Kingdom)',
'en_US' => 'English (United States)',
'en_ZW' => 'English (Zimbabwe)',
'en' => 'English',
'eo' => 'Esperanto',
'et_EE' => 'Estonian (Estonia)',
'et' => 'Estonian',
'ee_GH' => 'Ewe (Ghana)',
'ee_TG' => 'Ewe (Togo)',
'ee' => 'Ewe',
'fo_FO' => 'Faroese (Faroe Islands)',
'fo' => 'Faroese',
'fil_PH' => 'Filipino (Philippines)',
'fil' => 'Filipino',
'fi_FI' => 'Finnish (Finland)',
'fi' => 'Finnish',
'fr_BE' => 'French (Belgium)',
'fr_BJ' => 'French (Benin)',
'fr_BF' => 'French (Burkina Faso)',
'fr_BI' => 'French (Burundi)',
'fr_CM' => 'French (Cameroon)',
'fr_CA' => 'French (Canada)',
'fr_CF' => 'French (Central African Republic)',
'fr_TD' => 'French (Chad)',
'fr_KM' => 'French (Comoros)',
'fr_CG' => 'French (Congo - Brazzaville)',
'fr_CD' => 'French (Congo - Kinshasa)',
'fr_CI' => 'French (Côte dIvoire)',
'fr_DJ' => 'French (Djibouti)',
'fr_GQ' => 'French (Equatorial Guinea)',
'fr_FR' => 'French (France)',
'fr_GA' => 'French (Gabon)',
'fr_GP' => 'French (Guadeloupe)',
'fr_GN' => 'French (Guinea)',
'fr_LU' => 'French (Luxembourg)',
'fr_MG' => 'French (Madagascar)',
'fr_ML' => 'French (Mali)',
'fr_MQ' => 'French (Martinique)',
'fr_MC' => 'French (Monaco)',
'fr_NE' => 'French (Niger)',
'fr_RW' => 'French (Rwanda)',
'fr_RE' => 'French (Réunion)',
'fr_BL' => 'French (Saint Barthélemy)',
'fr_MF' => 'French (Saint Martin)',
'fr_SN' => 'French (Senegal)',
'fr_CH' => 'French (Switzerland)',
'fr_TG' => 'French (Togo)',
'fr' => 'French',
'ff_SN' => 'Fulah (Senegal)',
'ff' => 'Fulah',
'gl_ES' => 'Galician (Spain)',
'gl' => 'Galician',
'lg_UG' => 'Ganda (Uganda)',
'lg' => 'Ganda',
'ka_GE' => 'Georgian (Georgia)',
'ka' => 'Georgian',
'de_AT' => 'German (Austria)',
'de_BE' => 'German (Belgium)',
'de_DE' => 'German (Germany)',
'de_LI' => 'German (Liechtenstein)',
'de_LU' => 'German (Luxembourg)',
'de_CH' => 'German (Switzerland)',
'de' => 'German',
'el_CY' => 'Greek (Cyprus)',
'el_GR' => 'Greek (Greece)',
'el' => 'Greek',
'gu_IN' => 'Gujarati (India)',
'gu' => 'Gujarati',
'guz_KE' => 'Gusii (Kenya)',
'guz' => 'Gusii',
'ha_Latn' => 'Hausa (Latin)',
'ha_Latn_GH' => 'Hausa (Latin, Ghana)',
'ha_Latn_NE' => 'Hausa (Latin, Niger)',
'ha_Latn_NG' => 'Hausa (Latin, Nigeria)',
'ha' => 'Hausa',
'haw_US' => 'Hawaiian (United States)',
'haw' => 'Hawaiian',
'he_IL' => 'Hebrew (Israel)',
'he' => 'Hebrew',
'hi_IN' => 'Hindi (India)',
'hi' => 'Hindi',
'hu_HU' => 'Hungarian (Hungary)',
'hu' => 'Hungarian',
'is_IS' => 'Icelandic (Iceland)',
'is' => 'Icelandic',
'ig_NG' => 'Igbo (Nigeria)',
'ig' => 'Igbo',
'id_ID' => 'Indonesian (Indonesia)',
'id' => 'Indonesian',
'ga_IE' => 'Irish (Ireland)',
'ga' => 'Irish',
'it_IT' => 'Italian (Italy)',
'it_CH' => 'Italian (Switzerland)',
'it' => 'Italian',
'ja_JP' => 'Japanese (Japan)',
'ja' => 'Japanese',
'kea_CV' => 'Kabuverdianu (Cape Verde)',
'kea' => 'Kabuverdianu',
'kab_DZ' => 'Kabyle (Algeria)',
'kab' => 'Kabyle',
'kl_GL' => 'Kalaallisut (Greenland)',
'kl' => 'Kalaallisut',
'kln_KE' => 'Kalenjin (Kenya)',
'kln' => 'Kalenjin',
'kam_KE' => 'Kamba (Kenya)',
'kam' => 'Kamba',
'kn_IN' => 'Kannada (India)',
'kn' => 'Kannada',
'kk_Cyrl' => 'Kazakh (Cyrillic)',
'kk_Cyrl_KZ' => 'Kazakh (Cyrillic, Kazakhstan)',
'kk' => 'Kazakh',
'km_KH' => 'Khmer (Cambodia)',
'km' => 'Khmer',
'ki_KE' => 'Kikuyu (Kenya)',
'ki' => 'Kikuyu',
'rw_RW' => 'Kinyarwanda (Rwanda)',
'rw' => 'Kinyarwanda',
'kok_IN' => 'Konkani (India)',
'kok' => 'Konkani',
'ko_KR' => 'Korean (South Korea)',
'ko' => 'Korean',
'khq_ML' => 'Koyra Chiini (Mali)',
'khq' => 'Koyra Chiini',
'ses_ML' => 'Koyraboro Senni (Mali)',
'ses' => 'Koyraboro Senni',
'lag_TZ' => 'Langi (Tanzania)',
'lag' => 'Langi',
'lv_LV' => 'Latvian (Latvia)',
'lv' => 'Latvian',
'lt_LT' => 'Lithuanian (Lithuania)',
'lt' => 'Lithuanian',
'luo_KE' => 'Luo (Kenya)',
'luo' => 'Luo',
'luy_KE' => 'Luyia (Kenya)',
'luy' => 'Luyia',
'mk_MK' => 'Macedonian (Macedonia)',
'mk' => 'Macedonian',
'jmc_TZ' => 'Machame (Tanzania)',
'jmc' => 'Machame',
'kde_TZ' => 'Makonde (Tanzania)',
'kde' => 'Makonde',
'mg_MG' => 'Malagasy (Madagascar)',
'mg' => 'Malagasy',
'ms_BN' => 'Malay (Brunei)',
'ms_MY' => 'Malay (Malaysia)',
'ms' => 'Malay',
'ml_IN' => 'Malayalam (India)',
'ml' => 'Malayalam',
'mt_MT' => 'Maltese (Malta)',
'mt' => 'Maltese',
'gv_GB' => 'Manx (United Kingdom)',
'gv' => 'Manx',
'mr_IN' => 'Marathi (India)',
'mr' => 'Marathi',
'mas_KE' => 'Masai (Kenya)',
'mas_TZ' => 'Masai (Tanzania)',
'mas' => 'Masai',
'mer_KE' => 'Meru (Kenya)',
'mer' => 'Meru',
'mfe_MU' => 'Morisyen (Mauritius)',
'mfe' => 'Morisyen',
'naq_NA' => 'Nama (Namibia)',
'naq' => 'Nama',
'ne_IN' => 'Nepali (India)',
'ne_NP' => 'Nepali (Nepal)',
'ne' => 'Nepali',
'nd_ZW' => 'North Ndebele (Zimbabwe)',
'nd' => 'North Ndebele',
'nb_NO' => 'Norwegian Bokmål (Norway)',
'nb' => 'Norwegian Bokmål',
'nn_NO' => 'Norwegian Nynorsk (Norway)',
'nn' => 'Norwegian Nynorsk',
'nyn_UG' => 'Nyankole (Uganda)',
'nyn' => 'Nyankole',
'or_IN' => 'Oriya (India)',
'or' => 'Oriya',
'om_ET' => 'Oromo (Ethiopia)',
'om_KE' => 'Oromo (Kenya)',
'om' => 'Oromo',
'ps_AF' => 'Pashto (Afghanistan)',
'ps' => 'Pashto',
'fa_AF' => 'Persian (Afghanistan)',
'fa_IR' => 'Persian (Iran)',
'fa' => 'Persian',
'pl_PL' => 'Polish (Poland)',
'pl' => 'Polish',
'pt_BR' => 'Portuguese (Brazil)',
'pt_GW' => 'Portuguese (Guinea-Bissau)',
'pt_MZ' => 'Portuguese (Mozambique)',
'pt_PT' => 'Portuguese (Portugal)',
'pt' => 'Portuguese',
'pa_Arab' => 'Punjabi (Arabic)',
'pa_Arab_PK' => 'Punjabi (Arabic, Pakistan)',
'pa_Guru' => 'Punjabi (Gurmukhi)',
'pa_Guru_IN' => 'Punjabi (Gurmukhi, India)',
'pa' => 'Punjabi',
'ro_MD' => 'Romanian (Moldova)',
'ro_RO' => 'Romanian (Romania)',
'ro' => 'Romanian',
'rm_CH' => 'Romansh (Switzerland)',
'rm' => 'Romansh',
'rof_TZ' => 'Rombo (Tanzania)',
'rof' => 'Rombo',
'ru_MD' => 'Russian (Moldova)',
'ru_RU' => 'Russian (Russia)',
'ru_UA' => 'Russian (Ukraine)',
'ru' => 'Russian',
'rwk_TZ' => 'Rwa (Tanzania)',
'rwk' => 'Rwa',
'saq_KE' => 'Samburu (Kenya)',
'saq' => 'Samburu',
'sg_CF' => 'Sango (Central African Republic)',
'sg' => 'Sango',
'seh_MZ' => 'Sena (Mozambique)',
'seh' => 'Sena',
'sr_Cyrl' => 'Serbian (Cyrillic)',
'sr_Cyrl_BA' => 'Serbian (Cyrillic, Bosnia and Herzegovina)',
'sr_Cyrl_ME' => 'Serbian (Cyrillic, Montenegro)',
'sr_Cyrl_RS' => 'Serbian (Cyrillic, Serbia)',
'sr_Latn' => 'Serbian (Latin)',
'sr_Latn_BA' => 'Serbian (Latin, Bosnia and Herzegovina)',
'sr_Latn_ME' => 'Serbian (Latin, Montenegro)',
'sr_Latn_RS' => 'Serbian (Latin, Serbia)',
'sr' => 'Serbian',
'sn_ZW' => 'Shona (Zimbabwe)',
'sn' => 'Shona',
'ii_CN' => 'Sichuan Yi (China)',
'ii' => 'Sichuan Yi',
'si_LK' => 'Sinhala (Sri Lanka)',
'si' => 'Sinhala',
'sk_SK' => 'Slovak (Slovakia)',
'sk' => 'Slovak',
'sl_SI' => 'Slovenian (Slovenia)',
'sl' => 'Slovenian',
'xog_UG' => 'Soga (Uganda)',
'xog' => 'Soga',
'so_DJ' => 'Somali (Djibouti)',
'so_ET' => 'Somali (Ethiopia)',
'so_KE' => 'Somali (Kenya)',
'so_SO' => 'Somali (Somalia)',
'so' => 'Somali',
'es_AR' => 'Spanish (Argentina)',
'es_BO' => 'Spanish (Bolivia)',
'es_CL' => 'Spanish (Chile)',
'es_CO' => 'Spanish (Colombia)',
'es_CR' => 'Spanish (Costa Rica)',
'es_DO' => 'Spanish (Dominican Republic)',
'es_EC' => 'Spanish (Ecuador)',
'es_SV' => 'Spanish (El Salvador)',
'es_GQ' => 'Spanish (Equatorial Guinea)',
'es_GT' => 'Spanish (Guatemala)',
'es_HN' => 'Spanish (Honduras)',
'es_419' => 'Spanish (Latin America)',
'es_MX' => 'Spanish (Mexico)',
'es_NI' => 'Spanish (Nicaragua)',
'es_PA' => 'Spanish (Panama)',
'es_PY' => 'Spanish (Paraguay)',
'es_PE' => 'Spanish (Peru)',
'es_PR' => 'Spanish (Puerto Rico)',
'es_ES' => 'Spanish (Spain)',
'es_US' => 'Spanish (United States)',
'es_UY' => 'Spanish (Uruguay)',
'es_VE' => 'Spanish (Venezuela)',
'es' => 'Spanish',
'sw_KE' => 'Swahili (Kenya)',
'sw_TZ' => 'Swahili (Tanzania)',
'sw' => 'Swahili',
'sv_FI' => 'Swedish (Finland)',
'sv_SE' => 'Swedish (Sweden)',
'sv' => 'Swedish',
'gsw_CH' => 'Swiss German (Switzerland)',
'gsw' => 'Swiss German',
'shi_Latn' => 'Tachelhit (Latin)',
'shi_Latn_MA' => 'Tachelhit (Latin, Morocco)',
'shi_Tfng' => 'Tachelhit (Tifinagh)',
'shi_Tfng_MA' => 'Tachelhit (Tifinagh, Morocco)',
'shi' => 'Tachelhit',
'dav_KE' => 'Taita (Kenya)',
'dav' => 'Taita',
'ta_IN' => 'Tamil (India)',
'ta_LK' => 'Tamil (Sri Lanka)',
'ta' => 'Tamil',
'te_IN' => 'Telugu (India)',
'te' => 'Telugu',
'teo_KE' => 'Teso (Kenya)',
'teo_UG' => 'Teso (Uganda)',
'teo' => 'Teso',
'th_TH' => 'Thai (Thailand)',
'th' => 'Thai',
'bo_CN' => 'Tibetan (China)',
'bo_IN' => 'Tibetan (India)',
'bo' => 'Tibetan',
'ti_ER' => 'Tigrinya (Eritrea)',
'ti_ET' => 'Tigrinya (Ethiopia)',
'ti' => 'Tigrinya',
'to_TO' => 'Tonga (Tonga)',
'to' => 'Tonga',
'tr_TR' => 'Turkish (Turkey)',
'tr' => 'Turkish',
'uk_UA' => 'Ukrainian (Ukraine)',
'uk' => 'Ukrainian',
'ur_IN' => 'Urdu (India)',
'ur_PK' => 'Urdu (Pakistan)',
'ur' => 'Urdu',
'uz_Arab' => 'Uzbek (Arabic)',
'uz_Arab_AF' => 'Uzbek (Arabic, Afghanistan)',
'uz_Cyrl' => 'Uzbek (Cyrillic)',
'uz_Cyrl_UZ' => 'Uzbek (Cyrillic, Uzbekistan)',
'uz_Latn' => 'Uzbek (Latin)',
'uz_Latn_UZ' => 'Uzbek (Latin, Uzbekistan)',
'uz' => 'Uzbek',
'vi_VN' => 'Vietnamese (Vietnam)',
'vi' => 'Vietnamese',
'vun_TZ' => 'Vunjo (Tanzania)',
'vun' => 'Vunjo',
'cy_GB' => 'Welsh (United Kingdom)',
'cy' => 'Welsh',
'yo_NG' => 'Yoruba (Nigeria)',
'yo' => 'Yoruba',
'zu_ZA' => 'Zulu (South Africa)',
'zu' => 'Zulu',
];
?>