Merged with default branch stable

Wed, 05 Jun 2019 20:04:26 +0200

author
Michiel Broek <mbroek@mbse.eu>
date
Wed, 05 Jun 2019 20:04:26 +0200
branch
stable
changeset 402
c61f6559cc45
parent 388
0a31e1e80a1d (current diff)
parent 401
4aad74bde00b (diff)
child 403
0fc59d0aa3df

Merged with default branch

config.status file | annotate | diff | comparison | revisions
configure file | annotate | diff | comparison | revisions
configure.ac file | annotate | diff | comparison | revisions
--- a/README.design	Thu May 30 23:19:43 2019 +0200
+++ b/README.design	Wed Jun 05 20:04:26 2019 +0200
@@ -16,7 +16,7 @@
 Gisten diastaticus bit toevoegen.
 Gist typen: kveik en brett? Apart of niet.
 
-Popups is de editors met rekenhulpjes.
+Popups in de editors met rekenhulpjes.
 
-Beerxml cool tot temp toevoegen.
+Koolzuurdruk tabel inbouwen.
 
--- a/www/Makefile	Thu May 30 23:19:43 2019 +0200
+++ b/www/Makefile	Wed Jun 05 20:04:26 2019 +0200
@@ -12,8 +12,8 @@
 		  log_brew.php log_fermentation.php \
 		  mon_brewer.php mon_fermenter.php mon_node.php \
 		  prod_archive_code.php prod_archive_date.php prod_archive_name.php prod_beerxml.php \
-		  prod_duplicate.php prod_edit.php prod_export.php prod_forum.php prod_impbrew.php \
-		  prod_inprod.php prod_new.php prod_print.php prod_torecipe.php \
+		  prod_checklist.php prod_duplicate.php prod_edit.php prod_export.php prod_forum.php \
+		  prod_impbrew.php prod_inprod.php prod_new.php prod_print.php prod_torecipe.php \
 		  profile_fermentation.php profile_mash.php profile_setup.php profile_styles.php \
 		  profile_water.php \
 		  rec_beerxml.php rec_duplicate.php rec_edit.php rec_export.php rec_forum.php \
--- a/www/crontasks.php	Thu May 30 23:19:43 2019 +0200
+++ b/www/crontasks.php	Wed Jun 05 20:04:26 2019 +0200
@@ -27,510 +27,6 @@
 
 
 /*
- * Automatic reduce inventory depending on the production stage.
- *  Stage 3+, primary, reduce sugars(0-mash, 1-boil), hops(0-mash, 1-fwh, 2-boil, 3-aroma, 4-whirlpool), miscs(0-starter, 1-mash, 2-boil)
- *  Stage 4+, Secondary, reduce sugars(2-fermention), yeasts(0-Primary), miscs(3-primary)
- *  Stage 5+, Tertiary, reduce yeasts(1-Secondary)
- *  Stage 6+, packaged, reduce sugars(3-lagering), hops(5-dry-hop), yeasts(2-Tertiary), miscs(4-secondary)
- *  Stage 7+, carbonatiom, reduce sugars(4-bottle), yeasts(3-Bottle), miscs(5-bottling)
- */
-$query = "SELECT * FROM products WHERE inventory_reduced < stage";
-$result = mysqli_query($connect, $query);
-while ($row = mysqli_fetch_array($result, MYSQLI_ASSOC)) {
-
-    $savethis = 0;
-
-    /*
-     * If the brew is done, reduce the used ingredients.
-     */
-    if (($row['stage'] >= 3) && ($row['inventory_reduced'] < 3)) {
-	syslog(LOG_NOTICE, "Reduce brew inventory from " . $row['code'] . " " . $row['name']);
-
-	$fermentables = json_decode($row['json_fermentables'], true);
-        for ($i = 0; $i < count($fermentables); $i++) {
-	    if ($fermentables[$i]['f_added'] <= 1) {	// Mash, Boil
-		$sql2  = "UPDATE inventory_fermentables SET inventory = inventory - " . $fermentables[$i]['f_amount'];
-                $sql2 .= " WHERE name='" . mysqli_real_escape_string($connect, $fermentables[$i]['f_name']);
-                $sql2 .= "' AND origin='" . mysqli_real_escape_string($connect, $fermentables[$i]['f_origin']);
-                $sql2 .= "' AND supplier='" . mysqli_real_escape_string($connect, $fermentables[$i]['f_supplier']);
-                $sql2 .= "' AND inventory >= " . $fermentables[$i]['f_amount'];
-                $sql2 .= " LIMIT 1;";
-                $result2 = mysqli_query($connect, $sql2);
-                $ar = mysqli_affected_rows($connect);
-		if ($ar == 1) {
-		    syslog(LOG_NOTICE, "Reduced fermentable `".$fermentables[$i]['f_name']."' from `".$fermentables[$i]['f_supplier']."' with ".$fermentables[$i]['f_amount']." kg");
-		} else if ($ar == 0) {
-		    $sql2  = "UPDATE inventory_fermentables SET inventory = 0";
-                    $sql2 .= " WHERE name='" . mysqli_real_escape_string($connect, $fermentables[$i]['f_name']);
-                    $sql2 .= "' AND origin='" . mysqli_real_escape_string($connect, $fermentables[$i]['f_origin']);
-                    $sql2 .= "' AND supplier='" . mysqli_real_escape_string($connect, $fermentables[$i]['f_supplier']);
-                    $sql2 .= "' AND inventory < " . $fermentables[$i]['f_amount'];
-                    $sql2 .= " LIMIT 1;";
-                    $result2 = mysqli_query($connect, $sql2);
-                    $ar = mysqli_affected_rows($connect);
-                    if ($ar == 1) {
-                	syslog(LOG_NOTICE, "Reduced fermentable `".$fermentables[$i]['f_name']."' from `".$fermentables[$i]['f_supplier']."' to 0 kg");
-                    } else if ($ar == 0) {
-                        syslog(LOG_NOTICE, "Reduce fermentable `".$fermentables[$i]['f_name']."' from `".$fermentables[$i]['f_supplier']."' failed");
-                    }
-                }
-	    }
-	}
-
-	$hops = json_decode($row['json_hops'], true);
-        for ($i = 0; $i < count($hops); $i++) {
-	    if ($hops[$i]['h_useat'] <= 4) { // Mash, FWH, Boil, Flameout, Whirlpool
-		$sql2  = "UPDATE inventory_hops SET inventory = inventory - " . $hops[$i]['h_amount'];
-                $sql2 .= " WHERE name='" . mysqli_real_escape_string($connect, $hops[$i]['h_name']);
-                $sql2 .= "' AND origin='" . mysqli_real_escape_string($connect, $hops[$i]['h_origin']);
-                $sql2 .= "' AND form=" . $hops[$i]['h_form'];
-                $sql2 .= " AND inventory >= " . $hops[$i]['h_amount'] . " LIMIT 1;";
-                $result2 = mysqli_query($connect, $sql2);
-                $ar = mysqli_affected_rows($connect);
-                if ($ar == 1) {
-                    syslog(LOG_NOTICE, "Reduced hop `".$hops[$i]['h_name']."' from `".$hops[$i]['h_origin']."' with ".$hops[$i]['h_amount']." kg");
-                } else if ($ar == 0) {
-                    $sql2  = "UPDATE inventory_hops SET inventory = 0";
-                    $sql2 .= " WHERE name='" . mysqli_real_escape_string($connect, $hops[$i]['h_name']);
-                    $sql2 .= "' AND origin='" . mysqli_real_escape_string($connect, $hops[$i]['h_origin']);
-                    $sql2 .= "' AND form=" . $hops[$i]['h_form'];
-                    $sql2 .= " AND inventory < " . $hops[$i]['h_amount'] . " LIMIT 1;";
-                    $result2 = mysqli_query($connect, $sql2);
-                    $ar = mysqli_affected_rows($connect);
-                    if ($ar == 1) {
-                        syslog(LOG_NOTICE, "Reduced hop `".$hops[$i]['h_name']."' from `".$hops[$i]['h_origin']."' to 0 kg");
-                    } else if ($ar == 0) {
-                        syslog(LOG_NOTICE, "Reduce hop `".$hops[$i]['h_name']."' from `".$hops[$i]['h_origin']."' failed");
-                    }
-                }
-	    }
-	}
-
-	$miscs = json_decode($row['json_miscs'], true);
-        for ($i = 0; $i < count($miscs); $i++) {
-	    if ($miscs[$i]['m_use_use'] <= 2) {	// Starter, Mash, Boil
-                $sql2  = "UPDATE inventory_miscs SET inventory = inventory - " . $miscs[$i]['m_amount'];
-                $sql2 .= " WHERE name='" . mysqli_real_escape_string($connect, $miscs[$i]['m_name']);
-                $sql2 .= "' AND inventory >= " . $miscs[$i]['m_amount'] . " LIMIT 1;";
-                $result2 = mysqli_query($connect, $sql2);
-                $ar = mysqli_affected_rows($connect);
-                if ($ar == 1) {
-                    syslog(LOG_NOTICE, "Reduced misc `".$miscs[$i]['m_name']."' with ".$miscs[$i]['m_amount']);
-                } else if ($ar == 0) {
-                    $sql2  = "UPDATE inventory_miscs SET inventory = 0";
-                    $sql2 .= " WHERE name='" . mysqli_real_escape_string($connect, $miscs[$i]['m_name']);
-                    $sql2 .= "' AND inventory < " . $miscs[$i]['m_amount'] . " LIMIT 1;";
-                    $result2 = mysqli_query($connect, $sql2);
-                    $ar = mysqli_affected_rows($connect);
-                    if ($ar == 1) {
-                        syslog(LOG_NOTICE, "Reduced misc `".$miscs[$i]['m_name']."' to 0");
-                    } else if ($ar == 0) {
-                        syslog(LOG_NOTICE, "Reduce misc `".$miscs[$i]['m_name']."' failed");
-                    }
-                }
-	    }
-	}
-
-	if ($row['w1_name'] != '') {
-            $sql2  = "UPDATE inventory_waters SET inventory = inventory - ".$row['w1_amount'];
-            $sql2 .= " WHERE name='" . mysqli_real_escape_string($connect, $row['w1_name']);
-            $sql2 .= "' AND unlimited_stock=0 AND inventory >= ".$row['w1_amount']." LIMIT 1;";
-            $result2 = mysqli_query($connect, $sql2);
-            $ar = mysqli_affected_rows($connect);
-            if ($ar == 1) {
-                syslog(LOG_NOTICE, "Reduced water `".$row['w1_name']."' with ".$row['w1_amount']." liter");
-            } else if ($ar == 0) {
-                $sql2  = "UPDATE inventory_waters SET inventory = 0";
-                $sql2 .= " WHERE name='" . mysqli_real_escape_string($connect, $row['w1_name']);
-                $sql2 .= "' AND unlimited_stock=0 AND inventory < ".$row['w1_amount']." LIMIT 1;";
-                $result2 = mysqli_query($connect, $sql2);
-                $ar = mysqli_affected_rows($connect);
-                if ($ar == 1) {
-                    syslog(LOG_NOTICE, "Reduced water `".$row['w1_name']."' to 0 liters");
-                } else {
-                    syslog(LOG_NOTICE, "Reduce water `".$row['w1_name']."' not reduced is maybe tapwater");
-                }
-            }
-        }
-	if ($row['w2_name'] != '') {
-            $sql2  = "UPDATE inventory_waters SET inventory = inventory - ".$row['w2_amount'];
-            $sql2 .= " WHERE name='" . mysqli_real_escape_string($connect, $row['w2_name']);
-            $sql2 .= "' AND unlimited_stock=0 AND inventory >= ".$row['w2_amount']." LIMIT 1;";
-            $result2 = mysqli_query($connect, $sql2);
-            $ar = mysqli_affected_rows($connect);
-            if ($ar == 1) {
-                syslog(LOG_NOTICE, "Reduced water `".$row['w2_name']."' with ".$row['w2_amount']." liter");
-            } else if ($ar == 0) {
-                $sql2  = "UPDATE inventory_waters SET inventory = 0";
-                $sql2 .= " WHERE name='" . mysqli_real_escape_string($connect, $row['w2_name']);
-                $sql2 .= "' AND unlimited_stock=0 AND inventory < ".$row['w2_amount']." LIMIT 1;";
-                $result2 = mysqli_query($connect, $sql2);
-                $ar = mysqli_affected_rows($connect);
-                if ($ar == 1) {
-                    syslog(LOG_NOTICE, "Reduced water `".$row['w2_name']."' to 0 liters");
-		} else {
-                    syslog(LOG_NOTICE, "Reduce water `".$row['w2_name']."' failed");
-                }
-            }
-        }
-
-	$row['inventory_reduced'] = '3';
-	$savethis = 1;
-    }
-
-
-    /*
-     * After the Primary fermentation
-     */
-    if (($row['stage'] >= 4) && ($row['inventory_reduced'] < 4)) {
-        syslog(LOG_NOTICE, "Reduce Primary inventory from " . $row['code'] . " " . $row['name']);
-
-	$fermentables = json_decode($row['json_fermentables'], true);
-        for ($i = 0; $i < count($fermentables); $i++) {
-            if ($fermentables[$i]['f_added'] == 2) {    // Fermentation
-                $sql2  = "UPDATE inventory_fermentables SET inventory = inventory - " . $fermentables[$i]['f_amount'];
-                $sql2 .= " WHERE name='" . mysqli_real_escape_string($connect, $fermentables[$i]['f_name']);
-                $sql2 .= "' AND origin='" . mysqli_real_escape_string($connect, $fermentables[$i]['f_origin']);
-                $sql2 .= "' AND supplier='" . mysqli_real_escape_string($connect, $fermentables[$i]['f_supplier']);
-                $sql2 .= "' AND inventory >= " . $fermentables[$i]['f_amount'];
-                $sql2 .= " LIMIT 1;";
-                $result2 = mysqli_query($connect, $sql2);
-                $ar = mysqli_affected_rows($connect);
-                if ($ar == 1) {
-                    syslog(LOG_NOTICE, "Reduced fermentable `".$fermentables[$i]['f_name']."' from `".$fermentables[$i]['f_supplier']."' with ".$fermentables[$i]['f_amount']." kg");
-                } else if ($ar == 0) {
-                    $sql2  = "UPDATE inventory_fermentables SET inventory = 0";
-                    $sql2 .= " WHERE name='" . mysqli_real_escape_string($connect, $fermentables[$i]['f_name']);
-                    $sql2 .= "' AND origin='" . mysqli_real_escape_string($connect, $fermentables[$i]['f_origin']);
-                    $sql2 .= "' AND supplier='" . mysqli_real_escape_string($connect, $fermentables[$i]['f_supplier']);
-                    $sql2 .= "' AND inventory < " . $fermentables[$i]['f_amount'];
-                    $sql2 .= " LIMIT 1;";
-                    $result2 = mysqli_query($connect, $sql2);
-                    $ar = mysqli_affected_rows($connect);
-                    if ($ar == 1) {
-                        syslog(LOG_NOTICE, "Reduced fermentable `".$fermentables[$i]['f_name']."' from `".$fermentables[$i]['f_supplier']."' to 0 kg");
-                    } else if ($ar == 0) {
-                        syslog(LOG_NOTICE, "Reduce fermentable `".$fermentables[$i]['f_name']."' from `".$fermentables[$i]['f_supplier']."' failed");
-                    }
-                }
-            }
-        }
-
-	$miscs = json_decode($row['json_miscs'], true);
-        for ($i = 0; $i < count($miscs); $i++) {
-            if ($miscs[$i]['m_use_use'] == 3) { // Fermentation
-                $sql2  = "UPDATE inventory_miscs SET inventory = inventory - " . $miscs[$i]['m_amount'];
-                $sql2 .= " WHERE name='" . mysqli_real_escape_string($connect, $miscs[$i]['m_name']);
-                $sql2 .= "' AND inventory >= " . $miscs[$i]['m_amount'] . " LIMIT 1;";
-                $result2 = mysqli_query($connect, $sql2);
-                $ar = mysqli_affected_rows($connect);
-                if ($ar == 1) {
-                    syslog(LOG_NOTICE, "Reduced misc `".$miscs[$i]['m_name']."' with ".$miscs[$i]['m_amount']);
-                } else if ($ar == 0) {
-                    $sql2  = "UPDATE inventory_miscs SET inventory = 0";
-                    $sql2 .= " WHERE name='" . mysqli_real_escape_string($connect, $miscs[$i]['m_name']);
-                    $sql2 .= "' AND inventory < " . $miscs[$i]['m_amount'] . " LIMIT 1;";
-                    $result2 = mysqli_query($connect, $sql2);
-                    $ar = mysqli_affected_rows($connect);
-                    if ($ar == 1) {
-                        syslog(LOG_NOTICE, "Reduced misc `".$miscs[$i]['m_name']."' to 0");
-                    } else if ($ar == 0) {
-                        syslog(LOG_NOTICE, "Reduce misc `".$miscs[$i]['m_name']."' failed");
-                    }
-                }
-            }
-        }
-
-	$yeasts = json_decode($row['json_yeasts'], true);
-        for ($i = 0; $i < count($yeasts); $i++) {
-	    if ($yeasts[$i]['y_use'] == 0) {	// Primary
-		$sql2  = "UPDATE inventory_yeasts SET inventory = inventory - " . $yeasts[$i]['y_amount'];
-                $sql2 .= " WHERE name='" . mysqli_real_escape_string($connect, $yeasts[$i]['y_name']);
-                $sql2 .= "' AND laboratory='" . mysqli_real_escape_string($connect, $yeasts[$i]['y_laboratory']);
-                $sql2 .= "' AND product_id='" . mysqli_real_escape_string($connect, $yeasts[$i]['y_product_id']);
-                $sql2 .= "' AND form=" . $yeasts[$i]['y_form'];
-                $sql2 .= " AND inventory >= " . $yeasts[$i]['y_amount'] . " LIMIT 1;";
-                $result2 = mysqli_query($connect, $sql2);
-                $ar = mysqli_affected_rows($connect);
-                if ($ar == 1) {
-                    syslog(LOG_NOTICE, "Reduced yeast `".$yeasts[$i]['y_product_id'].' '.$yeasts[$i]['y_name']."' from `".$yeasts[$i]['y_laboratory']."' with ".$yeasts[$i]['y_amount']);
-                } else if ($ar == 0) {
-                    $sql2  = "UPDATE inventory_yeasts SET inventory = 0";
-                    $sql2 .= " WHERE name='" . mysqli_real_escape_string($connect, $yeasts[$i]['y_name']);
-                    $sql2 .= "' AND laboratory='" . mysqli_real_escape_string($connect, $yeasts[$i]['y_laboratory']);
-                    $sql2 .= "' AND product_id='" . mysqli_real_escape_string($connect, $yeasts[$i]['y_product_id']);
-                    $sql2 .= "' AND form=" . $yeasts[$i]['y_form'];
-                    $sql2 .= " AND inventory < " . $yeasts[$i]['y_amount'] . " LIMIT 1;";
-                    $result2 = mysqli_query($connect, $sql2);
-                    $ar = mysqli_affected_rows($connect);
-                    if ($ar == 1) {
-                        syslog(LOG_NOTICE, "Reduced yeast `".$yeasts[$i]['y_product_id'].' '.$yeasts[$i]['y_name']."' from `".$yeasts[$i]['y_laboratory']."' to 0");
-                    } else if ($ar == 0) {
-                        syslog(LOG_NOTICE, "Reduce yeast `".$yeasts[$i]['y_product_id'].' '.$yeasts[$i]['y_name']."' from `".$yeasts[$i]['y_laboratory']."' failed");
-                    }
-                }
-	    }
-	}
-
-        $row['inventory_reduced'] = '4';
-	$savethis = 1;
-    }
-
-
-    /*
-     * After the Seconday fermentation
-     */
-    if (($row['stage'] >= 5) && ($row['inventory_reduced'] < 5)) {
-        syslog(LOG_NOTICE, "Reduce Secondary inventory from " . $row['code'] . " " . $row['name']);
-
-	$yeasts = json_decode($row['json_yeasts'], true);
-        for ($i = 0; $i < count($yeasts); $i++) {
-            if ($yeasts[$i]['y_use'] == 1) {    // Secondary
-                $sql2  = "UPDATE inventory_yeasts SET inventory = inventory - " . $yeasts[$i]['y_amount'];
-                $sql2 .= " WHERE name='" . mysqli_real_escape_string($connect, $yeasts[$i]['y_name']);
-                $sql2 .= "' AND laboratory='" . mysqli_real_escape_string($connect, $yeasts[$i]['y_laboratory']);
-                $sql2 .= "' AND product_id='" . mysqli_real_escape_string($connect, $yeasts[$i]['y_product_id']);
-                $sql2 .= "' AND form=" . $yeasts[$i]['y_form'];
-                $sql2 .= " AND inventory >= " . $yeasts[$i]['y_amount'] . " LIMIT 1;";
-                $result2 = mysqli_query($connect, $sql2);
-                $ar = mysqli_affected_rows($connect);
-                if ($ar == 1) {
-                    syslog(LOG_NOTICE, "Reduced yeast `".$yeasts[$i]['y_product_id'].' '.$yeasts[$i]['y_name']."' from `".$yeasts[$i]['y_laboratory']."' with ".$yeasts[$i]['y_amount']);
-                } else if ($ar == 0) {
-                    $sql2  = "UPDATE inventory_yeasts SET inventory = 0";
-                    $sql2 .= " WHERE name='" . mysqli_real_escape_string($connect, $yeasts[$i]['y_name']);
-                    $sql2 .= "' AND laboratory='" . mysqli_real_escape_string($connect, $yeasts[$i]['y_laboratory']);
-                    $sql2 .= "' AND product_id='" . mysqli_real_escape_string($connect, $yeasts[$i]['y_product_id']);
-                    $sql2 .= "' AND form=" . $yeasts[$i]['y_form'];
-                    $sql2 .= " AND inventory < " . $yeasts[$i]['y_amount'] . " LIMIT 1;";
-                    $result2 = mysqli_query($connect, $sql2);
-                    $ar = mysqli_affected_rows($connect);
-                    if ($ar == 1) {
-                        syslog(LOG_NOTICE, "Reduced yeast `".$yeasts[$i]['y_product_id'].' '.$yeasts[$i]['y_name']."' from `".$yeasts[$i]['y_laboratory']."' to 0");
-                    } else if ($ar == 0) {
-                        syslog(LOG_NOTICE, "Reduce yeast `".$yeasts[$i]['y_product_id'].' '.$yeasts[$i]['y_name']."' from `".$yeasts[$i]['y_laboratory']."' failed");
-                    }
-                }
-            }
-        }
-        $row['inventory_reduced'] = '5';
-	$savethis = 1;
-    }
-
-
-    /*
-     * After the Tertiary fermentation
-     */
-    if (($row['stage'] >= 6) && ($row['inventory_reduced'] < 6)) {
-        syslog(LOG_NOTICE, "Reduce Tertiary inventory from " . $row['code'] . " " . $row['name']);
-
-        $fermentables = json_decode($row['json_fermentables'], true);
-        for ($i = 0; $i < count($fermentables); $i++) {
-            if ($fermentables[$i]['f_added'] == 3) {    // Lagering
-                $sql2  = "UPDATE inventory_fermentables SET inventory = inventory - " . $fermentables[$i]['f_amount'];
-                $sql2 .= " WHERE name='" . mysqli_real_escape_string($connect, $fermentables[$i]['f_name']);
-                $sql2 .= "' AND origin='" . mysqli_real_escape_string($connect, $fermentables[$i]['f_origin']);
-                $sql2 .= "' AND supplier='" . mysqli_real_escape_string($connect, $fermentables[$i]['f_supplier']);
-                $sql2 .= "' AND inventory >= " . $fermentables[$i]['f_amount'];
-                $sql2 .= " LIMIT 1;";
-                $result2 = mysqli_query($connect, $sql2);
-                $ar = mysqli_affected_rows($connect);
-                if ($ar == 1) {
-                    syslog(LOG_NOTICE, "Reduced fermentable `".$fermentables[$i]['f_name']."' from `".$fermentables[$i]['f_supplier']."' with ".$fermentables[$i]['f_amount']." kg");
-                } else if ($ar == 0) {
-                    $sql2  = "UPDATE inventory_fermentables SET inventory = 0";
-                    $sql2 .= " WHERE name='" . mysqli_real_escape_string($connect, $fermentables[$i]['f_name']);
-                    $sql2 .= "' AND origin='" . mysqli_real_escape_string($connect, $fermentables[$i]['f_origin']);
-                    $sql2 .= "' AND supplier='" . mysqli_real_escape_string($connect, $fermentables[$i]['f_supplier']);
-                    $sql2 .= "' AND inventory < " . $fermentables[$i]['f_amount'];
-                    $sql2 .= " LIMIT 1;";
-                    $result2 = mysqli_query($connect, $sql2);
-                    $ar = mysqli_affected_rows($connect);
-                    if ($ar == 1) {
-                        syslog(LOG_NOTICE, "Reduced fermentable `".$fermentables[$i]['f_name']."' from `".$fermentables[$i]['f_supplier']."' to 0 kg");
-                    } else if ($ar == 0) {
-                        syslog(LOG_NOTICE, "Reduce fermentable `".$fermentables[$i]['f_name']."' from `".$fermentables[$i]['f_supplier']."' failed");
-                    }
-                }
-            }
-        }
-
-	$hops = json_decode($row['json_hops'], true);
-        for ($i = 0; $i < count($hops); $i++) {
-            if ($hops[$i]['h_useat'] == 5) { // Dry hop
-                $sql2  = "UPDATE inventory_hops SET inventory = inventory - " . $hops[$i]['h_amount'];
-                $sql2 .= " WHERE name='" . mysqli_real_escape_string($connect, $hops[$i]['h_name']);
-                $sql2 .= "' AND origin='" . mysqli_real_escape_string($connect, $hops[$i]['h_origin']);
-                $sql2 .= "' AND form=" . $hops[$i]['h_form'];
-                $sql2 .= " AND inventory >= " . $hops[$i]['h_amount'] . " LIMIT 1;";
-                $result2 = mysqli_query($connect, $sql2);
-                $ar = mysqli_affected_rows($connect);
-                if ($ar == 1) {
-                    syslog(LOG_NOTICE, "Reduced hop `".$hops[$i]['h_name']."' from `".$hops[$i]['h_origin']."' with ".$hops[$i]['h_amount']." kg");
-                } else if ($ar == 0) {
-                    $sql2  = "UPDATE inventory_hops SET inventory = 0";
-                    $sql2 .= " WHERE name='" . mysqli_real_escape_string($connect, $hops[$i]['h_name']);
-                    $sql2 .= "' AND origin='" . mysqli_real_escape_string($connect, $hops[$i]['h_origin']);
-                    $sql2 .= "' AND form=" . $hops[$i]['h_form'];
-                    $sql2 .= " AND inventory < " . $hops[$i]['h_amount'] . " LIMIT 1;";
-                    $result2 = mysqli_query($connect, $sql2);
-                    $ar = mysqli_affected_rows($connect);
-                    if ($ar == 1) {
-                        syslog(LOG_NOTICE, "Reduced hop `".$hops[$i]['h_name']."' from `".$hops[$i]['h_origin']."' to 0 kg");
-                    } else if ($ar == 0) {
-                        syslog(LOG_NOTICE, "Reduce hop `".$hops[$i]['h_name']."' from `".$hops[$i]['h_origin']."' failed");
-                    }
-                }
-            }
-        }
-
-	$yeasts = json_decode($row['json_yeasts'], true);
-        for ($i = 0; $i < count($yeasts); $i++) {
-            if ($yeasts[$i]['y_use'] == 2) {    // Tertiary
-                $sql2  = "UPDATE inventory_yeasts SET inventory = inventory - " . $yeasts[$i]['y_amount'];
-                $sql2 .= " WHERE name='" . mysqli_real_escape_string($connect, $yeasts[$i]['y_name']);
-                $sql2 .= "' AND laboratory='" . mysqli_real_escape_string($connect, $yeasts[$i]['y_laboratory']);
-                $sql2 .= "' AND product_id='" . mysqli_real_escape_string($connect, $yeasts[$i]['y_product_id']);
-                $sql2 .= "' AND form=" . $yeasts[$i]['y_form'];
-                $sql2 .= " AND inventory >= " . $yeasts[$i]['y_amount'] . " LIMIT 1;";
-                $result2 = mysqli_query($connect, $sql2);
-                $ar = mysqli_affected_rows($connect);
-                if ($ar == 1) {
-                    syslog(LOG_NOTICE, "Reduced yeast `".$yeasts[$i]['y_product_id'].' '.$yeasts[$i]['y_name']."' from `".$yeasts[$i]['y_laboratory']."' with ".$yeasts[$i]['y_amount']);
-                } else if ($ar == 0) {
-                    $sql2  = "UPDATE inventory_yeasts SET inventory = 0";
-                    $sql2 .= " WHERE name='" . mysqli_real_escape_string($connect, $yeasts[$i]['y_name']);
-                    $sql2 .= "' AND laboratory='" . mysqli_real_escape_string($connect, $yeasts[$i]['y_laboratory']);
-                    $sql2 .= "' AND product_id='" . mysqli_real_escape_string($connect, $yeasts[$i]['y_product_id']);
-                    $sql2 .= "' AND form=" . $yeasts[$i]['y_form'];
-                    $sql2 .= " AND inventory < " . $yeasts[$i]['y_amount'] . " LIMIT 1;";
-                    $result2 = mysqli_query($connect, $sql2);
-                    $ar = mysqli_affected_rows($connect);
-                    if ($ar == 1) {
-                        syslog(LOG_NOTICE, "Reduced yeast `".$yeasts[$i]['y_product_id'].' '.$yeasts[$i]['y_name']."' from `".$yeasts[$i]['y_laboratory']."' to 0");
-                    } else if ($ar == 0) {
-                        syslog(LOG_NOTICE, "Reduce yeast `".$yeasts[$i]['y_product_id'].' '.$yeasts[$i]['y_name']."' from `".$yeasts[$i]['y_laboratory']."' failed");
-                    }
-                }
-            }
-        }
-
-	$miscs = json_decode($row['json_miscs'], true);
-        for ($i = 0; $i < count($miscs); $i++) {
-            if ($miscs[$i]['m_use_use'] == 4) { // Secondary or Tertiary
-                $sql2  = "UPDATE inventory_miscs SET inventory = inventory - " . $miscs[$i]['m_amount'];
-                $sql2 .= " WHERE name='" . mysqli_real_escape_string($connect, $miscs[$i]['m_name']);
-                $sql2 .= "' AND inventory >= " . $miscs[$i]['m_amount'] . " LIMIT 1;";
-                $result2 = mysqli_query($connect, $sql2);
-                $ar = mysqli_affected_rows($connect);
-                if ($ar == 1) {
-                    syslog(LOG_NOTICE, "Reduced misc `".$miscs[$i]['m_name']."' with ".$miscs[$i]['m_amount']);
-                } else if ($ar == 0) {
-                    $sql2  = "UPDATE inventory_miscs SET inventory = 0";
-                    $sql2 .= " WHERE name='" . mysqli_real_escape_string($connect, $miscs[$i]['m_name']);
-                    $sql2 .= "' AND inventory < " . $miscs[$i]['m_amount'] . " LIMIT 1;";
-                    $result2 = mysqli_query($connect, $sql2);
-                    $ar = mysqli_affected_rows($connect);
-                    if ($ar == 1) {
-                        syslog(LOG_NOTICE, "Reduced misc `".$miscs[$i]['m_name']."' to 0");
-                    } else if ($ar == 0) {
-                        syslog(LOG_NOTICE, "Reduce misc `".$miscs[$i]['m_name']."' failed");
-                    }
-                }
-            }
-        }
-
-        $row['inventory_reduced'] = '6';
-	$savethis = 1;
-    }
-
-
-    /*
-     * After packaging
-     *  reduce sugars(4-bottle), yeasts(3-Bottle), miscs(5-bottling)
-     */
-    if (($row['stage'] >= 7) && ($row['inventory_reduced'] < 7)) {
-        syslog(LOG_NOTICE, "Reduce Packaging inventory from " . $row['code'] . " " . $row['name']);
-
-	// Bottle sugar, how?
-
-	$yeasts = json_decode($row['json_yeasts'], true);
-        for ($i = 0; $i < count($yeasts); $i++) {
-            if ($yeasts[$i]['y_use'] == 3) {    // Bottle
-                $sql2  = "UPDATE inventory_yeasts SET inventory = inventory - " . $yeasts[$i]['y_amount'];
-                $sql2 .= " WHERE name='" . mysqli_real_escape_string($connect, $yeasts[$i]['y_name']);
-                $sql2 .= "' AND laboratory='" . mysqli_real_escape_string($connect, $yeasts[$i]['y_laboratory']);
-                $sql2 .= "' AND product_id='" . mysqli_real_escape_string($connect, $yeasts[$i]['y_product_id']);
-                $sql2 .= "' AND form=" . $yeasts[$i]['y_form'];
-                $sql2 .= " AND inventory >= " . $yeasts[$i]['y_amount'] . " LIMIT 1;";
-                $result2 = mysqli_query($connect, $sql2);
-                $ar = mysqli_affected_rows($connect);
-                if ($ar == 1) {
-                    syslog(LOG_NOTICE, "Reduced yeast `".$yeasts[$i]['y_product_id'].' '.$yeasts[$i]['y_name']."' from `".$yeasts[$i]['y_laboratory']."' with ".$yeasts[$i]['y_amount']);
-                } else if ($ar == 0) {
-                    $sql2  = "UPDATE inventory_yeasts SET inventory = 0";
-                    $sql2 .= " WHERE name='" . mysqli_real_escape_string($connect, $yeasts[$i]['y_name']);
-                    $sql2 .= "' AND laboratory='" . mysqli_real_escape_string($connect, $yeasts[$i]['y_laboratory']);
-                    $sql2 .= "' AND product_id='" . mysqli_real_escape_string($connect, $yeasts[$i]['y_product_id']);
-                    $sql2 .= "' AND form=" . $yeasts[$i]['y_form'];
-                    $sql2 .= " AND inventory < " . $yeasts[$i]['y_amount'] . " LIMIT 1;";
-                    $result2 = mysqli_query($connect, $sql2);
-                    $ar = mysqli_affected_rows($connect);
-                    if ($ar == 1) {
-                        syslog(LOG_NOTICE, "Reduced yeast `".$yeasts[$i]['y_product_id'].' '.$yeasts[$i]['y_name']."' from `".$yeasts[$i]['y_laboratory']."' to 0");
-                    } else if ($ar == 0) {
-                        syslog(LOG_NOTICE, "Reduce yeast `".$yeasts[$i]['y_product_id'].' '.$yeasts[$i]['y_name']."' from `".$yeasts[$i]['y_laboratory']."' failed");
-                    }
-                }
-            }
-        }
-
-	$miscs = json_decode($row['json_miscs'], true);
-        for ($i = 0; $i < count($miscs); $i++) {
-            if ($miscs[$i]['m_use_use'] == 5) { // Bottle
-                $sql2  = "UPDATE inventory_miscs SET inventory = inventory - " . $miscs[$i]['m_amount'];
-                $sql2 .= " WHERE name='" . mysqli_real_escape_string($connect, $miscs[$i]['m_name']);
-                $sql2 .= "' AND inventory >= " . $miscs[$i]['m_amount'] . " LIMIT 1;";
-                $result2 = mysqli_query($connect, $sql2);
-                $ar = mysqli_affected_rows($connect);
-                if ($ar == 1) {
-                    syslog(LOG_NOTICE, "Reduced misc `".$miscs[$i]['m_name']."' with ".$miscs[$i]['m_amount']);
-                } else if ($ar == 0) {
-                    $sql2  = "UPDATE inventory_miscs SET inventory = 0";
-                    $sql2 .= " WHERE name='" . mysqli_real_escape_string($connect, $miscs[$i]['m_name']);
-                    $sql2 .= "' AND inventory < " . $miscs[$i]['m_amount'] . " LIMIT 1;";
-                    $result2 = mysqli_query($connect, $sql2);
-                    $ar = mysqli_affected_rows($connect);
-                    if ($ar == 1) {
-                        syslog(LOG_NOTICE, "Reduced misc `".$miscs[$i]['m_name']."' to 0");
-                    } else if ($ar == 0) {
-                        syslog(LOG_NOTICE, "Reduce misc `".$miscs[$i]['m_name']."' failed");
-                    }
-                }
-            }
-        }
-
-        $row['inventory_reduced'] = $row['stage'];
-	$savethis = 1;
-    }
-
-    /*
-     * Save only if something was reduced.
-     */
-    if ($savethis == 1) {
-    	$sql2 = "UPDATE products SET inventory_reduced=".$row['inventory_reduced']." WHERE uuid = '" . $row['uuid'] . "';";
-    	syslog(LOG_NOTICE, $sql2);
-    	$result2 = mysqli_query($connect, $sql2);
-    	$ar = mysqli_affected_rows($connect);
-	if ($ar != 1) {
-    	    syslog(LOG_NOTICE, $sql2." error, affected rows: ".$ar);
-	}
-    }
-}
-
-
-
-/*
  * Update stages after packaging depending on the age.
  */
 $query = "UPDATE products SET stage=7 WHERE stage = 6 AND DATEDIFF(CURDATE(), package_date) > 0";
