Small fixes for prject import from Brouwhulp. Fixes for poduct database read/write. New menu entries. Equipment select in product editor. Started brewday editor. Added conditions on some buttons and edit fields. Screen layout changes.

Wed, 28 Nov 2018 21:57:06 +0100

author
Michiel Broek <mbroek@mbse.eu>
date
Wed, 28 Nov 2018 21:57:06 +0100
changeset 114
4935e86b2775
parent 113
982c9ae73e12
child 115
ad31f4bd4036

Small fixes for prject import from Brouwhulp. Fixes for poduct database read/write. New menu entries. Equipment select in product editor. Started brewday editor. Added conditions on some buttons and edit fields. Screen layout changes.

README.design file | annotate | diff | comparison | revisions
www/import/from_brouwhulp.php file | annotate | diff | comparison | revisions
www/includes/db_product.php file | annotate | diff | comparison | revisions
www/includes/global.inc.php file | annotate | diff | comparison | revisions
www/js/prod_edit.js file | annotate | diff | comparison | revisions
www/prod_edit.php file | annotate | diff | comparison | revisions
--- a/README.design	Fri Nov 23 15:25:54 2018 +0100
+++ b/README.design	Wed Nov 28 21:57:06 2018 +0100
@@ -114,3 +114,4 @@
 	Recipes are linked to prod_recipes.
 	  Recipes can be copied to 'recipes', imported from 'recipes'/'prod_recipes' or created manual.
 
+Een cronjob om de Stage bij te werken in geval van Package .. Taste. 
--- a/www/import/from_brouwhulp.php	Fri Nov 23 15:25:54 2018 +0100
+++ b/www/import/from_brouwhulp.php	Wed Nov 28 21:57:06 2018 +0100
@@ -1123,6 +1123,13 @@
 		$count = mysqli_affected_rows($db);
 		if ($count > 0) {
 			$psql .= "', log_fermentation='1";
+		} else {
+			// See if there really are no records
+			$sql  = "SELECT product_code FROM log_fermentation WHERE product_code='".$recipe->NR_RECIPE."';";
+			$count = mysqli_affected_rows($db);
+			if ($count > 0) {
+				$psql .= "', log_fermentation='1";
+			}
 		}
 
 		/*
@@ -1163,7 +1170,13 @@
 			if ($recipe->EQUIPMENT->TOP_UP_WATER)
 				$psql .= "', eq_top_up_water='" . floatval($recipe->EQUIPMENT->TOP_UP_WATER);
 			$psql .= "', eq_trub_chiller_loss='" . floatval($recipe->EQUIPMENT->TRUB_CHILLER_LOSS);
-			$psql .= "', eq_evap_rate='" . floatval($recipe->EQUIPMENT->EVAP_RATE);
+			/*
+			 * Brouwhulp uses a percentage for the evaporation rate. This is wrong
+			 * but was made so because the beerxml standard requires this. What we
+			 * do is calculate the actual evaporation and store that.
+			 * This is what we use. Brouwhulp calculates this on the fly.
+			 */
+			$psql .= "', eq_evap_rate='" . (floatval($recipe->EQUIPMENT->EVAP_RATE) * floatval($recipe->EQUIPMENT->BOIL_SIZE)) / 100;
 			$psql .= "', eq_boil_time='" . floatval($recipe->EQUIPMENT->BOIL_TIME);
 			($recipe->EQUIPMENT->CALC_BOIL_VOLUME == 'TRUE') ? $psql .= "', eq_calc_boil_volume='1" : $psql .= "', eq_calc_boil_volume='0";
 			if ($recipe->EQUIPMENT->TOP_UP_KETTLE)
--- a/www/includes/db_product.php	Fri Nov 23 15:25:54 2018 +0100
+++ b/www/includes/db_product.php	Wed Nov 28 21:57:06 2018 +0100
@@ -10,22 +10,12 @@
 }
 mysqli_set_charset($connect, "utf8" );
 
