@aidc-toolkit/gs1 0.9.17-beta → 0.9.19-beta
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/README.md +41 -14
- package/dist/character-set.d.ts +11 -1
- package/dist/character-set.d.ts.map +1 -1
- package/dist/character-set.js +10 -0
- package/dist/character-set.js.map +1 -1
- package/dist/check.d.ts +10 -8
- package/dist/check.d.ts.map +1 -1
- package/dist/check.js +28 -21
- package/dist/check.js.map +1 -1
- package/dist/idkey.d.ts +86 -2
- package/dist/idkey.d.ts.map +1 -1
- package/dist/idkey.js +223 -8
- package/dist/idkey.js.map +1 -1
- package/dist/locale/en/locale-strings.d.ts +7 -3
- package/dist/locale/en/locale-strings.d.ts.map +1 -1
- package/dist/locale/en/locale-strings.js +7 -3
- package/dist/locale/en/locale-strings.js.map +1 -1
- package/dist/locale/fr/locale-strings.d.ts +7 -3
- package/dist/locale/fr/locale-strings.d.ts.map +1 -1
- package/dist/locale/fr/locale-strings.js +7 -3
- package/dist/locale/fr/locale-strings.js.map +1 -1
- package/dist/locale/i18n.d.ts +4 -83
- package/dist/locale/i18n.d.ts.map +1 -1
- package/dist/locale/i18n.js.map +1 -1
- package/package.json +6 -6
- package/src/character-set.ts +13 -1
- package/src/check.ts +32 -23
- package/src/idkey.ts +293 -12
- package/src/locale/en/locale-strings.ts +7 -3
- package/src/locale/fr/locale-strings.ts +7 -3
- package/src/locale/i18n.ts +4 -4
- package/test/check.test.ts +19 -15
- package/test/idkey.test.ts +201 -3
package/src/idkey.ts
CHANGED
|
@@ -2,13 +2,13 @@ import {
|
|
|
2
2
|
CharacterSetCreator,
|
|
3
3
|
type CharacterSetValidation,
|
|
4
4
|
Exclusion,
|
|
5
|
+
mapIterable,
|
|
5
6
|
NUMERIC_CREATOR,
|
|
6
7
|
RegExpValidator,
|
|
7
8
|
type StringValidation,
|
|
8
9
|
type StringValidator,
|
|
9
10
|
type TransformerInput,
|
|
10
|
-
type TransformerOutput
|
|
11
|
-
transformIterable
|
|
11
|
+
type TransformerOutput
|
|
12
12
|
} from "@aidc-toolkit/utility";
|
|
13
13
|
import { Mixin } from "ts-mixer";
|
|
14
14
|
import { AI39_CREATOR, AI82_CREATOR } from "./character-set.js";
|
|
@@ -17,7 +17,9 @@ import {
|
|
|
17
17
|
checkDigit,
|
|
18
18
|
checkDigitSum,
|
|
19
19
|
hasValidCheckCharacterPair,
|
|
20
|
-
hasValidCheckDigit
|
|
20
|
+
hasValidCheckDigit,
|
|
21
|
+
isValidPriceOrWeightCheckDigit,
|
|
22
|
+
priceOrWeightCheckDigit
|
|
21
23
|
} from "./check.js";
|
|
22
24
|
import { i18nextGS1 } from "./locale/i18n.js";
|
|
23
25
|
|
|
@@ -141,6 +143,9 @@ export interface IdentificationKeyValidation extends StringValidation {
|
|
|
141
143
|
/**
|
|
142
144
|
* Identification key validator. Validates an identification key against its definition in section 3 of the {@link
|
|
143
145
|
* https://www.gs1.org/genspecs | GS1 General Specifications}.
|
|
146
|
+
*
|
|
147
|
+
* @template TIdentificationKeyValidation
|
|
148
|
+
* Identification key validation type.
|
|
144
149
|
*/
|
|
145
150
|
export interface IdentificationKeyValidator<TIdentificationKeyValidation extends IdentificationKeyValidation = IdentificationKeyValidation> extends StringValidator<TIdentificationKeyValidation> {
|
|
146
151
|
/**
|
|
@@ -167,7 +172,7 @@ export interface IdentificationKeyValidator<TIdentificationKeyValidation extends
|
|
|
167
172
|
get referenceCharacterSet(): ContentCharacterSet;
|
|
168
173
|
|
|
169
174
|
/**
|
|
170
|
-
* Get the reference
|
|
175
|
+
* Get the reference creator.
|
|
171
176
|
*/
|
|
172
177
|
get referenceCreator(): CharacterSetCreator;
|
|
173
178
|
|
|
@@ -467,6 +472,21 @@ export enum GTINLevel {
|
|
|
467
472
|
OtherThanRetailConsumer
|
|
468
473
|
}
|
|
469
474
|
|
|
475
|
+
/**
|
|
476
|
+
* Restricted Circulation Number reference.
|
|
477
|
+
*/
|
|
478
|
+
export interface RCNReference {
|
|
479
|
+
/**
|
|
480
|
+
* Item reference.
|
|
481
|
+
*/
|
|
482
|
+
itemReference: number;
|
|
483
|
+
|
|
484
|
+
/**
|
|
485
|
+
* Price or weight (whole number only).
|
|
486
|
+
*/
|
|
487
|
+
priceOrWeight: number;
|
|
488
|
+
}
|
|
489
|
+
|
|
470
490
|
/**
|
|
471
491
|
* GTIN validator.
|
|
472
492
|
*/
|
|
@@ -629,10 +649,8 @@ export class GTINValidator extends AbstractNumericIdentificationKeyValidator {
|
|
|
629
649
|
|
|
630
650
|
NUMERIC_CREATOR.validate(indicatorDigit, GTINValidator.OPTIONAL_INDICATOR_DIGIT_VALIDATION);
|
|
631
651
|
|
|
632
|
-
const gtinLength = gtin.length;
|
|
633
|
-
|
|
634
652
|
// Check digit doesn't change by prepending zeros.
|
|
635
|
-
let gtin14 =
|
|
653
|
+
let gtin14 = gtin.padStart(GTINType.GTIN14, "0");
|
|
636
654
|
|
|
637
655
|
// If indicator digit provided and is different, recalculate the check digit.
|
|
638
656
|
if (indicatorDigit.length !== 0 && indicatorDigit !== gtin14.charAt(0)) {
|
|
@@ -802,6 +820,134 @@ export class GTINValidator extends AbstractNumericIdentificationKeyValidator {
|
|
|
802
820
|
|
|
803
821
|
GTINCreator.validateAny(gtin14);
|
|
804
822
|
}
|
|
823
|
+
|
|
824
|
+
/**
|
|
825
|
+
* Parse a Restricted Circulation Number (RCN) using a variable measure trade item format. The format is a 12- or
|
|
826
|
+
* 13-character string (for RCN-12 or RCN-13 respectively), containing the following:
|
|
827
|
+
*
|
|
828
|
+
* - '2' - The first character of the RCN.
|
|
829
|
+
* - '0'-'9' - The second character of the RCN (RCN-13 only).
|
|
830
|
+
* - 'I' - One or more, in sequence, for the item reference.
|
|
831
|
+
* - 'P' - One or more, in sequence, for the price or weight.
|
|
832
|
+
* - 'V' - Zero or one, for the price or weight check digit.
|
|
833
|
+
* - 'C' - The check digit of the entire RCN.
|
|
834
|
+
*
|
|
835
|
+
* The 'I', 'P', and 'V' formats may be in any order.
|
|
836
|
+
*
|
|
837
|
+
* Some examples:
|
|
838
|
+
*
|
|
839
|
+
* - 2IIIIIVPPPPC - RCN-12 with a five-digit item reference, a price or weight check digit, and a four-digit price
|
|
840
|
+
* or weight.
|
|
841
|
+
* - 23IIIIVPPPPPC - RCN-13 with a four-digit item reference, a price or weight check digit, and a five-digit price
|
|
842
|
+
* or weight.
|
|
843
|
+
* - 2IIIIIIPPPPC - RCN-12 with a six-digit item reference and a four-digit price or eight.
|
|
844
|
+
* - 29IIIIIPPPPPC - RCN-13 with a five-digit item reference and a five-digit price or weight.
|
|
845
|
+
*
|
|
846
|
+
* @param format
|
|
847
|
+
* Format.
|
|
848
|
+
*
|
|
849
|
+
* @param rcn
|
|
850
|
+
* RCN.
|
|
851
|
+
*
|
|
852
|
+
* @returns
|
|
853
|
+
* RCN reference.
|
|
854
|
+
*/
|
|
855
|
+
static parseVariableMeasureRCN(format: string, rcn: string): RCNReference {
|
|
856
|
+
const formatLength = format.length;
|
|
857
|
+
|
|
858
|
+
if (rcn.length !== formatLength) {
|
|
859
|
+
throw new RangeError(i18nextGS1.t("IdentificationKey.invalidRCNLength"));
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
let validFormat = formatLength === 12 || formatLength === 13;
|
|
863
|
+
let validRCNPrefix = true;
|
|
864
|
+
|
|
865
|
+
let buildingItemReference = false;
|
|
866
|
+
let itemReference = "";
|
|
867
|
+
|
|
868
|
+
let buildingPriceOrWeight = false;
|
|
869
|
+
let priceOrWeight = "";
|
|
870
|
+
|
|
871
|
+
let priceOrWeightCheckDigit = "";
|
|
872
|
+
|
|
873
|
+
for (let index = 0; validFormat && index < formatLength; index++) {
|
|
874
|
+
const formatChar = format.charAt(index);
|
|
875
|
+
const rcnChar = rcn.charAt(index);
|
|
876
|
+
|
|
877
|
+
if (index === 0) {
|
|
878
|
+
validFormat = formatChar === "2";
|
|
879
|
+
validRCNPrefix = rcnChar === "2";
|
|
880
|
+
} else if (formatLength === 13 && index === 1) {
|
|
881
|
+
validFormat = NUMERIC_CREATOR.characterIndex(formatChar) !== undefined;
|
|
882
|
+
validRCNPrefix = rcnChar === formatChar;
|
|
883
|
+
} else if (index === formatLength - 1) {
|
|
884
|
+
validFormat = formatChar === "C";
|
|
885
|
+
} else {
|
|
886
|
+
switch (formatChar) {
|
|
887
|
+
case "I":
|
|
888
|
+
if (!buildingItemReference) {
|
|
889
|
+
// Item reference can't appear more than once.
|
|
890
|
+
validFormat = itemReference === "";
|
|
891
|
+
|
|
892
|
+
buildingItemReference = true;
|
|
893
|
+
buildingPriceOrWeight = false;
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
itemReference += rcnChar;
|
|
897
|
+
break;
|
|
898
|
+
|
|
899
|
+
case "P":
|
|
900
|
+
if (!buildingPriceOrWeight) {
|
|
901
|
+
// Price or weight can't appear more than once.
|
|
902
|
+
validFormat = priceOrWeight === "";
|
|
903
|
+
|
|
904
|
+
buildingPriceOrWeight = true;
|
|
905
|
+
buildingItemReference = false;
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
priceOrWeight += rcnChar;
|
|
909
|
+
break;
|
|
910
|
+
|
|
911
|
+
case "V":
|
|
912
|
+
// Price or weight check digit can't appear more than once.
|
|
913
|
+
validFormat = priceOrWeightCheckDigit === "";
|
|
914
|
+
|
|
915
|
+
buildingItemReference = false;
|
|
916
|
+
buildingPriceOrWeight = false;
|
|
917
|
+
|
|
918
|
+
priceOrWeightCheckDigit = rcnChar;
|
|
919
|
+
break;
|
|
920
|
+
|
|
921
|
+
default:
|
|
922
|
+
validFormat = false;
|
|
923
|
+
break;
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
validFormat &&= itemReference !== "" && priceOrWeight !== "";
|
|
929
|
+
|
|
930
|
+
if (!validFormat) {
|
|
931
|
+
throw new RangeError(i18nextGS1.t("IdentificationKey.invalidVariableMeasureRCNFormat"));
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
if (!validRCNPrefix) {
|
|
935
|
+
throw new RangeError(i18nextGS1.t("IdentificationKey.invalidVariableMeasureRCNPrefix"));
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
if (priceOrWeightCheckDigit !== "" && !isValidPriceOrWeightCheckDigit(priceOrWeight, priceOrWeightCheckDigit)) {
|
|
939
|
+
throw new RangeError(i18nextGS1.t("IdentificationKey.invalidVariableMeasurePriceOrWeight"));
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
if (!hasValidCheckDigit(rcn)) {
|
|
943
|
+
throw new RangeError(i18nextGS1.t("IdentificationKey.invalidCheckDigit"));
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
return {
|
|
947
|
+
itemReference: Number(itemReference),
|
|
948
|
+
priceOrWeight: Number(priceOrWeight)
|
|
949
|
+
};
|
|
950
|
+
}
|
|
805
951
|
}
|
|
806
952
|
|
|
807
953
|
/**
|
|
@@ -1194,6 +1340,9 @@ export interface NumericIdentificationKeyCreator extends NumericIdentificationKe
|
|
|
1194
1340
|
* Create identification key(s) with reference(s) based on numeric value(s). The value(s) is/are converted to
|
|
1195
1341
|
* references of the appropriate length using {@linkcode NUMERIC_CREATOR}.
|
|
1196
1342
|
*
|
|
1343
|
+
* @template TTransformerInput
|
|
1344
|
+
* Transformer input type.
|
|
1345
|
+
*
|
|
1197
1346
|
* @param valueOrValues
|
|
1198
1347
|
* Numeric value(s).
|
|
1199
1348
|
*
|
|
@@ -1219,7 +1368,8 @@ export interface NumericIdentificationKeyCreator extends NumericIdentificationKe
|
|
|
1219
1368
|
}
|
|
1220
1369
|
|
|
1221
1370
|
/**
|
|
1222
|
-
* Abstract numeric identification key creator. Implements common functionality for a numeric identification key
|
|
1371
|
+
* Abstract numeric identification key creator. Implements common functionality for a numeric identification key
|
|
1372
|
+
* creator.
|
|
1223
1373
|
*/
|
|
1224
1374
|
abstract class AbstractNumericIdentificationKeyCreator extends AbstractIdentificationKeyCreator implements NumericIdentificationKeyCreator {
|
|
1225
1375
|
/**
|
|
@@ -1405,6 +1555,9 @@ export class GTINCreator extends Mixin(GTINValidator, AbstractNumericIdentificat
|
|
|
1405
1555
|
* Create GTIN-14(s) with an indicator digit and reference(s) based on numeric value(s). The value(s) is/are
|
|
1406
1556
|
* converted to reference(s) of the appropriate length using {@linkcode NUMERIC_CREATOR}.
|
|
1407
1557
|
*
|
|
1558
|
+
* @template TTransformerInput
|
|
1559
|
+
* Transformer input type.
|
|
1560
|
+
*
|
|
1408
1561
|
* @param indicatorDigit
|
|
1409
1562
|
* Indicator digit.
|
|
1410
1563
|
*
|
|
@@ -1426,6 +1579,122 @@ export class GTINCreator extends Mixin(GTINValidator, AbstractNumericIdentificat
|
|
|
1426
1579
|
return partialIdentificationKey + checkDigit(partialIdentificationKey);
|
|
1427
1580
|
});
|
|
1428
1581
|
}
|
|
1582
|
+
|
|
1583
|
+
/**
|
|
1584
|
+
* Create a Restricted Circulation Number (RCN) using a variable measure trade item format. See {@linkcode
|
|
1585
|
+
* GTINValidator.parseVariableMeasureRCN} for format details.
|
|
1586
|
+
*
|
|
1587
|
+
* @param format
|
|
1588
|
+
* Format.
|
|
1589
|
+
*
|
|
1590
|
+
* @param itemReference
|
|
1591
|
+
* Item reference.
|
|
1592
|
+
*
|
|
1593
|
+
* @param priceOrWeight
|
|
1594
|
+
* Price or weight (whole number only).
|
|
1595
|
+
*
|
|
1596
|
+
* @returns
|
|
1597
|
+
* RCN-12 or RCN-13.
|
|
1598
|
+
*/
|
|
1599
|
+
static createVariableMeasureRCN(format: string, itemReference: number, priceOrWeight: number): string {
|
|
1600
|
+
const formatLength = format.length;
|
|
1601
|
+
|
|
1602
|
+
let validFormat = formatLength === 12 || formatLength === 13;
|
|
1603
|
+
|
|
1604
|
+
let rcnPrefix = "";
|
|
1605
|
+
|
|
1606
|
+
let buildingItemReference = false;
|
|
1607
|
+
let itemReferenceString = "";
|
|
1608
|
+
let itemReferenceLength = 0;
|
|
1609
|
+
|
|
1610
|
+
let buildingPriceOrWeight = false;
|
|
1611
|
+
let priceOrWeightString = "";
|
|
1612
|
+
let priceOrWeightLength = 0;
|
|
1613
|
+
|
|
1614
|
+
let calculatePriceOrWeightCheckDigit = false;
|
|
1615
|
+
|
|
1616
|
+
// RCN may be built in almost any order, so defer to builders that will be in ordered array.
|
|
1617
|
+
const rcnPrefixBuilder = (partialRCN: string): string => partialRCN + rcnPrefix;
|
|
1618
|
+
const itemReferenceBuilder = (partialRCN: string): string => partialRCN + itemReferenceString;
|
|
1619
|
+
const priceOrWeightBuilder = (partialRCN: string): string => partialRCN + priceOrWeightString;
|
|
1620
|
+
const priceOrWeightCheckDigitBuilder = (partialRCN: string): string => partialRCN + priceOrWeightCheckDigit(priceOrWeightString);
|
|
1621
|
+
const checkDigitBuilder = (partialRCN: string): string => partialRCN + checkDigit(partialRCN);
|
|
1622
|
+
|
|
1623
|
+
const rcnBuilders = [rcnPrefixBuilder];
|
|
1624
|
+
|
|
1625
|
+
for (let index = 0; validFormat && index < formatLength; index++) {
|
|
1626
|
+
const formatChar = format.charAt(index);
|
|
1627
|
+
|
|
1628
|
+
if (index === 0) {
|
|
1629
|
+
validFormat = formatChar === "2";
|
|
1630
|
+
rcnPrefix = formatChar;
|
|
1631
|
+
} else if (formatLength === 13 && index === 1) {
|
|
1632
|
+
validFormat = NUMERIC_CREATOR.characterIndex(formatChar) !== undefined;
|
|
1633
|
+
rcnPrefix += formatChar;
|
|
1634
|
+
} else if (index === formatLength - 1) {
|
|
1635
|
+
validFormat = formatChar === "C";
|
|
1636
|
+
} else {
|
|
1637
|
+
switch (formatChar) {
|
|
1638
|
+
case "I":
|
|
1639
|
+
if (!buildingItemReference) {
|
|
1640
|
+
// Item reference can't appear more than once.
|
|
1641
|
+
validFormat = itemReferenceLength === 0;
|
|
1642
|
+
|
|
1643
|
+
buildingItemReference = true;
|
|
1644
|
+
buildingPriceOrWeight = false;
|
|
1645
|
+
|
|
1646
|
+
rcnBuilders.push(itemReferenceBuilder);
|
|
1647
|
+
}
|
|
1648
|
+
|
|
1649
|
+
itemReferenceLength++;
|
|
1650
|
+
break;
|
|
1651
|
+
|
|
1652
|
+
case "P":
|
|
1653
|
+
if (!buildingPriceOrWeight) {
|
|
1654
|
+
// Price or weight can't appear more than once.
|
|
1655
|
+
validFormat = priceOrWeightLength === 0;
|
|
1656
|
+
|
|
1657
|
+
buildingPriceOrWeight = true;
|
|
1658
|
+
buildingItemReference = false;
|
|
1659
|
+
|
|
1660
|
+
rcnBuilders.push(priceOrWeightBuilder);
|
|
1661
|
+
}
|
|
1662
|
+
|
|
1663
|
+
priceOrWeightLength++;
|
|
1664
|
+
break;
|
|
1665
|
+
|
|
1666
|
+
case "V":
|
|
1667
|
+
// Price or weight check digit can't appear more than once.
|
|
1668
|
+
validFormat = !calculatePriceOrWeightCheckDigit;
|
|
1669
|
+
|
|
1670
|
+
buildingItemReference = false;
|
|
1671
|
+
buildingPriceOrWeight = false;
|
|
1672
|
+
|
|
1673
|
+
calculatePriceOrWeightCheckDigit = true;
|
|
1674
|
+
|
|
1675
|
+
rcnBuilders.push(priceOrWeightCheckDigitBuilder);
|
|
1676
|
+
break;
|
|
1677
|
+
|
|
1678
|
+
default:
|
|
1679
|
+
validFormat = false;
|
|
1680
|
+
break;
|
|
1681
|
+
}
|
|
1682
|
+
}
|
|
1683
|
+
}
|
|
1684
|
+
|
|
1685
|
+
validFormat &&= itemReferenceLength !== 0 && priceOrWeightLength !== 0;
|
|
1686
|
+
|
|
1687
|
+
if (!validFormat) {
|
|
1688
|
+
throw new RangeError(i18nextGS1.t("IdentificationKey.invalidVariableMeasureRCNFormat"));
|
|
1689
|
+
}
|
|
1690
|
+
|
|
1691
|
+
itemReferenceString = NUMERIC_CREATOR.create(itemReferenceLength, itemReference);
|
|
1692
|
+
priceOrWeightString = NUMERIC_CREATOR.create(priceOrWeightLength, priceOrWeight);
|
|
1693
|
+
|
|
1694
|
+
rcnBuilders.push(checkDigitBuilder);
|
|
1695
|
+
|
|
1696
|
+
return rcnBuilders.reduce((partialRCN, rcnBuilder) => rcnBuilder(partialRCN), "");
|
|
1697
|
+
}
|
|
1429
1698
|
}
|
|
1430
1699
|
|
|
1431
1700
|
/**
|
|
@@ -1487,6 +1756,9 @@ export class SerializableNumericIdentificationKeyCreator extends Mixin(Serializa
|
|
|
1487
1756
|
/**
|
|
1488
1757
|
* Concatenate a validated base identification key with serial component(s).
|
|
1489
1758
|
*
|
|
1759
|
+
* @template TTransformerInput
|
|
1760
|
+
* Transformer input type.
|
|
1761
|
+
*
|
|
1490
1762
|
* @param baseIdentificationKey
|
|
1491
1763
|
* Base identification key.
|
|
1492
1764
|
*
|
|
@@ -1521,7 +1793,7 @@ export class SerializableNumericIdentificationKeyCreator extends Mixin(Serializa
|
|
|
1521
1793
|
if (typeof serialComponentOrComponents !== "object") {
|
|
1522
1794
|
result = validateAndConcatenate(serialComponentOrComponents);
|
|
1523
1795
|
} else {
|
|
1524
|
-
result =
|
|
1796
|
+
result = mapIterable(serialComponentOrComponents, validateAndConcatenate);
|
|
1525
1797
|
}
|
|
1526
1798
|
|
|
1527
1799
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- Type determination is handled above.
|
|
@@ -1532,6 +1804,9 @@ export class SerializableNumericIdentificationKeyCreator extends Mixin(Serializa
|
|
|
1532
1804
|
* Create serialized identification key(s) with a reference based on a numeric value concatenated with serial
|
|
1533
1805
|
* component(s). The value is converted to a reference of the appropriate length using {@linkcode NUMERIC_CREATOR}.
|
|
1534
1806
|
*
|
|
1807
|
+
* @template TTransformerInput
|
|
1808
|
+
* Transformer input type.
|
|
1809
|
+
*
|
|
1535
1810
|
* @param value
|
|
1536
1811
|
* Numeric value of the reference.
|
|
1537
1812
|
*
|
|
@@ -1551,6 +1826,9 @@ export class SerializableNumericIdentificationKeyCreator extends Mixin(Serializa
|
|
|
1551
1826
|
/**
|
|
1552
1827
|
* Concatenate a base identification key with serial component(s).
|
|
1553
1828
|
*
|
|
1829
|
+
* @template TTransformerInput
|
|
1830
|
+
* Transformer input type.
|
|
1831
|
+
*
|
|
1554
1832
|
* @param baseIdentificationKey
|
|
1555
1833
|
* Base identification key.
|
|
1556
1834
|
*
|
|
@@ -1618,6 +1896,9 @@ export class NonNumericIdentificationKeyCreator extends Mixin(NonNumericIdentifi
|
|
|
1618
1896
|
/**
|
|
1619
1897
|
* Create identification key(s) with reference(s).
|
|
1620
1898
|
*
|
|
1899
|
+
* @template TTransformerInput
|
|
1900
|
+
* Transformer input type.
|
|
1901
|
+
*
|
|
1621
1902
|
* @param referenceOrReferences
|
|
1622
1903
|
* Reference(s).
|
|
1623
1904
|
*
|
|
@@ -1653,7 +1934,7 @@ export class NonNumericIdentificationKeyCreator extends Mixin(NonNumericIdentifi
|
|
|
1653
1934
|
if (typeof referenceOrReferences !== "object") {
|
|
1654
1935
|
result = validateAndCreate(referenceOrReferences);
|
|
1655
1936
|
} else {
|
|
1656
|
-
result =
|
|
1937
|
+
result = mapIterable(referenceOrReferences, validateAndCreate);
|
|
1657
1938
|
}
|
|
1658
1939
|
|
|
1659
1940
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- Type determination is handled above.
|
|
@@ -1913,7 +2194,7 @@ export class PrefixManager {
|
|
|
1913
2194
|
|
|
1914
2195
|
// Creator tweak factor is defined for numeric identification keys only.
|
|
1915
2196
|
if (creatorTweakFactor !== undefined) {
|
|
1916
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- Explicit cast without testing is necessary as "instanceof" doesn't work for mixin types.
|
|
2197
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion,no-param-reassign -- Explicit cast without testing is necessary as "instanceof" doesn't work for mixin types. Method purpose is to set the tweak.
|
|
1917
2198
|
(creator as AbstractNumericIdentificationKeyCreator).tweak = this.tweakFactor * creatorTweakFactor;
|
|
1918
2199
|
}
|
|
1919
2200
|
}
|
|
@@ -2089,7 +2370,7 @@ export class PrefixManager {
|
|
|
2089
2370
|
*/
|
|
2090
2371
|
private getIdentificationKeyCreator<TIdentificationKeyCreator extends IdentificationKeyCreator>(identificationKeyType: IdentificationKeyType, constructorCallback: () => TIdentificationKeyCreator): TIdentificationKeyCreator {
|
|
2091
2372
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- Type is paired with constructor callback.
|
|
2092
|
-
let creator = this._identificationKeyCreatorsMap.get(identificationKeyType) as
|
|
2373
|
+
let creator = this._identificationKeyCreatorsMap.get(identificationKeyType) as TIdentificationKeyCreator | undefined;
|
|
2093
2374
|
|
|
2094
2375
|
if (creator === undefined) {
|
|
2095
2376
|
if (this.prefixType === PrefixType.GS18Prefix && identificationKeyType !== IdentificationKeyType.GTIN) {
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
export const localeStrings = {
|
|
2
2
|
Check: {
|
|
3
|
-
lengthOfStringForPriceOrWeightMustBeExactly: "Length {{length}} of string for price or weight
|
|
3
|
+
lengthOfStringForPriceOrWeightMustBeExactly: "Length {{length, number}} of string for price or weight must be 4 or 5",
|
|
4
4
|
priceOrWeightComponent: "price or weight",
|
|
5
|
-
lengthOfStringForCheckCharacterPairMustBeLessThanOrEqualTo: "Length {{length}} of string for check character pair must be less than or equal to {{maximumLength}}"
|
|
5
|
+
lengthOfStringForCheckCharacterPairMustBeLessThanOrEqualTo: "Length {{length, number}} of string for check character pair must be less than or equal to {{maximumLength, number}}"
|
|
6
6
|
},
|
|
7
7
|
IdentificationKey: {
|
|
8
|
-
identificationKeyTypeLength: "{{identificationKeyType}} must be {{length}} digits long",
|
|
8
|
+
identificationKeyTypeLength: "{{identificationKeyType}} must be {{length, number}} digits long",
|
|
9
9
|
invalidCheckDigit: "Invalid check digit",
|
|
10
10
|
invalidGTINLength: "GTIN must be 13, 12, 8, or 14 digits long",
|
|
11
11
|
invalidGTIN14Length: "GTIN must be 14 digits long",
|
|
@@ -16,6 +16,10 @@ export const localeStrings = {
|
|
|
16
16
|
invalidGTIN13AtRetail: "GTIN-13 at retail consumer trade item level can't start with zero",
|
|
17
17
|
invalidGTINAtRetail: "GTIN not supported at retail consumer trade item level",
|
|
18
18
|
invalidGTINAtOtherThanRetail: "GTIN not supported at other than retail consumer trade item level",
|
|
19
|
+
invalidRCNLength: "RCN length must match format length",
|
|
20
|
+
invalidVariableMeasureRCNFormat: "Invalid variable measure RCN format",
|
|
21
|
+
invalidVariableMeasureRCNPrefix: "Invalid variable measure RCN prefix",
|
|
22
|
+
invalidVariableMeasurePriceOrWeight: "Invalid variable measure price or weight",
|
|
19
23
|
indicatorDigit: "indicator digit",
|
|
20
24
|
serialComponent: "serial component",
|
|
21
25
|
reference: "reference",
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
export const localeStrings = {
|
|
2
2
|
Check: {
|
|
3
|
-
lengthOfStringForPriceOrWeightMustBeExactly: "La longueur {{
|
|
3
|
+
lengthOfStringForPriceOrWeightMustBeExactly: "La longueur {{length, number}} de la chaîne pour le prix ou le poids doit être 4 ou 5",
|
|
4
4
|
priceOrWeightComponent: "prix ou poids",
|
|
5
|
-
lengthOfStringForCheckCharacterPairMustBeLessThanOrEqualTo: "La longueur {{length}} de la chaîne pour la paire de caractères de vérification doit être inférieure ou égale à {{maximum Length}}"
|
|
5
|
+
lengthOfStringForCheckCharacterPairMustBeLessThanOrEqualTo: "La longueur {{length, number}} de la chaîne pour la paire de caractères de vérification doit être inférieure ou égale à {{maximum Length}}"
|
|
6
6
|
},
|
|
7
7
|
IdentificationKey: {
|
|
8
|
-
identificationKeyTypeLength: "{{identificationKeyType}} doit comporter {{length}} chiffres",
|
|
8
|
+
identificationKeyTypeLength: "{{identificationKeyType}} doit comporter {{length, number}} chiffres",
|
|
9
9
|
invalidCheckDigit: "Chiffre de contrôle non valide",
|
|
10
10
|
invalidGTINLength: "Le GTIN doit comporter 13, 12, 8 ou 14 chiffres",
|
|
11
11
|
invalidGTIN14Length: "Le GTIN doit comporter 14 chiffres",
|
|
@@ -16,6 +16,10 @@ export const localeStrings = {
|
|
|
16
16
|
invalidGTIN13AtRetail: "Le GTIN-13 au niveau des articles de consommation au détail ne peut pas commencer par zéro",
|
|
17
17
|
invalidGTINAtRetail: "Le GTIN n'est pas pris en charge au niveau des articles de consommation au détail",
|
|
18
18
|
invalidGTINAtOtherThanRetail: "Le GTIN n'est pas pris en charge à d'autres niveaux que ceux des articles de consommation au détail",
|
|
19
|
+
invalidRCNLength: "La longueur du RCN doit correspondre à la longueur du format",
|
|
20
|
+
invalidVariableMeasureRCNFormat: "Format RCN de mesure variable non valide",
|
|
21
|
+
invalidVariableMeasureRCNPrefix: "Préfixe RCN de mesure variable non valide",
|
|
22
|
+
invalidVariableMeasurePriceOrWeight: "Mesure variable invalide : prix ou poids",
|
|
19
23
|
indicatorDigit: "chiffre indicateur",
|
|
20
24
|
serialComponent: "composant série",
|
|
21
25
|
reference: "référence",
|
package/src/locale/i18n.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { i18nAssertValidResources, i18nCoreInit, type
|
|
1
|
+
import { i18nAssertValidResources, i18nCoreInit, type I18nEnvironment } from "@aidc-toolkit/core";
|
|
2
2
|
import { i18nUtilityInit, utilityResources } from "@aidc-toolkit/utility";
|
|
3
|
-
import i18next, { type i18n } from "i18next";
|
|
3
|
+
import i18next, { type i18n, type Resource } from "i18next";
|
|
4
4
|
import { localeStrings as enLocaleStrings } from "./en/locale-strings.js";
|
|
5
5
|
import { localeStrings as frLocaleStrings } from "./fr/locale-strings.js";
|
|
6
6
|
|
|
@@ -16,7 +16,7 @@ i18nAssertValidResources(enLocaleStrings, "fr", frLocaleStrings);
|
|
|
16
16
|
/**
|
|
17
17
|
* GS1 resources.
|
|
18
18
|
*/
|
|
19
|
-
export const gs1Resources = {
|
|
19
|
+
export const gs1Resources: Resource = {
|
|
20
20
|
en: {
|
|
21
21
|
aidct_gs1: enLocaleStrings
|
|
22
22
|
},
|
|
@@ -40,7 +40,7 @@ export const i18nextGS1: i18n = i18next.createInstance();
|
|
|
40
40
|
* @returns
|
|
41
41
|
* Void promise.
|
|
42
42
|
*/
|
|
43
|
-
export async function i18nGS1Init(environment:
|
|
43
|
+
export async function i18nGS1Init(environment: I18nEnvironment, debug = false): Promise<void> {
|
|
44
44
|
await i18nUtilityInit(environment, debug);
|
|
45
45
|
await i18nCoreInit(i18nextGS1, environment, debug, gs1NS, utilityResources, gs1Resources);
|
|
46
46
|
}
|
package/test/check.test.ts
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { I18nEnvironment } from "@aidc-toolkit/core";
|
|
2
2
|
import { NUMERIC_CREATOR } from "@aidc-toolkit/utility";
|
|
3
3
|
import { describe, expect, test } from "vitest";
|
|
4
4
|
import {
|
|
5
5
|
checkCharacterPair,
|
|
6
6
|
checkDigit,
|
|
7
7
|
checkDigitSum,
|
|
8
|
-
fiveDigitPriceWeightCheckDigit,
|
|
9
|
-
fourDigitPriceWeightCheckDigit,
|
|
10
8
|
hasValidCheckCharacterPair,
|
|
11
9
|
hasValidCheckDigit,
|
|
12
|
-
i18nGS1Init
|
|
10
|
+
i18nGS1Init,
|
|
11
|
+
isValidPriceOrWeightCheckDigit,
|
|
12
|
+
priceOrWeightCheckDigit
|
|
13
13
|
} from "../src";
|
|
14
14
|
|
|
15
|
-
await i18nGS1Init(
|
|
15
|
+
await i18nGS1Init(I18nEnvironment.CLI, true);
|
|
16
16
|
|
|
17
17
|
describe("Check digit", () => {
|
|
18
18
|
const testNumericString = "1234567890";
|
|
@@ -40,7 +40,7 @@ describe("Check digit", () => {
|
|
|
40
40
|
});
|
|
41
41
|
});
|
|
42
42
|
|
|
43
|
-
describe("Price
|
|
43
|
+
describe("Price or weight check digit", () => {
|
|
44
44
|
function weight2Minus(characterIndex: number): number {
|
|
45
45
|
const product = characterIndex * 2;
|
|
46
46
|
|
|
@@ -69,7 +69,10 @@ describe("Price/weight check digit", () => {
|
|
|
69
69
|
|
|
70
70
|
const sum = weight2Minus(characterIndexes[0]) + weight2Minus(characterIndexes[1]) + weight3(characterIndexes[2]) + weight5Minus(characterIndexes[3]);
|
|
71
71
|
|
|
72
|
-
|
|
72
|
+
const checkDigit = priceOrWeightCheckDigit(s);
|
|
73
|
+
|
|
74
|
+
expect(checkDigit).toBe(NUMERIC_CREATOR.character(sum * 3 % 10));
|
|
75
|
+
expect(isValidPriceOrWeightCheckDigit(s, checkDigit)).toBe(true);
|
|
73
76
|
}
|
|
74
77
|
|
|
75
78
|
function testFiveDigitPriceWeightCheckDigit(s: string): void {
|
|
@@ -78,7 +81,10 @@ describe("Price/weight check digit", () => {
|
|
|
78
81
|
|
|
79
82
|
const sum = weight5Plus(characterIndexes[0]) + weight2Minus(characterIndexes[1]) + weight5Minus(characterIndexes[2]) + weight5Plus(characterIndexes[3]) + weight2Minus(characterIndexes[4]);
|
|
80
83
|
|
|
81
|
-
|
|
84
|
+
const checkDigit = priceOrWeightCheckDigit(s);
|
|
85
|
+
|
|
86
|
+
expect(weight5Minus(Number(checkDigit))).toBe(9 - (sum + 9) % 10);
|
|
87
|
+
expect(isValidPriceOrWeightCheckDigit(s, checkDigit)).toBe(true);
|
|
82
88
|
}
|
|
83
89
|
|
|
84
90
|
test("Four-digit", () => {
|
|
@@ -92,10 +98,6 @@ describe("Price/weight check digit", () => {
|
|
|
92
98
|
testFourDigitPriceWeightCheckDigit("7890");
|
|
93
99
|
testFourDigitPriceWeightCheckDigit("8901");
|
|
94
100
|
testFourDigitPriceWeightCheckDigit("9012");
|
|
95
|
-
|
|
96
|
-
expect(() => fourDigitPriceWeightCheckDigit("l234")).toThrow("Invalid character 'l' at position 1");
|
|
97
|
-
expect(() => fourDigitPriceWeightCheckDigit("123")).toThrow("Length 3 of string for price or weight sum must be exactly 4");
|
|
98
|
-
expect(() => fourDigitPriceWeightCheckDigit("12345")).toThrow("Length 5 of string for price or weight sum must be exactly 4");
|
|
99
101
|
});
|
|
100
102
|
|
|
101
103
|
test("Five-digit", () => {
|
|
@@ -109,10 +111,12 @@ describe("Price/weight check digit", () => {
|
|
|
109
111
|
testFiveDigitPriceWeightCheckDigit("78901");
|
|
110
112
|
testFiveDigitPriceWeightCheckDigit("89012");
|
|
111
113
|
testFiveDigitPriceWeightCheckDigit("90123");
|
|
114
|
+
});
|
|
112
115
|
|
|
113
|
-
|
|
114
|
-
expect(() =>
|
|
115
|
-
expect(() =>
|
|
116
|
+
test("Invalid", () => {
|
|
117
|
+
expect(() => priceOrWeightCheckDigit("l2345")).toThrow("Invalid character 'l' at position 1 of price or weight");
|
|
118
|
+
expect(() => priceOrWeightCheckDigit("123")).toThrow("Length 3 of string for price or weight must be 4 or 5");
|
|
119
|
+
expect(() => priceOrWeightCheckDigit("123456")).toThrow("Length 6 of string for price or weight must be 4 or 5");
|
|
116
120
|
});
|
|
117
121
|
});
|
|
118
122
|
|