Wed, 16 Oct 2019 21:05:03 +0200
Added dutch array strings to a global php script. Changed fermentables, hops, yeast and misc inventory scripts to use these strings between the database scripts and javascript scripts. This makes filtering on types strings useable. Added these changes to the product/recipe forum and print exports too.
/***************************************************************************** * Copyright (C) 2019 * * Michiel Broek <mbroek at mbse dot eu> * * This file is part of BMS * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * BrewCloud is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with ThermFerm; see the file COPYING. If not, write to the Free * Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. *****************************************************************************/ $(document).ready(function () { $('#divide_type').jqxDropDownList({ theme: theme, source: SplitAdapter, valueMember: 'id', displayMember: 'nl', width: 180, height: 23, autoDropDownHeight: true }); // Calculate the volume in the main batch. function calcLeftover() { rows = $('#splitGrid').jqxGrid('getrows'); leftover = Round(available, 1); for (i = 0; i < rows.length; i++) { row = rows[i]; leftover -= row.split_size; //console.log('i:' + i + ' split_size:' + row.split_size); } $('#leftover').val(leftover); //console.log('calcLeftover():' + leftover); } // Calculate available volume but ignore the current row. function calcRoom(r) { var rows, row, i, vol = 0; rows = $('#splitGrid').jqxGrid('getrows'); for (i = 0; i < rows.length; i++) { row = rows[i]; if (i != r) vol += row.split_size; } maxvolume = Round(available - minvolume - vol, 1); console.log('calcRoom(' + r + '):' + vol + ' room:' + maxvolume); } var dataRecord = {}, i, available = 0, leftover = 0, minvolume = 0, maxvolume = 0, url = 'includes/db_product.php', // Prepare the data source = { datatype: 'json', cache: false, datafields: [ // From prod_main { name: 'record', type: 'number' }, { name: 'uuid', type: 'string' }, { name: 'name', type: 'string' }, { name: 'code', type: 'string' }, { name: 'birth', type: 'string' }, { name: 'stage', type: 'int' }, { name: 'notes', type: 'string' }, { name: 'log_brew', type: 'int' }, { name: 'log_fermentation', type: 'int' }, { name: 'inventory_reduced', type: 'int' }, { name: 'locked', type: 'int' }, { name: 'eq_name', type: 'string' }, { name: 'eq_boil_size', type: 'float' }, { name: 'eq_batch_size', type: 'float' }, { name: 'eq_tun_volume', type: 'float' }, { name: 'eq_tun_weight', type: 'float' }, { name: 'eq_tun_specific_heat', type: 'float' }, { name: 'eq_tun_material', type: 'int' }, { name: 'eq_tun_height', type: 'float' }, { name: 'eq_top_up_water', type: 'float' }, { name: 'eq_trub_chiller_loss', type: 'float' }, { name: 'eq_evap_rate', type: 'float' }, { name: 'eq_boil_time', type: 'float' }, { name: 'eq_calc_boil_volume', type: 'int' }, { name: 'eq_top_up_kettle', type: 'float' }, { name: 'eq_hop_utilization', type: 'float' }, { name: 'eq_notes', type: 'string' }, { name: 'eq_lauter_volume', type: 'float' }, { name: 'eq_lauter_height', type: 'float' }, { name: 'eq_lauter_deadspace', type: 'float' }, { name: 'eq_kettle_volume', type: 'float' }, { name: 'eq_kettle_height', type: 'float' }, { name: 'eq_mash_volume', type: 'float' }, { name: 'eq_mash_max', type: 'float' }, { name: 'eq_efficiency', type: 'float' }, { name: 'brew_date_start', type: 'string' }, { name: 'brew_mash_ph', type: 'float' }, { name: 'brew_mash_sg', type: 'float' }, { name: 'brew_mash_efficiency', type: 'float' }, { name: 'brew_sparge_est', type: 'float' }, { name: 'brew_sparge_ph', type: 'float' }, { name: 'brew_preboil_volume', type: 'float' }, { name: 'brew_preboil_sg', type: 'float' }, { name: 'brew_preboil_ph', type: 'float' }, { name: 'brew_preboil_efficiency', type: 'float' }, { name: 'brew_aboil_volume', type: 'float' }, { name: 'brew_aboil_sg', type: 'float' }, { name: 'brew_aboil_ph', type: 'float' }, { name: 'brew_aboil_efficiency', type: 'float' }, { name: 'brew_cooling_method', type: 'int' }, { name: 'brew_cooling_time', type: 'float' }, { name: 'brew_cooling_to', type: 'float' }, { name: 'brew_whirlpool9', type: 'float' }, { name: 'brew_whirlpool7', type: 'float' }, { name: 'brew_whirlpool6', type: 'float' }, { name: 'brew_whirlpool2', type: 'float' }, { name: 'brew_fermenter_volume', type: 'float' }, { name: 'brew_fermenter_extrawater', type: 'float' }, { name: 'brew_fermenter_tcloss', type: 'float' }, { name: 'brew_aeration_time', type: 'float' }, { name: 'brew_aeration_speed', type: 'float' }, { name: 'brew_aeration_type', type: 'int' }, { name: 'brew_fermenter_sg', type: 'float' }, { name: 'brew_fermenter_ibu', type: 'float' }, { name: 'brew_fermenter_color', type: 'float' }, { name: 'brew_date_end', type: 'string' }, { name: 'og', type: 'float' }, { name: 'fg', type: 'float' }, { name: 'primary_start_temp', type: 'float' }, { name: 'primary_max_temp', type: 'float' }, { name: 'primary_end_temp', type: 'float' }, { name: 'primary_end_sg', type: 'float' }, { name: 'primary_end_date', type: 'string' }, { name: 'secondary_temp', type: 'float' }, { name: 'secondary_end_sg', type: 'float' }, { name: 'secondary_end_date', type: 'string' }, { name: 'tertiary_temp', type: 'float' }, { name: 'package_date', type: 'string' }, { name: 'package_volume', type: 'float' }, { name: 'package_infuse_amount', type: 'float' }, { name: 'package_infuse_abv', type: 'float' }, { name: 'package_infuse_notes', type: 'string' }, { name: 'package_abv', type: 'float' }, { name: 'package_ph', type: 'float' }, { name: 'bottle_amount', type: 'float' }, { name: 'bottle_carbonation', type: 'float' }, { name: 'bottle_priming_water', type: 'float' }, { name: 'bottle_priming_amount', type: 'float' }, { name: 'bottle_carbonation_temp', type: 'float' }, { name: 'keg_amount', type: 'float' }, { name: 'keg_carbonation', type: 'float' }, { name: 'keg_priming_water', type: 'float' }, { name: 'keg_priming_amount', type: 'float' }, { name: 'keg_carbonation_temp', type: 'float' }, { name: 'keg_forced_carb', type: 'int' }, { name: 'keg_pressure', type: 'float' }, { name: 'taste_notes', type: 'string' }, { name: 'taste_rate', type: 'float' }, { name: 'taste_date', type: 'string' }, { name: 'taste_color', type: 'string' }, { name: 'taste_transparency', type: 'string' }, { name: 'taste_head', type: 'string' }, { name: 'taste_aroma', type: 'string' }, { name: 'taste_taste', type: 'string' }, { name: 'taste_mouthfeel', type: 'string' }, { name: 'taste_aftertaste', type: 'string' }, { name: 'st_name', type: 'string' }, { name: 'st_letter', type: 'string' }, { name: 'st_guide', type: 'string' }, { name: 'st_category', type: 'string' }, { name: 'st_category_number', type: 'float' }, { name: 'st_type', type: 'int' }, { name: 'st_og_min', type: 'float' }, { name: 'st_og_max', type: 'float' }, { name: 'st_fg_min', type: 'float' }, { name: 'st_fg_max', type: 'float' }, { name: 'st_ibu_min', type: 'float' }, { name: 'st_ibu_max', type: 'float' }, { name: 'st_color_min', type: 'float' }, { name: 'st_color_max', type: 'float' }, { name: 'st_carb_min', type: 'float' }, { name: 'st_carb_max', type: 'float' }, { name: 'st_abv_min', type: 'float' }, { name: 'st_abv_max', type: 'float' }, { name: 'type', type: 'int' }, { name: 'batch_size', type: 'float' }, { name: 'boil_size', type: 'float' }, { name: 'boil_time', type: 'float' }, { name: 'efficiency', type: 'float' }, { name: 'est_og', type: 'float' }, { name: 'est_fg', type: 'float' }, { name: 'est_abv', type: 'float' }, { name: 'est_color', type: 'float' }, { name: 'color_method', type: 'int' }, { name: 'est_ibu', type: 'float' }, { name: 'ibu_method', type: 'int' }, { name: 'est_carb', type: 'float' }, { name: 'sparge_temp', type: 'float' }, { name: 'sparge_ph', type: 'float' }, { name: 'sparge_volume', type: 'float' }, { name: 'sparge_source', type: 'int' }, { name: 'sparge_acid_type', type: 'int' }, { name: 'sparge_acid_perc', type: 'float' }, { name: 'sparge_acid_amount', type: 'float' }, { name: 'mash_ph', type: 'float' }, { name: 'mash_name', type: 'string' }, { name: 'calc_acid', type: 'int' }, { name: 'w1_name', type: 'string' }, { name: 'w1_amount', type: 'float' }, { name: 'w1_calcium', type: 'float' }, { name: 'w1_sulfate', type: 'float' }, { name: 'w1_chloride', type: 'float' }, { name: 'w1_sodium', type: 'float' }, { name: 'w1_magnesium', type: 'float' }, { name: 'w1_total_alkalinity', type: 'float' }, { name: 'w1_ph', type: 'float' }, { name: 'w1_cost', type: 'float' }, { name: 'w2_name', type: 'string' }, { name: 'w2_amount', type: 'float' }, { name: 'w2_calcium', type: 'float' }, { name: 'w2_sulfate', type: 'float' }, { name: 'w2_chloride', type: 'float' }, { name: 'w2_sodium', type: 'float' }, { name: 'w2_magnesium', type: 'float' }, { name: 'w2_total_alkalinity', type: 'float' }, { name: 'w2_ph', type: 'float' }, { name: 'w2_cost', type: 'float' }, { name: 'wg_amount', type: 'float' }, { name: 'wg_calcium', type: 'float' }, { name: 'wg_sulfate', type: 'float' }, { name: 'wg_chloride', type: 'float' }, { name: 'wg_sodium', type: 'float' }, { name: 'wg_magnesium', type: 'float' }, { name: 'wg_total_alkalinity', type: 'float' }, { name: 'wg_ph', type: 'float' }, { name: 'wb_calcium', type: 'float' }, { name: 'wb_sulfate', type: 'float' }, { name: 'wb_chloride', type: 'float' }, { name: 'wb_sodium', type: 'float' }, { name: 'wb_magnesium', type: 'float' }, { name: 'wb_total_alkalinity', type: 'float' }, { name: 'wb_ph', type: 'float' }, { name: 'wa_acid_name', type: 'int' }, { name: 'wa_acid_perc', type: 'int' }, { name: 'wa_base_name', type: 'int' }, { name: 'starter_enable', type: 'int' }, { name: 'starter_type', type: 'int' }, { name: 'starter_sg', type: 'float' }, { name: 'starter_viability', type: 'int' }, { name: 'starter_viability', type: 'int' }, { name: 'prop1_type', type: 'int' }, { name: 'prop1_volume', type: 'float' }, { name: 'prop2_type', type: 'int' }, { name: 'prop2_volume', type: 'float' }, { name: 'prop3_type', type: 'int' }, { name: 'prop3_volume', type: 'float' }, { name: 'prop4_type', type: 'int' }, { name: 'prop4_volume', type: 'float' }, { name: 'divide_type', type: 'int' }, { name: 'divide_size', type: 'float' }, { name: 'divide_parts', type: 'int' }, { name: 'fermentables', type: 'string' }, { name: 'hops', type: 'string' }, { name: 'miscs', type: 'string' }, { name: 'yeasts', type: 'string' }, { name: 'mashs', type: 'string' } ], id: 'record', url: url + '?record=' + my_record }, // Load data and select one record. dataAdapter = new $.jqx.dataAdapter(source, { loadComplete: function() { var records = dataAdapter.records; dataRecord = records[0]; // Hidden record uuid $('#name').val(dataRecord.name); $('#code').val(dataRecord.code); $('#stage').val(StageData[dataRecord.stage].nl); // Disable stages that are already done. for (i = 0; i < SplitData.length; i++) { console.log('i:' + i + ' ok:' + SplitData[i].ok + ' stage:' + dataRecord.stage); if (SplitData[i].ok < dataRecord.stage) $("#divide_type").jqxDropDownList('disableAt', i); } }, loadError: function(jqXHR, status, error) { }, beforeLoadComplete: function(records) { $('#jqxLoader').jqxLoader('open'); } }); durl = 'includes/db_divides.php', // Prepare the data dividerec = { datatype: 'json', cache: false, datafields: [ // From prod_main { name: 'record', type: 'number' }, { name: 'divide_from', type: 'string' }, { name: 'divide_type', type: 'int' }, { name: 'divide_size', type: 'float' }, { name: 'name', type: 'string' }, { name: 'code', type: 'string' } ], id: 'record', url: durl + '?record=' + my_record }; var editSplit = function(data) { var splitSource = { datatype: 'local', cache: false, async: false, datafields: [ { name: 'split_code', type: 'string' }, { name: 'split_name', type: 'string' }, { name: 'split_size', type: 'float' } ], addrow: function(rowid, rowdata, position, commit) { console.log('split addrow ' + rowid); commit(true); }, deleterow: function(rowid, commit) { console.log('split deleterow ' + rowid); commit(true); } }, splitAdapter = new $.jqx.dataAdapter(splitSource, {}); $('#splitGrid').jqxGrid({ width: 1240, height: 375, source: splitAdapter, editable: true, enabletooltips: true, selectionmode: 'singlecell', editmode: 'click', theme: theme, showtoolbar: true, rendertoolbar: function(toolbar) { var container = $('<div style="overflow: hidden; position: relative; margin: 5px;"></div>'); toolbar.append(container); container.append('<input style="float: left; margin-left: 165px;" id="saddrowbutton" type="button" value="Nieuwe splitsing" />'); container.append('<input style="float: left; margin-left: 565px;" id="sdeleterowbutton" type="button" value="Verwijder splitsing" />'); $('#saddrowbutton').jqxButton({ template: 'primary', theme: theme, disabled: true, height: 27, width: 150 }); $('#saddrowbutton').on('click', function() { var row = {}, rowscount = $('#splitGrid').jqxGrid('getdatainformation').rowscount; row['split_code'] = dataRecord.code + '-' + (rowscount + 1); row['split_name'] = dataRecord.name + ' ' + (rowscount + 1); row['split_size'] = 0; $('#splitGrid').jqxGrid('addrow', null, row); $('#sdeleterowbutton').jqxButton({ disabled: false }); // Enable delete $('#divide_type').jqxDropDownList({ disabled: true }); // Disable dropdown }); // Delete last added split $('#sdeleterowbutton').jqxButton({ template: 'danger', theme: theme, disabled: true, height: 27, width: 150 }); $('#sdeleterowbutton').on('click', function() { var rowscount, id, row; rowscount = $('#splitGrid').jqxGrid('getdatainformation').rowscount; id = $('#splitGrid').jqxGrid('getrowid', rowscount - 1); // First, give back this batch volume. row = $('#splitGrid').jqxGrid('getrowdata', id); leftover += row.split_size; if (leftover > available) leftover = available; $('#leftover').val(leftover); // Then delete the row. $('#splitGrid').jqxGrid('deleterow', id); if (rowscount == 1) { $('#sdeleterowbutton').jqxButton({ disabled: true }); // No more rows $('#divide_type').jqxDropDownList({ disabled: false }); } }); }, columns: [ { text: 'Splits code', datafield: 'split_code', width: 120, editable: false }, { text: 'Splits naam', datafield: 'split_name' }, { text: 'Splits volume', datafield: 'split_size', width: 120, align: 'right', cellsalign: 'right', cellsformat: 'f1', columntype: 'numberinput', validation: function (cell, value) { if (value < 0 || value > maxvolume) { return { result: false, message: 'Volume should be between 0 and ' + maxvolume + ' liter' }; } return true; }, createeditor: function (row, cellvalue, editor) { editor.jqxNumberInput({ decimalDigits: 1, digits: 3 }); } } ] }); $('#splitGrid').on('cellbeginedit', function (event) { var args = event.args; calcRoom(args.rowindex); // Make maxvolume available. }); $('#splitGrid').on('cellvaluechanged', function (event) { var args = event.args; //console.log("cellvaluechanged, Column: " + args.datafield + ", Row: " + (1 + args.rowindex) + ", Value: " + args.value); calcLeftover(); }); }; dataAdapter.dataBind(); editSplit(dataRecord); // initialize the input fields. $('#name').jqxTooltip({ content: 'De naam voor dit product.' }); $('#name').jqxInput({ theme: theme, width: 640, height: 23 }); $('#code').jqxTooltip({ content: 'Product code nummer.' }); $('#code').jqxInput({ theme: theme, width: 100, height: 23 }); $('#stage').jqxTooltip({ content: 'De productie fase van dit product.' }); $('#stage').jqxInput({ theme: theme, width: 100, height: 23 }); $('#available').jqxNumberInput(Show1dec); $('#leftover').jqxNumberInput(Show1dec); $('#divide_type').val(0); $('#divide_type').on('change', function(event) { var index = event.args.index; console.log('divide_type:' + index); dataRecord.divide_type = index; switch (index) { case 0: available = 0; break; case 1: available = dataRecord.boil_size; break; case 2: available = dataRecord.batch_size; break; case 3: available = dataRecord.brew_fermenter_volume; break; case 4: case 5: available = Round(dataRecord.brew_fermenter_volume * 0.92, 1); // Estimate volume without yeast trub break; case 6: available = dataRecord.package_volume; break; } leftover = available; minvolume = Round(0.1 * available, 1); $('#available').val(available); $('#leftover').val(leftover); if (index != 0) { $('#saddrowbutton').jqxButton({ disabled: false }); } else { $('#saddrowbutton').jqxButton({ disabled: true }); } }); $('#Cancel').jqxButton({ template: 'primary', width: '80px', theme: theme }); $('#Cancel').bind('click', function() { window.location.href = my_return; }); $('#Save').jqxButton({ template: 'success', width: '80px', theme: theme }); $('#Save').bind('click', function() { var rows, row, i, div, data; if (leftover != available) { console.log('Save and there are splits'); // Record 0, the master data div = {}; div.divide_from = dataRecord.uuid; div.divide_type = dataRecord.divide_type; div.divide_size = leftover; div.divide_part = 0; div.name = dataRecord.name; div.code = dataRecord.code; data = 'insert=true&' + $.param(div); $.ajax({ dataType: 'json', url: durl, cache: false, data: data, type: "POST", success: function (data, status, xhr) { console.log('insert divides: 0'); }, error: function(jqXHR, textStatus, errorThrown) { console.log('insert divides: ' + textStatus); } }); rows = $('#splitGrid').jqxGrid('getrows'); for (i = 0; i < rows.length; i++) { row = rows[i]; console.log('split ' + i); div = {}; div.divide_from = dataRecord.uuid; div.divide_type = dataRecord.divide_type; div.divide_size = row.split_size; div.divide_part = i + 1; div.name = row.split_name; div.code = row.split_code; data = 'insert=true&' + $.param(div); $.ajax({ dataType: 'json', url: durl, cache: false, data: data, type: "POST", success: function (data, status, xhr) { console.log('insert divides: ' + i); }, error: function(jqXHR, textStatus, errorThrown) { console.log('insert divides: ' + textStatus); } }); } div = {}; div.record = dataRecord.record; div.divide_type = dataRecord.divide_type; div.divide_size = leftover; div.divide_parts = i; data = 'splitit=true&' + $.param(div); $.ajax({ dataType: 'json', url: url, cache: false, data: data, type: "POST", success: function (data, status, xhr) { console.log('updated products'); }, error: function(jqXHR, textStatus, errorThrown) { console.log('updated products: ' + textStatus); } }); } window.location.href = my_return; }); });