Massively improve statement input
authorJoey Schulze <joey@infodrom.org>
Mon, 15 Nov 2021 22:12:53 +0000 (23:12 +0100)
committerJoey Schulze <joey@infodrom.org>
Mon, 15 Nov 2021 22:31:42 +0000 (23:31 +0100)
class/accounttable.class.php
src/InfoCon/account/edit.wml
src/infodrom.js

index 89387ca..c58c588 100644 (file)
@@ -2,6 +2,7 @@
 
 abstract class AccountTable extends DatabaseTable {
   protected $valuecolumn;
+  protected $lookup_period = "2 years";
 
   public function __construct($table, $id)
   {
@@ -158,4 +159,88 @@ abstract class AccountTable extends DatabaseTable {
 
       return $this->db->insertInto($this->table, $item);
   }
+
+  public function ajaxGetCategoryInfo(Array $data)
+  {
+      $result = [];
+      $sql = sprintf("SELECT DISTINCT category FROM %s WHERE blz_kto = %s AND category <> '' AND category IS NOT NULL ORDER BY category",
+                    $this->table,
+                    $this->db->quote($data['blzkto']));
+
+      foreach ($this->db->fetchObjectList($sql) as $cat) {
+         $condition = sprintf("datum >= now() - interval '%s' AND category = %s",
+                              $this->lookup_period,
+                              $this->db->quote($cat->category));
+
+         $names = [['id' => '', 'title' => '']];
+         foreach ($this->distinctFromTo($data['blzkto'], $condition) as $row) {
+             $names[] = ['id' => utf8_encode($row->from_to),
+                         'title' => utf8_encode($row->from_to)];
+         }
+         $result[utf8_encode($cat->category)] = $names;
+      }
+
+      return ['list' => $result];
+  }
+
+  public function ajaxInsert(Array $data)
+  {
+      if (!strlen($data['category']) && strlen($data['newcategory']))
+         $data['category'] = $data['newcategory'];
+      if (!strlen($data['from_to']) && strlen($data['newfrom_to']))
+         $data['from_to'] = $data['newfrom_to'];
+
+      return $this->insert(['blz_kto' => $data['blzkto'],
+                           'datum' => Functions::date_german_to_iso($data['datum']),
+                           'statement' => $data['statement'],
+                           'from_to' => utf8_decode($data['from_to']),
+                           'descr' => utf8_decode($data['descr']),
+                           'category' => utf8_decode($data['category']),
+                           'value' => str_replace (",",".", $data['value'])]);
+  }
+
+  protected function getCommonPrefix(Array $list)
+  {
+      $pl = 0; // common prefix length
+      $n = count($list);
+      $l = strlen($list[0]);
+      while ($pl < $l) {
+         $c = $list[0][$pl];
+         for ($i=1; $i<$n; $i++) {
+             if ($list[$i][$pl] !== $c) break 2;
+         }
+         $pl++;
+      }
+      $prefix = substr($list[0], 0, $pl);
+
+      return $prefix;
+  }
+
+  public function ajaxGetItems(Array $data)
+  {
+      $sql = sprintf("SELECT DISTINCT %s AS value FROM %s WHERE blz_kto = %s AND category = %s AND from_to = %s AND datum >= now() - interval '%s'",
+                    $this->valuecolumn,
+                    $this->table,
+                    $this->quote($data['blzkto']),
+                    $this->quote(utf8_decode($data['category'])),
+                    $this->quote(utf8_decode($data['from_to'])),
+                    $this->lookup_period);
+      $values = $this->db->fetchObjectList($sql);
+
+      $sql = sprintf("SELECT DISTINCT descr FROM %s WHERE blz_kto = %s AND category = %s AND from_to = %s AND datum >= now() - interval '%s' ORDER BY descr",
+                    $this->table,
+                    $this->quote($data['blzkto']),
+                    $this->quote(utf8_decode($data['category'])),
+                    $this->quote(utf8_decode($data['from_to'])),
+                    $this->lookup_period);
+
+      $list = [];
+      foreach ($this->db->fetchObjectList($sql) as $row)
+         $list[] = utf8_encode($row->descr);
+
+      return ['use_value' => count($values) == 1,
+             'value' => count($values) == 1 ? $values[0]->value : '',
+             'list' => $list,
+             'prefix' => $this->getCommonPrefix($list)];
+  }
 }
index 38cc527..d277473 100644 (file)
@@ -145,6 +145,92 @@ textarea {
 
 </ul>
 
+<protect><script type="text/javascript">
+$(function(){
+    $('#statement').focus();
+
+    var from_to_values = {};
+    $.invoke('Accounting/GetCategoryInfo', 'blzkto='+$('input[name="blzkto"]').val(), function(data){
+       from_to_values = data.list;
+    });
+
+    $('<textarea id="descriptions" rows="10" cols="60" readonly />').insertBefore('h3.bar:last');
+    $('ul').append($('<li> Die Taste <b>r</b> im Feld Betrag springt zur Kategorie zurück</li>'));
+    if ($('input.button[value="Insert"]').length) {
+       $('select#category').blur(function(e){
+           if ($(e.target).val().length) {
+               $('input[name="newcategory"]').val('');
+               $('select#from_to').focus();
+
+               update_select('select#from_to', from_to_values[$('select#category').val()]);
+           } else {
+               $('input[name="newcategory"]').focus();
+           }
+       });
+       $('select#from_to').blur(function(e){
+           if ($(e.target).val().length) {
+               $('input[name="newfrom_to"]').val('');
+               $('input#value').focus();
+
+               if ($('select#category').val().length) {
+                   var parms = {};
+                   parms['blzkto'] = $('input[name="blzkto"]').val();
+                   parms['category'] = $('select#category').val();
+                   parms['from_to'] = $('select#from_to').val();
+                   $.invoke('Accounting/GetItems', parms, function(data){
+                       if (data.use_value)
+                           $('input#value').val(data.value);
+                       else
+                           $('input#value').select().focus();
+                       $('textarea#descriptions').val('');
+                       for (var i=0; i < data.list.length; i++)
+                           $('textarea#descriptions').val($('textarea#descriptions').val() + data.list[i] + '\n');
+                       if (data.prefix.length)
+                           $('textarea#descr').val(data.prefix);
+                       $('input#value').select().focus();
+                   });
+               }
+           } else {
+               $('input[name="newfrom_to"]').focus();
+           }
+       });
+       $('input#value').keypress(function(e){
+           if (e.key == 'r')
+               return false;
+       });
+       $('input#value').keyup(function(e){
+           if (e.key == 'r')
+               $('select#category').focus();
+       });
+       $('input.button[value="Insert"]').click(function(e){
+           if (!$('select#category').val().length && !$('input[name="newcategory"]').val().length) {
+               show_error('Keine Kategorie ausgewählt', 3);
+               return false;
+           }
+           if (!$('select#from_to').val().length && !$('input[name="newfrom_to"]').val().length) {
+               show_error('Kein Absender/Empfänger ausgewählt', 3);
+               return false;
+           }
+           if (!$('input#value').val().length) {
+               show_error('Kein Betrag angegeben', 3);
+               return false;
+           }
+           if (!$('textarea#descr').val().length) {
+               show_error('Kein Verwendungszweck angegeben', 3);
+               return false;
+           }
+
+           show_message('Buchung wird gespeichert.', 10);
+           $.invoke('Accounting/Insert', $('form').serialize(), function(data){
+               hide_message();
+               $('input#datum').selectRange(0,$('input#datum').val().lastIndexOf('.')).focus();
+           });
+
+           return false;
+       });
+    }
+});
+</script></protect>
 </page>
 
 # Local variables:
index 1311c89..33dfc83 100644 (file)
@@ -67,6 +67,16 @@ function make_editable(selector)
        });
 }
 
+function update_select(selector, options)
+{
+    var select = $(selector).empty();
+    $.each(options,function(i,e){
+       select.append($('<option>', {
+           value: e.id,
+           text: e.title}));
+    });
+}
+
 function site_url(path)
 {
     return SERVICE_ROOT + path;
@@ -114,6 +124,23 @@ function is_mobile()
                left:     x
            });
        });
+
+    };
+
+    // SELECT TEXT RANGE
+    $.fn.selectRange = function(start, end) {
+       return this.each(function() {
+           if (this.setSelectionRange) {
+               this.focus();
+               this.setSelectionRange(start, end);
+           } else if (this.createTextRange) {
+               var range = this.createTextRange();
+               range.collapse(true);
+               range.moveEnd('character', end);
+               range.moveStart('character', start);
+               range.select();
+           }
+       });
     };
 
 $.invoke = function(name, parms, callback) {