-syslog(LOG_NOTICE, "db_product: start");
-
-$escapers = array("\\", "/", "\"", "\n", "\r", "\t", "\x08", "\x0c");
-$replacements = array("\\\\", "\\/", "\\\"", "\\n", "\\r", "\\t", "\\f", "\\b");
-$rescapers = array("'");
-$rreplacements = array("\\'");
-$disallowed = array('visibleindex','uniqueid','boundindex','uid');
-
 
 if (isset($_POST['insert']) || isset($_POST['update'])) {
 	if (isset($_POST['insert'])) {
-		// INSERT COMMAND
 		$sql  = "INSERT INTO `prod_main` SET ";
 	}
 	if (isset($_POST['update'])) {
-		// UPDATE COMMAND
 		$sql  = "UPDATE `prod_main` SET ";
 	}
 	// Basic settings
@@ -44,8 +34,17 @@
 	$sql .= "', eq_batch_size='" . $_POST['eq_batch_size'];
 	$sql .= "', eq_tun_volume='" . $_POST['eq_tun_volume'];
 	$sql .= "', eq_tun_weight='" . $_POST['eq_tun_weight'];
-	$sql .= "', eq_tun_specific_heat='" . $_POST['eq_tun_specific_heat'];
-	$sql .= "', eq_tun_material='" . $_POST['eq_tun_material'];
+	$material = mysqli_real_escape_string($connect, $_GET['tun_material']);
+	$sql .= "', eq_tun_material='" . $material;
+	if ($material == "RVS") {
+		$sql .= "', eq_tun_specific_heat='0.11";
+	} else if ($material == "Aluminium") {
+		$sql .= "', eq_tun_specific_heat='0.22";
+	} else if ($material == "Kunststof") {
+		$sql .= "', eq_tun_specific_heat='0.46";
+	} else if ($material == "Koper") {
+		$sql .= "', eq_tun_specific_heat='0.092";
+	}
 	$sql .= "', eq_tun_height='" . $_POST['eq_tun_height'];
 	$sql .= "', eq_top_up_water='" . $_POST['eq_top_up_water'];
 	$sql .= "', eq_trub_chiller_loss='" . $_POST['eq_trub_chiller_loss'];
@@ -105,23 +104,16 @@
 	if (isset($_GET['select']) && ($_GET['select'] == "inprod")) {
 		$query = "SELECT record,name,code,birth,stage FROM prod_main WHERE stage != 'Closed' ORDER BY birth,code;";
 		$result = mysqli_query($connect, $query) or die("SQL Error 1: " . mysqli_error($connect));
-		$brews = '[';
-		$comma = FALSE;
 		while ($row = mysqli_fetch_array($result, MYSQLI_ASSOC)) {
-			// Manual encode to JSON.
-			if ($comma)
-				$brews .= ',';
-			$comma = TRUE;
-			$brews .=  '{"record":' . $row['record'];
-			$brews .=  ',"name":"' . str_replace($escapers, $replacements, $row['name']);
-			$brews .= '","code":"' . str_replace($escapers, $replacements, $row['code']);
-			$brews .= '","birth":"' . str_replace($escapers, $replacements, $row['birth']);
-			$brews .= '","stage":"' . str_replace($escapers, $replacements, $row['stage']);
-			$brews .= '"}';
+			$brews[] = array(
+				'record' => $row['record'],
+				'name' => $row['name'],
+				'code' => $row['code'],
+				'birth' => $row['birth'],
+				'stage' => $row['stage']
+			);
 		}
-		$brews .= ']';
-		header("Content-type: application/json");
-		echo $brews;
+		echo json_encode($brews);
 		return;
 	}
 
--- a/www/includes/global.inc.php	Fri Nov 23 15:25:54 2018 +0100
+++ b/www/includes/global.inc.php	Wed Nov 28 21:57:06 2018 +0100
@@ -193,6 +193,12 @@
          <li>Op datum</li>
         </ul>
        </li>
+       <li>Import
+        <ul>
+	 <li>Brouw log</li>
+	 <li>Etiket</li>
+        </ul>
+       </li>
        <li>Kalender</li>
       </ul>
      </li>
--- a/www/js/prod_edit.js	Fri Nov 23 15:25:54 2018 +0100
+++ b/www/js/prod_edit.js	Wed Nov 28 21:57:06 2018 +0100
@@ -46,8 +46,80 @@
 
 $(document).ready(function () {
 
+	var	brewstage = 0;	// Numeric value of stage
+
 	console.log("record:" + my_record + "  return:" + my_return + "  theme:" + theme);
 
+	// Equipemnt dropdown list
+	var equipmentUrl = "includes/db_inventory_equipments.php";
+	var equipmentSource = {
+		datatype: "json",
+		datafields: [
+			{ name: 'name', type: 'string' },
+			{ name: 'boil_size', type: 'float' },
+			{ name: 'batch_size', type: 'float' },
+			{ name: 'tun_volume', type: 'float' },
+			{ name: 'tun_weight', type: 'float' },
+			{ name: 'trub_chiller_loss', type: 'float' },
+			{ name: 'evap_rate', type: 'float' },
+			{ name: 'boil_time', type: 'float' },
+			{ name: 'lauter_deadspace', type: 'float' },
+			{ name: 'top_up_kettle', type: 'float' },
+			{ name: 'hop_utilization', type: 'float' },
+			{ name: 'notes', type: 'string' },
+			{ name: 'lauter_volume', type: 'float' },
+			{ name: 'kettle_volume', type: 'float' },
+			{ name: 'tun_material', type: 'string' },
+			{ name: 'tun_height', type: 'float' },
+			{ name: 'kettle_height', type: 'float' },
+			{ name: 'lauter_height', type: 'float' },
+			{ name: 'mash_volume', type: 'float' },
+			{ name: 'efficiency', type: 'float' }
+		],
+		url: equipmentUrl,
+		async: true
+	};
+	var equipmentlist = new $.jqx.dataAdapter(equipmentSource);
+	$("#equipmentSelect").jqxDropDownList({
+		placeHolder: "Kies apparatuur:",
+		theme: theme,
+		source: equipmentlist,
+		displayMember: "name",
+		width: 150,
+		height: 27,
+		dropDownWidth: 300,
+		renderer: function (index, label, value) {
+			var datarecord = equipmentlist.records[index];
+			return datarecord.batch_size + " liter " + datarecord.name;
+		}
+	});
+	$("#equipmentSelect").on('select', function (event) {
+		if (event.args) {
+			var index = event.args.index;
+			var datarecord = equipmentlist.records[index];
+			$("#eq_name").val(datarecord.name);
+			$("#eq_boil_size").val(datarecord.boil_size);
+			$("#eq_batch_size").val(datarecord.batch_size);
+			$("#eq_tun_volume").val(datarecord.tun_volume);
+			$("#eq_tun_weight").val(datarecord.tun_weight);
+			$("#eq_trub_chiller_loss").val(datarecord.trub_chiller_loss);
+			$("#eq_evap_rate").val(datarecord.evap_rate);
+			$("#eq_boil_time").val(datarecord.boil_time);
+			$("#eq_lauter_deadspace").val(datarecord.lauter_deadspace);
+			$("#eq_top_up_kettle").val(datarecord.top_up_kettle);
+			$("#eq_hop_utilization").val(datarecord.hop_utilization);
+			$("#eq_notes").val(datarecord.notes);
+			$("#eq_lauter_volume").val(datarecord.lauter_volume);
+			$("#eq_kettle_volume").val(datarecord.kettle_volume);
+			$("#eq_tun_material").val(datarecord.tun_material);
+			$("#eq_tun_height").val(datarecord.tun_height);
+			$("#eq_kettle_height").val(datarecord.kettle_height);
+			$("#eq_lauter_height").val(datarecord.lauter_height);
+			$("#eq_mash_volume").val(datarecord.mash_volume);
+			$("#eq_efficiency").val(datarecord.efficiency);
+		}
+	});
+
 	var dataReecord = {};
 	var url = "includes/db_product.php";
 	// tooltips
@@ -56,27 +128,26 @@
 	$("#birth").jqxTooltip({ content: 'De ontwerp datum van dit product.' });
 	$("#stage").jqxTooltip({ content: 'De productie fase van dit product.' });
 	$("#notes").jqxTooltip({ content: 'De uitgebreide opmerkingen over dit product.' });
-	$("#eq_name").jqxTooltip({ content: 'The unique name of this brew equipment.' });
-	$("#eq_notes").jqxTooltip({ content: 'Some notes about the equipment.' });
-	$("#eq_tun_volume").jqxTooltip({ content: 'Mash TUN volume.' });
-	$("#eq_tun_height").jqxTooltip({ content: 'Mash TUN height in cm.' });
-	$("#eq_tun_weight").jqxTooltip({ content: 'Mash TUN weight in Kg.' });
-	$("#eq_tun_material").jqxTooltip({ content: 'Mash TUN material. Needed to calculate the right strike temperature.' });
-	$("#eq_mash_volume").jqxTooltip({ content: 'Mash water for the first step.' });
-	$("#eq_lauter_volume").jqxTooltip({ content: 'Total lauter volume.' });
-	$("#eq_lauter_height").jqxTooltip({ content: 'Height of the lauter TUN in cm.' });
-	$("#eq_lauter_deadspace").jqxTooltip({ content: 'Volume loss in the lauter TUN.' });
-	$("#eq_efficiency").jqxTooltip({ content: 'Average efficiency.' });
-	$("#eq_kettle_volume").jqxTooltip({ content: 'Boil kettle volume in liters.' });
-	$("#eq_kettle_height").jqxTooltip({ content: 'Boil kettle height in cm.' });
-	$("#eq_boil_size").jqxTooltip({ content: 'Normal boil volume in liters' });
-	$("#eq_evap_rate").jqxTooltip({ content: 'Evaporation in liters per hour.' });
-	$("#eq_boil_time").jqxTooltip({ content: 'Normal boil time in minutes.' });
-	$("#eq_top_up_kettle").jqxTooltip({ content: 'Extra water added to the boil.' });
-	$("#eq_hop_utilization").jqxTooltip({ content: '100% for smaller installations, higher for large breweries.' });
-	$("#eq_batch_size").jqxTooltip({ content: 'Calculated batch size, liters at end of the boil.' });
-	$("#eq_trub_chiller_loss").jqxTooltip({ content: 'Standard loss in liters during transfer to the fermenter.' });
-
+	$("#eq_name").jqxTooltip({ content: 'De naam van deze brouw apparatuur.' });
+	$("#eq_notes").jqxTooltip({ content: 'Opmerkingen over deze apparatuur.' });
+	$("#eq_tun_volume").jqxTooltip({ content: 'Maisch ketel volume.' });
+	$("#eq_tun_height").jqxTooltip({ content: 'Maisch ketel hoogte in cm.' });
+	$("#eq_tun_weight").jqxTooltip({ content: 'Maisch ketel gewicht in Kg.' });
+	$("#eq_tun_material").jqxTooltip({ content: 'Maisch ketel materiaal. Nodig om de juiste inmaisch temperatuur te berekenen.' });
+	$("#eq_mash_volume").jqxTooltip({ content: 'Maisch water voor de eerste stap.' });
+	$("#eq_lauter_volume").jqxTooltip({ content: 'Filterkuip volume.' });
+	$("#eq_lauter_height").jqxTooltip({ content: 'Hoogte van de filterkuip in cm.' });
+	$("#eq_lauter_deadspace").jqxTooltip({ content: 'Filterkuip verlies in liters.' });
+	$("#eq_efficiency").jqxTooltip({ content: 'Gemiddeld brouwzaal rendement.' });
+	$("#eq_kettle_volume").jqxTooltip({ content: 'Kook ketel volume in liters.' });
+	$("#eq_kettle_height").jqxTooltip({ content: 'Kook ketel hoogte in cm.' });
+	$("#eq_boil_size").jqxTooltip({ content: 'Normaal kook volume in liters' });
+	$("#eq_evap_rate").jqxTooltip({ content: 'Verdamping in liters per uur.' });
+	$("#eq_boil_time").jqxTooltip({ content: 'Normale kooktijd in minuten..' });
+	$("#eq_top_up_kettle").jqxTooltip({ content: 'Extra water toevoegen tijdens de kook.' });
+	$("#eq_hop_utilization").jqxTooltip({ content: '100% voor kleine installaties, hoger voor grote brouwerijen.' });
+	$("#eq_batch_size").jqxTooltip({ content: 'Berekende batch grootte in liters aan het eind van de kook.' });
+	$("#eq_trub_chiller_loss").jqxTooltip({ content: 'Standaard verlies bij het overbrengen naar het gistvat.' });
 
 	// Prepare the data
 	var source = {
@@ -90,6 +161,10 @@
 			{ name: 'birth', type: 'string' },
 			{ name: 'stage', type: 'string' },
 			{ name: 'notes', type: 'string' },
+			{ name: 'log_brew', type: 'bool' },
+			{ name: 'log_fermentation', type: 'bool' },
+			{ name: 'inventory_reduced', type: 'bool' },
+			{ name: 'locked', type: 'bool' },
 			{ name: 'eq_name', type: 'string' },
 			{ name: 'eq_boil_size', type: 'float' },
 			{ name: 'eq_batch_size', type: 'float' },
@@ -109,7 +184,12 @@
 			{ name: 'eq_kettle_height', type: 'float' },
 			{ name: 'eq_lauter_height', type: 'float' },
 			{ name: 'eq_mash_volume', type: 'float' },
-			{ name: 'eq_efficiency', type: 'float' }
+			{ name: 'eq_efficiency', type: 'float' },
+			{ name: 'brew_date_start', type: 'string' },
+			{ name: 'brew_mash_ph', type: 'float' },
+			{ name: 'brew_mash_sg', type: 'float' },
+
+			{ name: 'brew_date_end', type: 'string' }
 		],
 		id: 'record',
 		url: url
@@ -125,6 +205,10 @@
 			$("#birth").val(dataRecord.birth);
 			$("#stage").val(dataRecord.stage);
 			$("#notes").val(dataRecord.notes);
+			$("#log_brew").val(dataRecord.log_brew);
+			$("#log_fermentation").val(dataRecord.log_fermentation);
+			$("#inventory_reduced").val(dataRecord.inventory_reduced);
+			$("#locked").val(dataRecord.locked);
 			$("#eq_name").val(dataRecord.eq_name);
 			$("#eq_boil_size").val(dataRecord.eq_boil_size);
 			$("#eq_batch_size").val(dataRecord.eq_batch_size);
@@ -145,11 +229,50 @@
 			$("#eq_lauter_height").val(dataRecord.eq_lauter_height);
 			$("#eq_mash_volume").val(dataRecord.eq_mash_volume);
 			$("#eq_efficiency").val(dataRecord.eq_efficiency);
+			$("#brew_date_start").val(dataRecord.brew_date_start);
+			$("#brew_mash_ph").val(dataRecord.brew_mash_ph);
+			$("#brew_mash_sg").val(dataRecord.brew_mash_sg);
 
-			if (dataRecord.stage != "Plan") {
-				// Only allow Delete when in Plan stage.
+			$("#brew_date_end").val(dataRecord.brew_date_end);
+
+			switch (dataRecord.stage) {
+				case 'Plan':		brewstage = 0;	break;
+				case 'Wait':		brewstage = 1;	break;
+				case 'Brew':		brewstage = 2;	break;
+				case 'Primary':		brewstage = 3;	break;
+				case 'Secondary':	brewstage = 4;	break;
+				case 'Tertiary':	brewstage = 5;	break;
+				case 'Package':		brewstage = 6;	break;
+				case 'Carbonation':	brewstage = 7;	break;
+				case 'Mature':		brewstage = 8;	break;
+				case 'Taste':		brewstage = 9;	break;
+				case 'Ready':		brewstage = 10;
+							$("#locked").jqxCheckBox({ disabled:false });
+							break;
+				case 'Closed':		brewstage = 11;
+							$("#locked").jqxCheckBox({ disabled:false });
+							break;
+			}
+			// Enable or Disable settings depending on the stage.
+			if (brewstage > 1)
+				$("#equipmentSelect").jqxDropDownList({ disabled: true });
+			if (brewstage > 0) {
 				$("#Delete").jqxButton({ disabled: true });
+				$("#birth").jqxDateTimeInput({ disabled: true });
 			}
+			if (brewstage < 3) {
+				$("#brew_log").jqxButton({ disabled: true });
+				$("#ferment_log").jqxButton({ disabled: true });
+			} else {
+				if (! dataRecord.log_brew)
+					$("#brew_log").jqxButton({ disabled: true });
+				if (! dataRecord.log_fermentation)
+					$("#ferment_log").jqxButton({ disabled: true });
+			}
+			if (brewstage < 6)
+				$("#inventory_reduced").jqxCheckBox({ disabled : true });
+			else if ($('#inventory_reduced').jqxCheckBox('checked'))
+				$("#inventory_reduced").jqxCheckBox({ disabled : true });
 		},
 		loadError: function (jqXHR, status, error) {
 		},
@@ -172,26 +295,50 @@
 	$("#birth").jqxDateTimeInput({ theme: theme, width: 150, height: 23, formatString: 'yyyy-MM-dd' });
 	$("#stage").jqxInput({ theme: theme, width: 100, height: 23 });
 	$("#notes").jqxInput({ theme: theme, width: 960, height: 200 });
+	$("#log_brew").jqxCheckBox({ theme: theme, width: 120, height: 23, disabled : true });
+	$("#log_fermentation").jqxCheckBox({ theme: theme, width: 120, height: 23, disabled : true });
+	$("#inventory_reduced").jqxCheckBox({ theme: theme, width: 120, height: 23 });
+	$('#inventory_reduced').on('checked', function (event) {
+		// Call a script to do the work and block this.
+		// Note that this script must set this flag too, so of the user doesn't Save it is still set.
+		// Call the script with the uuid.
+		$("#inventory_reduced").jqxCheckBox({ disabled : true });
+	});
+	$("#locked").jqxCheckBox({ theme: theme, width: 120, height: 23, disabled : true });
+	$('#locked').on('checked', function (event) {
+		$("#stage").val('Closed');
+		brewstage = 11;
+	});
+	$('#locked').on('unchecked', function (event) {
+		$("#stage").val('Ready');
+		brewstage = 10;
+	});
 	$("#eq_name").jqxInput({ theme: theme, width: 250, height: 23 });
-	$("#eq_boil_size").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 70, height: 23, min: 0, decimalDigits: 1, spinButtons: true, spinButtonsStep: 0.5 });
-	$("#eq_batch_size").jqxNumberInput({ inputMode: 'simple', readOnly: 'true', theme: theme, width: 50, height: 23, min: 0, decimalDigits: 1 });
-	$("#eq_tun_volume").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 70, height: 23, min: 0, decimalDigits: 1, spinButtons: true, spinButtonsStep: 0.5 });
-	$("#eq_tun_weight").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 70, height: 23, min: 0, decimalDigits: 2, spinButtons: true });
-	$("#eq_trub_chiller_loss").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 70, height: 23, min: 0, decimalDigits: 1, spinButtons: true, spinButtonsStep: 0.1 });
-	$("#eq_evap_rate").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 70, height: 23, min: 0, decimalDigits: 2, spinButtons: true, spinButtonsStep: 0.05 });
-	$("#eq_boil_time").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 70, height: 23, min: 0, decimalDigits: 0, spinButtons: true });
-	$("#eq_lauter_deadspace").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 70, height: 23, min: 0, decimalDigits: 1, spinButtons: true, spinButtonsStep: 0.1 });
-	$("#eq_top_up_kettle").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 70, height: 23, min: 0, decimalDigits: 1, spinButtons: true, spinButtonsStep: 0.1 });
-	$("#eq_hop_utilization").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 70, height: 23, min: 0, decimalDigits: 0, spinButtons: true });
+	$("#eq_boil_size").jqxNumberInput({ inputMode: 'simple', readOnly: true, theme: theme, width: 70, height: 23, decimalDigits: 1 });
+	$("#eq_batch_size").jqxNumberInput({ inputMode: 'simple', readOnly: true, theme: theme, width: 70, height: 23, decimalDigits: 1 });
+	$("#eq_tun_volume").jqxNumberInput({ inputMode: 'simple', readOnly: true, theme: theme, width: 70, height: 23, decimalDigits: 1 });
+	$("#eq_tun_weight").jqxNumberInput({ inputMode: 'simple', readOnly: true, theme: theme, width: 70, height: 23, decimalDigits: 2 });
+	$("#eq_trub_chiller_loss").jqxNumberInput({ inputMode: 'simple', readOnly: true, theme: theme, width: 70, height: 23, decimalDigits: 1 });
+	$("#eq_evap_rate").jqxNumberInput({ inputMode: 'simple', readOnly: true, theme: theme, width: 70, height: 23, decimalDigits: 2,  });
+	$("#eq_boil_time").jqxNumberInput({ inputMode: 'simple', readOnly: true, theme: theme, width: 70, height: 23, decimalDigits: 0 });
+	$("#eq_lauter_deadspace").jqxNumberInput({ inputMode: 'simple', readOnly: true, theme: theme, width: 70, height: 23, decimalDigits: 1 });
+	$("#eq_top_up_kettle").jqxNumberInput({ inputMode: 'simple', readOnly: true, theme: theme, width: 70, height: 23, decimalDigits: 1 });
+	$("#eq_hop_utilization").jqxNumberInput({ inputMode: 'simple', readOnly: true, theme: theme, width: 70, height: 23, decimalDigits: 0 });
 	$("#eq_notes").jqxInput({ theme: theme, width: 640, height: 100 });
