@contrail/flexplm 1.3.2-alpha.30ca8bf → 1.3.2-alpha.3ffe557

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 (113) hide show
  1. package/lib/cli/commands/compile.d.ts +4 -0
  2. package/lib/cli/commands/compile.js +73 -0
  3. package/lib/cli/commands/compile.spec.d.ts +1 -0
  4. package/lib/cli/commands/compile.spec.js +80 -0
  5. package/lib/cli/commands/create.d.ts +5 -0
  6. package/lib/cli/commands/create.js +77 -0
  7. package/lib/cli/commands/create.spec.d.ts +1 -0
  8. package/lib/cli/commands/create.spec.js +78 -0
  9. package/lib/cli/commands/upload.d.ts +17 -0
  10. package/lib/cli/commands/upload.js +228 -0
  11. package/lib/cli/commands/upload.spec.d.ts +1 -0
  12. package/lib/cli/commands/upload.spec.js +88 -0
  13. package/lib/cli/index.d.ts +5 -0
  14. package/lib/cli/index.js +70 -0
  15. package/lib/cli/index.spec.d.ts +1 -0
  16. package/lib/cli/index.spec.js +85 -0
  17. package/lib/cli/template/mapping-template.ts.template +62 -0
  18. package/lib/entity-processor/base-entity-processor.d.ts +47 -10
  19. package/lib/entity-processor/base-entity-processor.js +53 -34
  20. package/lib/entity-processor/base-entity-processor.spec.js +1 -191
  21. package/lib/index.d.ts +1 -0
  22. package/lib/index.js +1 -0
  23. package/lib/interfaces/mapping-file.d.ts +460 -0
  24. package/lib/interfaces/mapping-file.js +2 -0
  25. package/lib/publish/base-process-publish-assortment.d.ts +25 -0
  26. package/lib/publish/base-process-publish-assortment.js +60 -6
  27. package/lib/publish/base-process-publish-assortment.spec.js +22 -4
  28. package/lib/publish/mockData.js +5 -0
  29. package/lib/transform/identifier-conversion-spec-mockData.js +34 -6
  30. package/lib/transform/identifier-conversion.d.ts +36 -0
  31. package/lib/transform/identifier-conversion.js +36 -0
  32. package/lib/transform/identifier-conversion.spec.js +4 -0
  33. package/lib/util/config-defaults.d.ts +0 -1
  34. package/lib/util/config-defaults.js +3 -3
  35. package/lib/util/config-defaults.spec.js +9 -32
  36. package/lib/util/data-converter-spec-mockData.js +17 -3
  37. package/lib/util/data-converter.d.ts +97 -0
  38. package/lib/util/data-converter.js +133 -1
  39. package/lib/util/data-converter.spec.js +68 -0
  40. package/lib/util/error-response-object.d.ts +5 -0
  41. package/lib/util/error-response-object.js +7 -0
  42. package/lib/util/event-short-message-status.js +1 -0
  43. package/lib/util/federation.js +8 -0
  44. package/lib/util/flexplm-connect.d.ts +7 -0
  45. package/lib/util/flexplm-connect.js +14 -0
  46. package/lib/util/logger-config.js +1 -0
  47. package/lib/util/map-util-spec-mockData.js +17 -3
  48. package/lib/util/map-utils.d.ts +27 -0
  49. package/lib/util/map-utils.js +27 -0
  50. package/lib/util/thumbnail-util.d.ts +21 -0
  51. package/lib/util/thumbnail-util.js +28 -1
  52. package/lib/util/thumbnail-util.spec.js +6 -0
  53. package/lib/util/type-conversion-utils-spec-mockData.js +3 -4
  54. package/lib/util/type-conversion-utils.d.ts +140 -1
  55. package/lib/util/type-conversion-utils.js +143 -16
  56. package/lib/util/type-conversion-utils.spec.js +0 -59
  57. package/lib/util/type-defaults.d.ts +58 -0
  58. package/lib/util/type-defaults.js +58 -0
  59. package/lib/util/type-defaults.spec.js +5 -5
  60. package/lib/util/type-utils.d.ts +21 -0
  61. package/lib/util/type-utils.js +23 -0
  62. package/lib/util/type-utils.spec.js +2 -0
  63. package/package.json +21 -6
  64. package/scripts/copy-template.js +10 -0
  65. package/.github/pull_request_template.md +0 -31
  66. package/.github/workflows/flexplm-lib.yml +0 -27
  67. package/.github/workflows/publish-to-npm.yml +0 -121
  68. package/CHANGELOG.md +0 -36
  69. package/publish.bat +0 -5
  70. package/publish.sh +0 -5
  71. package/src/entity-processor/base-entity-processor.spec.ts +0 -689
  72. package/src/entity-processor/base-entity-processor.ts +0 -583
  73. package/src/flexplm-request.ts +0 -28
  74. package/src/flexplm-utils.spec.ts +0 -27
  75. package/src/flexplm-utils.ts +0 -29
  76. package/src/index.ts +0 -22
  77. package/src/interfaces/interfaces.ts +0 -122
  78. package/src/interfaces/item-family-changes.ts +0 -67
  79. package/src/interfaces/publish-change-data.ts +0 -43
  80. package/src/publish/base-process-publish-assortment-callback.ts +0 -50
  81. package/src/publish/base-process-publish-assortment.spec.ts +0 -1992
  82. package/src/publish/base-process-publish-assortment.ts +0 -1134
  83. package/src/publish/mockData.ts +0 -4561
  84. package/src/transform/identifier-conversion-spec-mockData.ts +0 -496
  85. package/src/transform/identifier-conversion.spec.ts +0 -354
  86. package/src/transform/identifier-conversion.ts +0 -282
  87. package/src/util/config-defaults.spec.ts +0 -392
  88. package/src/util/config-defaults.ts +0 -97
  89. package/src/util/data-converter-spec-mockData.ts +0 -231
  90. package/src/util/data-converter.spec.ts +0 -1041
  91. package/src/util/data-converter.ts +0 -762
  92. package/src/util/error-response-object.spec.ts +0 -116
  93. package/src/util/error-response-object.ts +0 -50
  94. package/src/util/event-short-message-status.ts +0 -22
  95. package/src/util/federation.ts +0 -172
  96. package/src/util/flexplm-connect.spec.ts +0 -132
  97. package/src/util/flexplm-connect.ts +0 -208
  98. package/src/util/logger-config.ts +0 -20
  99. package/src/util/map-util-spec-mockData.ts +0 -231
  100. package/src/util/map-utils.spec.ts +0 -103
  101. package/src/util/map-utils.ts +0 -41
  102. package/src/util/mockData.ts +0 -101
  103. package/src/util/thumbnail-util.spec.ts +0 -508
  104. package/src/util/thumbnail-util.ts +0 -272
  105. package/src/util/type-conversion-utils-spec-mockData.ts +0 -272
  106. package/src/util/type-conversion-utils.spec.ts +0 -1031
  107. package/src/util/type-conversion-utils.ts +0 -490
  108. package/src/util/type-defaults.spec.ts +0 -669
  109. package/src/util/type-defaults.ts +0 -281
  110. package/src/util/type-utils.spec.ts +0 -227
  111. package/src/util/type-utils.ts +0 -144
  112. package/tsconfig.json +0 -24
  113. package/tslint.json +0 -57
