Added generic tags support; tags for dimensions/gl accounts.
authorJanusz Dobrowolski <janusz@frontaccounting.eu>
Thu, 22 Oct 2009 10:34:22 +0000 (10:34 +0000)
committerJanusz Dobrowolski <janusz@frontaccounting.eu>
Thu, 22 Oct 2009 10:34:22 +0000 (10:34 +0000)
admin/db/tags_db.inc [new file with mode: 0644]
admin/tags.php [new file with mode: 0644]
applications/dimensions.php
applications/generalledger.php
dimensions/dimension_entry.php
gl/manage/gl_accounts.php
includes/data_checks.inc

diff --git a/admin/db/tags_db.inc b/admin/db/tags_db.inc
new file mode 100644 (file)
index 0000000..2a72fd8
--- /dev/null
@@ -0,0 +1,184 @@
+<?php
+/**********************************************************************
+    Copyright (C) FrontAccounting, LLC.
+       Released under the terms of the GNU General Public License, GPL, 
+       as published by the Free Software Foundation, either version 3 
+       of the License, or (at your option) any later version.
+    This program 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 License here <http://www.gnu.org/licenses/gpl-3.0.html>.
+***********************************************************************/
+
+function add_tag($type, $name, $description)
+{
+       $sql = "INSERT INTO ".TB_PREF."tags (type, name, description)
+               VALUES (".db_escape($type).", ".db_escape($name).", ".db_escape($description).")";
+
+       return db_query($sql);
+}
+
+//--------------------------------------------------------------------------------------
+
+function update_tag($id, $name, $description, $type=null)
+{
+       $sql = "UPDATE ".TB_PREF."tags SET name=".db_escape($name).", 
+                                       description=".db_escape($description);
+       if ($type != null)
+               $sql .= ", type=".db_escape($type);
+
+       $sql .= " WHERE id = ".db_escape($id);
+
+       return db_query($sql);
+}
+
+//--------------------------------------------------------------------------------------
+
+function get_tags($type, $all=false)
+{
+       $sql = "SELECT * FROM ".TB_PREF."tags WHERE type=".db_escape($type);
+       
+       if (!$all) $sql .= " AND !inactive";
+       
+       $sql .= " ORDER BY name";
+
+       return db_query($sql, "could not get tags");
+}
+
+//--------------------------------------------------------------------------------------
+
+function get_tag($id)
+{
+       $sql = "SELECT * FROM ".TB_PREF."tags WHERE id = ".db_escape($id);
+
+       $result = db_query($sql, "could not get tag");
+
+       return db_fetch($result);
+}
+
+//--------------------------------------------------------------------------------------
+
+function get_tag_type($id)
+{
+       $sql = "SELECT type FROM ".TB_PREF."tags WHERE id = ".db_escape($id);
+
+       $result = db_query($sql, "could not get tag type");
+
+       $row = db_fetch_row($result);
+       return $row[0];
+}
+
+//--------------------------------------------------------------------------------------
+
+function get_tag_name($id)
+{
+       $sql = "SELECT name FROM ".TB_PREF."tags WHERE id = ".db_escape($id);
+
+       $result = db_query($sql, "could not get tag name");
+
+       $row = db_fetch_row($result);
+       return $row[0];
+}
+
+//--------------------------------------------------------------------------------------
+
+function get_tag_description($id)
+{
+       $sql = "SELECT description FROM ".TB_PREF."tags WHERE id = ".db_escape($id);
+
+       $result = db_query($sql, "could not get tag description");
+
+       $row = db_fetch_row($result);
+       return $row[0];
+}
+
+//--------------------------------------------------------------------------------------
+
+function delete_tag($id)
+{
+       $sql = "DELETE FROM ".TB_PREF."tags WHERE id = ".db_escape($id);
+
+       db_query($sql, "could not delete tag");
+}
+
+//--------------------------------------------------------------------------------------
+
+function add_tag_associations($recordid, $tagids)
+{
+       _vd($tagids);
+       foreach($tagids as $tagid) {
+               if (!$tagid) continue;
+               $sql = "INSERT INTO ".TB_PREF."tag_associations (record_id, tag_id)
+                       VALUES (".db_escape($recordid).", ".db_escape($tagid).")";
+
+               db_query($sql, "could not add tag association");
+       }
+}
+
+//--------------------------------------------------------------------------------------
+
+function update_tag_associations($type, $recordid, $tagids)
+{
+       // Delete the old associations
+       delete_tag_associations($type, $recordid, false);
+       // Add the new associations
+       add_tag_associations($recordid, $tagids);
+}
+
+//--------------------------------------------------------------------------------------
+
+// To delete tag associations, we need to specify the tag type.
+// Otherwise we may inadvertantly delete records for another type of tag
+function delete_tag_associations($type, $recordid, $all=false)
+{
+       $sql = "DELETE ta FROM ".TB_PREF."tag_associations AS ta 
+                               INNER JOIN ".TB_PREF."tags AS tags ON tags.id = ta.tag_id 
+                               WHERE tags.type = ".db_escape($type)." AND ta.record_id = ".db_escape($recordid);
+       
+       if (!$all)
+               $sql .= " AND tags.inactive = 0";
+
+       db_query($sql, "could not delete tag associations");
+}
+
+//--------------------------------------------------------------------------------------
+
+function get_records_associated_with_tag($id)
+{
+       // Which table we query is based on the tag type
+       $type = get_tag_type($id);
+       
+       $table = $key = '';
+       switch ($type) {
+               case TAG_ACCOUNT:
+                       $table = TB_PREF."chart_master";
+                       $key = "account_code";
+                       break;
+               case TAG_DIMENSION:
+                       $table = TB_PREF."dimensions";
+                       $key = "id";
+                       break;
+       }
+       
+       $sql = "SELECT $table.* FROM $table 
+               INNER JOIN ".TB_PREF."tag_associations AS ta ON ta.record_id = $table.$key
+               INNER JOIN ".TB_PREF."tags AS tags ON ta.tag_id = tags.id
+               WHERE tags.id = ".db_escape($id);
+
+       return db_query($sql, "could not get tag associations for tag");
+}
+
+//--------------------------------------------------------------------------------------
+
+function get_tags_associated_with_record($type, $recordid)
+{
+       $sql = "SELECT tags.* FROM ".TB_PREF."tag_associations AS ta 
+                               INNER JOIN ".TB_PREF."tags AS tags ON tags.id = ta.tag_id 
+                               WHERE tags.type = $type AND ta.record_id = ".db_escape($recordid);
+
+       return db_query($sql, "could not get tags associations for record");
+}
+
+//--------------------------------------------------------------------------------------
+
+?>
\ No newline at end of file
diff --git a/admin/tags.php b/admin/tags.php
new file mode 100644 (file)
index 0000000..9bb6c6d
--- /dev/null
@@ -0,0 +1,188 @@
+<?php
+/**********************************************************************
+    Copyright (C) FrontAccounting, LLC.
+       Released under the terms of the GNU General Public License, GPL, 
+       as published by the Free Software Foundation, either version 3 
+       of the License, or (at your option) any later version.
+    This program 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 License here <http://www.gnu.org/licenses/gpl-3.0.html>.
+***********************************************************************/
+$path_to_root = "..";
+include_once($path_to_root . "/includes/types.inc"); // For tag constants
+
+// Set up page security based on what type of tags we're working with
+if ($_GET['type'] == "account" || $_POST['type'] == TAG_ACCOUNT) {
+       $page_security = 'SA_GLACCOUNTTAGS';
+} else if($_GET['type'] == "dimension" || $_POST['type'] == TAG_DIMENSION) {
+       $page_security = 'SA_DIMTAGS';
+}
+
+include($path_to_root . "/includes/session.inc");  // Define session before using $_SESSION
+
+if (!isset($page_security)) {
+  // If GET & POST don't have the info, try getting it from the session.
+  $page_security = $_SESSION['tags_page_security'];
+}
+$_SESSION['tags_page_security'] = $page_security;
+
+// We use $_POST['type'] throughout this script, so convert $_GET vars
+// if $_POST['type'] is not set.
+if (!isset($_POST['type'])) {
+       if ($_GET['type'] == "account")
+               $_POST['type'] = TAG_ACCOUNT;
+       elseif ($_GET['type'] == "dimension")
+               $_POST['type'] = TAG_DIMENSION;
+       else
+               die(_("Unspecified tag type"));
+}
+
+// Set up page based on what type of tags we're working with
+// TODO: Set $_SESSION['sel_app'] to be relevant app (see /includes/page/header.inc::page_header()
+switch ($_POST['type']) {
+       case TAG_ACCOUNT:
+               // Account tags
+               $_SESSION['page_title'] = _("Account Tags");
+               break;
+       case TAG_DIMENSION:
+               // Dimension tags
+               $_SESSION['page_title'] = _("Dimension Tags");
+}
+
+page($_SESSION['page_title']);
+include_once($path_to_root . "/admin/db/tags_db.inc");
+
+include($path_to_root . "/includes/ui.inc");
+
+simple_page_mode(true);
+
+//-----------------------------------------------------------------------------------
+
+function can_process() 
+{
+       if (strlen($_POST['name']) == 0) 
+       {
+               display_error( _("The tag name cannot be empty."));
+               set_focus('name');
+               return false;
+       }
+       return true;
+}
+
+//-----------------------------------------------------------------------------------
+
+if ($Mode=='ADD_ITEM' || $Mode=='UPDATE_ITEM') 
+{
+       if (can_process()) 
+       {
+       if ($selected_id != -1) 
+       {
+               if( $ret = update_tag($selected_id, $_POST['name'], $_POST['description']))
+                               display_notification(_('Selected tag settings have been updated'));
+       } 
+       else 
+       {
+               if( $ret = add_tag($_POST['type'], $_POST['name'], $_POST['description']))
+                               display_notification(_('New tag has been added'));
+       }
+               if ($ret) $Mode = 'RESET';
+       }
+}
+
+//-----------------------------------------------------------------------------------
+
+function can_delete($selected_id)
+{
+       if ($selected_id == -1)
+               return false;
+       $result = get_records_associated_with_tag($selected_id);
+       
+       if (db_num_rows($result) > 0)   
+       {
+               display_error(_("Cannot delete this tag because records have been created referring to it."));
+               return false;
+       }
+
+       return true;
+}
+
+
+//-----------------------------------------------------------------------------------
+
+if ($Mode == 'Delete')
+{
+       if (can_delete($selected_id))
+       {
+               delete_tag($selected_id);
+               display_notification(_('Selected tag has been deleted'));
+       }
+       $Mode = 'RESET';
+}
+
+//-----------------------------------------------------------------------------------
+
+if ($Mode == 'RESET')
+{
+       $selected_id = -1;
+       $_POST['name'] = $_POST['description'] = '';
+}
+
+//-----------------------------------------------------------------------------------
+
+$result = get_tags($_POST['type'], check_value('show_inactive'));
+
+start_form();
+start_table($table_style);
+$th = array(_("Tag Name"), _("Tag Description"), "", "");
+inactive_control_column($th);
+table_header($th);
+
+$k = 0;
+while ($myrow = db_fetch($result)) 
+{
+       alt_table_row_color($k);
+
+       label_cell($myrow['name']);
+       label_cell($myrow['description']);
+       inactive_control_cell($myrow["id"], $myrow["inactive"], 'tags', 'id');
+       edit_button_cell("Edit".$myrow["id"], _("Edit"));
+       delete_button_cell("Delete".$myrow["id"], _("Delete"));
+       end_row();
+}
+
+inactive_control_row($th);
+end_table(1);
+
+//-----------------------------------------------------------------------------------
+
+start_table($table_style2);
+
+if ($selected_id != -1) // We've selected a tag 
+{
+       if ($Mode == 'Edit') {
+               // Editing an existing tag
+               $myrow = get_tag($selected_id);
+       
+               $_POST['name'] = $myrow["name"];
+               $_POST['description'] = $myrow["description"];
+       }
+       // Note the selected tag
+       hidden('selected_id', $selected_id);
+}
+       
+text_row_ex(_("Tag Name:"), 'name', 15, 30);
+text_row_ex(_("Tag Description:"), 'description', 40, 60);
+hidden('type');
+
+end_table(1);
+
+submit_add_or_update_center($selected_id == -1, '', 'both');
+
+end_form();
+
+//------------------------------------------------------------------------------------
+
+end_page();
+
+?>
index 3a1cca71b1650cccda2ba36fba0ffbf9d9e03dc1..39ab0a36ff32f63ff6d7be875215c1d3d760f433 100644 (file)
@@ -31,15 +31,17 @@ class dimensions_app extends application
 
                        $this->add_rapp_function(1, _("Dimension &Reports"),
                                "reporting/reports_main.php?Class=4", 'SA_DIMENSIONREP');
