feat: Implement invoice generation and emailing functionality
- Added invoice generation logic using DomPDF. - Integrated invoice data retrieval from the API. - Implemented language determination for invoices based on customer data. - Added options to email invoices to customers and admin. - Included HTML output option for direct viewing in the browser. - Ensured proper redirection and error handling throughout the process.
This commit is contained in:
8
.gitignore
vendored
8
.gitignore
vendored
@@ -15,3 +15,11 @@ settings/soveliti/soveliti_settings.php
|
|||||||
assets/database/dev_schema.sql
|
assets/database/dev_schema.sql
|
||||||
assets/database/migration.sql
|
assets/database/migration.sql
|
||||||
assets/database/prod_schema.sql
|
assets/database/prod_schema.sql
|
||||||
|
migration.sql
|
||||||
|
assets/database/migration_triggers.sql
|
||||||
|
assets/database/migration_v2.sql
|
||||||
|
assets/database/migration_v3.sql
|
||||||
|
.DS_Store
|
||||||
|
api/.DS_Store
|
||||||
|
api/v1/.DS_Store
|
||||||
|
api/v2/.DS_Store
|
||||||
|
|||||||
BIN
api/.DS_Store
vendored
BIN
api/.DS_Store
vendored
Binary file not shown.
BIN
api/v1/.DS_Store
vendored
BIN
api/v1/.DS_Store
vendored
Binary file not shown.
BIN
api/v2/.DS_Store
vendored
BIN
api/v2/.DS_Store
vendored
Binary file not shown.
BIN
api/v2/get/.DS_Store
vendored
BIN
api/v2/get/.DS_Store
vendored
Binary file not shown.
@@ -143,6 +143,10 @@ if(isset($get_content) && $get_content!=''){
|
|||||||
$clause .= ' AND e.serialnumber IN (:'.$v[0].')';
|
$clause .= ' AND e.serialnumber IN (:'.$v[0].')';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
elseif ($v[0] == 'validate') {
|
||||||
|
// Set validation mode flag
|
||||||
|
$validation_mode = true;
|
||||||
|
}
|
||||||
elseif ($v[0] == 'firmware') {
|
elseif ($v[0] == 'firmware') {
|
||||||
//Assets with firmaware upgrade = 0 (1=latest version, 2=No software)
|
//Assets with firmaware upgrade = 0 (1=latest version, 2=No software)
|
||||||
$clause .= ' AND e.status != 5 AND e.sw_version_latest = 0';
|
$clause .= ' AND e.status != 5 AND e.sw_version_latest = 0';
|
||||||
@@ -161,7 +165,7 @@ if(isset($get_content) && $get_content!=''){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($sw_version_latest_update == 1){
|
if ($sw_version_latest_update == 1 || $clause == ''){
|
||||||
//------------------------------------------
|
//------------------------------------------
|
||||||
//UPDATE SW_STATUS
|
//UPDATE SW_STATUS
|
||||||
//------------------------------------------
|
//------------------------------------------
|
||||||
@@ -175,6 +179,10 @@ if (isset($criterias['download']) && $criterias['download'] ==''){
|
|||||||
//Request for download
|
//Request for download
|
||||||
$sql = 'SELECT e.rowID as equipmentID, e.*, p.productcode, p.productname from equipment e LEFT JOIN products p ON e.productrowid = p.rowID '.$whereclause.' ORDER BY equipmentID';
|
$sql = 'SELECT e.rowID as equipmentID, e.*, p.productcode, p.productname from equipment e LEFT JOIN products p ON e.productrowid = p.rowID '.$whereclause.' ORDER BY equipmentID';
|
||||||
}
|
}
|
||||||
|
elseif (isset($validation_mode) && $validation_mode === true) {
|
||||||
|
// Validation mode - return count only for serial validation
|
||||||
|
$sql = "SELECT count(rowID) as rowID from equipment e $whereclause";
|
||||||
|
}
|
||||||
elseif (isset($criterias['totals']) && $criterias['totals'] =='' && !isset($criterias['type'])){
|
elseif (isset($criterias['totals']) && $criterias['totals'] =='' && !isset($criterias['type'])){
|
||||||
//Request for total rows
|
//Request for total rows
|
||||||
$sql = 'SELECT count(*) as count from equipment e LEFT JOIN products p ON e.productrowid = p.rowID '.$whereclause.'';
|
$sql = 'SELECT count(*) as count from equipment e LEFT JOIN products p ON e.productrowid = p.rowID '.$whereclause.'';
|
||||||
@@ -314,7 +322,19 @@ if (debug){
|
|||||||
//------------------------------------------
|
//------------------------------------------
|
||||||
//Add paging details
|
//Add paging details
|
||||||
//------------------------------------------
|
//------------------------------------------
|
||||||
if(isset($criterias['totals']) && $criterias['totals']==''){
|
if (isset($validation_mode) && $validation_mode === true) {
|
||||||
|
$stmt->execute();
|
||||||
|
$messages = $stmt->fetch();
|
||||||
|
|
||||||
|
if ($messages[0] == 1) {
|
||||||
|
echo json_encode(array('SN'=> TRUE));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
echo json_encode(array('SN'=> FALSE));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
elseif(isset($criterias['totals']) && $criterias['totals']==''){
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
$messages = $stmt->fetch();
|
$messages = $stmt->fetch();
|
||||||
$messages = $messages[0];
|
$messages = $messages[0];
|
||||||
|
|||||||
@@ -136,10 +136,22 @@ else {
|
|||||||
$messages = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
$messages = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clean up nested JSON in description fields before final encoding
|
||||||
|
if (!isset($criterias['totals']) || $criterias['totals'] != '') {
|
||||||
|
foreach ($messages as &$message) {
|
||||||
|
if (isset($message['description']) && is_string($message['description'])) {
|
||||||
|
$decoded = json_decode($message['description'], true);
|
||||||
|
if (json_last_error() === JSON_ERROR_NONE) {
|
||||||
|
$message['description'] = json_encode($decoded, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//------------------------------------------
|
//------------------------------------------
|
||||||
//JSON_ENCODE
|
//JSON_ENCODE
|
||||||
//------------------------------------------
|
//------------------------------------------
|
||||||
$messages = json_encode($messages, JSON_UNESCAPED_UNICODE);
|
$messages = json_encode($messages, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||||||
|
|
||||||
//Send results
|
//Send results
|
||||||
echo $messages;
|
echo $messages;
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ elseif (isset($criterias['list']) && $criterias['list'] =='invoice'){
|
|||||||
//SQL for Paging
|
//SQL for Paging
|
||||||
$sql = 'SELECT tx.*, txi.item_id as item_id,txi.item_price as item_price, txi.item_quantity as item_quantity, txi.item_options as item_options, p.productcode, p.productname, inv.id as invoice, inv.created as invoice_created, i.language as user_language
|
$sql = 'SELECT tx.*, txi.item_id as item_id,txi.item_price as item_price, txi.item_quantity as item_quantity, txi.item_options as item_options, p.productcode, p.productname, inv.id as invoice, inv.created as invoice_created, i.language as user_language
|
||||||
FROM transactions tx
|
FROM transactions tx
|
||||||
left join invoice inv ON tx.id = inv.txn_id
|
left join invoice inv ON tx.txn_id = inv.txn_id
|
||||||
left join transactions_items txi ON tx.id = txi.txn_id
|
left join transactions_items txi ON tx.id = txi.txn_id
|
||||||
left join products p ON p.rowID = txi.item_id
|
left join products p ON p.rowID = txi.item_id
|
||||||
left join identity i ON i.userkey = tx.account_id '.$whereclause;
|
left join identity i ON i.userkey = tx.account_id '.$whereclause;
|
||||||
|
|||||||
@@ -161,6 +161,7 @@ if (isset($criterias['sn']) && $criterias['sn'] != ''){
|
|||||||
$debug['decision'] = 'No active software assignments found';
|
$debug['decision'] = 'No active software assignments found';
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
$available_upgrades = 0;
|
||||||
$has_priced_options = false;
|
$has_priced_options = false;
|
||||||
$has_latest_version_different = false;
|
$has_latest_version_different = false;
|
||||||
|
|
||||||
@@ -242,6 +243,8 @@ if (isset($criterias['sn']) && $criterias['sn'] != ''){
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($show_version) {
|
if ($show_version) {
|
||||||
|
$available_upgrades++;
|
||||||
|
|
||||||
//Check if there's a valid license for this upgrade
|
//Check if there's a valid license for this upgrade
|
||||||
if ($final_price > 0 && $sw_version_license) {
|
if ($final_price > 0 && $sw_version_license) {
|
||||||
//Check if the license is valid
|
//Check if the license is valid
|
||||||
@@ -286,23 +289,18 @@ if (isset($criterias['sn']) && $criterias['sn'] != ''){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply the logic:
|
// Simple logic: if any upgrades are available to show, return "yes"
|
||||||
// 1. If there are priced options -> "yes"
|
if ($available_upgrades > 0) {
|
||||||
// 2. If no priced options but current version != latest flagged version -> "yes"
|
|
||||||
// 3. Default -> "no"
|
|
||||||
if ($has_priced_options) {
|
|
||||||
$software_available = "yes";
|
$software_available = "yes";
|
||||||
$availability_reason = "Has priced upgrade options available";
|
$availability_reason = "Software upgrades available";
|
||||||
} elseif ($has_latest_version_different) {
|
|
||||||
$software_available = "yes";
|
|
||||||
$availability_reason = "Has free latest version available";
|
|
||||||
} else {
|
} else {
|
||||||
$software_available = "no";
|
$software_available = "no";
|
||||||
$availability_reason = "No upgrades available or already on latest";
|
$availability_reason = "No upgrades available";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (debug) {
|
if (debug) {
|
||||||
$debug['final_decision'] = [
|
$debug['final_decision'] = [
|
||||||
|
'available_upgrades' => $available_upgrades,
|
||||||
'has_priced_options' => $has_priced_options,
|
'has_priced_options' => $has_priced_options,
|
||||||
'has_latest_version_different' => $has_latest_version_different,
|
'has_latest_version_different' => $has_latest_version_different,
|
||||||
'software_available' => $software_available,
|
'software_available' => $software_available,
|
||||||
|
|||||||
@@ -133,6 +133,7 @@ if (isset($criterias['sn']) && $criterias['sn'] != ''){
|
|||||||
JOIN products_software_versions psv ON psa.software_version_id = psv.rowID
|
JOIN products_software_versions psv ON psa.software_version_id = psv.rowID
|
||||||
WHERE psa.product_id = ?
|
WHERE psa.product_id = ?
|
||||||
AND psa.status = 1
|
AND psa.status = 1
|
||||||
|
AND psv.latest = 1
|
||||||
AND (psv.hw_version = ? OR psv.hw_version IS NULL OR psv.hw_version = "")';
|
AND (psv.hw_version = ? OR psv.hw_version IS NULL OR psv.hw_version = "")';
|
||||||
|
|
||||||
$stmt = $pdo->prepare($sql);
|
$stmt = $pdo->prepare($sql);
|
||||||
@@ -212,16 +213,13 @@ if (isset($criterias['sn']) && $criterias['sn'] != ''){
|
|||||||
$decision_reason = 'Skipped - is current version but no upgrades scenario';
|
$decision_reason = 'Skipped - is current version but no upgrades scenario';
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
//Check if this is the current version and should be shown as disabled
|
//Check if this is the current version - always show it
|
||||||
if ($is_current_version && $has_paid_upgrade_from_current && $version['latest'] == 1) {
|
if ($is_current_version) {
|
||||||
//Show current version as disabled only if it's the latest AND there's a paid upgrade available
|
|
||||||
$show_version = true;
|
$show_version = true;
|
||||||
$is_current = true;
|
$is_current = true;
|
||||||
$final_price = '0.00';
|
$final_price = '0.00';
|
||||||
$final_currency = '';
|
$final_currency = '';
|
||||||
$decision_reason = 'Showing as CURRENT - is latest version with paid upgrade available';
|
$decision_reason = 'Showing as CURRENT - always show current version';
|
||||||
} else if ($is_current_version && !($has_paid_upgrade_from_current && $version['latest'] == 1)) {
|
|
||||||
$decision_reason = 'Skipped - is current version but not (latest + has_paid_upgrade)';
|
|
||||||
} else if (!$is_current_version) {
|
} else if (!$is_current_version) {
|
||||||
//Check if this version is part of ANY upgrade path system (either FROM or TO)
|
//Check if this version is part of ANY upgrade path system (either FROM or TO)
|
||||||
$sql = 'SELECT COUNT(*) as path_count
|
$sql = 'SELECT COUNT(*) as path_count
|
||||||
|
|||||||
BIN
api/v2/post/.DS_Store
vendored
BIN
api/v2/post/.DS_Store
vendored
Binary file not shown.
@@ -1,5 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
defined($security_key) or exit;
|
defined($security_key) or exit;
|
||||||
|
|
||||||
//------------------------------------------
|
//------------------------------------------
|
||||||
// History
|
// History
|
||||||
//------------------------------------------
|
//------------------------------------------
|
||||||
@@ -209,9 +210,8 @@ if (isset($post_content['sn']) && isset($post_content['payload'])){
|
|||||||
if ($equipmentUpdate == 1){
|
if ($equipmentUpdate == 1){
|
||||||
//get HW + SW from PortalAPI
|
//get HW + SW from PortalAPI
|
||||||
if ($post_content['type'] == 'firmware'){
|
if ($post_content['type'] == 'firmware'){
|
||||||
$test = json_decode($post_content['payload']);
|
$hw_version = $post_content['payload']['HW'];
|
||||||
$hw_version = $test->HW;
|
$sw_version = $post_content['payload']['HEX_FW'];
|
||||||
$sw_version = $test->HEX_FW;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
//GET HW + SW from object
|
//GET HW + SW from object
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ $post_content = json_decode($input,true);
|
|||||||
if (empty($partner->soldto) || $partner->soldto == ''){$soldto_search = '%';} else {$soldto_search = '-%';}
|
if (empty($partner->soldto) || $partner->soldto == ''){$soldto_search = '%';} else {$soldto_search = '-%';}
|
||||||
|
|
||||||
//default whereclause
|
//default whereclause
|
||||||
list($whereclause,$condition) = getWhereclauselvl2("software_upgrade_paths",$permission,$partner,'');
|
list($whereclause,$condition) = getWhereclauselvl2("",$permission,$partner,'');
|
||||||
|
|
||||||
//SET PARAMETERS FOR QUERY
|
//SET PARAMETERS FOR QUERY
|
||||||
$id = $post_content['rowID'] ?? ''; //check for rowID
|
$id = $post_content['rowID'] ?? ''; //check for rowID
|
||||||
|
|||||||
@@ -1672,7 +1672,7 @@ function overviewIndicators($warranty, $service, $sw_version, $sw_version_latest
|
|||||||
$indicator .= '<span class="dot" style="background-color: #13b368;">F</span>';
|
$indicator .= '<span class="dot" style="background-color: #13b368;">F</span>';
|
||||||
} else {
|
} else {
|
||||||
if ($sw_version == ''){
|
if ($sw_version == ''){
|
||||||
$indicator .= '<span class="dot" style="background-color: #81848a">F</span>';
|
$indicator .= '<span class="dot" style="background-color: #13b368;">F</span>';
|
||||||
} else {
|
} else {
|
||||||
$indicator .= '<span class="dot" style="background-color: #eb8a0d;">F</span>';
|
$indicator .= '<span class="dot" style="background-color: #eb8a0d;">F</span>';
|
||||||
}
|
}
|
||||||
@@ -1777,7 +1777,7 @@ function availableFirmware($sw_version,$sw_version_latest){
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
$message ='<span class="status">Unknown</span>';
|
$message ='<span class="status">✓</span>';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5339,10 +5339,12 @@ function generateSoftwareInvoice($invoice_data, $order_id, $language = 'US') {
|
|||||||
$customer_country = $customer['address_country'] ?? '';
|
$customer_country = $customer['address_country'] ?? '';
|
||||||
|
|
||||||
// Extract transaction data
|
// Extract transaction data
|
||||||
$payment_amount = $invoice_data['payment_amount'] ?? 0;
|
$pricing = $invoice_data['pricing'] ?? [];
|
||||||
$tax_amount = $invoice_data['tax_amount'] ?? 0;
|
$payment_amount = $pricing['payment_amount'] ?? $invoice_data['payment_amount'] ?? 0;
|
||||||
$shipping_amount = $invoice_data['shipping_amount'] ?? 0;
|
$tax_amount = $pricing['tax_total'] ?? $invoice_data['tax_amount'] ?? 0;
|
||||||
$discount_amount = $invoice_data['discount_amount'] ?? 0;
|
$shipping_amount = $pricing['shipping_total'] ?? $invoice_data['shipping_amount'] ?? 0;
|
||||||
|
$discount_amount = $pricing['discount_total'] ?? $invoice_data['discount_amount'] ?? 0;
|
||||||
|
$subtotal_amount = $pricing['subtotal'] ?? 0;
|
||||||
$currency = 'EUR'; // Default currency
|
$currency = 'EUR'; // Default currency
|
||||||
$invoice_date = $invoice_data['invoice_created'] ?? date('Y-m-d H:i:s');
|
$invoice_date = $invoice_data['invoice_created'] ?? date('Y-m-d H:i:s');
|
||||||
|
|
||||||
@@ -5373,6 +5375,39 @@ function generateSoftwareInvoice($invoice_data, $order_id, $language = 'US') {
|
|||||||
'serial_number' => $serial_number,
|
'serial_number' => $serial_number,
|
||||||
'license_key' => $license_key
|
'license_key' => $license_key
|
||||||
];
|
];
|
||||||
|
} elseif (isset($invoice_data['products']) && is_array($invoice_data['products'])) {
|
||||||
|
// New format with products array
|
||||||
|
$pdo = dbConnect($dbname);
|
||||||
|
|
||||||
|
foreach ($invoice_data['products'] as $product) {
|
||||||
|
$product_code = $product['productcode'] ?? null;
|
||||||
|
$product_name = $product['product_name'] ?? null;
|
||||||
|
$product_options = $product['options'] ?? [];
|
||||||
|
$product_serial = $product_options['serial_number'] ?? null;
|
||||||
|
|
||||||
|
// Handle case where productcode and product_name are empty but serial_number exists
|
||||||
|
if ((empty($product_code) || $product_code === null) &&
|
||||||
|
(empty($product_name) || $product_name === null) &&
|
||||||
|
!empty($product_serial)) {
|
||||||
|
$product_code = 'License';
|
||||||
|
$product_name = 'software license for ' . $product_serial;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get license key from database
|
||||||
|
$sql = 'SELECT license_key FROM products_software_licenses WHERE transaction_id = ? LIMIT 1';
|
||||||
|
$stmt = $pdo->prepare($sql);
|
||||||
|
$stmt->execute([$order_id]);
|
||||||
|
$license_result = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
$license_key = $license_result['license_key'] ?? 'Pending';
|
||||||
|
|
||||||
|
$items[] = [
|
||||||
|
'name' => $product_name ?? 'Software Upgrade',
|
||||||
|
'quantity' => $product['quantity'] ?? 1,
|
||||||
|
'price' => $product['price'] ?? 0,
|
||||||
|
'serial_number' => $product_serial ?? 'N/A',
|
||||||
|
'license_key' => $license_key
|
||||||
|
];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load language translations
|
// Load language translations
|
||||||
@@ -5402,127 +5437,319 @@ function generateSoftwareInvoice($invoice_data, $order_id, $language = 'US') {
|
|||||||
$lbl_license_key = $translations['license_key'] ?? 'License Key';
|
$lbl_license_key = $translations['license_key'] ?? 'License Key';
|
||||||
$lbl_license_expiry = $translations['license_expiry'] ?? 'License Expiry';
|
$lbl_license_expiry = $translations['license_expiry'] ?? 'License Expiry';
|
||||||
|
|
||||||
|
// Subtotal calculation - use from pricing data or calculate from items
|
||||||
|
if ($subtotal_amount > 0) {
|
||||||
|
$subtotal = $subtotal_amount;
|
||||||
|
} else {
|
||||||
|
// Calculate from items if not provided
|
||||||
|
$subtotal = 0;
|
||||||
|
foreach ($items as $item) {
|
||||||
|
$subtotal += $item['price'] * $item['quantity'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Build HTML invoice
|
// Build HTML invoice
|
||||||
$html = '<!DOCTYPE html>
|
$html = '<!DOCTYPE html>
|
||||||
<html>
|
<html lang="' . strtolower($language) . '">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>' . htmlspecialchars($lbl_invoice) . ' - Total Safety Solutions</title>
|
||||||
<style>
|
<style>
|
||||||
body { font-family: Arial, sans-serif; font-size: 12px; color: #333; }
|
@page {margin: 220px 50px; }
|
||||||
.invoice-header { margin-bottom: 30px; }
|
|
||||||
.invoice-title { font-size: 24px; font-weight: bold; margin-bottom: 10px; }
|
body {
|
||||||
.invoice-info { margin-bottom: 20px; }
|
font-family: "DejaVu Sans", Arial, sans-serif;
|
||||||
.customer-info { margin-bottom: 20px; background: #f5f5f5; padding: 15px; }
|
color: #000;
|
||||||
table { width: 100%; border-collapse: collapse; margin-bottom: 20px; }
|
font-size: 11px;
|
||||||
th { background: #4CAF50; color: white; padding: 10px; text-align: left; }
|
line-height: 1.4;
|
||||||
td { padding: 10px; border-bottom: 1px solid #ddd; }
|
margin: 0;
|
||||||
.text-right { text-align: right; }
|
padding: 0;
|
||||||
.total-row { font-weight: bold; background: #f9f9f9; }
|
}
|
||||||
.license-info { background: #e3f2fd; padding: 15px; margin-top: 20px; border-left: 4px solid #2196F3; }
|
|
||||||
.footer { margin-top: 40px; text-align: center; font-size: 10px; color: #666; }
|
#header {
|
||||||
|
position: fixed;
|
||||||
|
left: -52px;
|
||||||
|
top: -220px;
|
||||||
|
right: -50px;
|
||||||
|
height: 200px;
|
||||||
|
text-align: center;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#header img {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#footer {
|
||||||
|
position: fixed;
|
||||||
|
left: -50px;
|
||||||
|
bottom: -250px;
|
||||||
|
right: -50px;
|
||||||
|
height: 150px;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#footer img {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.invoice-title {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #2c5f5d;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.company-header {
|
||||||
|
display: table;
|
||||||
|
width: 100%;
|
||||||
|
margin-bottom: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.company-info, .contact-details {
|
||||||
|
display: table-cell;
|
||||||
|
vertical-align: top;
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.company-info h3 {
|
||||||
|
font-weight: bold;
|
||||||
|
margin: 0 0 5px 0;
|
||||||
|
color: #2c5f5d;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.company-info p, .contact-details p {
|
||||||
|
margin: 0;
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-details {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-details h3 {
|
||||||
|
font-weight: bold;
|
||||||
|
margin: 0 0 5px 0;
|
||||||
|
color: #2c5f5d;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.invoice-details {
|
||||||
|
display: table;
|
||||||
|
width: 100%;
|
||||||
|
margin-bottom: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.invoice-left, .invoice-right {
|
||||||
|
display: table-cell;
|
||||||
|
vertical-align: top;
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.invoice-right {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-row {
|
||||||
|
margin-bottom: 2px;
|
||||||
|
display: table;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-label {
|
||||||
|
display: table-cell;
|
||||||
|
font-weight: normal;
|
||||||
|
width: 140px;
|
||||||
|
padding-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-value {
|
||||||
|
display: table-cell;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-value {
|
||||||
|
display: table-cell;
|
||||||
|
}
|
||||||
|
|
||||||
|
.items-table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
border-bottom: 1px solid #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.items-table th {
|
||||||
|
padding: 8px 6px;
|
||||||
|
font-weight: bold;
|
||||||
|
text-align: left;
|
||||||
|
font-size: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.items-table td {
|
||||||
|
padding: 6px;
|
||||||
|
border-bottom: 1px solid #999;
|
||||||
|
font-size: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.items-table .qty-col {
|
||||||
|
text-align: center;
|
||||||
|
width: 70px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.items-table .price-col, .items-table .total-col {
|
||||||
|
text-align: right;
|
||||||
|
width: 80px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.items-table th.qty-col {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.items-table th.price-col, .items-table th.total-col {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.totals-section {
|
||||||
|
float: right;
|
||||||
|
width: 250px;
|
||||||
|
margin-top: 20px;
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
|
||||||
|
.total-row {
|
||||||
|
display: table;
|
||||||
|
width: 100%;
|
||||||
|
margin-bottom: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.total-label {
|
||||||
|
display: table-cell;
|
||||||
|
text-align: left;
|
||||||
|
width: 150px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.total-amount {
|
||||||
|
display: table-cell;
|
||||||
|
text-align: right;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.final-total {
|
||||||
|
border-top: 1px solid #000;
|
||||||
|
padding-top: 5px;
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.final-total .total-amount {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="invoice-header">
|
<div id="header">
|
||||||
|
<img src="https://'.$portalURL.'/assets/images/TSS_invoice_header.png" alt="Invoice header">
|
||||||
|
</div>
|
||||||
|
<div id="footer">
|
||||||
|
<img src="https://'.$portalURL.'/assets/images/TSS_invoice_footer.png" alt="Invoice footer">
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="invoice-title">' . htmlspecialchars($lbl_invoice) . '</div>
|
<div class="invoice-title">' . htmlspecialchars($lbl_invoice) . '</div>
|
||||||
<div class="invoice-info">
|
|
||||||
<strong>' . htmlspecialchars($lbl_invoice_number) . ':</strong> ' . htmlspecialchars($order_id) . '<br>
|
<div class="company-header">
|
||||||
<strong>' . htmlspecialchars($lbl_invoice_date) . ':</strong> ' . htmlspecialchars(date('Y-m-d', strtotime($invoice_date))) . '
|
<div class="company-info">
|
||||||
|
<h3>Total Safety Solutions B.V.</h3>
|
||||||
|
<p>Laarakkerweg 8</p>
|
||||||
|
<p>5061 JR OISTERWIJK</p>
|
||||||
|
<p>Nederland</p>
|
||||||
|
</div>
|
||||||
|
<div class="contact-details">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="customer-info">
|
<div class="invoice-details">
|
||||||
<strong>' . htmlspecialchars($lbl_customer) . ':</strong><br>
|
<div class="invoice-left">
|
||||||
' . htmlspecialchars($customer_name) . '<br>';
|
<div class="detail-row">
|
||||||
|
<div class="detail-label">Invoice Date</div>
|
||||||
if ($customer_address) {
|
<div class="detail-value">: ' . htmlspecialchars(date('d-m-Y', strtotime($invoice_date))) . '</div>
|
||||||
$html .= htmlspecialchars($customer_address) . '<br>';
|
</div>
|
||||||
}
|
<div class="detail-row">
|
||||||
if ($customer_city || $customer_zip) {
|
<div class="detail-label">Invoice Number</div>
|
||||||
$html .= htmlspecialchars($customer_zip . ' ' . $customer_city) . '<br>';
|
<div class="detail-value">: ' . htmlspecialchars($order_id) . '</div>
|
||||||
}
|
</div>
|
||||||
if ($customer_state) {
|
</div>
|
||||||
$html .= htmlspecialchars($customer_state) . '<br>';
|
<div class="invoice-right">
|
||||||
}
|
<div class="detail-row">
|
||||||
if ($customer_country) {
|
<div class="detail-label">Reference</div>
|
||||||
$html .= htmlspecialchars($customer_country) . '<br>';
|
<div class="detail-value">: Online order</div>
|
||||||
}
|
</div>
|
||||||
|
<div class="detail-row">
|
||||||
$html .= htmlspecialchars($customer_email) . '
|
<div class="detail-label">Order number</div>
|
||||||
|
<div class="detail-value">: ' . htmlspecialchars($order_id) . '</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<table>
|
<table class="items-table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>' . htmlspecialchars($lbl_product) . '</th>
|
<th>Item code</th>
|
||||||
<th class="text-right">' . htmlspecialchars($lbl_quantity) . '</th>
|
<th>Description</th>
|
||||||
<th class="text-right">' . htmlspecialchars($lbl_price) . '</th>
|
<th class="qty-col">Quantity</th>
|
||||||
|
<th class="price-col">Price</th>
|
||||||
|
<th class="total-col">Total</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>';
|
<tbody>';
|
||||||
|
|
||||||
foreach ($items as $item) {
|
foreach ($items as $item) {
|
||||||
|
$line_total = $item['price'] * $item['quantity'];
|
||||||
$html .= '<tr>
|
$html .= '<tr>
|
||||||
<td>' . htmlspecialchars($item['name']) . '</td>
|
<td>SOFTWARE</td>
|
||||||
<td class="text-right">' . htmlspecialchars($item['quantity']) . '</td>
|
<td>' . htmlspecialchars($item['name']);
|
||||||
<td class="text-right">' . number_format($item['price'], 2) . ' ' . htmlspecialchars($currency) . '</td>
|
|
||||||
</tr>';
|
if ($item['serial_number'] !== 'N/A') {
|
||||||
|
$html .= '<br><small>Serial: ' . htmlspecialchars($item['serial_number']) . '</small>';
|
||||||
|
}
|
||||||
|
if ($item['license_key'] !== 'Pending') {
|
||||||
|
$html .= '<br><small>License: ' . htmlspecialchars($item['license_key']) . '</small>';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Subtotal
|
$html .= '</td>
|
||||||
$subtotal = $payment_amount - $tax_amount - $shipping_amount + $discount_amount;
|
<td class="qty-col">' . htmlspecialchars($item['quantity']) . ' </td>
|
||||||
$html .= '<tr>
|
<td class="price-col">€ ' . number_format($item['price'], 2) . '</td>
|
||||||
<td colspan="2" class="text-right"><strong>' . htmlspecialchars($lbl_subtotal) . ':</strong></td>
|
<td class="total-col">€ ' . number_format($line_total, 2) . '</td>
|
||||||
<td class="text-right">' . number_format($subtotal, 2) . ' ' . htmlspecialchars($currency) . '</td>
|
|
||||||
</tr>';
|
|
||||||
|
|
||||||
// Tax
|
|
||||||
if ($tax_amount > 0) {
|
|
||||||
$html .= '<tr>
|
|
||||||
<td colspan="2" class="text-right"><strong>' . htmlspecialchars($lbl_tax) . ':</strong></td>
|
|
||||||
<td class="text-right">' . number_format($tax_amount, 2) . ' ' . htmlspecialchars($currency) . '</td>
|
|
||||||
</tr>';
|
</tr>';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shipping
|
|
||||||
if ($shipping_amount > 0) {
|
|
||||||
$html .= '<tr>
|
|
||||||
<td colspan="2" class="text-right"><strong>' . htmlspecialchars($lbl_shipping) . ':</strong></td>
|
|
||||||
<td class="text-right">' . number_format($shipping_amount, 2) . ' ' . htmlspecialchars($currency) . '</td>
|
|
||||||
</tr>';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Discount
|
|
||||||
if ($discount_amount > 0) {
|
|
||||||
$html .= '<tr>
|
|
||||||
<td colspan="2" class="text-right"><strong>' . htmlspecialchars($lbl_discount) . ':</strong></td>
|
|
||||||
<td class="text-right">-' . number_format($discount_amount, 2) . ' ' . htmlspecialchars($currency) . '</td>
|
|
||||||
</tr>';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Total
|
|
||||||
$html .= '<tr class="total-row">
|
|
||||||
<td colspan="2" class="text-right"><strong>' . htmlspecialchars($lbl_total) . ':</strong></td>
|
|
||||||
<td class="text-right"><strong>' . number_format($payment_amount, 2) . ' ' . htmlspecialchars($currency) . '</strong></td>
|
|
||||||
</tr>';
|
|
||||||
|
|
||||||
$html .= '</tbody>
|
$html .= '</tbody>
|
||||||
</table>';
|
</table>
|
||||||
|
|
||||||
// License information
|
<div class="totals-section">
|
||||||
if ($license_key && $serial_number) {
|
<div class="total-row">
|
||||||
$html .= '<div class="license-info">
|
<div class="total-label">' . htmlspecialchars($lbl_subtotal) . '</div>
|
||||||
<strong>Software License Information:</strong><br>
|
<div class="total-amount">€ ' . number_format($subtotal, 2) . '</div>
|
||||||
<strong>' . htmlspecialchars($lbl_device_serial) . ':</strong> ' . htmlspecialchars($serial_number) . '<br>
|
</div>';
|
||||||
<strong>' . htmlspecialchars($lbl_license_key) . ':</strong> ' . htmlspecialchars($license_key) . '<br>
|
|
||||||
<strong>' . htmlspecialchars($lbl_license_expiry) . ':</strong> 2099-12-31
|
if ($tax_amount > 0) {
|
||||||
|
$html .= '<div class="total-row">
|
||||||
|
<div class="total-label">' . htmlspecialchars($lbl_tax) . '</div>
|
||||||
|
<div class="total-amount">€ ' . number_format($tax_amount, 2) . '</div>
|
||||||
|
</div>';
|
||||||
|
} else {
|
||||||
|
$html .= '<div class="total-row">
|
||||||
|
<div class="total-label">VAT</div>
|
||||||
|
<div class="total-amount">included</div>
|
||||||
</div>';
|
</div>';
|
||||||
}
|
}
|
||||||
|
|
||||||
$html .= '<div class="footer">
|
$html .= '<div class="total-row final-total">
|
||||||
Thank you for your purchase!<br>
|
<div class="total-label">' . htmlspecialchars($lbl_total) . '</div>
|
||||||
This invoice was generated automatically.
|
<div class="total-amount">€ ' . number_format($payment_amount, 2) . '</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>';
|
</html>';
|
||||||
|
|
||||||
|
|||||||
BIN
assets/images/TSS_invoice_footer.png
Normal file
BIN
assets/images/TSS_invoice_footer.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 152 KiB |
BIN
assets/images/TSS_invoice_header.png
Normal file
BIN
assets/images/TSS_invoice_header.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 190 KiB |
BIN
assets/mollie/.DS_Store
vendored
BIN
assets/mollie/.DS_Store
vendored
Binary file not shown.
BIN
assets/mollie/src/.DS_Store
vendored
BIN
assets/mollie/src/.DS_Store
vendored
Binary file not shown.
@@ -119,7 +119,10 @@ async function connectDevice() {
|
|||||||
// Log connection failure details
|
// Log connection failure details
|
||||||
await logCommunication(`Serial connection failed: ${error.message || 'Unknown error'}`, 'disconnected');
|
await logCommunication(`Serial connection failed: ${error.message || 'Unknown error'}`, 'disconnected');
|
||||||
|
|
||||||
if (openPort = 1){
|
// Check for specific "No port selected" error and show user-friendly message
|
||||||
|
if (error.message && error.message.includes('No port selected by the user')) {
|
||||||
|
progressBar("100", "No device selected, please try again", "#ff6666");
|
||||||
|
} else if (openPort = 1){
|
||||||
closePort();
|
closePort();
|
||||||
console.log("Closing port");
|
console.log("Closing port");
|
||||||
alert("System is still trying to close the serial port. If this message continues to come up please refresh this page.");
|
alert("System is still trying to close the serial port. If this message continues to come up please refresh this page.");
|
||||||
|
|||||||
@@ -161,7 +161,13 @@ async function connectDeviceForSoftware() {
|
|||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
await logCommunication(`Connection error: ${error.message}`, 'error');
|
await logCommunication(`Connection error: ${error.message}`, 'error');
|
||||||
progressBar("0", "Error: " + error.message, "#ff6666");
|
|
||||||
|
// Check for specific "No port selected" error and show user-friendly message
|
||||||
|
if (error.message && error.message.includes('No port selected by the user')) {
|
||||||
|
progressBar("100", "No device selected, please try again", "#ff6666");
|
||||||
|
} else {
|
||||||
|
progressBar("100", "Error: " + error.message, "#ff6666");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1193,14 +1199,50 @@ async function downloadAndInstallSoftware(option, customerData = null) {
|
|||||||
console.log("Click the 'Install Software' button to test if upload.js can handle the file");
|
console.log("Click the 'Install Software' button to test if upload.js can handle the file");
|
||||||
alert("DEBUG MODE: Download complete!\n\nBlob size: " + blob.size + " bytes\n\nClick the 'Install Software' button to test upload.js");
|
alert("DEBUG MODE: Download complete!\n\nBlob size: " + blob.size + " bytes\n\nClick the 'Install Software' button to test upload.js");
|
||||||
} else {
|
} else {
|
||||||
// PRODUCTION MODE: Show upload button and automatically trigger
|
// PRODUCTION MODE: Hide button and show installation in progress
|
||||||
document.getElementById("uploadSection").style.display = "block";
|
document.getElementById("uploadSection").style.display = "block";
|
||||||
const uploadBtn = document.getElementById("uploadSoftware");
|
const uploadBtn = document.getElementById("uploadSoftware");
|
||||||
uploadBtn.style.display = "block";
|
uploadBtn.style.display = "none";
|
||||||
|
|
||||||
|
// Hide device version information during installation
|
||||||
|
const softwareOptions = document.getElementById("softwareOptions");
|
||||||
|
if (softwareOptions) {
|
||||||
|
softwareOptions.style.display = "none";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create installation status indicator
|
||||||
|
const installStatus = document.createElement("div");
|
||||||
|
installStatus.id = "installationStatus";
|
||||||
|
installStatus.style.cssText = `
|
||||||
|
text-align: center;
|
||||||
|
padding: 20px;
|
||||||
|
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
|
||||||
|
border-radius: 8px;
|
||||||
|
margin: 10px 0;
|
||||||
|
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
||||||
|
`;
|
||||||
|
installStatus.innerHTML = `
|
||||||
|
<i class="fa-solid fa-spinner fa-spin" style="font-size: 32px; color: #04AA6D; margin-bottom: 10px;"></i>
|
||||||
|
<p style="margin: 0; font-size: 18px; font-weight: 600; color: #333;">Installing Software...</p>
|
||||||
|
<p style="margin: 5px 0 0 0; color: #666; font-size: 14px;">Please keep your device connected and do not close this page</p>
|
||||||
|
`;
|
||||||
|
|
||||||
|
// Insert status before the hidden upload section
|
||||||
|
document.getElementById("uploadSection").parentNode.insertBefore(installStatus, document.getElementById("uploadSection"));
|
||||||
|
|
||||||
|
progressBar("60", "Starting automatic installation...", "#04AA6D");
|
||||||
|
|
||||||
|
// Enable the upload button and automatically click it
|
||||||
|
setTimeout(() => {
|
||||||
uploadBtn.disabled = false;
|
uploadBtn.disabled = false;
|
||||||
|
|
||||||
progressBar("60", "Ready to install, starting upload...", "#04AA6D");
|
// Start monitoring for completion
|
||||||
|
if (typeof startUploadMonitoring === 'function') {
|
||||||
|
startUploadMonitoring();
|
||||||
|
}
|
||||||
|
|
||||||
uploadBtn.click();
|
uploadBtn.click();
|
||||||
|
}, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ $color_accent = '#2FAC66'; //'#ececec';
|
|||||||
// Database settings
|
// Database settings
|
||||||
//------------------------------------------
|
//------------------------------------------
|
||||||
|
|
||||||
require '/var/www/vhosts/morvalwatches.com/settings/soveliti_cloud_settings.php';
|
require '/var/www/vhosts/morvalwatches.com/settings/bewellwell_cloud_settings.php';
|
||||||
|
|
||||||
//------------------------------------------
|
//------------------------------------------
|
||||||
// Menusetup & settings
|
// Menusetup & settings
|
||||||
|
|||||||
102
custom/morvalwatches/mail/email_template_new.php
Normal file
102
custom/morvalwatches/mail/email_template_new.php
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
<?php
|
||||||
|
defined($security_key) or exit;
|
||||||
|
//------------------------------------------
|
||||||
|
// Content Reset Email
|
||||||
|
//------------------------------------------
|
||||||
|
$newuser_subject = 'SoVeLiTi account created';
|
||||||
|
$newuser_header = 'Dear user';
|
||||||
|
|
||||||
|
$newuser_text = 'Your administrator has provided access to SoVeLiTi.';
|
||||||
|
$newuser_credential_text_1 = 'Your account has been created with username ';
|
||||||
|
$newuser_credential_text_2 = 'Please click the button below to complete your registration.';
|
||||||
|
|
||||||
|
$newuser_closure = 'For security reasons this link is only active for 10 minutes.';
|
||||||
|
|
||||||
|
//------------------------------------------
|
||||||
|
// Content Reset Email
|
||||||
|
//------------------------------------------
|
||||||
|
$subject = $newuser_subject;
|
||||||
|
|
||||||
|
$message = '
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>' . $subject . '</title>
|
||||||
|
<style>
|
||||||
|
@media screen and (max-width: 600px) {
|
||||||
|
.content {
|
||||||
|
width: 100% !important;
|
||||||
|
display: block !important;
|
||||||
|
padding: 10px !important;
|
||||||
|
}
|
||||||
|
.header, .body, .footer {
|
||||||
|
padding: 20px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body style="font-family: Arial, sans-serif">
|
||||||
|
<table width="100%" border="0" cellspacing="0" cellpadding="0">
|
||||||
|
<tr>
|
||||||
|
<td align="center" style="padding: 20px;">
|
||||||
|
<table class="content" width="600" border="0" cellspacing="0" cellpadding="0" style="border-collapse: collapse; border: 1px solid #cccccc;">
|
||||||
|
<!-- Header -->
|
||||||
|
<tr>
|
||||||
|
<td class="header" style="background-color:'.color.'; padding: 40px; text-align: center; color: white; font-size: 24px;">
|
||||||
|
'.site_name.'
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<!-- Body -->
|
||||||
|
<tr>
|
||||||
|
<td class="body" style="padding: 40px; text-align: left; font-size: 16px; line-height: 1.6;">
|
||||||
|
' . $newuser_header . ',
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
'.$newuser_text.' '.$newuser_credential_text_1.'<b>'.$post_content['username'].'</b>
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
'.$newuser_credential_text_2.'
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<!-- Call to action Button -->
|
||||||
|
<tr>
|
||||||
|
<td style="padding: 0px 40px 0px 40px; text-align: center;">
|
||||||
|
<!-- CTA Button -->
|
||||||
|
<table cellspacing="0" cellpadding="0" style="margin: auto;">
|
||||||
|
<tr>
|
||||||
|
<td align="center" style="background-color: '.color_accent.'; padding: 10px 20px; border-radius: 5px;">
|
||||||
|
<a href="https://' . $portalURL . '/reset.php?resetkey='.$resetkey.'" target="_blank" style="color: #ffffff; text-decoration: none; font-weight: bold;">Reset Password</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="body" style="padding: 40px; text-align: left; font-size: 16px; line-height: 1.6;">
|
||||||
|
' . $newuser_closure . '
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
Kind regards,
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
Service team
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<!-- Footer -->
|
||||||
|
<tr>
|
||||||
|
<td class="footer" style="background: url(\'https://'.$portalURL.emaillogo.'\');background-position: center center;background-repeat:no-repeat;background-size:contain;background-color: '.color.'; padding: 40px;">
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
';
|
||||||
99
custom/morvalwatches/mail/email_template_reset.php
Normal file
99
custom/morvalwatches/mail/email_template_reset.php
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
<?php
|
||||||
|
defined($security_key) or exit;
|
||||||
|
//------------------------------------------
|
||||||
|
// Content Reset Email
|
||||||
|
//------------------------------------------
|
||||||
|
$changeuser_subject = 'SoVeLiTi - password reset requested';
|
||||||
|
$changeuser_header = 'Dear user';
|
||||||
|
$changeuser_text = 'A password reset has been requested for your account.';
|
||||||
|
$changeuser_credential_text_1 = 'Please click the button below to reset the password of your SoVeLiTi account.';
|
||||||
|
$changeuser_closure = 'For security reasons this link is only active for 10 minutes.';
|
||||||
|
|
||||||
|
//------------------------------------------
|
||||||
|
// Content Reset Email
|
||||||
|
//------------------------------------------
|
||||||
|
$subject = $changeuser_subject;
|
||||||
|
|
||||||
|
$message = '
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>' . $subject . '</title>
|
||||||
|
<style>
|
||||||
|
@media screen and (max-width: 600px) {
|
||||||
|
.content {
|
||||||
|
width: 100% !important;
|
||||||
|
display: block !important;
|
||||||
|
padding: 10px !important;
|
||||||
|
}
|
||||||
|
.header, .body, .footer {
|
||||||
|
padding: 20px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body style="font-family: Arial, sans-serif">
|
||||||
|
<table width="100%" border="0" cellspacing="0" cellpadding="0">
|
||||||
|
<tr>
|
||||||
|
<td align="center" style="padding: 20px;">
|
||||||
|
<table class="content" width="600" border="0" cellspacing="0" cellpadding="0" style="border-collapse: collapse; border: 1px solid #cccccc;">
|
||||||
|
<!-- Header -->
|
||||||
|
<tr>
|
||||||
|
<td class="header" style="background-color:'.color.'; padding: 40px; text-align: center; color: white; font-size: 24px;">
|
||||||
|
'.site_title.'
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<!-- Body -->
|
||||||
|
<tr>
|
||||||
|
<td class="body" style="padding: 40px; text-align: left; font-size: 16px; line-height: 1.6;">
|
||||||
|
' . $changeuser_header . ',
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
'.$changeuser_text.'
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
'.$changeuser_credential_text_1 .'
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<!-- Call to action Button -->
|
||||||
|
<tr>
|
||||||
|
<td style="padding: 0px 40px 0px 40px; text-align: center;">
|
||||||
|
<!-- CTA Button -->
|
||||||
|
<table cellspacing="0" cellpadding="0" style="margin: auto;">
|
||||||
|
<tr>
|
||||||
|
<td align="center" style="background-color: '.color_accent.'; padding: 10px 20px; border-radius: 5px;">
|
||||||
|
<a href="https://' . $portalURL . '/reset.php?resetkey='.$resetkey.'" target="_blank" style="color: #ffffff; text-decoration: none; font-weight: bold;">Reset Password</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="body" style="padding: 40px; text-align: left; font-size: 16px; line-height: 1.6;">
|
||||||
|
' . $changeuser_closure . '
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
Kind regards,
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
Service team
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<!-- Footer -->
|
||||||
|
<tr>
|
||||||
|
<td class="footer" style="background: url(\'https://'.$portalURL.emaillogo.'\');background-position: center center;background-repeat:no-repeat;background-size:contain;background-color: '.color.'; padding: 40px;">
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
';
|
||||||
55
custom/morvalwatches/settings/morvalwatches_config.php
Normal file
55
custom/morvalwatches/settings/morvalwatches_config.php
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
<?php
|
||||||
|
require 'settingsprofiles.php';
|
||||||
|
|
||||||
|
// This will change the title on the website
|
||||||
|
define('site_name','');
|
||||||
|
define('site_name_footer','SoVeLiTi Cloud');
|
||||||
|
// This will change the title on browser TAB
|
||||||
|
define('site_title','SoVeLiTi');
|
||||||
|
//Scriptversion
|
||||||
|
define('script_version','v1');
|
||||||
|
//Enable VeLiTi-issue mgt
|
||||||
|
define('veliti_cim',true);
|
||||||
|
//Enable VeLiTi-analytics
|
||||||
|
define('veliti_analytics',false);
|
||||||
|
//Rewrite rule
|
||||||
|
define('rewrite_url',true);
|
||||||
|
define('news','');
|
||||||
|
//maintenance_mode
|
||||||
|
define('maintenance_mode_communication',false);
|
||||||
|
define('maintenance_mode_notification','Notice: Portal not accessible due to maintenance on May 15th between 12.00 - 13.00 CET.');
|
||||||
|
define('maintenance_mode',false);
|
||||||
|
define('maintenance_mode_text','System in maintenance');
|
||||||
|
define('debug',true);
|
||||||
|
define('debug_id','1');
|
||||||
|
|
||||||
|
/*Security*/
|
||||||
|
// Page security
|
||||||
|
define('page_security_key','secure_admin_342642');
|
||||||
|
define('cronjob_number','25');
|
||||||
|
define('header_security',false);
|
||||||
|
|
||||||
|
/* Email */
|
||||||
|
// The from email that will appear on the customer's order details email
|
||||||
|
define('mail_from','SoVeLiTi');
|
||||||
|
// Your email
|
||||||
|
define('email','CustomerPortal@veliti.nl');
|
||||||
|
//Additional phpmailer-settings
|
||||||
|
define('email_host_name','veliti.nl');
|
||||||
|
define('email_reply_to','info@gewoonlekkerspaans.nl');
|
||||||
|
define('email_outgoing_pw','306yc%X5f');
|
||||||
|
define('email_outgoing_port','587');
|
||||||
|
define('email_outgoing_security','ssl');
|
||||||
|
|
||||||
|
/*Appearance*/
|
||||||
|
//Icon
|
||||||
|
define('icon_image','/custom/soveliti/style/VeLiTi-Logo2.png');
|
||||||
|
define('color','#527ee5');
|
||||||
|
define('color_accent','#527ee5');
|
||||||
|
define('emaillogo','/custom/soveliti/style/SoVeLiTi.png');
|
||||||
|
|
||||||
|
/*Default Users*/
|
||||||
|
define('software_update_user','EMP-updater');
|
||||||
|
define('software_update_pw','EMP-updater');
|
||||||
|
define('interface_user','interface@test.nl');
|
||||||
|
define('interface_pw','test1234');
|
||||||
112
custom/morvalwatches/settings/morvalwatches_settings.php
Normal file
112
custom/morvalwatches/settings/morvalwatches_settings.php
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
<?php
|
||||||
|
//------------------------------------------
|
||||||
|
//EXCEPTION LIST
|
||||||
|
//------------------------------------------
|
||||||
|
$serialnumber_exceptions = array("22050695","22110095");
|
||||||
|
|
||||||
|
//------------------------------------------
|
||||||
|
// Security
|
||||||
|
//------------------------------------------
|
||||||
|
$security_key = 'secure_34563$52';
|
||||||
|
|
||||||
|
//------------------------------------------
|
||||||
|
// Base color
|
||||||
|
//------------------------------------------
|
||||||
|
$color = '#005655';//'#0b1054';
|
||||||
|
$color_accent = '#2FAC66'; //'#ececec';
|
||||||
|
|
||||||
|
//------------------------------------------
|
||||||
|
// Database settings
|
||||||
|
//------------------------------------------
|
||||||
|
|
||||||
|
require '/var/www/vhosts/veliti.nl/settings/morvalwatches_cloud_settings.php';
|
||||||
|
|
||||||
|
//------------------------------------------
|
||||||
|
// Menusetup & settings
|
||||||
|
//------------------------------------------
|
||||||
|
require 'settingsmenu.php';
|
||||||
|
|
||||||
|
//------------------------------------------
|
||||||
|
// API BaseUrl
|
||||||
|
//------------------------------------------
|
||||||
|
$baseurl = 'https://'.$_SERVER['SERVER_NAME'].'/api.php'; //URL of API
|
||||||
|
$portalURL = $_SERVER['SERVER_NAME'];
|
||||||
|
|
||||||
|
//------------------------------------------
|
||||||
|
// Equipmentdetails
|
||||||
|
//------------------------------------------
|
||||||
|
$servicedate = date("Y-m-d", strtotime("-365 days"));
|
||||||
|
$warrantydate = date("Y-m-d", strtotime("-365 days"));
|
||||||
|
$warranty_extended = date("Y-m-d", strtotime("+365 days"));
|
||||||
|
$date = date('Y-m-d H:i:s');
|
||||||
|
|
||||||
|
$curYear = date("Y", time());
|
||||||
|
$curMonth = date("m", time());
|
||||||
|
$curQuarter = (int)ceil($curMonth / 3);
|
||||||
|
$curdateObj = DateTime::createFromFormat('!m', $curMonth);
|
||||||
|
$curMonth_name = $curdateObj->format('F');
|
||||||
|
|
||||||
|
//------------------------------------------
|
||||||
|
//History Type
|
||||||
|
//------------------------------------------
|
||||||
|
$type1 = 'General';
|
||||||
|
$type2 = 'Customer';
|
||||||
|
$type3 = 'Service';
|
||||||
|
$type4 = 'Testing';
|
||||||
|
$type5 = 'Data';
|
||||||
|
$type6 = 'Other';
|
||||||
|
$type7 = 'Internal';
|
||||||
|
$type8 = 'Ignore';
|
||||||
|
$type9 = 'Warranty';
|
||||||
|
$type10 = 'Contract';
|
||||||
|
$type11 = 'Warranty-Expired';
|
||||||
|
$type12 = 'Contract-Expired';
|
||||||
|
$type13 = "Order";
|
||||||
|
$type14 = "ServiceReport";
|
||||||
|
$type15 = "SRIncluded";
|
||||||
|
$type16 = "Notes";
|
||||||
|
$type17 = "Visual";
|
||||||
|
|
||||||
|
$HistoryType_1 = 'Bootloader';
|
||||||
|
$HistoryType_2 = 'Firmware';
|
||||||
|
$HistoryType_3 = 'SerialNumber';
|
||||||
|
$HistoryType_4 = 'Visual_Test';
|
||||||
|
$HistoryType_5 = 'Maintenance_Test';
|
||||||
|
$HistoryType_6 = 'Assembly_Test';
|
||||||
|
$HistoryType_7 = 'ProductNumber';
|
||||||
|
$HistoryType_8 = 'Visual';
|
||||||
|
$HistoryType_9 = 'ServiceReport';
|
||||||
|
//------------------------------------------
|
||||||
|
//Permissions CRUD
|
||||||
|
//------------------------------------------
|
||||||
|
$permission_4 = 'CRUD'; //Admin+
|
||||||
|
$permission_3 = 'CRUD'; //Admin
|
||||||
|
$permission_2 = 'CRU'; //SuperUser
|
||||||
|
$permission_1 = 'CRU'; //CreateUpdate
|
||||||
|
$permission_0 = 'R'; //Readonly
|
||||||
|
|
||||||
|
$permissionlabel1 = 'Permission';
|
||||||
|
$permission1 = 'Superuser'; #1
|
||||||
|
$permission2 = 'Create & Update'; #2
|
||||||
|
$permission3 = 'read-only'; // #3
|
||||||
|
$permission4 = 'Admin'; //#4
|
||||||
|
$permission5 = 'Admin+'; // #5
|
||||||
|
|
||||||
|
$settingslabel1 = 'profile';
|
||||||
|
$setting1 = 'firmware'; //Fix
|
||||||
|
$setting2 = 'service';
|
||||||
|
$setting3 = 'build'; //Fix
|
||||||
|
$setting4 = 'distribution';
|
||||||
|
$setting5 = '';
|
||||||
|
$setting6 = '';
|
||||||
|
$setting7 = ''; //Fix
|
||||||
|
$setting8 = 'interface';
|
||||||
|
|
||||||
|
//------------------------------------------
|
||||||
|
//Partners
|
||||||
|
//------------------------------------------
|
||||||
|
$partnertype1 = 'SalesID';
|
||||||
|
$partnertype2 = 'SoldTo';
|
||||||
|
$partnertype3 = 'ShipTo';
|
||||||
|
$partnertype4 = 'Location';
|
||||||
|
$partnertype5 = 'Section';
|
||||||
365
custom/morvalwatches/settings/settingsmenu.php
Normal file
365
custom/morvalwatches/settings/settingsmenu.php
Normal file
@@ -0,0 +1,365 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
//------------------------------------------
|
||||||
|
// Menusetup and settings
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Each Menu name in urls array requires reference
|
||||||
|
// into translation files and corresponding profile
|
||||||
|
//------------------------------------------
|
||||||
|
$main_menu = [
|
||||||
|
"dashboard" => [
|
||||||
|
"main_menu" => [
|
||||||
|
"url" => "dashboard",
|
||||||
|
"selected" => "dashboard",
|
||||||
|
"icon" => "fas fa-tachometer-alt",
|
||||||
|
"name" => "menu_dashboard"
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"sales" => [
|
||||||
|
"main_menu" => [
|
||||||
|
"url" => "contracts",
|
||||||
|
"selected" => "contracts",
|
||||||
|
"icon" => "fa-solid fa-bars",
|
||||||
|
"name" => "menu_sales"
|
||||||
|
],
|
||||||
|
"accounts" => [
|
||||||
|
"url" => "accounts",
|
||||||
|
"selected" => "accounts",
|
||||||
|
"icon" => "fas fa-tachometer-alt",
|
||||||
|
"name" => "menu_sales_accounts"
|
||||||
|
],
|
||||||
|
"catalog" => [
|
||||||
|
"url" => "catalog",
|
||||||
|
"selected" => "catalog",
|
||||||
|
"icon" => "fa-solid fa-photo-film",
|
||||||
|
"name" => "menu_catalog"
|
||||||
|
],
|
||||||
|
"contracts" => [
|
||||||
|
"url" => "contracts",
|
||||||
|
"selected" => "contracts",
|
||||||
|
"icon" => "fas fa-tachometer-alt",
|
||||||
|
"name" => "menu_sales_contracts"
|
||||||
|
],
|
||||||
|
"orders" => [
|
||||||
|
"url" => "orders",
|
||||||
|
"selected" => "orders",
|
||||||
|
"icon" => "fas fa-tachometer-alt",
|
||||||
|
"name" => "menu_sales_orders"
|
||||||
|
],
|
||||||
|
"identity" => [
|
||||||
|
"url" => "identity",
|
||||||
|
"selected" => "identity",
|
||||||
|
"icon" => "fas fa-tachometer-alt",
|
||||||
|
"name" => "menu_identity"
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"dealers" => [
|
||||||
|
"main_menu" => [
|
||||||
|
"url" => "dealers",
|
||||||
|
"selected" => "dealers",
|
||||||
|
"icon" => "fas fa-tachometer-alt",
|
||||||
|
"name" => "menu_dealers"
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"buildtool" => [
|
||||||
|
"main_menu" => [
|
||||||
|
"url" => "buildtool",
|
||||||
|
"selected" => "buildtool",
|
||||||
|
"icon" => "fas fa-tachometer-alt",
|
||||||
|
"name" => "menu_build"
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"cartests" => [
|
||||||
|
"main_menu" => [
|
||||||
|
"url" => "cartests",
|
||||||
|
"selected" => "cartests",
|
||||||
|
"icon" => "fa-solid fa-car",
|
||||||
|
"name" => "menu_cartest"
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"marketing" => [
|
||||||
|
"main_menu" => [
|
||||||
|
"url" => "marketing&product_group=Emergency_Plug&product_content=Images",
|
||||||
|
"selected" => "marketing",
|
||||||
|
"icon" => "fas fa-tachometer-alt",
|
||||||
|
"name" => "menu_marketing"
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"equipments" => [
|
||||||
|
"main_menu" => [
|
||||||
|
"url" => "equipments",
|
||||||
|
"selected" => "assets",
|
||||||
|
"icon" => "fa-solid fa-database",
|
||||||
|
"name" => "menu_assets"
|
||||||
|
],
|
||||||
|
"equipments" =>[
|
||||||
|
"url" => "equipments",
|
||||||
|
"selected" => "assets",
|
||||||
|
"icon" => "fa-solid fa-database",
|
||||||
|
"name" => "menu_assets"
|
||||||
|
],
|
||||||
|
"servicereports" => [
|
||||||
|
"url" => "servicereports",
|
||||||
|
"selected" => "servicereports",
|
||||||
|
"icon" => "fas fa-tachometer-alt",
|
||||||
|
"name" => "menu_service_reports"
|
||||||
|
],
|
||||||
|
"rmas" => [
|
||||||
|
"url" => "rmas",
|
||||||
|
"selected" => "rmas",
|
||||||
|
"icon" => "fas fa-tachometer-alt",
|
||||||
|
"name" => "menu_rmas"
|
||||||
|
],
|
||||||
|
"histories" => [
|
||||||
|
"url" => "histories",
|
||||||
|
"selected" => "histories",
|
||||||
|
"icon" => "fas fa-tachometer-alt",
|
||||||
|
"name" => "menu_history"
|
||||||
|
],
|
||||||
|
"firmwaretool" => [
|
||||||
|
"url" => "firmwaretool",
|
||||||
|
"selected" => "firmwaretool",
|
||||||
|
"icon" => "fas fa-tachometer-alt",
|
||||||
|
"name" => "menu_firmwaretool"
|
||||||
|
] ,
|
||||||
|
"equipments_mass_update" => [
|
||||||
|
"url" => "equipments_mass_update",
|
||||||
|
"selected" => "equipments_mass_update",
|
||||||
|
"icon" => "fas fa-tachometer-alt",
|
||||||
|
"name" => "menu_equipments_mass_update"
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"products" => [
|
||||||
|
"main_menu" => [
|
||||||
|
"url" => "products&status=1",
|
||||||
|
"selected" => "products",
|
||||||
|
"icon" => "fas fa-box-open",
|
||||||
|
"name" => "menu_products"
|
||||||
|
],
|
||||||
|
"products" => [
|
||||||
|
"url" => "products&status=1",
|
||||||
|
"selected" => "products",
|
||||||
|
"icon" => "fas fa-box-open",
|
||||||
|
"name" => "menu_products"
|
||||||
|
],
|
||||||
|
"products_software" => [
|
||||||
|
"url" => "products_software_versions",
|
||||||
|
"selected" => "products_software_versions",
|
||||||
|
"icon" => "fas fa-box-open",
|
||||||
|
"name" => "menu_products_software_versions"
|
||||||
|
],
|
||||||
|
"products_attributes" => [
|
||||||
|
"url" => "products_attributes",
|
||||||
|
"selected" => "products_attributes",
|
||||||
|
"icon" => "fas fa-box-open",
|
||||||
|
"name" => "menu_products_attributes"
|
||||||
|
],
|
||||||
|
"pricelists" => [
|
||||||
|
"url" => "pricelists",
|
||||||
|
"selected" => "pricelists",
|
||||||
|
"icon" => "fa-solid fa-coins",
|
||||||
|
"name" => "menu_pricelists"
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"reporting" => [
|
||||||
|
"main_menu" => [
|
||||||
|
"url" => "report_build",
|
||||||
|
"selected" => "report_build",
|
||||||
|
"icon" => "fa-solid fa-magnifying-glass-chart",
|
||||||
|
"name" => "menu_report_main"
|
||||||
|
],
|
||||||
|
"report_build" => [
|
||||||
|
"url" => "report_build",
|
||||||
|
"selected" => "report_build",
|
||||||
|
"icon" => "fa-solid fa-magnifying-glass-chart",
|
||||||
|
"name" => "menu_report_build"
|
||||||
|
],
|
||||||
|
"report_contracts_billing" => [
|
||||||
|
"url" => "report_contracts_billing",
|
||||||
|
"selected" => "report_contracts_billing",
|
||||||
|
"icon" => "fa-solid fa-magnifying-glass-chart",
|
||||||
|
"name" => "menu_report_contracts_billing"
|
||||||
|
],
|
||||||
|
"report_healthindex" => [
|
||||||
|
"url" => "report_healthindex",
|
||||||
|
"selected" => "report_healthindex",
|
||||||
|
"icon" => "fa-solid fa-magnifying-glass-chart",
|
||||||
|
"name" => "menu_report_healthindex"
|
||||||
|
],
|
||||||
|
"report_usage" => [
|
||||||
|
"url" => "report_usage",
|
||||||
|
"selected" => "report_usage",
|
||||||
|
"icon" => "fa-solid fa-magnifying-glass-chart",
|
||||||
|
"name" => "menu_report_usage"
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"admin" =>[
|
||||||
|
"main_menu" => [
|
||||||
|
"url" => "partners",
|
||||||
|
"selected" => "partners",
|
||||||
|
"icon" => "fa-solid fa-bars",
|
||||||
|
"name" => "menu_admin"
|
||||||
|
],
|
||||||
|
"partners" => [
|
||||||
|
"url" => "partners",
|
||||||
|
"selected" => "partners",
|
||||||
|
"icon" => "fa-solid fa-bars",
|
||||||
|
"name" => "menu_admin_partners"
|
||||||
|
],
|
||||||
|
"users" => [
|
||||||
|
"url" => "users",
|
||||||
|
"selected" => "users",
|
||||||
|
"icon" => "fas fa-tachometer-alt",
|
||||||
|
"name" => "menu_admin_users"
|
||||||
|
],
|
||||||
|
"communications" => [
|
||||||
|
"url" => "communications",
|
||||||
|
"selected" => "communications",
|
||||||
|
"icon" => "fas fa-tachometer-alt",
|
||||||
|
"name" => "menu_admin_communications"
|
||||||
|
],
|
||||||
|
"media" => [
|
||||||
|
"url" => "media",
|
||||||
|
"selected" => "media",
|
||||||
|
"icon" => "fa-solid fa-photo-film",
|
||||||
|
"name" => "menu_media"
|
||||||
|
],
|
||||||
|
"categories" => [
|
||||||
|
"url" => "categories",
|
||||||
|
"selected" => "categories",
|
||||||
|
"icon" => "fa-solid fa-photo-film",
|
||||||
|
"name" => "menu_categories"
|
||||||
|
],
|
||||||
|
"discounts" => [
|
||||||
|
"url" => "discounts",
|
||||||
|
"selected" => "discounts",
|
||||||
|
"icon" => "fa-solid fa-photo-film",
|
||||||
|
"name" => "menu_discounts"
|
||||||
|
],
|
||||||
|
"shipping" => [
|
||||||
|
"url" => "shipping",
|
||||||
|
"selected" => "shipping",
|
||||||
|
"icon" => "fa-solid fa-truck-fast",
|
||||||
|
"name" => "menu_shipping"
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"settings" => [
|
||||||
|
"main_menu" => [
|
||||||
|
"url" => "settings",
|
||||||
|
"selected" => "settings",
|
||||||
|
"icon" => "fas fa-tools",
|
||||||
|
"name" => "menu_settings"
|
||||||
|
],
|
||||||
|
"config" => [
|
||||||
|
"url" => "settings",
|
||||||
|
"selected" => "settings",
|
||||||
|
"icon" => "fas fa-tools",
|
||||||
|
"name" => "menu_config"
|
||||||
|
],
|
||||||
|
"translations" => [
|
||||||
|
"url" => "translations",
|
||||||
|
"selected" => "translations",
|
||||||
|
"icon" => "fas fa-tachometer-alt",
|
||||||
|
"name" => "menu_translations"
|
||||||
|
],
|
||||||
|
"uploader" => [
|
||||||
|
"url" => "uploader",
|
||||||
|
"selected" => "uploader",
|
||||||
|
"icon" => "fas fa-tachometer-alt",
|
||||||
|
"name" => "menu_uploader"
|
||||||
|
],
|
||||||
|
"logfile" => [
|
||||||
|
"url" => "logfile",
|
||||||
|
"selected" => "logfile",
|
||||||
|
"icon" => "fas fa-tachometer-alt",
|
||||||
|
"name" => "menu_logfile"
|
||||||
|
],
|
||||||
|
"maintenance" => [
|
||||||
|
"url" => "maintenance",
|
||||||
|
"selected" => "maintenance",
|
||||||
|
"icon" => "fas fa-tachometer-alt",
|
||||||
|
"name" => "menu_maintenance"
|
||||||
|
],
|
||||||
|
"profiles" => [
|
||||||
|
"url" => "profiles",
|
||||||
|
"selected" => "profiles",
|
||||||
|
"icon" => "fas fa-tachometer-alt",
|
||||||
|
"name" => "menu_profiles"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
$routes = array(
|
||||||
|
'/' => 'equipments.php',
|
||||||
|
'equipments' => 'equipments.php',
|
||||||
|
'products' => 'products.php',
|
||||||
|
'logout' => 'logout.php'
|
||||||
|
);
|
||||||
|
|
||||||
|
//------------------------------------------
|
||||||
|
// Paging
|
||||||
|
//------------------------------------------
|
||||||
|
$page_rows_equipment = 25; //list Equipment
|
||||||
|
$page_rows_history = 15; //list History
|
||||||
|
$page_rows_products = 25;//list producst
|
||||||
|
$page_rows_users = 15;//list users
|
||||||
|
$page_rows_partners = 15;//list partners
|
||||||
|
$page_rows_communication = 25; //list communications
|
||||||
|
$page_rows_accounts = 25 ;// list accounts
|
||||||
|
$page_rows_contracts = 25 ;// list contracts
|
||||||
|
$page_rows_cartest = 25 ;// list contracts
|
||||||
|
$page_rows_equipment_servicereporst = 5 ;// Number of service reports on equipment
|
||||||
|
$page_rows_changelog = 50 ;// Number of changelogs returned
|
||||||
|
$page_rows_rma = 25; // list RMA
|
||||||
|
$page_rows_translations = 50; //list translation variables
|
||||||
|
$page_rows_products_attributes = 50; //list product attributes
|
||||||
|
$page_rows_media = 25; // list media
|
||||||
|
$page_rows_pricelists = 50;//pricelists
|
||||||
|
$page_rows_categories = 25;//categories
|
||||||
|
$page_rows_discounts = 25;//discounts
|
||||||
|
$page_rows_shipping = 25;//discounts
|
||||||
|
$page_rows_transactions = 25; //transactions
|
||||||
|
$page_rows_invoice = 25; //invoices
|
||||||
|
$page_rows_dealers = 25; //dealers
|
||||||
|
$page_rows_software_versions = 50; //software versions
|
||||||
|
|
||||||
|
//------------------------------------------
|
||||||
|
// Languages supported
|
||||||
|
//------------------------------------------
|
||||||
|
$supportedLanguages = ['US', 'NL', 'DE', 'ES','PT'];
|
||||||
|
|
||||||
|
//------------------------------------------
|
||||||
|
// Pricing
|
||||||
|
//------------------------------------------
|
||||||
|
$supportedCurrencies = ["0" =>"euro", "1"=>"dollar"];
|
||||||
|
|
||||||
|
$supportedModifiers = ["0" =>"subtract", "1"=>"add"];
|
||||||
|
|
||||||
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
// All individual views and APIs - Profile ++++++++++++++
|
||||||
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
$all_profiles = [
|
||||||
|
"build",
|
||||||
|
"commerce",
|
||||||
|
"distribution",
|
||||||
|
"firmware",
|
||||||
|
"garage",
|
||||||
|
"interface",
|
||||||
|
"service",
|
||||||
|
"other"
|
||||||
|
];
|
||||||
|
|
||||||
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
// Marketing +++++++++++++++++++++++++++++++++++++
|
||||||
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
|
||||||
|
$main_marketing_dir = './marketing/';
|
||||||
|
|
||||||
|
$marketing_structure = array(
|
||||||
|
"Emergency_Plug" => array(
|
||||||
|
"Documents",
|
||||||
|
"Images",
|
||||||
|
"Video"
|
||||||
|
)
|
||||||
|
);
|
||||||
27
custom/morvalwatches/settings/settingsprofiles.php
Normal file
27
custom/morvalwatches/settings/settingsprofiles.php
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
/*Standard*/
|
||||||
|
define('standard_profile','dashboard,profile,equipments,equipment,histories,history,firmwaretool,products_software,servicereports,servicereport,application');
|
||||||
|
/*Superuser*/
|
||||||
|
define('superuser_profile','dashboard,profile,assets,equipments,equipment,equipment_manage,equipment_manage_edit,equipments_mass_update,histories,history,history_manage,firmwaretool,products,products_versions,products_software,product,product_manage,servicereports,servicereport,admin,partners,partner,users,user,user_manage,marketing,application');
|
||||||
|
/*Admin*/
|
||||||
|
define('admin_profile','dashboard,profile,buildtool,sales,accounts,account,contracts,contract,contract_manage,cartests,cartest,cartest_manage,assets,equipments,equipment,equipment_healthindex,equipment_data,equipment_manage,equipment_manage_edit,equipments_mass_update,histories,history,history_manage,firmwaretool,rmas,rma,rma_manage,rma_history,rma_history_manage,buildtool,products,products_versions,products_software,product,product_manage,servicereports,servicereport,admin,partners,partner,users,user,user_manage,communications,communication,communication_send,marketing,reporting,report_build,report_contracts_billing,report_healthindex,changelog,application');
|
||||||
|
/*AdminPlus*/
|
||||||
|
define('adminplus_profile','dashboard,profile,buildtool,sales,accounts,account,contracts,contract,contract_manage,billing,cartests,cartest,cartest_manage,assets,equipments,equipment,equipment_healthindex,equipment_data,equipment_manage,equipment_manage_edit,equipments_mass_update,histories,history,history_manage,firmwaretool,rmas,rma,rma_manage,rma_history,rma_history_manage,buildtool,products,products_versions,products_software,products_attributes,products_attributes_items,products_attributes_manage,products_configurations,products_categories,products_media,product,product_manage,pricelists,pricelists_items,pricelists_manage,catalog,categories,category,discounts,discount,shipping,shipping_manage,servicereports,servicereport,admin,partners,partner,users,user,user_manage,communications,communication,communication_send,marketing,reporting,report_build,report_contracts_billing,report_healthindex,report_usage,config,settings,logfile,changelog,language,translations,translations_details,translation_manage,media,media_manage,application,maintenance,uploader,profiles,vin,shopping_cart,checkout,placeorder,taxes,transactions,transactions_items,invoice,order,orders,identity');
|
||||||
|
/*Build*/
|
||||||
|
define('build','dashboard,profile,buildtool,firmwaretool,buildtool,products_software,application');
|
||||||
|
/*Commerce*/
|
||||||
|
define('commerce','dashboard,profile,products,products_versions,products_software,products_attributes,products_attributes_items,products_attributes_manage,products_configurations,products_categories,products_media,product,product_manage,pricelists,pricelists_items,pricelists_manage,catalog,categories,category,discounts,discount,shipping,shipping_manage,admin,partners,partner,users,user,user_manage,translations,translations_details,translation_manage,media,media_manage,application,uploader,shopping_cart,checkout,placeorder,taxes,transactions,transactions_items,invoice,order,orders,identity');
|
||||||
|
/*Distribution*/
|
||||||
|
define('distribution','dashboard,profile,assets,equipments,equipment,equipment_manage,equipment_manage_edit,equipments_mass_update,histories,history,history_manage,firmwaretool,products,products_versions,products_software,product,product_manage,servicereports,servicereport,admin,partners,partner,users,user,user_manage,marketing,application');
|
||||||
|
/*Firmware*/
|
||||||
|
define('firmware','firmwaretool,products_software,application');
|
||||||
|
/*Garage*/
|
||||||
|
define('garage','dashboard,profile,cartests,cartest,cartest_manage,products_versions,application');
|
||||||
|
/*Interface*/
|
||||||
|
define('interface','contracts,contract,equipments,equipment_manage,firmwaretool,products_versions,products_software,users,application');
|
||||||
|
/*Service*/
|
||||||
|
define('service','dashboard,profile,assets,equipments,equipment,equipment_manage,histories,history,history_manage,firmwaretool,products_software,servicereports,servicereport,admin,partners,partner,users,user,user_manage,marketing,application');
|
||||||
|
/*Other*/
|
||||||
|
define('other','dashboard,profile,assets,equipments,equipment,equipment_manage,histories,history,history_manage,firmwaretool,products_software,servicereports,servicereport,admin,partners,partner,marketing,application');
|
||||||
|
|
||||||
|
?>
|
||||||
BIN
custom/morvalwatches/style/SoVeLiTi.png
Normal file
BIN
custom/morvalwatches/style/SoVeLiTi.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
BIN
custom/morvalwatches/style/VeLiTi-Logo2.png
Executable file
BIN
custom/morvalwatches/style/VeLiTi-Logo2.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 2.7 KiB |
BIN
custom/morvalwatches/style/VeLiTi.png
Normal file
BIN
custom/morvalwatches/style/VeLiTi.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.7 KiB |
231
custom/morvalwatches/style/morvalwatches_login.css
Normal file
231
custom/morvalwatches/style/morvalwatches_login.css
Normal file
@@ -0,0 +1,231 @@
|
|||||||
|
:root {
|
||||||
|
--color-white: #FFFFFF;
|
||||||
|
--color-light-blue: #344fd5c2;
|
||||||
|
--color-blue: #0b1054;
|
||||||
|
--color-red: #a75151;
|
||||||
|
--text-color: #333333;
|
||||||
|
--error-background: #f3c3c3;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
* {
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
font-family: "Open Sans", Helvetica, sans-serif;
|
||||||
|
accent-color: var(--color-blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
min-height: 100vh;
|
||||||
|
background-color: var(--color-white);
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-container {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 1200px;
|
||||||
|
height: calc(100vh - 40px);
|
||||||
|
background-color: var(--color-white);
|
||||||
|
border-radius: 16px;
|
||||||
|
box-shadow: 0 10px 25px rgba(0,0,0,0.1);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-form {
|
||||||
|
width: 45%;
|
||||||
|
padding: 40px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
position: absolute;
|
||||||
|
top: 20px;
|
||||||
|
left: 20px;
|
||||||
|
background-image: url(VeLiTi-Logo2.png);
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
opacity: inherit;
|
||||||
|
width: 85px;
|
||||||
|
height: 120px;
|
||||||
|
margin: 0 auto;
|
||||||
|
-webkit-filter: drop-shadow(5px 5px 5px #222);
|
||||||
|
filter: drop-shadow(5px 5px 5px #222);
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-visual {
|
||||||
|
width: 55%;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
background-image: url(veliti_intro.png);
|
||||||
|
background-position: center center;
|
||||||
|
background-size: 100% 100%;
|
||||||
|
background-color: var(--color-light-blue);
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-visual img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
.register-link {
|
||||||
|
position: absolute;
|
||||||
|
top: 20px;
|
||||||
|
right: 20px;
|
||||||
|
text-decoration: none;
|
||||||
|
color: var(--text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header h1 {
|
||||||
|
font-size: 24px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header p {
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-group {
|
||||||
|
margin-bottom: 15px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-group input {
|
||||||
|
width: 100%;
|
||||||
|
padding: 10px;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-group input[type="email"] {
|
||||||
|
padding-left: 40px;
|
||||||
|
background: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="%23999" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"></path><polyline points="22,6 12,13 2,6"></polyline></svg>') no-repeat left 10px center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-group input[type="password"] {
|
||||||
|
padding-left: 40px;
|
||||||
|
background: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="%23999" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect><path d="M7 11V7a5 5 0 0 1 10 0v4"></path></svg>') no-repeat left 10px center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.forgot-password {
|
||||||
|
color: var(--text-color);
|
||||||
|
text-decoration: none;
|
||||||
|
text-align: right;
|
||||||
|
margin-top: 5px;
|
||||||
|
float: right;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.remember-me {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.remember-me input {
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.maintenance {
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message p {
|
||||||
|
margin-top: 5px;
|
||||||
|
background-color: var(--error-background);
|
||||||
|
border-left: 4px solid var(--color-red);
|
||||||
|
color: var(--color-red);
|
||||||
|
padding: 5px;
|
||||||
|
border-radius: 4px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-btn {
|
||||||
|
width: 100%;
|
||||||
|
padding: 12px;
|
||||||
|
background-color: var(--color-light-blue);
|
||||||
|
color: var(--color-white);
|
||||||
|
border: none;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background-color 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-btn:hover {
|
||||||
|
background-color: var(--color-blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
.trademark {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 20px;
|
||||||
|
left: 20px;
|
||||||
|
color: var(--text-color);
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-selector {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 20px;
|
||||||
|
right: 20px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
color: var(--text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-selector select {
|
||||||
|
margin-left: 10px;
|
||||||
|
border: none;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Responsive Design */
|
||||||
|
@media screen and (max-width: 1024px) {
|
||||||
|
.login-container {
|
||||||
|
flex-direction: column;
|
||||||
|
height: auto;
|
||||||
|
max-width: 500px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-form, .login-visual {
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-visual {
|
||||||
|
height: 300px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
position: static;
|
||||||
|
margin: 20px auto;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.trademark, .language-selector {
|
||||||
|
position: static;
|
||||||
|
text-align: center;
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 480px) {
|
||||||
|
.login-form {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header h1 {
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
231
custom/morvalwatches/style/morvalwatches_reset.css
Normal file
231
custom/morvalwatches/style/morvalwatches_reset.css
Normal file
@@ -0,0 +1,231 @@
|
|||||||
|
:root {
|
||||||
|
--color-white: #FFFFFF;
|
||||||
|
--color-light-blue: #344fd5c2;
|
||||||
|
--color-blue: #0b1054;
|
||||||
|
--color-red: #a75151;
|
||||||
|
--text-color: #333333;
|
||||||
|
--error-background: #f3c3c3;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
* {
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
font-family: "Open Sans", Helvetica, sans-serif;
|
||||||
|
accent-color: var(--color-blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
min-height: 100vh;
|
||||||
|
background-color: var(--color-white);
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-container {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 1200px;
|
||||||
|
height: calc(100vh - 40px);
|
||||||
|
background-color: var(--color-white);
|
||||||
|
border-radius: 16px;
|
||||||
|
box-shadow: 0 10px 25px rgba(0,0,0,0.1);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-form {
|
||||||
|
width: 45%;
|
||||||
|
padding: 40px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
position: absolute;
|
||||||
|
top: 20px;
|
||||||
|
left: 20px;
|
||||||
|
background-image: url(VeLiTi-Logo2.png);
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
opacity: inherit;
|
||||||
|
width: 85px;
|
||||||
|
height: 120px;
|
||||||
|
margin: 0 auto;
|
||||||
|
-webkit-filter: drop-shadow(5px 5px 5px #222);
|
||||||
|
filter: drop-shadow(5px 5px 5px #222);
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-visual {
|
||||||
|
width: 55%;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
background-image: url(veliti_intro.png);
|
||||||
|
background-position: center center;
|
||||||
|
background-size: 100% 100%;
|
||||||
|
background-color: var(--color-light-blue);
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-visual img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
.register-link {
|
||||||
|
position: absolute;
|
||||||
|
top: 20px;
|
||||||
|
right: 20px;
|
||||||
|
text-decoration: none;
|
||||||
|
color: var(--text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header h1 {
|
||||||
|
font-size: 24px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header p {
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-group {
|
||||||
|
margin-bottom: 15px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-group input {
|
||||||
|
width: 100%;
|
||||||
|
padding: 10px;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-group input[type="email"] {
|
||||||
|
padding-left: 40px;
|
||||||
|
background: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="%23999" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"></path><polyline points="22,6 12,13 2,6"></polyline></svg>') no-repeat left 10px center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-group input[type="password"] {
|
||||||
|
padding-left: 40px;
|
||||||
|
background: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="%23999" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect><path d="M7 11V7a5 5 0 0 1 10 0v4"></path></svg>') no-repeat left 10px center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.forgot-password {
|
||||||
|
color: var(--text-color);
|
||||||
|
text-decoration: none;
|
||||||
|
text-align: right;
|
||||||
|
margin-top: 5px;
|
||||||
|
float: right;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.remember-me {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.remember-me input {
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.maintenance {
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message p {
|
||||||
|
margin-top: 5px;
|
||||||
|
background-color: var(--error-background);
|
||||||
|
border-left: 4px solid var(--color-red);
|
||||||
|
color: var(--color-red);
|
||||||
|
padding: 5px;
|
||||||
|
border-radius: 4px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-btn {
|
||||||
|
width: 100%;
|
||||||
|
padding: 12px;
|
||||||
|
background-color: var(--color-light-blue);
|
||||||
|
color: var(--color-white);
|
||||||
|
border: none;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background-color 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-btn:hover {
|
||||||
|
background-color: var(--color-blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
.trademark {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 20px;
|
||||||
|
left: 20px;
|
||||||
|
color: var(--text-color);
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-selector {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 20px;
|
||||||
|
right: 20px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
color: var(--text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-selector select {
|
||||||
|
margin-left: 10px;
|
||||||
|
border: none;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Responsive Design */
|
||||||
|
@media screen and (max-width: 1024px) {
|
||||||
|
.login-container {
|
||||||
|
flex-direction: column;
|
||||||
|
height: auto;
|
||||||
|
max-width: 500px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-form, .login-visual {
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-visual {
|
||||||
|
height: 300px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
position: static;
|
||||||
|
margin: 20px auto;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.trademark, .language-selector {
|
||||||
|
position: static;
|
||||||
|
text-align: center;
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 480px) {
|
||||||
|
.login-form {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header h1 {
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
2971
custom/morvalwatches/style/soveliti.css
Normal file
2971
custom/morvalwatches/style/soveliti.css
Normal file
File diff suppressed because one or more lines are too long
BIN
custom/morvalwatches/style/veliti_intro.png
Normal file
BIN
custom/morvalwatches/style/veliti_intro.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 167 KiB |
151
factuur.php
Normal file
151
factuur.php
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
<?php
|
||||||
|
defined(page_security_key) or exit;
|
||||||
|
|
||||||
|
if (debug && debug_id == $_SESSION['id']) {
|
||||||
|
ini_set('display_errors', '1');
|
||||||
|
ini_set('display_startup_errors', '1');
|
||||||
|
error_reporting(E_ALL);
|
||||||
|
}
|
||||||
|
|
||||||
|
include_once './assets/functions.php';
|
||||||
|
include_once './settings/settings_redirector.php';
|
||||||
|
|
||||||
|
// Check if allowed
|
||||||
|
if (isAllowed('order', $_SESSION['profile'], $_SESSION['permission'], 'R') === 0) {
|
||||||
|
header('location: index.php');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get transaction ID from POST or GET (for HTML output)
|
||||||
|
$order_number = $_POST['txn_id'] ?? $_GET['txn_id'] ?? '';
|
||||||
|
|
||||||
|
if (empty($order_number)) {
|
||||||
|
header('Location: index.php?page=orders');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connect to database
|
||||||
|
$pdo = dbConnect($dbname);
|
||||||
|
|
||||||
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
// Get detailed invoice data
|
||||||
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
|
||||||
|
$api_url = '/v2/invoice/list=invoice&txn_id=' . $order_number;
|
||||||
|
$invoice_data = ioServer($api_url, '');
|
||||||
|
$invoice_data = json_decode($invoice_data, true);
|
||||||
|
|
||||||
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
// Determine invoice language
|
||||||
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
$available_languages = [
|
||||||
|
'NL' => 'NL',
|
||||||
|
'BE' => 'NL',
|
||||||
|
'US' => 'US',
|
||||||
|
'GB' => 'US',
|
||||||
|
'DE' => 'DE',
|
||||||
|
'FR' => 'FR',
|
||||||
|
'ES' => 'ES'
|
||||||
|
];
|
||||||
|
|
||||||
|
$invoice_language = 'US'; // Default
|
||||||
|
if (!empty($invoice_data['customer']['language'])) {
|
||||||
|
$invoice_language = strtoupper($invoice_data['customer']['language']);
|
||||||
|
} elseif (!empty($invoice_data['customer']['country']) && isset($available_languages[strtoupper($invoice_data['customer']['country'])])) {
|
||||||
|
$invoice_language = $available_languages[strtoupper($invoice_data['customer']['country'])];
|
||||||
|
}
|
||||||
|
|
||||||
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
// Generate invoice HTML
|
||||||
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
|
||||||
|
var_dump($invoice_data);
|
||||||
|
list($data, $customer_email, $order_id) = generateSoftwareInvoice($invoice_data, $order_number, $invoice_language);
|
||||||
|
|
||||||
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
// Check for HTML output request
|
||||||
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
if (isset($_GET['output']) && $_GET['output'] === 'html') {
|
||||||
|
// Output HTML directly to browser
|
||||||
|
echo $data;
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
// Initialize DomPDF
|
||||||
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
use Dompdf\Dompdf;
|
||||||
|
use Dompdf\Options;
|
||||||
|
|
||||||
|
$options = new Options();
|
||||||
|
$options->set('isRemoteEnabled', true);
|
||||||
|
$dompdf = new Dompdf($options);
|
||||||
|
|
||||||
|
// Load HTML content
|
||||||
|
$dompdf->loadHtml($data);
|
||||||
|
|
||||||
|
// Setup paper size and orientation
|
||||||
|
$dompdf->setPaper('A4', 'portrait');
|
||||||
|
|
||||||
|
// Render the HTML as PDF
|
||||||
|
$dompdf->render();
|
||||||
|
|
||||||
|
$file_name = 'Factuur - ' . $order_id;
|
||||||
|
|
||||||
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
// Handle different actions
|
||||||
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
|
||||||
|
// Email invoice to customer
|
||||||
|
if (isset($_POST['email_invoice'])) {
|
||||||
|
$to = $customer_email;
|
||||||
|
$subject = 'Factuur - ' . $order_id;
|
||||||
|
$message = $data;
|
||||||
|
$attachment = $dompdf->output();
|
||||||
|
$attachment_name = $file_name . '.pdf';
|
||||||
|
|
||||||
|
$header_redirect = 'Location: index.php?page=order&id=' . $order_id . '&success=invoice_sent';
|
||||||
|
|
||||||
|
// Send to PHPMailer
|
||||||
|
send_mail($to, $subject, $message, $attachment, $attachment_name);
|
||||||
|
|
||||||
|
header($header_redirect);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Email invoice to admin/bookkeeping
|
||||||
|
if (isset($_POST['email_invoice_to_admin'])) {
|
||||||
|
$to = $customer_email;
|
||||||
|
$subject = 'Factuur - ' . $order_id;
|
||||||
|
$message = $data;
|
||||||
|
$attachment = $dompdf->output();
|
||||||
|
$attachment_name = $file_name . '.pdf';
|
||||||
|
|
||||||
|
$header_redirect = 'Location: index.php?page=order&id=' . $order_id . '&success=invoice_sent_admin';
|
||||||
|
|
||||||
|
// Send to bookkeeping if configured
|
||||||
|
if (defined('invoice_bookkeeping') && invoice_bookkeeping && defined('email_bookkeeping') && email_bookkeeping) {
|
||||||
|
send_mail(email_bookkeeping, $subject, $message, $attachment, $attachment_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
header($header_redirect);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show invoice in browser
|
||||||
|
if (isset($_POST['show_invoice'])) {
|
||||||
|
// Clean output buffer to prevent corrupted PDF
|
||||||
|
if (ob_get_level()) {
|
||||||
|
ob_end_clean();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stream PDF to browser
|
||||||
|
$dompdf->stream($file_name . ".pdf", array("Attachment" => false));
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no action specified, redirect back
|
||||||
|
header('Location: index.php?page=order&id=' . $order_number);
|
||||||
|
exit;
|
||||||
|
|
||||||
|
?>
|
||||||
@@ -30,16 +30,16 @@ $url = 'index.php?page=histories'.$status.$search;
|
|||||||
//GET Details from URL
|
//GET Details from URL
|
||||||
$GET_VALUES = urlGETdetails($_GET) ?? '';
|
$GET_VALUES = urlGETdetails($_GET) ?? '';
|
||||||
//CALL TO API
|
//CALL TO API
|
||||||
$api_url = '/v1/history/'.$GET_VALUES;
|
$api_url = '/v2/history/'.$GET_VALUES;
|
||||||
$responses = ioServer($api_url,'');
|
$responses = ioServer($api_url,'');
|
||||||
//Decode Payload
|
//Decode Payload
|
||||||
if (!empty($responses)){$responses = decode_payload($responses);}else{$responses = null;}
|
if (!empty($responses)){$responses = json_decode($responses);}else{$responses = null;}
|
||||||
|
|
||||||
//Return QueryTotal from API
|
//Return QueryTotal from API
|
||||||
$api_url = '/v1/history/'.$GET_VALUES.'&totals=';
|
$api_url = '/v2/history/'.$GET_VALUES.'&totals=';
|
||||||
$query_total = ioServer($api_url,'');
|
$query_total = ioServer($api_url,'');
|
||||||
//Decode Payload
|
//Decode Payload
|
||||||
if (!empty($query_total)){$query_total = decode_payload($query_total);}else{$query_total = null;}
|
if (!empty($query_total)){$query_total = json_decode($query_total);}else{$query_total = null;}
|
||||||
|
|
||||||
template_header('Histories', 'histories','view');
|
template_header('Histories', 'histories','view');
|
||||||
$view = '
|
$view = '
|
||||||
@@ -116,7 +116,7 @@ $view .= '
|
|||||||
foreach ($responses as $response){
|
foreach ($responses as $response){
|
||||||
|
|
||||||
$description = json_decode($response->description) ?? $response->description;
|
$description = json_decode($response->description) ?? $response->description;
|
||||||
$description = json_encode($description, JSON_PRETTY_PRINT);
|
$description = json_encode($description, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||||||
//Replace JSON ITEMS
|
//Replace JSON ITEMS
|
||||||
$search = ['{', '}', '"',':','[',']',','];
|
$search = ['{', '}', '"',':','[',']',','];
|
||||||
$replace = ['', '','','=','','',''];
|
$replace = ['', '','','=','','',''];
|
||||||
|
|||||||
10
history.php
10
history.php
@@ -33,16 +33,16 @@ $url = 'index.php?page=history&equipmentID='.$_GET['equipmentID'].$status.$searc
|
|||||||
//GET Details from URL
|
//GET Details from URL
|
||||||
$GET_VALUES = urlGETdetails($_GET) ?? '';
|
$GET_VALUES = urlGETdetails($_GET) ?? '';
|
||||||
//CALL TO API
|
//CALL TO API
|
||||||
$api_url = '/v1/history/'.$GET_VALUES;
|
$api_url = '/v2/history/'.$GET_VALUES;
|
||||||
$responses = ioServer($api_url,'');
|
$responses = ioServer($api_url,'');
|
||||||
//Decode Payload
|
//Decode Payload
|
||||||
if (!empty($responses)){$responses = decode_payload($responses);}else{$responses = null;}
|
if (!empty($responses)){$responses = json_decode($responses);}else{$responses = null;}
|
||||||
|
|
||||||
//Return QueryTotal from API
|
//Return QueryTotal from API
|
||||||
$api_url = '/v1/history/'.$GET_VALUES.'&totals=';
|
$api_url = '/v2/history/'.$GET_VALUES.'&totals=';
|
||||||
$query_total = ioServer($api_url,'');
|
$query_total = ioServer($api_url,'');
|
||||||
//Decode Payload
|
//Decode Payload
|
||||||
if (!empty($query_total)){$query_total = decode_payload($query_total);}else{$query_total = null;}
|
if (!empty($query_total)){$query_total = json_decode($query_total);}else{$query_total = null;}
|
||||||
|
|
||||||
|
|
||||||
// Handle success messages
|
// Handle success messages
|
||||||
@@ -137,7 +137,7 @@ $view .= '
|
|||||||
foreach ($responses as $response){
|
foreach ($responses as $response){
|
||||||
|
|
||||||
$description = json_decode($response->description) ?? $response->description;
|
$description = json_decode($response->description) ?? $response->description;
|
||||||
$description = json_encode($description, JSON_PRETTY_PRINT);
|
$description = json_encode($description, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||||||
|
|
||||||
//Replace JSON ITEMS
|
//Replace JSON ITEMS
|
||||||
$search = ['{', '}', '"',':','[',']',','];
|
$search = ['{', '}', '"',':','[',']',','];
|
||||||
|
|||||||
@@ -34,10 +34,10 @@ if ($rowID !=''){
|
|||||||
if (isset($_GET['rowID'])) {
|
if (isset($_GET['rowID'])) {
|
||||||
// ID param exists, edit an existing product
|
// ID param exists, edit an existing product
|
||||||
//CALL TO API
|
//CALL TO API
|
||||||
$api_url = '/v1/history/historyid='.$rowID;
|
$api_url = '/v2/history/historyid='.$rowID;
|
||||||
$responses = ioServer($api_url,'');
|
$responses = ioServer($api_url,'');
|
||||||
//Decode Payload
|
//Decode Payload
|
||||||
if (!empty($responses)){$responses = decode_payload($responses);}else{$responses = null;}
|
if (!empty($responses)){$responses = json_decode($responses);}else{$responses = null;}
|
||||||
|
|
||||||
$history = json_decode(json_encode($responses[0]), true);
|
$history = json_decode(json_encode($responses[0]), true);
|
||||||
|
|
||||||
|
|||||||
@@ -319,6 +319,21 @@ $firmwaretool_step_5 = 'Wenn Firmware verfügbar ist: Die Statusleiste zeigt "<i
|
|||||||
$firmwaretool_step_6 = 'Wenn Firmware verfügbar ist: Stellen Sie sicher, dass SN und HW vom Gerät gelesen werden und bestätigen Sie dies, indem Sie das Kontrollkästchen "Ich bestätige, dass SN und HW vom Gerät gelesen wurden" auswählen';
|
$firmwaretool_step_6 = 'Wenn Firmware verfügbar ist: Stellen Sie sicher, dass SN und HW vom Gerät gelesen werden und bestätigen Sie dies, indem Sie das Kontrollkästchen "Ich bestätige, dass SN und HW vom Gerät gelesen wurden" auswählen';
|
||||||
$firmwaretool_step_7 = 'Drücken Sie die <i>"Firmware aktualisieren"</i>-Schaltfläche, um den Firmware-Aktualisierungsdialog zu starten und folgen Sie den Anweisungen auf dem Bildschirm';
|
$firmwaretool_step_7 = 'Drücken Sie die <i>"Firmware aktualisieren"</i>-Schaltfläche, um den Firmware-Aktualisierungsdialog zu starten und folgen Sie den Anweisungen auf dem Bildschirm';
|
||||||
$firmwaretool_step_8 = '<b>Hinweis: Dieser Prozess kann nicht gestoppt werden und muss abgeschlossen werden.</b>';
|
$firmwaretool_step_8 = '<b>Hinweis: Dieser Prozess kann nicht gestoppt werden und muss abgeschlossen werden.</b>';
|
||||||
|
$softwaretool_h2 = 'Software-Upgrade-Tool';
|
||||||
|
$softwaretool_p = 'Software-Upgrade-Optionen.';
|
||||||
|
$softwaretool_step = 'Anweisungen';
|
||||||
|
$softwaretool_step_1 = 'Verbinden Sie das Gerät über USB mit dem Computer. (USB befindet sich unter der Batterieabdeckung)';
|
||||||
|
$softwaretool_step_2 = 'Drücken Sie die "<i>Verbinden</i>"-Schaltfläche';
|
||||||
|
$softwaretool_step_3 = 'Ein Popup-Fenster erscheint, in dem Sie ein Gerät auswählen können. Wählen Sie das Gerät aus, indem Sie darauf klicken, und drücken Sie dann die Verbinden-Schaltfläche.';
|
||||||
|
$softwaretool_step_4 = 'Nach dem Verschwinden des Popups wird das Gerät gelesen, die Statusleiste zeigt den Fortschritt an';
|
||||||
|
$softwaretool_step_5 = 'Verfügbare Software-Upgrades werden mit Name, Beschreibung und Preis angezeigt';
|
||||||
|
$softwaretool_step_6 = 'Wählen Sie eine Software-Version';
|
||||||
|
$softwaretool_step_7 = 'Für kostenpflichtige Upgrades folgen Sie bitte dem Zahlungsprozess';
|
||||||
|
$softwaretool_step_8 = '<b>Hinweis: Dieser Prozess kann nicht gestoppt werden und muss abgeschlossen werden.</b>';
|
||||||
|
$softwaretool_no_updates = 'Keine Software-Updates gefunden';
|
||||||
|
$softwaretool_checking = 'Suche nach Software-Updates...';
|
||||||
|
$softwaretool_available = 'Software-Updates verfügbar';
|
||||||
|
$softwaretool_select_upgrade = 'Wählen Sie eine Upgrade-Option:';
|
||||||
$newuser_subject = 'CustomerPortal-Benutzer erstellt';
|
$newuser_subject = 'CustomerPortal-Benutzer erstellt';
|
||||||
$newuser_header = 'Lieber CustomerPortal-Benutzer';
|
$newuser_header = 'Lieber CustomerPortal-Benutzer';
|
||||||
$newuser_text = 'Ihr CustomerPortal-Administrator hat Ihnen Zugriff auf das CustomerPortal gewährt. Um Ihr Konto abzuschließen, müssen Sie Ihr Passwort über den folgenden Link aktualisieren.';
|
$newuser_text = 'Ihr CustomerPortal-Administrator hat Ihnen Zugriff auf das CustomerPortal gewährt. Um Ihr Konto abzuschließen, müssen Sie Ihr Passwort über den folgenden Link aktualisieren.';
|
||||||
|
|||||||
@@ -319,6 +319,21 @@ $firmwaretool_step_5 = 'Cuando el firmware esté disponible: La barra de estado
|
|||||||
$firmwaretool_step_6 = 'Cuando el firmware esté disponible: Asegúrese de que el SN y el HW se lean del dispositivo y confirme esto seleccionando la casilla "Confirmo que el SN y el HW se han leído del dispositivo"';
|
$firmwaretool_step_6 = 'Cuando el firmware esté disponible: Asegúrese de que el SN y el HW se lean del dispositivo y confirme esto seleccionando la casilla "Confirmo que el SN y el HW se han leído del dispositivo"';
|
||||||
$firmwaretool_step_7 = 'Presione el botón <i>"Actualizar firmware"</i> para iniciar el diálogo de actualización de firmware y siga las instrucciones en pantalla';
|
$firmwaretool_step_7 = 'Presione el botón <i>"Actualizar firmware"</i> para iniciar el diálogo de actualización de firmware y siga las instrucciones en pantalla';
|
||||||
$firmwaretool_step_8 = '<b>Tenga en cuenta: Este proceso no se puede detener y debe finalizar.</b>';
|
$firmwaretool_step_8 = '<b>Tenga en cuenta: Este proceso no se puede detener y debe finalizar.</b>';
|
||||||
|
$softwaretool_h2 = 'Herramienta de actualización de software';
|
||||||
|
$softwaretool_p = 'Opciones de actualización de software.';
|
||||||
|
$softwaretool_step = 'Instrucciones';
|
||||||
|
$softwaretool_step_1 = 'Conecte el dispositivo a la computadora por USB. (Se encuentra debajo de la tapa de la batería)';
|
||||||
|
$softwaretool_step_2 = 'Presione el botón "<i>conectar</i>"';
|
||||||
|
$softwaretool_step_3 = 'Aparecerá una ventana emergente pidiendo seleccionar un dispositivo. Seleccione el dispositivo haciendo clic en él y luego presione el botón conectar.';
|
||||||
|
$softwaretool_step_4 = 'Después de que desaparezca la ventana emergente, el dispositivo será leído, la barra de estado mostrará el progreso';
|
||||||
|
$softwaretool_step_5 = 'Las actualizaciones de software disponibles se mostrarán con Nombre, Descripción y Precio';
|
||||||
|
$softwaretool_step_6 = 'Seleccione una versión de software';
|
||||||
|
$softwaretool_step_7 = 'Para actualizaciones de pago, siga el proceso de pago';
|
||||||
|
$softwaretool_step_8 = '<b>Tenga en cuenta: Este proceso no se puede detener y debe finalizar.</b>';
|
||||||
|
$softwaretool_no_updates = 'No se encontraron actualizaciones de software';
|
||||||
|
$softwaretool_checking = 'Buscando actualizaciones de software...';
|
||||||
|
$softwaretool_available = 'Actualizaciones de software disponibles';
|
||||||
|
$softwaretool_select_upgrade = 'Seleccione una opción de actualización:';
|
||||||
$newuser_subject = 'Usuario de CustomerPortal creado';
|
$newuser_subject = 'Usuario de CustomerPortal creado';
|
||||||
$newuser_header = 'Estimado usuario de CustomerPortal';
|
$newuser_header = 'Estimado usuario de CustomerPortal';
|
||||||
$newuser_text = 'Su administrador de CustomerPortal ha proporcionado acceso al CustomerPortal. Para completar su cuenta, debe actualizar su contraseña a través del siguiente enlace.';
|
$newuser_text = 'Su administrador de CustomerPortal ha proporcionado acceso al CustomerPortal. Para completar su cuenta, debe actualizar su contraseña a través del siguiente enlace.';
|
||||||
|
|||||||
@@ -319,6 +319,21 @@ $firmwaretool_step_5 = 'Wanneer software beschikbaar is zal de voortgang "<i>Fir
|
|||||||
$firmwaretool_step_6 = 'Wanneer software beschikbaar is: Bevestig dat SW and HW zijn gelezen van het apparaat door op de checkbox te klikken bij <i> Ik bevestig dat SN en HW zijn uitgelezen van de activa</i>.';
|
$firmwaretool_step_6 = 'Wanneer software beschikbaar is: Bevestig dat SW and HW zijn gelezen van het apparaat door op de checkbox te klikken bij <i> Ik bevestig dat SN en HW zijn uitgelezen van de activa</i>.';
|
||||||
$firmwaretool_step_7 = 'Druk op de <i>"Update firmware</i>" knop om de update te starten en de instructies op het scherm te volgen';
|
$firmwaretool_step_7 = 'Druk op de <i>"Update firmware</i>" knop om de update te starten en de instructies op het scherm te volgen';
|
||||||
$firmwaretool_step_8 = '<b>Opgelet: Dit proces kan niet onderbroken worden.</b>';
|
$firmwaretool_step_8 = '<b>Opgelet: Dit proces kan niet onderbroken worden.</b>';
|
||||||
|
$softwaretool_h2 = 'Software upgrade tool';
|
||||||
|
$softwaretool_p = 'Software upgrade opties.';
|
||||||
|
$softwaretool_step = 'Instructies';
|
||||||
|
$softwaretool_step_1 = 'Sluit het apparaat via USB aan op de computer.(USB bevindt zich onder de batterijklep)';
|
||||||
|
$softwaretool_step_2 = 'Druk "<i>connect</i>" knop';
|
||||||
|
$softwaretool_step_3 = 'In het popup venster selecteer het apparaat door er op te klikken. Druk daarna op de verbinding maken knop.';
|
||||||
|
$softwaretool_step_4 = 'Het apparaat wordt nu gelezen. Een voortgang status wordt getoond';
|
||||||
|
$softwaretool_step_5 = 'Beschikbare software upgrades worden weergegeven met Naam, Beschrijving en Prijs';
|
||||||
|
$softwaretool_step_6 = 'Selecteer een software versie';
|
||||||
|
$softwaretool_step_7 = 'Voor betaalde upgrades, volg het betalingsproces';
|
||||||
|
$softwaretool_step_8 = '<b>Opgelet: Dit proces kan niet onderbroken worden.</b>';
|
||||||
|
$softwaretool_no_updates = 'Geen software updates gevonden';
|
||||||
|
$softwaretool_checking = 'Controleren op software updates...';
|
||||||
|
$softwaretool_available = 'Software updates beschikbaar';
|
||||||
|
$softwaretool_select_upgrade = 'Selecteer een upgrade optie:';
|
||||||
$newuser_subject = 'CustomerPortal user created';
|
$newuser_subject = 'CustomerPortal user created';
|
||||||
$newuser_header = 'Dear CustomerPortal user';
|
$newuser_header = 'Dear CustomerPortal user';
|
||||||
$newuser_text = 'Your CustomerPortal administrator has provided access to the CustomerPortal. To complete your account you need to update your password via the link below.';
|
$newuser_text = 'Your CustomerPortal administrator has provided access to the CustomerPortal. To complete your account you need to update your password via the link below.';
|
||||||
|
|||||||
@@ -319,6 +319,21 @@ $firmwaretool_step_5 = 'Gdy oprogramowanie jest dostępne: Pasek stanu pokaże "
|
|||||||
$firmwaretool_step_6 = 'Gdy oprogramowanie jest dostępne: Upewnij się, że SN i HW zostały odczytane z urządzenia i potwierdź to zaznaczając pole "Potwierdzam, że SN i HW zostały odczytane z urządzenia"';
|
$firmwaretool_step_6 = 'Gdy oprogramowanie jest dostępne: Upewnij się, że SN i HW zostały odczytane z urządzenia i potwierdź to zaznaczając pole "Potwierdzam, że SN i HW zostały odczytane z urządzenia"';
|
||||||
$firmwaretool_step_7 = 'Naciśnij przycisk <i>"Aktualizuj oprogramowanie"</i>, aby uruchomić okno aktualizacji oprogramowania i postępuj zgodnie z instrukcjami na ekranie';
|
$firmwaretool_step_7 = 'Naciśnij przycisk <i>"Aktualizuj oprogramowanie"</i>, aby uruchomić okno aktualizacji oprogramowania i postępuj zgodnie z instrukcjami na ekranie';
|
||||||
$firmwaretool_step_8 = '<b>Uwaga: Ten proces nie może zostać przerwany i musi się zakończyć.</b>';
|
$firmwaretool_step_8 = '<b>Uwaga: Ten proces nie może zostać przerwany i musi się zakończyć.</b>';
|
||||||
|
$softwaretool_h2 = 'Narzędzie aktualizacji oprogramowania';
|
||||||
|
$softwaretool_p = 'Opcje aktualizacji oprogramowania.';
|
||||||
|
$softwaretool_step = 'Instrukcje';
|
||||||
|
$softwaretool_step_1 = 'Podłącz urządzenie do komputera przez USB. (Znajduje się pod pokrywą baterii)';
|
||||||
|
$softwaretool_step_2 = 'Naciśnij przycisk "<i>połącz</i>"';
|
||||||
|
$softwaretool_step_3 = 'Pojawi się okno popup z prośbą o wybranie urządzenia. Wybierz urządzenie klikając na nie, a następnie naciśnij przycisk połącz.';
|
||||||
|
$softwaretool_step_4 = 'Po zniknięciu okna popup urządzenie zostanie odczytane, pasek stanu pokaże postęp';
|
||||||
|
$softwaretool_step_5 = 'Dostępne aktualizacje oprogramowania zostaną wyświetlone z Nazwą, Opisem i Ceną';
|
||||||
|
$softwaretool_step_6 = 'Wybierz wersję oprogramowania';
|
||||||
|
$softwaretool_step_7 = 'W przypadku płatnych aktualizacji postępuj zgodnie z procesem płatności';
|
||||||
|
$softwaretool_step_8 = '<b>Uwaga: Ten proces nie może zostać przerwany i musi się zakończyć.</b>';
|
||||||
|
$softwaretool_no_updates = 'Nie znaleziono aktualizacji oprogramowania';
|
||||||
|
$softwaretool_checking = 'Sprawdzanie aktualizacji oprogramowania...';
|
||||||
|
$softwaretool_available = 'Dostępne aktualizacje oprogramowania';
|
||||||
|
$softwaretool_select_upgrade = 'Wybierz opcję aktualizacji:';
|
||||||
$newuser_subject = 'Użytkownik CustomerPortal utworzony';
|
$newuser_subject = 'Użytkownik CustomerPortal utworzony';
|
||||||
$newuser_header = 'Szanowny użytkowniku CustomerPortal';
|
$newuser_header = 'Szanowny użytkowniku CustomerPortal';
|
||||||
$newuser_text = 'Administrator CustomerPortal przyznał Ci dostęp do CustomerPortal. Aby ukończyć konfigurację konta, musisz zaktualizować hasło za pomocą poniższego linku.';
|
$newuser_text = 'Administrator CustomerPortal przyznał Ci dostęp do CustomerPortal. Aby ukończyć konfigurację konta, musisz zaktualizować hasło za pomocą poniższego linku.';
|
||||||
|
|||||||
@@ -319,6 +319,21 @@ $firmwaretool_step_5 = 'Quando o firmware estiver disponível: A barra de status
|
|||||||
$firmwaretool_step_6 = 'Quando o firmware estiver disponível: Certifique-se de que o SN e o HW sejam lidos do dispositivo e confirme isso selecionando a caixa "Eu confirmo que o SN e o HW foram lidos do dispositivo"';
|
$firmwaretool_step_6 = 'Quando o firmware estiver disponível: Certifique-se de que o SN e o HW sejam lidos do dispositivo e confirme isso selecionando a caixa "Eu confirmo que o SN e o HW foram lidos do dispositivo"';
|
||||||
$firmwaretool_step_7 = 'Pressione o botão <i>"Atualizar firmware"</i> para iniciar o diálogo de atualização de firmware e siga as instruções na tela';
|
$firmwaretool_step_7 = 'Pressione o botão <i>"Atualizar firmware"</i> para iniciar o diálogo de atualização de firmware e siga as instruções na tela';
|
||||||
$firmwaretool_step_8 = '<b>Esteja ciente: Este processo não pode ser interrompido e precisa ser concluído.</b>';
|
$firmwaretool_step_8 = '<b>Esteja ciente: Este processo não pode ser interrompido e precisa ser concluído.</b>';
|
||||||
|
$softwaretool_h2 = 'Ferramenta de atualização de software';
|
||||||
|
$softwaretool_p = 'Opções de atualização de software.';
|
||||||
|
$softwaretool_step = 'Instruções';
|
||||||
|
$softwaretool_step_1 = 'Conecte o dispositivo ao computador por USB. (Encontrado sob a tampa da bateria)';
|
||||||
|
$softwaretool_step_2 = 'Pressione o botão "<i>conectar</i>"';
|
||||||
|
$softwaretool_step_3 = 'Um popup aparecerá pedindo para selecionar um dispositivo. Selecione o dispositivo clicando nele e depois pressione o botão conectar.';
|
||||||
|
$softwaretool_step_4 = 'Após o popup desaparecer, o dispositivo será lido, a barra de status mostrará o progresso';
|
||||||
|
$softwaretool_step_5 = 'Atualizações de software disponíveis serão exibidas com Nome, Descrição e Preço';
|
||||||
|
$softwaretool_step_6 = 'Selecione uma versão de software';
|
||||||
|
$softwaretool_step_7 = 'Para atualizações pagas, siga o processo de pagamento';
|
||||||
|
$softwaretool_step_8 = '<b>Esteja ciente: Este processo não pode ser interrompido e precisa ser concluído.</b>';
|
||||||
|
$softwaretool_no_updates = 'Nenhuma atualização de software encontrada';
|
||||||
|
$softwaretool_checking = 'Verificando atualizações de software...';
|
||||||
|
$softwaretool_available = 'Atualizações de software disponíveis';
|
||||||
|
$softwaretool_select_upgrade = 'Selecione uma opção de atualização:';
|
||||||
$newuser_subject = 'Usuário do CustomerPortal criado';
|
$newuser_subject = 'Usuário do CustomerPortal criado';
|
||||||
$newuser_header = 'Caro usuário do CustomerPortal';
|
$newuser_header = 'Caro usuário do CustomerPortal';
|
||||||
$newuser_text = 'Seu administrador do CustomerPortal forneceu acesso ao CustomerPortal. Para completar sua conta, você precisa atualizar sua senha através do link abaixo.';
|
$newuser_text = 'Seu administrador do CustomerPortal forneceu acesso ao CustomerPortal. Para completar sua conta, você precisa atualizar sua senha através do link abaixo.';
|
||||||
|
|||||||
@@ -336,8 +336,8 @@ $softwaretool_step_2 = 'Press "<i>connect</i>" button"';
|
|||||||
$softwaretool_step_3 = 'A popup will appear asking to select a device. Select the device by clicking on it and the press the connect button.';
|
$softwaretool_step_3 = 'A popup will appear asking to select a device. Select the device by clicking on it and the press the connect button.';
|
||||||
$softwaretool_step_4 = 'After pop-up disappears the device will be read, status bar will show progress';
|
$softwaretool_step_4 = 'After pop-up disappears the device will be read, status bar will show progress';
|
||||||
$softwaretool_step_5 = 'Available software upgrades will be displayed with Name, Description and Price';
|
$softwaretool_step_5 = 'Available software upgrades will be displayed with Name, Description and Price';
|
||||||
$softwaretool_step_6 = 'Select a free upgrade (price = 0) to download and install';
|
$softwaretool_step_6 = 'Select a software version';
|
||||||
$softwaretool_step_7 = 'For paid upgrades, please contact support';
|
$softwaretool_step_7 = 'For paid upgrades, please follow the payment process';
|
||||||
$softwaretool_step_8 = '<b>Be aware: This process cannot be stopped and needs to finish.</b>';
|
$softwaretool_step_8 = '<b>Be aware: This process cannot be stopped and needs to finish.</b>';
|
||||||
$softwaretool_no_updates = 'No software updates found';
|
$softwaretool_no_updates = 'No software updates found';
|
||||||
$softwaretool_checking = 'Checking for software updates...';
|
$softwaretool_checking = 'Checking for software updates...';
|
||||||
|
|||||||
114
softwaretool.php
114
softwaretool.php
@@ -122,7 +122,7 @@ $view .= '<div class="content-block">
|
|||||||
|
|
||||||
<div id="connectdevice" style="display:flex; gap: 10px; margin-bottom: 20px;">
|
<div id="connectdevice" style="display:flex; gap: 10px; margin-bottom: 20px;">
|
||||||
<button class="btn" id="connectButton" onClick="connectDeviceForSoftware()" style="min-width: 150px;">
|
<button class="btn" id="connectButton" onClick="connectDeviceForSoftware()" style="min-width: 150px;">
|
||||||
<i class="fa-solid fa-plug"></i>Connect
|
<i class="fa-solid fa-plug"></i> Connect
|
||||||
</button>
|
</button>
|
||||||
<div id="readStatus" style="flex: 1; background-color: #f1f1f1; border-radius: 4px; overflow: hidden;">
|
<div id="readStatus" style="flex: 1; background-color: #f1f1f1; border-radius: 4px; overflow: hidden;">
|
||||||
<div id="readBar" style="height: 100%; transition: width 0.3s ease;"></div>
|
<div id="readBar" style="height: 100%; transition: width 0.3s ease;"></div>
|
||||||
@@ -143,10 +143,10 @@ $view .= '<div class="content-block">
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="noUpdatesMessage" style="margin: 20px 0; padding: 30px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; border-radius: 12px; text-align: center; display:none;">
|
<div id="noUpdatesMessage" style="margin: 20px 0; padding: 30px; background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%); border-radius: 3px; text-align: center; display:none; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);">
|
||||||
<i class="fa-solid fa-check-circle" style="font-size: 48px; margin-bottom: 15px;"></i>
|
<i class="fa-solid fa-check-circle" style="font-size: 48px; margin-bottom: 15px; color: #28a745;"></i>
|
||||||
<p style="margin: 0; font-size: 18px; font-weight: 500;"><strong>'.$softwaretool_no_updates.'</strong></p>
|
<p style="margin: 0; font-size: 18px; font-weight: 600; color: #155724;"><strong>'.$softwaretool_no_updates.'</strong></p>
|
||||||
<p style="margin: 10px 0 0 0; opacity: 0.9;">Your device is up to date</p>
|
<p style="margin: 10px 0 0 0; color: #6c757d; font-size: 14px;">Your device is up to date</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="uploadSection" style="margin-top: 10px; display:none;">
|
<div id="uploadSection" style="margin-top: 10px; display:none;">
|
||||||
@@ -157,6 +157,8 @@ $view .= '<div class="content-block">
|
|||||||
disabled>Install Software
|
disabled>Install Software
|
||||||
<span class="upload-progress"></span>
|
<span class="upload-progress"></span>
|
||||||
</button>
|
</button>
|
||||||
|
<!-- Hidden checkbox that upload.js expects -->
|
||||||
|
<input type="checkbox" id="action_firmware" style="display:none;">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -245,6 +247,108 @@ echo '
|
|||||||
closePaymentModal();
|
closePaymentModal();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Monitor upload completion
|
||||||
|
const observer = new MutationObserver(function(mutations) {
|
||||||
|
mutations.forEach(function(mutation) {
|
||||||
|
if (mutation.type === "attributes" && mutation.attributeName === "checked") {
|
||||||
|
const actionFirmware = document.getElementById("action_firmware");
|
||||||
|
if (actionFirmware && actionFirmware.checked) {
|
||||||
|
console.log("Upload completion detected!");
|
||||||
|
// Upload completed successfully
|
||||||
|
handleUploadCompletion(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Also monitor for readBar changes to detect completion
|
||||||
|
const readBarObserver = new MutationObserver(function(mutations) {
|
||||||
|
mutations.forEach(function(mutation) {
|
||||||
|
if (mutation.type === "childList" || mutation.type === "characterData") {
|
||||||
|
const readBar = document.getElementById("readBar");
|
||||||
|
if (readBar && readBar.innerHTML && readBar.innerHTML.includes("Firmware update completed")) {
|
||||||
|
console.log("Firmware update completed detected via readBar!");
|
||||||
|
setTimeout(() => handleUploadCompletion(true), 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Start observing when upload section is visible
|
||||||
|
function startUploadMonitoring() {
|
||||||
|
const actionFirmware = document.getElementById("action_firmware");
|
||||||
|
const readBar = document.getElementById("readBar");
|
||||||
|
|
||||||
|
if (actionFirmware) {
|
||||||
|
observer.observe(actionFirmware, {
|
||||||
|
attributes: true,
|
||||||
|
attributeFilter: ["checked"]
|
||||||
|
});
|
||||||
|
console.log("Started monitoring action_firmware checkbox");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (readBar) {
|
||||||
|
readBarObserver.observe(readBar, {
|
||||||
|
childList: true,
|
||||||
|
subtree: true,
|
||||||
|
characterData: true
|
||||||
|
});
|
||||||
|
console.log("Started monitoring readBar for completion");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle upload completion (success or failure)
|
||||||
|
window.handleUploadCompletion = function(success) {
|
||||||
|
console.log("handleUploadCompletion called with success:", success);
|
||||||
|
|
||||||
|
const installStatus = document.getElementById("installationStatus");
|
||||||
|
const readBar = document.getElementById("readBar");
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
// Success handling
|
||||||
|
console.log("Updating UI for successful completion");
|
||||||
|
if (installStatus) {
|
||||||
|
installStatus.innerHTML = \'\' +
|
||||||
|
\'<i class="fa-solid fa-check-circle" style="font-size: 48px; color: #28a745; margin-bottom: 15px;"></i>\' +
|
||||||
|
\'<p style="margin: 0; font-size: 18px; font-weight: 600; color: #155724;">Installation Complete!</p>\' +
|
||||||
|
\'<p style="margin: 5px 0 0 0; color: #666; font-size: 14px;">Your device has been successfully updated</p>\';
|
||||||
|
}
|
||||||
|
// Ensure progress bar is at 100%
|
||||||
|
if (readBar) {
|
||||||
|
readBar.style.width = "100%";
|
||||||
|
readBar.style.background = "#04AA6D";
|
||||||
|
readBar.innerHTML = "Firmware update completed - 100%";
|
||||||
|
console.log("Updated readBar to 100%");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Failure handling
|
||||||
|
console.log("Updating UI for failed completion");
|
||||||
|
if (installStatus) {
|
||||||
|
installStatus.innerHTML = \'\' +
|
||||||
|
\'<i class="fa-solid fa-exclamation-circle" style="font-size: 48px; color: #dc3545; margin-bottom: 15px;"></i>\' +
|
||||||
|
\'<p style="margin: 0; font-size: 18px; font-weight: 600; color: #721c24;">Installation Failed</p>\' +
|
||||||
|
\'<p style="margin: 5px 0 0 0; color: #666; font-size: 14px;">Please try again or contact support</p>\';
|
||||||
|
}
|
||||||
|
if (readBar) {
|
||||||
|
readBar.style.width = "100%";
|
||||||
|
readBar.style.background = "#dc3545";
|
||||||
|
readBar.innerHTML = "Installation failed";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop monitoring
|
||||||
|
observer.disconnect();
|
||||||
|
readBarObserver.disconnect();
|
||||||
|
console.log("Stopped monitoring observers");
|
||||||
|
};
|
||||||
|
|
||||||
|
// Monitor for upload errors
|
||||||
|
window.addEventListener("error", function(e) {
|
||||||
|
if (e.message && e.message.includes("upload")) {
|
||||||
|
handleUploadCompletion(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
</script>';
|
</script>';
|
||||||
|
|
||||||
template_footer();
|
template_footer();
|
||||||
|
|||||||
Reference in New Issue
Block a user