--- a/www/includes/db_product.php	Thu May 30 23:19:43 2019 +0200
+++ b/www/includes/db_product.php	Wed Jun 05 20:04:26 2019 +0200
@@ -76,12 +76,15 @@
 		$sql .= "', brew_date_start='" . $_POST['brew_date_start'] . "'";
 	$sql .=  ", brew_mash_ph='" . $_POST['brew_mash_ph'];
 	$sql .= "', brew_mash_sg='" . $_POST['brew_mash_sg'];
+	$sql .= "', brew_mash_efficiency='" . $_POST['brew_mash_efficiency'];
 	$sql .= "', brew_sparge_temperature='" . $_POST['brew_sparge_temperature'];
 	$sql .= "', brew_sparge_volume='" . $_POST['brew_sparge_volume'];
+	$sql .= "', brew_sparge_est='" . $_POST['brew_sparge_est'];
 	$sql .= "', brew_sparge_ph='" . $_POST['brew_sparge_ph'];
 	$sql .= "', brew_preboil_volume='" . $_POST['brew_preboil_volume'];
 	$sql .= "', brew_preboil_sg='" . $_POST['brew_preboil_sg'];
 	$sql .= "', brew_preboil_ph='" . $_POST['brew_preboil_ph'];
+	$sql .= "', brew_preboil_efficiency='" . $_POST['brew_preboil_efficiency'];
 	$sql .= "', brew_aboil_volume='" . $_POST['brew_aboil_volume'];
 	$sql .= "', brew_aboil_sg='" . $_POST['brew_aboil_sg'];
 	$sql .= "', brew_aboil_ph='" . $_POST['brew_aboil_ph'];
@@ -220,6 +223,21 @@
 		$sql .= "', w2_ph='" . $_POST['w2_ph'];
 		$sql .= "', w2_cost='" . $_POST['w2_cost'];
 	}
+	$sql .= "', wg_amount='" . $_POST['wg_amount'];
+        $sql .= "', wg_calcium='" . $_POST['wg_calcium'];
+        $sql .= "', wg_sulfate='" . $_POST['wg_sulfate'];
+        $sql .= "', wg_chloride='" . $_POST['wg_chloride'];
+        $sql .= "', wg_sodium='" . $_POST['wg_sodium'];
+        $sql .= "', wg_magnesium='" . $_POST['wg_magnesium'];
+        $sql .= "', wg_total_alkalinity='" . $_POST['wg_total_alkalinity'];
+        $sql .= "', wg_ph='" . $_POST['wg_ph'];
+        $sql .= "', wb_calcium='" . $_POST['wb_calcium'];
+        $sql .= "', wb_sulfate='" . $_POST['wb_sulfate'];
+        $sql .= "', wb_chloride='" . $_POST['wb_chloride'];
+        $sql .= "', wb_sodium='" . $_POST['wb_sodium'];
+        $sql .= "', wb_magnesium='" . $_POST['wb_magnesium'];
+        $sql .= "', wb_total_alkalinity='" . $_POST['wb_total_alkalinity'];
+        $sql .= "', wb_ph='" . $_POST['wb_ph'];
 	$sql .= "', wa_acid_name='" . $_POST['wa_acid_name'];
 	$sql .= "', wa_acid_perc='" . $_POST['wa_acid_perc'];
 	$sql .= "', wa_base_name='" . $_POST['wa_base_name'];
@@ -240,12 +258,23 @@
 		$sql .= "', prop4_type='" . $_POST['prop4_type'];
 		$sql .= "', prop4_volume='" . $_POST['prop4_volume'];
 	}
