diff --git a/.DS_Store b/.DS_Store index d585516..9d4c452 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/.gitignore b/.gitignore index 3d559fe..b32e0bd 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,11 @@ settings/soveliti/soveliti_settings.php assets/database/dev_schema.sql assets/database/migration.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 diff --git a/api/.DS_Store b/api/.DS_Store index 25bea50..362cceb 100644 Binary files a/api/.DS_Store and b/api/.DS_Store differ diff --git a/api/v1/.DS_Store b/api/v1/.DS_Store index cb2f10e..ad7d9dd 100644 Binary files a/api/v1/.DS_Store and b/api/v1/.DS_Store differ diff --git a/api/v2/.DS_Store b/api/v2/.DS_Store index c28ab40..16d8e39 100644 Binary files a/api/v2/.DS_Store and b/api/v2/.DS_Store differ diff --git a/api/v2/get/.DS_Store b/api/v2/get/.DS_Store deleted file mode 100644 index 5008ddf..0000000 Binary files a/api/v2/get/.DS_Store and /dev/null differ diff --git a/api/v2/get/equipments.php b/api/v2/get/equipments.php index d02c76d..13eb35e 100644 --- a/api/v2/get/equipments.php +++ b/api/v2/get/equipments.php @@ -143,6 +143,10 @@ if(isset($get_content) && $get_content!=''){ $clause .= ' AND e.serialnumber IN (:'.$v[0].')'; } } + elseif ($v[0] == 'validate') { + // Set validation mode flag + $validation_mode = true; + } elseif ($v[0] == 'firmware') { //Assets with firmaware upgrade = 0 (1=latest version, 2=No software) $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 //------------------------------------------ @@ -175,6 +179,10 @@ if (isset($criterias['download']) && $criterias['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'; } +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'])){ //Request for total rows $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 //------------------------------------------ -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(); $messages = $stmt->fetch(); $messages = $messages[0]; diff --git a/api/v2/get/history.php b/api/v2/get/history.php index be5c826..8967b7c 100644 --- a/api/v2/get/history.php +++ b/api/v2/get/history.php @@ -136,10 +136,22 @@ else { $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 //------------------------------------------ -$messages = json_encode($messages, JSON_UNESCAPED_UNICODE); +$messages = json_encode($messages, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); //Send results echo $messages; diff --git a/api/v2/get/invoice.php b/api/v2/get/invoice.php index 8091646..07055c6 100644 --- a/api/v2/get/invoice.php +++ b/api/v2/get/invoice.php @@ -51,7 +51,7 @@ elseif (isset($criterias['list']) && $criterias['list'] =='invoice'){ //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 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 products p ON p.rowID = txi.item_id left join identity i ON i.userkey = tx.account_id '.$whereclause; diff --git a/api/v2/get/software_available.php b/api/v2/get/software_available.php index 3513575..ef5f27f 100644 --- a/api/v2/get/software_available.php +++ b/api/v2/get/software_available.php @@ -161,6 +161,7 @@ if (isset($criterias['sn']) && $criterias['sn'] != ''){ $debug['decision'] = 'No active software assignments found'; } } else { + $available_upgrades = 0; $has_priced_options = false; $has_latest_version_different = false; @@ -242,6 +243,8 @@ if (isset($criterias['sn']) && $criterias['sn'] != ''){ } if ($show_version) { + $available_upgrades++; + //Check if there's a valid license for this upgrade if ($final_price > 0 && $sw_version_license) { //Check if the license is valid @@ -286,23 +289,18 @@ if (isset($criterias['sn']) && $criterias['sn'] != ''){ } } - // Apply the logic: - // 1. If there are priced options -> "yes" - // 2. If no priced options but current version != latest flagged version -> "yes" - // 3. Default -> "no" - if ($has_priced_options) { + // Simple logic: if any upgrades are available to show, return "yes" + if ($available_upgrades > 0) { $software_available = "yes"; - $availability_reason = "Has priced upgrade options available"; - } elseif ($has_latest_version_different) { - $software_available = "yes"; - $availability_reason = "Has free latest version available"; + $availability_reason = "Software upgrades available"; } else { $software_available = "no"; - $availability_reason = "No upgrades available or already on latest"; + $availability_reason = "No upgrades available"; } if (debug) { $debug['final_decision'] = [ + 'available_upgrades' => $available_upgrades, 'has_priced_options' => $has_priced_options, 'has_latest_version_different' => $has_latest_version_different, 'software_available' => $software_available, diff --git a/api/v2/get/software_update.php b/api/v2/get/software_update.php index 2f4696b..6742cd0 100644 --- a/api/v2/get/software_update.php +++ b/api/v2/get/software_update.php @@ -133,6 +133,7 @@ if (isset($criterias['sn']) && $criterias['sn'] != ''){ JOIN products_software_versions psv ON psa.software_version_id = psv.rowID WHERE psa.product_id = ? AND psa.status = 1 + AND psv.latest = 1 AND (psv.hw_version = ? OR psv.hw_version IS NULL OR psv.hw_version = "")'; $stmt = $pdo->prepare($sql); @@ -212,16 +213,13 @@ if (isset($criterias['sn']) && $criterias['sn'] != ''){ $decision_reason = 'Skipped - is current version but no upgrades scenario'; } } else { - //Check if this is the current version and should be shown as disabled - if ($is_current_version && $has_paid_upgrade_from_current && $version['latest'] == 1) { - //Show current version as disabled only if it's the latest AND there's a paid upgrade available + //Check if this is the current version - always show it + if ($is_current_version) { $show_version = true; $is_current = true; $final_price = '0.00'; $final_currency = ''; - $decision_reason = 'Showing as CURRENT - is latest version with paid upgrade available'; - } 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)'; + $decision_reason = 'Showing as CURRENT - always show current version'; } else if (!$is_current_version) { //Check if this version is part of ANY upgrade path system (either FROM or TO) $sql = 'SELECT COUNT(*) as path_count diff --git a/api/v2/post/.DS_Store b/api/v2/post/.DS_Store deleted file mode 100644 index 5008ddf..0000000 Binary files a/api/v2/post/.DS_Store and /dev/null differ diff --git a/api/v2/post/history.php b/api/v2/post/history.php index 75eead9..2cbe397 100644 --- a/api/v2/post/history.php +++ b/api/v2/post/history.php @@ -1,5 +1,6 @@ HW; - $sw_version = $test->HEX_FW; + $hw_version = $post_content['payload']['HW']; + $sw_version = $post_content['payload']['HEX_FW']; } else { //GET HW + SW from object diff --git a/api/v2/post/products_software_upgrade_paths.php b/api/v2/post/products_software_upgrade_paths.php index 6b6f9a4..6ce616f 100644 --- a/api/v2/post/products_software_upgrade_paths.php +++ b/api/v2/post/products_software_upgrade_paths.php @@ -14,7 +14,7 @@ $post_content = json_decode($input,true); if (empty($partner->soldto) || $partner->soldto == ''){$soldto_search = '%';} else {$soldto_search = '-%';} //default whereclause -list($whereclause,$condition) = getWhereclauselvl2("software_upgrade_paths",$permission,$partner,''); +list($whereclause,$condition) = getWhereclauselvl2("",$permission,$partner,''); //SET PARAMETERS FOR QUERY $id = $post_content['rowID'] ?? ''; //check for rowID diff --git a/assets/functions.php b/assets/functions.php index 6e50226..ed0e09f 100644 --- a/assets/functions.php +++ b/assets/functions.php @@ -1672,7 +1672,7 @@ function overviewIndicators($warranty, $service, $sw_version, $sw_version_latest $indicator .= 'F'; } else { if ($sw_version == ''){ - $indicator .= 'F'; + $indicator .= 'F'; } else { $indicator .= 'F'; } @@ -1777,7 +1777,7 @@ function availableFirmware($sw_version,$sw_version_latest){ break; default: - $message ='Unknown'; + $message ='✓'; break; } @@ -5339,10 +5339,12 @@ function generateSoftwareInvoice($invoice_data, $order_id, $language = 'US') { $customer_country = $customer['address_country'] ?? ''; // Extract transaction data - $payment_amount = $invoice_data['payment_amount'] ?? 0; - $tax_amount = $invoice_data['tax_amount'] ?? 0; - $shipping_amount = $invoice_data['shipping_amount'] ?? 0; - $discount_amount = $invoice_data['discount_amount'] ?? 0; + $pricing = $invoice_data['pricing'] ?? []; + $payment_amount = $pricing['payment_amount'] ?? $invoice_data['payment_amount'] ?? 0; + $tax_amount = $pricing['tax_total'] ?? $invoice_data['tax_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 $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, '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 @@ -5402,127 +5437,319 @@ function generateSoftwareInvoice($invoice_data, $order_id, $language = 'US') { $lbl_license_key = $translations['license_key'] ?? 'License Key'; $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 $html = ' - +
+ +
+ Laarakkerweg 8
+5061 JR OISTERWIJK
+Nederland
+| ' . htmlspecialchars($lbl_product) . ' | -' . htmlspecialchars($lbl_quantity) . ' | -' . htmlspecialchars($lbl_price) . ' | +Item code | +Description | +Quantity | +Price | +Total |
|---|---|---|---|---|---|---|---|
| ' . htmlspecialchars($item['name']) . ' | -' . htmlspecialchars($item['quantity']) . ' | -' . number_format($item['price'], 2) . ' ' . htmlspecialchars($currency) . ' | -SOFTWARE | +' . htmlspecialchars($item['name']);
+
+ if ($item['serial_number'] !== 'N/A') {
+ $html .= ' Serial: ' . htmlspecialchars($item['serial_number']) . ''; + } + if ($item['license_key'] !== 'Pending') { + $html .= ' License: ' . htmlspecialchars($item['license_key']) . ''; + } + + $html .= ' |
+ ' . htmlspecialchars($item['quantity']) . ' | +€ ' . number_format($item['price'], 2) . ' | +€ ' . number_format($line_total, 2) . ' | + '; } - // Subtotal - $subtotal = $payment_amount - $tax_amount - $shipping_amount + $discount_amount; - $html .= '
| ' . htmlspecialchars($lbl_subtotal) . ': | -' . number_format($subtotal, 2) . ' ' . htmlspecialchars($currency) . ' | -||||||
| ' . htmlspecialchars($lbl_tax) . ': | -' . number_format($tax_amount, 2) . ' ' . htmlspecialchars($currency) . ' | -||||||
| ' . htmlspecialchars($lbl_shipping) . ': | -' . number_format($shipping_amount, 2) . ' ' . htmlspecialchars($currency) . ' | -||||||
| ' . htmlspecialchars($lbl_discount) . ': | --' . number_format($discount_amount, 2) . ' ' . htmlspecialchars($currency) . ' | -||||||
| ' . htmlspecialchars($lbl_total) . ': | -' . number_format($payment_amount, 2) . ' ' . htmlspecialchars($currency) . ' | -||||||
Installing Software...
+Please keep your device connected and do not close this page
+ `; + + // Insert status before the hidden upload section + document.getElementById("uploadSection").parentNode.insertBefore(installStatus, document.getElementById("uploadSection")); - progressBar("60", "Ready to install, starting upload...", "#04AA6D"); - uploadBtn.click(); + progressBar("60", "Starting automatic installation...", "#04AA6D"); + + // Enable the upload button and automatically click it + setTimeout(() => { + uploadBtn.disabled = false; + + // Start monitoring for completion + if (typeof startUploadMonitoring === 'function') { + startUploadMonitoring(); + } + + uploadBtn.click(); + }, 1000); } } catch (error) { diff --git a/custom/bewellwell/settings/bewellwell_settings.php b/custom/bewellwell/settings/bewellwell_settings.php index 8cd76de..1780d98 100644 --- a/custom/bewellwell/settings/bewellwell_settings.php +++ b/custom/bewellwell/settings/bewellwell_settings.php @@ -19,7 +19,7 @@ $color_accent = '#2FAC66'; //'#ececec'; // 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 diff --git a/custom/morvalwatches/mail/email_template_new.php b/custom/morvalwatches/mail/email_template_new.php new file mode 100644 index 0000000..4760382 --- /dev/null +++ b/custom/morvalwatches/mail/email_template_new.php @@ -0,0 +1,102 @@ + + + + + +
+
|
+
+
|
+
Installation Complete!
\' + + \'Your device has been successfully updated
\'; + } + // 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 = \'\' + + \'\' + + \'Installation Failed
\' + + \'Please try again or contact support
\'; + } + 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); + } + }); '; template_footer();