UNPKG

navidev-abap-gw-api

Version:

API para la extracción de datos de servicios SAP GW

251 lines (250 loc) 14.4 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); //import { AdtConnection } from "navidev-adt-api"; const Result_1 = require("navidev-adt-api/dist/shared/core/Result"); const xmlParser_1 = __importDefault(require("../shared/utilities/parser/xmlParser")); const commonConstants_1 = require("../shared/constants/commonConstants"); const metadataApp_1 = __importDefault(require("./metadataApp")); const metadataConstants_1 = require("./metadataConstants"); const annotationVocabV2App_1 = __importDefault(require("./annotationVocabV2App")); class MetadataV2App extends metadataApp_1.default { constructor(connectionController, serviceBindingInfo, options) { super(connectionController, serviceBindingInfo, options); } /** * Obtiene el contenido del metadata * @param serviceBindingInfo */ getMetadataInfo() { return __awaiter(this, void 0, void 0, function* () { // En el odata v2 la lectura de datos del metadata se divide en dos partes. Datos del metadata en si mismo y // lectura de las anotaciones o vocabulario. El primero define que entidades, como se relacionan y campos que la componen. // El segundo son las anotaciones fiori aunque tambien puede contener otra información, todo eso hay que mirarlo. let resultMetadataContent = yield this.getMetadata(); if (resultMetadataContent.isSuccess) { // La lectura de anotaciones solo se realiza si el servicio tiene dicha URL, y se hará en una clase aparte porque tiene su complejidad leerlo. // Eso si, la info obtenida se complementa a la obtenida en el metadata if (!this.options.ignoreAnnotVocab) this.metadataContent = yield new annotationVocabV2App_1.default(this.connectionController, this.serviceBindingInfo, this.metadataContent).getAnnotVocab(); return Result_1.Result.ok(resultMetadataContent.getValue()); } else { return Result_1.Result.fail(resultMetadataContent.getErrorValue()); } }); } getMetadata() { return __awaiter(this, void 0, void 0, function* () { var _a; let resultLoad = yield this.loadMetadata((_a = this.serviceBindingInfo) === null || _a === void 0 ? void 0 : _a.serviceUrl); if (resultLoad.isSuccess) { let bodyParsed = xmlParser_1.default.fullParse(resultLoad.getValue()); this.metadataContent.namespace = this.extractNamespace(bodyParsed); this.extractEntities(bodyParsed); return Result_1.Result.ok(this.metadataContent); } else { return Result_1.Result.fail(resultLoad.getErrorValue()); } }); } extractEntities(bodyParsed) { // Todos los nodos que son array los convierto a array, ya que si solo hay un elemento no se convierte a array. Y quiero procesarlo // como si fuera un array para simplificar el código. this.entityTypes = xmlParser_1.default.xmlArray(bodyParsed["edmx:Edmx"]["edmx:DataServices"].Schema.EntityType); // Se ignoran las entidades de SAP se añadirán posteriormente si hace flata. xmlParser_1.default.xmlArray(bodyParsed["edmx:Edmx"]["edmx:DataServices"].Schema.EntityContainer .EntitySet) .filter((rowFilter) => !rowFilter["@_Name"].startsWith(commonConstants_1.PREFIX_SAP_IN_ENTITIES.SAP)) .forEach((rowEntity) => { this.metadataContent.entities.push(this.fillEntityInfo(rowEntity, bodyParsed)); }); } /** * Devuelve un objeto con las datos de la entity informada */ fillEntityInfo(rowEntity, bodyParsed) { var _a, _b, _c, _d; let entityInfo = { name: rowEntity["@_Name"], entityType: rowEntity["@_EntityType"], entityTypeName: this.extractEntityName(this.metadataContent.namespace, rowEntity["@_EntityType"]), creatable: (_a = rowEntity["@_sap:creatable"]) !== null && _a !== void 0 ? _a : false, deletable: (_b = rowEntity["@_sap:deletable"]) !== null && _b !== void 0 ? _b : false, updatable: (_c = rowEntity["@_sap:updatable"]) !== null && _c !== void 0 ? _c : false, searchable: (_d = rowEntity["@_sap:searchable"]) !== null && _d !== void 0 ? _d : false, label: "", fields: [], }; let entity = this.entityTypes.find((rowEntityType) => rowEntityType["@_Name"] === entityInfo.entityTypeName); if (entity) { entityInfo.label = entity["@_sap:label"]; if (!this.options.ignoreFields) entityInfo.fields = this.extractEntityTypeFields(bodyParsed, entity, entityInfo); } return entityInfo; } /** * Extrae los campos de la entityType * @param entityType * @returns */ extractEntityTypeFields(bodyParsed, entityType, entityInfo) { let fields = []; let keyFields = xmlParser_1.default.xmlArray(entityType.Key.PropertyRef); xmlParser_1.default.xmlArray(entityType.Property).forEach((rowProperty) => { var _a, _b, _c, _d, _e, _f, _g, _h, _j; let field = { name: rowProperty["@_Name"], type: rowProperty["@_Type"], label: (_a = rowProperty["@_sap:label"]) !== null && _a !== void 0 ? _a : "", heading: (_b = rowProperty["@_sap:label"]) !== null && _b !== void 0 ? _b : "", // Campo que aparece en el Odata V4 maxLength: (_c = rowProperty["@_MaxLength"]) !== null && _c !== void 0 ? _c : "", nullable: (_d = rowProperty["@_Nullable"]) !== null && _d !== void 0 ? _d : false, quickInfo: (_e = rowProperty["@_sap:quickinfo"]) !== null && _e !== void 0 ? _e : "", unit: (_f = rowProperty["@_sap:unit"]) !== null && _f !== void 0 ? _f : "", semantics: (_g = rowProperty["@_sap:semantics"]) !== null && _g !== void 0 ? _g : "", hiddenFilter: false, isCurrency: rowProperty["@_sap:semantics"] == metadataConstants_1.SEMANTICS_TYPES.CURRENCY ? true : false, key: keyFields.findIndex((keyField) => keyField["@_Name"] === rowProperty["@_Name"]) == -1 ? false : true, searchable: false, precision: (_h = rowProperty["@_Precision"]) !== null && _h !== void 0 ? _h : 0, scale: (_j = rowProperty["@_Scale"]) !== null && _j !== void 0 ? _j : 0, valueHelpInfo: { entityValueHelp: "", forValidation: false, parametersInOut: [], parametersDisplay: [], }, hidden: false, }; if (!this.options.ignoreValueHelp) { // Las entidades que empiezan por "SAP__" son internas de SAP (moneda, unidad de medida, etc) y no las añado // a la lista de entidades con campos semánticos. if (rowProperty["@_sap:value-list"] != undefined && rowProperty["@_sap:value-list"] != "" && !entityInfo.name.startsWith(commonConstants_1.PREFIX_SAP_IN_ENTITIES.SAP)) this.processFieldValueList(bodyParsed, entityInfo, field); // Proceso la ayuda para búsqueda, o lista de valores, como sale en el metadata, del campo. Solo proceso los // campos que no sean entidades de SAP. if (rowProperty["@_sap:semantics"] != undefined && rowProperty["@_sap:semantics"] != "" && !entityInfo.name.startsWith(commonConstants_1.PREFIX_SAP_IN_ENTITIES.SAP)) this.processFieldSemantics(bodyParsed, entityInfo, field); } fields.push(field); }); return fields; } /** * Procesa el campo que tiene un campo semantico asociado. Esos campos son de moneda o unidad de medida * @param bodyParsed * @param entityInfo * @param field */ processFieldSemantics(bodyParsed, entityInfo, field) { // Leemos las entidades de SAP xmlParser_1.default.xmlArray(bodyParsed["edmx:Edmx"]["edmx:DataServices"].Schema.EntityContainer .EntitySet) .filter((rowFilter) => rowFilter["@_Name"].startsWith(commonConstants_1.PREFIX_SAP_IN_ENTITIES.SAP)) .every((rowEntitySAP) => { // Obtenemos el nombre de la entidad para poder buscar en el nodo donde están los campos de dicha entidad. const entityTypeName = this.extractEntityName(this.metadataContent.namespace, rowEntitySAP["@_EntityType"]); // let entity = this.entityTypes.find((rowEntityType) => rowEntityType["@_Name"] === entityTypeName); if (entity) { // Buscamos el campo con el valor semantico que el campo de la entidad pasada por parámetro. const fieldSemantic = entity.Property.find((rowField) => rowField["@_sap:semantics"] === field.semantics); if (fieldSemantic) { field.valueHelpInfo.entityValueHelp = rowEntitySAP["@_Name"]; field.valueHelpInfo.forValidation = true; // Los campos de Input pongo el que tiene valor semántico field.valueHelpInfo.parametersInOut.push({ entityField: field.name, valueListField: fieldSemantic["@_Name"], onlyDisplay: false, }); field.valueHelpInfo.parametersDisplay = entity.Property.map((row) => { return { field: row["@_Name"] }; }); // Miro si la entidad del objeto semantico esta añadido en el modelo interno, si no es así, lo añado. if (this.metadataContent.entities.findIndex((row) => row.name == rowEntitySAP["@_Name"]) == -1) this.metadataContent.entities.push(this.fillEntityInfo(rowEntitySAP, bodyParsed)); return false; } } return true; }); } /** * Proceso la lista de valores, o ayuda para búsqueda, del campo * @param bodyParsed * @param entityInfo * @param field */ processFieldValueList(bodyParsed, entityInfo, field) { // Los datos de la ayuda para búsqueda del campo están dentro del array "Annotations". Y se buscan a partir de la concatenacion // del namespace, entidad y nombre de campo. let annotationField = bodyParsed["edmx:Edmx"]["edmx:DataServices"].Schema.Annotations.find((row) => row["@_Target"] == `${entityInfo.entityType}/${field.name}`); if (annotationField) { // Valor que indica si se usará para validación. Si no se quiere usar para validación el registro no vendra if (annotationField.Annotation.findIndex((row) => row["@_Term"] == "Common.ValueListForValidation") != -1) field.valueHelpInfo.forValidation = true; // Registro donde contiene la entidad de la ayuda para búsqueda y los campos que la contendrán let valueList = annotationField.Annotation.find((row) => row["@_Term"] == "Common.ValueList"); if (valueList) { valueList.Record.PropertyValue.forEach((row) => { if (row["@_Property"] == metadataConstants_1.PROPERTY_VALUES.COLLECTION_PATH) field.valueHelpInfo.entityValueHelp = row["@_String"]; // else if (row["@_Property"] == "SearchSupported") // field.valueHelpInfo.entityValueHelp = row["@_Bool"]; else if (row["@_Property"] == "Parameters") this.processParametersValueHelp(field, row["Collection"]["Record"]); }); } } } /** * Procesa los parámetros de la ayuda para búsqueda donde están los campos que la formarán y * los campos de entrada y salida. * @param field * @param valueListParameters */ processParametersValueHelp(field, valueListParameters) { valueListParameters.forEach((row) => { // Info de como se mapearán los valores de la ayuda para búsqueda con los campos de la entidad if (row["@_Type"] == metadataConstants_1.ANNOTATION_FIELD_TERM.VALUE_LIST_PARAM_INOUT_V2 || row["@_Type"] == metadataConstants_1.ANNOTATION_FIELD_TERM.VALUE_LIST_PARAM_OUT_V2) { field.valueHelpInfo.parametersInOut.push({ entityField: row.PropertyValue.find((row) => row["@_Property"] == "LocalDataProperty")["@_PropertyPath"], valueListField: row.PropertyValue.find((row) => row["@_Property"] == "ValueListProperty")["@_String"], onlyDisplay: row["@_Type"] == metadataConstants_1.ANNOTATION_FIELD_TERM.VALUE_LIST_PARAM_OUT_V2 ? true : false, }); } else if (row["@_Type"] == "Common.ValueListParameterDisplayOnly") { field.valueHelpInfo.parametersDisplay.push({ field: row["PropertyValue"]["@_String"], }); } }); } } exports.default = MetadataV2App;