-	syslog(LOG_NOTICE, $sql);
+//	syslog(LOG_NOTICE, $sql);
 
 	$fermentables = '[';
 	$comma = FALSE;
 	if (isset($_POST['fermentables'])) {
 		$array = $_POST['fermentables'];
+		// Sort the array
+		$added = array();
+		$amount = array();
+		for ($i = 0; $i < count($array); $i++) {
+			$added[] = $array[$i]['f_added'];
+			$amount[] = $array[$i]['f_amount'];
+		}
+		array_multisort($added, SORT_ASC, SORT_NUMERIC, 
+			$amount, SORT_DESC, SORT_NUMERIC,
+			$array);
+		// Write the sorted array.
 		foreach($array as $key => $item){
 			/*
 			 * Manual encode to json.
@@ -286,6 +315,20 @@
 	$comma = FALSE;
 	if (isset($_POST['hops'])) {
 		$array = $_POST['hops'];
+		// Sort the array
+		$useat = array();
+        	$time = array();
+		$amount = array();
+		for ($i = 0; $i < count($array); $i++) {
+	  		$useat[] = $array[$i]['h_useat'];
+	  		$time[] = $array[$i]['h_time'];
+			$amount[] = $array[$i]['h_amount'];
+		}
+		array_multisort($useat, SORT_ASC, SORT_NUMERIC, 
+				$time, SORT_DESC, SORT_NUMERIC,
+				$amount, SORT_DESC, SORT_NUMERIC,
+				$array);
+		// Write the sorted array.
 		foreach($array as $key => $item){
 			if ($comma)
 				$hops .= ',';
@@ -317,6 +360,20 @@
 	$comma = FALSE;
 	if (isset($_POST['miscs'])) {
 		$array = $_POST['miscs'];
+		// Sort the array
+                $use = array();
+                $type = array();
+		$amount = array();
+                for ($i = 0; $i < count($array); $i++) {
+                        $use[] = $array[$i]['m_use_use'];
+                        $type[] = $array[$i]['m_type'];
+			$amount[] = $array[$i]['m_amount'];
+                }
+                array_multisort($use, SORT_ASC, SORT_NUMERIC,
+                        $type, SORT_ASC, SORT_NUMERIC,
+			$amount, SORT_DESC, SORT_NUMERIC,
+                        $array);
+                // Write the sorted array.
 		foreach($array as $key => $item){
 			if ($comma)
 				$miscs .= ',';
@@ -339,6 +396,17 @@
 	$comma = FALSE;
 	if (isset($_POST['yeasts'])) {
 		$array = $_POST['yeasts'];
+		// Sort the array
+                $use = array();
+                $amount = array();
+                for ($i = 0; $i < count($array); $i++) {
+                        $use[] = $array[$i]['y_use'];
+                        $amount[] = $array[$i]['y_amount'];
+                }
+                array_multisort($use, SORT_ASC, SORT_NUMERIC,
+                        $amount, SORT_DESC, SORT_NUMERIC,
+                        $array);
+                // Write the sorted array.
 		foreach($array as $key => $item){
 			if ($comma)
 				$yeasts .= ',';
@@ -369,6 +437,13 @@
 	$comma = FALSE;
 	if (isset($_POST['mashs'])) {
 		$array = $_POST['mashs'];
+		// Sort the array
+                $temp = array();
+                for ($i = 0; $i < count($array); $i++) {
+                        $temp[] = $array[$i]['step_temp'];
+                }
+                array_multisort($temp, SORT_ASC, SORT_NUMERIC, $array);
+                // Write the sorted array.
 		foreach($array as $key => $item){
 			if ($comma)
 				$mashs .= ',';
@@ -403,6 +478,7 @@
 	} else {
 		if (isset($_POST['update'])) {
 			syslog(LOG_NOTICE, "db_product: updated record ".$_POST['record']);
+			inventory_reduce();
 		} else {
 			$lastid = mysqli_insert_id($connect);
 			syslog(LOG_NOTICE, "db_product: inserted record ".$lastid);
@@ -596,12 +672,15 @@
 		$brew .= ',"brew_date_start":"' . $row['brew_date_start'];
 		$brew .= '","brew_mash_ph":' . floatval($row['brew_mash_ph']);
 		$brew .= ',"brew_mash_sg":' . floatval($row['brew_mash_sg']);
+		$brew .= ',"brew_mash_efficiency":' . floatval($row['brew_mash_efficiency']);
 		$brew .= ',"brew_sparge_temperature":' . floatval($row['brew_sparge_temperature']);
 		$brew .= ',"brew_sparge_volume":' . floatval($row['brew_sparge_volume']);
+		$brew .= ',"brew_sparge_est":' . floatval($row['brew_sparge_est']);
 		$brew .= ',"brew_sparge_ph":' . floatval($row['brew_sparge_ph']);
 		$brew .= ',"brew_preboil_volume":' . floatval($row['brew_preboil_volume']);
 		$brew .= ',"brew_preboil_sg":' . floatval($row['brew_preboil_sg']);
 		$brew .= ',"brew_preboil_ph":' . floatval($row['brew_preboil_ph']);
+		$brew .= ',"brew_preboil_efficiency":' . floatval($row['brew_preboil_efficiency']);
 		$brew .= ',"brew_aboil_volume":' . floatval($row['brew_aboil_volume']);
 		$brew .= ',"brew_aboil_sg":' . floatval($row['brew_aboil_sg']);
 		$brew .= ',"brew_aboil_ph":' . floatval($row['brew_aboil_ph']);
@@ -717,6 +796,21 @@
 		$brew .= ',"w2_total_alkalinity":' . floatval($row['w2_total_alkalinity']);
 		$brew .= ',"w2_ph":' . floatval($row['w2_ph']);
 		$brew .= ',"w2_cost":' . floatval($row['w2_cost']);
+		$brew .= ',"wg_amount":' . floatval($row['wg_amount']);
+                $brew .= ',"wg_calcium":' . floatval($row['wg_calcium']);
+                $brew .= ',"wg_sulfate":' . floatval($row['wg_sulfate']);
+                $brew .= ',"wg_chloride":' . floatval($row['wg_chloride']);
+                $brew .= ',"wg_sodium":' . floatval($row['wg_sodium']);
+                $brew .= ',"wg_magnesium":' . floatval($row['wg_magnesium']);
+                $brew .= ',"wg_total_alkalinity":' . floatval($row['wg_total_alkalinity']);
+                $brew .= ',"wg_ph":' . floatval($row['wg_ph']);
+                $brew .= ',"wb_calcium":' . floatval($row['wb_calcium']);
+                $brew .= ',"wb_sulfate":' . floatval($row['wb_sulfate']);
+                $brew .= ',"wb_chloride":' . floatval($row['wb_chloride']);
+                $brew .= ',"wb_sodium":' . floatval($row['wb_sodium']);
+                $brew .= ',"wb_magnesium":' . floatval($row['wb_magnesium']);
+                $brew .= ',"wb_total_alkalinity":' . floatval($row['wb_total_alkalinity']);
+                $brew .= ',"wb_ph":' . floatval($row['wb_ph']);
 		$brew .= ',"wa_acid_name":' . $row['wa_acid_name'];
 		$brew .= ',"wa_acid_perc":' . $row['wa_acid_perc'];
 		$brew .= ',"wa_base_name":' . $row['wa_base_name'];
@@ -825,4 +919,384 @@
 	header("Content-type: application/json");
 	echo $brews;
 }
+
+
+
+function reduce_fermentables($item) {
+
+	global $connect;
+
+	$amount = round($item['f_amount'] * 1000) / 1000;
+        $sql2  = "UPDATE inventory_fermentables SET inventory = inventory - " . $amount;
+        $sql2 .= " WHERE name='" . mysqli_real_escape_string($connect, $item['f_name']);
+        $sql2 .= "' AND origin='" . mysqli_real_escape_string($connect, $item['f_origin']);
+        $sql2 .= "' AND supplier='" . mysqli_real_escape_string($connect, $item['f_supplier']);
+        $sql2 .= "' AND inventory >= " . $amount;
+        $sql2 .= " LIMIT 1;";
+        $result2 = mysqli_query($connect, $sql2);
+        $ar = mysqli_affected_rows($connect);
+        if ($ar == 1) {
+         	syslog(LOG_NOTICE, "Reduced fermentable `".$item['f_name']."' from `".$item['f_supplier']."' with ".$amount." kg");
+        } else if ($ar == 0) {
+                $sql2  = "UPDATE inventory_fermentables SET inventory = 0";
+                $sql2 .= " WHERE name='" . mysqli_real_escape_string($connect, $item['f_name']);
+                $sql2 .= "' AND origin='" . mysqli_real_escape_string($connect, $item['f_origin']);
+                $sql2 .= "' AND supplier='" . mysqli_real_escape_string($connect, $item['f_supplier']);
+                $sql2 .= "' AND inventory < " . $amount;
+                $sql2 .= " LIMIT 1;";
+                $result2 = mysqli_query($connect, $sql2);
+                $ar = mysqli_affected_rows($connect);
+                if ($ar == 1) {
+                        syslog(LOG_NOTICE, "Reduced fermentable `".$item['f_name']."' from `".$item['f_supplier']."' to 0 kg");
+                } else if ($ar == 0) {
+                        syslog(LOG_NOTICE, "Reduce fermentable `".$item['f_name']."' from `".$item['f_supplier']."' failed");
+                }
+        }
+}
+
+
+
+function reduce_hops($item) {
+
+	global $connect;
+
+	$amount = round($item['h_amount'] * 1000) / 1000;
+        $sql2  = "UPDATE inventory_hops SET inventory = inventory - " . $amount;
+        $sql2 .= " WHERE name='" . mysqli_real_escape_string($connect, $item['h_name']);
+        $sql2 .= "' AND origin='" . mysqli_real_escape_string($connect, $item['h_origin']);
+        $sql2 .= "' AND form=" . $item['h_form'];
+        $sql2 .= " AND inventory >= " . $amount . " LIMIT 1;";
+        $result2 = mysqli_query($connect, $sql2);
+        $ar = mysqli_affected_rows($connect);
+        if ($ar == 1) {
+                syslog(LOG_NOTICE, "Reduced hop `".$item['h_name']."' from `".$item['h_origin']."' with ".$amount." kg");
+        } else if ($ar == 0) {
+                $sql2  = "UPDATE inventory_hops SET inventory = 0";
+                $sql2 .= " WHERE name='" . mysqli_real_escape_string($connect, $item['h_name']);
+                $sql2 .= "' AND origin='" . mysqli_real_escape_string($connect, $item['h_origin']);
+                $sql2 .= "' AND form=" . $item['h_form'];
+                $sql2 .= " AND inventory < " . $amount . " LIMIT 1;";
+                $result2 = mysqli_query($connect, $sql2);
+                $ar = mysqli_affected_rows($connect);
+                if ($ar == 1) {
+                        syslog(LOG_NOTICE, "Reduced hop `".$item['h_name']."' from `".$item['h_origin']."' to 0 kg");
+                } else if ($ar == 0) {
+                        syslog(LOG_NOTICE, "Reduce hop `".$item['h_name']."' from `".$item['h_origin']."' failed");
+                }
+        }
+}
+
+
+
+function reduce_miscs($item) {
+
+	global $connect;
+
+	$amount = round($item['m_amount'] * 100000) / 100000;
+        $sql2  = "UPDATE inventory_miscs SET inventory = inventory - " . $amount;
+        $sql2 .= " WHERE name='" . mysqli_real_escape_string($connect, $item['m_name']);
+        $sql2 .= "' AND inventory >= " . $amount . " LIMIT 1;";
+        $result2 = mysqli_query($connect, $sql2);
+        $ar = mysqli_affected_rows($connect);
+        if ($ar == 1) {
+                syslog(LOG_NOTICE, "Reduced misc `".$item['m_name']."' with ".$amount);
+        } else if ($ar == 0) { 
+                $sql2  = "UPDATE inventory_miscs SET inventory = 0";
+                $sql2 .= " WHERE name='" . mysqli_real_escape_string($connect, $item['m_name']);
+                $sql2 .= "' AND inventory < " . $amount . " LIMIT 1;";
+                $result2 = mysqli_query($connect, $sql2); 
+                $ar = mysqli_affected_rows($connect);
+                if ($ar == 1) {
+                       syslog(LOG_NOTICE, "Reduced misc `".$item['m_name']."' to 0");
+                } else if ($ar == 0) { 
+                       syslog(LOG_NOTICE, "Reduce misc `".$item['m_name']."' failed");
+                }
+        }
+}
+
+
+
+function reduce_yeast($item) {
+
+	global $connect;
+
+	$amount = round($item['y_amount'] * 10000) / 10000;
+	$sql2  = "UPDATE inventory_yeasts SET inventory = inventory - " . $amount;
+        $sql2 .= " WHERE name='" . mysqli_real_escape_string($connect, $item['y_name']);
+        $sql2 .= "' AND laboratory='" . mysqli_real_escape_string($connect, $item['y_laboratory']);
+        $sql2 .= "' AND product_id='" . mysqli_real_escape_string($connect, $item['y_product_id']);
+        $sql2 .= "' AND form=" . $item['y_form'];
+        $sql2 .= " AND inventory >= " . $amount . " LIMIT 1;";
+        $result2 = mysqli_query($connect, $sql2);
+        $ar = mysqli_affected_rows($connect);
+        if ($ar == 1) {
+		syslog(LOG_NOTICE, "Reduced yeast `".$item['y_product_id'].' '.$item['y_name']."' from `".$item['y_laboratory']."' with ".$amount);
+        } else if ($ar == 0) {
+                $sql2  = "UPDATE inventory_yeasts SET inventory = 0";
+                $sql2 .= " WHERE name='" . mysqli_real_escape_string($connect, $item['y_name']);
+                $sql2 .= "' AND laboratory='" . mysqli_real_escape_string($connect, $item['y_laboratory']);
+                $sql2 .= "' AND product_id='" . mysqli_real_escape_string($connect, $item['y_product_id']);
+                $sql2 .= "' AND form=" . $item['y_form'];
+                $sql2 .= " AND inventory < " . $amount . " LIMIT 1;";
+                $result2 = mysqli_query($connect, $sql2);
+                $ar = mysqli_affected_rows($connect);
+                if ($ar == 1) {
+                        syslog(LOG_NOTICE, "Reduced yeast `".$item['y_product_id'].' '.$item['y_name']."' from `".$item['y_laboratory']."' to 0");
+                } else if ($ar == 0) {
+                	syslog(LOG_NOTICE, "Reduce yeast `".$item['y_product_id'].' '.$item['y_name']."' from `".$item['y_laboratory']."' failed");
+                }
+        }
+}
+
+
+
+/*
+ * Reduce inventory depending on the production stage.
+ *  Stage 3+, after brew, reduce sugars(0-mash, 1-boil), hops(0-mash, 1-fwh, 2-boil, 3-aroma, 4-whirlpool), miscs(0-starter, 1-mash, 2-boil)
+ *  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)
+ */
+function inventory_reduce() {
+
+    global $connect;
+
+    $savethis = 0;
+    $stage = $_POST['stage'];
+    $inventory_reduced = $_POST['inventory_reduced'];
+    syslog(LOG_NOTICE, "inventory_reduce() stage: ".$stage." inventory_reduced: ".$inventory_reduced);
+
+    /*
+     * If the brew is done, reduce the used ingredients.
+     */
+    if (($stage >= 3) && ($inventory_reduced < 3)) {
+	syslog(LOG_NOTICE, "Reduce brew inventory from " . $_POST['code'] . " " . $_POST['name']);
+
+	if (isset($_POST['fermentables'])) {
+            $array = $_POST['fermentables'];
+            foreach($array as $key => $item) {
+	    	if ($item['f_added'] <= 1) {	// Mash, Boil
+		    reduce_fermentables($item);
+	    	}
+	    }
+	}
+
+	if (isset($_POST['hops'])) {
+            $array = $_POST['hops'];
+            foreach($array as $key => $item) {
+	    	if ($item['h_useat'] <= 4) { // Mash, FWH, Boil, Flameout, Whirlpool
+		    reduce_hops($item);
+		}
+	    }
+	}
+
+	if (isset($_POST['miscs'])) {
+            $array = $_POST['miscs'];
+            foreach($array as $key => $item) {
+	    	if ($item['m_use_use'] <= 2) {	// Starter, Mash, Boil
+		    reduce_miscs($item);
+		}
+	    }
+	}
+
+	if ($_POST['w1_name'] != '') {
+            $sql2  = "UPDATE inventory_waters SET inventory = inventory - ".$_POST['w1_amount'];
+            $sql2 .= " WHERE name='" . mysqli_real_escape_string($connect, $_POST['w1_name']);
+            $sql2 .= "' AND unlimited_stock=0 AND inventory >= ".$_POST['w1_amount']." LIMIT 1;";
+            $result2 = mysqli_query($connect, $sql2);
+            $ar = mysqli_affected_rows($connect);
+            if ($ar == 1) {
+                syslog(LOG_NOTICE, "Reduced water `".$_POST['w1_name']."' with ".$_POST['w1_amount']." liter");
+            } else if ($ar == 0) {
+                $sql2  = "UPDATE inventory_waters SET inventory = 0";
+                $sql2 .= " WHERE name='" . mysqli_real_escape_string($connect, $_POST['w1_name']);
+                $sql2 .= "' AND unlimited_stock=0 AND inventory < ".$_POST['w1_amount']." LIMIT 1;";
+                $result2 = mysqli_query($connect, $sql2);
+                $ar = mysqli_affected_rows($connect);
+                if ($ar == 1) {
+                    syslog(LOG_NOTICE, "Reduced water `".$_POST['w1_name']."' to 0 liters");
+                } else {
+                    syslog(LOG_NOTICE, "Reduce water `".$_POST['w1_name']."' not reduced is maybe tapwater");
+                }
+            }
+        }
+	if ($_POST['w2_name'] != '') {
+            $sql2  = "UPDATE inventory_waters SET inventory = inventory - ".$_POST['w2_amount'];
+            $sql2 .= " WHERE name='" . mysqli_real_escape_string($connect, $_POST['w2_name']);
+            $sql2 .= "' AND unlimited_stock=0 AND inventory >= ".$_POST['w2_amount']." LIMIT 1;";
+            $result2 = mysqli_query($connect, $sql2);
+            $ar = mysqli_affected_rows($connect);
+            if ($ar == 1) {
+                syslog(LOG_NOTICE, "Reduced water `".$_POST['w2_name']."' with ".$_POST['w2_amount']." liter");
+            } else if ($ar == 0) {
+                $sql2  = "UPDATE inventory_waters SET inventory = 0";
+                $sql2 .= " WHERE name='" . mysqli_real_escape_string($connect, $_POST['w2_name']);
+                $sql2 .= "' AND unlimited_stock=0 AND inventory < ".$_POST['w2_amount']." LIMIT 1;";
+                $result2 = mysqli_query($connect, $sql2);
+                $ar = mysqli_affected_rows($connect);
+                if ($ar == 1) {
+                    syslog(LOG_NOTICE, "Reduced water `".$_POST['w2_name']."' to 0 liters");
+		} else {
+                    syslog(LOG_NOTICE, "Reduce water `".$_POST['w2_name']."' failed");
+                }
+            }
+        }
+
+	$inventory_reduced = 3;
+	$savethis = 1;
+    }
+
+    /*
+     * After the Primary fermentation
+     */
+    if (($stage >= 4) && ($inventory_reduced < 4)) {
+        syslog(LOG_NOTICE, "Reduce Primary inventory from " . $_POST['code'] . " " . $_POST['name']);
+
+	if (isset($_POST['fermentables'])) {
+            $array = $_POST['fermentables'];
+            foreach($array as $key => $item) {
+            	if ($item['f_added'] == 2) {    // Fermentation
+		    reduce_fermentables($item);
+		}
+            }
+        }
+
+	if (isset($_POST['miscs'])) {
+            $array = $_POST['miscs'];
+            foreach($array as $key => $item) {
+            	if ($item['m_use_use'] == 3) { // Fermentation
+		    reduce_miscs($item);
+		}
+            }
+        }
+
+	if (isset($_POST['yeasts'])) {
+            $array = $_POST['yeasts'];
+            foreach($array as $key => $item) {
+	    	if ($item['y_use'] == 0) {	// Primary
+		    reduce_yeast($item);
+		}
+	    }
+	}
+
+        $inventory_reduced = 4;
+	$savethis = 1;
+    }
+
+
+    /*
+     * After the Seconday fermentation
+     */
+    if (($stage >= 5) && ($inventory_reduced < 5)) {
+        syslog(LOG_NOTICE, "Reduce Secondary inventory from " . $_POST['code'] . " " . $_POST['name']);
+
+	if (isset($_POST['yeasts'])) {
+            $array = $_POST['yeasts'];
+            foreach($array as $key => $item) {
+                if ($item['y_use'] == 1) {      // Secondary
+                    reduce_yeast($item);
+                }
+            }
+        }
+
+        $inventory_reduced = 5;
+	$savethis = 1;
+    }
+
+
+    /*
+     * After the Tertiary fermentation
+     */
+    if (($stage >= 6) && ($inventory_reduced < 6)) {
+        syslog(LOG_NOTICE, "Reduce Tertiary inventory from " . $_POST['code'] . " " . $_POST['name']);
+
+	if (isset($_POST['fermentables'])) {
+            $array = $_POST['fermentables'];
+            foreach($array as $key => $item) {
+                if ($item['f_added'] == 3) {    // Lagering
+                    reduce_fermentables($item);
+                }
+            }
+        }
+
+	if (isset($_POST['hops'])) {
+            $array = $_POST['hops'];
+            foreach($array as $key => $item) {
+                if ($item['h_useat'] == 5) { // Dry hop
+                    reduce_hops($item);
+                }
+            }
+        }
+
+	if (isset($_POST['yeasts'])) {
+            $array = $_POST['yeasts'];
+            foreach($array as $key => $item) {
+                if ($item['y_use'] == 2) {      // Tertiary
+                    reduce_yeast($item);
+                }
+            }
+        }
+
+	if (isset($_POST['miscs'])) {
+            $array = $_POST['miscs'];
+            foreach($array as $key => $item) {
+                if ($item['m_use_use'] == 4) { // Secondary or Tertiary
+                    reduce_miscs($item);
+                }
+            }
+        }
+
+        $inventory_reduced = 6;
+	$savethis = 1;
+    }
+
+    /*
+     * After packaging
+     *  reduce sugars(4-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['yeasts'])) {
+            $array = $_POST['yeasts'];
+            foreach($array as $key => $item) {
+                if ($item['y_use'] == 3) {      // Bottle
+                    reduce_yeast($item);
+                }
+            }
+        }
+
+	if (isset($_POST['miscs'])) {
+            $array = $_POST['miscs'];
+            foreach($array as $key => $item) {
+                if ($item['m_use_use'] == 5) { // Bottle
+                    reduce_miscs($item);
+                }
+            }
+        }
+
+	if ($stage < 7)
+                $stage = 7;
+        $inventory_reduced = $stage;
+	$savethis = 1;
+    }
+
+    /*
+     * Save only if something was reduced.
+     */
+    if ($savethis == 1) {
+    	$sql2 = "UPDATE products SET stage=".$stage.", inventory_reduced=".$inventory_reduced." WHERE record='".$_POST['record']."';";
+    	syslog(LOG_NOTICE, $sql2);
+    	$result2 = mysqli_query($connect, $sql2);
+    	$ar = mysqli_affected_rows($connect);
+	if ($ar != 1) {
+    	    syslog(LOG_NOTICE, $sql2." error, affected rows: ".$ar);
+	}
+    }
+}
+
+
 ?>
--- a/www/includes/db_recipes.php	Thu May 30 23:19:43 2019 +0200
+++ b/www/includes/db_recipes.php	Wed Jun 05 20:04:26 2019 +0200
@@ -100,6 +100,21 @@
 		$sql .= "', w2_ph='" . $_POST['w2_ph'];
 		$sql .= "', w2_cost='" . $_POST['w2_cost'];
 	}
+	$sql .= "', wg_amount='" . $_POST['wg_amount'];
+	$sql .= "', wg_calcium='" . $_POST['wg_calcium'];
+	$sql .= "', wg_sulfate='" . $_POST['wg_sulfate'];
+	$sql .= "', wg_chloride='" . $_POST['wg_chloride'];
+	$sql .= "', wg_sodium='" . $_POST['wg_sodium'];
+	$sql .= "', wg_magnesium='" . $_POST['wg_magnesium'];
+	$sql .= "', wg_total_alkalinity='" . $_POST['wg_total_alkalinity'];
+	$sql .= "', wg_ph='" . $_POST['wg_ph'];
+	$sql .= "', wb_calcium='" . $_POST['wb_calcium'];
+	$sql .= "', wb_sulfate='" . $_POST['wb_sulfate'];
+	$sql .= "', wb_chloride='" . $_POST['wb_chloride'];
+	$sql .= "', wb_sodium='" . $_POST['wb_sodium'];
+	$sql .= "', wb_magnesium='" . $_POST['wb_magnesium'];
+	$sql .= "', wb_total_alkalinity='" . $_POST['wb_total_alkalinity'];
+	$sql .= "', wb_ph='" . $_POST['wb_ph'];
 	$sql .= "', wa_acid_name='" . $_POST['wa_acid_name'];
 	$sql .= "', wa_acid_perc='" . $_POST['wa_acid_perc'];
 	$sql .= "', wa_base_name='" . $_POST['wa_base_name'];
@@ -109,6 +124,17 @@
 	$comma = FALSE;
 	if (isset($_POST['fermentables'])) {
 		$array = $_POST['fermentables'];
+		// Sort the array
+                $added = array();
+                $amount = array();
+                for ($i = 0; $i < count($array); $i++) {
+                        $added[] = $array[$i]['f_added'];
+                        $amount[] = $array[$i]['f_amount'];
+                }
+                array_multisort($added, SORT_ASC, SORT_NUMERIC,
+                        $amount, SORT_DESC, SORT_NUMERIC,
+                        $array);
+                // Write the sorted array.
 		foreach($array as $key => $item){
 			/*
 			 * Manual encode to json.
@@ -149,6 +175,20 @@
 	$comma = FALSE;
 	if (isset($_POST['hops'])) {
 		$array = $_POST['hops'];
+		// Sort the array
+                $useat = array();
+                $time = array();
+                $amount = array();
+                for ($i = 0; $i < count($array); $i++) {
+                        $useat[] = $array[$i]['h_useat'];
+                        $time[] = $array[$i]['h_time'];
+                        $amount[] = $array[$i]['h_amount'];
+                }
+                array_multisort($useat, SORT_ASC, SORT_NUMERIC,
+                                $time, SORT_DESC, SORT_NUMERIC,
+                                $amount, SORT_DESC, SORT_NUMERIC,
+                                $array);
+                // Write the sorted array.
 		foreach($array as $key => $item){
 			if ($comma)
 				$hops .= ',';
@@ -180,6 +220,20 @@
 	$comma = FALSE;
 	if (isset($_POST['miscs'])) {
 		$array = $_POST['miscs'];
+		// Sort the array
+                $use = array();
+                $type = array();
+                $amount = array();
+                for ($i = 0; $i < count($array); $i++) {
+                        $use[] = $array[$i]['m_use_use'];
+                        $type[] = $array[$i]['m_type'];
+                        $amount[] = $array[$i]['m_amount'];
+                }
+                array_multisort($use, SORT_ASC, SORT_NUMERIC,
+                        $type, SORT_ASC, SORT_NUMERIC,
+                        $amount, SORT_DESC, SORT_NUMERIC,
+                        $array);
+                // Write the sorted array.
 		foreach($array as $key => $item) {
 			if ($comma)
 				$miscs .= ',';
@@ -202,7 +256,17 @@
 	$comma = FALSE;
 	if (isset($_POST['yeasts'])) {
 		$array = $_POST['yeasts'];
-syslog(LOG_NOTICE, $_POST['yeasts']);
+		// Sort the array
+                $use = array();
+                $amount = array();
+                for ($i = 0; $i < count($array); $i++) {
+                        $use[] = $array[$i]['y_use'];
+                        $amount[] = $array[$i]['y_amount'];
+                }
+                array_multisort($use, SORT_ASC, SORT_NUMERIC,
+                        $amount, SORT_DESC, SORT_NUMERIC,
+                        $array);
+                // Write the sorted array.
 		foreach($array as $key => $item) {
 			if ($comma)
 				$yeasts .= ',';
@@ -233,6 +297,13 @@
 	$comma = FALSE;
 	if (isset($_POST['mashs'])) {
 		$array = $_POST['mashs'];
+		// Sort the array
+                $temp = array();
+                for ($i = 0; $i < count($array); $i++) {
+                        $temp[] = $array[$i]['step_temp'];
+                }
+                array_multisort($temp, SORT_ASC, SORT_NUMERIC, $array);
+                // Write the sorted array.
 		foreach($array as $key => $item) {
 			if ($comma)
 				$mashs .= ',';
@@ -369,6 +440,21 @@
 		$recipes .= ',"w2_total_alkalinity":' . floatval($row['w2_total_alkalinity']);
 		$recipes .= ',"w2_ph":' . floatval($row['w2_ph']);
 		$recipes .= ',"w2_cost":' . floatval($row['w2_cost']);
+		$recipes .= ',"wg_amount":' . floatval($row['wg_amount']);
+		$recipes .= ',"wg_calcium":' . floatval($row['wg_calcium']);
+		$recipes .= ',"wg_sulfate":' . floatval($row['wg_sulfate']);
+		$recipes .= ',"wg_chloride":' . floatval($row['wg_chloride']);
+		$recipes .= ',"wg_sodium":' . floatval($row['wg_sodium']);
+		$recipes .= ',"wg_magnesium":' . floatval($row['wg_magnesium']);
+		$recipes .= ',"wg_total_alkalinity":' . floatval($row['wg_total_alkalinity']);
+		$recipes .= ',"wg_ph":' . floatval($row['wg_ph']);
+		$recipes .= ',"wb_calcium":' . floatval($row['wb_calcium']);
+		$recipes .= ',"wb_sulfate":' . floatval($row['wb_sulfate']);
+		$recipes .= ',"wb_chloride":' . floatval($row['wb_chloride']);
+		$recipes .= ',"wb_sodium":' . floatval($row['wb_sodium']);
+		$recipes .= ',"wb_magnesium":' . floatval($row['wb_magnesium']);
+		$recipes .= ',"wb_total_alkalinity":' . floatval($row['wb_total_alkalinity']);
+		$recipes .= ',"wb_ph":' . floatval($row['wb_ph']);
 		$recipes .= ',"wa_acid_name":' . $row['wa_acid_name'];
 		$recipes .= ',"wa_acid_perc":' . floatval($row['wa_acid_perc']);
 		$recipes .= ',"wa_base_name":' . $row['wa_base_name'];
--- a/www/includes/formulas.php	Thu May 30 23:19:43 2019 +0200
+++ b/www/includes/formulas.php	Wed Jun 05 20:04:26 2019 +0200
@@ -280,6 +280,16 @@
 
 
 
+function density_str($sg) {
+
+	global $my_brix_correction;
+	$plato = sg_to_plato(floatval($sg));
+	$brix = $plato * $my_brix_correction;
+	return sprintf("%.3f", floatval($sg))." SG  ".sprintf("%.1f",$brix).DEG.'Brix  '.sprintf("%.1f",$plato).DEG.'P';
+}
+
+
+
 /*
 
 Brouwhulp data.pas
--- a/www/js/inv_fermentables.js	Thu May 30 23:19:43 2019 +0200
+++ b/www/js/inv_fermentables.js	Wed Jun 05 20:04:26 2019 +0200
@@ -385,9 +385,9 @@
 			$('#jqxgrid').jqxGrid('updaterow', rowID, row);
 		} else {
 			$('#jqxgrid').jqxGrid('addrow', null, row);
+			location.reload( true );	// reload ourself.
 		}
 		$("#popupWindow").jqxWindow('hide');
-		location.reload( true );	// reload ourself.
 	});
 	createDelElements();
 });
--- a/www/js/inv_hops.js	Thu May 30 23:19:43 2019 +0200
+++ b/www/js/inv_hops.js	Wed Jun 05 20:04:26 2019 +0200
@@ -383,9 +383,9 @@
 			$('#jqxgrid').jqxGrid('updaterow', rowID, row);
 		} else {
 			$('#jqxgrid').jqxGrid('addrow', null, row);
+			location.reload( true );	// reload ourself.
 		}
 		$("#popupWindow").jqxWindow('hide');
-		location.reload( true );        // reload ourself.
 	});
 	createDelElements();
 });
--- a/www/js/inv_miscs.js	Thu May 30 23:19:43 2019 +0200
+++ b/www/js/inv_miscs.js	Wed Jun 05 20:04:26 2019 +0200
@@ -353,9 +353,9 @@
 			$('#jqxgrid').jqxGrid('updaterow', rowID, row);
 		} else {
 			$('#jqxgrid').jqxGrid('addrow', null, row);
+			location.reload( true );	// reload ourself.
 		}
 		$("#popupWindow").jqxWindow('hide');
-		location.reload( true );        // reload ourself.
 	});
 	createDelElements();
 });
--- a/www/js/inv_yeasts.js	Thu May 30 23:19:43 2019 +0200
+++ b/www/js/inv_yeasts.js	Wed Jun 05 20:04:26 2019 +0200
@@ -429,9 +429,9 @@
 			$('#jqxgrid').jqxGrid('updaterow', rowID, row);
 		} else {
 			$('#jqxgrid').jqxGrid('addrow', null, row);
+			location.reload( true );	// reload ourself.
 		}
 		$("#popupWindow").jqxWindow('hide');
-		location.reload( true );        // reload ourself.
 	});
 	createDelElements();
 });
--- a/www/js/mon_fermenter.js	Thu May 30 23:19:43 2019 +0200
+++ b/www/js/mon_fermenter.js	Wed Jun 05 20:04:26 2019 +0200
@@ -167,9 +167,7 @@
 		labels: { interval: 5 },
 		style: { fill: '#eeeeee', stroke: '#666666' },
 		value: 0,
-		colorScheme: 'scheme05',
-		easing: 'easeOutBack',
-		animationDuration: 600
+		colorScheme: 'scheme05'
 	};
 	var gaugeSmalloptions = {
 		min: -15, max: 25, width: 190, height: 190,
@@ -182,8 +180,6 @@
 		style: { fill: '#eeeeee', stroke: '#666666' },
 		value: 0,
 		colorScheme: 'scheme05',
-		easing: 'easeOutBack',
-		animationDuration: 400,
 		caption: { value: 'Chiller', position: 'bottom', offset: [0, 10] }
 	};
 	$("#gaugeContainer_air").jqxGauge( gaugeoptions );
@@ -228,12 +224,8 @@
 			url: "cmd_fermenter.php",
 			data: data,
 			type: "POST",
-			success: function(data) {
-				//do something after something is received from php
-			},
-			error: function(jqXHR, textStatus, errorThrown) {
-				console.log("sendBase() error");
-			}
+			success: function(data) {},
+			error: function(jqXHR, textStatus, errorThrown) { console.log("sendBase() error"); }
 		});
 	}
 
@@ -246,12 +238,8 @@
 			url: "cmd_fermenter.php",
 			data: data,
 			type: "POST",
-			success: function(data) {
-				//do something after something is received from php
-			},
-			error: function(jqXHR, textStatus, errorThrown) {
-				console.log("sendBase() error");
-			}
+			success: function(data) {},
+			error: function(jqXHR, textStatus, errorThrown) { console.log("sendSwitch() error"); }
 		});
 	}
 
@@ -264,12 +252,8 @@
 			url: "cmd_fermenter.php",
 			data: data,
 			type: "POST",
-			success: function(data) {
-				//do something after something is received from php
-			},
-			error: function(jqXHR, textStatus, errorThrown) {
-				console.log("sendBase() error");
-			}
+			success: function(data) {},
+			error: function(jqXHR, textStatus, errorThrown) { console.log("sendProduct() error"); }
 		});
 	}
 
@@ -281,12 +265,8 @@
 			url: "cmd_fermenter.php",
 			data: data,
 			type: "POST",
-			success: function(data) {
-				//do something after something is received from php
-			},
-			error: function(jqXHR, textStatus, errorThrown) {
-				console.log("sendBase() error");
-			}
+			success: function(data) {},
+			error: function(jqXHR, textStatus, errorThrown) { console.log("sendProfile() error"); }
 		});
 	}
 
--- a/www/js/prod_edit.js	Thu May 30 23:19:43 2019 +0200
+++ b/www/js/prod_edit.js	Wed Jun 05 20:04:26 2019 +0200
@@ -536,7 +536,7 @@
 		var irate = Math.round(prate * 10) / 10;
 		var egrams = (dataRecord.starter_sg - 1) * svol * gperpoint;
 		var grate = getGrowthRate(stype, start, egrams);
-		var ncells = Math.round(egrams * grate);
+		var ncells = Math.round(egrams * grate * 10) / 10;
 		var totcells = parseFloat(ncells) + start;
 		console.log("svol:"+svol+" start:"+start+" irate:"+irate+" egrams:"+egrams+" grate:"+grate+" ncells:"+ncells);
 		return {
@@ -813,80 +813,27 @@
 		if (dataRecord.starter_enable) {
 			calcSteps(dataRecord.starter_type, initcells, needed);
 
-			$("#r1_irate").html("");
-			$("#r1_growf").html("");
-			$("#r1_tcells").html("");
-			if (parseFloat($("#prop1_volume").val()) > 0) {
-				if ((parseFloat($("#prop1_irate").val()) < 25) || (parseFloat($("#prop1_irate").val()) > 100)) {
-					$("#r1_irate").html("<img src='images/dialog-error.png'>");
+			for (var i = 1; i < 5; i++) {
+				$("#r"+i+"_irate").html("");
+				$("#r"+i+"_growf").html("");
+				$("#r"+i+"_tcells").html("");
+				if (parseFloat($("#prop"+i+"_volume").val()) > 0) {
+					if ((parseFloat($("#prop"+i+"_irate").val()) < 25) || (parseFloat($("#prop"+i+"_irate").val()) > 100)) {
+						$("#r"+i+"_irate").html("<img src='images/dialog-error.png'>");
+					} else {
+						$("#r"+i+"_irate").html("<img src='images/dialog-ok-apply.png'>");
+					}
+					if (parseFloat($("#prop"+i+"_growf").val()) < 1)
+						$("#r"+i+"_growf").html("<img src='images/dialog-error.png'>");
+					if (($("#prop"+i+"_type").val() > 0) && (parseFloat($("#prop"+i+"_growf").val()) > 3))
+						$("#r"+i+"_growf").html("<img src='images/dialog-error.png'>");
+					if (parseFloat($("#prop"+i+"_tcells").val()) > needed)
+						$("#r"+i+"_tcells").html("<img src='images/dialog-ok-apply.png'>");
+					use_cells = parseFloat($("#prop"+i+"_tcells").val());
 				} else {
-					$("#r1_irate").html("<img src='images/dialog-ok-apply.png'>");
-				}
-				if (parseFloat($("#prop1_growf").val()) < 1)
-					$("#r1_growf").html("<img src='images/dialog-error.png'>");
-				if (($("#prop1_type").val() > 0) && (parseFloat($("#prop1_growf").val()) > 3))
-					$("#r1_growf").html("<img src='images/dialog-error.png'>");
-				if (parseFloat($("#prop1_tcells").val()) > needed) {
-					$("#r1_tcells").html("<img src='images/dialog-ok-apply.png'>");
-					use_cells = parseFloat($("#prop1_tcells").val());
-				}
-			}
-			$("#r2_irate").html("");
-			$("#r2_growf").html("");
-			$("#r2_tcells").html("");
-			if (parseFloat($("#prop2_volume").val()) > 0) {
-				if ((parseFloat($("#prop2_irate").val()) < 25) || (parseFloat($("#prop2_irate").val()) > 100)) {
-					$("#r2_irate").html("<img src='images/dialog-error.png'>");
-				} else {
-					$("#r2_irate").html("<img src='images/dialog-ok-apply.png'>");
-				}
-				if (parseFloat($("#prop2_growf").val()) < 1)
-					$("#r2_growf").html("<img src='images/dialog-error.png'>");
-				if (($("#prop2_type").val() > 0) && (parseFloat($("#prop2_growf").val()) > 3))
-					$("#r2_growf").html("<img src='images/dialog-error.png'>");
-				if (parseFloat($("#prop2_tcells").val()) > needed) {
-					$("#r2_tcells").html("<img src='images/dialog-ok-apply.png'>");
-					use_cells = parseFloat($("#prop2_tcells").val());
+					$("#r"+i+"_irate").html("");
 				}
 			}
-			$("#r3_irate").html("");
-			$("#r3_growf").html("");
-			$("#r3_tcells").html("");
-			if (parseFloat($("#prop3_volume").val()) > 0) {
-				if ((parseFloat($("#prop3_irate").val()) < 25) || (parseFloat($("#prop3_irate").val()) > 100)) {
-					$("#r3_irate").html("<img src='images/dialog-error.png'>");
-				} else {
-					$("#r3_irate").html("<img src='images/dialog-ok-apply.png'>");
-				}
-				if (parseFloat($("#prop3_growf").val()) < 1)
-					$("#r3_growf").html("<img src='images/dialog-error.png'>");
-				if (($("#prop3_type").val() > 0) && (parseFloat($("#prop3_growf").val()) > 3))
-					$("#r3_growf").html("<img src='images/dialog-error.png'>");
-				if (parseFloat($("#prop3_tcells").val()) > needed) {
-					$("#r3_tcells").html("<img src='images/dialog-ok-apply.png'>");
-					use_cells = parseFloat($("#prop3_tcells").val());
-				}
-			}
-			$("#r4_irate").html("");
-			$("#r4_growf").html("");
-			$("#r4_tcells").html("");
-			if (parseFloat($("#prop4_volume").val()) > 0) {
-				if ((parseFloat($("#prop4_irate").val()) < 25) || (parseFloat($("#prop4_irate").val()) > 100)) {
-					$("#r4_irate").html("<img src='images/dialog-error.png'>");
-				} else {
-					$("#r4_irate").html("<img src='images/dialog-ok-apply.png'>");
-				}
-				if (parseFloat($("#prop4_growf").val()) < 1)
-					$("#r4_growf").html("<img src='images/dialog-error.png'>");
-				if (($("#prop4_type").val() > 0) && (parseFloat($("#prop4_growf").val()) > 3))
-					$("#r4_growf").html("<img src='images/dialog-error.png'>");
-				if (parseFloat($("#prop4_tcells").val()) > needed) {
-					$("#r4_tcells").html("<img src='images/dialog-ok-apply.png'>");
-					use_cells = parseFloat($("#prop4_tcells").val());
-				}
-			} else {
-				$("#r4_irate").html("");
-			}
 		}
 		$("#plato_cells").val(parseFloat(use_cells / (volume * plato) ));
 	};
@@ -2601,12 +2548,15 @@
 			brew_date_start: $("#brew_date_start").val(),
 			brew_mash_ph: parseFloat($("#brew_mash_ph").jqxNumberInput('decimal')),
 			brew_mash_sg: parseFloat($("#brew_mash_sg").jqxNumberInput('decimal')),
+			brew_mash_efficiency: parseFloat($("#brew_mash_efficiency").jqxNumberInput('decimal')),
 			brew_sparge_temperature: parseFloat($("#brew_sparge_temperature").jqxNumberInput('decimal')),
 			brew_sparge_volume: parseFloat($("#brew_sparge_volume").jqxNumberInput('decimal')),
+			brew_sparge_est: parseFloat($("#brew_sparge_est").jqxNumberInput('decimal')),
 			brew_sparge_ph: parseFloat($("#brew_sparge_ph").jqxNumberInput('decimal')),
 			brew_preboil_volume: parseFloat($("#brew_preboil_volume").jqxNumberInput('decimal')),
 			brew_preboil_sg: parseFloat($("#brew_preboil_sg").jqxNumberInput('decimal')),
 			brew_preboil_ph: parseFloat($("#brew_preboil_ph").jqxNumberInput('decimal')),
+			brew_preboil_efficiency: parseFloat($("#brew_preboil_efficiency").jqxNumberInput('decimal')),
 			brew_aboil_volume: parseFloat($("#brew_aboil_volume").jqxNumberInput('decimal')),
 			brew_aboil_sg: parseFloat($("#brew_aboil_sg").jqxNumberInput('decimal')),
 			brew_aboil_ph: parseFloat($("#brew_aboil_ph").jqxNumberInput('decimal')),
@@ -2722,6 +2672,21 @@
 			w2_total_alkalinity: parseFloat($("#w2_total_alkalinity").jqxNumberInput('decimal')),
 			w2_ph: parseFloat($("#w2_ph").jqxNumberInput('decimal')),
 			w2_cost: dataRecord.w2_cost,
+			wg_amount: parseFloat($("#wg_amount").jqxNumberInput('decimal')),
+                        wg_calcium: parseFloat($("#wg_calcium").jqxNumberInput('decimal')),
+                        wg_sulfate: parseFloat($("#wg_sulfate").jqxNumberInput('decimal')),
+                        wg_chloride: parseFloat($("#wg_chloride").jqxNumberInput('decimal')),
+                        wg_sodium: parseFloat($("#wg_sodium").jqxNumberInput('decimal')),
+                        wg_magnesium: parseFloat($("#wg_magnesium").jqxNumberInput('decimal')),
+                        wg_total_alkalinity: parseFloat($("#wg_total_alkalinity").jqxNumberInput('decimal')),
+                        wg_ph: parseFloat($("#wg_ph").jqxNumberInput('decimal')),
+                        wb_calcium: parseFloat($("#wb_calcium").jqxNumberInput('decimal')),
+                        wb_sulfate: parseFloat($("#wb_sulfate").jqxNumberInput('decimal')),
+                        wb_chloride: parseFloat($("#wb_chloride").jqxNumberInput('decimal')),
+                        wb_sodium: parseFloat($("#wb_sodium").jqxNumberInput('decimal')),
+                        wb_magnesium: parseFloat($("#wb_magnesium").jqxNumberInput('decimal')),
+                        wb_total_alkalinity: parseFloat($("#wb_total_alkalinity").jqxNumberInput('decimal')),
+                        wb_ph: parseFloat($("#wb_ph").jqxNumberInput('decimal')),
 			wa_acid_name: $("#wa_acid_name").val(),
 			wa_acid_perc: parseFloat($("#wa_acid_perc").jqxNumberInput('decimal')),
 			wa_base_name: $("#wa_base_name").val(),
@@ -2806,12 +2771,15 @@
 			{ name: 'brew_date_start', type: 'string' },
 			{ name: 'brew_mash_ph', type: 'float' },
 			{ name: 'brew_mash_sg', type: 'float' },
+			{ name: 'brew_mash_efficiency', type: 'float' },
 			{ name: 'brew_sparge_temperature', type: 'float' },
 			{ name: 'brew_sparge_volume', type: 'float' },
+			{ name: 'brew_sparge_est', type: 'float' },
 			{ name: 'brew_sparge_ph', type: 'float' },
 			{ name: 'brew_preboil_volume', type: 'float' },
 			{ name: 'brew_preboil_sg', type: 'float' },
 			{ name: 'brew_preboil_ph', type: 'float' },
+			{ name: 'brew_preboil_efficiency', type: 'float' },
 			{ name: 'brew_aboil_volume', type: 'float' },
 			{ name: 'brew_aboil_sg', type: 'float' },
 			{ name: 'brew_aboil_ph', type: 'float' },
@@ -2927,6 +2895,21 @@
 			{ name: 'w2_total_alkalinity', type: 'float' },
 			{ name: 'w2_ph', type: 'float' },
 			{ name: 'w2_cost', type: 'float' },
+			{ name: 'wg_amount', type: 'float' },
+                        { name: 'wg_calcium', type: 'float' },
+                        { name: 'wg_sulfate', type: 'float' },
+                        { name: 'wg_chloride', type: 'float' },
+                        { name: 'wg_sodium', type: 'float' },
+                        { name: 'wg_magnesium', type: 'float' },
+                        { name: 'wg_total_alkalinity', type: 'float' },
+                        { name: 'wg_ph', type: 'float' },
+                        { name: 'wb_calcium', type: 'float' },
+                        { name: 'wb_sulfate', type: 'float' },
+                        { name: 'wb_chloride', type: 'float' },
+                        { name: 'wb_sodium', type: 'float' },
+                        { name: 'wb_magnesium', type: 'float' },
+                        { name: 'wb_total_alkalinity', type: 'float' },
+                        { name: 'wb_ph', type: 'float' },
 			{ name: 'wa_acid_name', type: 'int' },
 			{ name: 'wa_acid_perc', type: 'int' },
 			{ name: 'wa_base_name', type: 'int' },
@@ -2983,10 +2966,11 @@
 			$("#brew_date_start").val(dataRecord.brew_date_start);
 			$("#brew_mash_ph").val(dataRecord.brew_mash_ph);
 			$("#brew_mash_sg").val(dataRecord.brew_mash_sg);
-			// brew_mash_efficiency to calculate on th fly.
+			$("#brew_mash_efficiency").val(dataRecord.brew_mash_efficiency);
 			// Header Spoelen en filteren
 			$("#brew_sparge_temperature").val(dataRecord.brew_sparge_temperature);
 			$("#brew_sparge_volume").val(dataRecord.brew_sparge_volume);
+			$("#brew_sparge_est").val(dataRecord.brew_sparge_est);
 			$("#brew_sparge_ph").val(dataRecord.brew_sparge_ph);
 			// Header Beluchten
 			$("#brew_aeration_type").val(dataRecord.brew_aeration_type);
@@ -2996,7 +2980,7 @@
 			$("#brew_preboil_ph").val(dataRecord.brew_preboil_ph);
 			$("#brew_preboil_sg").val(dataRecord.brew_preboil_sg);
 			$("#brew_preboil_volume").val(dataRecord.brew_preboil_volume);
-			//$("#brew_preboil_efficiency").val(dataRecord.brew_preboil_efficiency);
+			$("#brew_preboil_efficiency").val(dataRecord.brew_preboil_efficiency);
 			// Header Koelen en whirlpoolen
 			$("#brew_whirlpool9").val(dataRecord.brew_whirlpool9);
 			$("#brew_whirlpool7").val(dataRecord.brew_whirlpool7);
@@ -3127,6 +3111,21 @@
 			$("#w2_total_alkalinity").val(dataRecord.w2_total_alkalinity);
 			$("#w2_ph").val(dataRecord.w2_ph);
 			$("#w2_cost").val(dataRecord.w2_cost);
+			$("#wg_amount").val(dataRecord.wg_amount);
+                        $("#wg_calcium").val(dataRecord.wg_calcium);
+                        $("#wg_sulfate").val(dataRecord.wg_sulfate);
+                        $("#wg_chloride").val(dataRecord.wg_chloride);
+                        $("#wg_sodium").val(dataRecord.wg_sodium);
+                        $("#wg_magnesium").val(dataRecord.wg_magnesium);
+                        $("#wg_total_alkalinity").val(dataRecord.wg_total_alkalinity);
+                        $("#wg_ph").val(dataRecord.wg_ph);
+                        $("#wb_calcium").val(dataRecord.wb_calcium);
+                        $("#wb_sulfate").val(dataRecord.wb_sulfate);
+                        $("#wb_chloride").val(dataRecord.wb_chloride);
+                        $("#wb_sodium").val(dataRecord.wb_sodium);
+                        $("#wb_magnesium").val(dataRecord.wb_magnesium);
+                        $("#wb_total_alkalinity").val(dataRecord.wb_total_alkalinity);
+                        $("#wb_ph").val(dataRecord.wb_ph);
 			$("#wa_acid_name").val(dataRecord.wa_acid_name);
 			$("#wa_acid_perc").val(dataRecord.wa_acid_perc);
 			$("#wa_base_name").val(dataRecord.wa_base_name);
@@ -3191,11 +3190,17 @@
 				{ name: 'f_avail', type: 'int' }
                         ],
                         addrow: function (rowid, rowdata, position, commit) {
+				console.log("fermentable addrow "+rowid);
                                 commit(true);
                         },
                         deleterow: function (rowid, commit) {
+				console.log("fermentable deleterow "+rowid);
                                 commit(true);
-                        }
+                        },
+			updaterow: function (rowid, rowdata, commit) {
+				console.log("fermentable updaterow "+rowid);
+				commit(true);
+			}
                 };
                 var fermentableAdapter = new $.jqx.dataAdapter(fermentableSource);
                 $("#fermentableGrid").jqxGrid({
@@ -3203,7 +3208,6 @@
                         height: 470,
                         source: fermentableAdapter,
                         theme: theme,
-                	sortmode: "many",
                         selectionmode: 'singlerow',
                         showtoolbar: true,
                         rendertoolbar: function (toolbar) {
@@ -3323,11 +3327,6 @@
                                 });
                         },
                         ready: function() {
-				var datainformation = $('#fermentableGrid').jqxGrid('getdatainformation');
-                                if (datainformation.rowscount) {
-					$("#fermentableGrid").jqxGrid('sortby', 'f_added', 'asc');
-					$("#fermentableGrid").jqxGrid('sortby', 'f_amount', 'desc');
-				}
 				calcFermentables();
                                 $('#jqxTabs').jqxTabs('next');
                         },
@@ -3380,7 +3379,9 @@
 				{ text: '', datafield: 'Edit', columntype: 'button', width: 100, align: 'center', cellsrenderer: function () {
 					return "Wijzig";
 					}, buttonclick: function (row) {
-						if (dataRecord.stage <= 3) {
+						if (dataRecord.stage > 3) {
+							alert("Ingredieënt is al verwerkt.");
+						} else {
 							fermentableRow = row;
 							fermentableData = $("#fermentableGrid").jqxGrid('getrowdata', fermentableRow);
 							$("#wf_name").val(fermentableData.f_name);
@@ -3426,11 +3427,17 @@
 				{ name: 'h_avail', type: 'int' }
                         ],
                         addrow: function (rowid, rowdata, position, commit) {
-                                commit(true);
-                        },
+				console.log("hop addrow "+rowid);
+				commit(true);
+			},
                         deleterow: function (rowid, commit) {
-                                commit(true);
-                        }
+				console.log("hop deleterow "+rowid);
+				commit(true);
+			},
+			updaterow: function (rowid, rowdata, commit) {
+				console.log("hop updaterow "+rowid);
+				commit(true);
+			}
                 };
                 var hopAdapter = new $.jqx.dataAdapter(hopSource);
                 $("#hopGrid").jqxGrid({
@@ -3438,7 +3445,6 @@
                         height: 560,
                         source: hopAdapter,
                         theme: theme,
-			sortmode: "many",
                         selectionmode: 'singlerow',
                         showtoolbar: true,
                         rendertoolbar: function (toolbar) {
@@ -3513,12 +3519,6 @@
                                 });
                         },
                         ready: function() {
-				var datainformation = $('#hopGrid').jqxGrid('getdatainformation');
-                                if (datainformation.rowscount) {
-					$("#hopGrid").jqxGrid('sortby', 'h_useat', 'asc');
-					$("#hopGrid").jqxGrid('sortby', 'h_time', 'desc');
-					$("#hopGrid").jqxGrid('sortby', 'h_amount', 'desc');
-				}
 				calcIBUs();
                                 $('#jqxTabs').jqxTabs('next');
                         },
@@ -3589,7 +3589,10 @@
 				{ text: '', datafield: 'Edit', columntype: 'button', width: 100, align: 'center', cellsrenderer: function () {
 					return "Wijzig";
 					}, buttonclick: function (row) {
-						if (dataRecord.stage <= 3) {
+						if (dataRecord.stage > 3) {
+                                                        alert("Ingredieënt is al verwerkt.");
+                                                } else {
+							console.log("edit button row "+row);
 							hopRow = row;
 							hopData = $("#hopGrid").jqxGrid('getrowdata', hopRow);
 							$("#wh_name").val(hopData.h_name);
@@ -3633,11 +3636,17 @@
 				{ name: 'm_avail', type: 'int' }
                         ],
                         addrow: function (rowid, rowdata, position, commit) {
+				console.log("misc addrow "+rowid);
                                 commit(true);
                         },
                         deleterow: function (rowid, commit) {
+				console.log("misc deleterow "+rowid);
                                 commit(true);
-                        }
+                        },
+			updaterow: function (rowid, rowdata, commit) {
+				console.log("misc updaterow "+rowid);
+				commit(true);
+			}
                 };
                 var miscAdapter = new $.jqx.dataAdapter(miscSource, {
                         beforeLoadComplete: function (records) {
@@ -3704,7 +3713,6 @@
                         height: 575,
                         source: miscAdapter,
                         theme: theme,
-			sortmode: "many",
                         selectionmode: 'singlerow',
                         showtoolbar: true,
                         rendertoolbar: function (toolbar) {
@@ -3762,11 +3770,6 @@
                                 });
                         },
                         ready: function() {
-				var datainformation = $('#miscGrid').jqxGrid('getdatainformation');
-                                if (datainformation.rowscount) {
-					$("#miscGrid").jqxGrid('sortby', 'm_use_use', 'asc');
-					$("#miscGrid").jqxGrid('sortby', 'm_type', 'asc');
-				}
 				calcMiscs();
                                 $('#jqxTabs').jqxTabs('next');
                         },
@@ -3819,9 +3822,14 @@
 				{ text: '', datafield: 'Edit', columntype: 'button', width: 100, align: 'center', cellsrenderer: function () {
 					return "Wijzig";
 					}, buttonclick: function (row) {
-						if (dataRecord.stage <= 3) {
-							miscRow = row;
-							miscData = $("#miscGrid").jqxGrid('getrowdata', miscRow);
+						miscRow = row;
+						miscData = $("#miscGrid").jqxGrid('getrowdata', miscRow);
+						if (dataRecord.stage > 3) {
+							alert("Ingredieënt is al verwerkt.");
+						} else if (miscData.m_type == 4) {
+							alert("Brouwzouten wijzigen in de water tab.");
+						} else {
+							console.log("edit button row "+row);
 							if (miscData.m_amount_is_weight)
 								$("#wm_pmpt_amount").html("Gewicht gram:");
 							else
@@ -3834,8 +3842,7 @@
 								$("#wm_time").val(miscData.m_time);
 							$("#wm_use_use").val(miscData.m_use_use);
 							// show the popup window.
-							if (miscData.m_type != 4)
-								$("#popupMisc").jqxWindow('open');
+							$("#popupMisc").jqxWindow('open');
 						}
 					}
 				}
@@ -3869,11 +3876,17 @@
 				{ name: 'y_avail', type: 'int' }
                         ],
                         addrow: function (rowid, rowdata, position, commit) {
+				console.log("yeast addrow "+rowid);
                                 commit(true);
                         },
                         deleterow: function (rowid, commit) {
+				console.log("yeast deleterow "+rowid);
                                 commit(true);
-                        }
+                        },
+			updaterow: function (rowid, rowdata, commit) {
+				console.log("yeast updaterow "+rowid);
+				commit(true);
+			}
                 };
                 var yeastAdapter = new $.jqx.dataAdapter(yeastSource);
                 $("#yeastGrid").jqxGrid({
@@ -3881,7 +3894,6 @@
                         height: 350,
                         source: yeastAdapter,
                         theme: theme,
-			sortmode: "many",
                         selectionmode: 'singlerow',
                         showtoolbar: true,
                         rendertoolbar: function (toolbar) {
@@ -3952,10 +3964,6 @@
                                 });
                         },
                         ready: function() {
-				var datainformation = $('#yeastGrid').jqxGrid('getdatainformation');
-                                if (datainformation.rowscount) {
-					$("#yeastGrid").jqxGrid('sortby', 'y_use', 'asc');
-				}
 				calcFermentables();
 				showStarter();
 				calcYeast();
@@ -4023,7 +4031,9 @@
 				{ text: '', datafield: 'Edit', columntype: 'button', width: 90, align: 'center', cellsrenderer: function () {
 					return "Wijzig";
 					}, buttonclick: function (row) {
-						if (dataRecord.stage <= 3) {
+						if (dataRecord.stage > 3) {
+                                                        alert("Ingredieënt is al verwerkt.");
+                                                } else {
 							yeastRow = row;
 							yeastData = $("#yeastGrid").jqxGrid('getrowdata', yeastRow);
 							if (yeastData.y_form == 0) {
@@ -4153,7 +4163,9 @@
 				{ text: '', datafield: 'Edit', columntype: 'button', width: 100, align: 'center', cellsrenderer: function () {
 					return "Wijzig";
 					}, buttonclick: function (row) {
-						if (dataRecord.stage <= 3) {
+						if (dataRecord.stage > 3) {
+                                                        alert("Het maichen is al gedaan.");
+                                                } else {
 							mashRow = row;
 							mashData = $("#mashGrid").jqxGrid('getrowdata', mashRow);
 							$("#wstep_name").val(mashData.step_name);
@@ -4419,6 +4431,35 @@
 	});
 	$("#FermentableReady").jqxButton({ template: "success", width: '90px', theme: theme });
 	$("#FermentableReady").click(function () {
+		var rowID = $("#fermentableGrid").jqxGrid('getrowid', fermentableRow);
+		console.log("FermentableReady row:"+fermentableRow+" ID:"+rowID);
+		var row = {
+			f_name: fermentableData.f_name,
+			f_origin: fermentableData.f_origin,
+			f_supplier: fermentableData.f_supplier,
+			f_amount: fermentableData.f_amount,
+			f_cost: fermentableData.f_cost,
+			f_type: fermentableData.f_type,
+			f_yield: fermentableData.f_yield,
+			f_color: fermentableData.f_color,
+			f_coarse_fine_diff: fermentableData.f_coarse_fine_diff,
+			f_moisture: fermentableData.f_moisture,
+			f_diastatic_power: fermentableData.f_diastatic_power,
+			f_protein: fermentableData.f_protein,
+			f_max_in_batch: fermentableData.f_max_in_batch,
+			f_graintype: fermentableData.f_graintype,
+			f_added: fermentableData.f_added,
+			f_dissolved_protein: fermentableData.f_dissolved_protein,
+			f_recommend_mash: fermentableData.f_recommend_mash,
+			f_add_after_boil: fermentableData.f_add_after_boil,
+			f_adjust_to_total_100: fermentableData.f_adjust_to_total_100,
+			f_percentage: fermentableData.f_percentage,
+			f_di_ph: fermentableData.f_di_ph,
+			f_acid_to_ph_57: fermentableData.f_acid_to_ph_57,
+			f_inventory: fermentableData.f_inventory,
+			f_avail: fermentableData.f_avail
+		};
+		$("#fermentableGrid").jqxGrid('updaterow', rowID, row);
 		// Recalc percentages
 		calcFermentables();
 		calcIBUs();
@@ -4449,33 +4490,33 @@
 		if (event.args) {
 			var index = event.args.index;
 			var datarecord = fermentablelist.records[index];
-			var rowdata = $("#fermentableGrid").jqxGrid('getrowdata', fermentableRow);
 			$("#wf_name").val(datarecord.name);
-			rowdata.f_name = datarecord.name;
-			rowdata.f_origin = datarecord.origin;
-			rowdata.f_supplier = datarecord.supplier;
-			rowdata.f_type = datarecord.type;
-			rowdata.f_cost = datarecord.cost;
-			rowdata.f_yield = datarecord.yield;
-			rowdata.f_color = datarecord.color;
-			rowdata.f_coarse_fine_diff = datarecord.coarse_fine_diff;
-			rowdata.f_moisture = datarecord.moisture;
-			rowdata.f_diastatic_power = datarecord.diastatic_power;
-			rowdata.f_protein = datarecord.protein;
-			rowdata.f_max_in_batch = datarecord.max_in_batch;
-			rowdata.f_graintype = datarecord.graintype;
-			rowdata.f_dissolved_protein = datarecord.dissolved_protein;
-			rowdata.f_recommend_mash = datarecord.recommend_mash;
-			rowdata.f_add_after_boil = datarecord.add_after_boil;
-			rowdata.f_di_ph = datarecord.di_ph;
-			rowdata.f_acid_to_ph_57 = datarecord.acid_to_ph_57;
-			rowdata.f_inventory = datarecord.inventory;
+			fermentableData.f_name = datarecord.name;
+			fermentableData.f_origin = datarecord.origin;
+			fermentableData.f_supplier = datarecord.supplier;
+			fermentableData.f_type = datarecord.type;
+			fermentableData.f_cost = datarecord.cost;
+			fermentableData.f_yield = datarecord.yield;
+			fermentableData.f_color = datarecord.color;
+			fermentableData.f_coarse_fine_diff = datarecord.coarse_fine_diff;
+			fermentableData.f_moisture = datarecord.moisture;
+			fermentableData.f_diastatic_power = datarecord.diastatic_power;
+			fermentableData.f_protein = datarecord.protein;
+			fermentableData.f_max_in_batch = datarecord.max_in_batch;
+			fermentableData.f_graintype = datarecord.graintype;
+			fermentableData.f_dissolved_protein = datarecord.dissolved_protein;
+			fermentableData.f_recommend_mash = datarecord.recommend_mash;
+			fermentableData.f_add_after_boil = datarecord.add_after_boil;
+			fermentableData.f_di_ph = datarecord.di_ph;
+			fermentableData.f_acid_to_ph_57 = datarecord.acid_to_ph_57;
+			fermentableData.f_inventory = datarecord.inventory;
 		}
 	});
 	$("#wf_amount").jqxNumberInput( Spin3dec );
 	$('#wf_amount').on('change', function (event) {
 		console.log("amount changed: "+event.args.value);
 		$("#fermentableGrid").jqxGrid('setcellvalue', fermentableRow, 'f_amount', event.args.value);
+		fermentableData.f_amount = event.args.value;
 		if (! to_100) {
 			// Recalculate percentages
 			console.log("adjust percentages");
@@ -4506,6 +4547,7 @@
 		var oldvalue = Math.round(fermentableData.f_percentage * 10) / 10.0;
 		var newvalue = event.args.value;
 		console.log("percentage changed: "+newvalue+" old: "+oldvalue);
+		fermentableData.f_percent = newvalue;
 		var rowscount = $("#fermentableGrid").jqxGrid('getdatainformation').rowscount;
 		if ((oldvalue != newvalue) && (rowscount > 1)) {
 			var rowdata = $("#fermentableGrid").jqxGrid('getrowdata', fermentableRow);
@@ -4671,6 +4713,29 @@
 	});
 	$("#HopReady").jqxButton({ template: "success", width: '90px', theme: theme });
 	$("#HopReady").click(function () {
+		var rowID = $("#hopGrid").jqxGrid('getrowid', hopRow);
+		console.log("HopReady row:"+hopRow+" ID:"+rowID);
+		var row = {
+			h_name: $("#wh_name").val(),
+			h_origin: hopData.h_origin,
+			h_amount: parseFloat($("#wh_amount").jqxNumberInput('decimal')) / 1000,
+			h_cost: hopData.h_cost,
+			h_type: hopData.h_type,
+			h_form: hopData.h_form,
+			h_useat: $("#wh_useat").val(),
+			h_time: hopData.h_time,
+			h_alpha: hopData.h_alpha,
+			h_beta: hopData.h_beta,
+			h_hsi: hopData.h_hsi,
+			h_humulene: hopData.h_humulene,
+			h_caryophyllene: hopData.h_caryophyllene,
+			h_cohumulone: hopData.h_cohumulone,
+			h_myrcene: hopData.h_myrcene,
+			h_total_oil: hopData.h_total_oil,
+			h_inventory: hopData.h_inventory,
+			h_avail: hopData.h_avail
+		};
+		$("#hopGrid").jqxGrid('updaterow', rowID, row);
 		calcIBUs();
 	});
 	$("#wh_name").jqxInput({ theme: theme, width: 320, height: 23 });
@@ -4697,70 +4762,64 @@
 		if (event.args) {
 			var index = event.args.index;
 			var datarecord = hoplist.records[index];
-			var rowdata = $("#hopGrid").jqxGrid('getrowdata', hopRow);
+			// console.log("select another hop:"+index+" "+datarecord.name);
 			$("#wh_name").val(datarecord.name);
-			rowdata.h_name = datarecord.name;
-			rowdata.h_origin = datarecord.origin;
-			rowdata.h_cost = datarecord.cost;
-			rowdata.h_type = datarecord.type;
-			rowdata.h_form = datarecord.form;
-			rowdata.h_alpha = datarecord.alpha;
-			rowdata.h_beta = datarecord.beta;
-			rowdata.h_hsi = datarecord.hsi;
-			rowdata.h_humulene = datarecord.humulene;
-			rowdata.h_caryophyllene = datarecord.caryophyllene;
-			rowdata.h_cohumulone = datarecord.cohumulone;
-			rowdata.h_myrcene = datarecord.myrcene;
-			rowdata.h_total_oil = datarecord.total_oil;
-			rowdata.h_inventory = datarecord.inventory;
+			hopData.h_name = datarecord.name;
+			hopData.h_origin = datarecord.origin;
+			hopData.h_cost = datarecord.cost;
+			hopData.h_type = datarecord.type;
+			hopData.h_form = datarecord.form;
+			hopData.h_alpha = datarecord.alpha;
+			hopData.h_beta = datarecord.beta;
+			hopData.h_hsi = datarecord.hsi;
+			hopData.h_humulene = datarecord.humulene;
+			hopData.h_caryophyllene = datarecord.caryophyllene;
+			hopData.h_cohumulone = datarecord.cohumulone;
+			hopData.h_myrcene = datarecord.myrcene;
+			hopData.h_total_oil = datarecord.total_oil;
+			hopData.h_inventory = datarecord.inventory;
 		}
 	});
 	$("#wh_amount").jqxNumberInput( Spin1dec );
 	$('#wh_amount').on('change', function (event) {
-		console.log("amount changed: "+event.args.value);
+		console.log("amount changed: "+event.args.value+" time:"+hopData.h_time+" alpha:"+hopData.h_alpha);
 		var amount = parseFloat(event.args.value) / 1000;
-		var rowdata = $("#hopGrid").jqxGrid('getrowdata', hopRow);
-		var ibu = toIBU(rowdata.h_useat, rowdata.h_form, preboil_sg,
+		var ibu = toIBU(hopData.h_useat, hopData.h_form, preboil_sg,
 			parseFloat($("#batch_size").jqxNumberInput('decimal')),
-			amount, parseFloat(rowdata.h_time),
-			parseFloat(rowdata.h_alpha), $("#ibu_method").val()
+			amount, parseFloat(hopData.h_time),
+			parseFloat(hopData.h_alpha), $("#ibu_method").val()
 		);
-		rowdata.h_amount = amount;
-		var ibu = toIBU(rowdata.h_useat, rowdata.h_form, preboil_sg, parseFloat($("#batch_size").jqxNumberInput('decimal')),
-				parseFloat(rowdata.h_amount), parseFloat(rowdata.h_time), parseFloat(rowdata.h_alpha), $("#ibu_method").val());
+		hopData.h_amount = amount;
 		$("#wh_ibu").val(ibu);
-		calcIBUs();
 	});
 	$("#wh_ibu").jqxNumberInput( Show1dec );
 	$("#wh_time").jqxNumberInput( PosInt );
 	$("#wh_time").on('change', function (event) {
-		console.log("time changed: "+event.args.value);
-		var rowdata = $("#hopGrid").jqxGrid('getrowdata', hopRow);
 		var newtime = parseFloat(event.args.value);
 		// Check limits and correct
-		if (rowdata.h_useat == 2) {     // Boil
+		if (hopData.h_useat == 2) {     // Boil
 			if (newtime > parseFloat($("#boil_time").jqxNumberInput('decimal'))) {
 				newtime = parseFloat($("#boil_time").jqxNumberInput('decimal'));
 				$("#wh_time").val(newtime);
 			}
-			rowdata.h_time = newtime;
-		} else if (rowdata.h_useat == 4) {      // Whirlpool
+			hopData.h_time = newtime;
+		} else if (hopData.h_useat == 4) {      // Whirlpool
 			if (newtime > 120) {
 				newtime = 120;
 				$("#wh_time").val(newtime);
 			}
-			rowdata.h_time = newtime;
-		} else if (rowdata.h_useat == 5) {      // Dry hop
+			hopData.h_time = newtime;
+		} else if (hopData.h_useat == 5) {      // Dry hop
 			if (newtime > 21) {
 				newtime = 21;
 				$("#wh_time").val(newtime);
 			}
-			rowdata.h_time = newtime * 1440;
+			hopData.h_time = newtime * 1440;
 		}
-		var ibu = toIBU(rowdata.h_useat, rowdata.h_form, preboil_sg, parseFloat($("#batch_size").jqxNumberInput('decimal')),
-				parseFloat(rowdata.h_amount), parseFloat(rowdata.h_time), parseFloat(rowdata.h_alpha), $("#ibu_method").val());
+		var ibu = toIBU(hopData.h_useat, hopData.h_form, preboil_sg, parseFloat($("#batch_size").jqxNumberInput('decimal')),
+				parseFloat(hopData.h_amount), parseFloat(hopData.h_time), parseFloat(hopData.h_alpha), $("#ibu_method").val());
+		// console.log("time changed: "+newtime+" final:"+hopData.h_time+" ibu:"+ibu);
 		$("#wh_ibu").val(ibu);
-		calcIBUs();
 	});
 	$("#wh_useat").jqxDropDownList({
 		theme: theme,
@@ -4775,14 +4834,13 @@
 	$("#wh_useat").on('select', function (event) {
 		if (event.args) {
 			var index = event.args.index;
-			var rowdata = $("#hopGrid").jqxGrid('getrowdata', hopRow);
-			rowdata.h_useat = index;
+			hopData.h_useat = index;
 			if ((index == 0) || (index == 1)) {     // Mashhop or First wort hop
-				rowdata.h_time = parseFloat(dataRecord.boil_time);
+				hopData.h_time = parseFloat(dataRecord.boil_time);
 				$("#wh_time").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
-				$("#wh_time").val(rowdata.h_time);
+				$("#wh_time").val(hopData.h_time);
 			} else if (index == 3) {        // Aroma
-				rowdata.h_time = 0;
+				hopData.h_time = 0;
 				$("#wh_time").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
 				$("#wh_time").val(0);
 			} else {        // Boil, Whirlpool or Dry hop
@@ -4809,6 +4867,20 @@
 	});
 	$("#MiscReady").jqxButton({ template: "success", width: '90px', theme: theme });
 	$("#MiscReady").click(function () {
+		var rowID = $("#miscGrid").jqxGrid('getrowid', miscRow);
+		console.log("MiscReady row:"+miscRow+" ID:"+rowID);
+		var row = {
+			m_name: miscData.m_name,
+			m_amount: miscData.m_amount,
+			m_cost: miscData.m_cost,
+			m_type: miscData.m_type,
+			m_use_use: miscData.m_use_use,
+			m_time: miscData.m_time,
+			m_amount_is_weight: miscData.m_amount_is_weight,
+			m_inventory: miscData.m_inventory,
+			m_avail:  miscData.m_avail
+		};
+		$("#miscGrid").jqxGrid('updaterow', rowID, row);
 		calcMiscs();
 	});
 	$("#wm_name").jqxInput({ theme: theme, width: 320, height: 23 });
@@ -4831,41 +4903,37 @@
 		if (event.args) {
 			var index = event.args.index;
 			var datarecord = misclist.records[index];
-			var rowdata = $("#miscGrid").jqxGrid('getrowdata', miscRow);
 			$("#wm_name").val(datarecord.name);
-			rowdata.m_name = datarecord.name;
-			rowdata.m_cost = datarecord.cost;
-			rowdata.m_type = datarecord.type;
-			rowdata.m_use_use = datarecord.use_use;
-			rowdata.m_amount_is_weight = datarecord.amount_is_weight;
-			rowdata.m_inventory = datarecord.inventory;
+			miscData.m_name = datarecord.name;
+			miscData.m_cost = datarecord.cost;
+			miscData.m_type = datarecord.type;
+			miscData.m_use_use = datarecord.use_use;
+			miscData.m_amount_is_weight = datarecord.amount_is_weight;
+			miscData.m_inventory = datarecord.inventory;
 		}
 	});
 	$("#wm_amount").jqxNumberInput( Spin1dec );
 	$('#wm_amount').on('change', function (event) {
 		console.log("amount changed: "+event.args.value);
-		var amount = parseFloat(event.args.value) / 1000;
-		var rowdata = $("#miscGrid").jqxGrid('getrowdata', miscRow);
-		rowdata.m_amount = amount;
+		miscData.m_amount = parseFloat(event.args.value) / 1000;
 	});
 	$("#wm_time").jqxNumberInput( PosInt );
 	$("#wm_time").on('change', function (event) {
 		console.log("time changed: "+event.args.value);
-		var rowdata = $("#miscGrid").jqxGrid('getrowdata', miscRow);
 		var newtime = parseFloat(event.args.value);
 
-		if (rowdata.m_use_use == 2) {   // Boil
+		if (miscData.m_use_use == 2) {   // Boil
 			if (newtime > parseFloat($("#boil_time").jqxNumberInput('decimal'))) {
 				newtime = parseFloat($("#boil_time").jqxNumberInput('decimal'));
 				$("#wm_time").val(newtime);
 			}
-			rowdata.m_time = newtime;
-		} else if ((rowdata.m_use_use == 3) || (rowdata.m_use_use == 4)) {      // Primary or Secondary
+			miscData.m_time = newtime;
+		} else if ((miscData.m_use_use == 3) || (miscData.m_use_use == 4)) {      // Primary or Secondary
 			if (newtime > 21) {
 				newtime = 21;
 				$("#wm_time").val(newtime);
 			}
-			rowdata.m_time = newtime * 1440;
+			miscData.m_time = newtime * 1440;
 		}
 	});
 	$("#wm_use_use").jqxDropDownList({
@@ -4881,14 +4949,13 @@
 	$("#wm_use_use").on('select', function (event) {
 		if (event.args) {
 			var index = event.args.index;
-			var rowdata = $("#miscGrid").jqxGrid('getrowdata', miscRow);
-			rowdata.m_use_use = index;
+			miscData.m_use_use = index;
 			if ((index == 2) || (index == 3) || (index == 4)) {     // Boil, Primary or Secondary
 				$("#wm_time").jqxNumberInput({ spinButtons: true, readOnly: false, width: 110 });
 			} else {
-				rowdata.m_time = 0;
 				$("#wm_time").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
 				$("#wm_time").val(0);
+				miscData.m_time = 0;
 			}
 		}
 	});
@@ -4914,6 +4981,27 @@
 	});
 	$("#YeastReady").jqxButton({ template: "success", width: '90px', theme: theme });
 	$("#YeastReady").click(function () {
+		var rowID = $("#yeastGrid").jqxGrid('getrowid', yeastRow);
+		console.log("YeastReady row:"+yeastRow+" ID:"+rowID);
+		var row = {
+			y_name: yeastData.y_name,
+			y_laboratory: yeastData.y_laboratory,
+			y_product_id: yeastData.y_product_id,
+			y_amount: yeastData.y_amount,
+			y_cost: yeastData.y_cost,
+			y_type: yeastData.y_type,
+			y_form: yeastData.y_form,
+			y_flocculation: yeastData.y_flocculation,
+			y_min_temperature: yeastData.y_min_temperature,
+			y_max_temperature: yeastData.y_max_temperature,
+			y_attenuation: yeastData.y_attenuation,
+			y_use: yeastData.y_use,
+			y_cells: yeastData.y_cells,
+			y_tolerance: yeastData.y_tolerance,
+			y_inventory: yeastData.y_inventory,
+			y_avail: yeastData.y_avail
+		};
+		$("#yeastGrid").jqxGrid('updaterow', rowID, row);
 		calcFermentables();
 		calcYeast();
 	});
@@ -4943,25 +5031,24 @@
 		if (event.args) {
 			var index = event.args.index;
 			var datarecord = yeastlist.records[index];
-			var rowdata = $("#yeastGrid").jqxGrid('getrowdata', yeastRow);
 			$("#wy_name").val(datarecord.name);
 			$("#wy_laboratory").val(datarecord.laboratory);
 			$("#wy_product_id").val(datarecord.product_id);
-			rowdata.y_name = datarecord.name;
-			rowdata.y_cost = datarecord.cost;
-			rowdata.y_type = datarecord.type;
-			rowdata.y_form = datarecord.form;
-			rowdata.y_laboratory = datarecord.laboratory;
-			rowdata.y_product_id = datarecord.product_id;
-			rowdata.y_min_temperature = datarecord.min_temperature;
-			rowdata.y_max_temperature = datarecord.max_temperature;
-			rowdata.y_flocculation = datarecord.flocculation;
-			rowdata.y_attenuation = datarecord.attenuation;
-			rowdata.y_cells = datarecord.cells;
-			rowdata.y_inventory = datarecord.inventory;
-			if (rowdata.y_form == 0) {
+			yeastData.y_name = datarecord.name;
+			yeastData.y_cost = datarecord.cost;
+			yeastData.y_type = datarecord.type;
+			yeastData.y_form = datarecord.form;
+			yeastData.y_laboratory = datarecord.laboratory;
+			yeastData.y_product_id = datarecord.product_id;
+			yeastData.y_min_temperature = datarecord.min_temperature;
+			yeastData.y_max_temperature = datarecord.max_temperature;
+			yeastData.y_flocculation = datarecord.flocculation;
+			yeastData.y_attenuation = datarecord.attenuation;
+			yeastData.y_cells = datarecord.cells;
+			yeastData.y_inventory = datarecord.inventory;
+			if (yeastData.y_form == 0) {
 				$("#wy_pmpt_amount").html("Pak(ken):");
-			} else if (rowdata.y_form == 1) {
+			} else if (yeastData.y_form == 1) {
 				$("#wy_pmpt_amount").html("Gewicht gram:");
 			} else {
 				$("#wy_pmpt_amount").html("Volume ml:");
@@ -4973,12 +5060,11 @@
 	$("#wy_amount").jqxNumberInput( Spin1dec );
 	$('#wy_amount').on('change', function (event) {
 		console.log("amount changed: "+event.args.value);
-		var rowdata = $("#yeastGrid").jqxGrid('getrowdata', yeastRow);
-		if (rowdata.y_form == 0)        // Liquid
+		if (yeastData.y_form == 0)        // Liquid
 			var amount = parseFloat(event.args.value);
 		else
 			var amount = parseFloat(event.args.value) / 1000;
-		rowdata.y_amount = amount;
+		yeastData.y_amount = amount;
 		calcFermentables();
 		calcYeast();
 	});
@@ -4995,8 +5081,7 @@
 	$("#wy_use").on('select', function (event) {
 		if (event.args) {
 			var index = event.args.index;
-			var rowdata = $("#yeastGrid").jqxGrid('getrowdata', yeastRow);
-			rowdata.y_use = index;
+			yeastData.y_use = index;
 			calcFermentables();
 			calcYeast();
 		}
@@ -5101,7 +5186,6 @@
 	});
 	$("#MashReady").jqxButton({ template: "success", width: '90px', theme: theme });
 	$("#MashReady").click(function () {
-		$("#mashGrid").jqxGrid('sortby', 'step_temp', 'asc');
 		calcMash();
 	});
 	$("#wstep_name").jqxInput({ theme: theme, width: 320, height: 23 });
@@ -5292,13 +5376,11 @@
 	$("#wb_magnesium").jqxNumberInput( Show1wat );
 	$("#wb_sodium").jqxTooltip({ content: 'De ideale hoeveelheid Natrium is lager dan 150.'});
 	$("#wb_sodium").jqxNumberInput( Show1wat );
-
 	$("#wb_total_alkalinity").jqxNumberInput( Show1wat );
 	$("#wb_chloride").jqxTooltip({ content: 'De ideale hoeveelheid Chloride is tussen 50 en 100.'});
 	$("#wb_chloride").jqxNumberInput( Show1wat );
 	$("#wb_sulfate").jqxTooltip({ content: 'De ideale hoeveelheid Sulfaat is tussen 50 en 350.'});
 	$("#wb_sulfate").jqxNumberInput( Show1wat );
-
 	$("#wb_ph").jqxNumberInput( Show1wat );
 	// Water target profile
 	$("#pr_name").jqxDropDownList({
--- a/www/js/prod_export.js	Thu May 30 23:19:43 2019 +0200
+++ b/www/js/prod_export.js	Wed Jun 05 20:04:26 2019 +0200
@@ -32,6 +32,7 @@
 	$("#jqxRadioButton3").jqxRadioButton({ theme: theme, width: 250, height: 23 });
 	$("#jqxRadioButton4").jqxRadioButton({ theme: theme, width: 250, height: 23 });
 	$("#jqxRadioButton5").jqxRadioButton({ theme: theme, width: 250, height: 23 });
+	$("#jqxRadioButton6").jqxRadioButton({ theme: theme, width: 250, height: 23 });
 	$('#jqxRadioButton1').on('checked', function (event) {
 	       	$('#Start').jqxButton({ disabled: false });
 		choice = 1;
@@ -52,6 +53,10 @@
                 $('#Start').jqxButton({ disabled: false });
                 choice = 5;
         });
+	$('#jqxRadioButton6').on('checked', function (event) {
+		$('#Start').jqxButton({ disabled: false });
+		choice = 6;
+	});
 
 	$('#Start').jqxButton({ template: "success", width: '100px', theme: theme, disabled: true });
 	$('#Start').click(function () {
@@ -68,11 +73,14 @@
 			var url="prod_print.php?record=" + my_record;
 			window.open(url);
 		} else if (choice == 5) {
+			var url="prod_checklist.php?record=" + my_record;
+			window.open(url);
+		} else if (choice == 6) {
                         var url="prod_forum.php?record=" + my_record;
                         window.open(url);
                 }
 		// Return to the original product
-		window.location.href = my_return + "?record=" + my_record;
+		window.location.href = "prod_edit.php?record=" + my_record + "&return=" + my_return;
 	});
 
 });
--- a/www/js/rec_edit.js	Thu May 30 23:19:43 2019 +0200
+++ b/www/js/rec_edit.js	Wed Jun 05 20:04:26 2019 +0200
@@ -1525,6 +1525,21 @@
 			w2_total_alkalinity: parseFloat($("#w2_total_alkalinity").jqxNumberInput('decimal')),
 			w2_ph: parseFloat($("#w2_ph").jqxNumberInput('decimal')),
 			w2_cost: dataRecord.w2_cost,
+			wg_amount: parseFloat($("#wg_amount").jqxNumberInput('decimal')),
+			wg_calcium: parseFloat($("#wg_calcium").jqxNumberInput('decimal')),
+			wg_sulfate: parseFloat($("#wg_sulfate").jqxNumberInput('decimal')),
+			wg_chloride: parseFloat($("#wg_chloride").jqxNumberInput('decimal')),
+			wg_sodium: parseFloat($("#wg_sodium").jqxNumberInput('decimal')),
+			wg_magnesium: parseFloat($("#wg_magnesium").jqxNumberInput('decimal')),
+			wg_total_alkalinity: parseFloat($("#wg_total_alkalinity").jqxNumberInput('decimal')),
+			wg_ph: parseFloat($("#wg_ph").jqxNumberInput('decimal')),
+			wb_calcium: parseFloat($("#wb_calcium").jqxNumberInput('decimal')),
+			wb_sulfate: parseFloat($("#wb_sulfate").jqxNumberInput('decimal')),
+			wb_chloride: parseFloat($("#wb_chloride").jqxNumberInput('decimal')),
+			wb_sodium: parseFloat($("#wb_sodium").jqxNumberInput('decimal')),
+			wb_magnesium: parseFloat($("#wb_magnesium").jqxNumberInput('decimal')),
+			wb_total_alkalinity: parseFloat($("#wb_total_alkalinity").jqxNumberInput('decimal')),
+			wb_ph: parseFloat($("#wb_ph").jqxNumberInput('decimal')),
 			wa_acid_name: $("#wa_acid_name").val(),
 			wa_acid_perc: parseFloat($("#wa_acid_perc").jqxNumberInput('decimal')),
 			wa_base_name: $("#wa_base_name").val(),
@@ -1625,6 +1640,21 @@
 			{ name: 'w2_total_alkalinity', type: 'float' },
 			{ name: 'w2_ph', type: 'float' },
 			{ name: 'w2_cost', type: 'float' },
+			{ name: 'wg_amount', type: 'float' },
+			{ name: 'wg_calcium', type: 'float' },
+			{ name: 'wg_sulfate', type: 'float' },
+			{ name: 'wg_chloride', type: 'float' },
+			{ name: 'wg_sodium', type: 'float' },
+			{ name: 'wg_magnesium', type: 'float' },
+			{ name: 'wg_total_alkalinity', type: 'float' },
+			{ name: 'wg_ph', type: 'float' },
+			{ name: 'wb_calcium', type: 'float' },
+			{ name: 'wb_sulfate', type: 'float' },
+			{ name: 'wb_chloride', type: 'float' },
+			{ name: 'wb_sodium', type: 'float' },
+			{ name: 'wb_magnesium', type: 'float' },
+			{ name: 'wb_total_alkalinity', type: 'float' },
+			{ name: 'wb_ph', type: 'float' },
 			{ name: 'wa_acid_name', type: 'int' },
 			{ name: 'wa_acid_perc', type: 'int' },
 			{ name: 'wa_base_name', type: 'int' },
@@ -1712,6 +1742,21 @@
 			$("#w2_total_alkalinity").val(dataRecord.w2_total_alkalinity);
 			$("#w2_ph").val(dataRecord.w2_ph);
 			$("#w2_cost").val(dataRecord.w2_cost);
+			$("#wg_amount").val(dataRecord.wg_amount);
+			$("#wg_calcium").val(dataRecord.wg_calcium);
+			$("#wg_sulfate").val(dataRecord.wg_sulfate);
+			$("#wg_chloride").val(dataRecord.wg_chloride);
+			$("#wg_sodium").val(dataRecord.wg_sodium);
+			$("#wg_magnesium").val(dataRecord.wg_magnesium);
+			$("#wg_total_alkalinity").val(dataRecord.wg_total_alkalinity);
+			$("#wg_ph").val(dataRecord.wg_ph);
+			$("#wb_calcium").val(dataRecord.wb_calcium);
+			$("#wb_sulfate").val(dataRecord.wb_sulfate);
+			$("#wb_chloride").val(dataRecord.wb_chloride);
+			$("#wb_sodium").val(dataRecord.wb_sodium);
+			$("#wb_magnesium").val(dataRecord.wb_magnesium);
+			$("#wb_total_alkalinity").val(dataRecord.wb_total_alkalinity);
+			$("#wb_ph").val(dataRecord.wb_ph);
 			$("#wa_acid_name").val(dataRecord.wa_acid_name);
 			$("#wa_acid_perc").val(dataRecord.wa_acid_perc);
 			$("#wa_base_name").val(dataRecord.wa_base_name);
@@ -1764,9 +1809,15 @@
 				{ name: 'f_avail', type: 'int' }
 			],
 			addrow: function (rowid, rowdata, position, commit) {
+				console.log("fermentable addrow "+rowid);
 				commit(true);
 			},
 			deleterow: function (rowid, commit) {
+				console.log("fermentable deleterow "+rowid);
+				commit(true);
+			},
+			updaterow: function (rowid, rowdata, commit) {
+				console.log("fermentable updaterow "+rowid);
 				commit(true);
 			}
 		};
@@ -1776,7 +1827,6 @@
 			height: 470,
 			source: fermentableAdapter,
 			theme: theme,
-			sortmode: "many",
 			selectionmode: 'singlerow',
 			showtoolbar: true,
 			rendertoolbar: function (toolbar) {
@@ -1895,11 +1945,6 @@
 				});
 			},
 			ready: function() {
-				var datainformation = $('#fermentableGrid').jqxGrid('getdatainformation');
-                                if (datainformation.rowscount) {
-					$("#fermentableGrid").jqxGrid('sortby', 'f_added', 'asc');
-					$("#fermentableGrid").jqxGrid('sortby', 'f_amount', 'desc');
-				}
 				calcFermentables();
 				$('#jqxTabs').jqxTabs('next');
 			},
@@ -1989,11 +2034,17 @@
 				{ name: 'h_avail', type: 'int' }
                         ],
                         addrow: function (rowid, rowdata, position, commit) {
+				console.log("hop addrow "+rowid);
                                 commit(true);
                         },
                         deleterow: function (rowid, commit) {
+				console.log("hop deleterow "+rowid);
                                 commit(true);
-                        }
+                        },
+			updaterow: function (rowid, rowdata, commit) {
+				console.log("hop updaterow "+rowid);
+				commit(true);
+			}
                 };
                 var hopAdapter = new $.jqx.dataAdapter(hopSource);
                 $("#hopGrid").jqxGrid({
@@ -2001,7 +2052,6 @@
                         height: 560,
                         source: hopAdapter,
                         theme: theme,
-			sortmode: "many",
                         selectionmode: 'singlerow',
                         showtoolbar: true,
                         rendertoolbar: function (toolbar) {
@@ -2074,12 +2124,6 @@
                                 });
                         },
 			ready: function() {
-				var datainformation = $('#hopGrid').jqxGrid('getdatainformation');
-                                if (datainformation.rowscount) {
-					$("#hopGrid").jqxGrid('sortby', 'h_useat', 'asc');
-					$("#hopGrid").jqxGrid('sortby', 'h_time', 'desc');
-					$("#hopGrid").jqxGrid('sortby', 'h_amount', 'desc');
-				}
 				calcIBUs();
 				$('#jqxTabs').jqxTabs('next');
 			},
@@ -2187,11 +2231,17 @@
 				{ name: 'm_avail', type: 'int' }
                         ],
                         addrow: function (rowid, rowdata, position, commit) {
+				console.log("misc addrow "+rowid);
                                 commit(true);
                         },
                         deleterow: function (rowid, commit) {
+				console.log("misc deleterow "+rowid);
                                 commit(true);
-                        }
+                        },
+			updaterow: function (rowid, rowdata, commit) {
+				console.log("misc updaterow "+rowid);
+				commit(true);
+			}
                 };
                 var miscAdapter = new $.jqx.dataAdapter(miscSource, {
 			beforeLoadComplete: function (records) {
@@ -2258,7 +2308,6 @@
                         height: 575,
                         source: miscAdapter,
                         theme: theme,
-			sortmode: "many",
                         selectionmode: 'singlerow',
                         showtoolbar: true,
                         rendertoolbar: function (toolbar) {
@@ -2315,11 +2364,6 @@
                                 });
                         },
 			ready: function() {
-				var datainformation = $('#miscGrid').jqxGrid('getdatainformation');
-				if (datainformation.rowscount) {
-					$("#miscGrid").jqxGrid('sortby', 'm_use_use', 'asc');
-					$("#miscGrid").jqxGrid('sortby', 'm_type', 'asc');
-				}
 				$('#jqxTabs').jqxTabs('next');
 			},
 			columns: [
@@ -2366,20 +2410,23 @@
 					}, buttonclick: function (row) {
 						miscRow = row;
 						miscData = $("#miscGrid").jqxGrid('getrowdata', miscRow);
-						if (miscData.m_amount_is_weight)
-							$("#wm_pmpt_amount").html("Gewicht gram:");
-						else
-							$("#wm_pmpt_amount").html("Volume ml:");
-						$("#wm_name").val(miscData.m_name);
-						$("#wm_amount").val(miscData.m_amount * 1000);
-						if ((miscData.m_use_use == 3) || (miscData.m_use_use == 4))	// Primary or Secondary
-							$("#wm_time").val(miscData.m_time / 1440);
-						else
-							$("#wm_time").val(miscData.m_time);
-						$("#wm_use_use").val(miscData.m_use_use);
-						// show the popup window.
-						if (miscData.m_type != 4)
+						if (miscData.m_type == 4) {
+							alert("Brouwzouten wijzigen in de water tab.");
+						} else {
+							if (miscData.m_amount_is_weight)
+								$("#wm_pmpt_amount").html("Gewicht gram:");
+							else
+								$("#wm_pmpt_amount").html("Volume ml:");
+							$("#wm_name").val(miscData.m_name);
+							$("#wm_amount").val(miscData.m_amount * 1000);
+							if ((miscData.m_use_use == 3) || (miscData.m_use_use == 4))	// Primary or Secondary
+								$("#wm_time").val(miscData.m_time / 1440);
+							else
+								$("#wm_time").val(miscData.m_time);
+							$("#wm_use_use").val(miscData.m_use_use);
+							// show the popup window.
 							$("#popupMisc").jqxWindow('open');
+						}
 					}
 				}
                         ]
@@ -2412,11 +2459,17 @@
 				{ name: 'y_avail', type: 'int' }
                         ],
                         addrow: function (rowid, rowdata, position, commit) {
+				console.log("yeast addrow "+rowid);
                                 commit(true);
                         },
                         deleterow: function (rowid, commit) {
+				console.log("yeast deleterow "+rowid);
                                 commit(true);
-                        }
+                        },
+			updaterow: function (rowid, rowdata, commit) {
+				console.log("yeast updaterow "+rowid);
+				commit(true);
+			}
                 };
                 var yeastAdapter = new $.jqx.dataAdapter(yeastSource);
                 $("#yeastGrid").jqxGrid({
@@ -2424,7 +2477,6 @@
                         height: 350,
                         source: yeastAdapter,
                         theme: theme,
-			sortmode: "many",
                         selectionmode: 'singlerow',
                         showtoolbar: true,
                         rendertoolbar: function (toolbar) {
@@ -2492,10 +2544,6 @@
                                 });
                         },
 			ready: function() {
-				var datainformation = $('#yeastGrid').jqxGrid('getdatainformation');
-                                if (datainformation.rowscount) {
-					$("#yeastGrid").jqxGrid('sortby', 'y_use', 'asc');
-				}
 				calcFermentables();
 				$('#jqxTabs').jqxTabs('next');
 			},
@@ -2888,6 +2936,35 @@
 	});
 	$("#FermentableReady").jqxButton({ template: "success", width: '90px', theme: theme });
 	$("#FermentableReady").click(function () {
+		var rowID = $("#fermentableGrid").jqxGrid('getrowid', fermentableRow);
+		console.log("FermentableReady row:"+fermentableRow+" ID:"+rowID);
+		var row = {
+			f_name: fermentableData.f_name,
+			f_origin: fermentableData.f_origin,
+			f_supplier: fermentableData.f_supplier,
+			f_amount: fermentableData.f_amount,
+			f_cost: fermentableData.f_cost,
+			f_type: fermentableData.f_type,
+			f_yield: fermentableData.f_yield,
+			f_color: fermentableData.f_color,
+			f_coarse_fine_diff: fermentableData.f_coarse_fine_diff,
+			f_moisture: fermentableData.f_moisture,
+			f_diastatic_power: fermentableData.f_diastatic_power,
+			f_protein: fermentableData.f_protein,
+			f_max_in_batch: fermentableData.f_max_in_batch,
+			f_graintype: fermentableData.f_graintype,
+			f_added: fermentableData.f_added,
+			f_dissolved_protein: fermentableData.f_dissolved_protein,
+			f_recommend_mash: fermentableData.f_recommend_mash,
+			f_add_after_boil: fermentableData.f_add_after_boil,
+			f_adjust_to_total_100: fermentableData.f_adjust_to_total_100,
+			f_percentage: fermentableData.f_percentage,
+			f_di_ph: fermentableData.f_di_ph,
+			f_acid_to_ph_57: fermentableData.f_acid_to_ph_57,
+			f_inventory: fermentableData.f_inventory,
+			f_avail: fermentableData.f_avail
+		};
+		$("#fermentableGrid").jqxGrid('updaterow', rowID, row);
 		// Recalc percentages
 		calcFermentables();
 		calcIBUs();
@@ -2918,33 +2995,33 @@
 		if (event.args) {
 			var index = event.args.index;
 			var datarecord = fermentablelist.records[index];
-			var rowdata = $("#fermentableGrid").jqxGrid('getrowdata', fermentableRow);
 			$("#wf_name").val(datarecord.name);
-			rowdata.f_name = datarecord.name;
-			rowdata.f_origin = datarecord.origin;
-			rowdata.f_supplier = datarecord.supplier;
-			rowdata.f_type = datarecord.type;
-			rowdata.f_cost = datarecord.cost;
-			rowdata.f_yield = datarecord.yield;
-			rowdata.f_color = datarecord.color;
-			rowdata.f_coarse_fine_diff = datarecord.coarse_fine_diff;
-			rowdata.f_moisture = datarecord.moisture;
-			rowdata.f_diastatic_power = datarecord.diastatic_power;
-			rowdata.f_protein = datarecord.protein;
-			rowdata.f_max_in_batch = datarecord.max_in_batch;
-			rowdata.f_graintype = datarecord.graintype;
-			rowdata.f_dissolved_protein = datarecord.dissolved_protein;
-			rowdata.f_recommend_mash = datarecord.recommend_mash;
-			rowdata.f_add_after_boil = datarecord.add_after_boil;
-			rowdata.f_di_ph = datarecord.di_ph;
-			rowdata.f_acid_to_ph_57 = datarecord.acid_to_ph_57;
-			rowdata.f_inventory = datarecord.inventory;
+			fermentableData.f_name = datarecord.name;
+			fermentableData.f_origin = datarecord.origin;
+			fermentableData.f_supplier = datarecord.supplier;
+			fermentableData.f_type = datarecord.type;
+			fermentableData.f_cost = datarecord.cost;
+			fermentableData.f_yield = datarecord.yield;
+			fermentableData.f_color = datarecord.color;
+			fermentableData.f_coarse_fine_diff = datarecord.coarse_fine_diff;
+			fermentableData.f_moisture = datarecord.moisture;
+			fermentableData.f_diastatic_power = datarecord.diastatic_power;
+			fermentableData.f_protein = datarecord.protein;
+			fermentableData.f_max_in_batch = datarecord.max_in_batch;
+			fermentableData.f_graintype = datarecord.graintype;
+			fermentableData.f_dissolved_protein = datarecord.dissolved_protein;
+			fermentableData.f_recommend_mash = datarecord.recommend_mash;
+			fermentableData.f_add_after_boil = datarecord.add_after_boil;
+			fermentableData.f_di_ph = datarecord.di_ph;
+			fermentableData.f_acid_to_ph_57 = datarecord.acid_to_ph_57;
+			fermentableData.f_inventory = datarecord.inventory;
 		}
 	});
 	$("#wf_amount").jqxNumberInput( Spin3dec );
 	$('#wf_amount').on('change', function (event) {
 		console.log("amount changed: "+event.args.value);
 		$("#fermentableGrid").jqxGrid('setcellvalue', fermentableRow, 'f_amount', event.args.value);
+		fermentableData.f_amount = event.args.value;
 		if (! to_100) {
 			// Recalculate percentages
 			console.log("adjust percentages");
@@ -2974,6 +3051,7 @@
 		var oldvalue = Math.round(fermentableData.f_percentage * 10) / 10.0;
 		var newvalue = event.args.value;
 		console.log("percentage changed: "+newvalue+" old: "+oldvalue);
+		fermentableData.f_percent = newvalue;
 		var rowscount = $("#fermentableGrid").jqxGrid('getdatainformation').rowscount;
 		if ((oldvalue != newvalue) && (rowscount > 1)) {
 			var rowdata = $("#fermentableGrid").jqxGrid('getrowdata', fermentableRow);
@@ -3141,6 +3219,29 @@
 	});
 	$("#HopReady").jqxButton({ template: "success", width: '90px', theme: theme });
 	$("#HopReady").click(function () {
+		var rowID = $("#hopGrid").jqxGrid('getrowid', hopRow);
+		console.log("HopReady row:"+hopRow+" ID:"+rowID);
+		var row = {
+			h_name: $("#wh_name").val(),
+			h_origin: hopData.h_origin,
+			h_amount: parseFloat($("#wh_amount").jqxNumberInput('decimal')) / 1000,
+			h_cost: hopData.h_cost,
+			h_type: hopData.h_type,
+			h_form: hopData.h_form,
+			h_useat: $("#wh_useat").val(),
+			h_time: hopData.h_time,
+			h_alpha: hopData.h_alpha,
+			h_beta: hopData.h_beta,
+			h_hsi: hopData.h_hsi,
+			h_humulene: hopData.h_humulene,
+			h_caryophyllene: hopData.h_caryophyllene,
+			h_cohumulone: hopData.h_cohumulone,
+			h_myrcene: hopData.h_myrcene,
+			h_total_oil: hopData.h_total_oil,
+			h_inventory: hopData.h_inventory,
+			h_avail: hopData.h_avail
+		};
+		$("#hopGrid").jqxGrid('updaterow', rowID, row);
 		calcIBUs();
 	});
 	$("#wh_name").jqxInput({ theme: theme, width: 320, height: 23 });
@@ -3167,71 +3268,63 @@
 		if (event.args) {
 			var index = event.args.index;
 			var datarecord = hoplist.records[index];
-			var rowdata = $("#hopGrid").jqxGrid('getrowdata', hopRow);
 			$("#wh_name").val(datarecord.name);
-			rowdata.h_name = datarecord.name;
-			rowdata.h_origin = datarecord.origin;
-			rowdata.h_cost = datarecord.cost;
-			rowdata.h_type = datarecord.type;
-			rowdata.h_form = datarecord.form;
-			rowdata.h_alpha = datarecord.alpha;
-			rowdata.h_beta = datarecord.beta;
-			rowdata.h_hsi = datarecord.hsi;
-			rowdata.h_humulene = datarecord.humulene;
-			rowdata.h_caryophyllene = datarecord.caryophyllene;
-			rowdata.h_cohumulone = datarecord.cohumulone;
-			rowdata.h_myrcene = datarecord.myrcene;
-			rowdata.h_total_oil = datarecord.total_oil;
-			rowdata.h_inventory = datarecord.inventory;
+			hopData.h_name = datarecord.name;
+			hopData.h_origin = datarecord.origin;
+			hopData.h_cost = datarecord.cost;
+			hopData.h_type = datarecord.type;
+			hopData.h_form = datarecord.form;
+			hopData.h_alpha = datarecord.alpha;
+			hopData.h_beta = datarecord.beta;
+			hopData.h_hsi = datarecord.hsi;
+			hopData.h_humulene = datarecord.humulene;
+			hopData.h_caryophyllene = datarecord.caryophyllene;
+			hopData.h_cohumulone = datarecord.cohumulone;
+			hopData.h_myrcene = datarecord.myrcene;
+			hopData.h_total_oil = datarecord.total_oil;
+			hopData.h_inventory = datarecord.inventory;
 		}
 	});
 	$("#wh_amount").jqxNumberInput( Spin1dec );
 	$('#wh_amount').on('change', function (event) {
-		console.log("amount changed: "+event.args.value);
+		console.log("amount changed: "+event.args.value+" time:"+hopData.h_time+" alpha:"+hopData.h_alpha);
 		var amount = parseFloat(event.args.value) / 1000;
-		var rowdata = $("#hopGrid").jqxGrid('getrowdata', hopRow);
 
-		var ibu = toIBU(rowdata.h_useat, rowdata.h_form, preboil_sg,
+		var ibu = toIBU(hopData.h_useat, hopData.h_form, preboil_sg,
 			parseFloat($("#batch_size").jqxNumberInput('decimal')),
-			amount, parseFloat(rowdata.h_time),
-			parseFloat(rowdata.h_alpha), $("#ibu_method").val()
+			amount, parseFloat(hopData.h_time),
+			parseFloat(hopData.h_alpha), $("#ibu_method").val()
 		);
-		rowdata.h_amount = amount;
-		var ibu = toIBU(rowdata.h_useat, rowdata.h_form, preboil_sg, parseFloat($("#batch_size").jqxNumberInput('decimal')),
-				parseFloat(rowdata.h_amount), parseFloat(rowdata.h_time), parseFloat(rowdata.h_alpha), $("#ibu_method").val());
+		hopData.h_amount = amount;
 		$("#wh_ibu").val(ibu);
-		calcIBUs();
 	});
 	$("#wh_ibu").jqxNumberInput( Show1dec );
 	$("#wh_time").jqxNumberInput( PosInt );
 	$("#wh_time").on('change', function (event) {
-		console.log("time changed: "+event.args.value);
-		var rowdata = $("#hopGrid").jqxGrid('getrowdata', hopRow);
 		var newtime = parseFloat(event.args.value);
 		// Check limits and correct
-		if (rowdata.h_useat == 2) {	// Boil
+		if (hopData.h_useat == 2) {	// Boil
 			if (newtime > parseFloat($("#boil_time").jqxNumberInput('decimal'))) {
 				newtime = parseFloat($("#boil_time").jqxNumberInput('decimal'));
 				$("#wh_time").val(newtime);
 			}
-			rowdata.h_time = newtime;
-		} else if (rowdata.h_useat == 4) {	// Whirlpool
+			hopData.h_time = newtime;
+		} else if (hopData.h_useat == 4) {	// Whirlpool
 			if (newtime > 120) {
 				newtime = 120;
 				$("#wh_time").val(newtime);
 			}
-			rowdata.h_time = newtime;
-		} else if (rowdata.h_useat == 5) {	// Dry hop
+			hopData.h_time = newtime;
+		} else if (hopData.h_useat == 5) {	// Dry hop
 			if (newtime > 21) {
 				newtime = 21;
 				$("#wh_time").val(newtime);
 			}
-			rowdata.h_time = newtime * 1440;
+			hopData.h_time = newtime * 1440;
 		}
-		var ibu = toIBU(rowdata.h_useat, rowdata.h_form, preboil_sg, parseFloat($("#batch_size").jqxNumberInput('decimal')),
-			parseFloat(rowdata.h_amount), parseFloat(rowdata.h_time), parseFloat(rowdata.h_alpha), $("#ibu_method").val());
+		var ibu = toIBU(hopData.h_useat, hopData.h_form, preboil_sg, parseFloat($("#batch_size").jqxNumberInput('decimal')),
+			parseFloat(hopData.h_amount), parseFloat(hopData.h_time), parseFloat(hopData.h_alpha), $("#ibu_method").val());
 		$("#wh_ibu").val(ibu);
-		calcIBUs();
 	});
 	$("#wh_useat").jqxDropDownList({
 		theme: theme,
@@ -3246,14 +3339,13 @@
 	$("#wh_useat").on('select', function (event) {
 		if (event.args) {
 			var index = event.args.index;
-			var rowdata = $("#hopGrid").jqxGrid('getrowdata', hopRow);
-			rowdata.h_useat = index;
+			hopData.h_useat = index;
 			if ((index == 0) || (index == 1)) {	// Mashhop or First wort hop
-				rowdata.h_time = parseFloat(dataRecord.boil_time);
+				hopData.h_time = parseFloat(dataRecord.boil_time);
 				$("#wh_time").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
-				$("#wh_time").val(rowdata.h_time);
+				$("#wh_time").val(hopData.h_time);
 			} else if (index == 3) {	// Aroma
-				rowdata.h_time = 0;
+				hopData.h_time = 0;
 				$("#wh_time").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
 				$("#wh_time").val(0);
 			} else {	// Boil, Whirlpool or Dry hop
@@ -3279,6 +3371,22 @@
 		modalOpacity: 0.40
 	});
 	$("#MiscReady").jqxButton({ template: "success", width: '90px', theme: theme });
+	$("#MiscReady").click(function () {
+		var rowID = $("#miscGrid").jqxGrid('getrowid', miscRow);
+		console.log("MiscReady row:"+miscRow+" ID:"+rowID);
+		var row = {
+			m_name: miscData.m_name,
+			m_amount: miscData.m_amount,
+			m_cost: miscData.m_cost,
+			m_type: miscData.m_type,
+			m_use_use: miscData.m_use_use,
+			m_time: miscData.m_time,
+			m_amount_is_weight: miscData.m_amount_is_weight,
+			m_inventory: miscData.m_inventory,
+			m_avail:  miscData.m_avail
+		};
+		$("#miscGrid").jqxGrid('updaterow', rowID, row);
+        });
 	$("#wm_name").jqxInput({ theme: theme, width: 320, height: 23 });
 	$("#wm_instock").jqxCheckBox({ theme: theme, height: 23 });
 	$("#wm_instock").on('change', function (event) {
@@ -3299,41 +3407,37 @@
 		if (event.args) {
 			var index = event.args.index;
 			var datarecord = misclist.records[index];
-			var rowdata = $("#miscGrid").jqxGrid('getrowdata', miscRow);
 			$("#wm_name").val(datarecord.name);
-			rowdata.m_name = datarecord.name;
-			rowdata.m_cost = datarecord.cost;
-			rowdata.m_type = datarecord.type;
-			rowdata.m_use_use = datarecord.use_use;
-			rowdata.m_amount_is_weight = datarecord.amount_is_weight;
-			rowdata.m_inventory = datarecord.inventory;
+			miscData.m_name = datarecord.name;
+			miscData.m_cost = datarecord.cost;
+			miscData.m_type = datarecord.type;
+			miscData.m_use_use = datarecord.use_use;
+			miscData.m_amount_is_weight = datarecord.amount_is_weight;
+			miscData.m_inventory = datarecord.inventory;
 		}
 	});
 	$("#wm_amount").jqxNumberInput( Spin1dec );
 	$('#wm_amount').on('change', function (event) {
 		console.log("amount changed: "+event.args.value);
-		var amount = parseFloat(event.args.value) / 1000;
-		var rowdata = $("#miscGrid").jqxGrid('getrowdata', miscRow);
-		rowdata.m_amount = amount;
+		miscData.m_amount = parseFloat(event.args.value) / 1000;
 	});
 	$("#wm_time").jqxNumberInput( PosInt );
 	$("#wm_time").on('change', function (event) {
 		console.log("time changed: "+event.args.value);
-		var rowdata = $("#miscGrid").jqxGrid('getrowdata', miscRow);
 		var newtime = parseFloat(event.args.value);
 
-		if (rowdata.m_use_use == 2) {	// Boil
+		if (miscData.m_use_use == 2) {	// Boil
 			if (newtime > parseFloat($("#boil_time").jqxNumberInput('decimal'))) {
 				newtime = parseFloat($("#boil_time").jqxNumberInput('decimal'));
 				$("#wm_time").val(newtime);
 			}
-		        rowdata.m_time = newtime;
-		} else if ((rowdata.m_use_use == 3) || (rowdata.m_use_use == 4)) {	// Primary or Secondary
+		        miscData.m_time = newtime;
+		} else if ((miscData.m_use_use == 3) || (miscData.m_use_use == 4)) {	// Primary or Secondary
 			if (newtime > 21) {
 				newtime = 21;
 				$("#wm_time").val(newtime);
 			}
-			rowdata.m_time = newtime * 1440;
+			miscData.m_time = newtime * 1440;
 		}
 	});
 	$("#wm_use_use").jqxDropDownList({
@@ -3349,12 +3453,11 @@
 	$("#wm_use_use").on('select', function (event) {
 		if (event.args) {
 			var index = event.args.index;
-			var rowdata = $("#miscGrid").jqxGrid('getrowdata', miscRow);
-			rowdata.m_use_use = index;
+			miscData.m_use_use = index;
 			if ((index == 2) || (index == 3) || (index == 4)) {	// Boil, Primary or Secondary
 				$("#wm_time").jqxNumberInput({ spinButtons: true, readOnly: false, width: 110 });
 			} else {
-				rowdata.m_time = 0;
+				miscData.m_time = 0;
 				$("#wm_time").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
 				$("#wm_time").val(0);
 			}
@@ -3379,6 +3482,27 @@
 	});
 	$("#YeastReady").jqxButton({ template: "success", width: '90px', theme: theme });
 	$("#YeastReady").click(function () {
+		var rowID = $("#yeastGrid").jqxGrid('getrowid', yeastRow);
+		console.log("YeastReady row:"+yeastRow+" ID:"+rowID);
+		var row = {
+			y_name: yeastData.y_name,
+			y_laboratory: yeastData.y_laboratory,
+			y_product_id: yeastData.y_product_id,
+			y_amount: yeastData.y_amount,
+			y_cost: yeastData.y_cost,
+			y_type: yeastData.y_type,
+			y_form: yeastData.y_form,
+			y_flocculation: yeastData.y_flocculation,
+			y_min_temperature: yeastData.y_min_temperature,
+			y_max_temperature: yeastData.y_max_temperature,
+			y_attenuation: yeastData.y_attenuation,
+			y_use: yeastData.y_use,
+			y_cells: yeastData.y_cells,
+			y_tolerance: yeastData.y_tolerance,
+			y_inventory: yeastData.y_inventory,
+			y_avail: yeastData.y_avail
+		};
+		$("#yeastGrid").jqxGrid('updaterow', rowID, row);
 		calcFermentables();
 	});
 	$("#wy_name").jqxInput({ theme: theme, width: 320, height: 23 });
@@ -3407,25 +3531,24 @@
 		if (event.args) {
 			var index = event.args.index;
 			var datarecord = yeastlist.records[index];
-			var rowdata = $("#yeastGrid").jqxGrid('getrowdata', yeastRow);
 			$("#wy_name").val(datarecord.name);
 			$("#wy_laboratory").val(datarecord.laboratory);
 			$("#wy_product_id").val(datarecord.product_id);
-			rowdata.y_name = datarecord.name;
-			rowdata.y_cost = datarecord.cost;
-			rowdata.y_type = datarecord.type;
-			rowdata.y_form = datarecord.form;
-			rowdata.y_laboratory = datarecord.laboratory;
-			rowdata.y_product_id = datarecord.product_id;
-			rowdata.y_min_temperature = datarecord.min_temperature;
-			rowdata.y_max_temperature = datarecord.max_temperature;
-			rowdata.y_flocculation = datarecord.flocculation;
-			rowdata.y_attenuation = datarecord.attenuation;
-			rowdata.y_cells = datarecord.cells;
-			rowdata.y_inventory = datarecord.inventory;
-			if (rowdata.y_form == 0) {
+			yeastData.y_name = datarecord.name;
+			yeastData.y_cost = datarecord.cost;
+			yeastData.y_type = datarecord.type;
+			yeastData.y_form = datarecord.form;
+			yeastData.y_laboratory = datarecord.laboratory;
+			yeastData.y_product_id = datarecord.product_id;
+			yeastData.y_min_temperature = datarecord.min_temperature;
+			yeastData.y_max_temperature = datarecord.max_temperature;
+			yeastData.y_flocculation = datarecord.flocculation;
+			yeastData.y_attenuation = datarecord.attenuation;
+			yeastData.y_cells = datarecord.cells;
+			yeastData.y_inventory = datarecord.inventory;
+			if (yeastData.y_form == 0) {
 				$("#wy_pmpt_amount").html("Pak(ken):");
-			} else if (rowdata.y_form == 1) {
+			} else if (yeastData.y_form == 1) {
 				$("#wy_pmpt_amount").html("Gewicht gram:");
 			} else {
 				$("#wy_pmpt_amount").html("Volume ml:");
@@ -3436,12 +3559,11 @@
 	$("#wy_amount").jqxNumberInput( Spin1dec );
 	$('#wy_amount').on('change', function (event) {
 		console.log("amount changed: "+event.args.value);
-		var rowdata = $("#yeastGrid").jqxGrid('getrowdata', yeastRow);
-		if (rowdata.y_form == 0)	// Liquid
+		if (yeastData.y_form == 0)	// Liquid
 			var amount = parseFloat(event.args.value);
 		else
 			var amount = parseFloat(event.args.value) / 1000;
-		rowdata.y_amount = amount;
+		yeastData.y_amount = amount;
 		calcFermentables();
 	});
 	$("#wy_use").jqxDropDownList({
@@ -3457,8 +3579,7 @@
 	$("#wy_use").on('select', function (event) {
 		if (event.args) {
 			var index = event.args.index;
-			var rowdata = $("#yeastGrid").jqxGrid('getrowdata', yeastRow);
-			rowdata.y_use = index;
+			yeastData.y_use = index;
 			calcFermentabes();
 		}
 	});
@@ -3527,7 +3648,6 @@
 	});
 	$("#MashReady").jqxButton({ template: "success", width: '90px', theme: theme });
 	$("#MashReady").click(function () {
-		$("#mashGrid").jqxGrid('sortby', 'step_temp', 'asc');
 		calcMash();
 	});
 	$("#wstep_name").jqxInput({ theme: theme, width: 320, height: 23 });
--- a/www/prod_beerxml.php	Thu May 30 23:19:43 2019 +0200
+++ b/www/prod_beerxml.php	Wed Jun 05 20:04:26 2019 +0200
@@ -96,6 +96,34 @@
 xmlwriter_text($xw, sprintf("%.3f",floatval($row['fg'])));
 xmlwriter_end_element($xw);
 
+if ($row['brew_cooling_to'] > 0) {
+	xmlwriter_start_element($xw, 'BMS_COOLING_TO');
+	xmlwriter_text($xw, sprintf("%.1f",floatval($row['brew_cooling_to'])));
+	xmlwriter_end_element($xw);
+}
+
+if ($row['brew_whirlpool9'] > 0) {
+	xmlwriter_start_element($xw, 'BMS_WHIRLPOOL9');
+	xmlwriter_text($xw, sprintf("%.0f",floatval($row['brew_whirlpool9'])));
+	xmlwriter_end_element($xw);
+}
+if ($row['brew_whirlpool7'] > 0) {
+        xmlwriter_start_element($xw, 'BMS_WHIRLPOOL7');
+        xmlwriter_text($xw, sprintf("%.0f",floatval($row['brew_whirlpool7'])));
+        xmlwriter_end_element($xw);
+}
+if ($row['brew_whirlpool6'] > 0) {
+        xmlwriter_start_element($xw, 'BMS_WHIRLPOOL6');
+        xmlwriter_text($xw, sprintf("%.0f",floatval($row['brew_whirlpool6'])));
+        xmlwriter_end_element($xw);
+}
+if ($row['brew_whirlpool2'] > 0) {
+        xmlwriter_start_element($xw, 'BMS_WHIRLPOOL2');
+        xmlwriter_text($xw, sprintf("%.0f",floatval($row['brew_whirlpool2'])));
+        xmlwriter_end_element($xw);
+}
+
+
 // Style
 xmlwriter_start_element($xw, 'STYLE');
 
@@ -289,7 +317,7 @@
 	xmlwriter_end_element($xw);
 
 	xmlwriter_start_element($xw, 'ADD_AFTER_BOIL');
-	($item['f_add_after_boil']) ? xmlwriter_text($xw, 'TRUE') : xmlwriter_text($xw, 'FALSE');
+	($item['f_added'] > 1) ? xmlwriter_text($xw, 'TRUE') : xmlwriter_text($xw, 'FALSE');
 	xmlwriter_end_element($xw);
 
 	xmlwriter_start_element($xw, 'ORIGIN');
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/www/prod_checklist.php	Wed Jun 05 20:04:26 2019 +0200
@@ -0,0 +1,588 @@
+<?php
+require_once($_SERVER['DOCUMENT_ROOT'].'/includes/global.inc.php');
+require_once($_SERVER['DOCUMENT_ROOT'].'/includes/formulas.php');
+require_once($_SERVER['DOCUMENT_ROOT'].'/fpdf/fpdf.php');
+
+
+$link = mysqli_connect(DBASE_HOST,DBASE_USER,DBASE_PASS,DBASE_NAME);
+if (! $link) {
+	die('Connect Error (' . mysqli_connect_errno() . ') ' . mysqli_connect_error());
+}
+if (! mysqli_set_charset($link, "utf8" )) {
+	echo "error";
+	return 1;
+}
+
+setlocale ( LC_ALL, 'nl_NL.UTF-8');
+$record = $_GET["record"];
+$result = mysqli_query($link, "SELECT * FROM products WHERE record='".$record."'");
+$row = mysqli_fetch_array($result);
+
+date_default_timezone_set('Europe/Amsterdam');
+$prdate = date(DATE_RFC2822);
+
+
+class PDF_MySQL_Table extends FPDF
+{
+	function Checkheader($text) {
+		$this->SetFont('Arial','B',10);
+		$this->Cell(0, 4,$text,0,0,'L',true);
+		$this->SetFont('Arial','',10);
+		$this->Ln(6);
+	}
+
+	function Checkline($text) {
+		$this->Cell(2, 4,' ',0,0,'L',true);
+		$this->Cell(4, 4,' ',1,0,'L',true);
+		$this->Cell(0, 4,' '.$text,0,1,'L',true);
+		$this->Ln(1);
+	}
+
+	function Checklist($row) {
+
+		global $my_grain_absorbtion;
+		global $my_brix_correction;
+		$mashwater = 0;
+		$numsalts = 0;
+
+		$this->AddPage();
+		$this->SetFillColor(255,255,255);
+
+		$ferms = json_decode($row['json_fermentables'], true);
+		$hops = json_decode($row['json_hops'], true);
+		$miscs = json_decode($row['json_miscs'], true);
+		$yeasts = json_decode($row['json_yeasts'], true);
+
+		if ($row['starter_enable'] && $row['prop1_volume']) {
+			$this->Checkheader('Giststarter maken');
+			$days = 0;
+			$last = 0;
+			for ($i = 1; $i < 5; $i++) {
+				$pt = "prop".$i."_type";
+				$pv = "prop".$i."_volume";
+				if (floatval($row[$pv])) {
+					$last = $i;
+					if ($row[$pt] == 0)
+						$days += 2;
+					else if ($row[$pt] == 1)
+						$days += 4;
+					else
+						$days += 6;
+				}
+			}
+			$this->Checkline("begin ongeveer ".$days." dagen voor de brouwdag met de giststarter");
+			for ($i = 1; $i < 5; $i++) {
+				$pt = "prop".$i."_type";
+				$pv = "prop".$i."_volume";
+				if (floatval($row[$pv])) {
+					$s  = "Starter stap ".$i.", van ".sprintf("%.3f",floatval($row[$pv]));
+					$s .= " liter maken met SG ".sprintf("%.3f",floatval($row['starter_sg']));
+					$this->Checkline($s);
+					if ($row[$pt] == 0) {
+						$s = "ongeveer 24 uur op een magneetroerder";
+					} else if ($row[$pt] == 1) {
+						$s = "enkele dagen regelmatig schudden";
+					} else {
+						$s = "bijna een week rustig laten staan";
+					}
+					$s .= " tot er voldoende gist is";
+					$this->Checkline($s);
+					if ($i < $last) {
+						$this->Checkline("starter minstens 24 uur in de koeling laten uitzakken");
+						$this->Checkline("starter uit de koelkast halen en afgieten");
+					} else {
+						$this->Checkline("starter in de koeling zetten tot de brouwdag");
+						$this->Checkline("starter op de brouwdag uit de koelkast halen en afgieten");
+					}
+				}
+			}
+			$this->Ln(5);
+		}
+
+		$this->Checkheader('Water en -behandeling');
+		if ($row['w1_name']) {
+			$this->Checkline(sprintf("%.1f",floatval($row['w1_amount'])).' liter water '.$row['w1_name']);
+			$mashwater += floatval($row['w1_amount']);
+		}
+		if ($row['w2_name']) {
+			$this->Checkline(sprintf("%.1f",floatval($row['w2_amount'])).' liter water '.$row['w2_name']);
+			$mashwater += floatval($row['w2_amount']);
+		}
+		foreach($miscs as $item) {
+			if ($item['m_type'] == 4) {	// Only the water agents
+				$unit = ($item['m_amount_is_weight']) ? " gr ":" ml ";
+				$this->Checkline(sprintf("%.1f",floatval($item['m_amount'] * 1000)).$unit.$item['m_name']);
+				$numsalts++;
+			}
+		}
+		$this->Ln(5);
+
+		$this->Checkheader('Mout afwegen en schroten');
+		foreach($ferms as $item) {
+			if ($item['f_added'] == 0) {	// to mash
+				$s = sprintf("%.3f",floatval($item['f_amount'])).' kg `';
+				$s .= iconv('UTF-8','windows-1252',$item['f_name']);
+				$s .= '` ('.iconv('UTF-8','windows-1252',$item['f_supplier']).')';
+				$this->Checkline($s);
+			}
+		}
+		$this->Checkline('mout schroten');
+		$this->Ln(5);
+
+		$this->Checkheader('Maischen');
+		$mvol = 0;
+		$msugars = 0;	// mash sugars
+		$grainabsorbtion = 0;
+		$arr = json_decode($row['json_mashs'], true);
+		if (count($arr) > 0) {
+			$loop = 0;
+			foreach($arr as $item) {
+				if ($item['step_type'] == 0)
+					$mvol += $item['step_infuse_amount'];	// We need this later.
+				if ($loop == 0) {
+					if ($item['step_type'] == 0)
+						$l = $item['step_infuse_amount'];
+					else
+						$l = $mashwater;
+					$s = sprintf("%.1f",$l).' liter water opwarmen tot ';
+					$s .= sprintf("%.1f",$item['step_temp']).' '.DEG.'C (';
+					$s .= sprintf("%.1f",kettle_cm($l,$row['eq_tun_volume'],$row['eq_tun_height']));
+					$s .= ' cm onder de rand)';
+					$this->Checkline($s);
+					if ($numsalts > 0)
+						$this->Checkline('brouwzouten en -zuren toevoegen');
+					$this->Checkline('mout storten en inmaischen');
+					foreach($hops as $item2) {
+						if ($item2['h_useat'] == 0) {
+							$s = sprintf("%.1f",$item2['h_amount']*1000).' gr `';
+							$s .= iconv('UTF-8','windows-1252',$item2['h_name']).'` toevoegen';
+							$this->Checkline($s);
+						}
+					}
+					foreach($miscs as $item3) {
+						if ($item3['m_use_use'] == 1 && $item3['m_type'] != 4) {	// Only if not a water agent
+							$unit = ($item3['m_amount_is_weight']) ? " gr ":" ml ";
+							$s = sprintf("%.2f",$item3['m_amount']*1000).$unit.'`';
+							$s .= iconv('UTF-8','windows-1252',$item3['m_name']).'` toevoegen';
+							$this->Checkline($s);
+						}
+					}
+					$this->Checkline($item['step_time'].' min. bij '.$item['step_temp'].' '.DEG.'C');
+					$this->Checkline('pH meten en bijstellen (doel pH beslag: '.sprintf("%.1f",$row['mash_ph']).' pH)');
+				} else {
+					if ($item['step_type'] == 0) {	// Infusion
+						$s = 'toevoegen '.$item['step_infuse_amount'].' liter water van xx '.DEG.'C';
+					} else if ($item['step_type'] == 1) {	// Direct heat
+						$s = 'opwarmen tot '.$item['step_temp'].' '.DEG.'C';
+					} else {	// Decoction
+						$s = 'uitnemen, opwarmen, koken en terugstorten van '.$item['step_infuse_amount'].' liter deelbeslag';
+					}
+					$this->Checkline($s);
+					$this->Checkline($item['step_time'].' min. bij '.$item['step_temp'].' '.DEG.'C');
+				}
+				$loop++;
+			}
+			$est_mash_sg = 0;
+			foreach($ferms as $item) {
+				if ($item['f_added'] == 0) {
+					$d = $item['f_amount'] * ($item['f_yield'] / 100) * (1 - $item['f_moisture'] / 100);
+					$mvol += $item['f_amount'] * $item['f_moisture'] / 100;
+					$grainabsorbtion += $my_grain_absorbtion * $item['f_amount'];
+					$msugars += $d;
+				}
+			}
+			$sugardensity = 1.611;
+			$v = $msugars / $sugardensity + $mvol;
+			$plato = 1000 * $msugars / ($v * 10);	// deg. Plato
+			$mash_sg = plato_to_sg($plato);
+			$this->Checkline('doel SG eind maischen: '.density_str($mash_sg));
+		}
+		if ($this->GetY() > 200)
+			$this->AddPage();
+		else
+			$this->Ln(5);
+
+		$acidtype = array( 'Melkzuur', 'Zoutzuur', 'Fosforzuur', 'Zwavelzuur' );
+		$this->Checkheader('Filteren en spoelen');
+		$s = sprintf("%.1f",$row['sparge_volume']).' liter spoelwater opwarmen tot '.sprintf("%.1f",$row['sparge_temp']).' '.DEG.'C';
+		$this->Checkline($s);
+		$s = 'spoelwater aanzuren tot pH <= '.sprintf("%.1f",$row['sparge_ph']).' met ';
+		$s .= sprintf("%.1f",$row['sparge_acid_amount']*1000).' ml. '.$acidtype[$row['sparge_acid_type']];
+		$this->Checkline($s);
+		$spoelw = ($row['boil_size'] - $mashwater + $grainabsorbtion + $row['eq_lauter_deadspace']) * 1.03;	// A small heat correction
+		$this->Checkline('spoelen met ongeveer '.sprintf("%.1f",$spoelw).' liter spoelwater');
+		$s = 'doelvolume in kookketel: '.sprintf("%.1f",$row['boil_size'] * 1.04).' liter (';
+		$s .= sprintf("%.1f",kettle_cm($row['boil_size'] * 1.04,$row['eq_kettle_volume'],$row['eq_kettle_height'])).' cm onder de rand)';
+		$this->Checkline($s);
+		$pre_sg = estimate_sg($msugars * floatval($row['efficiency']) / 100,floatval($row['boil_size']));
+		$this->Checkline('doel SG in kookketel: '.density_str($pre_sg));
+		foreach($hops as $item2) {
+			if ($item2['h_useat'] == 1) {
+				$s = sprintf("%.1f",$item2['h_amount']*1000).' gr `';
+				$s .= iconv('UTF-8','windows-1252',$item2['h_name']).'` toevoegen na het spoelen';
+				$this->Checkline($s);
+			}
+		}
+		if ($this->GetY() > 200)
+			$this->AddPage();
+		else
+			$this->Ln(5);
+
+		$this->Checkheader('Koken');
+		$this->Checkline('totale kooktijd: '.$row['boil_time'].' min.');
+		for ($i = $row['boil_time']; $i >= 0; $i--) {
+			if ($i == 10) {
+				foreach($ferms as $item1) {
+					if ($item1['f_added'] == 1) {
+						$s = sprintf("%.3f",$item1['f_amount']).' kg `';
+						$s .= iconv('UTF-8','windows-1252',$item1['f_name']).'` bij 10 minuten voor einde koken';
+						$this->Checkline($s);
+					}
+				}
+				if ($row['brew_cooling_method'] == 1)
+					$this->Checkline('Plaats dompelkoeler bij 10 minuten voor einde koken');
+			}
+			foreach($hops as $item2) {
+				if (($item2['h_useat'] == 2 || $item2['h_useat'] == 3) && ($item2['h_time'] == $i)) {
+					$s = sprintf("%.1f",$item2['h_amount']*1000).' gr `';
+					$s .= iconv('UTF-8','windows-1252',$item2['h_name']).'` bij ';
+					if ($i > 0)
+						$s .= $i.' minuten voor einde koken';
+					else
+						$s .= 'vlamuit';
+					$this->Checkline($s);
+				}
+			}
+			foreach($miscs as $item3) {
+				if ($item3['m_use_use'] == 2 && $item3['m_time'] == $i) {
+					$unit = ($item3['m_amount_is_weight']) ? " gr ":" ml ";
+					$s = sprintf("%.1f",$item3['m_amount']*1000).$unit.'`';
+					$s .= iconv('UTF-8','windows-1252',$item3['m_name']).'` bij ';
+					if ($i > 0)
+						$s .= $i.' minuten voor einde koken';
+					else
+						$s .= 'vlamuit';
+					$this->Checkline($s);
+				}
+			}
+
+		}
+		$s = 'doelvolume einde koken: '.sprintf("%.1f",$row['batch_size']*1.04).' liter (';
+		$s .= sprintf("%.1f",kettle_cm($row['batch_size']*1.04,$row['eq_kettle_volume'],$row['eq_kettle_height']));
+		$s .= ' cm onder de rand)';
+		$this->Checkline($s);
+		$this->Checkline('doel SG einde koken: '.density_str($row['est_og']));
+		if ($this->GetY() > 200)
+			$this->AddPage();
+		else
+			$this->Ln(5);
+
+		if (($row['brew_whirlpool9'] + $row['brew_whirlpool7'] + $row['brew_whirlpool6'] + $row['brew_whirlpool2']) > 0) {
+			$this->Checkheader('Whirlpool en koelen');
+			if ($row['brew_whirlpool9'] > 0) {
+				$s = 'Whirlpool voor '.$row['brew_whirlpool9'].' min. Temperatuur boven 85 '.DEG.'C houden';
+				$this->Checkline($s);
+			}
+			if ($row['brew_whirlpool7'] > 0) {
+				$this->Checkline('koelen tot 79 '.DEG.'C');
+				$s = 'Whirlpool voor '.$row['brew_whirlpool7'].' min. Temperatuur tussen 72 en 79 '.DEG.'C houden';
+				$this->Checkline($s);
+			}
+			if ($row['brew_whirlpool6'] > 0) {
+				$this->Checkline('koelen tot 66 '.DEG.'C');
+				$s = 'Whirlpool voor '.$row['brew_whirlpool6'].' min. Temperatuur tussen 60 en 66 '.DEG.'C houden';
+				$this->Checkline($s);
+			}
+			foreach($hops as $item2) {
+				if ($item2['h_useat'] == 4) {
+					$s = sprintf("%.1f",$item2['h_amount']*1000).' gr `';
+					$s .= iconv('UTF-8','windows-1252',$item2['h_name']).'` voor ';
+					$s .= $item2['h_time'].' minuten in de whirlpool';
+					$this->Checkline($s);
+				}
+			}
+			$this->Checkline('koelen tot '.sprintf("%.1f",$row['brew_cooling_to']).' '.DEG.'C');
+			if ($row['brew_whirlpool2'] > 0) {
+				$s = 'Whirlpool voor '.$row['brew_whirlpool2'].' min.';
+				$this->Checkline($s);
+			}
+		} else {
+			$this->Checkheader('Koelen');
+			$this->Checkline('koelen tot '.sprintf("%.1f",$row['brew_cooling_to']).' '.DEG.'C');
+		}
+		$this->Checkline('gistvat ontsmetten en evt. pomp en slangen ontsmetten');
+		$this->Checkline('wort naar gistvat overbrengen');
+		if ($this->GetY() > (300 - (5 * $lines)))
+			$this->AddPage();
+		else
+			$this->Ln(5);
+
+		$this->Checkheader('Gist enten');
+		$dry = 0;
+		foreach ($yeasts as $item) {
+			if ($item['y_use'] == 0) { // primary
+				if ($item['y_form'] == 0) { // Liquid
+					$this->Checkline($item['y_amount'].' pak '.$item['y_product_id'].', '.$item['y_name'].' gist');
+				} else if ($item['y_form'] == 1) { // Dry
+					$s = sprintf("%.1f",$item['y_amount']*1000).' gram '.$item['y_product_id'].', '.$item['y_name'];
+					$s .= ' gist';
+					$dry += $item['y_amount']*10000;
+					$this->Checkline($s);
+				} else { // Slant/Culture/Frozen/Bottle
+					$s = sprintf("%.0f",$item['y_amount']*1000).' ml '.$item['y_product_id'].', '.$item['y_name'].' gist';
+					$this->Checkline($s);
+				}
+			}
+		}
+		if ($dry > 0) {
+			$this->Checkline(' gist hydrateren in '.$dry.' ml gedesinfecteerd water van 32 '.DEG.'C');
+			$this->Checkline(' 15 minuten laten staan bij 32 '.DEG.'C');
+			$this->Checkline(' gistmengsel voorzichtig roeren en laten afkoelen tot temperatuur wort');
+			$this->Checkline(' gist toevoegen');
+			$this->Checkline('Of');
+			$this->Checkline(' gist rechtstreeks over het wort strooien');
+		} else {
+			if ($row['starter_enable'] && $row['prop1_volume'])
+				$this->Checkline('giststarter toevoegen');
+			else
+				$this->Checkline('gist toevoegen');
+		}
+		if ($row['brew_fermenter_extrawater'] > 0)
+			$this->Checkline(sprintf("%.1f", $row['brew_fermenter_extrawater']).' liter water toevoegen in gistvat');
+		if ($row['brew_aeration_type'] > 0) {
+			$s = 'wort '.$row['brew_aeration_time'].' minuten beluchten met ';
+			$s .= ($row['brew_aeration_type'] == 1) ? "lucht":"zuurstof";
+			$this->Checkline($s);
+		}
+		if ($this->GetY() > 200)
+			$this->AddPage();
+		else
+			$this->Ln(5);
+
+		$this->Checkheader('Vergisting starten');
+		$this->Checkline('klimaatkast instellen op '.sprintf("%.1f",$row['brew_cooling_to']).' '.DEG.'C');
+
+		/*
+		 * During primary fermentation: fermentables, misc
+		 */
+		$lines = 0;
+                foreach($ferms as $item1) {
+                        if ($item1['f_added'] == 2)
+				$lines++;
+		}
+                foreach($miscs as $item3) {
+                	if ($item3['m_use_use'] == 3)
+				$lines++;
+		}
+		if ($lines) {
+			if ($this->GetY() > (270 - (5 * $lines)))
+                        	$this->AddPage();
+                	else
+                        	$this->Ln(5);
+			$this->Checkheader('Hoofdgisting');
+		}
+		foreach($ferms as $item1) {
+                        if ($item1['f_added'] == 2) {
+				$s = sprintf("%.3f",$item1['f_amount']).' kg `';
+                                $s .= iconv('UTF-8','windows-1252',$item1['f_name']).'` op dag 3 of 4 toevoegen';
+                                $this->Checkline($s);
+			}
+                }
+                foreach($miscs as $item3) {
+                        if ($item3['m_use_use'] == 3) {
+				$unit = ($item3['m_amount_is_weight']) ? " gr ":" ml ";
+				$s = sprintf("%.1f",$item3['m_amount']*1000).$unit.'`';
+                                $s .= iconv('UTF-8','windows-1252',$item3['m_name']).'` op dag 3 of 4 toevoegen';
+                                $this->Checkline($s);
+			}
+                }
+
+		/*
+		 * During secondary fermentation: yeast
+		 */
+		$lines = 0;
+                foreach ($yeasts as $item4) {
+                        if ($item4['y_use'] == 1)
+				$lines++;
+		}
+		if ($lines) {
+			if ($this->GetY() > (270 - (5 * $lines)))
+                        	$this->AddPage();
+                	else
+                        	$this->Ln(5);
+                        $this->Checkheader('Nagisting');
+                }
+		foreach ($yeasts as $item4) {
+                        if ($item4['y_use'] == 1) {
+				if ($item4['y_form'] == 0) { // Liquid
+                                        $this->Checkline($item4['y_amount'].' pak '.$item4['y_product_id'].', '.$item4['y_name'].' gist (eventueel met starter)');
+                                } else if ($item['y_form'] == 1) { // Dry
+                                        $s = sprintf("%.1f",$item4['y_amount']*1000).' gram '.$item4['y_product_id'].', '.$item4['y_name'];
+                                        $s .= ' gist';
+                                        $this->Checkline($s);
+                                } else { // Slant/Culture/Frozen/Bottle
+                                        $s = sprintf("%.0f",$item4['y_amount']*1000).' ml '.$item4['y_product_id'].', '.$item4['y_name'].' gist (eventueel met starter)';
+                                        $this->Checkline($s);
+                                }
+			}
+                }
+
+		/*
+		 * During tertiary fermentation: fermentables, hop, yeast, misc
+		 */
+		$lines = 0;
+		foreach($ferms as $item1) {
+                        if ($item1['f_added'] == 3)
+                                $lines++;
+                }
+                foreach($hops as $item2) {
+                        if ($item2['h_useat'] == 5)
+				$lines++;
+		}
+                foreach ($yeasts as $item4) {
+                        if ($item4['y_use'] == 2)
+                                $lines++;
+                }
+                foreach($miscs as $item3) {
+                        if ($item3['m_use_use'] == 4)
+                                $lines++;
+                }
+		if ($lines) {
+			if ($this->GetY() > (270 - (5 * $lines)))
+                                $this->AddPage();
+                        else
+                                $this->Ln(5);
+                        $this->Checkheader('Lagering');
+                }
+		foreach($ferms as $item1) {
+                        if ($item1['f_added'] == 3) {
+                                $s = sprintf("%.3f",$item1['f_amount']).' kg `';
+                                $s .= iconv('UTF-8','windows-1252',$item1['f_name']).'` toevoegen';
+                                $this->Checkline($s);
+                        }
+                }
+		foreach($hops as $item2) {
+                        if ($item2['h_useat'] == 5) {
+                                $s = sprintf("%.1f",$item2['h_amount']*1000).' gr `';
+                                $s .= iconv('UTF-8','windows-1252',$item2['h_name']).'` voor';
+				$s .= sprintf("%.0f",$item2['h_time']/1440).' dagen toevoegen';
+                                $this->Checkline($s);
+                        }
+                }
+		foreach ($yeasts as $item4) {
+                        if ($item4['y_use'] == 2) {
+                                if ($item4['y_form'] == 0) { // Liquid
+                                        $s = $item4['y_amount'].' pak '.$item4['y_product_id'].', '.$item4['y_name'].' gist (eventueel met starter)';
+                                } else if ($item4['y_form'] == 1) { // Dry
+                                        $s = sprintf("%.1f",$item4['y_amount']*1000).' gram '.$item4['y_product_id'].', '.$item4['y_name'];
+                                        $s .= ' gist';
+                                } else { // Slant/Culture/Frozen/Bottle
+                                        $s = sprintf("%.0f",$item4['y_amount']*1000).' ml '.$item4['y_product_id'].', '.$item4['y_name'];
+					$s .= ' gist (eventueel met starter)';
+                                }
+				$this->Checkline($s);
+                        }
+                }
+		foreach($miscs as $item3) {
+                        if ($item3['m_use_use'] == 4) {
+				$unit = ($item3['m_amount_is_weight']) ? " gr ":" ml ";
+                                $s = sprintf("%.1f",$item3['m_amount']*1000).$unit.'`';
+                                $s .= iconv('UTF-8','windows-1252',$item3['m_name']).'` voor ';
+				$s .= sprintf("%.0f",$item3['m_time']/1440).' dagen toevoegen';
+                                $this->Checkline($s);
+                        }
+                }
+
+		/*
+		 * During packaging: fermentables, yeast, misc
+		 */
+		$lines = 0;
+		foreach($ferms as $item1) {
+                        if ($item1['f_added'] == 4)
+                                $lines++;
+                }
+		$yeasts = json_decode($row['json_yeasts'], true);
+                foreach ($yeasts as $item4) {
+                        if ($item4['y_use'] == 3)
+                                $lines++;
+                }
+		$miscs = json_decode($row['json_miscs'], true);
+                foreach($miscs as $item3) {
+                        if ($item3['m_use_use'] == 5)
+                                $lines++;
+                }
+		if ($lines) {
+			if ($this->GetY() > (270 - (5 * $lines)))
+                                $this->AddPage();
+                        else
+                                $this->Ln(5);
+                        $this->Checkheader('Verpakken');
+                }
+		foreach($ferms as $item1) {
+                        if ($item1['f_added'] == 4) {
+                                $s = sprintf("%.3f",$item1['f_amount']).' kg `';
+                                $s .= iconv('UTF-8','windows-1252',$item1['f_name']).'` bij bottelen';
+                                $this->Checkline($s);
+                        }
+                }
+		foreach ($yeasts as $item4) {
+                        if ($item4['y_use'] == 3) {
+                                if ($item4['y_form'] == 0) { // Liquid
+                                        $s = '`'.$item4['y_product_id'].', '.$item4['y_name'];
+                                } else if ($item4['y_form'] == 1) { // Dry
+                                        $s = sprintf("%.1f",$item4['y_amount']*1000).' gram `'.$item4['y_product_id'].', '.$item4['y_name'];
+                                } else { // Slant/Culture/Frozen/Bottle
+                                        $s = sprintf("%.0f",$item4['y_amount']*1000).' ml `'.$item4['y_product_id'].', '.$item4['y_name'];
+                                }
+				$s .= '` als bottelgist';
+				$this->Checkline($s);
+                        }
+                }
+		foreach($miscs as $item3) {
+                        if ($item3['m_use_use'] == 5) {
+				$unit = ($item3['m_amount_is_weight']) ? " gr ":" ml ";
+                                $s = sprintf("%.1f",$item3['m_amount']*1000).$unit.'`';
+                                $s .= iconv('UTF-8','windows-1252',$item3['m_name']).'` bij bottelen toevoegen';
+                                $this->Checkline($s);
+                        }
+                }
+	}
+
+}
+
+
+
+class PDF extends PDF_MySQL_Table {
+	function Header() {
+		global $row;
+		global $prdate;
+		$stage = array( 'Plan', 'Wacht', 'Brouwen', 'Hoofdgisting', 'Nagisting', 'Lagering', 'Afvullen', 'Hergisten', 'Rijpen', 'Proeven', 'Gereed', 'Afgesloten' );
+		$this->Image('images/logo.png',10,10,30);
+		// Title
+		$this->SetFont('Helvetica','B',18);
+		$this->SetX(45);
+		$this->Cell(0,8,$row['code'].' '.$row['name'],0,1,'L');
+		$this->Ln(1);
+		$this->SetFont('Helvetica','',10);
+		$this->SetX(45);
+		$this->Cell(17,5,'Datum:',0,0,'L');
+		$this->Cell(0,5,$prdate,0,1,'L');
+		$this->SetX(45);
+		$this->Cell(17,5,'Stijl:',0,0,'L');
+		$this->Cell(0,5,$row['st_name'],0,1,'L');
+		$this->SetX(45);
+		$this->Cell(17,5,'Fase:',0,0,'L');
+		$this->Cell(0,5,$stage[$row['stage']],0,1,'L');
+		$this->Ln(6);
+		// Ensure table header is printed
+		parent::Header();
+	}
+}
+
+
+/*
+ * Generate checklist PDF from recipe data
+ */
+$pdf = new PDF();
+$pdf->Checklist($row);
+$pdf->Output();
--- a/www/prod_export.php	Thu May 30 23:19:43 2019 +0200
+++ b/www/prod_export.php	Wed Jun 05 20:04:26 2019 +0200
@@ -33,8 +33,12 @@
        <td align="left"><div style='margin-left: 10px;' id='jqxRadioButton4'></div></td>
       </tr>
       <tr>
+       <td align="right" style="vertical-align: top;">Checklist van recept:</td>
+       <td align="left"><div style='margin-left: 10px;' id='jqxRadioButton5'></div></td>
+      </tr>
+      <tr>
        <td align="right" style="vertical-align: top;">Export voor forum:</td>
-       <td align="left"><div style='margin-left: 10px;' id='jqxRadioButton5'></div></td>
+       <td align="left"><div style='margin-left: 10px;' id='jqxRadioButton6'></div></td>
       </tr>
       <tr><td colspan="2">&nbsp;</td></tr>
       <tr>
--- a/www/prod_forum.php	Thu May 30 23:19:43 2019 +0200
+++ b/www/prod_forum.php	Wed Jun 05 20:04:26 2019 +0200
@@ -141,8 +141,10 @@
         $alpha  = floatval($item['h_alpha']);
 	$ibu    = calc_IBU($item['h_useat'], $item['h_form'], $preboil_sg, floatval($row['batch_size']), $amount, $time, $alpha, $row['ibu_method']);
 	$moment = $hopuse[$item['h_useat']];
-        if ($item['h_useat'] == 2) {    // Boil
-        	$moment = "Kook ".$time." minuten";
+        if (($item['h_useat'] == 2) || ($item['h_useat'] == 4)) {    // Boil or Whirlpool
+        	$moment = $hopuse[$item['h_useat']].' '.$time." minuten";
+	} else if ($item['h_useat'] == 5) {	// Dryhop
+		$moment = $hopuse[$item['h_useat']].' '.sprintf("%.0f", $time / 1440).' dagen';
         }
 
 	echo sprintf("%s %-7s %5.1f %5.1f %6.1f %-20s", $name, $hopform[$item['h_form']], $alpha, $ibu, $amount, $moment);
@@ -224,8 +226,7 @@
 	itemline("Maischwater", sprintf("%.1f",floatval($row['w1_amount'])).' liter water '.$row['w1_name']);
 }
 itemline("Maischwater aanzuren tot pH", $row['mash_ph'].' pH');
-$spoelw = ($row['boil_size'] - $mashwater + $grainabsorbtion + $row['eq_lauter_deadspace']) * 1.03;     // A small heat correction
-itemline("Spoelwater geschat", sprintf("%.1f", $spoelw)." liter");
+itemline("Spoelwater geschat", sprintf("%.1f", $row['brew_sparge_est'])." liter");
 itemline("Spoelwater temperatuur", $row['sparge_temp'].' &deg;C');
 itemline("Spoelwater aanzuren tot pH", sprintf("%.1f",$row['sparge_ph']).' pH');
 echo PHP_EOL . PHP_EOL;
--- a/www/prod_print.php	Thu May 30 23:19:43 2019 +0200
+++ b/www/prod_print.php	Wed Jun 05 20:04:26 2019 +0200
@@ -98,7 +98,7 @@
 		$this->Cell($vul,5,'',0,0,'L',false);
 		$this->Cell(35,5,'Installatie',0,0,'L',true);
 		$this->Cell(45,5,$row['eq_name'],0,0,'L',true);
-		$this->Ln(10);
+		$this->Ln();
 
 		$this->cMargin=$cMargin;
 	}