-	$("#eq_lauter_volume").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 70, height: 23, min: 0, decimalDigits: 1, spinButtons: true, spinButtonsStep: 0.5 });
-	$("#eq_kettle_volume").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 70, height: 23, min: 0, decimalDigits: 1, spinButtons: true, spinButtonsStep: 0.5 });
-	$("#eq_tun_material").jqxDropDownList({ theme: theme, source: srcMaterial, selectedIndex: 0, width: 110, height: 23, dropDownHeight: 130 });
-	$("#eq_tun_height").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 70, height: 23, min: 0, decimalDigits: 1, spinButtons: true });
-	$("#eq_kettle_height").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 70, height: 23, min: 0, decimalDigits: 1, spinButtons: true });
-	$("#eq_lauter_height").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 70, height: 23, min: 0, decimalDigits: 1, spinButtons: true });
-	$("#eq_mash_volume").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 70, height: 23, min: 0, decimalDigits: 1, spinButtons: true, spinButtonsStep: 0.5 });
-	$("#eq_efficiency").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 70, height: 23, min: 0, decimalDigits: 1, spinButtons: true });
+	$("#eq_lauter_volume").jqxNumberInput({ inputMode: 'simple', readOnly: true, theme: theme, width: 70, height: 23, decimalDigits: 1 });
+	$("#eq_kettle_volume").jqxNumberInput({ inputMode: 'simple', readOnly: true, theme: theme, width: 70, height: 23, decimalDigits: 1 });
+	$("#eq_tun_material").jqxInput({ theme: theme, width: 100, height: 23 });
+	$("#eq_tun_height").jqxNumberInput({ inputMode: 'simple', readOnly: true, theme: theme, width: 70, height: 23, decimalDigits: 1 });
+	$("#eq_kettle_height").jqxNumberInput({ inputMode: 'simple', readOnly: true, theme: theme, width: 70, height: 23, decimalDigits: 1 });
+	$("#eq_lauter_height").jqxNumberInput({ inputMode: 'simple', readOnly: true, theme: theme, width: 70, height: 23, decimalDigits: 1 });
+	$("#eq_mash_volume").jqxNumberInput({ inputMode: 'simple', readOnly: true, theme: theme, width: 70, height: 23, decimalDigits: 1 });
+	$("#eq_efficiency").jqxNumberInput({ inputMode: 'simple', readOnly: true, theme: theme, width: 70, height: 23, decimalDigits: 1 });
+
+	$("#brew_date_start").jqxDateTimeInput({ theme: theme, width: 230, height: 23, formatString: 'yyyy-MM-dd HH:mm:ss', showTimeButton: true });
+	$("#brew_mash_ph").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 70, height: 23, min: 0, decimalDigits: 1, spinButtons: true, spinButtonsStep: 0.1 });
+	$("#brew_mash_sg").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 90, height: 23, min: 0, decimalDigits: 3, spinButtons: true, spinButtonsStep: 0.001 });
+
+	$("#brew_date_end").jqxDateTimeInput({ theme: theme, width: 230, height: 23, formatString: 'yyyy-MM-dd HH:mm:ss', showTimeButton: true });
 
 	$('#jqxTabs').jqxTabs({
 		theme: theme,
@@ -202,7 +349,9 @@
 	});
 
 	// Buttons sidebar
