www/js/prod_edit.js

changeset 469
3d532097860d
parent 464
fbd2a7cecaaa
child 470
94a69f6b0f35
equal deleted inserted replaced
468:371f2da785d9 469:3d532097860d
44 44
45 45
46 46
47 $(document).ready(function () { 47 $(document).ready(function () {
48 48
49 var to_100 = false; // Fermentables adjust to 100% 49 var i,
50 var preboil_sg = 0; 50 to_100 = false, // Fermentables adjust to 100%
51 var aboil_sg = 0; 51 preboil_sg = 0,
52 var est_mash_sg = 0; 52 aboil_sg = 0,
53 var psugar = 0; // Percentage real sugars 53 est_mash_sg = 0,
54 var pcara = 0; // Percentage cara/crystal malts 54 psugar = 0, // Percentage real sugars
55 var svg = 77; // Default attenuation 55 pcara = 0, // Percentage cara/crystal malts
56 var mashkg = 0; // Malt in mash weight 56 svg = 77, // Default attenuation
57 var pitchrate = 0.75; // Yeast pitch rate default 57 mashkg = 0, // Malt in mash weight
58 var initcells = 0; // Initial yeast cell count 58 pitchrate = 0.75, // Yeast pitch rate default
59 59 initcells = 0, // Initial yeast cell count
60 var ok_fermentables = 1; // Fermentables are in stock 60
61 var ok_hops = 1; // Hops are in stock 61 ok_fermentables = 1, // Fermentables are in stock
62 var ok_miscs = 1; // Miscs are in stock 62 ok_hops = 1, // Hops are in stock
63 var ok_yeasts = 1; // Yeasts are in stock 63 ok_miscs = 1, // Miscs are in stock
64 var ok_waters = 1; // Waters are in stock 64 ok_yeasts = 1, // Yeasts are in stock
65 65 ok_waters = 1, // Waters are in stock
66 var hop_flavour = 0; 66
67 var hop_aroma = 0; 67 hop_flavour = 0,
68 var mash_infuse = 0; 68 hop_aroma = 0,
69 var last_base = ''; 69 mash_infuse = 0,
70 var last_acid = ''; 70 last_base = '',
71 71 last_acid = '',
72 var MMCa = 40.048; 72
73 var MMMg = 24.305; 73 MMCa = 40.048,
74 var MMNa = 22.98976928; 74 MMMg = 24.305,
75 var MMCl = 35.453; 75 MMNa = 22.98976928,
76 var MMSO4 = 96.0626; 76 MMCl = 35.453,
77 var MMHCO3 = 61.01684; 77 MMSO4 = 96.0626,
78 var MMCaSO4 = 172.171; 78 MMHCO3 = 61.01684,
79 var MMCaCl2 = 147.015; 79 MMCaSO4 = 172.171,
80 var MMCaCO3 = 100.087; 80 MMCaCl2 = 147.015,
81 var MMMgSO4 = 246.475; 81 MMCaCO3 = 100.087,
82 var MMNaHCO3 = 84.007; 82 MMMgSO4 = 246.475,
83 var MMNa2CO3 = 105.996; 83 MMNaHCO3 = 84.007,
84 var MMNaCl = 58.443; 84 MMNa2CO3 = 105.996,
85 var MMCaOH2 = 74.06268; 85 MMNaCl = 58.443,
86 86 MMCaOH2 = 74.06268,
87 var fermentableRow = 0; 87
88 var fermentableData = {}; 88 fermentableRow = 0,
89 var fermentableInit = 1; 89 fermentableData = {},
90 var hopRow = 0; 90 fermentableInit = 1,
91 var hopData = {}; 91 hopRow = 0,
92 var miscRow = 0; 92 hopData = {},
93 var miscData = {}; 93 miscRow = 0,
94 var yeastRow = 0; 94 miscData = {},
95 var yeastData = {}; 95 yeastRow = 0,
96 var mashRow = 0; 96 yeastData = {},
97 var mashData = {}; 97 mashRow = 0,
98 98 mashData = {},
99 /* 99 Ka1 = 0.0000004445,
100 * Remove the top menu so that we MUST use the buttons to leave the editor. 100 Ka2 = 0.0000000000468,
101 */ 101 dataRecord = {},
102 $('#jqxMenu').jqxMenu('destroy'); 102 url = "includes/db_product.php",
103
104 console.log("record:" + my_record + " return:" + my_return + " theme:" + theme);
105 $("#jqxLoader").jqxLoader({width:250,height:150,isModal:true,text:"Laden product ...",theme:theme});
106
107 function calcSupplies() {
108 if (dataRecord.inventory_reduced > 6) {
109 $("#ok_pmpt").hide();
110 return;
111 }
112 if (ok_fermentables && ok_hops && ok_miscs && ok_yeasts && ok_waters)
113 $("#ok_supplies").html("<img src='images/dialog-ok-apply.png'>");
114 else
115 $("#ok_supplies").html("<img src='images/dialog-error.png'>");
116 }
117
118 function calcPercentages() {
119
120 console.log("calcPercentages()");
121 var rowscount = $("#fermentableGrid").jqxGrid('getdatainformation').rowscount;
122 if (rowscount > 1) {
123 var tw = 0;
124 for (i = 0; i < rowscount; i++) {
125 var rowdata = $("#fermentableGrid").jqxGrid('getrowdata', i);
126 if (rowdata.f_added < 4)
127 tw += Math.round(rowdata.f_amount * 1000) / 1000;
128 };
129 tw = Math.round(tw * 1000) / 1000;
130
131 for (i = 0; i < rowscount; i++) {
132 var rowdata = $("#fermentableGrid").jqxGrid('getrowdata', i);
133 if (rowdata.f_added < 4) {
134 var percentage = Math.round(rowdata.f_amount / tw * 1000) / 10.0;
135 $("#fermentableGrid").jqxGrid('setcellvalue', i, "f_percentage", percentage);
136 } else {
137 $("#fermentableGrid").jqxGrid('setcellvalue', i, "f_percentage", 0);
138 }
139 };
140 } else {
141 $("#fermentableGrid").jqxGrid('setcellvalue', 0, "f_percentage", 100);
142 }
143 }
144
145 /*
146 * All calculations that depend on changes in the fermentables,
147 * volumes and equipments.
148 */
149 function calcFermentables() {
150
151 var sugarsf = 0; // fermentable sugars mash + boil
152 var sugarsm = 0; // fermentable sugars in mash
153 psugar = 0;
154 pcara = 0;
155 mashkg = 0;
156 ok_fermentables = 1; // All is in stock.
157 ok_yeasts = 1;
158 var vol = 0; // Volume sugars after boil
159 var addedS = 0; // Added sugars after boil
160 var addedmass = 0; // Added mass after boil
161 var mvol = 0; // mash volume
162 var colort = 0; // Colors srm * vol totals
163 var colorh = 0; // Colors ebc * vol * kt
164 var colorn = 0; // Colors ebc * pt * pct
165 var my_100 = false;
166 var mashtime = 0; // Total mash time
167 var mashtemp = 0; // Average mash temperature
168 var bv = 0.925; // Bierverlies rendement
169 var sr = 0.95; // Mash en spoel rendement
170 var lintner = 0; // Total recipe lintner
171
172 if ((rows = $('#mashGrid').jqxGrid('getrows'))){
173 for(var i=0;i<rows.length;i++){
174 var row=rows[i];
175 if(row.step_type==0) // Infusion
176 mvol+=parseFloat(row.step_infuse_amount);
177 if(row.step_temp<=75){ // Ignore mashout
178 var timem=row.step_time+row.ramp_time;
179 mashtime+=timem;
180 mashtemp+=timem*row.step_temp;
181 }
182 }
183 if(mashtime>5)
184 mashtime-=5;//Correct last ramp > 75
185 mashtemp=Round(mashtemp/mashtime,2);
186 }
187
188 if (!(rows = $('#fermentableGrid').jqxGrid('getrows'))) {
189 return; // grid not yet loaded.
190 }
191
192 var s = 0;
193 for (var i = 0; i < rows.length; i++) {
194 var row = rows[i];
195 if (row.f_adjust_to_total_100)
196 my_100 = true;
197 if (row.f_type == 1 && row.f_added < 4) // Sugar
198 psugar += row.f_percentage;
199 if (row.f_graintype == 2 && row.f_added < 4) // Crystal
200 pcara += row.f_percentage;
201 var d = row.f_amount * (row.f_yield / 100) * (1 - row.f_moisture / 100);
202 if (row.f_added == 0) { // Mash
203 if (mvol > 0) { // Only if mash already known.
204 mvol += row.f_amount * row.f_moisture / 100;
205 s += d;
206 }
207 d = parseFloat(dataRecord.efficiency) / 100 * d;
208 sugarsm += d;
209 mashkg += parseFloat(row.f_amount);
210 }
211 if (row.f_added == 0 || row.f_added == 1) // Mash or Boil
212 sugarsf += d;
213 if (row.f_added == 2 || row.f_added == 3) { // Fermentation or lagering
214 var x = (row.f_yield / 100) * (1 - row.f_moisture / 100);
215 addedS += row.f_amount * x;
216 addedmass += row.f_amount;
217 vol += (x * sugardensity + (1 - x) * 1) * row.f_amount;
218 }
219 if (row.f_added < 4) {
220 colort += row.f_amount * ebc_to_srm(row.f_color);
221 colorh += row.f_amount * row.f_color * get_kt(row.f_color);
222 colorn += (row.f_percentage / 100) * row.f_color; // For 8.6 Pt wort.
223 }
224 if (fermentableInit) {
225 if (row.f_added == 4) {
226 $("#bottle_priming_total").val(row.f_amount * 1000); // Prevent clearing
227 $("#bottle_priming_sugar").jqxDropDownList('selectItem', row.f_name);
228 }
229 if (row.f_added == 5) {
230 $("#keg_priming_total").val(row.f_amount * 1000);
231 $("#keg_priming_sugar").jqxDropDownList('selectItem', row.f_name);
232 }
233 }
234 // Check supplies.
235 if ((((dataRecord.inventory_reduced <= 2) && (row.f_added <= 1)) || // Mash or boil
236 ((dataRecord.inventory_reduced <= 3) && (row.f_added == 2)) || // Primary
237 ((dataRecord.inventory_reduced <= 5) && (row.f_added == 3)) || // Secondary or Tertiary
238 ((dataRecord.inventory_reduced <= 6) && (row.f_added == 4)) || // Bottle
239 ((dataRecord.inventory_reduced <= 6) && (row.f_added == 5))) && row.f_inventory < row.f_amount) {
240 ok_fermentables = 0;
241 }
242 if (row.f_added == 0 && (row.f_type == 0 || row.f_type == 4) && row.f_color < 50) { // Mash and Grain/Adjunct and Color < 50
243 lintner += row.f_diastatic_power * row.f_amount;
244 }
245 }
246 fermentableInit = 0;
247 $("#ferm_lintner").val(Math.round(parseFloat(lintner / mashkg)));
248 $("#mash_kg").val(mashkg);
249 console.log("calcFermentables() supplies:"+ok_fermentables+" moutsuiker:"+sugarsm+"/"+sugarsf);
250 to_100 = my_100;
251 if (to_100) {
252 $("#wf_amount").jqxNumberInput({ width: 90, readOnly: true, spinButtons: false });
253 } else {
254 $("#wf_amount").jqxNumberInput({ width: 110, readOnly: false, spinButtons: true });
255 }
256
257 if (mvol > 0) {
258 var v = s / sugardensity + mvol;
259 s = 1000 * s / (v * 10); //deg. Plato
260 est_mash_sg = Math.round(plato_to_sg(s) * 10000) / 10000;
261 $('#est_mash_sg').val(est_mash_sg);
262 }
263
264 // Estimate total recipe OG.
265 dataRecord.est_og = estimate_sg(sugarsf + addedS, parseFloat(dataRecord.batch_size));
266 $('#est_og').val(dataRecord.est_og);
267 $('#est_og2').val(dataRecord.est_og);
268 var org = dataRecord.est_og;
269
270 // Estimate SG in kettle after boil
271 aboil_sg = estimate_sg(sugarsf, parseFloat(dataRecord.batch_size));
272 $('#est_og3').val(aboil_sg);
273
274 // Estimate SG in kettle before boil
275 preboil_sg = estimate_sg(sugarsm, parseFloat(dataRecord.boil_size));
276 $('#est_pre_sg').val(preboil_sg);
277
278 // Recalculate volumes.
279 var aboil_volume = parseFloat(dataRecord.batch_size);
280 if (dataRecord.brew_aboil_volume > 0)
281 aboil_volume = dataRecord.brew_aboil_volume / 1.04; // volume @ 20 degrees
282 if (dataRecord.brew_fermenter_tcloss == 0) {
283 dataRecord.brew_fermenter_tcloss = dataRecord.eq_trub_chiller_loss;
284 $("#brew_fermenter_tcloss").val(dataRecord.brew_fermenter_tcloss);
285 }
286 dataRecord.brew_fermenter_volume = aboil_volume - dataRecord.brew_fermenter_tcloss + dataRecord.brew_fermenter_extrawater;
287 $("#brew_fermenter_volume").val(dataRecord.brew_fermenter_volume);
288 // Estimated needed sparge water corrected for the temperature.
289 var spoelw = (dataRecord.boil_size - mash_infuse + (mashkg * my_grain_absorbtion) + dataRecord.eq_lauter_deadspace) * 1.03;
290 $("#brew_sparge_est").val(spoelw);
291
292 // Calculate SG in fermenter
293 var ogx = dataRecord.brew_aboil_sg;
294 if (ogx < 1.002)
295 ogx = aboil_sg;
296 var top = dataRecord.brew_fermenter_extrawater;
297
298 if (dataRecord.brew_fermenter_volume > 0) {
299 var sug = sg_to_plato(ogx) * dataRecord.brew_fermenter_volume * ogx / 100; //kg of sugar in
300 sug += addedS; //kg
301
302 if ((dataRecord.brew_fermenter_volume * ogx + addedmass) > 0) {
303 var pt = 100 * sug / (dataRecord.brew_fermenter_volume * ogx + addedmass + top);
304 dataRecord.brew_fermenter_sg = Round(plato_to_sg(pt),4);
305 $("#brew_fermenter_sg").val(dataRecord.brew_fermenter_sg);
306 // color
307 if (dataRecord.color_method == 4) {
308 dataRecord.brew_fermenter_color = Math.round(((pt / 8.6) * colorn) + (dataRecord.boil_time / 60));
309 } else if (dataRecord.color_method == 3) {
310 dataRecord.brew_fermenter_color = Math.round((4.46 * bv * sr) / (aboil_volume + top) * colorh);
311 } else {
312 var cw = colort / (aboil_volume + top) * 8.34436;
313 dataRecord.brew_fermenter_color = kw_to_ebc(dataRecord.color_method, cw);
314 }
315 $("#brew_fermenter_color").val(dataRecord.brew_fermenter_color);
316 var scolor = ebc_to_color(dataRecord.brew_fermenter_color);
317 $("#bcolorf").show();
318 document.getElementById("bcolorf").style.background= scolor;
319 }
320 } else {
321 // Negative volume
322 dataRecord.brew_fermenter_sg = dataRecord.brew_fermenter_color = 0;
323 $("#brew_fermenter_sg").val(0);
324 $("#brew_fermenter_color").val(0);
325 $("#bcolorf").hide();
326 }
327
328 // Color of the wort
329 if (dataRecord.color_method == 4) {
330 var color = Math.round(((sg_to_plato(dataRecord.est_og) / 8.6) * colorn) + (dataRecord.boil_time / 60));
331 } else if (dataRecord.color_method == 3) { // Hans Halberstadt
332 var color = Math.round((4.46 * bv * sr) / parseFloat(dataRecord.batch_size) * colorh);
333 } else {
334 var cw = colort / parseFloat(dataRecord.batch_size) * 8.34436;
335 var color = kw_to_ebc(dataRecord.color_method, cw);
336 }
337 dataRecord.est_color = color;
338 $('#est_color').val(color);
339 $('#est_color2').val(color);
340 var scolor = ebc_to_color(color);
341 document.getElementById("bcolor").style.background= scolor;
342 document.getElementById("bcolor2").style.background= scolor;
343
344 // Progress bars
345 pmalts = mashkg / dataRecord.eq_mash_max * 100;
346 $("#perc_malts").jqxProgressBar('val', pmalts);
347 $("#perc_sugars").jqxProgressBar('val', psugar);
348 $("#perc_cara").jqxProgressBar('val', pcara);
349 calcStage();
350
351 // Calculate estimated svg.
352 svg = 0; // default.
353 initcells = 0;
354 var rows = $('#yeastGrid').jqxGrid('getrows');
355 for (var i = 0; i < rows.length; i++) {
356 var row = rows[i];
357 if (row.y_use == 0) { // Primary
358 if (parseFloat(row.y_attenuation) > svg)
359 svg = parseFloat(row.y_attenuation); // Take the highest if multiple yeasts.
360 if (row.y_form == 0)
361 initcells += (parseFloat(row.y_cells) / 1000000000) * parseFloat(row.y_amount) * (dataRecord.starter_viability / 100);
362 else
363 initcells += (parseFloat(row.y_cells) / 1000000) * parseFloat(row.y_amount);
364 }
365 // TODO: brett in secondary ??
366 if ((((dataRecord.inventory_reduced <= 3) && (row.y_use == 0)) || // Primary
367 ((dataRecord.inventory_reduced <= 4) && (row.y_use == 1)) || // Secondary
368 ((dataRecord.inventory_reduced <= 5) && (row.y_use == 2)) || // Tertiary
369 ((dataRecord.inventory_reduced <= 6) && (row.y_use == 3))) && // Bottle
370 (row.y_inventory < row.y_amount)) {
371 ok_yeasts = 0;
372 }
373 }
374 calcSupplies();
375 if (svg == 0)
376 svg = 77;
377
378 if ((mashkg > 0) && (mash_infuse > 0) && (mashtime > 0) && (mashtemp > 0)) {
379 dataRecord.est_fg = estimate_fg(psugar, pcara, mash_infuse / mashkg, mashtime, mashtemp, svg, dataRecord.est_og);
380 } else {
381 dataRecord.est_fg = estimate_fg(psugar, pcara, 0, 0, 0, svg, dataRecord.est_og);
382 }
383 $('#est_fg').val(dataRecord.est_fg);
384 $('#est_fg2').val(dataRecord.est_fg);
385 $('#est_fg3').val(dataRecord.est_fg);
386 var fig = dataRecord.est_fg;
387
388 dataRecord.est_abv = abvol(dataRecord.est_og, dataRecord.est_fg);
389 $("#est_abv").val(dataRecord.est_abv);
390 $("#est_abv2").val(dataRecord.est_abv);
391
392 // Calculate the final svg if available use the real value.
393 if ((dataRecord.stage >= 6) && (dataRecord.fg > 0.990) && (dataRecord.fg < dataRecord.brew_fermenter_sg)) {
394 svg = 100 * (dataRecord.brew_fermenter_sg - dataRecord.fg) / (dataRecord.brew_fermenter_sg - 1);
395 org = dataRecord.brew_fermenter_sg;
396 fig = dataRecord.fg;
397 }
398
399 $("#yeast_cells").val(initcells);
400 $("#need_cells").val(getNeededYeastCells());
401
402 // Calculate the calories in kcal/l (from brouwhulp)
403 var alc = 1881.22 * fig * (org - fig) / (1.775 - org);
404 var sug = 3550 * fig * (0.1808 * org + 0.8192 * fig - 1.0004);
405 $("#kcal").val(Math.round((alc + sug) / (12 * 0.0295735296)));
406 };
407
408 function calcMash() {
409
410 if (!(rows = $('#mashGrid').jqxGrid('getrows')))
411 return;
412 if (mashkg == 0)
413 return;
414
415 var infused = 0;
416 for (var i = 0; i < rows.length; i++) {
417 var row = $("#mashGrid").jqxGrid('getrowdata', i);
418 if (row.step_type == 0) // Infusion
419 infused += row.step_infuse_amount;
420 $("#mashGrid").jqxGrid('setcellvalue', i, "step_thickness", infused / mashkg);
421 }
422 }
423
424 /*
425 * Change OG of recipe but keep the water volumes.
426 */
427 function calcFermentablesFromOG(OG) {
428
429 console.log("calcFermentablesFromOG("+OG+")");
430 var efficiency = parseFloat($("#efficiency").jqxNumberInput('decimal'));
431 var sug = sg_to_plato(OG) * parseFloat($("#batch_size").jqxNumberInput('decimal')) * OG / 100; //total amount of sugars in kg
432 var tot = 0;
433 var rowscount = $("#fermentableGrid").jqxGrid('getdatainformation').rowscount;
434
435 for (var i = 0; i < rowscount; i++) {
436 var row = $("#fermentableGrid").jqxGrid('getrowdata', i);
437 if (row.f_added < 4) {
438 var d = row.f_percentage / 100 * (row.f_yield / 100) * (1 - row.f_moisture / 100);
439 if (row.f_added == 0) // Mash
440 d = efficiency / 100 * d;
441 tot += d;
442 }
443 }
444 var totmass = 0;
445 if (tot)
446 totmass = Math.round((sug / tot) * 1000) / 1000;
447
448 if (totmass) {
449 for (i = 0; i < rowscount; i++) {
450 var row = $("#fermentableGrid").jqxGrid('getrowdata', i);
451 if (row.f_added < 4) {
452 var amount = Math.round(row.f_percentage * 10 * totmass) / 1000;
453 $("#fermentableGrid").jqxGrid('setcellvalue', i, "f_amount", amount);
454 }
455 }
456 }
457 };
458
459 function getNeededYeastCells() {
460
461 var sg = dataRecord.brew_fermenter_sg;
462 if (sg <= 1.0001 && dataRecord.fg > 1.000)
463 sg = dataRecord.fg;
464 else if (sg <= 1.0001)
465 sg = dataRecord.est_og;
466 var plato = sg_to_plato(sg);
467
468 var volume = dataRecord.brew_fermenter_volume;
469 if (volume <= 0)
470 volume = dataRecord.batch_size - dataRecord.eq_trub_chiller_loss;
471
472 var result = pitchrate * volume * plato;
473 return result;
474 }
475
476 function hopFlavourContribution(bt, vol, use, amount) {
477 var result;
478
479 if (use == 1) { // First wort
480 result = 0.15; // assume 15% flavourcontribution for fwh
481 } else if (bt > 50) {
482 result = 0.10; // assume 10% flavourcontribution as a minimum
483 } else {
484 result = 15.25 / (6 * Math.sqrt(2 * Math.PI)) * Math.exp(-0.5 * Math.pow((bt - 21) /6, 2));
485 if (result < 0.10)
486 result = 0.10; // assume 10% flavourcontribution as a minimum
487 }
488 return (result * amount * 1000) / vol;
489 }
490
491 function hopAromaContribution(bt, vol, use, amount) {
492 var result = 0;
493
494 if (use == 5) { // Dry hop
495 result = 1.33;
496 } else if (bt > 20) {
497 result = 0;
498 } else if (bt > 7.5) {
499 result = 10.03 / (4 * Math.sqrt(2 * Math.PI)) * Math.exp(-0.5 * Math.pow((bt - 7.5) /4, 2));
500 } else if (use == 2) { // Boil
501 result = 1;
502 } else if (use == 3) { // Aroma
503 result = 1.2;
504 } else if (use == 4) { // Whirlpool
505 result = 1.2;
506 }
507 return (result * amount * 1000) / vol;
508 }
509
510 function calcIBUs() {
511 var total_ibus = 0;
512 var ferm_ibus = 0;
513 var rows = {};
514 hop_aroma = hop_flavour = 0;
515 if (!(rows = $('#hopGrid').jqxGrid('getrows'))) {
516 return;
517 }
518 ok_hops = 1;
519 for (var i = 0; i < rows.length; i++) {
520 var row = rows[i];
521 total_ibus += toIBU(row.h_useat, row.h_form, preboil_sg, parseFloat(dataRecord.batch_size),
522 parseFloat(row.h_amount), parseFloat(row.h_time), parseFloat(row.h_alpha), dataRecord.ibu_method);
523 ferm_ibus += toIBU(row.h_useat, row.h_form, preboil_sg,
524 parseFloat(dataRecord.brew_fermenter_volume) + parseFloat(dataRecord.brew_fermenter_tcloss),
525 parseFloat(row.h_amount), parseFloat(row.h_time), parseFloat(row.h_alpha), dataRecord.ibu_method);
526 hop_flavour += hopFlavourContribution(parseFloat(row.h_time), parseFloat(dataRecord.batch_size),
527 row.h_useat, parseFloat(row.h_amount));
528 hop_aroma += hopAromaContribution(parseFloat(row.h_time), parseFloat(dataRecord.batch_size),
529 row.h_useat, parseFloat(row.h_amount));
530 if ((((dataRecord.inventory_reduced <= 2) && (row.h_useat <= 4)) || // Mash, FW, Boil, Aroma, Whirlpool
531 ((dataRecord.inventory_reduced <= 6) && (row.h_useat == 5))) && // Dry-hop
532 (row.h_inventory < row.h_amount))
533 ok_hops = 0;
534 }
535 total_ibus = Math.round(total_ibus * 10) / 10;
536 ferm_ibus = Math.round(ferm_ibus * 10) / 10;
537 hop_flavour = Math.round(hop_flavour * 1000 / 5) / 10;
538 hop_aroma = Math.round(hop_aroma * 1000 / 6) / 10;
539 if (hop_flavour > 100)
540 hop_flavour = 100;
541 if (hop_aroma > 100)
542 hop_aroma = 100;
543 console.log("calcIBUs(): " + total_ibus + " flavour: " + hop_flavour + " aroma: " + hop_aroma+" fermenter:"+ferm_ibus+" supplies:"+ok_hops);
544 dataRecord.est_ibu = total_ibus;
545 $('#est_ibu').val(total_ibus);
546 $('#est_ibu2').val(total_ibus);
547 $("#hop_flavour").jqxProgressBar('val', hop_flavour);
548 $("#hop_aroma").jqxProgressBar('val', hop_aroma);
549 $("#brew_fermenter_ibu").val(ferm_ibus);
550 calcStage();
551 calcSupplies();
552 };
553
554 /*
555 * http://braukaiser.com/blog/blog/2012/11/03/estimating-yeast-growth/
556 *
557 * stype: 0=stirred, 1=shaken, 2=simple
558 * totcells: initial cells
559 * egrams: gram extract
560 */
561 function getGrowthRate(stype, totcells, egrams){
562
563 /* Cells per grams extract (B/g) */
564 var cpe = totcells / egrams;
565
566 if (cpe > 3.5)
567 return 0; // no growth
568 if (stype == 2)
569 return 0.4; // simple starter
570 if (stype == 1)
571 return 0.62; // shaken starter
572 if (cpe <= 1.4) // stirred starter
573 return 1.4;
574 return 2.33 - (.67 * cpe );
575 };
576
577 function calcStep(svol, stype, start) {
578
579 var gperpoint = 2.72715; //number of grams of extract per point of starter gravity per liter
580 var prate = start/svol * 1000;
581 var irate = Math.round(prate * 10) / 10;
582 var egrams = (dataRecord.starter_sg - 1) * svol * gperpoint;
583 var grate = getGrowthRate(stype, start, egrams);
584 var ncells = Math.round(egrams * grate * 10) / 10;
585 var totcells = parseFloat(ncells) + start;
586 console.log("svol:"+svol+" start:"+start+" irate:"+irate+" egrams:"+egrams+" grate:"+grate+" ncells:"+ncells);
587 return {
588 svol: svol,
589 irate: irate,
590 prate: Math.round(prate * 10)/10,
591 ncells: ncells,
592 totcells: totcells,
593 growf: Math.round(ncells/start*100)/100
594 };
595 }
596
597 /*
598 * Calculate all starter steps.
599 * stype: final starter type: 0 = stirred, 1 = shaked, 2 = simple.
600 * start: initial cells in billions
601 * needed: needed cells in billions
602 *
603 * result: all values updated.
604 */
605 function calcSteps(stype, start, needed) {
606
607 var uvols = [ 20, 40, 60, 80, 100, 150, 200, 250, 375, 500, 625, 750, 875, 1000, 1250, 1500, 2000, 2500, 3000, 4000, 5000 ];
608 var mvols = uvols.length;
609 var svol = 0;
610 var lasti = 0;
611 var result = {};
612
613 /*
614 * If no values are set, auto calculate the starter.
615 */
616 if ((parseFloat($("#prop1_volume").jqxNumberInput('decimal')) + parseFloat($("#prop2_volume").jqxNumberInput('decimal')) +
617 parseFloat($("#prop3_volume").jqxNumberInput('decimal')) + parseFloat($("#prop4_volume").jqxNumberInput('decimal'))) == 0) {
618 // clear by default
619 for (var i = 1; i < 5; i++) {
620 $("#prop"+i+"_type").hide();
621 $("#r"+i+"_pmpt").show();
622 $("#prop"+i+"_type").val(stype);
623 $("#prop"+i+"_volume").hide();
624 $("#prop"+i+"_volume").val(0);
625 $("#prop"+i+"_irate").hide();
626 $("#prop"+i+"_ncells").hide();
627 $("#prop"+i+"_tcells").hide();
628 $("#prop"+i+"_growf").hide();
629 }
630 if (start > needed) {
631 return; // no starter needed
632 }
633 $("#prop1_type").show();
634 $("#r1_pmpt").hide();
635 $("#prop1_volume").show();
636 $("#prop1_irate").show();
637 $("#prop1_ncells").show();
638 $("#prop1_tcells").show();
639 $("#prop1_growf").show();
640 for (var i = lasti; i <= mvols; i++) {
641 lasti = i;
642 svol = uvols[lasti];
643 result = calcStep(svol, stype, start);
644 if (result.irate < 25) {
645 // inocculation rate too low, backup one step and break out.
646 lasti = i - 1;
647 svol = uvols[lasti];
648 result = calcStep(svol, stype, start);
649 break;
650 }
651 if (result.totcells > needed || i == mvols) { // hit the target or loops done
652 break;
653 }
654 }
655 $("#prop1_volume").val(result.svol / 1000); // to liters
656 $("#prop1_irate").val(result.prate);
657 $("#prop1_ncells").val(result.ncells);
658 $("#prop1_tcells").val(result.totcells);
659 $("#prop1_growf").val(result.growf);
660 if (result.totcells > needed)
661 return; // hit the target
662
663 // second stage
664 $("#r2_pmpt").hide();
665 $("#prop2_type").val(stype);
666 $("#prop2_type").show();
667 $("#prop2_volume").show();
668 $("#prop2_irate").show();
669 $("#prop2_ncells").show();
670 $("#prop2_tcells").show();
671 $("#prop2_growf").show();
672 for (var i = lasti; i <= mvols; i++) {
673 lasti = i;
674 svol = uvols[lasti];
675 result = calcStep(svol, stype, $("#prop1_tcells").val());
676 if (result.irate < 25) {
677 lasti = i - 1;
678 svol = uvols[lasti];
679 result = calcStep(svol, stype, $("#prop1_tcells").val());
680 break;
681 }
682 if (result.totcells > needed || i == mvols) { // hit the target or loops done
683 break;
684 }
685 }
686 $("#prop2_volume").val(result.svol / 1000); // to liters
687 $("#prop2_irate").val(result.prate);
688 $("#prop2_ncells").val(result.ncells);
689 $("#prop2_tcells").val(result.totcells);
690 $("#prop2_growf").val(result.growf);
691 if (result.totcells > needed)
692 return; // hit the target
693
694 // third stage
695 $("#r3_pmpt").hide();
696 $("#prop3_type").val(stype);
697 $("#prop3_type").show();
698 $("#prop3_volume").show();
699 $("#prop3_irate").show();
700 $("#prop3_ncells").show();
701 $("#prop3_tcells").show();
702 $("#prop3_growf").show();
703 for (var i = lasti; i <= mvols; i++) {
704 lasti = i;
705 svol = uvols[lasti];
706 result = calcStep(svol, stype, $("#prop2_tcells").val());
707 if (result.irate < 25) {
708 lasti = i - 1;
709 svol = uvols[lasti];
710 result = calcStep(svol, stype, $("#prop2_tcells").val());
711 break;
712 }
713 if (result.totcells > needed || i == mvols) { // hit the target or loops done
714 break;
715 }
716 }
717 $("#prop3_volume").val(result.svol / 1000); // to liters
718 $("#prop3_irate").val(result.prate);
719 $("#prop3_ncells").val(result.ncells);
720 $("#prop3_tcells").val(result.totcells);
721 $("#prop3_growf").val(result.growf);
722 if (result.totcells > needed)
723 return; // hit the target
724
725 // fourth stage
726 $("#r4_pmpt").hide();
727 $("#prop4_type").val(stype);
728 $("#prop4_type").show();
729 $("#prop4_volume").show();
730 $("#prop4_irate").show();
731 $("#prop4_ncells").show();
732 $("#prop4_tcells").show();
733 $("#prop4_growf").show();
734 for (var i = lasti; i <= mvols; i++) {
735 lasti = i;
736 svol = uvols[lasti];
737 result = calcStep(svol, stype, $("#prop3_tcells").val());
738 if (result.totcells > needed || i == mvols) { // hit the target or loops done
739 $("#prop4_volume").val(result.svol / 1000); // to liters
740 $("#prop4_irate").val(result.prate);
741 $("#prop4_ncells").val(result.ncells);
742 $("#prop4_tcells").val(result.totcells);
743 $("#prop4_growf").val(result.growf);
744 return;
745 }
746 }
747 } else {
748 // recalculate
749 if (dataRecord.prop1_volume > 0) {
750 $("#r1_pmpt").hide();
751 $("#prop1_type").show();
752 $("#prop1_volume").show();
753 $("#prop1_irate").show();
754 $("#prop1_ncells").show();
755 $("#prop1_tcells").show();
756 $("#prop1_growf").show();
757 result = calcStep($("#prop1_volume").val() * 1000, dataRecord.prop1_type, start);
758 $("#prop1_irate").val(result.prate);
759 $("#prop1_ncells").val(result.ncells);
760 $("#prop1_tcells").val(result.totcells);
761 $("#prop1_growf").val(result.growf);
762 }
763 if (dataRecord.prop2_volume > 0) {
764 $("#r2_pmpt").hide();
765 $("#prop2_type").show();
766 $("#prop2_volume").show();
767 $("#prop2_irate").show();
768 $("#prop2_ncells").show();
769 $("#prop2_tcells").show();
770 $("#prop2_growf").show();
771 result = calcStep($("#prop2_volume").val() * 1000, dataRecord.prop2_type, $("#prop1_tcells").val());
772 $("#prop2_irate").val(result.prate);
773 $("#prop2_ncells").val(result.ncells);
774 $("#prop2_tcells").val(result.totcells);
775 $("#prop2_growf").val(result.growf);
776 }
777 if (dataRecord.prop3_volume > 0) {
778 $("#r3_pmpt").hide();
779 $("#prop3_type").show();
780 $("#prop3_volume").show();
781 $("#prop3_irate").show();
782 $("#prop3_ncells").show();
783 $("#prop3_tcells").show();
784 $("#prop3_growf").show();
785 result = calcStep($("#prop3_volume").val() * 1000, dataRecord.prop3_type, $("#prop2_tcells").val());
786 $("#prop3_irate").val(result.prate);
787 $("#prop3_ncells").val(result.ncells);
788 $("#prop3_tcells").val(result.totcells);
789 $("#prop3_growf").val(result.growf);
790 }
791 if (dataRecord.prop4_volume > 0) {
792 $("#r4_pmpt").hide();
793 $("#prop4_type").show();
794 $("#prop4_volume").show();
795 $("#prop4_irate").show();
796 $("#prop4_ncells").show();
797 $("#prop4_tcells").show();
798 $("#prop4_growf").show();
799 result = calcStep($("#prop4_volume").val() * 1000, dataRecord.prop4_type, $("#prop3_tcells").val());
800 $("#prop4_irate").val(result.prate);
801 $("#prop4_ncells").val(result.ncells);
802 $("#prop4_tcells").val(result.totcells);
803 $("#prop4_growf").val(result.growf);
804 }
805
806 }
807 }
808
809 function calcYeast() {
810
811 // Calculate needed cells.
812 var sg = dataRecord.brew_fermenter_sg;
813 if (sg <= 1.0001 && dataRecord.fg > 1.000)
814 sg = dataRecord.fg;
815 else if (sg <= 1.0001)
816 sg = dataRecord.est_og;
817 var plato = sg_to_plato(sg);
818
819 var volume = dataRecord.brew_fermenter_volume;
820 if (volume > 0) {
821 if (dataRecord.brew_fermenter_extrawater > 0)
822 volume += dataRecord.brew_fermenter_extrawater;
823 } else {
824 volume = dataRecord.batch_size - dataRecord.eq_trub_chiller_loss;
825 }
826
827 // Also in calcFermentables()
828 $("#yeast_cells").val(initcells);
829
830 if (!(rows = $('#yeastGrid').jqxGrid('getrows'))) {
831 return; // grid not yet loaded.
832 }
833 var rowscount = $("#yeastGrid").jqxGrid('getdatainformation').rowscount;
834 if (rowscount == 0)
835 return; // no yeast in recipe
836
837 for (var i = 0; i < rowscount; i++) {
838 var row = $("#yeastGrid").jqxGrid('getrowdata', i);
839 if (row.y_use == 0) { // primary
840 // pitchrate see https://www.brewersfriend.com/yeast-pitch-rate-and-starter-calculator/
841 // and http://braukaiser.com/blog/blog/2012/11/03/estimating-yeast-growth/
842 pitchrate = 0.75;
843 if (dataRecord.est_og > 1.060)
844 pitchrate = 1.0;
845 // if (dataRecord.est_og > 1.076)
846 // pitchrate = 1.25; // Wyeast labs. http://www.wyeastlab.com/hb_pitchrates.cfm
847 if (row.y_type == 0) // lager yeast
848 pitchrate *= 2;
849
850 if (row.y_form == 1) { // dry yeast
851 } else { // possible starter needed
852 }
853 }
854 }
855 var needed = pitchrate * volume * plato;
856 console.log("calcYeast() pitchrate:"+pitchrate+" start:"+initcells+" needed:"+needed+" volume:"+volume);
857 $("#need_cells").val(needed);
858 var use_cells = initcells;
859
860 if (dataRecord.starter_enable) {
861 calcSteps(dataRecord.starter_type, initcells, needed);
862
863 for (var i = 1; i < 5; i++) {
864 $("#r"+i+"_irate").html("");
865 $("#r"+i+"_growf").html("");
866 $("#r"+i+"_tcells").html("");
867 if (parseFloat($("#prop"+i+"_volume").val()) > 0) {
868 if ((parseFloat($("#prop"+i+"_irate").val()) < 25) || (parseFloat($("#prop"+i+"_irate").val()) > 100)) {
869 $("#r"+i+"_irate").html("<img src='images/dialog-error.png'>");
870 } else {
871 $("#r"+i+"_irate").html("<img src='images/dialog-ok-apply.png'>");
872 }
873 if (parseFloat($("#prop"+i+"_growf").val()) < 1)
874 $("#r"+i+"_growf").html("<img src='images/dialog-error.png'>");
875 if (($("#prop"+i+"_type").val() > 0) && (parseFloat($("#prop"+i+"_growf").val()) > 3))
876 $("#r"+i+"_growf").html("<img src='images/dialog-error.png'>");
877 if (parseFloat($("#prop"+i+"_tcells").val()) > needed)
878 $("#r"+i+"_tcells").html("<img src='images/dialog-ok-apply.png'>");
879 use_cells = parseFloat($("#prop"+i+"_tcells").val());
880 } else {
881 $("#r"+i+"_irate").html("");
882 }
883 }
884 }
885 $("#plato_cells").val(parseFloat(use_cells / (volume * plato) ));
886 };
887
888 function adjustHops(factor) {
889
890 console.log("adjustHops("+factor+")");
891
892 var rowscount = $("#hopGrid").jqxGrid('getdatainformation').rowscount;
893 if (rowscount == 0)
894 return;
895
896 for (var i = 0; i < rowscount; i++) {
897 var row = $("#hopGrid").jqxGrid('getrowdata', i);
898 var amount = row.h_amount * factor;
899 $("#hopGrid").jqxGrid('setcellvalue', i, "h_amount", amount);
900 }
901 };
902
903 function calcMiscs() {
904
905 ok_miscs = 1;
906 var rowscount = $("#miscGrid").jqxGrid('getdatainformation').rowscount;
907
908 if (rowscount == 0)
909 return;
910
911 for (var i = 0; i < rowscount; i++) {
912 var row = $("#miscGrid").jqxGrid('getrowdata', i);
913 if ((((dataRecord.inventory_reduced <= 2) && (row.m_use_use <= 2)) || // Starter, Mash, Boil
914 ((dataRecord.inventory_reduced <= 3) && (row.m_use_use == 3)) || // Primary
915 ((dataRecord.inventory_reduced <= 5) && (row.m_use_use == 4)) || // Secondary, Teriary
916 ((dataRecord.inventory_reduced <= 6) && (row.m_use_use == 5))) && // Bottle
917 (row.m_inventory < row.m_amount)) {
918 ok_miscs = 0;
919 }
920 }
921 calcSupplies();
922 };
923
924 function adjustMiscs(factor) {
925
926 console.log("adjustMiscs("+factor+")");
927
928 var rowscount = $("#miscGrid").jqxGrid('getdatainformation').rowscount;
929 if (rowscount == 0)
930 return;
931
932 for (var i = 0; i < rowscount; i++) {
933 var row = $("#miscGrid").jqxGrid('getrowdata', i);
934 var amount = row.m_amount * factor;
935 $("#miscGrid").jqxGrid('setcellvalue', i, "m_amount", amount);
936 switch (row.m_name) {
937 case 'CaCl2': $("#wa_cacl2").val(row.m_amount * 1000);
938 break;
939 case 'CaSO4': $("#wa_caso4").val(row.m_amount * 1000);
940 break;
941 case 'MgSO4': $("#wa_mgso4").val(row.m_amount * 1000);
942 break;
943 case 'NaCl': $("#wa_nacl").val(row.m_amount * 1000);
944 break;
945 case 'Melkzuur':
946 case 'Zoutzuur':
947 case 'Fosforzuur':
948 case 'Zwavelzuur': $("#wa_acid").val(row.m_amount * 1000);
949 break;
950 case 'NaHCO3':
951 case 'Na2CO3':
952 case 'CaCO3':
953 case 'Ca(OH)2': $("#wa_base").val(row.m_amount * 1000);
954 break;
955 }
956 }
957 };
958
959 function adjustYeasts(factor) {
960
961 console.log("adjustYeasts("+factor+")");
962
963 var rowscount = $("#yeastGrid").jqxGrid('getdatainformation').rowscount;
964 if (rowscount == 0)
965 return;
966
967 for (var i = 0; i < rowscount; i++) {
968 var row = $("#yeastGrid").jqxGrid('getrowdata', i);
969 if (row.y_form == 1) { // Only adjust dry yeast
970 var amount = row.y_amount * factor;
971 $("#yeastGrid").jqxGrid('setcellvalue', i, "y_amount", amount);
972 }
973 }
974
975 calcYeast();
976 };
977
978 function adjustWaters(factor) {
979
980 console.log("adjustWaters("+factor+")");
981
982 var rowscount = $("#mashGrid").jqxGrid('getdatainformation').rowscount;
983 if (rowscount == 0)
984 return;
985
986 mash_infuse = 0;
987 for (var i = 0; i < rowscount; i++) {
988 var row = $("#mashGrid").jqxGrid('getrowdata', i);
989 if (row.step_type == 0) { // Infusion
990 var amount = Math.round(row.step_infuse_amount * factor * 10) / 10;
991 $("#mashGrid").jqxGrid('setcellvalue', i, "step_infuse_amount", amount);
992 mash_infuse += amount;
993 }
994 }
995 if (dataRecord.w2_amount == 0) {
996 dataRecord.w1_amount = mash_infuse;
997 $("#w1_amount").val(mash_infuse);
998 } else {
999 dataRecord.w1_amount = (dataRecord.w1_amount / (dataRecord.w1_amount + dataRecord.w2_amount)) * mash_infuse;
1000 dataRecord.w2_amount = (dataRecord.w2_amount / (dataRecord.w1_amount + dataRecord.w2_amount)) * mash_infuse;
1001 $("#w1_amount").val(dataRecord.w1_amount);
1002 $("#w2_amount").val(dataRecord.w2_amount);
1003 }
1004 $('#wg_amount').val(mash_infuse);
1005 };
1006
1007
1008
1009 function calcMashEfficiency() {
1010 if (parseFloat($("#brew_mash_sg").jqxNumberInput('decimal')) < 1.002)
1011 return;
1012 var c = sg_to_plato(est_mash_sg);
1013 var m = sg_to_plato(parseFloat($("#brew_mash_sg").jqxNumberInput('decimal')));
1014 if (c > 0.5)
1015 $("#brew_mash_efficiency").val(100 * m / c);
1016 else
1017 $("#brew_mash_efficiency").val(0);
1018 };
1019
1020 function calcEfficiencyBeforeBoil() {
1021 var m = 0;
1022 var rows = {};
1023 if (!(rows = $('#fermentableGrid').jqxGrid('getrows'))) {
1024 return; // grid not yet loaded.
1025 }
1026 for (var i = 0; i < rows.length; i++) {
1027 var row = rows[i];
1028 if (row.f_added == 0) { // Mash
1029 m += row.f_amount * (row.f_yield / 100) * (1 - row.f_moisture / 100);
1030 }
1031 }
1032 var tot = sg_to_plato(dataRecord.brew_preboil_sg) * (dataRecord.brew_preboil_volume / 1.04) * dataRecord.brew_preboil_sg * 10 / 1000;
1033 var result = 0;
1034 if (m > 0)
1035 result = Math.round((tot / m * 100) * 10) / 10;
1036 if (result < 0)
1037 result = 0;
1038 $("#brew_preboil_efficiency").val(result);
1039 }
1040
1041 function calcEfficiencyAfterBoil() {
1042 var m = 0; // Sugars added at mash
1043 var b = 0; // Sugars added at boil
1044 var rows = {};
1045 if (!(rows = $('#fermentableGrid').jqxGrid('getrows'))) {
1046 return; // grid not yet loaded.
1047 }
1048 for (var i = 0; i < rows.length; i++) {
1049 var row = rows[i];
1050 if (row.f_added == 0) { // Mash
1051 m += row.f_amount * (row.f_yield / 100) * (1 - row.f_moisture / 100);
1052 } else if (row.f_added == 1) { // Boil
1053 b += row.f_amount * (row.f_yield / 100) * (1 - row.f_moisture / 100);
1054 }
1055 }
1056 var tot = sg_to_plato(dataRecord.brew_aboil_sg) * (dataRecord.brew_aboil_volume / 1.04) * dataRecord.brew_aboil_sg * 10 / 1000;
1057 tot -= b; // total sugars in wort minus added sugars.
1058 var result = 0;
1059 if (m > 0)
1060 result = Math.round((tot / m * 100) * 10) / 10;
1061 if (result < 0)
1062 result = 0;
1063 dataRecord.brew_aboil_efficiency = result;
1064 $("#brew_aboil_efficiency").val(result);
1065
1066 }
1067
1068 function GetBUGU() {
1069 var gu = (dataRecord.est_og - 1) * 1000;
1070 if (gu > 0)
1071 return dataRecord.est_ibu / gu;
1072 else
1073 return 0.5;
1074 }
1075
1076 function GetOptClSO4ratio() {
1077 var BUGU = GetBUGU();
1078 return (-1.2 * BUGU + 1.4);
1079 }
1080
1081 function setWaterAgent(name, amount) {
1082 var rows = $('#miscGrid').jqxGrid('getrows');
1083 if (amount == 0) {
1084 for (var i = 0; i < rows.length; i++) {
1085 var row = rows[i];
1086 if (row.m_name == name) {
1087 var id = $("#miscGrid").jqxGrid('getrowid', i);
1088 $("#miscGrid").jqxGrid('deleterow', id);
1089 }
1090 }
1091 } else {
1092 var found = false;
1093 for (var i = 0; i < rows.length; i++) {
1094 var row = rows[i];
1095 if (row.m_name == name) {
1096 found = true;
1097 $("#miscGrid").jqxGrid('setcellvalue', i, 'm_amount', amount / 1000);
1098 break;
1099 }
1100 }
1101 if (! found) {
1102 var miscs = new $.jqx.dataAdapter(miscInvSource, {
1103 loadComplete: function () {
1104 var records = miscs.records;
1105 for (var i = 0; i < records.length; i++) {
1106 var record = records[i];
1107 if (record.name == name) {
1108 var row = {};
1109 row["m_name"] = record.name;
1110 row["m_amount"] = amount / 1000;
1111 row["m_cost"] = record.cost;
1112 row["m_type"] = record.type;
1113 row["m_use_use"] = record.use_use;
1114 row["m_time"] = 0;
1115 row["m_amount_is_weight"] = record.amount_is_weight;
1116 row["m_inventory"] = record.inventory;
1117 row["m_avail"] = 1;
1118 $("#miscGrid").jqxGrid('addrow', null, row);
1119 }
1120 }
1121 }
1122 });
1123 miscs.dataBind();
1124 return;
1125 }
1126 }
1127 }
1128
1129 function setRangeIndicator(ion, rangeCode) {
1130 if ((rangeCode == "laag") || (rangeCode == "hoog"))
1131 $("#wr_"+ion).html("<img src='images/dialog-error.png'><span style='vertical-align: top; font-size: 10px; font-style: italic;'>"+rangeCode + "</span>");
1132 else
1133 $("#wr_"+ion).html("<img src='images/dialog-ok-apply.png'>");
1134 }
1135
1136 function mix(v1, v2, c1, c2) {
1137 if ((v1 + v2) > 0) {
1138 return ((v1 * c1) + (v2 * c2)) / (v1 + v2);
1139 }
1140 return 0;
1141 }
1142
1143 // mg/l as CaCO3
1144 function ResidualAlkalinity(total_alkalinity, calcium, magnesium) {
1145 return total_alkalinity - (calcium / 1.4 + magnesium / 1.7);
1146 }
1147
1148 var Ka1 = 0.0000004445;
1149 var Ka2 = 0.0000000000468;
1150
1151 function PartCO3(pH) {
1152 var H = Math.pow(10, -pH);
1153 return 100 * Ka1 * Ka2 / (H*H + H * Ka1 + Ka1 * Ka2);
1154 }
1155
1156 function PartHCO3(pH) {
1157 var H = Math.pow(10, -pH);
1158 return 100 * Ka1 * H / (H*H + H * Ka1 + Ka1 * Ka2);
1159 }
1160
1161 function Charge(pH) {
1162 return (-2 * PartCO3(pH) - PartHCO3(pH));
1163 }
1164
1165 //Z alkalinity is the amount of acid (in mEq/l) needed to bring water to the target pH (Z pH)
1166 function ZAlkalinity(pHZ) {
1167 var C43 = Charge(4.3);
1168 var Cw = Charge(parseFloat($("#wg_ph").jqxNumberInput('decimal')));
1169 var Cz = Charge(pHZ);
1170 var DeltaCNaught = -C43+Cw;
1171 var CT = parseFloat($("#wg_total_alkalinity").jqxNumberInput('decimal')) / 50 / DeltaCNaught;
1172 var DeltaCZ = -Cz+Cw;
1173 return CT * DeltaCZ;
1174 }
1175
1176 //Z Residual alkalinity is the amount of acid (in mEq/l) needed to bring the water in the mash to the target pH (Z pH)
1177 function ZRA(pHZ) {
1178
1179 var Calc = parseFloat($("#wg_calcium").jqxNumberInput('decimal')) / (MMCa / 2);
1180 var Magn = parseFloat($("#wg_magnesium").jqxNumberInput('decimal')) / (MMMg / 2);
1181 var Z = ZAlkalinity(pHZ);
1182 return Z - (Calc / 3.5 + Magn / 7);
1183 }
1184
1185 function ProtonDeficit(pHZ) {
1186
1187 var Result = ZRA(pHZ) * parseFloat($("#wg_amount").jqxNumberInput('decimal'));
1188 // proton deficit for the grist
1189 var rows = $('#fermentableGrid').jqxGrid('getrows');
1190 for (var i = 0; i < rows.length; i++) {
1191 var row = rows[i];
1192 if (row.f_added == 0 && row.f_graintype != 6) { // Added == Mash && graintype != No Malt
1193 // Check if acid is required
1194 var C1 = 0;
1195 if ((row.f_di_ph != 5.7) && ((row.f_acid_to_ph_57 < - 0.1) || (row.f_acid_to_ph_57 > 0.1))) {
1196 C1 = row.f_acid_to_ph_57 / (row.f_di_ph - 5.7);
1197 } else {
1198 // If the acid_to_ph_5.7 is unknown from the maltster, guess the required acid.
1199 var ebc = row.f_color;
1200 switch (row.f_graintype) {
1201 case 0: // Base, Special, Kilned
1202 case 3:
1203 case 5: C1 = 0.014 * ebc - 34.192;
1204 break;
1205 case 2: C1 = -0.0597 * ebc - 32.457; // Crystal
1206 break;
1207 case 1: C1 = 0.0107 * ebc - 54.768; // Roast
1208 break;
1209 case 4: C1 = -149; // Sour malt
1210 break;
1211 }
1212 }
1213 x = C1 * (pHZ - row.f_di_ph); // AcidRequired(ZpH)
1214 Result += x * row.f_amount;
1215 }
1216 }
1217 return Result;
1218 }
1219
1220 function MashpH() {
1221 var n = 0;
1222 var pH = 5.4;
1223 var deltapH = 0.001;
1224 var deltapd = 0.1;
1225 var pd = ProtonDeficit(pH);
1226 while (((pd < -deltapd) || (pd > deltapd)) && (n < 2000)) {
1227 n++;
1228 if (pd < -deltapd)
1229 pH -= deltapH;
1230 else if (pd > deltapd)
1231 pH += deltapH;
1232 pd = ProtonDeficit(pH);
1233 }
1234 console.log("MashpH() n: "+n+" pH: "+pH);
1235 return pH;
1236 }
1237
1238 function GetAcidSpecs(AT) {
1239 switch(AT) {
1240 case 0: return { // Melkzuur
1241 pK1: 3.86,
1242 pK2: 20,
1243 pK3: 20,
1244 MolWt: 90.08,
1245 AcidSG: 1214, // 1214 1209
1246 AcidPrc: 0.88 // 0.88 0.80
1247 };
1248 case 1: return { // Zoutzuur
1249 pK1: -7,
1250 pK2: 20,
1251 pK3: 20,
1252 MolWt: 36.46,
1253 AcidSG: 1142,
1254 AcidPrc: 0.28
1255 };
1256 case 2: return { // Fosforzuur
1257 pK1: 2.12,
1258 pK2: 7.20,
1259 pK3: 12.44,
1260 MolWt: 98.00,
1261 AcidSG: 1170,
1262 AcidPrc: 0.25
1263 };
1264 case 3: return { // Zwavelzuur
1265 pK1: -1,
1266 pK2: 1.92,
1267 pK3: 20,
1268 MolWt: 98.07,
1269 AcidSG: 1700,
1270 AcidPrc: 0.93
1271 };
1272 }
1273 }
1274
1275
1276 function calcWater() {
1277
1278 console.log("calcWater()");
1279 var liters = 0;
1280 var calcium = 0;
1281 var magnesium = 0;
1282 var sodium = 0;
1283 var total_alkalinity = 0;
1284 var bicarbonate = 0;
1285 var chloride = 0;
1286 var sulfate = 0;
1287 var ph = 0;
1288 var RA = 0;
1289 var frac = 0;
1290 var TpH = 0;
1291 var protonDeficit = 0;
1292
1293 if (dataRecord.w1_name == "") {
1294 return;
1295 }
1296
1297 // If there is a dillute water source, mix the waters.
1298 if (dataRecord.w2_name != "") {
1299 liters = dataRecord.w1_amount + dataRecord.w2_amount;
1300 calcium = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_calcium, dataRecord.w2_calcium);
1301 magnesium = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_magnesium, dataRecord.w2_magnesium);
1302 sodium = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_sodium, dataRecord.w2_sodium);
1303 chloride = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_chloride, dataRecord.w2_chloride);
1304 sulfate = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_sulfate, dataRecord.w2_sulfate);
1305 total_alkalinity = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_total_alkalinity, dataRecord.w2_total_alkalinity);
1306 ph = -Math.log10(((Math.pow(10, -dataRecord.w1_ph) * dataRecord.w1_amount) + (Math.pow(10, -dataRecord.w2_ph) * dataRecord.w2_amount)) / liters);
1307 } else {
1308 liters = dataRecord.w1_amount;
1309 calcium = dataRecord.w1_calcium;
1310 magnesium = dataRecord.w1_magnesium;
1311 sodium = dataRecord.w1_sodium;
1312 chloride = dataRecord.w1_chloride;
1313 sulfate = dataRecord.w1_sulfate;
1314 total_alkalinity = dataRecord.w1_total_alkalinity;
1315 ph = dataRecord.w1_ph;
1316 }
1317 $('#wg_amount').val(liters);
1318 var wg_calcium = calcium;
1319 $('#wg_calcium').val(Math.round(calcium * 10) / 10);
1320 //var wg_magnesium = magnesium;
1321 $('#wg_magnesium').val(Math.round(magnesium * 10) / 10);
1322 var wg_sodium = sodium;
1323 $('#wg_sodium').val(Math.round(sodium * 10) / 10);
1324 var wg_total_alkalinity = total_alkalinity;
1325 $('#wg_total_alkalinity').val(Math.round(total_alkalinity * 10) / 10);
1326 var wg_chloride = chloride;
1327 $('#wg_chloride').val(Math.round(chloride * 10) / 10);
1328 var wg_sulfate = sulfate;
1329 $('#wg_sulfate').val(Math.round(sulfate * 10) / 10);
1330 // Note: brouwhulp has the malts included here in the result.
1331 //var wg_ph = ph;
1332 $('#wg_ph').val(Math.round(ph * 10) / 10);
1333 $('#wb_ph').val(Math.round(MashpH() * 10) / 10);
1334 $('#est_mash_ph').val(Math.round(MashpH() * 10) / 10);
1335 bicarbonate = total_alkalinity * 1.22;
1336 var wg_bicarbonate = bicarbonate;
1337
1338 // Noot: de volgende berekeningen geven bijna gelijke resultaten in Brun'water.
1339 // Calculate Ca
1340 RA = parseFloat($("#wa_cacl2").jqxNumberInput('decimal')) * MMCa / MMCaCl2 +
1341 parseFloat($("#wa_caso4").jqxNumberInput('decimal')) * MMCa / MMCaSO4;
1342 calcium += 1000 * RA / liters;
1343
1344 // Calculate Mg
1345 RA = parseFloat($("#wa_mgso4").jqxNumberInput('decimal')) * MMMg / MMMgSO4;
1346 magnesium += 1000 * RA / liters;
1347
1348 // Calculate Na
1349 RA = parseFloat($("#wa_nacl").jqxNumberInput('decimal')) * MMNa / MMNaCl +
1350 parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMNa / MMNaHCO3;
1351 sodium += 1000 * RA / liters;
1352
1353 // Calculate SO4
1354 RA = parseFloat($("#wa_caso4").jqxNumberInput('decimal')) * MMSO4 / MMCaSO4 +
1355 parseFloat($("#wa_mgso4").jqxNumberInput('decimal')) * MMSO4 / MMMgSO4;
1356 sulfate += 1000 * RA / liters;
1357
1358 // Calculate Cl
1359 RA = 2 * parseFloat($("#wa_cacl2").jqxNumberInput('decimal')) * MMCl / MMCaCl2 +
1360 parseFloat($("#wa_nacl").jqxNumberInput('decimal')) * MMCl / MMNaCl;
1361 chloride += 1000 * RA / liters;
1362 // Einde noot.
1363
1364 if ($("#wa_acid_name").val() < 0 || $("#wa_acid_name").val() > 3) {
1365 $("#wa_acid_name").val(0);
1366 dataRecord.wa_acid_name = 0;
1367 }
1368 if (last_acid == '')
1369 last_acid = AcidTypeData[$("#wa_acid_name").val()].nl;
1370
1371 if ($("#wa_base_name").val() < 0 || $("#wa_base_name").val() > 3) {
1372 $("#wa_base_name").val(0);
1373 dataRecord.wa_base_name = 0;
1374 }
1375 if (last_base == '')
1376 last_base = BaseTypeData[$("#wa_base_name").val()].nl;
1377
1378 var AT = dataRecord.wa_acid_name;
1379 var BT = dataRecord.wa_base_name;
1380
1381 var result = GetAcidSpecs(AT);
1382 var pK1 = result.pK1;
1383 var pK2 = result.pK2;
1384 var pK3 = result.pK3;
1385 var MolWt = result.MolWt;
1386 var AcidSG = result.AcidSG;
1387 var AcidPrc = result.AcidPrc;
1388
1389 if (dataRecord.calc_acid) {
1390 TpH = parseFloat(dataRecord.mash_ph);
1391 protonDeficit = ProtonDeficit(TpH);
1392 console.log("calc_acid tgt: "+TpH+" protonDeficit: "+protonDeficit);
1393 if (protonDeficit > 0) { // Add acid
1394 $("#wa_base").val(0);
1395 setWaterAgent(last_base, 0);
1396 frac = CalcFrac(TpH, pK1, pK2, pK3);
1397 Acid = protonDeficit / frac;
1398 Acid *= MolWt; // mg
1399 Acidmg = Acid;
1400 Acid = Acid / AcidSG; // ml
1401
1402 if (parseFloat($("#wa_acid_perc").jqxNumberInput('decimal')) == 0)
1403 $("#wa_acid_perc").val(AcidPrc);
1404 Acid = Acid * AcidPrc / (parseFloat($("#wa_acid_perc").jqxNumberInput('decimal')) / 100); // ml
1405 console.log("Final ml: "+Acid);
1406 $("#wa_acid").val(Math.round(Acid * 100) / 100);
1407 setWaterAgent(AcidTypeData[AT].nl, Math.round(Acid * 100) / 100);
1408
1409 bicarbonate = bicarbonate - protonDeficit * frac / liters;
1410 total_alkalinity = bicarbonate * 50 / 61;
1411 } else if (protonDeficit < 0) { //Add base
1412 $("#wa_acid").val(0);
1413 setWaterAgent(last_acid, 0);
1414 var r1d = Math.pow(10, (TpH - 6.38));
1415 var r2d = Math.pow(10, (TpH - 10.38));
1416 var f1d = 1 / (1 + r1d + r1d * r2d);
1417 var f2d = f1d * r1d;
1418 var f3d = f2d * r2d;
1419 switch (BT) {
1420 case 0: RA = -protonDeficit / (f1d - f3d); // Sodiumbicarbonate, mmol totaal
1421 RA = RA * MMNaHCO3/1000; //gram
1422 $("#wa_base").val(Math.round(RA * 100) / 100);
1423 setWaterAgent('NaHCO3', Math.round(RA * 100) / 100);
1424 if (liters > 0) {
1425 // Na
1426 RA = parseFloat($("#wa_nacl").jqxNumberInput('decimal')) * MMNa / MMNaCl +
1427 parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMNa / MMNaHCO3;
1428 RA = 1000 * RA / liters;
1429 sodium = wg_sodium + RA;
1430 // HCO3
1431 RA = parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMHCO3 / MMNaHCO3;
1432 RA = 1000 * RA / liters;
1433 bicarbonate = wg_bicarbonate + RA;
1434 total_alkalinity = bicarbonate * 50 / 61;
1435 RA = ResidualAlkalinity(wb_total_alkalinity, wb_calcium, wb_magnesium);
1436 }
1437 break;
1438 case 1: RA = -protonDeficit / (2 * f1d + f2d); // Sodiumcarbonate, mmol totaal
1439 RA = RA * MMNa2CO3/1000; //gram
1440 $("#wa_base").val(Math.round(RA * 100) / 100);
1441 setWaterAgent('Na2CO3', Math.round(RA * 100) / 100);
1442 if (liters > 0) {
1443 RA = parseFloat($("#wa_nacl").jqxNumberInput('decimal')) * MMNa / MMNaCl +
1444 parseFloat($("#wa_base").jqxNumberInput('decimal')) * 2 * MMNa / MMNa2CO3;
1445 RA = 1000 * RA / liters;
1446 sodium = wg_sodium + RA;
1447 // HCO3
1448 RA = parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMHCO3 / MMNa2CO3;
1449 RA = 1000 * RA / liters;
1450 bicarbonate = wg_bicarbonate + RA;
1451 total_alkalinity = bicarbonate * 50 / 61;
1452 RA = ResidualAlkalinity(wb_total_alkalinity, wb_calcium, wb_magnesium);
1453 }
1454 break;
1455 case 2: RA = -protonDeficit * (f1d - f3d); // Calciumcarbonate, mmol totaal
1456 RA = RA * MMCaCO3/1000; //gram
1457 //but only 1/3 is effective, so add 3 times as much
1458 RA = 3 * RA;
1459 $("#wa_base").val(Math.round(RA * 100) / 100);
1460 setWaterAgent('CaCO3', Math.round(RA * 100) / 100);
1461 if (liters > 0) {
1462 //Bicarbonate
1463 RA = parseFloat($("#wa_base").jqxNumberInput('decimal')) / 3 * MMHCO3 / MMCaCO3;
1464 RA = 1000 * RA / liters;
1465 bicarbonate = wg_bicarbonate + RA;
1466 total_alkalinity = bicarbonate * 50 / 61;
1467 //Ca precipitates out as Ca10(PO4)6(OH)2
1468 RA = parseFloat($("#wa_cacl2").jqxNumberInput('decimal')) * MMCa / MMCaCl2 +
1469 parseFloat($("#wa_caso4").jqxNumberInput('decimal')) * MMCa / MMCaSO4 +
1470 parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMCa / MMCaCO3;
1471 RA = 1000 * RA / liters;
1472 calcium = wg_calcium + RA;
1473 RA = ResidualAlkalinity(wb_total_alkalinity, wb_calcium, wb_magnesium);
1474 }
1475 break;
1476 case 3: RA = -protonDeficit / 19.3; // Calciumhydroxide
1477 $("#wa_base").val(Math.round(RA * 100) / 100);
1478 setWaterAgent('Ca(OH)2', Math.round(RA * 100) / 100);
1479 if (liters > 0) {
1480 // Bicarbonate
1481 RA = -protonDeficit / liters;
1482 total_alkalinity = wg_total_alkalinity + RA;
1483 bicarbonate = total_alkalinity * 61 / 50;
1484 // Calcium
1485 RA = parseFloat($("#wa_cacl2").jqxNumberInput('decimal')) * MMCa / MMCaCl2 +
1486 parseFloat($("#wa_caso4").jqxNumberInput('decimal')) * MMCa / MMCaSO4 +
1487 parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMCa / MMCaOH2;
1488 RA = 1000 * RA / liters;
1489 calcium = wg_calcium + RA;
1490 RA = ResidualAlkalinity(wb_total_alkalinity, wb_calcium, wb_magnesium);
1491 }
1492 break;
1493 }
1494 }
1495 ph = TpH;
1496 $('#wb_ph').val(Math.round(ph * 10) / 10);
1497 $('#est_mash_ph').val(Math.round(ph * 10) / 10);
1498 } else { // Manual
1499 console.log("calc_acid no");
1500 // First add base salts
1501 if (parseFloat($("#wa_base").jqxNumberInput('decimal')) > 0) {
1502 if (liters > 0) {
1503 switch (BT) {
1504 case 0: // Sodiumbicarbonate, Na
1505 RA = parseFloat($("#wa_nacl").jqxNumberInput('decimal')) * MMNa / MMNaCl +
1506 parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMNa / MMNaHCO3;
1507 RA = 1000 * RA / liters;
1508 sodium = wg_sodium + RA;
1509 // HCO3
1510 RA = parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMHCO3 / MMNaHCO3;
1511 RA = 1000 * RA / liters;
1512 bicarbonate = wg_bicarbonate + RA;
1513 total_alkalinity = bicarbonate * 50 / 61;
1514 RA = ResidualAlkalinity(wb_total_alkalinity, wb_calcium, wb_magnesium);
1515 break;
1516 case 1: // Sodiumcarbonate
1517 RA = parseFloat($("#wa_nacl").jqxNumberInput('decimal')) * MMNa / MMNaCl +
1518 parseFloat($("#wa_base").jqxNumberInput('decimal')) * 2 * MMNa / MMNa2CO3;
1519 RA = 1000 * RA / liters;
1520 sodium = wg_sodium + RA;
1521 // HCO3
1522 RA = parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMHCO3 / MMNa2CO3;
1523 RA = 1000 * RA / liters;
1524 bicarbonate = wg_bicarbonate + RA;
1525 total_alkalinity = bicarbonate * 50 / 61;
1526 RA = ResidualAlkalinity(wb_total_alkalinity, wb_calcium, wb_magnesium);
1527 break;
1528 case 2: // Calciumcarbonate: Bicarbonate
1529 RA = parseFloat($("#wa_base").jqxNumberInput('decimal')) / 3 * MMHCO3 / MMCaCO3;
1530 RA = 1000 * RA / liters;
1531 bicarbonate = wg_bicarbonate + RA;
1532 total_alkalinity = bicarbonate * 50 / 61;
1533 RA = ResidualAlkalinity(wb_total_alkalinity, wb_calcium, wb_magnesium);
1534 // Ca
1535 RA = parseFloat($("#wa_cacl2").jqxNumberInput('decimal')) * MMCa / MMCaCl2 +
1536 parseFloat($("#wa_caso4").jqxNumberInput('decimal')) * MMCa / MMCaSO4 +
1537 parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMCa / MMCaCO3;
1538 RA = 1000 * RA / liters;
1539 calcium = wg_calcium + RA;
1540 break;
1541 }
1542 }
1543 }
1544
1545 TpH = parseFloat(dataRecord.mash_ph);
1546 pHa = MashpH(); // This one is in demi water, should be in adjusted water???
1547 // Then calculate the new pH with added acids
1548 if (parseFloat($("#wa_acid").jqxNumberInput('decimal')) > 0) {
1549 console.log("TpH: "+TpH+" water: "+pHa);
1550 Acid = parseFloat($("#wa_acid").jqxNumberInput('decimal'));
1551 if (parseFloat($("#wa_acid_perc").jqxNumberInput('decimal')) == 0)
1552 $("#wa_acid_perc").val(AcidPrc);
1553 Acid = Acid / AcidPrc * (parseFloat($("#wa_acid_perc").jqxNumberInput('decimal')) / 100); // ml
1554 Acid *= AcidSG; // ml
1555 Acid /= MolWt; // mg
1556 Acidmg = Acid;
1557
1558 //find the pH where the protondeficit = protondeficit by the acid
1559 frac = CalcFrac(pHa, pK1, pK2, pK3);
1560 protonDeficit = Acid * frac;
1561
1562 var deltapH = 0.001;
1563 var deltapd = 0.1;
1564 var pd = ProtonDeficit(pHa);
1565 var n = 0;
1566 while (((pd < (protonDeficit - deltapd)) || (pd > (protonDeficit + deltapd))) && (n < 2000)) {
1567 n++;
1568 if (pd < (protonDeficit-deltapd))
1569 pHa -= deltapH;
1570 else if (pd > (protonDeficit+deltapd))
1571 pHa += deltapH;
1572 frac = CalcFrac(pHa, pK1, pK2, pK3);
1573 protonDeficit = Acid * frac;
1574 pd = ProtonDeficit(pHa);
1575 }
1576 console.log("n: "+n+" pd: "+pd+" protonDeficit: "+protonDeficit+" frac: "+frac+" pHa: "+pHa);
1577 RA = wg_bicarbonate - protonDeficit * frac / liters;
1578 bicarbonate = RA;
1579 total_alkalinity = RA * 50 / 61;
1580 ph = pHa;
1581 $('#wb_ph').val(Math.round(ph * 10) / 10);
1582 $('#est_mash_ph').val(Math.round(ph * 10) / 10);
1583 }
1584 }
1585
1586 if ((AT == 3) && (liters > 0)) { // Sulfuctic / Zwavelzuur
1587 RA = parseFloat($("#wa_caso4").jqxNumberInput('decimal')) * MMSO4 / MMCaSO4 +
1588 parseFloat($("#wa_mgso4").jqxNumberInput('decimal')) * MMSO4 / MMMgSO4 +
1589 Acidmg / 1000 * MMSO4 / (MMSO4 + 2);
1590 RA = 1000 * RA / liters;
1591 sulfate = wg_sulfate + RA; // Not add to sulfate??
1592 } else if ((AT == 1) && (liters > 0)) { // Hydrochloric, Zoutzuur
1593 RA = parseFloat($("#wa_cacl2").jqxNumberInput('decimal')) * MMCl / MMCaCl2 +
1594 parseFloat($("#wa_nacl").jqxNumberInput('decimal')) * MMCl / MMNaCl +
1595 Acidmg / 1000 * MMCl / (MMCl + 1);
1596 RA = 1000 * RA / liters;
1597 chloride = wg_chloride + RA;
1598 }
1599
1600 // 2:1 Sulfate to Chroride IPA's, Pale Ales.
1601 // 1:1 Sulfate to Chloride Balanced
1602 // 1:2 Sulfate to Chloride Malty
1603 // Note, values below are the other way, cl to so4!
1604 // So: 0.5 is IPA's, Pale Ales.
1605 // 1 Balanced
1606 // 2 Malty.
1607 $('#tgt_bu').val(Math.round(GetBUGU() * 100) / 100);
1608 // From brouwhulp.
1609 if (GetBUGU() < 0.32)
1610 $('#wr_bu').html("<span style='vertical-align: top; font-size: 14px; font-style: italic;'>Zeer moutig en zoet</span>");
1611 else if (GetBUGU() < 0.43)
1612 $('#wr_bu').html("<span style='vertical-align: top; font-size: 14px; font-style: italic;'>Moutig, zoet</span>");
1613 else if (GetBUGU() < 0.52)
1614 $('#wr_bu').html("<span style='vertical-align: top; font-size: 14px; font-style: italic;'>Evenwichtig</span>");
1615 else if (GetBUGU() < 0.63)
1616 $('#wr_bu').html("<span style='vertical-align: top; font-size: 14px; font-style: italic;'>Licht hoppig, bitter</span>");
1617 else
1618 $('#wr_bu').html("<span style='vertical-align: top; font-size: 14px; font-style: italic;'>Extra hoppig, zeer bitter</span>");
1619 $('#tgt_cl_so4').val(Math.round(GetOptClSO4ratio() * 10) / 10);
1620 if (sulfate > 0)
1621 RA = chloride / sulfate;
1622 else
1623 RA = 10;
1624 $('#got_cl_so4').val(Math.round(RA * 10) / 10);
1625 var piCLSO4_low = 0.8 * GetOptClSO4ratio();
1626 var piCLSO4_high = 1.2 * GetOptClSO4ratio();
1627 var Res = 'normaal';
1628 if (RA < piCLSO4_low)
1629 Res = 'laag';
1630 else if (RA > piCLSO4_high)
1631 Res = 'hoog';
1632 setRangeIndicator('cl_so4', Res);
1633
1634 $('#wb_calcium').val(Math.round(calcium * 10) / 10);
1635 $('#wb_magnesium').val(Math.round(magnesium * 10) / 10);
1636 $('#wb_sodium').val(Math.round(sodium * 10) / 10);
1637 $('#wb_sulfate').val(Math.round(sulfate * 10) / 10);
1638 $('#wb_chloride').val(Math.round(chloride * 10) / 10);
1639 $('#wb_total_alkalinity').val(Math.round(total_alkalinity * 10) / 10);
1640
1641 if (calcium < 40) {
1642 setRangeIndicator("calcium", "laag");
1643 } else if (calcium > 150) {
1644 setRangeIndicator("calcium", "hoog");
1645 } else {
1646 setRangeIndicator("calcium", "normaal");
1647 }
1648 if (magnesium >= 0 && magnesium <= 30) {
1649 setRangeIndicator("magnesium", "normaal");
1650 } else {
1651 setRangeIndicator("magnesium", "hoog");
1652 }
1653 if (sodium <= 150) {
1654 setRangeIndicator("sodium", "normaal");
1655 } else {
1656 setRangeIndicator("sodium", "hoog");
1657 }
1658 // Both chloride and sulfate should be above 50 according to
1659 // John Palmer. So the Cl/SO4 ratio calculation will work.
1660 if (chloride <= 50) {
1661 setRangeIndicator("chloride", "laag");
1662 } else if (chloride <= 100) {
1663 setRangeIndicator("chloride", "normaal");
1664 } else {
1665 setRangeIndicator("chloride", "hoog");
1666 }
1667 if (sulfate <= 50) {
1668 setRangeIndicator("sulfate", "laag");
1669 } else if (sulfate <= 350) {
1670 setRangeIndicator("sulfate", "normaal");
1671 } else {
1672 setRangeIndicator("sulfate", "hoog");
1673 }
1674 if (ph < 5.2) {
1675 setRangeIndicator("ph", "laag");
1676 } else if (ph > 5.6) {
1677 setRangeIndicator("ph", "hoog");
1678 } else {
1679 setRangeIndicator("ph", "normaal");
1680 }
1681 calcSparge();
1682 calcMiscs();
1683 calcSupplies();
1684 }
1685
1686 function calcSparge() {
1687
1688 // Code from BrewBuddy/Brouwhulp, who got it from http://www.brewery.org/brewery/library/Acidi0,00fWaterAJD0497.html
1689 var TargetpH = dataRecord.sparge_ph;
1690 var Source_pH = dataRecord.w1_ph;
1691 var Source_alkalinity = dataRecord.w1_total_alkalinity;
1692 // Select watersource or fallback to the first source.
1693 if (dataRecord.sparge_source == 1) { // Source 2
1694 if (dataRecord.w2_ph > 0.0) {
1695 Source_pH = dataRecord.w2_ph;
1696 Source_alkalinity = dataRecord.w2_total_alkalinity;
1697 } else {
1698 dataRecord.sparge_source = 0; // Source 1
1699 $("#sparge_source").val(0);
1700 }
1701 } else if (dataRecord.sparge_source == 2) { // Mixed
1702 if (dataRecord.w2_ph > 0.0) {
1703 Source_pH = parseFloat($("#wg_ph").jqxNumberInput('decimal'));
1704 Source_alkalinity = parseFloat($("#wg_total_alkalinity").jqxNumberInput('decimal'));
1705 } else {
1706 dataRecord.sparge_source = 0;
1707 $("#sparge_source").val(0);
1708 }
1709 }
1710
1711 // Step 1: Compute the mole fractions of carbonic (f1o), bicarbonate (f2o) and carbonate(f3o) at the water pH
1712 var r1 = Math.pow(10, Source_pH - 6.38);
1713 var r2 = Math.pow(10, Source_pH - 10.373);
1714 var d = 1 + r1 + r1*r2;
1715 var f1 = 1/d;
1716 //var f2 = r1/d;
1717 var f3 = r1 * r2 / d;
1718
1719 //Step 2. Compute the mole fractions at pH = 4.3 (the pH which defines alkalinity)
1720 var r143 = Math.pow(10, 4.3 - 6.38);
1721 var r243 = Math.pow(10, 4.3 - 10.373);
1722 var d43 = 1 + r143 + r143*r243;
1723 var f143 = 1/d43;
1724 //var f243 = r143 / d43;
1725 var f343 = r143 * r243 / d43;
1726
1727 //Step 3. Convert the water alkalinity to milliequivalents/L
1728 var alkalinity = Source_alkalinity / 50;
1729
1730 //Step 4. Solve
1731 var Ct = (alkalinity - 1000 * (Math.pow(10, -4.3) - Math.pow(10, -Source_pH))) / ((f143-f1)+(f3-f343));
1732
1733 //Step 5. Compute mole fractions at desired pH
1734 var r1g = Math.pow(10, TargetpH - 6.38);
1735 var r2g = Math.pow(10, TargetpH - 10.373);
1736 var dg = 1 + r1g + r1g*r2g;
1737 var f1g = 1/dg;
1738 //var f2g = r1g / dg;
1739 var f3g = r1g * r2g / dg;
1740
1741 //Step 6. Use these to compute the milliequivalents acid required per liter (mEq/L)
1742 var Acid = Ct * ((f1g-f1)+(f3-f3g)) + Math.pow(10, -TargetpH) - Math.pow(10, -Source_pH); //mEq/l
1743 Acid += 0.01; // Add acid that would be required for distilled water.
1744 if (dataRecord.sparge_acid_type < 0 || dataRecord.sparge_acid_type > 3) {
1745 dataRecord.sparge_acid_type = 0;
1746 $("#sparge_acid_type").val(0);
1747 }
1748
1749 //Step 8. Get the acid data.
1750 var AT = dataRecord.sparge_acid_type;
1751 var result = GetAcidSpecs(AT);
1752 var pK1 = result.pK1;
1753 var pK2 = result.pK2;
1754 var pK3 = result.pK3;
1755 var MolWt = result.MolWt;
1756 var AcidSG = result.AcidSG;
1757 var AcidPrc = result.AcidPrc;
1758 var fract = CalcFrac(TargetpH, pK1, pK2, pK3);
1759
1760 //Step 9. Now divide the mEq required by the "fraction". This is the required number of moles of acid.
1761 Acid /= fract;
1762
1763 //Step 10. Multiply by molecular weight of the acid
1764 Acid *= MolWt; //mg
1765
1766 Acid = Acid / AcidSG; //ml ; 88% lactic solution
1767 var f1 = dataRecord.sparge_acid_perc;
1768 if (f1 <= 0.1)
1769 f1 = AcidPrc;
1770 Acid = Acid * AcidPrc / (f1 / 100);
1771
1772 Acid *= dataRecord.sparge_volume; //ml lactic acid total
1773 Acid = Math.round(Acid * 100) / 100;
1774 dataRecord.sparge_acid_amount = Acid / 1000;
1775 $("#sparge_acid_amount").val(Acid);
1776 }
1777
1778 function calcFermentation(){
1779
1780 if (dataRecord.brew_fermenter_sg<1.020)
1781 return;
1782
1783 // var obrix = sg_to_brix(dataRecord.brew_fermenter_sg);
1784 if ((dataRecord.primary_end_sg>0.990)&&(dataRecord.primary_end_sg<dataRecord.brew_fermenter_sg)){
1785 var primary_svg=Round(100*(dataRecord.brew_fermenter_sg-dataRecord.primary_end_sg)/(dataRecord.brew_fermenter_sg-1),1);
1786 $("#primary_svg").val(primary_svg);
1787 if((dataRecord.secondary_end_sg>0.990)&&(dataRecord.secondary_end_sg<dataRecord.brew_fermenter_sg)){
1788 var secondary_svg=Round(100*(dataRecord.brew_fermenter_sg-dataRecord.secondary_end_sg)/(dataRecord.brew_fermenter_sg-1),1);
1789 $("#secondary_svg").val(secondary_svg);
1790 if((dataRecord.fg>0.990)&&(dataRecord.fg<dataRecord.brew_fermenter_sg)){
1791 var final_svg=Round(100*(dataRecord.brew_fermenter_sg-dataRecord.fg)/(dataRecord.brew_fermenter_sg-1),1);
1792 $("#final_svg").val(final_svg);
1793 var ABV=Round(abvol(dataRecord.brew_fermenter_sg,dataRecord.fg),2);
1794 $("#final_abv").val(ABV);
1795 }
1796 }
1797 }
1798 }
1799
1800
1801
1802 function ResCO2(CO2,T){
1803
1804 var F=T*1.8+32;
1805 return 3.0378-0.050062*F+0.00026555*F*F;
1806 }
1807
1808
1809
1810 function CarbCO2toS(CO2,T,SFactor){
1811 var sugar=SFactor*(CO2-ResCO2(CO2,T))/0.286;
1812 if(sugar<0)
1813 sugar=0;
1814 return Round(sugar,3);
1815 }
1816
1817 function GetPressure(CO2, T1, T2) {
1818 var V = CO2 - ResCO2(CO2, T1);
1819 if (V < 0)
1820 return 0;
1821 var P = -1.09145427669121 + 0.00800006989646477 * T2 + 0.000260276315484684 * T2 * T2 + 0.0215142075945119 * T2 * V +
1822 0.674996600795854 * V + -0.00471757220150754 * V * V;
1823 //console.log("CO2: "+CO2+" "+V+" Temp: "+T1+" "+T2+" Pressure: "+P);
1824 if (P < 0)
1825 P = 0;
1826 P = P * 1.01325; // atm to bar
1827 return Round(P,1);
1828 }
1829
1830 function CarbCO2ToPressure(CO2, T) {
1831 return (CO2-(-0.000005594056*Math.pow(T,4)+0.000144357886*Math.pow(T,3)+0.000362999168*T*T-0.064872987645*T+1.641145175049)) /
1832 (0.00000498031*Math.pow(T,4)-0.00024358267*Math.pow(T,3)+0.00385867329*T*T-0.05671206825*T+1.53801423376);
1833 }
1834
1835 function calcCarbonation() {
1836
1837 var TSec=dataRecord.secondary_temp;
1838 if(TSec<1)
1839 TSec=dataRecord.primary_end_temp;
1840 if(TSec<1)
1841 TSec=18;
1842
1843 if(dataRecord.fg==0.000)
1844 var ABV=abvol(dataRecord.brew_fermenter_sg,parseFloat($("#est_fg").jqxNumberInput('decimal')));
1845 else
1846 var ABV=abvol(dataRecord.brew_fermenter_sg,dataRecord.fg);
1847
1848 /* Calculate new volume and alcohol. */
1849 var bvol=dataRecord.package_volume-(ABV*dataRecord.package_volume)/100;
1850 var balc=dataRecord.package_volume-bvol;
1851 var mvol=dataRecord.package_infuse_amount-(dataRecord.package_infuse_abv*dataRecord.package_infuse_amount)/100;
1852 var malc=dataRecord.package_infuse_amount-mvol;
1853 var talc=balc+malc;
1854 var tvol=bvol+mvol;
1855 ABV = Round(talc/(tvol+talc)*100,2);
1856 dataRecord.package_abv=ABV;
1857 $("#package_abv").val(ABV);
1858
1859 // console.log("calcCarbonation() TSec:"+TSec+" ABV:"+ABV);
1860 if(!(rows = $('#fermentableGrid').jqxGrid('getrows'))){return;}
1861
1862 // Bottles
1863 dataRecord.bottle_priming_amount=0;
1864 dataRecord.bottle_priming_total=0;
1865 for (var i=0;i<rows.length;i++){
1866 var row=rows[i];
1867 if(row.f_added==4){
1868 var SFactor=1/((row.f_yield/100)*(1-row.f_moisture/100));
1869 dataRecord.bottle_priming_amount=CarbCO2toS(dataRecord.bottle_carbonation,TSec,SFactor);
1870 dataRecord.bottle_priming_total=Round(dataRecord.bottle_amount*dataRecord.bottle_priming_amount,2);
1871 $("#fermentableGrid").jqxGrid('setcellvalue',i,'f_amount',dataRecord.bottle_priming_total/1000);
1872 }
1873 }
1874 $("#bottle_priming_amount").val(Round(dataRecord.bottle_priming_amount,1));
1875 $("#bottle_priming_total").val(dataRecord.bottle_priming_total);
1876 var pabv=ABV+dataRecord.bottle_priming_amount*0.47/7.907;
1877 var pvol=dataRecord.bottle_amount-(pabv*dataRecord.bottle_amount)/100;
1878 var talc=dataRecord.bottle_amount-pvol;
1879 var tvol=pvol+dataRecord.bottle_priming_water;
1880 var babv = Round(talc/(tvol+talc)*100,2);
1881 //console.log("bottle pabv:"+pabv+" pvol:"+pvol+" wvol:"+dataRecord.bottle_priming_water+" tvol:"+tvol+" talc:"+talc+" abv:"+babv);
1882 $("#bottle_abv").val(babv);
1883 $("#bottle_pressure").val(GetPressure(dataRecord.bottle_carbonation,TSec,dataRecord.bottle_carbonation_temp));
1884
1885 // Kegs
1886 var Pressure=CarbCO2ToPressure(dataRecord.keg_carbonation,dataRecord.keg_carbonation_temp);
1887 if(Pressure<0)Pressure=0;
1888 dataRecord.keg_pressure=Pressure;
1889 $("#keg_pressure").val(Round(Pressure,1));
1890
1891 dataRecord.keg_priming_amount=0;
1892 dataRecord.keg_priming_total=0;
1893 if(!dataRecord.keg_forced_carb){
1894 for(var i=0;i<rows.length;i++){
1895 var row=rows[i];
1896 if(row.f_added==5){
1897 var SFactor=1/((row.f_yield/100)*(1-row.f_moisture/100));
1898 dataRecord.keg_priming_amount=CarbCO2toS(dataRecord.keg_carbonation,TSec,SFactor);
1899 dataRecord.keg_priming_total=Round(dataRecord.keg_amount*dataRecord.keg_priming_amount,2);
1900 $("#fermentableGrid").jqxGrid('setcellvalue',i,'f_amount',dataRecord.keg_priming_total/1000);
1901 }
1902 }
1903 $("#keg_priming_amount").val(Round(dataRecord.keg_priming_amount,1));
1904 $("#keg_priming_total").val(dataRecord.keg_priming_total);
1905 var pabv=ABV+dataRecord.keg_priming_amount*0.47/7.907;
1906 var pvol=dataRecord.keg_amount-(pabv*dataRecord.keg_amount)/100;
1907 var talc=dataRecord.keg_amount-pvol;
1908 var tvol=pvol+dataRecord.keg_priming_water;
1909 var kabv=Round(talc/(tvol+talc)*100,2);
1910 //console.log("kegs pabv:"+pabv+" pvol:"+pvol+" wvol:"+dataRecord.keg_priming_water+" tvol:"+tvol+" talc:"+talc+" abv:"+kabv);
1911 $("#keg_abv").val(kabv);
1912 } else {
1913 $("#keg_priming_amount").val(0);
1914 $("#keg_priming_total").val(0);
1915 $("#keg_abv").val(ABV);
1916 }
1917 }
1918
1919 function calcStage() {
1920
1921 var newstage = dataRecord.stage;
1922 /* parseFloat$("#brew_date_start").val()) returns the year if it is a valid mysql style date. */
1923 if (newstage == 0 && dataRecord.est_og > 1.005 && dataRecord.est_color > 3 && dataRecord.est_ibu > 3)
1924 newstage = 1;
1925 if (newstage == 1 && parseFloat($("#brew_date_start").val()) > 2000)
1926 newstage = 2; // Brewday
1927 if (newstage == 2 && ($("#brew_date_start").val() == ''))
1928 newstage = 1; // No brewday
1929 if (newstage == 2 && parseFloat($("#brew_date_end").val()) > 2000)
1930 newstage = 3; // Primary
1931 if (newstage == 3 && parseFloat($("#primary_end_date").val()) > 2000)
1932 newstage = 4; // Secondary
1933 if (newstage == 4 && parseFloat($("#secondary_end_date").val()) > 2000)
1934 newstage = 5; // Tertiary
1935 if (newstage == 5 && parseFloat($("#package_date").val()) > 2000)
1936 newstage = 6; // Package
1937 if (newstage >= 6 && newstage < 9) {
1938 var d = new Date();
1939 var date2 = $("#package_date").val();
1940 date2 = date2.split('-');
1941 // Now we convert the array to a Date object
1942 date1 = new Date(d.getFullYear(), d.getMonth(), d.getDate());
1943 date2 = new Date(date2[0], date2[1]-1, date2[2]);
1944 // We use the getTime() method and get the unixtime
1945 date1_unixtime = parseInt(date1.getTime() / 1000);
1946 date2_unixtime = parseInt(date2.getTime() / 1000);
1947 // This is the calculated difference in seconds
1948 var timeDifference = date1_unixtime - date2_unixtime;
1949 var timeDifferenceInDays = timeDifference / 60 / 60 / 24;
1950 if (timeDifferenceInDays > 0) { // At least one day
1951 if (timeDifferenceInDays >= 42) // 6 weeks
1952 newstage = 9; // Ready to taste
1953 else if (timeDifferenceInDays >= 14) // 14 days
1954 newstage = 8; // Mature
1955 else
1956 newstage = 7; // Carbonation
1957 }
1958 }
1959 if (newstage == 9 && parseFloat($("#taste_date").val()) > 2000)
1960 newstage = 10; // Ready
1961
1962 if (newstage != dataRecord.stage) {
1963 console.log("calcStage() old: "+dataRecord.stage+" new: "+newstage);
1964 dataRecord.stage = newstage;
1965 }
1966
1967 /*
1968 * Set stage and enable or disable parts of the screens.
1969 */
1970 $("#stage").val(StageData[dataRecord.stage].nl);
1971 if (dataRecord.stage >= 10) {
1972 $("#locked").jqxCheckBox({ disabled:false });
1973 }
1974
1975 /*
1976 * When the brew is in progress or done, block equipment select and delete.
1977 */
1978 if (dataRecord.stage > 1) {
1979 $("#equipmentSelect").jqxDropDownList({ disabled: true });
1980 $("#Delete").jqxButton({ disabled: true });
1981 }
1982
1983 if (dataRecord.stage < 1) // Planning, no ingredients
1984 $('#jqxTabs').jqxTabs('disableAt', 8); // Brewday tab
1985 else
1986 $('#jqxTabs').jqxTabs('enableAt', 8);
1987
1988 if (dataRecord.stage < 3) { // Primary
1989 $('#jqxTabs').jqxTabs('disableAt', 9); // Fermentation tab
1990 } else {
1991 $('#jqxTabs').jqxTabs('enableAt', 9);
1992 $("#name").jqxInput({ disabled: true });
1993 $("#code").jqxInput({ disabled: true });
1994 $("#batch_size").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
1995 $("#boil_size").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
1996 $("#boil_time").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
1997 $("#efficiency").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
1998 $("#est_og").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
1999 $("#type").jqxDropDownList({ disabled: true });
2000 $("#styleSelect").jqxDropDownList({ disabled: true });
2001 $("#color_method").jqxDropDownList({ disabled: true });
2002 $("#ibu_method").jqxDropDownList({ disabled: true });
2003 $("#mash_select").jqxDropDownList({ disabled: true });
2004 $("#w1_name").jqxDropDownList({ disabled: true });
2005 $("#w2_name").jqxDropDownList({ disabled: true });
2006 $("#w2_amount").jqxNumberInput({ readOnly: true });
2007 $("#pr_name").jqxDropDownList({ disabled: true });
2008 $("#wa_cacl2").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
2009 $("#wa_caso4").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
2010 $("#wa_mgso4").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
2011 $("#wa_nacl").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
2012 $("#mash_ph").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
2013 $("#calc_acid").jqxCheckBox({ disabled: true });
2014 $("#wa_base_name").jqxDropDownList({ disabled: true });
2015 $("#wa_base").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
2016 $("#wa_acid_name").jqxDropDownList({ disabled: true });
2017 $("#wa_acid").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
2018 $("#wa_acid_perc").jqxNumberInput({ spinButtons: false, readOnly: true, width: 70 });
2019 $("#sparge_temp").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
2020 $("#sparge_volume").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
2021 $("#sparge_ph").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
2022 $("#sparge_source").jqxDropDownList({ disabled: true });
2023 $("#sparge_acid_type").jqxDropDownList({ disabled: true });
2024 $("#sparge_acid_perc").jqxNumberInput({ spinButtons: false, readOnly: true, width: false });
2025 $("#starter_enable").jqxCheckBox({ disabled: true });
2026 $("#starter_type").jqxDropDownList({ disabled: true });
2027 $("#starter_try").jqxButton({ disabled: true });
2028 $("#starter_sg").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
2029 $("#starter_viability").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
2030 }
2031 if (dataRecord.stage > 3) { // Primary fermentation done
2032 $("#brew_date_start").jqxDateTimeInput({ disabled: true });
2033 $("#brew_date_end").jqxDateTimeInput({ disabled: true });
2034 $("#brew_mash_ph").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
2035 $("#brew_preboil_ph").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
2036 $("#brew_aboil_ph").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
2037 $("#brew_mash_sg").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
2038 $("#brew_preboil_sg").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
2039 $("#brew_aboil_sg").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
2040 $("#brew_preboil_volume").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
2041 $("#brew_aboil_volume").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
2042 $("#brew_whirlpool9").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
2043 $("#brew_cooling_to").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
2044 $("#brew_whirlpool7").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
2045 $("#brew_cooling_method").jqxDropDownList({ disabled: true });
2046 $("#brew_whirlpool6").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
2047 $("#brew_cooling_time").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
2048 $("#brew_sparge_ph").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
2049 $("#brew_whirlpool2").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
2050 $("#brew_aeration_type").jqxDropDownList({ disabled: true });
2051 $("#brew_fermenter_tcloss").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
2052 $("#brew_aeration_time").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
2053 $("#brew_fermenter_extrawater").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
2054 $("#brew_aeration_speed").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
2055 }
2056 if (dataRecord.stage == 5) // Lagering, allow packaging
2057 $("#package_date").jqxDateTimeInput({ disabled: false });
2058 else
2059 $("#package_date").jqxDateTimeInput({ disabled: true });
2060 if (dataRecord.stage >= 5) { // At least secondary
2061 $("#primary_start_temp").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
2062 $("#primary_max_temp").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
2063 $("#primary_end_temp").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
2064 $("#primary_end_sg").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
2065 $("#primary_end_brix").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
2066 $("#primary_end_date").jqxDateTimeInput({ disabled: true });
2067 }
2068 if (dataRecord.stage >= 6) { // Packaged
2069 $("#secondary_temp").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
2070 $("#secondary_end_sg").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
2071 $("#secondary_end_date").jqxDateTimeInput({ disabled: true });
2072 $("#tertiary_temp").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
2073 $("#fg").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
2074 $("#final_brix").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
2075 $("#package_date").jqxDateTimeInput({ disabled: true });
2076 $("#package_volume").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
2077 $("#package_infuse_amount").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
2078 $("#package_infuse_abv").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
2079 $("#package_infuse_notes").jqxInput({ disabled: true });
2080 $("#package_ph").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
2081 $("#bottle_amount").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
2082 $("#bottle_priming_water").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
2083 $("#keg_priming_water").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
2084 $("#keg_amount").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
2085 $("#bottle_carbonation").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
2086 $("#keg_carbonation").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
2087 $("#bottle_priming_sugar").jqxDropDownList({ disabled: true });
2088 $("#keg_priming_sugar").jqxDropDownList({ disabled: true });
2089 $("#keg_forced_carb").jqxCheckBox({ disabled : true });
2090 $("#bottle_carbonation_temp").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
2091 $("#keg_carbonation_temp").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
2092 }
2093 if (dataRecord.stage < 8) { // Taste when at least Mature.
2094 $('#jqxTabs').jqxTabs('disableAt', 11); // Tasting tab
2095 } else {
2096 $('#jqxTabs').jqxTabs('enableAt', 11);
2097 }
2098
2099 if (dataRecord.stage == 11) { // Locked
2100 $("#taste_date").jqxDateTimeInput({ disabled: true });
2101 $("#taste_rate").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
2102 $("#taste_color").jqxInput({ disabled: true });
2103 $("#taste_transparency").jqxInput({ disabled: true });
2104 $("#taste_head").jqxInput({ disabled: true });
2105 $("#taste_aroma").jqxInput({ disabled: true });
2106 $("#taste_taste").jqxInput({ disabled: true });
2107 $("#taste_aftertaste").jqxInput({ disabled: true });
2108 $("#taste_mouthfeel").jqxInput({ disabled: true });
2109 $("#taste_notes").jqxInput({ disabled: true });
2110 $("#notes").jqxInput({ disabled: true });
2111 } else {
2112 $("#notes").jqxInput({ disabled: false });
2113 }
2114 }
2115
2116 function showStarter() {
2117
2118 if (dataRecord.starter_enable) {
2119 $("#propagator").show();
2120 $("#starter_type").jqxDropDownList( {disabled: false });
2121 $("#starter_try").jqxButton({ disabled: false });
2122 $("#starter_sg").jqxNumberInput({ spinButtons: true, readOnly: false, width: 110 });
2123 $("#starter_viability").jqxNumberInput({ spinButtons: true, readOnly: false, width: 110 });
2124 } else {
2125 $("#propagator").hide();
2126 $("#starter_type").jqxDropDownList( {disabled: true });
2127 $("#starter_try").jqxButton({ disabled: true });
2128 $("#starter_sg").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
2129 $("#starter_viability").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
2130 }
2131 }
2132
2133 function calcInit () {
2134 console.log("calcInit()");
2135
2136 calcMashEfficiency();
2137 calcEfficiencyBeforeBoil();
2138 calcEfficiencyAfterBoil();
2139
2140 $("#starter_enable").on('checked', function (event) {
2141 dataRecord.starter_enable = 1;
2142 showStarter();
2143 calcYeast();
2144 });
2145 $("#starter_enable").on('unchecked', function (event) {
2146 dataRecord.starter_enable = 0;
2147 showStarter();
2148 calcYeast();
2149 });
2150 $("#starter_try").click(function () {
2151 $("#prop1_volume").val(0);
2152 $("#prop2_volume").val(0);
2153 $("#prop3_volume").val(0);
2154 $("#prop4_volume").val(0);
2155 calcYeast();
2156 });
2157 $('#starter_type').on('change', function (event) {
2158 if (event.args) {
2159 var index = event.args.index;
2160 dataRecord.starter_type = index;
2161 calcYeast();
2162 }
2163 });
2164 $('#starter_sg').on('change', function (event) {
2165 if (event.args) {
2166 dataRecord.starter_sg = event.args.value;
2167 calcYeast();
2168 }
2169 });
2170 $('#starter_viability').on('change', function (event) {
2171 if (event.args) {
2172 dataRecord.starter_viability = event.args.value;
2173 calcFermentables();
2174 calcYeast();
2175 }
2176 });
2177 $('#prop1_type').on('change', function (event) {
2178 if (event.args) {
2179 var index = event.args.index;
2180 dataRecord.prop1_type = index;
2181 calcYeast();
2182 }
2183 });
2184 $('#prop1_volume').on('change', function (event) {
2185 if (event.args) {
2186 dataRecord.prop1_volume = event.args.value;
2187 calcYeast();
2188 }
2189 });
2190 $('#prop2_type').on('change', function (event) {
2191 if (event.args) {
2192 var index = event.args.index;
2193 dataRecord.prop2_type = index;
2194 calcYeast();
2195 }
2196 });
2197 $('#prop2_volume').on('change', function (event) {
2198 if (event.args) {
2199 dataRecord.prop2_volume = event.args.value;
2200 calcYeast();
2201 }
2202 });
2203 $('#prop3_type').on('change', function (event) {
2204 if (event.args) {
2205 var index = event.args.index;
2206 dataRecord.prop3_type = index;
2207 calcYeast();
2208 }
2209 });
2210 $('#prop3_volume').on('change', function (event) {
2211 if (event.args) {
2212 dataRecord.prop3_volume = event.args.value;
2213 calcYeast();
2214 }
2215 });
2216 $('#prop4_type').on('change', function (event) {
2217 if (event.args) {
2218 var index = event.args.index;
2219 dataRecord.prop4_type = index;
2220 calcYeast();
2221 }
2222 });
2223 $('#prop4_volume').on('change', function (event) {
2224 if (event.args) {
2225 dataRecord.prop4_volume = event.args.value;
2226 calcYeast();
2227 }
2228 });
2229
2230 $("#calc_acid").on('checked', function (event) {
2231 dataRecord.calc_acid = 1;
2232 calcWater();
2233 });
2234 $("#calc_acid").on('unchecked', function (event) {
2235 dataRecord.calc_acid = 0;
2236 calcWater();
2237 });
2238 $("#w1_name").jqxDropDownList('selectItem', dataRecord.w1_name);
2239 $("#w2_name").jqxDropDownList('selectItem', dataRecord.w2_name);
2240 // Fix tap water if zero using mash infuse amount.
2241 if (parseFloat($("#w1_amount").jqxNumberInput('decimal')) == 0 && mash_infuse > 0) {
2242 $("#w1_amount").val(mash_infuse);
2243 dataRecord.w1_amount = mash_infuse;
2244 $("#wg_amount").val(mash_infuse);
2245 $("#w2_amount").val(0);
2246 dataRecord.w2_amount = 0;
2247 }
2248 calcWater();
2249 $("#w2_amount").on('change', function (event) {
2250 var newval = parseFloat(event.args.value);
2251
2252 if (newval > mash_infuse) {
2253 $("#w2_amount").val(dataRecord.w2_amount);
2254 return;
2255 }
2256 dataRecord.w1_amount = parseFloat($("#wg_amount").jqxNumberInput('decimal')) - newval;
2257 $("#w1_amount").val(dataRecord.w1_amount);
2258 dataRecord.w2_amount = newval;
2259 console.log("new: "+event.args.value+" w1: "+dataRecord.w1_amount+" w2: "+dataRecord.w2_amount);
2260 calcWater();
2261 });
2262 $('#wa_cacl2').on('change', function (event) {
2263 if (event.args) {
2264 setWaterAgent('CaCl2', 0); // This can prevent double entries.
2265 setWaterAgent('CaCl2', event.args.value);
2266 calcWater();
2267 }
2268 });
2269 $('#wa_caso4').on('change', function (event) {
2270 if (event.args) {
2271 setWaterAgent('CaSO4', 0);
2272 setWaterAgent('CaSO4', event.args.value);
2273 calcWater();
2274 }
2275 });
2276 $('#wa_mgso4').on('change', function (event) {
2277 if (event.args) {
2278 setWaterAgent('MgSO4', 0);
2279 setWaterAgent('MgSO4', event.args.value);
2280 calcWater();
2281 }
2282 });
2283 $('#wa_nacl').on('change', function (event) {
2284 if (event.args) {
2285 setWaterAgent('NaCl', 0);
2286 setWaterAgent('NaCl', event.args.value);
2287 calcWater();
2288 }
2289 });
2290 $('#wa_base_name').on('change', function (event) {
2291 if (event.args) {
2292 var index = event.args.index;
2293 console.log("wa_base_name "+index);
2294 setWaterAgent(last_base, 0);
2295 last_base = BaseTypeData[index].nl;
2296 setWaterAgent(last_base, parseFloat($("#wa_base").jqxNumberInput('decimal')));
2297 dataRecord.wa_base_name = index;
2298 calcWater();
2299 }
2300 });
2301 $('#wa_base').on('change', function (event) {
2302 var name = BaseTypeData[$("#wa_base_name").val()].nl;
2303 setWaterAgent(name, parseFloat(event.args.value));
2304 calcWater();
2305 });
2306 $('#wa_acid_name').on('change', function (event) {
2307 if (event.args) {
2308 var index = event.args.index;
2309 console.log("wa_acid_name "+index);
2310 setWaterAgent(last_acid, 0);
2311 last_acid = AcidTypeData[index].nl;
2312 setWaterAgent(last_acid, parseFloat($("#wa_acid").jqxNumberInput('decimal')));
2313 dataRecord.wa_acid_name = index;
2314 calcWater();
2315 }
2316 });
2317 $('#wa_acid').on('change', function (event) {
2318 var name = AcidTypeData[$("#wa_acid_name").val()].nl;
2319 setWaterAgent(name, parseFloat(event.args.value));
2320 calcWater();
2321 });
2322 $('#wa_acid_perc').on('change', function (event) { calcWater(); });
2323
2324 $('#color_method').on('change', function (event) {
2325 dataRecord.color_method = event.args.index;
2326 calcFermentables();
2327 });
2328 $('#ibu_method').on('change', function (event) {
2329 dataRecord.ibu_method = event.args.index;
2330 calcFermentables();
2331 calcIBUs();
2332 });
2333
2334 $('#batch_size').on('change', function (event) {
2335 console.log("batch_size change:"+event.args.value+" old:"+dataRecord.batch_size);
2336 $("#est_a_vol").val(event.args.value * 1.04);
2337 var new_boil = parseFloat(event.args.value) + dataRecord.boil_size - dataRecord.batch_size;
2338 var factor = parseFloat(event.args.value) / dataRecord.batch_size;
2339 dataRecord.boil_size = new_boil;
2340 $("#boil_size").val(Math.round(new_boil * 100) / 100);
2341 $("#est_pre_vol").val(Math.round(new_boil * 1.04 * 100) / 100);
2342 dataRecord.sparge_volume *= factor;
2343 $("#sparge_volume").val(dataRecord.sparge_volume);
2344 $("#brew_sparge_volume").val(dataRecord.sparge_volume);
2345 dataRecord.batch_size = parseFloat(event.args.value);
2346 calcFermentablesFromOG(parseFloat($("#est_og").jqxNumberInput('decimal'))); // Keep the OG
2347 adjustWaters(factor);
2348 calcFermentables();
2349 adjustHops(factor);
2350 adjustMiscs(factor);
2351 adjustYeasts(factor);
2352 calcIBUs();
2353 calcWater();
2354 calcSparge();
2355 calcMash();
2356 });
2357 $('#boil_time').on('change', function (event) {
2358 console.log("boil_time change:"+parseFloat(event.args.value)+" old:"+dataRecord.boil_time);
2359 var old_evap = parseFloat(dataRecord.boil_size) - parseFloat(dataRecord.batch_size);
2360 var new_evap = old_evap * (parseFloat(event.args.value) / dataRecord.boil_time);
2361 var new_boil = parseFloat(dataRecord.batch_size) + new_evap;
2362 //var factor = new_boil / dataRecord.boil_size;
2363 dataRecord.boil_time = parseFloat(event.args.value);
2364 dataRecord.boil_size = new_boil;
2365 $("#est_pre_vol").val(Math.round(new_boil * 1.04 * 100) / 100);
2366 $("#boil_size").val(Math.round(new_boil * 100) / 100);
2367 calcFermentables();
2368 calcIBUs();
2369 calcYeast();
2370 });
2371 $('#efficiency').on('change', function (event) {
2372 var estog = parseFloat($("#est_og").jqxNumberInput('decimal'));
2373 dataRecord.efficiency = parseFloat(event.args.value);
2374 console.log("efficiency change:"+dataRecord.efficiency+" est_og:"+estog);
2375 calcFermentablesFromOG(estog); // Keep the OG
2376 calcFermentables();
2377 calcIBUs();
2378 calcYeast();
2379 });
2380 $('#est_og').on('change', function (event) {
2381 dataRecord.est_og = parseFloat(event.args.value);
2382 console.log("est_og change:"+dataRecord.est_og);
2383 $('#est_og2').val(dataRecord.est_og);
2384 calcFermentablesFromOG(dataRecord.est_og); // Adjust fermentables amounts
2385 calcFermentables(); // Update the recipe details
2386 calcIBUs(); // and the IBU's.
2387 calcMash();
2388 calcYeast();
2389 });
2390 $('#mash_ph').on('change', function (event) {
2391 dataRecord.mash_ph = parseFloat(event.args.value);
2392 calcWater();
2393 });
2394
2395 $('#sparge_ph').on('change', function (event) {
2396 dataRecord.sparge_ph = parseFloat(event.args.value);
2397 calcSparge();
2398 });
2399 $('#sparge_volume').on('change', function (event) {
2400 dataRecord.sparge_volume = parseFloat(event.args.value);
2401 $('#brew_sparge_volume').val(dataRecord.sparge_volume);
2402 calcSparge();
2403 });
2404 $("#sparge_temp").on('change', function (event) {
2405 dataRecord.sparge_temp = parseFloat(event.args.value);
2406 $('#brew_sparge_temperature').val(dataRecord.sparge_temp);
2407 });
2408 $('#sparge_source').on('change', function (event) {
2409 if (event.args) {
2410 var index = event.args.index;
2411 dataRecord.sparge_source= index;
2412 calcSparge();
2413 }
2414 });
2415 $('#sparge_acid_type').on('change', function (event) {
2416 if (event.args) {
2417 var index = event.args.index;
2418 dataRecord.sparge_acid_type = index;
2419 console.log("new sparge_acid_type: "+dataRecord.sparge_acid_type);
2420 calcSparge();
2421 }
2422 });
2423 $('#sparge_acid_perc').on('change', function (event) {
2424 dataRecord.sparge_acid_perc = parseFloat(event.args.value);
2425 calcSparge();
2426 });
2427
2428 calcFermentation();
2429 calcCarbonation();
2430 $('#package_volume').on('change', function (event) {
2431 var told = dataRecord.package_volume + dataRecord.package_infuse_amount;
2432 dataRecord.package_volume = parseFloat(event.args.value);
2433 if (dataRecord.package_volume > dataRecord.brew_fermenter_volume) {
2434 dataRecord.package_volume = dataRecord.brew_fermenter_volume;
2435 $('#package_volume').val(dataRecord.package_volume);
2436 }
2437 var tnew = dataRecord.package_volume + dataRecord.package_infuse_amount;
2438 var diff = tnew - told;
2439 if (told > 0) {
2440 dataRecord.bottle_amount += (dataRecord.bottle_amount / told) * diff;
2441 dataRecord.keg_amount += (dataRecord.keg_amount / told) * diff;
2442 } else {
2443 dataRecord.bottle_amount = tnew;
2444 dataRecord.keg_amount = 0;
2445 }
2446 console.log("diff:"+diff+" old:"+told+" bottle:"+dataRecord.bottle_amount+" keg:"+dataRecord.keg_amount);
2447 $('#bottle_amount').val(parseFloat(dataRecord.bottle_amount * 1000) / 1000);
2448 $('#keg_amount').val(parseFloat(dataRecord.keg_amount * 1000) / 1000);
2449 calcCarbonation();
2450 });
2451 $('#package_infuse_amount').on('change', function (event) {
2452 var told = dataRecord.package_volume + dataRecord.package_infuse_amount;
2453 dataRecord.package_infuse_amount = parseFloat(event.args.value);
2454 var tnew = dataRecord.package_volume + dataRecord.package_infuse_amount;
2455 var diff = tnew - told;
2456 if (told > 0) {
2457 dataRecord.bottle_amount += (dataRecord.bottle_amount / told) * diff;
2458 dataRecord.keg_amount += (dataRecord.keg_amount / told) * diff;
2459 } else {
2460 dataRecord.bottle_amount = tnew;
2461 dataRecord.keg_amount = 0;
2462 }
2463 console.log("diff:"+diff+" old:"+told+" bottle:"+dataRecord.bottle_amount+" keg:"+dataRecord.keg_amount);
2464 $('#bottle_amount').val(parseFloat(dataRecord.bottle_amount * 1000) / 1000);
2465 $('#keg_amount').val(parseFloat(dataRecord.keg_amount * 1000) / 1000);
2466 calcCarbonation();
2467 });
2468 $('#package_infuse_abv').on('change', function (event) {
2469 dataRecord.package_infuse_abv = parseFloat(event.args.value);
2470 calcCarbonation();
2471 });
2472 $('#bottle_amount').on('change', function (event) {
2473 var vnew = parseFloat(event.args.value);
2474 var vtot = dataRecord.package_volume + dataRecord.package_infuse_amount;
2475 if (vnew > vtot)
2476 vnew = vtot;
2477 diff = dataRecord.bottle_amount - vnew;
2478 dataRecord.bottle_amount = Math.round((dataRecord.bottle_amount - diff) * 1000) / 1000;
2479 dataRecord.keg_amount = Math.round((dataRecord.keg_amount + diff) * 1000) / 1000;
2480 $('#bottle_amount').val(parseFloat(dataRecord.bottle_amount));
2481 $('#keg_amount').val(parseFloat(dataRecord.keg_amount));
2482 calcCarbonation();
2483 });
2484 $("#bottle_priming_water").on('change', function (event) {
2485 dataRecord.bottle_priming_water = parseFloat(event.args.value);
2486 calcCarbonation();
2487 });
2488 $('#keg_amount').on('change', function (event) {
2489 var vnew = parseFloat(event.args.value);
2490 var vtot = dataRecord.package_volume + dataRecord.package_infuse_amount;
2491 if (vnew > vtot)
2492 vnew = vtot;
2493 diff = dataRecord.keg_amount - vnew;
2494 dataRecord.bottle_amount = Math.round((dataRecord.bottle_amount + diff) * 1000) / 1000;
2495 dataRecord.keg_amount = Math.round((dataRecord.keg_amount - diff) * 1000) / 1000;
2496 $('#bottle_amount').val(parseFloat(dataRecord.bottle_amount));
2497 $('#keg_amount').val(parseFloat(dataRecord.keg_amount));
2498 calcCarbonation();
2499 });
2500 $("#keg_priming_water").on('change', function (event) {
2501 dataRecord.keg_priming_water = parseFloat(event.args.value);
2502 calcCarbonation();
2503 });
2504 $('#bottle_carbonation').on('change', function (event) {
2505 dataRecord.bottle_carbonation = parseFloat(event.args.value);
2506 calcCarbonation();
2507 });
2508 $('#bottle_carbonation_temp').on('change', function (event) {
2509 dataRecord.bottle_carbonation_temp = parseFloat(event.args.value);
2510 calcCarbonation();
2511 });
2512 $('#keg_carbonation').on('change', function (event) {
2513 dataRecord.keg_carbonation = parseFloat(event.args.value);
2514 calcCarbonation();
2515 });
2516 $("#keg_forced_carb").on('checked', function (event) {
2517 dataRecord.keg_forced_carb = 1;
2518 calcCarbonation();
2519 });
2520 $("#keg_forced_carb").on('unchecked', function (event) {
2521 dataRecord.keg_forced_carb = 0;
2522 calcCarbonation();
2523 });
2524 $('#keg_carbonation_temp').on('change', function (event) {
2525 dataRecord.keg_carbonation_temp = parseFloat(event.args.value);
2526 calcCarbonation();
2527 });
2528
2529 $("#brew_fermenter_extrawater").on('change',function (event){
2530 dataRecord.brew_fermenter_extrawater=parseFloat(event.args.value);calcFermentables();calcIBUs();calcYeast();
2531 });
2532 $("#brew_fermenter_tcloss").on('change',function (event){
2533 dataRecord.brew_fermenter_tcloss=parseFloat(event.args.value);calcFermentables();calcIBUs();calcYeast();
2534 });
2535 $("#primary_end_sg").on('change',function (event){dataRecord.primary_end_sg=parseFloat(event.args.value);calcFermentation();});
2536 $("#primary_end_brix").on('change', function (event) {
2537 if(dataRecord.brew_fermenter_sg>=1.020){
2538 OBrix=sg_to_brix(dataRecord.brew_fermenter_sg);
2539 FBrix=parseFloat(event.args.value);
2540 var FG=Round(1.0031-0.002318474*OBrix-0.000007775*(OBrix*OBrix)-0.000000034*Math.pow(OBrix,3)+0.00574*(FBrix)+0.00003344*(FBrix*FBrix)+0.000000086*Math.pow(FBrix,3),4);
2541 //console.log("OBrix:"+OBrix+" FBrix:"+FBrix+" FG:"+FG);
2542 if(FBrix>0.05){$("#primary_end_sg").val(FG);dataRecord.primary_end_sg=FG;}
2543 calcFermentation();
2544 }
2545 });
2546 $("#secondary_end_sg").on('change',function (event){dataRecord.secondary_end_sg=parseFloat(event.args.value);calcFermentation();});
2547 $("#secondary_end_brix").on('change', function (event) {
2548 if(dataRecord.brew_fermenter_sg>=1.020){
2549 OBrix=sg_to_brix(dataRecord.brew_fermenter_sg);
2550 FBrix=parseFloat(event.args.value);
2551 var FG=Round(1.0031-0.002318474*OBrix-0.000007775*(OBrix*OBrix)-0.000000034*Math.pow(OBrix,3)+0.00574*(FBrix)+0.00003344*(FBrix*FBrix)+0.000000086*Math.pow(FBrix,3),4);
2552 //console.log("OBrix:"+OBrix+" FBrix:"+FBrix+" FG:"+FG);
2553 if(FBrix>0.05){$("#secondary_end_sg").val(FG);dataRecord.secondary_end_sg=FG;}
2554 calcFermentation();
2555 }
2556 });
2557 $("#final_brix").on('change',function (event){
2558 if(dataRecord.brew_fermenter_sg>=1.020){
2559 OBrix=sg_to_brix(dataRecord.brew_fermenter_sg);
2560 FBrix=parseFloat(event.args.value);
2561 var FG=Round(1.0031-0.002318474*OBrix-0.000007775*(OBrix*OBrix)-0.000000034*Math.pow(OBrix,3)+0.00574*(FBrix)+0.00003344*(FBrix*FBrix)+0.000000086*Math.pow(FBrix,3),4);
2562 // Ook brouwhulp SGFerm() maar is niet in gebruik.
2563 //var FG=((1.001843-0.002318474*OBrix-0.000007775*(OBrix*OBrix)-0.000000034*Math.pow(OBrix,3)+0.00574*(FBrix)+0.00003344*(FBrix*FBrix)+0.000000086*Math.pow(FBrix,3))+(1.313454)*0.001);
2564 //console.log("OBrix:"+OBrix+" FBrix:"+FBrix+" FG:"+FG);
2565 if(FBrix>0.05){$("#fg").val(FG);dataRecord.fg=FG;}
2566 calcFermentation();
2567 }
2568 });
2569 $("#fg").on('change',function (event){dataRecord.fg=parseFloat(event.args.value);calcFermentation();});
2570 $("#BLog").jqxButton({disabled:(dataRecord.log_brew)?false:true});
2571 $("#FLog").jqxButton({disabled:(dataRecord.log_fermentation)?false:true});
2572 };
2573
2574 $("#styleSelect").jqxDropDownList({
2575 placeHolder: "Kies bierstijl:",
2576 theme: theme,
2577 source: styleslist,
2578 displayMember: "name",
2579 width: 180,
2580 height: 23,
2581 dropDownVerticalAlignment: 'top',
2582 dropDownWidth: 500,
2583 dropDownHeight: 380,
2584 renderer: function (index, label, value) {
2585 var datarecord = styleslist.records[index];
2586 return datarecord.style_guide + " " + datarecord.style_letter+ " " + datarecord.name;
2587 }
2588 });
2589 $("#styleSelect").on('select', function (event) {
2590 if (event.args) {
2591 var index = event.args.index;
2592 var datarecord = styleslist.records[index];
2593 $("#st_name").val(datarecord.name);
2594 $("#st_category").val(datarecord.category);
2595 $("#st_category_number").val(datarecord.category_number);
2596 $("#st_letter").val(datarecord.style_letter);
2597 $("#st_guide").val(datarecord.style_guide);
2598 $("#st_type").val(StyleTypeData[datarecord.type].nl);
2599 $("#st_og_min").val(datarecord.og_min);
2600 $("#st_og_max").val(datarecord.og_max);
2601 $("#st_fg_min").val(datarecord.fg_min);
2602 $("#st_fg_max").val(datarecord.fg_max);
2603 $("#st_ibu_min").val(datarecord.ibu_min);
2604 $("#st_ibu_max").val(datarecord.ibu_max);
2605 $("#st_color_min").val(datarecord.color_min);
2606 $("#st_color_max").val(datarecord.color_max);
2607 $("#st_carb_min").val(datarecord.carb_min);
2608 $("#st_carb_min2").val(datarecord.carb_min);
2609 $("#st_carb_max").val(datarecord.carb_max);
2610 $("#st_carb_max2").val(datarecord.carb_max);
2611 $("#st_abv_min").val(datarecord.abv_min);
2612 $("#st_abv_max").val(datarecord.abv_max);
2613 }
2614 });
2615
2616 // Equipemnt dropdown list
2617 $("#equipmentSelect").jqxDropDownList({
2618 placeHolder: "Kies apparatuur:",
2619 theme: theme,
2620 source: equipmentlist,
2621 displayMember: "name",
2622 width: 170,
2623 height: 23,
2624 dropDownWidth: 300,
2625 renderer: function (index, label, value) {
2626 var datarecord = equipmentlist.records[index];
2627 return datarecord.batch_size + " liter " + datarecord.name;
2628 }
2629 });
2630 $("#equipmentSelect").on('select', function (event) {
2631 if (event.args) {
2632 var index = event.args.index;
2633 var datarecord = equipmentlist.records[index];
2634 var factor = datarecord.batch_size / dataRecord.batch_size;
2635 $("#eq_name").val(datarecord.name);
2636 $("#eq_boil_size").val(datarecord.boil_size);
2637 dataRecord.boil_size = datarecord.boil_size;
2638 $("#boil_size").val(datarecord.boil_size);
2639 $("#eq_batch_size").val(datarecord.batch_size);
2640 dataRecord.batch_size = datarecord.batch_size;
2641 $("#batch_size").val(datarecord.batch_size);
2642 $("#est_a_vol").val(datarecord.batch_size * 1.04);
2643 $("#eq_tun_volume").val(datarecord.tun_volume);
2644 dataRecord.eq_tun_weight = datarecord.tun_weight;
2645 dataRecord.eq_tun_specific_heat = datarecord.tun_specific_heat;
2646 dataRecord.eq_tun_material = datarecord.tun_material;
2647 dataRecord.eq_tun_height = datarecord.tun_height / 100.0;
2648 $("#eq_top_up_water").val(datarecord.top_up_water);
2649 dataRecord.eq_trub_chiller_loss = datarecord.trub_chiller_loss;
2650 $("#eq_trub_chiller_loss").val(datarecord.trub_chiller_loss);
2651 $("#eq_evap_rate").val(datarecord.evap_rate);
2652 $("#eq_boil_time").val(datarecord.boil_time);
2653 dataRecord.eq_calc_boil_volume = datarecord.calc_boil_volume;
2654 $("#eq_top_up_kettle").val(datarecord.top_up_kettle);
2655 $("#eq_hop_utilization").val(datarecord.hop_utilization);
2656 $("#eq_notes").val(datarecord.notes);
2657 $("#eq_lauter_volume").val(datarecord.lauter_volume);
2658 dataRecord.eq_lauter_height = datarecord.lauter_height / 100.0;
2659 $("#eq_lauter_deadspace").val(datarecord.lauter_deadspace);
2660 $("#eq_kettle_volume").val(datarecord.kettle_volume);
2661 dataRecord.eq_kettle_height = datarecord.kettle_height / 100.0;
2662 $("#eq_mash_volume").val(datarecord.mash_volume);
2663 $("#eq_mash_max").val(datarecord.mash_max);
2664 dataRecord.eq_mash_max = datarecord.mash_max;
2665 $("#mash_max").val(datarecord.mash_max);
2666 $("#eq_efficiency").val(datarecord.efficiency);
2667 dataRecord.efficiency = datarecord.efficiency;
2668 $("#efficiency").val(datarecord.efficiency);
2669
2670 dataRecord.sparge_volume = Math.round(datarecord.boil_size * 5) / 10;
2671 $("#sparge_volume").val(dataRecord.sparge_volume);
2672 $("#brew_sparge_volume").val(dataRecord.sparge_volume);
2673 $("#est_pre_vol").val(datarecord.boil_size * 1.04);
2674 calcFermentablesFromOG(parseFloat($("#est_og").jqxNumberInput('decimal'))); // Keep the OG
2675 adjustWaters(factor);
2676 calcFermentables();
2677 adjustHops(factor);
2678 adjustMiscs(factor);
2679 adjustYeasts(factor);
2680 calcIBUs();
2681 calcWater();
2682 calcSparge();
2683 }
2684 });
2685
2686 function saveRecord() {
2687 console.log("saveRecord()");
2688 var fermentablerow = $('#fermentableGrid').jqxGrid('getrows');
2689 var hoprow = $('#hopGrid').jqxGrid('getrows');
2690 var miscrow = $('#miscGrid').jqxGrid('getrows');
2691 var yeastrow = $('#yeastGrid').jqxGrid('getrows');
2692 var mashrow = $('#mashGrid').jqxGrid('getrows');
2693 var row = {
2694 record: my_record,
2695 uuid: dataRecord.uuid,
2696 name: $("#name").val(),
2697 code: $("#code").val(),
2698 birth: $("#birth").val(),
2699 stage: dataRecord.stage,
2700 notes: $("#notes").val(),
2701 log_brew: dataRecord.log_brew,
2702 log_fermentation: dataRecord.log_fermentation,
2703 inventory_reduced: dataRecord.inventory_reduced,
2704 locked: dataRecord.locked,
2705 eq_name: $("#eq_name").val(),
2706 eq_boil_size: parseFloat($("#eq_boil_size").jqxNumberInput('decimal')),
2707 eq_batch_size: parseFloat($("#eq_batch_size").jqxNumberInput('decimal')),
2708 eq_tun_volume: parseFloat($("#eq_tun_volume").jqxNumberInput('decimal')),
2709 eq_tun_weight: dataRecord.eq_tun_weight,
2710 eq_tun_specific_heat: dataRecord.eq_tun_specific_heat,
2711 eq_tun_material: dataRecord.eq_tun_material,
2712 eq_tun_height: dataRecord.eq_tun_height,
2713 eq_top_up_water: parseFloat($("#eq_top_up_water").jqxNumberInput('decimal')),
2714 eq_trub_chiller_loss: parseFloat($("#eq_trub_chiller_loss").jqxNumberInput('decimal')),
2715 eq_evap_rate: parseFloat($("#eq_evap_rate").jqxNumberInput('decimal')),
2716 eq_boil_time: parseFloat($("#eq_boil_time").jqxNumberInput('decimal')),
2717 eq_calc_boil_volume: dataRecord.eq_calc_boil_volume,
2718 eq_top_up_kettle: parseFloat($("#eq_top_up_kettle").jqxNumberInput('decimal')),
2719 eq_hop_utilization: parseFloat($("#eq_hop_utilization").jqxNumberInput('decimal')),
2720 eq_notes: $("#eq_notes").val(),
2721 eq_lauter_volume: parseFloat($("#eq_lauter_volume").jqxNumberInput('decimal')),
2722 eq_lauter_height: dataRecord.eq_lauter_height,
2723 eq_lauter_deadspace: parseFloat($("#eq_lauter_deadspace").jqxNumberInput('decimal')),
2724 eq_kettle_volume: parseFloat($("#eq_kettle_volume").jqxNumberInput('decimal')),
2725 eq_kettle_height: dataRecord.eq_kettle_height,
2726 eq_mash_volume: parseFloat($("#eq_mash_volume").jqxNumberInput('decimal')),
2727 eq_mash_max: parseFloat($("#eq_mash_max").jqxNumberInput('decimal')),
2728 eq_efficiency: parseFloat($("#eq_efficiency").jqxNumberInput('decimal')),
2729 brew_date_start: $("#brew_date_start").val(),
2730 brew_mash_ph: parseFloat($("#brew_mash_ph").jqxNumberInput('decimal')),
2731 brew_mash_sg: parseFloat($("#brew_mash_sg").jqxNumberInput('decimal')),
2732 brew_mash_efficiency: parseFloat($("#brew_mash_efficiency").jqxNumberInput('decimal')),
2733 brew_sparge_est: parseFloat($("#brew_sparge_est").jqxNumberInput('decimal')),
2734 brew_sparge_ph: parseFloat($("#brew_sparge_ph").jqxNumberInput('decimal')),
2735 brew_preboil_volume: parseFloat($("#brew_preboil_volume").jqxNumberInput('decimal')),
2736 brew_preboil_sg: parseFloat($("#brew_preboil_sg").jqxNumberInput('decimal')),
2737 brew_preboil_ph: parseFloat($("#brew_preboil_ph").jqxNumberInput('decimal')),
2738 brew_preboil_efficiency: parseFloat($("#brew_preboil_efficiency").jqxNumberInput('decimal')),
2739 brew_aboil_volume: parseFloat($("#brew_aboil_volume").jqxNumberInput('decimal')),
2740 brew_aboil_sg: parseFloat($("#brew_aboil_sg").jqxNumberInput('decimal')),
2741 brew_aboil_ph: parseFloat($("#brew_aboil_ph").jqxNumberInput('decimal')),
2742 brew_aboil_efficiency: parseFloat($("#brew_aboil_efficiency").jqxNumberInput('decimal')),
2743 brew_cooling_method: $("#brew_cooling_method").val(),
2744 brew_cooling_time: parseFloat($("#brew_cooling_time").jqxNumberInput('decimal')),
2745 brew_cooling_to: parseFloat($("#brew_cooling_to").jqxNumberInput('decimal')),
2746 brew_whirlpool9: parseFloat($("#brew_whirlpool9").jqxNumberInput('decimal')),
2747 brew_whirlpool7: parseFloat($("#brew_whirlpool7").jqxNumberInput('decimal')),
2748 brew_whirlpool6: parseFloat($("#brew_whirlpool6").jqxNumberInput('decimal')),
2749 brew_whirlpool2: parseFloat($("#brew_whirlpool2").jqxNumberInput('decimal')),
2750 brew_fermenter_volume: parseFloat($("#brew_fermenter_volume").jqxNumberInput('decimal')),
2751 brew_fermenter_extrawater: parseFloat($("#brew_fermenter_extrawater").jqxNumberInput('decimal')),
2752 brew_fermenter_tcloss: parseFloat($("#brew_fermenter_tcloss").jqxNumberInput('decimal')),
2753 brew_aeration_time: parseFloat($("#brew_aeration_time").jqxNumberInput('decimal')),
2754 brew_aeration_speed: parseFloat($("#brew_aeration_speed").jqxNumberInput('decimal')),
2755 brew_aeration_type: $("#brew_aeration_type").val(),
2756 brew_fermenter_sg: parseFloat($("#brew_fermenter_sg").jqxNumberInput('decimal')),
2757 brew_fermenter_ibu: parseFloat($("#brew_fermenter_ibu").jqxNumberInput('decimal')),
2758 brew_fermenter_color: parseFloat($("#brew_fermenter_color").jqxNumberInput('decimal')),
2759 brew_date_end: $("#brew_date_end").val(),
2760 og: dataRecord.og,
2761 fg: parseFloat($("#fg").jqxNumberInput('decimal')),
2762 primary_start_temp: parseFloat($("#primary_start_temp").jqxNumberInput('decimal')),
2763 primary_max_temp: parseFloat($("#primary_max_temp").jqxNumberInput('decimal')),
2764 primary_end_temp: parseFloat($("#primary_end_temp").jqxNumberInput('decimal')),
2765 primary_end_sg: parseFloat($("#primary_end_sg").jqxNumberInput('decimal')),
2766 primary_end_date: $("#primary_end_date").val(),
2767 secondary_temp: parseFloat($("#secondary_temp").jqxNumberInput('decimal')),
2768 secondary_end_sg: parseFloat($("#secondary_end_sg").jqxNumberInput('decimal')),
2769 secondary_end_date: $("#secondary_end_date").val(),
2770 tertiary_temp: parseFloat($("#tertiary_temp").jqxNumberInput('decimal')),
2771 package_date: $("#package_date").val(),
2772 package_volume: parseFloat($("#package_volume").jqxNumberInput('decimal')),
2773 package_infuse_amount: parseFloat($("#package_infuse_amount").jqxNumberInput('decimal')),
2774 package_infuse_abv: parseFloat($("#package_infuse_abv").jqxNumberInput('decimal')),
2775 package_infuse_notes: $("#package_infuse_notes").val(),
2776 package_abv: parseFloat($("#package_abv").jqxNumberInput('decimal')),
2777 package_ph: parseFloat($("#package_ph").jqxNumberInput('decimal')),
2778 bottle_amount: parseFloat($("#bottle_amount").jqxNumberInput('decimal')),
2779 bottle_carbonation: parseFloat($("#bottle_carbonation").jqxNumberInput('decimal')),
2780 bottle_priming_water: parseFloat($("#bottle_priming_water").jqxNumberInput('decimal')),
2781 bottle_priming_amount: parseFloat($("#bottle_priming_amount").jqxNumberInput('decimal')),
2782 bottle_carbonation_temp: parseFloat($("#bottle_carbonation_temp").jqxNumberInput('decimal')),
2783 keg_amount: parseFloat($("#keg_amount").jqxNumberInput('decimal')),
2784 keg_carbonation: parseFloat($("#keg_carbonation").jqxNumberInput('decimal')),
2785 keg_priming_water: parseFloat($("#keg_priming_water").jqxNumberInput('decimal')),
2786 keg_priming_amount: parseFloat($("#keg_priming_amount").jqxNumberInput('decimal')),
2787 keg_carbonation_temp: parseFloat($("#keg_carbonation_temp").jqxNumberInput('decimal')),
2788 keg_forced_carb: dataRecord.keg_forced_carb,
2789 keg_pressure: parseFloat($("#keg_pressure").jqxNumberInput('decimal')),
2790 taste_notes: $("#taste_notes").val(),
2791 taste_rate: parseFloat($("#taste_rate").jqxNumberInput('decimal')),
2792 taste_date: $("#taste_date").val(),
2793 taste_color: $("#taste_color").val(),
2794 taste_transparency: $("#taste_transparency").val(),
2795 taste_head: $("#taste_head").val(),
2796 taste_aroma: $("#taste_aroma").val(),
2797 taste_taste: $("#taste_taste").val(),
2798 taste_mouthfeel: $("#taste_mouthfeel").val(),
2799 taste_aftertaste: $("#taste_aftertaste").val(),
2800 st_name: $('#st_name').val(),
2801 st_letter: $('#st_letter').val(),
2802 st_guide: $('#st_guide').val(),
2803 st_type: dataRecord.st_type,
2804 st_category: $('#st_category').val(),
2805 st_category_number: parseFloat($("#st_category_number").jqxNumberInput('decimal')),
2806 st_og_min: parseFloat($("#st_og_min").jqxNumberInput('decimal')),
2807 st_og_max: parseFloat($("#st_og_max").jqxNumberInput('decimal')),
2808 st_fg_min: parseFloat($("#st_fg_min").jqxNumberInput('decimal')),
2809 st_fg_max: parseFloat($("#st_fg_max").jqxNumberInput('decimal')),
2810 st_ibu_min: parseFloat($("#st_ibu_min").jqxNumberInput('decimal')),
2811 st_ibu_max: parseFloat($("#st_ibu_max").jqxNumberInput('decimal')),
2812 st_color_min: parseFloat($("#st_color_min").jqxNumberInput('decimal')),
2813 st_color_max: parseFloat($("#st_color_max").jqxNumberInput('decimal')),
2814 st_carb_min: parseFloat($("#st_carb_min").jqxNumberInput('decimal')),
2815 st_carb_max: parseFloat($("#st_carb_max").jqxNumberInput('decimal')),
2816 st_abv_min: parseFloat($("#st_abv_min").jqxNumberInput('decimal')),
2817 st_abv_max: parseFloat($("#st_abv_max").jqxNumberInput('decimal')),
2818 type: $("#type").val(),
2819 batch_size: parseFloat($("#batch_size").jqxNumberInput('decimal')),
2820 boil_size: parseFloat($("#boil_size").jqxNumberInput('decimal')),
2821 boil_time: parseFloat($("#boil_time").jqxNumberInput('decimal')),
2822 efficiency: parseFloat($("#efficiency").jqxNumberInput('decimal')),
2823 est_og: parseFloat($("#est_og").jqxNumberInput('decimal')),
2824 est_fg: parseFloat($("#est_fg").jqxNumberInput('decimal')),
2825 est_abv: parseFloat($("#est_abv").jqxNumberInput('decimal')),
2826 est_color: parseFloat($("#est_color").jqxNumberInput('decimal')),
2827 color_method: $("#color_method").val(),
2828 est_ibu: parseFloat($("#est_ibu").jqxNumberInput('decimal')),
2829 ibu_method: $("#ibu_method").val(),
2830 est_carb: parseFloat($("#est_carb").jqxNumberInput('decimal')),
2831 mash_name: $("#mash_name").val(),
2832 mash_ph: parseFloat($("#mash_ph").jqxNumberInput('decimal')),
2833 sparge_temp: parseFloat($("#sparge_temp").jqxNumberInput('decimal')),
2834 sparge_ph: parseFloat($("#sparge_ph").jqxNumberInput('decimal')),
2835 sparge_volume: parseFloat($("#sparge_volume").jqxNumberInput('decimal')),
2836 sparge_source: $("#sparge_source").val(),
2837 sparge_acid_type: $("#sparge_acid_type").val(),
2838 sparge_acid_perc: parseFloat($("#sparge_acid_perc").jqxNumberInput('decimal')),
2839 sparge_acid_amount: dataRecord.sparge_acid_amount,
2840 calc_acid: dataRecord.calc_acid,
2841 w1_name: $("#w1_name").val(),
2842 w1_amount: parseFloat($("#w1_amount").jqxNumberInput('decimal')),
2843 w1_calcium: parseFloat($("#w1_calcium").jqxNumberInput('decimal')),
2844 w1_sulfate: parseFloat($("#w1_sulfate").jqxNumberInput('decimal')),
2845 w1_chloride: parseFloat($("#w1_chloride").jqxNumberInput('decimal')),
2846 w1_sodium: parseFloat($("#w1_sodium").jqxNumberInput('decimal')),
2847 w1_magnesium: parseFloat($("#w1_magnesium").jqxNumberInput('decimal')),
2848 w1_total_alkalinity: parseFloat($("#w1_total_alkalinity").jqxNumberInput('decimal')),
2849 w1_ph: parseFloat($("#w1_ph").jqxNumberInput('decimal')),
2850 w1_cost: dataRecord.w1_cost,
2851 w2_name: $("#w2_name").val(),
2852 w2_amount: parseFloat($("#w2_amount").jqxNumberInput('decimal')),
2853 w2_calcium: parseFloat($("#w2_calcium").jqxNumberInput('decimal')),
2854 w2_sulfate: parseFloat($("#w2_sulfate").jqxNumberInput('decimal')),
2855 w2_chloride: parseFloat($("#w2_chloride").jqxNumberInput('decimal')),
2856 w2_sodium: parseFloat($("#w2_sodium").jqxNumberInput('decimal')),
2857 w2_magnesium: parseFloat($("#w2_magnesium").jqxNumberInput('decimal')),
2858 w2_total_alkalinity: parseFloat($("#w2_total_alkalinity").jqxNumberInput('decimal')),
2859 w2_ph: parseFloat($("#w2_ph").jqxNumberInput('decimal')),
2860 w2_cost: dataRecord.w2_cost,
2861 wg_amount: parseFloat($("#wg_amount").jqxNumberInput('decimal')),
2862 wg_calcium: parseFloat($("#wg_calcium").jqxNumberInput('decimal')),
2863 wg_sulfate: parseFloat($("#wg_sulfate").jqxNumberInput('decimal')),
2864 wg_chloride: parseFloat($("#wg_chloride").jqxNumberInput('decimal')),
2865 wg_sodium: parseFloat($("#wg_sodium").jqxNumberInput('decimal')),
2866 wg_magnesium: parseFloat($("#wg_magnesium").jqxNumberInput('decimal')),
2867 wg_total_alkalinity: parseFloat($("#wg_total_alkalinity").jqxNumberInput('decimal')),
2868 wg_ph: parseFloat($("#wg_ph").jqxNumberInput('decimal')),
2869 wb_calcium: parseFloat($("#wb_calcium").jqxNumberInput('decimal')),
2870 wb_sulfate: parseFloat($("#wb_sulfate").jqxNumberInput('decimal')),
2871 wb_chloride: parseFloat($("#wb_chloride").jqxNumberInput('decimal')),
2872 wb_sodium: parseFloat($("#wb_sodium").jqxNumberInput('decimal')),
2873 wb_magnesium: parseFloat($("#wb_magnesium").jqxNumberInput('decimal')),
2874 wb_total_alkalinity: parseFloat($("#wb_total_alkalinity").jqxNumberInput('decimal')),
2875 wb_ph: parseFloat($("#wb_ph").jqxNumberInput('decimal')),
2876 wa_acid_name: $("#wa_acid_name").val(),
2877 wa_acid_perc: parseFloat($("#wa_acid_perc").jqxNumberInput('decimal')),
2878 wa_base_name: $("#wa_base_name").val(),
2879 starter_enable: dataRecord.starter_enable,
2880 starter_type: $("#starter_type").val(),
2881 starter_sg: parseFloat($("#starter_sg").jqxNumberInput('decimal')),
2882 starter_viability: parseFloat($("#starter_viability").jqxNumberInput('decimal')),
2883 prop1_type: $("#prop1_type").val(),
2884 prop1_volume: parseFloat($("#prop1_volume").jqxNumberInput('decimal')),
2885 prop2_type: $("#prop2_type").val(),
2886 prop2_volume: parseFloat($("#prop2_volume").jqxNumberInput('decimal')),
2887 prop3_type: $("#prop3_type").val(),
2888 prop3_volume: parseFloat($("#prop3_volume").jqxNumberInput('decimal')),
2889 prop4_type: $("#prop4_type").val(),
2890 prop4_volume: parseFloat($("#prop4_volume").jqxNumberInput('decimal')),
2891 fermentables: fermentablerow,
2892 hops: hoprow,
2893 miscs: miscrow,
2894 yeasts: yeastrow,
2895 mashs: mashrow
2896 };
2897 var data = "update=true&" + $.param(row);
2898 $.ajax({
2899 dataType: 'json',
2900 url: url,
2901 cache: false,
2902 data: data,
2903 async: false,
2904 type: "POST",
2905 success: function (data, status, xhr) {
2906 console.log("saveRecord() success");
2907 },
2908 error: function(jqXHR, textStatus, errorThrown) {
2909 console.log("saveRecord() error");
2910 }
2911 });
2912 };
2913
2914 var dataRecord = {};
2915 var url = "includes/db_product.php";
2916 103
2917 // Prepare the data 104 // Prepare the data
2918 var source = { 105 source = {
2919 datatype: "json", 106 datatype: "json",
2920 cache: false, 107 cache: false,
2921 datafields: [ 108 datafields: [
2922 // From prod_main 109 // From prod_main
2923 { name: 'record', type: 'number' }, 110 { name: 'record', type: 'number' },
3123 { name: 'yeasts', type: 'array' }, 310 { name: 'yeasts', type: 'array' },
3124 { name: 'mashs', type: 'array' } 311 { name: 'mashs', type: 'array' }
3125 ], 312 ],
3126 id: 'record', 313 id: 'record',
3127 url: url + '?record=' + my_record 314 url: url + '?record=' + my_record
3128 }; 315 },
3129 // Load data and select one record. 316 // Load data and select one record.
3130 var dataAdapter = new $.jqx.dataAdapter(source, { 317 dataAdapter = new $.jqx.dataAdapter(source, {
3131 loadComplete: function () { 318 loadComplete: function () {
3132 var records = dataAdapter.records; 319 var records = dataAdapter.records;
3133 dataRecord = records[0]; 320 dataRecord = records[0];
3134 // Hidden record uuid 321 // Hidden record uuid
3135 $("#name").val(dataRecord.name); 322 $("#name").val(dataRecord.name);
3352 loadError: function (jqXHR, status, error) { 539 loadError: function (jqXHR, status, error) {
3353 }, 540 },
3354 beforeLoadComplete: function (records) { 541 beforeLoadComplete: function (records) {
3355 $('#jqxLoader').jqxLoader('open'); 542 $('#jqxLoader').jqxLoader('open');
3356 } 543 }
3357 }); 544 }),
3358 dataAdapter.dataBind();
3359 545
3360 // Inline fermentables editor 546 // Inline fermentables editor
3361 var editFermentable = function (data) { 547 editFermentable = function (data) {
3362 var fermentableSource = { 548 var fermentableSource = {
3363 localdata: data.fermentables, 549 localdata: data.fermentables,
3364 datatype: "local", 550 datatype: "local",
3365 cache: false, 551 cache: false,
3366 async: false, 552 async: false,
3400 }, 586 },
3401 updaterow: function (rowid, rowdata, commit) { 587 updaterow: function (rowid, rowdata, commit) {
3402 //console.log("fermentable updaterow "+rowid); 588 //console.log("fermentable updaterow "+rowid);
3403 commit(true); 589 commit(true);
3404 } 590 }
3405 }; 591 },
3406 var fermentableAdapter = new $.jqx.dataAdapter(fermentableSource); 592 fermentableAdapter = new $.jqx.dataAdapter(fermentableSource);
593
3407 $("#fermentableGrid").jqxGrid({ 594 $("#fermentableGrid").jqxGrid({
3408 width: 1240, 595 width: 1240,
3409 height: 470, 596 height: 470,
3410 source: fermentableAdapter, 597 source: fermentableAdapter,
3411 theme: theme, 598 theme: theme,
3435 return datarecord.supplier+ " / " + datarecord.name + " (" + datarecord.color + " EBC)"; 622 return datarecord.supplier+ " / " + datarecord.name + " (" + datarecord.color + " EBC)";
3436 } 623 }
3437 }); 624 });
3438 $("#faddrowbutton").on('select', function (event) { 625 $("#faddrowbutton").on('select', function (event) {
3439 if (event.args) { 626 if (event.args) {
3440 var rowscount = $("#fermentableGrid").jqxGrid('getdatainformation').rowscount; 627 var index, datarecord, row = {}, rowscount = $("#fermentableGrid").jqxGrid('getdatainformation').rowscount;
3441 var index = event.args.index; 628 index = event.args.index;
3442 var datarecord = fermentablelist.records[index]; 629 datarecord = fermentablelist.records[index];
3443 var row = {};
3444 row["f_name"] = datarecord.name; 630 row["f_name"] = datarecord.name;
3445 row["f_origin"] = datarecord.origin; 631 row["f_origin"] = datarecord.origin;
3446 row["f_supplier"] = datarecord.supplier; 632 row["f_supplier"] = datarecord.supplier;
3447 row["f_amount"] = 0; 633 row["f_amount"] = 0;
3448 row["f_cost"] = datarecord.cost; 634 row["f_cost"] = datarecord.cost;
3487 }); 673 });
3488 674
3489 // delete selected fermentable. 675 // delete selected fermentable.
3490 $("#fdeleterowbutton").jqxButton({ template: "danger", theme: theme, height: 27, width: 150, disabled: (dataRecord.stage > 3) }); 676 $("#fdeleterowbutton").jqxButton({ template: "danger", theme: theme, height: 27, width: 150, disabled: (dataRecord.stage > 3) });
3491 $("#fdeleterowbutton").on('click', function () { 677 $("#fdeleterowbutton").on('click', function () {
3492 var selectedrowindex = $("#fermentableGrid").jqxGrid('getselectedrowindex'); 678 var rowscount, id, percent, amount, i, rowdata,
3493 var rowscount = $("#fermentableGrid").jqxGrid('getdatainformation').rowscount; 679 selectedrowindex = $("#fermentableGrid").jqxGrid('getselectedrowindex');
680 rowscount = $("#fermentableGrid").jqxGrid('getdatainformation').rowscount;
3494 if (selectedrowindex >= 0 && selectedrowindex < rowscount) { 681 if (selectedrowindex >= 0 && selectedrowindex < rowscount) {
3495 var id = $("#fermentableGrid").jqxGrid('getrowid', selectedrowindex); 682 id = $("#fermentableGrid").jqxGrid('getrowid', selectedrowindex);
3496 var percent = $('#fermentableGrid').jqxGrid('getcellvalue', id, "f_percentage"); 683 percent = $('#fermentableGrid').jqxGrid('getcellvalue', id, "f_percentage");
3497 var amount = $('#fermentableGrid').jqxGrid('getcellvalue', id, "f_amount"); 684 amount = $('#fermentableGrid').jqxGrid('getcellvalue', id, "f_amount");
3498 $("#fermentableGrid").jqxGrid('deleterow', id); 685 $("#fermentableGrid").jqxGrid('deleterow', id);
3499 } 686 }
3500 rowscount = $("#fermentableGrid").jqxGrid('getdatainformation').rowscount; 687 rowscount = $("#fermentableGrid").jqxGrid('getdatainformation').rowscount;
3501 if (rowscount > 1) { 688 if (rowscount > 1) {
3502 if (to_100) { 689 if (to_100) {
3503 for (var i = 0; i < rowscount; i++) { 690 for (i = 0; i < rowscount; i++) {
3504 var rowdata = $("#fermentableGrid").jqxGrid('getrowdata', i); 691 rowdata = $("#fermentableGrid").jqxGrid('getrowdata', i);
3505 if (rowdata.f_adjust_to_total_100) { 692 if (rowdata.f_adjust_to_total_100) {
3506 rowdata.f_percentage += percent; 693 rowdata.f_percentage += percent;
3507 rowdata.f_amount += amount; 694 rowdata.f_amount += amount;
3508 } 695 }
3509 } 696 }
3597 } 784 }
3598 } 785 }
3599 } 786 }
3600 ] 787 ]
3601 }); 788 });
3602 }; 789 },
3603 790
3604 // Inline hops editor 791 // Inline hops editor
3605 var editHop = function (data) { 792 editHop = function (data) {
3606 var hopSource = { 793 var hopSource = {
3607 localdata: data.hops, 794 localdata: data.hops,
3608 datatype: "local", 795 datatype: "local",
3609 cache: false, 796 cache: false,
3610 async: false, 797 async: false,
3638 }, 825 },
3639 updaterow: function (rowid, rowdata, commit) { 826 updaterow: function (rowid, rowdata, commit) {
3640 console.log("hop updaterow "+rowid); 827 console.log("hop updaterow "+rowid);
3641 commit(true); 828 commit(true);
3642 } 829 }
3643 }; 830 },
3644 var hopAdapter = new $.jqx.dataAdapter(hopSource); 831 hopAdapter = new $.jqx.dataAdapter(hopSource);
832
3645 $("#hopGrid").jqxGrid({ 833 $("#hopGrid").jqxGrid({
3646 width: 1240, 834 width: 1240,
3647 height: 560, 835 height: 560,
3648 source: hopAdapter, 836 source: hopAdapter,
3649 theme: theme, 837 theme: theme,
3674 " (" + datarecord.alpha + "% &alpha;)"; 862 " (" + datarecord.alpha + "% &alpha;)";
3675 } 863 }
3676 }); 864 });
3677 $("#haddrowbutton").on('select', function (event) { 865 $("#haddrowbutton").on('select', function (event) {
3678 if (event.args) { 866 if (event.args) {
3679 var index = event.args.index; 867 var datarecord, row = {}, index = event.args.index;
3680 var datarecord = hoplist.records[index]; 868 datarecord = hoplist.records[index];
3681 var row = {};
3682 row["h_name"] = datarecord.name; 869 row["h_name"] = datarecord.name;
3683 row["h_origin"] = datarecord.origin; 870 row["h_origin"] = datarecord.origin;
3684 row["h_amount"] = 0; 871 row["h_amount"] = 0;
3685 row["h_cost"] = datarecord.cost; 872 row["h_cost"] = datarecord.cost;
3686 row["h_type"] = datarecord.type; 873 row["h_type"] = datarecord.type;
3708 }); 895 });
3709 896
3710 // delete selected hop. 897 // delete selected hop.
3711 $("#hdeleterowbutton").jqxButton({ template: "danger", theme: theme, height: 27, width: 150, disabled: (dataRecord.stage > 3) }); 898 $("#hdeleterowbutton").jqxButton({ template: "danger", theme: theme, height: 27, width: 150, disabled: (dataRecord.stage > 3) });
3712 $("#hdeleterowbutton").on('click', function () { 899 $("#hdeleterowbutton").on('click', function () {
3713 var selectedrowindex = $("#hopGrid").jqxGrid('getselectedrowindex'); 900 var rowscount, id, selectedrowindex = $("#hopGrid").jqxGrid('getselectedrowindex');
3714 var rowscount = $("#hopGrid").jqxGrid('getdatainformation').rowscount; 901 rowscount = $("#hopGrid").jqxGrid('getdatainformation').rowscount;
3715 if (selectedrowindex >= 0 && selectedrowindex < rowscount) { 902 if (selectedrowindex >= 0 && selectedrowindex < rowscount) {
3716 var id = $("#hopGrid").jqxGrid('getrowid', selectedrowindex); 903 id = $("#hopGrid").jqxGrid('getrowid', selectedrowindex);
3717 $("#hopGrid").jqxGrid('deleterow', id); 904 $("#hopGrid").jqxGrid('deleterow', id);
3718 } 905 }
3719 calcIBUs(); 906 calcIBUs();
3720 }); 907 });
3721 }, 908 },
3773 }, 960 },
3774 { text: 'Voorraad', datafield: 'h_inventory', width: 110, align: 'right', 961 { text: 'Voorraad', datafield: 'h_inventory', width: 110, align: 'right',
3775 cellsrenderer: function (index, datafield, value, defaultvalue, column, rowdata) { 962 cellsrenderer: function (index, datafield, value, defaultvalue, column, rowdata) {
3776 if (((dataRecord.inventory_reduced <= 2) && (rowdata.h_useat <= 4)) || // Mash, FW, Boil, Aroma, Whirlpool 963 if (((dataRecord.inventory_reduced <= 2) && (rowdata.h_useat <= 4)) || // Mash, FW, Boil, Aroma, Whirlpool
3777 ((dataRecord.inventory_reduced <= 6) && (rowdata.h_useat == 5))) { // Dry hop 964 ((dataRecord.inventory_reduced <= 6) && (rowdata.h_useat == 5))) { // Dry hop
3778 var color = '#ffffff'; 965 var amount, color = '#ffffff';
3779 if (value < rowdata.h_amount) 966 if (value < rowdata.h_amount)
3780 color = '#ff4040'; 967 color = '#ff4040';
3781 var amount = dataAdapter.formatNumber(value, "f1") + ' kg'; 968 amount = dataAdapter.formatNumber(value, "f1") + ' kg';
3782 if (value < 1) 969 if (value < 1)
3783 amount = dataAdapter.formatNumber(value * 1000, "f1") + ' gr'; 970 amount = dataAdapter.formatNumber(value * 1000, "f1") + ' gr';
3784 return '<span style="margin: 4px; margin-top: 6px; float: right; color: '+color+';">'+amount+'</span>'; 971 return '<span style="margin: 4px; margin-top: 6px; float: right; color: '+color+';">'+amount+'</span>';
3785 } else { 972 } else {
3786 return '<span></span>'; 973 return '<span></span>';
3814 } 1001 }
3815 } 1002 }
3816 } 1003 }
3817 ] 1004 ]
3818 }); 1005 });
3819 }; 1006 },
3820 1007
3821 // Inline miscs editor 1008 // Inline miscs editor
3822 var editMisc = function (data) { 1009 editMisc = function (data) {
3823 var miscSource = { 1010 var miscSource = {
3824 localdata: data.miscs, 1011 localdata: data.miscs,
3825 datatype: "local", 1012 datatype: "local",
3826 cache: false, 1013 cache: false,
3827 async: false, 1014 async: false,
3846 }, 1033 },
3847 updaterow: function (rowid, rowdata, commit) { 1034 updaterow: function (rowid, rowdata, commit) {
3848 console.log("misc updaterow "+rowid); 1035 console.log("misc updaterow "+rowid);
3849 commit(true); 1036 commit(true);
3850 } 1037 }
3851 }; 1038 },
3852 var miscAdapter = new $.jqx.dataAdapter(miscSource, { 1039 miscAdapter = new $.jqx.dataAdapter(miscSource, {
3853 beforeLoadComplete: function (records) { 1040 beforeLoadComplete: function (records) {
3854 var data = new Array(); 1041 var row, i, data = new Array();
3855 for (var i = 0; i < records.length; i++) { 1042 for (i = 0; i < records.length; i++) {
3856 var row = records[i]; 1043 row = records[i];
3857 data.push(row); 1044 data.push(row);
3858 // Initial set water agent values. 1045 // Initial set water agent values.
3859 switch (row.m_name) { 1046 switch (row.m_name) {
3860 case 'CaCl2': $("#wa_cacl2").val(row.m_amount * 1000); 1047 case 'CaCl2': $("#wa_cacl2").val(row.m_amount * 1000);
3861 break; 1048 break;
3936 dropDownWidth: 500, 1123 dropDownWidth: 500,
3937 dropDownHeight: 500 1124 dropDownHeight: 500
3938 }); 1125 });
3939 $("#maddrowbutton").on('select', function (event) { 1126 $("#maddrowbutton").on('select', function (event) {
3940 if (event.args) { 1127 if (event.args) {
3941 var index = event.args.index; 1128 var datarecord, row = {}, index = event.args.index;
3942 var datarecord = misclist.records[index]; 1129 datarecord = misclist.records[index];
3943 var row = {};
3944 row["m_name"] = datarecord.name; 1130 row["m_name"] = datarecord.name;
3945 row["m_amount"] = 0; 1131 row["m_amount"] = 0;
3946 row["m_cost"] = datarecord.cost; 1132 row["m_cost"] = datarecord.cost;
3947 row["m_type"] = datarecord.type; 1133 row["m_type"] = datarecord.type;
3948 row["m_use_use"] = datarecord.use_use; 1134 row["m_use_use"] = datarecord.use_use;
3958 misclist.dataBind(); 1144 misclist.dataBind();
3959 }); 1145 });
3960 // delete selected misc. 1146 // delete selected misc.
3961 $("#mdeleterowbutton").jqxButton({ template: "danger", theme: theme, height: 27, width: 150, disabled: (dataRecord.stage > 3) }); 1147 $("#mdeleterowbutton").jqxButton({ template: "danger", theme: theme, height: 27, width: 150, disabled: (dataRecord.stage > 3) });
3962 $("#mdeleterowbutton").on('click', function () { 1148 $("#mdeleterowbutton").on('click', function () {
3963 var selectedrowindex = $("#miscGrid").jqxGrid('getselectedrowindex'); 1149 var rowscount, type, id, selectedrowindex = $("#miscGrid").jqxGrid('getselectedrowindex');
3964 var rowscount = $("#miscGrid").jqxGrid('getdatainformation').rowscount; 1150 rowscount = $("#miscGrid").jqxGrid('getdatainformation').rowscount;
3965 var type = $("#miscGrid").jqxGrid('getcellvalue', selectedrowindex, "m_type"); 1151 type = $("#miscGrid").jqxGrid('getcellvalue', selectedrowindex, "m_type");
3966 if (selectedrowindex >= 0 && selectedrowindex < rowscount && type != 4) { // Water agent 1152 if (selectedrowindex >= 0 && selectedrowindex < rowscount && type != 4) { // Water agent
3967 var id = $("#miscGrid").jqxGrid('getrowid', selectedrowindex); 1153 id = $("#miscGrid").jqxGrid('getrowid', selectedrowindex);
3968 $("#miscGrid").jqxGrid('deleterow', id); 1154 $("#miscGrid").jqxGrid('deleterow', id);
3969 } 1155 }
3970 }); 1156 });
3971 }, 1157 },
3972 ready: function() { 1158 ready: function() {
4002 dataAdapter.formatNumber(value * 1000,"f2")+" "+vstr + '</span>'; 1188 dataAdapter.formatNumber(value * 1000,"f2")+" "+vstr + '</span>';
4003 } 1189 }
4004 }, 1190 },
4005 { text: 'Voorraad', datafield: 'm_inventory', width: 110, align: 'right', 1191 { text: 'Voorraad', datafield: 'm_inventory', width: 110, align: 'right',
4006 cellsrenderer: function (index, datafield, value, defaultvalue, column, rowdata) { 1192 cellsrenderer: function (index, datafield, value, defaultvalue, column, rowdata) {
1193 var vstr, color, amount;
4007 if (((dataRecord.inventory_reduced <= 2) && (rowdata.m_use_use <= 2)) || // Starter, Mash, Boil 1194 if (((dataRecord.inventory_reduced <= 2) && (rowdata.m_use_use <= 2)) || // Starter, Mash, Boil
4008 ((dataRecord.inventory_reduced <= 3) && (rowdata.m_use_use == 3)) || // Primary 1195 ((dataRecord.inventory_reduced <= 3) && (rowdata.m_use_use == 3)) || // Primary
4009 ((dataRecord.inventory_reduced <= 5) && (rowdata.m_use_use == 4)) || // Secondary, Teriary 1196 ((dataRecord.inventory_reduced <= 5) && (rowdata.m_use_use == 4)) || // Secondary, Teriary
4010 ((dataRecord.inventory_reduced <= 6) && (rowdata.m_use_use == 5))) { // Bottle 1197 ((dataRecord.inventory_reduced <= 6) && (rowdata.m_use_use == 5))) { // Bottle
4011 var vstr = rowdata.m_amount_is_weight ? "gr":"ml"; 1198 vstr = rowdata.m_amount_is_weight ? "gr":"ml";
4012 var color = '#ffffff'; 1199 color = '#ffffff';
4013 if (value < rowdata.m_amount) 1200 if (value < rowdata.m_amount)
4014 color = '#ff4040'; 1201 color = '#ff4040';
4015 var amount = dataAdapter.formatNumber(value * 1000,"f2")+" "+vstr; 1202 amount = dataAdapter.formatNumber(value * 1000,"f2")+" "+vstr;
4016 return '<span style="margin: 4px; margin-top: 6px; float: right; color: '+color+';">'+amount+'</span>'; 1203 return '<span style="margin: 4px; margin-top: 6px; float: right; color: '+color+';">'+amount+'</span>';
4017 } else { 1204 } else {
4018 return '<span></span>'; 1205 return '<span></span>';
4019 } 1206 }
4020 } 1207 }
4046 } 1233 }
4047 } 1234 }
4048 } 1235 }
4049 ] 1236 ]
4050 }); 1237 });
4051 }; 1238 },
4052 1239
4053 // Inline yeasts editor 1240 // Inline yeasts editor
4054 var editYeast = function (data) { 1241 editYeast = function (data) {
4055 var yeastSource = { 1242 var yeastSource = {
4056 localdata: data.yeasts, 1243 localdata: data.yeasts,
4057 datatype: "local", 1244 datatype: "local",
4058 cache: false, 1245 cache: false,
4059 async: false, 1246 async: false,
4085 }, 1272 },
4086 updaterow: function (rowid, rowdata, commit) { 1273 updaterow: function (rowid, rowdata, commit) {
4087 console.log("yeast updaterow "+rowid); 1274 console.log("yeast updaterow "+rowid);
4088 commit(true); 1275 commit(true);
4089 } 1276 }
4090 }; 1277 },
4091 var yeastAdapter = new $.jqx.dataAdapter(yeastSource); 1278 yeastAdapter = new $.jqx.dataAdapter(yeastSource);
1279
4092 $("#yeastGrid").jqxGrid({ 1280 $("#yeastGrid").jqxGrid({
4093 width: 1240, 1281 width: 1240,
4094 height: 350, 1282 height: 350,
4095 source: yeastAdapter, 1283 source: yeastAdapter,
4096 theme: theme, 1284 theme: theme,
4120 return datarecord.laboratory+" "+datarecord.product_id+" "+datarecord.name; 1308 return datarecord.laboratory+" "+datarecord.product_id+" "+datarecord.name;
4121 } 1309 }
4122 }); 1310 });
4123 $("#yaddrowbutton").on('select', function (event) { 1311 $("#yaddrowbutton").on('select', function (event) {
4124 if (event.args) { 1312 if (event.args) {
4125 var index = event.args.index; 1313 var datarecord, row = {}, index = event.args.index;
4126 var datarecord = yeastlist.records[index]; 1314 datarecord = yeastlist.records[index];
4127 var row = {};
4128 row["y_name"] = datarecord.name; 1315 row["y_name"] = datarecord.name;
4129 row["y_laboratory"] = datarecord.laboratory; 1316 row["y_laboratory"] = datarecord.laboratory;
4130 row["y_product_id"] = datarecord.product_id; 1317 row["y_product_id"] = datarecord.product_id;
4131 row["y_type"] = datarecord.type; 1318 row["y_type"] = datarecord.type;
4132 row["y_form"] = datarecord.form; 1319 row["y_form"] = datarecord.form;
4151 yeastlist.dataBind(); 1338 yeastlist.dataBind();
4152 }); 1339 });
4153 // delete selected yeast. 1340 // delete selected yeast.
4154 $("#ydeleterowbutton").jqxButton({ template: "danger", theme: theme, height: 27, width: 150, disabled: (dataRecord.stage > 3) }); 1341 $("#ydeleterowbutton").jqxButton({ template: "danger", theme: theme, height: 27, width: 150, disabled: (dataRecord.stage > 3) });
4155 $("#ydeleterowbutton").on('click', function () { 1342 $("#ydeleterowbutton").on('click', function () {
4156 var selectedrowindex = $("#yeastGrid").jqxGrid('getselectedrowindex'); 1343 var id, rowscount, selectedrowindex = $("#yeastGrid").jqxGrid('getselectedrowindex');
4157 var rowscount = $("#yeastGrid").jqxGrid('getdatainformation').rowscount; 1344 rowscount = $("#yeastGrid").jqxGrid('getdatainformation').rowscount;
4158 if (selectedrowindex >= 0 && selectedrowindex < rowscount) { 1345 if (selectedrowindex >= 0 && selectedrowindex < rowscount) {
4159 var id = $("#yeastGrid").jqxGrid('getrowid', selectedrowindex); 1346 id = $("#yeastGrid").jqxGrid('getrowid', selectedrowindex);
4160 $("#yeastGrid").jqxGrid('deleterow', id); 1347 $("#yeastGrid").jqxGrid('deleterow', id);
4161 calcYeast(); 1348 calcYeast();
4162 } 1349 }
4163 }); 1350 });
4164 }, 1351 },
4179 }, 1366 },
4180 { text: 'Min. &deg;C', width: 70, align: 'right', cellsalign: 'right', datafield: 'y_min_temperature' }, 1367 { text: 'Min. &deg;C', width: 70, align: 'right', cellsalign: 'right', datafield: 'y_min_temperature' },
4181 { text: 'Max. &deg;C', width: 70, align: 'right', cellsalign: 'right', datafield: 'y_max_temperature' }, 1368 { text: 'Max. &deg;C', width: 70, align: 'right', cellsalign: 'right', datafield: 'y_max_temperature' },
4182 { text: 'Tol. %', width: 60, align: 'right', cellsalign: 'right', datafield: 'y_tolerance', 1369 { text: 'Tol. %', width: 60, align: 'right', cellsalign: 'right', datafield: 'y_tolerance',
4183 cellsrenderer: function (index, datafield, value, defaultvalue, column, rowdata) { 1370 cellsrenderer: function (index, datafield, value, defaultvalue, column, rowdata) {
4184 var color = '#ffffff'; 1371 var amount = "", color = '#ffffff';
4185 var amount = "";
4186 if (value > 0) { 1372 if (value > 0) {
4187 amount = dataAdapter.formatNumber(value, "f1"); 1373 amount = dataAdapter.formatNumber(value, "f1");
4188 if (dataRecord.est_abv > value) 1374 if (dataRecord.est_abv > value)
4189 color = '#ff4040'; 1375 color = '#ff4040';
4190 } 1376 }
4207 return '<span style="margin: 4px; margin-top: 6px; float: right;">' + amount + '</span>'; 1393 return '<span style="margin: 4px; margin-top: 6px; float: right;">' + amount + '</span>';
4208 } 1394 }
4209 }, 1395 },
4210 { text: 'Voorraad', datafield: 'y_inventory', width: 90, align: 'right', 1396 { text: 'Voorraad', datafield: 'y_inventory', width: 90, align: 'right',
4211 cellsrenderer: function (index, datafield, value, defaultvalue, column, rowdata) { 1397 cellsrenderer: function (index, datafield, value, defaultvalue, column, rowdata) {
1398 var color, amount;
4212 if (((dataRecord.inventory_reduced <= 3) && (rowdata.y_use == 0)) || // Primary 1399 if (((dataRecord.inventory_reduced <= 3) && (rowdata.y_use == 0)) || // Primary
4213 ((dataRecord.inventory_reduced <= 4) && (rowdata.y_use == 1)) || // Secondary 1400 ((dataRecord.inventory_reduced <= 4) && (rowdata.y_use == 1)) || // Secondary
4214 ((dataRecord.inventory_reduced <= 5) && (rowdata.y_use == 2)) || // Tertiary 1401 ((dataRecord.inventory_reduced <= 5) && (rowdata.y_use == 2)) || // Tertiary
4215 ((dataRecord.inventory_reduced <= 6) && (rowdata.y_use == 3))) { // Bottle 1402 ((dataRecord.inventory_reduced <= 6) && (rowdata.y_use == 3))) { // Bottle
4216 var color = '#ffffff'; 1403 color = '#ffffff';
4217 if (value < rowdata.y_amount) 1404 if (value < rowdata.y_amount)
4218 color = '#ff4040'; 1405 color = '#ff4040';
4219 var amount = dataAdapter.formatNumber(value*1000, "f0")+" ml"; 1406 amount = dataAdapter.formatNumber(value*1000, "f0")+" ml";
4220 if (rowdata.y_form == 0) // Liquid 1407 if (rowdata.y_form == 0) // Liquid
4221 amount = dataAdapter.formatNumber(value, "f0")+" pk"; 1408 amount = dataAdapter.formatNumber(value, "f0")+" pk";
4222 else if (rowdata.y_form == 1) // Dry 1409 else if (rowdata.y_form == 1) // Dry
4223 amount = dataAdapter.formatNumber(value*1000, "f1")+" gr"; 1410 amount = dataAdapter.formatNumber(value*1000, "f1")+" gr";
4224 return '<span style="margin: 4px; margin-top: 6px; float: right; color: '+color+';">'+amount+'</span>'; 1411 return '<span style="margin: 4px; margin-top: 6px; float: right; color: '+color+';">'+amount+'</span>';
4257 } 1444 }
4258 } 1445 }
4259 } 1446 }
4260 ] 1447 ]
4261 }); 1448 });
4262 }; 1449 },
4263
4264 // inline mash editor 1450 // inline mash editor
4265 var editMash = function (data) { 1451 editMash = function (data) {
4266 var mashSource = { 1452 var mashSource = {
4267 localdata: data.mashs, 1453 localdata: data.mashs,
4268 datatype: "local", 1454 datatype: "local",
4269 cache: false, 1455 cache: false,
4270 async: false, 1456 async: false,
4282 commit(true); 1468 commit(true);
4283 }, 1469 },
4284 deleterow: function (rowid, commit) { 1470 deleterow: function (rowid, commit) {
4285 commit(true); 1471 commit(true);
4286 } 1472 }
4287 }; 1473 },
4288 var mashAdapter = new $.jqx.dataAdapter(mashSource, { 1474 mashAdapter = new $.jqx.dataAdapter(mashSource, {
4289 beforeLoadComplete: function (records) { 1475 beforeLoadComplete: function (records) {
4290 mash_infuse = 0; 1476 mash_infuse = 0;
4291 var data = new Array(); 1477 var i, row, data = new Array();
4292 for (var i = 0; i < records.length; i++) { 1478 for (i = 0; i < records.length; i++) {
4293 var row = records[i]; 1479 row = records[i];
4294 if (row.step_type == 0) // Infusion 1480 if (row.step_type == 0) // Infusion
4295 mash_infuse += parseFloat(row.step_infuse_amount); 1481 mash_infuse += parseFloat(row.step_infuse_amount);
4296 row.step_thickness = 0; // Init this field. 1482 row.step_thickness = 0; // Init this field.
4297 data.push(row); 1483 data.push(row);
4298 } 1484 }
4310 toolbar.append(container); 1496 toolbar.append(container);
4311 container.append('<input style="float: left; margin-left: 165px;" id="saddrowbutton" type="button" value="Nieuwe stap" />'); 1497 container.append('<input style="float: left; margin-left: 165px;" id="saddrowbutton" type="button" value="Nieuwe stap" />');
4312 container.append('<input style="float: left; margin-left: 565px;" id="sdeleterowbutton" type="button" value="Verwijder stap" />'); 1498 container.append('<input style="float: left; margin-left: 565px;" id="sdeleterowbutton" type="button" value="Verwijder stap" />');
4313 $("#saddrowbutton").jqxButton({ template: "primary", theme: theme, height: 27, width: 150, disabled: (dataRecord.stage > 3) }); 1499 $("#saddrowbutton").jqxButton({ template: "primary", theme: theme, height: 27, width: 150, disabled: (dataRecord.stage > 3) });
4314 $("#saddrowbutton").on('click', function () { 1500 $("#saddrowbutton").on('click', function () {
4315 var rowscount = $("#mashGrid").jqxGrid('getdatainformation').rowscount; 1501 var row = {}, rowscount = $("#mashGrid").jqxGrid('getdatainformation').rowscount;
4316 var row = {};
4317 row["step_name"] = "Stap " + (rowscount + 1); 1502 row["step_name"] = "Stap " + (rowscount + 1);
4318 if (rowscount > 0) { 1503 if (rowscount > 0) {
4319 row["step_type"] = 1; 1504 row["step_type"] = 1;
4320 } else { 1505 } else {
4321 row["step_type"] = 0; 1506 row["step_type"] = 0;
4329 $("#mashGrid").jqxGrid('addrow', null, row); 1514 $("#mashGrid").jqxGrid('addrow', null, row);
4330 }); 1515 });
4331 // delete selected step. 1516 // delete selected step.
4332 $("#sdeleterowbutton").jqxButton({ template: "danger", theme: theme, height: 27, width: 150, disabled: (dataRecord.stage > 3) }); 1517 $("#sdeleterowbutton").jqxButton({ template: "danger", theme: theme, height: 27, width: 150, disabled: (dataRecord.stage > 3) });
4333 $("#sdeleterowbutton").on('click', function () { 1518 $("#sdeleterowbutton").on('click', function () {
4334 var selectedrowindex = $("#mashGrid").jqxGrid('getselectedrowindex'); 1519 var rowscount, id, selectedrowindex = $("#mashGrid").jqxGrid('getselectedrowindex');
4335 var rowscount = $("#mashGrid").jqxGrid('getdatainformation').rowscount; 1520 rowscount = $("#mashGrid").jqxGrid('getdatainformation').rowscount;
4336 if (selectedrowindex >= 0 && selectedrowindex < rowscount) { 1521 if (selectedrowindex >= 0 && selectedrowindex < rowscount) {
4337 var id = $("#mashGrid").jqxGrid('getrowid', selectedrowindex); 1522 id = $("#mashGrid").jqxGrid('getrowid', selectedrowindex);
4338 $("#mashGrid").jqxGrid('deleterow', id); 1523 $("#mashGrid").jqxGrid('deleterow', id);
4339 } 1524 }
4340 }); 1525 });
4341 }, 1526 },
4342 ready: function() { 1527 ready: function() {
4387 } 1572 }
4388 ] 1573 ]
4389 }); 1574 });
4390 }; 1575 };
4391 1576
1577 /*
1578 * Remove the top menu so that we MUST use the buttons to leave the editor.
1579 */
1580 $('#jqxMenu').jqxMenu('destroy');
1581 console.log("record:" + my_record + " return:" + my_return + " theme:" + theme);
1582 $("#jqxLoader").jqxLoader({width:250,height:150,isModal:true,text:"Laden product ...",theme:theme});
1583 dataAdapter.dataBind();
1584
1585 /*
1586 * Generic functions
1587 */
1588 function calcSupplies() {
1589 if (dataRecord.inventory_reduced > 6) {
1590 $("#ok_pmpt").hide();
1591 return;
1592 }
1593 if (ok_fermentables && ok_hops && ok_miscs && ok_yeasts && ok_waters)
1594 $("#ok_supplies").html("<img src='images/dialog-ok-apply.png'>");
1595 else
1596 $("#ok_supplies").html("<img src='images/dialog-error.png'>");
1597 }
1598
1599 function calcPercentages() {
1600
1601 console.log("calcPercentages()");
1602 var tw = 0, rowdata, percentage, rowscount = $("#fermentableGrid").jqxGrid('getdatainformation').rowscount;
1603 if (rowscount > 1) {
1604 for (i = 0; i < rowscount; i++) {
1605 rowdata = $("#fermentableGrid").jqxGrid('getrowdata', i);
1606 if (rowdata.f_added < 4)
1607 tw += Round(rowdata.f_amount, 3);
1608 };
1609 tw = Round(tw, 3);
1610
1611 for (i = 0; i < rowscount; i++) {
1612 rowdata = $("#fermentableGrid").jqxGrid('getrowdata', i);
1613 if (rowdata.f_added < 4) {
1614 percentage = Round(rowdata.f_amount / tw * 100, 1);
1615 $("#fermentableGrid").jqxGrid('setcellvalue', i, "f_percentage", percentage);
1616 } else {
1617 $("#fermentableGrid").jqxGrid('setcellvalue', i, "f_percentage", 0);
1618 }
1619 };
1620 } else {
1621 $("#fermentableGrid").jqxGrid('setcellvalue', 0, "f_percentage", 100);
1622 }
1623 }
1624
1625 /*
1626 * All calculations that depend on changes in the fermentables,
1627 * volumes and equipments.
1628 */
1629 function calcFermentables() {
1630
1631 var sugarsf = 0, // fermentable sugars mash + boil
1632 sugarsm = 0, // fermentable sugars in mash
1633 vol = 0, // Volume sugars after boil
1634 addedS = 0, // Added sugars after boil
1635 addedmass = 0, // Added mass after boil
1636 mvol = 0, // mash volume
1637 colort = 0, // Colors srm * vol totals
1638 colorh = 0, // Colors ebc * vol * kt
1639 colorn = 0, // Colors ebc * pt * pct
1640 my_100 = false,
1641 mashtime = 0, // Total mash time
1642 mashtemp = 0, // Average mash temperature
1643 bv = 0.925, // Bierverlies rendement
1644 sr = 0.95, // Mash en spoel rendement
1645 lintner = 0, // Total recipe lintner
1646 i, row, rows, org, timem, aboil_volume, spoelw, ogx, topw, s = 0, d, v, x,
1647 sug, alc, pt, cw, color, scolor, fig;
1648
1649 /* Init global variables */
1650 psugar = 0;
1651 pcara = 0;
1652 mashkg = 0;
1653 ok_fermentables = 1; // All is in stock.
1654 ok_yeasts = 1;
1655
1656 if ((rows = $('#mashGrid').jqxGrid('getrows'))){
1657 for (i = 0; i <rows.length; i++){
1658 row=rows[i];
1659 if(row.step_type==0) // Infusion
1660 mvol+=parseFloat(row.step_infuse_amount);
1661 if(row.step_temp<=75){ // Ignore mashout
1662 timem=row.step_time+row.ramp_time;
1663 mashtime+=timem;
1664 mashtemp+=timem*row.step_temp;
1665 }
1666 }
1667 if(mashtime>5)
1668 mashtime-=5;//Correct last ramp > 75
1669 mashtemp=Round(mashtemp/mashtime,2);
1670 }
1671
1672 if (!(rows = $('#fermentableGrid').jqxGrid('getrows'))) {
1673 return; // grid not yet loaded.
1674 }
1675
1676 for (i = 0; i < rows.length; i++) {
1677 row = rows[i];
1678 if (row.f_adjust_to_total_100)
1679 my_100 = true;
1680 if (row.f_type == 1 && row.f_added < 4) // Sugar
1681 psugar += row.f_percentage;
1682 if (row.f_graintype == 2 && row.f_added < 4) // Crystal
1683 pcara += row.f_percentage;
1684 d = row.f_amount * (row.f_yield / 100) * (1 - row.f_moisture / 100);
1685 if (row.f_added == 0) { // Mash
1686 if (mvol > 0) { // Only if mash already known.
1687 mvol += row.f_amount * row.f_moisture / 100;
1688 s += d;
1689 }
1690 d = parseFloat(dataRecord.efficiency) / 100 * d;
1691 sugarsm += d;
1692 mashkg += parseFloat(row.f_amount);
1693 }
1694 if (row.f_added == 0 || row.f_added == 1) // Mash or Boil
1695 sugarsf += d;
1696 if (row.f_added == 2 || row.f_added == 3) { // Fermentation or lagering
1697 x = (row.f_yield / 100) * (1 - row.f_moisture / 100);
1698 addedS += row.f_amount * x;
1699 addedmass += row.f_amount;
1700 vol += (x * sugardensity + (1 - x) * 1) * row.f_amount;
1701 }
1702 if (row.f_added < 4) {
1703 colort += row.f_amount * ebc_to_srm(row.f_color);
1704 colorh += row.f_amount * row.f_color * get_kt(row.f_color);
1705 colorn += (row.f_percentage / 100) * row.f_color; // For 8.6 Pt wort.
1706 }
1707 if (fermentableInit) {
1708 if (row.f_added == 4) {
1709 $("#bottle_priming_total").val(row.f_amount * 1000); // Prevent clearing
1710 $("#bottle_priming_sugar").jqxDropDownList('selectItem', row.f_name);
1711 }
1712 if (row.f_added == 5) {
1713 $("#keg_priming_total").val(row.f_amount * 1000);
1714 $("#keg_priming_sugar").jqxDropDownList('selectItem', row.f_name);
1715 }
1716 }
1717 // Check supplies.
1718 if ((((dataRecord.inventory_reduced <= 2) && (row.f_added <= 1)) || // Mash or boil
1719 ((dataRecord.inventory_reduced <= 3) && (row.f_added == 2)) || // Primary
1720 ((dataRecord.inventory_reduced <= 5) && (row.f_added == 3)) || // Secondary or Tertiary
1721 ((dataRecord.inventory_reduced <= 6) && (row.f_added == 4)) || // Bottle
1722 ((dataRecord.inventory_reduced <= 6) && (row.f_added == 5))) && row.f_inventory < row.f_amount) {
1723 ok_fermentables = 0;
1724 }
1725 if (row.f_added == 0 && (row.f_type == 0 || row.f_type == 4) && row.f_color < 50) { // Mash and Grain/Adjunct and Color < 50
1726 lintner += row.f_diastatic_power * row.f_amount;
1727 }
1728 }
1729 fermentableInit = 0;
1730 $("#ferm_lintner").val(Math.round(parseFloat(lintner / mashkg)));
1731 $("#mash_kg").val(mashkg);
1732 console.log("calcFermentables() supplies:"+ok_fermentables+" moutsuiker:"+sugarsm+"/"+sugarsf);
1733 to_100 = my_100;
1734 if (to_100) {
1735 $("#wf_amount").jqxNumberInput({ width: 90, readOnly: true, spinButtons: false });
1736 } else {
1737 $("#wf_amount").jqxNumberInput({ width: 110, readOnly: false, spinButtons: true });
1738 }
1739
1740 if (mvol > 0) {
1741 v = s / sugardensity + mvol;
1742 s = 1000 * s / (v * 10); //deg. Plato
1743 est_mash_sg = Round(plato_to_sg(s), 5);
1744 $('#est_mash_sg').val(est_mash_sg);
1745 }
1746
1747 // Estimate total recipe OG.
1748 dataRecord.est_og = estimate_sg(sugarsf + addedS, parseFloat(dataRecord.batch_size));
1749 $('#est_og').val(dataRecord.est_og);
1750 $('#est_og2').val(dataRecord.est_og);
1751 org = dataRecord.est_og;
1752
1753 // Estimate SG in kettle after boil
1754 aboil_sg = estimate_sg(sugarsf, parseFloat(dataRecord.batch_size));
1755 $('#est_og3').val(aboil_sg);
1756
1757 // Estimate SG in kettle before boil
1758 preboil_sg = estimate_sg(sugarsm, parseFloat(dataRecord.boil_size));
1759 $('#est_pre_sg').val(preboil_sg);
1760
1761 // Recalculate volumes.
1762 aboil_volume = parseFloat(dataRecord.batch_size);
1763 if (dataRecord.brew_aboil_volume > 0)
1764 aboil_volume = dataRecord.brew_aboil_volume / 1.04; // volume @ 20 degrees
1765 if (dataRecord.brew_fermenter_tcloss == 0) {
1766 dataRecord.brew_fermenter_tcloss = dataRecord.eq_trub_chiller_loss;
1767 $("#brew_fermenter_tcloss").val(dataRecord.brew_fermenter_tcloss);
1768 }
1769 dataRecord.brew_fermenter_volume = aboil_volume - dataRecord.brew_fermenter_tcloss + dataRecord.brew_fermenter_extrawater;
1770 $("#brew_fermenter_volume").val(dataRecord.brew_fermenter_volume);
1771 // Estimated needed sparge water corrected for the temperature.
1772 spoelw = (dataRecord.boil_size - mash_infuse + (mashkg * my_grain_absorbtion) + dataRecord.eq_lauter_deadspace) * 1.03;
1773 $("#brew_sparge_est").val(spoelw);
1774 // Calculate SG in fermenter
1775 ogx = dataRecord.brew_aboil_sg;
1776 if (ogx < 1.002)
1777 ogx = aboil_sg;
1778 topw = dataRecord.brew_fermenter_extrawater;
1779
1780 if (dataRecord.brew_fermenter_volume > 0) {
1781 sug = sg_to_plato(ogx) * dataRecord.brew_fermenter_volume * ogx / 100; //kg of sugar in
1782 sug += addedS; //kg
1783
1784 if ((dataRecord.brew_fermenter_volume * ogx + addedmass) > 0) {
1785 pt = 100 * sug / (dataRecord.brew_fermenter_volume * ogx + addedmass + topw);
1786 dataRecord.brew_fermenter_sg = Round(plato_to_sg(pt),4);
1787 $("#brew_fermenter_sg").val(dataRecord.brew_fermenter_sg);
1788 // color
1789 if (dataRecord.color_method == 4) {
1790 dataRecord.brew_fermenter_color = Math.round(((pt / 8.6) * colorn) + (dataRecord.boil_time / 60));
1791 } else if (dataRecord.color_method == 3) {
1792 dataRecord.brew_fermenter_color = Math.round((4.46 * bv * sr) / (aboil_volume + topw) * colorh);
1793 } else {
1794 cw = colort / (aboil_volume + topw) * 8.34436;
1795 dataRecord.brew_fermenter_color = kw_to_ebc(dataRecord.color_method, cw);
1796 }
1797 $("#brew_fermenter_color").val(dataRecord.brew_fermenter_color);
1798 scolor = ebc_to_color(dataRecord.brew_fermenter_color);
1799 $("#bcolorf").show();
1800 document.getElementById("bcolorf").style.background = scolor;
1801 }
1802 } else {
1803 // Negative volume
1804 dataRecord.brew_fermenter_sg = dataRecord.brew_fermenter_color = 0;
1805 $("#brew_fermenter_sg").val(0);
1806 $("#brew_fermenter_color").val(0);
1807 $("#bcolorf").hide();
1808 }
1809
1810 // Color of the wort
1811 if (dataRecord.color_method == 4) {
1812 color = Math.round(((sg_to_plato(dataRecord.est_og) / 8.6) * colorn) + (dataRecord.boil_time / 60));
1813 } else if (dataRecord.color_method == 3) { // Hans Halberstadt
1814 color = Math.round((4.46 * bv * sr) / parseFloat(dataRecord.batch_size) * colorh);
1815 } else {
1816 cw = colort / parseFloat(dataRecord.batch_size) * 8.34436;
1817 color = kw_to_ebc(dataRecord.color_method, cw);
1818 }
1819 dataRecord.est_color = color;
1820 $('#est_color').val(color);
1821 $('#est_color2').val(color);
1822 scolor = ebc_to_color(color);
1823 document.getElementById("bcolor").style.background= scolor;
1824 document.getElementById("bcolor2").style.background= scolor;
1825
1826 // Progress bars
1827 pmalts = mashkg / dataRecord.eq_mash_max * 100;
1828 $("#perc_malts").jqxProgressBar('val', pmalts);
1829 $("#perc_sugars").jqxProgressBar('val', psugar);
1830 $("#perc_cara").jqxProgressBar('val', pcara);
1831 calcStage();
1832
1833 // Calculate estimated svg.
1834 svg = 0; // default.
1835 initcells = 0;
1836 rows = $('#yeastGrid').jqxGrid('getrows');
1837 for (i = 0; i < rows.length; i++) {
1838 row = rows[i];
1839 if (row.y_use == 0) { // Primary
1840 if (parseFloat(row.y_attenuation) > svg)
1841 svg = parseFloat(row.y_attenuation); // Take the highest if multiple yeasts.
1842 if (row.y_form == 0)
1843 initcells += (parseFloat(row.y_cells) / 1000000000) * parseFloat(row.y_amount) * (dataRecord.starter_viability / 100);
1844 else
1845 initcells += (parseFloat(row.y_cells) / 1000000) * parseFloat(row.y_amount);
1846 }
1847 // TODO: brett in secondary ??
1848 if ((((dataRecord.inventory_reduced <= 3) && (row.y_use == 0)) || // Primary
1849 ((dataRecord.inventory_reduced <= 4) && (row.y_use == 1)) || // Secondary
1850 ((dataRecord.inventory_reduced <= 5) && (row.y_use == 2)) || // Tertiary
1851 ((dataRecord.inventory_reduced <= 6) && (row.y_use == 3))) && // Bottle
1852 (row.y_inventory < row.y_amount)) {
1853 ok_yeasts = 0;
1854 }
1855 }
1856 calcSupplies();
1857 if (svg == 0)
1858 svg = 77;
1859
1860 if ((mashkg > 0) && (mash_infuse > 0) && (mashtime > 0) && (mashtemp > 0)) {
1861 dataRecord.est_fg = estimate_fg(psugar, pcara, mash_infuse / mashkg, mashtime, mashtemp, svg, dataRecord.est_og);
1862 } else {
1863 dataRecord.est_fg = estimate_fg(psugar, pcara, 0, 0, 0, svg, dataRecord.est_og);
1864 }
1865 $('#est_fg').val(dataRecord.est_fg);
1866 $('#est_fg2').val(dataRecord.est_fg);
1867 $('#est_fg3').val(dataRecord.est_fg);
1868 fig = dataRecord.est_fg;
1869
1870 dataRecord.est_abv = abvol(dataRecord.est_og, dataRecord.est_fg);
1871 $("#est_abv").val(dataRecord.est_abv);
1872 $("#est_abv2").val(dataRecord.est_abv);
1873
1874 // Calculate the final svg if available use the real value.
1875 if ((dataRecord.stage >= 6) && (dataRecord.fg > 0.990) && (dataRecord.fg < dataRecord.brew_fermenter_sg)) {
1876 svg = 100 * (dataRecord.brew_fermenter_sg - dataRecord.fg) / (dataRecord.brew_fermenter_sg - 1);
1877 org = dataRecord.brew_fermenter_sg;
1878 fig = dataRecord.fg;
1879 }
1880
1881 $("#yeast_cells").val(initcells);
1882 $("#need_cells").val(getNeededYeastCells());
1883
1884 // Calculate the calories in kcal/l (from brouwhulp)
1885 alc = 1881.22 * fig * (org - fig) / (1.775 - org);
1886 sug = 3550 * fig * (0.1808 * org + 0.8192 * fig - 1.0004);
1887 $("#kcal").val(Math.round((alc + sug) / (12 * 0.0295735296)));
1888 };
1889
1890 function calcMash() {
1891
1892 var infused = 0, i, row;
1893
1894 if (!(rows = $('#mashGrid').jqxGrid('getrows')))
1895 return;
1896 if (mashkg == 0)
1897 return;
1898
1899 for (i = 0; i < rows.length; i++) {
1900 row = $("#mashGrid").jqxGrid('getrowdata', i);
1901 if (row.step_type == 0) // Infusion
1902 infused += row.step_infuse_amount;
1903 $("#mashGrid").jqxGrid('setcellvalue', i, "step_thickness", infused / mashkg);
1904 }
1905 }
1906
1907 /*
1908 * Change OG of recipe but keep the water volumes.
1909 */
1910 function calcFermentablesFromOG(OG) {
1911
1912 console.log("calcFermentablesFromOG("+OG+")");
1913 var amount, row, d, i, sug, tot = 0, totmass = 0, rowscount, efficiency = parseFloat($("#efficiency").jqxNumberInput('decimal'));
1914 sug = sg_to_plato(OG) * parseFloat($("#batch_size").jqxNumberInput('decimal')) * OG / 100; //total amount of sugars in kg
1915 rowscount = $("#fermentableGrid").jqxGrid('getdatainformation').rowscount;
1916
1917 for (i = 0; i < rowscount; i++) {
1918 row = $("#fermentableGrid").jqxGrid('getrowdata', i);
1919 if (row.f_added < 4) {
1920 d = row.f_percentage / 100 * (row.f_yield / 100) * (1 - row.f_moisture / 100);
1921 if (row.f_added == 0) // Mash
1922 d = efficiency / 100 * d;
1923 tot += d;
1924 }
1925 }
1926 if (tot)
1927 totmass = Round(sug / tot,3);
1928
1929 if (totmass) {
1930 for (i = 0; i < rowscount; i++) {
1931 row = $("#fermentableGrid").jqxGrid('getrowdata', i);
1932 if (row.f_added < 4) {
1933 amount = Math.round(row.f_percentage * 10 * totmass) / 1000;
1934 $("#fermentableGrid").jqxGrid('setcellvalue', i, "f_amount", amount);
1935 }
1936 }
1937 }
1938 };
1939
1940 function getNeededYeastCells() {
1941
1942 var plato, volume, sg = dataRecord.brew_fermenter_sg;
1943 if (sg <= 1.0001 && dataRecord.fg > 1.000)
1944 sg = dataRecord.fg;
1945 else if (sg <= 1.0001)
1946 sg = dataRecord.est_og;
1947 plato = sg_to_plato(sg);
1948
1949 volume = dataRecord.brew_fermenter_volume;
1950 if (volume <= 0)
1951 volume = dataRecord.batch_size - dataRecord.eq_trub_chiller_loss;
1952
1953 return pitchrate * volume * plato;
1954 }
1955
1956 function hopFlavourContribution(bt, vol, use, amount) {
1957 var result;
1958
1959 if (use == 1) { // First wort
1960 result = 0.15; // assume 15% flavourcontribution for fwh
1961 } else if (bt > 50) {
1962 result = 0.10; // assume 10% flavourcontribution as a minimum
1963 } else {
1964 result = 15.25 / (6 * Math.sqrt(2 * Math.PI)) * Math.exp(-0.5 * Math.pow((bt - 21) /6, 2));
1965 if (result < 0.10)
1966 result = 0.10; // assume 10% flavourcontribution as a minimum
1967 }
1968 return (result * amount * 1000) / vol;
1969 }
1970
1971 function hopAromaContribution(bt, vol, use, amount) {
1972 var result = 0;
1973
1974 if (use == 5) { // Dry hop
1975 result = 1.33;
1976 } else if (bt > 20) {
1977 result = 0;
1978 } else if (bt > 7.5) {
1979 result = 10.03 / (4 * Math.sqrt(2 * Math.PI)) * Math.exp(-0.5 * Math.pow((bt - 7.5) /4, 2));
1980 } else if (use == 2) { // Boil
1981 result = 1;
1982 } else if (use == 3) { // Aroma
1983 result = 1.2;
1984 } else if (use == 4) { // Whirlpool
1985 result = 1.2;
1986 }
1987 return (result * amount * 1000) / vol;
1988 }
1989
1990 function calcIBUs() {
1991 var total_ibus = 0, ferm_ibus = 0, rows = {}, i, row;
1992 hop_aroma = hop_flavour = 0;
1993 if (!(rows = $('#hopGrid').jqxGrid('getrows'))) {
1994 return;
1995 }
1996 ok_hops = 1;
1997 for (i = 0; i < rows.length; i++) {
1998 row = rows[i];
1999 total_ibus += toIBU(row.h_useat, row.h_form, preboil_sg, parseFloat(dataRecord.batch_size),
2000 parseFloat(row.h_amount), parseFloat(row.h_time), parseFloat(row.h_alpha), dataRecord.ibu_method);
2001 ferm_ibus += toIBU(row.h_useat, row.h_form, preboil_sg,
2002 parseFloat(dataRecord.brew_fermenter_volume) + parseFloat(dataRecord.brew_fermenter_tcloss),
2003 parseFloat(row.h_amount), parseFloat(row.h_time), parseFloat(row.h_alpha), dataRecord.ibu_method);
2004 hop_flavour += hopFlavourContribution(parseFloat(row.h_time), parseFloat(dataRecord.batch_size),
2005 row.h_useat, parseFloat(row.h_amount));
2006 hop_aroma += hopAromaContribution(parseFloat(row.h_time), parseFloat(dataRecord.batch_size),
2007 row.h_useat, parseFloat(row.h_amount));
2008 if ((((dataRecord.inventory_reduced <= 2) && (row.h_useat <= 4)) || // Mash, FW, Boil, Aroma, Whirlpool
2009 ((dataRecord.inventory_reduced <= 6) && (row.h_useat == 5))) && // Dry-hop
2010 (row.h_inventory < row.h_amount))
2011 ok_hops = 0;
2012 }
2013 total_ibus = Math.round(total_ibus * 10) / 10;
2014 ferm_ibus = Math.round(ferm_ibus * 10) / 10;
2015 hop_flavour = Math.round(hop_flavour * 1000 / 5) / 10;
2016 hop_aroma = Math.round(hop_aroma * 1000 / 6) / 10;
2017 if (hop_flavour > 100)
2018 hop_flavour = 100;
2019 if (hop_aroma > 100)
2020 hop_aroma = 100;
2021 console.log("calcIBUs(): " + total_ibus + " flavour: " + hop_flavour + " aroma: " + hop_aroma+" fermenter:"+ferm_ibus+" supplies:"+ok_hops);
2022 dataRecord.est_ibu = total_ibus;
2023 $('#est_ibu').val(total_ibus);
2024 $('#est_ibu2').val(total_ibus);
2025 $("#hop_flavour").jqxProgressBar('val', hop_flavour);
2026 $("#hop_aroma").jqxProgressBar('val', hop_aroma);
2027 $("#brew_fermenter_ibu").val(ferm_ibus);
2028 calcStage();
2029 calcSupplies();
2030 };
2031
2032 /*
2033 * http://braukaiser.com/blog/blog/2012/11/03/estimating-yeast-growth/
2034 *
2035 * stype: 0=stirred, 1=shaken, 2=simple
2036 * totcells: initial cells
2037 * egrams: gram extract
2038 */
2039 function getGrowthRate(stype, totcells, egrams){
2040
2041 /* Cells per grams extract (B/g) */
2042 var cpe = totcells / egrams;
2043
2044 if (cpe > 3.5)
2045 return 0; // no growth
2046 if (stype == 2)
2047 return 0.4; // simple starter
2048 if (stype == 1)
2049 return 0.62; // shaken starter
2050 if (cpe <= 1.4) // stirred starter
2051 return 1.4;
2052 return 2.33 - (.67 * cpe );
2053 };
2054
2055 function calcStep(svol, stype, start) {
2056
2057 var gperpoint = 2.72715, //number of grams of extract per point of starter gravity per liter
2058 prate = start/svol * 1000,
2059 irate = Round(prate,1),
2060 egrams = (dataRecord.starter_sg - 1) * svol * gperpoint;
2061 grate = getGrowthRate(stype, start, egrams),
2062 ncells = Round(egrams * grate, 1),
2063 totcells = parseFloat(ncells) + start;
2064
2065 console.log("svol:"+svol+" start:"+start+" irate:"+irate+" egrams:"+egrams+" grate:"+grate+" ncells:"+ncells);
2066 return {
2067 svol: svol,
2068 irate: irate,
2069 prate: Round(prate,1),
2070 ncells: ncells,
2071 totcells: totcells,
2072 growf: Round(ncells/start, 2)
2073 };
2074 }
2075
2076 /*
2077 * Calculate all starter steps.
2078 * stype: final starter type: 0 = stirred, 1 = shaked, 2 = simple.
2079 * start: initial cells in billions
2080 * needed: needed cells in billions
2081 *
2082 * result: all values updated.
2083 */
2084 function calcSteps(stype, start, needed) {
2085
2086 var uvols = [ 20, 40, 60, 80, 100, 150, 200, 250, 375, 500, 625, 750, 875, 1000, 1250, 1500, 2000, 2500, 3000, 4000, 5000 ],
2087 mvols = uvols.length, svol = 0, lasti = 0, result = {}, i;
2088
2089 /*
2090 * If no values are set, auto calculate the starter.
2091 */
2092 if ((parseFloat($("#prop1_volume").jqxNumberInput('decimal')) + parseFloat($("#prop2_volume").jqxNumberInput('decimal')) +
2093 parseFloat($("#prop3_volume").jqxNumberInput('decimal')) + parseFloat($("#prop4_volume").jqxNumberInput('decimal'))) == 0) {
2094 // clear by default
2095 for (i = 1; i < 5; i++) {
2096 $("#prop"+i+"_type").hide();
2097 $("#r"+i+"_pmpt").show();
2098 $("#prop"+i+"_type").val(stype);
2099 $("#prop"+i+"_volume").hide();
2100 $("#prop"+i+"_volume").val(0);
2101 $("#prop"+i+"_irate").hide();
2102 $("#prop"+i+"_ncells").hide();
2103 $("#prop"+i+"_tcells").hide();
2104 $("#prop"+i+"_growf").hide();
2105 }
2106 if (start > needed) {
2107 return; // no starter needed
2108 }
2109 $("#prop1_type").show();
2110 $("#r1_pmpt").hide();
2111 $("#prop1_volume").show();
2112 $("#prop1_irate").show();
2113 $("#prop1_ncells").show();
2114 $("#prop1_tcells").show();
2115 $("#prop1_growf").show();
2116 for (i = lasti; i <= mvols; i++) {
2117 lasti = i;
2118 svol = uvols[lasti];
2119 result = calcStep(svol, stype, start);
2120 if (result.irate < 25) {
2121 // inocculation rate too low, backup one step and break out.
2122 lasti = i - 1;
2123 svol = uvols[lasti];
2124 result = calcStep(svol, stype, start);
2125 break;
2126 }
2127 if (result.totcells > needed || i == mvols) { // hit the target or loops done
2128 break;
2129 }
2130 }
2131 $("#prop1_volume").val(result.svol / 1000); // to liters
2132 $("#prop1_irate").val(result.prate);
2133 $("#prop1_ncells").val(result.ncells);
2134 $("#prop1_tcells").val(result.totcells);
2135 $("#prop1_growf").val(result.growf);
2136 if (result.totcells > needed)
2137 return; // hit the target
2138
2139 // second stage
2140 $("#r2_pmpt").hide();
2141 $("#prop2_type").val(stype);
2142 $("#prop2_type").show();
2143 $("#prop2_volume").show();
2144 $("#prop2_irate").show();
2145 $("#prop2_ncells").show();
2146 $("#prop2_tcells").show();
2147 $("#prop2_growf").show();
2148 for (i = lasti; i <= mvols; i++) {
2149 lasti = i;
2150 svol = uvols[lasti];
2151 result = calcStep(svol, stype, $("#prop1_tcells").val());
2152 if (result.irate < 25) {
2153 lasti = i - 1;
2154 svol = uvols[lasti];
2155 result = calcStep(svol, stype, $("#prop1_tcells").val());
2156 break;
2157 }
2158 if (result.totcells > needed || i == mvols) { // hit the target or loops done
2159 break;
2160 }
2161 }
2162 $("#prop2_volume").val(result.svol / 1000); // to liters
2163 $("#prop2_irate").val(result.prate);
2164 $("#prop2_ncells").val(result.ncells);
2165 $("#prop2_tcells").val(result.totcells);
2166 $("#prop2_growf").val(result.growf);
2167 if (result.totcells > needed)
2168 return; // hit the target
2169
2170 // third stage
2171 $("#r3_pmpt").hide();
2172 $("#prop3_type").val(stype);
2173 $("#prop3_type").show();
2174 $("#prop3_volume").show();
2175 $("#prop3_irate").show();
2176 $("#prop3_ncells").show();
2177 $("#prop3_tcells").show();
2178 $("#prop3_growf").show();
2179 for (i = lasti; i <= mvols; i++) {
2180 lasti = i;
2181 svol = uvols[lasti];
2182 result = calcStep(svol, stype, $("#prop2_tcells").val());
2183 if (result.irate < 25) {
2184 lasti = i - 1;
2185 svol = uvols[lasti];
2186 result = calcStep(svol, stype, $("#prop2_tcells").val());
2187 break;
2188 }
2189 if (result.totcells > needed || i == mvols) { // hit the target or loops done
2190 break;
2191 }
2192 }
2193 $("#prop3_volume").val(result.svol / 1000); // to liters
2194 $("#prop3_irate").val(result.prate);
2195 $("#prop3_ncells").val(result.ncells);
2196 $("#prop3_tcells").val(result.totcells);
2197 $("#prop3_growf").val(result.growf);
2198 if (result.totcells > needed)
2199 return; // hit the target
2200
2201 // fourth stage
2202 $("#r4_pmpt").hide();
2203 $("#prop4_type").val(stype);
2204 $("#prop4_type").show();
2205 $("#prop4_volume").show();
2206 $("#prop4_irate").show();
2207 $("#prop4_ncells").show();
2208 $("#prop4_tcells").show();
2209 $("#prop4_growf").show();
2210 for (i = lasti; i <= mvols; i++) {
2211 lasti = i;
2212 svol = uvols[lasti];
2213 result = calcStep(svol, stype, $("#prop3_tcells").val());
2214 if (result.totcells > needed || i == mvols) { // hit the target or loops done
2215 $("#prop4_volume").val(result.svol / 1000); // to liters
2216 $("#prop4_irate").val(result.prate);
2217 $("#prop4_ncells").val(result.ncells);
2218 $("#prop4_tcells").val(result.totcells);
2219 $("#prop4_growf").val(result.growf);
2220 return;
2221 }
2222 }
2223 } else {
2224 // recalculate
2225 if (dataRecord.prop1_volume > 0) {
2226 $("#r1_pmpt").hide();
2227 $("#prop1_type").show();
2228 $("#prop1_volume").show();
2229 $("#prop1_irate").show();
2230 $("#prop1_ncells").show();
2231 $("#prop1_tcells").show();
2232 $("#prop1_growf").show();
2233 result = calcStep($("#prop1_volume").val() * 1000, dataRecord.prop1_type, start);
2234 $("#prop1_irate").val(result.prate);
2235 $("#prop1_ncells").val(result.ncells);
2236 $("#prop1_tcells").val(result.totcells);
2237 $("#prop1_growf").val(result.growf);
2238 }
2239 if (dataRecord.prop2_volume > 0) {
2240 $("#r2_pmpt").hide();
2241 $("#prop2_type").show();
2242 $("#prop2_volume").show();
2243 $("#prop2_irate").show();
2244 $("#prop2_ncells").show();
2245 $("#prop2_tcells").show();
2246 $("#prop2_growf").show();
2247 result = calcStep($("#prop2_volume").val() * 1000, dataRecord.prop2_type, $("#prop1_tcells").val());
2248 $("#prop2_irate").val(result.prate);
2249 $("#prop2_ncells").val(result.ncells);
2250 $("#prop2_tcells").val(result.totcells);
2251 $("#prop2_growf").val(result.growf);
2252 }
2253 if (dataRecord.prop3_volume > 0) {
2254 $("#r3_pmpt").hide();
2255 $("#prop3_type").show();
2256 $("#prop3_volume").show();
2257 $("#prop3_irate").show();
2258 $("#prop3_ncells").show();
2259 $("#prop3_tcells").show();
2260 $("#prop3_growf").show();
2261 result = calcStep($("#prop3_volume").val() * 1000, dataRecord.prop3_type, $("#prop2_tcells").val());
2262 $("#prop3_irate").val(result.prate);
2263 $("#prop3_ncells").val(result.ncells);
2264 $("#prop3_tcells").val(result.totcells);
2265 $("#prop3_growf").val(result.growf);
2266 }
2267 if (dataRecord.prop4_volume > 0) {
2268 $("#r4_pmpt").hide();
2269 $("#prop4_type").show();
2270 $("#prop4_volume").show();
2271 $("#prop4_irate").show();
2272 $("#prop4_ncells").show();
2273 $("#prop4_tcells").show();
2274 $("#prop4_growf").show();
2275 result = calcStep($("#prop4_volume").val() * 1000, dataRecord.prop4_type, $("#prop3_tcells").val());
2276 $("#prop4_irate").val(result.prate);
2277 $("#prop4_ncells").val(result.ncells);
2278 $("#prop4_tcells").val(result.totcells);
2279 $("#prop4_growf").val(result.growf);
2280 }
2281
2282 }
2283 }
2284
2285 function calcYeast() {
2286
2287 // Calculate needed cells.
2288 var plato, volume, rows, rowscount, row, i, needed, use_cells,
2289 sg = dataRecord.brew_fermenter_sg;
2290 if (sg <= 1.0001 && dataRecord.fg > 1.000)
2291 sg = dataRecord.fg;
2292 else if (sg <= 1.0001)
2293 sg = dataRecord.est_og;
2294 plato = sg_to_plato(sg);
2295
2296 volume = dataRecord.brew_fermenter_volume;
2297 if (volume > 0) {
2298 if (dataRecord.brew_fermenter_extrawater > 0)
2299 volume += dataRecord.brew_fermenter_extrawater;
2300 } else {
2301 volume = dataRecord.batch_size - dataRecord.eq_trub_chiller_loss;
2302 }
2303
2304 // Also in calcFermentables()
2305 $("#yeast_cells").val(initcells);
2306
2307 if (!(rows = $('#yeastGrid').jqxGrid('getrows'))) {
2308 return; // grid not yet loaded.
2309 }
2310 rowscount = $("#yeastGrid").jqxGrid('getdatainformation').rowscount;
2311 if (rowscount == 0)
2312 return; // no yeast in recipe
2313
2314 for (i = 0; i < rowscount; i++) {
2315 row = $("#yeastGrid").jqxGrid('getrowdata', i);
2316 if (row.y_use == 0) { // primary
2317 // pitchrate see https://www.brewersfriend.com/yeast-pitch-rate-and-starter-calculator/
2318 // and http://braukaiser.com/blog/blog/2012/11/03/estimating-yeast-growth/
2319 pitchrate = 0.75;
2320 if (dataRecord.est_og > 1.060)
2321 pitchrate = 1.0;
2322 // if (dataRecord.est_og > 1.076)
2323 // pitchrate = 1.25; // Wyeast labs. http://www.wyeastlab.com/hb_pitchrates.cfm
2324 if (row.y_type == 0) // lager yeast
2325 pitchrate *= 2;
2326
2327 if (row.y_form == 1) { // dry yeast
2328 } else { // possible starter needed
2329 }
2330 }
2331 }
2332 needed = pitchrate * volume * plato;
2333 console.log("calcYeast() pitchrate:"+pitchrate+" start:"+initcells+" needed:"+needed+" volume:"+volume);
2334 $("#need_cells").val(needed);
2335 use_cells = initcells;
2336
2337 if (dataRecord.starter_enable) {
2338 calcSteps(dataRecord.starter_type, initcells, needed);
2339
2340 for (i = 1; i < 5; i++) {
2341 $("#r"+i+"_irate").html("");
2342 $("#r"+i+"_growf").html("");
2343 $("#r"+i+"_tcells").html("");
2344 if (parseFloat($("#prop"+i+"_volume").val()) > 0) {
2345 if ((parseFloat($("#prop"+i+"_irate").val()) < 25) || (parseFloat($("#prop"+i+"_irate").val()) > 100)) {
2346 $("#r"+i+"_irate").html("<img src='images/dialog-error.png'>");
2347 } else {
2348 $("#r"+i+"_irate").html("<img src='images/dialog-ok-apply.png'>");
2349 }
2350 if (parseFloat($("#prop"+i+"_growf").val()) < 1)
2351 $("#r"+i+"_growf").html("<img src='images/dialog-error.png'>");
2352 if (($("#prop"+i+"_type").val() > 0) && (parseFloat($("#prop"+i+"_growf").val()) > 3))
2353 $("#r"+i+"_growf").html("<img src='images/dialog-error.png'>");
2354 if (parseFloat($("#prop"+i+"_tcells").val()) > needed)
2355 $("#r"+i+"_tcells").html("<img src='images/dialog-ok-apply.png'>");
2356 use_cells = parseFloat($("#prop"+i+"_tcells").val());
2357 } else {
2358 $("#r"+i+"_irate").html("");
2359 }
2360 }
2361 }
2362 $("#plato_cells").val(parseFloat(use_cells / (volume * plato) ));
2363 };
2364
2365 function adjustHops(factor) {
2366
2367 console.log("adjustHops("+factor+")");
2368 var row, i, amount, rowscount = $("#hopGrid").jqxGrid('getdatainformation').rowscount;
2369 if (rowscount == 0)
2370 return;
2371 for (i = 0; i < rowscount; i++) {
2372 row = $("#hopGrid").jqxGrid('getrowdata', i);
2373 amount = row.h_amount * factor;
2374 $("#hopGrid").jqxGrid('setcellvalue', i, "h_amount", amount);
2375 }
2376 };
2377
2378 function calcMiscs() {
2379
2380 ok_miscs = 1;
2381 var row, i, rowscount = $("#miscGrid").jqxGrid('getdatainformation').rowscount;
2382 if (rowscount == 0)
2383 return;
2384 for (i = 0; i < rowscount; i++) {
2385 row = $("#miscGrid").jqxGrid('getrowdata', i);
2386 if ((((dataRecord.inventory_reduced <= 2) && (row.m_use_use <= 2)) || // Starter, Mash, Boil
2387 ((dataRecord.inventory_reduced <= 3) && (row.m_use_use == 3)) || // Primary
2388 ((dataRecord.inventory_reduced <= 5) && (row.m_use_use == 4)) || // Secondary, Teriary
2389 ((dataRecord.inventory_reduced <= 6) && (row.m_use_use == 5))) && // Bottle
2390 (row.m_inventory < row.m_amount)) {
2391 ok_miscs = 0;
2392 }
2393 }
2394 calcSupplies();
2395 };
2396
2397 function adjustMiscs(factor) {
2398
2399 console.log("adjustMiscs("+factor+")");
2400 var row, i, amount, rowscount = $("#miscGrid").jqxGrid('getdatainformation').rowscount;
2401 if (rowscount == 0)
2402 return;
2403 for (i = 0; i < rowscount; i++) {
2404 row = $("#miscGrid").jqxGrid('getrowdata', i);
2405 amount = row.m_amount * factor;
2406 $("#miscGrid").jqxGrid('setcellvalue', i, "m_amount", amount);
2407 switch (row.m_name) {
2408 case 'CaCl2': $("#wa_cacl2").val(row.m_amount * 1000);
2409 break;
2410 case 'CaSO4': $("#wa_caso4").val(row.m_amount * 1000);
2411 break;
2412 case 'MgSO4': $("#wa_mgso4").val(row.m_amount * 1000);
2413 break;
2414 case 'NaCl': $("#wa_nacl").val(row.m_amount * 1000);
2415 break;
2416 case 'Melkzuur':
2417 case 'Zoutzuur':
2418 case 'Fosforzuur':
2419 case 'Zwavelzuur': $("#wa_acid").val(row.m_amount * 1000);
2420 break;
2421 case 'NaHCO3':
2422 case 'Na2CO3':
2423 case 'CaCO3':
2424 case 'Ca(OH)2': $("#wa_base").val(row.m_amount * 1000);
2425 break;
2426 }
2427 }
2428 };
2429
2430 function adjustYeasts(factor) {
2431
2432 console.log("adjustYeasts("+factor+")");
2433 var row, i, amount, rowscount = $("#yeastGrid").jqxGrid('getdatainformation').rowscount;
2434 if (rowscount == 0)
2435 return;
2436 for (i = 0; i < rowscount; i++) {
2437 row = $("#yeastGrid").jqxGrid('getrowdata', i);
2438 if (row.y_form == 1) { // Only adjust dry yeast
2439 amount = row.y_amount * factor;
2440 $("#yeastGrid").jqxGrid('setcellvalue', i, "y_amount", amount);
2441 }
2442 }
2443 calcYeast();
2444 };
2445
2446 function adjustWaters(factor) {
2447
2448 console.log("adjustWaters("+factor+")");
2449 var amount, row, i, rowscount = $("#mashGrid").jqxGrid('getdatainformation').rowscount;
2450 if (rowscount == 0)
2451 return;
2452 mash_infuse = 0;
2453 for (i = 0; i < rowscount; i++) {
2454 row = $("#mashGrid").jqxGrid('getrowdata', i);
2455 if (row.step_type == 0) { // Infusion
2456 amount = Round(row.step_infuse_amount * factor, 1);
2457 $("#mashGrid").jqxGrid('setcellvalue', i, "step_infuse_amount", amount);
2458 mash_infuse += amount;
2459 }
2460 }
2461 if (dataRecord.w2_amount == 0) {
2462 dataRecord.w1_amount = mash_infuse;
2463 $("#w1_amount").val(mash_infuse);
2464 } else {
2465 dataRecord.w1_amount = (dataRecord.w1_amount / (dataRecord.w1_amount + dataRecord.w2_amount)) * mash_infuse;
2466 dataRecord.w2_amount = (dataRecord.w2_amount / (dataRecord.w1_amount + dataRecord.w2_amount)) * mash_infuse;
2467 $("#w1_amount").val(dataRecord.w1_amount);
2468 $("#w2_amount").val(dataRecord.w2_amount);
2469 }
2470 $('#wg_amount').val(mash_infuse);
2471 };
2472
2473 function calcMashEfficiency() {
2474 var c, m;
2475 if (parseFloat($("#brew_mash_sg").jqxNumberInput('decimal')) < 1.002)
2476 return;
2477 c = sg_to_plato(est_mash_sg);
2478 m = sg_to_plato(parseFloat($("#brew_mash_sg").jqxNumberInput('decimal')));
2479 if (c > 0.5)
2480 $("#brew_mash_efficiency").val(100 * m / c);
2481 else
2482 $("#brew_mash_efficiency").val(0);
2483 };
2484
2485 function calcEfficiencyBeforeBoil() {
2486 var m = 0, rows = {}, i, row, tot, result = 0;
2487 if (!(rows = $('#fermentableGrid').jqxGrid('getrows'))) {
2488 return; // grid not yet loaded.
2489 }
2490 for (i = 0; i < rows.length; i++) {
2491 row = rows[i];
2492 if (row.f_added == 0) { // Mash
2493 m += row.f_amount * (row.f_yield / 100) * (1 - row.f_moisture / 100);
2494 }
2495 }
2496 tot = sg_to_plato(dataRecord.brew_preboil_sg) * (dataRecord.brew_preboil_volume / 1.04) * dataRecord.brew_preboil_sg * 10 / 1000;
2497 if (m > 0)
2498 result = Round((tot / m * 100), 1);
2499 if (result < 0)
2500 result = 0;
2501 $("#brew_preboil_efficiency").val(result);
2502 }
2503
2504 function calcEfficiencyAfterBoil() {
2505 var m = 0, // Sugars added at mash
2506 b = 0, // Sugars added at boil
2507 rows = {}, i, row, tot, result = 0;
2508 if (!(rows = $('#fermentableGrid').jqxGrid('getrows'))) {
2509 return; // grid not yet loaded.
2510 }
2511 for (i = 0; i < rows.length; i++) {
2512 row = rows[i];
2513 if (row.f_added == 0) { // Mash
2514 m += row.f_amount * (row.f_yield / 100) * (1 - row.f_moisture / 100);
2515 } else if (row.f_added == 1) { // Boil
2516 b += row.f_amount * (row.f_yield / 100) * (1 - row.f_moisture / 100);
2517 }
2518 }
2519 tot = sg_to_plato(dataRecord.brew_aboil_sg) * (dataRecord.brew_aboil_volume / 1.04) * dataRecord.brew_aboil_sg * 10 / 1000;
2520 tot -= b; // total sugars in wort minus added sugars.
2521 if (m > 0)
2522 result = Round((tot / m * 100), 1);
2523 if (result < 0)
2524 result = 0;
2525 dataRecord.brew_aboil_efficiency = result;
2526 $("#brew_aboil_efficiency").val(result);
2527
2528 }
2529
2530 function GetBUGU() {
2531 var gu = (dataRecord.est_og - 1) * 1000;
2532 if (gu > 0)
2533 return dataRecord.est_ibu / gu;
2534 else
2535 return 0.5;
2536 }
2537
2538 function GetOptClSO4ratio() {
2539 var BUGU = GetBUGU();
2540 return (-1.2 * BUGU + 1.4);
2541 }
2542
2543 function setWaterAgent(name, amount) {
2544 var row, i, id, found = false, miscs, rows = $('#miscGrid').jqxGrid('getrows');
2545 if (amount == 0) {
2546 for (i = 0; i < rows.length; i++) {
2547 row = rows[i];
2548 if (row.m_name == name) {
2549 id = $("#miscGrid").jqxGrid('getrowid', i);
2550 $("#miscGrid").jqxGrid('deleterow', id);
2551 }
2552 }
2553 } else {
2554 for (i = 0; i < rows.length; i++) {
2555 row = rows[i];
2556 if (row.m_name == name) {
2557 found = true;
2558 $("#miscGrid").jqxGrid('setcellvalue', i, 'm_amount', amount / 1000);
2559 break;
2560 }
2561 }
2562 if (! found) {
2563 miscs = new $.jqx.dataAdapter(miscInvSource, {
2564 loadComplete: function () {
2565 var record, i, row = {}, records = miscs.records;
2566 for (i = 0; i < records.length; i++) {
2567 record = records[i];
2568 if (record.name == name) {
2569 row["m_name"] = record.name;
2570 row["m_amount"] = amount / 1000;
2571 row["m_cost"] = record.cost;
2572 row["m_type"] = record.type;
2573 row["m_use_use"] = record.use_use;
2574 row["m_time"] = 0;
2575 row["m_amount_is_weight"] = record.amount_is_weight;
2576 row["m_inventory"] = record.inventory;
2577 row["m_avail"] = 1;
2578 $("#miscGrid").jqxGrid('addrow', null, row);
2579 }
2580 }
2581 }
2582 });
2583 miscs.dataBind();
2584 return;
2585 }
2586 }
2587 }
2588
2589 function setRangeIndicator(ion, rangeCode) {
2590 if ((rangeCode == "laag") || (rangeCode == "hoog"))
2591 $("#wr_"+ion).html("<img src='images/dialog-error.png'><span style='vertical-align: top; font-size: 10px; font-style: italic;'>"+rangeCode + "</span>");
2592 else
2593 $("#wr_"+ion).html("<img src='images/dialog-ok-apply.png'>");
2594 }
2595
2596 function mix(v1, v2, c1, c2) {
2597 if ((v1 + v2) > 0) {
2598 return ((v1 * c1) + (v2 * c2)) / (v1 + v2);
2599 }
2600 return 0;
2601 }
2602
2603 // mg/l as CaCO3
2604 function ResidualAlkalinity(total_alkalinity, calcium, magnesium) {
2605 return total_alkalinity - (calcium / 1.4 + magnesium / 1.7);
2606 }
2607
2608 function PartCO3(pH) {
2609 var H = Math.pow(10, -pH);
2610 return 100 * Ka1 * Ka2 / (H*H + H * Ka1 + Ka1 * Ka2);
2611 }
2612
2613 function PartHCO3(pH) {
2614 var H = Math.pow(10, -pH);
2615 return 100 * Ka1 * H / (H*H + H * Ka1 + Ka1 * Ka2);
2616 }
2617
2618 function Charge(pH) {
2619 return (-2 * PartCO3(pH) - PartHCO3(pH));
2620 }
2621
2622 //Z alkalinity is the amount of acid (in mEq/l) needed to bring water to the target pH (Z pH)
2623 function ZAlkalinity(pHZ) {
2624 var C43 = Charge(4.3),
2625 Cw = Charge(parseFloat($("#wg_ph").jqxNumberInput('decimal'))),
2626 Cz = Charge(pHZ),
2627 DeltaCNaught = -C43+Cw,
2628 CT = parseFloat($("#wg_total_alkalinity").jqxNumberInput('decimal')) / 50 / DeltaCNaught,
2629 DeltaCZ = -Cz+Cw;
2630 return CT * DeltaCZ;
2631 }
2632
2633 //Z Residual alkalinity is the amount of acid (in mEq/l) needed to bring the water in the mash to the target pH (Z pH)
2634 function ZRA(pHZ) {
2635
2636 var Magn, Z, Calc = parseFloat($("#wg_calcium").jqxNumberInput('decimal')) / (MMCa / 2);
2637 Magn = parseFloat($("#wg_magnesium").jqxNumberInput('decimal')) / (MMMg / 2);
2638 Z = ZAlkalinity(pHZ);
2639 return Z - (Calc / 3.5 + Magn / 7);
2640 }
2641
2642 function ProtonDeficit(pHZ) {
2643
2644 var rows, i, C1, ebc, x, Result = ZRA(pHZ) * parseFloat($("#wg_amount").jqxNumberInput('decimal'));
2645 // proton deficit for the grist
2646 rows = $('#fermentableGrid').jqxGrid('getrows');
2647 for (i = 0; i < rows.length; i++) {
2648 row = rows[i];
2649 if (row.f_added == 0 && row.f_graintype != 6) { // Added == Mash && graintype != No Malt
2650 // Check if acid is required
2651 C1 = 0;
2652 if ((row.f_di_ph != 5.7) && ((row.f_acid_to_ph_57 < - 0.1) || (row.f_acid_to_ph_57 > 0.1))) {
2653 C1 = row.f_acid_to_ph_57 / (row.f_di_ph - 5.7);
2654 } else {
2655 // If the acid_to_ph_5.7 is unknown from the maltster, guess the required acid.
2656 ebc = row.f_color;
2657 switch (row.f_graintype) {
2658 case 0: // Base, Special, Kilned
2659 case 3:
2660 case 5: C1 = 0.014 * ebc - 34.192;
2661 break;
2662 case 2: C1 = -0.0597 * ebc - 32.457; // Crystal
2663 break;
2664 case 1: C1 = 0.0107 * ebc - 54.768; // Roast
2665 break;
2666 case 4: C1 = -149; // Sour malt
2667 break;
2668 }
2669 }
2670 x = C1 * (pHZ - row.f_di_ph); // AcidRequired(ZpH)
2671 Result += x * row.f_amount;
2672 }
2673 }
2674 return Result;
2675 }
2676
2677 function MashpH() {
2678 var n = 0, pH = 5.4, deltapH = 0.001, deltapd = 0.1, pd = ProtonDeficit(pH);
2679 while (((pd < -deltapd) || (pd > deltapd)) && (n < 2000)) {
2680 n++;
2681 if (pd < -deltapd)
2682 pH -= deltapH;
2683 else if (pd > deltapd)
2684 pH += deltapH;
2685 pd = ProtonDeficit(pH);
2686 }
2687 console.log("MashpH() n: "+n+" pH: "+pH);
2688 return pH;
2689 }
2690
2691 function GetAcidSpecs(AT) {
2692 switch(AT) {
2693 case 0: return { // Melkzuur
2694 pK1: 3.86,
2695 pK2: 20,
2696 pK3: 20,
2697 MolWt: 90.08,
2698 AcidSG: 1214, // 1214 1209
2699 AcidPrc: 0.88 // 0.88 0.80
2700 };
2701 case 1: return { // Zoutzuur
2702 pK1: -7,
2703 pK2: 20,
2704 pK3: 20,
2705 MolWt: 36.46,
2706 AcidSG: 1142,
2707 AcidPrc: 0.28
2708 };
2709 case 2: return { // Fosforzuur
2710 pK1: 2.12,
2711 pK2: 7.20,
2712 pK3: 12.44,
2713 MolWt: 98.00,
2714 AcidSG: 1170,
2715 AcidPrc: 0.25
2716 };
2717 case 3: return { // Zwavelzuur
2718 pK1: -1,
2719 pK2: 1.92,
2720 pK3: 20,
2721 MolWt: 98.07,
2722 AcidSG: 1700,
2723 AcidPrc: 0.93
2724 };
2725 }
2726 }
2727
2728 function calcWater() {
2729
2730 console.log("calcWater()");
2731 var liters = 0,
2732 calcium = 0,
2733 magnesium = 0,
2734 sodium = 0,
2735 total_alkalinity = 0,
2736 bicarbonate = 0,
2737 chloride = 0,
2738 sulfate = 0,
2739 ph = 0,
2740 RA = 0,
2741 frac = 0,
2742 TpH = 0,
2743 protonDeficit = 0,
2744 AT, BT, result, pK1, pK2, pK3, MolWt, AcidSG, AcidPrc,
2745 r1d, r2d, f1d, f2d, f3d,
2746 deltapH, deltapd, pd, n,
2747 piCLSO4_low, piCLSO4_high, Res,
2748 wg_calcium, wg_sodium, wg_total_alkalinity, wg_chloride, wg_sulfate, wg_bicarbonate;
2749
2750 if (dataRecord.w1_name == "") {
2751 return;
2752 }
2753
2754 // If there is a dillute water source, mix the waters.
2755 if (dataRecord.w2_name != "") {
2756 liters = dataRecord.w1_amount + dataRecord.w2_amount;
2757 calcium = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_calcium, dataRecord.w2_calcium);
2758 magnesium = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_magnesium, dataRecord.w2_magnesium);
2759 sodium = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_sodium, dataRecord.w2_sodium);
2760 chloride = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_chloride, dataRecord.w2_chloride);
2761 sulfate = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_sulfate, dataRecord.w2_sulfate);
2762 total_alkalinity = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_total_alkalinity, dataRecord.w2_total_alkalinity);
2763 ph = -Math.log10(((Math.pow(10, -dataRecord.w1_ph) * dataRecord.w1_amount) + (Math.pow(10, -dataRecord.w2_ph) * dataRecord.w2_amount)) / liters);
2764 } else {
2765 liters = dataRecord.w1_amount;
2766 calcium = dataRecord.w1_calcium;
2767 magnesium = dataRecord.w1_magnesium;
2768 sodium = dataRecord.w1_sodium;
2769 chloride = dataRecord.w1_chloride;
2770 sulfate = dataRecord.w1_sulfate;
2771 total_alkalinity = dataRecord.w1_total_alkalinity;
2772 ph = dataRecord.w1_ph;
2773 }
2774 $('#wg_amount').val(liters);
2775 wg_calcium = calcium;
2776 $('#wg_calcium').val(Math.round(calcium * 10) / 10);
2777 //var wg_magnesium = magnesium;
2778 $('#wg_magnesium').val(Math.round(magnesium * 10) / 10);
2779 wg_sodium = sodium;
2780 $('#wg_sodium').val(Math.round(sodium * 10) / 10);
2781 wg_total_alkalinity = total_alkalinity;
2782 $('#wg_total_alkalinity').val(Math.round(total_alkalinity * 10) / 10);
2783 wg_chloride = chloride;
2784 $('#wg_chloride').val(Math.round(chloride * 10) / 10);
2785 wg_sulfate = sulfate;
2786 $('#wg_sulfate').val(Math.round(sulfate * 10) / 10);
2787 // Note: brouwhulp has the malts included here in the result.
2788 //var wg_ph = ph;
2789 $('#wg_ph').val(Round(ph,1));
2790 $('#wb_ph').val(Round(MashpH(), 1));
2791 $('#est_mash_ph').val(Round(MashpH(), 1));
2792 bicarbonate = total_alkalinity * 1.22;
2793 wg_bicarbonate = bicarbonate;
2794
2795 // Noot: de volgende berekeningen geven bijna gelijke resultaten in Brun'water.
2796 // Calculate Ca
2797 RA = parseFloat($("#wa_cacl2").jqxNumberInput('decimal')) * MMCa / MMCaCl2 +
2798 parseFloat($("#wa_caso4").jqxNumberInput('decimal')) * MMCa / MMCaSO4;
2799 calcium += 1000 * RA / liters;
2800
2801 // Calculate Mg
2802 RA = parseFloat($("#wa_mgso4").jqxNumberInput('decimal')) * MMMg / MMMgSO4;
2803 magnesium += 1000 * RA / liters;
2804
2805 // Calculate Na
2806 RA = parseFloat($("#wa_nacl").jqxNumberInput('decimal')) * MMNa / MMNaCl +
2807 parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMNa / MMNaHCO3;
2808 sodium += 1000 * RA / liters;
2809
2810 // Calculate SO4
2811 RA = parseFloat($("#wa_caso4").jqxNumberInput('decimal')) * MMSO4 / MMCaSO4 +
2812 parseFloat($("#wa_mgso4").jqxNumberInput('decimal')) * MMSO4 / MMMgSO4;
2813 sulfate += 1000 * RA / liters;
2814
2815 // Calculate Cl
2816 RA = 2 * parseFloat($("#wa_cacl2").jqxNumberInput('decimal')) * MMCl / MMCaCl2 +
2817 parseFloat($("#wa_nacl").jqxNumberInput('decimal')) * MMCl / MMNaCl;
2818 chloride += 1000 * RA / liters;
2819 // Einde noot.
2820
2821 if ($("#wa_acid_name").val() < 0 || $("#wa_acid_name").val() > 3) {
2822 $("#wa_acid_name").val(0);
2823 dataRecord.wa_acid_name = 0;
2824 }
2825 if (last_acid == '')
2826 last_acid = AcidTypeData[$("#wa_acid_name").val()].nl;
2827
2828 if ($("#wa_base_name").val() < 0 || $("#wa_base_name").val() > 3) {
2829 $("#wa_base_name").val(0);
2830 dataRecord.wa_base_name = 0;
2831 }
2832 if (last_base == '')
2833 last_base = BaseTypeData[$("#wa_base_name").val()].nl;
2834
2835 AT = dataRecord.wa_acid_name;
2836 BT = dataRecord.wa_base_name;
2837
2838 result = GetAcidSpecs(AT);
2839 pK1 = result.pK1;
2840 pK2 = result.pK2;
2841 pK3 = result.pK3;
2842 MolWt = result.MolWt;
2843 AcidSG = result.AcidSG;
2844 AcidPrc = result.AcidPrc;
2845
2846 if (dataRecord.calc_acid) {
2847 TpH = parseFloat(dataRecord.mash_ph);
2848 protonDeficit = ProtonDeficit(TpH);
2849 console.log("calc_acid tgt: "+TpH+" protonDeficit: "+protonDeficit);
2850 if (protonDeficit > 0) { // Add acid
2851 $("#wa_base").val(0);
2852 setWaterAgent(last_base, 0);
2853 frac = CalcFrac(TpH, pK1, pK2, pK3);
2854 Acid = protonDeficit / frac;
2855 Acid *= MolWt; // mg
2856 Acidmg = Acid;
2857 Acid = Acid / AcidSG; // ml
2858
2859 if (parseFloat($("#wa_acid_perc").jqxNumberInput('decimal')) == 0)
2860 $("#wa_acid_perc").val(AcidPrc);
2861 Acid = Acid * AcidPrc / (parseFloat($("#wa_acid_perc").jqxNumberInput('decimal')) / 100); // ml
2862 console.log("Final ml: "+Acid);
2863 $("#wa_acid").val(Round(Acid, 2));
2864 setWaterAgent(AcidTypeData[AT].nl, Round(Acid, 2));
2865
2866 bicarbonate = bicarbonate - protonDeficit * frac / liters;
2867 total_alkalinity = bicarbonate * 50 / 61;
2868 } else if (protonDeficit < 0) { //Add base
2869 $("#wa_acid").val(0);
2870 setWaterAgent(last_acid, 0);
2871 r1d = Math.pow(10, (TpH - 6.38));
2872 r2d = Math.pow(10, (TpH - 10.38));
2873 f1d = 1 / (1 + r1d + r1d * r2d);
2874 f2d = f1d * r1d;
2875 f3d = f2d * r2d;
2876 switch (BT) {
2877 case 0: RA = -protonDeficit / (f1d - f3d); // Sodiumbicarbonate, mmol totaal
2878 RA = RA * MMNaHCO3/1000; //gram
2879 $("#wa_base").val(Round(RA, 2));
2880 setWaterAgent('NaHCO3', Round(RA, 2));
2881 if (liters > 0) {
2882 // Na
2883 RA = parseFloat($("#wa_nacl").jqxNumberInput('decimal')) * MMNa / MMNaCl +
2884 parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMNa / MMNaHCO3;
2885 RA = 1000 * RA / liters;
2886 sodium = wg_sodium + RA;
2887 // HCO3
2888 RA = parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMHCO3 / MMNaHCO3;
2889 RA = 1000 * RA / liters;
2890 bicarbonate = wg_bicarbonate + RA;
2891 total_alkalinity = bicarbonate * 50 / 61;
2892 RA = ResidualAlkalinity(wb_total_alkalinity, wb_calcium, wb_magnesium);
2893 }
2894 break;
2895 case 1: RA = -protonDeficit / (2 * f1d + f2d); // Sodiumcarbonate, mmol totaal
2896 RA = RA * MMNa2CO3/1000; //gram
2897 $("#wa_base").val(Round(RA, 2));
2898 setWaterAgent('Na2CO3', Round(RA, 2));
2899 if (liters > 0) {
2900 RA = parseFloat($("#wa_nacl").jqxNumberInput('decimal')) * MMNa / MMNaCl +
2901 parseFloat($("#wa_base").jqxNumberInput('decimal')) * 2 * MMNa / MMNa2CO3;
2902 RA = 1000 * RA / liters;
2903 sodium = wg_sodium + RA;
2904 // HCO3
2905 RA = parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMHCO3 / MMNa2CO3;
2906 RA = 1000 * RA / liters;
2907 bicarbonate = wg_bicarbonate + RA;
2908 total_alkalinity = bicarbonate * 50 / 61;
2909 RA = ResidualAlkalinity(wb_total_alkalinity, wb_calcium, wb_magnesium);
2910 }
2911 break;
2912 case 2: RA = -protonDeficit * (f1d - f3d); // Calciumcarbonate, mmol totaal
2913 RA = RA * MMCaCO3/1000; //gram
2914 //but only 1/3 is effective, so add 3 times as much
2915 RA = 3 * RA;
2916 $("#wa_base").val(Round(RA, 2));
2917 setWaterAgent('CaCO3', Round(RA, 2));
2918 if (liters > 0) {
2919 //Bicarbonate
2920 RA = parseFloat($("#wa_base").jqxNumberInput('decimal')) / 3 * MMHCO3 / MMCaCO3;
2921 RA = 1000 * RA / liters;
2922 bicarbonate = wg_bicarbonate + RA;
2923 total_alkalinity = bicarbonate * 50 / 61;
2924 //Ca precipitates out as Ca10(PO4)6(OH)2
2925 RA = parseFloat($("#wa_cacl2").jqxNumberInput('decimal')) * MMCa / MMCaCl2 +
2926 parseFloat($("#wa_caso4").jqxNumberInput('decimal')) * MMCa / MMCaSO4 +
2927 parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMCa / MMCaCO3;
2928 RA = 1000 * RA / liters;
2929 calcium = wg_calcium + RA;
2930 RA = ResidualAlkalinity(wb_total_alkalinity, wb_calcium, wb_magnesium);
2931 }
2932 break;
2933 case 3: RA = -protonDeficit / 19.3; // Calciumhydroxide
2934 $("#wa_base").val(Round(RA, 2));
2935 setWaterAgent('Ca(OH)2', Round(RA, 2));
2936 if (liters > 0) {
2937 // Bicarbonate
2938 RA = -protonDeficit / liters;
2939 total_alkalinity = wg_total_alkalinity + RA;
2940 bicarbonate = total_alkalinity * 61 / 50;
2941 // Calcium
2942 RA = parseFloat($("#wa_cacl2").jqxNumberInput('decimal')) * MMCa / MMCaCl2 +
2943 parseFloat($("#wa_caso4").jqxNumberInput('decimal')) * MMCa / MMCaSO4 +
2944 parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMCa / MMCaOH2;
2945 RA = 1000 * RA / liters;
2946 calcium = wg_calcium + RA;
2947 RA = ResidualAlkalinity(wb_total_alkalinity, wb_calcium, wb_magnesium);
2948 }
2949 break;
2950 }
2951 }
2952 ph = TpH;
2953 $('#wb_ph').val(Round(ph, 1));
2954 $('#est_mash_ph').val(Round(ph, 1));
2955 } else { // Manual
2956 console.log("calc_acid no");
2957 // First add base salts
2958 if (parseFloat($("#wa_base").jqxNumberInput('decimal')) > 0) {
2959 if (liters > 0) {
2960 switch (BT) {
2961 case 0: // Sodiumbicarbonate, Na
2962 RA = parseFloat($("#wa_nacl").jqxNumberInput('decimal')) * MMNa / MMNaCl +
2963 parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMNa / MMNaHCO3;
2964 RA = 1000 * RA / liters;
2965 sodium = wg_sodium + RA;
2966 // HCO3
2967 RA = parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMHCO3 / MMNaHCO3;
2968 RA = 1000 * RA / liters;
2969 bicarbonate = wg_bicarbonate + RA;
2970 total_alkalinity = bicarbonate * 50 / 61;
2971 RA = ResidualAlkalinity(wb_total_alkalinity, wb_calcium, wb_magnesium);
2972 break;
2973 case 1: // Sodiumcarbonate
2974 RA = parseFloat($("#wa_nacl").jqxNumberInput('decimal')) * MMNa / MMNaCl +
2975 parseFloat($("#wa_base").jqxNumberInput('decimal')) * 2 * MMNa / MMNa2CO3;
2976 RA = 1000 * RA / liters;
2977 sodium = wg_sodium + RA;
2978 // HCO3
2979 RA = parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMHCO3 / MMNa2CO3;
2980 RA = 1000 * RA / liters;
2981 bicarbonate = wg_bicarbonate + RA;
2982 total_alkalinity = bicarbonate * 50 / 61;
2983 RA = ResidualAlkalinity(wb_total_alkalinity, wb_calcium, wb_magnesium);
2984 break;
2985 case 2: // Calciumcarbonate: Bicarbonate
2986 RA = parseFloat($("#wa_base").jqxNumberInput('decimal')) / 3 * MMHCO3 / MMCaCO3;
2987 RA = 1000 * RA / liters;
2988 bicarbonate = wg_bicarbonate + RA;
2989 total_alkalinity = bicarbonate * 50 / 61;
2990 RA = ResidualAlkalinity(wb_total_alkalinity, wb_calcium, wb_magnesium);
2991 // Ca
2992 RA = parseFloat($("#wa_cacl2").jqxNumberInput('decimal')) * MMCa / MMCaCl2 +
2993 parseFloat($("#wa_caso4").jqxNumberInput('decimal')) * MMCa / MMCaSO4 +
2994 parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMCa / MMCaCO3;
2995 RA = 1000 * RA / liters;
2996 calcium = wg_calcium + RA;
2997 break;
2998 }
2999 }
3000 }
3001
3002 TpH = parseFloat(dataRecord.mash_ph);
3003 pHa = MashpH(); // This one is in demi water, should be in adjusted water???
3004 // Then calculate the new pH with added acids
3005 if (parseFloat($("#wa_acid").jqxNumberInput('decimal')) > 0) {
3006 console.log("TpH: "+TpH+" water: "+pHa);
3007 Acid = parseFloat($("#wa_acid").jqxNumberInput('decimal'));
3008 if (parseFloat($("#wa_acid_perc").jqxNumberInput('decimal')) == 0)
3009 $("#wa_acid_perc").val(AcidPrc);
3010 Acid = Acid / AcidPrc * (parseFloat($("#wa_acid_perc").jqxNumberInput('decimal')) / 100); // ml
3011 Acid *= AcidSG; // ml
3012 Acid /= MolWt; // mg
3013 Acidmg = Acid;
3014
3015 //find the pH where the protondeficit = protondeficit by the acid
3016 frac = CalcFrac(pHa, pK1, pK2, pK3);
3017 protonDeficit = Acid * frac;
3018
3019 deltapH = 0.001;
3020 deltapd = 0.1;
3021 pd = ProtonDeficit(pHa);
3022 n = 0;
3023 while (((pd < (protonDeficit - deltapd)) || (pd > (protonDeficit + deltapd))) && (n < 2000)) {
3024 n++;
3025 if (pd < (protonDeficit-deltapd))
3026 pHa -= deltapH;
3027 else if (pd > (protonDeficit+deltapd))
3028 pHa += deltapH;
3029 frac = CalcFrac(pHa, pK1, pK2, pK3);
3030 protonDeficit = Acid * frac;
3031 pd = ProtonDeficit(pHa);
3032 }
3033 console.log("n: "+n+" pd: "+pd+" protonDeficit: "+protonDeficit+" frac: "+frac+" pHa: "+pHa);
3034 RA = wg_bicarbonate - protonDeficit * frac / liters;
3035 bicarbonate = RA;
3036 total_alkalinity = RA * 50 / 61;
3037 ph = pHa;
3038 $('#wb_ph').val(Round(ph, 1));
3039 $('#est_mash_ph').val(Round(ph, 1));
3040 }
3041 }
3042
3043 if ((AT == 3) && (liters > 0)) { // Sulfuctic / Zwavelzuur
3044 RA = parseFloat($("#wa_caso4").jqxNumberInput('decimal')) * MMSO4 / MMCaSO4 +
3045 parseFloat($("#wa_mgso4").jqxNumberInput('decimal')) * MMSO4 / MMMgSO4 +
3046 Acidmg / 1000 * MMSO4 / (MMSO4 + 2);
3047 RA = 1000 * RA / liters;
3048 sulfate = wg_sulfate + RA; // Not add to sulfate??
3049 } else if ((AT == 1) && (liters > 0)) { // Hydrochloric, Zoutzuur
3050 RA = parseFloat($("#wa_cacl2").jqxNumberInput('decimal')) * MMCl / MMCaCl2 +
3051 parseFloat($("#wa_nacl").jqxNumberInput('decimal')) * MMCl / MMNaCl +
3052 Acidmg / 1000 * MMCl / (MMCl + 1);
3053 RA = 1000 * RA / liters;
3054 chloride = wg_chloride + RA;
3055 }
3056
3057 // 2:1 Sulfate to Chroride IPA's, Pale Ales.
3058 // 1:1 Sulfate to Chloride Balanced
3059 // 1:2 Sulfate to Chloride Malty
3060 // Note, values below are the other way, cl to so4!
3061 // So: 0.5 is IPA's, Pale Ales.
3062 // 1 Balanced
3063 // 2 Malty.
3064 $('#tgt_bu').val(Round(GetBUGU(), 2));
3065 // From brouwhulp.
3066 if (GetBUGU() < 0.32)
3067 $('#wr_bu').html("<span style='vertical-align: top; font-size: 14px; font-style: italic;'>Zeer moutig en zoet</span>");
3068 else if (GetBUGU() < 0.43)
3069 $('#wr_bu').html("<span style='vertical-align: top; font-size: 14px; font-style: italic;'>Moutig, zoet</span>");
3070 else if (GetBUGU() < 0.52)
3071 $('#wr_bu').html("<span style='vertical-align: top; font-size: 14px; font-style: italic;'>Evenwichtig</span>");
3072 else if (GetBUGU() < 0.63)
3073 $('#wr_bu').html("<span style='vertical-align: top; font-size: 14px; font-style: italic;'>Licht hoppig, bitter</span>");
3074 else
3075 $('#wr_bu').html("<span style='vertical-align: top; font-size: 14px; font-style: italic;'>Extra hoppig, zeer bitter</span>");
3076 $('#tgt_cl_so4').val(Round(GetOptClSO4ratio(), 1));
3077 if (sulfate > 0)
3078 RA = chloride / sulfate;
3079 else
3080 RA = 10;
3081 $('#got_cl_so4').val(Round(RA, 1));
3082 piCLSO4_low = 0.8 * GetOptClSO4ratio();
3083 piCLSO4_high = 1.2 * GetOptClSO4ratio();
3084 Res = 'normaal';
3085 if (RA < piCLSO4_low)
3086 Res = 'laag';
3087 else if (RA > piCLSO4_high)
3088 Res = 'hoog';
3089 setRangeIndicator('cl_so4', Res);
3090
3091 $('#wb_calcium').val(Round(calcium, 1));
3092 $('#wb_magnesium').val(Round(magnesium, 1));
3093 $('#wb_sodium').val(Round(sodium, 1));
3094 $('#wb_sulfate').val(Round(sulfate, 1));
3095 $('#wb_chloride').val(Round(chloride, 1));
3096 $('#wb_total_alkalinity').val(Round(total_alkalinity, 1));
3097
3098 if (calcium < 40) {
3099 setRangeIndicator("calcium", "laag");
3100 } else if (calcium > 150) {
3101 setRangeIndicator("calcium", "hoog");
3102 } else {
3103 setRangeIndicator("calcium", "normaal");
3104 }
3105 if (magnesium >= 0 && magnesium <= 30) {
3106 setRangeIndicator("magnesium", "normaal");
3107 } else {
3108 setRangeIndicator("magnesium", "hoog");
3109 }
3110 if (sodium <= 150) {
3111 setRangeIndicator("sodium", "normaal");
3112 } else {
3113 setRangeIndicator("sodium", "hoog");
3114 }
3115 // Both chloride and sulfate should be above 50 according to
3116 // John Palmer. So the Cl/SO4 ratio calculation will work.
3117 if (chloride <= 50) {
3118 setRangeIndicator("chloride", "laag");
3119 } else if (chloride <= 100) {
3120 setRangeIndicator("chloride", "normaal");
3121 } else {
3122 setRangeIndicator("chloride", "hoog");
3123 }
3124 if (sulfate <= 50) {
3125 setRangeIndicator("sulfate", "laag");
3126 } else if (sulfate <= 350) {
3127 setRangeIndicator("sulfate", "normaal");
3128 } else {
3129 setRangeIndicator("sulfate", "hoog");
3130 }
3131 if (ph < 5.2) {
3132 setRangeIndicator("ph", "laag");
3133 } else if (ph > 5.6) {
3134 setRangeIndicator("ph", "hoog");
3135 } else {
3136 setRangeIndicator("ph", "normaal");
3137 }
3138 calcSparge();
3139 calcMiscs();
3140 calcSupplies();
3141 }
3142
3143 function calcSparge() {
3144
3145 var TargetpH, Source_pH, Source_alkalinity, r1, r2, d, f1, f3,
3146 r143, r243, d43, f143, f343, alkalinity, Ct, r1g, r2g, dg, f1g, f3g,
3147 Acid, AT, result, pK1, pK2, pK3, MolWt, AcidSG, AcidPrc, fract;
3148
3149 // Code from BrewBuddy/Brouwhulp, who got it from http://www.brewery.org/brewery/library/Acidi0,00fWaterAJD0497.html
3150 TargetpH = dataRecord.sparge_ph;
3151 Source_pH = dataRecord.w1_ph;
3152 Source_alkalinity = dataRecord.w1_total_alkalinity;
3153 // Select watersource or fallback to the first source.
3154 if (dataRecord.sparge_source == 1) { // Source 2
3155 if (dataRecord.w2_ph > 0.0) {
3156 Source_pH = dataRecord.w2_ph;
3157 Source_alkalinity = dataRecord.w2_total_alkalinity;
3158 } else {
3159 dataRecord.sparge_source = 0; // Source 1
3160 $("#sparge_source").val(0);
3161 }
3162 } else if (dataRecord.sparge_source == 2) { // Mixed
3163 if (dataRecord.w2_ph > 0.0) {
3164 Source_pH = parseFloat($("#wg_ph").jqxNumberInput('decimal'));
3165 Source_alkalinity = parseFloat($("#wg_total_alkalinity").jqxNumberInput('decimal'));
3166 } else {
3167 dataRecord.sparge_source = 0;
3168 $("#sparge_source").val(0);
3169 }
3170 }
3171
3172 // Step 1: Compute the mole fractions of carbonic (f1o), bicarbonate (f2o) and carbonate(f3o) at the water pH
3173 r1 = Math.pow(10, Source_pH - 6.38);
3174 r2 = Math.pow(10, Source_pH - 10.373);
3175 d = 1 + r1 + r1*r2;
3176 f1 = 1/d;
3177 f3 = r1 * r2 / d;
3178
3179 //Step 2. Compute the mole fractions at pH = 4.3 (the pH which defines alkalinity)
3180 r143 = Math.pow(10, 4.3 - 6.38);
3181 r243 = Math.pow(10, 4.3 - 10.373);
3182 d43 = 1 + r143 + r143*r243;
3183 f143 = 1/d43;
3184 f343 = r143 * r243 / d43;
3185
3186 //Step 3. Convert the water alkalinity to milliequivalents/L
3187 alkalinity = Source_alkalinity / 50;
3188
3189 //Step 4. Solve
3190 Ct = (alkalinity - 1000 * (Math.pow(10, -4.3) - Math.pow(10, -Source_pH))) / ((f143-f1)+(f3-f343));
3191
3192 //Step 5. Compute mole fractions at desired pH
3193 r1g = Math.pow(10, TargetpH - 6.38);
3194 r2g = Math.pow(10, TargetpH - 10.373);
3195 dg = 1 + r1g + r1g*r2g;
3196 f1g = 1/dg;
3197 f3g = r1g * r2g / dg;
3198
3199 //Step 6. Use these to compute the milliequivalents acid required per liter (mEq/L)
3200 Acid = Ct * ((f1g-f1)+(f3-f3g)) + Math.pow(10, -TargetpH) - Math.pow(10, -Source_pH); //mEq/l
3201 Acid += 0.01; // Add acid that would be required for distilled water.
3202 if (dataRecord.sparge_acid_type < 0 || dataRecord.sparge_acid_type > 3) {
3203 dataRecord.sparge_acid_type = 0;
3204 $("#sparge_acid_type").val(0);
3205 }
3206
3207 //Step 8. Get the acid data.
3208 AT = dataRecord.sparge_acid_type;
3209 result = GetAcidSpecs(AT);
3210 pK1 = result.pK1;
3211 pK2 = result.pK2;
3212 pK3 = result.pK3;
3213 MolWt = result.MolWt;
3214 AcidSG = result.AcidSG;
3215 AcidPrc = result.AcidPrc;
3216 fract = CalcFrac(TargetpH, pK1, pK2, pK3);
3217
3218 //Step 9. Now divide the mEq required by the "fraction". This is the required number of moles of acid.
3219 Acid /= fract;
3220
3221 //Step 10. Multiply by molecular weight of the acid
3222 Acid *= MolWt; //mg
3223
3224 Acid = Acid / AcidSG; //ml ; 88% lactic solution
3225 f1 = dataRecord.sparge_acid_perc;
3226 if (f1 <= 0.1)
3227 f1 = AcidPrc;
3228 Acid = Acid * AcidPrc / (f1 / 100);
3229
3230 Acid *= dataRecord.sparge_volume; //ml lactic acid total
3231 Acid = Round(Acid, 2);
3232 dataRecord.sparge_acid_amount = Acid / 1000;
3233 $("#sparge_acid_amount").val(Acid);
3234 }
3235
3236 function calcFermentation(){
3237
3238 var primary_svg, secondary_svg, final_svg, ABV;
3239 if (dataRecord.brew_fermenter_sg<1.020)
3240 return;
3241
3242 if ((dataRecord.primary_end_sg > 0.990) && (dataRecord.primary_end_sg < dataRecord.brew_fermenter_sg)) {
3243 primary_svg = Round(100*(dataRecord.brew_fermenter_sg-dataRecord.primary_end_sg)/(dataRecord.brew_fermenter_sg-1),1);
3244 $("#primary_svg").val(primary_svg);
3245 if ((dataRecord.secondary_end_sg > 0.990) && (dataRecord.secondary_end_sg < dataRecord.brew_fermenter_sg)) {
3246 secondary_svg = Round(100*(dataRecord.brew_fermenter_sg-dataRecord.secondary_end_sg)/(dataRecord.brew_fermenter_sg-1),1);
3247 $("#secondary_svg").val(secondary_svg);
3248 if ((dataRecord.fg > 0.990) && (dataRecord.fg < dataRecord.brew_fermenter_sg)) {
3249 final_svg = Round(100*(dataRecord.brew_fermenter_sg-dataRecord.fg)/(dataRecord.brew_fermenter_sg-1),1);
3250 $("#final_svg").val(final_svg);
3251 ABV = Round(abvol(dataRecord.brew_fermenter_sg,dataRecord.fg),2);
3252 $("#final_abv").val(ABV);
3253 }
3254 }
3255 }
3256 }
3257
3258 function ResCO2(CO2,T){
3259
3260 var F=T*1.8+32;
3261 return 3.0378-0.050062*F+0.00026555*F*F;
3262 }
3263
3264 function CarbCO2toS(CO2,T,SFactor){
3265 var sugar=SFactor*(CO2-ResCO2(CO2,T))/0.286;
3266 if(sugar<0)
3267 sugar=0;
3268 return Round(sugar,3);
3269 }
3270
3271 function GetPressure(CO2, T1, T2) {
3272 var P, V = CO2 - ResCO2(CO2, T1);
3273 if (V < 0)
3274 return 0;
3275 P = -1.09145427669121 + 0.00800006989646477 * T2 + 0.000260276315484684 * T2 * T2 + 0.0215142075945119 * T2 * V +
3276 0.674996600795854 * V + -0.00471757220150754 * V * V;
3277 //console.log("CO2: "+CO2+" "+V+" Temp: "+T1+" "+T2+" Pressure: "+P);
3278 if (P < 0)
3279 P = 0;
3280 P = P * 1.01325; // atm to bar
3281 return Round(P,1);
3282 }
3283
3284 function CarbCO2ToPressure(CO2, T) {
3285 return (CO2-(-0.000005594056*Math.pow(T,4)+0.000144357886*Math.pow(T,3)+0.000362999168*T*T-0.064872987645*T+1.641145175049)) /
3286 (0.00000498031*Math.pow(T,4)-0.00024358267*Math.pow(T,3)+0.00385867329*T*T-0.05671206825*T+1.53801423376);
3287 }
3288
3289 function calcCarbonation() {
3290
3291 var TSec, ABV, bvol, balc, babv, mvol, malc, tvol, talc,
3292 i, row, SFactor, pvol, pabv, Pressure, kabv;
3293
3294 TSec=dataRecord.secondary_temp;
3295 if(TSec<1)
3296 TSec=dataRecord.primary_end_temp;
3297 if(TSec<1)
3298 TSec=18;
3299
3300 if(dataRecord.fg==0.000)
3301 ABV=abvol(dataRecord.brew_fermenter_sg,parseFloat($("#est_fg").jqxNumberInput('decimal')));
3302 else
3303 ABV=abvol(dataRecord.brew_fermenter_sg,dataRecord.fg);
3304
3305 /* Calculate new volume and alcohol. */
3306 bvol = dataRecord.package_volume-(ABV*dataRecord.package_volume)/100;
3307 balc = dataRecord.package_volume-bvol;
3308 mvol = dataRecord.package_infuse_amount-(dataRecord.package_infuse_abv*dataRecord.package_infuse_amount)/100;
3309 malc = dataRecord.package_infuse_amount-mvol;
3310 talc = balc+malc;
3311 tvol = bvol+mvol;
3312 ABV = Round(talc/(tvol+talc)*100,2);
3313 dataRecord.package_abv=ABV;
3314 $("#package_abv").val(ABV);
3315
3316 // console.log("calcCarbonation() TSec:"+TSec+" ABV:"+ABV);
3317 if (!(rows = $('#fermentableGrid').jqxGrid('getrows'))){
3318 return;
3319 }
3320
3321 // Bottles
3322 dataRecord.bottle_priming_amount=0;
3323 dataRecord.bottle_priming_total=0;
3324 for (i = 0; i < rows.length; i++) {
3325 row = rows[i];
3326 if(row.f_added==4){
3327 SFactor=1/((row.f_yield/100)*(1-row.f_moisture/100));
3328 dataRecord.bottle_priming_amount=CarbCO2toS(dataRecord.bottle_carbonation,TSec,SFactor);
3329 dataRecord.bottle_priming_total=Round(dataRecord.bottle_amount*dataRecord.bottle_priming_amount,2);
3330 $("#fermentableGrid").jqxGrid('setcellvalue',i,'f_amount',dataRecord.bottle_priming_total/1000);
3331 }
3332 }
3333 $("#bottle_priming_amount").val(Round(dataRecord.bottle_priming_amount,1));
3334 $("#bottle_priming_total").val(dataRecord.bottle_priming_total);
3335 pabv=ABV+dataRecord.bottle_priming_amount*0.47/7.907;
3336 pvol=dataRecord.bottle_amount-(pabv*dataRecord.bottle_amount)/100;
3337 talc=dataRecord.bottle_amount-pvol;
3338 tvol=pvol+dataRecord.bottle_priming_water;
3339 babv = Round(talc/(tvol+talc)*100,2);
3340 //console.log("bottle pabv:"+pabv+" pvol:"+pvol+" wvol:"+dataRecord.bottle_priming_water+" tvol:"+tvol+" talc:"+talc+" abv:"+babv);
3341 $("#bottle_abv").val(babv);
3342 $("#bottle_pressure").val(GetPressure(dataRecord.bottle_carbonation,TSec,dataRecord.bottle_carbonation_temp));
3343
3344 // Kegs
3345 Pressure=CarbCO2ToPressure(dataRecord.keg_carbonation,dataRecord.keg_carbonation_temp);
3346 if(Pressure<0)Pressure=0;
3347 dataRecord.keg_pressure=Pressure;
3348 $("#keg_pressure").val(Round(Pressure,1));
3349
3350 dataRecord.keg_priming_amount=0;
3351 dataRecord.keg_priming_total=0;
3352 if(!dataRecord.keg_forced_carb){
3353 for(i = 0; i < rows.length; i++){
3354 row=rows[i];
3355 if(row.f_added==5){
3356 SFactor=1/((row.f_yield/100)*(1-row.f_moisture/100));
3357 dataRecord.keg_priming_amount=CarbCO2toS(dataRecord.keg_carbonation,TSec,SFactor);
3358 dataRecord.keg_priming_total=Round(dataRecord.keg_amount*dataRecord.keg_priming_amount,2);
3359 $("#fermentableGrid").jqxGrid('setcellvalue',i,'f_amount',dataRecord.keg_priming_total/1000);
3360 }
3361 }
3362 $("#keg_priming_amount").val(Round(dataRecord.keg_priming_amount,1));
3363 $("#keg_priming_total").val(dataRecord.keg_priming_total);
3364 pabv=ABV+dataRecord.keg_priming_amount*0.47/7.907;
3365 pvol=dataRecord.keg_amount-(pabv*dataRecord.keg_amount)/100;
3366 talc=dataRecord.keg_amount-pvol;
3367 tvol=pvol+dataRecord.keg_priming_water;
3368 kabv=Round(talc/(tvol+talc)*100,2);
3369 //console.log("kegs pabv:"+pabv+" pvol:"+pvol+" wvol:"+dataRecord.keg_priming_water+" tvol:"+tvol+" talc:"+talc+" abv:"+kabv);
3370 $("#keg_abv").val(kabv);
3371 } else {
3372 $("#keg_priming_amount").val(0);
3373 $("#keg_priming_total").val(0);
3374 $("#keg_abv").val(ABV);
3375 }
3376 }
3377
3378 function calcStage() {
3379
3380 var newstage = dataRecord.stage, d, date1, date2, date1_unixtime, date2_unixtime,
3381 timeDifference, timeDifferenceInDays;
3382
3383 if (newstage == 0 && dataRecord.est_og > 1.005 && dataRecord.est_color > 3 && dataRecord.est_ibu > 3)
3384 newstage = 1;
3385 if (newstage == 1 && parseFloat($("#brew_date_start").val()) > 2000)
3386 newstage = 2; // Brewday
3387 if (newstage == 2 && ($("#brew_date_start").val() == ''))
3388 newstage = 1; // No brewday
3389 if (newstage == 2 && parseFloat($("#brew_date_end").val()) > 2000)
3390 newstage = 3; // Primary
3391 if (newstage == 3 && parseFloat($("#primary_end_date").val()) > 2000)
3392 newstage = 4; // Secondary
3393 if (newstage == 4 && parseFloat($("#secondary_end_date").val()) > 2000)
3394 newstage = 5; // Tertiary
3395 if (newstage == 5 && parseFloat($("#package_date").val()) > 2000)
3396 newstage = 6; // Package
3397 if (newstage >= 6 && newstage < 9) {
3398 d = new Date();
3399 date2 = $("#package_date").val();
3400 date2 = date2.split('-');
3401 // Now we convert the array to a Date object
3402 date1 = new Date(d.getFullYear(), d.getMonth(), d.getDate());
3403 date2 = new Date(date2[0], date2[1]-1, date2[2]);
3404 // We use the getTime() method and get the unixtime
3405 date1_unixtime = parseInt(date1.getTime() / 1000);
3406 date2_unixtime = parseInt(date2.getTime() / 1000);
3407 // This is the calculated difference in seconds
3408 timeDifference = date1_unixtime - date2_unixtime;
3409 timeDifferenceInDays = timeDifference / 60 / 60 / 24;
3410 if (timeDifferenceInDays > 0) { // At least one day
3411 if (timeDifferenceInDays >= 42) // 6 weeks
3412 newstage = 9; // Ready to taste
3413 else if (timeDifferenceInDays >= 14) // 14 days
3414 newstage = 8; // Mature
3415 else
3416 newstage = 7; // Carbonation
3417 }
3418 }
3419 if (newstage == 9 && parseFloat($("#taste_date").val()) > 2000)
3420 newstage = 10; // Ready
3421
3422 if (newstage != dataRecord.stage) {
3423 console.log("calcStage() old: "+dataRecord.stage+" new: "+newstage);
3424 dataRecord.stage = newstage;
3425 }
3426
3427 /*
3428 * Set stage and enable or disable parts of the screens.
3429 */
3430 $("#stage").val(StageData[dataRecord.stage].nl);
3431 if (dataRecord.stage >= 10) {
3432 $("#locked").jqxCheckBox({ disabled:false });
3433 }
3434
3435 /*
3436 * When the brew is in progress or done, block equipment select and delete.
3437 */
3438 if (dataRecord.stage > 1) {
3439 $("#equipmentSelect").jqxDropDownList({ disabled: true });
3440 $("#Delete").jqxButton({ disabled: true });
3441 }
3442
3443 if (dataRecord.stage < 1) // Planning, no ingredients
3444 $('#jqxTabs').jqxTabs('disableAt', 8); // Brewday tab
3445 else
3446 $('#jqxTabs').jqxTabs('enableAt', 8);
3447
3448 if (dataRecord.stage < 3) { // Primary
3449 $('#jqxTabs').jqxTabs('disableAt', 9); // Fermentation tab
3450 } else {
3451 $('#jqxTabs').jqxTabs('enableAt', 9);
3452 $("#name").jqxInput({ disabled: true });
3453 $("#code").jqxInput({ disabled: true });
3454 $("#batch_size").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
3455 $("#boil_size").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
3456 $("#boil_time").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
3457 $("#efficiency").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
3458 $("#est_og").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
3459 $("#type").jqxDropDownList({ disabled: true });
3460 $("#styleSelect").jqxDropDownList({ disabled: true });
3461 $("#color_method").jqxDropDownList({ disabled: true });
3462 $("#ibu_method").jqxDropDownList({ disabled: true });
3463 $("#mash_select").jqxDropDownList({ disabled: true });
3464 $("#w1_name").jqxDropDownList({ disabled: true });
3465 $("#w2_name").jqxDropDownList({ disabled: true });
3466 $("#w2_amount").jqxNumberInput({ readOnly: true });
3467 $("#pr_name").jqxDropDownList({ disabled: true });
3468 $("#wa_cacl2").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
3469 $("#wa_caso4").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
3470 $("#wa_mgso4").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
3471 $("#wa_nacl").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
3472 $("#mash_ph").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
3473 $("#calc_acid").jqxCheckBox({ disabled: true });
3474 $("#wa_base_name").jqxDropDownList({ disabled: true });
3475 $("#wa_base").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
3476 $("#wa_acid_name").jqxDropDownList({ disabled: true });
3477 $("#wa_acid").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
3478 $("#wa_acid_perc").jqxNumberInput({ spinButtons: false, readOnly: true, width: 70 });
3479 $("#sparge_temp").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
3480 $("#sparge_volume").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
3481 $("#sparge_ph").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
3482 $("#sparge_source").jqxDropDownList({ disabled: true });
3483 $("#sparge_acid_type").jqxDropDownList({ disabled: true });
3484 $("#sparge_acid_perc").jqxNumberInput({ spinButtons: false, readOnly: true, width: false });
3485 $("#starter_enable").jqxCheckBox({ disabled: true });
3486 $("#starter_type").jqxDropDownList({ disabled: true });
3487 $("#starter_try").jqxButton({ disabled: true });
3488 $("#starter_sg").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
3489 $("#starter_viability").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
3490 }
3491 if (dataRecord.stage > 3) { // Primary fermentation done
3492 $("#brew_date_start").jqxDateTimeInput({ disabled: true });
3493 $("#brew_date_end").jqxDateTimeInput({ disabled: true });
3494 $("#brew_mash_ph").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
3495 $("#brew_preboil_ph").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
3496 $("#brew_aboil_ph").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
3497 $("#brew_mash_sg").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
3498 $("#brew_preboil_sg").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
3499 $("#brew_aboil_sg").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
3500 $("#brew_preboil_volume").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
3501 $("#brew_aboil_volume").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
3502 $("#brew_whirlpool9").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
3503 $("#brew_cooling_to").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
3504 $("#brew_whirlpool7").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
3505 $("#brew_cooling_method").jqxDropDownList({ disabled: true });
3506 $("#brew_whirlpool6").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
3507 $("#brew_cooling_time").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
3508 $("#brew_sparge_ph").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
3509 $("#brew_whirlpool2").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
3510 $("#brew_aeration_type").jqxDropDownList({ disabled: true });
3511 $("#brew_fermenter_tcloss").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
3512 $("#brew_aeration_time").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
3513 $("#brew_fermenter_extrawater").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
3514 $("#brew_aeration_speed").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
3515 }
3516 if (dataRecord.stage == 5) // Lagering, allow packaging
3517 $("#package_date").jqxDateTimeInput({ disabled: false });
3518 else
3519 $("#package_date").jqxDateTimeInput({ disabled: true });
3520 if (dataRecord.stage >= 5) { // At least secondary
3521 $("#primary_start_temp").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
3522 $("#primary_max_temp").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
3523 $("#primary_end_temp").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
3524 $("#primary_end_sg").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
3525 $("#primary_end_brix").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
3526 $("#primary_end_date").jqxDateTimeInput({ disabled: true });
3527 }
3528 if (dataRecord.stage >= 6) { // Packaged
3529 $("#secondary_temp").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
3530 $("#secondary_end_sg").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
3531 $("#secondary_end_date").jqxDateTimeInput({ disabled: true });
3532 $("#tertiary_temp").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
3533 $("#fg").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
3534 $("#final_brix").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
3535 $("#package_date").jqxDateTimeInput({ disabled: true });
3536 $("#package_volume").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
3537 $("#package_infuse_amount").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
3538 $("#package_infuse_abv").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
3539 $("#package_infuse_notes").jqxInput({ disabled: true });
3540 $("#package_ph").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
3541 $("#bottle_amount").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
3542 $("#bottle_priming_water").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
3543 $("#keg_priming_water").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
3544 $("#keg_amount").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
3545 $("#bottle_carbonation").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
3546 $("#keg_carbonation").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
3547 $("#bottle_priming_sugar").jqxDropDownList({ disabled: true });
3548 $("#keg_priming_sugar").jqxDropDownList({ disabled: true });
3549 $("#keg_forced_carb").jqxCheckBox({ disabled : true });
3550 $("#bottle_carbonation_temp").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
3551 $("#keg_carbonation_temp").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
3552 }
3553 if (dataRecord.stage < 8) { // Taste when at least Mature.
3554 $('#jqxTabs').jqxTabs('disableAt', 11); // Tasting tab
3555 } else {
3556 $('#jqxTabs').jqxTabs('enableAt', 11);
3557 }
3558
3559 if (dataRecord.stage == 11) { // Locked
3560 $("#taste_date").jqxDateTimeInput({ disabled: true });
3561 $("#taste_rate").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
3562 $("#taste_color").jqxInput({ disabled: true });
3563 $("#taste_transparency").jqxInput({ disabled: true });
3564 $("#taste_head").jqxInput({ disabled: true });
3565 $("#taste_aroma").jqxInput({ disabled: true });
3566 $("#taste_taste").jqxInput({ disabled: true });
3567 $("#taste_aftertaste").jqxInput({ disabled: true });
3568 $("#taste_mouthfeel").jqxInput({ disabled: true });
3569 $("#taste_notes").jqxInput({ disabled: true });
3570 $("#notes").jqxInput({ disabled: true });
3571 } else {
3572 $("#notes").jqxInput({ disabled: false });
3573 }
3574 }
3575
3576 function showStarter() {
3577
3578 if (dataRecord.starter_enable) {
3579 $("#propagator").show();
3580 $("#starter_type").jqxDropDownList( {disabled: false });
3581 $("#starter_try").jqxButton({ disabled: false });
3582 $("#starter_sg").jqxNumberInput({ spinButtons: true, readOnly: false, width: 110 });
3583 $("#starter_viability").jqxNumberInput({ spinButtons: true, readOnly: false, width: 110 });
3584 } else {
3585 $("#propagator").hide();
3586 $("#starter_type").jqxDropDownList( {disabled: true });
3587 $("#starter_try").jqxButton({ disabled: true });
3588 $("#starter_sg").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
3589 $("#starter_viability").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
3590 }
3591 }
3592
3593 function calcInit () {
3594 console.log("calcInit()");
3595
3596 calcMashEfficiency();
3597 calcEfficiencyBeforeBoil();
3598 calcEfficiencyAfterBoil();
3599
3600 $("#starter_enable").on('checked', function (event) {
3601 dataRecord.starter_enable = 1;
3602 showStarter();
3603 calcYeast();
3604 });
3605 $("#starter_enable").on('unchecked', function (event) {
3606 dataRecord.starter_enable = 0;
3607 showStarter();
3608 calcYeast();
3609 });
3610 $("#starter_try").click(function () {
3611 $("#prop1_volume").val(0);
3612 $("#prop2_volume").val(0);
3613 $("#prop3_volume").val(0);
3614 $("#prop4_volume").val(0);
3615 calcYeast();
3616 });
3617 $('#starter_type').on('change', function (event) {
3618 if (event.args) {
3619 var index = event.args.index;
3620 dataRecord.starter_type = index;
3621 calcYeast();
3622 }
3623 });
3624 $('#starter_sg').on('change', function (event) {
3625 if (event.args) {
3626 dataRecord.starter_sg = event.args.value;
3627 calcYeast();
3628 }
3629 });
3630 $('#starter_viability').on('change', function (event) {
3631 if (event.args) {
3632 dataRecord.starter_viability = event.args.value;
3633 calcFermentables();
3634 calcYeast();
3635 }
3636 });
3637 $('#prop1_type').on('change', function (event) {
3638 if (event.args) {
3639 var index = event.args.index;
3640 dataRecord.prop1_type = index;
3641 calcYeast();
3642 }
3643 });
3644 $('#prop1_volume').on('change', function (event) {
3645 if (event.args) {
3646 dataRecord.prop1_volume = event.args.value;
3647 calcYeast();
3648 }
3649 });
3650 $('#prop2_type').on('change', function (event) {
3651 if (event.args) {
3652 var index = event.args.index;
3653 dataRecord.prop2_type = index;
3654 calcYeast();
3655 }
3656 });
3657 $('#prop2_volume').on('change', function (event) {
3658 if (event.args) {
3659 dataRecord.prop2_volume = event.args.value;
3660 calcYeast();
3661 }
3662 });
3663 $('#prop3_type').on('change', function (event) {
3664 if (event.args) {
3665 var index = event.args.index;
3666 dataRecord.prop3_type = index;
3667 calcYeast();
3668 }
3669 });
3670 $('#prop3_volume').on('change', function (event) {
3671 if (event.args) {
3672 dataRecord.prop3_volume = event.args.value;
3673 calcYeast();
3674 }
3675 });
3676 $('#prop4_type').on('change', function (event) {
3677 if (event.args) {
3678 var index = event.args.index;
3679 dataRecord.prop4_type = index;
3680 calcYeast();
3681 }
3682 });
3683 $('#prop4_volume').on('change', function (event) {
3684 if (event.args) {
3685 dataRecord.prop4_volume = event.args.value;
3686 calcYeast();
3687 }
3688 });
3689
3690 $("#calc_acid").on('checked', function (event) {
3691 dataRecord.calc_acid = 1;
3692 calcWater();
3693 });
3694 $("#calc_acid").on('unchecked', function (event) {
3695 dataRecord.calc_acid = 0;
3696 calcWater();
3697 });
3698 $("#w1_name").jqxDropDownList('selectItem', dataRecord.w1_name);
3699 $("#w2_name").jqxDropDownList('selectItem', dataRecord.w2_name);
3700 // Fix tap water if zero using mash infuse amount.
3701 if (parseFloat($("#w1_amount").jqxNumberInput('decimal')) == 0 && mash_infuse > 0) {
3702 $("#w1_amount").val(mash_infuse);
3703 dataRecord.w1_amount = mash_infuse;
3704 $("#wg_amount").val(mash_infuse);
3705 $("#w2_amount").val(0);
3706 dataRecord.w2_amount = 0;
3707 }
3708 calcWater();
3709 $("#w2_amount").on('change', function (event) {
3710 var newval = parseFloat(event.args.value);
3711
3712 if (newval > mash_infuse) {
3713 $("#w2_amount").val(dataRecord.w2_amount);
3714 return;
3715 }
3716 dataRecord.w1_amount = parseFloat($("#wg_amount").jqxNumberInput('decimal')) - newval;
3717 $("#w1_amount").val(dataRecord.w1_amount);
3718 dataRecord.w2_amount = newval;
3719 console.log("new: "+event.args.value+" w1: "+dataRecord.w1_amount+" w2: "+dataRecord.w2_amount);
3720 calcWater();
3721 });
3722 $('#wa_cacl2').on('change', function (event) {
3723 if (event.args) {
3724 setWaterAgent('CaCl2', 0); // This can prevent double entries.
3725 setWaterAgent('CaCl2', event.args.value);
3726 calcWater();
3727 }
3728 });
3729 $('#wa_caso4').on('change', function (event) {
3730 if (event.args) {
3731 setWaterAgent('CaSO4', 0);
3732 setWaterAgent('CaSO4', event.args.value);
3733 calcWater();
3734 }
3735 });
3736 $('#wa_mgso4').on('change', function (event) {
3737 if (event.args) {
3738 setWaterAgent('MgSO4', 0);
3739 setWaterAgent('MgSO4', event.args.value);
3740 calcWater();
3741 }
3742 });
3743 $('#wa_nacl').on('change', function (event) {
3744 if (event.args) {
3745 setWaterAgent('NaCl', 0);
3746 setWaterAgent('NaCl', event.args.value);
3747 calcWater();
3748 }
3749 });
3750 $('#wa_base_name').on('change', function (event) {
3751 if (event.args) {
3752 var index = event.args.index;
3753 console.log("wa_base_name "+index);
3754 setWaterAgent(last_base, 0);
3755 last_base = BaseTypeData[index].nl;
3756 setWaterAgent(last_base, parseFloat($("#wa_base").jqxNumberInput('decimal')));
3757 dataRecord.wa_base_name = index;
3758 calcWater();
3759 }
3760 });
3761 $('#wa_base').on('change', function (event) {
3762 var name = BaseTypeData[$("#wa_base_name").val()].nl;
3763 setWaterAgent(name, parseFloat(event.args.value));
3764 calcWater();
3765 });
3766 $('#wa_acid_name').on('change', function (event) {
3767 if (event.args) {
3768 var index = event.args.index;
3769 console.log("wa_acid_name "+index);
3770 setWaterAgent(last_acid, 0);
3771 last_acid = AcidTypeData[index].nl;
3772 setWaterAgent(last_acid, parseFloat($("#wa_acid").jqxNumberInput('decimal')));
3773 dataRecord.wa_acid_name = index;
3774 calcWater();
3775 }
3776 });
3777 $('#wa_acid').on('change', function (event) {
3778 var name = AcidTypeData[$("#wa_acid_name").val()].nl;
3779 setWaterAgent(name, parseFloat(event.args.value));
3780 calcWater();
3781 });
3782 $('#wa_acid_perc').on('change', function (event) { calcWater(); });
3783
3784 $('#color_method').on('change', function (event) {
3785 dataRecord.color_method = event.args.index;
3786 calcFermentables();
3787 });
3788 $('#ibu_method').on('change', function (event) {
3789 dataRecord.ibu_method = event.args.index;
3790 calcFermentables();
3791 calcIBUs();
3792 });
3793
3794 $('#batch_size').on('change', function (event) {
3795 console.log("batch_size change:"+event.args.value+" old:"+dataRecord.batch_size);
3796 $("#est_a_vol").val(event.args.value * 1.04);
3797 var factor, new_boil = parseFloat(event.args.value) + dataRecord.boil_size - dataRecord.batch_size;
3798 factor = parseFloat(event.args.value) / dataRecord.batch_size;
3799 dataRecord.boil_size = new_boil;
3800 $("#boil_size").val(Round(new_boil, 2));
3801 $("#est_pre_vol").val(Round(new_boil * 1.04, 2));
3802 dataRecord.sparge_volume *= factor;
3803 $("#sparge_volume").val(dataRecord.sparge_volume);
3804 $("#brew_sparge_volume").val(dataRecord.sparge_volume);
3805 dataRecord.batch_size = parseFloat(event.args.value);
3806 calcFermentablesFromOG(parseFloat($("#est_og").jqxNumberInput('decimal'))); // Keep the OG
3807 adjustWaters(factor);
3808 calcFermentables();
3809 adjustHops(factor);
3810 adjustMiscs(factor);
3811 adjustYeasts(factor);
3812 calcIBUs();
3813 calcWater();
3814 calcSparge();
3815 calcMash();
3816 });
3817 $('#boil_time').on('change', function (event) {
3818 console.log("boil_time change:"+parseFloat(event.args.value)+" old:"+dataRecord.boil_time);
3819 var new_boil, new_evap, old_evap = parseFloat(dataRecord.boil_size) - parseFloat(dataRecord.batch_size);
3820 new_evap = old_evap * (parseFloat(event.args.value) / dataRecord.boil_time);
3821 new_boil = parseFloat(dataRecord.batch_size) + new_evap;
3822 dataRecord.boil_time = parseFloat(event.args.value);
3823 dataRecord.boil_size = new_boil;
3824 $("#est_pre_vol").val(Round(new_boil * 1.04, 2));
3825 $("#boil_size").val(Round(new_boil, 2));
3826 calcFermentables();
3827 calcIBUs();
3828 calcYeast();
3829 });
3830 $('#efficiency').on('change', function (event) {
3831 var estog = parseFloat($("#est_og").jqxNumberInput('decimal'));
3832 dataRecord.efficiency = parseFloat(event.args.value);
3833 console.log("efficiency change:"+dataRecord.efficiency+" est_og:"+estog);
3834 calcFermentablesFromOG(estog); // Keep the OG
3835 calcFermentables();
3836 calcIBUs();
3837 calcYeast();
3838 });
3839 $('#est_og').on('change', function (event) {
3840 dataRecord.est_og = parseFloat(event.args.value);
3841 console.log("est_og change:"+dataRecord.est_og);
3842 $('#est_og2').val(dataRecord.est_og);
3843 calcFermentablesFromOG(dataRecord.est_og); // Adjust fermentables amounts
3844 calcFermentables(); // Update the recipe details
3845 calcIBUs(); // and the IBU's.
3846 calcMash();
3847 calcYeast();
3848 });
3849 $('#mash_ph').on('change', function (event) {
3850 dataRecord.mash_ph = parseFloat(event.args.value);
3851 calcWater();
3852 });
3853
3854 $('#sparge_ph').on('change', function (event) {
3855 dataRecord.sparge_ph = parseFloat(event.args.value);
3856 calcSparge();
3857 });
3858 $('#sparge_volume').on('change', function (event) {
3859 dataRecord.sparge_volume = parseFloat(event.args.value);
3860 $('#brew_sparge_volume').val(dataRecord.sparge_volume);
3861 calcSparge();
3862 });
3863 $("#sparge_temp").on('change', function (event) {
3864 dataRecord.sparge_temp = parseFloat(event.args.value);
3865 $('#brew_sparge_temperature').val(dataRecord.sparge_temp);
3866 });
3867 $('#sparge_source').on('change', function (event) {
3868 if (event.args) {
3869 var index = event.args.index;
3870 dataRecord.sparge_source= index;
3871 calcSparge();
3872 }
3873 });
3874 $('#sparge_acid_type').on('change', function (event) {
3875 if (event.args) {
3876 var index = event.args.index;
3877 dataRecord.sparge_acid_type = index;
3878 console.log("new sparge_acid_type: "+dataRecord.sparge_acid_type);
3879 calcSparge();
3880 }
3881 });
3882 $('#sparge_acid_perc').on('change', function (event) {
3883 dataRecord.sparge_acid_perc = parseFloat(event.args.value);
3884 calcSparge();
3885 });
3886
3887 calcFermentation();
3888 calcCarbonation();
3889 $('#package_volume').on('change', function (event) {
3890 var diff, tnew, told = dataRecord.package_volume + dataRecord.package_infuse_amount;
3891 dataRecord.package_volume = parseFloat(event.args.value);
3892 if (dataRecord.package_volume > dataRecord.brew_fermenter_volume) {
3893 dataRecord.package_volume = dataRecord.brew_fermenter_volume;
3894 $('#package_volume').val(dataRecord.package_volume);
3895 }
3896 tnew = dataRecord.package_volume + dataRecord.package_infuse_amount;
3897 diff = tnew - told;
3898 if (told > 0) {
3899 dataRecord.bottle_amount += (dataRecord.bottle_amount / told) * diff;
3900 dataRecord.keg_amount += (dataRecord.keg_amount / told) * diff;
3901 } else {
3902 dataRecord.bottle_amount = tnew;
3903 dataRecord.keg_amount = 0;
3904 }
3905 console.log("diff:"+diff+" old:"+told+" bottle:"+dataRecord.bottle_amount+" keg:"+dataRecord.keg_amount);
3906 $('#bottle_amount').val(parseFloat(dataRecord.bottle_amount * 1000) / 1000);
3907 $('#keg_amount').val(parseFloat(dataRecord.keg_amount * 1000) / 1000);
3908 calcCarbonation();
3909 });
3910 $('#package_infuse_amount').on('change', function (event) {
3911 var diff, tnew, told = dataRecord.package_volume + dataRecord.package_infuse_amount;
3912 dataRecord.package_infuse_amount = parseFloat(event.args.value);
3913 tnew = dataRecord.package_volume + dataRecord.package_infuse_amount;
3914 diff = tnew - told;
3915 if (told > 0) {
3916 dataRecord.bottle_amount += (dataRecord.bottle_amount / told) * diff;
3917 dataRecord.keg_amount += (dataRecord.keg_amount / told) * diff;
3918 } else {
3919 dataRecord.bottle_amount = tnew;
3920 dataRecord.keg_amount = 0;
3921 }
3922 console.log("diff:"+diff+" old:"+told+" bottle:"+dataRecord.bottle_amount+" keg:"+dataRecord.keg_amount);
3923 $('#bottle_amount').val(parseFloat(dataRecord.bottle_amount * 1000) / 1000);
3924 $('#keg_amount').val(parseFloat(dataRecord.keg_amount * 1000) / 1000);
3925 calcCarbonation();
3926 });
3927 $('#package_infuse_abv').on('change', function (event) {
3928 dataRecord.package_infuse_abv = parseFloat(event.args.value);
3929 calcCarbonation();
3930 });
3931 $('#bottle_amount').on('change', function (event) {
3932 var vtot, diff, vnew = parseFloat(event.args.value);
3933 vtot = dataRecord.package_volume + dataRecord.package_infuse_amount;
3934 if (vnew > vtot)
3935 vnew = vtot;
3936 diff = dataRecord.bottle_amount - vnew;
3937 dataRecord.bottle_amount = Math.round((dataRecord.bottle_amount - diff) * 1000) / 1000;
3938 dataRecord.keg_amount = Math.round((dataRecord.keg_amount + diff) * 1000) / 1000;
3939 $('#bottle_amount').val(parseFloat(dataRecord.bottle_amount));
3940 $('#keg_amount').val(parseFloat(dataRecord.keg_amount));
3941 calcCarbonation();
3942 });
3943 $("#bottle_priming_water").on('change', function (event) {
3944 dataRecord.bottle_priming_water = parseFloat(event.args.value);
3945 calcCarbonation();
3946 });
3947 $('#keg_amount').on('change', function (event) {
3948 var diff, vtot, vnew = parseFloat(event.args.value);
3949 vtot = dataRecord.package_volume + dataRecord.package_infuse_amount;
3950 if (vnew > vtot)
3951 vnew = vtot;
3952 diff = dataRecord.keg_amount - vnew;
3953 dataRecord.bottle_amount = Math.round((dataRecord.bottle_amount + diff) * 1000) / 1000;
3954 dataRecord.keg_amount = Math.round((dataRecord.keg_amount - diff) * 1000) / 1000;
3955 $('#bottle_amount').val(parseFloat(dataRecord.bottle_amount));
3956 $('#keg_amount').val(parseFloat(dataRecord.keg_amount));
3957 calcCarbonation();
3958 });
3959 $("#keg_priming_water").on('change', function (event) {
3960 dataRecord.keg_priming_water = parseFloat(event.args.value);
3961 calcCarbonation();
3962 });
3963 $('#bottle_carbonation').on('change', function (event) {
3964 dataRecord.bottle_carbonation = parseFloat(event.args.value);
3965 calcCarbonation();
3966 });
3967 $('#bottle_carbonation_temp').on('change', function (event) {
3968 dataRecord.bottle_carbonation_temp = parseFloat(event.args.value);
3969 calcCarbonation();
3970 });
3971 $('#keg_carbonation').on('change', function (event) {
3972 dataRecord.keg_carbonation = parseFloat(event.args.value);
3973 calcCarbonation();
3974 });
3975 $("#keg_forced_carb").on('checked', function (event) {
3976 dataRecord.keg_forced_carb = 1;
3977 calcCarbonation();
3978 });
3979 $("#keg_forced_carb").on('unchecked', function (event) {
3980 dataRecord.keg_forced_carb = 0;
3981 calcCarbonation();
3982 });
3983 $('#keg_carbonation_temp').on('change', function (event) {
3984 dataRecord.keg_carbonation_temp = parseFloat(event.args.value);
3985 calcCarbonation();
3986 });
3987
3988 $("#brew_fermenter_extrawater").on('change',function (event){
3989 dataRecord.brew_fermenter_extrawater=parseFloat(event.args.value);calcFermentables();calcIBUs();calcYeast();
3990 });
3991 $("#brew_fermenter_tcloss").on('change',function (event){
3992 dataRecord.brew_fermenter_tcloss=parseFloat(event.args.value);calcFermentables();calcIBUs();calcYeast();
3993 });
3994 $("#primary_end_sg").on('change',function (event){dataRecord.primary_end_sg=parseFloat(event.args.value);calcFermentation();});
3995 $("#primary_end_brix").on('change', function (event) {
3996 var OBrix, FBrix, FG;
3997 if(dataRecord.brew_fermenter_sg>=1.020){
3998 OBrix = sg_to_brix(dataRecord.brew_fermenter_sg);
3999 FBrix = parseFloat(event.args.value);
4000 FG = Round(1.0031 - 0.002318474*OBrix - 0.000007775*(OBrix*OBrix) - 0.000000034*Math.pow(OBrix,3) +
4001 0.00574*(FBrix) + 0.00003344*(FBrix*FBrix) + 0.000000086*Math.pow(FBrix,3), 4);
4002 //console.log("OBrix:"+OBrix+" FBrix:"+FBrix+" FG:"+FG);
4003 if (FBrix > 0.05) {
4004 $("#primary_end_sg").val(FG);
4005 dataRecord.primary_end_sg=FG;
4006 }
4007 calcFermentation();
4008 }
4009 });
4010 $("#secondary_end_sg").on('change',function (event){dataRecord.secondary_end_sg=parseFloat(event.args.value);calcFermentation();});
4011 $("#secondary_end_brix").on('change', function (event) {
4012 var OBrix, FBrix, FG;
4013 if(dataRecord.brew_fermenter_sg>=1.020){
4014 OBrix = sg_to_brix(dataRecord.brew_fermenter_sg);
4015 FBrix = parseFloat(event.args.value);
4016 FG = Round(1.0031 - 0.002318474*OBrix - 0.000007775*(OBrix*OBrix) - 0.000000034*Math.pow(OBrix,3) +
4017 0.00574*(FBrix) + 0.00003344*(FBrix*FBrix) + 0.000000086*Math.pow(FBrix,3), 4);
4018 //console.log("OBrix:"+OBrix+" FBrix:"+FBrix+" FG:"+FG);
4019 if (FBrix > 0.05) {
4020 $("#secondary_end_sg").val(FG);
4021 dataRecord.secondary_end_sg=FG;
4022 }
4023 calcFermentation();
4024 }
4025 });
4026 $("#final_brix").on('change',function (event){
4027 var OBrix, FBrix, FG;
4028 if(dataRecord.brew_fermenter_sg>=1.020){
4029 OBrix = sg_to_brix(dataRecord.brew_fermenter_sg);
4030 FBrix = parseFloat(event.args.value);
4031 FG = Round(1.0031 - 0.002318474*OBrix - 0.000007775*(OBrix*OBrix) - 0.000000034*Math.pow(OBrix,3) +
4032 0.00574*(FBrix) + 0.00003344*(FBrix*FBrix) + 0.000000086*Math.pow(FBrix,3), 4);
4033 //console.log("OBrix:"+OBrix+" FBrix:"+FBrix+" FG:"+FG);
4034 if (FBrix > 0.05) {
4035 $("#fg").val(FG);
4036 dataRecord.fg=FG;
4037 }
4038 calcFermentation();
4039 }
4040 });
4041 $("#fg").on('change',function (event){dataRecord.fg=parseFloat(event.args.value);calcFermentation();});
4042 $("#BLog").jqxButton({disabled:(dataRecord.log_brew)?false:true});
4043 $("#FLog").jqxButton({disabled:(dataRecord.log_fermentation)?false:true});
4044 }
4045
4046 $("#styleSelect").jqxDropDownList({
4047 placeHolder: "Kies bierstijl:",
4048 theme: theme,
4049 source: styleslist,
4050 displayMember: "name",
4051 width: 180,
4052 height: 23,
4053 dropDownVerticalAlignment: 'top',
4054 dropDownWidth: 500,
4055 dropDownHeight: 380,
4056 renderer: function (index, label, value) {
4057 var datarecord = styleslist.records[index];
4058 return datarecord.style_guide + " " + datarecord.style_letter+ " " + datarecord.name;
4059 }
4060 });
4061 $("#styleSelect").on('select', function (event) {
4062 if (event.args) {
4063 var datarecord, index = event.args.index;
4064 datarecord = styleslist.records[index];
4065 $("#st_name").val(datarecord.name);
4066 $("#st_category").val(datarecord.category);
4067 $("#st_category_number").val(datarecord.category_number);
4068 $("#st_letter").val(datarecord.style_letter);
4069 $("#st_guide").val(datarecord.style_guide);
4070 $("#st_type").val(StyleTypeData[datarecord.type].nl);
4071 $("#st_og_min").val(datarecord.og_min);
4072 $("#st_og_max").val(datarecord.og_max);
4073 $("#st_fg_min").val(datarecord.fg_min);
4074 $("#st_fg_max").val(datarecord.fg_max);
4075 $("#st_ibu_min").val(datarecord.ibu_min);
4076 $("#st_ibu_max").val(datarecord.ibu_max);
4077 $("#st_color_min").val(datarecord.color_min);
4078 $("#st_color_max").val(datarecord.color_max);
4079 $("#st_carb_min").val(datarecord.carb_min);
4080 $("#st_carb_min2").val(datarecord.carb_min);
4081 $("#st_carb_max").val(datarecord.carb_max);
4082 $("#st_carb_max2").val(datarecord.carb_max);
4083 $("#st_abv_min").val(datarecord.abv_min);
4084 $("#st_abv_max").val(datarecord.abv_max);
4085 }
4086 });
4087
4088 // Equipemnt dropdown list
4089 $("#equipmentSelect").jqxDropDownList({
4090 placeHolder: "Kies apparatuur:",
4091 theme: theme,
4092 source: equipmentlist,
4093 displayMember: "name",
4094 width: 170,
4095 height: 23,
4096 dropDownWidth: 300,
4097 renderer: function (index, label, value) {
4098 var datarecord = equipmentlist.records[index];
4099 return datarecord.batch_size + " liter " + datarecord.name;
4100 }
4101 });
4102 $("#equipmentSelect").on('select', function (event) {
4103 if (event.args) {
4104 var datarecord, factor, index = event.args.index;
4105 datarecord = equipmentlist.records[index];
4106 factor = datarecord.batch_size / dataRecord.batch_size;
4107 $("#eq_name").val(datarecord.name);
4108 $("#eq_boil_size").val(datarecord.boil_size);
4109 dataRecord.boil_size = datarecord.boil_size;
4110 $("#boil_size").val(datarecord.boil_size);
4111 $("#eq_batch_size").val(datarecord.batch_size);
4112 dataRecord.batch_size = datarecord.batch_size;
4113 $("#batch_size").val(datarecord.batch_size);
4114 $("#est_a_vol").val(datarecord.batch_size * 1.04);
4115 $("#eq_tun_volume").val(datarecord.tun_volume);
4116 dataRecord.eq_tun_weight = datarecord.tun_weight;
4117 dataRecord.eq_tun_specific_heat = datarecord.tun_specific_heat;
4118 dataRecord.eq_tun_material = datarecord.tun_material;
4119 dataRecord.eq_tun_height = datarecord.tun_height / 100.0;
4120 $("#eq_top_up_water").val(datarecord.top_up_water);
4121 dataRecord.eq_trub_chiller_loss = datarecord.trub_chiller_loss;
4122 $("#eq_trub_chiller_loss").val(datarecord.trub_chiller_loss);
4123 $("#eq_evap_rate").val(datarecord.evap_rate);
4124 $("#eq_boil_time").val(datarecord.boil_time);
4125 dataRecord.eq_calc_boil_volume = datarecord.calc_boil_volume;
4126 $("#eq_top_up_kettle").val(datarecord.top_up_kettle);
4127 $("#eq_hop_utilization").val(datarecord.hop_utilization);
4128 $("#eq_notes").val(datarecord.notes);
4129 $("#eq_lauter_volume").val(datarecord.lauter_volume);
4130 dataRecord.eq_lauter_height = datarecord.lauter_height / 100.0;
4131 $("#eq_lauter_deadspace").val(datarecord.lauter_deadspace);
4132 $("#eq_kettle_volume").val(datarecord.kettle_volume);
4133 dataRecord.eq_kettle_height = datarecord.kettle_height / 100.0;
4134 $("#eq_mash_volume").val(datarecord.mash_volume);
4135 $("#eq_mash_max").val(datarecord.mash_max);
4136 dataRecord.eq_mash_max = datarecord.mash_max;
4137 $("#mash_max").val(datarecord.mash_max);
4138 $("#eq_efficiency").val(datarecord.efficiency);
4139 dataRecord.efficiency = datarecord.efficiency;
4140 $("#efficiency").val(datarecord.efficiency);
4141
4142 dataRecord.sparge_volume = Math.round(datarecord.boil_size * 5) / 10;
4143 $("#sparge_volume").val(dataRecord.sparge_volume);
4144 $("#brew_sparge_volume").val(dataRecord.sparge_volume);
4145 $("#est_pre_vol").val(datarecord.boil_size * 1.04);
4146 calcFermentablesFromOG(parseFloat($("#est_og").jqxNumberInput('decimal'))); // Keep the OG
4147 adjustWaters(factor);
4148 calcFermentables();
4149 adjustHops(factor);
4150 adjustMiscs(factor);
4151 adjustYeasts(factor);
4152 calcIBUs();
4153 calcWater();
4154 calcSparge();
4155 }
4156 });
4157
4158 function saveRecord() {
4159 console.log("saveRecord()");
4160 var row = {
4161 record: my_record,
4162 uuid: dataRecord.uuid,
4163 name: $("#name").val(),
4164 code: $("#code").val(),
4165 birth: $("#birth").val(),
4166 stage: dataRecord.stage,
4167 notes: $("#notes").val(),
4168 log_brew: dataRecord.log_brew,
4169 log_fermentation: dataRecord.log_fermentation,
4170 inventory_reduced: dataRecord.inventory_reduced,
4171 locked: dataRecord.locked,
4172 eq_name: $("#eq_name").val(),
4173 eq_boil_size: parseFloat($("#eq_boil_size").jqxNumberInput('decimal')),
4174 eq_batch_size: parseFloat($("#eq_batch_size").jqxNumberInput('decimal')),
4175 eq_tun_volume: parseFloat($("#eq_tun_volume").jqxNumberInput('decimal')),
4176 eq_tun_weight: dataRecord.eq_tun_weight,
4177 eq_tun_specific_heat: dataRecord.eq_tun_specific_heat,
4178 eq_tun_material: dataRecord.eq_tun_material,
4179 eq_tun_height: dataRecord.eq_tun_height,
4180 eq_top_up_water: parseFloat($("#eq_top_up_water").jqxNumberInput('decimal')),
4181 eq_trub_chiller_loss: parseFloat($("#eq_trub_chiller_loss").jqxNumberInput('decimal')),
4182 eq_evap_rate: parseFloat($("#eq_evap_rate").jqxNumberInput('decimal')),
4183 eq_boil_time: parseFloat($("#eq_boil_time").jqxNumberInput('decimal')),
4184 eq_calc_boil_volume: dataRecord.eq_calc_boil_volume,
4185 eq_top_up_kettle: parseFloat($("#eq_top_up_kettle").jqxNumberInput('decimal')),
4186 eq_hop_utilization: parseFloat($("#eq_hop_utilization").jqxNumberInput('decimal')),
4187 eq_notes: $("#eq_notes").val(),
4188 eq_lauter_volume: parseFloat($("#eq_lauter_volume").jqxNumberInput('decimal')),
4189 eq_lauter_height: dataRecord.eq_lauter_height,
4190 eq_lauter_deadspace: parseFloat($("#eq_lauter_deadspace").jqxNumberInput('decimal')),
4191 eq_kettle_volume: parseFloat($("#eq_kettle_volume").jqxNumberInput('decimal')),
4192 eq_kettle_height: dataRecord.eq_kettle_height,
4193 eq_mash_volume: parseFloat($("#eq_mash_volume").jqxNumberInput('decimal')),
4194 eq_mash_max: parseFloat($("#eq_mash_max").jqxNumberInput('decimal')),
4195 eq_efficiency: parseFloat($("#eq_efficiency").jqxNumberInput('decimal')),
4196 brew_date_start: $("#brew_date_start").val(),
4197 brew_mash_ph: parseFloat($("#brew_mash_ph").jqxNumberInput('decimal')),
4198 brew_mash_sg: parseFloat($("#brew_mash_sg").jqxNumberInput('decimal')),
4199 brew_mash_efficiency: parseFloat($("#brew_mash_efficiency").jqxNumberInput('decimal')),
4200 brew_sparge_est: parseFloat($("#brew_sparge_est").jqxNumberInput('decimal')),
4201 brew_sparge_ph: parseFloat($("#brew_sparge_ph").jqxNumberInput('decimal')),
4202 brew_preboil_volume: parseFloat($("#brew_preboil_volume").jqxNumberInput('decimal')),
4203 brew_preboil_sg: parseFloat($("#brew_preboil_sg").jqxNumberInput('decimal')),
4204 brew_preboil_ph: parseFloat($("#brew_preboil_ph").jqxNumberInput('decimal')),
4205 brew_preboil_efficiency: parseFloat($("#brew_preboil_efficiency").jqxNumberInput('decimal')),
4206 brew_aboil_volume: parseFloat($("#brew_aboil_volume").jqxNumberInput('decimal')),
4207 brew_aboil_sg: parseFloat($("#brew_aboil_sg").jqxNumberInput('decimal')),
4208 brew_aboil_ph: parseFloat($("#brew_aboil_ph").jqxNumberInput('decimal')),
4209 brew_aboil_efficiency: parseFloat($("#brew_aboil_efficiency").jqxNumberInput('decimal')),
4210 brew_cooling_method: $("#brew_cooling_method").val(),
4211 brew_cooling_time: parseFloat($("#brew_cooling_time").jqxNumberInput('decimal')),
4212 brew_cooling_to: parseFloat($("#brew_cooling_to").jqxNumberInput('decimal')),
4213 brew_whirlpool9: parseFloat($("#brew_whirlpool9").jqxNumberInput('decimal')),
4214 brew_whirlpool7: parseFloat($("#brew_whirlpool7").jqxNumberInput('decimal')),
4215 brew_whirlpool6: parseFloat($("#brew_whirlpool6").jqxNumberInput('decimal')),
4216 brew_whirlpool2: parseFloat($("#brew_whirlpool2").jqxNumberInput('decimal')),
4217 brew_fermenter_volume: parseFloat($("#brew_fermenter_volume").jqxNumberInput('decimal')),
4218 brew_fermenter_extrawater: parseFloat($("#brew_fermenter_extrawater").jqxNumberInput('decimal')),
4219 brew_fermenter_tcloss: parseFloat($("#brew_fermenter_tcloss").jqxNumberInput('decimal')),
4220 brew_aeration_time: parseFloat($("#brew_aeration_time").jqxNumberInput('decimal')),
4221 brew_aeration_speed: parseFloat($("#brew_aeration_speed").jqxNumberInput('decimal')),
4222 brew_aeration_type: $("#brew_aeration_type").val(),
4223 brew_fermenter_sg: parseFloat($("#brew_fermenter_sg").jqxNumberInput('decimal')),
4224 brew_fermenter_ibu: parseFloat($("#brew_fermenter_ibu").jqxNumberInput('decimal')),
4225 brew_fermenter_color: parseFloat($("#brew_fermenter_color").jqxNumberInput('decimal')),
4226 brew_date_end: $("#brew_date_end").val(),
4227 og: dataRecord.og,
4228 fg: parseFloat($("#fg").jqxNumberInput('decimal')),
4229 primary_start_temp: parseFloat($("#primary_start_temp").jqxNumberInput('decimal')),
4230 primary_max_temp: parseFloat($("#primary_max_temp").jqxNumberInput('decimal')),
4231 primary_end_temp: parseFloat($("#primary_end_temp").jqxNumberInput('decimal')),
4232 primary_end_sg: parseFloat($("#primary_end_sg").jqxNumberInput('decimal')),
4233 primary_end_date: $("#primary_end_date").val(),
4234 secondary_temp: parseFloat($("#secondary_temp").jqxNumberInput('decimal')),
4235 secondary_end_sg: parseFloat($("#secondary_end_sg").jqxNumberInput('decimal')),
4236 secondary_end_date: $("#secondary_end_date").val(),
4237 tertiary_temp: parseFloat($("#tertiary_temp").jqxNumberInput('decimal')),
4238 package_date: $("#package_date").val(),
4239 package_volume: parseFloat($("#package_volume").jqxNumberInput('decimal')),
4240 package_infuse_amount: parseFloat($("#package_infuse_amount").jqxNumberInput('decimal')),
4241 package_infuse_abv: parseFloat($("#package_infuse_abv").jqxNumberInput('decimal')),
4242 package_infuse_notes: $("#package_infuse_notes").val(),
4243 package_abv: parseFloat($("#package_abv").jqxNumberInput('decimal')),
4244 package_ph: parseFloat($("#package_ph").jqxNumberInput('decimal')),
4245 bottle_amount: parseFloat($("#bottle_amount").jqxNumberInput('decimal')),
4246 bottle_carbonation: parseFloat($("#bottle_carbonation").jqxNumberInput('decimal')),
4247 bottle_priming_water: parseFloat($("#bottle_priming_water").jqxNumberInput('decimal')),
4248 bottle_priming_amount: parseFloat($("#bottle_priming_amount").jqxNumberInput('decimal')),
4249 bottle_carbonation_temp: parseFloat($("#bottle_carbonation_temp").jqxNumberInput('decimal')),
4250 keg_amount: parseFloat($("#keg_amount").jqxNumberInput('decimal')),
4251 keg_carbonation: parseFloat($("#keg_carbonation").jqxNumberInput('decimal')),
4252 keg_priming_water: parseFloat($("#keg_priming_water").jqxNumberInput('decimal')),
4253 keg_priming_amount: parseFloat($("#keg_priming_amount").jqxNumberInput('decimal')),
4254 keg_carbonation_temp: parseFloat($("#keg_carbonation_temp").jqxNumberInput('decimal')),
4255 keg_forced_carb: dataRecord.keg_forced_carb,
4256 keg_pressure: parseFloat($("#keg_pressure").jqxNumberInput('decimal')),
4257 taste_notes: $("#taste_notes").val(),
4258 taste_rate: parseFloat($("#taste_rate").jqxNumberInput('decimal')),
4259 taste_date: $("#taste_date").val(),
4260 taste_color: $("#taste_color").val(),
4261 taste_transparency: $("#taste_transparency").val(),
4262 taste_head: $("#taste_head").val(),
4263 taste_aroma: $("#taste_aroma").val(),
4264 taste_taste: $("#taste_taste").val(),
4265 taste_mouthfeel: $("#taste_mouthfeel").val(),
4266 taste_aftertaste: $("#taste_aftertaste").val(),
4267 st_name: $('#st_name').val(),
4268 st_letter: $('#st_letter').val(),
4269 st_guide: $('#st_guide').val(),
4270 st_type: dataRecord.st_type,
4271 st_category: $('#st_category').val(),
4272 st_category_number: parseFloat($("#st_category_number").jqxNumberInput('decimal')),
4273 st_og_min: parseFloat($("#st_og_min").jqxNumberInput('decimal')),
4274 st_og_max: parseFloat($("#st_og_max").jqxNumberInput('decimal')),
4275 st_fg_min: parseFloat($("#st_fg_min").jqxNumberInput('decimal')),
4276 st_fg_max: parseFloat($("#st_fg_max").jqxNumberInput('decimal')),
4277 st_ibu_min: parseFloat($("#st_ibu_min").jqxNumberInput('decimal')),
4278 st_ibu_max: parseFloat($("#st_ibu_max").jqxNumberInput('decimal')),
4279 st_color_min: parseFloat($("#st_color_min").jqxNumberInput('decimal')),
4280 st_color_max: parseFloat($("#st_color_max").jqxNumberInput('decimal')),
4281 st_carb_min: parseFloat($("#st_carb_min").jqxNumberInput('decimal')),
4282 st_carb_max: parseFloat($("#st_carb_max").jqxNumberInput('decimal')),
4283 st_abv_min: parseFloat($("#st_abv_min").jqxNumberInput('decimal')),
4284 st_abv_max: parseFloat($("#st_abv_max").jqxNumberInput('decimal')),
4285 type: $("#type").val(),
4286 batch_size: parseFloat($("#batch_size").jqxNumberInput('decimal')),
4287 boil_size: parseFloat($("#boil_size").jqxNumberInput('decimal')),
4288 boil_time: parseFloat($("#boil_time").jqxNumberInput('decimal')),
4289 efficiency: parseFloat($("#efficiency").jqxNumberInput('decimal')),
4290 est_og: parseFloat($("#est_og").jqxNumberInput('decimal')),
4291 est_fg: parseFloat($("#est_fg").jqxNumberInput('decimal')),
4292 est_abv: parseFloat($("#est_abv").jqxNumberInput('decimal')),
4293 est_color: parseFloat($("#est_color").jqxNumberInput('decimal')),
4294 color_method: $("#color_method").val(),
4295 est_ibu: parseFloat($("#est_ibu").jqxNumberInput('decimal')),
4296 ibu_method: $("#ibu_method").val(),
4297 est_carb: parseFloat($("#est_carb").jqxNumberInput('decimal')),
4298 mash_name: $("#mash_name").val(),
4299 mash_ph: parseFloat($("#mash_ph").jqxNumberInput('decimal')),
4300 sparge_temp: parseFloat($("#sparge_temp").jqxNumberInput('decimal')),
4301 sparge_ph: parseFloat($("#sparge_ph").jqxNumberInput('decimal')),
4302 sparge_volume: parseFloat($("#sparge_volume").jqxNumberInput('decimal')),
4303 sparge_source: $("#sparge_source").val(),
4304 sparge_acid_type: $("#sparge_acid_type").val(),
4305 sparge_acid_perc: parseFloat($("#sparge_acid_perc").jqxNumberInput('decimal')),
4306 sparge_acid_amount: dataRecord.sparge_acid_amount,
4307 calc_acid: dataRecord.calc_acid,
4308 w1_name: $("#w1_name").val(),
4309 w1_amount: parseFloat($("#w1_amount").jqxNumberInput('decimal')),
4310 w1_calcium: parseFloat($("#w1_calcium").jqxNumberInput('decimal')),
4311 w1_sulfate: parseFloat($("#w1_sulfate").jqxNumberInput('decimal')),
4312 w1_chloride: parseFloat($("#w1_chloride").jqxNumberInput('decimal')),
4313 w1_sodium: parseFloat($("#w1_sodium").jqxNumberInput('decimal')),
4314 w1_magnesium: parseFloat($("#w1_magnesium").jqxNumberInput('decimal')),
4315 w1_total_alkalinity: parseFloat($("#w1_total_alkalinity").jqxNumberInput('decimal')),
4316 w1_ph: parseFloat($("#w1_ph").jqxNumberInput('decimal')),
4317 w1_cost: dataRecord.w1_cost,
4318 w2_name: $("#w2_name").val(),
4319 w2_amount: parseFloat($("#w2_amount").jqxNumberInput('decimal')),
4320 w2_calcium: parseFloat($("#w2_calcium").jqxNumberInput('decimal')),
4321 w2_sulfate: parseFloat($("#w2_sulfate").jqxNumberInput('decimal')),
4322 w2_chloride: parseFloat($("#w2_chloride").jqxNumberInput('decimal')),
4323 w2_sodium: parseFloat($("#w2_sodium").jqxNumberInput('decimal')),
4324 w2_magnesium: parseFloat($("#w2_magnesium").jqxNumberInput('decimal')),
4325 w2_total_alkalinity: parseFloat($("#w2_total_alkalinity").jqxNumberInput('decimal')),
4326 w2_ph: parseFloat($("#w2_ph").jqxNumberInput('decimal')),
4327 w2_cost: dataRecord.w2_cost,
4328 wg_amount: parseFloat($("#wg_amount").jqxNumberInput('decimal')),
4329 wg_calcium: parseFloat($("#wg_calcium").jqxNumberInput('decimal')),
4330 wg_sulfate: parseFloat($("#wg_sulfate").jqxNumberInput('decimal')),
4331 wg_chloride: parseFloat($("#wg_chloride").jqxNumberInput('decimal')),
4332 wg_sodium: parseFloat($("#wg_sodium").jqxNumberInput('decimal')),
4333 wg_magnesium: parseFloat($("#wg_magnesium").jqxNumberInput('decimal')),
4334 wg_total_alkalinity: parseFloat($("#wg_total_alkalinity").jqxNumberInput('decimal')),
4335 wg_ph: parseFloat($("#wg_ph").jqxNumberInput('decimal')),
4336 wb_calcium: parseFloat($("#wb_calcium").jqxNumberInput('decimal')),
4337 wb_sulfate: parseFloat($("#wb_sulfate").jqxNumberInput('decimal')),
4338 wb_chloride: parseFloat($("#wb_chloride").jqxNumberInput('decimal')),
4339 wb_sodium: parseFloat($("#wb_sodium").jqxNumberInput('decimal')),
4340 wb_magnesium: parseFloat($("#wb_magnesium").jqxNumberInput('decimal')),
4341 wb_total_alkalinity: parseFloat($("#wb_total_alkalinity").jqxNumberInput('decimal')),
4342 wb_ph: parseFloat($("#wb_ph").jqxNumberInput('decimal')),
4343 wa_acid_name: $("#wa_acid_name").val(),
4344 wa_acid_perc: parseFloat($("#wa_acid_perc").jqxNumberInput('decimal')),
4345 wa_base_name: $("#wa_base_name").val(),
4346 starter_enable: dataRecord.starter_enable,
4347 starter_type: $("#starter_type").val(),
4348 starter_sg: parseFloat($("#starter_sg").jqxNumberInput('decimal')),
4349 starter_viability: parseFloat($("#starter_viability").jqxNumberInput('decimal')),
4350 prop1_type: $("#prop1_type").val(),
4351 prop1_volume: parseFloat($("#prop1_volume").jqxNumberInput('decimal')),
4352 prop2_type: $("#prop2_type").val(),
4353 prop2_volume: parseFloat($("#prop2_volume").jqxNumberInput('decimal')),
4354 prop3_type: $("#prop3_type").val(),
4355 prop3_volume: parseFloat($("#prop3_volume").jqxNumberInput('decimal')),
4356 prop4_type: $("#prop4_type").val(),
4357 prop4_volume: parseFloat($("#prop4_volume").jqxNumberInput('decimal')),
4358 fermentables: $('#fermentableGrid').jqxGrid('getrows'),
4359 hops: $('#hopGrid').jqxGrid('getrows'),
4360 miscs: $('#miscGrid').jqxGrid('getrows'),
4361 yeasts: $('#yeastGrid').jqxGrid('getrows'),
4362 mashs: $('#mashGrid').jqxGrid('getrows')
4363 },
4364 data = "update=true&" + $.param(row);
4365 $.ajax({
4366 dataType: 'json',
4367 url: url,
4368 cache: false,
4369 data: data,
4370 async: false,
4371 type: "POST",
4372 success: function (data, status, xhr) {
4373 console.log("saveRecord() success");
4374 },
4375 error: function(jqXHR, textStatus, errorThrown) {
4376 console.log("saveRecord() error");
4377 }
4378 });
4379 };
4380
4392 // initialize the input fields. 4381 // initialize the input fields.
4393 // Tab 1, Algemeen 4382 // Tab 1, Algemeen
4394 $("#name").jqxTooltip({ content: 'De naam voor dit product.' }); 4383 $("#name").jqxTooltip({ content: 'De naam voor dit product.' });
4395 $("#name").jqxInput({ theme: theme, width: 640, height: 23 }); 4384 $("#name").jqxInput({ theme: theme, width: 640, height: 23 });
4396 $("#code").jqxTooltip({ content: 'Product code nummer.' }); 4385 $("#code").jqxTooltip({ content: 'Product code nummer.' });
4627 cancelButton: $("#FermentableReady"), 4616 cancelButton: $("#FermentableReady"),
4628 modalOpacity: 0.40 4617 modalOpacity: 0.40
4629 }); 4618 });
4630 $("#FermentableReady").jqxButton({ template: "success", width: '90px', theme: theme }); 4619 $("#FermentableReady").jqxButton({ template: "success", width: '90px', theme: theme });
4631 $("#FermentableReady").click(function () { 4620 $("#FermentableReady").click(function () {
4632 var rowID = $("#fermentableGrid").jqxGrid('getrowid', fermentableRow); 4621 var row, rowID = $("#fermentableGrid").jqxGrid('getrowid', fermentableRow);
4633 console.log("FermentableReady row:"+fermentableRow+" ID:"+rowID); 4622 console.log("FermentableReady row:"+fermentableRow+" ID:"+rowID);
4634 var row = { 4623 row = {
4635 f_name: fermentableData.f_name, 4624 f_name: fermentableData.f_name,
4636 f_origin: fermentableData.f_origin, 4625 f_origin: fermentableData.f_origin,
4637 f_supplier: fermentableData.f_supplier, 4626 f_supplier: fermentableData.f_supplier,
4638 f_amount: fermentableData.f_amount, 4627 f_amount: fermentableData.f_amount,
4639 f_cost: fermentableData.f_cost, 4628 f_cost: fermentableData.f_cost,
4684 return datarecord.supplier+ " / " + datarecord.name + " (" + datarecord.color + " EBC)"; 4673 return datarecord.supplier+ " / " + datarecord.name + " (" + datarecord.color + " EBC)";
4685 } 4674 }
4686 }); 4675 });
4687 $("#wf_select").on('select', function (event) { 4676 $("#wf_select").on('select', function (event) {
4688 if (event.args) { 4677 if (event.args) {
4689 var index = event.args.index; 4678 var datarecord, index = event.args.index;
4690 var datarecord = fermentablelist.records[index]; 4679 datarecord = fermentablelist.records[index];
4691 $("#wf_name").val(datarecord.name); 4680 $("#wf_name").val(datarecord.name);
4692 fermentableData.f_name = datarecord.name; 4681 fermentableData.f_name = datarecord.name;
4693 fermentableData.f_origin = datarecord.origin; 4682 fermentableData.f_origin = datarecord.origin;
4694 fermentableData.f_supplier = datarecord.supplier; 4683 fermentableData.f_supplier = datarecord.supplier;
4695 fermentableData.f_type = datarecord.type; 4684 fermentableData.f_type = datarecord.type;
4722 calcMash(); 4711 calcMash();
4723 }; 4712 };
4724 }); 4713 });
4725 $("#wf_percentage").jqxNumberInput( Perc1dec ); 4714 $("#wf_percentage").jqxNumberInput( Perc1dec );
4726 $("#wf_percentage").on('change', function (event) { 4715 $("#wf_percentage").on('change', function (event) {
4727 var oldvalue = Math.round(fermentableData.f_percentage * 10) / 10.0; 4716 var newvalue, rowscount, rowdata, diff, tw, damount, namount, nw, newperc,
4728 var newvalue = event.args.value; 4717 oldvalue = Math.round(fermentableData.f_percentage * 10) / 10.0;
4718 newvalue = event.args.value;
4729 console.log("percentage changed: "+newvalue+" old: "+oldvalue); 4719 console.log("percentage changed: "+newvalue+" old: "+oldvalue);
4730 fermentableData.f_percent = newvalue; 4720 fermentableData.f_percent = newvalue;
4731 var rowscount = $("#fermentableGrid").jqxGrid('getdatainformation').rowscount; 4721 rowscount = $("#fermentableGrid").jqxGrid('getdatainformation').rowscount;
4732 if ((oldvalue != newvalue) && (rowscount > 1)) { 4722 if ((oldvalue != newvalue) && (rowscount > 1)) {
4733 var rowdata = $("#fermentableGrid").jqxGrid('getrowdata', fermentableRow); 4723 rowdata = $("#fermentableGrid").jqxGrid('getrowdata', fermentableRow);
4734 if (rowdata.f_adjust_to_total_100) { 4724 if (rowdata.f_adjust_to_total_100) {
4735 $("#wf_percentage").val(oldvalue); 4725 $("#wf_percentage").val(oldvalue);
4736 } else { 4726 } else {
4737 var diff = newvalue - oldvalue; 4727 diff = newvalue - oldvalue;
4738 var tw = 0; // total weight 4728 tw = 0; // total weight
4739 for (i = 0; i < rowscount; i++) { 4729 for (i = 0; i < rowscount; i++) {
4740 var rowdata = $("#fermentableGrid").jqxGrid('getrowdata', i); 4730 rowdata = $("#fermentableGrid").jqxGrid('getrowdata', i);
4741 if (rowdata.f_added < 4) 4731 if (rowdata.f_added < 4)
4742 tw += Math.round(rowdata.f_amount * 1000) / 1000; 4732 tw += Math.round(rowdata.f_amount * 1000) / 1000;
4743 } 4733 }
4744 tw = Math.round(tw * 1000) / 1000; 4734 tw = Math.round(tw * 1000) / 1000;
4745 if (to_100) { 4735 if (to_100) {
4746 // Adjust this row and the 100% row. 4736 // Adjust this row and the 100% row.
4747 var damount = Math.round(tw * diff *10) / 1000; 4737 damount = Math.round(tw * diff *10) / 1000;
4748 var rowdata = $("#fermentableGrid").jqxGrid('getrowdata', fermentableRow); 4738 rowdata = $("#fermentableGrid").jqxGrid('getrowdata', fermentableRow);
4749 var namount = Math.round((rowdata.f_amount + damount) * 1000) / 1000; 4739 namount = Math.round((rowdata.f_amount + damount) * 1000) / 1000;
4750 $("#fermentableGrid").jqxGrid('setcellvalue', fermentableRow, 'f_amount', namount); 4740 $("#fermentableGrid").jqxGrid('setcellvalue', fermentableRow, 'f_amount', namount);
4751 $("#wf_amount").val(namount); 4741 $("#wf_amount").val(namount);
4752 $("#fermentableGrid").jqxGrid('setcellvalue', fermentableRow, 'f_percentage', rowdata.f_percentage + diff); 4742 $("#fermentableGrid").jqxGrid('setcellvalue', fermentableRow, 'f_percentage', rowdata.f_percentage + diff);
4753 for (i = 0; i < rowscount; i++) { 4743 for (i = 0; i < rowscount; i++) {
4754 var rowdata = $("#fermentableGrid").jqxGrid('getrowdata', i); 4744 rowdata = $("#fermentableGrid").jqxGrid('getrowdata', i);
4755 if (rowdata.f_adjust_to_total_100) { 4745 if (rowdata.f_adjust_to_total_100) {
4756 namount = rowdata.f_amount - damount; 4746 namount = rowdata.f_amount - damount;
4757 $("#fermentableGrid").jqxGrid('setcellvalue', i, 'f_percentage', rowdata.f_percentage - diff); 4747 $("#fermentableGrid").jqxGrid('setcellvalue', i, 'f_percentage', rowdata.f_percentage - diff);
4758 $("#fermentableGrid").jqxGrid('setcellvalue', i, 'f_amount', namount); 4748 $("#fermentableGrid").jqxGrid('setcellvalue', i, 'f_amount', namount);
4759 } 4749 }
4761 calcFermentables(); 4751 calcFermentables();
4762 calcIBUs(); 4752 calcIBUs();
4763 calcMash(); 4753 calcMash();
4764 } else { 4754 } else {
4765 // Adjust all the rows. 4755 // Adjust all the rows.
4766 var nw = tw * diff / 100; 4756 nw = tw * diff / 100;
4767 for (i = 0; i < rowscount; i++) { 4757 for (i = 0; i < rowscount; i++) {
4768 var rowdata = $("#fermentableGrid").jqxGrid('getrowdata', i); 4758 rowdata = $("#fermentableGrid").jqxGrid('getrowdata', i);
4769 if (rowdata.f_added < 4) { 4759 if (rowdata.f_added < 4) {
4770 if (i == fermentableRow) { 4760 if (i == fermentableRow) {
4771 var namount = Math.round((rowdata.f_amount + nw) * 1000) / 1000; 4761 namount = Math.round((rowdata.f_amount + nw) * 1000) / 1000;
4772 $("#fermentableGrid").jqxGrid('setcellvalue', i, 'f_amount', namount); 4762 $("#fermentableGrid").jqxGrid('setcellvalue', i, 'f_amount', namount);
4773 // $("#wf_amount").val(namount); // Will crash the script. 4763 // $("#wf_amount").val(namount); // Will crash the script.
4774 $("#fermentableGrid").jqxGrid('setcellvalue', i, 'f_percentage', newvalue); 4764 $("#fermentableGrid").jqxGrid('setcellvalue', i, 'f_percentage', newvalue);
4775 } else { 4765 } else {
4776 var namount = Math.round((rowdata.f_amount - (nw / (rowscount - 1))) * 1000) / 1000; 4766 namount = Math.round((rowdata.f_amount - (nw / (rowscount - 1))) * 1000) / 1000;
4777 var newperc = Math.round((namount / tw) * 1000) / 10.0; 4767 newperc = Math.round((namount / tw) * 1000) / 10.0;
4778 $("#fermentableGrid").jqxGrid('setcellvalue', i, 'f_amount', namount); 4768 $("#fermentableGrid").jqxGrid('setcellvalue', i, 'f_amount', namount);
4779 $("#fermentableGrid").jqxGrid('setcellvalue', i, 'f_percentage', newperc); 4769 $("#fermentableGrid").jqxGrid('setcellvalue', i, 'f_percentage', newperc);
4780 } 4770 }
4781 } else { 4771 } else {
4782 $("#fermentableGrid").jqxGrid('setcellvalue', i, 'f_percentage', 0); 4772 $("#fermentableGrid").jqxGrid('setcellvalue', i, 'f_percentage', 0);
4793 $("#wf_adjust_to_total_100").jqxCheckBox({ theme: theme, width: 120, height: 23 }); 4783 $("#wf_adjust_to_total_100").jqxCheckBox({ theme: theme, width: 120, height: 23 });
4794 $("#wf_adjust_to_total_100").on('checked', function (event) { 4784 $("#wf_adjust_to_total_100").on('checked', function (event) {
4795 if (fermentableData.f_adjust_to_total_100 == 0) { 4785 if (fermentableData.f_adjust_to_total_100 == 0) {
4796 if (to_100) { 4786 if (to_100) {
4797 // Reset other flag first. 4787 // Reset other flag first.
4798 var rowscount = $("#fermentableGrid").jqxGrid('getdatainformation').rowscount; 4788 var i, rowscount = $("#fermentableGrid").jqxGrid('getdatainformation').rowscount;
4799 for (var i = 0; i < rowscount; i++) { 4789 for (i = 0; i < rowscount; i++) {
4800 if (i != fermentableRow) { 4790 if (i != fermentableRow) {
4801 $("#fermentableGrid").jqxGrid('setcellvalue', i, 'f_adjust_to_total_100', 0); 4791 $("#fermentableGrid").jqxGrid('setcellvalue', i, 'f_adjust_to_total_100', 0);
4802 } 4792 }
4803 } 4793 }
4804 } 4794 }
4897 cancelButton: $("#HopReady"), 4887 cancelButton: $("#HopReady"),
4898 modalOpacity: 0.40 4888 modalOpacity: 0.40
4899 }); 4889 });
4900 $("#HopReady").jqxButton({ template: "success", width: '90px', theme: theme }); 4890 $("#HopReady").jqxButton({ template: "success", width: '90px', theme: theme });
4901 $("#HopReady").click(function () { 4891 $("#HopReady").click(function () {
4902 var rowID = $("#hopGrid").jqxGrid('getrowid', hopRow); 4892 var row, rowID = $("#hopGrid").jqxGrid('getrowid', hopRow);
4903 console.log("HopReady row:"+hopRow+" ID:"+rowID); 4893 row = {
4904 var row = {
4905 h_name: $("#wh_name").val(), 4894 h_name: $("#wh_name").val(),
4906 h_origin: hopData.h_origin, 4895 h_origin: hopData.h_origin,
4907 h_amount: parseFloat($("#wh_amount").jqxNumberInput('decimal')) / 1000, 4896 h_amount: parseFloat($("#wh_amount").jqxNumberInput('decimal')) / 1000,
4908 h_cost: hopData.h_cost, 4897 h_cost: hopData.h_cost,
4909 h_type: hopData.h_type, 4898 h_type: hopData.h_type,
4944 return datarecord.origin+ " - " + datarecord.name + " / " + HopFormData[datarecord.form].nl + " (" + datarecord.alpha + " % &alpha;)"; 4933 return datarecord.origin+ " - " + datarecord.name + " / " + HopFormData[datarecord.form].nl + " (" + datarecord.alpha + " % &alpha;)";
4945 } 4934 }
4946 }); 4935 });
4947 $("#wh_select").on('select', function (event) { 4936 $("#wh_select").on('select', function (event) {
4948 if (event.args) { 4937 if (event.args) {
4949 var index = event.args.index; 4938 var datarecord, index = event.args.index;
4950 var datarecord = hoplist.records[index]; 4939 datarecord = hoplist.records[index];
4951 // console.log("select another hop:"+index+" "+datarecord.name);
4952 $("#wh_name").val(datarecord.name); 4940 $("#wh_name").val(datarecord.name);
4953 hopData.h_name = datarecord.name; 4941 hopData.h_name = datarecord.name;
4954 hopData.h_origin = datarecord.origin; 4942 hopData.h_origin = datarecord.origin;
4955 hopData.h_cost = datarecord.cost; 4943 hopData.h_cost = datarecord.cost;
4956 hopData.h_type = datarecord.type; 4944 hopData.h_type = datarecord.type;
4967 } 4955 }
4968 }); 4956 });
4969 $("#wh_amount").jqxNumberInput( Spin1dec ); 4957 $("#wh_amount").jqxNumberInput( Spin1dec );
4970 $('#wh_amount').on('change', function (event) { 4958 $('#wh_amount').on('change', function (event) {
4971 console.log("amount changed: "+event.args.value+" time:"+hopData.h_time+" alpha:"+hopData.h_alpha); 4959 console.log("amount changed: "+event.args.value+" time:"+hopData.h_time+" alpha:"+hopData.h_alpha);
4972 var amount = parseFloat(event.args.value) / 1000; 4960 var ibu, amount = parseFloat(event.args.value) / 1000;
4973 var ibu = toIBU(hopData.h_useat, hopData.h_form, preboil_sg, 4961 ibu = toIBU(hopData.h_useat, hopData.h_form, preboil_sg,
4974 parseFloat($("#batch_size").jqxNumberInput('decimal')), 4962 parseFloat($("#batch_size").jqxNumberInput('decimal')),
4975 amount, parseFloat(hopData.h_time), 4963 amount, parseFloat(hopData.h_time),
4976 parseFloat(hopData.h_alpha), $("#ibu_method").val() 4964 parseFloat(hopData.h_alpha), $("#ibu_method").val()
4977 ); 4965 );
4978 hopData.h_amount = amount; 4966 hopData.h_amount = amount;
4979 $("#wh_ibu").val(ibu); 4967 $("#wh_ibu").val(ibu);
4980 }); 4968 });
4981 $("#wh_ibu").jqxNumberInput( Show1dec ); 4969 $("#wh_ibu").jqxNumberInput( Show1dec );
4982 $("#wh_time").jqxNumberInput( PosInt ); 4970 $("#wh_time").jqxNumberInput( PosInt );
4983 $("#wh_time").on('change', function (event) { 4971 $("#wh_time").on('change', function (event) {
4984 var newtime = parseFloat(event.args.value); 4972 var ibu, newtime = parseFloat(event.args.value);
4985 // Check limits and correct 4973 // Check limits and correct
4986 if (hopData.h_useat == 2) { // Boil 4974 if (hopData.h_useat == 2) { // Boil
4987 if (newtime > parseFloat($("#boil_time").jqxNumberInput('decimal'))) { 4975 if (newtime > parseFloat($("#boil_time").jqxNumberInput('decimal'))) {
4988 newtime = parseFloat($("#boil_time").jqxNumberInput('decimal')); 4976 newtime = parseFloat($("#boil_time").jqxNumberInput('decimal'));
4989 $("#wh_time").val(newtime); 4977 $("#wh_time").val(newtime);
5000 newtime = 21; 4988 newtime = 21;
5001 $("#wh_time").val(newtime); 4989 $("#wh_time").val(newtime);
5002 } 4990 }
5003 hopData.h_time = newtime * 1440; 4991 hopData.h_time = newtime * 1440;
5004 } 4992 }
5005 var ibu = toIBU(hopData.h_useat, hopData.h_form, preboil_sg, parseFloat($("#batch_size").jqxNumberInput('decimal')), 4993 ibu = toIBU(hopData.h_useat, hopData.h_form, preboil_sg, parseFloat($("#batch_size").jqxNumberInput('decimal')),
5006 parseFloat(hopData.h_amount), parseFloat(hopData.h_time), parseFloat(hopData.h_alpha), $("#ibu_method").val()); 4994 parseFloat(hopData.h_amount), parseFloat(hopData.h_time), parseFloat(hopData.h_alpha), $("#ibu_method").val());
5007 // console.log("time changed: "+newtime+" final:"+hopData.h_time+" ibu:"+ibu); 4995 // console.log("time changed: "+newtime+" final:"+hopData.h_time+" ibu:"+ibu);
5008 $("#wh_ibu").val(ibu); 4996 $("#wh_ibu").val(ibu);
5009 }); 4997 });
5010 $("#wh_useat").jqxDropDownList({ 4998 $("#wh_useat").jqxDropDownList({
5051 cancelButton: $("#MiscReady"), 5039 cancelButton: $("#MiscReady"),
5052 modalOpacity: 0.40 5040 modalOpacity: 0.40
5053 }); 5041 });
5054 $("#MiscReady").jqxButton({ template: "success", width: '90px', theme: theme }); 5042 $("#MiscReady").jqxButton({ template: "success", width: '90px', theme: theme });
5055 $("#MiscReady").click(function () { 5043 $("#MiscReady").click(function () {
5056 var rowID = $("#miscGrid").jqxGrid('getrowid', miscRow); 5044 var row, rowID = $("#miscGrid").jqxGrid('getrowid', miscRow);
5057 console.log("MiscReady row:"+miscRow+" ID:"+rowID); 5045 console.log("MiscReady row:"+miscRow+" ID:"+rowID);
5058 var row = { 5046 row = {
5059 m_name: miscData.m_name, 5047 m_name: miscData.m_name,
5060 m_amount: miscData.m_amount, 5048 m_amount: miscData.m_amount,
5061 m_cost: miscData.m_cost, 5049 m_cost: miscData.m_cost,
5062 m_type: miscData.m_type, 5050 m_type: miscData.m_type,
5063 m_use_use: miscData.m_use_use, 5051 m_use_use: miscData.m_use_use,
5085 dropDownWidth: 500, 5073 dropDownWidth: 500,
5086 dropDownHeight: 500 5074 dropDownHeight: 500
5087 }); 5075 });
5088 $("#wm_select").on('select', function (event) { 5076 $("#wm_select").on('select', function (event) {
5089 if (event.args) { 5077 if (event.args) {
5090 var index = event.args.index; 5078 var datarecord, index = event.args.index;
5091 var datarecord = misclist.records[index]; 5079 datarecord = misclist.records[index];
5092 $("#wm_name").val(datarecord.name); 5080 $("#wm_name").val(datarecord.name);
5093 miscData.m_name = datarecord.name; 5081 miscData.m_name = datarecord.name;
5094 miscData.m_cost = datarecord.cost; 5082 miscData.m_cost = datarecord.cost;
5095 miscData.m_type = datarecord.type; 5083 miscData.m_type = datarecord.type;
5096 miscData.m_use_use = datarecord.use_use; 5084 miscData.m_use_use = datarecord.use_use;
5103 console.log("amount changed: "+event.args.value); 5091 console.log("amount changed: "+event.args.value);
5104 miscData.m_amount = parseFloat(event.args.value) / 1000; 5092 miscData.m_amount = parseFloat(event.args.value) / 1000;
5105 }); 5093 });
5106 $("#wm_time").jqxNumberInput( PosInt ); 5094 $("#wm_time").jqxNumberInput( PosInt );
5107 $("#wm_time").on('change', function (event) { 5095 $("#wm_time").on('change', function (event) {
5108 console.log("time changed: "+event.args.value);
5109 var newtime = parseFloat(event.args.value); 5096 var newtime = parseFloat(event.args.value);
5110 5097
5111 if (miscData.m_use_use == 2) { // Boil 5098 if (miscData.m_use_use == 2) { // Boil
5112 if (newtime > parseFloat($("#boil_time").jqxNumberInput('decimal'))) { 5099 if (newtime > parseFloat($("#boil_time").jqxNumberInput('decimal'))) {
5113 newtime = parseFloat($("#boil_time").jqxNumberInput('decimal')); 5100 newtime = parseFloat($("#boil_time").jqxNumberInput('decimal'));
5165 cancelButton: $("#YeastReady"), 5152 cancelButton: $("#YeastReady"),
5166 modalOpacity: 0.40 5153 modalOpacity: 0.40
5167 }); 5154 });
5168 $("#YeastReady").jqxButton({ template: "success", width: '90px', theme: theme }); 5155 $("#YeastReady").jqxButton({ template: "success", width: '90px', theme: theme });
5169 $("#YeastReady").click(function () { 5156 $("#YeastReady").click(function () {
5170 var rowID = $("#yeastGrid").jqxGrid('getrowid', yeastRow); 5157 var row, rowID = $("#yeastGrid").jqxGrid('getrowid', yeastRow);
5171 console.log("YeastReady row:"+yeastRow+" ID:"+rowID); 5158 console.log("YeastReady row:"+yeastRow+" ID:"+rowID);
5172 var row = { 5159 row = {
5173 y_name: yeastData.y_name, 5160 y_name: yeastData.y_name,
5174 y_laboratory: yeastData.y_laboratory, 5161 y_laboratory: yeastData.y_laboratory,
5175 y_product_id: yeastData.y_product_id, 5162 y_product_id: yeastData.y_product_id,
5176 y_amount: yeastData.y_amount, 5163 y_amount: yeastData.y_amount,
5177 y_cost: yeastData.y_cost, 5164 y_cost: yeastData.y_cost,
5213 return datarecord.laboratory+" "+datarecord.product_id+" "+datarecord.name; 5200 return datarecord.laboratory+" "+datarecord.product_id+" "+datarecord.name;
5214 } 5201 }
5215 }); 5202 });
5216 $("#wy_select").on('select', function (event) { 5203 $("#wy_select").on('select', function (event) {
5217 if (event.args) { 5204 if (event.args) {
5218 var index = event.args.index; 5205 var datarecord, index = event.args.index;
5219 var datarecord = yeastlist.records[index]; 5206 datarecord = yeastlist.records[index];
5220 $("#wy_name").val(datarecord.name); 5207 $("#wy_name").val(datarecord.name);
5221 $("#wy_laboratory").val(datarecord.laboratory); 5208 $("#wy_laboratory").val(datarecord.laboratory);
5222 $("#wy_product_id").val(datarecord.product_id); 5209 $("#wy_product_id").val(datarecord.product_id);
5223 yeastData.y_name = datarecord.name; 5210 yeastData.y_name = datarecord.name;
5224 yeastData.y_cost = datarecord.cost; 5211 yeastData.y_cost = datarecord.cost;
5243 calcYeast(); 5230 calcYeast();
5244 } 5231 }
5245 }); 5232 });
5246 $("#wy_amount").jqxNumberInput( Spin1dec ); 5233 $("#wy_amount").jqxNumberInput( Spin1dec );
5247 $('#wy_amount').on('change', function (event) { 5234 $('#wy_amount').on('change', function (event) {
5248 console.log("amount changed: "+event.args.value); 5235 var amount = parseFloat(event.args.value);
5249 if (yeastData.y_form == 0) // Liquid 5236 if (yeastData.y_form != 0) // not Liquid
5250 var amount = parseFloat(event.args.value); 5237 amount = parseFloat(event.args.value) / 1000;
5251 else
5252 var amount = parseFloat(event.args.value) / 1000;
5253 yeastData.y_amount = amount; 5238 yeastData.y_amount = amount;
5254 calcFermentables(); 5239 calcFermentables();
5255 calcYeast(); 5240 calcYeast();
5256 }); 5241 });
5257 $("#wy_use").jqxDropDownList({ 5242 $("#wy_use").jqxDropDownList({
5270 yeastData.y_use = index; 5255 yeastData.y_use = index;
5271 calcFermentables(); 5256 calcFermentables();
5272 calcYeast(); 5257 calcYeast();
5273 } 5258 }
5274 }); 5259 });
5275 for (var i = 1; i < 5; i++) { 5260 for (i = 1; i < 5; i++) {
5276 $("#prop"+i+"_type").jqxDropDownList({ 5261 $("#prop"+i+"_type").jqxDropDownList({
5277 theme: theme, 5262 theme: theme,
5278 source: StarterTypeAdapter, 5263 source: StarterTypeAdapter,
5279 valueMember: 'id', 5264 valueMember: 'id',
5280 displayMember: 'nl', 5265 displayMember: 'nl',
5322 dropDownHeight: 500, 5307 dropDownHeight: 500,
5323 dropDownHorizontalAlignment: 'right' 5308 dropDownHorizontalAlignment: 'right'
5324 }); 5309 });
5325 $("#mash_select").on('select', function (event) { 5310 $("#mash_select").on('select', function (event) {
5326 if (event.args) { 5311 if (event.args) {
5327 var index = event.args.index; 5312 var data, datarecord, rowIDs, rows, i, row = {}, index = event.args.index;
5328 // First delete all current steps 5313 // First delete all current steps
5329 var rowIDs = new Array(); 5314 rowIDs = new Array();
5330 var rows = $("#mashGrid").jqxGrid('getdisplayrows'); 5315 rows = $("#mashGrid").jqxGrid('getdisplayrows');
5331 for (var i = 0; i < rows.length; i++) { 5316 for (i = 0; i < rows.length; i++) {
5332 var row = rows[i]; 5317 row = rows[i];
5333 rowIDs.push(row.uid); 5318 rowIDs.push(row.uid);
5334 } 5319 }
5335 $("#mashGrid").jqxGrid('deleterow', rowIDs); 5320 $("#mashGrid").jqxGrid('deleterow', rowIDs);
5336 // Then add the new steps 5321 // Then add the new steps
5337 var datarecord = mashlist.records[index]; 5322 datarecord = mashlist.records[index];
5338 $("#mash_name").val(datarecord.name); 5323 $("#mash_name").val(datarecord.name);
5339 for (i = 0; i < datarecord.steps.length; i++) { 5324 for (i = 0; i < datarecord.steps.length; i++) {
5340 var data = datarecord.steps[i]; 5325 data = datarecord.steps[i];
5341 var row = {};
5342 row["step_name"] = data.step_name; 5326 row["step_name"] = data.step_name;
5343 row["step_type"] = data.step_type; 5327 row["step_type"] = data.step_type;
5344 // For now, but this must be smarter. 5328 // For now, but this must be smarter.
5345 if (mash_infuse == 0 && dataRecord.w1_amount > 0) 5329 if (mash_infuse == 0 && dataRecord.w1_amount > 0)
5346 mash_infuse = dataRecord.w1_amount; 5330 mash_infuse = dataRecord.w1_amount;
5389 height: 23, 5373 height: 23,
5390 autoDropDownHeight: true 5374 autoDropDownHeight: true
5391 }); 5375 });
5392 $("#wstep_type").on('select', function (event) { 5376 $("#wstep_type").on('select', function (event) {
5393 if (event.args) { 5377 if (event.args) {
5394 var index = event.args.index; 5378 var rowdata, i, rows, row, index = event.args.index;
5395 var rowdata = $("#mashGrid").jqxGrid('getrowdata', mashRow); 5379 rowdata = $("#mashGrid").jqxGrid('getrowdata', mashRow);
5396 rowdata.step_type = index; 5380 rowdata.step_type = index;
5397 if (index == 0) { 5381 if (index == 0) {
5398 $("#wstep_infuse_amount").show(); 5382 $("#wstep_infuse_amount").show();
5399 $("#wstep_pmpt").show(); 5383 $("#wstep_pmpt").show();
5400 } else { 5384 } else {
5401 rowdata.step_infuse_amount = 0; 5385 rowdata.step_infuse_amount = 0;
5402 $("#wstep_infuse_amount").hide(); 5386 $("#wstep_infuse_amount").hide();
5403 $("#wstep_pmpt").hide(); 5387 $("#wstep_pmpt").hide();
5404 } 5388 }
5405 mash_infuse = 0; 5389 mash_infuse = 0;
5406 var rows = $('#mashGrid').jqxGrid('getrows'); 5390 rows = $('#mashGrid').jqxGrid('getrows');
5407 for (var i = 0; i < rows.length; i++) { 5391 for (i = 0; i < rows.length; i++) {
5408 var row = rows[i]; 5392 row = rows[i];
5409 if (row.step_type == 0) // Infusion 5393 if (row.step_type == 0) // Infusion
5410 mash_infuse += parseFloat(row.step_infuse_amount); 5394 mash_infuse += parseFloat(row.step_infuse_amount);
5411 } 5395 }
5412 } 5396 }
5413 }); 5397 });
5431 var rowdata = $("#mashGrid").jqxGrid('getrowdata', mashRow); 5415 var rowdata = $("#mashGrid").jqxGrid('getrowdata', mashRow);
5432 rowdata.ramp_time = parseFloat(event.args.value); 5416 rowdata.ramp_time = parseFloat(event.args.value);
5433 }); 5417 });
5434 $("#wstep_infuse_amount").jqxNumberInput( Spin1dec ); 5418 $("#wstep_infuse_amount").jqxNumberInput( Spin1dec );
5435 $('#wstep_infuse_amount').on('change', function (event) { 5419 $('#wstep_infuse_amount').on('change', function (event) {
5436 var rowdata = $("#mashGrid").jqxGrid('getrowdata', mashRow); 5420 var row, i, rows, rowdata = $("#mashGrid").jqxGrid('getrowdata', mashRow);
5437 rowdata.step_infuse_amount = parseFloat(event.args.value); 5421 rowdata.step_infuse_amount = parseFloat(event.args.value);
5438 mash_infuse = 0; 5422 mash_infuse = 0;
5439 var rows = $('#mashGrid').jqxGrid('getrows'); 5423 rows = $('#mashGrid').jqxGrid('getrows');
5440 for (var i = 0; i < rows.length; i++) { 5424 for (i = 0; i < rows.length; i++) {
5441 var row = rows[i]; 5425 row = rows[i];
5442 if (row.step_type == 0) // Infusion 5426 if (row.step_type == 0) // Infusion
5443 mash_infuse += parseFloat(row.step_infuse_amount); 5427 mash_infuse += parseFloat(row.step_infuse_amount);
5444 } 5428 }
5445 if (dataRecord.w2_amount == 0) { 5429 if (dataRecord.w2_amount == 0) {
5446 dataRecord.w1_amount = mash_infuse; 5430 dataRecord.w1_amount = mash_infuse;
5470 dropDownWidth: 400, 5454 dropDownWidth: 400,
5471 dropDownHeight: 400 5455 dropDownHeight: 400
5472 }); 5456 });
5473 $("#w1_name").on('select', function (event) { 5457 $("#w1_name").on('select', function (event) {
5474 if (event.args) { 5458 if (event.args) {
5475 var index = event.args.index; 5459 var datarecord, index = event.args.index;
5476 var datarecord = waterlist.records[index]; 5460 datarecord = waterlist.records[index];
5477 dataRecord.w1_name = datarecord.name; 5461 dataRecord.w1_name = datarecord.name;
5478 $("#w1_calcium").val(datarecord.calcium); 5462 $("#w1_calcium").val(datarecord.calcium);
5479 dataRecord.w1_calcium = datarecord.calcium; 5463 dataRecord.w1_calcium = datarecord.calcium;
5480 $("#w1_sulfate").val(datarecord.sulfate); 5464 $("#w1_sulfate").val(datarecord.sulfate);
5481 dataRecord.w1_sulfate = datarecord.sulfate; 5465 dataRecord.w1_sulfate = datarecord.sulfate;
5513 dropDownWidth: 400, 5497 dropDownWidth: 400,
5514 dropDownHeight: 400 5498 dropDownHeight: 400
5515 }); 5499 });
5516 $("#w2_name").on('select', function (event) { 5500 $("#w2_name").on('select', function (event) {
5517 if (event.args) { 5501 if (event.args) {
5518 var index = event.args.index; 5502 var datarecord, index = event.args.index;
5519 var datarecord = waterlist.records[index]; 5503 datarecord = waterlist.records[index];
5520 dataRecord.w2_name = datarecord.name; 5504 dataRecord.w2_name = datarecord.name;
5521 $("#w2_calcium").val(datarecord.calcium); 5505 $("#w2_calcium").val(datarecord.calcium);
5522 dataRecord.w2_calcium = datarecord.calcium; 5506 dataRecord.w2_calcium = datarecord.calcium;
5523 $("#w2_sulfate").val(datarecord.sulfate); 5507 $("#w2_sulfate").val(datarecord.sulfate);
5524 dataRecord.w2_sulfate = datarecord.sulfate; 5508 dataRecord.w2_sulfate = datarecord.sulfate;
5580 dropDownWidth: 400, 5564 dropDownWidth: 400,
5581 dropDownHeight: 300 5565 dropDownHeight: 300
5582 }); 5566 });
5583 $("#pr_name").on('select', function (event) { 5567 $("#pr_name").on('select', function (event) {
5584 if (event.args) { 5568 if (event.args) {
5585 var index = event.args.index; 5569 var datarecord, index = event.args.index;
5586 var datarecord = waterprofiles.records[index]; 5570 datarecord = waterprofiles.records[index];
5587 $("#pr_calcium").val(datarecord.calcium); 5571 $("#pr_calcium").val(datarecord.calcium);
5588 $("#pr_sulfate").val(datarecord.sulfate); 5572 $("#pr_sulfate").val(datarecord.sulfate);
5589 $("#pr_chloride").val(datarecord.chloride); 5573 $("#pr_chloride").val(datarecord.chloride);
5590 $("#pr_sodium").val(datarecord.sodium); 5574 $("#pr_sodium").val(datarecord.sodium);
5591 $("#pr_magnesium").val(datarecord.magnesium); 5575 $("#pr_magnesium").val(datarecord.magnesium);
5772 $("#brew_fermenter_ibu").jqxNumberInput( Show0dec ); 5756 $("#brew_fermenter_ibu").jqxNumberInput( Show0dec );
5773 $("#brew_fermenter_color").jqxNumberInput( Show0dec ); 5757 $("#brew_fermenter_color").jqxNumberInput( Show0dec );
5774 $("#BLog").jqxButton({ template: "info", width: '150px', theme: theme }); 5758 $("#BLog").jqxButton({ template: "info", width: '150px', theme: theme });
5775 $("#BLog").click(function () { 5759 $("#BLog").click(function () {
5776 // Open log in a new tab. 5760 // Open log in a new tab.
5777 var url="log_brew.php?code=" + dataRecord.code + "&name=" + dataRecord.name; 5761 window.open("log_brew.php?code=" + dataRecord.code + "&name=" + dataRecord.name);
5778 window.open(url);
5779 }); 5762 });
5780 5763
5781 // Tab 10, Fermentation 5764 // Tab 10, Fermentation
5782 // Note, fermentation temps changes must do calcCarbonation() 5765 // Note, fermentation temps changes must do calcCarbonation()
5783 $("#brew_fermenter_sg2").jqxTooltip({ content: 'Het behaalde SG in het gistvat, overgenomen van de brouwdag.' }); 5766 $("#brew_fermenter_sg2").jqxTooltip({ content: 'Het behaalde SG in het gistvat, overgenomen van de brouwdag.' });
5863 dropDownWidth: 300, 5846 dropDownWidth: 300,
5864 dropDownHeight: 400 5847 dropDownHeight: 400
5865 }); 5848 });
5866 $("#bottle_priming_sugar").on('select', function (event) { 5849 $("#bottle_priming_sugar").on('select', function (event) {
5867 if (event.args) { 5850 if (event.args) {
5868 var index = event.args.index; 5851 var rowID, index, editrow = -1, datarecord, rows, i, row = {};
5869 var editrow = -1; 5852 index = event.args.index;
5870 var datarecord = fermentablesugars.records[index]; 5853 datarecord = fermentablesugars.records[index];
5871 var rows = $('#fermentableGrid').jqxGrid('getrows'); 5854 rows = $('#fermentableGrid').jqxGrid('getrows');
5872 for (var i = 0; i < rows.length; i++) { 5855 for (i = 0; i < rows.length; i++) {
5873 if (rows[i].f_added == 4) { 5856 if (rows[i].f_added == 4) {
5874 editrow = i; 5857 editrow = i;
5875 } 5858 }
5876 } 5859 }
5877 var row = {};
5878 row["f_name"] = datarecord.name; 5860 row["f_name"] = datarecord.name;
5879 row["f_origin"] = datarecord.origin; 5861 row["f_origin"] = datarecord.origin;
5880 row["f_supplier"] = datarecord.supplier; 5862 row["f_supplier"] = datarecord.supplier;
5881 row["f_amount"] = parseFloat($("#bottle_priming_total").jqxNumberInput('decimal')) / 1000; 5863 row["f_amount"] = parseFloat($("#bottle_priming_total").jqxNumberInput('decimal')) / 1000;
5882 row["f_cost"] = datarecord.cost; 5864 row["f_cost"] = datarecord.cost;
5897 row["f_percentage"] = 0; 5879 row["f_percentage"] = 0;
5898 row["f_di_ph"] = datarecord.di_ph; 5880 row["f_di_ph"] = datarecord.di_ph;
5899 row["f_acid_to_ph_57"] = datarecord.acid_to_ph_57; 5881 row["f_acid_to_ph_57"] = datarecord.acid_to_ph_57;
5900 row["f_inventory"] = datarecord.inventory; 5882 row["f_inventory"] = datarecord.inventory;
5901 if (editrow >= 0) { 5883 if (editrow >= 0) {
5902 var rowID = $('#fermentableGrid').jqxGrid('getrowid', editrow); 5884 rowID = $('#fermentableGrid').jqxGrid('getrowid', editrow);
5903 $('#fermentableGrid').jqxGrid('updaterow', rowID, row); 5885 $('#fermentableGrid').jqxGrid('updaterow', rowID, row);
5904 } else { 5886 } else {
5905 $("#fermentableGrid").jqxGrid('addrow', null, row); 5887 $("#fermentableGrid").jqxGrid('addrow', null, row);
5906 } 5888 }
5907 calcCarbonation(); 5889 calcCarbonation();
5917 dropDownWidth: 300, 5899 dropDownWidth: 300,
5918 dropDownHeight: 400 5900 dropDownHeight: 400
5919 }); 5901 });
5920 $("#keg_priming_sugar").on('select', function (event) { 5902 $("#keg_priming_sugar").on('select', function (event) {
5921 if (event.args) { 5903 if (event.args) {
5922 var index = event.args.index; 5904 var rowID, index, editrow = -1, datarecord, rows, i, row = {};
5923 var editrow = -1; 5905 index = event.args.index;
5924 var datarecord = fermentablesugars.records[index]; 5906 datarecord = fermentablesugars.records[index];
5925 var rows = $('#fermentableGrid').jqxGrid('getrows'); 5907 rows = $('#fermentableGrid').jqxGrid('getrows');
5926 for (var i = 0; i < rows.length; i++) { 5908 for (i = 0; i < rows.length; i++) {
5927 if (rows[i].f_added == 5) { 5909 if (rows[i].f_added == 5) {
5928 editrow = i; 5910 editrow = i;
5929 } 5911 }
5930 } 5912 }
5931 var row = {};
5932 row["f_name"] = datarecord.name; 5913 row["f_name"] = datarecord.name;
5933 row["f_origin"] = datarecord.origin; 5914 row["f_origin"] = datarecord.origin;
5934 row["f_supplier"] = datarecord.supplier; 5915 row["f_supplier"] = datarecord.supplier;
5935 row["f_amount"] = parseFloat($("#keg_priming_total").jqxNumberInput('decimal')) / 1000; 5916 row["f_amount"] = parseFloat($("#keg_priming_total").jqxNumberInput('decimal')) / 1000;
5936 row["f_cost"] = datarecord.cost; 5917 row["f_cost"] = datarecord.cost;
5951 row["f_percentage"] = 0; 5932 row["f_percentage"] = 0;
5952 row["f_di_ph"] = datarecord.di_ph; 5933 row["f_di_ph"] = datarecord.di_ph;
5953 row["f_acid_to_ph_57"] = datarecord.acid_to_ph_57; 5934 row["f_acid_to_ph_57"] = datarecord.acid_to_ph_57;
5954 row["f_inventory"] = datarecord.inventory; 5935 row["f_inventory"] = datarecord.inventory;
5955 if (editrow >= 0) { 5936 if (editrow >= 0) {
5956 var rowID = $('#fermentableGrid').jqxGrid('getrowid', editrow); 5937 rowID = $('#fermentableGrid').jqxGrid('getrowid', editrow);
5957 $('#fermentableGrid').jqxGrid('updaterow', rowID, row); 5938 $('#fermentableGrid').jqxGrid('updaterow', rowID, row);
5958 } else { 5939 } else {
5959 $("#fermentableGrid").jqxGrid('addrow', null, row); 5940 $("#fermentableGrid").jqxGrid('addrow', null, row);
5960 } 5941 }
5961 calcCarbonation(); 5942 calcCarbonation();

mercurial