@@ -111,15 +111,17 @@
 		global $colorw;
 		global $preboil_sg;
 		global $mashkg;
-		$added = array( 'Maischen', 'Koken', 'Vergisten', 'Nagisten/lageren', 'Bottelen' );
-		$vul = $this->w - $this->rMargin - $this->lMargin - 132;
-		$this->AddCol($vul,'Grondstof','L');
-		$this->AddCol(30,'Leverancier','L');
-		$this->AddCol(15,'EBC','R');
-		$this->AddCol(17,'Moment','L');
-		$this->AddCol(20,'Kg','R');
+		$added = array( 'Maischen', 'Koken 10 min', 'Vergisten', 'Nagisten/lageren', 'Bottelen' );
+		$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;
+		$this->Ln();
+		$this->AddCol($vul,'Mout, granen en suikers','L');
 		$this->AddCol(15,'Procent','R');
 		$this->AddCol(15,'Opbr.','R');
+		$this->AddCol(25,'Soort', 'L');
+		$this->AddCol(30,'Gebruik moment','L');
+		$this->AddCol(20,'Hoeveel','R');
 		$this->AddCol(20,'Prijs','R');
 
 		$cMargin=$this->cMargin;
@@ -149,6 +151,11 @@
 			if ($item['f_graintype'] == 2)		// Crystal
 				$pCara += $percent;
 
