Merged with default stable

Fri, 14 Jun 2019 20:26:51 +0200

author
Michiel Broek <mbroek@mbse.eu>
date
Fri, 14 Jun 2019 20:26:51 +0200
branch
stable
changeset 413
cfd17cfe64dc
parent 403
0fc59d0aa3df (current diff)
parent 412
def3900207cc (diff)
child 414
a936a82cf3d9

Merged with default

config.status file | annotate | diff | comparison | revisions
configure file | annotate | diff | comparison | revisions
configure.ac file | annotate | diff | comparison | revisions
--- a/README.design	Wed Jun 05 20:06:14 2019 +0200
+++ b/README.design	Fri Jun 14 20:26:51 2019 +0200
@@ -20,3 +20,20 @@
 
 Koolzuurdruk tabel inbouwen.
 
+Bottelsuiker:
+
+x select name,type,yield,moisture from inventory_fermentables where type = 1 or type = 3;
+
+x Dit geeft de suikers en droge malt extracten. Hieruit is ook de opbrengst te berekenen
+  om de juiste hoeveelheid te bepalen. 
+x De PrimingSugarSource kan vervallen zodra alle bottelsuikers in de database verwerkt
+  zijn.
+x Hiervoor een script maken om deze suikers als fermentable in het recept te zetten
+  met  'added = 4'. 
+x Toevoegen added = 5, voor kegs.
+x In products vervallen de velden bottle_priming_sugar en keg_priming_sugar.
+x Deze waardes komen uit fermentables.
+x Let op, de amount waardes zijn g/l dus omrekenen.
+x Ook aanpassen de recept suikerstort, de added 4 of 5 niet meenemen.
+
+
--- a/bmsd/mysql.c	Wed Jun 05 20:06:14 2019 +0200
+++ b/bmsd/mysql.c	Fri Jun 14 20:26:51 2019 +0200
@@ -325,6 +325,38 @@
 
 
 
+int bms_mysql_query(const char *query)
+{
+    int		rc = mysql_query(con, query);
+
+    if (rc) {
+        syslog(LOG_NOTICE, "MySQL: error %u (%s)", mysql_errno(con), mysql_error(con));
+        syslog(LOG_NOTICE, query);
+    } else {
+	return 0;
+    }
+
+    /* Any error execpt server gone away */
+    if (rc != 2006)
+	return rc;
+
+    /* Try to reconnect and do the query again */
+    mysql_close(con);
+    if (mysql_real_connect(con, Config.mysql_host, Config.mysql_user, Config.mysql_pass, Config.mysql_database, Config.mysql_port, NULL, 0) == NULL) {
+        syslog(LOG_NOTICE, "MySQL: mysql_real_connect() %s", mysql_error(con));
+        return 2;
+    }
+    syslog(LOG_NOTICE, "MySQL: reconnected.");
+    rc = mysql_query(con, query);
+    if (rc) {
+        syslog(LOG_NOTICE, "MySQL: error %u (%s)", mysql_errno(con), mysql_error(con));
+        syslog(LOG_NOTICE, query);
+    }
+    return rc;
+}
+
+
+
 void bms_mysql_ping(void)
 {
 }
@@ -353,10 +385,7 @@
 	node->temperature, node->humidity, node->barometer, node->gps_latitude, node->gps_longitude, node->gps_altitude,
 	node->net_address, node->net_ifname, node->net_rssi);
 
-    if (mysql_query(con, query)) {
-	syslog(LOG_NOTICE, "MySQL: INSERT INTO mon_nodes error %u (%s))", mysql_errno(con), mysql_error(con));
-	syslog(LOG_NOTICE, query);
-    } else {
+    if (bms_mysql_query(query) == 0) {
 	syslog(LOG_NOTICE,  "MySQL: insert new node %s", node->node);
     }
 
@@ -382,11 +411,7 @@
 	node->temperature, node->humidity, node->barometer, node->gps_latitude, node->gps_longitude, node->gps_altitude, 
 	node->net_address, node->net_ifname, node->net_rssi, node->uuid);
 
-    if (mysql_query(con, query)) {
-	syslog(LOG_NOTICE, "MySQL: UPDATE mon_nodes error %u (%s))", mysql_errno(con), mysql_error(con));
-	syslog(LOG_NOTICE, query);
-    }
-
+    bms_mysql_query(query);
     free(query);
 }
 
@@ -397,12 +422,7 @@
     char        *query = malloc(512);
 
     snprintf(query, 511, "UPDATE mon_nodes SET online='N' WHERE node='%s'", node);
-
-    if (mysql_query(con, query)) {
-	syslog(LOG_NOTICE, "MySQL: UPDATE mon_nodes error %u (%s))", mysql_errno(con), mysql_error(con));
-	syslog(LOG_NOTICE, query);
-    }
-
+    bms_mysql_query(query);
     free(query);
 }
 
@@ -447,13 +467,9 @@
 	fermenter->profile_steps ? fermenter->profile_steps : "", fermenter->stage, fermenter->yeast_lo, fermenter->yeast_hi,
 	fermenter->webcam_url ? fermenter->webcam_url : "", fermenter->webcam_light);
 
-    if (mysql_query(con, query)) {
-	syslog(LOG_NOTICE, "MySQL: INSERT INTO mon_fermenters error %u (%s))", mysql_errno(con), mysql_error(con));
-	syslog(LOG_NOTICE, query);
-    } else {
+    if (bms_mysql_query(query) == 0) {
 	syslog(LOG_NOTICE,  "MySQL: insert new fermenter %s/%s", fermenter->node, fermenter->alias);
     }
-
     free(query);
 }
 
@@ -495,11 +511,7 @@
 	fermenter->profile_steps ? fermenter->profile_steps : "", fermenter->stage, fermenter->yeast_lo, fermenter->yeast_hi,
 	fermenter->webcam_url ? fermenter->webcam_url : "", fermenter->webcam_light, fermenter->uuid);
 
-    if (mysql_query(con, query)) {
-	syslog(LOG_NOTICE, "MySQL: UPDATE mon_fermenters error %u (%s))", mysql_errno(con), mysql_error(con));
-	syslog(LOG_NOTICE, query);
-    }
-
+    bms_mysql_query(query);
     free(query);
 }
 
@@ -514,11 +526,7 @@
     else
 	snprintf(query, 511, "UPDATE mon_fermenters SET online='N' WHERE node='%s'", node);
 
-    if (mysql_query(con, query)) {
-	syslog(LOG_NOTICE, "MySQL: UPDATE mon_fermenters error %u (%s))", mysql_errno(con), mysql_error(con));
-	syslog(LOG_NOTICE, query);
-    }
-
+    bms_mysql_query(query);
     free(query);
 }
 
--- a/bmsd/mysql.h	Wed Jun 05 20:06:14 2019 +0200
+++ b/bmsd/mysql.h	Fri Jun 14 20:26:51 2019 +0200
@@ -18,6 +18,13 @@
 void bms_mysql_end(void);
 
 /**
+ * @brief Send query to the MySQL server with one reconnect attempt.
+ * @param query The SQL query to send.
+ * @return Return 0 if no error, else the error code.
+ */
+int bms_mysql_query(const char *query);
+
+/**
  * @brief Ping MySQL connection and try to reconnect if the connection is broken.
  */
 void bms_mysql_ping(void);
--- a/www/includes/db_product.php	Wed Jun 05 20:06:14 2019 +0200
+++ b/www/includes/db_product.php	Fri Jun 14 20:26:51 2019 +0200
@@ -29,11 +29,9 @@
 	// Basic settings
 	if (isset($_POST['uuid'])) {
 		$sql .= "uuid='" . $_POST['uuid'];
-		syslog(LOG_NOTICE, 'Keep uuid ');
 	} else {
 		$uuid = str_replace("\n", "", file_get_contents('/proc/sys/kernel/random/uuid'));
 		$sql .= "uuid='" . $uuid;
-		syslog(LOG_NOTICE, 'New uuid ');
 	}
 	$sql .= "', name='" . mysqli_real_escape_string($connect, $_POST['name']);
 	$sql .= "', code='" . mysqli_real_escape_string($connect, $_POST['code']);
