src/EditProductTab11.cpp

Mon, 06 Jun 2022 17:15:27 +0200

author
Michiel Broek <mbroek@mbse.eu>
date
Mon, 06 Jun 2022 17:15:27 +0200
changeset 260
42b88d85fefc
parent 238
047e99c90848
child 283
242a68fa7186
permissions
-rw-r--r--

Fix default divide_size field in products. Update miscs table column 6 and 7 tooltips and display of the buttons after sort. After a new misc product is selected, update the current row index because the row may be moved. Fix some display misc values in the checklist, they were not multiplied by 1000. Fix display of some bars if the value was 24.

/**
 * EditProduct.cpp is part of bmsapp.
 *
 * Tab 11, package
 *
 * bmsapp is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * bmsapp is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

double EditProduct::ResCO2(double T)
{
    double F = T * 1.8 + 32;
    return round((3.0378 - 0.050062 * F + 0.00026555 * F * F) * 1000000.0) / 1000000.0;
}


double EditProduct::CarbCO2toS(double CO2, double T, double SFactor)
{
    //var sugar = SFactor * (CO2 - ResCO2(CO2, T)) / 0.286;
    double sugar = round((SFactor * (CO2 - ResCO2(T)) * 4.014094) * 1000000.0) / 1000000.0;
    if (sugar < 0)
	sugar = 0;
    return sugar; 	//Round(sugar, 3);
}


double EditProduct::GetPressure(double CO2, double T1, double T2)
{
    double V = CO2 - ResCO2(T1);
    V = CO2; // TODO: temp only total pressure, testing
    if (V < 0)
	return 0;

    double P = -1.09145427669121 + 0.00800006989646477 * T2 + 0.000260276315484684 * T2 * T2 + 0.0215142075945119 * T2 * V +
		0.674996600795854 * V + -0.00471757220150754 * V * V;
    if (P < 0)
	P = 0;
    P = round((P * 1.01325) * 100.0) / 100.0;	// atm to bar
    qDebug() << "  GetPressure(" << CO2 << "," << T1 << "," << T2 << ") V:" << V << "Bar:" << P << "ignored ResCO2:" << ResCO2(T1);
    return P;
}


double EditProduct::CarbCO2ToPressure(double CO2, double T)
{
    return (CO2 - (-0.000005594056 * pow(T, 4) + 0.000144357886 * pow(T, 3) +
		0.000362999168 * T * T - 0.064872987645 * T + 1.641145175049)) /
		(0.00000498031 * pow(T, 4) - 0.00024358267 * pow(T, 3) + 0.00385867329 * T * T - 0.05671206825 * T + 1.53801423376);
}


void EditProduct::calcPack()
{
    int		i, j;
    bool	found1, found2;
    QSqlQuery	query;
    double	TSec, SFactor;

    qDebug() << "calcPack()" << product->package_volume << product->package_abv << "inf" << product->package_infuse_amount << product->package_infuse_abv;

    if (product->package_volume < 1) {
	/*
	 * If there is not enough to package, then don't
	 * do any calculations and clear the rest of the form.
	 */
	product->package_volume = 0;
	ui->pack_finalabvShow->setValue(0);

	return;
    }

    double bvol = product->package_volume - (product->package_abv * product->package_volume) / 100.0;
    double balc = product->package_volume - bvol;
    double mvol = product->package_infuse_amount - (product->package_infuse_abv * product->package_infuse_amount) / 100.0;
    double malc = product->package_infuse_amount - mvol;
    double talc = balc + malc;
    double tvol = bvol + mvol;

    product->final_abv = round(talc / (tvol + talc) * 10000.0) / 100.0;
    ui->pack_finalabvShow->setValue(product->final_abv);

    TSec = product->secondary_temp;
    if (TSec < 1)
	TSec = product->primary_end_temp;
    if (TSec < 1)
	TSec = 18;

    /*
     * For bottles and kegs use the following complicated procedure to
     * find the needed priming sugars.
     *
     * 1. If we need a priming sugar then first see in the fermentables
     *    table if there is one selected. If not, clear sugars and done.
     * 2. Then, we update the data from the fermentables inventory.
     * 3. Set the found sugar in the pulldown menu.
     * 4. Calculate the sugar in gr/L and total amount need.
     * 5. Calculate the ABV in the bottles/kegs.
     * 6. Calculate the pressure build by the refermentation.
     *
     * Note that this is all a leftover from the web based application that
     * did work like this. It's a bit strange but it will allways give
     * the right data and sugar concentrations.
     * Sometimes bugs have good things.
     */
    found1 = false;
    if (product->bottle_amount) {
	for (i = 0; i < product->fermentables.size(); i++) {
	    if (product->fermentables.at(i).f_added == FERMENTABLE_ADDED_BOTTLE) {
		found1 = true;
		break;
	    }
	}
       	if (found1) {
	    SFactor = 1 / ((product->fermentables.at(i).f_yield / 100) * (1 - product->fermentables.at(i).f_moisture / 100));
	    qDebug() << "  bottle sugar" << product->fermentables.at(i).f_name << SFactor << TSec;

	    query.prepare("SELECT name,supplier FROM inventory_fermentables WHERE type = '1' OR type = '3' ORDER BY name");      // Sugars or dry extract
	    query.exec();
	    j = 0;
	    found2 = false;
	    while (query.next()) {
		j++;
		if (query.value(0).toString() == product->fermentables.at(i).f_name && query.value(1).toString() == product->fermentables.at(i).f_supplier) {
		    ui->bottle_sugarEdit->setCurrentIndex(j);
		    product->bottle_priming_sugar = j;
		    found2 = true;
		    break;
		}
	    }
	    if (! found2) {
		ui->bottle_sugarEdit->setCurrentIndex(0);	// Make sure not selected
		product->fermentables.removeAt(i);		// Remove false fermentable
		refreshFermentables();
	    } else {
		product->bottle_priming_amount = CarbCO2toS(product->bottle_carbonation, TSec, SFactor);
		ui->bottle_sug_amountShow->setValue(product->bottle_priming_amount);
		double total = round(product->bottle_priming_amount * product->bottle_amount * 100.0) / 100000.0;
		qDebug() << "  total" << total << product->fermentables.at(i).f_amount;
		if (total != product->fermentables.at(i).f_amount) {
		    qDebug() << "  update priming sugar" << total;
		    product->fermentables[i].f_amount = total;
		    refreshFermentables();
		    is_changed();
		}
		ui->bottle_sug_weightShow->setValue(total * 1000);

		double pabv = product->final_abv + (product->bottle_priming_amount * (1 / SFactor) * 0.47) / 7.907;
		double pvol = product->bottle_amount - (pabv * product->bottle_amount) / 100;
		talc = product->bottle_amount - pvol;
  		tvol = pvol + product->bottle_priming_water;
		product->bottle_abv = talc / (tvol + talc) * 100;
		product->bottle_bar = GetPressure(product->bottle_carbonation, TSec, product->bottle_carbonation_temp);
		ui->bottle_abvShow->setValue(product->bottle_abv);
		ui->bottle_barShow->setValue(product->bottle_bar);
	    }
	}
    }
    if (! found1) {
	qDebug() << "  no bottle priming";
	ui->bottle_sug_amountShow->setValue(0);
	ui->bottle_sug_weightShow->setValue(0);
	ui->bottle_abvShow->setValue(0);
	ui->bottle_barShow->setValue(0);
	product->bottle_abv = 0;
	product->bottle_bar = 0;
    }

    ui->keg_sugarLabel->setEnabled(! product->keg_forced_carb);
    ui->keg_sugarEdit->setEnabled(! product->keg_forced_carb);
    ui->keg_sug_weightLabel->setEnabled(! product->keg_forced_carb);
    ui->keg_sug_weightShow->setEnabled(! product->keg_forced_carb);
    ui->keg_sug_waterLabel->setEnabled(! product->keg_forced_carb);
    ui->keg_sug_waterEdit->setEnabled(! product->keg_forced_carb);
    ui->keg_sug_amountLabel->setEnabled(! product->keg_forced_carb);
    ui->keg_sug_amountShow->setEnabled(! product->keg_forced_carb);

    // keg_amount keg_carbonation keg_priming_sugar keg_priming_amount keg_priming_water keg_carbonation_temp keg_forced_carb keg_pressure
    found1 = false;
    if (product->keg_amount) {

	double Pressure = CarbCO2ToPressure(product->keg_carbonation, product->keg_carbonation_temp);
	if (Pressure < 0)
	    Pressure = 0;
	product->keg_pressure = Pressure;
	ui->keg_barShow->setValue(Pressure);

	if (! product->keg_forced_carb) {
	    for (i = 0; i < product->fermentables.size(); i++) {
            	if (product->fermentables.at(i).f_added == FERMENTABLE_ADDED_KEGS) {
                    found1 = true;
                    break;
            	}
            }
            if (found1) {
            	SFactor = 1 / ((product->fermentables.at(i).f_yield / 100) * (1 - product->fermentables.at(i).f_moisture / 100));
            	qDebug() << "  kegs sugar" << product->fermentables.at(i).f_name << SFactor << TSec;

            	query.prepare("SELECT name,supplier FROM inventory_fermentables WHERE type = '1' OR type = '3' ORDER BY name");      // Sugars or dry extract
            	query.exec();
            	j = 0;
            	found2 = false;
            	while (query.next()) {
                    j++;
                    if (query.value(0).toString() == product->fermentables.at(i).f_name && query.value(1).toString() == product->fermentables.at(i).f_supplier) {
                    	ui->keg_sugarEdit->setCurrentIndex(j);
                    	product->keg_priming_sugar = j;
                    	found2 = true;
                    	break;
                    }
            	}
            	if (! found2) {
                    ui->keg_sugarEdit->setCurrentIndex(0);	// Make sure not selected
                    product->fermentables.removeAt(i);	// Remove false fermentable
                    refreshFermentables();
            	} else {
                    product->keg_priming_amount = CarbCO2toS(product->keg_carbonation, TSec, SFactor);
                    ui->keg_sug_amountShow->setValue(product->keg_priming_amount);
                    double total = round(product->keg_priming_amount * product->keg_amount * 100.0) / 100000.0;
                    qDebug() << "  total" << total << product->fermentables.at(i).f_amount;
                    if (total != product->fermentables.at(i).f_amount) {
                    	qDebug() << "  update priming sugar" << total;
                    	product->fermentables[i].f_amount = total;
                    	refreshFermentables();
                    	is_changed();
                    }
		    ui->keg_sug_weightShow->setValue(total * 1000);

                    double pabv = product->final_abv + (product->keg_priming_amount * (1 / SFactor) * 0.47) / 7.907;
                    double pvol = product->keg_amount - (pabv * product->keg_amount) / 100;
                    talc = product->keg_amount - pvol;
                    tvol = pvol + product->keg_priming_water;
		    product->keg_abv = talc / (tvol + talc) * 100;
		    product->keg_bar = GetPressure(product->keg_carbonation, TSec, product->keg_carbonation_temp);
                    ui->keg_abvShow->setValue(product->keg_abv);
                    ui->keg_barShow->setValue(product->keg_bar);
            	}
	    } // if priming sugar.
	    if (! found1) {
        	qDebug() << "  no keg priming";
        	ui->keg_sug_amountShow->setValue(0);
        	ui->keg_sug_weightShow->setValue(0);
        	ui->keg_abvShow->setValue(0);
		product->keg_abv = 0;
		product->keg_bar = 0;
	    }
        } else {
	    /*
	     * Forced carbonation
	     */
	    ui->keg_abvShow->setValue(product->final_abv);
	    product->keg_abv = product->final_abv;
	    ui->keg_sug_amountShow->setValue(0);
            ui->keg_sug_weightShow->setValue(0);
	}
    } // if keg_amount
}


