diff --git a/api/v1/post/application.php b/api/v1/post/application.php
index dd567bf..0c397e1 100644
--- a/api/v1/post/application.php
+++ b/api/v1/post/application.php
@@ -15,7 +15,6 @@ if ($action !=''){
//Connect to DB
//------------------------------------------
$pdo = dbConnect($dbname);
-$pdo2 = dbConnect($dbname);
//------------------------------------------
//CONTENT FROM API (POST)
@@ -99,224 +98,108 @@ switch ($action) {
];
$description = json_encode($history_description, JSON_UNESCAPED_UNICODE);
+
// --------------------------------------------
// Check if multiple serialnumbers are provided
// --------------------------------------------
- if(is_array($post_content['sn'])){
- foreach ($post_content['sn'] as $sn){
- //Get equipmentid based on rowID
- $rowID = getrowID($dbname,'rowID','equipment','serialnumber="'.$sn.'"');
- if ($rowID){
- //check if under warranty
- $warranty = getrowID($dbname,'rowID','equipment_history','equipmentid="'.$rowID['rowID'].'" && (type="'.$type9.'" || type="'.$type10.'" || type="'.$type11.'" || type="'.$type12.'")');
- if ($warranty){
- // --------------------------------------------
- // Already under contract
- // --------------------------------------------
- //Serialnumber under warranty
- $message_box[] = $sn.' - '.$register_message_2;
- $communication_check = 1;
- } else
- {
- // --------------------------------------------
- // Not under warranty
- // --------------------------------------------
- //Send user firmware account
- $firmware_account_send = 1;
- //create history
- // Prepare queries
- $sql = 'INSERT INTO equipment_history (equipmentid, type, description, created, createdby,updatedby) VALUES (?,?,?,?,?,?)';
- $stmt = $pdo->prepare($sql);
- $stmt->execute([$rowID['rowID'],$type9,$description,$timestamp,$post_content['email'],$post_content['email']]);
+ // Normalize input to always be an array
+ $serial_numbers = is_array($post_content['sn']) ? $post_content['sn'] : [$post_content['sn']];
- //GET PARTNER DETAILS OF EQUIPMENT
- $partner_equipment = getrowID($dbname,'accounthierarchy','equipment','rowID="'.$rowID['rowID'].'"');
- $partner_equipment = json_decode($partner_equipment['accounthierarchy']);
-
- //Setup partnerhierarchy (salesID)
- $partnerhierarchy =[
- "salesid"=>$partner_equipment->salesid,
- "soldto"=>$partner_equipment->soldto
- ];
-
- //Setup variables for partner
- $partnername = $post_content['organization'];
- $partnernotes = 'created based on user registration';
- $salesID = json_encode($partnerhierarchy, JSON_UNESCAPED_UNICODE);
- $createdby = 'system';
-
- //Check if shipto is empty and if empty search partner or create
- if ($partner_equipment->shipto == ''){
- $partner_shipto = getrowID($dbname,'partnerID','partner','partnername = "'.$partnername.'" && partnertype="'.$partnertype3.'"');
- if ($partner_shipto){
- //Partner exists - Use it
- $partnerhierarchy['shipto'] = $partner_shipto['partnerID'].'-'.$partnername;
- } else {
- //Partner does not exist create
- $sql = 'INSERT INTO partner (partnertype,partnername,salesID,createdby,status) VALUES (?,?,?,?,?)';
- $stmt = $pdo2->prepare($sql);
- $stmt->execute([$partnertype3,$partnername,$salesID,$createdby,'1']);
-
- //Get rowID of created partner and use it
- $partner_rowid = $pdo2->lastInsertId();
- $partnerhierarchy['shipto'] = $partner_rowid.'-'.$partnername;
- }
- } else {
- // Shipto exist use it
- $partnerhierarchy['shipto'] = $partner_equipment->shipto;
- }
- //Check if location is empty and if empty search partner or create
- if ($partner_equipment->location == ''){
- $partner_location = getrowID($dbname,'partnerID','partner','partnername = "'.$partnername.'" && partnertype="'.$partnertype4.'"');
- if ($partner_location){
- //Partner exists - Use it
- $partnerhierarchy['location'] = $partner_location['partnerID'].'-'.$partnername;
-
- } else {
- //Partner does not exist create
- $sql = 'INSERT INTO partner (partnertype,partnername,salesID,createdby,status) VALUES (?,?,?,?,?)';
- $stmt = $pdo2->prepare($sql);
- $stmt->execute([$partnertype4,$partnername,$salesID,$createdby,'1']);
-
- //Get rowID of created partner and use it
- $partner_rowid = $pdo2->lastInsertId();
- $partnerhierarchy['location'] = $partner_rowid.'-'.$partnername;
- }
-
- } else {
- // Location exist use it
- $partnerhierarchy['location'] = $partner_equipment->location;
- }
-
- $shipto = $partnerhierarchy['shipto'] ?? '';
- $partnerhierarchy = json_encode($partnerhierarchy, JSON_UNESCAPED_UNICODE);
- // --------------------------------------------
- // Update equipment record warranty_date, partnerhierarchy, status equipment
- // --------------------------------------------
- $sql = 'UPDATE equipment SET status = ?, warranty_date = ?, accounthierarchy = ?,updatedby = ? WHERE rowID = ?';
- $stmt = $pdo->prepare($sql);
- $stmt->execute(['4',$warranty_extended,$partnerhierarchy,$username,$rowID['rowID']]);
-
- //Add warranty to changelog
- $warranty_user = $post_content['email'] ?? 'system';
- changelog($dbname,'equipment',$rowID['rowID'],'Warranty',$warranty_extended,$warranty_user);
-
- //Serialnumber recognized
- $message_box[] = $sn.' - '.$register_message_3;
- $communication_check = 1;
- }
- } else {
- //Serialnumber not recognized
- $message_box[] = $sn.' - '.$register_message_1;
- }
+ foreach ($serial_numbers as $sn) {
+ // Get equipment ID based on serial number
+ $rowID = getrowID($dbname, 'rowID', 'equipment', 'serialnumber="' . $sn . '"');
+
+ if (!$rowID) {
+ // Serial number not recognized
+ $message_box[] = $sn . ' - ' . $register_message_1;
+ continue;
}
- }
- else {
- // --------------------------------------------
- //Get equipmentid based on rowID
- // --------------------------------------------
- $rowID = getrowID($dbname,'rowID','equipment','serialnumber="'.$post_content['sn'].'"');
- if ($rowID){
- //check if under warranty
- $warranty = getrowID($dbname,'rowID','equipment_history','equipmentid="'.$rowID['rowID'].'" && (type="'.$type9.'" || type="'.$type10.'" || type="'.$type11.'" || type="'.$type12.'")');
- if ($warranty){
- // --------------------------------------------
+
+ // Check if under warranty
+ $warranty_types = [$type9, $type10, $type11, $type12];
+ $warranty_condition = 'equipmentid="' . $rowID['rowID'] . '" && (type="' . implode('" || type="', $warranty_types) . '")';
+ $warranty = getrowID($dbname, 'rowID', 'equipment_history', $warranty_condition);
+
+ if ($warranty) {
// Already under contract
- // --------------------------------------------
- //Serialnumber not recognized
- $message_box[] = $post_content['sn'].' - '.$register_message_2;
- } else
- {
- // --------------------------------------------
- // Not under warranty
- // --------------------------------------------
- $firmware_account_send = 1;
- //create history
- $sql = 'INSERT INTO equipment_history (equipmentid, type, description, created, createdby, updatedby) VALUES (?,?,?,?,?,?)';
- $stmt = $pdo->prepare($sql);
- $stmt->execute([$rowID['rowID'],$type9,$description,$timestamp,$post_content['email'],$post_content['email']]);
-
- //GET PARTNER DETAILS OF EQUIPMENT
- $partner_equipment = getrowID($dbname,'accounthierarchy','equipment','rowID="'.$rowID['rowID'].'"');
- $partner_equipment = json_decode($partner_equipment['accounthierarchy']);
-
- //Setup partnerhierarchy (salesID)
- $partnerhierarchy =[
- "salesid"=>$partner_equipment->salesid,
- "soldto"=>$partner_equipment->soldto
- ];
-
- //Setup variables for partner
- $partnername = $post_content['organization'];
- $partnernotes = 'created based on user registration';
- $salesID = json_encode($partnerhierarchy, JSON_UNESCAPED_UNICODE);
- $createdby = 'system';
-
- //Check if shipto is empty and if empty search partner or create
- if ($partner_equipment->shipto == ''){
- $partner_shipto = getrowID($dbname,'partnerID','partner','partnername = "'.$partnername.'" && partnertype="'.$partnertype3.'"');
- if ($partner_shipto){
- //Partner exists - Use it
- $partnerhierarchy['shipto'] = $partner_shipto['partnerID'].'-'.$partnername;
- } else {
- //Partner does not exist create
- $sql = 'INSERT INTO partner (partnertype, partnername,salesID,createdby,status) VALUES (?,?,?,?,?)';
- $stmt = $pdo2->prepare($sql);
- $stmt->execute([$partnertype3,$partnername,$salesID,$createdby,'1']);
-
- //Get rowID of created partner and use it
- $partner_rowid = $pdo2->lastInsertId();
- $partnerhierarchy['shipto'] = $partner_rowid.'-'.$partnername;
- }
- } else {
- // Shipto exist use it
- $partnerhierarchy['shipto'] = $partner_equipment->shipto;
- }
- //Check if location is empty and if empty search partner or create
- if ($partner_equipment->location == ''){
- $partner_location = getrowID($dbname,'partnerID','partner','partnername = "'.$partnername.'" && partnertype="'.$partnertype4.'"');
- if ($partner_location){
- //Partner exists - Use it
- $partnerhierarchy['location'] = $partner_location['partnerID'].'-'.$partnername;
-
- } else {
- //Partner does not exist create
- $sql = 'INSERT INTO partner (partnertype,partnername,salesID,createdby,status) VALUES (?,?,?,?,?)';
- $stmt = $pdo2->prepare($sql);
- $stmt->execute([$partnertype4,$partnername,$salesID,$createdby,'1']);
-
- //Get rowID of created partner and use it
- $partner_rowid = $pdo2->lastInsertId();
- $partnerhierarchy['location'] = $partner_rowid.'-'.$partnername;
- }
- } else {
- // Location exist use it
- $partnerhierarchy['location'] = $partner_equipment->location;
- }
-
- $partnerhierarchy = json_encode($partnerhierarchy, JSON_UNESCAPED_UNICODE);
-
- // --------------------------------------------
- // Update equipment record warranty_date, partnerhierarchy, status equipment
- // --------------------------------------------
- $sql = 'UPDATE equipment SET status = ?, warranty_date = ?, accounthierarchy = ?, updatedby = ? WHERE rowID = ?';
- $stmt = $pdo->prepare($sql);
- $stmt->execute(['4',$warranty_extended,$partnerhierarchy,$username,$rowID['rowID']]);
-
- //Add warranty to changelog
- $warranty_user = $post_content['email'] ?? 'system';
- changelog($dbname,'equipment',$rowID['rowID'],'Warranty',$warranty_extended,$warranty_user);
-
- //Serialnumber recognized
- $message_box[] = $post_content['sn'].' - '.$register_message_3;
- }
+ $message_box[] = $sn . ' - ' . $register_message_2;
+ $communication_check = 1;
+ continue;
}
- else {
- //Serialnumber not recognized
- $message_box[] = $post_content['sn'].' - '.$register_message_1;
- }
- }
+
+ // Not under warranty - process registration
+ $firmware_account_send = 1;
+
+ // Create history entry
+ $sql = 'INSERT INTO equipment_history (equipmentid, type, description, created, createdby, updatedby) VALUES (?,?,?,?,?,?)';
+ $stmt = $pdo->prepare($sql);
+ $stmt->execute([
+ $rowID['rowID'],
+ $type9,
+ $description,
+ $timestamp,
+ $post_content['email'],
+ $post_content['email']
+ ]);
+
+ // Get partner details of equipment
+ $partner_equipment = getrowID($dbname, 'accounthierarchy', 'equipment', 'rowID="' . $rowID['rowID'] . '"');
+ $partner_equipment = json_decode($partner_equipment['accounthierarchy']);
+
+ // Setup partner hierarchy
+ $partnerhierarchy = [
+ "salesid" => $partner_equipment->salesid,
+ "soldto" => $partner_equipment->soldto
+ ];
+
+ // Setup variables for partner
+ $partnername = $post_content['organization'];
+ $salesID = json_encode($partnerhierarchy, JSON_UNESCAPED_UNICODE);
+ $createdby = 'system';
+
+ // Helper function to get or create partner
+ $getOrCreatePartner = function($partnertype) use ($dbname, $partnername, $salesID, $createdby, $pdo) {
+ $partner = getrowID($dbname, 'partnerID', 'partner', 'partnername = "' . $partnername . '" && partnertype="' . $partnertype . '"');
+
+ if ($partner) {
+ return $partner['partnerID'] . '-' . $partnername;
+ }
+
+ // Partner does not exist - create
+ $sql = 'INSERT INTO partner (partnertype, partnername, salesID, createdby, status) VALUES (?,?,?,?,?)';
+ $stmt = $pdo->prepare($sql);
+ $stmt->execute([$partnertype, $partnername, $salesID, $createdby, '1']);
+
+ $partner_rowid = $pdo->lastInsertId();
+ return $partner_rowid . '-' . $partnername;
+ };
+
+ // Handle shipto
+ $partnerhierarchy['shipto'] = empty($partner_equipment->shipto)
+ ? $getOrCreatePartner($partnertype3)
+ : $partner_equipment->shipto;
+
+ // Handle location
+ $partnerhierarchy['location'] = empty($partner_equipment->location)
+ ? $getOrCreatePartner($partnertype4)
+ : $partner_equipment->location;
+
+ $partnerhierarchy_json = json_encode($partnerhierarchy, JSON_UNESCAPED_UNICODE);
+
+ // Update equipment record
+ $sql = 'UPDATE equipment SET status = ?, warranty_date = ?, accounthierarchy = ?, updatedby = ? WHERE rowID = ?';
+ $stmt = $pdo->prepare($sql);
+ $stmt->execute(['4', $warranty_extended, $partnerhierarchy_json, $username, $rowID['rowID']]);
+
+ // Add warranty to changelog
+ $warranty_user = $post_content['email'] ?? 'system';
+ changelog($dbname, 'equipment', $rowID['rowID'], 'Warranty', $warranty_extended, $warranty_user);
+
+ // Serial number recognized
+ $message_box[] = $sn . ' - ' . $register_message_3;
+ $communication_check = 1;
+ }
// --------------------------------------------
// Send generic account to user for software updates
diff --git a/api/v2/post/marketing_update.php b/api/v2/post/marketing_update.php
index 1062147..8ede166 100644
--- a/api/v2/post/marketing_update.php
+++ b/api/v2/post/marketing_update.php
@@ -19,9 +19,6 @@ if (isAllowed('marketing',$profile,$permission,'U') === 1){
$input = json_decode(file_get_contents('php://input'), true);
$file_id = $input['file_id'] ?? '';
- $folder_id = $input['folder_id'] ?? '';
- $tags = $input['tags'] ?? [];
- $title = $input['title'] ?? '';
if (empty($file_id)) {
echo json_encode(['success' => false, 'error' => 'File ID is required']);
@@ -29,35 +26,61 @@ if (isAllowed('marketing',$profile,$permission,'U') === 1){
}
try {
- // Update file
- $update_sql = 'UPDATE `marketing_files` SET `title` = ?, `folder_id` = ? WHERE `id` = ? AND `accounthierarchy` LIKE ?';
- $stmt = $pdo->prepare($update_sql);
- $stmt->execute([
- $title,
- $folder_id ?: null,
- $file_id,
- $condition
- ]);
-
- if ($stmt->rowCount() === 0) {
+ // First verify the file exists and user has access
+ $check_sql = 'SELECT id FROM `marketing_files` WHERE `id` = ?';
+ $check_stmt = $pdo->prepare($check_sql);
+ $check_stmt->execute([$file_id]);
+
+ if ($check_stmt->rowCount() === 0) {
echo json_encode(['success' => false, 'error' => 'File not found or access denied']);
exit;
}
- // Update tags - first remove existing
- $pdo->prepare('DELETE FROM `marketing_file_tags` WHERE `file_id` = ?')->execute([$file_id]);
+ // Build dynamic UPDATE query for only changed fields
+ $update_fields = [];
+ $update_params = [];
+
+ if (isset($input['title'])) {
+ $update_fields[] = '`title` = ?';
+ $update_params[] = $input['title'];
+ }
+
+ if (isset($input['folder_id'])) {
+ $update_fields[] = '`folder_id` = ?';
+ $update_params[] = $input['folder_id'] ?: null;
+ }
+
+ // Always update updatedby if there are changes
+ if (!empty($update_fields)) {
+ $update_fields[] = '`updatedby` = ?';
+ $update_params[] = $username;
+ $update_params[] = $file_id;
+
+ $update_sql = 'UPDATE `marketing_files` SET ' . implode(', ', $update_fields) . ' WHERE `id` = ?';
+ $stmt = $pdo->prepare($update_sql);
+ $stmt->execute($update_params);
+ }
- // Insert new tags
- if (!empty($tags)) {
- $tag_sql = 'INSERT IGNORE INTO `marketing_tags` (`tag_name`) VALUES (?)';
- $tag_stmt = $pdo->prepare($tag_sql);
+ // Update tags only if provided
+ if (isset($input['tags'])) {
+ // Remove existing tags
+ $pdo->prepare('DELETE FROM `marketing_file_tags` WHERE `file_id` = ?')->execute([$file_id]);
+
+ // Parse and insert new tags
+ $tags_string = $input['tags'];
+ $tags_array = array_filter(array_map('trim', explode(',', $tags_string)));
- $file_tag_sql = 'INSERT INTO `marketing_file_tags` (`file_id`, `tag_id`) SELECT ?, id FROM marketing_tags WHERE tag_name = ?';
- $file_tag_stmt = $pdo->prepare($file_tag_sql);
-
- foreach ($tags as $tag) {
- $tag_stmt->execute([trim($tag)]);
- $file_tag_stmt->execute([$file_id, trim($tag)]);
+ if (!empty($tags_array)) {
+ $tag_sql = 'INSERT IGNORE INTO `marketing_tags` (`tag_name`) VALUES (?)';
+ $tag_stmt = $pdo->prepare($tag_sql);
+
+ $file_tag_sql = 'INSERT INTO `marketing_file_tags` (`file_id`, `tag_id`) SELECT ?, id FROM marketing_tags WHERE tag_name = ?';
+ $file_tag_stmt = $pdo->prepare($file_tag_sql);
+
+ foreach ($tags_array as $tag) {
+ $tag_stmt->execute([$tag]);
+ $file_tag_stmt->execute([$file_id, $tag]);
+ }
}
}
diff --git a/api/v2/post/marketing_upload.php b/api/v2/post/marketing_upload.php
index a84a066..5055f52 100644
--- a/api/v2/post/marketing_upload.php
+++ b/api/v2/post/marketing_upload.php
@@ -53,8 +53,8 @@ if (isAllowed('marketing',$profile,$permission,'C') === 1){
}
// Non-images must be under 10MB
- if (!$isImage && $file['size'] > 10000000) {
- echo json_encode(['success' => false, 'error' => 'File too large. Maximum size is 10MB.']);
+ if (!$isImage && $file['size'] > 25000000) {
+ echo json_encode(['success' => false, 'error' => 'File too large. Maximum size is 25MB.']);
exit;
}
@@ -70,19 +70,28 @@ if (isAllowed('marketing',$profile,$permission,'C') === 1){
}
if (move_uploaded_file($file['tmp_name'], $target_file)) {
- // Generate thumbnail for images
+ // Generate thumbnail
$thumbnail_path = null;
+ $thumb_dir = $target_dir . "thumbs/";
+ if (!file_exists($thumb_dir)) {
+ mkdir($thumb_dir, 0755, true);
+ }
+
+ // Generate thumbnail for images
if (in_array($ext, ['jpg', 'jpeg', 'png', 'gif', 'webp'])) {
- $thumb_dir = $target_dir . "thumbs/";
- if (!file_exists($thumb_dir)) {
- mkdir($thumb_dir, 0755, true);
- }
-
$thumbnail_file = $thumb_dir . $unique_filename;
if (generateThumbnail($target_file, $thumbnail_file, 200, 200)) {
$thumbnail_path = "marketing/uploads/thumbs/" . $unique_filename;
}
}
+ // Generate thumbnail for videos
+ elseif (in_array($ext, ['mp4', 'mov', 'avi'])) {
+ $thumbnail_filename = pathinfo($unique_filename, PATHINFO_FILENAME) . '.jpg';
+ $thumbnail_file = $thumb_dir . $thumbnail_filename;
+ if (generateVideoThumbnail($target_file, $thumbnail_file)) {
+ $thumbnail_path = "marketing/uploads/thumbs/" . $thumbnail_filename;
+ }
+ }
// Insert into database
$insert_sql = 'INSERT INTO `marketing_files` (`title`, `original_filename`, `file_path`, `thumbnail_path`, `file_type`, `file_size`, `folder_id`, `tags`, `createdby`, `accounthierarchy`) VALUES (?,?,?,?,?,?,?,?,?,?)';
@@ -299,4 +308,29 @@ function generateThumbnail($source, $destination, $width, $height) {
return $result;
}
+// Function to generate video thumbnail
+function generateVideoThumbnail($source, $destination) {
+ // Check if ffmpeg is available
+ $ffmpeg = trim(shell_exec('which ffmpeg 2>/dev/null'));
+ if (empty($ffmpeg)) {
+ return false;
+ }
+
+ // Generate thumbnail from video at 1 second mark
+ // -i: input file
+ // -ss: seek to 1 second
+ // -vframes 1: extract one frame
+ // -vf: scale to 200x200 maintaining aspect ratio
+ $command = sprintf(
+ '%s -i %s -ss 00:00:01 -vframes 1 -vf "scale=200:200:force_original_aspect_ratio=decrease" %s 2>&1',
+ escapeshellarg($ffmpeg),
+ escapeshellarg($source),
+ escapeshellarg($destination)
+ );
+
+ exec($command, $output, $return_code);
+
+ return $return_code === 0 && file_exists($destination);
+}
+
?>
\ No newline at end of file
diff --git a/assets/functions.php b/assets/functions.php
index b9ed30c..ed8aff8 100644
--- a/assets/functions.php
+++ b/assets/functions.php
@@ -1771,12 +1771,12 @@ function warrantyStatus($input){
//INCLUDE TRANSLATION FILE
if(isset($_SESSION['country_code'])){
$api_file_language = dirname(__FILE__,2).'/settings/translations/translations_'.strtoupper($_SESSION['country_code']).'.php';
- if (file_exists($api_file_language)){
- include $api_file_language; //Include the code
- }
- else {
- include dirname(__FILE__,2).'/settings/translations/translations_US.php';
- }
+ if (file_exists($api_file_language)){
+ include $api_file_language; //Include the code
+ }
+ else {
+ include dirname(__FILE__,2).'/settings/translations/translations_US.php';
+ }
}
else {
include dirname(__FILE__,2).'/settings/translations/translations_US.php';
@@ -1787,7 +1787,7 @@ function warrantyStatus($input){
if (!empty($input) && $input < $warrantydate){
$warranty_date_due = ''.$warranty_outdated_text.'';
} else {
- $warranty_date_due =''.$warranty_recent.' ('.date('Y-m-d', strtotime($input. ' + 365 days')).')';
+ $warranty_date_due = ''.$warranty_recent.' ('.date('Y-m-d', strtotime($input. ' + 365 days')).')';
}
return $warranty_date_due;
@@ -5526,312 +5526,12 @@ function generateSoftwareInvoice($invoice_data, $order_id, $language = 'US') {
}
}
- // Build HTML invoice
- $html = '
-
-
-
-
- ' . htmlspecialchars($lbl_invoice) . ' - Total Safety Solutions
-
-
-
-
-
-
- ' . htmlspecialchars($lbl_invoice) . '
-
-
-
-
-
-
-
Invoice Date
-
: ' . htmlspecialchars(date('d-m-Y', strtotime($invoice_date))) . '
-
-
-
Invoice Number
-
: ' . htmlspecialchars($order_id) . '
-
-
-
-
-
Reference
-
: Online order
-
-
-
Order number
-
: ' . htmlspecialchars($order_id) . '
-
-
-
-
-
-
-
- | Item code |
- Description |
- Quantity |
- Price |
- Total |
-
-
- ';
-
- foreach ($items as $item) {
- $line_total = $item['price'] * $item['quantity'];
- $html .= '
- | 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) . ' |
-
';
- }
-
- $html .= '
-
-
-
-
-
' . htmlspecialchars($lbl_subtotal) . '
-
€ ' . number_format($subtotal, 2) . '
-
';
-
- if ($tax_amount > 0) {
- $html .= '
-
' . htmlspecialchars($lbl_tax) . '
-
€ ' . number_format($tax_amount, 2) . '
-
';
- } else {
- $html .= '
';
- }
-
- $html .= '
-
' . htmlspecialchars($lbl_total) . '
-
€ ' . number_format($payment_amount, 2) . '
-
-
-
-
-';
-
- return [$html, $customer_email, $order_id];
+ return [$message,$pdf,$customer_email, $order_id];
}
/**
diff --git a/assets/mail/email_template_invoice.php b/assets/mail/email_template_invoice.php
new file mode 100644
index 0000000..f45d166
--- /dev/null
+++ b/assets/mail/email_template_invoice.php
@@ -0,0 +1,138 @@
+
+
+
+
+
+ ' . htmlspecialchars($lbl_invoice) . ' - Total Safety Solutions
+
+
+
+
+
+
+
+
+
+
+
+
+ ' . htmlspecialchars($lbl_invoice) . '
+
+
+
+
+
+ Total Safety Solutions B.V.
+ Laarakkerweg 8
+ 5061 JR OISTERWIJK
+ Nederland
+ |
+
+
+ |
+
+
+
+
+
+
+
+
+
+ | Invoice Date: |
+ ' . htmlspecialchars(date('d-m-Y', strtotime($invoice_date))) . ' |
+
+
+ | Invoice Number: |
+ ' . htmlspecialchars($order_id) . ' |
+
+
+ |
+
+
+
+ | Reference: |
+ Online order |
+
+
+ | Order number: |
+ ' . htmlspecialchars($order_id) . ' |
+
+
+ |
+
+
+
+
+
+
+
+ | Item code |
+ Description |
+ Quantity |
+ Price |
+ Total |
+
+
+ ';
+
+foreach ($items as $item) {
+ $line_total = $item['price'] * $item['quantity'];
+ $message .= '
+ | SOFTWARE |
+ ' . htmlspecialchars($item['name']);
+
+ if ($item['serial_number'] !== 'N/A') {
+ $message .= ' Serial: ' . htmlspecialchars($item['serial_number']) . '';
+ }
+ if ($item['license_key'] !== 'Pending') {
+ $message .= ' License: ' . htmlspecialchars($item['license_key']) . '';
+ }
+
+ $message .= ' |
+ ' . htmlspecialchars($item['quantity']) . ' |
+ € ' . number_format($item['price'], 2) . ' |
+ € ' . number_format($line_total, 2) . ' |
+ ';
+}
+
+$message .= '
+
+
+
+
+
+ | ' . htmlspecialchars($lbl_subtotal) . ' |
+ € ' . number_format($subtotal, 2) . ' |
+ ';
+
+if ($tax_amount > 0) {
+ $message .= '
+ | ' . htmlspecialchars($lbl_tax) . ' |
+ € ' . number_format($tax_amount, 2) . ' |
+ ';
+} else {
+ $message .= '
+ | VAT |
+ included |
+ ';
+}
+
+$message .= '
+ | ' . htmlspecialchars($lbl_total) . ' |
+ € ' . number_format($payment_amount, 2) . ' |
+
+
+
+ |
+
+
+
+ |
+
+
+
+';
\ No newline at end of file
diff --git a/assets/mail/pdf_template_invoice.php b/assets/mail/pdf_template_invoice.php
new file mode 100644
index 0000000..f30e7e9
--- /dev/null
+++ b/assets/mail/pdf_template_invoice.php
@@ -0,0 +1,306 @@
+
+
+
+
+
+ ' . htmlspecialchars($lbl_invoice) . ' - Total Safety Solutions
+
+
+
+
+
+
+ ' . htmlspecialchars($lbl_invoice) . '
+
+
+
+
+
+
+
Invoice Date
+
: ' . htmlspecialchars(date('d-m-Y', strtotime($invoice_date))) . '
+
+
+
Invoice Number
+
: ' . htmlspecialchars($order_id) . '
+
+
+
+
+
Reference
+
: Online order
+
+
+
Order number
+
: ' . htmlspecialchars($order_id) . '
+
+
+
+
+
+
+
+ | Item code |
+ Description |
+ Quantity |
+ Price |
+ Total |
+
+
+ ';
+
+ foreach ($items as $item) {
+ $line_total = $item['price'] * $item['quantity'];
+ $pdf .= '
+ | SOFTWARE |
+ ' . htmlspecialchars($item['name']);
+
+ if ($item['serial_number'] !== 'N/A') {
+ $pdf .= ' Serial: ' . htmlspecialchars($item['serial_number']) . '';
+ }
+ if ($item['license_key'] !== 'Pending') {
+ $pdf .= ' License: ' . htmlspecialchars($item['license_key']) . '';
+ }
+
+ $pdf .= ' |
+ ' . htmlspecialchars($item['quantity']) . ' |
+ € ' . number_format($item['price'], 2) . ' |
+ € ' . number_format($line_total, 2) . ' |
+
';
+ }
+
+$pdf .= '
+
+
+
+
+
' . htmlspecialchars($lbl_subtotal) . '
+
€ ' . number_format($subtotal, 2) . '
+
';
+
+ if ($tax_amount > 0) {
+ $pdf .= '
+
' . htmlspecialchars($lbl_tax) . '
+
€ ' . number_format($tax_amount, 2) . '
+
';
+ } else {
+ $pdf .= '
';
+ }
+
+ $pdf .= '
+
' . htmlspecialchars($lbl_total) . '
+
€ ' . number_format($payment_amount, 2) . '
+
+
+
+
+';
\ No newline at end of file
diff --git a/assets/marketing.js b/assets/marketing.js
index d5581f7..faf20a2 100644
--- a/assets/marketing.js
+++ b/assets/marketing.js
@@ -17,6 +17,13 @@ class MarketingFileManager {
this.folders = []; // Store folders data
this.loadRequestId = 0; // Track the latest load request
+ // Get permissions from PHP
+ this.permissions = window.marketingPermissions || {
+ canCreate: 0,
+ canUpdate: 0,
+ canDelete: 0
+ };
+
this.init();
}
@@ -105,6 +112,18 @@ class MarketingFileManager {
document.getElementById('saveEdit')?.addEventListener('click', () => {
this.saveEdit();
});
+
+ // Edit folder
+ document.getElementById('saveEditFolder')?.addEventListener('click', () => {
+ this.saveEditFolder();
+ });
+
+ // Delete folder
+ document.getElementById('deleteFolder')?.addEventListener('click', () => {
+ if (this.selectedFolder) {
+ this.deleteFolder(this.selectedFolder);
+ }
+ });
}
bindUploadEvents() {
@@ -317,15 +336,29 @@ class MarketingFileManager {
const hasChildren = folder.children && folder.children.length > 0;
const expandIcon = hasChildren ? '' : '';
+ // Only show edit button if user has update permission
+ const editButton = this.permissions.canUpdate === 1
+ ? ``
+ : '';
+
folderItem.innerHTML = `
${expandIcon}
${this.escapeHtml(folder.folder_name)}
(${folder.file_count})
+ ${editButton}
`;
- folderItem.addEventListener('click', () => {
- this.selectFolder(folder.id);
+ folderItem.addEventListener('click', (e) => {
+ // Don't select folder if edit button was clicked
+ if (e.target.closest('.folder-edit-btn')) {
+ e.stopPropagation();
+ this.editFolder(folder);
+ } else {
+ this.selectFolder(folder.id);
+ }
});
container.appendChild(folderItem);
@@ -929,13 +962,20 @@ class MarketingFileManager {
const folderId = document.getElementById('editFolder').value;
const tags = document.getElementById('editTags').value.trim();
- // Prepare update data
- const updateData = {
- file_id: this.selectedFile.id,
- title: title || null,
- folder_id: folderId || null,
- tags: tags ? tags.split(',').map(tag => tag.trim()).filter(tag => tag) : []
- };
+ // Compare with original values to detect changes
+ const originalTitle = this.selectedFile.title || '';
+ const originalFolderId = this.selectedFile.folder_id || '';
+ const originalTags = (this.selectedFile.tags || []).join(', ');
+
+ const hasChanges = title !== originalTitle ||
+ folderId !== originalFolderId ||
+ tags !== originalTags;
+
+ if (!hasChanges) {
+ this.showToast('No changes detected', 'info');
+ this.closeModal(document.getElementById('editModal'));
+ return;
+ }
// Show loading state
const saveBtn = document.getElementById('saveEdit');
@@ -943,22 +983,35 @@ class MarketingFileManager {
saveBtn.innerHTML = ' Saving...';
saveBtn.disabled = true;
+ // Prepare FormData with only changed fields
+ const formData = new FormData();
+ formData.append('file_id', this.selectedFile.id);
+
+ if (title !== originalTitle) {
+ formData.append('title', title);
+ }
+ if (folderId !== originalFolderId) {
+ formData.append('folder_id', folderId);
+ }
+ if (tags !== originalTags) {
+ formData.append('tags', tags);
+ }
+
// Send update request
- fetch('./marketing.php?action=update_file', {
+ fetch('index.php?page=marketing&action=marketing_update', {
method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- },
- body: JSON.stringify(updateData)
+ body: formData
})
.then(response => response.json())
.then(data => {
if (data.success) {
this.showToast('File updated successfully!', 'success');
- this.closeModal(document.getElementById('editModal'));
- this.loadFiles(); // Reload to show changes
+ // Reload window to reflect changes
+ setTimeout(() => {
+ window.location.reload();
+ }, 500);
} else {
- throw new Error(data.message || 'Failed to update file');
+ throw new Error(data.error || data.message || 'Failed to update file');
}
})
.catch(error => {
@@ -994,6 +1047,193 @@ class MarketingFileManager {
this.renderUploadQueue();
document.getElementById('startUpload').disabled = this.uploadQueue.length === 0;
}
+
+ // Edit folder functionality
+ editFolder(folder) {
+ this.selectedFolder = folder;
+ this.showEditFolderModal();
+ this.populateEditFolderModal(folder);
+ }
+
+ showEditFolderModal() {
+ const modal = document.getElementById('editFolderModal');
+ if (modal) {
+ this.showModal(modal);
+ }
+ }
+
+ populateEditFolderModal(folder) {
+ // Populate folder name
+ const nameInput = document.getElementById('editFolderName');
+ if (nameInput) {
+ nameInput.value = folder.folder_name || '';
+ }
+
+ // Populate parent folder select
+ const parentSelect = document.getElementById('editParentFolder');
+ if (parentSelect) {
+ parentSelect.innerHTML = '';
+ this.addFolderOptionsExcluding(parentSelect, this.folders, folder.id);
+
+ // Select current parent
+ if (folder.parent_id) {
+ parentSelect.value = folder.parent_id;
+ }
+ }
+
+ // Populate description
+ const descInput = document.getElementById('editFolderDescription');
+ if (descInput) {
+ descInput.value = folder.description || '';
+ }
+ }
+
+ addFolderOptionsExcluding(select, folders, excludeId, level = 0) {
+ // Add folders but exclude the current folder and its children
+ folders.forEach(folder => {
+ if (folder.id !== excludeId && !this.isFolderDescendant(folder, excludeId)) {
+ const option = document.createElement('option');
+ option.value = folder.id;
+ option.textContent = ' '.repeat(level) + folder.folder_name;
+ select.appendChild(option);
+
+ if (folder.children && folder.children.length > 0) {
+ this.addFolderOptionsExcluding(select, folder.children, excludeId, level + 1);
+ }
+ }
+ });
+ }
+
+ isFolderDescendant(folder, ancestorId) {
+ // Check if folder is a descendant of ancestorId
+ if (folder.id === ancestorId) return true;
+ if (folder.children) {
+ for (let child of folder.children) {
+ if (this.isFolderDescendant(child, ancestorId)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ saveEditFolder() {
+ if (!this.selectedFolder) return;
+
+ const folderName = document.getElementById('editFolderName').value.trim();
+ const parentId = document.getElementById('editParentFolder').value;
+ const description = document.getElementById('editFolderDescription').value.trim();
+
+ // Compare with original values
+ const originalName = this.selectedFolder.folder_name || '';
+ const originalParentId = this.selectedFolder.parent_id || '';
+ const originalDescription = this.selectedFolder.description || '';
+
+ const hasChanges = folderName !== originalName ||
+ parentId !== originalParentId ||
+ description !== originalDescription;
+
+ if (!hasChanges) {
+ this.showToast('No changes detected', 'info');
+ this.closeModal(document.getElementById('editFolderModal'));
+ return;
+ }
+
+ if (!folderName) {
+ this.showToast('Folder name is required', 'error');
+ return;
+ }
+
+ // Show loading state
+ const saveBtn = document.getElementById('saveEditFolder');
+ const originalText = saveBtn.innerHTML;
+ saveBtn.innerHTML = ' Saving...';
+ saveBtn.disabled = true;
+
+ // Prepare FormData
+ const formData = new FormData();
+ formData.append('id', this.selectedFolder.id);
+
+ if (folderName !== originalName) {
+ formData.append('folder_name', folderName);
+ }
+ if (parentId !== originalParentId) {
+ formData.append('parent_id', parentId);
+ }
+ if (description !== originalDescription) {
+ formData.append('description', description);
+ }
+
+ // Send update request
+ fetch('index.php?page=marketing&action=marketing_folders', {
+ method: 'POST',
+ body: formData
+ })
+ .then(response => response.json())
+ .then(data => {
+ if (data.success) {
+ this.showToast('Folder updated successfully!', 'success');
+ // Reload window to reflect changes
+ setTimeout(() => {
+ window.location.reload();
+ }, 500);
+ } else {
+ throw new Error(data.error || data.message || 'Failed to update folder');
+ }
+ })
+ .catch(error => {
+ console.error('Update folder error:', error);
+ this.showToast('Error updating folder: ' + error.message, 'error');
+ })
+ .finally(() => {
+ // Restore button state
+ saveBtn.innerHTML = originalText;
+ saveBtn.disabled = false;
+ });
+ }
+
+ async deleteFolder(folder) {
+ if (!confirm(`Are you sure you want to delete the folder "${folder.folder_name}"? This action cannot be undone.`)) {
+ return;
+ }
+
+ try {
+ const formData = new FormData();
+ formData.append('id', folder.id);
+ formData.append('delete', 'true');
+
+ const response = await fetch('index.php?page=marketing&action=marketing_folders', {
+ method: 'POST',
+ body: formData
+ });
+
+ if (!response.ok) {
+ throw new Error(`HTTP error! status: ${response.status}`);
+ }
+
+ const text = await response.text();
+ if (!text || text.trim() === '') {
+ throw new Error('Empty response from server');
+ }
+
+ const data = JSON.parse(text);
+
+ if (data && (data.success || !data.error)) {
+ this.closeModal(document.getElementById('editFolderModal'));
+ this.showToast('Folder deleted successfully!', 'success');
+ // Reload window to reflect changes
+ setTimeout(() => {
+ window.location.reload();
+ }, 500);
+ } else if (data.error) {
+ throw new Error(data.error);
+ } else {
+ throw new Error('Unexpected response format');
+ }
+ } catch (error) {
+ this.showToast(error.message || 'Error deleting folder', 'error');
+ }
+ }
}
// Initialize when DOM is ready
diff --git a/assets/softwaretool.js b/assets/softwaretool.js
index 280feaf..a5db168 100644
--- a/assets/softwaretool.js
+++ b/assets/softwaretool.js
@@ -15,6 +15,71 @@ let reader;
let readableStreamClosed;
let keepReading = true;
+// Browser compatibility check
+let isSerialSupported = false;
+
+// Check browser compatibility on page load
+function checkBrowserCompatibility() {
+ isSerialSupported = 'serial' in navigator;
+
+ if (!isSerialSupported) {
+ // Show warning banner
+ showBrowserWarningBanner();
+ // Disable connect button
+ disableSerialFunctionality();
+ }
+
+ return isSerialSupported;
+}
+
+function showBrowserWarningBanner() {
+ const connectDevice = document.getElementById("connectdevice");
+ if (!connectDevice) return;
+
+ const warningBanner = document.createElement("div");
+ warningBanner.id = "browserWarningBanner";
+ warningBanner.style.cssText = `
+ background: linear-gradient(135deg, #dc3545 0%, #c82333 100%);
+ color: white;
+ padding: 15px 20px;
+ border-radius: 8px;
+ margin-bottom: 15px;
+ display: flex;
+ align-items: center;
+ gap: 15px;
+ box-shadow: 0 4px 12px rgba(220, 53, 69, 0.3);
+ `;
+
+ warningBanner.innerHTML = `
+
+
+
Browser Not Supported
+
+ Please use Chrome, Edge, or Opera to access device connectivity features.
+
+
+ `;
+
+ connectDevice.parentNode.insertBefore(warningBanner, connectDevice);
+}
+
+function disableSerialFunctionality() {
+ const connectButton = document.getElementById("connectButton");
+ if (connectButton) {
+ connectButton.disabled = true;
+ connectButton.style.opacity = "0.5";
+ connectButton.style.cursor = "not-allowed";
+ connectButton.title = "Browser is not supported. Please use Chrome, Edge, or Opera.";
+ }
+}
+
+// Call on page load
+if (document.readyState === 'loading') {
+ document.addEventListener('DOMContentLoaded', checkBrowserCompatibility);
+} else {
+ checkBrowserCompatibility();
+}
+
// Function to log communication to API (reused from scripts.js)
async function logCommunication(data, direction) {
// Only log if debug mode is enabled
@@ -69,6 +134,13 @@ function progressBar(percentage, message, color){
// Connect device for software tool
async function connectDeviceForSoftware() {
+ // Browser compatibility check
+ if (!isSerialSupported) {
+ progressBar("100", "Browser not supported - Please use Chrome, Edge, or Opera", "#dc3545");
+ await logCommunication('Connection attempt failed: Web Serial API not supported in browser', 'error');
+ return;
+ }
+
//clear input
readBar.innerHTML = '';
serialResultsDiv.innerHTML = '';
@@ -162,11 +234,18 @@ async function connectDeviceForSoftware() {
} catch (error) {
await logCommunication(`Connection error: ${error.message}`, 'error');
- // 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");
+ // Improved error messages with specific cases
+ if (error.name === 'NotSupportedError' || !navigator.serial) {
+ progressBar("100", "Browser not supported - Please use Chrome, Edge, or Opera", "#dc3545");
+ } else if (error.message && error.message.includes('No port selected by the user')) {
+ progressBar("100", "No device selected - Please try again", "#ff6666");
+ } else if (error.name === 'NetworkError') {
+ progressBar("100", "Connection failed - Please check device connection", "#ff6666");
+ } else if (error.name === 'InvalidStateError') {
+ progressBar("100", "Port already in use - Refreshing page...", "#ff9800");
+ setTimeout(() => location.reload(), 2000);
} else {
- progressBar("100", "Error: " + error.message, "#ff6666");
+ progressBar("100", "Connection error: " + error.message, "#ff6666");
}
}
}
diff --git a/equipment.php b/equipment.php
index b0e2cf1..e800dd3 100644
--- a/equipment.php
+++ b/equipment.php
@@ -54,11 +54,11 @@ $history = ioServer($api_url,'');
if (!empty($history)){$history = json_decode($history);}else{$history = null;}
//CALL TO API FOR EQUIPMENT DATA
-$api_url = '/v1/equipment_data/equipmentid='.$responses->equipmentID;
+$api_url = '/v2/equipment_data/equipmentid='.$responses->equipmentID;
$equipment_data = ioServer($api_url,'');
//Decode Payload
-if (!empty($equipment_data )){$equipment_data = decode_payload($equipment_data );}else{$equipment_data = null;}
+if (!empty($equipment_data )){$equipment_data = json_decode($equipment_data );}else{$equipment_data = null;}
//CALL TO API FOR CUSTOMER AND WARRANTY DATA (type = customer,Warranty in history)
$api_url = '/v2/history/equipmentID='.$responses->equipmentID.'&type=customer,Warranty';
@@ -83,10 +83,10 @@ if (is_array($registration_data) && count($registration_data) > 0) {
}
//GET PRODUCTS_SOFTWARE
-$api_url = '/v1/products_software/productrowid='.$responses->productrowid.'&status=1';
+$api_url = '/v2/products_software_versions/hw_version='.$responses->hw_version.'&status=1';
$products_software = ioServer($api_url,'');
//Decode Payload
-if (!empty($products_software)){$products_software = decode_payload($products_software);}else{$products_software = null;}
+if (!empty($products_software)){$products_software = json_decode($products_software);}else{$products_software = null;}
//------------------------------
//Variables
@@ -96,6 +96,17 @@ $warrantydate = warrantyStatus($responses->warranty_date);
$service_date_due = serviceStatus($responses->service_date);
$firmware_status = availableFirmware($responses->sw_version, $responses->sw_version_latest);
+// Get upgrade version text if exists
+$sw_version_upgrade_text = '';
+if (!empty($responses->sw_version_upgrade) && isset($products_software) && $products_software != '') {
+ foreach ($products_software as $products_soft) {
+ if ($products_soft->rowID == $responses->sw_version_upgrade) {
+ $sw_version_upgrade_text = $products_soft->version;
+ break;
+ }
+ }
+}
+
//Calculate Healthindex based on last test
$total_score = assetHealthIndex($_SESSION['profile'],$_SESSION['permission'],$equipment_data,0);
@@ -117,15 +128,12 @@ if ($update_allowed === 1){
//GET ALL POST DATA
$data = json_encode($_POST, JSON_UNESCAPED_UNICODE);
- //Secure data
- $payload = generate_payload($data);
-
//API call
- $responses = ioServer('/v1/history', $payload);
+ $responses = ioServer('/v2/history', $data);
if ($responses === 'NOK'){
} else {
- header('Location: index.php?page=equipment&equipmentID='.$_POST['equipmentid'].'&success_msg=2');
+ header('Location: index.php?page=equipment&equipmentID='.$_POST['equipmentid'].'&success_msg=2');
exit;
}
}
@@ -261,7 +269,7 @@ $view .= '
| '.$software_status.' |
- '.$firmware_status.' |
+ '.$firmware_status.((!empty($responses->sw_version_upgrade)) ? ' ' : '').' |
| '.$equipment_label5.' |
diff --git a/equipment_manage.php b/equipment_manage.php
index 3c179a8..c0f8adc 100644
--- a/equipment_manage.php
+++ b/equipment_manage.php
@@ -85,10 +85,8 @@ if (isset($_GET['equipmentID'])) {
$_POST['geolocation'] = json_encode($_POST['geolocation'],JSON_UNESCAPED_UNICODE);
//GET ALL POST DATA
$data = json_encode($_POST, JSON_UNESCAPED_UNICODE);
- //Secure data
- $payload = generate_payload($data);
//API call
- $responses = ioServer('/v1/equipments', $payload);
+ $responses = ioServer('/v2/equipments', $data);
if ($responses === 'NOK'){
} else {
@@ -102,10 +100,8 @@ if (isset($_GET['equipmentID'])) {
if (isset($_POST['delete'])) {
//GET ALL POST DATA
$data = json_encode($_POST , JSON_UNESCAPED_UNICODE);
- //Secure data
- $payload = generate_payload($data);
//API call
- $responses = ioServer('/v1/equipments', $payload);
+ $responses = ioServer('/v2/equipments', $data);
// Redirect and delete equipment
if ($responses === 'NOK'){
@@ -123,10 +119,8 @@ if (isset($_GET['equipmentID'])) {
$_POST['geolocation'] = json_encode($_POST['geolocation'],JSON_UNESCAPED_UNICODE);
//GET ALL POST DATA
$data = json_encode($_POST, JSON_UNESCAPED_UNICODE);
- //Secure data
- $payload = generate_payload($data);
//API call
- $responses = ioServer('/v1/equipments', $payload);
+ $responses = ioServer('/v2/equipments', $data);
if ($responses === 'NOK'){
} else {
diff --git a/equipments_mass_update.php b/equipments_mass_update.php
index 9f37425..5225e6c 100644
--- a/equipments_mass_update.php
+++ b/equipments_mass_update.php
@@ -54,11 +54,11 @@ if ($update_allowed === 1){
foreach ($excel_data_1 as $key => $val){
//GET ROW ID
- $api_url = '/v1/application/serialnumber='.$val.'/get_rowID';
+ $api_url = '/v2/application/serialnumber='.$val.'/get_rowID';
$responses = ioServer($api_url,'');
//Decode Payload
- if (!empty($responses)){$responses = decode_payload($responses);}else{$responses = null;}
+ if (!empty($responses)){$responses = json_decode($responses);}else{$responses = null;}
//IF rowID is found add to array
if (isset ($responses->rowID)){
@@ -92,10 +92,8 @@ if ($update_allowed === 1){
foreach ($output_excel as $data_to_update){
$data = json_encode($data_to_update, JSON_UNESCAPED_UNICODE);
- //Secure data
- $payload = generate_payload($data);
//API call
- $responses = ioServer('/v1/equipments', $payload);
+ $responses = ioServer('/v2/equipments', $data);
if ($responses === 'NOK'){
}
diff --git a/factuur.php b/factuur.php
index 713af31..5145079 100644
--- a/factuur.php
+++ b/factuur.php
@@ -59,7 +59,7 @@ if (!empty($invoice_data['customer']['language'])) {
// Generate invoice HTML
//+++++++++++++++++++++++++++++++++++++++++++++++++++++
-list($data, $customer_email, $order_id) = generateSoftwareInvoice($invoice_data, $order_number, $invoice_language);
+list($message,$pdf, $customer_email, $order_id) = generateSoftwareInvoice($invoice_data, $order_number, $invoice_language);
//+++++++++++++++++++++++++++++++++++++++++++++++++++++
@@ -67,7 +67,7 @@ list($data, $customer_email, $order_id) = generateSoftwareInvoice($invoice_data,
//+++++++++++++++++++++++++++++++++++++++++++++++++++++
if (isset($_GET['output']) && $_GET['output'] === 'html') {
// Output HTML directly to browser
- echo $data;
+ echo $message;
exit;
}
@@ -82,7 +82,7 @@ $options->set('isRemoteEnabled', true);
$dompdf = new Dompdf($options);
// Load HTML content
-$dompdf->loadHtml($data);
+$dompdf->loadHtml($pdf);
// Setup paper size and orientation
$dompdf->setPaper('A4', 'portrait');
@@ -101,7 +101,6 @@ $file_name = 'Factuur - ' . $order_id;
if (isset($_POST['email_invoice'])) {
$to = $customer_email;
$subject = 'Factuur - ' . $order_id;
- $message = $data;
$attachment = $dompdf->output();
$attachment_name = $file_name . '.pdf';
@@ -118,7 +117,6 @@ if (isset($_POST['email_invoice'])) {
if (isset($_POST['email_invoice_to_admin'])) {
$to = $customer_email;
$subject = 'Factuur - ' . $order_id;
- $message = $data;
$attachment = $dompdf->output();
$attachment_name = $file_name . '.pdf';
diff --git a/licenses.php b/licenses.php
index 30e1860..892dcdd 100644
--- a/licenses.php
+++ b/licenses.php
@@ -269,10 +269,10 @@ $view .= '
'.$response->license_key.' |
'.$response->version_name.' |
'.$status_text.' |
- '.($response->transaction_id ?? '-').' |
+ '.(isset($response->transaction_id) && strpos($response->transaction_id, 'SC') === 0 ? ''.$response->transaction_id.' ' : ($response->transaction_id ?? '-')).' |
'.$starts_display.' |
'.$expires_display.' |
- '.($response->assigned_serial ?? '-').' |
+ '.(isset($response->assigned_serial) ? ''.$response->assigned_serial.' ' : ($response->assigned_serial ?? '-')).' |
';
}
diff --git a/marketing.php b/marketing.php
index abdee3c..98a6ee9 100644
--- a/marketing.php
+++ b/marketing.php
@@ -40,13 +40,30 @@ if (isset($_GET['action'])) {
// Marketing folders
if ($action === 'marketing_folders') {
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
- // Create folder - use standard format expected by POST API
- $payload = [
- 'folder_name' => $_POST['folder_name'] ?? '',
- 'parent_id' => $_POST['parent_id'] ?? '',
- 'description' => $_POST['description'] ?? ''
- // rowID is empty = insert (standard pattern)
- ];
+ // Pass through all POST data for create/update/delete
+ $payload = [];
+
+ // Always include id if present (for update/delete)
+ if (isset($_POST['id'])) {
+ $payload['id'] = $_POST['id'];
+ }
+
+ // Include delete flag if present
+ if (isset($_POST['delete'])) {
+ $payload['delete'] = $_POST['delete'];
+ }
+
+ // Only include other fields if they were sent
+ if (isset($_POST['folder_name'])) {
+ $payload['folder_name'] = $_POST['folder_name'];
+ }
+ if (isset($_POST['parent_id'])) {
+ $payload['parent_id'] = $_POST['parent_id'];
+ }
+ if (isset($_POST['description'])) {
+ $payload['description'] = $_POST['description'];
+ }
+
$response = ioServer('/v2/marketing_folders', json_encode($payload));
} else {
// Get folders
@@ -128,7 +145,19 @@ if (isset($_GET['action'])) {
// Marketing update
if ($action === 'marketing_update' && $_SERVER['REQUEST_METHOD'] === 'POST') {
- $payload = $_POST;
+ $payload = ['file_id' => $_POST['file_id'] ?? ''];
+
+ // Only include fields that were actually sent
+ if (isset($_POST['title'])) {
+ $payload['title'] = $_POST['title'];
+ }
+ if (isset($_POST['folder_id'])) {
+ $payload['folder_id'] = $_POST['folder_id'];
+ }
+ if (isset($_POST['tags'])) {
+ $payload['tags'] = $_POST['tags'];
+ }
+
$response = ioServer('/v2/marketing_update', json_encode($payload));
header('Content-Type: application/json');
echo $response;
@@ -401,15 +430,64 @@ template_header('Marketing', 'marketing');
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
'.$bearertoken.'
@@ -276,8 +283,11 @@ echo '
var MOLLIE_ENABLED = '.(mollie_enabled ? 'true' : 'false').';
var PAYPAL_ENABLED = '.(paypal_enabled ? 'true' : 'false').';
var PAY_ON_DELIVERY_ENABLED = '.(pay_on_delivery_enabled ? 'true' : 'false').';
-
- // Translation variables
+ // Early browser compatibility check
+ if (!("serial" in navigator)) {
+ console.warn("Web Serial API is not supported in this browser");
+ }
+ // Translation variables
var TRANS_NAME = "'.($account_name ?? 'Name').'";
var TRANS_EMAIL = "'.($account_email ?? 'Email').'";
var TRANS_ADDRESS = "'.($shipping_address ?? 'Address').'";
diff --git a/style/marketing.css b/style/marketing.css
index c1b2cce..8668595 100644
--- a/style/marketing.css
+++ b/style/marketing.css
@@ -156,6 +156,7 @@
border-radius: 4px;
transition: all 0.2s;
font-size: 0.9rem;
+ position: relative;
}
.folder-item:hover {
@@ -180,6 +181,26 @@
color: var(--color-text-light, #6c757d);
}
+.folder-edit-btn {
+ display: none;
+ background: none;
+ border: none;
+ padding: 0.25rem 0.5rem;
+ cursor: pointer;
+ color: var(--color-text-light, #6c757d);
+ border-radius: 4px;
+ transition: all 0.2s;
+}
+
+.folder-item:hover .folder-edit-btn {
+ display: inline-block;
+}
+
+.folder-edit-btn:hover {
+ background-color: var(--color-primary-light, #cce7f0);
+ color: var(--color-primary, #005655);
+}
+
.expand-icon {
cursor: pointer;
transition: transform 0.2s;
diff --git a/webhook_mollie.php b/webhook_mollie.php
index 43f5951..d668b3e 100644
--- a/webhook_mollie.php
+++ b/webhook_mollie.php
@@ -250,12 +250,12 @@ try {
}
// Generate invoice HTML (using custom template for software upgrades)
- list($data,$customer_email,$order_id) = generateSoftwareInvoice($invoice_cust,$orderId,$invoice_language);
+ list($message,$pdf,$customer_email,$order_id) = generateSoftwareInvoice($invoice_cust,$orderId,$invoice_language);
//+++++++++++++++++++++++++++++++++++++++++++++++++++++
//CREATE PDF using DomPDF
//+++++++++++++++++++++++++++++++++++++++++++++++++++++
- $dompdf->loadHtml($data);
+ $dompdf->loadHtml($pdf);
$dompdf->setPaper('A4', 'portrait');
$dompdf->render();
$subject = 'Software Upgrade - Invoice: '.$order_id;
@@ -265,12 +265,12 @@ try {
//Send email via PHPMailer
//+++++++++++++++++++++++++++++++++++++++++++++++++++++
// The send_mail function will exit on error and debuglog the error
- $mail_result = send_mail($customer_email, $subject, $data, $attachment, $subject);
+ $mail_result = send_mail($customer_email, $subject, $message, $attachment, $subject);
// Send to bookkeeping if configured
if(invoice_bookkeeping){
debuglog("WEBHOOK: Sending to bookkeeping: " . email_bookkeeping);
- send_mail(email_bookkeeping, $subject, $data, $attachment, $subject);
+ send_mail(email_bookkeeping, $subject, $message, $attachment, $subject);
}
} else {
debuglog("WEBHOOK: No invoice data found for invoice_id: $invoice_id");
diff --git a/webhook_paypal.php b/webhook_paypal.php
index 2691d85..084e955 100644
--- a/webhook_paypal.php
+++ b/webhook_paypal.php
@@ -294,12 +294,12 @@ try {
}
// Generate invoice HTML (using custom template for software upgrades)
- list($data,$customer_email,$order_id) = generateSoftwareInvoice($invoice_cust,$orderId,$invoice_language);
+ list($message,$pdf,$customer_email,$order_id) = generateSoftwareInvoice($invoice_cust,$orderId,$invoice_language);
//+++++++++++++++++++++++++++++++++++++++++++++++++++++
//CREATE PDF using DomPDF
//+++++++++++++++++++++++++++++++++++++++++++++++++++++
- $dompdf->loadHtml($data);
+ $dompdf->loadHtml($pdf);
$dompdf->setPaper('A4', 'portrait');
$dompdf->render();
$subject = 'Software Upgrade - Invoice: '.$order_id;
@@ -308,12 +308,12 @@ try {
//+++++++++++++++++++++++++++++++++++++++++++++++++++++
//Send email via PHPMailer
//+++++++++++++++++++++++++++++++++++++++++++++++++++++
- $mail_result = send_mail($customer_email, $subject, $data, $attachment, $subject);
+ $mail_result = send_mail($customer_email, $subject, $message, $attachment, $subject);
// Send to bookkeeping if configured
if(invoice_bookkeeping){
debuglog("PAYPAL WEBHOOK: Sending to bookkeeping: " . email_bookkeeping);
- send_mail(email_bookkeeping, $subject, $data, $attachment, $subject);
+ send_mail(email_bookkeeping, $subject, $message, $attachment, $subject);
}
} else {
debuglog("PAYPAL WEBHOOK: No invoice data found for invoice_id: $invoice_id");