Added most of print product

Sat, 28 May 2022 16:59:36 +0200

author
Michiel Broek <mbroek@mbse.eu>
date
Sat, 28 May 2022 16:59:36 +0200
changeset 237
f1032191578b
parent 236
d0b1640ba951
child 238
047e99c90848

Added most of print product

src/EditProduct.h file | annotate | diff | comparison | revisions
src/EditProductExport.cpp file | annotate | diff | comparison | revisions
src/PrinterDialog.cpp file | annotate | diff | comparison | revisions
src/PrinterDialog.h file | annotate | diff | comparison | revisions
--- a/src/EditProduct.h	Mon May 23 14:16:44 2022 +0200
+++ b/src/EditProduct.h	Sat May 28 16:59:36 2022 +0200
@@ -304,6 +304,8 @@
     double GetPressure(double CO2, double T1, double T2);
     double CarbCO2ToPressure(double CO2, double T);
     void calcPack();
+    void exportBeerXML();
+    void printProduct();
 };
 
 #endif
--- a/src/EditProductExport.cpp	Mon May 23 14:16:44 2022 +0200
+++ b/src/EditProductExport.cpp	Sat May 28 16:59:36 2022 +0200
@@ -18,7 +18,7 @@
  */
 
 
-void EditProduct::on_exportButton_clicked()
+void EditProduct::exportBeerXML()
 {
     qDebug() << "export";
 
@@ -262,9 +262,21 @@
 }
 
 
-void EditProduct::on_printButton_clicked()
+void EditProduct::printProduct()
 {
-    PrinterDialog(PR_RECIPE, -1, this);
+    PrinterDialog(PR_PRODUCT, -1, this);
 }
 
 
+void EditProduct::on_exportButton_clicked()
+{
+    exportBeerXML();
+}
+
+
+void EditProduct::on_printButton_clicked()
+{
+    printProduct();
+}
+
+
--- a/src/PrinterDialog.cpp	Mon May 23 14:16:44 2022 +0200
+++ b/src/PrinterDialog.cpp	Sat May 28 16:59:36 2022 +0200
@@ -69,6 +69,7 @@
     const QStringList y_unit({tr("pkg"), tr("gr"), tr("ml"), tr("ml"), tr("ml"), tr("ml"), tr("gr")});
     const QStringList ibu_method({ "Tinseth", "Rager", "Daniels", "Garetz", "Mosher", "Noonan" });
     const QStringList color_method({ "Morey", "Mosher", "Daniels", "Halberstadt", "Naudts" });
+    const QStringList cooling_method({"-", tr("Emersion chiller"), tr("Counterflow chiller"), tr("Au bain marie"), tr("Natural") });
 
     painter.begin(printer);
     qreal y = 0;
@@ -652,35 +653,690 @@
         painter.drawText(585, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(recipe->wb_sulfate, 1, 'f', 1));
         painter.drawText(660, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(recipe->wb_ph, 1, 'f', 2));
 	y += 20;
