@dotdev/harmony-sdk 1.0.1

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.
Files changed (124) hide show
  1. package/README.md +132 -0
  2. package/dist/HarmonyAPI.d.ts +37 -0
  3. package/dist/HarmonyAPI.js +113 -0
  4. package/dist/errors/index.d.ts +15 -0
  5. package/dist/errors/index.js +18 -0
  6. package/dist/helpers/index.d.ts +50 -0
  7. package/dist/helpers/index.js +167 -0
  8. package/dist/helpers/index.spec.d.ts +1 -0
  9. package/dist/helpers/index.spec.js +147 -0
  10. package/dist/helpers/mapper.d.ts +2 -0
  11. package/dist/helpers/mapper.js +28 -0
  12. package/dist/helpers/utils.d.ts +71 -0
  13. package/dist/helpers/utils.js +133 -0
  14. package/dist/helpers/utils.spec.d.ts +1 -0
  15. package/dist/helpers/utils.spec.js +96 -0
  16. package/dist/index.d.ts +5 -0
  17. package/dist/index.js +5 -0
  18. package/dist/modules/auth/auth.module.d.ts +7 -0
  19. package/dist/modules/auth/auth.module.js +42 -0
  20. package/dist/modules/auth/auth.module.spec.d.ts +1 -0
  21. package/dist/modules/auth/auth.module.spec.js +55 -0
  22. package/dist/modules/auth/index.d.ts +2 -0
  23. package/dist/modules/auth/index.js +2 -0
  24. package/dist/modules/auth/types/index.d.ts +7 -0
  25. package/dist/modules/auth/types/index.js +1 -0
  26. package/dist/modules/carrier/carrier.module.d.ts +10 -0
  27. package/dist/modules/carrier/carrier.module.js +39 -0
  28. package/dist/modules/carrier/carrier.module.spec.d.ts +1 -0
  29. package/dist/modules/carrier/carrier.module.spec.js +187 -0
  30. package/dist/modules/carrier/index.d.ts +3 -0
  31. package/dist/modules/carrier/index.js +3 -0
  32. package/dist/modules/carrier/mappings/index.d.ts +5 -0
  33. package/dist/modules/carrier/mappings/index.js +36 -0
  34. package/dist/modules/carrier/types/index.d.ts +42 -0
  35. package/dist/modules/carrier/types/index.js +2 -0
  36. package/dist/modules/diary/diary.module.d.ts +9 -0
  37. package/dist/modules/diary/diary.module.js +28 -0
  38. package/dist/modules/diary/index.d.ts +3 -0
  39. package/dist/modules/diary/index.js +3 -0
  40. package/dist/modules/diary/mappings/diary.mapper.d.ts +4 -0
  41. package/dist/modules/diary/mappings/diary.mapper.js +101 -0
  42. package/dist/modules/diary/mappings/diary.mapper.spec.d.ts +1 -0
  43. package/dist/modules/diary/mappings/diary.mapper.spec.js +18 -0
  44. package/dist/modules/diary/mappings/index.d.ts +1 -0
  45. package/dist/modules/diary/mappings/index.js +1 -0
  46. package/dist/modules/diary/types/diary.interface.d.ts +138 -0
  47. package/dist/modules/diary/types/diary.interface.js +24 -0
  48. package/dist/modules/diary/types/index.d.ts +1 -0
  49. package/dist/modules/diary/types/index.js +1 -0
  50. package/dist/modules/gift-voucher/gift-voucher.module.d.ts +12 -0
  51. package/dist/modules/gift-voucher/gift-voucher.module.js +55 -0
  52. package/dist/modules/gift-voucher/gift-voucher.module.spec.d.ts +1 -0
  53. package/dist/modules/gift-voucher/gift-voucher.module.spec.js +296 -0
  54. package/dist/modules/gift-voucher/index.d.ts +1 -0
  55. package/dist/modules/gift-voucher/index.js +1 -0
  56. package/dist/modules/gift-voucher/mappings/index.d.ts +6 -0
  57. package/dist/modules/gift-voucher/mappings/index.js +70 -0
  58. package/dist/modules/gift-voucher/mappings/index.spec.d.ts +1 -0
  59. package/dist/modules/gift-voucher/mappings/index.spec.js +21 -0
  60. package/dist/modules/gift-voucher/types/index.d.ts +92 -0
  61. package/dist/modules/gift-voucher/types/index.js +1 -0
  62. package/dist/modules/index.d.ts +8 -0
  63. package/dist/modules/index.js +8 -0
  64. package/dist/modules/point-of-sale/index.d.ts +3 -0
  65. package/dist/modules/point-of-sale/index.js +3 -0
  66. package/dist/modules/point-of-sale/mappings/index.d.ts +1 -0
  67. package/dist/modules/point-of-sale/mappings/index.js +1 -0
  68. package/dist/modules/point-of-sale/mappings/process-sale-order.mapper.d.ts +6 -0
  69. package/dist/modules/point-of-sale/mappings/process-sale-order.mapper.js +142 -0
  70. package/dist/modules/point-of-sale/point-of-sale.module.d.ts +43 -0
  71. package/dist/modules/point-of-sale/point-of-sale.module.js +64 -0
  72. package/dist/modules/point-of-sale/point-of-sale.module.spec.d.ts +1 -0
  73. package/dist/modules/point-of-sale/point-of-sale.module.spec.js +205 -0
  74. package/dist/modules/point-of-sale/types/cancel-existing-sales-order.interface.d.ts +13 -0
  75. package/dist/modules/point-of-sale/types/cancel-existing-sales-order.interface.js +1 -0
  76. package/dist/modules/point-of-sale/types/index.d.ts +124 -0
  77. package/dist/modules/point-of-sale/types/index.js +31 -0
  78. package/dist/modules/point-of-sale/types/modify-existing-sales-order.interface.d.ts +12 -0
  79. package/dist/modules/point-of-sale/types/modify-existing-sales-order.interface.js +1 -0
  80. package/dist/modules/point-of-sale/types/process-returns.interface.d.ts +17 -0
  81. package/dist/modules/point-of-sale/types/process-returns.interface.js +1 -0
  82. package/dist/modules/point-of-sale/types/process-sale-order.interface.d.ts +67 -0
  83. package/dist/modules/point-of-sale/types/process-sale-order.interface.js +1 -0
  84. package/dist/modules/shared/index.d.ts +1 -0
  85. package/dist/modules/shared/index.js +1 -0
  86. package/dist/modules/shared/types/index.d.ts +93 -0
  87. package/dist/modules/shared/types/index.js +53 -0
  88. package/dist/modules/stock-level-lookup/index.d.ts +3 -0
  89. package/dist/modules/stock-level-lookup/index.js +3 -0
  90. package/dist/modules/stock-level-lookup/mappings/index.d.ts +1 -0
  91. package/dist/modules/stock-level-lookup/mappings/index.js +1 -0
  92. package/dist/modules/stock-level-lookup/mappings/stock-level-lookup.mapper.d.ts +4 -0
  93. package/dist/modules/stock-level-lookup/mappings/stock-level-lookup.mapper.js +78 -0
  94. package/dist/modules/stock-level-lookup/mappings/stock-level-lookup.mapper.spec.d.ts +1 -0
  95. package/dist/modules/stock-level-lookup/mappings/stock-level-lookup.mapper.spec.js +57 -0
  96. package/dist/modules/stock-level-lookup/stock-level-lookup.module.d.ts +10 -0
  97. package/dist/modules/stock-level-lookup/stock-level-lookup.module.js +39 -0
  98. package/dist/modules/stock-level-lookup/stock-level-lookup.module.spec.d.ts +1 -0
  99. package/dist/modules/stock-level-lookup/stock-level-lookup.module.spec.js +317 -0
  100. package/dist/modules/stock-level-lookup/types/index.d.ts +1 -0
  101. package/dist/modules/stock-level-lookup/types/index.js +1 -0
  102. package/dist/modules/stock-level-lookup/types/stock-level-lookup.interface.d.ts +162 -0
  103. package/dist/modules/stock-level-lookup/types/stock-level-lookup.interface.js +61 -0
  104. package/dist/modules/stock-lookup/index.d.ts +3 -0
  105. package/dist/modules/stock-lookup/index.js +3 -0
  106. package/dist/modules/stock-lookup/mappings/index.d.ts +1 -0
  107. package/dist/modules/stock-lookup/mappings/index.js +1 -0
  108. package/dist/modules/stock-lookup/mappings/stock-lookup.mapper.d.ts +22 -0
  109. package/dist/modules/stock-lookup/mappings/stock-lookup.mapper.js +156 -0
  110. package/dist/modules/stock-lookup/mappings/stock-lookup.mapper.spec.d.ts +1 -0
  111. package/dist/modules/stock-lookup/mappings/stock-lookup.mapper.spec.js +92 -0
  112. package/dist/modules/stock-lookup/stock-lookup.module.d.ts +65 -0
  113. package/dist/modules/stock-lookup/stock-lookup.module.js +141 -0
  114. package/dist/modules/stock-lookup/stock-lookup.module.spec.d.ts +1 -0
  115. package/dist/modules/stock-lookup/stock-lookup.module.spec.js +419 -0
  116. package/dist/modules/stock-lookup/types/index.d.ts +1 -0
  117. package/dist/modules/stock-lookup/types/index.js +1 -0
  118. package/dist/modules/stock-lookup/types/stock-lookup.interface.d.ts +242 -0
  119. package/dist/modules/stock-lookup/types/stock-lookup.interface.js +82 -0
  120. package/dist/modules/stock-lookup/types/stock-lookup.interface.spec.d.ts +1 -0
  121. package/dist/modules/stock-lookup/types/stock-lookup.interface.spec.js +76 -0
  122. package/dist/types/index.d.ts +5 -0
  123. package/dist/types/index.js +6 -0
  124. package/package.json +39 -0
