PageSourceSearch

https://ssl.innovoice.fi/min/?b=assets/js&g=site_js&v=169cfaadbe9a0cd6bba1c703d801d5cc415b30a3

js innovoice.fi collected 2026-10-08 04:36:03 UTC 994,376 bytes, 29,716 lines download raw bytes

1/**
2 * @ai:claude Sends the browser to the login form when an XHR comes back 401, carrying the page the
3 * user was on so they land back on it after logging in.
4 *
5 * MY_Controller::redirectToLoginForm() cannot redirect an XHR - a 302 on an ajax call is followed by
6 * jQuery and the login page arrives as the response body - so it answers 401 and leaves it to the
7 * browser. Nothing was listening: utils/global.js has a handler, but it is only loaded by the
8 * `vendor_new_js` and `frontpage_js` groups, and it opens a jQuery-UI dialog inside a try/catch that
9 * swallows the failure when the page has no #dialog element - and then never runs the redirect
10 * anyway, because showPromptDialog() ignores the callback it is passed. On omat_tiedot the result
11 * was an expired session that looked like nothing happening at all.
12 *
13 * Deliberately its own file rather than pulling global.js into more templates: that file also
14 * defines the `global` object, jQuery-UI dialogs and a placeholder shim, none of which these pages
15 * want.
16 *
17 * The returnUrl is the current page, not the failed endpoint. The endpoint is a POST that saves
18 * something; sending the user back to it after login would either 404 or repeat a write.
19 */
20(function($) {
21  'use strict';
22
23  if (!$ || window.ivSessionExpiry) {
24    return;
25  }
26
27  var LOGIN_PATH = '/auth/login';
28
29  var ivSessionExpiry = {
30    // One redirect per page, however many requests fail at once
31    redirecting: false,
32
33    loginUrl: function() {
34      return LOGIN_PATH + '?returnUrl=' + encodeURIComponent(window.location.pathname + window.location.search);
35    },
36
37    /**
38     * Never from the login form itself or the rest of /auth - the session is expected to be absent
39     * there, and redirecting would loop.
40     */
41    shouldRedirect: function() {
42      return !this.redirecting && window.location.pathname.indexOf('/auth/') !== 0;
43    },
44
45    handle: function(status) {
46      if (status !== 401 || !this.shouldRedirect()) {
47        return;
48      }
49
50      this.redirecting = true;
51      // replace() so Back does not return to a page whose session is gone
52      window.location.replace(this.loginUrl());
53    },
54  };
55
56  window.ivSessionExpiry = ivSessionExpiry;
57
58  $(document).ajaxError(function(event, jqXHR) {
59    ivSessionExpiry.handle(jqXHR && jqXHR.status);
60  });
61})(window.jQuery);
62
63;
64var CustomerCardDialogVm = function() {
65    'use strict';
66    var self = this;
67
68    // Reference to jQuery ui dialog
69    self.inited = ko.observable(false);
70    self.dialog = null;
71    self.saving = ko.observable(false);
72    self.saved = ko.observable(false);
73
74    self.customer = {
75        id: ko.observable(null),
76        identifier: ko.observable(''),
77        type: ko.observable(),
78        ssn: ko.observable(''),
79        firstName: ko.observable(''),
80        lastName: ko.observable(''),
81        companyName: ko.observable(''),
82        businessId: ko.observable(''),
83        contactPerson: ko.observable(''),
84        contactPersonEmail: ko.observable(''),
85        extraInfo: ko.observable(''),
86        additionalInfo:ko.observable(''),
87        co: ko.observable(''),
88        address: ko.observable(''),
89        zipcode: ko.observable(''),
90        city: ko.observable(''),
91        email: ko.observable(''),
92        phone: ko.observable(''),
93        eInvoiceAddress: ko.observable(''),
94        eInvoiceOperator: ko.observable(''),
95        paymentTerms: ko.observable('14'),
96        deliveryMethod: ko.observable('mail'),
97        notificationMethod: ko.observable(null)
98    };
99
100    self.customerCardTitle = ko.computed(function(){
101
102       return 'Asiakaskortti'
103    })
104
105    self.availableDeliveryMethods = ko.computed(function() {
106
107        if (self.customer.type() === 'person') {
108           return [
109                { value: 'mail', text: 'Postitse' },
110                { value: 'sms', text: 'Tekstiviesti' },
111                { value: 'email', text: 'Sähköpostitse' },
112            ];
113        }
114
115        if (self.customer.type() === 'company') {
116            return [
117                { value: 'mail', text: 'Postitse' },
118                { value: 'email', text: 'Sähköpostitse' },
119                { value: 'e_invoice', text: 'Verkkolasku' },
120            ];
121        }
122
123        return [];
124    });
125
126
127    self.availableTermsOfPayment = ko.computed(function() {
128        var availableTermsOfPayment = [
129            { value: 7, type: 'net', text: '7 pv netto' },
130            { value: 10, type: 'net', text: '10 pv netto' },
131            { value: 14, type: 'net', text: '14 pv netto' },
132            { value: 21, type: 'net', text: '21 pv netto' },
133            { value: 30, type: 'net', text: '30 pv netto' },
134            { value: 45, type: 'net', text: '45 pv netto' },
135            { value: 60, type: 'net', text: '60 pv netto' },
136            { value: 90, type: 'net', text: '90 pv netto' },
137        ];
138
139        if (self.customer.type() === 'person') {
140            availableTermsOfPayment = $.grep(availableTermsOfPayment, function(elem) {
141                return (
142                    (elem.type === 'net' && elem.value >= 14 && elem.value !== 45) || elem.type !== 'net'
143                );
144            });
145        }
146
147        return availableTermsOfPayment;
148    });
149
150    self.eInvoiceOperators = ko.observableArray([]);
151
152    self.init = function() {
153
154        if(self.inited())
155            return;
156
157        // console.log('CustomerCardDialogVm::init');
158       // self.initJQueryElements();
159        self.applyKoBindings($('#customer-card-dialog')[0]);
160        self.inited(true);
161    };
162
163    self.applyKoBindings = function(elem){
164        ko.applyBindings(this, elem);
165    };
166
167    self.fetchAndUpdateData = function(customerId) {
168        jQuery
169            .ajax({
170                url: '/asiakasrekisteri/customer/'.concat(customerId),
171                dataType: 'json',
172            })
173            .done(self.setData)
174            .fail(function(response) {
175            });
176    };
177
178    self.show = function(customerId) {
179
180        // If jQuery UI dialog has not been inited yet
181        if (self.dialog === null) {
182            self.dialog = $('#customer-card-dialog').dialog({
183                width: 800,
184                height: 600,
185                autoOpen: false,
186                modal: true,
187                resizable: true,
188                draggable: true,
189                beforeclose: function(event) {
190                    $('link#extrabs').remove();
191                    $('script#bsjs').remove();
192                    event.stopPropagation();
193                },
194                title: self.customerCardTitle(),
195                buttons: [
196                    {
197                        text: 'Sulje',
198                        class: 'close-btn btn btn-default',
199                        click: function() {
200                            self.close();
201                        },
202                    },
203                    {
204                        text: 'Tallenna',
205                        class: 'save-btn btn btn-default',
206                        click: function() {
207                            //self.dialog.find('#account_card_form').submit();
208                            self.saveCustomer();
209                        },
210                    },
211                ],
212            });
213        }
214
215        self.dialog.dialog('open');
216
217        self.fetchAndUpdateData(customerId);
218    };
219
220    self.close = function() {
221        self.dialog.dialog('close');
222    };
223
224    self.setData = function(data) {
225
226        if (data.eInvoiceOperators) {
227          // console.log('CustomerCardDialog::setData, eInvoiceOperators: ', data.eInvoiceOperators);
228          ko.mapping.fromJS(data.eInvoiceOperators, {}, self.eInvoiceOperators);
229        }
230        self.setCustomerData(data.customer);
231    };
232
233    self.setCustomerData = function(customerData){
234
235        // console.log('CustomerCardDialog::setCustomerData, customer: ', customerData);
236
237        ko.mapping.fromJS(customerData, {}, self.customer);
238
239        //console.log(ko.toJSON(self.customer));
240    };
241
242    self.deleteCustomer = function (){
243
244        // console.log('CustomerCardDialog::deleteCustomer');
245
246        self.saving(true);
247        global.showLoadingDialog('Poistetaan asiakasta...');
248
249        jQuery
250            .ajax({
251                type: 'post',
252                dataType: 'json',
253                url: '/asiakasrekisteri/trashCustomer',
254                data: { id: self.customer.id() },
255            })
256            .done(function(responseJSON) {
257                self.saved(true);
258                global.show_message(responseJSON);
259                global.close_loading_dialog();
260                self.setData(responseJSON.data);
261            })
262            .fail(function(data) {
263                global.show_message($.parseJSON(data.responseText));
264                global.close_loading_dialog();
265                console.error('.ajax.fail:', data);
266            })
267            .then(function() {
268                // Set the saved observable back to false, so we can,
269                // listen for new saved events outside this obj
270                self.saving(false);
271                self.saved(false);
272            });
273    }
274
275    self.saveCustomer = function() {
276
277        var data = {
278            customer: ko.mapping.toJSON(self.customer),
279        };
280
281        self.saving(true);
282        global.showLoadingDialog('Tallennetaan...');
283
284        jQuery
285            .ajax({
286                type: 'post',
287                dataType: 'json',
288                url: '/asiakasrekisteri/save',
289                data: data,
290            })
291            .done(function(responseJSON) {
292                self.saved(true);
293                global.show_message(responseJSON);
294                global.close_loading_dialog();
295                self.setData(responseJSON.data);
296            })
297            .fail(function(data) {
298                global.show_message($.parseJSON(data.responseText));
299                global.close_loading_dialog();
300                // console.error('.ajax.fail:', data);
301            })
302            .then(function() {
303                // Set the saved observable back to false, so we can,
304                // listen for new saved events outside this obj
305                self.saving(false);
306                self.saved(false);
307            });
308
309        return false;
310    };
311
312}
313
314;/**
315 * humane.js
316 * Humanized Messages for Notifications
317 * @author Marc Harter (@wavded)
318 * @example
319 *   humane.log('hello world');
320 * See more usage examples at: http://wavded.github.com/humane-js/
321 */
322
323;!function (name, context, definition) {
324   if (typeof module !== 'undefined') module.exports = definition(name, context)
325   else if (typeof define === 'function' && typeof define.amd  === 'object') define(definition)
326   else context[name] = definition(name, context)
327}('humane', this, function (name, context) {
328   var win = window
329   var doc = document
330
331   var ENV = {
332      on: function (el, type, cb) {
333         'addEventListener' in win ? el.addEventListener(type,cb,false) : el.attachEvent('on'+type,cb)
334      },
335      off: function (el, type, cb) {
336         'removeEventListener' in win ? el.removeEventListener(type,cb,false) : el.detachEvent('on'+type,cb)
337      },
338      bind: function (fn, ctx) {
339         return function () { fn.apply(ctx,arguments) }
340      },
341      isArray: Array.isArray || function (obj) { return Object.prototype.toString.call(obj) === '[object Array]' },
342      config: function (preferred, fallback) {
343         return preferred != null ? preferred : fallback
344      },
345      transSupport: false,
346      useFilter: /msie [678]/i.test(navigator.userAgent), // sniff, sniff
347      _checkTransition: function () {
348         var el = doc.createElement('div')
349         var vendors = { webkit: 'webkit', Moz: '', O: 'o', ms: 'MS' }
350
351         for (var vendor in vendors)
352            if (vendor + 'Transition' in el.style) {
353               this.vendorPrefix = vendors[vendor]
354               this.transSupport = true
355            }
356      }
357   }
358   ENV._checkTransition()
359
360   var Humane = function (o) {
361      o || (o = {})
362      this.queue = []
363      this.baseCls = o.baseCls || 'humane'
364      this.addnCls = o.addnCls || ''
365      this.timeout = 'timeout' in o ? o.timeout : 2500
366      this.waitForMove = o.waitForMove || false
367      this.clickToClose = o.clickToClose || false
368      this.timeoutAfterMove = o.timeoutAfterMove || false 
369      this.container = o.container
370
371      try { this._setupEl() } // attempt to setup elements
372      catch (e) {
373        ENV.on(win,'load',ENV.bind(this._setupEl, this)) // dom wasn't ready, wait till ready
374      }
375   }
376
377   Humane.prototype = {
378      constructor: Humane,
379      _setupEl: function () {
380         var el = doc.createElement('div')
381         el.style.display = 'none'
382         if (!this.container){
383           if(doc.body) this.container = doc.body;
384           else throw 'document.body is null'
385         }
386         this.container.appendChild(el)
387         this.el = el
388         this.removeEvent = ENV.bind(function(){ if (!this.timeoutAfterMove){this.remove()} else {setTimeout(ENV.bind(this.remove,this),this.timeout);}},this)
389         this.transEvent = ENV.bind(this._afterAnimation,this)
390         this._run()
391      },
392      _afterTimeout: function () {
393         if (!ENV.config(this.currentMsg.waitForMove,this.waitForMove)) this.remove()
394
395         else if (!this.removeEventsSet) {
396            ENV.on(doc.body,'mousemove',this.removeEvent)
397            ENV.on(doc.body,'click',this.removeEvent)
398            ENV.on(doc.body,'keypress',this.removeEvent)
399            ENV.on(doc.body,'touchstart',this.removeEvent)
400            this.removeEventsSet = true
401         }
402      },
403      _run: function () {
404         if (this._animating || !this.queue.length || !this.el) return
405
406         this._animating = true
407         if (this.currentTimer) {
408            clearTimeout(this.currentTimer)
409            this.currentTimer = null
410         }
411
412         var msg = this.queue.shift()
413         var clickToClose = ENV.config(msg.clickToClose,this.clickToClose)
414
415         if (clickToClose) {
416            ENV.on(this.el,'click',this.removeEvent)
417            ENV.on(this.el,'touchstart',this.removeEvent)
418         }
419
420         var timeout = ENV.config(msg.timeout,this.timeout)
421
422         if (timeout > 0)
423            this.currentTimer = setTimeout(ENV.bind(this._afterTimeout,this), timeout)
424
425         if (ENV.isArray(msg.html)) msg.html = '<ul><li>'+msg.html.join('<li>')+'</ul>'
426
427         this.el.innerHTML = msg.html
428         this.currentMsg = msg
429         this.el.className = this.baseCls
430         if (ENV.transSupport) {
431            this.el.style.display = 'block'
432            setTimeout(ENV.bind(this._showMsg,this),50)
433         } else {
434            this._showMsg()
435         }
436
437      },
438      _setOpacity: function (opacity) {
439         if (ENV.useFilter){
440            try{
441               this.el.filters.item('DXImageTransform.Microsoft.Alpha').Opacity = opacity*100
442            } catch(err){}
443         } else {
444            this.el.style.opacity = String(opacity)
445         }
446      },
447      _showMsg: function () {
448         var addnCls = ENV.config(this.currentMsg.addnCls,this.addnCls)
449         if (ENV.transSupport) {
450            this.el.className = this.baseCls+' '+addnCls+' '+this.baseCls+'-animate'
451         }
452         else {
453            var opacity = 0
454            this.el.className = this.baseCls+' '+addnCls+' '+this.baseCls+'-js-animate'
455            this._setOpacity(0) // reset value so hover states work
456            this.el.style.display = 'block'
457
458            var self = this
459            var interval = setInterval(function(){
460               if (opacity < 1) {
461                  opacity += 0.1
462                  if (opacity > 1) opacity = 1
463                  self._setOpacity(opacity)
464               }
465               else clearInterval(interval)
466            }, 30)
467         }
468      },
469      _hideMsg: function () {
470         var addnCls = ENV.config(this.currentMsg.addnCls,this.addnCls)
471         if (ENV.transSupport) {
472            this.el.className = this.baseCls+' '+addnCls
473            ENV.on(this.el,ENV.vendorPrefix ? ENV.vendorPrefix+'TransitionEnd' : 'transitionend',this.transEvent)
474         }
475         else {
476            var opacity = 1
477            var self = this
478            var interval = setInterval(function(){
479               if(opacity > 0) {
480                  opacity -= 0.1
481                  if (opacity < 0) opacity = 0
482                  self._setOpacity(opacity);
483               }
484               else {
485                  self.el.className = self.baseCls+' '+addnCls
486                  clearInterval(interval)
487                  self._afterAnimation()
488               }
489            }, 30)
490         }
491      },
492      _afterAnimation: function () {
493         if (ENV.transSupport) ENV.off(this.el,ENV.vendorPrefix ? ENV.vendorPrefix+'TransitionEnd' : 'transitionend',this.transEvent)
494
495         if (this.currentMsg.cb) this.currentMsg.cb()
496         this.el.style.display = 'none'
497
498         this._animating = false
499         this._run()
500      },
501      remove: function (e) {
502         var cb = typeof e == 'function' ? e : null
503
504         ENV.off(doc.body,'mousemove',this.removeEvent)
505         ENV.off(doc.body,'click',this.removeEvent)
506         ENV.off(doc.body,'keypress',this.removeEvent)
507         ENV.off(doc.body,'touchstart',this.removeEvent)
508         ENV.off(this.el,'click',this.removeEvent)
509         ENV.off(this.el,'touchstart',this.removeEvent)
510         this.removeEventsSet = false
511
512         if (cb && this.currentMsg) this.currentMsg.cb = cb
513         if (this._animating) this._hideMsg()
514         else if (cb) cb()
515      },
516      log: function (html, o, cb, defaults) {
517         var msg = {}
518         if (defaults)
519           for (var opt in defaults)
520               msg[opt] = defaults[opt]
521
522         if (typeof o == 'function') cb = o
523         else if (o)
524            for (var opt in o) msg[opt] = o[opt]
525
526         msg.html = html
527         if (cb) msg.cb = cb
528         this.queue.push(msg)
529         this._run()
530         return this
531      },
532      spawn: function (defaults) {
533         var self = this
534         return function (html, o, cb) {
535            self.log.call(self,html,o,cb,defaults)
536            return self
537         }
538      },
539      create: function (o) { return new Humane(o) }
540   }
541   return new Humane()
542})
543
544;
544/**
545 * @ai:claude Procountor accounting settings - the tab in omat_tiedot and the same editor embedded
546 * in the admin account card.
547 *
548 * Deliberately NOT a webpack module: omat_tiedot has no webpack entry and is not gaining one, so
549 * this is plain ES5 in the same style as the ~40 other view models in this directory, loaded through
550 * the `site_js` minify group.
551 *
552 * It is never bound on its own. ko.applyBindings(VM, $('#omat_tiedot_tabs')[0]) already binds the
553 * whole tab container, and a second applyBindings inside an already-bound element throws, so this
554 * hangs off its host view model instead - UserSettingsVm.accounting on the settings page,
555 * AccountCardDialogVm.accounting on the account card - and the markup reaches it with a `with:`
556 * binding. For the same reason nothing in here calls applyBindings.
557 *
558 * Every row object carries its own save/remove functions, closed over the view model, so the markup
559 * never has to reach out of a nested foreach with $root or $parent. That is what lets the identical
560 * body partial render under two different roots.
561 *
562 * Server state is the only state: each write posts one row and the endpoint replies with the whole
563 * page payload, which is fed straight back into setData(). Nothing here predicts what the server
564 * did with a save.
565 */
566
567var AccountingSettingsVm = function(opts) {
568  'use strict';
569  var self = this;
570
571  // Nothing renders until setData() has run - a company without Procountor never gets a payload
572  self.available = ko.observable(false);
573  self.canEdit = ko.observable(false);
574  self.busy = ko.observable(false);
575
576  self.companyId = ko.observable(null);
577  self.companyName = ko.observable('');
578
579  // Read-only: until the company is flipped, everything configured here is stored but not used
580  self.useConfigResolver = ko.observable(false);
581
582  self.accountDefaults = ko.observableArray([]);
583
584  /** [{key, label}] - the card's block headings, in render order */
585  self.accountDefaultGroupLabels = ko.observableArray([]);
586
587  /**
588   * @ai:claude The Täsmäytys ja rajoitukset card - four preferences_procountor flags, not account
589   * configuration, which is why they are their own block and their own endpoint.
590   */
591  self.preferences = {
592    automaticReconciliation: ko.observable(false),
593    maxReconciliationAmount: ko.observable(''),
594    bankStatement: ko.observable(false),
595    blockEuSales: ko.observable(false),
596  };
597
598  self.types = ko.observableArray([]);
599  // @ai:claude Static display rows, not configuration. Every vähennys posts NO_VAT to the
600  // Vähennystili with its debit taken from the carrying transaction, so there is nothing per-kind to
601  // edit and nothing per-company to load - these come straight from the catalogue.
602  self.deductionKinds = ko.observableArray([]);
603  self.itemGlAccounts = ko.observableArray([]);
604  self.customerGlAccounts = ko.observableArray([]);
605  self.dimensionLinks = ko.observableArray([]);
606  self.stations = ko.observableArray([]);
607  // @ai:claude The dimensions card asks for the entity type first, and only 'station' resolves in
608  // the factory today. The list is here rather than in the view so adding the customer type later
609  // is one entry, not a markup change.
610  self.entityTypeOptions = ko.observableArray([{ value: 'station', name: 'Toimipiste' }]);
611
612  self.dimensionOptions = ko.observableArray([]);
613
614  // Which type panels the user has open. Kept outside the row objects so a save, which replaces
615  // every row with a fresh one from the server, does not collapse the panel being edited.
616  self.openTypes = {};
617
618  // '/omat_tiedot' on the settings page, '/asiakkuudet' on the account card. The account card also
619  // appends the company id, because there the company being configured is not the session company.
620  self.baseUrl = '/omat_tiedot';
621  self.adminMode = ko.observable(false);
622
623  self.lookups = {
624    dimensions: new AccountingSettingsVm.Lookup(self, 'dimensions', 'Dimensiot'),
625  };
626
627  self.lookupList = ko.observableArray([
628    self.lookups.dimensions,
629  ]);
630
631  self.dimensionsAreFreeText = ko.computed(function() {
632    return self.lookups.dimensions.fallback();
633  });
634
635  self.editableRows = ko.computed(function() {
636    return self.canEdit() && !self.busy();
637  });
638
639  /**
640   * @ai:claude Replaces the whole page from a server payload. Every endpoint returns one, so this
641   * runs after each write as well as at page load - the browser never patches its own copy of the
642   * configuration, because a partial save that the server rejected would otherwise look applied.
643   */
644  self.setData = function(data) {
645    if (!data) {
646      self.available(false);
647      return;
648    }
649
650    self.available(true);
651    self.canEdit(!!data.canEdit);
652    self.companyId(data.companyId || null);
653    self.companyName(data.companyName || '');
654    self.useConfigResolver(!!data.useConfigResolver);
655
656    self.setLookupData(data.lookups || {});
657
658    self.setPreferences(data.preferences || {});
659    // @ai:claude Not sorted here. AccountDefaults::KEYS is already in group order, and the previous
660    // comparator was not a valid one - it returned -1 for payments_in_transit regardless of which
661    // side of the comparison it was on, so the order it produced depended on the sort algorithm.
662    self.accountDefaultGroupLabels(data.accountDefaultGroups || []);
663    self.accountDefaults(
664      (data.accountDefaults || []).map(function(row) {
665        return new AccountingSettingsVm.AccountDefault(self, row);
666      })
667    );
668
669    self.types(self.buildTypes(data.types || [], 'types'));
670
671    self.deductionKinds(data.deductionKinds || []);
672
673    self.itemGlAccounts(data.itemGlAccounts || []);
674    self.customerGlAccounts(data.customerGlAccounts || []);
675    // Same reason as the option lists below: an explicit empty entry, never an optionsCaption
676    self.stations([{ id: '', name: 'Valitse toimipiste' }].concat(data.stations || []));
677    self.dimensionLinks(self.buildDimensionLinks(data.dimensionLinks || []));
678
679    self.rebuildOptions();
680  };
681
682  /** Kept separate from setData() only because every write re-reads the whole payload back */
683  self.setPreferences = function(preferences) {
684    self.preferences.automaticReconciliation(!!preferences.automaticReconciliation);
685    self.preferences.maxReconciliationAmount(
686      typeof preferences.maxReconciliationAmount === 'undefined' ? '' : preferences.maxReconciliationAmount
687    );
688    self.preferences.bankStatement(!!preferences.bankStatement);
689    self.preferences.blockEuSales(!!preferences.blockEuSales);
690  };
691
692  self.setLookupData = function(lookups) {
693    self.lookups.dimensions.setData(lookups.dimensions);
694  };
695
696  self.buildTypes = function(types, section) {
697    return types.map(function(type) {
698      return new AccountingSettingsVm.Type(self, type, section);
699    });
700  };
701
702  self.buildDimensionLinks = function(links) {
703    return links.map(function(link) {
704      return new AccountingSettingsVm.DimensionLink(self, link);
705    });
706  };
707
708  /**
709   * @ai:claude Account-default inputs are plain text fields now, not dropdowns - accounts,
710   * vat_statuses and vat_rates lookups are gone with procountor_lookup_cache. The only option list
711   * left is dimensions, for the dimension-link picker.
712   */
713  self.rebuildOptions = function() {
714    self.dimensionOptions(
715      [{ id: '', name: 'Valitse dimensio', items: [] }].concat(self.lookups.dimensions.items())
716    );
717  };
718
719  self.url = function(path) {
720    var url = self.baseUrl + '/' + path;
721
722    if (self.adminMode() && self.companyId()) {
723      url += '/' + self.companyId();
724    }
725
726    return url;
727  };
728
729  /**
730   * @ai:claude One POST, one refresh. Serialised through `busy` so two saves cannot race and leave
731   * the page showing the losing one's payload.
732   */
733  self.post = function(path, data, successText) {
734    if (self.busy()) {
735      self.notify('Edellinen tallennus on vielä kesken', 'warning');
736      return;
737    }
738
739    self.busy(true);
740
741    return $.ajax({ url: self.url(path), type: 'POST', data: data })
742      .done(function(response) {
743        if (response && response.data) {
744          self.setData(response.data);
745        }
746
747        self.notify(successText || (response && response.text) || 'Tallennettu', 'success');
748      })
749      .fail(function(xhr) {
750        self.notify(self.errorText(xhr), 'danger');
751      })
752      .always(function() {
753        self.busy(false);
754      });
755  };
756
757  self.errorText = function(xhr) {
758    try {
759      var parsed = JSON.parse(xhr.responseText);
760      return parsed.text || 'Toimintoa ei voitu suorittaa';
761    } catch (e) {
762      return 'Toimintoa ei voitu suorittaa';
763    }
764  };
765
766  // bootstrap alert class -> humane.js theme class (jackedup.css only styles these three)
767  var HUMANE_CLASS_BY_TYPE = {
768    success: 'humane-jackedup-success',
769    info: 'humane-jackedup-info',
770    danger: 'humane-jackedup-error',
771    warning: 'humane-jackedup-error',
772  };
773
774  /**
775   * @ai:claude Replaces the old top-of-page alert box, which on the omat_tiedot tab's long page made
776   * a failed save three cards down easy to miss. humane.js is bundled into site_js specifically for
777   * this (see groupsConfig.php) so it is always present wherever this view model runs; the existence
778   * check is just the usual defensive habit around a global, not a real "might be missing" case.
779   */
780  self.notify = function(text, type) {
781    if (text && typeof humane !== 'undefined') {
782      humane.log(text, {
783        addnCls: HUMANE_CLASS_BY_TYPE[type] || 'humane-jackedup-info',
784        timeout: type === 'danger' || type === 'warning' ? 6000 : 3000,
785        clickToClose: true,
786      });
787    }
788  };
789
790
791  /**
792   * @ai:claude The whole "Oletus tilit" card in one post. There is nothing to propagate any more -
793   * the transaction config table below is generated live from these accounts on every read - so the
794   * reply is just the refreshed page, which already shows what the new accounts generate.
795   *
796   * Every field is submitted rather than only the dirty ones, so the server validates the card as
797   * the user left it. It skips the unchanged ones itself; see AccountingSettingsWriter.
798   */
799  self.saveAccountDefaults = function() {
800    if (self.missingAccountDefaults().length) {
801      self.notify(self.missingAccountDefaultsText(), 'danger');
802      return;
803    }
804
805    var accounts = {};
806
807    self.accountDefaults().forEach(function(row) {
808      accounts[row.key] = row.account();
809    });
810
811    self.post('saveAccountingDefaults', { accounts: accounts }, null);
812  };
813
814  /**
815   * @ai:claude The Oletus tilit card as blocks: [{key, label, rows}], empty blocks dropped.
816   *
817   * Presentation only - dirtyAccountDefaults, missingAccountDefaults and saveAccountDefaults all
818   * keep walking the flat accountDefaults array, so the save still posts every key regardless of
819   * how the card is carved up. A block can come out empty when every default in it is a VAT variant
820   * the company's Procountor cannot post, which the server has already filtered out.
821   */
822  self.accountDefaultGroups = ko.computed(function() {
823    var rowsByGroup = {};
824
825    self.accountDefaults().forEach(function(row) {
826      (rowsByGroup[row.group] = rowsByGroup[row.group] || []).push(row);
827    });
828
829    return self.accountDefaultGroupLabels()
830      .filter(function(group) {
831        return (rowsByGroup[group.key] || []).length > 0;
832      })
833      .map(function(group) {
834        return { key: group.key, label: group.label, rows: rowsByGroup[group.key] };
835      });
836  });
837
838  self.dirtyAccountDefaults = ko.computed(function() {
839    return self.accountDefaults().filter(function(row) {
840      return row.isDirty();
841    });
842  });
843
844  // @ai:claude Required fields left blank. A blank here is not "unset" downstream - it generates a
845  // NULL account, which TransactionAdapter turns into the literal '1700' without reporting anything.
846  // The server rejects the save either way; the card names them first so it is not a round trip.
847  self.missingAccountDefaults = ko.computed(function() {
848    return self.accountDefaults().filter(function(row) {
849      return row.isMissing();
850    });
851  });
852
853  self.missingAccountDefaultsText = ko.computed(function() {
854    var labels = self.missingAccountDefaults().map(function(row) {
855      return row.label;
856    });
857
858    if (!labels.length) {
859      return '';
860    }
861
862    return 'Nämä tilit ovat pakollisia eikä niitä voi jättää tyhjäksi: ' + labels.join(', ');
863  });
864
865  self.canSaveAccountDefaults = ko.computed(function() {
866    return self.editableRows() && self.dirtyAccountDefaults().length > 0;
867  });
868
869  //@ai:claude canRegenerate/regenerateBlockedText/regenerateConfigs are gone with the "Luo
870  //transaktiokohtaiset asetukset" button - there is no materialized table to rebuild, the
871  //transaction config table always shows what the saved accounts currently generate.
872
873  /**
874   * @ai:claude All four are submitted every time, so an unticked checkbox is a value rather than an
875   * omission - the writer reads them that way.
876   */
877  self.savePreferences = function() {
878    self.post(
879      'saveAccountingPreferences',
880      {
881        automatic_reconciliation: self.preferences.automaticReconciliation() ? 1 : 0,
882        max_reconciliation_amount: self.preferences.maxReconciliationAmount(),
883        bank_statement: self.preferences.bankStatement() ? 1 : 0,
884        block_eu_sales: self.preferences.blockEuSales() ? 1 : 0,
885      },
886      null
887    );
888  };
889
890  self.saveDimensionLink = function(link) {
891    self.post('saveAccountingDimensionLink', link.toPayload(), 'Dimensio tallennettu');
892  };
893
894  self.deleteDimensionLink = function(link) {
895    if (!link.id()) {
896      self.dimensionLinks.remove(link);
897      return;
898    }
899
900    self.post('deleteAccountingDimensionLink', { id: link.id() }, 'Dimensio poistettu');
901  };
902
903  self.addDimensionLink = function() {
904    self.dimensionLinks.push(new AccountingSettingsVm.DimensionLink(self, {}));
905  };
906
907  self.refreshLookup = function(lookupType) {
908    self.post('refreshAccountingLookup', { lookup_type: lookupType }, 'Lista haettu Procountorista');
909  };
910
911  // @ai:claude Two call shapes. omat_tiedot passes the server payload straight in, because there the
912  // company is always the session one and the endpoints live on this controller. The account card
913  // passes { baseUrl, adminMode, data } instead, because there the company being configured is not
914  // the session company and the endpoints have to carry its id.
915  if (opts) {
916    var payload = opts;
917
918    if (opts.baseUrl || opts.adminMode || Object.prototype.hasOwnProperty.call(opts, 'data')) {
919      if (opts.baseUrl) {
920        self.baseUrl = opts.baseUrl;
921      }
922
923      self.adminMode(!!opts.adminMode);
924      payload = opts.data;
925    }
926
927    self.setData(payload);
928  }
929};
930
931/**
932 * @ai:claude One row of the "Oletus tilit" card.
933 *
934 * ## Why this no longer saves on its own `change` event (2026-09-15)
935 *
936 * It used to. Picking a value - including the "Ei asetettu" entry - posted immediately, which made
937 * blanking an account a single click with no confirmation and no undo. Blanking Myyntisaamiset on
938 * company 521 that way propagated NULL into 35 generated cells, and nothing downstream then
939 * complained: a NULL account reaches TransactionAdapter, which quietly substitutes '1700'. The card
940 * is saved as a whole now, behind "Tallenna muutokset", so there is something to not press.
941 *
942 * `savedAccount` is the server's copy and `account` the edited one; the difference is what makes the
943 * row dirty. Nothing is patched locally on save - the server replies with the whole page and
944 * setData() rebuilds these rows, which is what puts the two back in step.
945 */
946AccountingSettingsVm.AccountDefault = function(vm, data) {
947  var self = this;
948
949  self.key = data.key;
950  self.label = data.label;
951  self.side = data.side || null;
952  self.group = data.group || null;
953  self.description = data.description || '';
954  self.inheritsFromLabel = data.inheritsFromLabel || null;
955  // Blank is a complete answer for a field that inherits, and for the selvittelytili. For everything
956  // else it generates a NULL cell, so the card marks it and the save button refuses to submit it.
957  self.required = data.required !== false;
958
959  self.account = ko.observable(data.account === null ? '' : data.account || '');
960  self.savedAccount = self.account();
961
962  // What generation would actually write. For a blank inheriting field that is the parent's account,
963  // which is why the row can show "peritään 3021" next to an empty input rather than looking unset.
964  self.effectiveAccount = ko.observable(data.effectiveAccount || '');
965  self.isInheriting = ko.observable(!!data.isInheriting);
966
967  self.editable = vm.editableRows;
968
969  self.isDirty = ko.computed(function() {
970    return self.account() !== self.savedAccount;
971  });
972
973  self.isMissing = ko.computed(function() {
974    return self.required && self.account() === '';
975  });
976};
977
978//@ai:claude AccountingSettingsVm.DeductionVariant is gone. It carried the editable ALV-käsittely
979//and the "do the eight rows agree?" reporting for one deduction variant; there are no deduction
980//config rows to disagree and no status to choose, so section 3 renders vm.deductionKinds - plain
981//objects from the catalogue - as static text.
982
983/**
984 * @ai:claude One pick-list - just dimensions today. Nothing is cached server-side any more: every
985 * page load starts as `fallback: true, items: []`, and only pressing "Päivitä" (refresh()) fills it
986 * in for this view, unsaved.
987 */
988AccountingSettingsVm.Lookup = function(vm, type, label) {
989  var self = this;
990
991  self.type = type;
992  self.label = ko.observable(label);
993  self.items = ko.observableArray([]);
994  self.fetchedAt = ko.observable(null);
995  self.fetchable = ko.observable(false);
996  self.fallback = ko.observable(true);
997  self.warning = ko.observable(null);
998
999  /**
1000   * @ai:claude Nothing is cached server-side any more (see ProcountorLookups) - every write posts
1001   * one row and reads the whole page back, and every type but the one refreshAccountingLookup() just
1002   * fetched comes back in that reply as "never fetched". Without a client-side copy, saving a single
1003   * dimension link would wipe the fetched list back to free text on every save. Keyed by company so
1004   * two companies sharing a browser never see each other's cached list.
1005   *
1006   * sessionStorage rather than localStorage: dimension names/items may carry personal data, and this
1007   * bounds how long it sits in the browser to the current tab's lifetime instead of indefinitely.
1008   */
1009  self.storageKey = function() {
1010    return 'iv.accountingLookup.' + vm.companyId() + '.' + type;
1011  };
1012
1013  self.cacheItems = function(items, fetchedAt) {
1014    try {
1015      sessionStorage.setItem(self.storageKey(), JSON.stringify({ items: items, fetchedAt: fetchedAt }));
1016    } catch (e) {
1017      // Private browsing or storage disabled - the fetched list just won't survive a save
1018    }
1019  };
1020
1021  self.loadCachedItems = function() {
1022    try {
1023      var raw = sessionStorage.getItem(self.storageKey());
1024      return raw ? JSON.parse(raw) : null;
1025    } catch (e) {
1026      return null;
1027    }
1028  };
1029
1030  self.setData = function(data) {
1031    if (!data) {
1032      return;
1033    }
1034
1035    self.label(data.label || label);
1036    self.fetchable(!!data.fetchable);
1037
1038    // A real fetch (the refresh button's own response) - cache it so the next unrelated save can
1039    // restore it. Anything else that comes back with items is already a restore, not a new fetch.
1040    if (!data.fallback && (data.items || []).length) {
1041      self.cacheItems(data.items, data.fetchedAt);
1042      self.items(data.items);
1043      self.fetchedAt(data.fetchedAt || null);
1044      self.fallback(false);
1045      self.warning(null);
1046      return;
1047    }
1048
1049    var cached = data.fallback ? self.loadCachedItems() : null;
1050
1051    if (cached) {
1052      self.items(cached.items || []);
1053      self.fetchedAt(cached.fetchedAt || null);
1054      self.fallback(false);
1055      self.warning(null);
1056      return;
1057    }
1058
1059    self.items(data.items || []);
1060    self.fetchedAt(data.fetchedAt || null);
1061    self.fallback(!!data.fallback);
1062    self.warning(data.warning || null);
1063  };
1064
1065  // @ai:claude Three states, not two. A list with no endpoint behind it reads as "kiinteä lista"
1066  // rather than "ei haettu kertaakaan", because the latter invites the reader to go and fetch it -
1067  // and there is nothing to press.
1068  self.fetchedAtText = ko.computed(function() {
1069    if (self.fetchedAt()) {
1070      return 'Haettu ' + self.fetchedAt();
1071    }
1072
1073    return self.fetchable() ? 'Ei haettu kertaakaan' : 'Kiinteä lista';
1074  });
1075
1076  self.canRefresh = ko.computed(function() {
1077    return self.fetchable() && vm.canEdit() && !vm.busy();
1078  });
1079
1080  self.refresh = function() {
1081    vm.refreshLookup(self.type);
1082  };
1083};
1084
1085/** One transaction type and its variants. Always fully generated - there is no disabled state. */
1086AccountingSettingsVm.Type = function(vm, data, section) {
1087  var self = this;
1088
1089  self.type = data.type;
1090  self.openKey = section + ':' + data.type;
1091  self.label = data.label;
1092  self.ledgerType = data.ledgerType;
1093  self.deprecated = !!data.deprecated;
1094  self.carriesVatStatus = data.carriesVatStatus !== false;
1095
1096  self.variants = ko.observableArray(
1097    (data.variants || []).map(function(variant) {
1098      return new AccountingSettingsVm.ConfigRow(vm, self, variant);
1099    })
1100  );
1101
1102  self.defaultRow = ko.computed(function() {
1103    var rows = self.variants().filter(function(row) {
1104      return row.isDefault;
1105    });
1106
1107    return rows.length ? rows[0] : null;
1108  });
1109
1110  // Nothing is configured at all - the required default it needs is blank - worth calling out on
1111  // the collapsed header instead of only inside the panel
1112  self.isUnconfigured = ko.computed(function() {
1113    var row = self.defaultRow();
1114
1115    return !row || !row.debitAccount() || !row.creditAccount();
1116  });
1117
1118  self.editable = vm.editableRows;
1119
1120  self.isOpen = ko.observable(!!vm.openTypes[self.openKey]);
1121
1122  self.toggle = function() {
1123    self.isOpen(!self.isOpen());
1124    vm.openTypes[self.openKey] = self.isOpen();
1125  };
1126};
1127
1128/** One (transaction type, variant) row: the two accounts and the VAT status posted with them */
1129AccountingSettingsVm.ConfigRow = function(vm, type, data) {
1130  var self = this;
1131
1132  self.type = type;
1133  self.transactionType = data.transactionType;
1134  self.variant = data.variant;
1135  self.label = data.label;
1136  self.isDefault = data.variant === 'default';
1137  // reconciliation_row posts through ReconciliationAdapter, which has no vatStatus at all
1138  self.carriesVatStatus = type.carriesVatStatus;
1139
1140  self.debitAccount = ko.observable(data.debitAccount === null ? '' : data.debitAccount || '');
1141  self.creditAccount = ko.observable(data.creditAccount === null ? '' : data.creditAccount || '');
1142  self.vatStatus = ko.observable(
1143    data.vatStatus === null || typeof data.vatStatus === 'undefined' ? '' : String(data.vatStatus)
1144  );
1145
1146  /**
1147   * @ai:claude The three cells as text. The row is display only - it is generated from the Oletus
1148   * tilit card, and the way to change it is to change a default and save the card. There is no
1149   * chart-of-accounts lookup any more to turn a code into "code - name", so this is just the bare
1150   * value, or "Ei asetettu" when the row has none.
1151   */
1152  self.debitAccountText = ko.computed(function() {
1153    return self.debitAccount() || 'Ei asetettu';
1154  });
1155
1156  self.creditAccountText = ko.computed(function() {
1157    return self.creditAccount() || 'Ei asetettu';
1158  });
1159
1160  self.vatStatusText = ko.computed(function() {
1161    return self.vatStatus() || 'Ei asetettu';
1162  });
1163};
1164
1165/**
1166 * One entity-to-dimension-item mapping. `isDefault` additionally makes its item the one used when a
1167 * ledger row's entity cannot be resolved - a flag on the mapping, which keeps resolving its entity.
1168 */
1169AccountingSettingsVm.DimensionLink = function(vm, data) {
1170  var self = this;
1171
1172  self.id = ko.observable(data.id || null);
1173  self.entityType = ko.observable(data.entityType || 'station');
1174  self.entityId = ko.observable(data.entityId === null ? '' : data.entityId || '');
1175  self.entityName = ko.observable(data.entityName || null);
1176  // @ai:claude Left as the numbers the payload carries rather than stringified. Knockout matches a
1177  // select's value against the option object's own value with ===, and the dimension and item ids
1178  // come back from json_encode as numbers - a string here would match nothing, select the empty
1179  // placeholder and write the id away.
1180  self.dimensionId = ko.observable(data.dimensionId ? data.dimensionId : '');
1181  self.dimensionName = ko.observable(data.dimensionName || '');
1182  self.itemId = ko.observable(data.itemId ? data.itemId : '');
1183  self.itemCodeName = ko.observable(data.itemCodeName || '');
1184  self.itemDescription = ko.observable(data.itemDescription || '');
1185  self.isDefault = ko.observable(!!data.isDefault);
1186
1187  self.isNew = ko.computed(function() {
1188    return !self.id();
1189  });
1190
1191  // @ai:claude A saved row opens locked - every field disabled - so an accidental click in a filled
1192  // table does not nudge a working mapping. "Muokkaa" is the only way in; a successful save rebuilds
1193  // every row from scratch (setData()), which drops this back to locked on its own.
1194  self.editingSaved = ko.observable(false);
1195
1196  self.entityTypeOptions = vm.entityTypeOptions;
1197  self.dimensionOptions = vm.dimensionOptions;
1198  self.dimensionsAreFreeText = vm.dimensionsAreFreeText;
1199
1200  // The page-level permission, for buttons whose availability must not depend on this row's own
1201  // lock state - Poista and Muokkaa both need to work on a row that is currently locked
1202  self.canEditRows = vm.editableRows;
1203
1204  // Field-level: a new row is editable outright, a saved one only once Muokkaa has been pressed
1205  self.editable = ko.computed(function() {
1206    return vm.editableRows() && (self.isNew() || self.editingSaved());
1207  });
1208
1209  self.showEditButton = ko.computed(function() {
1210    return !self.isNew() && !self.editingSaved();
1211  });
1212
1213  self.edit = function() {
1214    self.editingSaved(true);
1215  };
1216
1217  /**
1218   * @ai:claude The entities this row can point at, for its own entity type. Only stations exist as
1219   * a list today; an unknown type gets the empty entry alone rather than a station list that would
1220   * mean something else.
1221   *
1222   * A row whose entity is no longer in the list - a deleted station - has it appended, because
1223   * Knockout's value binding writes the first option back into the observable when the current one
1224   * matches nothing, which would silently repoint the mapping at another station on save.
1225   *
1226   * entityId is peeked, not read: this list is the option source for the very select that writes it,
1227   * so subscribing to it would rebuild the options on every pick. Peeking leaves the appended entry
1228   * in place after the user moves off it, which costs one stale option and no correctness.
1229   */
1230  self.entityOptions = ko.computed(function() {
1231    if (self.entityType() !== 'station') {
1232      return [{ id: '', name: 'Valitse kohde' }];
1233    }
1234
1235    var options = vm.stations();
1236    var entityId = self.entityId.peek();
1237
1238    var known = options.some(function(station) {
1239      return String(station.id) === String(entityId);
1240    });
1241
1242    if (!entityId || known) {
1243      return options;
1244    }
1245
1246    return options.concat([
1247      { id: entityId, name: (self.entityName() || 'Toimipiste #' + entityId) + ' (poistettu)' },
1248    ]);
1249  });
1250
1251  // Only an oletusarvo row is allowed to map nothing, so the card says so where the choice is made
1252  self.entityIsUnset = ko.computed(function() {
1253    return !self.entityId();
1254  });
1255
1256  /** The items of the currently selected dimension, empty when the list has never been fetched */
1257  self.itemOptions = ko.computed(function() {
1258    var dimensionId = self.dimensionId();
1259
1260    var matching = vm.dimensionOptions().filter(function(dimension) {
1261      return String(dimension.id) === String(dimensionId);
1262    });
1263
1264    return [{ itemId: '', name: 'Valitse dimensioarvo' }].concat(
1265      matching.length ? matching[0].items : []
1266    );
1267  });
1268
1269  // Only the placeholder entry: the dimension list has never been fetched, or the chosen dimension
1270  // carries no items, so the id and name are typed in by hand
1271  self.itemsAreFreeText = ko.computed(function() {
1272    return self.itemOptions().length <= 1;
1273  });
1274
1275  /**
1276   * @ai:claude A saved link shows its plain id/name fields always, fetched list or not - the same
1277   * shape whether or not anyone has pressed "Päivitä" this page view, and with no risk of the select
1278   * silently overwriting a saved id that is not in whatever the list happens to hold right now (a
1279   * renamed or deleted dimension/item, or simply a page view where the list was never fetched). Only
1280   * a row still being created gets the picker, and only once the list actually has something to pick
1281   * from.
1282   */
1283  self.showDimensionDropdown = ko.computed(function() {
1284    return self.isNew() && !self.dimensionsAreFreeText();
1285  });
1286
1287  self.showItemDropdown = ko.computed(function() {
1288    return self.isNew() && !self.itemsAreFreeText();
1289  });
1290
1291  // @ai:claude Keeps the denormalised names in step with the ids whenever the user picks from a
1292  // fetched list. They are stored on the row so a mapping still reads sensibly after the dimension
1293  // is renamed or the lookup goes unavailable, which means something has to maintain them.
1294  self.dimensionId.subscribe(function(dimensionId) {
1295    // The empty id is the placeholder option, which names nothing worth copying over
1296    if (!dimensionId) {
1297      return;
1298    }
1299
1300    var matching = vm.dimensionOptions().filter(function(dimension) {
1301      return String(dimension.id) === String(dimensionId);
1302    });
1303
1304    if (matching.length) {
1305      self.dimensionName(matching[0].name);
1306    }
1307  });
1308
1309  self.itemId.subscribe(function(itemId) {
1310    if (!itemId) {
1311      return;
1312    }
1313
1314    var matching = self.itemOptions().filter(function(item) {
1315      return String(item.itemId) === String(itemId);
1316    });
1317
1318    if (matching.length) {
1319      self.itemCodeName(matching[0].name);
1320      self.itemDescription(matching[0].description || '');
1321    }
1322  });
1323
1324  self.toPayload = function() {
1325    return {
1326      id: self.id() || '',
1327      entity_type: self.entityType(),
1328      entity_id: self.entityId(),
1329      dimension_id: self.dimensionId(),
1330      dimension_name: self.dimensionName(),
1331      item_id: self.itemId(),
1332      item_code_name: self.itemCodeName(),
1333      item_description: self.itemDescription(),
1334      is_default: self.isDefault() ? 1 : 0,
1335    };
1336  };
1337
1338  self.save = function() {
1339    vm.saveDimensionLink(self);
1340  };
1341
1342  self.remove = function() {
1343    vm.deleteDimensionLink(self);
1344  };
1345};
1346
1347;var UserSettingsVm = function (opts) {
1348  'use strict';
1349  var self = this;
1350  self.isPartner = opts.isPartner;
1351  self.userGroups = ko.observableArray(opts.userGroups);
1352  self.users = ko.observableArray(opts.users);
1353  
1354  self.workers = ko.observableArray(opts.workers);
1355  self.supervisors = ko.observableArray(opts.supervisors);
1356  self.editUserId = ko.observable(null);
1357  self.userCompanies = ko.observableArray([]);
1358  self.relatedCompanies = ko.observableArray([]);
1359  self.relatedCompaniesFilter = ko.observable('');
1360  self.selectedCompaniesFilter = ko.observable('');
1361  self.currentUserId = opts.currentUserId;
1362
1363  // @ai:claude The Procountor accounting settings tab. It hangs off this view model rather than
1364  // being bound on its own because ko.applyBindings(VM, $('#omat_tiedot_tabs')[0]) already binds the
1365  // whole tab container, and a second applyBindings inside an already-bound element throws.
1366  // opts.accounting is null whenever the tab is not shown, which AccountingSettingsVm handles.
1367  self.accounting = new AccountingSettingsVm(opts.accounting);
1368
1369  self.inactiveShowActiveText = 'Näytä vain aktiiviset käyttäjät';
1370  self.inactiveShowAllText = 'Näytä kaikki käyttäjät'
1371  self.hideInactiveUsers = ko.observable(false);
1372  self.hideInactiveUsersText = ko.observable(self.inactiveShowActiveText);
1373  self.hideInactiveSupervisors = ko.observable(false);
1374  self.hideInactiveSupervisorsText = ko.observable(self.inactiveShowActiveText);
1375  self.hideInactiveWorkers = ko.observable(false);
1376  self.hideInactiveWorkersText = ko.observable(self.inactiveShowActiveText);
1377  
1378  self.toggleInactiveUsers = function () {
1379    if (self.hideInactiveUsers()) {
1380      self.hideInactiveUsers(false);
1381      self.hideInactiveUsersText(self.inactiveShowActiveText);
1382    } else {
1383      self.hideInactiveUsers(true);
1384      self.hideInactiveUsersText(self.inactiveShowAllText);
1385    }
1386  };
1387
1388  self.toggleInactiveSupervisors = function () {
1389    if (self.hideInactiveSupervisors()) {
1390      self.hideInactiveSupervisors(false);
1391      self.hideInactiveSupervisorsText(self.inactiveShowActiveText);
1392    } else {
1393      self.hideInactiveSupervisors(true);
1394      self.hideInactiveSupervisorsText(self.inactiveShowAllText);
1395    }
1396  };
1397
1398  self.toggleInactiveWorkers = function () {
1399    if (self.hideInactiveWorkers()) {
1400      self.hideInactiveWorkers(false);
1401      self.hideInactiveWorkersText(self.inactiveShowActiveText);
1402    } else {
1403      self.hideInactiveWorkers(true);
1404      self.hideInactiveWorkersText(self.inactiveShowAllText);
1405    }
1406  };
1407
1408  self.userGroupEditable = function (groupId) {
1409    if (!groupId) return true;
1410    return (
1411      self.userGroups().filter(function (v) {
1412        return v.id === parseInt(groupId);
1413      }).length > 0
1414    );
1415  };
1416
1417  self.canEditDisable = function (user) {
1418    return user.user_id === self.currentUserId;
1419  };
1420  
1421  self.hideUser  = function (el, user, type) {
1422
1423    var userId = type === 'user' && user.user_id ? user.user_id : user.id;
1424    
1425    var isChecked = $(el).prop("checked");
1426    var salesName = user.sales_name;
1427    var url = '/omat_tiedot/hideUser';
1428    var isLoading = false;
1429
1430    $('#disableText').html(
1431        `Vahvista käyttäjän <strong>${salesName}</strong> ${isChecked  ? 'sulku' : 'aktivointi'}`
1432    );
1433
1434    $('#disableUserDialog').dialog({
1435      resizable: false,
1436      height: 'auto',
1437      closeOnEscape: false,
1438      width: 400,
1439      modal: true,
1440      open: function () {
1441        $('.ui-icon-closethick').parent('a').hide();
1442      },
1443      close: function(){
1444        console.log('Close function ran');
1445        $(this).dialog("close");
1446        isChecked = $(el).prop("checked");
1447        $(el).prop('checked', ! isChecked);
1448      },
1449      buttons: {
1450        Vahvista: function () {
1451          
1452          if(isLoading){
1453             return false;
1454          }
1455          
1456          jQuery
1457              .ajax({
1458                type: 'post',
1459                url: url,
1460                data: { userId: userId, hidden: (+ isChecked) },
1461                beforeSend(jqXHR, settings) {
1462                  isLoading = true;
1463                }
1464              })
1465              .then(function (response) {
1466                
1467                var msg = response.text || 'Käyttäjä muokattu';
1468                var action = msg.action || 'muokattu';
1469                var isHidden = msg.hidden;
1470                
1471                $('#disableText').text(msg.sales_name + ' ' + action);
1472                
1473                var updatedUser =  Object.assign({}, user, { hidden: isHidden });
1474
1475                console.log('action:', action);
1476                console.log('isHidden:', isHidden);
1477          //     console.log('user:', user);
1478          //     console.log('updateUser:', updatedUser);
1479
1480                $('#disableUserDialog').dialog("option", "buttons", {
1481                  "Sulje": function(){
1482                    $('#disableUserDialog').dialog('destroy');
1483                  }
1484                });
1485                
1486                self.replaceUserData(type, user, updatedUser);
1487                
1488              })
1489              .fail(function (response) {
1490                
1491                var msg = response.text || 'Toimintoa ei voitu suorittaa';
1492                $('#disableText').text(msg);
1493              });
1494        },
1495        Peruuta: function () {
1496
1497          if(isLoading)
1498            return false;
1499
1500          $(this).dialog("close");
1501        },
1502      },
1503    });
1504  };
1505
1506
1507  self.disableUser = function (el, user, type) {
1508    
1509    var userId = type === 'user' && user.user_id ? user.user_id : user.id;
1510    
1511    var isChecked =  $(el).prop("checked");
1512    var salesName = user.sales_name;
1513    var disabled = isChecked;
1514    var isLoading = false;
1515    
1516    var url = '/omat_tiedot/disableUser';
1517    
1518    $('#disableText').html(
1519      `Vahvista käyttäjän <strong>${salesName}</strong> ${isChecked ? 'sulku' : 'aktivointi'}`
1520    );
1521
1522    $('#disableUserDialog').dialog({
1523      resizable: false,
1524      height: 'auto',
1525      closeOnEscape: false,
1526      width: 400,
1527      modal: true,
1528      open: function () {
1529        $('.ui-icon-closethick').parent('a').hide();
1530      },
1531      close: function(){
1532        console.log('Close function ran');
1533        $(this).dialog("close");
1534        isChecked = $(el).prop("checked");
1535        $(el).prop('checked', ! isChecked);
1536      },
1537      buttons: {
1538        Vahvista: function () {
1539
1540          if(isLoading){
1541            return false;
1542          }
1543          
1544          jQuery
1545            .ajax({
1546              type: 'post',
1547              url: url,
1548              data: { userId: userId, disabled: (+ disabled)},
1549              
1550            })
1551            .then(function (response) {
1552              
1553              var msg = response.text || 'Käyttäjä muokattu';
1554              var action = msg.action || 'muokattu';
1555              var isDisabled = msg.disabled;
1556              $('#disableText').text(msg.sales_name + ' ' + action);
1557              
1558              var updateUser = Object.assign({}, user, { disabled: isDisabled });
1559              
1560              $('#disableUserDialog').dialog("option", "buttons", {
1561                "Sulje": function(){
1562                  $('#disableUserDialog').dialog('destroy');
1563                }
1564              });
1565              
1566              self.replaceUserData(type, user, updateUser);
1567              
1568            })
1569            .fail(function (response) {
1570              var msg = response.text || 'Toimintoa ei voitu suorittaa';
1571              $('#disableText').text(msg);
1572            });
1573        },
1574        Peruuta: function () {
1575
1576          if(isLoading)
1577            return false;
1578
1579          $(this).dialog("close");
1580        },
1581      },
1582    });
1583  };
1584
1585  self.newWorker = {
1586    name: ko.observable(''),
1587    extId: ko.observable(''),
1588  };
1589
1590  self.resetNewWorker = function () {
1591    self.newWorker.name('');
1592    self.newWorker.extId('');
1593  };
1594
1595  self.newSupervisor = {
1596    userName: ko.observable(''),
1597    email: ko.observable(''),
1598    name: ko.observable(''),
1599    extId: ko.observable(''),
1600  };
1601
1602  self.resetNewSupervisor = function () {
1603    self.newSupervisor.userName('');
1604    self.newSupervisor.email('');
1605    self.newSupervisor.name('');
1606    self.newSupervisor.extId('');
1607  };
1608
1609  self.newUser = {
1610    username: ko.observable(''),
1611    email: ko.observable(''),
1612    usergroup_id: ko.observable(''),
1613    sales_name: ko.observable(''),
1614  };
1615
1616  self.resetNewUser = function () {
1617    self.newUser.username('');
1618    self.newUser.email('');
1619    self.newUser.usergroup_id('');
1620    self.newUser.sales_name('');
1621  };
1622
1623  self.showAddUserModal = function () {
1624    $('#addUserModal').modal('show');
1625  };
1626
1627  self.showAddWorkerModal = function () {
1628    global.showLoadingDialog('Haetaan toimipaikkoja...');
1629    jQuery
1630      .ajax({
1631        url: '/omat_tiedot/getRelatedCompanies/',
1632        dataType: 'json',
1633      })
1634      .done(function (response) {
1635        global.close_loading_dialog();
1636        self.setCompanySelectModalData(response.data);
1637        $('#addWorkerModal').modal('show');
1638      })
1639      .fail(function (response) {
1640        global.close_loading_dialog();
1641        global.show_message(response.responseJSON);
1642      });
1643  };
1644
1645  self.showAddSupervisorModal = function () {
1646    global.showLoadingDialog('Haetaan toimipaikkoja...');
1647    jQuery
1648      .ajax({
1649        url: '/omat_tiedot/getRelatedCompanies/',
1650        dataType: 'json',
1651      })
1652      .done(function (response) {
1653        global.close_loading_dialog();
1654        self.setCompanySelectModalData(response.data);
1655        $('#addSupervisorModal').modal('show');
1656      })
1657      .fail(function (response) {
1658        global.close_loading_dialog();
1659        global.show_message(response.responseJSON);
1660      });
1661  };
1662
1663  self.showUserRelatedCompaniesModal = function (userId) {
1664    global.showLoadingDialog('Haetaan toimipaikkoja...');
1665    jQuery
1666      .ajax({
1667        url: '/omat_tiedot/getRelatedCompanies/'.concat(userId),
1668        dataType: 'json',
1669      })
1670      .done(function (response) {
1671        global.close_loading_dialog();
1672        self.setCompanySelectModalData(response.data);
1673        self.editUserId(userId);
1674        $('#companySelectModal').modal('show');
1675      })
1676      .fail(function (response) {
1677        global.close_loading_dialog();
1678        global.show_message(response.responseJSON);
1679      });
1680  };
1681
1682  $('#companySelectModal, #addUserModal, #addSupervisorModal, #addWorkerModal').on('hidden.bs.modal', function () {
1683    self.editUserId(null);
1684    self.relatedCompaniesFilter('');
1685    self.selectedCompaniesFilter('');
1686    self.resetNewWorker();
1687    self.resetNewSupervisor();
1688    self.resetNewUser();
1689  });
1690
1691  self.setCompanySelectModalData = function (data) {
1692    self.userCompanies(data.userCompanies);
1693    self.relatedCompanies(data.relatedCompanies);
1694  };
1695  self.removeCompany = function (company) {
1696    self.userCompanies.remove(company);
1697    self.relatedCompanies.push(company);
1698  };
1699
1700  self.addCompany = function (company) {
1701    self.relatedCompanies.remove(company);
1702    self.userCompanies.push(company);
1703  };
1704
1705  self.relatedCompaniesFilter.subscribe(function () {
1706    var filterText = self.relatedCompaniesFilter();
1707    $('#related_companies button').show();
1708    if (filterText != '') {
1709      $('#related_companies button').filter(function () {
1710        var btn = $(this).text();
1711        if (!btn.includes(filterText)) {
1712          $(this).hide();
1713        }
1714      });
1715    }
1716  });
1717
1718  self.selectedCompaniesFilter.subscribe(function () {
1719    var filterText = self.selectedCompaniesFilter();
1720    $('#user_companies button').show();
1721    if (filterText != '') {
1722      $('#user_companies button').filter(function () {
1723        var btn = $(this).text();
1724        if (!btn.includes(filterText)) {
1725          $(this).hide();
1726        }
1727      });
1728    }
1729  });
1730
1731  self.saveUserCompanies = function () {
1732    if (!self.editUserId()) {
1733      JSON = {
1734        type: 'error',
1735        title: 'Virhe',
1736        text: 'Virheellinen käyttäjä',
1737      };
1738      global.show_message(JSON);
1739      return;
1740    }
1741    if (self.userCompanies().length === 0) {
1742      JSON = {
1743        type: 'error',
1744        title: 'Virhe',
1745        text: 'Käyttäjän pitää kuulua vähintään yhteen toimipaikkaan',
1746      };
1747      global.show_message(JSON);
1748      return;
1749    }
1750    var data = {
1751      userCompanies: ko.toJS(self.userCompanies),
1752      relatedCompanies: ko.toJS(self.relatedCompanies),
1753    };
1754    global.showLoadingDialog('Tallennetaan...');
1755    jQuery
1756      .ajax({
1757        type: 'post',
1758        url: '/omat_tiedot/saveRelatedCompanies/'.concat(self.editUserId()),
1759        dataType: 'json',
1760        data: data,
1761      })
1762      .done(function (response) {
1763        global.close_loading_dialog();
1764        self.setCompanySelectModalData(response.data);
1765        self.showSuccessMessage('Tallennettu', 'Käyttäjän toimipaikat tallennettu');
1766      })
1767      .fail(function (response) {
1768        global.close_loading_dialog();
1769        global.show_message(response.responseJSON);
1770      });
1771  };
1772
1773  self.saveNewUser = function () {
1774    if (!self.newUser.username() || self.newUser.username().trim == '') {
1775      self.showErrorMessage('Virheellinen käyttäjätunnus');
1776      return;
1777    }
1778    if (!self.newUser.email() || self.newUser.email().trim == '') {
1779      self.showErrorMessage('Virheellinen käyttäjän sähköposti');
1780      return;
1781    }
1782    if (!self.newUser.usergroup_id() || self.newUser.usergroup_id().trim == '') {
1783      self.showErrorMessage('Virheellinen käyttäjätaso');
1784      return;
1785    }
1786    if (!self.newUser.sales_name() || self.newUser.sales_name().trim == '') {
1787      self.showErrorMessage('Virheellinen käyttäjän nimi');
1788      return;
1789    }
1790
1791    var data = {
1792      newUser: ko.toJS(self.newUser),
1793    };
1794    global.showLoadingDialog('Tallennetaan...');
1795    jQuery
1796      .ajax({
1797        type: 'post',
1798        url: '/omat_tiedot/saveNewUser/',
1799        dataType: 'json',
1800        data: data,
1801      })
1802      .done(function (response) {
1803        global.close_loading_dialog();
1804        self.users(response.data.users);
1805        $('#addUserModal').modal('hide');
1806        self.showSuccessMessage('Käyttäjä tallennettu', 'Uuden käyttäjän lisäys onnistui');
1807      })
1808      .fail(function (response) {
1809        global.close_loading_dialog();
1810        global.show_message(response.responseJSON);
1811      });
1812  };
1813
1814  self.saveNewWorker = function () {
1815    if (!self.newWorker.name() || self.newWorker.name().trim == '') {
1816      self.showErrorMessage('Virheellinen käyttäjän nimi');
1817      return;
1818    }
1819    if (!self.newWorker.extId() || self.newWorker.extId().trim == '') {
1820      self.showErrorMessage('Virheellinen käyttäjän Mepco-ID');
1821      return;
1822    }
1823    if (self.userCompanies().length === 0 && !self.isPartner) {
1824      self.showErrorMessage('Käyttäjän pitää kuulua vähintään yhteen toimipaikkaan');
1825      return;
1826    }
1827    var url = self.isPartner ? '/omat_tiedot/newWorkerForCompany/' : '/omat_tiedot/newWorkerForCompanyGroup/';
1828    var data = {
1829      userCompanies: ko.toJS(self.userCompanies),
1830      newWorker: ko.toJS(self.newWorker),
1831    };
1832    global.showLoadingDialog('Tallennetaan...');
1833    jQuery
1834      .ajax({
1835        type: 'post',
1836        url: url,
1837        dataType: 'json',
1838        data: data,
1839      })
1840      .done(function (response) {
1841        global.close_loading_dialog();
1842        self.workers(response.data.workers);
1843        $('#addWorkerModal').modal('hide');
1844        self.showSuccessMessage('Käyttäjä tallennettu', 'Uuden käyttäjän lisäys onnistui');
1845      })
1846      .fail(function (response) {
1847        var errorResponse = response.responseJSON ? response.responseJSON : JSON.parse(response.responseText);
1848        global.close_loading_dialog();
1849        global.show_message(errorResponse);
1850      });
1851  };
1852
1853  self.saveNewSupervisor = function () {
1854    if (!self.newSupervisor.userName() || self.newSupervisor.userName().trim == '') {
1855      self.showErrorMessage('Virheellinen käyttäjän käyttäjätunnus');
1856      return;
1857    }
1858    if (!self.newSupervisor.email() || self.newSupervisor.email().trim == '') {
1859      self.showErrorMessage('Virheellinen käyttäjän sähköpostiosoite');
1860      return;
1861    }
1862    if (!self.newSupervisor.name() || self.newSupervisor.name().trim == '') {
1863      self.showErrorMessage('Virheellinen käyttäjän nimi');
1864      return;
1865    }
1866    if (!self.newSupervisor.extId() || self.newSupervisor.extId().trim == '') {
1867      self.showErrorMessage('Virheellinen käyttäjän Mepco-ID');
1868      return;
1869    }
1870    if (self.userCompanies().length === 0 && !self.isPartner) {
1871      self.showErrorMessage('Käyttäjän pitää kuulua vähintään yhteen toimipaikkaan');
1872      return;
1873    }
1874
1875    var url = self.isPartner ? '/omat_tiedot/newSupervisorForCompany/' : '/omat_tiedot/newSupervisorForCompanyGroup/';
1876    var data = {
1877      userCompanies: ko.toJS(self.userCompanies),
1878      newSupervisor: ko.toJS(self.newSupervisor),
1879    };
1880    global.showLoadingDialog('Tallennetaan...');
1881    jQuery
1882      .ajax({
1883        type: 'post',
1884        url: url,
1885        dataType: 'json',
1886        data: data,
1887      })
1888      .done(function (response) {
1889        global.close_loading_dialog();
1890        self.supervisors(response.data.supervisors);
1891        $('#addSupervisorModal').modal('hide');
1892        self.showSuccessMessage('Käyttäjä tallennettu', 'Uuden käyttäjän lisäys onnistui');
1893      })
1894      .fail(function (response) {
1895        var errorResponse = response.responseJSON ? response.responseJSON : JSON.parse(response.responseText);
1896        global.close_loading_dialog();
1897        global.show_message(errorResponse);
1898      });
1899  };
1900
1901  self.updateUsers = function () {
1902    self.updateCompanyUsers(ko.toJS(self.users), 'users');
1903  };
1904
1905  self.updateWorkers = function () {
1906    var workersData = self.workers().map(function (row) {
1907      row.user_id = row.id;
1908      return row;
1909    });
1910    self.updateCompanyUsers(workersData, 'workers');
1911  };
1912
1913  self.updateSupervisors = function () {
1914    var supervisorsData = self.supervisors().map(function (row) {
1915      row.user_id = row.id;
1916      return row;
1917    });
1918    self.updateCompanyUsers(supervisorsData, 'supervisors');
1919  };
1920
1921  self.updateCompanyUsers = function (usersData, userType) {
1922    
1923    var data = { users: usersData, type: userType };
1924    global.showLoadingDialog('Tallennetaan...');
1925    jQuery
1926      .ajax({
1927        type: 'post',
1928        url: '/omat_tiedot/updateUsers/',
1929        dataType: 'json',
1930        data: data,
1931      })
1932      .done(function (response) {
1933        global.close_loading_dialog();
1934        if (userType === 'supervisors') self.supervisors(response.data.users);
1935        if (userType === 'workers') self.workers(response.data.users);
1936        if (userType === 'users') self.users(response.data.users);
1937        
1938        self.showSuccessMessage('Käyttäjät tallennettu', 'Käyttäjien tiedot päivitetty');
1939      })
1940      .fail(function (response) {
1941        global.close_loading_dialog();
1942        global.show_message(response.responseJSON);
1943      });
1944  };
1945
1946  self.resetPassword = function (user) {
1947    $('#resetText').text('Vahvista salasanan resetointi');
1948    $('#passwordResetModal').dialog({
1949      resizable: false,
1950      height: 'auto',
1951      width: 400,
1952      modal: true,
1953      buttons: {
1954        Resetoi: function () {
1955          jQuery
1956            .ajax({
1957              url: '/omat_tiedot/resetPassword',
1958              data: { userId: user.user_id ? user.user_id : user.id },
1959            })
1960            .then(function (response) {
1961              var msg = response.text || 'Salasana muutettu, ja lähettty sähköpostitse käyttäjälle';
1962              $('#resetText').text(msg);
1963              setTimeout(() => $('#passwordResetModal').dialog('close'), 2000);
1964            })
1965            .fail(function (response) {
1966              var msg = response.text || 'Salasanaa ei voitu resetoida';
1967              $('#resetText').text(msg);
1968            });
1969        },
1970        Peruuta: function () {
1971          $(this).dialog('close');
1972        },
1973      },
1974    });
1975  };
1976
1977  self.showSuccessMessage = function (title, txt) {
1978    JSON = {
1979      type: 'success',
1980      title: title,
1981      text: txt,
1982    };
1983    global.show_message(JSON);
1984  };
1985
1986  self.showErrorMessage = function (txt) {
1987    JSON = {
1988      type: 'error',
1989      title: 'Virhe',
1990      text: txt,
1991    };
1992    global.show_message(JSON);
1993  };
1994
1995  self.replaceUserData = function (type, oldVal, newVal) {
1996    switch (type) {
1997      case 'user':
1998        self.users.replace(oldVal, newVal);
1999        break;
2000      case 'worker':
2001        self.workers.replace(oldVal, newVal);
2002        break;
2003      case 'supervisor':
2004        self.supervisors.replace(oldVal, newVal);
2005        break;
2006    }
2007  };
2008};
2009
2010;/* global ko, $ */
2011const SSN_REGEX = /^(0[1-9]|[12]\d|3[01])(0[1-9]|1[0-2])([5-9]\d\+|\d\d-|[012]\dA)\d{3}[\dA-Z]$/
2012
2013const DEFAULT_CAR_TOW_USER_ACCESS_LEVEL = 3
2014const DEFAULT_USER_ACCESS_LEVEL = 2
2015const DEFAULT_CONNECTION_FEE = 139
2016
2017var selectpicker = {
2018  preprocess: function (value, name, addBindingCallback) {
2019    // add optionsCaption to the bindings against a "caption" sub-observable
2020    addBindingCallback('optionsCaption', value + '.caption');
2021    // just return the original value to allow this binding to remain as-is
2022    return value;
2023  },
2024  init: function (element, valueAccessor, allBindings) {
2025    var options = valueAccessor();
2026    var hasDisable = allBindings.get('disable');
2027    var notificationSettings =
2028      $(element).hasClass('notifications-stations-select') ||
2029      $(element).hasClass('notifications-types-select');
2030
2031    if (ko.isObservable(hasDisable)) {
2032      hasDisable.subscribe((isDisabled) => {
2033        $(element).prop('disabled', isDisabled);
2034        $(element).selectpicker('refresh');
2035      });
2036    }
2037    // create an observable to track the caption
2038    if (options && !ko.isObservable(options.caption)) {
2039      options.caption = ko.observable();
2040    }
2041    var opts = {
2042      liveSearch: true,
2043      size: 5,
2044      noneResultsText: 'Haku {0} ei tuottanut tuloksia',
2045      noneSelectedText: notificationSettings ? 'Kaikki' : 'Ei valintoja',
2046      liveSearchPlaceholder: 'Etsi nimellä',
2047    };
2048
2049    $(element).selectpicker(opts);
2050
2051    $('[data-toggle="automatic_reconciliation_tooltip"]').popover({
2052      trigger: 'hover',
2053          'placement': 'top'
2054    });
2055    $('[data-toggle="bank_statement_tooltip"]').popover({
2056      trigger: 'hover',
2057          'placement': 'top'
2058    });
2059    $('[data-toggle="service_charge_to_payment_account_tooltip"]').popover({
2060      trigger: 'hover',
2061          'placement': 'top'
2062    });
2063    $('[data-toggle="block_eu_sales_tooltip"]').popover({
2064      trigger: 'hover',
2065          'placement': 'top'
2066    });
2067
2068    return ko.bindingHandlers.options.init.apply(this, arguments);
2069  },
2070  update: function (element, valueAccessor, allBindings) {
2071    ko.bindingHandlers.options.update.apply(this, arguments);
2072    var value = allBindings.get('value');
2073    $(element).selectpicker('val', ko.unwrap(value));
2074    $(element).selectpicker('refresh');
2075  },
2076};
2077
2078ko.bindingHandlers.selectpicker = selectpicker;
2079
2080ko.extenders.uppercase = function(target, option) {
2081  target.subscribe(function(newValue) {
2082    if(newValue){
2083      target(newValue.toUpperCase());
2084    }
2085  });
2086  return target;
2087};
2088
2089function createNewShiftSettingGroup(data) {
2090  return {
2091    id: ko.observable(data.id || null),
2092    company_id: ko.observable(data.company_id || null),
2093    tes: ko.observable(data.tes || null),
2094    group_name: ko.observable(data.group_name || null),
2095    job_type: ko.observable(data.job_type || 'period'),
2096    period_start_date: ko.observable(data.period_start_date || null),
2097    period_length: ko.observable(data.period_length || 14),
2098    evening_start: ko.observable(data.evening_start || null),
2099    evening_end: ko.observable(data.evening_end || null),
2100    night_start: ko.observable(data.night_start || null),
2101    night_end: ko.observable(data.night_end || null),
2102    enable_wait: ko.observable(data.enable_wait),
2103    enable_standby: ko.observable(data.enable_standby),
2104    enable_evening: ko.observable(data.enable_evening),
2105    enable_night: ko.observable(data.enable_night),
2106    enable_overtime: ko.observable(data.enable_overtime),
2107  };
2108}
2109
2110function isValidSsn(ssn){
2111  return typeof ssn === 'string' ? /^\d{6}[+-Aa]\d{3}[a-zA-Z0-9]$/.test(ssn.trim()) : false;
2112}
2113
2114function maskedSsn(param){
2115  var ssn = ko.isObservable(param) ?  param() : param;
2116  //return typeof ssn === 'string' ?  ssn.substr(0, 7)+'****' : ssn;
2117  return isValidSsn(ssn) ? ssn.substr(0, 7)+'****' : ssn;
2118}
2119
2120function getUserLastLoggedLabel(param){
2121  var date = ko.isObservable(param) ? param() : param;
2122  var dateObj = new Date(date);
2123
2124  return dateObj != 'Invalid Date' ? 'Kirjautunut: ' + dateObj.toLocaleString('fi') : 'Käyttäjä ei ole kirjautunut palveluun';
2125}
2126
2127var AccountCardDialogVm = function () {
2128  'use strict';
2129  var self = this;
2130
2131  // Reference to jQuery ui dialog
2132  self.dialog = null;
2133  self.saving = ko.observable(false);
2134  self.saved = ko.observable(false);
2135  self.reactivatingTrial = ko.observable(false);
2136  self.toggleReactivatingTrial = function () {
2137    self.reactivatingTrial(!self.reactivatingTrial());
2138  };
2139  self.contactPersonSaved = {
2140    name: ko.observable(false),
2141    phone: ko.observable(false),
2142    ssn: ko.observable(false),
2143    email: ko.observable(false),
2144  };
2145
2146  // Static data
2147  self.autoklinikkaBranches = [];
2148  self.accountManagers = [];
2149  self.usergroups = [];
2150  self.eInvoiceOperators = [];
2151  self.workingFields = [];
2152  self.routeTypes = [
2153    { type: false, label: '4 Aikaleimaa' },
2154    { type: true, label: '6 Aikaleimaa' }
2155  ];
2156
2157  // @ai:claude Safe default so the view binding doesn't throw before account data is loaded.
2158  // bindComputedObservables() replaces this with a live ko.pureComputed once account exists.
2159  self.trialStatusBadge = ko.observable({ text: '', cls: 'label-default' });
2160
2161  // @ai:claude Trial status options matching Company::TRIAL_STATUS_* PHP constants (0–5).
2162  self.trialStatuses = [
2163    { value: 0, text: 'Luonnos' },
2164    { value: 1, text: 'Aktiivinen' },
2165    { value: 2, text: 'Vanhentunut' },
2166    { value: 3, text: 'Muuttumassa asiakkaaksi' },
2167    { value: 4, text: 'Muutettu asiakkaaksi' },
2168    { value: 5, text: 'Peruutettu' },
2169  ];
2170
2171  // @ai:claude Signals that the next saveAccount call should also convert the trial to a real customer.
2172  self.convertingTrialToCustomer = ko.observable(false);
2173
2174  // @ai:claude Promotes a trial company to a real paying customer. The company must be
2175  // aktiivinen (ACTIVE) — the backend accepts ACTIVE or CONVERTING and handles conversion.
2176  self.convertTrialToCustomer = function () {
2177    if (!self.account.company.contact_person_ssn()) {
2178      return global.show_message({ type: 'error', text: 'Muuttaminen vaatii sopimusyhteyshenkilön hetun' });
2179    }
2180
2181    var message = 'Muutetaanko kokeiluasiakkuus oikeaksi asiakkuudeksi? Tämä toimenpidettä ei voi perua.';
2182
2183    var $confirmDialog = $('<div />')
2184      .html('<p style="margin:0;">' + message + '</p>')
2185      .prepend(
2186        $(
2187          '<span />',
2188          {
2189            class: 'ui-icon ui-icon-alert',
2190            style: 'float:left; margin:0 7px 50px 0;',
2191          }
2192        )
2193      );
2194
2195    $confirmDialog.dialog({
2196      title: 'Vahvista muutos',
2197      modal: true,
2198      buttons: {
2199        Peruuta: function () {
2200          $confirmDialog.dialog('close');
2201        },
2202        Muuta: function () {
2203          $confirmDialog.dialog('close');
2204          self.convertingTrialToCustomer(true);
2205          self.saveAccount();
2206        },
2207      },
2208      close: function () {
2209        $confirmDialog.dialog('destroy');
2210        $confirmDialog.remove();
2211      },
2212    });
2213
2214    // Make sure the dialog appears above the account card.
2215    $confirmDialog.parents('.ui-dialog').css('z-index', 9999);
2216  };
2217
2218  // @ai:claude Cancels the trial — sets trial_status = 5 (CANCELLED).
2219  self.cancelTrialCustomer = function () {
2220    var $d = $('<div />').html('<p style="margin:0;">Haluatko varmasti peruuttaa kokeiluasiakkuuden?</p>')
2221      .prepend($('<span />', { class: 'ui-icon ui-icon-alert', style: 'float:left; margin:0 7px 50px 0;' }));
2222
2223    $d.dialog({
2224      title: 'Peruuta kokeiluasiakkuus',
2225      modal: true,
2226      buttons: {
2227        'Kyllä, peruuta': function () {
2228          $d.dialog('close');
2229          global.show_loading_dialog('Peruutetaan...');
2230          $.ajax({
2231            url: '/asiakkuudet/cancelTrialCustomer',
2232            type: 'POST',
2233            dataType: 'json',
2234            data: { company_id: self.account.company.id() },
2235            success: function (response) {
2236              global.close_loading_dialog();
2237              global.show_message(response);
2238              self.fetchAndUpdateData(self.account.company.id());
2239              self.saved(true);
2240              self.saved(false);
2241            },
2242            error: function (xhr) {
2243              global.close_loading_dialog();
2244              global.show_message($.parseJSON(xhr.responseText));
2245            },
2246          });
2247        },
2248        'Takaisin': function () { $d.dialog('close'); },
2249      },
2250      close: function () { $d.dialog('destroy'); $d.remove(); },
2251    }).parents('.ui-dialog').css('z-index', 9999);
2252  };
2253
2254  self.selectedCompanyGroups = ko.observableArray([]);
2255  self.companyGroupSelected = ko.observable(null);
2256  self.companyGroupSelected.subscribe(function(g) {
2257    var found = self.selectedCompanyGroups().find(id => id === g.id)
2258    if (found) {
2259      self.selectedCompanyGroups(self.selectedCompanyGroups().filter(id => id !== g.id))
2260    } else {
2261      self.selectedCompanyGroups.push(Number(g.id))
2262    }
2263  });
2264
2265  // Settings
2266  self.settings = {
2267    stationTypeOptions: [
2268      { type: 0, label: 'Asemapaikka' },
2269      { type: 1, label: 'Toimipiste' },
2270      { type: 2, label: 'Asemapaikka + Toimipiste' }
2271    ],
2272    stations: ko.observableArray([]),
2273    agreements: ko.observableArray([]),
2274    agreements_innokorjaamo: ko.observableArray([]),
2275    sms_templates: ko.observableArray([]),
2276    agreementToAdd: ko.observable(),
2277    resourceToAdd: {
2278      resource: ko.observable(null),
2279      ext_id: ko.observable(null),
2280    },
2281    roles: ko.observableArray([]),
2282    towingRecordTypes: ko.observableArray([]),
2283    typeToAdd: ko.observable(),
2284    freightTypes: ko.observableArray([]),
2285    jobOrderTypes: ko.observableArray([]),
2286    companyGroups: ko.observableArray([]),
2287    freightTypeToAdd: ko.observable(),
2288    jobOrderTypeToAdd: ko.observable(),
2289    depots: ko.observableArray([]),
2290    categories: ko.observableArray([]),
2291    glAccounts: ko.observableArray([]),
2292    resources: ko.observableArray([]),
2293    spare_parts: ko.observableArray([]),
2294    depotToAdd: ko.observable(),
2295    categoryToAdd: ko.observable(),
2296    subCategoryToAdd: ko.observable(),
2297    glAccountToAdd: {
2298      gl_account: ko.observable(null),
2299      desc: ko.observable(null),
2300    },
2301    shiftGroupSettings: ko.observableArray(),
2302    isHidden: function (type) {
2303      return typeof type.deleted_at === 'string';
2304    },
2305  };
2306
2307  self.apiKeys = ko.observableArray([]);
2308
2309  self.subcontractingCompanies = ko.observableArray([]);
2310  self.subcontractingSearch = ko.observable('');
2311  self.subcontractingSearchResults = ko.observableArray([]);
2312  self.subcontractingSearchLoading = ko.observable(false);
2313  self.subcontractingSearchNoResults = ko.observable(false);
2314  self._subcontractingDebounceTimer = null;
2315
2316  self.smsMessageTriggers = ko.observableArray([]);
2317  self.smsMessageTimings = ko.observableArray([]);
2318  self.onSmsTriggerChange = function(a) {
2319    // var used = self.smsMessageTriggers().find(function(t) {
2320    //   return t.type == ko.unwrap(a.trigger)
2321    // })
2322    // if (!used) { return; }
2323    ko.tasks.schedule(function() {
2324      if (ko.unwrap(a.id) == null) {
2325        switch (ko.unwrap(a.trigger)) {
2326          case 'reservation_confirmation':
2327            a.template('Hei! \n\nAjoneuvollesi {{REKNO}} on varattu huoltoaika {{ALOITUSPVM}} klo {{ALOITUSKLO}}.');
2328            a.timing('+0 day')
2329            a.title('Varausvahvistus');
2330            break;
2331          case 'reservation_reminder':
2332            a.template('Hei! \n\nMuistutus ajoneuvollesi {{REKNO}} varatusta huoltoajasta huomenna {{ALOITUSPVM}} klo {{ALOITUSKLO}}.');
2333            a.timing('-1 day')
2334            a.title('Varausvahvistus, muistutus');
2335            break;
2336          case 'work_started':
2337            a.template('Hei! \n\nAjoneuvosi {{REKNO}} on nyt otettu työn alle. Arvioitu valmistumisaika on {{VALMISPVM}} klo {{VALMISKLO}}. Ilmoitamme erikseen kun ajoneuvo on valmis noudettavaksi.');
2338            a.timing('+0 day')
2339            a.title('Ajoneuvo otettu työn alle');
2340            break;
2341          case 'work_done':
2342            a.template('Hei! \n\nAjoneuvosi {{REKNO}} on valmis noudettavaksi. Aukioloaikamme 09-17. Ota yhteyttä mikäli et pääse noutamaan ajoneuvoasi aukioloaikoaikojen puitteissa');
2343            a.timing('+0 day')
2344            a.title('Ajoneuvo valmis noudettavaksi');
2345            break;
2346          case 'job_finished':
2347            a.template('Hei! \n\nEsim. Muista kiristää ruuvit tmv.');
2348            a.timing('+0 day')
2349            a.title('Jälkiviesti');
2350            break;
2351        }
2352      }
2353    });
2354  }
2355
2356  self.kycIsDraft = ko.observable(false);
2357  self.kycDeclineReasonsRaw = [
2358    {
2359     selected: ko.observable(false),
2360     description: 'Kuuluu ALV-rekisteriin, mutta ilmoittanut että ei kuulu', 
2361    },
2362    {
2363     selected: ko.observable(false),
2364     description: 'Liikevaihto yli 20k mutta ei ole ALV-rekisterissä', 
2365    },
2366    {
2367     selected: ko.observable(false),
2368     description: 'Ei kuulu ennakkoperintärekisteriin', 
2369    },
2370    {
2371     selected: ko.observable(false),
2372     description: 'Ilmoitetut vastuuhenkilöt ei täsmää rekisteröityihin', 
2373    },
2374    {
2375     selected: ko.observable(false),
2376     description: 'Ilmoitetut nimenkirjoitusoikeudet ei täsmää rekisteröityihin', 
2377    },
2378    {
2379     selected: ko.observable(false),
2380     description: 'Kuuluu ennakkoperintärekisteriin, mutta ilmoittanut että ei kuulu', 
2381    },
2382    {
2383     selected: ko.observable(false),
2384     description: 'Ulkomainen tilinumero', 
2385    },
2386    {
2387     selected: ko.observable(false),
2388     description: 'Epäyhtenäisyys pankkiyhteystiedoissa', 
2389    },
2390    {
2391     selected: ko.observable(false),
2392     description: 'Epäyhtenäisyys pankkiyhteystiedoissa - Asiakasyritys ei ole tilinomistaja', 
2393    },
2394    {
2395     selected: ko.observable(false),
2396     description: 'Asiakastiedoissa yhteys black-list maahan', 
2397    },
2398    {
2399     selected: ko.observable(false),
2400     description: 'Pakotetarkastus tuottanut tuloksen', 
2401    },
2402    {
2403     selected: ko.observable(false),
2404     description: 'Allekirjoittajalle ei nimenkirjoitusoikeutta', 
2405    },
2406    {
2407     selected: ko.observable(false),
2408     description: 'Prokuraa ei rekisteröity tai tiedoissa epäyhtenäisyys', 
2409    },
2410  ]
2411
2412  self.kycDeclineReasons = ko.observableArray(self.kycDeclineReasonsRaw.sort(function(a, b){return a.description > b.description ? 1 : -1}))
2413
2414  self.kycDeclineReasonOther = ko.observable('');
2415
2416  self.declineKycReason = ko.computed(function(){
2417    let reasons = [];
2418    self.kycDeclineReasons().forEach(function(item){
2419      if(item.selected()){
2420        reasons.push(item.description);
2421      }
2422    })
2423    if(self.kycDeclineReasonOther()){
2424      reasons.push(self.kycDeclineReasonOther());
2425    }
2426    return reasons.join(', ');
2427  });
2428
2429  self.clearKycDeclineReasons = function(){
2430    self.kycDeclineReasons().forEach(function(item){
2431      item.selected(false);
2432    })
2433    self.kycDeclineReasonOther('');
2434  }
2435
2436  self.setKycManualAcceptanceRequired = ko.observable(false);
2437  self.continueInterval = ko.observable(false);
2438
2439  function SubCategory(data) {
2440    this.id = ko.observable(data.id);
2441    this.sub_category = ko.observable(data.sub_category);
2442    this.deleted_at = ko.observable(data.deleted_at);
2443  }
2444
2445  function Category(data) {
2446    this.id = ko.observable(data.id);
2447    this.category = ko.observable(data.category);
2448    this.deleted_at = ko.observable(data.deleted_at);
2449    this.sub_categories = ko.observableArray(data.sub_categories.map((s) => new SubCategory(s)));
2450  }
2451
2452  self.handleUpdateMFAServiceState = function(context, toggleMFA) {
2453    const accessLevel = self.account.company.field_of_work() === 'car_tow' ? DEFAULT_CAR_TOW_USER_ACCESS_LEVEL : DEFAULT_USER_ACCESS_LEVEL;
2454    self.account.preferences.min_access_level_required_to_use_mfa(toggleMFA ? accessLevel : null)
2455
2456    //If creating new company don't send request
2457    if( ! self.account.company.id()) {
2458      return
2459    }
2460
2461    self.updateServiceState(context, toggleMFA)
2462  }
2463
2464  self.updateServiceState = function (context, value) 
2465  {
2466    var value = value ? 1 : 0;
2467
2468    if (context === 'mod_sms' && value === 1) { 
2469      self.account.preferences.mobile_sales_vat(13.5);
2470    }
2471
2472    if(value && self.companyRestrictions.restrictionExists(context) ){
2473      window.alert('HUOM! Palvelu on yrityken palveluesto listalla. Mikäli sinulle ei ole hyvää syytä ottaa palvelua käyttöön, klikkaa palvelu pois päältä!');
2474      return;
2475    }
2476
2477    global.showLoadingDialog('Ladataan...');
2478
2479    $.ajax({
2480      url: '/asiakkuudet/updateModStatus',
2481      method: 'post',
2482      data: {
2483        company_id: self.account.company.id(),
2484        context,
2485        value,
2486      },
2487    })
2488      .then(function (success) {
2489        if (context === 'mod_company_group' && Number(value) === 0) {
2490          var reset = self.settings.companyGroups().map(g => { g.active = false; return g})
2491          self.settings.companyGroups.removeAll();
2492          self.settings.companyGroups(reset)
2493          self.selectedCompanyGroups([]);
2494          self.account.company.company_group_admin(false);
2495          self.account.company.ak_partner(false);
2496        }
2497        if (value === 0) {
2498          global.show_message(success);
2499        }
2500
2501        self.account.logs.unshift(success.data.logItem);
2502
2503        if (value === 1) {
2504          global.close_loading_dialog()
2505          var dia = $('#dialog')
2506            .dialog({
2507              resizable: false,
2508              title: 'Aktivointiviesti',
2509              height: 'auto',
2510              width: 400,
2511              modal: true,
2512              buttons: {
2513                'Lähetä': function () {
2514                  $.ajax({
2515                    url: '/asiakkuudet/sendActivationMail',
2516                    method: 'post',
2517                    data: {
2518                      company_id: self.account.company.id(),
2519                      context,
2520                      value,
2521                    },
2522                  })
2523                    .then(function (resp) { 
2524                      console.log(resp)
2525                      var msg = resp.msg || 'Toiminto suoritettu, mutta palvelin ei vastannut';
2526                      dia.dialog('option', 'title', 'Valmis');
2527                      dia.dialog('option', 'buttons', {});
2528                      dia.html('<p>' + msg + '</p>') 
2529                      setTimeout(function() { dia.dialog('close') }, 3500);
2530                    })
2531                    .fail(function (resp) { 
2532                      var msg = resp.responseJSON.error || 'Palvelinvirhe';
2533                      dia.dialog('option', 'title', 'Virhe');
2534                      dia.dialog('option', 'buttons', {});
2535                      dia.html('<p>' + msg + '</p>') })
2536                      setTimeout(function() { dia.dialog('close') }, 3500);
2537                },
2538                'Ei viestiä': function () {
2539                  dia.dialog('close');
2540                },
2541              },
2542            })
2543            .html('<p>Haluatko lähetetää sopimusyhteyshenkilölle palvelun aktivointiviestin?</p>');
2544        }
2545      })
2546      .fail(function (error) {
2547        global.show_message(error.responseJSON);
2548      })
2549      .always(function () {
2550        global.close_loading_dialog();
2551      });
2552  };
2553
2554  self.kredinorSubscriptionCount = ko.observable(0);
2555  self.companyDocuments = new CompanyDocumentsVM();
2556  self.companyRestrictions = new CompanyRestrictionsVM();
2557
2558  // @ai:claude The Procountor accounting settings editor, the same view model and the same markup
2559  // the company's own omat_tiedot tab uses, so the two editors cannot show different c
2559onfiguration.
2560  // adminMode makes its endpoints carry the company id, because the card configures a company other
2561  // than the admin's own session company. Filled by setData() when a card is opened.
2562  self.accounting = new AccountingSettingsVm({
2563    baseUrl: '/asiakkuudet',
2564    adminMode: true,
2565    data: null,
2566  });
2567
2568
2569  self.canSelectRiverty = function() {
2570    if (!self.account.company.id()) {
2571      return false;
2572    }
2573    
2574    var currentLedgerService = self.account.company.ledger_service();
2575    return currentLedgerService === 'riverty';
2576  };
2577
2578  self.companyMessagingDetails = new CompanyMessagingDetailsVM();
2579  self.companyMessagingDetailOptions = ko.observableArray([]);
2580  // START OF SERVICE SUBSCRIPTIONS
2581
2582  self.serviceSubscriptions = {
2583    //add subscriptions here
2584    review: {
2585      type: 'review',
2586      subscriptions: ko.observableArray([]),
2587    },
2588    paymentTerminal: {
2589      type: 'paymentTerminal',
2590      subscriptions: ko.observableArray([]),
2591    },
2592    accountingService: {
2593      type: 'accountingService',
2594      subscriptions: ko.observableArray([]),
2595    },
2596    workShiftService: {
2597      type: 'workShiftService',
2598      subscriptions: ko.observableArray([]),
2599    },
2600    trackingLink: {
2601      type: 'trackingLink',
2602      subscriptions: ko.observableArray([]),
2603    },
2604    paymentLink: {
2605      type: 'paymentLink',
2606      subscriptions: ko.observableArray([]),
2607    },
2608  };
2609
2610  self.serviceSubscriptions.review.isActive = ko.computed(function () {
2611    var isActive = false;
2612    self.serviceSubscriptions.review.subscriptions().forEach(function (subscription) {
2613      if (subscription.isActive()) {
2614        isActive = true;
2615      }
2616    });
2617    return isActive;
2618  });
2619
2620  self.serviceSubscriptions.paymentTerminal.isActive = ko.computed(function () {
2621    var isActive = false;
2622    self.serviceSubscriptions.paymentTerminal.subscriptions().forEach(function (subscription) {
2623      if (subscription.isActive()) {
2624        isActive = true;
2625      }
2626    });
2627    return isActive;
2628  });
2629
2630  self.serviceSubscriptions.accountingService.isActive = ko.computed(function () {
2631    var isActive = false;
2632    self.serviceSubscriptions.accountingService.subscriptions().forEach(function (subscription) {
2633      if (subscription.isActive()) {
2634        isActive = true;
2635      }
2636    });
2637    return isActive;
2638  });
2639
2640  self.serviceSubscriptions.workShiftService.isActive = ko.computed(function () {
2641    var isActive = false;
2642    self.serviceSubscriptions.workShiftService.subscriptions().forEach(function (subscription) {
2643      if (subscription.isActive()) {
2644        isActive = true;
2645      }
2646    });
2647    return isActive;
2648  });
2649
2650  self.serviceSubscriptions.trackingLink.isActive = ko.computed(function () {
2651    var isActive = false;
2652    self.serviceSubscriptions.trackingLink.subscriptions().forEach(function (subscription) {
2653      if (subscription.isActive()) {
2654        isActive = true;
2655      }
2656    });
2657    return isActive;
2658  });
2659
2660  self.companyForms = [
2661    { value: 'asoy', text: 'Asunto-osakeyhtö' },
2662    { value: 'ay', text: 'Avoin yhtiö' },
2663    { value: 'ky', text: 'Kommandiittiyhtiö' },
2664    { value: 'oy', text: 'Osakeyhtiö' },
2665    { value: 'sr', text: 'Säätiö' },
2666    { value: 'tmi', text: 'Toiminimi' },
2667    { value: 'ry', text: 'Yhdistys' },
2668    { value: 'other', text: 'Muu' },
2669  ];
2670  self.kycAddressOptions = [
2671    { value: 'same', text: 'Sama kuin postiosoite' },
2672    { value: 'different', text: 'Erillinen käyntiosoite' },
2673  ];
2674  self.kycRepresentationOptions = [
2675    { value: 'ceo', text: 'Toimitusjohtaja, yksin' },
2676    { value: 'ceo_substitute', text: 'Toimitusjohtajan sijainen, yksin' },
2677    { value: 'ceo_and_cabinet_member', text: 'Hallituksen jäsen ja toimitusjohtaja yhdessä' },
2678    { value: 'chairman', text: 'Hallituksen puheenjohtaja, yksin' },
2679    { value: 'cabinet_member', text: 'Hallituksen jäsen, yksin' },
2680    { value: 'cabinet_members', text: 'Hallituksen jäsen, kaksi yhdessä' },
2681    { value: 'deputy_member', text: 'Hallituksen varajäsen, yksin' },
2682    { value: 'deputy_members', text: 'Hallituksen varajäsen, kaksi yhdessä' },
2683    { value: 'full_cabinet', text: 'Hallitus, kokonaisuudessaan' },
2684    { value: 'sole_proprietor', text: 'Elinkeinonharjoittaja' },
2685    { value: 'partner', text: 'Yhtiömies yksin' },
2686    { value: 'partners', text: 'Yhtiömies kaksin' },
2687  ];
2688  self.kycProcuration = [
2689    { value: true, text: 'Kyllä' },
2690    { value: false, text: 'Ei' },
2691  ];
2692  self.kycInterval = [
2693    { value: 12, text: '1 vuosi' },
2694    { value: 24, text: '2 vuotta' },
2695  ];
2696  self.kycOwner = [
2697    { value: true, text: 'Kyllä' },
2698    { value: false, text: 'Ei' },
2699  ];
2700  self.kycProcurationsRepresentation = [
2701    { value: 'one', text: 'Yksin' },
2702    { value: 'two', text: 'Kaksin' },
2703    { value: 'other', text: 'Muu, mikä?' },
2704  ];
2705  self.kycCommissions = [
2706    { value: 'ceo', text: 'Toimitusjohtaja' },
2707    { value: 'ceo_substitute', text: 'Toimitusjohtajan sijainen' },
2708    { value: 'chairman', text: 'Hallituksen puheenjohtaja' },
2709    { value: 'cabinet_member', text: 'Hallituksen jäsen' },
2710    { value: 'cabinet_member2', text: 'Hallituksen varajäsen' },
2711    { value: 'partner', text: 'Yhtiömies (Ay)' },
2712    { value: 'liable_partner', text: 'Vastuunalainen yhtiömies (Ky)' },
2713    { value: 'sole_proprietor', text: 'Elinkeinonharjoittaja' },
2714  ];
2715
2716  self.pendingKycInformation = {
2717    contactPerson: ko.observable(),
2718    contactPersonSSN: ko.observable(),
2719    contactPersonEmail: ko.observable(),
2720    contactPersonPhone: ko.observable(),
2721  };
2722
2723  self.enableBankAccountInfo = ko.observable(false);
2724  self.toggleBankAccountInput = function() {
2725    self.enableBankAccountInfo(!self.enableBankAccountInfo());
2726  };
2727
2728  self.enableKycBaseInformation = ko.observable(true);
2729  self.enableKycContactPersonInformation = ko.observable(true);
2730  self.enableKycBankAccountInformation = ko.observable(true);
2731  self.enableKycRepresentationInformation = ko.observable(true);
2732  self.enableKycPersonInChargeInformation = ko.observable(true);
2733  self.enableKycOwnersInformation = ko.observable(true);
2734  self.enableKycPoliticallyInfluentialPersonsInformation = ko.observable(true);
2735
2736  self.toggleEnableKycBaseInformation = function () {
2737    self.enableKycBaseInformation(!self.enableKycBaseInformation());
2738  };
2739
2740  self.toggleEnableKycContactPersonInformation = function () {
2741    self.enableKycContactPersonInformation(!self.enableKycContactPersonInformation());
2742  };
2743
2744  self.toggleEnableKycBankAccountInformation = function () {
2745    self.enableKycBankAccountInformation(!self.enableKycBankAccountInformation());
2746  };
2747
2748  self.toggleKycRepresentationInformation = function () {
2749    self.enableKycRepresentationInformation(!self.enableKycRepresentationInformation());
2750  };
2751
2752  self.toggleKycPersonInChargeInformation = function () {
2753    self.enableKycPersonInChargeInformation(!self.enableKycPersonInChargeInformation());
2754  };
2755
2756  self.toggleKycOwnersInformation = function () {
2757    self.enableKycOwnersInformation(!self.enableKycOwnersInformation());
2758  };
2759
2760  self.addKycRepresentationInformation = function (value) {
2761    self.account.kyc.procurations.push(kycProcuration());
2762  };
2763
2764  self.removeKycProcuration = function(value) {
2765    self.account.kyc.procurations.remove(value);
2766  };
2767
2768  self.addKycPersonInCharge = function () {
2769    $('#add-person-in-charge').removeClass('error');
2770    self.account.kyc.personsInCharge.push(kycPersonInCharge());
2771    self.initDatepicker();
2772  };
2773
2774  self.removeKycPersonInCharge = function(value) {
2775    self.account.kyc.personsInCharge.remove(value);
2776  };
2777
2778  self.toggleKycPoliticallyInfluentialPersonsInformation = function () {
2779    self.enableKycPoliticallyInfluentialPersonsInformation(
2780      !self.enableKycPoliticallyInfluentialPersonsInformation()
2781    );
2782  };
2783
2784  self.addKycPoliticallyInfluentialPerson = function (type) {
2785    switch (type) {
2786      case 'pip':
2787        self.account.kyc.politicallyInfluentialPersons.push(kycPoliticallyInfluentialPerson(type));
2788        break;
2789      case 'family_member':
2790        self.account.kyc.politicallyInfluentialFamilyMembers.push(kycPoliticallyInfluentialPerson(type));
2791        break;
2792    }
2793  };
2794
2795  self.removeKycPIP = function (value) {
2796    switch (ko.toJS(value).type) {
2797      case 'pip':
2798        self.account.kyc.politicallyInfluentialPersons.remove(value);
2799        break;
2800      case 'family_member':
2801        self.account.kyc.politicallyInfluentialFamilyMembers.remove(value);
2802        break;
2803    }
2804  };
2805
2806  self.removeKycOwner = function (value) {
2807    switch (ko.toJS(value).type) {
2808      case 'person':
2809        self.account.kyc.personOwners.remove(value);
2810        break;
2811      case 'oy':
2812        self.account.kyc.oyOwners.remove(value);
2813        break;
2814      case 'ky':
2815        self.account.kyc.kyOwners.remove(value);
2816        break;
2817    }
2818  };
2819
2820  self.addKycPersonOwner = function() {
2821    self.account.kyc.personOwners.push(kycOwner('person'));
2822  };
2823
2824  self.addKycOyOwner = function() {
2825    self.account.kyc.oyOwners.push(kycOwner('oy'));
2826  };
2827
2828  self.addKycKyOwner = function() {
2829    self.account.kyc.kyOwners.push(kycOwner('ky'));
2830  };
2831
2832  self.searchCompanyRegister = function() {
2833    window.open('https://tietopalvelu.ytj.fi/yritys/' + self.account.company.business_id(), '_blank');
2834  };
2835
2836  self.acceptKYCChanges = function() {
2837
2838    try {
2839      global.showLoadingDialog('Hyväksytään muutoksia...');
2840
2841      jQuery
2842        .ajax({
2843          type: 'post',
2844          dataType: 'json',
2845          url: '/asiakkuudet/acceptKYCChanges',
2846          data: { id: self.account.kyc.id(), companyId: self.account.company.id() },
2847        })
2848        .done(function (responseJSON) {
2849          global.show_message({
2850            title: 'KYC muutokset tallennettu',
2851            text: 'KYC lomake tallennettu onnistuneesti.',
2852            type: 'success',
2853          });
2854          global.close_loading_dialog();
2855          //ko.mapping.fromJS(responseJSON.data, {}, self.account.kyc);
2856          self.setData(responseJSON);
2857        })
2858        .fail(function (data) {
2859          global.show_message($.parseJSON(data.responseText));
2860          global.close_loading_dialog();
2861          console.error('.ajax.fail:', data);
2862        });
2863    } catch (e) {
2864      console.error(e.message);
2865      global.show_message({type: 'error', text: e.message});
2866    }
2867  };
2868
2869  self.discardKYCChanges = function(){
2870    $dialog = $('#decline-kyc-dialog');
2871
2872    $dialog.dialog({
2873      width: 'auto',
2874      height: 'auto',
2875      modal: true,
2876      resizable: false,
2877      autoOpen: true,
2878      title: 'Hylkäyksen syy',
2879      close: function () {
2880          $(this).dialog('close');
2881      },
2882      buttons: {
2883        Hylkää: function(){
2884          self.declineKYC();
2885          $(this).dialog('close');
2886        },
2887        Sulje: function(){
2888          $(this).dialog('close');
2889        }
2890      }
2891    })
2892  }
2893
2894  self.discardKYCChanges = function(){
2895    $dialog = $('#decline-kyc-dialog');
2896
2897    $dialog.dialog({
2898      width: 'auto',
2899      height: 'auto',
2900      modal: true,
2901      resizable: false,
2902      autoOpen: true,
2903      title: 'Hylkäyksen syy',
2904      close: function () {
2905          $(this).dialog('close');
2906      },
2907      buttons: {
2908        Hylkää: function(){
2909          self.declineKYC();
2910          $(this).dialog('close');
2911        },
2912        Sulje: function(){
2913          self.clearKycDeclineReasons();
2914          $(this).dialog('close');
2915        }
2916      }
2917    })
2918  }
2919
2920  self.declineKYC = function() {
2921    try {
2922      let reason = self.declineKycReason();
2923      self.clearKycDeclineReasons();
2924      if(!reason){
2925        window.alert('Et ole antanut syytä hylkäämiselle.');
2926        return;
2927      }
2928      global.showLoadingDialog('Hylätään muutoksia...');
2929
2930      jQuery
2931        .ajax({
2932          type: 'post',
2933          dataType: 'json',
2934          url: '/asiakkuudet/discardKYCChanges',
2935          data: { id: self.account.kyc.id(), companyId: self.account.company.id(), reason: reason },
2936        })
2937        .done(function (responseJSON) {
2938          global.show_message({
2939            title: 'KYC muutokset hylätty',
2940            text: 'KYC lomake hylätty onnistuneesti.',
2941            type: 'success',
2942          });
2943          global.close_loading_dialog();
2944          //ko.mapping.fromJS(responseJSON.data, {}, self.account.kyc);
2945          self.setData(responseJSON);
2946        })
2947        .fail(function (data) {
2948          global.show_message($.parseJSON(data.responseText));
2949          global.close_loading_dialog();
2950          console.error('.ajax.fail:', data);
2951        });
2952    } catch (e) {
2953      console.error(e.message);
2954      global.show_message({type: 'error', text: e.message});
2955    }
2956  };
2957
2958  self.createKycFormDialog = function(){
2959    $dialog = $('#new-kyc-dialog');
2960
2961    $dialog.dialog({
2962      width: '400',
2963      height: 'auto',
2964      modal: true,
2965      resizable: false,
2966      autoOpen: true,
2967      title: 'Varmista lähetys',
2968      close: function () {
2969          $(this).dialog('close');
2970      },
2971      buttons: {
2972        "Luo ja lähetä": function(){
2973          self.createAndSendKycForm();
2974          $(this).dialog('close');
2975        },
2976        Sulje: function(){
2977          self.setKycManualAcceptanceRequired(false);
2978          $(this).dialog('close');
2979        }
2980      }
2981    })
2982  }
2983
2984  self.sendKycForm = function () {
2985    try {
2986      if (!self.account.kyc.recipientEmail()) {
2987        throw Error('Vastaanottajan sposti puuttuu');
2988      }
2989
2990      global.showLoadingDialog('Lähetetään...');
2991
2992      var data = ko.toJS(self.account.kyc);
2993      delete data.__ko_mapping__;
2994
2995      jQuery
2996        .ajax({
2997          type: 'post',
2998          dataType: 'json',
2999          url: '/asiakkuudet/updateReceiverAndSend',
3000          data: { formId: data.id, email: data.recipientEmail, companyId: self.account.company.id() },
3001        })
3002        .done(function (responseJSON) {
3003          global.show_message(responseJSON);
3004          global.close_loading_dialog();
3005        })
3006        .fail(function (data) {
3007          global.show_message($.parseJSON(data.responseText));
3008          global.close_loading_dialog();
3009          // console.error('.ajax.fail:', data);
3010        });
3011    } catch (e) {
3012      console.error(e.message);
3013      global.show_message({type: 'error', text: e.message});
3014    }
3015  };
3016
3017  self.changeKycInterval = function () {
3018    try {
3019      global.showLoadingDialog('Lähetetään...');
3020
3021      var data = ko.toJS(self.account.kyc);
3022      delete data.__ko_mapping__;
3023
3024      jQuery
3025        .ajax({
3026          type: 'post',
3027          dataType: 'json',
3028          url: '/asiakkuudet/changeKycInterval',
3029          data: { formId: data.id, interval: data.interval, companyId: self.account.company.id()},
3030        })
3031        .done(function (responseJSON) {
3032          global.show_message(responseJSON);
3033          global.close_loading_dialog();
3034        })
3035        .fail(function (data) {
3036          global.show_message($.parseJSON(data.responseText));
3037          global.close_loading_dialog();
3038          // console.error('.ajax.fail:', data);
3039        });
3040    } catch (e) {
3041      console.error(e.message);
3042      global.show_message({type: 'error', text: e.message});
3043    }
3044  };
3045
3046  self.createAndSendKycForm = function () {
3047    try {
3048      let forceManualAccept = self.setKycManualAcceptanceRequired() ? 1 : 0;
3049      let continueInterval = self.continueInterval() ? 1 : 0;
3050      self.setKycManualAcceptanceRequired(false);
3051      self.continueInterval(false);
3052
3053      if (!self.account.kyc.recipientEmail()) {
3054        throw Error('Vastaanottajan sposti puuttuu');
3055      }
3056
3057      global.showLoadingDialog('Lähetetään...');
3058
3059      var data = ko.toJS(self.account.kyc);
3060      delete data.__ko_mapping__;
3061
3062      jQuery
3063        .ajax({
3064          type: 'post',
3065          dataType: 'json',
3066          url: '/asiakkuudet/createAndSendKycForm',
3067          data: { 
3068            data: data, 
3069            companyId: self.account.company.id(), 
3070            forceManualAccept: forceManualAccept, 
3071            continueInterval: continueInterval,
3072            sentAt: self.account.kyc.sentAt(),
3073          },
3074        })
3075        .done(function (responseJSON) {
3076          global.show_message({
3077            title: 'KYC lomake lähetetty',
3078            text: 'KYC lomake lähetetty onnistuneesti.',
3079            type: 'success',
3080          });
3081          global.close_loading_dialog();
3082          //ko.mapping.fromJS(responseJSON.data, {}, self.account.kyc);
3083          self.setData(responseJSON);
3084        })
3085        .fail(function (data) {
3086          global.show_message($.parseJSON(data.responseText));
3087          global.close_loading_dialog();
3088          console.error('.ajax.fail:', data);
3089        });
3090    } catch (e) {
3091      console.error(e.message);
3092      global.show_message({type: 'error', text: e.message});
3093    }
3094  };
3095
3096  function kycProcuration() {
3097    return {
3098      id: ko.observable(null),
3099      representation: ko.observable(''),
3100      name: ko.observable(''),
3101      ssn: ko.observable(''),
3102      description: ko.observable(''),
3103      nationality: ko.observable('Suomi')
3104    };
3105  }
3106
3107  function kycPersonInCharge() {
3108    return {
3109      id: ko.observable(null),
3110      commission: ko.observable(''),
3111      name: ko.observable(''),
3112      ssn: ko.observable(''),
3113      commissionStartDate: ko.observable(''),
3114      nationality: ko.observable('Suomi')
3115    };
3116  }
3117
3118  function kycOwner(type = 'person') {
3119    return {
3120      id: ko.observable(null),
3121      type: ko.observable(type),
3122      name: ko.observable(''),
3123      companyName: ko.observable(''),
3124      ssn: ko.observable(''),
3125      businessId: ko.observable(''),
3126      nationality: ko.observable(''),
3127      stake: ko.observable(''),
3128    };
3129  }
3130
3131  function kycPoliticallyInfluentialPerson(type = 'person') {
3132    return {
3133      id: ko.observable(null),
3134      type: ko.observable(type),
3135      name: ko.observable(''),
3136      description: ko.observable(''),
3137    };
3138  }
3139
3140  self.getkycConfirmationLabel = function(date, addDays) {
3141    // date is in format d.m.Y or null and we want to return date + addDays in same format
3142    if (!date) {
3143      return 'Lähetyspvm puuttuu';
3144    } 
3145
3146    var parts = date.split('.');
3147    var result = new Date(parts[2], parts[1] - 1, parts[0]);
3148    result.setDate(result.getDate() + addDays);
3149    // if result is in the past, return addDays from today
3150    var today = new Date();
3151    if (result < today) {
3152      return 'pvm mennyt';
3153    }
3154    return result.getDate() + '.' + (result.getMonth() + 1) + '.' + result.getFullYear();
3155  }
3156
3157  self.addSubscription = function (type) {
3158    switch (type) {
3159      case 'review':
3160        var newSubscription = new ServiceSubscriptionVM();
3161        newSubscription.data.company_id(self.account.company.id());
3162        self.subscriptionDefaults.review &&
3163          newSubscription.setDefaults(Object.values(self.subscriptionDefaults.review));
3164        self.serviceSubscriptions.review.subscriptions.push(newSubscription);
3165        break;
3166      case 'paymentTerminal':
3167        var newSubscription = new ServiceSubscriptionVM();
3168        newSubscription.data.company_id(self.account.company.id());
3169        self.subscriptionDefaults.payment_terminal &&
3170          newSubscription.setDefaults(Object.values(self.subscriptionDefaults.payment_terminal));
3171        self.serviceSubscriptions.paymentTerminal.subscriptions.push(newSubscription);
3172        break;
3173      case 'accountingService':
3174        var newSubscription = new ServiceSubscriptionVM();
3175        newSubscription.data.company_id(self.account.company.id());
3176        self.subscriptionDefaults.accounting_service &&
3177          newSubscription.setDefaults(Object.values(self.subscriptionDefaults.accounting_service));
3178        self.serviceSubscriptions.accountingService.subscriptions.push(newSubscription);
3179        break;
3180      case 'workShiftService':
3181        var newSubscription = new ServiceSubscriptionVM();
3182        newSubscription.data.company_id(self.account.company.id());
3183        self.subscriptionDefaults.work_shift_service &&
3184          newSubscription.setDefaults(Object.values(self.subscriptionDefaults.work_shift_service));
3185        self.serviceSubscriptions.workShiftService.subscriptions.push(newSubscription);
3186        break;
3187      case 'trackingLink':
3188        var newSubscription = new ServiceSubscriptionVM();
3189        newSubscription.data.company_id(self.account.company.id());
3190        self.subscriptionDefaults.tracking_link &&
3191          newSubscription.setDefaults(Object.values(self.subscriptionDefaults.tracking_link));
3192        self.serviceSubscriptions.trackingLink.subscriptions.push(newSubscription);
3193        break;
3194      case 'paymentLink':
3195        var newSubscription = new ServiceSubscriptionVM();
3196        newSubscription.data.company_id(self.account.company.id());
3197        self.subscriptionDefaults.payment_link &&
3198          newSubscription.setDefaults(Object.values(self.subscriptionDefaults.payment_link));
3199        self.serviceSubscriptions.paymentLink.subscriptions.push(newSubscription);
3200        break;
3201      default:
3202        return;
3203    }
3204  };
3205
3206  self.removeServiceSubscription = function (index, type) {
3207    self.serviceSubscriptions[type].subscriptions.splice(index, 1);
3208  };
3209
3210  self.subscriptionDefaults = {};
3211
3212  self.emptyServiceSubscriptions = function () {
3213    self.serviceSubscriptions.review.subscriptions([]);
3214    self.serviceSubscriptions.paymentTerminal.subscriptions([]);
3215    self.serviceSubscriptions.accountingService.subscriptions([]);
3216    self.serviceSubscriptions.workShiftService.subscriptions([]);
3217    self.serviceSubscriptions.trackingLink.subscriptions([]);
3218    self.serviceSubscriptions.paymentLink.subscriptions([]);
3219  };
3220
3221  self.setSubscriptionData = function (subscriptions, companyId) {
3222    // first empty all models so we dont have any data from other companies
3223    self.emptyServiceSubscriptions();
3224
3225    subscriptions.forEach(function (subscription) {
3226      //add subscriptions here
3227      switch (subscription.type) {
3228        case 'monthly_fee_sms_review':
3229        case 'monthly_fee_sms_review_nps':
3230          var newSubscription = new ServiceSubscriptionVM();
3231          newSubscription.data.company_id(companyId);
3232          self.subscriptionDefaults.review &&
3233            newSubscription.setDefaults(Object.values(self.subscriptionDefaults.review));
3234          newSubscription.setActiveSubscription(subscription);
3235          self.serviceSubscriptions.review.subscriptions.push(newSubscription);
3236          break;
3237        case 'monthly_fee_payment_terminal':
3238          var newSubscription = new ServiceSubscriptionVM();
3239          newSubscription.data.company_id(companyId);
3240          self.subscriptionDefaults.payment_terminal &&
3241            newSubscription.setDefaults(Object.values(self.subscriptionDefaults.payment_terminal));
3242          newSubscription.setActiveSubscription(subscription);
3243          self.serviceSubscriptions.paymentTerminal.subscriptions.push(newSubscription);
3244          break;
3245        case 'monthly_fee_accounting_service':
3246          var newSubscription = new ServiceSubscriptionVM();
3247          newSubscription.data.company_id(companyId);
3248          self.subscriptionDefaults.accounting_service &&
3249            newSubscription.setDefaults(
3250              Object.values(self.subscriptionDefaults.accounting_service)
3251            );
3252          newSubscription.setActiveSubscription(subscription);
3253          self.serviceSubscriptions.accountingService.subscriptions.push(newSubscription);
3254          break;
3255        case 'monthly_fee_work_shift_service':
3256          var newSubscription = new ServiceSubscriptionVM();
3257          newSubscription.data.company_id(companyId);
3258          self.subscriptionDefaults.work_shift_service &&
3259            newSubscription.setDefaults(
3260              Object.values(self.subscriptionDefaults.work_shift_service)
3261            );
3262          newSubscription.setActiveSubscription(subscription);
3263          self.serviceSubscriptions.workShiftService.subscriptions.push(newSubscription);
3264          break;
3265        case 'monthly_fee_tracking_link':
3266          var newSubscription = new ServiceSubscriptionVM();
3267          newSubscription.data.company_id(companyId);
3268          self.subscriptionDefaults.tracking_link &&
3269            newSubscription.setDefaults(Object.values(self.subscriptionDefaults.tracking_link));
3270          newSubscription.setActiveSubscription(subscription);
3271          self.serviceSubscriptions.trackingLink.subscriptions.push(newSubscription);
3272          break;
3273        case 'monthly_fee_payment_link':
3274          var newSubscription = new ServiceSubscriptionVM();
3275          newSubscription.data.company_id(companyId);
3276          self.subscriptionDefaults.payment_link &&
3277            newSubscription.setDefaults(Object.values(self.subscriptionDefaults.payment_link));
3278          newSubscription.setActiveSubscription(subscription);
3279          self.serviceSubscriptions.paymentLink.subscriptions.push(newSubscription);
3280          break;
3281        default:
3282          return;
3283      }
3284    });
3285  };
3286
3287  // END OF SERVICE SUBSCRIPTIONS
3288
3289  self.openRegistryImport = function(){
3290    var company_id = ko.toJS(self.account.company.id);
3291    var url = '/rekisterin_tuonti/' + company_id;
3292    window.open(url, '_blank');
3293  }
3294  
3295  self.getRegistryTemplate = async function(type){
3296    var url = '/rekisterin_tuonti/getTemplate/' + type;
3297
3298    const data = await self.fetchTemplate(url);
3299    
3300    if(data !== null){
3301      self.downloadCSV(data);
3302    }
3303  }
3304  
3305  self.downloadCSV = function(data) {
3306    const link = document.createElement('a');
3307    link.href = window.URL.createObjectURL(data.blob);
3308    link.download = data.fileName;
3309    document.body.appendChild(link);
3310    link.click();
3311    document.body.removeChild(link);
3312  }
3313
3314  self.fetchTemplate = async function(url) {
3315
3316    var $dialog = $('<div>Haetaan tietoja...</div>');
3317
3318    $dialog.dialog({
3319      width: 400,
3320      height: 200,
3321      title: 'Haku käynnissä',
3322      close: function (e) {
3323        e.stopPropagation();
3324        $dialog.dialog('destroy').remove();
3325      },
3326    });
3327
3328    try {
3329      const response = await fetch(url, {
3330        method: "GET"
3331      });
3332
3333      const contentType = response.headers.get('content-type');
3334
3335      $dialog.dialog('destroy').remove();
3336
3337      if(contentType && contentType.includes('text/csv')){
3338
3339        const blob = await response.blob();
3340        const fileName = self.extractFileName(response.headers.get('Content-Disposition'));
3341
3342        return {
3343          blob: blob,
3344          fileName: fileName
3345        }
3346      } else {
3347
3348        self.errorDialog('Ei tuloksia');
3349        return null;
3350      }
3351
3352    } catch (error) {
3353      $dialog.html('<p>Mallin luonti epäonnistui</p>');
3354      console.log('Error!:', error);
3355      self.errorDialog(error);
3356      $dialog.dialog('close');
3357
3358      return null;
3359    }
3360  }
3361
3362  self.errorDialog = function(error){
3363
3364    const errorDialog = document.querySelector('.errorDialog');
3365
3366    if(errorDialog !== null){
3367      errorDialog.remove();
3368    }
3369
3370    var $dialog = $('<div>' + error + '</div>');
3371
3372    $dialog.dialog({
3373      dialogClass: 'errorDialog',
3374      width: 200,
3375      height: 150,
3376      title: 'Haku',
3377      close: function (e) {
3378        e.stopPropagation();
3379        $dialog.dialog('destroy').remove();
3380      },
3381    });
3382
3383  }
3384
3385  self.extractFileName = function(contentDisposition) {
3386    const match = contentDisposition.match(/filename="([^"]+)"/);
3387    if (match && match[1]) {
3388      return match[1];
3389    }
3390    return null;
3391  }
3392  
3393  
3394  self.selectedCategory = ko.observable(null);
3395  self.showSubcategories = (category) => self.selectedCategory(category.id());
3396
3397  self.subCategories = ko.pureComputed(() => {
3398    return self.settings
3399      .categories()
3400      .filter((category) => category.id() === self.selectedCategory())
3401      .map((category) => category.sub_categories())
3402      .flat();
3403  });
3404
3405  self.showOrHideCategory = (category) => {
3406    jQuery
3407      .ajax({
3408        url: 'asiakkuudet/hideOrShowCategory',
3409        method: 'post',
3410        data: {
3411          id: category.id,
3412          type: 'category',
3413          company_id: ko.toJS(self.account.company.id),
3414        },
3415      })
3416      .then(function (categories) {
3417        self.settings.categories.removeAll();
3418        self.settings.categories(categories.map((c) => new Category(c)));
3419      })
3420      .fail(function (error) {
3421        alert(error.responseJSON);
3422      });
3423  };
3424
3425  self.addGlAccount = () => {
3426    if (!self.settings.glAccountToAdd.gl_account()) {
3427      return alert('Tilikoodi-kenttä on tyhjä!');
3428    }
3429    if (!self.settings.glAccountToAdd.desc()) {
3430      return alert('Selite-kenttä on tyhjä!');
3431    }
3432
3433    var existing = self.settings.glAccounts().find((item) => {
3434      return item.gl_account == self.settings.glAccountToAdd.gl_account().trim();
3435    });
3436
3437    if (typeof existing !== 'undefined') {
3438      alert('Tili on jo olemassa!');
3439      return;
3440    }
3441
3442    jQuery
3443      .ajax({
3444        url: 'asiakkuudet/addGlAccount',
3445        method: 'post',
3446        data: {
3447          gl_account: self.settings.glAccountToAdd.gl_account(),
3448          desc: self.settings.glAccountToAdd.desc(),
3449          company_id: ko.toJS(self.account.company.id),
3450        },
3451      })
3452      .then(function (glAccounts) {
3453        self.settings.glAccounts(glAccounts);
3454        self.settings.glAccountToAdd.gl_account(null);
3455        self.settings.glAccountToAdd.desc(null);
3456      })
3457      .fail(function (error) {
3458        alert(error.responseJSON);
3459      });
3460  };
3461
3462  self.addCategory = () => {
3463    jQuery
3464      .ajax({
3465        url: 'asiakkuudet/addCategory',
3466        method: 'post',
3467        data: {
3468          category: self.settings.categoryToAdd(),
3469          type: 'category',
3470          company_id: ko.toJS(self.account.company.id),
3471        },
3472      })
3473      .then(function (categories) {
3474        self.settings.categories.removeAll();
3475        self.settings.categories(categories.map((c) => new Category(c)));
3476        self.settings.categoryToAdd(null);
3477      })
3478      .fail(function (error) {
3479        alert(error.responseJSON);
3480      });
3481  };
3482
3483  self.showOrHideSubCategory = (subCategory) => {
3484    jQuery
3485      .ajax({
3486        url: 'asiakkuudet/hideOrShowCategory',
3487        method: 'post',
3488        data: {
3489          id: subCategory.id,
3490          type: 'sub_category',
3491          company_id: ko.toJS(self.account.company.id),
3492        },
3493      })
3494      .then(function (categories) {
3495        self.settings.categories.removeAll();
3496        self.settings.categories(categories.map((c) => new Category(c)));
3497      })
3498      .fail(function (error) {
3499        alert(error.responseJSON);
3500      });
3501  };
3502
3503  self.addSubCategory = () => {
3504    jQuery
3505      .ajax({
3506        url: 'asiakkuudet/addCategory',
3507        method: 'post',
3508        data: {
3509          category: self.settings.subCategoryToAdd(),
3510          type: 'sub_category',
3511          company_id: ko.toJS(self.account.company.id),
3512          category_id: self.selectedCategory(),
3513        },
3514      })
3515      .then(function (categories) {
3516        self.settings.categories.removeAll();
3517        self.settings.categories(categories.map((c) => new Category(c)));
3518        self.settings.subCategoryToAdd(null);
3519      })
3520      .fail(function (error) {
3521        alert(error.responseJSON);
3522      });
3523  };
3524
3525  self.userShiftGroupSettings = ko.pureComputed(function () {
3526    return [
3527      {
3528        id: null,
3529        group_name: 'Ei kytketty',
3530      },
3531    ].concat(self.settings.shiftGroupSettings().filter((s) => Boolean(s.id())));
3532  });
3533
3534  self.isWorkerGroup = function (groupId) {
3535    groupId = groupId && !Number.isInteger(groupId) ? parseInt(groupId) : groupId;
3536    return (
3537      self.usergroups.filter(function (group) {
3538        return group.id === groupId && group.role === 'worker';
3539      }).length > 0
3540    );
3541  };
3542
3543  self.disableUserGroupChange = function(user){
3544    
3545    if( ! user.id()){
3546      return false;
3547    }
3548    
3549    //If user is related to many companies, a change in user group would change the group in all related companies
3550    //Prevent this from happening
3551    if( ko.toJS(user.related_company_ids).length > 1){
3552      return true;
3553    }
3554    
3555    if(self.isWorkerGroup(user.usergroup_id())){
3556      return true;
3557    }
3558    
3559    return false;
3560  }
3561
3562  self.getRole = function (groupId) {
3563    return self.usergroups
3564      .filter(function (group) {
3565        return group.id === groupId;
3566      })
3567      .map(function (obj) {
3568        return obj.role;
3569      });
3570  };
3571
3572  self.smsInvoicingFeeOptions = [
3573    { value: false, label: 'Ei käytössä' },
3574    { value: true, label: 'Käytössä' },
3575  ];
3576
3577  self.notificationMethods = [
3578    { value: 'disabled', label: 'Älä lähetä' },
3579    { value: 'email', label: 'Sähköposti' },
3580    { value: 'sms', label: 'SMS' },
3581  ];
3582
3583  self.towingNotifications = {
3584    stations: ko.observableArray([]),
3585    jobTypes: ko.observableArray([]),
3586    availableStations: ko.pureComputed(function () {
3587      return self.account.stations().filter(function (value) {
3588        return value.type() === 1 || value.type() === 2;
3589      });
3590    }),
3591    availableJobTypes: ko.pureComputed(function () {
3592      var jobTypes = ko.toJS(self.settings.towingRecordTypes);
3593      jobTypes = jobTypes.filter((type) => type.deleted_at === null);
3594      jobTypes = jobTypes.map(function (type) {
3595        return { id: type.type, type: type.type };
3596      });
3597
3598      if (jobTypes.length === 0) {
3599        ['A', 'B', 'C'].forEach(function (type) {
3600          jobTypes.push({ id: type, type: type });
3601        });
3602      }
3603
3604      jobTypes.unshift({ id: null, type: 'Tyhjä' });
3605
3606      if (self.account.company.mod_assistance()) {
3607        jobTypes.unshift({ id: 'AL', type: 'AL' });
3608      }
3609
3610      return jobTypes;
3611    }),
3612  };
3613
3614  // Dimension related observables
3615  self.dimensionIdToAdd = ko.observable();
3616  self.dimensionTypeOptions = [
3617    { type: 'station', label: 'Toimipiste (Station)' },
3618    { type: 'customer', label: 'Asiakas (Customer)'}
3619  ];
3620
3621  self.dimensionTypeToAdd = ko.observable('station');
3622  self.dimensionNameToAdd = ko.observable();
3623  self.dimensions = ko.observableArray();
3624  self.addDimensionItem = ko.observable(false);
3625  self.addDimension = ko.observable(false);
3626  
3627  self.setDimensions = function(dimensions){
3628    
3629    self.dimensions([]);
3630
3631    console.log('setDimensions:', dimensions);
3632    
3633    if( ! dimensions){
3634      console.log('No dimensions to set');
3635      return;
3636    }
3637   
3638    dimensions.forEach(function(dimension){
3639      self.addProcountorDimension(dimension);
3640    })
3641  };
3642
3643  self.dimensions.subscribe(function (dimensions) {
3644      console.log('self.dimensions changed, dimensions:', dimensions);
3645  }); 
3646
3647  self.dimensionItemIdToAdd = ko.observable();
3648  self.dimensionItemNameToAdd = ko.observable();
3649  self.dimensionItemIvIdToAdd = ko.observable();
3650
3651  self.dimensionToEdit = ko.observable();
3652
3653  self.newLogItem = ko.observable();
3654
3655  // SMS review system related observables
3656  self.reviewData = {
3657    jobTypes: ko.observableArray([]),
3658    availableJobTypes: ko.observableArray([]),
3659    towingRecordJobTypes: ko.observableArray([]),
3660    freightJobTypes: ko.observableArray([]),
3661    jobOrderJobTypes: ko.observableArray([]),
3662    stationSetting: ko.observable(),
3663    messageType: ko.observable(),
3664    message: ko.observable(),
3665    userStatistics: ko.observable(),
3666    settings: ko.observableArray([]),
3667    npsMessage: ko.pureComputed(function () {
3668      return 'Kiitos kun käytit palveluitamme! Asteikolla 0-10, kuinka todennäköisesti suosittelisit meitä ystävälle tai työtoverille? T. ';
3669    }),
3670    ownMessage: ko.pureComputed(function () {
3671      return 'Kiitos kun käytit palveluitamme! Palautteesi on meille tärkeää. Asteikolla 0-10, kuinka tyytyväinen olit saamaasi palveluun? T. ';
3672    }),
3673  };
3674
3675  self.addLogItem = function () {
3676    var companyId = ko.toJS(self.account.company.id),
3677      event = ko.toJS(self.newLogItem);
3678
3679    if (!event) return global.show_message({ type: 'error', text: 'Lokimerkintä on tyhjä' });
3680
3681    jQuery
3682      .ajax({
3683        url: '/asiakkuudet/add_log_item/' + companyId,
3684        dataType: 'json',
3685        data: {
3686          event: event,
3687        },
3688        type: 'post',
3689      })
3690
3691      .done(function (responseJSON) {
3692        self.account.logs.unshift(responseJSON.data.logItem);
3693        self.newLogItem('');
3694      })
3695      .fail(function (response) {
3696        global.show_message(response.responseJSON);
3697      });
3698  };
3699
3700  self.deleteLogItem = function (logItem) {
3701    if (window.confirm('Haluatko varmasti poistaa lokimerkinnän?')) {
3702      var id = ko.toJS(logItem.id);
3703
3704      $.ajax({
3705        url: '/asiakkuudet/delete_log_item/' + id,
3706        type: 'POST',
3707      })
3708        .done(function (responseJSON) {
3709          self.account.logs.remove(function (item) {
3710            return ko.toJS(item.id) == responseJSON.data.deletedLogItem.id;
3711          });
3712        })
3713        .fail(function (response) {
3714          global.show_message(response.responseJSON);
3715        });
3716    }
3717  };
3718
3719  self.removeCompanyRestriction = function(type){
3720    self.companyRestrictions.deleteRestrictions(type, self.setData)
3721  }
3722
3723  self.unselectTag = function (tag) {
3724    self.account.tags.remove(tag);
3725  };
3726
3727  self.showExtraUserSettings = function () {
3728    self.showUserExtraOptions(!self.showUserExtraOptions());
3729  };
3730
3731  self.selectTag = function (tag) {
3732    self.account.tags.push(tag);
3733  };
3734
3735  self.station = function () {
3736    return {
3737      id: ko.observable(),
3738      name: ko.observable(),
3739      short_name: ko.observable(),
3740      type: ko.observable(),
3741      address: ko.observable(),
3742      zipcode: ko.observable(),
3743      city: ko.observable(),
3744      accept_autoliitto_orders: ko.observable(),
3745      autoliitto_id: ko.observable(),
3746      autoliitto_phone: ko.observable(),
3747      autoliitto_email: ko.observable(),
3748      accept_sos_orders: ko.observable(false),
3749      email_notifications: ko.observable(),
3750      lahitapiola_direct_contract: ko.observable(false),
3751      sos_phone: ko.observable(),
3752      sos_call_robot_open_order: ko.observable(false),
3753      sos_call_robot_order_cancelled: ko.observable(false),
3754      sos_call_robot_use_ivr: ko.observable(false),
3755      sos_call_robot_open_order_phone: ko.observable(),
3756      sos_email: ko.observable(),
3757      coords_lat: ko.observable(),
3758      coords_long: ko.observable(),
3759      telegram_notifications: ko.observable(false),
3760      telegram_chat_id: ko.observable(),
3761      telegram_notifications_order_pending_acceptance: ko.observable(false),
3762      telegram_notifications_open_order: ko.observable(false),
3763      telegram_notifications_order_cancelled: ko.observable(true),
3764      ava_integration: ko.observable(false),
3765      urent_phone: ko.observable(),
3766      urent_call_robot_open_order: ko.observable(),
3767      urent_call_robot_order_cancelled: ko.observable(),
3768      urent_call_robot_use_ivr: ko.observable(),
3769      // @ai:claude Which provider receives incoming Autoliitto replacement car orders for this station.
3770      replacement_car_provider: ko.observable()
3771    };
3772  };
3773
3774  self.sendAutoliittoTestJob = function(station, jobType) {
3775    var station = ko.toJS(station);
3776
3777    if (!station.autoliitto_id)
3778      return alert('Autoliitto ID:tä ei ole täytetty, testikeikkaa ei voida lähettää');
3779
3780    self.confirmSendTestJob(station, 'autoliitto', jobType);
3781  };
3782
3783  self.sendLahiTapiolaTestJob = function (station) {
3784    var station = ko.toJS(station);
3785
3786    if (!station.autoliitto_id)
3787      return alert('Autoliitto ID:tä ei ole täytetty, testikeikkaa ei voida lähettää');
3788
3789    self.confirmSendTestJob(station, 'lahitapiola');
3790  };
3791
3792  self.sendSosTestJob = function (station) {
3793    var station = ko.toJS(station);
3794
3795    if (!station.accept_sos_orders)
3796      return alert(
3797        'Toimipistettä ei ole merkitty vastaanottamaan SOS-tilauksia, testikeikkaa ei voida lähettää'
3798      );
3799
3800    self.confirmSendTestJob(station, 'sos');
3801  };
3802
3803  self.sendUrentTestJob = function (station) {
3804    var station = ko.toJS(station);
3805    self.confirmSendTestJob(station, 'urent');
3806  }
3807
3808  self.sendStationTestMessage = function (station, notificationChannel) {
3809    var station = ko.toJS(station);
3810
3811    self.confirmSendTestMessage(station, notificationChannel);
3812  };
3813
3814  self.addStation = function (data) {
3815    var station = self.station();
3816    self.account.stations.push(station);
3817  };
3818
3819  self.removeStation = function (station) {
3820    // If existing user, confirm the removal
3821    if (station.id()) {
3822      return self.confirmRemoveStation(station);
3823    }
3824
3825    self.account.stations.remove(station);
3826  };
3827
3828  self.confirmSendTestJob = function(station, orderOrigin, jobType) {
3829
3830    var url;
3831
3832    if(orderOrigin === 'autoliitto')
3833      url = '/tilaukset/new_autoliitto_test_job';
3834
3835    if(orderOrigin === 'sos')
3836      url = '/tilaukset/new_sos_test_job';
3837
3838    if(orderOrigin === 'lahitapiola')
3839      url = '/tilaukset/new_lahitapiola_test_job';
3840
3841    if(orderOrigin === 'urent')
3842      url = '/tilaukset/new_urent_test_job';
3843
3844    var $dialog = $('<div />')
3845        .html(
3846            '<p style="font-weight:bold;"><span class="ui-icon ui-icon-alert" style="float:left; margin:0 7px 20px 0; "></span>Haluatko varmasti lähettää testikeikan asiakkaalle?</p>'
3847        )
3848        .dialog({
3849          resizable: false,
3850          height: 200,
3851          width: 400,
3852          title: 'Vahvista testikeikan lähetys',
3853          modal: true,
3854          buttons: {
3855            Ei: function() {
3856              $(this).dialog('close');
3857            },
3858            Kyllä: function() {
3859
3860              jQuery
3861                  .ajax({
3862                    url:  url,
3863                    data: {
3864                      stationId: station.id,
3865                      jobType: jobType
3866                    },
3867                    type: 'post',
3868                    dataType: 'json',
3869                    "beforeSend":function(request){
3870                      $dialog.dialog({
3871                       width:400,
3872                        height:200,
3873                        modal:true,
3874                        resizable:false,
3875                        title:'Lähetetään testikeikkaa',
3876                        close: function(){
3877                          $dialog.dialog('destroy');
3878                        }
3879                      });
3880
3881                  global.show_ajax_loader($dialog);
3882                },
3883              })
3884              .done(function (responseJSON) {
3885                $dialog.dialog('close');
3886                global.show_message(responseJSON);
3887              })
3888              .fail(function (response) {
3889                global.show_message(response.responseJSON);
3890              })
3891              .always(function () {
3892                global.close_loading_dialog();
3893              });
3894          },
3895        },
3896      });
3897  };
3898
3899  self.confirmSendTestMessage = function (station, notificationChannel) {
3900    var $dialog = $('<div />')
3901      .html(
3902        '<p style="font-weight:bold;"><span class="ui-icon ui-icon-alert" style="float:left; margin:0 7px 20px 0; "></span>
3902Haluatko varmasti lähettää testiviestin toimipisteelle?</p>'
3903      )
3904      .dialog({
3905        resizable: false,
3906        height: 200,
3907        width: 400,
3908        title: 'Vahvista testiviestin lähetys',
3909        modal: true,
3910        buttons: {
3911          Ei: function () {
3912            $(this).dialog('close');
3913          },
3914          Kyllä: function () {
3915            jQuery
3916              .ajax({
3917                url: '/asiakkuudet/send_station_test_message',
3918                data: {
3919                  stationId: station.id,
3920                  notificationChannel: notificationChannel,
3921                },
3922                type: 'post',
3923                dataType: 'json',
3924                beforeSend: function (request) {
3925                  $dialog.dialog({
3926                    width: 400,
3927                    height: 200,
3928                    modal: true,
3929                    resizable: false,
3930                    title: 'Lähetetään testiviestiä',
3931                    close: function () {
3932                      $dialog.dialog('destroy');
3933                    },
3934                  });
3935
3936                  global.show_ajax_loader($dialog);
3937                },
3938              })
3939              .done(function (responseJSON) {
3940                global.show_message(responseJSON);
3941              })
3942              .fail(function (response) {
3943                global.show_message(response.responseJSON);
3944              })
3945              .always(function () {
3946                $dialog.dialog('close');
3947              });
3948          },
3949        },
3950      });
3951  };
3952
3953  self.getBlockMoneyTransferReason = function () {
3954    var checked = self.account.company.block_money_transfer();
3955    var type = checked ? 'asetuksen' : 'poiston';
3956    var kycText = checked ? 'KYC suorittamatta' : 'KYC suoritettu'
3957    var dialogInput = $('<input />', {
3958      type: 'text',
3959      name: 'transfer_block_reason',
3960      id: 'transfer_block_reason',
3961      class: 'text form-control medium',
3962      style: 'border-top-right-radius: 0; border-bottom-right-radius: 0;'
3963    });
3964    var kycButton = $('<button />', {
3965      text: 'KYC',
3966      type: 'button',
3967      class: 'btn btn-default',
3968      click: function() {
3969        $('#transfer_block_reason').val(kycText);
3970      },
3971      style: 'height: 34px; border-top-left-radius: 0; border-bottom-left-radius: 0;'
3972    });
3973
3974    var $dialog = $('<div />')
3975      .html('<p style="font-weight:bold;">Tilitysten eston ' + type + ' syy:</p>')
3976      .append(dialogInput)
3977      .append(kycButton)
3978      .dialog({
3979        resizable: false,
3980        height: 200,
3981        width: 400,
3982        title: 'Tilitysten esto',
3983        modal: true,
3984        buttons: {
3985          Peruuta: function () {
3986            $(this).dialog('close');
3987          },
3988          Lisää: function () {
3989            var reason = $(this).find('#transfer_block_reason').val();
3990            if (reason && reason !== '') {
3991              var logMessage = checked
3992                ? 'Tilitysten eston asetus: ' + reason
3993                : 'Tilitysten eston poisto: ' + reason;
3994              self.moneyTransferBlockReason(logMessage);
3995              $(this).dialog('close');
3996            } else {
3997              global.show_message({
3998                type: 'error',
3999                text: 'Tilitysten eston ' + type + ' syy puuttuu',
4000              });
4001            }
4002          },
4003        },
4004        close: function () {
4005          //var reason = $(this).find('#transfer_block_reason').val();
4006          if (
4007            self.moneyTransferBlockReason() === '' &&
4008            self.account.company.block_money_transfer() != self.BlockMoneyTransferOld()
4009          ) {
4010            self.account.company.block_money_transfer(self.BlockMoneyTransferOld());
4011          }
4012          $(this).dialog('destroy').remove();
4013        },
4014      });
4015  };
4016
4017  self.confirmRemoveStation = function (station) {
4018    var $dialog = $('<div />')
4019      .html(
4020        '<p style="font-weight:bold;"><span class="ui-icon ui-icon-alert" style="float:left; margin:0 7px 20px 0; "></span>Haluatko varmasti poistaa kyseisen hinausyksikön?</p>'
4021      )
4022      .dialog({
4023        resizable: false,
4024        height: 200,
4025        width: 400,
4026        title: 'Poista hinausyksikkö',
4027        modal: true,
4028        buttons: {
4029          Ei: function () {
4030            $(this).dialog('close');
4031          },
4032          Kyllä: function () {
4033            jQuery
4034              .ajax({
4035                url: '/asiakkuudet/delete_station/' + station.id(),
4036                type: 'post',
4037                dataType: 'json',
4038              })
4039              .done(function (responseJSON) {
4040                self.account.stations.remove(station);
4041                $dialog.dialog('close');
4042                global.show_message(responseJSON);
4043
4044                // If this company has reviews enabled and they're using own settings for each station, we should delete
4045                // those settings too
4046                if (self.account.company.mod_review() && self.reviewData.stationSetting() == 1)
4047                  self.deleteStationSettings(station.id());
4048              })
4049              .fail(function (response) {
4050                global.show_message(response.responseJSON);
4051                global.close_loading_dialog();
4052              });
4053          },
4054        },
4055      });
4056  };
4057
4058  var modifyTypeDataOnServer = function (data) {
4059    var action = data.action;
4060
4061    jQuery
4062      .ajax({
4063        url: 'asiakkuudet/modifyTypeData',
4064        data: data,
4065      })
4066      .done(function (data) {
4067        self.settings.towingRecordTypes(
4068          self.settings.towingRecordTypes().map(function (type) {
4069            return type.id === data.id ? data : type;
4070          })
4071        );
4072
4073        if (action === 'disable') {
4074          self.reviewData.availableJobTypes.remove(function (item) {
4075            return item.id === 'kk' + data.id;
4076          });
4077          self.reviewData.jobTypes.remove(function (item) {
4078            return item.id === 'kk' + data.id;
4079          });
4080        } else {
4081          self.reviewData.availableJobTypes.push({
4082            id: 'kk' + data.id,
4083            label: data.type + ' (IH)',
4084          });
4085        }
4086      });
4087  };
4088
4089  var modifyFreightTypeDataOnServer = function (data) {
4090    var action = data.action;
4091
4092    jQuery
4093      .ajax({
4094        url: 'asiakkuudet/modifyFreightTypeData',
4095        data: data,
4096      })
4097      .done(function (data) {
4098        self.settings.freightTypes(
4099          self.settings.freightTypes().map(function (type) {
4100            return type.id === data.id ? data : type;
4101          })
4102        );
4103
4104        if (action === 'disable') {
4105          self.reviewData.availableJobTypes.remove(function (item) {
4106            return item.id === 'rk' + data.id;
4107          });
4108          self.reviewData.jobTypes.remove(function (item) {
4109            return item.id === 'rk' + data.id;
4110          });
4111        } else {
4112          self.reviewData.availableJobTypes.push({
4113            id: 'rk' + data.id,
4114            label: data.type + ' (IR)',
4115          });
4116        }
4117      });
4118  };
4119
4120  var modifyJobOrderTypeDataOnServer = function (data) {
4121    jQuery
4122      .ajax({
4123        url: 'asiakkuudet/modifyJobOrderTypeData',
4124        data: data,
4125      })
4126      .done(function (data) {
4127        self.settings.jobOrderTypes(
4128          self.settings.jobOrderTypes().map(function (name) {
4129            return name.id === data.id ? data : name;
4130          })
4131        );
4132      });
4133  };
4134
4135  var modifyResourceOnServer = function (data) {
4136    jQuery
4137      .ajax({
4138        url: 'asiakkuudet/modifyResources',
4139        data: data,
4140      })
4141      .done(function (data) {
4142        self.settings.resources(
4143          self.settings.resources().map(function (name) {
4144            return name.id === data.id ? data : name;
4145          })
4146        );
4147      });
4148  };
4149
4150  var modifyDepotsOnServer = function (data) {
4151    jQuery
4152      .ajax({
4153        url: 'asiakkuudet/modifyDepots',
4154        data: data,
4155      })
4156      .done(function (data) {
4157        self.settings.depots(
4158          self.settings.depots().map(function (name) {
4159            return name.id === data.id ? data : name;
4160          })
4161        );
4162      });
4163  };
4164
4165  var modifyAgreementOnServer = function (data) {
4166    jQuery
4167      .ajax({
4168        url: 'asiakkuudet/modifyAgreement',
4169        data: data,
4170      })
4171      .done(function (data) {
4172        if (data.type === 'default') {
4173          self.settings.agreements(
4174            self.settings.agreements().map(function (agreement) {
4175              return agreement.id === data.id ? data : agreement;
4176            })
4177          );
4178        }
4179        if (data.type === 'innokorjaamo') {
4180          self.settings.agreements_innokorjaamo(
4181            self.settings.agreements_innokorjaamo().map(function (agreement) {
4182              return agreement.id === data.id ? data : agreement;
4183            })
4184          );
4185        }
4186      });
4187  };
4188
4189  self.insertTypeData = function () {
4190    var data = ko.toJS(self.account.company);
4191    data.typeToAdd = self.settings.typeToAdd();
4192
4193    jQuery
4194      .ajax({
4195        url: 'asiakkuudet/addTypeData',
4196        data: data,
4197      })
4198      .done(function (data) {
4199        self.settings.towingRecordTypes.push(data);
4200        self.reviewData.availableJobTypes.push({ id: 'kk' + data.id, label: data.type + ' (IH)' });
4201        self.settings.typeToAdd('');
4202      });
4203  };
4204
4205  self.insertFreightTypeData = function () {
4206    var data = ko.toJS(self.account.company);
4207    data.freightTypeToAdd = self.settings.freightTypeToAdd();
4208
4209    jQuery
4210      .ajax({
4211        url: 'asiakkuudet/addFreightTypeData',
4212        data: data,
4213      })
4214      .done(function (data) {
4215        self.settings.freightTypes.push(data);
4216        self.reviewData.availableJobTypes.push({ id: 'rk' + data.id, label: data.type + ' (IR)' });
4217        self.settings.freightTypeToAdd('');
4218      });
4219  };
4220
4221  self.insertJobOrderTypeData = function () {
4222    var data = ko.toJS(self.account.company);
4223    data.jobOrderTypeToAdd = self.settings.jobOrderTypeToAdd();
4224
4225    jQuery
4226      .ajax({
4227        url: 'asiakkuudet/addJobOrderTypeData',
4228        data: data,
4229      })
4230      .done(function (data) {
4231        self.settings.jobOrderTypes.push(data);
4232        self.settings.jobOrderTypeToAdd('');
4233      });
4234  };
4235
4236  self.insertAgreement = function (type) {
4237    var data = ko.toJS(self.account.company);
4238    data.agreementToAdd = self.settings.agreementToAdd();
4239    data.type = type
4240    jQuery
4241      .ajax({
4242        url: 'asiakkuudet/addAgreeement',
4243        data: data,
4244      })
4245      .done(function (data) {
4246        if (data.type === 'default') {
4247          self.settings.agreements.push(data);
4248        }
4249        if (data.type === 'innokorjaamo') {
4250          self.settings.agreements_innokorjaamo.push(data);
4251        }
4252      }).always(function() {
4253        self.settings.agreementToAdd('');
4254      });
4255  };
4256
4257  self.insertResource = function () {
4258    var companyId = self.account.company.id();
4259    var resource = self.settings.resourceToAdd.resource();
4260    var extId = self.settings.resourceToAdd.ext_id();
4261
4262    jQuery
4263      .ajax({
4264        method: 'post',
4265        url: 'asiakkuudet/addResource',
4266        data: {
4267          company_id: companyId,
4268          resource: resource,
4269          ext_id: extId,
4270        },
4271      })
4272      .done(function (data) {
4273        self.settings.resources.push(data);
4274        self.settings.resourceToAdd.resource(null);
4275        self.settings.resourceToAdd.ext_id(null);
4276      });
4277  };
4278
4279  self.insertDepots = function () {
4280    var data = ko.toJS(self.account.company);
4281    data.depotToAdd = self.settings.depotToAdd();
4282    jQuery
4283      .ajax({
4284        url: 'asiakkuudet/addDepots',
4285        data: data,
4286      })
4287      .done(function (data) {
4288        self.settings.depots.push(data);
4289        self.settings.depotToAdd('');
4290      });
4291  };
4292  
4293  self.addProcountorDimension = function (dimensionParam) {
4294    
4295    console.log('addProcountorDimension:', dimensionParam);
4296    
4297    if( ! dimensionParam){
4298      dimensionParam = {
4299        id: '',
4300        name: '',
4301        type: 'station',
4302        isEditable: true
4303      };
4304    }
4305
4306    var dimension = {
4307      type: ko.observable(dimensionParam.type),
4308      id: ko.observable(dimensionParam.id),
4309      name: ko.observable(dimensionParam.name),
4310      items: ko.observableArray( []),
4311      isEditable: ko.observable(dimensionParam.isEditable),
4312      showItems: ko.observable(true),
4313
4314      toggleShowItems: function(){
4315        dimension.showItems( ! dimension.showItems());
4316      },
4317      edit: function(){
4318        dimension.isEditable(true)
4319      },
4320      delete: function(){
4321        
4322        console.log('dimension.delete called');
4323        
4324        if(dimension.id()){
4325          dimension.confirmDelete();
4326        }else {
4327          self.dimensions.remove(dimension);
4328        }
4329      },
4330      confirmDelete: function () {
4331
4332        var $dialog = $('<div />')
4333            .html(
4334                '<p style="font-weight:bold;"><span class="ui-icon ui-icon-alert" style="float:left; margin:0 7px 20px 0; "></span>Haluatko varmasti poistaa dimension?</p>'
4335            )
4336            .dialog({
4337              resizable: false,
4338              height: 200,
4339              width: 400,
4340              title: 'Poista Dimensio',
4341              modal: true,
4342              buttons: {
4343                Ei: function () {
4344                  $(this).dialog('close');
4345                },
4346                Kyllä: function () {
4347                  self.dimensions.remove(dimension);
4348                  $(this).dialog('close');
4349                },
4350              },
4351            });
4352      },
4353      removeItem: function(item){
4354        
4355        console.log('removeItem:', item);
4356
4357        if (item.itemId) {
4358          return dimension.confirmRemoveDimensionItem(item);
4359        }else {
4360          dimension.items.remove(item);
4361        }
4362      },
4363      confirmRemoveDimensionItem: function (item) {
4364        
4365        console.log('confirmRemoveDimensionItem:', item);
4366        
4367        var itemName =  ko.toJS(item.itemName);
4368
4369        var $dialog = $('<div />')
4370            .html(
4371                '<p style="font-weight:bold;"><span class="ui-icon ui-icon-alert" style="float:left; margin:0 7px 20px 0; "></span>Haluatko varmasti poistaa dimensioarvon ' +
4372                itemName +
4373                '?</p>'
4374            )
4375            .dialog({
4376              resizable: false,
4377              height: 200,
4378              width: 400,
4379              title: 'Poista Dimensioarvo',
4380              modal: true,
4381              buttons: {
4382                Ei: function () {
4383                  $(this).dialog('close');
4384                },
4385                Kyllä: function () {
4386
4387                  dimension.items.remove(item);
4388                  $(this).dialog('close');
4389                },
4390              },
4391            });
4392      },
4393      accept: function(){
4394        dimension.isEditable(false);
4395        self.addDimension(false);
4396      },
4397      setItems: function (items) {
4398        
4399        dimension.items([]);
4400
4401        console.log('setItems:', items);
4402
4403        if( ! items){
4404          console.log('No items to set');
4405          return;
4406        }
4407
4408        items.forEach(function(item){
4409          dimension.addItem(item);
4410        })
4411      },
4412      addItem: function(item){
4413
4414        var item = {
4415          itemIvId: ko.observable(ko.toJS(item.itemIvId) || ''),
4416          itemId:  ko.observable(ko.toJS(item.itemId) || ''),
4417          itemName:  ko.observable(ko.toJS(item.itemName) || '')
4418        }
4419
4420        dimension.items.push(item);
4421      }
4422    };
4423
4424    if(dimensionParam){
4425      dimension.setItems(dimensionParam.items);
4426    }
4427    
4428
4429    console.log('before self.dimensions.push:', dimension);
4430    
4431    self.dimensions.push(dimension);
4432    self.addDimension(true);
4433  }
4434  
4435  self.incidentInpection = function () {
4436    var data = ko.toJS(self.account.company),
4437      companyId = data.id,
4438      controllerName = data.incident_inspection_controller_name,
4439      controllerIdentifier = data.incident_inspection_controller_identifier;
4440
4441    self.company.incident_inspection_controller_name = ko.observable();
4442    self.company.incident_inspection_controller_identifier = ko.observable();
4443
4444    controllerName = self.settings.incident_inspection_controller_name;
4445    controllerIdentifier = self.settings.incident_inspection_controller_identifier;
4446
4447    jQuery
4448      .ajax({
4449        url: 'asiakkuudet/addIncidentInspection /' + companyId,
4450        data: { controller_name: controllerName, controller_identifier: controllerIdentifier },
4451      })
4452      .done(function (data) {
4453        self.settings.push(data);
4454      });
4455  };
4456
4457  self.deleteSmsTemplate = function (id) {
4458    if (!id) {
4459      return self.settings.sms_templates.remove(this);
4460    }
4461    var ok = window.confirm('Haluatko varmasti poistaa SMS viestipohjan?');
4462    if (!ok) {
4463      return;
4464    }
4465    jQuery.ajax({
4466      method: 'post',
4467      url: '/asiakkuudet/deleteSmsTemplate',
4468      data: {
4469        company_id: self.account.company.id(),
4470        id: id,
4471      }
4472    }).then((resp) => {
4473        self.settings.sms_templates.remove(this)
4474    }).fail((resp) => {
4475        var msg = resp.responseJSON || 'Palvelinvirhe: Viestipohjan poisto epäonnistui';
4476        global.show_message({ type: 'error', text: msg });
4477    });
4478  };
4479
4480  self.addSmsTemplate = function () {
4481    self.settings.sms_templates.push({
4482      id: ko.observable(null),
4483      title: ko.observable(''),
4484      timing: ko.observable('+0 day'),
4485      trigger: ko.observable(null),
4486      template: ko.observable(''),
4487    });
4488  };
4489
4490  self.modifyAgreementData = function (action, agreement) {
4491    agreement.action = action;
4492    return modifyAgreementOnServer(agreement);
4493  };
4494
4495  self.modifyTypeData = function (action, type) {
4496    type.action = action;
4497    return modifyTypeDataOnServer(type);
4498  };
4499
4500  self.modifyFreightTypeData = function (action, type) {
4501    type.action = action;
4502    return modifyFreightTypeDataOnServer(type);
4503  };
4504
4505  self.modifyJobOrderTypeData = function (action, type) {
4506    type.action = action;
4507    return modifyJobOrderTypeDataOnServer(type);
4508  };
4509
4510  self.modifyDepots = function (action, name) {
4511    name.action = action;
4512    return modifyDepotsOnServer(name);
4513  };
4514
4515  self.modifyResource = function (action, name) {
4516    name.action = action;
4517
4518    return modifyResourceOnServer(name);
4519  };
4520
4521  self.companyGroupSettings = {
4522    companyGroupId: ko.observable(),
4523  };
4524
4525  self.companyGroups = [
4526    { value: null, text: 'Ei kuulu yritysryhmään' },
4527    { value: 1, text: 'Autoklinikka' },
4528  ];
4529
4530  self.corporateChains = [
4531    { value: '', text: 'Ei kuulu ketjuun' },
4532    { value: 'Autoasi', text: 'Autoasi' },
4533    { value: 'Autonomi', text: 'Autonomi' },
4534    { value: 'Autoklinikka', text: 'Autoklinikka' },
4535    { value: 'Autoklinikka partneri', text: 'Autoklinikka partneri' },
4536    { value: 'Fixus', text: 'Fixus' },
4537    { value: 'Awux', text: 'Awux' },
4538    { value: 'KL', text: 'KL' },
4539    { value: 'Motonet', text: 'Motonet' },
4540    { value: 'Scandia Rent', text: 'Scandia Rent' },
4541    { value: '123 Tuulilasi', text: '123 Tuulilasi' },
4542    { value: 'Autoliitto', text: 'Autoliitto' },
4543    { value: 'AL tiepalvelu', text: 'AL tiepalvelu' },
4544    { value: 'Menevä', text: 'Menevä' },
4545    { value: 'Vaurioturva', text: 'Vaurioturva' },
4546  ];
4547
4548  self.themes = [
4549    { value: 'default', text: 'Innovoice' },
4550    { value: 'tuulilasi', text: '123 Tuulilasi' },
4551    { value: 'scandia', text: 'Scandia Rent' },
4552    { value: 'fixus', text: 'Fixus' },
4553    { value: 'awux', text: 'Awux' },
4554    { value: 'motonet', text: 'Motonet' },
4555    { value: 'vaurioturva', text: 'Vaurioturva' },
4556  ];
4557
4558  self.invoiceDeliveryMethods = [
4559    { value: 'e_invoice', text: 'Verkkolasku' },
4560    { value: 'email', text: 'Sähköpostitse' },
4561    { value: 'mail', text: 'Postitse' },
4562  ];
4563
4564  self.vatBases = [0, 10, 13.5, 14, 25.5];
4565
4566  self.companyFinancingPaymentTerms = [
4567    { text: '14pv netto', value: '14_days_net' },
4568    { text: '30pv netto', value: '30_days_net' },
4569  ];
4570
4571  self.consumerFinancingPaymentTerms = [
4572    { text: '14pv netto', value: '14_days_net' },
4573    { text: '30pv netto', value: '30_days_net' },
4574  ];
4575
4576  self.accountingServices = [
4577    { value: '', text: 'Ei kirjanpitosovellusta' },
4578    { value: 'procountor', text: 'Procountor' },
4579    { value: 'netvisor', text: 'Netvisor' },
4580  ];
4581
4582  self.invoiceSendingFrequencies = [
4583    { value: 'daily', text: 'Kerran päivässä' },
4584    { value: 'weekly', text: 'Kerran viikossa' },
4585    { value: 'monthly', text: 'Kerran kuukaudessa' },
4586  ];
4587
4588  self.account = null;
4589  self.logoBase64 = ko.observable('');
4590
4591  self.copyValue = function (target, value) {
4592    // If the target field is empty, copy the value to it
4593    if (!target()) {
4594      target(value);
4595    }
4596  };
4597  self.BlockMoneyTransferOld = ko.observable();
4598  self.moneyTransferBlockReason = ko.observable('');
4599  self.setBlockMoneyTransfer = function () {
4600    if (self.account.company.id()) {
4601      self.getBlockMoneyTransferReason();
4602    }
4603  };
4604
4605  self.setData = function (data) {
4606    self.setSettingsData(data);
4607
4608    if (typeof data.static !== 'undefined') {
4609      self.setStaticData(data.static);
4610    }
4611    self.setAccountData(data.account);
4612    if (typeof data.logItem !== 'undefined') {
4613      self.account.logs.unshift(data.logItem);
4614    }
4615    self.reviewData.settings([]);
4616
4617    if (data.account.company.mod_review === true) self.setReviewData(data);
4618    if (data.paymentTerminalDevices) {
4619      self.paymentTerminalDevices(data.paymentTerminalDevices);
4620    }
4621
4622    if(data.followUpSettings){
4623      self.populateFollowUpSettings(data.followUpSettings);
4624    }else{
4625      self.resetFollowUpSettings();
4626    }
4627
4628    if(data.defaultFollowUpSmsTemplate){
4629      self.defaultFollowUpSmsTemplate(data.defaultFollowUpSmsTemplate);
4630    }
4631
4632    if (typeof data.subscriptionDefaults !== 'undefined') {
4633      self.subscriptionDefaults = data.subscriptionDefaults;
4634      //self.setDefaultsToServiceSubscriptions();
4635    }
4636    self.companyRestrictions.getRestrictions(self.account.company.id());
4637
4638    self.companyDocuments.setData(data.companyDocuments, self.account.company.id());
4639    self.companyDocuments.setUnsignedDocumentsData(data.unsignedDocuments, self.account.company.email()
4639);
4640
4641    self.companyMessagingDetailOptions(data.companyMessagingDetailOptions);
4642    self.companyMessagingDetails.setData(self.account.company.id(), data.companyMessagingDetails);
4643
4644    // Null for a company that is not on Procountor, which the sub view model renders as unavailable
4645    self.accounting.setData(data.accountingSettings || null);
4646
4647    self.setSubscriptionData(data.subscriptions, self.account.company.id());
4648    self.initDatepicker();
4649
4650    if (self.account.kyc && (self.account.kyc.history().length > 0 || self.account.kyc.actualStatus() != 'draft') ) {
4651      self.disableAllKycInputs();
4652    } else {
4653      self.enableAllKycInputs();
4654    }
4655
4656    if (data.apiKeys) {
4657      self.apiKeys(data.apiKeys);
4658    }
4659
4660    self.kycOyParentOwners = ko.computed(function() {
4661      return self.account && self.account.kyc && self.account.kyc.owners ? self.account.kyc.owners().filter(function(o) {
4662       return o.type() === 'oy' && o.stake() > 25;
4663      }) : [];
4664    });
4665
4666    self.kycOtherParentOwners = ko.computed(function() {
4667      return self.account && self.account.kyc && self.account.kyc.owners ? self.account.kyc.owners().filter(function(o) {
4668       return (o.type() === 'ay' || o.type() === 'ko') && o.stake() > 25;
4669      }) : [];
4670    });
4671
4672    self.setKycManualAcceptanceRequired(false);
4673    self.continueInterval(false);
4674
4675    self.kredinorSubscriptionCount(data.kredinorSubscriptionCount);
4676
4677    self.subcontractingCompanies([]);
4678    self.subcontractingSearch('');
4679    self.subcontractingSearchResults([]);
4680    self.subcontractingSearchNoResults(false);
4681    self.subcontractingSearchLoading(false);
4682
4683    var companyId = self.account && self.account.company && self.account.company.id
4684      ? ko.unwrap(self.account.company.id)
4685      : null;
4686    if (companyId) {
4687      self.fetchSubcontractingCompanies(companyId);
4688    }
4689  };
4690
4691  self.setSettingsData = function (data) {
4692    self.settings.shiftGroupSettings.removeAll();
4693    self.settings.towingRecordTypes(data.towingRecordTypes);
4694    self.settings.roles(data.roles);
4695    data.shiftGroupSettings.forEach((s) =>
4696      self.settings.shiftGroupSettings.push(createNewShiftSettingGroup(s))
4697    );
4698    self.settings.freightTypes(data.freigthTypes);
4699    self.settings.jobOrderTypes(data.jobOrderTypes);
4700    self.settings.companyGroups(data.companyGroups);
4701    self.settings.depots(data.depots);
4702    self.settings.resources(data.resources);
4703    self.settings.spare_parts(data.spare_parts);
4704
4705    // Preset to null, so that the state is npt preserved when editing multiple accounts in sequence
4706    self.selectedCategory(null);
4707    self.settings.subCategoryToAdd(null);
4708    self.settings.categoryToAdd(null);
4709    self.selectedCompanyGroups([])
4710    self.noConnectionFee(false)
4711
4712    self.settings.glAccounts(data.gl_accounts || []);
4713    self.settings.glAccountToAdd.gl_account(null);
4714    self.settings.glAccountToAdd.desc(null);
4715
4716    self.settings.categories(data.categories.map((c) => new Category(c)));
4717
4718    if (data.messageTriggers) {
4719      self.smsMessageTriggers.removeAll();
4720      data.messageTriggers.forEach(trigger => {
4721        self.smsMessageTriggers.push(trigger)
4722      });
4723    }
4724
4725    if (data.messageTimings) {
4726      self.smsMessageTimings.removeAll();
4727      data.messageTimings.forEach(timing => {
4728        self.smsMessageTimings.push(timing)
4729      });
4730    }
4731
4732    if (data.account) {
4733      self.settings.agreements(data.account.agreements);
4734      self.settings.agreements_innokorjaamo(data.account.agreements_innokorjaamo);
4735      self.settings.sms_templates.removeAll();
4736      data.account.sms_templates.forEach(template => {
4737        self.settings.sms_templates.push({
4738          id: ko.observable(template.id),
4739          title: ko.observable(template.title),
4740          template: ko.observable(template.template),
4741          trigger: ko.observable(template.trigger),
4742          timing: ko.observable(template.timing),
4743        })
4744      });
4745    }
4746
4747    if(data.companyGroups){
4748      var active = data.companyGroups.filter(g => g.active === true).map(g => Number(g.id))
4749      active.forEach(id => self.selectedCompanyGroups.push(id))
4750    }
4751  };
4752
4753  self.addEmptyShiftSetting = function () {
4754    self.settings.shiftGroupSettings.push(
4755      createNewShiftSettingGroup({
4756        enable_evening: true,
4757        enable_overtime: true,
4758        enable_standby: true,
4759        enable_wait: true,
4760        enable_night: true,
4761      })
4762    );
4763  };
4764
4765  self.deleteShiftSetting = function (shift) {
4766    self.settings.shiftGroupSettings.remove(shift);
4767  };
4768
4769  self.setStaticData = function (staticData) {
4770    self.autoklinikkaBranches = staticData.akBranches;
4771    self.accountManagers = staticData.accountManagers;
4772    self.accountManagers.unshift({id: null, username: '', sales_name:'Ei asiakasvastaavaa'});
4773    self.usergroups = staticData.usergroups;
4774    self.mfaUsergroups = JSON.parse(JSON.stringify(self.usergroups));
4775    self.mfaUsergroups.unshift({access_level: null, group_name: '-- Ei vaadittu tunnistautumista --'});
4776    self.usergroups.unshift({access_level: null, group_name: '-- Valitse --'});
4777    self.eInvoiceOperators = staticData.eInvoiceOperators;
4778    self.workingFields = staticData.workingFields;
4779  };
4780
4781  self.noConnectionFee = ko.observable(false);
4782  self.noConnectionFee.subscribe(function(newValue) {
4783    if(self.account && self.account.preferences && !self.account.company.id())
4784      self.noConnectionFee(newValue);
4785      self.account.preferences.connection_fee(0);
4786  });
4787
4788  self.setAccountData = function (accountData) {
4789    //Remove the logo from accountData and place it in own observable, so it wont be sent back to the server
4790    self.logoBase64(accountData.company.logo_base64);
4791    delete accountData.company.logo_base64;
4792
4793    if (self.account) {
4794      // @TEMP HACK. Remove after we allow sales persons to change
4795      // a users shift working group
4796      if (accountData.users) {
4797        accountData.users = accountData.users.map((u) => {
4798          u.hadPreviousShiftSettingId = u.shift_group_setting_id;
4799          return u;
4800        });
4801      }
4802      ko.mapping.fromJS(accountData, {}, self.account);
4803    } else {
4804      self.account = ko.mapping.fromJS(accountData);
4805      self.bindExtenders();
4806      self.bindComputedObservables();
4807      self.bindSubscribers();
4808    }
4809
4810    //self.dimensions([]);
4811  
4812    if (
4813      self.account.preferences_procountor &&
4814      self.account.preferences_procountor.dimensions &&
4815      self.account.preferences_procountor.dimensions() !== null
4816    ) {
4817      console.log(self.account.preferences_procountor.dimensions, JSON.parse(ko.toJS(self.account.preferences_procountor.dimensions)));
4818      self.setDimensions(JSON.parse(ko.toJS(self.account.preferences_procountor.dimensions)));
4819    }
4820   
4821    if (
4822      self.account.preferences_procountor &&
4823      self.account.preferences_procountor.reminder_email &&
4824      self.account.preferences_procountor.reminder_email() == ''
4825    ) {
4826      self.account.preferences_procountor.reminder_email(self.account.company.email());
4827    }
4828
4829    //Block money transfers and enable sales monitoring for newly created accounts and enable MFA
4830    if (!self.account.company.id()) {
4831      self.account.company.block_money_transfer(true);
4832      self.account.company.sales_monitoring(true);
4833      self.account.company.mod_multifactor_authentication(1);
4834      self.account.preferences.min_access_level_required_to_use_mfa(DEFAULT_USER_ACCESS_LEVEL);
4835      self.account.preferences.connection_fee(DEFAULT_CONNECTION_FEE);
4836      self.account.company.is_trial(true);
4837    } else {
4838      self.BlockMoneyTransferOld(self.account.company.block_money_transfer());
4839    }
4840
4841    var towingNotificationData = accountData.preferences.towing_customer_notification_settings;
4842
4843    if (towingNotificationData) {
4844      towingNotificationData = JSON.parse(towingNotificationData);
4845      self.towingNotifications.stations(towingNotificationData.stations);
4846      self.towingNotifications.jobTypes(towingNotificationData.jobTypes);
4847
4848      $('.notifications-stations-select').selectpicker('refresh');
4849      $('.notifications-types-select').selectpicker('refresh');
4850    }
4851
4852    if (accountData.preferences.towing_customer_notification_display_name == null) {
4853      self.account.preferences.towing_customer_notification_display_name(
4854        'T. ' + self.account.company.invoice_company_name()
4855      );
4856    }
4857
4858    if (self.account.kyc && (self.account.kyc.history().length > 0 || self.account.kyc.actualStatus() != 'draft') ) {
4859      self.disableAllKycInputs();
4860      self.kycIsDraft(false);
4861    } else {
4862      self.enableAllKycInputs();
4863      self.kycIsDraft(true);
4864    }
4865
4866    if (self.account.kyc && !self.account.kyc.recipientEmail()) {
4867      self.account.kyc.recipientEmail(self.account.company.email()
4867);
4868    }
4869
4870    if (self.account && self.account.company) {
4871      if (self.account.company.contact_person() && self.account.company.contact_person() != '') {
4872        self.contactPersonSaved.name(true);
4873      } else {
4874        self.contactPersonSaved.name(false);
4875      }
4876
4877      if (self.account.company.phone() && self.account.company.phone() != '') {
4878        self.contactPersonSaved.phone(true);
4879      } else {
4880        self.contactPersonSaved.phone(false);
4881      }
4882
4883      if (self.account.company.contact_person_ssn() && self.account.company.contact_person_ssn() != '') {
4884        self.contactPersonSaved.ssn(true);
4885      } else {
4886        self.contactPersonSaved.ssn(false);
4887      }
4888
4889      if (self.account.company.email() && self.account.company.email() != '') {
4890        self.contactPersonSaved.email(true);
4891      } else {
4892        self.contactPersonSaved.email(false);
4893      }
4894    }
4895  };
4896
4897  self.enableAllKycInputs = function(){
4898
4899    self.enableKycBaseInformation(true);
4900    self.enableKycContactPersonInformation(false); // dont enable this becuase its not really editable (overridden from company data)
4901    self.enableKycBankAccountInformation(true);
4902    self.enableKycRepresentationInformation(true);
4903    self.enableKycPersonInChargeInformation(true);
4904    self.enableKycOwnersInformation(true);
4905    self.enableKycPoliticallyInfluentialPersonsInformation(true);
4906  };
4907
4908  self.disableAllKycInputs = function(){
4909
4910    self.enableKycBaseInformation(false);
4911    self.enableKycContactPersonInformation(false);
4912    self.enableKycBankAccountInformation(false);
4913    self.enableKycRepresentationInformation(false);
4914    self.enableKycPersonInChargeInformation(false);
4915    self.enableKycOwnersInformation(false);
4916    self.enableKycPoliticallyInfluentialPersonsInformation(false);
4917  };
4918
4919  self.setReviewData = function (data, type = 0) {
4920    self.reviewData.availableJobTypes([
4921      { id: 'all', label: 'Kaikki' },
4922      // { id: 'kk0', label: 'Kuormakirja' },
4923      // { id: 'tm0', label: 'Työmääräys' },
4924      // { id: 'rk0', label: 'Rahtikirja' },
4925    ]);
4926
4927    self.reviewData.towingRecordJobTypes([{ id: 'all', label: 'Kaikki' }]);
4928
4929    self.reviewData.freightJobTypes([{ id: 'all', label: 'Kaikki' }]);
4930
4931    self.reviewData.jobOrderJobTypes([{ id: 'all', label: 'Kaikki' }]);
4932
4933    if (self.account.company.mod_assistance() === true) {
4934      self.reviewData.availableJobTypes.push({ id: 'kk-1', label: 'Autoliitto' });
4935      self.reviewData.towingRecordJobTypes.push({ id: 'kk-1', label: 'Autoliitto' });
4936    }
4937
4938    if (self.account.company.mod_autoklinikka()) {
4939      [
4940        { type: 'D', label: 'Vauriokorjaus' },
4941        { type: 'W', label: 'Tuulilasin vaihto' },
4942        { type: 'F', label: 'Tuulilasin korjaus' },
4943        { type: 'R', label: 'PDR' },
4944        { type: 'Partneri', label: 'Partneri' },
4945        { type: 'O', label: 'Muu työ' },
4946      ].forEach(function (value) {
4947        self.reviewData.jobOrderJobTypes.push({ id: `tm${value.type}`, label: `${value.label} (IK)` });
4948        self.reviewData.availableJobTypes.push({ id: `tm${value.type}`, label: `${value.label} (IK)` });
4949      });
4950    }
4951
4952    if (type === 0) {
4953      data.towingRecordTypes.forEach(function (towingRecordType) {
4954        if (towingRecordType.deleted_at === null) {
4955          self.reviewData.availableJobTypes.push({
4956            id: 'kk' + towingRecordType.id,
4957            label: towingRecordType.type + ' (IH)',
4958          });
4959
4960          self.reviewData.towingRecordJobTypes.push({
4961            id: 'kk' + towingRecordType.id,
4962            label: towingRecordType.type + ' (IH)',
4963          });
4964        }
4965      });
4966
4967      
4968      if(data.jobOrderTypes){
4969        
4970        data.jobOrderTypes.forEach(function(type) {
4971          if (type.deleted_at === null) {
4972            self.reviewData.availableJobTypes.push({
4973              id: 'tm' + type.id,
4974              label: type.type + ' (IK)',
4975            });
4976
4977            self.reviewData.jobOrderJobTypes.push({
4978              id: 'tm' + type.id,
4979              label: type.type + ' (IK)',
4980            });
4981          }
4982        });
4983      }
4984      
4985      data.freigthTypes.forEach(function (freigthType) {
4986        if (freigthType.deleted_at === null) {
4987          self.reviewData.availableJobTypes.push({
4988            id: 'rk' + freigthType.id,
4989            label: freigthType.type + ' (IR)',
4990          });
4991
4992          self.reviewData.freightJobTypes.push({
4993            id: 'rk' + freigthType.id,
4994            label: freigthType.type + ' (IR)',
4995          });
4996        }
4997      });
4998
4999      ko.mapping.fromJS(data.preferencesReviews, {}, self.reviewData.settings);
5000    } else {
5001      ko.mapping.fromJS(data, {}, self.reviewData.settings);
5002
5003      self.settings.towingRecordTypes().forEach(function (towingRecordType) {
5004        self.reviewData.availableJobTypes.push({
5005          id: 'kk' + towingRecordType.id,
5006          label: towingRecordType.type + ' (IH)',
5007        });
5008      });
5009
5010      self.settings.jobOrderTypes().forEach(function(type) {
5011        if (type.deleted_at === null) {
5012          self.reviewData.availableJobTypes.push({
5013            id: 'tm' + type.id,
5014            label: type.type + ' (IK)',
5015          });
5016        }
5017      });
5018
5019      self.settings.freightTypes().forEach(function (freightType) {
5020        self.reviewData.availableJobTypes.push({
5021          id: 'rk' + freightType.id,
5022          label: freightType.type + ' (IR)',
5023        });
5024      });
5025    }
5026
5027    if (self.reviewData.settings()[0])
5028      self.reviewData.stationSetting(self.reviewData.settings()[0].type());
5029
5030    if (self.reviewData.settings()[0]) {
5031      self.reviewData.messageType(self.reviewData.settings()[0].message_type());
5032      if (self.reviewData.settings()[0].send_reply() && !self.reviewData.messageType().includes('+'))
5033        self.reviewData.messageType(self.reviewData.settings()[0].message_type() + '+');
5034
5035      self.reviewData.userStatistics(self.reviewData.settings()[0].user_statistics());
5036    }
5037
5038    //self.reviewData.userStatistics(false);
5039    //self.setDefaultMessageType();
5040    self.messageTypeChanged();
5041    $('.job-types-select').selectpicker('refresh');
5042  };
5043
5044  self.accountExists = function () {
5045    if (!self.account) return false;
5046
5047    return !!self.account.company.id();
5048  };
5049
5050  self.bindExtenders = function () {
5051    // Add extenders to mapped properties
5052    self.account.company.phone = self.account.company.phone.extend({ formatPhone: 1 });
5053    self.account.company.phone2 = self.account.company.phone2.extend({ formatPhone: 1 });
5054    self.account.company.invoice_phone = self.account.company.invoice_phone.extend({
5055      formatPhone: 1,
5056    });
5057    self.account.preferences.insurance_company_financing_commission_fee =
5058      self.account.preferences.insurance_company_financing_commission_fee.extend({
5059        commaNumeric: true,
5060      });
5061    self.account.preferences.company_14_days_net_financing_commission_fee =
5062      self.account.preferences.company_14_days_net_financing_commission_fee.extend({
5063        commaNumeric: true,
5064      });
5065    self.account.preferences.company_30_days_net_financing_commission_fee =
5066      self.account.preferences.company_30_days_net_financing_commission_fee.extend({
5067        commaNumeric: true,
5068      });
5069    self.account.preferences.consumer_financing_commission_fee =
5070      self.account.preferences.consumer_financing_commission_fee.extend({ commaNumeric: true });
5071    self.account.preferences.consumer_14_days_net_financing_commission_fee =
5072      self.account.preferences.consumer_14_days_net_financing_commission_fee.extend({
5073        commaNumeric: true,
5074      });
5075    self.account.preferences.consumer_30_days_net_financing_commission_fee =
5076      self.account.preferences.consumer_30_days_net_financing_commission_fee.extend({
5077        commaNumeric: true,
5078      });
5079    self.account.preferences.part_payment_transaction_fee =
5080      self.account.preferences.part_payment_transaction_fee.extend({ commaNumeric: true });
5081    self.account.preferences.part_payment_financing_commission_fee =
5082      self.account.preferences.part_payment_financing_commission_fee.extend({ commaNumeric: true });
5083    self.account.preferences.invoice_transaction_fee =
5084      self.account.preferences.invoice_transaction_fee.extend({ commaNumeric: true });
5085    self.account.preferences.paper_invoice_transaction_fee =
5086      self.account.preferences.paper_invoice_transaction_fee.extend({ commaNumeric: true });
5087    self.account.preferences.e_invoice_transaction_fee =
5088      self.account.preferences.e_invoice_transaction_fee.extend({ commaNumeric: true });
5089    self.account.preferences.connection_fee = self.account.preferences.connection_fee.extend({
5090      commaNumeric: true,
5091    });
5092    self.account.preferences.consumer_financing_limit =
5093      self.account.preferences.consumer_financing_limit.extend({ commaNumeric: true });
5094    self.account.preferences.company_financing_limit =
5095      self.account.preferences.company_financing_limit.extend({ commaNumeric: true });
5096    self.account.preferences.insurance_company_financing_limit =
5097      self.account.preferences.insurance_company_financing_limit.extend({ commaNumeric: true });
5098    self.account.preferences.part_payment_financing_limit =
5099      self.account.preferences.part_payment_financing_limit.extend({ commaNumeric: true });
5100    self.account.preferences.service_charge_fee =
5101      self.account.preferences.service_charge_fee.extend({
5102        commaNumeric: true,
5103      });
5104    self.account.preferences.sms_review_fee = self.account.preferences.sms_review_fee.extend({
5105      commaNumeric: true,
5106    });
5107    self.account.preferences.invoicing_fee = self.account.preferences.invoicing_fee.extend({
5108      commaNumeric: true,
5109    });
5110    self.account.preferences.online_payment_link_fee = self.account.preferences.online_payment_link_fee.extend({
5111      commaNumeric: true,
5112    });
5113  };
5114
5115  self.bindSubscribers = function () {
5116    // Add subscribers to some of properties to copy copy to anothers properties on change
5117    self.account.company.address.subscribe(function (value) {
5118      self.copyValue(self.account.company.invoice_address, value);
5119      self.copyValue(self.account.company.invoicing_address, value);
5120    });
5121
5122    self.account.company.zipcode.subscribe(function (value) {
5123      self.copyValue(self.account.company.invoice_zipcode, value);
5124      self.copyValue(self.account.company.invoicing_zipcode, value);
5125    });
5126
5127    self.account.company.city.subscribe(function (value) {
5128      self.copyValue(self.account.company.invoice_city, value);
5129      self.copyValue(self.account.company.invoicing_city, value);
5130    });
5131
5132    self.account.company.company_name.subscribe(function (value) {
5133      self.copyValue(self.account.company.invoice_company_name, value);
5134    });
5135
5136    self.account.company.email.subscribe(function (value) {
5137      self.copyValue(self.account.company.ticket_email, value);
5138      self.copyValue(self.account.company.sales_leads_email, value);
5139      self.copyValue(self.account.company.invoice_email, value);
5140      self.copyValue(self.account.company.invoicing_email, value);
5141      if (!self.account.kyc.recipientEmail()) {
5142        self.copyValue(self.account.kyc.recipientEmail, value);
5143      }
5144    });
5145
5146    self.account.company.phone.subscribe(function (value) {
5147      self.copyValue(self.account.company.invoice_phone, value);
5148      if (!self.account.kyc.signerPhone()) {
5149        self.copyValue(self.account.kyc.signerPhone, value);
5150      }
5151    });
5152
5153    self.account.company.business_id.subscribe(function (value) {
5154      self.copyValue(self.account.company.invoice_business_id, value);
5155    });
5156
5157    self.account.company.contact_person_ssn.subscribe(function(value) {
5158      if (value) {
5159        self.account.company.contact_person_ssn(value.toUpperCase());
5160        self.copyValue(self.account.kyc.signerSsn, value.toUpperCase());
5161      }
5162    });
5163
5164    self.account.company.contact_person.subscribe(function (value) {
5165      self.copyValue(self.account.kyc.signedBy, value);
5166    });
5167  };
5168
5169  self.bindComputedObservables = function() {
5170
5171    // @ai:claude Returns Bootstrap 3 label class and Finnish text for the current trial status,
5172    // used to render the colour-coded badge in the Kokeiluasiakkuuden tila panel header.
5173    self.trialStatusBadge = ko.pureComputed(function () {
5174      if (!self.account || !self.account.company) return { text: '', cls: 'label-default' };
5175      switch (parseInt(self.account.company.trial_status(), 10)) {
5176        case 0: return { text: 'Luonnos',                cls: 'label-default' };
5177        case 1: return { text: 'Aktiivinen',              cls: 'label-success' };
5178        case 2: return { text: 'Vanhentunut',             cls: 'label-danger'  };
5179        case 3: return { text: 'Muuttumassa asiakkaaksi', cls: 'label-warning' };
5180        case 4: return { text: 'Muutettu asiakkaaksi',    cls: 'label-primary' };
5181        case 5: return { text: 'Peruutettu',              cls: 'label-default' };
5182        default: return { text: 'Tuntematon',             cls: 'label-default' };
5183      }
5184    });
5185
5186    self.account.displayStations = ko.computed(function(){
5187
5188       return self.account.company.id() &&
5189       (
5190           self.account.company.field_of_work() === "car_tow"
5191        || self.account.company.field_of_work() === "car_rental"
5192        || self.account.company.mod_autoklinikka()
5193       )
5194    });
5195
5196    // Add computed to calculated stats totals
5197    function sumStatsField(fieldName) {
5198      return ko.computed(function () {
5199        var total = 0;
5200
5201        for (var p = 0; p < self.account.stats().length; ++p) {
5202          total += +self.account.stats()[p][fieldName]();
5203        }
5204
5205        return total;
5206      });
5207    }
5208
5209    self.account.statsTotal = sumStatsField("quantity");
5210    self.account.statsTotalCurrentYear = sumStatsField("quantity_current_year");
5211    self.account.statsTotalPreviousYear = sumStatsField("quantity_previous_year");
5212
5213    self.settings.availableTags = ko.computed(function () {
5214      if (!self.account) {
5215        return [];
5216      }
5217
5218      return [
5219        'fixus',
5220        'motonet',
5221        'webasto',
5222        'kaha',
5223        'autoasi',
5224        'scandia rent',
5225        'sos',
5226        'autoliitto',
5227        'autonomi',
5228        'awux',
5229        '123 tuulilasi',
5230        'kl',
5231        'terra gas',
5232      ].filter(function (tag) {
5233        return ko.toJS(self.account.tags).indexOf(tag) === -1;
5234      });
5235    });
5236
5237    self.kycEditButtonsVisible = ko.computed(function() {
5238
5239      if (!self.account) {
5240        return false;
5241      }
5242      var history = ko.toJS(self.account.kyc.history);
5243
5244      //If there is only one KYC form and it is still in draft status, allow it to be edited by Innovoice
5245      if (history.length === 1 && history[0].actualStatus === 'draft') {
5246        return true;
5247      }
5248
5249      return self.account.kyc.actualStatus() === 'declined';
5250    });
5251
5252    self.kycRepresentation = ko.computed(function() {
5253      var representation2 = self.account && self.account.kyc ? self.account.kyc.representation2() : null;
5254      var representation3 = self.account && self.account.kyc ? self.account.kyc.representation3() : null;
5255
5256      return self.kycRepresentationOptions.filter(value => value.value !== representation2 && value.value !== representation3);
5257    });
5258
5259    self.kycRepresentation2 = ko.computed(function() {
5260      var representation = self.account && self.account.kyc ? self.account.kyc.representation() : null;
5261      var representation3 = self.account && self.account.kyc ? self.account.kyc.representation3() : null;
5262
5263      return self.kycRepresentationOptions.filter(value => value.value !== representation && value.value !== representation3);
5264    });
5265
5266    self.kycRepresentation3 = ko.computed(function() {
5267      var representation = self.account && self.account.kyc ? self.account.kyc.representation() : null;
5268      var representation2 = self.account && self.account.kyc ? self.account.kyc.representation2() : null;
5269
5270      return self.kycRepresentationOptions.filter(value => value.value !== representation && value.value !== representation2);
5271    });
5272
5273    self.noActiveMainUsers = ko.computed(function() {
5274      var users = self.account.users();
5275      var hasMainUser = ko.toJS(users).find(function(user) {
5276        return (user.usergroup_id == '2' || user.usergroup_id == '14' || user.usergroup_id == '17') && (user.disabled === '0' || user.disabled === false) && user.deleted_at === null;
5277      });
5278
5279      return typeof hasMainUser === 'undefined';
5280    });
5281
5282    self.canSendKycForm = ko.computed(function() {
5283      if (self.account.kyc && self.account.kyc.disabled()) {
5284        return false;
5285      }
5286
5287      if ((self.account.kyc && (self.account.kyc.history().length > 0 && self.account.kyc.actualStatus() == 'pending_acceptance'))) {
5288        return false;
5289      }
5290
5291      if (self.account.kyc && (self.account.kyc.actualStatus() == 'ok' || self.account.kyc.actualStatus() == 'declined')) {
5292        return false;
5293      }
5294
5295      return !self.noActiveMainUsers();
5296    });
5297
5298    self.canCreateKycForm = ko.computed(function() {
5299      if (self.account.kyc && self.account.kyc.disabled()) {
5300        return false;
5301      }
5302      if (self.account.kyc && !(self.account.kyc.actualStatus() == 'ok' || self.account.kyc.actualStatus() == 'declined' || self.account.kyc.actualStatus() == 'draft')) {
5303        return false;
5304      }
5305
5306      return !self.noActiveMainUsers();
5307    });
5308  };
5309
5310  self.init = function () {
5311    self.initJQueryElements();
5312    self.fetchInitialDataAndApplyKoBindings();
5313    self.companyDocuments.addElementBinding();
5314  };
5315
5316  self.applyKoBindings = function (elem) {
5317    ko.applyBindings(this, elem);
5318  };
5319
5320  self.initJQueryElements = function () {
5321    $('#account-card-tabs').tabs();
5322    self.initDatepicker();
5323    //$('.job-types-select').selectpicker('refresh');
5324  };
5325
5326  self.initDatepicker = function () {
5327    $('.datepicker').datepicker({startDate: '01.01.1900'});
5328  };
5329
5330  self.fetchSubcontractingCompanies = function (companyId) {
5331    if (!companyId) return;
5332    jQuery
5333      .ajax({
5334        url: '/asiakkuudet/getSubcontractingCompanies/' + companyId,
5335        method: 'get',
5336        dataType: 'json',
5337      })
5338      .done(function (response) {
5339        self.subcontractingCompanies(
5340          Array.isArray(response.data) ? response.data.map(function (c) {
5341            // @ai:claude collapsed by default so long subcontractor lists stay scannable
5342            var mapped = ko.mapping.fromJS(c);
5343            mapped.isCollapsed = ko.observable(true);
5344            return mapped;
5345          }) : []
5346        );
5347      })
5348      .fail(function () {
5349        self.subcontractingCompanies([]);
5350      });
5351  };
5352
5353  self.onSubcontractingSearchInput = function () {
5354
5355    clearTimeout(self._subcontractingDebounceTimer);
5356
5357    self.subcontractingSearchResults([]);
5358    self.subcontractingSearchNoResults(false);
5359
5360    var query = self.subcontractingSearch();
5361    if (!query || query.trim().length < 2) {
5362      self.subcontractingSearchLoading(false);
5363      return;
5364    }
5365
5366    self.subcontractingSearchLoading(true);
5367
5368    self._subcontractingDebounceTimer = setTimeout(function () {
5369      jQuery
5370        .ajax({
5371          url: '/asiakkuudet/searchSubcontractingCompanies',
5372          method: 'post',
5373          dataType: 'json',
5374          data: {
5375            query: query.trim(),
5376            companyId: self.account.company.id(),
5377          },
5378        })
5379        .done(function (response) {
5380          self.subcontractingSearchResults(Array.isArray(response.data) ? response.data : []);
5381          self.subcontractingSearchNoResults(Array.isArray(response.data) && response.data.length === 0);
5382        })
5383        .fail(function () {
5384          self.subcontractingSearchResults([]);
5385          self.subcontractingSearchNoResults(false);
5386        })
5387        .always(function () {
5388          self.subcontractingSearchLoading(false);
5389        });
5390    }, 400);
5391  };
5392
5393  self.addSubcontractingCompany = function (company) {
5394    jQuery
5395      .ajax({
5396        url: '/asiakkuudet/addSubcontractingCompany',
5397        method: 'post',
5398        dataType: 'json',
5399        data: {
5400          companyId: self.account.company.id(),
5401          contractorId: company.id,
5402        },
5403      })
5404      .done(function (response) {
5405        console.log(response.data);
5406        // @ai:claude newly added company starts expanded, as the user likely wants to configure it right away
5407        var mapped = ko.mapping.fromJS(response.data);
5408        mapped.isCollapsed = ko.observable(false);
5409        self.subcontractingCompanies.push(mapped);
5410        self.subcontractingSearch('');
5411        self.subcontractingSearchResults([]);
5412        self.subcontractingSearchNoResults(false);
5413        if (!self.account.preferences.towing_subcontracts()) {
5414          self.account.preferences.towing_subcontracts(true);
5415        }
5416      })
5417      .fail(function (err) {
5418        window.show_message && window.show_message(err.responseJSON);
5419      });
5420  };
5421
5422  self.removeSubcontractingCompany = function (company) {
5423    if (!window.confirm('Haluatko varmasti poistaa alihankkijayrityksen ' + ko.unwrap(company.name) + '?')) {
5424      return;
5425    }
5426    jQuery
5427      .ajax({
5428        url: '/asiakkuudet/removeSubcontractingCompany',
5429        method: 'post',
5430        dataType: 'json',
5431        data: {
5432          companyId: self.account.company.id(),
5433          contractorId: ko.unwrap(company.id),
5434        },
5435      })
5436      .done(function () {
5437        self.subcontractingCompanies.remove(function (c) {
5438          return ko.unwrap(c.id) === ko.unwrap(company.id);
5439        });
5440      })
5441      .fail(function (err) {
5442        window.show_message && window.show_message(err.responseJSON);
5443      });
5444  };
5445
5446  // @ai:claude flips the per-company collapse state used to show/hide the settings panel body
5447  self.toggleSubcontractingCompany = function (company) {
5448    company.isCollapsed(!company.isCollapsed());
5449  };
5450
5451  self.updateSubcontractingCompanySettings = function (company) {
5452    jQuery.ajax({
5453      url: '/asiakkuudet/updateSubcontractingCompanySettings',
5454      method: 'post',
5455      dataType: 'json',
5456      data: {
5457        companyId:    self.account.company.id(),
5458        contractorId: ko.unwrap(company.id),
5459        client:       ko.mapping.toJS(company.clientSettings),
5460        contractor:   ko.mapping.toJS(company.contractorSettings),
5461      },
5462    }).fail(function (err) {
5463      window.show_message && window.show_message(err.responseJSON);
5464    });
5465  };
5466
5467  self.fetchAndUpdateData = function (companyId) {
5468    jQuery
5469      .ajax({
5470        url: '/asiakkuudet/asiakkuus/'.concat(companyId),
5471        dataType: 'json',
5472      })
5473      .done(self.setData)
5474      .fail(function (response) {});
5475  };
5476
5477  self.fetchInitialDataAndApplyKoBindings = function () {
5478    jQuery
5479      .ajax({
5480        url: '/asiakkuudet/asiakkuus/',
5481        dataType: 'json',
5482      })
5483      .done(self.setData)
5484      .then(function () {
5485        self.applyKoBindings($('#account-card-dialog')[0]);
5486      })
5487      .fail(function (response) {});
5488  };
5489
5490  self.includeDisabled = ko.observable(false);
5491  self.showUserExtraOptions = ko.observable(false);
5492  self.show = function (companyId) {
5493    // If jQuery UI dialog has not been inited yet
5494    if (self.dialog === null) {
5495      self.dialog = $('#account-card-dialog').dialog({
5496        width: window.innerWidth >= 1280 ? 1280 : '90%',
5497        height: 800,
5498        autoOpen: false,
5499        modal: true,
5500        resizable: true,
5501        draggable: true,
5502        beforeclose: function (event) {
5503          $('link#extrabs').remove();
5504          $('script#bsjs').remove();
5505          event.stopPropagation();
5506        },
5507        title: 'Asiakkuuskortti',
5508        buttons: [
5509          {
5510            text: 'Sulje',
5511            class: 'close-btn btn btn-default',
5512            click: function () {
5513              self.close();
5514            },
5515          },
5516          {
5517            text: 'Tallenna',
5518            class: 'save-btn btn btn-default',
5519            click: function () {
5520              //self.dialog.find('#account_card_form').submit();
5521              self.saveAccount();
5522            },
5523          },
5524        ],
5525      });
5526    }
5527
5528    self.dialog.dialog('open');
5529    $('div#account-card-tabs').tabs('option', 'active', 0);
5530    self.fetchAndUpdateData(companyId);
5531    self.showUserExtraOptions(false);
5532  };
5533
5534  self.close = function () {
5535    self.reviewData.availableJobTypes([]);
5536    self.reviewData.jobTypes([]);
5537    self.dialog.dialog('close');
5538  };
5539
5540  self.saveStations = function () {
5541    if (self.account.stations() && self.account.stations().length > 0) {
5542      var stationsNamesMissing =
5543        self.account.stations().filter(function (value) {
5544          return value.name() === '' && (value.type() === 1 || value.type() === 2);
5545        }).length > 0;
5546      var stationMissingCoords =
5547        self.account.stations().filter(function (value) {
5548          return isNaN(value.coords_lat()) || isNaN(value.coords_long());
5549        }).length > 0;
5550
5551      if (stationsNamesMissing)
5552        return global.show_message({ type: 'error', text: 'Toimipisteen nimi ei saa olla tyhjä' });
5553      if (stationMissingCoords)
5554        return global.show_message({
5555          type: 'error',
5556          text: 'Toimipisteen kordinaatit virheelliset. Käytä pistettä erottimena (esim 61.14046433).',
5557        });
5558    }
5559
5560    var stations = ko.mapping.toJSON(self.account.stations());
5561
5562    var data = {
5563      companyId: ko.toJS(self.account.company.id),
5564      stations,
5565    };
5566    global.showLoadingDialog('Tallennetaan...');
5567
5568    $.ajax({
5569      type: 'POST',
5570      url: 'asiakkuudet/saveStations/',
5571      data: data,
5572    })
5573      .done(function (response) {
5574        global.close_loading_dialog();
5575        global.show_message(response);
5576        if (response.data && response.data.stations) {
5577          ko.mapping.fromJS(response.data.stations, {}, self.account.stations);
5578        }
5579        if (self.account.company.mod_review() && response.data && response.data.reviews) {
5580          ko.mapping.fromJS(response.data.reviews, {}, self.reviewData.settings);
5581        }
5582      })
5583      .fail(function (error) {
5584        global.close_loading_dialog();
5585        global.show_message(error.responseJSON);
5586      });
5587  };
5588
5589  self.saveAccount = function () {
5590    if (
5591      self.account.company.id() &&
5592      !self.account.company.is_trial() &&
5593      !self.convertingTrialToCustomer()
5594    ) {
5595      var trialStatus = parseInt(self.account.company.trial_status(), 10);
5596      if (trialStatus === 1) {
5597        return global.show_message({
5598          type: 'error',
5599          text: 'Kokeiluasiakkuutta ei voi poistaa ruksista. Muuta se oikeaksi asiakkuudeksi.',
5600        });
5601      }
5602      if (trialStatus === 5) {
5603        return global.show_message({
5604          type: 'error',
5605          text: 'Kokeiluasiakkuutta ei voi poistaa ruksista. Käytä reaktivointia kokeilun jatkamiseksi.',
5606        });
5607      }
5608    }
5609
5610    // @ai:claude Guard: trial customers must have an expiry date before saving.
5611    if (self.account.company.is_trial() && !self.account.company.trial_expires_at()) {
5612      return global.show_message({
5613        type: 'error',
5614        text: 'Aseta kokeilujakson päättymispäivä ennen tallennusta.',
5615      });
5616    }
5617
5618    // Guard: if status is Vanhentunut and a future expiry is set, confirm reactivation first.
5619    if (
5620      self.account.company.is_trial() &&
5621      self.account.company.id() &&
5622      parseInt(self.account.company.trial_status(), 10) === 2 &&
5623      !self._confirmedTrialReactivation
5624    ) {
5625      var expiryRaw = self.account.company.trial_expires_at();
5626      if (expiryRaw) {
5627        var parts = expiryRaw.split('.');
5628        var expiryDate = parts.length === 3
5629          ? new Date(parts[2], parts[1] - 1, parts[0])
5630          : new Date(expiryRaw);
5631        if (expiryDate > new Date()) {
5632          var $d = $('<div />').html('<p style="margin:0;">Haluatko uudelleenaktivoida kokeiluasiakkuuden asettamalla uusi päättymispäivä?</p>')
5633            .prepend($('<span />', { class: 'ui-icon ui-icon-alert', style: 'float:left; margin:0 7px 50px 0;' }));
5634          $d.dialog({
5635            title: 'Uudelleenaktivoi kokeilu',
5636            modal: true,
5637            buttons: {
5638              'Kyllä, aktivoi uudelleen': function () {
5639                $d.dialog('close');
5640                self._confirmedTrialReactivation = true;
5641                self.saveAccount();
5642              },
5643              'Peruuta': function () { $d.dialog('close'); },
5644            },
5645            close: function () { $d.dialog('destroy'); $d.remove(); },
5646          }).parents('.ui-dialog').css('z-index', 9999);
5647          return;
5648        }
5649      }
5650    }
5651
5652    // @ai:claude Guard: if trial is Peruutettu and admin checked Reaktivoi, validate the
5653    // expiry date and confirm before saving. Mutates trial_status(1) and disabled(false)
5654    // so the normal save payload carries the updated values — no separate endpoint needed.
5655    if (
5656      self.account.company.is_trial() &&
5657      self.account.company.id() &&
5658      parseInt(self.account.company.trial_status(), 10) === 5 &&
5659      self.reactivatingTrial() &&
5660      !self._confirmedTrialReactivation
5661    ) {
5662      var expiryRawCancelled = self.account.company.trial_expires_at();
5663      if (!expiryRawCancelled) {
5664        global.show_message({ type: 'error', text: 'Aseta ensin uusi kokeilujakson päättymispäivä ennen reaktivointia.' });
5665        return;
5666      }
5667      var cancelledParts = expiryRawCancelled.split('.');
5668      var cancelledExpiry = new Date(cancelledParts[2], cancelledParts[1] - 1, cancelledParts[0]);
5669      cancelledExpiry.setHours(23, 59, 59, 0);
5670      if (cancelledExpiry <= new Date()) {
5671        global.show_message({ type: 'error', text: 'Aseta tuleva päättymispäivä ennen reaktivointia.' });
5672        return;
5673      }
5674      var $dCancel = $('<div />').html('<p style="margin:0;">Haluatko reaktivoida kokeiluasiakkuuden?</p>')
5675        .prepend($('<span />', { class: 'ui-icon ui-icon-alert', style: 'float:left; margin:0 7px 50px 0;' }));
5676      $dCancel.dialog({
5677        title: 'Reaktivoi kokeiluasiakkuus',
5678        modal: true,
5679        buttons: {
5680          'Kyllä, reaktivoi': function () {
5681            $dCancel.dialog('close');
5682            self.account.company.trial_status(1);
5683            self.account.company.disabled(false);
5684            self._confirmedTrialReactivation = true;
5685            self.saveAccount();
5686          },
5687          'Peruuta': function () { $dCancel.dialog('close'); },
5688        },
5689        close: function () { $dCancel.dialog('destroy'); $dCancel.remove(); },
5690      }).parents('.ui-dialog').css('z-index', 9999);
5691      return;
5692    }
5693
5694    self._confirmedTrialReactivation = false;
5695    self.reactivatingTrial(false);
5696
5697    if (self.account.stations() && self.account.stations().length > 0) {
5698      var stationsNamesMissing =
5699        self.account.stations().filter(function (value) {
5700          return value.name() === '' && (value.type() === 1 || value.type() === 2);
5701        }).length > 0;
5702      var stationMissingCoords =
5703        self.account.stations().filter(function (value) {
5704          return isNaN(value.coords_lat()) || isNaN(value.coords_long());
5705        }).length > 0;
5706
5707      if (stationsNamesMissing)
5708        return global.show_message({ type: 'error', text: 'Toimipisteen nimi ei saa olla tyhjä' });
5709      if (stationMissingCoords)
5710        return global.show_message({
5711          type: 'error',
5712          text: 'Toimipisteen kordinaatit virheelliset. Käytä pistettä erottimena (esim 61.14046433).',
5713        });
5714    }
5715
5716    var missingContactFields = !self.account.company.contact_person()
5717      || !self.account.company.email()
5718      || !self.account.company.phone();
5719
5720    if (!self.account.company.is_trial()) {
5721      missingContactFields = missingContactFields || !self.account.company.contact_person_ssn();
5722    }
5723
5724    if (!self.account.company.id() && missingContactFields) {
5725      return global.show_message({ type: 'error', text: 'Tarkasta yhteyshenkilön tiedot' });
5726    }
5727
5728    if (self.account.company.contact_person_ssn() && !SSN_REGEX.test(self.account.company.contact_person_ssn())) {
5729      return global.show_message({ type: 'error', text: 'Yhteyshenkilön hetu on virheellinen' });
5730    }
5731
5732    if (self.account.company.ext_service() === 'bildem' && !self.account.company.mod_bildem())
5733      self.account.company.ext_service('');
5734
5735    if (self.account.company.mod_bildem()) self.account.company.ext_service('bildem');
5736
5737    self.account.preferences.drivers_may_accept_external_towing_orders(
5738      Number(self.account.preferences.drivers_may_accept_external_towing_orders())
5739    );
5740
5741    if (self.account.preferences_procountor && self.account.preferences_procountor.dimensions)
5742      self.account.preferences_procountor.dimensions(self.dimensions);
5743
5744    if (self.account.company.mod_review() === true) {
5745      self.setReviewMessage();
5746    }
5747
5748    if (!self.account.kyc.signedBy()) {
5749      self.copyValue(self.account.kyc.signedBy, self.account.company.contact_person());
5750    }
5751
5752    if (!self.account.kyc.recipientEmail()) {
5753      self.copyValue(self.account.kyc.recipientEmail, self.account.company.email());
5754    }
5755
5756    if (!self.account.kyc.signerPhone()) {
5757      self.copyValue(self.account.kyc.signerPhone, self.account.company.phone());
5758    }
5759
5760    if (!self.account.kyc.signerSsn()) {
5761      self.copyValue(self.account.kyc.signerSsn, self.account.company.contact_person_ssn());
5762    }
5763    
5764    if (self.account.company.mod_trafi() && self.account.company.trafi_innokorjaamo_service_enabled() && self.account.company.trafi_innohinaus_service_enabled() && ! self.account.company.trafi_default_service()) {
5765
5766      return global.show_message({
5767        type: 'error',
5768        text: 'Ole hyvä ja valitse Traficom-haun ensisijainen palveluala',
5769      });
5770    }
5771
5772    // if (self.reviewData.message()) {
5773    //   self.reviewData.settings().forEach((settings) => {
5774    //     settings.message(self.reviewData.message());
5775    //   });
5776    // }
5777
5778    var account = ko.mapping.toJS(self.account);
5779
5780    if (self.convertingTrialToCustomer()) {
5781      account.company.convert_to_customer = true;
5782      self.convertingTrialToCustomer(false);
5783    }
5784
5785    var towingNotifications = ko.toJS(self.towingNotifications);
5786    var followUpSettings = self.account.company.mod_follow_up() === true ? ko.toJS(self.followUpSettings) : [];
5787    delete towingNotifications.availableJobTypes;
5788    delete towingNotifications.availableStations;
5789
5790    account.preferences.towing_customer_notification_settings = ko.toJSON(towingNotifications);
5791    account.companyGroupSettings = ko.toJS({ companyGroupIDs: self.selectedCompanyGroups() });
5792
5793    //Dont send log items unnecessarily to the server
5794    delete account.logs;
5795
5796    //
5797    delete account.company.kredinor_password;
5798    delete account.company.kredinor_username;
5799    delete account.company.kredinor_active;
5800
5801    // Delete preferences_reviews and send them as their own parameter
5802    delete account.preferences_reviews;
5803    // if block_money_transfer changed and reason added, add reason to log
5804    var newLogItem = {};
5805    if (
5806      self.account.company.block_money_transfer() != self.BlockMoneyTransferOld() &&
5807      self.moneyTransferBlockReason() != ''
5808    ) {
5809      newLogItem = ko.toJS(self.moneyTransferBlockReason);
5810    }
5811    var data = {
5812      account: ko.mapping.toJSON(account),
5813      preferencesReviews: ko.toJS(self.reviewData.settings),
5814      followUpSettings: followUpSettings,
5815      spareParts: ko.toJS(self.settings.spare_parts),
5816      sms_templates: ko.toJS(self.settings.sms_templates),
5817      selectedCompanyGroups: ko.toJS(self.selectedCompanyGroups),
5818      categories: ko.toJS(self.settings.categories).map((c) => ({
5819        id: c.id,
5820        sub_categories: c.sub_categories.map((s) => ({
5821          id: s.id,
5822        })),
5823      })),
5824      shiftGroupSettings: ko.toJS(self.settings.shiftGroupSettings).map((s) => {
5825        s.enable_evening = Number(s.enable_evening);
5826        s.enable_night = Number(s.enable_night);
5827        s.enable_overtime = Number(s.enable_overtime);
5828        s.enable_wait = Number(s.enable_wait);
5829        s.enable_standby = Number(s.enable_standby);
5830        return s;
5831      }),
5832      newLogItem: newLogItem,
5833    };
5834
5835    $(`.error`).removeClass('error');
5836
5837    self.saving(true);
5838    global.showLoadingDialog('Tallennetaan...');
5839
5840    jQuery
5841      .ajax({
5842        type: 'post',
5843        dataType: 'json',
5844        url: '/asiakkuudet/save',
5845        data: data,
5846      })
5847      .done(function (responseJSON) {
5848        self.saved(true);
5849        global.show_message(responseJSON);
5850        global.close_loading_dialog();
5851        self.setData(responseJSON.data);
5852      })
5853      .fail(function (data) {
5854        global.show_message($.parseJSON(data.responseText));
5855        global.close_loading_dialog();
5856        console.error('.ajax.fail:', data);
5857        if (data.responseJSON && data.responseJSON.data && data.responseJSON.data.kyc) {
5858          var index = $('#account-card-tabs a[href="#kyc-forms"]').parent().index();
5859          $('#account-card-tabs').tabs('option', 'active', index);
5860          var object = data.responseJSON.data.errors;
5861          console.log('object', object);
5862          self.setErrors(object);
5863        }
5864      })
5865      .then(function () {
5866        // Set the saved observable back to false, so we can,
5867        // listen for new saved events outside this obj
5868        self.saving(false);
5869        self.saved(false);
5870      });
5871
5872    return false;
5873  };
5874
5875  self.user = function () {
5876    var roles = self.settings.roles().map((role) => ({
5877      role_id: ko.observable(role.id),
5878      role_desc: role.role_desc,
5879      active: ko.observable(false),
5880    }));
5881
5882    var stations = self.account.stations().map((station) => ({
5883      station_id: ko.observable(station.id),
5884      name: station.name,
5885      active: ko.observable(false),
5886    }));
5887
5888    const minAccessLevelForMFA = Number(self.account.preferences.min_access_level_required_to_use_mfa());
5889    const matchingUserGroup = self.usergroups.find((group) => Number(group.access_level) === minAccessLevelForMFA);
5890    const defaultUserGroupIdForNewCompanyUser = matchingUserGroup ? matchingUserGroup.id : null;
5891
5892    return {
5893      id: ko.observable(),
5894      email: ko.observable(),
5895      username: ko.observable(),
5896      password: ko.observable(),
5897      roles: roles,
5898      stations: stations,
5899      usergroup_id: ko.observable(defaultUserGroupIdForNewCompanyUser),
5900      work_time_type: ko.observable('foo'),
5901      sales_name: ko.observable(''),
5902      disabled: ko.observable('0'),
5903      hidden: ko.observable('0'),
5904      user_authenticated: ko.observable('0'),
5905      firstname: ko.observable(''),
5906      lastname: ko.observable(''),
5907      msisdn_verified: ko.observable('0')
5908    };
5909  };
5910
5911  self.usergroupName = function (user) {
5912    var userGroupId =
5913      user.usergroup_id() && !Number.isInteger(user.usergroup_id())
5914        ? parseInt(user.usergroup_id())
5915        : user.usergroup_id();
5916    const filtered = self.usergroups.filter((group) => group.id === userGroupId);
5917    return (filtered[0] || { group_name: 'Ei valittu' }).group_name;
5918  };
5919
5920  self.addUser = function (data) {
5921    var user = self.user();
5922    self.account.users.push(user);
5923  };
5924
5925  self.removeUser = function (user) {
5926    // If existing user, confirm the removal
5927    if (user.id()) {
5928      return self.confirmRemoveUser(user);
5929    }
5930    self.account.users.remove(user);
5931  };
5932
5933  self.confirmRemoveUser = function (user) {
5934    var $dialog = $('<div />')
5935      .html(
5936        '<p style="font-weight:bold;"><span class="ui-icon ui-icon-alert" style="float:left; margin:0 7px 20px 0; "></span>Haluatko varmasti poistaa kyseisen käyttäjän?</p>'
5937      )
5938      .dialog({
5939        resizable: false,
5940        height: 200,
5941        width: 400,
5942        title: 'Poista käyttäjä',
5943        modal: true,
5944        buttons: {
5945          Ei: function () {
5946            $(this).dialog('close');
5947          },
5948          Kyllä: function () {
5949            jQuery
5950              .ajax({
5951                url: '/asiakkuudet/delete_user/' + user.id(),
5952                type: 'post',
5953                dataType: 'json',
5954              })
5955              .done(function (responseJSON) {
5956                if (user.usergroup_id() === '10') {
5957                  // Remove autofutur user from client
5958                  self.resetAutofuturUser();
5959                } else {
5960                  // Remove normal user from client
5961                  self.account.users.remove(user);
5962                }
5963                $dialog.dialog('close');
5964                global.show_message(responseJSON);
5965              })
5966              .fail(function (response) {
5967                global.show_message(response.responseJSON);
5968                global.close_loading_dialog();
5969              });
5970          },
5971        },
5972      });
5973  };
5974
5975  self.removeCompanyLogo = function () {
5976    // If existing user, confirm the removal
5977    return self.confirmRemoveCompanyLogo();
5978  };
5979
5980  self.processCompanyLogo = function (_, event) {
5981    var logo = event.target.files[0];
5982
5983    var data = new FormData();
5984    data.append('file', logo);
5985
5986    $.ajax({
5987      url: '/asiakkuudet/add_company_logo/' + ko.toJS(self.account.company.id),
5988      type: 'post',
5989      data: data,
5990      contentType: false,
5991      processData: false,
5992    })
5993      .done(function (responseJSON) {
5994        global.show_message(responseJSON);
5995        self.account.company.logo(responseJSON.data.logo);
5996        self.logoBase64(responseJSON.data.logo_base64);
5997        event.target.val(null);
5998      })
5999      .fail(function (error) {
6000        global.show_message(JSON.parse(error.responseText));
6001      });
6002  };
6003
6004  self.addCompanyLogo = function () {
6005    $('#fileElem').click();
6006  };
6007
6008  self.confirmRemoveCompanyLogo = function () {
6009    var $dialog = $('<div />')
6010      .html(
6011        '<p style="font-weight:bold;"><span class="ui-icon ui-icon-alert" style="float:left; margin:0 7px 20px 0; "></span>Haluatko varmasti poistaa yrityksen logon laskuilta?</p>'
6012      )
6013      .dialog({
6014        resizable: false,
6015        height: 200,
6016        width: 400,
6017        title: 'Poista logo',
6018        modal: true,
6019        buttons: {
6020          Ei: function () {
6021            $(this).dialog('close');
6022          },
6023          Kyllä: function () {
6024            jQuery
6025              .ajax({
6026                url: '/asiakkuudet/delete_company_logo/'.concat(self.account.company.id()),
6027                type: 'post',
6028                dataType: 'json',
6029              })
6030              .done(function (responseJSON) {
6031                self.account.company.logo('');
6032                self.logoBase64(false);
6033
6034                $dialog.dialog('close');
6035                global.show_message(responseJSON);
6036              })
6037              .fail(function (response) {
6038                global.show_message(response.responseJSON);
6039                global.close_loading_dialog();
6040              });
6041          },
6042        },
6043      });
6044  };
6045  
6046  self.showCreateAutofuturUser = function () {
6047    self.account.autofuturUser.createNewUser(true);
6048  };
6049
6050  self.hideCreateAutofuturUser = function () {
6051    self.account.autofuturUser.createNewUser(false);
6052  };
6053
6054  self.changeUserPassword = function (user) {
6055    var $form = $('<form />', {
6056      method: 'POST',
6057      action: '/asiakkuudet/change_user_password/' + user.id(),
6058    }).append(
6059      $('<fieldset />').append(
6060        $('<ol />', {}).append(
6061          $('<li />', {}).append(
6062            $('<label />', {}).html('Uusi salasana'),
6063            $('<input />', {
6064              type: 'text',
6065              name: 'new_password',
6066              id: 'new_password',
6067              class: 'text form-control medium',
6068            })
6069          )
6070        )
6071      )
6072    );
6073
6074    var $dialog = $('<div />', { style: 'text-align:left;' })
6075      .append($form)
6076      .dialog({
6077        width: 400,
6078        autoOpen: true,
6079        modal: true,
6080        resizable: false,
6081        draggable: false,
6082        beforeclose: function (event, ui) {
6083          event.stopPropagation();
6084        },
6085        title: 'Salasanan vaihto',
6086        buttons: {
6087          Peruuta: function () {
6088            $(this).dialog('close');
6089          },
6090          'Vaihda salasana': function () {
6091            $form.ajaxSubmit({
6092              type: 'post',
6093              dataType: 'json',
6094              beforeSubmit: function () {
6095                global.showLoadingDialog('Vaihdetaan salasanaa...');
6096              },
6097              success: function (responseJSON) {
6098                global.show_message(responseJSON);
6099                global.close_loading_dialog();
6100                $dialog.dialog('close');
6101              },
6102              error: function (data) {
6103                global.show_message($.parseJSON(data.responseText));
6104                global.close_loading_dialog();
6105              },
6106            });
6107          },
6108        },
6109      });
6110  };
6111
6112  self.enableUser = function (user) {
6113    user.disabled(false);
6114  };
6115
6116  self.disableUser = function (user) {
6117    user.disabled(true);
6118  };
6119
6120  self.createKredinorClient = function(){
6121    
6122    global.showLoadingDialog('Tallennetaan...');
6123    jQuery
6124    .ajax({
6125      url: '/asiakkuudet/createKredinorClientAndWebhookSubscriptions/' + self.account.company.id(),
6126      type: 'post',
6127      dataType: 'json',
6128    })
6129    .done(function(responseJSON) {
6130
6131      if(responseJSON && responseJSON.data && responseJSON.data.username){
6132        self.account.company.kredinor_username(responseJSON.data.username);
6133      }
6134
6135      if(responseJSON && responseJSON.data && responseJSON.data.subscriptionCount){
6136        self.kredinorSubscriptionCount(responseJSON.data.subscriptionCount);
6137      }
6138
6139      global.close_loading_dialog();
6140      global.show_message(responseJSON);
6141      
6142    })
6143    .fail(function(response) {
6144      global.close_loading_dialog();
6145      global.show_message(response.responseJSON);
6146    });
6147  }
6148
6149  self.createKredinorWebhookSubscriptions = function(){
6150    
6151    global.showLoadingDialog('Luodaan Webhook-tilauksia...');
6152    jQuery
6153        .ajax({
6154          url: '/asiakkuudet/createKredinorWebhookSubscriptions/' + self.account.company.id(),
6155          type: 'post',
6156          dataType: 'json',
6157        })
6158        .done(function(responseJSON) {
6159          
6160          if(responseJSON && responseJSON.data && responseJSON.data.subscriptionCount){
6161            self.kredinorSubscriptionCount(responseJSON.data.subscriptionCount);
6162          }
6163
6164          global.close_loading_dialog();
6165          global.show_message(responseJSON);
6166        })
6167        .fail(function(response) {
6168          global.close_loading_dialog();
6169          global.show_message(response.responseJSON);
6170        });
6171  }
6172  
6173  self.toggleKredinorClientActive = function(){
6174    global.showLoadingDialog('Päivitetään...');
6175    jQuery
6176    .ajax({
6177      url: '/asiakkuudet/toggleKredinorClientActive/' + self.account.company.id(),
6178      type: 'post',
6179      dataType: 'json',
6180    })
6181    .done(function(responseJSON) {
6182      global.close_loading_dialog();
6183      global.show_message(responseJSON);
6184      self.account.company.kredinor_active(1);
6185      self.account.logs.unshift(responseJSON.data.logItem);
6186    })
6187    .fail(function(response) {
6188      global.close_loading_dialog();
6189      global.show_message(response.responseJSON);
6190    });
6191  }
6192
6193  self.resetUserPassword = function(user) {
6194    $('<div />', { style: 'text-align:left;' })
6195      .html('Haluatko varmasti resetoida käyttäjän salasanan?')
6196      .dialog({
6197        autoOpen: true,
6198        modal: true,
6199        resizable: false,
6200        draggable: false,
6201        title: 'Resetoi käyttäjän salasana',
6202        beforeclose: function (event, ui) {
6203          event.stopPropagation();
6204        },
6205        buttons: {
6206          Peruuta: function () {
6207            $(this).dialog('close');
6208          },
6209          'Resetoi salasana': function () {
6210            jQuery
6211              .ajax({
6212                url: '/asiakkuudet/reset_user_password/' + user.id() + '/',
6213                type: 'post',
6214                dataType: 'json',
6215                beforeSubmit: function () {
6216                  global.showLoadingDialog('Resetoidaan salasanaa...');
6217                },
6218              })
6219              .done(function (responseJSON) {
6220                global.show_message(responseJSON);
6221              })
6222              .fail(function (response) {
6223                global.show_message(response.responseJSON);
6224                global.close_loading_dialog();
6225              });
6226
6227            $(this).dialog('close');
6228          },
6229        },
6230      });
6231  };
6232
6233  self.resetUserMFA = function(user) {
6234    $('<div />', { style: 'text-align:left;' })
6235      .html('Haluatko varmasti resetoida käyttäjän 2-vaiheisen tunnistautumisen?')
6236      .dialog({
6237        autoOpen: true,
6238        modal: true,
6239        resizable: false,
6240        draggable: false,
6241        title: 'Resetoi käyttäjän 2-vaiheinen tunnistus',
6242        beforeclose: function (event, ui) {
6243          event.stopPropagation();
6244        },
6245        buttons: {
6246          Peruuta: function () {
6247            $(this).dialog('close');
6248          },
6249          'Resetoi': function () {
6250            jQuery
6251              .ajax({
6252                url: '/asiakkuudet/reset_user_mfa/' + user.id() + '/',
6253                type: 'post',
6254                dataType: 'json',
6255                beforeSubmit: function () {
6256                  global.showLoadingDialog('Resetoidaan 2-vaiheista tunnistusta...');
6257                },
6258              })
6259              .done(function (responseJSON) {
6260                //console.log('reset callback user:', user);
6261                user.mfa_active(0);
6262                user.mfa_secret(null);
6263                global.show_message(responseJSON);
6264              })
6265              .fail(function (response) {
6266                global.show_message(response.responseJSON);
6267                global.close_loading_dialog();
6268              });
6269
6270            $(this).dialog('close');
6271          },
6272        },
6273      });
6274  };
6275
6276  self.resetAutofuturUser = function () {
6277    self.account.autofuturUser.id(null);
6278    self.account.autofuturUser.usergroup_id(null);
6279    self.account.autofuturUser.createNewUser(false);
6280    self.account.autofuturUser.existingUser(false);
6281    self.account.autofuturUser.registrationCode('');
6282    self.account.autofuturUser.username('autofutur.');
6283    self.account.autofuturUser.email('');
6284    self.account.autofuturUser.connectionFee(99);
6285    self.account.autofuturUser.sendActivationEmailToInnovoice(false);
6286  };
6287
6288  self.smsInterface = function () {
6289    return {
6290      id: ko.observable(),
6291      email: ko.observable(),
6292      username: ko.observable(),
6293      password: ko.observable(),
6294      usergroup_id: ko.observable(),
6295      sales_name: ko.observable(),
6296      disabled: ko.observable(false),
6297    };
6298  };
6299
6300  self.addSmsInterface = function () {
6301    var smsInterface = self.smsInterface();
6302    self.account.smsInterfaces.push(smsInterface);
6303  };
6304
6305  self.removeSmsInterface = function (smsInterface) {
6306    // If existing user, confirm the removal
6307    if (smsInterface.id()) {
6308      return self.confirmRemoveSmsInterface(smsInterface);
6309    }
6310    self.account.smsInterfaces.remove(smsInterface);
6311  };
6312
6313  self.confirmRemoveSmsInterface = function (smsInterface) {
6314    var $dialog = $('<div />')
6315      .html(
6316        '<p style="font-weight:bold;"><span class="ui-icon ui-icon-alert" style="float:left; margin:0 7px 20px 0; "></span>Haluatko varmasti poistaa kyseisen myyntipuhelimen?</p>'
6317      )
6318      .dialog({
6319        resizable: false,
6320        height: 200,
6321        width: 400,
6322        title: 'Poista myyntipuhelin',
6323        modal: true,
6324        buttons: {
6325          Ei: function () {
6326            $(this).dialog('close');
6327          },
6328          Kyllä: function () {
6329            jQuery
6330              .ajax({
6331                url: '/asiakkuudet/delete_sms_interface/' + smsInterface.id(),
6332                type: 'post',
6333                dataType: 'json',
6334              })
6335              .done(function (responseJSON) {
6336                self.account.smsInterfaces.remove(smsInterface);
6337                $dialog.dialog('close');
6338                global.show_message(responseJSON);
6339              })
6340              .fail(function (response) {
6341                global.show_message(response.responseJSON);
6342                global.close_loading_dialog();
6343              });
6344          },
6345        },
6346      });
6347  };
6348
6349  self.getDefaultReviewSettings = function () {
6350    // If user selected there to be only one settings for this customer, let's fetch default setting from DB
6351
6352    if (ko.toJS(self.account.company.id) === null) return;
6353
6354    global.showLoadingDialog('Ladataan...');
6355
6356    $.ajax({
6357      method: 'GET',
6358      url: 'asiakkuudet/getDefaultReviewSettings/' + ko.toJS(self.account.company.id),
6359    })
6360      .done(function (response) {
6361        global.show_message(response);
6362        self.setReviewData(response.data, 1);
6363      })
6364      .fail(function (response) {
6365        var errorText = JSON.parse(response.responseText);
6366        global.show_message(errorText);
6367      })
6368      .always(function () {
6369        global.close_loading_dialog();
6370      });
6371  };
6372
6373  self.getStationReviewSettings = function () {
6374    // If user selected that every station will have it's own settings, let's fetch them from DB (or create if they dont exist)
6375
6376    var data = {
6377      companyId: ko.toJS(self.account.company.id),
6378      stations: ko.toJS(self.account.stations),
6379    };
6380
6381    global.showLoadingDialog('Ladataan...');
6382
6383    $.ajax({
6384      type: 'POST',
6385      url: 'asiakkuudet/getStationReviewSettings/',
6386      data: data,
6387    })
6388      .done(function (response) {
6389        global.show_message(response);
6390        self.setReviewData(response.data, 1);
6391      })
6392      .fail(function (response) {
6393        var errorText = JSON.parse(response.responseText);
6394        global.show_message(errorText);
6395      })
6396      .always(function () {
6397        global.close_loading_dialog();
6398      });
6399  };
6400
6401  self.changeMessageType = function (index) {
6402    //, obj, event
6403
6404    self.reviewData.settings()[index].message_type(self.reviewData.messageType());
6405
6406    switch (self.reviewData.messageType()) {
6407      case 'nps':
6408        self.reviewData
6409          .settings()
6410          [index].message(
6411            self.reviewData.npsMessage() /* + self.reviewData.settings()[index].screen_name(),*/
6412          );
6413        self.reviewData.settings()[index].send_reply(false);
6414        self.reviewData.settings()[index].main_user_statistics(true);
6415        break;
6416      case 'nps+':
6417      case 'nps++':
6418        self.reviewData
6419          .settings()
6420          [index].message(
6421            self.reviewData.npsMessage() /* + self.reviewData.settings()[index].screen_name(),*/
6422          );
6423        self.reviewData.settings()[index].send_reply(true);
6424        self.reviewData.settings()[index].main_user_statistics(true);
6425        break;
6426      case 'own':
6427        self.reviewData
6428          .settings()
6429          [index].message(
6430            self.reviewData.ownMessage() /* + self.reviewData.settings()[index].screen_name(),*/
6431          );
6432        self.reviewData.settings()[index].send_reply(false);
6433        self.reviewData.settings()[index].main_user_statistics(true);
6434        break;
6435      case 'own+':
6436        self.reviewData
6437          .settings()
6438          [index].message(
6439            self.reviewData.ownMessage() /* + self.reviewData.settings()[index].screen_name(),*/
6440          );
6441        self.reviewData.settings()[index].send_reply(true);
6442        self.reviewData.settings()[index].main_user_statistics(true);
6443        break;
6444      case 'msg':
6445        self.reviewData
6446          .settings()
6447          [index].message(
6448            self.reviewData.message() /* + self.reviewData.settings()[index].screen_name()*/
6449          );
6450        self.reviewData.settings()[index].send_reply(false);
6451        self.reviewData.settings()[index].main_user_statistics(false);
6452        self.reviewData.settings()[index].user_statistics(false);
6453        break;
6454      // default:
6455      //   self.reviewData.settings()[index].message('');
6456      //   self.reviewData.settings()[index].send_reply(false);
6457      //   self.reviewData.settings()[index].main_user_statistics(false);
6458      //   self.reviewData.settings()[index].user_statistics(false);
6459      //   break;
6460    }
6461  };
6462
6463  self.messageTypeChanged = () => {
6464    var i = 0;
6465
6466    self.setDefaultMessageType();
6467
6468    self.reviewData.settings().forEach(function (setting) {
6469      self.changeMessageType(i);
6470      i++;
6471    });
6472  };
6473
6474  self.setMessageForStation = (index) => {
6475    self.changeMessageType(index);
6476  };
6477
6478  self.setDefaultMessageType = () => {
6479    switch (self.reviewData.messageType()) {
6480      case 'nps':
6481      case 'nps+':
6482      case 'nps++':
6483        self.reviewData.message(self.reviewData.npsMessage() /* + '{nimimerkki}'*/);
6484        break;
6485      case 'own':
6486      case 'own+':
6487        self.reviewData.message(self.reviewData.ownMessage() /* + '{nimimerkki}'*/);
6488        break;
6489      default:
6490        if (self.reviewData.settings()[0]) {
6491          self.reviewData.message(self.reviewData.settings()[0].message());
6492        }
6493        break;
6494    }
6495  };
6496
6497  self.stationSettingChanged = function (obj, event) {
6498    if (event.originalEvent) {
6499      if (self.reviewData.stationSetting() === '0' || self.reviewData.stationSetting() === '') {
6500        self.getDefaultReviewSettings();
6501      } else {
6502        self.getStationReviewSettings();
6503      }
6504    }
6505  };
6506
6507  self.userStatisticsChanged = () => {
6508    var i = 0;
6509
6510    self.reviewData.settings().forEach(function (setting) {
6511      self.changeUserStatisticSetting(i);
6512      i++;
6513    });
6514  };
6515
6516  self.changeUserStatisticSetting = (index) => {
6517    if (self.reviewData.userStatistics()) {
6518      self.reviewData.settings()[index].user_statistics(true);
6519    } else {
6520      self.reviewData.settings()[index].user_statistics(false);
6521    }
6522  };
6523
6524  self.deleteStationSettings = (id) => {
6525    var data = {
6526      companyId: ko.toJS(self.account.company.id),
6527      stationId: id,
6528    };
6529
6530    $.ajax({
6531      type: 'POST',
6532      url: 'asiakkuudet/deleteStationSettings/',
6533      data: data,
6534    })
6535      .done(function (response) {
6536        self.setReviewData(response.data, 1);
6537      })
6538      .fail(function (response) {
6539        global.show_message(errorText);
6540      });
6541  };
6542
6543  self.setReviewMessage = () => {
6544    var i = 0;
6545    self.reviewData.settings().forEach((settings) => {
6546      self.changeMessageType(i);
6547      i++;
6548    });
6549  };
6550
6551  self.showReplyMessageInput = (reply = false) => {
6552    var messageType = self.reviewData.messageType();
6553    var sendReply = ko.toJS(reply);
6554
6555    if (sendReply === true || messageType === 'msg') return true;
6556
6557    return false;
6558  };
6559
6560  self.showAdditionalReviewFields = () => {
6561    var messageType = self.reviewData.messageType();
6562
6563    if (messageType != 'msg' && messageType != '') return true;
6564
6565    return true;
6566  };
6567
6568  self.reviewMessageType = () => {
6569    var messageType = self.reviewData.messageType();
6570
6571    if (messageType === 'nps' || messageType === 'own') return 'stats';
6572
6573    if (messageType === 'nps+' || messageType === 'own+' || messageType === 'nps++') return 'stats+';
6574
6575    if (messageType === 'msg') return 'message';
6576
6577    return '';
6578  };
6579
6580  self.followUpSettings = {
6581    id: ko.observable(null),
6582    callrobot: ko.observable(false),
6583    sms: ko.observable(true),//default true
6584    contact_person: ko.observable(true),//default true
6585    contact_person2: ko.observable(false),
6586    other_contact_persons: ko.observableArray([]),
6587    send_interval: ko.observable('3'),//default 3
6588    sms_template: ko.observable(''),
6589    enabled_at: ko.observable(null),
6590  };
6591
6592  self.resetFollowUpSettings = function(){
6593    self.followUpSettings.id(null);
6594    self.followUpSettings.callrobot(false);
6595    self.followUpSettings.sms(true);
6596    self.followUpSettings.contact_person(true);
6597    self.followUpSettings.contact_person2(false);
6598    self.followUpSettings.send_interval('3');
6599    self.followUpSettings.sms_template('');
6600    self.followUpSettings.enabled_at(null);
6601    self.followUpSettings.other_contact_persons([]);
6602  };
6603
6604  self.populateFollowUpSettings = function(data){
6605    self.resetFollowUpSettings();
6606    var smsTemplate = data.sms_template != '' ? data.sms_template : self.defaultFollowUpSmsTemplate();
6607    self.followUpSettings.id(data.id);
6608    self.followUpSettings.callrobot(data.callrobot);
6609    self.followUpSettings.sms(data.sms);
6610    self.followUpSettings.contact_person(data.contact_person);
6611    self.followUpSettings.contact_person2(data.contact_person2);
6612    self.followUpSettings.send_interval(data.send_interval);
6613    self.followUpSettings.sms_template(smsTemplate);
6614    self.followUpSettings.enabled_at(data.enabled_at);
6615    if(data.other_contact_persons && data.other_contact_persons.length > 0){
6616      data.other_contact_persons.forEach(function(contactPerson){
6617        self.followUpSettings.other_contact_persons.push({
6618          id: ko.observable(contactPerson.id),
6619          msisdn: ko.observable(contactPerson.msisdn),
6620          sales_name: ko.observable(contactPerson.sales_name),
6621        });
6622      });
6623    }
6624  }
6625  self.defaultFollowUpSmsTemplate = ko.observable();
6626  self.getFollowUpTemplateText = function(){
6627    if(self.followUpSettings.sms_template() && self.followUpSettings.sms_template() != ''){
6628      return self.followUpSettings.sms_template();
6629    }
6630    return self.defaultFollowUpSmsTemplate();
6631  };
6632  self.editFollowUpSmsText = ko.observable('');
6633
6634  self.editSmsFollowupTextDialog = function(){
6635    self.editFollowUpSmsText(self.getFollowUpTemplateText());
6636    $("#editSmsFollowupTextDialog").dialog({
6637      resizable: true,
6638      height: 400,
6639      width: 400,
6640      title: 'Tekstiviesti follow-up pohja',
6641      modal: true,
6642      buttons: {
6643        Peruuta: function(){
6644          $(this).dialog('close');
6645        },
6646        Tallenna: function(){
6647          self.saveSmsFolloupText();
6648          $(this).dialog('close');
6649        }
6650      }
6651    });
6652  };
6653
6654  self.saveSmsFolloupText = function(){
6655    var data = {
6656      companyId: ko.toJS(self.account.company.id),
6657      followUpText: ko.toJS(self.editFollowUpSmsText)
6658    };
6659
6660    jQuery
6661      .ajax({
6662        type: 'POST',
6663        dataType: 'json',
6664        url: '/asiakkuudet/saveSmsFolloupText',
6665        data: data,
6666      })
6667      .then(function(data) {
6668        if(data && data.followUpSettings)
6669          self.populateFollowUpSettings(data.followUpSettings);
6670      })
6671      .fail(function(error) {
6672        alert(error.responseJSON);
6673      });
6674  };
6675
6676  self.followUpContactPerson = function() {
6677    return {
6678      id: ko.observable(),
6679      msisdn: ko.observable(),
6680      sales_name: ko.observable(),
6681    };
6682  };
6683
6684  self.addFollowUpContactPerson = function() {
6685    var contactPerson = self.followUpContactPerson();
6686    self.followUpSettings.other_contact_persons.push(contactPerson);
6687  };
6688
6689  self.removeFollowUpContactPerson = function(contactPerson) {
6690    if (contactPerson.id()) {
6691      return self.confirmRemoveFollowUpContactPerson(contactPerson);
6692    }
6693    self.followUpSettings.other_contact_persons.remove(contactPerson);
6694  };
6695
6696  self.confirmRemoveFollowUpContactPerson = function(contactPerson) {
6697    var $dialog = $('<div />')
6698      .html(
6699        '<p style="font-weight:bold;"><span class="ui-icon ui-icon-alert" style="float:left; margin:0 7px 20px 0; "></span>Haluatko varmasti poistaa vastaanottajan?</p>'
6700      )
6701      .dialog({
6702        resizable: false,
6703        height: 200,
6704        width: 400,
6705        title: 'Poista vastaanottaja',
6706        modal: true,
6707        buttons: {
6708          Ei: function() {
6709            $(this).dialog('close');
6710          },
6711          Kyllä: function() {
6712            jQuery
6713              .ajax({
6714                url: '/asiakkuudet/delete_follow_up_contact_person/' + contactPerson.id(),
6715                type: 'post',
6716                dataType: 'json',
6717              })
6718              .done(function(responseJSON) {
6719                self.followUpSettings.other_contact_persons.remove(contactPerson);
6720                $dialog.dialog('close');
6721                global.show_message(responseJSON);
6722              })
6723              .fail(function(response) {
6724                global.show_message(response.responseJSON);
6725                global.close_loading_dialog();
6726              });
6727          },
6728        },
6729      });
6730  };
6731
6732  self.paymentTerminalDevices = ko.observableArray([]);
6733
6734  self.newPaymentTerminalDevice = {
6735    terminalId: ko.observable(''),
6736    terminalName: ko.observable(''),
6737    isDefault: ko.observable(false),
6738  };
6739
6740  self.resetNewPaymentTerminalDevice = function () {
6741    self.newPaymentTerminalDevice.terminalId('');
6742    self.newPaymentTerminalDevice.terminalName('');
6743    self.newPaymentTerminalDevice.isDefault(false);
6744  };
6745
6746  self.editPaymentTerminalDevice = {
6747    id: ko.observable(''),
6748    terminalId: ko.observable(''),
6749    terminalName: ko.observable(''),
6750    isDefault: ko.observable(false),
6751  };
6752
6753  self.resetEditPaymentTerminalDevice = function () {
6754    self.editPaymentTerminalDevice.id('');
6755    self.editPaymentTerminalDevice.terminalId('');
6756    self.editPaymentTerminalDevice.terminalName('');
6757    self.editPaymentTerminalDevice.isDefault(false);
6758  };
6759
6760  self.populateEditPaymentTerminalDevice = function (data) {
6761    self.editPaymentTerminalDevice.id(data.id);
6762    self.editPaymentTerminalDevice.terminalId(data.terminal_id);
6763    self.editPaymentTerminalDevice.terminalName(data.terminal_name);
6764    self.editPaymentTerminalDevice.isDefault(data.is_default);
6765  };
6766
6767  self.getTerminalStatus = function (device) {
6768    var data = {
6769      user_name: device.user_name,
6770      password: device.password,
6771      url: device.url,
6772      terminal_id: device.terminal_id,
6773    };
6774    window.PaymentTerminal.getTerminalStatus(data);
6775  };
6776
6777  self.addPaymentDeviceDialog = function () {
6778    $('#addPaymentDeviceDialog').dialog({
6779      resizable: false,
6780      height: 400,
6781      width: 400,
6782      title: 'Lisää uusi maksupääte',
6783      modal: true,
6784      buttons: {
6785        Peruuta: function () {
6786          $(this).dialog('close');
6787        },
6788        Tallenna: function () {
6789          self.addPaymentTerminalDevice();
6790          $(this).dialog('close');
6791        },
6792      },
6793    });
6794  };
6795
6796  self.addPaymentTerminalDevice = function () {
6797    var data = {
6798      companyId: ko.toJS(self.account.company.id),
6799      newPaymentTerminalDevice: ko.toJS(self.newPaymentTerminalDevice),
6800    };
6801
6802    jQuery
6803      .ajax({
6804        type: 'POST',
6805        dataType: 'json',
6806        url: '/asiakkuudet/addPaymentDevice',
6807        data: data,
6808      })
6809      .then(function (data) {
6810        if (self.paymentTerminalDevices.length > 0) self.paymentTerminalDevices.removeAll();
6811
6812        self.paymentTerminalDevices(data);
6813        self.resetNewPaymentTerminalDevice();
6814      })
6815      .fail(function (error) {
6816        alert(error.responseJSON);
6817      });
6818  };
6819
6820  self.togglePaymentDeviceStatus = function (action, data) {
6821    self.populateEditPaymentTerminalDevice(data);
6822    return modifyPaymentDeviceOnServer(action);
6823  };
6824
6825  self.editPaymentDeviceDialog = function (action, data) {
6826    self.populateEditPaymentTerminalDevice(data);
6827    $('#editPaymentDeviceDialog').dialog({
6828      resizable: false,
6829      height: 400,
6830      width: 400,
6831      title: 'Muokkaa maksupäätelaitteen tietoja',
6832      modal: true,
6833      buttons: {
6834        Peruuta: function () {
6835          $(this).dialog('close');
6836        },
6837        Tallenna: function () {
6838          modifyPaymentDeviceOnServer(action);
6839          $(this).dialog('close');
6840        },
6841      },
6842    });
6843  };
6844
6845  var modifyPaymentDeviceOnServer = function (action) {
6846    var data = {
6847      action: action,
6848      companyId: ko.toJS(self.account.company.id),
6849      editPaymentTerminalDevice: ko.toJS(self.editPaymentTerminalDevice),
6850    };
6851    jQuery
6852      .ajax({
6853        type: 'POST',
6854        dataType: 'json',
6855        url: 'asiakkuudet/updatePaymentDevice',
6856        data: data,
6857      })
6858      .then(function (data) {
6859        if (self.paymentTerminalDevices.length > 0) self.paymentTerminalDevices.removeAll();
6860
6861        self.paymentTerminalDevices(data);
6862        self.resetEditPaymentTerminalDevice();
6863      })
6864      .fail(function (error) {
6865        alert(error.responseJSON);
6866      });
6867  };
6868
6869  self.createInnohinausApiKey = function() {
6870    var companyId = ko.toJS(self.account.company.id);
6871
6872    global.show_loading_dialog();
6873
6874    jQuery
6875      .ajax({
6876        type: 'POST',
6877        dataType: 'json',
6878        url: `asiakkuudet/create_api_key/innohinaus/${companyId}`,
6879      })
6880      .then(function (response) {
6881        if (response.data && response.data.innohinaus) {
6882          self.apiKeys.push(response.data.innohinaus);
6883        }
6884
6885        if (response.data && response.data[`innohinaus-update`]) {
6886          self.apiKeys.push(response.data[`innohinaus-update`]);
6887        }
6888
6889        global.close_loading_dialog();
6890      })
6891      .fail(function (response) {
6892        global.show_message(response.responseJSON);
6893        global.close_loading_dialog();
6894      });
6895  };
6896
6897  self.populateEinvoiceData = function(data, log){
6898    self.account.company.invoice_company_name(data.company_name || '');
6899    self.account.company.e_invoice_address(data.e_invoice_address || '');
6900    self.account.company.e_invoice_operator(data.e_invoice_operator || '');
6901  };
6902
6903  self.populateCompanyData = function(data){
6904    self.account.company.company_name(data.company_name || '');
6905    self.account.company.address(data.address || '');
6906    self.account.company.zipcode(data.zipcode || '');
6907    self.account.company.city(data.city || '');
6908    
6909    self.account.company.phone(data.phone || '');
6910    self.account.company.email(data.email || '');
6911
6912    self.account.company.business_id(data.business_id || '');
6913  }
6914
6915  self.autoPopulating = ko.observable(false);
6916  self.autoPopulateAccount = function () {
6917    var businessId = self.account.company.business_id();
6918    if (!businessId) {
6919      return self.errorDialog('Täytä ensin yrityksen y-tunnus');
6920    }
6921
6922    if (businessId.length < 9) {
6923      return self.errorDialog('Tarkista y-tunnuksen pituus');
6924    }
6925  
6926    self.autoPopulating(true);
6927    var eInvoicePromise = jQuery
6928      .ajax({
6929        method: 'get',
6930        url: '/rest/_search/e_invoice',
6931        dataType: 'json',
6932        data: {
6933          type: 'e_invoice',
6934          identifier: businessId,
6935          originatorApp: 'asiakkuudet',
6936        },
6937      })
6938      .then(function (response) {
6939        if (!response || !response.data) {
6940          self.errorDialog('Virhe verkkolaskutietojen hakemisessa');
6941          return;
6942        }
6943        if (response.data && response.data.length > 1) {
6944          self.errorDialog('Y-tunnukselle useampi verkkolaskuosoite. Valitse oikea osoite manuaalisesti.');
6945          return;
6946        }
6947        var data = response.data && response.data[0];
6948        if (!data) {
6949          self.errorDialog('Y-tunnukselle ei löytynyt verkkolaskuosoitetta');
6950        } else {
6951          self.populateEinvoiceData(data);
6952        }
6953      })
6954      .fail(function (error) {
6955        var msg = JSON.parse(error.responseText) || 'Virhe haussa. Yritä myöhemmin uudelleen.';
6956        self.errorDialog(msg);
6957      });
6958
6959    var companyPromise = jQuery
6960      .ajax({
6961        method: 'get',
6962        url: '/rest/_search/',
6963        dataType: 'json',
6964        data: {
6965          type: 'company',
6966          identifier: businessId,
6967          originatorApp: 'asiakkuudet',
6968        },
6969      })
6970      .then(function (response) {
6971        if (!response || !response.customer) {
6972          self.errorDialog('Virhe yritystietojen hakemisessa');
6973        }
6974        var data = response.customer;
6975        if (!data) {
6976          self.errorDialog('Y-tunnukselle ei löytynyt verkkolaskuosoitetta');
6977        } else {
6978          self.populateCompanyData(data);
6979          console.log({
6980            text: 'Verkkolaskutiedot haettu onnistuneesti',
6981            addnCls: 'humane-jackedup-success',
6982          });
6983        }
6984      })
6985      .fail(function (error) {
6986        var msg = JSON.parse(error.responseText) || 'Virhe haussa. Yritä myöhemmin uudelleen.';
6987        self.errorDialog(msg);
6988      });
6989
6990    jQuery.when(eInvoicePromise, companyPromise).always(function () {
6991      self.autoPopulating(false);
6992      global.show_message({
6993            title: 'Asiakuuden automaattinen täyttö',
6994            text: 'Verkkolasku ja yrityksen tiedot haettu onnistuneesti.',
6995            type: 'success',
6996      });
6997    });
6998  }
6999
7000  self.showCreateInnohinausApiKeysBtn = ko.pureComputed(function() {
7001    return ko.toJS(self.account.preferences.mod_innohinaus_api) && self.apiKeys && !ko.utils.arrayFirst(self.apiKeys(), function(element) {
7002      return element.api_name == 'innohinaus';
7003    });
7004  });
7005
7006  self.kycBankOwnerTypes = ko.observableArray([
7007    {
7008      name: 'Valitse', value: ''
7009    },
7010    {
7011      name: 'Yritys tai yhteisö', value: 'company'
7012    },
7013    {
7014      name: 'Yksityishenkilö', value: 'person'
7015    },
7016  ])
7017
7018  self.kycRegistrationOptions = ko.observableArray([
7019    { value: '', name: 'Valitse' },
7020    { value: 'yes', name: 'On rekisterissä' },
7021    { value: 'no', name: 'Ei rekisterissä' }
7022  ])
7023
7024  self.countries = ko.observableArray([
7025    {
7026      name: 'Suomi',
7027    },
7028    {
7029      name: 'Afganistan',
7030    },
7031    {
7032      name: 'Alankomaat',
7033    },
7034    {
7035      name: 'Alankomaiden Karibia',
7036    },
7037    {
7038      name: 'Albania',
7039    },
7040    {
7041      name: 'Algeria',
7042    },
7043    {
7044      name: 'Amerikan Samoa',
7045    },
7046    {
7047      name: 'Andorra',
7048    },
7049    {
7050      name: 'Angola',
7051    },
7052    {
7053      name: 'Anguilla',
7054    },
7055    {
7056      name: 'Antarktis',
7057    },
7058    {
7059      name: 'Antigua ja Barbuda',
7060    },
7061    {
7062      name: 'Arabiemiirikunnat',
7063    },
7064    {
7065      name: 'Argentiina',
7066    },
7067    {
7068      name: 'Armenia',
7069    },
7070    {
7071      name: 'Aruba',
7072    },
7073    {
7074      name: 'Australia',
7075    },
7076    {
7077      name: 'Azerbaidžan',
7078    },
7079    {
7080      name: 'Bahama',
7081    },
7082    {
7083      name: 'Bahrain',
7084    },
7085    {
7086      name: 'Bangladesh',
7087    },
7088    {
7089      name: 'Barbados',
7090    },
7091    {
7092      name: 'Belgia',
7093    },
7094    {
7095      name: 'Belize',
7096    },
7097    {
7098      name: 'Benin',
7099    },
7100    {
7101      name: 'Bermuda',
7102    },
7103    {
7104      name: 'Bhutan',
7105    },
7106    {
7107      name: 'Bolivia',
7108    },
7109    {
7110      name: 'Bosnia ja Hertsegovina',
7111    },
7112    {
7113      name: 'Botswana',
7114    },
7115    {
7116      name: 'Bouvet’nsaari',
7117    },
7118    {
7119      name: 'Brasilia',
7120    },
7121    {
7122      name: 'Brittiläinen Intian valtameren alue',
7123    },
7124    {
7125      name: 'Brittiläiset Neitsytsaaret',
7126    },
7127    {
7128      name: 'Brunei',
7129    },
7130    {
7131      name: 'Bulgaria',
7132    },
7133    {
7134      name: 'Burkina Faso',
7135    },
7136    {
7137      name: 'Burundi',
7138    },
7139    {
7140      name: 'Caymansaaret',
7141    },
7142    {
7143      name: 'Chile',
7144    },
7145    {
7146      name: 'Cookinsaaret',
7147    },
7148    {
7149      name: 'Costa Rica',
7150    },
7151    {
7152      name: 'Curaçao',
7153    },
7154    {
7155      name: 'Djibouti',
7156    },
7157    {
7158      name: 'Dominica',
7159    },
7160    {
7161      name: 'Dominikaaninen tasavalta',
7162    },
7163    {
7164      name: 'Ecuador',
7165    },
7166    {
7167      name: 'Egypti',
7168    },
7169    {
7170      name: 'El Salvador',
7171    },
7172    {
7173      name: 'Eritrea',
7174    },
7175    {
7176      name: 'Espanja',
7177    },
7178    {
7179      name: 'Etiopia',
7180    },
7181    {
7182      name: 'Etelä-Afrikka',
7183    },
7184    {
7185      name: 'Etelä-Georgia ja Eteläiset Sandwichsaaret',
7186    },
7187    {
7188      name: 'Etelä-Sudan',
7189    },
7190    {
7191      name: 'Falklandinsaaret',
7192    },
7193    {
7194      name: 'Färsaaret',
7195    },
7196    {
7197      name: 'Fidži',
7198    },
7199    {
7200      name: 'Filippiinit',
7201    },
7202    {
7203      name: 'Gabon',
7204    },
7205    {
7206      name: 'Gambia',
7207    },
7208    {
7209      name: 'Georgia',
7210    },
7211    {
7212      name: 'Ghana',
7213    },
7214    {
7215      name: 'Gibraltar',
7216    },
7217    {
7218      name: 'Grenada',
7219    },
7220    {
7221      name: 'Grönlanti',
7222    },
7223    {
7224      name: 'Guadeloupe',
7225    },
7226    {
7227      name: 'Guam',
7228    },
7229    {
7230      name: 'Guatemala',
7231    },
7232    {
7233      name: 'Guernsey',
7234    },
7235    {
7236      name: 'Guinea',
7237    },
7238    {
7239      name: 'Guinea-Bissau',
7240    },
7241    {
7242      name: 'Guyana',
7243    },
7244    {
7245      name: 'Haiti',
7246    },
7247    {
7248      name: 'Heard ja McDonaldinsaaret',
7249    },
7250    {
7251      name: 'Honduras',
7252    },
7253    {
7254      name: 'Hongkong',
7255    },
7256    {
7257      name: 'Indonesia',
7258    },
7259    {
7260      name: 'Intia',
7261    },
7262    {
7263      name: 'Irak',
7264    },
7265    {
7266      name: 'Iran',
7267    },
7268    {
7269      name: 'Irlanti',
7270    },
7271    {
7272      name: 'Islanti',
7273    },
7274    {
7275      name: 'Israel',
7276    },
7277    {
7278      name: 'Italia',
7279    },
7280    {
7281      name: 'Itä-Timor',
7282    },
7283    {
7284      name: 'Itävalta',
7285    },
7286    {
7287      name: 'Jamaika',
7288    },
7289    {
7290      name: 'Japani',
7291    },
7292    {
7293      name: 'Jemen',
7294    },
7295    {
7296      name: 'Jersey',
7297    },
7298    {
7299      name: 'Jordania',
7300    },
7301    {
7302      name: 'Joulusaari',
7303    },
7304    {
7305      name: 'Kambodža',
7306    },
7307    {
7308      name: 'Kamerun',
7309    },
7310    {
7311      name: 'Kanada',
7312    },
7313    {
7314      name: 'Kap Verde',
7315    },
7316    {
7317      name: 'Kazakstan',
7318    },
7319    {
7320      name: 'Kenia',
7321    },
7322    {
7323      name: 'Keski-Afrikan tasavalta',
7324    },
7325    {
7326      name: 'Kiina',
7327    },
7328    {
7329      name: 'Kirgisia',
7330    },
7331    {
7332      name: 'Kiribati',
7333    },
7334    {
7335      name: 'Kolumbia',
7336    },
7337    {
7338      name: 'Komorit',
7339    },
7340    {
7341      name: 'Kongon demokraattinen tasavalta',
7342    },
7343    {
7344      name: 'Kongon tasavalta',
7345    },
7346    {
7347      name: 'Kookossaaret',
7348    },
7349    {
7350      name: 'Korean demokraattinen kansantasavalta',
7351    },
7352    {
7353      name: 'Korean tasavalta',
7354    },
7355    {
7356      name: 'Kreikka',
7357    },
7358    {
7359      name: 'Kroatia',
7360    },
7361    {
7362      name: 'Kuuba',
7363    },
7364    {
7365      name: 'Kuwait',
7366    },
7367    {
7368      name: 'Kypros',
7369    },
7370    {
7371      name: 'Laos',
7372    },
7373    {
7374      name: 'Latvia',
7375    },
7376    {
7377      name: 'Lesotho',
7378    },
7379    {
7380      name: 'Libanon',
7381    },
7382    {
7383      name: 'Liberia',
7384    },
7385    {
7386      name: 'Libya',
7387    },
7388    {
7389      name: 'Liechtenstein',
7390    },
7391    {
7392      name: 'Liettua',
7393    },
7394    {
7395      name: 'Luxemburg',
7396    },
7397    {
7398      name: 'Länsi-Sahara',
7399    },
7400    {
7401      name: 'Macao',
7402    },
7403    {
7404      name: 'Madagaskar',
7405    },
7406    {
7407      name: 'Malawi',
7408    },
7409    {
7410      name: 'Malediivit',
7411    },
7412    {
7413      name: 'Malesia',
7414    },
7415    {
7416      name: 'Mali',
7417    },
7418    {
7419      name: 'Malta',
7420    },
7421    {
7422      name: 'Mansaari',
7423    },
7424    {
7425      name: 'Marokko',
7426    },
7427    {
7428      name: 'Marshallinsaaret',
7429    },
7430    {
7431      name: 'Martinique',
7432    },
7433    {
7434      name: 'Mauritania',
7435    },
7436    {
7437      name: 'Mauritius',
7438    },
7439    {
7440      name: 'Mayotte',
7441    },
7442    {
7443      name: 'Meksiko',
7444    },
7445    {
7446      name: 'Mikronesian liittovaltio',
7447    },
7448    {
7449      name: 'Moldova',
7450    },
7451    {
7452      name: 'Monaco',
7453    },
7454    {
7455      name: 'Mongolia',
7456    },
7457    {
7458      name: 'Montenegro',
7459    },
7460    {
7461      name: 'Montserrat',
7462    },
7463    {
7464      name: 'Mosambik',
7465    },
7466    {
7467      name: 'Myanmar',
7468    },
7469    {
7470      name: 'Namibia',
7471    },
7472    {
7473      name: 'Nauru',
7474    },
7475    {
7476      name: 'Nepal',
7477    },
7478    {
7479      name: 'Nicaragua',
7480    },
7481    {
7482      name: 'Niger',
7483    },
7484    {
7485      name: 'Nigeria',
7486    },
7487    {
7488      name: 'Niue',
7489    },
7490    {
7491      name: 'Norfolkinsaari',
7492    },
7493    {
7494      name: 'Norja',
7495    },
7496    {
7497      name: 'Norsunluurannikko',
7498    },
7499    {
7500      name: 'Oman',
7501    },
7502    {
7503      name: 'Pakistan',
7504    },
7505    {
7506      name: 'Palau',
7507    },
7508    {
7509      name: 'Palestiina',
7510    },
7511    {
7512      name: 'Panama',
7513    },
7514    {
7515      name: 'Papua-Uusi-Guinea',
7516    },
7517    {
7518      name: 'Paraguay',
7519    },
7520    {
7521      name: 'Peru',
7522    },
7523    {
7524      name: 'Pohjois-Mariaanit',
7525    },
7526    {
7527      name: 'Pitcairn',
7528    },
7529    {
7530      name: 'Pohjois-Makedonia',
7531    },
7532    {
7533      name: 'Portugali',
7534    },
7535    {
7536      name: 'Puerto Rico',
7537    },
7538    {
7539      name: 'Puola',
7540    },
7541    {
7542      name: 'Päiväntasaajan Guinea',
7543    },
7544    {
7545      name: 'Qatar',
7546    },
7547    {
7548      name: 'Ranska',
7549    },
7550    {
7551      name: 'Ranskan eteläiset alueet',
7552    },
7553    {
7554      name: 'Ranskan Guayana',
7555    },
7556    {
7557      name: 'Ranskan Polynesia',
7558    },
7559    {
7560      name: 'Réunion',
7561    },
7562    {
7563      name: 'Romania',
7564    },
7565    {
7566      name: 'Ruanda',
7567    },
7568    {
7569      name: 'Ruotsi',
7570    },
7571    {
7572      name: 'Saint Barthélemy',
7573    },
7574    {
7575      name: 'Saint Helena, Ascension ja Tristan da Cunha',
7576    },
7577    {
7578      name: 'Saint Kitts ja Nevis',
7579    },
7580    {
7581      name: 'Saint Lucia',
7582    },
7583    {
7584      name: 'Saint Martin (Ranska)',
7585    },
7586    {
7587      name: 'Saint-Pierre ja Miquelon',
7588    },
7589    {
7590      name: 'Saint Vincent ja Grenadiinit',
7591    },
7592    {
7593      name: 'Saksa',
7594    },
7595    {
7596      name: 'Salomonsaaret',
7597    },
7598    {
7599      name: 'Sambia',
7600    },
7601    {
7602      name: 'Samoa',
7603    },
7604    {
7605      name: 'San Marino',
7606    },
7607    {
7608      name: 'São Tomé ja Príncipe',
7609    },
7610    {
7611      name: 'Saudi-Arabia',
7612    },
7613    {
7614      name: 'Senegal',
7615    },
7616    {
7617      name: 'Serbia',
7618    },
7619    {
7620      name: 'Seychellit',
7621    },
7622    {
7623      name: 'Sierra Leone',
7624    },
7625    {
7626      name: 'Singapore',
7627    },
7628    {
7629      name: 'Sint Maarten (Alankomaat)',
7630    },
7631    {
7632      name: 'Slovakia',
7633    },
7634    {
7635      name: 'Slovenia',
7636    },
7637    {
7638      name: 'Somalia',
7639    },
7640    {
7641      name: 'Sri Lanka',
7642    },
7643    {
7644      name: 'Sudan',
7645    },
7646    {
7647      name: 'Suriname',
7648    },
7649    {
7650      name: 'Svalbard ja Jan Mayen',
7651    },
7652    {
7653      name: 'Swazimaa',
7654    },
7655    {
7656      name: 'Sveitsi',
7657    },
7658    {
7659      name: 'Syyria',
7660    },
7661    {
7662      name: 'Tadžikistan',
7663    },
7664    {
7665      name: 'Taiwan',
7666    },
7667    {
7668      name: 'Tansania',
7669    },
7670    {
7671      name: 'Tanska',
7672    },
7673    {
7674      name: 'Thaimaa',
7675    },
7676    {
7677      name: 'Togo',
7678    },
7679    {
7680      name: 'Tokelau',
7681    },
7682    {
7683      name: 'Tonga',
7684    },
7685    {
7686      name: 'Trinidad ja Tobago',
7687    },
7688    {
7689      name: 'Tšad',
7690    },
7691    {
7692      name: 'Tšekki',
7693    },
7694    {
7695      name: 'Tunisia',
7696    },
7697    {
7698      name: 'Turkki',
7699    },
7700    {
7701      name: 'Turkmenistan',
7702    },
7703    {
7704      name: 'Turks- ja Caicossaaret',
7705    },
7706    {
7707      name: 'Tuvalu',
7708    },
7709    {
7710      name: 'Uganda',
7711    },
7712    {
7713      name: 'Ukraina',
7714    },
7715    {
7716      name: 'Unkari',
7717    },
7718    {
7719      name: 'Uruguay',
7720    },
7721    {
7722      name: 'Uusi-Kaledonia',
7723    },
7724    {
7725      name: 'Uusi-Seelanti',
7726    },
7727    {
7728      name: 'Uzbekistan',
7729    },
7730    {
7731      name: 'Valko-Venäjä',
7732    },
7733    {
7734      name: 'Vanuatu',
7735    },
7736    {
7737      name: 'Vatikaanivaltio (Pyhä istuin)',
7738    },
7739    {
7740      name: 'Venezuela',
7741    },
7742    {
7743      name: 'Venäjä',
7744    },
7745    {
7746      name: 'Vietnam',
7747    },
7748    {
7749      name: 'Viro',
7750    },
7751    {
7752      name: 'Wallis ja Futunasaaret',
7753    },
7754    {
7755      name: 'Yhdistynyt kuningaskunta',
7756    },
7757    {
7758      name: 'Yhdysvallat',
7759    },
7760    {
7761      name: 'Yhdysvaltain Neitsytsaaret',
7762    },
7763    {
7764      name: 'Yhdysvaltain pienet erillissaaret',
7765    },
7766    {
7767      name: 'Zimbabwe',
7768    },
7769  ]);
7770};
7771
7772;var getNegativeValue = function(val){
7773    return parseFloat(String(ko.toJS(val)).replace(",", ".")) * -1;
7774};
7775
7776// format sum in view.
7777var formatAmount = function(amount) {
7778    var formatted = (+ ('' + ko.toJS(amount)).replace(',','.'));
7779    return formatted.toFixed(2).replace('.',',');
7780};
7781
7782var CreditInvoiceDialogVm = function(params) {
7783
7784  'use strict';
7785  var self = this;
7786
7787    self.changed = ko.observable(false); // A pub-sub flag that parent subscribers can check for
7788    self.crediting = ko.observable(false); // Flag to check if we should show spinner when crediting
7789    self.credited = ko.observable(false);
7790
7791    self.dialog = null; // reference to jQuery ui dialog obj
7792
7793    self.infoModal = {
7794
7795        $elem: $('#infoModal'),
7796        title: ko.observable(''),
7797        text: ko.observable(''),
7798
7799        show: function(text, title){
7800
7801            this.text(text);
7802            this.title(title);
7803
7804            this.$elem.dialog({
7805
7806                width:400,
7807                //height:200,
7808                autoOpen: true,
7809                modal: true,
7810                resizable: false,
7811                draggable: false,
7812                beforeclose: function(event, ui) {event.stopPropagation();},
7813                close: function(){
7814                    self.changed(true); //Set the changed param to true, so parent Dialog knows to refresh
7815                    $(this).dialog('destroy');
7816                    return true;
7817                },
7818                buttons: {
7819                    'Ok': function() {
7820                        $(this).dialog('close');
7821                    }
7822                }
7823            });
7824        }
7825    };
7826
7827    self.errorModal = {
7828
7829        $elem: $('#errorModal'),
7830        title: ko.observable(''),
7831        text: ko.observable(''),
7832
7833        show: function(text, title){
7834
7835            this.text(text);
7836            this.title(title);
7837
7838            this.$elem.dialog({
7839
7840                width:400,
7841                //height:200,
7842                autoOpen: true,
7843                modal: true,
7844                resizable: false,
7845                draggable: false,
7846                beforeclose: function(event, ui) {event.stopPropagation();},
7847                close: function(){
7848                    $(this).dialog('destroy')
7849                },
7850                buttons: {
7851                    'Sulje': function() {
7852                        $(this).dialog('close');
7853                    }
7854                }
7855            });
7856        }
7857    };
7858
7859    self.invoiceCreditAmount = ko.observable(false);
7860
7861    self.selectedCreditType = ko.observable();
7862
7863    self.selectedCreditSubType = ko.observable();
7864
7865    self.setSelectedCreditType = function(){
7866
7867        if(self.invoice.type() === 'credit_note' || self.invoice.type() === 'paid_to_customer'){
7868            return self.selectedCreditType('amountToPay');
7869        }
7870
7871        if(self.openAmountCreditingIsAllowed()){
7872            return self.selectedCreditType('openAmount');
7873        }
7874    };
7875
7876    self.setSelectedCreditSubType = function(){
7877
7878        if(self.vatExcludedCreditingIsAllowed() && self.vatAmountCreditingIsAllowed()){
7879            return self.selectedCreditSubType('vatIncluded');
7880        }
7881
7882        if(self.vatExcludedCreditingIsAllowed()){
7883            return self.selectedCreditSubType('vatExcluded');
7884        }
7885
7886        if(self.vatAmountCreditingIsAllowed()){
7887            return self.selectedCreditSubType('vatAmount');
7888        }
7889    };
7890
7891    self.vatOptions = ko.observableArray(['25.5', '24', '14', '10', '0']);
7892
7893    self.preferences = ko.mapping.fromJS(params.preferences);
7894    self.invoice = ko.mapping.fromJS(params.invoice);
7895    self.invoiceTotals = ko.mapping.fromJS(params.invoiceTotals);
7896
7897    var today = new Date(),
7898        dd = String(today.getDate()).padStart(2, '0'),
7899        mm = String(today.getMonth() + 1).padStart(2, '0'),
7900        yyyy = today.getFullYear();
7901
7902    //Holds details about the creditInvoice thats going to be applied
7903    self.creditInvoice = {
7904        items: ko.observableArray([]),
7905        deliveryOptions: {
7906            deliveryMethod: ko.observable('no_delivery'), //How creditInvoice will be delivered, mail/email/no_delivery
7907            email: ko.observable('')
7908        },
7909        partlyCreditAmount: ko.observable(),
7910        ownRiskAmount: ko.observable(),
7911        paidToCustomerAmount: ko.observable(self.invoiceTotals.amountToPay()),
7912        paidToCustomerDate: ko.observable(dd + '.' + mm + '.' + yyyy),
7913        vatDetails: ko.observableArray([]),
7914        creditType: ko.computed(function (){
7915            return self.selectedCreditType();
7916        }),
7917        creditSubType: ko.computed(function (){
7918            return self.selectedCreditSubType();
7919        }),
7920    };
7921
7922
7923    self.creditInvoice.makeItems = function(){
7924
7925        var amountToCreditLeft = self.creditInvoice.creditAmount();
7926
7927        var items = [], makeItem = function(invoiceVatDetailRow){
7928
7929            var creditType = self.selectedCreditType(),
7930                creditSubType = self.selectedCreditSubType(),
7931                type = 'credit',
7932                name =  'Hyvitys',
7933                unitprice = invoiceVatDetailRow.vatIncludedAmount > amountToCreditLeft ? amountToCreditLeft : invoiceVatDetailRow.vatIncludedAmount,
7934                unit = 'kpl',
7935                vat = invoiceVatDetailRow.vat,
7936                vat_included = 1;
7937
7938            if(creditSubType === 'vatIncluded'){
7939                type = 0;
7940            }
7941
7942            if(creditSubType === 'vatExcluded'){
7943                type = 20;
7944                name = 'Hyvitys, ALV-0%';
7945            }
7946
7947            if(creditSubType === 'vatAmount'){
7948                type = 21;
7949                name = 'Hyvitys, ALV';
7950            }
7951
7952            if(creditType === 'ownRisk'){
7953                name = 'Omavastuu';
7954                type = 60;
7955                vat = 0;
7956            }
7957
7958            if(creditType === 'paidToCustomer'){
7959                name = 'Maksettu suoraan myyjälle';
7960            }
7961
7962            if(creditType === 'vatExcludedAmount'){
7963                vat_included = 0;
7964                name = 'Vakuutusyhtiön osuus';
7965                type = 43;
7966            }
7967
7968            if(creditType === 'vatAmount'){
7969                vat_included = 0;
7970                name = 'ALV-vähennys';
7971                type = 41;
7972            }
7973
7974            if(self.invoice.type() === 'credit_note'){
7975                name = 'Hyvityslaskun mitätöinti (' + self.invoice.invoice_number() + ')';
7976                unitprice = invoiceVatDetailRow.vatIncludedAmount * -1;
7977            }
7978
7979            amountToCreditLeft -= unitprice;
7980
7981            return {
7982                type: ko.observable(type),
7983                name: ko.observable(name),
7984                unitprice: ko.observable(unitprice),
7985                unit: ko.observable(unit),
7986                vatFreeAmount: ko.observable(),
7987                vatAmount: ko.observable(),
7988                vatIncludedAmount: ko.observable(),
7989                vat: ko.observable(vat),
7990                vat_included: ko.observable(vat_included)
7991             };
7992        };
7993
7994        _.each(ko.toJS(self.invoiceTotals.vatDetails), function(elem, index){
7995            //console.log('_.each ...');
7996            //console.log(elem, index);
7997            //console.log('amountToCreditLeft before:', amountToCreditLeft);
7998
7999            if(self.invoice.type() !== 'credit_note' && amountToCreditLeft < 0){
8000                items.push(makeItem(elem));
8001            }
8002
8003            if(self.invoice.type() === 'credit_note' && amountToCreditLeft > 0){
8004                items.push(makeItem(elem));
8005            }
8006
8007            if(self.invoice.type() === 'paid_to_customer'){
8008                items.push(makeItem(elem));
8009            }
8010
8011            //console.log('amountToCreditLeft after:', amountToCreditLeft);
8012        });
8013
8014        self.creditInvoice.items(items);
8015    };
8016
8017    self.creditInvoice.creditAmount = ko.computed(function(){
8018
8019        var creditType = self.selectedCreditType(),
8020            creditAmount = self.invoiceTotals[creditType];
8021
8022        //Override calculation of ownRisk creditAmount
8023        if(creditType === 'ownRisk'){
8024            creditAmount = ko.toJS(self.creditInvoice.ownRiskAmount);
8025        }
8026
8027        //Override calculation of ownRisk creditAmount
8028        if(creditType === 'paidToCustomer'){
8029            creditAmount = ko.toJS(self.creditInvoice.paidToCustomerAmount);
8030        }
8031
8032        //Override calculation of custom creditAmount
8033        if(creditType === 'partly'){
8034            creditAmount = ko.toJS(self.creditInvoice.partlyCreditAmount);
8035        }
8036
8037        //Make creditAmount always negative
8038        creditAmount = getNegativeValue(creditAmount);
8039
8040        if(isNaN(creditAmount)){
8041            return 0;
8042        }
8043
8044        return creditAmount;
8045    });
8046
8047    //CreditAmount has changed, make new creditItems
8048    self.creditInvoice.creditAmount.subscribe(function(){
8049        self.creditInvoice.makeItems();
8050    });
8051
8052    self.selectedCreditType.subscribe(function(){
8053        self.setSelectedCreditSubType();
8054        self.creditInvoice.makeItems();
8055    });
8056
8057    self.selectedCreditSubType.subscribe(function(){
8058        self.creditInvoice.makeItems();
8059    });
8060
8061    self.creditInvoice.openAmountAfterCreditInvoice = ko.computed(function(){
8062
8063        var openAmount = parseFloat(ko.toJS(self.invoiceTotals.openAmount)),
8064            creditAmount = self.creditInvoice.creditAmount();
8065
8066        if(isNaN(openAmount) || isNaN(creditAmount)){
8067            return 0;
8068        }
8069
8070        //creditAmount will always be negative
8071        openAmount = (openAmount + creditAmount);
8072
8073        //Return 0 if openAmount would be less than zero
8074        return openAmount < 0 ? 0 : openAmount;
8075    });
8076
8077    self.creditInvoice.amountToPayAfterCreditInvoice = ko.computed(function(){
8078
8079        var amountToPay = parseFloat(ko.toJS(self.invoiceTotals.amountToPay)),
8080            creditAmount = self.creditInvoice.creditAmount();
8081
8082        if(isNaN(amountToPay) || isNaN(creditAmount)){
8083            return 0;
8084        }
8085
8086        //creditAmount will always be negative
8087        amountToPay = (amountToPay + creditAmount);
8088
8089        if(self.invoice.type() === 'credit_note'){
8090            return amountToPay;
8091        }
8092
8093        //Return 0 if openAmount would be less than zero
8094        return amountToPay < 0 ? 0 : amountToPay;
8095    });
8096
8097    self.getCreditAmountFromVatDetails = function(){
8098
8099        var creditAmount = 0, vatDetails = ko.toJS(self.creditInvoice.vatDetails);
8100
8101        _.each(vatDetails, function(elem, index){
8102
8103            creditAmount += (+ ko.toJS(elem.vatFreeAmount).toString().replace(",", "."));
8104            creditAmount += (+ ko.toJS(elem.vatAmount).toString().replace(",", "."));
8105        });
8106
8107        return creditAmount;
8108    };
8109
8110    self.setData = function(){
8111
8112        self.reset();
8113        self.setSelectedCreditType();
8114        self.presetDeliveryMethod();
8115    };
8116
8117    //Preset the delivery method to the same as on crossed invoice
8118    self.presetDeliveryMethod = function(){
8119
8120        var crossedInvoiceDeliveryMethod = ko.toJS(self.invoice.delivery_by),
8121            deliverCreditNotesToCustomers =  ko.toJS(self.preferences.credit_note_delivery);
8122
8123        if(deliverCreditNotesToCustomers)
8124            self.creditInvoice.deliveryOptions.deliveryMethod(crossedInvoiceDeliveryMethod);
8125    };
8126
8127    self.reset = function(){
8128        self.selectedCreditType(false);
8129        self.creditInvoice.vatDetails([]);
8130        self.creditInvoice.items([]);
8131    };
8132
8133  self.show = function(isAdmin = false){
8134
8135      //If jQuery UI dialog has not been inited yet
8136      if(self.dialog === null){
8137
8138          self.dialog = $('#credit-invoice-dialog').dialog({
8139
8140              width:800,
8141              height:600,
8142              autoOpen: false,
8143              modal: true,
8144              resizable: false,
8145              draggable: false,
8146              beforeclose: function(event) {
8147                  $('link#extrabs').remove();
8148                  $('script#bsjs').remove();
8149                  event.stopPropagation();
8150                  $('#errorModal')
8151              },
8152              close: function(){
8153                self.close();
8154              },
8155              title: 'Lisää hyvitys laskuun',
8156              buttons: {
8157                  'Sulje': function() {
8158                      self.dialog.dialog('close');
8159                  }
8160              }
8161          });
8162      }
8163
8164      self.dialog.dialog('open');
8165
8166      // Only append BS if it's not loaded already
8167      if (isAdmin === false) {
8168        self.dialog.append(
8169          $('<link />', {
8170            id: 'extrabs',
8171            rel: 'stylesheet',
8172            href:'//netdna.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css'}
8173          )
8174        );
8175      }
8176  };
8177
8178    self.close = function(){
8179
8180        if(self.dialog){
8181            self.dialog.dialog('destroy');
8182            self.dialog = null;
8183        }
8184    };
8185
8186    self.makeCreditInvoice = function(){
8187
8188        try {
8189            self.validateCreditInvoice();
8190        }catch(exception){
8191            return self.errorModal.show(exception, 'Virhe luotaessa hyvitystä');
8192        }
8193
8194
8195        var data = {
8196            invoiceId: ko.toJS(self.invoice.id),
8197            creditInvoice: ko.toJS(self.creditInvoice)
8198        };
8199
8200        self.crediting(true);
8201
8202        //Show success / error message
8203        $.ajax({
8204            type: 'post',
8205            url: '/iv_laskutus_ja_reskontra/creditInvoice',
8206            data: data
8207        }).fail(function(response) {
8208            self.crediting(false);
8209
8210            var parsed = $.parseJSON(response.responseText);
8211            //console.log(parsed);
8212            self.errorModal.show(parsed.text, 'Virhe luotaessa hyvitystä');
8213        }).done(function(response) {
8214            //console.log(response);
8215            self.crediting(false);
8216            self.credited(true);
8217            self.infoModal.show(response.text, 'Hyvitys luotu onnistuneesti');
8218
8219            //Refresh the datatables
8220            if(pages.iv_laskutus_ja_reskontra.$datatable_iv != null){
8221                pages.iv_laskutus_ja_reskontra.$datatable_iv.fnClearTable( 0 );
8222                pages.iv_laskutus_ja_reskontra.$datatable_iv.fnDraw();
8223            }
8224
8225            if(pages.iv_laskutus_ja_reskontra.$datatable != null){
8226                pages.iv_laskutus_ja_reskontra.$datatable.fnClearTable( 0 );
8227                pages.iv_laskutus_ja_reskontra.$datatable.fnDraw();
8228            }
8229
8230            if(pages.reskontra.$datatable != null){
8231                pages.reskontra.$datatable.fnClearTable( 0 );
8232                pages.reskontra.$datatable.fnDraw();
8233            }
8234        });
8235
8236    };
8237
8238    self.validateCreditInvoice = function(){
8239
8240        //Check that there is enough vatIncluded amount left on invoice to credit
8241        var creditAmount = self.creditInvoice.creditAmount(),
8242            invoiceTotals = ko.mapping.toJS(params.invoiceTotals);
8243
8244        if(self.invoice.type() !== 'credit_note' && self.invoice.type() !== 'paid_to_customer' && Math.abs(creditAmount) > invoiceTotals.amountToPay){
8245            throw "Hyvitettävä summa ylittää laskun maksettavan summan. Tarkista hyvitys!";
8246        }
8247
8248        if(self.selectedCreditType() === 'partly'){
8249
8250            if(self.selectedCreditSubType() === 'vatExcluded' && (creditAmount >  invoiceTotals.vatExcludedAmount)){
8251                throw 'Hyvitettävä summa ylittää laskun ALV-0% osuuden. Tarkista hyvitys!';
8252            }
8253
8254            if(self.selectedCreditSubType() === 'vatAmount' && (creditAmount >  invoiceTotals.vatAmount)){
8255                throw 'Hyvitettävä summa ylittää laskun ALV-osuuden. Tarkista hyvitys!';
8256            }
8257        }
8258    };
8259
8260
8261    self.openAmountCreditingIsAllowed = ko.computed(function(){
8262
8263        var invoiceTotals = ko.mapping.toJS(params.invoiceTotals);
8264
8265        return (invoiceTotals.openAmount > 0 && (invoiceTotals.amountToPay != invoiceTotals.openAmount));
8266    });
8267
8268    self.amountToPayCreditingIsAllowed  = ko.computed(function(){
8269
8270        var invoiceTotals = ko.mapping.toJS(params.invoiceTotals);
8271
8272        return ((self.invoice.type() !== 'credit_note' && invoiceTotals.amountToPay > 0)
8273        || (self.invoice.type() === 'credit_note' && invoiceTotals.amountToPay < 0));
8274    });
8275
8276    self.vatExcludedCreditingIsAllowed  = ko.computed(function(){
8277
8278        var invoiceTotals = ko.mapping.toJS(params.invoiceTotals);
8279
8280        return (invoiceTotals.vatExcludedAmount > 0);
8281    });
8282
8283    self.vatAmountCreditingIsAllowed  = ko.computed(function(){
8284
8285        var invoiceTotals = ko.mapping.toJS(params.invoiceTotals);
8286
8287        return (invoiceTotals.vatAmount > 0);
8288    });
8289
8290    self.creditingIsAllowed = ko.computed(function(){
8291
8292        if(self.invoice.type() === 'corporate_chain_invoice')
8293            return false;
8294
8295        if(self.invoice.type() === 'paid_to_customer')
8296            return true;
8297
8298        return (self.openAmountCreditingIsAllowed() || self.amountToPayCreditingIsAllowed());
8299    });
8300
8301    self.creditingNotAllowedText = ko.computed(function () {
8302
8303        var invoiceTotals = ko.mapping.toJS(params.invoiceTotals);
8304        
8305        if(self.invoice.type() === 'corporate_chain_invoice')
8306            return 'Ketjulaskulle ei voida suoraan tehdä hyvitystä. Hyvitykset tulee tehdä alkuperäiselle laskulle.';
8307
8308        if(invoiceTotals.openAmount === 0){
8309            return 'Laskuun ei voida kohdistaa hyvityksiä. Laskulla ei maksettavaa osuutta.'
8310        }
8311
8312        return '';
8313    })
8314
8315};
8316
8317;
8318var CustomerCreditInvoiceDialogVM = function () {
8319
8320  'use strict';
8321  var self = this;
8322
8323  //constanst
8324  self.dialog = null;
8325  self.dialogElem = '#customer-credit-invoice-dialog';
8326  self.invoiceVatAmount = 0;
8327  self.invoiceVatFreeAmount = 0;
8328  // observables
8329  self.data = {
8330    creditType: ko.observable(''),
8331    amount: ko.observable(0),
8332    vatBase: ko.observable(),
8333    vatDetails: null,
8334    itemsToCredit: ko.observableArray([]),
8335  };
8336  self.invoiceId = ko.observable(0)
8337  self.amountToCredit = ko.observable(0)
8338  self.amountToCreditVat = ko.observable(0)
8339  self.amountToCreditVatFree = ko.observable(0)
8340  self.items = ko.observableArray([]);
8341  self.amountToPay = ko.observable(0);
8342  self.openAmount = ko.observable(0);
8343  self.openAmountAfterCredit = ko.observable(0);
8344  self.amountToPayAfterCredit = ko.observable(0);
8345  self.hasMultipleVatBases = ko.observable(false);
8346  self.isInsuranceInvoice = ko.observable(false);
8347  self.inputAmount = ko.observable(0);
8348  self.invoiceStatus = ko.observable('');
8349
8350  self.toPrice = function (value) {
8351    var amount = value.toFixed(2)
8352    return amount.replace('.', ',') + ' €'
8353  }
8354
8355  self.shouldShowReminderFeesOption = ko.computed(function() {
8356    var status = self.invoiceStatus();
8357
8358    return status === '11' || status === '13'
8359  });
8360
8361  function getItemSum(items) {
8362    let sum = 0;
8363    let vatTotal = 0;
8364    items.forEach(function (item) {
8365      sum += parseFloat(item.itemTotal.replace(',', '.'));
8366      vatTotal += parseFloat(item.vatTotal.replace(',', '.'));
8367    })
8368    return { sum, vatTotal }
8369  }
8370
8371  function setItemSum(items) {
8372    let { sum, vatTotal } = getItemSum(items)
8373    self.data.amount(sum);
8374    self.amountToCreditVat(self.toPrice(vatTotal))
8375    self.amountToCreditVatFree(self.toPrice(sum - vatTotal))
8376  }
8377
8378  function getVatForOpenAmount() {
8379    let { sum, vatTotal } = getItemSum(self.items())
8380    let percentage = self.openAmount() / self.amountToPay()
8381
8382    self.amountToCreditVat(self.toPrice(vatTotal * percentage))
8383    self.amountToCreditVatFree(self.toPrice((sum - vatTotal) * percentage))
8384  }
8385
8386  self.data.itemsToCredit.subscribe(function (newItems) {
8387    setItemSum(newItems);
8388  }, 'change')
8389
8390  self.data.amount.subscribe(function (value) {
8391    self.amountToCredit(value);
8392
8393    switch (self.data.creditType()) {
8394      case 'items':
8395      case 'full':
8396      case 'openAmount':
8397      case 'removeFeesAndInterests':
8398        return;
8399      default:
8400        if (value === 0) {
8401          self.amountToCreditVat(self.toPrice(0))
8402          self.amountToCreditVatFree(self.toPrice(0))
8403          return;
8404        }
8405        if (!isNaN(parseInt(self.data.vatBase()))) {
8406          const vat = parseInt(self.data.vatBase());
8407          const vatFree = value / (1 + (vat / 100))
8408          const vatAmount = value - vatFree
8409          self.amountToCreditVat(self.toPrice(vatAmount))
8410          self.amountToCreditVatFree(self.toPrice(vatFree))
8411          return;
8412        }
8413        self.amountToCreditVat('-')
8414        self.amountToCreditVatFree('-')
8415    }
8416  }, 'change')
8417
8418  self.amountToCredit.subscribe(function (value) {
8419    self.openAmountAfterCredit(self.openAmount() - value);
8420    self.amountToPayAfterCredit(self.amountToPay() - value);
8421  }, 'change')
8422
8423  self.data.creditType.subscribe(function (type) {
8424    switch (type) {
8425      case 'full':
8426        self.data.amount(self.amountToPay());
8427        self.amountToCreditVat(self.toPrice(self.invoiceVatAmount))
8428        self.amountToCreditVatFree(self.toPrice(self.invoiceVatFreeAmount))
8429        return;
8430      case 'openAmount':
8431        self.data.amount(self.openAmount());
8432        getVatForOpenAmount();
8433        return;
8434      case 'partial':
8435        if (self.inputAmount() != 0) {
8436          $('input#amount_to_credit_input').first().trigger('change')
8437        }
8438        return self.data.amount(self.data.amount());
8439      case 'items':
8440        return setItemSum(self.data.itemsToCredit());
8441    }
8442  })
8443  // init the link to other popup
8444  $('p.header-remark a#create-request-for-crediting').first().on('click', function (event) {
8445    event.preventDefault();
8446    if (window.LaskutusJaReskontra) {
8447      window.LaskutusJaReskontra.invoiceDialog.showRequestForCreditingDialog();
8448    }
8449  })
8450
8451  $('input#amount_to_credit_input').first().on('change', function (event) {
8452    var value = event.target.value;
8453    if (value.match(/^\d+([\.|\,]?\d{1,2})?$/)) {
8454      var amount = value.replace(',', '.')
8455      self.data.amount(parseFloat(amount))
8456      $('#credit-amount-input-warning').first().remove()
8457      return;
8458    }
8459    $(this).after('<div id="credit-amount-input-warning" style="position: absolute; z-index: 10; border-radius: 3px; color: #ad3f1a;">Virheellinen numeromuoto</div>')
8460  })
8461
8462  $('input#amount_to_credit_input').first().on('focus', function (event) {
8463    $(this).trigger('select')
8464
8465  })
8466
8467
8468  self.validateAndSetData = function (data) {
8469
8470    if (data.invoice_items.length === 0) {
8471      throw Error('Virhe laskuriveissä. Hyvitystä ei voida luoda.')
8472    }
8473    if (Object.keys(data.vatDetails).length === 0) {
8474      throw Error('Virhe haettaessa laskun alv-kantaa. Hyvitystä ei voida luoda.')
8475    }
8476    if (typeof data.invoiceTotals.amountToPay === 'undefined' || typeof data.invoiceTotals.openAmount === 'undefined') {
8477      throw Error('Laskun tiedoissa havaitu virhe. Hyvitystä ei voida luoda.')
8478    }
8479
8480    var originatorApp = data.invoice.originator_app;
8481
8482    if (
8483      (originatorApp === 'innokorjaamo') ||
8484      (originatorApp === 'innorahti') ||
8485      (originatorApp === 'innohinaus') ||
8486      (originatorApp === 'innohinaus-app') ||
8487      (originatorApp === 'tujaus')
8488    ) {
8489      return { creditingNotAllowed: true }
8490    }
8491
8492    self.isInsuranceInvoice(data.isInsuranceCompany);
8493    // If we have insurance related items set isInsuranceInvoice. If we have other non 0 type items, dont allow creditting
8494    var hasNonNormalItems = false
8495    data.invoice_items.forEach(item => {
8496      
8497      let type = parseInt(item.type);
8498
8499      if(([41, 42, 43, 60].indexOf(type) !== -1)){
8500        self.isInsuranceInvoice(true);
8501      }
8502    
8503      if ([2, 3, 6, 20, 21, 40].indexOf(type) !== -1) {
8504        hasNonNormalItems = true;
8505      }
8506    })
8507    if (hasNonNormalItems) {
8508      return { creditingNotAllowed: true }
8509    }
8510
8511    // set constants
8512    self.invoiceId(data.invoice.id);
8513    self.invoiceVatAmount = data.invoiceTotals.vatAmount;
8514    self.invoiceVatFreeAmount = data.invoiceTotals.vatExcludedAmount;
8515    self.invoiceStatus(data.invoice.status);
8516
8517    //set observables
8518    self.items(data.invoice_items)
8519    if (Object.keys(data.vatDetails).length > 1) {
8520      self.hasMultipleVatBases(true)
8521    } else {
8522      var vatDetails = Object.values(data.vatDetails)[0];
8523      self.data.vatBase(vatDetails.vatRate);
8524      self.data.vatDetails = {
8525        vatName: vatDetails.vatName,
8526        vatType: vatDetails.vatType,
8527        vatUnit: vatDetails.vatUnit,
8528        vatCode: vatDetails.vatCode
8529      }
8530    }
8531    self.amountToPay(data.invoiceTotals.amountToPay);
8532    self.openAmount(data.invoiceTotals.openAmount);
8533
8534    return { creditingNotAllowed: false }
8535  }
8536
8537  self.confirmationModal = {
8538    $elem: $('#confirmationModal'),
8539    partialCreditText: ko.computed(function () {
8540      if (self.data.creditType() == 'full') {
8541        if(self.isInsuranceInvoice()){
8542          return '<strong>HUOM!</strong><br><br>Olet hyvittämässä vakuutustapaukseen liittyvää laskua.' +
8543                  '<br><br><strong>Huomioithan, että tapaukseen liittyy mahdollisesti useampi lasku (vakuutusyhtiön lasku, omavastuulasku, ALV-lasku) jotka tulee hyvittää erikseen.</strong>' + 
8544                  '<br><br>Haluatko varmasti hyvittää koko laskun?';
8545        }
8546        return 'Haluatko varmasti hyvittää koko laskun?';
8547      } else if (self.data.creditType() == 'removeFeesAndInterests') {
8548        return 'Haluatko varmasti hyvittää laskulle kertyneet muistutus- ja korkokulut?';
8549      }
8550      else {
8551        return 'Haluatko varmasti hyvittää laskusta ' + self.toPrice(self.amountToCredit()) + '?';
8552      }
8553
8554
8555    }),
8556
8557    show: function (callback) {
8558      var error = self.validateData()
8559      if (error) {
8560        return global.show_message({ type: 'error', text: error })
8561      }
8562
8563      var modalTitle = self.data.creditType() === 'removeFeesAndInterests' 
8564        ? 'Vahvista muistutus- ja korkokulujen hyvitys'
8565        : 'Varmista hyvitys';
8566
8567      var action = self.data.creditType() === 'removeFeesAndInterests' ? 'Vahvista hyvitys' : 'Lisää hyvitys';
8568
8569      this.$elem.dialog({
8570
8571        width: 600,
8572        //height:200,
8573        autoOpen: true,
8574        modal: true,
8575        resizable: false,
8576        draggable: false,
8577        title: modalTitle,
8578        beforeclose: function (event, ui) { event.stopPropagation(); },
8579        close: function () {
8580          $(this).dialog('destroy');
8581          return true;
8582        },
8583        buttons: {
8584          [action]: function () {
8585            self.createCreditNote(callback)
8586            $(this).dialog('close');
8587          },
8588          'Peruuta': function () {
8589            $(this).dialog('close');
8590          }
8591        }
8592      });
8593    }
8594  }
8595
8596  self.validateData = function () {
8597    if (self.data.amount() > self.amountToPay())
8598      return 'Hyvityksen määrä ei voi olla suurempi kuin laskun summa!'
8599
8600    if (self.data.amount() <= 0)
8601      return 'Hyvityksen määrä täytyy olla suurempi kuin 0 euroa'
8602
8603    if (self.data.creditType() === 'items' && self.data.itemsToCredit().length < 1)
8604      return 'Et ole valinnut hyvitettäviä laskurivejä.'
8605
8606    if (self.data.creditType() === 'partial' && typeof self.data.vatBase() === 'undefined')
8607      return 'Tiedoista puuttuu alvikanta. Ota yhteyttä asiakaspalveluun. Voit tehdä hyvityspyynnön hyvitysikkunan linkin kautta.'
8608
8609    return false
8610  }
8611
8612  self.show = function ({ callback }) {
8613    self.data.creditType('full');
8614    self.dialog = $(self.dialogElem).dialog({
8615      width: 800,
8616      height: 600,
8617      autoOpen: true,
8618      modal: true,
8619      resizable: false,
8620      draggable: false,
8621      title: 'Laskun hyvitys',
8622      beforeclose: function (event, ui) {
8623        event.stopPropagation();
8624      },
8625      close: function () {
8626        self.dialog.dialog('destroy');
8627      },
8628      buttons: {
8629        'Peruuta': function () {
8630          $(this).dialog('close');
8631        },
8632        'Lisää hyvitys': function () {
8633          self.confirmationModal.show(callback);
8634        }
8635      }
8636    });
8637  }
8638
8639  self.createCreditNote = function (callback) {
8640    let data = ko.toJS(self.data);
8641    data.isInsuranceInvoice = self.isInsuranceInvoice();
8642    $.ajax({
8643      dataType: 'json',
8644      type: 'POST',
8645      url: '/reskontra/addCreditNote/' + self.invoiceId(),
8646      data: data,
8647      beforeSend: function (request) {
8648        var loadingText = self.data.creditType() === 'removeFeesAndInterests' 
8649          ? 'Hyvitetään laskun muistutus- ja korkokuluja'
8650          : 'Luodaan hyvitystä...';
8651        global.showLoadingDialog(loadingText);
8652      }
8653    }).done(function (response) {
8654      var successText = self.data.creditType() === 'removeFeesAndInterests' 
8655        ? 'Laskun muistutus- ja korkokulut hyvitetty onnistuneesti'
8656        : 'Hyvitys luotu!';
8657      global.show_message({ type: 'success', text: successText })
8658
8659      setTimeout(function () {
8660        self.dialog.dialog('close')
8661        if (typeof callback === 'function') {
8662          callback()
8663        }
8664      }, 1000)
8665
8666    }).error(function (response) {
8667      global.show_message(JSON.parse(response.responseText));
8668    }).always(function () {
8669      global.close_loading_dialog();
8670    })
8671  }
8672};
8673
8674;var InvoiceLedgerServiceActionsVM = function (params) {
8675  'use strict';
8676  var self = this;
8677  console.log('InvoiceLedgerServiceActionsVM: ',params);
8678
8679  self.changed = ko.observable(false); //A pub-sub flag that parent subscribers can check for
8680  self.invoice = params.invoice;
8681
8682  self.changed = ko.observable(false); //A pub-sub flag that parent subscribers can check for
8683
8684  self.dialog = null; // reference to jQuery ui dialog obj
8685
8686  self.infoModal = {
8687
8688    $elem: $('#ledgerServiceActionsInfoModal'),
8689    title: ko.observable(''),
8690    text: ko.observable(''),
8691
8692    show: function(text, title){
8693
8694        this.text(text);
8695        this.title(title);
8696
8697        this.$elem.dialog({
8698
8699            width:400,
8700            //height:200,
8701            autoOpen: true,
8702            modal: true,
8703            resizable: false,
8704            draggable: false,
8705            beforeclose: function(event, ui) {event.stopPropagation();},
8706            close: function(){
8707                self.changed(true); //Set the changed param to true, so parent Dialog knows to refresh
8708                $(this).dialog('destroy');
8709                return true;
8710            },
8711            buttons: {
8712                'Ok': function() {
8713                    $(this).dialog('close');
8714                }
8715            }
8716        });
8717    }
8718};
8719
8720  self.showError = function(text, title){
8721    return global.show_message({
8722        type: 'error',
8723        title: title,
8724        text: text
8725    });
8726  };
8727  var originalDueDate = self.invoice ? new Date(self.invoice.due_date) : null;
8728  var today = new Date(),
8729    dd = String(today.getDate()).padStart(2, '0'),
8730    mm = String(today.getMonth() + 1).padStart(2, '0'),
8731    yyyy = today.getFullYear();
8732
8733  //self.actionType = ko.observable('addNote');
8734  //self.actionItemCode = ko.observable('Manual actions needed');
8735    
8736  self.ledgerAction = {
8737    actionType: ko.observable('addNote'), 
8738    actionNoteType: ko.observable(null),
8739    sendToKredinor: ko.observable(true),
8740    showToCompany: ko.observable(true),
8741    newDueDate: ko.observable(originalDueDate), 
8742    removeFeesType: ko.observable('removeFeesOnly'),
8743    message: ko.observable(''),
8744    interestFromDate: ko.observable(dd + '.' + mm + '.' + yyyy),
8745    stopUntilDate: ko.observable(dd + '.' + mm + '.' + yyyy), 
8746    stopForNowOrUntilDate: ko.observable(null),
8747  };
8748
8749  self.setData = function () {
8750    self.reset();
8751  };
8752
8753  self.reset = function () {
8754    self.ledgerAction.actionType('addNote');
8755    self.ledgerAction.newDueDate(originalDueDate);
8756    self.ledgerAction.message('');
8757    self.ledgerAction.interestFromDate(dd + '.' + mm + '.' + yyyy);
8758    self.ledgerAction.stopUntilDate(dd + '.' + mm + '.' + yyyy);
8759  };
8760
8761  self.show = function () {
8762    //If jQuery UI dialog has not been inited yet
8763    if (self.dialog === null) {
8764      self.dialog = $('#ledger-service-actions-dialog').dialog({
8765        width: 800,
8766        height: 660,
8767        autoOpen: false,
8768        modal: true,
8769        resizable: false,
8770        draggable: false,
8771        beforeclose: function (event) {
8772          $('link#extrabs').remove();
8773          $('script#bsjs').remove();
8774          event.stopPropagation();
8775        },
8776        close: function () {
8777          self.close();
8778        },
8779        title: 'Laskutuspalvelun toiminnot',
8780        buttons: {
8781          Tallenna: function () {
8782            self.takeAction();
8783          },
8784          Sulje: function () {
8785            self.dialog.dialog('close');
8786          },
8787        },
8788      });
8789    }
8790
8791    self.dialog.dialog('open');
8792  };
8793
8794  self.close = function () {
8795    if (self.dialog) {
8796      self.dialog.dialog('destroy');
8797      self.dialog = null;
8798    }
8799  };
8800
8801  self.getAccumulatedInterest = function(onSuccess, onError){
8802    var dialog = $('<div />', {}).dialog({
8803      autoOpen: true,
8804      modal: true,
8805      width: 500,
8806      position: {
8807        top: 50,
8808      },
8809      hide: {
8810        effect: 'fade',
8811        speed: 3000,
8812      },
8813      resizable: true,
8814      title: 'Laskun tiedot',
8815      draggable: true,
8816      buttons: {
8817        Sulje: function () {
8818          dialog.dialog('close');
8819        },
8820      },
8821    });
8822    dialog.html('Haetaan laskun korkotietoja...');
8823    var data = { invoice_id: self.invoice.id };
8824    $.ajax({
8825      url: '/reskontra/fetchInvoiceInterestData',
8826      type: 'get',
8827      data: data,
8828      success: function(resp) {
8829        onSuccess(resp, dialog);
8830      },
8831      error: function(response) {
8832        onError(response, dialog);
8833      }
8834    });
8835  }
8836
8837  self.fetchInvoiceInterestData = function(){
8838    function onSuccess(resp, target){
8839      if(resp.data){
8840        var dataString = JSON.stringify(resp.data, null, 4);
8841        dataString = dataString.replace(/[}{]/g, '');
8842        dataString = dataString.trim() != '' ? dataString : 'Laskun tietoja ei löytynyt';
8843        target.html('<pre>'+dataString+'</pre>');
8844      }else{
8845        target.html('Laskun tietoja ei löytynyt');
8846      }
8847    }
8848
8849    function onError(response, target){
8850      global.close_loading_dialog();
8851      try {
8852        target.html(JSON.parse(response.responseText));
8853      }catch (exception){
8854        target.html('Odottamaton virhe tapahtui palvelimella. Virhesanoma tallennettu palvelimen lokiin.');
8855      }
8856    }
8857
8858    self.getAccumulatedInterest(onSuccess, onError);
8859  };
8860
8861  self.takeAction = function(){
8862      
8863    console.log(ko.toJS(self.ledgerAction));
8864   
8865    var url, data;
8866    var actionType = self.ledgerAction.actionType();
8867    var actionNoteType = self.ledgerAction.actionNoteType();
8868    var message = self.ledgerAction.message();
8869    var stopUntilDate = self.ledgerAction.stopForNowOrUntilDate() === "stopUntilDate" ? self.ledgerAction.stopUntilDate() : null;
8870    var hideLogItemFromSeller=  + ( ! self.ledgerAction.showToCompany());
8871    
8872    switch(actionType){
8873        case 'addNote':
8874            url = 'iv_laskutus_ja_reskontra/addNoteToLedgerService';
8875            data = { invoice_id: self.invoice.id, message: message, hideLogItemFromSeller: hideLogItemFromSeller, sendToKredinor: self.ledgerAction.sendToKredinor()};
8876            break;
8877            
8878        case 'addActionNote':
8879        case 'removeFeesAction':
8880            url = 'iv_laskutus_ja_reskontra/addActionNoteToLedgerService';
8881            data = { invoice_id: self.invoice.id, actionNoteType: actionNoteType,  message: message, hideLogItemFromSeller: hideLogItemFromSeller};
8882            break;
8883            
8884        case 'postponeDueDate':
8885            url = "/iv_laskutus_ja_reskontra/update_due_date/".concat(self.invoice.id);
8886            data = { dueDate: self.ledgerAction.newDueDate(), message: message };
8887            break;
8888        case 'blockInterestCalculation':
8889            url = '/iv_laskutus_ja_reskontra/blockInterestCalculation';
8890            data = { invoice_id: self.invoice.id, message: message, interestFromDate: self.ledgerAction.interestFromDate()};
8891            break;
8892        case 'stopCollectionAndReminder':
8893            url = '/iv_laskutus_ja_reskontra/stopDebtCollection';
8894            data = { invoice_id: self.invoice.id, message: message, stopUntilDate: stopUntilDate };
8895            break;
8896        case 'resumeCollectionAndReminder':
8897            url = '/iv_laskutus_ja_reskontra/resumeDebtCollection';
8898            data = { invoice_id: self.invoice.id, message: message};
8899            break;
8900        case 'stopInterestCalculation':
8901            
8902            console.log('stopForNow:',self.ledgerAction.stopForNowOrUntilDate(), ' stopUntil:', stopUntilDate );
8903            
8904            url = '/iv_laskutus_ja_reskontra/stopInterestCalculation';
8905            data = { invoice_id: self.invoice.id, message: message, stopUntilDate: stopUntilDate };
8906            break;
8907        case 'resumeInterestCalculation':
8908            url = '/iv_laskutus_ja_reskontra/resumeInterestCalculation';
8909            data = { invoice_id: self.invoice.id, message: message };
8910            break;
8911       
8912        default:
8913            return self.showError('Virheellinen toiminto', 'Virhe');
8914    }
8915    
8916    $.ajax({
8917      url: url,
8918      type: 'post',
8919      data: data,
8920        beforeSend(jqXHR, settings) {
8921            global.showLoadingDialog('Suoritetaan toimintoa...');
8922        },
8923        success: function(resp) {
8924        global.close_loading_dialog();
8925        //global.show_message(resp);
8926        self.infoModal.show(resp.text, 'Toiminto suoritettu onnistuneesti');
8927        //Refresh the datatables
8928        if(pages.iv_laskutus_ja_reskontra.$datatable_iv != null){
8929            pages.iv_laskutus_ja_reskontra.$datatable_iv.fnClearTable( 0 );
8930            pages.iv_laskutus_ja_reskontra.$datatable_iv.fnDraw();
8931        }
8932
8933        if(pages.iv_laskutus_ja_reskontra.$datatable != null){
8934            pages.iv_laskutus_ja_reskontra.$datatable.fnClearTable( 0 );
8935            pages.iv_laskutus_ja_reskontra.$datatable.fnDraw();
8936        }
8937
8938        if(pages.reskontra.$datatable != null){
8939            pages.reskontra.$datatable.fnClearTable( 0 );
8940            pages.reskontra.$datatable.fnDraw();
8941        }
8942      },
8943      error: function(response) {
8944        global.close_loading_dialog();
8945        try {
8946          global.show_message(JSON.parse(response.responseText));
8947        }catch (exception){
8948          global.show_message({'type': 'error', 'text': 'Odottamaton virhe tapahtui palvelimella. Virhesanoma tallennettu palvelimen lokiin.' });
8949        }
8950      }
8951    });
8952  };
8953
8954  ko.bindingHandlers.ledgerActionsDatepicker = {
8955    init: function(element, valueAccessor, allBindings){
8956  
8957      var unWrappedValue = ko.unwrap(valueAccessor());
8958  
8959      $(element).datepicker({
8960        format: 'dd.mm.yyyy',
8961        language: 'fi-FI',
8962        weekStart: 1,
8963        todayHighlight: true,
8964        startDate: '-24m'
8965      });
8966
8967      $(element)
8968      .datepicker()
8969      .on('change', function (event) {
8970        var value = valueAccessor();
8971
8972        if (ko.isObservable(value)) {
8973          value(event.target.value);
8974        }
8975      });
8976
8977    $(element).datepicker('setDate', unWrappedValue);
8978    },
8979    update: function (element, valueAccessor, allBindingsAccessor) {
8980      var unWrappedValue = ko.unwrap(valueAccessor());
8981  
8982      $(element).datepicker('setDate', unWrappedValue);
8983      ko.utils.triggerEvent(element, 'blur');
8984    }
8985  };
8986};
8987
8988;
8989var InvoiceDialogVm = function() {
8990
8991  'use strict';
8992  var self = this;
8993
8994  self.inited = ko.observable(false);
8995
8996  //self.dialog = $('<div />', {});
8997  self.dialog = global.getGlobalDialogAndEmptyIfHasContent();
8998
8999    self.changeAccountingPeriodDialog = {
9000        jqDialog: null,
9001        dialogElem: '#change-accounting-period-dialog',
9002        accountingDate: ko.observable()
9003    };
9004
9005    self.addInvoiceNoteDialog = {
9006        jqDialog: null,
9007        dialogElem: '#add-invoice-note-dialog',
9008        ledgerService: ko.observable(''),
9009        noteOptions: ko.observableArray([
9010            { value: 0, label: 'Oma muistiinpano' },
9011            { value: 1, label: 'Viesti Innovoicen asiakaspalveluun' }
9012        ]),
9013        type: ko.observable(0),
9014        message: ko.observable(''),
9015        showToCompany: ko.observable(true),
9016        actionItemCode: ko.observable('Manual actions needed')
9017    };
9018
9019    self.addInvoiceNoteDialog.reset = function(){
9020        self.addInvoiceNoteDialog.ledgerService('');
9021        self.addInvoiceNoteDialog.noteOptions([
9022            { value: 0, label: 'Oma muistiinpano' },
9023            { value: 1, label: 'Viesti Innovoicen asiakaspalveluun' }
9024        ]);
9025        self.addInvoiceNoteDialog.type(0);
9026        self.addInvoiceNoteDialog.message('');
9027        self.addInvoiceNoteDialog.showToCompany(false);
9028        self.addInvoiceNoteDialog.actionItemCode('');
9029    };
9030
9031    self.postponeDueDateDialog = {
9032      jqDialog: null,
9033      dialogElem: '#postpone-due-date-dialog',
9034      dueDate: ko.observable(),
9035      message: ko.observable('')
9036  };
9037
9038  self.editReminderStopDialog = {
9039      jqDialog: null,
9040      dialogElem: '#edit-reminder-stop-dialog',
9041      reminderStop: ko.observable(),
9042      reminderStopEnd: ko.observable(),
9043      reminderStopEndDate: ko.observable()
9044  };
9045
9046    self.requestForCreditingDialog = {
9047        jqDialog: null,
9048        dialogElem: '#request-for-crediting-dialog',
9049        template: ko.observable('default'),
9050        creditType: ko.observable(),
9051        creditAmount: ko.observable(),
9052        additionalInfo: ko.observable(),
9053    };
9054
9055    self.requestForCreditingDialog.evaluateDialogTemplateForInvoice = function (invoice) {
9056
9057        if( ! self.inited())
9058            return 'default';
9059
9060        var originatorApp = ko.toJS(invoice.originator_app);
9061
9062        if(window.App.company.field_of_work === 'car_service' && window.App.company.mod_innokorjaamo && originatorApp === 'innokorjaamo')
9063            return 'car_service';
9064
9065        if(window.App.company.field_of_work === 'freight' && originatorApp === 'innorahti')
9066            return 'freight';
9067
9068        if(window.App.company.field_of_work === 'car_tow' && (originatorApp === 'innohinaus' || originatorApp === 'innohinaus-app'))
9069            return 'car_tow';
9070
9071        return 'default'
9072    }
9073
9074    self.requestForCreditingDialog.reset = function(){
9075
9076        self.requestForCreditingDialog.creditType(null);
9077        self.requestForCreditingDialog.creditAmount(null);
9078        self.requestForCreditingDialog.additionalInfo(null);
9079    };
9080
9081    self.requestForCreditingDialog.buttons = ko.computed(function(){
9082
9083        console.log('self.requestForCreditingDialog.buttons called, template: ', self.requestForCreditingDialog.template(), ' creditType:', self.requestForCreditingDialog.creditType());
9084
9085
9086        if(self.requestForCreditingDialog.template() === 'car_tow'){
9087
9088            return {
9089                'Sulje': function () {
9090                    $(this).dialog('close');
9091                },
9092                'Siirry kuormakirjaan': function (){
9093                    self.requestForCreditingDialog.navigateToTowingRecord();
9094                }
9095            };
9096        }
9097
9098        if(self.requestForCreditingDialog.template() === 'car_service'){
9099
9100            return {
9101                'Sulje': function () {
9102                    $(this).dialog('close');
9103                },
9104                'Lähetä hyvityspyyntö': function (){
9105                    self.requestForCreditingDialog.sendRequest();
9106                },
9107                'Siirry työmääräykseen': function (){
9108                    self.requestForCreditingDialog.navigateToJobOrder();
9109                }
9110            };
9111        }
9112
9113        if(self.requestForCreditingDialog.template() === 'freight'){
9114
9115            return {
9116                'Sulje': function () {
9117                    $(this).dialog('close');
9118                },
9119                'Lähetä hyvityspyyntö': function (){
9120                    self.requestForCreditingDialog.sendRequest();
9121                },
9122                'Siirry rahtikirjaan': function (){
9123                    self.requestForCreditingDialog.navigateToFreight();
9124                },
9125            };
9126        }
9127
9128        return {
9129            'Peruuta': function () {
9130                $(this).dialog('close');
9131            },
9132            'Lähetä': function () {
9133                self.requestForCreditingDialog.sendRequest();
9134            }
9135        };
9136    });
9137
9138  self.creditInvoiceDialog = null;
9139  self.customerCreditInvoiceVM = null;
9140
9141  self.ledgerServiceActionsDialog = null;
9142
9143  self.data = null;
9144
9145  self.invoiceId = ko.observable();
9146
9147  self.setData = function(data){
9148
9149    //console.log('InvoiceDialogVm::setData: ', data);
9150
9151    //Load the new data into ViewModel
9152    ko.mapping.fromJS(data, {}, self.data);
9153
9154    self.creditInvoiceDialog.setData(ko.mapping.toJS(self.data));
9155    self.ledgerServiceActionsDialog.setData(ko.mapping.toJS(self.data));
9156  };
9157
9158  self.init = function(params){
9159    if(typeof params.id !== "undefined") {
9160        self.invoiceId(params.id)
9161    }
9162    //console.log('InvoiceDialogVm::init');
9163    self.customerCreditInvoiceVM = new CustomerCreditInvoiceDialogVM(params);
9164
9165    self.data = ko.mapping.fromJS(params);
9166
9167    self.creditInvoiceDialog = new CreditInvoiceDialogVm(params);
9168    self.ledgerServiceActionsDialog = new InvoiceLedgerServiceActionsVM(params);
9169
9170    self.creditInvoiceDialog.changed.subscribe(function(){
9171       // console.log('InvoiceDialogVm creditInvoiceDialog.changed');
9172        self.refresh();
9173    });
9174
9175    self.ledgerServiceActionsDialog.changed.subscribe(function(){
9176         self.refresh();
9177     });
9178
9179    // Apply to vm to popup
9180    ko.applyBindings(self.customerCreditInvoiceVM, $('#customer-credit-invoice-dialog')[0]);
9181    ko.applyBindings(self.creditInvoiceDialog, $('#credit-invoice-dialog')[0]);
9182    ko.applyBindings(self.ledgerServiceActionsDialog, $('#ledger-service-actions-dialog')[0]);
9183    ko.applyBindings(self.postponeDueDateDialog, $('#postpone-due-date-dialog')[0]);
9184    ko.applyBindings(self.changeAccountingPeriodDialog, $('#change-accounting-period-dialog')[0]);
9185    ko.applyBindings(self.addInvoiceNoteDialog, $('#add-invoice-note-dialog')[0]);
9186    ko.applyBindings(self.editReminderStopDialog, $('#edit-reminder-stop-dialog')[0]);
9187    ko.applyBindings(self.requestForCreditingDialog, $('#request-for-crediting-dialog')[0]);
9188
9189    self.initJqueryElements();
9190
9191    self.inited(true);
9192  };
9193
9194  self.initJqueryElements = function () {
9195
9196      $('.edit_reminder_stop').dblclick(function (e) {
9197          self.editReminderStopDialog.show($(e.target).text());
9198      });
9199
9200      $('a.edit_due_date').on('click',function (e) {
9201          e.preventDefault();
9202          self.postponeDueDateDialog.show($(e.target).text());
9203      });
9204
9205      $('a.edit_accounting_period').on('click',function (e) {
9206          e.preventDefault();
9207          var accountingDate = $(e.target).data('accounting-date');
9208          self.changeAccountingPeriodDialog.show(accountingDate);
9209      });
9210
9211      $('input#accounting_date')
9212          .datepicker({minViewMode: "months", orientation: "bottom left"});
9213      
9214      var last_reminder_select_value = $('#reminder_and_debt_collection_stop').val();
9215      $('#reminder_and_debt_collection_stop').on('focus', function () {
9216          last_reminder_select_value = $(this).val();
9217      });
9218      
9219      $('select#reminder_and_debt_collection_stop').on('change', function(e){
9220        last_reminder_select_value = $(this).val();
9221        self.setReminderAndDebtCollectionStop();
9222      });
9223  };
9224  
9225  self.setReminderAndDebtCollectionStop = function(){
9226    
9227    var reminder_and_debt_collection_stop = document.querySelector('#reminder_and_debt_collection_stop').value;
9228    
9229    $.ajax({
9230      url: '/reskontra/reminder_and_debt_collection_stop',
9231      data: {
9232        invoiceId: self.invoiceId(),
9233        reminder_and_debt_collection_stop: reminder_and_debt_collection_stop
9234      },
9235      type: 'POST',
9236      dataType: 'json',
9237      beforeSend: function(request){
9238        global.showLoadingDialog('Asetetaan muistutus- ja perintäestoa');
9239      },
9240      success: function(responseJSON){
9241        global.show_message(responseJSON);
9242        global.close_loading_dialog();
9243      },
9244      error: function(data){
9245        var errorJSON = data.responseJSON;
9246        if(errorJSON){
9247          global.show_message(errorJSON);
9248        } else {
9249          global.show_message({
9250            type: 'error',
9251            text: 'Virhe asetettaessa muistutus- ja perintäestoa'
9252          });
9253        }
9254        global.close_loading_dialog();
9255      }
9256    });
9257  }
9258
9259  self.requestForCreditingDialog.sendRequest = function(){
9260
9261
9262
9263      if(! self.requestForCreditingDialog.creditAmount()){
9264
9265          return global.show_message({
9266              type: 'error',
9267              title: 'Virhe!',
9268              text: 'Ole hyvä ja syötä hyvitettävä summa (sis. alv)'
9269          });
9270
9271      }
9272
9273
9274
9275      if( ! self.requestForCreditingDialog.additionalInfo()){
9276
9277          return global.show_message({
9278              type: 'error',
9279              title: 'Virhe!',
9280              text: 'Ole hyvä ja täytä hyvityksen syy'
9281          });
9282      }
9283
9284      global.showLoadingDialog("Lähetetään hyvityspyyntöä...");
9285
9286      $.ajax({
9287
9288          url: 'logger/addRequestForCrediting/',
9289          type: 'post',
9290          data: {
9291              id: self.invoiceId(),
9292              message: self.requestForCreditingDialog.additionalInfo(),
9293              creditType: 'other_amount',
9294              otherAmount: self.requestForCreditingDialog.creditAmount()
9295          }
9296      }).done(function (responseJSON) {
9297
9298          global.close_loading_dialog();
9299          global.show_message({
9300              type: 'success',
9301              title: 'Hyvityspyyntö lähetetty',
9302              text: 'Hyvityspyyntö lähetetty onnistuneesti!'
9303          });
9304
9305          self.requestForCreditingDialog.reset();
9306          self.requestForCreditingDialog.jqDialog.dialog('destroy');
9307
9308      }).fail(function (response) {
9309
9310          var responseJSON = $.parseJSON(response.responseText);
9311
9312          global.close_loading_dialog();
9313          global.show_message(responseJSON);
9314      });
9315  };
9316
9317  self.requestForCreditingDialog.navigateToTowingRecord = function (){
9318      window.location = '/kuormakirja/navigate_by_invoice/'.concat(self.invoiceId());
9319  };
9320
9321  self.requestForCreditingDialog.navigateToJobOrder = function (){
9322      window.location = '/innokorjaamo/navigate_by_invoice/'.concat(self.invoiceId());
9323  };
9324
9325  self.requestForCreditingDialog.navigateToFreight = function (){
9326      window.location = '/innorahti/navigate_by_invoice/'.concat(self.invoiceId());
9327  };
9328
9329  self.requestForCreditingDialog.show = function(){
9330
9331      var dialogTemplate = self.requestForCreditingDialog.evaluateDialogTemplateForInvoice(ko.toJS(self.data.invoice));
9332      self.requestForCreditingDialog.template(dialogTemplate);
9333
9334      self.requestForCreditingDialog.jqDialog = $(self.requestForCreditingDialog.dialogElem).dialog({
9335          width: 400,
9336          autoOpen: true,
9337          modal: true,
9338          resizable: false,
9339          draggable: false,
9340          title: 'Lähetä hyvityspyyntö',
9341          beforeclose: function (event, ui) {
9342              event.stopPropagation();
9343          },
9344          close: function(){
9345            self.requestForCreditingDialog.jqDialog.dialog('destroy');
9346          },
9347          buttons: self.requestForCreditingDialog.buttons()
9348      });
9349
9350  };
9351
9352  self.editReminderStopDialog.show = function(reminderStop){
9353
9354      var d = new Date();
9355
9356      if(reminderStop === 'Päällä'){
9357          self.editReminderStopDialog.reminderStop('1');
9358      }else {
9359          self.editReminderStopDialog.reminderStop('0');
9360      }
9361
9362      self.editReminderStopDialog.reminderStopEnd(false);
9363      self.editReminderStopDialog.reminderStopEndDate(d.toLocaleDateString("fi-FI"));
9364
9365      self.editReminderStopDialog.jqDialog = $(self.editReminderStopDialog.dialogElem).dialog({
9366
9367              width: 340,
9368              height: 260,
9369              autoOpen: true,
9370              modal: false,
9371              resizable: false,
9372              draggable: true,
9373              beforeclose: function(event, ui) {
9374                  event.stopPropagation();
9375              },
9376              buttons: {
9377                  'Peruuta': function() {
9378                      self.editReminderStopDialog.jqDialog.dialog('destroy');
9379                  },
9380                  'Hyväksy': function() {
9381                      self.editReminderStopDialog.updateReminderStop();
9382                  }
9383              }
9384          });
9385  };
9386
9387  self.editReminderStopDialog.updateReminderStop = function(){
9388
9389      var reminderStop = self.editReminderStopDialog.reminderStop(),
9390          reminderStopEnd = self.editReminderStopDialog.reminderStopEnd(),
9391          reminderStopEndDate = reminderStopEnd ? self.editReminderStopDialog.reminderStopEndDate() : null;
9392
9393
9394      console.log('updateReminderStop:', reminderStop, reminderStopEnd, reminderStopEndDate);
9395
9396      var data = ko.toJSON({
9397          'reminderStop': reminderStop,
9398          'reminderStopEnd': reminderStopEnd,
9399          'reminderStopEndDate': reminderStopEndDate
9400      });
9401
9402      $.ajax({
9403          "dataType": 'json',
9404          "type": "POST",
9405          data: {
9406              'data': data
9407          },
9408          "url" : "/iv_laskutus_ja_reskontra/update_huomautus_esto/" .concat(self.invoiceId()),
9409          "beforeSend":function(request){
9410              global.showLoadingDialog('Päivitetään huomautus- ja korkoestoa Rivertylle...');
9411          }
9412      }).done(function(responseJSON){
9413          console.log('responseJSON!:', responseJSON);
9414          self.editReminderStopDialog.jqDialog.dialog('close');
9415          global.show_message(responseJSON, self.refresh());
9416        //   self.refresh();
9417      }).always(function(){
9418          global.close_loading_dialog();
9419      }).error(function(response){
9420          console.log('updateReminderStop error:', response);
9421          global.show_message($.parseJSON(response.responseText));
9422      });
9423  };
9424
9425
9426    self.changeAccountingPeriodDialog.show = function(currentAccountingPeriod){
9427
9428        var vm = self.changeAccountingPeriodDialog;
9429
9430        vm.accountingDate(currentAccountingPeriod);
9431
9432        vm.jqDialog = $(vm.dialogElem).dialog({
9433            width: 260,
9434            height: 200,
9435            autoOpen: true,
9436            modal: false,
9437            resizable: false,
9438            draggable: true,
9439            beforeclose: function(event, ui) {
9440                event.stopPropagation();
9441            },
9442            buttons: {
9443                'Peruuta': function() {
9444                    vm.jqDialog.dialog('destroy');
9445                },
9446                'Hyväksy': function() {
9447                    vm.updateAccountingDate();
9448                }
9449            }
9450        });
9451    };
9452
9453    self.changeAccountingPeriodDialog.updateAccountingDate = function(){
9454
9455        var vm = self.changeAccountingPeriodDialog, data = {
9456            'accountingDate': vm.accountingDate()
9457        };
9458
9459        var url;
9460
9461        if(pages.iv_laskutus_ja_reskontra.$datatable_iv != null && pages.reskontra.$datatable === null){
9462            url = "/iv_laskutus_ja_reskontra/update_accounting_date/" .concat(self.invoiceId());
9463        }else{
9464            url = "/reskontra/update_accounting_date/" .concat(self.invoiceId());
9465        }
9466
9467        $.ajax({
9468            "dataType": 'json',
9469            "type": "POST",
9470            data: data,
9471            "url" : url,
9472            "beforeSend":function(request){
9473                global.showLoadingDialog('Päivitetään kirjanpitokautta...');
9474            }
9475        }).done(function(responseJSON){
9476            console.log('responseJSON!:', responseJSON);
9477            vm.jqDialog.dialog('close');
9478            global.show_message(responseJSON, self.refresh());
9479            //self.refresh();
9480        }).always(function(){
9481            global.close_loading_dialog();
9482        }).error(function(response){
9483            console.log('UpdateDueDate error:', response);
9484            global.show_message($.parseJSON(response.responseText));
9485        });
9486    };
9487
9488    self.addInvoiceNoteDialog.show = function(){
9489        self.addInvoiceNoteDialog.reset();
9490        var ledgerService = self.data.invoice.ledger_service();
9491        self.addInvoiceNoteDialog.ledgerService(ledgerService);
9492        
9493        /*
9494        if(ledgerService === 'kredinor'){
9495            var kredinorNote = { value: 2, label: 'Viesti Kredinorille' };
9496            var kredinorAction = { value: 3, label: 'Tehtävä Kredinorille' };
9497            self.addInvoiceNoteDialog.noteOptions.push(kredinorNote);
9498            self.addInvoiceNoteDialog.noteOptions.push(kredinorAction);
9499        }
9500        */
9501        
9502        self.addInvoiceNoteDialog.jqDialog = $(self.addInvoiceNoteDialog.dialogElem).dialog({
9503            width: 400,
9504            autoOpen: true,
9505            modal: false,
9506            resizable: false,
9507            draggable: true,
9508            title: 'Lisää muistiinpano',
9509            beforeclose: function(event, ui) {
9510                event.stopPropagation();
9511            },
9512            buttons: {
9513                'Peruuta': function() {
9514                    self.addInvoiceNoteDialog.jqDialog.dialog('destroy');
9515                },
9516                'Lähetä': function() {
9517                    self.addInvoiceNoteDialog.addNote();
9518                }
9519            },
9520        });
9521    }
9522
9523    self.addInvoiceNoteDialog.addNote = function(){
9524        var invoice = self.data.invoice;
9525        var url, data;
9526        var type = self.addInvoiceNoteDialog.type();
9527        global.showLoadingDialog('Lisätään viestiä');
9528        switch(type){
9529            case 0: // log message
9530                url = 'logger/makeLogEntry/';
9531                data = { id: invoice.id(), message: self.addInvoiceNoteDialog.message(), notify: '0' };
9532                break;
9533            case 1: // log and ticket
9534                url = 'logger/makeLogEntry/';
9535                data = { id: invoice.id(), message: self.addInvoiceNoteDialog.message(), notify: '1' };
9536                break;
9537            case 2: // message to kredinor and log
9538                url = 'iv_laskutus_ja_reskontra/addNoteToLedgerService';
9539                data = { invoice_id: invoice.id(), message: self.addInvoiceNoteDialog.message(), addFollowUp: false, showToCompany: self.addInvoiceNoteDialog.showToCompany() };
9540                break;
9541            case 3: // action to kredinor and log
9542                url = 'iv_laskutus_ja_reskontra/addNoteToLedgerService';
9543                data = { invoice_id: invoice.id(), message: self.addInvoiceNoteDialog.message(), addFollowUp: true, showToCompany: self.addInvoiceNoteDialog.showToCompany(), actionItemCode: self.addInvoiceNoteDialog.actionItemCode() };
9544                break;
9545            default:
9546                global.show_message({
9547                    type: 'error',
9548                    title: 'Virhe! Muistiinpanoa ei voi lähettää',
9549                    text: 'Virheellinen muistiinpanon tyyppi.'
9550                });
9551                break;
9552        }
9553        $.ajax({
9554            url: url,
9555            type: 'post',
9556            data: data,
9557            success: function(resp) {
9558                self.addInvoiceNoteDialog.jqDialog.dialog('destroy');
9559                global.close_loading_dialog();
9560                global.show_message({
9561                    type: 'success',
9562                    title: 'Valmis',
9563                    text: 'Viesti lisätty onnistuneesti.',
9564                });
9565            },
9566            error: function(response) {
9567                global.close_loading_dialog();
9568                try {
9569                    global.show_message(JSON.parse(response.responseText));
9570                }catch (exception){
9571                    global.show_message({'type': 'error', 'text': 'Odottamaton virhe tapahtui palvelimella. Virhesanoma tallennettu palvelimen lokiin.' });
9572                }
9573            }
9574          });
9575    };
9576
9577    self.postponeDueDateDialog.show = function(currentDueDate){
9578
9579      var statusCheckResult = pages.reskontra.checkInvoiceStatusBeforeChangeDueDate(ko.toJS(self.data));
9580
9581      if (statusCheckResult) {
9582        return global.show_message({
9583          type: 'error',
9584          title: 'Virhe!',
9585          text: statusCheckResult
9586        });
9587      }
9588
9589      self.postponeDueDateDialog.dueDate(currentDueDate);
9590      self.postponeDueDateDialog.message('');
9591
9592      self.postponeDueDateDialog.jqDialog = $(self.postponeDueDateDialog.dialogElem).dialog({
9593          width: 260,
9594          height: 300,
9595          autoOpen: true,
9596          modal: false,
9597          resizable: false,
9598          draggable: true,
9599          beforeclose: function(event, ui) {
9600              event.stopPropagation();
9601          },
9602          buttons: {
9603              'Peruuta': function() {
9604                  self.postponeDueDateDialog.jqDialog.dialog('destroy');
9605              },
9606              'Hyväksy': function() {
9607                  self.postponeDueDateDialog.updateDueDate();
9608              }
9609          }
9610      });
9611  }
9612
9613  self.postponeDueDateDialog.updateDueDate = function(){
9614
9615      var data = {
9616          'dueDate': self.postponeDueDateDialog.dueDate(),
9617          'message': self.postponeDueDateDialog.message()
9618      };
9619      var url;
9620      if(pages.iv_laskutus_ja_reskontra.$datatable_iv != null && pages.reskontra.$datatable === null){
9621        url = "/iv_laskutus_ja_reskontra/update_due_date/" .concat(self.invoiceId());
9622      }else{
9623        url = "/reskontra/update_due_date/" .concat(self.invoiceId());
9624      }
9625      $.ajax({
9626          "dataType": 'json',
9627          "type": "POST",
9628          data: data,
9629          "url" : url,
9630          "beforeSend":function(request){
9631              global.showLoadingDialog('Siirretään eräpäivää...');
9632          }
9633      }).done(function(responseJSON){ 
9634          console.log('responseJSON!:', responseJSON);
9635          self.postponeDueDateDialog.jqDialog.dialog('close');
9636          global.show_message(responseJSON, self.refresh());
9637          //self.refresh();  
9638      }).always(function(){
9639          global.close_loading_dialog();
9640      }).error(function(response){
9641          console.log('UpdateDueDate error:',
9641 response);
9642          global.show_message($.parseJSON(response.responseText));
9643      });
9644  };
9645  
9646  self.show = function(){
9647
9648    $.ajax({
9649
9650      processData:false,
9651      dataType: 'html',
9652      type: "GET",
9653      url: "/ajax/get_invoice_html/".concat(self.invoiceId()),
9654
9655      "beforeSend":function(request){
9656
9657       self.dialog.dialog({
9658          width:800,
9659          height:600,
9660          modal:true,
9661          resizable:false,
9662          title:'Laskun tiedot',
9663          close: function(){
9664            // cleanup the dialogs for this invoice
9665            if(self.changeAccountingPeriodDialog.jqDialog){
9666                self.changeAccountingPeriodDialog.jqDialog.remove();
9667            }
9668            if(self.addInvoiceNoteDialog.jqDialog){
9669                self.addInvoiceNoteDialog.jqDialog.remove();
9670            }
9671            if(self.postponeDueDateDialog.jqDialog){
9672                self.postponeDueDateDialog.jqDialog.remove();
9673            }
9674            if(self.editReminderStopDialog.jqDialog){
9675                self.editReminderStopDialog.jqDialog.remove();
9676            }
9677            if(self.requestForCreditingDialog.jqDialog){
9678                self.requestForCreditingDialog.jqDialog.remove();
9679            }
9680            self.dialog.dialog('close');
9681          }
9682        });
9683
9684        global.show_ajax_loader(self.dialog);
9685      },
9686      "success": function(response){
9687
9688        self.dialog.html(response);
9689
9690        $(this).delegate(':button','click',function(){
9691          $(this).data({'invoice_id': invoice_id, 'open_sum':open_sum});
9692        });
9693      }
9694    });
9695  };
9696
9697  self.refresh = function(){
9698    self.creditInvoiceDialog.close();
9699    self.ledgerServiceActionsDialog.close();
9700    self.show();
9701  };
9702
9703  self.showCreditInvoiceDialog = function(){
9704    self.creditInvoiceDialog.show(true);
9705  };
9706
9707  self.showLedgerServiceActionsDialog = function(){
9708    self.ledgerServiceActionsDialog.show(true);
9709  };
9710
9711  self.showAccumulatedInterest = function(onSuccess, onError){
9712    self.ledgerServiceActionsDialog.getAccumulatedInterest(onSuccess, onError);
9713  }
9714
9715  self.showSuggestCreditLossDialog = function(){
9716
9717      var $dialog = $('<div />', {"id": "suggest-credit-loss-dialog", "style":"text-align:left;"}).html('Haluatko varmasti lähettää laskusta luotttappiosuosituksen?');
9718
9719      $dialog.dialog({
9720          autoOpen: true,
9721          modal: true,
9722          resizable: false,
9723          draggable: false,
9724          title: 'Luottotappiosuositus',
9725          beforeclose: function(event, ui) {
9726              event.stopPropagation()
9727          },
9728          buttons: {
9729              'Peruuta': function() {
9730                  $dialog.dialog('close');
9731              },
9732              'Lähetä luottotappiosuositus': function() {
9733                  self.suggestCreditLoss($dialog);
9734              }
9735          }
9736      });
9737  };
9738
9739  self.showAddCreditLossDialog = function(){
9740
9741      var creditLossStop = self.data.invoice.credit_loss_stop();
9742
9743      var dialog = $('<div></div>')
9744          .append(
9745              $('<label />', {'style': 'width:auto;'}).html('Automaattisen luottotappiomerkinnän esto'),
9746              $('<br />', {'style': 'clear:both'}),
9747              $('<label />', {'style': 'width:auto;'}).html('Päällä').append(
9748                  $('<input />', {style: 'float:left', type: 'radio', name:'credit_loss_stop', value: 1, checked: creditLossStop})
9749              ),
9750              $('<br />', {'style': 'clear:both'}),
9751              $('<label />', {'style': 'width:auto;'}).html('Pois päältä').append(
9752                  $('<input />', {style: 'float:left', type: 'radio', name:'credit_loss_stop', value: 0, checked: (! creditLossStop)}),
9753              ),
9754              $('<br />', {'style': 'clear:both'})
9755          );
9756
9757      dialog.dialog({
9758          width: 400,
9759          autoOpen: true,
9760          modal: true,
9761          resizable: false,
9762          draggable: false,
9763          title: 'Luottotappioasetukset',
9764          beforeclose: function(event, ui) {
9765              event.stopPropagation()
9766          },
9767          close: function(){
9768            dialog.dialog('destroy');
9769            dialog.remove();
9770          },
9771          buttons: {
9772              'Peruuta': function() {
9773                  dialog.dialog('close');
9774              },
9775              'Tallenna muutokset': function() {
9776                  self.updateCreditLossStopSetting(dialog);
9777              },
9778              'Merkitse luottotappioksi': function() {
9779
9780                  if(confirm("Haluatko varmasti merkitä laskun avoimen osuuden luottotappioksi?")){
9781                      self.addCreditLoss(dialog);
9782                  }
9783              }
9784          }
9785      });
9786  };
9787
9788  self.showNullifyCreditLossDialog = function(){
9789
9790      var dialog = $('<div></div>')
9791          .append(
9792              $('<br />', {'style': 'clear:both'}),
9793              $('<label />', {'style': 'width:auto;'}).html('Poista koko luottotappio').append(
9794                  $('<input />', {style: 'float:left', type: 'checkbox', class:'nullify_open_credit_loss_amount', value: 1, checked: fal
9794se})
9795                  .on('change', function(){
9796                    if($(this).is(':checked')){
9797                        $('input.nullify_amount').prop('disabled', true)
9798                    } else {
9799                        $('input.nullify_amount').prop('disabled', false)
9800                    }
9801                  })
9802              ),
9803              $('<br />', {'style': 'clear:both'}),
9804              $('<br />', {'style': 'clear:both'}),
9805              $('<label />', {'style': 'width:auto; float:left;'}).html('Anna poistettava summa'),
9806              $('<br />', {'style': 'clear:both'}),
9807              $('<input />', {style: 'float:left', type: 'text', class:'nullify_amount', value: ''}),
9808              $('<br />', {'style': 'clear:both'})
9809          );
9810
9811      dialog.dialog({
9812          width: 400,
9813          autoOpen: true,
9814          modal: true,
9815          resizable: false,
9816          draggable: false,
9817          title: 'Poista luottotappio',
9818          beforeclose: function(event, ui) {
9819              event.stopPropagation()
9820          },
9821          close: function(){
9822            dialog.dialog('destroy');
9823            dialog.remove();
9824          },
9825          buttons: {
9826              'Peruuta': function() {
9827                  dialog.dialog('close');
9828              },
9829              'Poista luottotappio': function() {
9830                  //console.log($('input.nullify_open_credit_loss_amount').is( ":checked" ), $('input.nullify_amount').val());
9831                  let nullifyFully = $('input.nullify_open_credit_loss_amount').is( ":checked" );
9832                  let amount = $('input.nullify_amount').val();
9833                  if(confirm("Haluatko varmasti poistaa luottotappion?")){
9834                      self.nullifyCreditLoss(dialog, nullifyFully, amount);
9835                  }
9836              }
9837          }
9838      });
9839  };
9840
9841  self.confirmAddCreditLoss = function(){
9842      var dialog = $('<div />', {"id": "confirm-add-credit-loss-dialog", "style":"text-align:left;"}).html('Haluatko varmasti merkitä laskun avoimen osuuden luottotappioksi?');
9843      
9844      dialog.dialog({
9845        width: 400,
9846        autoOpen: true,
9847        modal: true,
9848        resizable: false,
9849        draggable: false,
9850        title: 'Merkitse luottotappioksi',
9851        beforeclose: function(event, ui) {
9852            event.stopPropagation()
9853        },
9854          buttons: {
9855            'Peruuta': function() {
9856                dialog.dialog('close');
9857            },
9858            'Merkitse luottotappioksi': function() {
9859                    self.addCreditLoss(dialog);
9860            }
9861        }
9862    });
9863  };
9864
9865  self.suggestCreditLoss = function($dialog){
9866
9867      $.ajax({
9868          "dataType": 'json',
9869          "type": "POST",
9870          "url" : "/iv_laskutus_ja_reskontra/suggestCreditLoss/" .concat(self.invoiceId()),
9871          "beforeSend":function(request){
9872              global.showLoadingDialog('Lähetetään luottotappiosuositusta...');
9873          }
9874      }).done(function(responseJSON){
9875
9876          console.log('responseJSON!:', responseJSON);
9877          $dialog.dialog("close");
9878          global.show_message(responseJSON);
9879      }).always(function(){
9880          global.close_loading_dialog();
9881      }).error(function(response){
9882          console.log('addCreditLoss error:', response);
9883          global.show_message($.parseJSON(response.responseText));
9884      });
9885  };
9886
9887  self.updateCreditLossStopSetting = function($dialog){
9888
9889      var creditLossStop = $dialog.find('input:radio[name=credit_loss_stop]:checked').val();
9890
9891      $.ajax({
9892          "dataType": 'json',
9893          "type": "POST",
9894          "data": {
9895            credit_loss_stop: creditLossStop
9896          },
9897          "url" : "/iv_laskutus_ja_reskontra/update_credit_loss_stop_setting/" .concat(self.invoiceId()),
9898          "beforeSend":function(request){
9899              global.showLoadingDialog('Tallenetaan luottotappioeston asetus..');
9900          }
9901      }).done(function(responseJSON){
9902
9903          console.log('responseJSON!:', responseJSON);
9904
9905          //Refresh the datatables
9906          if(pages.iv_laskutus_ja_reskontra.$datatable_iv != null){
9907              pages.iv_laskutus_ja_reskontra.$datatable_iv.fnClearTable( 0 );
9908              pages.iv_laskutus_ja_reskontra.$datatable_iv.fnDraw();
9909          }
9910
9911          if(pages.iv_laskutus_ja_reskontra.$datatable != null){
9912              pages.iv_laskutus_ja_reskontra.$datatable.fnClearTable( 0 );
9913              pages.iv_laskutus_ja_reskontra.$datatable.fnDraw();
9914          }
9915
9916          $dialog.dialog("close");
9917          global.show_message(responseJSON, function(){self.refresh();});
9918        //   self.refresh();
9919      }).always(function(){
9920          global.close_loading_dialog();
9921      }).error(function(response){
9922          console.log('addCreditLoss error:', response);
9923          global.show_message($.parseJSON(response.responseText));
9924      });
9925  };
9926
9927  self.addCreditLoss = function($dialog){
9928    var url;
9929    if(pages.iv_laskutus_ja_reskontra.$datatable_iv != null && pages.reskontra.$datatable === null){
9930      url = "/iv_laskutus_ja_reskontra/addCreditLoss/" .concat(self.invoiceId());
9931    }else{
9932      url = "/reskontra/addCreditLoss/" .concat(self.invoiceId());
9933    }
9934      $.ajax({
9935          "dataType": 'json',
9936          "type": "POST",
9937          "url" : url,
9938          "beforeSend":function(request){
9939              global.showLoadingDialog('Merkitään luottotappiota...');
9940          }
9941      }).done(function(responseJSON){
9942
9943          console.log('responseJSON!:', responseJSON);
9944
9945          //Refresh the datatables
9946          if(pages.iv_laskutus_ja_reskontra.$datatable_iv != null){
9947              pages.iv_laskutus_ja_reskontra.$datatable_iv.fnClearTable( 0 );
9948              pages.iv_laskutus_ja_reskontra.$datatable_iv.fnDraw();
9949          }
9950
9951          if(pages.iv_laskutus_ja_reskontra.$datatable != null){
9952              pages.iv_laskutus_ja_reskontra.$datatable.fnClearTable( 0 );
9953              pages.iv_laskutus_ja_reskontra.$datatable.fnDraw();
9954          }
9955
9956          if( pages.reskontra.$datatable !== null ){
9957            pages.reskontra.$datatable.fnClearTable( 0 );
9958            pages.reskontra.$datatable.fnDraw();
9959        }
9960
9961          $dialog.dialog("close");
9962          global.show_message(responseJSON, function(){self.refresh();});
9963        //   self.refresh();
9964      }).always(function(){
9965          global.close_loading_dialog();
9966      }).error(function(response){
9967          console.log('addCreditLoss error:', response);
9968          global.show_message($.parseJSON(response.responseText));
9969      });
9970  };
9971
9972
9973  self.nullifyCreditLoss = function($dialog, nullifyFully, amount){
9974    let url = '';
9975    if(pages.iv_laskutus_ja_reskontra.$datatable_iv != null && pages.reskontra.$datatable === null){
9976        url = "/iv_laskutus_ja_reskontra/nullifyCreditLoss/" .concat(self.invoiceId());
9977    }
9978      $.ajax({
9979          "dataType": 'json',
9980          "type": "POST",
9981          "url" : url,
9982          "data": {
9983            nullifyFully,
9984            amount
9985          },
9986          "beforeSend":function(request){
9987              global.showLoadingDialog('Poistetaan luottotappiota...');
9988          }
9989      }).done(function(responseJSON){
9990
9991          //Refresh the datatables
9992          if(pages.iv_laskutus_ja_reskontra.$datatable_iv != null){
9993              pages.iv_laskutus_ja_reskontra.$datatable_iv.fnClearTable( 0 );
9994              pages.iv_laskutus_ja_reskontra.$datatable_iv.fnDraw();
9995          }
9996
9997          if(pages.iv_laskutus_ja_reskontra.$datatable != null){
9998              pages.iv_laskutus_ja_reskontra.$datatable.fnClearTable( 0 );
9999              pages.iv_laskutus_ja_reskontra.$datatable.fnDraw();
10000          }
10001
10002          if( pages.reskontra.$datatable !== null ){
10003            pages.reskontra.$datatable.fnClearTable( 0 );
10004            pages.reskontra.$datatable.fnDraw();
10005        }
10006
10007          $dialog.dialog("close");
10008          global.show_message(responseJSON, function(){self.refresh();});
10009        //   self.refresh();
10010      }).always(function(){
10011          global.close_loading_dialog();
10012      }).error(function(response){
10013          global.show_message(JSON.parse(response.responseText));
10014      });
10015  };
10016
10017  self.insertInvoiceToArvatoIfRequiredAndPrintPdf = function(){
10018
10019
10020      if(self.data.invoice.status() == 0){
10021        self.insertInvoiceToArvatoAndPrintPdf();
10022      }else {
10023        self.printInvoicePdf();
10024      }
10025  };
10026
10027  self.printInvoicePdf = function(){
10028
10029      window.open('/lasku/pdf/'.concat(self.invoiceId()));
10030      return false;
10031  };
10032
10033    self.insertInvoiceToArvatoAndPrintPdf = function(w){
10034
10035        var dialog = $('<div />', {"style":"text-align:left;"}).html('HUOM! Lasku muuttuu luonnoksesta avoimeksi tulostuksen yhteydessä. <br/><br/><strong>Itse tulostettuja laskuja ei toimiteta asiakkaalle Innovoicen toimesta.</strong>')
10036            .dialog({
10037                autoOpen: true,
10038                modal: true,
10039                resizable: false,
10040                draggable: false,
10041                title: 'Laskun tulostus',
10042                beforeclose: function(event, ui) {event.stopPropagation()},
10043                close: function(){
10044                    dialog.dialog('destroy');
10045                    dialog.remove();
10046                },
10047                buttons: {
10048                    'Peruuta': function() {
10049                        dialog.dialog('close');
10050                    },
10051                    'Tulosta lasku': function() {
10052
10053                        $.ajax({
10054                            "dataType": 'json',
10055                            "type": "POST",
10056                            "url" : "/reskontra/insertInvoiceToLedgerForPrinting/".concat(self.invoiceId()),
10057                            "beforeSend":function(request){
10058                                global.showLoadingDialog('Muodostetaan tulostettavaa laskua...');
10059                            },
10060                            "success": function(responseJSON){
10061
10062                                if(responseJSON.type == 'success'){
10063                                    self.printInvoicePdf();
10064
10065                                    if( pages.reskontra.$datatable !== null ){
10066                                        pages.reskontra.$datatable.fnClearTable( 0 );
10067                                        pages.reskontra.$datatable.fnDraw();
10068                                    }
10069
10070                                    self.refresh();
10071                                }
10072
10073                                global.close_loading_dialog();
10074                                dialog.dialog('close');
10075                            },
10076                            error: function(response){
10077                                global.close_loading_dialog();
10078                                global.show_message({
10079                                    type: 'error',
10080                                    title: 'Virhe! Laskua ei voitu tulostaa',
10081                                    text: 'Laskua ei voitu muuttaa luonnoksesta avoimeksi, yritä myöhemmin uudelleen. Mikäli virhe jatkuu, ota yhteyttä Innovoicen asiakaspalveluun.'
10082                                });
10083                            }
10084                        });
10085                    }
10086                }
10087            });
10088    };
10089
10090    self.showRequestForCreditingDialog = function() {
10091
10092        return self.requestForCreditingDialog.show();
10093    }
10094    
10095    self.showCustomerCreditInvoiceDialog = function() {
10096
10097        try{
10098            var result = self.customerCreditInvoiceVM.validateAndSetData(ko.toJS(self.data))
10099        } catch (error){
10100            return global.show_message({type: 'error', text: error.message})   
10101        }
10102
10103        if(result.creditingNotAllowed){
10104            return self.showRequestForCreditingDialog()
10105        }
10106
10107        function updateTablesAndInvoiceDialog(){
10108            self.show()
10109
10110            if( pages.reskontra.$datatable !== null ){
10111                pages.reskontra.$datatable.fnClearTable( 0 );
10112                pages.reskontra.$datatable.fnDraw();
10113            }
10114    
10115        }
10116        return self.customerCreditInvoiceVM.show({callback: updateTablesAndInvoiceDialog});
10117    }
10118};
10119
10120;var LedgerPaymentsDialogVm = function() {
10121  'use strict';
10122  var self = this;
10123  self.paymentDialog = null;
10124  //self.inited = ko.observable(false);
10125
10126  self.show_ledger_payment_report = function(reportDate, isHandled) {
10127    var $dialog = $('<div />')
10128
10129    if ($dialog.hasClass('ui-dialog-content')) {
10130      $dialog.dialog('destroy');
10131    }
10132
10133    $.ajax({
10134      processData: false,
10135      dataType: 'json',
10136      type: 'GET',
10137      url: 'innovoice_ledger_payments/daily_report?date=' + reportDate,
10138      beforeSend: function(request) {
10139        $dialog.dialog({
10140          width: 1200,
10141          height: 600,
10142          modal: true,
10143          resizable: true,
10144          title: 'Suoritukset ' + reportDate,
10145          close: function() {
10146            $dialog.dialog('destroy');
10147          }
10148        });
10149        global.show_ajax_loader($dialog);
10150      },
10151      success: function(response) {
10152        $dialog.html(response.viewFile);
10153
10154      },
10155      error: function(response) {
10156        $dialog.dialog('close');
10157        var responseJSON = JSON.parse(response.responseText);
10158
10159        global.close_loading_dialog();
10160        global.show_message(responseJSON);
10161      }
10162    });
10163
10164    var buttons = {
10165      'Päivitä tiedot': function(){
10166        $dialog.dialog('close');
10167        self.show_ledger_payment_report(reportDate);
10168      },
10169      'Lataa suoritukset': function(){
10170        self.downloadPayments(reportDate);
10171      }
10172    }
10173
10174    if(parseInt(isHandled) === 0){
10175      buttons["Merkitse käsitellyksi"] = function(){
10176        self.showConfirmDialog('<span>Merkitse päivä käsitellyks?</span>', self.markDateHandled, {entryDate: reportDate})
10177      }
10178    }
10179      $dialog.dialog('option', 'buttons', buttons)
10180    
10181  } //show_ledger_payment_report
10182
10183  self.downloadPayments = function(reportDate){
10184    url = 'innovoice_ledger_payments/exportPaymentData/?date=' + reportDate;
10185    window.location.href=url;
10186  }
10187
10188  self.refreshDatatables = function(){
10189    if( pages.reskontra.$datatable !== null ){
10190      pages.reskontra.$datatable.fnClearTable( 0 );
10191      pages.reskontra.$datatable.fnDraw();
10192    }
10193    if( pages.innovoice_ledger.$ledger_payments_dt !== null ){
10194      pages.innovoice_ledger.$ledger_payments_dt.fnClearTable(0);
10195      pages.innovoice_ledger.$ledger_payments_dt.fnDraw();
10196    }
10197    if( pages.innovoice_ledger.$ledger_payment_totals_dt !== null ){
10198      pages.innovoice_ledger.$ledger_payment_totals_dt.fnClearTable(0);
10199      pages.innovoice_ledger.$ledger_payment_totals_dt.fnDraw();
10200    }
10201  }
10202
10203  self.refreshTotalsDatatable = function(){
10204    if( pages.innovoice_ledger.$ledger_payment_totals_dt !== null ){
10205      pages.innovoice_ledger.$ledger_payment_totals_dt.fnClearTable(0);
10206      pages.innovoice_ledger.$ledger_payment_totals_dt.fnDraw();
10207    }
10208  }
10209
10210  self.show_ledger_payment = function(paymentId) {
10211    self.paymentDialog = $('#show-ledger-payment-dialog');
10212
10213    if(self.paymentDialog.length === 0){
10214      self.paymentDialog = $('<div id="show-ledger-payment-dialog"/>')
10215    }
10216
10217    if (self.paymentDialog.hasClass('ui-dialog-content')) {
10218      self.paymentDialog.dialog('destroy');
10219    }
10220
10221    $.ajax({
10222      processData: false,
10223      dataType: 'json',
10224      type: 'GET',
10225      url: 'innovoice_ledger_payments/get_payment?id=' + paymentId,
10226      beforeSend: function(request) {
10227        self.paymentDialog.dialog({
10228          width: 900,
10229          height: 600,
10230          modal: true,
10231          resizable: false,
10232          title: 'Suorituksen tiedot',
10233          // close: function() {
10234          //   $dialog.dialog('close');
10235          // },
10236        });
10237        global.show_ajax_loader(self.paymentDialog);
10238      },
10239      success: function(response) {
10240        
10241        var payment = response.payment;
10242        
10243        self.paymentDialog.html(response.viewFile);
10244        
10245      },
10246
10247    });
10248    
10249  } //show_ledger_payment
10250    
10251  self.reallocatePayment = function(paymentId, creditDate) {
10252    
10253    var $form = $('<form />').append(
10254      $('<p />').html('Anna Laskun numero'),
10255      $('<input />', { type: 'text', name: 'invoiceNo', id: 'invoiceId', class: 'form-control' }).val(''),
10256      $('<br><br>'),
10257      $('<p />').html('Kirjauspäivä'),
10258      $('<input />', { type: 'text', name: 'allocationDate', id: 'allocationDate', class: 'form-control' }).datepicker(
10259        {
10260          format: 'dd.mm.yyyy',
10261          calendarWeeks: true,
10262          language: 'fi',
10263          weekStart: 1,
10264          clearBtn: true,
10265          todayHighlight: true,
10266          defaultViewDate: 'today',
10267          autoclose: true
10268        }
10269      ).datepicker('setDate', new Date())
10270    );
10271
10272    // TODO JONNE: tänne pitäisi saada suorituksen(jonka id on paymentId) unallocated_reporting_add_date (päivämäärä jolloin se on hyvitetty)
10273    // jotta sitä voi tarvittaessa muuttaa. Esim heidi voi asettaa hyvitksen ja uuden kohdistuksen samalle päivälle kuin milloin suoritus tullut sisään.
10274    
10275    if(creditDate){
10276      $form.append(
10277        $('<br><br>'),
10278        $('<p />').html('Kirjauspäivä'),
10279        $('<input />', { type: 'text', name: 'creditDate', id: 'creditDate', class: 'form-control' }).datepicker(
10280          {
10281            format: 'dd.mm.yyyy',
10282            calendarWeeks: true,
10283            language: 'fi',
10284            weekStart: 1,
10285            clearBtn: true,
10286            todayHighlight: true,
10287            defaultViewDate: 'today',
10288            autoclose: true
10289          }
10290        ).datepicker('setDate', new Date(creditDate))
10291      );
10292    }
10293
10294    var $dialog = $('<div />', { style: 'text-align:left;' })
10295    .append($form)
10296    .dialog({
10297      width: 320,
10298      autoOpen: true,
10299      modal: true,
10300      resizable: false,
10301      draggable: false,
10302      beforeClose: function(event, ui) {
10303        event.stopPropagation();
10304      },
10305      close: function() {
10306        $dialog.dialog('destroy');
10307      },
10308      title: 'Kohdista maksu laskulle',
10309      buttons: {
10310        'Kohdista Maksu': function() {
10311          $form.trigger('submit');
10312        },
10313        Peruuta: function() {
10314          $(this).dialog('close');
10315        },
10316      },
10317    });
10318
10319    $form.on('submit', function(e) {
10320      //Get the data from the form element
10321      e.stopPropagation()
10322      var data = _.object(
10323        $form.serializeArray().map(function(v) {
10324          return [v.name, v.value];
10325        })
10326      );
10327      
10328      if(!data.invoiceNo){
10329        window.alert('Laskun numero on pakollinen')
10330        return false;
10331      }
10332      //Add some extra data
10333      _.extend(data, { paymentId: paymentId });
10334
10335      e.preventDefault();
10336
10337      global.show_loading_dialog('Kohdistetaan laskulle...');
10338
10339      $.ajax({
10340        url: '/innovoice_ledger_payments/reallocatePayment',
10341        dataType: 'json',
10342        type: 'POST',
10343        data: data,
10344      })
10345        .done(function(responseJSON) {
10346          $dialog.dialog('close');
10347          global.close_loading_dialog();
10348          self.paymentDialog.dialog('close');
10349          self.show_ledger_payment(paymentId);
10350          self.refreshDatatables()
10351          global.show_message(responseJSON);
10352        })
10353        .fail(function(response) {
10354          var responseJSON = JSON.parse(response.responseText);
10355
10356          global.close_loading_dialog();
10357          global.show_message(responseJSON);
10358        });
10359    });
10360  }
10361
10362  self.refundPayment = function(paymentId) {
10363   
10364    var $form = $('<form />').append(
10365      $('<p />').html('Kommentti (valinnainen)'),
10366      $('<input />', { type: 'text', name: 'comment', id: 'comment', class: 'text medium' }).val('')
10367    );
10368
10369    var $dialog = $('<div />', { style: 'text-align:left;' })
10370      .append($form)
10371      .dialog({
10372        width: 320,
10373        autoOpen: true,
10374        modal: true,
10375        resizable: false,
10376        draggable: false,
10377        beforeClose: function(event, ui) {
10378          event.stopPropagation();
10379        },
10380        close: function() {
10381          $dialog.dialog('destroy');
10382        },
10383        title: 'Merkitse maksu palautetuksi',
10384        buttons: {
10385          'Palauta Maksu': function() {
10386            $form.trigger('submit');
10387          },
10388          Peruuta: function() {
10389            $(this).dialog('close');
10390          },
10391        },
10392      });
10393
10394    $form.on('submit', function(e) {
10395      //Get the data from the form element
10396      var data = _.object(
10397        $form.serializeArray().map(function(v) {
10398          return [v.name, v.value];
10399        })
10400      );
10401
10402      //Add some extra data
10403      _.extend(data, { paymentId: paymentId });
10404
10405      e.preventDefault();
10406
10407      global.show_loading_dialog('Merkitään palautetuksi...');
10408
10409      $.ajax({
10410        url: '/innovoice_ledger_payments/refundPayment',
10411        dataType: 'json',
10412        type: 'POST',
10413        data: data,
10414      })
10415        .done(function(responseJSON) {
10416          $dialog.dialog('close');
10417          global.close_loading_dialog();
10418          self.paymentDialog.dialog('close');
10419          self.show_ledger_payment(paymentId);
10420          self.refreshTotalsDatatable()
10421          global.show_message(responseJSON);
10422        })
10423        .fail(function(response) {
10424          var responseJSON = JSON.parse(response.responseText);
10425
10426          global.close_loading_dialog();
10427          global.show_message(responseJSON);
10428        });
10429    });
10430    
10431  }
10432
10433  self.confirmDeletePayment = function(paymentId) {
10434   
10435    var data = { paymentId: paymentId };
10436    var html = '<strong>Huom! Poista ainoastaan suoritukset jotka eivät kuulu Innovoicen järjestelmään!</strong></br></br><span>Haluatko varmasti poistaa suorituksen?</span>';
10437     
10438    self.showConfirmDialog(html, self.deletePayment, data);
10439    
10440  }
10441
10442  
10443  self.markAsInterest = function(paymentId) {
10444    
10445    var $form = $('<form />').append(
10446      $('<p />').html('Anna Laskun numero'),
10447      $('<input />', { type: 'text', name: 'invoiceNo', id: 'invoiceId', class: 'text medium' }).val(''),
10448      $('<br><br>'),
10449      $('<input />', { type: 'text', name: 'allocationDate', id: 'allocationDate', class: 'form-control' }).datepicker(
10450        {
10451          format: 'dd.mm.yyyy',
10452          calendarWeeks: true,
10453          language: 'fi',
10454          weekStart: 1,
10455          clearBtn: true,
10456          todayHighlight: true,
10457          defaultViewDate: 'today',
10458          autoclose: true
10459        }
10460      ).datepicker('setDate', new Date()),
10461      $('<br><br>'),
10462      $('<p />').html('Kommentti (valinnainen)'),
10463      $('<input />', { type: 'text', name: 'comment', id: 'comment', class: 'text medium' }).val('')
10464    );
10465
10466    var $dialog = $('<div />', { style: 'text-align:left;' })
10467    .append($form)
10468    .dialog({
10469      width: 320,
10470      autoOpen: true,
10471      modal: true,
10472      resizable: false,
10473      draggable: false,
10474      beforeClose: function(event, ui) {
10475        event.stopPropagation();
10476      },
10477      close: function() {
10478        $dialog.dialog('destroy');
10479      },
10480      title: 'Kirjaa maksu korkotuotoksi',
10481      buttons: {
10482        'Tee Kirjaus': function() {
10483          $form.trigger('submit');
10484        },
10485        Peruuta: function() {
10486          $(this).dialog('close');
10487        },
10488      },
10489    });
10490
10491    $form.on('submit', function(e) {
10492      //Get the data from the form element
10493      var data = _.object(
10494        $form.serializeArray().map(function(v) {
10495          return [v.name, v.value];
10496        })
10497      );
10498
10499      //Add some extra data
10500      _.extend(data, { paymentId: paymentId });
10501
10502      e.preventDefault();
10503
10504      global.show_loading_dialog('Merkitään korkotuotoksi...');
10505
10506      $.ajax({
10507        url: '/innovoice_ledger_payments/markAsInterest',
10508        dataType: 'json',
10509        type: 'POST',
10510        data: data,
10511      })
10512        .done(function(responseJSON) {
10513          $dialog.dialog('close');
10514          global.close_loading_dialog();
10515          self.paymentDialog.dialog('close');
10516          self.show_ledger_payment(paymentId);
10517          self.refreshTotalsDatatable()
10518          global.show_message(responseJSON);
10519        })
10520        .fail(function(response) {
10521          var responseJSON = JSON.parse(response.responseText);
10522
10523          global.close_loading_dialog();
10524          global.show_message(responseJSON);
10525        });
10526    });
10527    
10528  }
10529
10530  self.deletePayment = function(data){
10531    global.show_loading_dialog('Poistetaan suoritusta...');
10532
10533    $.ajax({
10534      url: '/innovoice_ledger_payments/deletePayment',
10535      dataType: 'json',
10536      type: 'POST',
10537      data: data,
10538    })
10539      .done(function(responseJSON) {
10540        // $dialog.dialog('close');
10541        global.close_loading_dialog();
10542        self.paymentDialog.dialog('close');
10543        self.refreshDatatables();
10544        global.show_message(responseJSON);
10545      })
10546      .fail(function(response) {
10547        var responseJSON = JSON.parse(response.responseText);
10548
10549        global.close_loading_dialog();
10550        global.show_message(responseJSON);
10551      });
10552  }
10553
10554  self.showConfirmDialog = function(html, callback, data){
10555    var $dialog = $('<div />', { style: 'text-align:left;' })
10556    .dialog({
10557      width: 320,
10558      autoOpen: true,
10559      modal: true,
10560      resizable: false,
10561      draggable: false,
10562      close: function() {
10563        $dialog.dialog('destroy');
10564      },
10565      buttons: {
10566        'Kyllä': function() {
10567          if(typeof callback === 'function'){
10568            callback(data);
10569            $(this).dialog('close');
10570          }
10571        },
10572        Peruuta: function() {
10573          $(this).dialog('close');
10574        },
10575      },
10576    }).html(html);
10577  }
10578
10579  self.markDateHandled = function(data){
10580    global.show_loading_dialog('Käsitellään pyyntöä...');
10581    $.ajax({
10582      url: '/innovoice_ledger_payments/markDateAsHandled',
10583      dataType: 'json',
10584      type: 'POST',
10585      data: data,
10586    })
10587      .done(function(responseJSON) {
10588
10589        global.close_loading_dialog();
10590        self.refreshTotalsDatatable()
10591        global.show_message(responseJSON);
10592      })
10593      .fail(function(response) {
10594        var responseJSON = JSON.parse(response.responseText);
10595
10596        global.close_loading_dialog();
10597        global.show_message(responseJSON);
10598      });
10599  }
10600
10601  self.getPaymentLog = function(paymentId, element){
10602    $.ajax({
10603      url: '/innovoice_ledger_payments/getPaymentLog',
10604      dataType: 'json',
10605      type: 'POST',
10606      data: {paymentId: paymentId},
10607      beforeSend: function(){
10608      }
10609    })
10610      .done(function(response) {
10611        element.html(response.data.view);
10612      })
10613      .fail(function(response) {
10614        var responseJSON = JSON.parse(response.responseText);
10615        global.show_message(responseJSON);
10616      });
10617
10618  }
10619
10620  self.addLogEntry = function(paymentId, message, element, input){
10621
10622    $.ajax({
10623        url: '/innovoice_ledger_payments/addPaymentLogItem',
10624        dataType: 'json',
10625        type: 'POST',
10626        data: {paymentId: paymentId, message: message},
10627        beforeSend: function(){
10628        }
10629      })
10630        .done(function(response) {
10631          element.html(response.data.view);
10632          input.val('');
10633        })
10634        .fail(function(response) {
10635          var responseJSON = JSON.parse(response.responseText);
10636          global.show_message(responseJSON);
10637        });
10638  }
10639  
10640}
10641
10642;var PaymentTerminalVm = function (data) {
10643  'use strict';
10644  var self = this;
10645  self.receiptId = null;
10646  self.currentPayment = ko.observableArray([]);
10647  self.selectedPaymentTerminal = ko.observable('');
10648  self.paymentTerminalError = ko.observable('');
10649  self.paymentTerminalResponse = ko.observable('');
10650  self.wsConnection = new WSConnection();
10651  self.originatorApp = null;
10652  self.tempTransaction = null;
10653  self.refundTransaction = ko.observableArray([]);
10654  self.checkTransaction = ko.observableArray([]);
10655  self.previousTransactionId = null;
10656  self.showErrorMessage = function(message) {
10657    humane.log(message, {
10658      addnCls: 'humane-jackedup-error',
10659      timeout: 8000,
10660    });
10661  };
10662
10663  self.showAbort = ko.observable(false);
10664
10665  // asiakkuudet page status and terminalinfo response will be set here
10666  self.wsConnection.connection.response.subscribe(function(response){
10667    if(response.result && response.result.response_to && (response.result.response_to == 'Status' || response.result.response_to == 'TerminalInfo')){
10668      self.paymentTerminalResponse(JSON.stringify(response.result, undefined, 2));
10669    }
10670  });
10671
10672  self.wsConnection.connection.status.subscribe(function(status){
10673    if(status == 'error'){
10674      self.paymentTerminalError('');
10675      self.paymentTerminalError(self.wsConnection.connection.msg);
10676    }
10677  });
10678
10679  // if paymentTerminal is connected and connection reason matches case defined below do something
10680  self.wsConnection.connection.connected.subscribe(function(connected){
10681    if (connected && self.wsConnection.connection.connectionReason() === 'check') {
10682      self.wsSendCheck();
10683    }
10684    if (connected && self.wsConnection.connection.connectionReason() === 'purchase') {
10685      self.wsSendPurchase();
10686    }
10687    if (connected && self.wsConnection.connection.connectionReason() === 'refund') {
10688      self.wsSendRefund();
10689    }
10690  });
10691
10692  self.getTerminalStatus = function (terminalData) {
10693    self.paymentTerminalError('');
10694    self.paymentTerminalResponse('');
10695    if (
10696      !terminalData ||
10697      !terminalData.user_name ||
10698      !terminalData.password ||
10699      !terminalData.terminal_id ||
10700      !terminalData.url
10701    ) {
10702      var msg = 'Yhteyden luomiseen tarvittavat tiedot puutteelliset';
10703      self.paymentTerminalError(msg);
10704    } else {
10705      self.wsConnection.setWsConnectionData({
10706        selectedTerminal: terminalData,
10707        connectionReason: 'TerminalInfo',
10708      });
10709      self.wsConnection.wsConnect();
10710      $('#wsDialog').dialog({
10711        width: 400,
10712        modal: true,
10713        resizable: false,
10714        title: 'Maksupäätelaitteen tila',
10715        close: function () {
10716          if (self.wsConnection.ws) self.wsConnection.ws.close();
10717        },
10718        buttons: {
10719          'Hae tila': function(){
10720            self.wsConnection.setWsConnectionData({
10721              selectedTerminal: terminalData,
10722              connectionReason: 'Status',
10723            });
10724            self.wsConnection.wsConnect();
10725          },
10726          'Hae tiedot': function(){
10727            self.wsConnection.setWsConnectionData({
10728              selectedTerminal: terminalData,
10729              connectionReason: 'TerminalInfo',
10730            });
10731            self.wsConnection.wsConnect();
10732          }
10733        }
10734      });
10735    }
10736  };
10737
10738  self.connectPaymentTerminalPurchase = function(paymentTerminals, paymentSum, receiptId, payment, origin){
10739    var ladda = Ladda.create(document.querySelector('#connectToTerminalButton'));
10740    ladda.start();
10741    self.paymentTerminalError('');
10742    self.wsConnection.resetWsConnectionData();
10743    if (!self.selectedPaymentTerminal()) {
10744      self.wsConnection.setWsConnectionData({ status: 'error', msg: 'Valitse ensin maksupäätelaite!' });
10745      ladda.remove();
10746      return;
10747    }
10748
10749    var terminalData = paymentTerminals.find(function(terminal){
10750      return terminal.terminal_id == self.selectedPaymentTerminal();
10751    });
10752    if (
10753      !terminalData ||
10754      !terminalData.user_name ||
10755      !terminalData.password ||
10756      !terminalData.terminal_id
10757    ) {
10758      self.wsConnection.setWsConnectionData({ status: 'error', msg: 'Maksupäätelaitteen tiedot puutteelliset!' });
10759      ladda.remove();
10760      return;
10761    }
10762    if (
10763      !paymentSum || paymentSum == 0
10764    ) {
10765      self.wsConnection.setWsConnectionData({ status: 'error', msg: 'Maksurivien summa virheellinen!' });
10766      ladda.remove();
10767      return;
10768    }
10769
10770    if(!payment){
10771      self.wsConnection.setWsConnectionData({ status: 'error', msg: 'Kuormakirjalle ei löydy maksutapahtumaa!' });
10772      ladda.remove();
10773      return;
10774    }
10775
10776    self.receiptId = receiptId;
10777    self.originatorApp = origin;
10778    self.currentPayment(payment);
10779    self.wsConnection.setWsConnectionData({
10780      selectedTerminal: terminalData,
10781      amountToPay: paymentSum,
10782      connectionReason: 'purchase',
10783    });
10784    self.wsConnection.wsConnect();
10785  };
10786
10787  self.connectPaymentTerminalRefund = function(paymentTerminals, receiptId, payment, origin){
10788    self.paymentTerminalError('');
10789    self.wsConnection.resetWsConnectionData();
10790    self.previousTransactionId = payment.payment_terminal_transaction_id;
10791    try{
10792      var fetchTransaction = self.getPaymentTerminalTransaction({ transactionId: self.previousTransactionId });
10793      fetchTransaction.then(function(data){
10794        self.refundTransaction(data);
10795        self.currentPayment(payment);
10796        self.receiptId = receiptId;
10797        self.originatorApp = origin;
10798        var terminalData = paymentTerminals.find(function(terminal){
10799          return terminal.terminal_id == data.terminal_id;
10800        });
10801        if(!terminalData){
10802          self.wsConnection.setWsConnectionData({ status: 'error', msg: 'Maksupäätetapahtumaan liitetttyä maksupäätettä ei löytynyt!' });
10803          ladda.remove();
10804          return;
10805        }
10806        self.wsConnection.setWsConnectionData({
10807          selectedTerminal: terminalData,
10808          connectionReason: 'refund',
10809        });
10810        self.wsConnection.wsConnect();
10811        });
10812        fetchTransaction.fail(function(response){
10813          var responseJson = JSON.parse(response.responseText),
10814          error;
10815          error = responseJson.error || responseJson || 'Maksupäätetapahtuman haku epäonnistui';
10816          self.showErrorMessage(error);
10817          self.wsConnection.wsDisconnect();
10818        });
10819    }catch(err){
10820      self.paymentTerminalError('Maksupäätetapahtuman haku epäonnistui');
10821    }
10822  };
10823
10824  self.connectPaymentTerminalCheck = function(paymentTerminals, receiptId, payment, pendingPaymentTerminalTransaction, origin){
10825    self.paymentTerminalError('');
10826    self.wsConnection.resetWsConnectionData();
10827    var transactionId = pendingPaymentTerminalTransaction.id;
10828    try{
10829      var fetchTransaction = self.getPaymentTerminalTransaction({ transactionId: transactionId });
10830      fetchTransaction.then(function(data){
10831        self.checkTransaction(data);
10832        self.currentPayment(payment);
10833        self.receiptId = receiptId;
10834        self.originatorApp = origin;
10835        var terminalData = paymentTerminals.find(function(terminal){
10836          return terminal.terminal_id == data.terminal_id;
10837        });
10838        if(!terminalData){
10839          self.wsConnection.setWsConnectionData({ status: 'error', msg: 'Maksupäätetapahtumaan liitetttyä maksupäätettä ei löytynyt!' });
10840          ladda.remove();
10841          return;
10842        }
10843        self.wsConnection.setWsConnectionData({
10844          selectedTerminal: terminalData,
10845          connectionReason: 'check',
10846        });
10847        self.wsConnection.wsConnect();
10848      });
10849      fetchTransaction.fail(function(response){
10850        var responseJson = JSON.parse(response.responseText),
10851        error;
10852        error = responseJson.error || responseJson || 'Maksupäätetapahtuman haku epäonnistui';
10853        self.showErrorMessage(error);
10854        self.wsConnection.wsDisconnect();
10855      });
10856    }catch(err){
10857      self.paymentTerminalError('Maksupäätetapahtuman haku epäonnistui');
10858    }
10859  };
10860
10861  self.reconnect = function(){
10862    self.wsConnection.wsConnect();
10863  };
10864
10865  self.completePaymentTerminalPayment = function(companyData, transactionData){
10866    self.wsSendPrint(companyData, transactionData);
10867    self.wsClose();
10868  }
10869
10870  self.completePaymentTerminalRefund = function(companyData, transactionData){
10871    self.wsSendPrint(companyData, transactionData);
10872    self.wsClose();
10873  }
10874
10875  self.wsSendPurchase = function(){
10876    try {
10877      var amount = self.wsConnection.connection.amountToPay();
10878      amount = Math.round(100 * amount);
10879
10880      var setTransaction = self.setTransactionToPayment({
10881        paymentId: self.currentPayment().id,
10882        transactionType: 'Purchase',
10883        receiptId: self.receiptId,
10884        origin: self.originatorApp,
10885        terminalId: self.wsConnection.connection.selectedTerminal()['terminal_id'],
10886        amount: amount,
10887      });
10888
10889      setTransaction.then(function(response){
10890        self.tempTransaction = response.transaction;
10891        var sendParams = {
10892          cashier_language: 'fi',
10893          receipt_id: self.receiptId,
10894          amount: amount,
10895          currency: 'EUR',
10896          no_timeout: false,
10897        };
10898        self.wsConnection.wsSend('Purchase', sendParams);
10899      });
10900      setTransaction.fail(function(response){
10901        var responseJson = JSON.parse(response.responseText),
10902        error;
10903        error = responseJson.error || responseJson || 'Maksun lähetys epäonnistui';
10904        self.showErrorMessage(error);
10905        self.wsConnection.wsDisconnect();
10906      });
10907    } catch (error) {
10908      self.paymentTerminalError('Maksun lähetys epäonnistui');
10909      console.log(error);
10910    }
10911  };
10912
10913  self.wsSendCheck = function(){
10914      var data = ko.toJS(self.checkTransaction);
10915      var sendParams = {
10916        receipt_id: parseInt(data['receipt_id']),
10917        amount: parseInt(data['amount']),
10918        currency: 'EUR',
10919      };
10920      self.wsConnection.wsSend('Check', sendParams);
10921  };
10922
10923  self.wsSendRefund = function(){
10924    try {
10925      var data = ko.toJS(self.refundTransaction);
10926      var setTransaction = self.setTransactionToPayment({
10927        paymentId: self.currentPayment().id,
10928        transactionType: 'Refund',
10929        previousTransactionId: self.previousTransactionId,
10930        receiptId: self.receiptId,
10931        origin: self.originatorApp,
10932        terminalId: self.wsConnection.connection.selectedTerminal()['terminal_id'],
10933        amount: parseInt(data['amount']),
10934      });
10935
10936      setTransaction.then(function(response){
10937        self.tempTransaction = response.transaction;
10938        var sendParams = {
10939          cashier_language: 'fi',
10940          receipt_id: self.receiptId,
10941          amount: parseInt(data['amount']),
10942          currency: 'EUR',
10943        };
10944        self.showAbort(true);
10945        self.wsConnection.wsSend('Refund', sendParams);
10946      });
10947      setTransaction.fail(function(response){
10948        var responseJson = JSON.parse(response.responseText),
10949        error;
10950        error = responseJson.error || responseJson || 'Hyvityksen lähetys epäonnistui';
10951        self.showErrorMessage(error);
10952        self.wsConnection.wsDisconnect();
10953      });
10954    } catch (error) {
10955      self.paymentTerminalError('Hyvityksen lähetys epäonnistui');
10956      console.log(error);
10957    }
10958  };
10959
10960  self.wsClose = function(){
10961    self.paymentTerminalError('');
10962    self.selectedPaymentTerminal('');
10963    self.wsConnection.wsDisconnect();
10964  };
10965
10966  self.wsSendAbort = function(){
10967    var sendParams = {};
10968    self.wsConnection.wsSend('Abort', sendParams);
10969    self.revertOrRemoveTransactionOnPayment({
10970      transactionId: self.tempTransaction.id,
10971      paymentId: self.currentPayment().id,
10972      origin: self.originatorApp,
10973    });
10974  };
10975
10976  self.setTransactionToPayment = function(data){
10977    return jQuery
10978      .ajax({
10979        url: '/payment_devices/setTransactionToPayment',
10980        method: 'post',
10981        data: data,
10982      });
10983  };
10984
10985  self.updateTransactionData = function(data){
10986    return jQuery
10987      .ajax({
10988        url: '/payment_devices/updateTransactionData',
10989        method: 'post',
10990        data: data,
10991      });
10992  };
10993
10994  self.revertOrRemoveTransactionOnPayment = function(data){
10995    return jQuery
10996      .ajax({
10997        url: '/payment_devices/revertTransactionOnPayment',
10998        method: 'post',
10999        data: data,
11000      });
11001  };
11002
11003  self.deleteTransactionFromPayment = function(data){
11004    return jQuery
11005      .ajax({
11006        url: '/payment_devices/deleteTransactionFromPayment',
11007        method: 'post',
11008        data: data,
11009      });
11010  };
11011
11012  self.getPaymentTerminalTransaction = function(data){
11013    return jQuery
11014      .ajax({
11015        url:
11015 '/payment_devices/getPTTransaction',
11016        method: 'post',
11017        data: data,
11018      });
11019  };
11020
11021  self.wsSendPrint = function(companyData, transactionData){
11022    var receiptImages = generateReceiptImg(transactionData, companyData);
11023    receiptImages.forEach(function(receiptImg){
11024      var sendParams = {
11025        eject: receiptImages.length == 1,
11026        image: {
11027          format: 'png',
11028          data: receiptImg,
11029        },
11030      };
11031      console.log('sendParams',sendParams);
11032      self.wsConnection.wsSend('Print', sendParams);
11033    });
11034  };
11035
11036function generateReceiptImg(transactionData, companyData) {
11037  var receiptData = transactionData.customer_receipt;
11038  var images = [];
11039  // set default height and width, will be changed if got terminal specific values
11040  var maxWidth = 365;
11041  var maxHeight = 1000;
11042  var lineheight = 25;
11043  var font = 'bold 25px Courier New';
11044  var lines = receiptData.split(/\r?\n|\\n/);
11045  lines = mergeWithCompanyData(lines, companyData);
11046
11047  var splitLines = [];
11048  var i;
11049  for (i = 0; i < lines.length; i++) {
11050    var splitLine = fragmentText(lines[i], maxWidth, font);
11051    splitLines.push.apply(splitLines, splitLine);
11052  }
11053
11054  lines = splitLines;
11055
11056  // if refund add empty line and signature line
11057  if (transactionData.transaction_type === 'Refund') {
11058    var signatureLine = getSignatureLine(maxWidth, font);
11059    lines.push('');
11060    lines.push(signatureLine);
11061  }
11062
11063  if (self.wsConnection.connection.terminalInfo().printer) {
11064    var printerInfo = self.wsConnection.connection.terminalInfo().printer;
11065    if (printerInf.max_height) maxHeight = printerInfo.max_height;
11066    if (printerInfo.max_width) maxWidth = printerInfo.max_width;
11067  }
11068
11069  // set canvas height by lines length + some extra for padding
11070  var heightByLines = lineheight * (lines.length + 3);
11071  if (heightByLines < maxHeight) {
11072    var img = generateReceiptBase64(lines, heightByLines, maxWidth, lineheight, font);
11073    images.push(img);
11074  } else {
11075    var chunkSize = Math.round(maxHeight / lineheight);
11076    var i;
11077    for (i = 0; i < lines.length; i += chunkSize) {
11078      var linesChunk = lines.slice(i, i + chunkSize);
11079      var img = generateReceiptBase64(linesChunk, heightByLines, maxWidth, lineheight, font);
11080      images.push(img);
11081    }
11082  }
11083  return images;
11084}
11085
11086function mergeWithCompanyData(lines, companyData) {
11087  var mergeLines = [];
11088  //company name and newline
11089  if('invoice_company_name' in companyData && companyData['invoice_company_name'] != ''){
11090      mergeLines.push(companyData['invoice_company_name']);
11091      mergeLines.push('');
11092  }
11093  //company address
11094  if('invoice_address' in companyData && companyData['invoice_address'] != ''){
11095    mergeLines.push(companyData['invoice_address']);
11096  }
11097  //company zipcode and city if both exist and newline
11098  if('invoice_zipcode' in companyData && companyData['invoice_zipcode'] != ''
11099      &&
11100    'invoice_city' in companyData && companyData['invoice_city'] != ''){
11101    mergeLines.push(companyData['invoice_zipcode']+' '+companyData['invoice_city']);
11102    mergeLines.push('');
11103  }
11104  //company email
11105  if('invoice_email' in companyData && companyData['invoice_email'] != ''){
11106    mergeLines.push(companyData['invoice_email']);
11107  }
11108  //company phone
11109  if('invoice_phone' in companyData && companyData['invoice_phone'] != ''){
11110    mergeLines.push(companyData['invoice_phone']);
11111    mergeLines.push('');
11112  }
11113
11114  mergeLines.push.apply(mergeLines, lines);
11115  return mergeLines;
11116}
11117
11118function fragmentText(text, maxWidth, font) {
11119  var lineCheckCanvas = document.createElement('canvas');
11120  var context = lineCheckCanvas.getContext('2d');
11121  context.font = font;
11122
11123  var words = text.split(' '),
11124    lines = [],
11125    line = '';
11126  if (context.measureText(text).width < maxWidth) {
11127    return [text];
11128  }
11129  while (words.length > 0) {
11130    var split = false;
11131    while (context.measureText(words[0]).width >= maxWidth) {
11132      var tmp = words[0];
11133      words[0] = tmp.slice(0, -1);
11134      if (!split) {
11135        split = true;
11136        words.splice(1, 0, tmp.slice(-1));
11137      } else {
11138        words[1] = tmp.slice(-1) + words[1];
11139      }
11140    }
11141    if (context.measureText(line + words[0]).width < maxWidth) {
11142      line += words.shift() + ' ';
11143    } else {
11144      lines.push(line);
11145      line = '';
11146    }
11147    if (words.length === 0) {
11148      lines.push(line);
11149    }
11150  }
11151
11152  return lines;
11153}
11154
11155function getSignatureLine(maxWidth, font) {
11156  var lineCheckCanvas = document.createElement('canvas');
11157  var context = lineCheckCanvas.getContext('2d');
11158  context.font = font;
11159  var line = '_';
11160  while (context.measureText(line).width <= maxWidth) {
11161    line = line + line;
11162  }
11163  return line;
11164}
11165
11166function generateReceiptBase64(data, height, width, lineheight, font) {
11167  var canvas = document.createElement('canvas');
11168  canvas.height = height;
11169  canvas.width = width;
11170  var ctx = canvas.getContext('2d');
11171  // set canvas background as white
11172  ctx.fillStyle = '#ffffff';
11173  ctx.fillRect(0, 0, canvas.width, canvas.height);
11174
11175  ctx.font = font;
11176  var x = 10;
11177  var y = 50;
11178  // set font color to black
11179  ctx.fillStyle = 'black';
11180  // loop throught receipt lines and them to canvas
11181  var i;
11182  for (i = 0; i < data.length; i++) ctx.fillText(data[i], x, y + i * lineheight);
11183
11184  // set canvas base64 blob as image to return
11185  return canvas.toDataURL('image/png').split(';base64,')[1];
11186}
11187
11188};
11189;var ServiceSubscriptionVM = function() {
11190    var self = this;
11191    self.defaults = ko.observableArray([]);
11192    self.chosenService = ko.observable();
11193    self.activeSubscription = null;
11194    self.allowEdit = ko.observable(false);
11195    self.data = {
11196        id: ko.observable(null),
11197        service_name: ko.observable(),
11198        service_description: ko.observable(),
11199        type: ko.observable(),
11200        company_id: ko.observable(),
11201        quantity: ko.observable(),
11202        amount: ko.observable('0.00'),
11203        vat: ko.observable(24),
11204        created: ko.observable()
11205    };
11206
11207    self.clearDataExcludingId = function(){
11208
11209        self.data.service_name(undefined);
11210        self.data.service_description(undefined);
11211        self.data.type(undefined);
11212        self.data.quantity(1);
11213        self.data.amount('0.00');
11214        self.data.vat(24);
11215    }
11216
11217    self.emptyData = function(options){
11218
11219        if(options.clearCompanyId){
11220            self.data.company_id(undefined);
11221        }
11222        self.clearDataExcludingId();
11223        self.data.id(null);
11224        self.data.created(undefined);
11225        
11226        self.chosenService(undefined);
11227        self.activeSubscription = null;
11228        self.setAllowEditFalse();
11229    }
11230
11231    self.setAllowEditTrue = function(){
11232      self.allowEdit(true);
11233    }
11234    self.setAllowEditFalse = function(){
11235      self.allowEdit(false);
11236    }
11237
11238    self.setDefaults = function(defaults){
11239      self.defaults(defaults);
11240    }
11241
11242    self.revertChanges = function(){
11243      self.setAllowEditFalse();
11244      self.resetActiveSubscription();
11245    }
11246
11247    self.setActiveSubscription = function(subscription){
11248      self.activeSubscription = subscription;
11249
11250      var defaultValues = self.getDefaultsByDescription(subscription.service_description);
11251      if(defaultValues){
11252        self.chosenService(defaultValues);
11253      }
11254
11255      self.setData(subscription);
11256    }
11257
11258    self.resetActiveSubscription = function(){
11259      self.setData(self.activeSubscription);
11260    }
11261
11262    self.getDefaultsByDescription = function(desc){
11263      
11264      return self.defaults().find(defaults => 
11265        defaults.description === desc);
11266
11267    }
11268
11269    self.isActive = ko.pureComputed(function(){
11270        return self.data.created() && self.data.id();
11271    })
11272
11273    self.status = ko.pureComputed(function(){
11274        return self.data.created() && self.data.id() ? 'Veloitus Aktiivinen' : 'Ei Aktiivinen';
11275    })
11276
11277    self.setCompanyId = function(companyId){
11278        self.data.company_id(companyId)
11279    }
11280
11281    self.setDefaultsValues = function(){
11282
11283        if(!self.chosenService()){
11284            self.clearDataExcludingId();
11285            return;
11286        }
11287        if(self.chosenService().description === self.data.service_description()){
11288            return;
11289        }
11290
11291        var qty = self.chosenService().quantity ? self.chosenService().quantity : 1;
11292
11293        self.data.type(self.chosenService().type);
11294        self.data.service_description(self.chosenService().description)
11295        self.data.quantity(qty);
11296        self.setAmount(self.chosenService().monthly_fee);
11297        self.data.vat(self.chosenService().vat)
11298        self.data.service_name(self.chosenService().name)
11299        return;
11300    }
11301
11302    self.setData = function(subscription){
11303        if(!subscription || typeof subscription == 'undefined'){
11304            window.alert('kuukausiveloituksen tiedot puutteelliset. Ota yhteyttä dev-tiimiin.')
11305            return;
11306        }
11307        self.data.id(subscription.id);
11308        self.data.service_name(subscription.service_name ? subscription.service_name : '');
11309        self.data.service_description(subscription.service_description ? subscription.service_description: '')
11310        self.data.type(subscription.type ? subscription.type : '');
11311        self.data.quantity(subscription.quantity ? subscription.quantity : 1);
11312        self.setAmount(subscription.amount);
11313        self.data.vat(subscription.vat)
11314        self.data.created(subscription.created);
11315    }
11316
11317    self.setAmount = function(value){
11318        if(!value || typeof value == 'undefined'){
11319            self.data.amount('0,00');
11320        }
11321        self.data.amount(value.toFixed(2).replace('.', ','));
11322    }
11323
11324    self.createServiceSubscription = function(){
11325        
11326        if(!self.validateSaveOrUpdate()){
11327            return;
11328        }
11329
11330        global.showLoadingDialog('Ladataan...');
11331
11332        jQuery
11333          .ajax({
11334            url: 'asiakkuudet/createServiceSubscription',
11335            method: 'post',
11336            data: {data: ko.toJS(self.data)}
11337          })
11338          .then(function(success) {
11339            global.show_message(success);
11340            self.setActiveSubscription(success.data);
11341            self.setAllowEditFalse();
11342          })
11343          .fail(function(error) {
11344            global.show_message(error.responseJSON);
11345          })
11346          .always(function(){
11347            global.close_loading_dialog();
11348          })
11349      }
11350
11351      self.deleteServiceSubscription = function(){
11352        if(!window.confirm('Haluatko varmasti poistaa kuukausiveloituksen? \n\nHUOM. Kuukausiveloituksen poisto EI poista palvelua käytöstä!')){
11353          return;
11354        }
11355
11356        global.showLoadingDialog('Ladataan...');
11357
11358        jQuery
11359          .ajax({
11360            url: 'asiakkuudet/deleteServiceSubscription',
11361            method: 'post',
11362            data: {
11363                id: self.data.id(),
11364                company_id: self.data.company_id()
11365            }
11366          })
11367          .then(function(success) {
11368            global.show_message(success);
11369            self.emptyData({clearCompanyId: false});
11370          })
11371          .fail(function(error) {
11372            global.show_message(error.responseJSON);
11373          })
11374          .always(function(){
11375            global.close_loading_dialog();
11376          })
11377      }
11378
11379      self.editServiceSubscription = function(){
11380
11381        if(!self.validateSaveOrUpdate()){
11382          return;
11383        }
11384
11385        global.showLoadingDialog('Ladataan...');
11386
11387        jQuery
11388          .ajax({
11389            url: 'asiakkuudet/editServiceSubscription',
11390            method: 'post',
11391            data: {data: ko.toJS(self.data)}
11392          })
11393          .then(function(success) {
11394            global.show_message(success);
11395            self.setActiveSubscription(success.data);
11396            self.setAllowEditFalse();
11397          })
11398          .fail(function(error) {
11399            global.show_message(error.responseJSON);
11400          })
11401          .always(function(){
11402            global.close_loading_dialog();
11403          })
11404      }
11405    
11406      self.validateSaveOrUpdate = function(){
11407        if(!self.data.type()){
11408            window.alert('valitse veloituksen tyyppi')
11409            return false;
11410        }
11411        if(!self.data.amount()){
11412            window.alert('anna veloituksen hinta')
11413            return false;
11414        }
11415
11416        if(!/^\d+$|^\d+\,?\d+$/.test(self.data.amount())){
11417            window.alert('anna veloituksen hinta muodossa 12,00')
11418            return false;
11419        }
11420
11421        if(!self.data.quantity()){
11422            window.alert('anna veloituksen kappalemäärä');
11423            return false;
11424        }
11425        if(!self.data.company_id()){
11426            window.alert('yrityksen id puuttuu, veloitusta ei voida päivittää. Ota yhteyttä kehitystiimiin.');
11427            return false;
11428        }
11429
11430        return true;
11431      }
11432
11433}
11434
11435;var CompanyDocumentsVM = function() {
11436  var self = this;
11437
11438  self.types = [
11439    {type: 'iv_payment_terminal_contract', name: 'IV maksupäätesopimus (allekirjoitettu versio)'},
11440    {type: 'iv_service_contract', name: 'IV palvelusopimus (Allekirjoitettu versio)'},
11441    {type: 'kredinor_invoicing_contract', name: 'Kredinor laskupalvelusopimus'},
11442    {type: 'kredinor_power_of_attorney', name: 'Kredinor valtakirja'},
11443    {type: 'contact_person_payment_failure', name: 'Maksuhäiriöt, vastuuhenkilöt (IV haku)'},
11444    {type: 'company_payment_failure', name: 'Maksuhäiriöt, yritys (IV haku)'},
11445    {type: 'other_document', name: 'Muu dokumentti'},
11446    {type: 'traficom_contract', name: 'Ajoneuvotietohaku-palvelukuvaus'},
11447    {type: 'traficom_permit', name: 'Traficom lupa'},
11448    {type: 'forclosure_payment_denial', name: 'Ulosoton maksukielto'},
11449    {type: 'forclosure_payment_denial_cancelation', name: 'Ulosoton maksukiellon peruutus'},
11450    {type: 'forclosure_investigation_request', name: 'Ulosoton selvityspyyntö'},
11451    {type: 'company_information_report', name: 'Yritystietoraportti (laaja)'},
11452    {type: 'company_information_report_alfa', name: 'Yritystietoraportti (Rating Alfa)'},
11453    {type: 'company_information_report_short', name: 'Yritystietoraportti (suppea)'},
11454    {type: 'follow_link_service_contract', name: 'Lisäpalvelun käyttöönottosopimus: Seurantalinkki'},
11455    {type: 'post_marketing_service_contract', name: 'Lisäpalvelun käyttöönottosopimus: Jälkimarkkinointi'},
11456    {type: 'accounting_service_contract', name: 'Lisäpalvelun käyttöönottosopimus: Kirjanpitointegraatio'},
11457    {type: 'shifts_service_contract', name: 'Lisäpalvelun käyttöönottosopimus: Työajanseruanta'},
11458    {type: 'payment_link_service_contract', name: 'Lisäpalvelun käyttöönottosopimus: Maksulinkki'},
11459    {type: 'payment_link_kyc_accept', name: 'Maksulinkki kyc hyväksyntä'},
11460    {type: 'company_pep_document', name: 'Yrityksen pep ja pakotteet'},
11461    {type: 'company_trade_reg_extract', name: 'Yrityksen kaupparekisteriote'},
11462  ];
11463
11464  self.typeOptions = ko.observableArray(self.types.sort(function(a, b){return a.name > b.name ? 1 : -1}));
11465  // add categories here if needed (also add in backend)
11466
11467  self.signDocTypes = [
11468    {type: 'trafi', name: 'Ajoneuvotietohaku-palvelukuvaus'},
11469    {type: 'kredinor', name: 'Kredinor laskupalvelusopimus'},
11470    {type: 'debt_collection_power_of_attorney', name: 'Kredinor valtakirja'},
11471    {type: 'follow_link', name: 'Lisäpalvelun käyttöönottosopimus: Seurantalinkki'},
11472    {type: 'post_marketing', name: 'Lisäpalvelun käyttöönottosopimus: Jälkimarkkinointi'},
11473    {type: 'accounting', name: 'Lisäpalvelun käyttöönottosopimus: Kirjanpitointegraatio'},
11474    {type: 'shifts', name: 'Lisäpalvelun käyttöönottosopimus: Työajanseruanta'},
11475    {type: 'payment_link', name: 'Lisäpalvelun käyttöönottosopimus: Maksulinkki'},
11476  ];
11477
11478  self.signableDocuments = ko.observableArray(self.signDocTypes.sort(function(a, b){return a.name > b.name ? 1 : -1}));
11479
11480  // Create the observale arrays
11481  self.documents = ko.observableArray([]);
11482  self.typeFilter = ko.observable('');
11483  self.formVisible = ko.observable(false);
11484
11485  self.newDocDate = ko.observable('');
11486  self.newDocFileName = ko.observable('');
11487  self.newDocFile = ko.observable(null);
11488  self.newDocType = ko.observable('');
11489  self.newDocTempName = ko.observable('');
11490
11491  self.companyId = ko.observable(null);
11492
11493  self.unsignedDocuments = ko.observableArray([]);
11494  self.contactPersonEmail = ko.observable('');
11495  self.selectedSignableDocument = ko.observable('');
11496
11497  self.setUnsignedDocumentsData = function(data, email){
11498    self.unsignedDocuments([]);
11499    self.unsignedDocuments(data);
11500    if(email){
11501      self.contactPersonEmail(email);
11502    }
11503  }
11504
11505  self.setData = function(documents, companyId){
11506    // empty the observable arrays
11507    self.documents([]);
11508    self.typeFilter('');
11509    self.formVisible(false);
11510
11511    self.newDocDate('');
11512    self.newDocFileName('');
11513    self.newDocFile(null);
11514    self.newDocType('');
11515    self.newDocTempName('');
11516  
11517    self.companyId(companyId)
11518
11519    if(!documents && !(documents instanceof Array)){
11520      return;
11521    }
11522    documents.forEach(document => {
11523
11524      self.addOne(document)
11525    });
11526
11527    self.sort();
11528  }
11529
11530  self.sort = function(){
11531    self.documents.sort((a, b)=>{
11532      let aParts = a.doc_date.split('.');
11533      let bParts = b.doc_date.split('.');
11534
11535      if(aParts[2] !== bParts[2]){
11536        return bParts[2] - aParts[2];
11537      }
11538      if(aParts[1] !== bParts[1]){
11539        return bParts[1] - aParts[1];
11540      }
11541      if(aParts[0] !== bParts[0]){
11542        return bParts[0] - aParts[0];
11543      }
11544
11545    })
11546  }
11547
11548  self.typeFilter.subscribe((value) => {
11549    self.documents().forEach((document)=>{
11550      if(!value){
11551        document.visible(true);
11552        return;
11553      }
11554      if(value === document.type){
11555        document.visible(true);
11556        return;
11557      }
11558      document.visible(false);
11559    })
11560  });
11561
11562  self.addOne = function(document){
11563  
11564    let data = {
11565      id: document.id ? document.id : null,
11566      company_id: document.company_id ? document.company_id : null,
11567      doc_name: document.doc_name ? document.doc_name : null,
11568      type: document.type ? document.type : null,
11569      typeTranslation: document.type_translation ? document.type_translation : '',
11570      doc_date: document.doc_date ? document.doc_date : null,
11571      doc_type: document.doc_type ? document.doc_type : null,
11572      added_by: document.added_by ? document.added_by : '',
11573      created: document.created ? document.created : null,
11574      visible: ko.observable(true)
11575    }
11576    if(!self.validate(data)){
11577      return;
11578    }
11579
11580    self.documents.push(data);
11581  }
11582
11583  self.removeOne = function(item){
11584    self.documents.remove(item);
11585  }
11586
11587  self.validate = function(data){
11588
11589    return !!data.id && !!data.type && !!data.doc_name && !!data.doc_date && !!data.id && data.company_id == self.companyId();
11590  }
11591
11592  
11593  self.addDocument = function(){
11594
11595    global.showLoadingDialog('Ladataan...');
11596
11597    let data = new FormData()
11598    data.append('file', self.newDocFile());
11599    data.append('docDate', self.newDocDate())
11600    data.append('docType', self.newDocType())
11601    data.append('client_company_id', self.companyId())
11602    data.append('tempName', self.newDocTempName())
11603
11604    jQuery
11605      .ajax({
11606        url: 'asiakkuudet/addDocument',
11607        method: 'post',
11608        data: data,
11609        contentType: false,
11610        processData: false,
11611      })
11612      .then(function(success) {
11613        global.show_message(success);
11614        self.hideForm()
11615        self.addOne(success.data);
11616        self.sort();
11617      })
11618      .fail(function(error) {
11619        global.show_message(error.responseJSON);
11620      })
11621      .always(function(){
11622        global.close_loading_dialog();
11623      })
11624
11625  }
11626
11627  self.addSignableDocument = function(){
11628
11629    global.showLoadingDialog('Ladataan...');
11630
11631    let data = {
11632      type: self.selectedSignableDocument(),
11633      client_company_id: self.companyId(),
11634    }
11635
11636    jQuery
11637      .ajax({
11638        url: 'asiakkuudet/addUnsignedDocument',
11639        method: 'post',
11640        data: data,
11641      })
11642      .then(function(success) {
11643        global.show_message(success);
11644        self.setUnsignedDocumentsData(success.data, false);
11645      })
11646      .fail(function(error) {
11647        global.show_message(error.responseJSON);
11648      })
11649      .always(function(){
11650        global.close_loading_dialog();
11651        self.selectedSignableDocument('');
11652      })
11653
11654  }
11655
11656  self.removeSignableDocument = function(id){
11657
11658    global.showLoadingDialog('Ladataan...');
11659
11660    let data = {
11661      id: id,
11662      client_company_id: self.companyId(),
11663    }
11664
11665    jQuery
11666      .ajax({
11667        url: 'asiakkuudet/deleteUnsignedDocument',
11668        method: 'post',
11669        data: data,
11670      })
11671      .then(function(success) {
11672        global.show_message(success);
11673        var data = success.data ? success.data : [];
11674        self.setUnsignedDocumentsData(data, false);
11675      })
11676      .fail(function(error) {
11677        global.show_message(error.responseJSON);
11678      })
11679      .always(function(){
11680        global.close_loading_dialog();
11681      })
11682
11683  }
11684
11685  self.getDocument = function(item) {
11686    let url = '/asiakkuudet/getDocument/' + item.id;
11687    window.open(url, '_blank');
11688  };
11689
11690  self.deleteDocument = function(item){
11691    
11692    if(!window.confirm('Haluatko varmasti poistaa dokumentin ' + item.doc_name + ' (' + item.typeTranslation + ') ?')){
11693      return;
11694    }
11695
11696    global.showLoadingDialog('Poistetaan...');
11697    jQuery
11698      .ajax({
11699        url: '/asiakkuudet/deleteDocument/' + item.id,
11700        method: 'post',
11701        contentType: false,
11702        processData: false,
11703      })
11704      .then(function(success) {
11705        global.show_message(success);
11706        self.removeOne(item);
11707      })
11708      .fail(function(error) {
11709        global.show_message(error.responseJSON);
11710      })
11711      .always(function(){
11712        global.close_loading_dialog();
11713      })
11714  }
11715
11716
11717  self.sendSigningRequest = function(){
11718
11719    if(!window.confirm('Varmista, että asiakkaan tiedot on syötetty oikein asiakaskortille ja tiedot näkyvät sopimuksella avaamalla ja tarkastamalla sopimus')){
11720      return;
11721    }
11722
11723    global.showLoadingDialog('Ladataan...');
11724
11725    let data = new FormData()
11726    data.append('email', self.contactPersonEmail());
11727
11728
11729    jQuery
11730      .ajax({
11731        url: 'asiakkuudet/sendSigningRequest/' + self.companyId(),
11732        method: 'post',
11733        data: data,
11734        contentType: false,
11735        processData: false,
11736      })
11737      .then(function(success) {
11738        global.show_message(success);
11739      })
11740      .fail(function(error) {
11741        global.show_message(error.responseJSON);
11742      })
11743      .always(function(){
11744        global.close_loading_dialog();
11745      })
11746  }
11747
11748  self.showForm = function(){
11749    self.formVisible(true);
11750  }
11751
11752  self.hideForm = function(){
11753    self.newDocDate('');
11754    self.newDocType('');
11755    self.newDocFile(null);
11756    self.newDocFileName('');
11757    self.newDocTempName('');
11758    self.formVisible(false);
11759  }
11760
11761
11762  self.dragDropHandler = function(item, ev) {
11763
11764    let dropArea = $('#drop_zone');
11765    dropArea.removeClass('highlight');
11766    ev.preventDefault();
11767  
11768    if (ev.originalEvent.dataTransfer.items) {
11769      // Use DataTransferItemList interface to access the file(s)
11770      if(ev.originalEvent.dataTransfer.items.length !== 1){
11771        window.alert('Voit ladata ainoastaan yhden tiedoston kerrallaan.');
11772        return;
11773      }
11774
11775      [...ev.originalEvent.dataTransfer.items].forEach((item, i) => {
11776
11777        if (item.kind === "file") {
11778          const file = item.getAsFile();
11779          self.newDocFile(file)
11780          self.newDocFileName(file.name)
11781        }
11782      });
11783    } else {
11784      
11785      window.alert('Jokin meni vikaan. Yritä lisätä tiedosto painikkeen kautta.')
11786    }
11787  }
11788  
11789  self.processDocument = function(_, evt){
11790    let file = evt.target.files[0];
11791    if(file && file.name){
11792      self.newDocFile(file)
11793      self.newDocFileName(file.name)
11794    }
11795  }
11796
11797
11798  self.addElementBinding = function(){
11799
11800    let dropArea = $('#drop_zone');
11801
11802    function preventDefaults (e) {
11803      e.preventDefault()
11804      e.stopPropagation()
11805    };
11806
11807    dropArea.on('dragenter dragover', function(e){
11808      preventDefaults(e)
11809      dropArea.addClass('highlight')
11810    })
11811
11812    dropArea.on('dragleave', function(e){
11813      preventDefaults(e)
11814      dropArea.removeClass('highlight')
11815    })
11816
11817  }
11818}
11819
11820ko.bindingHandlers.company_doc_datepicker = {
11821  init: function(element, valueAccessor, allBindings){
11822
11823    var options = valueAccessor(),
11824        value = ko.unwrap(options);
11825
11826    $(element).datepicker({
11827      format: 'dd.mm.yyyy',
11828      language: 'fi-FI',
11829      weekStart: 1,
11830      todayHighlight: true,
11831      startDate: '-180m',
11832      todayBtn: 'linked',
11833      forceParse: false
11834    });
11835
11836    $(element).on('changeDate', function(){
11837      $(element).datepicker('hide');
11838    })
11839  }
11840};
11841
11842;var CompanyRestrictionsVM = function() {
11843var self = this;
11844
11845  self.companyId = ko.observable(null);
11846  self.restrictions = ko.observableArray([]);
11847  
11848  self.showHeader = ko.observable(false);
11849  self.showRestrictions = ko.observable(false);
11850  self.deleteButtons = ko.observableArray([]);
11851
11852
11853  self.toggleRestrictions = function(){
11854    self.showRestrictions(!self.showRestrictions());
11855  }
11856
11857  self.setData = function(companyId, restrictions){
11858
11859    self.restrictions([]);
11860    self.companyId(companyId);
11861    self.deleteButtons([]);
11862    self.showHeader(false);
11863
11864    if(!restrictions && !(restrictions instanceof Array)){
11865      return;
11866    }
11867
11868    restrictions.forEach(function(item){
11869        if(self.validate(item)){
11870            if(!self.deleteButtons().find(function(i){return i.type === item.type})){
11871              self.deleteButtons.push({reason: item.reason, type: item.type});
11872            }
11873
11874            self.restrictions.push(item);
11875        }
11876    });
11877
11878    if(self.restrictions().length > 0){
11879      self.showHeader(true);
11880    } else {
11881      self.showHeader(false);
11882    }
11883
11884  }
11885
11886  self.validate = function(data){
11887    return !!data.id && !!data.service && !!data.reason && !!data.date && !!data.origValue && data.company_id == self.companyId();
11888  }
11889
11890  self.restrictionExists = function(field){
11891    let filtered = self.restrictions().filter(function(item){
11892      return item.field_name == field;
11893    })
11894
11895    if(filtered.length > 0){
11896      return true;
11897    }
11898    return false;
11899  }
11900  
11901  self.deleteRestrictions = function(type, successCallback){
11902    if(!window.confirm('Haluatko varmasti palveluestot?')){
11903      return;
11904    }
11905    
11906    let client_company_id = self.companyId();
11907    
11908    if(!client_company_id){
11909        window.alert('Virheellinen yritys id!');
11910        return;
11911    }
11912
11913    global.showLoadingDialog('Ladataan...');
11914
11915    jQuery
11916      .ajax({
11917        url: 'asiakkuudet/deleteCompanyRestrictions/'+client_company_id,
11918        method: 'post',
11919        data: {type: type},
11920        dataType: 'json',
11921      })
11922      .done(function(responseJSON) {
11923        global.show_message({type: 'success', title: 'Valmis', text: 'Esto poistettu, päivitetään asiakkuuskortti'});
11924        console.log(responseJSON);
11925        successCallback(responseJSON);
11926      })
11927      .fail(function(error) {
11928        global.show_message(error.responseJSON);
11929      })
11930      .always(function(){
11931        global.close_loading_dialog();
11932      })
11933
11934  }
11935
11936  self.getRestrictions = function(companyId)
11937  {
11938
11939    // reset some data
11940    self.restrictions([]);
11941    self.showHeader(false);
11942    self.showRestrictions(false);
11943    if(!companyId){
11944        return;
11945    }
11946
11947    jQuery
11948      .ajax({
11949        url: 'asiakkuudet/getCompanyRestrictions/'+companyId,
11950        method: 'get',
11951      })
11952      .then(function(success) {
11953        self.setData(companyId, success.data);
11954      })
11955      .fail(function(error) {
11956        console.log('Could not get company restrictions')
11957      });
11958
11959  }
11960
11961  self.removeRow = function(item){
11962
11963    self.restrictions.remove(item);
11964  }
11965  
11966}
11967
11968;var CompanyMessagingDetailsVM = function() {
11969  var self = this;
11970
11971  // add categories here if needed (also add in backend)
11972  self.categories = ['sms', 'email', 'warning'];
11973
11974  // Create the observale arrays
11975  self.categories.forEach((cat)=>{
11976    self[cat] = ko.observableArray([]);
11977  })
11978
11979  self.companyId = ko.observable(null);
11980
11981  self.setData = function(companyId, details){
11982    // empty the observable arrays
11983    self.categories.forEach((cat)=>{
11984      self[cat]([]);
11985    })
11986  
11987    self.companyId(companyId)
11988
11989    if(!details && !(details instanceof Array)){
11990      return;
11991    }
11992    details.forEach(detail => {
11993
11994      self.addOne(detail)
11995    });
11996    
11997    self.categories.forEach((cat)=>{
11998      self.sort(cat);
11999    })
12000
12001  }
12002
12003  self.sort = function(category){
12004    self[category].sort((a, b)=>{
12005      return a.order - b.order;
12006    })
12007  }
12008
12009  self.addOne = function(details){
12010    // this is for if someone sets the order to 0 in the backend it would not show in client
12011    if(details.order === 0){
12012      details.order = 10000;
12013    }
12014    let data = {
12015      id: details.id ? ko.observable(details.id) : null,
12016      company_id: details.company_id ? details.company_id : null,
12017      category: details.category ? details.category : null,
12018      type: details.type ? ko.observable(details.type) : null,
12019      value: details.value ? ko.observable(details.value) : null,
12020      order: (details.order || details.order === 0) ? details.order : null,
12021      name: details.name ? ko.observable(details.name) : null,
12022      description: details.description ? ko.observable(details.description) : null,
12023      edit: ko.observable(false)
12024    }
12025    if(!self.validate(data)){
12026      return;
12027    }
12028
12029    self[data.category].push(data);
12030  }
12031
12032  self.updateOne = function(details){
12033    // this is for if someone sets the order to 0 in the backend it would not show in client
12034    if(details.order === 0){
12035      details.order = 10000;
12036    }
12037    let data = {
12038      id: details.id ? ko.observable(details.id) : null,
12039      company_id: details.company_id ? details.company_id : null,
12040      category: details.category ? details.category : null,
12041      type: details.type ? ko.observable(details.type) : null,
12042      value: details.value ? ko.observable(details.value) : null,
12043      order: details.order ? details.order : null,
12044      name: details.name ? ko.observable(details.name) : null,
12045      description: details.description ? ko.observable(details.description) : null,
12046      edit: ko.observable(false)
12047    }
12048    if(!self.validate(data)){
12049      // console.log(data)
12050      return;
12051    }
12052
12053    let oldItems = self[data.category]();
12054    let oldItem = oldItems.find((item)=>{
12055      return item.id === data.id;
12056    })
12057    self[data.category].replace(oldItem, data);
12058    
12059  }
12060
12061  self.validate = function(data){
12062
12063    const isValidCategory = data.category && (self.categories.indexOf(data.category) !== -1);
12064    // const value = isValidCategory && !!data.id && !!data.type && !!data.value && !!data.order && !!data.name && data.company_id == self.companyId();
12065    // console.log('validate', value, data)
12066    return isValidCategory && !!data.id && !!data.type && !!data.value && !!data.order && !!data.name && !!data.description && data.company_id == self.companyId();
12067  }
12068
12069  self.allowEdit = function(detail, value){
12070    //console.log(detail);
12071    if(value){
12072      detail.oldValue = detail.value();
12073    } else {
12074      detail.value(detail.oldValue)
12075    }
12076    detail.edit(value);
12077  }
12078  
12079  self.updateValue = function(item, context, action){
12080    // console.log(item, context, action);
12081    if(action === 'delete' && !window.confirm('Haluatko varmasti poistaa rivin?')){
12082      return;
12083    }
12084    global.showLoadingDialog('Ladataan...');
12085
12086    let data = ko.toJS(item);
12087    data.action = action;
12088    data.client_company_id = self.companyId();
12089
12090    jQuery
12091      .ajax({
12092        url: 'asiakkuudet/modifyCompanyMessagingDetail',
12093        method: 'post',
12094        data: data
12095      })
12096      .then(function(success) {
12097        global.show_message(success);
12098        switch(action){
12099          case 'edit':
12100            self.updateOne(success.data);
12101          case 'create':
12102            self[context].remove(item);
12103            self.addOne(success.data);
12104            self.sort(context);
12105          case 'delete':
12106            self.removeRow(item, context)
12107        }
12108        
12109      })
12110      .fail(function(error) {
12111        global.show_message(error.responseJSON);
12112      })
12113      .always(function(){
12114        global.close_loading_dialog();
12115      })
12116
12117  }
12118
12119  self.addEmpty = function(category){
12120    let data = {
12121      id: ko.observable(null),
12122      company_id: self.companyId(),
12123      type: ko.observable(''),
12124      value: ko.observable(''),
12125      name: ko.observable(''),
12126      description: ko.observable(''),
12127      edit: ko.observable(true)
12128    }
12129    self[category].push(data);
12130  }
12131
12132  self.removeRow = function(item, context){
12133
12134    self[context].remove(item);
12135  }
12136
12137  self.setDropDownOption = function(detail, options){
12138    //console.log(detail, options);
12139
12140    var option = options instanceof Array ? options.filter((item)=>{
12141      return item.type === detail.type()
12142    }) : false;
12143
12144    if(!option || option.length !== 1){
12145      return;
12146    }
12147
12148    ko.isObservable(detail.name) && detail.name(option[0].name)
12149    ko.isObservable(detail.description) && detail.description(option[0].description)
12150
12151  }
12152  
12153}
12154;//     Underscore.js 1.5.1
12155//     http://underscorejs.org
12156//     (c) 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
12157//     Underscore may be freely distributed under the MIT license.
12158!function(){var n=this,t=n._,r={},e=Array.prototype,u=Object.prototype,i=Function.prototype,a=e.push,o=e.slice,c=e.concat,l=u.toString,f=u.hasOwnProperty,s=e.forEach,p=e.map,v=e.reduce,h=e.reduceRight,d=e.filter,g=e.every,m=e.some,y=e.indexOf,b=e.lastIndexOf,x=Array.isArray,_=Object.keys,w=i.bind,j=function(n){return n instanceof j?n:this instanceof j?(this._wrapped=n,void 0):new j(n)};"undefined"!=typeof exports?("undefined"!=typeof module&&module.exports&&(exports=module.exports=j),exports._=j):n._=j,j.VERSION="1.5.1";var A=j.each=j.forEach=function(n,t,e){if(null!=n)if(s&&n.forEach===s)n.forEach(t,e);else if(n.length===+n.length){for(var u=0,i=n.length;i>u;u++)if(t.call(e,n[u],u,n)===r)return}else for(var a in n)if(j.has(n,a)&&t.call(e,n[a],a,n)===r)return};j.map=j.collect=function(n,t,r){var e=[];return null==n?e:p&&n.map===p?n.map(t,r):(A(n,function(n,u,i){e.push(t.call(r,n,u,i))}),e)};var E="Reduce of empty array with no initial value";j.reduce=j.foldl=j.inject=function(n,t,r,e){var u=arguments.length>2;if(null==n&&(n=[]),v&&n.reduce===v)return e&&(t=j.bind(t,e)),u?n.reduce(t,r):n.reduce(t);if(A(n,function(n,i,a){u?r=t.call(e,r,n,i,a):(r=n,u=!0)}),!u)throw new TypeError(E);return r},j.reduceRight=j.foldr=function(n,t,r,e){var u=arguments.length>2;if(null==n&&(n=[]),h&&n.reduceRight===h)return e&&(t=j.bind(t,e)),u?n.reduceRight(t,r):n.reduceRight(t);var i=n.length;if(i!==+i){var a=j.keys(n);i=a.length}if(A(n,function(o,c,l){c=a?a[--i]:--i,u?r=t.call(e,r,n[c],c,l):(r=n[c],u=!0)}),!u)throw new TypeError(E);return r},j.find=j.detect=function(n,t,r){var e;return O(n,function(n,u,i){return t.call(r,n,u,i)?(e=n,!0):void 0}),e},j.filter=j.select=function(n,t,r){var e=[];return null==n?e:d&&n.filter===d?n.filter(t,r):(A(n,function(n,u,i){t.call(r,n,u,i)&&e.push(n)}),e)},j.reject=function(n,t,r){return j.filter(n,function(n,e,u){return!t.call(r,n,e,u)},r)},j.every=j.all=function(n,t,e){t||(t=j.identity);var u=!0;return null==n?u:g&&n.every===g?n.every(t,e):(A(n,function(n,i,a){return(u=u&&t.call(e,n,i,a))?void 0:r}),!!u)};var O=j.some=j.any=function(n,t,e){t||(t=j.identity);var u=!1;return null==n?u:m&&n.some===m?n.some(t,e):(A(n,function(n,i,a){return u||(u=t.call(e,n,i,a))?r:void 0}),!!u)};j.contains=j.include=function(n,t){return null==n?!1:y&&n.indexOf===y?n.indexOf(t)!=-1:O(n,function(n){return n===t})},j.invoke=function(n,t){var r=o.call(arguments,2),e=j.isFunction(t);return j.map(n,function(n){return(e?t:n[t]).apply(n,r)})},j.pluck=function(n,t){return j.map(n,function(n){return n[t]})},j.where=function(n,t,r){return j.isEmpty(t)?r?void 0:[]:j[r?"find":"filter"](n,function(n){for(var r in t)if(t[r]!==n[r])return!1;return!0})},j.findWhere=function(n,t){return j.where(n,t,!0)},j.max=function(n,t,r){if(!t&&j.isArray(n)&&n[0]===+n[0]&&n.length<65535)return Math.max.apply(Math,n);if(!t&&j.isEmpty(n))return-1/0;var e={computed:-1/0,value:-1/0};return A(n,function(n,u,i){var a=t?t.call(r,n,u,i):n;a>e.computed&&(e={value:n,computed:a})}),e.value},j.min=function(n,t,r){if(!t&&j.isArray(n)&&n[0]===+n[0]&&n.length<65535)return Math.min.apply(Math,n);if(!t&&j.isEmpty(n))return 1/0;var e={computed:1/0,value:1/0};return A(n,function(n,u,i){var a=t?t.call(r,n,u,i):n;a<e.computed&&(e={value:n,computed:a})}),e.value},j.shuffle=function(n){var t,r=0,e=[];return A(n,function(n){t=j.random(r++),e[r-1]=e[t],e[t]=n}),e};var F=function(n){return j.isFunction(n)?n:function(t){return t[n]}};j.sortBy=function(n,t,r){var e=F(t);return j.pluck(j.map(n,function(n,t,u){return{value:n,index:t,criteria:e.call(r,n,t,u)}}).sort(function(n,t){var r=n.criteria,e=t.criteria;if(r!==e){if(r>e||r===void 0)return 1;if(e>r||e===void 0)return-1}return n.index<t.index?-1:1}),"value")};var k=function(n,t,r,e){var u={},i=F(null==t?j.identity:t);return A(n,function(t,a){var o=i.call(r,t,a,n);e(u,o,t)}),u};j.groupBy=function(n,t,r){return k(n,t,r,function(n,t,r){(j.has(n,t)?n[t]:n[t]=[]).push(r)})},j.countBy=function(n,t,r){return k(n,t,r,function(n,t){j.has(n,t)||(n[t]=0),n[t]++})},j.sortedIndex=function(n,t,r,e){r=null==r?j.identity:F(r);for(var u=r.call(e,t),i=0,a=n.length;a>i;){var o=i+a>>>1;r.call(e,n[o])<u?i=o+1:a=o}return i},j.toArray=function(n){return n?j.isArray(n)?o.call(n):n.length===+n.length?j.map(n,j.identity):j.values(n):[]},j.size=function(n){return null==n?0:n.length===+n.length?n.length:j.keys(n).length},j.first=j.head=j.take=function(n,t,r){return null==n?void 0:null==t||r?n[0]:o.call(n,0,t)},j.initial=function(n,t,r){return o.call(n,0,n.length-(null==t||r?1:t))},j.last=function(n,t,r){return null==n?void 0:null==t||r?n[n.length-1]:o.call(n,Math.max(n.length-t,0))},j.rest=j.tail=j.drop=function(n,t,r){return o.call(n,null==t||r?1:t)},j.compact=function(n){return j.filter(n,j.identity)};var R=function(n,t,r){return t&&j.every(n,j.isArray)?c.apply(r,n):(A(n,function(n){j.isArray(n)||j.isArguments(n)?t?a.apply(r,n):R(n,t,r):r.push(n)}),r)};j.flatten=function(n,t){return R(n,t,[])}
12158,j.without=function(n){return j.difference(n,o.call(arguments,1))},j.uniq=j.unique=function(n,t,r,e){j.isFunction(t)&&(e=r,r=t,t=!1);var u=r?j.map(n,r,e):n,i=[],a=[];return A(u,function(r,e){(t?e&&a[a.length-1]===r:j.contains(a,r))||(a.push(r),i.push(n[e]))}),i},j.union=function(){return j.uniq(j.flatten(arguments,!0))},j.intersection=function(n){var t=o.call(arguments,1);return j.filter(j.uniq(n),function(n){return j.every(t,function(t){return j.indexOf(t,n)>=0})})},j.difference=function(n){var t=c.apply(e,o.call(arguments,1));return j.filter(n,function(n){return!j.contains(t,n)})},j.zip=function(){for(var n=j.max(j.pluck(arguments,"length").concat(0)),t=new Array(n),r=0;n>r;r++)t[r]=j.pluck(arguments,""+r);return t},j.object=function(n,t){if(null==n)return{};for(var r={},e=0,u=n.length;u>e;e++)t?r[n[e]]=t[e]:r[n[e][0]]=n[e][1];return r},j.indexOf=function(n,t,r){if(null==n)return-1;var e=0,u=n.length;if(r){if("number"!=typeof r)return e=j.sortedIndex(n,t),n[e]===t?e:-1;e=0>r?Math.max(0,u+r):r}if(y&&n.indexOf===y)return n.indexOf(t,r);for(;u>e;e++)if(n[e]===t)return e;return-1},j.lastIndexOf=function(n,t,r){if(null==n)return-1;var e=null!=r;if(b&&n.lastIndexOf===b)return e?n.lastIndexOf(t,r):n.lastIndexOf(t);for(var u=e?r:n.length;u--;)if(n[u]===t)return u;return-1},j.range=function(n,t,r){arguments.length<=1&&(t=n||0,n=0),r=arguments[2]||1;for(var e=Math.max(Math.ceil((t-n)/r),0),u=0,i=new Array(e);e>u;)i[u++]=n,n+=r;return i};var M=function(){};j.bind=function(n,t){var r,e;if(w&&n.bind===w)return w.apply(n,o.call(arguments,1));if(!j.isFunction(n))throw new TypeError;return r=o.call(arguments,2),e=function(){if(!(this instanceof e))return n.apply(t,r.concat(o.call(arguments)));M.prototype=n.prototype;var u=new M;M.prototype=null;var i=n.apply(u,r.concat(o.call(arguments)));return Object(i)===i?i:u}},j.partial=function(n){var t=o.call(arguments,1);return function(){return n.apply(this,t.concat(o.call(arguments)))}},j.bindAll=function(n){var t=o.call(arguments,1);if(0===t.length)throw new Error("bindAll must be passed function names");return A(t,function(t){n[t]=j.bind(n[t],n)}),n},j.memoize=function(n,t){var r={};return t||(t=j.identity),function(){var e=t.apply(this,arguments);return j.has(r,e)?r[e]:r[e]=n.apply(this,arguments)}},j.delay=function(n,t){var r=o.call(arguments,2);return setTimeout(function(){return n.apply(null,r)},t)},j.defer=function(n){return j.delay.apply(j,[n,1].concat(o.call(arguments,1)))},j.throttle=function(n,t,r){var e,u,i,a=null,o=0;r||(r={});var c=function(){o=r.leading===!1?0:new Date,a=null,i=n.apply(e,u)};return function(){var l=new Date;o||r.leading!==!1||(o=l);var f=t-(l-o);return e=this,u=arguments,0>=f?(clearTimeout(a),a=null,o=l,i=n.apply(e,u)):a||r.trailing===!1||(a=setTimeout(c,f)),i}},j.debounce=function(n,t,r){var e,u=null;return function(){var i=this,a=arguments,o=function(){u=null,r||(e=n.apply(i,a))},c=r&&!u;return clearTimeout(u),u=setTimeout(o,t),c&&(e=n.apply(i,a)),e}},j.once=function(n){var t,r=!1;return function(){return r?t:(r=!0,t=n.apply(this,arguments),n=null,t)}},j.wrap=function(n,t){return function(){var r=[n];return a.apply(r,arguments),t.apply(this,r)}},j.compose=function(){var n=arguments;return function(){for(var t=arguments,r=n.length-1;r>=0;r--)t=[n[r].apply(this,t)];return t[0]}},j.after=function(n,t){return function(){return--n<1?t.apply(this,arguments):void 0}},j.keys=_||function(n){if(n!==Object(n))throw new TypeError("Invalid object");var t=[];for(var r in n)j.has(n,r)&&t.push(r);return t},j.values=function(n){var t=[];for(var r in n)j.has(n,r)&&t.push(n[r]);return t},j.pairs=function(n){var t=[];for(var r in n)j.has(n,r)&&t.push([r,n[r]]);return t},j.invert=function(n){var t={};for(var r in n)j.has(n,r)&&(t[n[r]]=r);return t},j.functions=j.methods=function(n){var t=[];for(var r in n)j.isFunction(n[r])&&t.push(r);return t.sort()},j.extend=function(n){return A(o.call(arguments,1),function(t){if(t)for(var r in t)n[r]=t[r]}),n},j.pick=function(n){var t={},r=c.apply(e,o.call(arguments,1));return A(r,function(r){r in n&&(t[r]=n[r])}),t},j.omit=function(n){var t={}
12158,r=c.apply(e,o.call(arguments,1));for(var u in n)j.contains(r,u)||(t[u]=n[u]);return t},j.defaults=function(n){return A(o.call(arguments,1),function(t){if(t)for(var r in t)n[r]===void 0&&(n[r]=t[r])}),n},j.clone=function(n){return j.isObject(n)?j.isArray(n)?n.slice():j.extend({},n):n},j.tap=function(n,t){return t(n),n};var S=function(n,t,r,e){if(n===t)return 0!==n||1/n==1/t;if(null==n||null==t)return n===t;n instanceof j&&(n=n._wrapped),t instanceof j&&(t=t._wrapped);var u=l.call(n);if(u!=l.call(t))return!1;switch(u){case"[object String]":return n==String(t);case"[object Number]":return n!=+n?t!=+t:0==n?1/n==1/t:n==+t;case"[object Date]":case"[object Boolean]":return+n==+t;case"[object RegExp]":return n.source==t.source&&n.global==t.global&&n.multiline==t.multiline&&n.ignoreCase==t.ignoreCase}if("object"!=typeof n||"object"!=typeof t)return!1;for(var i=r.length;i--;)if(r[i]==n)return e[i]==t;var a=n.constructor,o=t.constructor;if(a!==o&&!(j.isFunction(a)&&a instanceof a&&j.isFunction(o)&&o instanceof o))return!1;r.push(n),e.push(t);var c=0,f=!0;if("[object Array]"==u){if(c=n.length,f=c==t.length)for(;c--&&(f=S(n[c],t[c],r,e)););}else{for(var s in n)if(j.has(n,s)&&(c++,!(f=j.has(t,s)&&S(n[s],t[s],r,e))))break;if(f){for(s in t)if(j.has(t,s)&&!c--)break;f=!c}}return r.pop(),e.pop(),f};j.isEqual=function(n,t){return S(n,t,[],[])},j.isEmpty=function(n){if(null==n)return!0;if(j.isArray(n)||j.isString(n))return 0===n.length;for(var t in n)if(j.has(n,t))return!1;return!0},j.isElement=function(n){return!(!n||1!==n.nodeType)},j.isArray=x||function(n){return"[object Array]"==l.call(n)},j.isObject=function(n){return n===Object(n)},A(["Arguments","Function","String","Number","Date","RegExp"],function(n){j["is"+n]=function(t){return l.call(t)=="[object "+n+"]"}}),j.isArguments(arguments)||(j.isArguments=function(n){return!(!n||!j.has(n,"callee"))}),"function"!=typeof/./&&(j.isFunction=function(n){return"function"==typeof n}),j.isFinite=function(n){return isFinite(n)&&!isNaN(parseFloat(n))},j.isNaN=function(n){return j.isNumber(n)&&n!=+n},j.isBoolean=function(n){return n===!0||n===!1||"[object Boolean]"==l.call(n)},j.isNull=function(n){return null===n},j.isUndefined=function(n){return n===void 0},j.has=function(n,t){return f.call(n,t)},j.noConflict=function(){return n._=t,this},j.identity=function(n){return n},j.times=function(n,t,r){for(var e=Array(Math.max(0,n)),u=0;n>u;u++)e[u]=t.call(r,u);return e},j.random=function(n,t){return null==t&&(t=n,n=0),n+Math.floor(Math.random()*(t-n+1))};var I={escape:{"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#x27;","/":"&#x2F;"}};I.unescape=j.invert(I.escape);var T={escape:new RegExp("["+j.keys(I.escape).join("")+"]","g"),unescape:new RegExp("("+j.keys(I.unescape).join("|")+")","g")};j.each(["escape","unescape"],function(n){j[n]=function(t){return null==t?"":(""+t).replace(T[n],function(t){return I[n][t]})}}),j.result=function(n,t){if(null==n)return void 0;var r=n[t];return j.isFunction(r)?r.call(n):r},j.mixin=function(n){A(j.functions(n),function(t){var r=j[t]=n[t];j.prototype[t]=function(){var n=[this._wrapped];return a.apply(n,arguments),z.call(this,r.apply(j,n))}})};var N=0;j.uniqueId=function(n){var t=++N+"";return n?n+t:t},j.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var q=/(.)^/,B={"'":"'","\\":"\\","\r":"r","\n":"n","	":"t","\u2028":"u2028","\u2029":"u2029"},D=/\\|'|\r|\n|\t|\u2028|\u2029/g;j.template=function(n,t,r){var e;r=j.defaults({},r,j.templateSettings);var u=new RegExp([(r.escape||q).source,(r.interpolate||q).source,(r.evaluate||q).source].join("|")+"|$","g"),i=0,a="__p+='";n.replace(u,function(t,r,e,u,o){return a+=n.slice(i,o).replace(D,function(n){return"\\"+B[n]}),r&&(a+="'+\n((__t=("+r+"))==null?'':_.escape(__t))+\n'"),e&&(a+="'+\n((__t=("+e+"))==null?'':__t)+\n'"),u&&(a+="';\n"+u+"\n__p+='"),i=o+t.length,t}),a+="';\n",r.variable||(a="with(obj||{}){\n"+a+"}\n"),a="var __t,__p='',__j=Array.prototype.join,"+"print=function(){__p+=__j.call(arguments,'');};\n"+a+"return __p;\n";try{e=new Function(r.variable||"obj","_",a)}catch(o){throw o.source=a,o}if(t)return e(t,j);var c=function(n){return e.call(this,n,j)};
12158return c.source="function("+(r.variable||"obj")+"){\n"+a+"}",c},j.chain=function(n){return j(n).chain()};var z=function(n){return this._chain?j(n).chain():n};j.mixin(j),A(["pop","push","reverse","shift","sort","splice","unshift"],function(n){var t=e[n];j.prototype[n]=function(){var r=this._wrapped;return t.apply(r,arguments),"shift"!=n&&"splice"!=n||0!==r.length||delete r[0],z.call(this,r)}}),A(["concat","join","slice"],function(n){var t=e[n];j.prototype[n]=function(){return z.call(this,t.apply(this._wrapped,arguments))}}),j.extend(j.prototype,{chain:function(){return this._chain=!0,this},value:function(){return this._wrapped}})}.call(this);
12159//# sourceMappingURL=underscore-min.map
12160;$.ajaxSetup({
12161  // Disable caching of AJAX responses
12162  cache: false,
12163});
12164
12165var urlParams = new URLSearchParams(window.location.search);
12166console.log(window.location.pathname, urlParams.toString());
12167var intialSearch = '';
12168if (urlParams.has('lasku') && (window.location.pathname === '/iv_laskutus_ja_reskontra' || window.location.pathname === '/reskontra')) {
12169    intialSearch = urlParams.get('lasku');
12170    window.history.replaceState({}, '', window.location.pathname);
12171}
12172
12173var callbacks = {};
12174
12175callbacks.success_add_refund_payment = function () {
12176  pages.iv_laskutus_ja_reskontra.$datatable_refunds.fnClearTable(0);
12177  pages.iv_laskutus_ja_reskontra.$datatable_refunds.fnDraw();
12178};
12179
12180function setClipboardText(text, successMessage) {
12181  if (!navigator.clipboard || typeof navigator.clipboard.writeText !== 'function') {
12182    if(window.toastr) {
12183      window.toastr.error('Selain ei tue kopiointia leikepöydälle');
12184    }
12185    return;
12186  }
12187  if(!text){
12188    if(window.toastr) {
12189      window.toastr.error('Kopioitava teksti on tyhjä');
12190    }
12191    return;
12192  }
12193  navigator.clipboard.writeText(text).then(function() {
12194    if(window.toastr && successMessage) {
12195      window.toastr.success(successMessage, '', {timeOut: 2000});
12196    }
12197  }
12198  ).catch(function() {
12199    if(window.toastr) {
12200      window.toastr.error('Tekstin kopiointi leikepöydälle epäonnistui');
12201    }
12202  });
12203}
12204
12205
12206var global = {};
12207
12208global.dataTablesLanguage = {
12209  sProcessing: 'Ladataan...',
12210  sLengthMenu: 'N&auml;yt&auml; _MENU_ rivi&auml;',
12211  sZeroRecords: 'Ei yht&auml;&auml;n rivi&auml;',
12212  sInfo: 'N&auml;ytet&auml;&auml;n rivit _START_ - _END_, yhteens&auml; _TOTAL_ rivist&auml;',
12213  sInfoEmpty: 'N&auml;ytet&auml;&auml;n rivit 0 - 0, yhteens&auml; 0 rivist&auml;',
12214  sInfoFiltered: '(suodatettu _MAX_ rivist&auml;)',
12215  sInfoPostFix: '',
12216  sSearch: 'Etsi:',
12217  sUrl: '',
12218  oPaginate: {
12219    sFirst: 'Ensimm&auml;inen',
12220    sPrevious: 'Edellinen',
12221    sNext: 'Seuraava',
12222    sLast: 'Viimeinen',
12223  },
12224};
12225
12226//Global properties
12227global.$dialog = '';
12228global.$loading_dialog = $(
12229  '<div><p style="margin: 0 auto; width: 66px; padding-top:38px;"><img src="/assets/images/ajax_loading.gif" width="66" height="66" /></p></div>'
12230);
12231global.$ajax_loader = $(
12232  '<p style="text-align:center;"><img src="/assets/images/ajax_loading.gif" width="66" height="66" /></p>'
12233);
12234global.$mini_loader = $(
12235  '<p style="text-align:center;"><img src="/assets/images/ajax_loading.gif" width="14" height="14" /></p>'
12236);
12237global.viewModels = {};
12238
12239//Global Methods
12240global.init = function () {
12241  global.$dialog = $('#dialog');
12242
12243  $(document.body).ajaxError(function (event, jqXHR, ajaxSettings, thrownError) {
12244    var JSON;
12245    global.close_loading_dialog();
12246
12247    if (thrownError === 'Unauthorized') {
12248      JSON = $.parseJSON(jqXHR.responseText);
12249      global.show_message(JSON, function () {
12250        window.location = 'auth/login/';
12251      });
12252    }
12253
12254    if (thrownError === 'Forbidden') {
12255      JSON = {
12256        type: 'error',
12257        title: 'Ei käyttöoikeuksia',
12258        text: 'Sinulla ei ole riittäviä käyttöoikeuksia toimintoon',
12259      };
12260      global.show_message(JSON);
12261    }
12262
12263    if (thrownError === 'Internal Server Error') {
12264      JSON = {
12265        type: 'error',
12266        text: 'Sivustolla ilmeni virhe yrittäessään suorittaa haluttua toimintoa, ole hyvä ja yritä uudelleen',
12267      };
12268      global.show_message(JSON);
12269    }
12270  });
12271
12272  global.$loading_dialog.dialog({
12273    modal: true,
12274    resizable: false,
12275    draggable: false,
12276    width: 320,
12277    height: 240,
12278    closeOnEscape: false,
12279    autoOpen: false,
12280    open: function () {
12281      $(this).parents('.ui-dialog:first').find('.ui-dialog-titlebar-close').remove();
12282    },
12283  });
12284
12285  // $('.tip_small').tooltip({
12286  //   tipClass: 'tooltip_small',
12287  //   effect: 'fade',
12288  //   fadeOutSpeed: 100,
12289  //   predelay: 400,
12290  // });
12291  //
12292  // $('.tip_big').tooltip({
12293  //   tipClass: 'tooltip_big',
12294  //   effect: 'fade',
12295  //   fadeOutSpeed: 100,
12296  //   predelay: 400,
12297  // });
12298  //
12299  // $('.tip').tooltip({
12300  //   effect: 'fade',
12301  //   fadeOutSpeed: 100,
12302  //   predelay: 400,
12303  //   position: 'top right',
12304  //   offset: [0, 0],
12305  // });
12306
12307  $('#omat_tiedot')
12308    .button({})
12309    .on('click', function () {
12310      window.location = '/omat_tiedot/';
12311    });
12312
12313  //Make all links inside datatables to call the functions in href attribute to be called via ajax
12314  $('body').on('click', 'a.ajax', function (e) {
12315    e.preventDefault();
12316
12317    var namespace = $(e.target).attr('name');
12318    var method = $(e.target).attr('target');
12319    var ajax_url = $(e.target).attr('href');
12320    var additional_params = $(e.target).parent('td').data();
12321
12322    //console.log(namespace, method, ajax_url, additional_params);
12323    //console.log('isFunction()', $.isFunction(window[namespace][method]));
12324    //console.log(typeof(window[namespace]), namespace, method, namespace[method]);
12325
12326    //If namespace and method are defined call the corresponding method
12327    if (typeof method != 'undefined' && typeof namespace != 'undefined') {
12328      if (typeof pages[namespace] != 'undefined') {
12329        if ($.isFunction(pages[namespace][method])) {
12330          pages[namespace][method](ajax_url, additional_params);
12331        }
12332      }
12333
12334      if (typeof window[namespace] != 'undefined') {
12335        if ($.isFunction(window[namespace][method])) {
12336          window[namespace][method](ajax_url, additional_params);
12337        }
12338      }
12339    }
12340  });
12341
12342  //Make all links inside datatables to call the functions in href attribute to be called via ajax
12343  $('.dataTable').on('click', 'a', function (e) {
12344    e.preventDefault();
12345    var namespace = $(e.target).attr('name');
12346    var method = $(e.target).attr('class');
12347    var ajax_url = $(e.target).attr('href');
12348    var additional_params = $(e.target).parent('td').data();
12349
12350    //console.log(namespace, method, ajax_url, additional_params);
12351    //console.log('isFunction()', $.isFunction(window[namespace][method]));
12352    // console.log(typeof(window[namespace]), namespace, method, namespace[method]);
12353    // console.log(window[namespace][method]());
12354
12355    //If namespace and method are defined call the corresponding method
12356    if (typeof method != 'undefined' && typeof namespace != 'undefined') {
12357      if (typeof pages[namespace] != 'undefined') {
12358        if ($.isFunction(pages[namespace][method])) {
12359          pages[namespace][method](ajax_url, additional_params);
12360        }
12361      }
12362
12363      if (typeof window[namespace] != 'undefined') {
12364        if ($.isFunction(window[namespace][method])) {
12365          window[namespace][method](ajax_url, additional_params);
12366        }
12367      }
12368    }
12369  });
12370};
12371
12372global.getGlobalDialogAndEmptyIfHasContent = function () {
12373  // if element does not exist, create it
12374  if (!$('#dialog').length) {
12375    $('<div id="dialog"></div>').appendTo('body');
12376  }
12377  // set global property to #dialog, may have been reset to something else
12378  global.$dialog = $('#dialog');
12379
12380  // check if it has content and close it (will remove any inner dialogs from InvoiceDialog)
12381  if (global.$dialog.hasClass('ui-dialog-content')) {
12382    console.log('closing global dialog!');
12383    global.$dialog.dialog('close');
12384  }
12385  // check if it still has content and destroy it
12386  if (global.$dialog.hasClass('ui-dialog-content')) {
12387    console.log('destroying global dialog!');
12388    global.$dialog.dialog('destroy');
12389  }
12390  return global.$dialog;
12391};
12392
12393global.show_ajax_loader = function ($dialog, $separateLoaderDiv) {
12394  if ($separateLoaderDiv) {
12395    $separateLoaderDiv.html(global.$ajax_loader);
12396  } else {
12397    var dialog_height = $dialog.dialog('option', 'height') / 2 - 106;
12398    global.$ajax_loader.css('padding-top', dialog_height);
12399
12400    $dialog.html(global.$ajax_loader);
12401  }
12402};
12403
12404//Show a dialog with a loading bar
12405global.show_loading_dialog = function (dialog_title) {
12406  global.$loading_dialog.dialog('option', 'title', dialog_title);
12407  global.$loading_dialog.dialog('open')
12408};
12409
12410global.close_loading_dialog = function () {
12411  global.$loading_dialog.dialog('close');
12412};
12413
12414global.showLoadingDialog = function (title) {
12415  global.$loading_dialog.dialog({
12416    modal: true,
12417    resizable: false,
12418    draggable: false,
12419    width: 320,
12420    height: 240,
12421    title: title,
12422    closeOnEscape: false,
12423    autoOpen: true,
12424    open: function () {
12425      $(this).parents('.ui-dialog:first').find('.ui-dialog-titlebar-close').remove();
12426    },
12427  }).parents('.ui-dialog').css('z-index', 9998);
12428};
12429
12430global.show_message = function (msgJSON, callback) {
12431  var icon = '';
12432  var $message_dialog = '';
12433  var timer;
12434
12435  switch (msgJSON.type) {
12436    case 'success':
12437      icon = 'ui-icon-circle-check';
12438      break;
12439    case 'error':
12440      icon = 'ui-icon-circle-close';
12441      break;
12442    case 'alert':
12443      icon = 'ui-icon-alert';
12444      break;
12445  }
12446
12447  if ((msgJSON.title === '' || typeof msgJSON.title === 'undefined') && msgJSON.type === 'error') {
12448    msgJSON.title = 'Virhe!';
12449  }
12450
12451  $message_dialog = $('<div />', {});
12452  $message_dialog.append($('<p />', {})).html(msgJSON.text);
12453
12454  if (msgJSON.type !== 'info') {
12455    $message_dialog.prepend(
12456      $('<span />', { class: 'ui-icon ' + icon, style: 'float:left; margin:0 7px 50px 0;' })
12457    );
12458  }
12459
12460  $message_dialog.dialog({
12461    title: msgJSON.title,
12462    modal: true,
12463    buttons: {
12464      Ok: function () {
12465        $(this).dialog('close');
12466      },
12467    },
12468    open: function () {
12469      if (msgJSON.type === 'success') {
12470        timer = setTimeout(function () {
12471          $message_dialog.dialog('widget').hide('highlight', {}, 1500, function () {
12472            $message_dialog.dialog('close');
12473          });
12474        }, 2000);
12475      }
12476      if (msgJSON.type === 'info') {
12477      }
12478    },
12479    beforeClose: function () {
12480      clearTimeout(timer);
12481    },
12482    close: function () {
12483      if (typeof callback !== 'undefined') {
12484        callback();
12485      }
12486      $(this).dialog('destroy');
12487      $(this).remove();
12488    },
12489  }).parents('.ui-dialog').css('z-index', 9999);
12490};
12491
12492global.show_log = function (url) {
12493  global.$dialog = $('<div />');
12494  var $dialog = global.$dialog; //
12495
12496  if (typeof url != 'undefined') {
12497    $.ajax({
12498      processData: false,
12499      dataType: 'html',
12500      type: 'GET',
12501      url: url,
12502      beforeSend: function (request) {
12503        $dialog.dialog({
12504          width: 650,
12505          height: 450,
12506          title: 'Tapahtumaloki',
12507          close: function (e) {
12508            e.stopPropagation();
12509          },
12510        });
12511        global.show_ajax_loader($dialog);
12512      },
12513      success: function (response) {
12514        $dialog.html(response);
12515      },
12516    });
12517  }
12518}; //show_log
12519
12520global.showJob = function (url) {
12521  var dialog = $('<div />');
12522
12523  if (dialog.hasClass('ui-dialog-content')) dialog.dialog('destroy');
12524
12525  if (typeof url != 'undeifned') {
12526    $.ajax({
12527      processData: false,
12528      dataType: 'html',
12529      type: 'GET',
12530      url: url,
12531      beforeSend: function (request) {
12532        dialog.dialog({
12533          width: 800,
12534          height: 600,
12535          title: 'Kuormakirja',
12536          close: function (e) {
12537            e.stopPropagation();
12538            dialog.dialog('destroy');
12539          },
12540        });
12541        global.show_ajax_loader(dialog);
12542      },
12543      success: function (response) {
12544        dialog.html(response);
12545      },
12546    });
12547  }
12548};
12549
12550global.add_payment = function (url, params) {
12551  var d = new Date();
12552
12553  //Define the URL and success function for the invoice payment case
12554  /*
12555		if(target_type == 'invoice'){
12556			var url = '/ajax/add_payment/' + id;
12557			var success_callback = function(responseJSON, statusText, xhr, $form) {
12558				global.close_loading_dialog();
12559				global.show_message(responseJSON);
12560				$add_payment_dialog.dialog("destroy");
12561
12562				//Refresh the datatables
12563				pages.iv_laskutus_ja_reskontra.$datatable_iv.fnClearTable( 0 );
12564				pages.iv_laskutus_ja_reskontra.$datatable_iv.fnDraw();
12565
12566				pages.iv_laskutus_ja_reskontra.$datatable.fnClearTable( 0 );
12567				pages.iv_laskutus_ja_reskontra.$datatable.fnDraw();
12568			}
12569		}
12570
12571		//Define the URL and success function for the refund payment case
12572		if(target_type == 'refund'){
12573			var url = '/ajax/add_refund_payment/' + id;
12574			var success_callback = function(responseJSON, statusText, xhr, $form) {
12575				global.close_loading_dialog();
12576				global.show_message(responseJSON);
12577				$add_payment_dialog.dialog("destroy");
12578
12579				//Refresh the datatable
12580				pages.iv_laskutus_ja_reskontra.$datatable_refunds.fnReloadAjax();
12581			}
12582		}
12583		*/
12584
12585  $add_payment_dialog = $('<div></div>')
12586    .append(
12587      $('<form />', { id: 'add_payment_form', method: 'post', action: url })
12588        .append(
12589          $('<fieldset />', { class: 'fs-invisible', style: '' })
12590            .append('<p>Syötä maksusuorituksen summa euroissa ja lisää suorituksen päivämäärä</p>')
12591            .append(
12592              $('<ol />')
12593                .append(
12594                  $('<li />')
12595                    .append($('<label for="amount">Summa:</label>'))
12596                    .append(
12597                      $(
12598                        '<input type="text" name="amount" id="amount" value="' +
12599                          params.open_sum +
12600                          '" class="text small" />'
12601                      )
12602                    )
12603                    .append(' &euro;')
12604                )
12605                .append(
12606                  $('<li />')
12607                    .append($('<label id="created_label" for="created">Päivämäärä:</label>'))
12608                    .append(
12609                      $(
12610                        '<input type="text" class="text small" id="created" name="created" value="' +
12611                          d.getDate() +
12612                          '.' +
12613                          (d.getMonth() + 1) +
12614                          '.' +
12615                          d.getFullYear() +
12616                          '" />'
12617                      ).datepicker($.datepicker.regional.fi)
12618                    )
12619                )
12620                .append(
12621                  $('<li />').append(
12622                    $('<button type="submit">Tallenna maksusuoritus</button>').button()
12623                  )
12624                )
12625            )
12626        )
12627        .submit(function () {
12628          $(this).ajaxSubmit({
12629            dataType: 'json',
12630            beforeSubmit: function () {
12631              global.show_loading_dialog('Tallennetaan maksusuoritusta...');
12632            },
12633            success: function (responseJSON, statusText, xhr, $form) {
12634              global.close_loading_dialog();
12635              global.show_message(responseJSON);
12636              $add_payment_dialog.dialog('close');
12637
12638              var fn = window.callbacks[responseJSON.data.callback];
12639
12640              if ($.isFunction(fn)) {
12641                fn();
12642              }
12643            },
12644          });
12645          return false;
12646        })
12647    )
12648    .dialog({
12649      width: 400,
12650      //height:200,
12651      autoOpen: true,
12652      modal: true,
12653      resizable: false,
12654      draggable: false,
12655      beforeClose: function (event, ui) {
12656        event.stopPropagation();
12657      },
12658      close: function () {
12659        $(this).dialog('destroy');
12660        $(this).remove();
12661      },
12662      title: 'Lisää maksusuoritus',
12663      buttons: {
12664        Peruuta: function () {
12665          $(this).dialog('close');
12666        },
12667      },
12668    });
12669}; //add_payment
12670
12671global.setCompaniesOptions = function () {
12672  if (
12673    !localStorage.getItem('companiesOptions') &&
12674    window.App &&
12675    window.App.user.access_level >= 100
12676  ) {
12677    $.ajax({
12678      processData: false,
12679      dataType: 'json',
12680      type: 'GET',
12681      url: '/ajax/getCompaniesOptions/',
12682      success: function (companiesJSON) {
12683        localStorage.setItem('companiesOptions', JSON.stringify(companiesJSON));
12684      },
12685    });
12686  }
12687};
12688
12689global.clearCompaniesOptions = function () {
12690  localStorage.removeItem('companiesOptions');
12691};
12692
12693global.renderCompaniesFilterOptions = function (selectEl) {
12694  if (localStorage.getItem('companiesOptions') === null) {
12695    return;
12696  }
12697  var companiesJSON = JSON.parse(localStorage.getItem('companiesOptions'));
12698  $.each(companiesJSON, function (key, value) {
12699    $(selectEl).append('<option value=' + key + '>' + value + '</option>');
12700  });
12701  $(selectEl).selectpicker('refresh');
12702};
12703
12704var pages = {
12705  auth: {
12706    init: function () {
12707      // clear companies options from localstorage on login page
12708      global.clearCompaniesOptions();
12709
12710      $('#username').focus();
12711
12712      $('#login_btn').button({ icons: { primary: 'ui-icon-locked' }, text: true });
12713
12714      $('#login_tabs').tabs();
12715    },
12716
12717    init_activate: function () {
12718      $('#activate_btn')
12719        .button({ icons: { primary: 'ui-icon-locked' }, text: true })
12720        .hover(
12721          function () {
12722            $(this).button('option', 'icons', { primary: 'ui-icon-unlocked' });
12723          },
12724          function () {
12725            $(this).button('option', 'icons', { primary: 'ui-icon-locked' });
12726          }
12727        );
12728
12729      $('#add_car')
12730        .button({ icons: { primary: 'ui-icon-plusthick' }, text: true })
12731        .on('click', function () {
12732          pages.auth.add_car();
12733        })
12734        .trigger('click');
12735    },
12736
12737    forgot_password_dialog: function () {
12738      $('<div />', { style: 'text-align:left;' })
12739        .append(
12740          $('<p />').html('Anna sähköpostiosoitteesi lähetetään'),
12741          $('<form>', { method: 'post', action: '/ajax/forgot_password/' }).append(
12742            $('<input />', { type: 'text', name: 'email', id: 'email', class: 'text medium' })
12743          )
12744        )
12745        .submit(function () {
12746          $(this).ajaxSubmit({
12747            processData: true,
12748            data: post_data,
12749            dataType: 'json',
12750            //show the loading message
12751            beforeSubmit: function () {
12752              global.show_loading_dialog('Lähetetään sähköpostia...');
12753            },
12754
12755            // success identifies the function to invoke when the server response
12756            // has been received; here we apply a fade-in effect to the new content
12757            success: function (responseJSON, statusText, xhr, $form) {
12758              global.close_loading_dialog();
12759              var $message_dialog = $('<div />')
12760                .append(
12761                  '<p><span class="ui-icon-check" style="float:left; margin:0 7px 50px 0;"></span>Sähköpostiisi on lähetetty ohjeet kuinka saat uuden salasanasi käyttöön</p>'
12762                )
12763                .dialog({
12764                  title: 'Salasana vaihdettu!',
12765                  modal: true,
12766                  close: function () {},
12767                  buttons: {
12768                    Jatka: function () {
12769                      $(this).dialog('close');
12770                    },
12771                  },
12772                });
12773            },
12774          });
12775          return false;
12776        })
12777        .dialog({
12778          width: 320,
12779          autoOpen: true,
12780          modal: true,
12781          resizable: false,
12782          draggable: false,
12783          beforeClose: function (event, ui) {
12784            event.stopPropagation();
12785          },
12786          title: 'Olen unohtanut salasanani',
12787          buttons: {
12788            Peruuta: function () {
12789              $(this).dialog('close');
12790            },
12791            'Lähetä lasku': function () {
12792              $(this).dialog('close');
12793            },
12794          },
12795        });
12796    },
12797
12798    add_car: function () {
12799      $num = $('#cars tbody tr').size();
12800      $remove_btn = $('<button type="button" style="float:right; padding:0px 5px;">Poista</button>')
12801        .button({ icons: { primary: 'ui-icon-trash' }, text: true })
12802        .on('click', function (e) {
12803          e.stopPropagation();
12804          $wrapper = $(this).parent().parent();
12805          $('<div />')
12806            .html(
12807              '<p style="font-weight:bold;"><span class="ui-icon ui-icon-alert" style="float:left; margin:0 7px 20px 0; "></span>Haluatko varmasti poistaa kyseisen auton?</p>'
12808            )
12809            .dialog({
12810              resizable: false,
12811              height: 180,
12812              width: 340,
12813              title: 'Poista auto',
12814              modal: true,
12815              buttons: {
12816                Ei: function () {
12817                  $(this).dialog('close');
12818                },
12819                Kyllä: function () {
12820                  $(this).dialog('close');
12821
12822                  $wrapper.hide('highlight', function () {
12823                    $(this).remove();
12824                  });
12825                },
12826              },
12827            });
12828        });
12829
12830      $car_data = $('<tr />', { class: 'car', style: 'width:900px;' }).append(
12831        $('<td />').append(
12832          '<input type="text" name="cars[' +
12833            $num +
12834            '][phone]" id="cars[' +
12835            $num +
12836            '][phone]" class="text medium-small required" />'
12837        ),
12838        $('<td />').append(
12839          '<input type="text" name="cars[' +
12840            $num +
12841            '][registry_nr]" id="cars[' +
12842            $num +
12843            '][registry_nr]" class="text small" />'
12844        ),
12845        $('<td />').append(
12846          '<input type="text" name="cars[' +
12847            $num +
12848            '][car_nr]" id="cars[' +
12849            $num +
12850            '][car_nr]" class="text small required" />'
12851        ),
12852        $('<td />').append(
12853          '<input type="text" name="cars[' +
12854            $num +
12855            '][stationary_position]" id="cars[' +
12856            $num +
12857            '][stationary_position]" class="text small required"  />'
12858        )
12859      );
12860
12861      if ($num > 0) {
12862        $car_data.append($('<td />').append($remove_btn));
12863      }
12864
12865      /*
12866						$('<div />', {"style":"float:left;"})
12867						.append(
12868							$('<ol />', {"style":"float:left; width:100%;"})
12869							.append(
12870								$('<li />',{"style":"float:left; clear:none; display:inline; width:auto; padding-right:20px;"})
12871								.append('<label for="phone">Puhelinnumero:</label>')
12872								.append('<input type="text" name="cars['+$num+'][phone]" id="cars['+$num+'][phone]" class="text small required" />'),
12873								$('<li />',{"style":"float:left; clear:none; display:inline; width:auto;  padding-right:20px;"})
12874								.append('<label for="registry_nr">Rek. Numero:</label>')
12875								.append('<input type="text" name="cars['+$num+'][registry_nr]" id="cars['+$num+'][registry_nr]" class="text vsmall" />'),
12876								$('<li />',{"style":"float:left; clear:none; display:inline; width:auto;  padding-right:20px;"})
12877								.append('<label for="car_nr">Järjestysnumero:</label>')
12878								.append('<input type="text" name="cars['+$num+'][car_nr]" id="cars['+$num+'][car_nr]" class="text xsmall required" />'),
12879								$('<li />',{"style":"float:left; clear:none; display:inline; width:auto;"})
12880								.append('<label for="stationary_position">Asemapaikka:</li>')
12881								.append('<input type="text" name="cars['+$num+'][stationary_position]" id="cars['+$num+'][stationary_position]" class="text medium-small required"  />'),
12882								$('<li />',{"style":"float:left; clear:none; display:inline; width:auto;"})
12883								.append($('<div />', {"class": "buttons"}))
12884							)
12885
12886						)
12887				);
12888
12889				$remove_btn.prependTo($car_data.find('div.buttons'));
12890				*/
12891
12892      $('#cars').prepend($car_data);
12893    }, //add_car
12894  },
12895
12896  iv_asiakkuudet: {
12897    //IV_Asiakkuudet properties
12898    car_types_JSON: {},
12899    car_brands_JSON: {},
12900    contract_types_JSON: {},
12901    $innotaxi_datatable: '',
12902    $accounts_datatable: '',
12903    $accounts_datatable_disabled: '',
12904    $accounts_datatable_deleted: '',
12905
12906    //IV_Asiakkuudet Methods
12907    init: function () {
12908      $('#accounts_tabs').tabs();
12909
12910      $('#actions #new_account:button')
12911        .button({ icons: { primary: 'ui-icon-plusthick' } })
12912        .on('click', function () {
12913          window.AccountCard.show();
12914        });
12915
12916      $('#accounts_dt').delegate('#accounts_dt a.show_account_card', 'click', function (e) {
12917        e.preventDefault();
12918        var company_id = $(e.target).attr('href');
12919        var action = $(e.target).attr('class');
12920
12921        switch (action) {
12922          case 'show_account_card':
12923            window.AccountCard.show(company_id);
12924            break;
12925        }
12926      });
12927
12928      //Init the asiakkuudet datatable
12929      pages.iv_asiakkuudet.$accounts_datatable = $('#accounts_dt').dataTable({
12930        oLanguage: global.dataTablesLanguage,
12931        sPaginationType: 'full_numbers',
12932        bPaginate: true,
12933        iDisplayLength: 10,
12934        bAutoWidth: false,
12935        bJQueryUI: true,
12936        bProcessing: true,
12937        bServerSide: false,
12938        sAjaxSource: 'ajax/get_accounts_json/',
12939        aoColumns: [
12940          /** company_id **/ null,
12941          /** Yritys **/ null,
12942          /** Y-tunnus **/ { bVisible: false, bSearchable: false },
12943          /** Kaupunki **/ null,
12944          /** Yhteyshenkilö **/ null,
12945          /** Puhelinnumero **/ null,
12946          /** Sähköposti **/ null,
12947          /** Asiakkuus luotu **/ { sType: 'date-eu' },
12948          /** User type **/ { bVisible: true, bSearchable: false },
12949        ],
12950        aaSorting: [[7, 'desc']],
12951        fnServerData: function (sSource, aoData, fnCallback) {
12952          $.getJSON(sSource, null, function (json) {
12953            /* Do whatever additional processing you want on the callback, then tell DataTables */
12954            fnCallback(json);
12955          });
12956        },
12957        //Called before each row is shown
12958        fnRowCallback: function (nRow, aData, iDisplayIndex) {
12959          var company_id = aData[0];
12960          var company_name = aData[1];
12961          var user_type = aData[8];
12962
12963          //Add the transaction id to every rows data object
12964          $('td:eq(1)', nRow).html(
12965            '<a href="' + company_id + '" class="show_account_card" >' + company_name + '</a>'
12966          );
12967          return nRow;
12968        },
12969      });
12970
12971      pages.iv_asiakkuudet.$accounts_datatable_disabled = $('#accounts_dt_disabled').dataTable({
12972        oLanguage: global.dataTablesLanguage,
12973        sPaginationType: 'full_numbers',
12974        bPaginate: true,
12975        iDisplayLength: 10,
12976        bAutoWidth: false,
12977        bJQueryUI: true,
12978        bProcessing: true,
12979        bServerSide: false,
12980        sAjaxSource: 'ajax/get_accounts_json/',
12981        aoColumns: [
12982          /** company_id **/ null,
12983          /** Yritys **/ null,
12984          /** Y-tunnus **/ { bVisible: false, bSearchable: false },
12985          /** Kaupunki **/ null,
12986          /** Yhteyshenkilö **/ null,
12987          /** Puhelinnumero **/ null,
12988          /** Sähköposti **/ null,
12989          /** Asiakkuus luotu **/ { sType: 'date-eu' },
12990          /** User type **/ { bVisible: true, bSearchable: false },
12991        ],
12992        aaSorting: [[7, 'desc']],
12993        fnServerData: function (sSource, aoData, fnCallback) {
12994          $.getJSON(sSource, null, function (json) {
12995            /* Do whatever additional processing you want on the callback, then tell DataTables */
12996            fnCallback(json);
12997          });
12998        },
12999        //Called before each row is shown
13000        fnRowCallback: function (nRow, aData, iDisplayIndex) {
13001          var company_id = aData[0];
13002          var company_name = aData[1];
13003          var user_type = aData[8];
13004
13005          //Add the transaction id to every rows data object
13006          $('td:eq(1)', nRow).html(
13007            '<a href="' + company_id + '" class="show_account_card" >' + company_name + '</a>'
13008          );
13009          return nRow;
13010        },
13011      });
13012
13013      pages.iv_asiakkuudet.$accounts_datatable_deleted = $('#accounts_dt_deleted').dataTable({
13014        oLanguage: global.dataTablesLanguage,
13015        sPaginationType: 'full_numbers',
13016        bPaginate: true,
13017        iDisplayLength: 10,
13018        bAutoWidth: false,
13019        bJQueryUI: true,
13020        bProcessing: true,
13021        bServerSide: false,
13022        sAjaxSource: 'ajax/get_accounts_json/',
13023        aoColumns: [
13024          /** company_id **/ null,
13025          /** Yritys **/ null,
13026          /** Y-tunnus **/ { bVisible: false, bSearchable: false },
13027          /** Kaupunki **/ null,
13028          /** Yhteyshenkilö **/ null,
13029          /** Puhelinnumero **/ null,
13030          /** Sähköposti **/ null,
13031          /** Asiakkuus luotu **/ { sType: 'date-eu' },
13032          /** User type **/ { bVisible: true, bSearchable: false },
13033        ],
13034        aaSorting: [[7, 'desc']],
13035        fnServerData: function (sSource, aoData, fnCallback) {
13036          $.getJSON(sSource, null, function (json) {
13037            /* Do whatever additional processing you want on the callback, then tell DataTables */
13038            fnCallback(json);
13039          });
13040        },
13041        //Called before each row is shown
13042        fnRowCallback: function (nRow, aData, iDisplayIndex) {
13043          var company_id = aData[0];
13044          var company_name = aData[1];
13045          var user_type = aData[8];
13046
13047          //Add the transaction id to every rows data object
13048          $('td:eq(1)', nRow).html(
13049            '<a href="' + company_id + '" class="show_account_card" >' + company_name + '</a>'
13050          );
13051          return nRow;
13052        },
13053      });
13054    },
13055  }, //IV_Asiakkuudet
13056
13057  iv_laskutus_ja_reskontra: {
13058    $datatable: null,
13059    $datatable_iv: null,
13060    recurring_invoicing: null,
13061    $part_payments_datatable: null,
13062    $datatable_money_transfers: null,
13063    $datatable_refunds: null,
13064    $datatable_direct_payments: null,
13065    $datatable_deductions: null,
13066    $datatable_remittances: null,
13067
13068    init: function () {
13069      // iv_laskut specific jQuery functions.
13070      $('#invoices_tabs').tabs();
13071
13072      $('#new_invoice_person')
13073        .button({ icons: { primary: 'ui-icon-plusthick' } })
13074        .on('click', function () {
13075          //pages.reskontra.show_invoice_dialog('person');
13076          window.location = '/lasku/kuluttajalasku/';
13077        });
13078
13079      $('#new_invoice_company')
13080        .button({ icons: { primary: 'ui-icon-plusthick' } })
13081        .on('click', function () {
13082          //pages.reskontra.show_invoice_dialog('company');
13083          window.location = '/lasku/yrityslasku/';
13084        });
13085
13086      $('#new_part_payment')
13087        .button({ icons: { primary: 'ui-icon-plusthick' } })
13088        .wrap($('<div />', { style: 'float:left;margin-right:7px;' }))
13089        .on('click', function () {
13090          window.location = '/osamaksu/';
13091        });
13092
13093      $('#new_deduction')
13094        .button({ icons: { primary: 'ui-icon-plusthick' } })
13095        .wrap($('<div />', { style: 'float:left;margin-right:7px;' }))
13096        .on('click', function () {
13097          window.location = '/veloitukset/';
13098        });
13099
13100      $('#new_invoice')
13101        .button({ icons: { primary: null, secondary: 'ui-icon-triangle-1-s' } })
13102        .wrap($('<div />', { style: 'float:left;' }))
13103        .wrap($('<div />', {}))
13104        .parent()
13105        .parent()
13106        .append(
13107          $('<ul />', { style: 'position:absolute; z-index:99; font-size:13px;' }).append(
13108            $('<li />', {}).append(
13109              $('<a />', { href: '/lasku/kuluttajalasku/' })
13110                .on('click', function () {
13111                  window.location = '/lasku/kuluttajalasku/';
13112                })
13113                .text('Kuluttajalle')
13114            ),
13115            $('<li />', {}).append(
13116              $('<a />', { href: '/lasku/yrityslasku/' })
13117                .on('click', function () {
13118                  window.location = '/lasku/yrityslasku/';
13119                })
13120                .text('Yritykselle')
13121            ),
13122            $('<li />', {}).append(
13123              $('<a />', { href: '/lasku/vakuutusyhtio/' })
13124                .on('click', function () {
13125                  window.location = '/lasku/vakuutusyhtio/';
13126                })
13127                .text('Vakuutusyhtiölle')
13128            )
13129          )
13130        )
13131        .parent()
13132        .parent()
13133        .find('#new_invoice')
13134        .on('click', function () {
13135          console.log('#new_invoice');
13136
13137          //pages.reskontra.show_invoice_dialog('company');
13138          //window.location = '/lasku/yrityslasku/';
13139          var $menu = $(this).parent().next();
13140
13141          if ($menu.is(':visible')) {
13142            $menu.hide();
13143          } else {
13144            $menu.show().position({
13145              my: 'left top',
13146              at: 'left bottom',
13147              of: this,
13148            });
13149          }
13150
13151          var menu = $(this).parent().next();
13152          $(document).one('click', function () {
13153            menu.hide();
13154          });
13155          return false;
13156        })
13157        .parent()
13158        .buttonset()
13159        .next()
13160        .hide()
13161        .menu();
13162
13163
13164      $('#new_report')
13165          .button({ icons: { primary: null, secondary: 'ui-icon-triangle-1-s' } })
13166          .wrap($('<div />', { style: 'float:left;' }))
13167          .wrap($('<div />', {}))
13168          .parent()
13169          .parent()
13170          .append(
13171              $('<ul />', { style: 'position:absolute; z-index:99; font-size:13px;' }).append(
13172                  /*
13173                  $('<li />', {}).append(
13174                      $('<a />', { href: '/' })
13175                          .on('click', function (e) {
13176                            e.preventDefault();
13177                            window.InvoiceReport.reportModal.openDialog();
13178                          })
13179                          .text('Myynnit')
13180                  ),
13181                  */
13182                  $('<li />', {}).append(
13183                      $('<a />', { href: '/' })
13184                          .on('click', function (e) {
13185                            e.preventDefault();
13186                            pages.iv_laskutus_ja_reskontra.showCreateOpenInvoicesReportDialog();
13187                          })
13188                          .text('Avoimet laskut')
13189                  )
13190                  /*
13191                  $('<li />', {}).append(
13192                      $('<a />', { href: '/' })
13193                          .on('click', function (e) {
13194                            e.preventDefault();
13195                            window.CreditLossReport.reportModal.openDialog();
13196                          })
13197                          .text('Luottotappiot')
13198                  )
13199                  */
13200              )
13201          )
13202          .parent()
13203          .parent()
13204          .find('#new_report')
13205          .on('click', function () {
13206            console.log('#new_report');
13207
13208            //pages.reskontra.show_invoice_dialog('company');
13209            //window.location = '/lasku/yrityslasku/';
13210            var $menu = $(this).parent().next();
13211
13212            if ($menu.is(':visible')) {
13213              $menu.hide();
13214            } else {
13215              $menu.show().position({
13216                my: 'left top',
13217                at: 'left bottom',
13218                of: this,
13219              });
13220            }
13221
13222            var menu = $(this).parent().next();
13223            $(document).one('click', function () {
13224              menu.hide();
13225            });
13226            return false;
13227          })
13228          .parent()
13229          .buttonset()
13230          .next()
13231          .hide()
13232          .menu();
13233
13234      /*
13235						.parent()
13236					.buttonset()
13237					.next()
13238					.hide()
13239					.menu()
13240					*/
13241
13242      $('#get_iv_invoices')
13243        .button({ icons: { primary: 'ui-icon-search' } })
13244        .on('click', function () {
13245          pages.iv_laskutus_ja_reskontra.$datatable_iv.fnClearTable(0);
13246          pages.iv_laskutus_ja_reskontra.$datatable_iv.fnDraw();
13247        });
13248
13249      $('#iv_invoices_dt').on('click', 'a.show_invoice, a.show_invoice_log', function (e) {
13250        e.preventDefault();
13251
13252        var invoice_id = $(e.target).attr('href');
13253        var action = $(e.target).attr('class');
13254        switch (action) {
13255          case 'show_invoice':
13256            pages.iv_laskutus_ja_reskontra.show_invoice(invoice_id);
13257            break;
13258          case 'show_invoice_log':
13259            pages.iv_laskutus_ja_reskontra.show_invoice_log(invoice_id);
13260            break;
13261        }
13262      });
13263
13264      $('#invoices_filter_form').on('change', 'input:checkbox', function () {
13265        var filter = $(this).attr('name'),
13266          is_checked = $(this).is(':checked');
13267
13268        if (filter != 'all' && is_checked) {
13269          $('#invoices_filter_form').find('input[name=all]').prop('checked', false);
13270        }
13271
13272        if (filter == 'all' && is_checked) {
13273          $('#invoices_filter_form')
13274            .find('input:checkbox:checked')
13275            .each(function (index, elem) {
13276              if ($(elem).attr('name') != 'all') {
13277                $(elem).prop('checked', false);
13278              }
13279            });
13280        }
13281      });
13282
13283      $('#iv_invoices_filter_form').on('change', 'input:checkbox', function () {
13284        var filter = $(this).attr('name'),
13285          is_checked = $(this).is(':checked');
13286
13287        if (filter != 'all' && is_checked) {
13288          $('#iv_invoices_filter_form').find('input[name=all]').prop('checked', false);
13289        }
13290
13291        if (filter == 'all' && is_checked) {
13292          $('#iv_invoices_filter_form')
13293            .find('input:checkbox:checked')
13294            .each(function (index, elem) {
13295              if ($(elem).attr('name') != 'all') {
13296                $(elem).prop('checked', false);
13297              }
13298            });
13299        }
13300      });
13301
13302      $('#invoices_dt').on(
13303        'click',
13304        'a.show_invoice, a.show_account_card, a.show_invoice_log',
13305        function (e) {
13306          e.preventDefault();
13307
13308          var invoice_id = $(e.target).attr('href');
13309          var action = $(e.target).attr('class');
13310          var companyId = $(e.target).attr('data-companyId');
13311
13312          switch (action) {
13313            case 'show_invoice':
13314              pages.iv_laskutus_ja_reskontra.show_invoice(invoice_id);
13315              break;
13316            case 'show_account_card':
13317              window.AccountCard.show(companyId);
13318              break;
13319            case 'show_invoice_log':
13320              pages.iv_laskutus_ja_reskontra.show_invoice_log(invoice_id);
13321              break;
13322          }
13323        }
13324      );
13325
13326      $('#invoices_dt').on(
13327        'contextmenu',
13328        'a.show_account_card',
13329        function (e) {
13330          e.preventDefault();
13331
13332          // var invoice_id = $(e.target).attr('href');
13333          var action = $(e.target).attr('class');
13334          var companyId = $(e.target).attr('data-companyId');
13335
13336          switch (action) {
13337            case 'show_account_card':
13338              setClipboardText(companyId, 'Asiakkaan id kopioitu leikepöydälle');
13339              break;
13340          }
13341        }
13342      );
13343
13344      $('#direct_payments_dt').on(
13345        'click',
13346        'a.show_add_payment_dialog, a.show_account_card, a.show_invoice_log,' +
13347          ' a.show_towing_record, a.show_direct_payment_log, a.show_job_order, a.show_direct_payment',
13348        function (e) {
13349          e.preventDefault();
13350          var id = $(e.target).attr('href');
13351          var action = $(e.target).attr('class');
13352          var companyId = $(e.target).attr('data-companyId');
13353          var openAmount = $(e.target).attr('data-openAmount');
13354
13355          switch (action) {
13356            case 'show_add_payment_dialog':
13357              pages.iv_laskutus_ja_reskontra.showAddDirectPaymentDialog(id, openAmount);
13358              break;
13359            case 'show_account_card':
13360              window.AccountCard.show(companyId);
13361              break;
13362            case 'show_towing_record':
13363              global.showJob(id);
13364              break;
13365            case 'show_direct_payment_log':
13366              global.show_log(id);
13367              break;
13368            case 'show_job_order':
13369              window.openDialog(id);
13370            case 'show_direct_payment':
13371              pages.iv_laskutus_ja_reskontra.show_direct_payment(id);
13372              break;
13373          }
13374        }
13375      );
13376
13377      $('#part_payments_filter_form').on('change', 'input:checkbox', function () {
13378        var filter = $(this).attr('name'),
13379          is_checked = $(this).is(':checked');
13380
13381        if (filter != 'all' && is_checked) {
13382          $('#part_payments_filter_form').find('input[name=all]').prop('checked', false);
13383        }
13384
13385        if (filter == 'all' && is_checked) {
13386          $('#part_payments_filter_form')
13387            .find('input:checkbox:checked')
13388            .each(function (index, elem) {
13389              if ($(elem).attr('name') != 'all') {
13390                $(elem).prop('checked', false);
13391              }
13392            });
13393        }
13394      });
13395
13396      $('#part_payments_dt').on('click', 'a', function (e) {
13397        e.preventDefault();
13398
13399        var id = $(e.target).attr('href');
13400        var action = $(e.target).attr('class');
13401
13402        switch (action) {
13403          case 'show_part_payment_log':
13404            global.show_log(id);
13405            break;
13406          case 'show_part_payment':
13407            pages.iv_laskutus_ja_reskontra.show_part_payment(id);
13408            break;
13409          case 'show_invoice':
13410            pages.iv_laskutus_ja_reskontra.show_invoice(id);
13411            break;
13412          case 'show_invoice_log':
13413            pages.iv_laskutus_ja_reskontra.show_invoice_log(id);
13414            break;
13415        }
13416      });
13417
13418      $('#money_transfers_dt').on('click', 'a', function (e) {
13419        e.preventDefault();
13420
13421        var id = $(e.target).attr('href');
13422        var action = $(e.target).attr('class');
13423        var moneyTransferDate = $(e.target).attr('data-date');
13424
13425        switch (action) {
13426          case 'show_money_transfer_open':
13427            pages.iv_laskutus_ja_reskontra.show_money_transfer(id, moneyTransferDate, 'open');
13428            break;
13429          case 'show_money_transfer_transferred':
13430            pages.iv_laskutus_ja_reskontra.show_money_transfer(id, moneyTransferDate, 'transferred');
13431            break;
13432          case 'show_money_transfer_deleted':
13433            pages.iv_laskutus_ja_reskontra.show_money_transfer(id, moneyTransferDate, 'deleted');
13434            break;
13435          case 'download_report':
13436            window.open(id);
13437            break;
13438        }
13439      });
13440
13441      $('#refunds_dt').on('click', 'a', function (e) {
13442        e.preventDefault();
13443
13444        var id = $(e.target).attr('href');
13445        var action = $(e.target).attr('class');
13446        var open_sum = $(e.target).parent('td').data('open_sum');
13447
13448        switch (action) {
13449          case 'show_account_card':
13450            window.AccountCard.show(id);
13451            break;
13452          case 'show_invoice':
13453            pages.iv_laskutus_ja_reskontra.show_invoice(id);
13454            break;
13455          case 'show_log':
13456            global.show_log(id);
13457            break;
13458        }
13459      });
13460
13461      $('#iv_deductions_dt').on('click', 'a', function (e) {
13462        e.preventDefault();
13463
13464        var id = $(e.target).attr('href'),
13465          action = $(e.target).attr('class');
13466
13467        switch (action) {
13468          case 'show_account_card':
13469            window.AccountCard.show(id);
13470            break;
13471          case 'show_deduction_card':
13472            pages.iv_laskutus_ja_reskontra.showDeductionCard(id);
13473            break;
13474          case 'show_invoice':
13475            pages.iv_laskutus_ja_reskontra.show_invoice(id);
13476            break;
13477        }
13478      });
13479
13480      $('#iv_remittances_dt').on('click', 'a', function (e) {
13481        e.preventDefault();
13482
13483        var data = $(e.target).attr('href'),
13484          action = $(e.target).attr('class');
13485
13486        switch (action) {
13487          case 'try-reject-remittance':
13488            pages.iv_laskutus_ja_reskontra.confirm_action(
13489              'Varmista toiminta',
13490              'Haluatko varmasti hylätä kohdistuksen?',
13491              function () {
13492                pages.iv_laskutus_ja_reskontra.tryActionRemittance(data);
13493              }
13494            );
13495            break;
13496          case 'try-allocate-remittance':
13497            pages.iv_laskutus_ja_reskontra.confirm_action(
13498              'Varmista toiminta',
13499              'Haluatko varmasti kohdistaa laskukohdistuksen?',
13500              function () {
13501                pages.iv_laskutus_ja_reskontra.tryActionRemittance(data);
13502              }
13503            );
13504            break;
13505        }
13506      });
13507
13508      $('#iv_deductions_filter_form').on('change', 'input:checkbox', function () {
13509        var filter = $(this).attr('name'),
13510          is_checked = $(this).is(':checked');
13511
13512        if (filter != 'all' && is_checked) {
13513          $('#iv_deductions_filter_form').find('input[name=all]').prop('checked', false);
13514        }
13515
13516        if (filter == 'all' && is_checked) {
13517          $('#iv_deductions_filter_form')
13518            .find('input:checkbox:checked')
13519            .each(function (index, elem) {
13520              if ($(elem).attr('name') != 'all') {
13521                $(elem).prop('checked', false);
13522              }
13523            });
13524        }
13525
13526        if (filter === 'open' && is_checked) {
13527          $('#iv_deductions_filter_form')
13528            .find('input:checkbox:checked')
13529            .each(function (index, elem) {
13530              if ($(elem).attr('name') != 'open') {
13531                $(elem).prop('checked', false);
13532              }
13533            });
13534        }
13535
13536        if (filter === 'debited' && is_checked) {
13537          $('#iv_deductions_filter_form')
13538            .find('input:checkbox:checked')
13539            .each(function (index, elem) {
13540              if ($(elem).attr('name') != 'debited') {
13541                $(elem).prop('checked', false);
13542              }
13543            });
13544        }
13545
13546        if (filter === 'credited' && is_checked) {
13547          $('#iv_deductions_filter_form')
13548            .find('input:checkbox:checked')
13549            .each(function (index, elem) {
13550              if ($(elem).attr('name') != 'credited') {
13551                $(elem).prop('checked', false);
13552              }
13553            });
13554        }
13555      });
13556
13557      // $('#invoices_filter_form #month, #invoices_filter_form #year, #iv_invoices_filter_form select, #corporate-chain-invoices_filter_form select, #part_payments_filter_form #month, #part_payments_filter_form #year, #iv_deductions_filter_form #year, #iv_deductions_filter_form #month').selectmenu({
13558      //   style: 'popup',
13559      //   width: 200,
13560      //   menuWidth: 200,
13561      // });
13562
13563      // $('#invoices_filter_form .company-select').searchable({
13564      //   warnNoMatch: 'Ei tuloksia',
13565      //   wildcards: true
13566      // });
13567      //
13568      // $('#part_payments_filter_form .company-part-payment').searchable({
13569      //   warnNoMatch: 'Ei tuloksia',
13570      //   wildcards: true
13571      // });
13572      //
13573      // $('#iv_deductions_filter_form .company-select').searchable({
13574      //   warnNoMatch: 'Ei tuloksia',
13575      //   wildcards: true
13576      // });
13577
13578      $('#invoices_filter_form, #part_payments_filter_form, #iv_deductions_filter_form').keypress(
13579        function (e) {
13580          if (e.keyCode == 13) e.preventDefault();
13581        }
13582      );
13583
13584      pages.iv_laskutus_ja_reskontra.gaiSelected = [];
13585
13586      //$('#invoice_card_tabs').tabs();
13587
13588      $('#get_yearly_payment_invoices')
13589        .button({ icons: { primary: 'ui-icon-search' } })
13590        .on('click', function () {
13591          pages.iv_laskutus_ja_reskontra.$datatable_yearly_payments.fnClearTable(0);
13592          pages.iv_laskutus_ja_reskontra.$datatable_yearly_payments.fnDraw();
13593        });
13594
13595      $('#yearly_payment_invoices_filter_form select').selectmenu({
13596        style: 'popup',
13597        width: 200,
13598        menuWidth: 200,
13599      });
13600
13601      $('#upload_gothia_payment_file')
13602        .button({ text: true, icons: { primary: 'ui-icon-arrowthickstop-1-s' } })
13603        .on('click', function () {
13604          pages.iv_laskutus_ja_reskontra.show_upload_gothia_payment_file_dialog();
13605        });
13606
13607      $('#mark_payments_paid')
13608        .button({ text: true, icons: { primary: 'ui-icon-arrowthickstop-1-s' } })
13609        .on('click', function () {
13610          pages.iv_laskutus_ja_reskontra.confirm_mark_payments(
13611            pages.iv_laskutus_ja_reskontra.gaiSelected
13612          );
13613        });
13614
13615      pages.iv_laskutus_ja_reskontra.showDeductionCard = function (id) {
13616        global.$dialog = $('<div />', {});
13617        var $dialog = global.$dialog;
13618
13619        if ($dialog.hasClass('ui-dialog-content')) {
13620          $dialog.dialog('destroy');
13621        }
13622
13623        $dialog.on('click', 'a', function (e) {
13624          e.preventDefault();
13625
13626          var id = $(e.target).attr('href'),
13627            action = $(e.target).attr('class');
13628
13629          switch (action) {
13630            case 'show_invoice':
13631              pages.iv_laskutus_ja_reskontra.show_invoice(id);
13632              break;
13633          }
13634        });
13635
13636        $.ajax({
13637          processData: false,
13638          dataType: 'html',
13639          method: 'GET',
13640          url: 'veloitukset/getDeductionCardHtml/' + id + '/',
13641          beforeSend: function (request) {
13642            $dialog.dialog({
13643              width: 800,
13644              height: 600,
13645              modal: true,
13646              resizable: false,
13647              title: 'Veloituksen tiedot',
13648              close: function () {
13649                $dialog.dialog('destroy');
13650              },
13651            });
13652
13653            global.show_ajax_loader($dialog);
13654          },
13655          success: function (response) {
13656            $dialog.html(response);
13657          },
13658        });
13659      };
13660
13661      pages.iv_laskutus_ja_reskontra.recurring_invoicing = new recurringInvoicing({
13662        showStation: false,
13663        isAdmin: true,
13664        controller: '/iv_laskutus_ja_reskontra',
13665        invoiceEndpoint: '/iv_laskutus_ja_reskontra/customerInvoicesDataTable/'
13666      });
13667      
13668      pages.iv_laskutus_ja_reskontra.recurring_invoicing.init();
13669
13670      pages.iv_laskutus_ja_reskontra.$datatable = $('#invoices_dt').dataTable({
13671        oSearch: {"sSearch": intialSearch},
13672        oLanguage: global.dataTablesLanguage,
13673        sPaginationType: 'full_numbers',
13674        iDisplayLength: 10,
13675        bPaginate: true,
13676        bAutoWidth: false,
13677        bJQueryUI: true,
13678        bFilter: true,
13679        bInfo: true,
13680        bProcessing: true,
13681        bServerSide: true,
13682        sAjaxSource: '/iv_laskutus_ja_reskontra/customerInvoicesDataTable/',
13683        aoColumns: [
13684          /** invoice_id **/ null,
13685          /** gothia_invoice_nr **/ { bVisible: false, bSearchable: true, bSortable: false },
13686          /** ref_nr **/ { bVisible: false, bSearchable: true, bSortable: false },
13687          /** Lähettäjä **/ null,
13688          /** Velallinen **/ null,
13689          /** c/o **/ { bVisible: false, bSearchable: true, bSortable: false },
13690          /** Päiväys **/ null,
13691          /** Eräpäivä **/ null,
13692          /** Summa **/ { bSearchable: false, bSortable: false },
13693          /** Avoinna **/ { bSearchable: false, bSortable: false },
13694          /** Rahoitettu **/ null,
13695          /** Viitteemme **/ null,
13696          /** Laskun **/ { bSearchable: false, bSortable: 'status' },
13697          /** status **/ { bVisible: false, bSearchable: false, bSortable: false },
13698          /** company_id **/ { bVisible: false, bSearchable: false, bSortable: false },
13699          /** customer_id **/ { bVisible: false, bSearchable: false, bSortable: false },
13700          /** customer_type **/ { bVisible: false, bSearchable: false, bSortable: false },
13701          /** ledger_service **/ { bVisible: false, bSearchable: false, bSortable: false },
13702        ],
13703        aaSorting: [[0, 'desc']],
13704
13705        fnServerParams: function (aoData) {
13706          var company = $('#ac-tab-sent')
13707            .find('select[name=company] option:selected')
13708            .attr('value');
13709          var month = $('#ac-tab-sent').find('select[name=month] option:selected').attr('value');
13710          var year = $('#ac-tab-sent').find('select[name=year] option:selected').attr('value');
13711
13712          var filters = [];
13713          filters.push('client_invoices');
13714
13715          $('#invoices_filter_form input:checkbox:checked').each(function () {
13716            console.log($(this).attr('name'));
13717            filters.push($(this).attr('name'));
13718          });
13719
13720          aoData.push({ name: 'month', value: month });
13721          aoData.push({ name: 'year', value: year });
13722          aoData.push({ name: 'company', value: company });
13723          aoData.push({ name: 'filters', value: filters });
13724        },
13725
13726        fnDrawCallback: function () {
13727          var company = $('#ac-tab-sent').find('select[name=company] option:selected').html();
13728          var month = $('#ac-tab-sent').find('select[name=month] option:selected').html();
13729          var year = $('#ac-tab-sent').find('select[name=year] option:selected').html();
13730          $('span#month_year').html(month + ', ' + year);
13731        },
13732
13733        /*
13734					"fnServerData": function ( sSource, aoData, fnCallback ) {
13735
13736						var company = $('#company option:selected').attr("value");
13737						var month = $('#month option:selected').attr("value");
13738						var year = $('#year option:selected').attr("value");
13739
13740						sSource += year + "/" + month + "/" + company  + '/';
13741
13742						var data = {'filters':[]};
13743						data.filters.push('client_invoices');
13744
13745						$('#invoices_filter_form input:checkbox:checked').each(function(){
13746							data.filters.push($(this).attr('name'));
13747						});
13748
13749						$.post( sSource, data, function (json){
13750							$('span#month_year').html(json.month + ", " + json.year);
13751							fnCallback(json);
13752						}, "json" );
13753
13754						$.getJSON(sSource, data, function (json){
13755							$('span#month_year').html(json.month + ", " + json.year);
13756							fnCallback(json);
13757						});
13758					},
13759					*/
13760        //Called before each row is shown
13761        fnRowCallback: function (nRow, aData, iDisplayIndex) {
13762          var invoice_id = aData[0];
13763          var receiver = aData[4];
13764          var open_sum = aData[9];
13765          var row_class = aData[13];
13766          var status = aData[12];
13767          var company_id = aData[14];
13768          var customer_id = aData[15];
13769          var customer_type = aData[16];
13770          var ledger_service = aData[17];
13771          var company_name = aData[3];
13772
13773          // Add the transaction id to every rows data object
13774          $(nRow).addClass(row_class);
13775          $('td:eq(0)', nRow).html(
13776            '<a href="' + invoice_id + '" class="show_invoice" >' + invoice_id + '</a>'
13777          );
13778          $('td:eq(1)', nRow).html(
13779            '<a href="' +
13780              company_id +
13781              '" class="show_account_card" data-companyId="' +
13782              company_id +
13783              '">' +
13784              company_name +
13785              '</a>'
13786          );
13787          $('td:eq(2)', nRow).html(
13788            '<a href="' +
13789              customer_id +
13790              '" class="show_customer_card" data-cType="' +
13791              customer_type +
13792              '" data-cId="' +
13793              customer_id +
13794              '">' +
13795              receiver +
13796              '</a>'
13797          );
13798          $('td:eq(7)', nRow)
13799            .html(ledger_service);
13800
13801          $('td:eq(9)', nRow)
13802            .addClass('status')
13803            .html('<a href="' + invoice_id + '" class="show_invoice_log" >' + status + '</a>');
13804
13805          return nRow;
13806        },
13807      });
13808
13809      // We haveto fallback to delegate, because we got an ancient jQuery. :(
13810      $('#invoices_dt').on('click', 'a.show_customer_card', function (e) {
13811        e.preventDefault();
13812        var custId = $(this).data('cid');
13813        window.CustomerCard.show(custId);
13814      });
13815
13816      pages.iv_laskutus_ja_reskontra.$part_payments_datatable = $('#part_payments_dt').dataTable({
13817        oLanguage: global.dataTablesLanguage,
13818        sPaginationType: 'full_numbers',
13819        bPaginate: true,
13820        bAutoWidth: false,
13821        bJQueryUI: true,
13822        bFilter: true,
13823        bInfo: true,
13824        bProcessing: true,
13825        bServerSide: true,
13826        sAjaxSource: 'osamaksu/get_part_payments/',
13827        aoColumns: [
13828          /** SopimusNr **/ { bVisible: true, bSearchable: true },
13829          /** Yritys **/ { bVisible: true, bSearchable: true },
13830          /** Toimipiste **/ { bVisible: false, bSearchable: false },
13831          /** Luotonhakija **/ { bVisible: true, bSearchable: false },
13832          /** Summa **/ { bVisible: true, bSearchable: false },
13833          /** Sopimuksen pvm **/ { sType: 'date-eu', bVisible: true, bSearchable: false },
13834          /** Käsirahan eräpäivä **/ { sType: 'date-eu', bVisible: false, bSearchable: false },
13835          /** Toimitus pvm **/ { sType: 'date-eu', bSearchable: false },
13836          /** Rahoitus pvm **/ { bVisible: false, bSearchable: false },
13837          /** Sopimuksen tila **/ { sType: 'date-eu', bSearchable: false },
13838          /** Käsirahan tila **/ { bSearchable: false },
13839          /** Käsirahalasku ID **/ { bVisible: false, bSearchable: true },
13840          /** Tililasku ID **/ { bVisible: false, bSearchable: true },
13841          /** Käsirahalasku **/ null,
13842          /** Tililasku **/ null,
13843          /** Company id **/ { bVisible: false, bSearchable: true },
13844        ],
13845        aaSorting: [[0, 'desc']],
13846
13847        fnServerParams: function (aoData) {
13848          var company = $('#osamaksusopimukset')
13849            .find('select[name=company] option:selected')
13850            .attr('value');
13851          var month = $('#osamaksusopimukset')
13852            .find('select[name=month] option:selected')
13853            .attr('value');
13854          var year = $('#osamaksusopimukset')
13855            .find('select[name=year] option:selected')
13856            .attr('value');
13857
13858          var filters = [];
13859
13860          $('#part_payments_filter_form input:checkbox:checked').each(function () {
13861            filters.push($(this).attr('name'));
13862          });
13863
13864          // filters.push('part_payments');
13865
13866          aoData.push({ name: 'month', value: month });
13867          aoData.push({ name: 'year', value: year });
13868          aoData.push({ name: 'company', value: company });
13869          aoData.push({ name: 'filters', value: filters });
13870        },
13871
13872        fnDrawCallback: function () {
13873          var company = $('#osamaksusopimukset')
13874            .find('select[name=company] option:selected')
13875            .html();
13876          var month = $('#osamaksusopimukset').find('select[name=month] option:selected').html();
13877          var year = $('#osamaksusopimukset').find('select[name=year] option:selected').html();
13878          //$('span#month_year').html(month + ', ' + year);
13879          $('span#pp_month_year').html(month + ', ' + year);
13880        },
13881
13882        //Called before each row is shown
13883        fnRowCallback: function (nRow, aData, iDisplayIndex) {
13884          var part_payment_id = aData[0];
13885          var company_name = aData[1];
13886          var part_payment_status = aData[9];
13887          var down_payment_status = aData[10];
13888
13889          var down_payment_invoice_id = aData[11];
13890          var part_payment_invoice_id = aData[12];
13891
13892          var down_payment_invoice_no = aData[13];
13893          var part_payment_invoice_no = aData[14];
13894          var company_id = aData[15];
13895          var signature_type = aData[16];
13896          //var open_sum = aData[8];
13897          //var row_class = aData[12];
13898          //var status = aData[11];
13899
13900          if (signature_type === 'self_signed') {
13901            part_payment_status = part_payment_status + ' [online]';
13902          }
13903
13904          //Add the transaction id to every rows data object
13905          //$(nRow).addClass(row_class);
13906          $('td:eq(0)', nRow).html(
13907            '<a href="' +
13908              part_payment_id +
13909              '" class="show_part_payment" >' +
13910              part_payment_id +
13911              '</a>'
13912          );
13913          $('td:eq(1)', nRow).html(
13914            '<a href="' +
13915              company_id +
13916              '" class="show_account_card" data-companyId="' +
13917              company_id +
13918              '">' +
13919              company_name +
13920              '</a>'
13921          );
13922          $('td:eq(6)', nRow).html(
13923            '<a href="/logs/getLogHtml/part_payment/' +
13924              part_payment_id +
13925              '" name="global" class="show_part_payment_log" >' +
13926              part_payment_status +
13927              '</a>'
13928          );
13929
13930          if (part_payment_invoice_id == null) {
13931            $('td:eq(9)', nRow).html('');
13932          } else {
13933            $('td:eq(9)', nRow).html(
13934              '<a href="' +
13935                part_payment_invoice_id +
13936                '" class="show_invoice" >' +
13937                part_payment_invoice_no +
13938                '</a>'
13939            );
13940          }
13941
13942          if (down_payment_invoice_id == null) {
13943            $('td:eq(7)', nRow).html('');
13944            $('td:eq(8)', nRow).html('');
13945          } else {
13946            $('td:eq(7)', nRow).html(
13947              '<a href="' +
13948                down_payment_invoice_id +
13949                '" class="show_invoice_log" >' +
13950                down_payment_status +
13951                '</a>'
13952            );
13953            $('td:eq(8)', nRow)
13954              .addClass('status')
13955              .html(
13956                '<a href="' +
13957                  down_payment_invoice_id +
13958                  '" class="show_invoice" >' +
13959                  down_payment_invoice_no +
13960                  '</a>'
13961              );
13962          }
13963
13964          return nRow;
13965        },
13966      });
13967
13968      // We haveto fallback to delegate, because we got an ancient jQuery. :(
13969      $('#part_payments_dt').on('click', 'a.show_account_card', function (e) {
13970        e.preventDefault();
13971        var cId = $(this).data('companyid');
13972        window.AccountCard.show(cId);
13973      });
13974
13975      $('#part_payments_filter_form input:checkbox, #part_payments_filter_form select').change(
13976        function (e) {
13977          pages.iv_laskutus_ja_reskontra.$part_payments_datatable.fnClearTable(0);
13978          pages.iv_laskutus_ja_reskontra.$part_payments_datatable.fnDraw();
13979        }
13980      );
13981
13982      $('#invoices_filter_form input:checkbox, #invoices_filter_form select').change(function (e) {
13983        // Timeout used here to prevent sending checked checkboxes when swithing from any filter -> all
13984        // If fnDraw() is called when swithcing checkboxes, previous filter will override all filter
13985        setTimeout(function () {
13986          pages.iv_laskutus_ja_reskontra.$datatable.fnClearTable(0);
13987          pages.iv_laskutus_ja_reskontra.$datatable.fnDraw();
13988        }, 1);
13989      });
13990
13991      $('#iv_invoices_filter_form input:checkbox, #iv_invoices_filter_form select').change(function (e) {
13992        // Timeout used here to prevent sending checked checkboxes when swithing from any filter -> all
13993        // If fnDraw() is called when switching checkboxes, previous filter will override all filter
13994        setTimeout(function () {
13995          pages.iv_laskutus_ja_reskontra.$datatable_iv.fnClearTable(0);
13996          pages.iv_laskutus_ja_reskontra.$datatable_iv.fnDraw();
13997        }, 1);
13998      });
13999
14000      pages.iv_laskutus_ja_reskontra.$datatable_iv = $('#iv_invoices_dt').dataTable({
14001        oLanguage: global.dataTablesLanguage,
14002        sPaginationType: 'full_numbers',
14003        iDisplayLength: 10,
14004        bPaginate: true,
14005        bAutoWidth: false,
14006        bJQueryUI: true,
14007        bFilter: true,
14008        bInfo: true,
14009        bProcessing: true,
14010        bServerSide: true,
14011        sAjaxSource: 'ajax/get_invoices_json/',
14012        aoColumns: [
14013          /** invoice_id **/ null,
14014          /** gothia_invoice_number **/ { bVisible: false, bSearchable: false },
14015          /** ref_nr **/ { bVisible: false, bSearchable: false, bSortable: false },
14016          /** Lähettäjä **/  { bVisible: false, bSearchable: false, bSortable: false },
14017          /** Velallinen **/ null,
14018          /** c/o **/ { bVisible: false, bSearchable: true, bSortable: false },
14019          /** Päiväys **/ { sType: 'date-eu' },
14020          /** Eräpäivä **/ { sType: 'date-eu' },
14021          /** Summa **/ { sType: 'currency', bSearchable: false, bSortable: false },
14022          /** Avoinna **/ { sType: 'currency', bSearchable: false, bSortable: false },
14023          /** Rahoitettu **/ { bVisible: false, bSearchable: false },
14024          /** Viitteemme **/ null,
14025          /** Laskun **/ null,
14026          /**  status  **/ { bVisible: false },
14027          /** customer_id **/ { bVisible: false, bSearchable: false, bSortable: false },
14028          /** customer_type **/ { bVisible: false, bSearchable: false, bSortable: false },
14029        ],
14030        aaSorting: [[0, 'desc']],
14031
14032        fnServerParams: function (aoData) {
14033          var month = $('#ac-tab-iv_invoices')
14034            .find('select[name=month] option:selected')
14035            .attr('value');
14036          var year = $('#ac-tab-iv_invoices')
14037            .find('select[name=year] option:selected')
14038            .attr('value');
14039
14040          var filters = [];
14041          $('#iv_invoices_filter_form input:checkbox:checked').each(function(){
14042            console.log($(this).attr('name'));
14043           	filters.push($(this).attr('name'));
14044          });
14045
14046          aoData.push({ name: 'month', value: month });
14047          aoData.push({ name: 'year', value: year });
14048          aoData.push({ name: 'company', value: 30 });
14049          aoData.push({ name: 'filters', value: filters });
14050        },
14051
14052        fnDrawCallback: function () {
14053          var month = $('#ac-tab-iv_invoices')
14054            .find('select[name=month] option:selected')
14055            .attr('value');
14056          var year = $('#ac-tab-iv_invoices')
14057            .find('select[name=year] option:selected')
14058            .attr('value');
14059
14060          $('span#month_year').html(month + ', ' + year);
14061        },
14062
14063        //Called before each row is shown
14064        fnRowCallback: function (nRow, aData, iDisplayIndex) {
14065          var invoice_id = aData[0];
14066          var open_sum = aData[9];
14067          var row_class = aData[13];
14068          var status = aData[12];
14069
14070          //Add the transaction id to every rows data object
14071          $(nRow).addClass(row_class);
14072          $('td:eq(0)', nRow).html(
14073            '<a href="' + invoice_id + '" class="show_invoice" >' + invoice_id + '</a>'
14074          );
14075          $('td:eq(7)', nRow)
14076            .addClass('status')
14077            .html('<a href="' + invoice_id + '" class="show_invoice_log" >' + status + '</a>');
14078
14079          return nRow;
14080        },
14081      });
14082
14083      pages.iv_laskutus_ja_reskontra.$datatable_money_transfers = $(
14084        'table#money_transfers_dt'
14085      ).dataTable({
14086        oLanguage: global.dataTablesLanguage,
14087        sPaginationType: 'full_numbers',
14088        bAutoWidth: false,
14089        bJQueryUI: true,
14090        bFilter: true,
14091        bInfo: true,
14092        bPaginate: true,
14093        bProcessing: true,
14094        bServerSide: true,
14095        sAjaxSource: 'iv_laskutus_ja_reskontra/moneyTransfersDataTable/',
14096        aoColumns: [
14097          /** id **/ { bVisible: false },
14098          /** Money_transfer date **/ { sType: 'date-eu' },
14099          /** Sales **/ { bSortable: false, bSearchable: false },
14100          /** Deductions **/ { bSortable: false, bSearchable: false },
14101          /** To be paid **/ { bSortable: false, bSearchable: false },
14102          /** report **/ { bSortable: false, bSearchable: false },
14103        ],
14104        aaSorting: [[1, 'desc']],
14105
14106        fnServerParams: function (aoData) {
14107          var filters = [];
14108
14109          $('#money_transfers_filter_form input[name=filters]:checked').each(function () {
14110            filters.push($(this).val());
14111
14112            //console.log(filters);
14113          });
14114
14115          aoData.push({ name: 'filters', value: filters });
14116        },
14117
14118        //Called before each row is shown
14119        fnRowCallback: function (nRow, aData, iDisplayIndex) {
14120          var id = aData[0];
14121          var money_transfer_date = aData[1];
14122          var count_open = aData[2];
14123          var count_transferred = aData[3];
14124          var count_deleted = aData[4];
14125          var report_url = aData[5];
14126
14127          //Add the transaction id to every rows data object
14128          //$(nRow).data({"id":id});
14129          $('td:eq(0)', nRow).html(
14130            money_transfer_date
14131          );
14132          $('td:eq(1)', nRow).html(
14133            '<a href="' + id + '" data-date="' + money_transfer_date + '" class="show_money_transfer_open" >' + 'Avoimet (' + count_open + ')' + '</a>'
14134          );
14135          $('td:eq(2)', nRow).html(
14136            '<a href="' + id + '" data-date="' + money_transfer_date + '" class="show_money_transfer_transferred" >' + 'Tilitetyt (' + count_transferred + ')' + '</a>'
14137          );
14138          $('td:eq(3)', nRow).html(
14139            '<a href="' + id + '" data-date="' + money_transfer_date + '" class="show_money_transfer_deleted" >' + 'Poistetut (' + count_deleted + ')' + '</a>'
14140          );
14141          $('td:eq(4)', nRow).html(
14142            '<a href="' +
14143              report_url +
14144              '" class="download_report" >Kaikki</a> <a style="padding-left:10px;" href="' +
14145              report_url +
14146              '/0/1" class="download_report" >Vain rahoitukset</a>'
14147          );
14148          return nRow;
14149        },
14150      });
14151
14152      $('#money_transfers_filter_form input[name=filters]').change(function (e) {
14153        pages.iv_laskutus_ja_reskontra.$datatable_money_transfers.fnClearTable(0);
14154        pages.iv_laskutus_ja_reskontra.$datatable_money_transfers.fnDraw();
14155      });
14156
14157      pages.iv_laskutus_ja_reskontra.$datatable_refunds = $('#refunds_dt').dataTable({
14158        oLanguage: global.dataTablesLanguage,
14159        sPaginationType: 'full_numbers',
14160        bAutoWidth: false,
14161        bJQueryUI: true,
14162        bFilter: true,
14163        bInfo: true,
14164        bPaginate: true,
14165        bProcessing: true,
14166        bServerSide: true,
14167        sAjaxSource: 'iv_laskutus_ja_reskontra/get_refunds_json/',
14168        aoColumns: [
14169          /** id **/ null,
14170          /** Yritys ID **/ { bVisible: false },
14171          /** Yritys **/ null,
14172          /** Yritys ID **/ { bVisible: false },
14173          /** Laskunr **/ null,
14174          /** Hyvityslaskunr ID **/ { bVisible: false },
14175          /** Hyvityslaskunr **/ { bVisible: false },
14176          /** PalautusLaskunr ID **/ { bVisible: false },
14177          /** PalautusLaskunr **/ null,
14178          /** Hyvityspvm **/ { sType: 'date-eu' },
14179          /** Viite **/ { bVisible: false },
14180          /** Palautettava **/ { bSearchable: false },
14181          /** Palautettu **/ { bSearchable: false },
14182          /** Jäännös **/ { bVisible: false, bSearchable: false },
14183          /** Palautuspvm **/ { sType: 'date-eu', bSearchable: false },
14184          /** Tila **/ null,
14185        ],
14186        aaSorting: [[0, 'desc']],
14187
14188        fnServerParams: function (aoData) {
14189          /*
14190                        var open_refunds = $('#refunds_filter_form input[name=open_refunds]').is(':checked'),
14191                            paid_refunds = $('#refunds_filter_form input[name=paid_refunds]').is(':checked'); //.attr("value");
14192                        aoData.push({"name": "open_refunds", 'value': open_refunds});
14193                        aoData.push({"name": "paid_refunds", 'value': paid_refunds});
14194                        */
14195          var filters = [];
14196
14197          $('#refunds_filter_form input:checkbox:checked').each(function () {
14198            filters.push($(this).attr('name'));
14199          });
14200
14201          aoData.push({ name: 'filters', value: filters });
14202        },
14203
14204        //Called before each row is shown
14205        fnRowCallback: function (nRow, aData, iDisplayIndex) {
14206          var id = aData[0];
14207          var company_id = aData[1];
14208          var company_name = aData[2];
14209          var invoice_id = aData[3];
14210          var invoice_no = aData[4];
14211          var refund_invoice_id = aData[7];
14212          var refund_invoice_no = aData[8];
14213          var credit_invoice_id = aData[5];
14214          var credit__invoice_no = aData[6];
14215          var status = aData[15];
14216          //var refund_sum = ( + aData[5].replace(",","."));
14217          //var paid_sum = ( + aData[6].replace(",","."));
14218          var open_sum = +aData[13];
14219          //Add the transaction id to every rows data object
14220          $('td:eq(2)', nRow).html(
14221            '<a href="' + invoice_id + '" class="show_invoice" >' + invoice_no + '</a>'
14222          );
14223          $('td:eq(3)', nRow).html(
14224            '<a href="' +
14225              refund_invoice_id +
14226              '" class="show_invoice" >' +
14227              refund_invoice_no +
14228              '</a>'
14229          );
14230          $('td:eq(1)', nRow).html(
14231            '<a href="' +
14232              company_id +
14233              '" class="show_account_card" data-companyId="' +
14234              company_id +
14235              '">' +
14236              company_name +
14237              '</a>'
14238          );
14239          $('td:eq(8)', nRow).html(
14240            '<a href="/logs/getLogHtml/refund/' +
14241              id +
14242              '" class="show_log" name="global" >' +
14243              status +
14244              '</a>'
14245          );
14246          return nRow;
14247        },
14248      });
14249
14250      $('#refunds_filter_form').on('change', 'input', function (e) {
14251        pages.iv_laskutus_ja_reskontra.$datatable_refunds.fnClearTable(0);
14252        pages.iv_laskutus_ja_reskontra.$datatable_refunds.fnDraw();
14253      });
14254
14255      pages.iv_laskutus_ja_reskontra.$datatable_direct_payments = $(
14256        '#direct_payments_dt'
14257      ).dataTable({
14258        oLanguage: global.dataTablesLanguage,
14259        sPaginationType: 'full_numbers',
14260        bAutoWidth: false,
14261        bJQueryUI: true,
14262        bFilter: true,
14263        bInfo: true,
14264        bPaginate: true,
14265        bProcessing: true,
14266        bServerSide: true,
14267        sAjaxSource: 'iv_laskutus_ja_reskontra/directPaymentsDataTable/',
14268        aoColumns: [
14269          /** ID **/ null,
14270          /** Yritys ID **/ { bVisible: false },
14271          /** Yritys **/ null,
14272          /** Maksunumero  **/ { bVisible: false },
14273          /** TyömääräysId **/ { bVisible: false },
14274          /** Työmääräysnumero **/ { bVisible: false },
14275          /** KuormakirjaId **/ { bVisible: false },
14276          /** Kuormakirjanumero **/ { bVisible: false },
14277          /** Työn nro **/ { bSortable: false },
14278          /** Toimipiste **/ { bVisible: false },
14279          /** Pvm **/ null,
14280          /** Tyyppi **/ null,
14281          /** Maksaja **/ { bVisible: false },
14282          /** Työn suorittaja **/ null,
14283          /** Summa **/ { bSortable: false },
14284          /** Tilitetty **/ { bVisible: true, bSortable: false },
14285          /** Avoinna **/ { bVisible: true, bSortable: false },
14286          /** Tilakoodi **/ { bVisible: false },
14287          /** Tila **/ { bSortable: 'status' },
14288          /** Row class **/ { bVisible: false, bSearchable: false },
14289        ],
14290        aaSorting: [[0, 'desc']],
14291
14292        fnServerParams: function (aoData) {
14293          var filters = [],
14294            payment_type;
14295
14296          var month =
14297            $('#direct_payments_filter_form select.month option:selected').attr('value') || 'all';
14298          var year =
14299            $('#direct_payments_filter_form select.year option:selected').attr('value') || 'all';
14300          var company = $(
14301            '#direct_payments_filter_form select[name="company"] option:selected'
14302          ).attr('value');
14303          $('#direct_payments_filter_form input:checkbox:checked').each(function () {
14304            filters.push($(this).attr('name'));
14305          });
14306
14307          payment_type = $('#direct_payments_filter_form')
14308            .find('select[name=payment_type] option:selected')
14309            .attr('value');
14310
14311          filters.push(payment_type);
14312
14313          aoData.push({ name: 'filters', value: filters });
14314          aoData.push({ name: 'company', value: company });
14315          aoData.push({ name: 'month', value: month });
14316          aoData.push({ name: 'year', value: year });
14317        },
14318
14319        //Called before each row is shown
14320        fnRowCallback: function (nRow, aData, iDisplayIndex) {
14321          var id = aData[0],
14322            companyId = aData[1],
14323            companyName = aData[2],
14324            ourReference = aData[3],
14325            jobOrderId = aData[4],
14326            towingRecordId = aData[6],
14327            towingRecordNo = aData[7],
14328            paymentType = aData[11],
14329            amountToPay = aData[14],
14330            moneyTrasferred = aData[15],
14331            openAmount = aData[16],
14332            status = aData[18],
14333            jobOrderNumber = aData[20],
14334            jobType = aData[21];
14335
14336          if (towingRecordId) {
14337            if (jobType === 'towing_record') {
14338              $('td:eq(2)', nRow).html(
14339                '<a href="kuormakirjat/get_towing_record_html/' +
14340                  towingRecordId +
14341                  '" name="kuormakirjat" class="show_towing_record" >' +
14342                  towingRecordNo +
14343                  '</a>'
14344              );
14345            }
14346          }
14347          if (!towingRecordId) {
14348            if (jobType === 'job_order') {
14349              var jobOrderReference = ourReference.split('/');
14350              jobOrderType = jobOrderReference[1];
14351              if (jobOrderType !== ' RAH') {
14352                $('td:eq(2)', nRow).html(
14353                  '<a href="' +
14354                    jobOrderId.toString() +
14355                    '" name="global" class="show_job_order" >' +
14356                    jobOrderNumber.toString() +
14357                    '</a>'
14358                );
14359              } else {
14360                $('td:eq(2)', nRow).html(jobOrderNumber.toString());
14361              }
14362            }
14363          }
14364          if (paymentType === 'Korttimaksu') {
14365            $('td:eq(4)', nRow).html(
14366              '<a href="' + id + '" class="show_direct_payment" >' + paymentType + '</a>'
14367            );
14368          }
14369          $('td:eq(7)', nRow).html(
14370            '<a href="' +
14371              id +
14372              '" class="show_add_payment_dialog" data-moneyTransferred="' +
14373              moneyTrasferred +
14374              '" >' +
14375              moneyTrasferred +
14376              '</a>'
14377          );
14378
14379          $('td:eq(8)', nRow).html(openAmount);
14380          $('td:eq(1)', nRow).html(
14381            '<a href="' +
14382              companyId +
14383              '" class="show_account_card" data-companyId="' +
14384              companyId +
14385              '">' +
14386              companyName +
14387              '</a>'
14388          );
14389          $('td:eq(9)', nRow).html(
14390            '<a href="/logs/getLogHtml/direct_payment/' +
14391              id +
14392              '" class="show_direct_payment_log" name="global" >' +
14393              status +
14394              '</a>'
14395          );
14396
14397          return nRow;
14398        },
14399      });
14400
14401      $('#iv_deductions_filter_form input:checkbox, #iv_deductions_filter_form select').change(
14402        function (e) {
14403          // setTimeout used to prevent refreshing dataTable before new filters are applied
14404          setTimeout(function () {
14405            pages.iv_laskutus_ja_reskontra.$datatable_deductions.fnClearTable(0);
14406            pages.iv_laskutus_ja_reskontra.$datatable_deductions.fnDraw();
14407          }, 1);
14408        }
14409      );
14410
14411      pages.iv_laskutus_ja_reskontra.$datatable_deductions = $('#iv_deductions_dt').dataTable({
14412        oLanguage: global.dataTablesLanguage,
14413        sPaginationType: 'full_numbers',
14414        bAutoWidth: false,
14415        bJQueryUI: true,
14416        bFilter: true,
14417        bInfo: true,
14418        bPaginate: true,
14419        bProcessing: true,
14420        bServerSide: true,
14421        sAjaxSource: 'veloitukset/getDeductionsDataTable/',
14422        aoColumns: [
14423          /** id **/ null,
14424          /** company_name **/ null,
14425          /** type_description **/ null,
14426          /** created **/ null,
14427          /** amount **/ null,
14428          /** invoice_id **/ null,
14429          /** status **/ null,
14430        ],
14431        aaSorting: [[0, 'desc']],
14432
14433        fnServerParams: function (aoData) {
14434          var filters = [];
14435          var company = $('#iv_deductions_filter_form')
14436            .find('select[name=company] option:selected')
14437            .attr('value');
14438          var month = $('#iv_deductions_filter_form')
14439            .find('select[name=month] option:selected')
14440            .attr('value');
14441          var year = $('#iv_deductions_filter_form')
14442            .find('select[name=year] option:selected')
14443            .attr('value');
14444
14445          $('#iv_deductions_filter_form input:checkbox:checked').each(function () {
14446            filters.push($(this).attr('name'));
14447          });
14448
14449          aoData.push({ name: 'filters', value: filters });
14450          aoData.push({ name: 'company', value: company });
14451          aoData.push({ name: 'year', value: year });
14452          aoData.push({ name: 'month', value: month });
14453        },
14454
14455        fnRowCallback: function (nRow, aData, iDisplayIndex) {
14456          var id = aData[0],
14457            companyId = aData[1],
14458            companyName = aData[2],
14459            created = aData[3],
14460            amount = aData[4],
14461            invoiceId = aData[5],
14462            status = aData[6];
14463          typeDescription = aData[7];
14464
14465          $('td:eq(0)', nRow).html(
14466            '<a href="' +
14467              id +
14468              '" class="show_deduction_card" data-deductionId="' +
14469              id +
14470              '">' +
14471              id +
14472              '</a>'
14473          );
14474
14475          $('td:eq(1)', nRow).html(
14476            '<a href="' +
14477              companyId +
14478              '" class="show_account_card" data-companyId="' +
14479              companyId +
14480              '">' +
14481              companyName +
14482              '</a>'
14483          );
14484
14485          $('td:eq(2)', nRow).html(typeDescription);
14486
14487          if (invoiceId === null) invoiceId = '';
14488
14489          $('td:eq(5)', nRow).html(
14490            '<a href="' + invoiceId + '" class="show_invoice" >' + invoiceId + '</a>'
14491          );
14492
14493          return nRow;
14494        },
14495      });
14496
14497      $('#remittance-filter-form input:checkbox, #remittance-filter-form select').change(function (
14498        e
14499      ) {
14500        // setTimeout used to prevent refreshing dataTable before new filters are applied
14501        setTimeout(function () {
14502          pages.iv_laskutus_ja_reskontra.$datatable_remittances.fnClearTable(0);
14503          pages.iv_laskutus_ja_reskontra.$datatable_remittances.fnDraw();
14504        }, 1);
14505      });
14506
14507      pages.iv_laskutus_ja_reskontra.$datatable_remittances = $('#iv_remittances_dt').DataTable({
14508        oLanguage: global.dataTablesLanguage,
14509        sPaginationType: 'full_numbers',
14510        bAutoWidth: false,
14511        bJQueryUI: true,
14512        bFilter: true,
14513        bInfo: true,
14514        bPaginate: true,
14515        bProcessing: true,
14516        bServerSide: true,
14517        sAjaxSource: 'remittances/getRemittancesDataTable/',
14518        aoColumns: [
14519          /** id **/ null,
14520          /** status  **/ { bSearchable: false },
14521          /** account */ null,
14522          /** type */ { bVisible: true, bSearchable: false },
14523          /** amount (remittance) **/ { bSearchable: false },
14524          /** invoice_no **/ null,
14525          /** invoice_total **/ { bSearchable: false },
14526          /** entry_date */ { bSearchable: false },
14527          /** updated */ { bSearchable: false },
14528          /** source -->  actions */ { bSearchable: false },
14529        ],
14530        aaSorting: [[0, 'desc']],
14531
14532        fnServerParams: function (aoData) {
14533          var filters = [];
14534
14535          $('#remittance-filter-form input:checkbox:checked').each(function () {
14536            filters.push($(this).attr('name'));
14537          });
14538          if (filters === undefined || filters.length == 0) {
14539            filters.push('unallocated', 'allocated', 'rejected');
14540          }
14541          aoData.push({ name: 'filters', value: filters });
14542        },
14543
14544        fnRowCallback: function (nRow, aData, iDisplayIndex) {
14545          var id = aData[0],
14546            status = aData[1],
14547            account = aData[2],
14548            type = aData[3],
14549            amount = aData[4],
14550            invoice_no = aData[5],
14551            invoice_total = aData[6],
14552            entry_date = aData[7],
14553            updated = aData[8],
14554            source = aData[9];
14555
14556          var statusDescription = '';
14557          switch (status) {
14558            case '0':
14559              statusDescription = 'Kohdistamaton';
14560              break;
14561            case '1':
14562              statusDescription = 'Kohdistettu';
14563              break;
14564            case '2':
14565              statusDescription = 'Hylätty';
14566              break;
14567          }
14568
14569          $('td:eq(1)', nRow).html(statusDescription);
14570          if (status === '0') {
14571            var data = { remittance_id: id, updated: updated };
14572            $('td:eq(9)', nRow).html(
14573              "<a href='" +
14574                JSON.stringify({
14575                  remittance_id: id,
14576                  updated: updated,
14577                  url: '/remittances/tryToRejectRemittance',
14578                }) +
14579                "' class='try-reject-remittance'>Hylkää</a>" +
14580                '   ' +
14581                "<a href='" +
14582                JSON.stringify({
14583                  remittance_id: id,
14584                  updated: updated,
14585                  url: '/remittances/tryToAllocateRemittance',
14586                }) +
14587                "' class='try-allocate-remittance'>Kohdista</a>"
14588            );
14589          } else {
14590            $('td:eq(9)', nRow).html("<a href=''></a>");
14591          }
14592        },
14593      });
14594      $('#direct_payments_filter_form').on('change', 'input, select', function (e) {
14595        pages.iv_laskutus_ja_reskontra.$datatable_direct_payments.fnClearTable(0);
14596        pages.iv_laskutus_ja_reskontra.$datatable_direct_payments.fnDraw();
14597      });
14598
14599      $('select[name=company]').each(function () {
14600        global.renderCompaniesFilterOptions(this);
14601      });
14602    }, // init Laskutus ja reskontra end
14603
14604    init_show_invoice: function (invoice) {
14605      invoice_id = invoice.id;
14606      open_sum = invoice.open_sum;
14607      invoice_items = invoice.items;
14608
14609      $('.edit_invoice_data').editable('/ajax/update_invoice_data', {
14610        submitdata: { invoice_id: invoice_id },
14611        indicator: 'Tallennetaan...',
14612        tooltip: 'Muokkaa',
14613        placeholder: '',
14614        id: 'field',
14615        event: 'dblclick',
14616      });
14617
14618      $('.edit_area_invoice_data').editable('/ajax/update_invoice_data', {
14619        submitdata: { invoice_id: invoice_id },
14620        indicator: 'Tallennetaan...',
14621        tooltip: 'Muokkaa',
14622        placeholder: '',
14623        id: 'field',
14624        type: 'textarea',
14625        event: 'dblclick',
14626        submit: 'Tallenna',
14627        data: function (value, settings) {
14628          /* Convert <br> to newline. */
14629          var retval = value.replace(/<br[\s\/]?>/gi, '\n');
14630          return retval.trim();
14631        },
14632      });
14633
14634      $('.edit_invoice_data_details').editable('/ajax/update_invoice_data_details', {
14635        submitdata: { invoice_id: invoice_id },
14636        indicator: 'Tallennetaan...',
14637        tooltip: 'Muokkaa',
14638        placeholder: '',
14639        id: 'field',
14640        event: 'dblclick',
14641        data: function (value, settings) {
14642          /* Convert <br> to newline. */
14643          var retval = value.replace(/<br[\s\/]?>/gi, '\n');
14644          return retval.trim();
14645        },
14646      });
14647
14648      $('.edit_invoice_item_data').editable('/ajax/update_invoice_item_data', {
14649        indicator: 'Tallennetaan...',
14650        tooltip: 'Muokkaa',
14651        placeholder: '',
14652        id: 'field',
14653        event: 'dblclick',
14654        data: function (val) {
14655          return val.trim();
14656        },
14657      });
14658
14659      $('.edit_is_financed').editable('/ajax/update_invoice_data', {
14660        data: " {0:'Ei', 1:'Kyllä'}",
14661        submitdata: { invoice_id: invoice_id },
14662        type: 'select',
14663        indicator: 'Tallennetaan...',
14664        tooltip: 'Muokkaa',
14665        placeholder: '',
14666        id: 'field',
14667        submit: 'Tallenna',
14668        event: 'dblclick',
14669      });
14670
14671      $('.edit_next_notification').editable('/ajax/update_invoice_data', {
14672        data: " {0:'Ei määritelty', sp:'Selvityspyyntö (Asiakas)', kp:'Korjauspyyntö (Myyjä)'}",
14673        submitdata: { invoice_id: invoice_id },
14674        type: 'select',
14675        indicator: 'Tallennetaan...',
14676        tooltip: 'Muokkaa',
14677        placeholder: '',
14678        id: 'field',
14679        submit: 'Tallenna',
14680        event: 'dblclick',
14681      });
14682
14683      $('.edit_seller_notification').editable('/ajax/update_invoice_data', {
14684        data: " {0:'Ei määritelty', kp:'Korjauspyyntö (Myyjä)'}",
14685        submitdata: { invoice_id: invoice_id },
14686        type: 'select',
14687        indicator: 'Tallennetaan...',
14688        tooltip: 'Muokkaa',
14689        placeholder: '',
14690        id: 'field',
14691        submit: 'Tallenna',
14692        event: 'dblclick',
14693      });
14694
14695      $('#show_invoice_pdf')
14696        .button({ icons: { primary: 'ui-icon-document' } })
14697        .on('click', function () {
14698          //window.location = 'iv_laskutus_ja_reskontra/get_pdf_invoice/' + invoice_id + '/download';
14699
14700          //show_invoice_pdf
14701          pages.iv_laskutus_ja_reskontra.show_invoice_pdf(invoice_id);
14702        });
14703
14704      var invoiceDeliveryMethods = function () {
14705        var $list = $('<ul />', { style: 'position:absolute; z-index:99; font-size:13px;' });
14706        $list.append(
14707          $('<li />', {}).append(
14708            $('<a />', { href: '' })
14709              .on('click', function (e) {
14710                e.preventDefault();
14711                pages.iv_laskutus_ja_reskontra.send_invoice_by_mail(invoice.id);
14712              })
14713              .text('Postitse')
14714          ),
14715          $('<li />', {}).append(
14716            $('<a />', { href: '' })
14717              .on('click', function (e) {
14718                e.preventDefault();
14719                pages.iv_laskutus_ja_reskontra.send_invoice_by_email(invoice.id, invoice.email);
14720              })
14721              .text('Sähköpostitse')
14722          )
14723        );
14724        if (invoice.invoice.customer_type !== 'person') {
14725          $list.append(
14726            $('<li />', {}).append(
14727              $('<a />', { href: '' })
14728                .on('click', function (e) {
14729                  e.preventDefault();
14730                  pages.iv_laskutus_ja_reskontra.send_invoice_by_e_invoice(invoice.id);
14731                })
14732                .text('Verkkolaskuna')
14733            )
14734          );
14735        }
14736
14737        $list.append(
14738          $('<li />', {}).append(
14739            $('<a />', { href: '' })
14740              .on('click', function (e) {
14741                e.preventDefault();
14742                pages.iv_laskutus_ja_reskontra.insert_invoice_to_ledger(invoice.id);
14743              })
14744              .text('Lähetä reskontraan (ei toimitusta)')
14745          )
14746        );
14747        return $list;
14748      };
14749
14750      $('#send_invoice')
14751        .button({ icons: { primary: 'ui-icon-mail-closed', secondary: 'ui-icon-triangle-1-s' } })
14752        .wrap($('<div />', { style: 'float:left;' }))
14753        .wrap($('<div />', {}))
14754        .parent()
14755        .parent()
14756        .append(invoiceDeliveryMethods())
14757        .parent()
14758        .parent()
14759        .find('#send_invoice')
14760        .on('click', function () {
14761          var $menu = $(this).parent().next();
14762
14763          if ($menu.is(':visible')) {
14764            $menu.hide();
14765          } else {
14766            $menu.show().position({
14767              my: 'left top',
14768              at: 'left bottom',
14769              of: this,
14770            });
14771          }
14772
14773          var menu = $(this).parent().next();
14774          $(document).one('click', function () {
14775            menu.hide();
14776          });
14777          return false;
14778        })
14779        .parent()
14780        .buttonset()
14781        .next()
14782        .hide()
14783        .menu();
14784
14785      $('#copy_invoice')
14786        .button({ icons: { primary: 'ui-icon-copy' } })
14787        .on('click', function () {
14788          pages.iv_laskutus_ja_reskontra.copy_invoice(invoice_id);
14789        });
14790
14791      $('#delete_draft')
14792        .button({ icons: { primary: 'ui-icon-trash' } })
14793        .on('click', function () {
14794          pages.iv_laskutus_ja_reskontra.confirm_delete_draft(invoice_id);
14795        });
14796
14797      $('#add_payment')
14798        .button({ icons: { primary: 'ui-icon-plusthick' } })
14799        .on('click', function () {
14800          pages.iv_laskutus_ja_reskontra.show_add_payment_dialog(invoice_id, open_sum, 'invoice');
14801        });
14802
14803      $('#add_credit_line')
14804        .button({ icons: { primary: 'ui-icon-plusthick' } })
14805        .on('click', function () {
14806          pages.iv_laskutus_ja_reskontra.show_add_credit_line_dialog(invoice_id, invoice_items);
14807        });
14808
14809      $('#show-credit-invoice-dialog')
14810        .button({ icons: { primary: 'ui-icon-plusthick' } })
14811        .on('click', function () {
14812          LaskutusJaReskontra.invoiceDialog.showCreditInvoiceDialog();
14813        });
14814
14815      $('#show-invoice-ledger-service-actions-dialog')
14816        .button({ icons: { primary: 'ui-icon-plusthick' } })
14817        .on('click',function() {
14818          LaskutusJaReskontra.invoiceDialog.showLedgerServiceActionsDialog();
14819        });
14820
14821      $('#modify').button({ icons: { primary: 'ui-icon-pencil' } });
14822
14823      $('#add_log_item')
14824        .button({ icons: { primary: 'ui-icon-plusthick' } })
14825        .on('click',function() {
14826          window.LaskutusJaReskontra.invoiceDialog.addInvoiceNoteDialog.show();
14827        });
14828
14829      $('#print_invoice')
14830        .button({ icons: { primary: 'ui-icon-print' } })
14831        .on('click', function () {
14832          w = window.open();
14833          w.location = 'iv_laskutus_ja_reskontra/get_pdf_invoice/' + invoice_id;
14834          w.print();
14835          w.close();
14836        });
14837
14838      $('#print_receipt')
14839        .button({ icons: { primary: 'ui-icon-print' } })
14840        .on('click', function () {
14841          var receiptUrl = '/lasku/kuitti/' + invoice_id,
14842            w = window.open();
14843
14844          w.location = receiptUrl;
14845        });
14846
14847      $('#show_invoice .show_invoice_log').on('click', function (e) {
14848        e.preventDefault();
14849        var invoice_id = $(this).attr('href');
14850        pages.iv_laskutus_ja_reskontra.show_invoice_log(invoice_id);
14851      });
14852
14853      $('#show_invoice a.show_invoice').on('click', function (e) {
14854        e.preventDefault();
14855        var invoice_id = $(this).attr('href');
14856        pages.iv_laskutus_ja_reskontra.show_invoice(invoice_id);
14857      });
14858
14859      $('#send_by_mail')
14860        .button({ icons: { primary: 'ui-icon-mail-closed' } })
14861        .on('click', function (e) {
14862          pages.iv_laskutus_ja_reskontra.send_invoice_by_mail(invoice.id);
14863        });
14864
14865      $('#send_by_email')
14866        .button({ icons: { primary: 'ui-icon-mail-closed' } })
14867        .on('click', function () {
14868          pages.iv_laskutus_ja_reskontra.send_invoice_by_email(invoice.id, invoice.email);
14869        });
14870
14871      $('#send_invoice_copy_by_email')
14872        .button({ icons: { primary: 'ui-icon-mail-closed' } })
14873        .on('click', function () {
14874          pages.iv_laskutus_ja_reskontra.send_invoice_copy_by_email(invoice.id, invoice.email);
14875        });
14876
14877      $('#send_credit_note_copy_by_email')
14878        .button({ icons: { primary: 'ui-icon-mail-closed' } })
14879        .on('click', function () {
14880          pages.iv_laskutus_ja_reskontra.send_credit_note_copy_by_email(invoice.id, invoice.email);
14881        });
14882
14883      $('#add-credit-loss')
14884        .button({ icons: { primary: 'ui-icon-plusthick' } })
14885        .on('click', function () {
14886          LaskutusJaReskontra.invoiceDialog.showAddCreditLossDialog();
14887        });
14888
14889      $('#suggest-credit-loss')
14890        .button({ icons: { primary: 'ui-icon-plusthick' } })
14891        .on('click', function () {
14892          LaskutusJaReskontra.invoiceDialog.showSuggestCreditLossDialog();
14893        });
14894
14895      $('#nullify-credit-loss')
14896        .button({ icons: { primary: 'ui-icon-minusthick' } })
14897        .on('click', function () {
14898          window.LaskutusJaReskontra.invoiceDialog.showNullifyCreditLossDialog();
14899        });
14900
14901      var creditLossMethods = function () {
14902        return $('<li />', {}).append(
14903          $('<a />', { href: '' })
14904            .on('click', function (e) {
14905              e.preventDefault();
14906              LaskutusJaReskontra.invoiceDialog.showSuggestCreditLossDialog();
14907            })
14908            .text('Luottotappiosuositus'),
14909          $('<li />', {}).append(
14910            $('<a />', { href: '' })
14911              .on('click', function (e) {
14912                e.preventDefault();
14913                LaskutusJaReskontra.invoiceDialog.showAddCreditLossDialog();
14914              })
14915              .text('Merkitse luottotappioksi')
14916          )
14917        );
14918      };
14919
14920      $('#credit-loss')
14921        .button({ icons: { primary: 'ui-icon-plusthick' } })
14922        .append('<span class="ui-icon ui-icon-triangle-1-s" style="float: right; margin-left: 5px;"></span>')
14923
14924        .wrap($('<div />', { style: 'float:right;' }))
14925        .wrap($('<div />', {}))
14926        .parent()
14927        .parent()
14928        .append(
14929          $('<ul />', { style: 'position:absolute; z-index:99; font-size:13px;' }).append(
14930            creditLossMethods()
14931          )
14932        )
14933        .parent()
14934        .parent()
14935        .find('#credit-loss')
14936        .on('click', function () {
14937          var $menu = $(this).parent().next();
14938
14939          if ($menu.is(':visible')) {
14940            $menu.hide();
14941          } else {
14942            $menu.show().position({
14943              my: 'left top',
14944              at: 'left bottom',
14945              of: this,
14946            });
14947          }
14948
14949          var menu = $(this).parent().next();
14950          $(document).one('click', function () {
14951            menu.hide();
14952          });
14953          return false;
14954        })
14955        .parent()
14956        .buttonset()
14957        .next()
14958        .hide()
14959        .menu();
14960
14961      var invoiceCopyDeliveryMethods = function () {
14962        var $list = $('<ul />', { style: 'position:absolute; z-index:99; font-size:13px;' });
14963
14964        $list.append(
14965          $('<li />', {}).append(
14966            $('<a />', { href: '' })
14967              .on('click', function (e) {
14968                e.preventDefault();
14969                pages.iv_laskutus_ja_reskontra.send_invoice_copy_by_mail(invoice.id);
14970              })
14971              .text('Postitse')
14972          ),
14973          $('<li />', {}).append(
14974            $('<a />', { href: '' })
14975              .on('click', function (e) {
14976                e.preventDefault();
14977                pages.iv_laskutus_ja_reskontra.send_invoice_copy_by_email(
14978                  invoice.id,
14979                  invoice.email
14980                );
14981              })
14982              .text('Sähköpostitse')
14983          )
14984        );
14985        if (invoice.invoice.type != 'credit_note') {
14986          $list.append(
14987            $('<li />', {}).append(
14988              $('<a />', { href: '' })
14989                .on('click', function (e) {
14990                  e.preventDefault();
14991                  pages.iv_laskutus_ja_reskontra.send_invoice_copy_by_sms(
14992                    invoice.id,
14993                    invoice.phone
14994                  );
14995                })
14996                .text('Tekstiviestillä')
14997            )
14998          );
14999        }
15000        if (invoice.invoice.customer_type !== 'person') {
15001          var disableEditing =
15002            invoice.isAutoliitto || invoice.isSos || invoice.isInsuranceCompany ? true : false;
15003          $list.append(
15004            $('<li />', {}).append(
15005              $('<a />', { href: '' })
15006                .on('click', function (e) {
15007                  e.preventDefault();
15008                  pages.iv_laskutus_ja_reskontra.send_invoice_copy_by_e_invoice(
15009                    invoice.id,
15010                    disableEditing,
15011                    invoice.eInvoiceAddress,
15012                    invoice.eInvoiceOperator,
15013                    invoice.eInvoiceOperators
15014                  );
15015                })
15016                .text('Verkkolaskuna')
15017            )
15018          );
15019        }
15020
15021        return $list;
15022      };
15023
15024      $('#send_invoice_copy')
15025        .button({ icons: { primary: 'ui-icon-mail-closed' } })
15026        .append('<span class="ui-icon ui-icon-triangle-1-s" style="float: right; margin-left: 5px;"></span>')
15027
15028        .wrap($('<div />', { style: 'float:left;' }))
15029        .wrap($('<div />', {}))
15030        .parent()
15031        .parent()
15032        .append(invoiceCopyDeliveryMethods())
15033        .parent()
15034        .parent()
15035        .find('#send_invoice_copy')
15036        .on('click', function () {
15037          var $menu = $(this).parent().next();
15038
15039          if ($menu.is(':visible')) {
15040            $menu.hide();
15041          } else {
15042            $menu.show().position({
15043              my: 'left top',
15044              at: 'left bottom',
15045              of: this,
15046            });
15047          }
15048
15049          var menu = $(this).parent().next();
15050          $(document).one('click', function () {
15051            menu.hide();
15052          });
15053          return false;
15054        })
15055        .parent()
15056        .buttonset()
15057        .next()
15058        .hide()
15059        .menu();
15060
15061      /*
15062				$('#send_invoice_copy').button({icons:{primary:'ui-icon-mail-closed'}}).on('click',function(){
15063					pages.iv_laskutus_ja_reskontra.send_invoice_copy(invoice.id, invoice.email);
15064				});
15065				*/
15066
15067      $('#show_invoice .edit_invoice_status').on('click', function (e) {
15068        e.preventDefault();
15069        var invoice_id = $(this).attr('href');
15070        pages.iv_laskutus_ja_reskontra.show_edit_invoice_status_dialog(invoice_id);
15071      });
15072
15073      $('#delivery_stop')
15074        .find('input:radio[name=delivery_stop]')
15075        .change(function (e) {
15076          var delivery_stop = $(e.target).val();
15077
15078          $.ajax({
15079            url: '/ajax/set_invoice_delivery_stop/',
15080            data: { invoice_id: invoice_id, delivery_stop: delivery_stop },
15081            type: 'POST',
15082            dataType: 'json',
15083            beforeSend: function (request) {
15084              global.showLoadingDialog('Muutetaan lähetyksen estoa...');
15085            },
15086            success: function (responseJSON) {
15087              global.show_message(responseJSON);
15088              global.close_loading_dialog();
15089            },
15090            error: function (data) {
15091              global.close_loading_dialog();
15092            },
15093          });
15094        });
15095    }, //init_show_invoice
15096
15097   showCreateOpenInvoicesReportDialog: function () {
15098      var dateTo = new Date();
15099      dateTo.setDate(1);
15100
15101      var $createReportDialog = $('<div />')
15102          .append(
15103              $('<form method="post" action="/raportit/createOpenInvoicesReport/csv"/>').append(
15104                  $('<label />', { id: 'date_to_label', style: 'width:auto; float:none;' }).html(
15105                      'Hae avoimet laskut päivämäärällä'
15106                  ),
15107                  $(
15108                      '<input type="text" class="text small" id="date_to" name="open_until_date" value="' +
15109                      dateTo.getDate() +
15110                      '.' +
15111                      (dateTo.getMonth() + 1) +
15112                      '.' +
15113                      dateTo.getFullYear() +
15114                      '" />'
15115                  ).datepicker()
15116              )
15117          )
15118          .dialog({
15119            width: 400,
15120            autoOpen: true,
15121            modal: true,
15122            resizable: false,
15123            draggable: false,
15124            beforeClose: function (event, ui) {
15125              event.stopPropagation();
15126            },
15127            title: 'Luo raportti avoimista laskuista',
15128            buttons: {
15129              Peruuta: function () {
15130                $(this).dialog('close');
15131              },
15132              'Luo raportti': function () {
15133                console.log($createReportDialog.find('form'));
15134                $createReportDialog.find('form').submit();
15135              },
15136            },
15137          });
15138    },
15139
15140    show_invoice_pdf: function (invoice_id) {
15141      $('<div></div>')
15142        .append(
15143          $('<p />', {}).append(
15144            $('<strong />', {}).html('Laskun tila:'),
15145            $('<br />'),
15146            $('<input />', {
15147              name: 'invoice_status',
15148              id: 'invoice_status_current',
15149              type: 'radio',
15150              value: 'current',
15151              checked: 'checked',
15152            }),
15153            $('<label />', {
15154              for: 'invoice_status_current',
15155              style: 'display:inline; float:none;',
15156            }).html('Nykyinen'),
15157            $('<br />'),
15158            $('<input />', {
15159              name: 'invoice_status',
15160              id: 'invoice_status_original',
15161              type: 'radio',
15162              value: 'original',
15163            }),
15164            $('<label />', {
15165              for: 'invoice_status_original',
15166              style: 'display:inline; float:none;',
15167            }).html('Alkuperäinen')
15168          ),
15169
15170          $('<p />', {}).append(
15171            $('<strong />', {}).html('Kirjekuoren ikkuna:'),
15172            $('<br />'),
15173            $('<input />', {
15174              name: 'envelope_window_size',
15175              id: 'envelope_window_size_large',
15176              type: 'radio',
15177              value: 'large',
15178              checked: 'checked',
15179            }),
15180            $('<label />', {
15181              for: 'envelope_window_size_large',
15182              style: 'display:inline; float:none;',
15183            }).html('Suuri'),
15184            $('<br />'),
15185            $('<input />', {
15186              name: 'envelope_window_size',
15187              id: 'envelope_window_size_small',
15188              type: 'radio',
15189              value: 'small',
15190            }),
15191            $('<label />', {
15192              for: 'envelope_window_size_small',
15193              style: 'display:inline; float:none;',
15194            }).html('Pieni')
15195          )
15196        )
15197        .dialog({
15198          autoOpen: true,
15199          modal: true,
15200          resizable: false,
15201          draggable: false,
15202          title: 'Valitse PDF-laskun asetukset',
15203          beforeClose: function (event, ui) {
15204            event.stopPropagation();
15205          },
15206          buttons: {
15207            Sulje: function () {
15208              $(this).dialog('close');
15209            },
15210            'Lataa PDF-tiedosto': function () {
15211              var invoice_status = $(this).find('input:radio[name=invoice_status]:checked').val();
15212              var envelope_window_size = $(this)
15213                .find('input:radio[name=envelope_window_size]:checked')
15214                .val();
15215              window.location =
15216                'iv_laskutus_ja_reskontra/get_pdf_invoice/' +
15217                invoice_id +
15218                '/' +
15219                invoice_status +
15220                '/' +
15221                envelope_window_size +
15222                '/download';
15223            },
15224          },
15225        });
15226    },
15227
15228    send_invoice_by_mail: function (invoice_id) {
15229      $dialog = $('<div />', { style: 'text-align:left;' })
15230        .html('Haluatko varmasti lähettää laskun?')
15231        .dialog({
15232          autoOpen: true,
15233          modal: true,
15234          resizable: false,
15235          draggable: false,
15236          title: 'Lähetä lasku postitse',
15237          beforeClose: function (event, ui) {
15238            event.stopPropagation();
15239          },
15240          buttons: {
15241            Peruuta: function () {
15242              $dialog.dialog('close');
15243            },
15244            'Lähetä lasku': function () {
15245              $.ajax({
15246                dataType: 'json',
15247                type: 'POST',
15248                url: '/ajax/send_invoice_by_mail/' + invoice_id,
15249                beforeSend: function (request) {
15250                  global.showLoadingDialog('Lähetetään laskua...');
15251                },
15252                success: function (responseJSON) {
15253                  if (responseJSON.type == 'success') {
15254                    //Refresh the datatables
15255                    if (pages.iv_laskutus_ja_reskontra.$datatable_iv != null) {
15256                      pages.iv_laskutus_ja_reskontra.$datatable_iv.fnClearTable(0);
15257                      pages.iv_laskutus_ja_reskontra.$datatable_iv.fnDraw();
15258                    }
15259
15260                    if (pages.iv_laskutus_ja_reskontra.$datatable != null) {
15261                      pages.iv_laskutus_ja_reskontra.$datatable.fnClearTable(0);
15262                      pages.iv_laskutus_ja_reskontra.$datatable.fnDraw();
15263                    }
15264
15265                    if (pages.reskontra.$datatable != null) {
15266                      pages.reskontra.$datatable.fnClearTable(0);
15267                      pages.reskontra.$datatable.fnDraw();
15268                    }
15269
15270                    LaskutusJaReskontra.showInvoiceDialog({
15271                      invoiceId: invoice_id,
15272                    });
15273                  }
15274
15275                  global.show_message(responseJSON);
15276                  global.close_loading_dialog();
15277
15278                  $dialog.dialog('close');
15279                },
15280                error: function (response) {
15281                  global.close_loading_dialog();
15282                  global.show_message($.parseJSON(response.responseText));
15283                },
15284              });
15285            },
15286          },
15287        });
15288    }, //send_invoice_by_mail
15289
15290    send_invoice_copy_by_mail: function (invoice_id) {
15291      $dialog = $('<div />', { style: 'text-align:left;' })
15292        .html('Haluatko varmasti lähettää laskukopion postitse?')
15293        .dialog({
15294          autoOpen: true,
15295          modal: true,
15296          resizable: false,
15297          draggable: false,
15298          title: 'Lähetä laskukopio postitse',
15299          beforeClose: function (event, ui) {
15300            event.stopPropagation();
15301          },
15302          buttons: {
15303            Peruuta: function () {
15304              $dialog.dialog('close');
15305            },
15306            'Lähetä laskukopio': function () {
15307              $.ajax({
15308                dataType: 'json',
15309                type: 'POST',
15310                url: '/ajax/send_invoice_copy_by_mail/',
15311                data: { invoiceId: invoice_id },
15312                beforeSend: function (request) {
15313                  global.showLoadingDialog('Lähetetään laskukopiota...');
15314                },
15315                success: function (responseJSON) {
15316                  if (responseJSON.type == 'success') {
15317                    //Refresh the datatables
15318                    if (pages.iv_laskutus_ja_reskontra.$datatable_iv != null) {
15319                      pages.iv_laskutus_ja_reskontra.$datatable_iv.fnClearTable(0);
15320                      pages.iv_laskutus_ja_reskontra.$datatable_iv.fnDraw();
15321                    }
15322
15323                    if (pages.iv_laskutus_ja_reskontra.$datatable != null) {
15324                      pages.iv_laskutus_ja_reskontra.$datatable.fnClearTable(0);
15325                      pages.iv_laskutus_ja_reskontra.$datatable.fnDraw();
15326                    }
15327
15328                    LaskutusJaReskontra.showInvoiceDialog({
15329                      invoiceId: invoice_id,
15330                    });
15331                  }
15332
15333                  global.show_message(responseJSON);
15334                  global.close_loading_dialog();
15335
15336                  $dialog.dialog('close');
15337                },
15338                error: function (response) {
15339                  global.close_loading_dialog();
15340                  global.show_message($.parseJSON(response.responseText));
15341                },
15342              });
15343            },
15344          },
15345        });
15346    }, //send_invoice_by_mail
15347
15348    send_invoice_by_e_invoice: function (invoice_id) {
15349      $dialog = $('<div />', { style: 'text-align:left;' })
15350        .html('Haluatko varmasti lähettää laskun verkkolaskuna?')
15351        .dialog({
15352          autoOpen: true,
15353          modal: true,
15354          resizable: false,
15355          draggable: false,
15356          title: 'Lähetä lasku verkkolaskuna',
15357          beforeClose: function (event, ui) {
15358            event.stopPropagation();
15359          },
15360          buttons: {
15361            Peruuta: function () {
15362              $dialog.dialog('close');
15363            },
15364            'Lähetä lasku': function () {
15365              $.ajax({
15366                dataType: 'json',
15367                type: 'POST',
15368                url: '/ajax/send_invoice_by_e_invoice/' + invoice_id,
15369                beforeSend: function (request) {
15370                  global.showLoadingDialog('Lähetetään laskua...');
15371                },
15372                success: function (responseJSON) {
15373                  if (responseJSON.type == 'success') {
15374                    //Refresh the datatables
15375                    if (pages.iv_laskutus_ja_reskontra.$datatable_iv != null) {
15376                      pages.iv_laskutus_ja_reskontra.$datatable_iv.fnClearTable(0);
15377                      pages.iv_laskutus_ja_reskontra.$datatable_iv.fnDraw();
15378                    }
15379
15380                    if (pages.iv_laskutus_ja_reskontra.$datatable != null) {
15381                      pages.iv_laskutus_ja_reskontra.$datatable.fnClearTable(0);
15382                      pages.iv_laskutus_ja_reskontra.$datatable.fnDraw();
15383                    }
15384
15385                    if (pages.reskontra.$datatable != null) {
15386                      pages.reskontra.$datatable.fnClearTable(0);
15387                      pages.reskontra.$datatable.fnDraw();
15388                    }
15389
15390                    LaskutusJaReskontra.showInvoiceDialog({
15391                      invoiceId: invoice_id,
15392                    });
15393                  }
15394
15395                  global.show_message(responseJSON);
15396                  global.close_loading_dialog();
15397
15398                  $dialog.dialog('close');
15399                },
15400                error: function (response) {
15401                  global.close_loading_dialog();
15402                  global.show_message($.parseJSON(response.responseText));
15403                },
15404              });
15405            },
15406          },
15407        });
15408    }, //send_invoice_by_mail
15409
15410    send_invoice_copy_by_e_invoice: function (
15411      invoice_id,
15412      disableEditing,
15413      eInvoiceAddress,
15414      eInvoiceOperator,
15415      eInvoiceOperators
15416    ) {
15417      var selectEl = $('<select />', {
15418        type: 'text',
15419        name: 'eInvoiceOperator',
15420        id: 'eInvoiceOperator',
15421        class: 'form-control input-sm',
15422      });
15423      $.each(eInvoiceOperators, function (i, obj) {
15424        $(selectEl).append('<option value=' + obj.code + '>' + obj.name + '</option>');
15425      });
15426      selectEl.val(eInvoiceOperator);
15427      selectEl.prop('disabled', disableEditing);
15428
15429      var eInvoiceInputField = $('<input />', {
15430        type: 'text',
15431        name: 'eInvoiceAddress',
15432        id: 'eInvoiceAddress',
15433        class: 'text medium',
15434      }).val(eInvoiceAddress);
15435      eInvoiceInputField.prop('disabled', disableEditing);
15436
15437      var $form = $('<form />').append(
15438        $('<label />').html('Verkkolaskuosoite'),
15439        eInvoiceInputField,
15440        $('<label />').html('Operaattori'),
15441        selectEl
15442      );
15443      if (disableEditing) {
15444        $form.append(
15445          $('<input />', { type: 'hidden', name: 'eInvoiceAddress', id: 'eInvoiceAddress' }).val(
15446            eInvoiceAddress
15447          ),
15448          $('<input />', { type: 'hidden', name: 'eInvoiceOperator', id: 'eInvoiceOperator' }).val(
15449            eInvoiceOperator
15450          )
15451        );
15452      }
15453
15454      $form.submit(function (e) {
15455        //Get the data from the form element
15456        var data = _.object(
15457          $form.serializeArray().map(function (v) {
15458            return [v.name, v.value];
15459          })
15460        );
15461
15462        //Add some extra data
15463        _.extend(data, { invoiceId: invoice_id });
15464
15465        e.preventDefault();
15466
15467        $.ajax({
15468          dataType: 'json',
15469          type: 'POST',
15470          url: '/ajax/send_invoice_copy_by_e_invoice/',
15471          data: data,
15472          beforeSend: function (request) {
15473            global.showLoadingDialog('Lähetetään laskukopiota...');
15474          },
15475          success: function (responseJSON) {
15476            if (responseJSON.type == 'success') {
15477              //Refresh the datatables
15478              if (pages.iv_laskutus_ja_reskontra.$datatable_iv != null) {
15479                pages.iv_laskutus_ja_reskontra.$datatable_iv.fnClearTable(0);
15480                pages.iv_laskutus_ja_reskontra.$datatable_iv.fnDraw();
15481              }
15482
15483              if (pages.iv_laskutus_ja_reskontra.$datatable != null) {
15484                pages.iv_laskutus_ja_reskontra.$datatable.fnClearTable(0);
15485                pages.iv_laskutus_ja_reskontra.$datatable.fnDraw();
15486              }
15487
15488              LaskutusJaReskontra.showInvoiceDialog({
15489                invoiceId: invoice_id,
15490              });
15491            }
15492
15493            global.show_message(responseJSON);
15494            global.close_loading_dialog();
15495
15496            $dialog.dialog('close');
15497          },
15498          error: function (response) {
15499            global.close_loading_dialog();
15500            global.show_message($.parseJSON(response.responseText));
15501          },
15502        });
15503      });
15504
15505      $dialog = $('<div />', { style: 'text-align:left;' })
15506        .append($form)
15507        .dialog({
15508          autoOpen: true,
15509          modal: true,
15510          resizable: false,
15511          draggable: false,
15512          title: 'Lähetä laskukopio verkkolaskuna',
15513          beforeClose: function (event, ui) {
15514            event.stopPropagation();
15515          },
15516          buttons: {
15517            Peruuta: function () {
15518              $dialog.dialog('close');
15519            },
15520            'Lähetä laskukopio': function () {
15521              $form.submit();
15522            },
15523          },
15524        });
15525    }, //send_invoice_copy_by_e_invoice
15526
15527    insert_invoice_to_ledger: function(invoice_id) {
15528      $dialog = $('<div />', { style: 'text-align:left;' })
15529        .html(
15530          'Haluatko varmasti lähettää laskun reskontrattavaksi? HUOM! Asiakkaalle ei toimiteta laskua'
15531        )
15532        .dialog({
15533          autoOpen: true,
15534          modal: true,
15535          resizable: false,
15536          draggable: false,
15537          title: 'Lähetä lasku reskontraan',
15538          beforeClose: function (event, ui) {
15539            event.stopPropagation();
15540          },
15541          buttons: {
15542            Peruuta: function () {
15543              $dialog.dialog('close');
15544            },
15545            'Lähetä lasku': function () {
15546              $.ajax({
15547                dataType: 'json',
15548                type: 'POST',
15549                url: '/iv_laskutus_ja_reskontra/insert_invoice_to_ledger/' + invoice_id,
15550                beforeSend: function(request) {
15551                  global.showLoadingDialog('Lähetetään laskua...');
15552                },
15553                success: function (responseJSON) {
15554                  if (responseJSON.type == 'success') {
15555                    //Refresh the datatables
15556                    if (pages.iv_laskutus_ja_reskontra.$datatable_iv != null) {
15557                      pages.iv_laskutus_ja_reskontra.$datatable_iv.fnClearTable(0);
15558                      pages.iv_laskutus_ja_reskontra.$datatable_iv.fnDraw();
15559                    }
15560
15561                    if (pages.iv_laskutus_ja_reskontra.$datatable != null) {
15562                      pages.iv_laskutus_ja_reskontra.$datatable.fnClearTable(0);
15563                      pages.iv_laskutus_ja_reskontra.$datatable.fnDraw();
15564                    }
15565
15566                    if (pages.reskontra.$datatable != null) {
15567                      pages.reskontra.$datatable.fnClearTable(0);
15568                      pages.reskontra.$datatable.fnDraw();
15569                    }
15570
15571                    LaskutusJaReskontra.showInvoiceDialog({
15572                      invoiceId: invoice_id,
15573                    });
15574                  }
15575
15576                  global.show_message(responseJSON);
15577                  global.close_loading_dialog();
15578
15579                  $dialog.dialog('close');
15580                },
15581                error: function (response) {
15582                  global.close_loading_dialog();
15583                  global.show_message($.parseJSON(response.responseText));
15584                },
15585              });
15586            },
15587          },
15588        });
15589    }, //send_invoice_by_mail
15590
15591    send_invoice_by_sms: function (invoiceId, phone) {
15592      var $form = $('<form />').append(
15593        $('<p />').html('Anna puhelinnumero'),
15594        $('<input />', { type: 'text', name: 'toSms', id: 'toSms', class: 'text medium' }).val(
15595          phone
15596        )
15597      );
15598
15599      $form.submit(function (e) {
15600        e.preventDefault();
15601        var phone = document.getElementById('toSms').value;
15602        var data = {
15603          phone: phone,
15604          invoiceId: invoiceId,
15605        };
15606
15607        global.showLoadingDialog('Lähetetään lasku...');
15608
15609        $.ajax({
15610          url: '/ajax/send_invoice_by_sms/',
15611          dataType: 'json',
15612          type: 'POST',
15613          data: data,
15614        })
15615          .done(function (responseJSON) {
15616            $dialog.dialog('close');
15617            global.show_message(responseJSON);
15618            global.close_loading_dialog();
15619          })
15620          .fail(function (response) {
15621            var responseJSON = $.parseJSON(response.responseText);
15622            global.close_loading_dialog();
15623            global.show_message(responseJSON);
15624          });
15625      });
15626
15627      var $dialog = $('<div />', { style: 'text-align:left;' })
15628        .append($form)
15629        .dialog({
15630          width: 320,
15631          autoOpen: true,
15632          modal: true,
15633          resizable: false,
15634          draggable: false,
15635          beforeClose: function (event, ui) {
15636            event.stopPropagation();
15637          },
15638          close: function () {
15639            $(this).dialog('destroy');
15640            $(this).remove();
15641          },
15642          title: 'Lähetä lasku sms viestinä',
15643          buttons: {
15644            Peruuta: function () {
15645              $(this).dialog('close');
15646            },
15647            'Lähetä lasku': function () {
15648              $form.submit();
15649            },
15650          },
15651        });
15652    },
15653    send_invoice_by_email: function (invoice_id, email) {
15654      //console.log('send_invoice_by_email', 3406);
15655
15656      var $form = $('<form />', {
15657        method: 'POST',
15658        action: '/ajax/send_invoice_by_email/' + invoice_id,
15659      }).append(
15660        $('<p />').html('Anna sähköpostiosoite minne lasku lähetetään'),
15661        $('<input />', {
15662          type: 'text',
15663          name: 'send_to_email',
15664          id: 'send_to_email',
15665          class: 'text medium',
15666        }).val(email)
15667      );
15668
15669      $form.submit(function (e) {
15670        e.preventDefault();
15671
15672        $form.ajaxSubmit({
15673          dataType: 'json',
15674          type: 'POST',
15675
15676          beforeSend: function (request) {
15677            global.showLoadingDialog('Lähetetään laskua...');
15678          },
15679          success: function (responseJSON) {
15680            if (responseJSON.type == 'success') {
15681              $dialog.dialog('close');
15682
15683              //Refresh the datatables
15684              if (pages.iv_laskutus_ja_reskontra.$datatable_iv != null) {
15685                pages.iv_laskutus_ja_reskontra.$datatable_iv.fnClearTable(0);
15686                pages.iv_laskutus_ja_reskontra.$datatable_iv.fnDraw();
15687              }
15688
15689              if (pages.iv_laskutus_ja_reskontra.$datatable != null) {
15690                pages.iv_laskutus_ja_reskontra.$datatable.fnClearTable(0);
15691                pages.iv_laskutus_ja_reskontra.$datatable.fnDraw();
15692              }
15693
15694              if (pages.reskontra.$datatable != null) {
15695                pages.reskontra.$datatable.fnClearTable(0);
15696                pages.reskontra.$datatable.fnDraw();
15697              }
15698
15699              LaskutusJaReskontra.showInvoiceDialog({
15700                invoiceId: invoice_id,
15701              });
15702            }
15703
15704            global.show_message(responseJSON);
15705            global.close_loading_dialog();
15706          },
15707          error: function (response) {
15708            global.close_loading_dialog();
15709            global.show_message($.parseJSON(response.responseText));
15710          },
15711        });
15712      });
15713
15714      var $dialog = $('<div />', { style: 'text-align:left;' })
15715        .append($form)
15716        .dialog({
15717          width: 320,
15718          autoOpen: true,
15719          modal: true,
15720          resizable: false,
15721          draggable: false,
15722          beforeClose: function (event, ui) {
15723            event.stopPropagation();
15724          },
15725          title: 'Lähetä lasku sähköpostitse',
15726          buttons: {
15727            Peruuta: function () {
15728              $(this).dialog('close');
15729            },
15730            'Lähetä lasku': function () {
15731              $form.submit();
15732            },
15733          },
15734        });
15735    }, //send_invoice_by_email
15736
15737    send_invoice_copy_by_sms: function (invoiceId, phone) {
15738      var $form = $('<form />').append(
15739        $('<p />').html('Anna puhelinnumero'),
15740        $('<input />', { type: 'text', name: 'toSms', id: 'toSms', class: 'text medium' }).val(
15741          phone
15742        )
15743      );
15744
15745      $form.submit(function (e) {
15746        e.preventDefault();
15747        var phone = document.getElementById('toSms').value;
15748        var data = {
15749          phone: phone,
15750          invoiceId: invoiceId,
15751        };
15752
15753        global.showLoadingDialog('Lähetetään laskukopiota...');
15754
15755        $.ajax({
15756          url: '/ajax/send_invoice_copy_by_sms/',
15757          dataType: 'json',
15758          type: 'POST',
15759          data: data,
15760        })
15761          .done(function (responseJSON) {
15762            $dialog.dialog('close');
15763            global.show_message(responseJSON);
15764            global.close_loading_dialog();
15765          })
15766          .fail(function (response) {
15767            var responseJSON = $.parseJSON(response.responseText);
15768            global.close_loading_dialog();
15769            global.show_message(responseJSON);
15770          });
15771      });
15772
15773      var $dialog = $('<div />', { style: 'text-align:left;' })
15774        .append($form)
15775        .dialog({
15776          width: 320,
15777          autoOpen: true,
15778          modal: true,
15779          resizable: false,
15780          draggable: false,
15781          beforeClose: function (event, ui) {
15782            event.stopPropagation();
15783          },
15784          close: function () {
15785            $(this).dialog('destroy');
15786            $(this).remove();
15787          },
15788          title: 'Lähetä laskukopio sms viestinä',
15789          buttons: {
15790            Peruuta: function () {
15791              $(this).dialog('close');
15792            },
15793            'Lähetä lasku': function () {
15794              $form.submit();
15795            },
15796          },
15797        });
15798    },
15799    send_invoice_copy_by_email: function (invoice_id, email) {
15800      var $form = $('<form />').append(
15801        $('<p />').html('Anna sähköpostiosoite'),
15802        $('<input />', { type: 'text', name: 'toEmail', id: 'toEmail', class: 'text medium' }).val(
15803          email
15804        )
15805      );
15806
15807      $form.submit(function (e) {
15808        //Get the data from the form element
15809        var data = _.object(
15810          $form.serializeArray().map(function (v) {
15811            return [v.name, v.value];
15812          })
15813        );
15814
15815        //Add some extra data
15816        _.extend(data, { invoiceId: invoice_id });
15817
15818        e.preventDefault();
15819
15820        global.showLoadingDialog('Lähetetään laskukopiota...');
15821
15822        $.ajax({
15823          url: '/ajax/send_invoice_copy_by_email/',
15824          dataType: 'json',
15825          type: 'POST',
15826          data: data,
15827        })
15828          .done(function (responseJSON) {
15829            $dialog.dialog('close');
15830            global.show_message(responseJSON);
15831            global.close_loading_dialog();
15832          })
15833          .fail(function (response) {
15834            var responseJSON = $.parseJSON(response.responseText);
15835
15836            //	console.log('fail:', response);
15837            //	console.log($.parseJSON(response.responseText));
15838            global.close_loading_dialog();
15839            global.show_message(responseJSON);
15840          });
15841      });
15842
15843      var $dialog = $('<div />', { style: 'text-align:left;' })
15844        .append($form)
15845        .dialog({
15846          width: 320,
15847          autoOpen: true,
15848          modal: true,
15849          resizable: false,
15850          draggable: false,
15851          beforeClose: function (event, ui) {
15852            event.stopPropagation();
15853          },
15854          title: 'Lähetä laskukopio sähköpostitse',
15855          buttons: {
15856            Peruuta: function () {
15857              $(this).dialog('close');
15858            },
15859            'Lähetä lasku': function () {
15860              $form.submit();
15861            },
15862          },
15863        });
15864    }, //send_invoice_copy_by_email
15865
15866    send_credit_note_copy_by_email: function (invoice_id, email) {
15867      var $form = $('<form />').append(
15868        $('<p />').html('Anna sähköpostiosoite'),
15869        $('<input />', { type: 'text', name: 'toEmail', id: 'toEmail', class: 'text medium' }).val(
15870          email
15871        )
15872      );
15873
15874      $form.submit(function (e) {
15875        //Get the data from the form element
15876        var data = _.object(
15877          $form.serializeArray().map(function (v) {
15878            return [v.name, v.value];
15879          })
15880        );
15881
15882        //Add some extra data
15883        _.extend(data, { invoiceId: invoice_id });
15884
15885        e.preventDefault();
15886
15887        global.showLoadingDialog('Lähetetään hyvityslaskua...');
15888
15889        $.ajax({
15890          url: '/ajax/send_invoice_copy_by_email/',
15891          dataType: 'json',
15892          type: 'POST',
15893          data: data,
15894        })
15895          .done(function (responseJSON) {
15896            $dialog.dialog('close');
15897            global.show_message(responseJSON);
15898            global.close_loading_dialog();
15899          })
15900          .fail(function (response) {
15901            var responseJSON = $.parseJSON(response.responseText);
15902
15903            //	console.log('fail:', response);
15904            //	console.log($.parseJSON(response.responseText));
15905            global.close_loading_dialog();
15906            global.show_message(responseJSON);
15907          });
15908      });
15909
15910      var $dialog = $('<div />', { style: 'text-align:left;' })
15911        .append($form)
15912        .dialog({
15913          width: 320,
15914          autoOpen: true,
15915          modal: true,
15916          resizable: false,
15917          draggable: false,
15918          beforeClose: function (event, ui) {
15919            event.stopPropagation();
15920          },
15921          title: 'Lähetä laskukopio sähköpostitse',
15922          buttons: {
15923            Peruuta: function () {
15924              $(this).dialog('close');
15925            },
15926            'Lähetä lasku': function () {
15927              $form.submit();
15928            },
15929          },
15930        });
15931    }, //send_invoice_copy_by_email
15932
15933    send_invoice_copy: function (invoice_id, email) {
15934      $('<div></div>')
15935        .append(
15936          $('<p />', {}).append(
15937            $('<strong />', {}).html('Laskun tila:'),
15938            $('<br />'),
15939            $('<input />', {
15940              name: 'invoice_status',
15941              id: 'invoice_status_current',
15942              type: 'radio',
15943              value: 'current',
15944              checked: 'checked',
15945            }),
15946            $('<label />', {
15947              for: 'invoice_status_current',
15948              style: 'display:inline; float:none;',
15949            }).html('Nykyinen'),
15950            $('<br />'),
15951            $('<input />', {
15952              name: 'invoice_status',
15953              id: 'invoice_status_original',
15954              type: 'radio',
15955              value: 'original',
15956            }),
15957            $('<label />', {
15958              for: 'invoice_status_original',
15959              style: 'display:inline; float:none;',
15960            }).html('Alkuperäinen')
15961          ),
15962          $('<p />', {}).append(
15963            $('<strong />', {}).html('Laskun toimitus:'),
15964            $('<br />'),
15965            $('<input />', {
15966              name: 'invoice_status',
15967              id: 'invoice_status_current',
15968              type: 'radio',
15969              value: 'current',
15970              checked: 'checked',
15971            }),
15972            $('<label />', {
15973              for: 'invoice_status_current',
15974              style: 'display:inline; float:none;',
15975            }).html('Nykyinen'),
15976            $('<br />'),
15977            $('<input />', {
15978              name: 'invoice_status',
15979              id: 'invoice_status_original',
15980              type: 'radio',
15981              value: 'original',
15982            }),
15983            $('<label />', {
15984              for: 'invoice_status_original',
15985              style: 'display:inline; float:none;',
15986            }).html('Alkuperäinen')
15987          )
15988        )
15989        .dialog({
15990          autoOpen: true,
15991          modal: true,
15992          resizable: false,
15993          draggable: false,
15994          title: 'Valitse PDF-laskun asetukset',
15995          beforeClose: function (event, ui) {
15996            event.stopPropagation();
15997          },
15998          buttons: {
15999            Sulje: function () {
16000              $(this).dialog('close');
16001            },
16002            'Lataa PDF-tiedosto': function () {
16003              var invoice_status = $(this).find('input:radio[name=invoice_status]:checked').val();
16004              var envelope_window_size = $(this)
16005                .find('input:radio[name=envelope_window_size]:checked')
16006                .val();
16007              window.location =
16008                'iv_laskutus_ja_reskontra/get_pdf_invoice/' +
16009                invoice_id +
16010                '/' +
16011                invoice_status +
16012                '/' +
16013                envelope_window_size +
16014                '/download';
16015            },
16016          },
16017        });
16018
16019      var $form = $('<form />').append(
16020        $('<p />').html('Anna sähköpostiosoite'),
16021        $('<input />', { type: 'text', name: 'toEmail', id: 'toEmail', class: 'text medium' }).val(
16022          email
16023        )
16024      );
16025
16026      $form.submit(function (e) {
16027        //Get the data from the form element
16028        var data = _.object(
16029          $form.serializeArray().map(function (v) {
16030            return [v.name, v.value];
16031          })
16032        );
16033
16034        //Add some extra data
16035        _.extend(data, { invoiceId: invoice_id });
16036
16037        e.preventDefault();
16038
16039        global.showLoadingDialog('Lähetetään laskukopiota...');
16040
16041        $.ajax({
16042          url: '/ajax/send_invoice_copy_by_email/',
16043          dataType: 'json',
16044          type: 'POST',
16045          data: data,
16046        })
16047          .done(function (responseJSON) {
16048            $dialog.dialog('close');
16049            global.show_message(responseJSON);
16050            global.close_loading_dialog();
16051          })
16052          .fail(function (response) {
16053            var responseJSON = $.parseJSON(response.responseText);
16054
16055            //	console.log('fail:', response);
16056            //	console.log($.parseJSON(response.responseText));
16057            global.close_loading_dialog();
16058            global.show_message(responseJSON);
16059          });
16060      });
16061
16062      var $dialog = $('<div />', { style: 'text-align:left;' })
16063        .append($form)
16064        .dialog({
16065          width: 320,
16066          autoOpen: true,
16067          modal: true,
16068          resizable: false,
16069          draggable: false,
16070          beforeClose: function (event, ui) {
16071            event.stopPropagation();
16072          },
16073          title: 'Lähetä laskukopio sähköpostitse',
16074          buttons: {
16075            Peruuta: function () {
16076              $(this).dialog('close');
16077            },
16078            'Lähetä lasku': function () {
16079              $form.submit();
16080            },
16081          },
16082        });
16083    }, //send_invoice_copy
16084
16085    show_edit_invoice_status_dialog: function (invoice_id) {
16086      var d = new Date();
16087
16088      var $edit_invoice_status_dialog = $('<div></div>');
16089
16090      $edit_invoice_status_dialog
16091        .append(
16092          $('<label />', {})
16093            .html('Uusi tila:')
16094            .append(
16095              $('<select />', { name: 'invoice_status', id: 'invoice_status' }).append(
16096                $('<option />', { value: 'sent' }).html('Avoin'),
16097                $('<option />', { value: 'credited' }).html('Hyvitetty'),
16098                $('<option />', { value: 'money_transferred' }).html('Tilitetty')
16099              )
16100            )
16101        )
16102        .dialog({
16103          width: 400,
16104          height: 350,
16105          autoOpen: true,
16106          modal: true,
16107          resizable: false,
16108          draggable: false,
16109          open: function () {
16110            $(this).find('#invoice_status').selectpicker();
16111          },
16112          title: 'Muuta laskun tila',
16113          beforeClose: function (event, ui) {
16114            event.stopPropagation();
16115          },
16116          buttons: {
16117            Peruuta: function () {
16118              $(this).dialog('close');
16119            },
16120            Tallenna: function () {
16121              var new_status = $(this).find('#invoice_status').val();
16122
16123              if (new_status === 'paid_to_customer') {
16124                var $paid_to_customer_date_dialog = $('<div></div>');
16125                var $paid_to_customer_datepicker = $(
16126                  '<input type="text" class="text small" id="paid_to_customer_date" name="paid_to_customer_date" value="' +
16127                    d.getDate() +
16128                    '.' +
16129                    (d.getMonth() + 1) +
16130                    '.' +
16131                    d.getFullYear() +
16132                    '" />'
16133                );
16134
16135                $paid_to_customer_date_dialog
16136                  .append(
16137                    $(
16138                      '<label style="width:280px;" id="paid_to_customer_date_label" for="paid_to_customer_date">Päiväämärä jolloin lasku on suoritettu asiakkaalle</label>'
16139                    ),
16140                    $paid_to_customer_datepicker.datepicker($.datepicker.regional.fi)
16141                  )
16142                  .dialog({
16143                    width: 320,
16144                    height: 240,
16145                    autoOpen: true,
16146                    modal: true,
16147                    resizable: false,
16148                    draggable: false,
16149                    title: 'Anna ohisuorituksen päivämäärä',
16150                    beforeClose: function (event, ui) {
16151                      event.stopPropagation();
16152                    },
16153                    buttons: {
16154                      Peruuta: function () {
16155                        $paid_to_customer_date_dialog.dialog('destroy');
16156                      },
16157                      Hyväksy: function () {
16158                        var send_credit_invoice_to_customer = +$paid_to_customer_date_dialog
16159                          .find('#send_credit_invoice_to_customer')
16160                          .is(':checked');
16161                        var selectedDate = new Date(
16162                          $paid_to_customer_datepicker.datepicker('getDate').getTime()
16163                        );
16164                        var datestr =
16165                          selectedDate.getFullYear() +
16166                          '-' +
16167                          (selectedDate.getMonth() + 1) +
16168                          '-' +
16169                          selectedDate.getDate();
16170                        pages.iv_laskutus_ja_reskontra.update_invoice_status(
16171                          invoice_id,
16172                          new_status,
16173                          datestr,
16174                          send_credit_invoice_to_customer
16175                        );
16176                        $paid_to_customer_date_dialog.dialog('destroy');
16177                        $edit_invoice_status_dialog.dialog('close');
16178                      },
16179                    },
16180                  });
16181              } else {
16182                pages.iv_laskutus_ja_reskontra.update_invoice_status(invoice_id, new_status);
16183                $(this).dialog('close');
16184              }
16185            },
16186          },
16187        });
16188    },
16189
16190    update_invoice_status: function (
16191      invoice_id,
16192      new_status,
16193      date,
16194      send_credit_invoice_to_customer
16195    ) {
16196      $.ajax({
16197        dataType: 'json',
16198        type: 'POST',
16199        url: 'iv_laskutus_ja_reskontra/update_invoice_status/',
16200        data: {
16201          invoice_id: invoice_id,
16202          new_status: new_status,
16203          date: date,
16204          send_credit_invoice_to_customer: send_credit_invoice_to_customer,
16205        },
16206
16207        beforeSend: function (request) {
16208          global.showLoadingDialog('Vaihdetaan laskun tilaa');
16209        },
16210        success: function (responseJSON) {
16211          global.close_loading_dialog();
16212
16213          //Refresh the datatables
16214          if (pages.iv_laskutus_ja_reskontra.$datatable_iv != null) {
16215            pages.iv_laskutus_ja_reskontra.$datatable_iv.fnClearTable(0);
16216            pages.iv_laskutus_ja_reskontra.$datatable_iv.fnDraw();
16217          }
16218
16219          if (pages.iv_laskutus_ja_reskontra.$datatable != null) {
16220            pages.iv_laskutus_ja_reskontra.$datatable.fnClearTable(0);
16221            pages.iv_laskutus_ja_reskontra.$datatable.fnDraw();
16222          }
16223
16224          //Refresh the invoice dialog
16225          global.show_message(responseJSON);
16226
16227          LaskutusJaReskontra.showInvoiceDialog({
16228            invoiceId: invoice_id,
16229          });
16230        },
16231        error: function (data) {
16232          global.show_message($.parseJSON(data.responseText));
16233          global.close_loading_dialog();
16234        },
16235      });
16236    },
16237
16238    init_show_money_transfer: function (money_transfer_id) {
16239      $('#money-transfer-items-tabs').tabs();
16240
16241      $('#money_transfers_form').submit(function () {
16242        $(this).ajaxSubmit({
16243          type: 'post',
16244          dataType: 'json',
16245          //show the loading message
16246          beforeSubmit: function () {
16247            global.showLoadingDialog('Merkitään tilityksiä...');
16248          },
16249
16250          success: function (responseJSON, statusText, xhr, $form) {
16251            if (responseJSON.type === 'success') {
16252              //Refresh the datatable and the dialog close the dialog
16253              dialogs.refresh();
16254              pages.iv_laskutus_ja_reskontra.$datatable_money_transfers.fnClearTable(0);
16255              pages.iv_laskutus_ja_reskontra.$datatable_money_transfers.fnDraw();
16256            }
16257
16258            global.show_message(responseJSON);
16259            global.close_loading_dialog();
16260          },
16261          error: function (data) {
16262            global.close_loading_dialog();
16263          },
16264        });
16265
16266        return false;
16267      });
16268
16269      $('#mark_money_transfers')
16270        .button({ icons: { primary: 'ui-icon-check' } })
16271        .on('click', function () {
16272          $('#money_transfers_form').attr('action', 'tilitykset/mark_items_accepted_for_transfer');
16273          $('#money_transfers_form').submit();
16274        });
16275
16276      $('#process_money_transfers')
16277        .button({ icons: { primary: 'ui-icon-check' } })
16278        .on('click', function () {
16279          $('#money_transfers_form').attr('action', 'tilitykset/mark_items_transferred');
16280          $('#money_transfers_form').submit();
16281        });
16282
16283      $('#execute_accepted_transfers')
16284        .button({ icons: { primary: 'ui-icon-check' } })
16285        .on('click', function () {
16286          pages.iv_laskutus_ja_reskontra.execute_accepted_money_transfers(money_transfer_id);
16287        });
16288
16289      $('#add_invoice_to_money_transfer')
16290        .button({ icons: { primary: 'ui-icon-refresh' } })
16291        .on('click', function () {
16292          $('<div></div>')
16293            .html('Syötä laskun ID jonka haluat lisättävän t
16293ilitettäväksi')
16294            .dialog({
16295              autoOpen: true,
16296              modal: true,
16297              resizable: false,
16298              draggable: false,
16299              title: 'Lisää yksittäinen lasku tilitykseen',
16300              beforeClose: function (event, ui) {
16301                event.stopPropagation();
16302              },
16303              buttons: {
16304                Peruuta: function () {
16305                  $(this).dialog('close');
16306                },
16307                Lisää: function () {
16308                  $(this).dialog('close');
16309                  pages.iv_laskutus_ja_reskontra.add_invoice_to_money_transfer(
16310                    money_transfer_id,
16311                    invoice_id
16312                  );
16313                },
16314              },
16315            });
16316        });
16317
16318      $('#refresh_money_transfer')
16319        .button({ icons: { primary: 'ui-icon-refresh' } })
16320        .on('click', function () {
16321          $('<div></div>')
16322            .html(
16323              'Haluatko varmasti päivittää tilitysten tiedot? <br/><br/>Vähennykset sekä IBAN tieto haetaan uudestaan'
16324            )
16325            .dialog({
16326              autoOpen: true,
16327              modal: true,
16328              resizable: false,
16329              draggable: false,
16330              title: 'Päivitä tilitysten tiedot',
16331              beforeClose: function (event, ui) {
16332                event.stopPropagation();
16333              },
16334              buttons: {
16335                Peruuta: function () {
16336                  $(this).dialog('close');
16337                },
16338                Päivitä: function () {
16339                  $(this).dialog('close');
16340                  pages.iv_laskutus_ja_reskontra.refresh_money_transfer(money_transfer_id);
16341                },
16342              },
16343            });
16344        });
16345
16346      $('#money_transfer_items .copy_to_clipboard').on('click', function (e) {
16347        e.preventDefault();
16348        var bank_barcode = $(this).attr('href');
16349        window.prompt('Kopioi pankkiviivakoodi ja paina ok', bank_barcode);
16350      });
16351
16352      $('#money_transfer_items .toggle_invoices').on('click', function (e) {
16353        e.preventDefault();
16354        $(this).parents('tr').next().toggle();
16355      });
16356
16357      $('#money_transfer_items .toggle_service_charges').on('click', function (e) {
16358        e.preventDefault();
16359        $(this).parents('tr').next().next().toggle();
16360      });
16361
16362      $('#money_transfer_items .toggle').on('click', function (e) {
16363        e.preventDefault();
16364        $link = $(this);
16365
16366        checked = $link.hasClass('checked');
16367
16368        if (!checked) {
16369          checked = true;
16370          $link.addClass('checked');
16371        } else {
16372          checked = false;
16373          $link.removeClass('checked');
16374        }
16375
16376        var col_index = $link.parents('th').index();
16377
16378        $link
16379          .parents('table')
16380          .find('tbody tr')
16381          .each(function (i, e) {
16382            $(e)
16383              .find('td:eq(' + col_index + ') input')
16384              .prop('checked', checked);
16385          });
16386      });
16387
16388      $('#money_transfer_items .check_all').on('click', function (e) {
16389        e.preventDefault();
16390        $link = $(this);
16391
16392        var col_index = $link.parents('th').index();
16393
16394        $link
16395          .parents('table')
16396          .find('tbody tr')
16397          .each(function (i, e) {
16398            $(e)
16399              .find('td:eq(' + col_index + ') input')
16400              .prop('checked', true);
16401          });
16402
16403        $link.removeClass('check_all').addClass('uncheck_all');
16404      });
16405    }, //init_show_invoice
16406
16407    refresh_money_transfer: function (money_transfer_id) {
16408      $.ajax({
16409        processData: false,
16410        dataType: 'json',
16411        type: 'GET',
16412        url: 'ajax/refresh_money_transfer/' + money_transfer_id + '/',
16413        beforeSend: function (request) {
16414          global.showLoadingDialog('Päivitetään tilityksiä...');
16415        },
16416        success: function (responseJSON) {
16417          global.close_loading_dialog();
16418          global.show_message(responseJSON);
16419          dialogs.refresh();
16420        },
16421      });
16422    },
16423
16424    create_money_transfer_from_invoices: function (invoices) {
16425      $.ajax({
16426        processData: false,
16427        dataType: 'json',
16428        type: 'POST',
16429        url:
16430          'ajax/create_money_transfer_from_invoices/' + money_transfer_id + '/' + invoice_id + '/',
16431        beforeSend: function (request) {
16432          global.showLoadingDialog('Lisätään laskua tilitykseen...');
16433        },
16434        success: function (responseJSON) {
16435          global.close_loading_dialog();
16436          global.show_message(responseJSON);
16437          dialogs.refresh();
16438        },
16439      });
16440    },
16441
16442    show_invoice_log: function (invoice_id) {
16443      var $dialog = $('<div />');
16444
16445      if (invoice_id.length > 0) {
16446        $.ajax({
16447          processData: false,
16448          dataType: 'html',
16449          type: 'GET',
16450          url: 'reskontra/get_invoice_log_html/' + invoice_id + '/',
16451          beforeSend: function (request) {
16452            $dialog.dialog({
16453              width: 650,
16454              height: 450,
16455              title: 'Laskun tapahtumaloki',
16456              buttons: {
16457                'Lisää muistiinpano': function() {
16458                  pages.iv_laskutus_ja_reskontra.add_log_item(invoice_id);
16459                },
16460              },
16461              close: function (e) {
16462                e.stopPropagation();
16463                $('div#logs').remove();
16464                $('div#convo').remove();
16465                $dialog.dialog('destroy');
16466                $dialog.remove();
16467              },
16468            });
16469            global.show_ajax_loader($dialog);
16470          },
16471          success: function (response) {
16472            $dialog.html(response);
16473            // Tabs for tought.
16474            $('.invoiceLogTabs').tabs();
16475            $('div#convo article').each(function (index, article) {
16476              $('button.showTicket:first').addClass('active');
16477              if (index > 0) {
16478                $(article).addClass('ticket-hidden');
16479              }
16480            });
16481
16482            $(
16483              "span:contains('This e-mail and any attachment may contain confidential and/or proprietary information')"
16484            ).addClass('trash');
16485            $(
16486              "span:contains('immediately and destroy this e-mail and all of the contained information.')"
16487            ).addClass('trash');
16488            $(
16489              "span:contains('arvato Financial Solutions is a global financial service provider')"
16490            ).addClass('trash');
16491            $("span:contains('22 countries, including a strong presence in Europe')").addClass(
16492              'trash'
16493            );
16494            $("span:contains('cash flow in all phases of the customer lifecycle')").addClass(
16495              'trash'
16496            );
16497            $(
16498              "span:contains('customers making us Europe’s third largest integrated financial service provider')"
16499            ).addClass('trash');
16500            $("span:contains('---------------------------------')").addClass('trash');
16501            $(
16502              "span:contains('Gothia Financial Group is a part of the German company arvato 
16502infoscore')"
16503            ).addClass('trash');
16504            $("span:contains('Follow us on •')").parent().addClass('trash');
16505            //$('span:blank').remove();
16506            //$('div:blank').remove();
16507
16508            //Add special click handler to show towing record popup instead of redirecting user to towing record page
16509            $dialog.on('click', 'a.show_towing_record', function (e) {
16510              e.preventDefault();
16511              $dialog.dialog('close');
16512              var url = $(this).data('url');
16513              console.log('show_towing_record', url);
16514              kuormakirjat.show_towing_record(url);
16515            });
16516          },
16517        });
16518      }
16519    }, //show_invoice_log
16520
16521    show_part_payment: function (part_payment_id) {
16522      // global.$dialog = $('<div />', {});
16523      // var $dialog = global.$dialog;
16524
16525      // if ($dialog.hasClass('ui-dialog-content')) {
16526      //   $dialog.dialog('destroy');
16527      // }
16528      var $dialog = global.getGlobalDialogAndEmptyIfHasContent();
16529
16530      $.ajax({
16531        processData: false,
16532        dataType: 'html',
16533        type: 'GET',
16534        url: 'osamaksu/get_part_payment_dialog/' + part_payment_id + '/',
16535        beforeSend: function (request) {
16536          $dialog.dialog({
16537            width: 800,
16538            height: 600,
16539            modal: true,
16540            resizable: false,
16541            title: 'Osamaksusopimuksen tiedot',
16542            close: function () {
16543              $dialog.dialog('close');
16544            },
16545          });
16546          global.show_ajax_loader($dialog);
16547        },
16548        success: function (response) {
16549          $dialog.html(response);
16550          /*
16551						$(this).delegate(':button','click',function(){
16552							$(this).data({'invoice_id': invoice_id, 'open_sum':open_sum});
16553						});
16554					*/
16555        },
16556      });
16557    }, //show_part_payment
16558
16559    init_part_payment_dialog: function (part_payment_id) {
16560      $('#accept_for_money_transfer')
16561        .button({ icons: { primary: 'ui-icon-check' } })
16562        .on('click', function () {
16563          $('<div></div>')
16564            .html(
16565              '<p>Haluatko varmasti hyväksyä osamaksusopimuksen tilitettäväksi?</p><p>Osamaksusopimus siirtyy tilityksiin heti kun kyseisen sopimuksen rahoituksen ehdot ovat täyttyneet ja suoritteet saapuneet Gothialta.</p>'
16566            )
16567            .dialog({
16568              width: 400,
16569              autoOpen: true,
16570              modal: true,
16571              resizable: false,
16572              draggable: false,
16573              title: 'Hyväksy osamaksusopimus tilitettäväksi',
16574              beforeClose: function (event, ui) {
16575                event.stopPropagation();
16576              },
16577              buttons: {
16578                Peruuta: function () {
16579                  $(this).dialog('close');
16580                },
16581                Hyväksy: function () {
16582                  $(this).dialog('close');
16583                  pages.iv_laskutus_ja_reskontra.accept_for_money_transfer(part_payment_id);
16584                },
16585              },
16586            });
16587        });
16588
16589      $('#create_part_payment_invoice')
16590        .button({ icons: { primary: 'ui-icon-plusthick' } })
16591        .on('click', function () {
16592          $('<div></div>')
16593            .html('Haluatko varmasti luoda tililaskun?')
16594            .dialog({
16595              autoOpen: true,
16596              modal: true,
16597              resizable: false,
16598              draggable: false,
16599              title: 'Luo tililasku',
16600              beforeClose: function (event, ui) {
16601                event.stopPropagation();
16602              },
16603              close: function () {
16604                $(this).dialog('destroy');
16605                $(this).remove();
16606              },
16607              buttons: {
16608                Peruuta: function () {
16609                  $(this).dialog('close');
16610                },
16611                'Luo tililasku': function () {
16612                  $(this).dialog('close');
16613                  pages.iv_laskutus_ja_reskontra.create_part_payment_invoice(part_payment_id);
16614                },
16615              },
16616            });
16617        });
16618
16619      $('#create_down_payment_invoice')
16620        .button({ icons: { primary: 'ui-icon-plusthick' } })
16621        .on('click', function () {
16622          $('<div></div>')
16623            .html('Haluatko varmasti luoda käsirahalaskun')
16624            .dialog({
16625              autoOpen: true,
16626              modal: true,
16627              resizable: false,
16628              draggable: false,
16629              title: 'Luo käsirahalasku',
16630              beforeClose: function (event, ui) {
16631                event.stopPropagation();
16632              },
16633              close: function () {
16634                $(this).dialog('destroy');
16635                $(this).remove();
16636              },
16637              buttons: {
16638                Peruuta: function () {
16639                  $(this).dialog('close');
16640                },
16641                'Luo käsirahalasku': function () {
16642                  $(this).dialog('close');
16643                  pages.iv_laskutus_ja_reskontra.create_down_payment_invoice(part_payment_id);
16644                },
16645              },
16646            });
16647        });
16648
16649      $('#approve_application')
16650        .button({ icons: { primary: 'ui-icon-check' } })
16651        .on('click', function () {
16652          $('<div></div>')
16653            .html('Haluatko varmasti hyväksyä osamaksusopimuksen')
16654            .dialog({
16655              autoOpen: true,
16656              modal: true,
16657              resizable: false,
16658              draggable: false,
16659              title: 'Hyväksy osamaksusopimus',
16660              beforeClose: function (event, ui) {
16661                event.stopPropagation();
16662              },
16663              close: function () {
16664                $(this).dialog('destroy');
16665                $(this).remove();
16666              },
16667              buttons: {
16668                Peruuta: function () {
16669                  $(this).dialog('close');
16670                },
16671                'Hyväksy osamaksusopimus': function () {
16672                  $(this).dialog('close');
16673                  pages.iv_laskutus_ja_reskontra.approve_part_payment_application(part_payment_id);
16674                },
16675              },
16676            });
16677        });
16678
16679      $('#decline_application')
16680        .button({ icons: { primary: 'ui-icon-close' } })
16681        .on('click', function () {
16682          $('<div></div>')
16683            .append(
16684              $('<label />', { style: 'width:auto;' })
16685                .html('Syy hylkäämiselle')
16686                .append(
16687                  $('<textarea />', { style: 'width:240px; height:36px;', name: 'decline_reason' })
16688                )
16689            )
16690            .dialog({
16691              autoOpen: true,
16692              modal: true,
16693              resizable: false,
16694              draggable: false,
16695              title: 'Hylkää osamaksusopimus',
16696              beforeClose: function (event, ui) {
16697                event.stopPropagation();
16698              },
16699              close: function () {
16700                $(this).dialog('destroy');
16701                $(this).remove();
16702              },
16703              buttons: {
16704                Peruuta: function () {
16705                  $(this).dialog('close');
16706                },
16707                'Hylkää sopimus': function () {
16708                  $(this).dialog('close');
16709                  var decline_reason = $(this).find('textarea[name=decline_reason]').val();
16710                  pages.iv_laskutus_ja_reskontra.decline_part_payment_contract(
16711                    part_payment_id,
16712                    decline_reason
16713                  );
16714                },
16715              },
16716            });
16717        });
16718
16719      $('#cancel_contract')
16720        .button({ icons: { primary: 'ui-icon-close' } })
16721        .on('click', function () {
16722          $('<div></div>')
16723            .append(
16724              $('<label />', { style: 'width:auto;' })
16725                .html('Syy peruuttamiselle')
16726                .append(
16727                  $('<textarea />', { style: 'width:240px; height:36px;', name: 'cancel_reason' })
16728                )
16729            )
16730            .dialog({
16731              autoOpen: true,
16732              modal: true,
16733              resizable: false,
16734              draggable: false,
16735              title: 'Peruuta osamaksusopimus',
16736              beforeClose: function (event, ui) {
16737                event.stopPropagation();
16738              },
16739              close: function () {
16740                $(this).dialog('destroy');
16741                $(this).remove();
16742              },
16743              buttons: {
16744                Poistu: function () {
16745                  $(this).dialog('close');
16746                },
16747                'Peruuta sopimus': function () {
16748                  $(this).dialog('close');
16749                  var cancel_reason = $(this).find('textarea[name=cancel_reason]').val();
16750                  pages.iv_laskutus_ja_reskontra.cancel_part_payment_contract(
16751                    part_payment_id,
16752                    cancel_reason
16753                  );
16754                },
16755              },
16756            });
16757        });
16758
16759      $('#delete_contract')
16760        .button({ icons: { primary: 'ui-icon-trash' } })
16761        .on('click', function () {
16762          $('<div></div>')
16763            .html('Haluatko varmasti poistaa osamaksusopimuksen?')
16764            .dialog({
16765              autoOpen: true,
16766              modal: true,
16767              resizable: false,
16768              draggable: false,
16769              title: 'Poista osamaksusopimus',
16770              beforeClose: function (event, ui) {
16771                event.stopPropagation();
16772              },
16773              close: function () {
16774                $(this).dialog('destroy');
16775                $(this).remove();
16776              },
16777              buttons: {
16778                Peruuta: function () {
16779                  $(this).dialog('close');
16780                },
16781                'Poista sopimus': function () {
16782                  pages.iv_laskutus_ja_reskontra.delete_part_payment_contract(part_payment_id);
16783                  $(this).dialog('close');
16784                },
16785              },
16786            });
16787        });
16788
16789      $('#convert_to_invoice')
16790        .button({ icons: { primary: 'ui-icon-transferthick-e-w' } })
16791        .on('click', function () {
16792          $('<div></div>')
16793            .html('Haluatko varmasti muuntaa osamaksusopimuksen laskuksi?')
16794            .append(
16795              '<br/><br/><input id="addCancellationFee" type="checkbox" name="addCancellationFee" value="1" disabled="disabled"><span>Lisää peruutuskulu laskulle</span>'
16796            )
16797            .dialog({
16798              autoOpen: true,
16799              modal: true,
16800              resizable: false,
16801              draggable: false,
16802              title: 'Muunna osamaksusopimus laskuksi',
16803              beforeClose: function (event, ui) {
16804                event.stopPropagation();
16805              },
16806              close: function () {
16807                $(this).dialog('destroy');
16808                $(this).remove();
16809              },
16810              buttons: {
16811                Peruuta: function () {
16812                  $(this).dialog('close');
16813                },
16814                'Muunna sopimus': function () {
16815                  var addCancellationFee = +$(this).find('#addCancellationFee').is(':checked');
16816
16817                  $(this).dialog('close');
16818                  pages.iv_laskutus_ja_reskontra.convert_part_payment_contract_to_invoice(
16819                    part_payment_id,
16820                    addCancellationFee
16821                  );
16822                },
16823              },
16824            });
16825        });
16826
16827      $('#accept_customer_account_terms')
16828        .button({ icons: { primary: 'ui-icon-check' } })
16829        .on('click', function () {
16830          $('<div></div>')
16831            .html('Haluatko varmasti merkitä asiakkaan Rivertyn tiliehdot hyväksytyksi?')
16832            .append(
16833              $('<label />', { style: 'width:auto;' })
16834                .html('Selite hyväksynnälle')
16835                .append(
16836                  $('<textarea />', {
16837                    style: 'width:320px; height:60px;',
16838                    name: 'acceptance_description',
16839                  })
16840                )
16841            )
16842            .dialog({
16843              width: 360,
16844              autoOpen: true,
16845              modal: true,
16846              resizable: false,
16847              draggable: false,
16848              title: 'Merkitse Rivertyn tiliehdot hyväksytyksi',
16849              beforeClose: function (event, ui) {
16850                event.stopPropagation();
16851              },
16852              close: function () {
16853                $(this).dialog('destroy');
16854                $(this).remove();
16855              },
16856              buttons: {
16857                Peruuta: function () {
16858                  $(this).dialog('close');
16859                },
16860                'Merkitse hyväksytyksi': function () {
16861                  var acceptanceDescription = $(this)
16862                    .find('textarea[name=acceptance_description]')
16863                    .val();
16864
16865                  $(this).dialog('close');
16866                  global.showLoadingDialog('Merkitään tiliehtoja hyväksytyksi...');
16867
16868                  var data = {
16869                    part_payment_id: part_payment_id,
16870                    acceptance_description: acceptanceDescription,
16871                  };
16872                  $.ajax({
16873                    url: 'osamaksu/accept_customer_account_Terms/',
16874                    type: 'post',
16875                    data: data,
16876                    success: function (resp) {
16877                      global.close_loading_dialog();
16878                      global.show_message(resp);
16879                    },
16880                  });
16881                },
16882              },
16883            });
16884        });
16885
16886      $('#add_log_item')
16887        .button({ icons: { primary: 'ui-icon-plusthick' } })
16888        .on('click', function () {
16889          $('<div></div>')
16890            .append(
16891              $('<label />', { style: 'width:auto;' })
16892                .html('Lokitapahtuma')
16893                .append(
16894                  $('<textarea />', { style: 'width:320px; height:60px;', name: 'log_event' })
16895                )
16896            )
16897            .dialog({
16898              width: 360,
16899              autoOpen: true,
16900              modal: true,
16901              resizable: false,
16902              draggable: false,
16903              title: 'Lisää muistiinpano',
16904              beforeClose: function (event, ui) {
16905                event.stopPropagation();
16906              },
16907              close: function () {
16908                $(this).dialog('destroy');
16909                $(this).remove();
16910              },
16911              buttons: {
16912                Peruuta: function () {
16913                  $(this).dialog('close');
16914                },
16915                'Luo lokimerkintä': function () {
16916                  $(this).dialog('close');
16917                  global.showLoadingDialog('Luodaan lokimerkintää...');
16918
16919                  var logEvent = $(this).find('textarea[name=log_event]').val();
16920
16921                  var data = { part_payment_id: part_payment_id, log_event: logEvent };
16922                  $.ajax({
16923                    url: 'osamaksu/add_log_item/',
16924                    type: 'post',
16925                    data: data,
16926                    success: function (resp) {
16927                      global.close_loading_dialog();
16928                      global.show_message(resp);
16929                    },
16930                  });
16931                },
16932              },
16933            });
16934          $('button').addClass('btn btn-default');
16935        });
16936
16937      $('#approve_and_send_signature_invitation')
16938        .button({ icons: { primary: 'ui-icon-mail-closed' } })
16939        .on('click', function () {
16940          //console.log('enter_email_dialog', 5976);
16941          var customer_email = $('#customer_email').html();
16942          var $email_input = $('<input />', {
16943            type: 'text',
16944            name: 'email',
16945            id: 'email',
16946            class: 'text medium',
16947          }).val(customer_email);
16948          $('<div />', { style: 'text-align:left;' })
16949            .append(
16950              $('<p />').html('Syötä sähköpostiosoite minne allekirjoituskutsu lähetetään'),
16951              $email_input
16952            )
16953            .dialog({
16954              width: 320,
16955              autoOpen: true,
16956              modal: true,
16957              resizable: false,
16958              draggable: false,
16959              beforeClose: function (event, ui) {
16960                event.stopPropagation();
16961              },
16962              title: 'Hyväksy sopimus ja lähetä allekirjoituskutsu sähköpostiin',
16963              buttons: {
16964                Lähetä: function () {
16965               
16965   $(this).dialog('close');
16966                  email = $email_input.val();
16967                  pages.iv_laskutus_ja_reskontra.approve_and_send_signature_invitation(
16968                    part_payment_id,
16969                    email
16970                  );
16971                },
16972                Peruuta: function () {
16973                  $(this).dialog('close');
16974                },
16975              },
16976            });
16977        });
16978
16979      $('#send_signature_invitation')
16980        .button({ icons: { primary: 'ui-icon-mail-closed' } })
16981        .on('click', function () {
16982          //console.log('enter_email_dialog', 5976);
16983          var customer_email = $('#customer_email').html();
16984          var $email_input = $('<input />', {
16985            type: 'text',
16986            name: 'email',
16987            id: 'email',
16988            class: 'text medium',
16989          }).val(customer_email);
16990          $('<div />', { style: 'text-align:left;' })
16991            .append(
16992              $('<p />').html('Syötä sähköpostiosoite minne allekirjoituskutsu lähetetään'),
16993              $email_input
16994            )
16995            .dialog({
16996              width: 320,
16997              autoOpen: true,
16998              modal: true,
16999              resizable: false,
17000              draggable: false,
17001              beforeClose: function (event, ui) {
17002                event.stopPropagation();
17003              },
17004              title: 'Lähetä allekirjoituskutsu sähköpostiin',
17005              buttons: {
17006                Lähetä: function () {
17007                  $(this).dialog('close');
17008                  email = $email_input.val();
17009                  pages.iv_laskutus_ja_reskontra.send_signature_invitation(part_payment_id, email);
17010                },
17011                Peruuta: function () {
17012                  $(this).dialog('close');
17013                },
17014              },
17015            });
17016        });
17017
17018      $('#send_customer_acceptance_invitation')
17019        .button({ icons: { primary: 'ui-icon-mail-closed' } })
17020        .on('click', function () {
17021          //console.log('enter_email_dialog', 5976);
17022          var customer_email = $('#customer_email').html();
17023          var $email_input = $('<input />', {
17024            type: 'text',
17025            name: 'email',
17026            id: 'email',
17027            class: 'text medium',
17028          }).val(customer_email);
17029
17030          var customer_phone = $('#customer_phone').html();
17031          var $phone_input = $('<input />', {
17032            type: 'text',
17033            name: 'email',
17034            id: 'email',
17035            class: 'text medium',
17036          }).val(customer_phone);
17037
17038          $('<div />', { style: 'text-align:left;' })
17039            .append(
17040              $('<p />').html(
17041                'Sähköposti ja puhelinnumero, minne linkki maksusopimuksen ja tiliehtojen hyväksyntään lähetetään'
17042              ),
17043              $('<label />', { text: 'Sähköposti' }),
17044              $email_input,
17045              $('<label />', { text: 'Puhelinnumero' }),
17046              $phone_input
17047            )
17048            .dialog({
17049              width: 320,
17050              autoOpen: true,
17051              modal: true,
17052              resizable: false,
17053              draggable: false,
17054              beforeClose: function (event, ui) {
17055                event.stopPropagation();
17056              },
17057              title: 'Lähetä maksusopimus/tiliehdot hyväksyttäväksi',
17058              buttons: {
17059                Lähetä: function () {
17060                  $(this).dialog('close');
17061                  pages.iv_laskutus_ja_reskontra.send_customer_acceptance_invitation(
17062                    part_payment_id,
17063                    $email_input.val(),
17064                    $phone_input.val()
17065                  );
17066                },
17067                Peruuta: function () {
17068                  $(this).dialog('close');
17069                },
17070              },
17071            });
17072        });
17073
17074      $('#get_application_pdf')
17075        .button({ icons: { primary: 'ui-icon-document' } })
17076        .on('click', function () {
17077          window.open('osamaksu/get_contract_pdf/' + part_payment_id);
17078        });
17079
17080      $('#get_arvato_account_terms_pdf')
17081        .button({ icons: { primary: 'ui-icon-document' } })
17082        .on('click', function () {
17083          window.open('osamaksu/get_arvato_account_terms_pdf/' + part_payment_id);
17084        });
17085
17086      /*
17087					$('#send_towing_record_pdf_by_email').button({icons:{primary:'ui-icon-mail-closed'}}).on('click',function(){
17088						kuormakirjat.send_towing_record_by_email(towing_record_id);
17089					});
17090					*/
17091
17092      /*
17093					$('#send_receipt_by_email').button({icons:{primary:'ui-icon-mail-closed'}}).on('click',function(){
17094						kuormakirjat.send_receipt_by_email(towing_record_id);
17095					});
17096					*/
17097    },
17098
17099    refresh_part_payment_dialog_and_datatable: function (part_payment_id) {
17100      //Refresh the datatable
17101      if (pages.iv_laskutus_ja_reskontra.$part_payments_datatable != null) {
17102        pages.iv_laskutus_ja_reskontra.$part_payments_datatable.fnClearTable(0);
17103        pages.iv_laskutus_ja_reskontra.$part_payments_datatable.fnDraw();
17104      }
17105
17106      //Refresh the invoice dialog
17107      global.show_ajax_loader(global.$dialog);
17108      global.$dialog.load('/osamaksu/get_part_payment_dialog/' + part_payment_id + '/');
17109    },
17110
17111    show_direct_payment: function (direct_payment_id) {
17112      global.$dialog = $('<div />', {});
17113      var $dialog = global.$dialog;
17114
17115      $.ajax({
17116        processData: false,
17117        dataType: 'html',
17118        type: 'GET',
17119        url: 'ajax/get_direct_payment_dialog/' + direct_payment_id + '/',
17120        beforeSend: function (request) {
17121          $dialog.dialog({
17122            width: 800,
17123            height: 600,
17124            modal: true,
17125            resizable: false,
17126            title: 'Korttimaksun tiedot',
17127            close: function () {
17128              $dialog.dialog('destroy');
17129            },
17130          });
17131          global.show_ajax_loader($dialog);
17132        },
17133        success: function (response) {
17134          $dialog.html(response);
17135        },
17136      });
17137    }, //show_direct_payment
17138
17139    init_direct_payment_dialog: function (directPaymentId) {
17140      $('#creditPayments').on('click', 'a.show_direct_payment', function (e) {
17141        e.preventDefault();
17142        var id = $(e.target).attr('href');
17143        pages.reskontra.show_direct_payment(id);
17144      });
17145      $('#print_receipt_pdf')
17146        .button({ icons: { primary: 'ui-icon-document' } })
17147        .on('click', function () {
17148          var pdfUrl = '/reskontra/directPayment/' + directPaymentId + '/pdf';
17149          window.open(pdfUrl);
17150        });
17151      $('#download_direct_payment_receipt')
17152        .button({ icons: { primary: 'ui-icon-document' } })
17153        .on('click', function () {
17154          var paymentId = $(this).data('direct-payment-id');
17155          var receiptUrl = '/payment_devices/tuloste/' + paymentId;
17156          window.open(receiptUrl);
17157        });
17158      $('#confirm_online_payment')
17159        .button({ icons: { primary: 'ui-icon-document' } })
17160        .on('click', function () {
17161          if(window.onlinePaymentDt){
17162            var paymentId = $(this).data('direct-payment-id');
17163            var type = $(this).data('conf-type');
17164            window.onlinePaymentDt.openConfirmOnlinePayment(paymentId, type);
17165          }
17166        });
17167      $('#get_payment_terminal_details')
17168        .button({ icons: { primary: 'ui-icon-document' } })
17169        .on('click', function () {
17170          var transactionId = $(this).data('pt-transaction-id');
17171
17172          var dialog = $('<div />', {}).dialog({
17173            autoOpen: true,
17174            modal: true,
17175            width: 500,
17176            position: {
17177              top: 50,
17178            },
17179            hide: {
17180              effect: 'fade',
17181              speed: 3000,
17182            },
17183            resizable: true,
17184            title: 'Maksupäätetapahtuman tiedot',
17185            draggable: true,
17186            buttons: {
17187              Sulje: function () {
17188                dialog.dialog('close');
17189              },
17190            },
17191          });
17192          dialog.html('<p>Ladataan maksupäätetapahtuman tietoja...</p>');
17193          jQuery
17194            .ajax({
17195              type: 'POST',
17196              url: '/payment_devices/getPTTransaction',
17197              data: {
17198                transactionId: transactionId,
17199              },
17200            })
17201            .then(function (data) {
17202              var dialogHtml = '';
17203              if (data.transaction_status === 'success') {
17204                var merchantReceipt = JSON.parse(data.merchant_receipt);
17205                var dateString = data.transaction_time;
17206                var yy = 20 + dateString.substring(0, 2),
17207                  mm = dateString.substring(2, 4),
17208                  dd = dateString.substring(4, 6),
17209                  hh = dateString.substring(6, 8),
17210                  MM = dateString.substring(8, 10);
17211
17212                var transactionTime = dd + '.' + mm + '.' + yy + ' ' + hh + ':' + MM;
17213                var transactionType = data.transaction_type === 'Purchase' ? 'Maksu' : 'Hyvitys';
17214                dialogHtml =
17215                  '<pre><code>' +
17216                  'Tapahtumatyyppi: ' +
17217                  transactionType +
17218                  '\n' +
17219                  'Maksupääte: ' +
17220                  data.terminal_name +
17221                  ' (' +
17222                  data.terminal_id +
17223                  ')\n' +
17224                  'Tapahtuma luotu: ' +
17225                  transactionTime +
17226                  '\n' +
17227                  'Kortin lukutapa: ' +
17228                  data.card_reading_method +
17229                  '\n' +
17230                  merchantReceipt.text +
17231                  '</code></pre>';
17232              } else {
17233                dialogHtml =
17234                  'Maksupääte tapahtuman tietoja ei voitu hakea, maksupäätetapahtuma keskeneräinen';
17235              }
17236              dialog.html(dialogHtml);
17237            })
17238            .fail(function (err) {
17239              console.log(err);
17240              dialog.html('<p>Maksupäätetapahtuman haku epäonnistui</p>');
17241            });
17242        });
17243    }, // init_direct_payment_dialog
17244
17245    accept_for_money_transfer: function (part_payment_id) {
17246      $.ajax({
17247        dataType: 'json',
17248        type: 'POST',
17249        data: { part_payment_id: part_payment_id },
17250        url: '/osamaksu/accept_for_money_transfer/',
17251
17252        beforeSend: function (request) {
17253          global.showLoadingDialog('Hyväksytään osamaksusopimusta tilitettäväksi...');
17254        },
17255        success: function (responseJSON) {
17256          global.close_loading_dialog();
17257          global.show_message(responseJSON);
17258          pages.iv_laskutus_ja_reskontra.refresh_part_payment_dialog_and_datatable(part_payment_id);
17259        },
17260        error: function (data) {
17261          global.show_message($.parseJSON(data.responseText));
17262          global.close_loading_dialog();
17263        },
17264      });
17265    },
17266
17267    create_down_payment_invoice: function (part_payment_id) {
17268      $.ajax({
17269        dataType: 'json',
17270        type: 'POST',
17271        data: { part_payment_id: part_payment_id, invoice_type: 'down_payment' },
17272        url: '/osamaksu/create_invoice/',
17273
17274        beforeSend: function (request) {
17275          global.showLoadingDialog('Luodaan käsirahalaskua...');
17276        },
17277        success: function (responseJSON) {
17278          global.close_loading_dialog();
17279          global.show_message(responseJSON);
17280          pages.iv_laskutus_ja_reskontra.refresh_part_payment_dialog_and_datatable(part_payment_id);
17281        },
17282        error: function (data) {
17283          global.show_message($.parseJSON(data.responseText));
17284          global.close_loading_dialog();
17285        },
17286      });
17287    },
17288
17289    create_part_payment_invoice: function (part_payment_id) {
17290      $.ajax({
17291        dataType: 'json',
17292        type: 'POST',
17293        data: { part_payment_id: part_payment_id, invoice_type: 'part_payment' },
17294        url: '/osamaksu/create_invoice/',
17295
17296        beforeSend: function (request) {
17297          global.showLoadingDialog('Luodaan tililaskua...');
17298        },
17299        success: function (responseJSON) {
17300          global.close_loading_dialog();
17301          global.show_message(responseJSON);
17302          pages.iv_laskutus_ja_reskontra.refresh_part_payment_dialog_and_datatable(part_payment_id);
17303        },
17304        error: function (data) {
17305          global.show_message($.parseJSON(data.responseText));
17306          global.close_loading_dialog();
17307        },
17308      });
17309    },
17310
17311    cancel_part_payment_contract: function (part_payment_id, cancel_reason) {
17312      //Do ajax request
17313      $.ajax({
17314        dataType: 'json',
17315        type: 'POST',
17316        url: 'osamaksu/cancel_contract/',
17317        data: { part_payment_id: part_payment_id, cancel_reason: cancel_reason },
17318
17319        beforeSend: function (request) {
17320          global.showLoadingDialog('Perutaan osamaksusopimusta');
17321        },
17322        success: function (responseJSON) {
17323          global.close_loading_dialog();
17324          global.show_message(responseJSON);
17325          pages.iv_laskutus_ja_reskontra.refresh_part_payment_dialog_and_datatable(part_payment_id);
17326        },
17327        error: function (data) {
17328          global.show_message($.parseJSON(data.responseText));
17329          global.close_loading_dialog();
17330        },
17331      });
17332    },
17333
17334    convert_part_payment_contract_to_invoice: function (partPaymentId, addCancellationFee) {
17335      //Do ajax request
17336      $.ajax({
17337        dataType: 'json',
17338        type: 'POST',
17339        url: 'osamaksu/convert_to_invoice/',
17340        data: { part_payment_id: partPaymentId, add_cancellation_fee: addCancellationFee },
17341
17342        beforeSend: function (request) {
17343          global.showLoadingDialog('Muunnetaan osamaksusopimusta');
17344        },
17345        success: function (responseJSON) {
17346          global.close_loading_dialog();
17347          global.show_message(responseJSON);
17348          pages.iv_laskutus_ja_reskontra.refresh_part_payment_dialog_and_datatable(partPaymentId);
17349        },
17350        error: function (data) {
17351          global.show_message($.parseJSON(data.responseText));
17352          global.close_loading_dialog();
17353        },
17354      });
17355    },
17356
17357    delete_part_payment_contract: function (part_payment_id) {
17358      //Do ajax request
17359      $.ajax({
17360        dataType: 'json',
17361        type: 'POST',
17362        url: 'osamaksu/delete_contract/',
17363        data: { part_payment_id: part_payment_id },
17364
17365        beforeSend: function (request) {
17366          global.showLoadingDialog('Poistetaan osamaksusopimusta');
17367        },
17368        success: function (responseJSON) {
17369          global.close_loading_dialog();
17370          global.show_message(responseJSON);
17371          pages.iv_laskutus_ja_reskontra.refresh_part_payment_dialog_and_datatable(part_payment_id);
17372        },
17373        error: function (data) {
17374          global.show_message($.parseJSON(data.responseText));
17375          global.close_loading_dialog();
17376        },
17377      });
17378    },
17379
17380    decline_part_payment_contract: function (part_payment_id, decline_reason) {
17381      //Do ajax request
17382      $.ajax({
17383        dataType: 'json',
17384        type: 'POST',
17385        url: 'osamaksu/decline_contract/',
17386        data: { part_payment_id: part_payment_id, decline_reason: decline_reason },
17387
17388        beforeSend: function (request) {
17389          global.showLoadingDialog('Hylätään osamaksusopimusta');
17390        },
17391        success: function (responseJSON) {
17392          global.close_loading_dialog();
17393          global.show_message(responseJSON);
17394          pages.iv_laskutus_ja_reskontra.refresh_part_payment_dialog_and_datatable(part_payment_id);
17395        },
17396        error: function (data) {
17397          global.show_message($.parseJSON(data.responseText));
17398          global.close_loading_dialog();
17399        },
17400      });
17401    },
17402
17403    approve_part_payment_application: function (part_payment_id) {
17404      //Do ajax request
17405
17406      $.ajax({
17407        dataType: 'json',
17408        type: 'POST',
17409        url: 'osamaksu/approve_application/',
17410        data: { part_payment_id: part_payment_id },
17411
17412        beforeSend: function (request) {
17413          global.showLoadingDialog('Merkitään osamaksua hyväksytyksi');
17414        },
17415        success: function (responseJSON) {
17416          global.close_loading_dialog();
17417          global.show_message(responseJSON);
17418          pages.iv_laskutus_ja_reskontra.refresh_part_payment_dialog_and_datatable(part_payment_id);
17419        },
17420        error: function (data) {
17421          global.show_message($.parseJSON(data.responseText));
17422          global.close_loading_dialog();
17423        },
17424      });
17425
17426      //refresh dialog
17427    },
17428
17429    approve_and_send_signature_invitation: function (part_payment_id, email) {
17430      //Do ajax request
17431      $.ajax({
17432        dataType: 'json',
17433        type: 'POST',
17434        url: '/osamaksu/approve_and_send_signature_invitation/',
17435        data: { part_payment_id: part_payment_id, email: email },
17436
17437        beforeSend: function (request) {
17438          global.showLoadingDialog('Hyväksytään sopimusta ja lähetetään allekirjoituskutsua');
17439        },
17440        success: function (responseJSON) {
17441          global.close_loading_dialog();
17442          global.show_message(responseJSON);
17443          pages.iv_laskutus_ja_reskontra.refresh_part_payment_dialog_and_datatable(part_payment_id);
17444        },
17445        error: function (data) {
17446          global.show_message($.parseJSON(data.responseText));
17447          global.close_loading_dialog();
17448        },
17449      });
17450    },
17451
17452    send_signature_invitation: function (part_payment_id, email) {
17453      //Do ajax request
17454      $.ajax({
17455        dataType: 'json',
17456        type: 'POST',
17457        url: '/osamaksu/send_signature_invitation/',
17458        data: { part_payment_id: part_payment_id, email: email },
17459
17460        beforeSend: function (request) {
17461          global.showLoadingDialog('Lähetetään allekirjoituskutsua');
17462        },
17463        success: function (responseJSON) {
17464          global.close_loading_dialog();
17465          global.show_message(responseJSON);
17466        },
17467        error: function (data) {
17468          global.show_message($.parseJSON(data.responseText));
17469          global.close_loading_dialog();
17470        },
17471      });
17472    },
17473
17474    send_customer_acceptance_invitation: function (part_payment_id, email, phone) {
17475      //Do ajax request
17476      $.ajax({
17477        dataType: 'json',
17478        type: 'POST',
17479        url: '/osamaksu/send_customer_acceptance_invitation/',
17480        data: {
17481          part_payment_id: part_payment_id,
17482          email: email,
17483          phone: phone,
17484        },
17485        beforeSend: function (request) {
17486          global.showLoadingDialog('Lähetetään hyväksyntäpyyntöä');
17487        },
17488        success: function (responseJSON) {
17489          global.close_loading_dialog();
17490          global.show_message(responseJSON);
17491        },
17492        error: function (data) {
17493          global.show_message($.parseJSON(data.responseText));
17494          global.close_loading_dialog();
17495        },
17496      });
17497    },
17498
17499    show_invoice: function (invoice_id, open_sum) {
17500      LaskutusJaReskontra.showInvoiceDialog({
17501        invoiceId: invoice_id,
17502      });
17503
17504      /*
17505				var $dialog = global.$dialog;
17506
17507				if($dialog.hasClass('ui-dialog-content')){
17508					$dialog.dialog('destroy');
17509				}
17510
17511				$.ajax( {
17512					"processData":false,
17513					"dataType": 'html',
17514					"type": "GET",
17515					"url": "ajax/get_invoice_html/" + invoice_id  + '/',
17516					"beforeSend":function(request){
17517						$dialog.dialog({
17518							width:800,
17519							height:600,
17520							modal:true,
17521							resizable:false,
17522							title:'Laskun tiedot',
17523							close: function(){
17524								$dialog.dialog('destroy');
17525							}
17526						});
17527						global.show_ajax_loader($dialog);
17528					},
17529					"success": function(response){
17530						$dialog.html(response);
17531
17532						$(this).delegate(':button','click',function(){
17533							$(this).data({'invoice_id': invoice_id, 'open_sum':open_sum});
17534						});
17535					}
17536				});
17537				*/
17538    }, //show_invoice
17539
17540    copy_invoice: function (invoice_id) {
17541      $('<div></div>')
17542        .html('Haluatko siirtyä luomaan uuden laskun, käyttäen tätä laskua pohjana?')
17543        .dialog({
17544          autoOpen: true,
17545          modal: true,
17546          resizable: false,
17547          draggable: false,
17548          title: 'Kopioi lasku',
17549          beforeClose: function (event, ui) {
17550            event.stopPropagation();
17551          },
17552          buttons: {
17553            Peruuta: function () {
17554              $(this).dialog('close');
17555            },
17556            'Siirry laskun luontiin': function () {
17557              $(this).dialog('close');
17558
17559              window.location = '/lasku/kopioi/' + invoice_id;
17560            },
17561          },
17562        });
17563    }, //copy_invoice
17564
17565    confirm_delete_draft: function (invoice_id) {
17566      $('<div></div>')
17567        .html('Haluatko varmasti poistaa laskun luonnoksen')
17568        .dialog({
17569          autoOpen: true,
17570          modal: true,
17571          resizable: false,
17572          draggable: false,
17573          title: 'Poista laskun luonnos',
17574          beforeClose: function (event, ui) {
17575            event.stopPropagation();
17576          },
17577          close: function () {
17578            $(this).dialog('destroy');
17579            $(this).remove();
17580          },
17581          buttons: {
17582            Peruuta: function () {
17583              $(this).dialog('close');
17584            },
17585            Poista: function () {
17586              $(this).dialog('close');
17587              pages.iv_laskutus_ja_reskontra.delete_draft(invoice_id);
17588            },
17589          },
17590        });
17591    }, //confirm_delete_draft
17592
17593    delete_draft: function (invoice_id) {
17594      //global.$dialog = $('</div />');
17595      var $dialog = global.$dialog;
17596
17597      if ($dialog.hasClass('ui-dialog-content')) {
17598        $dialog.dialog('close');
17599      }
17600
17601      //console.log("delete_draft");
17602
17603      $.ajax({
17604        processData: false,
17605        dataType: 'json',
17606        type: 'GET',
17607        url: '/ajax/delete_invoice_draft/' + invoice_id + '/',
17608        beforeSend: function (request) {
17609          global.showLoadingDialog('Poistetaan lasku...');
17610        },
17611        success: function (responseJSON) {
17612          global.close_loading_dialog();
17613          global.show_message(responseJSON);
17614
17615          pages.iv_laskutus_ja_reskontra.$datatable_iv.fnClearTable(0);
17616          pages.iv_laskutus_ja_reskontra.$datatable_iv.fnDraw();
17617
17618          pages.iv_laskutus_ja_reskontra.$datatable.fnClearTable(0);
17619          pages.iv_laskutus_ja_reskontra.$datatable.fnDraw();
17620        },
17621      });
17622    }, //delete_draft
17623
17624    showAddDirectPaymentDialog: function (id, openAmount) {
17625      //Define the URL and success function for the refund payment case
17626      var $dialog = $('#add_direct_payment_dialog');
17627
17628      if (!$dialog.length) {
17629        $dialog = pages.iv_laskutus_ja_reskontra.createDirectPaymentDialog();
17630        $dialog.find('input#paid_date').datepicker($.datepicker.regional.fi);
17631      }
17632
17633      //Set date and open amount values
17634      $dialog.find('input#paid_date').datepicker('setDate', new Date());
17635      $dialog.find('input#amount').val(openAmount);
17636    
17636  $dialog.find('input#id').val(id);
17637
17638      $dialog.dialog('open');
17639    },
17640
17641    createDirectPaymentDialog: function () {
17642      var d = new Date(),
17643        url = '/iv_laskutus_ja_reskontra/addPaymentToDirectPayment/',
17644        $dialog = $('<div></div>', { id: 'add_direct_payment_dialog' }).append(
17645          $('<form />', { id: 'add_payment_form' }).append(
17646            $('<fieldset />', { class: '', style: '' })
17647              .append('<p>Syötä tilityksen summa ja päivämäärä</p>')
17648              .append(
17649                $('<ol />')
17650                  .append($('<input type="hidden" name="id" id="id" value="" />'))
17651                  .append(
17652                    $('<li />')
17653                      .append($('<label for="amount">Summa:</label>'))
17654                      .append(
17655                        $('<input type="text" name="amount" id="amount"  class="text small" />')
17656                      )
17657                      .append(' &euro;')
17658                  )
17659                  .append(
17660                    $('<li />')
17661                      .append($('<label id="paid_date_label" for="paid_date">Päivämäärä:</label>'))
17662                      .append(
17663                        $(
17664                          '<input type="text" class="text small" id="paid_date" name="paid_date" />'
17665                        )
17666                      )
17667                  )
17668                  .append(
17669                    $('<li />').append(
17670                      $(
17671                        '<button type="submit" class="btn btn-default">Tallenna' +
17672                          ' tilitys</button>'
17673                      ).button()
17674                    )
17675                  )
17676              )
17677          )
17678        );
17679
17680      $dialog.find('form#add_payment_form').submit(function () {
17681        var data = _.object(
17682          $dialog
17683            .find('#add_payment_form')
17684            .serializeArray()
17685            .map(function (v) {
17686              return [v.name, v.value];
17687            })
17688        );
17689
17690        $.ajax({
17691          type: 'POST',
17692          url: url.concat(data.id),
17693          data: data,
17694          beforeSend: function (request) {
17695            global.showLoadingDialog('Tallennetaan tilitystä...');
17696          },
17697        })
17698          .done(function (data) {
17699            global.close_loading_dialog();
17700            global.show_message(data);
17701            $dialog.dialog('close');
17702
17703            //Refresh the datatable
17704            pages.iv_laskutus_ja_reskontra.$datatable_direct_payments.fnClearTable(0);
17705            pages.iv_laskutus_ja_reskontra.$datatable_direct_payments.fnDraw();
17706          })
17707          .fail(function (data) {
17708            global.show_message($.parseJSON(data.responseText));
17709            global.close_loading_dialog();
17710          });
17711
17712        return false;
17713      });
17714
17715      $dialog.dialog({
17716        width: 400,
17717        //height:200,
17718        autoOpen: false,
17719        modal: true,
17720        resizable: false,
17721        draggable: false,
17722        beforeClose: function (event, ui) {
17723          event.stopPropagation();
17724        },
17725        title: 'Lisää tilitys',
17726        buttons: {
17727          Peruuta: function () {
17728            $(this).dialog('close');
17729          },
17730        },
17731      });
17732
17733      return $dialog;
17734    },
17735
17736    show_add_payment_dialog: function (id, open_sum, target_type) {
17737      //console.log('show_add_payment_dialog');
17738
17739      var d = new Date();
17740
17741      //Define the URL and success function for the invoice payment case
17742      if (target_type == 'invoice') {
17743        var url = '/ajax/add_invoice_payment/' + id;
17744        var success_callback = function (responseJSON, statusText, xhr, $form) {
17745          global.close_loading_dialog();
17746          global.show_message(responseJSON);
17747          $add_payment_dialog.dialog('close');
17748
17749          //Refresh the datatables
17750          pages.iv_laskutus_ja_reskontra.$datatable_iv.fnClearTable(0);
17751          pages.iv_laskutus_ja_reskontra.$datatable_iv.fnDraw();
17752
17753          pages.iv_laskutus_ja_reskontra.$datatable.fnClearTable(0);
17754          pages.iv_laskutus_ja_reskontra.$datatable.fnDraw();
17755        };
17756      }
17757
17758      //Define the URL and success function for the refund payment case
17759      if (target_type == 'refund') {
17760        var url = '/ajax/add_refund_payment/' + id;
17761        var success_callback = function (responseJSON, statusText, xhr, $form) {
17762          global.close_loading_dialog();
17763          global.show_message(responseJSON);
17764          $add_payment_dialog.dialog('close');
17765
17766          //Refresh the datatable
17767          pages.iv_laskutus_ja_reskontra.$datatable_refunds.fnReloadAjax();
17768        };
17769      }
17770
17771      $add_payment_dialog = $('<div></div>')
17772        .append(
17773          $('<form />', { id: 'add_payment_form', method: 'post', action: url })
17774            .append(
17775              $('<fieldset />', { class: 'fs-invisible', style: '' })
17776                .append(
17777                  '<p>Syötä maksusuorituksen summa euroissa ja lisää suorituksen päivämäärä</p>'
17778                )
17779                .append(
17780                  $('<ol />')
17781                    .append(
17782                      $('<li />')
17783                        .append($('<label for="amount">Summa:</label>'))
17784                        .append(
17785                          $(
17786                            '<input type="text" name="amount" id="amount" value="' +
17787                              open_sum +
17788                              '" class="text small" />'
17789                          )
17790                        )
17791                        .append(' &euro;')
17792                    )
17793                    .append(
17794                      $('<li />')
17795                        .append($('<label id="created_label" for="created">Päivämäärä:</label>'))
17796                        .append(
17797                          $(
17798                            '<input type="text" class="text small" id="created" name="created" value="' +
17799                              d.getDate() +
17800                              '.' +
17801                              (d.getMonth() + 1) +
17802                              '.' +
17803                              d.getFullYear() +
17804                              '" />'
17805                          ).datepicker($.datepicker.regional.fi)
17806                        )
17807                    )
17808                    .append(
17809                      $('<li />').append(
17810                        $('<button type="submit">Tallenna maksusuoritus</button>').button()
17811                      )
17812                    )
17813                )
17814            )
17815            .submit(function () {
17816              $(this).ajaxSubmit({
17817                dataType: 'json',
17818                beforeSubmit: function () {
17819                  global.showLoadingDialog('Tallennetaan maksusuoritusta...');
17820                },
17821                success: success_callback,
17822              });
17823              return false;
17824            })
17825        )
17826        .dialog({
17827          width: 400,
17828          //height:200,
17829          autoOpen: true,
17830          modal: true,
17831          resizable: false,
17832          draggable: false,
17833          beforeClose: function (event, ui) {
17834            event.stopPropagation();
17835          },
17836          close: function () {
17837            $(this).dialog('destroy');
17838            $(this).remove();
17839          },
17840          title: 'Lisää maksusuoritus',
17841          buttons: {
17842            Peruuta: function () {
17843              $(this).dialog('close');
17844            },
17845          },
17846        });
17847    }, //show_add_payment_dialog
17848    add_log_item: function (invoice_id) {
17849      $('<div></div>')
17850        .append(
17851          $('<label />', {
17852            id: '',
17853            for: 'notifyInnovoice',
17854            style: 'font-weight:bold; width:100%;margin-bottom: 0;',
17855          }).html('Tyyppi'),
17856          $('<select/>', {
17857            id: 'notifyInnovoice',
17858            class: 'btn-sm',
17859            name: 'notify',
17860            style: 'font-weight: 500; line-height: 1.5; margin-bottom: 10px;',
17861          }).append(
17862            $('<option />', { value: '' }).html('Valitse'),
17863            $('<option />', { value: '1' }).html('Viesti Innovoicen asiakaspalveluun'),
17864            $('<option />', { value: '0' }).html('Oma muistiinpano')
17865          ),
17866          $('<label />', { style: 'width:auto;' })
17867            .html('Viesti')
17868            .append($('<textarea />', { style: 'width:320px; height:72px;', name: 'log_event' }))
17869            .append('<br />')
17870            .append('<br />')
17871        )
17872        .dialog({
17873          autoOpen: true,
17874          modal: true,
17875          resizable: false,
17876          draggable: false,
17877          width: 380,
17878          title: 'Lisää muistiinpano',
17879          beforeClose: function (event, ui) {
17880            event.stopPropagation();
17881          },
17882          close: function () {
17883            $(this).dialog('destroy');
17884            $(this).remove();
17885          },
17886          buttons: {
17887            Peruuta: function () {
17888              $(this).dialog('close');
17889            },
17890            Tallenna: function () {
17891              global.showLoadingDialog('Viestiä tallennetaan...');
17892              var message = $(this).find('textarea[name=log_event]').val();
17893              var notify = $('select#notifyInnovoice').val();
17894              if (notify === '') {
17895                global.close_loading_dialog();
17896                global.show_message({
17897                  type: 'error',
17898                  title: 'Virhe',
17899                  text: 'Valitse viestin tyyppi.',
17900                });
17901                return;
17902              }
17903              var data = { id: invoice_id, message: message, notify: notify };
17904              $(this).dialog('close');
17905              $.ajax({
17906                url: 'logger/makeLogEntry/',
17907                type: 'post',
17908                data: data,
17909                success: function (resp) {
17910                  global.close_loading_dialog();
17911                  global.show_message({
17912                    type: 'success',
17913                    title: 'Valmis',
17914                    text: 'Muistiinpano lisätty onnistuneesti.',
17915                  });
17916                },
17917              });
17918            },
17919          },
17920        });
17921      $('button').addClass('btn btn-default');
17922    },
17923
17924    confirm_mark_payments: function (selected_payments) {
17925      $('<div></div>')
17926        .html('Haluatko varmasti merkitä valitut laskut maksetuiksi')
17927        .dialog({
17928          autoOpen: true,
17929          modal: true,
17930          resizable: false,
17931          draggable: false,
17932          title: 'Merkitse laskut maksetuiksi',
17933          beforeClose: function (event, ui) {
17934            event.stopPropagation();
17935          },
17936          buttons: {
17937            Kyllä: function () {
17938              $(this).dialog('close');
17939              pages.iv_laskutus_ja_reskontra.mark_payments_paid(selected_payments);
17940            },
17941            Peruuta: function () {
17942              $(this).dialog('close');
17943            },
17944          },
17945        });
17946    }, //confirm_mark_payments
17947    /**
17948     * General confirmation window. functions passed in must be anonymous. see params explanation
17949     * @param {String} title Window title
17950     * @param {String} message Window message
17951     * @param {function} onConfirm function is ran when modal confirmed -- () => { exampleFunction(exampleData) }
17952     * @param {function} onCancel function is ran when modal canceled-- () => { exampleFunction(exampleData) }
17953     */
17954    confirm_action: function (title, message, onConfirm, onCancel) {
17955      onCancel = onCancel || false;
17956
17957      $('<div></div>')
17958        .html(message)
17959        .dialog({
17960          autoOpen: true,
17961          modal: true,
17962          resizable: false,
17963          draggable: false,
17964          title: title,
17965          beforeClose: function (event, ui) {
17966            event.stopPropagation();
17967          },
17968          buttons: {
17969            Kyllä: function () {
17970              $(this).dialog('close');
17971              onConfirm();
17972            },
17973            Peruuta: function () {
17974              $(this).dialog('close');
17975              if (onCancel) {
17976                onCancel();
17977              }
17978            },
17979          },
17980        });
17981    },
17982
17983    mark_payments_paid: function (payments) {
17984      global.showLoadingDialog('Merkitään tilityksiä maksetuiksi...');
17985
17986      $.post(
17987        'iv_laskutus_ja_reskontra/ajax_mark_payments_paid',
17988        { 'payments[]': payments },
17989        function (responseJSON) {
17990          global.close_loading_dialog();
17991          global.show_message(responseJSON);
17992          pages.iv_laskutus_ja_reskontra.$datatable_paid_payments.fnReloadAjax();
17993          pages.iv_laskutus_ja_reskontra.$datatable_open_payments.fnReloadAjax();
17994        },
17995        'json'
17996      );
17997    }, //mark_payments_paid
17998
17999    show_upload_gothia_payment_file_dialog: function () {
18000      $upload_file_dialog = $('<div></div>')
18001        .append(
18002          $('<form />', {
18003            enctype: 'multipart/form-data',
18004            id: 'upload_gothia_payment_file_form',
18005            method: 'post',
18006            action: '/iv_laskutus_ja_reskontra/upload_gothia_payment_file/',
18007          })
18008            .append(
18009              $('<fieldset />', { class: 'fs-invisible', style: '' })
18010                .append('<p>Valitse Gothian tilitystiedosto</p>')
18011                .append(
18012                  $('<ol />')
18013                    .append(
18014                      $('<li />').append(
18015                        $(
18016                          '<input type="file" name="gothia_payment_file" id="gothia_payment_file" />'
18017                        )
18018                      )
18019                    )
18020                    .append(
18021                      $('<li />').append(
18022                        $('<button type="submit">Luo tiedostosta tilitys</button>').button()
18023                      )
18024                    )
18025                )
18026            )
18027            .submit(function () {
18028              $(this).ajaxSubmit({
18029                dataType: 'json',
18030                iframe: true,
18031                beforeSubmit: function () {
18032                  global.showLoadingDialog('Luodaan tilitystä...');
18033                },
18034                success: function (responseJSON, statusText, xhr, $form) {
18035                  global.close_loading_dialog();
18036                  global.show_message(responseJSON);
18037
18038                  if (responseJSON.type === 'success') {
18039                    pages.iv_laskutus_ja_reskontra.$datatable_money_transfers.fnClearTable(0);
18040                    pages.iv_laskutus_ja_reskontra.$datatable_money_transfers.fnDraw();
18041                    $upload_file_dialog.dialog('destroy');
18042                  }
18043                },
18044              });
18045              return false;
18046            })
18047        )
18048        .dialog({
18049          width: 400,
18050          //height:200,
18051          autoOpen: true,
18052          modal: true,
18053          resizable: false,
18054          draggable: false,
18055          beforeClose: function (event, ui) {
18056            event.stopPropagation();
18057          },
18058          title: 'Syötä Gothian tilitystiedosto',
18059          buttons: {
18060            Peruuta: function () {
18061              $(this).dialog('close');
18062            },
18063          },
18064        });
18065    },
18066
18067    show_money_transfer: function (id, moneyTransferDate, type) {
18068      global.$dialog = $('<div />', {});
18069      var $dialog = global.$dialog;
18070
18071      if ($dialog.hasClass('ui-dialog-content')) {
18072        $dialog.dialog('destroy');
18073      }
18074
18075      dialogs.url = 'ajax/get_money_transfer_html/' + id + '/' + type;
18076
18077      $.ajax({
18078        processData: false,
18079        dataType: 'html',
18080        type: 'GET',
18081        url: dialogs.url,
18082        beforeSend: function (request) {
18083          $dialog.dialog({
18084            width: 800,
18085            height: 500,
18086            modal: true,
18087            resizable: false,
18088            title: 'Tilityksen tiedot '.concat(moneyTransferDate),
18089            close: function () {
18090              $dialog.dialog('destroy');
18091            },
18092          });
18093          global.show_ajax_loader($dialog);
18094        },
18095        success: function (response) {
18096          $dialog.html(response);
18097          /*
18098						$(this).delegate(':button','click',function(){
18099							$(this).data({'invoice_id': invoice_id, 'open_sum':open_sum});
18100						});
18101						*/
18102        },
18103      });
18104    }, //show_invoice
18105
18106    execute_accepted_money_transfers: function (money_transfer_id) {
18107      var $dialog = $('<div />', { style: 'text-align:left;' }),
18108        $loadingDialog = $(
18109          '<div><p style="margin: 0 auto; width: 66px; padding-top:38px;"><img src="/assets/images/ajax_loading.gif" width="66" height="66" /></p></div>'
18110        );
18111
18112      $form = $('<form />', { id: 'sign_money_transfer_form' })
18113        .append(
18114          $('<p />').html('Allekirjoita eräsiirto antamalla varmenteen avainfraasi'),
18115          $('<input />', {
18116            type: 'password',
18117            name: 'passphrase',
18118            id: 'passphrase',
18119            class: 'text medium',
18120          })
18121        )
18122        .submit(function () {
18123          $(this).ajaxSubmit({
18124            data: { money_transfer_id: money_transfer_id },
18125            url: '/tilitykset/execute_accepted_money_transfers',
18126            type: 'POST',
18127            dataType: 'json',
18128            beforeSubmit: function () {
18129              global.showLoadingDialog('Suoritetaan eräsiirtoa pankkiin...');
18130            },
18131            success: function (responseJSON) {
18132              global.close_loading_dialog();
18133              global.show_message(responseJSON);
18134
18135              if (responseJSON.type === 'success' || responseJSON.type === 'info') {
18136                //Refresh the datatable and the dialog close the dialog
18137                $dialog.dialog('destroy');
18138                dialogs.refresh();
18139                pages.iv_laskutus_ja_reskontra.$datatable_money_transfers.fnClearTable(0);
18140                pages.iv_laskutus_ja_reskontra.$datatable_money_transfers.fnDraw();
18141              }
18142            },
18143            error: function (response) {
18144              global.close_loading_dialog();
18145
18146              try {
18147                global.show_message(JSON.parse(response.responseText));
18148              } catch (exception) {
18149                global.show_message({
18150                  type: 'error',
18151                  text: 'Odottamaton virhe tapahtui palvelimella. Virhesanoma tallennettu palvelimen lokiin.',
18152                });
18153              }
18154            },
18155          });
18156
18157          return false;
18158        });
18159
18160      $dialog.append($form).dialog({
18161        width: 320,
18162        autoOpen: true,
18163        modal: true,
18164        resizable: false,
18165        draggable: false,
18166        beforeClose: function (event, ui) {
18167          event.stopPropagation();
18168        },
18169        title: 'Allekirjoita pankin eräsiirto',
18170        buttons: {
18171          Peruuta: function () {
18172            $(this).dialog('close');
18173          },
18174          'Hyväksy eräsiirto': function () {
18175            $(this).find('#sign_money_transfer_form').submit();
18176          },
18177        },
18178      });
18179    }, //execute_accepted_money_transfers
18180    tryActionRemittance: function (data) {
18181      var inputData = JSON.parse(data);
18182      $.ajax({
18183        dataType: 'json',
18184        type: 'POST',
18185        url: inputData.url,
18186        data: {
18187          remittance_id: inputData.remittance_id,
18188          updated: inputData.updated,
18189        },
18190        beforeSend: function (request) {
18191          global.showLoadingDialog('Lähetetään hyväksyntäpyyntöä');
18192        },
18193        success: function (responseJSON) {
18194          global.close_loading_dialog();
18195          global.show_message(responseJSON);
18196
18197          pages.iv_laskutus_ja_reskontra.$datatable_remittances.fnClearTable(0);
18198          pages.iv_laskutus_ja_reskontra.$datatable_remittances.fnDraw();
18199        },
18200        error: function (data) {
18201          global.show_message($.parseJSON(data.responseText));
18202          global.close_loading_dialog();
18203          if (data.status === 409) {
18204            pages.iv_laskutus_ja_reskontra.$datatable_remittances.fnClearTable(0);
18205            pages.iv_laskutus_ja_reskontra.$datatable_remittances.fnDraw();
18206          }
18207        },
18208      });
18209    },
18210  }, //iv_laskutus_ja_reskontra
18211
18212  iv_tapahtumaloki: {
18213    $datatable: '',
18214
18215    init: function () {
18216      $('#get_transactions')
18217        .button({ icons: { primary: 'ui-icon-search' } })
18218        .on('click', function () {
18219          pages.iv_tapahtumaloki.$datatable.fnReloadAjax();
18220        });
18221
18222      $('#transactions_tabs').tabs();
18223
18224      $('#transactions_filter_form select').change(function (e) {
18225        // Timeout used here to prevent sending checked checkboxes when swithing from any filter -> all
18226        // If fnDraw() is called when swithcing checkboxes, previous filter will override all filter
18227        setTimeout(function () {
18228          pages.iv_tapahtumaloki.$datatable.fnClearTable(0);
18229          pages.iv_tapahtumaloki.$datatable.fnDraw();
18230        }, 1);
18231      });
18232
18233      $('#admin_transactions_dt').on('click', 'a.show_transaction_log', function (e) {
18234        e.preventDefault();
18235
18236        var transactionId = $(e.target).attr('href');
18237        var action = $(e.target).attr('class');
18238
18239        switch (action) {
18240          case 'show_transaction_log':
18241            pages.iv_tapahtumaloki.show_transaction_log(transactionId);
18242            break;
18243        }
18244      });
18245
18246      pages.iv_tapahtumaloki.$datatable = $('#admin_transactions_dt').dataTable({
18247        oLanguage: global.dataTablesLanguage,
18248        sPaginationType: 'full_numbers',
18249        iDisplayLength: 25,
18250        bAutoWidth: false,
18251        bJQueryUI: true,
18252        bFilter: true,
18253        bInfo: true,
18254        bPaginate: true,
18255        bProcessing: true,
18256        bServerSide: true,
18257        sAjaxSource: 'tapahtumaloki/datatable/',
18258        aoColumns: [
18259          /** ID **/ { bVisible: false, bSearchable: false },
18260          /** Yritys **/ { bVisible: true, bSearchable: false },
18261          /** Tapahtumatunnus **/ { bVisible: true, bSearchable: true },
18262          /** Asiakas **/ { bVisible: true, bSearchable: false, bSortable: false },
18263          /** Päiväys **/ { sType: 'date-eu', bVisible: true, bSearchable: false },
18264          /** Käyttöliittymä **/ { bVisible: true, bSearchable: false },
18265          /** Tyyppi **/ { bVisible: true, bSearchable: false },
18266          /** Tila **/ { bVisible: true, bSearchable: false },
18267        ],
18268        aaSorting: [[4, 'desc']],
18269
18270        fnServerParams: function (aoData) {
18271          var month = $('#transactions_filter_form select[name=month] option:selected').attr(
18272            'value'
18273          );
18274          var year = $('#transactions_filter_form select[name=year] option:selected').attr('value');
18275          var company = $('#transactions_filter_form select[name=company] option:selected').attr(
18276            'value'
18277          );
18278
18279          aoData.push({ name: 'month', value: month });
18280          aoData.push({ name: 'year', value: year });
18281          aoData.push({ name: 'company', value: company });
18282        },
18283
18284        //Called before each row is shown
18285        fnRowCallback: function (nRow, aData, iDisplayIndex) {
18286          var transaction_id = aData[0];
18287          var transaction_key = aData[2];
18288          //Add the transaction id to every rows data object
18289          $(nRow).data({ transaction_id: transaction_id });
18290
18291          $('td:eq(1)', nRow).html(
18292            '<a href="' +
18293              transaction_id +
18294              '" class="show_transaction_log" >' +
18295              transaction_key +
18296              '</a>'
18297          );
18298          return nRow;
18299        },
18300      });
18301      $('select[name=company]').each(function () {
18302        global.renderCompaniesFilterOptions(this);
18303      });
18304    },
18305
18306    show_transaction_log: function (transactionId) {
18307      var $dialog = $('<div />', { style: 'text-align:left;' });
18308
18309      if (transactionId.length > 0) {
18310        $.ajax({
18311          processData: false,
18312          dataType: 'html',
18313          type: 'GET',
18314          url: 'tapahtumaloki/get_transaction_log_html/' + transactionId,
18315          beforeSend: function (request) {
18316            $dialog.dialog({
18317              width: 650,
18318              height: 350,
18319              title: 'Tapahtumaloki',
18320              close: function () {
18321                $dialog.dialog('destroy');
18322              },
18323            });
18324            global.show_ajax_loader($dialog);
18325          },
18326          success: function (response) {
18327            $dialog.html(response);
18328          },
18329        });
18330      }
18331    }, // show_transaction_log
18332  }, //iv_tapahtumaloki
18333
18334  iv_sms_loki: {
18335    $datatable: '',
18336
18337    init: function () {
18338      $('#sms_log_tabs').tabs();
18339      $('#get_sms_log')
18340        .button({ icons: { primary: 'ui-icon-search' } })
18341        .on('click', function () {
18342          pages.iv_sms_loki.$datatable.fnReloadAjax();
18343        });
18344
18345      pages.iv_sms_loki.$datatable = $('table#sms_log_dt').dataTable({
18346        oLanguage: global.dataTablesLanguage,
18347        sPaginationType: 'full_numbers',
18348        iDisplayLength: 25,
18349        bAutoWidth: false,
18350        bJQueryUI: true,
18351        bFilter: true,
18352        bInfo: true,
18353        bPaginate: true,
18354        bProcessing: true,
18355        bServerSide: false,
18356        sAjaxSource: 'ajax/get_sms_log_json/',
18357        aoColumns: [
18358          /** ID **/ { bVisible: false },
18359          /** Aika **/ { bSortable: false },
18360          /** Välittäjä **/ { bSortable: false },
18361          /** Lähettäjän numero **/ null,
18362          /** Yritys **/ null,
18363          /** Auton nro. **/ { bSortable: false },
18364          /** Lähetetty viesti **/ { bSortable: false },
18365          /** Palvelun vastaus **/ { bSortable: false },
18366        ],
18367        aaSorting: [[0, 'desc']],
18368        fnServerData: function (sSource, aoData, fnCallback) {
18369          /* Add some extra data to the sender */
18370          var month = $('#ac-tab-log').find('select[name=month] option:selected').attr('value');
18371          var year = $('#ac-tab-log').find('select[name=year] option:selected').attr('value');
18372          sSource += year + '/' + month + '/';
18373
18374          $.getJSON(sSource, null, function (json) {
18375            $('span#month_year').html(json.month + ', ' + json.year);
18376            fnCallback(json);
18377          });
18378        },
18379      }); // $datatable
18380    }, //iv_sms_loki
18381  },
18382
18383  iv_henkilorekisteri: {
18384    $datatable: '',
18385
18386    init: function () {
18387      $('#customer_registry_tabs').tabs();
18388
18389      $('#create_customer_person')
18390        .button({ icons: { primary: 'ui-icon-plusthick' } })
18391        .on('click', function () {
18392          pages.iv_henkilorekisteri.show_customer_card();
18393        });
18394
18395      $('#customer_registry_dt').delegate(
18396        '#customer_registry_dt a.show_customer_card',
18397        'click',
18398        function (e) {
18399          e.preventDefault();
18400          var customer_id = $(e.target).attr('href');
18401          var action = $(e.target).attr('class');
18402
18403          switch (action) {
18404            case 'show_customer_card':
18405              pages.iv_henkilorekisteri.show_customer_card(customer_id);
18406              break;
18407          }
18408        }
18409      );
18410
18411      pages.iv_henkilorekisteri.$datatable = $('#customer_registry_dt').dataTable({
18412        oLanguage: global.dataTablesLanguage,
18413        sPaginationType: 'full_numbers',
18414        bPaginate: false,
18415        bAutoWidth: false,
18416        bJQueryUI: true,
18417        bProcessing: true,
18418        bServerSide: false,
18419        sAjaxSource: 'iv_henkilorekisteri/ajax_get_customers_json/',
18420        aoColumns: [
18421          /** user_id **/ { bVisible: false },
18422          /** Nimi **/ null,
18423          /** HETU **/ null,
18424          /** Osoite **/ null,
18425          /** Kaupunki **/ null,
18426          /** Puhelinnumero **/ null,
18427          /** Sähköposti **/ null,
18428          /** Laskun lähetystapa **/ null,
18429          /** Ei luottotark. **/ null,
18430        ],
18431        aaSorting: [[5, 'asc']],
18432        fnServerData: function (sSource, aoData, fnCallback) {
18433          $.getJSON(sSource, null, function (json) {
18434            /* Do whatever additional processing you want on the callback, then tell DataTables */
18435            fnCallback(json);
18436          });
18437        },
18438        //Called before each row is shown
18439        fnRowCallback: function (nRow, aData, iDisplayIndex) {
18440          var user_id = aData[0];
18441          var customer_name = aData[1];
18442
18443          $('td:eq(0)', nRow).html(
18444            '<a href="' + user_id + '" class="show_customer_card" >' + customer_name + '</a>'
18445          );
18446          return nRow;
18447        },
18448      }); //datatables
18449    }, //init
18450
18451    init_customer_card: function (id) {
18452      //var id = $('#id').val();
18453      $('#customer_card_tabs').tabs();
18454
18455      $('button:submit').button({ text: true, icons: { primary: 'ui-icon-disk' } });
18456      $('button#delete_customer').button({ text: true, icons: { primary: 'ui-icon-trash' } });
18457
18458      $('#customer_card_form').submit(function () {
18459        $(this).ajaxSubmit({
18460          dataType: 'json',
18461          //show the loading message
18462          beforeSubmit: function () {
18463            global.show_loading_dialog('Tallennetaan tietoja...');
18464          },
18465          success: function (responseJSON, statusText, xhr, $form) {
18466            global.close_loading_dialog();
18467            global.show_message(responseJSON);
18468
18469            if (responseJSON.type === 'success') {
18470              //Refresh the datatable and close the dialog
18471              if ($form.find('#id').val() === '') {
18472                global.$dialog.dialog('destroy');
18473              }
18474              pages.iv_henkilorekisteri.$datatable.fnReloadAjax();
18475            }
18476          },
18477        });
18478        return false;
18479      });
18480    },
18481
18482    show_customer_card: function (user_id) {
18483      var $dialog = global.$dialog;
18484
18485      if ($dialog.hasClass('ui-dialog-content')) {
18486        $dialog.dialog('destroy');
18487      }
18488
18489      var url = '/iv_henkilorekisteri/ajax_get_customer_card/';
18490
18491      if (typeof user_id !== 'undefined') {
18492        url += user_id + '/';
18493      }
18494
18495      $dialog.dialog({
18496        width: 800,
18497        height: 550,
18498        modal: true,
18499        resizable: false,
18500        title: 'Henkilökortti',
18501        open: function () {
18502          global.show_ajax_loader($dialog);
18503
18504          $.get(url, function (data) {
18505            $dialog.html(data);
18506          });
18507        },
18508        close: function () {
18509          $dialog.dialog('destroy');
18510        },
18511      });
18512    }, // show_customer_card
18513  }, // iv_henkilorekisteri
18514
18515  etusivu: {
18516    init: function () {
18517      $('#create_invoice_btn')
18518        .button({ icons: { primary: 'ui-icon-plusthick' } })
18519        .on('click', function (e) {
18520          var url = $(e.target).attr('name');
18521          window.location = url;
18522        });
18523
18524      $('#latest_transactions').on('click', 'a.show_transaction_log', {}, function (e) {
18525        global.$dialog = $('#dialog');
18526        e.preventDefault();
18527
18528        var transactionId = $(e.target).attr('href');
18529        var action = $(e.target).attr('class');
18530
18531        var n = transactionId.lastIndexOf('/');
18532
18533        transactionId = transactionId.substring(n + 1);
18534
18535        switch (action) {
18536          case 'show_transaction_log':
18537            pages.iv_tapahtumaloki.show_transaction_log(transactionId);
18538            break;
18539        }
18540      });
18541
18542      $('#latest_invoices').on('click', 'a.show_invoice, a.show_invoice_log', {}, function (e) {
18543        global.$dialog = $('#dialog');
18544
18545        e.preventDefault();
18546
18547        var invoice_id = $(e.target).attr('href');
18548        var action = $(e.target).attr('class');
18549
18550        var n = invoice_id.lastIndexOf('/');
18551        invoice_id = invoice_id.substring(n + 1);
18552
18553        switch (action) {
18554          case 'show_invoice':
18555            pages.iv_laskutus_ja_reskontra.show_invoice(invoice_id);
18556            break;
18557          case 'show_invoice_log':
18558            pages.iv_laskutus_ja_reskontra.show_invoice_log(invoice_id);
18559            break;
18560        }
18561      });
18562
18563      $('#user_manual')
18564        .button({ icons: { primary: 'ui-icon-document' } })
18565        .on('click', function () {
18566          window.open('http://www.innotaxi.fi/ohjeet/', 'user_manual');
18567        });
18568
18569      $(
18570        '#recent_events table tr:odd, #recent_logons table tr:odd, #recent_invoices table tr:odd, #recent_sms_logs table tr:odd'
18571      ).each(function () {
18572        $(this).addClass('odd');
18573      });
18574
18575      $('#recent_events tr, #recent_logons tr, #recent_invoices tr, #recent_sms_logs tr').hover(
18576        function () {
18577          $(this).addClass('hover');
18578        },
18579        function () {
18580          $(this).removeClass('hover');
18581        }
18582      );
18583    },
18584
18585    init_online_agreement: function () {
18586      $('#accept_online_agreement').button({ icons: { primary: 'ui-icon-check' } });
18587
18588      $('#agreement').change(function () {
18589        if ($('#agreement').is(':checked')) {
18590          $('#accept_online_agreement').button('enable');
18591        } else {
18592          $('#accept_online_agreement').button('disable');
18593        }
18594      });
18595    },
18596
18597    get_open_transactions: function ($wrapper) {
18598      //Refresh open transactions
18599      $.getJSON('/ajax/get_open_transactions_json/', function (responseJSON) {
18600        if (responseJSON.aaData.length > 0) {
18601          $tbody = $('<tbody />', {});
18602
18603          $.each(responseJSON.aaData, function (index, transaction) {
18604            //console.log(transaction);
18605
18606            $tbody.append(
18607              $('<tr />').append(
18608                $('<td />', { class: 'ui-helper-hidden' }).html(transaction.id),
18609                $('<td />').html(transaction.date),
18610                $('<td />').html(transaction.time),
18611                $('<td />').html(transaction.customer_name),
18612                $('<td />').html(transaction.type),
18613                $('<td />').html(transaction.credit_decision),
18614                $('<td />')
18615                  .html(
18616                    $('<a />', {
18617                      href: '/lasku/avoin/' + transaction.id,
18618                      class: 'resume_transaction',
18619                    }).html('Laskuta')
18620                  )
18621                  .append(' &nbsp; &nbsp; ')
18622                  .append(
18623                    $('<a />', {
18624                      href: '/ajax/close_transaction/' + transaction.id,
18625                      class: 'close_transaction',
18626                    }).html('Sulje')
18627                  )
18628              )
18629            );
18630          });
18631
18632          $html = $('<table />', {
18633            cellspacing: '0',
18634            cellpadding: '0',
18635            border: '0',
18636            id: 'open_transactions_table',
18637          }).append(
18638            $('<thead />', {}).append(
18639              $('<tr />').append(
18640                $('<th />', { class: 'ui-helper-hidden' }).html('ID'),
18641                $('<th />').html('Pvm'),
18642                $('<th />').html('Klo'),
18643                $('<th />').html('Asiakas'),
18644                $('<th />').html('Tapahtuma'),
18645                $('<th />').html('Luottopäätös'),
18646                $('<th />', { width: '90px' }).html('')
18647              )
18648            ),
18649            $tbody
18650          );
18651        } else {
18652          $html = $('<p />', { style: 'padding-top:20px; margin:0; font-size:16px;' }).html(
18653            'Ei avoimia tapahtumia'
18654          );
18655        }
18656
18657        $wrapper.html($html);
18658        //console.log(responseJSON);
18659      });
18660    },
18661
18662    show_customer_info: function (person_info, credit_info) {
18663      //Set the person info
18664      $receiver_wrapper = $('#person_info').find('table tbody');
18665
18666      $receiver_wrapper
18667        .find('tr.name')
18668        .find('td.val')
18669        .html(person_info.lastname + ' ' + person_info.firstname);
18670      $receiver_wrapper
18671        .find('tr.address')
18672        .find('td.val')
18673        .html(person_info.address + '<br />' + person_info.zipcode + ' ' + person_info.city);
18674
18675      //$receiver_wrapper.find('input[name=\'person[customer_id]\']').val(person_info.id);
18676
18677      //$receiver_wrapper.find('input[name=\'person[gothia_cust_no]\']').val(person_info.gothia_cust_no
18677);
18678
18679      //$receiver_wrapper.find('input[name=\'person[ssn]\']').val(person_info.ssn);
18680
18681      //Set the credit check info
18682      //$receiver_wrapper.find('input[name=rating]').val(credit_info.rating);
18683
18684      //console.log($('#credit_info'));
18685
18686      $('#credit_info').show().find('.output').html('');
18687      $('#person_info').show();
18688      $('#financing_limit').hide();
18689
18690      switch (credit_info.decision) {
18691        case 1:
18692        case 3:
18693        case 4:
18694          $('#credit_decision').addClass('credit_green').removeClass('credit_red');
18695          $('#credit_decision').html('Puoltava');
18696          //$('#credit_decision_reason').css('font-weight', 'bold').show().html(credit_info.response_message);
18697          $('#credit_info').find('.output').show().html(credit_info.response_message);
18698
18699          if (credit_info.financing_limit) {
18700            $('#financing_limit')
18701              .show()
18702              .find('.output')
18703              .addClass('credit_green')
18704              .html(('' + (+credit_info.financing_limit).toFixed(2)).replace('.', ','));
18705          }
18706          break;
18707        case 2:
18708          $('#credit_decision').addClass('credit_red').removeClass('credit_green');
18709          $('#credit_decision').html('Kielteinen');
18710          $('#credit_info').find('.output').show().html(credit_info.response_message);
18711          break;
18712        default:
18713          $('#credit_decision').removeClass('credit_red').removeClass('credit_green');
18714          $('#credit_decision').html('');
18715          $('#credit_info').find('.output').show().html(credit_info.response_message);
18716          break;
18717      }
18718
18719      //Show the btn
18720      $('#create_invoice').show();
18721    },
18722  }, //etusivu
18723
18724  raportit: {
18725    init: function () {
18726      $('#report_tabs').tabs();
18727      $('body').delegate('#report_tabs', 'tabsshow', function (ev, ui) {
18728        var rex = /^[^#]*#/;
18729        var hash = ui.tab.href.replace(rex, '');
18730        window.location.hash = '#'.concat(hash);
18731      });
18732
18733      $('#reports tr:odd').each(function () {
18734        $(this).addClass('odd');
18735      });
18736
18737      $('#reports tr').hover(
18738        function () {
18739          $(this).addClass('hover');
18740        },
18741        function () {
18742          $(this).removeClass('hover');
18743        }
18744      );
18745
18746      $('select[name=company]').each(function () {
18747        global.renderCompaniesFilterOptions(this);
18748      });
18749
18750      $('#get_iv_reports')
18751        .button({})
18752        .on('click', function (e) {
18753          $form = $(e.target).parents('form');
18754
18755          //console.log($form.length);
18756
18757          var month = $form.find('select[name=month]').val(),
18758            year = $form.find('select[name=year]').val(),
18759            report_type = $form.find('.report_type:checked').val();
18760
18761          window.location = location.pathname + '/' + report_type + '/' + year + '/' + month + '/';
18762        });
18763
18764      $('#get_client_reports')
18765        .button({})
18766        .on('click', function (e) {
18767          $form = $(e.target).parents('form');
18768
18769          var company = $form.find('select[name=company]').val(),
18770            month = $form.find('select[name=month]').val(),
18771            year = $form.find('select[name=year]').val(),
18772            report_type = $form.find('.report_type:checked').val();
18773
18774          window.location =
18775            location.pathname + '/' + report_type + '/' + company + '/' + year + '/' + month + '/';
18776        });
18777    },
18778  },
18779
18780  reskontra: {
18781    $datatable: null,
18782    recurring_invoicing: null,
18783    $part_payments_datatable: null,
18784    $money_transfers_dt: null,
18785    $direct_payments_dt: null,
18786    $corporate_chain_invoices_dt: null,
18787    dataTableParams: {
18788      invoice: null,
18789      directPayments: null,
18790      partPayments: null,
18791    },
18792
18793    init: function (opts) {
18794      var showClientCompanies = opts && opts.showClientCompanies === 1 ? true : false;
18795      var d_from = new Date();
18796      d_from.setDate(1);
18797      var d_to = new Date();
18798      var $date_from = $(
18799        '<input type="text" class="text small" id="date_from" name="date_from" value="' +
18800          d_from.getDate() +
18801          '.' +
18802          (d_from.getMonth() + 1) +
18803          '.' +
18804          d_from.getFullYear() +
18805          '" />'
18806      ).datepicker($.datepicker.regional.fi);
18807      var $date_to = $(
18808        '<input type="text" class="text small" id="date_to" name="date_to" value="' +
18809          d_to.getDate() +
18810          '.' +
18811          (d_to.getMonth() + 1) +
18812          '.' +
18813          d_to.getFullYear() +
18814          '" />'
18815      ).datepicker($.datepicker.regional.fi);
18816
18817      [
18818        'input#filter-invoice-start-date',
18819        'input#filter-invoice-end-date',
18820        'input#filter-dp-start-date',
18821        'input#filter-dp-end-date',
18822        'input#filter-part-payment-start-date',
18823        'input#filter-part-payment-end-date',
18824        'input#filter-corporate-chain-start-date',
18825        'input#filter-corporate-chain-end-date',
18826        'input#filter-money-transfers-start-date',
18827        'input#filter-money-transfers-end-date',
18828      ].forEach(function (input) {
18829        if($(input).length === 0){
18830          return;
18831        }
18832        $(input).datepicker({
18833          showButtonPanel: true,
18834          language: 'fi-FI',
18835          weekStart: 1,
18836          todayHighlight: true,
18837          startDate: '-120m',
18838          autoclose: true,
18839          clearBtn: true,
18840          format: 'dd.mm.yyyy',
18841          forceParse: true,
18842          assumeNearbyYear: true,
18843        });
18844        // console.log('DATEPICKER INITED: ', input);
18845      });
18846
18847      $('#reskontra_tabs').tabs();
18848
18849      $('#corporate-chain-get_invoices')
18850        .button({ icons: { primary: 'ui-icon-search' } })
18851        .on('click', function () {
18852          pages.reskontra.$corporate_chain_invoices_dt.fnClearTable(0);
18853          pages.reskontra.$corporate_chain_invoices_dt.fnDraw();
18854        });
18855
18856      $('#new_invoice_person')
18857        .button({ icons: { primary: 'ui-icon-plusthick' } })
18858        .on('click', function () {
18859          //pages.reskontra.show_invoice_dialog('person');
18860          window.location = '/lasku/kuluttajalasku/';
18861        });
18862
18863      $('#new_invoice')
18864        .button({ icons: { primary: null, secondary: 'ui-icon-triangle-1-s' } })
18865        .wrap($('<div />', { style: 'float:left;' }))
18866        .wrap($('<div />', {}))
18867        .parent()
18868        .parent()
18869        .append(
18870          $('<ul />', { style: 'position:absolute; z-index:99; font-size:13px;' }).append(
18871            $('<li />', {}).append(
18872              $('<a />', { href: '/lasku/kuluttajalasku/' })
18873                .on('click', function () {
18874                  window.location = '/lasku/kuluttajalasku/';
18875                })
18876                .text('Kuluttajalle')
18877            ),
18878            $('<li />', {}).append(
18879              $('<a />', { href: '/lasku/yrityslasku/' })
18880                .on('click', function () {
18881                  window.location = '/lasku/yrityslasku/';
18882                })
18883                .text('Yritykselle')
18884            ),
18885            $('<li />', {}).append(
18886              $('<a />', { href: '/lasku/vakuutusyhtio/' })
18887                .on('click', function () {
18888                  window.location = '/lasku/vakuutusyhtio/';
18889                })
18890                .text('Vakuutusyhtiölle')
18891            )
18892          )
18893        )
18894        .parent()
18895        .parent()
18896        .find('#new_invoice')
18897        .on('click', function () {
18898          console.log('#new_invoice');
18899
18900          //pages.reskontra.show_invoice_dialog('company');
18901          //window.location = '/lasku/yrityslasku/';
18902          var $menu = $(this).parent().next();
18903
18904          if ($menu.is(':visible')) {
18905            $menu.hide();
18906          } else {
18907            $menu.show().position({
18908              my: 'left top',
18909              at: 'left bottom',
18910              of: this,
18911            });
18912          }
18913
18914          var menu = $(this).parent().next();
18915          $(document).one('click', function () {
18916            menu.hide();
18917          });
18918          return false;
18919        })
18920        .parent()
18921        .buttonset()
18922        .next()
18923        .hide()
18924        .menu();
18925
18926      $('#new_report')
18927        .button({ icons: { primary: null, secondary: 'ui-icon-triangle-1-s' } })
18928        .wrap($('<div />', { style: 'float:left;' }))
18929        .wrap($('<div />', {}))
18930        .parent()
18931        .parent()
18932        .append(
18933          $('<ul />', { style: 'position:absolute; z-index:99; font-size:13px;' }).append(
18934            $('<li />', {}).append(
18935              $('<a />', { href: '/' })
18936                .on('click', function (e) {
18937                  //window.location = '/lasku/kuluttajalasku/';
18938                  e.preventDefault();
18939                  window.FivaldiReport.reportModal.openDialog();
18940                })
18941                .text('Fivaldi-kirjanpitoraportti')
18942            ),
18943            $('<li />', {}).append(
18944              $('<a />', { href: '/' })
18945                .on('click', function (e) {
18946                  e.preventDefault();
18947                  window.InvoiceReport.reportModal.openDialog();
18948                })
18949                .text('Myynnit')
18950            ),
18951            $('<li />', {}).append(
18952              $('<a />', { href: '/' })
18953                .on('click', function (e) {
18954                  e.preventDefault();
18955                  pages.reskontra.showCreateOpenInvoicesReportDialog();
18956                })
18957                .text('Avoimet laskut')
18958            ),
18959            $('<li />', {}).append(
18960                $('<a />', { href: '/' })
18961                    .on('click', function (e) {
18962                      e.preventDefault();
18963                      window.SATReport.reportModal.openDialog();
18964                    })
18965                    .text('SAT-raportti')
18966            ),
18967            $('<li />', {}).append(
18968                $('<a />', { href: '/' })
18969                    .on('click', function (e) {
18970                      e.preventDefault();
18971                      window.CreditLossReport.reportModal.openDialog();
18972                    })
18973                    .text('Luottotappiot')
18974            )
18975          )
18976        )
18977        .parent()
18978        .parent()
18979        .find('#new_report')
18980        .on('click', function () {
18981          console.log('#new_report');
18982
18983          //pages.reskontra.show_invoice_dialog('company');
18984          //window.location = '/lasku/yrityslasku/';
18985          var $menu = $(this).parent().next();
18986
18987          if ($menu.is(':visible')) {
18988            $menu.hide();
18989          } else {
18990            $menu.show().position({
18991              my: 'left top',
18992              at: 'left bottom',
18993              of: this,
18994            });
18995          }
18996
18997          var menu = $(this).parent().next();
18998          $(document).one('click', function () {
18999            menu.hide();
19000          });
19001          return false;
19002        })
19003        .parent()
19004        .buttonset()
19005        .next()
19006        .hide()
19007        .menu();
19008
19009      $('#close_previous_accounting_period').on('click', function () {
19010        console.log('close previous accounting period');
19011
19012        var $closeButton = $(this);
19013
19014        $('<div></div>')
19015          .html('<p>Haluatko varmasti sulkea edellisen kirjanpitokauden?</p>')
19016          .dialog({
19017            autoOpen: true,
19018            modal: true,
19019            resizable: false,
19020            draggable: false,
19021            title: 'Sulje edellinen kirjanpitokausi',
19022            beforeClose: function (event, ui) {
19023              event.stopPropagation();
19024            },
19025            buttons: {
19026              Peruuta: function () {
19027                $(this).dialog('close');
19028              },
19029              'Sulje kirjanpitokausi': function () {
19030                pages.reskontra.close_previous_accounting_period($(this), $closeButton);
19031              },
19032            },
19033          });
19034      });
19035
19036      $('#new_invoice_company')
19037        .button({ icons: { primary: 'ui-icon-plusthick' } })
19038        .on('click', function () {
19039          //pages.reskontra.show_invoice_dialog('company');
19040          window.location = '/lasku/yrityslasku/';
19041        });
19042
19043      $('#new_configurable_report')
19044        .button({ icons: { primary: 'ui-icon-plusthick' } })
19045        .click(function () {
19046          window.InvoiceReport.reportModal.openDialog();
19047        }),
19048        $('#new_pos_payment')
19049          .button({ icons: { primary: 'ui-icon-plusthick' } })
19050          .click(function () {
19051            window.location.href = '/innokassa/add';
19052          }),
19053        $('#new_invoice_report')
19054          .button({ icons: { primary: 'ui-icon-plusthick' } })
19055          .on('click', function () {
19056            pages.reskontra.createInvoiceReport();
19057          });
19058
19059      $('#new_direct_payments_report')
19060        .button({ icons: { primary: 'ui-icon-plusthick' } })
19061        .on('click', function () {
19062          var $createReportDialog = $('<div></div>')
19063            .append(
19064              $('<form />', {
19065                id: 'create_direct_payments_report',
19066                target: '_blank',
19067                method: 'post',
19068              }).append(
19069                $('<span />', { class: 'ui-helper-hidden-accessible' }).append('<input />', {
19070                  type: 'text',
19071                }),
19072                $('<fieldset />', { class: 'fs-invisible', style: '' }).append(
19073                  $('<ol />').append(
19074                    $('<li />', { style: 'padding:7px 0;' }).append(
19075                      $('<label />', { id: 'date_from_label', style: 'width:130px;' }).html(
19076                        'Kassaraportti ajalta'
19077                      ),
19078                      $date_from,
19079                      ' - ',
19080                      $date_to
19081                    ),
19082                    $('<li />', { style: 'padding:7px 0;' }).append(
19083                      $('<label />', {
19084                        id: '',
19085                        style: 'font-weight:bold; width:130px; height:40px;',
19086                      }).html('Maksutapa'),
19087                      $('<select/>', { name: 'filters[payment_type]' }).append(
19088                        $('<option />', { value: 'all' }).html('Kaikki'),
19089                        $('<option />', { value: 'cash' }).html('Käteismaksu'),
19090                        $('<option />', { value: 'card' }).html('Korttimaksu'),
19091                        $('<option />', { value: 'cash_on_delivery' }).html('Jälkivaatimus')
19092                      )
19093                    )
19094                  )
19095                )
19096              )
19097            )
19098            .dialog({
19099              width: 550,
19100              autoOpen: true,
19101              modal: true,
19102              resizable: false,
19103              draggable: false,
19104              beforeClose: function (event, ui) {
19105                event.stopPropagation();
19106              },
19107              title: 'Luo kassaraportti',
19108              buttons: {
19109                Peruuta: function () {
19110                  $(this).dialog('close');
19111                },
19112                'Luo PDF': function () {
19113                  $createReportDialog
19114                    .find('form')
19115                    .attr('action', '/reskontra/create_direct_payments_report/pdf')
19116                    .submit();
19117                  // $createReportDialog.find('form')
19118                },
19119                /*
19120                    'Luo CSV': function() {
19121                      $createReportDialog
19122                          .find('form')
19123                          .attr('action', '/reskontra/create_direct_payments_report/csv')
19124                          .submit();
19125                    },
19126
19127                     */
19128              },
19129            });
19130        });
19131
19132      $('#new_invoice_from_registry')
19133        .button({ icons: { primary: 'ui-icon-plusthick' } })
19134        .on('click', function () {
19135          window.location = '/lasku/asiakasrekisterista/';
19136        });
19137
19138      $('#new_invoice_insurance_company')
19139        .button({ icons: { primary: 'ui-icon-plusthick' } })
19140        .on('click', function () {
19141          window.location = '/lasku/vakuutusyhtio/';
19142        });
19143
19144      $('#new_part_payment')
19145        .button({ icons: { primary: 'ui-icon-plusthick' } })
19146        .on('click', function () {
19147          window.location = '/osamaksu/';
19148        });
19149
19150      $('button#export_invoice_csv').on('click', function (event) {
19151        event.preventDefault();
19152
19153        pages.reskontra.getDatatableCsv(pages.reskontra.dataTableParams.invoice, 'invoice', 'button#export_invoice_csv');
19154      });
19155
19156      $('button#export_part_payment_csv').on('click', function (event) {
19157        event.preventDefault();
19158
19159        pages.reskontra.getDatatableCsv(pages.reskontra.dataTableParams.partPayments, 'partPayment', 'button#export_part_payment_csv');
19160      });
19161
19162      $('button#export_direct_payment_csv').on('click', function (event) {
19163        event.preventDefault();
19164
19165        pages.reskontra.getDatatableCsv(pages.reskontra.dataTableParams.directPayments, 'directPayment', 'button#export_direct_payment_csv');
19166      });
19167
19168      $('#corporate-chain-invoices_filter_form.extended').delegate(
19169        'input:checkbox',
19170        'change',
19171        function () {
19172          var filter = $(this).attr('name'),
19173            is_checked = $(this).is(':checked');
19174
19175          if (filter != 'all' && is_checked) {
19176            $('#corporate-chain-invoices_filter_form')
19177              .find('input[name=all]')
19178              .prop('checked', false);
19179          }
19180
19181          if (filter == 'all' && is_checked) {
19182            $('#corporate-chain-invoices_filter_form')
19183              .find('input:checkbox:checked')
19184              .each(function (index, elem) {
19185                if ($(elem).attr('name') != 'all') {
19186                  $(elem).prop('checked', false);
19187                }
19188              });
19189          }
19190        }
19191      );
19192
19193      $(
19194        '#corporate-chain-invoices_filter_form input:checkbox, #corporate-chain-invoices_filter_form select'
19195      ).change(function (e) {
19196        var filters = [];
19197
19198        $('#corporate-chain-invoices_filter_form input:checkbox:checked').each(function () {
19199          filters.push($(this).attr('name'));
19200        });
19201        if(filters.length === 0){
19202          return;
19203        }
19204        // Timeout used here to prevent sending checked checkboxes when swithing from any filter -> all
19205        // If fnDraw() is called when swithcing checkboxes, previous filter will override all filter
19206        setTimeout(function () {
19207          pages.reskontra.$corporate_chain_invoices_dt.fnClearTable(0);
19208          pages.reskontra.$corporate_chain_invoices_dt.fnDraw();
19209        }, 1);
19210      });
19211
19212      $('#invoices_filter_form.extended').delegate('input:checkbox', 'change', function () {
19213        var filter = $(this).attr('name'),
19214          is_checked = $(this).is(':checked');
19215
19216        if (filter != 'all' && is_checked) {
19217          $('#invoices_filter_form').find('input[name=all]').prop('checked', false);
19218        }
19219
19220        if (filter == 'all' && is_checked) {
19221          $('#invoices_filter_form')
19222            .find('input:checkbox:checked')
19223            .each(function (index, elem) {
19224              if ($(elem).attr('name') != 'all') {
19225                $(elem).prop('checked', false);
19226              }
19227            });
19228        }
19229      });
19230
19231      $('#invoices_dt').on('click', 'a.show_invoice, a.show_invoice_log', function (e) {
19232        e.preventDefault();
19233
19234        var invoice_id = $(e.target).attr('href');
19235        var action = $(e.target).attr('class');
19236
19237        var n = invoice_id.lastIndexOf('/');
19238
19239        invoice_id = invoice_id.substring(n + 1);
19240
19241        switch (action) {
19242          case 'show_invoice':
19243            pages.reskontra.show_invoice(invoice_id);
19244            break;
19245          case 'show_invoice_log':
19246            pages.reskontra.show_invoice_log(invoice_id);
19247            break;
19248        }
19249      });
19250     
19251
19252      $('#corporate-chain-invoices_dt').on(
19253        'click',
19254        'a.show_invoice, a.show_invoice_log',
19255        function (e) {
19256          e.preventDefault();
19257
19258          var invoice_id = $(e.target).attr('href');
19259          var action = $(e.target).attr('class');
19260
19261          var n = invoice_id.lastIndexOf('/');
19262
19263          invoice_id = invoice_id.substring(n + 1);
19264
19265          switch (action) {
19266            case 'show_invoice':
19267              pages.reskontra.show_invoice(invoice_id);
19268              break;
19269            case 'show_invoice_log':
19270              pages.reskontra.show_invoice_log(invoice_id);
19271              break;
19272          }
19273        }
19274      );
19275
19276      $('#money_transfers_dt').on('click', 'a.show_money_transfer_item', function (e) {
19277        e.preventDefault();
19278        var money_transfer_item_url = $(e.target).attr('href');
19279        var action = $(e.target).attr('class');
19280        var parts = money_transfer_item_url.split('/');
19281
19282        switch (action) {
19283          case 'show_money_transfer_item':
19284            pages.reskontra.show_money_transfer_item(parts[1], parts[0]);
19285            break;
19286        }
19287      });
19288
19289      $('#direct_payments_dt').on(
19290        'click',
19291        'a.show_add_payment_dialog, a.show_account_card, a.show_direct_payment_log, a.reskontra_show_job_order, a.show_direct_payment, a.show_pos_payment, a.show_freight',
19292
19293        function (e) {
19294          console.log('here');
19295          e.preventDefault();
19296          var id = $(e.target).attr('href');
19297          var action = $(e.target).attr('class');
19298          var companyId = $(e.target).attr('data-companyId');
19299          var openAmount = $(e.target).attr('data-openAmount');
19300
19301          switch (action) {
19302            case 'show_add_payment_dialog':
19303              pages.reskontra.showAddDirectPaymentDialog(id, openAmount);
19304              break;
19305            case 'show_account_card':
19306              window.AccountCard.show(companyId);
19307              break;
19308            case 'reskontra_show_job_order':
19309              window.openDialog(id);
19310              break;
19311            case 'show_direct_payment_log':
19312              global.show_log(id);
19313              break;
19314            case 'show_direct_payment':
19315              pages.reskontra.show_direct_payment(id);
19316              break;
19317            case 'show_pos_payment':
19318              document.location.href = '/innokassa/edit/' + id;
19319              break;
19320            case 'show_freight':
19321              // @ai:claude same-window navigation for freight links; href already holds the full /innorahti/edit/{id} path
19322              document.location.href = id;
19323              break;
19324          }
19325        }
19326      );
19327
19328      var showStationField =
19329        window.App.company.mod_company_group && window.App.company.company_group_admin;
19330
19331
19332      if($('#toistuva_laskutus').length !== 0){
19333        pages.reskontra.recurring_invoicing = new recurringInvoicing({
19334          showStation: showStationField,
19335          isAdmin: false,
19336          controller: '/reskontra',
19337          invoiceEndpoint: '/reskontra/invoicesDataTable/'
19338        });
19339        
19340        pages.reskontra.recurring_invoicing.init();
19341       
19342      } 
19343      //If there is part_payments datatable init it
19344      if ($('#part_payments_dt').size()) {
19345        $('#part_payments_dt').on('click', 'a', function (e) {
19346          e.preventDefault();
19347
19348          var id = $(e.target).attr('href');
19349          var action = $(e.target).attr('class');
19350
19351          switch (action) {
19352            case 'show_part_payment_log':
19353              global.show_log(id);
19354              break;
19355            case 'show_part_payment':
19356              pages.reskontra.show_part_payment(id);
19357              break;
19358            case 'show_invoice':
19359              pages.reskontra.show_invoice(id);
19360              break;
19361            case 'show_invoice_log':
19362              pages.reskontra.show_invoice_log(id);
19363              break;
19364          }
19365        });
19366
19367        $('#part_payments_filter_form').find('select[name="company[]"]').on('changed.bs.select', function (e, clickedIndex, isSelected) {
19368          var $select = $(this);
19369          var selectedValues = $select.val() ? $select.val() : [];
19370          
19371          if (selectedValues.includes('all') && selectedValues.length > 1) {
19372              if ($select.find('option').eq(clickedIndex).val() === 'all') {
19373                  selectedValues = ['all'];
19374              } else {
19375                  selectedValues = selectedValues.filter(function(company){ return company !== 'all'});
19376              }
19377              $select.selectpicker('val', selectedValues);
19378          }
19379          
19380        });
19381        
19382        //If company group admin, we want to show the company field in datatable
19383
19384        pages.reskontra.$part_payments_datatable = $('#part_payments_dt').dataTable({
19385          oLanguage: global.dataTablesLanguage,
19386          sPaginationType: 'full_numbers',
19387          bPaginate: true,
19388          bAutoWidth: false,
19389          bJQueryUI: true,
19390          bFilter: true,
19391          bInfo: true,
19392          bProcessing: true,
19393          bServerSide: true,
19394          sAjaxSource: 'osamaksu/get_part_payments/',
19395          aoColumns: [
19396            /** SopimusNr **/ null,
19397            /** Yritys **/ { bVisible: false, bSearchable: false },
19398            /** Toimipiste **/ { bVisible: showStationField, bSortable: false, bSearchable: false },
19399            /** Luotonhakija **/ null,
19400            /** Summa **/ null,
19401            /** Sopimuspvm **/ { sType: 'date-eu' },
19402            /** Käsirahan eräpäivä **/ { bVisible: false, bSearchable: false },
19403            /** Toimituspvm **/ { sType: 'date-eu' },
19404            /** Rahoituspvm **/ { bVisible: false, bSearchable: false },
19405            /** Sopimuksen tila **/ null,
19406            /** Käsirahan tila **/ { bVisible: false, bSearchable: false },
19407            /** Käsirahalasku ID **/ { bVisible: false, bSearchable: false },
19408            /** Tililasku ID **/ { bVisible: false, bSearchable: false },
19409            /** Käsirahalasku **/ { bVisible: false, bSearchable: false },
19410            /** Tililasku **/ { bVisible: false, bSearchable: false },
19411          ],
19412          aaSorting: [[0, 'desc']],
19413
19414          fnServerParams: function (aoData) {
19415            var month = $('#osamaksusopimukset')
19416              .find('select[name=month] option:selected')
19417              .attr('value');
19418            var year = $('#osamaksusopimukset')
19419              .find('select[name=year] option:selected')
19420              .attr('value');
19421
19422            var selectedCompanies = $('#part_payments_filter_form select[name="company[]"]').val() ? $('#part_payments_filter_form select[name="company[]"]').val() : [];
19423
19424            if (selectedCompanies.includes('all')){
19425              selectedCompanies = selectedCompanies.filter(function (company) { return company !== 'all'});
19426            }
19427  
19428            company = selectedCompanies.includes('all') ? 'all' : selectedCompanies;
19429
19430            var startDate;
19431            var endDate;
19432            if ($('input#filter-part-payment-start-date').length > 0) {
19433              startDate = $('input#filter-part-payment-start-date')[0].value;
19434              endDate = $('input#filter-part-payment-end-date')[0].value;
19435            }
19436
19437            var filters = [];
19438
19439            $('#part_payments_filter_form input:checkbox:checked').each(function () {
19440              filters.push($(this).attr('name'));
19441            });
19442
19443            // filters.push('part_payments');
19444
19445            aoData.push({ name: 'month', value: month });
19446            aoData.push({ name: 'year', value: year });
19447            aoData.push({ name: 'company', value: company });
19448            aoData.push({ name: 'startDate', value: startDate });
19449            aoData.push({ name: 'endDate', value: endDate });
19450            aoData.push({ name: 'filters', value: filters });
19451
19452            $('#export_part_payment_csv').html(global.$mini_loader).attr('disabled', true);
19453            pages.reskontra.dataTableParams.partPayments = aoData;
19454          },
19455
19456          fnInfoCallback: function (oSettings, iStart, iEnd, iMax, iTotal, sPre) {
19457
19458            var responseJson = JSON.parse(oSettings.jqXHR.responseText);
19459            var sums = responseJson.iSumma;
19460            if (typeof sums !== 'undefined') {
19461              return (
19462                'N&auml;ytet&auml;&auml;n rivit ' +
19463                iStart +
19464                ' - ' +
19465                iEnd +
19466                ' / ' +
19467                iTotal +
19468                ',  summa: ' +
19469                sums.sumTotal
19470              );
19471            }
19472            return 'N&auml;ytet&auml;&auml;n rivit ' + iStart + ' - ' + iEnd + ' / ' + iTotal;
19473          },
19474
19475          fnDrawCallback: function(){
19476            $('#export_part_payment_csv').html('Vie Csv-tiedostoon').attr('disabled', false);
19477          },
19478
19479          //Called before each row is shown
19480          fnRowCallback: function (nRow, aData, iDisplayIndex) {
19481            var part_payment_id = aData[0];
19482            var part_payment_status = aData[9];
19483            var down_payment_status = aData[10];
19484
19485            var down_payment_invoice_id = aData[11];
19486            var part_payment_invoice_id = aData[12];
19487
19488            var down_payment_invoice_no = aData[13];
19489            var part_payment_invoice_no = aData[14];
19490            //var open_sum = aData[8];
19491            //var row_class = aData[12];
19492            //var status = aData[11];
19493
19494            //Add the transaction id to every rows data object
19495            //$(nRow).addClass(row_class);
19496            $('td:eq(0)', nRow).html(
19497              '<a href="' +
19498                part_payment_id +
19499                '" class="show_part_payment" >' +
19500                part_payment_id +
19501                '</a>'
19502            );
19503            $('td:eq(' + (5 + showStationField) + ')', nRow).html(
19504              '<a href="/logs/getLogHtml/part_payment/' +
19505                part_payment_id +
19506                '" name="global" class="show_part_payment_log" >' +
19507                part_payment_status +
19508                '</a>'
19509            );
19510
19511            if (part_payment_invoice_id == null) {
19512              $('td:eq(' + (9 + showStationField) + ')', nRow).html('');
19513            } else {
19514              $('td:eq(' + (9 + showStationField) + ')', nRow).html(
19515                '<a href="' +
19516                  part_payment_invoice_id +
19517                  '" class="show_invoice" >' +
19518                  part_payment_invoice_no +
19519                  '</a>'
19520              );
19521            }
19522
19523            if (down_payment_invoice_id == null) {
19524              $('td:eq(' + (6 + showStationField) + ')', nRow).html('');
19525              $('td:eq(' + (7 + showStationField) + ')', nRow).html('');
19526            } else {
19527              $('td:eq(' + (6 + showStationField) + ')', nRow).html(
19528                '<a href="' +
19529                  down_payment_invoice_id +
19530                  '" class="show_invoice_log" >' +
19531                  down_payment_status +
19532                  '</a>'
19533              );
19534              $('td:eq(' + (7 + showStationField) + ')', nRow)
19535                .addClass('status')
19536                .html(
19537                  '<a href="' +
19538                    down_payment_invoice_id +
19539                    '" class="show_invoice" >' +
19540                    down_payment_invoice_no +
19541                    '</a>'
19542                );
19543            }
19544
19545            return nRow;
19546          },
19547        });
19548
19549        $('#part_payments_filter_form input:checkbox, #part_payments_filter_form select').change(
19550          function (e) {
19551            var filters = [];
19552
19553            $('#part_payments_filter_form input:checkbox:checked').each(function () {
19554              filters.push($(this).attr('name'));
19555            });
19556            if(filters.length === 0){
19557              return;
19558            }
19559            
19560            setTimeout(function () {
19561              pages.reskontra.$part_payments_datatable.fnClearTable(0);
19562              pages.reskontra.$part_payments_datatable.fnDraw();
19563            }, 1);
19564        
19565          }
19566        );
19567      }
19568
19569      function isCorrectDateFormat(input) {
19570        return /^([0-9]|[0-9]{2})[./]([0-9]|[0-9]{2})[./]([0-9]{4})$/.test(input);
19571      }
19572
19573      $('#invoices_filter_form input:checkbox, #invoices_filter_form select').change(function (e) {
19574        var filters = [];
19575
19576        $('#invoices_filter_form input:checkbox:checked').each(function () {
19577          filters.push($(this).attr('name'));
19578        });
19579        if(filters.length === 0){
19580          return;
19581        }
19582        // Timeout used here to prevent sending checked checkboxes when swithing from any filter -> all
19583        // If fnDraw() is called when swithcing checkboxes, previous filter will override all filter
19584        setTimeout(function () {
19585          pages.reskontra.$datatable.fnClearTable(0);
19586          pages.reskontra.$datatable.fnDraw();
19587        }, 1);
19588      });
19589
19590      $('.input-group.date .input-group-addon.open-calendar').on('click', function (e) {
19591        e.preventDefault();
19592        $(this).parent().children().first().trigger('focus');
19593      });
19594      $('.input-group.date .input-group-addon.delete-date').on('click', function (e) {
19595        e.preventDefault();
19596        $(this).parent().children().first().datepicker('update', '');
19597        $(this).parent().children().first().trigger('changeDate');
19598      });
19599      $('input#filter-invoice-start-date, input#filter-invoice-end-date').each(function () {
19600        $(this).on('change changeDate clearDate blur', function (e) {
19601          var d = e.target.value;
19602          if (/^[0-9]{6}$/.test(d)) {
19603            $(this).datepicker('update', d[0] + d[1] + '.' + d[2] + d[3] + '.20' + d[4] + d[5]);
19604            $(this).trigger('changeDate');
19605            $(this).trigger('blur');
19606            $(this).datepicker('hide');
19607            return;
19608          }
19609          if (/^[0-9]{8}$/.test(d)) {
19610            $(this).datepicker(
19611              'update',
19612              d[0] + d[1] + '.' + d[2] + d[3] + '.' + d[4] + d[5] + d[6] + d[7]
19613            );
19614            $(this).trigger('changeDate');
19615            $(this).trigger('blur');
19616            $(this).datepicker('hide');
19617            return;
19618          }
19619          if (!!d && !isCorrectDateFormat(d)) {
19620            if (e.type === 'blur') {
19621              $(this).datepicker('update', '');
19622            }
19623            return;
19624          }
19625          if (e.type === 'changeDate') {
19626            setTimeout(function () {
19627              pages.reskontra.$datatable.fnClearTable(0);
19628              pages.reskontra.$datatable.fnDraw();
19629            }, 1);
19630          }
19631        });
19632      });
19633      $('input#filter-dp-end-date, input#filter-dp-start-date').each(function () {
19634        $(this).on('change changeDate blur', function (e) {
19635          var d = e.target.value;
19636          if (/^[0-9]{6}$/.test(d)) {
19637            $(this).datepicker('update', d[0] + d[1] + '.' + d[2] + d[3] + '.20' + d[4] + d[5]);
19638            $(this).trigger('changeDate');
19639            $(this).trigger('blur');
19640            $(this).datepicker('hide');
19641            return;
19642          }
19643          if (/^[0-9]{8}$/.test(d)) {
19644            $(this).datepicker(
19645              'update',
19646              d[0] + d[1] + '.' + d[2] + d[3] + '.' + d[4] + d[5] + d[6] + d[7]
19647            );
19648            $(this).trigger('changeDate');
19649            $(this).trigger('blur');
19650            $(this).datepicker('hide');
19651            return;
19652          }
19653          if (!!e.target.value && !isCorrectDateFormat(d)) {
19654            if (e.type === 'blur') {
19655              $(this).datepicker('update', '');
19656            }
19657            return;
19658          }
19659          if (e.type === 'changeDate') {
19660            setTimeout(function () {
19661              pages.reskontra.$direct_payments_dt.fnClearTable(0);
19662              pages.reskontra.$direct_payments_dt.fnDraw();
19663            }, 1);
19664          }
19665        });
19666      });
19667      $('input#filter-part-payment-end-date, input#filter-part-payment-start-date').each(
19668        function () {
19669          $(this).on('change changeDate blur', function (e) {
19670            var d = e.target.value;
19671            if (/^[0-9]{6}$/.test(d)) {
19672              $(this).datepicker('update', d[0] + d[1] + '.' + d[2] + d[3] + '.20' + d[4] + d[5]);
19673              $(this).trigger('changeDate');
19674              $(this).trigger('blur');
19675              $(this).datepicker('hide');
19676              return;
19677            }
19678            if (/^[0-9]{8}$/.test(d)) {
19679              $(this).datepicker(
19680                'update',
19681                d[0] + d[1] + '.' + d[2] + d[3] + '.' + d[4] + d[5] + d[6] + d[7]
19682              );
19683              $(this).trigger('changeDate');
19684              $(this).trigger('blur');
19685              $(this).datepicker('hide');
19686              return;
19687            }
19688            if (!!e.target.value && !isCorrectDateFormat(d)) {
19689              if (e.type === 'blur') {
19690                $(this).datepicker('update', '');
19691              }
19692              return;
19693            }
19694            if (e.type === 'changeDate') {
19695              setTimeout(function () {
19696                pages.reskontra.$part_payments_datatable.fnClearTable(0);
19697                pages.reskontra.$part_payments_datatable.fnDraw();
19698              }, 1);
19699            }
19700          });
19701        }
19702      );
19703      $('input#filter-money-transfers-end-date, input#filter-money-transfers-start-date').each(
19704        function () {
19705          $(this).on('change changeDate blur', function (e) {
19706            var d = e.target.value;
19707            if (/^[0-9]{6}$/.test(d)) {
19708              $(this).datepicker('update', d[0] + d[1] + '.' + d[2] + d[3] + '.20' + d[4] + d[5]);
19709              $(this).trigger('changeDate');
19710              $(this).trigger('blur');
19711              $(this).datepicker('hide');
19712              return;
19713            }
19714            if (/^[0-9]{8}$/.test(d)) {
19715              $(this).datepicker(
19716                'update',
19717                d[0] + d[1] + '.' + d[2] + d[3] + '.' + d[4] + d[5] + d[6] + d[7]
19718              );
19719              $(this).trigger('changeDate');
19720              $(this).trigger('blur');
19721              $(this).datepicker('hide');
19722              return;
19723            }
19724            if (!!e.target.value && !isCorrectDateFormat(d)) {
19725              if (e.type === 'blur') {
19726                $(this).datepicker('update', '');
19727              }
19728              return;
19729            }
19730            if (e.type === 'changeDate') {
19731              setTimeout(function () {
19732                pages.reskontra.$money_transfers_dt.fnClearTable(0);
19733                pages.reskontra.$money_transfers_dt.fnDraw();
19734              }, 1);
19735            }
19736          });
19737        }
19738      );
19739      $('input#filter-corporate-chain-end-date, input#filter-corporate-chain-start-date').each(
19740        function () {
19741          $(this).on('change changeDate blur', function (e) {
19742            var d = e.target.value;
19743            if (/^[0-9]{6}$/.test(d)) {
19744              $(this).datepicker('update', d[0] + d[1] + '.' + d[2] + d[3] + '.20' + d[4] + d[5]);
19745              $(this).trigger('changeDate');
19746              $(this).trigger('blur');
19747              $(this).datepicker('hide');
19748              return;
19749            }
19750            if (/^[0-9]{8}$/.test(d)) {
19751              $(this).datepicker(
19752                'update',
19753                d[0] + d[1] + '.' + d[2] + d[3] + '.' + d[4] + d[5] + d[6] + d[7]
19754              );
19755              $(this).trigger('changeDate');
19756              $(this).trigger('blur');
19757              $(this).datepicker('hide');
19758              return;
19759            }
19760            if (!!e.target.value && !isCorrectDateFormat(d)) {
19761              if (e.type === 'blur') {
19762                $(this).datepicker('update', '');
19763              }
19764              return;
19765            }
19766            if (e.type === 'changeDate') {
19767              setTimeout(function () {
19768                pages.reskontra.$corporate_chain_invoices_dt.fnClearTable(0);
19769                pages.reskontra.$corporate_chain_invoices_dt.fnDraw();
19770              }, 1);
19771            }
19772          });
19773        }
19774      );
19775
19776      $('#invoices_filter_form').find('select[name="company[]"]').on('changed.bs.select', function (e, clickedIndex, isSelected) {
19777        var $select = $(this);
19778        var selectedValues = $select.val() ? $select.val() : [];
19779
19780        if (selectedValues.includes('all') && selectedValues.length > 1) {
19781            if (isSelected && $select.find('option').eq(clickedIndex).val() === 'all') {
19782                selectedValues = ['all'];
19783            } else {
19784                selectedValues = selectedValues.filter(function(company) {return company !== 'all'});
19785            }
19786            $select.selectpicker('val', selectedValues);
19787        }
19788      });
19789
19790      pages.reskontra.$datatable = $('#invoices_dt').dataTable({
19791        oSearch: {"sSearch": intialSearch},
19792        oLanguage: global.dataTablesLanguage,
19793        sPaginationType: 'full_numbers',
19794        bPaginate: true,
19795        iDisplayLength: 25,
19796        bAutoWidth: false,
19797        bJQueryUI: true,
19798        bFilter: true,
19799        bInfo: true,
19800        bProcessing: true,
19801        bServerSide: true,
19802        sAjaxSource: 'reskontra/invoicesDataTable/',
19803        aoColumns: [
19804          /** id **/ { bVisible: false, bSortable: true, bSearchable: true },
19805          /** invoice_number **/ { bVisible: true, bSortable: false, bSearchable: true },
19806          /** reference_nr **/ { bVisible: false, bSortable: false, bSearchable: true },
19807          /** company **/ { bVisible: false, bSortable: false, bSearchable: false },
19808          /** station **/ { bVisible: showStationField, bSortable: false, bSearchable: false },
19809          /** receiver **/ null,
19810          /** c/o **/ { bVisible: false, bSearchable: true, bSortable: false },
19811          /** delivery_date **/ { sType: 'date-eu' },
19812          /** due_date **/ { sType: 'date-eu' },
19813          /** sum **/ { bSortable: false, bSearchable: false },
19814          /** open_amount **/ { bVisible: true, bSortable: false, bSearchable: false },
19815          /** is_financed **/ { bVisible: false, bSortable: false, bSearchable: false },
19816          /** our_reference **/ null,
19817          /** status **/ null,
19818          /** status_class **/ { bVisible: false },
19819          /** customer_id **/ { bVisible: false, bSearchable: false, bSortable: false },
19820          /** customer_type **/ { bVisible: false, bSearchable: false, bSortable: false },
19821        ],
19822        aaSorting: [[0, 'desc']],
19823
19824        fnServerParams: function (aoData) {
19825          var month = $('#invoices_filter_form select[name="month"] option:selected').attr('value');
19826          var year = $('#invoices_filter_form select[name="year"] option:selected').attr('value');
19827          var startDate;
19828          var endDate;
19829          if ($('input#filter-invoice-start-date').length > 0) {
19830            startDate = $('input#filter-invoice-start-date')[0].value;
19831            endDate = $('input#filter-invoice-end-date')[0].value;
19832          }
19833
19834          var filters = [];
19835          var selectedCompanies = $('#invoices_filter_form select[name="company[]"]').val() ? $('#invoices_filter_form select[name="company[]"]').val() : [];
19836
19837          if (selectedCompanies.includes('all') && selectedCompanies.length > 1){
19838            selectedCompanies = selectedCompanies.filter(function(company){return company !== 'all'});
19839          }
19840
19841          company = selectedCompanies.includes('all') ? 'all' : selectedCompanies;
19842
19843          $('#invoices_filter_form input:checkbox:checked').each(function () {
19844            filters.push($(this).attr('name'));
19845          });
19846
19847          aoData.push({ name: 'month', value: month });
19848          aoData.push({ name: 'year', value: year });
19849          aoData.push({ name: 'company', value: company });
19850          aoData.push({ name: 'startDate', value: startDate });
19851          aoData.push({ name: 'endDate', value: endDate });
19852          aoData.push({ name: 'filters', value: filters });
19853
19854          $('#export_invoice_csv').attr('disabled', true);
19855          $('#export_invoice_csv').html(global.$mini_loader);
19856          pages.reskontra.dataTableParams.invoice = aoData;
19857        },
19858
19859        fnInfoCallback: function (oSettings, iStart, iEnd, iMax, iTotal, sPre) {
19860
19861          var responseJson = JSON.parse(oSettings.jqXHR.responseText);
19862          var sums = responseJson.iSumma;
19863          if (typeof sums !== 'undefined') {
19864            return (
19865              'N&auml;ytet&auml;&auml;n rivit ' +
19866              iStart +
19867              ' - ' +
19868              iEnd +
19869              ' / ' +
19870              iTotal +
19871              ',  summa: ' +
19872              sums.amountToPay +
19873              ',  avoinna: ' +
19874              sums.openAmount
19875            );
19876          }
19877          return 'N&auml;ytet&auml;&auml;n rivit ' + iStart + ' - ' + iEnd + ' / ' + iTotal;
19878        },
19879
19880        fnDrawCallback: function () {
19881          var month = $('#invoices_filter_form select.month option:selected').html();
19882          var year = $('#invoices_filter_form select.year option:selected').html();
19883          $('#ac-tab-invoices span.month_year').html(month + ', ' + year);
19884          $('#export_invoice_csv').html('Vie Csv-tiedostoon').attr('disabled', false);
19885        },
19886
19887        //Called before each row is shown
19888        fnRowCallback: function (nRow, aData, iDisplayIndex) {
19889          var invoiceId = aData[0];
19890          var invoiceNumber = aData[1];
19891          var rowClass = aData[14];
19892          var status = aData[13];
19893
19894          //Add the transaction id to every rows data object
19895          //$(nRow).data({"invoice_id":invoice_id});
19896          $(nRow).addClass(rowClass);
19897
19898          $('td:eq(0)', nRow).html(
19899            '<a href="' + invoiceId + '" class="show_invoice" >' + invoiceNumber + '</a>'
19900          );
19901
19902          //Status column is 8:th in case the station col is visible
19903          $('td:eq(' + (7 + showStationField) + ')', nRow)
19904            .addClass('status')
19905            .html('<a href="' + invoiceId + '" class="show_invoice_log" >' + status + '</a>');
19906
19907          return nRow;
19908        },
19909      });
19910
19911      pages.reskontra.$corporate_chain_invoices_dt = $('#corporate-chain-invoices_dt').dataTable({
19912        oLanguage: global.dataTablesLanguage,
19913        sPaginationType: 'full_numbers',
19914        bPaginate: true,
19915        iDisplayLength: 10,
19916        bAutoWidth: false,
19917        bJQueryUI: true,
19918        bFilter: true,
19919        bInfo: true,
19920        bProcessing: true,
19921        bServerSide: true,
19922        sAjaxSource: 'reskontra/invoicesDataTable/',
19923        aoColumns: [
19924          /** invoice_id **/ null,
19925          /** gothia_invoice_number **/ { bVisible: false, bSortable: false, bSearchable: true },
19926          /** reference_nr **/ { bVisible: false, bSortable: false, bSearchable: true },
19927          /** company **/ { bVisible: true, bSortable: false, bSearchable: false },
19928          /** Toimipiste **/ { bVisible: false, bSortable: false, bSearchable: false },
19929          /** receiver **/ null,
19930          /** c/o **/ { bVisible: false, bSearchable: true, bSortable: false },
19931          /** date **/ { sType: 'date-eu' },
19932          /** due_date **/ { sType: 'date-eu' },
19933          /** sum **/ { bSortable: false, bSearchable: false },
19934          /** open_sum **/ { bVisible: true, bSortable: false, bSearchable: false },
19935          /** rahoitettu **/ { bVisible: false, bSortable: false, bSearchable: false },
19936          /** our_reference **/ null,
19937          /** status **/ null,
19938          /** status_class **/ { bVisible: false },
19939          /** customer_id **/ { bVisible: false, bSearchable: false, bSortable: false },
19940          /** customer_type **/ { bVisible: false, bSearchable: false, bSortable: false },
19941        ],
19942        aaSorting: [[0, 'desc']],
19943
19944        fnServerParams: function (aoData) {
19945          var month = $('#corporate-chain-invoices_filter_form select.month option:selected').attr(
19946            'value'
19947          ) || 'all';
19948          var year = $('#corporate-chain-invoices_filter_form select.year option:selected').attr(
19949            'value'
19950          ) || 'all';
19951
19952          var startDate;
19953          var endDate;
19954          if ($('input#filter-corporate-chain-start-date').length > 0) {
19955            startDate = $('input#filter-corporate-chain-start-date')[0].value;
19956            endDate = $('input#filter-corporate-chain-end-date')[0].value;
19957          }
19958
19959          var filters = [];
19960
19961          filters.push('corporate_chain_invoices');
19962
19963          $('#corporate-chain-invoices_filter_form input:checkbox:checked').each(function () {
19964            filters.push($(this).attr('name'));
19965          });
19966
19967          aoData.push({ name: 'month', value: month });
19968          aoData.push({ name: 'year', value: year });
19969          aoData.push({ name: 'startDate', value: startDate });
19970          aoData.push({ name: 'endDate', value: endDate });
19971          aoData.push({ name: 'filters', value: filters });
19972        },
19973
19974        fnDrawCallback: function () {
19975          var month = $(
19976            '#corporate-chain-invoices_filter_form select.month option:selected'
19977          ).html();
19978          var year = $('#corporate-chain-invoices_filter_form select.year option:selected').html();
19979          $('#ac-tab-invoices span.month_year').html(month + ', ' + year);
19980        },
19981
19982        //Called before each row is shown
19983        fnRowCallback: function (nRow, aData, iDisplayIndex) {
19984          var invoice_id = aData[0];
19985          var rowClass = aData[14];
19986          var status = aData[13];
19987
19988          //Add the transaction id to every rows data object
19989          //$(nRow).data({"invoice_id":invoice_id});
19990          $(nRow).addClass(rowClass);
19991
19992          $('td:eq(0)', nRow).html(
19993            '<a href="' + invoice_id + '" class="show_invoice" >' + invoice_id + '</a>'
19994          );
19995          $('td:eq(8)', nRow)
19996            .addClass('status')
19997            .html('<a href="' + invoice_id + '" class="show_invoice_log" >' + status + '</a>');
19998
19999          return nRow;
20000        },
20001      });
20002
20003      pages.reskontra.$money_transfers_dt = $('#money_transfers_dt').dataTable({
20004        oLanguage: global.dataTablesLanguage,
20005        sPaginationType: 'full_numbers',
20006        bPaginate: true,
20007        bAutoWidth: false,
20008        bJQueryUI: true,
20009        bFilter: true,
20010        bInfo: true,
20011        bProcessing: true,
20012        bServerSide: true,
20013        sAjaxSource: 'reskontra/moneyTransferItemsDataTable/',
20014        aoColumns: [
20015          /** ID **/ { bVisible: false },
20016          /** company_id **/ { bVisible: false },
20017          /** Toimipiste **/ { bVisible: showStationField, bSortable: false, bSearchable: false },
20018          /** date **/ { sType: 'date-eu' },
20019          /** source */ null,
20020          /** paid_invoice **/ null,
20021          /** service_charges **/ null,
20022          /** money_transfer **/ null,
20023          /** reference_number **/ null,
20024          /** show_money_transfer_item **/ { bVisible: true, bSortable: false, bSearchable: false },
20025        ],
20026        aaSorting: [[3, 'desc']],
20027
20028        fnServerParams: function (aoData) {
20029          /* Add some extra data to the sender */
20030          var month = $('#money_transfers_filter_form select.month option:selected').attr('value') || 'all';
20031          var year = $('#money_transfers_filter_form select.year option:selected').attr('value') || 'all';
20032          var company = $('#money_transfers_filter_form select[name="company"] option:selected').attr('value');
20033          var source = $('#money_transfers_filter_form select.source option:selected').attr('value') || 'all';
20034
20035          var startDate;
20036          var endDate;
20037          if ($('input#filter-money-transfers-start-date').length > 0) {
20038            startDate = $('input#filter-money-transfers-start-date')[0].value;
20039            endDate = $('input#filter-money-transfers-end-date')[0].value;
20040          }
20041
20042          aoData.push({ name: 'company', value: company });
20043          aoData.push({ name: 'month', value: month });
20044          aoData.push({ name: 'year', value: year });
20045          aoData.push({ name: 'source', value: source });
20046          aoData.push({ name: 'startDate', value: startDate });
20047          aoData.push({ name: 'endDate', value: endDate });
20048
20049        },
20050
20051        //Called before each row is shown
20052        fnRowCallback: function (nRow, aData, iDisplayIndex) {
20053          var money_transfer_item_id = aData[0],
20054            company_id = aData[1],
20055            paid_invoices = aData[5],
20056            service_charges = aData[6],
20057            money_transferred = aData[7];
20058            source = aData[4];
20059
20060          var colShift = showStationField ? 1 : 0;
20061
20062          $('td:eq('+ (6 + colShift) +')', nRow).html(
20063            '<a href="' + source + '/' + money_transfer_item_id + '" class="show_money_transfer_item" >Näytä tiedot</a>'
20064          );
20065
20066          return nRow;
20067        },
20068      });
20069
20070      $('#money_transfers_filter_form select').on('change', function (e) {
20071        // Timeout used here to prevent sending checked checkboxes when swithing from any filter -> all
20072        // If fnDraw() is called when swithcing checkboxes, previous filter will override all filter
20073        setTimeout(function () {
20074          pages.reskontra.$money_transfers_dt.fnClearTable(0);
20075          pages.reskontra.$money_transfers_dt.fnDraw();
20076        }, 1);
20077      });
20078
20079      $('#direct_payments_filter_form').find('select[name="company[]"]').on('changed.bs.select', function (e, clickedIndex, isSelected) {
20080        var $select = $(this);
20081        var selectedValues = $select.val() ? $select.val() : [];
20082
20083        if (selectedValues.includes('all') && selectedValues.length > 1) {
20084            if (isSelected && $select.find('option').eq(clickedIndex).val() === 'all') {
20085                selectedValues = ['all'];
20086            } else {
20087                selectedValues = selectedValues.filter(function(company){return company !== 'all'});
20088            }
20089            $select.selectpicker('val', selectedValues);
20090        }
20091      });
20092
20093      pages.reskontra.$direct_payments_dt = $('#direct_payments_dt').dataTable({
20094        oLanguage: global.dataTablesLanguage,
20095        sPaginationType: 'full_numbers',
20096        bAutoWidth: false,
20097        bJQueryUI: true,
20098        bFilter: true,
20099        bInfo: true,
20100        bPaginate: true,
20101        bProcessing: true,
20102        bServerSide: true,
20103        sAjaxSource: 'reskontra/directPaymentsDataTable/',
20104        aoColumns: [
20105          /** ID **/ { bVisible: false },
20106          /** Yritys ID **/ { bVisible: false },
20107          /** Yritys **/ { bVisible: false },
20108          /** Maksunumero  **/ { bVisible: false },
20109          /** TyömääräysId **/ { bVisible: false },
20110          /** Työmääräysnumero **/ { bVisible: false },
20111          /** KuormakirjaId **/ { bVisible: false },
20112          /** Kuormakirjanumero **/ { bVisible: false },
20113          /** Työ **/ { bSortable: false },
20114          /** Toimipiste **/ { bVisible: showStationField, bSortable: false, bSearchable: false },
20115          /** Pvm **/ null,
20116          /** Tyyppi **/ null,
20117          /** Maksaja / Viiteemme **/ { bVisible: showStationField },
20118          /** Työn suorittaja **/ null,
20119          /** Summa **/ { bSortable: false },
20120          /** Tilitetty **/ { bVisible: true, bSortable: false },
20121          /** Avoinna **/ { bVisible: true, bSortable: false },
20122          /** Tilakoodi **/ { bVisible: false },
20123          /** Tila **/ { bSortable: 'status' },
20124          /** Maksun päivä **/ { bVisible: false },
20125          /** Työmääräys numero **/ { bVisible: false },
20126          /** Työ tyyppi **/ { bVisible: false, bSearchable: false },
20127          /** external payment id **/ { bVisible: false },
20128          /** freight id **/ { bVisible: false },
20129        ],
20130        aaSorting: [[0, 'desc']],
20131
20132        fnServerParams: function (aoData) {
20133          var filters = [],
20134            payment_type;
20135
20136          var month =
20137            $('#direct_payments_filter_form select.month option:selected').attr('value') || 'all';
20138          var year =
20139            $('#direct_payments_filter_form select.year option:selected').attr('value') || 'all';
20140
20141          var selectedCompanies = $('#direct_payments_filter_form select[name="company[]"]').val() ? $('#direct_payments_filter_form select[name="company[]"]').val() : [];
20142
20143          if (selectedCompanies.includes('all') && selectedCompanies.length > 1){
20144            selectedCompanies = selectedCompanies.filter(function(company){return company !== 'all'});
20145          }
20146
20147          company = selectedCompanies.includes('all') ? 'all' : selectedCompanies;
20148
20149          $('#direct_payments_filter_form input:checkbox:checked').each(function () {
20150            filters.push($(this).attr('name'));
20151          });
20152          var startDate;
20153          var endDate;
20154          if ($('input#filter-dp-start-date').length > 0) {
20155            startDate = $('input#filter-dp-start-date')[0].value;
20156            endDate = $('input#filter-dp-end-date')[0].value;
20157          }
20158
20159          //If no checkbox filter in UI, open both and paid statuses to filters
20160          if ($('#direct_payments_filter_form input:checkbox').length < 1) {
20161            filters.push('paid');
20162            filters.push('open');
20163          }
20164
20165          payment_type = $('#direct_payments_filter_form')
20166            .find('select[name=payment_type] option:selected')
20167            .attr('value');
20168
20169          filters.push(payment_type);
20170
20171          aoData.push({ name: 'filters', value: filters });
20172          aoData.push({ name: 'company', value: company });
20173          aoData.push({ name: 'month', value: month });
20174          aoData.push({ name: 'year', value: year });
20175          aoData.push({ name: 'endDate', value: endDate });
20176          aoData.push({ name: 'startDate', value: startDate });
20177
20178          $('#export_direct_payment_csv').html(global.$mini_loader).attr('disabled', true);
20179          pages.reskontra.dataTableParams.directPayments = aoData;
20180        },
20181
20182        fnInfoCallback: function (oSettings, iStart, iEnd, iMax, iTotal, sPre) {
20183
20184          var responseJson = JSON.parse(oSettings.jqXHR.responseText);
20185          var sums = responseJson.iSumma;
20186          if (typeof sums !== 'undefined') {
20187            return (
20188              'N&auml;ytet&auml;&auml;n rivit ' +
20189              iStart +
20190              ' - ' +
20191              iEnd +
20192              ' / ' +
20193              iTotal +
20194              ',  summa: ' +
20195              sums.amountToPay +
20196              ',  avoinna: ' +
20197              sums.openAmount
20198            );
20199          }
20200          return 'N&auml;ytet&auml;&auml;n rivit ' + iStart + ' - ' + iEnd + ' / ' + iTotal;
20201        },
20202
20203        fnDrawCallback: function(){
20204          $('#export_direct_payment_csv').html('Vie Csv-tiedostoon').attr('disabled', false);
20205        },
20206
20207        //Called before each row is shown
20208        fnRowCallback: function (nRow, aData, iDisplayIndex) {
20209          var id = aData[0],
20210            companyId = aData[1],
20211            companyName = aData[2],
20212            ourReference = aData[3],
20213            jobOrderId = aData[4],
20214            towingRecordId = aData[6],
20215            towingRecordNo = aData[7],
20216            paymentType = aData[11],
20217            amountToPay = aData[14],
20218            moneyTrasferred = aData[15],
20219            openAmount = aData[16],
20220            status = aData[18],
20221            entityNumber = aData[20],
20222            jobType = aData[21];
20223            posId = aData[22];
20224            extPaymentId = aData[23];
20225            freightId = aData[24];
20226
20227          var colShift = showStationField ? 1 : 0;
20228
20229          if (towingRecordId) {
20230            if (jobType === 'towing_record') {
20231              $('td:eq(0)', nRow).html(
20232                '<a href="kuormakirjat/get_towing_record_html/' +
20233                  towingRecordId +
20234                  '" name="kuormakirjat" class="show_towing_record" >' +
20235                  towingRecordNo +
20236                  '</a>'
20237              );
20238            }
20239          } else if (extPaymentId) {
20240            $('td:eq(0)', nRow).html(extPaymentId.toString());
20241          } else {
20242            if (jobType === 'pos') {
20243              $('td:eq(0)', nRow).html(
20244                '<a class="show_pos_payment" href="' + posId + '">' + ourReference + '</a>'
20245              );
20246            }
20247
20248            if (jobType === 'job_order') {
20249              var jobOrderReference = ourReference.split('/');
20250              jobOrderType = jobOrderReference[1];
20251              if (jobOrderType !== ' RAH') {
20252                $('td:eq(0)', nRow).html(
20253                  '<a href="' +
20254                    jobOrderId.toString() +
20255                    '" class="reskontra_show_job_order" >' +
20256                    entityNumber.toString() +
20257                    '</a>'
20258                );
20259              } else {
20260                $('td:eq(0)', nRow).html(entityNumber.toString());
20261              }
20262            }
20263
20264            if (jobType === 'freight') {
20265              $('td:eq(0)', nRow).html(
20266                '<a href="/innorahti/edit/' +
20267                  freightId +
20268                  '" class="show_freight" >' +
20269                  entityNumber.toString() +
20270                  '</a>'
20271              );
20272            }
20273          }
20274
20275          if (paymentType === 'Korttimaksu') {
20276            $('td:eq(' + (2 + colShift) + ')', nRow).html(
20277              '<a href="' + id + '" class="show_direct_payment" >' + paymentType + '</a>'
20278            );
20279          }
20280
20281          if(showStationField){ourReference
20282            $('td:eq(4)', nRow).html(ourReference);
20283          }
20284
20285          colShift += showStationField ? 1 : 0;
20286
20287          $('td:eq(' + (5 + colShift) + ')', nRow).html(
20288            '<a href="' +
20289              id +
20290              '" class="show_add_payment_dialog" data-moneyTransferred="' +
20291              moneyTrasferred +
20292              '" >' +
20293              moneyTrasferred +
20294              '</a>'
20295          );
20296
20297          $('td:eq(' + (6 + colShift) + ')', nRow).html(openAmount);
20298          $('td:eq(' + (7 + colShift) + ')', nRow).html(
20299            '<a href="/logs/getLogHtml/direct_payment/' +
20300              id +
20301              '" class="show_direct_payment_log" name="global" >' +
20302              status +
20303              '</a>'
20304          );
20305
20306          return nRow;
20307        },
20308      });
20309
20310      $('#direct_payments_filter_form input:checkbox, #direct_payments_filter_form select').on(
20311        'change',
20312        function (e) {
20313          // Timeout used here to prevent sending checked checkboxes when swithing from any filter -> all
20314          // If fnDraw() is called when swithcing checkboxes, previous filter will override all filter
20315          setTimeout(function () {
20316            pages.reskontra.$direct_payments_dt.fnClearTable(0);
20317            pages.reskontra.$direct_payments_dt.fnDraw();
20318          }, 1);
20319        }
20320      );
20321
20322      /*
20323      $('#direct_payments_recopart_dt').on(
20324          'click',
20325          'a.s, a.show_account_card, a.show_invoice_log,' +
20326          ' a.show_towing_record, a.show_log',
20327          function(e) {
20328            e.preventDefault();
20329
20330            var id = $(e.target).attr('href');
20331            var action = $(e.target).attr('class');
20332            var companyId = $(e.target).attr('data-companyId');
20333            var openAmount = $(e.target).attr('data-openAmount');
20334
20335            switch (action) {
20336              case 'show_add_payment_dialog':
20337                pages.iv_laskutus_ja_reskontra.showAddDirectPaymentDialog(id, openAmount);
20338                break;
20339              case 'show_account_card':
20340                window.AccountCard.show(companyId);
20341                break;
20342              case 'show_towing_record':
20343                global.showJob(id);
20344                break;
20345              case 'show_log':
20346                global.show_log(id);
20347                break;
20348            }
20349          }
20350      );
20351      */
20352
20353      pages.reskontra.$direct_payments_recopart_dt = $('#direct_payments_recopart_dt').dataTable({
20354        oLanguage: global.dataTablesLanguage,
20355        sPaginationType: 'full_numbers',
20356        bAutoWidth: false,
20357        bJQueryUI: true,
20358        bFilter: true,
20359        bInfo: true,
20360        bPaginate: true,
20361        bProcessing: true,
20362        bServerSide: true,
20363        sAjaxSource: 'reskontra/recopartDirectPaymentsDataTable/',
20364        aoColumns: [
20365          /** ID **/ { bVisible: false },
20366          /** Yritys ID **/ { bVisible: false },
20367          /** Yritys **/ { bVisible: false },
20368          /** Pvm **/ null,
20369          /** Maksunumero  **/ { bVisible: true },
20370          /** Tyyppi **/ null,
20371          /** Maksaja **/ { bVisible: true },
20372          /** Oma viite **/ { bVisible: true },
20373          /** Summa **/ null,
20374          /** external_order_id  **/ { bVisible: false },
20375          /** external_payment_id  **/ { bVisible: false },
20376          /** external_payment_reference  **/ { bVisible: false },
20377        ],
20378        aaSorting: [[0, 'desc']],
20379
20380        fnServerParams: function (aoData) {
20381          var filters = [],
20382            payment_type;
20383
20384          $('#direct_payments_recopart_filter_form input:checkbox:checked').each(function () {
20385            filters.push($(this).attr('name'));
20386          });
20387
20388          payment_type = $('#direct_payments_recopart_filter_form')
20389            .find('select[name=payment_type] option:selected')
20390            .attr('value');
20391
20392          filters.push(payment_type);
20393
20394          aoData.push({ name: 'filters', value: filters });
20395        },
20396
20397        //Called before each row is shown
20398        fnRowCallback: function (nRow, aData, iDisplayIndex) {
20399          var id = aData[0],
20400            companyId = aData[1],
20401            companyName = aData[2],
20402            ourReference = aData[3],
20403            amountToPay = aData[13];
20404
20405          $('td:eq(0)', nRow).html(
20406            $('<a />', {
20407              href: 'reskontra/directPayment/' + id + '/',
20408              name: 'DirectPaymentDialog',
20409              class: 'show',
20410            }).html(id)
20411          );
20412
20413          return nRow;
20414        },
20415      });
20416
20417      $('#direct_payments_recopart_filter_form').delegate('input, select', 'change', function (e) {
20418        pages.reskontra.$direct_payments_recopart_dt.fnClearTable(0);
20419        pages.reskontra.$direct_payments_recopart_dt.fnDraw();
20420      });
20421    }, // init 
20422
20423    insert_invoice_to_ledger: function(invoice_id) {
20424      var $dialog = $('<div />', { style: 'text-align:left;' })
20425        .html(
20426          'Haluatko varmasti lähettää laskun reskontrattavaksi? HUOM! Asiakkaalle ei toimiteta laskua'
20427        )
20428        .dialog({
20429          autoOpen: true,
20430          modal: true,
20431          resizable: false,
20432          draggable: false,
20433          title: 'Lähetä lasku reskontraan',
20434          beforeClose: function (event, ui) {
20435            event.stopPropagation();
20436          },
20437          buttons: {
20438            Peruuta: function () {
20439              $dialog.dialog('close');
20440            },
20441            'Lähetä lasku': function () {
20442              $.ajax({
20443                dataType: 'json',
20444                type: 'POST',
20445                url: '/reskontra/insert_invoice_to_ledger/' + invoice_id,
20446                beforeSend: function(request) {
20447                  global.showLoadingDialog('Lähetetään laskua...');
20448                },
20449                success: function (responseJSON) {
20450                  if (responseJSON.type == 'success') {
20451  
20452                    if (pages.reskontra.$datatable != null) {
20453                      pages.reskontra.$datatable.fnClearTable(0);
20454                      pages.reskontra.$datatable.fnDraw();
20455                    }
20456  
20457                    LaskutusJaReskontra.showInvoiceDialog({
20458                      invoiceId: invoice_id,
20459                    });
20460                  }
20461  
20462                  global.show_message(responseJSON);
20463                  global.close_loading_dialog();
20464  
20465                  $dialog.dialog('close');
20466                },
20467                error: function (response) {
20468                  global.close_loading_dialog();
20469                  global.show_message($.parseJSON(response.responseText));
20470                },
20471              });
20472            },
20473          },
20474        });
20475    }, 
20476
20477    showAddDirectPaymentDialog: function (id, openAmount) {
20478      //Define the URL and success function for the refund payment case
20479      var $dialog = $('#add_direct_payment_dialog');
20480
20481      if (!$dialog.length) {
20482        $dialog = pages.reskontra.createDirectPaymentDialog();
20483        $dialog.find('input#paid_date').datepicker($.datepicker.regional.fi);
20484      }
20485
20486      //Set date and open amount values
20487      $dialog.find('input#paid_date').datepicker('setDate', new Date());
20488      $dialog.find('input#amount').val(openAmount);
20489      $dialog.find('input#id').val(id);
20490
20491      $dialog.dialog('open');
20492    },
20493
20494    showAddManualReminderDialog: function (invoiceId, recipientEmail) {
20495      var defaultReminderText = 'Kirjanpitomme mukaan tämä lasku on maksamatta. ';
20496      var textAreaStyle = 'width:320px; height:72px; font-weight: 500; line-height: 1.5;';
20497      var textArea = $('<textarea />', { style: textAreaStyle, name: 'reminder_message' });
20498      var sendMethodEl =
20499        '<div style="width: 100%;"><label>Toimitustapa: <select id="reminder_send_method" style="font-weight: 500; line-height: 1.5;" name="send_method"><option value="mail">Postitse</option><option value="email">Sähköpostitse</option></select></label></div>';
20500      var recipientEl =
20501        '<div id="reminder_recipient_field" style="display: none;"><label style="width: 100%;">Vastaanottajan sähköpostiosoite: <input style="width: 200px;" type="text" name="recipient" value="' +
20502        recipientEmail +
20503        '"></div></div>';
20504      $('<div></div>')
20505        .append(
20506          $('<label />', { style: 'width:auto;' })
20507            .html('Muistutusteksti')
20508            .append(textArea)
20509            .append('<br />')
20510            .append(sendMethodEl)
20511            .append('<br />')
20512            .append(recipientEl)
20513        )
20514        .dialog({
20515          autoOpen: true,
20516          modal: true,
20517          resizable: false,
20518          draggable: false,
20519          width: 380,
20520          title: 'Lähetä maksumuistutus',
20521          open: function (event, ui) {
20522            $(textArea).val(defaultReminderText);
20523            $('#reminder_send_method').on('change', function (el) {
20524              if ($(this).val() == 'email') {
20525                $('#reminder_recipient_field').show();
20526              } else {
20527                $('#reminder_recipient_field').hide();
20528              }
20529            });
20530          },
20531          beforeClose: function (event, ui) {
20532            event.stopPropagation();
20533          },
20534          close: function () {
20535            $(this).dialog('destroy');
20536            $(this).remove();
20537          },
20538          buttons: {
20539            Peruuta: function () {
20540              $(this).dialog('close');
20541            },
20542            'Lähetä muistutus': function () {
20543              var sendDialog = this;
20544              global.showLoadingDialog('Viestiä lähetetään...');
20545              var message = $(this).find('textarea[name=reminder_message]').val();
20546              if (message.length > 400) {
20547                global.close_loading_dialog();
20548                global.show_message({
20549                  type: 'error',
20550                  title: 'Virhe',
20551                  text: 'Muistutusteksti ei saa olla yli 400 merkkiä pitkä.',
20552                });
20553                return;
20554              }
20555              var sendMethod = $('#reminder_send_method').val();
20556              var recipient = $('#reminder_recipient_field input').val();
20557              var data = {
20558                invoiceId: invoiceId,
20559                message: message,
20560                sendMethod: sendMethod,
20561                recipient: recipient,
20562              };
20563              var url = '/reskontra/takeManualOverDueAction/';
20564              $.ajax({
20565                url: url,
20566                type: 'post',
20567                data: data,
20568                success: function (resp) {
20569                  $(sendDialog).dialog('close');
20570                  global.close_loading_dialog();
20571                  global.show_message({
20572                    type: 'success',
20573                    title: 'Valmis',
20574                    text: 'Maksumuistutus lähetetty.',
20575                  });
20576                  pages.reskontra.$datatable.fnClearTable(0);
20577                  pages.reskontra.$datatable.fnDraw();
20578                },
20579                error: function (response) {
20580                  global.close_loading_dialog();
20581                  var error = JSON.parse(response.responseText);
20582                  global.show_message(error);
20583                },
20584              });
20585            },
20586          },
20587        });
20588      $('button').addClass('btn btn-default');
20589    },
20590
20591    showCreateOpenInvoicesReportDialog: function () {
20592      var dateTo = new Date();
20593      dateTo.setDate(1);
20594
20595      var $createReportDialog = $('<div />')
20596        .append(
20597          $('<form method="post" action="/raportit/createOpenInvoicesReport/csv"/>').append(
20598            $('<label />', { id: 'date_to_label', style: 'width:auto; float:none;' }).html(
20599              'Hae avoimet laskut päivämäärällä'
20600            ),
20601            $(
20602              '<input type="text" class="text small" id="date_to" name="open_until_date" value="' +
20603                dateTo.getDate() +
20604                '.' +
20605                (dateTo.getMonth() + 1) +
20606                '.' +
20607                dateTo.getFullYear() +
20608                '" />'
20609            ).datepicker()
20610          )
20611        )
20612        .dialog({
20613          width: 400,
20614          autoOpen: true,
20615          modal: true,
20616          resizable: false,
20617          draggable: false,
20618          beforeClose: function (event, ui) {
20619            event.stopPropagation();
20620          },
20621          title: 'Luo raportti avoimista laskuista',
20622          buttons: {
20623            Peruuta: function () {
20624              $(this).dialog('close');
20625            },
20626            'Luo raportti': function () {
20627              console.log($createReportDialog.find('form'));
20628              $createReportDialog.find('form').submit();
20629              //pages.reskontra.createOpenInvoicesReport($(this).find('input[name=date_to]').val());
20630            },
20631          },
20632        });
20633    },
20634
20635    createOpenInvoicesReport: function (endDate) {
20636      var data = {
20637        endDate: endDate,
20638      };
20639
20640      $.ajax({
20641        data: data,
20642        dataType: 'json',
20643        type: 'POST',
20644        url: '/raportit/createOpenInvoicesReport/csv',
20645        beforeSend: function (request) {
20646          $dialog.dialog({
20647            width: 400,
20648            height: 200,
20649            title: 'Haku käynnissä',
20650            close: function (e) {
20651              e.stopPropagation();
20652              $dialog.dialog('destroy').remove();
20653            },
20654          });
20655        },
20656        success: function (responseJSON) {
20657          self.data = responseJSON;
20658
20659          console.log(responseJSON);
20660
20661          // self.close();
20662          $dialog.dialog({
20663            width: 400,
20664            height: 200,
20665            title: self.data.title || '',
20666            close: function (e) {
20667              e.stopPropagation();
20668              // $dialog.dialog('destroy').remove();
20669            },
20670            buttons: {
20671              OK: function (e) {
20672                e.stopPropagation();
20673                //  $dialog.dialog('destroy').remove();
20674                self.dialog.dialog('close');
20675              },
20676            },
20677          });
20678          $dialog.html('<p>' + self.data.text + '</p>');
20679          console.log('data haettu onnistuneesti', responseJSON);
20680          // $dialog.dialog('close');
20681          // DO SOMETHING WITH THE DATA
20682          if (typeof callback == 'function') {
20683            callback();
20684          }
20685        },
20686        error: function (response) {
20687          $dialog.html('<p>Tietojen haku epäonnistui</p>');
20688          console.log('Error!:', response);
20689          var error = JSON.parse(response.responseText);
20690          global.show_message(error);
20691          $dialog.dialog('close');
20692        },
20693      });
20694    },
20695
20696    createDirectPaymentDialog: function () {
20697      var d = new Date(),
20698        url = '/reskontra/addPaymentToDirectPayment/',
20699        $dialog = $('<div></div>', { id: 'add_direct_payment_dialog' }).append(
20700          $('<form />', { id: 'add_payment_form' }).append(
20701            $('<fieldset />', { class: '', style: '' })
20702              .append('<p>Syötä tilityksen summa ja päivämäärä</p>')
20703              .append(
20704                $('<ol />')
20705                  .append($('<input type="hidden" name="id" id="id" value="" />'))
20706                  .append(
20707                    $('<li />')
20708                      .append($('<label for="amount">Summa:</label>'))
20709                      .append(
20710                        $('<input type="text" name="amount" id="amount"  class="text small" />')
20711                      )
20712                      .append(' &euro;')
20713                  )
20714                  .append(
20715                    $('<li />')
20716                      .append($('<label id="paid_date_label" for="paid_date">Päivämäärä:</label>'))
20717                      .append(
20718                        $(
20719                          '<input type="text" class="text small" id="paid_date" name="paid_date" />'
20720                        )
20721                      )
20722                  )
20723                  .append(
20724                    $('<li />').append(
20725                      $('<button type="submit">Tallenna tilitys</button>').button()
20726                    )
20727                  )
20728              )
20729          )
20730        );
20731
20732      $dialog.find('form#add_payment_form').submit(function () {
20733        var data = _.object(
20734          $dialog
20735            .find('#add_payment_form')
20736            .serializeArray()
20737            .map(function (v) {
20738              return [v.name, v.value];
20739            })
20740        );
20741
20742        $.ajax({
20743          type: 'POST',
20744          url: url.concat(data.id),
20745          data: data,
20746          beforeSend: function (request) {
20747            global.show_loading_dialog('Tallennetaan tilitystä...');
20748          },
20749        })
20750          .done(function (data) {
20751            global.close_loading_dialog();
20752            global.show_message(data);
20753            $dialog.dialog('close');
20754
20755            //Refresh the datatable
20756            pages.reskontra.$direct_payments_dt.fnClearTable(0);
20757            pages.reskontra.$direct_payments_dt.fnDraw();
20758          })
20759          .fail(function (data) {
20760            global.show_message($.parseJSON(data.responseText));
20761            global.close_loading_dialog();
20762          });
20763
20764        return false;
20765      });
20766
20767      $dialog.dialog({
20768        width: 400,
20769        //height:200,
20770        autoOpen: false,
20771        modal: true,
20772        resizable: false,
20773        draggable: false,
20774        beforeClose: function (event, ui) {
20775          event.stopPropagation();
20776        },
20777        title: 'Lisää tilitys',
20778        buttons: {
20779          Peruuta: function () {
20780            $(this).dialog('close');
20781          },
20782        },
20783      });
20784
20785      return $dialog;
20786    },
20787
20788    init_show_invoice: function (invoice) {
20789      var invoice_id = invoice.id;
20790      var open_sum = invoice.open_sum;
20791      var invoice_items = invoice.items;
20792      var jobOrderId = invoice.jobOrderId || false;
20793      var towingRecordId = invoice.invoice.towing_record_id || false;
20794      var recipientEmail = invoice.email;
20795
20796      var sendInvoiceMethods = function () {
20797        var $list = $('<ul />', { style: 'position:absolute; z-index:99; font-size:13px;' });
20798          $list.append(
20799            $('<li />', {}).append(
20800              $('<a />', { href: '' })
20801                .on('click', function (e) {
20802                  e.preventDefault();
20803                  pages.reskontra.send_invoice_by_mail(invoice.id);
20804                })
20805                .text('Posti')
20806            ),
20807            $('<li />', {}).append(
20808              $('<a />', { href: '' })
20809              .on('click', function (e) {
20810                  e.preventDefault();
20811                  pages.reskontra.send_invoice_by_email(invoice.id, invoice.email);
20812                })
20813                .text('Sähköposti')
20814            ),
20815            $('<li />', {}).append(
20816              $('<a />', { href: '' })
20817              .on('click', function (e) {
20818                  e.preventDefault();
20819                  pages.reskontra.send_invoice_by_sms(invoice.id);
20820                })
20821                .text('Tekstiviesti')
20822            )
20823          );
20824          if (invoice.invoice.customer_type !== 'person') {
20825            $list.append(
20826            $('<li />', {}).append(
20827              $('<a />', { href: '' })
20828              .on('click', function (e) {
20829                  e.preventDefault();
20830
20831                  var errorMessage = pages.reskontra.checkInvoiceStatusBeforeSendEinvoice(invoice);
20832                  if (errorMessage) {
20833                    $('<div>' + errorMessage + '</div>').dialog({
20834                      modal: true,
20835                      buttons: {
20836                        Ok: function() {
20837                          $(this).dialog('close');
20838                        }
20839                      }
20840                    });
20841                    return;
20842                  }
20843                  
20844                  pages.reskontra.send_invoice_by_e_invoice(invoice.id);
20845                })
20846                .text('Verkkolasku')
20847            ));
20848          }
20849
20850          //For AK company group admins
20851          if (window.App.user.access_level >= 10) {
20852            $list.append(
20853              $('<li />', {}).append(
20854                $('<a />', { href: '' })
20855                .on('click', function (e) {
20856                    e.preventDefault();
20857                    pages.reskontra.insert_invoice_to_ledger(invoice.id);
20858                  })
20859                  .text('Muuta avoimeksi (ei toimitusta)')
20860              ));
20861          }
20862        return $list;
20863      };
20864
20865      // Lähetä heti action
20866      $('#send_invoice')
20867        .button({ icons: { primary: 'ui-icon-mail-closed' } })
20868        .append('<span class="ui-icon ui-icon-triangle-1-s" style="float: right; margin-left: 5px;"></span>')
20869        .wrap($('<div />', { style: 'float:left;' }))
20870        .wrap($('<div />', {}))
20871        .parent()
20872        .parent()
20873        .append(sendInvoiceMethods())
20874        .parent()
20875        .parent()
20876        .find('#send_invoice')
20877        .on('click', function () {
20878          var $menu = $(this).parent().next();
20879
20880          if ($menu.is(':visible')) {
20881            $menu.hide();
20882          } else {
20883            $('.ui-menu').hide();
20884            $menu.show().position({
20885              my: 'left top',
20886              at: 'left bottom',
20887              of: this,
20888            });
20889          }
20890
20891          var menu = $(this).parent().next();
20892          $(document).one('click', function () {
20893            menu.hide();
20894          });
20895          return false;
20896        })
20897        .parent()
20898        .buttonset()
20899        .next()
20900        .hide()
20901        .menu();
20902
20903      // Lataa lasku options
20904      var downloadInvoiceMethods = function () {
20905        var $list = $('<ul />', { style: 'position:absolute; z-index:99; font-size:13px;' });
20906        if (invoice.invoice.status !== '0') {
20907          $list.append(
20908            $('<li />', {}).append(
20909              $('<a />', { href: '' })
20910                .on('click', function (e) {
20911                  e.preventDefault();
20912                  window.LaskutusJaReskontra.invoiceDialog.insertInvoiceToArvatoIfRequiredAndPrintPdf();
20913                })
20914                .text('Laskukopio')
20915            )
20916          )
20917        }
20918        if (invoice.invoice.status === '20' && invoice.creditInvoices.length > 0) {
20919          $list.append(
20920            $('<li />', {}).append(
20921              $('<a />', { href: '' })
20922                .on('click', function (e) {
20923                  e.preventDefault();
20924                 
20925                  $('<div />', {
20926                    title: 'Valitse hyvityslasku',
20927                    id: 'credit-invoice-dialog'
20928                  })
20929                  .append(
20930                    $('<div />', {}).append(
20931                      invoice.creditInvoices.map(function(creditInvoice, index) {
20932                        return $('<div />', {
20933                        }).append(
20934                          $('<br />'),
20935                          $('<input />', {
20936                            type: 'radio',
20937                            name: 'credit-invoice',
20938                            id: 'credit-invoice-' + index,
20939                            value: creditInvoice.id,
20940                            checked: index === 0
20941                          }),
20942                          $('<label />', {
20943                            for: 'credit-invoice-' + index,
20944                            text: creditInvoice.invoice_number,
20945                            style: 'display:inline; float:none;',
20946                          })
20947                        );
20948                      })
20949                    )
20950                  ) 
20951                  .dialog({
20952                    modal: true,
20953                    width: 300,
20954                    buttons: {
20955                      'Peruuta': function() {
20956                        $(this).dialog('close');
20957                      },
20958                      'Lataa': function() {
20959                        var selectedId = $('input[name="credit-invoice"]:checked').val();
20960                        if (selectedId) {
20961                          window.open('/lasku/pdf/'.concat(selectedId));
20962                          return false;
20963                        }
20964                      }
20965                    }
20966                  });
20967                })
20968                .text('Hyvityslasku')
20969            )
20970          )
20971        }
20972        $list.append(
20973          $('<li />', {}).append(
20974            $('<a />', { href: '' })
20975              .on('click', function (e) {
20976                e.preventDefault();
20977                var receiptUrl = '/reskontra/kuitti/' + invoice_id,
20978                w = window.open();
20979    
20980                w.location = receiptUrl;
20981              })
20982              .text('Laskulähete')
20983          )
20984        );
20985        return $list;
20986      };
20987
20988      var sendCreditInvoiceCopyMethods = function () {
20989        var $list = $('<ul />', { style: 'position:absolute; z-index:99; font-size:13px;' });
20990        $list.append(
20991          $('<li />', {}).append(
20992            $('<a />', { href: '' })
20993              .on('click', function (e) {
20994                e.preventDefault();
20995
20996                if (!invoice.creditInvoices || invoice.creditInvoices.length === 0) {
20997                  global.show_message({ type: 'error', text: 'Ei hyvityslaskuja saatavilla' });
20998                  return;
20999                }
21000
21001                $('<div />', {
21002                  title: 'Valitse hyvityslasku',
21003                  id: 'credit-invoice-dialog'
21004                })
21005                .append(
21006                  $('<div />', {
21007                  }).append(
21008                    invoice.creditInvoices.map(function(creditInvoice, index) {
21009                      return $('<div />', {
21010                      }).append(
21011                        $('<br />'),
21012                        $('<input />', {
21013                          type: 'radio',
21014                          name: 'credit-invoice',
21015                          id: 'credit-invoice-' + index,
21016                          value: creditInvoice.id,
21017                          checked: index === 0
21018                        }),
21019                        $('<label />', {
21020                          for: 'credit-invoice-' + index,
21021                          text: creditInvoice.invoice_number,
21022                          style: 'display:inline; float:none;',
21023                        })
21024                      );
21025                    })
21026                  )
21027                )
21028                .dialog({
21029                  modal: true,
21030                  width: 300,
21031                  buttons: {
21032                    'Peruuta': function() {
21033                      $(this).dialog('close');
21034                    },
21035                    'Lähetä': function() {
21036                      var selectedId = $('input[name="credit-invoice"]:checked').val();
21037
21038                      if (selectedId) {
21039                        $.ajax({
21040                          dataType: 'json',
21041                          type: 'POST',
21042                          url: '/reskontra/send_invoice_copy_by_mail/' + selectedId,
21043                          beforeSend: function () {
21044                            global.showLoadingDialog('Lähetetään hyvityslaskua...');
21045                          }
21046                        }).done(function () {
21047                          global.show_message({ type: 'success', text: 'Hyvityslasku lähetetty!' })
21048                    
21049                          setTimeout(function () {
21050                            $(this).dialog('close')
21051                          }, 100)
21052                    
21053                        }).error(function (response) {
21054                          global.show_message(JSON.parse(response.responseText));
21055                        }).always(function () {
21056                          global.close_loading_dialog();
21057                        })
21058                        $(this).dialog('close');
21059
21060                      } else {
21061                        global.show_message({ type: 'error', text: 'Valitse hyvityslasku' });
21062                      }
21063                      $(this).dialog('close');
21064                    }
21065                  }
21066                });
21067
21068              })
21069              .text('Posti')
21070          ),
21071          $('<li />', {}).append(
21072            $('<a />', { href: '' })
21073              .on('click', function (e) {
21074                e.preventDefault();
21075
21076                if (!invoice.creditInvoices || invoice.creditInvoices.length === 0) {
21077                  global.show_message({ type: 'error', text: 'Ei hyvityslaskuja saatavilla' });
21078                  return;
21079                }
21080
21081                $('<div />', {
21082                  title: 'Valitse hyvityslasku',
21083                  id: 'credit-invoice-dialog'
21084                })
21085                .append(
21086                  $('<div />', {
21087                  }).append(
21088                    invoice.creditInvoices.map(function(creditInvoice, index) {
21089                      return $('<div />', {
21090                      }).append(
21091                        $('<br />'),
21092                        $('<input />', {
21093                          type: 'radio',
21094                          name: 'credit-invoice',
21095                          id: 'credit-invoice-' + index,
21096                          value: creditInvoice.id,
21097                          checked: index === 0
21098                        }),
21099                        $('<label />', {
21100                          for: 'credit-invoice-' + index,
21101                          text: creditInvoice.invoice_number,
21102                          style: 'display:inline; float:none;',
21103                        })
21104                      );
21105                    })
21106                  ),
21107                  $('<div />', {
21108                    style: 'margin-top: 15px;'
21109                  }).append(
21110                    $('<label />', {
21111                      for: 'send-to-email',
21112                      text: 'Sähköposti:',
21113                      style: 'display: block; margin-bottom: 5px;'
21114                    }),
21115                    $('<input />', {
21116                      type: 'email',
21117                      id: 'send-to-email',
21118                      name: 'send-to-email',
21119                      value: invoice.email,
21120                      style: 'width: 100%;'
21121                    })
21122                  )
21123                )
21124                .dialog({
21125                  modal: true,
21126                  width: 300,
21127                  buttons: {
21128                    'Peruuta': function() {
21129                      $(this).dialog('close');
21130                    },
21131                    'Lähetä': function() {
21132                      var selectedId = $('input[name="credit-invoice"]:checked').val();
21133                      var email = $('#send-to-email').val();
21134
21135                      if (!selectedId) {
21136                        global.show_message({ type: 'error', text: 'Valitse hyvityslasku' });
21137                        return;
21138                      }
21139
21140                      if (!email) {
21141                        global.show_message({ type: 'error', text: 'Anna sähköpostiosoite' });
21142                        return;
21143                      }
21144
21145                      $.ajax({
21146                        dataType: 'json',
21147                        type: 'POST',
21148                        url: '/reskontra/send_invoice_copy_by_email/' + selectedId,
21149                        data: {
21150                          send_to_email: email
21151                        },
21152                        beforeSend: function () {
21153                          global.showLoadingDialog('Lähetetään hyvityslaskua...');
21154                        }
21155                      }).done(function () {
21156                        global.show_message({ type: 'success', text: 'Hyvityslasku lähetetty!' })
21157                  
21158                        setTimeout(function () {
21159                          $(this).dialog('close')
21160                        }, 100)
21161                  
21162                      }).error(function (response) {
21163                        global.show_message(JSON.parse(response.responseText));
21164                      }).always(function () {
21165                        global.close_loading_dialog();
21166                      })
21167                      $(this).dialog('close');
21168                    }
21169                  }
21170                });
21171              })
21172              .text('Sähköposti')
21173          ),
21174          $('<li />', {}).append(
21175            $('<a />', { href: '' })
21176              .on('click', function (e) {
21177                e.preventDefault();
21178
21179                if (!invoice.creditInvoices || invoice.creditInvoices.length === 0) {
21180                  global.show_message({ type: 'error', text: 'Ei hyvityslaskuja saatavilla' });
21181                  return;
21182                }
21183
21184                $('<div />', {
21185                  title: 'Valitse hyvityslasku',
21186                  id: 'credit-invoice-dialog'
21187                })
21188                .append(
21189                  $('<div />', {
21190                  }).append(
21191                    invoice.creditInvoices.map(function(creditInvoice, index) {
21192                      return $('<div />', {
21193                      }).append(
21194                        $('<br />'),
21195                        $('<input />', {
21196                          type: 'radio',
21197                          name: 'credit-invoice',
21198                          id: 'credit-invoice-' + index,
21199                          value: creditInvoice.id,
21200                          checked: index === 0
21201                        }),
21202                        $('<label />', {
21203                          for: 'credit-invoice-' + index,
21204                          text: creditInvoice.invoice_number,
21205                          style: 'display:inline; float:none;',
21206                        })
21207                      );
21208                    })
21209                  ),
21210                  $('<div />', {
21211                    style: 'margin-top: 15px;'
21212                  }).append(
21213                    $('<label />', {
21214                      for: 'phone-number',
21215                      text: 'Puhelinnumero:',
21216                      style: 'display: block; margin-bottom: 5px;'
21217                    }),
21218                    $('<input />', {
21219                      type: 'text',
21220                      id: 'phone-number',
21221                      name: 'phone-number',
21222                      style: 'width: 100%;'
21223                    })
21224                  )
21225                )
21226                .dialog({
21227                  modal: true,
21228                  width: 300,
21229                  buttons: {
21230                    'Peruuta': function() {
21231                      $(this).dialog('close');
21232                    },
21233                    'Lähetä': function() {
21234                      var selectedId = $('input[name="credit-invoice"]:checked').val();
21235                      var phoneNumber = $('#phone-number').val();
21236
21237                      if (!selectedId) {
21238                        global.show_message({ type: 'error', text: 'Valitse hyvityslasku' });
21239                        return;
21240                      }
21241
21242                      if (!phoneNumber) {
21243                        global.show_message({ type: 'error', text: 'Syötä puhelinnumero' });
21244                        return;
21245                      }
21246
21247                      $.ajax({
21248                        dataType: 'json',
21249                        type: 'POST',
21250                        url: '/reskontra/send_invoice_copy_by_sms/' + selectedId,
21251                        data: {
21252                          phone: phoneNumber
21253                        },
21254                        beforeSend: function () {
21255                          global.showLoadingDialog('Lähetetään hyvityslaskua...');
21256                        }
21257                      }).done(function () {
21258                        global.show_message({ type: 'success', text: 'Hyvityslasku lähetetty!' })
21259                  
21260                        setTimeout(function () {
21261                          $(this).dialog('close')
21262                        }, 100)
21263                  
21264                      }).error(function (response) {
21265                        global.show_message(JSON.parse(response.responseText));
21266                      }).always(function () {
21267                        global.close_loading_dialog();
21268                      })
21269                      $(this).dialog('close');
21270                    }
21271                  }
21272                });
21273              })
21274              .text('Tekstiviesti')
21275          )
21276        );
21277
21278        if (invoice.invoice.customer_type !== 'person') {
21279          $list.append(
21280          $('<li />', {}).append(
21281            $('<a />', { href: '' })
21282            .on('click', function (e) {
21283                e.preventDefault();
21284
21285                if (!invoice.creditInvoices || invoice.creditInvoices.length === 0) {
21286                  global.show_message({ type: 'error', text: 'Ei hyvityslaskuja saatavilla' });
21287                  return;
21288                }
21289
21290                $('<div />', {
21291                  title: 'Valitse hyvityslasku',
21292                  id: 'credit-invoice-dialog'
21293                })
21294                .append(
21295                  $('<div />', {
21296                  }).append(
21297                    invoice.creditInvoices.map(function(creditInvoice, index) {
21298                      return $('<div />', {
21299                      }).append(
21300                        $('<br />'),
21301                        $('<input />', {
21302                          type: 'radio',
21303                          name: 'credit-invoice',
21304                          id: 'credit-invoice-' + index,
21305                          value: creditInvoice.id,
21306                          checked: index === 0
21307                        }),
21308                        $('<label />', {
21309                          for: 'credit-invoice-' + index,
21310                          text: creditInvoice.invoice_number,
21311                          style: 'display:inline; float:none;',
21312                        })
21313                      );
21314                    })  
21315                  )
21316                )
21317                .dialog({
21318                  modal: true,
21319                  width: 300,
21320   
21320               buttons: {
21321                    'Peruuta': function() {
21322                      $(this).dialog('close');
21323                    },
21324                    'Lähetä': function() {
21325                      var selectedId = $('input[name="credit-invoice"]:checked').val();
21326                      pages.reskontra.send_invoice_by_e_invoice(selectedId);
21327                    }
21328                  }
21329                });
21330              })
21331              .text('Verkkolasku')
21332          ));
21333        }
21334
21335        return $list;
21336      };
21337
21338      $('#send_credit_invoice')
21339      .button({ icons: { primary: 'ui-icon-mail-closed' } })
21340      .append('<span class="ui-icon ui-icon-triangle-1-s" style="float: right; margin-left: 5px;"></span>')
21341      .wrap($('<div />', { style: 'float:left;' }))
21342      .wrap($('<div />', {}))
21343      .parent()
21344      .parent()
21345      .append(sendCreditInvoiceCopyMethods())
21346      .parent()
21347      .parent()
21348      .find('#send_credit_invoice')
21349      .on('click', function () {
21350        var $menu = $(this).parent().next();
21351
21352        if ($menu.is(':visible')) {
21353          $menu.hide();
21354        } else {
21355          $('.ui-menu').hide();
21356          $menu.show().position({
21357            my: 'left top',
21358            at: 'left bottom',
21359            of: this,
21360          });
21361        }
21362
21363        var menu = $(this).parent().next();
21364        $(document).one('click', function () {
21365          menu.hide();
21366        });
21367        return false;
21368      })
21369      .parent()
21370      .buttonset()
21371      .next()
21372      .hide()
21373      .menu();
21374
21375      // Lataa lasku action
21376      $('#download_invoice')
21377        .button({ icons: { primary: 'ui-icon-mail-closed' } })
21378        .append('<span class="ui-icon ui-icon-triangle-1-s" style="float: right; margin-left: 5px;"></span>')
21379        .wrap($('<div />', { style: 'float:left;' }))
21380        .wrap($('<div />', {}))
21381        .parent()
21382        .parent()
21383        .append(downloadInvoiceMethods())
21384        .parent()
21385        .parent()
21386        .find('#download_invoice')
21387        .on('click', function () {
21388          var $menu = $(this).parent().next();
21389
21390          if ($menu.is(':visible')) {
21391            $menu.hide();
21392          } else {
21393            $('.ui-menu').hide();
21394            $menu.show().position({
21395              my: 'left top',
21396              at: 'left bottom',
21397              of: this,
21398            });
21399          }
21400
21401          var menu = $(this).parent().next();
21402          $(document).one('click', function () {
21403            menu.hide();
21404          });
21405          return false;
21406        })
21407        .parent()
21408        .buttonset()
21409        .next()
21410        .hide()
21411        .menu();
21412
21413      var functionsMethods = function () {
21414        var $list = $('<ul />', { style: 'position:absolute; z-index:99; font-size:13px;' });
21415        $list.append(
21416          $('<li />', {}).append(
21417            $('<a />', { href: '' })
21418              .on('click', function (e) {
21419                e.preventDefault();
21420                pages.reskontra.add_log_item(invoice_id);
21421              })
21422              .text('Muistiinpano')
21423          )
21424        );
21425
21426        if (!invoice.jobOrderId && !invoice.invoice.towing_record_id) {
21427          $list.append(
21428            $('<li />', {}).append(
21429            $('<a />', { href: '' })
21430              .on('click', function (e) {
21431                e.preventDefault();
21432                pages.reskontra.copy_invoice(invoice_id);
21433              })
21434              .text('Kopioi lasku')
21435          ))
21436        }
21437
21438        if (
21439          invoice.invoice.status !== '0' && 
21440          invoice.invoice.status !== '7' &&
21441          invoice.invoice.status !== '20' &&
21442          invoice.invoice.status !== '30' && 
21443          invoice.invoice.status !== '40' &&
21444          invoice.invoice.status !== '50' 
21445        ) {
21446          $list.append(
21447            $('<li />', {}).append(
21448              $('<a />', { href: '' })
21449                .on('click', function (e) {
21450                    e.preventDefault();
21451
21452                    var errorMessage = pages.reskontra.checkInvoiceStatusBeforeChangeDueDate(invoice);
21453                    if (errorMessage) {
21454                      $('<div>' + errorMessage + '</div>').dialog({
21455                        modal: true,
21456                        buttons: {
21457                          Ok: function() {
21458                            $(this).dialog('close');
21459                          }
21460                        }
21461                      });
21462                      return;
21463                    }
21464                    window.LaskutusJaReskontra.invoiceDialog.postponeDueDateDialog.show(
21465                      $('#due_date').text()
21466                    );
21467
21468                })
21469                .text('Siirrä eräpäivää')
21470            )
21471          );
21472        }
21473
21474        if (
21475          invoice.invoice.status !== '0' && 
21476          invoice.invoice.status !== '7' &&
21477          invoice.invoice.status !== '20' &&
21478          invoice.invoice.status !== '30' && 
21479          invoice.invoice.ledger_service !== 'innovoice'
21480        ) {
21481          $list.append(
21482            $('<li />', {}).append(
21483              $('<a />', { href: '' })
21484                .on('click', function (e) {
21485                  e.preventDefault();
21486                  pages.reskontra.paid_to_customer(invoice);
21487                })
21488                .text('Asiakas maksoi tililleni')
21489            )
21490          );
21491        }
21492        
21493        return $list;
21494      };
21495
21496      // Toiminnot action
21497      $('#functions')
21498        .button({ icons: { primary: 'ui-icon-triangle-1-s' } })
21499        .append('<span class="ui-icon ui-icon-triangle-1-s" style="float: right; margin-left: 5px;"></span>')
21500        .wrap($('<div />', { style: 'float:left;' }))
21501        .wrap($('<div />', {}))
21502        .parent()
21503        .parent()
21504        .append(functionsMethods())
21505        .parent()
21506        .parent()
21507        .find('#functions')
21508        .on('click', function (e) {
21509          e.stopPropagation();
21510
21511          $('.menu').hide();
21512
21513          var $menu = $(this).parent().next();
21514
21515          if ($menu.is(':visible')) {
21516            $menu.hide();
21517          } else {
21518            $('.ui-menu').hide();
21519            $menu.show().position({
21520              my: 'left top',
21521              at: 'left bottom',
21522              of: this,
21523            });
21524          }
21525
21526          var menu = $(this).parent().next();
21527          $(document).one('click', function () {
21528            menu.hide();
21529          });
21530
21531          $(document).one('click', function () {
21532            $menu.hide();
21533          });
21534          return false;
21535        })
21536        .parent()
21537        .buttonset()
21538        .next()
21539        .hide()
21540        .menu();
21541
21542        var customerAddCreditnoteMethods = function () {
21543          var $list = $('<ul />', { style: 'position:absolute; z-index:99; font-size:13px;' });
21544          var jobOrderId = invoice.jobOrderId;
21545          var towingRecordId = invoice.invoice.towing_record_id;
21546
21547          $list.append(
21548            $('<li />', {}).append(
21549              $('<a />', { href: '' })
21550                .on('click', function (e) {
21551                  e.preventDefault();
21552                  $('<div />', {
21553                    title: 'Hyvitä koko lasku',
21554                    id: 'credit-invoice-dialog'
21555                  }).html('Siirry ' + (jobOrderId ? 'työmääräykseen' : towingRecordId ? 'kuormakirjaan' : '')).dialog({
21556                    modal: true,
21557                    width: 300,
21558                    buttons: {
21559                      'Peruuta': function() {
21560                        $(this).dialog('close');
21561                      },
21562                      'Siirry': function() {
21563                        if (jobOrderId) {
21564                          document.location.assign('/innokorjaamo/edit/' + jobOrderId);
21565                        } else if (towingRecordId) {
21566                          document.location.assign('/kuormakirja/edit/' + towingRecordId);
21567                        }
21568                      }
21569                    }
21570                  });
21571                })
21572                .text('Hyvitä koko lasku')
21573            ),
21574            $('<li />', {}).append(
21575              $('<a />', { href: '' })
21576                .on('click', function (e) {
21577                  e.preventDefault();
21578                  $('<div />', {
21579                    title: 'Osahyvitys',
21580                    id: 'credit-invoice-dialog'
21581                  })
21582                  .append($('<div />', {
21583                    style: 'margin-bottom: 15px; '
21584                  }).append(
21585                    $('<label />', {
21586                      text: 'Hyvitettävä summa (sis. ALV)',
21587                      style: 'width: auto;'
21588                    }),
21589                    $('<input />', {
21590                      type: 'text',
21591                      id: 'credit-amount',
21592                      class: 'form-control'
21593                    }),
21594                    $('<label />', {
21595                      text: 'Hyvityksen syy, lisätiedot tms.',
21596                      style: 'width: auto; margin-top: 10px;'
21597                    }),
21598                    $('<textarea />', {
21599                      id: 'credit-reason',
21600                      class: 'form-control'
21601                    })
21602                  ))
21603                  .dialog({
21604                    modal: true,
21605                    width: 400, 
21606                    buttons: {
21607                      'Peruuta': function() {
21608                        $(this).dialog('close');
21609                      },
21610                      'Lähetä hyvityspyyntö': function() {
21611                        var creditAmount = $('#credit-amount').val();
21612                        var creditReason = $('#credit-reason').val();
21613
21614                        var data = {
21615                          id: invoice_id,
21616                          creditType: 'partial',
21617                          otherAmount: creditAmount,
21618                          message: creditReason
21619                        }
21620
21621                        $.ajax({
21622                          dataType: 'json',
21623                          type: 'POST',
21624                          url: '/logger/addRequestForCrediting/',
21625                          data: data,
21626                          beforeSend: function () {
21627                            global.showLoadingDialog('Luodaan hyvitystä...');
21628                          }
21629                        }).done(function () {
21630                          global.show_message({ type: 'success', text: 'Hyvityspyyntö lähetetty asiakaspalveluun!' })
21631                    
21632                          setTimeout(function () {
21633                            $(this).dialog('close')
21634                          }, 100)
21635                    
21636                        }).error(function (response) {
21637                          global.show_message(JSON.parse(response.responseText));
21638                        }).always(function () {
21639                          global.close_loading_dialog();
21640                        })
21641                        $(this).dialog('close');
21642                      }
21643                    }
21644                  });
21645                })
21646                .text('Osahyvitys')
21647            )
21648          );
21649
21650          if ((invoice.jobOrderId || invoice.invoice.towing_record_id) && (invoice.invoice.status === '11' || invoice.invoice.status === '13')) {
21651            $list.append(
21652              $('<li />', {}).append(
21653                $('<a />', { href: '' })
21654                  .on('click', function (e) {
21655                    e.preventDefault();
21656                    pages.reskontra.credit_debt_collection_fees(invoice_id);
21657                  })
21658                  .text('Hyvitä muistutuskulut laskulta')
21659              )
21660            )
21661          }
21662          return $list;
21663        };
21664
21665        if (!invoice.jobOrderId && !invoice.invoice.towing_record_id) {
21666          $('#customer_add_creditnote')
21667            .button({ icons: { primary: 'ui-icon-pencil' } })
21668            .on('click', function () {
21669              window.LaskutusJaReskontra.invoiceDialog.showCustomerCreditInvoiceDialog();
21670            });
21671        } else {
21672          $('#customer_add_creditnote')
21673              .button({ icons: { primary: 'ui-icon-triangle-1-s' } })
21674              .append('<span class="ui-icon ui-icon-triangle-1-s" style="float: right; margin-left: 5px;"></span>')
21675              .wrap($('<div />', { style: 'float:left;' }))
21676              .wrap($('<div />', {}))
21677              .parent()
21678              .parent()
21679              .append(customerAddCreditnoteMethods())
21680              .parent()
21681              .parent()
21682              .find('#customer_add_creditnote')
21683              .on('click', function (e) {
21684                e.stopPropagation();
21685      
21686                $('.menu').hide();
21687      
21688                var $menu = $(this).parent().next();
21689      
21690                if ($menu.is(':visible')) {
21691                  $menu.hide();
21692                } else {
21693                  $('.ui-menu').hide();
21694                  $menu.show().position({
21695                    my: 'left top',
21696                    at: 'left bottom',
21697                    of: this,
21698                  });
21699                }
21700      
21701                var menu = $(this).parent().next();
21702                $(document).one('click', function () {
21703                  menu.hide();
21704                });
21705      
21706                $(document).one('click', function () {
21707                  $menu.hide();
21708                });
21709                return false;
21710              })
21711              .parent()
21712              .buttonset()
21713              .next()
21714              .hide()
21715              .menu();
21716        }
21717
21718      //console.log('init_show_invoice', 7175);
21719      $('#add_credit_line')
21720        .button({ icons: { primary: 'ui-icon-plusthick' } })
21721        .addClass('btn btn-default')
21722        .on('click', function () {
21723          pages.reskontra.show_add_credit_line_dialog(invoice_id, invoice_items);
21724        });
21725
21726      $('#copy_invoice')
21727        .button({ icons: { primary: 'ui-icon-copy' } })
21728        .on('click', function () {
21729          pages.reskontra.copy_invoice(invoice_id);
21730        });
21731
21732      $('#delete_draft')
21733        .button({ icons: { primary: 'ui-icon-trash' } })
21734        .on('click', function () {
21735          pages.reskontra.confirm_delete_draft(invoice_id);
21736        });
21737
21738      $('#add_payment')
21739        .button({ icons: { primary: 'ui-icon-plusthick' } })
21740        .click(function () {
21741          pages.reskontra.show_add_payment_dialog(invoice_id, open_sum, 'invoice');
21742        });
21743
21744      $('#add_refund_payment')
21745        .button({ icons: { primary: 'ui-icon-plusthick' } })
21746        .click(function () {
21747          console.log('add_refund_payment');
21748          pages.reskontra.show_add_refund_payment_dialog(invoice_id, open_sum, 'invoice');
21749        });
21750
21751      $('#start_debt_collection')
21752        .button({ icons: { primary: 'ui-icon-plusthick' } })
21753        .on('click', function () {
21754          console.log('start_debt_collection');
21755          pages.reskontra.confirm_debt_collection(invoice_id);
21756        });
21757
21758      var invoiceCopyDeliveryMethods = function () {
21759        var $list = $('<ul />', { style: 'position:absolute; z-index:99; font-size:13px;' });
21760
21761        $list.append(
21762          $('<li />', {}).append(
21763            $('<a />', { href: '' })
21764              .on('click', function (e) {
21765                e.preventDefault();
21766                pages.reskontra.send_invoice_copy_by_mail(invoice.id);
21767              })
21768              .text('Posti')
21769          ),
21770          $('<li />', {}).append(
21771            $('<a />', { href: '' })
21772              .on('click', function (e) {
21773                e.preventDefault();
21774                pages.reskontra.send_invoice_copy_by_email(invoice.id, invoice.email);
21775              })
21776              .text('Sähköposti')
21777          ),
21778          $('<li />', {}).append(
21779            $('<a />', { href: '' })
21780              .on('click', function (e) {
21781                e.preventDefault();
21782                pages.reskontra.send_invoice_copy_by_sms(invoice.id);
21783              })
21784              .text('Tekstiviesti')
21785          )
21786        );
21787
21788        if (invoice.invoice.customer_type !== 'person') {
21789          var disableEditing =
21790            invoice.isAutoliitto || invoice.isSos || invoice.isInsuranceCompany ? true : false;
21791          $list.append(
21792            $('<li />', {}).append(
21793              $('<a />', { href: '' })
21794                .on('click', function (e) {
21795                  e.preventDefault();
21796
21797                  var errorMessage = pages.reskontra.checkInvoiceStatusBeforeSendEinvoice(invoice);
21798                  if (errorMessage) {
21799                    $('<div>' + errorMessage + '</div>').dialog({
21800                      modal: true,
21801                      buttons: {
21802                        Ok: function() {
21803                          $(this).dialog('close');
21804                        }
21805                      }
21806                    });
21807                    return;
21808                  }
21809
21810                  pages.reskontra.send_invoice_copy_by_e_invoice(
21811                    invoice.id,
21812                    disableEditing,
21813                    invoice.eInvoiceAddress,
21814                    invoice.eInvoiceOperator,
21815                    invoice.eInvoiceOperators
21816                  );
21817                })
21818                .text('Verkkolasku')
21819            )
21820          );
21821        }
21822        return $list;
21823      };
21824
21825      $('#send_invoice_copy')
21826          .button({ icons: { primary: 'ui-icon-mail-closed' } })
21827          .append('<span class="ui-icon ui-icon-triangle-1-s" style="float: right; margin-left: 5px;"></span>')
21828          .wrap($('<div />', { style: 'float:left;' }))
21829          .wrap($('<div />', {}))
21830          .parent()
21831          .parent()
21832          .append(invoiceCopyDeliveryMethods())
21833          .parent()
21834          .parent()
21835          .find('#send_invoice_copy')
21836          .on('click',function() {
21837            var $menu = $(this)
21838                .parent()
21839                .next();
21840
21841            if ($menu.is(':visible')) {
21842              $menu.hide();
21843            } else {
21844              $('.ui-menu').hide();
21845              $menu.show().position({
21846                my: 'left top',
21847                at: 'left bottom',
21848                of: this,
21849              });
21850            }
21851
21852            var menu = $(this)
21853                .parent()
21854                .next();
21855            $(document).one('click', function() {
21856              menu.hide();
21857            });
21858            return false;
21859          })
21860          .parent()
21861          .buttonset()
21862          .next()
21863          .hide()
21864          .menu();
21865
21866      $('#send_by_email')
21867        .button({ icons: { primary: 'ui-icon-mail-closed' } })
21868        .on('click', function () {
21869          //console.log("button clicked", 6427);
21870          pages.reskontra.enter_email_dialog(invoice_id);
21871        });
21872
21873      $('#show_invoice_interest')
21874        .button({ icons: { primary: 'ui-icon-plusthick' } })
21875        .on('click',function() {
21876
21877          function onSuccess(resp, target){
21878            if(resp.data){
21879
21880              var remainingFee = resp.data.remainingFee === 0 || resp.data.remainingFee ? resp.data.remainingFee : null;
21881              var remainingInterest = resp.data.remainingInterest === 0 || resp.data.remainingInterest ? resp.data.remainingInterest : null;
21882
21883              if(remainingInterest !== null && remainingInterest !== null){
21884                var partialData = {
21885                  'Maksamattomat_kulut': remainingFee,
21886                  'Maksamattomat_korot': remainingInterest
21887                }
21888
21889                var dataString = JSON.stringify(partialData, null, 4);
21890                dataString = dataString.replace(/[}{]/g, '');
21891                target.html('<pre>'+dataString+'</pre><span>Mikäli haluatte hyvittää perinnästä aiheutuneet kulut/korot, jätä viesti asiakaspalveluumme (Muistiinpano)</span>');
21892              } else {
21893                target.html('Laskun tietoja ei löytynyt');
21894              }
21895            }else{
21896              target.html('Laskun tietoja ei löytynyt');
21897            }
21898          }
21899
21900          function onError(response, target){
21901            global.close_loading_dialog();
21902            try {
21903              target.html(JSON.parse(response.responseText));
21904            }catch (exception){
21905              target.html('Odottamaton virhe tapahtui palvelimella. Virhesanoma tallennettu palvelimen lokiin.');
21906            }
21907          }
21908          LaskutusJaReskontra.invoiceDialog.showAccumulatedInterest(onSuccess, onError);
21909        });
21910
21911      $('#send_invoice_copy_by_email')
21912        .button({ icons: { primary: 'ui-icon-mail-closed' } })
21913        .on('click', function () {
21914          pages.reskontra.send_invoice_copy_by_email(invoice.id, invoice.email);
21915        });
21916
21917      $('#send_invoice_copy_by_sms')
21918        .button({ icons: { primary: 'ui-icon-mail-closed' } })
21919        .on('click', function () {
21920          pages.iv_laskutus_ja_reskontra.send_invoice_copy_by_sms(
21921            invoice.invoice.id,
21922            invoice.invoice.phone
21923          );
21924        });
21925
21926      $('#send_manual_reminder')
21927        .button({ icons: { primary: 'ui-icon-plusthick' } })
21928        .on('click', function () {
21929          console.log(invoice);
21930          pages.reskontra.showAddManualReminderDialog(invoice_id, recipientEmail);
21931        });
21932
21933      $('#add_log_item')
21934        .button({ icons: { primary: 'ui-icon-plusthick' } })
21935        .on('click', function () {
21936          pages.iv_laskutus_ja_reskontra.add_log_item(invoice_id);
21937        });
21938
21939      $('#show_invoice_pdf')
21940        .button({ icons: { primary: 'ui-icon-document' } })
21941        .on('click', function () {
21942          var receiptUrl = '/lasku/pdf/' + invoice_id,
21943            w = window.open();
21944          w.location = receiptUrl;
21945        });
21946
21947      $('#show_invoice .show_invoice_log').on('click', function (e) {
21948        e.preventDefault();
21949        var invoice_id = $(this).attr('href');
21950        pages.reskontra.show_invoice_log(invoice_id);
21951      });
21952
21953      $('#print-pdf')
21954        .button({ icons: { primary: 'ui-icon-print' } })
21955        .wrap($('<div />', { style: 'float:left; margin-right: 5px;' }))
21956        .on('click', function () {
21957          window.LaskutusJaReskontra.invoiceDialog.insertInvoiceToArvatoIfRequiredAndPrintPdf();
21958        });
21959
21960      $('#request_for_crediting')
21961        .button({ icons: { primary: 'ui-icon-cancel' } })
21962        .on('click', function () {
21963          window.LaskutusJaReskontra.invoiceDialog.showRequestForCreditingDialog();
21964        });
21965
21966      $('#edit_invoice')
21967        .button({ icons: { primary: 'ui-icon-pencil' } })
21968        .on('click', function () {
21969          pages.reskontra.edit_invoice(invoice_id);
21970        });
21971
21972      $('#show_invoice a.show_invoice').on('click', function (e) {
21973        e.preventDefault();
21974        var invoice_id = $(this).attr('href');
21975        pages.reskontra.show_invoice(invoice_id);
21976      });
21977
21978      $('#print_receipt')
21979        .button({ icons: { primary: 'ui-icon-print' } })
21980        .on('click', function () {
21981          var receiptUrl = '/lasku/kuitti/' + invoice_id;
21982
21983          window.open(receiptUrl);
21984        });
21985
21986      $('#show-credit-invoice-dialog')
21987        .button({ icons: { primary: 'ui-icon-plusthick' } })
21988        .on('click', function () {
21989          window.LaskutusJaReskontra.invoiceDialog.showCreditInvoiceDialog();
21990        });
21991
21992      $('#go_to_job_order')
21993        .button({ icons: { primary: 'ui-icon-arrowthick-1-e' } })
21994        .click(function () {
21995          document.location.assign('/innokorjaamo/edit/' + jobOrderId);
21996        });
21997
21998      $('#go_to_towing_record')
21999      .button({ icons: { primary: 'ui-icon-arrowthick-1-e' }})
22000      .click(function () {
22001        document.location.assign('/kuormakirja/edit/' + towingRecordId);
22002      })
22003
22004      $('#update_due_date')
22005        .button({ icons: { primary: 'ui-icon-calendar' } })
22006        .click(function () {
22007          window.LaskutusJaReskontra.invoiceDialog.postponeDueDateDialog.show(
22008            $('#due_date').text()
22009          );
22010        });
22011
22012      $('#add-credit-loss')
22013        .button({ icons: { primary: 'ui-icon-plusthick' } })
22014        .click(function () {
22015          window.LaskutusJaReskontra.invoiceDialog.confirmAddCreditLoss();
22016        });
22017    }, //init_show_invoice
22018
22019    checkInvoiceStatusBeforeChangeDueDate: function (invoice) {
22020      
22021      if (window.App.user.access_level >= 100) {
22022        return null;
22023      }
22024      switch (invoice.invoice.status){
22025        case '2':
22026        case '6':
22027          return 'Eräpäivää ei voi siirtää, lasku on rahoitettu'
22028        case '11':
22029          return 'Eräpäivää ei voi siirtää, lasku on muistutuksessa'
22030        case '13':
22031          return 'Eräpäivää ei voi siirtää, lasku on perinnässä'
22032        case '30':
22033          return 'Eräpäivää ei voi siirtää.'
22034        case '40':
22035        case '50':
22036          if (invoice.invoice.ledger_service === 'kredinor') {
22037            return 'Eräpäivää ei voi siirtää, lasku on maksettu.'
22038          } else if (invoice.invoice.ledger_service === 'riverty') {
22039            return 'Eräpäivää ei voi siirtää, lasku on rahoitettu.'
22040          }
22041          return 'Eräpäivää ei voi siirtää.'
22042        default:
22043          return null
22044      }
22045    },
22046
22047    checkInvoiceStatusBeforeSendEinvoice: function (invoice) {
22048      switch (invoice.invoice.status) {
22049        case '7':
22050        case '40':
22051        case '50':
22052          var dueDate = new Date(invoice.invoice.due_date);
22053          var currentDate = new Date();
22054          
22055          if (dueDate < currentDate) {
22056            return 'Verkkolaskua ei voi lähettää, lasku on erääntynyt.';
22057          }
22058          break;
22059        case '10':
22060        case '11':
22061        case '13':
22062        case '30':
22063          return 'Verkkolaskua ei voi lähettää, lasku on erääntynyt.';
22064        default:
22065          return null;
22066      }
22067    },
22068
22069    checkInvoiceStatusBeforePaidToCustomer: function (invoice) {
22070      switch (invoice.invoice.status){
22071        case '40':
22072        case '50':
22073          if (invoice.invoice.ledger_service === 'kredinor') {
22074            return 'Lasku on jo maksettu, et voi merkitä tätä maksetuksi tilillenne.'
22075          } else if (invoice.invoice.ledger_service === 'riverty') {
22076            return null;
22077          }
22078          return null;
22079        default:
22080          return null
22081      }
22082    },
22083
22084    createInvoiceReport: function () {
22085      var customers = [
22086        '<option value="insurance_companies_and_display_in_custom_registry">Vakuutusyhtiöt ja asiakasrekisteri</option>',
22087        '<option value="insurance_companies">Vakuutusyhtiöt</option>',
22088        '<option value="display_in_customer_registry">Asiakasrekisterissä olevat</option>',
22089        '<option value="hansel">Hansel</option>',
22090        '<option value="all">Kaikki</option>',
22091      ];
22092      var d_from = new Date();
22093      d_from.setDate(1);
22094      var d_to = new Date();
22095      var $date_from = $(
22096        '<input type="text" class="text small" id="date_from" name="date_from" value="' +
22097          d_from.getDate() +
22098          '.' +
22099          (d_from.getMonth() + 1) +
22100          '.' +
22101          d_from.getFullYear() +
22102          '" />'
22103      ).datepicker($.datepicker.regional.fi);
22104      var $date_to = $(
22105        '<input type="text" class="text small" id="date_to" name="date_to" value="' +
22106          d_to.getDate() +
22107          '.' +
22108          (d_to.getMonth() + 1) +
22109          '.' +
22110          d_to.getFullYear() +
22111          '" />'
22112      ).datepicker($.datepicker.regional.fi);
22113
22114      var $createReportDialog = $('<div></div>')
22115        .append(
22116          $('<form />', {
22117            id: 'create_invoice_report',
22118            target: '_blank',
22119            method: 'post',
22120            action: '/reskontra/create_invoice_report',
22121          }).append(
22122            $('<span />', { class: 'ui-helper-hidden-accessible' }).append('<input />', {
22123              type: 'text',
22124            }),
22125            $('<fieldset />', { class: 'fs-invisible', style: '' }).append(
22126              $('<ol />').append(
22127                $('<li />', { style: 'padding:7px 0;' }).append(
22128                  $('<label />', { id: 'date_from_label', style: 'width:130px;' }).html(
22129                    'Laskut ajalta'
22130                  ),
22131                  $date_from,
22132                  ' - ',
22133                  $date_to
22134                ),
22135
22136                $('<li />', { style: 'padding:7px 0;' }).append(
22137                  $('<label />', {
22138                    id: '',
22139                    style: 'font-weight:bold; width:130px; height:40px;',
22140                  }).html('Asiakkaat'),
22141                  $('<select/>', { name: 'filters[customers]' }
22141).append(customers.join(''))
22142                ),
22143                $('<li />', { style: 'padding:7px 0;' }).append(
22144                  $('<label />', {
22145                    id: '',
22146                    style: 'font-weight:bold; width:130px; height:40px;',
22147                  }).html('Erittele laskut'),
22148                  $('<select/>', { name: 'grouping', id: 'grouping' }).append(
22149                    $('<option />', { value: 'by_customer_summarized' }).html(
22150                      'Asiakkaittain - Summat'
22151                    ),
22152                    $('<option />', { value: 'by_customer' }).html('Asiakkaittain - Laskuerittely'),
22153                    $('<option />', { value: 'by_delivery_date' }).html(
22154                      'Luontipäivän mukaan - Laskuerittely'
22155                    ),
22156                    $('<option />', { value: 'all' }).html('Kaikki yhdessä - Laskuerittely')
22157                  )
22158                ),
22159
22160                $('<li />', { style: 'padding:7px 0;' }).append(
22161                  $('<label />', { style: 'font-weight:bold; width:130px; height:40px;' }).html(
22162                    'Näytä laskut'
22163                  ),
22164                  $('<input />', {
22165                    id: 'status_open',
22166                    type: 'checkbox',
22167                    name: 'filters[status][]',
22168                    value: 'open',
22169                    checked: 'checked',
22170                  }),
22171                  $('<label />', {
22172                    for: 'status_open',
22173                    style: 'font-weight:normal;  display:inline; float:none; width:auto;',
22174                  }).html('Avoimet'),
22175                  $('<input />', {
22176                    id: 'status_paid',
22177                    type: 'checkbox',
22178                    name: 'filters[status][]',
22179                    value: 'paid',
22180                    checked: 'checked',
22181                  }),
22182                  $('<label />', {
22183                    for: 'status_paid',
22184                    style: 'font-weight:normal;  display:inline; float:none; width:auto;',
22185                  }).html('Tilitetyt'),
22186                  $('<input />', {
22187                    id: 'status_credited',
22188                    type: 'checkbox',
22189                    name: 'filters[status][]',
22190                    value: 'credited',
22191                    checked: 'checked',
22192                  }),
22193                  $('<label />', {
22194                    for: 'status_credited',
22195                    style: 'font-weight:normal;  display:inline; float:none; width:auto;',
22196                  }).html('Hyvitetyt')
22197                ),
22198
22199                $('<li />', { style: 'padding:7px 0;' }).append(
22200                  $('<label />', {
22201                    id: '',
22202                    style: 'font-weight:bold; width:130px; height:40px;',
22203                  }).html('Raportin muoto'),
22204                  $('<select/>', { name: 'printer', id: 'printer' }).append(
22205                    $('<option />', { value: 'csv' }).html('CSV'),
22206                    $('<option />', { value: 'pdf' }).html('PDF')
22207                  )
22208                )
22209              )
22210            )
22211          )
22212        )
22213        .dialog({
22214          width: 550,
22215          autoOpen: true,
22216          modal: true,
22217          resizable: false,
22218          draggable: false,
22219          beforeClose: function (event, ui) {
22220            event.stopPropagation();
22221          },
22222          title: 'Luo raportti laskuista',
22223          buttons: {
22224            Peruuta: function () {
22225              $(this).dialog('close');
22226            },
22227            'Luo raportti': function () {
22228              $createReportDialog.find('form').submit();
22229            },
22230          },
22231        });
22232    },
22233
22234    init_show_money_transfer_item: function() {},
22235
22236    send_invoice_by_mail: function (invoice_id) {
22237      $dialog = $('<div />', { style: 'text-align:left;' })
22238        .html('Haluatko varmasti lähettää lasku postitse?')
22239        .dialog({
22240          autoOpen: true,
22241          modal: true,
22242          resizable: false,
22243          draggable: false,
22244          title: 'Lähetä lasku postitse',
22245          beforeClose: function (event, ui) {
22246            event.stopPropagation();
22247          },
22248          buttons: {
22249            Peruuta: function () {
22250              $dialog.dialog('close');
22251            },
22252            'Lähetä lasku': function () {
22253              $.ajax({
22254                dataType: 'json',
22255                type: 'POST',
22256                url: '/reskontra/send_invoice_by_mail/' + invoice_id,
22257                beforeSend: function (request) {
22258                  global.showLoadingDialog('Lähetetään laskua...');
22259                },
22260                success: function (responseJSON) {
22261                  if (responseJSON.type == 'success') {
22262                    //Refresh the datatables
22263                    if (pages.iv_laskutus_ja_reskontra.$datatable_iv != null) {
22264                      pages.iv_laskutus_ja_reskontra.$datatable_iv.fnClearTable(0);
22265                      pages.iv_laskutus_ja_reskontra.$datatable_iv.fnDraw();
22266                    }
22267
22268                    if (pages.iv_laskutus_ja_reskontra.$datatable != null) {
22269                      pages.iv_laskutus_ja_reskontra.$datatable.fnClearTable(0);
22270                      pages.iv_laskutus_ja_reskontra.$datatable.fnDraw();
22271                    }
22272
22273                    if (pages.reskontra.$datatable != null) {
22274                      pages.reskontra.$datatable.fnClearTable(0);
22275                      pages.reskontra.$datatable.fnDraw();
22276                    }
22277
22278                    LaskutusJaReskontra.showInvoiceDialog({
22279                      invoiceId: invoice_id,
22280                    });
22281                  }
22282
22283                  global.show_message(responseJSON);
22284                  global.close_loading_dialog();
22285
22286                  $dialog.dialog('close');
22287                },
22288                error: function (response) {
22289                  global.close_loading_dialog();
22290                  global.show_message($.parseJSON(response.responseText));
22291                },
22292              });
22293            },
22294          },
22295        });
22296    },
22297
22298    send_invoice_by_sms: function (invoiceId, phone) {
22299      var $form = $('<form />').append(
22300        $('<p />').html('Anna puhelinnumero'),
22301        $('<input />', { type: 'text', name: 'toSms', id: 'toSms', class: 'text medium' }).val(
22302          phone
22303        )
22304      );
22305
22306      $form.submit(function (e) {
22307        e.preventDefault();
22308        var phone = document.getElementById('toSms').value;
22309        var data = {
22310          phone: phone,
22311        };
22312
22313        global.showLoadingDialog('Lähetetään lasku...');
22314
22315        $.ajax({
22316          url: '/reskontra/send_invoice_by_sms/' + invoiceId,
22317          dataType: 'json',
22318          type: 'POST',
22319          data: data,
22320        })
22321          .done(function (responseJSON) {
22322            $dialog.dialog('close');
22323            global.show_message(responseJSON);
22324            global.close_loading_dialog();
22325          })
22326          .fail(function (response) {
22327            var responseJSON = $.parseJSON(response.responseText);
22328            global.close_loading_dialog();
22329            global.show_message(responseJSON);
22330          });
22331      });
22332
22333      var $dialog = $('<div />', { style: 'text-align:left;' })
22334        .append($form)
22335        .dialog({
22336          width: 320,
22337          autoOpen: true,
22338          modal: true,
22339          resizable: false,
22340          draggable: false,
22341          beforeClose: function (event, ui) {
22342            event.stopPropagation();
22343          },
22344          close: function () {
22345            $(this).dialog('destroy');
22346            $(this).remove();
22347          },
22348          title: 'Lähetä lasku sms viestinä',
22349          buttons: {
22350            Peruuta: function () {
22351              $(this).dialog('close');
22352            },
22353            'Lähetä lasku': function () {
22354              $form.submit();
22355            },
22356          },
22357        });
22358    },
22359
22360    send_invoice_by_email: function (invoice_id, email) {
22361      var $form = $('<form />', {
22362        method: 'POST',
22363        action: '/reskontra/send_invoice_by_email/' + invoice_id,
22364      }).append(
22365        $('<p />').html('Anna sähköpostiosoite minne lasku lähetetään'),
22366        $('<input />', {
22367          type: 'text',
22368          name: 'send_to_email',
22369          id: 'send_to_email',
22370          class: 'text medium',
22371        }).val(email)
22372      );
22373
22374      $form.submit(function (e) {
22375        e.preventDefault();
22376
22377        $form.ajaxSubmit({
22378          dataType: 'json',
22379          type: 'POST',
22380
22381          beforeSend: function (request) {
22382            global.showLoadingDialog('Lähetetään laskua...');
22383          },
22384          success: function (responseJSON) {
22385            if (responseJSON.type == 'success') {
22386              $dialog.dialog('close');
22387
22388              //Refresh the datatables
22389              if (pages.iv_laskutus_ja_reskontra.$datatable_iv != null) {
22390                pages.iv_laskutus_ja_reskontra.$datatable_iv.fnClearTable(0);
22391                pages.iv_laskutus_ja_reskontra.$datatable_iv.fnDraw();
22392              }
22393
22394              if (pages.iv_laskutus_ja_reskontra.$datatable != null) {
22395                pages.iv_laskutus_ja_reskontra.$datatable.fnClearTable(0);
22396                pages.iv_laskutus_ja_reskontra.$datatable.fnDraw();
22397              }
22398
22399              if (pages.reskontra.$datatable != null) {
22400                pages.reskontra.$datatable.fnClearTable(0);
22401                pages.reskontra.$datatable.fnDraw();
22402              }
22403
22404              LaskutusJaReskontra.showInvoiceDialog({
22405                invoiceId: invoice_id,
22406              });
22407            }
22408
22409            global.show_message(responseJSON);
22410            global.close_loading_dialog();
22411          },
22412          error: function (response) {
22413            global.close_loading_dialog();
22414            global.show_message($.parseJSON(response.responseText));
22415          },
22416        });
22417      });
22418
22419      var $dialog = $('<div />', { style: 'text-align:left;' })
22420        .append($form)
22421        .dialog({
22422          width: 320,
22423          autoOpen: true,
22424          modal: true,
22425          resizable: false,
22426          draggable: false,
22427          beforeClose: function (event, ui) {
22428            event.stopPropagation();
22429          },
22430          title: 'Lähetä lasku sähköpostitse',
22431          buttons: {
22432            Peruuta: function () {
22433              $(this).dialog('close');
22434            },
22435            'Lähetä lasku': function () {
22436              $form.submit();
22437            },
22438          },
22439        });
22440    },
22441
22442    send_invoice_by_e_invoice: function (invoice_id) {
22443      $dialog = $('<div />', { style: 'text-align:left;' })
22444        .html('Haluatko varmasti lähettää laskun verkkolaskuna?')
22445        .dialog({
22446          autoOpen: true,
22447          modal: true,
22448          resizable: false,
22449          draggable: false,
22450          title: 'Lähetä lasku verkkolaskuna',
22451          beforeClose: function (event, ui) {
22452            event.stopPropagation();
22453          },
22454          buttons: {
22455            Peruuta: function () {
22456              $dialog.dialog('close');
22457            },
22458            'Lähetä lasku': function () {
22459              $.ajax({
22460                dataType: 'json',
22461                type: 'POST',
22462                url: '/reskontra/send_invoice_by_e_invoice/' + invoice_id,
22463                beforeSend: function (request) {
22464                  global.showLoadingDialog('Lähetetään laskua...');
22465                },
22466                success: function (responseJSON) {
22467                  if (responseJSON.type == 'success') {
22468                    //Refresh the datatables
22469                    if (pages.iv_laskutus_ja_reskontra.$datatable_iv != null) {
22470                      pages.iv_laskutus_ja_reskontra.$datatable_iv.fnClearTable(0);
22471                      pages.iv_laskutus_ja_reskontra.$datatable_iv.fnDraw();
22472                    }
22473
22474                    if (pages.iv_laskutus_ja_reskontra.$datatable != null) {
22475                      pages.iv_laskutus_ja_reskontra.$datatable.fnClearTable(0);
22476                      pages.iv_laskutus_ja_reskontra.$datatable.fnDraw();
22477                    }
22478
22479                    if (pages.reskontra.$datatable != null) {
22480                      pages.reskontra.$datatable.fnClearTable(0);
22481                      pages.reskontra.$datatable.fnDraw();
22482                    }
22483
22484                    LaskutusJaReskontra.showInvoiceDialog({
22485                      invoiceId: invoice_id,
22486                    });
22487                  }
22488
22489                  global.show_message(responseJSON);
22490                  global.close_loading_dialog();
22491
22492                  $dialog.dialog('close');
22493                },
22494                error: function (response) {
22495                  global.close_loading_dialog();
22496                  global.show_message($.parseJSON(response.responseText));
22497                },
22498              });
22499            },
22500          },
22501        });
22502    },
22503
22504    credit_debt_collection_fees: function (invoice_id) {
22505      var $dialog = $('<div></div>')
22506        .append(
22507          $('<p />', {}).append(
22508            $('<br />'),
22509            $('<input />', {
22510              type: 'radio',
22511              id: 'removeFees',
22512              name: 'actionNoteType',
22513              value: 'removeFees',
22514            }),
22515            $('<label />', {
22516              for: 'removeFees',
22517              text: 'Hyvitä muistutus- ja perintäkulut',
22518              style: 'display:inline; float:none;',
22519            }),
22520            $('<br />'),
22521            $('<input />', {
22522              type: 'radio',
22523              id: 'removeFeesAndInterests',
22524              name: 'actionNoteType',
22525              value: 'removeFeesAndInterests',
22526              checked: true,
22527            }),
22528            $('<label />', {
22529              for: 'removeFeesAndInterests',
22530              text: 'Hyvitä muistutus- ja perintäkulut + korot',
22531              style: 'display:inline; float:none;',
22532            }),
22533            $('<div>', {
22534              style: 'margin-top: 15px;'
22535            }).append(
22536              $('<label>', {
22537                text: 'Viesti:',
22538                style: 'display: block; margin-bottom: 5px; font-weight: bold;'
22539              }),
22540              $('<textarea>', {
22541                id: 'message',
22542                style: 'width: 100%; height: 80px; resize: vertical;'
22543              })
22544            )
22545          )
22546        )
22547        .dialog({
22548          autoOpen: true,
22549          modal: true,
22550          resizable: false,
22551          draggable: true,
22552          title: 'Hyvitä muistutus- ja perintäkulut / korot',
22553          width: 400,
22554          beforeClose: function (e) {
22555            e.stopPropagation();
22556          },
22557          buttons: {
22558            'Sulje': function () {
22559              $(this).dialog('close');
22560            },
22561            'Hyvitä': function () {
22562              var creditType = $dialog.find('input[name="actionNoteType"]:checked').val();
22563              var message = $dialog.find('#message').val();
22564              global.showLoadingDialog('Hyvitetään muistutuskulut laskulta...');
22565              $.ajax({
22566                url: '/reskontra/credit_debt_collection_fees/',
22567                type: 'post',
22568                data: {
22569                  invoice_id: invoice_id,
22570                  actionNoteType: creditType,
22571                  message: message
22572                },
22573                success: function (responseJSON) {
22574                  global.close_loading_dialog();
22575                  global.show_message(responseJSON);
22576                  $dialog.dialog('close');
22577                },
22578                error: function (response) {
22579                  global.close_loading_dialog();
22580                  global.show_message($.parseJSON(response.responseText));
22581                }
22582              });
22583            },
22584          },
22585        });
22586    },
22587
22588    paid_to_customer: function (invoice) {
22589      var $dialog = $('<div></div>')
22590        .append($('<div />', {
22591          style: 'margin-bottom: 15px; '
22592        }).append(
22593          $('<label />', {
22594            text: 'Maksettu summa',
22595            style: 'width: auto;'
22596          }),
22597          $('<input />', {
22598            type: 'text',
22599            id: 'amount',
22600            class: 'form-control',
22601            value: invoice.invoiceTotals.openAmount
22602          }),
22603          $('<label />', {
22604            text: 'Maksettu päivämäärä',
22605            style: 'width: auto;'
22606          }),
22607          $('<input />', {
22608            type: 'date',
22609            id: 'paidDate',
22610            class: 'form-control',
22611            value: new Date().toISOString().split('T')[0]
22612   
22612       })
22613        ))
22614        .dialog({
22615          autoOpen: true,
22616          modal: true,
22617          resizable: false,
22618          draggable: true,
22619          title: 'Asiakas maksoi tililleni',
22620          beforeClose: function (event, ui) {
22621            event.stopPropagation();
22622          },
22623          buttons: {
22624            'Sulje': function () {
22625              $(this).dialog('close');
22626            },
22627            'Tallenna': function (e) {
22628              e.preventDefault();
22629
22630              var errorMessage = pages.reskontra.checkInvoiceStatusBeforePaidToCustomer(invoice);
22631              if (errorMessage) {
22632                $('<div>' + errorMessage + '</div>').dialog({
22633                  modal: true,
22634                  buttons: {
22635                    Ok: function() {
22636                      $(this).dialog('close');
22637                    }
22638                  }
22639                });
22640                return;
22641              }
22642
22643              var amount = $(this).find('#amount').val();
22644              var paidDate = $(this).find('#paidDate').val();
22645              var data = {
22646                invoiceId: invoice.id,
22647                amount: amount,
22648                paidDate: paidDate
22649              };
22650              $.ajax({
22651                url: '/reskontra/paid_to_customer/',
22652                type: 'post',
22653                data: data,
22654                success: function (responseJSON) {
22655                  if (responseJSON.type == 'success') {
22656
22657                    LaskutusJaReskontra.showInvoiceDialog({
22658                      invoiceId: invoice.id,
22659                    });
22660                  }
22661
22662                  global.show_message(responseJSON);
22663                  global.close_loading_dialog();
22664                  $dialog.dialog('close');
22665                },
22666                error: function (response) {
22667                  global.close_loading_dialog();
22668                  global.show_message($.parseJSON(response.responseText));
22669                }
22670              });
22671            },
22672          },
22673        });
22674    },
22675
22676    add_log_item: function (invoice_id) {
22677      $('<div></div>')
22678        .append(
22679          $('<label />', {
22680            id: '',
22681            for: 'notifyInnovoice',
22682            style: 'font-weight:bold; width:100%;margin-bottom: 0;',
22683          }).html('Tyyppi'),
22684          $('<select/>', {
22685            id: 'notifyInnovoice',
22686            class: 'btn-sm',
22687            name: 'notify',
22688            style: 'font-weight: 500; line-height: 1.5; margin-bottom: 10px;',
22689          }).append(
22690            $('<option />', { value: '' }).html('Valitse'),
22691            $('<option />', { value: '1' }).html('Viesti Innovoicen asiakaspalveluun'),
22692            $('<option />', { value: '0' }).html('Oma muistiinpano')
22693          ),
22694          $('<label />', { style: 'width:auto;' })
22695            .html('Viesti')
22696            .append($('<textarea />', { style: 'width:320px; height:72px;', name: 'log_event' }))
22697            .append('<br />')
22698            .append('<br />')
22699        )
22700        .dialog({
22701          autoOpen: true,
22702          modal: true,
22703          resizable: false,
22704          draggable: false,
22705          width: 380,
22706          title: 'Lisää muistiinpano',
22707          beforeClose: function (event, ui) {
22708            event.stopPropagation();
22709          },
22710          close: function () {
22711            $(this).dialog('destroy');
22712            $(this).remove();
22713          },
22714          buttons: {
22715            Peruuta: function () {
22716              $(this).dialog('close');
22717            },
22718            Tallenna: function () {
22719              global.showLoadingDialog('Viestiä tallennetaan...');
22720              var message = $(this).find('textarea[name=log_event]').val();
22721              var notify = $('select#notifyInnovoice').val();
22722              if (notify === '') {
22723                global.close_loading_dialog();
22724                global.show_message({
22725                  type: 'error',
22726                  title: 'Virhe',
22727                  text: 'Valitse viestin tyyppi.',
22728                });
22729                return;
22730              }
22731              var data = { id: invoice_id, message: message, notify: notify };
22732              $(this).dialog('close');
22733              $.ajax({
22734                url: 'logger/makeLogEntry/',
22735                type: 'post',
22736                data: data,
22737                success: function (resp) {
22738                  global.close_loading_dialog();
22739                  global.show_message({
22740                    type: 'success',
22741                    title: 'Valmis',
22742                    text: 'Muistiinpano lisätty onnistuneesti.',
22743                  });
22744                },
22745              });
22746            },
22747          },
22748        });
22749      $('button').addClass('btn btn-default');
22750    },
22751    
22752    copy_invoice: function (invoice_id) {
22753      $('<div></div>')
22754        .html('Haluatko siirtyä luomaan uuden laskun, käyttäen tätä laskua pohjana?')
22755        .dialog({
22756          autoOpen: true,
22757          modal: true,
22758          resizable: false,
22759          draggable: false,
22760          title: 'Kopioi lasku',
22761          beforeClose: function (event, ui) {
22762            event.stopPropagation();
22763          },
22764          buttons: {
22765            Peruuta: function () {
22766              $(this).dialog('close');
22767            },
22768            'Siirry laskun luontiin': function () {
22769              $(this).dialog('close');
22770
22771              window.location = '/lasku/kopioi/' + invoice_id;
22772            },
22773          },
22774        });
22775    }, //copy_invoice
22776
22777    print_receipt: function (invoice_id) {
22778      $('<div></div>')
22779        .html('Haluatko varmasti tulostaa laskun lähete?')
22780        .dialog({
22781          autoOpen: true,
22782          modal: true,
22783          resizable: false,
22784          draggable: false,
22785          title: 'Tulosta laskun lähete',
22786          beforeClose: function (event, ui) {
22787            event.stopPropagation();
22788          },
22789          buttons: {
22790            Peruuta: function () {
22791              $(this).dialog('close');
22792            },
22793            'Tulosta laskun lähete': function () {
22794              $(this).dialog('close');
22795              var receiptUrl = '/lasku/kuitti/' + invoice_id;
22796
22797              window.open(receiptUrl);
22798            },
22799          },
22800        });
22801    },
22802
22803    close_previous_accounting_period: function (
22804      $confirmDialog,
22805      $closePreviousAccountingPeriodButton
22806    ) {
22807      global.show_loading_dialog('Suljetaan kirjanpitokautta');
22808
22809      $.ajax({
22810        url: '/reskontra/close_previous_accounting_period/',
22811        dataType: 'json',
22812        type: 'POST',
22813      })
22814        .done(function (responseJSON) {
22815          $confirmDialog.dialog('close');
22816          $closePreviousAccountingPeriodButton.effect('highlight', {}, 500).fadeOut();
22817          global.show_message(responseJSON);
22818          global.close_loading_dialog();
22819        })
22820        .fail(function (response) {
22821          var responseJSON = $.parseJSON(response.responseText);
22822
22823          //	console.log('fail:', response);
22824          //	console.log($.parseJSON(response.responseText));
22825          global.close_loading_dialog();
22826          global.show_message(responseJSON);
22827        });
22828    },
22829
22830    confirm_delete_draft: function (invoice_id) {
22831      $('<div></div>')
22832        .html('Haluatko varmasti poistaa laskun luonnoksen')
22833        .dialog({
22834          autoOpen: true,
22835          modal: true,
22836          resizable: false,
22837          draggable: false,
22838          title: 'Poista laskun luonnos',
22839          beforeClose: function (event, ui) {
22840            event.stopPropagation();
22841          },
22842          close: function () {
22843            $(this).dialog('destroy');
22844          },
22845          buttons: {
22846            Peruuta: function () {
22847              $(this).dialog('close');
22848            },
22849            Poista: function () {
22850              $(this).dialog('close');
22851              pages.reskontra.delete_draft(invoice_id);
22852            },
22853          },
22854        });
22855    }, //confirm_delete_draft
22856    confirm_debt_collection: function (invoice_id) {
22857      var opts = {
22858        type: 'POST',
22859        url: '/reskontra/startDebtCollection/' + invoice_id,
22860      }
22861      var $dialog = $('<div></div>');
22862      $dialog.html('Haluatko varmasti siirtää laskun perintään')
22863        .dialog({
22864          autoOpen: true,
22865          modal: true,
22866          resizable: false,
22867          draggable: false,
22868          title: 'Poista laskun luonnos',
22869          beforeClose: function (event, ui) {
22870            event.stopPropagation();
22871          },
22872          close: function () {
22873            $(this).dialog('destroy');
22874          },
22875          buttons: {
22876            Peruuta: function () {
22877              $(this).dialog('destroy');
22878            },
22879            "Siirrä perintään": function () {
22880              global.showLoadingDialog('Siirretään laskua...');
22881
22882              $.ajax(opts).done(function(responseJSON){
22883                global.show_message(responseJSON);
22884              }).fail(function(err){
22885                global.show_message(JSON.parse(err.responseText));
22886                pages.reskontra.$datatable.fnClearTable(0);
22887                pages.reskontra.$datatable.fnDraw();
22888              }).always(function(){
22889                global.close_loading_dialog();
22890                $dialog.dialog('close');
22891              })
22892            },
22893          },
22894        });
22895    }, //confirm_delete_draft
22896    show_add_payment_dialog: function (id, open_sum, target_type) {
22897      var d = new Date();
22898      var url = '/reskontra/addInvoicePayment/' + id;
22899
22900      $add_payment_dialog = $('<div></div>')
22901        .append(
22902          $('<form />', { id: 'add_payment_form', method: 'post', action: url })
22903            .append(
22904              $('<fieldset />', { class: 'fs-invisible', style: '' })
22905                .append(
22906                  '<p>Syötä maksusuorituksen summa euroissa ja lisää suorituksen päivämäärä</p>'
22907                )
22908                .append(
22909                  $('<ol />')
22910                    .append(
22911                      $('<li />')
22912                        .append($('<label for="amount">Summa:</label>'))
22913                        .append(
22914                          $(
22915                            '<input type="text" name="amount" id="amount" value="' +
22916                              open_sum +
22917                              '" class="text small" />'
22918                          )
22919                        )
22920                        .append(' &euro;')
22921                    )
22922                    .append(
22923                      $('<li />')
22924                        .append($('<label id="created_label" for="created">Päivämäärä:</label>'))
22925                        .append(
22926                          $(
22927                            '<input type="text" class="text small" id="created" name="created" value="' +
22928                              d.getDate() +
22929                              '.' +
22930                              (d.getMonth() + 1) +
22931                              '.' +
22932                              d.getFullYear() +
22933                              '" />'
22934                          ).datepicker($.datepicker.regional.fi)
22935                        )
22936                    )
22937                    .append(
22938                      $('<li />').append(
22939                        $('<button type="submit">Tallenna maksusuoritus</button>').button()
22940                      )
22941                    )
22942                )
22943            )
22944            .submit(function () {
22945              $(this).ajaxSubmit({
22946                dataType: 'json',
22947                beforeSubmit: function () {
22948                  global.showLoadingDialog('Tallennetaan maksusuoritusta...');
22949                },
22950                success: function (responseJSON) {
22951                  global.show_message(responseJSON);
22952                  global.close_loading_dialog();
22953
22954                  $add_payment_dialog.dialog('close');
22955
22956                  //Refresh the datatables
22957                  pages.reskontra.$datatable.fnClearTable(0);
22958                  pages.reskontra.$datatable.fnDraw();
22959                },
22960                error: function (response) {
22961                  global.close_loading_dialog();
22962                  global.show_message($.parseJSON(response.responseText));
22963                },
22964              });
22965              return false;
22966            })
22967        )
22968        .dialog({
22969          width: 400,
22970          //height:200,
22971          autoOpen: true,
22972          modal: true,
22973          resizable: false,
22974          draggable: false,
22975          beforeClose: function (event, ui) {
22976            event.stopPropagation();
22977          },
22978          close: function () {
22979            $(this).dialog('destroy');
22980            $(this).remove();
22981          },
22982          title: 'Lisää maksusuoritus',
22983          buttons: {
22984            Peruuta: function () {
22985              $(this).dialog('close');
22986            },
22987          },
22988        });
22989    }, //show_add_payment_dialog
22990    show_add_refund_payment_dialog: function (id, open_sum, target_type) {
22991      var d = new Date();
22992      var url = '/reskontra/addRefundPayment/' + id;
22993
22994      $add_payment_dialog = $('<div></div>')
22995        .append(
22996          $('<form />', { id: 'add_payment_form', method: 'post', action: url })
22997            .append(
22998              $('<fieldset />', { class: 'fs-invisible', style: '' })
22999                .append('<p>Tarkista palautettu summa ja anna palautuksen päivämäärä</p>')
23000                .append(
23001                  $('<ol />')
23002                    .append(
23003                      $('<li />')
23004                        .append($('<label for="amount">Summa:</label>'))
23005                        .append(
23006                          $(
23007                            '<input type="text" name="amount" id="amount" value="' +
23008                              open_sum +
23009                              '" class="text small" />'
23010                          )
23011                        )
23012                        .append(' &euro;')
23013                    )
23014                    .append(
23015                      $('<li />')
23016                        .append($('<label id="created_label" for="refundDate">Päivämäärä:</label>'))
23017                        .append(
23018                          $(
23019                            '<input type="text" class="text small" id="created" name="refundDate" value="' +
23020                              d.getDate() +
23021                              '.' +
23022                              (d.getMonth() + 1) +
23023                              '.' +
23024                              d.getFullYear() +
23025                              '" />'
23026                          ).datepicker($.datepicker.regional.fi)
23027                        )
23028                    )
23029                    .append(
23030                      $('<li />').append(
23031                        $('<button type="submit">Merkitse palautetuksi</button>').button()
23032                      )
23033                    )
23034                )
23035            )
23036            .submit(function () {
23037              $(this).ajaxSubmit({
23038                dataType: 'json',
23039                beforeSubmit: function () {
23040                  global.showLoadingDialog('Tallennetaan palautusta...');
23041                },
23042                success: function (responseJSON) {
23043                  window.LaskutusJaReskontra.invoiceDialog.refresh();
23044
23045                  global.show_message(responseJSON);
23046                  global.close_loading_dialog();
23047
23048                  $add_payment_dialog.dialog('close');
23049
23050                  //Refresh the datatables
23051                  pages.reskontra.$datatable.fnClearTable(0);
23052                  pages.reskontra.$datatable.fnDraw();
23053                },
23054                error: function (response) {
23055                  global.close_loading_dialog();
23056                  global.show_message($.parseJSON(response.responseText));
23057                },
23058              });
23059              return false;
23060            })
23061        )
23062        .dialog({
23063          width: 400,
23064          //height:200,
23065          autoOpen: true,
23066          modal: true,
23067          resizable: false,
23068          draggable: false,
23069          beforeClose: function (event, ui) {
23070            event.stopPropagation();
23071          },
23072          close: function () {
23073            $(this).dialog('destroy');
23074            $(this).remove();
23075          },
23076          title: 'Merkitse palautus',
23077          buttons: {
23078            Peruuta: function () {
23079              $(this).dialog('close');
23080            },
23081          },
23082        });
23083    }, //show_add_payment_dialog
23084    enter_email_dialog: function (invoice_id) {
23085      var $form = $('<form />', {
23086        method: 'POST',
23087        action: '/reskontra/send_by_email/' + invoice_id,
23088      }).append(
23089        $('<p />').html('Anna sähköpostiosoite minne lasku lähetetään'),
23090        $('<input />', {
23091          type: 'text',
23092          name: 'send_to_email',
23093          id: 'send_to_email',
23094          class: 'text medium',
23095        })
23096      );
23097
23098      var $dialog = $('<div />', { style: 'text-align:left;' })
23099        .append($form)
23100        .dialog({
23101          width: 320,
23102          autoOpen: true,
23103          modal: true,
23104          resizable: false,
23105          draggable: false,
23106          beforeClose: function (event, ui) {
23107            event.stopPropagation();
23108          },
23109          title: 'Lähetä lasku sähköpostitse',
23110          buttons: {
23111            Peruuta: function () {
23112              $(this).dialog('close');
23113            },
23114            'Lähetä lasku': function () {
23115              $form.ajaxSubmit({
23116                type: 'post',
23117                dataType: 'json',
23118                //show the loading message
23119                beforeSubmit: function () {
23120                  global.show_loading_dialog('Lähetetään laskua...');
23121                },
23122
23123                success: function (responseJSON, statusText, xhr, $form) {
23124                  if (responseJSON.type == 'success') {
23125                    pages.reskontra.$datatable.fnReloadAjax();
23126                  }
23127
23128                  global.show_message(responseJSON);
23129                  global.close_loading_dialog();
23130                  $dialog.dialog('close');
23131                },
23132                error: function (data) {
23133                  global.close_loading_dialog();
23134                },
23135              }); //ajaxSubmit
23136            },
23137          },
23138        });
23139    }, //enter_email_dialog
23140
23141    send_invoice_copy_by_mail: function (invoice_id) {
23142      $dialog = $('<div />', { style: 'text-align:left;' })
23143        .html('Haluatko varmasti lähettää laskukopion postitse?')
23144        .dialog({
23145          autoOpen: true,
23146          modal: true,
23147          resizable: false,
23148          draggable: false,
23149          title: 'Lähetä laskukopio postitse',
23150          beforeClose: function (event, ui) {
23151            event.stopPropagation();
23152          },
23153          buttons: {
23154            Peruuta: function () {
23155              $dialog.dialog('close');
23156            },
23157            'Lähetä laskukopio': function () {
23158              $.ajax({
23159                dataType: 'json',
23160                type: 'POST',
23161                url: '/reskontra/send_invoice_copy_by_mail/',
23162                data: { invoiceId: invoice_id },
23163                beforeSend: function (request) {
23164                  global.showLoadingDialog('Lähetetään laskukopiota...');
23165                },
23166                success: function (responseJSON) {
23167                  if (responseJSON.type == 'success') {
23168                    //Refresh the datatables
23169                    if (pages.iv_laskutus_ja_reskontra.$datatable_iv != null) {
23170                      pages.iv_laskutus_ja_reskontra.$datatable_iv.fnClearTable(0);
23171                      pages.iv_laskutus_ja_reskontra.$datatable_iv.fnDraw();
23172                    }
23173
23174                    if (pages.iv_laskutus_ja_reskontra.$datatable != null) {
23175                      pages.iv_laskutus_ja_reskontra.$datatable.fnClearTable(0);
23176                      pages.iv_laskutus_ja_reskontra.$datatable.fnDraw();
23177                    }
23178
23179                    LaskutusJaReskontra.showInvoiceDialog({
23180                      invoiceId: invoice_id,
23181                    });
23182                  }
23183
23184                  global.show_message(responseJSON);
23185                  global.close_loading_dialog();
23186
23187                  $dialog.dialog('close');
23188                },
23189                error: function (response) {
23190                  global.close_loading_dialog();
23191                  global.show_message($.parseJSON(response.responseText));
23192                },
23193              });
23194            },
23195          },
23196        });
23197    }, //send_invoice_copy_by_mail
23198
23199    send_invoice_copy_by_email: function (invoice_id, email) {
23200      var $form = $('<form />').append(
23201        $('<p />').html('Anna sähköpostiosoite'),
23202        $('<input />', { type: 'text', name: 'toEmail', id: 'toEmail', class: 'text medium' }).val(
23203          email
23204        )
23205      );
23206
23207      $form.submit(function (e) {
23208        //Get the data from the form element
23209        var data = _.object(
23210          $form.serializeArray().map(function (v) {
23211            return [v.name, v.value];
23212          })
23213        );
23214
23215        //Add some extra data
23216        _.extend(data, { invoiceId: invoice_id });
23217
23218        e.preventDefault();
23219
23220        global.show_loading_dialog('Lähetetään laskukopiota...');
23221
23222        $.ajax({
23223          url: '/reskontra/send_invoice_copy_by_email/',
23224          dataType: 'json',
23225          type: 'POST',
23226          data: data,
23227        })
23228          .done(function (responseJSON) {
23229            $dialog.dialog('destroy');
23230            global.show_message(responseJSON);
23231            global.close_loading_dialog();
23232            $dialog.remove();
23233          })
23234          .fail(function (response) {
23235            var responseJSON = $.parseJSON(response.responseText);
23236
23237            global.close_loading_dialog();
23238            global.show_message(responseJSON);
23239          });
23240      });
23241
23242      var $dialog = $('<div />', { style: 'text-align:left;' })
23243        .append($form)
23244        .dialog({
23245          width: 320,
23246          autoOpen: true,
23247          modal: true,
23248          resizable: false,
23249          draggable: false,
23250          beforeClose: function (event, ui) {
23251            event.stopPropagation();
23252          },
23253          close: function () {
23254            $(this).dialog('destroy');
23255            $dialog.remove();
23256          },
23257          title: 'Lähetä laskukopio sähköpostitse',
23258          buttons: {
23259            Peruuta: function () {
23260              $(this).dialog('destroy');
23261              $dialog.remove();
23262            },
23263            'Lähetä lasku': function () {
23264              $form.submit();
23265            },
23266          },
23267        });
23268    }, //send_invoice_copy_by_email
23269
23270    send_invoice_copy_by_sms: function (invoiceId, phone) {
23271      var $form = $('<form />').append(
23272        $('<p />').html('Anna puhelinnumero'),
23273        $('<input />', { type: 'text', name: 'toSms', id: 'toSms', class: 'text medium' }).val(
23274          phone
23275        )
23276      );
23277
23278      $form.submit(function (e) {
23279        e.preventDefault();
23280        var phone = document.getElementById('toSms').value;
23281        var data = {
23282          phone: phone,
23283          invoiceId: invoiceId,
23284        };
23285
23286        global.showLoadingDialog('Lähetetään laskukopiota...');
23287
23288        $.ajax({
23289          url: '/reskontra/send_invoice_copy_by_sms/',
23290          dataType: 'json',
23291          type: 'POST',
23292          data: data,
23293        })
23294          .done(function (responseJSON) {
23295            $dialog.dialog('close');
23296            global.show_message(responseJSON);
23297            global.close_loading_dialog();
23298          })
23299          .fail(function (response) {
23300            var responseJSON = $.parseJSON(response.responseText);
23301            global.close_loading_dialog();
23302            global.show_message(responseJSON);
23303          });
23304      });
23305
23306      var $dialog = $('<div />', { style: 'text-align:left;' })
23307        .append($form)
23308        .dialog({
23309          width: 320,
23310          autoOpen: true,
23311          modal: true,
23312          resizable: false,
23313          draggable: false,
23314          beforeClose: function (event, ui) {
23315            event.stopPropagation();
23316          },
23317          close: function () {
23318            $(this).dialog('destroy');
23319            $(this).remove();
23320          },
23321          title: 'Lähetä laskukopio sms viestinä',
23322          buttons: {
23323            Peruuta: function () {
23324              $(this).dialog('close');
23325            },
23326            'Lähetä lasku': function () {
23327              $form.submit();
23328            },
23329          },
23330        });
23331    },
23332
23333    send_invoice_copy_by_e_invoice: function (
23334      invoice_id,
23335      disableEditing,
23336      eInvoiceAddress,
23337      eInvoiceOperator,
23338      eInvoiceOperators
23339    ) {
23340      var selectEl = $('<select />', {
23341        type: 'text',
23342        name: 'eInvoiceOperator',
23343        id: 'eInvoiceOperator',
23344        class: 'form-control input-sm',
23345      });
23346      $.each(eInvoiceOperators, function (i, obj) {
23347        $(selectEl).append('<option value=' + obj.code + '>' + obj.name + '</option>');
23348      });
23349      selectEl.val(eInvoiceOperator);
23350      selectEl.prop('disabled', disableEditing);
23351
23352      var eInvoiceInputField = $('<input />', {
23353        type: 'text',
23354        name: 'eInvoiceAddress',
23355        id: 'eInvoiceAddress',
23356        class: 'text medium',
23357      }).val(eInvoiceAddress);
23358      eInvoiceInputField.prop('disabled', disableEditing);
23359
23360      var $form = $('<form />').append(
23361        $('<label />').html('Verkkolaskuosoite'),
23362        eInvoiceInputField,
23363        $('<label />').html('Operaattori'),
23364        selectEl
23365      );
23366      if (disableEditing) {
23367        $form.append(
23368          $('<input />', { type: 'hidden', name: 'eInvoiceAddress', id: 'eInvoiceAddress' }).val(
23369            eInvoiceAddress
23370          ),
23371          $('<input />', { type: 'hidden', name: 'eInvoiceOperator', id: 'eInvoiceOperator' }).val(
23372            eInvoiceOperator
23373          )
23374        );
23375      }
23376      $form.submit(function (e) {
23377        //Get the data from the form element
23378        var data = _.object(
23379          $form.serializeArray().map(function (v) {
23380            return [v.name, v.value];
23381          })
23382        );
23383
23384        //Add some extra data
23385        _.extend(data, { invoiceId: invoice_id });
23386
23387        e.preventDefault();
23388
23389        $.ajax({
23390          dataType: 'json',
23391          type: 'POST',
23392          url: '/reskontra/send_invoice_copy_by_e_invoice/',
23393          data: data,
23394          beforeSend: function (request) {
23395            global.showLoadingDialog('Lähetetään laskukopiota...');
23396          },
23397          success: function (responseJSON) {
23398            if (responseJSON.type == 'success') {
23399              //Refresh the datatables
23400              if (pages.iv_laskutus_ja_reskontra.$datatable_iv != null) {
23401                pages.iv_laskutus_ja_reskontra.$datatable_iv.fnClearTable(0);
23402                pages.iv_laskutus_ja_reskontra.$datatable_iv.fnDraw();
23403              }
23404
23405              if (pages.iv_laskutus_ja_reskontra.$datatable != null) {
23406                pages.iv_laskutus_ja_reskontra.$datatable.fnClearTable(0);
23407                pages.iv_laskutus_ja_reskontra.$datatable.fnDraw();
23408              }
23409
23410              LaskutusJaReskontra.showInvoiceDialog({
23411                invoiceId: invoice_id,
23412              });
23413            }
23414
23415            global.show_message(responseJSON);
23416            global.close_loading_dialog();
23417
23418            $dialog.dialog('close');
23419          },
23420          error: function (response) {
23421            global.close_loading_dialog();
23422            global.show_message($.parseJSON(response.responseText));
23423          },
23424        });
23425      });
23426
23427      $dialog = $('<div />', { style: 'text-align:left;' })
23428        .append($form)
23429        .dialog({
23430          autoOpen: true,
23431          modal: true,
23432          resizable: false,
23433          draggable: false,
23434          title: 'Lähetä laskukopio verkkolaskuna',
23435          beforeClose: function (event, ui) {
23436            event.stopPropagation();
23437          },
23438          buttons: {
23439            Peruuta: function () {
23440              $dialog.dialog('close');
23441            },
23442            'Lähetä laskukopio': function () {
23443              $form.submit();
23444            },
23445          },
23446        });
23447    }, //send_invoice_copy_by_e_invoice
23448
23449    getDatatableCsv: function(params, table, selector){
23450
23451      var data = '?' + params.map(function (item) {
23452            return item.name + '=' + encodeURIComponent(item.value);
23453          }).join('&');
23454      var url = 'reskontra/exportDataTable/' + data + '&table=' + table;
23455      $.ajax({
23456        type: 'GET',
23457        contentType: 'application/csv',
23458        url: url,
23459        beforeSend: function(){
23460          $(selector).html(global.$mini_loader).attr('focus', false).attr('disabled', true);
23461        },
23462        success: function(response){
23463          if(response){
23464
23465            // var csvContent = "data:text/csv;charset=utf-8," + response;
23466            var blob = new Blob([response], { type: 'text/csv' });
23467            var url = window.URL.createObjectURL(blob);
23468            var a = document.createElement('a');
23469            a.setAttribute('href', url);
23470            a.setAttribute('download', table + '_datatable_' + Date.now() + '.csv');
23471            a.click();
23472            a.remove();
23473            // var encodedUri = encodeURI(csvContent);
23474            // window.location.href = encodedUri;
23475          }
23476        },
23477        error: function(error){
23478          global.show_message(JSON.parse(error.responseText));
23479        },
23480        complete: function(){
23481          $(selector).text('Vie Csv-tiedostoon').attr('disabled', false);
23482        }
23483      });
23484    },
23485
23486    delete_draft: function (invoice_id) {
23487      var $dialog = global.$dialog;
23488
23489      if ($dialog.hasClass('ui-dialog-content')) {
23490        $dialog.dialog('close');
23491      }
23492
23493      $.ajax({
23494        processData: false,
23495        dataType: 'json',
23496        type: 'GET',
23497        url: 'ajax/delete_invoice_draft/' + invoice_id + '/',
23498        beforeSend: function (request) {
23499          global.show_loading_dialog('Poistetaan lasku...');
23500        },
23501        success: function (responseJSON) {
23502          global.close_loading_dialog();
23503          global.show_message(responseJSON);
23504
23505          if (pages.reskontra.$datatable != null) {
23506            pages.reskontra.$datatable.fnClearTable(0);
23507            pages.reskontra.$datatable.fnDraw();
23508          }
23509
23510          if (kuormakirjat.$datatable !== null) {
23511            kuormakirjat.$datatable.fnReloadAjax();
23512          }
23513        },
23514      });
23515    }, //delete_draft
23516
23517    show_invoice_dialog: function (customer_type) {
23518      var $dialog = global.getGlobalDialogAndEmptyIfHasContent();
23519      var url = 'reskontra/ajax_get_create_invoice/' + customer_type + '/';
23520
23521      dialogs.url = url;
23522
23523      if ($dialog.hasClass('ui-dialog-content')) {
23524        $dialog.dialog('destroy');
23525      }
23526
23527      $dialog.dialog({
23528        autoOpen: true,
23529        width: 860,
23530        height: 600,
23531        title: 'Luo lasku',
23532        modal: true,
23533        resizable: false,
23534        open: function () {
23535          global.show_ajax_loader($dialog);
23536
23537          $.get(url, function (html) {
23538            $dialog.html(html);
23539          });
23540        },
23541        close: function () {
23542          $(this).dialog('destroy');
23543        },
23544      });
23545    },
23546
23547    show_edit_invoice_dialog: function () {},
23548
23549    show_invoice_log: function (invoice_id) {
23550      global.$dialog = $('<div />');
23551      var $dialog = global.$dialog;
23552
23553      if (invoice_id.length > 0) {
23554        $.ajax({
23555          processData: false,
23556          dataType: 'html',
23557          type: 'GET',
23558          url: 'reskontra/get_invoice_log_html/' + invoice_id + '/',
23559          beforeSend: function (request) {
23560            $dialog.dialog({
23561              width: 650,
23562              height: 450,
23563              title: 'Laskun tapahtumaloki',
23564              buttons: {
23565                'Lisää muistiinpano': function () {
23566                  pages.iv_laskutus_ja_reskontra.add_log_item(invoice_id);
23567                },
23568              },
23569              close: function (e) {
23570                e.stopPropagation();
23571                $dialog.dialog('destroy');
23572                $dialog.remove();
23573              },
23574            });
23575            global.show_ajax_loader($dialog);
23576          },
23577          success: function (response) {
23578            $dialog.html(response);
23579            $('.invoiceLogTabs').tabs();
23580            //Add special click handler to show towing record popup 
23580instead of redirecting user to towing record page
23581            $dialog.on('click', 'a.show_towing_record', function (e) {
23582              e.preventDefault();
23583              $dialog.dialog('destroy');
23584              $dialog.remove();
23585              var url = $(this).data('url');
23586              kuormakirjat.show_towing_record(url);
23587            });
23588          },
23589        });
23590      }
23591    }, //show_invoice_log
23592
23593    show_invoice: function (invoice_id, open_sum) {
23594      if (window.LaskutusJaReskontra && window.LaskutusJaReskontra.invoiceDialog) {
23595        window.LaskutusJaReskontra.showInvoiceDialog({
23596          invoiceId: invoice_id,
23597        });
23598      } else {
23599        var $dialog = $('#dialog');
23600
23601        if ($dialog.hasClass('ui-dialog-content')) {
23602          $dialog.dialog('close');
23603        }
23604
23605        $.ajax({
23606          processData: false,
23607          dataType: 'html',
23608          type: 'GET',
23609          url: 'ajax/get_invoice_html/' + invoice_id + '/',
23610          beforeSend: function (request) {
23611            $dialog.dialog({
23612              width: 800,
23613              height: 600,
23614              modal: true,
23615              resizable: false,
23616              title: 'Laskun tiedot',
23617              close: function () {
23618                $dialog.dialog('close');
23619              },
23620            });
23621            global.show_ajax_loader($dialog);
23622          },
23623          success: function (response) {
23624            $dialog.html(response);
23625
23626            $(this).delegate(':button', 'click', function () {
23627              $(this).data({ invoice_id: invoice_id, open_sum: open_sum });
23628            });
23629          },
23630        });
23631      }
23632    }, //show_invoice
23633
23634    show_invoice_2: function (url) {
23635      var $dialog = global.getGlobalDialogAndEmptyIfHasContent();
23636      // console.log('new has content',$dialog.hasClass('ui-dialog-content'))
23637      // if ($dialog.hasClass('ui-dialog-content')) {
23638      //   $dialog.dialog('destroy');
23639      // }
23640
23641      //console.log('show_invoice_2');
23642
23643      $.ajax({
23644        processData: false,
23645        dataType: 'html',
23646        type: 'GET',
23647        url: url,
23648        beforeSend: function (request) {
23649          $dialog.dialog({
23650            width: 800,
23651            height: 600,
23652            modal: true,
23653            resizable: false,
23654            title: 'Laskun tiedot',
23655          });
23656          global.show_ajax_loader($dialog);
23657        },
23658        success: function (response) {
23659          $dialog.html(response);
23660        },
23661      });
23662    }, //show_invoice
23663
23664    show_invoice_by: function (id, get_by) {
23665      var $dialog = global.$dialog;
23666
23667      if ($dialog.hasClass('ui-dialog-content')) {
23668        $dialog.dialog('destroy');
23669      }
23670
23671      $.ajax({
23672        processData: false,
23673        dataType: 'html',
23674        type: 'GET',
23675        url: 'ajax/get_invoice/' + id + '/' + get_by + '/',
23676        beforeSend: function (request) {
23677          $dialog.dialog({
23678            width: 650,
23679            height: 450,
23680            title: 'Laskun tiedot',
23681            modal: true,
23682            resizable: false,
23683          });
23684          global.show_ajax_loader($dialog);
23685        },
23686        success: function (response) {
23687          $dialog.html(response);
23688          var invoice_id = $dialog.find('#invoice_id').val();
23689          var open_sum = $dialog.find('#open_sum').val();
23690
23691          $dialog.delegate(':button', 'click', function () {
23692            $(this).data({ invoice_id: invoice_id, open_sum: open_sum });
23693          });
23694        },
23695      });
23696    }, //show_invoice_by
23697
23698    show_money_transfer_item: function(money_transfer_item_id, source) {
23699      var $dialog = global.$dialog;
23700
23701      if ($dialog.hasClass('ui-dialog-content')) {
23702        $dialog.dialog('destroy');
23703      }
23704
23705      $.ajax({
23706        processData: false,
23707        dataType: 'html',
23708        type: 'GET',
23709        url: 'ajax/get_money_transfer_item/' + money_transfer_item_id + '/' + source,
23710        beforeSend: function(request) {
23711          $dialog.dialog({
23712            width: 800,
23713            height: 600,
23714            modal: true,
23715            resizable: false,
23716            title: 'Tilityksen tiedot',
23717          });
23718          global.show_ajax_loader($dialog);
23719        },
23720        success: function (response) {
23721          $dialog.html(response);
23722        },
23723      });
23724    }, //show_invoice
23725
23726    show_part_payment: function (part_payment_id) {
23727      var $dialog = global.$dialog;
23728
23729      $.ajax({
23730        processData: false,
23731        dataType: 'html',
23732        type: 'GET',
23733        url: 'osamaksu/get_part_payment_dialog/' + part_payment_id + '/',
23734        beforeSend: function (request) {
23735          $dialog.dialog({
23736            width: 800,
23737            height: 600,
23738            modal: true,
23739            resizable: false,
23740            title: 'Osamaksusopimuksen tiedot',
23741          });
23742          global.show_ajax_loader($dialog);
23743        },
23744        success: function (response) {
23745          $dialog.html(response);
23746        },
23747      });
23748    }, //show_part_payment
23749
23750    init_part_payment_dialog: function (part_payment_id) {
23751      $('#confirm_financing')
23752        .button({ icons: { primary: 'ui-icon-check' } })
23753        .on('click', function () {
23754          $('<div></div>')
23755            .html(
23756              'Haluatko varmasti merkitä osamaksusopimuksen rahoituksen ehdot täyttyneeksi? Kun rahoituksen ehdot ovat täyttyneet, on mahdollista luoda tililasku osamaksusopimuksesta'
23757            )
23758            .dialog({
23759              autoOpen: true,
23760              modal: true,
23761              resizable: false,
23762              draggable: false,
23763              title: 'Merkitse rahoituksen ehdot täyttyneeksi',
23764              beforeClose: function (event, ui) {
23765                event.stopPropagation();
23766              },
23767              buttons: {
23768                Peruuta: function () {
23769                  $(this).dialog('close');
23770                },
23771                Merkitse: function () {
23772                  $(this).dialog('close');
23773                  pages.iv_laskutus_ja_reskontra.mark_as_confirmed_for_financing(part_payment_id);
23774                },
23775              },
23776            });
23777        });
23778    },
23779
23780    show_direct_payment: function (direct_payment_id, title) {
23781      var $dialog = global.$dialog;
23782
23783      $.ajax({
23784        processData: false,
23785        dataType: 'html',
23786        type: 'GET',
23787        url: 'ajax/get_direct_payment_dialog/' + direct_payment_id + '/',
23788        beforeSend: function (request) {
23789          $dialog.dialog({
23790            width: 800,
23791            height: 600,
23792            modal: true,
23793            resizable: false,
23794            title: title ? title : 'Korttimaksun tiedot',
23795          });
23796          global.show_ajax_loader($dialog);
23797        },
23798        success: function (response) {
23799          $dialog.html(response);
23800        },
23801      });
23802    }, //show_direct_payment
23803
23804    init_direct_payment_dialog: function () {
23805      $('#creditPayments').on('click', 'a.show_direct_payment', function (e) {
23806        e.preventDefault();
23807        var id = $(e.target).attr('href');
23808        pages.reskontra.show_direct_payment(id);
23809      });
23810      $('#get_payment_terminal_details')
23811        .button({ icons: { primary: 'ui-icon-document' } })
23812        .on('click', function () {
23813          var transactionId = $(this).data('pt-transaction-id');
23814
23815          var dialog = $('<div />', {}).dialog({
23816            autoOpen: true,
23817            modal: true,
23818            width: 500,
23819            position: {
23820              top: 50,
23821            },
23822            hide: {
23823              effect: 'fade',
23824              speed: 3000,
23825            },
23826            resizable: true,
23827            title: 'Maksupäätetapahtuman tiedot',
23828            draggable: true,
23829            buttons: {
23830              Sulje: function () {
23831                dialog.dialog('close');
23832              },
23833            },
23834          });
23835          dialog.html('<p>Ladataan maksupäätetapahtuman tietoja...</p>');
23836          jQuery
23837            .ajax({
23838              type: 'POST',
23839              url: '/payment_devices/getPTTransaction',
23840              data: {
23841                transactionId: transactionId,
23842              },
23843            })
23844            .then(function (data) {
23845              var dialogHtml = '';
23846              if (data.transaction_status === 'success') {
23847                var merchantReceipt = JSON.parse(data.merchant_receipt);
23848                var dateString = data.transaction_time;
23849                var yy = 20 + dateString.substring(0, 2),
23850                  mm = dateString.substring(2, 4),
23851                  dd = dateString.substring(4, 6),
23852                  hh = dateString.substring(6, 8),
23853                  MM = dateString.substring(8, 10);
23854
23855                var transactionTime = dd + '.' + mm + '.' + yy + ' ' + hh + ':' + MM;
23856                var transactionType = data.transaction_type === 'Purchase' ? 'Maksu' : 'Hyvitys';
23857                dialogHtml =
23858                  '<pre><code>' +
23859                  'Tapahtumatyyppi: ' +
23860                  transactionType +
23861                  '\n' +
23862                  'Maksupääte: ' +
23863                  data.terminal_name +
23864                  ' (' +
23865                  data.terminal_id +
23866                  ')\n' +
23867                  'Tapahtuma luotu: ' +
23868                  transactionTime +
23869                  '\n' +
23870                  'Kortin lukutapa: ' +
23871                  data.card_reading_method +
23872                  '\n' +
23873                  merchantReceipt.text +
23874                  '</code></pre>';
23875              } else {
23876                dialogHtml =
23877                  'Maksupäätetapahtuma keskeneräinen, viimeistele maksutapahtuma työmääräyksellä';
23878              }
23879              dialog.html(dialogHtml);
23880            })
23881            .fail(function (err) {
23882              console.log(err);
23883              dialog.html('<p>Maksupäätetapahtuman haku epäonnistui</p>');
23884            });
23885        });
23886    }, // init_direct_payment_dialog
23887
23888    createSATReportDialog: function () {
23889
23890      const html = pages.reskontra.getReportDialog();
23891
23892      var SATReportDialog = $('<div>').html(html).dialog({
23893        dialogClass: 'SATReportDialog',
23894        width: 400,
23895        height: 300,
23896        autoOpen: false,
23897        modal: true,
23898        resizable: false,
23899        draggable: false,
23900        title: 'Luo raportti',
23901        beforeclose: function (event, ui) {
23902          event.stopPropagation();
23903        },
23904        buttons: {
23905          Peruuta: function () {
23906            $(this).dialog('close');
23907          },
23908          'Luo raportti': function () {
23909            var data = pages.reskontra.SATReportData();
23910            pages.reskontra.createSATReport(data);
23911          },
23912        },
23913      });
23914
23915      SATReportDialog.dialog('open');
23916    },
23917
23918
23919
23920    getReportDialog: function (dialog) {
23921
23922      const div = document.createElement('div');
23923
23924      const select = document.createElement('select');
23925      const option = document.createElement('option');
23926      option.textContent = 'valitse';
23927      option.value = "";
23928      select.appendChild(option);
23929      div.appendChild(select);
23930
23931      return div;
23932    },
23933
23934  }, //reskontra
23935
23936  innovoice_ledger: {
23937    $datatable: null,
23938    $ledger_payment_totals_dt: null,
23939    $ledger_payments_dt: null,
23940    paymentsVM: new LedgerPaymentsDialogVm(),
23941
23942    init: function (opts) {
23943      $('#ledger_payments_filter_form select').selectmenu({
23944        style: 'popup',
23945        width: 200,
23946        menuWidth: 200,
23947      });
23948
23949      $('#ledger_payment_totals_filter_form')
23950        .button({ icons: { primary: 'ui-icon-search' } })
23951        .on('change', function () {
23952          pages.innovoice_ledger.$ledger_payment_totals_dt.fnClearTable(0);
23953          pages.innovoice_ledger.$ledger_payment_totals_dt.fnDraw();
23954        });
23955
23956      $('#ledger_payments_filter_form input:checkbox').on('change', function (e) {
23957        // Timeout needed for filters to set before reRender
23958        setTimeout(function () {
23959          pages.innovoice_ledger.$ledger_payments_dt.fnClearTable(0);
23960          pages.innovoice_ledger.$ledger_payments_dt.fnDraw();
23961        }, 1);
23962      });
23963
23964      $('#get_ledger_payments')
23965        .button({ icons: { primary: 'ui-icon-search' } })
23966        .on('click', function () {
23967          pages.innovoice_ledger.$ledger_payments_dt.fnClearTable(0);
23968          pages.innovoice_ledger.$ledger_payments_dt.fnDraw();
23969        });
23970
23971      $('#ledger_payments_filter_form input:checkbox').on('change', function (e) {
23972        var filter = $(this).attr('name');
23973        var isChecked = $(this).is(':checked');
23974        if (filter == 'all' && isChecked) {
23975          $('#ledger_payments_filter_form')
23976            .find('input:checkbox:checked')
23977            .each(function (ind, elem) {
23978              if ($(elem).attr('name') != 'all') {
23979                $(elem).prop('checked', false);
23980              }
23981            });
23982        }
23983
23984        if (filter != 'all' && isChecked) {
23985          $('#ledger_payments_filter_form').find('input[name=all]').prop('checked', false);
23986        }
23987      });
23988
23989      $('#ledger_payment_totals_dt').on('click', 'a.show_ledger_payment_report', function (e) {
23990        e.preventDefault();
23991        var param = $(e.target).attr('href');
23992        var action = $(e.target).attr('class');
23993        var isHandled = $(e.target).attr('data-handled');
23994
23995        switch (action) {
23996          case 'show_ledger_payment_report':
23997            pages.innovoice_ledger.paymentsVM.show_ledger_payment_report(param, isHandled);
23998            break;
23999        }
24000      });
24001
24002      $('#ledger_payments_dt').on(
24003        'click',
24004        'a.show_ledger_payment, a.show_ledger_payment_invoice',
24005        function (e) {
24006          e.preventDefault();
24007
24008          var id = $(e.target).attr('href');
24009          var action = $(e.target).attr('class');
24010
24011          switch (action) {
24012            case 'show_ledger_payment':
24013              pages.innovoice_ledger.paymentsVM.show_ledger_payment(id);
24014              break;
24015            case 'show_ledger_payment_invoice':
24016              pages.reskontra.show_invoice(id);
24017              break;
24018          }
24019        }
24020      );
24021      //if ($('#ledger_payment_totals_dt').size()) {
24022      // on click of <a> --> id = href and action = class
24023
24024      pages.innovoice_ledger.$ledger_payment_totals_dt = $('#ledger_payment_totals_dt').dataTable({
24025        oLanguage: global.dataTablesLanguage,
24026        sPaginationType: 'full_numbers',
24027        bPaginate: true,
24028        iDisplayLength: 10,
24029        bAutoWidth: false,
24030        bJQueryUI: true,
24031        bFilter: true,
24032        bInfo: true,
24033        bProcessing: true,
24034        bServerSide: true,
24035        sAjaxSource: 'innovoice_ledger_payments/get_payment_totals_data/',
24036        aoColumns: [
24037          /** payment_date **/ { bVisible: true, bSortable: true, bSearchable: false },
24038          /** Määrä **/ { bVisible: true, bSortable: false, bSearchable: false },
24039          /** Määrä alisuorituksia **/ { bVisible: true, bSortable: false, bSearchable: false },
24040          /** Määrä ylisuorituksia**/ { bVisible: true, bSortable: false, bSearchable: false },
24041          /** Summa **/ { bVisible: true, bSortable: false, bSearchable: false },
24042          /** Allokoitu **/ { bVisible: true, bSortable: false, bSearchable: false },
24043          /** Allokoimattomat **/ { bVisible: true, bSortable: false, bSearchable: false },
24044          /** Korkotuotto **/ { bVisible: true, bSortable: false, bSearchable: false },
24045          /** Palautukset **/ { bVisible: true, bSortable: false, bSearchable: false },
24046          /** KÄSITELTY **/ { bVisible: true, bSortable: false, bSearchable: false },
24047        ],
24048        aaSorting: [[0, 'desc']],
24049
24050        fnServerParams: function (aoData) {
24051          var month = $('#ledger_payment_totals_filter_form select.month option:selected').attr(
24052            'value'
24053          );
24054          var year = $('#ledger_payment_totals_filter_form select.year option:selected').attr(
24055            'value'
24056          );
24057          var handledStatus = $(
24058            '#ledger_payment_totals_filter_form select.handled option:selected'
24059          ).attr('value');
24060
24061          // filters.push('corporate_chain_invoices');
24062          // $('#corporate-chain-invoices_filter_form input:checkbox:checked').each(function() {
24063          //   filters.push($(this).attr('name'));
24064          // });
24065
24066          aoData.push({ name: 'month', value: month });
24067          aoData.push({ name: 'year', value: year });
24068          aoData.push({ name: 'handledStatus', value: handledStatus });
24069        },
24070
24071        // fnDrawCallback: function() {
24072        //   var month = $('#ledger_payment_totals_filter_form select.month option:selected').html();
24073        //   var year = $('#ledger_payment_totals_filter_form select.year option:selected').html();
24074        //   $('#maksusuoritukset span.month_year').html(month + ', ' + year);
24075        // },
24076
24077        //Called before each row is shown
24078        fnRowCallback: function (nRow, aData, iDisplayIndex) {
24079          var date = aData[0];
24080          var total = aData[1];
24081          var totalUnderpaid = aData[2];
24082          var totalOverpaid = aData[3];
24083          var sum = parseFloat(aData[4]);
24084          var alloc = parseFloat(aData[5]);
24085          var unalloc = parseFloat(aData[6]);
24086          var intrest = parseFloat(aData[7]);
24087          var refunds = parseFloat(aData[8]);
24088          var dateHandled = parseInt(aData[9]);
24089
24090          var tick = '';
24091
24092          if (unalloc > 0) {
24093            $(nRow).addClass('danger');
24094          } else if (totalOverpaid > 0 || totalUnderpaid > 0) {
24095            $(nRow).addClass('warning');
24096          }
24097
24098          if (!!dateHandled) {
24099            tick =
24100              '<span class="glyphicon glyphicon-ok" style="display:block; text-align:center;"></span>';
24101          }
24102
24103          $('td:eq(0)', nRow).html(
24104            '<a href="' +
24105              date +
24106              '" data-handled="' +
24107              dateHandled +
24108              '" class="show_ledger_payment_report" >' +
24109              date +
24110              '</a>'
24111          );
24112          $('td:eq(4)', nRow).html('<span>' + sum.toFixed(2).replace('.', ',') + '</span>');
24113          $('td:eq(5)', nRow).html('<span>' + alloc.toFixed(2).replace('.', ',') + '</span>');
24114          $('td:eq(6)', nRow).html('<span>' + unalloc.toFixed(2).replace('.', ',') + '</span>');
24115          $('td:eq(7)', nRow).html('<span>' + intrest.toFixed(2).replace('.', ',') + '</span>');
24116          $('td:eq(8)', nRow).html('<span>' + refunds.toFixed(2).replace('.', ',') + '</span>');
24117          $('td:eq(9)', nRow).html(tick);
24118
24119          return nRow;
24120        },
24121      });
24122
24123      pages.innovoice_ledger.$ledger_payments_dt = $('#ledger_payments_dt').dataTable({
24124        oLanguage: global.dataTablesLanguage,
24125        sPaginationType: 'full_numbers',
24126        bPaginate: true,
24127        iDisplayLength: 10,
24128        bAutoWidth: false,
24129        bJQueryUI: true,
24130        bFilter: true,
24131        bInfo: true,
24132        bProcessing: true,
24133        bServerSide: true,
24134        sAjaxSource: 'innovoice_ledger_payments/get_payments_data/',
24135        aoColumns: [
24136          /* 'id' */ { bVisible: true, bSearchable: true, bSortable: true },
24137          /* 'entryDate' */ { bVisible: true, bSearchable: true, bSortable: true },
24138          /* 'statusDescription' */ { bVisible: true, bSearchable: false, bSortable: false },
24139          /* 'amount' */ { bVisible: true, bSearchable: false, bSortable: true },
24140          /* 'ref_no' */ { bVisible: true, bSearchable: true, bSortable: true },
24141          /* 'invoiceNumber' */ { bVisible: true, bSearchable: true, bSortable: true },
24142          /* 'payer_name' */ { bVisible: true, bSearchable: true, bSortable: true },
24143          /* 'allocated_at' */ { bVisible: true, bSearchable: false, bSortable: true },
24144          /* 'refunded_at' */ { bVisible: true, bSearchable: false, bSortable: true },
24145          /* 'invoice_id' */ { bVisible: false, bSearchable: false, bSortable: false },
24146          /* 'type' */ { bVisible: false, bSearchable: false, bSortable: false },
24147          /* 'original_payment_id' */ { bVisible: false, bSearchable: true, bSortable: false },
24148        ],
24149        aaSorting: [[0, 'desc']],
24150
24151        fnServerParams: function (aoData) {
24152          var month = $('#ledger_payments_filter_form select.month option:selected').attr('value');
24153          var year = $('#ledger_payments_filter_form select.year option:selected').attr('value');
24154
24155          var filters = [];
24156
24157          filters.push('ledger_payments');
24158
24159          $('#ledger_payments_filter_form input:checkbox:checked').each(function () {
24160            filters.push($(this).attr('name'));
24161          });
24162
24163          aoData.push({ name: 'month', value: month });
24164          aoData.push({ name: 'year', value: year });
24165          aoData.push({ name: 'filters', value: filters });
24166        },
24167
24168        fnDrawCallback: function () {
24169          var month =
24170            $('#ledger_payments_filter_form select.month option:selected').html() ===
24171            '-- Kaikki kuukaudet --'
24172              ? 'Kaikki'
24173              : $('#ledger_payments_filter_form select.month option:selected').html();
24174          var year =
24175            $('#ledger_payments_filter_form select.year option:selected').html() ===
24176            '-- Kaikki vuodet --'
24177              ? 'Kaikki'
24178              : $('#ledger_payments_filter_form select.year option:selected').html();
24179          $('#maksusuoritukset span.month_year').html(month + ', ' + year);
24180        },
24181
24182        //Called before each row is shown
24183        fnRowCallback: function (nRow, aData, iDisplayIndex) {
24184          var id = aData[0];
24185          var entryDate = aData[1];
24186          var status = aData[2];
24187          var amount = aData[3];
24188          var ref_no = aData[4];
24189          var invoice_no = aData[5] ? aData[5] : '';
24190          var refund = aData[8];
24191          var invoiceId = aData[9] ? aData[9] : '';
24192          var type = aData[10];
24193          var originalPaymentId = aData[11];
24194          var isInterest = '';
24195          if (parseInt(type) === 2) {
24196            isInterest = ' (Korko)';
24197          }
24198
24199          var displayId = originalPaymentId ? originalPaymentId : id;
24200
24201          $('td:eq(0)', nRow).html(
24202            '<a href="' + id + '" class="show_ledger_payment" >' + displayId + '</a>'
24203          );
24204          $('td:eq(2)', nRow).html('<span>' + status + isInterest + '</span>');
24205          $('td:eq(3)', nRow).html('<span>' + amount + '</span>');
24206          $('td:eq(5)', nRow).html(
24207            '<a href="' +
24208              invoiceId +
24209              '" class="show_ledger_payment_invoice" >' +
24210              invoice_no +
24211              '</a>'
24212          );
24213
24214          return nRow;
24215        },
24216      });
24217    },
24218  },
24219
24220  tools: {
24221    cache: {},
24222    lastXhr: '',
24223    $datatable: '',
24224
24225    init: function () {
24226      $('#tools_tabs').tabs();
24227    },
24228    init_stats: function () {
24229      $('#stats_tabs').tabs();
24230    },
24231  },
24232
24233  omat_tiedot: {
24234    init: function (user_id) {
24235      $('#omat_tiedot_tabs').tabs();
24236      $('body').delegate('#omat_tiedot_tabs', 'tabsshow', function (ev, ui) {
24237        var rex = /^[^#]*#/;
24238        var hash = ui.tab.href.replace(rex, '');
24239        window.location.hash = '#'.concat(hash);
24240      });
24241
24242      if ($('#company_users_tabs').length) {
24243        $('#company_users_tabs').tabs();
24244        $('body').delegate('#company_users_tabs', 'tabsshow', function (ev, ui) {
24245          var rex = /^[^#]*#/;
24246          var hash = ui.tab.href.replace(rex, '');
24247          window.location.hash = '#'.concat(hash);
24248        });
24249      }
24250
24251      $('#change_password')
24252        .button({})
24253        .on('click', function () {
24254          pages.omat_tiedot.change_password(user_id);
24255        });
24256
24257      $('button.save').button({ icons: { primary: 'ui-icon-disk' } });
24258      $('button#download_gdpr_disclaimer')
24259        .button({ icons: { primary: 'ui-icon-document' } })
24260        .on('click', function () {
24261          w = window.open();
24262          w.location = 'omat_tiedot/tietosuojaseloste/';
24263        });
24264
24265      $('#add_phone')
24266        .button({ icons: { primary: 'ui-icon-plusthick' }, text: true })
24267        .on('click', function () {
24268          pages.omat_tiedot.add_phone();
24269        });
24270
24271      $('.remove_phone')
24272        .button({ icons: { primary: 'ui-icon-trash' }, text: true })
24273        .on('click', function () {
24274          pages.omat_tiedot.remove_phone($(this));
24275        });
24276
24277      $('#omat_tiedot_form')
24278        .find('button[type=submit]')
24279        .on('click', function (e) {
24280          e.preventDefault();
24281
24282          var $form = $('#omat_tiedot_form');
24283
24284          console.log('omat_tiedot_form clicked');
24285
24286          if (!pages.omat_tiedot.validateSave($form)) {
24287            return false;
24288          }
24289
24290          $form.ajaxSubmit({
24291            type: 'post',
24292            dataType: 'json',
24293            //show the loading message
24294            beforeSubmit: function () {
24295              global.show_loading_dialog('Päivitetään tietoja...');
24296            },
24297            success: function (responseJSON, statusText, xhr, $form) {
24298              
24299              console.log('response', responseJSON)
24300              
24301              if (responseJSON.type === 'success') {
24302                global.show_message(responseJSON);
24303                global.close_loading_dialog();
24304
24305                if (typeof changeSmsInterfaceUI === "function") {
24306                  changeSmsInterfaceUI(responseJSON.data);
24307                }
24308
24309                if (typeof updateNewlyAddedUsers === "function") {
24310                  updateNewlyAddedUsers(responseJSON.data);
24311                }
24312                
24313              } else {
24314                global.show_message(responseJSON);
24315                global.close_loading_dialog();
24316              }
24317            },
24318            error: function (data) {
24319              global.close_loading_dialog();
24320              global.show_message($.parseJSON(data.responseText));
24321            },
24322          });
24323        });
24324
24325      /*
24326      $('#omat_tiedot_form').validate({
24327        debug: true,
24328        ignore: ':button',
24329
24330        errorPlacement: function(error, element) {},
24331
24332        invalidHandler: function() {
24333          var msgJSON = {};
24334          msgJSON.text = 'Ole hyvä ja täytä kaikki pakolliset kentät';
24335          msgJSON.type = 'error';
24336          global.show_message(msgJSON);
24337        },
24338
24339        submitHandler: function(form) {
24340          $(form).ajaxSubmit({
24341            type: 'post',
24342            dataType: 'json',
24343            //show the loading message
24344            beforeSubmit: function() {
24345              global.show_loading_dialog('Päivitetään tietoja...');
24346            },
24347
24348            success: function(responseJSON, statusText, xhr, $form) {
24349              if (responseJSON.type === 'success') {
24350                global.show_message(responseJSON);
24351                global.close_loading_dialog();
24352              } else {
24353                global.show_message(responseJSON);
24354                global.close_loading_dialog();
24355              }
24356            },
24357            error: function(data) {
24358              global.close_loading_dialog();
24359              global.show_message($.parseJSON(data.responseText));
24360            },
24361          });
24362          return false;
24363        },
24364      });
24365
24366      */
24367
24368      $('button#change_bank_account_number')
24369        .on('click', function () {
24370          $('div#bank-account-dialog').dialog({
24371            autoOpen: true,
24372            modal: true,
24373            width: 350,
24374            height: 240,
24375            position: {
24376              top: 50,
24377            },
24378            hide: {
24379              effect: 'fade',
24380              speed: 3000,
24381            },
24382            resizable: true,
24383            draggable: true,
24384            title: 'Vaihda tilinumero',
24385            buttons: {
24386              Peruuta: function () {
24387                $(this).dialog('close');
24388              },
24389              Siirry: function () {
24390                pages.omat_tiedot.sendKycForm();
24391              },
24392            },
24393          });
24394        });
24395      
24396      $('button#sign_kredinor_contracts').button({ icons: { primary: 'ui-icon-pencil' } }).on('click',function () {
24397        pages.omat_tiedot.signKredinorContracts();
24398      });
24399      $('button#edit_kyc_form')
24400        .button({ icons: { primary: 'ui-icon-pencil' } })
24401        .on('click', function () {
24402          pages.omat_tiedot.sendKycForm('edit_form');
24403        })
24404      
24405      $('button#edit_contact_person')
24406        .button({ icons: { primary: 'ui-icon-pencil' } })
24407        .on('click', function () {
24408          
24409          $('div#contact-person-dialog').dialog({
24410            autoOpen: true,
24411            modal: true,
24412            width: 350,
24413            height: 240,
24414            hide: {
24415              effect: 'fade',
24416              speed: 3000,
24417            },
24418            resizable: true,
24419            draggable: true,
24420            title: 'Muokkaa sopimusyhteyshenkilöä',
24421            buttons: {
24422              Peruuta: function () {
24423                $(this).dialog('close');
24424              },
24425              Siirry: function () {
24426                pages.omat_tiedot.sendKycForm('edit_contact_person');
24427              },
24428            },
24429          });
24430        });
24431    },
24432
24433    change_password: function (user_id) {
24434      var $form = $('<form />', {
24435        method: 'POST',
24436        action: '/omat_tiedot/change_password/' + user_id,
24437      }).append(
24438        $('<fieldset />', { class: 'fs-invisible' }).append(
24439          $('<ol />', {}).append(
24440            $('<li />', {}).append(
24441              $('<label />', {}).html('Nykyinen salasanasi'),
24442              $('<input />', {
24443                type: 'password',
24444                name: 'old_password',
24445                id: 'old_password',
24446                class: 'text medium',
24447              })
24448            ),
24449
24450            $('<li />', {}).append(
24451              $('<label />', {}).html('Uusi salasana'),
24452              $('<input />', {
24453                type: 'password',
24454                name: 'new_password',
24455                id: 'new_password',
24456                class: 'text medium',
24457              })
24458            ),
24459
24460            $('<li />', {}).append(
24461              $('<label />', {}).html('Vahvista uusi salasana'),
24462              $('<input />', {
24463                type: 'password',
24464                name: 'confirm_password',
24465                id: 'confirm_password',
24466                class: 'text medium',
24467              })
24468            )
24469          )
24470        )
24471      );
24472
24473      var $dialog = $('<div />', { style: 'text-align:left;' })
24474        .append($form)
24475        .dialog({
24476          width: 400,
24477          autoOpen: true,
24478          modal: true,
24479          resizable: false,
24480          draggable: false,
24481          beforeClose: function (event, ui) {
24482            event.stopPropagation();
24483          },
24484          title: 'Salasanan vaihto',
24485          buttons: {
24486            Peruuta: function () {
24487              $(this).dialog('close');
24488            },
24489            'Vaihda salasana': function () {
24490              $form.ajaxSubmit({
24491                type: 'post',
24492                dataType: 'json',
24493                //show the loading message
24494                beforeSubmit: function () {
24495                  global.show_loading_dialog('Vaihdetaan salasanaa...');
24496                },
24497
24498                success: function (responseJSON, statusText, xhr, $form) {
24499                  $dialog.dialog('close');
24500                  global.show_message(responseJSON);
24501                  global.close_loading_dialog();
24502                },
24503                error: function (data) {
24504                  global.show_message($.parseJSON(data.responseText));
24505                  global.close_loading_dialog();
24506                },
24507              }); //ajaxSubmit
24508            },
24509          },
24510        });
24511    }, //change_password
24512
24513    add_car: function ($cars) {
24514      $num = $cars.find('tbody tr').size();
24515      var company_id = $cars
24516        .parents('.company')
24517        .find('input:hidden')
24518        .filter('[name=company_id]')
24519        .val();
24520
24521      if (typeof company_id == 'undefined') {
24522        var new_id = $cars.parents('.company').data('new_id');
24523        company_id = 'new_' + new_id;
24524      }
24525
24526      $remove_btn = $(
24527        '<button type="button" class="remove_car" style="float:right;">Poista</button>'
24528      )
24529        .button({ icons: { primary: 'ui-icon-trash' }, text: true })
24530        .on('click', function (e) {
24531          e.stopPropagation();
24532          $wrapper = $(this).parent().parent();
24533          $('<div />')
24534            .html(
24535              '<p style="font-weight:bold;"><span class="ui-icon ui-icon-alert" style="float:left; margin:0 7px 20px 0; "></span>Haluatko varmasti poistaa kyseisen auton?</p>'
24536            )
24537            .dialog({
24538              resizable: false,
24539              height: 180,
24540              width: 340,
24541              title: 'Poista auto',
24542              modal: true,
24543              buttons: {
24544                Ei: function () {
24545                  $(this).dialog('close');
24546                },
24547                Kyllä: function () {
24548                  $(this).dialog('close');
24549
24550                  $wrapper.hide('highlight', function () {
24551                    $(this).remove();
24552                  });
24553                },
24554              },
24555            });
24556        });
24557
24558      $car_data = $('<tr />', { class: 'car', style: 'width:900px;' }).append(
24559        $('<td />').append(
24560          '<input type="text" name="cars[' +
24561            company_id +
24562            '][new_' +
24563            $num +
24564            '][phone]" id="cars[' +
24565            $num +
24566            '][phone]" class="text medium-small required" />'
24567        ),
24568        $('<td />').append(
24569          '<input type="text" name="cars[' +
24570            company_id +
24571            '][new_' +
24572            $num +
24573            '][car_nr]" id="cars[' +
24574            $num +
24575            '][car_nr]" class="text small required" />'
24576        ),
24577        $('<td />').append(
24578          '<input type="text" name="cars[' +
24579            company_id +
24580            '][new_' +
24581            $num +
24582            '][stationary_position]" id="cars[' +
24583            $num +
24584            '][stationary_position]" class="text small required"  />'
24585        ),
24586        $('<td />', {}).append($remove_btn)
24587      );
24588
24589      $cars.prepend($car_data);
24590    }, //add_car
24591
24592    add_phone: function () {
24593      $num = $('#phones tbody tr').size();
24594
24595      $remove_btn = $('<button />', { type: 'button' })
24596        .html('Poista')
24597        .button({ icons: { primary: 'ui-icon-trash' }, text: true })
24598        .on('click', function (e) {
24599          e.stopPropagation();
24600          pages.omat_tiedot.remove_phone(e.target);
24601        });
24602
24603      $phone_data = $('<tr />', { class: 'phone', style: 'width:900px;' }).append(
24604        $('<td />').append(
24605          '<input type="text" name="sms_interface[' +
24606            ($num + 10) +
24607            '][msisdn]" id="sms_interface[' +
24608            ($num + 10) +
24609            '][msisdn]" class="text small required" />'
24610        ),
24611        $('<td />').append(
24612          '<input type="text" name="sms_interface[' +
24613            ($num + 10) +
24614            '][sales_person]" id="sms_interface[' +
24615            ($num + 10) +
24616            '][sales_person]" class="text small" />'
24617        ),
24618        $('<td />').append(
24619          '<input type="text" name="sms_interface[' +
24620            ($num + 10) +
24621            '][product]" id="sms_interface[' +
24622            ($num + 10) +
24623            '][product]" class="text medium-small" />'
24624        ),
24625        $('<td />', {}).append($remove_btn)
24626      );
24627
24628      //$phone_data.append();
24629      $('#phones').prepend($phone_data);
24630    },
24631
24632    add_company: function () {
24633      var $userinfo = $('#companies .company').eq(0),
24634        contact_info = [],
24635        $num = 0;
24636
24637      if (typeof $userinfo[0] !== 'undefined') {
24638        var $input_fields = $userinfo.find('input');
24639        contact_info.contact_person = $input_fields.filter('[name*=contact_person]').val();
24640        contact_info.contact_phone = $input_fields.filter('[name*=phone]').val();
24641        contact_info.contact_address = $input_fields.filter('[name*=address]').val();
24642        contact_info.contact_zipcode = $input_fields.filter('[name*=zipcode]').val();
24643        contact_info.contact_city = $input_fields.filter('[name*=city]').val();
24644      }
24645
24646      $num = '' + $('#companies .company').size();
24647
24648      if (typeof contact_info.contact_person === 'undefined') {
24649        contact_info.contact_person = '';
24650        contact_info.contact_phone = '';
24651        contact_info.contact_address = '';
24652        contact_info.contact_zipcode = '';
24653        contact_info.contact_city = '';
24654      }
24655
24656      $remove_company_btn = $('<button />', {
24657        type: 'button',
24658        style: 'float:right; padding:0px 5px;',
24659      })
24660        .html('Poista yritys')
24661        .button({ icons: { primary: 'ui-icon-trash' }, text: true })
24662        .on('click', function (e) {
24663          e.stopPropagation();
24664          $wrapper = $(this).parents('.company');
24665
24666          $('<div />', {})
24667            .html(
24668              '<p style="font-weight:bold;"><span class="ui-icon ui-icon-alert" style="float:left; margin:0 7px 20px 0; "></span>Haluatko varmasti poistaa kyseisen yrityksen?</p>'
24669            )
24670            .dialog({
24671              resizable: false,
24672              height: 200,
24673              width: 300,
24674              title: 'Poista yritys',
24675              modal: true,
24676              buttons: {
24677                Ei: function () {
24678                  $(this).dialog('close');
24679                },
24680                Kyllä: function () {
24681                  $(this).dialog('close');
24682
24683                  $wrapper.hide('highlight', function () {
24684                    $(this).remove();
24685                  });
24686                },
24687              },
24688            });
24689        });
24690
24691      $company_data = $('<div />', { class: 'company' }).append(
24692        $('<fieldset />', {})
24693          .append(
24694            $('<legend>Yritys</legend>'),
24695            $('<div />', { class: 'buttons', style: 'display:block; float:right; ' }),
24696            $('<div />', { style: 'width:280px; float:left;' }).append(
24697              $('<ol />').append(
24698                $('<li><label for="company_name">Yrityksen nimi:</label></li>').append(
24699                  $(
24700                    '<input type="text"  name="company[new_' +
24701                      $num +
24702                      '][company_name]" id="company[new_' +
24703                      $num +
24704                      '][company_name]" class="text medium-small required"  />'
24705                  )
24706                ),
24707                $('<li><label for="business_id">Y-tunnus:</label></li>').append(
24708                  '<input type="text" name="company[new_' +
24709                    $num +
24710                    '][business_id]" id="compamy[new_' +
24711                    $num +
24712                    '][business_id]" class="text medium-small required" />'
24713                ),
24714                $('<li><label for="iban">IBAN:</label>').append(
24715                  '<input type="text" name="company[new_' +
24716                    $num +
24717                    '][iban]" id="company[new_' +
24718                    $num +
24719                    '][iban]" class="text medium-small" />'
24720                ),
24721                $('<li><label for="bic">BIC:</label></li>').append(
24722                  '<input type="text" name="company[new_' +
24723                    $num +
24724                    '][bic]" id="company[new_' +
24725                    $num +
24726                    '][bic]" class="text medium-small" />'
24727                )
24728              )
24729            )
24730          )
24731          .append(
24732            $('<div />', { class: 'right', style: 'float:left;' }).append(
24733              $('<ol />').append(
24734                $('<li><label for="contact_person">Yhteyshenkilö:</label></li>').append(
24735                  '<input type="text" name="company[new_' +
24736                    $num +
24737                    '][contact_person]" id="company[new_' +
24738                    $num +
24739                    '][contact_person]" class="text medium-small required" value="' +
24740                    contact_info.contact_person +
24741                    '" />'
24742                ),
24743                $('<li><label for="phone">Puhelin:</label></li>').append(
24744                  '<input type="text" name="company[new_' +
24745                    $num +
24746                    '][phone]" id="company[new_' +
24747                    $num +
24748                    '][phone]" class="text medium-small" value="' +
24749                    contact_info.contact_phone +
24750                    '" />'
24751                ),
24752                $('<li><label for="address">Osoite:</label>').append(
24753                  '<input type="text" name="company[new_' +
24754                    $num +
24755                    '][address]" id="company[new_' +
24756                    $num +
24757                    '][address]" class="text medium-small required" value="' +
24758                    contact_info.contact_address +
24759                    '" />'
24760                ),
24761                $('<li><label for="zipcode">Postinumero:</label></li>').append(
24762                  '<input type="text" name="company[new_' +
24763                    $num +
24764                    '][zipcode]" id="company[new_' +
24765                    $num +
24766                    '][zipcode]" class="text medium-small required"  value="' +
24767                    contact_info.contact_zipcode +
24768                    '"/>'
24769                ),
24770                $('<li><label for="city">Kaupunki:</label></li>').append(
24771                  '<input type="text"  name="company[new_' +
24772                    $num +
24773                    '][city]" id="company[new_' +
24774                    $num +
24775                    '][city]" class="text medium-small required" value="' +
24776                    contact_info.contact_city +
24777                    '" />'
24778                ),
24779                $(
24780                  '<label for="company_id"><input type="hidden" name="company[new_' +
24781                    $num +
24782                    '][id]" id="company[new_' +
24783                    $num +
24784                    '][id]" value="0" /></label>'
24785                ),
24786                $(
24787                  '<label for="company_id"><input type="hidden" name="company[new_' +
24788                    $num +
24789                    '][new_id]" id="company[new_' +
24790                    $num +
24791                    '][new_id]" value="new_' +
24792                    $num +
24793                    '" /></label>'
24794                )
24795              )
24796            )
24797          )
24798          .append(
24799            $('<div />', { style: 'clear:both;' })
24800              .append(
24801                $('<h3 />', { style: 'margin:0; padding:0;' }).html('Autot'),
24802                $('<table />', { id: 'cars', style: 'width:680px;' }).append(
24803                  $('<thead />').append(
24804                    $('<tr />').append(
24805                      $('<th />').html('Autopuhelimen nro.'),
24806                      $('<th />').html('Rekisterinumero'),
24807                      $('<th />').html('Järjestysnumero'),
24808                      $('<th />').html('Asemapaikka')
24809                    )
24810                  )
24811                )
24812              )
24813              .append(
24814                $('<button />', {
24815                  type: 'button',
24816                  style: 'margin:0px 10px 10px 10px;',
24817                  class: 'add_car',
24818                })
24819                  .html('Lisää auto')
24820                  .button({ icons: { primary: 'ui-icon-plusthick' } })
24821                  .on('click', function (e) {
24822                    $btn = $(e.currentTarget);
24823                    dialogs.account_card.innotaxi.add_car($btn.parent().find('#cars'));
24824                  })
24825              )
24826          )
24827      );
24828
24829      //<button type="button" style="margin:0px 10px 10px 10px;" id="add_car">Lisää uusi auto</button>
24830
24831      $('#companies').prepend($company_data.data({ new_id: $num }));
24832      $remove_company_btn.prependTo($company_data.find('div.buttons'));
24833
24834      $company_data.find('.add_car').trigger('click');
24835
24836      $('#companies').delegate('[id*="company_name"]', 'keyup', function () {
24837        $(this).parents('fieldset').find('legend').html($(this).val());
24838      });
24839    }, //add_company
24840
24841    remove_phone: function (btn) {
24842      $wrapper = $(btn).parent().parent();
24843
24844      $('<div />')
24845        .html(
24846          '<p style="font-weight:bold;"><span class="ui-icon ui-icon-alert" style="float:left; margin:0 7px 20px 0; "></span>Haluatko varmasti poistaa kyseisen puhelimen?</p>'
24847        )
24848        .dialog({
24849          resizable: false,
24850          height: 180,
24851          width: 340,
24852          title: 'Poista SMS-käyttöliittymä',
24853          modal: true,
24854          buttons: {
24855            Ei: function () {
24856              $(this).dialog('close');
24857            },
24858            Kyllä: function () {
24859              $(this).dialog('close');
24860
24861              var sms_interface_id = $wrapper.find('input:hidden').filter('[name*=id]').val();
24862
24863              if (sms_interface_id != '' && typeof sms_interface_id != 'undefined') {
24864                $.ajax({
24865                  url: 'ajax/delete_sms_interface/' + sms_interface_id + '/',
24866                  type: 'post',
24867                  dataType: 'json',
24868                  success: function (responseJSON, textStatus, jqXHR) {
24869                    if (responseJSON.type == 'success') {
24870                      $wrapper.hide('highlight', function () {
24871                        $(this).remove();
24872                      });
24873                    } else {
24874                      global.show_message(responseJSON);
24875                    }
24876                  },
24877                });
24878              } else {
24879                $wrapper.hide('highlight', function () {
24880                  $(this).remove();
24881                });
24882              }
24883            },
24884          },
24885        });
24886    },
24887
24888    remove_car: function (btn) {
24889      $wrapper = $(btn).parent().parent();
24890
24891      $('<div />')
24892        .html(
24893          '<p style="font-weight:bold;"><span class="ui-icon ui-icon-alert" style="float:left; margin:0 7px 20px 0; "></span>Haluatko varmasti poistaa kyseisen auton?</p>'
24894        )
24895        .dialog({
24896          resizable: false,
24897          height: 180,
24898          width: 340,
24899          title: 'Poista Auto',
24900          modal: true,
24901          buttons: {
24902            Ei: function () {
24903              $(this).dialog('close');
24904            },
24905            Kyllä: function () {
24906              $(this).dialog('close');
24907
24908              var car_id = $wrapper.find('input:hidden').filter('[name*=id]').val();
24909
24910              if (car_id !== '' && typeof car_id !== 'undefined') {
24911                $.ajax({
24912                  url: 'ajax/delete_car/' + car_id + '/',
24913                  type: 'post',
24914                  dataType: 'json',
24915                  success: function (responseJSON, textStatus, jqXHR) {
24916                    if (responseJSON.type === 'success') {
24917                      $wrapper.hide('highlight', function () {
24918                        $(this).remove();
24919                      });
24920                    } else {
24921                      global.show_message(responseJSON);
24922                    }
24923                  },
24924                });
24925              } else {
24926                $wrapper.hide('highlight', function () {
24927                  $(this).remove();
24928                });
24929              }
24930            },
24931          },
24932        });
24933    },
24934
24935    validateSave: function ($form) {
24936      var msgJSON = {},
24937        errors = [];
24938      msgJSON.text = 'Ole hyvä ja täytä kaikki pakolliset kentät';
24939      msgJSON.type = 'error';
24940
24941      // Validate required fields on current page
24942      // Get all fields that have required class on it
24943      var $inputs = $form.find('fieldset:enabled input.required').not(':disabled');
24944
24945      $inputs.each(function (index, elem) {
24946        if ($(elem).val() === '') {
24947          $(elem).addClass('error');
24948
24949          console.log('Field caused validation errors:', index, elem);
24950          errors.push('Ole hyvä ja täytä kaikki pakolliset tiedot');
24951        } else {
24952          if ($(elem).hasClass('error')) {
24953            $(elem).removeClass('error');
24954          }
24955        }
24956      });
24957
24958      if (errors.length > 0) {
24959        global.show_message(msgJSON);
24960        return false;
24961      }
24962
24963      return true;
24964    },
24965
24966    sendKycForm: function (type) {
24967      type = type || 'edit_bank_account';
24968      $.ajax({
24969        url: '/omat_tiedot/send_kyc_form',
24970        data: { type: type },
24971        type: 'POST',
24972        dataType: 'application/json',
24973        beforeSend: function () {
24974          global.show_loading_dialog('Lähetetään...');
24975        },
24976        success: function () {
24977          global.close_loading_dialog();
24978        },
24979        error: function () {
24980          global.close_loading_dialog();
24981        },
24982        complete: function (response) {
24983          console.log('complete response', JSON.parse(response.responseText).text);
24984          var json = JSON.parse(response.responseText);
24985
24986          switch (json.type) {
24987            case 'success':
24988              console.log('url', json.data.url);
24989              $('.info-text').fadeOut();
24990              //$('.response-text').text(json.text);
24991              //$('.response-text').fadeIn();
24992              window.location.href = json.data.url;
24993              $('.ui-dialog .ui-dialog-buttonpane').find('button:last').hide();
24994              $('.ui-dialog .ui-dialog-buttonpane').find('button:first').text('Sulje');
24995              break;
24996            case 'error':
24997              global.show_message(json);
24998              break;
24999          }
25000        },
25001      });
25002    },
25003
25004    signKredinorContracts: function() {
25005      $.ajax({
25006        url: '/omat_tiedot/sign_contract',
25007        type: 'GET',
25008        dataType: 'application/json',
25009        beforeSend: function () {
25010          global.show_loading_dialog('Siirrytään allekirjoitukseen...');
25011        },
25012        success: function(){
25013          global.close_loading_dialog();
25014        },
25015        error: function(){
25016          global.close_loading_dialog();
25017        },
25018        complete: function (response) {
25019          console.log('signKredinorContracts response', JSON.parse(response.responseText).text);
25020          var json = JSON.parse(response.responseText);
25021
25022          switch (json.type) {
25023            case 'success':
25024              console.log('url', json.data.url);
25025              $('.info-text').fadeOut();
25026              //$('.response-text').text(json.text);
25027              //$('.response-text').fadeIn();
25028              window.location.href = json.data.url;
25029              $('.ui-dialog .ui-dialog-buttonpane').find('button:last').hide();
25030              $('.ui-dialog .ui-dialog-buttonpane').find('button:first').text('Sulje');
25031              break;
25032            case 'error':
25033              global.show_message(json);
25034              break;
25035          }
25036        }
25037      });
25038    }
25039  }
25040}; //pages
25041
25042var dialogs = {
25043  url: '',
25044
25045  refresh: function () {
25046    global.show_ajax_loader(global.$dialog);
25047    $.get(dialogs.url, function (data) {
25048      global.$dialog.html(data);
25049    });
25050  },
25051};
25052
25053global.addressFormatting = function (text) {
25054  var newText = text;
25055  //array of find replaces
25056  var findreps = [
25057    { find: /^([^\:]+) \: /g, rep: '<span class="ui-selectmenu-item-header">$1</span>' },
25058    { find: /([^\|><]+) \| /g, rep: '<span class="ui-selectmenu-item-content">$1</span>' },
25059    { find: /([^\|><\(\)]+) (\()/g, rep: '<span class="ui-selectmenu-item-content">$1</span>$2' },
25060    { find: /([^\|><\(\)]+)$/g, rep: '<span class="ui-selectmenu-item-content">$1</span>' },
25061    { find: /(\([^\|><]+\))$/g, rep: '<span class="ui-selectmenu-item-footer">$1</span>' },
25062  ];
25063
25064  for (var i in findreps) {
25065    newText = newText.replace(findreps[i].find, findreps[i].rep);
25066  }
25067  return newText;
25068};
25069
25070var lasku = lasku || {};
25071lasku.asiakasrekisterista = lasku.asiakasrekisterista || {};
25072
25073lasku.asiakasrekisterista.init = function () {
25074  $('#search_from_customer_registry_form').submit(function () {
25075    var customer_type = $('#change_customer_type')
25076        .find('input:radio[name=customer_type]:checked')
25077        .val(),
25078      customer_id;
25079
25080    //if customer type is 0 = person, 1 = company
25081    if (customer_type == 0) {
25082      customer_id = $('#person_list option:selected').val();
25083    }
25084
25085    if (customer_type == 1) {
25086      customer_id = $('#company_list option:selected').val();
25087    }
25088
25089    customer_data = lasku.asiakasrekisterista.get_customer_data(customer_id);
25090    return false;
25091  });
25092
25093  $('#change_customer_type')
25094    .find('input:radio[name=customer_type]')
25095    .change(function (e) {
25096      if ($(e.target).val() == 0) {
25097        $('#person').show();
25098        $('#company').hide();
25099      }
25100
25101      if ($(e.target).val() == 1) {
25102        $('#person').hide();
25103        $('#company').show();
25104      }
25105    });
25106
25107  $('#person_list').selectmenu({
25108    width: 200,
25109    menuWidth: 350,
25110    format: global.addressFormatting,
25111    style: 'dropdown',
25112    maxHeight: 300,
25113  });
25114
25115  $('#company_list').selectmenu({
25116    width: 200,
25117    menuWidth: 350,
25118    format: global.addressFormatting,
25119    style: 'dropdown',
25120    maxHeight: 300,
25121  });
25122
25123  $('#get_customer_data').button({ icons: { primary: 'ui-icon-search' } });
25124};
25125
25126lasku.asiakasrekisterista.get_customer_data = function (customer_id) {
25127  //console.log('lasku.asiakasrekisterista.get_customer_data');
25128
25129  //console.log($('#person_list').find('option:selected').val());
25130  /*
25131		var customer_type = $('#change_customer_type').find('input:radio[name=customer_type]:checked').val(), customer_id;
25132
25133		//if customer type is 0 = person, 1 = company
25134		if(customer_type == 0){
25135			customer_id = $('#person_list option:selected').val();
25136		}
25137
25138		if(customer_type == 1){
25139			customer_id = $('#company_list option:selected').val();
25140		}
25141		*/
25142
25143  $.getJSON('ajax/get_customer_json/' + customer_id, function (data, textStatus, jqXHR) {
25144    var customer_info;
25145
25146    if (customer_type == 0) {
25147      $('.company').remove();
25148      $('#company_info').hide();
25149      $customer_info = $('#person_info');
25150      $customer_info.find("input[name='customer[firstname]']").val(data.firstname);
25151      $customer_info.find("input[name='customer[lastname]']").val(data.lastname);
25152      $customer_info.find("input[name='customer[ssn]']").val(data.ssn);
25153    }
25154
25155    if (customer_type == 1) {
25156      $('.person').remove();
25157      $('#person_info').hide();
25158      $customer_info = $('#company_info');
25159      $customer_info.find("input[name='customer[company_name]']").val(data.company_name);
25160      $customer_info.find("input[name='customer[business_id]']").val(data.business_id);
25161
25162      $payment_terms_select = $("select[name='customer[payment_terms]']")
25163        .selectmenu()
25164        .selectmenu('value', data.payment_terms);
25165      //$payment_terms_option = $payment_terms_select.find('option[value='+ data.payment_terms +']');
25166      //	$('select[name=set_payment_terms] option[value='+ data.payment_terms +']').attr('selected', 'selected');
25167
25168      //console.log($('select[name=customer_payment_terms]').selectmenu("value"));
25169      //console.log($('select[name=set_payment_terms]').selectmenu("value"));
25170      //console.log($payment_terms_option);
25171
25172      //If the given payment_terms is not selectable, set it to payment_terms = 14;
25173      //	index = $payment_terms_option.index() == -1? 1 : $payment_terms_option.index();
25174      //	$payment_terms_select.selectmenu('index', index);
25175      //console.log(index);
25176
25177      //$('#set_payment_terms').selectmenu('value', index);
25178      //pages.lasku.set_payment_terms(data.payment_terms);
25179      //	pages.lasku.set_payment_terms(data.payment_terms);
25180    }
25181
25182    $('#receiver').show();
25183    $customer_info.show();
25184    $customer_info.find("input[name='customer[address]']").val(data.address);
25185    $customer_info.find("input[name='customer[zipcode]']").val(data.zipcode);
25186    $customer_info.find("input[name='customer[city]']").val(data.city);
25187    $customer_info.find("input[name='customer[email]']").val(data.email);
25188    $customer_info.find("input[name='customer[id]']").val(data.id);
25189
25190    //console.log('delivery_by:', delivery_by);
25191
25192    if (data.delivery_by == 'mail' || data.delivery_by == 'gothia') {
25193      $customer_info.find('td.delivery').find('input[value=gothia]').attr('checked', 'checked');
25194    }
25195
25196    if (data.delivery_by == 'email') {
25197      $customer_info.find('td.delivery').find('input[value=email]').attr('checked', 'checked');
25198    }
25199  });
25200};
25201
25202pages.laskutus = {
25203  init: function (data) {
25204    $('#laskutus-tabs').tabs();
25205    var upload = document.getElementById('upload-material');
25206    $('#upload-material').change(function () {
25207      console.log('Change');
25208    });
25209    upload.addEventListener('change', function () {
25210      var fileName = upload.files[0].name;
25211      $('#file-name').text(fileName).css('display', 'block');
25212      $('#parse_invoice_material').css('display', 'inline');
25213    });
25214    $('#upload_invoice_material')
25215      .button({ icons: { primary: 'ui-icon-plus' } })
25216      .on('click', function () {
25217        $('#upload-material').trigger('click');
25218      });
25219    $('#parse_invoice_material')
25220      .button({ icons: { primary: 'ui-icon-arrowthickstop-1-s' } })
25221      .on('click', function () {
25222        console.log('send to server...');
25223        $('#parse_invoice_material').find('span.ui-button-text').text('Odota. Ladataan...');
25224        $('#parse_invoice_material').attr('disabled', 'disabled');
25225        $('#upload-to-server').submit();
25226      });
25227    window.batchData = data;
25228  },
25229};
25230
25231;var recurringInvoicing = function({showStation, isAdmin, controller, invoiceEndpoint}){
25232 
25233  var self = this;
25234
25235  self.isAdmin = isAdmin;
25236  self.recurringInvoiceId = 0;
25237  self.showStationField = showStation;
25238  self.controller = controller;
25239  self.invoiceEndpoint = invoiceEndpoint;
25240
25241  $('body').append('<div id="recurring_popup"><div/>');
25242  self.dialog = $('#recurring_popup');
25243
25244  $('body').append('<div id="recurring_extra_popup"><div/>');
25245  self.extraDialog = $('#recurring_extra_popup');
25246
25247  self.dialogOpen = function(title, width, height){
25248    self.dialog.html(global.$ajax_loader).dialog({
25249      autoOpen: true,
25250      modal: true,
25251      hide: {
25252        effect: 'fade',
25253        speed: 3000,
25254      },
25255      width: width ? width : 'auto',
25256      height: height ? height : 'auto',
25257      resizable: true,
25258      title: title,
25259      draggable: true,
25260      close: function(){
25261        $(this).dialog('close');
25262      }
25263    });
25264  }
25265
25266  self.dialogReplaceHtml = function(html){
25267    self.dialog.dialog().html(html);
25268  }
25269  self.dialogStartLoading = function(){
25270    self.dialog.dialog().html(global.$ajax_loader);
25271  }
25272
25273  self.extraDialogOpen = function(title, width, height){
25274    self.extraDialog.html(global.$ajax_loader).dialog({
25275      autoOpen: true,
25276      modal: true,
25277      hide: {
25278        effect: 'fade',
25279        speed: 3000,
25280      },
25281      width: width ? width : 'auto',
25282      height: height ? height : 'auto',
25283      resizable: false,
25284      title: title,
25285      draggable: true,
25286      close: function(){
25287        $(this).dialog('close');
25288      }
25289    });
25290  }
25291
25292  self.extraDialogReplaceHtml = function(html){
25293    self.extraDialog.dialog().html(html);
25294  }
25295  self.extraDialogStartLoading = function(){
25296    self.extraDialog.dialog().html(global.$ajax_loader);
25297  }
25298
25299  self.loadStatusDialog = function(id){
25300    self.extraDialogOpen('Loki', 540, 450);
25301    $.ajax({
25302      type: 'GET',
25303      url: '/reskontra/getRecurringInvoiceLog/' + id,
25304    }).done(function(response){
25305      self.extraDialogReplaceHtml(response.data.html);
25306    }).fail(function(error){
25307      var msg = JSON.parse(error.responseText);
25308      self.extraDialogReplaceHtml('<span>' + msg.text + '<span/>');
25309      self.extraDialogClose(4000);
25310    })
25311  } 
25312  self.loadDateFixDialog = function(id){
25313    self.dialogOpen('Muuta laskun päiväys', 520);
25314    $.ajax({
25315      type: 'GET',
25316      url: '/reskontra/getRecurringDateFixDialog/' + id,
25317    }).done(function(response){
25318      self.dialogReplaceHtml(response.data.html);
25319    }).fail(function(error){
25320      var msg = JSON.parse(error.responseText);
25321      self.dialogReplaceHtml('<span>' + msg.text + '<span/>');
25322      self.dialogClose(4000);
25323    })
25324  }
25325
25326  self.loadEndDateDialog = function(id){
25327    self.extraDialogOpen('Aseta päättymispäivä', 520);
25328    $.ajax({
25329      type: 'GET',
25330      url: '/reskontra/getRecurringEndDateDialog/' + id,
25331    }).done(function(response){
25332      self.extraDialogReplaceHtml(response.data.html);
25333    }).fail(function(error){
25334      var msg = JSON.parse(error.responseText);
25335      self.extraDialogReplaceHtml('<span>' + msg.text + '<span/>');
25336      self.extraDialogClose(3000);
25337    })
25338  }
25339
25340  self.loadRecurringInvoiceDialog = function(id){
25341    self.dialogOpen('Laskutuspohjan asetukset', 800, 600);
25342    $.ajax({
25343      type: 'GET',
25344      url: 'reskontra/getRecurringInvoiceDialog/' + id,
25345    }).done(function(response){
25346      self.dialogReplaceHtml(response.data.html);
25347    }).fail(function(error){
25348      var msg = JSON.parse(error.responseText);
25349      self.dialogReplaceHtml('<span>' + msg.text + '<span/>');
25350      self.dialogClose(4000);
25351    })
25352  } 
25353
25354  self.dialogClose = function(delay){
25355    if(!self.dialog){
25356      return;
25357    }
25358    if(!delay){
25359      self.dialog.dialog('close');
25360    }
25361
25362    setTimeout(function(){
25363      self.dialog.dialog('close');
25364    }, delay);
25365  }
25366
25367  self.extraDialogClose = function(delay){
25368    if(!self.extraDialog){
25369      return;
25370    }
25371    if(!delay){
25372      self.extraDialog.dialog('close');
25373    }
25374
25375    setTimeout(function(){
25376      self.extraDialog.dialog('close');
25377    }, delay);
25378  }
25379
25380  self.dt = $('#recurring_dt').dataTable({
25381    oLanguage: global.dataTablesLanguage,
25382    sPaginationType: 'full_numbers',
25383    bPaginate: true,
25384    iDisplayLength: 10,
25385    bAutoWidth: false,
25386    bJQueryUI: true,
25387    bFilter: true,
25388    bInfo: true,
25389    bProcessing: true,
25390    bServerSide: true,
25391    sAjaxSource: 'reskontra/recurringDataTable/',
25392    aoColumns: [
25393      /** id **/ { bVisible: true, bSortable: true, bSearchable: true },
25394      /** customer_id **/ { bVisible: false, bSortable: false, bSearchable: false },
25395      /** myyjä **/ { bVisible: self.isAdmin, bSortable: true, bSearchable: self.isAdmin },
25396      /** asiakas **/ { bVisible: true, bSortable: true, bSearchable: true },
25397      /** luotu **/ { bVisible: true, bSortable: false, bSearchable: false },
25398      /** ed. lasku **/ { bVisible: true, bSortable: false, bSearchable: false },
25399      /** seur. lasku **/ { bVisible: true, bSortable: false, bSearchable: false },
25400      /** summa **/ { bVisible: true, bSortable: false, bSearchable: false },
25401      /** viitteemme **/ { bVisible: true, bSortable: true, bSearchable: true },
25402      /** laskutuskausi **/ { bVisible: true, bSearchable: false, bSortable: false },
25403      /** laskutettu **/ { bVisible: true, bSearchable: false, bSortable: false },
25404      /** tila **/ { bVisible: true, bSearchable: false, bSortable: false },
25405      /** end_date **/ { bVisible: false, bSearchable: false, bSortable: false },
25406    ],
25407    aaSorting: [[0, 'desc']],
25408
25409    fnServerParams: function (aoData) {
25410      // var month = $('#invoices_filter_form select[name="month"] option:selected').attr('value');
25411      // var year = $('#invoices_filter_form select[name="year"] option:selected').attr('value');
25412      var company = $('#invoices_filter_form select[name="company"] option:selected').attr(
25413        'value'
25414      );
25415      var startDate;
25416      var endDate;
25417      if ($('input#filter-recurring-start-date').length > 0) {
25418        startDate = $('input#filter-recurring-start-date')[0].value;
25419        endDate = $('input#filter-recurring-end-date')[0].value;
25420      }
25421
25422      var filters = [];
25423
25424      $('#recurring_filter_form input:checkbox:checked').each(function () {
25425        filters.push($(this).attr('name'));
25426      });
25427
25428      // aoData.push({ name: 'month', value: month });
25429      // aoData.push({ name: 'year', value: year });
25430      aoData.push({ name: 'company', value: company });
25431      aoData.push({ name: 'startDate', value: startDate });
25432      aoData.push({ name: 'endDate', value: endDate });
25433      aoData.push({ name: 'filters', value: filters });
25434
25435    },
25436
25437    //Called before each row is shown
25438    fnRowCallback: function (nRow, aData, iDisplayIndex) {
25439      var id = aData[0];
25440      // var customer_id = aData[1];
25441      // var customer_name = aData[2];
25442      var next_date = aData[6];
25443      var recurrence = aData[9];
25444      var status = aData[11];
25445      var endDate = aData[12];
25446
25447      $(nRow).attr('data-record-id', id);
25448
25449      $('td:eq(0)', nRow).html(
25450        '<a href="' + id + '" class="show_recurring_invoice" >' + id + '</a>'
25451      );
25452
25453      var dateError = false;
25454      if(next_date){
25455        var parts = next_date.split('.');
25456        var dateError = Date.parse(parts[2]+'-'+ parts[1].padStart(2, '0') + '-' + parts[0].padStart(2, '0')+'T23:59:59.000Z') < Date.now();
25457      } else {
25458        dateError = true;
25459      }
25460  
25461      var dateCol = isAdmin ? 5 : 4;
25462      if(dateError && status == 'Käynnissä'){
25463        $('td:eq('+dateCol+')', nRow).html(
25464          '<a href="' + id + '" class="show_date_error" >' + (next_date ? next_date : 'Virhe') + '</a>'
25465        ).addClass('warning');
25466      } else {
25467        $('td:eq('+dateCol+')', nRow).removeClass('warning');
25468      } 
25469      var recurrenceCol = isAdmin ? 8 : 7;
25470      var recurrenceText = endDate ? recurrence + '<br>( päättyy ' + endDate + ' )' : recurrence;
25471      $('td:eq('+recurrenceCol+')', nRow)
25472        .html(recurrenceText);
25473
25474      var statusCol = isAdmin ? 10 : 9;
25475
25476      $('td:eq('+statusCol+')', nRow)
25477        .html('<a href="' + id + '" class="show_recurring_log" >' + status + '</a>');
25478
25479      return nRow;
25480    }, 
25481  })
25482
25483  function getInvoiceColumns(isAdmin){
25484    if(isAdmin){
25485      return [
25486        /** invoice_id **/ null,
25487        /** gothia_invoice_nr **/ { bVisible: false, bSearchable: true, bSortable: false },
25488        /** ref_nr **/ { bVisible: false, bSearchable: true, bSortable: false },
25489        /** Lähettäjä **/ null,
25490        /** Velallinen **/ null,
25491        /** c/o **/ { bVisible: false, bSearchable: true, bSortable: false },
25492        /** Päiväys **/ null,
25493        /** Eräpäivä **/ null,
25494        /** Summa **/ { bSearchable: false, bSortable: false },
25495        /** Avoinna **/ { bSearchable: false, bSortable: false },
25496        /** Rahoitettu **/ null,
25497        /** Viitteemme **/ null,
25498        /** Laskun **/ { bSearchable: false, bSortable: 'status' },
25499        /** status **/ { bVisible: false, bSearchable: false, bSortable: false },
25500        /** customer_id **/ { bVisible: false, bSearchable: false, bSortable: false },
25501        /** customer_type **/ { bVisible: false, bSearchable: false, bSortable: false },
25502      ]
25503    } else {
25504      return [
25505        /** id **/ { bVisible: false, bSortable: true, bSearchable: true },
25506      /** invoice_number **/ { bVisible: true, bSortable: false, bSearchable: true },
25507      /** reference_nr **/ { bVisible: false, bSortable: false, bSearchable: true },
25508      /** company **/ { bVisible: false, bSortable: false, bSearchable: false },
25509      /** station **/ { bVisible: false, bSortable: false, bSearchable: false },
25510      /** receiver **/ null,
25511      /** c/o **/ { bVisible: false, bSearchable: true, bSortable: false },
25512      /** delivery_date **/ { sType: 'date-eu' },
25513      /** due_date **/ { sType: 'date-eu' },
25514      /** sum **/ { bSortable: false, bSearchable: false },
25515      /** open_amount **/ { bVisible: true, bSortable: false, bSearchable: false },
25516      /** is_financed **/ { bVisible: false, bSortable: false, bSearchable: false },
25517      /** our_reference **/ null,
25518      /** status **/ null,
25519      /** status_class **/ { bVisible: false },
25520      /** customer_id **/ { bVisible: false, bSearchable: false, bSortable: false },
25521      /** customer_type **/ { bVisible: false, bSearchable: false, bSortable: false }, 
25522      ]
25523    }
25524  }
25525
25526  function getRowCallbackFunction(){
25527    var adminCallback = function (nRow, aData, iDisplayIndex) {
25528      var invoice_id = aData[0];
25529      // var receiver = aData[4];
25530      // var open_sum = aData[9];
25531      var row_class = aData[13];
25532      var status = aData[12];
25533      // var company_id = aData[14];
25534      // var customer_id = aData[15];
25535      var ledger_service = aData[17];
25536      // var company_name = aData[3];
25537      $('td:eq(7)', nRow).html(ledger_service);
25538
25539      // Add the transaction id to every rows data object
25540      $(nRow).addClass(row_class);
25541      $('td:eq(0)', nRow).html(
25542        '<a href="' + invoice_id + '" class="show_invoice" >' + invoice_id + '</a>'
25543      );
25544     
25545      $('td:eq(9)', nRow)
25546        .addClass('status')
25547        .html('<a href="' + invoice_id + '" class="show_invoice_log" >' + status + '</a>');
25548
25549      return nRow;
25550    }
25551    var defaultCallback = function (nRow, aData, iDisplayIndex) {
25552      var invoiceId = aData[0];
25553      var invoiceNumber = aData[1];
25554      var rowClass = aData[14];
25555      var status = aData[13];
25556
25557      $(nRow).addClass(rowClass);
25558
25559      $('td:eq(0)', nRow).html(
25560        '<a href="' + invoiceId + '" class="show_invoice" >' + invoiceNumber + '</a>'
25561      );
25562
25563      //Status column is 8:th in case the station col is visible
25564      $('td:eq(' + (7 + self.showStationField) + ')', nRow)
25565        .addClass('status')
25566        .html('<a href="' + invoiceId + '" class="show_invoice_log" >' + status + '</a>');
25567
25568      return nRow;
25569    }
25570
25571    return isAdmin ? adminCallback : defaultCallback;
25572  }
25573
25574  self.invoice_dt = $('#recurring_invoices_dt').dataTable({
25575    oLanguage: global.dataTablesLanguage,
25576    sPaginationType: 'full_numbers',
25577    bPaginate: false,
25578    iDisplayLength: 100,
25579    bAutoWidth: false,
25580    bJQueryUI: true,
25581    bFilter: false,
25582    bInfo: false,
25583    sDom: 'rt',
25584    bProcessing: true,
25585    bServerSide: true,
25586    sAjaxSource: self.invoiceEndpoint,
25587    aoColumns: getInvoiceColumns(isAdmin),
25588    aaSorting: [[0, 'desc']],
25589
25590    fnServerParams: function (aoData) {
25591      aoData.push({ name: 'recurringInvoiceId', value: self.recurringInvoiceId });
25592      aoData.push({ name: 'filters', value: ['all'] });
25593    },
25594
25595    fnInfoCallback: function (oSettings, iStart, iEnd, iMax, iTotal, sPre) {
25596
25597      var responseJson = JSON.parse(oSettings.jqXHR.responseText);
25598      if(responseJson.aaData.length === 0){
25599        self.hide
25600      }
25601      var sums = responseJson.iSumma;
25602      if (typeof sums !== 'undefined') {
25603        return (
25604          'N&auml;ytet&auml;&auml;n rivit ' +
25605          iStart +
25606          ' - ' +
25607          iEnd +
25608          ' / ' +
25609          iTotal +
25610          ',  summa: ' +
25611          sums.amountToPay +
25612          ',  avoinna: ' +
25613          sums.openAmount
25614        );
25615      }
25616      return 'N&auml;ytet&auml;&auml;n rivit ' + iStart + ' - ' + iEnd + ' / ' + iTotal;
25617    },
25618
25619    //Called before each row is shown
25620    fnRowCallback: getRowCallbackFunction(),
25621
25622  })
25623
25624  self.updateDt = function(){
25625    self.dt.fnClearTable(0);
25626    self.dt.fnDraw(); 
25627  }
25628  self.updateInvoiceDt = function(){
25629    self.invoice_dt.fnClearTable(0);
25630    self.invoice_dt.fnDraw(); 
25631  }
25632  self.hideInvoices = function(){
25633    if($('#recurring_invoices_dt').hasClass('hide')){
25634      return;
25635    }
25636    self.recurringInvoiceId = 0;
25637    self.updateInvoiceDt();
25638    $('#recurring_invoices_dt').addClass('hide');
25639    $('#recurring_invoices_dt_container .no-items').removeClass('hide');
25640  }
25641  self.showInvoices = function(id){
25642    self.recurringInvoiceId = id;
25643    self.updateInvoiceDt();
25644    $('#recurring_invoices_dt').removeClass('hide');
25645    $('#recurring_invoices_dt_container .no-items').addClass('hide');
25646  }
25647
25648  self.init = function(){
25649
25650    $('#recurring_invoices_dt').on('click', 'a.show_invoice, a.show_invoice_log', function (e) {
25651      e.preventDefault();
25652
25653      var invoice_id = $(e.target).attr('href');
25654      var action = $(e.target).attr('class');
25655
25656      var n = invoice_id.lastIndexOf('/');
25657
25658      invoice_id = invoice_id.substring(n + 1);
25659
25660      switch (action) {
25661        case 'show_invoice':
25662          pages.reskontra.show_invoice(invoice_id);
25663          break;
25664        case 'show_invoice_log':
25665          pages.reskontra.show_invoice_log(invoice_id);
25666          break;
25667      }
25668    });
25669
25670    $('#recurring_filter_form input:checkbox, #recurring_filter_form select').on('change',
25671      function (e) {
25672        var filters = [];
25673
25674        $('#recurring_filter_form input:checkbox:checked').each(function () {
25675          filters.push($(this).attr('name'));
25676        });
25677        if(filters.length === 0){
25678          return;
25679        }
25680        if(self.recurringInvoiceId !== 0){}
25681
25682        self.hideInvoices();
25683        self.dt.fnClearTable(0);
25684        self.dt.fnDraw();
25685      }
25686    );
25687
25688    $('#recurring_dt_filter').on('keypress',
25689      function (e) {
25690        self.hideInvoices();
25691      }
25692    );
25693
25694    $('#recurring_dt').on('click', 'td', function(){
25695      var id = $(this).parent().attr('data-record-id');
25696
25697      if(id === self.recurringInvoiceId){
25698        return;
25699      }
25700      $('#recurring_dt tr').each(function(item){
25701        $(this).removeClass('selected');
25702      })
25703      $(this).parent().addClass('selected'); 
25704      self.showInvoices(id)
25705    });
25706    
25707    $('#recurring_dt').on(
25708      'click',
25709      'a.show_recurring_log, a.show_date_error, a.show_recurring_invoice',
25710      function (e) {
25711        e.preventDefault();
25712        e.stopPropagation();
25713  
25714        var id = $(e.target).attr('href');
25715        var action = $(e.target).attr('class');
25716  
25717        switch (action) {
25718          case 'show_recurring_log':
25719            self.loadStatusDialog(id);
25720            break;
25721          case 'show_date_error':
25722            self.loadDateFixDialog(id);
25723            break;
25724          case 'show_recurring_invoice':
25725            self.loadRecurringInvoiceDialog(id);
25726            break;
25727        }
25728      }
25729    );
25730
25731
25732  }
25733  window.recurringInvoiceFunctions = {
25734    loadRecurringInvoiceDialog: function(id){
25735      self.loadRecurringInvoiceDialog(id);
25736    },
25737    loadEndDateDialog: function(id){
25738      self.loadEndDateDialog(id);
25739    },
25740    loadStatusDialog: function(id){
25741      self.loadStatusDialog(id);
25742    },
25743    dialogStartLoading: function(){
25744      self.dialogStartLoading();
25745    },
25746    closeDialog: function(delay){
25747      self.closeDialog(delay);
25748    },
25749    dialogReplaceHtml: function(html){
25750      self.dialogReplaceHtml(html);
25751    },
25752    extraDialogClose: function(delay){
25753      self.extraDialogClose(delay);
25754    },
25755    extraDialogStartLoading: function(){
25756      self.extraDialogStartLoading();
25757    },
25758    extraDialogReplaceHtml: function(html){
25759      self.extraDialogReplaceHtml(html);
25760    },
25761    updateDt: function(){
25762      self.updateDt();
25763    },
25764    hideInvoices: function(){
25765      self.hideInvoices();
25766    }
25767  }
25768  
25769}
25770
25771
25772;var PaymentLinkDataTable = function({isAdmin, isCompanyGroupAdmin}){
25773  var self = this;
25774  self.isAdmin = isAdmin ? true : false;
25775  self.isCompanyGroupAdmin = isCompanyGroupAdmin ? true : false;
25776
25777  self.openJobOrder = function(id){
25778    console.log('OPENING JOB ORDER')
25779  }
25780
25781  self.openTowingRecord = function(id){
25782    console.log('OPENING TOWING ORDER')
25783  }
25784  
25785  self.openLog = function(id){
25786    
25787    console.log('OPENING LOG')
25788  }
25789
25790  $('#payment_link_filter_form').find('select[name="company"]').on('changed.bs.select', function (e, clickedIndex, isSelected) {
25791    var $select = $(this);
25792    var selectedValues = $select.val() || [];
25793
25794    if (selectedValues.includes('all') && selectedValues.length > 1) {
25795        if (isSelected && $select.find('option').eq(clickedIndex).val() === 'all') {
25796            selectedValues = ['all'];
25797        } else {
25798            selectedValues = selectedValues.filter(company => company !== 'all');
25799        }
25800        $select.selectpicker('val', selectedValues);
25801    }
25802  });
25803
25804  self.dataTable = $('#payment_links_dt').dataTable({
25805    oLanguage: global.dataTablesLanguage,
25806    sPaginationType: 'full_numbers',
25807    bPaginate: true,
25808    iDisplayLength: 10,
25809    bAutoWidth: false,
25810    bJQueryUI: true,
25811    bFilter: true,
25812    bInfo: true,
25813    bProcessing: true,
25814    bServerSide: true,
25815    sAjaxSource: 'reskontra/paymentLinksDataTable/',
25816    aoColumns: [
25817      /** id **/ { bVisible: false, bSortable: true, bSearchable: true},
25818      /** company_id **/ { bVisible: false, bSortable: false, bSearchable: false },
25819      /** job_id **/ { bVisible: false, bSortable: false, bSearchable: true },
25820      /** job_type **/ { bVisible: false, bSortable: false, bSearchable: false },
25821      /** number **/ { bVisible: true, bSortable: true, bSearchable: true },
25822      /** company_name **/ { bVisible: self.isAdmin, bSortable: false, bSearchable: false },
25823      /** station_name **/ { bVisible: self.isCompanyGroupAdmin, bSortable: false, bSearchable: false },
25824      /** created_date **/ { bVisible: true, bSortable: true, bSearchable: false },
25825      /** confirmed_date **/ { bVisible: true, bSortable: true, bSearchable: false },
25826      /** our_reference **/ { bVisible: true, bSortable: false, bSearchable: true },
25827      /** debtor **/ { bVisible: true, bSortable: false, bSearchable: false },
25828      /** operator **/ { bVisible: false, bSortable: false, bSearchable: false },
25829      /** reference_number **/ { bVisible: true, bSortable: false, bSearchable: true },
25830      /** amount_to_pay **/ { bVisible: true, bSortable: false, bSearchable: false },
25831      /** status **/ { bVisible: false, bSortable: true, bSearchable: false },
25832      /** status_description **/ { bVisible: true, bSortable: false, bSearchable: false }
25833    ],
25834    aaSorting: [[14, 'desc'], [0, 'desc']],
25835
25836    fnServerParams: function (aoData) {
25837
25838      var filters = [];
25839      var selectedCompanies = $('#payment_link_filter_form select[name="company"]').val() || [];
25840
25841      if(!Array.isArray(selectedCompanies)){
25842        selectedCompanies = [selectedCompanies];
25843      }
25844
25845      if (selectedCompanies.includes('all') && selectedCompanies.length > 1){
25846        selectedCompanies = selectedCompanies.filter(company => company !== 'all');
25847      }
25848
25849      company = selectedCompanies.includes('all') ? 'all' : selectedCompanies;
25850
25851      var jobType = $('#payment_link_filter_form select[name="job_type"] option:selected').attr(
25852        'value'
25853      );
25854      var startDate;
25855      var endDate;
25856      if ($('input#filter-payment-link-start-date').length > 0) {
25857        startDate = $('input#filter-payment-link-start-date')[0].value;
25858        endDate = $('input#filter-payment-link-end-date')[0].value;
25859      }
25860
25861      $('#payment_link_filter_form input:checkbox:checked').each(function () {
25862        filters.push($(this).attr('name'));
25863      });
25864
25865      aoData.push({ name: 'company', value: company });
25866      aoData.push({ name: 'jobType', value: jobType });
25867      aoData.push({ name: 'startDate', value: startDate });
25868      aoData.push({ name: 'endDate', value: endDate });
25869      aoData.push({ name: 'filters', value: filters });
25870
25871    },
25872
25873    //Called before each row is shown
25874    fnRowCallback: function (nRow, aData, iDisplayIndex) {
25875      var id = aData[0];
25876      var company_id = aData[1];
25877      var job_id = aData[2];
25878      var job_type = aData[3];
25879      var job_number = aData[4];
25880      var company_name = aData[5];
25881      var station_name = aData[6];
25882      var created = aData[7];
25883      var paid = aData[8];
25884      var jobRef = aData[9];
25885      var status = aData[14];
25886      var status_description = aData[15];
25887
25888      var statusClasses = {
25889        'link_expired': 'status-alert',
25890        'payment_non_trackable': 'status-alert',
25891        'payment_failed': 'status-alert',
25892        'link_sent': 'status-warning'
25893      }
25894     
25895      var shiftCol = self.isCompanyGroupAdmin || self.isAdmin ? 1 : 0;
25896
25897      $(nRow).addClass(statusClasses[status]);
25898
25899      var jobHref = job_id;
25900      if (job_type === 'TOWING_ORDER') {
25901        jobHref = '/tilaus/' + job_id;
25902      }
25903
25904      $('td:eq(0)', nRow).html(
25905        '<a href="' + jobHref + '" class="open_job_record" data_type='+ job_type +' >' + job_number + '</a>'
25906      );
25907      $('td:eq('+ (1 + shiftCol) +')', nRow).html(`<span>${created}</span>`);
25908      $('td:eq('+ (2 + shiftCol) +')', nRow).html(`<span>${paid}</span>`);
25909      $('td:eq('+ (3 + shiftCol) +')', nRow).html(
25910        '<a href="' + id + '" class="open_direct_payment" >' + jobRef + '</a>'
25911      );
25912      $('td:eq('+ (7 + shiftCol) +')', nRow).html(
25913        '<a href="/logs/getLogHtml/direct_payment/' + id + '" class="open_log" >' + status_description + '</a>'
25914      );
25915
25916      return nRow;
25917    }, 
25918  })
25919
25920  self.updateDt = function(){
25921    setTimeout(function () {
25922      self.dataTable.fnClearTable(0);
25923      self.dataTable.fnDraw(); 
25924    }, 1)
25925  }
25926
25927
25928  self.init = function(){
25929
25930    $('#payment_links_dt').on('click', 'a.open_job_record, a.open_log, a.open_direct_payment', function (e) {
25931      e.preventDefault();
25932
25933      var id = $(e.target).attr('href');
25934      var action = $(e.target).attr('class');
25935
25936      switch (action) {
25937        case 'open_job_record':
25938          var type = $(e.target).attr('data_type');
25939          console.log(type, ' This is the type')
25940          if(type === 'JOB_ORDER'){
25941            window.openDialog(id);
25942          }
25943          if(type === 'TOWING_RECORD'){
25944            var url = 'kuormakirjat/get_towing_record_html/' + id;
25945            global.showJob(url);
25946          }
25947          if(type === 'TOWING_ORDER'){
25948            window.location = id;
25949          }
25950          break;
25951        case 'open_log':
25952          global.show_log(id);
25953          break;
25954        case 'open_direct_payment':
25955          pages.reskontra.show_direct_payment(id, 'Maksun tiedot');
25956          break;
25957      }
25958    });
25959
25960    $('#payment_link_filter_form input:checkbox, #payment_link_filter_form select').on('change',
25961      function (e) {
25962        var filters = [];
25963
25964        $('#payment_link_filter_form input:checkbox:checked').each(function () {
25965          filters.push($(this).attr('name'));
25966        });
25967        if(filters.length === 0){
25968          return;
25969        }
25970
25971        self.updateDt();
25972      }
25973    );
25974
25975    [
25976      'input#filter-payment-link-start-date',
25977      'input#filter-payment-link-end-date'
25978    ].forEach(function (input) {
25979      if($(input).length === 0){
25980        return;
25981      }
25982      $(input).datepicker({
25983        showButtonPanel: true,
25984        language: 'fi-FI',
25985        weekStart: 1,
25986        todayHighlight: true,
25987        startDate: '-120m',
25988        autoclose: true,
25989        clearBtn: true,
25990        format: 'dd.mm.yyyy',
25991        forceParse: true,
25992        assumeNearbyYear: true,
25993      });
25994    });
25995
25996    function isCorrectDateFormat(input) {
25997      return /^([0-9]|[0-9]{2})[./]([0-9]|[0-9]{2})[./]([0-9]{4})$/.test(input);
25998    }
25999
26000    $('input#filter-payment-link-end-date, input#filter-payment-link-start-date').each(
26001      function () {
26002        $(this).on('change changeDate blur', function (e) {
26003          var d = e.target.value;
26004          if (/^[0-9]{6}$/.test(d)) {
26005            $(this).datepicker('update', d[0] + d[1] + '.' + d[2] + d[3] + '.20' + d[4] + d[5]);
26006            $(this).trigger('changeDate');
26007            $(this).trigger('blur');
26008            $(this).datepicker('hide');
26009            return;
26010          }
26011          if (/^[0-9]{8}$/.test(d)) {
26012            $(this).datepicker(
26013              'update',
26014              d[0] + d[1] + '.' + d[2] + d[3] + '.' + d[4] + d[5] + d[6] + d[7]
26015            );
26016            $(this).trigger('changeDate');
26017            $(this).trigger('blur');
26018            $(this).datepicker('hide');
26019            return;
26020          }
26021          if (!!e.target.value && !isCorrectDateFormat(d)) {
26022            if (e.type === 'blur') {
26023              $(this).datepicker('update', '');
26024            }
26025            return;
26026          }
26027          if (e.type === 'changeDate') {
26028            setTimeout(function () {
26029              self.updateDt();
26030            }, 1);
26031          }
26032        });
26033      }
26034    );
26035  }
26036
26037  self.confirmDateDialogHtml = `<div>
26038    <form id="confirm-online-payment-form">
26039    <fieldset>
26040      <p>Syötä maksun päivämäärä</p>
26041      <ol>
26042        <li>
26043          <label id="paid_date_label" for="paid_date">Päivämäärä:</label>
26044          <input type="text" class="text small" id="paid_date" name="paid_date" />
26045        </li>
26046        <li>
26047          <div style="margin-top: 2rem;">  
26048            <button id="submit-button" type="submit">Merkitse maksetuksi</button>
26049          </div>
26050        </li>
26051      </ol>
26052      </fieldset>
26053    </form>
26054  </div>`;
26055
26056  self.confirmDialogHtml = `<div>
26057    <form id="confirm-online-payment-form">
26058    <fieldset>
26059      <p>Haluatko varmasti merkitä maksun maksetuksi</p>
26060      <ol>
26061        <li>
26062          <div style="margin-top: 2rem;">  
26063            <button id="submit-button" type="submit">Merkitse maksetuksi</button>
26064          </div>
26065        </li>
26066      </ol>
26067      </fieldset>
26068    </form>
26069  </div>`;
26070
26071  self.confirmDialogOptions = {
26072    width: 400,
26073    //height:200,
26074    autoOpen: true,
26075    modal: true,
26076    resizable: false,
26077    draggable: false,
26078    beforeClose: function (event, ui) {
26079      event.stopPropagation();
26080    },
26081    onclose: function(){
26082      $(this).dialog('destroy');
26083    },
26084    title: 'Merkitse maksu',
26085    buttons: {
26086      Peruuta: function () {
26087        $(this).dialog('close');
26088      },
26089    },
26090  };
26091
26092  self.openConfirmOnlinePayment = function(paymentId, type) {
26093    if(type == 'confirmed'){
26094      self.openVerifyOnlinePayment(paymentId)
26095    } else {
26096      self.openConfirmDateOnlinePayment(paymentId)
26097    }
26098  }
26099
26100  self.openConfirmDateOnlinePayment = function(paymentId) {
26101
26102    $dialog = $(self.confirmDateDialogHtml);
26103
26104    $dialog.find("input#paid_date").datepicker({
26105      showButtonPanel: true,
26106      language: 'fi-FI',
26107      weekStart: 1,
26108      todayHighlight: true,
26109      startDate: '-12m',
26110      autoclose: true,
26111      clearBtn: true,
26112      format: 'dd.mm.yyyy',
26113      forceParse: true,
26114      assumeNearbyYear: true,
26115      endDate: '+0d'
26116    });
26117
26118    $dialog.find('form#confirm-online-payment-form').on('submit', function (e) {
26119      e.preventDefault();
26120      var data = _.object(
26121        $dialog
26122          .find('#confirm-online-payment-form')
26123          .serializeArray()
26124          .map(function (v) {
26125            return [v.name, v.value];
26126          })
26127      );
26128
26129      self.callConfirmeEndpoint(paymentId, data, $dialog);
26130
26131      return false;
26132    });
26133
26134    $dialog.dialog(self.confirmDialogOptions);
26135  }
26136
26137  self.openVerifyOnlinePayment = function(paymentId) {
26138
26139    $dialog = $(self.confirmDialogHtml);
26140
26141    $dialog.find('form#confirm-online-payment-form').on('submit', function (e) {
26142      e.preventDefault();
26143      self.callConfirmeEndpoint(paymentId, {paid_date: null}, $dialog);
26144
26145      return false;
26146    });
26147
26148    $dialog.dialog(self.confirmDialogOptions);
26149  }
26150
26151  self.callConfirmeEndpoint = function(paymentId, data, $dialog){
26152    $.ajax({
26153      type: 'POST',
26154      url: '/reskontra/confirmOnlinePayment/' + paymentId,
26155      data: data,
26156      beforeSend: function (request) {
26157        global.showLoadingDialog('Tallennetaan maksua...');
26158      },
26159    })
26160      .done(function (data) {
26161        global.close_loading_dialog();
26162        global.show_message(data);
26163        $dialog.dialog('close');
26164        global.$dialog.dialog('close');
26165        pages.reskontra.show_direct_payment(paymentId, 'Maksun tiedot');
26166        //Refresh the datatable
26167        self.updateDt();
26168      })
26169      .fail(function (data) {
26170        global.show_message(JSON.parse(data.responseText));
26171        global.close_loading_dialog();
26172      });
26173  }
26174}
26175
26176
26177;//Declare class properties and methods
26178var tuotteet = (function () {
26179  var self = this;
26180
26181  //Properties
26182  self.$dialog = $('<div />', {});
26183  self.$items_datatable = null;
26184  self.$item_groups_datatable = null;
26185  self.itemDialog = null;
26186  self.itemGroupDialog = null;
26187
26188  //Define methods
26189  self.show_message = function (msgJSON, callback) {
26190    var icon = '';
26191    var $message_dialog = '';
26192    var timer;
26193
26194    switch (msgJSON.type) {
26195      case 'success':
26196        icon = 'ui-icon-circle-check';
26197        break;
26198      case 'error':
26199        icon = 'ui-icon-circle-close';
26200        break;
26201      case 'alert':
26202        icon = 'ui-icon-alert';
26203        break;
26204    }
26205
26206    if (
26207      (msgJSON.title === '' || typeof msgJSON.title === 'undefined') &&
26208      msgJSON.type === 'error'
26209    ) {
26210      msgJSON.title = 'Virhe!';
26211    }
26212
26213    $message_dialog = $('<div />', {});
26214    $message_dialog.append($('<p />', {})).html(msgJSON.text);
26215
26216    if (msgJSON.type !== 'info') {
26217      $message_dialog.prepend(
26218        $('<span />', { class: 'ui-icon ' + icon, style: 'float:left; margin:0 7px 50px 0;' })
26219      );
26220    }
26221
26222    $message_dialog.dialog({
26223      title: msgJSON.title,
26224      modal: true,
26225      buttons: {
26226        Ok: function () {
26227          $(this).dialog('close');
26228        },
26229      },
26230      open: function () {
26231        if (msgJSON.type === 'success') {
26232          timer = setTimeout(function () {
26233            $message_dialog.dialog('widget').hide('highlight', {}, 1500, function () {
26234              $message_dialog.dialog('close');
26235            });
26236          }, 2000);
26237        }
26238        if (msgJSON.type === 'info') {
26239        }
26240      },
26241      beforeClose: function () {
26242        clearTimeout(timer);
26243      },
26244      close: function () {
26245        if (typeof callback !== 'undefined') {
26246          callback();
26247        }
26248      },
26249    });
26250  };
26251
26252  self.init = function (opts) {
26253    $('#items_tabs').tabs();
26254
26255    $('#add_item')
26256      .button({ icons: { primary: 'ui-icon-plusthick' } })
26257      .click(function () {
26258        window.ItemDialog.show();
26259      });
26260
26261    $('#add_item_group')
26262      .button({ icons: { primary: 'ui-icon-plusthick' } })
26263      .click(function () {
26264        window.ItemGroupDialog.show();
26265      });
26266
26267    $('#upgrade_vat_pct')
26268      .button({ icons: { primary: 'ui-icon-document' } })
26269      .click(function () {
26270        self.openVatUpgardeModal();
26271      });
26272
26273    $('#open_report_generator')
26274      .button({ icons: { primary: 'ui-icon-document' } })
26275      .click(function () {
26276        self.reportGenerator();
26277      });
26278
26279    var aoColumns = [
26280      /** id **/ { bVisible: false },
26281      /** item_name **/ null,
26282      /** unitprice **/ null,
26283      /** vat **/ null,
26284      /** vat_included **/ null,
26285      /** unit **/ null,
26286      /** limited_usage **/ { bVisible: false },
26287      /** is_tracked **/ { bVisible: false },
26288      /** show_groups **/ null,
26289    ];
26290    // Hide the limited usage column for everyone except car_tow companies
26291    if (opts.field_of_work == 'car_tow') {
26292      aoColumns = [
26293        /** id **/ { bVisible: false },
26294        /** item_name **/ null,
26295        /** unitprice **/ null,
26296        /** vat **/ null,
26297        /** vat_included **/ null,
26298        /** unit **/ null,
26299        /** limited_usage **/ null,
26300        /** is_tracked **/ { bVisible: false },
26301        /** show_groups **/ null,
26302      ];
26303    }
26304
26305    if (opts.innokorjaamo === '1') {
26306      aoColumns = [
26307        /** id **/ { bVisible: false },
26308        /** item_name **/ null,
26309        /** unitprice **/ null,
26310        /** vat **/ null,
26311        /** vat_included **/ null,
26312        /** unit **/ null,
26313        /** limited_usage **/ null,
26314        /** is_tracked **/ { bVisible: true },
26315        /** show_groups **/ null,
26316      ];
26317    }
26318
26319    self.$items_datatable = $('#items_dt').dataTable({
26320      oLanguage: global.dataTablesLanguage,
26321      sPaginationType: 'full_numbers',
26322      iDisplayLength: 25,
26323      bAutoWidth: false,
26324      bJQueryUI: true,
26325      bFilter: true,
26326      bInfo: true,
26327      bPaginate: true,
26328      bProcessing: true,
26329      bServerSide: false,
26330      sAjaxSource: 'tuotteet/get_items_json/',
26331      aoColumns: aoColumns,
26332      aaSorting: [[1, 'asc']],
26333
26334      fnRowCallback: function (nRow, aData) {
26335        var id = aData[0];
26336        var item_name = aData[1];
26337        var is_owner = aData[19];
26338        if (is_owner) {
26339          $('td:eq(0)', nRow).html(
26340            $('<a />', {
26341              href: 'tuotteet/item/' + id + '/',
26342              name: 'ItemDialog',
26343              class: 'show',
26344            }).html(item_name)
26345          );
26346          $('td:last', nRow).html(
26347            $('<a />', { href: id + '/', name: 'tuotteet', class: 'edit_items_groups' }).html(
26348              'Näytä'
26349            )
26350          );
26351        } else {
26352          $('td:last', nRow).html('Näytä');
26353        }
26354        return nRow;
26355      },
26356    });
26357
26358    self.$AK_items_datatable = $('#AK_items_dt').dataTable({
26359      oLanguage: global.dataTablesLanguage,
26360      sPaginationType: 'full_numbers',
26361      iDisplayLength: 25,
26362      bAutoWidth: false,
26363      bJQueryUI: true,
26364      bFilter: true,
26365      bInfo: true,
26366      bPaginate: true,
26367      bProcessing: true,
26368      bServerSide: false,
26369      sAjaxSource: 'tuotteet/get_AK_items_json/',
26370      aoColumns: [
26371        /** id **/ { bVisible: false },
26372        /** item_name **/ null,
26373        /** unitprice **/ null,
26374        /** vat **/ null,
26375        /** vat_included **/ null,
26376        /** unit **/ null,
26377        /** limited_usage **/ { bVisible: false },
26378        /** is_tracked **/ { bVisible: false },
26379        /** show_groups **/ { bVisible: false },
26380      ],
26381      aaSorting: [[1, 'asc']],
26382      fnRowCallback: function () {},
26383    });
26384
26385    self.$AK_item_groups_datatable = $('#AK_item_groups_dt').dataTable({
26386      oLanguage: global.dataTablesLanguage,
26387      sPaginationType: 'full_numbers',
26388      iDisplayLength: 25,
26389      bAutoWidth: false,
26390      bJQueryUI: true,
26391      bFilter: true,
26392      bInfo: true,
26393      bPaginate: true,
26394      bProcessing: true,
26395      bServerSide: false,
26396      sAjaxSource: 'tuotteet/get_AK_item_groups_json/',
26397      aoColumns: [/** id **/ { bVisible: false }, /** group_name **/ null],
26398
26399      aaSorting: [[1, 'asc']],
26400
26401      //Called before each row is shown
26402      fnRowCallback: function (nRow, aData) {
26403        var id = aData[0],
26404          group_name = aData[1];
26405        $('td:eq(0)', nRow).html(
26406          $('<a />', { href: id + '/', name: 'tuotteet', class: 'show_AK_item_group' }).html(
26407            group_name
26408          )
26409        );
26410        return nRow;
26411      },
26412    });
26413
26414    self.$item_inventory_datatable = $('#item_inventory_dt').dataTable({
26415      oLanguage: global.dataTablesLanguage,
26416      sPaginationType: 'full_numbers',
26417      iDisplayLength: 25,
26418      bAutoWidth: false,
26419      bJQueryUI: true,
26420      bFilter: true,
26421      bInfo: true,
26422      bPaginate: true,
26423      bProcessing: true,
26424      bServerSide: false,
26425      sAjaxSource: 'tuotteet/inventory/',
26426      aoColumns: [
26427        { sTitle: 'id', mDataProp: 'item_id', bVisible: false },
26428        { sTitle: 'Tuote', mDataProp: 'name', bVisible: true },
26429        { sTitle: 'Varattu', mDataProp: 'reserved', bVisible: true },
26430        { sTitle: 'Vapaana', mDataProp: 'in_stock', bVisible: true },
26431        { sTitle: 'Yhteensä', mDataProp: 'total', bVisible: true },
26432        { sTitle: 'Arvo', mDataProp: 'stock_value', bVisible: true },
26433      ],
26434      aaSorting: [[1, 'desc']],
26435      fnRowCallback: function (element, item, _index) {
26436        $('td:eq(0)', element).html(
26437          $('<a>', { href: item.item_id + '/', name: 'tuotteet', class: 'show_item_history' }).html(
26438            item.name
26439          )
26440        );
26441        return element;
26442      },
26443    });
26444
26445    self.$item_groups_datatable = $('#item_groups_dt').dataTable({
26446      oLanguage: global.dataTablesLanguage,
26447      sPaginationType: 'full_numbers',
26448      iDisplayLength: 25,
26449      bAutoWidth: false,
26450      bJQueryUI: true,
26451      bFilter: true,
26452      bInfo: true,
26453      bPaginate: true,
26454      bProcessing: true,
26455      bServerSide: false,
26456      sAjaxSource: 'tuotteet/get_item_groups_json/',
26457      aoColumns: [/** id **/ { bVisible: false }, /** group_name **/ null],
26458
26459      aaSorting: [[1, 'asc']],
26460
26461      //Called before each row is shown
26462      fnRowCallback: function (nRow, aData) {
26463        var id = aData[0],
26464          group_name = aData[1];
26465        $('td:eq(0)', nRow).html(
26466          $('<a />', {
26467            href: 'tuotteet/itemGroup/' + id + '/',
26468            name: 'ItemGroupDialog',
26469            class: 'show',
26470          }).html(group_name)
26471        );
26472        return nRow;
26473      },
26474    });
26475  };
26476
26477  self.show_item_history = function (itemId) {
26478    if (!itemId) {
26479      return;
26480    }
26481    var $dialog = self.$dialog;
26482    var url = '/tuotteet/history/';
26483    var title = 'Tuotteen varastotilanne';
26484
26485    if ($dialog.hasClass('ui-dialog-content')) {
26486      $dialog.dialog('destroy');
26487    }
26488
26489    $dialog.dialog({
26490      width: 800,
26491      height: 800,
26492      modal: true,
26493      resizable: false,
26494      title: title,
26495      open: function () {
26496        global.show_ajax_loader($dialog);
26497        $.get(url + itemId, function (html) {
26498          $dialog.html(html);
26499        });
26500      },
26501      beforeClose: function (event) {
26502        $('link.js-popup').remove();
26503        $('style.js-popup').remove();
26504        event.stopPropagation();
26505      },
26506      close: function () {
26507        $dialog.dialog('destroy');
26508      },
26509    });
26510  };
26511
26512  self.reportPdfGenerator = function (
26513    year,
26514    month,
26515    type,
26516    product,
26517    layout,
26518    user_id,
26519    sales_aggregate
26520  ) {
26521    var url = window.location.href + '/get_report_pdf/';
26522    // User lists, so we can easily add more filters int the future...
26523    url += year + '/' + month + '/?type[]=' + type;
26524    url += '&layout=' + layout;
26525    url += '&user_id=' + user_id;
26526    url += '&sales_aggregate=' + sales_aggregate;
26527    url += '&product[]=' + product;
26528
26529    window.open(url, '_blank');
26530  };
26531
26532  var processing = false;
26533  self.openVatUpgardeModal = function () {
26534    $dialog.dialog({
26535      width: 600,
26536      height: 400,
26537      modal: true,
26538      resizable: false,
26539      title: 'Muuta tuotteiden 24% ALV kanta',
26540      open: function () {
26541        global.show_ajax_loader($dialog);
26542        var html = `
26543          <p>Muuta kaikkien ALV24% tuotteiden arvonlisäveroksi ALV25,5%</p>
26544          <p>Huomaa tuotteen arvonlisäveroasetuksen vaikutus hintaan kun arvonlisäverokannan muutoksen yhtydessä</p>
26545          <p>Jos “Hinta ei sis ALV” pysyy tuotteen veroton hinta (ALV0) muuttumattomana ja maksettava verollinen hinta nousee.
26546          <br>Jos “Hinta sis. ALV” pienenee tuotteen veroton hinta (ALV0) ja maksettava verollinen hinta pysyy muuttumattomana.
26547          </p>
26548          `;
26549        $dialog.html(html);
26550      },
26551      buttons: [
26552        {
26553          text: 'Peruuta',
26554          click: function () {
26555            $(this).dialog('close');
26556          },
26557        },
26558        {
26559          text: 'Muuta',
26560          click: function () {
26561            if (processing) {
26562              return;
26563            }
26564            processing = true;
26565            jQuery
26566              .ajax({
26567                url: '/tuotteet/upgradeVatPercentage',
26568              })
26569              .done(function (ok) {
26570                $dialog.html(ok.msg);
26571                self.refreshDataTables();
26572                $('#upgrade_vat_pct').remove();
26573                setTimeout(function () {
26574                  $dialog.dialog('destroy');
26575                }, 2500);
26576              })
26577              .error(function (err) {
26578                $dialog.html(err.msg);
26579                setTimeout(function () {
26580                  $dialog.dialog('destroy');
26581                }, 2500);
26582              })
26583              .always(function () {
26584                console.log('always');
26585                processing = false;
26586              });
26587          },
26588        },
26589      ],
26590      close: function () {
26591        $dialog.dialog('destroy');
26592      },
26593    });
26594  };
26595
26596  self.reportGenerator = function (year, month, type, product, layout, user_id, sales_aggregate) {
26597    user_id = user_id || 'all';
26598    year = year || 0;
26599    month = month || 0;
26600    type = type || '';
26601    product = product || '';
26602    layout = layout || '';
26603    sales_aggregate = sales_aggregate || 'separate';
26604    var $dialog = self.$dialog;
26605    var url = window.location.href + '/report/';
26606    var title = 'Varastoraportti';
26607
26608    if ($dialog.hasClass('ui-dialog-content')) {
26609      $dialog.dialog('destroy');
26610    }
26611
26612    $dialog.dialog({
26613      width: 1000,
26614      height: 800,
26615      modal: true,
26616      resizable: false,
26617      title: title,
26618      open: function () {
26619        global.show_ajax_loader($dialog);
26620        // User lists, so we can easily add more filters int the future...
26621        url += year + '/' + month + '/?type[]=' + type;
26622        url += '&layout=' + layout;
26623        url += '&product[]=' + product;
26624        url += '&user_id=' + user_id;
26625        url += '&sales_aggregate=' + sales_aggregate;
26626        $.get(url, function (html) {
26627          $dialog.html(html);
26628        });
26629      },
26630      beforeClose: function (event) {
26631        $('link.js-popup').remove();
26632        $('style.js-popup').remove();
26633        event.stopPropagation();
26634      },
26635      close: function () {
26636        $dialog.dialog('destroy');
26637      },
26638    });
26639  };
26640
26641  self.show_AK_item_group = function (item_group_id) {
26642    var $dialog = self.$dialog;
26643    if ($dialog.hasClass('ui-dialog-content')) {
26644      $dialog.dialog('destroy');
26645    }
26646
26647    var url = '/tuotteet/get_AK_item_group_html/' + item_group_id;
26648
26649    $dialog.dialog({
26650      width: 500,
26651      height: 300,
26652      modal: true,
26653      resizable: false,
26654      open: function () {
26655        global.show_ajax_loader($dialog);
26656
26657        $.get(url, function (html) {
26658          $dialog.html(html);
26659        });
26660      },
26661      buttons: {
26662        Poistu: function () {
26663          $dialog.dialog('destroy');
26664        },
26665      },
26666    });
26667  };
26668
26669  self.init_show_items_item_groups = function () {
26670    self.$dialog.find('#submit').button({ icons: { primary: 'ui-icon-disk' } });
26671
26672    self.$dialog
26673      .find('#close')
26674      .button({ icons: { primary: 'ui-icon-close' } })
26675      .click(function () {
26676        self.$dialog.dialog('close');
26677      });
26678
26679    self.$dialog.find('form').submit(function (e) {
26680      e.preventDefault();
26681
26682      $(this).ajaxSubmit({
26683        dataType: 'json',
26684        beforeSubmit: function () {
26685          global.show_loading_dialog('Tallennetaan...');
26686        },
26687        success: function (responseJSON) {
26688          global.close_loading_dialog();
26689          global.show_message(responseJSON);
26690        },
26691        error: function (response) {
26692          global.close_loading_dialog();
26693          global.show_message(response.responseJSON);
26694        },
26695      });
26696
26697      return false;
26698    });
26699  };
26700
26701  self.delete_item = function (item_id) {
26702    //Show confirm
26703    var $deleteItemDialog = $('<div></div>')
26704      .html('Haluatko varmasti poistaa tuotteen? (Tuote poistuu myös ryhmistä joihin se kuuluu)')
26705      .dialog({
26706        autoOpen: true,
26707        modal: true,
26708        resizable: false,
26709        draggable: false,
26710        title: 'Vahvista tuotteen poisto',
26711        beforeClose: function (event) {
26712          event.stopPropagation();
26713        },
26714        buttons: {
26715          Peruuta: function () {
26716            $(this).dialog('close');
26717          },
26718          Poista: function () {
26719            $(this).dialog('close');
26720
26721            $.ajax({
26722              processData: false,
26723              dataType: 'json',
26724              type: 'GET',
26725              url: '/tuotteet/delete_item/' + item_id + '/',
26726              beforeSend: function () {
26727                global.show_loading_dialog('Poistetaan tuotetta...');
26728              },
26729              success: function (responseJSON) {
26730                global.close_loading_dialog();
26731                global.show_message(responseJSON);
26732
26733                if (self.$items_datatable != null) {
26734                  self.$items_datatable.fnReloadAjax();
26735                }
26736
26737                window.ItemDialog.close();
26738                $deleteItemDialog.dialog('close');
26739              },
26740            });
26741          },
26742        },
26743      });
26744  };
26745
26746  self.edit_items_groups = function (item_id) {
26747    var $dialog = self.$dialog;
26748    var url = '/tuotteet/get_items_item_groups_html/';
26749    var title = '';
26750
26751    if (typeof item_id !== 'undefined') {
26752      url += item_id;
26753      title = 'Valitse tuotteen ryhmät';
26754    } else {
26755      title = 'Uusi tuotepaketti';
26756    }
26757
26758    $dialog.dialog({
26759      width: 600,
26760      modal: true,
26761      resizable: false,
26762      title: title,
26763      dialogClass: 'show-over-flow',
26764      open: function () {
26765        global.show_ajax_loader($dialog);
26766
26767        $.get(url, function (html) {
26768          $dialog.html(html);
26769        });
26770      },
26771      close: function () {
26772        $(this).dialog('destroy');
26773        $(this).remove();
26774      },
26775    });
26776  };
26777
26778  self.delete_item_group = function (item_group_id) {
26779    $('<div></div>')
26780      .html(
26781        'Haluatko varmasti poistaa kyseisen tuotepaketin? (Tuotteet säilyvät tuoterekisterissä)'
26782      )
26783      .dialog({
26784        autoOpen: true,
26785        modal: true,
26786        resizable: false,
26787        draggable: false,
26788        title: 'Vahvista tuotepaketin poisto',
26789        beforeClose: function (event) {
26790          event.stopPropagation();
26791        },
26792        buttons: {
26793          Peruuta: function () {
26794            $(this).dialog('close');
26795          },
26796          Poista: function () {
26797            $(this).dialog('close');
26798
26799            $.ajax({
26800              processData: false,
26801              dataType: 'json',
26802              type: 'GET',
26803              url: '/tuotteet/delete_item_group/' + item_group_id + '/',
26804              beforeSend: function () {
26805                global.show_loading_dialog('Poistetaan tuotepakettia...');
26806              },
26807              success: function (responseJSON) {
26808                global.close_loading_dialog();
26809                global.show_message(responseJSON);
26810
26811                if (self.$items_datatable != null) {
26812                  self.$items_datatable.fnReloadAjax();
26813                }
26814
26815                if (self.$item_groups_datatable != null) {
26816                  self.$item_groups_datatable.fnReloadAjax();
26817                }
26818
26819                window.ItemGroupDialog.close();
26820              },
26821            });
26822          },
26823        },
26824      });
26825  };
26826
26827  self.refreshDataTables = function () {
26828    if (self.$items_datatable != null) {
26829      self.$items_datatable.fnReloadAjax();
26830    }
26831
26832    if (self.$item_groups_datatable != null) {
26833      self.$item_groups_datatable.fnReloadAjax();
26834    }
26835  };
26836
26837  return self;
26838})();
26839
26840;/**
26841 *  Version 2.4.1 Copyright (C) 2013
26842 *  Tested in IE 11, FF 28.0 and Chrome 33.0.1750.154
26843 *  No official support for other browsers, but will TRY to accommodate challenges in other browsers.
26844 *  Example:
26845 *      Print Button: <div id="print_button">Print</div>
26846 *      Print Area  : <div class="PrintArea" id="MyId" class="MyClass"> ... html ... </div>
26847 *      Javascript  : <script>
26848 *                       $("div#print_button").click(function(){
26849 *                           $("div.PrintArea").printArea( [OPTIONS] );
26850 *                       });
26851 *                     </script>
26852 *  options are passed as json (example: {mode: "popup", popClose
26852: false})
26853 *
26854 *  {OPTIONS}   | [type]     | (default), values      | Explanation
26855 *  ---------   | ---------  | ---------------------- | -----------
26856 *  @mode       | [string]   | (iframe),popup         | printable window is either iframe or browser popup
26857 *  @popHt      | [number]   | (500)                  | popup window height
26858 *  @popWd      | [number]   | (400)                  | popup window width
26859 *  @popX       | [number]   | (500)                  | popup window screen X position
26860 *  @popY       | [number]   | (500)                  | popup window screen Y position
26861 *  @popTitle   | [string]   | ('')                   | popup window title element
26862 *  @popClose   | [boolean]  | (false),true           | popup window close after printing
26863 *  @extraCss   | [string]   | ('')                   | comma separated list of extra css to include
26864 *  @retainAttr | [string[]] | ["id","class","style"] | string array of attributes to retain for the containment area. (ie: id, style, class)
26865 *  @standard   | [string]   | strict, loose, (html5) | Only for popup. For html 4.01, strict or loose document standard, or html 5 standard
26866 *  @extraHead  | [string]   | ('')                   | comma separated list of extra elements to be appended to the head tag
26867 */
26868(function($) {
26869    var counter = 0;
26870    var modes = { iframe : "iframe", popup : "popup" };
26871    var standards = { strict : "strict", loose : "loose", html5 : "html5" };
26872    var defaults = { mode       : modes.iframe,
26873                     standard   : standards.html5,
26874                     popHt      : 500,
26875                     popWd      : 400,
26876                     popX       : 200,
26877                     popY       : 200,
26878                     popTitle   : '',
26879                     popClose   : false,
26880                     extraCss   : '',
26881                     extraHead  : '',
26882                     retainAttr : ["id","class","style"] };
26883
26884    var settings = {};//global settings
26885
26886    $.fn.printArea = function( options )
26887    {
26888        $.extend( settings, defaults, options );
26889
26890        counter++;
26891        var idPrefix = "printArea_";
26892        $( "[id^=" + idPrefix + "]" ).remove();
26893
26894        settings.id = idPrefix + counter;
26895
26896        var $printSource = $(this);
26897
26898        var PrintAreaWindow = PrintArea.getPrintWindow();
26899
26900        PrintArea.write( PrintAreaWindow.doc, $printSource );
26901
26902        setTimeout( function () { PrintArea.print( PrintAreaWindow ); }, 1000 );
26903    };
26904
26905    var PrintArea = {
26906        print : function( PAWindow ) {
26907            var paWindow = PAWindow.win;
26908
26909            $(PAWindow.doc).ready(function(){
26910                paWindow.focus();
26911                paWindow.print();
26912
26913                if ( settings.mode == modes.popup && settings.popClose )
26914                    setTimeout(function() { paWindow.close(); }, 2000);
26915            });
26916        },
26917        write : function ( PADocument, $ele ) {
26918            PADocument.open();
26919            PADocument.write( PrintArea.docType() + "<html>" + PrintArea.getHead() + PrintArea.getBody( $ele ) + "</html>" );
26920            PADocument.close();
26921        },
26922        docType : function() {
26923            if ( settings.mode == modes.iframe ) return "";
26924
26925            if ( settings.standard == standards.html5 ) return "<!DOCTYPE html>";
26926
26927            var transitional = settings.standard == standards.loose ? " Transitional" : "";
26928            var dtd = settings.standard == standards.loose ? "loose" : "strict";
26929
26930            return '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01' + transitional + '//EN" "http://www.w3.org/TR/html4/' + dtd +  '.dtd">';
26931        },
26932        getHead : function() {
26933            var extraHead = "";
26934            var links = "";
26935
26936            if ( settings.extraHead ) settings.extraHead.replace( /([^,]+)/g, function(m){ extraHead += m });
26937
26938            $(document).find("link")
26939                .filter(function(){ // Requirement: <link> element MUST have rel="stylesheet" to be considered in print document
26940                        var relAttr = $(this).attr("rel");
26941                        return ($.type(relAttr) === 'undefined') == false && relAttr.toLowerCase() == 'stylesheet';
26942                    })
26943                .filter(function(){ // Include if media is undefined, empty, print or all
26944                        var mediaAttr = $(this).attr("media");
26945                        return $.type(mediaAttr) === 'undefined' || mediaAttr == "" || mediaAttr.toLowerCase() == 'print' || mediaAttr.toLowerCase() == 'all'
26946                    })
26947                .each(function(){
26948                        links += '<link type="text/css" rel="stylesheet" href="' + $(this).attr("href") + '" >';
26949                    });
26950            if ( settings.extraCss ) settings.extraCss.replace( /([^,\s]+)/g, function(m){ links += '<link type="text/css" rel="stylesheet" href="' + m + '">' });
26951
26952            return "<head><title>" + settings.popTitle + "</title>" + extraHead + links + "</head>";
26953        },
26954        getBody : function ( elements ) {
26955            var htm = "";
26956            var attrs = settings.retainAttr;
26957            elements.each(function() {
26958                var ele = PrintArea.getFormData( $(this) );
26959
26960                var attributes = ""
26961                for ( var x = 0; x < attrs.length; x++ )
26962                {
26963                    var eleAttr = $(ele).attr( attrs[x] );
26964                    if ( eleAttr ) attributes += (attributes.length > 0 ? " ":"") + attrs[x] + "='" + eleAttr + "'";
26965                }
26966
26967                htm += '<div ' + attributes + '>' + $(ele).html() + '</div>';
26968            });
26969
26970            return "<body>" + htm + "</body>";
26971        },
26972        getFormData : function ( ele ) {
26973            var copy = ele.clone();
26974            var copiedInputs = $("input,select,textarea", copy);
26975            $("input,select,textarea", ele).each(function( i ){
26976                var typeInput = $(this).attr("type");
26977                if ($.type(typeInput) === 'undefined') typeInput = $(this).is("select") ? "select" : $(this).is("textarea") ? "textarea" : "";
26978                var copiedInput = copiedInputs.eq( i );
26979
26980                if ( typeInput == "radio" || typeInput == "checkbox" ) copiedInput.attr( "checked", $(this).is(":checked") );
26981                else if ( typeInput == "text" || typeInput == "" ) copiedInput.attr( "value", $(this).val() );
26982                else if ( typeInput == "select" )
26983                    $(this).find( "option" ).each( function( i ) {
26984                        if ( $(this).is(":selected") ) $("option", copiedInput).eq( i ).attr( "selected", true );
26985                    });
26986                else if ( typeInput == "textarea" ) copiedInput.text( $(this).val() );
26987            });
26988            return copy;
26989        },
26990        getPrintWindow : function () {
26991            switch ( settings.mode )
26992            {
26993                case modes.iframe :
26994                    var f = new PrintArea.Iframe();
26995                    return { win : f.contentWindow || f, doc : f.doc };
26996                case modes.popup :
26997                    var p = new PrintArea.Popup();
26998                    return { win : p, doc : p.doc };
26999            }
27000        },
27001        Iframe : function () {
27002            var frameId = settings.id;
27003            var iframeStyle = 'border:0;position:absolute;width:0px;height:0px;right:0px;top:0px;';
27004            var iframe;
27005
27006            try
27007            {
27008                iframe = document.createElement('iframe');
27009                document.body.appendChild(iframe);
27010                $(iframe).attr({ style: iframeStyle, id: frameId, src: "#" + new Date().getTime() });
27011                iframe.doc = null;
27012                iframe.doc = iframe.contentDocument ? iframe.contentDocument : ( iframe.contentWindow ? iframe.contentWindow.document : iframe.document);
27013            }
27014            catch( e ) { throw e + ". iframes may not be supported in this browser."; }
27015
27016            if ( iframe.doc == null ) throw "Cannot find document.";
27017
27018            return iframe;
27019        },
27020        Popup : function () {
27021            var windowAttr = "location=yes,statusbar=no,directories=no,menubar=no,titlebar=no,toolbar=no,dependent=no";
27022            windowAttr += ",width=" + settings.popWd + ",height=" + settings.popHt;
27023            windowAttr += ",resizable=yes,screenX=" + settings.popX + ",screenY=" + settings.popY + ",personalbar=no,scrollbars=yes";
27024
27025            var newWin = window.open( "", "_blank",  windowAttr );
27026
27027            newWin.doc = newWin.document;
27028
27029            return newWin;
27030        }
27031    };
27032})(jQuery);
27033
27034;/**
27035 * Functionality for ajax calls, used by app admin to update part payments.
27036 * @param {Object} opts [Holds the data for the partpayment about to be edited.]
27037 */
27038var editPartPaymentData = function(opts) {
27039  var server = '/iv_laskutus_ja_reskontra/update_partpayment_data';
27040  var serverRemove = '/iv_laskutus_ja_reskontra/remove_item';
27041  var serverAdd = '/iv_laskutus_ja_reskontra/add_item';
27042  var serverEdit = '/iv_laskutus_ja_reskontra/edit_item';
27043  var options = {
27044    'partPaymentId': opts.partPaymentId,
27045    'customerId': opts.customerId
27046  };
27047
27048  /**
27049   * General ajax changes. See serverside for the posibilities.
27050   */
27051  $('.edit_osamaksu_data').editable(server, {
27052    submitdata: options,
27053    id: 'field',
27054    indicator : 'Tallennetaan...'
27055  });
27056
27057  /**
27058   * Edit the signature type. Either pankkitunniste or by hand.
27059   *
27060   */
27061  $('.edit_osamaksu_current_signature').editable(server, {
27062    data: "{'written':'Allekirjoituksella'," +
27063          "'tupas':'Pankkitunnisteilla'," +
27064          "'selected': '" + opts.signatureType + "'}",
27065    submitdata: options,
27066    type: 'select',
27067    id: 'field',
27068    submit : 'OK',
27069    indicator : 'Tallennetaan...'
27070  });
27071
27072  /**
27073   * Edit a item in the partpayment.
27074   * @type Promise.
27075   */
27076  $('.edit-partpayment-item').editable(function(value) {
27077
27078    var itemId = $(this).parent('tr').data('item');
27079    var fieldInEdit = $(this).attr('id');
27080
27081    var editedItemData = {
27082      itemId: itemId,
27083      value: value,
27084      field: fieldInEdit
27085    };
27086    $.post(serverEdit, editedItemData, function() {
27087    })
27088    .then(function(data) {
27089      $('a[href=' + opts.partPaymentId + ']').click();
27090    })
27091    .fail(function(e) {
27092      alert("Palvelimella tapahtui virhe!", e);
27093    });
27094  });
27095
27096  /**
27097   * Add a new item to the partpayment.
27098   * Defaults to an empty object in the database.
27099   * @type Promise.
27100   */
27101  $('button#add-item').click(function() {
27102    var addToId = options.partPaymentId;
27103    var data = { addToPartPaymentId: addToId };
27104
27105    $.post(serverAdd, data, function() {
27106    })
27107    .then(function(data){
27108      $('a[href=' + addToId + ']').click();
27109    })
27110    .fail(function(e) {
27111      alert("Palvelimella tapahtui virhe!", e);
27112    });
27113  });
27114
27115
27116  /**
27117   * Remove a item from the partpayment.
27118   * @type Promise.
27119   */
27120  $('button.remove').click(function() {
27121    if (window.confirm("Haluatko varmasti poistaa kyseisen rivin?")) {
27122
27123      var row = $(this).parent().parent('tr');
27124      var itemId = $(row).data('item');
27125      var data = { rowToDelete: itemId };
27126
27127      $.post(serverRemove, data, function() {
27128      })
27129      .then(function(data) {
27130        var resp = JSON.parse(data);
27131        row.fadeOut(500);
27132      })
27133      .fail(function(e) {
27134        alert("Palvelimella tapahtui virhe!", e);
27135      });
27136
27137    }
27138  });
27139
27140  /**
27141   * Edit downpayment and total sum. Updated fields
27142   * and refreshed the dialog on callback.
27143   */
27144  $('.edit-osamaksu-sums').editable(server, {
27145    submitdata: options,
27146    id: 'field',
27147    indicator : 'Tallennetaan...',
27148    callback : function() {
27149      $('a[href=' + opts.partPaymentId + ']').click();
27150    }
27151  });
27152
27153  /**
27154   * @BETA-version (0.0.1)
27155   * Fixed on the Server.
27156   */
27157
27158  $('.edit_osamaksu_payment_parts').editable(function(val, settings) {
27159    var partPaymentData = {
27160      partPaymentId: opts.partPaymentId,
27161      field: 'part_payment_maksuerat',
27162      value: val,
27163    };
27164    $.post(server, partPaymentData, function() {
27165    })
27166    .then(function(a,b,c) {
27167      $('a[href=' + opts.partPaymentId + ']').click();
27168    });
27169
27170  }, {
27171    data: "{'3':'3'," +
27172          "'6':'6'," +
27173          "'9':'9'," +
27174          "'12':'12'," +
27175          "'18':'18'," +
27176          "'24':'24'," +
27177          "'selected': '" + opts.currentPaymentRate + "'}",
27178    type: 'select',
27179    submit : 'OK'
27180  });
27181
27182};
27183
27184;function VehicleInfoCheckVM(opts) {
27185  var self = this;
27186  
27187  self.vehicleInfoSearchMeta = {
27188    id : ko.observable(),
27189    requestParam:  ko.observable(),
27190    daysOld: ko.observable(),
27191    datetime : ko.observable(),
27192    dataSource: ko.observable(),
27193    dataSourceLongText: ko.observable(),
27194    dataSourceShortText: ko.observable()
27195  };
27196
27197  self.id = ko.computed(function(){
27198    return ko.toJS(self.vehicleInfoSearchMeta.id);
27199  });
27200
27201  //self.searchAgeVisual = ko.computed(window.trafiExtras.visualizeSearchAge, self);
27202  self.searchAge = ko.computed(window.trafiExtras.searchAge, self);
27203
27204  self.vehicleInfo = {
27205    reg_no: ko.observable(''),
27206    vehicle_class: ko.observable(''),
27207    vehicle_brand: ko.observable(''),
27208    vehicle_model: ko.observable(''),
27209    vehicle_brand_and_model: ko.observable(''),
27210    vehicle_commercial_model: ko.observable(''),
27211    vehicle_status: ko.observable(''),
27212    vehicle_model_year: ko.observable(''),
27213    vehicle_color: ko.observable(''),
27214    serial_no: ko.observable(''),
27215    initialization_date: ko.observable(''),
27216    first_registration_date: ko.observable(''),
27217    last_inspection_date: ko.observable(''),
27218    last_inspection_result: ko.observable(''),
27219    last_inspection_result_description: ko.observable(''),
27220    next_inspection_date: ko.observable(''),
27221    restriction_info: ko.observable(''),
27222    remarks: ko.observable(''),
27223    fuel: ko.observable(''),
27224    transmission: ko.observable(''),
27225    drive: ko.observable(''),
27226    displacement: ko.observable(''),
27227    max_net_effect: ko.observable(''),
27228    max_net_weight: ko.observable(''),
27229    max_tech_net_weight: ko.observable(''),
27230    length: ko.observable(''),
27231    width: ko.observable(''),
27232    height: ko.observable(''),
27233    weight: ko.observable(''),
27234    holder_name: ko.observable(''),
27235    holder_address: ko.observable(''),
27236    owner_name: ko.observable(''),
27237    owner_address: ko.observable(''),
27238  };
27239
27240  self.insuranceInfo = {
27241    insurance_company: ko.observable(''),
27242    insurance_start_date: ko.observable(''),
27243    insurance_end_date: ko.observable(''),
27244    insured_party: ko.observable('')
27245  };
27246
27247  self.restrictionInfos = ko.observableArray();
27248  self.ownersHolders = ko.observableArray();
27249  self.transferPermit = ko.observable(null);
27250
27251  self.ownersHoldersConsumers = ko.computed(function (){
27252
27253    var consumers = [], customerList = [], ownersHolders = ko.toJS(self.ownersHolders);
27254
27255    console.log('VehicleInfoCheckVM::ownersHolders:', ownersHolders);
27256    
27257    if( ! ownersHolders)
27258      return [];
27259
27260    ownersHolders
27261        .filter(function (ownerHolder){
27262          return ownerHolder.customer_type === 'person' && ownerHolder.restriction < 1;
27263        })
27264        .forEach(function(ownerHolder) {
27265
27266          var trafiRes = $.extend(true, {}, ownerHolder);
27267          var trafiName = trafiRes.name || '';
27268          var nameParts = (trafiRes.name || '').split(' ');
27269          var trafiNameLen = nameParts.length;
27270          var hasDeath = nameParts[trafiNameLen -1] === '(Kuolinpesä)';
27271          var lName = hasDeath ? nameParts[0] + ' (Kuolinpesä)' : nameParts[0];
27272          var fName = hasDeath ? nameParts.slice(1, trafiNameLen -1).join(' ') : nameParts.slice(1, trafiNameLen).join(' ');
27273          console.table({hasDeath: hasDeath, lName: lName, fName: fName, nameParts: nameParts, trafiNameLen: trafiNameLen, part: nameParts[-1]});
27274           var moddedTrafiResult = Object.assign(trafiRes, {
27275            displayName: 'Trafi / ' + trafiRes.ownership_type_description + ' / ' + trafiRes.name,
27276            company_name: trafiRes.name,
27277            // business_id: trafiRes.identifier,
27278            customer_type: 0,
27279            lastname: lName,
27280            firstname: fName,
27281            // lastname: trafiName.split(' ')[0] + ' ' 
27282            // firstname: trafiName
27283            //     .split(' ')
27284            //     .slice(1, trafiNameLen)
27285            //     .join(' '),
27286            source: null,
27287          });
27288          // self.customerList.unshift(moddedTrafiResult);
27289          //     customerList.unshift(moddedTrafiResult);
27290
27291          // Remove stuff not related to the consumer
27292          moddedTrafiResult.company_name = null;
27293          moddedTrafiResult.business_id = null;
27294
27295          consumers.push(moddedTrafiResult);
27296        });
27297
27298    return consumers;
27299  });
27300
27301  self.ownersHoldersCompanies = ko.computed(function (){
27302
27303    var companies = [], customerList = [], ownersHolders = ko.toJS(self.ownersHolders);
27304
27305    if( ! ownersHolders)
27306      return [];
27307    
27308    ownersHolders
27309        .filter(function (ownerHolder){
27310          return ownerHolder.customer_type === 'company' && ownerHolder.restriction < 1;
27311        })
27312        .forEach(function(ownerHolder) {
27313
27314          var trafiRes = $.extend(true, {}, ownerHolder);
27315          var trafiName = trafiRes.name || '';
27316          var trafiNameLen = (trafiRes.name || '').split(' ').length;
27317          var moddedTrafiResult = Object.assign(trafiRes, {
27318            displayName: 'Trafi / ' + trafiRes.ownership_type_description + ' / ' + trafiRes.name,
27319            company_name: trafiRes.name,
27320            business_id: trafiRes.identifier,
27321            customer_type: 1,
27322            lastname: trafiName.split(' ')[0],
27323            firstname: trafiName
27324                .split(' ')
27325                .slice(1, trafiNameLen)
27326                .join(' '),
27327            source: null,
27328          });
27329          // self.customerList.unshift(moddedTrafiResult);
27330
27331          // Remove stuff not related to the company
27332          moddedTrafiResult.firstname = null;
27333          moddedTrafiResult.lastname = null;
27334
27335          ownerHolder.business_id = ownerHolder.identifier;
27336
27337          // @HACK override addresses for a few special cases
27338          // Santander consumer finance
27339          if (ownerHolder.business_id === '2076455-0') {
27340            ownerHolder.address = 'PL 626';
27341            ownerHolder.zipcode = '00026';
27342            ownerHolder.city = 'BASWARE';
27343            ownerHolder.e_invoice_address = '00372076455001';
27344            ownerHolder.e_invoice_operator = 'BAWCFI22';
27345            ownerHolder.delivery_by = 'e_invoice';
27346          }
27347
27348          // Veho Oy Ab
27349          if (ownerHolder.business_id === '0115761-6') {
27350            ownerHolder.address = 'PL 1004';
27351            ownerHolder.contact_person = 'Ostolaskut';
27352            ownerHolder.zipcode = '01511';
27353            ownerHolder.city = 'VANTAA';
27354            ownerHolder.e_invoice_address = '003701157616';
27355            ownerHolder.e_invoice_operator = 'BAWCFI22';
27356            ownerHolder.delivery_by = 'e_invoice';
27357          }
27358
27359          // LeasePlan Finland Oy
27360          if (ownerHolder.business_id === '1440371-6') {
27361            ownerHolder.address = 'PL 1400';
27362            ownerHolder.zipcode = '02066';
27363            ownerHolder.city = 'DOCUSCAN';
27364            ownerHolder.e_invoice_address = 'TE003714403716';
27365            ownerHolder.e_invoice_operator = '003701011385';
27366            ownerHolder.delivery_by = 'e_invoice';
27367          }
27368
27369          companies.push(moddedTrafiResult);
27370
27371          companies.forEach(function(key, idx) {
27372            companies[idx].company_name = key.name;
27373          });
27374        });
27375
27376    return companies;
27377  });
27378
27379  self.parseVehicleInfo = function(data) {
27380    
27381    console.log('VehicleInfoCheckVm, data:', data);
27382    
27383    self.vehicleInfoSearchMeta.id(data.id);
27384    self.vehicleInfoSearchMeta.requestParam(data.searchMeta.requestParam);
27385    self.vehicleInfoSearchMeta.dataSource(data.searchMeta.dataSource);
27386    self.vehicleInfoSearchMeta.datetime(data.searchMeta.datetime);
27387    self.vehicleInfoSearchMeta.daysOld(data.searchMeta.daysOld);
27388    self.vehicleInfoSearchMeta.dataSourceLongText(data.searchMeta.dataSourceLongText ? data.searchMeta.dataSourceLongText : '')
27389    self.vehicleInfoSearchMeta.dataSourceShortText(data.searchMeta.dataSourceShortText ? data.searchMeta.dataSourceShortText : '')
27390
27391    // Vehicle info
27392    self.vehicleInfo.reg_no(data.vehicleInfo.reg_no);
27393    self.vehicleInfo.serial_no(data.vehicleInfo.serial_no);
27394    self.vehicleInfo.vehicle_class(data.vehicleInfo.vehicle_class);
27395    self.vehicleInfo.vehicle_brand(data.vehicleInfo.vehicle_brand);
27396    self.vehicleInfo.vehicle_model(data.vehicleInfo.vehicle_model);
27397    self.vehicleInfo.vehicle_commercial_model(data.vehicleInfo.vehicle_commercial_model);
27398    self.vehicleInfo.vehicle_brand_and_model(data.vehicleInfo.vehicle_brand_and_model);
27399    self.vehicleInfo.vehicle_status(data.vehicleInfo.vehicle_status);
27400    self.vehicleInfo.vehicle_model_year(data.vehicleInfo.vehicle_model_year);
27401    self.vehicleInfo.vehicle_color(data.vehicleInfo.vehicle_color);
27402    self.vehicleInfo.fuel(data.vehicleInfo.fuel);
27403    self.vehicleInfo.transmission(data.vehicleInfo.transmission);
27404    self.vehicleInfo.drive(data.vehicleInfo.drive);
27405    self.vehicleInfo.displacement(data.vehicleInfo.displacement);
27406    self.vehicleInfo.max_net_effect(data.vehicleInfo.max_net_effect);
27407    self.vehicleInfo.max_net_weight(data.vehicleInfo.max_net_weight);
27408    self.vehicleInfo.max_tech_net_weight(data.vehicleInfo.max_tech_net_weight);
27409    self.vehicleInfo.length(data.vehicleInfo.length);
27410    self.vehicleInfo.width(data.vehicleInfo.width);
27411    self.vehicleInfo.height(data.vehicleInfo.height);
27412    self.vehicleInfo.weight(data.vehicleInfo.weight);
27413    self.vehicleInfo.initialization_date(data.vehicleInfo.initialization_date);
27414    self.vehicleInfo.first_registration_date(data.vehicleInfo.first_registration_date);
27415    self.vehicleInfo.last_inspection_date(data.vehicleInfo.last_inspection_date);
27416    self.vehicleInfo.last_inspection_result(data.vehicleInfo.last_inspection_result);
27417    self.vehicleInfo.last_inspection_result_description(data.vehicleInfo.last_inspection_result_description);
27418    self.vehicleInfo.next_inspection_date(data.vehicleInfo.next_inspection_date);
27419    self.vehicleInfo.remarks(data.vehicleInfo.remarks);
27420    self.vehicleInfo.holder_name(data.vehicleInfo.holder_name);
27421    self.vehicleInfo.holder_address(data.vehicleInfo.holder_address);
27422    self.vehicleInfo.owner_name(data.vehicleInfo.owner_name);
27423    self.vehicleInfo.owner_address(data.vehicleInfo.owner_address);
27424
27425    // RestrictionInfos
27426    // reset observableArray
27427    self.restrictionInfos([]);
27428
27429    _.each(data.restrictionInfos, function(restrictionInfo) {
27430      self.restrictionInfos.push(restrictionInfo);
27431    });
27432
27433    self.transferPermit(null);
27434    if(data.transferPermit){
27435      var applicant = (data.transferPermit && data.transferPermit.applicant) ? data.transferPermit.applicant : {};
27436      self.transferPermit({
27437        purposeOfUse: data.transferPermit.purposeOfUse ? data.transferPermit.purposeOfUse : '',
27438        validityStarts: data.transferPermit.validityStarts ? data.transferPermit.validityStarts : '',
27439        validityEnds: data.transferPermit.validityEnds ? data.transferPermit.validityEnds : '',
27440        lastNameMainUnit: applicant.lastNameMainUnit ? applicant.lastNameMainUnit : '',
27441        firstNameSubUnit: applicant.firstNameSubUnit ? applicant.firstNameSubUnit : '',
27442        streetAddress: applicant.streetAddress ? applicant.streetAddress : '',
27443        postalCode: applicant.postalCode ? applicant.postalCode : '',
27444        city: applicant.city ? applicant.city : '',
27445        route: data.transferPermit.route ? data.transferPermit.route : ''
27446      });
27447    }
27448
27449    // Holders info
27450    // reset observableArray
27451    self.ownersHolders([]);
27452
27453    _.each(data.ownersHolders, function(ownerHolder) {
27454      self.ownersHolders.push(ownerHolder);
27455    });
27456
27457    // Insurance info
27458    self.insuranceInfo.insurance_company(data.insuranceInfo.insurance_company);
27459    self.insuranceInfo.insurance_start_date(data.insuranceInfo.insurance_start_date);
27460    self.insuranceInfo.insurance_end_date(data.insuranceInfo.insurance_end_date);
27461    self.insuranceInfo.insured_party(data.insuranceInfo.insured_party);
27462
27463    self.printVehicleInfo = function() {
27464      $('#vehicle-info-check').printArea({
27465        extraCss: '/assets/css/new/bootstrap-3.2.0.min.css, /assets/css/kuormakirja-print.css'
27466      });
27467    };
27468
27469    self.closeJQueryUIVehicleInfoDialog = function() {
27470      global.$dialog.dialog("close");
27471    };
27472
27473  };
27474
27475  if (opts) {
27476    self.parseVehicleInfo(opts);
27477  }
27478
27479};
27480
27481;// Common features for enhanced Trafi searches
27482window.trafiExtras = function() {
27483  var changeTimeToFinnishStyle = function(timeString) {
27484    if (timeString === '0000-00-00') { return 'Aikaa ei asetettu'; }
27485    var time = timeString.split('-');
27486    return [time[2], time[1], time[0]].join('.');
27487  };
27488
27489  var renderTRecordStatus = function(code) {
27490    switch(code) {
27491    case 'deleted': return 'Poistettu';
27492    case 'payment_undefined': return 'Laskuttamaton';
27493    case 'aggregate': return 'Koonti';
27494    case 'unfinished': return 'Kesken';
27495    case 'complete': return 'Valmis';
27496    default: return 'Tuntematon';
27497    }
27498  };
27499
27500  var renderTOrderStatus = function(code) {
27501    switch(code) {
27502      case 'pending_acceptance': return 'Odottaa kuittausta';
27503    case 'open': return 'Avoin';
27504    case 'accepted': return 'Hyväksytty';
27505    case 'assigned': return 'Osoitettu';
27506    case 'accepted': return 'Avoin';
27507    case 'cancelled': return 'Peruutettu';
27508    case 'autoliitto': return 'Autoliitto';
27509    case 'towing_record_created': return 'Kuormakirja luotu';
27510    default: return 'Tuntematon ('+code+')';
27511    }
27512  };
27513
27514  var togglePreviousHistory = function() {
27515    $('.previous-searches').toggle();
27516    $('.previous-searches-open').toggle();
27517    $('.previous-searches-close').toggle();
27518  };
27519
27520  /*
27521  var visualizeSearchAge = function() {
27522    if(this.vehicleInfoSearchMeta.dataSource() == 'undefined'){
27523      return '#d9534f';
27524    }
27525    var days = Number(this.vehicleInfoSearchMeta.daysOld());
27526    if (days <= 14) { return '#5cb85c'; }
27527    if (days > 14 && days <= 30) { return '#f0ad4e'; }
27528    return '#d9534f';
27529  };
27530*/
27531  
27532  var searchAge = function() {
27533    return this.vehicleInfoSearchMeta.dataSourceLongText();
27534    // var ago = Number(this.vehicleInfoSearchMeta.daysOld());
27535    // if (isNaN(ago)) { return 'ei haettu Traficomista'; }
27536    // var time = this.vehicleInfoSearchMeta.datetime();
27537    // if (!time) { return ''; }
27538    // var splitted = time.split(' ');
27539    // var dataSource
27540
27541    // switch(this.vehicleInfoSearchMeta.dataSource()){
27542    //   case 'trafi': 
27543    //     dataSource = 'haettu Traficomista';
27544    //     break;
27545    //   case 'sos': 
27546    //     dataSource = 'saatu SOS tilauksen yhteydessä';
27547    //     break;
27548    //   default: 
27549    //     return 'ei haettu Traficomista';
27550    // }
27551
27552    // switch(ago) {
27553    // case 0: return dataSource + ' tänään klo. ' + splitted[1];
27554    // case 1: return dataSource + ' eilen klo. ' + splitted[1];
27555    // default: return dataSource + ' ' + splitted[0] + ', ' + ago + ' päivää sitten';
27556    // }
27557  };
27558
27559  return {
27560    changeTimeToFinnishStyle: changeTimeToFinnishStyle,
27561    renderTRecordStatus: renderTRecordStatus,
27562    togglePreviousHistory: togglePreviousHistory,
27563    searchAge: searchAge,
27564    renderTOrderStatus: renderTOrderStatus
27565  };
27566}();
27567
27568;/*!
27569 * Datepicker for Bootstrap v1.7.0-dev (https://github.com/eternicode/bootstrap-datepicker)
27570 *
27571 * Copyright 2012 Stefan Petre
27572 * Improvements by Andrew Rowls
27573 * Licensed under the Apache License v2.0 (http://www.apache.org/licenses/LICENSE-2.0)
27574 */(function(factory){
27575    if (typeof define === "function" && define.amd) {
27576        define(["jquery"], factory);
27577    } else if (typeof exports === 'object') {
27578        factory(require('jquery'));
27579    } else {
27580        factory(jQuery);
27581    }
27582}(function($, undefined){
27583
27584  function UTCDate(){
27585    return new Date(Date.UTC.apply(Date, arguments));
27586  }
27587  function UTCToday(){
27588    var today = new Date();
27589    return UTCDate(today.getFullYear(), today.getMonth(), today.getDate());
27590  }
27591  function isUTCEquals(date1, date2) {
27592    return (
27593      date1.getUTCFullYear() === date2.getUTCFullYear() &&
27594      date1.getUTCMonth() === date2.getUTCMonth() &&
27595      date1.getUTCDate() === date2.getUTCDate()
27596    );
27597  }
27598  function alias(method){
27599    return function(){
27600      return this[method].apply(this, arguments);
27601    };
27602  }
27603  function isValidDate(d) {
27604    return d && !isNaN(d.getTime());
27605  }
27606
27607  var DateArray = (function(){
27608    var extras = {
27609      get: function(i){
27610        return this.slice(i)[0];
27611      },
27612      contains: function(d){
27613        // Array.indexOf is not cross-browser;
27614        // $.inArray doesn't work with Dates
27615        var val = d && d.valueOf();
27616        for (var i=0, l=this.length; i < l; i++)
27617          if (this[i].valueOf() === val)
27618            return i;
27619        return -1;
27620      },
27621      remove: function(i){
27622        this.splice(i,1);
27623      },
27624      replace: function(new_array){
27625        if (!new_array)
27626          return;
27627        if (!$.isArray(new_array))
27628          new_array = [new_array];
27629        this.clear();
27630        this.push.apply(this, new_array);
27631      },
27632      clear: function(){
27633        this.length = 0;
27634      },
27635      copy: function(){
27636        var a = new DateArray();
27637        a.replace(this);
27638        return a;
27639      }
27640    };
27641
27642    return function(){
27643      var a = [];
27644      a.push.apply(a, arguments);
27645      $.extend(a, extras);
27646      return a;
27647    };
27648  })();
27649
27650
27651  // Picker object
27652
27653  var Datepicker = function(element, options){
27654    $(element).data('datepicker', this);
27655    this._process_options(options);
27656
27657    this.dates = new DateArray();
27658    this.viewDate = this.o.defaultViewDate;
27659    this.focusDate = null;
27660
27661    this.element = $(element);
27662    this.isInline = false;
27663    this.isInput = this.element.is('input');
27664    this.component = this.element.hasClass('date') ? this.element.find('.add-on, .input-group-addon, .btn') : false;
27665    this.hasInput = this.component && this.element.find('input').length;
27666    if (this.component && this.component.length === 0)
27667      this.component = false;
27668
27669    this.picker = $(DPGlobal.template);
27670
27671    // Checking templates and inserting
27672    if (this._check_template(this.o.templates.leftArrow)) {
27673      this.picker.find('.prev').html(this.o.templates.leftArrow);
27674    }
27675    if (this._check_template(this.o.templates.rightArrow)) {
27676      this.picker.find('.next').html(this.o.templates.rightArrow);
27677    }
27678
27679    this._buildEvents();
27680    this._attachEvents();
27681
27682    if (this.isInline){
27683      this.picker.addClass('datepicker-inline').appendTo(this.element);
27684    }
27685    else {
27686      this.picker.addClass('datepicker-dropdown dropdown-menu');
27687    }
27688
27689    if (this.o.rtl){
27690      this.picker.addClass('datepicker-rtl');
27691    }
27692
27693    this.viewMode = this.o.startView;
27694
27695    if (this.o.calendarWeeks)
27696      this.picker.find('thead .datepicker-title, tfoot .today, tfoot .clear')
27697            .attr('colspan', function(i, val){
27698              return parseInt(val) + 1;
27699            });
27700
27701    this._allow_update = false;
27702
27703    this.setStartDate(this._o.startDate);
27704    this.setEndDate(this._o.endDate);
27705    this.setDaysOfWeekDisabled(this.o.daysOfWeekDisabled);
27706    this.setDaysOfWeekHighlighted(this.o.daysOfWeekHighlighted);
27707    this.setDatesDisabled(this.o.datesDisabled);
27708
27709    this.fillDow();
27710    this.fillMonths();
27711
27712    this._allow_update = true;
27713
27714    this.update();
27715    this.showMode();
27716
27717    if (this.isInline){
27718      this.show();
27719    }
27720  };
27721
27722  Datepicker.prototype = {
27723    constructor: Datepicker,
27724
27725    _resolveViewName: function(view, default_value){
27726      if (view === 0 || view === 'days' || view === 'month') {
27727        return 0;
27728      }
27729      if (view === 1 || view === 'months' || view === 'year') {
27730        return 1;
27731      }
27732      if (view === 2 || view === 'years' || view === 'decade') {
27733        return 2;
27734      }
27735      if (view === 3 || view === 'decades' || view === 'century') {
27736        return 3;
27737      }
27738      if (view === 4 || view === 'centuries' || view === 'millennium') {
27739        return 4;
27740      }
27741      return default_value === undefined ? false : default_value;
27742    },
27743
27744    _check_template: function(tmp){
27745      try {
27746        // If empty
27747        if (tmp === undefined || tmp === "") {
27748          return false;
27749        }
27750        // If no html, everything ok
27751        if ((tmp.match(/[<>]/g) || []).length <= 0) {
27752          return true;
27753        }
27754        // Checking if html is fine
27755        var jDom = $(tmp);
27756        return jDom.length > 0;
27757      }
27758      catch (ex) {
27759        return false;
27760      }
27761    },
27762
27763    _process_options: function(opts){
27764      // Store raw options for reference
27765      this._o = $.extend({}, this._o, opts);
27766      // Processed options
27767      var o = this.o = $.extend({}, this._o);
27768
27769      // Check if "de-DE" style date is available, if not language should
27770      // fallback to 2 letter code eg "de"
27771      var lang = o.language;
27772      if (!dates[lang]){
27773        lang = lang.split('-')[0];
27774        if (!dates[lang])
27775          lang = defaults.language;
27776      }
27777      o.language = lang;
27778
27779      // Retrieve view index from any aliases
27780      o.startView = this._resolveViewName(o.startView, 0);
27781      o.minViewMode = this._resolveViewName(o.minViewMode, 0);
27782      o.maxViewMode = this._resolveViewName(o.maxViewMode, 4);
27783
27784      // Check that the start view is between min and max
27785      o.startView = Math.min(o.startView, o.maxViewMode);
27786      o.startView = Math.max(o.startView, o.minViewMode);
27787
27788      // true, false, or Number > 0
27789      if (o.multidate !== true){
27790        o.multidate = Number(o.multidate) || false;
27791        if (o.multidate !== false)
27792          o.multidate = Math.max(0, o.multidate);
27793      }
27794      o.multidateSeparator = String(o.multidateSeparator);
27795
27796      o.weekStart %= 7;
27797      o.weekEnd = (o.weekStart + 6) % 7;
27798
27799      var format = DPGlobal.parseFormat(o.format);
27800      if (o.startDate !== -Infinity){
27801        if (!!o.startDate){
27802          if (o.startDate instanceof Date)
27803            o.startDate = this._local_to_utc(this._zero_time(o.startDate));
27804          else
27805            o.startDate = DPGlobal.parseDate(o.startDate, format, o.language, o.assumeNearbyYear);
27806        }
27807        else {
27808          o.startDate = -Infinity;
27809        }
27810      }
27811      if (o.endDate !== Infinity){
27812        if (!!o.endDate){
27813          if (o.endDate instanceof Date)
27814            o.endDate = this._local_to_utc(this._zero_time(o.endDate));
27815          else
27816            o.endDate = DPGlobal.parseDate(o.endDate, format, o.language, o.assumeNearbyYear);
27817        }
27818        else {
27819          o.endDate = Infinity;
27820        }
27821      }
27822
27823      o.daysOfWeekDisabled = o.daysOfWeekDisabled||[];
27824      if (!$.isArray(o.daysOfWeekDisabled))
27825        o.daysOfWeekDisabled = o.daysOfWeekDisabled.split(/[,\s]*/);
27826      o.daysOfWeekDisabled = $.map(o.daysOfWeekDisabled, function(d){
27827        return parseInt(d, 10);
27828      });
27829
27830      o.daysOfWeekHighlighted = o.daysOfWeekHighlighted||[];
27831      if (!$.isArray(o.daysOfWeekHighlighted))
27832        o.daysOfWeekHighlighted = o.daysOfWeekHighlighted.split(/[,\s]*/);
27833      o.daysOfWeekHighlighted = $.map(o.daysOfWeekHighlighted, function(d){
27834        return parseInt(d, 10);
27835      });
27836
27837      o.datesDisabled = o.datesDisabled||[];
27838      if (!$.isArray(o.datesDisabled)) {
27839        var datesDisabled = [];
27840        datesDisabled.push(DPGlobal.parseDate(o.datesDisabled, format, o.language, o.assumeNearbyYear));
27841        o.datesDisabled = datesDisabled;
27842      }
27843      o.datesDisabled = $.map(o.datesDisabled,function(d){
27844        return DPGlobal.parseDate(d, format, o.language, o.assumeNearbyYear);
27845      });
27846
27847      var plc = String(o.orientation).toLowerCase().split(/\s+/g),
27848        _plc = o.orientation.toLowerCase();
27849      plc = $.grep(plc, function(word){
27850        return /^auto|left|right|top|bottom$/.test(word);
27851      });
27852      o.orientation = {x: 'auto', y: 'auto'};
27853      if (!_plc || _plc === 'auto')
27854        ; // no action
27855      else if (plc.length === 1){
27856        switch (plc[0]){
27857          case 'top':
27858          case 'bottom':
27859            o.orientation.y = plc[0];
27860            break;
27861          case 'left':
27862          case 'right':
27863            o.orientation.x = plc[0];
27864            break;
27865        }
27866      }
27867      else {
27868        _plc = $.grep(plc, function(word){
27869          return /^left|right$/.test(word);
27870        });
27871        o.orientation.x = _plc[0] || 'auto';
27872
27873        _plc = $.grep(plc, function(word){
27874          return /^top|bottom$/.test(word);
27875        });
27876        o.orientation.y = _plc[0] || 'auto';
27877      }
27878      if (o.defaultViewDate) {
27879        var year = o.defaultViewDate.year || new Date().getFullYear();
27880        var month = o.defaultViewDate.month || 0;
27881        var day = o.defaultViewDate.day || 1;
27882        o.defaultViewDate = UTCDate(year, month, day);
27883      } else {
27884        o.defaultViewDate = UTCToday();
27885      }
27886    },
27887    _events: [],
27888    _secondaryEvents: [],
27889    _applyEvents: function(evs){
27890      for (var i=0, el, ch, ev; i < evs.length; i++){
27891        el = evs[i][0];
27892        if (evs[i].length === 2){
27893          ch = undefined;
27894          ev = evs[i][1];
27895        }
27896        else if (evs[i].length === 3){
27897          ch = evs[i][1];
27898          ev = evs[i][2];
27899        }
27900        el.on(ev, ch);
27901      }
27902    },
27903    _unapplyEvents: function(evs){
27904      for (var i=0, el, ev, ch; i < evs.length; i++){
27905        el = evs[i][0];
27906        if (evs[i].length === 2){
27907          ch = undefined;
27908          ev = evs[i][1];
27909        }
27910        else if (evs[i].length === 3){
27911          ch = evs[i][1];
27912          ev = evs[i][2];
27913        }
27914        el.off(ev, ch);
27915      }
27916    },
27917    _buildEvents: function(){
27918            var events = {
27919                keyup: $.proxy(function(e){
27920                    if ($.inArray(e.keyCode, [27, 37, 39, 38, 40, 32, 13, 9]) === -1)
27921                        this.update();
27922                }, this),
27923                keydown: $.proxy(this.keydown, this),
27924                paste: $.proxy(this.paste, this)
27925            };
27926
27927            if (this.o.showOnFocus === true) {
27928                events.focus = $.proxy(this.show, this);
27929            }
27930
27931            if (this.isInput) { // single input
27932                this._events = [
27933                    [this.element, events]
27934                ];
27935            }
27936            else if (this.component && this.hasInput) { // component: input + button
27937                this._events = [
27938                    // For components that are not readonly, allow keyboard nav
27939                    [this.element.find('input'), events],
27940                    [this.component, {
27941                        click: $.proxy(this.show, this)
27942                    }]
27943                ];
27944            }
27945      else if (this.element.is('div')){  // inline datepicker
27946        this.isInline = true;
27947      }
27948      else {
27949        this._events = [
27950          [this.element, {
27951            click: $.proxy(this.show, this),
27952            keydown: $.proxy(this.keydown, this)
27953          }]
27954        ];
27955      }
27956      this._events.push(
27957        // Component: listen for blur on element descendants
27958        [this.element, '*', {
27959          blur: $.proxy(function(e){
27960            this._focused_from = e.target;
27961          }, this)
27962        }],
27963        // Input: listen for blur on element
27964        [this.element, {
27965          blur: $.proxy(function(e){
27966            this._focused_from = e.target;
27967          }, this)
27968        }]
27969      );
27970
27971      if (this.o.immediateUpdates) {
27972        // Trigger input updates immediately on changed year/month
27973        this._events.push([this.element, {
27974          'changeYear changeMonth': $.proxy(function(e){
27975            this.update(e.date);
27976          }, this)
27977        }]);
27978      }
27979
27980      this._secondaryEvents = [
27981        [this.picker, {
27982          click: $.proxy(this.click, this)
27983        }],
27984        [$(window), {
27985          resize: $.proxy(this.place, this)
27986        }],
27987        [$(document), {
27988          mousedown: $.proxy(function(e){
27989            // Clicked outside the datepicker, hide it
27990            if (!(
27991              this.element.is(e.target) ||
27992              this.element.find(e.target).length ||
27993              this.picker.is(e.target) ||
27994              this.picker.find(e.target).length ||
27995              this.picker.hasClass('datepicker-inline')
27996            )){
27997              this.hide();
27998            }
27999          }, this)
28000        }]
28001      ];
28002    },
28003    _attachEvents: function(){
28004      this._detachEvents();
28005      this._applyEvents(this._events);
28006    },
28007    _detachEvents: function(){
28008      this._unapplyEvents(this._events);
28009    },
28010    _attachSecondaryEvents: function(){
28011      this._detachSecondaryEvents();
28012      this._applyEvents(this._secondaryEvents);
28013    },
28014    _detachSecondaryEvents: function(){
28015      this._unapplyEvents(this._secondaryEvents);
28016    },
28017    _trigger: function(event, altdate){
28018      var date = altdate || this.dates.get(-1),
28019        local_date = this._utc_to_local(date);
28020
28021      this.element.trigger({
28022        type: event,
28023        date: local_date,
28024        dates: $.map(this.dates, this._utc_to_local),
28025        format: $.proxy(function(ix, format){
28026          if (arguments.length === 0){
28027            ix = this.dates.length - 1;
28028            format = this.o.format;
28029          }
28030          else if (typeof ix === 'string'){
28031            format = ix;
28032            ix = this.dates.length - 1;
28033          }
28034          format = format || this.o.format;
28035          var date = this.dates.get(ix);
28036          return DPGlobal.formatDate(date, format, this.o.language);
28037        }, this)
28038      });
28039    },
28040
28041    show: function(){
28042      var element = this.component ? this.element.find('input') : this.element;
28043      if (element.attr('readonly') && this.o.enableOnReadonly === false)
28044        return;
28045      if (!this.isInline)
28046        this.picker.appendTo(this.o.container);
28047      this.place();
28048      this.picker.show();
28049      this._attachSecondaryEvents();
28050      this._trigger('show');
28051      if ((window.navigator.msMaxTouchPoints || 'ontouchstart' in document) && this.o.disableTouchKeyboard) {
28052        $(this.element).blur();
28053      }
28054      return this;
28055    },
28056
28057    hide: function(){
28058      if (this.isInline)
28059        return this;
28060      if (!this.picker.is(':visible'))
28061        return this;
28062      this.focusDate = null;
28063      this.picker.hide().detach();
28064      this._detachSecondaryEvents();
28065      this.viewMode = this.o.startView;
28066      this.showMode();
28067
28068      if (
28069        this.o.forceParse &&
28070        (
28071          this.isInput && this.element.val() ||
28072          this.hasInput && this.element.find('input').val()
28073        )
28074      )
28075        this.setValue();
28076      this._trigger('hide');
28077      return this;
28078    },
28079
28080    destroy: function(){
28081      this.hide();
28082      this._detachEvents();
28083      this._detachSecondaryEvents();
28084      this.picker.remove();
28085      delete this.element.data().datepicker;
28086      if (!this.isInput){
28087        delete this.element.data().date;
28088      }
28089      return this;
28090    },
28091
28092    paste: function(evt){
28093      var dateString;
28094      if (evt.originalEvent.clipboardData && evt.originalEvent.clipboardData.types
28095        && $.inArray('text/plain', evt.originalEvent.clipboardData.types) !== -1) {
28096        dateString = evt.originalEvent.clipboardData.getData('text/plain');
28097      }
28098      else if (window.clipboardData) {
28099        dateString = window.clipboardData.getData('Text');
28100      }
28101      else {
28102        return;
28103      }
28104      this.setDate(dateString);
28105      this.update();
28106      evt.preventDefault();
28107    },
28108
28109    _utc_to_local: function(utc){
28110      return utc && new Date(utc.getTime() + (utc.getTimezoneOffset()*60000));
28111    },
28112    _local_to_utc: function(local){
28113      return local && new Date(local.getTime() - (local.getTimezoneOffset()*60000));
28114    },
28115    _zero_time: function(local){
28116      return local && new Date(local.getFullYear(), local.getMonth(), local.getDate());
28117    },
28118    _zero_utc_time: function(utc){
28119      return utc && new Date(Date.UTC(utc.getUTCFullYear(), utc.getUTCMonth(), utc.getUTCDate()));
28120    },
28121
28122    getDates: function(){
28123      return $.map(this.dates, this._utc_to_local);
28124    },
28125
28126    getUTCDates: function(){
28127      return $.map(this.dates, function(d){
28128        return new Date(d);
28129      });
28130    },
28131
28132    getDate: function(){
28133      return this._utc_to_local(this.getUTCDate());
28134    },
28135
28136    getUTCDate: function(){
28137      var selected_date = this.dates.get(-1);
28138      if (typeof selected_date !== 'undefined') {
28139        return new Date(selected_date);
28140      } else {
28141        return null;
28142      }
28143    },
28144
28145    clearDates: function(){
28146      var element;
28147      if (this.isInput) {
28148        element = this.element;
28149      } else if (this.component) {
28150        element = this.element.find('input');
28151      }
28152
28153      if (element) {
28154        element.val('');
28155      }
28156
28157      this.update();
28158      this._trigger('changeDate');
28159
28160      if (this.o.autoclose) {
28161        this.hide();
28162      }
28163    },
28164    setDates: function(){
28165      var args = $.isArray(arguments[0]) ? arguments[0] : arguments;
28166      this.update.apply(this, args);
28167      this._trigger('changeDate');
28168      this.setValue();
28169      return this;
28170    },
28171
28172    setUTCDates: function(){
28173      var args = $.isArray(arguments[0]) ? arguments[0] : arguments;
28174      this.update.apply(this, $.map(args, this._utc_to_local));
28175      this._trigger('changeDate');
28176      this.setValue();
28177      return this;
28178    },
28179
28180    setDate: alias('setDates'),
28181    setUTCDate: alias('setUTCDates'),
28182    remove: alias('destroy'),
28183
28184    setValue: function(){
28185      var formatted = this.getFormattedDate();
28186      if (!this.isInput){
28187        if (this.component){
28188          this.element.find('input').val(formatted);
28189        }
28190      }
28191      else {
28192        this.element.val(formatted);
28193      }
28194      return this;
28195    },
28196
28197    getFormattedDate: function(format){
28198      if (format === undefined)
28199        format = this.o.format;
28200
28201      var lang = this.o.language;
28202      return $.map(this.dates, function(d){
28203        return DPGlobal.formatDate(d, format, lang);
28204      }).join(this.o.multidateSeparator);
28205    },
28206
28207    getStartDate: function(){
28208      return this.o.startDate;
28209    },
28210
28211    setStartDate: function(startDate){
28212      this._process_options({startDate: startDate});
28213      this.update();
28214      this.updateNavArrows();
28215      return this;
28216    },
28217
28218    getEndDate: function(){
28219      return this.o.endDate;
28220    },
28221
28222    setEndDate: function(endDate){
28223      this._process_options({endDate: endDate});
28224      this.update();
28225      this.updateNavArrows();
28226      return this;
28227    },
28228
28229    setDaysOfWeekDisabled: function(daysOfWeekDisabled){
28230      this._process_options({daysOfWeekDisabled: daysOfWeekDisabled});
28231      this.update();
28232      this.updateNavArrows();
28233      return this;
28234    },
28235
28236    setDaysOfWeekHighlighted: function(daysOfWeekHighlighted){
28237      this._process_options({daysOfWeekHighlighted: daysOfWeekHighlighted});
28238      this.update();
28239      return this;
28240    },
28241
28242    setDatesDisabled: function(datesDisabled){
28243      this._process_options({datesDisabled: datesDisabled});
28244      this.update();
28245      this.updateNavArrows();
28246    },
28247
28248    place: function(){
28249      if (this.isInline)
28250        return this;
28251      var calendarWidth = this.picker.outerWidth(),
28252        calendarHeight = this.picker.outerHeight(),
28253        visualPadding = 10,
28254        container = $(this.o.container),
28255        windowWidth = container.width(),
28256        scrollTop = this.o.container === 'body' ? $(document).scrollTop() : container.scrollTop(),
28257        appendOffset = container.offset();
28258
28259      var parentsZindex = [];
28260      this.element.parents().each(function(){
28261        var itemZIndex = $(this).css('z-index');
28262        if (itemZIndex !== 'auto' && itemZIndex !== 0) parentsZindex.push(parseInt(itemZIndex));
28263      });
28264      var zIndex = Math.max.apply(Math, parentsZindex) + this.o.zIndexOffset;
28265      var offset = this.component ? this.component.parent().offset() : this.element.offset();
28266      var height = this.component ? this.component.outerHeight(true) : this.element.outerHeight(false);
28267      var width = this.component ? this.component.outerWidth(true) : this.element.outerWidth(false);
28268      var left = offset.left - appendOffset.left,
28269        top = offset.top - appendOffset.top;
28270
28271      if (this.o.container !== 'body') {
28272        top += scrollTop;
28273      }
28274
28275      this.picker.removeClass(
28276        'datepicker-orient-top datepicker-orient-bottom '+
28277        'datepicker-orient-right datepicker-orient-left'
28278      );
28279
28280      if (this.o.orientation.x !== 'auto'){
28281        this.picker.addClass('datepicker-orient-' + this.o.orientation.x);
28282        if (this.o.orientation.x === 'right')
28283          left -= calendarWidth - width;
28284      }
28285      // auto x orientation is best-placement: if it crosses a window
28286      // edge, fudge it sideways
28287      else {
28288        if (offset.left < 0) {
28289          // component is outside the window on the left side. Move it into visible range
28290          this.picker.addClass('datepicker-orient-left');
28291          left -= offset.left - visualPadding;
28292        } else if (left + calendarWidth > windowWidth) {
28293          // the calendar passes the widow right edge. Align it to component right side
28294          this.picker.addClass('datepicker-orient-right');
28295          left += width - calendarWidth;
28296        } else {
28297          // Default to left
28298          this.picker.addClass('datepicker-orient-left');
28299        }
28300      }
28301
28302      // auto y orientation is best-situation: top or bottom, no fudging,
28303      // decision based on which shows more of the calendar
28304      var yorient = this.o.orientation.y,
28305        top_overflow;
28306      if (yorient === 'auto'){
28307        top_overflow = -scrollTop + top - calendarHeight;
28308        yorient = top_overflow < 0 ? 'bottom' : 'top';
28309      }
28310
28311      this.picker.addClass('datepicker-orient-' + yorient);
28312      if (yorient === 'top')
28313        top -= calendarHeight + parseInt(this.picker.css('padding-top'));
28314      else
28315        top += height;
28316
28317      if (this.o.rtl) {
28318        var right = windowWidth - (left + width);
28319        this.picker.css({
28320          top: top,
28321          right: right,
28322          zIndex: zIndex
28323        });
28324      } else {
28325        this.picker.css({
28326          top: top,
28327          left: left,
28328          zIndex: zIndex
28329        });
28330      }
28331      return this;
28332    },
28333
28334    _allow_update: true,
28335    update: function(){
28336      if (!this._allow_update)
28337        return this;
28338
28339      var oldDates = this.dates.copy(),
28340        dates = [],
28341        fromArgs = false;
28342      if (arguments.length){
28343        $.each(arguments, $.proxy(function(i, date){
28344          if (date instanceof Date)
28345            date = this._local_to_utc(date);
28346          dates.push(date);
28347        }, this));
28348        fromArgs = true;
28349      }
28350      else {
28351        dates = this.isInput
28352            ? this.element.val()
28353            : this.element.data('date') || this.element.find('input').val();
28354        if (dates && this.o.multidate)
28355          dates = dates.split(this.o.multidateSeparator);
28356        else
28357          dates = [dates];
28358        delete this.element.data().date;
28359      }
28360
28361      dates = $.map(dates, $.proxy(function(date){
28362        return DPGlobal.parseDate(date, this.o.format, this.o.language, this.o.assumeNearbyYear);
28363      }, this));
28364      dates = $.grep(dates, $.proxy(function(date){
28365        return (
28366          !this.dateWithinRange(date) ||
28367          !date
28368        );
28369      }, this), true);
28370      this.dates.replace(dates);
28371
28372      if (this.dates.length)
28373        this.viewDate = new Date(this.dates.get(-1));
28374      else if (this.viewDate < this.o.startDate)
28375        this.viewDate = new Date(this.o.startDate);
28376      else if (this.viewDate > this.o.endDate)
28377        this.viewDate = new Date(this.o.endDate);
28378      else
28379        this.viewDate = this.o.defaultViewDate;
28380
28381      if (fromArgs){
28382        // setting date by clicking
28383        this.setValue();
28384      }
28385      else if (dates.length){
28386        // setting date by typing
28387        if (String(oldDates) !== String(this.dates))
28388          this._trigger('changeDate');
28389      }
28390      if (!this.dates.length && oldDates.length)
28391        this._trigger('clearDate');
28392
28393      this.fill();
28394      this.element.change();
28395      return this;
28396    },
28397
28398    fillDow: function(){
28399      var dowCnt = this.o.weekStart,
28400        html = '<tr>';
28401      if (this.o.calendarWeeks){
28402        this.picker.find('.datepicker-days .datepicker-switch')
28403          .attr('colspan', function(i, val){
28404            return parseInt(val) + 1;
28405          });
28406        html += '<th class="cw">&#160;</th>';
28407      }
28408      while (dowCnt < this.o.weekStart + 7){
28409        html += '<th class="dow';
28410        if ($.inArray(dowCnt, this.o.daysOfWeekDisabled) > -1)
28411          html += ' disabled';
28412        html += '">'+dates[this.o.language].daysMin[(dowCnt++)%7]+'</th>';
28413      }
28414      html += '</tr>';
28415      this.picker.find('.datepicker-days thead').append(html);
28416    },
28417
28418    fillMonths: function(){
28419      var localDate = this._utc_to_local(this.viewDate);
28420      var html = '',
28421      i = 0;
28422      while (i < 12){
28423        var focused = localDate && localDate.getMonth() === i ? ' focused' : '';
28424        html += '<span class="month' + focused + '">' + dates[this.o.language].monthsShort[i++]+'</span>';
28425      }
28426      this.picker.find('.datepicker-months td').html(html);
28427    },
28428
28429    setRange: function(range){
28430      if (!range || !range.length)
28431        delete this.range;
28432      else
28433        this.range = $.map(range, function(d){
28434          return d.valueOf();
28435        });
28436      this.fill();
28437    },
28438
28439    getClassNames: function(date){
28440      var cls = [],
28441        year = this.viewDate.getUTCFullYear(),
28442        month = this.viewDate.getUTCMonth(),
28443        today = new Date();
28444      if (date.getUTCFullYear() < year || (date.getUTCFullYear() === year && date.getUTCMonth() < month)){
28445        cls.push('old');
28446      }
28447      else if (date.getUTCFullYear() > year || (date.getUTCFullYear() === year && date.getUTCMonth() > month)){
28448        cls.push('new');
28449      }
28450      if (this.focusDate && date.valueOf() === this.focusDate.valueOf())
28451        cls.push('focused');
28452      // Compare internal UTC date with local today, not UTC today
28453      if (this.o.todayHighlight &&
28454        date.getUTCFullYear() === today.getFullYear() &&
28455        date.getUTCMonth() === today.getMonth() &&
28456        date.getUTCDate() === today.getDate()){
28457        cls.push('today');
28458      }
28459      if (this.dates.contains(date) !== -1)
28460        cls.push('active');
28461      if (!this.dateWithinRange(date)){
28462        cls.push('disabled');
28463      }
28464      if (this.dateIsDisabled(date)){
28465        cls.push('disabled', 'disabled-date');
28466      }
28467      if ($.inArray(date.getUTCDay(), this.o.daysOfWeekHighlighted) !== -1){
28468        cls.push('highlighted');
28469      }
28470
28471      if (this.range){
28472        if (date > this.range[0] && date < this.range[this.range.length-1]){
28473          cls.push('range');
28474        }
28475        if ($.inArray(date.valueOf(), this.range) !== -1){
28476          cls.push('selected');
28477        }
28478        if (date.valueOf() === this.range[0]){
28479          cls.push('range-start');
28480        }
28481        if (date.valueOf() === this.range[this.range.length-1]){
28482          cls.push('range-end');
28483        }
28484      }
28485      return cls;
28486    },
28487
28488    _fill_yearsView: function(selector, cssClass, factor, step, currentYear, startYear, endYear, callback){
28489      var html, view, year, steps, startStep, endStep, thisYear, i, classes, tooltip, before;
28490
28491      html      = '';
28492      view      = this.picker.find(selector);
28493      year      = parseInt(currentYear / factor, 10) * factor;
28494      startStep = parseInt(startYear / step, 10) * step;
28495      endStep   = parseInt(endYear / step, 10) * step;
28496      steps     = $.map(this.dates, function(d){
28497        return parseInt(d.getUTCFullYear() / step, 10) * step;
28498      });
28499
28500      view.find('.datepicker-switch').text(year + '-' + (year + step * 9));
28501
28502      thisYear = year - step;
28503      for (i = -1; i < 11; i += 1) {
28504        classes = [cssClass];
28505        tooltip = null;
28506
28507        if (i === -1) {
28508          classes.push('old');
28509        } else if (i === 10) {
28510          classes.push('new');
28511        }
28512        if ($.inArray(thisYear, steps) !== -1) {
28513          classes.push('active');
28514        }
28515        if (thisYear < startStep || thisYear > endStep) {
28516          classes.push('disabled');
28517        }
28518        if (thisYear === this.viewDate.getFullYear()) {
28519          classes.push('focused');
28520        }
28521
28522        if (callback !== $.noop) {
28523          before = callback(new Date(thisYear, 0, 1));
28524          if (before === undefined) {
28525            before = {};
28526          } else if (typeof(before) === 'boolean') {
28527            before = {enabled: before};
28528          } else if (typeof(before) === 'string') {
28529            before = {classes: before};
28530          }
28531          if (before.enabled === false) {
28532            classes.push('disabled');
28533          }
28534          if (before.classes) {
28535            classes = classes.concat(before.classes.split(/\s+/));
28536          }
28537          if (before.tooltip) {
28538            tooltip = before.tooltip;
28539          }
28540        }
28541
28542        html += '<span class="' + classes.join(' ') + '"' + (tooltip ? ' title="' + tooltip + '"' : '') + '>' + thisYear + '</span>';
28543        thisYear += step;
28544      }
28545      view.find('td').html(html);
28546    },
28547
28548    fill: function(){
28549      var d = new Date(this.viewDate),
28550        year = d.getUTCFullYear(),
28551        month = d.getUTCMonth(),
28552        startYear = this.o.startDate !== -Infinity ? this.o.startDate.getUTCFullYear() : -Infinity,
28553        startMonth = this.o.startDate !== -Infinity ? this.o.startDate.getUTCMonth() : -Infinity,
28554        endYear = this.o.endDate !== Infinity ? this.o.endDate.getUTCFullYear() : Infinity,
28555        endMonth = this.o.endDate !== Infinity ? this.o.endDate.getUTCMonth() : Infinity,
28556        todaytxt = dates[this.o.language].today || dates['en'].today || '',
28557        cleartxt = dates[this.o.language].clear || dates['en'].clear || '',
28558        titleFormat = dates[this.o.language].titleFormat || dates['en'].titleFormat,
28559        tooltip,
28560        before;
28561      if (isNaN(year) || isNaN(month))
28562        return;
28563      this.picker.find('.datepicker-days .datepicker-switch')
28564            .text(DPGlobal.formatDate(d, titleFormat, this.o.language));
28565      this.picker.find('tfoot .today')
28566            .text(todaytxt)
28567            .toggle(this.o.todayBtn !== false);
28568      this.picker.find('tfoot .clear')
28569            .text(cleartxt)
28570            .toggle(this.o.clearBtn !== false);
28571      this.picker.find('thead .datepicker-title')
28572            .text(this.o.title)
28573            .toggle(this.o.title !== '');
28574      this.updateNavArrows();
28575      this.fillMonths();
28576      var prevMonth = UTCDate(year, month-1, 28),
28577        day = DPGlobal.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
28578      prevMonth.setUTCDate(day);
28579      prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.o.weekStart + 7)%7);
28580      var nextMonth = new Date(prevMonth);
28581      if (prevMonth.getUTCFullYear() < 100){
28582        nextMonth.setUTCFullYear(prevMonth.getUTCFullYear());
28583      }
28584      nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
28585      nextMonth = nextMonth.valueOf();
28586      var html = [];
28587      var clsName;
28588      while (prevMonth.valueOf() < nextMonth){
28589        if (prevMonth.getUTCDay() === this.o.weekStart){
28590          html.push('<tr>');
28591          if (this.o.calendarWeeks){
28592            // ISO 8601: First week contains first thursday.
28593            // ISO also states week starts on Monday, but we can be more abstract here.
28594            var
28595              // Start of current week: based on weekstart/current date
28596              ws = new Date(+prevMonth + (this.o.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
28597              // Thursday of this week
28598              th = new Date(Number(ws) + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
28599              // First Thursday of year, year from thursday
28600              yth = new Date(Number(yth = UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
28601              // Calendar week: ms between thursdays, div ms per day, div 7 days
28602              calWeek =  (th - yth) / 864e5 / 7 + 1;
28603            html.push('<td class="cw">'+ calWeek +'</td>');
28604
28605          }
28606        }
28607        clsName = this.getClassNames(prevMonth);
28608        clsName.push('day');
28609
28610        if (this.o.beforeShowDay !== $.noop){
28611          before = this.o.beforeShowDay(this._utc_to_local(prevMonth));
28612          if (before === undefined)
28613            before = {};
28614          else if (typeof(before) === 'boolean')
28615            before = {enabled: before};
28616          else if (typeof(before) === 'string')
28617            before = {classes: before};
28618          if (before.enabled === false)
28619            clsName.push('disabled');
28620          if (before.classes)
28621            clsName = clsName.concat(before.classes.split(/\s+/));
28622          if (before.tooltip)
28623            tooltip = before.tooltip;
28624        }
28625
28626        clsName = $.unique(clsName);
28627        html.push('<td class="'+clsName.join(' ')+'"' + (tooltip ? ' title="'+tooltip+'"' : '') + '>'+prevMonth.getUTCDate() + '</td>');
28628        tooltip = null;
28629        if (prevMonth.getUTCDay() === this.o.weekEnd){
28630          html.push('</tr>');
28631        }
28632        prevMonth.setUTCDate(prevMonth.getUTCDate()+1);
28633      }
28634      this.picker.find('.datepicker-days tbody').empty().append(html.join(''));
28635
28636      var monthsTitle = dates[this.o.language].monthsTitle || dates['en'].monthsTitle || 'Months';
28637      var months = this.picker.find('.datepicker-months')
28638            .find('.datepicker-switch')
28639              .text(this.o.maxViewMode < 2 ? monthsTitle : year)
28640              .end()
28641            .find('span').removeClass('active');
28642
28643      $.each(this.dates, function(i, d){
28644        if (d.getUTCFullYear() === year)
28645          months.eq(d.getUTCMonth()).addClass('active');
28646      });
28647
28648      if (year < startYear || year > endYear){
28649        months.addClass('disabled');
28650      }
28651      if (year === startYear){
28652        months.slice(0, startMonth).addClass('disabled');
28653      }
28654      if (year === endYear){
28655        months.slice(endMonth+1).addClass('disabled');
28656      }
28657
28658      if (this.o.beforeShowMonth !== $.noop){
28659        var that = this;
28660        $.each(months, function(i, month){
28661          var moDate = new Date(year, i, 1);
28662          var before = that.o.beforeShowMonth(moDate);
28663          if (before === undefined)
28664            before = {};
28665          else if (typeof(before) === 'boolean')
28666            before = {enabled: before};
28667          else if (typeof(before) === 'string')
28668            before = {classes: before};
28669          if (before.enabled === false && !$(month).hasClass('disabled'))
28670              $(month).addClass('disabled');
28671          if (before.classes)
28672              $(month).addClass(before.classes);
28673          if (before.tooltip)
28674              $(month).prop('title', before.tooltip);
28675        });
28676      }
28677
28678      // Generating decade/years picker
28679      this._fill_yearsView(
28680        '.datepicker-years',
28681        'year',
28682        10,
28683        1,
28684        year,
28685        startYear,
28686        endYear,
28687        this.o.beforeShowYear
28688      );
28689
28690      // Generating century/decades picker
28691      this._fill_yearsView(
28692        '.datepicker-decades',
28693        'decade',
28694        100,
28695        10,
28696        year,
28697        startYear,
28698        endYear,
28699        this.o.beforeShowDecade
28700      );
28701
28702      // Generating millennium/centuries picker
28703      this._fill_yearsView(
28704        '.datepicker-centuries',
28705        'century',
28706        1000,
28707        100,
28708        year,
28709        startYear,
28710        endYear,
28711        this.o.beforeShowCentury
28712      );
28713    },
28714
28715    updateNavArrows: function(){
28716      if (!this._allow_update)
28717        return;
28718
28719      var d = new Date(this.viewDate),
28720        year = d.getUTCFullYear(),
28721        month = d.getUTCMonth();
28722      switch (this.viewMode){
28723        case 0:
28724          if (this.o.startDate !== -Infinity && year <= this.o.startDate.getUTCFullYear() && month <= this.o.startDate.getUTCMonth()){
28725            this.picker.find('.prev').css({visibility: 'hidden'});
28726          }
28727          else {
28728            this.picker.find('.prev').css({visibility: 'visible'});
28729          }
28730          if (this.o.endDate !== Infinity && year >= this.o.endDate.getUTCFullYear() && month >= this.o.endDate.getUTCMonth()){
28731            this.picker.find('.next').css({visibility: 'hidden'});
28732          }
28733          else {
28734            this.picker.find('.next').css({visibility: 'visible'});
28735          }
28736          break;
28737        case 1:
28738        case 2:
28739        case 3:
28740        case 4:
28741          if (this.o.startDate !== -Infinity && year <= this.o.startDate.getUTCFullYear() || this.o.maxViewMode < 2){
28742            this.picker.find('.prev').css({visibility: 'hidden'});
28743          }
28744          else {
28745            this.picker.find('.prev').css({visibility: 'visible'});
28746          }
28747          if (this.o.endDate !== Infinity && year >= this.o.endDate.getUTCFullYear() || this.o.maxViewMode < 2){
28748            this.picker.find('.next').css({visibility: 'hidden'});
28749          }
28750          else {
28751            this.picker.find('.next').css({visibility: 'visible'});
28752          }
28753          break;
28754      }
28755    },
28756
28757    click: function(e){
28758      e.preventDefault();
28759      e.stopPropagation();
28760
28761      var target, dir, day, year, month, monthChanged, yearChanged;
28762      target = $(e.target);
28763
28764      // Clicked on the switch
28765      if (target.hasClass('datepicker-switch')){
28766        this.showMode(1);
28767      }
28768
28769      // Clicked on prev or next
28770      var navArrow = target.closest('.prev, .next');
28771      if (navArrow.length > 0) {
28772        dir = DPGlobal.modes[this.viewMode].navStep * (navArrow.hasClass('prev') ? -1 : 1);
28773        if (this.viewMode === 0){
28774          this.viewDate = this.moveMonth(this.viewDate, dir);
28775          this._trigger('changeMonth', this.viewDate);
28776        } else {
28777          this.viewDate = this.moveYear(this.viewDate, dir);
28778          if (this.viewMode === 1){
28779            this._trigger('changeYear', this.viewDate);
28780          }
28781        }
28782        this.fill();
28783      }
28784
28785      // Clicked on today button
28786      if (target.hasClass('today')){
28787        this.showMode(-2);
28788        this._setDate(UTCToday(), this.o.todayBtn === 'linked' ? null : 'view');
28789      }
28790
28791      // Clicked on clear button
28792      if (target.hasClass('clear')){
28793        this.clearDates();
28794      }
28795
28796      if (!target.hasClass('disabled')){
28797        // Clicked on a day
28798        if (target.hasClass('day')){
28799          day = parseInt(target.text(), 10) || 1;
28800          year = this.viewDate.getUTCFullYear();
28801          month = this.viewDate.getUTCMonth();
28802
28803          // From last month
28804          if (target.hasClass('old')){
28805            if (month === 0) {
28806              month = 11;
28807              year = year - 1;
28808              monthChanged = true;
28809              yearChanged = true;
28810            } else {
28811              month = month - 1;
28812              monthChanged = true;
28813            }
28814          }
28815
28816          // From next month
28817          if (target.hasClass('new')) {
28818            if (month === 11){
28819              month = 0;
28820              year = year + 1;
28821              monthChanged = true;
28822              yearChanged = true;
28823            } else {
28824              month = month + 1;
28825              monthChanged = true;
28826            }
28827          }
28828          this._setDate(UTCDate(year, month, day));
28829          if (yearChanged) {
28830            this._trigger('changeYear', this.viewDate);
28831          }
28832          if (monthChanged) {
28833            this._trigger('changeMonth', this.viewDate);
28834          }
28835        }
28836
28837        // Clicked on a month
28838        if (target.hasClass('month')) {
28839          this.viewDate.setUTCDate(1);
28840          day = 1;
28841          month = target.parent().find('span').index(target);
28842          year = this.viewDate.getUTCFullYear();
28843          this.viewDate.setUTCMonth(month);
28844          this._trigger('changeMonth', this.viewDate);
28845          if (this.o.minViewMode === 1){
28846            this._setDate(UTCDate(year, month, day));
28847            this.showMode();
28848          } else {
28849            this.showMode(-1);
28850          }
28851          this.fill();
28852        }
28853
28854        // Clicked on a year
28855        if (target.hasClass('year')
28856            || target.hasClass('decade')
28857            || target.hasClass('century')) {
28858          this.viewDate.setUTCDate(1);
28859
28860          day = 1;
28861          month = 0;
28862          year = parseInt(target.text(), 10)||0;
28863          this.viewDate.setUTCFullYear(year);
28864
28865          if (target.hasClass('year')){
28866            this._trigger('changeYear', this.viewDate);
28867            if (this.o.minViewMode === 2){
28868              this._setDate(UTCDate(year, month, day));
28869            }
28870          }
28871          if (target.hasClass('decade')){
28872            this._trigger('changeDecade', this.viewDate);
28873            if (this.o.minViewMode === 3){
28874              this._setDate(UTCDate(year, month, day));
28875            }
28876          }
28877          if (target.hasClass('century')){
28878            this._trigger('changeCentury', this.viewDate);
28879            if (this.o.minViewMode === 4){
28880              this._setDate(UTCDate(year, month, day));
28881            }
28882          }
28883
28884          this.showMode(-1);
28885          this.fill();
28886        }
28887      }
28888
28889      if (this.picker.is(':visible') && this._focused_from){
28890        $(this._focused_from).focus();
28891      }
28892      delete this._focused_from;
28893    },
28894
28895    _toggle_multidate: function(date){
28896      var ix = this.dates.contains(date);
28897      if (!date){
28898        this.dates.clear();
28899      }
28900
28901      if (ix !== -1){
28902        if (this.o.multidate === true || this.o.multidate > 1 || this.o.toggleActive){
28903          this.dates.remove(ix);
28904        }
28905      } else if (this.o.multidate === false) {
28906        this.dates.clear();
28907        this.dates.push(date);
28908      }
28909      else {
28910        this.dates.push(date);
28911      }
28912
28913      if (typeof this.o.multidate === 'number')
28914        while (this.dates.length > this.o.multidate)
28915          this.dates.remove(0);
28916    },
28917
28918    _setDate: function(date, which){
28919      if (!which || which === 'date')
28920        this._toggle_multidate(date && new Date(date));
28921      if (!which || which === 'view')
28922        this.viewDate = date && new Date(date);
28923
28924      this.fill();
28925      this.setValue();
28926      if (!which || which !== 'view') {
28927        this._trigger('changeDate');
28928      }
28929      var element;
28930      if (this.isInput){
28931        element = this.element;
28932      }
28933      else if (this.component){
28934        element = this.element.find('input');
28935      }
28936      if (element){
28937        element.change();
28938      }
28939      if (this.o.autoclose && (!which || which === 'date')){
28940        this.hide();
28941      }
28942    },
28943
28944    moveDay: function(date, dir){
28945      var newDate = new Date(date);
28946      newDate.setUTCDate(date.getUTCDate() + dir);
28947
28948      return newDate;
28949    },
28950
28951    moveWeek: function(date, dir){
28952      return this.moveDay(date, dir * 7);
28953    },
28954
28955    moveMonth: function(date, dir){
28956      if (!isValidDate(date))
28957        return this.o.defaultViewDate;
28958      if (!dir)
28959        return date;
28960      var new_date = new Date(date.valueOf()),
28961        day = new_date.getUTCDate(),
28962        month = new_date.getUTCMonth(),
28963        mag = Math.abs(dir),
28964        new_month, test;
28965      dir = dir > 0 ? 1 : -1;
28966      if (mag === 1){
28967        test = dir === -1
28968          // If going back one month, make sure month is not current month
28969          // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
28970          ? function(){
28971            return new_date.getUTCMonth() === month;
28972          }
28973          // If going forward one month, make sure month is as expected
28974          // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
28975          : function(){
28976            return new_date.getUTCMonth() !== new_month;
28977          };
28978        new_month = month + dir;
28979        new_date.setUTCMonth(new_month);
28980        // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
28981        if (new_month < 0 || new_month > 11)
28982          new_month = (new_month + 12) % 12;
28983      }
28984      else {
28985        // For magnitudes >1, move one month at a time...
28986        for (var i=0; i < mag; i++)
28987          // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
28988          new_date = this.moveMonth(new_date, dir);
28989        // ...then reset the day, keeping it in the new month
28990        new_month = new_date.getUTCMonth();
28991        new_date.setUTCDate(day);
28992        test = function(){
28993          return new_month !== new_date.getUTCMonth();
28994        };
28995      }
28996      // Common date-resetting loop -- if date is beyond end of month, make it
28997      // end of month
28998      while (test()){
28999        new_date.setUTCDate(--day);
29000        new_date.setUTCMonth(new_month);
29001      }
29002      return new_date;
29003    },
29004
29005    moveYear: function(date, dir){
29006      return this.moveMonth(date, dir*12);
29007    },
29008
29009    moveAvailableDate: function(date, dir, fn){
29010      do {
29011        date = this[fn](date, dir);
29012
29013        if (!this.dateWithinRange(date))
29014          return false;
29015
29016        fn = 'moveDay';
29017      }
29018      while (this.dateIsDisabled(date));
29019
29020      return date;
29021    },
29022
29023    weekOfDateIsDisabled: function(date){
29024      return $.inArray(date.getUTCDay(), this.o.daysOfWeekDisabled) !== -1;
29025    },
29026
29027    dateIsDisabled: function(date){
29028      return (
29029        this.weekOfDateIsDisabled(date) ||
29030        $.grep(this.o.datesDisabled, function(d){
29031          return isUTCEquals(date, d);
29032        }).length > 0
29033      );
29034    },
29035
29036    dateWithinRange: function(date){
29037      return date >= this.o.startDate && date <= this.o.endDate;
29038    },
29039
29040    keydown: function(e){
29041      if (!this.picker.is(':visible')){
29042        if (e.keyCode === 40 || e.keyCode === 27) { // allow down to re-show picker
29043          this.show();
29044          e.stopPropagation();
29045        }
29046        return;
29047      }
29048      var dateChanged = false,
29049        dir, newViewDate,
29050        focusDate = this.focusDate || this.viewDate;
29051      switch (e.keyCode){
29052        case 27: // escape
29053          if (this.focusDate){
29054            this.focusDate = null;
29055            this.viewDate = this.dates.get(-1) || this.viewDate;
29056            this.fill();
29057          }
29058          else
29059            this.hide();
29060          e.preventDefault();
29061          e.stopPropagation();
29062          break;
29063        case 37: // left
29064        case 38: // up
29065        case 39: // right
29066        case 40: // down
29067          if (!this.o.keyboardNavigation || this.o.daysOfWeekDisabled.length === 7)
29068            break;
29069          dir = e.keyCode === 37 || e.keyCode === 38 ? -1 : 1;
29070          if (this.viewMode === 0) {
29071            if (e.ctrlKey){
29072              newViewDate = this.moveAvailableDate(focusDate, dir, 'moveYear');
29073
29074              if (newViewDate)
29075                this._trigger('changeYear', this.viewDate);
29076            }
29077            else if (e.shiftKey){
29078              newViewDate = this.moveAvailableDate(focusDate, dir, 'moveMonth');
29079
29080              if (newViewDate)
29081                this._trigger('changeMonth', this.viewDate);
29082            }
29083            else if (e.keyCode === 37 || e.keyCode === 39){
29084              newViewDate = this.moveAvailableDate(focusDate, dir, 'moveDay');
29085            }
29086            else if (!this.weekOfDateIsDisabled(focusDate)){
29087              newViewDate = this.moveAvailableDate(focusDate, dir, 'moveWeek');
29088            }
29089          } else if (this.viewMode === 1) {
29090            if (e.keyCode === 38 || e.keyCode === 40) {
29091              dir = dir * 4;
29092            }
29093            newViewDate = this.moveAvailableDate(focusDate, dir, 'moveMonth');
29094          } else if (this.viewMode === 2) {
29095            if (e.keyCode === 38 || e.keyCode === 40) {
29096              dir = dir * 4;
29097            }
29098            newViewDate = this.moveAvailableDate(focusDate, dir, 'moveYear');
29099          }
29100          if (newViewDate){
29101            this.focusDate = this.viewDate = newViewDate;
29102            this.setValue();
29103            this.fill();
29104            e.preventDefault();
29105          }
29106          break;
29107        case 13: // enter
29108          if (!this.o.forceParse)
29109            break;
29110          focusDate = this.focusDate || this.dates.get(-1) || this.viewDate;
29111          if (this.o.keyboardNavigation) {
29112            this._toggle_multidate(focusDate);
29113            dateChanged = true;
29114          }
29115          this.focusDate = null;
29116          this.viewDate = this.dates.get(-1) || this.viewDate;
29117          this.setValue();
29118          this.fill();
29119          if (this.picker.is(':visible')){
29120            e.preventDefault();
29121            e.stopPropagation();
29122            if (this.o.autoclose)
29123              this.hide();
29124          }
29125          break;
29126        case 9: // tab
29127          this.focusDate = null;
29128          this.viewDate = this.dates.get(-1) || this.viewDate;
29129          this.fill();
29130          this.hide();
29131          break;
29132      }
29133      if (dateChanged){
29134        if (this.dates.length)
29135          this._trigger('changeDate');
29136        else
29137          this._trigger('clearDate');
29138        var element;
29139        if (this.isInput){
29140          element = this.element;
29141        }
29142        else if (this.component){
29143          element = this.element.find('input');
29144        }
29145        if (element){
29146          element.change();
29147        }
29148      }
29149    },
29150
29151    showMode: function(dir){
29152      if (dir){
29153        this.viewMode = Math.max(this.o.minViewMode, Math.min(this.o.maxViewMode, this.viewMode + dir));
29154      }
29155      this.picker
29156        .children('div')
29157        .hide()
29158        .filter('.datepicker-' + DPGlobal.modes[this.viewMode].clsName)
29159          .show();
29160      this.updateNavArrows();
29161    }
29162  };
29163
29164  var DateRangePicker = function(element, options){
29165    $(element).data('datepicker', this);
29166    this.element = $(element);
29167    this.inputs = $.map(options.inputs, function(i){
29168      return i.jquery ? i[0] : i;
29169    });
29170    delete options.inputs;
29171
29172    datepickerPlugin.call($(this.inputs), options)
29173      .on('changeDate', $.proxy(this.dateUpdated, this));
29174
29175    this.pickers = $.map(this.inputs, function(i){
29176      return $(i).data('datepicker');
29177    });
29178    this.updateDates();
29179  };
29180  DateRangePicker.prototype = {
29181    updateDates: function(){
29182      this.dates = $.map(this.pickers, function(i){
29183        return i.getUTCDate();
29184      });
29185      this.updateRanges();
29186    },
29187    updateRanges: function(){
29188      var range = $.map(this.dates, function(d){
29189        return d.valueOf();
29190      });
29191      $.each(this.pickers, function(i, p){
29192        p.setRange(range);
29193      });
29194    },
29195    dateUpdated: function(e){
29196      // `this.updating` is a workaround for preventing infinite recursion
29197      // between `changeDate` triggering and `setUTCDate` calling.  Until
29198      // there is a better mechanism.
29199      if (this.updating)
29200        return;
29201      this.updating = true;
29202
29203      var dp = $(e.target).data('datepicker');
29204
29205      if (typeof(dp) === "undefined") {
29206        return;
29207      }
29208
29209      var new_date = dp.getUTCDate(),
29210        i = $.inArray(e.target, this.inputs),
29211        j = i - 1,
29212        k = i + 1,
29213        l = this.inputs.length;
29214      if (i === -1)
29215        return;
29216
29217      $.each(this.pickers, function(i, p){
29218        if (!p.getUTCDate())
29219          p.setUTCDate(new_date);
29220      });
29221
29222      if (new_date < this.dates[j]){
29223        // Date being moved earlier/left
29224        while (j >= 0 && new_date < this.dates[j]){
29225          this.pickers[j--].setUTCDate(new_date);
29226        }
29227      }
29228      else if (new_date > this.dates[k]){
29229        // Date being moved later/right
29230        while (k < l && new_date > this.dates[k]){
29231          this.pickers[k++].setUTCDate(new_date);
29232        }
29233      }
29234      this.updateDates();
29235
29236      delete this.updating;
29237    },
29238    remove: function(){
29239      $.map(this.pickers, function(p){ p.remove(); });
29240      delete this.element.data().datepicker;
29241    }
29242  };
29243
29244  function opts_from_el(el, prefix){
29245    // Derive options from element data-attrs
29246    var data = $(el).data(),
29247      out = {}, inkey,
29248      replace = new RegExp('^' + prefix.toLowerCase() + '([A-Z])');
29249    prefix = new RegExp('^' + prefix.toLowerCase());
29250    function re_lower(_,a){
29251      return a.toLowerCase();
29252    }
29253    for (var key in data)
29254      if (prefix.test(key)){
29255        inkey = key.replace(replace, re_lower);
29256        out[inkey] = data[key];
29257      }
29258    return out;
29259  }
29260
29261  function opts_from_locale(lang){
29262    // Derive options from locale plugins
29263    var out = {};
29264    // Check if "de-DE" style date is available, if not language should
29265    // fallback to 2 letter code eg "de"
29266    if (!dates[lang]){
29267      lang = lang.split('-')[0];
29268      if (!dates[lang])
29269        return;
29270    }
29271    var d = dates[lang];
29272    $.each(locale_opts, function(i,k){
29273      if (k in d)
29274        out[k] = d[k];
29275    });
29276    return out;
29277  }
29278
29279  var old = $.fn.datepicker;
29280  var datepickerPlugin = function(option){
29281    var args = Array.apply(null, arguments);
29282    args.shift();
29283    var internal_return;
29284    this.each(function(){
29285      var $this = $(this),
29286        data = $this.data('datepicker'),
29287        options = typeof option === 'object' && option;
29288      if (!data){
29289        var elopts = opts_from_el(this, 'date'),
29290          // Preliminary otions
29291          xopts = $.extend({}, defaults, elopts, options),
29292          locopts = opts_from_locale(xopts.language),
29293          // Options priority: js args, data-attrs, locales, defaults
29294          opts = $.extend({}, defaults, locopts, elopts, options);
29295        if ($this.hasClass('input-daterange') || opts.inputs){
29296          $.extend(opts, {
29297            inputs: opts.inputs || $this.find('input').toArray()
29298          });
29299          data = new DateRangePicker(this, opts);
29300        }
29301        else {
29302          data = new Datepicker(this, opts);
29303        }
29304        $this.data('datepicker', data);
29305      }
29306      if (typeof option === 'string' && typeof data[option] === 'function'){
29307        internal_return = data[option].apply(data, args);
29308      }
29309    });
29310
29311    if (
29312      internal_return === undefined ||
29313      internal_return instanceof Datepicker ||
29314      internal_return instanceof DateRangePicker
29315    )
29316      return this;
29317
29318    if (this.length > 1)
29319      throw new Error('Using only allowed for the collection of a single element (' + option + ' function)');
29320    else
29321      return internal_return;
29322  };
29323  $.fn.datepicker = datepickerPlugin;
29324
29325  var defaults = $.fn.datepicker.defaults = {
29326    assumeNearbyYear: false,
29327    autoclose: false,
29328    beforeShowDay: $.noop,
29329    beforeShowMonth: $.noop,
29330    beforeShowYear: $.noop,
29331    beforeShowDecade: $.noop,
29332    beforeShowCentury: $.noop,
29333    calendarWeeks: false,
29334    clearBtn: false,
29335    toggleActive: false,
29336    daysOfWeekDisabled: [],
29337    daysOfWeekHighlighted: [],
29338    datesDisabled: [],
29339    endDate: Infinity,
29340    forceParse: true,
29341    format: 'mm/dd/yyyy',
29342    keyboardNavigation: true,
29343    language: 'en',
29344    minViewMode: 0,
29345    maxViewMode: 4,
29346    multidate: false,
29347    multidateSeparator: ',',
29348    orientation: "auto",
29349    rtl: false,
29350    startDate: -Infinity,
29351    startView: 0,
29352    todayBtn: false,
29353    todayHighlight: false,
29354    weekStart: 0,
29355    disableTouchKeyboard: false,
29356    enableOnReadonly: true,
29357    showOnFocus: true,
29358    zIndexOffset: 10,
29359    container: 'body',
29360    immediateUpdates: false,
29361    title: '',
29362    templates: {
29363      leftArrow: '&laquo;',
29364      rightArrow: '&raquo;'
29365    }
29366  };
29367  var locale_opts = $.fn.datepicker.locale_opts = [
29368    'format',
29369    'rtl',
29370    'weekStart'
29371  ];
29372  $.fn.datepicker.Constructor = Datepicker;
29373  var dates = $.fn.datepicker.dates = {
29374    en: {
29375      days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
29376      daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
29377      daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"],
29378      months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "
29378November", "December"],
29379      monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
29380      today: "Today",
29381      clear: "Clear",
29382      titleFormat: "MM yyyy"
29383    }
29384  };
29385
29386  var DPGlobal = {
29387    modes: [
29388      {
29389        clsName: 'days',
29390        navFnc: 'Month',
29391        navStep: 1
29392      },
29393      {
29394        clsName: 'months',
29395        navFnc: 'FullYear',
29396        navStep: 1
29397      },
29398      {
29399        clsName: 'years',
29400        navFnc: 'FullYear',
29401        navStep: 10
29402      },
29403      {
29404        clsName: 'decades',
29405        navFnc: 'FullDecade',
29406        navStep: 100
29407      },
29408      {
29409        clsName: 'centuries',
29410        navFnc: 'FullCentury',
29411        navStep: 1000
29412    }],
29413    isLeapYear: function(year){
29414      return (((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0));
29415    },
29416    getDaysInMonth: function(year, month){
29417      return [31, (DPGlobal.isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month];
29418    },
29419    validParts: /dd?|DD?|mm?|MM?|yy(?:yy)?/g,
29420    nonpunctuation: /[^ -\/:-@\u5e74\u6708\u65e5\[-`{-~\t\n\r]+/g,
29421    parseFormat: function(format){
29422      if (typeof format.toValue === 'function' && typeof format.toDisplay === 'function')
29423                return format;
29424            // IE treats \0 as a string end in inputs (truncating the value),
29425      // so it's a bad format delimiter, anyway
29426      var separators = format.replace(this.validParts, '\0').split('\0'),
29427        parts = format.match(this.validParts);
29428      if (!separators || !separators.length || !parts || parts.length === 0){
29429        throw new Error("Invalid date format.");
29430      }
29431      return {separators: separators, parts: parts};
29432    },
29433    parseDate: function(date, format, language, assumeNearby){
29434      if (!date)
29435        return undefined;
29436      if (date instanceof Date)
29437        return date;
29438      if (typeof format === 'string')
29439        format = DPGlobal.parseFormat(format);
29440      if (format.toValue)
29441                return format.toValue(date, format, language);
29442            var part_re = /([\-+]\d+)([dmwy])/,
29443        parts = date.match(/([\-+]\d+)([dmwy])/g),
29444        fn_map = {
29445          d: 'moveDay',
29446          m: 'moveMonth',
29447          w: 'moveWeek',
29448          y: 'moveYear'
29449        },
29450        dateAliases = {
29451          yesterday: '-1d',
29452          today: '+0d',
29453          tomorrow: '+1d'
29454        },
29455        part, dir, i, fn;
29456      if (/^[\-+]\d+[dmwy]([\s,]+[\-+]\d+[dmwy])*$/.test(date)){
29457        date = new Date();
29458        for (i=0; i < parts.length; i++){
29459          part = part_re.exec(parts[i]);
29460          dir = parseInt(part[1]);
29461          fn = fn_map[part[2]];
29462          date = Datepicker.prototype[fn](date, dir);
29463        }
29464        return UTCDate(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate());
29465      }
29466
29467      if (typeof dateAliases[date] !== 'undefined') {
29468        date = dateAliases[date];
29469        parts = date.match(/([\-+]\d+)([dmwy])/g);
29470
29471        if (/^[\-+]\d+[dmwy]([\s,]+[\-+]\d+[dmwy])*$/.test(date)){
29472          date = new Date();
29473            for (i=0; i < parts.length; i++){
29474            part = part_re.exec(parts[i]);
29475            dir = parseInt(part[1]);
29476            fn = fn_map[part[2]];
29477            date = Datepicker.prototype[fn](date, dir);
29478            }
29479
29480            return UTCDate(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate());
29481        }
29482      }
29483
29484      parts = date && date.match(this.nonpunctuation) || [];
29485      date = new Date();
29486
29487      function applyNearbyYear(year, threshold){
29488        if (threshold === true)
29489          threshold = 10;
29490
29491        // if year is 2 digits or less, than the user most likely is trying to get a recent century
29492        if (year < 100){
29493          year += 2000;
29494          // if the new year is more than threshold years in advance, use last century
29495          if (year > ((new Date()).getFullYear()+threshold)){
29496            year -= 100;
29497          }
29498        }
29499
29500        return year;
29501      }
29502
29503      var parsed = {},
29504        setters_order = ['yyyy', 'yy', 'M', 'MM', 'm', 'mm', 'd', 'dd'],
29505        setters_map = {
29506          yyyy: function(d,v){
29507            return d.setUTCFullYear(assumeNearby ? applyNearbyYear(v, assumeNearby) : v);
29508          },
29509          yy: function(d,v){
29510            return d.setUTCFullYear(assumeNearby ? applyNearbyYear(v, assumeNearby) : v);
29511          },
29512          m: function(d,v){
29513            if (isNaN(d))
29514              return d;
29515            v -= 1;
29516            while (v < 0) v += 12;
29517            v %= 12;
29518            d.setUTCMonth(v);
29519            while (d.getUTCMonth() !== v)
29520              d.setUTCDate(d.getUTCDate()-1);
29521            return d;
29522          },
29523          d: function(d,v){
29524            return d.setUTCDate(v);
29525          }
29526        },
29527        val, filtered;
29528      setters_map['M'] = setters_map['MM'] = setters_map['mm'] = setters_map['m'];
29529      setters_map['dd'] = setters_map['d'];
29530      date = UTCToday();
29531      var fparts = format.parts.slice();
29532      // Remove noop parts
29533      if (parts.length !== fparts.length){
29534        fparts = $(fparts).filter(function(i,p){
29535          return $.inArray(p, setters_order) !== -1;
29536        }).toArray();
29537      }
29538      // Process remainder
29539      function match_part(){
29540        var m = this.slice(0, parts[i].length),
29541          p = parts[i].slice(0, m.length);
29542        return m.toLowerCase() === p.toLowerCase();
29543      }
29544      if (parts.length === fparts.length){
29545        var cnt;
29546        for (i=0, cnt = fparts.length; i < cnt; i++){
29547          val = parseInt(parts[i], 10);
29548          part = fparts[i];
29549          if (isNaN(val)){
29550            switch (part){
29551              case 'MM':
29552                filtered = $(dates[language].months).filter(match_part);
29553                val = $.inArray(filtered[0], dates[language].months) + 1;
29554                break;
29555              case 'M':
29556                filtered = $(dates[language].monthsShort).filter(match_part);
29557                val = $.inArray(filtered[0], dates[language].monthsShort) + 1;
29558                break;
29559            }
29560          }
29561          parsed[part] = val;
29562        }
29563        var _date, s;
29564        for (i=0; i < setters_order.length; i++){
29565          s = setters_order[i];
29566          if (s in parsed && !isNaN(parsed[s])){
29567            _date = new Date(date);
29568            setters_map[s](_date, parsed[s]);
29569            if (!isNaN(_date))
29570              date = _date;
29571          }
29572        }
29573      }
29574      return date;
29575    },
29576    formatDate: function(date, format, language){
29577      if (!date)
29578        return '';
29579      if (typeof format === 'string')
29580        format = DPGlobal.parseFormat(format);
29581      if (format.toDisplay)
29582                return format.toDisplay(date, format, language);
29583            var val = {
29584        d: date.getUTCDate(),
29585        D: dates[language].daysShort[date.getUTCDay()],
29586        DD: dates[language].days[date.getUTCDay()],
29587        m: date.getUTCMonth() + 1,
29588        M: dates[language].monthsShort[date.getUTCMonth()],
29589        MM: dates[language].months[date.getUTCMonth()],
29590        yy: date.getUTCFullYear().toString().substring(2),
29591        yyyy: date.getUTCFullYear()
29592      };
29593      val.dd = (val.d < 10 ? '0' : '') + val.d;
29594      val.mm = (val.m < 10 ? '0' : '') + val.m;
29595      date = [];
29596      var seps = $.extend([], format.separators);
29597      for (var i=0, cnt = format.parts.length; i <= cnt; i++){
29598        if (seps.length)
29599          date.push(seps.shift());
29600        date.push(val[format.parts[i]]);
29601      }
29602      return date.join('');
29603    },
29604    headTemplate: '<thead>'+
29605                    '<tr>'+
29606                      '<th colspan="7" class="datepicker-title"></th>'+
29607                    '</tr>'+
29608              '<tr>'+
29609                '<th class="prev">&laquo;</th>'+
29610                '<th colspan="5" class="datepicker-switch"></th>'+
29611                '<th class="next">&raquo;</th>'+
29612              '</tr>'+
29613            '</thead>',
29614    contTemplate: '<tbody><tr><td colspan="7"></td></tr></tbody>',
29615    footTemplate: '<tfoot>'+
29616              '<tr>'+
29617                '<th colspan="7" class="today"></th>'+
29618              '</tr>'+
29619              '<tr>'+
29620                '<th colspan="7" class="clear"></th>'+
29621              '</tr>'+
29622            '</tfoot>'
29623  };
29624  DPGlobal.template = '<div class="datepicker">'+
29625              '<div class="datepicker-days">'+
29626                '<table class=" table-condensed">'+
29627                  DPGlobal.headTemplate+
29628                  '<tbody></tbody>'+
29629                  DPGlobal.footTemplate+
29630                '</table>'+
29631              '</div>'+
29632              '<div class="datepicker-months">'+
29633                '<table class="table-condensed">'+
29634                  DPGlobal.headTemplate+
29635                  DPGlobal.contTemplate+
29636                  DPGlobal.footTemplate+
29637                '</table>'+
29638              '</div>'+
29639              '<div class="datepicker-years">'+
29640                '<table class="table-condensed">'+
29641                  DPGlobal.headTemplate+
29642                  DPGlobal.contTemplate+
29643                  DPGlobal.footTemplate+
29644                '</table>'+
29645              '</div>'+
29646              '<div class="datepicker-decades">'+
29647                '<table class="table-condensed">'+
29648                  DPGlobal.headTemplate+
29649                  DPGlobal.contTemplate+
29650                  DPGlobal.footTemplate+
29651                '</table>'+
29652              '</div>'+
29653              '<div class="datepicker-centuries">'+
29654                '<table class="table-condensed">'+
29655                  DPGlobal.headTemplate+
29656                  DPGlobal.contTemplate+
29657                  DPGlobal.footTemplate+
29658                '</table>'+
29659              '</div>'+
29660            '</div>';
29661
29662  $.fn.datepicker.DPGlobal = DPGlobal;
29663
29664
29665  /* DATEPICKER NO CONFLICT
29666  * =================== */
29667
29668  $.fn.datepicker.noConflict = function(){
29669    $.fn.datepicker = old;
29670    return this;
29671  };
29672
29673  /* DATEPICKER VERSION
29674   * =================== */
29675  $.fn.datepicker.version = '1.7.0-dev';
29676
29677  /* DATEPICKER DATA-API
29678  * ================== */
29679
29680  $(document).on(
29681    'focus.datepicker.data-api click.datepicker.data-api',
29682    '[data-provide="datepicker"]',
29683    function(e){
29684      var $this = $(this);
29685      if ($this.data('datepicker'))
29686        return;
29687      e.preventDefault();
29688      // component click requires us to explicitly show it
29689      datepickerPlugin.call($this, 'show');
29690    }
29691  );
29692  $(function(){
29693    datepickerPlugin.call($('[data-provide="datepicker-inline"]'));
29694  });
29695
29696}));
29697
29698;$(function(){
29699
29700    if($.fn.datepicker){
29701        $.fn.datepicker.dates['fi'] = {
29702            days: ["sunnuntai", "maanantai", "tiistai", "keskiviikko", "torstai", "perjantai", "lauantai", "sunnuntai"],
29703            daysShort: ["sun", "maa", "tii", "kes", "tor", "per", "lau", "sun"],
29704            daysMin: ["su", "ma", "ti", "ke", "to", "pe", "la", "su"],
29705            months: ["tammikuu", "helmikuu", "maaliskuu", "huhtikuu", "toukokuu", "kesäkuu", "heinäkuu", "elokuu", "syyskuu", "lokakuu", "marraskuu", "joulukuu"],
29706            monthsShort: ["tam", "hel", "maa", "huh", "tou", "kes", "hei", "elo", "syy", "lok", "mar", "jou"],
29707            today: "tänään",
29708        };
29709
29710        $.fn.datepicker.defaults.format = "dd.mm.yyyy";
29711        $.fn.datepicker.defaults.language = 'fi-FI';
29712        $.fn.datepicker.defaults.todayHighlight = true;
29713        $.fn.datepicker.defaults.weekStart = 1;
29714        $.fn.datepicker.defaults.startDate = '-36m';
29715    }
29716});

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.