src/EditProductTab1.cpp

Thu, 18 Aug 2022 16:11:20 +0200

author
Michiel Broek <mbroek@mbse.eu>
date
Thu, 18 Aug 2022 16:11:20 +0200
changeset 397
877420a13815
parent 395
7212b980a527
child 403
2ed66e586a52
permissions
-rw-r--r--

Edit Product, split CO2 package pressure in bottles and kegs. BU:RE code cleanup. calcPack() sets the CO2 values on the first tab. Show final EBC on tab 1 if the stage is after brew. Show final ABV and energy on tab 1 if fermentation is done. Removed wrong bottle priming calculation from calcFermentables() because calcPack() does this.

/**
 * EditProduct.cpp is part of bmsapp.
 *
 * Tab 1, generic settings.
 *
 * 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/>.
 */


void EditProduct::calcStyle()
{
    /*
     * https://www.homebrewersassociation.org/forum/index.php?topic=10548.0
     *
     * Calculate the ideal BU:GU and BU:RE ranges. These values
     * will be used in the RangedSliders.
     */
    double bugu_min = product->st_ibu_min / ((product->st_og_min - 1) * 1000);
    double bugu_max = product->st_ibu_max / ((product->st_og_max - 1) * 1000);
    ui->est_buguShow->setRange(bugu_min, bugu_max);

    double fg_min = product->st_fg_min;
    if (fg_min < 1.002)		/* Use 1.002 fg as lowest minimal value */
	fg_min = 1.002;

    /*
     * Real Extract (RE)
     */
    double re = ((0.1808 * ((Utils::sg_to_plato(product->st_og_min) + Utils::sg_to_plato(product->st_og_max)) / 2)) +
		 (0.8192 * ((Utils::sg_to_plato(fg_min) + Utils::sg_to_plato(product->st_fg_max)) / 2)));

    /*
     * BU:RE
     * Divide over average RE gives the best ranges.
     */
    double bure_min = product->st_ibu_min / re;
    double bure_max = product->st_ibu_max / re;
    ui->est_bufguShow->setRange(bure_min, bure_max);
}


void EditProduct::code_changed(QString code)
{
    product->code = code;
    is_changed();
}


void EditProduct::name_changed(QString name)
{
    product->name = name;
    is_changed();
}


void EditProduct::notes_changed()
{
    /* The text cannot be passed in a simple way :) */
    product->notes = ui->notesEdit->toPlainText();
    is_changed();
}


/*
 * New beerstyle is selected.
 */
void EditProduct::style_changed(int val)
{
    QSqlQuery query;

    query.prepare("SELECT * FROM profile_styles ORDER BY style_guide,style_letter,name");
    query.exec();
    query.first();
    // Skip to the record index.
    for (int i = 0; i < (val - 1); i++) {
        query.next();
    }
    // Set relevant fields and update ranges.
    product->st_name = query.value(1).toString();
    product->st_category = query.value(2).toString();
    product->st_category_number = query.value(3).toInt();
    product->st_letter = query.value(4).toString();
    product->st_guide = query.value(5).toString();
    product->st_type = query.value(6).toInt();
    product->st_og_min = query.value(7).toDouble();
    product->st_og_max = query.value(8).toDouble();
    product->st_fg_min = query.value(9).toDouble();
    product->st_fg_max = query.value(10).toDouble();
    product->st_ibu_min = query.value(11).toDouble();
    product->st_ibu_max = query.value(12).toDouble();
    product->st_color_min = query.value(13).toDouble();
    product->st_color_max = query.value(14).toDouble();
    product->st_carb_min = query.value(15).toDouble();
    product->st_carb_max = query.value(16).toDouble();
    product->st_abv_min = query.value(17).toDouble();
    product->st_abv_max = query.value(18).toDouble();

    ui->st_nameEdit->setText(product->st_name);
    ui->st_groupEdit->setText(product->st_letter);
    ui->st_guideEdit->setText(product->st_guide);
    ui->st_catEdit->setText(product->st_category);
    ui->st_catnrEdit->setText(QString("%1").arg(product->st_category_number));
    ui->st_typeEdit->setText(QCoreApplication::translate("BeerType", g_style_types[product->st_type]));

    ui->est_ogShow->setRange(query.value(7).toDouble(), query.value(8).toDouble());
    ui->est_fgShow->setRange(query.value(9).toDouble(), query.value(10).toDouble());
    ui->est_ibuShow->setRange(query.value(11).toDouble(), query.value(12).toDouble());
    ui->est_colorShow->setRange(query.value(13).toDouble(), query.value(14).toDouble());
    ui->est_bottle_co2Show->setRange(query.value(15).toDouble(), query.value(16).toDouble());
    ui->est_kegs_co2Show->setRange(query.value(15).toDouble(), query.value(16).toDouble());
    ui->est_abvShow->setRange(query.value(17).toDouble(), query.value(18).toDouble());

    calcStyle();
    is_changed();
}


void EditProduct::colormethod_changed(int val)
{
    product->color_method = val;
    calcFermentables();
    is_changed();
}


void EditProduct::ibumethod_changed(int val)
{
    product->ibu_method = val;
    calcIBUs();
    is_changed();
    emit refreshAll();
}


void EditProduct::est_og_changed(double val)
{
    product->est_og = val;
    calcFermentablesFromOG(val);// Adjust fermentables amounts
    calcFermentables();		// Update the product details
    calcIBUs();
    calcMash();
    is_changed();
    emit refreshAll();
}


void EditProduct::efficiency_changed(double val)
{
    double estog = product->est_og;
    product->efficiency = val;
    calcFermentablesFromOG(estog);
    calcFermentables();
    calcIBUs();
    is_changed();
    emit refreshAll();
}


void EditProduct::boil_time_changed(int val)
{
    qDebug() << "boil_time_changed" << val;
    double new_evap = (0.1 * product->batch_size) * val / 60.0;
    product->boil_size = product->batch_size + new_evap;
    product->boil_time = val;
    ui->boil_sizeEdit->setValue(product->boil_size);
    ui->brew_preboilvolShow->setValue(product->boil_size * 1.04);
    calcFermentables();
    calcIBUs();
    is_changed();
}


void EditProduct::batch_size_changed(double val)
{
    qDebug() << "batch_size_changed" << val << "old" << product->batch_size;

    double evap = (0.1 * val) * product->boil_time / 60.0;
    product->boil_size = val + evap;
    double factor = val / product->batch_size;
    ui->boil_sizeEdit->setValue(product->boil_size);
    ui->brew_preboilvolShow->setValue(product->boil_size * 1.04);
    product->sparge_volume *= factor;
    ui->sp_volEdit->setValue(product->sparge_volume);
    ui->brew_spargevolShow->setValue(product->sparge_volume);
    product->batch_size = val;
    calcFermentablesFromOG(product->est_og);	// Keep the OG
    adjustWaters(factor);
    calcFermentables();
    adjustHops(factor);
    adjustMiscs(factor);
    adjustYeasts(factor);
    calcIBUs();
    calcWater();
    calcMash();
    is_changed();
    emit refreshAll();
}


