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.

This commit is contained in:
“VeLiTi”
2026-02-03 09:10:33 +01:00
parent 0648b69eff
commit e97d2e5ef2
17 changed files with 289 additions and 37 deletions

BIN
.DS_Store vendored

Binary file not shown.

View File

@@ -272,7 +272,7 @@ $view .= '<div class="tabs">
//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 .= '<div class="tabs">
<a href="#">'.$tab3.'</a>

View File

@@ -1,6 +1,10 @@
<?php
defined($security_key) or exit;
ini_set('display_errors', '1');
ini_set('display_startup_errors', '1');
error_reporting(E_ALL);
//------------------------------------------
// Catalog
//------------------------------------------
@@ -22,7 +26,7 @@ if(isset($get_content) && $get_content!=''){
foreach ($requests as $y){
$v = explode("=", $y);
//INCLUDE VARIABLES IN ARRAY
$criterias[$v[0]] = $v[1];
$criterias[$v[0]] = $v[1] ?? true;
if ($v[0] == 'category'){
//------------------------------------------
@@ -88,7 +92,7 @@ foreach ($products as $product) {
$version_configurations[$item['version']] = [
'version_id' => $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
//------------------------------------------

View File

@@ -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]]);
}

View File

@@ -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

View File

@@ -308,8 +308,9 @@ $pdf .= '</tbody>
</div>';
if ($tax_amount > 0) {
$tax_percentage = ($subtotal > 0) ? round(($tax_amount / $subtotal) * 100, 2) : 0;
$pdf .= '<div class="total-row">
<div class="total-label">' . htmlspecialchars($lbl_tax) . '</div>
<div class="total-label">' . htmlspecialchars($lbl_tax) . ' (' . $tax_percentage . '%)</div>
<div class="total-amount">€ ' . number_format($tax_amount, 2) . '</div>
</div>';
} else {

View File

@@ -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);

View File

@@ -248,10 +248,10 @@ $view .=' </div>
$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 .= '<div class="tabs">

View File

@@ -216,10 +216,10 @@ $view .= '<div class="tabs">
//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';}

View File

@@ -200,10 +200,10 @@ $view .= '<form action="" method="post" id="mass_update_form">
//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 .='<div class="content-block">
<div class="block-header">

View File

@@ -103,7 +103,7 @@ echo '
<script>
var link = "'.$baseurl.'";
var DEBUG = '.(debug ? 'true' : 'false').';
var port, textEncoder, writableStreamClosed, writer, historyIndex = -1;
var historyIndex = -1;
const lineHistory = [];
</script>';

171
marketing_migrate.php Normal file
View File

@@ -0,0 +1,171 @@
<?php
defined(page_security_key) or exit;
/**
* Marketing System Migration
* Migrate existing marketing files from directory structure to database
*/
include_once './assets/functions.php';
$pdo = dbConnect($dbname);
// Check if marketing tables exist
try {
$pdo->query("SELECT 1 FROM marketing_files LIMIT 1");
} catch (PDOException $e) {
echo "Marketing tables not found. Please run marketing_install.php first.<br>";
echo "<a href='marketing_install.php'>Install Marketing System</a>";
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<br>";
exit;
}
echo "<h2>Marketing File Migration</h2>";
echo "<p>Migrating existing marketing files to the new system...</p>";
$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: <strong>$product_group</strong><br>";
// 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 "&nbsp;&nbsp;- Processing folder: $folder_name<br>";
// 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 "&nbsp;&nbsp;&nbsp;&nbsp;✓ $file<br>";
// 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 "<br><h3>Migration Summary</h3>";
echo "✓ Folders migrated: <strong>$migrated_folders</strong><br>";
echo "✓ Files migrated: <strong>$migrated_files</strong><br>";
if (!empty($errors)) {
echo "<br><h4>Errors/Warnings:</h4>";
foreach ($errors as $error) {
echo "$error<br>";
}
}
echo "<br><strong>Migration completed successfully!</strong><br>";
echo "<a href='index.php?page=marketing'>Go to Marketing Page</a>";
} catch (Exception $e) {
echo "Migration error: " . $e->getMessage();
}
?>

View File

@@ -163,8 +163,8 @@ $view .= '</div>
//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 .= '<div class="tabs">

View File

@@ -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;
}

View File

@@ -494,8 +494,8 @@ $view .= '<div class="content-block">
<table>';
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 .= '<tr>
<td style="width:25%;">'.($general_salesid ?? 'Sales ID').'</td>
@@ -513,8 +513,8 @@ if ($hierarchyLevel == 0 || $hierarchyLevel == 1){
</tr>';
}
$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 .= '<tr>
<td style="width:25%;">'.($general_shipto ?? 'Ship To').'</td>

View File

@@ -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 {

View File

@@ -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 {