-    }
+
+    	/*
+    	 * Print recipe notes if present.
+    	 */
+    	if (recipe->notes.length()) {
+    	    QStringList lines = recipe->notes.split("\n");
+
+    	    if (lines.size() && recipe->notes != "") {
+            	if ((y + 80 + (lines.size() * 20)) > painter.device()->height()) {
+            	    printer->newPage();
+            	    printHeader(&painter);
+            	    y = 120;
+            	} else {
+            	    y += 40;
+            	}
+
+	    	/* Notes header */
+            	painter.setFont(QFont("Helvetica", 9, QFont::Bold));
+            	painter.setPen(Qt::black);
+            	painter.fillRect(  0, y,   735, 20, c_header);
+            	painter.drawText(  0, y+4, 735, 20, Qt::AlignCenter, tr("Recipe notes"));
+            	y += 20;
+            	painter.setFont(QFont("Helvetica", 9, QFont::Normal));
+	    	for (int i = 0; i < lines.size(); i++) {
+            	    painter.fillRect(  0, y,   735, 20, c_line1);
+	    	    painter.drawText(  0, y+4, 735, 20, Qt::AlignLeft, lines[i]);
+	     	    y += 20;
+	    	}
+	    }
+	}
+
+    } else if (p_job == PR_PRODUCT) {
+
+	qDebug() << "print product";
+	printHeader(&painter);
+        y = 120;
+        /* Generic header */
+        painter.setFont(QFont("Helvetica", 9, QFont::Bold));
+        painter.setPen(Qt::black);
+        painter.fillRect(  0, y,   735, 20, c_header);
+        painter.drawText(  0, y+4, 735, 20, Qt::AlignCenter, tr("Product overview"));
+        y += 20;
+        painter.setFont(QFont("Helvetica", 9, QFont::Normal));
+        painter.fillRect(  0, y,   300, 20, c_line1);
+        painter.drawText(  0, y+4, 120, 20, Qt::AlignLeft, tr("Brew type"));
+        painter.drawText(120, y+4, 180, 20, Qt::AlignLeft, recipe_types[product->type]);
+        painter.fillRect(435, y,   300, 20, c_line1);
+        painter.drawText(435, y+4, 120, 20, Qt::AlignLeft, tr("Efficiency"));
+        painter.drawText(555, y+4, 180, 20, Qt::AlignLeft, QString("%1 %").arg(product->efficiency, 1, 'f', 1));
+        y += 20;
+        painter.fillRect(  0, y,   300, 20, c_line1);
+        painter.drawText(  0, y+4, 120, 20, Qt::AlignLeft, tr("Boil time"));
+        painter.drawText(120, y+4, 180, 20, Qt::AlignLeft, QString("%1 minutes.").arg(product->boil_time, 1, 'f', 0));
+        painter.fillRect(435, y,   300, 20, c_line1);
+        painter.drawText(435, y+4, 120, 20, Qt::AlignLeft, tr("Batch size"));
+        painter.drawText(555, y+4, 180, 20, Qt::AlignLeft, QString("%1 L.").arg(product->batch_size, 1, 'f', 1));
+        y += 20;
+        painter.fillRect(  0, y,   300, 20, c_line1);
+        painter.drawText(  0, y+4, 120, 20, Qt::AlignLeft, tr("Start SG"));
+        painter.drawText(120, y+4,  90, 20, Qt::AlignLeft, QString("%1").arg(product->est_og, 1, 'f', 3));
+        painter.drawText(210, y+4,  90, 20, Qt::AlignLeft, QString("(%1 - %2)").arg(product->st_og_min, 1, 'f', 3).arg(product->st_og_max, 1, 'f', 3));
+        painter.fillRect(435, y,   300, 20, c_line1);
+        painter.drawText(435, y+4, 120, 20, Qt::AlignLeft, tr("End SG"));
+        painter.drawText(555, y+4,  90, 20, Qt::AlignLeft, QString("%1").arg(product->est_fg, 1, 'f', 3));
+        painter.drawText(645, y+4,  90, 20, Qt::AlignLeft, QString("(%1 - %2)").arg(product->st_fg_min, 1, 'f', 3).arg(product->st_fg_max, 1, 'f', 3));
+        y += 20;
+        painter.fillRect(  0, y,   300, 20, c_line1);
+        painter.drawText(  0, y+4, 120, 20, Qt::AlignLeft, tr("Estimated Alcohol"));
+        painter.drawText(120, y+4,  90, 20, Qt::AlignLeft, QString("%1%").arg(product->est_abv, 1, 'f', 1));
+        painter.drawText(210, y+4,  90, 20, Qt::AlignLeft, QString("(%1 - %2)").arg(product->st_abv_min, 1, 'f', 1).arg(product->st_abv_max, 1, 'f', 1));
+        painter.fillRect(435, y,   300, 20, c_line1);
+        painter.drawText(435, y+4, 120, 20, Qt::AlignLeft, tr("Estimated CO2 vol"));
+        painter.drawText(555, y+4,  90, 20, Qt::AlignLeft, QString("%1").arg(product->est_carb, 1, 'f', 1));
+        painter.drawText(645, y+4,  90, 20, Qt::AlignLeft, QString("(%1 - %2)").arg(product->st_carb_min, 1, 'f', 1).arg(product->st_carb_max, 1, 'f', 1));
+        y += 20;
+        painter.fillRect(  0, y,   120, 20, c_line1);
+        painter.drawText(  0, y+4, 120, 20, Qt::AlignLeft, tr("Color (") + color_method[product->color_method] + ")");
+        painter.fillRect(120, y,   180, 20, Utils::ebc_to_color(product->est_color));
+        if (product->est_color > 30)
+            painter.setPen(Qt::white);
+        painter.drawText(120, y+4,  90, 20, Qt::AlignLeft, QString("%1 EBC").arg(product->est_color, 1, 'f', 0));
+        painter.drawText(210, y+4,  90, 20, Qt::AlignLeft, QString("(%1 - %2)").arg(product->st_color_min, 1, 'f', 0).arg(product->st_color_max, 1, 'f', 0));
+	painter.setPen(Qt::black);
+        painter.fillRect(435, y,   300, 20, c_line1);
+        painter.drawText(435, y+4, 120, 20, Qt::AlignLeft, tr("IBU (") + ibu_method[product->ibu_method] + ")");
+        painter.drawText(555, y+4,  90, 20, Qt::AlignLeft, QString("%1").arg(product->est_ibu, 1, 'f', 1));
+        painter.drawText(645, y+4,  90, 20, Qt::AlignLeft, QString("(%1 - %2)").arg(product->st_ibu_min, 1, 'f', 0).arg(product->st_ibu_max, 1, 'f', 0));
+	y += 20;
+	painter.fillRect(  0, y,   300, 20, c_line1);
+	painter.drawText(  0, y+4, 120, 20, Qt::AlignLeft, tr("Beer style"));
+	painter.drawText(120, y+4, 180, 20, Qt::AlignLeft, product->st_name);
+	painter.fillRect(435, y,   300, 20, c_line1);
+	painter.drawText(435, y+4, 120, 20, Qt::AlignLeft, tr("Stage"));
+	painter.drawText(555, y+4, 180, 20, Qt::AlignLeft, prod_stages[product->stage]);
+        y += 40;
+
+	/* Fermentables */
+        painter.setFont(QFont("Helvetica", 9, QFont::Bold));
+        painter.setPen(Qt::black);
+        painter.fillRect(  0, y,   735, 20, c_header);
+        painter.drawText(  0, y+4, 260, 20, Qt::AlignLeft, tr("Fermentable"));
+        painter.drawText(265, y+4,  70, 20, Qt::AlignRight, tr("Percent"));
+        painter.drawText(340, y+4,  70, 20, Qt::AlignRight, tr("Yield"));
+        painter.drawText(415, y+4,  90, 20, Qt::AlignLeft, tr("Type"));
+        painter.drawText(510, y+4,  90, 20, Qt::AlignLeft, tr("Use at"));
+        painter.drawText(605, y+4,  60, 20, Qt::AlignRight, tr("Amount"));
+        painter.drawText(670, y+4,  60, 20, Qt::AlignRight, tr("Cost"));
+        y += 20;
+        painter.setFont(QFont("Helvetica", 9, QFont::Normal));
+        double cost_fermentables = 0;
+        QString soort, amount, use;
+        for (int i = 0; i < product->fermentables.size(); i++) {
+            double cost = product->fermentables.at(i).f_amount * product->fermentables.at(i).f_cost;
+            cost_fermentables += cost;
+
+            if (product->fermentables.at(i).f_type == 0)
+                soort = fermentable_graintypes[product->fermentables.at(i).f_graintype];
+            else
+                soort = fermentable_types[product->fermentables.at(i).f_type];
+
+            if (product->fermentables.at(i).f_amount > 100)
+                amount = QString("%1 kg").arg(product->fermentables.at(i).f_amount, 1, 'f', 1);
+            else if (product->fermentables.at(i).f_amount > 10)
+                amount = QString("%1 kg").arg(product->fermentables.at(i).f_amount, 1, 'f', 2);
+            else
+                amount = QString("%1 gr").arg(product->fermentables.at(i).f_amount * 1000, 1, 'f', 0);
+
+            painter.fillRect(  0, y,   735, 20, f_line);
+
+            painter.drawText(  0, y+4, 260, 20, Qt::AlignLeft,  product->fermentables.at(i).f_name +
+                                                                QString(", %1 EBC (").arg(product->fermentables.at(i).f_color, 1, 'f', 0) +
+                                                                product->fermentables.at(i).f_supplier + ")");
+	    if (product->fermentables.at(i).f_added < FERMENTABLE_ADDED_BOTTLE)
+            	painter.drawText(265, y+4,  70, 20, Qt::AlignRight, QString("%1%").arg(product->fermentables.at(i).f_percentage, 1, 'f', 1));
+	    else
+		painter.drawText(265, y+4,  70, 20, Qt::AlignRight, "");
+            painter.drawText(340, y+4,  70, 20, Qt::AlignRight, QString("%1%").arg(product->fermentables.at(i).f_yield, 1, 'f', 1));
+            painter.drawText(415, y+4,  90, 20, Qt::AlignLeft,  soort);
+            painter.drawText(510, y+4,  90, 20, Qt::AlignLeft,  fermentable_added[product->fermentables.at(i).f_added]);
+            painter.drawText(605, y+4,  60, 20, Qt::AlignRight, amount);
+            painter.drawText(670, y+4,  60, 20, Qt::AlignRight, QString("%1 €").arg(cost, 1, 'f', 3));
+            y += 20;
+        }
+        painter.fillRect(670, y,    60, 20, c_line1);
+        painter.drawText(670, y+4,  60, 20, Qt::AlignRight, QString("%1 €").arg(cost_fermentables, 1, 'f', 3));
+        y += 40;
+
+	/* Hops */
+        painter.setFont(QFont("Helvetica", 9, QFont::Bold));
+        painter.fillRect(  0, y,   735, 20, c_header);
+        painter.drawText(  0, y+4, 260, 20, Qt::AlignLeft, tr("Hop"));
+        painter.drawText(265, y+4,  70, 20, Qt::AlignRight, tr("Alpha"));
+        painter.drawText(340, y+4,  70, 20, Qt::AlignRight, tr("IBU"));
+        painter.drawText(415, y+4,  90, 20, Qt::AlignLeft, tr("Type"));
+        painter.drawText(510, y+4,  90, 20, Qt::AlignLeft, tr("Use at"));
+        painter.drawText(605, y+4,  60, 20, Qt::AlignRight, tr("Amount"));
+        painter.drawText(670, y+4,  60, 20, Qt::AlignRight, tr("Cost"));
+        y += 20;
+        painter.setFont(QFont("Helvetica", 9, QFont::Normal));
+        double cost_hops = 0;
+        for (int i = 0; i < product->hops.size(); i++) {
+
+            double cost = product->hops.at(i).h_amount * product->hops.at(i).h_cost;
+            cost_hops += cost;
+            double ibu = Utils::toIBU(product->hops.at(i).h_useat, product->hops.at(i).h_form, product->preboil_sg, product->batch_size,
+                                      product->hops.at(i).h_amount, product->hops.at(i).h_time, product->hops.at(i).h_alpha,
+                                      product->ibu_method, product->brew_whirlpool9, product->brew_whirlpool7, product->brew_whirlpool6, product->boil_time);
+
+            if (product->hops.at(i).h_useat == 2 || product->hops.at(i).h_useat == 4)     // Boil or Whirlpool
+                use = hop_useat[product->hops.at(i).h_useat] + QString(" %1 min").arg(product->hops.at(i).h_time);
+            else if (product->hops.at(i).h_useat == 5)                                   // Dryhop
+                use = hop_useat[product->hops.at(i).h_useat] + QString(" %1 days").arg(product->hops.at(i).h_time / 1440);
+            else
+                use = hop_useat[product->hops.at(i).h_useat];
+
+            if (product->hops.at(i).h_amount > 1)
+                amount = QString("%1 kg").arg(product->hops.at(i).h_amount, 1, 'f', 3);
+            else
+                amount = QString("%1 gr").arg(product->hops.at(i).h_amount * 1000, 1, 'f', 1);
+
+            painter.fillRect(  0, y,   735, 20, h_line);
+            painter.drawText(  0, y+4, 260, 20, Qt::AlignLeft,  product->hops.at(i).h_name + " (" + product->hops.at(i).h_origin + ")");
+            painter.drawText(265, y+4,  70, 20, Qt::AlignRight, QString("%1%").arg(product->hops.at(i).h_alpha, 1, 'f', 1));
+            painter.drawText(340, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(ibu, 1, 'f', 1));
+            painter.drawText(415, y+4,  90, 20, Qt::AlignLeft,  hop_forms[product->hops.at(i).h_form]);
+            painter.drawText(510, y+4,  90, 20, Qt::AlignLeft,  use);
+            painter.drawText(605, y+4,  60, 20, Qt::AlignRight, amount);
+            painter.drawText(670, y+4,  60, 20, Qt::AlignRight, QString("%1 €").arg(cost, 1, 'f', 3));
+            y += 20;
+        }
+        painter.fillRect(670, y,    60, 20, c_line1);
+        painter.drawText(670, y+4,  60, 20, Qt::AlignRight, QString("%1 €").arg(cost_hops, 1, 'f', 3));
+        y += 40;
+
+	/* Yeasts */
+        painter.setFont(QFont("Helvetica", 9, QFont::Bold));
+        painter.fillRect(  0, y,   735, 20, c_header);
+        painter.drawText(  0, y+4, 335, 20, Qt::AlignLeft, tr("Yeast"));
+        painter.drawText(340, y+4,  70, 20, Qt::AlignRight, tr("Attn"));
+        painter.drawText(415, y+4,  90, 20, Qt::AlignLeft, tr("Type"));
+        painter.drawText(510, y+4,  90, 20, Qt::AlignLeft, tr("Use at"));
+        painter.drawText(605, y+4,  60, 20, Qt::AlignRight, tr("Amount"));
+        painter.drawText(670, y+4,  60, 20, Qt::AlignRight, tr("Cost"));
+        y += 20;
+        painter.setFont(QFont("Helvetica", 9, QFont::Normal));
+        double cost_yeasts = 0;
+        for (int i = 0; i < product->yeasts.size(); i++) {
+            double cost = product->yeasts.at(i).y_amount * product->yeasts.at(i).y_cost;
+            cost_yeasts += cost;
+
+            if (product->yeasts.at(i).y_form == 0)
+                amount = QString("%1 pack").arg(product->yeasts.at(i).y_amount, 1, 'f', 0);
+            else if (product->yeasts.at(i).y_form == 1 || product->yeasts.at(i).y_form == 6)
+                amount = QString("%1 gr").arg(product->yeasts.at(i).y_amount * 1000.0, 1, 'f', 1);
+            else
+                amount = QString("%1 ml").arg(product->yeasts.at(i).y_amount * 1000.0, 1, 'f', 1);
 
-    /*
-     * Print recipe notes if present.
-     */
-    if (recipe->notes.length()) {
-    	QStringList lines = recipe->notes.split("\n");
+            painter.fillRect(  0, y,   735, 20, y_line);
+            painter.drawText(  0, y+4, 260, 20, Qt::AlignLeft,  product->yeasts.at(i).y_laboratory + " " +
+                                                                product->yeasts.at(i).y_product_id + " (" +
+                                                                product->yeasts.at(i).y_name + ")");
+            painter.drawText(340, y+4,  70, 20, Qt::AlignRight, QString("%1%").arg(product->yeasts.at(i).y_attenuation, 1, 'f', 1));
+            painter.drawText(415, y+4,  90, 20, Qt::AlignLeft,  yeast_forms[product->yeasts.at(i).y_form]);
+            painter.drawText(510, y+4,  90, 20, Qt::AlignLeft,  yeast_use[product->yeasts.at(i).y_use]);
+            painter.drawText(605, y+4,  60, 20, Qt::AlignRight, amount);
+            painter.drawText(670, y+4,  60, 20, Qt::AlignRight, QString("%1 €").arg(cost, 1, 'f', 3));
+            y += 20;
+        }
+	if (product->starter_enable && product->prop_volume[0]) {
+	    int st = 0;
+	    double sv = 0;
+	    for (int i = 0; i < 4; i++) {
+		if (product->prop_volume[i] > 0.0) {
+		    st++;
+		    if (product->prop_volume[i] > sv)
+			sv = product->prop_volume[i];
+		}
+	    }
+	    painter.fillRect(  0, y,   735, 20, y_line);
+            painter.drawText(  0, y+4, 260, 20, Qt::AlignLeft,  QString(tr("%1 step yeaststarter")).arg(st));
+	    painter.drawText(510, y+4,  90, 20, Qt::AlignLeft,  QString(tr("Before")));
+	    painter.drawText(605, y+4,  60, 20, Qt::AlignRight, QString("%1 L").arg(sv, 1, 'f', 3));
+	    y += 20;
+	}
+        painter.fillRect(670, y,    60, 20, c_line1);
+        painter.drawText(670, y+4,  60, 20, Qt::AlignRight, QString("%1 €").arg(cost_yeasts, 1, 'f', 3));
+
+        if ((y + 80 + (product->miscs.size() * 20)) > painter.device()->height()) {      /* Rows + header + footer + blank */
+            printer->newPage();
+            printHeader(&painter);
+            y = 120;
+        } else {
+            y += 40;
+        }
+
+	/* Miscs */
+        painter.setFont(QFont("Helvetica", 9, QFont::Bold));
+        painter.fillRect(  0, y,   735, 20, c_header);
+        painter.drawText(  0, y+4, 410, 20, Qt::AlignLeft, tr("Misc ingredient"));
+        painter.drawText(415, y+4,  90, 20, Qt::AlignLeft, tr("Type"));
+        painter.drawText(510, y+4,  90, 20, Qt::AlignLeft, tr("Use at"));
+        painter.drawText(605, y+4,  60, 20, Qt::AlignRight, tr("Amount"));
+        painter.drawText(670, y+4,  60, 20, Qt::AlignRight, tr("Cost"));
+        y += 20;
+        painter.setFont(QFont("Helvetica", 9, QFont::Normal));
+        double cost_miscs = 0;
+        for (int i = 0; i < product->miscs.size(); i++) {
+            double cost = product->miscs.at(i).m_amount * product->miscs.at(i).m_cost;
+            cost_miscs += cost;
+
+            if (product->miscs.at(i).m_use_use == 2)
+                use = misc_uses[product->miscs.at(i).m_use_use] + QString(" %1 min").arg(product->miscs.at(i).m_time);
+            else
+                use = misc_uses[product->miscs.at(i).m_use_use];
+
+            if (product->miscs.at(i).m_type == 4)                                        // Water agent
+                painter.fillRect(  0, y,   735, 20, mw_line);
+            else if (product->miscs.at(i).m_type == 3)                                   // Fining
+                painter.fillRect(  0, y,   735, 20, mf_line);
+            else if (product->miscs.at(i).m_type < 3 || product->miscs.at(i).m_type == 5) // Spice, Herb, Flavour, Yeast nutrient
+                painter.fillRect(  0, y,   735, 20, ms_line);
+            else
+                painter.fillRect(  0, y,   735, 20, mo_line);
+            painter.drawText(  0, y+4, 410, 20, Qt::AlignLeft,  product->miscs.at(i).m_name);
+            painter.drawText(415, y+4,  90, 20, Qt::AlignLeft,  misc_types[product->miscs.at(i).m_type]);
+            painter.drawText(510, y+4,  90, 20, Qt::AlignLeft,  use);
+            painter.drawText(605, y+4,  60, 20, Qt::AlignRight,
+                            QString("%1 %2").arg(product->miscs.at(i).m_amount * 1000.0, 1, 'f', 1).arg(product->miscs.at(i).m_amount_is_weight ? "gr":"ml"));
+            painter.drawText(670, y+4,  60, 20, Qt::AlignRight, QString("%1 €").arg(cost, 1, 'f', 3));
+            y += 20;
+        }
+        painter.fillRect(670, y,    60, 20, c_line1);
+        painter.drawText(670, y+4,  60, 20, Qt::AlignRight, QString("%1 €").arg(cost_miscs, 1, 'f', 3));
+
+        if ((y + 60 + (product->mashs.size() * 20)) > painter.device()->height()) {      /* Rows + header + blank */
+            printer->newPage();
+            printHeader(&painter);
+            y = 120;
+        } else {
+            y += 40;
+        }
 
-    	if (lines.size() && recipe->notes != "") {
-            if ((y + 80 + (lines.size() * 20)) > painter.device()->height()) {
-            	printer->newPage();
-            	printHeader(&painter);
-            	y = 120;
+	/* Mash */
+        painter.setFont(QFont("Helvetica", 9, QFont::Bold));
+        painter.fillRect(  0, y,   735, 20, c_header);
+        painter.drawText(  0, y+4, 160, 20, Qt::AlignLeft, tr("Mash step"));
+        painter.drawText(165, y+4,  90, 20, Qt::AlignLeft, tr("Step type"));
+        painter.drawText(260, y+4,  60, 20, Qt::AlignRight, tr("Start °C"));
+        painter.drawText(325, y+4,  60, 20, Qt::AlignRight, tr("End °C"));
+        painter.drawText(390, y+4,  60, 20, Qt::AlignRight, tr("Time"));
+        painter.drawText(455, y+4,  60, 20, Qt::AlignRight, tr("Ramp"));
+        painter.drawText(520, y+4,  60, 20, Qt::AlignRight, tr("L/kg"));
+        painter.drawText(585, y+4,  70, 20, Qt::AlignRight, tr("Inf/dec L."));
+        painter.drawText(660, y+4,  70, 20, Qt::AlignRight, tr("Inf/dec °C"));
+        y += 20;
+        painter.setFont(QFont("Helvetica", 9, QFont::Normal));
+        for (int i = 0; i < product->mashs.size(); i++) {
+            painter.fillRect(  0, y,   735, 20, m_line);
+            painter.drawText(  0, y+4, 160, 20, Qt::AlignLeft,  product->mashs.at(i).step_name);
+            painter.drawText(165, y+4,  90, 20, Qt::AlignLeft,  step_types[product->mashs.at(i).step_type]);
+            painter.drawText(260, y+4,  60, 20, Qt::AlignRight, QString("%1").arg(product->mashs.at(i).step_temp, 1, 'f', 1));
+            painter.drawText(325, y+4,  60, 20, Qt::AlignRight, QString("%1").arg(product->mashs.at(i).end_temp, 1, 'f', 1));
+            painter.drawText(390, y+4,  60, 20, Qt::AlignRight, QString("%1").arg(product->mashs.at(i).step_time, 1, 'f', 0));
+            painter.drawText(455, y+4,  60, 20, Qt::AlignRight, QString("%1").arg(product->mashs.at(i).ramp_time, 1, 'f', 0));
+            painter.drawText(520, y+4,  60, 20, Qt::AlignRight, QString("%1").arg(product->mashs.at(i).step_wg_ratio, 1, 'f', 2));
+            if (product->mashs.at(i).step_type != 1) {
+                painter.drawText(585, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(product->mashs.at(i).step_infuse_amount, 1, 'f', 1));
+                painter.drawText(660, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(product->mashs.at(i).step_infuse_temp, 1, 'f', 1));
+            }
+            y += 20;
+        }
+
+        if ((y + 80 + ((product->w2_amount > 0) ? 40:0)) > painter.device()->height()) {      /* waters + header + blank */
+            printer->newPage();
+            printHeader(&painter);
+            y = 120;
+        } else {
+            y += 40;
+        }
+
+	/* Water */
+        painter.setFont(QFont("Helvetica", 9, QFont::Bold));
+        painter.fillRect(  0, y,   735, 20, c_header);
+        painter.drawText(  0, y+4, 135, 20, Qt::AlignLeft,  tr("Water source"));
+        painter.drawText(135, y+4,  70, 20, Qt::AlignRight, tr("Volume"));
+        painter.drawText(210, y+4,  70, 20, Qt::AlignRight, tr("Ca"));
+        painter.drawText(285, y+4,  70, 20, Qt::AlignRight, tr("Mg"));
+        painter.drawText(360, y+4,  70, 20, Qt::AlignRight, tr("CaCO3"));
+        painter.drawText(435, y+4,  70, 20, Qt::AlignRight, tr("Na"));
+        painter.drawText(510, y+4,  70, 20, Qt::AlignRight, tr("Cl"));
+        painter.drawText(585, y+4,  70, 20, Qt::AlignRight, tr("SO4"));
+        painter.drawText(660, y+4,  70, 20, Qt::AlignRight, tr("pH"));
+        y += 20;
+        painter.setFont(QFont("Helvetica", 9, QFont::Normal));
+        painter.fillRect(  0, y,   735, 20, w_line);
+        painter.drawText(  0, y+4, 135, 20, Qt::AlignLeft,  product->w1_name);
+        painter.drawText(135, y+4,  70, 20, Qt::AlignRight, QString("%1 L").arg(product->w1_amount, 1, 'f', 1));
+        painter.drawText(210, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(product->w1_calcium, 1, 'f', 1));
+        painter.drawText(285, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(product->w1_magnesium, 1, 'f', 1));
+        painter.drawText(360, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(product->w1_total_alkalinity, 1, 'f', 1));
+        painter.drawText(435, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(product->w1_sodium, 1, 'f', 1));
+        painter.drawText(510, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(product->w1_chloride, 1, 'f', 1));
+        painter.drawText(585, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(product->w1_sulfate, 1, 'f', 1));
+        painter.drawText(660, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(product->w1_ph, 1, 'f', 2));
+        y += 20;
+	if (product->w2_amount > 0) {
+            /*
+             * If there is dillution water, show it and the mixed result too.
+             */
+            painter.fillRect(  0, y,   735, 20, w_line);
+            painter.drawText(  0, y+4, 135, 20, Qt::AlignLeft,  product->w2_name);
+            painter.drawText(135, y+4,  70, 20, Qt::AlignRight, QString("%1 L").arg(product->w2_amount, 1, 'f', 1));
+            painter.drawText(210, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(product->w2_calcium, 1, 'f', 1));
+            painter.drawText(285, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(product->w2_magnesium, 1, 'f', 1));
+            painter.drawText(360, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(product->w2_total_alkalinity, 1, 'f', 1));
+            painter.drawText(435, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(product->w2_sodium, 1, 'f', 1));
+            painter.drawText(510, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(product->w2_chloride, 1, 'f', 1));
+            painter.drawText(585, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(product->w2_sulfate, 1, 'f', 1));
+            painter.drawText(660, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(product->w2_ph, 1, 'f', 2));
+            y += 20;
+            painter.fillRect(  0, y,   735, 20, w_line);
+            painter.drawText(  0, y+4, 135, 20, Qt::AlignLeft,  tr("Mixed water"));
+            painter.drawText(135, y+4,  70, 20, Qt::AlignRight, QString("%1 L").arg(product->wg_amount, 1, 'f', 1));
+            painter.drawText(210, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(product->wg_calcium, 1, 'f', 1));
+            painter.drawText(285, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(product->wg_magnesium, 1, 'f', 1));
+            painter.drawText(360, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(product->wg_total_alkalinity, 1, 'f', 1));
+            painter.drawText(435, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(product->wg_sodium, 1, 'f', 1));
+            painter.drawText(510, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(product->wg_chloride, 1, 'f', 1));
+            painter.drawText(585, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(product->wg_sulfate, 1, 'f', 1));
+            painter.drawText(660, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(product->wg_ph, 1, 'f', 2));
+            y += 20;
+        }
+        painter.fillRect(  0, y,   735, 20, w_line);
+        painter.drawText(  0, y+4, 135, 20, Qt::AlignLeft,  tr("Treated water"));
+        painter.drawText(210, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(product->wb_calcium, 1, 'f', 1));
+        painter.drawText(285, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(product->wb_magnesium, 1, 'f', 1));
+        painter.drawText(360, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(product->wb_total_alkalinity, 1, 'f', 1));
+        painter.drawText(435, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(product->wb_sodium, 1, 'f', 1));
+        painter.drawText(510, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(product->wb_chloride, 1, 'f', 1));
+        painter.drawText(585, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(product->wb_sulfate, 1, 'f', 1));
+        painter.drawText(660, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(product->wb_ph, 1, 'f', 2));
+        y += 20;
+
+	/*
+         * Print product notes if present.
+         */
+        if (product->notes.length()) {
+            QStringList lines = product->notes.split("\n");
+
+            if (lines.size() && product->notes != "") {
+                if ((y + 80 + (lines.size() * 20)) > painter.device()->height()) {
+                    printer->newPage();
+                    printHeader(&painter);
+                    y = 120;
+                } else {
+                    y += 40;
+                }
+
+                /* Notes header */
+                painter.setFont(QFont("Helvetica", 9, QFont::Bold));
+                painter.setPen(Qt::black);
+                painter.fillRect(  0, y,   735, 20, c_header);
+                painter.drawText(  0, y+4, 735, 20, Qt::AlignCenter, tr("Recipe notes"));
+                y += 20;
+                painter.setFont(QFont("Helvetica", 9, QFont::Normal));
+                for (int i = 0; i < lines.size(); i++) {
+                    painter.fillRect(  0, y,   735, 20, c_line1);
+                    painter.drawText(  0, y+4, 735, 20, Qt::AlignLeft, lines[i]);
+                    y += 20;
+                }
+            }
+        }
+
+	if (product->stage > PROD_STAGE_BREW) {
+	    if ((y + 100) > painter.device()->height()) {
+		printer->newPage();
+		printHeader(&painter);
+		y = 120;
             } else {
             	y += 40;
             }
-
-	    /* Notes header */
-            painter.setFont(QFont("Helvetica", 9, QFont::Bold));
+	    painter.setFont(QFont("Helvetica", 9, QFont::Bold));
             painter.setPen(Qt::black);
             painter.fillRect(  0, y,   735, 20, c_header);
-            painter.drawText(  0, y+4, 735, 20, Qt::AlignCenter, tr("Recipe notes"));
+            painter.drawText(  0, y+2, 735, 20, Qt::AlignCenter, tr("Product brewday"));
+            y += 20;
+	    painter.setFont(QFont("Helvetica", 9, QFont::Normal));
+	    painter.fillRect(  0, y,   300, 20, c_line1);
+            painter.drawText(  0, y+4, 120, 20, Qt::AlignLeft, tr("Brewday start"));
+            painter.drawText(120, y+4, 180, 20, Qt::AlignLeft, product->brew_date_start.toString("dd MMM yyyy  hh:mm"));
+            painter.fillRect(435, y,   300, 20, c_line1);
+            painter.drawText(435, y+4, 120, 20, Qt::AlignLeft, tr("Brewday end"));
+            painter.drawText(555, y+4, 180, 20, Qt::AlignLeft, product->brew_date_end.toString("dd MMM yyyy  hh:mm"));
+
+	    /* Mash history */
+	    if ((y + 60 + (product->mashs.size() * 20)) > painter.device()->height()) {
+                printer->newPage();
+                printHeader(&painter);
+                y = 120;
+            } else {
+                y += 40;
+            }
+	    painter.setFont(QFont("Helvetica", 9, QFont::Bold));
+	    painter.fillRect(  0, y,   735, 20, m_line);
+	    painter.drawText( 30, y+4, 260, 20, Qt::AlignLeft, tr("Mash step"));
+	    painter.drawText(290, y+4, 120, 20, Qt::AlignLeft, tr("Step type"));
+	    painter.drawText(400, y+4, 110, 20, Qt::AlignLeft, tr("Temperature"));
+	    painter.drawText(510, y+4,  75, 20, Qt::AlignLeft, tr("Minutes"));
+	    painter.drawText(585, y+4,  75, 20, Qt::AlignLeft, tr("SG"));
+	    painter.drawText(660, y+4,  75, 20, Qt::AlignLeft, tr("pH"));
+	    painter.setFont(QFont("Helvetica", 9, QFont::Normal));
+	    y += 20;
+	    for (int i = 0; i < product->mashs.size(); i++) {
+		painter.fillRect(  0, y,   735, 20, c_line1);
+		painter.drawText(  0, y+4,  30, 20, Qt::AlignCenter, QString("%1").arg(i + 1));
+		painter.drawText( 30, y+4, 260, 20, Qt::AlignLeft, product->mashs.at(i).step_name);
+		painter.drawText(290, y+4, 120, 20, Qt::AlignLeft, step_types[product->mashs.at(i).step_type]);
+		painter.drawText(400, y+4, 110, 20, Qt::AlignLeft, QString("%1 - %2°C").
+				arg(product->mashs.at(i).step_temp, 1, 'f', 1).arg(product->mashs.at(i).end_temp, 1, 'f', 1));
+		painter.drawText(510, y+4,  75, 20, Qt::AlignLeft, QString("%1").arg(product->mashs.at(i).step_time, 1, 'f', 0));
+		painter.drawText(585, y+4,  75, 20, Qt::AlignLeft, QString("%1").arg(product->mashs.at(i).step_sg, 1, 'f', 3));
+		painter.drawText(660, y+4,  75, 20, Qt::AlignLeft, QString("%1").arg(product->mashs.at(i).step_ph, 1, 'f', 1));
+		y += 20;
+	    }
+
+	    /* Brew history */
+	    if ((y + 470) > painter.device()->height()) {
+                printer->newPage();
+                printHeader(&painter);
+                y = 120;
+            } else {
+                y += 20;
+            }
+	    painter.setFont(QFont("Helvetica", 9, QFont::Bold));
+            painter.fillRect(  0, y,   735, 20, m_line);
+            painter.drawText(  0, y+4, 250, 20, Qt::AlignLeft, tr("Brew item"));
+	    painter.drawText(250, y+4, 200, 20, Qt::AlignLeft, tr("Expected"));
+	    painter.drawText(450, y+4, 200, 20, Qt::AlignLeft, tr("Reached"));
+	    painter.drawText(650, y+4,  85, 20, Qt::AlignLeft, tr("Difference"));
+	    painter.setFont(QFont("Helvetica", 9, QFont::Normal));
+            y += 20;
+	    painter.fillRect(  0, y,   735, 20, c_line1);
+	    painter.drawText(  0, y+4, 250, 20, Qt::AlignLeft, tr("Mash pH"));
+	    painter.drawText(250, y+4, 200, 20, Qt::AlignLeft, QString("%1 pH").arg(product->mash_ph, 1, 'f', 2));
+	    painter.drawText(450, y+4, 200, 20, Qt::AlignLeft, QString("%1 pH").arg(product->brew_mash_ph, 1, 'f', 2));
+	    painter.drawText(650, y+4,  85, 20, Qt::AlignLeft, strDiff(product->mash_ph, product->brew_mash_ph, 2, " pH"));
+	    y += 20;
+            painter.fillRect(  0, y,   735, 20, c_line1);
+            painter.drawText(  0, y+4, 250, 20, Qt::AlignLeft, tr("Mash density"));
+	    painter.drawText(250, y+4, 200, 20, Qt::AlignLeft, strDensity(product->est_mash_sg));
+	    painter.drawText(450, y+4, 200, 20, Qt::AlignLeft, strDensity(product->brew_mash_sg));
+	    painter.drawText(650, y+4,  85, 20, Qt::AlignLeft, strDiff(product->est_mash_sg, product->brew_mash_sg, 3, " SG"));
+	    y += 20;
+            painter.fillRect(  0, y,   735, 20, c_line1);
+            painter.drawText(  0, y+4, 250, 20, Qt::AlignLeft, tr("Mash efficiency"));
+	    painter.drawText(250, y+4, 200, 20, Qt::AlignLeft, "100%");
+	    painter.drawText(450, y+4, 200, 20, Qt::AlignLeft, QString("%1%").arg(product->brew_mash_efficiency, 1, 'f', 1));
+	    painter.drawText(650, y+4,  85, 20, Qt::AlignLeft, strDiff(100.0, product->brew_mash_efficiency, 1, "%"));
+	    y += 20;
+            painter.fillRect(  0, y,   735, 20, c_line1);
+            painter.drawText(  0, y+4, 250, 20, Qt::AlignLeft, tr("Sparge pH"));
+	    painter.drawText(250, y+4, 200, 20, Qt::AlignLeft, QString("%1 pH").arg(product->sparge_ph, 1, 'f', 2));
+	    painter.drawText(450, y+4, 200, 20, Qt::AlignLeft, QString("%1 pH").arg(product->brew_sparge_ph, 1, 'f', 2));
+	    painter.drawText(650, y+4,  85, 20, Qt::AlignLeft, strDiff(product->sparge_ph, product->brew_sparge_ph, 2, " pH"));
+	    y += 25;
+
+            painter.fillRect(  0, y,   735, 20, c_line1);
+            painter.drawText(  0, y+4, 250, 20, Qt::AlignLeft, tr("Pre boil pH"));
+	    painter.drawText(450, y+4, 200, 20, Qt::AlignLeft, QString("%1 pH").arg(product->brew_preboil_ph, 1, 'f', 2));
+	    y += 20;
+            painter.fillRect(  0, y,   735, 20, c_line1);
+            painter.drawText(  0, y+4, 250, 20, Qt::AlignLeft, tr("Pre boil density"));
+	    painter.drawText(250, y+4, 200, 20, Qt::AlignLeft, strDensity(product->preboil_sg));
+	    painter.drawText(450, y+4, 200, 20, Qt::AlignLeft, strDensity(product->brew_preboil_sg));
+	    painter.drawText(650, y+4,  85, 20, Qt::AlignLeft, strDiff(product->preboil_sg, product->brew_preboil_sg, 3, " SG"));
+	    y += 20;
+            painter.fillRect(  0, y,   735, 20, c_line1);
+            painter.drawText(  0, y+4, 250, 20, Qt::AlignLeft, tr("Pre boil volume"));
+	    painter.drawText(250, y+4, 200, 20, Qt::AlignLeft, QString("%1 L").arg(product->boil_size * 1.04, 1, 'f', 1));
+	    painter.drawText(450, y+4, 200, 20, Qt::AlignLeft, QString("%1 L").arg(product->brew_preboil_volume, 1, 'f', 1));
+	    painter.drawText(650, y+4,  85, 20, Qt::AlignLeft, strDiff(product->boil_size * 1.04, product->brew_preboil_volume, 1, " L"));
+	    y += 20;
+            painter.fillRect(  0, y,   735, 20, c_line1);
+            painter.drawText(  0, y+4, 250, 20, Qt::AlignLeft, tr("Pre boil efficiency"));
+	    painter.drawText(250, y+4, 200, 20, Qt::AlignLeft, QString("%1%").arg(product->efficiency, 1, 'f', 1));
+	    painter.drawText(450, y+4, 200, 20, Qt::AlignLeft, QString("%1%").arg(product->brew_preboil_efficiency, 1, 'f', 1));
+	    painter.drawText(650, y+4,  85, 20, Qt::AlignLeft, strDiff(product->efficiency, product->brew_preboil_efficiency, 1, "%"));
+	    y += 25;
+            painter.fillRect(  0, y,   735, 20, c_line1);
+            painter.drawText(  0, y+4, 250, 20, Qt::AlignLeft, tr("After boil pH"));
+	    //painter.drawText(250, y+4, 200, 20, Qt::AlignLeft, QString("%1 pH").arg(product->brew_preboil_ph, 1, 'f', 2));
+	    painter.drawText(450, y+4, 200, 20, Qt::AlignLeft, QString("%1 pH").arg(product->brew_aboil_ph, 1, 'f', 2));
+	    y += 20;
+            painter.fillRect(  0, y,   735, 20, c_line1);
+            painter.drawText(  0, y+4, 250, 20, Qt::AlignLeft, tr("After boil density"));
+	    painter.drawText(250, y+4, 200, 20, Qt::AlignLeft, strDensity(product->est_og));
+            painter.drawText(450, y+4, 200, 20, Qt::AlignLeft, strDensity(product->brew_aboil_sg));
+            painter.drawText(650, y+4,  85, 20, Qt::AlignLeft, strDiff(product->est_og, product->brew_aboil_sg, 3, " SG"));
+	    y += 20;
+            painter.fillRect(  0, y,   735, 20, c_line1);
+            painter.drawText(  0, y+4, 250, 20, Qt::AlignLeft, tr("After boil volume"));
+	    painter.drawText(250, y+4, 200, 20, Qt::AlignLeft, QString("%1 L").arg(product->batch_size * 1.04, 1, 'f', 1));
+            painter.drawText(450, y+4, 200, 20, Qt::AlignLeft, QString("%1 L").arg(product->brew_aboil_volume, 1, 'f', 1));
+            painter.drawText(650, y+4,  85, 20, Qt::AlignLeft, strDiff(product->batch_size * 1.04, product->brew_aboil_volume, 1, " L"));
+	    y += 20;
+            painter.fillRect(  0, y,   735, 20, c_line1);
+            painter.drawText(  0, y+4, 250, 20, Qt::AlignLeft, tr("After boil efficiency"));
+	    painter.drawText(250, y+4, 200, 20, Qt::AlignLeft, QString("%1%").arg(product->efficiency, 1, 'f', 1));
+            painter.drawText(450, y+4, 200, 20, Qt::AlignLeft, QString("%1%").arg(product->brew_aboil_efficiency, 1, 'f', 1));
+            painter.drawText(650, y+4,  85, 20, Qt::AlignLeft, strDiff(product->efficiency, product->brew_aboil_efficiency, 1, "%"));
+	    y += 25;
+            painter.fillRect(  0, y,   735, 20, c_line1);
+            painter.drawText(  0, y+4, 250, 20, Qt::AlignLeft, tr("Chiller and trub loss"));
+	    painter.drawText(250, y+4, 200, 20, Qt::AlignLeft, QString("%1 L").arg(product->eq_trub_chiller_loss, 1, 'f', 1));
+            painter.drawText(450, y+4, 200, 20, Qt::AlignLeft, QString("%1 L").arg(product->brew_fermenter_tcloss, 1, 'f', 1));
+            painter.drawText(650, y+4,  85, 20, Qt::AlignLeft, strDiff(product->eq_trub_chiller_loss, product->brew_fermenter_tcloss, 1, " L"));
+	    y += 20;
+            painter.fillRect(  0, y,   735, 20, c_line1);
+            painter.drawText(  0, y+4, 250, 20, Qt::AlignLeft, tr("Top up water"));
+	    painter.drawText(250, y+4, 200, 20, Qt::AlignLeft, QString("%1 L").arg(product->eq_top_up_water, 1, 'f', 1));
+            painter.drawText(450, y+4, 200, 20, Qt::AlignLeft, QString("%1 L").arg(product->brew_fermenter_extrawater, 1, 'f', 1));
+            painter.drawText(650, y+4,  85, 20, Qt::AlignLeft, strDiff(product->eq_top_up_water, product->brew_fermenter_extrawater, 1, " L"));
+	    y += 20;
+            painter.fillRect(  0, y,   735, 20, c_line1);
+            painter.drawText(  0, y+4, 250, 20, Qt::AlignLeft, tr("Fermenter volume"));
+	    painter.drawText(250, y+4, 200, 20, Qt::AlignLeft, QString("%1 L").arg(product->batch_size - product->eq_trub_chiller_loss, 1, 'f', 1));
+            painter.drawText(450, y+4, 200, 20, Qt::AlignLeft, QString("%1 L").arg(product->brew_fermenter_volume, 1, 'f', 1));
+            painter.drawText(650, y+4,  85, 20, Qt::AlignLeft, strDiff(product->batch_size - product->eq_trub_chiller_loss, product->brew_fermenter_volume, 1, " L"));
+	    y += 20;
+            painter.fillRect(  0, y,   735, 20, c_line1);
+            painter.drawText(  0, y+4, 250, 20, Qt::AlignLeft, tr("Fermenter density"));
+	    painter.drawText(250, y+4, 200, 20, Qt::AlignLeft, strDensity(product->est_og));
+            painter.drawText(450, y+4, 200, 20, Qt::AlignLeft, strDensity(product->brew_fermenter_sg));
+            painter.drawText(650, y+4,  85, 20, Qt::AlignLeft, strDiff(product->est_og, product->brew_fermenter_sg, 3, " SG"));
+	    y += 20;
+            painter.fillRect(  0, y,   735, 20, c_line1);
+            painter.drawText(  0, y+4, 250, 20, Qt::AlignLeft, tr("Fermenter color"));
+	    painter.drawText(250, y+4, 200, 20, Qt::AlignLeft, QString("%1 EBC").arg(product->est_color, 1, 'f', 0));
+	    painter.drawText(450, y+4, 200, 20, Qt::AlignLeft, QString("%1 EBC").arg(product->brew_fermenter_color, 1, 'f', 0));
+	    painter.drawText(650, y+4,  85, 20, Qt::AlignLeft, strDiff(product->est_color, product->brew_fermenter_color, 0, " EBC"));
+	    y += 20;
+            painter.fillRect(  0, y,   735, 20, c_line1);
+            painter.drawText(  0, y+4, 250, 20, Qt::AlignLeft, tr("Fermenter IBU"));
+	    painter.drawText(250, y+4, 200, 20, Qt::AlignLeft, QString("%1 IBU").arg(product->est_ibu, 1, 'f', 0));
+            painter.drawText(450, y+4, 200, 20, Qt::AlignLeft, QString("%1 IBU").arg(product->brew_fermenter_ibu, 1, 'f', 0));
+            painter.drawText(650, y+4,  85, 20, Qt::AlignLeft, strDiff(product->est_ibu, product->brew_fermenter_ibu, 0, " IBU"));
+	    y += 25;
+            painter.fillRect(  0, y,   450, 20, c_line1);
+            painter.drawText(  0, y+4, 250, 20, Qt::AlignLeft, tr("Cooling method"));
+	    painter.drawText(250, y+4, 200, 20, Qt::AlignLeft, cooling_method[product->brew_cooling_method]);
+	    y += 20;
+            painter.fillRect(  0, y,   450, 20, c_line1);
+            painter.drawText(  0, y+4, 250, 20, Qt::AlignLeft, tr("Cooling temperature"));
+	    painter.drawText(250, y+4, 200, 20, Qt::AlignLeft, QString("%1°C").arg(product->brew_cooling_to, 1, 'f', 1));
+	    y += 20;
+            painter.fillRect(  0, y,   450, 20, c_line1);
+            painter.drawText(  0, y+4, 250, 20, Qt::AlignLeft, tr("Cooling time"));
+	    painter.drawText(250, y+4, 200, 20, Qt::AlignLeft, QString("%1 min").arg(product->brew_cooling_time, 1, 'f', 0));
+	}
+
+	if (product->stage > PROD_STAGE_TERTIARY) {
+	    if ((y + 200) > painter.device()->height()) {
+                printer->newPage();
+                printHeader(&painter);
+                y = 120;
+            } else {
+                y += 40;
+            }
+	    painter.setFont(QFont("Helvetica", 9, QFont::Bold));
+            painter.setPen(Qt::black);
+            painter.fillRect(  0, y,   735, 20, c_header);
+            painter.drawText(  0, y+2, 735, 20, Qt::AlignCenter, tr("Product fermentation"));
             y += 20;
             painter.setFont(QFont("Helvetica", 9, QFont::Normal));
-	    for (int i = 0; i < lines.size(); i++) {
-            	painter.fillRect(  0, y,   735, 20, c_line1);
-	    	painter.drawText(  0, y+4, 735, 20, Qt::AlignLeft, lines[i]);
-	    	y += 20;
-	    }
+	    painter.fillRect(  0, y,   300, 20, c_line1);
+            painter.drawText(  0, y+4, 120, 20, Qt::AlignLeft, tr("Primary start temp"));
+            painter.drawText(120, y+4, 180, 20, Qt::AlignLeft, QString("%1°C").arg(product->primary_start_temp, 1, 'f', 1));
+            painter.fillRect(435, y,   300, 20, c_line1);
+            painter.drawText(435, y+4, 120, 20, Qt::AlignLeft, tr("Primary peak temp"));
+            painter.drawText(555, y+4, 180, 20, Qt::AlignLeft, QString("%1°C").arg(product->primary_max_temp, 1, 'f', 1));
+	    y += 20;
+	    painter.fillRect(  0, y,   300, 20, c_line1);
+            painter.drawText(  0, y+4, 120, 20, Qt::AlignLeft, tr("Primary end temp"));
+            painter.drawText(120, y+4, 180, 20, Qt::AlignLeft, QString("%1°C").arg(product->primary_end_temp, 1, 'f', 1));
+            painter.fillRect(435, y,   300, 20, c_line1);
+            painter.drawText(435, y+4, 120, 20, Qt::AlignLeft, tr("Primary density"));
+	    painter.drawText(555, y+4, 180, 20, Qt::AlignLeft, QString("%1 SG").arg(product->primary_end_sg, 1, 'f', 3));
+	    y += 20;
+            painter.fillRect(  0, y,   300, 20, c_line1);
+            painter.drawText(  0, y+4, 120, 20, Qt::AlignLeft, tr("Primary end date"));
+            painter.drawText(120, y+4, 180, 20, Qt::AlignLeft, product->primary_end_date.toString("dd MMM yyyy"));
+	    y += 20;
+	    painter.fillRect(  0, y,   300, 20, c_line1);
+            painter.drawText(  0, y+4, 120, 20, Qt::AlignLeft, tr("Secondary end temp"));
+            painter.drawText(120, y+4, 180, 20, Qt::AlignLeft, QString("%1°C").arg(product->secondary_temp, 1, 'f', 1));
+            painter.fillRect(435, y,   300, 20, c_line1);
+            painter.drawText(435, y+4, 120, 20, Qt::AlignLeft, tr("Secondary density"));
+            painter.drawText(555, y+4, 180, 20, Qt::AlignLeft, QString("%1 SG").arg(product->secondary_end_sg, 1, 'f', 3));
+	    y += 20;
+            painter.fillRect(  0, y,   300, 20, c_line1);
+            painter.drawText(  0, y+4, 120, 20, Qt::AlignLeft, tr("Secondary end date"));
+            painter.drawText(120, y+4, 180, 20, Qt::AlignLeft, product->secondary_end_date.toString("dd MMM yyyy"));
+	    y += 20;
+            painter.fillRect(  0, y,   300, 20, c_line1);
+            painter.drawText(  0, y+4, 120, 20, Qt::AlignLeft, tr("Tertiary temperature"));
+            painter.drawText(120, y+4, 180, 20, Qt::AlignLeft, QString("%1°C").arg(product->tertiary_temp, 1, 'f', 1));
+            painter.fillRect(435, y,   300, 20, c_line1);
+            painter.drawText(435, y+4, 120, 20, Qt::AlignLeft, tr("Final density"));
+            painter.drawText(555, y+4, 180, 20, Qt::AlignLeft, QString("%1 SG").arg(product->fg, 1, 'f', 3));
+	    y += 20;
+	    painter.fillRect(  0, y,   300, 20, c_line1);
+            painter.drawText(  0, y+4, 120, 20, Qt::AlignLeft, tr("Tertiary end date"));
+            painter.drawText(120, y+4, 180, 20, Qt::AlignLeft, product->package_date.toString("dd MMM yyyy"));
+            painter.fillRect(435, y,   300, 20, c_line1);
+            painter.drawText(435, y+4, 120, 20, Qt::AlignLeft, tr("Apperant attenuation"));
+            painter.drawText(555, y+4, 180, 20, Qt::AlignLeft, QString("%1%").arg(Utils::calc_svg(product->brew_fermenter_sg, product->fg), 1, 'f', 1));
+	}
+
+	if (product->stage > PROD_STAGE_PACKAGE) {
+
+	}
+
+	if (product->stage > PROD_STAGE_TASTE) {
+
 	}
     }
 
@@ -688,6 +1344,17 @@
 }
 
 
+QString PrinterDialog::strDiff(double v1, double v2, int decimals, QString suffix)
+{
+    return QString("%1%2%3").arg((v2 > v1) ? "+":"").arg(v2 - v1, 1, 'f', decimals).arg(suffix);
+}
+
+
+QString PrinterDialog::strDensity(double density)
+{
+    return QString("%1 SG %2°Brix %3°P").arg(density, 1, 'f', 3).arg(Utils::sg_to_brix(density), 1, 'f', 1).arg(Utils::sg_to_plato(density), 1, 'f', 1);
+}
+
 
 void PrinterDialog::printHeader(QPainter *painter)
 {
@@ -712,17 +1379,23 @@
 	painter->drawText(120, 0,  500, 40, Qt::AlignLeft, tr("Yeastbank") + " " + my_brewery_name);
     } else if (p_job == PR_RECIPE) {
 	painter->drawText(120, 0,  500, 40, Qt::AlignLeft, recipe->name);
+    } else if (p_job == PR_PRODUCT) {
+        painter->drawText(120, 0,  500, 40, Qt::AlignLeft, product->code + "  " + product->name);
     } else {
         painter->drawText(120, 0,  500, 40, Qt::AlignLeft, "?? " + my_brewery_name);
     }
     /* The first normal header line */
     painter->setFont(QFont("Helvetica",10, QFont::Normal));
     painter->drawText(120,35,  80, 20, Qt::AlignLeft, tr("Date and time"));
-    painter->drawText(200,35, 400, 20, Qt::AlignLeft, ": " + QDateTime::currentDateTime().toString("dd-MM-yyyy hh:mm"));
+    painter->drawText(200,35, 400, 20, Qt::AlignLeft, ": " + QDateTime::currentDateTime().toString("dd-MMM-yyyy hh:mm"));
     if (p_job == PR_RECIPE) {
 	painter->drawText(120,55,  80, 20, Qt::AlignLeft, tr("Beer style"));
     	painter->drawText(200,55, 400, 20, Qt::AlignLeft, ": " + recipe->st_name);
     }
+    if (p_job == PR_PRODUCT) {
+        painter->drawText(120,55,  80, 20, Qt::AlignLeft, tr("Beer style"));
+        painter->drawText(200,55, 400, 20, Qt::AlignLeft, ": " + product->st_name);
+    }
     /* The report itself may print more lines from y = 55. */
 }
 
--- a/src/PrinterDialog.h	Mon May 23 14:16:44 2022 +0200
+++ b/src/PrinterDialog.h	Sat May 28 16:59:36 2022 +0200
@@ -6,7 +6,7 @@
 #include <QPainter>
 
 
-enum JobType { PR_SUPPLIES, PR_YEASTBANK, PR_RECIPE };
+enum JobType { PR_SUPPLIES, PR_YEASTBANK, PR_RECIPE, PR_PRODUCT };
 
 namespace Ui {
 class PrinterDialog;
@@ -37,6 +37,8 @@
     int p_rec;
 
     void printHeader(QPainter *painter);
+    QString strDensity(double density);
+    QString strDiff(double v1, double v2, int decimals, QString suffix);
 };
 
 #endif

mercurial