void EditProduct::brew_type_changed(int val)
{
    product->type;
    is_changed();
}


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

    if (product->stage < PROD_STAGE_READY)
	return;

    product->locked = val;
    product->stage = val ? PROD_STAGE_CLOSED : PROD_STAGE_READY;
    setStage();
    is_changed();
}


void EditProduct::setStage()
{
    int	 stage = product->stage;
    bool locked = product->locked;

    /*
     * See if we need to set a new stage.
     */
    if ((stage == PROD_STAGE_PLAN) && (product->est_og > 1.005) && (product->est_color > 3) && (product->est_ibu > 3))
	stage = PROD_STAGE_WAIT;
    if ((stage == PROD_STAGE_WAIT) && (product->brew_date_start.date().isValid()))
	stage = PROD_STAGE_BREW;
    if ((stage == PROD_STAGE_BREW) && (! product->brew_date_start.date().isValid()))
	stage = PROD_STAGE_WAIT;
    /* from PROD_STAGE_BREW to PROD_STAGE_PRIMARY is handled in EditProductTab9.cpp */
    /* from PROD_STAGE_PRIMARY to PROD_STAGE_SECONDARY is handled in EditProductTab10.cpp */
    /* from PROD_STAGE_SECONDARY to PROD_STAGE_TERIARY is handled in EditProductTab10.cpp */
    if ((stage == PROD_STAGE_TERTIARY) && product->package_date.isValid())
	stage = PROD_STAGE_PACKAGE;
    if ((stage == PROD_STAGE_PACKAGE) && (! product->package_date.isValid()))
	stage = PROD_STAGE_TERTIARY;
    /* from PROD_STAGE_PACKAGE to PROD_STAGE_CARBONATION is handled in EditProductTab11.cpp */
    if ((stage == PROD_STAGE_CARBONATION) && (product->package_date.daysTo(QDate::currentDate()) > 14))
	stage = PROD_STAGE_MATURE;

    if (product->stage != stage) {
	qDebug() << "setStage() change state:" << g_prod_stages[product->stage] << "to:" << g_prod_stages[stage];
    	product->stage = stage;
	is_changed();
    } else {
	qDebug() << "setStage() stage:" << g_prod_stages[stage];
    }

    ui->stageEdit->setText(QCoreApplication::translate("ProdStages", g_prod_stages[stage]));

    /* Tab 1, generic */
    ui->typeEdit->setDisabled(stage > PROD_STAGE_WAIT);
    ui->color_methodEdit->setDisabled(locked);
    ui->ibu_methodEdit->setDisabled(locked);
    ui->beerstyleEdit->setDisabled(stage > PROD_STAGE_WAIT);
    ui->nameEdit->setReadOnly(stage > PROD_STAGE_WAIT);
    ui->codeEdit->setReadOnly(stage > PROD_STAGE_WAIT || product->divide_type);	/* Never change this in a splitted product. */
    ui->notesEdit->setReadOnly(locked);
    ui->batch_sizeEdit->setReadOnly(stage > PROD_STAGE_WAIT);
    ui->batch_sizeEdit->setButtonSymbols((stage > PROD_STAGE_WAIT) ? QAbstractSpinBox::NoButtons : QAbstractSpinBox::UpDownArrows);
    ui->boil_sizeEdit->setReadOnly(stage > PROD_STAGE_WAIT);
    ui->boil_sizeEdit->setButtonSymbols((stage > PROD_STAGE_WAIT) ? QAbstractSpinBox::NoButtons : QAbstractSpinBox::UpDownArrows);
    ui->boil_timeEdit->setReadOnly(stage > PROD_STAGE_WAIT);
    ui->boil_timeEdit->setButtonSymbols((stage > PROD_STAGE_WAIT) ? QAbstractSpinBox::NoButtons : QAbstractSpinBox::UpDownArrows);
    ui->efficiencyEdit->setReadOnly(stage > PROD_STAGE_WAIT);
    ui->efficiencyEdit->setButtonSymbols((stage > PROD_STAGE_WAIT) ? QAbstractSpinBox::NoButtons : QAbstractSpinBox::UpDownArrows);
    ui->est_ogEdit->setReadOnly(stage > PROD_STAGE_WAIT);
    ui->est_ogEdit->setButtonSymbols((stage > PROD_STAGE_WAIT) ? QAbstractSpinBox::NoButtons : QAbstractSpinBox::UpDownArrows);
    /*
     * The next two items are displayed on the same location.
     * But they are not needed at the same time.
     */
    if (stage > PROD_STAGE_PACKAGE) {
	ui->ok_pmptLabel->hide();
	ui->ok_pmptIcon->hide();
    } else {
	ui->ok_pmptLabel->show();
        ui->ok_pmptIcon->show();
    }
    if (stage >= PROD_STAGE_READY) {
	ui->lockedLabel->show();
	ui->lockedEdit->show();
    } else {
	ui->lockedLabel->hide();
        ui->lockedEdit->hide();
    }

    /* Tab 2, equipment */
    ui->tabWidget->setTabEnabled(1, stage < PROD_STAGE_BREW);

    /* Tab 3, fermentables */
    ui->est_og2Edit->setReadOnly(stage > PROD_STAGE_WAIT);
    ui->est_og2Edit->setButtonSymbols((stage > PROD_STAGE_WAIT) ? QAbstractSpinBox::NoButtons : QAbstractSpinBox::UpDownArrows);
    ui->addFermentable->setEnabled(stage <= PROD_STAGE_PACKAGE);

    /* Tab 4, hops */
    ui->addHop->setEnabled(stage <= PROD_STAGE_PACKAGE);

    /* Tab 5, miscs */
    ui->addMisc->setEnabled(stage <= PROD_STAGE_PACKAGE);

    /* Tab 6, yeasts */
    ui->addYeast->setEnabled(stage <= PROD_STAGE_PACKAGE);

    /* Tab 7, mash */
    ui->addMash->setEnabled(stage <= PROD_STAGE_BREW);
    ui->mash_nameEdit->setReadOnly(stage > PROD_STAGE_BREW);
    ui->mash_pickEdit->setDisabled(stage > PROD_STAGE_BREW);

    /* Tab 8, water */
    ui->wt_sourceEdit->setDisabled(stage > PROD_STAGE_BREW);
    ui->w1_nameEdit->setDisabled(stage > PROD_STAGE_BREW);
    ui->w2_nameEdit->setDisabled(stage > PROD_STAGE_BREW);
    ui->mw_acidPick->setDisabled(stage > PROD_STAGE_BREW);
    ui->sp_acidtypeEdit->setDisabled(stage > PROD_STAGE_BREW);
    ui->w2_volEdit->setReadOnly(stage > PROD_STAGE_BREW);
    ui->w2_volEdit->setButtonSymbols((stage > PROD_STAGE_BREW) ? QAbstractSpinBox::NoButtons : QAbstractSpinBox::UpDownArrows);
    ui->sp_volEdit->setReadOnly(stage > PROD_STAGE_BREW);
    ui->sp_volEdit->setButtonSymbols((stage > PROD_STAGE_BREW) ? QAbstractSpinBox::NoButtons : QAbstractSpinBox::UpDownArrows);
    ui->bs_cacl2Edit->setReadOnly(stage > PROD_STAGE_BREW);
    ui->bs_cacl2Edit->setButtonSymbols((stage > PROD_STAGE_BREW) ? QAbstractSpinBox::NoButtons : QAbstractSpinBox::UpDownArrows);
    ui->bs_caso4Edit->setReadOnly(stage > PROD_STAGE_BREW);
    ui->bs_caso4Edit->setButtonSymbols((stage > PROD_STAGE_BREW) ? QAbstractSpinBox::NoButtons : QAbstractSpinBox::UpDownArrows);
    ui->bs_mgso4Edit->setReadOnly(stage > PROD_STAGE_BREW);
    ui->bs_mgso4Edit->setButtonSymbols((stage > PROD_STAGE_BREW) ? QAbstractSpinBox::NoButtons : QAbstractSpinBox::UpDownArrows);
    ui->bs_naclEdit->setReadOnly(stage > PROD_STAGE_BREW);
    ui->bs_naclEdit->setButtonSymbols((stage > PROD_STAGE_BREW) ? QAbstractSpinBox::NoButtons : QAbstractSpinBox::UpDownArrows);
    ui->bs_mgcl2Edit->setReadOnly(stage > PROD_STAGE_BREW);
    ui->bs_mgcl2Edit->setButtonSymbols((stage > PROD_STAGE_BREW) ? QAbstractSpinBox::NoButtons : QAbstractSpinBox::UpDownArrows);
    ui->bs_nahco3Edit->setReadOnly(stage > PROD_STAGE_BREW);
    ui->bs_nahco3Edit->setButtonSymbols((stage > PROD_STAGE_BREW) ? QAbstractSpinBox::NoButtons : QAbstractSpinBox::UpDownArrows);
    ui->bs_caco3Edit->setReadOnly(stage > PROD_STAGE_BREW);
    ui->bs_caco3Edit->setButtonSymbols((stage > PROD_STAGE_BREW) ? QAbstractSpinBox::NoButtons : QAbstractSpinBox::UpDownArrows);
    if (stage > PROD_STAGE_BREW) {
    	ui->mw_phEdit->setReadOnly(true);
	ui->mw_phEdit->setButtonSymbols(QAbstractSpinBox::NoButtons);
	ui->mw_acidvolEdit->setReadOnly(true);
	ui->mw_acidvolEdit->setButtonSymbols(QAbstractSpinBox::NoButtons);
	ui->sp_phEdit->setReadOnly(true);
    	ui->sp_phEdit->setButtonSymbols(QAbstractSpinBox::NoButtons);
	ui->sp_acidvolEdit->setReadOnly(true);
        ui->sp_acidvolEdit->setButtonSymbols(QAbstractSpinBox::NoButtons);
    } else {
    	ui->mw_phEdit->setReadOnly(! product->calc_acid);
    	ui->mw_phEdit->setButtonSymbols(product->calc_acid ? QAbstractSpinBox::UpDownArrows : QAbstractSpinBox::NoButtons);
    	ui->mw_acidvolEdit->setReadOnly(product->calc_acid);
    	ui->mw_acidvolEdit->setButtonSymbols(product->calc_acid ? QAbstractSpinBox::NoButtons : QAbstractSpinBox::UpDownArrows);
	ui->sp_phEdit->setReadOnly(! product->calc_acid);
    	ui->sp_phEdit->setButtonSymbols(product->calc_acid ? QAbstractSpinBox::UpDownArrows : QAbstractSpinBox::NoButtons);
	ui->sp_acidvolEdit->setReadOnly(product->calc_acid);
        ui->sp_acidvolEdit->setButtonSymbols(product->calc_acid ? QAbstractSpinBox::NoButtons : QAbstractSpinBox::UpDownArrows);
    }
    ui->mw_autoEdit->setDisabled(stage > PROD_STAGE_BREW);
    setButtons(stage > PROD_STAGE_BREW);

    /* Tab 9, brewday */
    ui->tabWidget->setTabEnabled(8, stage > PROD_STAGE_PLAN);
    if (product->log_brew) {
	ui->brew_logLabel->show();
	ui->brew_logButton->show();
    } else {
	ui->brew_logLabel->hide();
	ui->brew_logButton->hide();
    }
    ui->brew_ackLabel->hide();
    ui->brew_ackButton->hide();
    if (product->stage < PROD_STAGE_BREW) {
	ui->brew_startButton1->show();
        ui->brew_startButton2->show();
        ui->brew_startDate->setReadOnly(false);
	ui->brew_startDate->setMinimumDate(product->birth.addDays(-1));	// The birth date is the first valid date.
	ui->brew_endButton1->hide();
	ui->brew_startLabel2->hide();
	ui->brew_endLabel->hide();
	ui->brew_endLabel2->hide();
	ui->brew_startTime->hide();
        ui->brew_endDate->hide();
        ui->brew_endTime->hide();
    } else if (product->stage == PROD_STAGE_BREW) {
	ui->brew_startButton1->show();
        ui->brew_startButton2->show();
        ui->brew_startDate->setReadOnly(false);
	ui->brew_startLabel2->show();

	/*
	 * Enable brew_end settings if it is the right date or later.
	 * If some essential values are filled in.
	 */
	int brewTime = product->brew_date_start.date().daysTo(QDate::currentDate());

	if ((brewTime >= 0) && (product->brew_cooling_method > 0) && (product->brew_cooling_time > 0) &&
	    (product->brew_aboil_sg > 1.002) && (product->brew_aboil_volume > 0)) {
            ui->brew_endLabel->show();
	    ui->brew_startLabel2->show();
            ui->brew_endLabel2->show();
	    ui->brew_endButton1->show();
	    ui->brew_startTime->setButtonSymbols(QAbstractSpinBox::UpDownArrows);
	    ui->brew_startTime->show();
	    ui->brew_endDate->setButtonSymbols(QAbstractSpinBox::UpDownArrows);
            ui->brew_endDate->show();
	    ui->brew_endDate->setReadOnly(false);
	    ui->brew_endTime->setButtonSymbols(QAbstractSpinBox::UpDownArrows);
            ui->brew_endTime->show();
	    if (product->brew_date_end.isValid() && product->brew_date_start.isValid() &&
		(product->brew_date_start.msecsTo(product->brew_date_end) > 7200000)) {
		/* The start and end dates are valid, and the end is more then two hours after the start. */
		ui->brew_ackLabel->show();
		ui->brew_ackButton->show();
	    }
	} else {
	    ui->brew_endButton1->hide();
            ui->brew_startLabel2->hide();
            ui->brew_endLabel->hide();
            ui->brew_endLabel2->hide();
            ui->brew_startTime->hide();
            ui->brew_endDate->hide();
            ui->brew_endTime->hide();
	}
    } else {
	ui->brew_startButton1->hide();
        ui->brew_startButton2->hide();
        ui->brew_startDate->setReadOnly(true);
	ui->brew_startLabel2->show();
        ui->brew_endLabel->show();
        ui->brew_endLabel2->show();
	ui->brew_endButton1->hide();
	ui->brew_startTime->setButtonSymbols(QAbstractSpinBox::NoButtons);
	ui->brew_startTime->show();
	ui->brew_startTime->setReadOnly(true);
	ui->brew_endDate->setButtonSymbols(QAbstractSpinBox::NoButtons);
        ui->brew_endDate->show();
	ui->brew_endDate->setReadOnly(true);
	ui->brew_endTime->setButtonSymbols(QAbstractSpinBox::NoButtons);
        ui->brew_endTime->show();
	ui->brew_endTime->setReadOnly(true);
    }
    ui->brew_mashphEdit->setReadOnly(stage > PROD_STAGE_BREW);
    ui->brew_mashphEdit->setButtonSymbols( (stage > PROD_STAGE_BREW) ? QAbstractSpinBox::NoButtons : QAbstractSpinBox::UpDownArrows);
    ui->brew_mashsgEdit->setReadOnly(stage > PROD_STAGE_BREW);
    ui->brew_mashsgEdit->setButtonSymbols( (stage > PROD_STAGE_BREW) ? QAbstractSpinBox::NoButtons : QAbstractSpinBox::UpDownArrows);
    ui->brew_spargephEdit->setReadOnly(stage > PROD_STAGE_BREW);
    ui->brew_spargephEdit->setButtonSymbols( (stage > PROD_STAGE_BREW) ? QAbstractSpinBox::NoButtons : QAbstractSpinBox::UpDownArrows);
    ui->brew_spargetempEdit->setReadOnly(stage > PROD_STAGE_BREW);
    ui->brew_spargetempEdit->setButtonSymbols((stage > PROD_STAGE_BREW) ? QAbstractSpinBox::NoButtons : QAbstractSpinBox::UpDownArrows);
    ui->brew_preboilphEdit->setReadOnly(stage > PROD_STAGE_BREW);
    ui->brew_preboilphEdit->setButtonSymbols( (stage > PROD_STAGE_BREW) ? QAbstractSpinBox::NoButtons : QAbstractSpinBox::UpDownArrows);
    ui->brew_preboilsgEdit->setReadOnly(stage > PROD_STAGE_BREW);
    ui->brew_preboilsgEdit->setButtonSymbols( (stage > PROD_STAGE_BREW) ? QAbstractSpinBox::NoButtons : QAbstractSpinBox::UpDownArrows);
    ui->brew_preboilvolEdit->setReadOnly(stage > PROD_STAGE_BREW);
    ui->brew_preboilvolEdit->setButtonSymbols( (stage > PROD_STAGE_BREW) ? QAbstractSpinBox::NoButtons : QAbstractSpinBox::UpDownArrows);
    ui->brew_preboilButton->setDisabled(stage > PROD_STAGE_BREW);
    ui->brew_aboilphEdit->setReadOnly(stage > PROD_STAGE_BREW);
    ui->brew_aboilphEdit->setButtonSymbols( (stage > PROD_STAGE_BREW) ? QAbstractSpinBox::NoButtons : QAbstractSpinBox::UpDownArrows);
    ui->brew_aboilsgEdit->setReadOnly(stage > PROD_STAGE_BREW);
    ui->brew_aboilsgEdit->setButtonSymbols( (stage > PROD_STAGE_BREW) ? QAbstractSpinBox::NoButtons : QAbstractSpinBox::UpDownArrows);
    ui->brew_aboilvolEdit->setReadOnly(stage > PROD_STAGE_BREW);
    ui->brew_aboilvolEdit->setButtonSymbols( (stage > PROD_STAGE_BREW) ? QAbstractSpinBox::NoButtons : QAbstractSpinBox::UpDownArrows);
    ui->brew_aboilButton->setDisabled(stage > PROD_STAGE_BREW);
    ui->brew_cooltoEdit->setReadOnly(stage > PROD_STAGE_BREW);
    ui->brew_cooltoEdit->setButtonSymbols( (stage > PROD_STAGE_BREW) ? QAbstractSpinBox::NoButtons : QAbstractSpinBox::UpDownArrows);
    ui->brew_cooltimeEdit->setReadOnly(stage > PROD_STAGE_BREW);
    ui->brew_cooltimeEdit->setButtonSymbols( (stage > PROD_STAGE_BREW) ? QAbstractSpinBox::NoButtons : QAbstractSpinBox::UpDownArrows);
    ui->brew_coolwithEdit->setDisabled(stage > PROD_STAGE_BREW);
    ui->brew_whirlpool9Edit->setReadOnly(stage > PROD_STAGE_BREW);
    ui->brew_whirlpool9Edit->setButtonSymbols( (stage > PROD_STAGE_BREW) ? QAbstractSpinBox::NoButtons : QAbstractSpinBox::UpDownArrows);
    ui->brew_whirlpool7Edit->setReadOnly(stage > PROD_STAGE_BREW);
    ui->brew_whirlpool7Edit->setButtonSymbols( (stage > PROD_STAGE_BREW) ? QAbstractSpinBox::NoButtons : QAbstractSpinBox::UpDownArrows);
    ui->brew_whirlpool6Edit->setReadOnly(stage > PROD_STAGE_BREW);
    ui->brew_whirlpool6Edit->setButtonSymbols( (stage > PROD_STAGE_BREW) ? QAbstractSpinBox::NoButtons : QAbstractSpinBox::UpDownArrows);
    ui->brew_whirlpool2Edit->setReadOnly(stage > PROD_STAGE_BREW);
    ui->brew_whirlpool2Edit->setButtonSymbols( (stage > PROD_STAGE_BREW) ? QAbstractSpinBox::NoButtons : QAbstractSpinBox::UpDownArrows);
    ui->brew_aerspeedEdit->setReadOnly(stage > PROD_STAGE_BREW);
    ui->brew_aerspeedEdit->setButtonSymbols( (stage > PROD_STAGE_BREW) ? QAbstractSpinBox::NoButtons : QAbstractSpinBox::UpDownArrows);
    ui->brew_aertimeEdit->setReadOnly(stage > PROD_STAGE_BREW);
    ui->brew_aertimeEdit->setButtonSymbols( (stage > PROD_STAGE_BREW) ? QAbstractSpinBox::NoButtons : QAbstractSpinBox::UpDownArrows);
    ui->brew_aerwithEdit->setDisabled(stage > PROD_STAGE_BREW);
    ui->brew_trublossEdit->setReadOnly(stage > PROD_STAGE_BREW);
    ui->brew_trublossEdit->setButtonSymbols( (stage > PROD_STAGE_BREW) ? QAbstractSpinBox::NoButtons : QAbstractSpinBox::UpDownArrows);
    ui->brew_topupwaterEdit->setReadOnly(stage > PROD_STAGE_BREW);
    ui->brew_topupwaterEdit->setButtonSymbols( (stage > PROD_STAGE_BREW) ? QAbstractSpinBox::NoButtons : QAbstractSpinBox::UpDownArrows);

    /* Tab 10, fermentation */
    ui->tabWidget->setTabEnabled(9, stage > PROD_STAGE_WAIT);
    if (product->log_fermentation) {
	ui->ferm_log1Label->show();
	ui->ferm_log1Button->show();
    } else {
	ui->ferm_log1Label->hide();
        ui->ferm_log1Button->hide();
    }
    if (product->log_ispindel) {
	ui->ferm_log2Label->show();
        ui->ferm_log2Button->show();
    } else {
	ui->ferm_log2Label->hide();
        ui->ferm_log2Button->hide();
    }
    ui->prim_enddateEdit->setReadOnly(true);
    ui->prim_enddateEdit->setButtonSymbols(QAbstractSpinBox::NoButtons);
    ui->prim_enddateButton->hide();
    ui->prim_ackButton->hide();
    ui->sec_enddateEdit->setReadOnly(true);
    ui->sec_enddateEdit->setButtonSymbols(QAbstractSpinBox::NoButtons);
    ui->sec_enddateButton->hide();
    ui->sec_ackButton->hide();
    ui->prim_startCEdit->setReadOnly(product->stage != PROD_STAGE_PRIMARY);
    ui->prim_startCEdit->setButtonSymbols((product->stage == PROD_STAGE_PRIMARY) ? QAbstractSpinBox::UpDownArrows : QAbstractSpinBox::NoButtons);
    ui->prim_maxCEdit->setReadOnly(product->stage != PROD_STAGE_PRIMARY);
    ui->prim_maxCEdit->setButtonSymbols((product->stage == PROD_STAGE_PRIMARY) ? QAbstractSpinBox::UpDownArrows : QAbstractSpinBox::NoButtons);
    ui->prim_endCEdit->setReadOnly(product->stage != PROD_STAGE_PRIMARY);
    ui->prim_endCEdit->setButtonSymbols((product->stage == PROD_STAGE_PRIMARY) ? QAbstractSpinBox::UpDownArrows : QAbstractSpinBox::NoButtons);
    ui->prim_endsgEdit->setReadOnly(product->stage != PROD_STAGE_PRIMARY);
    ui->prim_endsgEdit->setButtonSymbols((product->stage == PROD_STAGE_PRIMARY) ? QAbstractSpinBox::UpDownArrows : QAbstractSpinBox::NoButtons);
    if (product->stage == PROD_STAGE_PRIMARY)
	ui->prim_endsgButton->show();
    else
	ui->prim_endsgButton->hide();
    if ((product->primary_start_temp > 0) && (product->primary_max_temp > 0) && (product->primary_end_temp > 0) &&
	(product->primary_end_sg > 0.980) && (product->stage == PROD_STAGE_PRIMARY)) {
	ui->prim_enddateEdit->setReadOnly(false);
	ui->prim_enddateEdit->setButtonSymbols(QAbstractSpinBox::UpDownArrows);
	ui->prim_enddateEdit->setMinimumDate(product->brew_date_end.date());
        ui->prim_enddateEdit->setMaximumDate(QDate::currentDate());
	ui->prim_enddateButton->show();
	if (product->primary_end_date.isValid()) {
	    ui->prim_ackButton->show();
	}
    }
    ui->sec_tempEdit->setReadOnly(product->stage != PROD_STAGE_SECONDARY);
    ui->sec_tempEdit->setButtonSymbols((product->stage == PROD_STAGE_SECONDARY) ? QAbstractSpinBox::UpDownArrows : QAbstractSpinBox::NoButtons);
    ui->sec_sgEdit->setReadOnly(product->stage != PROD_STAGE_SECONDARY);
    ui->sec_sgEdit->setButtonSymbols((product->stage == PROD_STAGE_SECONDARY) ? QAbstractSpinBox::UpDownArrows : QAbstractSpinBox::NoButtons);
    if (product->stage == PROD_STAGE_SECONDARY)
        ui->sec_sgButton->show();
    else
        ui->sec_sgButton->hide();
    if ((product->secondary_end_sg > 0.980) && (product->secondary_temp > 0) && (product->stage == PROD_STAGE_SECONDARY)) {
	ui->sec_enddateEdit->setReadOnly(false);
    	ui->sec_enddateEdit->setButtonSymbols(QAbstractSpinBox::UpDownArrows);
	ui->sec_enddateEdit->setMinimumDate(product->primary_end_date.addDays(-1));	// Allow same date as primary end.
	ui->sec_enddateEdit->setMaximumDate(QDate::currentDate());
    	ui->sec_enddateButton->show();
	if (product->secondary_end_date.isValid()) {
	    ui->sec_ackButton->show();
	}
    }
    ui->tert_tempEdit->setReadOnly(product->stage != PROD_STAGE_TERTIARY);
    ui->tert_tempEdit->setButtonSymbols((product->stage == PROD_STAGE_TERTIARY) ? QAbstractSpinBox::UpDownArrows : QAbstractSpinBox::NoButtons);
    ui->tert_sgEdit->setReadOnly(product->stage != PROD_STAGE_TERTIARY);
    ui->tert_sgEdit->setButtonSymbols((product->stage == PROD_STAGE_TERTIARY) ? QAbstractSpinBox::UpDownArrows : QAbstractSpinBox::NoButtons);
    if (product->stage == PROD_STAGE_TERTIARY)
        ui->tert_sgButton->show();
    else
        ui->tert_sgButton->hide();

    /* Tab 11, packaging */
    ui->tabWidget->setTabEnabled(10, stage > PROD_STAGE_PLAN);
    bool pack = ((stage > PROD_STAGE_PLAN) && (stage <= PROD_STAGE_PACKAGE)) ? true:false;
    ui->pack_volumeEdit->setReadOnly(! pack);
    ui->pack_volumeEdit->setButtonSymbols((pack) ? QAbstractSpinBox::UpDownArrows : QAbstractSpinBox::NoButtons);
    ui->pack_phEdit->setReadOnly(! pack);
    ui->pack_phEdit->setButtonSymbols((pack) ? QAbstractSpinBox::UpDownArrows : QAbstractSpinBox::NoButtons);
    ui->pack_addvolEdit->setReadOnly(! pack);
    ui->pack_addvolEdit->setButtonSymbols((pack) ? QAbstractSpinBox::UpDownArrows : QAbstractSpinBox::NoButtons);
    ui->pack_addabvEdit->setReadOnly(! pack);
    ui->pack_addabvEdit->setButtonSymbols((pack) ? QAbstractSpinBox::UpDownArrows : QAbstractSpinBox::NoButtons);
    ui->pack_notesEdit->setReadOnly(! pack);
    ui->bottle_volumeEdit->setReadOnly(! pack);
    ui->bottle_volumeEdit->setButtonSymbols((pack) ? QAbstractSpinBox::UpDownArrows : QAbstractSpinBox::NoButtons);
    ui->bottle_carbEdit->setReadOnly(! pack);
    ui->bottle_carbEdit->setButtonSymbols((pack) ? QAbstractSpinBox::UpDownArrows : QAbstractSpinBox::NoButtons);
    ui->bottle_sugarEdit->setDisabled(! pack);
    ui->bottle_sug_waterEdit->setReadOnly(! pack);
    ui->bottle_sug_waterEdit->setButtonSymbols((pack) ? QAbstractSpinBox::UpDownArrows : QAbstractSpinBox::NoButtons);
    ui->bottle_tempEdit->setReadOnly(! pack);
    ui->bottle_tempEdit->setButtonSymbols((pack) ? QAbstractSpinBox::UpDownArrows : QAbstractSpinBox::NoButtons);
    ui->keg_volumeEdit->setReadOnly(! pack);
    ui->keg_volumeEdit->setButtonSymbols((pack) ? QAbstractSpinBox::UpDownArrows : QAbstractSpinBox::NoButtons);
    ui->keg_carbEdit->setReadOnly(! pack);
    ui->keg_carbEdit->setButtonSymbols((pack) ? QAbstractSpinBox::UpDownArrows : QAbstractSpinBox::NoButtons);
    ui->keg_sugarEdit->setDisabled(! pack);
    ui->keg_sug_waterEdit->setReadOnly(! pack);
    ui->keg_sug_waterEdit->setButtonSymbols((pack) ? QAbstractSpinBox::UpDownArrows : QAbstractSpinBox::NoButtons);
    ui->keg_tempEdit->setReadOnly(! pack);
    ui->keg_tempEdit->setButtonSymbols((pack) ? QAbstractSpinBox::UpDownArrows : QAbstractSpinBox::NoButtons);
    ui->keg_forcedEdit->setDisabled(! pack);
    ui->pack_dateEdit->setReadOnly(true);
    ui->pack_dateEdit->setButtonSymbols(QAbstractSpinBox::NoButtons);
    ui->pack_dateButton->hide();
    ui->pack_ackButton->hide();
    if (product->log_co2pressure) {
        ui->carb_logLabel->show();
        ui->carb_logButton->show();
    } else {
        ui->carb_logLabel->hide();
        ui->carb_logButton->hide();
    }
    if (((stage == PROD_STAGE_TERTIARY) || (stage == PROD_STAGE_PACKAGE)) &&
	 (product->package_volume > 1) && ((product->bottle_amount + product->keg_amount) > 1)) {
	ui->pack_dateEdit->setReadOnly(false);
        ui->pack_dateEdit->setButtonSymbols(QAbstractSpinBox::UpDownArrows);
	ui->pack_dateEdit->setMinimumDate(product->secondary_end_date.addDays(-1));     // Allow same date as secondary end.
        ui->pack_dateEdit->setMaximumDate(QDate::currentDate());
        ui->pack_dateButton->show();
	if (stage == PROD_STAGE_PACKAGE)
	    ui->pack_ackButton->show();
    }

    /* Tab 12, tasting */
    ui->tabWidget->setTabEnabled(11, stage > PROD_STAGE_PACKAGE);
    ui->taste_dateEdit->setEnabled(stage == PROD_STAGE_TASTE);
    if (stage == PROD_STAGE_TASTE) {
	ui->taste_dateEdit->setMinimumDate(product->package_date.addDays(41));
	ui->taste_dateEdit->setMaximumDate(QDate::currentDate());
    }
    ui->taste_dateButton->setEnabled(stage == PROD_STAGE_TASTE);
    ui->taste_colorEdit->setEnabled(stage == PROD_STAGE_TASTE);
    ui->taste_transparencyEdit->setEnabled(stage == PROD_STAGE_TASTE);
    ui->taste_headEdit->setEnabled(stage == PROD_STAGE_TASTE);
    ui->taste_aromaEdit->setEnabled(stage == PROD_STAGE_TASTE);
    ui->taste_tasteEdit->setEnabled(stage == PROD_STAGE_TASTE);
    ui->taste_mouthfeelEdit->setEnabled(stage == PROD_STAGE_TASTE);
    ui->taste_aftertasteEdit->setEnabled(stage == PROD_STAGE_TASTE);
    ui->taste_notesEdit->setEnabled(stage == PROD_STAGE_TASTE);
    ui->taste_rateEdit->setEnabled(stage == PROD_STAGE_TASTE);
    if ((product->taste_color != "") && (product->taste_transparency != "") && (product->taste_head != "") &&
	(product->taste_aroma != "") && (product->taste_taste != "") && (product->taste_mouthfeel != "") &&
	(product->taste_aftertaste != "") && (product->taste_notes != "") && (product->taste_rate > 0) &&
	(product->taste_date.isValid() && (stage == PROD_STAGE_TASTE)))
	ui->taste_ackButton->show();
    else
	ui->taste_ackButton->hide();
}


