2139 checkLine(&painter, &y, QString(tr("Add %1 gr `%2`")).arg(product->hops.at(i).amount * 1000 * factor, 1, 'f', 2) |
2139 checkLine(&painter, &y, QString(tr("Add %1 gr `%2`")).arg(product->hops.at(i).amount * 1000 * factor, 1, 'f', 2) |
2140 .arg(product->hops.at(i).name)); |
2140 .arg(product->hops.at(i).name)); |
2141 } |
2141 } |
2142 } |
2142 } |
2143 } |
2143 } |
|
2144 } else if (p_job == PR_REP_TOTAL) { |
|
2145 |
|
2146 qInfo() << "Print total production"; |
|
2147 printHeader(&painter); |
|
2148 y = 120; |
|
2149 |
|
2150 /* Report header */ |
|
2151 painter.setFont(QFont("Helvetica", 9, QFont::Bold)); |
|
2152 painter.setPen(Qt::black); |
|
2153 painter.fillRect( 20, y, 540, 20, c_header); |
|
2154 painter.drawText( 20, y+4, 80, 20, Qt::AlignHCenter, tr("Number")); |
|
2155 painter.drawText(100, y+4, 80, 20, Qt::AlignHCenter, tr("Year")); |
|
2156 painter.drawText(180, y+4, 120, 20, Qt::AlignRight, tr("Brew sessions")); |
|
2157 painter.drawText(300, y+4, 120, 20, Qt::AlignRight, tr("Brew volume")); |
|
2158 painter.drawText(420, y+4, 120, 20, Qt::AlignRight, tr("Average volume")); |
|
2159 y += 20; |
|
2160 painter.setFont(QFont("Helvetica", 9, QFont::Normal)); |
|
2161 query.exec("SELECT DISTINCT YEAR(package_date) FROM products WHERE package_date ORDER BY package_date"); |
|
2162 query.first(); |
|
2163 int regel = 0, brews = 0, total = 0; |
|
2164 double packaged = 0, tvolume = 0, average; |
|
2165 QString year = ""; |
|
2166 for (int i = 0 ; i < query.size() ; i++ ) { |
|
2167 if ((y + 20) > painter.device()->height()) { |
|
2168 printer->newPage(); |
|
2169 printHeader(&painter); |
|
2170 y = 120; |
|
2171 } |
|
2172 |
|
2173 brews = 0; |
|
2174 packaged = 0; |
|
2175 regel++; |
|
2176 year = query.value(0).toString(); |
|
2177 QSqlQuery query2; |
|
2178 query2.exec("SELECT package_volume FROM products WHERE package_date AND YEAR(package_date) = '" + year + "'"); |
|
2179 while (query2.next()) { |
|
2180 brews++; |
|
2181 total++; |
|
2182 packaged += query2.value(0).toDouble(); |
|
2183 tvolume += query2.value(0).toDouble(); |
|
2184 } |
|
2185 average = packaged / brews; |
|
2186 painter.fillRect( 20, y, 540, 20, (i % 2) ? c_line1:c_line2); |
|
2187 painter.drawText( 20, y+4, 80, 20, Qt::AlignCenter, QString("%1").arg(regel)); |
|
2188 painter.drawText(100, y+4, 100, 20, Qt::AlignCenter, year); |
|
2189 painter.drawText(180, y+4, 120, 20, Qt::AlignRight, QString("%1").arg(brews)); |
|
2190 painter.drawText(300, y+4, 120, 20, Qt::AlignRight, QString("%1 L").arg(packaged, 2, 'f', 1, '0')); |
|
2191 painter.drawText(420, y+4, 120, 20, Qt::AlignRight, QString("%1 L").arg(average, 2, 'f', 1, '0')); |
|
2192 query.next(); |
|
2193 y += 20; |
|
2194 } |
|
2195 average = tvolume / total; |
|
2196 painter.fillRect(180, y, 360, 20, w_line); |
|
2197 painter.drawText(180, y+4, 120, 20, Qt::AlignRight, QString("%1").arg(total)); |
|
2198 painter.drawText(300, y+4, 120, 20, Qt::AlignRight, QString("%1 L").arg(tvolume, 2, 'f', 1, '0')); |
|
2199 painter.drawText(420, y+4, 120, 20, Qt::AlignRight, QString("%1 L").arg(average, 2, 'f', 1, '0')); |
|
2200 y += 20; |
|
2201 |
|
2202 } else if (p_job == PR_REP_EFF) { |
|
2203 |
|
2204 qInfo() << "Print efficiency"; |
|
2205 y = painter.device()->height() + 100; |
|
2206 |
|
2207 query.exec("SELECT * FROM products WHERE package_date AND type='2' ORDER BY code"); |
|
2208 query.first(); |
|
2209 for (int i = 0 ; i < query.size() ; i++ ) { |
|
2210 if ((y + 20) > painter.device()->height()) { |
|
2211 if (i > 0) |
|
2212 printer->newPage(); |
|
2213 printHeader(&painter); |
|
2214 y = 120; |
|
2215 |
|
2216 /* Report header */ |
|
2217 painter.setFont(QFont("Helvetica", 9, QFont::Bold)); |
|
2218 painter.setPen(Qt::black); |
|
2219 painter.fillRect( 20, y, 715, 20, c_header); |
|
2220 painter.drawText( 25, y+4, 65, 20, Qt::AlignLeft, tr("Code")); |
|
2221 painter.drawText( 90, y+4, 200, 20, Qt::AlignLeft, tr("Name")); |
|
2222 painter.drawText(290, y+4, 120, 20, Qt::AlignLeft, tr("Beer style")); |
|
2223 painter.drawText(410, y+4, 80, 20, Qt::AlignRight, tr("Max extract")); |
|
2224 painter.drawText(490, y+4, 80, 20, Qt::AlignRight, tr("Mash eff.")); |
|
2225 painter.drawText(570, y+4, 80, 20, Qt::AlignRight, tr("Sparge eff")); |
|
2226 painter.drawText(650, y+4, 80, 20, Qt::AlignRight, tr("Boil eff")); |
|
2227 y += 20; |
|
2228 painter.setFont(QFont("Helvetica", 9, QFont::Normal)); |
|
2229 } |
|
2230 |
|
2231 /* |
|
2232 * Data is not always available, calculate the missing pieces. |
|
2233 */ |
|
2234 double mvol = 0, msugars = 0, ssugars = 0; |
|
2235 QJsonParseError parseError; |
|
2236 |
|
2237 const auto& ma_json = query.value("json_mashs").toString().trimmed(); |
|
2238 if (!ma_json.trimmed().isEmpty()) { |
|
2239 const auto& formattedJson = QString("%1").arg(ma_json); |
|
2240 QJsonDocument mashs = QJsonDocument::fromJson(formattedJson.toUtf8(), &parseError); |
|
2241 if (parseError.error != QJsonParseError::NoError) { |
|
2242 qWarning() << "Parse error: " << parseError.errorString() << "at" << parseError.offset ; |
|
2243 } else if (mashs.isArray()) { |
|
2244 for (int j = 0; j < mashs.array().size(); j++) { |
|
2245 QJsonObject obj = mashs.array().at(j).toObject(); |
|
2246 if (obj["step_type"].toInt() == 0) |
|
2247 mvol += obj["step_infuse_amount"].toDouble(); |
|
2248 } |
|
2249 } |
|
2250 } |
|
2251 |
|
2252 const auto& f_json = query.value("json_fermentables").toString(); |
|
2253 if (!f_json.trimmed().isEmpty()) { |
|
2254 const auto& formattedJson = QString("%1").arg(f_json); |
|
2255 QJsonDocument fermentables = QJsonDocument::fromJson(formattedJson.toUtf8(), &parseError); |
|
2256 if (parseError.error != QJsonParseError::NoError) { |
|
2257 qWarning() << "Parse error: " << parseError.errorString() << "at" << parseError.offset ; |
|
2258 } else if (fermentables.isArray()) { |
|
2259 for (int j = 0; j < fermentables.array().size(); j++) { |
|
2260 QJsonObject obj = fermentables.array().at(j).toObject(); |
|
2261 if (obj["f_added"].toInt() == 0) { |
|
2262 double d = obj["f_amount"].toDouble() * (obj["f_yield"].toDouble() / 100) * (1 - obj["f_moisture"].toDouble() / 100); |
|
2263 ssugars += obj["f_amount"].toDouble(); |
|
2264 mvol += obj["f_amount"].toDouble() * obj["f_moisture"].toDouble() / 100; |
|
2265 msugars += d; |
|
2266 } |
|
2267 } |
|
2268 } |
|
2269 } |
|
2270 |
|
2271 double sugardensity = 1.611; |
|
2272 double v = msugars / sugardensity + mvol; |
|
2273 double plato = 1000 * msugars / (v * 10); // deg. Plato |
|
2274 double mash_efficiency = query.value("brew_mash_efficiency").toDouble(); |
|
2275 double mash_sg = query.value("brew_mash_sg").toDouble(); |
|
2276 if ((mash_efficiency == 0) && (mash_sg > 1)) { |
|
2277 mash_efficiency = 100 * Utils::sg_to_plato(mash_sg) / plato; |
|
2278 } |
|
2279 double mash_extract = 100 * msugars / ssugars; |
|
2280 double preboil_sg = query.value("brew_preboil_sg").toDouble(); |
|
2281 double preboil_volume = query.value("brew_preboil_volume").toDouble(); |
|
2282 double est_preboil_plato = Utils::sg_to_plato(preboil_sg) * (preboil_volume / 1.04) * preboil_sg * 10 / 1000; |
|
2283 double preboil_efficiency = query.value("brew_preboil_efficiency").toDouble(); |
|
2284 if ((msugars > 0) && (preboil_efficiency == 0)) |
|
2285 preboil_efficiency = est_preboil_plato / msugars * 100; |
|
2286 if (preboil_efficiency < 0) |
|
2287 preboil_efficiency = 0; |
|
2288 double aboil_efficiency = query.value("brew_aboil_efficiency").toDouble(); |
|
2289 |
|
2290 painter.fillRect( 20, y, 715, 20, (i % 2) ? c_line1:c_line2); |
|
2291 painter.drawText( 25, y+4, 65, 20, Qt::AlignLeft, query.value("code").toString()); |
|
2292 painter.drawText( 90, y+4, 200, 20, Qt::AlignLeft, query.value("name").toString()); |
|
2293 painter.drawText(290, y+4, 120, 20, Qt::AlignLeft, query.value("st_name").toString()); |
|
2294 painter.drawText(410, y+4, 80, 20, Qt::AlignRight, QString("%1%").arg(mash_extract, 2, 'f', 1, '0')); |
|
2295 painter.drawText(490, y+4, 80, 20, Qt::AlignRight, QString("%1%").arg(mash_efficiency, 2, 'f', 1, '0')); |
|
2296 painter.drawText(570, y+4, 80, 20, Qt::AlignRight, QString("%1%").arg(preboil_efficiency, 2, 'f', 1, '0')); |
|
2297 painter.drawText(650, y+4, 80, 20, Qt::AlignRight, QString("%1%").arg(aboil_efficiency, 2, 'f', 1, '0')); |
|
2298 query.next(); |
|
2299 y += 20; |
|
2300 } |
|
2301 |
|
2302 } else if (p_job == PR_REP_SVG) { |
|
2303 |
|
2304 qInfo() << "Print fermentations"; |
|
2305 y = painter.device()->height() + 100; |
|
2306 QString y_name, y_lab, y_product; |
|
2307 |
|
2308 /* |
|
2309 * Works from MariaDB 10.6.x and later, MySQL 8.x and later. |
|
2310 * Pick the first yeast record, that should be the one used for primary. |
|
2311 */ |
|
2312 query.exec("SELECT code,name,brew_date_end,primary_end_temp,primary_end_date,secondary_temp,secondary_end_date,tertiary_temp," |
|
2313 "package_date,brew_fermenter_sg,fg,json_yeasts," |
|
2314 "JSON_EXTRACT(json_yeasts, '$[0].y_laboratory') AS yeastLab,JSON_EXTRACT(json_yeasts, '$[0].y_product_id') AS yeastID " |
|
2315 "FROM products WHERE package_date AND type='2' ORDER BY yeastID"); |
|
2316 query.first(); |
|
2317 |
|
2318 for (int i = 0 ; i < query.size() ; i++ ) { |
|
2319 if ((y + 20) > painter.device()->height()) { |
|
2320 if (i > 0) |
|
2321 printer->newPage(); |
|
2322 printHeader(&painter); |
|
2323 y = 120; |
|
2324 |
|
2325 /* Report header */ |
|
2326 painter.setFont(QFont("Helvetica", 9, QFont::Bold)); |
|
2327 painter.setPen(Qt::black); |
|
2328 painter.fillRect( 20, y, 715, 20, c_header); |
|
2329 painter.drawText( 25, y+4, 65, 20, Qt::AlignLeft, tr("Code")); |
|
2330 painter.drawText( 90, y+4, 180, 20, Qt::AlignLeft, tr("Name")); |
|
2331 painter.drawText(270, y+4, 110, 20, Qt::AlignLeft, tr("Yeast")); |
|
2332 painter.drawText(380, y+4, 60, 20, Qt::AlignHCenter, tr("Primary")); |
|
2333 painter.drawText(440, y+4, 60, 20, Qt::AlignHCenter, tr("Secondary")); |
|
2334 painter.drawText(500, y+4, 60, 20, Qt::AlignHCenter, tr("Tertiary")); |
|
2335 painter.drawText(560, y+4, 40, 20, Qt::AlignRight, tr("Days")); |
|
2336 painter.drawText(600, y+4, 40, 20, Qt::AlignRight, tr("OG")); |
|
2337 painter.drawText(640, y+4, 40, 20, Qt::AlignRight, tr("FG")); |
|
2338 painter.drawText(680, y+4, 50, 20, Qt::AlignRight, tr("AA")); |
|
2339 y += 20; |
|
2340 painter.setFont(QFont("Helvetica", 9, QFont::Normal)); |
|
2341 } |
|
2342 |
|
2343 int primary = query.value("brew_date_end").toDate().daysTo(query.value("primary_end_date").toDate()); |
|
2344 int secondary = query.value("primary_end_date").toDate().daysTo(query.value("secondary_end_date").toDate()); |
|
2345 int tertiary = query.value("secondary_end_date").toDate().daysTo(query.value("package_date").toDate()); |
|
2346 int total = query.value("brew_date_end").toDate().daysTo(query.value("package_date").toDate()); |
|
2347 double og = query.value("brew_fermenter_sg").toDouble(); |
|
2348 double fg = query.value("fg").toDouble(); |
|
2349 double aa = Utils::calc_svg(og, fg); |
|
2350 |
|
2351 painter.fillRect( 20, y, 715, 20, (i % 2) ? c_line1:c_line2); |
|
2352 painter.drawText( 25, y+4, 65, 20, Qt::AlignLeft, query.value("code").toString()); |
|
2353 painter.drawText( 90, y+4, 180, 20, Qt::AlignLeft, query.value("name").toString()); |
|
2354 painter.drawText(270, y+4, 110, 20, Qt::AlignLeft, query.value("yeastID").toString() + " " + query.value("yeastLab").toString()); |
|
2355 painter.drawText(380, y+4, 40, 20, Qt::AlignRight, QString("%1°").arg(query.value("primary_end_temp").toDouble(), 2, 'f', 1)); |
|
2356 painter.drawText(420, y+4, 20, 20, Qt::AlignRight, QString("%1").arg(primary)); |
|
2357 painter.drawText(440, y+4, 40, 20, Qt::AlignRight, QString("%1°").arg(query.value("secondary_temp").toDouble(), 2, 'f', 1)); |
|
2358 painter.drawText(480, y+4, 20, 20, Qt::AlignRight, QString("%1").arg(secondary)); |
|
2359 painter.drawText(500, y+4, 40, 20, Qt::AlignRight, QString("%1°").arg(query.value("tertiary_temp").toDouble(), 2, 'f', 1)); |
|
2360 painter.drawText(540, y+4, 20, 20, Qt::AlignRight, QString("%1").arg(tertiary)); |
|
2361 painter.drawText(560, y+4, 40, 20, Qt::AlignRight, QString("%1").arg(total)); |
|
2362 painter.drawText(600, y+4, 40, 20, Qt::AlignRight, QString("%1").arg(og, 4, 'f', 3, '0')); |
|
2363 painter.drawText(640, y+4, 40, 20, Qt::AlignRight, QString("%1").arg(fg, 4, 'f', 3, '0')); |
|
2364 painter.drawText(680, y+4, 50, 20, Qt::AlignRight, QString("%1%").arg(aa, 2, 'f', 1, '0')); |
|
2365 |
|
2366 query.next(); |
|
2367 y += 20; |
|
2368 } |
2144 } |
2369 } |
2145 |
2370 |
2146 painter.end(); |
2371 painter.end(); |
2147 } |
2372 } |
2148 |
2373 |