/*
 * Triggered by writing to ui->pack_abvShow
 */
void EditProduct::pack_abv_changed(double val)
{
    calcPack();
}


void EditProduct::pack_date_changed(QDate val)
{
    qDebug() << "pack_date_changed" << val;
    product->package_date = ui->pack_dateEdit->nullDate();
    is_changed();
    setStage();
}


void EditProduct::pack_date_button()
{
    ui->pack_dateEdit->setDate(QDate::currentDate());
}


void EditProduct::pack_date_ack()
{
    int rc = QMessageBox::warning(this, tr("Confirm package"), tr("Confirm that the beer is packaged and all data is correct"),
                            QMessageBox::Yes | QMessageBox::No, QMessageBox::No);

    if (rc == QMessageBox::No)
        return;

    product->stage = PROD_STAGE_CARBONATION;
    setStage();
    is_changed();
}


void EditProduct::pack_volume_changed(double val)
{
    /*
     * If the total volume is decreased, check if the
     * bottle and kegs amount need to be lowered as well.
     */

    product->package_volume = val;
    calcPack();
    is_changed();
}


void EditProduct::pack_ph_changed(double val)
{
    if (product->package_ph == 0) {
        product->package_ph = 4.0;
        const QSignalBlocker blocker1(ui->pack_phEdit);
        ui->pack_phEdit->setValue(4.0);
    } else {
    	product->package_ph = val;
    }
    is_changed();
}