void EditProduct::reduce_fermentable(int i)
{
    QSqlQuery query;

    query.prepare("SELECT record,inventory FROM inventory_fermentables WHERE name=:name AND origin=:origin AND supplier=:supplier LIMIT 1");
    query.bindValue(":name", product->fermentables.at(i).name);
    query.bindValue(":origin", product->fermentables.at(i).origin);
    query.bindValue(":supplier", product->fermentables.at(i).supplier);
    query.exec();
    if (query.first()) {
	int record = query.value("record").toInt();
	double inventory = query.value("inventory").toDouble() - product->fermentables.at(i).amount;
	if (inventory < 0)
	    inventory = 0;
	else
	    inventory = round(inventory * 100000) / 100000;
	query.prepare("UPDATE inventory_fermentables SET inventory=:inventory WHERE record=:record");
	query.bindValue(":inventory", inventory );
	query.bindValue(":record", record);
	query.exec();
	if (query.lastError().isValid()) {
	    qWarning() << "UPDATE inventory_fermentables" << query.lastError();
	} else {
	    qInfo() << "  Reduced" << product->fermentables.at(i).name << "to" << inventory;
	}
    } else {
	qWarning() << "  Fermentable" << product->fermentables.at(i).name << "not found";
    }
}


void EditProduct::reduce_hop(int i)
{
    QSqlQuery query;

    query.prepare("SELECT record,inventory FROM inventory_hops WHERE name=:name AND origin=:origin AND form=:form LIMIT 1");
    query.bindValue(":name", product->hops.at(i).name);
    query.bindValue(":origin", product->hops.at(i).origin);
    query.bindValue(":form", product->hops.at(i).form);
    query.exec();
    if (query.first()) {
        int record = query.value("record").toInt();
        double inventory = query.value("inventory").toDouble() - product->hops.at(i).amount;
        if (inventory < 0)
            inventory = 0;
        else
            inventory = round(inventory * 100000) / 100000;
        query.prepare("UPDATE inventory_hops SET inventory=:inventory WHERE record=:record");
        query.bindValue(":inventory", inventory );
        query.bindValue(":record", record);
        query.exec();
        if (query.lastError().isValid()) {
            qWarning() << "UPDATE inventory_hops" << query.lastError();
        } else {
            qInfo() << "  Reduced" << product->hops.at(i).name << "to" << inventory;
        }
    } else {
        qWarning() << "  Hop" << product->hops.at(i).name << "not found";
    }
}