-	$("#rec_edit").jqxButton({ template: "primary", width: '110px', theme: theme });
+	$("#rec_edit").jqxButton({ template: "primary", width: '140px', theme: theme });
+	$("#brew_log").jqxButton({ template: "primary", width: '140px', theme: theme });
+	$("#ferment_log").jqxButton({ template: "primary", width: '140px', theme: theme });
 
 	// Buttons below
 	$("#Delete").jqxButton({ template: "danger", width: '80px', theme: theme });
@@ -232,6 +381,56 @@
 		window.location.href = my_return;
 	});
 
+	$("#Save").jqxButton({ template: "success", width: '90px', theme: theme });
+	$("#Save").click(function () {
+		var row = {
+			record: my_record,
+			uuid: $("#uuid").val(),
+			name: $("#name").val(),
+			code: $("#code").val(),
+			birth: $("#birth").val(),
+			stage: $("#stage").val(),
+			notes: $("#notes").val(),
+			log_brew: $("#log_brew").val(),
+			log_fermentation: $("#log_fermentation").val(),
+			inventory_reduced: $("#inventory_reduced").val(),
+			locked: $("#locked").val(),
+			eq_name: $("#eq_name").val(),
+			eq_boil_size: parseFloat($("#eq_boil_size").jqxNumberInput('decimal')),
+			eq_batch_size: parseFloat($("#eq_batch_size").jqxNumberInput('decimal')),
+			eq_tun_volume: parseFloat($("#eq_tun_volume").jqxNumberInput('decimal')),
+			eq_tun_weight: parseFloat($("#eq_tun_weight").jqxNumberInput('decimal')),
+			eq_trub_chiller_loss: parseFloat($("#eq_trub_chiller_loss").jqxNumberInput('decimal')),
+			eq_evap_rate: parseFloat($("#eq_evap_rate").jqxNumberInput('decimal')),
+			eq_boil_time: parseFloat($("#eq_boil_time").jqxNumberInput('decimal')),
+			eq_lauter_deadspace: parseFloat($("#eq_lauter_deadspace").jqxNumberInput('decimal')),
+			eq_top_up_kettle: parseFloat($("#eq_top_up_kettle").jqxNumberInput('decimal')),
+			eq_hop_utilization: parseFloat($("#eq_hop_utilization").jqxNumberInput('decimal')),
+			eq_notes: $("#eq_notes").val(),
+			eq_lauter_volume: parseFloat($("#eq_lauter_volume").jqxNumberInput('decimal')),
+			eq_kettle_volume: parseFloat($("#eq_kettle_volume").jqxNumberInput('decimal')),
+			eq_tun_material: $("#eq_tun_material").val(),
+			eq_tun_height: parseFloat($("#eq_tun_height").jqxNumberInput('decimal')),
+			eq_kettle_height: parseFloat($("#eq_kettle_height").jqxNumberInput('decimal')),
+			eq_lauter_height: parseFloat($("#eq_lauter_height").jqxNumberInput('decimal')),
+			eq_mash_volume: parseFloat($("#eq_mash_volume").jqxNumberInput('decimal')),
+			eq_efficiency: parseFloat($("#eq_efficiency").jqxNumberInput('decimal'))
+		};
+		var data = "update=true&" + $.param(row);
+		$.ajax({
+			dataType: 'json',
+			url: url,
+			cache: false,
+			data: data,
+			type: "POST",
+			success: function (data, status, xhr) {
+				// update command is executed.
+				window.location.href = my_return;
+			},
+			error: function(jqXHR, textStatus, errorThrown) {
+			}
+		});
+	});	
 	createDelElements();
 });
 
