043dd4763857217e56bbf5b97b21c2e9874afb27
[working/Evergreen.git] / Open-ILS / web / js / ui / default / staff / reporter / services / template.js
1 /**
2  * Report templates
3  */
4
5 angular.module('egReportMod', ['egCoreMod', 'ui.bootstrap'])
6 .factory('egReportTemplateSvc',
7
8        ['$uibModal','$q','egCore','egConfirmDialog','egAlertDialog',
9 function($uibModal , $q , egCore , egConfirmDialog , egAlertDialog) {
10
11     //dojo.requireLocalization("openils.reports", "reports");
12     //var egCore.strings = dojo.i18n.getLocalization("openils.reports", "reports");
13
14     var OILS_RPT_DTYPE_ARRAY = 'array';
15     var OILS_RPT_DTYPE_STRING = 'text';
16     var OILS_RPT_DTYPE_MONEY = 'money';
17     var OILS_RPT_DTYPE_BOOL = 'bool';
18     var OILS_RPT_DTYPE_INT = 'int';
19     var OILS_RPT_DTYPE_ID = 'id';
20     var OILS_RPT_DTYPE_OU = 'org_unit';
21     var OILS_RPT_DTYPE_FLOAT = 'float';
22     var OILS_RPT_DTYPE_TIMESTAMP = 'timestamp';
23     var OILS_RPT_DTYPE_INTERVAL = 'interval';
24     var OILS_RPT_DTYPE_LINK = 'link';
25     var OILS_RPT_DTYPE_NONE = '';
26     var OILS_RPT_DTYPE_NULL = null;
27     var OILS_RPT_DTYPE_UNDEF;
28     
29     var OILS_RPT_DTYPE_ALL = [
30         OILS_RPT_DTYPE_STRING,
31         OILS_RPT_DTYPE_MONEY,
32         OILS_RPT_DTYPE_INT,
33         OILS_RPT_DTYPE_ID,
34         OILS_RPT_DTYPE_FLOAT,
35         OILS_RPT_DTYPE_TIMESTAMP,
36         OILS_RPT_DTYPE_BOOL,
37         OILS_RPT_DTYPE_OU,
38         OILS_RPT_DTYPE_NONE,
39         OILS_RPT_DTYPE_NULL,
40         OILS_RPT_DTYPE_UNDEF,
41         OILS_RPT_DTYPE_INTERVAL,
42         OILS_RPT_DTYPE_LINK
43     ];
44     var OILS_RPT_DTYPE_NOT_ID = [OILS_RPT_DTYPE_STRING,OILS_RPT_DTYPE_MONEY,OILS_RPT_DTYPE_INT,OILS_RPT_DTYPE_FLOAT,OILS_RPT_DTYPE_TIMESTAMP];
45     var OILS_RPT_DTYPE_NOT_BOOL = [OILS_RPT_DTYPE_STRING,OILS_RPT_DTYPE_MONEY,OILS_RPT_DTYPE_INT,OILS_RPT_DTYPE_FLOAT,OILS_RPT_DTYPE_TIMESTAMP,OILS_RPT_DTYPE_ID,OILS_RPT_DTYPE_OU,OILS_RPT_DTYPE_LINK];
46
47     var service = {
48         display_fields : [],
49         filter_fields  : [],
50
51         Filters : {
52                 '=' : {
53                         label : egCore.strings.OPERATORS_EQUALS
54                 },
55         
56                 'like' : {
57                         label : egCore.strings.OPERATORS_LIKE
58                 }, 
59         
60                 ilike : {
61                         label : egCore.strings.OPERATORS_ILIKE
62                 },
63         
64                 '>' : {
65                         label : egCore.strings.OPERATORS_GREATER_THAN,
66                         labels : { timestamp : egCore.strings.OPERATORS_GT_TIME }
67                 },
68         
69                 '>=' : {
70                         label : egCore.strings.OPERATORS_GT_EQUAL,
71                         labels : { timestamp : egCore.strings.OPERATORS_GTE_TIME }
72                 }, 
73         
74         
75                 '<' : {
76                         label : egCore.strings.OPERATORS_LESS_THAN,
77                         labels : { timestamp : egCore.strings.OPERATORS_LT_TIME }
78                 }, 
79         
80                 '<=' : {
81                         label : egCore.strings.OPERATORS_LT_EQUAL, 
82                         labels : { timestamp : egCore.strings.OPERATORS_LTE_TIME }
83                 },
84         
85                 'in' : {
86                         label : egCore.strings.OPERATORS_IN_LIST
87                 },
88         
89                 'not in' : {
90                         label : egCore.strings.OPERATORS_NOT_IN_LIST
91                 },
92         
93                 'between' : {
94                         label : egCore.strings.OPERATORS_BETWEEN
95                 },
96         
97                 'not between' : {
98                         label : egCore.strings.OPERATORS_NOT_BETWEEN
99                 },
100         
101                 'is' : {
102                         label : egCore.strings.OPERATORS_IS_NULL
103                 },
104         
105                 'is not' : {
106                         label : egCore.strings.OPERATORS_IS_NOT_NULL
107                 },
108         
109                 'is blank' : {
110                         label : egCore.strings.OPERATORS_NULL_BLANK
111                 },
112         
113                 'is not blank' : {
114                         label : egCore.strings.OPERATORS_NOT_NULL_BLANK
115                 },
116         
117                 '= any' : {
118                         labels : { 'array' : egCore.strings.OPERATORS_EQ_ANY }
119                 },
120         
121                 '<> any' : {
122                         labels : { 'array' : egCore.strings.OPERATORS_NE_ANY }
123                 }
124         },
125
126         Transforms : {
127            Bare : {
128                 datatype : OILS_RPT_DTYPE_ALL,
129                 label : egCore.strings.TRANSFORMS_BARE
130             },
131         
132             first : {
133                 datatype : OILS_RPT_DTYPE_NOT_ID,
134                 label : egCore.strings.TRANSFORMS_FIRST
135             },
136         
137             last : {
138                 datatype : OILS_RPT_DTYPE_NOT_ID,
139                 label : egCore.strings.TRANSFORMS_LAST
140             },
141         
142             count : {
143                 datatype : OILS_RPT_DTYPE_NOT_BOOL,
144                 aggregate : true,
145                 label :  egCore.strings.TRANSFORMS_COUNT
146             },
147         
148             count_distinct : {
149                 datatype : OILS_RPT_DTYPE_NOT_BOOL,
150                 aggregate : true,
151                 label : egCore.strings.TRANSFORMS_COUNT_DISTINCT
152             },
153         
154             min : {
155                 datatype : OILS_RPT_DTYPE_NOT_ID,
156                 aggregate : true,
157                 label : egCore.strings.TRANSFORMS_MIN
158             },
159         
160             max : {
161                 datatype : OILS_RPT_DTYPE_NOT_ID,
162                 aggregate : true,
163                 label : egCore.strings.TRANSFORMS_MAX
164             },
165         
166             /* string transforms ------------------------- */
167         
168             substring : {
169                 datatype : [ OILS_RPT_DTYPE_STRING ],
170                 params : 2,
171                 label : egCore.strings.TRANSFORMS_SUBSTRING
172             },
173         
174             lower : {
175                 datatype : [ OILS_RPT_DTYPE_STRING ],
176                 label : egCore.strings.TRANSFORMS_LOWER
177             },
178         
179             upper : {
180                 datatype : [ OILS_RPT_DTYPE_STRING ],
181                 label : egCore.strings.TRANSFORMS_UPPER
182             },
183         
184             first5 : {
185                 datatype : [ OILS_RPT_DTYPE_STRING ],
186                 label : egCore.strings.TRANSFORMS_FIRST5
187             },
188         
189                 first_word : {
190                         datatype : [OILS_RPT_DTYPE_STRING, 'text'],
191                         label : egCore.strings.TRANSFORMS_FIRST_WORD
192                 },
193         
194             /* timestamp transforms ----------------------- */
195             dow : {
196                 datatype : [ OILS_RPT_DTYPE_TIMESTAMP ],
197                 label : egCore.strings.TRANSFORMS_DOW,
198                 cal_format : '%w',
199                 regex : /^[0-6]$/
200             },
201             dom : {
202                 datatype : [ OILS_RPT_DTYPE_TIMESTAMP ],
203                 label : egCore.strings.TRANSFORMS_DOM,
204                 cal_format : '%e',
205                 regex : /^[0-9]{1,2}$/
206             },
207         
208             doy : {
209                 datatype : [ OILS_RPT_DTYPE_TIMESTAMP ],
210                 label : egCore.strings.TRANSFORMS_DOY,
211                 cal_format : '%j',
212                 regex : /^[0-9]{1,3}$/
213             },
214         
215             woy : {
216                 datatype : [ OILS_RPT_DTYPE_TIMESTAMP ],
217                 label : egCore.strings.TRANSFORMS_WOY,
218                 cal_format : '%U',
219                 regex : /^[0-9]{1,2}$/
220             },
221         
222             moy : {
223                 datatype : [ OILS_RPT_DTYPE_TIMESTAMP ],
224                 label : egCore.strings.TRANSFORMS_MOY,
225                 cal_format : '%m',
226                 regex : /^\d{1,2}$/
227             },
228         
229             qoy : {
230                 datatype : [ OILS_RPT_DTYPE_TIMESTAMP ],
231                 label : egCore.strings.TRANSFORMS_QOY,
232                 regex : /^[1234]$/
233             }, 
234         
235             hod : {
236                 datatype : [ OILS_RPT_DTYPE_TIMESTAMP ],
237                 label : egCore.strings.TRANSFORMS_HOD,
238                 cal_format : '%H',
239                 regex : /^\d{1,2}$/
240             }, 
241         
242             date : {
243                 datatype : [ OILS_RPT_DTYPE_TIMESTAMP ],
244                 label : egCore.strings.TRANSFORMS_DATE,
245                 regex : /^\d{4}-\d{2}-\d{2}$/,
246                 hint  : 'YYYY-MM-DD',
247                 cal_format : '%Y-%m-%d',
248                 input_size : 10
249             },
250         
251             month_trunc : {
252                 datatype : [ OILS_RPT_DTYPE_TIMESTAMP ],
253                 label : egCore.strings.TRANSFORMS_MONTH_TRUNC,
254                 regex : /^\d{4}-\d{2}$/,
255                 hint  : 'YYYY-MM',
256                 cal_format : '%Y-%m',
257                 input_size : 7
258             },
259         
260             year_trunc : {
261                 datatype : [ OILS_RPT_DTYPE_TIMESTAMP ],
262                 label : egCore.strings.TRANSFORMS_YEAR_TRUNC,
263                 regex : /^\d{4}$/,
264                 hint  : 'YYYY',
265                 cal_format : '%Y',
266                 input_size : 4
267             },
268         
269             hour_trunc : {
270                 datatype : [ OILS_RPT_DTYPE_TIMESTAMP ],
271                 label : egCore.strings.TRANSFORMS_HOUR_TRUNC,
272                 regex : /^\d{2}$/,
273                 hint  : 'HH',
274                 cal_format : '%Y-%m-$d %H',
275                 input_size : 2
276             },
277         
278             day_name : {
279                 datatype : [ OILS_RPT_DTYPE_TIMESTAMP ],
280                 cal_format : '%A',
281                 label : egCore.strings.TRANSFORMS_DAY_NAME
282             }, 
283         
284             month_name : {
285                 datatype : [ OILS_RPT_DTYPE_TIMESTAMP ],
286                 cal_format : '%B',
287                 label : egCore.strings.TRANSFORMS_MONTH_NAME
288             },
289             age : {
290                 datatype : [ OILS_RPT_DTYPE_TIMESTAMP ],
291                 label : egCore.strings.TRANSFORMS_AGE
292             },
293         
294             months_ago : {
295                 datatype : [ OILS_RPT_DTYPE_TIMESTAMP ],
296                 label : egCore.strings.TRANSFORMS_MONTHS_AGO
297             },
298         
299             quarters_ago : {
300                 datatype : [ OILS_RPT_DTYPE_TIMESTAMP ],
301                 label : egCore.strings.TRANSFORMS_QUARTERS_AGO
302             },
303         
304             /* int  / float transforms ----------------------------------- */
305             sum : {
306                 datatype : [ OILS_RPT_DTYPE_INT, OILS_RPT_DTYPE_FLOAT, OILS_RPT_DTYPE_MONEY ],
307                 label : egCore.strings.TRANSFORMS_SUM,
308                 aggregate : true
309             }, 
310         
311             average : {
312                 datatype : [ OILS_RPT_DTYPE_INT, OILS_RPT_DTYPE_FLOAT, OILS_RPT_DTYPE_MONEY ],
313                 label : egCore.strings.TRANSFORMS_AVERAGE,
314                 aggregate : true
315             },
316         
317             round : {
318                 datatype : [ OILS_RPT_DTYPE_INT, OILS_RPT_DTYPE_FLOAT ],
319                 label : egCore.strings.TRANSFORMS_ROUND,
320             },
321         
322             'int' : {
323                 datatype : [ OILS_RPT_DTYPE_FLOAT ],
324                 label : egCore.strings.TRANSFORMS_INT
325             }
326         }
327     };
328
329     service.addFields = function (type, fields, transform, source_label, source_path, op) {
330         fields.forEach(function(f) {
331             var l = f.label ? f.label : f.name;
332             var new_field = angular.extend(
333                 {},
334                 f,
335                 { index : service[type].length,
336                   label : l,
337                   path  : source_path,
338                   path_label : source_label,
339                   operator   : op,
340                   transform  : transform,
341                   doc_text   : ''
342                 }
343             );
344
345             var add = true;
346             service[type].forEach(function(e) {
347                 if (e.name == new_field.name && e.path == new_field.path) add = false;
348             });
349             if (add) service[type].push(new_field);
350         });
351     }
352
353     service.moveFieldUp = function (type, field) {
354         var new_list = [];
355         while (service[type].length) {
356             var f = service[type].pop();
357             if (field.index == f.index && f.index > 0)
358                 new_list.unshift(f,service[type].pop());
359             else
360                 new_list.unshift(f);
361         }
362         new_list.forEach(function(f) {
363             service[type].push(angular.extend(f, { index : service[type].length}));
364         });
365     }
366
367     service.moveFieldDown = function (type, field) {
368         var new_list = [];
369         var start_len = service[type].length - 1;
370         while (service[type].length) {
371             var f = service[type].shift();
372             if (field.index == f.index && f.index < start_len)
373                 new_list.push(service[type].shift(),f);
374             else
375                 new_list.push(f);
376         }
377         new_list.forEach(function(f) {
378             service[type].push(angular.extend(f, { index : service[type].length}));
379         });
380     }
381
382     service.updateFilterValue = function(item, value) {
383         switch (item.operator.op) {
384             case 'between':
385             case 'not between':
386             case 'not in':
387             case 'in':
388                 //if value isn't an array yet, split into an array for
389                 //  operators that need it
390                 if (typeof value === 'string') {
391                     value = value.split(/\s*,\s*/);
392                 }
393                 break;
394
395             default:
396                 //if value was split but shouldn't be, then convert back to
397                 //  comma-separated string
398                 if (Array.isArray(value)) {
399                     value = value.toString();
400                 }
401         }
402
403         service.filter_fields[item.index].value = value;
404     }
405
406     service.removeField = function (type, field) {
407         var new_list = [];
408         while (service[type].length) {
409             var f = service[type].pop();
410             if (field.index != f.index ) new_list.push(f);
411         }
412         new_list.forEach(function(f) {
413             service[type].push(angular.extend(f, { index : service[type].length}));
414         });
415     }
416
417     service.getTransformByLabel = function (l) {
418         for( var key in service.Transforms ) {
419             var t = service.Transforms[key];
420             if (l == t.label) return key;
421             if (angular.isArray(t.labels) && t.labels.indexOf(l) > -1) return key;
422         }
423         return null;
424     }
425
426     service.getFilterByLabel = function (l) {
427         for( var key in service.Filters ) {
428             var t = service.Filters[key];
429             if (l == t.label) return key;
430             if (angular.isArray(t.labels) && t.labels.indexOf(l) > -1) return key;
431         }
432         return null;
433     }
434
435     service.getTransforms = function (args) {
436         var dtype = args.datatype;
437         var agg = args.aggregate;
438         var nonagg = args.non_aggregate;
439         var label = args.label;
440     
441         var tforms = [];
442     
443         for( var key in service.Transforms ) {
444             var obj = service.Transforms[key];
445             if( agg && !nonagg && !obj.aggregate ) continue;
446             if( !agg && nonagg && obj.aggregate ) continue;
447             if( !dtype && obj.datatype.length > 0 ) continue;
448             if( dtype && obj.datatype.length > 0 && transformIsForDatatype(key,dtype).length == 0 ) continue;
449             tforms.push(key);
450         }
451     
452         return tforms;
453     }
454
455
456     service.transformIsForDatatype = function (tform, dtype) {
457         var obj = service.Transforms[tform];
458         return obj.datateype.filter(function(d) { return (d == dtype) })[0];
459     }
460
461     return service;
462 }])
463 ;
464