@softwear/latestcollectioncore 1.0.199 → 1.0.202
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/articleStatus.js +49 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +3 -1
- package/dist/parseScannedBarcode.d.ts +6 -0
- package/dist/parseScannedBarcode.js +22 -0
- package/dist/types.d.ts +1 -0
- package/package.json +1 -1
- package/src/articleStatus.ts +47 -0
- package/src/index.ts +1 -0
- package/src/parseScannedBarcode.ts +14 -0
- package/src/types.ts +1 -0
- package/test/articleStatus.spec.js +34 -1
- package/test/parseScannedBarcode.spec.js +30 -0
package/dist/articleStatus.js
CHANGED
|
@@ -364,6 +364,51 @@ function runQuery(timeframe, rawAggregations, beginStock, transactions, selected
|
|
|
364
364
|
}
|
|
365
365
|
return rawAggregations;
|
|
366
366
|
}
|
|
367
|
+
/** True when the bound casts to an ISO instant. A calendar day or a stray "T" does not. */
|
|
368
|
+
function hasClockTime(raw) {
|
|
369
|
+
const value = String(raw).trim();
|
|
370
|
+
const cast = new Date(value);
|
|
371
|
+
if (Number.isNaN(cast.getTime()))
|
|
372
|
+
return false;
|
|
373
|
+
const iso = cast.toISOString();
|
|
374
|
+
// yyyy-MM-dd casts to UTC midnight, but the string is only that date prefix.
|
|
375
|
+
if (iso.slice(0, 10) === value)
|
|
376
|
+
return false;
|
|
377
|
+
// The time designator is the character after yyyy-MM-dd, not a stray "T".
|
|
378
|
+
return value.length > 10 && value[10] === 'T';
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* Exact begin/end for two ISO instants. The end bound is that instant, not end-of-day.
|
|
382
|
+
*/
|
|
383
|
+
function getDateRangeFromIsoInstant(inputDates) {
|
|
384
|
+
const dates = inputDates.slice();
|
|
385
|
+
dates.sort((a, b) => {
|
|
386
|
+
return ('' + a).localeCompare(b);
|
|
387
|
+
});
|
|
388
|
+
const fromDate = new Date(Date.parse(dates[0]));
|
|
389
|
+
const toDate = new Date(Date.parse(dates[1]));
|
|
390
|
+
const beginTimeStamp = fromDate.getTime();
|
|
391
|
+
const endTimeStamp = toDate.getTime();
|
|
392
|
+
const timeFrame = endTimeStamp - beginTimeStamp;
|
|
393
|
+
return {
|
|
394
|
+
beginTimeStamp,
|
|
395
|
+
endTimeStamp,
|
|
396
|
+
timeFrame,
|
|
397
|
+
utcFromYear: fromDate.getUTCFullYear(),
|
|
398
|
+
utcToYear: toDate.getUTCFullYear(),
|
|
399
|
+
utcFromMonth: fromDate.getUTCMonth() + 1,
|
|
400
|
+
utcToMonth: toDate.getUTCMonth() + 1,
|
|
401
|
+
fromYear: parseInt((0, date_fns_1.format)(fromDate, 'yyyy')),
|
|
402
|
+
toYear: parseInt((0, date_fns_1.format)(toDate, 'yyyy')),
|
|
403
|
+
fromMonth: parseInt((0, date_fns_1.format)(fromDate, 'MM')),
|
|
404
|
+
toMonth: parseInt((0, date_fns_1.format)(toDate, 'MM')),
|
|
405
|
+
hrYear: (0, date_fns_1.format)(fromDate, 'yyyy'),
|
|
406
|
+
hrQuarter: (0, date_fns_1.format)(fromDate, 'yyyy-QQQ'),
|
|
407
|
+
hrMonth: (0, date_fns_1.format)(fromDate, 'yyyy-MM'),
|
|
408
|
+
hrWeek: (0, date_fns_1.format)(fromDate, 'RRRR-II'),
|
|
409
|
+
hrDay: (0, date_fns_1.format)(fromDate, 'yyyy-MM-dd'),
|
|
410
|
+
};
|
|
411
|
+
}
|
|
367
412
|
/**
|
|
368
413
|
* @param inputDates array of two YYYY-MM-DD strings
|
|
369
414
|
*/
|
|
@@ -387,6 +432,8 @@ const getDateRangeFromPicker = function (inputDates) {
|
|
|
387
432
|
hrWeek: '',
|
|
388
433
|
hrDay: '',
|
|
389
434
|
};
|
|
435
|
+
if (hasClockTime(inputDates[0]) || hasClockTime(inputDates[1]))
|
|
436
|
+
return getDateRangeFromIsoInstant(inputDates);
|
|
390
437
|
const dates = inputDates.slice();
|
|
391
438
|
dates.sort((a, b) => {
|
|
392
439
|
return ('' + a).localeCompare(b);
|
|
@@ -439,6 +486,8 @@ const getDateRangeFromDatePair = function (inputDates) {
|
|
|
439
486
|
hrWeek: '',
|
|
440
487
|
hrDay: '',
|
|
441
488
|
};
|
|
489
|
+
if (hasClockTime(inputDates[0]) || hasClockTime(inputDates[1]))
|
|
490
|
+
return getDateRangeFromIsoInstant(inputDates);
|
|
442
491
|
const dates = inputDates.slice();
|
|
443
492
|
dates.sort((a, b) => {
|
|
444
493
|
return ('' + a).localeCompare(b);
|
package/dist/index.d.ts
CHANGED
|
@@ -13,6 +13,7 @@ export { default as hashBrand } from './hashBrand';
|
|
|
13
13
|
export { default as hasOnlyDigits } from './hasOnlyDigits';
|
|
14
14
|
export { default as imageBinder } from './imageBinder';
|
|
15
15
|
export { default as isean13 } from './isean13';
|
|
16
|
+
export { default as parseScannedBarcode } from './parseScannedBarcode';
|
|
16
17
|
export { default as pivotTable } from './pivotTable';
|
|
17
18
|
export { default as projectObject } from './projectObject';
|
|
18
19
|
export { default as reports, genPDF } from './reports';
|
package/dist/index.js
CHANGED
|
@@ -17,7 +17,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
17
17
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
18
18
|
};
|
|
19
19
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
-
exports.isAxiosError = exports.exponentialDelay = exports.axiosRetry = exports.createAxiosInstance = exports.lcAxios = exports.shouldSuppressZeroField = exports.resolveLayoutFieldText = exports.isZeroFieldValue = exports.isCurrencyFieldFormat = exports.transaction = exports.sizeToMap = exports.round2 = exports.genPDF = exports.reports = exports.projectObject = exports.pivotTable = exports.isean13 = exports.imageBinder = exports.hasOnlyDigits = exports.hashBrand = exports.getPreferedPropertyMappings = exports.getBrandName = exports.findMetaBrandSetting = exports.findSkuByBarcode = exports.ensureImpliedProperties = exports.ensureArray = exports.edifact = exports.ean13 = exports.deepCopy = exports.buildPropertyMappingFn = exports.articleStatus = void 0;
|
|
20
|
+
exports.isAxiosError = exports.exponentialDelay = exports.axiosRetry = exports.createAxiosInstance = exports.lcAxios = exports.shouldSuppressZeroField = exports.resolveLayoutFieldText = exports.isZeroFieldValue = exports.isCurrencyFieldFormat = exports.transaction = exports.sizeToMap = exports.round2 = exports.genPDF = exports.reports = exports.projectObject = exports.pivotTable = exports.parseScannedBarcode = exports.isean13 = exports.imageBinder = exports.hasOnlyDigits = exports.hashBrand = exports.getPreferedPropertyMappings = exports.getBrandName = exports.findMetaBrandSetting = exports.findSkuByBarcode = exports.ensureImpliedProperties = exports.ensureArray = exports.edifact = exports.ean13 = exports.deepCopy = exports.buildPropertyMappingFn = exports.articleStatus = void 0;
|
|
21
21
|
var articleStatus_1 = require("./articleStatus");
|
|
22
22
|
Object.defineProperty(exports, "articleStatus", { enumerable: true, get: function () { return __importDefault(articleStatus_1).default; } });
|
|
23
23
|
var buildPropertyMappingFn_1 = require("./buildPropertyMappingFn");
|
|
@@ -48,6 +48,8 @@ var imageBinder_1 = require("./imageBinder");
|
|
|
48
48
|
Object.defineProperty(exports, "imageBinder", { enumerable: true, get: function () { return __importDefault(imageBinder_1).default; } });
|
|
49
49
|
var isean13_1 = require("./isean13");
|
|
50
50
|
Object.defineProperty(exports, "isean13", { enumerable: true, get: function () { return __importDefault(isean13_1).default; } });
|
|
51
|
+
var parseScannedBarcode_1 = require("./parseScannedBarcode");
|
|
52
|
+
Object.defineProperty(exports, "parseScannedBarcode", { enumerable: true, get: function () { return __importDefault(parseScannedBarcode_1).default; } });
|
|
51
53
|
var pivotTable_1 = require("./pivotTable");
|
|
52
54
|
Object.defineProperty(exports, "pivotTable", { enumerable: true, get: function () { return __importDefault(pivotTable_1).default; } });
|
|
53
55
|
var projectObject_1 = require("./projectObject");
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gate for scanner / typed barcode input.
|
|
3
|
+
* Strips a leading `#` (scanner prefix), then accepts only 12- or 13-digit strings.
|
|
4
|
+
* Does not validate the EAN check digit (isean13) and does not pad a leading 0 (findSkuByBarcode).
|
|
5
|
+
*/
|
|
6
|
+
export default function parseScannedBarcode(raw: unknown): string | null;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const hasOnlyDigits_1 = __importDefault(require("./hasOnlyDigits"));
|
|
7
|
+
/**
|
|
8
|
+
* Gate for scanner / typed barcode input.
|
|
9
|
+
* Strips a leading `#` (scanner prefix), then accepts only 12- or 13-digit strings.
|
|
10
|
+
* Does not validate the EAN check digit (isean13) and does not pad a leading 0 (findSkuByBarcode).
|
|
11
|
+
*/
|
|
12
|
+
function parseScannedBarcode(raw) {
|
|
13
|
+
if (typeof raw !== 'string')
|
|
14
|
+
return null;
|
|
15
|
+
const scan = raw.startsWith('#') ? raw.substring(1) : raw;
|
|
16
|
+
if (scan.length !== 12 && scan.length !== 13)
|
|
17
|
+
return null;
|
|
18
|
+
if (!(0, hasOnlyDigits_1.default)(scan))
|
|
19
|
+
return null;
|
|
20
|
+
return scan;
|
|
21
|
+
}
|
|
22
|
+
exports.default = parseScannedBarcode;
|
package/dist/types.d.ts
CHANGED
|
@@ -129,6 +129,7 @@ interface SkuI {
|
|
|
129
129
|
brandhash?: string;
|
|
130
130
|
ATTRIBUTES?: object;
|
|
131
131
|
IMAGES?: Array<ImageI>;
|
|
132
|
+
IMAGE_URLS?: Array<string>;
|
|
132
133
|
SIZES?: unknown;
|
|
133
134
|
FOOTPRINT?: number;
|
|
134
135
|
/** UI-only clustering key for product tiles / matrices; not persisted. Phase 1 mirrors articleCodeSupplier after ensureImpliedProperties. */
|
package/package.json
CHANGED
package/src/articleStatus.ts
CHANGED
|
@@ -457,6 +457,51 @@ function runQuery(
|
|
|
457
457
|
return rawAggregations
|
|
458
458
|
}
|
|
459
459
|
|
|
460
|
+
/** True when the bound casts to an ISO instant. A calendar day or a stray "T" does not. */
|
|
461
|
+
function hasClockTime(raw: string): boolean {
|
|
462
|
+
const value = String(raw).trim()
|
|
463
|
+
const cast = new Date(value)
|
|
464
|
+
if (Number.isNaN(cast.getTime())) return false
|
|
465
|
+
const iso = cast.toISOString()
|
|
466
|
+
// yyyy-MM-dd casts to UTC midnight, but the string is only that date prefix.
|
|
467
|
+
if (iso.slice(0, 10) === value) return false
|
|
468
|
+
// The time designator is the character after yyyy-MM-dd, not a stray "T".
|
|
469
|
+
return value.length > 10 && value[10] === 'T'
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
/**
|
|
473
|
+
* Exact begin/end for two ISO instants. The end bound is that instant, not end-of-day.
|
|
474
|
+
*/
|
|
475
|
+
function getDateRangeFromIsoInstant(inputDates: string[]): HrTimeframeI {
|
|
476
|
+
const dates = inputDates.slice()
|
|
477
|
+
dates.sort((a, b) => {
|
|
478
|
+
return ('' + a).localeCompare(b)
|
|
479
|
+
})
|
|
480
|
+
const fromDate = new Date(Date.parse(dates[0]))
|
|
481
|
+
const toDate = new Date(Date.parse(dates[1]))
|
|
482
|
+
const beginTimeStamp = fromDate.getTime()
|
|
483
|
+
const endTimeStamp = toDate.getTime()
|
|
484
|
+
const timeFrame = endTimeStamp - beginTimeStamp
|
|
485
|
+
return {
|
|
486
|
+
beginTimeStamp,
|
|
487
|
+
endTimeStamp,
|
|
488
|
+
timeFrame,
|
|
489
|
+
utcFromYear: fromDate.getUTCFullYear(),
|
|
490
|
+
utcToYear: toDate.getUTCFullYear(),
|
|
491
|
+
utcFromMonth: fromDate.getUTCMonth() + 1,
|
|
492
|
+
utcToMonth: toDate.getUTCMonth() + 1,
|
|
493
|
+
fromYear: parseInt(format(fromDate, 'yyyy')),
|
|
494
|
+
toYear: parseInt(format(toDate, 'yyyy')),
|
|
495
|
+
fromMonth: parseInt(format(fromDate, 'MM')),
|
|
496
|
+
toMonth: parseInt(format(toDate, 'MM')),
|
|
497
|
+
hrYear: format(fromDate, 'yyyy'),
|
|
498
|
+
hrQuarter: format(fromDate, 'yyyy-QQQ'),
|
|
499
|
+
hrMonth: format(fromDate, 'yyyy-MM'),
|
|
500
|
+
hrWeek: format(fromDate, 'RRRR-II'),
|
|
501
|
+
hrDay: format(fromDate, 'yyyy-MM-dd'),
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
|
|
460
505
|
/**
|
|
461
506
|
* @param inputDates array of two YYYY-MM-DD strings
|
|
462
507
|
*/
|
|
@@ -480,6 +525,7 @@ const getDateRangeFromPicker = function (inputDates: string[]): HrTimeframeI {
|
|
|
480
525
|
hrWeek: '',
|
|
481
526
|
hrDay: '',
|
|
482
527
|
}
|
|
528
|
+
if (hasClockTime(inputDates[0]) || hasClockTime(inputDates[1])) return getDateRangeFromIsoInstant(inputDates)
|
|
483
529
|
const dates = inputDates.slice()
|
|
484
530
|
dates.sort((a, b) => {
|
|
485
531
|
return ('' + a).localeCompare(b)
|
|
@@ -534,6 +580,7 @@ const getDateRangeFromDatePair = function (inputDates: string[]): HrTimeframeI {
|
|
|
534
580
|
hrWeek: '',
|
|
535
581
|
hrDay: '',
|
|
536
582
|
}
|
|
583
|
+
if (hasClockTime(inputDates[0]) || hasClockTime(inputDates[1])) return getDateRangeFromIsoInstant(inputDates)
|
|
537
584
|
const dates = inputDates.slice()
|
|
538
585
|
dates.sort((a, b) => {
|
|
539
586
|
return ('' + a).localeCompare(b)
|
package/src/index.ts
CHANGED
|
@@ -13,6 +13,7 @@ export { default as hashBrand } from './hashBrand'
|
|
|
13
13
|
export { default as hasOnlyDigits } from './hasOnlyDigits'
|
|
14
14
|
export { default as imageBinder } from './imageBinder'
|
|
15
15
|
export { default as isean13 } from './isean13'
|
|
16
|
+
export { default as parseScannedBarcode } from './parseScannedBarcode'
|
|
16
17
|
export { default as pivotTable } from './pivotTable'
|
|
17
18
|
export { default as projectObject } from './projectObject'
|
|
18
19
|
export { default as reports, genPDF } from './reports'
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import hasOnlyDigits from './hasOnlyDigits'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Gate for scanner / typed barcode input.
|
|
5
|
+
* Strips a leading `#` (scanner prefix), then accepts only 12- or 13-digit strings.
|
|
6
|
+
* Does not validate the EAN check digit (isean13) and does not pad a leading 0 (findSkuByBarcode).
|
|
7
|
+
*/
|
|
8
|
+
export default function parseScannedBarcode(raw: unknown): string | null {
|
|
9
|
+
if (typeof raw !== 'string') return null
|
|
10
|
+
const scan = raw.startsWith('#') ? raw.substring(1) : raw
|
|
11
|
+
if (scan.length !== 12 && scan.length !== 13) return null
|
|
12
|
+
if (!hasOnlyDigits(scan)) return null
|
|
13
|
+
return scan
|
|
14
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -138,6 +138,7 @@ interface SkuI {
|
|
|
138
138
|
brandhash?: string
|
|
139
139
|
ATTRIBUTES?: object
|
|
140
140
|
IMAGES?: Array<ImageI>
|
|
141
|
+
IMAGE_URLS?: Array<string>
|
|
141
142
|
SIZES?: unknown
|
|
142
143
|
FOOTPRINT?: number
|
|
143
144
|
/** UI-only clustering key for product tiles / matrices; not persisted. Phase 1 mirrors articleCodeSupplier after ensureImpliedProperties. */
|
|
@@ -549,6 +549,7 @@ describe('articleStatus', () => {
|
|
|
549
549
|
it('#getDateRangeFromDatePair', () => {
|
|
550
550
|
const dateRange = articleStatus.getDateRangeFromDatePair(['2023-12-31T23:00:00.000Z', '2024-12-31T23:00:00.000Z'])
|
|
551
551
|
expect(dateRange.beginTimeStamp).toBe(1704063600000)
|
|
552
|
+
expect(dateRange.endTimeStamp).toBe(Date.parse('2024-12-31T23:00:00.000Z'))
|
|
552
553
|
expect(dateRange.fromYear).toBe(2024)
|
|
553
554
|
expect(dateRange.fromMonth).toBe(1)
|
|
554
555
|
expect(dateRange.toYear).toBe(2025)
|
|
@@ -558,7 +559,39 @@ describe('articleStatus', () => {
|
|
|
558
559
|
expect(dateRange.hrMonth).toBe('2024-01')
|
|
559
560
|
expect(dateRange.hrWeek).toBe('2024-01')
|
|
560
561
|
expect(dateRange.hrDay).toBe('2024-01-01')
|
|
561
|
-
expect(dateRange.timeFrame).toBe(
|
|
562
|
+
expect(dateRange.timeFrame).toBe(366 * 24 * 3600 * 1000)
|
|
563
|
+
})
|
|
564
|
+
|
|
565
|
+
it('#getDateRangeFromDatePair keeps clock time for since-last-run windows', () => {
|
|
566
|
+
const from = '2026-09-18T11:04:01.000Z'
|
|
567
|
+
const to = '2026-09-21T15:04:32.000Z'
|
|
568
|
+
const dateRange = articleStatus.getDateRangeFromDatePair([from, to])
|
|
569
|
+
expect(dateRange.beginTimeStamp).toBe(Date.parse(from))
|
|
570
|
+
expect(dateRange.endTimeStamp).toBe(Date.parse(to))
|
|
571
|
+
expect(dateRange.timeFrame).toBe(Date.parse(to) - Date.parse(from))
|
|
572
|
+
})
|
|
573
|
+
|
|
574
|
+
it('#getDateRangeFromDatePair date-only still includes the end day', () => {
|
|
575
|
+
const dateRange = articleStatus.getDateRangeFromDatePair(['2024-01-01', '2024-01-01'])
|
|
576
|
+
expect(dateRange.beginTimeStamp).toBe(Date.parse('2024-01-01'))
|
|
577
|
+
expect(dateRange.endTimeStamp).toBe(Date.parse('2024-01-01') + 24 * 3600 * 1000)
|
|
578
|
+
expect(dateRange.timeFrame).toBe(24 * 3600 * 1000)
|
|
579
|
+
})
|
|
580
|
+
|
|
581
|
+
it('#getDateRangeFromPicker delegates ISO bounds to exact timestamps', () => {
|
|
582
|
+
const from = '2026-09-18T11:04:01.000Z'
|
|
583
|
+
const to = '2026-09-21T15:04:32.000Z'
|
|
584
|
+
const dateRange = articleStatus.getDateRangeFromPicker([from, to])
|
|
585
|
+
expect(dateRange.beginTimeStamp).toBe(Date.parse(from))
|
|
586
|
+
expect(dateRange.endTimeStamp).toBe(Date.parse(to))
|
|
587
|
+
})
|
|
588
|
+
|
|
589
|
+
it('#getDateRangeFromDatePair keeps a real ISO instant that is not the canonical spelling', () => {
|
|
590
|
+
const raw = '2024-01-01T00:00:00Z'
|
|
591
|
+
const dateRange = articleStatus.getDateRangeFromDatePair([raw, raw])
|
|
592
|
+
expect(new Date(raw).toISOString()).not.toBe(raw)
|
|
593
|
+
expect(dateRange.beginTimeStamp).toBe(new Date(raw).getTime())
|
|
594
|
+
expect(dateRange.endTimeStamp).toBe(new Date(raw).getTime())
|
|
562
595
|
})
|
|
563
596
|
|
|
564
597
|
it('should calculate ROI percentage from post-aggregated values', () => {
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
const { parseScannedBarcode } = require('../dist/index')
|
|
2
|
+
|
|
3
|
+
describe('parseScannedBarcode', function () {
|
|
4
|
+
it('returns null for non-strings and empty input', function () {
|
|
5
|
+
expect(parseScannedBarcode(undefined)).toBe(null)
|
|
6
|
+
expect(parseScannedBarcode(null)).toBe(null)
|
|
7
|
+
expect(parseScannedBarcode(1234567890123)).toBe(null)
|
|
8
|
+
expect(parseScannedBarcode('')).toBe(null)
|
|
9
|
+
expect(parseScannedBarcode('#')).toBe(null)
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
it('strips a leading # and accepts 12- or 13-digit scans', function () {
|
|
13
|
+
expect(parseScannedBarcode('195093100888')).toBe('195093100888')
|
|
14
|
+
expect(parseScannedBarcode('0195093100888')).toBe('0195093100888')
|
|
15
|
+
expect(parseScannedBarcode('#195093100888')).toBe('195093100888')
|
|
16
|
+
expect(parseScannedBarcode('#0195093100888')).toBe('0195093100888')
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
it('rejects wrong length, letters, and commas', function () {
|
|
20
|
+
expect(parseScannedBarcode('12345678901')).toBe(null)
|
|
21
|
+
expect(parseScannedBarcode('12345678901234')).toBe(null)
|
|
22
|
+
expect(parseScannedBarcode('19509310088a')).toBe(null)
|
|
23
|
+
expect(parseScannedBarcode('19509310088,8')).toBe(null)
|
|
24
|
+
expect(parseScannedBarcode('12e3456789012')).toBe(null)
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
it('does not require a valid EAN check digit', function () {
|
|
28
|
+
expect(parseScannedBarcode('1234567890129')).toBe('1234567890129')
|
|
29
|
+
})
|
|
30
|
+
})
|