dolibarr  19.0.0-dev
lib_head.js.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) 2005-2018 Laurent Destailleur <eldy@users.sourceforge.net>
3  * Copyright (C) 2005-2014 Regis Houssin <regis.houssin@inodbox.com>
4  * Copyright (C) 2015 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program. If not, see <https://www.gnu.org/licenses/>.
18  * or see https://www.gnu.org/
19  */
20 
27 if (!defined('NOREQUIRESOC')) {
28  define('NOREQUIRESOC', '1');
29 }
30 if (!defined('NOCSRFCHECK')) {
31  define('NOCSRFCHECK', 1);
32 }
33 if (!defined('NOTOKENRENEWAL')) {
34  define('NOTOKENRENEWAL', 1);
35 }
36 if (!defined('NOLOGIN')) {
37  define('NOLOGIN', 1);
38 }
39 if (!defined('NOREQUIREMENU')) {
40  define('NOREQUIREMENU', 1);
41 }
42 if (!defined('NOREQUIREHTML')) {
43  define('NOREQUIREHTML', 1);
44 }
45 if (!defined('NOREQUIREAJAX')) {
46  define('NOREQUIREAJAX', '1');
47 }
48 
49 session_cache_limiter('public');
50 
51 require_once '../../main.inc.php';
52 
53 
54 /*
55  * View
56  */
57 
58 // Define javascript type
59 top_httphead('text/javascript; charset=UTF-8');
60 // Important: Following code is to avoid page request by browser and PHP CPU at each Dolibarr page access.
61 if (empty($dolibarr_nocache)) {
62  header('Cache-Control: max-age=10800, public, must-revalidate');
63 } else {
64  header('Cache-Control: no-cache');
65 }
66 
67 
68 
69 // Define tradMonths javascript array (we define this in datepicker AND in parent page to avoid errors with IE8)
70 $tradMonths = array(
71 dol_escape_js($langs->transnoentitiesnoconv("Month01")),
72 dol_escape_js($langs->transnoentitiesnoconv("Month02")),
73 dol_escape_js($langs->transnoentitiesnoconv("Month03")),
74 dol_escape_js($langs->transnoentitiesnoconv("Month04")),
75 dol_escape_js($langs->transnoentitiesnoconv("Month05")),
76 dol_escape_js($langs->transnoentitiesnoconv("Month06")),
77 dol_escape_js($langs->transnoentitiesnoconv("Month07")),
78 dol_escape_js($langs->transnoentitiesnoconv("Month08")),
79 dol_escape_js($langs->transnoentitiesnoconv("Month09")),
80 dol_escape_js($langs->transnoentitiesnoconv("Month10")),
81 dol_escape_js($langs->transnoentitiesnoconv("Month11")),
82 dol_escape_js($langs->transnoentitiesnoconv("Month12"))
83 );
84 
85 $tradMonthsShort = array(
86 $langs->trans("MonthShort01"),
87 $langs->trans("MonthShort02"),
88 $langs->trans("MonthShort03"),
89 $langs->trans("MonthShort04"),
90 $langs->trans("MonthShort05"),
91 $langs->trans("MonthShort06"),
92 $langs->trans("MonthShort07"),
93 $langs->trans("MonthShort08"),
94 $langs->trans("MonthShort09"),
95 $langs->trans("MonthShort10"),
96 $langs->trans("MonthShort11"),
97 $langs->trans("MonthShort12")
98 );
99 
100 $tradDays = array(
101 $langs->trans("Sunday"),
102 $langs->trans("Monday"),
103 $langs->trans("Tuesday"),
104 $langs->trans("Wednesday"),
105 $langs->trans("Thursday"),
106 $langs->trans("Friday"),
107 $langs->trans("Saturday")
108 );
109 
110 $tradDaysShort = array(
111 $langs->trans("ShortSunday"),
112 $langs->trans("ShortMonday"),
113 $langs->trans("ShortTuesday"),
114 $langs->trans("ShortWednesday"),
115 $langs->trans("ShortThursday"),
116 $langs->trans("ShortFriday"),
117 $langs->trans("ShortSaturday")
118 );
119 
120 $tradDaysMin = array(
121 $langs->trans("SundayMin"),
122 $langs->trans("MondayMin"),
123 $langs->trans("TuesdayMin"),
124 $langs->trans("WednesdayMin"),
125 $langs->trans("ThursdayMin"),
126 $langs->trans("FridayMin"),
127 $langs->trans("SaturdayMin")
128 );
129 
130 
131 $dec = ',';
132 $thousand = ' ';
133 if ($langs->transnoentitiesnoconv("SeparatorDecimal") != "SeparatorDecimal") {
134  $dec = $langs->transnoentitiesnoconv("SeparatorDecimal");
135 }
136 if ($langs->transnoentitiesnoconv("SeparatorThousand") != "SeparatorThousand") {
137  $thousand = $langs->transnoentitiesnoconv("SeparatorThousand");
138 }
139 if ($thousand == 'Space') {
140  $thousand = ' ';
141 }
142 
143 ?>
144 // Javascript libraries for Dolibarr ERP CRM (https://www.dolibarr.org)
145 
146 // For jQuery date picker
147 var tradMonths = <?php echo json_encode($tradMonths) ?>;
148 var tradMonthsShort = <?php echo json_encode($tradMonthsShort) ?>;
149 var tradDays = <?php echo json_encode($tradDays) ?>;
150 var tradDaysShort = <?php echo json_encode($tradDaysShort) ?>;
151 var tradDaysMin = <?php echo json_encode($tradDaysMin) ?>;
152 var currencyCache = <?php echo json_encode($langs->cache_currencies) ?>;
153 
154 // For JQuery date picker
155 $(document).ready(function() {
156  $.datepicker.setDefaults({
157  autoSize: true,
158  changeMonth: true,
159  changeYear: true,
160  altField: '#timestamp',
161  altFormat: '@' // Gives a timestamp dateformat
162  });
163 });
164 
165 jQuery(function($){
166  $.datepicker.regional['<?php echo $langs->defaultlang ?>'] = {
167  closeText: '<?php echo $langs->trans("Close2") ?>',
168  prevText: '<?php echo $langs->trans("Previous") ?>',
169  nextText: '<?php echo $langs->trans("Next") ?>',
170  currentText: '<?php echo $langs->trans("Now") ?>',
171  monthNames: tradMonths,
172  monthNamesShort: tradMonthsShort,
173  dayNames: tradDays,
174  dayNamesShort: tradDaysShort,
175  dayNamesMin: tradDaysMin,
176  weekHeader: '<?php echo $langs->trans("Week"); ?>',
177  dateFormat: '<?php echo $langs->trans("FormatDateShortJQuery"); ?>', /* Note dd/mm/yy means year on 4 digit in jquery format */
178  firstDay: <?php echo (isset($conf->global->MAIN_START_WEEK) ? $conf->global->MAIN_START_WEEK : '1'); ?>,
179  isRTL: <?php echo ($langs->trans("DIRECTION") == 'rtl' ? 'true' : 'false'); ?>,
180  showMonthAfterYear: false, /* TODO add specific to country */
181  yearSuffix: '' /* TODO add specific to country */
182  };
183  $.datepicker.setDefaults($.datepicker.regional['<?php echo $langs->defaultlang ?>']);
184 });
185 
186 
187 
192 var select2arrayoflanguage = {
193  matches: function (matches) { return matches + " <?php echo dol_escape_js($langs->transnoentitiesnoconv("Select2ResultFoundUseArrows")); ?>"; },
194  noResults: function () { return "<?php echo dol_escape_js($langs->transnoentitiesnoconv("Select2NotFound")); ?>"; },
195  inputTooShort: function (input) {
196  var n = input.minimum;
197  /*console.log(input);
198  console.log(input.minimum);*/
199  if (n > 1) return "<?php echo dol_escape_js($langs->transnoentitiesnoconv("Select2Enter")); ?> " + n + " <?php echo dol_escape_js($langs->transnoentitiesnoconv("Select2MoreCharacters")); ?>";
200  else return "<?php echo dol_escape_js($langs->transnoentitiesnoconv("Select2Enter")); ?> " + n + " <?php echo dol_escape_js($langs->transnoentitiesnoconv("Select2MoreCharacter")); ?>"
201  },
202  loadMore: function (pageNumber) { return "<?php echo dol_escape_js($langs->transnoentitiesnoconv("Select2LoadingMoreResults")); ?>"; },
203  searching: function () { return "<?php echo dol_escape_js($langs->transnoentitiesnoconv("Select2SearchInProgress")); ?>"; }
204 };
205 
206 
211 // Returns an object given an id
212 function getObjectFromID(id){
213  var theObject;
214  if(document.getElementById)
215  theObject=document.getElementById(id);
216  else
217  theObject=document.all[id];
218  return theObject;
219 }
220 
221 // Called after selection of a date to save details into detailed fields
222 function dpChangeDay(dateFieldID, format)
223 {
224  //showDP.datefieldID=dateFieldID;
225  console.log("Call dpChangeDay, we save date into detailed fields from format = "+format);
226 
227  var thefield=getObjectFromID(dateFieldID);
228  var thefieldday=getObjectFromID(dateFieldID+"day");
229  var thefieldmonth=getObjectFromID(dateFieldID+"month");
230  var thefieldyear=getObjectFromID(dateFieldID+"year");
231 
232  var date=getDateFromFormat(thefield.value, format);
233  //console.log(date);
234  if (date)
235  {
236  thefieldday.value=date.getDate();
237  if(thefieldday.onchange) thefieldday.onchange.call(thefieldday);
238  thefieldmonth.value=date.getMonth()+1;
239  if(thefieldmonth.onchange) thefieldmonth.onchange.call(thefieldmonth);
240  thefieldyear.value=date.getFullYear();
241  if(thefieldyear.onchange) thefieldyear.onchange.call(thefieldyear);
242  }
243  else
244  {
245  thefieldday.value='';
246  if(thefieldday.onchange) thefieldday.onchange.call(thefieldday);
247  thefieldmonth.value='';
248  if(thefieldmonth.onchange) thefieldmonth.onchange.call(thefieldmonth);
249  thefieldyear.value='';
250  if(thefieldyear.onchange) thefieldyear.onchange.call(thefieldyear);
251  }
252 }
253 
254 /*
255  * =================================================================
256  * Function:
257  * formatDate (javascript object Date(), format) Purpose: Returns a date in the
258  * output format specified. The format string can use the following tags: Field |
259  * Tags -------------+------------------------------- Year | yyyy (4 digits), yy
260  * (2 digits) Month | MM (2 digits) Day of Month | dd (2 digits) Hour (1-12) |
261  * hh (2 digits) Hour (0-23) | HH (2 digits) Minute | mm (2 digits) Second | ss
262  * (2 digits) Author: Laurent Destailleur Author: Matelli (see
263  * http://matelli.fr/showcases/patchs-dolibarr/update-date-input-in-action-form.html)
264  * Licence: GPL
265  * ==================================================================
266  */
267 function formatDate(date,format)
268 {
269  // alert('formatDate date='+date+' format='+format);
270 
271  // Force parametres en chaine
272  format=format+"";
273 
274  var result="";
275 
276  var year=date.getYear()+""; if (year.length < 4) { year=""+(year-0+1900); }
277  var month=date.getMonth()+1;
278  var day=date.getDate();
279  var hour=date.getHours();
280  var minute=date.getMinutes();
281  var seconde=date.getSeconds();
282 
283  var i=0;
284  while (i < format.length)
285  {
286  c=format.charAt(i); // Recupere char du format
287  var substr = '';
288  j=i;
289  while ((format.charAt(j)==c) && (j < format.length)) // Recupere char successif identiques
290  {
291  substr += format.charAt(j++);
292  }
293 
294  // alert('substr='+substr);
295  if (substr == 'yyyy') { result=result+year; }
296  else if (substr == 'yy') { result=result+year.substring(2,4); }
297  else if (substr == 'M') { result=result+month; }
298  else if (substr == 'MM') { result=result+(month<1||month>9?"":"0")+month; }
299  else if (substr == 'd') { result=result+day; }
300  else if (substr == 'dd') { result=result+(day<1||day>9?"":"0")+day; }
301  else if (substr == 'hh') { if (hour > 12) hour-=12; result=result+(hour<0||hour>9?"":"0")+hour; }
302  else if (substr == 'HH') { result=result+(hour<0||hour>9?"":"0")+hour; }
303  else if (substr == 'mm') { result=result+(minute<0||minute>9?"":"0")+minute; }
304  else if (substr == 'ss') { result=result+(seconde<0||seconde>9?"":"0")+seconde; }
305  else { result=result+substr; }
306 
307  i+=substr.length;
308  }
309 
310  // alert(result);
311  return result;
312 }
313 
314 
315 /*
316  * =================================================================
317  * Function: getDateFromFormat(date_string, format_string)
318  * Purpose: This function takes a date string and a format string.
319  * It parses the date string with format and it
320  * returns the date as a javascript Date() object. If date does not match
321  * format, it returns 0. The format string can use the following tags:
322  * Field | Tags
323  * -------------+-----------------------------------
324  * Year | yyyy (4 digits), yy (2 digits)
325  * Month | MM (2 digits)
326  * Day of Month | dd (2 digits)
327  * Hour (1-12) | hh (2 digits)
328  * Hour (0-23) | HH (2 digits)
329  * Minute | mm (2 digits)
330  * Second | ss (2 digits)
331  * Author: Laurent Destailleur
332  * Licence: GPL
333  * ==================================================================
334  */
335 function getDateFromFormat(val,format)
336 {
337  // alert('getDateFromFormat val='+val+' format='+format);
338 
339  // Force parametres en chaine
340  val=val+"";
341  format=format+"";
342 
343  if (val == '') return 0;
344 
345  var now=new Date();
346  var year=now.getYear(); if (year.length < 4) { year=""+(year-0+1900); }
347  var month=now.getMonth()+1;
348  var day=now.getDate();
349  var hour=now.getHours();
350  var minute=now.getMinutes();
351  var seconde=now.getSeconds();
352 
353  var i=0;
354  var d=0; // -d- follows the date string while -i- follows the format
355  // string
356 
357  while (i < format.length)
358  {
359  c=format.charAt(i); // Recupere char du format
360  substr="";
361  j=i;
362  while ((format.charAt(j)==c) && (j < format.length)) // Recupere char
363  // successif
364  // identiques
365  {
366  substr += format.charAt(j++);
367  }
368 
369  // alert('substr='+substr);
370  if (substr == "yyyy") year=getIntegerInString(val,d,4,4);
371  if (substr == "yy") year=""+(getIntegerInString(val,d,2,2)-0+1900);
372  if (substr == "MM" ||substr == "M")
373  {
374  month=getIntegerInString(val,d,1,2);
375  if (month) d -= 2- month.length;
376  }
377  if (substr == "dd")
378  {
379  day=getIntegerInString(val,d,1,2);
380  if (day) d -= 2- day.length;
381  }
382  if (substr == "HH" ||substr == "hh" )
383  {
384  hour=getIntegerInString(val,d,1,2);
385  if (dhouray) d -= 2- hour.length;
386  }
387  if (substr == "mm"){
388  minute=getIntegerInString(val,d,1,2);
389  if (minute) d -= 2- minute.length;
390  }
391  if (substr == "ss")
392  {
393  seconde=getIntegerInString(val,d,1,2);
394  if (seconde) d -= 2- seconde.length;
395  }
396 
397  i+=substr.length;
398  d+=substr.length;
399  }
400 
401  // Check if format param are ok
402  if (year==null||year<1) { return 0; }
403  if (month==null||(month<1)||(month>12)) { return 0; }
404  if (day==null||(day<1)||(day>31)) { return 0; }
405  if (hour==null||(hour<0)||(hour>24)) { return 0; }
406  if (minute==null||(minute<0)||(minute>60)) { return 0; }
407  if (seconde==null||(seconde<0)||(seconde>60)) { return 0; }
408 
409  // alert(year+' '+month+' '+day+' '+hour+' '+minute+' '+seconde);
410  return new Date(year,month-1,day,hour,minute,seconde);
411 }
412 
413 /*
414  * =================================================================
415  * Function: stringIsInteger(string)
416  * Purpose: Return true if string is an integer
417  * ==================================================================
418  */
419 function stringIsInteger(str)
420 {
421  var digits="1234567890";
422  for (var i=0; i < str.length; i++)
423  {
424  if (digits.indexOf(str.charAt(i))==-1)
425  {
426  return false;
427  }
428  }
429  return true;
430 }
431 
432 /*
433  * =================================================================
434  * Function: getIntegerInString(string,pos,minlength,maxlength)
435  * Purpose: Return part of string from position i that is integer
436  * ==================================================================
437  */
438 function getIntegerInString(str,i,minlength,maxlength)
439 {
440  for (var x=maxlength; x>=minlength; x--)
441  {
442  var substr=str.substring(i,i+x);
443  if (substr.length < minlength) { return null; }
444  if (stringIsInteger(substr)) { return substr; }
445  }
446  return null;
447 }
448 
449 
450 /*
451  * =================================================================
452  * Purpose: Clean string to have it url encoded
453  * Input: s
454  * Author: Laurent Destailleur
455  * Licence: GPL
456  * ==================================================================
457  */
458 function urlencode(s) {
459  var news = s;
460  news = news.replace(/\+/gi,'%2B');
461  news = news.replace(/&/gi,'%26');
462  return news;
463 }
464 
465 /*
466  * =================================================================
467  * Purpose: Clean string to get a HTML coded string.
468  * Input: s
469  * Author: Laurent Destailleur
470  * Licence: GPL
471  * ==================================================================
472  */
473 function htmlEntityDecodeJs(inp){
474  var replacements = {'&lt;':'<','&gt;':'>','&sol;':'/','&quot;':'"','&apos;':'\'','&amp;':'&','&nbsp;':' '};
475  if (inp) {
476  for(var r in replacements){
477  inp = inp.replace(new RegExp(r,'g'),replacements[r]);
478  }
479  return inp.replace(/&#(\d+);/g, function(match, dec) {
480  return String.fromCharCode(dec);
481  });
482  } else {
483  return '';
484  }
485 }
486 
487 
488 /*
489  * =================================================================
490  * Purpose: Applique un delai avant execution. Used for autocompletion of companies.
491  * Input: funct, delay
492  * Author: Regis Houssin
493  * Licence: GPL
494  * ==================================================================
495  */
496  function ac_delay(funct,delay) {
497  // delay before start of action
498  setTimeout(funct,delay);
499 }
500 
501 
502 /*
503  * =================================================================
504  * Purpose:
505  * Clean values of a "Sortable.serialize". Used by drag and drop.
506  * Input: expr
507  * Author: Regis Houssin
508  * Licence: GPL
509  * ==================================================================
510  */
511 function cleanSerialize(expr) {
512  if (typeof(expr) != 'string') {
513  return '';
514  }
515  var reg = new RegExp("(&)", "g");
516  var reg2 = new RegExp("[^A-Z0-9,]", "g");
517  var liste1 = expr.replace(reg, ",");
518  return liste1.replace(reg2, "");
519 }
520 
521 
522 /*
523  * =================================================================
524  * Purpose: Display a temporary message in input text fields (For showing help message on
525  * input field).
526  * Input: fieldId
527  * Input: message
528  * Author: Regis Houssin
529  * Licence: GPL
530  * ==================================================================
531  */
532 function displayMessage(fieldId,message) {
533  var textbox = document.getElementById(fieldId);
534  if (textbox.value == '') {
535  textbox.style.color = 'grey';
536  textbox.value = message;
537  }
538 }
539 
540 /*
541  * =================================================================
542  * Purpose: Hide a temporary message in input text fields (For showing help message on
543  * input field).
544  * Input: fiedId
545  * Input: message
546  * Author: Regis Houssin
547  * Licence: GPL
548  * ==================================================================
549  */
550 function hideMessage(fieldId,message) {
551  var textbox = document.getElementById(fieldId);
552  textbox.style.color = 'black';
553  if (textbox.value == message) textbox.value = '';
554 }
555 
556 
557 /*
558  * Used by button to set on/off.
559  * Call url then make complementary action (like show/hide, enable/disable or set another option).
560  *
561  * @param string url Url (warning: as any url called in ajax mode, the url called here must not renew the token)
562  * @param string code Code
563  * @param string intput Array of complementary actions to do if success
564  * @param int entity Entity
565  * @param int strict Strict
566  * @param int forcereload Force reload
567  * @param int userid User id
568  * @param int value Value to set
569  * @param string token Token
570  * @retun boolean
571  */
572 function setConstant(url, code, input, entity, strict, forcereload, userid, token, value) {
573  var saved_url = url; /* avoid undefined url */
574  $.post( url, {
575  action: "set",
576  name: code,
577  entity: entity,
578  token: token,
579  value: value
580  },
581  function() { /* handler for success of post */
582  console.log("Ajax url request to set constant is a success. Make complementary actions and then forcereload="+forcereload+" value="+value);
583  if (value == 0) {
584  $("#set_" + code).show();
585  $("#del_" + code).hide();
586  } else {
587  $("#set_" + code).hide();
588  $("#del_" + code).show();
589  }
590  $.each(input, function(type, data) {
591  // Enable another element
592  if (type == "disabled" && strict != 1) {
593  $.each(data, function(key, value) {
594  var newvalue=((value.search("^#") < 0 && value.search("^\.") < 0) ? "#" : "") + value;
595  $(newvalue).removeAttr("disabled");
596  if ($(newvalue).hasClass("butActionRefused") == true) {
597  $(newvalue).removeClass("butActionRefused");
598  $(newvalue).addClass("butAction");
599  }
600  });
601  } else if (type == "enabled") {
602  $.each(data, function(key, value) {
603  var newvalue=((value.search("^#") < 0 && value.search("^\.") < 0) ? "#" : "") + value;
604  if (strict == 1)
605  $(newvalue).removeAttr("disabled");
606  else
607  $(newvalue).attr("disabled", true);
608  if ($(newvalue).hasClass("butAction") == true) {
609  $(newvalue).removeClass("butAction");
610  $(newvalue).addClass("butActionRefused");
611  }
612  });
613  // Show another element
614  } else if (type == "showhide" || type == "show") {
615  $.each(data, function(key, value) {
616  var newvalue=((value.search("^#") < 0 && value.search("^\.") < 0) ? "#" : "") + value;
617  $(newvalue).show();
618  });
619  // Set another constant
620  } else if (type == "set") {
621  $.each(data, function(key, value) {
622  $("#set_" + key).hide();
623  $("#del_" + key).show();
624  $.post( saved_url, {
625  action: "set",
626  name: key,
627  value: value,
628  entity: entity,
629  token: token
630  });
631  });
632  }
633  });
634  if (forcereload) {
635  var url = window.location.href;
636  if (url.indexOf('dol_resetcache') < 0) {
637  if (url.indexOf('?') > -1) {
638  url = url + "&dol_resetcache=1";
639  } else {
640  url = url + "?dol_resetcache=1";
641  }
642  }
643  var page_y = $(document).scrollTop();
644  url = url.replace(/page_y=\d+/g, '');
645  if (page_y > 0) {
646  if (url.indexOf('?') > -1) {
647  url = url + "&page_y="+page_y;
648  } else {
649  url = url + "?page_y="+page_y;
650  }
651  }
652  url = url.replace(/&&+/, '&');
653  console.log("url ro redirect = "+url);
654 
655  window.location.href = url;
656  //location.reload();
657  return false;
658  }
659  }).fail(function(error) { console.log("Error, we force reload"); location.reload(); }); /* When it fails, we always force reload to have setEventErrorMessages in session visible */
660 
661  return true;
662 }
663 
664 /*
665  * Used by button to set on/off
666  * Call url then make complementary action (like show/hide, enable/disable or set another option).
667  *
668  * @param {string} url Url (warning: as any url called in ajax mode, the url called here must not renew the token)
669  * @param {string} code Code
670  * @param {string} intput Array of complementary actions to do if success
671  * @param {int} entity Entity
672  * @param {int} strict Strict
673  * @param {int} forcereload Force reload
674  * @param {int} userid User id
675  * @param {string} token Token
676  * @return boolean
677  */
678 function delConstant(url, code, input, entity, strict, forcereload, userid, token) {
679  var saved_url = url; /* avoid undefined url */
680  $.post( url, {
681  action: "del",
682  name: code,
683  entity: entity,
684  token: token
685  },
686  function() {
687  console.log("Ajax url request to delete constant is success. Make complementary actions and then forcereload="+forcereload);
688  $("#del_" + code).hide();
689  $("#set_" + code).show();
690  $.each(input, function(type, data) {
691  // Disable another element
692  if (type == "disabled") {
693  $.each(data, function(key, value) {
694  var newvalue=((value.search("^#") < 0 && value.search("^\.") < 0) ? "#" : "") + value;
695  $(newvalue).attr("disabled", true);
696  if ($(newvalue).hasClass("butAction") == true) {
697  $(newvalue).removeClass("butAction");
698  $(newvalue).addClass("butActionRefused");
699  }
700  });
701  } else if (type == "enabled" && strict != 1) {
702  $.each(data, function(key, value) {
703  var newvalue=((value.search("^#") < 0 && value.search("^\.") < 0) ? "#" : "") + value;
704  $(newvalue).removeAttr("disabled");
705  if ($(newvalue).hasClass("butActionRefused") == true) {
706  $(newvalue).removeClass("butActionRefused");
707  $(newvalue).addClass("butAction");
708  }
709  });
710  // Hide another element
711  } else if (type == "showhide" || type == "hide") {
712  $.each(data, function(key, value) {
713  var newvalue=((value.search("^#") < 0 && value.search("^\.") < 0) ? "#" : "") + value;
714  $(newvalue).hide();
715  });
716  // Delete another constant
717  } else if (type == "del") {
718  $.each(data, function(key, value) {
719  $("#del_" + value).hide();
720  $("#set_" + value).show();
721  $.post( saved_url, {
722  action: "del",
723  name: value,
724  entity: entity,
725  token: token
726  });
727  });
728  }
729  });
730  if (forcereload) {
731  var url = window.location.href;
732  if (url.indexOf('dol_resetcache') < 0) {
733  if (url.indexOf('?') > -1) {
734  url = url + "&dol_resetcache=1";
735  } else {
736  url = url + "?dol_resetcache=1";
737  }
738  }
739  var page_y = $(document).scrollTop();
740  url = url.replace(/page_y=\d+/g, '');
741  if (page_y > 0) {
742  if (url.indexOf('?') > -1) {
743  url = url + "&page_y="+page_y;
744  } else {
745  url = url + "?page_y="+page_y;
746  }
747  }
748  url = url.replace(/&&+/, '&');
749  console.log("url ro redirect = "+url);
750 
751  window.location.href = url;
752  //location.reload();
753  return false;
754  }
755  }).fail(function(error) { console.log("Error, we force reload"); location.reload(); }); /* When it fails, we always force reload to have setEventErrorMessages in session visible */
756 
757  return true;
758 }
759 
760 /*
761  * Call the setConstant or delConstant but with a confirmation before.
762  * Used by button to set on/off.
763  *
764  * @param string action Action
765  * @param string url Url
766  * @param string code Code
767  * @param string intput Array of complementary actions to do if success
768  * @param string box Box
769  * @param int entity Entity
770  * @param int yesButton yesButton
771  * @param int noButton noButton
772  * @param int strict Strict
773  * @param int userid User id
774  * @param string token Token
775  * @return boolean
776  */
777 function confirmConstantAction(action, url, code, input, box, entity, yesButton, noButton, strict, userid, token) {
778  var boxConfirm = box;
779  $("#confirm_" + code)
780  .attr("title", boxConfirm.title)
781  .html(boxConfirm.content)
782  .dialog({
783  resizable: false,
784  height: 170,
785  width: 500,
786  modal: true,
787  buttons: [
788  {
789  id : 'yesButton_' + code,
790  text : yesButton,
791  click : function() {
792  if (action == "set") {
793  setConstant(url, code, input, entity, strict, 0, userid, token, 1);
794  } else if (action == "del") {
795  delConstant(url, code, input, entity, strict, 0, userid, token);
796  }
797  // Close dialog
798  $(this).dialog("close");
799  // Execute another method
800  if (boxConfirm.method) {
801  var fnName = boxConfirm.method;
802  if (window.hasOwnProperty(fnName)) {
803  window[fnName]();
804  }
805  }
806  }
807  },
808  {
809  id : 'noButton_' + code,
810  text : noButton,
811  click : function() {
812  $(this).dialog("close");
813  }
814  }
815  ]
816  });
817  // For information dialog box only, hide the noButton
818  if (boxConfirm.info) {
819  $("#noButton_" + code).button().hide();
820  }
821 
822  return true;
823 }
824 
825 
826 /*
827  * =================================================================
828  * This is to allow to transform all select box into ajax autocomplete box
829  * with just one line:
830  * $(function() { $( "#idofmylist" ).combobox(); });
831  * Do not use it on large combo boxes
832  * =================================================================
833  */
834 (function( $ ) {
835  $.widget( "ui.combobox", {
836  options: {
837  minLengthToAutocomplete: 0
838  },
839  _create: function() {
840  var savMinLengthToAutocomplete = this.options.minLengthToAutocomplete;
841  var self = this,
842  select = this.element.hide(),
843  selected = select.children( ":selected" ),
844  value = selected.val() ? selected.text() : "";
845  var input = this.input = $( "<input>" )
846  .insertAfter( select )
847  .val( value )
848  .attr('id', 'inputautocomplete'+select.attr('id'))
849  .autocomplete({
850  delay: 0,
851  minLength: this.options.minLengthToAutocomplete,
852  source: function( request, response ) {
853  var matcher = new RegExp( $.ui.autocomplete.escapeRegex(request.term), "i" );
854  response( select.children( "option:enabled" ).map(function() {
855  var text = $( this ).text();
856  if ( this.value && ( !request.term || matcher.test(text) ) )
857  return {
858  label: text.replace(
859  new RegExp(
860  "(?![^&;]+;)(?!<[^<>]*)(" +
861  $.ui.autocomplete.escapeRegex(request.term) +
862  ")(?![^<>]*>)(?![^&;]+;)", "gi"
863  ), "<strong>$1</strong>" ),
864  value: text,
865  option: this
866  };
867  }) );
868  },
869  select: function( event, ui ) {
870  ui.item.option.selected = true;
871  self._trigger( "selected", event, {
872  item: ui.item.option
873  });
874  },
875  change: function( event, ui ) {
876  if ( !ui.item ) {
877  var matcher = new RegExp( "^" + $.ui.autocomplete.escapeRegex( $(this).val() ) + "$", "i" ),
878  valid = false;
879  select.children( "option" ).each(function() {
880  if ( $( this ).text().match( matcher ) ) {
881  this.selected = valid = true;
882  return false;
883  }
884  });
885  if ( !valid ) {
886  // remove invalid value, as it didnt match anything
887  $( this ).val( "" );
888  select.val( "" );
889  input.data("ui-autocomplete").term = "";
890  return false;
891  }
892  }
893  }
894  })
895  .addClass( "ui-widget ui-widget-content ui-corner-left dolibarrcombobox" );
896 
897  input.data("ui-autocomplete")._renderItem = function( ul, item ) {
898  return $("<li>")
899  .data( "ui-autocomplete-item", item ) // jQuery UI > 1.10.0
900  .append( "<a>" + item.label + "</a>" )
901  .appendTo( ul );
902  };
903 
904  this.button = $( "<button type=\'button\'>&nbsp;</button>" )
905  .attr( "tabIndex", -1 )
906  .attr( "title", "Show All Items" )
907  .insertAfter( input )
908  .button({
909  icons: {
910  primary: "ui-icon-triangle-1-s"
911  },
912  text: false
913  })
914  .removeClass( "ui-corner-all" )
915  .addClass( "ui-corner-right ui-button-icon" )
916  .click(function() {
917  // close if already visible
918  if ( input.autocomplete( "widget" ).is( ":visible" ) ) {
919  input.autocomplete( "close" );
920  return;
921  }
922 
923  // pass empty string as value to search for, displaying all results
924  input.autocomplete({ minLength: 0 });
925  input.autocomplete( "search", "" );
926  input.autocomplete({ minLength: savMinLengthToAutocomplete });
927  input.focus();
928  });
929  },
930 
931  destroy: function() {
932  this.input.remove();
933  this.button.remove();
934  this.element.show();
935  $.Widget.prototype.destroy.call( this );
936  }
937  });
938 })( jQuery );
939 
940 
941 
948 function copyToClipboard(text,text2)
949 {
950  text = text.replace(/<br>/g,"\n");
951  var newElem = '<textarea id="coordsforpopup" style="border: none; width: 90%; height: 120px;">'+text+'</textarea><br><br>'+text2;
952  /* alert(newElem); */
953  $("#dialogforpopup").html(newElem);
954  $("#dialogforpopup").dialog();
955  $("#coordsforpopup").select();
956 
957  return false;
958 }
959 
960 
969 function newpopup(url, title) {
970  var argv = newpopup.arguments;
971  var argc = newpopup.arguments.length;
972  var tmp = url;
973  console.log("newpopup "+argv[2]+" "+argv[3]);
974  var l = (argc > 2) ? argv[2] : 600;
975  var h = (argc > 3) ? argv[3] : 400;
976  var left = (screen.width - l)/2;
977  var top = (screen.height - h)/2;
978  var wfeatures = "directories=0,menubar=0,status=0,resizable=0,scrollbars=1,toolbar=0,width=" + l +",height=" + h + ",left=" + left + ",top=" + top;
979  fen=window.open(tmp,title,wfeatures);
980 
981  return false;
982 }
983 
994 function document_preview(file, type, title)
995 {
996  var ValidImageTypes = ["image/gif", "image/jpeg", "image/png", "image/webp"];
997  var showOriginalSizeButton = false;
998 
999  console.log("document_preview A click was done. file="+file+", type="+type+", title="+title);
1000 
1001  if ($.inArray(type, ValidImageTypes) < 0) {
1002  /* Not an image */
1003  var width='85%';
1004  var object_width='100%';
1005  var height = ($( window ).height() - 60) * 0.90;
1006  var object_height='98%';
1007 
1008  show_preview('notimage');
1009 
1010  } else {
1011  /* This is an image */
1012  var object_width=0;
1013  var object_height=0;
1014 
1015  var img = new Image();
1016 
1017  img.onload = function() {
1018  object_width = this.width;
1019  object_height = this.height;
1020 
1021  width = $( window ).width()*0.90;
1022  console.log("object_width="+object_width+" window width="+width);
1023  if(object_width < width){
1024  console.log("Object width is small, we set width of popup according to image width.");
1025  width = object_width + 30
1026  }
1027  height = $( window ).height()*0.85;
1028  console.log("object_height="+object_height+" window height="+height);
1029  if(object_height < height){
1030  console.log("Object height is small, we set height of popup according to image height.");
1031  height = object_height + 80
1032  }
1033  else
1034  {
1035  showOriginalSizeButton = true;
1036  }
1037 
1038  show_preview('image');
1039 
1040  };
1041  img.src = file;
1042 
1043  }
1044 
1045  function show_preview(mode) {
1046  /* console.log("mode="+mode+" file="+file+" type="+type+" width="+width+" height="+height); */
1047  var newElem = '<object name="objectpreview" data="'+file+'" type="'+type+'" width="'+object_width+'" height="'+object_height+'" param="noparam"></object>';
1048 
1049  optionsbuttons = {}
1050  if (mode == 'image' && showOriginalSizeButton)
1051  {
1052  optionsbuttons = {
1053  "<?php echo dol_escape_js($langs->transnoentitiesnoconv("OriginalSize")); ?>": function() { console.log("Click on original size"); jQuery(".ui-dialog-content.ui-widget-content > object").css({ "max-height": "none" }); },
1054  "<?php echo dol_escape_js($langs->transnoentitiesnoconv("CloseWindow")); ?>": function() { $( this ).dialog( "close" ); }
1055  };
1056  }
1057 
1058  $("#dialogforpopup").html(newElem);
1059 
1060  $("#dialogforpopup").dialog({
1061  closeOnEscape: true,
1062  resizable: true,
1063  width: width,
1064  height: height,
1065  modal: true,
1066  title: title,
1067  buttons: optionsbuttons
1068  });
1069 
1070  if (showOriginalSizeButton)
1071  {
1072  jQuery(".ui-dialog-content.ui-widget-content > object").css({ "max-height": "100%", "width": "auto", "margin-left": "auto", "margin-right": "auto", "display": "block" });
1073  }
1074  }
1075 }
1076 
1077 /*
1078  * Provide a function to get an URL GET parameter in javascript
1079  *
1080  * @param name Name of parameter
1081  * @param valueifnotfound Value if not found
1082  * @return string Value
1083  */
1084 function getParameterByName(name, valueifnotfound)
1085 {
1086  name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
1087  var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
1088  results = regex.exec(location.search);
1089  return results === null ? valueifnotfound : decodeURIComponent(results[1].replace(/\+/g, " "));
1090 }
1091 
1092 
1093 // Code in the public domain from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round
1094 (function() {
1103  function decimalAdjust(type, value, exp) {
1104  // If the exp is undefined or zero...
1105  if (typeof exp === 'undefined' || +exp === 0) {
1106  return Math[type](value);
1107  }
1108  value = +value;
1109  exp = +exp;
1110  // If the value is not a number or the exp is not an integer...
1111  if (isNaN(value) || !(typeof exp === 'number' && exp % 1 === 0)) {
1112  return NaN;
1113  }
1114  // Shift
1115  value = value.toString().split('e');
1116  value = Math[type](+(value[0] + 'e' + (value[1] ? (+value[1] - exp) : -exp)));
1117  // Shift back
1118  value = value.toString().split('e');
1119  return +(value[0] + 'e' + (value[1] ? (+value[1] + exp) : exp));
1120  }
1121 
1122  // Decimal round
1123  if (!Math.round10) {
1124  Math.round10 = function(value, exp) {
1125  return decimalAdjust('round', value, exp);
1126  };
1127  }
1128  // Decimal floor
1129  if (!Math.floor10) {
1130  Math.floor10 = function(value, exp) {
1131  return decimalAdjust('floor', value, exp);
1132  };
1133  }
1134  // Decimal ceil
1135  if (!Math.ceil10) {
1136  Math.ceil10 = function(value, exp) {
1137  return decimalAdjust('ceil', value, exp);
1138  };
1139  }
1140 })();
1141 
1142 // Another solution, easier, to build a javascript rounding function
1143 function dolroundjs(number, decimals) { return +(Math.round(number + "e+" + decimals) + "e-" + decimals); }
1144 
1162 function pricejs(amount, mode = 'MT', currency_code = '', force_locale = '') {
1163  var main_max_dec_shown = <?php echo (int) str_replace('.', '', getDolGlobalInt('MAIN_MAX_DECIMALS_SHOWN')); ?>;
1164  var main_rounding_unit = <?php echo (int) getDolGlobalInt('MAIN_MAX_DECIMALS_UNIT'); ?>;
1165  var main_rounding_tot = <?php echo (int) getDolGlobalInt('MAIN_MAX_DECIMALS_TOT'); ?>;
1166  var main_decimal_separator = <?php echo json_encode($dec) ?>;
1167  var main_thousand_separator = <?php echo json_encode($thousand) ?>;
1168  var locale_code = force_locale || <?php echo json_encode($langs->defaultlang) ?>;
1169  var amountAsLocalizedString;
1170  var useIntl = Boolean(Intl && Intl.NumberFormat);
1171  var nDigits;
1172  if (currency_code === 'auto') currency_code = <?php echo json_encode($conf->currency) ?>;
1173 
1174  if (mode === 'MU') nDigits = main_rounding_unit;
1175  else if (mode === 'MT') nDigits = main_rounding_tot;
1176  else return 'Bad value for parameter mode';
1177 
1178  if (useIntl) {
1179  // simple version: let the browser decide how to format the number using the provided language / currency
1180  // parameters
1181  var formattingOptions = {
1182  minimumFractionDigits: nDigits,
1183  maximumFractionDigits: nDigits
1184  };
1185  if (currency_code) {
1186  formattingOptions['style'] = 'currency';
1187  formattingOptions['currency'] = currency_code;
1188  }
1189  return Intl.NumberFormat(locale_code.replace('_', '-'), formattingOptions).format(amount);
1190  }
1191 
1192  // No Intl -> attempt to format the number in a way similar to Dolibarr PHP's `price()` function
1193  amountAsLocalizedString = amount.toFixed(nDigits).replace(
1194  /((?!^)(?:\d{3})*)(?:\.(\d+))?$/,
1195  (fullMatch, digitsByThree, decimals) =>
1196  digitsByThree.replace(
1197  /\d{3}/g,
1198  (groupOfThree) => main_thousand_separator + groupOfThree
1199  ) + (decimals !== undefined ? main_decimal_separator + decimals : '')
1200  ).replace(/ /, ' ');
1201  if (!currency_code) return amountAsLocalizedString;
1202 
1203  // print with currency
1204  var currency_symbol = currency_code;
1205 
1206  // codes of languages / currencies where the symbol must be placed before the amount
1207  var currencyBeforeAmountCodes = {
1208  currency: ['AUD', 'CAD', 'CNY', 'COP', 'CLP', 'GBP', 'HKD', 'MXN', 'PEN', 'USD'],
1209  language: ['nl_NL']
1210  };
1211 
1212  if (currencyCache[currency_code]
1213  && currencyCache[currency_code]['unicode']
1214  && currencyCache[currency_code]['unicode'].length) {
1215  currency_symbol = currencyCache[currency_code]['unicode'].reduce(function (res, cur) {return res + cur}, '');
1216  }
1217 
1218  if (currencyBeforeAmountCodes.currency.indexOf(currency_code) >= 0
1219  || currencyBeforeAmountCodes.language.indexOf(locale_code)) {
1220  // if we use a language or a currency where the symbol is placed before the amount
1221  return currency_symbol + amountAsLocalizedString;
1222  }
1223 
1224  // by default: currency symbol after the amount
1225  return amountAsLocalizedString + ' ' + currency_symbol;
1226 }
1227 
1235 function price2numjs(amount) {
1236  if (amount == '') return '';
1237 
1238  var dec = <?php echo json_encode($dec) ?>;
1239  var thousand = <?php echo json_encode($thousand) ?>;
1240 
1241  var main_max_dec_shown = <?php echo (int) str_replace('.', '', getDolGlobalInt('MAIN_MAX_DECIMALS_SHOWN')); ?>;
1242  var main_rounding_unit = <?php echo (int) getDolGlobalInt('MAIN_MAX_DECIMALS_UNIT'); ?>;
1243  var main_rounding_tot = <?php echo (int) getDolGlobalInt('MAIN_MAX_DECIMALS_TOT'); ?>;
1244 
1245  var amount = amount.toString();
1246 
1247  // rounding for unit price
1248  var rounding = main_rounding_unit;
1249  var pos = amount.indexOf(dec);
1250  var decpart = '';
1251  if (pos >= 0) {
1252  decpart = amount.substring(pos + 1).replace('/0+$/i', ''); // Remove 0 for decimal part
1253  }
1254  var nbdec = decpart.length;
1255  if (nbdec > rounding) {
1256  rounding = nbdec;
1257  }
1258  // If rounding higher than max shown
1259  if (rounding > main_max_dec_shown) rounding = main_max_dec_shown;
1260  if (thousand != ',' && thousand != '.') amount = amount.replace(',', '.');
1261  amount = amount.replace(' ', ''); // To avoid spaces
1262  amount = amount.replace(thousand, ''); // Replace of thousand before replace of dec to avoid pb if thousand is .
1263  amount = amount.replace(dec, '.');
1264 
1265  //console.log("amount before="+amount+" rouding="+rounding)
1266  var res = Math.round10(amount, - rounding);
1267  // Other solution is
1268  // var res = dolroundjs(amount, rounding)
1269 
1270  console.log("price2numjs text="+amount+" return="+res);
1271 
1272  return res;
1273 }
1274 
1275 
1276 <?php
1277 if (empty($conf->global->MAIN_DISABLE_JQUERY_JNOTIFY) && !defined('DISABLE_JQUERY_JNOTIFY')) {
1278  ?>
1279 // Defined properties for JNotify
1280 $(document).ready(function() {
1281  if (typeof $.jnotify == 'function') {
1282  $.jnotify.setup({
1283  delay: 3000 // the default time to show each notification (in milliseconds)
1284  , sticky: false // determines if the message should be considered "sticky" (user must manually close notification)
1285  , closeLabel: "&times;" // the HTML to use for the "Close" link
1286  , showClose: true // determines if the "Close" link should be shown if notification is also sticky
1287  , fadeSpeed: 1000 // the speed to fade messages out (in milliseconds)
1288  , slideSpeed: 250 // the speed used to slide messages out (in milliseconds)
1289  , classContainer: "jnotify-container"
1290  , classNotification: "jnotify-notification"
1291  , classBackground: "jnotify-background"
1292  , classClose: "jnotify-close"
1293  , classMessage: "jnotify-message"
1294  , init: null // callback that occurs when the main jnotify container is created
1295  , create: null // callback that occurs when when the note is created (occurs just before appearing in DOM)
1296  , beforeRemove: null // callback that occurs when before the notification starts to fade away
1297  });
1298  }
1299 });
1300 <?php } ?>
1301 
1302 jQuery(document).ready(function() {
1303  // Force to hide menus when page is inside an iFrame so we can show any page into a dialog popup
1304  if (window.location && window.location.pathname.indexOf("externalsite/frametop.php") == -1 && window.location !== window.parent.location ) {
1305  console.log("Page is detected to be into an iframe, we hide by CSS the menus");
1306  // The page is in an iframe
1307  jQuery(".side-nav-vert, .side-nav, .websitebar").hide();
1308  jQuery(".id-container").css('width', '100%');
1309 
1310  }
1311 
1312  // Code to set tooltip on search field
1313  jQuery('table.liste tr.liste_titre_filter td.liste_titre input[name^="search"][type=text]:not("maxwidthdate")').attr('title', '<?php echo dol_escape_js($langs->transnoentities("SearchSyntaxTooltipForStringOrNum")) ?>');
1314 });
1315 
1316 
1317 /*
1318  * Hacky fix for a bug in select2 with jQuery 3.6.0's new nested-focus "protection"
1319  * see: https://github.com/select2/select2/issues/5993
1320  * see: https://github.com/jquery/jquery/issues/4382
1321  *
1322  * TODO: Recheck with the select2 GH issue and remove once this is fixed on their side
1323  */
1324 
1325 <?php
1326 if (empty($conf->global->MAIN_DISABLE_SELECT2_FOCUS_PROTECTION) && !defined('DISABLE_SELECT2_FOCUS_PROTECTION')) {
1327  ?>
1328 $(document).on('select2:open', (e) => {
1329  console.log("Execute the focus (click on combo or use space when on component");
1330  const target = $(e.target);
1331  if (target && target.length) {
1332  let id = target[0].id || target[0].name;
1333  if (id.substr(-2) == "[]") id = id.substr(0,id.length-2);
1334  document.querySelector('input[aria-controls*='+id+']').focus();
1335  }
1336 });
1337  <?php
1338 }
1339 ?>
1340 
1341 
1342 // End of lib_head.js.php
getDolGlobalInt($key, $default=0)
Return dolibarr global constant int value.
dol_escape_js($stringtoescape, $mode=0, $noescapebackslashn=0)
Returns text escaped for inclusion into javascript code.
if(empty($user->rights->takepos->run) &&!defined('INCLUDE_PHONEPAGE_FROM_PUBLIC_PAGE')) if((getDolGlobalString('TAKEPOS_PHONE_BASIC_LAYOUT')==1 && $conf->browser->layout=='phone')||defined('INCLUDE_PHONEPAGE_FROM_PUBLIC_PAGE')) fail($message)
Abort invoice creationg with a given error message.
Definition: invoice.php:88
getParameterByName(name, valueifnotfound)
copyToClipboard(text, text2)
Function to output a dialog box for copy/paste.
document_preview(file, type, title)
Function show document preview.
pricejs(amount, mode='MT', currency_code='', force_locale='')
Function similar to PHP price()
newpopup(url, title)
Show a popup HTML page.
price2numjs(amount)
Function similar to PHP price2num()
if(!defined('NOREQUIREMENU')) if(!empty(GETPOST('seteventmessages', 'alpha'))) if(!function_exists("llxHeader")) top_httphead($contenttype='text/html', $forcenocache=0)
Show HTTP header.
Definition: main.inc.php:1494
table tableforfield button
0 = Do not include form tag and submit button -1 = Do not include form tag but include submit button
Definition: style.css.php:848
if(preg_match('/crypted:/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
Definition: repair.php:120
$conf db name
Only used if Module[ID]Name translation string is not found.
Definition: repair.php:123
print *****$script_file(".$version.") pid code
! Closing after partial payment: discount_vat, badcustomer or badsupplier, bankcharge,...