@@ -131,12 +129,12 @@
 		$sql .= "', package_date='" . $_POST['package_date'] ."'";
 	$sql .=  ", bottle_amount='" . $_POST['bottle_amount'];
 	$sql .= "', bottle_carbonation='" . $_POST['bottle_carbonation'];
-	$sql .= "', bottle_priming_sugar='" . $_POST['bottle_priming_sugar'];
+	//$sql .= "', bottle_priming_sugar='" . $_POST['bottle_priming_sugar'];
 	$sql .= "', bottle_priming_amount='" . $_POST['bottle_priming_amount'];
 	$sql .= "', bottle_carbonation_temp='" . $_POST['bottle_carbonation_temp'];
 	$sql .= "', keg_amount='" . $_POST['keg_amount'];
 	$sql .= "', keg_carbonation='" . $_POST['keg_carbonation'];
-	$sql .= "', keg_priming_sugar='" . $_POST['keg_priming_sugar'];
+	//$sql .= "', keg_priming_sugar='" . $_POST['keg_priming_sugar'];
 	$sql .= "', keg_priming_amount='" . $_POST['keg_priming_amount'];
 	$sql .= "', keg_carbonation_temp='" . $_POST['keg_carbonation_temp'];
 	$sql .= "', keg_forced_carb='" . $_POST['keg_forced_carb'];
@@ -715,12 +713,12 @@
 		$brew .= ',"package_date":"' . $row['package_date'];
 		$brew .= '","bottle_amount":' . floatval($row['bottle_amount']);
 		$brew .= ',"bottle_carbonation":' . floatval($row['bottle_carbonation']);
-		$brew .= ',"bottle_priming_sugar":' . $row['bottle_priming_sugar'];
+		//$brew .= ',"bottle_priming_sugar":' . $row['bottle_priming_sugar'];
 		$brew .= ',"bottle_priming_amount":' . floatval($row['bottle_priming_amount']);
 		$brew .= ',"bottle_carbonation_temp":' . floatval($row['bottle_carbonation_temp']);
 		$brew .= ',"keg_amount":' . floatval($row['keg_amount']);
 		$brew .= ',"keg_carbonation":' . floatval($row['keg_carbonation']);
-		$brew .= ',"keg_priming_sugar":' . $row['keg_priming_sugar'];
+		//$brew .= ',"keg_priming_sugar":' . $row['keg_priming_sugar'];
 		$brew .= ',"keg_priming_amount":' . floatval($row['keg_priming_amount']);
 		$brew .= ',"keg_carbonation_temp":' . floatval($row['keg_carbonation_temp']);
 		$brew .= ',"keg_forced_carb":' . floatval($row['keg_forced_carb']);
@@ -1056,7 +1054,7 @@
  *  Stage 4+, after primary, reduce sugars(2-fermention), yeasts(0-Primary), miscs(3-primary)
  *  Stage 5+, after secondary, reduce yeasts(1-Secondary)
  *  Stage 6+, after tertiary, reduce sugars(3-lagering), hops(5-dry-hop), yeasts(2-Tertiary), miscs(4-secondary)
- *  Stage 7+, after packaging, reduce sugars(4-bottle), yeasts(3-Bottle), miscs(5-bottling)
+ *  Stage 7+, after packaging, reduce sugars(4-bottle, 5-kegs), yeasts(3-Bottle), miscs(5-bottling)
  */
 function inventory_reduce() {
 
@@ -1065,6 +1063,9 @@
     $savethis = 0;
     $stage = $_POST['stage'];
     $inventory_reduced = $_POST['inventory_reduced'];
+    if ($stage == $inventory_reduced) {
+	return;
+    }
     syslog(LOG_NOTICE, "inventory_reduce() stage: ".$stage." inventory_reduced: ".$inventory_reduced);
 
     /*
@@ -1253,12 +1254,19 @@
 
     /*
      * After packaging
-     *  reduce sugars(4-bottle), yeasts(3-Bottle), miscs(5-bottling)
+     *  reduce sugars(4/5-bottle), yeasts(3-Bottle), miscs(5-bottling)
      */
     if (($stage >= 6) && ($inventory_reduced < 7)) {
         syslog(LOG_NOTICE, "Reduce Packaging inventory from " . $_POST['code'] . " " . $_POST['name']);
 
-	// Bottle sugar, how?
+	if (isset($_POST['fermentables'])) {
+            $array = $_POST['fermentables'];
+            foreach($array as $key => $item) {
+                if ($item['f_added'] >= 4) {    // Bottling or Kegging
+                    reduce_fermentables($item);
+                }
+            }
+        }
 
 	if (isset($_POST['yeasts'])) {
             $array = $_POST['yeasts'];
--- a/www/js/global.js	Wed Jun 05 20:06:14 2019 +0200
+++ b/www/js/global.js	Fri Jun 14 20:26:51 2019 +0200
@@ -92,7 +92,8 @@
 	{ id: 1, en: 'Boil', nl: 'Koken' },
 	{ id: 2, en: 'Fermentation', nl: 'Vergisten' },
 	{ id: 3, en: 'Lagering', nl: 'Nagisten/lageren' },
-	{ id: 4, en: 'Bottle', nl: 'Bottelen' }
+	{ id: 4, en: 'Bottle', nl: 'Bottelen' },
+	{ id: 5, en: 'Kegs', nl: 'Fust' }
 ];
 var AddedSource = {
 	localdata: AddedData,
@@ -333,20 +334,6 @@
 };
 var AerationTypeAdapter = new $.jqx.dataAdapter(AerationTypeSource);
 
-var PrimingSugarData = [
-	{ id: 0, en: 'Saccharose',          nl: 'Kristalsuiker',    factor: 1 },
-	{ id: 1, en: 'Glucose or dextrose', nl: 'Glucose/dextrose', factor: 1.16 },
-	{ id: 2, en: 'Honey',               nl: 'Honing',           factor: 1.28 },
-	{ id: 3, en: 'DME',                 nl: 'Moutextract',      factor: 1.74 },
-	{ id: 4, en: 'Molassis',            nl: 'Melasse',          factor: 3.83 }
-];
-var PrimingSugarSource = {
-	localdata: PrimingSugarData,
-	datatype: "array",
-	datafields: [{ name: 'id' }, { name: 'en' }, { name: 'nl' }, { name: 'factor' }] 
-};
-var PrimingSugarAdapter = new $.jqx.dataAdapter(PrimingSugarSource);
-
 var AcidTypeData = [
 	{ id: 0, en: 'Lactic',       nl: 'Melkzuur' },
 	{ id: 1, en: 'Hydrochloric', nl: 'Zoutzuur' },
@@ -523,7 +510,21 @@
 		return data;
 	},
         loadError: function(jqXHR, status, error) {
-		$('#err').text(status + ' ' + error);
+		console.log(status + ' ' + error);
+	},
+});
+var fermentablesugars = new $.jqx.dataAdapter(fermentableInvSource, {
+	beforeLoadComplete: function (records) {
+		var data = new Array();
+		for (var i = 0; i < records.length; i++) {
+			var row = records[i];
+			if (row.type == 1 || row.type == 3)	// Sugars or dry extract
+				data.push(row);
+		}
+		return data;
+	},
+	loadError: function(jqXHR, status, error) {
+		console.log(status + ' ' + error);
 	},
 });
 
@@ -562,7 +563,7 @@
 		return data;
 	},
         loadError: function(jqXHR, status, error) {
-		$('#err').text(status + ' ' + error);
+		console.log(status + ' ' + error);
 	},
 });
 
@@ -593,7 +594,7 @@
 		return data;
 	},
         loadError: function(jqXHR, status, error) {
-		$('#err').text(status + ' ' + error);
+		console.log(status + ' ' + error);
 	},
 });
 
@@ -630,7 +631,7 @@
 		return data;
 	},
 	loadError: function(jqXHR, status, error) {
-		$('#err').text(status + ' ' + error);
+		console.log(status + ' ' + error);
 	},
 });
 
