Merge branch '2016.11' into 2016.11-develop
[tine20] / tine20 / Timetracker / js / TimesheetGridPanel.js
1 /*
2  * Tine 2.0
3  * 
4  * @package     Timetracker
5  * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
6  * @author      Philipp Schüle <p.schuele@metaways.de>
7  * @copyright   Copyright (c) 2007-2016 Metaways Infosystems GmbH (http://www.metaways.de)
8  *
9  */
10  
11 Ext.namespace('Tine.Timetracker');
12
13 /**
14  * Timesheet grid panel
15  * 
16  * @namespace   Tine.Timetracker
17  * @class       Tine.Timetracker.TimesheetGridPanel
18  * @extends     Tine.widgets.grid.GridPanel
19  * 
20  * <p>Timesheet Grid Panel</p>
21  * <p><pre>
22  * </pre></p>
23  * 
24  * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
25  * @author      Philipp Schüle <p.schuele@metaways.de>
26  * 
27  * @param       {Object} config
28  * @constructor
29  * Create a new Tine.Timetracker.TimesheetGridPanel
30  */
31 Tine.Timetracker.TimesheetGridPanel = Ext.extend(Tine.widgets.grid.GridPanel, {
32
33     /**
34      * activates copy action
35      */
36     copyEditAction: true,
37
38     /**
39      * only allow multi edit with manage_timeaccounts right (because of timeaccount handling in edit dlg)
40      */
41     multipleEditRequiredRight: 'manage_timeaccounts',
42
43     initComponent: function() {
44         this.defaultFilters = [
45             {field: 'start_date', operator: 'within', value: 'weekThis'},
46             {field: 'account_id', operator: 'equals', value: Tine.Tinebase.registry.get('currentAccount')}
47         ];
48
49         this.initDetailsPanel();
50         
51         // only eval grants in action updater if user does not have the right to manage timeaccounts
52         this.evalGrants = ! Tine.Tinebase.common.hasRight('manage', 'Timetracker', 'timeaccounts');
53         
54         Tine.Timetracker.TimesheetGridPanel.superclass.initComponent.call(this);
55     },
56
57     /**
58      * @private
59      */
60     initDetailsPanel: function() {
61         this.detailsPanel = new Tine.widgets.grid.DetailsPanel({
62             gridpanel: this,
63             
64             // use default Tpl for default and multi view
65             defaultTpl: new Ext.XTemplate(
66                 '<div class="preview-panel-timesheet-nobreak">',
67                     '<!-- Preview timeframe -->',           
68                     '<div class="preview-panel preview-panel-timesheet-left">',
69                         '<div class="bordercorner_1"></div>',
70                         '<div class="bordercorner_2"></div>',
71                         '<div class="bordercorner_3"></div>',
72                         '<div class="bordercorner_4"></div>',
73                         '<div class="preview-panel-declaration">' /*+ this.app.i18n._('timeframe')*/ + '</div>',
74                         '<div class="preview-panel-timesheet-leftside preview-panel-left">',
75                             '<span class="preview-panel-bold">',
76                             /*'First Entry'*/'<br/>',
77                             /*'Last Entry*/'<br/>',
78                             /*'Duration*/'<br/>',
79                             '<br/>',
80                             '</span>',
81                         '</div>',
82                         '<div class="preview-panel-timesheet-rightside preview-panel-left">',
83                             '<span class="preview-panel-nonbold">',
84                             '<br/>',
85                             '<br/>',
86                             '<br/>',
87                             '<br/>',
88                             '</span>',
89                         '</div>',
90                     '</div>',
91                     '<!-- Preview summary -->',
92                     '<div class="preview-panel-timesheet-right">',
93                         '<div class="bordercorner_gray_1"></div>',
94                         '<div class="bordercorner_gray_2"></div>',
95                         '<div class="bordercorner_gray_3"></div>',
96                         '<div class="bordercorner_gray_4"></div>',
97                         '<div class="preview-panel-declaration">'/* + this.app.i18n._('summary')*/ + '</div>',
98                         '<div class="preview-panel-timesheet-leftside preview-panel-left">',
99                             '<span class="preview-panel-bold">',
100                             this.app.i18n._('Total Timesheets') + '<br/>',
101                             this.app.i18n._('Billable Timesheets') + '<br/>',
102                             this.app.i18n._('Total Time') + '<br/>',
103                             this.app.i18n._('Time of Billable Timesheets') + '<br/>',
104                             '</span>',
105                         '</div>',
106                         '<div class="preview-panel-timesheet-rightside preview-panel-left">',
107                             '<span class="preview-panel-nonbold">',
108                             '{count}<br/>',
109                             '{countbillable}<br/>',
110                             '{sum}<br/>',
111                             '{sumbillable}<br/>',
112                             '</span>',
113                         '</div>',
114                     '</div>',
115                 '</div>'            
116             ),
117             
118             showDefault: function(body) {
119                 
120                 var data = {
121                     count: this.gridpanel.store.proxy.jsonReader.jsonData.totalcount,
122                     countbillable: (this.gridpanel.store.proxy.jsonReader.jsonData.totalcountbillable) ? this.gridpanel.store.proxy.jsonReader.jsonData.totalcountbillable : 0,
123                     sum:  Tine.Tinebase.common.minutesRenderer(this.gridpanel.store.proxy.jsonReader.jsonData.totalsum),
124                     sumbillable: Tine.Tinebase.common.minutesRenderer(this.gridpanel.store.proxy.jsonReader.jsonData.totalsumbillable)
125                 };
126                 
127                 this.defaultTpl.overwrite(body, data);
128             },
129             
130             showMulti: function(sm, body) {
131                 
132                 var data = {
133                     count: sm.getCount(),
134                     countbillable: 0,
135                     sum: 0,
136                     sumbillable: 0
137                 };
138                 sm.each(function(record){
139                     
140                     data.sum = data.sum + parseInt(record.data.duration);
141                     if (record.data.is_billable_combined == '1') {
142                         data.countbillable++;
143                         data.sumbillable = data.sumbillable + parseInt(record.data.duration);
144                     }
145                 });
146                 data.sum = Tine.Tinebase.common.minutesRenderer(data.sum);
147                 data.sumbillable = Tine.Tinebase.common.minutesRenderer(data.sumbillable);
148                 
149                 this.defaultTpl.overwrite(body, data);
150             },
151             
152             tpl: new Ext.XTemplate(
153                 '<div class="preview-panel-timesheet-nobreak">',    
154                     '<!-- Preview beschreibung -->',
155                     '<div class="preview-panel preview-panel-timesheet-left">',
156                         '<div class="bordercorner_1"></div>',
157                         '<div class="bordercorner_2"></div>',
158                         '<div class="bordercorner_3"></div>',
159                         '<div class="bordercorner_4"></div>',
160                         '<div class="preview-panel-declaration">' /* + this.app.i18n._('Description') */ + '</div>',
161                         '<div class="preview-panel-timesheet-description preview-panel-left" ext:qtip="{[this.encode(values.description)]}">',
162                             '<span class="preview-panel-nonbold">',
163                              '{[this.encode(values.description, "longtext")]}',
164                             '<br/>',
165                             '</span>',
166                         '</div>',
167                     '</div>',
168                     '<!-- Preview detail-->',
169                     '<div class="preview-panel-timesheet-right">',
170                         '<div class="bordercorner_gray_1"></div>',
171                         '<div class="bordercorner_gray_2"></div>',
172                         '<div class="bordercorner_gray_3"></div>',
173                         '<div class="bordercorner_gray_4"></div>',
174                         '<div class="preview-panel-declaration">' /* + this.app.i18n._('Detail') */ + '</div>',
175                         '<div class="preview-panel-timesheet-leftside preview-panel-left">',
176                         // @todo add custom fields here
177                         /*
178                             '<span class="preview-panel-bold">',
179                             'Ansprechpartner<br/>',
180                             'Newsletter<br/>',
181                             'Ticketnummer<br/>',
182                             'Ticketsubjekt<br/>',
183                             '</span>',
184                         */
185                         '</div>',
186                         '<div class="preview-panel-timesheet-rightside preview-panel-left">',
187                             '<span class="preview-panel-nonbold">',
188                             '<br/>',
189                             '<br/>',
190                             '<br/>',
191                             '<br/>',
192                             '</span>',
193                         '</div>',
194                     '</div>',
195                 '</div>',{
196                 encode: function(value, type, prefix) {
197                     if (value) {
198                         if (type) {
199                             switch (type) {
200                                 case 'longtext':
201                                     value = Ext.util.Format.ellipsis(value, 150);
202                                     break;
203                                 default:
204                                     value += type;
205                             }
206                         } else {
207                             value = Ext.util.Format.htmlEncode(value);
208                         }
209                         
210                         var encoded = Ext.util.Format.htmlEncode(value);
211                         encoded = Ext.util.Format.nl2br(encoded);
212                         
213                         return encoded;
214                     } else {
215                         return '';
216                     }
217                 }
218             })
219         });
220     },
221
222     /**
223      * @private
224      */
225     initActions: function() {
226         this.actions_export = new Ext.Action({
227             text: this.app.i18n._('Export Timesheets'),
228             iconCls: 'action_export',
229             scope: this,
230             requiredGrant: 'exportGrant',
231             disabled: true,
232             allowMultiple: true,
233             actionUpdater: this.updateExportAction,
234             menu: {
235                 items: [
236                     new Tine.widgets.grid.ExportButton({
237                         text: this.app.i18n._('Export as ODS'),
238                         format: 'ods',
239                         iconCls: 'tinebase-action-export-ods',
240                         exportFunction: 'Timetracker.exportTimesheets',
241                         gridPanel: this
242                     }),
243                     new Tine.widgets.grid.ExportButton({
244                         text: this.app.i18n._('Export as CSV'),
245                         format: 'csv',
246                         iconCls: 'tinebase-action-export-csv',
247                         exportFunction: 'Timetracker.exportTimesheets',
248                         gridPanel: this
249                     }),
250                     new Tine.widgets.grid.ExportButton({
251                         text: this.app.i18n._('Export as ...'),
252                         iconCls: 'tinebase-action-export-xls',
253                         exportFunction: 'Timetracker.exportTimesheets',
254                         showExportDialog: true,
255                         gridPanel: this
256                     })
257                 ]
258             }
259         });
260         
261         // register actions in updater
262         this.actionUpdater.addActions([
263             this.actions_export
264         ]);
265         
266         Tine.Timetracker.TimesheetGridPanel.superclass.initActions.call(this);
267     },
268
269     /**
270      * check user exportGrant for timeaccounts
271      * NOTE: manage_timeaccounts ALWAYS allows to export
272      *
273      * @param action
274      * @param grants
275      * @param records
276      * @returns {boolean}
277      */
278     updateExportAction: function(action, grants, records) {
279         var exportGrant = true;
280         if (! Tine.Tinebase.common.hasRight('manage', 'Timetracker', 'timeaccounts')) {
281             Ext.each(records, function (record) {
282                 var c = record.get('timeaccount_id').container_id;
283                 if (c.hasOwnProperty('account_grants')) {
284                     if (!c.account_grants.exportGrant) {
285                         exportGrant = false;
286                         return false;
287                     }
288                 }
289             });
290         }
291
292         var disable = ! exportGrant;
293         action.setDisabled(disable);
294         return false;
295     }
296 });