diff --git a/CHANGELOG.md b/CHANGELOG.md index ba20da30..6c5436df 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,18 @@ # CHANGELOG +### Version 11.0 +- Making SDS GA +- Added maximum allowed usage for a formula +- Changed datatype for PubChem to json +- Added a button to view ingredient data in PubChem +- Fix PubChemData update button +- Added more error handling for ajax requests +- Added a var (pvSearch) to search ingredients in the local datatabase +- Changed the way the ingredient is handled when exists in a formula but not in the database. Instead of auto creating it when clicked, it presents options to create it, search in PV Online or import via JSON +- Added editability in IFRA Library +- Fix a bug preventing adding new ingredients +- Treat empty IFRA Library values (PROHIBITION, SPECIFICATION) as 0% allowed +- IFRA structure images import improvements + ### Version 10.9 - Sys update check improvements - Dashboard page updates diff --git a/README.md b/README.md index 42943dcd..0b169329 100755 --- a/README.md +++ b/README.md @@ -62,7 +62,6 @@ Please note, all DB_ variables are required. or via docker compose --- - version: '3.8' services: pvdb: image: mariadb:10.5 diff --git a/VERSION.md b/VERSION.md index 73def33c..2dbc24b3 100755 --- a/VERSION.md +++ b/VERSION.md @@ -1 +1 @@ -10.9 +11.0 diff --git a/core/finished_formula_data.php b/core/finished_formula_data.php index c403a14b..01352ad7 100644 --- a/core/finished_formula_data.php +++ b/core/finished_formula_data.php @@ -126,15 +126,29 @@ $r['cost'] = (float)calcCosts(getPrefSupplier($ing_q['id'],$conn)['price'],$new_quantity, $formula['concentration'], getPrefSupplier($ing_q['id'],$conn)['size']); } - $u = explode(' - ',searchIFRA($ing_q['cas'],$formula['ingredient'],null,$defCatClass)); - - if(($u['0'] && $ing_q['byPassIFRA'] == 0)){ - $r['usage_limit'] = number_format((float)$u['0']?:100, $settings['qStep']); - $r['usage_restriction'] = (string)$u['1'] ?: 'N/A'; + //$u = explode(' - ',searchIFRA($ing_q['cas'],$formula['ingredient'],null,$defCatClass)); + $u = searchIFRA($ing_q['cas'],$formula['ingredient'],null,$defCatClass); + + //if(($u['0'] && $ing_q['byPassIFRA'] == 0)){ + if(($u['val'] || $u['type'] && $ing_q['byPassIFRA'] == 0)){ + $r['usage_limit'] = number_format((float)$u['val']?:100, $settings['qStep']); + $r['usage_restriction'] = (string)$u['risk'] ?: 'N/A'; + $r['usage_restriction_type'] = (string)$u['type'] ?: 'N/A'; $r['usage_regulator'] = (string)"IFRA"; }else{ $r['usage_limit'] = number_format((float)$ing_q["$defCatClass"], $settings['qStep']) ?: 100; $r['usage_restriction'] = (int)$ing_q['classification']; + if ($ing_q['classification'] == 1) { + $r['usage_restriction_type'] = 'RECOMMENDATION'; + } elseif ($ing_q['classification'] == 2) { + $r['usage_restriction_type'] = 'RESTRICTION'; + } elseif ($ing_q['classification'] == 3) { + $r['usage_restriction_type'] = 'SPECIFICATION'; + } elseif ($ing_q['classification'] == 4) { + $r['usage_restriction_type'] = 'PROHIBITION'; + } else { + $r['usage_restriction_type'] = 'RECOMMENDATION'; + } $r['usage_regulator'] = (string)"PV"; $r['ingredient']['classification'] = (int)$ing_q['classification'] ?: 1; } diff --git a/core/full_formula_data.php b/core/full_formula_data.php index bab7e72c..9995b4fa 100644 --- a/core/full_formula_data.php +++ b/core/full_formula_data.php @@ -121,6 +121,7 @@ foreach ($form as $formula){ $ing_q = mysqli_fetch_array(mysqli_query($conn, "SELECT id, name, cas, $defCatClass, profile, odor, category, physical_state,usage_type AS classification, type, byPassIFRA FROM ingredients WHERE name = '".$formula['ingredient']."'")); + /* $reps = mysqli_query($conn,"SELECT ing_rep_name FROM ingReplacements WHERE ing_name = '".$formula['ingredient']."'"); if (mysqli_num_rows($reps)==0) { $reps = mysqli_query($conn,"SELECT ing_name FROM ingReplacements WHERE ing_rep_name = '".$formula['ingredient']."'"); @@ -128,7 +129,7 @@ while($replacements = mysqli_fetch_array($reps)){ $replacement[] = $replacements; } - + */ $totalcontainsOthers = mysqli_num_rows(mysqli_query($conn, "SELECT name,$defPercentage,cas FROM ingredient_compounds WHERE ing = '".$formula['ingredient']."'")); @@ -192,15 +193,28 @@ } - $u = explode(' - ',searchIFRA($ing_q['cas'],$formula['ingredient'],null,$defCatClass)); + $u = searchIFRA($ing_q['cas'],$formula['ingredient'],null,$defCatClass); - if(($u['0'] && $ing_q['byPassIFRA'] == 0)){ - $r['usage_limit'] = number_format((float)$u['0']?:100, $settings['qStep']); - $r['usage_restriction'] = (string)$u['1'] ?: 'N/A'; + if(($u['val'] || $u['type'] && $ing_q['byPassIFRA'] == 0)){ + $r['usage_limit'] = (float)number_format((float)$u['val'], $settings['qStep']); + $r['usage_restriction'] = (string)$u['risk'] ?: 'N/A'; + $r['usage_restriction_type'] = (string)$u['type'] ?: 'N/A'; $r['usage_regulator'] = (string)"IFRA"; }else{ $r['usage_limit'] = number_format((float)$ing_q["$defCatClass"], $settings['qStep']) ?: 100; $r['usage_restriction'] = (int)$ing_q['classification']; + + if ($ing_q['classification'] == 1) { + $r['usage_restriction_type'] = 'RECOMMENDATION'; + } elseif ($ing_q['classification'] == 2) { + $r['usage_restriction_type'] = 'RESTRICTION'; + } elseif ($ing_q['classification'] == 3) { + $r['usage_restriction_type'] = 'SPECIFICATION'; + } elseif ($ing_q['classification'] == 4) { + $r['usage_restriction_type'] = 'PROHIBITION'; + } else { + $r['usage_restriction_type'] = 'RECOMMENDATION'; + } $r['usage_regulator'] = (string)"PV"; $r['ingredient']['classification'] = (int)$ing_q['classification'] ?: 1; } @@ -217,7 +231,6 @@ $r['ingredient']['name'] = (string)$ingName ?: $formula['ingredient']; $r['ingredient']['cas'] = (string)$ing_q['cas'] ?: 'N/A'; $r['ingredient']['physical_state'] = (int)$ing_q['physical_state']; - //$r['ingredient']['classification'] = (int)$ing_q['classification'] ?: 1; $r['ingredient']['type'] = (string)$ing_q['type'] ?: 'Unknown'; $r['ingredient']['desc'] = (string)$desc ?: '-'; @@ -229,17 +242,11 @@ $r['ingredient']['inventory']['batch'] = (string)$inventory['batch'] ?: 'N/A'; $r['ingredient']['inventory']['purchased'] = (string)$inventory['purchased'] ?: 'N/A'; - //$totalReplacements = 0; - //foreach ($replacement as $rp){ - // $totalReplacements++; - // $r['ingredient'][]['replacement']['name'] = (string)$rp['ing_rep_name'] ?: (string)$rp['ing_name'] ?: 'N/A'; - //} - //$r['ingredient']['replacement']['total'] = $totalReplacements ?: 0; - $r['ingredient']['containsOthers']['total'] = $totalcontainsOthers ?: 0; - $r['chk_ingredient'] = (string)checkIng($formula['ingredient'],$defCatClass,$conn) ?: null; + $r['chk_ingredient'] = (string)checkIng($formula['ingredient'],$defCatClass,$conn)['text']; + $r['chk_ingredient_code'] = (int)checkIng($formula['ingredient'],$defCatClass,$conn)['code']; $r['exclude_from_calculation'] = (int)$formula['exclude_from_calculation'] ?: 0; @@ -273,6 +280,24 @@ $m['formula_description'] = (string)$meta['notes']; $m['protected'] = (bool)$meta['isProtected']; +$lastValAccepted = null; + +for ($c = 1; $c <= 100; $c++) { + $result = validateFormula($meta['fid'], 100, $c, $mg['total_mg'], $defCatClass, $settings['qStep']); + + if ($result === 0) { + $lastValAccepted = $c; + } else { + break; + } +} +if( $lastValAccepted !== null) { + + $m['max_usage'] = $lastValAccepted; +} else { + $m['max_usage'] = 'Unable to calculate'; +} +/* $new_conc = $_GET['final_total_ml'] ?: 100/100*$_GET['final_type_conc'] ?: 100; $carrier = $_GET['final_total_ml'] ?: 100 - $new_conc; @@ -292,6 +317,7 @@ $compliance['message'] = (string)$val_msg ?: 'Formula is IFRA compliant'; $response['compliance'] = $compliance; +*/ $response['meta'] = $m; $s['load_time'] = microtime(true) - $starttime; diff --git a/core/list_IFRA_data.php b/core/list_IFRA_data.php index 0cea9ce2..d65a3825 100644 --- a/core/list_IFRA_data.php +++ b/core/list_IFRA_data.php @@ -47,24 +47,24 @@ $r['risk'] = (string)$IFRA['risk']?:'N/A'; $r['contrib_others'] = (string)$IFRA['contrib_others']?:'N/A'; $r['contrib_others_notes'] = (string)$IFRA['contrib_others_notes']?:'N/A'; - $r['cat1'] = (float)$IFRA['cat1']?:'N/A'; - $r['cat2'] = (float)$IFRA['cat2']?:'N/A'; - $r['cat3'] = (float)$IFRA['cat3']?:'N/A'; - $r['cat4'] = (float)$IFRA['cat4']?:'N/A'; - $r['cat5A'] = (float)$IFRA['cat5A']?:'N/A'; - $r['cat5B'] = (float)$IFRA['cat5B']?:'N/A'; - $r['cat5C'] = (float)$IFRA['cat5C']?:'N/A'; - $r['cat5D'] = (float)$IFRA['cat5D']?:'N/A'; - $r['cat6'] = (float)$IFRA['cat6']?:'N/A'; - $r['cat7A'] = (float)$IFRA['cat7A']?:'N/A'; - $r['cat7B'] = (float)$IFRA['cat7B']?:'N/A'; - $r['cat8'] = (float)$IFRA['cat8']?:'N/A'; - $r['cat9'] = (float)$IFRA['cat9']?:'N/A'; - $r['cat10A'] = (float)$IFRA['cat10A']?:'N/A'; - $r['cat10B'] = (float)$IFRA['cat10B']?:'N/A'; - $r['cat11A'] = (float)$IFRA['cat11A']?:'N/A'; - $r['cat11B'] = (float)$IFRA['cat11B']?:'N/A'; - $r['cat12'] = (float)$IFRA['cat12']?:'N/A'; + $r['cat1'] = (float)$IFRA['cat1']; + $r['cat2'] = (float)$IFRA['cat2']; + $r['cat3'] = (float)$IFRA['cat3']; + $r['cat4'] = (float)$IFRA['cat4']; + $r['cat5A'] = (float)$IFRA['cat5A']; + $r['cat5B'] = (float)$IFRA['cat5B']; + $r['cat5C'] = (float)$IFRA['cat5C']; + $r['cat5D'] = (float)$IFRA['cat5D']; + $r['cat6'] = (float)$IFRA['cat6']; + $r['cat7A'] = (float)$IFRA['cat7A']; + $r['cat7B'] = (float)$IFRA['cat7B']; + $r['cat8'] = (float)$IFRA['cat8']; + $r['cat9'] = (float)$IFRA['cat9']; + $r['cat10A'] = (float)$IFRA['cat10A']; + $r['cat10B'] = (float)$IFRA['cat10B']; + $r['cat11A'] = (float)$IFRA['cat11A']; + $r['cat11B'] = (float)$IFRA['cat11B']; + $r['cat12'] = (float)$IFRA['cat12']; $r['defCat']['class'] = (string)$defCatClass?:'N/A'; $r['defCat']['limit'] = (float)$IFRA[$defCatClass]?:'0'; diff --git a/core/list_formula_analysis_data.php b/core/list_formula_analysis_data.php index a5cf864c..0ab05ab1 100644 --- a/core/list_formula_analysis_data.php +++ b/core/list_formula_analysis_data.php @@ -48,8 +48,8 @@ } $r['contained_percentage'] = $conc_p; + $u = searchIFRA($get_data_ing['cas'], $get_data_ing['name'], null, $defCatClass); - $u = explode(' - ', searchIFRA($get_data_ing['cas'], $get_data_ing['name'], null, $defCatClass)); $r['max_allowed'] = $u[0]; $response['data'][] = $r; diff --git a/css/vault.css b/css/vault.css index e9ef7413..1247516c 100755 --- a/css/vault.css +++ b/css/vault.css @@ -174,6 +174,15 @@ a { font-weight: bold; } +.custom_profile_notes { + background-size: 30px 30px; + background-repeat:no-repeat; + display: inline-block; + height: 30px; + content:""; + font-weight: bold; +} + .img-formula { height: 60px; float: right; diff --git a/db/schema.ver b/db/schema.ver index 73def33c..2dbc24b3 100644 --- a/db/schema.ver +++ b/db/schema.ver @@ -1 +1 @@ -10.9 +11.0 diff --git a/docker-compose/compose.yaml b/docker-compose/compose.yaml index f0f2239f..5582e0cd 100644 --- a/docker-compose/compose.yaml +++ b/docker-compose/compose.yaml @@ -1,5 +1,4 @@ --- -version: '3.8' services: pvdb: image: mariadb:10.5 diff --git a/func/checkIng.php b/func/checkIng.php index 5b1b6592..45542c10 100755 --- a/func/checkIng.php +++ b/func/checkIng.php @@ -1,5 +1,5 @@ - 'Missing usage data', 'code' => 1]; } if(empty($chkPrice['price'])){ - return 'Missing pricing data'; + return ['text' => 'Missing pricing data', 'code' => 2]; } if(!($qValues['profile'])){ - return 'Missing profile data'; + return ['text' => 'Missing profile data', 'code' => 3]; } } }else{ - return 'Ingredient is missing from the database'; + return ['text' => 'Ingredient is missing from the database', 'code' => 4]; } } -?> + diff --git a/func/fixIFRACas.php b/func/fixIFRACas.php index 7d5439f4..a547d45c 100644 --- a/func/fixIFRACas.php +++ b/func/fixIFRACas.php @@ -1,27 +1,27 @@ - \ No newline at end of file diff --git a/func/searchIFRA.php b/func/searchIFRA.php index 7646d66d..9ec815db 100755 --- a/func/searchIFRA.php +++ b/func/searchIFRA.php @@ -1,31 +1,55 @@ $res['type'], + 'risk' => $res['risk'], + 'val' => null // val is null if $defCatClass is empty + ); + } else { + if (in_array($res['type'], ['PROHIBITION', 'SPECIFICATION'])) { + return array( + 'risk' => $res['risk'], + 'type' => $res['type'], + 'val' => 0 + ); + } else { + return array( + 'risk' => $res['risk'], + 'type' => $res['type'], + 'val' => $res[$defCatClass] + ); + } + } + } + } + } + + return null; // Fallback if no conditions are met } + ?> diff --git a/func/validateFormula.php b/func/validateFormula.php index 0e603071..c9e679cc 100644 --- a/func/validateFormula.php +++ b/func/validateFormula.php @@ -24,22 +24,27 @@ function validateFormula($fid, $bottle, $new_conc, $mg, $defCatClass, $qStep) { $ing = mysqli_fetch_array($ingredient_query); $cas = $ing['cas']; - $limitIFRA = searchIFRA($cas, $ingredient_name, null, $defCatClass); - $limit = explode(' - ', $limitIFRA)[0]; - + $limitIFRA = searchIFRA($cas,$ingredient_name,null,$defCatClass); + $limit = $limitIFRA['val']; + $type = $limitIFRA['type']; + + // Calculate new quantity and concentration $new_quantity = $formula['quantity'] / $mg * $new_conc; $conc = ($new_quantity / $bottle) * 100; $conc_p = number_format(($formula['concentration'] / 100) * $conc, $qStep); - if ($limit ) { + if ($limit) { if ($limit < $conc_p) { - $errors[] = "Ingredient $ingredient_name exceeds IFRA limit $limit%"; + $errors[] = "$ingredient_name exceeds IFRA limit $limit% - $type"; + if($type === "PROHIBITION"){ + $errors[] = "$type is PROHIBITED"; + } } } else { if ($ing[$defCatClass] !== null) { if ($ing[$defCatClass] < $conc_p) { - $errors[] = "Ingredient $ingredient_name exceeds local DB limit%"; + $errors[] = "$ingredient_name exceeds local DB limit $ing[$defCatClass]%"; } } else { $errors[] = "No limit record found for ingredient $ingredient_name"; diff --git a/index.php b/index.php index d5bc2a7e..10f393c0 100755 --- a/index.php +++ b/index.php @@ -162,188 +162,208 @@ function chkUpdate() { -
+
+ + + + + - + - - + + + + - - + + + + + My SDSs + + + + + if ($_GET['do'] == 'Formula') { + require_once(__ROOT__.'/pages/formula.php'); + } elseif ($_GET['do'] == 'ingredients') { + require_once(__ROOT__.'/pages/ingredients.php'); + } elseif ($_GET['do'] == 'settings') { + require_once(__ROOT__.'/pages/settings.php'); + } elseif ($_GET['do'] == 'marketplace') { + require_once(__ROOT__.'/pages/views/pvOnline/marketPlace.php'); + } elseif ($_GET['do'] == 'statistics') { + require_once(__ROOT__.'/pages/statistics.php'); + } elseif ($_GET['do'] == 'IFRA') { + require_once(__ROOT__.'/pages/IFRA.php'); + } elseif ($_GET['do'] == 'listFormulas') { + ?>
- -
-
-
- -
-
-
+ +
+
+
+
+
+
+
-
-
+
+
-
- - + + + - -
- - -