Skip to content

Commit

Permalink
Merge pull request #185 from globaldyne/v11.3
Browse files Browse the repository at this point in the history
V11.3
  • Loading branch information
globaldyne authored Sep 13, 2024
2 parents 8a91391 + 73770c9 commit 0865eca
Show file tree
Hide file tree
Showing 51 changed files with 801 additions and 307 deletions.
19 changes: 19 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,23 @@
# CHANGELOG
### Version 11.3
- Minor UI updates
- Fix merge ingredient returning incorrect value when nothing found
- Fix placeholder for ingredient selection in formula
- Added force delete for ingredients in use
- A new updated IFRA document added
- IFRA document will show the maximum limit per all categories for 100% concentration
- IFRA document will be generated regardless if final product is off ifra limits
- Fixed currency symbol for finished product
- Ingredient UI update
- Formula UI and backend update
- Structure update
- UI update for IFRA Library
- Refactor JSON import for IFRALibrary
- Increase filter box size
- Extended search to the product name for Batches
- Added delete option for Batches even if the pdf is missing
- Batches backend rewrite

### Version 11.2
- Refactor of backend
- Fix author name not display properly in the contact form in Marketplace
Expand Down
2 changes: 1 addition & 1 deletion VERSION.md
Original file line number Diff line number Diff line change
@@ -1 +1 @@
11.2
11.3
2 changes: 1 addition & 1 deletion core/finished_formula_data.php
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@


$m['cat_class'] = (string)$defCatClass;
$m['currency'] = (string)utf8_encode($settings['currency']);
$m['currency'] = (string)$settings['currency'];
$m['product_concentration'] = (int)$concentration;
$m['formula_name'] = (string)$meta['name'];
$m['product_name'] = (string)$meta['product_name'] ?: '-';
Expand Down
2 changes: 2 additions & 0 deletions core/full_formula_data.php
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,8 @@

if(empty($r)){
$response['data'] = [];
echo json_encode($response);
return;
}

$m['total_ingredients'] = (int)countElement("formulas WHERE fid = '".$meta['fid']."'",$conn);
Expand Down
41 changes: 41 additions & 0 deletions core/getIngInfo.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php
define('__ROOT__', dirname(dirname(__FILE__)));

require_once(__ROOT__.'/inc/sec.php');
require_once(__ROOT__.'/inc/opendb.php');
require_once(__ROOT__.'/inc/settings.php');
require_once(__ROOT__.'/func/searchIFRA.php');

if (isset($_GET['id']) && isset($_GET['filter'])) {
$id = mysqli_real_escape_string($conn, $_GET['id']);
$filters = explode(',', mysqli_real_escape_string($conn, $_GET['filter']));

$response = [];
foreach ($filters as $filter) {
if (!in_array($filter, ['solvent', 'purity'])) {
continue;
}

$query = "SELECT $filter FROM ingredients WHERE id = '$id'";
$info = mysqli_fetch_array(mysqli_query($conn, $query));

if ($info && isset($info[$filter])) {
switch ($filter) {
case "solvent":
$response[$filter] = $info[$filter] ?: "None";
break;
case "purity":
$response[$filter] = (float)$info[$filter] ?: 100;
break;
}
} else {
$response[$filter] = "No data";
}
}

header('Content-Type: application/json; charset=utf-8');
echo json_encode($response);
return;
}

?>
98 changes: 62 additions & 36 deletions core/list_batch_data.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,55 +5,81 @@
require_once(__ROOT__.'/inc/opendb.php');
require_once(__ROOT__.'/inc/settings.php');

$row = $_POST['start']?:0;
$limit = $_POST['length']?:10;
$row = isset($_POST['start']) ? (int)$_POST['start'] : 0;
$limit = isset($_POST['length']) ? (int)$_POST['length'] : 10;

$order_by = $_POST['order_by']?:'created';
$order = $_POST['order_as']?:'ASC';
$extra = "ORDER BY ".$order_by." ".$order;
$order_by = isset($_POST['order_by']) ? $_POST['order_by'] : 'created';
$order = isset($_POST['order_as']) && in_array(strtoupper($_POST['order_as']), ['ASC', 'DESC']) ? strtoupper($_POST['order_as']) : 'ASC';

