@contrail/flexplm 1.4.0 → 1.5.0-alpha.6d9ffc4

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/CHANGELOG.md CHANGED
@@ -6,6 +6,8 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
6
6
  Versioning follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
8
  ## [Unreleased]
9
+ ### Added
10
+ - Added support for Inbound `LCSMaterial` to sync to the entity class `item` with type path `item:material` and `itemNumber` as identifier. This is controlled by an `LCSMaterial.processAsItem` (default `false`) config default.
9
11
 
10
12
  ## [1.4.0] - 2026-05-06
11
13
  ### Added
@@ -201,7 +201,7 @@ class IdentifierConversion {
201
201
  }
202
202
  static async getItemCriteriaFromObject(transformMapFile, mapFileUtil, dc, object) {
203
203
  const criteria = await IdentifierConversion.getEntityCriteriaFromObject(transformMapFile, mapFileUtil, dc, object);
204
- const roles = (object.flexPLMObjectClass === 'LCSProduct') ? 'family' : 'color';
204
+ const roles = (['LCSProduct', 'LCSMaterial'].includes(object.flexPLMObjectClass)) ? 'family' : 'color';
205
205
  criteria['roles'] = roles;
206
206
  return criteria;
207
207
  }
@@ -4,6 +4,7 @@ const transform_data_1 = require("@contrail/transform-data");
4
4
  const identifier_conversion_1 = require("./identifier-conversion");
5
5
  const data_converter_1 = require("../util/data-converter");
6
6
  const sdk_1 = require("@contrail/sdk");
7
+ const type_defaults_1 = require("../util/type-defaults");
7
8
  const mapFile1Data = require('./identifier-conversion-spec-mockData');
8
9
  const mapFile1Mappings = mapFile1Data?.mapping;
9
10
  const mapFile2Mappings = mapFile1Data?.mapping2;
@@ -296,6 +297,36 @@ describe('getItemCriteriaFromObject', () => {
296
297
  }
297
298
  }
298
299
  });