+			if ($item['f_type'] == 0)
+				$soort = iconv('UTF-8','windows-1252',$mtype[$item['f_graintype']]);
+			else
+				$soort = iconv('UTF-8','windows-1252',$ftype[$item['f_type']]);
+
 			$cost = $amount * $costkg;
 			$cost_fermentables += $cost;
 			$total_fermentables += $amount;
@@ -162,28 +169,31 @@
 			$sugarsf += $d;
 			$colorw += ($amount * ebc_to_srm($color) / $row['batch_size']) * 8.34436;
 
-			$this->Cell($vul,5,$name,0,0,'L',true);
-			$this->Cell(30,5,$supplier,0,0,'L',true);
-			$this->Cell(15,5,sprintf("%.0f",$color),0,0,'R',true);
-			$this->Cell(17,5,$added[$item['f_added']],0,0,'L',true);
-			$this->Cell(20,5,sprintf("%8.3f",$amount),0,0,'R',true);
+			if ($amount > 100)
+				$amount = sprintf("%.1f",$amount).' kg';
+			else if ($amount > 10)
+				$amount = sprintf("%.2f",$amount).' kg';
+			else
+				$amount = sprintf("%.0f",$amount * 1000).' gr';
+			$this->Cell($vul,5,$name.' ('.$supplier.') '.sprintf("%.0f",$color).' EBC',0,0,'L',true);
 			$this->Cell(15,5,sprintf("%.1f%%",$percent),0,0,'R',true);
 			$this->Cell(15,5,sprintf("%.1f%%",$yield),0,0,'R',true);