--- a/www/prod_edit.php	Fri Nov 23 15:25:54 2018 +0100
+++ b/www/prod_edit.php	Wed Nov 28 21:57:06 2018 +0100
@@ -26,7 +26,20 @@
            <td style="vertical-align: top; float: right; padding: 3px;">Start planning:</td>
            <td align="left" style="vertical-align: top;"><div id="birth"></div></td>
            <td style="vertical-align: top; float: right; padding: 3px;">Brouw fase:</td>
-           <td align="left" style="vertical-align: top; padding: 3px;"><input id="stage" readonly /></td>
+	   <td align="left" style="vertical-align: top; padding: 3px;"><input id="stage" readonly /></td>
+          </tr>
+          <tr>
+           <td align="right" style="vertical-align: top;">Brouw log:</td>
+           <td align="left"><div id="log_brew"></div></td>
+           <td align="right" style="vertical-align: top;">Vergisting log:</td>
+           <td align="left"><div id="log_fermentation"></div></td>
+           <td align="right" style="vertical-align: top;">Ingredienten afgeboekt:</td>
+	   <td align="left"><div id="inventory_reduced"></div></td>
+          </tr>
+          <tr>
+           <td align="right" style="vertical-align: top;">Afgesloten:</td>
+	   <td align="left" colspan="5" ><div id="locked"></div></td>
+          </tr>
           <tr>
            <td style="vertical-align: top; float: right; padding: 3px;">Opmerkingen:</td>
            <td colspan="5" style="padding: 3px;"><textarea id="notes"></textarea></td>
