app.controller('WizardCtrl', function($scope, $http, $routeParams, Hotel, Flight, Activity, $filter, $location, $timeout, notify) { // original camp data $scope.originalCampData = {}; $scope.verbergenTonen = []; $scope.hotelOption = {}; $scope.customerFilter = ''; $scope.customerAccounts = []; $scope.approveQuotation = function() { var req = { url: '/quotation/approve/' + $routeParams.hash, method: 'GET', } $http(req).then(function(response) { if (response.status && response.data.status) { //succes message swal('Gelukt!', 'De offerte is geaccepteerd en klaar om te verzenden.', 'success'); $location.url('/page/offertes'); } else { swal('Mislukt!', response.data.message, 'error'); } }); } $scope.readyForCheck = function() { // Check if calculatedMargin and marginpp are exists if ($scope.calculatedMargin && $scope.calculatedMargin.marginpp !== undefined) { let marginpp = $scope.calculatedMargin.marginpp * 100; var req = { url: '/quotation/readyForCheck/' + $routeParams.hash + '/' + marginpp, method: 'GET', }; $http(req).then(function(response) { if (response.status && response.data.status) { // Succesbericht if (marginpp < 15) { swal('Gelukt!', 'De offerte is klaar gezet voor controle.', 'success'); } else { swal('Gelukt!', 'De offerte is geaccepteerd en klaar om te verzenden.', 'success'); } $location.url('/page/offertes'); } }).catch(function(error) { console.error('Fout bij het aanvragen van de status update:', error); }); } else { // Als marginpp niet beschikbaar is, toon een waarschuwing console.error('Fout: marginpp is niet beschikbaar. Bereken de marge eerst.'); $scope.notification('Waarschuwing!', 'De marge is niet berekend, probeer opnieuw.', 'warning'); } }; $scope.declineQuotation = function() { swal({ title: 'Let op!', text: 'U wilt offerte ' + $scope.quotationNumber + ' weigeren.\nGeef hieronder een reden op:', type: 'warning', content: 'input', buttons: { cancel: 'Terug', confirm: { text: 'OK', closeModal: false, }, }, }).then(name => { if (!name) { throw null; } // If the user confirms if (name.length >= 0) { var req = { url: '/quotation/internalDecline/' + $routeParams.hash, method: 'POST', data: {'decline_reason': name}, } $http(req).then(function(response) { if (response.status && response.data.status) { //succes message swal('Gelukt!', 'De offerte is geweigerd.', 'success'); $location.url('/page/offertes'); } }); } else { // No valid camp name swal({ title: 'Let op!', text: 'Voer een geldige reden in.', type: 'warning' }); } }) } // quotation layout information $scope.layout = {}; $scope.informationHeaders = []; $scope.getInformationHeaders = function() { var req = { url: '/quotation_information_header/getAll', method: 'GET', } $http(req).then(function(response) { if (response.status && response.data.status) { $scope.informationHeaders = response.data.data; } }); } $scope.getInformationHeaders(); $scope.notification = function(title, message, type, duration) { if (type == undefined) { type == 'success'; } if (duration == undefined) { duration = 5000; } notify({ message: message, messageTemplate: '
' + title + '

' + message + '

', classes: ["alert-" + type], duration: duration, position: "right", }) } $scope.getLayoutImages = function() { var images = (Array.isArray($scope.hotelOption['images']) ? $scope.hotelOption['images'] : []); if ($scope.campData['activities'] !== undefined && Array.isArray($scope.campData['activities'])) { $scope.campData['activities'].forEach(function(activity) { if (activity['images'] !== undefined && Array.isArray(activity['images']) && activity['images'].length) { images = images.concat(activity['images']); } if (activity['football_match'] !== undefined && activity['football_match']['images'] && Array.isArray(activity['football_match']['images']) && activity['football_match']['images'].length) { images = images.concat(activity['football_match']['images']); } }); } return images; } $scope.setLayoutImages = function(field, number) { if (field['value']['images'] == undefined) { field['value']['images'] = new Array(); } var images = $scope.getLayoutImages(); for (let i = 0; i < images.length; i++) { //set i + 1 to start with 1 and not with 0 if (!field['value']['images'][i+1] || !images.includes(field['value']['images'][i+1])) { field['value']['images'][i+1] = images[i]; } } } // END - quotation layout information $scope.getStandardTexts = function() { var req = { url: '/standard_text/get', method: 'GET', } $http(req).then(function(response) { if (response.status && response.data.status) { $scope.standardTexts = response.data.data; } }); } $scope.getStandardTexts(); $scope.filterStandardTexts = function(header) { if ($scope.standardTexts && header){ let standardTextLines = $scope.standardTexts.filter(function(text) { return text.tag == header.tag }); return standardTextLines; } } $scope.newInformationLine = {}; $scope.addNewInformationLine = function(header, value) { if (value['info'] === undefined || Array.isArray(value['info'])) { value['info'] = {}; } if (value['info'][header] === undefined) { value['info'][header] = []; } value['info'][header].push($scope.newInformationLine[header]); $scope.newInformationLine[header] = ''; } $scope.changeTitle = function (type, key) { if ($scope.verbergenTonen[type][key] && $scope.verbergenTonen[type][key] == 'Tonen') { $scope.verbergenTonen[type][key] = 'Verbergen'; } else { $scope.verbergenTonen[type][key] = 'Tonen'; } } // hotel room information $scope.rooms = []; $scope.roomTypes = []; $scope.amountOfAttendees = 0; $scope.changeNumberOfAttendees = function(field) { $scope.amountOfAttendees = parseInt(field.value); } $scope.changeNumberOfRooms = function(field) { $scope.rooms = []; if ($scope.roomTypes !== undefined && Array.isArray($scope.roomTypes)) { $scope.roomTypes.forEach(function(room) { if (room['amount'] !== undefined && angular.isNumber(room['amount'])) { for (var i = 0; i < room['amount']; i++) { $scope.rooms.push(angular.copy(room)); } } }); } } // reload hotel option rooms from standardisation $scope.reloadHotelOptionRooms = function() { if ($scope.originalCampData['hotels'] !== undefined && Array.isArray($scope.originalCampData['hotels']) && $scope.hotelOption['id'] !== undefined && $scope.hotelOption['id']) { $scope.originalCampData['hotels'].forEach(function(hotel) { if (hotel['id'] !== undefined && $scope.hotelOption['id'] == hotel['id'] && hotel['rooms'] !== undefined && typeof hotel['rooms'] === 'string') { try { $scope.hotelOption['rooms'] = JSON.parse(hotel['rooms']); $scope.getHotelRoomTypes(); } catch (e) { // JSON failed, do nothing } } }); } else { if ($scope.hotelOption['id'] !== undefined && $scope.hotels !== undefined && Array.isArray($scope.hotels)) { $scope.hotels.forEach(function(hotel) { if (hotel['id'] !== undefined && $scope.hotelOption['id'] == hotel['id'] && hotel['rooms'] !== undefined){ $scope.hotelOption['rooms'] = hotel['rooms']; } }); } } } $scope.onChangeRoomOptions = function() { $scope.getHotelRoomTypes(); } // generates hotel room types array, call when hotel room options change $scope.getHotelRoomTypes = function() { // initialize array $scope.roomTypes = []; // add default room to array $scope.roomTypes.push({ name: $scope.hotelOption['room_name'], amount_of_singles: parseInt($scope.hotelOption['room_amount_of_singles']), amount_of_doubles: parseInt($scope.hotelOption['room_amount_of_doubles']), }); // add surcharge rooms to array if ($scope.hotelOption['rooms'] !== undefined && Array.isArray($scope.hotelOption['rooms'])) { $scope.hotelOption['rooms'].forEach(function(room) { $scope.roomTypes.push(room); }); } // reset input on number of rooms $scope.changeNumberOfRooms(); } $scope.getAmountOfBeds = function(rooms) { if ($scope.roomTypes === undefined || !Array.isArray($scope.roomTypes)) { return 0; } return $scope.roomTypes.reduce(function(total, room) { var amountOfBeds = 0; if (room['amount_of_singles'] !== undefined && angular.isNumber(parseInt(room['amount_of_singles']))) { amountOfBeds += parseInt(room['amount_of_singles']); } if (room['amount_of_doubles'] !== undefined && angular.isNumber(parseInt(room['amount_of_doubles']))) { amountOfBeds += parseInt(room['amount_of_doubles'] * 2); } total += amountOfBeds * (room['amount'] !== undefined && angular.isNumber(room['amount']) ? room['amount'] : 0); return total; }, 0); } $scope.setMatchPanel = function(activity){ return Activity.setMatchPanel(activity, $scope); } /* Flow: * 1 getNumOfPages * 2 preparePage * 3 getPageData */ // Initialize variables $scope.currentPage = 0; $scope.numOfPages = 0; $scope.quotationNumber = null; $scope.quotationHash = 0; $scope.wizard = { 'id': 0, }; $scope.pageType = 'wizard' $scope.selectWizard = function(btn, row) { $scope.wizard = row; $scope.getNumOfPages(); } // Get the fields and values for wizard 1 and the current page $scope.getNumOfPages = function() { // Get the fields var req = { method: 'GET', url: '/wizard_page/getNumOfPages/' + $scope.wizard.id, } $http(req).then(function(response) { if (response.status && response.data.status) { $scope.numOfPages = response.data.data.numOfPages; if ($scope.numOfPages) { // Load the data $scope.currentPage = 1; $scope.getPageData(); } else { // Warning $scope.notification('Foutmelding', 'Geen pagina data gevonden', 'danger'); } } else { // Error $scope.notification('Foutmelding', response.data.message, 'danger'); } }); } $scope.getCountryById = function(countryId) { angular.forEach($scope.countries, function(country) { if (country.id == countryId) { countryName = country.name; } }) return countryName; } // Prepare the page $scope.preparePage = function(pageNum) { if (pageNum <= $scope.numOfPages) { if ((pageNum == 3) && $scope.pageData.campCountry) { var countryName = $scope.getCountryById($scope.pageData.campCountry) // Get the location if (countryName == 'Nederland' || countryName == 'België' || countryName == 'Duitsland') { // Switch to wizard 'Binnenland' $scope.getPageData(3, 2); } else if ($scope.pageData.campCountry != undefined) { $scope.getPageData(3); } } } else { // Load the data for the last page $scope.pageData.titles[5] = {name: 'Offerte Gegenereerd'}; } } function getMailTemplate () { var req = { method: 'GET', url: '/wizard/getQuotationTemplate', } $http(req).then(function(response) { if (response.data && response.data.status) { $scope.emailTemplate = response.data.data; if (typeof $scope.emailTemplate.variables == 'string') { try { $scope.emailTemplate.variables = JSON.parse($scope.emailTemplate.variables) } catch (e) { $scope.emailTemplate.variables = []; } } //make variables for button $scope.makeElements(); } }); } getMailTemplate(); function getInformalMail () { var req = { method: 'GET', url: '/email_template/getByEmailName/QUOTATION_INFORMAL', } $http(req).then(function(response) { if (response.data && response.data.status) { $scope.informalMail = response.data.data; $scope.originalInformalMail = response.data.data; $scope.updatePreviewMail(); } }); } getInformalMail(); // Get the fields and values for wizard 1 $scope.getPageData = function(pageNum = 0, wizardId = 1) { $scope.loadingPage = true; if ($routeParams.hash || ($scope.currentPage <= $scope.numOfPages)) { if ($scope.pageData == undefined) { $scope.pageData = {}; } // Get the page titles var req = { method: 'GET', url: '/wizard_page/getByWizard/' + (pageNum ? 2 : 1), } $http(req).then(function(response) { if (response.status && response.data.status) { if (pageNum) { // Get one title $scope.pageData.titles[pageNum-1] = response.data.data[0]; } else { // Get all page titles $scope.pageData.titles = response.data.data; } } }) // Get the fields var req = null if ((pageNum == 0) && $routeParams.hash) { // If this is an existing quotation req = { method: 'GET', url: '/quotation/getForWizard/' + $routeParams.hash, } } else // If the quotation is being created if ((!$routeParams.hash || $scope.quotationStatus == 'Concept')) { req = { method: 'POST', url: '/wizard/getData', data: { wizard_id: wizardId, page_num: pageNum, }, } } if (req) { $http(req).then(function(response) { if (response.status && response.data.status) { $scope.setPageFields(pageNum, response.data.data.fields); // Deleted/Old version? $scope.deletedAt = response.data.data.deleted_at; $scope.declineReason = response.data.data.decline_reason; $scope.internalDeclineReason = response.data.data.internal_decline_reason; // Get the status if ((pageNum == 0) && $routeParams.hash) { $scope.quotationStatus = response.data.data.status; } else { $scope.quotationStatus = 'Concept'; } // Get the field options $scope.getPageFieldOptions(pageNum); if ((pageNum == 0) && $routeParams.hash) { // Set the wizard id $scope.wizard.id = 1; // Set the quotation number $scope.quotationNumber = response.data.data.quotation_number; $scope.quotationReadOnly = $scope.quotationStatus != 'Concept'; } //build index $scope.fieldIndex = []; angular.forEach($scope.pageData.fields, function(field, key) { //update index $scope.fieldIndex[field.subtype] = key; page = parseInt(field.page_num); if (page > $scope.numOfPages) { $scope.numOfPages = page; } }); //check campId $scope.checkCampId(); //set budget $scope.budget = $scope.getfVar('budget'); if ($location.search().p !== undefined && angular.isNumber(parseInt($location.search().p))) { $scope.setValues(parseInt($location.search().p)); } } else { $scope.pageData = {}; // Set the quotation number and status $scope.quotationNumber = response.data.data.quotation_number; $scope.quotationStatus = response.data.data.status; // Error $scope.notification('Foutmelding', response.data.message, 'danger'); } }); } } else { // Load the data for the last page $scope.pageData = { fields: [], titles: {5: {name: 'Offerte Gegenereerd'}}, }; } $scope.loadingPage = false; } $scope.setfVar = function(fieldSubType, fieldValue){ if($scope.fieldIndex[fieldSubType] !== undefined){ $scope.pageData.fields[$scope.fieldIndex[fieldSubType]].value = fieldValue; } } $scope.validateFlightDate = function(departure ,dateTime) { if (departure) { fromDate = $scope.pageData.fields.filter(field => field.subtype == 'from') if (fromDate[0] && fromDate[0].value){ fromDate = fromDate[0].value; if (dateTime.getTime() < fromDate.getTime()) { $scope.notification('Let op!', 'De opgegeven heenvlucht is eerder dan de begin datum van het trainingskamp.', 'warning'); } } } else { tillDate = $scope.pageData.fields.filter(field => field.subtype == 'till') if (tillDate[0] && tillDate[0].value){ tillDate = tillDate[0].value; dateTimeCopy = angular.copy(dateTime); dateTimeCopy.setHours(0,0,0,0); //remove time from return flight for good comparison if (dateTimeCopy.getTime() > tillDate.getTime()) { $scope.notification('Let op!', 'De terugvlucht is later dan de eind datum van het trainingskamp.', 'warning'); } } } } $scope.getfVar = function(fieldSubType){ if($scope.fieldIndex[fieldSubType] !== undefined){ return $scope.pageData.fields[$scope.fieldIndex[fieldSubType]].value; } } $scope.getField = function(fieldSubType){ if($scope.fieldIndex != undefined && $scope.fieldIndex[fieldSubType] !== undefined){ return $scope.pageData.fields[$scope.fieldIndex[fieldSubType]]; }else{ return {}; } } $scope.setPageFields = function(pageNum, newFields) { if ($scope.pageData == undefined) { $scope.pageData = {}; } // Set the fields fields = []; if (pageNum > 0) { // Remove the current page fields angular.forEach($scope.pageData.fields, function(field, key) { if (field.page_num != pageNum) { fields[key] = field; } }); // Add the new page fields, with the id as key angular.forEach($scope.formatGetData(angular.copy(newFields)), function(field, key) { // set existing field back to fields, add only new fields if ($scope.pageData.fields[field.id] !== undefined) { fields[field.id] = $scope.pageData.fields[field.id]; } else { fields[field.id] = field; } switch (field.subtype) { case 'flights': if ($scope.originalCampData == undefined) { $scope.originalCampData = {}; } if ($scope.originalCampData.flights == undefined) { $scope.originalCampData.flights = []; } Flight.set($scope, $scope.originalCampData.flights); // Add/show these options by default Flight.resetAddMany($scope, $scope.campData, $scope.originalCampData.flights); break; } }); } else { fieldsObj = $scope.formatGetData(angular.copy(newFields)); angular.forEach(fieldsObj, function(field, key) { // Set a default value per field switch (field.subtype) { case 'customer': if (field.value) { $scope.retrieveCustomerAccounts(field.value); $scope.updatePreviewMail(); } break; case 'adminbv': if (field.value == undefined || field.value == null) { field.value = '1'; } break; case 'camp': if (field.value) { // Get the hotel options for this camp $scope.campHotelsLoaded = true; $scope.onChange(field, true); } break; case 'exclusive': if (field.value == undefined || field.value == null) { field.value = ($scope.defaultTexts['OFFERTE-EXCLUSIEF'] !== undefined ? $scope.defaultTexts['OFFERTE-EXCLUSIEF']['description'] : ''); } break; case 'from': if (field.value) { $scope.onChange(field); } break; case 'till': if (field.value) { $scope.onChange(field); } break; case 'hotels': if ($scope.campData == undefined) { $scope.campData = {}; } if (field.value) { $scope.hotelOption = field.value[0]; } else { $scope.hotelOption = {}; } // If needed, set the default hotel options if (!$scope.hotels) { Hotel.init($scope, $http); field.options = $scope.hotels; } break; case 'rooms': if (field.value) { // set room types $scope.roomTypes = field.value; // initiate via change function $scope.changeNumberOfRooms(field); } break; case 'flights': if ($scope.campData == undefined) { $scope.campData = {}; } angular.forEach(field.value, function(flight) { Flight.add($scope, $scope.campData, flight); }); // If needed, set the default flight options if (!$scope.flights) { Flight.init($scope, $http); field.options = $scope.flights; } // Set the right carrier data if ($scope.campData.flights !== undefined && angular.isArray($scope.campData.flights)) { angular.forEach($scope.campData.flights, function(flightOption) { $scope.changeCarrier(flightOption); }); } break; case 'activities': if ($scope.campData == undefined) { $scope.campData = {}; } angular.forEach(field.value, function(activity) { Activity.add($scope, $scope.campData, activity); }) // If needed, set the default activit options if (!$scope.activities) { Activity.init($scope, $http); field.options = $scope.activities; } break; case 'pax': $scope.onChange(field); break; case 'guests': $scope.onChange(field); break; case 'marginpp': if (field.value == undefined || field.value == null) { field.value = 20; } field.readOnly = false; case 'deposit': if (field.readOnly == undefined || field.readOnly == null) { field.readOnly = true; } if (field.value == undefined || field.value == null) { field.value = 0.00; } break; case 'tourist_tax': $scope.onChange(field); break; case 'manualdeposit': field.readOnly = $scope.user.rights['wizard'] === undefined || $scope.user.rights['wizard']['changedeposit'] === undefined || !$scope.user.rights['wizard']['changedeposit']; if (field.value == undefined || field.value == null) { field.value = false; } break; case 'mail_template': if (field.value == undefined || field.value == null || field.value.length <= 0) { // get default mail template and set it in field.value field.value = $scope.emailTemplate.default; } break; case 'formal_mail': if (field.value == undefined || field.value == null || field.value == false) { if (!$routeParams.hash){ field.value = true; } } break; case 'additional_text_template': $scope.updatePreviewMail(field); break; } fields[field.id] = field; }); // Set the default hotel service if ($scope.hotelOption == undefined) { $scope.hotelOption = {}; } if ($scope.hotelOption.service_level == undefined) { $scope.hotelOption.service_level = 'Logies'; } // Set the default flights if ($scope.campData == undefined) { $scope.campData = {}; } } $scope.pageData.fields = fields; $scope.updatePreviewMail(); } $scope.getLayoutImageLabel = function(key) { return 'Afbeelding ' + (parseInt(key) + 1); } $scope.getHotel = function(hotelId) { if (hotelId == 'Nieuw' || !hotelId) { hotelOption = null } else { // Get the hotel option var hotelId = parseInt(hotelId) angular.forEach($scope.hotels, function(option) { if (hotelId == option.id) { hotelOption = angular.copy(option) } }) if (typeof hotelOption === 'undefined') { hotelOption = null; } } return hotelOption; } $scope.flightModalFieldsChanged = false; $scope.updateQuotation = function() { if ($scope.flightModalFieldsChanged) { $scope.currentPage = 2; $scope.flightModalFieldsChanged = false; // Error $scope.notification('Waarschuwing', 'De kamp data is gewijzigd, controleer de offerte.', 'warning'); } else { $scope.postQuotation(true); } $('#flight-modal').modal('hide'); } // If a quotation should be loaded, load it $scope.selectWizard(null, {id: 1}); $scope.onChangeModalField = function(field) { $scope.flightModalFieldsChanged = true; } $scope.calculatetotalPrice = function() { $scope.totalPricePP = 0.0; $scope.totalPricePPSales = 0.0; if (!$scope.amountOfAttendees) { $scope.amountOfAttendees = 0 } if ($scope.hotelOption && $scope.hotelOption.price_per_person_per_night) { if (!$scope.numOfNights) { $scope.numOfNights = 0 } // Add the hotel price $scope.totalPricePP += ($scope.hotelOption.price_per_person_per_night && $scope.numOfNights ? $scope.hotelOption.price_per_person_per_night * $scope.numOfNights: 0); $scope.totalPricePPSales += ($scope.hotelOption.price_per_person_per_night_sales && $scope.numOfNights ? $scope.hotelOption.price_per_person_per_night_sales * $scope.numOfNights: 0); } // Add room surcharges angular.forEach($scope.roomTypes, function(roomType) { $scope.totalPricePP += ($scope.calcRoomTypePrice(roomType) / $scope.amountOfAttendees) * $scope.numOfNights; $scope.totalPricePPSales += ($scope.calcRoomTypePrice(roomType, true) / $scope.amountOfAttendees) * $scope.numOfNights; }); // Add the laundry surcharge if ($scope.hotelOption && $scope.hotelOption.price_laundry_service) { $scope.totalPricePP += ($scope.hotelOption.price_laundry_service * $scope.calcTrainingsPlusMatches()); $scope.totalPricePPSales += ($scope.hotelOption.price_laundry_service * $scope.calcTrainingsPlusMatches()) * 1.2; } // Add the activity prices angular.forEach($scope.campData.activities, function(option) { if (option.pay_per_camp) { $scope.totalPricePP += option.price && $scope.amountOfAttendees ? option.price / $scope.amountOfAttendees : 0; $scope.totalPricePPSales += option.price_sales && $scope.amountOfAttendees ? (option.price_sales / $scope.amountOfAttendees) : (option.price_sales ? option.price_sales : (option.price && $scope.amountOfAttendees ? (option.price / $scope.amountOfAttendees) * 1.2 : 0)); } else { $scope.totalPricePP += option.price ? option.price : 0; $scope.totalPricePPSales += option.price_sales ? option.price_sales : (option.price ? option.price * 1.2 : 0); } }); // Add the flight prices and flight baggage prices $scope.baggagePricePP = 0.0; angular.forEach($scope.campData.flights, function(option) { $scope.totalPricePP += option.price && parseFloat(option.price) ? parseFloat(option.price) * option.passengers / $scope.amountOfAttendees : 0; $scope.totalPricePPSales += option.price && parseFloat(option.price) ? parseFloat(option.price) * option.passengers / $scope.amountOfAttendees * 1.2 : 0; $scope.baggagePricePP += option.luggage_price && parseFloat(option.luggage_price) ? parseFloat(option.luggage_price) * option.passengers / $scope.amountOfAttendees : 0; $scope.totalPricePP += option.luggage_price && parseFloat(option.luggage_price) ? parseFloat(option.luggage_price) * option.passengers / $scope.amountOfAttendees : 0; $scope.totalPricePPSales += option.luggage_price && parseFloat(option.luggage_price) ? parseFloat(option.luggage_price) * option.passengers / $scope.amountOfAttendees * 1.2 : 0; }); // calculate margin based on new price if($scope.totalPricePP != $scope.oldTotalPricePP){ $scope.oldTotalPricePP = $scope.totalPricePP; if($scope.getField('pricepp') && !isNaN($scope.getField('pricepp').value)){ $scope.changePrice($scope.getField('pricepp')); } } $scope.changePrice($scope.getField('pricepp')); //calculate let brutoMargin = ($scope.getField('pricepp') * $scope.amountOfAttendees) - ($scope.totalPricePP * $scope.amountOfAttendees); let rbrCosts = 21/121 * brutoMargin; $scope.setfVar('brutomargin', parseFloat(brutoMargin.toFixed(2))); $scope.setfVar('rbrcosts', parseFloat(rbrCosts.toFixed(2))); } $scope.hasPrice = function(item) { return item.price !== undefined && item.price !== null && item.price != 0; } $scope.getFieldOrder = function(item) { return parseInt(item.order); } $scope.setValues = function(nextPage) { $scope.currentPage = nextPage; switch (nextPage) { case 4: $scope.calculatetotalPrice(); break; } if ($routeParams.hash !== undefined && $routeParams.hash) { $location.url('/page/offerte/' + $routeParams.hash + '?p=' + nextPage); } } // Get the options for each select box $scope.getPageFieldOptions = function(pageNum) { angular.forEach($scope.pageData.fields, function(field) { if ((pageNum == 0) || (field.page_num == pageNum)) { // If this is a select box, get the options if (['select','customer','camp'].includes(field.type) && field.controller) { $scope.getFieldOptions(field); } } }); } $scope.getType = function(value) { return typeof value } // Get the options for the field $scope.getFieldOptions = function(field) { if (field.function && field.function.length) { get_function = field.function; } else { get_function = 'get'; } // Get the fields var req = { method: 'GET', url: '/' + field.controller + '/' + get_function, } $http(req).then(function(response) { // Success? Set the options if (response.status && response.data.status) { field.options = response.data.data; if (!$routeParams.hash) { $scope.onChange(field); } } else { // Error } }); } // Get the flight carriers $scope.getCarriers = function() { // Get the fields var req = { method: 'GET', url: '/carrier/getAll', } $http(req).then(function(response) { // Success? Set the options if (response.status && response.data.status) { $scope.carriers = response.data.data; } else { // Error $scope.notification('Foutmelding', "De vliegmaatschappijen konden niet opgehaald worden." + response.data.message, 'danger'); } }); } $scope.getCarriers(); // Get the airports $scope.getAirports = function() { // Get the fields var req = { method: 'GET', url: '/airport/getForSelect', } $http(req).then(function(response) { // Success? Set the options if (response.status && response.data.status) { $scope.airports = response.data.data; } else { // Error $scope.notification('Foutmelding', "De vliegmaatschappijen konden niet opgehaald worden." + response.data.message, 'danger'); } }); } $scope.getAirports(); // A field value is changed $scope.onChange = function(field, option = null) { // If the value is JSON formatted, decode it if (isJSON(field.value)) { field.value = JSON.parse(field.value); } // Convert a number to a string if (['select','customer','customer_account','camp'].includes(field.type) && parseInt(field.value)) { field.value = field.value.toString() } if (field.on_change_function && field.on_change_function.length) { if (typeof $scope[field.on_change_function] === 'function') { // Call the function $scope[field.on_change_function](field, option); } } //informal/ formal text if (field.subtype == 'formal_mail') { $scope.onMailChange(field); } } $scope.onMailChange = function(changedField) { angular.forEach(angular.copy($scope.pageData.fields), function(field, key){ if (field != undefined && field.subtype != undefined) { switch (field.subtype){ case 'formal_mail': if (changedField.subtype == 'informal_mail' && changedField.value == true) { $scope.pageData.fields[key].value = false; } else if (changedField.subtype == 'informal_mail') { $scope.pageData.fields[key].value = true } break; case 'informal_mail': if (changedField.subtype == 'formal_mail' && changedField.value == true) { $scope.pageData.fields[key].value = false; } break; } } }); } // A field is blurred (focus is turned off) $scope.onBlur = function(field, option = null) { // If the value is JSON formatted, decode it if (isJSON(field.value)) { field.value = JSON.parse(field.value); } // Convert a number to a string if (['select','customer','customer_account','camp'].includes(field.type) && parseInt(field.value)) { field.value = field.value.toString() } if (field.on_blur_function && field.on_blur_function.length) { if (typeof $scope[field.on_blur_function] === 'function') { // Call the function $scope[field.on_blur_function](field, option); } } } $scope.updatePreviewMail = function(field, option) { if ($scope.originalInformalMail && $scope.pageData && $scope.pageData.fields) { $scope.informalMail = JSON.parse(JSON.stringify($scope.originalInformalMail)); angular.forEach($scope.pageData.fields, function(field, key) { if (field.value) { switch (field.subtype) { case 'additional_text_template': $scope.informalMail.html = $scope.informalMail.html.replace('##text##', field.value); break; case 'contact': $scope.informalMail.html = $scope.informalMail.html.replace('##customerName##', field.value); break; } } }); } } // A field is initiated $scope.onInit = function(field, option = null) { // If the value is JSON formatted, decode it if (isJSON(field.value)) { field.value = JSON.parse(field.value); } // Convert a number to a string if (['select','customer','customer_account','camp'].includes(field.type) && parseInt(field.value)) { field.value = field.value.toString() } if (field.on_init_function && field.on_init_function.length) { if (typeof $scope[field.on_init_function] === 'function') { // Call the function $scope[field.on_init_function](field, option); } } } $scope.setDefaultCampChoise = function (field, option) { //set default value if (field.value == undefined) { field.value = 'yes'; } } $scope.setDefaultHotelChoise = function (field, option) { //set default value if (field.value == undefined) { field.value = 'yes'; } } $scope.setDefaultFlightChoise = function (field, option) { //set default value if (field.value == undefined) { field.value = 'yes'; } } $scope.changePrice = function (field) { // Update the field values if (field && field.value && $scope.totalPricePP) { // Calculate margin pp let isRbr = $scope.getfVar('rbr'); let pp = ($scope.totalPricePP * $scope.amountOfAttendees); let ap = field.value * $scope.amountOfAttendees; let bm = ap - pp; let rbrCosts = 0; if (isRbr) { rbrCosts = bm * (21 / 121); } else { rbrCosts = 0; } let m = bm - rbrCosts; let mp = (m / ap) * 100; // Add results to $scope so they can be used in other places $scope.calculatedMargin = { brutomargin: parseFloat(bm.toFixed(2)), rbrcosts: parseFloat(rbrCosts.toFixed(2)), marginppabs: parseFloat(m.toFixed(2)), marginpp: parseFloat(mp.toFixed(2)) }; // Update the scope with the calculated margin $scope.setfVar('brutomargin', parseFloat(bm.toFixed(2))); $scope.setfVar('rbrcosts', parseFloat(rbrCosts.toFixed(2))); $scope.setfVar('marginppabs', parseFloat(m.toFixed(2))); $scope.setfVar('marginpp', parseFloat(mp.toFixed(2))); if (mp < 20) { $scope.notification('Waarschuwing!', 'De nieuwe marge p.p. ligt onder de 20%', 'warning'); } // Calculate total price of whole arrangement if (field && field.value && $scope.amountOfAttendees) { field.comment = "Totale prijs voor arrangement: € " + parseFloat(ap).toFixed(2); $scope.calculateDeposit(); } } if (field && field.value < $scope.totalPricePP) { $scope.notification('Waarschuwing!', 'Deze prijs is lager dan de berekende totaalprijs per persoon.', 'warning'); } } $scope.changeMargin = function (field) { // Update the field values if(field && !isNaN(field.value)){ let isRbr = $scope.getfVar('rbr'); let mp = field.value / 100; let pp = ($scope.totalPricePP * $scope.amountOfAttendees); let m = 0; let bm = 0; if (isRbr) { m = (mp * pp) / (1-(1.21*mp)); bm = m * 1.21; } else { m = (mp * pp) / (1-(mp)); bm = m; } let ap = (pp + bm); let appp = ap / $scope.amountOfAttendees; let rbrCosts = bm - m; // Add results to $scope so they can be used in other places $scope.calculatedMargin = { brutomargin: parseFloat(bm.toFixed(2)), rbrcosts: parseFloat(rbrCosts.toFixed(2)), marginppabs: parseFloat(m.toFixed(2)), marginpp: parseFloat(mp.toFixed(2)) }; $scope.setfVar('brutomargin', parseFloat(bm.toFixed(2))); $scope.setfVar('rbrcosts', parseFloat(rbrCosts.toFixed(2))); $scope.setfVar('pricepp', parseFloat(appp.toFixed(2))); $scope.setfVar('marginppabs', parseFloat(m.toFixed(2))); if (parseFloat(field.value) < 20) { $scope.notification('Waarschuwing!', 'De nieuwe marge p.p. ligt onder de 20%', 'warning'); } } } $scope.changeMarginAbs = function (field) { // Update the field values if(field && !isNaN(field.value)){ let isRbr = $scope.getfVar('rbr'); let m = field.value; let purchasePrice = ($scope.totalPricePP * $scope.amountOfAttendees); let bm = 0; if (isRbr) { bm = m * 1.21; } else { bm = m; } let ap = (purchasePrice + bm); let appp = ap / $scope.amountOfAttendees; let mp = (m / ap) * 100; let rbrCosts = bm - m; // Add results to $scope so they can be used in other places $scope.calculatedMargin = { brutomargin: parseFloat(bm.toFixed(2)), rbrcosts: parseFloat(rbrCosts.toFixed(2)), pricepp: parseFloat(appp.toFixed(2)), marginpp: parseFloat(mp.toFixed(2)) }; $scope.setfVar('brutomargin', parseFloat(bm.toFixed(2))); $scope.setfVar('rbrcosts', parseFloat(rbrCosts.toFixed(2))); $scope.setfVar('pricepp', parseFloat(appp.toFixed(2))); $scope.setfVar('marginpp', parseFloat(mp.toFixed(2))); if (parseFloat(mp) < 20) { $scope.notification('Waarschuwing!', 'De nieuwe marge p.p. ligt onder de 20%', 'warning'); } } } // calculate deposit amount if manual deposit is not checked $scope.calculateDeposit = function() { var priceppField = $scope.getField('pricepp'); if (priceppField !== undefined && priceppField !== null && priceppField.value) { var totalPrice = parseFloat(priceppField.value) * $scope.amountOfAttendees; // calculate and set deposit amount if the manual deposit is not checked var manualDepositField = $scope.getField('manualdeposit'); if (manualDepositField === undefined || manualDepositField === null || manualDepositField.value == false) { var depositAmount = totalPrice * 0.3; //get from date field var fromDate = $scope.getField('from'); if (fromDate.value != undefined) { var diffTime = Math.abs(new Date() - fromDate.value ); var diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24)); if (diffDays >= 60 && diffDays <= 90) { depositAmount = totalPrice * 0.7; // 70% invoice } else if (diffDays < 60) { depositAmount = totalPrice; // 100% inovice } else { depositAmount = totalPrice * 0.3; // %30 invoice } } depositAmount = depositAmount.toFixed(2); $scope.setfVar('deposit', parseFloat(depositAmount)); } } } $scope.changeManualDeposit = function (field) { // set deposit field read only based on manual input var depositField = $scope.getField('deposit'); if (depositField !== undefined && depositField !== null) { depositField.readOnly = field.value ? false : true; // if read only, recalculate total price if (depositField.readOnly) { $scope.calculateDeposit(); } } } $scope.changeActivityMatch = function (activity) { Activity.setMatch($scope, activity); } // The customer is changed $scope.changeCustomer = function(changedField) { if (changedField) { var selectedOption = null; if (changedField.value && !isNaN(changedField.value)) { selectedOption = changedField.options.filter(option => option.id === changedField.value) } selectedOption = selectedOption ? selectedOption[0] : {}; // Update the field values angular.forEach($scope.pageData.fields, function(field, key) { switch (field.subtype) { // Customer name case 'customername': $scope.pageData.fields[key].value = selectedOption.name; if (selectedOption.name && !selectedOption.new) { $scope.pageData.fields[key].readOnly = true; }else{ $scope.pageData.fields[key].readOnly = false; } break; // Club name case 'club': $scope.pageData.fields[key].value = selectedOption.club_name; if (selectedOption.club_name && !selectedOption.new) { $scope.pageData.fields[key].readOnly = true; }else{ $scope.pageData.fields[key].readOnly = false; } break; // Salutation case 'salutation': $scope.pageData.fields[key].value = selectedOption.contactperson_salutation; if (selectedOption.contactperson_salutation && !selectedOption.new) { $scope.pageData.fields[key].readOnly = true; }else{ $scope.pageData.fields[key].readOnly = false; } break; // Contact person case 'contact': $scope.pageData.fields[key].value = selectedOption.contactperson_name; if (selectedOption.contactperson_name && !selectedOption.new) { $scope.pageData.fields[key].readOnly = true; }else{ $scope.pageData.fields[key].readOnly = false; } break; // Address case 'address': $scope.pageData.fields[key].value = selectedOption.address; if (selectedOption.address && !selectedOption.new) { $scope.pageData.fields[key].readOnly = true; }else{ $scope.pageData.fields[key].readOnly = false; } break; // postalcode case 'zipcode': $scope.pageData.fields[key].value = selectedOption.postalcode; if (selectedOption.postalcode && !selectedOption.new) { $scope.pageData.fields[key].readOnly = true; }else{ $scope.pageData.fields[key].readOnly = false; } break; // place case 'place': $scope.pageData.fields[key].value = selectedOption.place; if (selectedOption.place && !selectedOption.new) { $scope.pageData.fields[key].readOnly = true; }else{ $scope.pageData.fields[key].readOnly = false; } break; // country case 'country': if (selectedOption.country) { var selectedCountry = $filter('filter')($scope.countries, {'code': selectedOption.country }); $scope.pageData.fields[key].value = selectedCountry[0] && selectedCountry[0].id ? selectedCountry[0].id : {}; if (selectedOption.country && !selectedOption.new) { $scope.pageData.fields[key].readOnly = true; } else { $scope.pageData.fields[key].readOnly = false; } } else { $scope.pageData.fields[key].value = null; $scope.pageData.fields[key].readOnly = false; } break; // VAT code case 'vatcode': $scope.pageData.fields[key].value = selectedOption.vat_code; if (selectedOption.vat_code && !selectedOption.new) { $scope.pageData.fields[key].readOnly = true; }else{ $scope.pageData.fields[key].readOnly = false; } break; // email case 'email': $scope.pageData.fields[key].value = selectedOption.email; if (selectedOption.email && !selectedOption.new) { $scope.pageData.fields[key].readOnly = true; }else{ $scope.pageData.fields[key].readOnly = false; } break; // coc_code case 'coccode': $scope.pageData.fields[key].value = parseInt(selectedOption.coc_code); if (selectedOption.coc_code && !selectedOption.new) { $scope.pageData.fields[key].readOnly = true; }else{ $scope.pageData.fields[key].readOnly = false; } break; // phone_number case 'phone': $scope.pageData.fields[key].value = selectedOption.phone_number; if (selectedOption.phone_number && !selectedOption.new) { $scope.pageData.fields[key].readOnly = true; }else{ $scope.pageData.fields[key].readOnly = false; } break; //empty cc, bcc case 'cc': $scope.pageData.fields[key].value = ''; break; case 'bcc': $scope.pageData.fields[key].value = ''; break; } }); // retrieve customer accounts $scope.retrieveCustomerAccounts(selectedOption.id); }else{ //if new customer all fields !readOnly angular.forEach($scope.pageData.fields, function(field, key) { $scope.pageData.fields[key].readOnly = false; }); } } $scope.retrieveCustomerAccounts = function(customerId) { $scope.customerAccounts = []; var req = { method: 'GET', url: '/customer/getAccounts/' + customerId + '/1', } $http(req).then(function(response) { // Success? if (response.status && response.data.status && response.data.data[0]) { $scope.customerAccounts = response.data.data; } else { $scope.customerAccounts = []; } }, function(error) { $scope.customerAccounts = []; }); } $scope.initLocationPicker = function() { $scope.selectedHotelOption = $scope.hotelOption; $scope.createMap($scope.hotelOption); $scope.showGoogleMap = true; } $scope.changeHotel = function(option) { if (option) { // If the value is JSON formatted, decode it if (isJSON(option)) { option = JSON.parse(option); } $scope.hotelOption = $scope.getHotel(option); if (option == 'Nieuw') { $scope.selectedAccommodation = 'Nieuw'; } if ($scope.hotelOption) { Hotel.formatData($scope.hotelOption); // Set the default service $scope.hotelOption.service_level = ($scope.hotelOption.service_level && $scope.hotelOption.service_level.length) ? $scope.hotelOption.service_level : 'Logies' /* // Get the camp hotel images $scope.$broadcast('getImages', { model: 'training_camp_hotels', id: $scope.hotelOption.id, item: $scope.hotelOption, }); */ // Show the location on the map $scope.createMap($scope.hotelOption); $scope.showGoogleMap = true; let informationLines = {}; if ($scope.hotelOption['information_lines']) { try { informationLines = JSON.parse($scope.hotelOption['information_lines']); } catch(e) { informationLines = {}; } } angular.forEach($scope.pageData.fields, function(field, key) { if (field.subtype == 'layout') { if (informationLines.info_header || informationLines.info) { if ($scope.pageData.fields[key].value == undefined){ $scope.pageData.fields[key].value = {}; } //set info headers if ($scope.pageData.fields[key].value['info_header'] == undefined){ $scope.pageData.fields[key].value['info_header'] = {}; } $scope.pageData.fields[key].value['info_header']['FACILITIES'] = informationLines['info_header']['FACILITIES']; $scope.pageData.fields[key].value['info_header']['MEALS'] = informationLines['info_header']['MEALS']; //set info if ($scope.pageData.fields[key].value['info'] == undefined){ $scope.pageData.fields[key].value['info'] = {}; } $scope.pageData.fields[key].value['info']['FACILITIES'] = informationLines['info']['FACILITIES']; $scope.pageData.fields[key].value['info']['MEALS'] = informationLines['info']['MEALS']; } } }); } } else { // New hotel $scope.hotelOption = {}; $scope.hotelOption.service_level = 'Logies'; } // generate hotel types $scope.getHotelRoomTypes(); } function daysBetween(startDate, endDate) { if ((typeof startDate !== 'object') ||(typeof endDate !== 'object')) { return null; } // The number of milliseconds in all UTC days (no DST) const ONE_DAY = 1000 * 60 * 60 * 24; // Convert both dates to milliseconds var start_ms = startDate.getTime(); var end_ms = endDate.getTime(); if (start_ms <= end_ms) { // Calculate the difference in milliseconds var difference_ms = Math.abs(start_ms - end_ms); // Convert back to days and return return Math.round(difference_ms/ONE_DAY); } else { // startDate > endDate return -1; } } // Change the (hotel) booking period - from date $scope.changeFromDate = function(field) { if (field) { $scope.fromDate = field.value; $scope.calculateDeposit(); if ($scope.tillDate) { // Calculate the number of nights var nights = daysBetween($scope.fromDate, $scope.tillDate); // Check #nights if (nights == -1) { $scope.notification('Let op!', 'De startdatum valt na de einddatum', 'warning'); } else if (nights >= 0) { $scope.numOfNights = nights } $scope.filterFlights(); } } } // Change the (hotel) booking period - to date $scope.changeToDate = function(field) { if (field) { $scope.tillDate = field.value; if ($scope.fromDate) { // Calculate the number of nights var nights = daysBetween($scope.fromDate, $scope.tillDate); // Check #nights if (nights == -1) { $scope.notification('Let op!', 'De startdatum valt na de einddatum', 'warning'); } else if (nights >= 0) { $scope.numOfNights = nights } $scope.filterFlights(); } } } $scope.flightsFound = true; // change the flights based on dates $scope.filterFlights = function() { if ($scope.fromDate && $scope.tillDate && $scope.campId) { var req = { method: 'POST', url: '/training_camp/getWithDates/' + $scope.pageData.fields[$scope.fieldIndex['camp']]['value'], data: { 'from': $scope.convertDateObjToJS($scope.fromDate, true, 'datetime'), 'till': $scope.convertDateObjToJS($scope.tillDate, true, 'datetime'), } } $http(req).then(function(response) { // Success? if (response.status && response.data.status && response.data.data[0]) { $scope.flightsFound = true; Flight.set($scope, response.data.data[0].flights); } else { $scope.flightsFound = false; } }); } } $scope.reloadCamp = function() { if ($scope.campId) { $scope.changeCamp($scope.pageData.fields[$scope.fieldIndex['camp']], false); } } $scope.checkCampId = function() { if ($scope.fieldIndex !== undefined && $scope.fieldIndex['camp'] !== undefined && ($scope.pageData.fields[$scope.fieldIndex['camp']].value) !== null && !isNaN($scope.pageData.fields[$scope.fieldIndex['camp']].value)) { $scope.campId = true; } else { $scope.campId = false; } } $scope.changeCamp = function(field, setOnlyOptions = false) { $scope.checkCampId(); if (field && field.value) { if (setOnlyOptions) { // Get the camp ID if (campId = parseInt(field.value)) { // Get the training camp details var req = { method: 'GET', url: '/training_camp/getWith/' + campId, } $http(req).then(function(response) { // Success? if (response.status && response.data.status && response.data.data[0]) { $scope.updateCampFields(response.data.data[0], setOnlyOptions); } else { // Error $scope.notification('Foutmelding', 'De trainingskamp velden konden niet worden bijgewerkt', 'danger'); } }); } else { $scope.updateCampFields(null, setOnlyOptions) } } else { // Give a swal swal({ title: 'Let op!', text: 'Als u dit trainingskamp selecteert, worden de huidige velden overschreven met de gegevens van dit trainingskamp.', icon: 'warning', buttons: { cancel: 'Annuleren', OK: { text: 'OK', value: true, closeModal: false, }, }, }).then( function(inputValue){ if (inputValue === true && inputValue !== null) { //ok button clicked if (!inputValue) throw null; // Get the camp ID if (campId = parseInt(field.value)) { // Get the training camp details var req = { method: 'GET', url: '/training_camp/getWith/' + campId, } $http(req).then(function(response) { // Success? if (response.status && response.data.status) { $scope.updateCampFields(response.data.data[0], setOnlyOptions); swal.stopLoading(); swal.close(); } else { // Error $scope.notification('Foutmelding', 'De trainingskamp velden konden niet worden bijgewerkt', 'danger'); } }); } else { $scope.updateCampFields(null, setOnlyOptions); swal.stopLoading(); swal.close(); } } else { //cancel button clicked $scope.pageData.fields[field.id].value = null; } }).catch(err => { if (err) { $scope.notification('Foutmelding', 'Er is een onbekende fout opgetreden!', 'danger'); console.error(err) } else { swal.stopLoading(); swal.close(); } }) } } } function isJSON(str) { try { JSON.parse(str); } catch (e) { return false; } return true; } // VAT changed $scope.changeVat = function(field) { if (field.value) { // Check the BTW validity var req = { method: 'POST', url: '/quotation/checkVatCode/' + field.value, } $http(req).then(function(response) { // Success? if (response.status && response.data.status) { $scope.hash = response.data.data.hash; // Success fields[field.id].valid = true; } else { // Error fields[field.id].valid = false; $scope.notification('Foutmelding', 'Het opgegeven BTW-nummer is ongeldig', 'danger'); } }) } } // On changing the activity $scope.changeActivity = function(activity) { // Change the activity date/time Activity.formatData(activity, false, $scope); } $scope.changeCountry = function(field) { $scope.pageData.campCountry = field.value; $scope.preparePage(3); //find country if (field.value != undefined) { let country = field.options.find(country => country.id == field.value); if (country != undefined && country.is_rbr == 1) { $scope.pageData.fields.forEach((pageDataField) => { if (pageDataField.id == 59) { pageDataField.value = true; } if (pageDataField.id == 77 || pageDataField.id == 78) { pageDataField.readOnly = true; } }); } } } $scope.changeHandBaggage = function(field) { $scope.handBaggage = field.value; } $scope.changeBaggage = function(field) { $scope.baggage = field.value; } $scope.changeBudget = function(field) { $scope.budget = field.value; } $scope.changeSportBaggage = function(field) { $scope.sportBaggage = field.value; } $scope.changeSelfTransport = function(field) { $scope.selfTransport = field.value; } $scope.changeTouristTax = function(field) { $scope.tourist_tax = field.value; } $scope.getAirports = function() { var req = { method: 'GET', url: '/airport/getAll', } $http(req).then(function(response) { // Success? if (response.status && response.data.status && response.data.data) { $scope.airports = response.data.data; } else { $scope.notification('Foutmelding', 'Geen beschikbare vluchten gevonden', 'danger'); } }); } $scope.getAirports(); $scope.getAirportByIata = function(iata) { if ($scope.airports && Array.isArray($scope.airports)) { let selectedAirport = {}; angular.forEach(angular.copy($scope.airports), function(airport) { if (airport.iata == iata) { selectedAirport = airport; } }, selectedAirport); return selectedAirport.name + ' (' + selectedAirport.iata + ')'; } } $scope.getSelectOptions = function(field) { if (field) { switch (field.subtype) { case 'hotels': field.options = $scope.hotels break; case 'flights': field.options = $scope.flights break; case 'country': field.options = $scope.countries break; } return field.options; } return []; } $scope.getFilteredCustomers = function(field, filter) { var customers = $scope.getSelectOptions(field); //check if customers are defined if (customers !== undefined && customers !== null) { //filter customers with filter customers = customers.filter(function (customer) { return customer.name.toLowerCase().includes(filter.toLowerCase()); }, filter); //if only 1 result fill and call onchange if (customers.length == 1 && field.value != customers[0]['id']) { field.value = customers[0]['id']; $scope.onChange(field); } } return customers; } $scope.getFilteredCustomerAccounts = function(field) { return $scope.customerAccounts; } $scope.selectOptionName = function(option, field = null) { var optionName = ''; optionName = option.name; return optionName; } $scope.toggleTKorAllHotels = function() { if ($scope.campHotels !== undefined) { if ($scope.hotels == $scope.allHotels) { $scope.hotels = $scope.campHotels; } else { $scope.hotels = $scope.allHotels; } } } $scope.updateCampFields = function(data, setOnlyOptions = null) { //$scope.originalCampData = angular.copy(data); // Update the field values angular.forEach($scope.pageData.fields, function(field, key) { switch (field.subtype) { // Camp name case 'campname': if (!setOnlyOptions) { $scope.pageData.fields[key].value = data ? data.name : null; } break; // Training camp place/location case 'camplocation': if (!setOnlyOptions) { $scope.pageData.fields[key].value = data ? data.location : null; } break; // Training camp country case 'campcountry': if (!setOnlyOptions) { if (data) { country = data.country.id; $scope.pageData.fields[key].value = country; $scope.pageData.campCountry = data.country; $scope.changeCountry(field); } else { $scope.pageData.campCountry = null } } break; case 'description': if (data && !setOnlyOptions) { $scope.pageData.fields[key].value = data.description; break; } // Training camp transfers case 'transfers': if (!setOnlyOptions) { if (data) { $scope.pageData.fields[key].value = data.transfers; } } break; // Tourist tax options case 'tourist_tax': if (!setOnlyOptions) { if (data) { if (data.has_tourist_tax == "0") { $scope.pageData.fields[key].value = false; } else { $scope.pageData.fields[key].value = true; } } } break; // Flight options case 'flights': $scope.filterFlights(); break; // if (data && !setOnlyOptions) { // Flight.set($scope, data.flights); // // Add/show these options by default // Flight.resetAddMany($scope, $scope.campData, data.flights); // } else { // Flight.init($scope, $http); // } // break; // Activity options case 'activities': if (data && !setOnlyOptions) { //remove options not standardised in standard camp //Activity.set($scope, data.activities); data.activities = $filter('orderBy')(angular.copy(data.activities), 'day'); // Add/show these options by default Activity.resetAddMany($scope, $scope.campData, data.activities); } else { Activity.init($scope, $http); } break; // The camp exclusion case 'exclusive': if (data && !setOnlyOptions) { $scope.pageData.fields[key].value = data && data.exclusive ? data.exclusive : null; break; } break; // The selected hotel case 'hotels': // Set the hotel options if (data) { // Set the hotel options // Hotel.set($scope, data.hotels); if (!setOnlyOptions) { // If there is only 1 hotel option, select it by default if (data.hotels.length == 1) { // format hotel option for number data Hotel.formatData(data.hotels[0]); $scope.pageData.fields[key].value = data.hotels[0]; if(data.hotels[0]['price_surcharge_single_sales']){ data.hotels[0]['price_surcharge_single_sales'] = parseFloat(data.hotels[0]['price_surcharge_single_sales']); } if(data.hotels[0]['price_laundry_service']){ data.hotels[0]['price_laundry_service'] = parseFloat(data.hotels[0]['price_laundry_service']); } if(data.hotels[0]['phone_number']){ data.hotels[0]['phone_number'] = data.hotels[0]['phone_number']; } if(data.hotels[0]['email']){ data.hotels[0]['email'] = data.hotels[0]['email']; } if (data.hotels[0]['rooms'] !== undefined && Array.isArray(data.hotels[0]['rooms'])) { // correct format } else if (data.hotels[0]['rooms'] !== undefined) { try { data.hotels[0]['rooms'] = JSON.parse(data.hotels[0]['rooms']); } catch (e) { data.hotels[0]['rooms'] = []; } } // set hotel option $scope.hotelOption = data.hotels[0]; $scope.selectedAccommodation = data.hotels[0].id; // create map $scope.createMap($scope.hotelOption); $scope.showGoogleMap = true; // generate hotel room types for chambers $scope.getHotelRoomTypes(); } else { // set default value $scope.hotelOption = { service_level: 'Logies' } $scope.selectedAccommodation = null; } } //set Available Hotels $scope.campHotels = data.hotels; $scope.hotels = data.hotels; } else { Hotel.init($scope, $http) $scope.selectedAccommodation = null } break; case 'layout': if (data && !setOnlyOptions) { let informationLines = { info: {}, info_header: {}, }; if (data.hotels && Array.isArray(data.hotels) && data.hotels.length == 1 && data.hotels[0] && data.hotels[0]['information_lines']) { try { let hotelInformationLines = JSON.parse(data.hotels[0]['information_lines']); informationLines = Object.assign(informationLines, hotelInformationLines); } catch(e) { informationLines = { info: {}, info_header: {}, }; } } if (data['information_lines']) { try { let generalInformationLines = JSON.parse(data['information_lines']); if (generalInformationLines['info'] !== undefined && generalInformationLines['info'] && typeof generalInformationLines['info'] === 'object') { if (informationLines['info'] !== undefined && informationLines['info'] && typeof informationLines['info'] === 'object') { informationLines['info'] = Object.assign(informationLines['info'], generalInformationLines['info']); } else { informationLines['info'] = generalInformationLines['info']; } } if (generalInformationLines['info_header'] !== undefined && generalInformationLines['info_header'] && typeof generalInformationLines['info_header'] === 'object') { if (informationLines['info_header'] !== undefined && informationLines['info_header'] && typeof informationLines['info_header'] === 'object') { informationLines['info_header'] = Object.assign(informationLines['info_header'], generalInformationLines['info_header']); } else { informationLines['info_header'] = generalInformationLines['info_header']; } } } catch(e) { informationLines = { info: {}, info_header: {}, }; } } if ($scope.pageData.fields[key].value !== undefined && informationLines){ $scope.pageData.fields[key].value = Object.assign($scope.pageData.fields[key].value, informationLines); } else if ($scope.pageData.fields[key].value === undefined) { $scope.pageData.fields[key].value = informationLines; } } break; } }); } // Save the current page and go to the next page $scope.nextPage = function() { $scope.setValues($scope.currentPage + 1); } // Save the current page and go to the next page $scope.previousPage = function() { $scope.setValues($scope.currentPage - 1); } // Go top page [pageNum] $scope.goToPage = function(pageNum) { // Set the current values $scope.setValues(pageNum); } // Send an e-mail to the customer $scope.sendMail = function() { // Send an email var req = { method: 'POST', url: '/quotation/email/' + $scope.quotationHash, } $http(req).then(function(response) { // Success? if (response.status && response.data.status) { // Success $scope.notification('Succes','De nieuwe offerte is successvol verzonden!', 'success'); } else { // Error $scope.notification('Foutmelding', 'Deze offerte kan niet verzonden worden.
' + response.data.message, 'danger'); } }); } // Format the retrieved data $scope.formatGetData = function(fields) { angular.forEach(fields, function(field, key) { // Format the date and time format if (['date','time'].includes(field.type)) { fields[key].value = $scope.convertDateObjToJS(field.value, false, field.type); } // Convert boolean values fields[key].ask_validation = field.ask_validation == '1'; if (field.type == 'checkbox') { fields[key].value = field.value == '1'; } }); return fields; } $scope.convertDateObjToJS = function(objDate, reverse, type) { if (!objDate) { return objDate; } if (!reverse) { if (typeof objDate === 'object') { return objDate; } tempTime = objDate.split(/[- :T.]/) switch(type){ case 'date': tempNewTime = new Date(tempTime[0], tempTime[1]-1, tempTime[2], 0, 0, 0); break; case 'time': if(!tempTime[2]){ tempTime[2] = 0; } tempNewTime = new Date(0 ,0, 0, tempTime[0], tempTime[1], 0); break; case 'datetime': tempNewTime = new Date(tempTime[0], tempTime[1]-1, tempTime[2], tempTime[3], tempTime[4], tempTime[5] ? tempTime[5] : 0); break; } return tempNewTime; }else{ if (typeof objDate === 'string') { return objDate; } switch(type){ case 'date': if(typeof objDate.getFullYear !== 'function'){ return null; } return ([objDate.getFullYear(), objDate.getMonth()+1, objDate.getDate()].join('-')); break; case 'time': if(typeof objDate.getHours !== 'function'){ return null; } return ([('00' + objDate.getHours()).slice(-2), ('00' + objDate.getMinutes()).slice(-2)].join(':')); break; case 'datetime': if(typeof objDate.getFullYear !== 'function'){ return null; } return ([objDate.getFullYear(), objDate.getMonth()+1, objDate.getDate()].join('-')+' '+[('00' + objDate.getHours()).slice(-2), ('00' + objDate.getMinutes()).slice(-2)].join(':')); break; default: return objDate; break; } } } // Create a new quotation using the data in the database $scope.createQuotation = function() { // Is an existing quotation revised? Warn the user if ($routeParams.hash) { swal({ title: 'Let op!', text: 'Er wordt een bijgewerkte, nieuwe versie van deze offerte aangemaakt.', icon: 'warning', buttons: { cancel: 'Annuleren', OK: true, }, }).then(ok => { if (!ok) throw null; $scope.postQuotation(); }).catch(err => { if (err) { swal('Foutmelding', 'De aanvraag is mislukt!', 'error'); console.error(err) } else { swal.stopLoading(); swal.close(); } }); } else { $scope.postQuotation(); } } function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } $scope.postQuotation = function(saveOk = false) { //check if (!saveOk) { if ($scope.fromDate && $scope.tillDate && $scope.campData.flights) { let showModal = false; let fromDateInFlight = false; let tillDateInFlight = false; //loop flights to see if they are on the camp dates if ($scope.campData.flights.length) { angular.forEach(angular.copy($scope.campData.flights), function(flight) { if (!(moment(flight.departure_date).format('YYYY-MM-DD') >= moment($scope.fromDate).format('YYYY-MM-DD') && moment(flight.arrival_date).format('YYYY-MM-DD') <= moment($scope.tillDate).format('YYYY-MM-DD'))) { showModal = true; } if (moment(flight.departure_date).format('YYYY-MM-DD') == moment($scope.fromDate).format('YYYY-MM-DD')) { fromDateInFlight = true; } if (moment(flight.arrival_date).format('YYYY-MM-DD') == moment($scope.tillDate).format('YYYY-MM-DD')) { tillDateInFlight = true; } }); if (!fromDateInFlight || !tillDateInFlight) { showModal = true; } } else { saveOk = true; } if (showModal) { $('#flight-modal').modal('show'); return; } else { saveOk = true; } } else { saveOk = true; } } // Copy the fields object var fields = Object.assign({}, $scope.pageData.fields); // angular copy to evade warnings when transforming date objects fields = angular.copy(fields); angular.forEach(fields, function(field, key) { // Format the dates if (['date','time'].includes(field.type)) { fields[key].value = $scope.convertDateObjToJS(field.value, true, field.type); } if ((field.ask_validation == false) && field.controller) { // Delete the field options delete field.options; } if (field.subtype == 'customer'){ if ($scope.customerId !== undefined) { fields[key].value = $scope.customerId; } } switch (field.type) { // Set the hotel options case 'hotels': if ($scope.hotelOption) { fields[key].value = [$scope.hotelOption]; newHotelId = field.show_on_field_id; } break; // Set the activities case 'activities': fields[key].value = angular.copy($scope.campData.activities); // Format the data angular.forEach(fields[key].value, function(activity) { Activity.formatData(activity, true, $scope); }); break; // Set the flights case 'flights': var campDataFlights = []; if ($scope.campData.flights) { campDataFlights = angular.copy($scope.campData.flights); angular.forEach(campDataFlights, function(flight, index) { if (flight['arrival_date']){ campDataFlights[index]['arrival_date'] = moment(flight['arrival_date']).format('YYYY-MM-DD HH:mm:ss'); } if (flight['departure_date']){ campDataFlights[index]['departure_date'] = moment(flight['departure_date']).format('YYYY-MM-DD HH:mm:ss'); } }); } fields[key].value = campDataFlights; break; // Set the rooms case 'chambers': fields[key].value = $scope.roomTypes; break; } }); if(saveOk) { // Create the quotation, send the data var req = { method: 'POST', url: '/quotation/createQuotation', data: { 'quotation_number': $scope.quotationNumber, 'fields': fields, } } $http(req).then(async function(response) { // Success? if (response.status && response.data.status) { $scope.quotationHash = response.data.data.hash; if (response.data.message) { $scope.quotationReadOnly = true; // Warning $scope.notification('Warning', response.data.message, "warning"); await sleep(2000); } // Rewrite the url if ($location.search().p !== undefined && angular.isNumber(parseInt($location.search().p))) { window.location.replace('page/offerte/' + $scope.quotationHash + '?p=' + $location.search().p); } else { window.location.replace('page/offerte/' + $scope.quotationHash); } // Success $scope.notification('Success', ($routeParams.hash ? 'De offerte is bijgewerkt' : 'De nieuwe offerte is successvol aangemaakt!'), "success"); } else { // Error $scope.notification('Foutmelding', 'De offerte kon helaas niet aangemaakt worden.
' + response.data.message, "danger"); } }, function(error) { // Error $scope.notification('Foutmelding', 'De offerte kon helaas niet aangemaakt worden.', "danger"); }); } } $scope.formatFlightDate = function(date, dateFormat) { return moment(date).format(dateFormat); } // Get the countries $scope.getCountries = function() { var req = { method: 'GET', url: '/country/getNames', } $http(req).then(function(response) { // Success? Set the options if (response.status && response.data.status) { $scope.countries = response.data.data; } else { // Error $scope.notification('Foutmelding', response.data.message, "danger"); } }); } $scope.getCountries(); $scope.campData = {}; Activity.init($scope, $http); // Add a flight $scope.addFlight = function(newItem) { if (newItem) { //check allotment let req = { method: 'POST', url: '/quotation/getavailableallotments', data: newItem, } $http(req).then(function(response) { if (response.status && response.data.status) { newItem.available_allotments = response.data.data.available_allotments; } //check for carrier id and set in carrier object if (newItem.carrier_id) { newItem['carrier'] = new Object(); newItem['carrier']['id'] = newItem.carrier_id; //execute changeCarrier function to set defaults $scope.changeCarrier(newItem); } var itemNum = Flight.add($scope, $scope.campData, newItem) $timeout(function() { $('#flight' + itemNum).collapse() }, 0); }); } else { var itemNum = Flight.add($scope, $scope.campData, newItem) $timeout(function() { $('#flight' + itemNum).collapse() }, 0); } } // Delete a flight $scope.deleteFlight = function(key) { swal({ title: 'Waarschuwing!', text: 'Weet u zeker dat u deze vlucht wilt verwijderen?', icon: 'warning', buttons: { cancel: 'Annuleren', OK: true, }, }).then(ok => { if (!ok) throw null; if ($scope.quotationStatus == 'Concept') { Flight.delete(key, $scope.campData); $scope.$apply(); } }).catch(err => { if (err) { $scope.notification('Foutmelding', 'Het verwijderen is mislukt!', 'danger'); console.error(err) } else { swal.stopLoading(); swal.close(); } }) } // Add an activity $scope.addActivity = function(newItem) { //var itemNum = Activity.add($scope, $scope.campData, newItem); //$timeout(function() { $('#activity' + itemNum).collapse() }, 0); } // Delete an activity $scope.deleteActivity = function(key, activityOption) { //find activity for the right activity to delete let selectedActivity = $scope.campData.activities.findIndex(activity => activity == activityOption); swal({ title: 'Waarschuwing!', text: 'Weet u zeker dat u deze activiteit wilt verwijderen?', icon: 'warning', buttons: { cancel: 'Annuleren', OK: true, }, }).then(ok => { if (!ok) throw null; if ($scope.quotationStatus == 'Concept') { Activity.delete(selectedActivity, $scope.campData); $scope.$apply(); } }).catch(err => { if (err) { $scope.notification('Foutmelding', 'Het verwijderen is mislukt!', "danger"); console.error(err) } else { swal.stopLoading(); swal.close(); } }) } // Add an hotel $scope.addHotel = function(newItem) { Hotel.add($scope, $scope.campData, newItem) } // Delete an hotel $scope.deleteHotel = function(key) { swal({ title: 'Waarschuwing!', text: 'Weet u zeker dat u dit hotel wilt verwijderen?', icon: 'warning', buttons: { cancel: 'Annuleren', OK: true, }, }).then(ok => { if (!ok) throw null; if ($scope.quotationStatus == 'Concept') { Hotel.delete(key, $scope.campData); } }).catch(err => { if (err) { $scope.notification('Foutmelding', 'Het verwijderen is mislukt!', "danger"); console.error(err) } else { swal.stopLoading(); swal.close(); } }) } /** * Function to initiate Google Maps */ $scope.createMap = function(hotelOption) { if (!hotelOption) { console.warn('Er is geen hotel geselecteerd.'); } // Get lat and long from the hotel if (hotelOption && hotelOption.latitude != undefined && !isNaN(parseFloat(hotelOption.latitude)) && hotelOption.longitude != undefined && !isNaN(parseFloat(hotelOption.longitude))) { zoomLevel = parseInt(hotelOption.zoom_level); // Set lat en long from hotel var LatLng = {lat: parseFloat(hotelOption.latitude), lng: parseFloat(hotelOption.longitude)}; setMarker = true; } else { //if undefined set Amsterdam lat en long var LatLng = {lat: 52.3545653, lng: 4.7585435}; setMarker = false; } // Get the zoom level if ((typeof zoomLevel === 'undefined') || !zoomLevel || isNaN(zoomLevel)) { zoomLevel = 4; } // Init map mapId = 'hotelMap' if (mapElement = document.getElementById(mapId)) { var map = new google.maps.Map(mapElement, { zoom: zoomLevel, center: LatLng, disableDefaultUI: $scope.quotationReadOnly, }); if (setMarker) { $scope.marker = new google.maps.Marker({ position: LatLng, map: map, title: "Hotel" }); } else { $scope.marker = null } if (!$scope.quotationReadOnly) { // Create the search box and link it to the UI element. var card = document.getElementById('pac-card'); var input = document.getElementById('pac-input'); var infowindowContent = document.getElementById('infowindow-content'); map.controls[google.maps.ControlPosition.LEFT_TOP].push(card); var autocomplete = new google.maps.places.Autocomplete(input); var infowindow = new google.maps.InfoWindow(); infowindow.setContent(infowindowContent); autocomplete.addListener('place_changed',function() { document.getElementById("location-error").style.display = 'none'; infowindow.close(); var place = autocomplete.getPlace(); if (!place.geometry) { document.getElementById("location-error").style.display = 'inline-block'; document.getElementById("location-error").innerHTML = "Cannot Locate '" + input.value + "' on map"; return; } map.fitBounds(place.geometry.viewport); if ($scope.marker != null) { $scope.marker.setPosition(place.geometry.location); $scope.marker.setVisible(true); } else { $scope.marker = new google.maps.Marker({ position: place.geometry.location, map: map, title: "Hotel" }); } }); google.maps.event.addListener(map, 'click', function( event ){ var LatLng = new google.maps.LatLng(event.latLng.lat(), event.latLng.lng()); // (Re)place the marker if ($scope.marker) { // Replace the current marker $scope.marker.setPosition(LatLng); } else { $scope.marker = new google.maps.Marker({ position: LatLng, map: map, title: "Hotel" }); } hotelOption.latitude = event.latLng.lat(); hotelOption.longitude = event.latLng.lng(); hotelOption.zoom_level = map.getZoom(); }); } } else { console.error('Google map element ' + mapId + ' is not found.') } } /** * Functions for the image modal */ $scope.showImageModal = function (item, key) { $scope.$broadcast('showImageModal', { model: null, cardSubjectId: key, item: item, }); } $scope.showCampHotelImageUploader = function(item, key) { $scope.showImageModal(item, key); } $scope.showCampActivityImageUploader = function(item, key) { $scope.showImageModal(item, key); } $scope.showCampMatchImageUploader = function(item, key) { $scope.showImageModal(item, key); } /** * Functions to add a new item dynamically in a popup form */ $scope.setNewItemFields = function(fields) { $scope.newItemFields = fields; } $scope.addNewItem = function(item) { // Create the item, send the data var req = { method: 'POST', url: '/' + item.controller + '/insert', data: item.data, } $http(req).then(function(response) { // Success? if (response.status && response.data.status) { // Success $scope.notification('Success', 'Het nieuwe item is successvol aangemaakt!', 'success'); } else { // Error $scope.notification('Foutmelding', response.data.message,"danger"); } }); } $scope.closeView = function() { window.location.replace('page/offertes') } /*--------[Hotel Calc]------------*/ $scope.calcHotelSingles = function(rooms){ singles = 0; angular.forEach(rooms, function(room){ if((room.doubles == 0 || !room.doubles) && room.singles && room.singles == 1){ singles = singles +1; } }); return singles; } $scope.calcRoomTypePrice = function(roomType, sales = false) { // set different key when sales var priceKey = 'price_surcharge'; if (sales) { priceKey = 'price_surcharge_sales'; } // check required data if (roomType['amount'] !== undefined && roomType['amount'] > 0 && roomType[priceKey] !== undefined && roomType[priceKey] != 0) { if (roomType['price_surcharge_per'] !== undefined && roomType['price_surcharge_per'] === 'PERSON') { return roomType['amount'] * (parseInt(roomType['amount_of_singles']) + (parseInt(roomType['amount_of_doubles']) * 2)) * roomType[priceKey]; } else if (roomType['price_surcharge_per'] !== undefined && roomType['price_surcharge_per'] === 'ROOM') { return roomType['amount'] * roomType[priceKey]; } } return 0.0; } // callback for manual washes $scope.changeManualWashes = function(field) { $scope.calcTrainingsPlusMatches(); } /*--------[Laundry Calc]------------*/ $scope.calcTrainingsPlusMatches = function() { // check if manual entry for laundry amount var manualLaundryAmount = false; angular.forEach($scope.pageData.fields, function (field) { if (field.subtype == 'manualwashes' && $scope.pageData.fields[field.id] !== undefined && $scope.pageData.fields[field.id].value !== undefined) { manualLaundryAmount = $scope.pageData.fields[field.id].value; } }); var laundryAmt = 0; if (manualLaundryAmount) { // find laundry amount and set field to readOnly angular.forEach($scope.pageData.fields, function (field) { if (field.subtype == 'washes' && $scope.pageData.fields[field.id] !== undefined && $scope.pageData.fields[field.id].value !== undefined) { laundryAmt = parseInt($scope.pageData.fields[field.id].value); $scope.pageData.fields[field.id].readOnly = false; } }); } else { // calculate laundry amount based on matches and trainings if($scope.campData.activities){ angular.forEach($scope.campData.activities, function(activity){ /* Matches and Trainings */ if(activity.activity_type){ activity_type = JSON.parse(activity.activity_type) if(activity_type.id){ if(activity_type.id == 1 || activity_type.id == 5) { laundryAmt = laundryAmt + 1; } } } }); } // write calculated laundry amount back to field angular.forEach($scope.pageData.fields, function (field) { if (field.subtype == 'washes') { $scope.pageData.fields[field.id].value = laundryAmt; $scope.pageData.fields[field.id].readOnly = true; } }); } return laundryAmt; } //email template functions $scope.makeElements = function() { $scope.htmlElements = '
  • '; //replace names elements angular.forEach($scope.emailTemplate.variables, function(variable, key){ $scope.htmlElements += ''; }); $scope.htmlElements += '
  • '; if ($('#email_html')) { var documentContents = $('#email_html').summernote('code'); $('#email_html').summernote('reset'); if (angular.isString(documentContents)) { $('#email_html').summernote('code', documentContents); } } } $scope.insertElement = function (context) { var ui = $.summernote.ui; var list = $('#elements-list').val(); var button = ui.buttonGroup([ ui.button({ className: 'dropdown-toggle', contents: 'Voeg een variabele in', tooltip: "Elements", container: false, data: { toggle: 'dropdown' }, click: function() { // Cursor position must be saved because is lost when dropdown is opened. context.invoke('editor.saveRange'); } }), ui.dropdown({ className: 'drop-default summernote-list', contents: $scope.htmlElements, callback: function($dropdown) { $dropdown.find('ul').click(function() { context.invoke('editor.restoreRange'); context.invoke('editor.focus'); context.invoke('editor.insertText', $(this)[0].innerText); }); } }) ]); return button.render(); } //summernote config $scope.summernoteoptions = { toolbar: [ ['edit',['undo','redo']], ['headline', ['style']], ['style', ['bold', 'italic', 'underline', 'clear']], ['fontface', ['fontname']], ['textsize', ['fontsize']], ['fontclr', ['color']], ['alignment', ['ul', 'ol', 'paragraph', 'lineheight']], ['height', ['height']], ['table', ['table']], ['insert', ['link','hr','picture']], ['view', ['fullscreen', 'codeview']], ['extraColom', ['element']], ], buttons: { element: $scope.insertElement } }; }); app.directive('stringToNumber', function() { return { require: 'ngModel', link: function(scope, element, attrs, ngModel) { ngModel.$parsers.push(function(value) { return '' + value; }); ngModel.$formatters.push(function(value) { return parseFloat(value); }); } }; });