diff --git a/entity/Offeritem_entity/entityfields/quantity/onValidation.js b/entity/Offeritem_entity/entityfields/quantity/onValidation.js index b6b200a8090a588e8b3dc92419ce03155b2898e4..7797e12bfd656b1ca61bd99adbf43b5c7d4db5e9 100644 --- a/entity/Offeritem_entity/entityfields/quantity/onValidation.js +++ b/entity/Offeritem_entity/entityfields/quantity/onValidation.js @@ -1,10 +1,8 @@ import("system.translate"); -import("system.logging"); import("system.result"); import("system.vars"); -logging.log("validate") if (parseInt(vars.get("$field.QUANTITY")) <= 0) { result.string(translate.text("${QUANTITY_LOWER_THAN_1}")); -} \ No newline at end of file +} diff --git a/entity/Prod2prod_entity/Prod2prod_entity.aod b/entity/Prod2prod_entity/Prod2prod_entity.aod index a6c4e305ff501ff5c3a5ddafed8e664845a48475..ff0f7aa649bb92f6cb269c95d11a47769de19e08 100644 --- a/entity/Prod2prod_entity/Prod2prod_entity.aod +++ b/entity/Prod2prod_entity/Prod2prod_entity.aod @@ -139,15 +139,11 @@ <onDelete>%aditoprj%/entity/Prod2prod_entity/recordcontainers/jdito/onDelete.js</onDelete> <recordFields> <element>UID.value</element> - <element>PARENTID.value</element> - <element>PROD2PRODID.value</element> + <element>SOURCE_ID.value</element> + <element>DEST_ID.value</element> <element>QUANTITY.value</element> - <element>OPTIONAL.value</element> - <element>TAKEPRICE.value</element> <element>PRODUCTCODE.value</element> <element>PRODUCTID.value</element> - <element>SOURCE_ID.value</element> - <element>DEST_ID.displayValue</element> </recordFields> </jDitoRecordContainer> </recordContainers> diff --git a/entity/Prod2prod_entity/recordcontainers/jdito/contentProcess.js b/entity/Prod2prod_entity/recordcontainers/jdito/contentProcess.js index 1eca5fb315ce03cf0f9cd20ce70f3b869cddd834..2e71e4c9dd769dfb2ac8d258de4574683599ad0d 100644 --- a/entity/Prod2prod_entity/recordcontainers/jdito/contentProcess.js +++ b/entity/Prod2prod_entity/recordcontainers/jdito/contentProcess.js @@ -1,3 +1,4 @@ +import("system.logging"); import("system.neon"); import("system.result"); import("system.vars"); @@ -5,17 +6,138 @@ import("system.db"); import("system.util"); import("Product_lib"); +/** + * Calculate the root elements for this tree. + * + * @param productRootID string + * @param rows TreeData[] + * @return string[] + */ +function calculateRootElements (productRootID, rows) { + return rows.filter(function (row) { + // Filter predicate if the DIST_ID matches. + return row[2] === productRootID; + }).map(function (row) { + // Map to PROD2PROD_ID. + return row[0]; + }); +} + +/** +* Calculates a mapping object which has the PROD2PROD_ID as +* key and the full TreeData array as value. +* +* @param rows TreeData[] +* @return {[key: TreeData]} +*/ +function buildProd2ProdIDMapping (rows) { + var mapping = {} + + rows.forEach(function(row) { + // Create new property which PROD2PROD_ID as key and data + // as value. + mapping[row[0]] = row; + }); + + return mapping; +} + +/** + * Calcualtes the children mapping structure which has the DIST_ID + * as key and an array of PROD2PROD_IDs as value. + * + * @param rows TreeData[] + * @return {[key: string[]]} + */ +function buildChildrenMapping(rows) { + var parrentMapping = {} + + rows.forEach(function (row) { + // Create empty array if not created previously. + if (parrentMapping[row[2]] === undefined) + parrentMapping[row[2]] = [] + + // Push with DIST_ID as key and PROD2PROD_ID as value. + parrentMapping[row[2]].push(row[0]); + }) + + return parrentMapping +} + +/** + * Calculates the graph starting from the given elementID. + */ +function buildGraph (elementID, parentElementID, mappingStructure, prod2prodIdMapping) { + var elements = [] + + // Get the PROD2PROD data array and copy it. + // Copying is requried due to mutability of arrays. + var elementData = prod2prodIdMapping[elementID].slice(0); + + // Just as an error prevention. + if (elementData === undefined) + return elements; + + // Generate new PROD2PROD_ID to create a uniqueness between the PROD2PROD objects. + var virtualProd2ProdId = util.getNewUUID(); + + // Override actual PROD2PROD_ID with new ID. + elementData[0] = virtualProd2ProdId; + + // Override parent id to match overriden prod2prodId of parent + if (parentElementID === null || parentElementID === undefined) + // Describes an root element + elementData[2] = null; + else + elementData[2] = parentElementID; + + // Push element data to elements array of this graph. + elements.push(elementData); + + // Search for children + var childrens = mappingStructure[elementData[1]]; + + if (childrens !== undefined && childrens.length > 0) { + // Build graph for each children + + childrens.forEach(function(children) { + // Recursive function call (!) + + var graphResult = buildGraph(children, elementData[0], mappingStructure, prod2prodIdMapping); + + graphResult.forEach(function(res) {elements.push(res)}) + }); + } + + return elements; +} + if (vars.get("$sys.recordstate") != neon.OPERATINGSTATE_NEW) { var prodid = vars.exists("$param.ProductId_param") && vars.get("$param.ProductId_param") != null ? vars.get("$param.ProductId_param") : ""; if(prodid != "") { - var p2pUtils = new Prod2ProdUtils(prodid); - result.object(p2pUtils.getPartsListForRecordContainer()); + // First 3 columns are crucial, the rest is optional. + var data = db.table("select PROD2PRODID, SOURCE_ID, DEST_ID, QUANTITY, PRODUCTCODE, PRODUCTID " + + "from PROD2PROD join PRODUCT on PROD2PROD.SOURCE_ID = PRODUCTID " + + "order by PRODUCTCODE"); + + var prod2prodIdMapping = buildProd2ProdIDMapping(data); + var childrenMapping = buildChildrenMapping(data); + var rootElements = calculateRootElements(prodid, data); + + var allData = [] + + rootElements.forEach(function(rg) { + var graphData = buildGraph(rg, null, childrenMapping, prod2prodIdMapping) + graphData.forEach(function (gd) { allData.push(gd); }) + }) + + result.object(allData); } } else { result.object([]); -} \ No newline at end of file +} diff --git a/neonContext/Prod2prod/Prod2prod.aod b/neonContext/Prod2prod/Prod2prod.aod index 3599d2911411108281f6660aa074a9d6087a9979..5f3312e66db92e967ab68ffbf4668b4fafcbf9bb 100644 --- a/neonContext/Prod2prod/Prod2prod.aod +++ b/neonContext/Prod2prod/Prod2prod.aod @@ -16,5 +16,9 @@ <name>428b22a1-427f-4547-a478-964442078bc1</name> <view>Prod2ProdEdit_view</view> </neonViewReference> + <neonViewReference> + <name>257aa20f-d6b4-4a64-8f61-bb62b6ef49c8</name> + <view>Prod2prodTable_view</view> + </neonViewReference> </references> </neonContext> diff --git a/neonView/Prod2prodFilter_view/Prod2prodFilter_view.aod b/neonView/Prod2prodFilter_view/Prod2prodFilter_view.aod index b22717b6dc3e85d0af6f3d8b88d740f7f67ceb3c..eeaf321c7d4fb8abf36121ada2ec9a394a9c7aa2 100644 --- a/neonView/Prod2prodFilter_view/Prod2prodFilter_view.aod +++ b/neonView/Prod2prodFilter_view/Prod2prodFilter_view.aod @@ -11,7 +11,7 @@ <children> <treetableViewTemplate> <name>Partlist</name> - <parentField>PARENTID</parentField> + <parentField>DEST_ID</parentField> <favoriteActionGroup1>alter</favoriteActionGroup1> <titleField>PRODUCTCODE</titleField> <descriptionField>QUANTITY</descriptionField> diff --git a/neonView/Prod2prodTable_view/Prod2prodTable_view.aod b/neonView/Prod2prodTable_view/Prod2prodTable_view.aod new file mode 100644 index 0000000000000000000000000000000000000000..7b14b322f32eb0d867d8fbea6f83da35863a9503 --- /dev/null +++ b/neonView/Prod2prodTable_view/Prod2prodTable_view.aod @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="UTF-8"?> +<neonView xmlns="http://www.adito.de/2018/ao/Model" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" VERSION="1.1.0" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/neonView/1.1.0"> + <name>Prod2prodTable_view</name> + <majorModelMode>DISTRIBUTED</majorModelMode> + <layout> + <boxLayout> + <name>layout</name> + </boxLayout> + </layout> + <children> + <tableViewTemplate> + <name>data</name> + <entityField>#ENTITY</entityField> + <columns> + <neonTableColumn> + <name>1a1880db-4a23-4c0f-9a87-7da546461cca</name> + <entityField>PARENTID</entityField> + </neonTableColumn> + <neonTableColumn> + <name>40710edc-b8ef-43fa-8f8c-99add3946c47</name> + <entityField>SOURCE_ID</entityField> + </neonTableColumn> + <neonTableColumn> + <name>673daab5-c779-49db-aaf4-851f2d0a2c95</name> + <entityField>QUANTITY</entityField> + </neonTableColumn> + <neonTableColumn> + <name>0c99aadc-0798-45eb-b015-8cdef16bf0f1</name> + <entityField>OPTIONAL</entityField> + </neonTableColumn> + <neonTableColumn> + <name>da0abba6-9ea0-4503-9b51-8d232f345aa8</name> + <entityField>TAKEPRICE</entityField> + </neonTableColumn> + </columns> + </tableViewTemplate> + </children> +</neonView> diff --git a/neonView/ProductMain_view/ProductMain_view.aod b/neonView/ProductMain_view/ProductMain_view.aod index 7ac4a87c4db385d9c6be171334d2084be0cbe6e9..ed9d388e2641f2c4c61afc9c7c36c7144c580d4c 100644 --- a/neonView/ProductMain_view/ProductMain_view.aod +++ b/neonView/ProductMain_view/ProductMain_view.aod @@ -29,6 +29,11 @@ <entityField>#ENTITY</entityField> <view>ProductDescription_view</view> </neonViewReference> + <neonViewReference> + <name>cbcf23d7-1d80-41c5-8041-8e768fa91487</name> + <entityField>ProductLinks</entityField> + <view>Prod2prodTable_view</view> + </neonViewReference> <neonViewReference> <name>7f416115-ff89-45ca-be10-ed568cac266c</name> <entityField>ProductLinks</entityField> diff --git a/process/OfferOrder_lib/process.js b/process/OfferOrder_lib/process.js index 1b286d5154d3bec99a17fff08da8f70ef755b303..bb660ba440d2f9ebebe90fa4883372927b681d18 100644 --- a/process/OfferOrder_lib/process.js +++ b/process/OfferOrder_lib/process.js @@ -272,10 +272,9 @@ ItemUtils.prototype.insertPartsList = function(columns, productId, assignedTo, c columns = columns.concat(additionalProductInfo.map(function(item) {return item[0]})); var colTypes = db.getColumnTypes(table, columns); - // partsList[rootProdId] = root node - if (partsList[rootProdId] != undefined) // if product has a parts list + if (partsList.root != undefined) // if product has a parts list { - __itemInsertStatement(partsList[rootProdId], assignedTo, currency, contactId); + __itemInsertStatement(partsList.root, assignedTo, currency, contactId); } if (statements.length > 0) diff --git a/process/Product_lib/process.js b/process/Product_lib/process.js index 6ee4f51c5dd21b8a37604f9d4e22269358babdee..7f1383f16f3f237b640367c13bc3da8bd2d5bf39 100644 --- a/process/Product_lib/process.js +++ b/process/Product_lib/process.js @@ -393,14 +393,15 @@ ProductUtils.removeImage = function(pProductId) * @class * */ -function Prod2ProdUtils(productId) { +function Prod2ProdUtils(productId) +{ this.productId = productId; this.data = undefined; } /** - * Delivers an Object containing parts list structure for passed product "productId" (Constructor parameter) - * + * Delivers an Object containing parts list structure for passed product "pProductId" (Constructor parameter) + * * @return {Object} { $prod2prodid$ { <br> * ids: [ Array containing child Prod2ProdIds for passed product "pProductId" (Constructor parameter) ] <br> * , rowdata: [ "PROD2PRODID", "DEST_ID", "SOURCE_ID", "QUANTITY", "OPTIONAL", "TAKEPRICE" ] from DB-Table PROD2PROD <br> @@ -409,10 +410,13 @@ function Prod2ProdUtils(productId) { * , quantity: "Quantity" <br> * , optional: "0" = not optional, "1" = optional <br> * , takeprice: "0" = no price, "1" = price <br> + * , productcode: "Productcode" <br> + * , productid: "Productid" <br> * } } */ -Prod2ProdUtils.prototype.getPartsListObject = function() { - return this._relateChilds().getTreeObject(); +Prod2ProdUtils.prototype.getPartsListObject = function() +{ + return this._relateChilds(); } /** @@ -434,9 +438,27 @@ Prod2ProdUtils.prototype.getPartsListObject = function() { * , "PRODUCTCODE" * , "PRODUCTID"] ] */ -Prod2ProdUtils.prototype.getPartsListForRecordContainer = function() { - var tree = this._relateChilds(); - return tree.toArray(7); +Prod2ProdUtils.prototype.getPartsListForRecordContainer = function() +{ + var ret = []; + var childs = this._relateChilds(); + + __push(childs.root); + + function __push(pObj) + { + for(var i = 0; i < pObj.ids.length; i++) + { + var rowdata = childs[pObj.ids[i]].rowdata; + var UID = util.getNewUUID(); + var PARENTID = childs[pObj.ids[i]].destid; + + rowdata = [UID, PARENTID].concat(rowdata); + ret.push(rowdata); + __push( childs[pObj.ids[i]] ); + } + } + return ret; } /** @@ -446,18 +468,21 @@ Prod2ProdUtils.prototype.getPartsListForRecordContainer = function() { * * @return {String[]} [ "SOURCE_ID" ] */ -Prod2ProdUtils.prototype.getPartsListProdIds = function() { +Prod2ProdUtils.prototype.getPartsListProdIds = function() +{ var ret = []; - var childs = this._relateChilds().getTreeObject(); + var childs = this._relateChilds(); __push(childs.root); return ret; - function __push(pObj) { - for (var i = 0; i < pObj.ids.length; i++) { + function __push(pObj) + { + for(var i = 0; i < pObj.ids.length; i++) + { ret.push(childs[pObj.ids[i]].sourceid); - __push(childs[pObj.ids[i]]); + __push( childs[pObj.ids[i]] ); } } } @@ -469,7 +494,8 @@ Prod2ProdUtils.prototype.getPartsListProdIds = function() { * * @return {String[]} [ "DEST_ID" ] */ -Prod2ProdUtils.prototype.getParentProdIds = function() { +Prod2ProdUtils.prototype.getParentProdIds = function() +{ var ret = []; var parents = this._relateParents(); @@ -477,10 +503,12 @@ Prod2ProdUtils.prototype.getParentProdIds = function() { return ret; - function __push(pObj) { - for (var i = 0; i < pObj.ids.length; i++) { + function __push(pObj) + { + for(var i = 0; i < pObj.ids.length; i++) + { ret.push(parents[pObj.ids[i]].destid); - __push(parents[pObj.ids[i]]); + __push( parents[pObj.ids[i]] ); } } } @@ -491,9 +519,10 @@ Prod2ProdUtils.prototype.getParentProdIds = function() { * * @ignore */ -Prod2ProdUtils.prototype._initProd2ProdData = function() { +Prod2ProdUtils.prototype._initProd2ProdData = function() +{ if (this.data == undefined) { - this.data = db.table("select SOURCE_ID, DEST_ID, PROD2PRODID, QUANTITY, OPTIONAL, TAKEPRICE, PRODUCTCODE, PRODUCTID, SOURCE_ID, DEST_ID " + this.data = db.table("select PROD2PRODID, DEST_ID, SOURCE_ID, QUANTITY, OPTIONAL, TAKEPRICE, PRODUCTCODE, PRODUCTID " + "from PROD2PROD join PRODUCT on PROD2PROD.SOURCE_ID = PRODUCTID " + "order by PRODUCTCODE "); } @@ -502,78 +531,77 @@ Prod2ProdUtils.prototype._initProd2ProdData = function() { /** * object tree to relate products by DEST_ID / SOURCE_ID. **/ -Prod2ProdUtils.prototype._buildTree = function(supervised) { +Prod2ProdUtils.prototype._buildTree = function(pSupervised) +{ this._initProd2ProdData(); - var productId = this.productId; + + var tree = { root: {ids: [], sourceid: this.productId } }; - var tree = DataTree.begin(this.productId).addArray(this.data, - function(pUid, pNode) + if(pSupervised) + tree = { root: {ids: [], destid: this.productId } }; + + for (var i = 0; i < this.data.length; i++) { - if (pUid == productId) + var prod2prodid = this.data[i][0]; + if ( tree[prod2prodid] == undefined ) { - pNode["sourceid"] = productId; - if (supervised) - { - pNode["destid"] = productId; - } - } - else - { - pNode["destid"] = pNode.parent; - pNode["sourceid"] = pUid; - - if (pNode.data != undefined) { - pNode["quantity"] = pNode.data[1]; - pNode["optional"] = pNode.data[2]; - pNode["takeprice"] = pNode.data[3]; - pNode["productcode"] = pNode.data[4]; - pNode["productid"] = pNode.data[5]; - } + tree[prod2prodid] = { + ids: [] + , rowdata: this.data[i].slice(0)//copy to get NativeArray for concatenation + , destid: this.data[i][1] + , sourceid: this.data[i][2] + , quantity: this.data[i][3] + , optional: this.data[i][4] + , takeprice: this.data[i][5] + , productcode: this.data[i][6] + , productid: this.data[i][7] + }; } } - ); + + return tree; - return tree; } -Prod2ProdUtils.prototype._relateChilds = function() { +Prod2ProdUtils.prototype._relateChilds = function() +{ var tree = this._buildTree(false); - __relate(this.productId); + + __relate("root"); return tree; - function __relate(id) { - var treeObject = tree.getTreeObject(); - if (treeObject[id] != undefined) + function __relate(pID) + { + for ( var id in tree ) { - for (var treeId in treeObject) { - if (treeObject[treeId].destid == treeObject[id].sourceid && treeObject[id].ids.indexOf(treeId) == -1) { - treeObject[id].ids.push(treeId); - __relate(treeId); - } - } + if ( tree[id].destid == tree[pID].sourceid && tree[pID].ids.indexOf(id) == -1 ) + { + tree[pID].ids.push(id); + __relate(id); + } } } } -Prod2ProdUtils.prototype._relateParents = function() { +Prod2ProdUtils.prototype._relateParents = function() +{ var tree = this._buildTree(true); - __relate(this.productId); + __relate("root"); return tree; - function __relate(id) { - var treeObject = tree.getTreeObject(); - if (treeObject[id] != undefined) + function __relate(pID) + { + for ( var id in tree ) { - for (var treeId in treeObject) { - if (treeObject[treeId].sourceid == treeObject[id].destid && treeObject[id].ids.indexOf(treeId) == -1) { - treeObject[id].ids.push(treeId); - __relate(treeId); - } - } + if ( tree[id].sourceid == tree[pID].destid && tree[pID].ids.indexOf(id) == -1 ) + { + tree[pID].ids.push(id); + __relate(id); + } } } } \ No newline at end of file