(function () { 'use strict'; // Source: src/html/scripts/checkout/index.js /** * @ngdoc overview * @name checkout * Checkout module */ angular.module('checkout', [ 'ui.bootstrap', 'ui.router', 'oc.lazyLoad' ]).config([ 'datepickerConfig', 'datepickerPopupConfig', function (datepickerConfig, datepickerPopupConfig) { datepickerConfig.showWeeks = false; datepickerConfig.dayFormat = 'd'; datepickerConfig.startingDay = 1; datepickerConfig.datepickerMode = 'year'; datepickerPopupConfig.toggleWeeksText = null; datepickerPopupConfig.showButtonBar = false; //datepickerConfig.da } ]).config([ '$sceProvider', '$stateProvider', '$urlRouterProvider', '$httpProvider', function ($sceProvider, $stateProvider, $urlRouterProvider, $httpProvider) { function resolveCart($http, $stateParams) { return $http.get('/carts/' + $stateParams.cart).then(function (res) { return res.data; }, function () { return null; }); } function loadDependencies(deps, $ocLazyLoad) { var flattened = []; angular.forEach(deps, function (val, key) { flattened.push({ name: key, files: val }); }); return $ocLazyLoad.load(flattened); } function sortPanes(a, b) { return a.weight - b.weight; } $stateProvider.state('checkout', { url: '/:cart', templateUrl: 'checkout-form', controller: 'CheckoutCtrl', resolve: { countries: [ '$http', function ($http) { return $http.get('https://s3-eu-west-1.amazonaws.com/jsdn/countries_fr.json').then(function (res) { var countries = []; for (var code in res.data) { countries.push({ code: code, name: res.data[code] }); } return countries; }); } ], cart: [ '$http', '$stateParams', function ($http, $stateParams) { return resolveCart($http, $stateParams); } ], paymentMethods: [ '$http', '$stateParams', function ($http, $stateParams) { return $http.get('/payment-methods?cart=' + $stateParams.cart).then(function (res) { return res.data; }, function () { return []; }); } ], panes: [ '$http', '$stateParams', '$ocLazyLoad', function ($http, $stateParams, $ocLazyLoad) { return $http.get('/checkout-panes?cart=' + $stateParams.cart).then(function (res) { var pane, result = { summary: [], form: [] }; var deps = {}; for (var i = 0; i < res.data.length; i++) { pane = res.data[i]; //result[pane.type][pane.id] = pane; result[pane.type].push(pane); if (pane.dependencies) { angular.extend(deps, pane.dependencies); } if (pane.templates) { for (var id in pane.templates) { $templateCache.put(id, pane.templates[id]); } } } // sort stuff by weight result.summary.sort(sortPanes); result.form.sort(sortPanes); return loadDependencies(deps, $ocLazyLoad).then(function () { return result; }, function (error) { throw new Error('Could not load panes dependencies.' + error); }); }, function () { return []; }); } ] } }).state('processing', { url: '/:cart/processing', templateUrl: 'checkout-processing', controller: 'ProcessingCtrl' }).state('complete', { url: '/:cart/complete', templateUrl: 'checkout-complete', controller: 'CheckoutCompleteCtrl', resolve: { cart: [ '$http', '$stateParams', function ($http, $stateParams) { return resolveCart($http, $stateParams); } ], panes: [ '$http', '$stateParams', '$ocLazyLoad', function ($http, $stateParams, $ocLazyLoad) { return $http.get('/checkout-panes?cart=' + $stateParams.cart).then(function (res) { var pane, result = { summary: [] }; var deps = {}; for (var i = res.data.length - 1; i >= 0; i--) { pane = res.data[i]; if (pane.type !== 'summary') { continue; } pane = res.data[i]; //result[pane.type][pane.id] = pane; result.summary.push(pane); if (pane.dependencies) { angular.extend(deps, pane.dependencies); } if (pane.templates) { for (var id in pane.templates) { $templateCache.put(id, pane.templates[id]); } } } // sort stuff by weight result.summary.sort(sortPanes); return loadDependencies(deps, $ocLazyLoad).then(function () { return result; }, function (error) { throw new Error('Could not load panes dependencies.' + error); }); }, function () { return []; }); } ] } }).state('error', { url: '/:cart/error', templateUrl: 'checkout-error', controller: 'CheckoutErrorCtrl', resolve: { cart: [ '$http', '$stateParams', function ($http, $stateParams) { return resolveCart($http, $stateParams); } ] } }); // otherwise 404 $urlRouterProvider.otherwise('/'); $httpProvider.defaults.headers.common.Accept = 'application/json'; } ]); // Source: src/html/scripts/checkout/analytics.js angular.module('checkout').run([ '$rootScope', '$injector', '$log', function ($rootScope, $injector, $log) { if (!window.ga) { $log.debug('no ga'); return; } var $analytics; try { $analytics = $injector.get('$analytics'); } catch (e) { // Error: [$injector:unpr] // just returned, analytics is not loaded $log.warn('$analytics not available'); return; } var ga = window.ga; /* $rootScope.$on('cartLoaded', function (cart) { $log.info('checkout start'); angular.forEach(cart.items , function(item) { ga('ec:addProduct', itemToGa(item)); }); ga('ec:setAction', 'checkout', {'step': 1}); //ga('send', 'event'); ga('send', 'pageview'); }); $rootScope.$on('checkoutPayment', function (cart, payment) { $log.info('checkout payment'); angular.forEach(cart.items , function(item) { ga('ec:addProduct', itemToGa(item)); }); ga('ec:setAction', 'checkout', {'step': 2}); //ga('send', 'event'); ga('send', 'pageview'); //$analytics.pageTrack('/checkout/payment'); });*/ // may be move this to checkout complete // ga will can handle duplicates with transaction id ? $rootScope.$on('checkoutComplete', function ($event, cart) { $log.info('checkout complete', cart); angular.forEach(cart.items, function (item) { ga('ec:addProduct', itemToGa(item)); }); ga('ec:setAction', 'purchase', { id: cart.orderNumber || cart._id, revenue: cart.totals.total }); //ga('send', 'event'); ga('send', 'pageview', '/checkout/complete'); }); $rootScope.$on('checkoutUpdateCartSuccess', function ($event, cart) { $log.info('checkout update cart:', cart); var path = '/checkout/', type = cart.items[0]['@type'] ? cart.items[0]['@type'].toLowerCase() : 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; } $analytics.pageTrack(path); }); $rootScope.$on('checkoutError', function ($event, cart) { $log.info('checkout error'); //cartId = ($event.cart && $event.cart._id) || 'NC'; $analytics.eventTrack('checkoutError', { category: 'checkout' }); }); $rootScope.$on('cartExpired', function ($event, cart) { $log.info('cart expired'); $analytics.eventTrack('cartExpired', { category: 'checkout' }); }); function itemToGa(item) { return { id: item.type || item['@type'], category: item.type || item['@type'], name: item.type || item['@type'], quantity: 1, price: item.totals.total }; } } ]); // Source: src/html/scripts/checkout/controllers/checkout.js angular.module('checkout').controller('CheckoutCtrl', [ '$scope', '$window', '$rootScope', '$http', '$timeout', '$log', '$modal', 'settings', 'cart', '$state', '$q', 'paymentMethods', 'panes', 'countries', function CheckoutCtrl($scope, $window, $rootScope, $http, $timeout, $log, $modal, settings, cart, $state, $q, paymentMethods, panes, countries) { var cartExpires; //$log.debug('panes', panes); function init() { if (cart === null) { $window.location.href = '/404'; return false; } else if (cart.status === 'complete') { $state.go('complete', { cart: cart._id }); } else if (cart.status === 'errored') { $state.go('error', { cart: cart._id }); } else { // timeout on cart expiry so as not to have problems later if (cart.expires) { $log.debug('cart expires ' + cart.expires); var expires = moment(cart.expires).diff(moment()); cartExpires = $timeout(expireCart, expires); } // orders.get().then(init); angular.extend($scope, { operations: {}, order: cart, paymentMethods: paymentMethods, settings: settings, saveOption: saveOption, toPayment: toPayment, toggleCalendar: toggleCalendar, calendars: {}, options: { greetings: [ 'Mr', 'Mme' ], countries: countries }, panes: panes }); $rootScope.$emit('cartLoaded', cart); $scope.$on('$destroy', destroy); } } function destroy() { if (cartExpires) { cartExpires.clear(); //clear(cartExpires); } } function toggleCalendar($event, cal) { $event.preventDefault(); $event.stopPropagation(); var oldvalue = $scope.calendars[cal]; $scope.calendars = {}; $scope.calendars[cal] = !oldvalue; } function expireCart() { $rootScope.$emit('cartExpired', cart); $state.go('error', { cart: cart.number, error: 'expired' }); } function toPayment(paymentMethod) { paymentMethod.disabled = true; $scope.paymentMethod = paymentMethod; if ($scope.checkoutForm && $scope.checkoutForm.$invalid) { $log.error('Cannot update order since form is invalid.'); return false; } cart.status = 'checkout'; saveCart().then(continueToPayment, cartNotSaved); } function saveOption() { // enure status == checkout cart.status = 'checkout'; saveCart().then(function (c) { $scope.cart = c; var opts = { templateUrl: 'cart-save-message', scope: $scope, backdrop: 'static', controller: 'SavedMessageCtrl' }; var message = $modal.open(opts); /* message.result.then(function () { if (paymentSuccessfull(payment)) { $scope.$emit('checkoutComplete', cart); $state.go('complete', { cart: $scope.cart._id }); } }); */ }, cartNotSaved); } /** * * */ function customTypes(cart) { // lodge n'a pas @type ==> laisser le traitement comme avant if (cart.items[0]['@type']) { return cart.items.filter(function (item) { item['@type'].toLowerCase() === 'customtopay'; }); } else return []; } function saveCart() { var def = $q.defer(); var cstmTypes = customTypes(cart); //if for is pristine && valid(has already been saved) if (cart.orderNumber || $scope.checkoutForm && $scope.checkoutForm.$pristine && cstmTypes.length == 0) { def.resolve(cart); return def.promise; } $scope.operations.cartSaving = true; $http.put('/carts/' + cart._id, cart).success(function (body) { console.log('cart saved success', body); body._id = body._id || cart._id; angular.extend(cart, body); if (body.status === 'errored') { var e = new Error('Cart saved but has issues'); e.cart = body; def.reject(e); } else { if ($scope.checkoutForm) { $scope.checkoutForm.$setPristine(); } $rootScope.$broadcast('cart saved', body); //if(cart.status && ['', 'filled'].indexOf(cart.status.toLowerCase() > -1)) { $scope.$emit('checkoutUpdateCartSuccess', cart); //} def.resolve(body); } $scope.operations.cartSaving = false; }).error(function (status) { console.log('error while updating cart', status); var e = new Error('Could not update cart. Server response ' + status); $log.error(e, arguments); e.cart = cart; def.reject(e); $scope.operations.cartSaving = false; }); return def.promise; } function cartNotSaved(error) { $rootScope.$emit('checkoutError', error); // may be we should use "inconsistent". errored sounds weird... if (error.cart && error.cart.status === 'errored') { $state.go('error', { cart: cart._id }); } } function continueToPayment(cart) { // should mark cart as saved // so we don't have to recreate it if user does not change data $scope.cart = cart; var opts = { templateUrl: 'payment-popup', controller: 'PaymentCtrl', size: 'lg', windowClass: 'payment-popup', scope: $scope, backdrop: 'static' }; var paymentModal = $modal.open(opts); paymentModal.result.then(function (payment) { if (paymentSuccessfull(payment)) { $scope.$emit('checkoutComplete', cart); $state.go('complete', { cart: $scope.cart._id }); } }, function (error) { $scope.$emit('checkoutError', error); }); } function paymentSuccessfull(payment) { return [ 'authorized', 'received', 'processed', 'cleared' ].indexOf(payment.status > -1); } init(); } ]); // Source: src/html/scripts/checkout/controllers/complete.js angular.module('checkout').controller('CheckoutCompleteCtrl', [ '$scope', 'cart', 'panes', '$state', '$http', '$log', 'settings', '$filter', '$timeout', 'paymentMethods', '$window', 'GoogleTagManager', function ($scope, cart, panes, $state, $http, $log, settings, $filter, $timeout, paymentMethods, $window, GoogleTagManager) { if (cart === null) { window.location.href = '/404'; } if (cart.status === 'errored') { return $state.go('error', { cart: cart._id }); } else if (cart.status === 'processing') { return $state.go('processing', { cart: cart._id }); } else if (cart.status !== 'complete') { return $state.go('checkout', { cart: cart._id }); } $scope.cart = cart; $scope.order = cart; $scope.panes = panes; $scope.settings = settings; var category = null; var lobs = cart.items.map(function (item) { // @type is still used but deprecated // lobs MUST update to type return item['@type'] || item.type; }).filter(function (type) { return type !== 'fee'; }).map(function (type) { return type.toLowerCase(); }); var transactionProducts; if (lobs.indexOf('air') > -1) { GoogleTagManager.push({ 'event': 'confirmation_vol' }); transactionProducts = cart.items.map(function (item, i) { return { 'sku': item.number, 'name': cart.trip.segments[0].departure.location.name + '-' + cart.trip.segments[0].arrival.location.name, 'category': 'vol', 'price': item.totals.TOTAL, 'quantity': item.quantity }; }); } else if (lobs.indexOf('lodge') > -1) { GoogleTagManager.push({ 'event': 'confirmation_hotel' }); transactionProducts = cart.items.map(function (item, i) { return { 'sku': item.type + '-' + (item.type !== 'fee' ? item.product.code : item.fee ? item.fee.code : null), 'name': cart.trip.segments[0].property.name + '_' + cart.trip.segments[0].property.address.country + '_' + cart.trip.segments[0].property.address.location, 'category': 'hotel', 'price': item.totals.total, 'quantity': item.quantity }; }); } else if (lobs.indexOf('vo') > -1 || lobs.indexOf('omra') > -1) { GoogleTagManager.push({ 'event': 'confirmation_vo' }); transactionProducts = cart.items.map(function (item, i) { return { 'sku': item.product.code, 'name': item.product.name, 'category': 'hotel', 'price': item.totals.total, 'quantity': item.qty }; }); } GoogleTagManager.push({ 'event': 'achats', 'transactionId': cart.orderNumber || cart._id, 'transactionAffiliation': 'Atlasvoyages', 'transactionTotal': cart.totals.total, 'transactionProducts': transactionProducts }); console.log('dataLayer', $window.dataLayer); // payement methode function init(payment) { console.log(' geting payment : ', payment); $scope.paymentOrder = payment[0]; } function methodsQueryFailed() { console.log(' failed geting payment'); } paymentMethods.getPaymentByOrder($scope.order).then(init, methodsQueryFailed); //******** generate commande pdf ******// $scope.currentDate = new Date(); $scope.loadingCommande = false; $scope.generatePdfCommande = function () { var date = $filter('date')($scope.currentDate, 'yyyy-MM-dd'); $scope.loadingCommande = 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 commande as pdf'); $timeout(function () { kendo.drawing.drawDOM('#commande', { paperSize: 'A4', margin: '1cm', scale: 0.7 }).then(function (group) { kendo.drawing.pdf.saveAs(group, 'commande N\xb0 ' + $scope.cart._id + '-' + date + '.pdf'); $scope.loadingCommande = false; $scope.$apply(); }); }, 10); }; //******** generate recette pdf ******// $scope.loadingRecette = false; $scope.generatePdfRecette = function () { var date = $filter('date')($scope.currentDate, 'yyyy-MM-dd'); $scope.loadingRecette = 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 bon de recette as pdf'); $timeout(function () { kendo.drawing.drawDOM('#recette', { paperSize: 'A4', margin: '1cm', scale: 0.7 }).then(function (group) { kendo.drawing.pdf.saveAs(group, 'bon_recette N\xb0 ' + $scope.cart._id + '-' + date + '.pdf'); $scope.loadingRecette = false; $scope.$apply(); }); }, 10); } // if $scope.order not complete redirect to / ; } ]); // Source: src/html/scripts/checkout/controllers/error.js angular.module('checkout').controller('CheckoutErrorCtrl', [ '$scope', 'cart', '$http', '$log', 'settings', function CheckoutCtrl($scope, cart, $http, $log, settings) { if (cart === null || cart.status !== 'errored') { window.location.href = '/404'; } $scope.cart = cart; $scope.settings = settings; } ]); // Source: src/html/scripts/checkout/controllers/payment.js angular.module('checkout').controller('PaymentCtrl', [ '$scope', '$window', '$timeout', '$log', '$sce', '$q', '$http', '$ocLazyLoad', '$modalInstance', '$rootScope', function PaymentCtrl($scope, $window, $timeout, $log, $sce, $q, $http, $ocLazyLoad, $modalInstance, $rootScope) { $scope.statuses = { IDLE: 0, LOADING: 10, SUBMITING_PAYMENT: 11, PAYMENT_ERROR: 30 }; var confirmAction = { label: 'Confirmer', run: submitPayment, primary: true, busy: false }; /** * creates a payment object with data from cart. * - if the payment method requires a redirect * it saves payment to let the method add * redirect info on the server side * - if method defines a form for additional payment info * loads any dependencies then sets template path in scope * so it can be loaded in view (and filled by user) * - otherwise, the method is supposed to be a direct payment method * therefore POST payment as is. * */ function init() { var method = $scope.paymentMethod; var payment = createPayment($scope.cart, method); console.log('payemettttt', payment, method); $scope.payment = payment; $scope.status = 'processing'; if (method.redirect) { // payment redirect need saving payment first savePayment(payment).then(paymentRedirect, displayServerError); } else if (method.form) { if (method.form.dependencies) { $ocLazyLoad.load(method.form.dependencies).then(setupPaymentForm, displayServerError); } else { setupPaymentForm(); } } else { submitPayment(); } } function customTypes(cart) { // lodge n'a pas @type ==> laisser le traitement comme avant if (cart.items[0]['@type']) { return cart.items.filter(function (item) { return item['@type'].toLowerCase() == 'vo' || item['@type'].toLowerCase() == 'customtopay'; }); } else return []; } function createPayment(cart, method) { return { status: 'intended', method: method.code, order: cart._id || cart.number, total: customTypes(cart).length > 0 && $scope.cart.totals.toPay ? $scope.cart.totals.toPay : $scope.cart.totals.total }; } function setupPaymentForm() { $scope.formTemplate = $scope.paymentMethod.form.template; $scope.submitPayment = submitPayment; $scope.actions = [ confirmAction, { label: 'Fermer', run: cancel } ]; $scope.status = 'idle'; } function savePayment(payment) { var def = $q.defer(); confirmAction.busy = true; $scope.status = 'saving'; $http.post('/payments', payment).success(function (body) { console.log('save payment success ...'); $scope.$broadcast('payment created', body); def.resolve(body); confirmAction.busy = false; $scope.status = 'idle'; }).error(function () { var e = new Error('Could not create payment. Server response ' + status); console.error(e, arguments); def.reject(arguments[1]); confirmAction.busy = false; $scope.status = 'error'; }); return def.promise; } function submitPayment() { savePayment($scope.payment).then(paymentDone, displayServerError); } /** * closes modal returning payment object to parent */ function paymentDone(payment) { console.log('paymentDone', payment); if (payment.status === 'rejected') { $scope.status = 'error'; // rejection has message $scope.error = payment.error; $scope.actions = [{ label: 'Fermer', run: cancel }]; } else { $scope.status = 'processing'; $modalInstance.close(payment); } // close } function cancel() { $modalInstance.dismiss('cancel'); } function paymentRedirect(payment) { if (!payment.redirect) { throw new Error('Cannot process payment redirect. Payment has no redirect info.'); } var info = payment.redirect; var removeRedirectDoneListener = $scope.$on('paymentRedirectDone', function (p) { removeRedirectDoneListener(); paymentDone(p); }); if (info.method === 'GET' && payment.method.toLowerCase() === 'payzone') { $window.location.href = info.url; return; } // security hole ? If the server side gets hacked... Not otherwise :P ? info.url = $sce.trustAsResourceUrl(info.url); if (info.type === 'html') { info.data = $sce.trustAsHtml(info.data); } $scope.paymentRedirect = info; $scope.status = 'idle'; $rootScope.$broadcast('gateway.redirect', info); } function displayServerError(status, res, body) { $scope.status = 'error'; //$scope.statuses.PAYMENT_ERROR; if (body) { $scope.errorMessage = body.message; } else { $scope.errorMessage = 'An unexpected error happend while trying to continue to payment. Please call the support team for further details'; } $scope.actions = [{ label: 'Fermer', run: cancel }]; } init(); } ]).directive('offsitePayment', [ '$timeout', function ($timeout) { return { replace: true, scope: {}, template: '<form action="{{redirect.url}}" method="POST" name="redirectForm">{{redirect.data}}</form>', link: function ($scope, element, $attrs) { $scope.$on($attrs['event'], function (event, redirect) { if (redirect.url) { if (redirect.method === 'GET') { window.location.href = redirect.url; return; } else if (redirect.method === 'POST' && redirect.type === 'html') { $scope.redirect = redirect; $timeout(function () { console.log('element', element); $(element).submit(); }); } } }); } }; } ]); // Source: src/html/scripts/checkout/controllers/processing.js angular.module('checkout').controller('ProcessingCtrl', [ '$scope', '$state', '$timeout', '$stateParams', '$http', '$log', 'settings', function ProcessingCtrl($scope, $state, $timeout, $stateParams, $http, $log, settings) { var cartCheck = $timeout(getCart, 2000); $scope.$on('$destroy', function () { $timeout.cancel(cartCheck); }); function getCart() { $http.get('/carts/' + $stateParams.cart).success(function (data, status, headers, config) { if (data.status === 'processing') { cartCheck = $timeout(getCart, 2000); } else { $state.go('complete', { cart: $stateParams.cart }); } }).error(function (data, status, headers, config) { if (status === 404) { $timeout.cancel(cartCheck); window.location.href = '/404'; } else { $state.go('error', { cart: $stateParams.cart }); } }); } } ]); // Source: src/html/scripts/checkout/controllers/saved-message.js angular.module('checkout').controller('SavedMessageCtrl', [ '$scope', '$state', '$log', function ProcessingCtrl($scope, $state, $log) { } ]); // Source: src/html/scripts/checkout/directives/ui-datepicker.js angular.module('ui.bootstrap.datepicker').controller('DatepickerController', [ '$scope', '$attrs', '$parse', '$interpolate', '$timeout', '$log', 'dateFilter', 'datepickerConfig', function ($scope, $attrs, $parse, $interpolate, $timeout, $log, dateFilter, datepickerConfig) { console.log('DatepickerController'); 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)) { console.log($attrs.initDate, $parse($attrs.initDate)); $scope.$parent.$watch($parse('$parent.$parent.' + $attrs.initDate), function (value) { console.log('initdare ' + 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, classes: $attrs.dateClasses && $scope.dateClasses({ date: date, mode: $scope.datepickerMode }) || '' }; }; 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(); } }; } ]); // Source: src/html/scripts/checkout/filters/name.js angular.module('checkout').filter('name', function () { var vals = [ 'prefix', 'first', 'last' ]; return function (input) { if (!input) { return ''; } else if (typeof input === 'string') { return input; } else { return vals.map(function (field) { return input[field] || ''; }).join(' '); } }; }); // Source: src/html/scripts/checkout/filters/toWords.js angular.module('checkout').filter('words', function () { function isInteger(x) { return x % 1 === 0; } return function (value) { if (value && isInteger(value)) return toWords(value); return value; }; }); var th = [ '', 'mille', 'million', 'billion', 'trillion' ]; var dg = [ 'z\xe9ro', 'un', 'deux', 'trois', 'quatre', 'cinq', 'six', 'sept', 'huit', 'neuf' ]; var tn = [ 'dix', 'onze', 'douze', 'treize', 'quatorze', 'quinze', 'seize', 'dix-sept', 'dix-huit', 'dix-neuf' ]; var tw = [ 'vingt', 'trente', 'quarante', 'cinquante', 'soixante', 'soixante-dix', 'quatre-vingt', 'quatre-vingt-dix' ]; function toWords(s) { s = s.toString(); s = s.replace(/[\, ]/g, ''); if (s != parseFloat(s)) return 'not a number'; var x = s.indexOf('.'); if (x == -1) x = s.length; if (x > 15) return 'too big'; var n = s.split(''); var str = ''; var sk = 0; for (var i = 0; i < x; i++) { if ((x - i) % 3 == 2) { if (n[i] == '1') { str += tn[Number(n[i + 1])] + ' '; i++; sk = 1; } else if (n[i] != 0) { str += tw[n[i] - 2] + ' '; sk = 1; } } else if (n[i] != 0) { str += dg[n[i]] + ' '; if ((x - i) % 3 == 0) str += 'cent '; sk = 1; } if ((x - i) % 3 == 1) { if (sk) str += th[(x - i - 1) / 3] + ' '; sk = 0; } } if (x != s.length) { var y = s.length; str += 'point '; for (var i = x + 1; i < y; i++) str += dg[n[i]] + ' '; } return str.replace(/\s+/g, ' '); } window.toWords = toWords; // Source: src/html/scripts/checkout/mocks/panes/remarks.js /* angular.module('checkout') .controller('PaymentCtrl', function PaymentCtrl($scope, paymentMethods) { function init(methods){ $scope.paymentMethods = methods; $scope.payment = {}; // if one select it by default if (methods.length === 1) { $scope.payment.method = methods[0]; $scope.singleMethod = true; } else { $scope.singleMethod = false; } } function methodsQueryFailed() { $scope.errors.paymentMethods = "Failed to load payment methods"; } paymentMethods.query($scope.order).then(init, methodsQueryFailed); }); */ // Source: src/html/scripts/checkout/mocks/panes/travellers.js /* angular.module('checkout') .controller('PaymentCtrl', function PaymentCtrl($scope, paymentMethods) { function init(methods){ $scope.paymentMethods = methods; $scope.payment = {}; // if one select it by default if (methods.length === 1) { $scope.payment.method = methods[0]; $scope.singleMethod = true; } else { $scope.singleMethod = false; } } function methodsQueryFailed() { $scope.errors.paymentMethods = "Failed to load payment methods"; } paymentMethods.query($scope.order).then(init, methodsQueryFailed); }); */ // Source: src/html/scripts/checkout/services/gtm.js angular.module('checkout').service('GoogleTagManager', [ '$window', function ($window) { this.push = function (data) { try { $window.dataLayer.push(data); } catch (e) { } }; } ]); // Source: src/html/scripts/checkout/services/itemtypes.js /* angular.module('checkout') .service('Itemtypes', function Itemtypes() { // AngularJS will instantiate a singleton by calling "new" on this function }); */ // Source: src/html/scripts/checkout/services/payment-methods.js angular.module('checkout').factory('paymentMethods', [ '$q', '$http', '$log', function paymentMethods($q, $http, $log) { function query(cart) { var def = $q.defer(); $http.get('/payment-methods?order=' + cart._id).success(function (data) { def.resolve(data); }).error(function () { def.reject(arguments); }); return def.promise; } function preparePayment(cart, payment) { var method = payment.method; var def = $q.defer(); // TODO loop through payments and get the one with status PENDING $log.debug('preparePayment method', method); $http.get('/payment-methods/' + method.code + '?checkout=1').success(function (data) { def.resolve(data); }).error(function () { def.reject('Unable to process order payement'); }); return def.promise; } function getPaymentByOrder(cart) { var order = cart._id; console.log(' id cart : ', order); var def = $q.defer(); // TODO loop through payments and get the one with status PENDING $log.debug('Payment by order', order); $http.get('/payments?qt=byCode&code=' + order).success(function (data) { def.resolve(data); }).error(function () { def.reject('Unable to process order payement'); }); return def.promise; } // AngularJS will instantiate a singleton by calling "new" on this function return { process: preparePayment, query: query, getPaymentByOrder: getPaymentByOrder }; } ]); }());