void EditProduct::reduce_misc(int i)
{
    QSqlQuery query;

    query.prepare("SELECT record,inventory FROM inventory_miscs WHERE name=:name LIMIT 1");
    query.bindValue(":name", product->miscs.at(i).name);
    query.exec();
    if (query.first()) {
        int record = query.value("record").toInt();
        double inventory = query.value("inventory").toDouble() - product->miscs.at(i).amount;
        if (inventory < 0)
            inventory = 0;
        else
            inventory = round(inventory * 100000) / 100000;
        query.prepare("UPDATE inventory_miscs SET inventory=:inventory WHERE record=:record");
        query.bindValue(":inventory", inventory );
        query.bindValue(":record", record);
        query.exec();
        if (query.lastError().isValid()) {
            qWarning() << "UPDATE inventory_miscs" << query.lastError();
        } else {
            qInfo() << "  Reduced" << product->miscs.at(i).name << "to" << inventory;
        }
    } else {
        qWarning() << "  Misc" << product->miscs.at(i).name << "not found";
    }
}


void EditProduct::reduce_yeast(int i)
{
    QSqlQuery query;

    query.prepare("SELECT record,inventory FROM inventory_yeasts WHERE name=:name AND laboratory=:laboratory AND product_id=:product_id AND form=:form LIMIT 1");
    query.bindValue(":name", product->yeasts.at(i).name);
    query.bindValue(":laboratory", product->yeasts.at(i).laboratory);
    query.bindValue(":product_id", product->yeasts.at(i).product_id);
    query.bindValue(":form", product->yeasts.at(i).form);
    query.exec();
    if (query.first()) {
        int record = query.value("record").toInt();
        double inventory = query.value("inventory").toDouble() - product->yeasts.at(i).amount;
        if (inventory < 0)
            inventory = 0;
        else
            inventory = round(inventory * 100000) / 100000;
        query.prepare("UPDATE inventory_yeasts SET inventory=:inventory WHERE record=:record");
        query.bindValue(":inventory", inventory );
        query.bindValue(":record", record);
        query.exec();
        if (query.lastError().isValid()) {
            qWarning() << "UPDATE inventory_yeasts" << query.lastError();
        } else {
            qInfo() << "  Reduced" << product->yeasts.at(i).name << "to" << inventory;
        }
    } else {
        qWarning() << "  Yeast" << product->yeasts.at(i).name << "not found";
    }
}