+                       
+                       $this->add_module(_("Maintenance"));
+                       $this->add_lapp_function(2, _("Dimension &Tags"),
+                               "admin/tags.php?type=dimension", 'SA_DIMTAGS');
+                               
                        if (count($installed_extensions) > 0)
                        {
-                               $i = 0;
                                foreach ($installed_extensions as $mod)
                                {
                                        if (@$mod['active'] && $mod['type'] == 'plugin' && $mod["tab"] == "proj")
                                        {
-                                               if ($i++ == 0)
-                                                       $this->add_module(_("Maintenance"));
                                                $this->add_rapp_function(2, $mod["title"], 
                                                        "modules/".$mod["path"]."/".$mod["filename"]."?",
                                                        isset($mod["access"]) ? $mod["access"] : 'SA_OPEN' );
index 062eef687d59c0e4b1788ecfda7b9b848d0aa03e..5a8a7612b2e2442f966282b94f77d18a06d25864 100644 (file)
@@ -52,6 +52,8 @@ class general_ledger_app extends application
                        "gl/manage/bank_accounts.php?", 'SA_BANKACCOUNT');
                $this->add_lapp_function(2, _("&Quick Entries"),
                        "gl/manage/gl_quick_entries.php?", 'SA_QUICKENTRY');
+               $this->add_lapp_function(2, _("Account &Tags"),
+                       "admin/tags.php?type=account", 'SA_GLACCOUNTTAGS');
                $this->add_lapp_function(2, "","");
                $this->add_lapp_function(2, _("&Currencies"),
                        "gl/manage/currencies.php?", 'SA_CURRENCY');
index 7b9bcb3791ceb475581dc3a87287c7ed71b480c8..626d8466914e5ca6a1b393c9b4c85542dfd952d1 100644 (file)
@@ -17,6 +17,7 @@ include_once($path_to_root . "/includes/date_functions.inc");
 include_once($path_to_root . "/includes/manufacturing.inc");
 include_once($path_to_root . "/includes/data_checks.inc");
 
+include_once($path_to_root . "/admin/db/tags_db.inc");
 include_once($path_to_root . "/dimensions/includes/dimensions_db.inc");
 include_once($path_to_root . "/dimensions/includes/dimensions_ui.inc");
 
@@ -161,6 +162,7 @@ if (isset($_POST['ADD_ITEM']) || isset($_POST['UPDATE_ITEM']))
                {
 
                        $id = add_dimension($_POST['ref'], $_POST['name'], $_POST['type_'], $_POST['date_'], $_POST['due_date'], $_POST['memo_']);
+                       add_tag_associations($id, $_POST['dimension_tags']);
 
                        meta_forward($_SERVER['PHP_SELF'], "AddedID=$id");
                } 
@@ -168,6 +170,7 @@ if (isset($_POST['ADD_ITEM']) || isset($_POST['UPDATE_ITEM']))
                {
 
                        update_dimension($selected_id, $_POST['name'], $_POST['type_'], $_POST['date_'], $_POST['due_date'], $_POST['memo_']);
+                       update_tag_associations(TAG_DIMENSION, $selected_id, $_POST['dimension_tags']);
 
                        meta_forward($_SERVER['PHP_SELF'], "UpdatedID=$selected_id");
                }
@@ -194,6 +197,7 @@ if (isset($_POST['delete']))
 
                // delete
                delete_dimension($selected_id);
+               delete_tag_associations(TAG_DIMENSION,$selected_id, true);
                meta_forward($_SERVER['PHP_SELF'], "DeletedID=$selected_id");
        }
 }
