www/js/prod_divide.js

Wed, 04 Mar 2020 10:48:21 +0100

author
Michiel Broek <mbroek@mbse.eu>
date
Wed, 04 Mar 2020 10:48:21 +0100
changeset 622
39902353b159
parent 615
9034e65b0d7a
child 645
3b1510050c9b
permissions
-rw-r--r--

Workaround for hang during startup. Changed order of displayed fields on the yeast tab. Tooltip text changes. More decimals on the checklist for misc ingredients. More decimals for the starter on product print.

/*****************************************************************************
 * Copyright (C) 2019-2020
 *
 * 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: 'log_ispindel', type: 'int' },
   { name: 'log_co2pressure', 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');
  }
 });

 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');

   // Send all the info to the database. The server handles the splitting.
   var divide_data = new Array();
   row = {};
   row.name = dataRecord.name;
   row.code = dataRecord.code;
   row.size = Round(leftover, 4);
   row.factor = Round((leftover / available), 4);
   row.part = 0;
   divide_data.push(row);

   rows = $('#splitGrid').jqxGrid('getrows');
   for (i = 0; i < rows.length; i++) {
    row = rows[i];
    console.log('split ' + i);
    div = {};
    div.size = Round(row.split_size, 4);
    div.factor = Round((row.split_size / available), 4);
    div.part = i + 1;
    div.name = row.split_name;
    div.code = row.split_code;
    divide_data.push(div);
   }

   // Send the data to the server
   div = {};
   div.record = dataRecord.record;
   div.divide_type = dataRecord.divide_type;
   div.divide_parts = i;
   div.divide_data = divide_data;
   data = $.param(div);
   $.ajax({
     dataType: 'json',
     url: 'includes/db_divides.php',
     cache: false,
     data: data,
     type: 'POST',
     success: function(data, status, xhr) {
      console.log('insert divides: success');
      window.location.href = my_return;
     },
     error: function(jqXHR, textStatus, errorThrown) {
      console.log('insert divides: ' + textStatus);
     }
   });

  }
 });
});

mercurial