PageSourceSearch

https://www.prairiequilt.com/1775641146/pos-app/js/utils.js

js prairiequilt.com collected 2026-09-25 20:59:22 UTC 20,161 bytes, 751 lines download raw bytes

1function getHourList(startHour, endHour)
2{
3    var hours   = [];
4
5    if(!isNaN(startHour) && !isNaN(endHour))
6    {
7        for(var i = startHour; i <= endHour; i++)
8        {
9            var ampm    = (i > 11 ? "pm" : "am");
10            var hour    = i.toString();
11            if(hour > 12)
12            {
13                hour -= 12;
14            }
15            hours.push({"name":hour + ":00" + ampm});
16            if(i !== endHour)
17            {
18                hours.push({"name":hour + ":30" + ampm});
19            }
20        }
21    }
22    return hours;
23}
24
25function selectOption(coll, selection)
26{
27    for(var i = 0; i < coll.length; i++)
28    {
29        if(coll[i].name === selection)
30        {
31            return coll[i];
32        }
33    }
34    return coll[0];
35}
36
37function checkAndParseFloat(value)
38{
39    var result = 0;
40    if(value !== null && !isNaN(value) && value !== "")
41    {
42        result = parseFloat(value);
43    }
44    return result;
45}
46
47function validateAndParseFloat(a_number) {
48    "use strict";
49    var return_value = 0;
50
51    if (a_number) {
52        return_value = parseFloat(a_number);
53        if ((isNaN(return_value)) || (return_value === null)) {
54            return_value = 0;
55        }
56    }
57
58    return return_value;
59}
60
61function roundAndFixNumberAsString(a_number) {
62    "use strict";
63    var value = validateAndParseFloat(a_number);
64
65    var return_value = '';
66
67    return_value = Number(Math.round(value + 'e' + 2) + 'e-' + 2).toFixed(2);
68
69    return return_value;
70}
71
72function roundAndFixNumberAsNumber(a_number) {
73    "use strict";
74    var value = validateAndParseFloat(a_number);
75
76    var return_value = '';
77
78    return_value = Number(Math.round(value + 'e' + 2) + 'e-' + 2);
79
80    return return_value;
81}
82
83// This is here because toFixed has bugs when rounding and is not reliable
84function roundNumber(value, precision) {
85    if (!value) {
86        return 0;
87    }
88
89    if (precision <= 0) {
90        precision = 0;
91    } else if (!precision) {
92        precision = 2;
93    }
94
95    var p = Math.pow(10, precision);
96    return Math.round(value * p) / p;
97}
98
99function intersect_arrays(first, second) {
100    "use strict";
101    var common = [];
102
103    if ((first) && (second)) {
104        var sorted_a = first.concat().sort();
105        var sorted_b = second.concat().sort();
106        var first_i = 0;
107        var second_i = 0;
108
109        while (first_i < first.length && second_i < second.length) {
110            if ((sorted_a[first_i] === sorted_b[second_i]) || (parseInt(sorted_a[first_i]) === parseInt(sorted_b[second_i]))){
111                common.push(sorted_a[first_i]);
112                first_i++;
113                second_i++;
114            }
115            else if (sorted_a[first_i] < sorted_b[second_i]) {
116                first_i++;
117            }
118            else {
119                second_i++;
120            }
121        }
122    }
123
124    return common;
125}
126
127function roundIt(amount)
128{
129    var bd = new BigDecimal(amount);
130    var rounded = bd.setScale(2, BigDecimal.ROUND_HALF_UP);
131    return parseFloat(rounded.toString());
132}
133
134function getNextDate(date, interval)
135{
136    var parsed = dateFns.parse(date);
137    switch(interval)
138    {
139        case 'Weekly':
140            return dateFns.format(dateFns.addWeeks(parsed, 1), "M/D/YYYY");
141        case 'Bi-Weekly':
142            return dateFns.format(dateFns.addWeeks(parsed, 2), "M/D/YYYY");
143        case 'Monthly':
144            return dateFns.format(dateFns.addMonths(parsed, 1), "M/D/YYYY");
145        case 'Yearly':
146            return dateFns.format(dateFns.addYears(parsed, 1), "M/D/YYYY");
147        default:
148            break;
149    }
150}
151
152function todaysDateString()
153{
154    var today = new Date();
155    return (today.getMonth()+1) + "/" + today.getDate() + "/" + today.getFullYear();
156}
157
158function formatPhone(phone_text) {
159    if (phone_text !== undefined && phone_text !== null) {
160
161        if (phone_text.charAt(0) == '+' && phone_text.length > 10) {
162            phone_text = formatPhone(phone_text.substr(1));
163        } else if (phone_text.length >= 10) {
164            var temp_text = phone_text.replace(/[\- \(\)+]/g, "");
165            var start = temp_text.length - 10;
166            var end = temp_text.length;
167            phone_text = temp_text.substr(start,end).replace(/(\d{3})(\d{3})(\d{4})/, "($1) $2-$3");
168        } else if (phone_text.length >= 7) {
169            var temp_text = phone_text.replace(/[\- \(\)+]/g, "");
170            var start = temp_text.length - 7;
171            var end = temp_text.length;
172            phone_text = temp_text.substr(start,end).replace(/(\d{3})(\d{4})/, "$1-$2");
173        }
174
175        if (phone_text.length === 10) {
176
177            phone_text = phone_text.replace(/(\d{3})(\d{3})(\d{4})/, "($1) $2-$3");
178        } else if (phone_text.length === 7) {
179
180            phone_text = phone_text.replace(/(\d{3})(\d{4})/, "$1-$2");
181        }
182    }
183    return phone_text;
184}
185
186function getPaymentInfo(total, term, start_date, due_date)
187{
188    "use strict";
189    var info = new Object();
190    if(start_date === null)
191    {
192        start_date = todaysDateString();
193    }
194
195    var startDate = moment(start_date);
196
197    var dueDate = moment(due_date);
198
199    var numOfPayments = dueDate.diff(startDate, term);
200    var lastRegularPaymentDate = startDate.add(term, numOfPayments);
201
202    //console.log('Difference is ', numOfPayments, term);
203    var daysLeft = dueDate.diff(lastRegularPaymentDate, 'days');
204    if(daysLeft > 0)
205    {
206        numOfPayments++;
207    }
208    //console.log('Days remainder ', daysLeft);
209
210    info.payment_amount = Math.round(total/numOfPayments);
211    info.final_payment_amount = total - (info.payment_amount * numOfPayments);
212    info.num_of_payments = numOfPayments-1;
213    if(daysLeft >= 0)
214    {
215        info.final_payment_amount = info.final_payment_amount + info.payment_amount;
216    }
217    //console.log('payment amount ', payment*2);
218
219    //console.log(daysLeft);
220    //console.log(lastRegularPaymentDate.format("l"));
221    return info;
222}
223
224function removeFromArray(key, myArray)
225{
226    "use strict";
227    for(var i = myArray.length-1; i >= 0; i--){  // STEP 1
228        if(myArray[i].key === key){              // STEP 2
229            myArray.splice(i,1);                 // STEP 3
230        }
231    }
232    return myArray;
233}
234
235function is_array(value) {
236    "use strict";
237    if (value) {
238        return value &&
239            typeof value === 'object' &&
240            typeof value.length === 'number' &&
241            typeof value.splice === 'function' &&
242            !(value.propertyIsEnumerable('length'));
243    } else {
244        return false;
245    }
246};
247
248function getCardType(cc_number) {
249
250    var card_type = "";
251
252    if(!isNaN(cc_number)) {
253
254        var num = cc_number.substring(0, 1);
255        num = parseInt(num);
256
257        switch (num) {
258
259            case 3:
260                card_type = "AMEX";
261                break;
262            case 4:
263                card_type = "VISA";
264                break;
265            case 5:
266                card_type = "MC";
267                break;
268            case 6:
269                card_type = "DISC";
270                break;
271            default:
272                break;
273        }
274    }
275
276    return card_type;
277};
278
279function is_set(val) {
280
281    return (val !== undefined && val !== null);
282};
283
284function objectIsEmpty(obj) {
285
286    return !obj || Object.keys(obj).length <= 0;
287};
288
289function is_undefined(val) {
290
291    return (typeof val === "undefined");
292};
293
294function toFixedNoZero(x, d) {
295    if (!d) return x.toFixed(d); // don't go wrong if no decimal
296    return x.toFixed(d).replace(/\.?0+$/, '');
297};
298
299function diffInMonths(date1, date2) {
300
301    var a = moment(date1);
302    var b = moment(date2);
303    return a.diff(b, 'months')
304};
305
306function getYearsObjectsList(num_of_years, num_of_future_years_to_add) {
307
308    var now = new moment();
309    var current_year = parseInt(now.format("YYYY"));
310
311    if(!is_set(num_of_years)) {
312
313        num_of_years = 20;
314    }
315
316    if(is_set(num_of_future_years_to_add)) {
317
318        num_of_years += num_of_future_years_to_add;
319        current_year += num_of_future_years_to_add;
320    }
321
322    var years = [];
323    for (var i = 0; i < num_of_years; i++) {
324
325        years.push({id:i, year:current_year});
326        current_year--;
327    }
328    return years;
329};
330
331function uppercaseFirstLetter(str) {
332
333    return str.charAt(0).toUpperCase() + str.slice(1);
334};
335
336function getTotalAmountFromCollection(collection) {
337
338    var total = null;
339    if(collection) {
340
341        total = 0;
342        for(var i = 0; i < collection.length; i++) {
343
344            var item = collection[i];
345            if(item.amount) {
346
347                total += parseFloat(item.amount);
348            }
349        }
350    }
351    return total;
352}
353
354function toNumeric(amount) {
355
356    if(amount) {
357
358        amount = amount.replace(/[^0-9\.]/g, "");
359    }
360    return amount;
361}
362
363/**
364 * QTY Precision constant
365 */
366var DEFAULT_QTY_PRECISION = 3;
367
368/**
369 * This method return amount value with 2 or 3 precision.
370 * We need this for smarty showing qty amount.
371 * If qty has 3 digits after decimal point we will show it
372 * In other case - show 2 digits
373 * */
374function qtyAmountFormat(value, precision, hideDecimal = false) {
375    if (typeof precision === 'undefined') {
376        precision = DEFAULT_QTY_PRECISION;
377    }
378    var qtyAmount = roundNumber(value, precision);
379    if (hideDecimal) {
380        //If decimal is .00, get rid of them
381        if (qtyAmount % 1 === 0) {
382            return qtyAmount.toFixed(0);
383        }
384    }
385    if (qtyAmount.toString().indexOf('.') !== -1) {
386        var decimalPlaces = qtyAmount.toString().split('.')[1].length;
387        if (decimalPlaces < 3) {
388            qtyAmount = qtyAmount.toFixed(2);
389        } else {
390            qtyAmount = qtyAmount.toFixed(3);
391        }
392    } else {
393        qtyAmount = qtyAmount.toFixed(2);
394    }
395
396    return qtyAmount;
397}
398
399function is_string(val) {
400    return typeof val === 'string' || ((!!val && typeof val === 'object') && Object.prototype.toString.call(val) === '[object String]');
401}
402
403function is_json(str) {
404    if (!(str && typeof str === "string")) {
405        return false;
406    }
407
408    try {
409        JSON.parse(str);
410        return true;
411    } catch(error) {
412        return false;
413    }
414}
415
416function isValidEmail(string){
417    return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(string)
418}
419
420/**
421 * @link https://regex101.com/r/xI4jdu/5 for test list
422 * @param email
423 * @returns {boolean}
424 */
425function isValidEmailV2(email){
426    return /^[\w\d!#$%&'*+/=?^_`{|}~-]+(?:\.[\w\d!#$%&'*+/=?^_`{|}~-]+)*@(?:[\w\d](?:[\w\d-]*[\w\d])?\.)+[\w\d](?:[\w\d-]*[\w\d])?$/.test(email);
427}
428
429function isSimplePhoneNumber(phoneNumber) {
430    //Can start with + must have >= 11 digits
431    //If no +, must have >= 10 digits
432    //Spaces okay
433    return /^(?:\+(\d\s?){11,}|(\d\s?){10,})$/.test(phoneNumber);
434}
435
436function isValidPostalCode(postalCode, countryIso3Code) {
437    if (!postalCode || !countryIso3Code) {
438        return false;
439    }
440
441    switch (countryIso3Code) {
442        case 'USA':
443            return /^\d{5}(?:-\d{4})?$/.test(postalCode);
444        case 'CAN':
445            return /^[A-Za-z]\d[A-Za-z][ -]?\d[A-Za-z]\d$/.test(postalCode);
446        case 'AUS':
447        case 'NZL':
448            return /^\d{4}$/.test(postalCode);
449        case 'GBR':
450            return /^[A-Za-z]{1,2}\d[A-Za-z\d]?\s?\d[A-Za-z]{2}$/.test(postalCode);
451        default:
452            return postalCode.length >= 3;
453    }
454}
455
456// This should mimic the logic of module levers
457function checkFlag(flagName) {
458    flagName = 'module_' + flagName;
459    return !is_undefined(window.knobby) && !is_undefined(window.knobby[flagName]) && window.knobby[flagName] === true;
460}
461
462function reportMarginCalculationWithoutRounding(cost, net) {
463    // Revenue = 0: undefined margin (--) :
464    // A product sold for 0.00, but the cost is greater than 0.00. We can’t calculate the margin because it was given away for free.
465    if (net === 0 && cost > 0) {
466        return '&nbsp;&nbsp;--';
467    }
468
469    // Cost = 0, revenue > 0: 100% margin (100%):
470    // Product doesn't have a cost assigned. Or the cost assigned is $0. Therefore the entire amount of revenue collected is considered profit.
471    // roundedNet < 0 for return cases
472    if ((net > 0  || net < 0) && cost === 0) {
473        return '100.00%';
474    }
475
476    // Revenue = Cost: zero margin (0%):
477    // Product is sold for exactly what it cost.
478    if (net === cost) {
479        return '0.00%';
480    }
481
482    // Revenue < Cost: negative margin (-20%):
483    // Product is sold for less than it cost. You can go above a -100% margin, since items can cost significantly more than what might be collected in revenue.
484    // Revenue > Cost: positive margin (50%):
485    // Product is sold for more than it cost. This should be the most common use case, since stores would go out of business otherwise.
486    return (((net - cost)/net) * 100).toFixed(2)+'%';
487
488}
489
490function handleDropDownMenuContentWidth() {
491    var dropDownMenus = document.querySelectorAll("ul.dropdown-menu.ng-isolate-scope");
492    var handleContentWidth = function (el) {
493        var initialContent = el.textContent;
494        var checks = el.textContent.length;
495        var newContent = '';
496        var newLines = [];
497        var offset = 5;
498        for (var i = 0; i < checks; i++) {
499            newContent += initialContent[i];
500            el.innerHTML = newContent;
501            if (el.scrollWidth > el.clientWidth) {
502                newLines.push(newContent.slice(0, -offset));
503                newContent = newContent.slice(-offset);
504            }
505        }
506        newLines.push(newContent);
507        el.innerHTML = newLines.join('<br />');
508    }
509
510    /* Options for the observer (which mutations to observe) */
511    var config = {childList: true};
512
513    /* Callback function to execute when mutations are observed */
514    var callback = function (mutationsList, observer) {
515        var menu = mutationsList.pop().target;
516        for (var child of menu.children) {
517            var ref = child.querySelector("a");
518            if (ref.scrollWidth > ref.clientWidth) {
519                handleContentWidth(ref);
520            }
521        }
522    };
523
524    /* Create an observer instance linked to the callback function */
525    var observer = new MutationObserver(callback);
526
527    dropDownMenus.forEach(function (dropDownMenu) {
528        /* Start observing the target node for configured mutations */
529        observer.observe(dropDownMenu, config);
530    });
531}
532
533function getBrandSpecificTerm(term) {
534    var brandSpecificTerm = '';
535
536    if (industryTerms !== undefined
537        && industryTerms[term] !== undefined) {
538        brandSpecificTerm = industryTerms[term];
539    } else {
540        if (term === 'vendor_consignment') {
541            brandSpecificTerm = 'Vendor Consignment';
542        } else if (term === 'vendor_consign') {
543            brandSpecificTerm = 'Vendor Consign';
544
545        }
546    }
547
548    return brandSpecificTerm;
549}
550
551function waitForElm(selector) {
552    return new Promise(function(resolve) {
553        if (document.querySelector(selector)) {
554            return resolve(document.querySelector(selector));
555        }
556
557        var observer = new MutationObserver(function(mutations) {
558            if (document.querySelector(selector)) {
559                resolve(document.querySelector(selector));
560                observer.disconnect();
561            }
562        });
563
564        observer.observe(document.body, {
565            childList: true,
566            subtree: true
567        });
568    });
569}
570
571function isChromeInIos() {
572    return navigator.userAgent.toLowerCase().includes('crios');
573}
574
575function printJSFixed(options) {
576    // print-js pdf print doesn't work in Chrome on IOS, because of a browser compatibility issue,
577    // so we do this workaround instead
578	if (checkFlag('print_ipad_fix') && (isChromeInIos() && 'pdf' === options.type && options.base64)) {
579		// Convert base64 to blob and create blob URL to avoid cross-origin restrictions
580		const base64Data = options.printable;
581		const byteCharacters = atob(base64Data);
582		const byteNumbers = new Array(byteCharacters.length);
583
584		for (let i = 0; i < byteCharacters.length; i++) {
585			byteNumbers[i] = byteCharacters.charCodeAt(i);
586		}
587
588        const byteArray = new Uint8Array(byteNumbers);
589		const blob = new Blob([byteArray], {type: 'application/pdf'});
590		const blobUrl = URL.createObjectURL(blob);
591
592		let pdfWindow = window.open(blobUrl, '_blank');
593
594		if (!pdfWindow) {
595			URL.revokeObjectURL(blobUrl);
596			return;
597		}
598
599		let hasPrinted = false;
600
601		// Wait for the PDF to load, then print the window directly
602		// Since the window only contains the PDF, printing the window will print the PDF
603		pdfWindow.onload = function() {
604			setTimeout(function() {
605				if (!hasPrinted) {
606					hasPrinted = true;
607					pdfWindow.print();
608
609					setTimeout(function() {
610						URL.revokeObjectURL(blobUrl);
611					}, 1000);
612				}
613			}, 500);
614		};
615
616		// Fallback: if onload doesn't fire, try printing after a delay
617		setTimeout(function() {
618			if (pdfWindow && !pdfWindow.closed && !hasPrinted) {
619				hasPrinted = true;
620				pdfWindow.print();
621
622				setTimeout(function() {
623					URL.revokeObjectURL(blobUrl);
624				}, 1000);
625			}
626		}, 1000);
627	} else if (isChromeInIos() && 'pdf' === options.type && options.base64) {
628        var newWindow = window.open('', '_blank');
629        newWindow.document.write('<embed width="100%" height="100%" src="data:application/pdf;base64,' + options.printable + '" type="application/pdf"/>');
630        newWindow.print();
631    } else {
632        printJS(options);
633    }
634}
635
636function jqprintCheckChromeOnIOS(elements) {
637    // print doesn't work in Chrome on IOS, because of a browser compatibility issue,
638    // so we do this workaround instead
639    if (isChromeInIos()) {
640        let printWindow = window.open('', '_blank');
641
642        printWindow.document.write($(elements).html());
643        printWindow.document.close();
644        printWindow.print();
645    } else {
646        $(elements).jqprint({importCSS: true});
647    }
648}
649
650function hasUserPermission(key) {
651    if (!window.hasOwnProperty('rain_permission')) {
652        return true;
653    }
654
655    var permission = window.rain_permission;
656
657    if (!permission.hasOwnProperty(key)) {
658        return false;
659    }
660
661    return permission[key];
662}
663
664function arraySum(array) {
665    if (!Array.isArray(array)) {
666        return 0;
667    }
668
669    return array.reduce(function (carry, current) {
670        return carry + current;
671    }, 0);
672}
673
674function arrayUnique(array) {
675    if (!Array.isArray(array)) {
676        return [];
677    }
678
679    return array.filter(function(value, index, array) {
680        return array.indexOf(value) === index;
681    });
682}
683
684function jsonToQueryParams(data) {
685    if (objectIsEmpty(data)) {
686        return '';
687    }
688
689    return Object.keys(data).map(function(k) {
690        return encodeURIComponent(k) + '=' + encodeURIComponent(data[k])
691    }).join('&');
692}
693
694function generateUniqueID() {
695    var d = new Date().getTime();
696    var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
697        var r = (d + Math.random() * 16) % 16 | 0;
698        d = Math.floor(d / 16);
699        return (c == 'x' ? r : (r & 0x7 | 0x8)).toString(16);
700    });
701    return uuid;
702}
703
704if (typeof getPartsDate === 'undefined') {
705    function getPartsDate(date) {
706        if (!date || typeof date !== 'string') {
707            return {
708                month: 0,
709                day: 0,
710                year: 0,
711            };
712        }
713        var dateParts = date.split('/');
714
715        return {
716            month: parseInt(dateParts[0], 10),
717            day: parseInt(dateParts[1], 10),
718            year: parseInt(dateParts[2], 10),
719        };
720    }
721}
722
723var TBDSerialHelper = function() {
724    "use strict";
725    this.lastGeneratedTBD = '';
726    this.generatedTBDIndex = 0;
727};
728
729TBDSerialHelper.prototype = {
730    lastGeneratedTBD: '',
731    generatedTBDIndex: 0,
732    isTBD: function (serial) {
733        return serial.toUpperCase().startsWith('TBD');
734    },
735    getTBD: function (date) {
736        if (!(date instanceof Date)) {
737            date = new Date();
738        }
739
740        const serial = 'TBD-' + dateFns.format(date, 'YYYY-MM-DD_HH:mm:ss');
741
742        if (serial !== this.lastGeneratedTBD) {
743            this.lastGeneratedTBD = serial;
744            this.generatedTBDIndex = 0;
745
746            return serial;
747        }
748
749        return serial + '-' + ++this.generatedTBDIndex;
750    }
751}

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.