//@include lib_Class.js
/**
* Rendering Excel file from a Excel template.
*
* This can either be used for creating a new Document in the archive (`targetId` specified) or can create a new version on an existing object (`objId`).
*
* Which fields will be written, is specified by the template (first line of the data worksheet contains the ObjKeys)
* or by the first Sord of the data.sords array (all ObjKeys).
*
* @author ELO Digital Office GmbH
* @version 1.1
*
* @eloas
*
* @requires sol.common.StringUtils
* @requires sol.common.ObjectUtils
* @requires sol.common.DateUtils
* @requires sol.common.SordUtils
* @requires sol.common.RepoUtils
* @requires sol.common.Template
* @requires sol.common.as.ExcelDocument
*
*/
sol.define("sol.common.as.renderer.Excel", {
requiredConfig: ["templateId"],
/**
* @cfg {String} templateId (required)
* The template which should be rendered
*/
/**
* @cfg {String} targetId
* The target folder to store the rendered document
*/
/**
* @cfg {String} objId
* The rendered document will be saved as a version of this object
* Either `targetId` or `objId` has to be defined.
*/
/**
* @cfg {Boolean} copyMetaData
* If `true`, the mask and the metadata of the template will be copied to the new document
*/
/**
* @cfg {String} [datasheet="Data"]
* Specifies on which worksheet the data should be written
*/
/**
* @private
* @property {String} mapPrefix
*/
mapPrefix: "MAP_",
initialize: function (config) {
var me = this;
me.$super("sol.Base", "initialize", [config]);
if (!me.objId && !me.targetId) {
throw "IllegalArgumentException: either 'targetId' or 'objId' has to defined";
}
me.datasheet = config.datasheet || "Data";
me._mapKeys = [];
},
/**
* Starts the template rendering.
* @param {String} name Name
* @param {String} data Data
* @return {Object}
*/
render: function (name, data) {
var me = this,
config = {},
templateSord;
if (me.objId) {
config.objId = me.objId;
} else {
config.name = name;
config.parentId = me.targetId;
}
config.format = "xlsx";
if (me.copyMetaData === true) {
templateSord = ixConnect.ix().checkoutSord(me.templateId, SordC.mbAllIndex, LockC.NO);
config.maskId = templateSord.mask;
config.objKeysObj = sol.common.SordUtils.getTemplateSord(templateSord).sord.objKeys;
}
return me.renderExcel(data, config);
},
/**
* @private
* @param {Object} data Data
* @param {Object} config Configuration
* @return {Object}
*/
renderExcel: function (data, config) {
var me = this,
result = {},
excelDocument;
try {
excelDocument = sol.create("sol.common.as.ExcelDocument", {});
excelDocument.openFromRepo({ objId: me.templateId });
me.fillExcelSpreadsheet(excelDocument, data);
result.objId = excelDocument.saveToRepo(config);
} catch (ex) {
me.logger.error(["error rendering report '{0}' (templateId='{1}')", config.name, me.templateId], ex);
}
return result;
},
/**
* @private
* Fills the data to an Excel spreadsheet
* @param {sol.common.as.ExcelDocument} excelDocument Excel document
* @param {Object} data Data *
*/
fillExcelSpreadsheet: function (excelDocument, data) {
var me = this,
workbook = excelDocument.workbook;
me._worksheet = workbook.worksheets.get(me.datasheet);
if (!me._worksheet) {
return;
}
// Excel renderer would be used in combination with ParentDataCollector.
// ParentDataCollector will always return data.sord as one object.
// So we ensure that data.sords is an array with 1 element
if (data && data.sord && !data.sords) {
data.sords = [data.sord];
}
if (data && data.sords && (data.sords.length > 0)) {
me.prepareColumnMapping(data.sords[0]);
me.prepareHeader();
me.writeData(data.sords);
}
},
/**
* @private
* @param {de.elo.ix.client.Sord} sord Sord
*/
prepareColumnMapping: function (sord) {
var me = this,
header = me.readHeader(sord),
columnIdx, columnDescObj;
me._columnMapping = {};
me._header = [];
if (header) {
for (columnIdx = 0; columnIdx < header.length; columnIdx++) {
columnDescObj = header[columnIdx];
columnDescObj.idx = columnIdx;
me._columnMapping[columnDescObj.key] = columnDescObj;
me._header.push(columnDescObj.key); // to preserve header order
}
}
},
* @private
* @param {de.elo.ix.client.Sord} sord Sord
* @return {Array}
*/
readHeader: function (sord) {
var me = this,
header = me.readHeaderFromWorksheet();
if (!header) {
header = me.readHeaderFromSord(sord);
}
return header;
},
* @private
* @return {Array}
*/
readHeaderFromWorksheet: function () {
var me = this,
cells = me._worksheet.getCells(),
columnIdx = 0,
cell = cells.getCell(0, columnIdx++),
headerData = [],
value;
while (cell && cell.getValue() !== null) {
value = {
key: cell.getValue() + "",
isDate: me.isDate(cell),
isNumber: me.isNumber(cell)
};
headerData.push(value);
if (sol.common.StringUtils.startsWith(value.key, me.mapPrefix)) {
me._mapKeys.push(value.key.replace(me.mapPrefix, "") + "*");
}
cell = cells.getCell(0, columnIdx++);
}
return (headerData.length > 0) ? headerData : null;
},
/**
* @private
* Checks, if a Cell is formated as number.
* @param {com.aspose.cells.Cell} cell
* @return {Boolean}
*/
isNumber: function (cell) {
var styleNumber = cell.style.getNumber();
return (styleNumber > 0 && styleNumber < 14) || (styleNumber > 22 && styleNumber < 45);
},
/**
* @private
* Checks, if a Cell is formated as date.
* @param {com.aspose.cells.Cell} cell
* @return {Boolean}
*/
isDate: function (cell) {
return cell.style.isDateTime();
},
* @private
* @param {de.elo.ix.client.Sord} sord Sord
* @return {Array}
*/
readHeaderFromSord: function (sord) {
var headerData = [],
objKey;
for (objKey in sord.objKeys) {
if (sord.objKeys.hasOwnProperty(objKey)) {
headerData.push({ key: objKey });
}
}
return (headerData.length > 0) ? headerData : null;
},
* @private
*/
prepareHeader: function () {
var me = this;
me.writeLine(0, me._header);
},
/**
* @private
* @param {de.elo.ix.client.Sord[]} rowSords Row Sords
*/
writeData: function (rowSords) {
var me = this,
line = 1;
rowSords.forEach(function (rowSord) {
var rows;
if (me._mapKeys.length > 0) {
rows = me.expandRowSord(rowSord);
if (rows) {
rows.forEach(function (row) {
me.writeLine(line++, row);
});
}
} else {
me.writeLine(line++, rowSord.objKeys);
}
});
},
/**
* @private
* Extract the lines for the map items.
* If there is a map value with an index, the line (the ObjKeys) will be repeated for each map index.
* If the `rowSord` contains `mapKeys`, those will be used and the map values will not be checked out again.
* @param {de.elo.ix.client.Sord} rowSord Row sord
* @return {Object}
*/
expandRowSord: function (rowSord) {
var me = this,
result = [],
mapitems, mapkey, tmpRow;
if (rowSord.mapKeys && !sol.common.ObjectUtils.isEmpty(rowSord.mapKeys)) {
mapitems = [];
for (mapkey in rowSord.mapKeys) {
if (rowSord.mapKeys.hasOwnProperty(mapkey)) {
mapitems.push(new KeyValue(mapkey, rowSord.mapKeys[mapkey]));
}
}
} else {
mapitems = ixConnect.ix().checkoutMap(MapDomainC.DOMAIN_SORD, rowSord.id, me._mapKeys, LockC.NO).items;
}
mapitems.forEach(function (mapitem) {
var key = me.mapPrefix + mapitem.key,
idx = me.getIndexFromName(key);
if (idx) {
if (!result[idx - 1]) {
result[idx - 1] = me.copyObject(rowSord);
}
result[idx - 1][sol.common.StringUtils.removeTrailingNumber(key)] = mapitem.value + "";
} else {
if (!tmpRow) {
tmpRow = me.copyObject(rowSord);
}
tmpRow[key] = mapitem.value + "";
}
});
if (tmpRow) {
result.push(tmpRow);
}
return (result.length > 0) ? result : [rowSord.objKeys];
},
/**
* @private
* @param {de.elo.ix.client.Sord} rowSord Row sord
* @return {Object}
*/
copyObject: function (rowSord) {
var copy = {},
prop;
for (prop in rowSord.objKeys) {
if (rowSord.objKeys.hasOwnProperty(prop)) {
copy[prop] = rowSord.objKeys[prop];
}
}
return copy;
},
/**
* @private
* @param {String} fieldName
* @return {String}
*/
getIndexFromName: function (fieldName) {
if (!fieldName) {
return null;
}
return sol.common.StringUtils.getTrailingNumber(fieldName);
},
/**
* @private
* @param {Number} rowIndex Row index
* @param {Array} rowData Row data
*/
writeLine: function (rowIndex, rowData) {
var me = this,
cells = me._worksheet.getCells(),
columnIdx, column, value;
if (sol.common.ObjectUtils.isArray(rowData)) {
for (columnIdx = 0; columnIdx < rowData.length; columnIdx++) {
cells.getCell(rowIndex, columnIdx).putValue(rowData[columnIdx]);
}
} else {
for (column in rowData) {
if (rowData.hasOwnProperty(column) && rowData[column] && me._columnMapping.hasOwnProperty(column)) {
if (me._columnMapping[column].isDate === true) {
value = new java.util.Date(sol.common.DateUtils.isoToDate(rowData[column]).getTime());
} else if (me._columnMapping[column].isNumber === true) {
try {
value = java.lang.Double.parseDouble(rowData[column].replace(",", "."));
} catch (ex) {
value = rowData[column];
}
} else {
value = rowData[column];
}
cells.getCell(rowIndex, me._columnMapping[column].idx).putValue(value);
}
}
}
}
});