@@ -0,0 +1,70 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.main = exports.Cli = void 0;
5
+ const create_1 = require("./commands/create");
6
+ const compile_1 = require("./commands/compile");
7
+ const upload_1 = require("./commands/upload");
8
+ const USAGE = `Usage: flexplm-mapping <command> [args]
9
+
10
+ Commands:
11
+ create Scaffold a new mapping .ts file in the current directory
12
+ compile <path.ts> Transpile a mapping .ts file to .js alongside it
13
+ upload <path.ts> [opts] Compile a mapping .ts file and upload the resulting .js to VibeIQ
14
+
15
+ Upload options:
16
+ -m <message> Git commit message (prompted if omitted)
17
+ -b <branch> Create a new git branch before committing
18
+ --skip-git Skip the post-upload git commit (default: commit)
19
+
20
+ Environment (upload):
21
+ CONTRAIL_CLI_EMAIL VibeIQ user email
22
+ CONTRAIL_CLI_PASSWORD VibeIQ user password
23
+ `;
24
+ class Cli {
25
+ async main() {
26
+ const [, , command, ...rest] = process.argv;
27
+ switch (command) {
28
+ case 'create':
29
+ await new create_1.CreateCommand().run();
30
+ return;
31
+ case 'compile':
32
+ if (!rest[0]) {
33
+ console.error('compile: missing <path.ts> argument');
34
+ console.error(USAGE);
35
+ process.exit(1);
36
+ }
37
+ await new compile_1.CompileCommand().run(rest[0]);
38
+ return;
39
+ case 'upload':
40
+ if (!rest[0]) {
41
+ console.error('upload: missing <path.ts> argument');
42
+ console.error(USAGE);
43
+ process.exit(1);
44
+ }
45
+ await new upload_1.UploadCommand().run(rest);
46
+ return;
47
+ case undefined:
48
+ case '-h':
49
+ case '--help':
50
+ case 'help':
51
+ console.log(USAGE);
52
+ return;
53
+ default:
54
+ console.error(`Unknown command: ${command}`);
55
+ console.error(USAGE);
56
+ process.exit(1);
57
+ }
58
+ }
59
+ }
60
+ exports.Cli = Cli;
61
+ function main() {
62
+ return new Cli().main();
63
+ }
64
+ exports.main = main;
65
+ if (require.main === module) {
66
+ main().catch((err) => {
67
+ console.error(err && err.message ? err.message : err);
68
+ process.exit(1);
69
+ });
70
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,85 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const createRunMock = jest.fn().mockResolvedValue(undefined);
4
+ const compileRunMock = jest.fn().mockResolvedValue(undefined);
5
+ const uploadRunMock = jest.fn().mockResolvedValue(undefined);
6
+ jest.mock('./commands/create', () => ({
7
+ CreateCommand: jest.fn().mockImplementation(() => ({ run: createRunMock })),
8
+ }));
9
+ jest.mock('./commands/compile', () => ({
10
+ CompileCommand: jest.fn().mockImplementation(() => ({ run: compileRunMock })),
11
+ }));
12
+ jest.mock('./commands/upload', () => ({
13
+ UploadCommand: jest.fn().mockImplementation(() => ({ run: uploadRunMock })),
14
+ }));
15
+ const index_1 = require("./index");
16
+ describe('cli main dispatcher', () => {
17
+ let originalArgv;
18
+ let logSpy;
19
+ let errorSpy;
20
+ let exitSpy;
21
+ beforeEach(() => {
22
+ originalArgv = process.argv;
23
+ createRunMock.mockClear();
24
+ compileRunMock.mockClear();
25
+ uploadRunMock.mockClear();
26
+ logSpy = jest.spyOn(console, 'log').mockImplementation(() => { });
27
+ errorSpy = jest.spyOn(console, 'error').mockImplementation(() => { });
28
+ exitSpy = jest.spyOn(process, 'exit').mockImplementation(((code) => {
29
+ throw new Error(`__EXIT__:${code}`);
30
+ }));
31
+ });
32
+ afterEach(() => {
33
+ process.argv = originalArgv;
34
+ logSpy.mockRestore();
35
+ errorSpy.mockRestore();
36
+ exitSpy.mockRestore();
37
+ });
38
+ function setArgv(...args) {
39
+ process.argv = ['node', 'cli', ...args];
40
+ }
41
+ it('dispatches the create command', async () => {
42
+ setArgv('create');
43
+ await (0, index_1.main)();
44
+ expect(createRunMock).toHaveBeenCalledTimes(1);
45
+ expect(compileRunMock).not.toHaveBeenCalled();
46
+ expect(uploadRunMock).not.toHaveBeenCalled();
47
+ });
48
+ it('dispatches the compile command with its argument', async () => {
49
+ setArgv('compile', 'mapping.ts');
50
+ await (0, index_1.main)();
51
+ expect(compileRunMock).toHaveBeenCalledWith('mapping.ts');
52
+ });
53
+ it('exits when compile is missing its argument', async () => {
54
+ setArgv('compile');
55
+ await expect((0, index_1.main)()).rejects.toThrow('__EXIT__:1');
56
+ expect(compileRunMock).not.toHaveBeenCalled();
57
+ expect(errorSpy).toHaveBeenCalledWith(expect.stringMatching(/missing <path\.ts>/));
58
+ });
59
+ it('dispatches the upload command and forwards remaining args', async () => {
60
+ setArgv('upload', 'mapping.ts', '-m', 'msg', '--skip-git');
61
+ await (0, index_1.main)();
62
+ expect(uploadRunMock).toHaveBeenCalledWith(['mapping.ts', '-m', 'msg', '--skip-git']);
63
+ });
64
+ it('exits when upload is missing its argument', async () => {
65
+ setArgv('upload');
66
+ await expect((0, index_1.main)()).rejects.toThrow('__EXIT__:1');
67
+ expect(uploadRunMock).not.toHaveBeenCalled();
68
+ expect(errorSpy).toHaveBeenCalledWith(expect.stringMatching(/missing <path\.ts>/));
69
+ });
70
+ it.each(['help', '-h', '--help'])('prints usage for %s', async (helpFlag) => {
71
+ setArgv(helpFlag);
72
+ await (0, index_1.main)();
73
+ expect(logSpy).toHaveBeenCalledWith(expect.stringMatching(/Usage: flexplm-mapping/));
74
+ });
75
+ it('prints usage when no command is provided', async () => {
76
+ setArgv();
77
+ await (0, index_1.main)();
78
+ expect(logSpy).toHaveBeenCalledWith(expect.stringMatching(/Usage: flexplm-mapping/));
79
+ });
80
+ it('exits on an unknown command', async () => {
81
+ setArgv('bogus');
82
+ await expect((0, index_1.main)()).rejects.toThrow('__EXIT__:1');
83
+ expect(errorSpy).toHaveBeenCalledWith(expect.stringMatching(/Unknown command: bogus/));
84
+ });
85
+ });
@@ -0,0 +1,62 @@
1
+ import type { MappingFile } from '@contrail/flexplm';
2
+
3
+ export const mapping: MappingFile = {
4
+ orgInfo: {
5
+ appIdentifier: '@vibeiq/flexplm-connector',
6
+ orgName: '<ORG_NAME>',
7
+ },
8
+ typeConversion: {
9
+ vibe2flex: {},
10
+ flex2vibe: {},
11
+ },
12
+ LCSSeason: {
13
+ vibeOwningKeys: ['flexPLMSeasonName'],
14
+ vibe2flex: {
15
+ transformOrder: [{ processor: 'REKEY', rekeyDelete: true, rekeyTransformersKey: 'rekey' }],
16
+ rekey: {
17
+ seasonName: 'flexPLMSeasonName',
18
+ },
19
+ },
20
+ flex2vibe: {
21
+ transformOrder: [{ processor: 'REKEY', rekeyDelete: true, rekeyTransformersKey: 'rekey' }],
22
+ rekey: {
23
+ flexPLMSeasonName: 'seasonName',
24
+ },
25
+ },
26
+ },
27
+ LCSProduct: {
28
+ vibeOwningKeys: ['itemNumber'],
29
+ vibe2flex: {
30
+ transformOrder: [{ processor: 'REKEY', rekeyDelete: true, rekeyTransformersKey: 'rekey' }],
31
+ rekey: {
32
+ vibeIQIdentifier: 'itemNumber',
33
+ productName: 'name',
34
+ },
35
+ },
36
+ flex2vibe: {
37
+ transformOrder: [{ processor: 'REKEY', rekeyDelete: true, rekeyTransformersKey: 'rekey' }],
38
+ rekey: {
39
+ itemNumber: 'vibeIQIdentifier',
40
+ name: 'productName',
41
+ },
42
+ },
43
+ },
44
+ LCSSKU: {
45
+ vibeOwningKeys: ['itemNumber'],
46
+ vibe2flex: {
47
+ transformOrder: [{ processor: 'REKEY', rekeyDelete: true, rekeyTransformersKey: 'rekey' }],
48
+ rekey: {
49
+ vibeIQIdentifier: 'itemNumber',
50
+ skuName: 'optionName',
51
+ },
52
+ },
53
+ flex2vibe: {
54
+ transformOrder: [{ processor: 'REKEY', rekeyDelete: true, rekeyTransformersKey: 'rekey' }],
55
+ rekey: {
56
+ itemNumber: 'vibeIQIdentifier',
57
+ optionName: 'skuName',
58
+ },
59
+ },
60
+ },
61
+
62
+ };
@@ -19,18 +19,36 @@ export declare abstract class BaseEntityProcessor {
19
19
  inbound(event: EntityPayloadType): Promise<any>;
20
20
  handleIncomingUpsert(event: EntityPayloadType): Promise<any>;
21
21
  getInboundStatusMessage(statusObject: any): string;
22
- getIdentityEntity(params: {
23
- poolKey: string;
24
- propertyName: string;
25
- propertyValue: string;
26
- }): Promise<any | undefined>;
27
- getEntityUsingIdentityService(params: {
28
- poolKey: string;
29
- propertyName: string;
30
- propertyValue: string;
31
- }): Promise<any | undefined>;
22
+ /**This will query for the entity, and handle post-processing
23
+ * of any critieria that is defined at the sub-type level.
24
+ * Because sub-type criteria can't be used in the search done
25
+ * on the server. This is expected to be called by getIncomingEntity().
26
+ *
27
+ * @param entityType: the root type of the entity
28
+ * @param entityTypePath: the full type path of the entity. Ex: custom-entity:sample
29
+ * @param propertyCriteria: all the criteria to search for the entity
30
+ * @returns the entities that match the criteria
31
+ */
32
32
  queryEntityWithSubTypeCriteria(entityType: string, entityTypePath: string, propertyCriteria: any): Promise<any[]>;
33
+ /** This is to get the criteria for the entity that is being processed.
34
+ * This is to be overridden for item & project-item because of the need for
35
+ * setting the roles criteria.
36
+ *
37
+ * @param entityType: the root type of the entity
38
+ * @param entityTypePath: the full type path of the entity. Ex: custom-entity:sample
39
+ * @param propertyCriteria: all the criteria to search for the entity
40
+ * @returns the criteria for the entity
41
+ */
33
42
  getCriteriaForEntity(entityType: string, entityTypePath: string, propertyCriteria: any): Promise<any>;
43
+ /** This is to get the properties that are owned by the root type
44
+ * This needs to be overridded for multi-level types, such as item
45
+ * and project-item. And for those types, the propertyCriteria
46
+ * will be needed to determine the correct level.
47
+ *
48
+ * @param rootType: the full root type entity for the processed entity
49
+ * @param propertyCriteria: the criteria to determine the correct level (unused for single level types)
50
+ * @returns: string[] of the property keys
51
+ */
34
52
  getRootTypePropertyKeys(rootType: any, propertyCriteria?: any): string[];
35
53
  handleIncomingDelete(event: any): Promise<void>;
36
54
  getTransformedData(event: any): Promise<any>;
@@ -46,7 +64,26 @@ export declare abstract class BaseEntityProcessor {
46
64
  getOutboundEntityUpdates(event: any, flexResponse: any): Promise<any>;
47
65
  handleOutgoingDelete(entityType: any, event: any): Promise<void>;
48
66
  protected abstract getOutgoingUpsertPayload(entityType: any, event: any): Promise<EntityPayloadType>;
67
+ /** Create a new event-workflow-request to rerun sending the entity to FlexPLM
68
+ * The event must contain any information needed to ensure it is put in the correct queue for the entity
69
+ *
70
+ * @param triggerKey Ex: event.entityType + '|sendUpsertToFlexPLM'
71
+ * @param event
72
+ * @returns
73
+ */
49
74
  protected triggerNewEvent(triggerKey: string, event: any): Promise<any>;
75
+ /** Sends the current state of the entity to FlexPLM.
76
+ * So any changes made in Vibe between the event being generated and the event being processed are sent to FlexPLM.
77
+ *
78
+ * @param event must contain entityType, id; which are used to query for the entity
79
+ * @returns results of sending the entity to FlexPLM
80
+ */
50
81
  protected sendUpsertToFlexPLM(event: any): Promise<any>;
82
+ /** Generates the payload to send to FlexPLM, based on the current state of the entity.
83
+ * The current state of the entity are used as the newData and oldData; which is passed
84
+ * to getOutgoingUpsertPayload to generate the payload.
85
+ * @param event information about the item to send to FlexPLM
86
+ * @returns The payload to send to FlexPLM
87
+ */
51
88
  protected getEntityCurrentStateUpsertPayload(event: any): Promise<EntityPayloadType>;
52
89
  }
@@ -23,6 +23,7 @@ class BaseEntityProcessor {
23
23
  this.entities = new sdk_1.Entities();
24
24
  this.orgSlug = this.config?.orgSlug || 'unset-orgSlug';
25
25
  }
26
+ // inbound
26
27
  async inbound(event) {
27
28
  const eventType = event.eventType;
28
29
  console.log(`inbound entity: ${eventType}:${event.objectClass}`);
@@ -42,6 +43,7 @@ class BaseEntityProcessor {
42
43
  async handleIncomingUpsert(event) {
43
44
  const inboundData = await this.getTransformedData(event);
44
45
  const incomingEntityResponse = await this.getIncomingEntity(event, inboundData);
46
+ // This case means there was an early return in the getIncomingEntity method
45
47
  if (incomingEntityResponse.earlyReturn) {
46
48
  const statusMsg = this.getInboundStatusMessage({
47
49
  status: event_short_message_status_1.EventShortMessageStatus.FAILURE,
@@ -136,41 +138,18 @@ class BaseEntityProcessor {
136
138
  + ', federatedId: ' + statusObject.federatedId
137
139
  + ', orgSlug: ' + this.orgSlug;
138
140
  }
139
- async getIdentityEntity(params) {
140
- const { poolKey, propertyName, propertyValue } = params;
141
- if (!poolKey || !propertyName || !propertyValue) {
142
- throw new Error('poolKey, propertyName, and propertyValue must be defined');
143
- }
144
- const identityEntities = await this.entities.get({
145
- entityName: 'identity',
146
- criteria: {
147
- poolKey,
148
- propertyName,
149
- propertyValue
150
- }
151
- });
152
- if (!identityEntities || (Array.isArray(identityEntities) && identityEntities.length === 0)) {
153
- return undefined;
154
- }
155
- if (Array.isArray(identityEntities) && identityEntities.length > 1) {
156
- throw new Error('Multiple identity entities found for poolKey: ' + poolKey + ', ' + propertyName + ': ' + propertyValue);
157
- }
158
- return Array.isArray(identityEntities) ? identityEntities[0] : identityEntities;
159
- }
160
- async getEntityUsingIdentityService(params) {
161
- const identityEntity = await this.getIdentityEntity(params);
162
- if (!identityEntity) {
163
- return undefined;
164
- }
165
- const entityReference = identityEntity.entityReference;
166
- const [entityName, id] = entityReference.split(':');
167
- const entity = await this.entities.get({
168
- entityName,
169
- id
170
- });
171
- return entity;
172
- }
141
+ /**This will query for the entity, and handle post-processing
142
+ * of any critieria that is defined at the sub-type level.
143
+ * Because sub-type criteria can't be used in the search done
144
+ * on the server. This is expected to be called by getIncomingEntity().
145
+ *
146
+ * @param entityType: the root type of the entity
147
+ * @param entityTypePath: the full type path of the entity. Ex: custom-entity:sample
148
+ * @param propertyCriteria: all the criteria to search for the entity
149
+ * @returns the entities that match the criteria
150
+ */
173
151
  async queryEntityWithSubTypeCriteria(entityType, entityTypePath, propertyCriteria) {
152
+ //allCriteria; identifierKeys; entityType; entityTypePath
174
153
  if (!entityType || !entityTypePath) {
175
154
  throw new Error('type and entityTypePath must be defined');
176
155
  }
@@ -181,6 +160,15 @@ class BaseEntityProcessor {
181
160
  const returnedEntities = await this.dc.getAllObjectReferences(entityType, rootTypeCriteria, subTypeCriteria);
182
161
  return returnedEntities;
183
162
  }
163
+ /** This is to get the criteria for the entity that is being processed.
164
+ * This is to be overridden for item & project-item because of the need for
165
+ * setting the roles criteria.
166
+ *
167
+ * @param entityType: the root type of the entity
168
+ * @param entityTypePath: the full type path of the entity. Ex: custom-entity:sample
169
+ * @param propertyCriteria: all the criteria to search for the entity
170
+ * @returns the criteria for the entity
171
+ */
184
172
  async getCriteriaForEntity(entityType, entityTypePath, propertyCriteria) {
185
173
  if (!entityType || !entityTypePath) {
186
174
  throw new Error('type and entityTypePath must be defined');
@@ -205,6 +193,15 @@ class BaseEntityProcessor {
205
193
  }
206
194
  return { rootTypeCriteria, subTypeCriteria };
207
195
  }
196
+ /** This is to get the properties that are owned by the root type
197
+ * This needs to be overridded for multi-level types, such as item
198
+ * and project-item. And for those types, the propertyCriteria
199
+ * will be needed to determine the correct level.
200
+ *
201
+ * @param rootType: the full root type entity for the processed entity
202
+ * @param propertyCriteria: the criteria to determine the correct level (unused for single level types)
203
+ * @returns: string[] of the property keys
204
+ */
208
205
  getRootTypePropertyKeys(rootType, propertyCriteria = null) {
209
206
  const props = rootType['typeProperties'];
210
207
  const rootTypePropertyKeys = props.map(prop => prop.slug);
@@ -237,6 +234,8 @@ class BaseEntityProcessor {
237
234
  async getVibeOwningKeys(entity) {
238
235
  let vibeOwningKeys = [];
239
236
  if (this.transformMapFile && entity) {
237
+ //Technically the transform is flex->vibe. But the vibe entity being updated was passed in,
238
+ // so we use VIBE2FLEX_DIRECTION to get the mapKey
240
239
  const mapKey = await type_conversion_utils_1.TypeConversionUtils.getMapKey(this.transformMapFile, this.mapFileUtil, entity, type_conversion_utils_1.TypeConversionUtils.VIBE2FLEX_DIRECTION);
241
240
  const mapSection = await map_utils_1.MapUtil.getFullMapSection(this.transformMapFile, this.mapFileUtil, mapKey);
242
241
  vibeOwningKeys = mapSection?.vibeOwningKeys || [];
@@ -271,6 +270,7 @@ class BaseEntityProcessor {
271
270
  console.log('updateEntity: ' + JSON.stringify(options));
272
271
  return await new sdk_1.Entities().update(options);
273
272
  }
273
+ // outbound
274
274
  async outbound(event) {
275
275
  const entityType = event.entityType;
276
276
  const eventType = event.eventType;
@@ -347,6 +347,13 @@ class BaseEntityProcessor {
347
347
  async handleOutgoingDelete(entityType, event) {
348
348
  console.warn('delete is not configured', entityType, event.oldData);
349
349
  }
350
+ /** Create a new event-workflow-request to rerun sending the entity to FlexPLM
351
+ * The event must contain any information needed to ensure it is put in the correct queue for the entity
352
+ *
353
+ * @param triggerKey Ex: event.entityType + '|sendUpsertToFlexPLM'
354
+ * @param event
355
+ * @returns
356
+ */
350
357
  async triggerNewEvent(triggerKey, event) {
351
358
  const newEvent = {
352
359
  entityName: 'event-workflow-request',
@@ -358,6 +365,12 @@ class BaseEntityProcessor {
358
365
  const response = await this.entities.create(newEvent);
359
366
  return response;
360
367
  }
368
+ /** Sends the current state of the entity to FlexPLM.
369
+ * So any changes made in Vibe between the event being generated and the event being processed are sent to FlexPLM.
370
+ *
371
+ * @param event must contain entityType, id; which are used to query for the entity
372
+ * @returns results of sending the entity to FlexPLM
373
+ */
361
374
  async sendUpsertToFlexPLM(event) {
362
375
  const payload = await this.getEntityCurrentStateUpsertPayload(event);
363
376
  if (!payload) {
@@ -398,6 +411,12 @@ class BaseEntityProcessor {
398
411
  throw e;
399
412
  }
400
413
  }
414
+ /** Generates the payload to send to FlexPLM, based on the current state of the entity.
415
+ * The current state of the entity are used as the newData and oldData; which is passed
416
+ * to getOutgoingUpsertPayload to generate the payload.
417
+ * @param event information about the item to send to FlexPLM
418
+ * @returns The payload to send to FlexPLM
419
+ */
401
420
  async getEntityCurrentStateUpsertPayload(event) {
402
421
  const id = event.id;
403
422
  if (!id) {
@@ -269,6 +269,7 @@ describe('BaseEntityProcessor', () => {
269
269
  const rootCriteriaResults = Object.assign({}, rootCriteria);
270
270
  const subCriteriaResults = Object.assign({}, subCriteria);
271
271
  const mockGetByRootTypeProperties = jest.spyOn(btep, 'getRootTypePropertyKeys').mockReturnValue(['rootText']);
272
+ // const mockDCgetAllObjectReferences = jest.spyOn(dc, 'getAllObjectReferences').mockReturnValue(Promise.resolve([]));
272
273
  const { rootTypeCriteria, subTypeCriteria } = await btep.getCriteriaForEntity(entityType, entityTypePath, propertyCriteria);
273
274
  expect(mockTypeUtilGetByRootAndPath).toBeCalledTimes(1);
274
275
  expect(mockTypeUtilGetByRootAndPath).toBeCalledWith({ root: entityType });
@@ -394,195 +395,4 @@ describe('BaseEntityProcessor', () => {
394
395
  expect(result).toEqual({ status: 200, data: { message: 'No Changes to persist for entity: existing-1' } });
395
396
  });
396
397
  });
397
- describe('getIdentityEntity', () => {
398
- const config = {};
399
- const mapFileUtil = new transform_data_1.MapFileUtil(new sdk_1.Entities());
400
- const dc = new data_converter_1.DataConverter(config, mapFileUtil);
401
- let btep;
402
- let mockEntitiesGet;
403
- beforeEach(() => {
404
- btep = new TestBaseEntityProcessor(config, dc, mapFileUtil, 'item');
405
- mockEntitiesGet = jest.fn();
406
- btep.entities = { get: mockEntitiesGet };
407
- });
408
- it('should throw error when poolKey is missing', async () => {
409
- await expect(btep.getIdentityEntity({
410
- poolKey: '',
411
- propertyName: 'itemNumber',
412
- propertyValue: '12345'
413
- })).rejects.toThrow('poolKey, propertyName, and propertyValue must be defined');
414
- });
415
- it('should throw error when propertyName is missing', async () => {
416
- await expect(btep.getIdentityEntity({
417
- poolKey: 'item',
418
- propertyName: '',
419
- propertyValue: '12345'
420
- })).rejects.toThrow('poolKey, propertyName, and propertyValue must be defined');
421
- });
422
- it('should throw error when propertyValue is missing', async () => {
423
- await expect(btep.getIdentityEntity({
424
- poolKey: 'item',
425
- propertyName: 'itemNumber',
426
- propertyValue: ''
427
- })).rejects.toThrow('poolKey, propertyName, and propertyValue must be defined');
428
- });
429
- it('should return undefined when no identity entities are found (empty array)', async () => {
430
- mockEntitiesGet.mockResolvedValue([]);
431
- const result = await btep.getIdentityEntity({
432
- poolKey: 'item',
433
- propertyName: 'itemNumber',
434
- propertyValue: '12345'
435
- });
436
- expect(result).toBeUndefined();
437
- expect(mockEntitiesGet).toHaveBeenCalledWith({
438
- entityName: 'identity',
439
- criteria: { poolKey: 'item', propertyName: 'itemNumber', propertyValue: '12345' }
440
- });
441
- });
442
- it('should return undefined when identity entities result is null', async () => {
443
- mockEntitiesGet.mockResolvedValue(null);
444
- const result = await btep.getIdentityEntity({
445
- poolKey: 'item',
446
- propertyName: 'itemNumber',
447
- propertyValue: '12345'
448
- });
449
- expect(result).toBeUndefined();
450
- });
451
- it('should throw error when multiple identity entities are found', async () => {
452
- mockEntitiesGet.mockResolvedValue([
453
- { entityReference: 'item:1' },
454
- { entityReference: 'item:2' }
455
- ]);
456
- await expect(btep.getIdentityEntity({
457
- poolKey: 'item',
458
- propertyName: 'itemNumber',
459
- propertyValue: '12345'
460
- })).rejects.toThrow('Multiple identity entities found for poolKey: item, itemNumber: 12345');
461
- });
462
- it('should return the identity entity when one is found (array)', async () => {
463
- const identityEntity = { entityReference: 'item:1' };
464
- mockEntitiesGet.mockResolvedValue([identityEntity]);
465
- const result = await btep.getIdentityEntity({
466
- poolKey: 'item',
467
- propertyName: 'itemNumber',
468
- propertyValue: '12345'
469
- });
470
- expect(result).toEqual(identityEntity);
471
- expect(mockEntitiesGet).toHaveBeenCalledTimes(1);
472
- });
473
- it('should return the identity entity when result is a single object (not array)', async () => {
474
- const identityEntity = { entityReference: 'item:5' };
475
- mockEntitiesGet.mockResolvedValue(identityEntity);
476
- const result = await btep.getIdentityEntity({
477
- poolKey: 'item:material',
478
- propertyName: 'materialNumber',
479
- propertyValue: 'MAT-001'
480
- });
481
- expect(result).toEqual(identityEntity);
482
- expect(mockEntitiesGet).toHaveBeenCalledTimes(1);
483
- });
484
- });
485
- describe('getEntityUsingIdentityService', () => {
486
- const config = {};
487
- const mapFileUtil = new transform_data_1.MapFileUtil(new sdk_1.Entities());
488
- const dc = new data_converter_1.DataConverter(config, mapFileUtil);
489
- let btep;
490
- let mockEntitiesGet;
491
- beforeEach(() => {
492
- btep = new TestBaseEntityProcessor(config, dc, mapFileUtil, 'item');
493
- mockEntitiesGet = jest.fn();
494
- btep.entities = { get: mockEntitiesGet };
495
- });
496
- it('should throw error when poolKey is missing', async () => {
497
- await expect(btep.getEntityUsingIdentityService({
498
- poolKey: '',
499
- propertyName: 'itemNumber',
500
- propertyValue: '12345'
501
- })).rejects.toThrow('poolKey, propertyName, and propertyValue must be defined');
502
- });
503
- it('should throw error when propertyName is missing', async () => {
504
- await expect(btep.getEntityUsingIdentityService({
505
- poolKey: 'item',
506
- propertyName: '',
507
- propertyValue: '12345'
508
- })).rejects.toThrow('poolKey, propertyName, and propertyValue must be defined');
509
- });
510
- it('should throw error when propertyValue is missing', async () => {
511
- await expect(btep.getEntityUsingIdentityService({
512
- poolKey: 'item',
513
- propertyName: 'itemNumber',
514
- propertyValue: ''
515
- })).rejects.toThrow('poolKey, propertyName, and propertyValue must be defined');
516
- });
517
- it('should return undefined when no identity entities are found (empty array)', async () => {
518
- mockEntitiesGet.mockResolvedValue([]);
519
- const result = await btep.getEntityUsingIdentityService({
520
- poolKey: 'item',
521
- propertyName: 'itemNumber',
522
- propertyValue: '12345'
523
- });
524
- expect(result).toBeUndefined();
525
- expect(mockEntitiesGet).toHaveBeenCalledWith({
526
- entityName: 'identity',
527
- criteria: { poolKey: 'item', propertyName: 'itemNumber', propertyValue: '12345' }
528
- });
529
- });
530
- it('should return undefined when identity entities result is null', async () => {
531
- mockEntitiesGet.mockResolvedValue(null);
532
- const result = await btep.getEntityUsingIdentityService({
533
- poolKey: 'item',
534
- propertyName: 'itemNumber',
535
- propertyValue: '12345'
536
- });
537
- expect(result).toBeUndefined();
538
- });
539
- it('should throw error when multiple identity entities are found', async () => {
540
- mockEntitiesGet.mockResolvedValue([
541
- { entityReference: 'item:1' },
542
- { entityReference: 'item:2' }
543
- ]);
544
- await expect(btep.getEntityUsingIdentityService({
545
- poolKey: 'item',
546
- propertyName: 'itemNumber',
547
- propertyValue: '12345'
548
- })).rejects.toThrow('Multiple identity entities found for poolKey: item, itemNumber: 12345');
549
- });
550
- it('should return the entity when one identity entity is found (array)', async () => {
551
- const mockEntity = { id: '1', name: 'Test Item' };
552
- mockEntitiesGet
553
- .mockResolvedValueOnce([{ entityReference: 'item:1' }])
554
- .mockResolvedValueOnce(mockEntity);
555
- const result = await btep.getEntityUsingIdentityService({
556
- poolKey: 'item',
557
- propertyName: 'itemNumber',
558
- propertyValue: '12345'
559
- });
560
- expect(result).toEqual(mockEntity);
561
- expect(mockEntitiesGet).toHaveBeenCalledTimes(2);
562
- expect(mockEntitiesGet).toHaveBeenNthCalledWith(1, {
563
- entityName: 'identity',
564
- criteria: { poolKey: 'item', propertyName: 'itemNumber', propertyValue: '12345' }
565
- });
566
- expect(mockEntitiesGet).toHaveBeenNthCalledWith(2, {
567
- entityName: 'item',
568
- id: '1'
569
- });
570
- });
571
- it('should return the entity when identity result is a single object (not array)', async () => {
572
- const mockEntity = { id: '5', name: 'Test Material' };
573
- mockEntitiesGet
574
- .mockResolvedValueOnce({ entityReference: 'item:5' })
575
- .mockResolvedValueOnce(mockEntity);
576
- const result = await btep.getEntityUsingIdentityService({
577
- poolKey: 'item:material',
578
- propertyName: 'materialNumber',
579
- propertyValue: 'MAT-001'
580
- });
581
- expect(result).toEqual(mockEntity);
582
- expect(mockEntitiesGet).toHaveBeenNthCalledWith(2, {
583
- entityName: 'item',
584
- id: '5'
585
- });
586
- });
587
- });
588
398
  });
package/lib/index.d.ts CHANGED
@@ -16,6 +16,7 @@ export * from './util/map-utils';
16
16
  export * from './interfaces/interfaces';
17
17
  export * from './interfaces/item-family-changes';
18
18
  export * from './interfaces/publish-change-data';
19
+ export * from './interfaces/mapping-file';
19
20
  export * from './publish/base-process-publish-assortment';
20
21
  export * from './publish/base-process-publish-assortment-callback';
21
22
  export * from './entity-processor/base-entity-processor';
package/lib/index.js CHANGED
@@ -32,6 +32,7 @@ __exportStar(require("./util/map-utils"), exports);
32
32
  __exportStar(require("./interfaces/interfaces"), exports);
33
33
  __exportStar(require("./interfaces/item-family-changes"), exports);
34
34
  __exportStar(require("./interfaces/publish-change-data"), exports);
35
+ __exportStar(require("./interfaces/mapping-file"), exports);
35
36
  __exportStar(require("./publish/base-process-publish-assortment"), exports);
36
37
  __exportStar(require("./publish/base-process-publish-assortment-callback"), exports);
37
38
  __exportStar(require("./entity-processor/base-entity-processor"), exports);