@@ -36,8 +49,8 @@
         <td style="vertical-align: top;">
          <table>
           <tr><td style="padding: 5px;"><input style="margin-right: 10px;" type="button" id="rec_edit" value="Recept" /></td></tr>
-          <tr><td style="padding: 5px;"><input style="margin-right: 10px;" type="button" id="Knop2"  value="Knop 2" /></td></tr>
-          <tr><td style="padding: 5px;"><input style="margin-right: 10px;" type="button" id="Knop3"  value="Knop 3" /></td></tr>
+          <tr><td style="padding: 5px;"><input style="margin-right: 10px;" type="button" id="brew_log"  value="Brouw log" /></td></tr>
+          <tr><td style="padding: 5px;"><input style="margin-right: 10px;" type="button" id="ferment_log"  value="Vergisting log" /></td></tr>
          </table>
         </td>
        </tr>
@@ -54,18 +67,18 @@
 
     <div> <!-- Tab 2 -->
      <div style="overflow: hidden;">
-      <table>
+      <table style="width: 100%;">
        <tr>
         <td align="right" style="vertical-align: top;">Kies apparatuur:</td>
-        <td align="left" colspan="3"><div id="styleSelect">Apparatuur</div></td>
+        <td align="left" colspan="3"><div id="equipmentSelect">Apparatuur</div></td>
        </tr>
        <tr>
         <td style="vertical-align: top; float: right; padding: 3px;">Installatie naam:</td>