$extra = "ORDER BY $order_by $order";

$s = trim($_POST['search']['value']);
$search_value = isset($_POST['search']['value']) ? trim($_POST['search']['value']) : '';
$f = '';

if($s != ''){
$f = "WHERE 1 AND (id LIKE '%".$s."%')";
if (!empty($search_value)) {
$f = "WHERE id LIKE ? OR product_name LIKE ?";
}

$q = mysqli_query($conn, "SELECT * FROM batchIDHistory $f $extra LIMIT $row, $limit");
while($res = mysqli_fetch_array($q)){
$query = "SELECT * FROM batchIDHistory $f $extra LIMIT ?, ?";
$stmt = $conn->prepare($query);

if (!empty($search_value)) {
$search_param = "%$search_value%";
$stmt->bind_param('ssii', $search_param, $search_param, $row, $limit);
} else {
$stmt->bind_param('ii', $row, $limit);
}

$stmt->execute();
$result = $stmt->get_result();

$rs = [];
while ($res = $result->fetch_assoc()) {
$rs[] = $res;
}

foreach ($rs as $rq) {

if(file_exists(__ROOT__.'/'.$rq['pdf']) === TRUE){
$s = 1;
}

$r['id'] = (string)$rq['id'];
$r['fid'] = (string)$rq['fid'];
$r['product_name'] = (string)$rq['product_name']?:'N/A';
$r['pdf'] = (string)$rq['pdf'];
$r['state'] = (int)$s?:0;
$r['created'] = (string)$rq['created'];

$rx[]=$r;
$rx = [];
foreach ($rs as $rq) {
$state = 0;
if (file_exists(__ROOT__.'/'.$rq['pdf'])) {
$state = 1;
}

$r = [
'id' => (string)$rq['id'],
'fid' => (string)$rq['fid'],
'product_name' => (string)$rq['product_name'] ?: 'N/A',
'pdf' => (string)$rq['pdf'],
'state' => (int)$state,
'created' => (string)$rq['created']
];

$rx[] = $r;
}
$total = mysqli_fetch_assoc(mysqli_query($conn,"SELECT COUNT(id) AS entries FROM batchIDHistory"));
$filtered = mysqli_fetch_assoc(mysqli_query($conn,"SELECT COUNT(id) AS entries FROM batchIDHistory ".$f));

$response = array(
"draw" => (int)$_POST['draw'],
"recordsTotal" => (int)$total['entries'],
"recordsFiltered" => (int)$filtered['entries'],
"data" => $rx
);

if(empty($r)){
$response['data'] = [];

$total_query = "SELECT COUNT(id) AS entries FROM batchIDHistory";
$total_result = mysqli_fetch_assoc(mysqli_query($conn, $total_query));

$filtered_query = "SELECT COUNT(id) AS entries FROM batchIDHistory $f";
$filtered_stmt = $conn->prepare($filtered_query);

if (!empty($search_value)) {
$filtered_stmt->bind_param('ss', $search_param, $search_param);
}
$filtered_stmt->execute();
$filtered_result = $filtered_stmt->get_result();
$filtered = $filtered_result->fetch_assoc();

$response = [
"draw" => isset($_POST['draw']) ? (int)$_POST['draw'] : 1,
"recordsTotal" => (int)$total_result['entries'],
"recordsFiltered" => (int)$filtered['entries'],
"data" => !empty($rx) ? $rx : []
];

header('Content-Type: application/json; charset=utf-8');
echo json_encode($response);

return;

?>
13 changes: 11 additions & 2 deletions css/vault.css
Original file line number Diff line number Diff line change
Expand Up @@ -1410,8 +1410,17 @@ hr.hr-text::before {
}

.dataTables_filter input {
width: 400px;
display: inline-block;
width: 400px !important;
height: 40px;
padding: 10px;
font-size: 16px;
}

.pvCustomSearch {
width: 400px;
height: 40px;
padding: 10px;
font-size: 16px;
}

input[type="search"]::-webkit-search-cancel-button {
Expand Down
92 changes: 91 additions & 1 deletion db/pvault.sql

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion db/schema.ver
Original file line number Diff line number Diff line change
@@ -1 +1 @@
11.2
11.3
91 changes: 91 additions & 0 deletions db/updates/update_11.2-11.3.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
INSERT INTO `templates` (`id`, `name`, `content`, `created`, `updated`, `description`) VALUES (NULL, 'IFRA Document Template', '<!doctype html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link rel="icon" type="image/png" sizes="32x32" href="/img/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/img/favicon-16x16.png">
<link href="/css/ifraCert.css" rel="stylesheet">
</head>
<body>
<div>
<p style="margin-bottom: 0.63in"><img src="%LOGO%" width="200px" /></p>
</div>
<h1 class="western"><font face="Arial, sans-serif"><span style="font-style: normal">CERTIFICATE OF CONFORMITY OF FRAGRANCE MIXTURES WITH IFRA STANDARDS</span></font><br>
</h1>
<p align=center style="widows: 0; orphans: 0"><font face="Helvetica 65 Medium, Arial Narrow, sans-serif"><font size=4><b><font face="Arial, sans-serif"><font size=2 style="font-size: 11pt"><u>This Certificate assesses the conformity of a fragrance mixture with IFRA Standards and provides restrictions for use as necessary. It is based only on those materials subject to IFRA Standards for the toxicity endpoint(s) described in each Standard. </u></font></font></b></font></font>
</p>
<p align=center style="widows: 0; orphans: 0"><br>
</p>
<hr size="1">
</p>
<p class="western"><font face="Arial, sans-serif"><u><b>CERTIFYING PARTY:</b></u></font></p>
<p class="western"><font face="Arial, sans-serif">%BRAND_NAME%</font></p>
<p class="western"><font face="Arial, sans-serif">%BRAND_ADDRESS%</font></p>
<p class="western"><font face="Arial, sans-serif">%BRAND_EMAIL%</font></p>
<p class="western"><font face="Arial, sans-serif">%BRAND_PHONE%</font></p>
</p>
<p class="western"><font face="Arial, sans-serif"><u><b>CERTIFICATE DELIVERED TO: </b></u></font>
</p>
<p class="western"><font face="Arial, sans-serif"><span ><b>Customer: </b></span></font></p>
<p class="western"><font face="Arial, sans-serif">%CUSTOMER_NAME%</font></p>
<p class="western"><font face="Arial, sans-serif">%CUSTOMER_ADDRESS%</font></p>
<p class="western"><font face="Arial, sans-serif">%CUSTOMER_EMAIL%</font></p>
<p class="western"><font face="Arial, sans-serif">%CUSTOMER_WEB%</font></p>
<p class="western"><br>
</p>
<p class="western"><font face="Arial, sans-serif"><u><b>SCOPE OF THE CERTIFICATE:</b></u></font></p>
<p class="western"><font face="Arial, sans-serif"><span >Product: <B>%PRODUCT_NAME%</b></span></font></p>
<p class="western">Size:<strong> %PRODUCT_SIZE%ml</strong></p>
<p class="western">Concentration: <strong>%PRODUCT_CONCENTRATION%%</strong></p>
<hr size="1"><br>
<font face="Arial, sans-serif"><span ><U><B>COMPULSORY INFORMATION:</b></u></span></font>
<p class="western" style="margin-right: -0.12in">
<font face="Arial, sans-serif"><span >We certify that the above mixture is in compliance with the Standards of the INTERNATIONAL FRAGRANCE ASSOCIATION (IFRA), up to and including the <strong>%IFRA_AMENDMENT%</strong> Amendment to the IFRA Standards (published </span><b>%IFRA_AMENDMENT_DATE%</span></b>),
provided it is used in the following</span></font> <font face="Arial, sans-serif"><span >category(ies)
at a maximum concentration level of:</span></font></p>
<p class="western" style="margin-right: -0.12in"> </p>
<table class="table table-stripped">
<tr>
<th bgcolor="#d9d9d9"><strong>IFRA Category</strong></th>
<th bgcolor="#d9d9d9"><strong>Description</strong></th>
<th bgcolor="#d9d9d9"><strong>Level of use (%)*</strong></th>
</tr>
<tr>
<td align="center">%IFRA_CAT_LIST%</td>
</tr>
</table>
<p class="western" style="margin-right: -0.12in"><font face="Arial, sans-serif"><I>*Actual use level or maximum use level at 100% concentration</I></font> </p>
<p class="western" style="margin-right: -0.12in">
<font face="Arial, sans-serif"><span >For other kinds of, application or use at higher concentration levels, a new evaluation may be needed; please contact </span></font><font face="Arial, sans-serif"><b>%BRAND_NAME%</b></font><font face="Arial, sans-serif"><span >.
</span></font></p>
<p class="western" style="margin-right: -0.12in"><font face="Arial, sans-serif"><span >Information about presence and concentration of fragrance ingredients subject to IFRA Standards in the fragrance mixture </span></font><font face="Arial, sans-serif"><B>%PRODUCT_NAME%</b></font><font face="Arial, sans-serif"><span> is as follows:</span></font></p>
<p class="western" style="margin-right: -0.12in"> </p>
<table class="table table-stripped">
<tr>
<th width="22%" bgcolor="#d9d9d9"><strong>Material(s) under the scope of IFRA Standards:</strong></th>
<th width="12%" bgcolor="#d9d9d9"><strong>CAS number(s):</strong></th>
<th width="28%" bgcolor="#d9d9d9"><strong>Recommendation (%) from IFRA Standard:</strong></th>
<th width="19%" bgcolor="#d9d9d9"><strong>Concentration (%) in finished product:</strong></th>
<th width="19%" bgcolor="#d9d9d9">Risk</th>
</tr>
%IFRA_MATERIALS_LIST%
</table>
<p> </p>
<p><font face="Arial, sans-serif"><span >Signature </span></font><font face="Arial, sans-serif"><span><i>(If generated electronically, no signature)</i></span></font></p>
<p><font face="Arial, sans-serif"><span >Date: </span></font><strong>%CURRENT_DATE%</strong></p>
</p>
<div>
<p style="margin-right: 0in; margin-top: 0.08in">
<font face="Segoe UI, sans-serif"><font size=1 style="font-size: 8pt"><span><u>Disclaimer</u>:
</span></font></font></p>
<p style="margin-right: 0in; margin-top: 0.08in"><font face="Segoe UI, sans-serif"><font size=1 style="font-size: 8pt"><span>This Certificate provides restrictions for use of the specified product based only on those materials restricted by IFRA Standards for the toxicity endpoint(s) described in each Standard.</span></font></font></p>
<p style="margin-right: 0in; margin-top: 0.08in"><font face="Segoe UI, sans-serif"><font size=1 style="font-size: 8pt"><span>This Certificate does not provide certification of a comprehensive safety assessment of all product constituents.</span></font></font></p>
<p style="margin-right: 0in; margin-top: 0.08in"><font face="Segoe UI, sans-serif"><font size=1 style="font-size: 8pt"><span> This certificate is the responsibility of the fragrance supplier issuing it. It has not been prepared or endorsed by IFRA in anyway. </span></font></font>
</p>
</div>
</body>
</html>', current_timestamp(), current_timestamp(), 'The default IFRA document template');
14 changes: 14 additions & 0 deletions func/convert_to_decimal_point.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php
if (!defined('pvault_panel')){ die('Not Found');}

function convert_to_decimal_point($number) {
$decimalPlaces = (int)$number;

if ($decimalPlaces > 0) {
return '.' . str_repeat('0', $decimalPlaces);
} else {
return '0'; // If 0 or negative, return plain 0
}
}

?>
11 changes: 7 additions & 4 deletions js/fullformula.view.js
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ $("#formula").on("click", ".open-replace-dialog", function () {

$("#repIngNameDest").select2({
width: '100%',
placeholder: 'Search for ingredient (name, cas)',
placeholder: '',
allowClear: true,
dropdownAutoWidth: true,
containerCssClass: "repIngNameDest",
Expand Down Expand Up @@ -309,12 +309,15 @@ $("#formula").on("click", ".open-replace-dialog", function () {


function formatIngredients (ingredientData) {
//console.log(ingredientData);
if (ingredientData.name === '') {
return 'Search for ingredient (name, cas)';
}

if (ingredientData.loading) {
return ingredientData.name;
}

//extrasShow();


if (!ingredientData.name){
return 'No ingredient found...';
}
Expand Down
Loading

0 comments on commit 0865eca

Please sign in to comment.