@transai/connector-runner-mkg 0.2.0
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/.eslintrc.json +30 -0
- package/CHANGELOG.md +24 -0
- package/README.md +11 -0
- package/jest.config.ts +10 -0
- package/package.json +16 -0
- package/project.json +29 -0
- package/src/index.ts +1 -0
- package/src/lib/actions-handler.spec.ts +177 -0
- package/src/lib/actions-handler.ts +143 -0
- package/src/lib/connector-runner-mkg.spec.ts +219 -0
- package/src/lib/connector-runner-mkg.ts +155 -0
- package/src/lib/extractor.service.spec.ts +123 -0
- package/src/lib/extractor.service.ts +125 -0
- package/src/lib/tables/_all.ts +60 -0
- package/src/lib/tables/artg.ts +12 -0
- package/src/lib/tables/arti.ts +99 -0
- package/src/lib/tables/base/action.ts +70 -0
- package/src/lib/tables/base/table.ts +57 -0
- package/src/lib/tables/bwrg.ts +13 -0
- package/src/lib/tables/bwrk.ts +60 -0
- package/src/lib/tables/clch.ts +42 -0
- package/src/lib/tables/debi.ts +62 -0
- package/src/lib/tables/magl.ts +15 -0
- package/src/lib/tables/magz.ts +14 -0
- package/src/lib/tables/medw.ts +97 -0
- package/src/lib/tables/parl.ts +24 -0
- package/src/lib/tables/plnb.ts +46 -0
- package/src/lib/tables/prbv.ts +31 -0
- package/src/lib/tables/prdh.ts +46 -0
- package/src/lib/tables/prdr.ts +25 -0
- package/src/lib/tables/prmv.ts +31 -0
- package/src/lib/tables/rela.ts +40 -0
- package/src/lib/tables/rgrs.ts +68 -0
- package/src/lib/tables/rsrc.ts +23 -0
- package/src/lib/tables/rsrd.ts +98 -0
- package/src/lib/tables/rsrg.ts +6 -0
- package/src/lib/tables/stlh.ts +24 -0
- package/src/lib/tables/stlm.ts +80 -0
- package/src/lib/tables/stlr.ts +60 -0
- package/src/lib/tables/vrdg.ts +27 -0
- package/src/lib/types.ts +45 -0
- package/tsconfig.json +22 -0
- package/tsconfig.lib.json +10 -0
- package/tsconfig.spec.json +14 -0
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/* eslint-disable camelcase,@typescript-eslint/naming-convention */
|
|
2
|
+
import {
|
|
3
|
+
ConnectorRuntimeSDK,
|
|
4
|
+
ConnectorSDKInterface,
|
|
5
|
+
HttpClientSDKInterface,
|
|
6
|
+
HttpRequestOptions,
|
|
7
|
+
} from '@transai/connector-runtime-sdk';
|
|
8
|
+
import { ConnectorInterface } from '@xip-online-data/types';
|
|
9
|
+
|
|
10
|
+
import { ActionsHandler } from './actions-handler';
|
|
11
|
+
import { ExtractorService } from './extractor.service';
|
|
12
|
+
import { MKG_TABLES } from './tables/_all';
|
|
13
|
+
import {
|
|
14
|
+
ConnectorConfig,
|
|
15
|
+
SESSION_COOKIE_NAME,
|
|
16
|
+
SESSION_EXPIRATION_SECONDS,
|
|
17
|
+
} from './types';
|
|
18
|
+
|
|
19
|
+
export class ConnectorRunnerMkg extends ConnectorRuntimeSDK<ConnectorConfig> {
|
|
20
|
+
readonly #actionsHandler: ActionsHandler;
|
|
21
|
+
|
|
22
|
+
readonly #mkgHttpClient: HttpClientSDKInterface;
|
|
23
|
+
|
|
24
|
+
readonly #sessionTokenHttpClient: HttpClientSDKInterface;
|
|
25
|
+
|
|
26
|
+
#sessionToken?: {
|
|
27
|
+
token: string;
|
|
28
|
+
expiresAt: number;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
constructor(
|
|
32
|
+
connector: ConnectorInterface,
|
|
33
|
+
connectorSDK: ConnectorSDKInterface,
|
|
34
|
+
) {
|
|
35
|
+
super(connector, connectorSDK);
|
|
36
|
+
|
|
37
|
+
const { config } = this.connectorSDK;
|
|
38
|
+
|
|
39
|
+
this.#sessionTokenHttpClient = this.connectorSDK.httpClient({
|
|
40
|
+
baseUrl: `https://${config.server}:${config.port ?? 443}/${(config.path ?? '/mkg').replace(/^\/+/, '')}`,
|
|
41
|
+
});
|
|
42
|
+
this.#mkgHttpClient = this.connectorSDK
|
|
43
|
+
.httpClient({
|
|
44
|
+
baseUrl: `https://${config.server}:${config.port ?? 443}/${(config.path ?? '/mkg').replace(/^\/+/, '')}`,
|
|
45
|
+
})
|
|
46
|
+
.setRequestOptionsFormatter(this.#requestOptionsFormatter);
|
|
47
|
+
|
|
48
|
+
this.#actionsHandler = new ActionsHandler(
|
|
49
|
+
this.connectorSDK,
|
|
50
|
+
this.#mkgHttpClient,
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
this.callbackFunction = this.#actionsHandler.callbackFunctionChain;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
override init = async (): Promise<void> => {
|
|
57
|
+
const { config } = this.connectorSDK;
|
|
58
|
+
|
|
59
|
+
Object.entries(config.tables ?? {}).forEach(
|
|
60
|
+
([tableIdentifier, configOrTrue]) => {
|
|
61
|
+
// eslint-disable-next-line security/detect-object-injection
|
|
62
|
+
const table = MKG_TABLES[tableIdentifier];
|
|
63
|
+
if (!table) {
|
|
64
|
+
this.connectorSDK.logger.warn(
|
|
65
|
+
`[MKG] Unknown table identifier "${tableIdentifier}", skipping configuration.`,
|
|
66
|
+
);
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (!table.interval || table.interval <= 0) {
|
|
71
|
+
this.connectorSDK.logger.verbose(
|
|
72
|
+
`[MKG] Table "${tableIdentifier}" does not have a valid interval configured, skipping registration.`,
|
|
73
|
+
);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
this.connectorSDK.processing.registerInterval(
|
|
78
|
+
table.interval,
|
|
79
|
+
new ExtractorService(
|
|
80
|
+
this.connectorSDK,
|
|
81
|
+
this.#mkgHttpClient,
|
|
82
|
+
tableIdentifier,
|
|
83
|
+
table.cloneFromTableConfig(configOrTrue),
|
|
84
|
+
),
|
|
85
|
+
{ immediate: table.immediate },
|
|
86
|
+
);
|
|
87
|
+
},
|
|
88
|
+
);
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
#requestOptionsFormatter = async <D = string | object>(
|
|
92
|
+
options: HttpRequestOptions<D>,
|
|
93
|
+
): Promise<HttpRequestOptions<D>> => {
|
|
94
|
+
const { config } = this.connectorSDK;
|
|
95
|
+
|
|
96
|
+
return {
|
|
97
|
+
...options,
|
|
98
|
+
headers: {
|
|
99
|
+
...(options?.headers ?? {}),
|
|
100
|
+
Cookie: `${SESSION_COOKIE_NAME}=${await this.#getSessionCookie(config.username, config.password)}`,
|
|
101
|
+
'X-CustomerID': config.apiToken,
|
|
102
|
+
},
|
|
103
|
+
};
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
async #getSessionCookie(
|
|
107
|
+
j_username: string,
|
|
108
|
+
j_password: string,
|
|
109
|
+
): Promise<string> {
|
|
110
|
+
const token = this.#sessionToken;
|
|
111
|
+
if (token && token.expiresAt > Date.now()) {
|
|
112
|
+
return token.token;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const response = await this.#sessionTokenHttpClient.post(
|
|
116
|
+
'/static/auth/j_spring_security_check',
|
|
117
|
+
{
|
|
118
|
+
j_username,
|
|
119
|
+
j_password,
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
headers: {
|
|
123
|
+
Accept: 'application/json',
|
|
124
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
if (!response) {
|
|
130
|
+
throw new Error('Failed to authenticate and retrieve session cookie');
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const cookies = (response.headers?.['set-cookie'] ??
|
|
134
|
+
response.headers?.['Set-Cookie'] ??
|
|
135
|
+
[]) as Array<string>;
|
|
136
|
+
const sessionCookie = cookies.find((cookie: string) =>
|
|
137
|
+
cookie.startsWith(`${SESSION_COOKIE_NAME}=`),
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
if (!sessionCookie) {
|
|
141
|
+
throw new Error('Session cookie not found in authentication response');
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const sessionToken = sessionCookie
|
|
145
|
+
.split(';')[0]
|
|
146
|
+
?.substring(`${SESSION_COOKIE_NAME}=`.length);
|
|
147
|
+
|
|
148
|
+
this.#sessionToken = {
|
|
149
|
+
token: sessionToken,
|
|
150
|
+
expiresAt: Date.now() + SESSION_EXPIRATION_SECONDS - 1000,
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
return sessionToken;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ConnectorSDKInterface,
|
|
3
|
+
HttpClientSDKInterface,
|
|
4
|
+
} from '@transai/connector-runtime-sdk';
|
|
5
|
+
|
|
6
|
+
import { ExtractorService } from './extractor.service';
|
|
7
|
+
import { MkgTable } from './tables/base/table';
|
|
8
|
+
import { ConnectorConfig } from './types';
|
|
9
|
+
|
|
10
|
+
describe('ExtractorService', () => {
|
|
11
|
+
let service: ExtractorService;
|
|
12
|
+
|
|
13
|
+
const sdkMock = {
|
|
14
|
+
logger: {
|
|
15
|
+
info: jest.fn(),
|
|
16
|
+
debug: jest.fn(),
|
|
17
|
+
error: jest.fn(),
|
|
18
|
+
verbose: jest.fn(),
|
|
19
|
+
},
|
|
20
|
+
offsetStore: {
|
|
21
|
+
getOffset: jest.fn().mockResolvedValue({
|
|
22
|
+
id: 0,
|
|
23
|
+
timestamp: new Date().getTime(),
|
|
24
|
+
rawTimestamp: new Date().toISOString(),
|
|
25
|
+
isoDate: new Date().toISOString(),
|
|
26
|
+
}),
|
|
27
|
+
setOffset: jest.fn().mockResolvedValue(undefined),
|
|
28
|
+
},
|
|
29
|
+
sender: {
|
|
30
|
+
documents: jest.fn().mockResolvedValue(undefined),
|
|
31
|
+
},
|
|
32
|
+
config: {},
|
|
33
|
+
} as unknown as ConnectorSDKInterface<ConnectorConfig>;
|
|
34
|
+
|
|
35
|
+
const httpClientMock = {} as HttpClientSDKInterface;
|
|
36
|
+
|
|
37
|
+
beforeEach(() => {
|
|
38
|
+
service = new ExtractorService(
|
|
39
|
+
sdkMock,
|
|
40
|
+
httpClientMock,
|
|
41
|
+
'test-table',
|
|
42
|
+
new MkgTable({
|
|
43
|
+
identifier: 'test-table',
|
|
44
|
+
fields: ['field1', 'field2'],
|
|
45
|
+
}).cloneFromTableConfig({
|
|
46
|
+
fields: ['field1', 'field11', 'field2'],
|
|
47
|
+
}),
|
|
48
|
+
);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
afterEach(() => {
|
|
52
|
+
jest.clearAllMocks();
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('should initialize and register interval', () => {
|
|
56
|
+
expect(service).toBeDefined();
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
describe('onRun', () => {
|
|
60
|
+
it('should run without errors', async () => {
|
|
61
|
+
const data = [
|
|
62
|
+
{
|
|
63
|
+
sys_dat_wijzig: '2025-11-02',
|
|
64
|
+
RowKey: '1',
|
|
65
|
+
field1: 'value1',
|
|
66
|
+
field2: 'value2',
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
sys_dat_wijzig: '2025-11-03',
|
|
70
|
+
RowKey: '2',
|
|
71
|
+
field1: 'value3',
|
|
72
|
+
field2: 'value4',
|
|
73
|
+
},
|
|
74
|
+
];
|
|
75
|
+
httpClientMock.get = jest.fn().mockResolvedValue({
|
|
76
|
+
success: true,
|
|
77
|
+
data: {
|
|
78
|
+
response: {
|
|
79
|
+
ResultData: [
|
|
80
|
+
{
|
|
81
|
+
'test-table': data,
|
|
82
|
+
},
|
|
83
|
+
],
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
await expect(service.onRun()).resolves.toBeUndefined();
|
|
89
|
+
|
|
90
|
+
expect(sdkMock.sender.documents).toHaveBeenCalledWith(data, {
|
|
91
|
+
keyField: 'RowKey',
|
|
92
|
+
collection: 'mkg_test-table',
|
|
93
|
+
});
|
|
94
|
+
expect(sdkMock.offsetStore.setOffset).toHaveBeenCalledWith(
|
|
95
|
+
{
|
|
96
|
+
id: '2',
|
|
97
|
+
timestamp: expect.any(Number),
|
|
98
|
+
rawTimestamp: expect.any(String),
|
|
99
|
+
},
|
|
100
|
+
'offset_test-table',
|
|
101
|
+
);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it('should now send documents on error response', async () => {
|
|
105
|
+
httpClientMock.get = jest.fn().mockResolvedValue({
|
|
106
|
+
success: false,
|
|
107
|
+
error: 'some-error',
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
await expect(service.onRun()).resolves.toBeUndefined();
|
|
111
|
+
|
|
112
|
+
expect(sdkMock.sender.documents).not.toHaveBeenCalled();
|
|
113
|
+
expect(sdkMock.offsetStore.setOffset).toHaveBeenCalledWith(
|
|
114
|
+
{
|
|
115
|
+
id: '0',
|
|
116
|
+
timestamp: expect.any(Number),
|
|
117
|
+
rawTimestamp: expect.any(String),
|
|
118
|
+
},
|
|
119
|
+
'offset_test-table',
|
|
120
|
+
);
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
});
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ConnectorSDKInterface,
|
|
3
|
+
HttpClientSDKInterface,
|
|
4
|
+
HttpError,
|
|
5
|
+
IntervalHandler,
|
|
6
|
+
StoredOffset,
|
|
7
|
+
} from '@transai/connector-runtime-sdk';
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
ConnectorConfig,
|
|
11
|
+
DEFAULT_DATASOURCE,
|
|
12
|
+
MkgTableInterface,
|
|
13
|
+
} from './types';
|
|
14
|
+
|
|
15
|
+
type FetchDataResponse<D> = {
|
|
16
|
+
response: {
|
|
17
|
+
ResultData: [
|
|
18
|
+
{
|
|
19
|
+
[key: string]: Array<D>;
|
|
20
|
+
},
|
|
21
|
+
];
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export class ExtractorService implements IntervalHandler {
|
|
26
|
+
readonly #sdk: ConnectorSDKInterface<ConnectorConfig>;
|
|
27
|
+
|
|
28
|
+
readonly #httpClient: HttpClientSDKInterface;
|
|
29
|
+
|
|
30
|
+
readonly #tableIdentifier: string;
|
|
31
|
+
|
|
32
|
+
readonly #table: Required<MkgTableInterface>;
|
|
33
|
+
|
|
34
|
+
readonly #fieldsList: string;
|
|
35
|
+
|
|
36
|
+
constructor(
|
|
37
|
+
sdk: ConnectorSDKInterface<ConnectorConfig>,
|
|
38
|
+
httpClient: HttpClientSDKInterface,
|
|
39
|
+
tableIdentifier: string,
|
|
40
|
+
table: Required<MkgTableInterface>,
|
|
41
|
+
) {
|
|
42
|
+
this.#sdk = sdk;
|
|
43
|
+
this.#httpClient = httpClient;
|
|
44
|
+
this.#tableIdentifier = tableIdentifier;
|
|
45
|
+
this.#table = table;
|
|
46
|
+
this.#fieldsList = table.fields.join(',');
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
get name(): string {
|
|
50
|
+
return `mkg-extractor-${this.#tableIdentifier}`;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async onRun(): Promise<void> {
|
|
54
|
+
try {
|
|
55
|
+
const now = new Date();
|
|
56
|
+
const latestOffset = await this.#sdk.offsetStore.getOffset(
|
|
57
|
+
`offset_${this.#tableIdentifier}`,
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
const data = await this.#fetchData(latestOffset);
|
|
61
|
+
if (data.length > 0) {
|
|
62
|
+
await this.#sdk.sender.documents(data, {
|
|
63
|
+
keyField: this.#table.identifierField,
|
|
64
|
+
collection: `${this.#sdk.config.datasourceIdentifier ?? DEFAULT_DATASOURCE}_${this.#tableIdentifier}`,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
this.#sdk.logger.debug(
|
|
69
|
+
`[MKG] Processed ${data.length} records from ${this.#tableIdentifier}`,
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
this.#sdk.offsetStore.setOffset(
|
|
73
|
+
{
|
|
74
|
+
id: String(
|
|
75
|
+
data[data.length - 1]?.[this.#table.identifierField] ??
|
|
76
|
+
latestOffset.id,
|
|
77
|
+
),
|
|
78
|
+
timestamp: now.getTime(),
|
|
79
|
+
rawTimestamp: now.toISOString(),
|
|
80
|
+
},
|
|
81
|
+
`offset_${this.#tableIdentifier}`,
|
|
82
|
+
);
|
|
83
|
+
} catch (error) {
|
|
84
|
+
this.#sdk.logger.error(
|
|
85
|
+
`[MKG] Failed to retrieve and process data from OPC UA source service`,
|
|
86
|
+
{ error },
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
#fetchData = async (
|
|
92
|
+
latestOffset: StoredOffset,
|
|
93
|
+
): Promise<
|
|
94
|
+
Array<{
|
|
95
|
+
[key: string]: string | number | boolean;
|
|
96
|
+
}>
|
|
97
|
+
> => {
|
|
98
|
+
const parameters = new URLSearchParams();
|
|
99
|
+
parameters.set('NumRows', String(this.#table.rows));
|
|
100
|
+
parameters.set(
|
|
101
|
+
'Filter',
|
|
102
|
+
`${this.#table.dateField}>=${latestOffset.rawTimestamp}`,
|
|
103
|
+
);
|
|
104
|
+
parameters.set('FieldList', `${this.#table.dateField},${this.#fieldsList}`);
|
|
105
|
+
|
|
106
|
+
try {
|
|
107
|
+
const response = await this.#httpClient.get<
|
|
108
|
+
FetchDataResponse<{
|
|
109
|
+
[key: string]: string | number | boolean;
|
|
110
|
+
}>
|
|
111
|
+
>(
|
|
112
|
+
`/web/v3/MKG/Documents/${this.#tableIdentifier}?${parameters.toString()}`,
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
return (
|
|
116
|
+
response.data?.response?.ResultData?.[0]?.[this.#tableIdentifier] ?? []
|
|
117
|
+
);
|
|
118
|
+
} catch (error: HttpError | unknown) {
|
|
119
|
+
const logMessage = `[MKG] Failed to fetch data from table "${this.#tableIdentifier}": (${(error as HttpError)?.status}) ${(error as HttpError)?.error ?? (error as Error)?.message}`;
|
|
120
|
+
this.#sdk.logger.error(logMessage);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return [];
|
|
124
|
+
};
|
|
125
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { MKG_TABLE_ARTG } from './artg';
|
|
2
|
+
import { MKG_TABLE_ARTI } from './arti';
|
|
3
|
+
import { MkgTable } from './base/table';
|
|
4
|
+
import { MKG_TABLE_BWRG } from './bwrg';
|
|
5
|
+
import { MKG_TABLE_BWRK } from './bwrk';
|
|
6
|
+
import { MKG_TABLE_CLCH } from './clch';
|
|
7
|
+
import { MKG_TABLE_DEBI } from './debi';
|
|
8
|
+
import { MKG_TABLE_MAGL } from './magl';
|
|
9
|
+
import { MKG_TABLE_MAGZ } from './magz';
|
|
10
|
+
import { MKG_TABLE_MEDW } from './medw';
|
|
11
|
+
import { MKG_TABLE_PARL } from './parl';
|
|
12
|
+
import { MKG_TABLE_PLNB } from './plnb';
|
|
13
|
+
import { MKG_TABLE_PRBV } from './prbv';
|
|
14
|
+
import { MKG_TABLE_PRDH } from './prdh';
|
|
15
|
+
import { MKG_TABLE_PRDR } from './prdr';
|
|
16
|
+
import { MKG_TABLE_PRMV } from './prmv';
|
|
17
|
+
import { MKG_TABLE_RELA } from './rela';
|
|
18
|
+
import { MKG_TABLE_RGRS } from './rgrs';
|
|
19
|
+
import { MKG_TABLE_RSRC } from './rsrc';
|
|
20
|
+
import { MKG_TABLE_RSRD } from './rsrd';
|
|
21
|
+
import { MKG_TABLE_RSRG } from './rsrg';
|
|
22
|
+
import { MKG_TABLE_STLH } from './stlh';
|
|
23
|
+
import { MKG_TABLE_STLM } from './stlm';
|
|
24
|
+
import { MKG_TABLE_STLR } from './stlr';
|
|
25
|
+
import { MKG_TABLE_VRDG } from './vrdg';
|
|
26
|
+
|
|
27
|
+
const tables = [
|
|
28
|
+
MKG_TABLE_RELA,
|
|
29
|
+
MKG_TABLE_DEBI,
|
|
30
|
+
MKG_TABLE_MEDW,
|
|
31
|
+
MKG_TABLE_ARTI,
|
|
32
|
+
MKG_TABLE_RSRC,
|
|
33
|
+
MKG_TABLE_RSRD,
|
|
34
|
+
MKG_TABLE_RSRG,
|
|
35
|
+
MKG_TABLE_MAGZ,
|
|
36
|
+
MKG_TABLE_MAGL,
|
|
37
|
+
MKG_TABLE_STLH,
|
|
38
|
+
MKG_TABLE_STLR,
|
|
39
|
+
MKG_TABLE_STLM,
|
|
40
|
+
MKG_TABLE_PRDH,
|
|
41
|
+
MKG_TABLE_BWRK,
|
|
42
|
+
MKG_TABLE_BWRG,
|
|
43
|
+
MKG_TABLE_CLCH,
|
|
44
|
+
MKG_TABLE_VRDG,
|
|
45
|
+
MKG_TABLE_RGRS,
|
|
46
|
+
MKG_TABLE_PLNB,
|
|
47
|
+
MKG_TABLE_ARTG,
|
|
48
|
+
MKG_TABLE_PRDR,
|
|
49
|
+
MKG_TABLE_PRMV,
|
|
50
|
+
MKG_TABLE_PRBV,
|
|
51
|
+
MKG_TABLE_PARL,
|
|
52
|
+
];
|
|
53
|
+
|
|
54
|
+
export const MKG_TABLES: { [identifier: string]: MkgTable } = tables.reduce(
|
|
55
|
+
(acc, table) => {
|
|
56
|
+
acc[table.identifier] = table;
|
|
57
|
+
return acc;
|
|
58
|
+
},
|
|
59
|
+
{} as { [identifier: string]: MkgTable },
|
|
60
|
+
);
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { MkgTable } from './base/table';
|
|
2
|
+
|
|
3
|
+
export const MKG_TABLE_ARTI = new MkgTable({
|
|
4
|
+
identifier: 'arti',
|
|
5
|
+
interval: 300,
|
|
6
|
+
fields: [
|
|
7
|
+
'arti_parameter_2',
|
|
8
|
+
'arti_prijs_vast_man',
|
|
9
|
+
'arti_seriegrootte',
|
|
10
|
+
'arti_vrij_memo_1',
|
|
11
|
+
'arti_bestellen',
|
|
12
|
+
'arti_btw_aanpasbaar',
|
|
13
|
+
'arti_vrij_datum_1',
|
|
14
|
+
'arti_eenh_uitgifte',
|
|
15
|
+
'arti_eenh_prijs_inkoop',
|
|
16
|
+
'arti_partij_per_1',
|
|
17
|
+
'arti_partij',
|
|
18
|
+
'arti_voorraad_waarde_mach',
|
|
19
|
+
'arti_parameter_4',
|
|
20
|
+
'arti_eenh_ontvangst',
|
|
21
|
+
'arti_prijs_vast_mat',
|
|
22
|
+
'arti_verh_tijd_aantal_grp',
|
|
23
|
+
'arti_voorraad_aantal',
|
|
24
|
+
'arti_bestel_freq_eenh',
|
|
25
|
+
'arti_vrij_datum_4',
|
|
26
|
+
'arti_eenh_vrk',
|
|
27
|
+
'arti_trans_eenh',
|
|
28
|
+
'arti_kosten_artikel',
|
|
29
|
+
'arti_verh_tijd_aantal_vrd',
|
|
30
|
+
'arti_verh_volume_aantal_grp',
|
|
31
|
+
'arti_memo_verkoop_intern',
|
|
32
|
+
'arti_verh_volume_aantal_vrd',
|
|
33
|
+
'arti_vrij_memo_2',
|
|
34
|
+
'arti_zoeknaam',
|
|
35
|
+
'arti_blok_verkoop',
|
|
36
|
+
'arti_verh_aantal_aantal_vrd',
|
|
37
|
+
'arti_actief',
|
|
38
|
+
'arti_bestelcode',
|
|
39
|
+
'arti_locatie',
|
|
40
|
+
'arti_prijs_netto_mat',
|
|
41
|
+
'arti_prijs_vast',
|
|
42
|
+
'arti_vrij_veld_1',
|
|
43
|
+
'arti_parameter_1',
|
|
44
|
+
'arti_vrij_datum_2',
|
|
45
|
+
'arti_gewicht_per_m',
|
|
46
|
+
'arti_memo_inkoop_extern',
|
|
47
|
+
'arti_inkoopofferte',
|
|
48
|
+
'arti_prijs_gemiddeld_mat',
|
|
49
|
+
'arti_dienst_verkoop',
|
|
50
|
+
'arti_oms_2',
|
|
51
|
+
'arti_levertijd_inkoop',
|
|
52
|
+
'arti_verh_tijd_eenh_grp',
|
|
53
|
+
'arti_prijs_netto_uitb',
|
|
54
|
+
'arti_oppervlakte',
|
|
55
|
+
'arti_voorraadsysteem',
|
|
56
|
+
'arti_kostprijssysteem',
|
|
57
|
+
'arti_niet_autores',
|
|
58
|
+
'arti_wvp_obv_gvp',
|
|
59
|
+
'arti_vrij_memo_5',
|
|
60
|
+
'arti_prijs_inkoop',
|
|
61
|
+
'arti_levertijd_productie',
|
|
62
|
+
'arti_verh_gewicht_aantal_grp',
|
|
63
|
+
'arti_verh_gewicht_eenh_grp',
|
|
64
|
+
'arti_vrij_veld_2',
|
|
65
|
+
'arti_prijs_gemiddeld_mach',
|
|
66
|
+
'arti_lijst_3',
|
|
67
|
+
'arti_verh_gewicht_aantal_vrd',
|
|
68
|
+
'arti_parameter_3',
|
|
69
|
+
'arti_lijst_1',
|
|
70
|
+
'arti_prijs_vast_mach',
|
|
71
|
+
'arti_vrij_veld_5',
|
|
72
|
+
'arti_ict_fact_verkoop',
|
|
73
|
+
'arti_verh_lengte_aantal_vrd',
|
|
74
|
+
'arti_backflush',
|
|
75
|
+
'arti_vrij_datum_3',
|
|
76
|
+
'arti_vrd_aanvullen_tot',
|
|
77
|
+
'arti_inkoop_artikel',
|
|
78
|
+
'arti_verh_rest_aantal_grp',
|
|
79
|
+
'arti_eenh_vrd',
|
|
80
|
+
'arti_prijs_vast_uitb',
|
|
81
|
+
'arti_trans_gewicht',
|
|
82
|
+
'arti_memo_inkoop_intern',
|
|
83
|
+
'arti_vrij_memo_3',
|
|
84
|
+
'arti_prijs_netto',
|
|
85
|
+
'arti_mat_lengte',
|
|
86
|
+
'arti_bestelhoeveelheid',
|
|
87
|
+
'arti_eenh_bestelling',
|
|
88
|
+
'arti_verh_oppv_eenh_grp',
|
|
89
|
+
'arti_voorraad_artikel',
|
|
90
|
+
'arti_backflush_uitval',
|
|
91
|
+
'arti_lijst_9',
|
|
92
|
+
'arti_vrij_datum_5',
|
|
93
|
+
'arti_verh_oppv_aantal_grp',
|
|
94
|
+
'arti_prijs_gemiddeld_uitb',
|
|
95
|
+
'arti_prijs_verkoop_eenm',
|
|
96
|
+
'arti_oms_3',
|
|
97
|
+
'arti_oms_1',
|
|
98
|
+
],
|
|
99
|
+
});
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { MkgTableInterface } from '../../types';
|
|
2
|
+
|
|
3
|
+
type MkgActionMethod = 'GET' | 'POST' | 'PUT' | 'DELETE';
|
|
4
|
+
|
|
5
|
+
export interface MkgActionInterface {
|
|
6
|
+
identifier: string;
|
|
7
|
+
|
|
8
|
+
method: MkgActionMethod;
|
|
9
|
+
|
|
10
|
+
fields: Array<string>;
|
|
11
|
+
|
|
12
|
+
optionalFields?: Array<string>;
|
|
13
|
+
|
|
14
|
+
path?: (inputData: Record<string, unknown>) => string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export class MkgAction implements MkgActionInterface {
|
|
18
|
+
readonly identifier: string;
|
|
19
|
+
|
|
20
|
+
readonly method: MkgActionMethod;
|
|
21
|
+
|
|
22
|
+
readonly fields: Array<string>;
|
|
23
|
+
|
|
24
|
+
readonly optionalFields: Array<string>;
|
|
25
|
+
|
|
26
|
+
readonly path: (inputData: Record<string, unknown>) => string;
|
|
27
|
+
|
|
28
|
+
#table!: MkgTableInterface;
|
|
29
|
+
|
|
30
|
+
constructor(params: MkgActionInterface) {
|
|
31
|
+
this.identifier = params.identifier;
|
|
32
|
+
this.method = params.method;
|
|
33
|
+
this.fields = params.fields;
|
|
34
|
+
this.optionalFields = params.optionalFields ?? [];
|
|
35
|
+
this.path = params.path ?? ((): string => this.#table.identifier);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
withParentTable(table: MkgTableInterface): MkgAction {
|
|
39
|
+
const action = new MkgAction(this);
|
|
40
|
+
action.#table = table;
|
|
41
|
+
|
|
42
|
+
return action;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
fieldSet(inputData: Record<string, unknown>): Record<string, unknown> {
|
|
46
|
+
const fieldData = new Map<string, unknown>();
|
|
47
|
+
|
|
48
|
+
this.fields.forEach((field) => {
|
|
49
|
+
// eslint-disable-next-line security/detect-object-injection
|
|
50
|
+
const inputDataValue = inputData[field];
|
|
51
|
+
if (!inputDataValue) {
|
|
52
|
+
throw new Error(
|
|
53
|
+
`Missing required field '${field}' for action '${this.identifier}'`,
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
fieldData.set(field, inputDataValue);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
this.optionalFields.forEach((field) => {
|
|
61
|
+
// eslint-disable-next-line security/detect-object-injection
|
|
62
|
+
const inputDataValue = inputData[field];
|
|
63
|
+
if (inputDataValue) {
|
|
64
|
+
fieldData.set(field, inputDataValue);
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
return Object.fromEntries(fieldData.entries());
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DEFAULT_DATE_FIELD,
|
|
3
|
+
DEFAULT_INTERVAL,
|
|
4
|
+
DEFAULT_NUM_ROWS,
|
|
5
|
+
DEFAULT_ROW_KEY_FIELD,
|
|
6
|
+
MkgTableInterface,
|
|
7
|
+
TableConfig,
|
|
8
|
+
} from '../../types';
|
|
9
|
+
|
|
10
|
+
import { MkgAction } from './action';
|
|
11
|
+
|
|
12
|
+
export class MkgTable implements MkgTableInterface {
|
|
13
|
+
readonly identifier: string;
|
|
14
|
+
|
|
15
|
+
readonly fields: Array<string>;
|
|
16
|
+
|
|
17
|
+
readonly immediate: boolean;
|
|
18
|
+
|
|
19
|
+
readonly interval: number;
|
|
20
|
+
|
|
21
|
+
readonly identifierField: string;
|
|
22
|
+
|
|
23
|
+
readonly dateField: string;
|
|
24
|
+
|
|
25
|
+
readonly rows: number;
|
|
26
|
+
|
|
27
|
+
readonly actions: Array<MkgAction>;
|
|
28
|
+
|
|
29
|
+
constructor(params: MkgTableInterface, actions: Array<MkgAction> = []) {
|
|
30
|
+
this.identifier = params.identifier;
|
|
31
|
+
this.fields = params.fields;
|
|
32
|
+
this.immediate = params.immediate !== false;
|
|
33
|
+
this.interval =
|
|
34
|
+
params.interval ?? (this.fields.length > 0 ? DEFAULT_INTERVAL : 0);
|
|
35
|
+
this.identifierField = params.identifierField ?? DEFAULT_ROW_KEY_FIELD;
|
|
36
|
+
this.dateField = params.dateField ?? DEFAULT_DATE_FIELD;
|
|
37
|
+
this.rows = params.rows ?? DEFAULT_NUM_ROWS;
|
|
38
|
+
this.actions = actions.map((action) => action.withParentTable(this));
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
cloneFromTableConfig(tableConfig: TableConfig | true): MkgTable {
|
|
42
|
+
if (tableConfig === true || tableConfig.fields === undefined) {
|
|
43
|
+
return this;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return new MkgTable({
|
|
47
|
+
...this,
|
|
48
|
+
fields: this.fields.filter((field) =>
|
|
49
|
+
tableConfig.fields?.includes(field),
|
|
50
|
+
),
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
action(identifier: string): MkgAction | undefined {
|
|
55
|
+
return this.actions.find((a) => a.identifier === identifier);
|
|
56
|
+
}
|
|
57
|
+
}
|