-			$this->Cell(20,5,sprintf("%8.3f",$cost).EURO,0,0,'R',true);
+			$this->Cell(25,5,$soort,0,0,'L',true);
+			$this->Cell(30,5,$added[$item['f_added']],0,0,'L',true);
+			$this->Cell(20,5,$amount,0,0,'R',true);
+			$this->Cell(20,5,sprintf("%.3f",$cost).EURO,0,0,'R',true);
 			$this->Ln();
 		}
 
 		$row['est_og'] = estimate_sg($sugarsf, floatval($row['batch_size']));
 		$preboil_sg = estimate_sg($sugarsm, floatval($row['boil_size']));
 		$this->SetFillColor(210,245,255);
-		$this->Cell($vul+62,5,'',0,0,'L',false);
-		$this->Cell(20,5,sprintf("%8.3f",$total_fermentables),0,0,'R',true);
-		$this->Cell(30,5,'',0,0,'L',false);
-		$this->Cell(20,5,sprintf("%8.3f",$cost_fermentables).EURO,0,0,'R',true);
-		$this->Ln(10);
+		$this->Cell($vul+105,5,'',0,0,'L',false);
+		$this->Cell(20,5,sprintf("%.3f",$cost_fermentables).EURO,0,0,'R',true);
 		$this->ProcessingTable=false;
 		$this->cMargin=$cMargin;
 		$this->aCols=array();
