From 9e253deb96aa004c0214a2ed23c92be100fb1df3 Mon Sep 17 00:00:00 2001
From: "S.Listl" <S.Listl@SLISTL.aditosoftware.local>
Date: Fri, 22 Feb 2019 10:07:30 +0100
Subject: [PATCH] =?UTF-8?q?[Projekt:=20Entwicklung=20-=20Neon][TicketNr.:?=
 =?UTF-8?q?=201034882][Angebot=20kopieren=20-=20Im=20Neuanlagemodus=20?=
 =?UTF-8?q?=C3=B6ffnen]?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 entity/Offer_entity/Offer_entity.aod          |  23 ++++
 .../entityfields/address/valueProcess.js      |   7 ++
 .../currency/displayValueProcess.js           |   2 +-
 .../entityfields/currency/valueProcess.js     |   2 +-
 .../entityfields/header/valueProcess.js       |   2 +-
 .../language/displayValueProcess.js           |   2 +-
 .../entityfields/language/valueProcess.js     |   2 +-
 .../newofferversion/onActionProcess.js        |  32 ++----
 .../entityfields/offer_id/valueProcess.js     |   0
 .../entityfields/offercode/onValidation.js    |   3 +-
 .../entityfields/offercode/valueProcess.js    |   7 +-
 .../entityfields/versnr/valueProcess.js       |   5 +-
 .../recordcontainers/db/onDBInsert.js         |   2 +-
 .../AttributePreview_view.aod                 |   4 +
 .../how to copy objects with subitems.adoc    | 100 ++++++++++++++++++
 15 files changed, 162 insertions(+), 31 deletions(-)
 create mode 100644 entity/Offer_entity/entityfields/address/valueProcess.js
 create mode 100644 entity/Offer_entity/entityfields/offer_id/valueProcess.js
 create mode 100644 others/guide/how to copy objects with subitems.adoc

diff --git a/entity/Offer_entity/Offer_entity.aod b/entity/Offer_entity/Offer_entity.aod
index b956bffb57..cba3010100 100644
--- a/entity/Offer_entity/Offer_entity.aod
+++ b/entity/Offer_entity/Offer_entity.aod
@@ -203,6 +203,7 @@
     <entityField>
       <name>OFFER_ID</name>
       <documentation>%aditoprj%/entity/Offer_entity/entityfields/offer_id/documentation.adoc</documentation>
+      <valueProcess>%aditoprj%/entity/Offer_entity/entityfields/offer_id/valueProcess.js</valueProcess>
     </entityField>
     <entityFieldGroup>
       <name>OfferCode_VersNr_fieldgroup</name>
@@ -319,6 +320,7 @@
       <description></description>
       <contentType>LONG_TEXT</contentType>
       <mandatory v="true" />
+      <valueProcess>%aditoprj%/entity/Offer_entity/entityfields/address/valueProcess.js</valueProcess>
     </entityField>
     <entityField>
       <name>ChosenAddress</name>
@@ -451,6 +453,27 @@
       <mandatory v="false" />
       <description>PARAMETER</description>
     </entityParameter>
+    <entityParameter>
+      <name>OfferAddress_param</name>
+      <expose v="true" />
+      <triggerRecalculation v="true" />
+      <mandatory v="false" />
+      <description>PARAMETER</description>
+    </entityParameter>
+    <entityParameter>
+      <name>OfferCode_param</name>
+      <expose v="true" />
+      <triggerRecalculation v="true" />
+      <mandatory v="false" />
+      <description>PARAMETER</description>
+    </entityParameter>
+    <entityParameter>
+      <name>OfferVersnr_param</name>
+      <expose v="true" />
+      <triggerRecalculation v="true" />
+      <mandatory v="false" />
+      <description>PARAMETER</description>
+    </entityParameter>
   </entityFields>
   <recordContainers>
     <dbRecordContainer>
