From 906ce7b843f80cc37d655ecad417e9a1d828ad63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CVeLiTi=E2=80=9D?= <“info@veliti.nl”> Date: Thu, 9 Jan 2025 15:40:59 +0100 Subject: [PATCH] CMXX - Initial product attributes --- api/v2/get/products_attributes.php | 118 +++++++++ api/v2/get/products_attributes_items.php | 118 +++++++++ api/v2/post/products_attributes.php | 105 ++++++++ api/v2/post/products_attributes_items.php | 103 ++++++++ products_attributes.php | 153 +++++++++++ products_attributes_manage.php | 297 ++++++++++++++++++++++ settings/settingsmenu.php | 9 +- settings/settingsprofiles.php | 2 +- settings/settingsviews.php | 2 + 9 files changed, 905 insertions(+), 2 deletions(-) create mode 100644 api/v2/get/products_attributes.php create mode 100644 api/v2/get/products_attributes_items.php create mode 100644 api/v2/post/products_attributes.php create mode 100644 api/v2/post/products_attributes_items.php create mode 100644 products_attributes.php create mode 100644 products_attributes_manage.php diff --git a/api/v2/get/products_attributes.php b/api/v2/get/products_attributes.php new file mode 100644 index 0000000..d261a32 --- /dev/null +++ b/api/v2/get/products_attributes.php @@ -0,0 +1,118 @@ +soldto) || $partner->soldto == ''){$soldto_search = '%';} else {$soldto_search = '-%';} + +//default whereclause +$whereclause = ''; + +switch ($permission) { + case '4': + $whereclause = ''; + break; + case '3': + $whereclause = ''; + break; + default: + $condition = '__salesid___'.$partner->salesid.'___soldto___'.substr($partner->soldto, 0, strpos($partner->soldto, "-")).$soldto_search; + $whereclause = 'WHERE accounthierarchy like "'.$condition.'"'; + break; +} + +//NEW ARRAY +$criterias = []; +$clause = ''; + +//Check for $_GET variables and build up clause +if(isset($get_content) && $get_content!=''){ + //GET VARIABLES FROM URL + $requests = explode("&", $get_content); + //Check for keys and values + foreach ($requests as $y){ + $v = explode("=", $y); + //INCLUDE VARIABLES IN ARRAY + $criterias[$v[0]] = $v[1]; + + if ($v[0] == 'page' || $v[0] =='p' || $v[0] =='totals' || $v[0] =='list' || $v[0] =='history'|| $v[0] =='success_msg'){ + //do nothing + } + elseif ($v[0] == 'search') { + //build up search + $clause .= ' AND variable like :'.$v[0]; + } + else {//create clause + $clause .= ' AND '.$v[0].' = :'.$v[0]; + } + } + if ($whereclause == '' && $clause !=''){ + $whereclause = 'WHERE '.substr($clause, 4); + } else { + $whereclause .= $clause; + } +} +//Define Query +if(isset($criterias['totals']) && $criterias['totals'] ==''){ +//Request for total rows + $sql = 'SELECT count(*) as count FROM products_attributes_groups '.$whereclause.''; +} +else { + //SQL for Paging + $sql = 'SELECT * FROM products_attributes_groups '.$whereclause.' LIMIT :page,:num_products'; +} + +$stmt = $pdo->prepare($sql); + +//Bind to query +if (str_contains($whereclause, ':condition')){ + $stmt->bindValue('condition', $condition, PDO::PARAM_STR); +} + +if (!empty($criterias)){ + foreach ($criterias as $key => $value){ + $key_condition = ':'.$key; + if (str_contains($whereclause, $key_condition)){ + if ($key == 'search'){ + $search_value = '%'.$value.'%'; + $stmt->bindValue($key, $search_value, PDO::PARAM_STR); + } + else { + $stmt->bindValue($key, $value, PDO::PARAM_STR); + } + } + } +} + +//Add paging details +if(isset($criterias['totals']) && $criterias['totals']==''){ + $stmt->execute(); + $messages = $stmt->fetch(); + $messages = $messages[0]; +} +else { + $current_page = isset($criterias['p']) && is_numeric($criterias['p']) ? (int)$criterias['p'] : 1; + $stmt->bindValue('page', ($current_page - 1) * $page_rows_products_attributes, PDO::PARAM_INT); + $stmt->bindValue('num_products', $page_rows_products_attributes, PDO::PARAM_INT); + + //Excute Query + $stmt->execute(); + //Get results + $messages = $stmt->fetchAll(PDO::FETCH_ASSOC); +} + +//------------------------------------------ +//JSON_ENCODE +//------------------------------------------ +$messages = json_encode($messages, JSON_UNESCAPED_UNICODE); + +//Send results +echo $messages; + +?> \ No newline at end of file diff --git a/api/v2/get/products_attributes_items.php b/api/v2/get/products_attributes_items.php new file mode 100644 index 0000000..bf4f0eb --- /dev/null +++ b/api/v2/get/products_attributes_items.php @@ -0,0 +1,118 @@ +soldto) || $partner->soldto == ''){$soldto_search = '%';} else {$soldto_search = '-%';} + +//default whereclause +$whereclause = ''; + +switch ($permission) { + case '4': + $whereclause = ''; + break; + case '3': + $whereclause = ''; + break; + default: + $condition = '__salesid___'.$partner->salesid.'___soldto___'.substr($partner->soldto, 0, strpos($partner->soldto, "-")).$soldto_search; + $whereclause = 'WHERE accounthierarchy like "'.$condition.'"'; + break; +} + +//NEW ARRAY +$criterias = []; +$clause = ''; + +//Check for $_GET variables and build up clause +if(isset($get_content) && $get_content!=''){ + //GET VARIABLES FROM URL + $requests = explode("&", $get_content); + //Check for keys and values + foreach ($requests as $y){ + $v = explode("=", $y); + //INCLUDE VARIABLES IN ARRAY + $criterias[$v[0]] = $v[1]; + + if ($v[0] == 'page' || $v[0] =='p' || $v[0] =='totals' || $v[0] =='list' || $v[0] =='history'|| $v[0] =='success_msg'){ + //do nothing + } + elseif ($v[0] == 'search') { + //build up search + $clause .= ' AND translation like :'.$v[0]; + } + else {//create clause + $clause .= ' AND '.$v[0].' = :'.$v[0]; + } + } + if ($whereclause == '' && $clause !=''){ + $whereclause = 'WHERE '.substr($clause, 4); + } else { + $whereclause .= $clause; + } +} +//Define Query +if(isset($criterias['totals']) && $criterias['totals'] ==''){ +//Request for total rows + $sql = 'SELECT count(*) as count FROM products_attributes_items '.$whereclause.''; +} +else { + //SQL for Paging + $sql = 'SELECT * FROM products_attributes_items '.$whereclause.' LIMIT :page,:num_products'; +} + +$stmt = $pdo->prepare($sql); + +//Bind to query +if (str_contains($whereclause, ':condition')){ + $stmt->bindValue('condition', $condition, PDO::PARAM_STR); +} + +if (!empty($criterias)){ + foreach ($criterias as $key => $value){ + $key_condition = ':'.$key; + if (str_contains($whereclause, $key_condition)){ + if ($key == 'search'){ + $search_value = '%'.$value.'%'; + $stmt->bindValue($key, $search_value, PDO::PARAM_STR); + } + else { + $stmt->bindValue($key, $value, PDO::PARAM_STR); + } + } + } +} + +//Add paging details +if(isset($criterias['totals']) && $criterias['totals']==''){ + $stmt->execute(); + $messages = $stmt->fetch(); + $messages = $messages[0]; +} +else { + $current_page = isset($criterias['p']) && is_numeric($criterias['p']) ? (int)$criterias['p'] : 1; + $stmt->bindValue('page', ($current_page - 1) * $page_rows_products_attributes, PDO::PARAM_INT); + $stmt->bindValue('num_products', $page_rows_products_attributes, PDO::PARAM_INT); + + //Excute Query + $stmt->execute(); + //Get results + $messages = $stmt->fetchAll(PDO::FETCH_ASSOC); +} + +//------------------------------------------ +//JSON_ENCODE +//------------------------------------------ +$messages = json_encode($messages, JSON_UNESCAPED_UNICODE); + +//Send results +echo $messages; + +?> \ No newline at end of file diff --git a/api/v2/post/products_attributes.php b/api/v2/post/products_attributes.php new file mode 100644 index 0000000..ccc68a6 --- /dev/null +++ b/api/v2/post/products_attributes.php @@ -0,0 +1,105 @@ +soldto) || $partner->soldto == ''){$soldto_search = '%';} else {$soldto_search = '-%';} + +//default whereclause +$whereclause = ''; + +switch ($permission) { + case '4': + $whereclause = ''; + break; + case '3': + $whereclause = ''; + break; + default: + $condition = '__salesid___'.$partner->salesid.'___soldto___'.substr($partner->soldto, 0, strpos($partner->soldto, "-")).$soldto_search; + $whereclause = ' AND accounthierarchy like "'.$condition.'"'; + break; +} + +//SET PARAMETERS FOR QUERY +$id = $post_content['rowID'] ?? ''; //check for rowID +$command = ($id == '')? 'insert' : 'update'; //IF rowID = empty then INSERT +if (isset($post_content['delete'])){$command = 'delete';} //change command to delete +$date = date('Y-m-d H:i:s'); + +//CREATE EMPTY STRINGS +$clause = ''; +$clause_insert =''; +$input_insert = ''; + +//BUILD UP PARTNERHIERARCHY FROM USER +$partner_product = json_encode(array("salesid"=>$partner->salesid,"soldto"=>$partner->soldto), JSON_UNESCAPED_UNICODE); + +//ADD STANDARD PARAMETERS TO ARRAY BASED ON INSERT OR UPDATE +if ($command == 'update'){ + $post_content['updatedby'] = $username ; + +} +elseif ($command == 'insert'){ + $post_content['createdby'] = $username; + $post_content['accounthierarchy'] = $partner_product; +} +else { + //do nothing +} + +//CREAT NEW ARRAY AND MAP TO CLAUSE +if(isset($post_content) && $post_content!=''){ + foreach ($post_content as $key => $var){ + if ($key == 'submit' || $key == 'rowID'){ + //do nothing + } + else { + $criterias[$key] = $var; + $clause .= ' , '.$key.' = ?'; + $clause_insert .= ' , '.$key.''; + $input_insert .= ', ?'; // ? for each insert item + $execute_input[]= $var; // Build array for input + } + } +} + +//CLEAN UP INPUT +$clause = substr($clause, 2); //Clean clause - remove first comma +$clause_insert = substr($clause_insert, 2); //Clean clause - remove first comma +$input_insert = substr($input_insert, 1); //Clean clause - remove first comma + +//QUERY AND VERIFY ALLOWED +if ($command == 'update' && isAllowed('products_attributes_manage',$profile,$permission,'U') === 1){ + $sql = 'UPDATE products_attributes_groups SET '.$clause.' WHERE rowID = ? '.$whereclause.''; + $execute_input[] = $id; + $stmt = $pdo->prepare($sql); + $stmt->execute($execute_input); +} +elseif ($command == 'insert' && isAllowed('products_attributes_manage',$profile,$permission,'C') === 1){ + $sql = 'INSERT INTO products_attributes_groups('.$clause_insert.') VALUES ('.$input_insert.')'; + $stmt = $pdo->prepare($sql); + $stmt->execute($execute_input); + // Return ID + echo json_encode(array('rowID'=> $pdo->lastInsertId())); +} +elseif ($command == 'delete' && isAllowed('products_attributes_manage',$profile,$permission,'D') === 1){ + $stmt = $pdo->prepare('DELETE FROM products_attributes_groups WHERE rowID = ? '.$whereclause.''); + $stmt->execute([ $id ]); + + //Add deletion to changelog + changelog($dbname,'products_attributes_groups',$id,'Delete','Delete',$username); +} else +{ + //do nothing +} + +?> \ No newline at end of file diff --git a/api/v2/post/products_attributes_items.php b/api/v2/post/products_attributes_items.php new file mode 100644 index 0000000..0a0cb86 --- /dev/null +++ b/api/v2/post/products_attributes_items.php @@ -0,0 +1,103 @@ +soldto) || $partner->soldto == ''){$soldto_search = '%';} else {$soldto_search = '-%';} + +//default whereclause +$whereclause = ''; + +switch ($permission) { + case '4': + $whereclause = ''; + break; + case '3': + $whereclause = ''; + break; + default: + $condition = '__salesid___'.$partner->salesid.'___soldto___'.substr($partner->soldto, 0, strpos($partner->soldto, "-")).$soldto_search; + $whereclause = ' AND accounthierarchy like "'.$condition.'"'; + break; +} + +//SET PARAMETERS FOR QUERY +$id = $post_content['rowID'] ?? ''; //check for rowID +$command = ($id == '')? 'insert' : 'update'; //IF rowID = empty then INSERT +if (isset($post_content['delete'])){$command = 'delete';} //change command to delete +$date = date('Y-m-d H:i:s'); + +//CREATE EMPTY STRINGS +$clause = ''; +$clause_insert =''; +$input_insert = ''; + +//BUILD UP PARTNERHIERARCHY FROM USER +$partner_product = json_encode(array("salesid"=>$partner->salesid,"soldto"=>$partner->soldto), JSON_UNESCAPED_UNICODE); + +//ADD STANDARD PARAMETERS TO ARRAY BASED ON INSERT OR UPDATE +if ($command == 'update'){ + $post_content['updatedby'] = $username ; + +} +elseif ($command == 'insert'){ + $post_content['createdby'] = $username; + $post_content['accounthierarchy'] = $partner_product; +} +else { + //do nothing +} + +//CREAT NEW ARRAY AND MAP TO CLAUSE +if(isset($post_content) && $post_content!=''){ + foreach ($post_content as $key => $var){ + if ($key == 'submit' || $key == 'update' || $key == 'add' ||$key == 'rowID'){ + //do nothing + } + else { + $criterias[$key] = $var; + $clause .= ' , '.$key.' = ?'; + $clause_insert .= ' , '.$key.''; + $input_insert .= ', ?'; // ? for each insert item + $execute_input[]= $var; // Build array for input + } + } +} + +//CLEAN UP INPUT +$clause = substr($clause, 2); //Clean clause - remove first comma +$clause_insert = substr($clause_insert, 2); //Clean clause - remove first comma +$input_insert = substr($input_insert, 1); //Clean clause - remove first comma + +//QUERY AND VERIFY ALLOWED +if ($command == 'update' && isAllowed('products_attributes_manage',$profile,$permission,'U') === 1){ + $sql = 'UPDATE products_attributes_items SET '.$clause.' WHERE rowID = ? '.$whereclause.''; + $execute_input[] = $id; + $stmt = $pdo->prepare($sql); + $stmt->execute($execute_input); +} +elseif ($command == 'insert' && isAllowed('products_attributes_manage',$profile,$permission,'C') === 1){ + $sql = 'INSERT INTO products_attributes_items ('.$clause_insert.') VALUES ('.$input_insert.')'; + $stmt = $pdo->prepare($sql); + $stmt->execute($execute_input); +} +elseif ($command == 'delete' && isAllowed('products_attributes_manage',$profile,$permission,'D') === 1){ + $stmt = $pdo->prepare('DELETE FROM products_attributes_items WHERE rowID = ? '.$whereclause.''); + $stmt->execute([ $id ]); + + //Add deletion to changelog + changelog($dbname,'products_attributes_items',$id,'Delete','Delete',$username); +} else +{ + //do nothing +} + +?> \ No newline at end of file diff --git a/products_attributes.php b/products_attributes.php new file mode 100644 index 0000000..d885978 --- /dev/null +++ b/products_attributes.php @@ -0,0 +1,153 @@ + +
+ +
+