+		$this->Ln();
 	}
 
 	function TableHops($row) {
@@ -193,14 +203,14 @@
 		global $preboil_sg;
 		$hopform = array( 'Pellets', 'Plugs', 'Bellen', 'Hop nat' );
 		$hopuse  = array( 'Maischen', 'First wort', 'Koken', 'Vlamuit', 'Whirlpool', 'Koudhop' );
-		$vul = $this->w - $this->rMargin - $this->lMargin - 135;
+		$vul = $this->w - $this->rMargin - $this->lMargin - 122;
+		$this->Ln();
 		$this->AddCol($vul,'Hop','L');
-		$this->AddCol(35,'Land','L');
-		$this->AddCol(15,'Soort','L');
-		$this->AddCol(20,'Moment','L');
 		$this->AddCol(15,'Alpha','R');
 		$this->AddCol(12,'IBU','R');
-		$this->AddCol(18,'Gram','R');
+		$this->AddCol(25,'Soort','L');
+		$this->AddCol(30,'Gebruik moment','L');
+		$this->AddCol(20,'Hoeveel','R');
 		$this->AddCol(20,'Prijs','R');
 
 		$cMargin=$this->cMargin;
@@ -216,43 +226,47 @@
 		foreach($arr as $item) { //foreach element in $arr
 			$name     = iconv('UTF-8','windows-1252',$item['h_name']);
 			$origin   = iconv('UTF-8','windows-1252',$item['h_origin']);
-			$amount   = floatval($item['h_amount']) * 1000;
-			$mass     = $amount;
+			$amount   = floatval($item['h_amount']);
+			$mass     = $amount * 1000;
 			$costkg   = floatval($item['h_cost']);
 			$time     = floatval($item['h_time']);
 			$alpha    = floatval($item['h_alpha']);
 
-			$cost = ($amount * $costkg) / 1000;
+			$cost = ($amount * $costkg);
 			$cost_hops += $cost;
 			$total_hops += $amount;
 
 			$moment = $hopuse[$item['h_useat']];
-			if ($item['h_useat'] == 2) {    // Boil
-				$moment   = "Kook@".$time;
+			if (($item['h_useat'] == 2) || ($item['h_useat'] == 4)) {    // Boil or Whirlpool
+				$moment = $hopuse[$item['h_useat']].' '.$time." min";
+			} else if ($item['h_useat'] == 5) {	// Dryhop
+				$moment = $hopuse[$item['h_useat']].' '.sprintf("%.0f", $time / 1440).' dagen';
 			}
 			$ibu = calc_IBU($item['h_useat'], $item['h_form'], $preboil_sg, floatval($row['batch_size']), $mass, $time, $alpha, $row['ibu_method']);
 			$total_ibus += $ibu;
 
-			$this->Cell($vul,5,$name,0,0,'L',true);
-			$this->Cell(35,5,$origin,0,0,'L',true);
-			$this->Cell(15,5,$hopform[$item['h_form']],0,0,'L',true);
-			$this->Cell(20,5,$moment,0,0,'L',true);
+			if ($amount > 1)
+				$amount = sprintf("%.3f",$amount).' kg';
+			else
+				$amount = sprintf("%.1f",$amount * 1000).' gr';
+
+			$this->Cell($vul,5,$name.' ('.$origin.')',0,0,'L',true);
 			$this->Cell(15,5,sprintf("%.1f%%",$alpha),0,0,'R',true);
 			$this->Cell(12,5,sprintf("%.1f",$ibu),0,0,'R',true);
-			$this->Cell(18,5,sprintf("%.1f",$amount),0,0,'R',true);
-			$this->Cell(20,5,sprintf("%8.3f",$cost).EURO,0,0,'R',true);
+			$this->Cell(25,5,$hopform[$item['h_form']],0,0,'L',true);
+			$this->Cell(30,5,$moment,0,0,'L',true);
+			$this->Cell(20,5,$amount,0,0,'R',true);
+			$this->Cell(20,5,sprintf("%.3f",$cost).EURO,0,0,'R',true);
 			$this->Ln();
 		}
 
 		$this->SetFillColor(210,245,255);
-		$this->Cell($vul+85,5,'',0,0,'L',false);
-		$this->Cell(12,5,sprintf("%.1f",$total_ibus),0,0,'R',true);
-		$this->Cell(18,5,sprintf("%.1f",$total_hops),0,0,'R',true);
-		$this->Cell(20,5,sprintf("%8.3f",$cost_hops).EURO,0,0,'R',true);
-		$this->Ln(10);
+		$this->Cell($vul+102,5,'',0,0,'L',false);
+		$this->Cell(20,5,sprintf("%.3f",$cost_hops).EURO,0,0,'R',true);
 		$this->ProcessingTable=false;
 		$this->cMargin=$cMargin;
 		$this->aCols=array();
+		$this->Ln();
 	}
 
 	function TableYeasts($row) {
@@ -260,14 +274,13 @@
 		global $svg;
 		$yeastform = array( 'Vloeibaar', 'Droog', 'Schuine buis', 'Slurry', 'Ingevroren', 'Depot' );
 		$yeastuse  = array( 'Hoofdgisting', 'Nagisting', 'Lagering', 'Bottelen' );
-		$vul = $this->w - $this->rMargin - $this->lMargin - 140;
-		$this->AddCol(27,'Laboratorium','L');
-		$this->AddCol(18,'Product','L');
+		$vul = $this->w - $this->rMargin - $this->lMargin - 110;
+		$this->Ln();
 		$this->AddCol($vul,'Gist','L');
-		$this->AddCol(20,'Gebruik','L');
 		$this->AddCol(15,'Attn','R');
-		$this->AddCol(22,'Vorm','L');
-		$this->AddCol(18,'Gram','R');
+		$this->AddCol(25,'Soort','L');
+		$this->AddCol(30,'Gebruik moment','L');
+		$this->AddCol(20,'Hoeveel','R');
 		$this->AddCol(20,'Prijs','R');
 
 		$cMargin=$this->cMargin;
@@ -297,44 +310,54 @@
 			else
 				$amount = sprintf("%.0f",floatval($item['y_amount'])*1000)." ml";
 
-			$this->Cell(27,5,$laboratory,0,0,'L',true);
-			$this->Cell(18,5,$product_id,0,0,'L',true);
-			$this->Cell($vul,5,$name,0,0,'L',true);
-			$this->Cell(20,5,$yeastuse[$item['y_use']],0,0,'L',true);
+			$this->Cell($vul,5,$laboratory.' '.$product_id.' ('.$name.')',0,0,'L',true);
 			$this->Cell(15,5,sprintf("%.1f%%",$attenuation),0,0,'R',true);
-			$this->Cell(22,5,$yeastform[$item['y_form']],0,0,'L',true);
-			$this->Cell(18,5,$amount,0,0,'R',true);
+			$this->Cell(25,5,$yeastform[$item['y_form']],0,0,'L',true);
+			$this->Cell(30,5,$yeastuse[$item['y_use']],0,0,'L',true);
+			$this->Cell(20,5,$amount,0,0,'R',true);
 			$this->Cell(20,5,sprintf("%8.3f",$cost).EURO,0,0,'R',true);
 			$this->Ln();
 		}
-		if ($row['starter_enable']) {
-			$v = floatval($row['prop1_volume']) + floatval($row['prop2_volume']) + floatval($row['prop3_volume']) + floatval($row['prop4_volume']);
-			if ($v) {
-				$this->Cell(45,5,'',0,0,'L',true);
-				$this->Cell($vul,5,"Giststarter ".sprintf("%.2f",$v)." liter",0,0,'L',true);
-				$this->Cell(20,5,"Tevoren",0,0,'L',true);
-				$this->Cell(75,5,'',0,0,'L',true);
-				$this->Ln();
-			}
+		if ($row['starter_enable'] && $row['prop1_volume']) {
+			$sv = 0;
+			$st = 0;
+        		for ($i = 1; $i < 5; $i++) {
+                		$pv = "prop".$i."_volume";
+                		if (floatval($row[$pv])) {
+					$st++;
+					if (floatval($row[$pv]) > $sv)
+                        			$sv = floatval($row[$pv]);
+                		}
+        		}
+			$this->Cell($vul,5,$st." staps giststarter",0,0,'L',true);
+			$this->Cell(40,5,'',0,0,'R',true);
+			$this->Cell(30,5,"Vooraf",0,0,'L',true);
+			$this->Cell(20,5,sprintf("%.2f",$sv)." L",0,0,'R',true);
+			$this->Cell(20,5,'',0,0,'R',true);
+			$this->Ln();
 		}
 
 		$this->SetFillColor(210,245,255);
-		$this->Cell($vul+120,5,'',0,0,'L',false);
+		$this->Cell($vul+90,5,'',0,0,'L',false);
 		$this->Cell(20,5,sprintf("%8.3f",$cost_yeasts).EURO,0,0,'R',true);
-		$this->Ln(10);
 		$this->ProcessingTable=false;
 		$this->cMargin=$cMargin;
 		$this->aCols=array();
+		$this->Ln();
 	}
 
 	function TableMiscs($row) {
 		global $cost_miscs;
 		$misctype = array( 'Specerij', 'Kruid', 'Smaakstof', 'Klaringsmiddel', 'Brouwzout', 'Gistvoeding', 'Anders' );
 		$miscuse  = array( 'Starter', 'Maischen', 'Koken', 'Hoofdvergisting', 'Nagisting/lagering', 'Bottelen' );
-		$vul = $this->w - $this->rMargin - $this->lMargin - 100;
-		$this->AddCol($vul,'Naam','L');
-		$this->AddCol(30,'Soort','L');
-		$this->AddCol(30,'Gebruik','L');
+		$vul = $this->w - $this->rMargin - $this->lMargin - 95;
+		if ($this->GetY() > 200)
+                        $this->AddPage();
+                else
+                        $this->Ln();
+		$this->AddCol($vul,'Diversen naam','L');
+		$this->AddCol(25,'Soort','L');
+		$this->AddCol(30,'Gebruik moment','L');
 		$this->AddCol(20,'Hoeveel','R');
 		$this->AddCol(20,'Prijs','R');
 
@@ -375,7 +398,7 @@
 
 			$hoeveel = sprintf("%.2f %s",$amount,$aiw ? "gr":"ml");
 			$this->Cell($vul,5,$name,0,0,'L',true);
-			$this->Cell(30,5,$misctype[$type],0,0,'L',true);
+			$this->Cell(25,5,$misctype[$type],0,0,'L',true);
 			$this->Cell(30,5,$gebruik,0,0,'L',true);
 			$this->Cell(20,5,$hoeveel,0,0,'R',true);
 			$this->Cell(20,5,sprintf("%8.3f",$cost).EURO,0,0,'R',true);
@@ -383,16 +406,139 @@
 		}
 
 		$this->SetFillColor(210,245,255);
-		$this->Cell($vul+80,5,'',0,0,'L',false);
+		$this->Cell($vul+75,5,'',0,0,'L',false);
 		$this->Cell(20,5,sprintf("%8.3f",$cost_miscs).EURO,0,0,'R',true);
-		$this->Ln(10);
 
 		$this->ProcessingTable=false;
 		$this->cMargin=$cMargin;
 		$this->aCols=array();
+                $this->Ln();
+	}
+
+	function TableMashs($row) {
+                global $cost_yeasts;
+                global $svg;
+		global $mashkg;
+                $mashtype = array( 'Infusie', 'Verwarming', 'Decoctie' );
+                $vul = $this->w - $this->rMargin - $this->lMargin - 137;
+		if ($this->GetY() > 250)
+                        $this->AddPage();
+                else
+                        $this->Ln();
+                $this->AddCol($vul,'Maisch stap naam','L');
+                $this->AddCol(25,'Stap type','L');
+                $this->AddCol(18,'Start '.DEG.'C','R');
+                $this->AddCol(18,'Eind '.DEG.'C','R');
+                $this->AddCol(18,'Rust min','R');
+                $this->AddCol(18,'Stap min','R');
+                $this->AddCol(20,'L/Kg','R');
+                $this->AddCol(20,'Infusie L','R');
+
+		$cMargin=$this->cMargin;
+                $this->cMargin=2;
+                $this->TableX=$this->lMargin;
+                $this->TableHeader();
+                $this->ProcessingTable=true;
+
+                $this->SetFont('Helvetica','',9);
+                $this->SetFillColor(175, 175, 255);
+
+		$vol = 0;
+                $arr = json_decode($row['json_mashs'], true);
+		foreach($arr as $item) { //foreach element in $arr
+
+			if ($item['step_type'] == 0)
+				$vol += $item['step_infuse_amount'];
+			if ($mashkg > 0)
+				$thick = $vol / $mashkg;
+			else
+				$thick = 0;
+			$this->Cell($vul,5,$item['step_name'],0,0,'L',true);
+			$this->Cell(25,5,$mashtype[$item['step_type']],0,0,'L',true);
+			$this->Cell(18,5,sprintf("%.1f",$item['step_temp']),0,0,'R',true);
+			$this->Cell(18,5,sprintf("%.1f",$item['end_temp']),0,0,'R',true);
+			$this->Cell(18,5,sprintf("%.0f",$item['step_time']),0,0,'R',true);
+			$this->Cell(18,5,sprintf("%.0f",$item['ramp_time']),0,0,'R',true);
+			$this->Cell(20,5,sprintf("%.2f",$thick),0,0,'R',true);
+			$this->Cell(20,5,sprintf("%.1f",$item['step_infuse_amount']),0,0,'R',true);
+			$this->Ln();
+		}
+		$this->ProcessingTable=false;
+                $this->cMargin=$cMargin;
+                $this->aCols=array();
+		$this->Ln();
 	}
 
-	// Watercolor $this->SetFillColor(120,255,250);
+	function TableWaters($row) {
+
+		$vul = $this->w - $this->rMargin - $this->lMargin - 137;
+                if ($this->GetY() > 250)
+                        $this->AddPage();
+                else
+                        $this->Ln();
+                $this->AddCol($vul,'Water bron','L');
+                $this->AddCol(20,'Volume','R');
+                $this->AddCol(15,'Ca','R');
+                $this->AddCol(15,'Mg','R');
+                $this->AddCol(15,'Na','R');
+                $this->AddCol(15,'CaCO3','R');
+                $this->AddCol(15,'Cl','R');
+                $this->AddCol(15,'SO4','R');
+		$this->AddCol(15,'pH','R');
+
+		$cMargin=$this->cMargin;
+                $this->cMargin=2;
+                $this->TableX=$this->lMargin;
+                $this->TableHeader();
+                $this->ProcessingTable=true;
+
+                $this->SetFont('Helvetica','',9);
+                $this->SetFillColor(120, 255, 250);
+
+		$this->Cell($vul,5,$row['w1_name'],0,0,'L',true);
+                $this->Cell(20,5,sprintf("%.1f", $row['w1_amount']).' L',0,0,'R',true);
+		$this->Cell(15,5,sprintf("%.1f", $row['w1_calcium']),0,0,'R',true);
+		$this->Cell(15,5,sprintf("%.1f", $row['w1_magnesium']),0,0,'R',true);
+		$this->Cell(15,5,sprintf("%.1f", $row['w1_sodium']),0,0,'R',true);
+		$this->Cell(15,5,sprintf("%.1f", $row['w1_total_alkalinity']),0,0,'R',true);
+		$this->Cell(15,5,sprintf("%.1f", $row['w1_chloride']),0,0,'R',true);
+		$this->Cell(15,5,sprintf("%.1f", $row['w1_sulfate']),0,0,'R',true);
+		$this->Cell(15,5,sprintf("%.1f", $row['w1_ph']),0,0,'R',true);
+                $this->Ln();
+		$this->Cell($vul,5,$row['w2_name'],0,0,'L',true);
+                $this->Cell(20,5,sprintf("%.1f", $row['w2_amount']).' L',0,0,'R',true);
+                $this->Cell(15,5,sprintf("%.1f", $row['w2_calcium']),0,0,'R',true);
+                $this->Cell(15,5,sprintf("%.1f", $row['w2_magnesium']),0,0,'R',true);
+                $this->Cell(15,5,sprintf("%.1f", $row['w2_sodium']),0,0,'R',true);
+                $this->Cell(15,5,sprintf("%.1f", $row['w2_total_alkalinity']),0,0,'R',true);
+                $this->Cell(15,5,sprintf("%.1f", $row['w2_chloride']),0,0,'R',true);
+                $this->Cell(15,5,sprintf("%.1f", $row['w2_sulfate']),0,0,'R',true);
+                $this->Cell(15,5,sprintf("%.1f", $row['w2_ph']),0,0,'R',true);
+                $this->Ln();
+		$this->Cell($vul,5,'Gemengd water',0,0,'L',true);
+                $this->Cell(20,5,sprintf("%.1f", $row['wg_amount']).' L',0,0,'R',true);
+                $this->Cell(15,5,sprintf("%.1f", $row['wg_calcium']),0,0,'R',true);
+                $this->Cell(15,5,sprintf("%.1f", $row['wg_magnesium']),0,0,'R',true);
+                $this->Cell(15,5,sprintf("%.1f", $row['wg_sodium']),0,0,'R',true);
+                $this->Cell(15,5,sprintf("%.1f", $row['wg_total_alkalinity']),0,0,'R',true);
+                $this->Cell(15,5,sprintf("%.1f", $row['wg_chloride']),0,0,'R',true);
+                $this->Cell(15,5,sprintf("%.1f", $row['wg_sulfate']),0,0,'R',true);
+                $this->Cell(15,5,sprintf("%.1f", $row['wg_ph']),0,0,'R',true);
+                $this->Ln();
+		$this->Cell($vul,5,'Behandeld water',0,0,'L',true);
+                $this->Cell(20,5,'',0,0,'R',true);
+                $this->Cell(15,5,sprintf("%.1f", $row['wb_calcium']),0,0,'R',true);
+                $this->Cell(15,5,sprintf("%.1f", $row['wb_magnesium']),0,0,'R',true);
+                $this->Cell(15,5,sprintf("%.1f", $row['wb_sodium']),0,0,'R',true);
+                $this->Cell(15,5,sprintf("%.1f", $row['wb_total_alkalinity']),0,0,'R',true);
+                $this->Cell(15,5,sprintf("%.1f", $row['wb_chloride']),0,0,'R',true);
+                $this->Cell(15,5,sprintf("%.1f", $row['wb_sulfate']),0,0,'R',true);
+                $this->Cell(15,5,sprintf("%.1f", $row['wb_ph']),0,0,'R',true);
+		$this->ProcessingTable=false;
+                $this->cMargin=$cMargin;
+                $this->aCols=array();
+                $this->Ln();
+	}
 
 	function TableSummary($row) {
 		global $pSugar;
@@ -407,6 +553,10 @@
 		$colormethod = array( 'Morey', 'Mosher', 'Daniels' );
 		$ibumethod = array( 'Tinseth', 'Rager', 'Daniels' );
 		/* 2 Columns */
+		if ($this->GetY() > 200)
+                        $this->AddPage();
+                else
+                        $this->Ln();
 		$vul = $this->w - $this->rMargin - $this->lMargin - 170;
 		$cMargin=$this->cMargin;
 		$this->cMargin=2;
@@ -483,356 +633,164 @@
 		$this->Cell(35,5,'Kosten',0,0,'L',true);
 		$this->Cell(25,5,sprintf("%.2f",$cost_total).EURO,0,0,'L',true);
 		$this->Cell(25,5,sprintf("%.2f",$cost_total/$row['batch_size']).EURO.' / liter',0,0,'L',true);
-		$this->Ln(10);
 
-
-		// Kostprijs per liter, calorieren
-		$this->cMargin=$cMargin;
-	}
-
-	function Checkheader($text) {
-		$this->SetFont('Arial','B',10);
-		$this->Cell(0, 4,$text,0,0,'L',true);
-		$this->SetFont('Arial','',10);
-		$this->Ln(6);
-	}
-
-	function Checkline($text) {
-		//	$this->SetX(5);
-		$this->Cell(2, 4,' ',0,0,'L',true);
-		$this->Cell(4, 4,' ',1,0,'L',true);
-	//	$this->Rect(10,$this->GetY(),4,4);
-	//	$this->SetX(15);
-		$this->Cell(0, 4,' '.$text,0,1,'L',true);
-		$this->Ln(1);
+		// calorieen
+		$this->ProcessingTable=false;
+                $this->cMargin=$cMargin;
+                $this->aCols=array();
+                $this->Ln();
 	}
 
-	function Checklist($row) {
+	function Brewday($row) {
 
-		global $my_grain_absorbtion;
 		global $my_brix_correction;
-		$mashwater = 0;
-		$numsalts = 0;
+		global $my_grain_absorbtion;
 
-		$this->AddPage();
-		$this->SetFillColor(255,255,255);
+		if ($this->GetY() > 180)
+                        $this->AddPage();
+                else
+                        $this->Ln(10);
 
-		if ($row['starter_enable'] && $row['prop1_volume']) {
-			$this->Checkheader('Giststarter maken');
-			$days = 0;
-			$last = 0;
-			for ($i = 1; $i < 5; $i++) {
-				$pt = "prop".$i."_type";
-				$pv = "prop".$i."_volume";
-				if (floatval($row[$pv])) {
-					$last = $i;
-					if ($row[$pt] == 0)
-						$days += 2;
-					else if ($row[$pt] == 1)
-						$days += 4;
-					else
-						$days += 6;
-				}
-			}
-			$this->Checkline("begin ongeveer ".$days." dagen voor de brouwdag met de giststarter");
-			for ($i = 1; $i < 5; $i++) {
-				$pt = "prop".$i."_type";
-				$pv = "prop".$i."_volume";
-				if (floatval($row[$pv])) {
-					$s  = "Starter stap ".$i.", van ".sprintf("%.3f",floatval($row[$pv]));
-					$s .= " liter maken met SG ".sprintf("%.3f",floatval($row['starter_sg']));
-					$this->Checkline($s);
-					if ($row[$pt] == 0) {
-						$s = "ongeveer 24 uur op een magneetroerder";
-					} else if ($row[$pt] == 1) {
-						$s = "enkele dagen regelmatig schudden";
-					} else {
-						$s = "bijna een week rustig laten staan";
-					}
-					$s .= " tot er voldoende gist is";
-					$this->Checkline($s);
-					if ($i < $last) {
-						$this->Checkline("starter minstens 24 uur in de koeling laten uitzakken");
-						$this->Checkline("starter uit de koelkast halen en afgieten");
-					} else {
-						$this->Checkline("starter in de koeling zetten tot de brouwdag");
-						$this->Checkline("starter op de brouwdag uit de koelkast halen en afgieten");
-					}
-				}
-			}
-			$this->Ln(5);
-		}
+		$vul = $this->w - $this->rMargin - $this->lMargin - 170;
+		$cMargin=$this->cMargin;
+		$this->cMargin=2;
+		$this->TableX=$this->lMargin;
+		$this->SetFont('Helvetica','B',9);
+		$this->SetX($this->TableX);
+		$this->SetFillColor(255,150,100);
+		$this->Cell(0, 5, 'Brouwdag gegevens',0,0,'C',true);
+		$this->Ln();
 
-		$this->Checkheader('Water en -behandeling');
-		if ($row['w1_name']) {
-			$this->Checkline(sprintf("%.1f",floatval($row['w1_amount'])).' liter water '.$row['w1_name']);
-			$mashwater += floatval($row['w1_amount']);
-		}
-		if ($row['w2_name']) {
-			$this->Checkline(sprintf("%.1f",floatval($row['w2_amount'])).' liter water '.$row['w2_name']);
-			$mashwater += floatval($row['w2_amount']);
-		}
-		$arr = json_decode($row['json_miscs'], true);
-		foreach($arr as $item) {
-			if ($item['m_type'] == 4) {	// Only the water agents
-				$unit = ($item['m_amount_is_weight']) ? " gram ":" ml ";
-				$this->Checkline(sprintf("%.1f",floatval($item['m_amount'] * 1000)).$unit.$item['m_name']);
-				$numsalts++;
-			}
-		}
-		$this->Ln(5);
+		$this->SetFont('Helvetica','',9);
+        	$this->SetFillColor(210,245,255);
+
+        	$this->SetX($this->TableX);
+        	$this->Cell(35,5,'Datum start',0,0,'L',true);
+        	$this->Cell(50,5,$row['brew_date_start'],0,0,'L',true);
+        	$this->Cell($vul,5,'',0,0,'L',false);
+        	$this->Cell(35,5,'Maisch zuurgraad',0,0,'L',true);
+        	$this->Cell(50,5,sprintf("%.1f", $row['brew_mash_ph']).' pH',0,0,'L',true);
+        	$this->Ln();
 
-		$this->Checkheader('Mout afwegen en schroten');
-		$arr = json_decode($row['json_fermentables'], true);
-		foreach($arr as $item) {
-			if ($item['f_added'] == 0) {	// to mash
-				$s = sprintf("%.3f",floatval($item['f_amount'])).' kg ';
-				$s .= iconv('UTF-8','windows-1252',$item['f_name']);
-				$s .= ' ('.iconv('UTF-8','windows-1252',$item['f_supplier']).')';
-				$this->Checkline($s);
-			}
-		}
-		$this->Checkline('mout schroten');
-		$this->Ln(5);
+		$this->SetX($this->TableX);
+                $this->Cell(35,5,'Datum eind',0,0,'L',true);
+                $this->Cell(50,5,$row['brew_date_end'],0,0,'L',true);
+                $this->Cell($vul,5,'',0,0,'L',false);
+                $this->Cell(35,5,'Maisch densiteit',0,0,'L',true);
+                $this->Cell(50,5,density_str(floatval($row['brew_mash_sg'])),0,0,'L',true);
+                $this->Ln();
+
+		$this->SetX($this->TableX);
+                $this->Cell(85+$vul,5,'',0,0,'L',false);
+                $this->Cell(35,5,'Maisch rendement',0,0,'L',true);
+                $this->Cell(50,5,sprintf("%.1f", floatval($row['brew_mash_efficiency']))."%",0,0,'L',true);
+                $this->Ln(7);
 
-		$this->Checkheader('Maischen');
-		$mvol = 0;
-		$msugars = 0;	// mash sugars
-		$grainabsorbtion = 0;
-		$arr = json_decode($row['json_mashs'], true);
-		if (count($arr) > 0) {
-			$loop = 0;
-			foreach($arr as $item) {
-				if ($item['step_type'] == 0)
-					$mvol += $item['step_infuse_amount'];	// We need this later.
-				if ($loop == 0) {
-					if ($item['step_type'] == 0)
-						$l = $item['step_infuse_amount'];
-					else
-						$l = $mashwater;
-					$s = sprintf("%.1f",$l).' liter water opwarmen tot ';
-					$s .= sprintf("%.1f",$item['step_temp']).' '.DEG.'C (';
-					$s .= sprintf("%.1f",kettle_cm($l,$row['eq_tun_volume'],$row['eq_tun_height']));
-					$s .= ' cm onder de rand)';
-					$this->Checkline($s);
-					if ($numsalts > 0)
-						$this->Checkline('brouwzouten en -zuren toevoegen');
-					$this->Checkline('mout storten en inmaischen');
-					$hops = json_decode($row['json_hops'], true);
-					foreach($hops as $item2) {
-						if ($item2['h_useat'] == 0) {
-							$s = sprintf("%.1f",$item2['h_amount']*1000).' gr ';
-							$s .= iconv('UTF-8','windows-1252',$item2['h_name']).' toevoegen';
-							$this->Checkline($s);
-						}
-					}
-					$this->Checkline($item['step_time'].' min. bij '.$item['step_temp'].' '.DEG.'C');
-					$this->Checkline('pH meten en bijstellen (doel pH beslag: '.sprintf("%.1f",$row['mash_ph']).' pH)');
-				} else {
-					if ($item['step_type'] == 0) {	// Infusion
-						$s = 'toevoegen '.$item['step_infuse_amount'].' liter water van xx '.DEG.'C';
-					} else if ($item['step_type'] == 1) {	// Direct heat
-						$s = 'opwarmen tot '.$item['step_temp'].' '.DEG.'C';
-					} else {	// Decoction
-						$s = 'uitnemen, opwarmen, koken en terugstorten van '.$item['step_infuse_amount'].' liter deelbeslag';
-					}
-					$this->Checkline($s);
-					$this->Checkline($item['step_time'].' min. bij '.$item['step_temp'].' '.DEG.'C');
-				}
-				$loop++;
-			}
-			$est_mash_sg = 0;
-			$ferms = json_decode($row['json_fermentables'], true);
-			foreach($ferms as $item) {
-				if ($item['f_added'] == 0) {
-					$d = $item['f_amount'] * ($item['f_yield'] / 100) * (1 - $item['f_moisture'] / 100);
-					$mvol += $item['f_amount'] * $item['f_moisture'] / 100;
-					$grainabsorbtion += $my_grain_absorbtion * $item['f_amount'];
-					$msugars += $d;
-				}
-			}
-			$sugardensity = 1.611;
-			$v = $msugars / $sugardensity + $mvol;
-			$plato = 1000 * $msugars / ($v * 10);	// deg. Plato
-			$mash_sg = plato_to_sg($plato);
-			$brix = $plato * $my_brix_correction;
-			$s = 'doel sg eind maischen: '.sprintf("%.3f",$mash_sg);
-			$s .= ' SG ('.sprintf("%.1f",$brix).' '.DEG.'Brix, '.sprintf("%.1f",$plato).' '.DEG.'P)';
-			$this->Checkline($s);
-		}
-		if ($this->GetY() > 200)
-			$this->AddPage();
-		else
-			$this->Ln(5);
+		$this->SetX($this->TableX);
+                $this->Cell(35,5,'Voor koken zuurgraad',0,0,'L',true);
+                $this->Cell(50,5,sprintf("%.1f", $row['brew_preboil_ph'])." pH",0,0,'L',true);
+                $this->Cell($vul,5,'',0,0,'L',false);
+                $this->Cell(35,5,'Na koken zuurgraad',0,0,'L',true);
+                $this->Cell(50,5,sprintf("%.1f", $row['brew_aboil_ph'])." pH",0,0,'L',true);
+                $this->Ln();
+
+		$this->SetX($this->TableX);
+                $this->Cell(35,5,'Voor koken densiteit',0,0,'L',true);
+                $this->Cell(50,5,density_str(floatval($row['brew_preboil_sg'])),0,0,'L',true);
+                $this->Cell($vul,5,'',0,0,'L',false);
+                $this->Cell(35,5,'Na koken densiteit',0,0,'L',true);
+                $this->Cell(50,5,density_str(floatval($row['brew_aboil_sg'])),0,0,'L',true);
+                $this->Ln();
+
+		$this->SetX($this->TableX);
+                $this->Cell(35,5,'Voor koken volume',0,0,'L',true);
+                $this->Cell(50,5,sprintf("%.1f", $row['brew_preboil_volume'])." liter",0,0,'L',true);
+                $this->Cell($vul,5,'',0,0,'L',false);
+                $this->Cell(35,5,'Na koken volume',0,0,'L',true);
+                $this->Cell(50,5,sprintf("%.1f", $row['brew_aboil_volume'])." liter",0,0,'L',true);
+                $this->Ln();
 
-		$acidtype = array( 'Melkzuur', 'Zoutzuur', 'Fosforzuur', 'Zwavelzuur' );
-		$this->Checkheader('Filteren en spoelen');
-		$s = sprintf("%.1f",$row['sparge_volume']).' liter spoelwater opwarmen tot '.sprintf("%.1f",$row['sparge_temp']).' '.DEG.'C';
-		$this->Checkline($s);
-		$s = 'spoelwater aanzuren tot pH <= '.sprintf("%.1f",$row['sparge_ph']).' met ';
-		$s .= sprintf("%.1f",$row['sparge_acid_amount']*1000).' ml. '.$acidtype[$row['sparge_acid_type']];
-		$this->Checkline($s);
-		$spoelw = ($row['boil_size'] - $mashwater + $grainabsorbtion + $row['eq_lauter_deadspace']) * 1.03;	// A small heat correction
-		$this->Checkline('spoelen met ongeveer '.sprintf("%.1f",$spoelw).' liter spoelwater');
-		$s = 'doelvolume in kookketel: '.sprintf("%.1f",$row['boil_size'] * 1.04).' liter (';
-		$s .= sprintf("%.1f",kettle_cm($row['boil_size'] * 1.04,$row['eq_kettle_volume'],$row['eq_kettle_height'])).' cm onder de rand)';
-		$this->Checkline($s);
-		$pre_sg = estimate_sg($msugars * floatval($row['efficiency']) / 100,floatval($row['boil_size']));
-		$plato = sg_to_plato($pre_sg);
-		$brix = $plato * $my_brix_correction;
-		$s = 'doel SG in kookketel: '.sprintf("%.3f",$pre_sg).' SG ('.sprintf("%.1f",$brix).' '.DEG.'Brix, '.sprintf("%.1f",$plato).' '.DEG.'P)';
-		$this->Checkline($s);
-		$hops = json_decode($row['json_hops'], true);
-		foreach($hops as $item2) {
-			if ($item2['h_useat'] == 1) {
-				$s = sprintf("%.1f",$item2['h_amount']*1000).' gr ';
-				$s .= iconv('UTF-8','windows-1252',$item2['h_name']).' toevoegen na het spoelen';
-				$this->Checkline($s);
-			}
-		}
-		if ($this->GetY() > 200)
-			$this->AddPage();
-		else
-			$this->Ln(5);
+		$this->SetX($this->TableX);
+                $this->Cell(35,5,'Voor koken rendement',0,0,'L',true);
+                $this->Cell(50,5,sprintf("%.1f", floatval($row['brew_preboil_efficiency']))."%",0,0,'L',true);
+                $this->Cell($vul,5,'',0,0,'L',false);
+                $this->Cell(35,5,'Na koken rendement',0,0,'L',true);
+                $this->Cell(50,5,sprintf("%.1f", floatval($row['brew_aboil_efficiency']))."%",0,0,'L',true);
+                $this->Ln(7);
+
+		$coolingtype = array( '-', 'Dompelkoeler', 'Tegenstroomkoeler', 'Au bain marie', 'Laten afkoelen' );
+		$this->SetX($this->TableX);
+                $this->Cell(35,5,'Spoelwater temperatuur',0,0,'L',true);
+                $this->Cell(50,5,sprintf("%.1f", $row['brew_sparge_temperature']).DEG.'C',0,0,'L',true);
+                $this->Cell($vul,5,'',0,0,'L',false);
+                $this->Cell(35,5,'Koel methode',0,0,'L',true);
+                $this->Cell(50,5,$coolingtype[$row['brew_cooling_method']],0,0,'L',true);
+                $this->Ln();
 
-		$this->Checkheader('Koken');
-		$this->Checkline('totale kooktijd: '.$row['boil_time'].' min.');
-		for ($i = $row['boil_time']; $i >= 0; $i--) {
-			if ($i == 10) {
-				$ferms = json_decode($row['json_fermentables'], true);
-				foreach($ferms as $item1) {
-					if ($item1['f_added'] == 1) {
-						$s = sprintf("%.3f",$item1['f_amount']).' kg ';
-						$s .= iconv('UTF-8','windows-1252',$item1['f_name']).' bij 10 minuten voor einde koken';
-						$this->Checkline($s);
-					}
-				}
-				if ($row['brew_cooling_method'] == 1)
-					$this->Checkline('Plaats dompelkoeler bij 10 minuten voor einde koken');
-			}
-			$hops = json_decode($row['json_hops'], true);
-			foreach($hops as $item2) {
-				if (($item2['h_useat'] == 2 || $item2['h_useat'] == 3) && ($item2['h_time'] == $i)) {
-					$s = sprintf("%.1f",$item2['h_amount']*1000).' gr ';
-					$s .= iconv('UTF-8','windows-1252',$item2['h_name']).' bij ';
-					if ($i > 0)
-						$s .= $i.' minuten voor einde koken';
-					else
-						$s .= 'vlamuit';
-					$this->Checkline($s);
-				}
-			}
-			$miscs = json_decode($row['json_miscs'], true);
-			foreach($miscs as $item3) {
-				if ($item3['m_use_use'] == 2 && $item3['m_time'] == $i) {
-					$s = sprintf("%.1f",$item3['m_amount']*1000).' gr ';
-					$s .= iconv('UTF-8','windows-1252',$item3['m_name']).' bij ';
-					if ($i > 0)
-						$s .= $i.' minuten voor einde koken';
-					else
-						$s .= 'vlamuit';
-					$this->Checkline($s);
-				}
-			}
+		$this->SetX($this->TableX);
+                $this->Cell(35,5,'Spoelwater geschat',0,0,'L',true);
+                $this->Cell(50,5,sprintf("%.1f", floatval($row['brew_sparge_est'])).' liter',0,0,'L',true);
+                $this->Cell($vul,5,'',0,0,'L',false);
+                $this->Cell(35,5,'Koel temperatuur',0,0,'L',true);
+                $this->Cell(50,5,sprintf("%.1f", floatval($row['brew_cooling_to'])).DEG.'C',0,0,'L',true);
+                $this->Ln();
+
+		$this->SetX($this->TableX);
+                $this->Cell(35,5,'Spoelwater zuurgraad',0,0,'L',true);
+                $this->Cell(50,5,sprintf("%.1f", $row['brew_sparge_ph']).' pH',0,0,'L',true);
+                $this->Cell($vul,5,'',0,0,'L',false);
+                $this->Cell(35,5,'Koel tijdsduur',0,0,'L',true);
+                $this->Cell(50,5,sprintf("%.0f", floatval($row['brew_cooling_time'])).' minuten',0,0,'L',true);
+                $this->Ln(7);
+
+		$this->SetX($this->TableX);
+                $this->Cell(35,5,'Whirlpool +85'.DEG.'C',0,0,'L',true);
+                $this->Cell(50,5,sprintf("%.0f", $row['brew_whirlpool9']).' minuten',0,0,'L',true);
+                $this->Cell($vul,5,'',0,0,'L',false);
+                $this->Cell(35,5,'Koeler & trub verlies',0,0,'L',true);
+                $this->Cell(50,5,sprintf("%.1f", floatval($row['brew_fermenter_tcloss'])).' liter',0,0,'L',true);
+                $this->Ln();
 
-		}
-		$s = 'doelvolume einde koken: '.sprintf("%.1f",$row['batch_size']*1.04).' liter (';
-		$s .= sprintf("%.1f",kettle_cm($row['batch_size']*1.04,$row['eq_kettle_volume'],$row['eq_kettle_height']));
-		$s .= ' cm onder de rand)';
-		$this->Checkline($s);
-		$plato = sg_to_plato($row['est_og']);
-		$brix = $plato * $my_brix_correction;
-		$s = 'doel SG einde koken: '.sprintf("%.3f",$row['est_og']).' SG (';
-		$s .= sprintf("%.1f",$brix).' '.DEG.'Brix, '.sprintf("%.1f",$plato).' '.DEG.'P)';
-		$this->Checkline($s);
-		if ($this->GetY() > 200)
-			$this->AddPage();
-		else
-			$this->Ln(5);
+		$this->SetX($this->TableX);
+                $this->Cell(35,5,'Whirlpool 72..79'.DEG.'C',0,0,'L',true);
+                $this->Cell(50,5,sprintf("%.0f", $row['brew_whirlpool7']).' minuten',0,0,'L',true);
+                $this->Cell($vul,5,'',0,0,'L',false);
+                $this->Cell(35,5,'Extra water in gistvat',0,0,'L',true);
+                $this->Cell(50,5,sprintf("%.1f", floatval($row['brew_fermenter_extrawater'])).' liter',0,0,'L',true);
+                $this->Ln();
 
-		if (($row['brew_whirlpool9'] + $row['brew_whirlpool7'] + $row['brew_whirlpool6'] + $row['brew_whirlpool2']) > 0) {
-			$this->Checkheader('Whirlpool en koelen');
-			if ($row['brew_whirlpool9'] > 0) {
-				$s = 'Whirlpool voor '.$row['brew_whirlpool9'].' min. Temperatuur boven 85 '.DEG.'C houden';
-				$this->Checkline($s);
-			}
-			if ($row['brew_whirlpool7'] > 0) {
-				$this->Checkline('koelen tot 79 '.DEG.'C');
-				$s = 'Whirlpool voor '.$row['brew_whirlpool7'].' min. Temperatuur tussen 72 en 79 '.DEG.'C houden';
-				$this->Checkline($s);
-			}
-			if ($row['brew_whirlpool6'] > 0) {
-				$this->Checkline('koelen tot 66 '.DEG.'C');
-				$s = 'Whirlpool voor '.$row['brew_whirlpool6'].' min. Temperatuur tussen 60 en 66 '.DEG.'C houden';
-				$this->Checkline($s);
-			}
-			$this->Checkline('koelen tot '.sprintf("%.1f",$row['brew_cooling_to']).' '.DEG.'C');
-			if ($row['brew_whirlpool2'] > 0) {
-				$s = 'Whirlpool voor '.$row['brew_whirlpool2'].' min.';
-				$this->Checkline($s);
-			}
-		} else {
-			$this->Checkheader('Koelen');
-			$this->Checkline('koelen tot '.sprintf("%.1f",$row['brew_cooling_to']).' '.DEG.'C');
-		}
-		$this->Checkline('gistvat ontsmetten en evt. pomp en slangen ontsmetten');
-		$this->Checkline('wort naar gistvat overbrengen');
-		if ($this->GetY() > 200)
-			$this->AddPage();
-		else
-			$this->Ln(5);
+		$this->SetX($this->TableX);
+                $this->Cell(35,5,'Whirlpool 60..66'.DEG.'C',0,0,'L',true);
+                $this->Cell(50,5,sprintf("%.0f", $row['brew_whirlpool6']).' minuten',0,0,'L',true);
+                $this->Cell($vul,5,'',0,0,'L',false);
+                $this->Cell(35,5,'Volume naar gistvat',0,0,'L',true);
+                $this->Cell(50,5,sprintf("%.1f", floatval($row['brew_fermenter_volume'])).' liter',0,0,'L',true);
+                $this->Ln();
 
-		$this->Checkheader('Gist enten');
-		$dry = 0;
-		$yeasts = json_decode($row['json_yeasts'], true);
-		foreach ($yeasts as $item) {
-			if ($item['y_use'] == 0) { // primary
-				if ($item['y_form'] == 0) { // Liquid
-					$this->Checkline($item['y_amount'].' pak '.$item['y_product_id'].', '.$item['y_name'].' gist');
-				} else if ($item['y_form'] == 1) { // Dry
-					$s = sprintf("%.1f",$item['y_amount']*1000).' gram '.$item['y_product_id'].', '.$item['y_name'];
-					$s .= ' gist';
-					$dry += $item['y_amount']*10000;
-					$this->Checkline($s);
-				} else { // Slant/Culture/Frozen/Bottle
-					$s = sprintf("%.0f",$item['y_amount']*1000).' ml '.$item['y_product_id'].', '.$item['y_name'].' gist';
-					$this->Checkline($s);
-				}
-			}
-		}
-		if ($dry > 0) {
-			$this->Checkline(' gist hydrateren in '.$dry.' ml gedesinfecteerd water van 32 '.DEG.'C');
-			$this->Checkline(' 15 minuten laten staan bij 32 '.DEG.'C');
-			$this->Checkline(' gistmengsel voorzichtig roeren en laten afkoelen tot temperatuur wort');
-			$this->Checkline(' gist toevoegen');
-			$this->Checkline('Of');
-			$this->Checkline(' gist rechtstreeks over het wort strooien');
-		} else {
-			if ($row['starter_enable'] && $row['prop1_volume'])
-				$this->Checkline('giststarter toevoegen');
-			else
-				$this->Checkline('gist toevoegen');
-		}
-		if ($row['brew_fermenter_extrawater'] > 0)
-			$this->Checkline(sprintf("%.1f", $row['brew_fermenter_extrawater']).' liter water toevoegen in gistvat');
-		if ($row['brew_aeration_type'] > 0) {
-			$s = 'wort '.$row['brew_aeration_time'].' minuten beluchten met ';
-			$s .= ($row['brew_aeration_type'] == 1) ? "lucht":"zuurstof";
-			$this->Checkline($s);
-		}
-		if ($this->GetY() > 200)
-			$this->AddPage();
-		else
-			$this->Ln(5);
+		$this->SetX($this->TableX);
+                $this->Cell(35,5,'Whirlpool koud',0,0,'L',true);
+                $this->Cell(50,5,sprintf("%.0f", $row['brew_whirlpool2']).' minuten',0,0,'L',true);
+                $this->Cell($vul,5,'',0,0,'L',false);
+                $this->Cell(35,5,'Densiteit in gistvat',0,0,'L',true);
+                $this->Cell(50,5,density_str(floatval($row['brew_fermenter_sg'])),0,0,'L',true);
+                $this->Ln(7);
 
-		$this->Checkheader('Vergisting starten');
-		$this->Checkline('klimaatkast instellen op '.sprintf("%.1f",$row['brew_cooling_to']).' '.DEG.'C');
+		$aerationtype = array( 'Geen', 'Lucht', 'Zuurstof' );
+		$this->SetX($this->TableX);
+                $this->Cell(35,5,'Beluchten met',0,0,'L',true);
+                $this->Cell(50,5,$aerationtype[$row['brew_aeration_type']],0,0,'L',true);
+                $this->Cell($vul,5,'',0,0,'L',false);
+                $this->Cell(35,5,'Kleur in gistvat',0,0,'L',true);
+                $this->Cell(50,5,sprintf("%.0f", floatval($row['brew_fermenter_color'])).' EBC',0,0,'L',true);
+                $this->Ln();
 
-		// 'Toevoegingen tijdens vergisting'
-		// 'Toevoegingen tijdens nagisting/lagering'
-		// fermentables & hops & miscs  verdelen over primary/secondary/teriary
-
-		// 'Toevoegingen tijdens bottelen/op fust zetten'
+		$this->SetX($this->TableX);
+                $this->Cell(35,5,'Beluchten snelheid/tijd',0,0,'L',true);
+                $this->Cell(50,5,$row['brew_aeration_speed'].'/'.$row['brew_aeration_time'],0,0,'L',true);
+                $this->Cell($vul,5,'',0,0,'L',false);
+                $this->Cell(35,5,'Bitterheid in gistvat',0,0,'L',true);
+                $this->Cell(50,5,sprintf("%.0f", floatval($row['brew_fermenter_ibu'])).' IBU',0,0,'L',true);
+                $this->Ln();
 	}
 }
 
