# HG changeset patch # User Michiel Broek # Date 1651601104 -7200 # Node ID bb6c06910f0f5c1057fb1a6f98b18bdbd52d3b73 # Parent 722a4eed545d38ce370bb6ac5a8526b357d88d55 Added calcSupplies() which shows if ingredients are in stock to brew the recipe. In tab 3, changed the fermentables numbers into more readable enum constants. Disable delete and edit buttons in fermentables rows for bottle and kegs sugars. Better mash time calculation in calcFermentables. Added check supplies. Added recalculate volumes. Update inventory when a fermentable is replaced. Added tooltips in brewing salts fields in the miscs table. diff -r 722a4eed545d -r bb6c06910f0f src/EditProduct.cpp --- a/src/EditProduct.cpp Mon May 02 22:42:19 2022 +0200 +++ b/src/EditProduct.cpp Tue May 03 20:05:04 2022 +0200 @@ -1092,6 +1092,23 @@ } +void EditProduct::calcSupplies() +{ + if (product->inventory_reduced > PROD_STAGE_PACKAGE) { + ui->ok_pmptLabel->setVisible(false); + ui->ok_pmptIcon->setVisible(false); + return; + } + + qDebug() << "calcSupplies() f:" << product->fermentables_ok /*<< "h:" << product->hops_ok << "m:" << product->miscs_ok << "y:" << product->yeasts_ok << "w:" << product->waters_ok*/; + if (product->fermentables_ok /*&& product->hops_ok && product->miscs_ok && product->yeasts_ok && product->waters_ok */) { + ui->ok_pmptIcon->setPixmap(QPixmap(QString::fromUtf8(":/icons/silk/tick.png"))); + } else { + ui->ok_pmptIcon->setPixmap(QPixmap(QString::fromUtf8(":/icons/silk/error.png"))); + } +} + + void EditProduct::refreshAll() { refreshFermentables(); diff -r 722a4eed545d -r bb6c06910f0f src/EditProduct.h --- a/src/EditProduct.h Mon May 02 22:42:19 2022 +0200 +++ b/src/EditProduct.h Tue May 03 20:05:04 2022 +0200 @@ -159,6 +159,7 @@ static bool misc_sort_test(const Miscs &D1, const Miscs &D2); static bool yeast_sort_test(const Yeasts &D1, const Yeasts &D2); void WindowTitle(); + void calcSupplies(); void showEquipment(); void initEquipment(); void setStage(); diff -r 722a4eed545d -r bb6c06910f0f src/EditProductTab1.cpp --- a/src/EditProductTab1.cpp Mon May 02 22:42:19 2022 +0200 +++ b/src/EditProductTab1.cpp Tue May 03 20:05:04 2022 +0200 @@ -298,7 +298,7 @@ ui->tabWidget->setTabEnabled(8, stage > PROD_STAGE_PLAN); /* Tab 10, fermentation */ - ui->tabWidget->setTabEnabled(9, stage > PROD_STAGE_PLAN); + ui->tabWidget->setTabEnabled(9, stage > PROD_STAGE_WAIT); /* Tab 11, packaging */ @@ -306,7 +306,7 @@ /* Tab 12, tasting */ - ui->tabWidget->setTabEnabled(11, stage > PROD_STAGE_PLAN); + ui->tabWidget->setTabEnabled(11, stage > PROD_STAGE_PACKAGE); } diff -r 722a4eed545d -r bb6c06910f0f src/EditProductTab3.cpp --- a/src/EditProductTab3.cpp Mon May 02 22:42:19 2022 +0200 +++ b/src/EditProductTab3.cpp Tue May 03 20:05:04 2022 +0200 @@ -109,9 +109,11 @@ item = new QTableWidgetItem(QString("%1 Kg").arg(product->fermentables.at(i).f_inventory, 4, 'f', 3, '0')); item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); + if (product->fermentables.at(i).f_inventory < product->fermentables.at(i).f_amount) + item->setForeground(QBrush(QColor(Qt::red))); ui->fermentablesTable->setItem(i, 8, item); - if (product->fermentables.at(i).f_added < 4) { + if (product->fermentables.at(i).f_added < FERMENTABLE_ADDED_BOTTLE) { item = new QTableWidgetItem(QString("%1%").arg(product->fermentables.at(i).f_percentage, 2, 'f', 1, '0')); } else { item = new QTableWidgetItem(QString("")); // Blank for bottling and kegging. @@ -122,27 +124,36 @@ to100Fermentables(i); /* Add the Delete row button */ - pWidget = new QWidget(); - QPushButton* btn_dele = new QPushButton(); - btn_dele->setObjectName(QString("%1").arg(i)); /* Send row with the button */ - btn_dele->setText(tr("Delete")); - connect(btn_dele, SIGNAL(clicked()), this, SLOT(deleteFermentRow_clicked())); - pLayout = new QHBoxLayout(pWidget); - pLayout->addWidget(btn_dele); - pLayout->setContentsMargins(5, 0, 5, 0); - pWidget->setLayout(pLayout); - ui->fermentablesTable->setCellWidget(i, 11, pWidget); + if (product->fermentables.at(i).f_added < FERMENTABLE_ADDED_BOTTLE) { + pWidget = new QWidget(); + QPushButton* btn_dele = new QPushButton(); + btn_dele->setObjectName(QString("%1").arg(i)); /* Send row with the button */ + btn_dele->setText(tr("Delete")); + connect(btn_dele, SIGNAL(clicked()), this, SLOT(deleteFermentRow_clicked())); + pLayout = new QHBoxLayout(pWidget); + pLayout->addWidget(btn_dele); + pLayout->setContentsMargins(5, 0, 5, 0); + pWidget->setLayout(pLayout); + ui->fermentablesTable->setCellWidget(i, 11, pWidget); - pWidget = new QWidget(); - QPushButton* btn_edit = new QPushButton(); - btn_edit->setObjectName(QString("%1").arg(i)); /* Send row with the button */ - btn_edit->setText(tr("Edit")); - connect(btn_edit, SIGNAL(clicked()), this, SLOT(editFermentRow_clicked())); - pLayout = new QHBoxLayout(pWidget); - pLayout->addWidget(btn_edit); - pLayout->setContentsMargins(5, 0, 5, 0); - pWidget->setLayout(pLayout); - ui->fermentablesTable->setCellWidget(i, 12, pWidget); + pWidget = new QWidget(); + QPushButton* btn_edit = new QPushButton(); + btn_edit->setObjectName(QString("%1").arg(i)); /* Send row with the button */ + btn_edit->setText(tr("Edit")); + connect(btn_edit, SIGNAL(clicked()), this, SLOT(editFermentRow_clicked())); + pLayout = new QHBoxLayout(pWidget); + pLayout->addWidget(btn_edit); + pLayout->setContentsMargins(5, 0, 5, 0); + pWidget->setLayout(pLayout); + ui->fermentablesTable->setCellWidget(i, 12, pWidget); + } else { + item = new QTableWidgetItem(""); + item->setToolTip(tr("Edit this from the package tab")); + ui->fermentablesTable->setItem(i, 11, item); + item = new QTableWidgetItem(""); + item->setToolTip(tr("Edit this from the package tab")); + ui->fermentablesTable->setItem(i, 12, item); + } } } @@ -150,7 +161,7 @@ void EditProduct::calcFermentables() { int i; - double psugar = 0, pcara = 0, d, s = 0, x, color; + double psugar = 0, pcara = 0, d, s = 0, x, cw, color; double vol = 0; // Volume sugars after boil double addedS = 0; // Added sugars after boil double addedmass = 0; // Added mass after boil @@ -165,6 +176,8 @@ double colort = 0; // Colors srm * vol totals double colorh = 0; // Colors ebc * vol * kt double colorn = 0; // Colors ebc * pt * pct + double bv = 0.925; // Beer loss efficiency + double sr = 0.95; // Mash and sparge efficiency qDebug() << "calcFermentables()"; @@ -177,10 +190,14 @@ if (product->mashs.at(i).step_type == 0) // Infusion mashinfuse += product->mashs.at(i).step_infuse_amount; if (product->mashs.at(i).step_temp < 75) { // Ignore mashout - mashtime += product->mashs.at(i).step_time; - mashtemp += product->mashs.at(i).step_time * product->mashs.at(i).step_temp; + double timem = product->mashs.at(i).step_time; + if (i > 0) + timem += product->mashs.at(i).ramp_time; + mashtime += timem; + mashtemp += timem * product->mashs.at(i).step_temp; } } + mashtime += 5; // Correction for missing last ramp_time. mashtemp = mashtemp / mashtime; mvol = mashinfuse; qDebug() << " mash time" << mashtime << "temp" << mashtemp << "infuse" << mashinfuse; @@ -223,15 +240,16 @@ } qDebug() << " adjust to 100" << product->fermentables_use100; + product->fermentables_ok = true; product->mashs_kg = 0; for (i = 0; i < product->fermentables.size(); i++) { - if (product->fermentables.at(i).f_type == 1 && product->fermentables.at(i).f_added < 4) // Sugars + if (product->fermentables.at(i).f_type == FERMENTABLE_TYPE_SUGAR && product->fermentables.at(i).f_added < FERMENTABLE_ADDED_BOTTLE) psugar += product->fermentables.at(i).f_percentage; - if (product->fermentables.at(i).f_graintype == 2 && product->fermentables.at(i).f_added < 4) // Crystal/Cara + if (product->fermentables.at(i).f_graintype == FERMENTABLE_GRAINTYPE_CRYSTAL && product->fermentables.at(i).f_added < FERMENTABLE_ADDED_BOTTLE) pcara += product->fermentables.at(i).f_percentage; d = product->fermentables.at(i).f_amount * (product->fermentables.at(i).f_yield / 100) * (1 - product->fermentables.at(i).f_moisture / 100); - if (product->fermentables.at(i).f_added == 0) { // Mash - if (mvol > 0) { // If mash volume is known + if (product->fermentables.at(i).f_added == FERMENTABLE_ADDED_MASH) { + if (mvol > 0) { // If mash volume is known mvol += product->fermentables.at(i).f_amount * product->fermentables.at(i).f_moisture / 100; s += d; } @@ -239,32 +257,42 @@ sugarsm += d; product->mashs_kg += product->fermentables.at(i).f_amount; } - if (product->fermentables.at(i).f_added == 0 || product->fermentables.at(i).f_added == 1) // Mash or boil + if (product->fermentables.at(i).f_added == FERMENTABLE_ADDED_MASH || product->fermentables.at(i).f_added == FERMENTABLE_ADDED_BOIL) sugarsf += d; - if (product->fermentables.at(i).f_added == 2 || product->fermentables.at(i).f_added == 3) { // Fermentation or lagering + if (product->fermentables.at(i).f_added == FERMENTABLE_ADDED_FERMENTATION || product->fermentables.at(i).f_added == FERMENTABLE_ADDED_LAGERING) { x = (product->fermentables.at(i).f_yield / 100) * (1 - product->fermentables.at(i).f_moisture / 100); addedS += product->fermentables.at(i).f_amount * x; addedmass += product->fermentables.at(i).f_amount; vol += (x * sugardensity + (1 - x) * 1) * product->fermentables.at(i).f_amount; } - if (product->fermentables.at(i).f_added == 0 && - (product->fermentables.at(i).f_type == 0 || product->fermentables.at(i).f_type == 4) && + if (product->fermentables.at(i).f_added == FERMENTABLE_ADDED_MASH && + (product->fermentables.at(i).f_type == FERMENTABLE_TYPE_GRAIN || product->fermentables.at(i).f_type == FERMENTABLE_TYPE_ADJUCT) && product->fermentables.at(i).f_color < 50) { lintner += product->fermentables.at(i).f_diastatic_power * product->fermentables.at(i).f_amount; } - if (product->fermentables.at(i).f_added < 4) { + if (product->fermentables.at(i).f_added < FERMENTABLE_ADDED_BOTTLE) { colort += product->fermentables.at(i).f_amount * Utils::ebc_to_srm(product->fermentables.at(i).f_color); colorh += product->fermentables.at(i).f_amount * product->fermentables.at(i).f_color * Utils::get_kt(product->fermentables.at(i).f_color); colorn += (product->fermentables.at(i).f_percentage / 100) * product->fermentables.at(i).f_color; // For 8.6 Pt wort. } - if (product->fermentables.at(i).f_added == 4) { // Bottle priming + if (product->fermentables.at(i).f_added == FERMENTABLE_ADDED_BOTTLE) { // Bottle priming ui->bottle_sug_weightShow->setValue(product->fermentables.at(i).f_amount * 1000); // product->fermentables.at(i).f_name select in dropdown } - if (product->fermentables.at(i).f_added == 5) { // Keg priming + if (product->fermentables.at(i).f_added == FERMENTABLE_ADDED_KEGS) { // Keg priming } + /* Check supplies */ + if ((((product->inventory_reduced <= PROD_STAGE_BREW) && (product->fermentables.at(i).f_added <= FERMENTABLE_ADDED_BOIL)) || + ((product->inventory_reduced <= PROD_STAGE_PRIMARY) && (product->fermentables.at(i).f_added == FERMENTABLE_ADDED_FERMENTATION)) || + ((product->inventory_reduced <= PROD_STAGE_TERTIARY) && (product->fermentables.at(i).f_added == FERMENTABLE_ADDED_LAGERING)) || + ((product->inventory_reduced <= PROD_STAGE_PACKAGE) && (product->fermentables.at(i).f_added == FERMENTABLE_ADDED_BOTTLE)) || + ((product->inventory_reduced <= PROD_STAGE_PACKAGE) && (product->fermentables.at(i).f_added == FERMENTABLE_ADDED_KEGS))) && + product->fermentables.at(i).f_inventory < product->fermentables.at(i).f_amount) { + product->fermentables_ok = false; + } } + qDebug() << " supplies" << product->fermentables_ok; qDebug() << " colort" << colort << "colorh" << colorh << "colorn" << colorn; qDebug() << " psugar" << psugar << "pcara" << pcara << "mvol" << mvol; qDebug() << " sugarsf" << sugarsf << "sugarsm" << sugarsm; @@ -274,32 +302,78 @@ product->est_mash_sg = Utils::plato_to_sg(s); ui->brew_mashsgShow->setValue(product->est_mash_sg); - double og = Utils::estimate_sg(sugarsf + addedS, product->batch_size); - qDebug() << " OG" << ui->est_ogEdit->value() << og; - product->est_og = og; - ui->est_ogEdit->setValue(og); - ui->est_og2Edit->setValue(og); - ui->est_og4Edit->setValue(og); - ui->est_ogShow->setValue(og); + /* Estimate total recipe OG */ + product->est_og = Utils::estimate_sg(sugarsf + addedS, product->batch_size); + qDebug() << " OG" << ui->est_ogEdit->value() << product->est_og; + ui->est_ogEdit->setValue(product->est_og); + ui->est_og2Edit->setValue(product->est_og); + ui->est_og4Edit->setValue(product->est_og); + ui->est_ogShow->setValue(product->est_og); + /* Estimate SG in kettle after boil */ product->est_og3 = Utils::estimate_sg(sugarsf, product->batch_size); ui->brew_aboilsgShow->setValue(product->est_og3); + /* Estimate SG in kettle before boil */ product->preboil_sg = Utils::estimate_sg(sugarsm, product->boil_size); ui->brew_preboilsgShow->setValue(product->preboil_sg); qDebug() << " preboil SG" << product->preboil_sg; /* + * Recalculate volumes + */ + double aboil_volume = product->batch_size; + if (product->brew_aboil_volume > 0) + aboil_volume = product->brew_aboil_volume / 1.04; // Volume @ 20 degrees. + if (product->brew_fermenter_tcloss == 0) { + product->brew_fermenter_tcloss = product->eq_trub_chiller_loss; + ui->brew_trublossEdit->setValue(product->brew_fermenter_tcloss); + } + product->brew_fermenter_volume = aboil_volume - product->brew_fermenter_tcloss + product->brew_fermenter_extrawater; + ui->brew_tofermentEdit->setValue(product->brew_fermenter_volume); + /* Calculate SG in fermenter */ + double ogx = product->brew_aboil_sg; + if (ogx < 1.002) + ogx = product->est_og3; + double topw = product->brew_fermenter_extrawater; + + if (product->brew_fermenter_volume > 0) { + double sug = Utils::sg_to_plato(ogx) * product->brew_fermenter_volume * ogx / 100; //kg of sugar in + sug += addedS; //kg + + if ((product->brew_fermenter_volume * ogx + addedmass) > 0) { + double pt = 100 * sug / (product->brew_fermenter_volume * ogx + addedmass + topw); + product->og = product->brew_fermenter_sg = round(Utils::plato_to_sg(pt) * 10000) / 10000.0; + ui->brew_fermentsgShow->setValue(product->brew_fermenter_sg); + // color + if (product->color_method == 4) { // Naudts + product->brew_fermenter_color = round(((pt / 8.6) * colorn) + (product->boil_time / 60)); + } else if (product->color_method == 3) { // Hans Halberstadt + product->brew_fermenter_color = round((4.46 * bv * sr) / (aboil_volume + topw) * colorh); + } else { + cw = colort / (aboil_volume + topw) * 8.34436; + product->brew_fermenter_color = Utils::kw_to_ebc(product->color_method, cw); + } + ui->brew_fermentcolorShow->setValue(product->brew_fermenter_color); + ui->brew_fermentcolorShow->setStyleSheet(Utils::ebc_to_style(product->brew_fermenter_color)); + } + } else { + // Negative volume + product->brew_fermenter_sg = product->brew_fermenter_color = 0; + ui->brew_fermentsgShow->setValue(0); + ui->brew_fermentcolorShow->setStyleSheet(0); + ui->brew_fermentcolorShow->setValue(0); + } + + /* * Color of the wort */ if (product->color_method == 4) { // Naudts - color = round(((Utils::sg_to_plato(og) / 8.6) * colorn) + (product->boil_time / 60)); + color = round(((Utils::sg_to_plato(product->est_og) / 8.6) * colorn) + (product->boil_time / 60)); } else if (product->color_method == 3) { // Hans Halberstadt - double bv = 0.925; // Beer loss efficiency - double sr = 0.95; // Mash and sparge efficiency color = round((4.46 * bv * sr) / product->batch_size * colorh); } else { - double cw = colort / product->batch_size * 8.34436; + cw = colort / product->batch_size * 8.34436; color = Utils::kw_to_ebc(product->color_method, cw); //qDebug() << " oud EBC" << color << "new EBC" << Utils::kw_to_newebc(product->color_method, cw) << "SRM" << Utils::kw_to_srm(product->color_method, cw); } @@ -327,50 +401,68 @@ * Calculate the apparant attenuation. */ double svg = 0; + double initcells = 0; if (product->yeasts.size() > 0) { for (i = 0; i < product->yeasts.size(); i++) { if (product->yeasts.at(i).y_use == 0) { // Used in primary if (product->yeasts.at(i).y_attenuation > svg) svg = product->yeasts.at(i).y_attenuation; // Take the highest if multiple yeasts. } + if (product->yeasts.at(i).y_form == 0) + initcells += (product->yeasts.at(i).y_cells / 1000000000) * product->yeasts.at(i).y_amount * (product->starter_viability / 100); + else + initcells += (product->yeasts.at(i).y_cells / 1000000) * product->yeasts.at(i).y_amount * (product->starter_viability / 100); // TODO: brett or others in secondary. + product->yeasts_ok = true; + if ((((product->inventory_reduced <= PROD_STAGE_PRIMARY) && (product->yeasts.at(i).y_use == 0)) || // Primary + ((product->inventory_reduced <= PROD_STAGE_SECONDARY) && (product->yeasts.at(i).y_use == 1)) || // Secondary + ((product->inventory_reduced <= PROD_STAGE_TERTIARY) && (product->yeasts.at(i).y_use == 2)) || // Tertiary + ((product->inventory_reduced <= PROD_STAGE_PACKAGE) && (product->yeasts.at(i).y_use == 3))) && // Bottle + (product->yeasts.at(i).y_inventory < product->yeasts.at(i).y_amount)) { + product->yeasts_ok = false; + } } qDebug() << " SVG" << svg; } + calcSupplies(); if (svg == 0) svg = 77.0; ui->est_svgEdit->setValue(svg); - double fg; if (product->mashs_kg > 0 && mashinfuse > 0 && mashtime > 0 && mashtemp > 0) - fg = Utils::estimate_fg(psugar, pcara, mashinfuse / product->mashs_kg, mashtime, mashtemp, svg, og); + product->est_fg = Utils::estimate_fg(psugar, pcara, mashinfuse / product->mashs_kg, mashtime, mashtemp, svg, product->est_og); else - fg = Utils::estimate_fg(psugar, pcara, 0, 0, 0, svg, og); - qDebug() << " FG" << ui->est_fgEdit->value() << fg; - product->est_fg = fg; - ui->est_fgEdit->setValue(fg); - ui->est_fg3Edit->setValue(fg); - ui->est_fgShow->setValue(fg); + product->est_fg = Utils::estimate_fg(psugar, pcara, 0, 0, 0, svg, product->est_og); + qDebug() << " FG" << ui->est_fgEdit->value() << product->est_fg; + ui->est_fgEdit->setValue(product->est_fg); + ui->est_fg3Edit->setValue(product->est_fg); + ui->est_fgShow->setValue(product->est_fg); - double abv = Utils::abvol(og, fg); - qDebug() << " ABV" << ui->est_abvEdit->value() << abv; - ui->est_abvEdit->setValue(abv); - ui->est_abv2Edit->setValue(abv); - ui->est_abvShow->setValue(abv); - product->est_abv = abv; + /* + * Calculate the final values if available. + */ + if ((product->stage >= 6) && (product->fg > 0.990) && (product->fg < product->brew_fermenter_sg)) { + + } + + product->est_abv = Utils::abvol(product->est_og, product->est_fg); + qDebug() << " ABV" << ui->est_abvEdit->value() << product->est_abv; + ui->est_abvEdit->setValue(product->est_abv); + ui->est_abv2Edit->setValue(product->est_abv); + ui->est_abvShow->setValue(product->est_abv); /* * Calculate kilocalories/liter. Formula from brouwhulp. * Take the alcohol and sugar parts and then combine. */ - double alc = 1881.22 * fg * (og - fg) / (1.775 - og); - double sug = 3550 * fg * (0.1808 * og + 0.8192 * fg - 1.0004); + double alc = 1881.22 * product->est_fg * (product->est_og - product->est_fg) / (1.775 - product->est_og); + double sug = 3550 * product->est_fg * (0.1808 * product->est_og + 0.8192 * product->est_fg - 1.0004); ui->calEdit->setValue(round((alc + sug) / (12 * 0.0295735296))); // Bottle priming double priming_total = 0; for (i = 0; i < product->fermentables.size(); i++) { - if (product->fermentables.at(i).f_added == 4) { + if (product->fermentables.at(i).f_added == FERMENTABLE_ADDED_BOTTLE) { priming_total += ((product->fermentables.at(i).f_yield / 100) * (1 - product->fermentables.at(i).f_moisture / 100)) * product->fermentables.at(i).f_amount; qDebug() << " priming" << product->fermentables.at(i).f_amount << "total" << priming_total; @@ -400,11 +492,11 @@ double sug = Utils::sg_to_plato(og) * product->batch_size * og / 100.0; // total amount of sugars in kg. for (i = 0; i < product->fermentables.size(); i++) { - if (product->fermentables.at(i).f_added < 4) { + if (product->fermentables.at(i).f_added < FERMENTABLE_ADDED_BOTTLE) { d = product->fermentables.at(i).f_percentage / 100.0 * (product->fermentables.at(i).f_yield / 100.0) * (1 - product->fermentables.at(i).f_moisture / 100.0); - if (product->fermentables.at(i).f_added == 0) // Mash + if (product->fermentables.at(i).f_added == FERMENTABLE_ADDED_MASH) d = efficiency / 100.0 * d; tot += d; } @@ -477,7 +569,7 @@ newf.f_supplier = ""; newf.f_amount = 0; newf.f_cost = 0; - newf.f_type = 0; + newf.f_type = FERMENTABLE_TYPE_GRAIN; newf.f_yield = 0; newf.f_color = 0; newf.f_coarse_fine_diff = 0; @@ -486,8 +578,8 @@ newf.f_protein = 0; newf.f_dissolved_protein = 0; newf.f_max_in_batch = 100; - newf.f_graintype = 0; - newf.f_added = 0; + newf.f_graintype = FERMENTABLE_GRAINTYPE_BASE; + newf.f_added = FERMENTABLE_ADDED_MASH; newf.f_recommend_mash = true; newf.f_add_after_boil = false; newf.f_adjust_to_total_100 = false; @@ -524,10 +616,10 @@ */ double total = 0; for (int i = 0; i < product->fermentables.size(); i++) - if (product->fermentables.at(i).f_added < 4) // Only before bottle/kegging + if (product->fermentables.at(i).f_added < FERMENTABLE_ADDED_BOTTLE) // Only before bottle/kegging total += product->fermentables.at(i).f_amount; for (int i = 0; i < product->fermentables.size(); i++) - if (product->fermentables.at(i).f_added < 4) + if (product->fermentables.at(i).f_added < FERMENTABLE_ADDED_BOTTLE) product->fermentables[i].f_percentage = product->fermentables.at(i).f_amount / total * 100; is_changed(); @@ -540,7 +632,7 @@ QTableWidgetItem *item; double total = 0, perc; - if (product->fermentables_use100 && product->fermentables.at(product->fermentables_row).f_added < 4) + if (product->fermentables_use100 && product->fermentables.at(product->fermentables_row).f_added < FERMENTABLE_ADDED_BOTTLE) return; qDebug() << "ferment_amount_changed()" << product->fermentables_row << val; @@ -551,13 +643,13 @@ ui->fermentablesTable->setItem(product->fermentables_row, 7, item); for (int i = 0; i < product->fermentables.size(); i++) - if (product->fermentables.at(i).f_added < 4) // Only before bottle/kegging + if (product->fermentables.at(i).f_added < FERMENTABLE_ADDED_BOTTLE) // Only before bottle/kegging total += product->fermentables.at(i).f_amount; /* * Recalculate the percentages */ for (int i = 0; i < product->fermentables.size(); i++) { - if (product->fermentables.at(i).f_added < 4) { + if (product->fermentables.at(i).f_added < FERMENTABLE_ADDED_BOTTLE) { perc = product->fermentables.at(i).f_amount / total * 100; product->fermentables[i].f_percentage = perc; item = new QTableWidgetItem(QString("%1%").arg(perc, 2, 'f', 1, '0')); @@ -585,7 +677,7 @@ * this is not the entry to be adjusted to 100. */ for (int i = 0; i < product->fermentables.size(); i++) { - if (product->fermentables.at(i).f_added < 4) // Only before bottle/kegging + if (product->fermentables.at(i).f_added < FERMENTABLE_ADDED_BOTTLE) // Only before bottle/kegging total += product->fermentables.at(i).f_amount; if (product->fermentables.at(i).f_adjust_to_total_100) row100 = i; @@ -625,7 +717,7 @@ { qDebug() << "ferment_to100_changed()" << product->fermentables_row << val << product->fermentables_use100; - if (product->fermentables.at(product->fermentables_row).f_added >= 4) { + if (product->fermentables.at(product->fermentables_row).f_added >= FERMENTABLE_ADDED_BOTTLE) { const QSignalBlocker blocker1(to100Edit); product->fermentables[product->fermentables_row].f_adjust_to_total_100 = false; to100Edit->setChecked(false); @@ -684,7 +776,7 @@ * Search the fermentable pointed by the index and instock flag. */ QString sql = "SELECT name,origin,supplier,cost,type,yield,color,coarse_fine_diff,moisture,diastatic_power,protein,dissolved_protein,max_in_batch," - "graintype,recommend_mash,add_after_boil,di_ph,acid_to_ph_57 FROM inventory_fermentables "; + "graintype,recommend_mash,add_after_boil,di_ph,acid_to_ph_57,inventory FROM inventory_fermentables "; if (instock) sql.append("WHERE inventory > 0 "); sql.append("ORDER BY supplier,name"); @@ -694,7 +786,6 @@ for (int i = 0; i < (val - 1); i++) { query.next(); } - qDebug() << "found" << query.value(2).toString() << query.value(0).toString(); /* * Replace the fermentable record contents @@ -717,6 +808,7 @@ product->fermentables[product->fermentables_row].f_add_after_boil = query.value(15).toInt() ? true:false; product->fermentables[product->fermentables_row].f_di_ph = query.value(16).toDouble(); product->fermentables[product->fermentables_row].f_acid_to_ph_57 = query.value(17).toDouble(); + product->fermentables[product->fermentables_row].f_inventory = query.value(18).toDouble(); /* * Update the visible fields @@ -745,6 +837,12 @@ item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); ui->fermentablesTable->setItem(product->fermentables_row, 6, item); + item = new QTableWidgetItem(QString("%1 Kg").arg(product->fermentables.at(product->fermentables_row).f_inventory, 4, 'f', 3, '0')); + item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); + if (product->fermentables.at(product->fermentables_row).f_inventory < product->fermentables.at(product->fermentables_row).f_amount) + item->setForeground(QBrush(QColor(Qt::red))); + ui->fermentablesTable->setItem(product->fermentables_row, 8, item); + calcFermentables(); is_changed(); } @@ -783,15 +881,15 @@ item->setTextAlignment(Qt::AlignCenter|Qt::AlignVCenter); ui->fermentablesTable->setItem(product->fermentables_row, 5, item); - famountEdit->setReadOnly(product->fermentables_use100 && product->fermentables.at(product->fermentables_row).f_added < 4); - pctEdit->setReadOnly(! (product->fermentables_use100 && product->fermentables.at(product->fermentables_row).f_added < 4)); + famountEdit->setReadOnly(product->fermentables_use100 && product->fermentables.at(product->fermentables_row).f_added < FERMENTABLE_ADDED_BOTTLE); + pctEdit->setReadOnly(! (product->fermentables_use100 && product->fermentables.at(product->fermentables_row).f_added < FERMENTABLE_ADDED_BOTTLE)); double total = 0; for (int i = 0; i < product->fermentables.size(); i++) - if (product->fermentables.at(i).f_added < 4) // Only before bottle/kegging + if (product->fermentables.at(i).f_added < FERMENTABLE_ADDED_BOTTLE) // Only before bottle/kegging total += product->fermentables.at(i).f_amount; for (int i = 0; i < product->fermentables.size(); i++) - if (product->fermentables.at(i).f_added < 4) + if (product->fermentables.at(i).f_added < FERMENTABLE_ADDED_BOTTLE) product->fermentables[i].f_percentage = product->fermentables.at(i).f_amount / total * 100; is_changed(); @@ -897,7 +995,7 @@ pctEdit->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); pctEdit->setAccelerated(true); pctEdit->setDecimals(1); - if (product->fermentables_use100 && product->fermentables.at(product->fermentables_row).f_added < 4) { + if (product->fermentables_use100 && product->fermentables.at(product->fermentables_row).f_added < FERMENTABLE_ADDED_BOTTLE) { if (product->fermentables.at(product->fermentables_row).f_adjust_to_total_100) pctEdit->setReadOnly(true); else @@ -916,8 +1014,6 @@ faddedEdit->addItem(tr("Boil")); faddedEdit->addItem(tr("Fermentation")); faddedEdit->addItem(tr("Lagering")); - faddedEdit->addItem(tr("Bottle")); - faddedEdit->addItem(tr("Kegs")); faddedEdit->setCurrentIndex(product->fermentables.at(product->fermentables_row).f_added); to100Edit = new QCheckBox(dialog); @@ -960,13 +1056,13 @@ */ double total = 0; for (int i = 0; i < product->fermentables.size(); i++) - if (product->fermentables.at(i).f_added < 4) // Only before bottle/kegging + if (product->fermentables.at(i).f_added < FERMENTABLE_ADDED_BOTTLE) // Only before bottle/kegging total += product->fermentables.at(i).f_amount; product->fermentables_use100 = false; for (int i = 0; i < product->fermentables.size(); i++) { if (product->fermentables.at(i).f_adjust_to_total_100) product->fermentables_use100 = true; - if (product->fermentables.at(i).f_added < 4) { + if (product->fermentables.at(i).f_added < FERMENTABLE_ADDED_BOTTLE) { product->fermentables[i].f_percentage = product->fermentables.at(i).f_amount / total * 100; } } diff -r 722a4eed545d -r bb6c06910f0f src/EditProductTab5.cpp --- a/src/EditProductTab5.cpp Mon May 02 22:42:19 2022 +0200 +++ b/src/EditProductTab5.cpp Tue May 03 20:05:04 2022 +0200 @@ -108,8 +108,12 @@ * Not for water agents, these are set on the water tab. */ if (product->miscs.at(i).m_type == 4) { - ui->miscsTable->removeCellWidget(i, 6); - ui->miscsTable->removeCellWidget(i, 7); + item = new QTableWidgetItem(""); + item->setToolTip(tr("Edit this from the water tab")); + ui->miscsTable->setItem(i, 6, item); + item = new QTableWidgetItem(""); + item->setToolTip(tr("Edit this from the water tab")); + ui->miscsTable->setItem(i, 7, item); } else { pWidget = new QWidget(); QPushButton* btn_dele = new QPushButton(); diff -r 722a4eed545d -r bb6c06910f0f src/global.h --- a/src/global.h Mon May 02 22:42:19 2022 +0200 +++ b/src/global.h Tue May 03 20:05:04 2022 +0200 @@ -524,9 +524,14 @@ */ int fermentables_row; ///< Current row, -1 is invalid. bool fermentables_use100; ///< Use percentages instead of amount + bool fermentables_ok; ///< Inventory check int hops_row; + bool hops_ok; int miscs_row; + bool miscs_ok; int yeasts_row; + bool yeasts_ok; + bool waters_ok; int mashs_row; double mashs_kg; ///< Kg fermentables in the mash. int mashs_time; ///< Total mash time. @@ -572,8 +577,38 @@ extern const QStringList prod_split; extern const QStringList recipe_types; extern const QStringList style_types; + +enum FermentableTypes { + FERMENTABLE_TYPE_GRAIN, + FERMENTABLE_TYPE_SUGAR, + FERMENTABLE_TYPE_EXTRACT, + FERMENTABLE_TYPE_DRY_EXTRACT, + FERMENTABLE_TYPE_ADJUCT +}; + extern const QStringList fermentable_types; + +enum FermentableGraintypes { + FERMENTABLE_GRAINTYPE_BASE, + FERMENTABLE_GRAINTYPE_ROAST, + FERMENTABLE_GRAINTYPE_CRYSTAL, + FERMENTABLE_GRAINTYPE_KILNED, + FERMENTABLE_GRAINTYPE_SOUR_MALT, + FERMENTABLE_GRAINTYPE_SPECIAL, + FERMENTABLE_GRAINTYPE_NO_MALT +}; + extern const QStringList fermentable_graintypes; + +enum FermentableAdded { + FERMENTABLE_ADDED_MASH, + FERMENTABLE_ADDED_BOIL, + FERMENTABLE_ADDED_FERMENTATION, + FERMENTABLE_ADDED_LAGERING, + FERMENTABLE_ADDED_BOTTLE, + FERMENTABLE_ADDED_KEGS +}; + extern const QStringList fermentable_added; extern const QStringList hop_types; extern const QStringList hop_forms; diff -r 722a4eed545d -r bb6c06910f0f ui/EditProduct.ui --- a/ui/EditProduct.ui Mon May 02 22:42:19 2022 +0200 +++ b/ui/EditProduct.ui Tue May 03 20:05:04 2022 +0200 @@ -173,7 +173,7 @@ 870 - 180 + 200 131 20 @@ -189,7 +189,7 @@ 1010 - 180 + 200 61 21 @@ -1222,10 +1222,10 @@ true - - - - 620 + + + + 740 180 131 20 @@ -1238,6 +1238,22 @@ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + 880 + 180 + 20 + 20 + + + + + + + :/icons/silk/error.png + +