Refactor API endpoints and update invoice generation
- Updated API calls in equipment.php, equipment_manage.php, and equipments_mass_update.php to use v2 endpoints. - Changed payload decoding from decode_payload to json_decode for consistency. - Enhanced invoice generation in factuur.php and webhook files to use a new email template and PDF structure. - Added new email and PDF templates for invoices to improve formatting and readability. - Improved marketing folder handling in marketing.php with better payload management. - Updated CSS for marketing to enhance UI interactions. - Added JavaScript checks for browser compatibility in softwaretool.php. - Adjusted user permissions in settingsprofiles.php to reflect new features.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -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 = '<span class="status warranty_outdated">'.$warranty_outdated_text.'</span>';
|
||||
} else {
|
||||
$warranty_date_due ='<span class="">'.$warranty_recent.' ('.date('Y-m-d', strtotime($input. ' + 365 days')).')</span>';
|
||||
$warranty_date_due = '<span class="">'.$warranty_recent.' ('.date('Y-m-d', strtotime($input. ' + 365 days')).')</span>';
|
||||
}
|
||||
|
||||
return $warranty_date_due;
|
||||
@@ -5526,312 +5526,12 @@ function generateSoftwareInvoice($invoice_data, $order_id, $language = 'US') {
|
||||
}
|
||||
}
|
||||
|
||||
// Build HTML invoice
|
||||
$html = '<!DOCTYPE html>
|
||||
<html lang="' . strtolower($language) . '">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>' . htmlspecialchars($lbl_invoice) . ' - Total Safety Solutions</title>
|
||||
<style>
|
||||
@page {margin: 220px 50px; }
|
||||
// Build HTML for PDF and EMAIL
|
||||
include dirname(__FILE__,2).'/assets/mail/email_template_invoice.php';
|
||||
include dirname(__FILE__,2).'/assets/mail/pdf_template_invoice.php';
|
||||
|
||||
|
||||
body {
|
||||
font-family: "DejaVu Sans", Arial, sans-serif;
|
||||
color: #000;
|
||||
font-size: 11px;
|
||||
line-height: 1.4;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#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>
|
||||
</head>
|
||||
<body>
|
||||
<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="company-header">
|
||||
<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 class="invoice-details">
|
||||
<div class="invoice-left">
|
||||
<div class="detail-row">
|
||||
<div class="detail-label">Invoice Date</div>
|
||||
<div class="detail-value">: ' . htmlspecialchars(date('d-m-Y', strtotime($invoice_date))) . '</div>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<div class="detail-label">Invoice Number</div>
|
||||
<div class="detail-value">: ' . htmlspecialchars($order_id) . '</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="invoice-right">
|
||||
<div class="detail-row">
|
||||
<div class="detail-label">Reference</div>
|
||||
<div class="detail-value">: Online order</div>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<div class="detail-label">Order number</div>
|
||||
<div class="detail-value">: ' . htmlspecialchars($order_id) . '</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<table class="items-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Item code</th>
|
||||
<th>Description</th>
|
||||
<th class="qty-col">Quantity</th>
|
||||
<th class="price-col">Price</th>
|
||||
<th class="total-col">Total</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>';
|
||||
|
||||
foreach ($items as $item) {
|
||||
$line_total = $item['price'] * $item['quantity'];
|
||||
$html .= '<tr>
|
||||
<td>SOFTWARE</td>
|
||||
<td>' . htmlspecialchars($item['name']);
|
||||
|
||||
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>';
|
||||
}
|
||||
|
||||
$html .= '</td>
|
||||
<td class="qty-col">' . htmlspecialchars($item['quantity']) . ' </td>
|
||||
<td class="price-col">€ ' . number_format($item['price'], 2) . '</td>
|
||||
<td class="total-col">€ ' . number_format($line_total, 2) . '</td>
|
||||
</tr>';
|
||||
}
|
||||
|
||||
$html .= '</tbody>
|
||||
</table>
|
||||
|
||||
<div class="totals-section">
|
||||
<div class="total-row">
|
||||
<div class="total-label">' . htmlspecialchars($lbl_subtotal) . '</div>
|
||||
<div class="total-amount">€ ' . number_format($subtotal, 2) . '</div>
|
||||
</div>';
|
||||
|
||||
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>';
|
||||
}
|
||||
|
||||
$html .= '<div class="total-row final-total">
|
||||
<div class="total-label">' . htmlspecialchars($lbl_total) . '</div>
|
||||
<div class="total-amount">€ ' . number_format($payment_amount, 2) . '</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>';
|
||||
|
||||
return [$html, $customer_email, $order_id];
|
||||
return [$message,$pdf,$customer_email, $order_id];
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
138
assets/mail/email_template_invoice.php
Normal file
138
assets/mail/email_template_invoice.php
Normal file
@@ -0,0 +1,138 @@
|
||||
<?php
|
||||
|
||||
$message = '
|
||||
<!DOCTYPE html>
|
||||
<html lang="' . strtolower($language) . '">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>' . htmlspecialchars($lbl_invoice) . ' - Total Safety Solutions</title>
|
||||
</head>
|
||||
<body style="font-family: Arial, Helvetica, sans-serif; color: #000000; font-size: 14px; line-height: 1.6; margin: 0; padding: 0; background-color: #f4f4f4;">
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%" style="background-color: #f4f4f4;">
|
||||
<tr>
|
||||
<td align="center" style="padding: 20px 0;">
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="600" style="background-color: #ffffff; max-width: 600px;">
|
||||
|
||||
<!-- Content -->
|
||||
<tr>
|
||||
<td style="padding: 30px 40px;">
|
||||
|
||||
<!-- Invoice Title -->
|
||||
<h1 style="font-size: 24px; font-weight: bold; color: #2c5f5d; margin: 0 0 25px 0;">' . htmlspecialchars($lbl_invoice) . '</h1>
|
||||
|
||||
<!-- Company Header -->
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%" style="margin-bottom: 25px;">
|
||||
<tr>
|
||||
<td width="50%" style="vertical-align: top; font-size: 13px; line-height: 1.5;">
|
||||
<strong style="color: #2c5f5d; font-size: 14px;">Total Safety Solutions B.V.</strong><br>
|
||||
Laarakkerweg 8<br>
|
||||
5061 JR OISTERWIJK<br>
|
||||
Nederland
|
||||
</td>
|
||||
<td width="50%" style="vertical-align: top; text-align: right;">
|
||||
<!-- Contact details if needed -->
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!-- Invoice Details -->
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%" style="margin-bottom: 25px; font-size: 13px;">
|
||||
<tr>
|
||||
<td width="50%" style="vertical-align: top; padding-right: 10px;">
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
|
||||
<tr>
|
||||
<td style="padding: 3px 0;"><strong>Invoice Date:</strong></td>
|
||||
<td style="padding: 3px 0;">' . htmlspecialchars(date('d-m-Y', strtotime($invoice_date))) . '</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding: 3px 0;"><strong>Invoice Number:</strong></td>
|
||||
<td style="padding: 3px 0;">' . htmlspecialchars($order_id) . '</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
<td width="50%" style="vertical-align: top; padding-left: 10px;">
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
|
||||
<tr>
|
||||
<td style="padding: 3px 0;"><strong>Reference:</strong></td>
|
||||
<td style="padding: 3px 0;">Online order</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding: 3px 0;"><strong>Order number:</strong></td>
|
||||
<td style="padding: 3px 0;">' . htmlspecialchars($order_id) . '</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!-- Items Table -->
|
||||
<table role="presentation" cellspacing="0" cellpadding="8" border="0" width="100%" style="margin-bottom: 20px; border-bottom: 2px solid #999999;">
|
||||
<thead>
|
||||
<tr style="background-color: #f8f8f8;">
|
||||
<th style="text-align: left; font-weight: bold; font-size: 12px; padding: 10px 8px; border-bottom: 1px solid #999999;">Item code</th>
|
||||
<th style="text-align: left; font-weight: bold; font-size: 12px; padding: 10px 8px; border-bottom: 1px solid #999999;">Description</th>
|
||||
<th style="text-align: center; font-weight: bold; font-size: 12px; padding: 10px 8px; border-bottom: 1px solid #999999;">Quantity</th>
|
||||
<th style="text-align: right; font-weight: bold; font-size: 12px; padding: 10px 8px; border-bottom: 1px solid #999999;">Price</th>
|
||||
<th style="text-align: right; font-weight: bold; font-size: 12px; padding: 10px 8px; border-bottom: 1px solid #999999;">Total</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>';
|
||||
|
||||
foreach ($items as $item) {
|
||||
$line_total = $item['price'] * $item['quantity'];
|
||||
$message .= '<tr>
|
||||
<td style="padding: 10px 8px; border-bottom: 1px solid #dddddd; font-size: 13px;">SOFTWARE</td>
|
||||
<td style="padding: 10px 8px; border-bottom: 1px solid #dddddd; font-size: 13px;">' . htmlspecialchars($item['name']);
|
||||
|
||||
if ($item['serial_number'] !== 'N/A') {
|
||||
$message .= '<br><span style="font-size: 12px; color: #666666;">Serial: ' . htmlspecialchars($item['serial_number']) . '</span>';
|
||||
}
|
||||
if ($item['license_key'] !== 'Pending') {
|
||||
$message .= '<br><span style="font-size: 12px; color: #666666;">License: ' . htmlspecialchars($item['license_key']) . '</span>';
|
||||
}
|
||||
|
||||
$message .= '</td>
|
||||
<td style="text-align: center; padding: 10px 8px; border-bottom: 1px solid #dddddd; font-size: 13px;">' . htmlspecialchars($item['quantity']) . '</td>
|
||||
<td style="text-align: right; padding: 10px 8px; border-bottom: 1px solid #dddddd; font-size: 13px;">€ ' . number_format($item['price'], 2) . '</td>
|
||||
<td style="text-align: right; padding: 10px 8px; border-bottom: 1px solid #dddddd; font-size: 13px;">€ ' . number_format($line_total, 2) . '</td>
|
||||
</tr>';
|
||||
}
|
||||
|
||||
$message .= '</tbody>
|
||||
</table>
|
||||
|
||||
<!-- Totals -->
|
||||
<table role="presentation" cellspacing="0" cellpadding="5" border="0" width="250" align="right" style="margin-top: 10px; font-size: 13px;">
|
||||
<tr>
|
||||
<td style="text-align: left; padding: 5px 0;">' . htmlspecialchars($lbl_subtotal) . '</td>
|
||||
<td style="text-align: right; padding: 5px 0;">€ ' . number_format($subtotal, 2) . '</td>
|
||||
</tr>';
|
||||
|
||||
if ($tax_amount > 0) {
|
||||
$message .= '<tr>
|
||||
<td style="text-align: left; padding: 5px 0;">' . htmlspecialchars($lbl_tax) . '</td>
|
||||
<td style="text-align: right; padding: 5px 0;">€ ' . number_format($tax_amount, 2) . '</td>
|
||||
</tr>';
|
||||
} else {
|
||||
$message .= '<tr>
|
||||
<td style="text-align: left; padding: 5px 0;">VAT</td>
|
||||
<td style="text-align: right; padding: 5px 0;">included</td>
|
||||
</tr>';
|
||||
}
|
||||
|
||||
$message .= '<tr style="border-top: 2px solid #000000;">
|
||||
<td style="text-align: left; padding: 8px 0 5px 0;"><strong>' . htmlspecialchars($lbl_total) . '</strong></td>
|
||||
<td style="text-align: right; padding: 8px 0 5px 0;"><strong>€ ' . number_format($payment_amount, 2) . '</strong></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>';
|
||||
306
assets/mail/pdf_template_invoice.php
Normal file
306
assets/mail/pdf_template_invoice.php
Normal file
@@ -0,0 +1,306 @@
|
||||
<?php
|
||||
|
||||
$pdf = '<!DOCTYPE html>
|
||||
<html lang="' . strtolower($language) . '">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>' . htmlspecialchars($lbl_invoice) . ' - Total Safety Solutions</title>
|
||||
<style>
|
||||
@page {margin: 220px 50px; }
|
||||
|
||||
body {
|
||||
font-family: "DejaVu Sans", Arial, sans-serif;
|
||||
color: #000;
|
||||
font-size: 11px;
|
||||
line-height: 1.4;
|
||||
margin: 10px auto;
|
||||
padding: 0;
|
||||
width:90%;
|
||||
}
|
||||
|
||||
#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>
|
||||
</head>
|
||||
<body>
|
||||
<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="company-header">
|
||||
<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 class="invoice-details">
|
||||
<div class="invoice-left">
|
||||
<div class="detail-row">
|
||||
<div class="detail-label">Invoice Date</div>
|
||||
<div class="detail-value">: ' . htmlspecialchars(date('d-m-Y', strtotime($invoice_date))) . '</div>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<div class="detail-label">Invoice Number</div>
|
||||
<div class="detail-value">: ' . htmlspecialchars($order_id) . '</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="invoice-right">
|
||||
<div class="detail-row">
|
||||
<div class="detail-label">Reference</div>
|
||||
<div class="detail-value">: Online order</div>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<div class="detail-label">Order number</div>
|
||||
<div class="detail-value">: ' . htmlspecialchars($order_id) . '</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<table class="items-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Item code</th>
|
||||
<th>Description</th>
|
||||
<th class="qty-col">Quantity</th>
|
||||
<th class="price-col">Price</th>
|
||||
<th class="total-col">Total</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>';
|
||||
|
||||
foreach ($items as $item) {
|
||||
$line_total = $item['price'] * $item['quantity'];
|
||||
$pdf .= '<tr>
|
||||
<td>SOFTWARE</td>
|
||||
<td>' . htmlspecialchars($item['name']);
|
||||
|
||||
if ($item['serial_number'] !== 'N/A') {
|
||||
$pdf .= '<br><small>Serial: ' . htmlspecialchars($item['serial_number']) . '</small>';
|
||||
}
|
||||
if ($item['license_key'] !== 'Pending') {
|
||||
$pdf .= '<br><small>License: ' . htmlspecialchars($item['license_key']) . '</small>';
|
||||
}
|
||||
|
||||
$pdf .= '</td>
|
||||
<td class="qty-col">' . htmlspecialchars($item['quantity']) . ' </td>
|
||||
<td class="price-col">€ ' . number_format($item['price'], 2) . '</td>
|
||||
<td class="total-col">€ ' . number_format($line_total, 2) . '</td>
|
||||
</tr>';
|
||||
}
|
||||
|
||||
$pdf .= '</tbody>
|
||||
</table>
|
||||
|
||||
<div class="totals-section">
|
||||
<div class="total-row">
|
||||
<div class="total-label">' . htmlspecialchars($lbl_subtotal) . '</div>
|
||||
<div class="total-amount">€ ' . number_format($subtotal, 2) . '</div>
|
||||
</div>';
|
||||
|
||||
if ($tax_amount > 0) {
|
||||
$pdf .= '<div class="total-row">
|
||||
<div class="total-label">' . htmlspecialchars($lbl_tax) . '</div>
|
||||
<div class="total-amount">€ ' . number_format($tax_amount, 2) . '</div>
|
||||
</div>';
|
||||
} else {
|
||||
$pdf .= '<div class="total-row">
|
||||
<div class="total-label">VAT</div>
|
||||
<div class="total-amount">included</div>
|
||||
</div>';
|
||||
}
|
||||
|
||||
$pdf .= '<div class="total-row final-total">
|
||||
<div class="total-label">' . htmlspecialchars($lbl_total) . '</div>
|
||||
<div class="total-amount">€ ' . number_format($payment_amount, 2) . '</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>';
|
||||
@@ -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 ? '<i class="fa fa-chevron-right expand-icon"></i>' : '';
|
||||
|
||||
// Only show edit button if user has update permission
|
||||
const editButton = this.permissions.canUpdate === 1
|
||||
? `<button class="folder-edit-btn" title="Edit folder" data-folder-id="${folder.id}">
|
||||
<i class="fa fa-edit"></i>
|
||||
</button>`
|
||||
: '';
|
||||
|
||||
folderItem.innerHTML = `
|
||||
${expandIcon}
|
||||
<i class="fa fa-folder"></i>
|
||||
<span class="folder-name">${this.escapeHtml(folder.folder_name)}</span>
|
||||
<span class="file-count">(${folder.file_count})</span>
|
||||
${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 = '<i class="fa fa-spinner fa-spin"></i> 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 = '<option value="">Root Folder</option>';
|
||||
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 = '<i class="fa fa-spinner fa-spin"></i> 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
|
||||
|
||||
@@ -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 = `
|
||||
<i class="fa-solid fa-exclamation-triangle" style="font-size: 24px;"></i>
|
||||
<div style="flex: 1;">
|
||||
<strong style="display: block; margin-bottom: 5px; font-size: 16px;">Browser Not Supported</strong>
|
||||
<p style="margin: 0; font-size: 14px; opacity: 0.95;">
|
||||
Please use <strong>Chrome</strong>, <strong>Edge</strong>, or <strong>Opera</strong> to access device connectivity features.
|
||||
</p>
|
||||
</div>
|
||||
`;
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 .= '<div class="content-block">
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="width:25%;">'.$software_status.'</td>
|
||||
<td>'.$firmware_status.'</td>
|
||||
<td>'.$firmware_status.((!empty($responses->sw_version_upgrade)) ? ' <i class="fa-solid fa-wrench" style="color: #ff9800;" title="Software override: '.htmlspecialchars($sw_version_upgrade_text).'"></i>' : '').'</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="width:25%;">'.$equipment_label5.'</td>
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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'){
|
||||
|
||||
}
|
||||
|
||||
@@ -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';
|
||||
|
||||
|
||||
@@ -269,10 +269,10 @@ $view .= '
|
||||
<td>'.$response->license_key.'</td>
|
||||
<td>'.$response->version_name.'</td>
|
||||
<td>'.$status_text.'</td>
|
||||
<td>'.($response->transaction_id ?? '-').'</td>
|
||||
<td>'.(isset($response->transaction_id) && strpos($response->transaction_id, 'SC') === 0 ? '<a href="index.php?page=order&txn_id='.$response->transaction_id.'" class="link-with-icon">'.$response->transaction_id.' <i class="fa-solid fa-up-right-from-square"></i></a>' : ($response->transaction_id ?? '-')).'</td>
|
||||
<td>'.$starts_display.'</td>
|
||||
<td>'.$expires_display.'</td>
|
||||
<td>'.($response->assigned_serial ?? '-').'</td>
|
||||
<td>'.(isset($response->assigned_serial) ? '<a href="index.php?page=equipment&serialnumber='.$response->assigned_serial.'" class="link-with-icon">'.$response->assigned_serial.' <i class="fa-solid fa-up-right-from-square"></i></a>' : ($response->assigned_serial ?? '-')).'</td>
|
||||
</tr>
|
||||
';
|
||||
}
|
||||
|
||||
@@ -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');
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button id="saveEdit" class="btn btn-primary">
|
||||
<i class="fa fa-save"></i> Save Changes
|
||||
<i class="fa fa-save"></i>
|
||||
</button>
|
||||
<button class="modal-cancel btn btn-secondary">Cancel</button>
|
||||
<button class="modal-cancel btn btn-secondary">X</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- Edit Folder Modal -->
|
||||
<?php if ($update_allowed === 1): ?>
|
||||
<div id="editFolderModal" class="modal">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h3>Edit Folder</h3>
|
||||
<button class="modal-close">×</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="form-group">
|
||||
<label for="editFolderName">Folder Name:</label>
|
||||
<input type="text" id="editFolderName" class="form-control" placeholder="Enter folder name">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="editParentFolder">Parent Folder:</label>
|
||||
<select id="editParentFolder" class="form-control">
|
||||
<option value="">Root Folder</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="editFolderDescription">Description:</label>
|
||||
<textarea id="editFolderDescription" class="form-control" rows="3" placeholder="Optional description"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button id="saveEditFolder" class="btn btn-primary">
|
||||
<i class="fa fa-save"></i>
|
||||
</button>
|
||||
<?php if ($delete_allowed === 1): ?>
|
||||
<button id="deleteFolder" class="btn btn-danger">
|
||||
<i class="fa fa-trash"></i>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
<button class="modal-cancel btn btn-secondary">X</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<script src="./assets/marketing.js"></script>
|
||||
<script>
|
||||
// Pass PHP permissions to JavaScript
|
||||
window.marketingPermissions = {
|
||||
canCreate: <?php echo $create_allowed; ?>,
|
||||
canUpdate: <?php echo $update_allowed; ?>,
|
||||
canDelete: <?php echo $delete_allowed; ?>
|
||||
};
|
||||
</script>
|
||||
|
||||
<?php
|
||||
template_footer();
|
||||
|
||||
@@ -4,7 +4,7 @@ define('standard_profile','dashboard,profile,application,firmwaretool,histories,
|
||||
/*Superuser*/
|
||||
define('superuser_profile','admin,dashboard,profile,application,assets,firmwaretool,histories,history,history_manage,marketing,partner,partners,servicereport,servicereports,equipment,equipment_manage,equipment_manage_edit,equipments,equipments_mass_update,product,product_manage,products,products_software,products_versions,user,user_manage,users');
|
||||
/*Admin*/
|
||||
define('admin_profile','account,accounts,admin,dashboard,profile,application,assets,buildtool,buildtool,cartest,cartest_manage,cartests,changelog,communication,communication_send,communications,firmwaretool,histories,history,history_manage,marketing,partner,partners,sales,servicereport,servicereports,software_available,software_download,software_update,softwaretool,contract,contract_manage,contracts,equipment,equipment_data,equipment_healthindex,equipment_manage,equipment_manage_edit,equipments,equipments_mass_update,product,product_manage,products,products_software,products_software_assignment,products_software_assignments,products_versions,report_build,report_contracts_billing,report_healthindex,reporting,rma,rma_history,rma_history_manage,rma_manage,rmas,user,user_manage,users');
|
||||
define('admin_profile','account,accounts,admin,dashboard,profile,application,assets,buildtool,buildtool,cartest,cartest_manage,cartests,changelog,communication,communication_send,communications,firmwaretool,histories,history,history_manage,marketing,partner,partners,sales,servicereport,servicereports,software_available,software_download,software_update,softwaretool,contract,contract_manage,contracts,equipment,equipment_data,equipment_healthindex,equipment_manage,equipment_manage_edit,equipments,equipments_mass_update,product,product_manage,products,products_software,products_software_assignment,products_software_assignments,products_software_assignments,products_versions,report_build,report_contracts_billing,report_healthindex,reporting,rma,rma_history,rma_history_manage,rma_manage,rmas,user,user_manage,users');
|
||||
/*AdminPlus*/
|
||||
define('adminplus_profile','account,account_manage,accounts,admin,config,dashboard,profile,settings,api,application,appointment,assets,billing,buildtool,buildtool,cartest,cartest_manage,cartests,catalog,categories,category,changelog,checkout,com_log,communication,communication_send,communications,cronjob,debug,dev,discount,discounts,factuur,firmwaretool,functions,generate_download_token,histories,history,history_manage,identity,identity_dealers,initialize,invoice,language,licenses,logfile,mailer,maintenance,marketing,marketing_delete,marketing_files,marketing_folders,marketing_migrate,marketing_tags,marketing_update,marketing_upload,media,media_manage,media_scanner,media_upload,order,orders,partner,partners,payment,placeorder,pricelists,pricelists_items,pricelists_manage,profiles,register,render_service_report,reset,sales,security,service,servicereport,servicereports,shipping,shipping_manage,shopping_cart,software_available,software_download,software_update,softwaretool,tax,taxes,test,transactions,transactions_items,translation_manage,translations,translations_details,unscribe,upgrades,uploader,vin,webhook_mollie,webhook_paypal,contract,contract_manage,contracts,dealer,dealer_manage,dealers,dealers_media,equipment,equipment_data,equipment_healthindex,equipment_history,equipment_manage,equipment_manage_edit,equipments,equipments_mass_update,product,product_manage,products,products_attributes,products_attributes_items,products_attributes_manage,products_categories,products_configurations,products_media,products_software,products_software_assignment,products_software_assignments,products_software_assignments,products_software_licenses,products_software_upgrade_paths,products_software_upgrade_paths_manage,products_software_version,products_software_version_access_rules_manage,products_software_version_manage,products_software_versions,products_versions,report_build,report_contracts_billing,report_healthindex,report_usage,reporting,rma,rma_history,rma_history_manage,rma_manage,rmas,user,user_credentials,user_manage,users');
|
||||
/*Build*/
|
||||
@@ -14,7 +14,7 @@ define('commerce','admin,dashboard,profile,application,catalog,categories,catego
|
||||
/*Distribution*/
|
||||
define('distribution','admin,dashboard,profile,application,assets,firmwaretool,histories,history,history_manage,marketing,partner,partners,servicereport,servicereports,equipment,equipment_manage,equipment_manage_edit,equipments,equipments_mass_update,product,product_manage,products,products_software,products_versions,user,user_manage,users');
|
||||
/*Firmware*/
|
||||
define('firmware','application,firmwaretool,software_available,software_download,software_update,softwaretool,transactions,transactions_items,products_software');
|
||||
define('firmware','application,software_available,software_download,software_update,softwaretool,transactions,transactions_items,products_software_versions');
|
||||
/*Garage*/
|
||||
define('garage','dashboard,profile,application,cartest,cartest_manage,cartests,products_versions');
|
||||
/*Interface*/
|
||||
|
||||
@@ -184,6 +184,13 @@ $view .= '
|
||||
|
||||
$view .= '<div class="content-block">
|
||||
|
||||
<noscript>
|
||||
<div style="background: #dc3545; color: white; padding: 15px; border-radius: 8px; margin-bottom: 20px;">
|
||||
<strong>JavaScript Required</strong><br>
|
||||
This tool requires JavaScript to be enabled in your browser.
|
||||
</div>
|
||||
</noscript>
|
||||
|
||||
<p id="servicetoken" value="" hidden>'.$bearertoken.'</p>
|
||||
|
||||
<div id="connectdevice" style="display:flex; gap: 10px; margin-bottom: 20px;">
|
||||
@@ -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').'";
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user