(function () { 'use strict'; // Source: src/html/scripts/tour-sales/module.js angular.module('tour-sales', [ 'ui.router', 'tours', 'ui.bootstrap', 'daterangepicker' ]); angular.module('sightseeing-sales', [ 'ui.router', 'tours', 'ui.bootstrap', 'daterangepicker' ]); angular.module('vo-sales', [ 'ui.router', 'tours', 'ui.bootstrap', 'htmlToPdfSave', 'updateMeta', 'daterangepicker' ]); angular.module('cruise-sales', [ 'ui.router', 'tours', 'ui.bootstrap', 'daterangepicker' ]); angular.module('clubmed-sales', [ 'ui.router', 'tours', 'ui.bootstrap', 'daterangepicker' ]); angular.module('omra-sales', [ 'ui.router', 'tours', 'ui.bootstrap', 'daterangepicker' ]); angular.module('tours', [ 'ui.bootstrap', 'daterangepicker' ]); // Source: src/html/scripts/tour-sales/states.js angular.module('tours').config([ '$sceProvider', '$stateProvider', '$urlRouterProvider', 'settings', function ($sceProvider, $stateProvider, $urlRouterProvider, settings) { // Completely disable SCE. For demonstration purposes only! // Do not use in new projects. $sceProvider.enabled(false); //https://atlasvoyages.com/ngapps/vo-sales#/?country=MA:Maroc&type=VO&lang=fr&from=2018-08-13&to=2018-10-12 $stateProvider.state('tourSearch', { url: '/?departure&theme&lang&vcity&depname&type&country&from&to', templateUrl: settings.templates.search, controller: 'tours_SearchCtrl' }).state('tour', { url: '/tour/:tour?from&to&lang', templateUrl: settings.templates.product, controller: 'tours_TourCtrl' }).state('bookings', { url: '/tours/orders/:tour', templateUrl: 'hermes-tour-orders', controller: 'tours_ords' }).state('tours2', { url: '/tours2/?departure&theme&lang&vcity&depname&type&country&from&to', templateUrl: 'tour-atlas-elite', controller: 'tours_SearchCtrl' }).state('order', { url: '/tours/order/:order', templateUrl: 'tour-order-detail', controller: 'tours_ord_det' }); $urlRouterProvider.otherwise('/'); } ]); // Source: src/html/scripts/tour-sales/saveHtmlToPdf.js angular.module('htmlToPdfSave', []); angular.module('htmlToPdfSave').directive('pdfSaveButton', [ '$rootScope', '$pdfStorage', function ($rootScope, $pdfStorage) { return { restrict: 'A', link: function (scope, element, attrs) { $pdfStorage.pdfSaveButtons.push(element); scope.buttonText = 'Button'; element.on('click', function () { var activePdfSaveId = attrs.pdfSaveButton; var activePdfSaveName = attrs.pdfName; $rootScope.$broadcast('savePdfEvent', { activePdfSaveId: activePdfSaveId, activePdfSaveName: activePdfSaveName }); }); } }; } ]); angular.module('htmlToPdfSave').directive('pdfSaveContent', [ '$rootScope', '$pdfStorage', function ($rootScope, $pdfStorage) { return { link: function (scope, element, attrs) { $pdfStorage.pdfSaveContents.push(element); var myListener = scope.$on('savePdfEvent', function (event, args) { var currentElement = element; var currentElementId = currentElement[0].getAttribute('pdf-save-content'); // save a call of query selector because angular loads the element on load by default // var elem = document.querySelectorAll('[pdf-save]') ; var elem = $pdfStorage.pdfSaveContents; var broadcastedId = args.activePdfSaveId; var broadcastedName = args.activePdfSaveName || 'default.pdf'; //iterate through the element array to match the id for (var i = 0; i < elem.length; i++) { // handle the case of elem getting length // if(i == 'length' || i == 'item') // continue ; // if the event is received by other element than for whom it what propogated for continue if (!matchTheIds(broadcastedId, currentElementId)) continue; var single = elem[i]; var singleElement = single[0]; //var parent = single[0] ; var pdfId = singleElement.getAttribute('pdf-save-content'); if (matchTheIds(pdfId, broadcastedId)) { console.log('Id is same'); convertToPdf(elem, pdfId); break; // exit the loop once pdf gets printed } } function matchTheIds(elemId, broadcastedId) { return elemId == broadcastedId; } function convertToPdf(theElement, id) { //theElement = [theElement]; convert(theElement, id); } function convert(theElement, id) { var quotes = $('div[pdf-save-content=' + id + ']')[0]; html2canvas(quotes, { onrendered: function (canvas) { var pdf = new jsPDF('p', 'pt', 'letter'); for (var i = 0; i <= quotes.clientHeight / 980; i++) { var srcImg = canvas; var sX = 0; var sY = 980 * i; // start 980 pixels down for every new page var sWidth = 900; var sHeight = 980; var dX = 0; var dY = 0; var dWidth = 900; var dHeight = 980; window.onePageCanvas = document.createElement('canvas'); onePageCanvas.setAttribute('width', 900); onePageCanvas.setAttribute('height', 980); var ctx = onePageCanvas.getContext('2d'); // details on this usage of this function: // https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Using_images#Slicing ctx.drawImage(srcImg, sX, sY, sWidth, sHeight, dX, dY, dWidth, dHeight); // document.body.appendChild(canvas); var canvasDataURL = onePageCanvas.toDataURL('image/png', 1); var width = onePageCanvas.width; var height = onePageCanvas.clientHeight; //! If we're on anything other than the first page, // add another page if (i > 0) { pdf.addPage(612, 791); //8.5" x 11" in pts (in*72) } //! now we declare that we're working on that page pdf.setPage(i + 1); //! now we add content to that page! pdf.addImage(canvasDataURL, 'PNG', 20, 40, width * 0.62, height * 0.62); } //! after the for loop is finished running, we save the pdf. pdf.save(broadcastedName); } }); /*var element = $('[pdf-save-content='+id+']') , cache_width = element.width(), a4 =[ 595.28, 841.89]; // for a4 size paper width and height $('body').scrollTop(0); createPDF(); //create pdf function createPDF(){ getCanvas().then(function(canvas){ console.log('resolved get canvas'); var img = canvas.toDataURL("image/png"), doc = new jsPDF({ unit:'px', format:'a4' }); doc.addImage(img, 'JPEG', 20, 20); doc.save(broadcastedName); element.width(cache_width); }) } // create canvas object function getCanvas(){ element.width((a4[0]*1.33333) -80).css('max-width','none'); return html2canvas(element,{ imageTimeout:2000, removeContainer:true }); }*/ } }); // handle the memory leak // unbind the event scope.$on('$destroy', myListener); } }; } ]); angular.module('htmlToPdfSave').service('$pdfStorage', function () { this.pdfSaveButtons = []; this.pdfSaveContents = []; }).service('pdfSaveConfig', function () { this.pdfName = 'default.pdf'; }); // Source: src/html/scripts/tour-sales/config/analytics.js angular.module('tours').run([ '$rootScope', '$injector', '$log', '$http', 'settings', function ($rootScope, $injector, $log, $http, settings) { var $analytics; try { $analytics = $injector.get('$analytics'); } catch (e) { // Error: [$injector:unpr] // just returned, analytics is not loaded $log.warn('$analytics not available'); return; } $rootScope.$on('tourSearchQuery', function ($event, q) { // $log.debug('tourSearchQuery query', JSON.stringify(q)); var path = '/recherche'; if (q.type.toLowerCase() == 'vo') path += '/voyages-organise'; if (q.country) path += '/' + q.country.split(':')[1]; path += '/' + q.from + '/' + q.to + '/'; // $log.debug('$analytics.pageTrack', path); // $analytics.pageTrack(path); }); $rootScope.$on('tourProducthQuery', function ($event, tourName) { $log.debug('tourProducthQuery query', tourName); var path = ''; if (tourName) { path = '/voyages-organise/' + tourName + '/'; // $log.debug('$analytics.pageTrack', path); // $analytics.pageTrack(path); } }); $rootScope.$on('bookCartSaved', function ($event, cart) { var path = '/checkout/'; var type = cart.items[0]['@type'].toLowerCase(); switch (type) { case 'air': path += 'air'; break; case 'stayitem': path += 'stay'; break; case 'omra': path += 'omra'; break; case 'haj': path += 'hajj'; break; case 'vo': path += 'voyages-organis\xe9s'; break; default: path += type; } //$log.info('checkout-update:cart:', path); // $analytics.pageTrack(path); }); /*$rootScope.$on('airOfferDetails', function ($event, quote) { var airline = _.str.slugify(quote.trip.segments[0].flights[0].marketer.code), airports = quote.trip.segments.map(function (seg) { return _.str.slugify(seg.departure.location.code) + '/' + _.str.slugify(seg.arrival.location.code); }).join('/'), path = '/flights/offer/' + airline + '/' + airports; path += '/dtd:' + moment(quote.trip.segments[0].departure.date).diff(moment(), 'days'); $log.debug('$analytics.pageTrack', path); $analytics.pageTrack(path); });*/ } ]); // Source: src/html/scripts/tour-sales/controllers/departures-calendar.js angular.module('tours').controller('tours_TourQuoteCtrl', [ '$scope', '$http', '$stateParams', '$location', 'settings', '$log', function ($scope, $http, $stateParams, $location, settings, $log) { var isoDate = 'YYYY-MM-DD'; var options = { adults: [ 1, 2, 3, 4, 5, 6 ], children: [ 0, 1, 2, 3, 4, 5, 6 ], childAges: [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 ] }; function buildQuery() { var query = {}; var from = moment($stateParams.from || 'invalid'); var to = moment($stateParams.to || 'invalid'); var ages; if (!from.isValid() || from.isBefore()) { from = moment().startOf('day'); } if (!to.isValid() || to.isBefore(from) || to.isSame(from)) { to = moment(from); to.add('months', 1); } if (/\d{1,2}(,\d{1,2})*/.test($stateParams.children)) { ages = $stateParams.children.split(','); } else { ages = []; } query.tour = $stateParams.tour; query.from = from.toDate(); query.to = to.toDate(); query.adults = $stateParams.adults || 1; query.children = ages.length; query.ages = ages; return query; } function queryRates(query) { var params = { qt: 'search', tour: $stateParams.tour, from: moment(query.from).format(isoDate), to: moment(query.to).format(isoDate) }; var url = settings.tours.quote; $http.get(url, { params: params }).success(function (data) { $log.debug('query', $scope.query); $scope.pricing = data[0].pricing[0]; $scope.currency = $scope.pricing.currency; $log.debug($scope.pricing); }).error(function () { $log.error('Error querying rates', arguments); }); } $scope.query = buildQuery(); $log.debug('query', $scope.query); queryRates($scope.query); // fake function getData() { var deps = [], last, i = 1; deps.push(moment().startOf('day').add('days', 3).toDate()); while (i < 10) { last = deps[i - 1]; deps.push(moment(last).add('days', 5)); i += 1; } return deps; } function isDepartue(d, deps) { var i = 0, len = deps.length; while (i < len) { if (d.isSame(deps[i])) { return true; } i += 1; } return false; } function buildDay(d, deps, month, week) { var day = { label: d.month() === month ? d.date() : '', date: moment(d).toDate(), currentMonth: d.month() === month, departure: isDepartue(d, departures) }; week.push(day); } var departures = getData(); var firstDayOfMonth = moment(departures[0]).startOf('month'); var month = firstDayOfMonth.month(); var d = moment(firstDayOfMonth).startOf('week'); var weeks = []; var week = []; while (d.month() <= month) { buildDay(d, departures, month, week); d.add('days', 1); // week end if (week.length === 7) { weeks.push(week); week = []; } } while (week.length > 0 && week.length < 7) { buildDay(d, departures, month, week); d.add('days', 1); } weeks.push(week); $scope.weeks = weeks; $scope.showRates = function (d) { $scope.rates = 'Rate for ' + moment(d).format(); }; return; var q = $location.search(); $log.log(q); var tourCode = $stateParams.tour; $scope.tourcontent = {}; $scope.description = {}; $scope.suppnbr = 0; $scope.quote = {}; $scope.ddate = ''; function initQuote() { var cur = $scope.quote.currency; $scope.quote = { status: 'quote', created: moment(), modified: moment(), pricing: { items: [], prices: [] }, trip: { content: { type: 'tour', tour: $scope.tourcontent }, travellers: [{ type: 'Traveller', classification: 'ADULT', id: 1 }] }, currency: cur }; } var url = settings.tours.endpoint; $http.get(url + '?qt=search&tour=' + $stateParams.tour + '&from=' + q.from + '&to=' + q.to).success(function (data) { $scope.pricing = data[0].pricing[0]; $scope.quote.currency = $scope.pricing.currency; }); $scope.travellers = { adult: 1, child: 0, ages: [] }; $scope.childages = function () { $scope.travellers.ages = []; for (var i = 0; i < $scope.travellers.child; i++) { $scope.travellers.ages.push({ i: i, v: 1 }); } }; $scope.setquotetravellers = function () { initQuote(); $scope.ddate = ''; $scope.selectedrate = {}; $scope.quote.trip.travellers = []; var travellerid = 1; // set adults for (var i = 0; i < $scope.travellers.adult; i++) { $scope.quote.trip.travellers.push({ type: 'Traveller', classification: 'ADULT', id: travellerid++ }); } // set children for (var i = 0; i < $scope.travellers.child; i++) { $scope.quote.trip.travellers.push({ type: 'Traveller', classification: 'CHILD', id: travellerid++, age: $scope.travellers.ages[i].v }); } }; $scope.loadproduct = function (ddate) { $scope.quote.trip.content.checkin = ddate; var ci = moment($scope.quote.trip.content.checkin, 'YYYY-MM-DDTHH:mm:SS.SSSZ'); $scope.quote.trip.content.checkout = ci.add('days', $scope.tour.days.length); getselectedrates(ddate); }; getselectedrates = function (ddate) { $scope.selectedRates = []; for (var i = 0; i < $scope.pricing.rates.length; i++) { /// RATE WILL NOT BE A TABLE for (var j = $scope.pricing.rates[i].lines.length - 1; j >= 0; j--) { var dp = moment(ddate); var ld = moment($scope.pricing.rates[i].lines[j].departure); if (ld.isSame(dp) && $scope.pricing.rates[i].lines[j].actif == true) { $scope.selectedRates.push({ category: $scope.pricing.rates[i].category, ligne: $scope.pricing.rates[i].lines[j], selected: false }); //console.log("selected rate" ,rate.lines[j]); } } ; } ; if ($scope.selectedRates.length > 0) $scope.selectedRates[0].selected = true; }; $scope.selectRate = function (index) { for (var i = $scope.selectedRates.length - 1; i >= 0; i--) { if (i == index) $scope.selectedRates[i].selected = true; else $scope.selectedRates[i].selected = false; } ; }; $scope.selectedrate = {}; $scope.selected = false; $scope.quoteloaditems = function (rate) { $scope.quote.pricing.items = []; $scope.selectedrate = rate; $scope.selected = true; // for(var i=0;i< $scope.travellers.adult;i++){ $scope.quote.pricing.items.push({ type: 'TourItem', product: { type: 'TourProduct', code: rate.category.code, childs: rate.ligne.childs, cancellation: rate.ligne.cancellation, supplements: rate.ligne.supplements }, quantity: $scope.travellers.adult, prices: [ { value: $scope.travellers.adult * rate.ligne.price, scope: 'TOTAL' }, { value: rate.ligne.price, scope: 'UNIT' } ] }); //} for (var i = 0; i < $scope.travellers.child; i++) { childage = $scope.travellers.ages[i].v; childrate = 0; var cliltrate = null; rate.ligne.childs.forEach(function (child) { if (childage <= child.to) cliltrate = child; }); if (cliltrate == null) { childrate = rate.ligne.price; } else if (cliltrate.charge[1] == '%') { childrate = rate.ligne.price * cliltrate.charge[0] / 100; } /* else if (cliltrate.charge[1] == $scope.quote.currency) { console.log("selected child price " + cliltrate + " en " + $scope.quote.currency) }*/ $scope.quote.pricing.items.push({ type: 'TourItem', product: { type: 'TourProduct', code: rate.category.code, childs: rate.ligne.childs, cancellation: rate.ligne.cancellation, supplements: rate.ligne.supplements }, quantity: 1, prices: [ { value: childrate, scope: 'TOTAL' }, { value: childrate, scope: 'UNIT' } ] }); // if(rate.ligne.childs[]) // totalprice=totalprice+rate.ligne.price; } updateTotalPrice(); }; $scope.quoteloadsupplements = function (supp, suppnbr) { for (var i = $scope.quote.pricing.items.length - 1; i >= 0; i--) { var item = $scope.quote.pricing.items[i]; if (item.product.code == supp.name) $scope.quote.pricing.items.splice(i, 1); } ; if (supp.charge[2] === $scope.quote.currency) $scope.quote.pricing.items.push({ type: 'Item', product: { type: 'Product', code: supp.name, name: supp.name }, quantity: suppnbr, prices: [ { value: parseInt(supp.charge[0] + 1) * (suppnbr * parseInt(supp.charge[1])), scope: 'TOTAL' }, { value: parseInt(supp.charge[0] + 1) * parseInt(supp.charge[1]), scope: 'UNIT' } ] }); if (supp.charge[2] == '%') $scope.quote.pricing.items.push({ type: 'Item', product: { type: 'Product', code: supp.name, name: supp.name }, quantity: suppnbr, prices: [ { value: parseInt(supp.charge[0] + 1) * (suppnbr * parseInt(supp.charge[1]) * parseInt($scope.selectedrate.ligne.price) / 100), scope: 'TOTAL' }, { value: parseInt(supp.charge[0] + 1) * parseInt(supp.charge[1]) * parseInt($scope.selectedrate.ligne.price) / 100, scope: 'UNIT' } ] }); updateTotalPrice(); }; updateTotalPrice = function () { var tprice = 0; $scope.quote.pricing.prices = []; for (var i = $scope.quote.pricing.items.length - 1; i >= 0; i--) { var item = $scope.quote.pricing.items[i]; for (var j = item.prices.length - 1; j >= 0; j--) { if (item.prices[j].scope == 'TOTAL') tprice = tprice + item.prices[j].value; } } $scope.quote.pricing.prices.push({ value: tprice + ' ' + $scope.quote.currency, scope: 'TOTAL' }); }; } ]); // Source: src/html/scripts/tour-sales/controllers/order-detail.js angular.module('tours').controller('tours_ord_det', [ '$scope', '$location', '$window', 'settings', '$log', '$http', '$state', function ($scope, $location, $window, settings, $log, $http, $state) { var url = settings.tours.bookings + '/' + $state.params.order; var options = { headers: { 'authorized': settings.tours.authorized } }; $http.get(url, options).success(onSearchResults); function pad(d) { return d < 10 ? '0' + d.toString() : d.toString(); } function onSearchResults(data, status, fn, o) { switch (status) { case 200: $scope.status = 'found'; $scope.order = data; break; default: $scope.status = 'error'; $scope.error = data; $scope.order = {}; } var order = $scope.order; $scope.showRL = false; $scope.trbyRoom = { single: 1, 'double': 2, doubleWithChild: 3, triple: 3 }; $scope.order = order; $scope.rooms = Object.keys(order.rooms); $scope.roomingList = { single: [], 'double': [], doubleWithChild: [], triple: [] }; for (var i = order.trip.roominglist.length - 1; i >= 0; i--) { for (var j = $scope.rooms.length - 1; j >= 0; j--) { if (order.trip.roominglist[i].room.split('-')[0] == $scope.rooms[j]) { for (var k = order.trip.roominglist[i].travelers.length - 1; k >= 0; k--) { for (var m = order.trip.travellers.length - 1; m >= 0; m--) { if (order.trip.roominglist[i].travelers[k] == order.trip.travellers[m].id) { if (order.trip.hasOwnProperty('flight')) { for (var ii = order.trip.flight.length - 1; ii >= 0; ii--) { if (order.trip.flight[ii].traveller == order.trip.travellers[m].id) { if (order.trip.flight[ii].hasOwnProperty('arrival')) { if (order.trip.flight[ii].arrival.hasOwnProperty('transfert') && order.trip.flight[ii].arrival.transfert == true && order.trip.flight[ii].arrival.hasOwnProperty('date')) { order.trip.travellers[m].arrival = order.trip.flight[ii].arrival.date; if (order.trip.flight[ii].arrival.hasOwnProperty('time')) order.trip.travellers[m].arrival += ' at ' + pad(order.trip.flight[ii].arrival.time.hour) + ':' + pad(order.trip.flight[ii].arrival.time.min) + ' [' + order.trip.flight[ii].arrival.number.toUpperCase() + ']'; } } if (order.trip.flight[ii].hasOwnProperty('departure')) { if (order.trip.flight[ii].departure.hasOwnProperty('transfert') && order.trip.flight[ii].departure.transfert == true && order.trip.flight[ii].departure.hasOwnProperty('date')) { order.trip.travellers[m].departure = order.trip.flight[ii].departure.date; if (order.trip.flight[ii].departure.hasOwnProperty('time')) order.trip.travellers[m].departure += ' at ' + pad(order.trip.flight[ii].departure.time.hour) + ':' + pad(order.trip.flight[ii].departure.time.min) + ' [' + order.trip.flight[ii].departure.number.toUpperCase() + ']'; } } } } $scope.roomingList[$scope.rooms[j]].splice(0, 0, order.trip.travellers[m]); break; } } } ; } ; } } ; } ; if (order.status == 'confirmed') { var cancellation = order.items[0].product.rate.cancellation; var checkin = moment(order.trip.content.checkin, 'YYYY-MM-DDTHH:mm:SS.SSSZ'); if (cancellation.length > 0) { $scope.chargeConditions = cancellation[cancellation.length - 1].charge[0] > 0 ? 'Cancellation Charge Until ' + checkin.subtract(cancellation[cancellation.length - 1].start, 'days').format('DD/MM/YYYY') + ' : ' + (cancellation[cancellation.length - 1].charge[1] == '%' ? $scope.order.totals.total * cancellation[cancellation.length - 1].charge[0] / 1000 : cancellation[cancellation.length - 1].charge[0]) + ' ' + order.currency + String.fromCharCode(10) : 'Free Cancellation Until ' + checkin.subtract(cancellation[cancellation.length - 1].start, 'days').format('DD/MM/YYYY') + String.fromCharCode(10); for (var i = cancellation.length - 1; i > 0; i--) { checkin = moment(order.trip.content.checkin, 'YYYY-MM-DDTHH:mm:SS.SSSZ'); $scope.chargeConditions += ' From ' + checkin.subtract(cancellation[i].start - 1, 'days').format('DD/MM/YYYY'); checkin = moment(order.trip.content.checkin, 'YYYY-MM-DDTHH:mm:SS.SSSZ'); $scope.chargeConditions += ' To ' + checkin.subtract(cancellation[i - 1].start, 'days').format('DD/MM/YYYY') + ' : ' + (cancellation[i - 1].charge[1] == '%' ? $scope.order.totals.total * cancellation[i - 1].charge[0] / 100 : cancellation[i - 1].charge[0]) + ' ' + order.currency + String.fromCharCode(10); } ; } else $scope.chargeConditions = 'no fees'; order.calendarlink = 'http://www.google.com/calendar/event?action=TEMPLATE&text=' + order.items[0].product.parent.name + '&dates=' + checkin.format('YYYYMMDDTHHmmss') + 'Z/' + checkin.add(1, 'hours').format('YYYYMMDDTHHmmss') + 'Z&details=' + order.items[0].product.parent.name + '&location=Casablanca Morocco'; } } ; } ]); // Source: src/html/scripts/tour-sales/controllers/search-form.js angular.module('tours').controller('tours_SearchFormCtrl', [ '$scope', '$location', '$window', 'settings', '$log', '$http', '$state', function ($scope, $location, $window, settings, $log, $http, $state) { // $log.debug('toursSearchFormCtrl init', settings); $scope.setting = settings; /* Converts an object into a key/value par with an optional prefix. Used for converting objects to a query string */ var metaRouter = {}; metaRouter.go = function (target, opts) { opts = opts || {}; var route = settings.routes[target]; if (!route) { throw new Error('Unknown route ' + target); } if (route.type === 'redirect') { var href = route.href.replace(':path', opts.path || ''); href = href.replace(':query', qs(opts.query) || ''); $log.debug('redirect', href); $window.location.href = href; } else if (route.type === 'state') { $state.go(route.name, opts); } }; var qs = function (obj, prefix) { var str = []; for (var p in obj) { var k = prefix ? prefix + '[' + p + ']' : p, v = obj[k]; str.push(angular.isObject(v) ? qs(v, k) : k + '=' + encodeURIComponent(v)); } return str.join('&'); }; function themes(q) { } function langs(q) { var url = settings.tours.langAutocomplete.replace(':term', q); return $http.get(url).then(function (response) { return response.data; }); } /** * returns autocomple result promise */ function localities(q) { var url = settings.tours.localitiesAutocomplete.replace(':term', q); return $http.get(url).then(function (response) { $log.debug(response); return response.data; }); } function countries(q) { var url = settings.tours.countriesAutocomplete.replace(':term', q); return $http.get(url).then(function (response) { $log.debug(response); return response.data; }); } function submit() { $log.info('in_submit', $scope.query); var params = angular.extend({}, $scope.query); console.log('submit', $scope.query); if (params.from) { params.from = moment(params.from).format('YYYY-MM-DD'); //var futureMonthPlus = moment(params.from).add(1, 'M'); //params.to = moment(futureMonthPlus).endOf('month').format('YYYY-MM-DD'); // params.to = moment(params.from).add(60, 'days').format('YYYY-MM-DD'); params.to = moment(params.to).format('YYYY-MM-DD'); } /*if (params.to) { var futureMonthPlus = moment(params.from).add(1, 'M'); params.to = moment(futureMonthPlus).endOf('month').format('YYYY-MM-DD'); }*/ if (params.departure) { params.departure = params.departure.code; } if (params.vcity) { params.vcity = params.vcity.code; } if (params.b2bdep && params.b2bdep.code != undefined) { params.departure = params.b2bdep.code; params.depname = params.b2bdep.name; } if (params.theme) { params.theme = params.theme; // will search by code } /*if (params.theme.toLowerCase() == 'tout') delete params.theme; */ if (params.country) { params.country = params.country.code + ':' + params.country.name; // will search by code } params.type = settings.templates.type; params.lang = params.lang.code ? params.lang.code : 'fr'; metaRouter.go('search', params); } $window.onload = function () { // console.log("windows location", $window.location); $scope.holderVar = $location.search(); // console.log('location search', $location.search(), $scope.holderVar); var length = Object.keys($location.search()); if (length > 0) { var params = { type: $location.search().type, from: $location.search().from, to: $location.search().to, lang: $location.search().lang || 'fr' }; } else if (length == 0) { var params = { type: settings.templates.type, lang: 'fr', from: moment().format('YYYY-MM-DD') }; // params.to = moment(params.from).add(30, 'days').format('YYYY-MM-DD'); params.to = moment(params.from).add(3, 'M').format('YYYY-MM-DD'); } metaRouter.go('search', params); }; $scope.$watch('query.from', function (fresh, old) { // console.log('fresh, old', fresh, old); // console.log('fresh, old', $scope.query.from, $scope.query.to); if (fresh === old) return; var min = moment(fresh).add(1, 'days'); var to = moment($scope.query.to || 'invalid'); if (to.isValid() && to.isBefore(min)) { $scope.query.to = min.toDate(); } $scope.options.minEndDate = min.toDate(); $scope.options.minEndMonth = moment(min).startOf('month').toDate(); }); /* $http.get(settings.tours.themesAutocomplete.replace(':term', '')).then(function (response) { $scope.options.themes = response.data; });*/ function toggleCalendar($event, cal) { $event.preventDefault(); $event.stopPropagation(); angular.forEach($scope.calendarsOpen, function (value, key) { // close others $scope.calendarsOpen[key] = false; }); $scope.calendarsOpen[cal] = !$scope.calendarsOpen[cal]; } angular.extend($scope, { themes: themes, langs: langs, localities: localities, submit: submit, toggleCalendar: toggleCalendar, calendarsOpen: {}, countries: countries, options: { minStartDate: moment().startOf('day').toDate(), minEndDate: moment().add(1, 'days').startOf('day').toDate(), minEndMonth: moment().add(1, 'days').startOf('month').toDate(), datepickerTo: { initDate: '$parent.$parent.options.minEndDate' }, langs: settings.default.langs, b2bdep: settings.default.b2bdep, themes: settings.default.themes, countries: settings.default.countries || [] } }); $scope.destOps = []; var countries = $scope.options.countries; $scope.destOps.push({ label: 'Destination', value: { 'code': 'DestinationCode', 'name': 'DestinationName' } }); for (var i = 0; i <= countries.length; i++) { if (countries[i]) { var o = { label: countries[i].name, value: countries[i] }; $scope.destOps.push(o); } } $scope.destSelection = $scope.destOps[0].value; $scope.themeOps = []; var themes = $scope.options.themes; $scope.themeOps.push({ label: 'Th\xe8me', value: 'Th\xe8me' }); for (var i = 0; i <= themes.length; i++) { if (themes[i]) { var o = { label: themes[i].name, value: themes[i].name }; $scope.themeOps.push(o); } } $scope.themeSelection = $scope.themeOps[0].value; if ($scope.query.country) { $scope.destSelection = $scope.query.country; } if ($scope.query.theme) { $scope.themeSelection = $scope.query.theme; } $scope.$watch('destSelection', function (newVal) { // console.log('destSelection newVal', newVal) if (newVal.code !== 'DestinationCode') $scope.query.country = newVal; }); $scope.$watch('themeSelection', function (newVal) { // console.log('themeSelection newVal', newVal) if (newVal !== 'Th\xe8me') $scope.query.theme = newVal; }); } ]); ; angular.module('ui.bootstrap.datepicker').controller('DatepickerController', [ '$scope', '$attrs', '$parse', '$interpolate', '$timeout', '$log', 'dateFilter', 'datepickerConfig', function ($scope, $attrs, $parse, $interpolate, $timeout, $log, dateFilter, datepickerConfig) { datepickerConfig.showWeeks = false; var self = this, ngModelCtrl = { $setViewValue: angular.noop }; // nullModelCtrl; // Modes chain this.modes = [ 'day', 'month', 'year' ]; // Configuration attributes angular.forEach([ 'formatDay', 'formatMonth', 'formatYear', 'formatDayHeader', 'formatDayTitle', 'formatMonthTitle', 'minMode', 'maxMode', 'showWeeks', 'startingDay', 'yearRange' ], function (key, index) { self[key] = angular.isDefined($attrs[key]) ? index < 8 ? $interpolate($attrs[key])($scope.$parent) : $scope.$parent.$eval($attrs[key]) : datepickerConfig[key]; }); // Watchable date attributes angular.forEach([ 'minDate', 'maxDate' ], function (key) { if ($attrs[key]) { $scope.$parent.$watch($parse($attrs[key]), function (value) { self[key] = value ? new Date(value) : null; self.refreshView(); }); } else { self[key] = datepickerConfig[key] ? new Date(datepickerConfig[key]) : null; } }); if (angular.isDefined($attrs.initDate)) { $scope.$parent.$watch($parse($attrs.initDate), function (value) { if (!ngModelCtrl.$modelValue) { self.activeDate = value ? new Date(value) : new Date(); self.refreshView(); } }); } $scope.datepickerMode = $scope.datepickerMode || datepickerConfig.datepickerMode; $scope.uniqueId = 'datepicker-' + $scope.$id + '-' + Math.floor(Math.random() * 10000); this.activeDate = angular.isDefined($attrs.initDate) ? $scope.$parent.$eval($attrs.initDate) : new Date(); $scope.isActive = function (dateObject) { if (self.compare(dateObject.date, self.activeDate) === 0) { $scope.activeDateId = dateObject.uid; return true; } return false; }; this.init = function (ngModelCtrl_) { ngModelCtrl = ngModelCtrl_; ngModelCtrl.$render = function () { self.render(); }; }; this.render = function () { if (ngModelCtrl.$modelValue) { var date = new Date(ngModelCtrl.$modelValue), isValid = !isNaN(date); if (isValid) { this.activeDate = date; } else { $log.error('Datepicker directive: "ng-model" value must be a Date object, a number of milliseconds since 01.01.1970 or a string representing an RFC2822 or ISO 8601 date.'); } ngModelCtrl.$setValidity('date', isValid); } this.refreshView(); }; this.refreshView = function () { if (this.element) { this._refreshView(); var date = ngModelCtrl.$modelValue ? new Date(ngModelCtrl.$modelValue) : null; ngModelCtrl.$setValidity('date-disabled', !date || this.element && !this.isDisabled(date)); } }; this.createDateObject = function (date, format) { var model = ngModelCtrl.$modelValue ? new Date(ngModelCtrl.$modelValue) : null; return { date: date, label: dateFilter(date, format), selected: model && this.compare(date, model) === 0, disabled: this.isDisabled(date), current: this.compare(date, new Date()) === 0 }; }; this.isDisabled = function (date) { return this.minDate && this.compare(date, this.minDate) < 0 || this.maxDate && this.compare(date, this.maxDate) > 0 || $attrs.dateDisabled && $scope.dateDisabled({ date: date, mode: $scope.datepickerMode }); }; // Split array into smaller arrays this.split = function (arr, size) { var arrays = []; while (arr.length > 0) { arrays.push(arr.splice(0, size)); } return arrays; }; $scope.select = function (date) { if ($scope.datepickerMode === self.minMode) { var dt = ngModelCtrl.$modelValue ? new Date(ngModelCtrl.$modelValue) : new Date(0, 0, 0, 0, 0, 0, 0); dt.setFullYear(date.getFullYear(), date.getMonth(), date.getDate()); ngModelCtrl.$setViewValue(dt); ngModelCtrl.$render(); } else { self.activeDate = date; $scope.datepickerMode = self.modes[self.modes.indexOf($scope.datepickerMode) - 1]; } }; $scope.move = function (direction) { var year = self.activeDate.getFullYear() + direction * (self.step.years || 0), month = self.activeDate.getMonth() + direction * (self.step.months || 0); self.activeDate.setFullYear(year, month, 1); self.refreshView(); }; $scope.toggleMode = function (direction) { direction = direction || 1; if ($scope.datepickerMode === self.maxMode && direction === 1 || $scope.datepickerMode === self.minMode && direction === -1) { return; } $scope.datepickerMode = self.modes[self.modes.indexOf($scope.datepickerMode) + direction]; }; // Key event mapper $scope.keys = { 13: 'enter', 32: 'space', 33: 'pageup', 34: 'pagedown', 35: 'end', 36: 'home', 37: 'left', 38: 'up', 39: 'right', 40: 'down' }; var focusElement = function () { $timeout(function () { self.element[0].focus(); }, 0, false); }; // Listen for focus requests from popup directive $scope.$on('datepicker.focus', focusElement); $scope.keydown = function (evt) { var key = $scope.keys[evt.which]; if (!key || evt.shiftKey || evt.altKey) { return; } evt.preventDefault(); evt.stopPropagation(); if (key === 'enter' || key === 'space') { if (self.isDisabled(self.activeDate)) { return; // do nothing } $scope.select(self.activeDate); focusElement(); } else if (evt.ctrlKey && (key === 'up' || key === 'down')) { $scope.toggleMode(key === 'up' ? 1 : -1); focusElement(); } else { self.handleKeyDown(key, evt); self.refreshView(); } }; } ]); /* //http://outgoing.fractalite.com/tours?from=2016-07-01&lang=fr&limit=100&qt=search&skip=0&to=2016-09-30&type=vo /*function initSearch() { var params = { type: settings.templates.type, from: $scope.query.from ? moment($scope.query.from).format('YYYY-MM-DD') : moment().format('YYYY-MM-DD') }; params.to = moment(params.from).add(30, 'days').format('YYYY-MM-DD'); // params.to = moment(futureMonthPlus).endOf('month').format('YYYY-MM-DD'); console.log('initSearch just called', params); metaRouter.go('search', params); } */ // Source: src/html/scripts/tour-sales/controllers/search.js angular.module('tours').controller('tours_SearchCtrl', [ '$scope', '$http', '$stateParams', '$state', '$location', 'settings', '$window', '$log', function ($scope, $http, $stateParams, $state, $location, settings, $window, $log) { // $log.info('tours_SearchCtrl:', settings); // $log.info('stateParams:', $stateParams) //$log.debug("search/ stateparams", $location.search(), $stateParams); var to = $stateParams.to; var from = $stateParams.from; var departure = $stateParams.departure; var depname = $stateParams.depname; var theme = $stateParams.theme; var lang = $stateParams.lang ? $stateParams.lang : 'fr'; var vcity = $stateParams.vcity; var country = $stateParams.country; var skip = 0; var limit = 100; var type = $stateParams.type || 'VO'; // will be from web var langs = settings.default.langs; var b2bdep = settings.default.b2bdep; var olang = langs[0]; var odep; for (var i = langs.length - 1; i >= 0; i--) { if (langs[i].code === lang) olang = langs[i]; } ; if (b2bdep) { for (var i = b2bdep.length - 1; i >= 0; i--) { if (b2bdep[i].name === depname) odep = b2bdep[i]; } ; } if (odep === undefined) odep = departure; var lg = olang.code; $scope.query = { from: from, to: to, departure: departure, theme: theme, vcity: vcity, lang: lg, skip: skip, limit: limit, type: type, depname: depname, b2bdep: odep, country: country }; //$log.debug('emit tourSearchQuery', JSON.stringify($scope.query)); $scope.$emit('tourSearchQuery', $scope.query); $scope.context = 'search'; //console.log("country ", country); // settings.tours.endpoints.search var params = { qt: 'search' }; var url = settings.tours.search; if (from && to) { //$log.info('from_to 1', from, to) var checkin = moment(from || 'invalid', 'YYYY-MM-DD'), checkout = moment(to || 'invalid', 'YYYY-MM-DD'), current = moment().format('YYYY-MM-DD'); if (checkin.isValid() && checkout.isValid() && checkin.isBefore(current)) { from = current; to = moment().add(120, 'days').format('YYYY-MM-DD'); //$log.info('from&to', from, to); $stateParams.from = from; $stateParams.to = to; $scope.query.from = from; $location.search('from', from); $location.search('to', to); } var countryCode; if (country) { countryCode = country.split(':')[0]; $scope.query.country = { code: countryCode, name: country.split(':')[1] }; } params = { qt: 'search', from: from, vcity: vcity, to: to, city: departure, lang: lang, skip: skip, limit: limit, type: type, depname: depname, country: countryCode }; if (theme && theme.toLowerCase() !== 'tout') { params.theme = theme; } $scope.status = 'searching'; } else { var out = fromStateParam($stateParams); $stateParams.from = moment(out.checkin, 'YYYY-MM-DD').format('YYYY-MM-DD'); $stateParams.to = moment(out.checkout, 'YYYY-MM-DD').format('YYYY-MM-DD'); $state.transitionTo($state.current, $stateParams, { reload: true, inherit: false, notify: true }); $scope.status = 'filling'; } var options = { headers: { 'authorized': settings.tours.authorized }, params: params }; $http.get(url, options).success(onSearchResults); function fromStateParam(input) { var output = Object.create(null); output.checkin = moment().add(1, 'days').format('YYYY-MM-DD'); output.checkout = moment().add(60, 'days').format('YYYY-MM-DD'); return output; } function decode(tour) { var products = []; var product; if (tour.hasOwnProperty('pricing')) { if (tour.pricing[0] !== undefined && tour.pricing[0].rates !== undefined) { var rates = tour.pricing[0].rates; for (var i = 0; i < rates.length; i++) { var ispromo = false; var length = rates[i].lines.length || 0; var promosProductLines = []; for (var j = 0; j < length; j++) { if (rates[i].lines[j].price && rates[i].lines[j].priceYield) { if (+rates[i].lines[j].price > +rates[i].lines[j].priceYield) { ispromo = true; product = { code: rates[i].category.code, name: rates[i].category.name, startingAt: rates[i].lines[j].price, ystartingAt: rates[i].lines[j].priceYield, ispromo: ispromo, currency: tour.pricing[0].currency }; promosProductLines.push(product); } } } if (promosProductLines.length > 0) { product = promosProductLines[0]; } else { product = { code: rates[i].category.code, name: rates[i].category.name, startingAt: rates[i].lines[0].price, ystartingAt: rates[i].lines[0].priceYield, ispromo: ispromo, currency: tour.pricing[0].currency }; } ; products.push(product); } products.sort(comparePrice); } else { console.log('no pricing for tour', tour._id || tour.code); } tour.products = products; tour.href = settings.routes.tour.href.replace(':tour', tour.code); tour.href = tour.href + '?from=' + from + '&to=' + to + '&lang=' + lang; } return tour; } function getMinPrice() { // There's no real number bigger than plus Infinity var lowest = Number.POSITIVE_INFINITY; // var highest = Number.NEGATIVE_INFINITY; var tmp; var rates = $scope.pricing.rates; for (var i = rates.length - 1; i >= 0; i--) { var lines = rates[i].lines; for (var j = lines.length - 1; j >= 0; j--) { var tmp = lines[j].priceYield; if (tmp < lowest) lowest = tmp; //if (tmp > highest) highest = tmp; } } return lowest; } function comparePrice(producta, productb) { //return producta.startingAt - productb.startingAt; if (producta.startingAt < productb.startingAt) return -1; if (producta.startingAt > productb.startingAt) return 1; return 0; } function onSearchResults(data, status, fn, o) { //console.log("onSearchResults", status); switch (status) { case 404: case 204: $scope.status = 'no content'; break; case 206: case 200: $scope.status = 'found'; $scope.tours = data.map(decode); break; default: $scope.status = 'error'; $scope.error = data; } } // simple date picker $scope.singleDatePicker = { picker: null, options: { singleDatePicker: true, pickerClasses: 'custom-display', buttonClasses: 'btn', applyButtonClasses: 'btn-primary', cancelButtonClasses: 'btn-danger', minDate: moment(), locale: { applyLabel: 'valider', cancelLabel: 'annuler', customRangeLabel: 'Custom range', separator: ' - ', format: 'DD/MM/YYYY', weekLabel: 'S', daysOfWeek: [ 'Di', 'Lu', 'Ma', 'Me', 'Je', 'Ve', 'Sa' ], monthNames: [ 'Janvier', 'F\xe9vrier', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Ao\xfbt', 'Septembre', 'Octobre', 'Novembre', 'Decembre' ], 'firstDay': 1 }, eventHandlers: { 'apply.daterangepicker': function (event, picker) { $scope.query.from = $scope.singleDatePicker.date; } } } }; if ($scope.query !== undefined && $stateParams.from) { $scope.singleDatePicker.date = $stateParams.from; } else { $scope.singleDatePicker.date = moment(); } } ]); ; // Source: src/html/scripts/tour-sales/controllers/tour-orders.js angular.module('tours').controller('tours_ords', [ '$scope', '$location', '$window', 'settings', '$log', '$http', '$state', function ($scope, $location, $window, settings, $log, $http, $state) { clear(); // serach(); function onSearchResults(data, status, fn, o) { switch (status) { case 204: $scope.status = 'no content'; $scope.orders = []; break; case 206: case 200: $scope.status = 'found'; $scope.orders = data.map(decode); break; default: $scope.status = 'error'; $scope.error = data; $scope.orders = []; } } function clear() { $scope.query = {}; $scope.orders = []; intskiplimit(); } function intskiplimit() { $scope.query.skip = 0; $scope.query.limit = 20; } function serach() { var created; var departureDate; var client; var traveller; var number; var status; var mod = 'list'; var url = settings.tours.bookings; if ($scope.query.created != undefined) created = moment($scope.query.created).format('DD/MM/YYYY'); // I hate this format, will be changed in ws if ($scope.query.deprating != undefined) departureDate = moment($scope.query.deprating).format('DD/MM/YYYY'); //if($scope.query.created != undefined) client = ''; if ($scope.query.traveller != undefined) traveller = $scope.query.traveller; if ($scope.query.number != undefined) number = $scope.query.number; if ($scope.query.status != undefined) status = $scope.query.status; var params = { qt: 'filter', created: created, departureDate: departureDate, client: client, traveller: traveller, number: number, mod: mod, status: status, skip: $scope.query.skip, limit: $scope.query.limit }; var options = { headers: { authorized: settings.tours.authorized }, params: params }; console.log('options', options); $http.get(url, options).success(onSearchResults); } function toggleCalendar($event, cal) { $event.preventDefault(); $event.stopPropagation(); angular.forEach($scope.calendarsOpen, function (value, key) { $scope.calendarsOpen[key] = false; }); $scope.calendarsOpen[cal] = !$scope.calendarsOpen[cal]; } function decode(order) { order.href = '#/tours/order/' + order.number; order.moreTr = false; return order; } $scope.showMoreTravellers = function (index) { $scope.orders[index].moreTr = !$scope.orders[index].moreTr; }; function previous() { $scope.query.skip -= $scope.query.limit; serach(); } function next() { $scope.query.skip += $scope.query.limit; serach(); } angular.extend($scope, { clear: clear, next: next, intskiplimit: intskiplimit, previous: previous, serach: serach, calendarsOpen: {}, toggleCalendar: toggleCalendar }); } ]); // Source: src/html/scripts/tour-sales/controllers/tour-quote.js angular.module('tours').controller('tours_TourQuoteCtrl', [ '$scope', '$http', '$stateParams', '$rootScope', '$timeout', '$location', 'settings', 'tourQuoteService', '$window', '$log', '$filter', function ($scope, $http, $stateParams, $rootScope, $timeout, $location, settings, tourQuoteService, $window, $log, $filter) { $scope.roomnbr = 1; $scope.rooms = [1]; var isoDate = 'YYYY-MM-DD'; var options = { adults: [ 1, 2, 3, 4, 5, 6 ], children: [ 0, 1, 2, 3, 4, 5, 6 ], ages: [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 ], quantities: [ 0, 0 ], boardQte: [ 0, 0 ] }; var omraOptions = { single: { adults: [1], chds: [0] }, double: { adults: [ 1, 2 ], chds: [ 0, 1, 2 ] }, triple: { adults: [ 1, 2, 3 ], chds: [ 0, 1, 2 ] }, quadruple: { adults: [ 1, 2, 3, 4 ], chds: [0] } }; var request = { children: [] }; function getMinPrice() { // There's no real number bigger than plus Infinity var lowest = Number.POSITIVE_INFINITY; // var highest = Number.NEGATIVE_INFINITY; var tmp; var rates = $scope.pricing.rates; for (var i = rates.length - 1; i >= 0; i--) { var lines = rates[i].lines; for (var j = lines.length - 1; j >= 0; j--) { var tmp = lines[j].priceYield; if (tmp < lowest) lowest = tmp; //if (tmp > highest) highest = tmp; } } $scope.minPrice = lowest; //$scope.maxPrice = highest; } function roomTypeChanged() { var t = $scope.query.type; $scope.nbrOfAdults = omraOptions[t]['adults']; $scope.query.maxchildren = omraOptions[t]['chds']; angular.extend($scope.query, { single: 0, double: 0, triple: 0, quadruple: 0, doubleWithChild: 0, adults: 1, children: 0 }); $scope.query[t] = 1; $scope.showRates = false; $scope.selectedDate = null; //adultCountChanged(); } function adultCountChanged() { if ($scope.tour.type === 'Tour' || $scope.tour.type === 'VO') { $scope.query.adults = $scope.query.single + ($scope.query.double + $scope.query.doubleWithChild) * 2 + $scope.query.triple * 3 + $scope.query.quadruple * 4; } var N = $scope.query.adults + $scope.query.children + 1; options.boardQte = Array.apply(null, { length: N }).map(Number.call, Number); options.quantities = [ 0, $scope.query.adults ]; $scope.products = null; $scope.product = null; $scope.query.maxchildren = [0]; var nbr = $scope.query.double * 3 + $scope.query.triple; //console.log("nbr ", nbr); for (var i = 1; i <= nbr; i++) { $scope.query.maxchildren.push(i); } ; //console.log("$scope.query.maxchildren ", $scope.query.maxchildren); } /** * Listen for child count change to push/pop elements from ages */ function childCountChanged() { var ages = $scope.query.ages; //console.log('childCountChanged',count) var i = 0; while (ages.length < $scope.query.doubleWithChild) { ages.push({ 'i': i++, 'v': $scope.query.age }); } // remove elements if length > count while (ages.length > $scope.query.doubleWithChild) { ages.pop(); } var N = $scope.query.adults + $scope.query.children + 1; options.boardQte = Array.apply(null, { length: N }).map(Number.call, Number); ////console.log("in childCountChanged",ages.length,$scope.query.ages) } function setChildren() { var ages = $scope.query.ages; //console.log('setChildren ages children', $scope.query.ages, $scope.query.children); var i = 0; while (i < $scope.query.children) { //$scope.query.ages[i] = 0; //i++; ages.push({ 'i': i++, 'v': $scope.query.age }); } // remove elements if length > count while (ages.length > $scope.query.children) { ages.pop(); } //console.log("in setChildren", ages.length, $scope.query.ages) } function addchildage() { var ages = $scope.query.ages; ages.push(query.age); } // Should go to a servce in v1, to nodejs in v2 to tour-server in v3... function _getDepartures(rates) { // all we need is rates[n].lines aggregated in one arre (reduce...etc) var result = []; rates.map(function (rate) { return rate.lines; }).reduce(function (reduced, lines) { var i = lines.length, tmp; while (i--) { tmp = lines[i].departure.split('T')[0]; if (reduced.indexOf(tmp) === -1) { reduced.push(tmp); } } return reduced; }, result); result.sort(); return result; } /** * Process http success */ function _processRatesResponse(data) { if (data != undefined && data[0] != undefined && data[0].pricing != undefined && data[0].pricing[0] != undefined) { $scope.pricing = data[0].pricing[0]; $scope.currency = $scope.pricing.currency; $scope.departures = _getDepartures($scope.pricing.rates); } $log.debug('pricing', $scope.pricing); $log.debug('dates', $scope.departures); updateCalendar($scope.departures); getMinPrice(); } function _processRatesError() { $log.error('Error querying rates', arguments); $scope.error = arguments; } function queryRates(query) { $log.debug('queryRates: query', query); var params = { qt: 'search', tour: query.tour, from: moment(query.from).format(isoDate), to: moment(query.to).format(isoDate), lang: query.lang }; var options = { headers: { 'authorized': settings.tours.authorized }, params: params }; //var url = settings.tours.search; var url = settings.tours.endpoint; //console.log('--------------url -----------', url); // this should be in settings. And we shouldn't call ratesGroup // there should be a getDepartures service then a quoteDeparture service... $http.get(url, options).success(_processRatesResponse).error(_processRatesError).finally(function () { }); } // Builds a data object for a day to be used in calendar. function _buildDay(d, deps, month, week) { var date = d.format(isoDate), day = { label: d.month() === month ? d.date() : '', date: moment.utc(d).startOf('day').toDate(), currentMonth: d.month() === month, departure: deps.indexOf(date) > -1 }; //console.log('build day', day); week.push(day); } function _getDateRate(date, lines) { var i = lines.length; var mDate = moment.utc(date); while (i--) { if (moment(lines[i].departure).isSame(mDate, 'day')) { var ln = lines[i]; ln.code = $scope.pricing.code; return ln; } } return null; } function updateCalendar(departures) { var firstOfMonth = moment.utc(departures[0], isoDate).startOf('month'); //console.log("firstOfMonth ",firstOfMonth); var month = firstOfMonth.month(); var d = moment.utc(firstOfMonth).startOf('isoWeek'); var weeks = [], week = []; //console.log('firstDayOfMonth',firstOfMonth,'month',month,'d',d) ; //console.log('(d.month(',d.month(),'month',month) ; while (d.isBefore(firstOfMonth, 'day') || d.month() === month) { _buildDay(d, departures, month, week); d.add('days', 1); // week end if (week.length === 7) { weeks.push(week); week = []; } } while (week.length > 0 && week.length < 7) { _buildDay(d, departures, month, week); d.add('days', 1); } weeks.push(week); $scope.weeks = weeks; $scope.firstOfMonth = firstOfMonth.toDate(); } function goToMonth(date, diff) { var m = 'month'; var operation = diff > 0 ? 'add' : 'subtract'; var target = moment(date)[operation](m, 1).startOf(m); var q = $scope.query; q.from = target.toDate(); q.to = moment(target).endOf(m).toDate(); queryRates(q); } function nextMonth(date) { goToMonth(date, 1); } function previousMonth(date) { goToMonth(date, -1); } function showProducts(date) { $scope.depDate = moment(date).format('DD-MM-YYYY'); $scope.arivDate = moment(date).add($scope.tour.days.length, 'days').format('DD-MM-YYYY'); var categories = $scope.pricing.rates, category, rate, selection = [], i = categories.length; while (i--) { category = categories[i]; rate = _getDateRate(date, category.lines); //console.log("selected rate ", rate); if (rate !== null) { if (rate.promo) { rate.priceYield = rate.promo.value; //rawProduct.promo = rate.promo.name; } // if ($scope.query.triple === 1){ // } selection.unshift({ code: category.category.code, name: category.category.name, rate: rate }); } else { console.warn('no rate for ' + date + ' in cat' + category.category); } } //console.log("showProducts products ", selection); $scope.products = selection; $scope.product = null; $scope.selectedDate = date; $scope.showRates = true; } function showRules(p) { p.rate.showRules = !p.rate.showRules; } function sendFormStatus() { $scope.productButtonSelected = false; } function selectProduct(p) { $scope.productButtonSelected = true; $scope.clicked = true; $scope.devisOn = true; var query = $scope.query; query.currency = $scope.currency; $scope.product = p; //console.log("selectProduct ", p); //console.log(" devis tour quote : ", $scope.devisOn); $scope.quote = tourQuoteService.quote($scope.tour, p, query); /* for (var i = 0 ; i<query.adults ; i++) { $scope.quote.trip.travellers.push( {"classification": "ADULT","id": i,"type": "Traveller"}); }; for (var i = 0 ; i<query.ages.length ; i++) { $scope.quote.trip.travellers.push( {"classification": "CHILD","age": query.ages[i].v ,"id": query.adults+i,"type": "Traveller"} ); };*/ $scope.paxes = query.adults + query.ages.length; } function checkDisabledConditions() { //console.log('checkDisabledConditions $scope.products', $scope.products, $scope.productButtonSelected) //if (($scope.products == null || $scope.products.length <= 0) && $scope.productButtonSelected == false) if (angular.isArray($scope.products) && $scope.products.length > 0 && $scope.productButtonSelected === true) return false; else return true; } function optionSelected(opt) { return opt.qty > 0; } function quantityChanged(item) { if (item['@type'] === 'tourExtra' && item.product.type === 'board') { for (var i = $scope.quote.items.length - 1; i >= 0; i--) { var it = $scope.quote.items[i]; //console.log("it is ", item); if (it != item && it['@type'] === 'tourExtra' && it.product.type === 'board') { $scope.quote.totals.total = $scope.quote.totals.total - it.totals.total; it.qty = 0; it.totals.total = 0; } } } ; var oldTotal = item.totals.total || 0; item.totals.total = item.product.price * item.qty; var diff = item.totals.total - oldTotal; $scope.quote.totals.total += diff; } function errorCallback(error) { $scope.error = error; } function cartSaveFailure(error) { $scope.error = error; $log.error('cart saving failed', error); } function cartSaveSuccess() { $scope.status = 'checkoutRedirect'; $log.debug('cart saved', arguments); $window.location.href = settings.links.checkout; } function book(quote) { /* $http.delete('/carts') .then(function() { $http.put('/carts',$scope.quote).then(cartSaveSuccess, cartSaveFailure); }); */ $scope.quote.rooms = { single: $scope.query.single, double: $scope.query.double, doubleWithChild: $scope.query.doubleWithChild, triple: $scope.query.triple, quadruple: $scope.query.quadruple }; $http.post('/carts', $scope.quote).then(function (res) { if (angular.isArray(res.data)) { res.data = res.data[0]; } $scope.$emit('bookCartSaved', res.data); $window.location.href = '/ngapps/checkout#/' + res.data._id; }, function failed() { $log.error('cart saving failed', arguments); }); } function requestSaved() { $scope.requestStatus = 'success'; if (window.ga) { window.ga('send', 'event', 'voyage', 'demande', $rootScope.meta && $rootScope.meta.title); } } function requestSaveFailed() { $scope.requestStatus = 'failed'; } function sendReservation() { $scope.requestStatus = 'saving'; var productName = ''; for (var i = $scope.query.ages.length - 1; i >= 0; i--) { request.children.push({ age: $scope.query.ages[i] }); } request.adults = $scope.query.adults; if (angular.isArray($scope.products) && $scope.products.length > 0) { if ($scope.products[0].parent) { productName = $scope.products[0].parent.name + ' ' + $scope.products[0].name; } } request.product = { _id: $scope.query.tour, name: productName }; request.departure = $scope.query.from; $log.debug('request', $scope.request); //return; $http.post('/travel-product-requests', $scope.request).success(requestSaved).error(requestSaveFailed); } function clearRates() { $scope.showRates = false; $scope.selectedDate = null; } function initChildAges() { var children = $scope.query.children; var length = children.length; for (var i = 0; i < length; i++) { $scope.query.ages[i] = 1; } } function buildQuery() { var from = moment($stateParams.from || 'invalid', isoDate), to = moment($stateParams.to || 'invalid', isoDate), lang = $stateParams.lang, ages, adults = /\d/.test($stateParams.adults) ? parseInt($stateParams.adults, 10) : 1; /*if (!from.isValid() || from.isBefore()) { from = moment().startOf('day'); }*/ if (!to.isValid() || to.isBefore(from, 'day') || to.isSame(from, 'day')) { to = moment(from); to.add('months', 1); } // regex should not allow 0 or above 12 if (/\d{1,2}(,\d{1,2})*/.test($stateParams.children)) { ages = $stateParams.children.split(',').map(function (element) { var a = parseInt(element, 10); return 0 < a && a < 12 ? a : 0; }); } else { ages = []; } return { tour: $stateParams.tour, from: from.toDate(), to: to.toDate(), lang: lang, adults: 0, single: 0, double: 0, doubleWithChild: 0, triple: 0, quadruple: 0, ages: [], children: [], age: 0, maxchildren: [0], children: 0, type: 'single' }; } //type: 'single' angular.extend($scope, { childCountChanged: childCountChanged, setChildren: setChildren, addchildage: addchildage, nextMonth: nextMonth, previousMonth: previousMonth, showProducts: showProducts, selectProduct: selectProduct, showRules: showRules, optionSelected: optionSelected, quantityChanged: quantityChanged, book: book, adultCountChanged: adultCountChanged, getQuote: '', sendFormStatus: sendFormStatus, productButtonSelected: false, checkDisabledConditions: checkDisabledConditions, sendReservation: sendReservation, request: request, roomTypeChanged: roomTypeChanged, nbrOfAdults: [1], clearRates: clearRates, initChildAges: initChildAges, depDate: null, generatePdfTarifs: generatePdfTarifs, loadingTarif: false, devisOn: false, depDate: null, options: options, query: buildQuery() }); $log.debug('query', $scope.query); queryRates($scope.query); //******** generate tarifs pdf ******// function generatePdfTarifs() { var date = $filter('date')($scope.currentDate, 'yyyy-MM-dd'); $scope.loadingTarif = true; kendo.pdf.defineFont({ 'DejaVu Sans': 'https://kendo.cdn.telerik.com/2016.1.112/styles/fonts/DejaVu/DejaVuSans.ttf', 'DejaVu Sans|Bold': 'https://kendo.cdn.telerik.com/2016.1.112/styles/fonts/DejaVu/DejaVuSans-Bold.ttf', 'DejaVu Sans|Bold|Italic': 'https://kendo.cdn.telerik.com/2016.1.112/styles/fonts/DejaVu/DejaVuSans-Oblique.ttf', 'DejaVu Sans|Italic': 'https://kendo.cdn.telerik.com/2016.1.112/styles/fonts/DejaVu/DejaVuSans-Oblique.ttf' }); //console.log(' in generate devis as pdf'); $timeout(function () { kendo.drawing.drawDOM('#tarifs', { paperSize: 'A4', margin: '1cm', scale: 0.7 }).then(function (group) { kendo.drawing.pdf.saveAs(group, 'devis ' + $scope.tour.name + '-' + date + '.pdf'); $scope.loadingTarif = false; //console.log(' end generate devis as pdf'); $scope.$apply(); }); }, 10); } } ]); /*$scope.childrenAges = [ { id: 0, age: 0 }, { id: 1, age: 1 }, { id: 2, age: 2 }, { id: 3, age: 3 }, { id: 4, age: 4 }, { id: 5, age: 5 }, { id: 6, age: 6 }, { id: 7, age: 7 }, { id: 8, age: 8 }, { id: 9, age: 9 }, { id: 10, age: 10 }, { id: 11, age: 11 } ];*/ // Source: src/html/scripts/tour-sales/controllers/tour.js angular.module('tours').controller('tours_TourCtrl', [ '$scope', '$http', '$q', '$stateParams', '$location', '$timeout', 'settings', '$log', 'tourQuoteService', '$rootScope', '$anchorScroll', '$window', '$filter', function ($scope, $http, $q, $stateParams, $location, $timeout, settings, $log, tourQuoteService, $rootScope, $anchorScroll, $window, $filter) { // $log.log("tours_TourCtrl ", settings); var tour = {}; var kendoGroupe = null; // Get description var url = settings.tours.descriptions; function showMoreDaysProgram() { $scope.daysProgram = !$scope.daysProgram; //console.log("------------ program days -------------", $scope.daysProgram); } $scope.daysProgram = false; var _options = { headers: { authorized: settings.tours.authorized } }; var promises = { description: $http.get(url + '?qt=byTour&tour=' + $stateParams.tour + '&lang=' + $stateParams.lang, _options), tourData: $http.get(settings.tours.endpoint + '/' + $stateParams.tour, _options) }; function setup(resolvedData) { ////console.log("in setup data", resolvedData); var description = resolvedData.description.data[0]; angular.extend(tour, { description: description }); var data = resolvedData.tourData.data; $scope.pdfImage = data.photos[0].url.replace('http', 'https'); data.photos.forEach(function (p, i) { //settings.tour.imgrsz p.url = i === 0 ? 'https://imgrsz.atlasvoyages.com/img/1920x1000/' + p.url : 'https://imgrsz.atlasvoyages.com/img/750x450/' + p.url; //p.url = p.url.replace("http", "https"); //p.url = p.url.replace("https://imgrsz.atlasvoyages.com/img/750x450/http", "https"); }); var facebookMeta = { title: data.name, description: description.lead, image: data.photos[0].url, url: 'https://www.atlasvoyages.com/ngapps/vo-sales#/tour/' + $stateParams.tour + '?from=' + $stateParams.from + '&to=' + $stateParams.to + '&lang=fr' }; data.facebookMeta = facebookMeta; angular.extend(tour, data); $scope.tour = tour; // $log.debug("emit tourProducthQuery", JSON.stringify($scope.tour.name)); // $scope.$emit("tourProducthQuery", $scope.tour.name); $scope.context = 'product'; } $q.all(promises).then(setup); $scope.myInterval = 4000; $scope.roomnbr = 1; $scope.rooms = [1]; var isoDate = 'YYYY-MM-DD'; var options = { adults: [ 1, 2, 3, 4, 5, 6 ], children: [ 0, 1, 2, 3, 4, 5, 6 ], ages: [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 ], quantities: [ 0, 0 ], boardQte: [ 0, 0 ] }; var omraOptions = { single: { adults: [1], chds: [0] }, double: { adults: [ 1, 2 ], chds: [ 0, 1, 2 ] }, triple: { adults: [ 1, 2, 3 ], chds: [ 0, 1, 2 ] }, quadruple: { adults: [ 1, 2, 3, 4 ], chds: [0] } }; var request = { children: [] }; function getMinPrice() { // There's no real number bigger than plus Infinity var lowest = Number.POSITIVE_INFINITY; // var highest = Number.NEGATIVE_INFINITY; var tmp, date, departureDate; var rates = $scope.pricing.rates; for (var i = rates.length - 1; i >= 0; i--) { var lines = rates[i].lines; for (var j = 0; j < lines.length; j++) { tmp = lines[j].priceYield; if (lines[j].promo && lines[j].promo.value < tmp) { tmp = lines[j].promo.value; //console.log('--------------------- lines in rates to get the min price ', lines); } else if (lines[j].quadruple && lines[j].quadruple < tmp) { tmp = lines[j].quadruple; } else if (lines[j].tripleReduction && lines[j].tripleReduction[0] < tmp) { tmp = lines[j].tripleReduction[0]; } date = lines[j].departure; if (tmp < lowest) { lowest = tmp; departureDate = date; } //if (tmp > highest) highest = tmp; } } $scope.minPrice = lowest; $scope.departureDate = moment(departureDate).format('DD-MM-YYYY'); //$scope.maxPrice = highest; } function roomTypeChanged() { var t = $scope.query.type; $scope.nbrOfAdults = omraOptions[t]['adults']; $scope.query.maxchildren = omraOptions[t]['chds']; angular.extend($scope.query, { single: 0, double: 0, triple: 0, quadruple: 0, doubleWithChild: 0, adults: 1, children: 0 }); $scope.query[t] = 1; $scope.showRates = false; //$scope.selectedDate = null; //adultCountChanged(); //$scope.products = null; //$scope.product = null; } function clearRates() { $scope.showRates = false; //$scope.selectedDate = null; //$scope.products = null; //$scope.product = null; } function scrollTo(id) { ////console.log('scrolling id', id); $location.hash(id); $anchorScroll(); } function buildQuery() { // $log.debug('$stateParams --------------------------', $stateParams); var from = moment($stateParams.from || 'invalid', isoDate), to = moment($stateParams.to || 'invalid', isoDate), lang = $stateParams.lang ? $stateParams.lang : 'fr', ages, adults = /\d/.test($stateParams.adults) ? parseInt($stateParams.adults, 10) : 1; if (!from.isValid()) { //|| from.isBefore() from = moment().startOf('day'); } if (!to.isValid() || to.isBefore(from, 'day') || to.isSame(from, 'day')) { to = moment(from); to.add('months', 1); } // regex should not allow 0 or above 12 if (/\d{1,2}(,\d{1,2})*/.test($stateParams.children)) { ages = $stateParams.children.split(',').map(function (element) { var a = parseInt(element, 10); return 0 < a && a < 12 ? a : 0; }); } else { ages = []; } return { tour: $stateParams.tour, from: from.toDate(), to: to.toDate(), lang: lang, adults: 0, ages: [], children: [], single: 0, double: 0, doubleWithChild: 0, triple: 0, quadruple: 0, age: 0, maxchildren: [0], children: 0, type: '' }; } /** * Listen for child count change to push/pop elements from ages */ function childCountChanged() { var ages = $scope.query.ages; ////console.log('childCountChanged',count) var i = 0; while (ages.length < $scope.query.doubleWithChild) { ages.push({ i: i++, v: $scope.query.age }); } // remove elements if length > count while (ages.length > $scope.query.doubleWithChild) { ages.pop(); } // //console.log("in childCountChanged",ages.length,$scope.query.ages) } function setChildren() { var ages = $scope.query.ages; var i = 0; while (ages.length < $scope.query.children) { ages.push({ i: i++, v: $scope.query.age }); } // remove elements if length > count while (ages.length > $scope.query.children) { ages.pop(); } //console.log("in setChildren", ages.length, $scope.query.ages); } function addchildage() { var ages = $scope.query.ages; ages.push(query.age); } $scope.singleOps = []; $scope.doubleOps = []; for (var i = 0; i <= 3; i++) { var o = { label: i, value: i }; $scope.singleOps.push(o); $scope.doubleOps.push(o); } ; $scope.tripleOps = []; for (var i = 0; i <= 1; i++) { var o = { label: i, value: i }; $scope.tripleOps.push(o); } ; $scope.childrenOps = [{ label: '0', value: '0' }]; $scope.agesOps = []; for (var i = 0; i <= 11; i++) { var o = { label: i, value: i }; $scope.agesOps.push(o); } $scope.singleSelection = 0; $scope.doubleSelection = 0; $scope.tripleSelection = 0; $scope.childrenSelection = 0; $scope.agesSelection = 0; $scope.$watch('singleSelection', function (newVal) { $scope.query.single = newVal; if ($scope.tour !== undefined) { adultCountChanged(); sendFormStatus(); } }); $scope.$watch('doubleSelection', function (newVal) { $scope.query.double = newVal; if ($scope.tour !== undefined) { adultCountChanged(); sendFormStatus(); } }); $scope.$watch('tripleSelection', function (newVal) { $scope.query.triple = newVal; if ($scope.tour !== undefined) { adultCountChanged(); sendFormStatus(); } }); $scope.$watch('childrenSelection', function (newVal) { $scope.query.children = newVal; if ($scope.tour !== undefined) { setChildren(); sendFormStatus(); } }); $scope.$watch('agesSelection', function (newVal) { // $scope.query.ages[$index] = newVal; if ($scope.tour !== undefined) { setChildren(); adultCountChanged(); sendFormStatus(); } }); function adultCountChanged() { // console.log("--------------------- hdfgkjdhgkjhdfjkgh ----------------", $scope.tour); if ($scope.tour.type === 'Tour' || $scope.tour.type === 'VO' || $scope.tour.type === 'OMRA') { $scope.query.adults = $scope.query.single + ($scope.query.double + $scope.query.doubleWithChild) * 2 + $scope.query.triple * 3 + $scope.query.quadruple * 4; } var N = $scope.query.adults + 1; options.boardQte = Array.apply(null, { length: N }).map(Number.call, Number); options.quantities = [ 0, $scope.query.adults ]; //$scope.products = null; //$scope.product = null; $scope.query.maxchildren = [0]; // var nbr = $scope.query.double * 3 + $scope.query.triple; var nbr = $scope.query.double; //console.log("nbr ", nbr); for (var i = 1; i <= nbr; i++) { $scope.query.maxchildren.push(i); } //console.log("$scope.query.maxchildren ", $scope.query.maxchildren); } // Should go to a servce in v1, to nodejs in v2 to tour-server in v3... function _getDepartures(rates) { // all we need is rates[n].lines aggregated in one arre (reduce...etc) var result = []; rates.map(function (rate) { return rate.lines; }).reduce(function (reduced, lines) { var i = lines.length, tmp; while (i--) { tmp = lines[i].departure.split('T')[0]; if (reduced.indexOf(tmp) === -1) { reduced.push(tmp); } } return reduced; }, result); result.sort(); return result; } /** * Process http success */ function _processRatesResponse(data) { if (data != undefined && data[0] != undefined && data[0].pricing != undefined && data[0].pricing[0] != undefined) { $scope.pricing = data[0].pricing[0]; $scope.currency = $scope.pricing.currency; $scope.departures = _getDepartures($scope.pricing.rates); } // $log.debug("pricing", $scope.pricing); // $log.debug("dates", $scope.departures); // console.log("------------ date departues ------------", $scope.departures); updateCalendar($scope.departures); getMinPrice(); // generatePdfOnit(); } function _processRatesError() { $log.error('Error querying rates', arguments); $scope.error = arguments; } function queryRates(query) { // $log.debug("queryRates: query", query); //console.log('--------------------------query in set date ', query); var params = { qt: 'search', tour: query.tour, from: moment(query.from).format(isoDate), to: moment(query.to).format(isoDate), lang: query.lang }; var options = { headers: { authorized: settings.tours.authorized }, params: params }; var url = settings.tours.endpoint; // this should be in settings. And we shouldn't call ratesGroup // there should be a getDepartures service then a quoteDeparture service... $http.get(url, options).success(_processRatesResponse).error(_processRatesError).finally(function () { }); } // Builds a data object for a day to be used in calendar. function _buildDay(d, deps, month, week) { var date = d.format(isoDate), day = { label: d.month() === month ? d.date() : '', date: moment.utc(d).startOf('day').toDate(), currentMonth: d.month() === month, departure: deps.indexOf(date) > -1, selected: false }; ////console.log('build day', day); week.push(day); } function _getDateRate(date, lines) { var i = lines.length; var mDate = moment.utc(date); while (i--) { if (moment(lines[i].departure).isSame(mDate, 'day')) { var ln = lines[i]; ln.code = $scope.pricing.code; //console.log('---------------------- get date rate ', ln); return ln; } } return null; } function updateCalendar(departures) { var firstOfMonth = moment.utc(departures[0], isoDate).startOf('month'); ////console.log("firstOfMonth ",firstOfMonth); var month = firstOfMonth.month(); var d = moment.utc(firstOfMonth).startOf('isoWeek'); var weeks = [], week = []; ////console.log('firstDayOfMonth',firstOfMonth,'month',month,'d',d) ; ////console.log('(d.month(',d.month(),'month',month) ; while (d.isBefore(firstOfMonth, 'day') || d.month() === month) { _buildDay(d, departures, month, week); d.add('days', 1); // week end if (week.length === 7) { weeks.push(week); week = []; } } while (week.length > 0 && week.length < 7) { _buildDay(d, departures, month, week); d.add('days', 1); } weeks.push(week); $scope.weeks = weeks; $scope.firstOfMonth = firstOfMonth.toDate(); } function goToMonth(date, diff) { var m = 'month'; var operation = diff > 0 ? 'add' : 'subtract'; var target = moment(date)[operation](1, m).startOf(m); var q = $scope.query; q.from = target.toDate(); q.to = moment(target).endOf(m).toDate(); // $log.debug("goToMonth query", q); queryRates(q); } function nextMonth(date) { goToMonth(date, 1); } function previousMonth(date) { goToMonth(date, -1); } // $scope.departureDate = null; function showProducts(date) { //console.log("date", date); $scope.depDate = moment(date).format('DD-MM-YYYY'); $scope.arivDate = moment(date).add($scope.tour.days.length, 'days').format('DD-MM-YYYY'); var categories = $scope.pricing.rates, category, rate, selection = [], i = categories.length; while (i--) { category = categories[i]; ////console.log("----------------------selected categories ", category); rate = _getDateRate(date, category.lines); ////console.log("----------------------selected rate ", rate); if (rate !== null) { if (rate.promo) { rate.priceYield = rate.promo.value; ////console.log("----------------------selected promo rate ", rate); //rawProduct.promo = rate.promo.name; } selection.unshift({ code: category.category.code, name: category.category.name, rate: rate, quadruple: category.category.quadruple }); } else { } } // //console.log("showProducts products ",selection); $scope.products = selection; $scope.product = null; for (var i = 0; i < $scope.weeks.length; i++) { for (var j = 0; j < $scope.weeks[i].length; j++) { date = new moment(new moment(date).format('DD/MM/YYYY'), 'DD/MM/YYYY'); $scope.weeks[i][j].date = new moment(new moment($scope.weeks[i][j].date).format('DD/MM/YYYY'), 'DD/MM/YYYY'); if (date.isSame($scope.weeks[i][j].date)) { $scope.weeks[i][j].selected = true; } else { $scope.weeks[i][j].selected = false; } } } } function showRules(p) { p.rate.showRules = !p.rate.showRules; } function sendFormStatus() { $scope.productButtonSelected = false; $scope.product = null; } function selectProduct(p) { $scope.productButtonSelected = true; $scope.devisOn = true; var query = $scope.query; query.currency = $scope.currency; $scope.product = p; //console.log("selectProduct ", p); $scope.quote = tourQuoteService.quote($scope.tour, p, query); /* for (var i = 0 ; i<query.adults ; i++) { $scope.quote.trip.travellers.push( {"classification": "ADULT","id": i,"type": "Traveller"}); }; for (var i = 0 ; i<query.ages.length ; i++) { $scope.quote.trip.travellers.push( {"classification": "CHILD","age": query.ages[i].v ,"id": query.adults+i,"type": "Traveller"} ); };*/ $scope.paxes = query.adults + query.ages.length; } function checkDisabledConditions() { if (angular.isArray($scope.products) && $scope.products.length > 0 && $scope.productButtonSelected === true) return false; else return true; } function optionSelected(opt) { return opt.qty > 0; } function quantityChanged(item) { if (item['@type'] === 'tourExtra' && item.product.type === 'board') { for (var i = $scope.quote.items.length - 1; i >= 0; i--) { var it = $scope.quote.items[i]; ////console.log("it is ", item); if (it != item && it['@type'] === 'tourExtra' && it.product.type === 'board') { $scope.quote.totals.total = $scope.quote.totals.total - it.totals.total; it.qty = 0; it.totals.total = 0; } } } var oldTotal = item.totals.total || 0; item.totals.total = item.product.price * item.qty; var diff = item.totals.total - oldTotal; $scope.quote.totals.total += diff; } function errorCallback(error) { $scope.error = error; } function cartSaveFailure(error) { $scope.error = error; $log.error('cart saving failed', error); } function cartSaveSuccess() { $scope.status = 'checkoutRedirect'; // $log.debug("cart saved", arguments); $window.location.href = settings.links.checkout; } function book(quote) { /* $http.delete('/carts') .then(function() { $http.put('/carts',$scope.quote).then(cartSaveSuccess, cartSaveFailure); }); */ $scope.quote.rooms = { single: $scope.query.single, double: $scope.query.double, doubleWithChild: $scope.query.doubleWithChild, triple: $scope.query.triple, quadruple: $scope.query.quadruple }; //console.log('in book') $http.post('/carts', $scope.quote).then(function (res) { //console.log("saveCard..tour"); if (angular.isArray(res.data)) { res.data = res.data[0]; } $scope.$emit('bookCartSaved', res.data); $window.location.href = '/ngapps/checkout#/' + res.data._id; }, function failed() { $log.error('cart saving failed', arguments); }); } function requestSaved() { $scope.requestStatus = 'success'; if (window.ga) { window.ga('send', 'event', 'voyage', 'demande', $rootScope.meta && $rootScope.meta.title); } } function requestSaveFailed() { $scope.requestStatus = 'failed'; } function initChildAges() { var children = $scope.query.children; var length = children.length; for (var i = 0; i < length; i++) { $scope.query.ages[i] = 1; } } function sendReservation() { $scope.requestStatus = 'saving'; var productName = ''; for (var i = $scope.query.ages.length - 1; i >= 0; i--) { request.children.push({ age: $scope.query.ages[i] }); } request.adults = $scope.query.adults; if (angular.isArray($scope.products) && $scope.products.length > 0) { if ($scope.products[0].parent) { productName = $scope.products[0].parent.name + ' ' + $scope.products[0].name; } } request.product = { _id: $scope.query.tour, name: productName }; request.departure = $scope.query.from; // $log.debug("request", $scope.request); //return; $http.post('/travel-product-requests', $scope.request).success(requestSaved).error(requestSaveFailed); } angular.extend($scope, { childCountChanged: childCountChanged, setChildren: setChildren, addchildage: addchildage, nextMonth: nextMonth, previousMonth: previousMonth, showProducts: showProducts, selectProduct: selectProduct, showRules: showRules, optionSelected: optionSelected, quantityChanged: quantityChanged, book: book, adultCountChanged: adultCountChanged, roomTypeChanged: roomTypeChanged, getQuote: '', sendFormStatus: sendFormStatus, productButtonSelected: false, checkDisabledConditions: checkDisabledConditions, sendReservation: sendReservation, request: request, depDate: null, nbrOfAdults: [1], clearRates: clearRates, initChildAges: initChildAges, scrollTo: scrollTo, generatePDF: generatePDF, loadingProgram: false, date: null, generatePdfTarifs: generatePdfTarifs, loadingTarif: false, devisOn: false, arivDate: null, pdfImage: null, options: options, query: buildQuery(), showMoreDaysProgram: showMoreDaysProgram }); // $log.debug("query", $scope.query); queryRates($scope.query); //****** pdwith kendo $scope.currentDate = new Date(); var someDate = new Date(); var numberOfDaysToAdd = 6; someDate.setDate(someDate.getDate() + numberOfDaysToAdd); function generatePDF() { //generatePdfOnit //console.log("generate program as pdf"); $scope.loadingProgram = true; kendo.pdf.defineFont({ 'DejaVu Sans': 'https://kendo.cdn.telerik.com/2016.1.112/styles/fonts/DejaVu/DejaVuSans.ttf', 'DejaVu Sans|Bold': 'https://kendo.cdn.telerik.com/2016.1.112/styles/fonts/DejaVu/DejaVuSans-Bold.ttf', 'DejaVu Sans|Bold|Italic': 'https://kendo.cdn.telerik.com/2016.1.112/styles/fonts/DejaVu/DejaVuSans-Oblique.ttf', 'DejaVu Sans|Italic': 'https://kendo.cdn.telerik.com/2016.1.112/styles/fonts/DejaVu/DejaVuSans-Oblique.ttf' }); // $timeout(function() { kendo.drawing.drawDOM('#program', { template: $('#page-template').html(), paperSize: 'A4', margin: '1cm', scale: 0.6, forcePageBreak: '.page-break', multiPage: true }).then(function (group) { //console.log(" ending generating group", group); kendoGroupe = group; var date = $filter('date')($scope.currentDate, 'yyyy-MM-dd'); //console.log(" begin saving pdf", kendoGroupe); kendo.drawing.pdf.saveAs(kendoGroupe, 'programme ' + $scope.tour.name + '-' + date + '.pdf'); $scope.loadingProgram = false; $scope.$apply(); }); //}, 100); } function generatePDF2() { var date = $filter('date')($scope.currentDate, 'yyyy-MM-dd'); //console.log(" begin saving pdf", kendoGroupe); kendo.drawing.pdf.saveAs(kendoGroupe, 'programme ' + $scope.tour.name + '-' + date + '.pdf'); //console.log("end saving pdf"); } //******** generate tarifs pdf ******// function generatePdfTarifs() { var date = $filter('date')($scope.currentDate, 'yyyy-MM-dd'); $scope.loadingTarif = true; kendo.pdf.defineFont({ 'DejaVu Sans': 'https://kendo.cdn.telerik.com/2016.1.112/styles/fonts/DejaVu/DejaVuSans.ttf', 'DejaVu Sans|Bold': 'https://kendo.cdn.telerik.com/2016.1.112/styles/fonts/DejaVu/DejaVuSans-Bold.ttf', 'DejaVu Sans|Bold|Italic': 'https://kendo.cdn.telerik.com/2016.1.112/styles/fonts/DejaVu/DejaVuSans-Oblique.ttf', 'DejaVu Sans|Italic': 'https://kendo.cdn.telerik.com/2016.1.112/styles/fonts/DejaVu/DejaVuSans-Oblique.ttf' }); //console.log("in generate tarifs as pdf"); $timeout(function () { kendo.drawing.drawDOM('#tarifs', { paperSize: 'A4', margin: '1cm', scale: 0.7 }).then(function (group) { kendo.drawing.pdf.saveAs(group, 'devis ' + $scope.tour.name + '-' + date + '.pdf'); $scope.loadingTarif = false; $scope.$apply(); }); }, 10); } } ]); /*if ($scope.query.type.toLowerCase() === 'quadruple') { selection.unshift({ code: category.category.code, name: category.category.name, rate: rate, hasQuadruple :false //category.category.quadruple }); }else{ selection.unshift({ code: category.category.code, name: category.category.name, rate: rate, hasQuadruple :true }); };*/ // $http.get(url + "?qt=byTour&tour=" + $stateParams.tour + "&lang=" + $stateParams.lang, _options).success(function (data) { // angular.extend(tour, { // description: data[0] // }); // }); // Get "tour" : // TODO there must be only one call to get full tour (data sheet+ description) // api should serve those two MERGED. // $http.get(settings.tours.endpoint + "/" + $stateParams.tour, _options).success(function (data) { // $scope.pdfImage = data.photos[0].url.replace("http", "https"); // data.photos.forEach(function (p) { // //settings.tour.imgrsz // p.url = "https://imgrsz.atlasvoyages.com/img/750x450/" + p.url; // //p.url = p.url.replace("http", "https"); // //p.url = p.url.replace("https://imgrsz.atlasvoyages.com/img/750x450/http", "https"); // }); // var facebookMeta = { // title: data.name, // description: data.description.lead, // image: data.photos[0].url, // url: "https://www.atlasvoyages.com/ngapps/vo-sales#/tour/" + $stateParams.tour + "?from=" + $stateParams.from + "&to=" + $stateParams.to + "&lang=fr" // }; // data.facebookMeta = facebookMeta; // angular.extend(tour, data); // $log.debug('emit tourProducthQuery', JSON.stringify($scope.tour.name)); // $scope.$emit('tourProducthQuery', $scope.tour.name); // $scope.context = 'product'; // }); angular.module('tours').directive('mySelect', [ '$window', function ($window) { function main(scope, element, attrs) { // console.log('mySelect directive', scope.ops, scope.selection); // Selecting model value for (var idx in scope.ops) { if (scope.ops[idx].value == scope.selection) { scope.selectedOpt = scope.ops[idx]; } } // Is a mobile device var isMobile = false; if (/ipad|iphone|android/gi.test($window.navigator.userAgent)) { isMobile = true; } // Select an option scope.selectOpt = function (opt) { scope.selection = opt.value; //scope.selectedOpt = opt; optionsDom.removeClass('active'); backdrop.removeClass('active'); }; scope.$watch('selection', function (newVal) { for (var idx in scope.ops) { if (typeof newVal == 'object' && JSON.stringify(newVal) == JSON.stringify(scope.ops[idx].value)) { scope.selectedOpt = scope.ops[idx]; } else if (scope.ops[idx].value == newVal) { scope.selectedOpt = scope.ops[idx]; } } }); // DOM References var labelDom = element.find('.my-select-label'); var optionsDom = element.find('.my-select-ops'); var backdrop = element.find('.my-select-backdrop'); var mobileSelect = element.find('select'); // DOM Event Listeners labelDom.on('click', function (e) { rePositionOps(); optionsDom.toggleClass('active'); backdrop.toggleClass('active'); }); backdrop.on('click', function (e) { optionsDom.removeClass('active'); backdrop.removeClass('active'); }); element.on('keydown', function (ev) { switch (ev.which) { case 37: // left arrow case 38: // top arrow preSelectPrev(); break; case 39: // right arrow case 40: // down arrow preSelectNext(); break; case 13: // enter key preSelectPush(); } }); // Initialization rePositionOps(); $($window).on('resize', function () { rePositionOps(); }); if (isMobile) { mobileSelect.addClass('active'); } // Positioning options function rePositionOps() { optionsDom.width(labelDom.width()); optionsDom.css({}); // Mobile ops mobileSelect.width(labelDom.outerWidth()); mobileSelect.height(labelDom.outerHeight()); mobileSelect.css({}); // console.log("rePositionOps", optionsDom); } // PreSelection logic: // This controls option selecting and highlighting by pressing the arrow // keys. var preSelected = 0; function updatePreSelection() { optionsDom.children().filter('.preselected').removeClass('preselected'); optionsDom.find('div').eq(preSelected).addClass('preselected'); // console.log(preSelected); } updatePreSelection(); function preSelectNext() { // console.log(scope.ops.length); preSelected = (preSelected + 1) % scope.ops.length; updatePreSelection(); } function preSelectPrev() { // console.log(scope.ops.length); preSelected = (preSelected - 1) % scope.ops.length; updatePreSelection(); } function preSelectPush() { scope.selectOpt(scope.ops[preSelected]); scope.$apply(); } } return { link: main, scope: { ops: '=mySelect', selection: '=selection' }, template: '<div class="my-select-label" tabindex="0" title="{{selectedOpt.label}}"><span class="my-select-label-text">{{selectedOpt.label}}</span><span class="my-select-caret"><svg viewBox="0 0 100 60"><polyline points="10,10 50,50 90,10" style="fill:none;stroke:#c30800;stroke-width:8;stroke-linecap:round;"/></svg></span></div><div class="my-select-backdrop"></div><div class="my-select-ops"><div ng-repeat="o in ops" ng-click="selectOpt(o)">{{o.label}}</div></div><select ng-options="opt.value as opt.label for opt in ops" ng-model="selection"></select>' }; } ]); // Source: src/html/scripts/tour-sales/services/tour-quote.js angular.module('tours').factory('tourQuoteService', function () { function addExtras(rawProduct, quote) { var extras = rawProduct.rate.supplements; var items = quote.items, charge; angular.forEach(extras, function (extra, index) { charge = extra.charge.slice(1); // TODO charge returned by tour is [UNIT,VALUE] // but should be [VALUE,UNIT] //charge.push(charge.shift()); if (extra.charge[0] === '-') { charge[0] = -charge[0]; } var day = ''; if (extra.code != undefined && extra.code.indexOf('#') > -1) { var arrayOfStrings = extra.code.split('#'); day = ' on ' + moment(quote.trip.content.checkin).add(parseInt(arrayOfStrings[1]) - 1, 'days').format('YYYY-MM-DD'); } items.push({ $type: 'tourExtra', '@type': 'tourExtra', product: { code: extra.code || rawProduct.code + ':opt:' + index, name: rawProduct.name + ' - ' + extra.name + day, type: extra.type, price: charge[0] }, qty: 0, totals: { total: 0 } }); }); } function createItem(type, product, travellers, parent) { travellers = travellers || []; // if(product.name.indexOf(":") <= -1) // product.name = name+": "+product.name; product.parent = { 'name': parent.name, 'type': parent.type }; // console.log("parent ",parent); //product.translationDate = parent.translationDate; //var product.rate.departure var arrivalDates = []; var departures = []; if (parent.translationDate == undefined || parent.translationDate == 0) { var d = moment(product.rate.departure); arrivalDates.push(d.format('YYYY-MM-DD')); departures.push(d.add(parent.days.length, 'days').format('YYYY-MM-DD')); } else // support departure date translation , parent.translationDate>0 { for (var i = 0; i <= parent.translationDate; i++) { var d = moment(product.rate.departure).add(parseInt(i), 'days'); arrivalDates.push(d.format('YYYY-MM-DD')); //2014-12-25 departures.push(d.add(parent.days.length - 1, 'days').format('YYYY-MM-DD')); //2014-12-25 } ; } product.departuresDates = departures; product.arrivalDates = arrivalDates; var adnbr = 0; for (var i = travellers.length - 1; i >= 0; i--) { if (travellers[i].classification === 'ADULT') adnbr++; } return { $type: type, '@type': type, product: product, travellers: travellers, qty: adnbr, totals: { total: product.price * adnbr } }; } function quote(tour, rawProduct, query) { var quote = { trip: {}, items: [], totals: { total: 0 } }; var travellers = []; var adults = []; var children = [], child, adult; quote.trip.travellers = []; // console.log("quote tour ",tour); var adnbr = 1; var chnbr = 1; while (travellers.length < query.adults) { adult = { 'classification': 'ADULT', 'id': adnbr++, 'type': 'Traveller' }; travellers.push(adult); adults.push(adult); } // console.log("quote ages ", query.ages, rawProduct.rate.childs); while (children.length < query.ages.length) { var rules = rawProduct.rate.childs; var isch = false; var i = 0; while (i < rules.length) { if (query.ages[children.length] <= rules[i].to) { isch = true; } i++; } if (isch) { child = { 'classification': 'CHILD', 'id': adnbr + chnbr++, 'type': 'Traveller', age: query.ages[children.length] }; children.push(child); travellers.push(child); } else { adult = { 'classification': 'ADULT', 'id': adnbr++, 'type': 'Traveller', age: query.ages[children.length] }; travellers.push(adult); adults.push(adult); } // using children.length as index since it's growing } // console.log("quote children ", children, travellers); if (rawProduct.rate.promo) { //rawProduct.rate.priceYield = rawProduct.rate.promo.value; rawProduct.promo = rawProduct.rate.promo.name; rawProduct.rate.tripleReduction[0] = rawProduct.rate.promo.triple; } rawProduct.price = rawProduct.rate.priceYield; rawProduct.code = tour.code + ':' + rawProduct.code + ':' + rawProduct.rate.code + ':' + query.lang; // rawProduct.code = rawProduct.code /////////// will be deleted when doubleWith child will be removed from old booking processs ////////// if (query.doubleWithChild > 0) quote.items.push(createItem(tour.type, rawProduct, adults, tour)); else quote.items.push(createItem(tour.type, rawProduct, travellers, tour)); ///////////////////////////////////////////////////////////////////////////////////////////////////// quote.trip.content = {}; quote.currency = query.currency; quote.trip.content.checkin = rawProduct.rate.departure; quoteChildren(rawProduct, children, quote.items, tour); // console.log('tour.typetour.typetour.type', tour.type, query.single, query.triple); if (tour.type === 'Tour' || tour.type === 'VO' || tour.type === 'OMRA') { // console.log('tourQuoteService', query); if (query.single != 0) { quote.items.push({ $type: 'tourExtra', '@type': 'tourExtra', product: { code: rawProduct.code + ':opt:supp', name: 'Single Supplements', price: rawProduct.rate.supplmtSingleYield }, qty: query.single, totals: { total: query.single * rawProduct.rate.supplmtSingleYield } }); } if (query.triple != 0) { var qte = 3; if (tour.type === 'OMRA') qte = query.adults; quote.items.push({ $type: 'tourExtra', '@type': 'tourExtra', product: { code: rawProduct.code + ':opt:supp', name: 'Triple Discount', price: rawProduct.rate.tripleReduction[1] === '%' ? -1 * rawProduct.rate.priceYield * rawProduct.rate.tripleReduction[0] / 100 : rawProduct.rate.tripleReduction[0] - rawProduct.rate.priceYield }, qty: rawProduct.rate.tripleReduction[1] === '%' ? query.triple : qte * query.triple, totals: { total: rawProduct.rate.tripleReduction[1] === '%' ? query.triple * -1 * rawProduct.rate.priceYield * rawProduct.rate.tripleReduction[0] / 100 : qte * query.triple * (rawProduct.rate.tripleReduction[0] - rawProduct.rate.priceYield) } }); } ; if (query.quadruple != 0) { var qte = 4; if (tour.type === 'OMRA') qte = query.adults; quote.items.push({ $type: 'tourExtra', '@type': 'tourExtra', product: { code: rawProduct.code + ':opt:supp', name: 'Quadruple Discount', price: rawProduct.rate.quadruple - rawProduct.rate.priceYield }, qty: qte * query.quadruple, totals: { total: qte * query.quadruple * (rawProduct.rate.quadruple - rawProduct.rate.priceYield) } }); } ; } ; // calculate total quote.totals.total = quote.items.reduce(function (total, item) { return total + item.totals.total; }, 0); quote.trip.travellers = travellers; addExtras(rawProduct, quote); return quote; } function quoteChildren(product, children, items, tour) { var standardPrice = product.rate.price, rules = product.rate.childs, len = rules.length, childItemsMap = {}; // console.log("quoteChildren ", children); children.forEach(function (child) { var i = 0; while (i < len) { if (child.age < rules[i].to) { // TODO .to should be called .under // console.log('creating rule ', child, rules[i], childItemsMap, product); return _addChildToItems(child, rules[i], childItemsMap, product, tour); } i++; } }); // console.log("childItemsMap", childItemsMap); // Now that we have aggregated children into items // do a 'list.addAll(map.values)' for (var k in childItemsMap) { items.push(childItemsMap[k]); } } function _addChildToItems(child, rule, childItemsMap, _product, tour) { var key = 'child' + rule.to; var item = childItemsMap[key]; var product; if (!item) { product = { code: _product.code + ':chd' + rule.to, name: _product.name + ' - child under ' + rule.to + ' years', price: calculateCharge(rule.charge, _product.rate.priceYield), rate: _product.rate }; item = childItemsMap[key] = createItem(tour.type, product, undefined, tour); } item.travellers.push(child); item.qty += 1; item.totals.total += item.product.price; return item; } /** * given charge [value,unit] and basePrice * returns the relative charge if unit is % or flat charge if unit * is currency */ function calculateCharge(charge, basePrice) { if (charge[1] === '%') { return charge[0] * basePrice / 100; } else { return charge[0]; } } return { quote: quote }; }); }());