void EditProduct::pack_infusion_vol_changed(double val)
{
    product->package_infuse_amount = val;
    calcPack();
    is_changed();
}


void EditProduct::pack_infusion_abv_changed(double val)
{
    product->package_infuse_abv = val;
    calcPack();
    is_changed();
}


void EditProduct::pack_infusion_txt_changed(QString val)
{
    product->package_infuse_notes = val;
    is_changed();
}


void EditProduct::bottle_volume_changed(double val)
{
    /*
     * Check if kegs volume plus this new volume fits in the package volume.
     */
    if ((val + product->keg_amount) > product->package_volume) {
        double kegs = product->package_volume - val;
        const QSignalBlocker blocker1(ui->keg_volumeEdit);
        product->keg_amount = kegs;
        ui->keg_volumeEdit->setValue(kegs);
    }
    product->bottle_amount = val;
    calcPack();
    is_changed();
}


void EditProduct::bottle_co2_changed(double val)
{
    product->bottle_carbonation = val;
    calcPack();
    is_changed();
}


void EditProduct::bottle_sugar_changed(int val)
{
    Fermentables newf;
    QSqlQuery   query;

    qDebug() << "bottle_sugar_changed" << product->bottle_priming_sugar << val;
    for (int i = 0; i < product->fermentables.size(); i++) {
	if (product->fermentables.at(i).f_added == FERMENTABLE_ADDED_BOTTLE) {
	    product->fermentables.removeAt(i);
	    refreshFermentables();
	    break;
	}
    }

    /*
     * Search the sugar pointed by the index.
     */
    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,inventory FROM inventory_fermentables "
		  "WHERE type = '1' OR type = '3' ORDER BY name";
    query.prepare(sql);
    query.exec();
    query.first();
    for (int i = 0; i < (val - 1); i++) {
        query.next();
    }

    newf.f_name = query.value(0).toString();
    newf.f_origin = query.value(1).toString();
    newf.f_supplier = query.value(2).toString();
    newf.f_cost = query.value(3).toDouble();
    newf.f_type = query.value(4).toInt();
    newf.f_yield = query.value(5).toDouble();
    newf.f_color = query.value(6).toDouble();
    newf.f_coarse_fine_diff = query.value(7).toDouble();
    newf.f_moisture = query.value(8).toDouble();
    newf.f_diastatic_power = query.value(9).toDouble();
    newf.f_protein = query.value(10).toDouble();
    newf.f_dissolved_protein = query.value(11).toDouble();
    newf.f_max_in_batch = query.value(12).toDouble();
    newf.f_graintype = query.value(13).toInt();
    newf.f_recommend_mash = query.value(14).toInt() ? true:false;
    newf.f_add_after_boil = true;
    newf.f_di_ph = query.value(16).toDouble();
    newf.f_acid_to_ph_57 = query.value(17).toDouble();
    newf.f_inventory = query.value(18).toDouble();
    newf.f_amount = 0;
    newf.f_added = FERMENTABLE_ADDED_BOTTLE;

    product->fermentables.append(newf);
    refreshFermentables();
    const QSignalBlocker blocker1(ui->bottle_sugarEdit);
    calcPack();
    is_changed();
}


