From 181fa351ac7bfec76d8fc68f2b04ea823ec94c32 Mon Sep 17 00:00:00 2001 From: "S.Listl" <S.Listl@SLISTL.aditosoftware.local> Date: Wed, 12 Jun 2019 14:36:15 +0200 Subject: [PATCH] Email fixed --- process/Address_lib/process.js | 31 +- process/DocumentTemplate_lib/process.js | 137 ++-- process/Offer_lib/process.js | 1002 +++++++++++------------ 3 files changed, 594 insertions(+), 576 deletions(-) diff --git a/process/Address_lib/process.js b/process/Address_lib/process.js index cc782a7e24..03e8d5d77a 100644 --- a/process/Address_lib/process.js +++ b/process/Address_lib/process.js @@ -1,3 +1,4 @@ +import("Employee_lib"); import("system.swing"); import("system.text"); import("system.db"); @@ -12,16 +13,16 @@ import("DocumentTemplate_lib"); /* * Creates a Address Object * -* @param {String} pRelationID req relationid for which address should be retrieved -* @param {String} pAddressID opt addressid for which address should be retrieved +* @param {String} pContactId req relationid for which address should be retrieved +* @param {String} pAddressId opt addressid for which address should be retrieved * @param {boolean} pPerson whether the address is from a person, not an organisation * * @return {String} the formatted address */ -function AddrObject( pRelationID, pPerson, pAddressID ) +function AddrObject(pContactId, pPerson, pAddressId) { - this.Data = fetchAddressData( [ pRelationID ] , [["", "addressformat", ""]], pAddressID, pPerson ); + this.Data = fetchAddressData([pContactId], [new Placeholder("", Placeholder.types.ADDRESSFORMAT, "")], pAddressId, pPerson); this.fmt = this.Data[0][0][26]; /* @@ -58,13 +59,13 @@ function getAddressesData( pCondition, pConfig, pSenderID, pAddressID ) { switch (pConfig[i].target) { - case PlaceholderUtils.targets.EMPLOYEE: + case Placeholder.targets.EMPLOYEE: employeeconfig.push(pConfig[i]); break; - case PlaceholderUtils.targets.SENDER: + case Placeholder.targets.SENDER: senderconfig.push(pConfig[i]); break; - case PlaceholderUtils.targets.RECIPIENT: + case Placeholder.targets.RECIPIENT: default: config.push(pConfig[i]); break; @@ -75,7 +76,7 @@ function getAddressesData( pCondition, pConfig, pSenderID, pAddressID ) if (senderconfig.length > 0) var senderdata = getAddressData([pSenderID], senderconfig); if (employeeconfig.length > 0) - var employeedata = getAddressData([vars.get("$global.user").relationid], employeeconfig); + var employeedata = getAddressData([EmployeeUtils.getCurrentContactId()], employeeconfig); if (data.length > 0 && (senderconfig.length > 0 || employeeconfig.length > 0)) { var ze = data[0]; @@ -141,13 +142,13 @@ function fetchAddressData( pCondition, pConfig, AddressID, pPerson ) { switch( pConfig[i].type ) { - case PlaceholderUtils.types.SQLPART: //sql part + case Placeholder.types.SQLPART: //sql part fields.push( pConfig[i].valueDefinition ); //TODO: maybe do vars.resolveVariables output.push([pos++, pConfig[i].type]); header.push( pConfig[i].placeholderName ); break; - case PlaceholderUtils.types.SQLPARTFUNCTION: // adito SQL functions - fields.push(pConfig[i].valueDefinition.call()); + case Placeholder.types.SQLPARTFUNCTION: // adito SQL functions + fields.push("(" + pConfig[i].valueDefinition.call() + ")"); output.push([pos++, pConfig[i].type]); header.push( pConfig[i].placeholderName ); break; @@ -168,7 +169,7 @@ function fetchAddressData( pCondition, pConfig, AddressID, pPerson ) output.push([pos++, pConfig[i].type]); header.push( pConfig[i].placeholderName ); break; - case PlaceholderUtils.types.ADDRESSFORMAT: + case Placeholder.types.ADDRESSFORMAT: if ( posaddrfields == -1 ) { var sortfields = ["ORGANISATION.NAME", "PERSON.LASTNAME"]; @@ -266,14 +267,14 @@ function setAddressData( pData ) { switch( output[z][1] ) { - case PlaceholderUtils.types.SQLPART: - case PlaceholderUtils.types.SQLPARTFUNCTION: + case Placeholder.types.SQLPART: + case Placeholder.types.SQLPARTFUNCTION: case "afunction": case "resolveIDFunction": case "select": row[z] = sqlresult[i][output[z][0]]; break; - case PlaceholderUtils.types.ADDRESSFORMAT: + case Placeholder.types.ADDRESSFORMAT: if (addrdata.length == 0) addrdata = _getAddrData( sqlresult[i].slice(output[z][0], output[z][0] + addrfields.length) ); row[z] = _formatAddrData( addrdata, output[z][2], false ); break; diff --git a/process/DocumentTemplate_lib/process.js b/process/DocumentTemplate_lib/process.js index 11fd5fe474..ba6e8e61be 100644 --- a/process/DocumentTemplate_lib/process.js +++ b/process/DocumentTemplate_lib/process.js @@ -1,5 +1,5 @@ +import("Communication_lib"); import("system.neon"); -import("system.logging"); import("Employee_lib"); import("KeywordRegistry_basic"); import("Document_lib"); @@ -62,6 +62,13 @@ DocumentTemplate.loadTemplate = function (pTemplateId) return new DocumentTemplate(); //TODO: throw error? } +DocumentTemplate._replaceText = function (pText, pReplacements) +{ + for (let placeholder in pReplacements) + pText = pText.replace(placeholder, pReplacements[placeholder], "ig"); + return pText; +} + DocumentTemplate.prototype.toString = function () { return this.content; @@ -83,7 +90,8 @@ DocumentTemplate.prototype.getReplacedContent = function (pReplacements) for (let i in pReplacements) pReplacements[i] = text.replaceAll(pReplacements[i], {"\n" : "<br>"}); case DocumentTemplate.types.TXT: - return text.replaceAll(this.content, pReplacements); + let decodedContent = util.decodeBase64String(this.content) + return DocumentTemplate._replaceText(decodedContent, pReplacements); case DocumentTemplate.types.EML: return this._getReplacedEML(pReplacements); case DocumentTemplate.types.ODT: @@ -116,24 +124,11 @@ DocumentTemplate.prototype.getReplacedContentByContactId = function (pContactId) */ DocumentTemplate.prototype._getReplacedEML = function (pReplacements) { - var email = mail.parseRFC(this.content, "UTF-8"); + var email = mail.parseRFC(util.decodeBase64String(this.content)); var htmlText = email[mail.MAIL_HTMLTEXT]; - return text.replaceAll(htmlText, pReplacements); -} - -/** - * replaces placeholders for plain text - * - * @param {Object} pReplacements mapping with replacements for every placeholder - * - * @return {String} the replaced content - */ -DocumentTemplate.prototype._getReplacedText = function (pReplacements) -{ - return text.replaceAll(this.content, pReplacements); + return DocumentTemplate._replaceText(htmlText, pReplacements); } - /* * replaces a given Odt-File on the server and returns the replaced base64-file * @@ -212,10 +207,14 @@ DocumentTemplate.prototype._getReplacedODT = function (pReplacements) */ DocumentTemplate.prototype._getReplacedDOCX = function (pReplacements) { + var replacements = {}; + for (let placeholder in pReplacements) + replacements[placeholder.slice(3, -3)] = pReplacements[placeholder]; + //this is executed as a process because of better performance var documentData = process.execute("getDocxDocument_serverProcess", { templateb64: this.content, - placeholderConfig: JSON.stringify(PlaceholderUtils.removePreAndPostFix(pReplacements)) //process.execute is only able to handle strings + placeholderConfig: JSON.stringify(replacements) //process.execute is only able to handle strings }); return documentData; @@ -238,13 +237,27 @@ DocumentTemplateUtils.getSingleReplacedDocument = function (pTemplateId, pContac return template.getReplacedTextByContactId(pContactId); } +/** + * represents a placeholder + * + * @param {String} pName name of the placeholder (without prefix and postfix) + * @param {String} pType type of the placeholder, see PlaceholderUtils.types + * @param {String|Function} pValueDef string or function (depends on the type) defining the value + * @param {String} [pTarget] what contact is used to get the data, see PlaceholderUtils.targets + */ +function Placeholder (pName, pType, pValueDef, pTarget) +{ + this.placeholderName = PlaceholderUtils.formatPlaceholder(pName); + this.type = pType; + this.target = pTarget || Placeholder.targets.RECIPIENT; + this.valueDefinition = pValueDef; +} -function PlaceholderUtils () {} /** * placeholder types, defines how the value is acquired */ -PlaceholderUtils.types = { +Placeholder.types = { ADDRESSFORMAT : "ADDRESSFORMAT", SQLPART : "SQLPART", SQLPARTFUNCTION : "SQLPARTFUNCTION" @@ -252,76 +265,72 @@ PlaceholderUtils.types = { /** * placeholder targets, defines whose data is used */ -PlaceholderUtils.targets = { +Placeholder.targets = { + /** + * use the data of the recipient (default) + */ RECIPIENT : "RECIPIENT", + /** + * use the data of the sender + */ SENDER : "SENDER", + /** + * use the data of the user + */ EMPLOYEE : "EMPLOYEE" }; +function PlaceholderUtils () {} + /** * Returns the placeholder with the required prefix and postfix added. * This function defines the format for placeholders. */ -PlaceholderUtils.formatPlaceholder = function (pPlaceholder) +PlaceholderUtils.formatPlaceholder = function (pPlaceholder, pEscapeForRegex) { return "{@" + pPlaceholder + "@}"; } /** - * Removes the prefix and postfix from the pReplacements map. This is required for the docxTemplater - * where they are added separately - */ -PlaceholderUtils.removePreAndPostFix = function (pReplacements) -{ - var unformattedReplacements = {}; - for (let placeholder in pReplacements) - { - let unformatted = placeholder.slice(2, -2); - unformattedReplacements[unformatted] = pReplacements[placeholder] - } - return unformattedReplacements; -} - -/** - * gets the placeholder configuration + * placeholder configuration * * @return {Array} array of placeholders */ PlaceholderUtils.getPlaceholders = function () { + //these functions should make adding placeholders easier and require less code: + /** - * represents a placeholder - * - * @param {String} pName name of the placeholder (without prefix and postfix) - * @param {String} pType type of the placeholder, see PlaceholderUtils.types - * @param {String|Function} pValueDef string or function (depends on the type) defining the value - * @param {String} [pTarget] what contact is used to get the data, see PlaceholderUtils.targets + * add an address format placeholder to placeholders */ - function Placeholder (pName, pType, pValueDef, pTarget) - { - this.placeholderName = PlaceholderUtils.formatPlaceholder(pName); - this.type = pType; - this.target = pTarget || PlaceholderUtils.targets.RECIPIENT; - this.valueDefinition = pValueDef; - } - function _addAddressFormat (pName, pFormat, pTarget) { - placeholders.push(new Placeholder(pName, PlaceholderUtils.types.ADDRESSFORMAT, pFormat, pTarget)); + placeholders.push(new Placeholder(pName, Placeholder.types.ADDRESSFORMAT, pFormat, pTarget)); } - function _addSqlPart (pName, pSqlPart, pAddBraces) + /** + * Add a sub-sql placeholder to placeholders. For further information regarding the full query, you can take + * a look at the function 'fetchAddressData' in Address_lib. You can use fields from CONTACT, ADDRESS, ORGANISATION and PERSON. + */ + function _addSqlPart (pName, pSqlPart, pTarget, pAddBraces) { - placeholders.push(new Placeholder(pName, PlaceholderUtils.types.SQLPART, pAddBraces ? "(" + pSqlPart + ")" : pSqlPart)); + placeholders.push(new Placeholder(pName, Placeholder.types.SQLPART, pAddBraces ? "(" + pSqlPart + ")" : pSqlPart, pTarget)); } + /** + * Add a placeholder to placeholders with a function that returns a sub-sql. The function will be called + * with no parameters. You have to deliver an actual function, don't call it here. + */ function _addSqlPartFunction (pName, pSqlPartFunction, pTarget) { - placeholders.push(new Placeholder(pName, PlaceholderUtils.types.SQLPARTFUNCTION, pSqlPartFunction, pTarget)); + placeholders.push(new Placeholder(pName, Placeholder.types.SQLPARTFUNCTION, pSqlPartFunction, pTarget)); } + var placeholders = []; + //placeholders should be added here: + _addAddressFormat("address", "{street} {buildingno}"); _addAddressFormat("zipCode", "{zip}"); _addAddressFormat("city", "{city}"); @@ -330,10 +339,18 @@ PlaceholderUtils.getPlaceholders = function () _addAddressFormat("country", "{country}"); _addAddressFormat("letterSalutation", "{letter_salutation}"); _addAddressFormat("fullAddress", ""); - _addAddressFormat("senderOrgname", "{organisation_name}", PlaceholderUtils.targets.SENDER); - _addAddressFormat("senderAddress", "{street} {buildingno}", PlaceholderUtils.targets.SENDER); - _addAddressFormat("senderZipCity", "{country} - {zip} {city}", PlaceholderUtils.targets.SENDER); - _addAddressFormat("senderFullAddress", "", PlaceholderUtils.targets.SENDER); + _addAddressFormat("senderOrgname", "{organisation_name}", Placeholder.targets.SENDER); + _addAddressFormat("senderAddress", "{street} {buildingno}", Placeholder.targets.SENDER); + _addAddressFormat("senderZipCity", "{country} - {zip} {city}", Placeholder.targets.SENDER); + _addAddressFormat("senderFullAddress", "", Placeholder.targets.SENDER); + + _addSqlPart("orgname", "ORGANISATION.NAME"); + + _addSqlPartFunction("phone", CommUtil.getStandardSubSqlPhone); + _addSqlPartFunction("email", CommUtil.getStandardSubSqlMail); + _addSqlPartFunction("senderPhone", CommUtil.getStandardSubSqlPhone, Placeholder.targets.SENDER); + _addSqlPartFunction("senderEmail", CommUtil.getStandardSubSqlMail, Placeholder.targets.SENDER); + return placeholders; } diff --git a/process/Offer_lib/process.js b/process/Offer_lib/process.js index 1fb2ad442f..6b12a3f927 100644 --- a/process/Offer_lib/process.js +++ b/process/Offer_lib/process.js @@ -1,501 +1,501 @@ -import("system.vars"); -import("system.util"); -import("system.datetime"); -import("system.text"); -import("system.neon"); -import("system.db"); -import("system.translate"); -import("system.eMath"); -import("Util_lib"); -import("Sql_lib"); -import("Keyword_lib"); -import("Product_lib"); -import("Report_lib"); -import("OfferOrder_lib"); -import("PostalAddress_lib"); -import("Neon_lib"); -import("KeywordRegistry_basic"); - -/** - * Methods used by Offer. - * Do not create an instance of this! - * - * @class - */ -function OfferUtils() {} - -/** - * Delivers the next valid offer number (has to be unique) - * - * @return {String} next valid offer number - */ -OfferUtils.getNextOfferNumber = function() { - return NumberSequencingUtils.getNextUniqueNumber("OFFERCODE", "OFFER"); -} - -/** - * Delivers the next valid offer version number - * - * @return {String} offerCode next valid offer version number - */ -OfferUtils.getNextOfferVersionNumber = function(offerCode) { - return NumberSequencingUtils.getNextUniqueNumber("VERSNR", "OFFER", 1, "OFFERCODE = " + offerCode); -} - -/** - * Checks if the passed offer number is valid (has to be unique) - * - * @param {String} offerNumber offer number to check - * - * @return {Boolean} passed number is valid - */ -OfferUtils.validateOfferNumber = function(offerNumber) { - return NumberSequencingUtils.validateUniqueNumber(offerNumber, "OFFERCODE", "OFFER"); -} - -OfferUtils.getOfferNumberValidationFailString = function() { - return translate.text("The offer number already exists!"); -} - -OfferUtils.isEditable = function(status) { - // TODO: Administrator darf immer �ndern, warten auf neue Berechtigungslogik? - - // Offer should be editable if offer state not equals "Sent", "Won" or "Lost" - return status != "2" && status != "3" && status != "4"; -} - -/** - * Create a new offer and open the offer context in NEW-mode - */ -OfferUtils.createNewOffer = function(pContextId, pRowId, pRelationId) -{ - var params = {}; - - if (pRowId && pContextId) - { - params["ObjectRowId_param"] = pRowId; - params["ObjectType_param"] = pContextId; - } - - if (pRelationId) - params["ContactId_param"] = pRelationId; - - neon.openContext("Offer", null, null, neon.OPERATINGSTATE_NEW, params); -} - -/* - * Open Offer report, the report is translated to the language of the offer - * - * @param {String} pOfferID - * - * @return {[]} - */ -OfferUtils.openOfferReport = function (pOfferID) -{ - var offerReport = new Report("Offer_report"); - - var sqlUtil = new SqlMaskingUtils(); - - var offerFields = [ - "ADDRESS", - "CONTACT_ID", - "LANGUAGE", - "PAYMENTTERMS", - "DELIVERYTERMS", //4 - "OFFERCODE", - "CURRENCY", - "OFFERDATE", - "HEADER", //8 - "VAT", - sqlUtil.isNull("VERSNR", "0"), - sqlUtil.isNull("OFFERCODE", "0"), - "OBJECT_TYPE", //12 - "OBJECT_ROWID", //13 - "FOOTER" //14 - ]; - - var offerSql = SqlCondition.begin() - .andPrepare("OFFER.OFFERID", pOfferID) - .buildSql("select " + offerFields.join(", ") + " from OFFER", "1 = 0"); - var offerData = db.array(db.ROW, offerSql); - - offerData[7] = datetime.toDate(offerData[7], translate.text("dd.MM.yyyy", language)); - - var language = db.cell(SqlCondition.begin() - .andPrepare("AB_LANGUAGE.ISO3", offerData[2]) - .buildSql("select ISO2 from AB_LANGUAGE", "1=0")); - var contactId = offerData[1]; - - - var offerItemFields = [ - "OFFERITEM.INFO", - "OFFERITEM.ASSIGNEDTO", - "OFFERITEM.PRODUCT_ID", - "OFFERITEM.ITEMNAME" , - "OFFERITEM.OPTIONAL", //4 - "OFFERITEM.ITEMPOSITION", - "PRODUCT.PRODUCTCODE", - "PRODUCT.PRODUCTID", - "OFFERITEM.UNIT", //8 - sqlUtil.isNull("OFFERITEM.QUANTITY", "0"), - sqlUtil.isNull("OFFERITEM.PRICE", "0"), - sqlUtil.isNull("OFFERITEM.DISCOUNT", "0"), - sqlUtil.isNull("OFFERITEM.VAT", "0"), //12 - "0", - "''" - ]; - - var offerItemSql = SqlCondition.begin() - .andPrepare("OFFERITEM.OFFER_ID", pOfferID) - .buildSql( - "select " + offerItemFields.join(", ") + " from OFFERITEM left join PRODUCT on PRODUCT.PRODUCTID = OFFERITEM.PRODUCT_ID", - "1 = 0" - ); - var itemData = db.table(offerItemSql); - - if (itemData.length == 0) - return; - - // TODO: AddrObject implementieren - //var addrobj = new AddrObject(contactId); - - var fullPrice = 0; - var itemSum = 0; - var sumItemSum = 0; - var total = 0; - var sums = []; - var vatsum = 0; - var printDiscount = false; - - itemData = itemData.map(function (item) - { - //quantity * price - fullPrice = eMath.mulDec(parseFloat(item[9]), parseFloat(item[10])); //price without discount - - if (item[4] != "1") //optional - { - //itemSum = (fullPrice * (100 - discount)) / 100 - itemSum = eMath.roundDec(eMath.divDec(eMath.mulDec(fullPrice, eMath.subDec(100, item[11])), 100), 2, eMath.ROUND_HALF_EVEN); //sum of the item (with discount) - sumItemSum += itemSum; //total sum (without vat) - } - //vatsum = itemSum * vat / 100 - vatsum = eMath.divDec(eMath.mulDec(itemSum, item[12]), 100); //vat per product - if (item[12] > 0) - sums.push([item[12], vatsum]); //MWSteuerwerte für Map vorbereiten - - // sumItemSum + vat - total = eMath.addDec(sumItemSum, offerData[9]); //total sum with vat - - if (!printDiscount && item[11] > 0) - printDiscount = true; - - return [ - offerData[6], //currency - offerData[7], //offerdate - pOfferID, //offerId - item[0], //info - item[1], //assignedTo - item[3], //itemname - item[4], //optional - item[5], //itemposition - item[6], //productcode - offerData[8], //header - offerData[14], //footer - text.formatDouble(item[9], translate.text("#,##0"), true), //quantity - text.formatDouble(item[10], translate.text("#,##0.00"), true), //price - text.formatDouble(item[11], translate.text("0.00"), true), //discount - offerData[10], //versnr - offerData[5], //offercode - text.formatDouble(item[12], translate.text("#,##0.00"), true), //vat - text.formatDouble(itemSum, translate.text("#,##0.00"), true), //itemsum - KeywordUtils.getViewValue($KeywordRegistry.quantityUnit(), item[8]) //unittext - ]; - }); - - // TODO: get Images implementieren - var imgData = ["meineFirma | Konrad-Zuse-Straße 4 | DE 84144 Geisenhausen", - "base64:iVBORw0KGgoAAAANSUhEUgAAAM4AAABRCAYAAACaL5lSAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYxIDY0LjE0MDk0OSwgMjAxMC8xMi8wNy0xMDo1NzowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNS4xIFdpbmRvd3MiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6MDA4QzAyM0IwREIwMTFFNEFGMDREM0VEMjExRjlBRTIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MDA4QzAyM0MwREIwMTFFNEFGMDREM0VEMjExRjlBRTIiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDowMDhDMDIzOTBEQjAxMUU0QUYwNEQzRUQyMTFGOUFFMiIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDowMDhDMDIzQTBEQjAxMUU0QUYwNEQzRUQyMTFGOUFFMiIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PhF3nYoAAAlvSURBVHja7J1fjBXV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"] - // getMyASYS_ICONSdata(); - - // TODO: implementieren wenn Attribute möglich sind - var adma = ""; //adma = Aussendienstmitarbeiter - /*var adm = getAddressData( [GetAttributeKey( "Aussendienst", "1", orgrelid, pUser )[0]], - [["Person","function", "concat( ['SALUTATION', 'TITLE', 'FIRSTNAME','LASTNAME'])"], - ["Telefon", "function", "getCommAddrSQL('Telefon', 'CONTACT.CONTACTID')"], - ["Email", "function", "getCommAddrSQL('E-Mail', 'CONTACT.CONTACTID')"] - ] ); - var adma = ""; - if (adm[1] != undefined) adma = adm[1].join("\n");*/ - - var params = { - "PaymentConditions" : translate.text("Conditions of payment", language), - "Articledescription" : translate.text("Articledescription", language), - "DeliveryConditions" : translate.text("Deliveryspecification", language), - "OFFERPers" : (AddressUtils.getLetterSalutation() + ",").toString(), // TODO: AddrObject implementieren (addrobj.formatAddress("{ls},");) - "Articlenumber" : translate.text("Articlenumber", language), - "OFFERAddr" : translate.text(offerData[0].trim(), language), - "PlusSalestax" : translate.text("Plus Salestax", language), - "Unitprice" : translate.text("Unitprice", language), - "directlyResponsible" : translate.text("Directly responsible:", language), - "Number" : translate.text("Number", language), - "Discount" : translate.text("Discount", language), - "Amount" : translate.text("Amount", language), - "Total" : translate.text("Total", language), - "Date" : translate.text("Date", language), - "VAT" : translate.text("VAT", language), - "Sum" : translate.text("Sum", language), - "Pos" : translate.text("Pos.", language), - "myAddr" : imgData[0], - "OfferPaymentTerm" : KeywordUtils.getViewValue($KeywordRegistry.paymentTerm(), offerData[3]), - "OfferDeliveryTerm" : KeywordUtils.getViewValue($KeywordRegistry.deliveryTerm(), offerData[4]), - "responsible" : adma, - "SUMITEMSUM" : sumItemSum, - "TOTAL" : text.formatDouble(total, translate.text("#,##0.00"), true), - "printDiscount" : printDiscount ? "1" : "0" - }; - - - - offerReport.addImage("myLogo", imgData[1]); - - offerReport.addSubReportData("subdata", ReportData.begin(["VAT","WERT"]).add(sums)); - offerReport.addReportParams(params); - - offerReport.setReportData(ReportData.begin( - [ - "OFFER_CURRENCY", - "OFFER_OFFERDATE", - "OFFER_OFFERID", - "OFFERITEM_INFO", - "OFFERITEM_ASSIGNEDTO", //4 - "OFFERITEM_ITEMNAME" , - "OFFERITEM_OPTIONAL", - "OFFERITEM_ITEMPOSITION", - "PRODUCT_PRODUCTCODE", //8 - "OFFER_HEADER", - "OFFER_FOOTER", - "OFFERITEM_QUANTITY", - "OFFERITEM_PRICE", - "OFFERITEM_DISCOUNT", //13 - "OFFER_VERSNR", - "OFFER_OFFERCODE", - "OFFERITEM_VAT", - "ITEMSUM", // 17 - "OFFERITEM_UNITTEXT" - ]) - .add(itemData)); - offerReport.openReport(); -} - -/** - * opens an offer in NEW mode with values from an offer - * - * @param {String} pOfferId of the offer - * @param {String} pContactId - * @param {String} pLanguage - * @param {String} [pCurrency=""] - * @param {String} [pHeader=""] - * @param {String} [pFooter=""] - * @param {String} [pDeliveryTerm=""] - * @param {String} [pPaymentTerm=""] - * @param {String} [pSalesprojectId=""] - */ -OfferUtils.copyOffer = function (pOfferId, pContactId, pLanguage, pCurrency, pHeader, pFooter, pDeliveryTerm, pPaymentTerm, pObjectType, pRowId) -{ - var params = { - "ContactId_param" : pContactId, - "OfferLanguage_param" : pLanguage, - "OfferOriginal_Id_param" : pOfferId, - "OfferCurrency_param" : pCurrency || "", - "OfferHeader_param" : pHeader || "", - "OfferFooter_param" : pFooter || "", - "OfferDeliveryTerm_param" : pDeliveryTerm || "", - "OfferPaymentTerm_param" : pPaymentTerm || "", - "ObjectType_param" : pObjectType || "", - "ObjectRowId_param" : pRowId || "" - }; - neon.openContext("Offer", null, null, neon.OPERATINGSTATE_NEW, params); -} - -/** - * copies all offerItems from one offer to another - * - * @param {String} pSourceOfferId - * @param {String} pTargetOfferId - */ -OfferUtils.copyOfferItems = function (pSourceOfferId, pTargetOfferId) -{ - var InputMapping = { - "OFFERITEM": { - condition: "OFFER_ID = '" + pSourceOfferId + "' order by ITEMSORT", - ValueMapping: { - "OFFER_ID" : pTargetOfferId - } - } - }; - CopyModuleUtils.copyModule(InputMapping); - - var oiUtils = new OfferItemUtils(pTargetOfferId); - - //update order price - cols = ["NET", "VAT"]; - var vals = oiUtils.getNetAndVat(); - - db.updateData("OFFER", cols, null, vals, SqlCondition.equals("OFFER.OFFERID", pTargetOfferId, "1 = 2")); -} - -/** - * opens an order in NEW mode with values from an offer - * - * @param pOfferId {String} id of the offer - * @param pSalesprojectId {String} salesproject id - * @param pContactId {String} contact id - * @param pLanguage {String} language - * @param pCurrency {String} [currency=""] - * @param pAddress {String} [address=""] - * @param pHeader {String} [header=""] - */ -OfferUtils.copyToOrder = function (pOfferId, pSalesprojectId, pContactId, pLanguage, pCurrency, pAddress, pHeader) -{ - var params = { - "ContactId_param" : pContactId, - "SalesprojectId_param" : pSalesprojectId, - "OrderLanguage_param" : pLanguage, - "OfferId_param" : pOfferId, - "OrderCurrency_param" : pCurrency || "", - "OrderAddress_param" : pAddress || "", - "OrderHeader_param" : pHeader || "" - }; - neon.openContext("Order", null, null, neon.OPERATINGSTATE_NEW, params); -} - -/** - * gets the title of an offer from the id - * - * @param pOfferId {String} offer-id - * - * @return {String} offer title - */ -OfferUtils.getOfferTitleById = function (pOfferId) -{ - if (!pOfferId) - return ""; - var offerNumber = db.array(db.ROW, SqlCondition.begin() - .andPrepare("OFFER.OFFERID", pOfferId) - .buildSql("select OFFERCODE, VERSNR from OFFER")); - return offerNumber.length > 0 - ? translate.text("Offer") + " " + offerNumber.join("-") - : ""; -} - - -/******************************************************************************/ - -/** - * Provides methods for dealing with offer items. - * Inherits methods from abstract class ItemUtils. - * For documentation, see class ItemUtils. - * - * @class - */ -function OfferItemUtils(pOfferId) { - // extends ItemUtils - ItemUtils.apply(this, [pOfferId, "OFFER"]); - OfferItemUtils.prototype = Object.create(ItemUtils.prototype); - OfferItemUtils.prototype.constructor = OfferItemUtils; -} - -/** - * For documentation, see class ItemUtils. - */ -OfferItemUtils.prototype.getNetAndVat = function(offeritemIdsToDel) { - return ItemUtils.prototype.getNetAndVat.apply(this, [offeritemIdsToDel]); -} - -/** - * For documentation, see class ItemUtils. - */ -OfferItemUtils.prototype.initItemTree = function() { - ItemUtils.prototype.initItemTree.apply(this); -} - -/** - * For documentation, see class ItemUtils. - */ -OfferItemUtils.prototype.getItemSum = function(pQuantity, pPrice, pDiscount, pOptional) { - return ItemUtils.prototype.getItemSum.apply(this, [pQuantity, pPrice, pDiscount, pOptional]); -} - -/** - * For documentation, see class ItemUtils. - */ -OfferItemUtils.prototype.getItemVAT = function(pQuantity, pPrice, pDiscount, pVAT, pOptional) { - return ItemUtils.prototype.getItemVAT.apply(this, [pQuantity, pPrice, pDiscount, pVAT, pOptional]); -} - -/** - * For documentation, see class ItemUtils. - */ -OfferItemUtils.prototype.roundPrice = function(pPrice) { - return ItemUtils.prototype.roundPrice.apply(this, [pPrice]); -} - -/** - * For documentation, see class ItemUtils. - */ -OfferItemUtils.prototype.insertPartsList = function(pProductId, pAssignedTo, pCurrency, pContactId) { - this.initItemTree(); - - var cols = ["OFFERITEMID" - , "OFFER_ID" - , "PRODUCT_ID" - , "GROUPCODEID" - , "ASSIGNEDTO" - , "ITEMNAME" - , "UNIT" - , "PRICE" - , "VAT" - , "QUANTITY" - , "OPTIONAL" - , "ITEMPOSITION" - , "ITEMSORT"]; - - return ItemUtils.prototype.insertPartsList.apply(this, [cols, pProductId, pAssignedTo, pCurrency, pContactId, [["INFO", "INFO"]]]); -} - -/** - * For documentation, see class ItemUtils. - */ -OfferItemUtils.prototype.deletePartsList = function(pItemId) { - this.initItemTree(); - - return ItemUtils.prototype.deletePartsList.apply(this, [pItemId]); -} - -/** - * For documentation, see class ItemUtils. - */ -OfferItemUtils.prototype.getNextItemSort = function(pIds) { - this.initItemTree(); - - return ItemUtils.prototype.getNextItemSort.apply(this, [pIds]); -} - -/** - * For documentation, see class ItemUtils. - */ -OfferItemUtils.prototype.getNextItemPosition = function(pAssignedTo, pTree, pIds) { - this.initItemTree(); - - return ItemUtils.prototype.getNextItemPosition.apply(this, [pAssignedTo, pTree, pIds]); -} - -/** - * For documentation, see class ItemUtils. - */ -OfferItemUtils.prototype.reOrgItems = function() { - this.initItemTree(); - - ItemUtils.prototype.reOrgItems.apply(this); -} - +import("system.vars"); +import("system.util"); +import("system.datetime"); +import("system.text"); +import("system.neon"); +import("system.db"); +import("system.translate"); +import("system.eMath"); +import("Util_lib"); +import("Sql_lib"); +import("Keyword_lib"); +import("Product_lib"); +import("Report_lib"); +import("OfferOrder_lib"); +import("PostalAddress_lib"); +import("Neon_lib"); +import("KeywordRegistry_basic"); +import("Address_lib"); + +/** + * Methods used by Offer. + * Do not create an instance of this! + * + * @class + */ +function OfferUtils() {} + +/** + * Delivers the next valid offer number (has to be unique) + * + * @return {String} next valid offer number + */ +OfferUtils.getNextOfferNumber = function() { + return NumberSequencingUtils.getNextUniqueNumber("OFFERCODE", "OFFER"); +} + +/** + * Delivers the next valid offer version number + * + * @return {String} offerCode next valid offer version number + */ +OfferUtils.getNextOfferVersionNumber = function(offerCode) { + return NumberSequencingUtils.getNextUniqueNumber("VERSNR", "OFFER", 1, "OFFERCODE = " + offerCode); +} + +/** + * Checks if the passed offer number is valid (has to be unique) + * + * @param {String} offerNumber offer number to check + * + * @return {Boolean} passed number is valid + */ +OfferUtils.validateOfferNumber = function(offerNumber) { + return NumberSequencingUtils.validateUniqueNumber(offerNumber, "OFFERCODE", "OFFER"); +} + +OfferUtils.getOfferNumberValidationFailString = function() { + return translate.text("The offer number already exists!"); +} + +OfferUtils.isEditable = function(status) { + // TODO: Administrator darf immer �ndern, warten auf neue Berechtigungslogik? + + // Offer should be editable if offer state not equals "Sent", "Won" or "Lost" + return status != "2" && status != "3" && status != "4"; +} + +/** + * Create a new offer and open the offer context in NEW-mode + */ +OfferUtils.createNewOffer = function(pContextId, pRowId, pRelationId) +{ + var params = {}; + + if (pRowId && pContextId) + { + params["ObjectRowId_param"] = pRowId; + params["ObjectType_param"] = pContextId; + } + + if (pRelationId) + params["ContactId_param"] = pRelationId; + + neon.openContext("Offer", null, null, neon.OPERATINGSTATE_NEW, params); +} + +/* + * Open Offer report, the report is translated to the language of the offer + * + * @param {String} pOfferID + * + * @return {[]} + */ +OfferUtils.openOfferReport = function (pOfferID) +{ + var offerReport = new Report("Offer_report"); + + var sqlUtil = new SqlMaskingUtils(); + + var offerFields = [ + "ADDRESS", + "CONTACT_ID", + "LANGUAGE", + "PAYMENTTERMS", + "DELIVERYTERMS", //4 + "OFFERCODE", + "CURRENCY", + "OFFERDATE", + "HEADER", //8 + "VAT", + sqlUtil.isNull("VERSNR", "0"), + sqlUtil.isNull("OFFERCODE", "0"), + "OBJECT_TYPE", //12 + "OBJECT_ROWID", //13 + "FOOTER" //14 + ]; + + var offerSql = SqlCondition.begin() + .andPrepare("OFFER.OFFERID", pOfferID) + .buildSql("select " + offerFields.join(", ") + " from OFFER", "1 = 0"); + var offerData = db.array(db.ROW, offerSql); + + offerData[7] = datetime.toDate(offerData[7], translate.text("dd.MM.yyyy", language)); + + var language = db.cell(SqlCondition.begin() + .andPrepare("AB_LANGUAGE.ISO3", offerData[2]) + .buildSql("select ISO2 from AB_LANGUAGE", "1=0")); + var contactId = offerData[1]; + + + var offerItemFields = [ + "OFFERITEM.INFO", + "OFFERITEM.ASSIGNEDTO", + "OFFERITEM.PRODUCT_ID", + "OFFERITEM.ITEMNAME" , + "OFFERITEM.OPTIONAL", //4 + "OFFERITEM.ITEMPOSITION", + "PRODUCT.PRODUCTCODE", + "PRODUCT.PRODUCTID", + "OFFERITEM.UNIT", //8 + sqlUtil.isNull("OFFERITEM.QUANTITY", "0"), + sqlUtil.isNull("OFFERITEM.PRICE", "0"), + sqlUtil.isNull("OFFERITEM.DISCOUNT", "0"), + sqlUtil.isNull("OFFERITEM.VAT", "0"), //12 + "0", + "''" + ]; + + var offerItemSql = SqlCondition.begin() + .andPrepare("OFFERITEM.OFFER_ID", pOfferID) + .buildSql( + "select " + offerItemFields.join(", ") + " from OFFERITEM left join PRODUCT on PRODUCT.PRODUCTID = OFFERITEM.PRODUCT_ID", + "1 = 0" + ); + var itemData = db.table(offerItemSql); + + if (itemData.length == 0) + return; + + var addrobj = new AddrObject(contactId); + + var fullPrice = 0; + var itemSum = 0; + var sumItemSum = 0; + var total = 0; + var sums = []; + var vatsum = 0; + var printDiscount = false; + + itemData = itemData.map(function (item) + { + //quantity * price + fullPrice = eMath.mulDec(parseFloat(item[9]), parseFloat(item[10])); //price without discount + + if (item[4] != "1") //optional + { + //itemSum = (fullPrice * (100 - discount)) / 100 + itemSum = eMath.roundDec(eMath.divDec(eMath.mulDec(fullPrice, eMath.subDec(100, item[11])), 100), 2, eMath.ROUND_HALF_EVEN); //sum of the item (with discount) + sumItemSum += itemSum; //total sum (without vat) + } + //vatsum = itemSum * vat / 100 + vatsum = eMath.divDec(eMath.mulDec(itemSum, item[12]), 100); //vat per product + if (item[12] > 0) + sums.push([item[12], vatsum]); //MWSteuerwerte für Map vorbereiten + + // sumItemSum + vat + total = eMath.addDec(sumItemSum, offerData[9]); //total sum with vat + + if (!printDiscount && item[11] > 0) + printDiscount = true; + + return [ + offerData[6], //currency + offerData[7], //offerdate + pOfferID, //offerId + item[0], //info + item[1], //assignedTo + item[3], //itemname + item[4], //optional + item[5], //itemposition + item[6], //productcode + offerData[8], //header + offerData[14], //footer + text.formatDouble(item[9], translate.text("#,##0"), true), //quantity + text.formatDouble(item[10], translate.text("#,##0.00"), true), //price + text.formatDouble(item[11], translate.text("0.00"), true), //discount + offerData[10], //versnr + offerData[5], //offercode + text.formatDouble(item[12], translate.text("#,##0.00"), true), //vat + text.formatDouble(itemSum, translate.text("#,##0.00"), true), //itemsum + KeywordUtils.getViewValue($KeywordRegistry.quantityUnit(), item[8]) //unittext + ]; + }); + + // TODO: get Images implementieren + var imgData = ["meineFirma | Konrad-Zuse-Straße 4 | DE 84144 Geisenhausen", + "base64:iVBORw0KGgoAAAANSUhEUgAAAM4AAABRCAYAAACaL5lSAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYxIDY0LjE0MDk0OSwgMjAxMC8xMi8wNy0xMDo1NzowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNS4xIFdpbmRvd3MiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6MDA4QzAyM0IwREIwMTFFNEFGMDREM0VEMjExRjlBRTIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MDA4QzAyM0MwREIwMTFFNEFGMDREM0VEMjExRjlBRTIiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDowMDhDMDIzOTBEQjAxMUU0QUYwNEQzRUQyMTFGOUFFMiIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDowMDhDMDIzQTBEQjAxMUU0QUYwNEQzRUQyMTFGOUFFMiIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PhF3nYoAAAlvSURBVHja7J1fjBXV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"] + // getMyASYS_ICONSdata(); + + // TODO: implementieren wenn Attribute möglich sind + var adma = ""; //adma = Aussendienstmitarbeiter + /*var adm = getAddressData( [GetAttributeKey( "Aussendienst", "1", orgrelid, pUser )[0]], + [["Person","function", "concat( ['SALUTATION', 'TITLE', 'FIRSTNAME','LASTNAME'])"], + ["Telefon", "function", "getCommAddrSQL('Telefon', 'CONTACT.CONTACTID')"], + ["Email", "function", "getCommAddrSQL('E-Mail', 'CONTACT.CONTACTID')"] + ] ); + var adma = ""; + if (adm[1] != undefined) adma = adm[1].join("\n");*/ + + var params = { + "PaymentConditions" : translate.text("Conditions of payment", language), + "Articledescription" : translate.text("Articledescription", language), + "DeliveryConditions" : translate.text("Deliveryspecification", language), + "OFFERPers" : addrobj.getFormattedAddress(false, "{letter_salutation},"), + "Articlenumber" : translate.text("Articlenumber", language), + "OFFERAddr" : translate.text(offerData[0].trim(), language), + "PlusSalestax" : translate.text("Plus Salestax", language), + "Unitprice" : translate.text("Unitprice", language), + "directlyResponsible" : translate.text("Directly responsible:", language), + "Number" : translate.text("Number", language), + "Discount" : translate.text("Discount", language), + "Amount" : translate.text("Amount", language), + "Total" : translate.text("Total", language), + "Date" : translate.text("Date", language), + "VAT" : translate.text("VAT", language), + "Sum" : translate.text("Sum", language), + "Pos" : translate.text("Pos.", language), + "myAddr" : imgData[0], + "OfferPaymentTerm" : KeywordUtils.getViewValue($KeywordRegistry.paymentTerm(), offerData[3]), + "OfferDeliveryTerm" : KeywordUtils.getViewValue($KeywordRegistry.deliveryTerm(), offerData[4]), + "responsible" : adma, + "SUMITEMSUM" : sumItemSum, + "TOTAL" : text.formatDouble(total, translate.text("#,##0.00"), true), + "printDiscount" : printDiscount ? "1" : "0" + }; + + + + offerReport.addImage("myLogo", imgData[1]); + + offerReport.addSubReportData("subdata", ReportData.begin(["VAT","WERT"]).add(sums)); + offerReport.addReportParams(params); + + offerReport.setReportData(ReportData.begin( + [ + "OFFER_CURRENCY", + "OFFER_OFFERDATE", + "OFFER_OFFERID", + "OFFERITEM_INFO", + "OFFERITEM_ASSIGNEDTO", //4 + "OFFERITEM_ITEMNAME" , + "OFFERITEM_OPTIONAL", + "OFFERITEM_ITEMPOSITION", + "PRODUCT_PRODUCTCODE", //8 + "OFFER_HEADER", + "OFFER_FOOTER", + "OFFERITEM_QUANTITY", + "OFFERITEM_PRICE", + "OFFERITEM_DISCOUNT", //13 + "OFFER_VERSNR", + "OFFER_OFFERCODE", + "OFFERITEM_VAT", + "ITEMSUM", // 17 + "OFFERITEM_UNITTEXT" + ]) + .add(itemData)); + offerReport.openReport(); +} + +/** + * opens an offer in NEW mode with values from an offer + * + * @param {String} pOfferId of the offer + * @param {String} pContactId + * @param {String} pLanguage + * @param {String} [pCurrency=""] + * @param {String} [pHeader=""] + * @param {String} [pFooter=""] + * @param {String} [pDeliveryTerm=""] + * @param {String} [pPaymentTerm=""] + * @param {String} [pSalesprojectId=""] + */ +OfferUtils.copyOffer = function (pOfferId, pContactId, pLanguage, pCurrency, pHeader, pFooter, pDeliveryTerm, pPaymentTerm, pObjectType, pRowId) +{ + var params = { + "ContactId_param" : pContactId, + "OfferLanguage_param" : pLanguage, + "OfferOriginal_Id_param" : pOfferId, + "OfferCurrency_param" : pCurrency || "", + "OfferHeader_param" : pHeader || "", + "OfferFooter_param" : pFooter || "", + "OfferDeliveryTerm_param" : pDeliveryTerm || "", + "OfferPaymentTerm_param" : pPaymentTerm || "", + "ObjectType_param" : pObjectType || "", + "ObjectRowId_param" : pRowId || "" + }; + neon.openContext("Offer", null, null, neon.OPERATINGSTATE_NEW, params); +} + +/** + * copies all offerItems from one offer to another + * + * @param {String} pSourceOfferId + * @param {String} pTargetOfferId + */ +OfferUtils.copyOfferItems = function (pSourceOfferId, pTargetOfferId) +{ + var InputMapping = { + "OFFERITEM": { + condition: "OFFER_ID = '" + pSourceOfferId + "' order by ITEMSORT", + ValueMapping: { + "OFFER_ID" : pTargetOfferId + } + } + }; + CopyModuleUtils.copyModule(InputMapping); + + var oiUtils = new OfferItemUtils(pTargetOfferId); + + //update order price + cols = ["NET", "VAT"]; + var vals = oiUtils.getNetAndVat(); + + db.updateData("OFFER", cols, null, vals, SqlCondition.equals("OFFER.OFFERID", pTargetOfferId, "1 = 2")); +} + +/** + * opens an order in NEW mode with values from an offer + * + * @param pOfferId {String} id of the offer + * @param pSalesprojectId {String} salesproject id + * @param pContactId {String} contact id + * @param pLanguage {String} language + * @param pCurrency {String} [currency=""] + * @param pAddress {String} [address=""] + * @param pHeader {String} [header=""] + */ +OfferUtils.copyToOrder = function (pOfferId, pSalesprojectId, pContactId, pLanguage, pCurrency, pAddress, pHeader) +{ + var params = { + "ContactId_param" : pContactId, + "SalesprojectId_param" : pSalesprojectId, + "OrderLanguage_param" : pLanguage, + "OfferId_param" : pOfferId, + "OrderCurrency_param" : pCurrency || "", + "OrderAddress_param" : pAddress || "", + "OrderHeader_param" : pHeader || "" + }; + neon.openContext("Order", null, null, neon.OPERATINGSTATE_NEW, params); +} + +/** + * gets the title of an offer from the id + * + * @param pOfferId {String} offer-id + * + * @return {String} offer title + */ +OfferUtils.getOfferTitleById = function (pOfferId) +{ + if (!pOfferId) + return ""; + var offerNumber = db.array(db.ROW, SqlCondition.begin() + .andPrepare("OFFER.OFFERID", pOfferId) + .buildSql("select OFFERCODE, VERSNR from OFFER")); + return offerNumber.length > 0 + ? translate.text("Offer") + " " + offerNumber.join("-") + : ""; +} + + +/******************************************************************************/ + +/** + * Provides methods for dealing with offer items. + * Inherits methods from abstract class ItemUtils. + * For documentation, see class ItemUtils. + * + * @class + */ +function OfferItemUtils(pOfferId) { + // extends ItemUtils + ItemUtils.apply(this, [pOfferId, "OFFER"]); + OfferItemUtils.prototype = Object.create(ItemUtils.prototype); + OfferItemUtils.prototype.constructor = OfferItemUtils; +} + +/** + * For documentation, see class ItemUtils. + */ +OfferItemUtils.prototype.getNetAndVat = function(offeritemIdsToDel) { + return ItemUtils.prototype.getNetAndVat.apply(this, [offeritemIdsToDel]); +} + +/** + * For documentation, see class ItemUtils. + */ +OfferItemUtils.prototype.initItemTree = function() { + ItemUtils.prototype.initItemTree.apply(this); +} + +/** + * For documentation, see class ItemUtils. + */ +OfferItemUtils.prototype.getItemSum = function(pQuantity, pPrice, pDiscount, pOptional) { + return ItemUtils.prototype.getItemSum.apply(this, [pQuantity, pPrice, pDiscount, pOptional]); +} + +/** + * For documentation, see class ItemUtils. + */ +OfferItemUtils.prototype.getItemVAT = function(pQuantity, pPrice, pDiscount, pVAT, pOptional) { + return ItemUtils.prototype.getItemVAT.apply(this, [pQuantity, pPrice, pDiscount, pVAT, pOptional]); +} + +/** + * For documentation, see class ItemUtils. + */ +OfferItemUtils.prototype.roundPrice = function(pPrice) { + return ItemUtils.prototype.roundPrice.apply(this, [pPrice]); +} + +/** + * For documentation, see class ItemUtils. + */ +OfferItemUtils.prototype.insertPartsList = function(pProductId, pAssignedTo, pCurrency, pContactId) { + this.initItemTree(); + + var cols = ["OFFERITEMID" + , "OFFER_ID" + , "PRODUCT_ID" + , "GROUPCODEID" + , "ASSIGNEDTO" + , "ITEMNAME" + , "UNIT" + , "PRICE" + , "VAT" + , "QUANTITY" + , "OPTIONAL" + , "ITEMPOSITION" + , "ITEMSORT"]; + + return ItemUtils.prototype.insertPartsList.apply(this, [cols, pProductId, pAssignedTo, pCurrency, pContactId, [["INFO", "INFO"]]]); +} + +/** + * For documentation, see class ItemUtils. + */ +OfferItemUtils.prototype.deletePartsList = function(pItemId) { + this.initItemTree(); + + return ItemUtils.prototype.deletePartsList.apply(this, [pItemId]); +} + +/** + * For documentation, see class ItemUtils. + */ +OfferItemUtils.prototype.getNextItemSort = function(pIds) { + this.initItemTree(); + + return ItemUtils.prototype.getNextItemSort.apply(this, [pIds]); +} + +/** + * For documentation, see class ItemUtils. + */ +OfferItemUtils.prototype.getNextItemPosition = function(pAssignedTo, pTree, pIds) { + this.initItemTree(); + + return ItemUtils.prototype.getNextItemPosition.apply(this, [pAssignedTo, pTree, pIds]); +} + +/** + * For documentation, see class ItemUtils. + */ +OfferItemUtils.prototype.reOrgItems = function() { + this.initItemTree(); + + ItemUtils.prototype.reOrgItems.apply(this); +} + -- GitLab