@@ -245,6 +249,12 @@ if ($selected_id != -1)
        $_POST['date_'] = sql2date($myrow["date_"]);
        $_POST['due_date'] = sql2date($myrow["due_date"]);
        $_POST['memo_'] = get_comments_string(ST_DIMENSION, $selected_id);
+       
+       $tags_result = get_tags_associated_with_record(TAG_DIMENSION, $selected_id);
+       $tagids = array();
+       while ($tag = db_fetch($tags_result)) 
+               $tagids[] = $tag['id'];
+       $_POST['dimension_tags'] = $tagids;     
 
        hidden('ref', $_POST['ref']);
 
@@ -254,6 +264,7 @@ if ($selected_id != -1)
 } 
 else 
 {
+       $_POST['dimension_tags'] = array();
        ref_row(_("Dimension Reference:"), 'ref', '', $Refs->get_next(ST_DIMENSION));
 }
 
@@ -267,6 +278,8 @@ date_row(_("Start Date") . ":", 'date_');
 
 date_row(_("Date Required By") . ":", 'due_date', '', null, $SysPrefs->default_dimension_required_by());
 
+tag_list_row(_("Tags:"), 'dimension_tags', 5, TAG_DIMENSION, true);
+
 textarea_row(_("Memo:"), 'memo_', null, 40, 5);
 
 end_table(1);