'.($text_variables_h2 ?? '').' ('.$query_total.')

+

'.($text_variables_p ?? '').'

+
+
+'; + +if (isset($success_msg)){ +$view .= '
+ +

'.$success_msg.'

+ +
'; +} +$view .= ' +
+ '.($button_create_text_variable ?? '').' +
+ + +
+
+'; + +$view .= ' +
+
+ + + + + + + + + + + '; + + if (empty($responses)){ + + $view .= ' + + + '; + } + else { + foreach ($responses as $response){ + $view .= ' + + + + + + '; + + + } + } +$view .= ' + +
'.($text_variable_rowID ?? '').''.($text_variable_variable ?? '').''.$general_created.''.$general_actions.'
'.($message_no_text_variables ?? '').'
'.$response['rowID'].''.$response['variable'].''.getRelativeTime($response['created']).''.$general_view .'
+
+
+'; + +$view.=''; +//OUTPUT +echo $view; + +template_footer(); +?> \ No newline at end of file diff --git a/products_attributes_manage.php b/products_attributes_manage.php new file mode 100644 index 0000000..07ac8b0 --- /dev/null +++ b/products_attributes_manage.php @@ -0,0 +1,297 @@ + '', + 'variable' => '', + 'created' => '', + 'createdby' => '', + 'updated' => '', + 'updatedby' => '', + 'accounthierarchy' => '' +]; + +if (isset($_GET['rowID'])) { + //CALL TO API + $api_url = '/v2/translations/rowID='.$_GET['rowID']; + $responses = ioServer($api_url,''); + //Decode Payload + if (!empty($responses)){$responses = json_decode($responses,true);}else{$responses = null;} + + $text_variable = json_decode(json_encode($responses[0]), true); + + //CALL TO API FOR RELATED TRANSLATIONS + $api_url = '/v2/translations_details/variable_ID='.$_GET['rowID']; + $text_variable_translations = ioServer($api_url,''); + //Decode Payload + if (!empty($text_variable_translations)){$text_variable_translations = json_decode($text_variable_translations,true);}else{$text_variable_translations = null;} + + if ($update_allowed === 1){ + if (isset($_POST['submit'])) { + + //GET ALL POST DATA + $payload = json_encode($_POST, JSON_UNESCAPED_UNICODE); + //API call + $responses = ioServer('/v2/translations', $payload); + + if ($responses === 'NOK'){ + + } else { + header('Location: index.php?page=translations&success_msg=2'); + exit; + } + } + + if (isset($_POST['update']) || isset($_POST['add'])) { + + //GET ALL POST DATA + $payload = json_encode($_POST, JSON_UNESCAPED_UNICODE); + //API call + $responses = ioServer('/v2/translations_details', $payload); + + if ($responses === 'NOK'){ + + } else { + header('Location: index.php?page=translation_manage&rowID='.$_GET['rowID'].''); + exit; + } + + } + } + + if ($delete_allowed === 1){ + if (isset($_POST['delete'])) { + //GET ALL POST DATA + $payload = json_encode($_POST, JSON_UNESCAPED_UNICODE); + //API call + $responses = ioServer('/v2/translations', $payload); + // Redirect and delete product + if ($responses === 'NOK'){ + + } else { + header('Location: index.php?page=translations&success_msg=3'); + exit; + } + } + } + +} else { + // Create a new variable + if (isset($_POST['submit']) && $create_allowed === 1) { + //GET ALL POST DATA + $payload = json_encode($_POST, JSON_UNESCAPED_UNICODE); + //API call + $responses = ioServer('/v2/translations', $payload); + + if ($responses === 'NOK'){ + + } else { + //GET ROWID OF CREATED ITEM + $variable_rowID = json_decode($responses,true); + header('Location: index.php?page=translation_manage&rowID='.$variable_rowID['rowID'].''); + exit; + } + } +} +//EMPTY VIEW +$view = ''; + +// Handle success messages +if (isset($_GET['success_msg'])) { + if ($_GET['success_msg'] == 0) { + $success_msg = $error_msg_0; + } +} + +template_header('Translation', 'translation', 'manage'); + +if (isset($success_msg)){ + $view .= '
+ +