@@ -665,7 +666,7 @@
 		return data;
 	},
         loadError: function(jqXHR, status, error) {
-		$('#err').text(status + ' ' + error);
+		console.log(status + ' ' + error);
 	},
 });
 
--- a/www/js/prod_edit.js	Wed Jun 05 20:06:14 2019 +0200
+++ b/www/js/prod_edit.js	Fri Jun 14 20:26:51 2019 +0200
@@ -87,6 +87,7 @@
 
 	var     fermentableRow = 0;
 	var     fermentableData = {};
+	var	fermentableInit = 1;
 	var     hopRow = 0;
 	var     hopData = {};
 	var     miscRow = 0;
@@ -122,6 +123,32 @@
                         $("#ok_supplies").html("<img src='images/dialog-error.png'>");
 	}
 
+	function calcPercentages() {
+
+		console.log("calcPercentages()");
+		var rowscount = $("#fermentableGrid").jqxGrid('getdatainformation').rowscount;
+		if (rowscount > 1) {
+			var tw = 0;
+			for (i = 0; i < rowscount; i++) {
+				var rowdata = $("#fermentableGrid").jqxGrid('getrowdata', i);
+				if (rowdata.f_added < 4)
+					tw += Math.round(rowdata.f_amount * 1000) / 1000;
+			};
+			tw = Math.round(tw * 1000) / 1000;
+
+			for (i = 0; i < rowscount; i++) {
+				var rowdata = $("#fermentableGrid").jqxGrid('getrowdata', i);
+				if (rowdata.f_added < 4) {
+					var percentage = Math.round(rowdata.f_amount / tw * 1000) / 10.0;
+					$("#fermentableGrid").jqxGrid('setcellvalue', i, "f_percentage", percentage);
+				} else {
+					$("#fermentableGrid").jqxGrid('setcellvalue', i, "f_percentage", 0);
+				}
+			};
+		} else {
+			$("#fermentableGrid").jqxGrid('setcellvalue', 0, "f_percentage", 100);
+		}
+	}
 
 	/*
 	 * All calculations that depend on changes in the fermentables,
@@ -172,9 +199,9 @@
                         var row = rows[i];
                         if (row.f_adjust_to_total_100)
                                 my_100 = true;
-			if (row.f_type == 1)	// Sugar
+			if (row.f_type == 1 && row.f_added < 4)	// Sugar
 				psugar += row.f_percentage;
-			if (row.f_graintype == 2)	// Crystal
+			if (row.f_graintype == 2 && row.f_added < 4)	// Crystal
 				pcara += row.f_percentage;
 			var d = row.f_amount * (row.f_yield / 100) * (1 - row.f_moisture / 100);
 			if (row.f_added == 0) {	// Mash
@@ -188,31 +215,41 @@
 			}
 			if (row.f_added == 0 || row.f_added == 1)	// Mash or Boil
 				sugarsf += d;
-			if (row.f_added == 2 || row.f_added == 3) {
+			if (row.f_added == 2 || row.f_added == 3) {	// Fermentation or lagering
 				var x = (row.f_yield / 100) * (1 - row.f_moisture / 100);
 				addedS += row.f_amount * x;
 				addedmass += row.f_amount;
 				vol += (x * sugardensity + (1 - x) * 1) * row.f_amount;
 			}
-			colort += row.f_amount * ebc_to_srm(row.f_color);
-			colorh += row.f_amount * row.f_color * get_kt(row.f_color);
-			colorn += (row.f_percentage / 100) * row.f_color;	// For 8.6 Pt wort.
+			if (row.f_added < 4) {
+				colort += row.f_amount * ebc_to_srm(row.f_color);
+				colorh += row.f_amount * row.f_color * get_kt(row.f_color);
+				colorn += (row.f_percentage / 100) * row.f_color;	// For 8.6 Pt wort.
+			}
+			if (fermentableInit) {
+				if (row.f_added == 4) {
+					$("#bottle_priming_total").val(row.f_amount * 1000);	// Prevent clearing
+					$("#bottle_priming_sugar").jqxDropDownList('selectItem', row.f_name);
+				}
+				if (row.f_added == 5) {
+					$("#keg_priming_total").val(row.f_amount * 1000);
+					$("#keg_priming_sugar").jqxDropDownList('selectItem', row.f_name);
+				}
+			}
 			// Check supplies.
 			if ((((dataRecord.inventory_reduced <= 2) && (row.f_added <= 1)) ||  // Mash or boil
                              ((dataRecord.inventory_reduced <= 3) && (row.f_added == 2)) ||  // Primary
                              ((dataRecord.inventory_reduced <= 5) && (row.f_added == 3)) ||  // Secondary or Tertiary
-		    	     ((dataRecord.inventory_reduced <= 6) && (row.f_added == 4))) && row.f_inventory < row.f_amount) {
+		    	     ((dataRecord.inventory_reduced <= 6) && (row.f_added == 4)) ||  // Bottle
+			     ((dataRecord.inventory_reduced <= 6) && (row.f_added == 5))) && row.f_inventory < row.f_amount) {
 				ok_fermentables = 0;
 			}
 			if (row.f_added == 0 && (row.f_type == 0 || row.f_type == 4) && row.f_color < 50) { // Mash and Grain/Adjunct and Color < 50
 				lintner += row.f_diastatic_power * row.f_amount;
-	//			console.log("add "+row.f_name+" diastatic_power:"+row.f_diastatic_power*row.f_amount+" now:"+lintner);
-	//		} else {
-	//			console.log("ign "+row.f_name+" diastatic_power:"+row.f_diastatic_power*row.f_amount+" now:"+lintner);
 			}
 		}
+		fermentableInit = 0;
 		$("#ferm_lintner").val(Math.round(parseFloat(lintner / mashkg)));
-	//	console.log("lintner:"+lintner+" kg:"+mashkg);
 		$("#mash_kg").val(mashkg);
 		console.log("calcFermentables() supplies:"+ok_fermentables);
 		to_100 = my_100;
@@ -393,20 +430,24 @@
 
 		for (var i = 0; i < rowscount; i++) {
 			var row = $("#fermentableGrid").jqxGrid('getrowdata', i);
-			var d = row.f_percentage / 100 * (row.f_yield / 100) * (1 - row.f_moisture / 100);
-			if (row.f_added == 0)	// Mash
-				d = efficiency / 100 * d;
-			tot += d;
+			if (row.f_added < 4) {
+				var d = row.f_percentage / 100 * (row.f_yield / 100) * (1 - row.f_moisture / 100);
+				if (row.f_added == 0)	// Mash
+					d = efficiency / 100 * d;
+				tot += d;
+			}
 		}
 		var totmass = 0;
 		if (tot)
-			totmass = sug / tot;
+			totmass = Math.round((sug / tot) * 1000) / 1000;
 
 		if (totmass) {
 			for (i = 0; i < rowscount; i++) {
 				var row = $("#fermentableGrid").jqxGrid('getrowdata', i);
-				var amount = row.f_percentage / 100 * totmass;
-				$("#fermentableGrid").jqxGrid('setcellvalue', i, "f_amount", amount);
+				if (row.f_added < 4) {
+					var amount = Math.round(row.f_percentage * 10 * totmass) / 1000;
+					$("#fermentableGrid").jqxGrid('setcellvalue', i, "f_amount", amount);
+				}
 			}
 		}
 	};
@@ -1747,13 +1788,11 @@
 	}
 
 	function CarbCO2toS(CO2, T, SFactor) {
-		// Calcuation of disolved CO2 in the beer.
-		// Brewersfriend uses: 3.0378 - (0.050062 * temp) + (0.00026555 * temp^2)
-		// Brouwhulp uses:     0.000849151 * T * T - 0.0587512 * T + 1.71137)
+		// Calculation of disolved CO2 in the beer, brouwhulp.
 		var sugar = SFactor * (CO2 - (0.000849151 * T * T - 0.0587512 * T + 1.71137)) / 0.286;
 		if (sugar < 0)
 			sugar = 0;
-		return sugar;
+		return Math.round(sugar * 1000) / 1000;
 	}
 
 	function CarbCO2ToPressure(CO2, T) {
@@ -1771,40 +1810,56 @@
 		if (TSec < 1)
 			TSec = 18;	// Fallback to room temperature.
 
-		if (dataRecord.fg == 1.000)
+		if (dataRecord.fg == 0.000)
 			var ABV = abvol(dataRecord.brew_fermenter_sg, parseFloat($("#est_fg").jqxNumberInput('decimal')));
 		else
 			var ABV = abvol(dataRecord.brew_fermenter_sg, dataRecord.fg);
+		ABV = Math.round(ABV * 100) / 100;
+
+		console.log("calcCarbonation() TSec:"+TSec+"  ABV:"+ABV);
+		if (!(rows = $('#fermentableGrid').jqxGrid('getrows'))) {
+			return;	// grid not yet loaded.
+		}
 
 		// Bottles
-		var SFactor = PrimingSugarData[dataRecord.bottle_priming_sugar].factor;
-		var Amount = CarbCO2toS(dataRecord.bottle_carbonation, TSec, SFactor);
-		dataRecord.bottle_priming_amount = Amount;
+		dataRecord.bottle_priming_amount = 0;
+		dataRecord.bottle_priming_total = 0;
+		for (var i = 0; i < rows.length; i++) {
+			var row = rows[i];
+			if (row.f_added == 4) {
+				var SFactor = 1 / ((row.f_yield / 100) * (1 - row.f_moisture / 100));
+				dataRecord.bottle_priming_amount = CarbCO2toS(dataRecord.bottle_carbonation, TSec, SFactor);
+				dataRecord.bottle_priming_total = Math.round(dataRecord.bottle_amount * dataRecord.bottle_priming_amount * 100) / 100;
+				$("#fermentableGrid").jqxGrid('setcellvalue', i, 'f_amount', dataRecord.bottle_priming_total / 1000);
+			}
+		}
 		$("#bottle_priming_amount").val(Math.round(dataRecord.bottle_priming_amount * 10) / 10);
-		$("#bottle_priming_total").val(Math.round(dataRecord.bottle_amount * dataRecord.bottle_priming_amount * 10) / 10);
-		$("#bottle_abv").val(Math.round((ABV + Amount * 0.47 / 7.907) * 10) / 10);
+                $("#bottle_priming_total").val(dataRecord.bottle_priming_total);
+                $("#bottle_abv").val(Math.round((ABV + dataRecord.bottle_priming_amount * 0.47 / 7.907) * 10) / 10);
 
 		// Kegs
-		SFactor = PrimingSugarData[dataRecord.keg_priming_sugar].factor;
-		Amount = CarbCO2toS(dataRecord.keg_carbonation, TSec, SFactor);
 		var Pressure = CarbCO2ToPressure(dataRecord.keg_carbonation, dataRecord.keg_carbonation_temp);
 		if (Pressure < 0)
 			Pressure = 0;
 		dataRecord.keg_pressure = Pressure;
 		$("#keg_pressure").val(Math.round(Pressure * 10) / 10);
 
-		if (dataRecord.keg_forced_carb) {
-			Amount = 0;
-			dataRecord.keg_priming_amount = 0;
-			$("#keg_priming_amount").val(0);
-			$("#keg_priming_total").val(0);
-		} else {
-			dataRecord.keg_priming_amount = Amount;
-			$("#keg_priming_amount").val(Math.round(dataRecord.keg_priming_amount * 10) / 10);
-			$("#keg_priming_total").val(Math.round(dataRecord.keg_amount * dataRecord.keg_priming_amount * 10) / 10);
+		dataRecord.keg_priming_amount = 0;
+		dataRecord.keg_priming_total = 0;
+		if (! dataRecord.keg_forced_carb) {
+			for (var i = 0; i < rows.length; i++) {
+				var row = rows[i];
+				if (row.f_added == 5) {
+					var SFactor = 1 / ((row.f_yield / 100) * (1 - row.f_moisture / 100));
+                			dataRecord.keg_priming_amount = CarbCO2toS(dataRecord.keg_carbonation, TSec, SFactor);
+					dataRecord.keg_priming_total = Math.round(dataRecord.keg_amount * dataRecord.keg_priming_amount * 100) / 100;
+					$("#fermentableGrid").jqxGrid('setcellvalue', i, 'f_amount', dataRecord.keg_priming_total / 1000);
+				}
+			}
 		}
-
-		$("#keg_abv").val(Math.round((ABV + Amount * 0.47 / 7.907) * 10) / 10);
+		$("#keg_priming_amount").val(Math.round(dataRecord.keg_priming_amount * 10) / 10);
+		$("#keg_priming_total").val(dataRecord.keg_priming_total);
+		$("#keg_abv").val(Math.round((ABV + dataRecord.keg_priming_amount * 0.47 / 7.907) * 10) / 10);
 	}
 
 	function calcStage() {
@@ -1945,10 +2000,11 @@
 			$("#brew_fermenter_extrawater").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
 			$("#brew_aeration_speed").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
 		}
-		if (dataRecord.stage < 5) { // At least secondary
-			$('#jqxTabs').jqxTabs('disableAt', 10);	// Packaging tab
-		} else {
-			$('#jqxTabs').jqxTabs('enableAt', 10);
+		if (dataRecord.stage == 5) // Lagering, allow packaging
+			$("#package_date").jqxDateTimeInput({ disabled: false });
+		else
+			$("#package_date").jqxDateTimeInput({ disabled: true });
+		if (dataRecord.stage >= 5) { // At least secondary
 			$("#primary_start_temp").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
 			$("#primary_max_temp").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
 			$("#primary_end_temp").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
@@ -2307,18 +2363,14 @@
 			dataRecord.bottle_carbonation = parseFloat(event.args.value);
 			calcCarbonation();
 		});
+		$('#bottle_carbonation_temp').on('change', function (event) {
+                        dataRecord.bottle_carbonation_temp = parseFloat(event.args.value);
+                        calcCarbonation();
+                });
 		$('#keg_carbonation').on('change', function (event) {
 			dataRecord.keg_carbonation = parseFloat(event.args.value);
 			calcCarbonation();
 		});
-		$('#bottle_priming_sugar').on('change', function (event) {
-			dataRecord.bottle_priming_sugar = event.args.item.value;
-			calcCarbonation();
-		});
-		$('#keg_priming_sugar').on('change', function (event) {
-			dataRecord.keg_priming_sugar = event.args.item.value;
-			calcCarbonation();
-		});
 		$("#keg_forced_carb").on('checked', function (event) {
 			dataRecord.keg_forced_carb = 1;
 			calcCarbonation();
@@ -2591,12 +2643,12 @@
 			package_date: $("#package_date").val(),
 			bottle_amount: parseFloat($("#bottle_amount").jqxNumberInput('decimal')),
 			bottle_carbonation: parseFloat($("#bottle_carbonation").jqxNumberInput('decimal')),
-			bottle_priming_sugar: $("#bottle_priming_sugar").val(),
+			//bottle_priming_sugar: $("#bottle_priming_sugar").val(),
 			bottle_priming_amount: parseFloat($("#bottle_priming_amount").jqxNumberInput('decimal')),
 			bottle_carbonation_temp: parseFloat($("#bottle_carbonation_temp").jqxNumberInput('decimal')),
 			keg_amount: parseFloat($("#keg_amount").jqxNumberInput('decimal')),
 			keg_carbonation: parseFloat($("#keg_carbonation").jqxNumberInput('decimal')),
-			keg_priming_sugar: $("#keg_priming_sugar").val(),
+			//keg_priming_sugar: $("#keg_priming_sugar").val(),
 			keg_priming_amount: parseFloat($("#keg_priming_amount").jqxNumberInput('decimal')),
 			keg_carbonation_temp: parseFloat($("#keg_carbonation_temp").jqxNumberInput('decimal')),
 			keg_forced_carb: dataRecord.keg_forced_carb,
@@ -2814,12 +2866,12 @@
 			{ name: 'package_date', type: 'string' },
 			{ name: 'bottle_amount', type: 'float' },
 			{ name: 'bottle_carbonation', type: 'float' },
-			{ name: 'bottle_priming_sugar', type: 'int' },
+			//{ name: 'bottle_priming_sugar', type: 'int' },
 			{ name: 'bottle_priming_amount', type: 'float' },
 			{ name: 'bottle_carbonation_temp', type: 'float' },
 			{ name: 'keg_amount', type: 'float' },
 			{ name: 'keg_carbonation', type: 'float' },
-			{ name: 'keg_priming_sugar', type: 'int' },
+			//{ name: 'keg_priming_sugar', type: 'int' },
 			{ name: 'keg_priming_amount', type: 'float' },
 			{ name: 'keg_carbonation_temp', type: 'float' },
 			{ name: 'keg_forced_carb', type: 'int' },
@@ -3018,12 +3070,12 @@
 			$("#package_date").val(dataRecord.package_date);
 			$("#bottle_amount").val(dataRecord.bottle_amount);
 			$("#bottle_carbonation").val(dataRecord.bottle_carbonation);
-			$("#bottle_priming_sugar").val(dataRecord.bottle_priming_sugar);
+			//$("#bottle_priming_sugar").val(dataRecord.bottle_priming_sugar);
 			$("#bottle_priming_amount").val(dataRecord.bottle_priming_amount);
 			$("#bottle_carbonation_temp").val(dataRecord.bottle_carbonation_temp);
 			$("#keg_amount").val(dataRecord.keg_amount);
 			$("#keg_carbonation").val(dataRecord.keg_carbonation);
-			$("#keg_priming_sugar").val(dataRecord.keg_priming_sugar);
+			//$("#keg_priming_sugar").val(dataRecord.keg_priming_sugar);
 			$("#keg_priming_amount").val(dataRecord.keg_priming_amount);
 			$("#keg_carbonation_temp").val(dataRecord.keg_carbonation_temp);
 			$("#keg_forced_carb").val(dataRecord.keg_forced_carb);
@@ -3190,15 +3242,15 @@
 				{ name: 'f_avail', type: 'int' }
                         ],
                         addrow: function (rowid, rowdata, position, commit) {
-				console.log("fermentable addrow "+rowid);
+				//console.log("fermentable addrow "+rowid);
                                 commit(true);
                         },
                         deleterow: function (rowid, commit) {
-				console.log("fermentable deleterow "+rowid);
+				//console.log("fermentable deleterow "+rowid);
                                 commit(true);
                         },
 			updaterow: function (rowid, rowdata, commit) {
-				console.log("fermentable updaterow "+rowid);
+				//console.log("fermentable updaterow "+rowid);
 				commit(true);
 			}
                 };
@@ -3308,16 +3360,7 @@
                                                                 }
                                                         }
                                                 } else {
-                                                        var tw = 0;
-                                                        for (i = 0; i < rowscount; i++) {
-                                                                var rowdata = $("#fermentableGrid").jqxGrid('getrowdata', i);
-                                                                tw += rowdata.f_amount;
-                                                        };
-                                                        for (i = 0; i < rowscount; i++) {
-                                                                var rowdata = $("#fermentableGrid").jqxGrid('getrowdata', i);
-                                                                var percentage = Math.round(rowdata.f_amount / tw * 1000) / 10.0;
-                                                                $("#fermentableGrid").jqxGrid('setcellvalue', i, "f_percentage", percentage);
-                                                        };
+							calcPercentages();
                                                 }
                                         } else {
                                                 $("#fermentableGrid").jqxGrid('setcellvalue', 0, "f_percentage", 100);
@@ -3356,7 +3399,8 @@
 					if (((dataRecord.inventory_reduced <= 2) && (rowdata.f_added <= 1)) ||	// Mash or boil
 					    ((dataRecord.inventory_reduced <= 3) && (rowdata.f_added == 2)) ||	// Primary
 					    ((dataRecord.inventory_reduced <= 5) && (rowdata.f_added == 3)) ||	// Secondary or Tertiary
-					    ((dataRecord.inventory_reduced <= 6) && (rowdata.f_added == 4))) {	// Bottle
+					    ((dataRecord.inventory_reduced <= 6) && (rowdata.f_added == 4)) ||	// Bottle
+					    ((dataRecord.inventory_reduced <= 6) && (rowdata.f_added == 5))) {	// Kegs
 						if (value < rowdata.f_amount)
 							color = '#ff4040';
 						return  '<span style="margin: 4px; margin-top: 6px; float: right; color: ' +
@@ -3368,6 +3412,8 @@
 				},
                                 { text: 'Procent', datafield: 'f_percentage', width: 90, align: 'right',
 				  cellsrenderer:  function (row, columnfield, value, defaulthtml, columnproperties, rowdata) {
+					if (rowdata.f_added >= 4)
+						return '<span></span>';
 					var color = '#ffffff';
 					if (value > rowdata.f_max_in_batch)
 						color = '#ff4040';
@@ -3375,15 +3421,23 @@
 						color + ';">' +fermentableAdapter.formatNumber(value, "p1") + '</span>';
 				  }
 				},
-                                { text: '100%', align: 'center', datafield: 'f_adjust_to_total_100', columntype: 'checkbox', width: 70 },
+                                { text: '100%', datafield: 'f_adjust_to_total_100', width: 70, align: 'center', cellsalign: 'center',
+				  cellsrenderer:  function (index, datafield, value, defaultvalue, column, rowdata) {
+					if (value == 0)
+						return '<span></span>';
+					return  '<span><img style="float:left; margin-left:25px; margin-top:4px;" src="images/dialog-ok-apply.png"></span>';
+				  }
+				},
 				{ text: '', datafield: 'Edit', columntype: 'button', width: 100, align: 'center', cellsrenderer: function () {
 					return "Wijzig";
 					}, buttonclick: function (row) {
-						if (dataRecord.stage > 3) {
+						fermentableRow = row;
+						fermentableData = $("#fermentableGrid").jqxGrid('getrowdata', fermentableRow);
+						if (fermentableData.f_added >= 4) {
+							alert("Wijzig dit in de Verpakken tab");
+						} else if (dataRecord.stage > 3) {
 							alert("Ingredieƫnt is al verwerkt.");
 						} else {
-							fermentableRow = row;
-							fermentableData = $("#fermentableGrid").jqxGrid('getrowdata', fermentableRow);
 							$("#wf_name").val(fermentableData.f_name);
 							$("#wf_amount").val(fermentableData.f_amount);
 							$("#wf_percentage").val(fermentableData.f_percentage);
@@ -4460,7 +4514,7 @@
 			f_avail: fermentableData.f_avail
 		};
 		$("#fermentableGrid").jqxGrid('updaterow', rowID, row);
-		// Recalc percentages
+		calcPercentages();
 		calcFermentables();
 		calcIBUs();
 		calcMash();
@@ -4518,25 +4572,7 @@
 		$("#fermentableGrid").jqxGrid('setcellvalue', fermentableRow, 'f_amount', event.args.value);
 		fermentableData.f_amount = event.args.value;
 		if (! to_100) {
-			// Recalculate percentages
-			console.log("adjust percentages");
-			var rowscount = $("#fermentableGrid").jqxGrid('getdatainformation').rowscount;
-			if (rowscount > 1) {
-				var tw = 0;
-				for (i = 0; i < rowscount; i++) {
-					var rowdata = $("#fermentableGrid").jqxGrid('getrowdata', i);
-					tw += rowdata.f_amount;
-				};
-				for (i = 0; i < rowscount; i++) {
-					var rowdata = $("#fermentableGrid").jqxGrid('getrowdata', i);
-					var percentage = Math.round(rowdata.f_amount / tw * 1000) / 10.0;
-					$("#fermentableGrid").jqxGrid('setcellvalue', i, "f_percentage", percentage);
-		//                      if (i == fermentableRow) // Will crash the script.
-		//                              $("#wf_percentage").val(percentage);
-				};
-			} else {
-				$("#fermentableGrid").jqxGrid('setcellvalue', 0, "f_percentage", 100);
-			}
+			calcPercentages();
 			calcFermentables();
 			calcIBUs();
 			calcMash();
@@ -4558,13 +4594,15 @@
 				var tw = 0;     // total weight
 				for (i = 0; i < rowscount; i++) {
 					var rowdata = $("#fermentableGrid").jqxGrid('getrowdata', i);
-					tw += rowdata.f_amount;
+					if (rowdata.f_added < 4)
+						tw += Math.round(rowdata.f_amount * 1000) / 1000;
 				}
+				tw = Math.round(tw * 1000) / 1000;
 				if (to_100) {
 					// Adjust this row and the 100% row.
-					var damount = tw * diff / 100;
+					var damount = Math.round(tw * diff *10) / 1000;
 					var rowdata = $("#fermentableGrid").jqxGrid('getrowdata', fermentableRow);
-					var namount = rowdata.f_amount + damount;
+					var namount = Math.round((rowdata.f_amount + damount) * 1000) / 1000;
 					$("#fermentableGrid").jqxGrid('setcellvalue', fermentableRow, 'f_amount', namount);
 					$("#wf_amount").val(namount);
 					$("#fermentableGrid").jqxGrid('setcellvalue', fermentableRow, 'f_percentage', rowdata.f_percentage + diff);
@@ -4584,16 +4622,20 @@
 					var nw = tw * diff / 100;
 					for (i = 0; i < rowscount; i++) {
 						var rowdata = $("#fermentableGrid").jqxGrid('getrowdata', i);
-						if (i == fermentableRow) {
-							var namount = rowdata.f_amount + nw;
-							$("#fermentableGrid").jqxGrid('setcellvalue', i, 'f_amount', namount);
-		//                                      $("#wf_amount").val(namount); // Will crash the script.
-							$("#fermentableGrid").jqxGrid('setcellvalue', i, 'f_percentage', newvalue);
+						if (rowdata.f_added < 4) {
+							if (i == fermentableRow) {
+								var namount = Math.round((rowdata.f_amount + nw) * 1000) / 1000;
+								$("#fermentableGrid").jqxGrid('setcellvalue', i, 'f_amount', namount);
+		//                                      	$("#wf_amount").val(namount); // Will crash the script.
+								$("#fermentableGrid").jqxGrid('setcellvalue', i, 'f_percentage', newvalue);
+							} else {
+								var namount = Math.round((rowdata.f_amount - (nw / (rowscount - 1))) * 1000) / 1000;
+								var newperc = Math.round((namount / tw) * 1000) / 10.0;
+								$("#fermentableGrid").jqxGrid('setcellvalue', i, 'f_amount', namount);
+								$("#fermentableGrid").jqxGrid('setcellvalue', i, 'f_percentage', newperc);
+							}
 						} else {
-							var namount = rowdata.f_amount - (nw / (rowscount - 1));
-							var newperc = Math.round((namount / tw) * 1000) / 10.0;
-							$("#fermentableGrid").jqxGrid('setcellvalue', i, 'f_amount', namount);
-							$("#fermentableGrid").jqxGrid('setcellvalue', i, 'f_percentage', newperc);
+							$("#fermentableGrid").jqxGrid('setcellvalue', i, 'f_percentage', 0);
 						}
 					}
 					calcFermentables();
@@ -5647,23 +5689,113 @@
 	$("#keg_carbonation").jqxNumberInput( Spin2dec );
 	$("#keg_carbonation").jqxNumberInput({ max: 5 });
 	$("#bottle_priming_sugar").jqxDropDownList({
+		placeHolder: "Kies suiker:",
 		theme: theme,
-		source: PrimingSugarAdapter,
-		valueMember: 'id',
-		displayMember: 'nl',
-		width: 180,
+		source: fermentablesugars,
+		displayMember: 'name',
+		width: 200,
 		height: 23,
-		autoDropDownHeight: true
+		dropDownWidth: 300,
+		dropDownHeight: 400
+	});
+	$("#bottle_priming_sugar").on('select', function (event) {
+		if (event.args) {
+			var index = event.args.index;
+			var editrow = -1;
+			var datarecord = fermentablesugars.records[index];
+			var rows = $('#fermentableGrid').jqxGrid('getrows');
+			for (var i = 0; i < rows.length; i++) {
+				if (rows[i].f_added == 4) {
+					editrow = i;
+				}
+			}
+			var row = {};
+			row["f_name"] = datarecord.name;
+                        row["f_origin"] = datarecord.origin;
+                        row["f_supplier"] = datarecord.supplier;
+                        row["f_amount"] = parseFloat($("#bottle_priming_total").jqxNumberInput('decimal')) / 1000;
+                        row["f_cost"] = datarecord.cost;
+                        row["f_type"] = datarecord.type;
+                        row["f_yield"] = datarecord.yield;
+                        row["f_color"] = datarecord.color;
+                        row["f_coarse_fine_diff"] = datarecord.coarse_fine_diff;
+                        row["f_moisture"] = datarecord.moisture;
+                        row["f_diastatic_power"] = datarecord.diastatic_power;
+                        row["f_protein"] = datarecord.protein;
+                        row["f_max_in_batch"] = datarecord.max_in_batch;
+                        row["f_graintype"] = datarecord.graintype;
+			row["f_added"] = 4;
+			row["f_dissolved_protein"] = datarecord.dissolved_protein;
+                        row["f_recommend_mash"] = datarecord.recommend_mash;
+                        row["f_add_after_boil"] = 1;
+                        row["f_adjust_to_total_100"] = 0;
+                        row["f_percentage"] = 0;
+                        row["f_di_ph"] = datarecord.di_ph;
+                        row["f_acid_to_ph_57"] = datarecord.acid_to_ph_57;
+                        row["f_inventory"] = datarecord.inventory;
+			if (editrow >= 0) {
+				var rowID = $('#fermentableGrid').jqxGrid('getrowid', editrow);
+				$('#fermentableGrid').jqxGrid('updaterow', rowID, row);
+			} else {
+                        	$("#fermentableGrid").jqxGrid('addrow', null, row);
+			}
+			calcCarbonation();
+		}
 	});
 	$("#keg_priming_sugar").jqxDropDownList({
+		placeHolder: "Kies suiker:",
 		theme: theme,
-		source: PrimingSugarAdapter,
-		valueMember: 'id',
-		displayMember: 'nl',
-		width: 180,
+		source: fermentablesugars,
+		displayMember: 'name',
+		width: 200,
 		height: 23,
-		autoDropDownHeight: true
+		dropDownWidth: 300,
+                dropDownHeight: 400
 	});
+	$("#keg_priming_sugar").on('select', function (event) {
+                if (event.args) {
+                        var index = event.args.index;
+                        var editrow = -1;
+                        var datarecord = fermentablesugars.records[index];
+                        var rows = $('#fermentableGrid').jqxGrid('getrows');
+                        for (var i = 0; i < rows.length; i++) {
+                                if (rows[i].f_added == 5) {
+                                        editrow = i;
+                                }
+                        }
+                        var row = {}; 
+                        row["f_name"] = datarecord.name;
+                        row["f_origin"] = datarecord.origin;
+                        row["f_supplier"] = datarecord.supplier;
+                        row["f_amount"] = parseFloat($("#keg_priming_total").jqxNumberInput('decimal')) / 1000;
+                        row["f_cost"] = datarecord.cost;
+                        row["f_type"] = datarecord.type;
+                        row["f_yield"] = datarecord.yield;
+                        row["f_color"] = datarecord.color;
+                        row["f_coarse_fine_diff"] = datarecord.coarse_fine_diff;
+                        row["f_moisture"] = datarecord.moisture;
+                        row["f_diastatic_power"] = datarecord.diastatic_power;
+                        row["f_protein"] = datarecord.protein;
+                        row["f_max_in_batch"] = datarecord.max_in_batch;
+                        row["f_graintype"] = datarecord.graintype;
+                        row["f_added"] = 5;
+                        row["f_dissolved_protein"] = datarecord.dissolved_protein;
+                        row["f_recommend_mash"] = datarecord.recommend_mash;
+                        row["f_add_after_boil"] = 1;
+                        row["f_adjust_to_total_100"] = 0;
+                        row["f_percentage"] = 0;
+                        row["f_di_ph"] = datarecord.di_ph;
+                        row["f_acid_to_ph_57"] = datarecord.acid_to_ph_57;
+                        row["f_inventory"] = datarecord.inventory;
+                        if (editrow >= 0) {
+                                var rowID = $('#fermentableGrid').jqxGrid('getrowid', editrow);
+                                $('#fermentableGrid').jqxGrid('updaterow', rowID, row);
+                        } else {
+                                $("#fermentableGrid").jqxGrid('addrow', null, row);
+                        }
+			calcCarbonation();
+                }
+        });
 	$("#bottle_priming_amount").jqxNumberInput( Show1dec );
 	$("#keg_priming_amount").jqxNumberInput( Show1dec );
 	$("#bottle_priming_total").jqxNumberInput( Show1dec );
--- a/www/js/rec_edit.js	Wed Jun 05 20:06:14 2019 +0200
+++ b/www/js/rec_edit.js	Fri Jun 14 20:26:51 2019 +0200
@@ -157,6 +157,33 @@
 		$("#sparge_acid_perc").jqxNumberInput({ spinButtons: rw, readOnly: ro, width: w100 });
 	};
 
+	function calcPercentages() {
+
+		console.log("calcPercentages()");
+		var rowscount = $("#fermentableGrid").jqxGrid('getdatainformation').rowscount;
+		if (rowscount > 1) {
+			var tw = 0;
+			for (i = 0; i < rowscount; i++) {
+				var rowdata = $("#fermentableGrid").jqxGrid('getrowdata', i);
+				if (rowdata.f_added < 4)
+					tw += Math.round(rowdata.f_amount * 1000) / 1000;
+			};
+			tw = Math.round(tw * 1000) / 1000;
+
+			for (i = 0; i < rowscount; i++) {
+				var rowdata = $("#fermentableGrid").jqxGrid('getrowdata', i);
+				if (rowdata.f_added < 4) {
+					var percentage = Math.round(rowdata.f_amount / tw * 1000) / 10.0;
+					$("#fermentableGrid").jqxGrid('setcellvalue', i, "f_percentage", percentage);
+				} else {
+					$("#fermentableGrid").jqxGrid('setcellvalue', i, "f_percentage", 0);
+				}
+			};
+		} else {
+			$("#fermentableGrid").jqxGrid('setcellvalue', 0, "f_percentage", 100);
+		}
+	}
+
 	function calcFermentables() {
 		console.log("calcFermentables()");
 		sugarsf = 0;		// fermentable sugars mash + boil
@@ -200,9 +227,9 @@
 			var row = rows[i];
 			if (row.f_adjust_to_total_100)
 				my_100 = true;
-			if (row.f_type == 1)		// Sugar
+			if (row.f_type == 1 && row.f_added < 4)		// Sugar
 				psugar += row.f_percentage;
-			if (row.f_graintype == 2)	// Crystal
+			if (row.f_graintype == 2 && row.f_added < 4)	// Crystal
 				pcara += row.f_percentage;
 			var d = row.f_amount * (row.f_yield / 100) * (1 - row.f_moisture / 100);
 			if (row.f_added == 0) {		// Mash
@@ -216,7 +243,7 @@
 			}
 			if (row.f_added == 0 || row.f_added == 1)	// Mash or Boil
 				sugarsf += d;
-			if (row.f_added == 2 || row.f_added == 3) {
+			if (row.f_added == 2 || row.f_added == 3) {	// Fermentation or lagering
 				var x = (row.f_yield / 100) * (1 - row.f_moisture / 100);
 				addedS += row.f_amount * x;
 				addedmass += row.f_amount;
@@ -225,9 +252,11 @@
 			if (row.f_added == 0 && (row.f_type == 0 || row.f_type == 4) && row.f_color < 50) { // Mash and Grain/Adjunct and Color < 50
 				lintner += row.f_diastatic_power * row.f_amount;
 			}
-			colort += row.f_amount * ebc_to_srm(row.f_color);
-			colorh += row.f_amount * row.f_color * get_kt(row.f_color);
-			colorn += (row.f_percentage / 100) * row.f_color;	// For 8.6 Pt wort.
+			if (row.f_added < 4) {
+				colort += row.f_amount * ebc_to_srm(row.f_color);
+				colorh += row.f_amount * row.f_color * get_kt(row.f_color);
+				colorn += (row.f_percentage / 100) * row.f_color;	// For 8.6 Pt wort.
+			}
 		}
 		$("#ferm_lintner").val(Math.round(parseFloat(lintner / mashkg)));
 		console.log("lintner:"+lintner+" kg:"+mashkg);
@@ -1196,20 +1225,24 @@
 
 		for (var i = 0; i < rowscount; i++) {
 			var row = $("#fermentableGrid").jqxGrid('getrowdata', i);
-			var d = row.f_percentage / 100 * (row.f_yield / 100) * (1 - row.f_moisture / 100);
-			if (row.f_added == 0)	// Mash
-				d = efficiency / 100 * d;
-			tot += d;
+			if (row.f_added < 4) {
+				var d = row.f_percentage / 100 * (row.f_yield / 100) * (1 - row.f_moisture / 100);
+				if (row.f_added == 0)	// Mash
+					d = efficiency / 100 * d;
+				tot += d;
+			}
 		}
 		var	totmass = 0;
 		if (tot)
-			totmass = sug / tot;
+			totmass = Math.round((sug / tot) * 1000) / 1000;
 
 		if (totmass) {
 			for (i = 0; i < rowscount; i++) {
 				var row = $("#fermentableGrid").jqxGrid('getrowdata', i);
-				var amount = row.f_percentage / 100 * totmass;
-				$("#fermentableGrid").jqxGrid('setcellvalue', i, "f_amount", amount);
+				if (row.f_added < 4) {
+					var amount = Math.round(row.f_percentage * 10 * totmass) / 1000;
+					$("#fermentableGrid").jqxGrid('setcellvalue', i, "f_amount", amount);
+				}
 			}
 		}
 	};
@@ -1809,15 +1842,15 @@
 				{ name: 'f_avail', type: 'int' }
 			],
 			addrow: function (rowid, rowdata, position, commit) {
-				console.log("fermentable addrow "+rowid);
+				//console.log("fermentable addrow "+rowid);
 				commit(true);
 			},
 			deleterow: function (rowid, commit) {
-				console.log("fermentable deleterow "+rowid);
+				//console.log("fermentable deleterow "+rowid);
 				commit(true);
 			},
 			updaterow: function (rowid, rowdata, commit) {
-				console.log("fermentable updaterow "+rowid);
+				//console.log("fermentable updaterow "+rowid);
 				commit(true);
 			}
 		};
@@ -1926,16 +1959,7 @@
 								}
 							}
 						} else {
-							var tw = 0;
-							for (i = 0; i < rowscount; i++) {
-								var rowdata = $("#fermentableGrid").jqxGrid('getrowdata', i);
-								tw += rowdata.f_amount;
-							};
-							for (i = 0; i < rowscount; i++) {
-								var rowdata = $("#fermentableGrid").jqxGrid('getrowdata', i);
-								var percentage = Math.round(rowdata.f_amount / tw * 1000) / 10.0;
-								$("#fermentableGrid").jqxGrid('setcellvalue', i, "f_percentage", percentage);
-							};
+							calcPercentages();
 						}
 					} else {
 						$("#fermentableGrid").jqxGrid('setcellvalue', 0, "f_percentage", 100);
@@ -2965,7 +2989,7 @@
 			f_avail: fermentableData.f_avail
 		};
 		$("#fermentableGrid").jqxGrid('updaterow', rowID, row);
-		// Recalc percentages
+		calcPercentages();
 		calcFermentables();
 		calcIBUs();
 		calcMash();
@@ -3023,25 +3047,7 @@
 		$("#fermentableGrid").jqxGrid('setcellvalue', fermentableRow, 'f_amount', event.args.value);
 		fermentableData.f_amount = event.args.value;
 		if (! to_100) {
-			// Recalculate percentages
-			console.log("adjust percentages");
-			var rowscount = $("#fermentableGrid").jqxGrid('getdatainformation').rowscount;
-			if (rowscount > 1) {
-				var tw = 0;
-				for (i = 0; i < rowscount; i++) {
-					var rowdata = $("#fermentableGrid").jqxGrid('getrowdata', i);
-					tw += rowdata.f_amount;
-				};
-				for (i = 0; i < rowscount; i++) {
-					var rowdata = $("#fermentableGrid").jqxGrid('getrowdata', i);
-					var percentage = Math.round(rowdata.f_amount / tw * 1000) / 10.0;
-					$("#fermentableGrid").jqxGrid('setcellvalue', i, "f_percentage", percentage);
-		//			if (i == fermentableRow) // Will crash the script.
-		//				$("#wf_percentage").val(percentage);
-				};
-			} else {
-				$("#fermentableGrid").jqxGrid('setcellvalue', 0, "f_percentage", 100);
-			}
+			calcPercentages();
 			calcFermentables();
 			calcMash();
 		};
@@ -3062,13 +3068,15 @@
 				var tw = 0;     // total weight
 				for (i = 0; i < rowscount; i++) {
 					var rowdata = $("#fermentableGrid").jqxGrid('getrowdata', i);
-					tw += rowdata.f_amount;
+					if (rowdata.f_added < 4)
+						tw += Math.round(rowdata.f_amount * 1000) / 1000;
 				}
+				tw = Math.round(tw * 1000) / 1000;
 				if (to_100) {
 					// Adjust this row and the 100% row.
-					var damount = tw * diff / 100;
+					var damount = Math.round(tw * diff *10) / 1000;
 					var rowdata = $("#fermentableGrid").jqxGrid('getrowdata', fermentableRow);
-					var namount = rowdata.f_amount + damount;
+					var namount = Math.round((rowdata.f_amount + damount) * 1000) / 1000;					
 					$("#fermentableGrid").jqxGrid('setcellvalue', fermentableRow, 'f_amount', namount);
 					$("#wf_amount").val(namount);
 					$("#fermentableGrid").jqxGrid('setcellvalue', fermentableRow, 'f_percentage', rowdata.f_percentage + diff);
@@ -3087,16 +3095,20 @@
 					var nw = tw * diff / 100;
 					for (i = 0; i < rowscount; i++) {
 						var rowdata = $("#fermentableGrid").jqxGrid('getrowdata', i);
-						if (i == fermentableRow) {
-							var namount = rowdata.f_amount + nw;
-							$("#fermentableGrid").jqxGrid('setcellvalue', i, 'f_amount', namount);
-		//					$("#wf_amount").val(namount); // Will crash the script.
-							$("#fermentableGrid").jqxGrid('setcellvalue', i, 'f_percentage', newvalue);
+						if (rowdata.f_added < 4) {
+							if (i == fermentableRow) {
+								var namount = Math.round((rowdata.f_amount + nw) * 1000) / 1000;
+								$("#fermentableGrid").jqxGrid('setcellvalue', i, 'f_amount', namount);
+		//						$("#wf_amount").val(namount); // Will crash the script.
+								$("#fermentableGrid").jqxGrid('setcellvalue', i, 'f_percentage', newvalue);
+							} else {
+								var namount = Math.round((rowdata.f_amount - (nw / (rowscount - 1))) * 1000) / 1000;
+								var newperc = Math.round((namount / tw) * 1000) / 10.0;
+								$("#fermentableGrid").jqxGrid('setcellvalue', i, 'f_amount', namount);
+								$("#fermentableGrid").jqxGrid('setcellvalue', i, 'f_percentage', newperc);
+							}
 						} else {
-							var namount = rowdata.f_amount - (nw / (rowscount - 1));
-							var newperc = Math.round((namount / tw) * 1000) / 10.0;
-							$("#fermentableGrid").jqxGrid('setcellvalue', i, 'f_amount', namount);
-							$("#fermentableGrid").jqxGrid('setcellvalue', i, 'f_percentage', newperc);
+							$("#fermentableGrid").jqxGrid('setcellvalue', i, 'f_percentage', 0);
 						}
 					}
 					calcFermentables();
--- a/www/prod_checklist.php	Wed Jun 05 20:06:14 2019 +0200
+++ b/www/prod_checklist.php	Fri Jun 14 20:26:51 2019 +0200
@@ -312,11 +312,11 @@
 		}
 		$this->Checkline('gistvat ontsmetten en evt. pomp en slangen ontsmetten');
 		$this->Checkline('wort naar gistvat overbrengen');
-		if ($this->GetY() > (300 - (5 * $lines)))
+
+		if ($this->GetY() > 240)
 			$this->AddPage();
 		else
 			$this->Ln(5);
-
 		$this->Checkheader('Gist enten');
 		$dry = 0;
 		foreach ($yeasts as $item) {
--- a/www/prod_edit.php	Wed Jun 05 20:06:14 2019 +0200
+++ b/www/prod_edit.php	Fri Jun 14 20:26:51 2019 +0200
@@ -727,7 +727,7 @@
         <td style="vertical-align: top; float: right; padding: 3px;">Datum:</td>
 	<td align="left" style="vertical-align: top;"><div id="package_date"></div></td>
         <td style="vertical-align: top; float: right; padding: 3px;">Aanbevolen koolzuur vol:</td>
-        <td style="padding: 3px;"><div style="float: left; margin-left: 15px;" id="st_carb_min2"></div><div style="float: left; margin-left: 5px;" id="st_carb_max2"></div></td>
+        <td style="padding: 3px;"><div style="float: left;" id="st_carb_min2"></div><div style="float: left; margin-left: 5px;" id="st_carb_max2"></div></td>
        </tr>
        <tr>
         <td colspan="4"><hr></td>
@@ -749,9 +749,9 @@
         <td align="left" style="vertical-align: top;"><div id="keg_carbonation"></div></td>
        </tr>
        <tr>
-        <td style="vertical-align: top; float: right; padding: 3px;">Suiker type:</td>
+        <td style="vertical-align: top; float: right; padding: 3px;">Suiker:</td>
         <td align="left" style="vertical-align: top;"><div id="bottle_priming_sugar"></div></td>
-        <td style="vertical-align: top; float: right; padding: 3px;">Suiker type:</td>
+        <td style="vertical-align: top; float: right; padding: 3px;">Suiker:</td>
         <td align="left" style="vertical-align: top;"><div id="keg_priming_sugar"></div></td>
        </tr>
        <tr>
@@ -761,9 +761,9 @@
         <td align="left" style="vertical-align: top;"><div id="keg_priming_amount"></div></td>
        </tr>
        <tr>
-        <td style="vertical-align: top; float: right; padding: 3px;">Suiker totaal gr:</td>
+        <td style="vertical-align: top; float: right; padding: 3px;">Suiker totaal gram:</td>
         <td align="left" style="vertical-align: top;"><div id="bottle_priming_total"></div></td>
-        <td style="vertical-align: top; float: right; padding: 3px;">Suiker totaal gr:</td>
+        <td style="vertical-align: top; float: right; padding: 3px;">Suiker totaal gram:</td>
         <td align="left" style="vertical-align: top;"><div id="keg_priming_total"></div></td>
        </tr>
        <tr>
--- a/www/prod_print.php	Wed Jun 05 20:06:14 2019 +0200
+++ b/www/prod_print.php	Fri Jun 14 20:26:51 2019 +0200
@@ -111,7 +111,7 @@
 		global $colorw;
 		global $preboil_sg;
 		global $mashkg;
-		$added = array( 'Maischen', 'Koken 10 min', 'Vergisten', 'Nagisten/lageren', 'Bottelen' );
+		$added = array( 'Maischen', 'Koken 10 min', 'Vergisten', 'Nagisten/lageren', 'Bottelen', 'Op fust' );
 		$ftype = array( 'Mout', 'Suiker', 'Vloeibaar extract', 'Droog extract', 'Ongemout graan' );
 		$mtype = array( 'Basismout', 'Geroosterde mout', 'Cara- of crystalmout', 'Geƫeste mout', 'Zuurmout', 'Speciale mout', 'Geen mout' );
 		$vul = $this->w - $this->rMargin - $this->lMargin - 125;

mercurial