noalyss-commit
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Noalyss-commit] [noalyss] 07/13: task #0001697: Extension usage des éti


From: Dany De Bontridder
Subject: [Noalyss-commit] [noalyss] 07/13: task #0001697: Extension usage des étiquettes , tag on operation + export CSV + filter
Date: Wed, 11 Nov 2020 10:23:42 -0500 (EST)

sparkyx pushed a commit to branch master
in repository noalyss.

commit 085efd0efa4c1dc9bc0ce923064e8ff810a5875d
Author: sparkyx <danydb@noalyss.eu>
AuthorDate: Tue Nov 10 19:48:20 2020 +0100

    task #0001697: Extension usage des étiquettes , tag on operation + export 
CSV + filter
---
 html/ajax_misc.php                         |  10 +-
 html/js/acc_ledger.js                      |  26 +++-
 html/js/scripts.js                         | 142 +++++++++++++++++++-
 html/recherche.php                         |  12 +-
 include/ajax/ajax_ledger.php               |   1 +
 include/ajax/ajax_operation_tag.php        | 166 ++++++++++++++++++++++++
 include/ajax/ajax_search_add_tag.php       |   8 +-
 include/ajax/ajax_search_clear_tag.php     |   4 +-
 include/ajax/ajax_search_display_tag.php   |  23 +++-
 include/ajax/ajax_search_filter.php        |  42 ++++--
 include/ajax/ajax_tag_list.php             |  10 +-
 include/ajax/ajax_tag_select_search.php    |   4 +-
 include/class/acc_ledger_search.class.php  |  27 +++-
 include/class/follow_up.class.php          |   1 +
 include/class/tag.class.php                |  62 ++-------
 include/class/tag_action.class.php         |  94 ++++++++++++++
 include/class/tag_operation.class.php      | 199 +++++++++++++++++++++++++++++
 include/constant.php                       |   2 +-
 include/database/user_filter_sql.class.php |   5 +
 include/history_operation.inc.php          |  13 +-
 include/sql/patch/upgrade150.sql           |  15 +++
 include/template/action_other_action.php   |   8 +-
 include/template/action_search.php         |   6 +-
 include/template/detail-action.php         |   2 +-
 include/template/ledger_detail_bottom.php  |  19 ++-
 include/template/ledger_search.php         |  37 +++++-
 include/template/tag_select.php            |  19 ++-
 27 files changed, 857 insertions(+), 100 deletions(-)