diff --git a/entity/Offer_entity/entityfields/address/valueProcess.js b/entity/Offer_entity/entityfields/address/valueProcess.js
new file mode 100644
index 0000000000..160f9518ed
--- /dev/null
+++ b/entity/Offer_entity/entityfields/address/valueProcess.js
@@ -0,0 +1,7 @@
+import("system.result");
+import("system.vars");
+
+if (vars.exists("$param.OfferAddress_param")) 
+{
+    result.string(vars.get("$param.OfferAddress_param"));
+}
\ No newline at end of file
diff --git a/entity/Offer_entity/entityfields/currency/displayValueProcess.js b/entity/Offer_entity/entityfields/currency/displayValueProcess.js
index 0b37c8e450..251895de0c 100644
--- a/entity/Offer_entity/entityfields/currency/displayValueProcess.js
+++ b/entity/Offer_entity/entityfields/currency/displayValueProcess.js
@@ -2,7 +2,7 @@ import("system.result");
 import("system.vars");
 import("Keyword_lib");
 
-if (vars.exists("$param.OfferCurrency_param")) 
+if (vars.exists("$param.OfferCurrency_param") && vars.get("$param.OfferCurrency_param")) 
 {
     var currency = KeywordUtils.getViewValue($KeywordRegistry.get.Currency, vars.get("$param.OfferCurrency_param"));
     result.string(currency);
diff --git a/entity/Offer_entity/entityfields/currency/valueProcess.js b/entity/Offer_entity/entityfields/currency/valueProcess.js
index 260f47d133..636be1adc9 100644
--- a/entity/Offer_entity/entityfields/currency/valueProcess.js
+++ b/entity/Offer_entity/entityfields/currency/valueProcess.js
@@ -1,7 +1,7 @@
 import("system.result");
 import("system.vars");
 
-if (vars.exists("$param.OfferCurrency_param")) 
+if (vars.exists("$param.OfferCurrency_param") && vars.get("$param.OfferCurrency_param")) 
 {
     result.string(vars.get("$param.OfferCurrency_param"));
 }
\ No newline at end of file
diff --git a/entity/Offer_entity/entityfields/header/valueProcess.js b/entity/Offer_entity/entityfields/header/valueProcess.js
index 6dcb1ead4d..c1dd2bbc6e 100644
--- a/entity/Offer_entity/entityfields/header/valueProcess.js
+++ b/entity/Offer_entity/entityfields/header/valueProcess.js
@@ -1,7 +1,7 @@
 import("system.result");
 import("system.vars");
 
-if (vars.exists("$param.OfferHeader_param")) 
+if (vars.exists("$param.OfferHeader_param") && vars.get("$param.OfferHeader_param")) 
 {
     result.string(vars.get("$param.OfferHeader_param"));
 }
\ No newline at end of file
diff --git a/entity/Offer_entity/entityfields/language/displayValueProcess.js b/entity/Offer_entity/entityfields/language/displayValueProcess.js
index a9f344b0ee..987df7556f 100644
--- a/entity/Offer_entity/entityfields/language/displayValueProcess.js
+++ b/entity/Offer_entity/entityfields/language/displayValueProcess.js
@@ -4,7 +4,7 @@ import("system.result");
 import("system.vars");
 import("Sql_lib");
 
-if (vars.exists("$param.OfferLanguage_param")) 
+if (vars.exists("$param.OfferLanguage_param") && vars.get("$param.OfferLanguage_param")) 
 {
     var iso3 = vars.get("$param.OfferLanguage_param");
     var latinName = db.cell(SqlCondition.begin()
diff --git a/entity/Offer_entity/entityfields/language/valueProcess.js b/entity/Offer_entity/entityfields/language/valueProcess.js
index 7bb63ab86b..4fc924e182 100644
--- a/entity/Offer_entity/entityfields/language/valueProcess.js
+++ b/entity/Offer_entity/entityfields/language/valueProcess.js
@@ -1,7 +1,7 @@
 import("system.result");
 import("system.vars");
 
-if (vars.exists("$param.OfferLanguage_param")) 
+if (vars.exists("$param.OfferLanguage_param") && vars.get("$param.OfferLanguage_param")) 
 {
     result.string(vars.get("$param.OfferLanguage_param"));
 }
\ No newline at end of file
diff --git a/entity/Offer_entity/entityfields/newofferversion/onActionProcess.js b/entity/Offer_entity/entityfields/newofferversion/onActionProcess.js
index 0a83f68272..add48fbf11 100644
--- a/entity/Offer_entity/entityfields/newofferversion/onActionProcess.js
+++ b/entity/Offer_entity/entityfields/newofferversion/onActionProcess.js
@@ -1,26 +1,16 @@
 import("system.vars");
 import("system.neon");
-import("Util_lib");
-import("Neon_lib");
 import("Offer_lib");
 
-var InputMapping = {
-    
-    "OFFER": {
-            condition: "OFFERID = '" + vars.get("$field.OFFERID") + "'"
-            , ValueMapping: {
-                            "OFFER_ID": vars.get("$field.OFFERID")
-                            , "OFFERCODE":  vars.get("$field.OFFERCODE")
-                            , "VERSNR":  OfferUtils.getNextOfferVersionNumber(vars.get("$field.OFFERCODE"))
-                        }
-            , SubModules:{
-                "OFFERITEM": {
-                    condition: "OFFER_ID = '" + vars.get("$field.OFFERID") + "' order by ITEMSORT" 
-            }
-        }
-    }
+var params = {
+    "ContactId_param" : vars.get("$field.CONTACT_ID"),
+    "SalesprojectId_param" : vars.get("$field.SALESPROJECT_ID"),
+    "OfferLanguage_param" : vars.get("$field.LANGUAGE"),
+    "OfferOriginal_Id_param" : vars.get("$field.OFFERID"),
+    "OfferCode_param" : vars.get("$field.OFFERCODE"),
+    "OfferVersnr_param" : OfferUtils.getNextOfferVersionNumber(vars.get("$field.OFFERCODE")),
+    "OfferCurrency_param" : vars.get("$field.CURRENCY"),
+    "OfferAddress_param" : vars.get("$field.ADDRESS"),
+    "OfferHeader_param" : vars.get("$field.HEADER")
 }
-
-var ModulesMapping = CopyModuleUtils.copyModule(InputMapping);
-
-CopyModuleUtils.openNewModules("Offer", ModulesMapping);
\ No newline at end of file
+neon.openContext("Offer", null, null, neon.OPERATINGSTATE_NEW, params);
\ No newline at end of file
diff --git a/entity/Offer_entity/entityfields/offer_id/valueProcess.js b/entity/Offer_entity/entityfields/offer_id/valueProcess.js
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/entity/Offer_entity/entityfields/offercode/onValidation.js b/entity/Offer_entity/entityfields/offercode/onValidation.js
index de949a3e76..3b9c0b76f6 100644
--- a/entity/Offer_entity/entityfields/offercode/onValidation.js
+++ b/entity/Offer_entity/entityfields/offercode/onValidation.js
@@ -6,7 +6,8 @@ import("Salesproject_lib");
 import("Util_lib");
 import("Entity_lib");
 
-if( vars.get("$sys.recordstate") == neon.OPERATINGSTATE_NEW
+if (vars.get("$sys.recordstate") == neon.OPERATINGSTATE_NEW
+    && !vars.exists("$param.OfferCode_param")
     && !OfferUtils.validateOfferNumber(ProcessHandlingUtils.getOnValidationValue(vars.get("$field.OFFERCODE"))) )
 {
     vars.set( "$field.OFFERCODE", OfferUtils.getNextOfferNumber().toString() );
diff --git a/entity/Offer_entity/entityfields/offercode/valueProcess.js b/entity/Offer_entity/entityfields/offercode/valueProcess.js
index 933257e8cc..502b44731b 100644
--- a/entity/Offer_entity/entityfields/offercode/valueProcess.js
+++ b/entity/Offer_entity/entityfields/offercode/valueProcess.js
@@ -4,6 +4,9 @@ import("system.neon");
 import("Offer_lib");
 
 if(vars.get("$sys.recordstate") == neon.OPERATINGSTATE_NEW)
-{    
-    result.string(OfferUtils.getNextOfferNumber());
+{
+    if (vars.exists("$param.OfferCode_param") && vars.get("$param.OfferCode_param"))
+        result.string(vars.get("$param.OfferCode_param"));
+    else
+        result.string(OfferUtils.getNextOfferNumber());
 }
\ No newline at end of file
diff --git a/entity/Offer_entity/entityfields/versnr/valueProcess.js b/entity/Offer_entity/entityfields/versnr/valueProcess.js
index f3ad73d056..5d3797b77b 100644
--- a/entity/Offer_entity/entityfields/versnr/valueProcess.js
+++ b/entity/Offer_entity/entityfields/versnr/valueProcess.js
@@ -5,5 +5,8 @@ import("Offer_lib");
 
 if(vars.get("$sys.recordstate") == neon.OPERATINGSTATE_NEW)
 {
-    result.string( "1" );
+    if (vars.exists("$param.OfferVersnr_param") && vars.get("$param.OfferVersnr_param"))
+        result.string(vars.get("$param.OfferVersnr_param"));
+    else
+        result.string( "1" );
 }
\ No newline at end of file
diff --git a/entity/Offer_entity/recordcontainers/db/onDBInsert.js b/entity/Offer_entity/recordcontainers/db/onDBInsert.js
index 5630d92a29..6b3c4033a0 100644
--- a/entity/Offer_entity/recordcontainers/db/onDBInsert.js
+++ b/entity/Offer_entity/recordcontainers/db/onDBInsert.js
@@ -3,4 +3,4 @@ import("system.vars");
 import("Offer_lib");
 
 if (vars.get("$sys.operatingstate") == neon.OPERATINGSTATE_NEW && vars.exists("$param.OfferOriginal_Id_param"))
-    OfferUtils.copyOfferItems(vars.getString("$param.OfferOriginal_Id_param"), vars.get("$field.OFFERID"));
\ No newline at end of file
+    OfferUtils.copyOfferItems(vars.getString("$param.OfferOriginal_Id_param"), vars.get("$field.OFFERID"));
diff --git a/neonView/AttributePreview_view/AttributePreview_view.aod b/neonView/AttributePreview_view/AttributePreview_view.aod
index 59adbab341..f3e5d5fa9e 100644
--- a/neonView/AttributePreview_view/AttributePreview_view.aod
+++ b/neonView/AttributePreview_view/AttributePreview_view.aod
@@ -20,6 +20,10 @@
       <entityField>#ENTITY</entityField>
       <title></title>
       <fields>
+        <entityFieldLink>
+          <name>5f20a5d4-0343-4b8c-92bf-15eeb2483ba9</name>
+          <entityField>ATTRIBUTE_PARENT_ID</entityField>
+        </entityFieldLink>
         <entityFieldLink>
           <name>e00bfeb1-7003-4d5a-b71a-c6921e255c9d</name>
           <entityField>ATTRIBUTE_ACTIVE</entityField>
diff --git a/others/guide/how to copy objects with subitems.adoc b/others/guide/how to copy objects with subitems.adoc
new file mode 100644
index 0000000000..63f85af694
--- /dev/null
+++ b/others/guide/how to copy objects with subitems.adoc	
@@ -0,0 +1,100 @@
+How to make an action for copying modules
+=========================================
+:toc2: left
+:numbered:
+
+== What this guide is for ==
+You want to create an action or process that should copy a module with
+related sub-items.
+(for example: Offer + OfferItems, Order + OrderItems)
+
+== How to do it ==
+There are two possibilities when it comes to creating a new dataset based on another one:
+
+* Save it directly and open the created dataset in show-mode
+* Open it in new-mode so that the user can make changes first or cancel the action
+
+=== Save it directly ===
+This is relatively easy to do with the functions in the Neon_lib.
+At first you have make the copy with the method "CopyModuleUtils.copyModule". It requires an InputMapping object that
+defines the structure of the module. For example:
+
+[source, javascript]
+----
+var InputMapping = {
+    "OFFER": {
+            condition: "OFFERID = '" + vars.get("$field.OFFERID") + "'"
+            , ValueMapping: {
+                            "OFFER_ID": ""
+                            , "OFFERCODE":  OfferUtils.getNextOfferNumber()
+                            , "VERSNR": "1"
+                        }
+            , SubModules:{
+                "OFFERITEM": {
+                    condition: "OFFER_ID = '" + vars.get("$field.OFFERID") + "' order by ITEMSORT" 
+            }
+        }
+    }
+}
+----
+
+The root element of the object (in this case 'OFFER') defines what module is copied, the condition is used to select the specific dataset.
+'ValueMapping' should be used when some fields need new values (for example the offercode should not be the same as in the copied object).
+You can also set 'SubModules' in order to copy sub-elements like offerItems.
+Now you just have to use the following code:
+
+[source, javascript]
+----
+var ModulesMapping = CopyModuleUtils.copyModule(InputMapping);
+
+CopyModuleUtils.openNewModules("Offer", ModulesMapping);
+----
+
+The first line copies the module and the second line opens the newly created dataset.
+
+=== Open it in new-mode first ===
+For this case it needs a few more steps. For values that should be preset in the edit view, you will need to create
+parameters in the entity for every one (set them exposed, triggerRecalculation and not mandatory). After that you have to use these parameters in the valueProcess of the fields
+they should fill. 
+The next step is to create an action that opens the context in new-mode. That could look like this:
+
+[source, javascript]
+----
+var params = {
+    "ContactId_param" : vars.get("$field.CONTACT_ID"),
+    "SalesprojectId_param" : vars.get("$field.SALESPROJECT_ID"),
+    "OfferLanguage_param" : vars.get("$field.LANGUAGE"),
+    "OfferOriginal_Id_param" : vars.get("$field.OFFERID"),
+    "OfferCode_param" : vars.get("$field.OFFERCODE"),
+    "OfferVersnr_param" : OfferUtils.getNextOfferVersionNumber(vars.get("$field.OFFERCODE")),
+    "OfferCurrency_param" : vars.get("$field.CURRENCY"),
+    "OfferAddress_param" : vars.get("$field.ADDRESS"),
+    "OfferHeader_param" : vars.get("$field.HEADER")
+}
+neon.openContext("Offer", null, null, neon.OPERATINGSTATE_NEW, params);
+----
+
+Important: There has to be one parameter for the id, so that sub-items can be copied (see the following).
+
+Now we can preset values of the module, but what about related things like offerItems?
+For that we use the same function as in the section above. Because the offerItems should only be copied to the new offer when the user
+saved it, this has to be done in the onInsert-process of the recordcontainer.
+
+[source, javascript]
+----
+if (vars.get("$sys.operatingstate") == neon.OPERATINGSTATE_NEW && vars.exists("$param.OfferOriginal_Id_param"))
+{
+    var InputMapping = {
+        "OFFERITEM": {
+            condition: "OFFER_ID = '" + vars.getString("$param.OfferOriginal_Id_param") + "' order by ITEMSORT",
+            ValueMapping: {
+                "OFFER_ID" : vars.get("$field.OFFERID")
+            }
+        }
+    };
+    CopyModuleUtils.copyModule(InputMapping);
+}
+----
+
+The offer is already created, so that only offerItem is needed in the 'InputMapping'. The 'condition' should use the id of the offer
+that is copied and in 'ValueMapping' the foreign-key 'OFFER_ID' gets the value of the id of the newly created offer.
\ No newline at end of file
-- 
GitLab