]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/xul/staff_client/server/patron/ue_config.js
names now have to start with a letter (no spaces)
[Evergreen.git] / Open-ILS / xul / staff_client / server / patron / ue_config.js
1 /* -----------------------------------------------------------------------
2         ----------------------------------------------------------------------- */
3 var SC_FETCH_ALL                = 'open-ils.circ:open-ils.circ.stat_cat.actor.retrieve.all';
4 var SC_CREATE_MAP               = 'open-ils.circ:open-ils.circ.stat_cat.actor.user_map.create';
5 var SV_FETCH_ALL                = 'open-ils.circ:open-ils.circ.survey.retrieve.all';
6 var FETCH_ID_TYPES      = 'open-ils.actor:open-ils.actor.user.ident_types.retrieve';
7 var FETCH_GROUPS                = 'open-ils.actor:open-ils.actor.groups.tree.retrieve';
8 var UPDATE_PATRON               = 'open-ils.actor:open-ils.actor.patron.update';
9 var PATRON_SEARCH               = 'open-ils.actor:open-ils.actor.patron.search.advanced';
10 var ZIP_SEARCH                  = 'open-ils.search:open-ils.search.zip';
11 var defaultState                = 'GA';
12 var defaultCountry      = 'USA';
13 var CSS_INVALID_DATA = 'invalid_value';
14
15 /* if they don't have these perms, they shouldn't be here */
16 var myPerms = [ 'CREATE_USER', 'UPDATE_USER', 'CREATE_PATRON_STAT_CAT_ENTRY_MAP' ];
17
18 var dataFields;
19 var numRegex    = /^\d+$/;
20 var wordRegex   = /^\w+$/;
21 var ssnRegex    = /^\d{3}-\d{2}-\d{4}$/;
22 var dlRegex             = /^[a-zA-Z]{2}-\w+/; /* driver's license */
23 var phoneRegex  = /\d{3}-\d{3}-\d{4}/;
24 var nonumRegex  = /^[a-zA-Z]\D*$/; /* no numbers, no beginning whitespace */
25 var dateRegex   = /^\d{4}-\d{2}-\d{2}/;
26
27
28
29 function uEditDefineData(patron) {
30         
31         var fields = [
32                 {
33                         required : true,
34                         object  : patron.card(),
35                         key             : 'barcode',
36                         errkey  : 'ue_bad_barcode',
37                         widget  : {
38                                 id              : 'ue_barcode',
39                                 regex   : wordRegex,
40                                 type    : 'input'
41                         }
42                 },
43                 {
44                         required : true,
45                         object  : patron,
46                         key             : 'usrname',
47                         errkey  : 'ue_bad_username',
48                         widget  : {
49                                 id              : 'ue_username',
50                                 regex   : wordRegex,
51                                 type    : 'input'
52                         }
53                 },
54                 {
55                         required : (patron.isnew()) ? true : false,
56                         object  : patron,
57                         key             : 'passwd',
58                         errkey  : 'ue_bad_password',
59                         widget  : {
60                                 id              : 'ue_password1',
61                                 type    : 'input',
62                                 onpostchange : function(field, newval) {
63                                         var pw2 = uEditFindFieldByWId('ue_password2');
64                                         /* tell the second passsword input to re-validate */
65                                         pw2.widget.node.onchange();
66                                 }
67
68                         }
69                 },
70                 {
71                         required : (patron.isnew()) ? true : false,
72                         object  : patron,
73                         key             : 'passwd',
74                         errkey  : 'ue_bad_password',
75                         widget  : {
76                                 id              : 'ue_password2',
77                                 type    : 'input',
78                                 onpostchange : function(field, newval) {
79                                         var pw1f = uEditFindFieldByWId('ue_password1');
80                                         var pw1 = uEditNodeVal(pw1f);
81                                         if( pw1 == newval ) 
82                                                 removeCSSClass(field.widget.node, CSS_INVALID_DATA);
83                                         else
84                                                 addCSSClass(field.widget.node, CSS_INVALID_DATA);
85                                 }
86                         }
87                 },
88                 {
89                         required : true,
90                         object  : patron,
91                         key             : 'first_given_name',
92                         errkey  : 'ue_bad_firstname',
93                         widget  : {
94                                 id              : 'ue_firstname',
95                                 regex   : nonumRegex,
96                                 type    : 'input',
97                                 onblur : function(field) {
98                                         uEditCheckNamesDup('first', field );
99                                 }
100                         }
101                 },
102
103                 {
104                         required : false,
105                         object  : patron,
106                         key             : 'second_given_name',
107                         errkey  : 'ue_bad_middlename',
108                         widget  : {
109                                 id              : 'ue_middlename',
110                                 regex   : nonumRegex,
111                                 type    : 'input'
112                         }
113                 },
114                 {
115                         required : true,
116                         object  : patron,
117                         key             : 'family_name',
118                         errkey  : 'ue_bad_lastname',
119                         widget  : {
120                                 id              : 'ue_lastname',
121                                 regex   : nonumRegex,
122                                 type    : 'input',
123                                 onblur : function(field) {
124                                         uEditCheckNamesDup('last', field );
125                                 }
126                         }
127                 },
128                 {
129                         required : false,
130                         object  : patron,
131                         key             : 'suffix',
132                         widget  : {
133                                 id                      : 'ue_suffix',
134                                 type            : 'input',
135                                 onload  : function(val) {
136                                         setSelector($('ue_suffix_selector'), val);
137                                 }
138                         }
139                 },
140                 {
141                         required : true,
142                         object  : patron,
143                         key             : 'dob',
144                         errkey  : 'ue_bad_dob',
145                         widget  : {
146                                 id                      : 'ue_dob',
147                                 regex           : dateRegex,
148                                 type            : 'input',
149                         }
150                 },
151                 {
152                         required : true,
153                         object  : patron,
154                         key             : 'ident_type',
155                         errkey  : 'ue_no_ident',
156                         widget  : {
157                                 id              : 'ue_primary_ident_type',
158                                 regex   : numRegex,
159                                 type    : 'select',
160                                 onpostchange : function(field, newval) 
161                                         { _uEditIdentPostchange('primary', field, newval); }
162                         }
163                 },
164                 {
165                         required : false,
166                         object  : patron,
167                         key             : 'ident_value',
168                         widget  : {
169                                 id                      : 'ue_primary_ident',
170                                 type            : 'input',
171                                 onblur : function(field) {
172                                         uEditCheckIdentDup(field);
173                                 }
174                         }
175                 },
176                 {
177                         required : false,
178                         object  : patron,
179                         key             : 'ident_type2',
180                         widget  : {
181                                 id              : 'ue_secondary_ident_type',
182                                 regex   : numRegex,
183                                 type    : 'select',
184                                 onpostchange : function(field, newval) 
185                                         { _uEditIdentPostchange('secondary', field, newval); }
186                         }
187                 },
188                 {
189                         required : false,
190                         object  : patron,
191                         key             : 'ident_value2',
192                         widget  : {
193                                 id                      : 'ue_secondary_ident',
194                                 type            : 'input',
195                                 onblur : function(field) {
196                                         uEditCheckIdentDup(field);
197                                 }
198                         }
199                 },
200                 {
201                         required : false,
202                         object  : patron,
203                         key             : 'email',
204                         errkey  : 'ue_bad_email',
205                         widget  : {
206                                 id                      : 'ue_email',
207                                 type            : 'input',
208                                 regex           :  /.+\@.+\..+/,  /* make me better */
209                                 onblur  : function(field) {
210                                         var val = uEditNodeVal(field);
211                                         if( val && val != field.oldemail ) {
212                                                 uEditRunDupeSearch('email',
213                                                         { email : { value : val, group : 0 } });
214                                                 field.oldemail = val;
215                                         }
216                                 }
217                         }
218                 },
219                 {
220                         required : false,
221                         object  : patron,
222                         key             : 'day_phone',
223                         errkey  : 'ue_bad_phone',
224                         widget  : {
225                                 id                      : 'ue_day_phone',
226                                 type            : 'input',
227                                 regex           :  phoneRegex,
228                         }
229                 },
230                 {
231                         required : false,
232                         object  : patron,
233                         key             : 'evening_phone',
234                         errkey  : 'ue_bad_phone',
235                         widget  : {
236                                 id                      : 'ue_night_phone',
237                                 type            : 'input',
238                                 regex           :  phoneRegex,
239                         }
240                 },
241                 {
242                         required : false,
243                         object  : patron,
244                         key             : 'other_phone',
245                         errkey  : 'ue_bad_phone',
246                         widget  : {
247                                 id                      : 'ue_other_phone',
248                                 type            : 'input',
249                                 regex           :  phoneRegex,
250                         }
251                 },
252                 {
253                         required : true,
254                         object  : patron,
255                         key             : 'home_ou',
256                         widget  : {
257                                 id                      : 'ue_org_selector',
258                                 type            : 'select',
259                                 regex           :  numRegex,
260                         }
261                 },
262                 {
263                         required : true,
264                         object  : patron,
265                         key             : 'expire_date',
266                         errkey  : 'ue_bad_expire',
267                         widget  : {
268                                 id                      : 'ue_expire',
269                                 type            : 'input',
270                                 regex           :  dateRegex,
271                         }
272                 },
273                 {
274                         required : false,
275                         object  : patron,
276                         key             : 'active',
277                         widget  : {
278                                 id                      : 'ue_active',
279                                 type            : 'checkbox',
280                         }
281                 },
282                 {
283                         required : false,
284                         object  : patron,
285                         key             : 'barred',
286                         widget  : {
287                                 id                      : 'ue_barred',
288                                 type            : 'checkbox',
289                         }
290                 },
291                 {
292                         required : true,
293                         object  : patron,
294                         key             : 'profile',
295                         errkey  : 'ue_no_profile',
296                         widget  : {
297                                 id                      : 'ue_profile',
298                                 type            : 'select',
299                                 regex           : numRegex,
300                                 onpostchange : function(field, value) {
301                                         var type                        = groupsCache[value];
302                                         var interval    = type.perm_interval();
303                                         var intsecs             = parseInt(util.date.interval_to_seconds(interval));
304
305                                         var expdate             = new Date();
306                                         var exptime             = expdate.getTime();
307                                         exptime                 += intsecs * 1000;
308                                         expdate.setTime(exptime);
309
310                                         var year                        = expdate.getYear() + 1900;
311                                         var month               = (expdate.getMonth() + 1) + '';
312                                         var day                 = (expdate.getDate() + 1) + '';
313
314                                         if(!month.match(/\d{2}/)) month = '0' + month;
315                                         if(!day.match(/\d{2}/)) day = '0' + day;
316
317                                         var node = $('ue_expire');
318                                         node.value = year+'-'+month+'-'+day;
319                                 }
320                         }
321                 },
322                 {
323                         required : false,
324                         object  : patron,
325                         key             : 'master_account',
326                         widget  : {
327                                 id                      : 'ue_group_lead',
328                                 type            : 'checkbox',
329                         }
330                 },
331                 {
332                         required : true,
333                         object  : patron,
334                         key             : 'claims_returned_count',
335                         widget  : {
336                                 id                      : 'ue_claims_returned',
337                                 type            : 'input',
338                                 regex           : numRegex,
339                         }
340                 },
341                 {
342                         required : false,
343                         object  : patron,
344                         key             : 'alert_message',
345                         widget  : {
346                                 id                      : 'ue_alert_message',
347                                 type            : 'input',
348                         }
349                 }
350         ];
351
352         for( var f in fields ) 
353                 dataFields.push(fields[f]);
354
355         uEditBuildAddrs(patron);
356         uEditBuildPatronSCM(patron);
357 }
358
359 var uEditOldFirstName;
360 var uEditOldMiddleName; /* future */
361 var uEditOldLastName;
362 function uEditCheckNamesDup(type, field) {
363         var newval = uEditNodeVal(field);
364         if(!newval) return;
365
366         var dosearch = false;
367
368         if(type =='first') {
369                 if( newval != uEditOldFirstName )
370                         dosearch = true;
371                 uEditOldFirstName = newval;
372         }
373
374         if(type =='last') {
375                 if( newval != uEditOldLastName )
376                         dosearch = true;
377                 uEditOldLastName = newval;
378         }
379
380         if( dosearch && uEditOldFirstName && uEditOldLastName ) {
381                 var search_hash = {};
382                 search_hash['first_given_name'] = { value : uEditOldFirstName, group : 0 };
383                 search_hash['family_name'] = { value : uEditOldLastName, group : 0 };
384                 uEditRunDupeSearch('names', search_hash);
385         }
386 }
387
388 var uEditOldIdentValue;
389 function uEditCheckIdentDup(field) {
390         var newval = uEditNodeVal(field);
391         if( newval && newval != uEditOldIdentValue ) {
392                 /* searches all ident_value fields */
393                 var search_hash  = { ident : { value : newval, group : 2 } };
394                 uEditRunDupeSearch('ident', search_hash);
395                 uEditOldIdentValue = newval;
396         }
397 }
398
399
400 /* Adds all of the addresses attached to the patron object
401         to the fields array */
402 var uEditAddrTemplate;
403 function uEditBuildAddrs(patron) {
404         var tbody = $('ue_address_tbody');
405         uEditAddrTemplate = 
406                 tbody.removeChild($('ue_address_template'));
407         for( var a in patron.addresses() ) 
408                 uEditBuildAddrFields( patron, patron.addresses()[a]);
409 }
410
411
412 function uEditDeleteAddr( tbody, row, address ) {
413         if(!confirm($('ue_delete_addr_warn').innerHTML)) return;
414         if(address.isnew()) { 
415                 patron.addresses(
416                         grep( patron.addresses(), 
417                                 function(i) {
418                                         return (i.id() != address.id());
419                                 }
420                         )
421                 );
422         } else {
423                 address.isdeleted(1);
424         }
425         tbody.removeChild(row);
426
427         var bid = patron.billing_address();
428         bid = (typeof bid == 'object') ? bid.id() : bid;
429
430         var mid = patron.mailing_address();
431         mid = (typeof mid == 'object') ? mid.id() : mid;
432
433
434         /* -----------------------------------------------------------------------
435                 if we're deleting a billing or mailing address 
436                 make sure some other address is automatically
437                 assigned as the billing or mailng address 
438                 ----------------------------------------------------------------------- */
439
440         if( bid == address.id() ) {
441                 for( var a in patron.addresses() ) {
442                         var addr = patron.addresses()[a];
443                         if(!addr.isdeleted()) {
444                                 var node = uEditFindAddrInput('billing', addr.id());
445                                 node.checked = true;
446                                 uEditAddrTypeClick(node, 'billing');
447                                 break;
448                         }
449                 }
450         }
451
452         if( mid == address.id() ) {
453                 for( var a in patron.addresses() ) {
454                         var addr = patron.addresses()[a];
455                         if(!addr.isdeleted()) {
456                                 var node = uEditFindAddrInput('mailing', addr.id());
457                                 node.checked = true;
458                                 uEditAddrTypeClick(node, 'mailing');
459                                 break;
460                         }
461                 }
462         }
463 }
464
465
466 function uEditFindAddrInput(type, id) {
467         var tbody = $('ue_address_tbody');
468         var rows = tbody.getElementsByTagName('tr');
469         for( var r in rows ) {
470                 var row = rows[r];
471                 if(row.parentNode != tbody) continue;
472                 var node = $n(row, 'ue_addr_'+type+'_yes');
473                 if( node.getAttribute('address') == id )
474                         return node;
475         }
476 }
477
478
479 function uEditAddrTypeClick(input, type) {
480         var tbody = $('ue_address_tbody');
481         var rows = tbody.getElementsByTagName('tr');
482         for( var r in rows ) {
483                 var row = rows[r];
484                 if(row.parentNode != tbody) continue;
485                 var node = $n(row, 'ue_addr_'+type+'_yes');
486                 removeCSSClass(node.parentNode,'addr_info_checked');
487         }
488
489         addCSSClass(input.parentNode,'addr_info_checked');
490         patron[type+'_address'](input.getAttribute('address'));
491         patron.ischanged(1);
492 }
493
494
495
496
497 /* Creates the field entries for an address object. */
498 function uEditBuildAddrFields(patron, address) {
499
500         var tbody = $('ue_address_tbody');
501         var row = tbody.appendChild(
502                 uEditAddrTemplate.cloneNode(true));
503
504         $n(row, 'ue_addr_delete').onclick = 
505                 function() { uEditDeleteAddr(tbody, row, address); }
506
507         if( address.id() == patron.billing_address().id() ) 
508                 $n(row, 'ue_addr_billing_yes').checked = true;
509         
510
511         if( address.id() == patron.mailing_address().id() ) 
512                 $n(row, 'ue_addr_mailing_yes').checked = true;
513
514         $n(row, 'ue_addr_billing_yes').setAttribute('address', address.id());
515         $n(row, 'ue_addr_mailing_yes').setAttribute('address', address.id());
516
517         var fields = [
518                 { 
519                         required : false,
520                         object  : address, 
521                         key             : 'address_type', 
522                         widget  : {
523                                 base    : row,
524                                 name    : 'ue_addr_label',
525                                 type    : 'input',
526                         }
527                 },
528                 { 
529                         required : true,
530                         object  : address, 
531                         key             : 'street1', 
532                         errkey  : 'ue_bad_addr_street',
533                         widget  : {
534                                 base    : row,
535                                 name    : 'ue_addr_street1',
536                                 type    : 'input',
537                         }
538                 },
539                 { 
540                         required : false,
541                         object  : address, 
542                         key             : 'street2', 
543                         errkey  : 'ue_bad_addr_street',
544                         widget  : {
545                                 base    : row,
546                                 name    : 'ue_addr_street2',
547                                 type    : 'input',
548                         }
549                 },
550                 { 
551                         required : true,
552                         object  : address, 
553                         key             : 'city', 
554                         errkey  : 'ue_bad_addr_city',
555                         widget  : {
556                                 base    : row,
557                                 name    : 'ue_addr_city',
558                                 type    : 'input',
559                         }
560                 },
561                 { 
562                         required : false,
563                         object  : address, 
564                         key             : 'county', 
565                         widget  : {
566                                 base    : row,
567                                 name    : 'ue_addr_county',
568                                 type    : 'input',
569                         }
570                 },
571                 { 
572                         required : true,
573                         object  : address, 
574                         key             : 'state', 
575                         errkey  : 'ue_bad_addr_state',
576                         widget  : {
577                                 base    : row,
578                                 name    : 'ue_addr_state',
579                                 type    : 'input',
580                         }
581                 },
582                 { 
583                         required : true,
584                         object  : address, 
585                         key             : 'country', 
586                         errkey  : 'ue_bad_addr_country',
587                         widget  : {
588                                 base    : row,
589                                 name    : 'ue_addr_country',
590                                 type    : 'input',
591                         }
592                 },
593                 { 
594                         required : true,
595                         object  : address, 
596                         key             : 'post_code',
597                         errkey  : 'ue_bad_addr_zip',
598                         widget  : {
599                                 base    : row,
600                                 name    : 'ue_addr_zip',
601                                 type    : 'input',
602                                 regex   : /^\d{5}$/,
603                                 onblur : function(f) {
604                                         var v = uEditNodeVal(f);
605                                         var req = new Request(ZIP_SEARCH, v);
606                                         req.callback( 
607                                                 function(r) {
608                                                         var info = r.getResultObject();
609                                                         if(!info) return;
610                                                         var state = $n(f.widget.base, 'ue_addr_state');
611                                                         var county = $n(f.widget.base, 'ue_addr_county');
612                                                         var city = $n(f.widget.base, 'ue_addr_city');
613                                                         if(!state.value) state.value = info.state;
614                                                         if(!county.value) county.value = info.county;
615                                                         if(!city.value) city.value = info.city;
616                                                 }
617                                         );
618                                         req.send();
619                                 }
620                         }
621                 },
622                 { 
623                         required : false,
624                         object  : address, 
625                         key             : 'within_city_limits',
626                         widget  : {
627                                 base    : row,
628                                 name    : 'ue_addr_inc_yes',
629                                 type    : 'checkbox',
630                         }
631                 },
632                 { 
633                         required : false,
634                         object  : address, 
635                         key             : 'valid',
636                         widget  : {
637                                 base    : row,
638                                 name    : 'ue_addr_valid_yes',
639                                 type    : 'checkbox',
640                         }
641                 }
642         ];
643
644         for( var f in fields ) {
645                 dataFields.push(fields[f]);
646                 uEditActivateField(fields[f]);
647         }
648 }
649
650 function uEditBuildPatronSCM(patron) {
651         /* get the list of pre-defined maps */
652         var fields = uEditFindFieldsByKey('stat_cat_entry');
653         var map;
654         var newmaps = [];
655
656         /* for each user stat cat, pop it off the list,
657         updated the existing stat map field to match
658         the popped map and shove the existing stat
659         map field onto the user's list of stat maps */
660         while( (map = patron.stat_cat_entries().pop()) ) {
661
662                 var field = grep(fields, 
663                         function(item) {
664                                 return (item.object.stat_cat() == map.stat_cat());
665                         }
666                 );
667
668                 if(field) {
669                         var val = map.stat_cat_entry();
670                         field = field[0];
671                         $n(field.widget.base, field.widget.name).value = val;
672                         setSelector($n(field.widget.base, 'ue_stat_cat_selector'), val );
673                         field.object.stat_cat_entry(val);
674                         field.object.id(map.id());
675                         newmaps.push(field.object);
676                 }
677         }
678
679         for( var m in newmaps ) 
680                 patron.stat_cat_entries().push(newmaps[m]);
681 }
682
683
684 function uEditBuildSCMField(statcat, row) {
685
686         var map = new actscecm();
687         map.stat_cat(statcat.id());
688         map.target_usr(patron.id());
689
690         var field = {
691                 required : false,
692                 object  : map,
693                 key             : 'stat_cat_entry',
694                 widget  : {
695                         base    : row,
696                         name    : 'ue_stat_cat_newval',
697                         type    : 'input',
698
699                         onpostchange : function( field, newval ) {
700
701                                 /* see if the current map already resides in 
702                                         the patron entry list */
703                                 var exists = grep( patron.stat_cat_entries(),
704                                         function(item) {
705                                                 return (item.stat_cat() == statcat.id()); 
706                                         }
707                                 );
708
709                                 if(newval) {
710                                         map.isdeleted(0);
711                                         setSelector($n(row, 'ue_stat_cat_selector'), newval);
712                                 }
713
714                                 if(exists) {
715                                         if(!newval) {
716
717                                                 /* if the map is new but currently contains no value
718                                                         remove it from the set of new maps */
719                                                 if(map.isnew()) {
720                                                         patron.stat_cat_entries(
721                                                                 grep( patron.stat_cat_entries(),
722                                                                         function(item) {
723                                                                                 return (item.stat_cat() != map.stat_cat());
724                                                                         }
725                                                                 )
726                                                         );
727
728                                                 } else {
729                                                         map.isdeleted(1);
730                                                         map.ischanged(0);
731                                                 }
732                                         } 
733
734                                 } else {
735
736                                         /* map does not exist in the map array but now has data */
737                                         if(newval) { 
738                                                 map.isnew(1);
739                                                 patron.stat_cat_entries().push(map);
740                                         }
741                                 }
742                         }
743                 }
744         }
745
746         dataFields.push(field);
747 }
748
749
750
751 /** Run this after a new ident type is selected */
752 function _uEditIdentPostchange(type, field, newval) {
753
754         if(!newval) return;
755
756         /* When the ident type is changed, we change the
757         regex on the ident_value to match the selected type */
758         var vfname = 'ident_value';
759         if(type == 'secondary') vfname = 'ident_value2';
760         var vfield = uEditFindFieldByKey(vfname);
761         var name = identTypesCache[uEditNodeVal(field)].name();
762
763         hideMe($(type+'_ident_ssn_help'));
764         hideMe($(type+'_ident_dl_help'));
765
766         if(name.match(/ssn/i)) {
767                 vfield.widget.regex = ssnRegex;
768                 vfield.errkey = 'ue_bad_ident_ssn';
769                 unHideMe($(type+'_ident_ssn_help'));
770
771         } else {
772
773                 if(name.match(/driver/i)) {
774                         vfield.widget.regex = dlRegex;
775                         vfield.errkey = 'ue_bad_ident_dl';
776                         unHideMe($(type+'_ident_dl_help'));
777                         if(!uEditNodeVal(vfield))
778                                 vfield.widget.node.value = defaultState + '-';
779
780                 } else {
781                         vfield.widget.regex = null;
782                         vfield.errkey = null;
783                 }
784         }
785
786         /* focus then valdate the value field */
787         vfield.widget.node.onchange();
788         vfield.widget.node.focus();
789 }
790
791
792
793
794
795