diff --git a/entity/Offeritem_entity/entityfields/product_id/onValueChange.js b/entity/Offeritem_entity/entityfields/product_id/onValueChange.js index 338d9afba724543f06295e6852687c063d63bbc4..2dc7f5d987c0b34ce0729068c679995626a41707 100644 --- a/entity/Offeritem_entity/entityfields/product_id/onValueChange.js +++ b/entity/Offeritem_entity/entityfields/product_id/onValueChange.js @@ -24,9 +24,10 @@ if(pId != "" && vars.get("$sys.recordstate") == neon.OPERATINGSTATE_NEW) } var partsListObject = oiUtils.insertPartsList(pId, vars.get("$field.OFFERITEMID"), curr, contactid, language, quantity, true, vars.get("$field.OFFER_ID"), sumUpTop); + neon.setFieldValue("$field.itemInsertStatements", JSON.stringify(partsListObject["partsList"])); - if(sumUpTop)//only sum-up this price if there is no valid Price + if(sumUpTop && partsListObject["topProductInfo"])//only sum-up this price if there is no valid Price { neon.setFieldValue("$field.PRICE", partsListObject["topProductInfo"]["price"]*quantity); neon.setFieldValue("$field.VAT", partsListObject["topProductInfo"]["vat"]); diff --git a/entity/Productprice_entity/onValidation.js b/entity/Productprice_entity/onValidation.js index 2bfd42916247e16b08a7d6d09da372ed9bef0449..2d96e9b5c19b0e339f8845561d5d4dac4de746e4 100644 --- a/entity/Productprice_entity/onValidation.js +++ b/entity/Productprice_entity/onValidation.js @@ -1,3 +1,8 @@ +import("system.datetime"); +import("system.eMath"); +import("system.translate"); +import("system.neon"); +import("Product_lib"); import("Date_lib"); import("system.result"); import("system.vars"); @@ -11,4 +16,67 @@ if(vars.getString("$param.IgnoreOnValidation_param") != "true") { result.string(DateUtils.getValidationFailString()); } + //The logic for creating a new priceA is the following: + //If there already exists the same priceB (-> same pricelist, buySell, fromQuantity and currency) + // and the validFrom of priceB is before the validFrom of priceA + // ->change the validTo of priceB to one date prior the validFrom of priceA. + // (A)|-------| -> |---| + // (B) |-----------| -> |-----------| + // + // and the validTo of priceB is after the validTo of priceA + // ->change the validFrom of priceB to one date after the validTo of priceA. + // (A) |-------| -> |-----| + // (B) |---------| -> |---------| + // + //There is another case we cannot handle as easy: + // if priceB's validFrom is after the validFrom of priceA and it's validTo is also before the validTo of priceA + // -> catch this case in the onValidation, since the only solution would be to delete priceB + // (A) |----| -> handle in onValidation + // (B) |-------------| -> handle in onValidation + else if(vars.get("$sys.recordstate") == neon.OPERATINGSTATE_NEW) + { + var priceList = vars.get("$field.PRICELIST"); + var productId = vars.get("$field.PRODUCT_ID"); + var buySell = vars.get("$field.BUYSELL"); + var validFrom = vars.get("$field.VALID_FROM"); + var validTo = vars.get("$field.VALID_TO"); + var currency = vars.get("$field.CURRENCY"); + var productPriceListId = vars.get("$field.PRODUCTPRICEID"); + + var priceListFilter = { currency: currency + , quantity: vars.get("$field.FROMQUANTITY") + , priceList: priceList + , buySell: buySell + , dateFrom: validFrom + , dateTo: validTo}; + var ProductDetails = ProductUtils.getProductDetails(productId, priceListFilter); + + var priceListsToPotentiallyReplace = ProductDetails.CurrentValidPriceLists; + var priceListsToReplace1 = []; + var priceListsToReplace2 = []; + + var showMessage = false; + for (var valPriceList in priceListsToPotentiallyReplace) + { + var currPriceList = priceListsToPotentiallyReplace[valPriceList]; + if(currPriceList["priceList"] == priceList && currPriceList["buySell"] == buySell) + { + if(currPriceList["validFrom"] > validFrom && ((validTo == undefined || validTo == "") || + (currPriceList["validTo"] != undefined && currPriceList["validTo"] != "" && currPriceList["validTo"] < validTo))) + { + showMessage = true; + break; + } + else if(eMath.addInt(currPriceList["validFrom"], datetime.ONE_DAY) == currPriceList["validTo"]) + { + showMessage = true; + break; + } + } + } + if(showMessage) + { + result.string(translate.withArguments("There already exists a %0 price with the same type of pricelist, quantity and currency in the defined range.", [vars.get("$field.BUYSELL")])); + } + } } \ No newline at end of file diff --git a/entity/Productprice_entity/recordcontainers/db/onDBInsert.js b/entity/Productprice_entity/recordcontainers/db/onDBInsert.js index 5d9ed76f358f35176af7e052e4630a14b9774255..62b572aaab1fd35c0b53c327d4d4f9a9b174d3dd 100644 --- a/entity/Productprice_entity/recordcontainers/db/onDBInsert.js +++ b/entity/Productprice_entity/recordcontainers/db/onDBInsert.js @@ -4,28 +4,70 @@ import("system.datetime"); import("system.entities"); import("Sql_lib"); import("system.vars"); +import("Product_lib"); +//The logic for creating a new priceA is the following: +//If there already exists the same priceB (-> same pricelist, buySell, fromQuantity and currency) +// and the validFrom of priceB is before the validFrom of priceA +// ->change the validTo of priceB to one date prior the validFrom of priceA. +// (A)|-------| -> |---| +// (B) |-----------| -> |-----------| +// +// and the validTo of priceB is after the validTo of priceA +// ->change the validFrom of priceB to one date after the validTo of priceA. +// (A) |-------| -> |-----| +// (B) |---------| -> |---------| +// +//There is another case we cannot handle as easy: +// if priceB's validFrom is after the validFrom of priceA and it's validTo is also before the validTo of priceA +// -> catch this case in the onValidation, since the only solution would be to delete priceB +// (A) |----| -> handle in onValidation +// (B) |-------------| -> handle in onValidation +// +var priceListId = vars.get("$field.PRODUCTPRICEID"); var priceList = vars.get("$field.PRICELIST"); var productId = vars.get("$field.PRODUCT_ID"); var buySell = vars.get("$field.BUYSELL"); var validFrom = vars.get("$field.VALID_FROM"); +var validTo = vars.get("$field.VALID_TO"); +var currency = vars.get("$field.CURRENCY"); var oneDayPrior = eMath.subInt(validFrom, datetime.ONE_DAY); +var oneDayAfter = eMath.addInt(validTo, datetime.ONE_DAY); var productPriceListId = vars.get("$field.PRODUCTPRICEID"); -var validPriceLists = newSelect("PRODUCTPRICE.PRODUCTPRICEID") - .from("PRODUCTPRICE") - .where("PRODUCTPRICE.PRICELIST", priceList) - .and("PRODUCTPRICE.PRODUCTPRICEID", productPriceListId, SqlBuilder.NOT_EQUAL()) - .and("PRODUCTPRICE.PRODUCT_ID", productId) - .and("PRODUCTPRICE.BUYSELL", buySell) - .and("PRODUCTPRICE.FROMQUANTITY", validFrom, SqlBuilder.LESS_OR_EQUAL()) - .and(newWhere("PRODUCTPRICE.VALID_TO", validFrom, SqlBuilder.GREATER_OR_EQUAL()).or("PRODUCTPRICE.VALID_TO is null")) - .arrayColumn(); +var PriceListFilter = { currency: currency, quantity: vars.get("$field.FROMQUANTITY"), priceList: priceList, buySell: buySell, dateFrom: validFrom, dateTo: validTo}; +var ProductDetails = ProductUtils.getProductDetails(productId, PriceListFilter); -var config = entities.createConfigForUpdatingRows().entity("Productprice_entity").fieldValues({"VALID_TO": oneDayPrior}).addParameter("IgnoreOnValidation_param", true); +var priceListsToPotentiallyReplace = ProductDetails.CurrentValidPriceLists; +var priceListsUpdateValidTo = []; +var priceListsUpdateValidFrom = []; +var configValidTo = entities.createConfigForUpdatingRows().entity("Productprice_entity") + .fieldValues({"VALID_TO": oneDayPrior}).addParameter("IgnoreOnValidation_param", true); +var configValidFrom = entities.createConfigForUpdatingRows().entity("Productprice_entity") + .fieldValues({"VALID_FROM": oneDayAfter}).addParameter("IgnoreOnValidation_param", true); + +for (var valPriceList in priceListsToPotentiallyReplace) +{ + var currPriceList = priceListsToPotentiallyReplace[valPriceList]; + if(currPriceList["priceListId"] != priceListId && currPriceList["priceList"] == priceList && currPriceList["buySell"] == buySell) + { + if(currPriceList["validFrom"] < validFrom && (!currPriceList["validTo"] || currPriceList["validTo"] > validFrom)) + { + priceListsUpdateValidTo.push(currPriceList["priceListId"]); + } + else if(currPriceList["validFrom"] < validTo && (!currPriceList["validTo"] || currPriceList["validTo"] > validTo)) + { + priceListsUpdateValidFrom.push(currPriceList["priceListId"]); + } + } +} -for (i = 0; i < validPriceLists.length; i++) { - - entities.updateRow(config.uid(validPriceLists[i])) +for (let i = 0; i < priceListsUpdateValidTo.length; i++) +{ + entities.updateRow(configValidTo.uid(priceListsUpdateValidTo[i])); } +for (let i = 0; i < priceListsUpdateValidFrom.length; i++) +{ + entities.updateRow(configValidFrom.uid(priceListsUpdateValidFrom[i])); +} \ No newline at end of file diff --git a/language/_____LANGUAGE_EXTRA/_____LANGUAGE_EXTRA.aod b/language/_____LANGUAGE_EXTRA/_____LANGUAGE_EXTRA.aod index 52d36bec804bcf9d542ec32ca62a944534c83d0e..f8a0d9c47b3b42a1a1be93a9ac5665fcd22cd5fa 100644 --- a/language/_____LANGUAGE_EXTRA/_____LANGUAGE_EXTRA.aod +++ b/language/_____LANGUAGE_EXTRA/_____LANGUAGE_EXTRA.aod @@ -8370,6 +8370,48 @@ <entry> <key>On site</key> </entry> + <entry> + <key>Event Data</key> + </entry> + <entry> + <key>On Site</key> + </entry> + <entry> + <key>Event Type</key> + </entry> + <entry> + <key>New child product</key> + </entry> + <entry> + <key>Communication: Link</key> + </entry> + <entry> + <key>Event Begin</key> + </entry> + <entry> + <key>Buying center and internal project team</key> + </entry> + <entry> + <key>Communication: Phone</key> + </entry> + <entry> + <key>Event</key> + </entry> + <entry> + <key>other</key> + </entry> + <entry> + <key>Communication: Mail</key> + </entry> + <entry> + <key>Vacation</key> + </entry> + <entry> + <key>Event End</key> + </entry> + <entry> + <key>On site</key> + </entry> </keyValueMap> <font name="Dialog" style="0" size="11" /> <sqlModels> diff --git a/language/_____LANGUAGE_de/_____LANGUAGE_de.aod b/language/_____LANGUAGE_de/_____LANGUAGE_de.aod index 4593fc87b7e0e8eb8ef9d988094a3835ab793408..6ceb69f4c964104c60cd9490a9e9ca0c52835a6a 100644 --- a/language/_____LANGUAGE_de/_____LANGUAGE_de.aod +++ b/language/_____LANGUAGE_de/_____LANGUAGE_de.aod @@ -10913,6 +10913,10 @@ Bitte Datumseingabe prüfen</value> <key>Set not completed</key> <value>Nicht erledigt setzen</value> </entry> + <entry> + <key>There already exists a %0 price with the same type of pricelist, quantity and currency in the defined range.</key> + <value>Es gibt bereits einen %0 Preis mit der selben Preisliste, Menge und Einheit im festgeleten Bereich.</value> + </entry> </keyValueMap> <font name="Dialog" style="0" size="11" /> </language> diff --git a/language/_____LANGUAGE_en/_____LANGUAGE_en.aod b/language/_____LANGUAGE_en/_____LANGUAGE_en.aod index 06e91e0b7abc071d6653caaef1b6ae48eb5aa97b..cc77285492d6d78727daf798d086460d66bc84f5 100644 --- a/language/_____LANGUAGE_en/_____LANGUAGE_en.aod +++ b/language/_____LANGUAGE_en/_____LANGUAGE_en.aod @@ -8400,6 +8400,27 @@ <entry> <key>Vacation</key> </entry> + <entry> + <key>On Site</key> + </entry> + <entry> + <key>New child product</key> + </entry> + <entry> + <key>Communication: Link</key> + </entry> + <entry> + <key>Buying center and internal project team</key> + </entry> + <entry> + <key>Communication: Phone</key> + </entry> + <entry> + <key>Communication: Mail</key> + </entry> + <entry> + <key>Vacation</key> + </entry> </keyValueMap> <font name="Dialog" style="0" size="11" /> </language> diff --git a/process/Product_lib/process.js b/process/Product_lib/process.js index c0a56e64560e2c111906ef19c205e1448c627a21..cf20a1cf64911ee631f8de66c69d0ee86a2e135b 100644 --- a/process/Product_lib/process.js +++ b/process/Product_lib/process.js @@ -159,6 +159,17 @@ ProductUtils.getStockCount = function(pid) { ProductUtils.getProductDetails = function(pid, pPriceListFilter, pAdditionalProductInfoSubselects) { var priceListFilter = pPriceListFilter; + var dateFrom; + if(priceListFilter.dateFrom != undefined) + { + dateFrom = priceListFilter.dateFrom; + } + var dateTo; + if(priceListFilter.dateTo != undefined) + { + dateTo = priceListFilter.dateTo; + } + var additionalProductInfoSubselects = pAdditionalProductInfoSubselects; if (additionalProductInfoSubselects == undefined) { @@ -189,19 +200,44 @@ ProductUtils.getProductDetails = function(pid, pPriceListFilter, pAdditionalProd && priceListFilter.currency != undefined && priceListFilter.currency != "" && priceListFilter.quantity != undefined && priceListFilter.quantity != "") { + if(priceListFilter.relationId == undefined) + { + priceListFilter.relationId = ""; + } validPriceLists = true; var colsPricelistValid = ["validPP.PRODUCTPRICEID", "validPP.CONTACT_ID", "validPP.PRICELIST", "validPP.PRICE", "validPP.VAT" , "validPP.VALID_FROM", "validPP.VALID_TO", "validPP.BUYSELL", "validPP.FROMQUANTITY", "validPP.CURRENCY"]; orderBy = orderBy.concat(["validPP.VALID_FROM desc", "validPP.FROMQUANTITY desc"]); cols = cols.concat(colsPricelistValid); + var cond; + if(dateFrom != undefined) + { + var secondCond; + if(dateTo) + { + secondCond = newWhere(["PRODUCTPRICE", "VALID_FROM", "validPP"], dateTo, SqlBuilder.LESS_OR_EQUAL()) + } + else + { + secondCond = newWhere(["PRODUCTPRICE", "VALID_FROM", "validPP"], dateFrom, SqlBuilder.LESS_OR_EQUAL()) + } + cond = newWhere().and(newWhere() + .or(["PRODUCTPRICE", "VALID_TO", "validPP"], dateFrom, SqlBuilder.GREATER_OR_EQUAL()) + .or("validPP.VALID_TO is null")) + .and(secondCond) + } + else + { + cond = newWhere().and(["PRODUCTPRICE", "VALID_FROM", "validPP"], datetime.date().toString(), SqlBuilder.LESS_OR_EQUAL()) + .and(newWhere() + .or(["PRODUCTPRICE", "VALID_TO", "validPP"], datetime.today().toString(), SqlBuilder.GREATER_OR_EQUAL()) + .or("validPP.VALID_TO is null")) + } joins.push(["left", "PRODUCTPRICE", "validPP", newWhere("validPP.PRODUCT_ID = PRODUCTID") .and(["PRODUCTPRICE", "CURRENCY", "validPP"], priceListFilter.currency) - .and(["PRODUCTPRICE", "VALID_FROM", "validPP"], datetime.date().toString(), SqlBuilder.LESS_OR_EQUAL()) - .and(newWhere() - .or(["PRODUCTPRICE", "VALID_TO", "validPP"], datetime.today().toString(), SqlBuilder.GREATER_OR_EQUAL()) - .or("validPP.VALID_TO is null")) + .and(cond) .and(["PRODUCTPRICE", "FROMQUANTITY", "validPP"], priceListFilter.quantity, SqlBuilder.LESS_OR_EQUAL()) .and(newWhere() .or(["PRODUCTPRICE", "CONTACT_ID", "validPP"], priceListFilter.relationId) @@ -247,12 +283,6 @@ ProductUtils.getProductDetails = function(pid, pPriceListFilter, pAdditionalProd countPos++; }, ProductDetails); } - //Pricelist (all) - var colIdx = colsProduct.length; - if (ProductData[i][colIdx] != "" && ProductDetails.PriceLists[ProductData[i][colIdx]] == undefined) //Pricelist found - { - ProductDetails.PriceLists[ProductData[i][colIdx]] = _getPriceListObject(); - } //Pricelist (currently valid) colIdx = colsProduct.length + colsPricelistAll.length; @@ -291,7 +321,7 @@ ProductUtils.getProductDetails = function(pid, pPriceListFilter, pAdditionalProd //infividual pricelists always have the highest priority, so we loop trough and use the first one we find regardles of the rest for (var indivList in priceLists) { - if(priceLists[indivList]["priceList"] == $KeywordRegistry.productPricelist$specialList()) + if(priceLists[indivList]["priceList"] == "") { return priceLists[indivList]; }