@aidc-toolkit/gs1 0.9.18-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/check.d.ts +8 -5
- package/dist/check.d.ts.map +1 -1
- package/dist/check.js +13 -11
- package/dist/check.js.map +1 -1
- package/dist/idkey.d.ts +64 -1
- package/dist/idkey.d.ts.map +1 -1
- package/dist/idkey.js +206 -6
- package/dist/idkey.js.map +1 -1
- package/dist/locale/en/locale-strings.d.ts +4 -0
- package/dist/locale/en/locale-strings.d.ts.map +1 -1
- package/dist/locale/en/locale-strings.js +4 -0
- package/dist/locale/en/locale-strings.js.map +1 -1
- package/dist/locale/fr/locale-strings.d.ts +4 -0
- package/dist/locale/fr/locale-strings.d.ts.map +1 -1
- package/dist/locale/fr/locale-strings.js +4 -0
- 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/check.ts +13 -12
- package/src/idkey.ts +269 -9
- package/src/locale/en/locale-strings.ts +4 -0
- package/src/locale/fr/locale-strings.ts +4 -0
- package/src/locale/i18n.ts +4 -4
- package/test/check.test.ts +17 -12
- 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
|
-
mapIterable
|
|
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
|
|
|
@@ -470,6 +472,21 @@ export enum GTINLevel {
|
|
|
470
472
|
OtherThanRetailConsumer
|
|
471
473
|
}
|
|
472
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
|
+
|
|
473
490
|
/**
|
|
474
491
|
* GTIN validator.
|
|
475
492
|
*/
|
|
@@ -632,10 +649,8 @@ export class GTINValidator extends AbstractNumericIdentificationKeyValidator {
|
|
|
632
649
|
|
|
633
650
|
NUMERIC_CREATOR.validate(indicatorDigit, GTINValidator.OPTIONAL_INDICATOR_DIGIT_VALIDATION);
|
|
634
651
|
|
|
635
|
-
const gtinLength = gtin.length;
|
|
636
|
-
|
|
637
652
|
// Check digit doesn't change by prepending zeros.
|
|
638
|
-
let gtin14 =
|
|
653
|
+
let gtin14 = gtin.padStart(GTINType.GTIN14, "0");
|
|
639
654
|
|
|
640
655
|
// If indicator digit provided and is different, recalculate the check digit.
|
|
641
656
|
if (indicatorDigit.length !== 0 && indicatorDigit !== gtin14.charAt(0)) {
|
|
@@ -805,6 +820,134 @@ export class GTINValidator extends AbstractNumericIdentificationKeyValidator {
|
|
|
805
820
|
|
|
806
821
|
GTINCreator.validateAny(gtin14);
|
|
807
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
|
+
}
|
|
808
951
|
}
|
|
809
952
|
|
|
810
953
|
/**
|
|
@@ -1225,7 +1368,8 @@ export interface NumericIdentificationKeyCreator extends NumericIdentificationKe
|
|
|
1225
1368
|
}
|
|
1226
1369
|
|
|
1227
1370
|
/**
|
|
1228
|
-
* 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.
|
|
1229
1373
|
*/
|
|
1230
1374
|
abstract class AbstractNumericIdentificationKeyCreator extends AbstractIdentificationKeyCreator implements NumericIdentificationKeyCreator {
|
|
1231
1375
|
/**
|
|
@@ -1435,6 +1579,122 @@ export class GTINCreator extends Mixin(GTINValidator, AbstractNumericIdentificat
|
|
|
1435
1579
|
return partialIdentificationKey + checkDigit(partialIdentificationKey);
|
|
1436
1580
|
});
|
|
1437
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
|
+
}
|
|
1438
1698
|
}
|
|
1439
1699
|
|
|
1440
1700
|
/**
|
|
@@ -1934,7 +2194,7 @@ export class PrefixManager {
|
|
|
1934
2194
|
|
|
1935
2195
|
// Creator tweak factor is defined for numeric identification keys only.
|
|
1936
2196
|
if (creatorTweakFactor !== undefined) {
|
|
1937
|
-
// 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.
|
|
1938
2198
|
(creator as AbstractNumericIdentificationKeyCreator).tweak = this.tweakFactor * creatorTweakFactor;
|
|
1939
2199
|
}
|
|
1940
2200
|
}
|
|
@@ -2110,7 +2370,7 @@ export class PrefixManager {
|
|
|
2110
2370
|
*/
|
|
2111
2371
|
private getIdentificationKeyCreator<TIdentificationKeyCreator extends IdentificationKeyCreator>(identificationKeyType: IdentificationKeyType, constructorCallback: () => TIdentificationKeyCreator): TIdentificationKeyCreator {
|
|
2112
2372
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- Type is paired with constructor callback.
|
|
2113
|
-
let creator = this._identificationKeyCreatorsMap.get(identificationKeyType) as
|
|
2373
|
+
let creator = this._identificationKeyCreatorsMap.get(identificationKeyType) as TIdentificationKeyCreator | undefined;
|
|
2114
2374
|
|
|
2115
2375
|
if (creator === undefined) {
|
|
2116
2376
|
if (this.prefixType === PrefixType.GS18Prefix && identificationKeyType !== IdentificationKeyType.GTIN) {
|
|
@@ -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",
|
|
@@ -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,4 +1,4 @@
|
|
|
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 {
|
|
@@ -6,12 +6,13 @@ import {
|
|
|
6
6
|
checkDigit,
|
|
7
7
|
checkDigitSum,
|
|
8
8
|
hasValidCheckCharacterPair,
|
|
9
|
-
hasValidCheckDigit,
|
|
9
|
+
hasValidCheckDigit,
|
|
10
10
|
i18nGS1Init,
|
|
11
|
-
|
|
11
|
+
isValidPriceOrWeightCheckDigit,
|
|
12
|
+
priceOrWeightCheckDigit
|
|
12
13
|
} from "../src";
|
|
13
14
|
|
|
14
|
-
await i18nGS1Init(
|
|
15
|
+
await i18nGS1Init(I18nEnvironment.CLI, true);
|
|
15
16
|
|
|
16
17
|
describe("Check digit", () => {
|
|
17
18
|
const testNumericString = "1234567890";
|
|
@@ -39,7 +40,7 @@ describe("Check digit", () => {
|
|
|
39
40
|
});
|
|
40
41
|
});
|
|
41
42
|
|
|
42
|
-
describe("Price
|
|
43
|
+
describe("Price or weight check digit", () => {
|
|
43
44
|
function weight2Minus(characterIndex: number): number {
|
|
44
45
|
const product = characterIndex * 2;
|
|
45
46
|
|
|
@@ -68,8 +69,10 @@ describe("Price/weight check digit", () => {
|
|
|
68
69
|
|
|
69
70
|
const sum = weight2Minus(characterIndexes[0]) + weight2Minus(characterIndexes[1]) + weight3(characterIndexes[2]) + weight5Minus(characterIndexes[3]);
|
|
70
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,8 +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
|
-
|
|
82
|
-
|
|
84
|
+
const checkDigit = priceOrWeightCheckDigit(s);
|
|
85
|
+
|
|
86
|
+
expect(weight5Minus(Number(checkDigit))).toBe(9 - (sum + 9) % 10);
|
|
87
|
+
expect(isValidPriceOrWeightCheckDigit(s, checkDigit)).toBe(true);
|
|
83
88
|
}
|
|
84
89
|
|
|
85
90
|
test("Four-digit", () => {
|
|
@@ -109,9 +114,9 @@ describe("Price/weight check digit", () => {
|
|
|
109
114
|
});
|
|
110
115
|
|
|
111
116
|
test("Invalid", () => {
|
|
112
|
-
expect(() =>
|
|
113
|
-
expect(() =>
|
|
114
|
-
expect(() =>
|
|
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");
|
|
115
120
|
});
|
|
116
121
|
});
|
|
117
122
|
|