-        <td align="left" colspan="3" style="vertical-align: top; padding: 3px;"><input id="eq_name" /></td>
+        <td align="left" colspan="3" style="vertical-align: top; padding: 3px;"><input id="eq_name" readonly /></td>
        </tr>
        <tr>
         <td style="vertical-align: top; float: right; padding: 3px;">Opmerkingen:</td>
-        <td colspan="5" style="padding: 3px;"><textarea id="eq_notes"></textarea></td>
+        <td colspan="5" style="padding: 3px;"><textarea id="eq_notes" readonly></textarea></td>
        </tr>
        <tr>
         <th style="text-align: center;" colspan="2">Maischen</th>
@@ -90,8 +103,8 @@
         <td><div id="eq_boil_size"></div></td>
        </tr>
        <tr>
-        <td style="vertical-align: top; float: right;">Maischkuip materiaal:</td>
-        <td><div id="eq_tun_material"></div></td>
+	<td style="vertical-align: top; float: right;">Maischkuip materiaal:</td>
+        <td align="left" style="vertical-align: top; padding: 3px;"><input id="eq_tun_material" readonly /></td>
         <td style="vertical-align: top; float: right;">Verdamping per uur l:</td>
         <td><div id="eq_evap_rate"></div></td>
        </tr>
@@ -131,22 +144,117 @@
        </tr>
       </table>
      </div>
-     <div class="hint" id="hintStyle">
-     </div>
     </div>
 