void EditProduct::bottle_water_changed(double val)
{
    product->bottle_priming_water = val;
    calcPack();
    is_changed();
}


void EditProduct::bottle_temp_changed(double val)
{
    product->bottle_carbonation_temp = val;
    calcPack();
    is_changed();
}


void EditProduct::kegs_volume_changed(double val)
{
    /*
     * Check if bottle volume plus this new volume fits in the package volume.
     */
    if ((val + product->bottle_amount) > product->package_volume) {
	double bottle = product->package_volume - val;
	const QSignalBlocker blocker1(ui->bottle_volumeEdit);
	product->bottle_amount = bottle;
	ui->bottle_volumeEdit->setValue(bottle);
    }
    product->keg_amount = val;
    calcPack();
    is_changed();
}


void EditProduct::kegs_co2_changed(double val)
{
    product->keg_carbonation = val;
    calcPack();
    is_changed();
}


void EditProduct::kegs_sugar_changed(int val)
{
    Fermentables newf;
    QSqlQuery   query;

    qDebug() << "kegs_sugar_changed" << product->keg_priming_sugar << val;
    for (int i = 0; i < product->fermentables.size(); i++) {
        if (product->fermentables.at(i).f_added == FERMENTABLE_ADDED_KEGS) {
            product->fermentables.removeAt(i);
            refreshFermentables();
            break;
        }
    }

    /*
     * Search the sugar pointed by the index.
     */
    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,inventory FROM inventory_fermentables "
                  "WHERE type = '1' OR type = '3' ORDER BY name";
    query.prepare(sql);
    query.exec();
    query.first();
    for (int i = 0; i < (val - 1); i++) {
        query.next();
    }

    newf.f_name = query.value(0).toString();
    newf.f_origin = query.value(1).toString();
    newf.f_supplier = query.value(2).toString();
    newf.f_cost = query.value(3).toDouble();
    newf.f_type = query.value(4).toInt();
    newf.f_yield = query.value(5).toDouble();
    newf.f_color = query.value(6).toDouble();
    newf.f_coarse_fine_diff = query.value(7).toDouble();
    newf.f_moisture = query.value(8).toDouble();
    newf.f_diastatic_power = query.value(9).toDouble();
    newf.f_protein = query.value(10).toDouble();
    newf.f_dissolved_protein = query.value(11).toDouble();
    newf.f_max_in_batch = query.value(12).toDouble();
    newf.f_graintype = query.value(13).toInt();
    newf.f_recommend_mash = query.value(14).toInt() ? true:false;
    newf.f_add_after_boil = true;
    newf.f_di_ph = query.value(16).toDouble();
    newf.f_acid_to_ph_57 = query.value(17).toDouble();
    newf.f_inventory = query.value(18).toDouble();
    newf.f_amount = 0;
    newf.f_added = FERMENTABLE_ADDED_KEGS;

    product->fermentables.append(newf);
    refreshFermentables();
    const QSignalBlocker blocker1(ui->keg_sugarEdit);
    calcPack();
    is_changed();
}