diff --git a/html/ajax_misc.php b/html/ajax_misc.php
index 2db616d..a1dfd69 100644
--- a/html/ajax_misc.php
+++ b/html/ajax_misc.php
@@ -240,6 +240,8 @@ $path = array(
     "save_filter"=>"ajax_search_filter",
     // Load a search filter
     "load_filter"=>"ajax_search_filter",
+    // display tag for filter
+    'display_filter_tag'=>'ajax_search_filter',
     // search operation to reconcile
        'search_op'=>'ajax_search_operation',
     // delete operation
@@ -269,7 +271,13 @@ $path = array(
     // set the group for a tag
     'tag_set_group'=>"ajax_tag_set_group",
     // Document_state
-    "document_state"=>"ajax_document_state"
+    "document_state"=>"ajax_document_state",
+    // Operations tag add
+    'operation_tag_add'=>"ajax_operation_tag",
+    // Operations tag remove
+    'operation_tag_remove'=>"ajax_operation_tag",
+    // Operations tag select
+    'operation_tag_select'=>"ajax_operation_tag"
 )    ;
 
 if (array_key_exists($op, $path)) {
diff --git a/html/js/acc_ledger.js b/html/js/acc_ledger.js
index 33e959f..03116b7 100644
--- a/html/js/acc_ledger.js
+++ b/html/js/acc_ledger.js
@@ -1297,8 +1297,8 @@ function manage_search_filter(p_obj) {
        onSuccess:function(req) {
             remove_waiting_box();
             var x=posX;
-            var y=posY-20;
-            
create_div({'id':'boxfilter'+p_obj.div,'cssclass':'inner_box','html':req.responseText,'style':'top:'+y+'px;left:'+x+'px;position:absolute;width:400px'});
+            var y=calcy(200)
+            
create_div({'id':'boxfilter'+p_obj.div,'cssclass':'inner_box','html':req.responseText,'style':'top:'+y+'px;left:'+x+'px;position:absolute;width:400px',drag:1});
             $('boxfilter'+p_obj.div).show();
        }
     });
@@ -1315,8 +1315,9 @@ function manage_search_filter(p_obj) {
 function save_filter(p_div,p_dossier) {
     var elt=['ledger_type','nb_jrn','date_start','date_end',
         
'date_paid_start','date_paid_end','desc','amount_min','amount_max','qcode','accounting',
-        'operation_filter'];
+        'operation_filter','tag_option'];
     var eltValue={};
+    var i =0;
     eltValue['gDossier']=p_dossier;
     eltValue['op']="save_filter";
     eltValue['div']=p_div;
@@ -1339,6 +1340,12 @@ function save_filter(p_div,p_dossier) {
    
         }
     }
+      //ledger's tags
+    var aTag=Array.from(document.getElementsByName(p_div+"tag[]"));
+    eltValue["tag[]"]=[];
+    for (i=0 ; i < aTag.length;i++) {
+            eltValue["tag[]"][i]=aTag[i].value;
+    }
     new Ajax.Request('ajax_misc.php', {
         method:"POST",
         parameters:eltValue,
@@ -1349,7 +1356,7 @@ function save_filter(p_div,p_dossier) {
                     /*Add the new list to the selection */
                     var new_item=document.createElement('li');
                     new_item.innerHTML=answer.filter_name;
-                    
new_item.setAttribute("id","li"+p_div+"_"+answer.filter_id);
+                    
new_item.setAttribute("id","manageli"+p_div+"_"+answer.filter_id);
                     $('manage'+p_div).appendChild(new_item);
                     $(p_div+"filter_new").value="";
                 } else {
@@ -1377,7 +1384,7 @@ function load_filter(p_div,p_dossier,p_filter_id) {
                 var answer=req.responseJSON;    
                 console.log(answer);
                 var 
elt=['ledger_type','date_start','date_end','date_paid_start','date_paid_end',
-                    
'desc','amount_min','amount_max','qcode','accounting','operation_filter'];
+                    
'desc','amount_min','amount_max','qcode','accounting','operation_filter','tag_option'];
                 for (var i=0;i<elt.length;i++) {
                     var idx=elt[i];
                     $(p_div+idx).value=answer[elt[i]];
@@ -1402,8 +1409,15 @@ function load_filter(p_div,p_dossier,p_filter_id) {
                    eltHidden.setAttribute("value",answer.r_jrn[i]);
                    eltLedgerId.appendChild(eltHidden);
                }
+               new Ajax.Request("ajax_misc.php",{
+                   method:"get",
+                   
parameters:{"gDossier":p_dossier,"div":p_div,"op":"display_filter_tag","filter_id":p_filter_id,
+                   uf_tag:answer.uf_tag},
+                   onSuccess:function (req) {
+                       $(p_div+'tag_choose_td').update(req.responseText);
+                   }
+               })
                
-
                
            } catch (e) {
               smoke.alert(e.message);
diff --git a/html/js/scripts.js b/html/js/scripts.js
index 69c6116..14a8a4f 100644
--- a/html/js/scripts.js
+++ b/html/js/scripts.js
@@ -2711,13 +2711,16 @@ function activate_tag(p_dossier, p_tag_id) {
  * Display a div with available tags, this div can update the cell
  * tag_choose_td
  * @param {type} p_dossier
+ * @param {string} p_prefix is the prefix of the div
+ * @param {string} Calling object either Tag_Operation or Tag_Action
  * @returns {undefined}
+ * 
  */
-function search_display_tag(p_dossier, p_prefix)
+function search_display_tag(p_dossier, p_prefix,p_object)
 {
     try {
         waiting_box();
-        var queryString = "op=search_display_tag&gDossier=" + p_dossier + 
"&pref=" + p_prefix;
+        var queryString = { op : 
"search_display_tag",gDossier:p_dossier,pref:p_prefix,caller_obj:p_object};
         var action = new Ajax.Request(
                 "ajax_misc.php",
                 {
@@ -3818,4 +3821,137 @@ function uncheck_other(p_click,p_name)
         aCheckbox[i].checked=false;
     }
     p_click.checked=true;
-}
\ No newline at end of file
+}
+/**
+ * Manage the tag with operations
+ * @returns {undefined}
+ */
+var operation_tag = function (p_div)
+{
+    this.ctl = p_div;
+    console.log("ctl "+p_div);
+    /**
+     * Show a list of tag which can be added to the current followup document
+     * @param {type} p_dossier
+     * @param {type} jrn_id
+     * @returns {undefined}
+     */
+    this.select = function (p_dossier, p_jrn_id)
+    {
+        try {
+            waiting_box();
+            var queryString = 
{jrn_id:p_jrn_id,op:"operation_tag_select",gDossier:p_dossier,ctl:this.ctl};
+            var action = new Ajax.Request(
+                    "ajax_misc.php",
+                    {
+                        method: 'get', 
+                        parameters: queryString,
+                        onFailure: ajax_misc_failure,
+                        onSuccess: function (req, j) {
+                            remove_waiting_box();
+                            
+                            var answer = req.responseXML;
+                            var html = answer.getElementsByTagName('code');
+                            if (html.length === 0)
+                            {
+                                var rec = unescape_xml(req.responseText);
+                                error_message('erreur :' + rec);
+                            }
+                            var code_html = getNodeText(html[0]);
+                            code_html = unescape_xml(code_html);
+                            var pos = fixed_position(35, 229);
+                            add_div({id: 'tag_div', style: pos, cssclass: 
'inner_box tag', drag: 0});
+
+                            remove_waiting_box();
+                            $('tag_div').innerHTML = code_html;
+                        }
+                    }
+            );
+        } catch (e) {
+            error_message(e.message);
+        }
+    };
+
+    /**
+     * @brief Add the current tag to the current ag_id
+     * @param {type} p_dossier
+     * @param {type} ag_id
+     * @param p_isgroup g it is a group , t is a single tag
+     * @returns {undefined}
+     */
+    this.add = function (p_dossier, p_jrn_id, t_id, p_isgroup)
+    {
+        try {
+            waiting_box();
+            var queryString = 
{t_id:t_id,jrn_id:p_jrn_id,op:"operation_tag_add",
+                gDossier:p_dossier,ctl:this.ctl,isgroup:p_isgroup};
+            var ctl=this.ctl;
+            var action = new Ajax.Request(
+                    "ajax_misc.php",
+                    {
+                        method: 'get', parameters: queryString,
+                        onFailure: ajax_misc_failure,
+                        onSuccess: function (req, j) {
+                            var answer = req.responseXML;
+                            console.log("1-ctl "+ctl);
+                            var html = answer.getElementsByTagName('code');
+                            if (html.length === 0)
+                            {
+                                var rec = unescape_xml(req.responseText);
+                                error_message('erreur :' + rec);
+                            }
+                            var code_html = getNodeText(html[0]);
+                            code_html = unescape_xml(code_html);
+                            remove_waiting_box();
+                            $('operation_tag_td'+ctl).innerHTML = code_html;
+                            removeDiv('tag_div');
+                        }
+                    }
+            );
+        } catch (e) {
+            error_message(e.message);
+        }
+    };
+    /**
+     * @brief remove the current tag to the current ag_id
+     * @param {type} p_dossier
+     * @param {type} ag_id
+     * @returns {undefined}
+     */
+    this.remove = function (p_dossier, p_jrn_id, t_id)
+    {
+        var ctl=this.ctl;
+         console.log("remove-1.ctl "+ctl);
+        confirm_box(null, content[50], function () {
+            try {
+                waiting_box();
+                var queryString = 
{t_id:t_id,jrn_id:p_jrn_id,op:"operation_tag_remove",gDossier:p_dossier,ctl:ctl};
+                var action = new Ajax.Request(
+                        "ajax_misc.php",
+                        {
+                            method: 'get', 
+                            parameters: queryString,
+                            onFailure: ajax_misc_failure,
+                            onSuccess: function (req, j) {
+                                var answer = req.responseXML;
+                                var html = answer.getElementsByTagName('code');
+                                if (html.length === 0)
+                                {
+                                    var rec = unescape_xml(req.responseText);
+                                    error_message('erreur :' + rec);
+                                }
+                                var code_html = getNodeText(html[0]);
+                                code_html = unescape_xml(code_html);
+                                remove_waiting_box();
+                                console.log("remove-2.ctl "+ctl);
+                                $('operation_tag_td'+ctl).innerHTML = 
code_html;
+
+                            }
+                        }
+                );
+                } catch (e) {
+                    error_message(e.message);
+                }
+            });
+    };
+};
diff --git a/html/recherche.php b/html/recherche.php
index f34549a..aa655ca 100644
--- a/html/recherche.php
+++ b/html/recherche.php
@@ -124,7 +124,7 @@ if ( isset ($_GET['viewsearch']))
      * Export to csv
      */
     
$r=HtmlInput::get_to_hidden(array('l','date_start','date_end','desc','amount_min','amount_max',
-        'qcode','accounting','unpaid','gDossier','ledger_type'));
+        'qcode','accounting','unpaid','gDossier','ledger_type','tag_option'));
     if (isset($_GET['r_jrn'])) {
         $http=new HttpInput();
         $a_rjrn=$http->get("r_jrn","array");
@@ -135,6 +135,16 @@ if ( isset ($_GET['viewsearch']))
         }
       }
     }
+    if (isset($_GET['tag'])) {
+        $http=new HttpInput();
+        $aTag=$http->get("tag","array");
+      foreach ($aTag as $k=>$v) {
+          // Protect : check that $k and $v are numeric
+        if (isNumber($k)&&isNumber($v)) {
+            $r.=HtmlInput::hidden('tag[]',$v);
+        }
+      }
+    }
     echo '<form action="export.php" method="get">';
     echo $r;
     echo HtmlInput::hidden('act','CSV:histo');
diff --git a/include/ajax/ajax_ledger.php b/include/ajax/ajax_ledger.php
index 316a5a6..6eb4bcb 100644
--- a/include/ajax/ajax_ledger.php
+++ b/include/ajax/ajax_ledger.php
@@ -42,6 +42,7 @@ require_once NOALYSS_INCLUDE.'/lib/idate.class.php';
 require_once NOALYSS_INCLUDE.'/class/noalyss_parameter_folder.class.php';
 require_once NOALYSS_INCLUDE.'/lib/iconcerned.class.php';
 require_once NOALYSS_INCLUDE.'/lib/http_input.class.php';
+require_once NOALYSS_INCLUDE.'/class/tag_operation.class.php';
 $http=new HttpInput();
 
 /**
diff --git a/include/ajax/ajax_operation_tag.php 
b/include/ajax/ajax_operation_tag.php
new file mode 100644
index 0000000..7c0a0d2
--- /dev/null
+++ b/include/ajax/ajax_operation_tag.php
@@ -0,0 +1,166 @@
+<?php
+
+/*
+ *   This file is part of NOALYSS.
+ *
+ *   PhpCompta 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 of the License, or
+ *   (at your option) any later version.
+ *
+ *   PhpCompta 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 PhpCompta; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+// Copyright (2002-2020) Author Dany De Bontridder <danydb@noalyss.eu>
+
+if (!defined('ALLOWED'))
+    die('Appel direct ne sont pas permis');
+require_once NOALYSS_INCLUDE.'/class/tag.class.php';
+require_once NOALYSS_INCLUDE.'/class/tag_operation.class.php';
+
+/**
+ * @file
+ * @brief manage the ajax calls for adding , deleting tag on operations
+ */
+try
+{
+    $op=$http->request('op');
+    $jrn_id=$http->request('jrn_id', "number");
+}
+catch (Exception $ex)
+{
+    echo $ex->getMessage();
+}
+
+// Security : check ledger accessible
+global $g_user;
+$ledger=$cn->get_value("select jr_def_id from jrn where jr_id=$1", [$jrn_id]);
+
+if ($g_user->get_ledger_access($ledger)!='W')
+{
+    record_log("AJT0001");
+    return;
+}
+switch ($op)
+{
+    case 'operation_tag_select':
+        
//--------------------------------------------------------------------------------------------------
+        // Display a list of available tag
+        
//--------------------------------------------------------------------------------------------------
+        ob_start();
+        $tag_operation=new Tag_Operation($cn);
+        echo $tag_operation->select($ctl);
+
+        //------------------- Propose to add a tag
+
+        $js=sprintf("onclick=\"show_tag('%s','%s','%s','j')\"", Dossier::id(), 
'', '-1');
+        if ($g_user->check_action(TAGADD)==1)
+        {
+            echo HtmlInput::button("tag_add", _("Ajout d'un tag"), $js);
+        }
+        echo HtmlInput::button_close("tag_div");
+
+        $response=ob_get_clean();
+        if (headers_sent()&&DEBUG)
+        {
+            echo $response;
+        }
+        else
+        {
+            header('Content-type: text/xml; charset=UTF-8');
+        }
+        $html=escape_xml($response);
+        echo <<<EOF
+<?xml version="1.0" encoding="UTF-8"?>
+        <data>
+        <ctl></ctl>
+        <code>$html</code>
+        </data>
+EOF;
+        return;
+    case 'operation_tag_add':
+        
//--------------------------------------------------------------------------------------------------
+        // Display all the tags attached to this operation
+        
//--------------------------------------------------------------------------------------------------
+        $tag_operation=new Tag_Operation($cn);
+        $tag_operation->set_jrn_id($jrn_id);
+        $pref=$http->request("ctl");
+
+        if ($http->request("isgroup")=='t')
+        {
+            $tag_operation->tag_add($http->request('t_id', "number"));
+        }
+        else
+        {
+            // Add all the tag from the group 
+            $aTag=$cn->get_array("select t_id,t_tag ,t_color from 
jnt_tag_group_tag jtgt  join tags on (tag_id=t_id) where tag_group_id=$1 order 
by 2 ",
+                    [$http->request("t_id", "number")]);
+            $nb_atag=count($aTag);
+            if ($nb_atag>0)
+            {
+                for ($i=0; $i<$nb_atag; $i++)
+                {
+                    $tag_operation->tag_add($aTag[$i]['t_id']);
+                }
+            }
+        }
+
+        ob_start();
+
+        $tag_operation->tag_cell($ctl);
+
+        $response=ob_get_clean();
+        if (headers_sent()&&DEBUG)
+        {
+            echo $response;
+        }
+        else
+        {
+            header('Content-type: text/xml; charset=UTF-8');
+        }
+        $html=escape_xml($response);
+        echo <<<EOF
+<?xml version="1.0" encoding="UTF-8"?>
+<data>
+<ctl></ctl>
+<code>$html</code>
+</data>
+EOF;
+        return;
+        break;
+    case 'operation_tag_remove':
+        $tag_operation=new Tag_Operation($cn);
+        $tag_operation->set_jrn_id($jrn_id);
+        $pref=$http->request("ctl");
+        $tag_operation->tag_remove($http->request("t_id", "number"));
+
+        ob_start();
+
+        $tag_operation->tag_cell($pref);
+
+        $response=ob_get_clean();
+        if (headers_sent()&&DEBUG)
+        {
+            echo $response;
+        }
+        else
+        {
+            header('Content-type: text/xml; charset=UTF-8');
+        }
+        $html=escape_xml($response);
+        echo <<<EOF
+<?xml version="1.0" encoding="UTF-8"?>
+<data>
+<ctl></ctl>
+<code>$html</code>
+</data>
+EOF;
+        return;
+        break;
+}
\ No newline at end of file
diff --git a/include/ajax/ajax_search_add_tag.php 
b/include/ajax/ajax_search_add_tag.php
index d1e3b85..b3697ae 100644
--- a/include/ajax/ajax_search_add_tag.php
+++ b/include/ajax/ajax_search_add_tag.php
@@ -25,18 +25,18 @@ if (!defined('ALLOWED'))
  * @brief add tag , used for follow up
  * @see Tag
  */
-require_once NOALYSS_INCLUDE.'/class/tag.class.php';
+require_once NOALYSS_INCLUDE.'/class/tag_action.class.php';
 //Single Tag
 ob_start();
 if ($_GET['clear']==1)
 {
     /* Add a clear button */
-    echo Tag::add_clear_button($_GET['pref']);
+    echo Tag_Action::add_clear_button($_GET['pref']);
 }
 if ($http->request("obj")=='t')
 {
 
-    $tag=new Tag($cn, $http->get("id", "number"));
+    $tag=new Tag_Action($cn, $http->get("id", "number"));
     $tag->update_search_cell($http->get("pref"));
 }
 elseif ($http->request("obj")=="g")
@@ -47,7 +47,7 @@ elseif ($http->request("obj")=="g")
     $pref=$http->get("pref");
     if ( $nb_atag > 0) {
         for ($i=0;$i<$nb_atag;$i++){
-            $tag=new Tag($cn,$aTag[$i]['t_id']);
+            $tag=new Tag_Action($cn,$aTag[$i]['t_id']);
             $tag->update_search_cell($pref);
         }
     }
diff --git a/include/ajax/ajax_search_clear_tag.php 
b/include/ajax/ajax_search_clear_tag.php
index 3904e07..95ab181 100644
--- a/include/ajax/ajax_search_clear_tag.php
+++ b/include/ajax/ajax_search_clear_tag.php
@@ -24,9 +24,9 @@ if ( !defined ('ALLOWED') )  die('Appel direct ne sont pas 
permis');
  *@see Tag
  */
 
-require_once NOALYSS_INCLUDE.'/class/tag.class.php';
+require_once NOALYSS_INCLUDE.'/class/tag_action.class.php';
 ob_start();
-echo Tag::button_search($_GET['pref']);
+echo Tag_Action::select_tag_search($_GET['pref']);
 $response=  ob_get_clean();
 $html=escape_xml($response);
 header('Content-type: text/xml; charset=UTF-8');
diff --git a/include/ajax/ajax_search_display_tag.php 
b/include/ajax/ajax_search_display_tag.php
index b4295cc..43efd2c 100644
--- a/include/ajax/ajax_search_display_tag.php
+++ b/include/ajax/ajax_search_display_tag.php
@@ -24,10 +24,27 @@ if ( !defined ('ALLOWED') )  die('Appel direct ne sont pas 
permis');
  *@see Tag
  */
 
-require_once NOALYSS_INCLUDE.'/class/tag.class.php';
-$tag=new Tag($cn);
+require_once NOALYSS_INCLUDE.'/class/tag_action.class.php';
+require_once NOALYSS_INCLUDE.'/class/tag_operation.class.php';
 
-$response=  $tag->select_search($_GET['pref']);
+try {
+    $caller_obj=$http->request("caller_obj");
+    $prefix=$http->request("pref");
+} catch (Exception $ex) {
+    echo $ex->getMessage();
+    return;
+}
+
+if ( $caller_obj == 'Tag_Action' ) { 
+    $tag=new Tag_Action($cn);
+}elseif ($caller_obj=='Tag_Operation')
+{
+    $tag=new Tag_Operation( $cn);
+} else {
+    throw new Exception("AJD001 invalid caller [$caller_obj]");
+}
+
+$response=  $tag->select_search($pref);
 
 $html=escape_xml($response);
 header('Content-type: text/xml; charset=UTF-8');
diff --git a/include/ajax/ajax_search_filter.php 
b/include/ajax/ajax_search_filter.php
index 7f6a8ea..c27458f 100644
--- a/include/ajax/ajax_search_filter.php
+++ b/include/ajax/ajax_search_filter.php
@@ -24,6 +24,7 @@ if (!defined('ALLOWED'))
 
 require NOALYSS_INCLUDE.'/database/user_filter_sql.class.php';
 require NOALYSS_INCLUDE.'/class/acc_ledger_search.class.php';
+require_once NOALYSS_INCLUDE.'/class/tag_operation.class.php';
 $cn=Dossier::connect();
 $dossier_id=Dossier::id();
 global $g_user;
@@ -55,12 +56,19 @@ if ($op=='save_filter')
         $new->setp("amount_max", $http->post("amount_max", 'number', NULL));
         $new->setp("qcode", $http->post("qcode", 'string', NULL));
         $new->setp("accounting", $http->post("accounting", 'string', NULL));
+        $new->setp("uf_tag_option",$http->post("tag_option","string",null));
         $new->setp("date_paid_start",
                 $http->post("date_paid_start", 'string', NULL));
         $new->setp("date_paid_end", $http->post("date_paid_end", 'string', 
NULL));
         $new->setp("ledger_type", $http->post("ledger_type", 'string'));
         $new->setp("operation_filter", $http->post("operation_filter", 
'string', NULL));
         $new->setp("filter_name", h($http->post("filter_name", 'string')));
+        $tag=$http->post("tag","string",'');
+        
+        if (is_array($tag) ) 
+            $new->setp("uf_tag",join(',',$tag));
+        else
+            $new->setp("uf_tag",null);
         $aJrn=[];
         $max=$http->post("nb_jrn");
         for ($i=0; $i<$max; $i++)
@@ -75,11 +83,11 @@ if ($op=='save_filter')
         $new->save();
         $rmAction=sprintf("delete_filter('%s','%s','%s')",  
trim($http->post('div')), $dossier_id,
                 $new->getp('id'));
-        $answer['filter_name']=sprintf('<a class="tinybutton" 
style="display:inline" id="" onclick="'.$rmAction.'">'.SMALLX.'</a>'
-        );
-        $answer['filter_name'].=sprintf("<a style=\"display:inline\" 
onclick=\"load_filter('%s','%s','%s')\">%s</a>",
+        $answer['filter_name']="";
+        $answer['filter_name'].=sprintf("<a class=\"line\" 
style=\"display:inline;text-decoration:underline\" 
onclick=\"load_filter('%s','%s','%s')\">%s</a>",
                 trim($http->post('div')), $dossier_id, $new->getp('id'),
                 $new->getp("filter_name"));
+        $answer['filter_name'].='<span id="'.uniqid().'" 
onclick="'.$rmAction.'" class="icon" 
style="display:inline;margin-left:2em">&#xe80f;</span>';; 
         $answer['filter_id']=$new->getp("id");
         $answer['status']='OK';
     }
@@ -108,7 +116,8 @@ if ($op=="load_filter")
 
     $record['desc']=$record['description'];
     $record['r_jrn']=explode(",", $record['r_jrn']);
-
+    $record['tag']=explode(",",$record['uf_tag']);
+    $record['tag_option']=$record["uf_tag_option"];
     $result=array_merge($answer, $record);
 
 
@@ -148,7 +157,7 @@ if ($op=="display_search_filter")
     echo "</li>";
     
     echo "<li>";
-    echo HtmlInput::anchor(_("Remise à zéro"), "", 
"onclick=\"reset_filter('$p_div');removeDiv('boxfilter{$p_div}')\"");
+    echo HtmlInput::anchor(_("Remise à zéro"), "", 
"style=\"text-decoration:underline\" 
onclick=\"reset_filter('$p_div');removeDiv('boxfilter{$p_div}')\"");
     echo "</li>";
     
     // Link reset
@@ -157,12 +166,11 @@ if ($op=="display_search_filter")
         printf(' <li id="manageli%s_%d">', $p_div, $result[$i]["id"]);
         $rmAction=sprintf("delete_filter('%s','%s','%s')", $p_div, $dossier_id,
                 $result[$i]['id']);
-        printf('<a class="tinybutton" style="display:inline" id="" 
onclick="'.$rmAction.'">'.SMALLX.'</a>'
-        );
-        printf("<a style=\"display:inline\" 
onclick=\"load_filter('%s','%s','%s');removeDiv('boxfilter%s')\">",
+        printf("<a href=\"javascript:void(0)\" 
style=\"display:inline;text-decoration:underline\"  
onclick=\"load_filter('%s','%s','%s');removeDiv('boxfilter%s')\">",
                 $p_div, $dossier_id, $result[$i]["id"],$p_div);
         echo $result[$i]["filter_name"];
         echo '</a>';
+        echo '<span id="'.uniqid().'" onclick="'.$rmAction.'" class="icon" 
style="display:inline;margin-left:2em">&#xe80f;</span>';
 
         printf("</li>");
     }
@@ -198,4 +206,22 @@ if ($op=="delete_search_operation")
     header('Content-Type: application/json;charset=utf-8');
     echo json_encode($answer);
     return;
+}
+//---------------------------------------------------------------------------------------------------------------
+// display_filter_tag : transform uf_tag into a list of tag , and display 
those tags in cells
+//----------------------------------------------------------------------------------------------------------------
+if ($op=='display_filter_tag')
+{
+    $tag=$http->request("uf_tag");
+    $div=$http->request("div");
+    $aTag=explode(',', $tag);
+    if (is_array($aTag))
+    {
+        $nb_tag=count($aTag);
+        for ($j=0; $j<$nb_tag; $j++)
+        {
+            $tag_operation=new Tag_Operation($cn, $aTag[$j]);
+            $tag_operation->update_search_cell($div);
+        }
+    }
 }
\ No newline at end of file
diff --git a/include/ajax/ajax_tag_list.php b/include/ajax/ajax_tag_list.php
index 5ce78c4..794b21a 100644
--- a/include/ajax/ajax_tag_list.php
+++ b/include/ajax/ajax_tag_list.php
@@ -23,9 +23,9 @@
    */
 if ( !defined ('ALLOWED') )  die('Appel direct ne sont pas permis');
 
-require_once NOALYSS_INCLUDE.'/class/tag.class.php';
+require_once NOALYSS_INCLUDE.'/class/tag_action.class.php';
 ob_start();
-$tag=new Tag($cn);
+$tag=new Tag_Action($cn);
 $tag->select();
 
 //------------------- Propose to add a tag
@@ -35,8 +35,12 @@ if ( $g_user->check_action(TAGADD) == 1) { echo 
HtmlInput::button("tag_add", _("
 echo HtmlInput::button_close("tag_div");
 
 $response=  ob_get_clean();
+if (headers_sent() && DEBUG ){
+    echo $response;
+} else {
+    header('Content-type: text/xml; charset=UTF-8');
+}
 $html=escape_xml($response);
-header('Content-type: text/xml; charset=UTF-8');
 echo <<<EOF
 <?xml version="1.0" encoding="UTF-8"?>
 <data>
diff --git a/include/ajax/ajax_tag_select_search.php 
b/include/ajax/ajax_tag_select_search.php
index f5f9462..f103a4f 100644
--- a/include/ajax/ajax_tag_select_search.php
+++ b/include/ajax/ajax_tag_select_search.php
@@ -23,9 +23,9 @@ if ( !defined ('ALLOWED') )  die('Appel direct ne sont pas 
permis');
  *@brief Show the tags to select
  *@see Tag
  */
-require_once NOALYSS_INCLUDE.'/class/tag.class.php';
+require_once NOALYSS_INCLUDE.'/class/tag_action.class.php';
 ob_start();
-$tag=new Tag($cn);
+$tag=new Tag_Action($cn);
 $tag->select_search();
 
 $response=  ob_get_clean();
diff --git a/include/class/acc_ledger_search.class.php 
b/include/class/acc_ledger_search.class.php
index 801e98b..4989f61 100644
--- a/include/class/acc_ledger_search.class.php
+++ b/include/class/acc_ledger_search.class.php
@@ -21,6 +21,8 @@
 
 // if (!defined('ALLOWED'))     die('Appel direct ne sont pas permis');
 
+require_once NOALYSS_INCLUDE."/class/tag_operation.class.php";
+
 /**
  * @file
  * @brief search in ledger
@@ -455,6 +457,7 @@ class Acc_Ledger_Search
         $fil_paid='';
         $fil_date_paid='';
         $fil_hide_operation='';
+        $fil_tag='';
 
         $and='';
         $g_user=new User($this->cn);
@@ -500,7 +503,27 @@ class Acc_Ledger_Search
                 $and='';
             }
         }
-
+        //----
+        // Search tags
+        if ( isset($p_array[$op."tag"] ))
+        {
+            $strTag=join(",", $p_array[$op."tag"]);
+            if ($p_array[$op."tag_option"] == 1){
+                // any tag
+                $fil_tag=$and.' jr_id in (select jrn_id from operation_tag 
where tag_id in ('.sql_string($strTag).')) ';
+            } else {
+                // all tags
+                $aTag=$p_array[$op."tag"];
+                $sub_tag=""; $nb_tag=count($aTag);
+                $and2='';
+                for ($x=0;$x < $nb_tag;$x++) {
+                    $sub_tag = " tag_id = ".sql_string($aTag[$x]);
+                    $fil_tag=$and.' jr_id in (select jrn_id from operation_tag 
where '.$sub_tag.')' ;
+                    $and=" and ";
+                }
+            }
+            $and=" and ";
+        }
         /* format the number */
         $amount_min=abs(toNumber($amount_min));
         $amount_max=abs(toNumber($amount_max));
@@ -620,7 +643,7 @@ class Acc_Ledger_Search
                     " and uj_priv in ('R','W'))";
         }
         
$where=$fil_ledger.$fil_amount.$fil_date.$fil_desc.$fil_sec.$fil_amount.
-            
$fil_qcode.$fil_paid.$fil_account.$fil_date_paid.$fil_hide_operation;
+            
$fil_qcode.$fil_paid.$fil_account.$fil_date_paid.$fil_hide_operation.$fil_tag;
         $sql.=" where ".$where;
         
         // Q?? Why do we return where if it is included in SQL ?
diff --git a/include/class/follow_up.class.php 
b/include/class/follow_up.class.php
index e674ee1..f8c5929 100644
--- a/include/class/follow_up.class.php
+++ b/include/class/follow_up.class.php
@@ -42,6 +42,7 @@ require_once 
NOALYSS_INCLUDE.'/class/document_option.class.php';
 require_once NOALYSS_INCLUDE.'/class/default_menu.class.php';
 require_once NOALYSS_INCLUDE.'/lib/inplace_edit.class.php';
 require_once NOALYSS_INCLUDE.'/lib/noalyss_csv.class.php';
+require_once NOALYSS_INCLUDE.'/class/tag_action.class.php';
 
 /**
  * \file
diff --git a/include/class/tag.class.php b/include/class/tag.class.php
index aacd777..5672adf 100644
--- a/include/class/tag.class.php
+++ b/include/class/tag.class.php
@@ -38,7 +38,7 @@ class Tag
         return $this;
     }
 
-        /**
+    /**
      * Show the list of available tag
      * @return HTML
      */
@@ -48,19 +48,7 @@ class Tag
         if ( $this->cn->count($ret) == 0) return "";
         require_once NOALYSS_TEMPLATE.'/tag_list.php';
     }
-    /**
-     * let select a tag to add
-     */
-    function select()
-    {
-        $ret=$this->data->seek("where t_actif='Y' order by t_tag");
-        $ret=$this->cn->exec_sql(" select t_id,t_tag,t_description,'t' as 
tag_type ,t_color
-                    from tags 
-                    where t_actif='Y' 
-                union all 
-                select tg_id,tg_name ,'G','g' ,1 from tag_group order by 2");
-        require_once NOALYSS_TEMPLATE.'/tag_select.php';
-    }
+    
     /**
      * Display a inner window with the detail of a tag
      */
@@ -93,43 +81,17 @@ class Tag
         $this->data->t_id=$p_array['t_id'];
         $this->data->delete();
     }
-    /**
-     * Show a button to select tag for Search
-     * @return HTML
+    /***
+     * query the active tag and returns the database handler
      */
-    static  function button_search($p_prefix)
-    {
-        $r="";
-        $r.=HtmlInput::button("choose_tag", _("Etiquette"), 
'onclick="search_display_tag('.Dossier::id().',\''.$p_prefix.'\')"', 
"smallbutton");
-        return $r;
-    }
-    /**
-     * let select a tag to add to the search
-     */
-    function select_search($p_prefix)
-    {
-        $res="";
-        $ret=$this->data->seek(' order by t_tag');
-        require_once NOALYSS_TEMPLATE.'/tag_search_select.php';
-        return HtmlInput::title_box('Tag', $p_prefix.'tag_div').$res;
-    }
-    /**
-     * In the screen search add this data to the cell
-     */
-    function update_search_cell($p_prefix) {
-        echo '<span id="sp_'.$p_prefix.$this->data->t_id.'" class="tagcell">';
-        echo h($this->data->t_tag);
-        echo HtmlInput::hidden($p_prefix.'tag[]', $this->data->t_id);
-        $js=sprintf("$('sp_".$p_prefix.$this->data->t_id."').remove();");
-        echo Icon_Action::trash(uniqid(), $js);
-        echo '</span>';
-    }
-    /**
-     * clear the search cell
-     */
-    static function add_clear_button($p_prefix) {
-        $clear=HtmlInput::button('clear', 'X', 
'onclick="search_clear_tag('.Dossier::id().',\''.$p_prefix.'\');"', 
'smallbutton');
-        return $clear;
+    function query_active_tag()
+    {  
+        $ret=$this->cn->exec_sql(" select t_id,t_tag,t_description,'t' as 
tag_type ,t_color
+                    from tags 
+                    where t_actif='Y' 
+                union all 
+                select tg_id,tg_name ,'G','g' ,1 from tag_group order by 2");
+        return $ret;
     }
 }
 
diff --git a/include/class/tag_action.class.php 
b/include/class/tag_action.class.php
new file mode 100644
index 0000000..41521d4
--- /dev/null
+++ b/include/class/tag_action.class.php
@@ -0,0 +1,94 @@
+<?php
+
+/*
+ * * Copyright (C) 2020 Dany De Bontridder <dany@alchimerys.be>
+ *
+ * This program 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
+ * 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
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+ * 
+ * Author : Dany De Bontridder danydb@noalyss.eu
+ * 
+ */
+
+require_once NOALYSS_INCLUDE.'/class/tag.class.php';
+
+/**
+ * @file
+ * @brief  concerns the tags linked to an action
+ */
+class Tag_Action extends Tag
+{
+    function __construct($p_cn, $p_id=-1 )
+    {
+        parent::__construct($p_cn, $p_id);
+    }
+
+    /**
+     * let select a tag to add
+     */
+    function select($p_prefix="")
+    {
+        $ret=parent::query_active_tag();
+        require_once NOALYSS_TEMPLATE.'/tag_select.php';
+    }
+
+    /**
+     * Show a button to select tag for Search
+     * @return HTML
+     */
+    static function select_tag_search($p_prefix)
+    {
+        $r="";
+        $r.=HtmlInput::button("choose_tag", _("Etiquette"),
+                        
'onclick="search_display_tag('.Dossier::id().',\''.$p_prefix.'\',\'Tag_Action\')"',
 "smallbutton");
+        return $r;
+    }
+
+    /**
+     * clear the search cell
+     */
+    static function add_clear_button($p_prefix)
+    {
+        $clear=HtmlInput::button('clear', 'X', 
'onclick="search_clear_tag('.Dossier::id().',\''.$p_prefix.'\');"',
+                        'smallbutton');
+        return $clear;
+    }
+
+    /**
+     * In the screen search add this data to the cell
+     */
+    function update_search_cell($p_prefix)
+    {
+        $data=$this->get_data();
+        echo '<span id="sp_'.$p_prefix.$data->t_id.'" class="tagcell">';
+        echo h($data->t_tag);
+        echo HtmlInput::hidden($p_prefix.'tag[]', $data->t_id);
+        $js=sprintf("$('sp_".$p_prefix.$data->t_id."').remove();");
+        echo Icon_Action::trash(uniqid(), $js);
+        echo '</span>';
+    }
+
+    /**
+     * let select a tag to add to the search
+     */
+    function select_search($p_prefix)
+    {
+        $res="";
+        $ret=$this->get_data()->seek(' order by t_tag');
+        require_once NOALYSS_TEMPLATE.'/tag_search_select.php';
+        return HtmlInput::title_box('Tag', $p_prefix.'tag_div').$res;
+    }
+
+}
diff --git a/include/class/tag_operation.class.php 
b/include/class/tag_operation.class.php
new file mode 100644
index 0000000..af89bd9
--- /dev/null
+++ b/include/class/tag_operation.class.php
@@ -0,0 +1,199 @@
+<?php
+
+/*
+ *   This file is part of NOALYSS.
+ *
+ *   PhpCompta 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 of the License, or
+ *   (at your option) any later version.
+ *
+ *   PhpCompta 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 PhpCompta; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+// Copyright (2002-2020) Author Dany De Bontridder <danydb@noalyss.eu>
+
+if (!defined('ALLOWED'))
+    die('Appel direct ne sont pas permis');
+
+/**
+ * @file
+ * @brief   concerns the tags linked to an accountancy writing
+ */
+class Tag_Operation extends Tag
+{
+
+    private $jrn_id=-1;
+
+    function __construct($p_cn, $p_id=-1)
+    {
+        parent::__construct($p_cn, $p_id);
+    }
+
+    public function get_jrn_id()
+    {
+        return $this->jrn_id;
+    }
+
+    public function set_jrn_id($jrn_id)
+    {
+        $this->jrn_id=$jrn_id;
+        return $this;
+    }
+
+    /**
+     * let select a tag to add
+     */
+    function select($p_prefix="")
+    {
+        $ret=parent::query_active_tag();
+        require_once NOALYSS_TEMPLATE.'/tag_select.php';
+    }
+
+    /**
+     * Show a button to select tag for Search
+     * @param $p_jr jr_id of the operation
+     * @param $p_div prefix of the dialog box
+     * @return HTML
+     */
+    static function button_search($p_jr, $p_div)
+    {
+        $r="";
+        $js=sprintf("onclick=\"new operation_tag('%s').select('%s','%s')\"", 
$p_div, dossier::id(), $p_jr);
+        $r.=HtmlInput::button('tag_bt', _('Ajout étiquette'), $js, 
'smallbutton');
+        return $r;
+    }
+
+    /**
+     * clear the search cell
+     */
+    static function add_clear_button($p_prefix)
+    {
+        $clear=HtmlInput::button('clear', 'X', 
'onclick="search_clear_tag('.Dossier::id().',\''.$p_prefix.'\');"',
+                        'smallbutton');
+        return $clear;
+    }
+
+    /**
+     * In the screen search add this data to the cell
+     */
+    function update_search_cell($p_prefix)
+    {
+        $data=$this->get_data();
+        echo '<span id="sp_'.$p_prefix.$data->t_id.'" class="tagcell">';
+        echo h($data->t_tag);
+        echo HtmlInput::hidden($p_prefix.'tag[]', $data->t_id);
+        $js=sprintf("$('sp_".$p_prefix.$data->t_id."').remove();");
+        echo Icon_Action::trash(uniqid(), $js);
+        echo '</span>';
+    }
+
+    /**
+     * Links a tag to an operation
+     * @param int $p_tag_id tag.t_id 
+     */
+    function tag_add($p_tag_id)
+    {
+        if ($this->jrn_id==-1)
+        {
+            throw new Exception("TO99 jrn_id unset");
+        }
+        $count=$this->cn->get_value('select count(*) from operation_tag'.
+                ' where jrn_id=$1 and tag_id=$2', array($this->jrn_id, 
$p_tag_id));
+        if ($count>0)
+            return;
+        $sql=' insert into operation_tag (jrn_id,tag_id) values ($1,$2)';
+        $this->cn->exec_sql($sql, array($this->jrn_id, $p_tag_id));
+    }
+
+    /**
+     * @brief show the cell content in Display for the tags
+     * @param $div prefix of the DOM id 
+     * called also by ajax
+     */
+    function tag_cell($p_div)
+    {
+        global $g_user;
+        $a_tag=$this->tag_get();
+        $c=count($a_tag);
+        $ledger=$this->cn->get_value("select jr_def_id from jrn where 
jr_id=$1", [$this->jrn_id]);
+        $access=$g_user->get_ledger_access($ledger);
+        for ($e=0; $e<$c; $e++)
+        {
+            echo '<span class="tagcell 
tagcell-color'.$a_tag[$e]['t_color'].'">';
+            echo $a_tag[$e]['t_tag'];
+            if ($access=='W')
+            {
+                $js_remove=sprintf("new 
operation_tag('%s').remove('%s','%s','%s')", $p_div, dossier::id(),
+                        $this->jrn_id, $a_tag[$e]['t_id']);
+                echo Icon_Action::trash(uniqid(), $js_remove);
+            }
+            echo '</span>';
+            echo '&nbsp;';
+            echo '&nbsp;';
+        }
+    }
+
+    /**
+     * @brief get the tags of the current objet
+     * @return an array idx [ag_id,t_id,at_id,t_tag]
+     */
+    function tag_get()
+    {
+        if ($this->jrn_id==-1)
+        {
+            throw new Exception("TO01 jrn_id unset");
+        }
+        $sql='select b.jrn_id,a.t_id,a.t_id,a.t_tag,a.t_color'
+                .' from '
+                .' tags as a join operation_tag as b on (a.t_id=b.tag_id)'
+                .' where jrn_id=$1 '
+                .' order by a.t_tag';
+        $array=$this->cn->get_array($sql, array($this->jrn_id));
+        return $array;
+    }
+
+    /**
+     * Remove a tag 
+     * @param int  $p_tag_id tag id
+     */
+    function tag_remove($p_tag_id)
+    {
+        if ($this->jrn_id==-1)
+        {
+            throw new Exception("TO01 jrn_id unset");
+        }
+        $this->cn->exec_sql("delete from operation_tag where jrn_id=$1 and 
tag_id=$2", [$this->jrn_id, $p_tag_id]);
+    }
+
+    /**
+     * let select a tag to add to the search
+     */
+    function select_search($p_prefix)
+    {
+        $res="";
+        $ret=$this->get_data()->seek(' order by t_tag');
+        require_once NOALYSS_TEMPLATE.'/tag_search_select.php';
+        return HtmlInput::title_box('Tag', $p_prefix.'tag_div').$res;
+    }
+    /**
+     * Show a button to select tag for Search
+     * @return HTML
+     */
+    static function select_tag_search($p_prefix)
+    {
+        $r="";
+        $r.=HtmlInput::button("choose_tag", _("Etiquette"),
+                        
'onclick="search_display_tag('.Dossier::id().',\''.$p_prefix.'\',\'Tag_Operation\')"',
 "smallbutton");
+        return $r;
+    }
+
+}
+
+?>
\ No newline at end of file
diff --git a/include/constant.php b/include/constant.php
index 7d08aea..92046e5 100644
--- a/include/constant.php
+++ b/include/constant.php
@@ -107,7 +107,7 @@ if ( !defined ("NOALYSS_PACKAGE_REPOSITORY")) {
 if ( ! defined ("SYSINFO_DISPLAY")) {
     define ("SYSINFO_DISPLAY",TRUE);
 }
-define ("DBVERSION",150);
+define ("DBVERSION",151);
 define ("MONO_DATABASE",25);
 define ("DBVERSIONREPO",18);
 define ('NOTFOUND','--not found--');
diff --git a/include/database/user_filter_sql.class.php 
b/include/database/user_filter_sql.class.php
index 72ebb83..55b59be 100644
--- a/include/database/user_filter_sql.class.php
+++ b/include/database/user_filter_sql.class.php
@@ -56,6 +56,9 @@ class User_filter_SQL extends Noalyss_SQL
             , "all_ledger"=>"all_ledger"
             ,"operation_filter"=>"operation_filter"
             ,'filter_name'=>"filter_name"
+            ,'uf_tag'=>'uf_tag'
+            ,'uf_tag_option'=>'uf_tag_option'
+            
         );
         /*
          * Type of columns
@@ -78,6 +81,8 @@ class User_filter_SQL extends Noalyss_SQL
             , "all_ledger"=>"numeric"
             ,"operation_filter"=>"text"
             ,"filter_name"=>"text"
+            ,'uf_tag'=>'text'
+            ,'uf_tag_option'=>'numeric'
         );
 
 
diff --git a/include/history_operation.inc.php 
b/include/history_operation.inc.php
index 5e7aac3..d61658e 100644
--- a/include/history_operation.inc.php
+++ b/include/history_operation.inc.php
@@ -175,17 +175,28 @@ echo '</form>';
  */
 $r = HtmlInput::get_to_hidden(array('l', 'date_paid_start','date_paid_end',
                                    'date_start', 'date_end', 'desc', 
'amount_min', 'amount_max', 'qcode','operation_filter',
-                                   'accounting', 'unpaid', 'gDossier', 
'ledger_type', 'p_action'));
+                                   'accounting', 'unpaid', 'gDossier', 
'ledger_type', 'p_action','search_optag_option'));
 if (isset($_GET['search_opr_jrn']))
 {
     foreach ($a_search_opr_jrn as $k => $v)
        if (isNumber($v))  $r.=HtmlInput::hidden('r_jrn[' . $k . ']', $v);
 }
+$r.=HtmlInput::hidden("tag_option",$http->request("search_optag_option","string",0));
 if (isset($_GET['r_jrn']))
 {
        foreach ($a_rjn as $k => $v)
        if (isNumber($v))       $r.=HtmlInput::hidden('r_jrn[' . $k . ']', $v);
 }
+if (isset($_GET['search_optag'])) {
+    $http=new HttpInput();
+    $aTag=$http->get("search_optag","array");
+  foreach ($aTag as $k=>$v) {
+      // Protect : check that $k and $v are numeric
+    if (isNumber($k)&&isNumber($v)) {
+        $r.=HtmlInput::hidden('tag[]',$v);
+    }
+  }
+}
 echo '<form action="export.php" method="get">';
 echo $r;
 echo HtmlInput::hidden('act', 'CSV:histo');
diff --git a/include/sql/patch/upgrade150.sql b/include/sql/patch/upgrade150.sql
new file mode 100644
index 0000000..b3a879b
--- /dev/null
+++ b/include/sql/patch/upgrade150.sql
@@ -0,0 +1,15 @@
+begin;
+alter table tags add column t_color int;
+alter table tags alter t_color set default 1;
+update tags set t_color=1;
+create table operation_tag (opt_id bigserial primary key, jrn_id bigint , 
tag_id int);
+alter table operation_tag add constraint opt_jrnx foreign key   (jrn_id)  
references jrn (jr_id) on update cascade on delete cascade;
+alter table operation_tag add constraint opt_tag_id foreign key   (tag_id)  
references tags (t_id) on update cascade on delete cascade;
+comment on table operation_tag is 'Tag attached to an operation';
+ALTER TABLE public.user_filter ADD uf_tag text ;
+alter table user_filter add uf_tag_option int;
+
+COMMENT ON COLUMN public.user_filter.uf_tag IS 'Tag list';
+COMMENT ON COLUMN public.user_filter.uf_tag_option IS '0 : all tags must be 
present, 1: at least one';
+insert into version (val,v_description) values (151,'Tag with color and 
operation');
+commit;
diff --git a/include/template/action_other_action.php 
b/include/template/action_other_action.php
index 4759467..19d5104 100644
--- a/include/template/action_other_action.php
+++ b/include/template/action_other_action.php
@@ -33,16 +33,16 @@ echo 
HtmlInput::request_to_hidden(array("closed_action","remind_date_end","remin
         <li>
             <?php $radio->value="ETIADD";echo $radio->input(); ?>
             <?php echo _("Ajout d'étiquettes");?>
-            <?php echo Tag::button_search('add'); ?>
-            <?php echo Tag::add_clear_button('add'); ?>
+            <?php echo Tag_Action::select_tag_search('add'); ?>
+            <?php echo Tag_Action::add_clear_button('add'); ?>
                                <span id="addtag_choose_td">
                                 </span>
         </li>
         <li>
             <?php $radio->value="ETIREM";echo $radio->input(); ?>
             <?php echo _("Enlever des étiquettes");?>
-            <?php echo Tag::button_search('rem'); ?>
-            <?php echo Tag::add_clear_button('rem'); ?>
+            <?php echo Tag_Action::select_tag_search('rem'); ?>
+            <?php echo Tag_Action::add_clear_button('rem'); ?>
                                <span id="remtag_choose_td">
                                 </span>
         </li>
diff --git a/include/template/action_search.php 
b/include/template/action_search.php
index 20f3a43..00d11ec 100644
--- a/include/template/action_search.php
+++ b/include/template/action_search.php
@@ -129,14 +129,14 @@
             <p>
                 <?php echo _('Etiquette'); ?>
                <span id="searchtag_choose_td">
-                   <?php echo Tag::button_search('search'); ?>
+                   <?php echo Tag_Action::select_tag_search('search'); ?>
                    <?php
                        if ( isset($_GET['searchtag'])) {
                            $http=new HttpInput();
-                           echo Tag::add_clear_button('search');
+                           echo Tag_Action::add_clear_button('search');
                            $asearchtag= 
$http->get("searchtag","array",array());
                            for ($i=0;$i<count($asearchtag);$i++) {
-                               $t=new Tag($cn, $asearchtag[$i]);
+                               $t=new Tag_Action($cn, $asearchtag[$i]);
                                echo $t->update_search_cell('search');
                            }
                        }
diff --git a/include/template/detail-action.php 
b/include/template/detail-action.php
index 821cb62..d930f53 100644
--- a/include/template/detail-action.php
+++ b/include/template/detail-action.php
@@ -160,7 +160,7 @@ $uniq=uniqid("tab",TRUE);
                 Dossier / Etiquette
             </TD>
             
-            <td id="action_tag_td">
+            <td id="action_tag_td" style="max-width:35rem">
                 <?php
                    $this->tag_cell($p_view);
                 ?>
diff --git a/include/template/ledger_detail_bottom.php 
b/include/template/ledger_detail_bottom.php
index f62975a..3675ad2 100644
--- a/include/template/ledger_detail_bottom.php
+++ b/include/template/ledger_detail_bottom.php
@@ -44,6 +44,7 @@ 
$a_tab['linked_operation_div']=array('id'=>'linked_operation_div'.$div,'label'=>
 
$a_tab['document_operation_div']=array('id'=>'document_operation_div'.$div,'label'=>_('Document').'('.$nb_document.')','display'=>'block');
 
$a_tab['linked_action_div']=array('id'=>'linked_action_div'.$div,'label'=>_('Actions
 Gestion').'('.count($a_followup).')','display'=>'none');
 
$a_tab['analytic_div']=array('id'=>'analytic_div'.$div,'label'=>_('Comptabilité 
Analytique'),'display'=>'none');
+$a_tab['tag_operation_div']=array('id'=>'tag_operation_div'.$div,'label'=>_('Etiquette'),'display'=>'none');
 
  
 // show tabs
@@ -308,7 +309,23 @@ require_once NOALYSS_TEMPLATE.'/ledger_detail_file.php';
     </span>
 <?php endif;?>
 </div>
-
+<div id="tag_operation_div<?=$div?>" style="overflow:auto;display:<?php echo 
$a_tab['tag_operation_div']['display']?>"> 
+    <div id="operation_tag_td<?=$div?>">
+    <?php
+    
/******************************************************************************************************************
+     * Tags on operation
+     
*****************************************************************************************************************/
+    $tag_operation=new Tag_Operation($cn);
+    $tag_operation->set_jrn_id($obj->det->jr_id);
+    $tag_operation->tag_cell($div);
+    ?>
+    
+    </div>
+    <?php
+    // Button add tags
+         if ( $access=='W') { echo 
Tag_Operation::button_search($obj->det->jr_id,$div);}
+    ?>
+</div>
 <hr>
 <?php 
       echo '<p style="text-align:center">';
diff --git a/include/template/ledger_search.php 
b/include/template/ledger_search.php
index a6a1e00..7461998 100644
--- a/include/template/ledger_search.php
+++ b/include/template/ledger_search.php
@@ -87,5 +87,40 @@ echo $f_accounting->input();  ?>
 <?php echo $f_paid->input();  ?>
 </td>
 </tr>
-
+<tr>
+    
+<td  style="text-align:right;width:30em">
+    
+        <?php
+         $iselect= new ISelect($this->div."tag_option");
+                $iselect->value=array(
+                    array("value"=>0,"label"=>_("Toutes les étiquettes")),
+                    array("value"=>1,"label"=>_("Au moins une étiquette"))
+                    );
+                
+                
$iselect->set_value($http->request($this->div."tag_option","number",0));
+                echo $iselect->input(); 
+               
+        ?>
+        <?php
+        echo Tag_Operation::select_tag_search($this->div);
+        ?>
+</td>
+    <td >
+        <span id="<?=$this->div?>tag_choose_td">
+            <?php 
+            $aTag= $http->request($this->div."tag","string",0);
+                if (is_array($aTag) ) {
+                    $nb_tag=count($aTag);
+                    for ($j=0;$j< $nb_tag;$j++) {
+                        $tag_operation=new Tag_Operation($this->cn,$aTag[$j]);
+                        $tag_operation->update_search_cell($this->div);
+                    }
+                }
+            ?>
+        
+        </span>
+    </td>
+</tr>
+    
 </table>
diff --git a/include/template/tag_select.php b/include/template/tag_select.php
index 59732c3..4263df1 100644
--- a/include/template/tag_select.php
+++ b/include/template/tag_select.php
@@ -27,15 +27,28 @@ if ( $max == 0 ) {
     </tr>
 <?php
 $gDossier=Dossier::id();
-$ag_id=$http->request("ag_id","number");
-if (isNumber($ag_id) == 0 ) die ('ERROR : parameters invalid');
+$id="none";
+
+if ( get_class($this) == 'Tag_Action' ) {
+    $id=$http->request("ag_id","number");
+ } elseif (get_class($this)=='Tag_Operation')
+{
+     $id=$http->request("jrn_id");
+}
+
+if (isNumber($id) == 0 ) die ('ERROR : parameters invalid');
     for ($i=0;$i<$max;$i++):
         $row=Database::fetch_array($ret, $i);
 ?>
     <tr class="<?php echo (($i%2==0)?'even':'odd');?>">
         <td class="tagcell-color<?=$row['t_color']?>">
             <?php
-            
$js=sprintf("action_tag_add('%s','%s','%s','%s')",$gDossier,$ag_id,$row['t_id'],$row['tag_type']);
+            if ( get_class($this) == 'Tag_Action' ) {
+                
$js=sprintf("action_tag_add('%s','%s','%s','%s')",$gDossier,$id,$row['t_id'],$row['tag_type']);
+            } else {
+                $js=sprintf("new 
operation_tag('%s').add('%s','%s','%s','%s')",$p_prefix,$gDossier,$id,$row['t_id'],$row['tag_type']);
+            }
+            
             echo HtmlInput::anchor($row['t_tag'], "", "onclick=\"$js\"");
             ?>
         </td>



reply via email to

[Prev in Thread] Current Thread [Next in Thread]