@@ -0,0 +1,147 @@
1
+ import axios from "axios";
2
+ import { ApiHelper, checkParamLimits, Utils } from ".";
3
+ import { ServiceAlias } from "../modules/shared/types";
4
+ // Increase timeout due to Harmony API having long response time
5
+ jest.setTimeout(999999);
6
+ jest.mock("axios");
7
+ const mAxios = axios;
8
+ describe("ApiHelper", () => {
9
+ test("ApiHelper.sendSoapRequest", async () => {
10
+ const endpoint = "/StockLookupService/StockLookupService";
11
+ const sessionId = "test-session-id";
12
+ const requestBody = `
13
+ <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/" xmlns:stk="http://stk.ws.fbsaust.com.au">
14
+ <S:Header>
15
+ <stk:SessionId>${sessionId}</stk:SessionId>
16
+ </S:Header>
17
+ <S:Body>
18
+ <stk:StockClassificationLookup>
19
+ <SearchType>STK00</SearchType>
20
+ </stk:StockClassificationLookup>
21
+ </S:Body>
22
+ </S:Envelope>
23
+ `;
24
+ mAxios.post.mockResolvedValueOnce({
25
+ data: `
26
+ <?xml version='1.0' encoding='UTF-8'?>
27
+ <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
28
+ <S:Body>
29
+ <ns2:StockClassificationLookupResponse xmlns:ns2="http://stk.ws.fbsaust.com.au">
30
+ <StockClassification>
31
+ <code>BACK</code>
32
+ <description>TEST</description>
33
+ </StockClassification>
34
+ </ns2:StockClassificationLookupResponse>
35
+ </S:Body>
36
+ </S:Envelope>
37
+ `,
38
+ });
39
+ const response = await ApiHelper.sendSoapRequest(endpoint, mAxios, requestBody);
40
+ expect(response["ns2:StockClassificationLookupResponse"][0]
41
+ .StockClassification).toEqual([
42
+ {
43
+ code: ["BACK"],
44
+ description: ["TEST"],
45
+ },
46
+ ]);
47
+ });
48
+ test("createServiceRequestBody should return correct SOAP request body", () => {
49
+ const expected = `
50
+ <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/" xmlns:stk="http://stk.ws.fbsaust.com.au">
51
+ <S:Header>
52
+ <stk:SessionId>ABC</stk:SessionId>
53
+ </S:Header>
54
+ <S:Body>
55
+ <stk:StockClassificationLookup>
56
+ <SearchType>STK99</SearchType>
57
+ </stk:StockClassificationLookup>
58
+ </S:Body>
59
+ </S:Envelope>
60
+ `;
61
+ const actual = ApiHelper.createServiceRequestBody("StockClassificationLookup", "ABC", ServiceAlias.STOCK_LOOKUP, "<SearchType>STK99</SearchType>");
62
+ expect(Utils.removeEmptySpaces(actual)).toEqual(Utils.removeEmptySpaces(expected));
63
+ });
64
+ });
65
+ describe("Other functions", () => {
66
+ test("checkParamLimit", () => {
67
+ const params = {
68
+ param1: 123,
69
+ param2: "abc",
70
+ param3: true,
71
+ };
72
+ // Matching param limit
73
+ const matchedParamLimit = {
74
+ param1: 3,
75
+ param2: 3,
76
+ param3: (val) => typeof val === "boolean" && val === true,
77
+ };
78
+ expect(checkParamLimits(params, matchedParamLimit)).toBe(true);
79
+ // Exceeded param limit
80
+ const exceededParamLimit = {
81
+ param1: 3,
82
+ param2: 2,
83
+ param3: (val) => typeof val === "boolean" && val === true,
84
+ };
85
+ expect(() => checkParamLimits(params, exceededParamLimit)).toThrow(`Provided value for "param2" exceeds limit of 2`);
86
+ // Limit using function return false
87
+ const falseParamLimit = {
88
+ param1: 3,
89
+ param2: 3,
90
+ param3: (val) => val === false,
91
+ };
92
+ expect(() => checkParamLimits(params, falseParamLimit)).toThrow(`Invalid value for parameter "param3": true`);
93
+ });
94
+ test("checkParamLimit with enum", () => {
95
+ let TestEnum;
96
+ (function (TestEnum) {
97
+ TestEnum[TestEnum["A"] = 0] = "A";
98
+ TestEnum[TestEnum["B"] = 1] = "B";
99
+ })(TestEnum || (TestEnum = {}));
100
+ const params = {
101
+ param1: TestEnum.A,
102
+ };
103
+ const wrongParams = {
104
+ param1: "C",
105
+ };
106
+ // Matching param limit
107
+ const matchedParamLimit = {
108
+ param1: (val) => Object.values(TestEnum).includes(val),
109
+ };
110
+ expect(checkParamLimits(params, matchedParamLimit)).toBe(true);
111
+ expect(() => checkParamLimits(wrongParams, matchedParamLimit)).toThrow(`Invalid value for parameter "param1": C`);
112
+ });
113
+ test("checkParamLimit with no limit", () => {
114
+ const params = {
115
+ param1: "asdf",
116
+ };
117
+ // Matching param limit
118
+ const matchedParamLimit = {};
119
+ expect(checkParamLimits(params, matchedParamLimit)).toBe(true);
120
+ });
121
+ });
122
+ describe("parseRequestError", () => {
123
+ it("should handle error correctly and return the error string", async () => {
124
+ const errResp = `
125
+ <?xml version='1.0' encoding='UTF-8'?>
126
+ <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
127
+ <S:Body>
128
+ <S:Fault xmlns:ns4="http://www.w3.org/2003/05/soap-envelope">
129
+ <faultcode>S:Server</faultcode>
130
+ <faultstring>Failed Test Request</faultstring>
131
+ <detail>
132
+ <ns2:ServiceFault xmlns:ns2="http://pos.ws.fbsaust.com.au">
133
+ <errorDetails>[204-104-2408071537-0000851206] (Invalid value)</errorDetails>
134
+ </ns2:ServiceFault>
135
+ </detail>
136
+ </S:Fault>
137
+ </S:Body>
138
+ </S:Envelope>
139
+ `;
140
+ const expected = {
141
+ code: "S:Server",
142
+ name: "Failed Test Request",
143
+ message: "[204-104-2408071537-0000851206] (Invalid value)",
144
+ };
145
+ expect(await ApiHelper.parseHarmonyErrorResponse(errResp)).toEqual(expected);
146
+ });
147
+ });
@@ -0,0 +1,2 @@
1
+ import { OptionalStockQueryParams, OptionalStockRequestBody } from "../modules/shared/types";
2
+ export declare function mapOptionalStockQueryParams(src: OptionalStockQueryParams): OptionalStockRequestBody;
@@ -0,0 +1,28 @@
1
+ import { OptionalStockRequestBody, } from "../modules/shared/types";
2
+ export function mapOptionalStockQueryParams(src) {
3
+ return new OptionalStockRequestBody({
4
+ StockCategoryFr: src?.stockCategoryFr ?? "",
5
+ StockCategoryTo: src?.stockCategoryTo ?? "",
6
+ StockClassFr1: src?.stockClassFr1 ?? "",
7
+ StockClassTo1: src?.stockClassTo1 ?? "",
8
+ StockClassFr2: src?.stockClassFr2 ?? "",
9
+ StockClassTo2: src?.stockClassTo2 ?? "",
10
+ StockClassFr3: src?.stockClassFr3 ?? "",
11
+ StockClassTo3: src?.stockClassTo3 ?? "",
12
+ StockExtraClassFr1: src?.stockExtraClassFr1 ?? "",
13
+ StockExtraClassTo1: src?.stockExtraClassTo1 ?? "",
14
+ StockExtraClassFr2: src?.stockExtraClassFr2 ?? "",
15
+ StockExtraClassTo2: src?.stockExtraClassTo2 ?? "",
16
+ StockExtraClassFr3: src?.stockExtraClassFr3 ?? "",
17
+ StockExtraClassTo3: src?.stockExtraClassTo3 ?? "",
18
+ StockExtraClassFr4: src?.stockExtraClassFr4 ?? "",
19
+ StockExtraClassTo4: src?.stockExtraClassTo4 ?? "",
20
+ StockExtraClassFr5: src?.stockExtraClassFr5 ?? "",
21
+ StockExtraClassTo5: src?.stockExtraClassTo5 ?? "",
22
+ SysModTimeFr: src?.sysModTimeFr ?? "",
23
+ SysModTimeTo: src?.sysModTimeTo ?? "",
24
+ AlternateNamekeyFr: src?.alternateNamekeyFr ?? "",
25
+ AlternateNamekeyTo: src?.alternateNamekeyTo ?? "",
26
+ StockActive: src?.stockActive?.map(String)?.join("") ?? "",
27
+ });
28
+ }
@@ -0,0 +1,71 @@
1
+ export declare abstract class Utils {
2
+ /**
3
+ * Check if an object is an empty array or not an array
4
+ *
5
+ * @static
6
+ * @param {*} obj object to check
7
+ * @returns {boolean} true if object is an empty array
8
+ */
9
+ static isEmptyArray(obj: any): boolean;
10
+ /**
11
+ * Check if an object is a non-empty array.
12
+ *
13
+ * @static
14
+ * @param {*} obj object to check
15
+ * @returns {boolean} true if object is a non-empty array
16
+ */
17
+ static nonEmptyArray(obj: any): boolean;
18
+ /**
19
+ * Chcek if an object is an empty string or not a string
20
+ *
21
+ * @static
22
+ * @param {*} obj object to check
23
+ * @returns {boolean} true if object is an empty string
24
+ */
25
+ static isEmptyString(obj: any): boolean;
26
+ /**
27
+ * Check if an object is a non-empty string.
28
+ *
29
+ * @static
30
+ * @param {*} obj object to check
31
+ * @returns {boolean} true if object is a non-empty string
32
+ */
33
+ static nonEmptyString(obj: any): boolean;
34
+ /**
35
+ * Convert a value to a number.
36
+ *
37
+ * @static
38
+ * @param {*} obj object to convert to a number
39
+ * @returns {number} the converted number
40
+ */
41
+ static toNumber(obj: any): number;
42
+ static checkMaxStringLength(str: any, length: number, propName?: string): boolean;
43
+ /**
44
+ * Remove all empty spaces within a string, including new lines and tabs...
45
+ *
46
+ * @static
47
+ * @param {string} str to remove empty spaces from
48
+ * @returns {string} string with empty spaces removed
49
+ */
50
+ static removeEmptySpaces(str: string): string;
51
+ static isXmlEqualJson(xml: string, json: any): Promise<boolean>;
52
+ /**
53
+ * Recursively convert an object into xml format
54
+ *
55
+ * @static
56
+ * @param {*} obj
57
+ * @returns {string}
58
+ */
59
+ static toXml(obj: object, parent?: string): string;
60
+ static deleteUndefinedProps(obj: any): any;
61
+ static deleteEmptyProps(obj: any): any;
62
+ /**
63
+ * Returns first element of an array.
64
+ * Responses extracted from XML have all properties in the format of arrays of 1 element. This is used to extract value out of those properties
65
+ *
66
+ * @static
67
+ * @param {*} prop property array to extract
68
+ * @returns {*} first value in the array
69
+ */
70
+ static getFirst(prop: any): string;
71
+ }
@@ -0,0 +1,133 @@
1
+ import { promisify } from "util";
2
+ import { parseString } from "xml2js";
3
+ const parseXml = promisify(parseString);
4
+ export class Utils {
5
+ /**
6
+ * Check if an object is an empty array or not an array
7
+ *
8
+ * @static
9
+ * @param {*} obj object to check
10
+ * @returns {boolean} true if object is an empty array
11
+ */
12
+ static isEmptyArray(obj) {
13
+ return !Utils.nonEmptyArray(obj);
14
+ }
15
+ /**
16
+ * Check if an object is a non-empty array.
17
+ *
18
+ * @static
19
+ * @param {*} obj object to check
20
+ * @returns {boolean} true if object is a non-empty array
21
+ */
22
+ static nonEmptyArray(obj) {
23
+ return Array.isArray(obj) && obj.length > 0;
24
+ }
25
+ /**
26
+ * Chcek if an object is an empty string or not a string
27
+ *
28
+ * @static
29
+ * @param {*} obj object to check
30
+ * @returns {boolean} true if object is an empty string
31
+ */
32
+ static isEmptyString(obj) {
33
+ return !Utils.nonEmptyString(obj);
34
+ }
35
+ /**
36
+ * Check if an object is a non-empty string.
37
+ *
38
+ * @static
39
+ * @param {*} obj object to check
40
+ * @returns {boolean} true if object is a non-empty string
41
+ */
42
+ static nonEmptyString(obj) {
43
+ return typeof obj === "string" && obj.trim() !== "";
44
+ }
45
+ /**
46
+ * Convert a value to a number.
47
+ *
48
+ * @static
49
+ * @param {*} obj object to convert to a number
50
+ * @returns {number} the converted number
51
+ */
52
+ static toNumber(obj) {
53
+ const num = Number(obj);
54
+ if (isNaN(num))
55
+ throw new Error(`Provided value [${obj}] is not a number.`);
56
+ return num;
57
+ }
58
+ static checkMaxStringLength(str, length, propName = "property") {
59
+ if (!(typeof str === "string" && str.length <= length))
60
+ throw new Error(`Provided ${propName} exceeds maximum length of ${length} characters.`);
61
+ return true;
62
+ }
63
+ /**
64
+ * Remove all empty spaces within a string, including new lines and tabs...
65
+ *
66
+ * @static
67
+ * @param {string} str to remove empty spaces from
68
+ * @returns {string} string with empty spaces removed
69
+ */
70
+ static removeEmptySpaces(str) {
71
+ return str.replace(/\s/g, "");
72
+ }
73
+ static async isXmlEqualJson(xml, json) {
74
+ const result = (await parseXml(`<result>${xml}</result>`))["result"];
75
+ // Test that each key value pair matches the expected
76
+ for (const k in result) {
77
+ const val = result[k][0];
78
+ if (json[k] !== val)
79
+ return false;
80
+ }
81
+ return true;
82
+ }
83
+ /**
84
+ * Recursively convert an object into xml format
85
+ *
86
+ * @static
87
+ * @param {*} obj
88
+ * @returns {string}
89
+ */
90
+ static toXml(obj, parent) {
91
+ if (obj == null)
92
+ return "";
93
+ let str = "";
94
+ const open = parent ? `<${parent}>` : "";
95
+ const close = parent ? `</${parent}>` : "";
96
+ if (Array.isArray(obj)) {
97
+ str += obj.map((o) => open + Utils.toXml(o) + close).join("");
98
+ }
99
+ else if (typeof obj === "object") {
100
+ let valStr = "";
101
+ for (const k in obj) {
102
+ const val = obj[k];
103
+ if (!(val == null)) {
104
+ valStr += `${Utils.toXml(val, k)}`;
105
+ }
106
+ }
107
+ str += open + valStr + close;
108
+ }
109
+ else {
110
+ str += open + obj + close;
111
+ }
112
+ return str;
113
+ }
114
+ static deleteUndefinedProps(obj) {
115
+ Object.keys(obj).forEach((key) => obj[key] === undefined && delete obj[key]);
116
+ return obj;
117
+ }
118
+ static deleteEmptyProps(obj) {
119
+ Object.keys(obj).forEach((key) => [undefined, null, ""].includes(obj[key]) && delete obj[key]);
120
+ return obj;
121
+ }
122
+ /**
123
+ * Returns first element of an array.
124
+ * Responses extracted from XML have all properties in the format of arrays of 1 element. This is used to extract value out of those properties
125
+ *
126
+ * @static
127
+ * @param {*} prop property array to extract
128
+ * @returns {*} first value in the array
129
+ */
130
+ static getFirst(prop) {
131
+ return (prop ?? [])[0];
132
+ }
133
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,96 @@
1
+ import { Utils } from "./utils";
2
+ describe("Utils", () => {
3
+ test("isEmptyArray", () => {
4
+ expect.assertions(7);
5
+ const nonEmpty = [1, 2, 3];
6
+ const nonEmptyStr = ["1", "2", "3"];
7
+ expect(Utils.isEmptyArray(nonEmpty)).toBe(false);
8
+ expect(Utils.isEmptyArray(nonEmptyStr)).toBe(false);
9
+ expect(Utils.isEmptyArray([])).toBe(true);
10
+ expect(Utils.isEmptyArray("")).toBe(true);
11
+ expect(Utils.isEmptyArray("asadf")).toBe(true);
12
+ expect(Utils.isEmptyArray(null)).toBe(true);
13
+ expect(Utils.isEmptyArray(undefined)).toBe(true);
14
+ });
15
+ test("isEmptyString", () => {
16
+ expect.assertions(6);
17
+ const nonEmpty = "test";
18
+ expect(Utils.isEmptyString(nonEmpty)).toBe(false);
19
+ expect(Utils.isEmptyString([])).toBe(true);
20
+ expect(Utils.isEmptyString(["1", "2", "3"])).toBe(true);
21
+ expect(Utils.isEmptyString("")).toBe(true);
22
+ expect(Utils.isEmptyString(null)).toBe(true);
23
+ expect(Utils.isEmptyString(undefined)).toBe(true);
24
+ });
25
+ test("toNumber", () => {
26
+ const invalidValues = [undefined, "abc", "123abc", {}, "*&^*"];
27
+ for (const i of invalidValues) {
28
+ expect(() => Utils.toNumber(i)).toThrow(`Provided value [${i}] is not a number.`);
29
+ }
30
+ expect(Utils.toNumber("123")).toBe(123);
31
+ expect(Utils.toNumber("123.45")).toBe(123.45);
32
+ expect(Utils.toNumber(true)).toBe(1);
33
+ expect(Utils.toNumber(false)).toBe(0);
34
+ expect(Utils.toNumber("")).toBe(0);
35
+ expect(Utils.toNumber(null)).toBe(0);
36
+ });
37
+ test("toXml should convert to XML string successfully", () => {
38
+ const obj = {
39
+ name: "John Doe",
40
+ age: 30,
41
+ city: "New York",
42
+ hobbies: ["reading", "painting"],
43
+ address: {
44
+ street: "123 Main St",
45
+ city: "New York",
46
+ state: "NY",
47
+ zip: "10001",
48
+ },
49
+ count: 0,
50
+ nullable: null,
51
+ };
52
+ const expectedXml = `
53
+ <name>John Doe</name>
54
+ <age>30</age>
55
+ <city>New York</city>
56
+ <hobbies>reading</hobbies>
57
+ <hobbies>painting</hobbies>
58
+ <address>
59
+ <street>123 Main St</street>
60
+ <city>New York</city>
61
+ <state>NY</state>
62
+ <zip>10001</zip>
63
+ </address>
64
+ <count>0</count>
65
+ `;
66
+ expect(Utils.removeEmptySpaces(Utils.toXml(obj))).toEqual(Utils.removeEmptySpaces(expectedXml));
67
+ });
68
+ test("deleteUndefinedProps() should remove undefined properties", () => {
69
+ const obj = {
70
+ "1": true,
71
+ "2": "test",
72
+ "3": undefined,
73
+ "4": null,
74
+ };
75
+ Utils.deleteUndefinedProps(obj);
76
+ expect(obj).toEqual({
77
+ "1": true,
78
+ "2": "test",
79
+ "4": null,
80
+ });
81
+ });
82
+ test("deleteEmptyProps() should remove all empty properties", () => {
83
+ const obj = {
84
+ "1": true,
85
+ "2": "test",
86
+ "3": undefined,
87
+ "4": null,
88
+ "5": "",
89
+ };
90
+ Utils.deleteEmptyProps(obj);
91
+ expect(obj).toEqual({
92
+ "1": true,
93
+ "2": "test",
94
+ });
95
+ });
96
+ });
@@ -0,0 +1,5 @@
1
+ export * from "./errors";
2
+ export * from "./HarmonyAPI";
3
+ export * from "./helpers";
4
+ export * from "./modules";
5
+ export * from "./types";
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ export * from "./errors";
2
+ export * from "./HarmonyAPI";
3
+ export * from "./helpers";
4
+ export * from "./modules";
5
+ export * from "./types";
@@ -0,0 +1,7 @@
1
+ import { AxiosInstance } from "axios";
2
+ import { AuthenticationToken } from "./types";
3
+ export declare class AuthModule {
4
+ private axiosInstance;
5
+ constructor(axiosInstance: AxiosInstance);
6
+ authenticate(authToken: AuthenticationToken): Promise<string>;
7
+ }
@@ -0,0 +1,42 @@
1
+ import { AuthenticationError } from "../../errors";
2
+ import { ApiHelper } from "../../helpers";
3
+ export class AuthModule {
4
+ axiosInstance;
5
+ constructor(axiosInstance) {
6
+ this.axiosInstance = axiosInstance;
7
+ }
8
+ async authenticate(authToken) {
9
+ // @todo: TBC whether using `xmlbuilder` or template string
10
+ const authHeader = `
11
+ <ns2:AuthenticationToken xmlns:ns2="http://auth.ws.fbsaust.com.au" xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
12
+ <username>${authToken.username}</username>
13
+ <method>${authToken.method}</method>
14
+ <password>${authToken.password}</password>
15
+ <timeout>${authToken.timeout}${authToken.timeoutUnit}</timeout>
16
+ </ns2:AuthenticationToken>
17
+ `;
18
+ const loginBody = '<ns2:Login xmlns:ns2="http://auth.ws.fbsaust.com.au"/>';
19
+ const soapEnvelope = `
20
+ <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
21
+ <S:Header>${authHeader}</S:Header>
22
+ <S:Body>${loginBody}</S:Body>
23
+ </S:Envelope>
24
+ `;
25
+ try {
26
+ const response = await ApiHelper.sendSoapRequest("/AuthenticationService/AuthenticationService", this.axiosInstance, soapEnvelope);
27
+ const token = response["ns2:LoginResponse"][0]["token"][0];
28
+ if (!token) {
29
+ throw new AuthenticationError("No token received in the authentication response");
30
+ }
31
+ return token;
32
+ }
33
+ catch (error) {
34
+ if (error instanceof AuthenticationError) {
35
+ throw error;
36
+ }
37
+ else {
38
+ throw new AuthenticationError(`An unexpected error occurred: ${error.message}`);
39
+ }
40
+ }
41
+ }
42
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,55 @@
1
+ import axios from "axios";
2
+ import { ApiHelper, Utils } from "../../helpers";
3
+ import { AuthModule } from "./auth.module";
4
+ jest.mock("axios");
5
+ const mAxios = axios;
6
+ const sessionId = ""; // process.env.SESSION_ID as string;
7
+ describe("AuthModule", () => {
8
+ let authModule;
9
+ beforeAll(() => {
10
+ authModule = new AuthModule(mAxios);
11
+ });
12
+ test("authenticate successfully", async () => {
13
+ const mockedSendApiRequest = jest.spyOn(ApiHelper, "sendSoapRequest");
14
+ const authToken = {
15
+ username: "test-username",
16
+ password: "test-password",
17
+ method: "Basic",
18
+ timeout: 365,
19
+ timeoutUnit: "day",
20
+ };
21
+ const mockedToken = "CI03GWHZzXO0VJQ6JSLJoPwWijXTIPilphKvlLhLHcjDQ3yrr6eJeTK6wxDb8XZb";
22
+ const mockedResponse = {
23
+ data: `
24
+ <?xml version='1.0' encoding='UTF-8'?>
25
+ <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
26
+ <S:Body>
27
+ <ns2:LoginResponse xmlns:ns2="http://auth.ws.fbsaust.com.au">
28
+ <token>${mockedToken}</token>
29
+ </ns2:LoginResponse>
30
+ </S:Body>
31
+ </S:Envelope>
32
+ `,
33
+ };
34
+ mAxios.post.mockResolvedValueOnce(mockedResponse);
35
+ const token = await authModule.authenticate(authToken);
36
+ expect(mockedSendApiRequest).toHaveBeenCalled();
37
+ expect(mAxios.post).toHaveBeenCalled();
38
+ expect(Utils.removeEmptySpaces(mAxios.post.mock.calls[0][1])).toEqual(Utils.removeEmptySpaces(`
39
+ <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
40
+ <S:Header>
41
+ <ns2:AuthenticationToken xmlns:ns2="http://auth.ws.fbsaust.com.au" xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
42
+ <username>${authToken.username}</username>
43
+ <method>${authToken.method}</method>
44
+ <password>${authToken.password}</password>
45
+ <timeout>${authToken.timeout}${authToken.timeoutUnit}</timeout>
46
+ </ns2:AuthenticationToken>
47
+ </S:Header>
48
+ <S:Body>
49
+ <ns2:Login xmlns:ns2="http://auth.ws.fbsaust.com.au"/>
50
+ </S:Body>
51
+ </S:Envelope>
52
+ `));
53
+ expect(token).toEqual(mockedToken);
54
+ });
55
+ });
@@ -0,0 +1,2 @@
1
+ export * from "./auth.module";
2
+ export * from "./types";
@@ -0,0 +1,2 @@
1
+ export * from "./auth.module";
2
+ export * from "./types";
@@ -0,0 +1,7 @@
1
+ export interface AuthenticationToken {
2
+ username: string;
3
+ method: string;
4
+ password: string;
5
+ timeout: number;
6
+ timeoutUnit: string;
7
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,10 @@
1
+ import { AxiosInstance } from "axios";
2
+ import { Carrier, CarrierShipment, GetCarrierShipmentByTimeQueryParams } from "./types";
3
+ export declare class CarrierModule {
4
+ private axiosInstance;
5
+ private readonly SERVICE_URL;
6
+ constructor(axiosInstance: AxiosInstance);
7
+ getCarrier(sessionId: string): Promise<Carrier[]>;
8
+ getCarrierShipmentByOrderNumber(orderNo: string, sessionId: string): Promise<CarrierShipment[]>;
9
+ getCarrierShipmentBySysTime(params: GetCarrierShipmentByTimeQueryParams, sessionId: string): Promise<CarrierShipment[]>;
10
+ }