@softwear/latestcollectioncore 1.0.196 → 1.0.198
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.d.ts +0 -4
- package/dist/articleStatus.js +7 -3
- package/dist/consts.d.ts +4 -0
- package/dist/consts.js +4 -0
- package/dist/dataRetention.d.ts +4 -0
- package/dist/dataRetention.js +27 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/types.d.ts +1 -0
- package/package.json +1 -1
- package/src/articleStatus.ts +8 -3
- package/src/consts.ts +4 -0
- package/src/dataRetention.ts +23 -0
- package/src/index.ts +1 -0
- package/src/types.ts +1 -0
- package/test/articleStatus.spec.js +55 -0
- package/test/dataRetention.spec.ts +21 -0
package/dist/articleStatus.d.ts
CHANGED
|
@@ -1,8 +1,4 @@
|
|
|
1
1
|
import { TransactionI, RaGI, HrTimeframeI, TimeGranularityE, SkuI } from './types';
|
|
2
|
-
/**
|
|
3
|
-
* The propFunction for FiltreX needs some data that can't be passed as parameters. That's why the 'globalsRelations' variable is needed.
|
|
4
|
-
* TODO: Functional: Experiment with curried functions
|
|
5
|
-
*/
|
|
6
2
|
declare function propFunction(propertyName: string, getPropertyName: Function, obj: Record<string, any>): any;
|
|
7
3
|
declare function whichShardsToProcess(dateRange: any, granularity: 'year' | 'month'): any[];
|
|
8
4
|
/**
|
package/dist/articleStatus.js
CHANGED
|
@@ -29,16 +29,20 @@ let globalNrAggegationExpressions = 0; // tracks the # aggregations rows so we c
|
|
|
29
29
|
* The propFunction for FiltreX needs some data that can't be passed as parameters. That's why the 'globalsRelations' variable is needed.
|
|
30
30
|
* TODO: Functional: Experiment with curried functions
|
|
31
31
|
*/
|
|
32
|
+
function resolvePath(obj, path) {
|
|
33
|
+
return path.reduce((o, key) => o === null || o === void 0 ? void 0 : o[key], obj);
|
|
34
|
+
}
|
|
32
35
|
function propFunction(propertyName, getPropertyName, obj) {
|
|
33
36
|
var _a, _b;
|
|
34
37
|
const positionOfDot = propertyName.indexOf('.');
|
|
35
38
|
if (positionOfDot < 0)
|
|
36
39
|
return obj[propertyName];
|
|
37
40
|
const table = propertyName.substring(0, positionOfDot);
|
|
38
|
-
const
|
|
41
|
+
const path = propertyName.substring(positionOfDot + 1).split('.');
|
|
39
42
|
if (table == 'transaction')
|
|
40
|
-
return obj
|
|
41
|
-
|
|
43
|
+
return resolvePath(obj, path);
|
|
44
|
+
const joinedRecord = (_a = globalRelations[table]) === null || _a === void 0 ? void 0 : _a[obj[globalJoinableTables[table]]];
|
|
45
|
+
return (_b = resolvePath(joinedRecord, path)) !== null && _b !== void 0 ? _b : '~ ?';
|
|
42
46
|
}
|
|
43
47
|
const lower = (s) => s.toLowerCase();
|
|
44
48
|
const upper = (s) => s.toUpperCase();
|
package/dist/consts.d.ts
CHANGED
|
@@ -4,21 +4,25 @@ declare const SUBSCRIPTION_LIMITS: {
|
|
|
4
4
|
readonly maxBarcodes: 1000;
|
|
5
5
|
readonly maxDownloadBarcodes: 1000;
|
|
6
6
|
readonly maxCustomers: 0;
|
|
7
|
+
readonly maxDataRetentionYears: 3;
|
|
7
8
|
};
|
|
8
9
|
readonly basiq: {
|
|
9
10
|
readonly maxBarcodes: 100000;
|
|
10
11
|
readonly maxDownloadBarcodes: 10000;
|
|
11
12
|
readonly maxCustomers: 1000;
|
|
13
|
+
readonly maxDataRetentionYears: 3;
|
|
12
14
|
};
|
|
13
15
|
readonly pro: {
|
|
14
16
|
readonly maxBarcodes: 200000;
|
|
15
17
|
readonly maxDownloadBarcodes: 20000;
|
|
16
18
|
readonly maxCustomers: 10000;
|
|
19
|
+
readonly maxDataRetentionYears: 5;
|
|
17
20
|
};
|
|
18
21
|
readonly ultimate: {
|
|
19
22
|
readonly maxBarcodes: 500000;
|
|
20
23
|
readonly maxDownloadBarcodes: 50000;
|
|
21
24
|
readonly maxCustomers: 100000;
|
|
25
|
+
readonly maxDataRetentionYears: 7;
|
|
22
26
|
};
|
|
23
27
|
};
|
|
24
28
|
declare const latestCollectionGLN: "8719332204995";
|
package/dist/consts.js
CHANGED
|
@@ -22,21 +22,25 @@ const SUBSCRIPTION_LIMITS = {
|
|
|
22
22
|
maxBarcodes: 1000,
|
|
23
23
|
maxDownloadBarcodes: 1000,
|
|
24
24
|
maxCustomers: 0,
|
|
25
|
+
maxDataRetentionYears: 3,
|
|
25
26
|
},
|
|
26
27
|
basiq: {
|
|
27
28
|
maxBarcodes: 100000,
|
|
28
29
|
maxDownloadBarcodes: 10000,
|
|
29
30
|
maxCustomers: 1000,
|
|
31
|
+
maxDataRetentionYears: 3,
|
|
30
32
|
},
|
|
31
33
|
pro: {
|
|
32
34
|
maxBarcodes: 200000,
|
|
33
35
|
maxDownloadBarcodes: 20000,
|
|
34
36
|
maxCustomers: 10000,
|
|
37
|
+
maxDataRetentionYears: 5,
|
|
35
38
|
},
|
|
36
39
|
ultimate: {
|
|
37
40
|
maxBarcodes: 500000,
|
|
38
41
|
maxDownloadBarcodes: 50000,
|
|
39
42
|
maxCustomers: 100000,
|
|
43
|
+
maxDataRetentionYears: 7,
|
|
40
44
|
},
|
|
41
45
|
};
|
|
42
46
|
exports.SUBSCRIPTION_LIMITS = SUBSCRIPTION_LIMITS;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare function getMaxDataRetentionYears(subscription: string): number;
|
|
2
|
+
export declare function getEarliestAllowedYear(maxRetentionYears: number, thisYear?: number): number;
|
|
3
|
+
export declare function isYearWithinDataRetention(year: number | string, maxRetentionYears: number, thisYear?: number): boolean;
|
|
4
|
+
export declare function isDateWithinDataRetention(date: string, maxRetentionYears: number, thisYear?: number): boolean;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isDateWithinDataRetention = exports.isYearWithinDataRetention = exports.getEarliestAllowedYear = exports.getMaxDataRetentionYears = void 0;
|
|
4
|
+
const consts_1 = require("./consts");
|
|
5
|
+
function getMaxDataRetentionYears(subscription) {
|
|
6
|
+
var _a;
|
|
7
|
+
const limits = consts_1.SUBSCRIPTION_LIMITS[subscription];
|
|
8
|
+
return (_a = limits === null || limits === void 0 ? void 0 : limits.maxDataRetentionYears) !== null && _a !== void 0 ? _a : consts_1.SUBSCRIPTION_LIMITS.basiq.maxDataRetentionYears;
|
|
9
|
+
}
|
|
10
|
+
exports.getMaxDataRetentionYears = getMaxDataRetentionYears;
|
|
11
|
+
function getEarliestAllowedYear(maxRetentionYears, thisYear = new Date().getFullYear()) {
|
|
12
|
+
return thisYear - maxRetentionYears + 1;
|
|
13
|
+
}
|
|
14
|
+
exports.getEarliestAllowedYear = getEarliestAllowedYear;
|
|
15
|
+
function isYearWithinDataRetention(year, maxRetentionYears, thisYear = new Date().getFullYear()) {
|
|
16
|
+
const parsedYear = parseInt(String(year), 10);
|
|
17
|
+
if (Number.isNaN(parsedYear))
|
|
18
|
+
return true;
|
|
19
|
+
return parsedYear >= getEarliestAllowedYear(maxRetentionYears, thisYear);
|
|
20
|
+
}
|
|
21
|
+
exports.isYearWithinDataRetention = isYearWithinDataRetention;
|
|
22
|
+
function isDateWithinDataRetention(date, maxRetentionYears, thisYear = new Date().getFullYear()) {
|
|
23
|
+
if (!date)
|
|
24
|
+
return true;
|
|
25
|
+
return isYearWithinDataRetention(parseInt(date.substring(0, 4), 10), maxRetentionYears, thisYear);
|
|
26
|
+
}
|
|
27
|
+
exports.isDateWithinDataRetention = isDateWithinDataRetention;
|
package/dist/index.d.ts
CHANGED
|
@@ -25,5 +25,6 @@ export * from './pdf';
|
|
|
25
25
|
export type { GenPdfAlert, GenPdfOptions, PdfFontDefinition, PdfFontVariant, PdfImageAsset } from './reports';
|
|
26
26
|
export * from './types';
|
|
27
27
|
export * from './consts';
|
|
28
|
+
export * from './dataRetention';
|
|
28
29
|
export { default as lcAxios, createAxiosInstance, axiosRetry, exponentialDelay, isAxiosError, } from './lcAxios';
|
|
29
30
|
export type { AxiosRequestConfig, AxiosResponse, AxiosPromise, AxiosError, AxiosTransformer, AxiosRetryOptions, AxiosRequestConfigAny, } from './lcAxios';
|
package/dist/index.js
CHANGED
|
@@ -69,6 +69,7 @@ Object.defineProperty(exports, "shouldSuppressZeroField", { enumerable: true, ge
|
|
|
69
69
|
__exportStar(require("./pdf"), exports);
|
|
70
70
|
__exportStar(require("./types"), exports);
|
|
71
71
|
__exportStar(require("./consts"), exports);
|
|
72
|
+
__exportStar(require("./dataRetention"), exports);
|
|
72
73
|
var lcAxios_1 = require("./lcAxios");
|
|
73
74
|
Object.defineProperty(exports, "lcAxios", { enumerable: true, get: function () { return __importDefault(lcAxios_1).default; } });
|
|
74
75
|
Object.defineProperty(exports, "createAxiosInstance", { enumerable: true, get: function () { return lcAxios_1.createAxiosInstance; } });
|
package/dist/types.d.ts
CHANGED
package/package.json
CHANGED
package/src/articleStatus.ts
CHANGED
|
@@ -97,13 +97,18 @@ let globalNrAggegationExpressions = 0 // tracks the # aggregations rows so we ca
|
|
|
97
97
|
* The propFunction for FiltreX needs some data that can't be passed as parameters. That's why the 'globalsRelations' variable is needed.
|
|
98
98
|
* TODO: Functional: Experiment with curried functions
|
|
99
99
|
*/
|
|
100
|
+
function resolvePath(obj: Record<string, any> | undefined, path: string[]): any {
|
|
101
|
+
return path.reduce((o, key) => o?.[key], obj)
|
|
102
|
+
}
|
|
103
|
+
|
|
100
104
|
function propFunction(propertyName: string, getPropertyName: Function, obj: Record<string, any>): any {
|
|
101
105
|
const positionOfDot = propertyName.indexOf('.')
|
|
102
106
|
if (positionOfDot < 0) return obj[propertyName]
|
|
103
107
|
const table = propertyName.substring(0, positionOfDot)
|
|
104
|
-
const
|
|
105
|
-
if (table == 'transaction') return obj
|
|
106
|
-
|
|
108
|
+
const path = propertyName.substring(positionOfDot + 1).split('.')
|
|
109
|
+
if (table == 'transaction') return resolvePath(obj, path)
|
|
110
|
+
const joinedRecord = globalRelations[table]?.[obj[globalJoinableTables[table]]]
|
|
111
|
+
return resolvePath(joinedRecord, path) ?? '~ ?'
|
|
107
112
|
}
|
|
108
113
|
|
|
109
114
|
const lower = (s: string) => s.toLowerCase()
|
package/src/consts.ts
CHANGED
|
@@ -18,21 +18,25 @@ const SUBSCRIPTION_LIMITS = {
|
|
|
18
18
|
maxBarcodes: 1000,
|
|
19
19
|
maxDownloadBarcodes: 1000,
|
|
20
20
|
maxCustomers: 0,
|
|
21
|
+
maxDataRetentionYears: 3,
|
|
21
22
|
},
|
|
22
23
|
basiq: {
|
|
23
24
|
maxBarcodes: 100000,
|
|
24
25
|
maxDownloadBarcodes: 10000,
|
|
25
26
|
maxCustomers: 1000,
|
|
27
|
+
maxDataRetentionYears: 3,
|
|
26
28
|
},
|
|
27
29
|
pro: {
|
|
28
30
|
maxBarcodes: 200000,
|
|
29
31
|
maxDownloadBarcodes: 20000,
|
|
30
32
|
maxCustomers: 10000,
|
|
33
|
+
maxDataRetentionYears: 5,
|
|
31
34
|
},
|
|
32
35
|
ultimate: {
|
|
33
36
|
maxBarcodes: 500000,
|
|
34
37
|
maxDownloadBarcodes: 50000,
|
|
35
38
|
maxCustomers: 100000,
|
|
39
|
+
maxDataRetentionYears: 7,
|
|
36
40
|
},
|
|
37
41
|
} as const
|
|
38
42
|
const latestCollectionGLN = '8719332204995' as const
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { SUBSCRIPTION_LIMITS } from './consts'
|
|
2
|
+
|
|
3
|
+
type SubscriptionKey = keyof typeof SUBSCRIPTION_LIMITS
|
|
4
|
+
|
|
5
|
+
export function getMaxDataRetentionYears(subscription: string): number {
|
|
6
|
+
const limits = SUBSCRIPTION_LIMITS[subscription as SubscriptionKey]
|
|
7
|
+
return limits?.maxDataRetentionYears ?? SUBSCRIPTION_LIMITS.basiq.maxDataRetentionYears
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function getEarliestAllowedYear(maxRetentionYears: number, thisYear = new Date().getFullYear()): number {
|
|
11
|
+
return thisYear - maxRetentionYears + 1
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function isYearWithinDataRetention(year: number | string, maxRetentionYears: number, thisYear = new Date().getFullYear()): boolean {
|
|
15
|
+
const parsedYear = parseInt(String(year), 10)
|
|
16
|
+
if (Number.isNaN(parsedYear)) return true
|
|
17
|
+
return parsedYear >= getEarliestAllowedYear(maxRetentionYears, thisYear)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function isDateWithinDataRetention(date: string, maxRetentionYears: number, thisYear = new Date().getFullYear()): boolean {
|
|
21
|
+
if (!date) return true
|
|
22
|
+
return isYearWithinDataRetention(parseInt(date.substring(0, 4), 10), maxRetentionYears, thisYear)
|
|
23
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -25,6 +25,7 @@ export * from './pdf'
|
|
|
25
25
|
export type { GenPdfAlert, GenPdfOptions, PdfFontDefinition, PdfFontVariant, PdfImageAsset } from './reports'
|
|
26
26
|
export * from './types'
|
|
27
27
|
export * from './consts'
|
|
28
|
+
export * from './dataRetention'
|
|
28
29
|
export {
|
|
29
30
|
default as lcAxios,
|
|
30
31
|
createAxiosInstance,
|
package/src/types.ts
CHANGED
|
@@ -271,6 +271,61 @@ describe('articleStatus', () => {
|
|
|
271
271
|
expect(result[2].vector[articleStatus.MARGIN]).toBe(50)
|
|
272
272
|
})
|
|
273
273
|
|
|
274
|
+
it('should resolve nested property paths like customer.invoiceAddress.countrycode when grouping', () => {
|
|
275
|
+
const CUSTOMERS = {
|
|
276
|
+
'*zBXU': { invoiceAddress: { countrycode: 'NL' } },
|
|
277
|
+
}
|
|
278
|
+
const rawAggregations = {}
|
|
279
|
+
articleStatus.runQuery(
|
|
280
|
+
{ beginTimeStamp: 1569316408000, endTimeStamp: 1569316409000 + msYear },
|
|
281
|
+
rawAggregations,
|
|
282
|
+
true,
|
|
283
|
+
TRANSACTIONS,
|
|
284
|
+
['customer.invoiceAddress.countrycode'],
|
|
285
|
+
SKUS,
|
|
286
|
+
{},
|
|
287
|
+
CUSTOMERS,
|
|
288
|
+
false,
|
|
289
|
+
'',
|
|
290
|
+
false
|
|
291
|
+
)
|
|
292
|
+
|
|
293
|
+
// Sales (custnr '*zBXU') resolve the nested path to 'NL',
|
|
294
|
+
// beginStock transactions have no custnr and fall back to '~ ?'
|
|
295
|
+
expect(Object.keys(rawAggregations)).toEqual(['** TOTAL **', '~ ?', 'NL'])
|
|
296
|
+
expect(rawAggregations['NL'][articleStatus.QTY_SOLD]).toBe(2)
|
|
297
|
+
})
|
|
298
|
+
|
|
299
|
+
it('should resolve nested property paths in filter expressions', () => {
|
|
300
|
+
const CUSTOMERS = {
|
|
301
|
+
'*zBXU': { invoiceAddress: { countrycode: 'NL' } },
|
|
302
|
+
}
|
|
303
|
+
const run = (countrycode) => {
|
|
304
|
+
const rawAggregations = {}
|
|
305
|
+
articleStatus.runQuery(
|
|
306
|
+
{ beginTimeStamp: 1569316408000, endTimeStamp: 1569316409000 + msYear },
|
|
307
|
+
rawAggregations,
|
|
308
|
+
false,
|
|
309
|
+
TRANSACTIONS,
|
|
310
|
+
['transaction.ean'],
|
|
311
|
+
SKUS,
|
|
312
|
+
{},
|
|
313
|
+
CUSTOMERS,
|
|
314
|
+
false,
|
|
315
|
+
'customer.invoiceAddress.countrycode == "' + countrycode + '"',
|
|
316
|
+
false
|
|
317
|
+
)
|
|
318
|
+
return rawAggregations
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
const matching = run('NL')
|
|
322
|
+
expect(Object.keys(matching)).toEqual(['** TOTAL **', '000558000143', '8700558000143'])
|
|
323
|
+
expect(matching['000558000143'][articleStatus.QTY_SOLD]).toBe(1)
|
|
324
|
+
|
|
325
|
+
const nonMatching = run('DE')
|
|
326
|
+
expect(Object.keys(nonMatching)).toEqual([])
|
|
327
|
+
})
|
|
328
|
+
|
|
274
329
|
it('should calculate shelfStock correctly with type 10 (beginShelfStock) and type 94 (picklist)', () => {
|
|
275
330
|
// Test scenario:
|
|
276
331
|
// - beginStock (type 0): 100 units
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
import { getEarliestAllowedYear, getMaxDataRetentionYears, isDateWithinDataRetention, isYearWithinDataRetention } from '../src/dataRetention'
|
|
3
|
+
|
|
4
|
+
describe('dataRetention', () => {
|
|
5
|
+
const thisYear = 2026
|
|
6
|
+
|
|
7
|
+
it('returns retention years per subscription', () => {
|
|
8
|
+
expect(getMaxDataRetentionYears('basiq')).toBe(3)
|
|
9
|
+
expect(getMaxDataRetentionYears('pro')).toBe(5)
|
|
10
|
+
expect(getMaxDataRetentionYears('ultimate')).toBe(7)
|
|
11
|
+
expect(getMaxDataRetentionYears('unknown')).toBe(3)
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
it('checks year and date access against retention', () => {
|
|
15
|
+
expect(getEarliestAllowedYear(3, thisYear)).toBe(2024)
|
|
16
|
+
expect(isYearWithinDataRetention(2024, 3, thisYear)).toBe(true)
|
|
17
|
+
expect(isYearWithinDataRetention(2023, 3, thisYear)).toBe(false)
|
|
18
|
+
expect(isDateWithinDataRetention('2023-12-31', 3, thisYear)).toBe(false)
|
|
19
|
+
expect(isDateWithinDataRetention('2024-01-01', 3, thisYear)).toBe(true)
|
|
20
|
+
})
|
|
21
|
+
})
|