'use strict'; var basePath = `${BASE_URL_SITE}/v1/`; var INTEGER_REGEXP = /^\-?\d+$/; var PIVA_REGEXP = /^\d{11,11}$/; var bootstrapDatepickerConfig = { format: "dd/mm/yyyy", todayBtn: "linked", language: "it", autoclose: true, orientation: 'auto bottom', startDate: '01-01-1900', endDate: '31-12-9999' }; var app = angular.module('app', ['ngResource', 'ngStorage', 'ngAnimate', 'ui.bootstrap', 'toaster', 'angularMoment','chart.js','daterangepicker']) .config(($sessionStorageProvider) => { $sessionStorageProvider.setKeyPrefix('movedelivery_'); }) .run(($rootScope, $http, $locale, amMoment, $sessionStorage, AuthService) => { amMoment.changeLocale('it'); const token = $('body').attr('data-token'); $sessionStorage.token = token; $http.defaults.headers.common['Authorization'] = `Basic ${token}`; //Inizializzo i dati per cui l'utente è authenticato lato server AuthService.Load(); }) //services .factory('AuthService', ($sessionStorage, $rootScope, Users, toaster) => { const service = {}; service.Load = () => { Users.getUserData().then((result) => { service.setUserData(result.data); }).catch((err) => { toaster.error("Errore", "Non è stato possibile recuperare l'utente, conttatare l'amministrazione!") }); }; service.setUserData = function (user) { $rootScope.authUser = user; $sessionStorage.authUser = user; }; service.getUserData = function () { return $sessionStorage.authUser; }; service.getInfo = function (param) { return $sessionStorage.authUser[param]; }; return service; }) .factory('socket', ($rootScope) => { // const wsUrl = 'http://localhost:3000'; const wsUrl = 'https://wsdev.movedelivery.it'; const token = 'Secret a5addff3637fd153b1301b84f1c768a0'; let socket = io.connect(wsUrl, { transportOptions: { polling: { extraHeaders: { Authorization: token, }, }, }, }); return { connection: function (callback) { socket.on('connect', () => { $rootScope.$apply(function () { callback(socket.id); }); }); }, on: function (eventName, callback) { socket.on(eventName, function () { let args = arguments; $rootScope.$apply(function () { callback.apply(socket, args); }); }); }, emit: function (eventName, data, callback) { socket.emit(eventName, data, function () { let args = arguments; $rootScope.$apply(function () { if (callback) { callback.apply(socket, args); } }); }); }, }; }) //Filters .filter("isNumeric", function () { return function (value) { if (value == null || value == 'null' || value == '' || !angular.isDefined(value)) return false; return (!isNaN(parseFloat(value)) && isFinite(value)); }; }) .filter('getById', function () { return function (input, id) { var i = 0, len = input.length; for (; i < len; i++) { if (+input[i].id == +id) { return input[i]; } } return null; } }) .filter('getBooleanValueOfCheck', function () { return function (input) { return input === '1' || input === true || input === 1; } }) .filter('getElementByKeyValue', function () { return function (elenco, chiaveDaCercare, valoraDaCercare) { if (elenco == undefined) return null; if (valoraDaCercare == null) return null; var value = null; angular.forEach(elenco, function (val) { if (val[chiaveDaCercare].toLowerCase() == valoraDaCercare.toLowerCase()) { value = val; } }); return value; } }) .filter('sanitize', function ($sce) { return function (htmlCode) { return $sce.trustAsHtml(htmlCode); } }) .filter("formattaInPrezzoUnitario", function ($filter) { return function (value, valuta) { value = String(value).replace(',', '.').replace(/[^\d.-]/g, ''); var num = $filter('number')(value, 2); if (valuta) return num + " €"; else return num; }; }) .filter('AddressEncode', function () { return function (comune, cap, provincia) { var str = ''; if (cap) str += cap; if (cap && comune) str += " - " + comune; else if (cap) str += comune; if (provincia) str += ' (' + provincia + ')'; return str; } }) .filter('contaElementiOggetto', function () { return function (input) { if (!angular.isDefined(input)) return 0; var i = 0; angular.forEach(input, function (val) { if (angular.isDefined(val) && val != '') i++; }); return i; } }) .filter("slashDataNoTime", function () { return function (data) { if (!angular.isDefined(data) || data == null) return; data = data.split("-"); data.reverse(); return data.join("/"); } }) .filter("unslashDataNoTime", function () { return function (data) { if (!angular.isDefined(data) || data == null) return; data = data.split("/"); data.reverse(); return data.join("-"); } }) .filter("slashDataWithTime", function () { return function (data, withtime) { withtime = (withtime === undefined) ? true : withtime; if (!angular.isDefined(data) || data == null) return; data = data.split(' '); let time = data[1]; data = data[0].split("-"); data.reverse(); if (withtime) return data.join("/") + " " + time; else return data.join("/"); } }) .filter("DataIsoFormat", function (moment) { return function (data, formatString) { if (angular.isUndefined(data)) return; formatString = formatString || 'DD/MM/YYYY'; return moment(data).format(formatString); } }) .filter("getTipoOperazione", function () { return function (data) { if (!angular.isDefined(data) || data == null) return ''; switch (data) { case 'NEW': return 'Nuova Attivazione'; case 'RINNOVO': return 'Rinnovo Licenza'; case 'CAMBIOVERSIONE': return 'Cambio Versione Licenza'; } } }) .filter('cleanZero', function ($filter) { return function (val) { if (val === undefined) return; if (!$filter('isNumeric')(parseFloat(val.replace(',', '.'))) || parseFloat(val.replace(',', '.')) == '0') return ''; else return val; } }) //Factory .factory('focus', function ($timeout, $window) { return function (id, selectText) { selectText = (angular.isDefined(selectText)) ? selectText : false; $timeout(function () { let element = $window.document.getElementById(id); if (element) { element.focus(); if (selectText) { element.select(); } } }); }; }) //Directive .directive('cleanZeroValue', function () { return { require: 'ngModel', link: function (scope, element, attrs, ngModelCtrl) { const value = parseFloat(ngModelCtrl.modelValue); if (value === 0) { ngModelCtrl.$setViewValue(''); ngModelCtrl.$render(); } } } }) .directive('integer', function () { return { require: 'ngModel', link: function (scope, elm, attrs, ctrl) { ctrl.$validators.integer = function (modelValue, viewValue) { if (ctrl.$isEmpty(modelValue)) { return true; } if (!INTEGER_REGEXP.test(viewValue)) { return false; } // it is invalid return true; }; } }; }) .directive('limitInput', function () { return { require: 'ngModel', link: function (scope, elem, attrs) { var limit = parseInt(attrs.limitInput); angular.element(elem).on("keypress", function (e) { if (e.charCode >= 39 && e.charCode <= 249) { //il controllo viene effettuato solo sui caratteri stampabili if (this.value.length >= limit) e.preventDefault(); } }); } }; }) .directive('partitaiva', function () { return { require: 'ngModel', link: function (scope, elm, attrs, ctrl) { ctrl.$validators.partitaiva = function (modelValue, viewValue) { let isValid = true; if (ctrl.$isEmpty(modelValue)) { return true; } if (!PIVA_REGEXP.test(viewValue)) { return false; } let s = 0; for (let i = 0; i <= 9; i += 2) s += ord(viewValue[i]) - ord('0'); for (let i = 1; i <= 9; i += 2) { let c = 2 * (ord(viewValue[i]) - ord('0')); if (c > 9) c = c - 9; s += c; } if ((10 - s % 10) % 10 !== ord(viewValue[10]) - ord('0')) { isValid = false; } return isValid; }; } }; function ord(string) { let str = string + '', code = str.charCodeAt(0); if (0xD800 <= code && code <= 0xDBFF) { let hi = code; if (str.length === 1) { return code; } let low = str.charCodeAt(1); return ((hi - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000; } if (0xDC00 <= code && code <= 0xDFFF) { // Low surrogate return code; } return code; } }) .directive('checkPiva', function (Licenze) { return { require: 'ngModel', scope: {idLicenza: '=', ngModel: '&'}, link: function (scope, elm, attrs, ctrl) { ctrl.$validators.checkPiva = function (modelValue, viewValue) { let isValid = true; const validFormat = ctrl.$validators.partitaiva(modelValue, viewValue); if (modelValue && (ctrl.$isEmpty(modelValue) || (modelValue + '').length !== 11 || !validFormat)) { return true; } if (!scope.idLicenza && (modelValue + '').length === 11) { Licenze.checkEsistenzaPiva(modelValue).then((res) => { isValid = !res.isActive; ctrl.$setValidity('checkPiva', isValid); console.log('res set Valitidity', res); }).catch(() => isValid = true); } return isValid; }; } }; }) .directive('identical', function () { return { require: "ngModel", scope: { otherModelValue: "=identical" }, link: function (scope, element, attributes, ngModel) { ngModel.$validators.identical = function (modelValue) { return modelValue == scope.otherModelValue; }; scope.$watch("otherModelValue", function () { ngModel.$validate(); }); } }; }) .directive('icheck', function icheck($timeout, $parse) { return { restrict: 'A', require: 'ngModel', link: function ($scope, element, $attrs) { return $timeout(function () { let form = null; const ngModelGetter = $parse($attrs['ngModel']); // let value = $parse($attrs['ngModel'])($scope); //Controlli per settare il form collegato come dirty quando cambia il valore if (angular.isDefined($attrs.form)) form = $parse($attrs['form'])($scope); $(element).iCheck({ checkboxClass: 'icheckbox_square-blue', radioClass: 'iradio_square-blue' }).on('ifChanged', function (event) { if ($(element).attr('type') === 'checkbox' && $attrs['ngModel']) { $scope.$apply(function () { return ngModelGetter.assign($scope, (event.target.checked) ? 1 : 0); }); } }).on('ifClicked', function (event) { //Gestisco l'attributo ngClick se presente chiamo la funzione associata if (angular.isDefined($attrs.ngClick)) { var clickFunction = $parse($attrs['ngClick'])($scope); if (angular.isDefined(clickFunction)) $timeout(function () { $scope.$apply(function () { clickFunction(); }); }); } if (form != null) form.$setDirty(true); }); $scope.$watch($attrs['ngModel'], function (value) { $timeout(function () { if (!value || value == '0') { $(element).iCheck('uncheck'); } else { $(element).iCheck('check'); } }); }); }); } }; }) .directive('onEnterKey', function onEnterKey() { return function (scope, element, attrs) { element.bind("keydown keypress", function (event) { if (event.which === 13) { scope.$apply(function () { scope.$eval(attrs.onEnterKey); }); event.preventDefault(); } }); }; }) .directive('numbersOnly', function () { return { require: 'ngModel', link: function (scope, element, attrs, modelCtrl) { modelCtrl.$parsers.push(function (inputValue) { if (inputValue == undefined) return ''; var transformedInput = inputValue.replace(/[^0-9]/g, ''); if (transformedInput !== inputValue) { modelCtrl.$setViewValue(transformedInput); modelCtrl.$render(); } return transformedInput; }); } }; }) .directive('quantityInput', function () { return { restrict: 'EA', require: ['ngModel'], replace: true, template: `
+
-
`, scope: { quantita: "=ngModel", step: "=", min: "=", max: "=", onClickBtn: "=", disabled: '=ngDisabled' }, link: function (scope, element, attrs, modelCtrl) { var input = element.find('input[type="number"]'); var btnUp = element.find('.quantity-up'), btnDown = element.find('.quantity-down'), min = scope.min || 1, max = scope.max || undefined, step = scope.step || 1; btnUp.click(function () { if (scope.disabled) return; var oldValue = parseFloat(scope.quantita); if (oldValue >= max) { var newVal = oldValue; } else { var newVal = oldValue + step; } element.find("input").val(newVal); element.find("input").trigger("change"); if (oldValue != newVal) scope.onClickBtn(scope.quantita); }); btnDown.click(function () { if (scope.disabled) return; var oldValue = parseFloat(input.val()); if (oldValue <= min) { var newVal = oldValue; } else { var newVal = oldValue - step; } element.find("input").val(newVal); element.find("input").trigger("change"); if (oldValue != newVal) scope.onClickBtn(scope.quantita); }); } }; }) .directive("moveNextOnMaxlength", function () { return { restrict: "A", link: function ($scope, element) { var $nextElement; if (angular.isDefined(element.attr("next-element"))) { $nextElement = $('#' + element.attr("next-element"))[0]; } else { $nextElement = element.next(); } element.on("input", function (e) { if (element.val().length === parseInt(element.attr("maxlength"))) { if (angular.isDefined($nextElement)) { $nextElement.focus(); } } }); } } }) .directive('bootstrapDatepicker', function bootstrapDatepicker($parse) { return { require: '?ngModel', restrict: 'A', link: function ($scope, element, attrs, controller) { var updateModel, form = null; updateModel = function (ev) { //element.datepicker('hide'); //element.blur(); return $scope.$apply(function () { return controller.$setViewValue(ev.date); }); }; //Controlli per settare il form collegato come dirty quando cambia il valore if (angular.isDefined(attrs.form)) form = $parse(attrs['form'])($scope); if (controller != null) { controller.$render = function () { element.datepicker(bootstrapDatepickerConfig); element.datepicker('update', controller.$viewValue); element.datepicker('setValue'); element.datepicker('update'); return controller.$viewValue; }; } return attrs.$observe('bootstrapDatepicker', function (value) { var options; options = angular.copy(bootstrapDatepickerConfig); if (angular.isObject(value)) { options = value; } if (typeof (value) === "string" && value.length > 0) { options = angular.fromJson(value); } if (angular.isDefined(attrs.dateOrientation)) { options.orientation = attrs.dateOrientation; } return element.datepicker(options).on('changeDate', function () { updateModel; if (form != null) form.$setDirty(true); }); }); } }; }) .directive('inputNumber', function ($locale) { // Usage: // // Creates: // var directive = { link: link, require: 'ngModel', restrict: 'A' }; return directive; function link(scope, el, attrs, ngModelCtrl) { el.addClass('text-right'); if (angular.isDefined(attrs.noCleanzero)) { var cleanzero = false; } else { var cleanzero = true; } var decimalSeparator = $locale.NUMBER_FORMATS.DECIMAL_SEP; var groupSeparator = $locale.NUMBER_FORMATS.GROUP_SEP; // Create new regular expression with current decimal separator. var NUMBER_REGEXP = "^\\s*(\\-|\\+)?(\\d+|(\\d*(\\.\\d*)))\\s*$"; var regex = new RegExp(NUMBER_REGEXP); var formatting = true; var maxInputLength = 16; // Maximum input length. Default max ECMA script. var max; // Maximum value. Default undefined. var min; // Minimum value. Default undefined. var lastValidValue; // Last valid value. var decimals = 2; // Number of decimals. Default 2. /*switch (attrs.inputNumber) { case'prezzo': decimals = 2; break; case'prezzo_unitario': decimals = ConfigParam.get('DecimaliPrezzoUnitario'); break; case'quantita': decimals = ConfigParam.get('DecimaliQuantita'); break; }*/ // Create parsers and formatters. ngModelCtrl.$parsers.push(parseViewValue); ngModelCtrl.$parsers.push(minValidator); ngModelCtrl.$parsers.push(maxValidator); ngModelCtrl.$formatters.push(formatViewValue); el.bind('blur', onBlur); // Event handler for the leave event. el.bind('focus', onFocus); // Event handler for the focus event. // Put a watch on the min, max and decimal value changes in the attribute. scope.$watch(attrs.min, onMinChanged); scope.$watch(attrs.max, onMaxChanged); scope.$watch(attrs.decimals, onDecimalsChanged); scope.$watch(attrs.formatting, onFormattingChanged); // Setup decimal formatting. if (decimals > -1) { ngModelCtrl.$parsers.push(function (value) { return (value) ? round(value) : value; }); ngModelCtrl.$formatters.push(function (value) { return (value) ? formatPrecision(value) : value; }); } function onMinChanged(value) { if (!angular.isUndefined(value)) { min = parseFloat(value); lastValidValue = minValidator(ngModelCtrl.$modelValue); ngModelCtrl.$setViewValue(formatPrecision(lastValidValue)); ngModelCtrl.$render(); } } function onMaxChanged(value) { if (!angular.isUndefined(value)) { max = parseFloat(value); maxInputLength = calculateMaxLength(max); lastValidValue = maxValidator(ngModelCtrl.$modelValue); ngModelCtrl.$setViewValue(formatPrecision(lastValidValue)); ngModelCtrl.$render(); } } function onDecimalsChanged(value) { if (!angular.isUndefined(value)) { decimals = parseFloat(value); maxInputLength = calculateMaxLength(max); if (lastValidValue !== undefined) { ngModelCtrl.$setViewValue(formatPrecision(lastValidValue)); ngModelCtrl.$render(); } } } function onFormattingChanged(value) { if (!angular.isUndefined(value)) { formatting = (value !== false); ngModelCtrl.$setViewValue(formatPrecision(lastValidValue)); ngModelCtrl.$render(); } } /** * Round the value to the closest decimal. */ function round(value) { var d = Math.pow(10, decimals); return Math.round(value * d) / d; } /** * Format a number with the thousand group separator. */ function numberWithCommas(value) { if (formatting) { var parts = value.toString().split(decimalSeparator); parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, groupSeparator); return parts.join(decimalSeparator); } else { // No formatting applies. return value; } } /** * Format a value with thousand group separator and correct decimal char. */ function formatPrecision(value, noComma) { noComma = (angular.isDefined(noComma)) ? noComma : false; if (!(value || value === 0)) { return ''; } var formattedValue = parseFloat(value).toFixedExcess(decimals); formattedValue = formattedValue.replace('.', decimalSeparator); return (noComma) ? formattedValue : numberWithCommas(formattedValue); } function formatViewValue(value) { if (angular.isString(value) && (value == null || (cleanzero && parseFloat(value.replace(',', '.')) == 0))) return ''; return ngModelCtrl.$isEmpty(value) ? '' : '' + value; } /** * Parse the view value. */ function parseViewValue(value) { if (angular.isUndefined(value)) { value = ''; } value = value.toString().replace(decimalSeparator, '.'); // Handle leading decimal point, like ".5" if (value.indexOf('.') === 0) { value = '0' + value; } // Allow "-" inputs only when min < 0 if (value.indexOf('-') === 0) { if (min >= 0) { value = null; ngModelCtrl.$setViewValue(formatViewValue(lastValidValue)); ngModelCtrl.$render(); } else if (value === '-') { value = ''; } } var empty = ngModelCtrl.$isEmpty(value); if (empty) { lastValidValue = ''; //ngModelCtrl.$modelValue = undefined; } else { if (regex.test(value) && (value.length <= maxInputLength)) { if (value > max) { lastValidValue = max; } else if (value < min) { lastValidValue = min; } else { lastValidValue = (value === '') ? null : parseFloat(value); } } else { // Render the last valid input in the field ngModelCtrl.$setViewValue(formatViewValue(lastValidValue)); ngModelCtrl.$render(); } } return lastValidValue; } /** * Calculate the maximum input length in characters. * If no maximum the input will be limited to 16; the maximum ECMA script int. */ function calculateMaxLength(value) { var length = 16; if (!angular.isUndefined(value)) { length = Math.floor(value).toString().length; } if (decimals > 0) { // Add extra length for the decimals plus one for the decimal separator. length += decimals + 1; } if (min < 0) { // Add extra length for the - sign. length++; } return length; } /** * Minimum value validator. */ function minValidator(value) { if (!angular.isUndefined(min)) { if (!ngModelCtrl.$isEmpty(value) && (value < min)) { return min; } else { return value; } } else { return value; } } /** * Maximum value validator. */ function maxValidator(value) { if (!angular.isUndefined(max)) { if (!ngModelCtrl.$isEmpty(value) && (value > max)) { return max; } else { return value; } } else { return value; } } /** * Function for handeling the blur (leave) event on the control. */ function onBlur() { var value = ngModelCtrl.$modelValue; if (!angular.isUndefined(value)) { if (value == null || (cleanzero && parseFloat(value) == 0)) { ngModelCtrl.$viewValue = ""; ngModelCtrl.$render(); return; } // Format the model value. ngModelCtrl.$viewValue = formatPrecision(value); ngModelCtrl.$render(); } } /** * Function for handeling the focus (enter) event on the control. * On focus show the value without the group separators. */ function onFocus() { var value = ngModelCtrl.$modelValue; if (!angular.isUndefined(value)) { if (value == null || (cleanzero && parseFloat(value) == 0)) { ngModelCtrl.$viewValue = ""; ngModelCtrl.$render(); return; } ngModelCtrl.$viewValue = formatPrecision(value, true).toString().replace(".", decimalSeparator); ngModelCtrl.$render(); } } } }) .directive('elastic', function elastic($timeout, $rootScope) { return { restrict: 'A', link: function ($scope, element, attrs) { $scope.initialHeight = $scope.initialHeight || element[0].style.height; $scope.maxHeight = attrs.elasticMaxHeight || null; let resize = function () { //Controllo che se impostato il param maxHeight e se viene superato blocco il resize if ($scope.maxHeight && (element[0].scrollHeight > $scope.maxHeight)) { return; } element[0].style.height = $scope.initialHeight; element[0].style.height = "" + element[0].scrollHeight + "px"; }; element.on("input change focus", resize); $timeout(resize, 1500); //Funzione per richiamare lo showhide esternamente $rootScope.$on('resize-elastic-textbox', function (event) { resize(); }); } }; }) .directive('maxlines', function () { return function (scope, element, attrs) { element.bind("keydown keypress", function (event) { if (event.which === 13) { let text = element.val(), numberOfLines = (text.match(/\n/g) || []).length + 1, maxRows = parseInt(element.attr('maxlines')); if (event.which === 13 && numberOfLines === maxRows) { return false; } } }); }; }) .service('DateRangePickerService', function (moment) { let service = {}; service.getDefaultOptions = function () { return defaultDateRangePickerOptions; }; service.getTrimestreCustomRangeOptions = function(){ let ranges = { 'Ultimi 30 gg': [moment().subtract(29, 'days'), moment()], 'Questo Mese': [moment().startOf('month'), moment().endOf('month')], 'Mese Scorso': [moment().subtract(1,'month').startOf('month'), moment().subtract(1,'month').endOf('month')], 'Anno in Corso': [moment().startOf('year'), moment().endOf('year')]}; let periodi ={ 1:{start:0,end:2}, 2:{start:3,end:5}, 3:{start:6,end:8}, 4:{start:9,end:11} }; let Anno = moment().format('YYYY'); for(let i=1;i<5;i++){ let labelAnno = i+"° Trimestre "+Anno; ranges[labelAnno] = [moment().month(periodi[i].start).startOf('month'), moment().month(periodi[i].end).endOf('month')]; } ranges['Anno Scorso'] = [moment().subtract(1,'year').startOf('year'), moment().subtract(1,'year').endOf('year')]; return ranges; }; /** * Formatta le date dei filtri nel modo corretto prima di invairle alla richiesta del web service * @param filtri * @param nomeDateStart * @param nomeDateEnd * @returns {*} */ service.getFormattedFilterDate = function (filtri,nomeDateStart,nomeDateEnd,dateFormatString) { nomeDateStart = nomeDateStart || 'DateStart'; nomeDateEnd = nomeDateEnd || 'DateEnd'; dateFormatString = dateFormatString || 'DD/MM/YYYY'; var tmpFilter = angular.copy(filtri); tmpFilter[nomeDateStart] = moment(tmpFilter[nomeDateStart]).format(dateFormatString); tmpFilter[nomeDateEnd] = moment(tmpFilter[nomeDateEnd]).format(dateFormatString); return tmpFilter; }; return service; });