-    <div> <!-- Tab 3 -->
-     <div style="overflow: hidden; margin: 25px;"><br>
-      <p>Alle nodige gegevens zijn compleet.</p>
-      <p> Zodra je de "Volgende" toets gebruikt zal een nieuw recept aangemaakt worden en<br>
-      wordt het recept in de database gezet. Hierna kun je dat recept bewerken.</p>
-     </div>
-     <div id="completedButtonsWrapper">
-      <input type="button" value="Terug" id="backButtonCompleted" class="backButton" />
-      <input type="button" value="Volgende" class="nextButton" id="nextButtonCompleted" />
-     </div>
+    <div> <!-- Brewday -->
+     <table style="width: 100%;">
+      <tr>
+       <td style="vertical-align: top; float: right; padding: 3px;">Brouwdag start:</td>
+       <td align="left" colspan="3" style="vertical-align: top;"><div id="brew_date_start"></div></td>
+       <td style="vertical-align: top; float: right; padding: 3px;">Brouwdag eind:</td>
+       <td align="left" style="vertical-align: top;"><div id="brew_date_end"></div></td>
+      </tr>
+      <tr>
+       <th style="text-align: center;" colspan="2">Maischen</th>
+       <th style="text-align: center;" colspan="4">Koken</th>
+      </tr>
+      <tr>
+       <td style="vertical-align: top; float: right;">Maisch pH:</td>
+       <td><div id="brew_mash_ph"></div></td>
+       <td style="vertical-align: top; float: right;">pH voor koken:</td>
+       <td><div id="brew_preboil_ph"></div></td>
+       <td style="vertical-align: top; float: right;">pH na koken:</td>
+       <td><div id="brew_aboil_ph"></div></td>
+      </tr>
+      <tr>
+       <td style="vertical-align: top; float: right;">Maisch SG:</td>
+       <td><div id="brew_mash_sg"></div></td>
+       <td style="vertical-align: top; float: right;">SG voor koken:</td>
+       <td><div id="brew_preboil_sg"></div></td>
+       <td style="vertical-align: top; float: right;">SG na koken:</td>
+       <td><div id="brew_aboil_sg"></div></td>
+      </tr>
+      <tr>
+       <td style="vertical-align: top; float: right;">Maisch rendement:</td>
+       <td><div id="brew_mash_efficiency"></div></td>
+       <td style="vertical-align: top; float: right;">Volume voor koken:</td>
+       <td><div id="brew_preboil_volume"></div></td>
+       <td style="vertical-align: top; float: right;">Volume na koken:</td>
+       <td><div id="brew_aboil_volume"></div></td>
+      </tr>
+      <tr>
+       <th style="text-align: center;" colspan="2">Spoelen en filteren</th>
+       <td style="vertical-align: top; float: right;">Rendement voor koken:</td>
+       <td><div id="brew_preboil_efficiency"></div></td>
+       <td style="vertical-align: top; float: right;">Rendement na koken:</td>
+       <td><div id="brew_aboil_efficiency"></div></td>
+      </tr>
+       <tr>
+       <td style="vertical-align: top; float: right;">Spoelwater temperatuur:</td>
+       <td><div id="brew_sparge_temperature"></div></td>
+       <th style="text-align: center;" colspan="4">Koelen en whirlpoolen</th>
+      </tr>
+      <tr>
+       <td style="vertical-align: top; float: right;">Spoelwater volume:</td>
+       <td><div id="brew_sparge_volume"></div></td>
+       <td style="vertical-align: top; float: right;">Whirlpool 85..100&deg;C:</td>
+       <td><div id="brew_whirlpool9"></div></td>
+       <td style="vertical-align: top; float: right;">Koelen tot:</td>
+       <td><div id="brew_cooling_to"></div></td>
+      </tr>
+      <tr>
+       <td style="vertical-align: top; float: right;">Spoelwater pH:</td>
+       <td><div id="brew_sparge_volume"></div></td>
+       <td style="vertical-align: top; float: right;">Whirlpool 72..79&deg;C:</td>
+       <td><div id="brew_whirlpool7"></div></td>
+       <td style="vertical-align: top; float: right;">Koelen met:</td>
+       <td><div id="brew_cooling_to"></div></td>
+      </tr>
+      <tr>
+       <th style="text-align: center;" colspan="2">Beluchten</th>
+       <td style="vertical-align: top; float: right;">Whirlpool 60..66&deg;C:</td>
+       <td><div id="brew_whirlpool6"></div></td>
+       <td style="vertical-align: top; float: right;">Koelen tijd:</td>
+       <td><div id="brew_cooling_time"></div></td>
+      </tr>
+      <tr>
+       <td style="vertical-align: top; float: right;">Beluchten met:</td>
+       <td><div id="brew_aeration_type"></div></td>
+       <td style="vertical-align: top; float: right;">Whirlpool koud:</td>
+       <td><div id="brew_whirlpool2"></div></td>
+       <td colspan="2"> </td>
+      </tr>
+      <tr>
+       <td style="vertical-align: top; float: right;">Beluchten tijd:</td>
+       <td><div id="brew_aeration_time"></div></td>
+       <th style="text-align: center;" colspan="4">Naar gistvat</th>
+      </tr>
+      <tr>
+       <td style="vertical-align: top; float: right;">Beluchten snelheid:</td>
+       <td><div id="brew_aeration_speed"></div></td>
+       <td style="vertical-align: top; float: right;">Volume naar gistvat:</td>
+       <td><div id="brew_fermenter_volume"></div></td>
+       <td style="vertical-align: top; float: right;">Extra water:</td>
+       <td><div id="brew_fermenter_extrawater"></div></td>
+      </tr>
+      <tr>
+       <td colspan="2"> </td>
+       <td style="vertical-align: top; float: right;">SG in gistvat:</td>
+       <td><div id="brew_fermenter_volume"></div></td>
+       <td style="vertical-align: top; float: right;">Extra suiker:</td>
+       <td><div id="brew_fermenter_extrasugar"></div></td>
+      </tr>
+      <tr>
+       <td colspan="2"> </td>
+       <td style="vertical-align: top; float: right;">IBU in gistvat:</td>
+       <td><div id="brew_fermenter_ibu"></div></td>
+       <td style="vertical-align: top; float: right;">Kleur in gistvat:</td>
+       <td><div id="brew_fermenter_color"></div></td>
+      </tr>
+     </table>
     </div>
-   </div>
+
+   </div> <!-- Tabs -->
 
 <?php
 confirm_delete();

mercurial