From e97d2e5ef288b8a848dcba76e1e8207a1de0b65d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CVeLiTi=E2=80=9D?= <“info@veliti.nl”> Date: Tue, 3 Feb 2026 09:10:33 +0100 Subject: [PATCH] Refactor partner dropdowns to utilize authorization permissions across various management pages. Enhance invoice creation in webhooks to include account hierarchy. Add marketing system migration script for transitioning files to database structure. --- .DS_Store | Bin 12292 -> 12292 bytes account_manage.php | 2 +- api/v2/get/catalog.php | 66 ++++++++- api/v2/get/history.php | 2 +- api/v2/get/products_software_licenses.php | 2 +- assets/mail/pdf_template_invoice.php | 3 +- assets/softwaretool.js | 26 +++- contract_manage.php | 8 +- equipment_manage.php | 8 +- equipments_mass_update.php | 8 +- firmwaretool.php | 2 +- marketing_migrate.php | 171 ++++++++++++++++++++++ partner.php | 4 +- style/admin.css | 2 +- user.php | 8 +- webhook_mollie.php | 7 +- webhook_paypal.php | 7 +- 17 files changed, 289 insertions(+), 37 deletions(-) create mode 100644 marketing_migrate.php diff --git a/.DS_Store b/.DS_Store index 9d4c452e8d05565dc11a62679d1101247abf067b..0b0a16d737eedde9cb1079aed4c86b9e84cd7276 100644 GIT binary patch delta 236 zcmZokXi1ph&uF_b;4m9!T1s(pQht68<78&`7d#9M42(bw1RUI(4@!u$Y*y!a!px|< znMc5xIft1chasOK9i|1Oj0+;f5YJ%5V921yP{L5bP~w@BpPZDFp9GW_02(L@#P9xt z0Z0pq9wQujx;Hxr2k9i^f-$ M%|faR8L`O%0JpgxmjD0& diff --git a/account_manage.php b/account_manage.php index a2c3161..eb225fa 100644 --- a/account_manage.php +++ b/account_manage.php @@ -272,7 +272,7 @@ $view .= '
//Dropdown $partner_data = json_decode($_SESSION['authorization']['partnerhierarchy']); -$soldto_dropdown = listPartner('soldto',$accounthierarchy->soldto,'',$_SESSION['authorization']['permission']); +$soldto_dropdown = listPartner('soldto',$_SESSION['authorization']['permission'],$accounthierarchy->soldto,''); $view .= '
'.$tab3.' diff --git a/api/v2/get/catalog.php b/api/v2/get/catalog.php index 56d1126..97a1b6d 100644 --- a/api/v2/get/catalog.php +++ b/api/v2/get/catalog.php @@ -1,6 +1,10 @@ $item['version'], 'config_setting' => $item['config'], - 'main_option_for_display' => $item['measurement'], + 'main_option_for_display' => $item['measurement'] ?? '', 'configurations' => [] ]; } @@ -170,6 +174,64 @@ removeKeysRecursive($catalog,$keys_to_remove); //------------------------------------------ $messages = processProductCollection($catalog); +//------------------------------------------ +//check for METAfeed request +//------------------------------------------ +if (isset($criterias['meta'])){ + //------------------------------------------ + // Meta Feed Configuration + //------------------------------------------ + $meta_config = [ + 'base_url' => 'https://www.morvalwatches.com', // Product page URL + 'image_base_url' => 'https://cloud.soveliti.nl', + 'brand' => 'Morval Watches', + 'currency' => 'EUR', + 'condition' => 'new', + 'availability' => 'in stock', + 'google_product_category' => 'Apparel & Accessories > Jewelry > Watches', + 'output_format' => 'json' // Options: 'csv', 'xml', 'json' + ]; + + //------------------------------------------ + // Product Code Based Descriptions + // Keys can be: exact code (MWTH2NB) or pattern (MWTH1*, MWTH2*) + //------------------------------------------ + $meta_descriptions = [ + // Pattern based (will match any product starting with this) + 'MWTH1' => 'The Thomas-I exudes elegance and sophistication. Classic dimensions combined with subtle details in the dial make it an special automatic watch that can be worn on all occasions.', + 'MWTH2' => 'The Thomas-II provides a view of the beating heart of the Swiss timepiece. It marks the precision and perfection with which the time is displayed.', + 'MWABR' => 'Handmade Italian calf leather bracelet', + ]; + + //------------------------------------------ + //Include meta functions + //------------------------------------------ + include_once './assets/functions_meta.php'; + + $meta_feed = catalogToMetaFeed($messages, $meta_config); + //------------------------------------------ + // Output based on format parameter + //------------------------------------------ + if ($criterias['meta'] === true) { + $format = $meta_config['output_format']; + } else { + $format = $criterias['meta']; + } + + switch ($format) { + case 'xml': + $messages = outputMetaFeedXML($meta_feed); + break; + case 'csv': + $messages = outputMetaFeedCSV($meta_feed); + break; + case 'json': + default: + $messages = outputMetaFeedJSON($meta_feed); + break; + } + exit(); +} //------------------------------------------ //JSON_ENCODE //------------------------------------------ diff --git a/api/v2/get/history.php b/api/v2/get/history.php index aa81a11..c2ff77a 100644 --- a/api/v2/get/history.php +++ b/api/v2/get/history.php @@ -102,7 +102,7 @@ if(isset($get_content) && $get_content!=''){ //Filter out only relevant servicereports $filter_key_1 = '"%serialnumber%"'; $filter_key_2 = '"ServiceReport"'; - $clause .= ' AND h.type = '.$filter_key_2.' AND NOT e.productrowid = "31" AND h.description like '.$filter_key_1; + $clause .= ' AND h.type = '.$filter_key_2.' AND e.productrowid = "31" AND h.description like '.$filter_key_1; //remove from criterias to prevent double binding unset($criterias[$v[0]]); } diff --git a/api/v2/get/products_software_licenses.php b/api/v2/get/products_software_licenses.php index f47175d..6b9a1d0 100644 --- a/api/v2/get/products_software_licenses.php +++ b/api/v2/get/products_software_licenses.php @@ -51,7 +51,7 @@ if(isset($get_content) && $get_content!=''){ //Define Query if(isset($criterias['totals']) && $criterias['totals'] ==''){ //Request for total rows - $sql = 'SELECT count(*) as count FROM products_software_licenses '.$whereclause.''; + $sql = 'SELECT count(*) as count FROM products_software_licenses l '.$whereclause.''; } elseif (isset($criterias['list']) && $criterias['list'] =='') { //SQL for list diff --git a/assets/mail/pdf_template_invoice.php b/assets/mail/pdf_template_invoice.php index 29aea68..33a8a1b 100644 --- a/assets/mail/pdf_template_invoice.php +++ b/assets/mail/pdf_template_invoice.php @@ -308,8 +308,9 @@ $pdf .= '
'; if ($tax_amount > 0) { + $tax_percentage = ($subtotal > 0) ? round(($tax_amount / $subtotal) * 100, 2) : 0; $pdf .= '
-
' . htmlspecialchars($lbl_tax) . '
+
' . htmlspecialchars($lbl_tax) . ' (' . $tax_percentage . '%)
€ ' . number_format($tax_amount, 2) . '
'; } else { diff --git a/assets/softwaretool.js b/assets/softwaretool.js index a8855c8..4e5e8f4 100644 --- a/assets/softwaretool.js +++ b/assets/softwaretool.js @@ -230,6 +230,10 @@ async function connectDeviceForSoftware() { deviceVersion = ""; deviceHwVersion = ""; + // Clear the flag so popup shows for each new device connection + // This allows users to connect multiple devices in the same session + sessionStorage.removeItem('customerDataShownThisSession'); + //set progress bar progressBar("1", "", ""); @@ -612,14 +616,23 @@ async function fetchSoftwareOptions() { document.getElementById("softwareOptionsContainer").style.display = "block"; progressBar("100", "Software options loaded", "#04AA6D"); - // Check if customer data already exists in sessionStorage - const savedCustomerData = sessionStorage.getItem('customerData'); + // Check if we're returning from a payment + const urlParams = new URLSearchParams(window.location.search); + const isReturningFromPayment = urlParams.has('payment_return') || urlParams.has('order_id'); - // Show user info modal only if no saved data and not in debug mode - if ((typeof DEBUG === 'undefined' || !DEBUG || typeof DEBUG_ID === 'undefined' || !DEBUG_ID) && !savedCustomerData) { + // Check if customer data was already shown in THIS session (not from previous session) + const customerDataShownThisSession = sessionStorage.getItem('customerDataShownThisSession'); + + // Show user info modal unless: + // 1. We're in debug mode + // 2. We're returning from payment + // 3. We already showed the modal in this session + if ((typeof DEBUG === 'undefined' || !DEBUG || typeof DEBUG_ID === 'undefined' || !DEBUG_ID) + && !isReturningFromPayment + && !customerDataShownThisSession) { showUserInfoModal(); } else { - // Customer data already exists or debug mode - reveal software options immediately + // Debug mode, returning from payment, or already shown this session - reveal software options immediately const softwareOptions = document.getElementById("softwareOptions"); if (softwareOptions) { softwareOptions.style.filter = "none"; @@ -992,6 +1005,9 @@ function showUserInfoModal() { // Save customer data to sessionStorage sessionStorage.setItem('customerData', JSON.stringify(customerData)); + // Mark that we've shown the customer data modal in this session + sessionStorage.setItem('customerDataShownThisSession', 'true'); + // Send to API await sendUserInfoToAPI(customerData); diff --git a/contract_manage.php b/contract_manage.php index 9d7b602..7c46e33 100644 --- a/contract_manage.php +++ b/contract_manage.php @@ -248,10 +248,10 @@ $view .='
$partner_data = json_decode($contract['accounthierarchy']); //BUID UP DROPDOWNS -$salesid_dropdown = listPartner('salesid',$partner_data->salesid,'',$_SESSION['authorization']['permission']); -$soldto_dropdown = listPartner('soldto',$partner_data->soldto,'',$_SESSION['authorization']['permission']); -$shipto_dropdown = listPartner('shipto',$partner_data->shipto,'',$_SESSION['authorization']['permission']); -$location_dropdown = listPartner('location',$partner_data->location,'',$_SESSION['authorization']['permission']); +$salesid_dropdown = listPartner('salesid',$_SESSION['authorization']['permission'],$partner_data->salesid,''); +$soldto_dropdown = listPartner('soldto',$_SESSION['authorization']['permission'],$partner_data->soldto,''); +$shipto_dropdown = listPartner('shipto',$_SESSION['authorization']['permission'],$partner_data->shipto,''); +$location_dropdown = listPartner('location',$_SESSION['authorization']['permission'],$partner_data->location,''); //DISPLAY $view .= '
diff --git a/equipment_manage.php b/equipment_manage.php index e72fa6e..8e8f031 100644 --- a/equipment_manage.php +++ b/equipment_manage.php @@ -216,10 +216,10 @@ $view .= '
//GET PARTNERDATA $partner_data = json_decode($equipment['accounthierarchy']); //BUID UP DROPDOWNS -$salesid_dropdown = listPartner('salesid',$partner_data->salesid,'',$_SESSION['authorization']['permission']); -$soldto_dropdown = listPartner('soldto',$partner_data->soldto,'',$_SESSION['authorization']['permission']); -$shipto_dropdown = listPartner('shipto',$partner_data->shipto,'',$_SESSION['authorization']['permission']); -$location_dropdown = listPartner('location',$partner_data->location,'',$_SESSION['authorization']['permission']); +$salesid_dropdown = listPartner('salesid',$_SESSION['authorization']['permission'],$partner_data->salesid,''); +$soldto_dropdown = listPartner('soldto',$_SESSION['authorization']['permission'],$partner_data->soldto,''); +$shipto_dropdown = listPartner('shipto',$_SESSION['authorization']['permission'],$partner_data->shipto,''); +$location_dropdown = listPartner('location',$_SESSION['authorization']['permission'],$partner_data->location,''); if (isset($partner_data->section)){$section = getPartnerName($partner_data->section) ?? 'Not specified';} else {$section = 'Not specified';} diff --git a/equipments_mass_update.php b/equipments_mass_update.php index b0e44f1..565043e 100644 --- a/equipments_mass_update.php +++ b/equipments_mass_update.php @@ -200,10 +200,10 @@ $view .= '
//BUID UP DROPDOWNS $partner = json_decode($_SESSION['authorization']['partnerhierarchy'],true); -$salesid_dropdown = listPartner('salesid',$partner['salesid'],'yes',$_SESSION['authorization']['permission']); -$soldto_dropdown = listPartner('soldto','','yes',$_SESSION['authorization']['permission']); -$shipto_dropdown = listPartner('shipto','','',$_SESSION['authorization']['permission']); -$location_dropdown = listPartner('location','','',$_SESSION['authorization']['permission']); +$salesid_dropdown = listPartner('salesid',$_SESSION['authorization']['permission'],$partner['salesid'],'yes'); +$soldto_dropdown = listPartner('soldto',$_SESSION['authorization']['permission'],'','yes'); +$shipto_dropdown = listPartner('shipto',$_SESSION['authorization']['permission'],'',''); +$location_dropdown = listPartner('location',$_SESSION['authorization']['permission'],'',''); $view .='
diff --git a/firmwaretool.php b/firmwaretool.php index 8e33277..b19bbb8 100644 --- a/firmwaretool.php +++ b/firmwaretool.php @@ -103,7 +103,7 @@ echo ' '; diff --git a/marketing_migrate.php b/marketing_migrate.php new file mode 100644 index 0000000..43c745c --- /dev/null +++ b/marketing_migrate.php @@ -0,0 +1,171 @@ +query("SELECT 1 FROM marketing_files LIMIT 1"); +} catch (PDOException $e) { + echo "Marketing tables not found. Please run marketing_install.php first.
"; + echo "Install Marketing System"; + exit; +} + +// Get marketing structure from settings +$main_marketing_dir = './marketing/'; + +if (!file_exists($main_marketing_dir)) { + echo "Marketing directory not found at: $main_marketing_dir
"; + exit; +} + +echo "

Marketing File Migration

"; +echo "

Migrating existing marketing files to the new system...

"; + +$migrated_folders = 0; +$migrated_files = 0; +$errors = []; + +try { + // Build partner hierarchy for current user + $partner_hierarchy = json_encode(array("salesid" => $partner->salesid, "soldto" => $partner->soldto), JSON_UNESCAPED_UNICODE); + + // Scan marketing directory structure + if (isset($marketing_structure) && is_array($marketing_structure)) { + foreach ($marketing_structure as $product_group => $folders) { + echo "Processing product group: $product_group
"; + + // Create product group folder + $stmt = $pdo->prepare("INSERT INTO marketing_folders (folder_name, description, createdby, accounthierarchy) VALUES (?, ?, ?, ?)"); + $stmt->execute([$product_group, "Migrated from legacy structure", $username, $partner_hierarchy]); + $group_folder_id = $pdo->lastInsertId(); + $migrated_folders++; + + foreach ($folders as $folder_name) { + $folder_path = $main_marketing_dir . $product_group . '/' . $folder_name; + + if (is_dir($folder_path)) { + echo "  - Processing folder: $folder_name
"; + + // Create content folder + $stmt = $pdo->prepare("INSERT INTO marketing_folders (folder_name, parent_id, description, createdby, accounthierarchy) VALUES (?, ?, ?, ?, ?)"); + $stmt->execute([$folder_name, $group_folder_id, "Migrated from legacy structure", $username, $partner_hierarchy]); + $content_folder_id = $pdo->lastInsertId(); + $migrated_folders++; + + // Process files in folder + $files = array_diff(scandir($folder_path), array('.', '..', 'Thumb')); + + foreach ($files as $file) { + $file_path = $folder_path . '/' . $file; + + if (is_file($file_path) && !is_dir($file_path)) { + $file_info = pathinfo($file); + $file_ext = strtolower($file_info['extension'] ?? ''); + + // Skip system files + if (in_array($file_ext, ['ds_store', 'thumbs.db']) || empty($file_ext)) { + continue; + } + + // Check if file type is supported + $allowed_types = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'pdf', 'doc', 'docx', 'xls', 'xlsx', 'mp4', 'mov', 'avi']; + if (!in_array($file_ext, $allowed_types)) { + $errors[] = "Skipped unsupported file type: $file"; + continue; + } + + $file_size = filesize($file_path); + $relative_path = str_replace('./', '', $file_path); + + // Check for existing thumbnail + $thumbnail_path = null; + $thumb_file = $folder_path . '/Thumb/' . $file; + if (file_exists($thumb_file)) { + $thumbnail_path = str_replace('./', '', $thumb_file); + } + + // Generate tags based on product group and folder + $tags = [$product_group, $folder_name]; + if (strpos(strtolower($file), 'brochure') !== false) $tags[] = 'brochure'; + if (strpos(strtolower($file), 'manual') !== false) $tags[] = 'manual'; + if (strpos(strtolower($file), 'spec') !== false) $tags[] = 'specifications'; + + try { + $stmt = $pdo->prepare(" + INSERT INTO marketing_files + (title, original_filename, file_path, thumbnail_path, file_type, file_size, folder_id, tags, createdby, accounthierarchy) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + "); + + $stmt->execute([ + $file_info['filename'], + $file, + $relative_path, + $thumbnail_path, + $file_ext, + $file_size, + $content_folder_id, + json_encode($tags), + $username, + $partner_hierarchy + ]); + + $migrated_files++; + echo "    ✓ $file
"; + + // Insert tags + foreach ($tags as $tag) { + $tag = trim($tag); + if (!empty($tag)) { + // Insert tag if not exists + $pdo->prepare("INSERT IGNORE INTO marketing_tags (tag_name) VALUES (?)")->execute([$tag]); + + // Link file to tag + $tag_id_stmt = $pdo->prepare("SELECT id FROM marketing_tags WHERE tag_name = ?"); + $tag_id_stmt->execute([$tag]); + $tag_id = $tag_id_stmt->fetchColumn(); + + if ($tag_id) { + $pdo->prepare("INSERT IGNORE INTO marketing_file_tags (file_id, tag_id) VALUES (?, ?)") + ->execute([$pdo->lastInsertId(), $tag_id]); + } + } + } + + } catch (PDOException $e) { + $errors[] = "Error migrating file $file: " . $e->getMessage(); + } + } + } + } + } + } + } + + echo "

Migration Summary

"; + echo "✓ Folders migrated: $migrated_folders
"; + echo "✓ Files migrated: $migrated_files
"; + + if (!empty($errors)) { + echo "

Errors/Warnings:

"; + foreach ($errors as $error) { + echo "⚠ $error
"; + } + } + + echo "
Migration completed successfully!
"; + echo "Go to Marketing Page"; + +} catch (Exception $e) { + echo "Migration error: " . $e->getMessage(); +} +?> \ No newline at end of file diff --git a/partner.php b/partner.php index 91eb7e9..ff1cddf 100644 --- a/partner.php +++ b/partner.php @@ -163,8 +163,8 @@ $view .= '
//GET PARTNERDATA $partner_data = json_decode($partner['salesID'])?? json_decode($_SESSION['authorization']['partnerhierarchy']) ; //BUID UP DROPDOWNS -$salesid_dropdown = listPartner('salesid',$partner_data->salesid,'',$_SESSION['authorization']['permission']); -$soldto_dropdown = listPartner('soldto',$partner_data->soldto,'',$_SESSION['authorization']['permission']); +$salesid_dropdown = listPartner('salesid',$_SESSION['authorization']['permission'],$partner_data->salesid,''); +$soldto_dropdown = listPartner('soldto',$_SESSION['authorization']['permission'],$partner_data->soldto,''); //DISPLAY $view .= '
diff --git a/style/admin.css b/style/admin.css index 959804a..c96be5f 100644 --- a/style/admin.css +++ b/style/admin.css @@ -591,7 +591,7 @@ main .content-block-wrapper .content-block { width: 100%; margin: 0 10px; border-radius: 3px; - max-height: 300px; + max-height: 400px; overflow-y: auto; } diff --git a/user.php b/user.php index cb772ac..54c12d3 100644 --- a/user.php +++ b/user.php @@ -494,8 +494,8 @@ $view .= '
'; if ($hierarchyLevel == 0 || $hierarchyLevel == 1){ - $salesid_dropdown = listPartner('salesid', $partner_data->salesid ?? '', '', $_SESSION['authorization']['permission']); - $soldto_dropdown = listPartner('soldto', $partner_data->soldto ?? '', '', $_SESSION['authorization']['permission']); + $salesid_dropdown = listPartner('salesid', $_SESSION['authorization']['permission'], $partner_data->salesid ?? '', ''); + $soldto_dropdown = listPartner('soldto', $_SESSION['authorization']['permission'], $partner_data->soldto ?? '', ''); $view .= ' @@ -513,8 +513,8 @@ if ($hierarchyLevel == 0 || $hierarchyLevel == 1){ '; } -$shipto_dropdown = listPartner('shipto', $partner_data->shipto ?? '', '', $_SESSION['authorization']['permission']); -$location_dropdown = listPartner('location', $partner_data->location ?? '', '', $_SESSION['authorization']['permission']); +$shipto_dropdown = listPartner('shipto', $_SESSION['authorization']['permission'], $partner_data->shipto ?? '', ''); +$location_dropdown = listPartner('location', $_SESSION['authorization']['permission'], $partner_data->location ?? '', ''); $view .= ' diff --git a/webhook_mollie.php b/webhook_mollie.php index cac5356..d02a021 100644 --- a/webhook_mollie.php +++ b/webhook_mollie.php @@ -204,8 +204,8 @@ try { if (!$existing_invoice) { // Create invoice - $sql = 'INSERT INTO invoice (txn_id, payment_status, payment_amount, shipping_amount, discount_amount, tax_amount, created) - VALUES (?, ?, ?, ?, ?, ?, ?)'; + $sql = 'INSERT INTO invoice (txn_id, payment_status, payment_amount, shipping_amount, discount_amount, tax_amount, created,accounthierarchy) + VALUES (?, ?, ?, ?, ?, ?, ?,?)'; $stmt = $pdo->prepare($sql); $stmt->execute([ $transaction['txn_id'], @@ -214,7 +214,8 @@ try { $transaction['shipping_amount'] ?? 0.00, $transaction['discount_amount'] ?? 0.00, $transaction['tax_amount'] ?? 0.00, - date('Y-m-d H:i:s') + date('Y-m-d H:i:s'), + '{"salesid":"21-Total Safety Solutions B.V.","soldto":""}' ]); $invoice_id = $pdo->lastInsertId(); } else { diff --git a/webhook_paypal.php b/webhook_paypal.php index f25f56f..3df5306 100644 --- a/webhook_paypal.php +++ b/webhook_paypal.php @@ -250,8 +250,8 @@ try { if (!$existing_invoice) { // Create invoice - $sql = 'INSERT INTO invoice (txn_id, payment_status, payment_amount, shipping_amount, discount_amount, tax_amount, created) - VALUES (?, ?, ?, ?, ?, ?, ?)'; + $sql = 'INSERT INTO invoice (txn_id, payment_status, payment_amount, shipping_amount, discount_amount, tax_amount, created,accounthierarchy) + VALUES (?, ?, ?, ?, ?, ?, ?,?)'; $stmt = $pdo->prepare($sql); $stmt->execute([ $transaction['txn_id'], @@ -260,7 +260,8 @@ try { $transaction['shipping_amount'] ?? 0.00, $transaction['discount_amount'] ?? 0.00, $transaction['tax_amount'] ?? 0.00, - date('Y-m-d H:i:s') + date('Y-m-d H:i:s'), + '{"salesid":"21-Total Safety Solutions B.V.","soldto":""}' ]); $invoice_id = $pdo->lastInsertId(); } else {
'.($general_salesid ?? 'Sales ID').'
'.($general_shipto ?? 'Ship To').'