@@ -277,7 +290,7 @@ if (isset($_POST['closed']) && $_POST['closed'] == 1)
 if ($selected_id != -1) 
 {
        echo "<br>";
-       submit_center_first('UPDATE_ITEM', _("Update"), _('Save changes to dimension'), 'default');
+       submit_center_first('UPDATE_ITEM', _("Update"), _('Save changes to dimension'), false);
        if ($_POST['closed'] == 1)
                submit('reopen', _("Re-open This Dimension"), true, _('Mark this dimension as re-opened'), true);
        else    
@@ -286,7 +299,7 @@ if ($selected_id != -1)
 }
 else
 {
-       submit_center('ADD_ITEM', _("Add"), true, '', 'default');
+       submit_center('ADD_ITEM', _("Add"), true, '', false);
 }
 end_form();
 
index 718be9bd872f692f7b257154933e348a60c8fe65..02a78bc763bf8c5e37a55cfbb1a8b71081001416 100644 (file)
@@ -17,6 +17,7 @@ page(_("Chart of Accounts"));
 
 include($path_to_root . "/includes/ui.inc");
 include($path_to_root . "/gl/includes/gl_db.inc");
+include($path_to_root . "/admin/db/tags_db.inc");
 include_once($path_to_root . "/includes/data_checks.inc");
 
 check_db_has_gl_account_groups(_("There are no account groups defined. Please define at least one account group before entering accounts."));