@@ -876,22 +834,27 @@
 $pdf->TableHops($row);
 $pdf->TableYeasts($row);
 $pdf->TableMiscs($row);
+$pdf->TableMashs($row);
+$pdf->TableWaters($row);
 $pdf->TableSummary($row);
 if (strlen($row['notes'])) {
+	if ($pdf->GetY() > 200)
+		$pdf->AddPage();
+	else
+		$pdf->Ln(10);
 	$pdf->SetFillColor(255,150,100);
+	$pdf->SetFont('Helvetica','B',9);
 	$pdf->Cell(0, 5, 'Recept opmerkingen',0,0,'C',true);
 	$pdf->Ln();
+	$pdf->SetFont('Helvetica','',9);
 	$pdf->SetFillColor(210,245,255);
 	$pdf->MultiCell(0,4,$row['notes'],0,'L',true);
 }
 
-if ($row['stage'] == 1 || $row['stage'] == 2) {
-	// Checklist
-	$pdf->Checklist($row);
+if ($row['stage'] > 2) {
+	$pdf->Brewday($row);
 }
-if ($row['stage'] > 2) {
-	// Brouw rapport
-}
+
 if ($row['stage'] > 3) {
 	// Vergisting gegevens
 }
@@ -902,5 +865,4 @@
 	// Taste notes
 }
 
-
 $pdf->Output();
--- a/www/rec_beerxml.php	Thu May 30 23:19:43 2019 +0200
+++ b/www/rec_beerxml.php	Wed Jun 05 20:04:26 2019 +0200
@@ -280,7 +280,7 @@
 	xmlwriter_end_element($xw);
 
 	xmlwriter_start_element($xw, 'ADD_AFTER_BOIL');
-	($item['f_add_after_boil']) ? xmlwriter_text($xw, 'TRUE') : xmlwriter_text($xw, 'FALSE');
+	($item['f_added'] > 1) ? xmlwriter_text($xw, 'TRUE') : xmlwriter_text($xw, 'FALSE');
 	xmlwriter_end_element($xw);
 
 	xmlwriter_start_element($xw, 'ORIGIN');
--- a/www/rec_forum.php	Thu May 30 23:19:43 2019 +0200
+++ b/www/rec_forum.php	Wed Jun 05 20:04:26 2019 +0200
@@ -141,8 +141,10 @@
         $alpha  = floatval($item['h_alpha']);
 	$ibu    = calc_IBU($item['h_useat'], $item['h_form'], $preboil_sg, floatval($row['batch_size']), $amount, $time, $alpha, $row['ibu_method']);
 	$moment = $hopuse[$item['h_useat']];
-        if ($item['h_useat'] == 2) {    // Boil
-        	$moment = "Kook ".$time." minuten";
+        if (($item['h_useat'] == 2) || ($item['h_useat'] == 4)) {    // Boil or Whirlpool
+        	$moment = $hopuse[$item['h_useat']].' '.$time." minuten";
+	} else if ($item['h_useat'] == 5) {	// Dryhop
+		$moment = $hopuse[$item['h_useat']].' '.sprintf("%.0f", $time / 1440).' dagen';
         }
 
 	echo sprintf("%s %-7s %5.1f %5.1f %6.1f %-20s", $name, $hopform[$item['h_form']], $alpha, $ibu, $amount, $moment);
--- a/www/rec_print.php	Thu May 30 23:19:43 2019 +0200
+++ b/www/rec_print.php	Wed Jun 05 20:04:26 2019 +0200
@@ -88,7 +88,7 @@
 		$this->Cell($vul,5,'',0,0,'L',false);
 		$this->Cell(35,5,'Brouwzaal rendement',0,0,'L',true);
 		$this->Cell(25,5,$row['efficiency'].' %',0,0,'L',true);
-		$this->Ln(10);
+		$this->Ln();
 
 		$this->cMargin=$cMargin;
 	}
@@ -100,15 +100,17 @@
 		global $pCara;
 		global $colorw;
 		global $preboil_sg;
-		$added = array( 'Maischen', 'Koken', 'Vergisten', 'Nagisten/lageren', 'Bottelen' );
-		$vul = $this->w - $this->rMargin - $this->lMargin - 132;
-		$this->AddCol($vul,'Grondstof','L');
-		$this->AddCol(30,'Leverancier','L');
-		$this->AddCol(15,'EBC','R');
-		$this->AddCol(17,'Moment','L');
-		$this->AddCol(20,'Kg','R');
+		$added = array( 'Maischen', 'Koken 10 min', 'Vergisten', 'Nagisten/lageren', 'Bottelen' );
+		$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;
+		$this->Ln();
+		$this->AddCol($vul,'Mout, granen en suikers','L');
 		$this->AddCol(15,'Procent','R');
 		$this->AddCol(15,'Opbr.','R');
+		$this->AddCol(25,'Soort', 'L');
+		$this->AddCol(30,'Gebruik moment','L');
+		$this->AddCol(20,'Hoeveel','R');
 		$this->AddCol(20,'Prijs','R');
 
 		$cMargin=$this->cMargin;
@@ -137,6 +139,11 @@
 			if ($item['f_graintype'] == 2)	// Crystal
 				$pCara += $percent;
 
+			if ($item['f_type'] == 0)
+				$soort = iconv('UTF-8','windows-1252',$mtype[$item['f_graintype']]);
+			else
+				$soort = iconv('UTF-8','windows-1252',$ftype[$item['f_type']]);
+
 			$cost = $amount * $costkg;
 			$cost_fermentables += $cost;
 			$total_fermentables += $amount;
@@ -149,28 +156,31 @@
 			$sugarsf += $d;
 			$colorw += ($amount * ebc_to_srm($color) / $row['batch_size']) * 8.34436;
 
-			$this->Cell($vul,5,$name,0,0,'L',true);
-			$this->Cell(30,5,$supplier,0,0,'L',true);
-			$this->Cell(15,5,sprintf("%.0f",$color),0,0,'R',true);
-			$this->Cell(17,5,$added[$item['f_added']],0,0,'L',true);
-			$this->Cell(20,5,sprintf("%8.3f",$amount),0,0,'R',true);
+			if ($amount > 100)
+				$amount = sprintf("%.1f",$amount).' kg';
+			else if ($amount > 10)
+				$amount = sprintf("%.2f",$amount).' kg';
+			else
+				$amount = sprintf("%.0f",$amount * 1000).' gr';
+			$this->Cell($vul,5,$name.' ('.$supplier.') '.sprintf("%.0f",$color).' EBC',0,0,'L',true);
 			$this->Cell(15,5,sprintf("%.1f%%",$percent),0,0,'R',true);
 			$this->Cell(15,5,sprintf("%.1f%%",$yield),0,0,'R',true);
-			$this->Cell(20,5,sprintf("%8.3f",$cost).EURO,0,0,'R',true);
+			$this->Cell(25,5,$soort,0,0,'L',true);
+			$this->Cell(30,5,$added[$item['f_added']],0,0,'L',true);
+			$this->Cell(20,5,$amount,0,0,'R',true);
+			$this->Cell(20,5,sprintf("%.3f",$cost).EURO,0,0,'R',true);
 			$this->Ln();
 		}
 
 		$row['est_og'] = estimate_sg($sugarsf, floatval($row['batch_size']));
 		$preboil_sg = estimate_sg($sugarsm, floatval($row['boil_size']));
 		$this->SetFillColor(210,245,255);
-		$this->Cell($vul+62,5,'',0,0,'L',false);
-		$this->Cell(20,5,sprintf("%8.3f",$total_fermentables),0,0,'R',true);
-		$this->Cell(30,5,'',0,0,'L',false);
-		$this->Cell(20,5,sprintf("%8.3f",$cost_fermentables).EURO,0,0,'R',true);
-		$this->Ln(10);
+		$this->Cell($vul+105,5,'',0,0,'L',false);
+		$this->Cell(20,5,sprintf("%.3f",$cost_fermentables).EURO,0,0,'R',true);
 		$this->ProcessingTable=false;
 		$this->cMargin=$cMargin;
 		$this->aCols=array();
+		$this->Ln();
 	}
 
 	function TableHops($row) {
@@ -178,17 +188,16 @@
 		global $total_ibus;
 		global $cost_hops;
 		global $preboil_sg;
-//		$hoptype = array( 'Bitterhop', 'Aromahop', 'Beide' );
 		$hopform = array( 'Pellets', 'Plugs', 'Bellen', 'Hop nat' );
 		$hopuse  = array( 'Maischen', 'First wort', 'Koken', 'Vlamuit', 'Whirlpool', 'Koudhop' );
-		$vul = $this->w - $this->rMargin - $this->lMargin - 135;
+		$vul = $this->w - $this->rMargin - $this->lMargin - 122;
+		$this->Ln();
 		$this->AddCol($vul,'Hop','L');
-		$this->AddCol(35,'Land','L');
-		$this->AddCol(15,'Soort','L');
-		$this->AddCol(20,'Moment','L');
 		$this->AddCol(15,'Alpha','R');
 		$this->AddCol(12,'IBU','R');
-		$this->AddCol(18,'Gram','R');
+		$this->AddCol(25,'Soort','L');
+		$this->AddCol(30,'Gebruik moment','L');
+		$this->AddCol(20,'Hoeveel','R');
 		$this->AddCol(20,'Prijs','R');
 
 		$cMargin=$this->cMargin;
@@ -204,43 +213,47 @@
 		foreach($arr as $item) { //foreach element in $arr
 			$name     = iconv('UTF-8','windows-1252',$item['h_name']);
 			$origin   = iconv('UTF-8','windows-1252',$item['h_origin']);
-			$amount   = floatval($item['h_amount']) * 1000;
-			$mass     = $amount;
+			$amount   = floatval($item['h_amount']);
+			$mass     = $amount * 1000;
 			$costkg   = floatval($item['h_cost']);
 			$time     = floatval($item['h_time']);
 			$alpha    = floatval($item['h_alpha']);
 
-			$cost = ($amount * $costkg) / 1000;
+			$cost = ($amount * $costkg);
 			$cost_hops += $cost;
 			$total_hops += $amount;
 
 			$moment = $hopuse[$item['h_useat']];
-			if ($item['h_useat'] == 2) {	// Boil
-				$moment   = "Kook@".$time;
+			if (($item['h_useat'] == 2) || ($item['h_useat'] == 4)) {	// Boil or Whirlpool
+				$moment  = $hopuse[$item['h_useat']].' '.$time." min";
+			} else if ($item['h_useat'] == 5) {	// Dryhop
+				$moment  = $hopuse[$item['h_useat']].' '.sprintf("%.0f", $time / 1440).' dagen';
 			}
 			$ibu = calc_IBU($item['h_useat'], $item['h_form'], $preboil_sg, floatval($row['batch_size']), $mass, $time, $alpha, $row['ibu_method']);
 			$total_ibus += $ibu;
 
-			$this->Cell($vul,5,$name,0,0,'L',true);
-			$this->Cell(35,5,$origin,0,0,'L',true);
-			$this->Cell(15,5,$hopform[$item['h_form']],0,0,'L',true);
-			$this->Cell(20,5,$moment,0,0,'L',true);
+			if ($amount > 1)
+				$amount = sprintf("%.3f",$amount).' kg';
+			else
+				$amount = sprintf("%.1f",$amount * 1000).' gr';
+
+			$this->Cell($vul,5,$name.' ('.$origin.')',0,0,'L',true);
 			$this->Cell(15,5,sprintf("%.1f%%",$alpha),0,0,'R',true);
 			$this->Cell(12,5,sprintf("%.1f",$ibu),0,0,'R',true);
-			$this->Cell(18,5,sprintf("%.1f",$amount),0,0,'R',true);
-			$this->Cell(20,5,sprintf("%8.3f",$cost).EURO,0,0,'R',true);
+			$this->Cell(25,5,$hopform[$item['h_form']],0,0,'L',true);
+			$this->Cell(30,5,$moment,0,0,'L',true);
+			$this->Cell(20,5,$amount,0,0,'R',true);
+			$this->Cell(20,5,sprintf("%.3f",$cost).EURO,0,0,'R',true);
 			$this->Ln();
 		}
 
 		$this->SetFillColor(210,245,255);
-		$this->Cell($vul+85,5,'',0,0,'L',false);
-		$this->Cell(12,5,sprintf("%.1f",$total_ibus),0,0,'R',true);
-		$this->Cell(18,5,sprintf("%.1f",$total_hops),0,0,'R',true);
-		$this->Cell(20,5,sprintf("%8.3f",$cost_hops).EURO,0,0,'R',true);
-		$this->Ln(10);
+		$this->Cell($vul+102,5,'',0,0,'L',false);
+		$this->Cell(20,5,sprintf("%.3f",$cost_hops).EURO,0,0,'R',true);
 		$this->ProcessingTable=false;
 		$this->cMargin=$cMargin;
 		$this->aCols=array();
+		$this->Ln();
 	}
 
 	function TableYeasts($row) {
@@ -248,14 +261,13 @@
 		global $svg;
 		$yeastform = array( 'Vloeibaar', 'Droog', 'Schuine buis', 'Slurry', 'Ingevroren', 'Depot' );
 		$yeastuse  = array( 'Hoofdgisting', 'Nagisting', 'Lagering', 'Bottelen' );
-		$vul = $this->w - $this->rMargin - $this->lMargin - 140;
-		$this->AddCol(27,'Laboratorium','L');
-		$this->AddCol(18,'Product','L');
+		$vul = $this->w - $this->rMargin - $this->lMargin - 110;
+		$this->Ln();
 		$this->AddCol($vul,'Gist','L');
-		$this->AddCol(20,'Gebruik','L');
 		$this->AddCol(15,'Attn','R');
-		$this->AddCol(22,'Vorm','L');
-		$this->AddCol(18,'Hoeveel','R');
+		$this->AddCol(25,'Soort','L');
+		$this->AddCol(30,'Gebruik moment','L');
+		$this->AddCol(20,'Hoeveel','R');
 		$this->AddCol(20,'Prijs','R');
 
 		$cMargin=$this->cMargin;
@@ -285,34 +297,36 @@
 				$amount = sprintf("%.1f",floatval($item['y_amount'])*1000)." gr";
 			else
 				$amount = sprintf("%.0f",floatval($item['y_amount'])*1000)." ml";
-			$this->Cell(27,5,$laboratory,0,0,'L',true);
-			$this->Cell(18,5,$product_id,0,0,'L',true);
-			$this->Cell($vul,5,$name,0,0,'L',true);
-			$this->Cell(20,5,$yeastuse[$item['y_use']],0,0,'L',true);
+			$this->Cell($vul,5,$laboratory.' '.$product_id.' ('.$name.')',0,0,'L',true);
 			$this->Cell(15,5,sprintf("%.1f%%",$attenuation),0,0,'R',true);
-			$this->Cell(22,5,$yeastform[$item['y_form']],0,0,'L',true);
-			$this->Cell(18,5,$amount,0,0,'R',true);
+			$this->Cell(25,5,$yeastform[$item['y_form']],0,0,'L',true);
+			$this->Cell(30,5,$yeastuse[$item['y_use']],0,0,'L',true);
+			$this->Cell(20,5,$amount,0,0,'R',true);
 			$this->Cell(20,5,sprintf("%8.3f",$cost).EURO,0,0,'R',true);
 			$this->Ln();
 		}
 
 		$this->SetFillColor(210,245,255);
-		$this->Cell($vul+120,5,'',0,0,'L',false);
+		$this->Cell($vul+90,5,'',0,0,'L',false);
 		$this->Cell(20,5,sprintf("%8.3f",$cost_yeasts).EURO,0,0,'R',true);
-		$this->Ln(10);
 		$this->ProcessingTable=false;
 		$this->cMargin=$cMargin;
 		$this->aCols=array();
+		$this->Ln();
 	}
 
 	function TableMiscs($row) {
 		global $cost_miscs;
 		$misctype = array( 'Specerij', 'Kruid', 'Smaakstof', 'Klaringsmiddel', 'Brouwzout', 'Gistvoeding', 'Anders' );
 		$miscuse  = array( 'Starter', 'Maischen', 'Koken', 'Hoofdvergisting', 'Nagisting/lagering', 'Bottelen' );
-		$vul = $this->w - $this->rMargin - $this->lMargin - 100;
+		$vul = $this->w - $this->rMargin - $this->lMargin - 95;
+		if ($this->GetY() > 200)
+                        $this->AddPage();
+                else
+                        $this->Ln();
 		$this->AddCol($vul,'Naam','L');
-		$this->AddCol(30,'Soort','L');
-		$this->AddCol(30,'Gebruik','L');
+		$this->AddCol(25,'Soort','L');
+		$this->AddCol(30,'Gebruik moment','L');
 		$this->AddCol(20,'Hoeveel','R');
 		$this->AddCol(20,'Prijs','R');
 
@@ -353,7 +367,7 @@
 
 			$hoeveel = sprintf("%.1f %s",$amount,$aiw ? "gr":"ml");
 			$this->Cell($vul,5,$name,0,0,'L',true);
-			$this->Cell(30,5,$misctype[$type],0,0,'L',true);
+			$this->Cell(25,5,$misctype[$type],0,0,'L',true);
 			$this->Cell(30,5,$gebruik,0,0,'L',true);
 			$this->Cell(20,5,$hoeveel,0,0,'R',true);
 			$this->Cell(20,5,sprintf("%8.3f",$cost).EURO,0,0,'R',true);
@@ -361,16 +375,139 @@
 		}
 
 		$this->SetFillColor(210,245,255);
-		$this->Cell($vul+80,5,'',0,0,'L',false);
+		$this->Cell($vul+75,5,'',0,0,'L',false);
 		$this->Cell(20,5,sprintf("%8.3f",$cost_miscs).EURO,0,0,'R',true);
-		$this->Ln(10);
 
 		$this->ProcessingTable=false;
 		$this->cMargin=$cMargin;
 		$this->aCols=array();
+		$this->Ln();
+	}
+
+	function TableMashs($row) {
+                global $cost_yeasts;
+                global $svg;
+                global $mashkg;
+                $mashtype = array( 'Infusie', 'Verwarming', 'Decoctie' );
+                $vul = $this->w - $this->rMargin - $this->lMargin - 137;
+                if ($this->GetY() > 250)
+                        $this->AddPage();
+                else
+                        $this->Ln();
+                $this->AddCol($vul,'Maisch stap naam','L');
+                $this->AddCol(25,'Stap type','L');
+                $this->AddCol(18,'Start '.DEG.'C','R');
+                $this->AddCol(18,'Eind '.DEG.'C','R');
+                $this->AddCol(18,'Rust min','R');
+                $this->AddCol(18,'Stap min','R');
+                $this->AddCol(20,'L/Kg','R');
+                $this->AddCol(20,'Infusie L','R');
+
+                $cMargin=$this->cMargin;
+                $this->cMargin=2;
+                $this->TableX=$this->lMargin;
+                $this->TableHeader();
+                $this->ProcessingTable=true;
+
+                $this->SetFont('Helvetica','',9);
+                $this->SetFillColor(175, 175, 255);
+
+                $vol = 0;
+                $arr = json_decode($row['json_mashs'], true);
+                foreach($arr as $item) { //foreach element in $arr
+
+                        if ($item['step_type'] == 0)
+                                $vol += $item['step_infuse_amount'];
+                        if ($mashkg > 0)
+                                $thick = $vol / $mashkg;
+                        else
+                                $thick = 0;
+                        $this->Cell($vul,5,$item['step_name'],0,0,'L',true);
+                        $this->Cell(25,5,$mashtype[$item['step_type']],0,0,'L',true);
+                        $this->Cell(18,5,sprintf("%.1f",$item['step_temp']),0,0,'R',true);
+                        $this->Cell(18,5,sprintf("%.1f",$item['end_temp']),0,0,'R',true);
+                        $this->Cell(18,5,sprintf("%.0f",$item['step_time']),0,0,'R',true);
+                        $this->Cell(18,5,sprintf("%.0f",$item['ramp_time']),0,0,'R',true);
+                        $this->Cell(20,5,sprintf("%.2f",$thick),0,0,'R',true);
+                        $this->Cell(20,5,sprintf("%.1f",$item['step_infuse_amount']),0,0,'R',true);
+                        $this->Ln();
+                }
+                $this->ProcessingTable=false;
+                $this->cMargin=$cMargin;
+                $this->aCols=array();
+                $this->Ln();
 	}
 
-	// Watercolor $this->SetFillColor(120,255,250);
+	function TableWaters($row) {
+
+		$vul = $this->w - $this->rMargin - $this->lMargin - 137;
+		if ($this->GetY() > 250)
+			$this->AddPage();
+		else
+			$this->Ln();
+		$this->AddCol($vul,'Water bron','L');
+		$this->AddCol(20,'Volume','R');
+		$this->AddCol(15,'Ca','R');
+		$this->AddCol(15,'Mg','R');
+		$this->AddCol(15,'Na','R');
+		$this->AddCol(15,'CaCO3','R');
+		$this->AddCol(15,'Cl','R');
+		$this->AddCol(15,'SO4','R');
+		$this->AddCol(15,'pH','R');
+
+		$cMargin=$this->cMargin;
+		$this->cMargin=2;
+		$this->TableX=$this->lMargin;
+		$this->TableHeader();
+		$this->ProcessingTable=true;
+
+		$this->SetFont('Helvetica','',9);
+		$this->SetFillColor(120, 255, 250);
+
+		$this->Cell($vul,5,$row['w1_name'],0,0,'L',true);
+		$this->Cell(20,5,sprintf("%.1f", $row['w1_amount']).' L',0,0,'R',true);
+		$this->Cell(15,5,sprintf("%.1f", $row['w1_calcium']),0,0,'R',true);
+		$this->Cell(15,5,sprintf("%.1f", $row['w1_magnesium']),0,0,'R',true);
+		$this->Cell(15,5,sprintf("%.1f", $row['w1_sodium']),0,0,'R',true);
+		$this->Cell(15,5,sprintf("%.1f", $row['w1_total_alkalinity']),0,0,'R',true);
+		$this->Cell(15,5,sprintf("%.1f", $row['w1_chloride']),0,0,'R',true);
+		$this->Cell(15,5,sprintf("%.1f", $row['w1_sulfate']),0,0,'R',true);
+		$this->Cell(15,5,sprintf("%.1f", $row['w1_ph']),0,0,'R',true);
+		$this->Ln();
+		$this->Cell($vul,5,$row['w2_name'],0,0,'L',true);
+		$this->Cell(20,5,sprintf("%.1f", $row['w2_amount']).' L',0,0,'R',true);
+		$this->Cell(15,5,sprintf("%.1f", $row['w2_calcium']),0,0,'R',true);
+		$this->Cell(15,5,sprintf("%.1f", $row['w2_magnesium']),0,0,'R',true);
+		$this->Cell(15,5,sprintf("%.1f", $row['w2_sodium']),0,0,'R',true);
+		$this->Cell(15,5,sprintf("%.1f", $row['w2_total_alkalinity']),0,0,'R',true);
+		$this->Cell(15,5,sprintf("%.1f", $row['w2_chloride']),0,0,'R',true);
+		$this->Cell(15,5,sprintf("%.1f", $row['w2_sulfate']),0,0,'R',true);
+		$this->Cell(15,5,sprintf("%.1f", $row['w2_ph']),0,0,'R',true);
+		$this->Ln();
+		$this->Cell($vul,5,'Gemengd water',0,0,'L',true);
+		$this->Cell(20,5,sprintf("%.1f", $row['wg_amount']).' L',0,0,'R',true);
+		$this->Cell(15,5,sprintf("%.1f", $row['wg_calcium']),0,0,'R',true);
+		$this->Cell(15,5,sprintf("%.1f", $row['wg_magnesium']),0,0,'R',true);
+		$this->Cell(15,5,sprintf("%.1f", $row['wg_sodium']),0,0,'R',true);
+		$this->Cell(15,5,sprintf("%.1f", $row['wg_total_alkalinity']),0,0,'R',true);
+		$this->Cell(15,5,sprintf("%.1f", $row['wg_chloride']),0,0,'R',true);
+		$this->Cell(15,5,sprintf("%.1f", $row['wg_sulfate']),0,0,'R',true);
+		$this->Cell(15,5,sprintf("%.1f", $row['wg_ph']),0,0,'R',true);
+		$this->Ln();
+		$this->Cell($vul,5,'Behandeld water',0,0,'L',true);
+		$this->Cell(20,5,'',0,0,'R',true);
+		$this->Cell(15,5,sprintf("%.1f", $row['wb_calcium']),0,0,'R',true);
+		$this->Cell(15,5,sprintf("%.1f", $row['wb_magnesium']),0,0,'R',true);
+		$this->Cell(15,5,sprintf("%.1f", $row['wb_sodium']),0,0,'R',true);
+		$this->Cell(15,5,sprintf("%.1f", $row['wb_total_alkalinity']),0,0,'R',true);
+		$this->Cell(15,5,sprintf("%.1f", $row['wb_chloride']),0,0,'R',true);
+		$this->Cell(15,5,sprintf("%.1f", $row['wb_sulfate']),0,0,'R',true);
+		$this->Cell(15,5,sprintf("%.1f", $row['wb_ph']),0,0,'R',true);
+		$this->ProcessingTable=false;
+                $this->cMargin=$cMargin;
+                $this->aCols=array();
+		$this->Ln();
+	}
 
 	function TableSummary($row) {
 		global $pSugar;
@@ -384,6 +521,10 @@
 		$colormethod = array( 'Morey', 'Mosher', 'Daniels' );
 		$ibumethod = array( 'Tinseth', 'Rager', 'Daniels' );
 		/* 2 Columns */
+		if ($this->GetY() > 200)
+                        $this->AddPage();
+                else
+                        $this->Ln();
 		$vul = $this->w - $this->rMargin - $this->lMargin - 170;
 		$cMargin=$this->cMargin;
 		$this->cMargin=2;
@@ -442,11 +583,12 @@
 		$this->Cell(35,5,'Kosten',0,0,'L',true);
 		$this->Cell(25,5,sprintf("%.2f",$cost_total).EURO,0,0,'L',true);
 		$this->Cell(25,5,sprintf("%.2f",$cost_total/$row['batch_size']).EURO.' / liter',0,0,'L',true);
-		$this->Ln(10);
 
-
-		// Kostprijs per liter, calorieren
-		$this->cMargin=$cMargin;
+                // calorieen
+                $this->ProcessingTable=false;
+                $this->cMargin=$cMargin;
+                $this->aCols=array();
+                $this->Ln();
 	}
 }
 
@@ -486,11 +628,19 @@
 $pdf->TableHops($row);
 $pdf->TableYeasts($row);
 $pdf->TableMiscs($row);
+$pdf->TableMashs($row);
+$pdf->TableWaters($row);
 $pdf->TableSummary($row);
 if (strlen($row['notes'])) {
+	if ($pdf->GetY() > 200)
+                $pdf->AddPage();
+        else
+                $pdf->Ln(10);
 	$pdf->SetFillColor(255,150,100);
+	$pdf->SetFont('Helvetica','B',9);
 	$pdf->Cell(0, 5, 'Recept opmerkingen',0,0,'C',true);
 	$pdf->Ln();
+	$pdf->SetFont('Helvetica','',9);
 	$pdf->SetFillColor(210,245,255);
 	$pdf->MultiCell(0,4,$row['notes'],0,'L',true);
 }

mercurial