void EditProduct::kegs_water_changed(double val)
{
    product->keg_priming_water = val;
    calcPack();
    is_changed();
}


void EditProduct::kegs_forced_changed(bool val)
{
    qDebug() << "kegs_forced_changed" << val;

    product->keg_forced_carb = val;
    if (val) {
	/*
	 * Make sure to remove priming sugars.
	 */
	for (int i = 0; i < product->fermentables.size(); i++) {
	    if (product->fermentables.at(i).f_added == FERMENTABLE_ADDED_KEGS) {
		product->fermentables.removeAt(i);
		refreshFermentables();
		break;
	    }
	}
	product->keg_priming_sugar = 0;
	product->keg_priming_amount = 0;
	product->keg_priming_water = 0;
	const QSignalBlocker blocker1(ui->keg_sugarEdit);
	const QSignalBlocker blocker2(ui->keg_sug_waterEdit);
	ui->keg_sugarEdit->setCurrentIndex(0);
	ui->keg_sug_weightShow->setValue(0);
	ui->keg_sug_waterEdit->setValue(0);
	ui->keg_sug_amountShow->setValue(0);
    }

    calcPack();
    is_changed();
}


void EditProduct::kegs_temp_changed(double val)
{
    product->keg_carbonation_temp = val;
    calcPack();
    is_changed();
}

mercurial