'.$success_msg.'

+ +
'; +} + +$view .=' +
+
+

'.($text_variables_h2 ?? '').'

+ '.$button_cancel.' +'; + +if ($delete_allowed === 1){ + $view .= ''; +} +if ($update_allowed === 1){ + $view .= ''; +} + +$view .= '
'; + +$view .= '
+ '.$tab1 .' + '.$tab3.' +
+ '; + +//Define Service and User enabled +$view .= '
+
+ + + + '; + +$view .= '
+
'; + +$view .= '
+
+ + + + + + + + +
+
'; +$view .= '
'; + + +$view .= ' +
+ +
+
+ +
+ + + + + + + + + + + '; + + if (empty($text_variable_translations)){ + $view .= ' + + + + '; + } + else { + foreach ($text_variable_translations as $translation){ + $view .= ' + + + + + + + + + + '; + } + } +$view .= ' + +
'.($text_variable_translation_languagekey ?? '').''.($text_variable_translation_translation ?? '').''.$general_created.''.$general_actions.'
'.($message_no_text_variables ?? '').'
+ '.getRelativeTime($translation['created']).'
+ + +
+
+'; + + + +//Output +echo $view; +template_footer() +?> \ No newline at end of file diff --git a/settings/settingsmenu.php b/settings/settingsmenu.php index 641c394..ff4aaa1 100644 --- a/settings/settingsmenu.php +++ b/settings/settingsmenu.php @@ -13,7 +13,7 @@ $main_menu = array ('dashboard','sales','buildtool','cartests','marketing','equi //Sub menus $equipments_sub = array('equipments','servicereports','rmas','histories','firmwaretool','equipments_mass_update'); $sales_sub = array('accounts','contracts'); -$products_sub = array('products'); +$products_sub = array('products','attributes'); $admin_sub = array('users','communications','partners'); $reporting_sub = array('report_build','report_contracts_billing','report_healthindex','report_usage'); $settings_sub = array('config','translations','logfile','maintenance','profiles'); @@ -68,6 +68,12 @@ $urls = array( "icon" => "fas fa-box-open", "name" => "menu_products" ), + "attributes" => array( + "url" => "products_attributes", + "selected" => "products_attributes", + "icon" => "fas fa-box-open", + "name" => "menu_products_attributes" + ), "sales" => array( "url" => "contracts", "selected" => "contracts", @@ -219,6 +225,7 @@ $page_rows_equipment_servicereporst = 5 ;// Number of service reports on equipme $page_rows_changelog = 50 ;// Number of changelogs returned $page_rows_rma = 25; // list RMA $page_rows_translations = 50; //list translation variables +$page_rows_products_attributes = 50; //list product attributes //------------------------------------------ // Languages supported diff --git a/settings/settingsprofiles.php b/settings/settingsprofiles.php index 7e46c7e..ec2c942 100644 --- a/settings/settingsprofiles.php +++ b/settings/settingsprofiles.php @@ -6,7 +6,7 @@ define('superuser_profile','dashboard,profile,assets,equipments,equipment,equipm /*Admin*/ define('admin_profile','dashboard,profile,buildtool,sales,accounts,account,contracts,contract,contract_manage,cartests,cartest,cartest_manage,assets,equipments,equipment,equipment_healthindex,equipment_data,equipment_manage,equipment_manage_edit,equipments_mass_update,histories,history,history_manage,firmwaretool,buildtool,products,products_versions,products_software,product,product_manage,servicereports,servicereport,admin,partners,partner,users,user,user_manage,communications,communication,communication_send,marketing,reporting,report_build,report_contracts_billing,report_healthindex,changelog,application'); /*AdminPlus*/ -define('adminplus_profile','dashboard,profile,buildtool,sales,accounts,account,contracts,contract,contract_manage,cartests,cartest,cartest_manage,assets,equipments,equipment,equipment_healthindex,equipment_data,equipment_manage,equipment_manage_edit,equipments_mass_update,histories,history,history_manage,firmwaretool,rmas,rma,rma_manage,rma_history,rma_history_manage,buildtool,products,products_versions,products_software,product,product_manage,servicereports,servicereport,admin,partners,partner,users,user,user_manage,communications,communication,communication_send,marketing,reporting,report_build,report_contracts_billing,report_healthindex,report_usage,config,settings,logfile,changelog,language,application,maintenance,profiles,vin'); +define('adminplus_profile','dashboard,profile,buildtool,sales,accounts,account,contracts,contract,contract_manage,billing,cartests,cartest,cartest_manage,assets,equipments,equipment,equipment_healthindex,equipment_data,equipment_manage,equipment_manage_edit,equipments_mass_update,histories,history,history_manage,firmwaretool,rmas,rma,rma_manage,rma_history,rma_history_manage,buildtool,products,products_versions,products_software,product,product_manage,servicereports,servicereport,admin,partners,partner,users,user,user_manage,communications,communication,communication_send,marketing,reporting,report_build,report_contracts_billing,report_healthindex,report_usage,config,settings,logfile,changelog,language,translations,translations_details,translation_manage,application,maintenance,profiles,vin'); /*Build*/ define('build','dashboard,profile,buildtool,firmwaretool,buildtool,products_software,application'); /*Distribution*/ diff --git a/settings/settingsviews.php b/settings/settingsviews.php index 7ba8b99..b569625 100644 --- a/settings/settingsviews.php +++ b/settings/settingsviews.php @@ -38,6 +38,8 @@ $all_views = [ "products", "products_versions", "products_software", + "products_attributes", + "products_attributes_manage", "product", "product_manage", "servicereports",