300
+ it('should return the item family criteria from the object -LCSMaterial', async () => {
301
+ const object = {
302
+ "flexPLMObjectClass": "LCSMaterial",
303
+ "flexPLMTypePath": "Material\\form",
304
+ "itemNumber": "MAT-100"
305
+ };
306
+ const criteriaObject = {
307
+ flexPLMObjectClass: 'LCSMaterial',
308
+ itemNumber: 'MAT-100',
309
+ flexPLMTypePath: 'Material\\form',
310
+ };
311
+ const resultsObject = {
312
+ roles: 'family',
313
+ itemNumber: 'MAT-100'
314
+ };
315
+ let getEntityValuesSpyOn = undefined;
316
+ type_defaults_1.TypeDefaults.applyConfig({ LCSMaterial: { processAsItem: true } });
317
+ try {
318
+ getEntityValuesSpyOn = jest.spyOn(dc, 'getEntityValues');
319
+ const result = await identifier_conversion_1.IdentifierConversion.getItemCriteriaFromObject(transformMapFile1, mapFileUtil, dc, object);
320
+ expect(getEntityValuesSpyOn).toHaveBeenCalledWith('LCSMaterial', criteriaObject, []);
321
+ expect(result).toEqual(resultsObject);
322
+ }
323
+ finally {
324
+ if (getEntityValuesSpyOn) {
325
+ getEntityValuesSpyOn.mockRestore();
326
+ }
327
+ type_defaults_1.TypeDefaults.applyConfig({});
328
+ }
329
+ });
299
330
  it('should return the item option criteria from the object -uniqueIdentifierA, uniqueIdentifierB', async () => {
300
331
  const object = {
301
332
  "flexBoolean": false,
@@ -3,6 +3,24 @@ export declare class ConfigDefaults {
3
3
  static NEED_CONFIG_VALUES: string;
4
4
  static STATIC_CONFIG_CACHE: {};
5
5
  static setConfigDefaults(config: any): Promise<FCConfig>;
6
+ static getDefaultConfig(): {
7
+ urlContext: string;
8
+ sendMode: {
9
+ ASYNC_PUBLISH_SEASON: string;
10
+ };
11
+ itemPreDevelopmentLifecycleStages: string[];
12
+ identifierAtts: {
13
+ LCSProduct: string[];
14
+ LCSSeason: string[];
15
+ LCSSKU: string[];
16
+ };
17
+ LCSMaterial: {
18
+ processAsItem: boolean;
19
+ };
20
+ csrfEndpoint: string;
21
+ vibeEventEndpoint: string;
22
+ payloadDefaultAsArray: boolean;
23
+ };
6
24
  static getConfigFile(fileId: string): Promise<any>;
7
25
  static isPropertyTrue(value: any): boolean;
8
26
  static clearConfigCache(): void;
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ConfigDefaults = void 0;
4
4
  const sdk_1 = require("@contrail/sdk");
5
5
  const util_1 = require("@contrail/util");
6
+ const type_defaults_1 = require("./type-defaults");
6
7
  class ConfigDefaults {
7
8
  static async setConfigDefaults(config) {
8
9
  if (!config.apiHost || !config.userName || !config.password) {
@@ -14,7 +15,24 @@ class ConfigDefaults {
14
15
  else if (Object.keys(config).includes('itemPreDevelopmentLifecycleStages')) {
15
16
  delete config['itemPreDevelopmentLifecycleStages'];
16
17
  }
17
- const defaultConfig = {
18
+ const configArr = [ConfigDefaults.getDefaultConfig()];
19
+ if (config.configFile) {
20
+ const fileConfig = await ConfigDefaults.getConfigFile(config.configFile);
21
+ configArr.push(fileConfig);
22
+ }
23
+ configArr.push(config);
24
+ const outputConfig = util_1.ObjectUtil.mergeDeep({}, ...configArr);
25
+ const uName = outputConfig.userName;
26
+ const pass = outputConfig.password;
27
+ outputConfig.userName = () => uName;
28
+ outputConfig.password = () => pass;
29
+ outputConfig['OOBvibeEventEndpoint'] = '/rfa/vibeiq/vibeEvents';
30
+ type_defaults_1.TypeDefaults.applyConfig(outputConfig);
31
+ console.log('outputConfig: ' + JSON.stringify(outputConfig));
32
+ return outputConfig;
33
+ }
34
+ static getDefaultConfig() {
35
+ return {
18
36
  urlContext: '/Windchill',
19
37
  sendMode: {
20
38
  ASYNC_PUBLISH_SEASON: 'vibeiqfile'
@@ -25,24 +43,13 @@ class ConfigDefaults {
25
43
  LCSSeason: ['flexPLMSeasonName'],
26
44
  LCSSKU: ['itemNumber']
27
45
  },
46
+ LCSMaterial: {
47
+ processAsItem: false
48
+ },
28
49
  csrfEndpoint: '/servlet/rest/security/csrf',
29
50
  vibeEventEndpoint: '/rfa/vibeiq/vibeEvents',
30
51
  payloadDefaultAsArray: true
31
52
  };
32
- const configArr = [defaultConfig];
33
- if (config.configFile) {
34
- const fileConfig = await ConfigDefaults.getConfigFile(config.configFile);
35
- configArr.push(fileConfig);
36
- }
37
- configArr.push(config);
38
- const outputConfig = util_1.ObjectUtil.mergeDeep({}, ...configArr);
39
- const uName = outputConfig.userName;
40
- const pass = outputConfig.password;
41
- outputConfig.userName = () => uName;
42
- outputConfig.password = () => pass;
43
- outputConfig['OOBvibeEventEndpoint'] = '/rfa/vibeiq/vibeEvents';
44
- console.log('outputConfig: ' + JSON.stringify(outputConfig));
45
- return outputConfig;
46
53
  }
47
54
  static async getConfigFile(fileId) {
48
55
  try {
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const config_defaults_1 = require("./config-defaults");
4
+ const type_defaults_1 = require("./type-defaults");
4
5
  let entityObject = {};
5
6
  jest.mock('@contrail/sdk', () => {
6
7
  return {
@@ -296,6 +297,52 @@ describe('all tests', () => {
296
297
  expect(config_defaults_1.ConfigDefaults.isPropertyTrue(1)).toBe(false);
297
298
  });
298
299
  });
300
+ describe('getDefaultConfig', () => {
301
+ it('returns LCSMaterial.processAsItem=false by default', () => {
302
+ const dc = config_defaults_1.ConfigDefaults.getDefaultConfig();
303
+ expect(dc.LCSMaterial).toBeDefined();
304
+ expect(dc.LCSMaterial.processAsItem).toBe(false);
305
+ });
306
+ it('returns a fresh object each call (no shared reference)', () => {
307
+ const a = config_defaults_1.ConfigDefaults.getDefaultConfig();
308
+ const b = config_defaults_1.ConfigDefaults.getDefaultConfig();
309
+ expect(a).not.toBe(b);
310
+ expect(a.LCSMaterial).not.toBe(b.LCSMaterial);
311
+ a.LCSMaterial.processAsItem = true;
312
+ expect(b.LCSMaterial.processAsItem).toBe(false);
313
+ });
314
+ });
315
+ describe('setConfigDefaults - LCSMaterial', () => {
316
+ const config = {
317
+ apiHost: 'http://test.com',
318
+ userName: 'vibeiq',
319
+ password: 'vibeiq'
320
+ };
321
+ it('LCSMaterial.processAsItem-get default', async () => {
322
+ const startConfig = Object.assign({}, config);
323
+ const fcConfig = await config_defaults_1.ConfigDefaults.setConfigDefaults(startConfig);
324
+ expect(fcConfig.LCSMaterial.processAsItem).toBe(false);
325
+ });
326
+ it('LCSMaterial.processAsItem-override', async () => {
327
+ const startConfig = Object.assign({}, config);
328
+ startConfig.LCSMaterial = { processAsItem: true };
329
+ const fcConfig = await config_defaults_1.ConfigDefaults.setConfigDefaults(startConfig);
330
+ expect(fcConfig.LCSMaterial.processAsItem).toBe(true);
331
+ });
332
+ it('applies LCSMaterial.processAsItem to TypeDefaults', async () => {
333
+ try {
334
+ const startConfig = Object.assign({}, config, { LCSMaterial: { processAsItem: true } });
335
+ await config_defaults_1.ConfigDefaults.setConfigDefaults(startConfig);
336
+ expect(type_defaults_1.TypeDefaults.processLCSMaterialAsItem).toBe(true);
337
+ const defaultStart = Object.assign({}, config);
338
+ await config_defaults_1.ConfigDefaults.setConfigDefaults(defaultStart);
339
+ expect(type_defaults_1.TypeDefaults.processLCSMaterialAsItem).toBe(false);
340
+ }
341
+ finally {
342
+ type_defaults_1.TypeDefaults.applyConfig({});
343
+ }
344
+ });
345
+ });
299
346
  describe('getConfigFile', () => {
300
347
  beforeEach(() => {
301
348
  config_defaults_1.ConfigDefaults.clearConfigCache();
@@ -235,7 +235,7 @@ class DataConverter {
235
235
  const type = await this.typeUtils.getByRootAndPath(tco);
236
236
  const typePath = type['typePath'];
237
237
  if (typePath && (typePath.startsWith('item') || typePath.startsWith('project-item'))) {
238
- if (['LCSProduct', 'LCSProductSeasonLink'].includes(objectClass)) {
238
+ if (['LCSProduct', 'LCSProductSeasonLink', 'LCSMaterial'].includes(objectClass)) {
239
239
  entityValues['roles'] = ['family'];
240
240
  }
241
241
  else {
@@ -525,6 +525,47 @@ describe('getObjectReferenceValue - use mapping', () => {
525
525
  }
526
526
  });
527
527
  });
528
+ describe('getEntityValues', () => {
529
+ const config = {
530
+ apiHost: 'host',
531
+ userName: () => 'user',
532
+ password: () => 'pass',
533
+ urlContext: 'xxx',
534
+ vibeEventEndpoint: '/rfa/vibeiq/vibeEvents',
535
+ csrfEndpoint: '/servlet/rest/security/csrf',
536
+ itemPreDevelopmentLifecycleStages: ['concept']
537
+ };
538
+ const mapFileUtil = new transform_data_1.MapFileUtil(new sdk_1.Entities());
539
+ const dc = new data_converter_1.DataConverter(config, mapFileUtil);
540
+ const runWithStubs = async (typePath, objectClass, data) => {
541
+ const tcoSpy = jest.spyOn(dc['typeUtils'], 'getEntityTypeClientOptionsUsingMapping')
542
+ .mockImplementation(async () => ({ root: 'item' }));
543
+ const typeSpy = jest.spyOn(dc['typeUtils'], 'getByRootAndPath')
544
+ .mockImplementation(async () => ({ typePath, typeProperties: [] }));
545
+ const filterSpy = jest.spyOn(dc['typeUtils'], 'filterTypeProperties')
546
+ .mockImplementation(() => []);
547
+ try {
548
+ return await dc.getEntityValues(objectClass, data);
549
+ }
550
+ finally {
551
+ tcoSpy.mockRestore();
552
+ typeSpy.mockRestore();
553
+ filterSpy.mockRestore();
554
+ }
555
+ };
556
+ it('LCSProduct -> roles family', async () => {
557
+ const result = await runWithStubs('item', 'LCSProduct', { itemNumber: 'X1' });
558
+ expect(result['roles']).toEqual(['family']);
559
+ });
560
+ it('LCSSKU -> roles color, option', async () => {
561
+ const result = await runWithStubs('item', 'LCSSKU', { itemNumber: 'X1' });
562
+ expect(result['roles']).toEqual(['color', 'option']);
563
+ });
564
+ it('LCSMaterial -> roles family', async () => {
565
+ const result = await runWithStubs('item:material', 'LCSMaterial', { itemNumber: 'MAT-100' });
566
+ expect(result['roles']).toEqual(['family']);
567
+ });
568
+ });
528
569
  describe('setEnumerationKeys', () => {
529
570
  const config = {
530
571
  apiHost: 'host',
@@ -2,7 +2,9 @@ export declare class TypeDefaults {
2
2
  static NO_ENTITY_TYPE: string;
3
3
  static NO_OBJECT_CLASS: string;
4
4
  static NO_TYPE_PATH: string;
5
+ static processLCSMaterialAsItem: boolean;
5
6
  constructor();
7
+ static applyConfig(config: any): void;
6
8
  static getDefaultObjectClass(entity: any): string;
7
9
  static getDefaultObjectTypePath(entity: any): string;
8
10
  static getDefaultIdentifierProperties(entity: any): string[];
@@ -4,6 +4,11 @@ exports.TypeDefaults = void 0;
4
4
  class TypeDefaults {
5
5
  constructor() {
6
6
  }
7
+ static applyConfig(config) {
8
+ const val = config?.LCSMaterial?.processAsItem;
9
+ TypeDefaults.processLCSMaterialAsItem =
10
+ val === true || (typeof val === 'string' && val.toLowerCase() === 'true');
11
+ }
7
12
  static getDefaultObjectClass(entity) {
8
13
  const entityType = this.getEntityType(entity);
9
14
  let objectClass = '';
@@ -130,7 +135,13 @@ class TypeDefaults {
130
135
  static getDefaultEntityClass(object) {
131
136
  let entityClass = '';
132
137
  let objectClass = TypeDefaults.getObjectClass(object);
133
- if (['LCSProduct', 'LCSSKU'].includes(objectClass)) {
138
+ const itemClasses = TypeDefaults.processLCSMaterialAsItem
139
+ ? ['LCSProduct', 'LCSSKU', 'LCSMaterial']
140
+ : ['LCSProduct', 'LCSSKU'];
141
+ const customEntityClasses = TypeDefaults.processLCSMaterialAsItem
142
+ ? ['LCSRevisableEntity', 'LCSLifecycleManaged', 'LCSLast']
143
+ : ['LCSRevisableEntity', 'LCSLifecycleManaged', 'LCSLast', 'LCSMaterial'];
144
+ if (itemClasses.includes(objectClass)) {
134
145
  entityClass = 'item';
135
146
  }
136
147
  else if (['LCSProductSeasonLink', 'LCSSKUSeasonLink'].includes(objectClass)) {
@@ -142,7 +153,7 @@ class TypeDefaults {
142
153
  else if (['LCSSeason', 'SeasonGroup'].includes(objectClass)) {
143
154
  entityClass = 'assortment';
144
155
  }
145
- else if (['LCSRevisableEntity', 'LCSLifecycleManaged', 'LCSLast', 'LCSMaterial'].includes(objectClass)) {
156
+ else if (customEntityClasses.includes(objectClass)) {
146
157
  entityClass = 'custom-entity';
147
158
  }
148
159
  if (entityClass === '')
@@ -157,6 +168,11 @@ class TypeDefaults {
157
168
  case 'LCSSKU':
158
169
  typePath = 'item';
159
170
  break;
171
+ case 'LCSMaterial':
172
+ if (TypeDefaults.processLCSMaterialAsItem) {
173
+ typePath = 'item:material';
174
+ }
175
+ break;
160
176
  case 'LCSProductSeasonLink':
161
177
  case 'LCSSKUSeasonLink':
162
178
  typePath = 'project-item';
@@ -181,6 +197,14 @@ class TypeDefaults {
181
197
  case 'LCSSKU':
182
198
  identifierProps.push('itemNumber');
183
199
  break;
200
+ case 'LCSMaterial':
201
+ if (TypeDefaults.processLCSMaterialAsItem) {
202
+ identifierProps.push('itemNumber');
203
+ }
204
+ else {
205
+ identifierProps.push('name');
206
+ }
207
+ break;
184
208
  case 'LCSSeason':
185
209
  identifierProps.push('flexPLMSeasonName');
186
210
  break;
@@ -191,7 +215,6 @@ class TypeDefaults {
191
215
  case 'LCSRevisableEntity':
192
216
  case 'LCSLifecycleManaged':
193
217
  case 'LCSLast':
194
- case 'LCSMaterial':
195
218
  identifierProps.push('name');
196
219
  break;
197
220
  }
@@ -200,7 +223,10 @@ class TypeDefaults {
200
223
  static getDefaultInformationalPropertiesFromObject(object) {
201
224
  const objectClass = TypeDefaults.getObjectClass(object);
202
225
  let properties = [];
203
- if ('LCSProduct' === objectClass) {
226
+ const itemClasses = TypeDefaults.processLCSMaterialAsItem
227
+ ? ['LCSProduct', 'LCSMaterial']
228
+ : ['LCSProduct'];
229
+ if (itemClasses.includes(objectClass)) {
204
230
  properties.push('name');
205
231
  }
206
232
  else if ('LCSSKU' === objectClass) {
@@ -219,3 +245,4 @@ exports.TypeDefaults = TypeDefaults;
219
245
  TypeDefaults.NO_ENTITY_TYPE = 'Not able to determine the entity type of the entity object';
220
246
  TypeDefaults.NO_OBJECT_CLASS = 'Please ensure that the flexPLMObjectClass property is provided.';
221
247
  TypeDefaults.NO_TYPE_PATH = 'Please ensure that the flexPLMTypePath property is provided.';
248
+ TypeDefaults.processLCSMaterialAsItem = false;
@@ -369,6 +369,26 @@ describe('Type Defaults', () => {
369
369
  const entityClass = type_defaults_1.TypeDefaults.getDefaultEntityClass(object);
370
370
  expect(entityClass).toBe('custom-entity');
371
371
  });
372
+ it('item - LCSMaterial - processAsItem=true', () => {
373
+ const object = {
374
+ flexPLMObjectClass: 'LCSMaterial'
375
+ };
376
+ type_defaults_1.TypeDefaults.applyConfig({ LCSMaterial: { processAsItem: true } });
377
+ try {
378
+ const entityClass = type_defaults_1.TypeDefaults.getDefaultEntityClass(object);
379
+ expect(entityClass).toBe('item');
380
+ }
381
+ finally {
382
+ type_defaults_1.TypeDefaults.applyConfig({});
383
+ }
384
+ });
385
+ it('custom-entity - LCSMaterial - processAsItem=false (default)', () => {
386
+ const object = {
387
+ flexPLMObjectClass: 'LCSMaterial'
388
+ };
389
+ const entityClass = type_defaults_1.TypeDefaults.getDefaultEntityClass(object);
390
+ expect(entityClass).toBe('custom-entity');
391
+ });
372
392
  });
373
393
  describe('getDefaultEntityTypePath', () => {
374
394
  it('LCSProduct', () => {
@@ -420,6 +440,25 @@ describe('Type Defaults', () => {
420
440
  const typePath = type_defaults_1.TypeDefaults.getDefaultEntityTypePath(object);
421
441
  expect(typePath).toBe('assortment');
422
442
  });
443
+ it('LCSMaterial - processAsItem=true', () => {
444
+ const object = {
445
+ flexPLMObjectClass: 'LCSMaterial'
446
+ };
447
+ type_defaults_1.TypeDefaults.applyConfig({ LCSMaterial: { processAsItem: true } });
448
+ try {
449
+ const typePath = type_defaults_1.TypeDefaults.getDefaultEntityTypePath(object);
450
+ expect(typePath).toBe('item:material');
451
+ }
452
+ finally {
453
+ type_defaults_1.TypeDefaults.applyConfig({});
454
+ }
455
+ });
456
+ it('LCSMaterial - processAsItem=false (default) throws', () => {
457
+ const object = {
458
+ flexPLMObjectClass: 'LCSMaterial'
459
+ };
460
+ expect(() => type_defaults_1.TypeDefaults.getDefaultEntityTypePath(object)).toThrowError(type_defaults_1.TypeDefaults.NO_TYPE_PATH);
461
+ });
423
462
  });
424
463
  describe('getDefaultIdentifierPropertiesFromObject', () => {
425
464
  it('LCSProduct', () => {
@@ -478,6 +517,28 @@ describe('Type Defaults', () => {
478
517
  expect(defaultIdentifiers).toContain('name');
479
518
  expect(defaultIdentifiers).toHaveLength(1);
480
519
  });
520
+ it('LCSMaterial - processAsItem=true', () => {
521
+ const object = {
522
+ flexPLMObjectClass: 'LCSMaterial'
523
+ };
524
+ type_defaults_1.TypeDefaults.applyConfig({ LCSMaterial: { processAsItem: true } });
525
+ try {
526
+ const defaultIdentifiers = type_defaults_1.TypeDefaults.getDefaultIdentifierPropertiesFromObject(object);
527
+ expect(defaultIdentifiers).toContain('itemNumber');
528
+ expect(defaultIdentifiers).toHaveLength(1);
529
+ }
530
+ finally {
531
+ type_defaults_1.TypeDefaults.applyConfig({});
532
+ }
533
+ });
534
+ it('LCSMaterial - processAsItem=false (default)', () => {
535
+ const object = {
536
+ flexPLMObjectClass: 'LCSMaterial'
537
+ };
538
+ const defaultIdentifiers = type_defaults_1.TypeDefaults.getDefaultIdentifierPropertiesFromObject(object);
539
+ expect(defaultIdentifiers).toContain('name');
540
+ expect(defaultIdentifiers).toHaveLength(1);
541
+ });
481
542
  });
482
543
  describe('getDefaultInformationalPropertiesFromObject', () => {
483
544
  it('LCSProduct', () => {
@@ -512,5 +573,54 @@ describe('Type Defaults', () => {
512
573
  expect(defaultIdentifiers).toContain('name');
513
574
  expect(defaultIdentifiers).toHaveLength(1);
514
575
  });
576
+ it('LCSMaterial - processAsItem=true', () => {
577
+ const object = {
578
+ flexPLMObjectClass: 'LCSMaterial'
579
+ };
580
+ type_defaults_1.TypeDefaults.applyConfig({ LCSMaterial: { processAsItem: true } });
581
+ try {
582
+ const defaultIdentifiers = type_defaults_1.TypeDefaults.getDefaultInformationalPropertiesFromObject(object);
583
+ expect(defaultIdentifiers).toContain('name');
584
+ expect(defaultIdentifiers).toHaveLength(1);
585
+ }
586
+ finally {
587
+ type_defaults_1.TypeDefaults.applyConfig({});
588
+ }
589
+ });
590
+ it('LCSMaterial - processAsItem=false (default) yields no informational props', () => {
591
+ const object = {
592
+ flexPLMObjectClass: 'LCSMaterial'
593
+ };
594
+ const defaultIdentifiers = type_defaults_1.TypeDefaults.getDefaultInformationalPropertiesFromObject(object);
595
+ expect(defaultIdentifiers).toHaveLength(0);
596
+ });
597
+ });
598
+ describe('applyConfig', () => {
599
+ afterEach(() => {
600
+ type_defaults_1.TypeDefaults.applyConfig({});
601
+ });
602
+ it('sets processLCSMaterialAsItem=true when processAsItem=true', () => {
603
+ type_defaults_1.TypeDefaults.applyConfig({ LCSMaterial: { processAsItem: true } });
604
+ expect(type_defaults_1.TypeDefaults.processLCSMaterialAsItem).toBe(true);
605
+ });
606
+ it('sets processLCSMaterialAsItem=true when processAsItem=\"true\" (string)', () => {
607
+ type_defaults_1.TypeDefaults.applyConfig({ LCSMaterial: { processAsItem: 'true' } });
608
+ expect(type_defaults_1.TypeDefaults.processLCSMaterialAsItem).toBe(true);
609
+ });
610
+ it('sets processLCSMaterialAsItem=false when processAsItem=false', () => {
611
+ type_defaults_1.TypeDefaults.processLCSMaterialAsItem = true;
612
+ type_defaults_1.TypeDefaults.applyConfig({ LCSMaterial: { processAsItem: false } });
613
+ expect(type_defaults_1.TypeDefaults.processLCSMaterialAsItem).toBe(false);
614
+ });
615
+ it('sets processLCSMaterialAsItem=false when LCSMaterial missing', () => {
616
+ type_defaults_1.TypeDefaults.processLCSMaterialAsItem = true;
617
+ type_defaults_1.TypeDefaults.applyConfig({});
618
+ expect(type_defaults_1.TypeDefaults.processLCSMaterialAsItem).toBe(false);
619
+ });
620
+ it('sets processLCSMaterialAsItem=false when config is null/undefined', () => {
621
+ type_defaults_1.TypeDefaults.processLCSMaterialAsItem = true;
622
+ type_defaults_1.TypeDefaults.applyConfig(undefined);
623
+ expect(type_defaults_1.TypeDefaults.processLCSMaterialAsItem).toBe(false);
624
+ });
515
625
  });
516
626
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contrail/flexplm",
3
- "version": "1.4.0",
3
+ "version": "1.5.0-alpha.6d9ffc4",
4
4
  "description": "Library used for integration with flexplm.",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -3,6 +3,7 @@ import { IdentifierConversion } from "./identifier-conversion";
3
3
  import { DataConverter } from "../util/data-converter";
4
4
  import { FCConfig } from "../interfaces/interfaces";
5
5
  import { Entities } from "@contrail/sdk";
6
+ import { TypeDefaults } from "../util/type-defaults";
6
7
 
7
8
  const mapFile1Data = require('./identifier-conversion-spec-mockData');
8
9
  const mapFile1Mappings = mapFile1Data?.mapping;
@@ -309,6 +310,37 @@ describe('getItemCriteriaFromObject', () => {
309
310
  }
310
311
  });
311
312
 
313
+ it('should return the item family criteria from the object -LCSMaterial', async () => {
314
+ const object = {
315
+ "flexPLMObjectClass": "LCSMaterial",
316
+ "flexPLMTypePath": "Material\\form",
317
+ "itemNumber": "MAT-100"
318
+ };
319
+ const criteriaObject = {
320
+ flexPLMObjectClass: 'LCSMaterial',
321
+ itemNumber: 'MAT-100',
322
+ flexPLMTypePath: 'Material\\form',
323
+ };
324
+ const resultsObject = {
325
+ roles: 'family',
326
+ itemNumber: 'MAT-100'
327
+ };
328
+ let getEntityValuesSpyOn = undefined
329
+ TypeDefaults.applyConfig({ LCSMaterial: { processAsItem: true } });
330
+ try {
331
+
332
+ getEntityValuesSpyOn = jest.spyOn(dc, 'getEntityValues');
333
+ const result = await IdentifierConversion.getItemCriteriaFromObject(transformMapFile1, mapFileUtil, dc, object);
334
+ expect(getEntityValuesSpyOn).toHaveBeenCalledWith('LCSMaterial', criteriaObject, []);
335
+ expect(result).toEqual(resultsObject);
336
+ } finally {
337
+ if (getEntityValuesSpyOn) {
338
+ getEntityValuesSpyOn.mockRestore();
339
+ }
340
+ TypeDefaults.applyConfig({});
341
+ }
342
+ });
343
+
312
344
  it('should return the item option criteria from the object -uniqueIdentifierA, uniqueIdentifierB', async () => {
313
345
  const object = {
314
346
  "flexBoolean": false,
@@ -274,7 +274,7 @@ export class IdentifierConversion {
274
274
 
275
275
  static async getItemCriteriaFromObject(transformMapFile: string, mapFileUtil: MapFileUtil, dc: DataConverter, object: any): Promise<any> {
276
276
  const criteria = await IdentifierConversion.getEntityCriteriaFromObject(transformMapFile, mapFileUtil, dc, object);
277
- const roles = (object.flexPLMObjectClass === 'LCSProduct') ? 'family' : 'color';
277
+ const roles = (['LCSProduct', 'LCSMaterial'].includes(object.flexPLMObjectClass)) ? 'family' : 'color';
278
278
  criteria['roles'] = roles;
279
279
 
280
280
  return criteria;
@@ -1,5 +1,6 @@
1
1
  import { ConfigDefaults } from './config-defaults';
2
2
  import { FCConfig } from '../interfaces/interfaces';
3
+ import { TypeDefaults } from './type-defaults';
3
4
 
4
5
  let entityObject = {};
5
6
  jest.mock('@contrail/sdk', () => {
@@ -356,6 +357,58 @@ describe('all tests', () => {
356
357
  });
357
358
  });
358
359
 
360
+ describe('getDefaultConfig', () => {
361
+ it('returns LCSMaterial.processAsItem=false by default', () => {
362
+ const dc: any = ConfigDefaults.getDefaultConfig();
363
+ expect(dc.LCSMaterial).toBeDefined();
364
+ expect(dc.LCSMaterial.processAsItem).toBe(false);
365
+ });
366
+
367
+ it('returns a fresh object each call (no shared reference)', () => {
368
+ const a: any = ConfigDefaults.getDefaultConfig();
369
+ const b: any = ConfigDefaults.getDefaultConfig();
370
+ expect(a).not.toBe(b);
371
+ expect(a.LCSMaterial).not.toBe(b.LCSMaterial);
372
+ a.LCSMaterial.processAsItem = true;
373
+ expect(b.LCSMaterial.processAsItem).toBe(false);
374
+ });
375
+ });
376
+
377
+ describe('setConfigDefaults - LCSMaterial', () => {
378
+ const config = {
379
+ apiHost: 'http://test.com',
380
+ userName: 'vibeiq',
381
+ password: 'vibeiq'
382
+ };
383
+
384
+ it('LCSMaterial.processAsItem-get default', async () => {
385
+ const startConfig = Object.assign({}, config);
386
+ const fcConfig: any = await ConfigDefaults.setConfigDefaults(startConfig);
387
+ expect(fcConfig.LCSMaterial.processAsItem).toBe(false);
388
+ });
389
+
390
+ it('LCSMaterial.processAsItem-override', async () => {
391
+ const startConfig: any = Object.assign({}, config);
392
+ startConfig.LCSMaterial = { processAsItem: true };
393
+ const fcConfig: any = await ConfigDefaults.setConfigDefaults(startConfig);
394
+ expect(fcConfig.LCSMaterial.processAsItem).toBe(true);
395
+ });
396
+
397
+ it('applies LCSMaterial.processAsItem to TypeDefaults', async () => {
398
+ try {
399
+ const startConfig: any = Object.assign({}, config, { LCSMaterial: { processAsItem: true } });
400
+ await ConfigDefaults.setConfigDefaults(startConfig);
401
+ expect(TypeDefaults.processLCSMaterialAsItem).toBe(true);
402
+
403
+ const defaultStart: any = Object.assign({}, config);
404
+ await ConfigDefaults.setConfigDefaults(defaultStart);
405
+ expect(TypeDefaults.processLCSMaterialAsItem).toBe(false);
406
+ } finally {
407
+ TypeDefaults.applyConfig({});
408
+ }
409
+ });
410
+ });
411
+
359
412
  describe('getConfigFile', () => {
360
413
  beforeEach(() => {
361
414
  ConfigDefaults.clearConfigCache();
@@ -1,6 +1,7 @@
1
1
  import { Entities } from '@contrail/sdk';
2
2
  import { FCConfig } from '../interfaces/interfaces';
3
3
  import { ObjectUtil } from '@contrail/util';
4
+ import { TypeDefaults } from './type-defaults';
4
5
 
5
6
  export class ConfigDefaults {
6
7
  static NEED_CONFIG_VALUES = 'To connect to FlexPLM all these APP values need to be set apiHost, userName, and password';
@@ -18,22 +19,7 @@ export class ConfigDefaults {
18
19
  delete config['itemPreDevelopmentLifecycleStages'];
19
20
  }
20
21
 
21
- const defaultConfig = {
22
- urlContext: '/Windchill',
23
- sendMode: {
24
- ASYNC_PUBLISH_SEASON: 'vibeiqfile'
25
- },
26
- itemPreDevelopmentLifecycleStages: ['concept'],
27
- identifierAtts: {
28
- LCSProduct: ['itemNumber'],
29
- LCSSeason: ['flexPLMSeasonName'],
30
- LCSSKU: ['itemNumber']
31
- },
32
- csrfEndpoint: '/servlet/rest/security/csrf',
33
- vibeEventEndpoint: '/rfa/vibeiq/vibeEvents',
34
- payloadDefaultAsArray: true
35
- };
36
- const configArr = [defaultConfig];
22
+ const configArr = [ConfigDefaults.getDefaultConfig()];
37
23
 
38
24
  if(config.configFile){
39
25
  const fileConfig = await ConfigDefaults.getConfigFile(config.configFile);
@@ -49,10 +35,33 @@ export class ConfigDefaults {
49
35
  //Don't allow overwriting this.
50
36
  outputConfig['OOBvibeEventEndpoint'] = '/rfa/vibeiq/vibeEvents';
51
37
 
38
+ TypeDefaults.applyConfig(outputConfig);
39
+
52
40
  console.log('outputConfig: ' + JSON.stringify(outputConfig));
53
41
  return outputConfig as FCConfig;
54
42
  }
55
43
 
44
+ static getDefaultConfig() {
45
+ return {
46
+ urlContext: '/Windchill',
47
+ sendMode: {
48
+ ASYNC_PUBLISH_SEASON: 'vibeiqfile'
49
+ },
50
+ itemPreDevelopmentLifecycleStages: ['concept'],
51
+ identifierAtts: {
52
+ LCSProduct: ['itemNumber'],
53
+ LCSSeason: ['flexPLMSeasonName'],
54
+ LCSSKU: ['itemNumber']
55
+ },
56
+ LCSMaterial: {
57
+ processAsItem: false
58
+ },
59
+ csrfEndpoint: '/servlet/rest/security/csrf',
60
+ vibeEventEndpoint: '/rfa/vibeiq/vibeEvents',
61
+ payloadDefaultAsArray: true
62
+ };
63
+ }
64
+
56
65
  static async getConfigFile(fileId: string) {
57
66
  try {
58
67
 
@@ -594,6 +594,51 @@ describe('getObjectReferenceValue - use mapping', () => {
594
594
  });
595
595
  });
596
596
 
597
+ describe('getEntityValues', () => {
598
+ const config: FCConfig = {
599
+ apiHost: 'host',
600
+ userName: () => 'user',
601
+ password: () => 'pass',
602
+ urlContext: 'xxx',
603
+ vibeEventEndpoint: '/rfa/vibeiq/vibeEvents',
604
+ csrfEndpoint: '/servlet/rest/security/csrf',
605
+ itemPreDevelopmentLifecycleStages: ['concept']
606
+ };
607
+ const mapFileUtil = new MapFileUtil(new Entities());
608
+ const dc = new DataConverter(config, mapFileUtil);
609
+
610
+ const runWithStubs = async (typePath: string, objectClass: string, data: any) => {
611
+ const tcoSpy = jest.spyOn(dc['typeUtils'], 'getEntityTypeClientOptionsUsingMapping')
612
+ .mockImplementation(async () => ({ root: 'item' }));
613
+ const typeSpy = jest.spyOn(dc['typeUtils'], 'getByRootAndPath')
614
+ .mockImplementation(async () => ({ typePath, typeProperties: [] }));
615
+ const filterSpy = jest.spyOn(dc['typeUtils'], 'filterTypeProperties')
616
+ .mockImplementation(() => []);
617
+ try {
618
+ return await dc.getEntityValues(objectClass, data);
619
+ } finally {
620
+ tcoSpy.mockRestore();
621
+ typeSpy.mockRestore();
622
+ filterSpy.mockRestore();
623
+ }
624
+ };
625
+
626
+ it('LCSProduct -> roles family', async () => {
627
+ const result = await runWithStubs('item', 'LCSProduct', { itemNumber: 'X1' });
628
+ expect(result['roles']).toEqual(['family']);
629
+ });
630
+
631
+ it('LCSSKU -> roles color, option', async () => {
632
+ const result = await runWithStubs('item', 'LCSSKU', { itemNumber: 'X1' });
633
+ expect(result['roles']).toEqual(['color', 'option']);
634
+ });
635
+
636
+ it('LCSMaterial -> roles family', async () => {
637
+ const result = await runWithStubs('item:material', 'LCSMaterial', { itemNumber: 'MAT-100' });
638
+ expect(result['roles']).toEqual(['family']);
639
+ });
640
+ });
641
+
597
642
  describe('setEnumerationKeys', () =>{
598
643
  const config: FCConfig = {
599
644
  apiHost: 'host',
@@ -287,7 +287,7 @@ export class DataConverter {
287
287
  const type = await this.typeUtils.getByRootAndPath(tco);
288
288
  const typePath = type['typePath'];
289
289
  if(typePath && (typePath.startsWith('item') || typePath.startsWith('project-item'))){
290
- if(['LCSProduct', 'LCSProductSeasonLink'].includes(objectClass)){
290
+ if(['LCSProduct', 'LCSProductSeasonLink', 'LCSMaterial'].includes(objectClass)){
291
291
  entityValues['roles'] = ['family'];
292
292
  }else{
293
293
  entityValues['roles'] = ['color', 'option'];
@@ -485,6 +485,30 @@ describe('Type Defaults', () =>{
485
485
  expect(entityClass).toBe('custom-entity');
486
486
  });
487
487
 
488
+ it('item - LCSMaterial - processAsItem=true', () =>{
489
+ const object = {
490
+ flexPLMObjectClass: 'LCSMaterial'
491
+ };
492
+
493
+ TypeDefaults.applyConfig({ LCSMaterial: { processAsItem: true } });
494
+ try {
495
+ const entityClass = TypeDefaults.getDefaultEntityClass(object);
496
+ expect(entityClass).toBe('item');
497
+ } finally {
498
+ TypeDefaults.applyConfig({});
499
+ }
500
+ });
501
+
502
+ it('custom-entity - LCSMaterial - processAsItem=false (default)', () =>{
503
+ const object = {
504
+ flexPLMObjectClass: 'LCSMaterial'
505
+ };
506
+
507
+ const entityClass = TypeDefaults.getDefaultEntityClass(object);
508
+
509
+ expect(entityClass).toBe('custom-entity');
510
+ });
511
+
488
512
  });//getDefaultEntityClass
489
513
 
490
514
  describe('getDefaultEntityTypePath', () =>{
@@ -549,6 +573,28 @@ describe('Type Defaults', () =>{
549
573
  const typePath = TypeDefaults.getDefaultEntityTypePath(object);
550
574
  expect(typePath).toBe('assortment');
551
575
  });
576
+
577
+ it('LCSMaterial - processAsItem=true', () =>{
578
+ const object = {
579
+ flexPLMObjectClass: 'LCSMaterial'
580
+ };
581
+
582
+ TypeDefaults.applyConfig({ LCSMaterial: { processAsItem: true } });
583
+ try {
584
+ const typePath = TypeDefaults.getDefaultEntityTypePath(object);
585
+ expect(typePath).toBe('item:material');
586
+ } finally {
587
+ TypeDefaults.applyConfig({});
588
+ }
589
+ });
590
+
591
+ it('LCSMaterial - processAsItem=false (default) throws', () =>{
592
+ const object = {
593
+ flexPLMObjectClass: 'LCSMaterial'
594
+ };
595
+
596
+ expect(() => TypeDefaults.getDefaultEntityTypePath(object)).toThrowError(TypeDefaults.NO_TYPE_PATH);
597
+ });
552
598
  });//getDefaultEntityTypePath
553
599
 
554
600
  describe('getDefaultIdentifierPropertiesFromObject', () =>{
@@ -622,6 +668,30 @@ describe('Type Defaults', () =>{
622
668
  expect(defaultIdentifiers).toHaveLength(1);
623
669
  });
624
670
 
671
+ it('LCSMaterial - processAsItem=true', () =>{
672
+ const object = {
673
+ flexPLMObjectClass: 'LCSMaterial'
674
+ };
675
+ TypeDefaults.applyConfig({ LCSMaterial: { processAsItem: true } });
676
+ try {
677
+ const defaultIdentifiers = TypeDefaults.getDefaultIdentifierPropertiesFromObject(object);
678
+ expect(defaultIdentifiers).toContain('itemNumber');
679
+ expect(defaultIdentifiers).toHaveLength(1);
680
+ } finally {
681
+ TypeDefaults.applyConfig({});
682
+ }
683
+ });
684
+
685
+ it('LCSMaterial - processAsItem=false (default)', () =>{
686
+ const object = {
687
+ flexPLMObjectClass: 'LCSMaterial'
688
+ };
689
+ const defaultIdentifiers = TypeDefaults.getDefaultIdentifierPropertiesFromObject(object);
690
+
691
+ expect(defaultIdentifiers).toContain('name');
692
+ expect(defaultIdentifiers).toHaveLength(1);
693
+ });
694
+
625
695
  });//getDefaultIdentifierPropertiesFromObject
626
696
 
627
697
  describe('getDefaultInformationalPropertiesFromObject', () =>{
@@ -665,5 +735,63 @@ describe('Type Defaults', () =>{
665
735
  expect(defaultIdentifiers).toHaveLength(1);
666
736
  });
667
737
 
738
+ it('LCSMaterial - processAsItem=true', () =>{
739
+ const object = {
740
+ flexPLMObjectClass: 'LCSMaterial'
741
+ };
742
+
743
+ TypeDefaults.applyConfig({ LCSMaterial: { processAsItem: true } });
744
+ try {
745
+ const defaultIdentifiers = TypeDefaults.getDefaultInformationalPropertiesFromObject(object);
746
+ expect(defaultIdentifiers).toContain('name');
747
+ expect(defaultIdentifiers).toHaveLength(1);
748
+ } finally {
749
+ TypeDefaults.applyConfig({});
750
+ }
751
+ });
752
+
753
+ it('LCSMaterial - processAsItem=false (default) yields no informational props', () =>{
754
+ const object = {
755
+ flexPLMObjectClass: 'LCSMaterial'
756
+ };
757
+
758
+ const defaultIdentifiers = TypeDefaults.getDefaultInformationalPropertiesFromObject(object);
759
+ expect(defaultIdentifiers).toHaveLength(0);
760
+ });
761
+
668
762
  });//getDefaultInformationalPropertiesFromObject
763
+
764
+ describe('applyConfig', () => {
765
+ afterEach(() => {
766
+ TypeDefaults.applyConfig({});
767
+ });
768
+
769
+ it('sets processLCSMaterialAsItem=true when processAsItem=true', () => {
770
+ TypeDefaults.applyConfig({ LCSMaterial: { processAsItem: true } });
771
+ expect(TypeDefaults.processLCSMaterialAsItem).toBe(true);
772
+ });
773
+
774
+ it('sets processLCSMaterialAsItem=true when processAsItem=\"true\" (string)', () => {
775
+ TypeDefaults.applyConfig({ LCSMaterial: { processAsItem: 'true' } });
776
+ expect(TypeDefaults.processLCSMaterialAsItem).toBe(true);
777
+ });
778
+
779
+ it('sets processLCSMaterialAsItem=false when processAsItem=false', () => {
780
+ TypeDefaults.processLCSMaterialAsItem = true;
781
+ TypeDefaults.applyConfig({ LCSMaterial: { processAsItem: false } });
782
+ expect(TypeDefaults.processLCSMaterialAsItem).toBe(false);
783
+ });
784
+
785
+ it('sets processLCSMaterialAsItem=false when LCSMaterial missing', () => {
786
+ TypeDefaults.processLCSMaterialAsItem = true;
787
+ TypeDefaults.applyConfig({});
788
+ expect(TypeDefaults.processLCSMaterialAsItem).toBe(false);
789
+ });
790
+
791
+ it('sets processLCSMaterialAsItem=false when config is null/undefined', () => {
792
+ TypeDefaults.processLCSMaterialAsItem = true;
793
+ TypeDefaults.applyConfig(undefined);
794
+ expect(TypeDefaults.processLCSMaterialAsItem).toBe(false);
795
+ });
796
+ });
669
797
  });
@@ -2,8 +2,23 @@ export class TypeDefaults {
2
2
  static NO_ENTITY_TYPE = 'Not able to determine the entity type of the entity object';
3
3
  static NO_OBJECT_CLASS = 'Please ensure that the flexPLMObjectClass property is provided.';
4
4
  static NO_TYPE_PATH = 'Please ensure that the flexPLMTypePath property is provided.';
5
+ static processLCSMaterialAsItem = false;
5
6
  constructor() {
6
7
  }
8
+
9
+ /** Applies values from the resolved config to TypeDefaults static state.
10
+ * Currently toggles whether LCSMaterial is treated as an item (new) or a
11
+ * custom-entity (old) based on config.LCSMaterial.processAsItem.
12
+ * Technically this could cause side effects if different parts of the code
13
+ * expect different behavior, but in practice * @param config will be
14
+ * consistent across the app and this is simpler than passing this config
15
+ * through multiple layers of function calls.
16
+ */
17
+ static applyConfig(config: any): void {
18
+ const val = config?.LCSMaterial?.processAsItem;
19
+ TypeDefaults.processLCSMaterialAsItem =
20
+ val === true || (typeof val === 'string' && val.toLowerCase() === 'true');
21
+ }
7
22
  /**Takes in full entity and returs the default FlexPLM
8
23
  * object class.
9
24
  *
@@ -87,7 +102,7 @@ export class TypeDefaults {
87
102
  */
88
103
 
89
104
  static getDefaultIdentifierProperties(entity): string[] {
90
- const identifierProps = [];
105
+ const identifierProps: string[] = [];
91
106
  const entityType = this.getEntityType(entity);
92
107
 
93
108
  switch (entityType) {
@@ -168,7 +183,13 @@ export class TypeDefaults {
168
183
  static getDefaultEntityClass(object): string {
169
184
  let entityClass = '';
170
185
  let objectClass = TypeDefaults.getObjectClass(object);
171
- if(['LCSProduct', 'LCSSKU'].includes(objectClass)){
186
+ const itemClasses = TypeDefaults.processLCSMaterialAsItem
187
+ ? ['LCSProduct', 'LCSSKU', 'LCSMaterial']
188
+ : ['LCSProduct', 'LCSSKU'];
189
+ const customEntityClasses = TypeDefaults.processLCSMaterialAsItem
190
+ ? ['LCSRevisableEntity', 'LCSLifecycleManaged', 'LCSLast']
191
+ : ['LCSRevisableEntity', 'LCSLifecycleManaged', 'LCSLast', 'LCSMaterial'];
192
+ if(itemClasses.includes(objectClass)){
172
193
  entityClass = 'item';
173
194
  }else if(['LCSProductSeasonLink', 'LCSSKUSeasonLink'].includes(objectClass)){
174
195
  entityClass = 'project-item'
@@ -176,7 +197,7 @@ export class TypeDefaults {
176
197
  entityClass = 'color';
177
198
  } else if(['LCSSeason', 'SeasonGroup'].includes(objectClass)) {
178
199
  entityClass = 'assortment';
179
- } else if(['LCSRevisableEntity', 'LCSLifecycleManaged', 'LCSLast', 'LCSMaterial'].includes(objectClass)) {
200
+ } else if(customEntityClasses.includes(objectClass)) {
180
201
  entityClass = 'custom-entity';
181
202
  }
182
203
 
@@ -201,6 +222,11 @@ export class TypeDefaults {
201
222
  case 'LCSSKU':
202
223
  typePath = 'item';
203
224
  break;
225
+ case 'LCSMaterial':
226
+ if (TypeDefaults.processLCSMaterialAsItem) {
227
+ typePath = 'item:material';
228
+ }
229
+ break;
204
230
  case 'LCSProductSeasonLink':
205
231
  case 'LCSSKUSeasonLink':
206
232
  typePath = 'project-item';
@@ -229,7 +255,7 @@ export class TypeDefaults {
229
255
  */
230
256
 
231
257
  static getDefaultIdentifierPropertiesFromObject(object): string[] {
232
- const identifierProps = [];
258
+ const identifierProps: string[] = [];
233
259
  const objectClass = TypeDefaults.getObjectClass(object);
234
260
 
235
261
  switch (objectClass) {
@@ -237,6 +263,13 @@ export class TypeDefaults {
237
263
  case 'LCSSKU':
238
264
  identifierProps.push('itemNumber');
239
265
  break;
266
+ case 'LCSMaterial':
267
+ if (TypeDefaults.processLCSMaterialAsItem) {
268
+ identifierProps.push('itemNumber');
269
+ } else {
270
+ identifierProps.push('name');
271
+ }
272
+ break;
240
273
  case 'LCSSeason':
241
274
  identifierProps.push('flexPLMSeasonName');
242
275
  break;
@@ -247,7 +280,6 @@ export class TypeDefaults {
247
280
  case 'LCSRevisableEntity':
248
281
  case 'LCSLifecycleManaged':
249
282
  case 'LCSLast':
250
- case 'LCSMaterial':
251
283
  identifierProps.push('name');
252
284
  break;
253
285
  }
@@ -265,7 +297,10 @@ export class TypeDefaults {
265
297
  static getDefaultInformationalPropertiesFromObject(object): string[] {
266
298
  const objectClass = TypeDefaults.getObjectClass(object);
267
299
  let properties:string[] = [];
268
- if ('LCSProduct' === objectClass) {
300
+ const itemClasses = TypeDefaults.processLCSMaterialAsItem
301
+ ? ['LCSProduct', 'LCSMaterial']
302
+ : ['LCSProduct'];
303
+ if (itemClasses.includes(objectClass)) {
269
304
  properties.push('name');
270
305
  } else if ('LCSSKU' === objectClass) {
271
306
  properties.push('optionName');