navidev-abap-gw-api
Version:
API para la extracción de datos de servicios SAP GW
251 lines (250 loc) • 14.4 kB
JavaScript
;
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;