/*
 * Reduce inventory depending on the production stage.
 *  Stage PROD_STAGE_BREW+, after brew, reduce sugars(0-mash, 1-boil), hops(0-mash, 1-fwh, 2-boil, 3-aroma, 4-whirlpool), miscs(0-starter, 1-mash, 2-boil)
 *  Stage PROD_STAGE_PRIMARY+, after primary, reduce sugars(2-fermention), yeasts(0-Primary), miscs(3-primary)
 *  Stage PROD_STAGE_SECONDARY+, after secondary, reduce yeasts(1-Secondary)
 *  Stage PROD_STAGE_TERTIARY+, after tertiary, reduce sugars(3-lagering), hops(5-dry-hop), yeasts(2-Tertiary), miscs(4-secondary)
 *  Stage PROD_STAGE_PACKAGE+, after packaging, reduce sugars(4-bottle, 5-kegs), hops( Extract ), yeasts(3-Bottle), miscs(5-bottling)
 */
void EditProduct::inventory_reduce()
{
    bool savethis = false;
    QSqlQuery query;

    if (product->stage == product->inventory_reduced)
	return;

    /*
     * Nothing to reduce yet, but just set inventory reduced.
     */
    if ((product->stage >= PROD_STAGE_WAIT) && (product->inventory_reduced < PROD_STAGE_WAIT)) {
	product->inventory_reduced = PROD_STAGE_WAIT;
	savethis = true;
    }
    if ((product->stage >= PROD_STAGE_BREW) && (product->inventory_reduced < PROD_STAGE_BREW)) {
	product->inventory_reduced = PROD_STAGE_BREW;
	savethis = true;
    }

    /*
     * If the brew is done, reduce the used ingredients.
     */
    if ((product->stage >= PROD_STAGE_PRIMARY) && (product->inventory_reduced < PROD_STAGE_PRIMARY)) {
	qInfo() << "Reduce brew inventory from" << product->code << product->name;

	if (product->fermentables.size()) {
	    for (int i = 0; i < product->fermentables.size(); i++) {
		if (product->fermentables.at(i).added <= FERMENTABLE_ADDED_BOIL) {	/* Mash or boil */
		    reduce_fermentable(i);
		}
	    }
	}
	if (product->hops.size()) {
	    for (int i = 0; i < product->hops.size(); i++) {
		if (product->hops.at(i).useat <= HOP_USEAT_WHIRLPOOL) {	/* Mash, FWH, Boil, Flameout, Whirlpool */
		    reduce_hop(i);
		}
	    }
	}
	if (product->miscs.size()) {
	    for (int i = 0; i < product->miscs.size(); i++) {
		if (product->miscs.at(i).use_use <= MISC_USES_BOIL) {	/* Starter, Mash, Boil */
		    reduce_misc(i);
		}
	    }
	}
	if ((product->w1_name != "") && (product->w1_amount > 0)) {
	    query.prepare("SELECT record,inventory FROM inventory_waters WHERE name=:name AND unlimited_stock=0 LIMIT 1");
	    query.bindValue(":name", product->w1_name);
	    query.exec();
	    if (query.first()) {
		int record = query.value("record").toInt();
		double inventory = query.value("inventory").toDouble() - product->w1_amount;
	        if (inventory < 0)
        	    inventory = 0;
        	else
        	    inventory = round(inventory * 100) / 100;
        	query.prepare("UPDATE inventory_waters SET inventory=:inventory WHERE record=:record");
        	query.bindValue(":inventory", inventory );
        	query.bindValue(":record", record);
        	query.exec();
        	if (query.lastError().isValid()) {
        	    qWarning() << "UPDATE inventory_waters" << query.lastError();
        	} else {
        	    qInfo() << "  Reduced" << product->w1_name << "to" << inventory;
        	}
	    }
	}
	if ((product->w2_name != "") && (product->w2_amount > 0)) {
	    query.prepare("SELECT record,inventory FROM inventory_waters WHERE name=:name AND unlimited_stock=0 LIMIT 1");
            query.bindValue(":name", product->w1_name);
            query.exec();
            if (query.first()) {
                int record = query.value("record").toInt();
                double inventory = query.value("inventory").toDouble() - product->w1_amount;
                if (inventory < 0)
                    inventory = 0;
                else
                    inventory = round(inventory * 100) / 100;
                query.prepare("UPDATE inventory_waters SET inventory=:inventory WHERE record=:record");
                query.bindValue(":inventory", inventory );
                query.bindValue(":record", record);
                query.exec();
                if (query.lastError().isValid()) {
                    qWarning() << "UPDATE inventory_waters" << query.lastError();
                } else {
                    qInfo() << "  Reduced" << product->w1_name << "to" << inventory;
                }
            }
	}
	product->inventory_reduced = PROD_STAGE_PRIMARY;
        savethis = true;
    }

    /*
     * After the Primary fermentation
     */
    if ((product->stage >= PROD_STAGE_SECONDARY) && (product->inventory_reduced < PROD_STAGE_SECONDARY)) {
	qInfo() << "Reduce primary inventory from" << product->code << product->name;

	if (product->fermentables.size()) {
            for (int i = 0; i < product->fermentables.size(); i++) {
                if (product->fermentables.at(i).added == FERMENTABLE_ADDED_FERMENTATION) {
                    reduce_fermentable(i);
                }
            }
        }
	if (product->miscs.size()) {
            for (int i = 0; i < product->miscs.size(); i++) {
                if (product->miscs.at(i).use_use == MISC_USES_PRIMARY) {
                    reduce_misc(i);
                }
            }
        }
	if (product->yeasts.size()) {
            for (int i = 0; i < product->yeasts.size(); i++) {
                if (product->yeasts.at(i).use == YEAST_USE_PRIMARY) {
                    reduce_yeast(i);
                }
            }
        }
	product->inventory_reduced = PROD_STAGE_SECONDARY;
        savethis = true;
    }

    /*
     * After the Seconday fermentation
     */
    if ((product->stage >= PROD_STAGE_TERTIARY) && (product->inventory_reduced < PROD_STAGE_TERTIARY)) {
	qInfo() << "Reduce secondary inventory from" << product->code << product->name;

	if (product->yeasts.size()) {
            for (int i = 0; i < product->yeasts.size(); i++) {
                if (product->yeasts.at(i).use == YEAST_USE_SECONDARY) {
                    reduce_yeast(i);
                }
            }
        }
	product->inventory_reduced = PROD_STAGE_TERTIARY;
        savethis = true;
    }

    /*
     * After the Tertiary fermentation
     */
    if ((product->stage >= PROD_STAGE_PACKAGE) && (product->inventory_reduced < PROD_STAGE_PACKAGE)) {
	qInfo() << "Reduce tertiary inventory from" << product->code << product->name;

	if (product->fermentables.size()) {
            for (int i = 0; i < product->fermentables.size(); i++) {
                if (product->fermentables.at(i).added == FERMENTABLE_ADDED_LAGERING) {
                    reduce_fermentable(i);
                }
            }
        }
	if (product->hops.size()) {
            for (int i = 0; i < product->hops.size(); i++) {
                if (product->hops.at(i).useat == HOP_USEAT_DRY_HOP) {
                    reduce_hop(i);
                }
            }
        }
	if (product->miscs.size()) {
            for (int i = 0; i < product->miscs.size(); i++) {
                if (product->miscs.at(i).use_use == MISC_USES_SECONDARY) {
                    reduce_misc(i);
                }
            }
        }
        if (product->yeasts.size()) {
            for (int i = 0; i < product->yeasts.size(); i++) {
                if (product->yeasts.at(i).use == YEAST_USE_TERTIARY) {
                    reduce_yeast(i);
                }
            }
        }

	product->inventory_reduced = PROD_STAGE_PACKAGE;
        savethis = true;
    }

    /*
     * After packaging
     *  reduce sugars(4/5-bottle), yeasts(3-Bottle), miscs(5-bottling)
     */
    if ((product->stage >= PROD_STAGE_CARBONATION) && (product->inventory_reduced < PROD_STAGE_CARBONATION)) {
	qInfo() << "Reduce package inventory from" << product->code << product->name;

	if (product->fermentables.size()) {
            for (int i = 0; i < product->fermentables.size(); i++) {
                if (product->fermentables.at(i).added >= FERMENTABLE_ADDED_BOTTLE) {
                    reduce_fermentable(i);
                }
            }
        }
	if (product->yeasts.size()) {
            for (int i = 0; i < product->yeasts.size(); i++) {
                if (product->yeasts.at(i).use == YEAST_USE_BOTTLE) {
                    reduce_yeast(i);
                }
            }
        }
	if (product->hops.size()) {
            for (int i = 0; i < product->hops.size(); i++) {
                if (product->hops.at(i).useat == HOP_USEAT_BOTTLING) {
                    reduce_hop(i);
                }
            }
        }
	if (product->miscs.size()) {
            for (int i = 0; i < product->miscs.size(); i++) {
                if (product->miscs.at(i).use_use == MISC_USES_BOTTLING) {
                    reduce_misc(i);
                }
            }
        }
	product->inventory_reduced = PROD_STAGE_CARBONATION;
        savethis = true;
    }

    if ((product->stage >= PROD_STAGE_MATURE) && (product->inventory_reduced < PROD_STAGE_MATURE)) {
	product->inventory_reduced = product->stage;
	savethis = true;
    }

    /*
     * Update the inventory_reduced state.
     */
    if (savethis) {
	query.prepare("UPDATE products SET inventory_reduced=:inventory_reduced WHERE record=:record");
	query.bindValue(":record", product->record);
	query.bindValue(":inventory_reduced", product->inventory_reduced);
	query.exec();
    	if (query.lastError().isValid()) {
	    qWarning() << "UPDATE products" << query.lastError();
	}
    }
}

mercurial