@@ -39,7 +40,6 @@ elseif (isset($_GET['selected_account']))
 }
 else
        $selected_account = "";
-
 //-------------------------------------------------------------------------------------
 
 if (isset($_POST['add']) || isset($_POST['update'])) 
@@ -70,12 +70,15 @@ if (isset($_POST['add']) || isset($_POST['update']))
        {
                if ($accounts_alpha == 2)
                        $_POST['account_code'] = strtoupper($_POST['account_code']);
+
        if ($selected_account) 
                {
                if (update_gl_account($_POST['account_code'], $_POST['account_name'], 
                                $_POST['account_type'], $_POST['account_code2'])) {
                                update_record_status($_POST['account_code'], $_POST['inactive'],
                                        'chart_master', 'account_code');
+                               update_tag_associations(TAG_ACCOUNT, $_POST['account_code'], 
+                                       $_POST['account_tags']);
                                $Ajax->activate('account_code'); // in case of status change
                                display_notification(_("Account data has been updated."));
                        }
@@ -85,6 +88,7 @@ if (isset($_POST['add']) || isset($_POST['update']))
                if (add_gl_account($_POST['account_code'], $_POST['account_name'], 
                                $_POST['account_type'], $_POST['account_code2']))
                                {
+                                       add_tag_associations($_POST['account_code'], $_POST['account_tags']);
                                        display_notification(_("New account has been added."));
                                        $selected_account = $_POST['AccountList'] = $_POST['account_code'];
                                }
@@ -214,6 +218,8 @@ if (isset($_POST['delete']))
        {
                delete_gl_account($selected_account);
                $selected_account = $_POST['AccountList'] = '';
+               delete_tag_associations(TAG_ACCOUNT,$selected_account, true);
+               $selected_account = $_POST['AccountList'] = '';
                display_notification(_("Selected account has been deleted"));
                unset($_POST['account_code']);
                $Ajax->activate('_page_body');
@@ -252,6 +258,12 @@ if ($selected_account != "")
        $_POST['account_name']  = $myrow["account_name"];
        $_POST['account_type'] = $myrow["account_type"];
        $_POST['inactive'] = $myrow["inactive"];
+       
+       $tags_result = get_tags_associated_with_record(TAG_ACCOUNT, $selected_account);
+       $tagids = array();
+       while ($tag = db_fetch($tags_result)) 
+               $tagids[] = $tag['id'];
+       $_POST['account_tags'] = $tagids;
 
        hidden('account_code', $_POST['account_code']);
        hidden('selected_account', $selected_account);
@@ -261,6 +273,7 @@ if ($selected_account != "")
 else
 {
        if (!isset($_POST['account_code'])) {
+               $_POST['account_tags'] = array();
                $_POST['account_code'] = $_POST['account_code2'] = '';
                $_POST['account_name']  = $_POST['account_type'] = '';
                $_POST['inactive'] = 0;
@@ -274,16 +287,18 @@ text_row_ex(_("Account Name:"), 'account_name', 60);
 
 gl_account_types_list_row(_("Account Group:"), 'account_type', null);
 
+tag_list_row(_("Account Tags:"), 'account_tags', 5, TAG_ACCOUNT, true);
+
 record_status_list_row(_("Account status:"), 'inactive');
 end_table(1);
 
 if ($selected_account == "") 
 {
-       submit_center('add', _("Add Account"), true, '', 'default');
+       submit_center('add', _("Add Account"), true, '', false);
 } 
 else 
 {
-    submit_center_first('update', _("Update Account"), '', 'default');
+    submit_center_first('update', _("Update Account"), '', false);
     submit_center_last('delete', _("Delete account"), '',true);
 }
 end_form();
index 8e03d5849567ff107b12d1e3029ea537b0750ddb..295a353e1203d2ec1cc484291803d9e8113f7fe7 100644 (file)
@@ -428,6 +428,22 @@ function db_has_quick_entries()
        return check_empty_result("SELECT COUNT(*) FROM ".TB_PREF."quick_entries");
 }
 
+function db_has_tags($type)
+{
+       return check_empty_result("SELECT COUNT(*) FROM ".TB_PREF."tags WHERE type=$type");
+}
+
+function check_db_has_tags($type, $msg)
+{
+       global $path_to_root;
+    if (!db_has_tags($type)) 
+    {
+       display_error($msg, true);
+       end_page();
+       exit;   
+    }  
+}
+
 function check_empty_result($sql)
 {
        $result = db_query($sql, "could not do check empty query");