src/EditProductTab1.cpp

Fri, 29 Jul 2022 13:12:26 +0200

author
Michiel Broek <mbroek@mbse.eu>
date
Fri, 29 Jul 2022 13:12:26 +0200
changeset 373
b02aca4e926c
parent 361
ec8de79f6ff6
child 395
7212b980a527
permissions
-rw-r--r--

First load of changes for hops. In EditHop load the dropdown buttons from the global table. Use named query fields. Added database utilisation and bu_factor fields for hop extracts. Added edit fields for these new fields. Added post boil SG, utilisation and bu_factor parameters to the toIBU function. Added hops form parameter to the hopFlavourContribution and hopAromaContribution display bars. In the hops inventory list dispay volumes instead of weight for hop extracts. Modified the TinsethIBU function to use utilisation and bu_factor parameters. Add calculations for co2 and iso hop extracts, this is work in progress. The toIBU function makes use of the preSG and postSG values to use the correct SG to caall the TinsethIBU function. This results in a bit lower IBU values mostly affecting the late additions. Added use hop at bottling for iso hop extracts like Tetra hops using the formula from BarthHaas.

/**
 * 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::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_carbShow->setRange(query.value(15).toDouble(), query.value(16).toDouble());
    ui->est_abvShow->setRange(query.value(17).toDouble(), query.value(18).toDouble());

    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_tempEdit->setReadOnly(stage > PROD_STAGE_BREW);
    //ui->sp_tempEdit->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