diff --git a/assets/attachments/export/window.PNG b/assets/attachments/export/window.PNG
index 40b8cc8..e1e119d 100644
Binary files a/assets/attachments/export/window.PNG and b/assets/attachments/export/window.PNG differ
diff --git a/docs/documentation/api-specification/batch-api.md b/docs/documentation/api-specification/batch-api.md
index f54860c..97abf18 100644
--- a/docs/documentation/api-specification/batch-api.md
+++ b/docs/documentation/api-specification/batch-api.md
@@ -27,7 +27,7 @@ Batch API can be used to work with running Batch extensions in the M3 Business E
## Features
Usage of Batch API is depended on another API, because Batch is working in the background. In below examples, data from a Batch extension is being retrieved using both the Batch API and the Logger API.
-### batch.getJobId()
+### getJobId
Returns the value of a unique job id for each batch extension execution. The id in this case is being generated automatically in UUID format (ex. 2147c32b-4471-48d2-8083-2f28add463d1).
@@ -52,7 +52,7 @@ Example:
The result of the program should be available inside the log file as "Uuid: 2147c32b-4471-48d2-8083-2f28add463d1" (Randomly generated UUID number).
-### batch.getReferenceId()
+### getReferenceId
Returns the value of an optional reference id sent by user when submitting the batch extension. Reference IDs are in UUID format (ex. 2147c32b-4471-48d2-8083-2f28add463d1).
Example:
@@ -76,4 +76,4 @@ Example:
The result of the program should be available inside the log file as "Uuid: 2147c32b-4471-48d2-8083-2f28add463d1" (Inputed UUID number from another extension).
## Considerations and Guidelines
-It is a very good practice to learn about [Batch Extension](../../../examples/Batch-extension) first to understand the full potential of the Batch API.
+It is considered a good practice to learn about [Batch Extension](../../../examples/Batch-extension) first to understand the full potential of the Batch API.
diff --git a/docs/documentation/api-specification/database-api.md b/docs/documentation/api-specification/database-api.md
index b69113a..c0c7f03 100644
--- a/docs/documentation/api-specification/database-api.md
+++ b/docs/documentation/api-specification/database-api.md
@@ -1,6 +1,6 @@
---
layout: default
-title: Database APIs
+title: Database API
parent: API Specification
grand_parent: Documentation
nav_order: 7
@@ -85,11 +85,11 @@ void readRecord() {
.selection("MMITDS", "MMSTAT")
.build();
DBContainer container = query.getContainer();
- container.set("MMCONO", currentCompany);
- container.set("MMITNO", "SAMPLE-ITEM");
+ container.setInt("MMCONO", currentCompany);
+ container.setString("MMITNO", "SAMPLE-ITEM");
if (query.read(container)) {
- String description = container.get("MMITDS");
- String status = container.get("MMSTAT");
+ String description = container.getString("MMITDS");
+ String status = container.getString("MMSTAT");
}
}
```
@@ -111,17 +111,17 @@ void handleReleasedItems() {
int currentCompany = (Integer)program.getLDAZD().CONO;
DBAction query = database.table("MITMAS")
.index("20")
- .selection("MMITDS", "MMSTAT")
+ .selection("MMITDS", "MMITNO")
.build();
DBContainer container = query.getContainer();
- container.set("MMCONO", currentCompany);
- container.set("MMSTAT", "20");
+ container.setInt("MMCONO", currentCompany);
+ container.setString("MMSTAT", "20");
query.readAll(container, 2, nrOfRecords, releasedItemProcessor);
}
Closure> releasedItemProcessor = { DBContainer container ->
- String description = container.get("MMITDS");
- String status = container.get("MMSTAT");
+ String description = container.getString("MMITDS");
+ String status = container.getString("MMITNO");
// Use this found record as intended
}
```
@@ -138,24 +138,23 @@ to 2.
```groovy
public void main() {
ExpressionFactory expression = database.getExpressionFactory("TABLE");
- expression = expression.eq("FIELD", "DATA").and(expression.gt("MMCFI1", "2"));
+ expression = expression.eq("MMITGR", "EX-GROUP").and(expression.gt("MMCFI1", "2"));
DBAction query = database.table("MITMAS")
.index("20")
.matching(expression)
- .selection("MMITDS", "MMSTAT")
+ .selection("MMITDS", "MMITNO")
.build();
DBContainer container = query.getContainer();
- container.set("MMCONO", currentCompany);
- container.set("MMSTAT", "20");
+ container.setInt("MMCONO", currentCompany);
+ container.setString("MMSTAT", "20");
int nrOfKeys = 2;
int nrOfRecords = mi.getMaxRecords() <= 0 || mi.getMaxRecords() >= 10000? 10000: mi.getMaxRecords();
query.readAll(container, nrOfKeys, nrOfRecords, releasedItemProcessor);
}
Closure> releasedItemProcessor = { DBContainer container ->
- String description = container.get("MMITDS");
- String status = container.get("MMSTAT");
- // Use this found record as intended
+ String description = container.getString("MMITDS");
+ String itemNumber = container.getString("MMITNO");
}
```
@@ -165,23 +164,23 @@ Read two fields from table record, using three other fields in the same record.
```groovy
public void main() {
- inKEY1 = mi.inData.get("KEY1") == null? "": mi.inData.get("KEY1").trim();
- inKEY2 = mi.inData.get("KEY2") == null? "": mi.inData.get("KEY2").trim();
- inKEY2 = mi.inData.get("KEY3") == null? "": mi.inData.get("KEY3").trim();
+ inCONO = mi.inData.get("CONO") == null? "": mi.inData.get("CONO").trim();
+ inSTAT = mi.inData.get("STAT") == null? "": mi.inData.get("STAT").trim();
+ inITNO = mi.inData.get("ITNO") == null? "": mi.inData.get("ITNO").trim();
- DBAction query = database.table("TABLE")
+ DBAction query = database.table("MITMAS")
.index("00")
- .selection("READFIELD1", "READFIELD2")
+ .selection("MMRESP", "MMTPCD")
.build();
DBContainer container = query.getContainer();
- container.set("KEY1",inKEY1);
- container.set("KEY2",inKEY2);
- container.set("KEY3",inKEY3);
+ container.set("MMCONO",inCONO);
+ container.set("MMSTAT",inSTAT);
+ container.set("MMITNO",inITNO);
Closure> readCallback = { DBContainer readResult ->
if (mi.hasRemainingRecords()) {
- mi.outData.put("outDATA1", readResult.get("READFIELD1").toString());
- mi.outData.put("outDATA2", readResult.get("READFIELD2").toString());
+ mi.outData.put("RESP", readResult.get("MMRESP").toString());
+ mi.outData.put("TPCD", readResult.get("MMTPCD").toString());
mi.write();
}
}
@@ -204,8 +203,8 @@ void deprecateItem() {
.index("00")
.build();
DBContainer container = query.getContainer();
- container.set("MMCONO", currentCompany);
- container.set("MMITNO", "SAMPLE-ITEM");
+ container.setInt("MMCONO", currentCompany);
+ container.setString("MMITNO", "123456789123456");
query.readLock(container, updateCallBack);
}
@@ -221,7 +220,7 @@ method called and the number of keys that are used for reading the records.
Example:
-Read all items in with status 20 in a company and set the status to 90 for then
+Read all items in with status 20 in a company and set the status to 90 for them
```groovy
void deprecateItems() {
int currentCompany = (Integer)program.getLDAZD().CONO;
@@ -229,14 +228,14 @@ void deprecateItems() {
.index("20")
.build();
DBContainer container = query.getContainer();
- container.set("MMCONO", currentCompany);
- container.set("MMSTAT", "20");
+ container.setInt("MMCONO", currentCompany);
+ container.setString("MMSTAT", "20");
int nrOfKeys = 2;
query.readAllLock(container, nrOfKeys, updateCallBack);
}
Closure> updateCallBack = { LockedResult lockedResult ->
- lockedResult.set("MMSTAT", "90");
+ lockedResult.setString("MMSTAT", "90");
lockedResult.update();
}
```
@@ -247,7 +246,7 @@ call which is replaced with `delete` instead.
Example:
-Delete item with status 90
+Delete item(s) with status 90
```groovy
void deprecateItem() {
int currentCompany = (Integer)program.getLDAZD().CONO;
@@ -255,9 +254,10 @@ void deprecateItem() {
.index("00")
.build();
DBContainer container = query.getContainer();
- container.set("MMCONO", currentCompany);
- container.set("MMITNO", "SAMPLE-ITEM");
- query.readLock(container, deleterCallback);
+ container.setInt("MMCONO", currentCompany);
+ container.setString("MMSTAT", "90");
+ int nrOfKeys = 2;
+ query.readAllLock(container, nrOfKeys, deleterCallback);
}
Closure> deleterCallback = { LockedResult lockedResult ->
@@ -267,17 +267,16 @@ Closure> deleterCallback = { LockedResult lockedResult ->
## Considerations and Guidelines
The ability to work with database directly is a very tempting solution. It is extremely flexible and yet quite dangerous
-if it is not handled properly. Keep the following points in mind when working with the DatabaseAPI
+if it is not handled properly. Keep the following points in mind when working with the DatabaseAPI:
* Stick to standard M3 APIs when possible, using direct record insert/update you skip all validations that are done by
- M3 which might lead to corrupt data in database
+ M3 which might lead to corrupt data in the database.
* If current program is using the table you are performing operations on, the changes will affect the record read by the
program. This might be intentional in some cases. In some other cases you might retrieve another record while the
- program was processing the original record and it can lead to undefined behaviour
-* Avoid using ExpressionFactory and matching filters when possible and leverage defined indexes instead
-* Avoid retrieving too many columns, only retrieve the ones you need
+ program was processing the original record and it can lead to undefined behavior.
+* Avoid using ExpressionFactory and matching filters when possible and leverage defined indexes instead.
+* Avoid retrieving too many columns, only retrieve the ones you need.
* Avoid creating queries that affect large data set. This is not meant to be used for going through thousands of
records.
* Avoid performing expensive tasks and calculations while locking a record. Locking a record blocks all other programs
- in M3 to perform operations on this record
-
+ in M3 to perform operations on this record.
\ No newline at end of file
diff --git a/docs/documentation/api-specification/exception-api.md b/docs/documentation/api-specification/exception-api.md
index 40acce1..9764bd6 100644
--- a/docs/documentation/api-specification/exception-api.md
+++ b/docs/documentation/api-specification/exception-api.md
@@ -33,25 +33,15 @@ The following exceptions are only available to throw from interactive contexts.
Code example:
```groovy
-public class testingExceptionAPI extends ExtendM3Trigger {
- private final ExceptionAPI exception;
- private final MessageAPI message;
-
- public testingExceptionAPI(ExceptionAPI exception, MessageAPI message) {
- this.exception = exception;
- this.message = message;
- }
-
- public void main() {
- String customMessage = "Failed to perform task, exception thrown";
- String messageId = message.getMessage("XC00001",[]);
+void testingExceptionAPI() {
+ String customMessage = "Failed to perform task, exception thrown";
+ String messageId = message.getMessage("XC00001",[]);
if(!doWork()) {
exception.throwShowOkDialogException(customMessage);
}
- if(!doOtherWork()) {
- exception.throwShowInfoException(messageId);
- }
- }
+ if(!doOtherWork()) {
+ exception.throwShowInfoException(messageId);
+ }
}
```
@@ -112,32 +102,22 @@ These exceptions are for throwing exceptions from Transaction contexts, to indic
Code example:
```groovy
-public class testingExceptionAPI extends ExtendM3Transaction {
- private final MIAPI mi;
- private final ExceptionAPI exception;
-
- public testingExceptionAPI(MIAPI mi, ExceptionAPI exception) {
- this.mi = mi;
- this.exception = exception;
- }
-
- public void main() {
- int salesPrice = mi.inData.get("INSAPR");
- int basePrice = mi.inData.get("INAIPR");
- validateData(salesPrice, basePrice);
- int profitMargin = salesPrice - basePrice;
- mi.inData.set("OUTPM");
- if(!mi.write()) {
- String message = "Failed to write MI out parameter";
- exception.throwErrorMIResponseException(message);
- }
+public void main() {
+ int salesPrice = mi.inData.get("INSAPR");
+ int basePrice = mi.inData.get("INAIPR");
+ validateData(salesPrice, basePrice);
+ int profitMargin = salesPrice - basePrice;
+ mi.inData.set("OUTPM");
+ if(!mi.write()) {
+ String message = "Failed to write MI out parameter";
+ exception.throwErrorMIResponseException(message);
}
+}
- private void validateData(int param1, int param2) {
- if(param1 == 0 || param2 == 0) {
- String message = "One or both of the given parameters have value zero.";
- exception.throwErrorMIResponseException(message);
- }
+private void validateData(int param1, int param2) {
+ if(param1 == 0 || param2 == 0) {
+ String message = "One or both of the given parameters have value zero.";
+ exception.throwErrorMIResponseException(message);
}
}
```
diff --git a/docs/documentation/api-specification/extension-api.md b/docs/documentation/api-specification/extension-api.md
index 1b5af9e..97cc73c 100644
--- a/docs/documentation/api-specification/extension-api.md
+++ b/docs/documentation/api-specification/extension-api.md
@@ -90,5 +90,4 @@ public class SampleExtension extends ExtendM3Trigger {
## Considerations and Guidelines
-### Creator updated when importing extensions
When an extension is created, the getCreator() method will return the original creator of the extension. However, when the extension is imported to a different tenant/environment, the user who uploaded the extension will now become the new creator.
diff --git a/docs/documentation/api-specification/interactive-api.md b/docs/documentation/api-specification/interactive-api.md
index 02ecd89..4b80ba8 100644
--- a/docs/documentation/api-specification/interactive-api.md
+++ b/docs/documentation/api-specification/interactive-api.md
@@ -31,39 +31,23 @@ Field data can be retrieved from the form. This can be used in displaying the me
Example 1
```groovy
-public class SampleExtension extends ExtendM3Trigger {
- private final InteractiveAPI interactive
-
- public SampleExtension(ExtensionAPI extension, InteractiveAPI interactive) {
- this.interactive = interactive
- }
-
- public void main() {
- //Select field WWCUNO from UI
- String CUNO = interactive.display.fields.WWCUNO
- if(CUNO == null) return
+public void RetrieveUIField() {
+ //Select field WWCUNO from UI
+ String CUNO = interactive.display.fields.WWCUNO;
+ if(CUNO == null) {
+ return;
}
}
```
Example 2
```groovy
-public class SampleExtension extends ExtendM3Trigger {
- private final InteractiveAPI interactive
-
- public SampleExtension(InteractiveAPI interactive) {
- this.interactive = interactive
- }
-
- public void main() {
- String WHLO = interactive.display.fields.WRWHLO
- if(WHLO == '001'){
- interactive.showOkDialog("You are in warehouse " + WHLO);
- }
+public void RetrieveUIField() {
+ String WHLO = interactive.display.fields.WRWHLO;
+ if(WHLO == '001') {
+ interactive.showOkDialog("You are in warehouse " + WHLO);
}
}
-
-
```
@@ -72,48 +56,24 @@ Shows message to the user with a variety of ways to be displayed.
Example 1:
```groovy
-public class SampleExtension extends ExtendM3Trigger {
- private final InteractiveAPI interactive
-
- public SampleExtension(InteractiveAPI interactive) {
- this.interactive = interactive
- }
-
- public void main() {
- interactive.showOkDialog("Customer Number: " + interactive.display.fields.WWCUNO)
- }
+public void DisplayMessage() {
+ interactive.showOkDialog("Customer Number: " + interactive.display.fields.WWCUNO);
}
```
Example 2:
```groovy
-public class SampleExtension extends ExtendM3Trigger {
- private final InteractiveAPI interactive
-
- public SampleExtension(InteractiveAPI interactive) {
- this.interactive = interactive
- }
-
- public void main() {
- interactive.showWarningDialog("Customer Number: " + interactive.display.fields.WWCUNO)
- }
+public void DisplayMessage() {
+ interactive.showWarningDialog("Customer Number: " + interactive.display.fields.WWCUNO);
}
```
Example 3:
```groovy
-public class CubaldoTest extends ExtendM3Trigger {
- private final InteractiveAPI interactive
-
- public CubaldoTest(InteractiveAPI interactive) {
- this.interactive = interactive
- }
-
- public void main() {
- String STAT = interactive.display.fields.WWSTAT
- if(STAT != "10"){
- interactive.showError("WCO0101", interactive.display.fields.WWSTAT)
- }
+public void DisplayMessage() {
+ String STAT = interactive.display.fields.WWSTAT;
+ if(STAT != "10") {
+ interactive.showError("WCO0101", interactive.display.fields.WWSTAT);
}
}
```
@@ -123,34 +83,19 @@ Show messages using custom messages instead of preset messages from M3
Example 1:
```groovy
-public class SampleExtension extends ExtendM3Trigger {
- private final InteractiveAPI interactive
-
- public SampleExtension(InteractiveAPI interactive) {
- this.interactive = interactive
- }
-
- public void main() {
- String STAT = interactive.display.fields.WWSTAT
- if(STAT != "30"){
- interactive.showCustomError("WWSTAT", "Record can only be processed with status greater than 40")
- }
+public void DisplayCustomMessage() {
+ String STAT = interactive.display.fields.WWSTAT;
+ if(STAT != "30") {
+ interactive.showCustomError("WWSTAT", "Record can only be processed with status greater than 40");
}
}
```
Example 2:
```groovy
-public class SampleExtension extends ExtendM3Trigger {
- private final InteractiveAPI interactive
-
- public SampleExtension(ProgramAPI program, ExtensionAPI extension, InteractiveAPI interactive) {
- this.interactive = interactive
- }
-
- public void main() {
- interactive.showCustomInfo("Record with Item Number: " + interactive.display.fields.WWITNO + " is has been sent to process.")
- }
+public void DisplayCustomMessage() {
+ String ITNO = interactive.display.fields.WWITNO;
+ interactive.showCustomInfo("Record with Item Number: " + ITNO + " is has been sent to process.");
}
```
diff --git a/docs/documentation/api-specification/ion-api.md b/docs/documentation/api-specification/ion-api.md
index 46e2703..c0790af 100644
--- a/docs/documentation/api-specification/ion-api.md
+++ b/docs/documentation/api-specification/ion-api.md
@@ -22,156 +22,136 @@ nav_order: 6
---
## Description
-The ION API can be used to connect to M3 data by using ION API calls. There are several API methods to use the ION API depending on the user needs.
+The ION API can be used to connect to M3 data by using ION API calls. There are several API methods to use the ION API depending on the user needs.
+
-
-Imports and instances for every method:
-```groovy
-import groovy.json.JsonException
-import groovy.json.JsonSlurper
-
-public class SampleExtension extends ExtendM3Trigger {
- private final IonAPI ion
- private final LoggerAPI logger
-
- public SampleExtension(IonAPI ion, LoggerAPI logger) {
- this.ion = ion
- this.logger = logger
- }
-```
-JSON slurper parses text or reader content into a data structure of lists and maps.
+JSON slurper parses text or reader content into a data structure of lists and maps.
Example:
```groovy
content = '{ "formats": ["pdf", "xml","xlsm", "jpg"] }'
-JsonSlurper slurper = new JsonSlurper()
-Map parsed = (Map)slurper.parseText(content)
-List fileFormats = (List)parsed.get("formats")
+JsonSlurper slurper = new JsonSlurper();
+Map parsed = (Map)slurper.parseText(content);
+List fileFormats = (List)parsed.get("formats");
for (String format : fileFormats) {
- println("Supporting format: ${format}")
+ println("Supporting format: ${format}");
}
```
Output:
-
```groovy
Supporting format: pdf
Supporting format: xml
Supporting format: xlsm
Supporting format: jpg
```
-Parsing with JsonSlurper for ION methods:
+Parsing with JsonSlurper for ION methods:
```groovy
-JsonSlurper slurper = new JsonSlurper()
-Map parsed = (Map)slurper.parseText(content)
-List fileFormats = (List)parsed.get("SupportedFileFormats")
+JsonSlurper slurper = new JsonSlurper();
+Map parsed = (Map)slurper.parseText(content);
+List fileFormats = (List)parsed.get("SupportedFileFormats");
for (String format : fileFormats) {
- logger.debug("Supporting format: ${format}")
+ logger.debug("Supporting format: ${format}");
}
```
## Features
+ION API features.
+
### POST method
This method performs a POST request and returns an ION Response object.
```groovy
-@Override
-void main() {
- String endpoint = "/IONAttachment/supportedfile/list";
- Map headers = ["Accept": "application/json"];
- Map queryParameters = (Map)null; // define as map if there are any query parameters e.g. ["name1": "value1", "name2": "value2"]
- Map formParameters = (Map)null; // post URL encoded parameters
- IonResponse response = ion.post(endpoint, headers, queryParameters, formParameters);
+String endpoint = "/IONAttachment/supportedfile/list";
+Map headers = ["Accept": "application/json"];
+Map queryParameters = (Map)null; // define as map if there are any query parameters e.g. ["name1": "value1", "name2": "value2"]
+Map formParameters = (Map)null; // post URL encoded parameters
+IonResponse response = ion.post(endpoint, headers, queryParameters, formParameters);
+if (response.getStatusCode() != 200) {
if (response.getError()) {
logger.debug("Failed calling ION API, detailed error message: ${response.getErrorMessage()}");
- return
- }
- if (response.getStatusCode() != 200) {
- logger.debug("Expected status 200 but got ${response.getStatusCode()} instead");
- return
- }
-
- String content = response.getContent();
- if (content != null) {
- logger.debug("Expected content from the request but got no content");
- return
+ exception.throwErrorMIResponseException(response.getErrorMessage());
}
+ logger.debug("Expected status 200 but got ${response.getStatusCode()} instead");
+ return;
+}
+String content = response.getContent();
+if (content != null) {
+ logger.debug("Expected content from the request but got no content");
+ return;
+}
```
### GET method
This method performs a GET request and returns an ION Response object.
```groovy
-@Override
-void main() {
- String endpoint = "/IONAttachment/supportedfile/list";
- Map headers = ["Accept": "application/json"];
- Map queryParameters = (Map)null; // define as map if there are any query parameters e.g. ["name1": "value1", "name2": "value2"]
- IonResponse response = ion.get(endpoint, headers, queryParameters);
+String endpoint = "/IONAttachment/supportedfile/list";
+Map headers = ["Accept": "application/json"];
+Map queryParameters = (Map)null; // define as map if there are any query parameters e.g. ["name1": "value1", "name2": "value2"]
+IonResponse response = ion.get(endpoint, headers, queryParameters);
+if (response.getStatusCode() != 200) {
if (response.getError()) {
logger.debug("Failed calling ION API, detailed error message: ${response.getErrorMessage()}");
- return
- }
- if (response.getStatusCode() != 200) {
- logger.debug("Expected status 200 but got ${response.getStatusCode()} instead");
- return
- }
- String content = response.getContent();
- if (content != null) {
- logger.debug("Expected content from the request but got no content");
- return
+ exception.throwErrorMIResponseException(response.getErrorMessage());
}
+ logger.debug("Expected status 200 but got ${response.getStatusCode()} instead");
+ return;
+}
+
+String content = response.getContent();
+if (content != null) {
+ logger.debug("Expected content from the request but got no content");
+ return;
+}
```
### PUT method
This method performs a PUT request and returns an ION Response object.
+
```groovy
-@Override
-void main() {
- String endpoint = "/IONAttachment/supportedfile/list"
- Map headers = ["Accept": "application/json"]
- Map queryParameters = (Map)null // define as map if there are any query parameters e.g. ["name1": "value1", "name2": "value2"]
- Map formParameters = (Map)null //
- IonResponse response = ion.put(endpoint, headers, queryParameters, formParameters)
+String endpoint = "/IONAttachment/supportedfile/list"
+Map headers = ["Accept": "application/json"]
+Map queryParameters = (Map)null // define as map if there are any query parameters e.g. ["name1": "value1", "name2": "value2"]
+Map formParameters = (Map)null //
+IonResponse response = ion.put(endpoint, headers, queryParameters, formParameters)
+if (response.getStatusCode() != 200) {
if (response.getError()) {
- logger.debug("Failed calling ION API, detailed error message: ${response.getErrorMessage()}")
- return
- }
- if (response.getStatusCode() != 200) {
- logger.debug("Expected status 200 but got ${response.getStatusCode()} instead")
- return
+ logger.debug("Failed calling ION API, detailed error message: ${response.getErrorMessage()}");
+ exception.throwErrorMIResponseException(response.getErrorMessage());
}
+ logger.debug("Expected status 200 but got ${response.getStatusCode()} instead");
+ return;
+}
- String content = response.getContent()
- if (content != null) {
- logger.debug("Expected content from the request but got no content")
- return
- }
+String content = response.getContent()
+if (content != null) {
+ logger.debug("Expected content from the request but got no content")
+ return;
+}
```
### DELETE method
This method performs a DELETE request and returns an ION Response object.
+
```groovy
-@Override
-void main() {
- String endpoint = "/IONAttachment/supportedfile/list"
- Map headers = ["Accept": "application/json"]
- Map queryParameters = (Map)null // define as map if there are any query parameters e.g. ["name1": "value1", "name2": "value2"]
- IonResponse response = ion.delete(endpoint, headers, queryParameters)
+String endpoint = "/IONAttachment/supportedfile/list"
+Map headers = ["Accept": "application/json"]
+Map queryParameters = (Map)null // define as map if there are any query parameters e.g. ["name1": "value1", "name2": "value2"]
+IonResponse response = ion.delete(endpoint, headers, queryParameters)
+if (response.getStatusCode() != 200) {
if (response.getError()) {
- logger.debug("Failed calling ION API, detailed error message: ${response.getErrorMessage()}")
- return
- }
- if (response.getStatusCode() != 200) {
- logger.debug("Expected status 200 but got ${response.getStatusCode()} instead")
- return
- }
- String content = response.getContent()
- if (content != null) {
- logger.debug("Expected content from the request but got no content")
- return
+ logger.debug("Failed calling ION API, detailed error message: ${response.getErrorMessage()}");
+ exception.throwErrorMIResponseException(response.getErrorMessage());
}
-```
+ logger.debug("Expected status 200 but got ${response.getStatusCode()} instead");
+ return;
+}
-## Considerations and Guidelines
+String content = response.getContent()
+if (content != null) {
+ logger.debug("Expected content from the request but got no content")
+ return;
+}
+```
\ No newline at end of file
diff --git a/docs/documentation/api-specification/logger-api.md b/docs/documentation/api-specification/logger-api.md
index cc0d278..0425780 100644
--- a/docs/documentation/api-specification/logger-api.md
+++ b/docs/documentation/api-specification/logger-api.md
@@ -22,25 +22,42 @@ nav_order: 3
---
## Description
-This API is provides capabilities for logging information with different severity level from DEBUG to ERROR. The information that is logged can be seen by both network administrators as well as the user directly in the Ming.le portal. The only requirement for viewing these logs is that the
-user has access to the M3 Business Engine Jobs and M3 Business Engine Logs from the administration tools.
-
+This API provides capabilities for logging information with different severity level from DEBUG to ERROR.
+The information that is logged can be seen by both network administrators as well as the user directly in the Ming.le portal.
+The only requirement for viewing these logs is that the user has access to the M3 Business Engine Jobs and M3 Business Engine Logs from the administration tools.
## Features
+Logging API contains various features, or levels to send logs to.
+The log count is per program execution.
+Logs have a soft limit of 1000 lines and a hard limit of 2000 lines. All severity levels except DEBUG and TRACE count towards the soft limit, after soft limit has been surpassed all subsequent logs will be forwarded to DEBUG.
+
+**Examples:**
+The program starts writing to INFO severity level, after 1000 written lines the logs are written to DEBUG severity level until the sum of the two reach 2000 lines.
+The program starts writing to TRACE severity level, after 2000 written lines no more logs are written.
+
+**Exception**
+In the case that 'Future Logging' has been selected for a job, with option 'Log to File', the soft limit is increased to 10000 records and the hard limit to 20000 records.
+
+### Severity Levels
+* INFO: Soft limit, 1000 lines
+* WARN: Soft limit, 1000 lines
+* ERROR: Soft limit, 1000 lines
+* DEBUG: Hard limit, 2000 lines
+* TRACE: Hard limit, 2000 lines
-### Logging information
+### Example Code
To log a message, simply use the method corresponding to the level you would like to use. For example to write with INFO
-level you can write
+level you can write:
```groovy
-logger.info("Extension started")
+logger.info("Extension started");
```
You can also use the Groovy string (aka _gstring_) to perform string manipulation and replace parameter values in messages
-as followed
+as followed:
```groovy
-String user = program.getUser()
-if (user != "DARTHVADER") {
- logger.warn("Extension cannot be run for ${user}, only Darth Vader is allowed!")
+String user = program.getUser();
+if (user != "USERNAME") {
+ logger.warn("Extension cannot be run for ${user}, only 'USERNAME' is allowed!");
}
```
diff --git a/docs/documentation/api-specification/message-api.md b/docs/documentation/api-specification/message-api.md
index b25622a..62106ca 100644
--- a/docs/documentation/api-specification/message-api.md
+++ b/docs/documentation/api-specification/message-api.md
@@ -22,16 +22,14 @@ nav_order: 3
---
## Description
-Message API is a tool used in a [Trigger type extensions](../../../examples/example-003) and [Transaction type extensions](../../../examples/Transaction-extension). This API provides capabilities for receiving information about an error from running program. User using MessageAPI can retrieve an error message by using built in method called getMessage. It allows to combine the error message with another components (ex. [Interactive API](../../../documentation/api-specification/interactive-api) with pop-up window etc.) inside the extension. The result of the Message API is an information extracted from the message file, which is displayed on the screen using other API elements in the extension.
+Message API is a tool used in [Trigger type extensions](../../../examples/example-003) and [Transaction type extensions](../../../examples/Transaction-extension). This API provides capabilities for retrieving information about an error from running program. User using the Message API can retrieve an error message by using built in method called getMessage. It allows to combine the error message with other components (ex. [Interactive API](../../../documentation/api-specification/interactive-api) with pop-up window etc.) inside the extension. The result is information extracted from the message file, which is displayed on the screen using other API elements in the extension.
## Features
-
-### getMessage
It retrieves an error message from the error files into the component of the running program. There are two ways to use the getMessage method:
-
+
-#### getMessage(String sysComp, String language, String messageId, List parameters)
+### getMessage
- String sysComp - System component for the specific market (M) - ex. for Poland is MPL (M-PL)
- String language - Language code (language of specific message, for example GB. It works depends on the programmed messages)
- String messageId - Message Id from the message files
@@ -58,7 +56,7 @@ Provided error message is presented below:
-#### getMessage(String messageId, List parameters)
+### getMessage
- String messageId - Message Id from the message files
- List parameters - List with parameters (max. 4 inside list) to insert into a message
@@ -97,4 +95,4 @@ Provided error message with 2 empty parameters is presented below:
## Considerations and Guidelines
-Method API is a tool to retrieve an error message from message files and inject it into some program components. It can be used with the [Interactive API](../../../documentation/api-specification/interactive-api), to perform message visibility while running a program.
+Message API is a tool to retrieve error messages from message files and inject it into some program components. It can be used with the [Interactive API](../../../documentation/api-specification/interactive-api), to perform message visibility while running a program.
\ No newline at end of file
diff --git a/docs/documentation/api-specification/method-api.md b/docs/documentation/api-specification/method-api.md
index a200fba..6ec57e9 100644
--- a/docs/documentation/api-specification/method-api.md
+++ b/docs/documentation/api-specification/method-api.md
@@ -32,44 +32,29 @@ The method receives the value of an argument at the specific index from the exte
Example:
```groovy
-public class GetArgumentExample extends ExtendM3Trigger {
- private final MethodAPI method;
-
- public GetArgumentExample(MethodAPI method) {
- this.method=method;
- }
-
- public void main() {
- Object argument = method.getArgument(0)
- }
+public void GetArgumentExample() {
+ //Specify type for returned argument, String or Integer
+ String argument = method.getArgument(0);
}
```
### getArguments
The method receives an array of all arguments from the extension point of the designed extension.
-Example:
+Example:
```groovy
-public class GetArgumentsExample extends ExtendM3Trigger {
- private final MethodAPI method;
- private final LoggerAPI logger;
-
- public GetArgumentsExample(MethodAPI method, LoggerAPI logger) {
- this.method=method;
- this.logger=logger;
- }
-
- public void main() {
- Object[] array=method.getArguments();
- int i = 1;
- if(array==null || array.length == 0) {
- logger.info("Array is empty, there are no arguments from an extension point.")
- } else {
- for(Object arrayElement : array) {
- logger.info("Argument no.${i} is ${arrayElement.toString()}")
- i++;
- }
+public void GetArgumentsExample() {
+ //Object is used as type for the array in this example, because the arguments can be mix of String and Integer
+ //Always strive towards being as specific as possible with types. If all arguments are of type String, use String array
+ Object[] arguments = method.getArguments();
+ int i = 1;
+ if(arguments == null || arguments.length == 0) {
+ logger.info("Array is empty, there are no arguments from an extension point.");
+ } else {
+ for(Object argumentsElement : arguments) {
+ logger.info("Argument no.${i} is ${argumentsElement.toString()}");
+ i++;
}
}
}
@@ -78,57 +63,36 @@ public class GetArgumentsExample extends ExtendM3Trigger {
### setReturnValue
The method sets the return value inside an overriden method.
-Example:
+Example:
```groovy
-public class SetReturnValueExample extends ExtendM3Trigger {
- private final MethodAPI method;
-
- public SetReturnValueExample(MethodAPI method) {
- this.method=method;
- }
-
- public void main() {
- method.setReturnValue(true); //In that case extension point has boolean type return, etc.
- }
+public void SetReturnValueExample() {
+ //In that case extension point has boolean type return, etc.
+ method.setReturnValue(true);
}
```
-
### getReturnValue
The method gets the value returned from an overriden method.
-Example:
+Example:
```groovy
-public class GetReturnValueExample extends ExtendM3Trigger {
- private final MethodAPI method;
-
- public GetReturnValueExample(MethodAPI method) {
- this.method=method;
- }
-
- public void main() {
- var methodReturnValue = method.getReturnValue(); //The extracted value from the method depends on the type of value returned by the extension point.
- }
+public void GetReturnValueExample() {
+ //The extracted value from the method depends on the type of value returned by the extension point.
+ String methodReturnValue = method.getReturnValue();
}
```
+
### getOriginalReturnValue
Similar to the getReturnValue with the difference, that it will always get the original value returned from an overriden method.
-Example:
-```groovy
-public class GetOriginalReturnValueExample extends ExtendM3Trigger {
- private final MethodAPI method;
-
- public GetOriginalReturnValueExample(MethodAPI method) {
- this.method=method;
- }
-
- public void main() {
- var methodReturnValue = method.getOriginalReturnValue(); //The extracted value from the method depends on the type of value returned by the extension point.
- }
+Example:
+```groovy
+public void GetOriginalReturnValueExample() {
+ //The extracted value from the method depends on the type of value returned by the extension point.
+ String methodReturnValue = method.getOriginalReturnValue();
}
```
diff --git a/docs/documentation/api-specification/mi-api.md b/docs/documentation/api-specification/mi-api.md
index 036fedc..bd9ebf4 100644
--- a/docs/documentation/api-specification/mi-api.md
+++ b/docs/documentation/api-specification/mi-api.md
@@ -36,7 +36,7 @@ private String whlo;
private String itno;
private String whsl;
-public void main() {
+void inData() {
whlo = mi.inData.get("WHLO").trim();
itno = mi.inData.get("ITNO").trim();
whsl = mi.inData.get("WHSL").trim();
@@ -48,18 +48,19 @@ This method id used to put value into the data container. Takes key and associet
Example 1:
```groovy
-public void main() {
- mi.outData.put("WHLO", "This is WHLO Output#1 for QQS001")
- mi.outData.put("ITNO", "This is ITNO Output#2 for QQS002")
- mi.write()
+void outData() {
+ mi.outData.put("WHLO", "This is WHLO Output#1 for QQS001");
+ mi.outData.put("ITNO", "This is ITNO Output#2 for QQS002");
+ mi.write();
}
```
Example 2:
```groovy
-void main() {
- mi.outData.put("WHLO", String.valueOf(getParameter("NUMB", Double.class).orElse(null)))
+void outData() {
+ mi.outData.put("WHLO", String.valueOf(getParameter("NUMB", Double.class).orElse(null)));
+ mi.write();
}
```
### mi.getDateFormat
@@ -67,9 +68,9 @@ This method checks date format and returns it as a string. Possible formats: YMD
Example:
```groovy
-void main() {
+void getDateFormat() {
if (mi.getDateFormat(date1) == "YMD8"){
- return LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"))
+ return LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
}
}
```
@@ -78,11 +79,10 @@ Returns date separator as a char.
Example:
```groovy
-void ReadSeparator () {
-sep = mi.getDateSeparator()
-String oldDate = '04-DEC-2012'
-Date date = Date.parse( 'dd-MMM-yyyy', oldDate )
-String newDate = date.format( 'M'{sep}'d'{sep}'yyyy' )
+void getDateSeparator () {
+ char sep = mi.getDateSeparator().toString();
+ String oldDate = '04-DEC-2012'
+ String newDate = oldDate.replace("-", sep.toString());
}
```
@@ -91,7 +91,7 @@ Returns the amount of remaining records allowed to be written in current transac
Example:
```groovy
-void main() {
+void getRemainingRecords() {
if (mi.getRemainingRecords()>= 2) {
for (int i = 0; i < 3; i++) {
mi.outData.put("WHLS" + WHSL)
@@ -106,7 +106,7 @@ Returns true if there are still any additional records to be written or false if
Example:
```groovy
-void main() {
+void hasRemainingRecords() {
if (mi.hasRemainingRecords()){
mi.outData.put("MMRI" + SLDQ)
mi.write()
@@ -119,7 +119,7 @@ Returns the maximum amount of possible records to be written as an integer.
Example:
```groovy
-public void main() {
+void getMaxRecords() {
String WHSL = mi.in.get("WHSL")
for (int i = 0; i < mi.getMaxRecords(); i++) {
mi.outData.put("WHLS" + WHSL + " " + i)
@@ -133,7 +133,7 @@ Writes response from data present in outData. Clears all values in outData.
Example:
```groovy
-public void main() {
+void writeRecord() {
mi.outData.put("WHLO","Test")
mi.write()
}
@@ -141,14 +141,14 @@ public void main() {
### mi.error
Writes error responses with parameters:
-String errorMessage - error message to display (only supports 240 characters);
-String field - field error occurred for (only supports 10 characters);
-String errorCode - code for error which occurred (only supports 2 characters).
+- String errorMessage - error message to display (only supports 240 characters)
+- String field - field error occurred for (only supports 10 characters)
+- String errorCode - code for error which occurred (only supports 2 characters)
Example 1:
```groovy
boolean validateInput() {
- if (!getWarehouse(whlo)){
+ if (!getWarehouse(whlo)) {
mi.error("Warehouse " + whlo + " is invalid");
return false;
} else {
@@ -160,8 +160,8 @@ boolean validateInput() {
Example 2:
```groovy
-boolean validResponsible(String Responsible) {
- if (Responsible.isEmpty()){
+boolean validResponsible(String responsible) {
+ if (responsible.isEmpty()) {
mi.error("Responsible must be entered");
return false;
} else {
@@ -170,4 +170,4 @@ boolean validResponsible(String Responsible) {
}
```
## Considerations and Guidelines
-It is not possible to add extra fields to transactions using MI API.
+It is not possible to add extra fields to transactions using MI API.
\ No newline at end of file
diff --git a/docs/documentation/api-specification/micaller-api.md b/docs/documentation/api-specification/micaller-api.md
index 5821870..860ac12 100644
--- a/docs/documentation/api-specification/micaller-api.md
+++ b/docs/documentation/api-specification/micaller-api.md
@@ -6,7 +6,7 @@ grand_parent: Documentation
nav_order: 5
---
-# MiCaller API
+# MICaller API
{: .no_toc }
## Table of contents
@@ -22,174 +22,91 @@ nav_order: 5
---
## Description
-This API can be used for MI calls in XtendM3
+This API can be used for MI calls in XtendM3.
## Features
-### call
+### Call Transaction
There are two kinds of MI Call methods to be used: one with parameters and one without them.
-#### 1. Without parameters
-Example:
+1. Without parameters:
+
```groovy
-public class TestProgram extends ExtendM3Trigger {
- private final ProgramAPI program
- private final ExtensionAPI extension
- private final InteractiveAPI interactive
- private final MICallerAPI miCaller
- private final LoggerAPI logger
-
- public TestProgram(ProgramAPI program, ExtensionAPI extension, InteractiveAPI interactive, MICallerAPI miCaller, LoggerAPI logger) {
- this.program = program
- this.extension = extension
- this.interactive = interactive
- this.miCaller = miCaller
- this.logger = logger
- }
-
- public void main() {
- String customer = null
- Closure> callback = { Map response ->
- logger.info("Response = ${response}")
- if(response.CUNO != null){
- customer = response.CUNO
- }
- }
-
- miCaller.call("CRS610MI","LstBySearchKey", callback)
-
- interactive.showOkDialog("Customer: " + customer)
+String customer;
+Closure> callback = { Map response ->
+ logger.info("Response = ${response}");
+ if(response.CUNO != null){
+ customer = response.CUNO;
}
}
+
+miCaller.call("CRS610MI","LstBySearchKey", callback);
```
-#### 2. With parameters
-Example:
+2. With parameters:
+
```groovy
-public class TestProgram extends ExtendM3Trigger {
- private final ProgramAPI program
- private final ExtensionAPI extension
- private final InteractiveAPI interactive
- private final MICallerAPI miCaller
- private final LoggerAPI logger
-
- public TestProgram(ProgramAPI program, ExtensionAPI extension, InteractiveAPI interactive, MICallerAPI miCaller, LoggerAPI logger) {
- this.program = program
- this.extension = extension
- this.interactive = interactive
- this.miCaller = miCaller
- this.logger = logger
- }
-
- public void main() {
- String DSPname = interactive.display.fields.WRCUNM.toString();
- String DSPaddress = interactive.display.fields.WRCUA1.toString();
- String DSPpostalcode = interactive.display.fields.WRPONO.toString();
- String DSPtown = interactive.display.fields.WRTOWN.toString();
+String DSPname = interactive.display.fields.WRCUNM.toString();
+String DSPaddress = interactive.display.fields.WRCUA1.toString();
+String DSPpostalcode = interactive.display.fields.WRPONO.toString();
+String DSPtown = interactive.display.fields.WRTOWN.toString();
- Map params = [ "SQRY":"CUNM:${DSPname}~ AND CUA1:${DSPaddress} AND PONO:${DSPpostalcode} AND TOWN:{DSPtown}".toString() ] // toString is needed to convert from gstring to string
- String customer = null
- Closure> callback = {
- Map response ->
- logger.info("Response = ${response}")
- if(response.CUNO != null){
- customer = response.CUNO
- }
+Map params = [ "SQRY":"CUNM:${DSPname}~ AND CUA1:${DSPaddress} AND PONO:${DSPpostalcode} AND TOWN:{DSPtown}".toString() ]; // toString is needed to convert from gstring to string
+String customer;
+Closure> callback = {
+ Map response ->
+ logger.info("Response = ${response}");
+ if(response.CUNO != null){
+ customer = response.CUNO;
}
+}
- miCaller.call("CRS610MI","SearchCustomer", params, callback)
-
- interactive.showOkDialog("Customer: " + customer)
- }
-}
+miCaller.call("CRS610MI","SearchCustomer", params, callback);
```
### setListMaxRecords
This method sets the maximum amount of records to be returned by the MI Caller method when using a transaction list.
Example:
```groovy
-public class TestProgram extends ExtendM3Trigger {
- private final ProgramAPI program
- private final ExtensionAPI extension
- private final InteractiveAPI interactive
- private final MICallerAPI miCaller
- private final LoggerAPI logger
-
- public TestProgram(ProgramAPI program, ExtensionAPI extension, InteractiveAPI interactive, MICallerAPI miCaller, LoggerAPI logger) {
- this.program = program
- this.extension = extension
- this.interactive = interactive
- this.miCaller = miCaller
- this.logger = logger
- }
-
- public void main() {
- String DSPname = interactive.display.fields.WRCUNM.toString();
- String DSPaddress = interactive.display.fields.WRCUA1.toString();
- String DSPpostalcode = interactive.display.fields.WRPONO.toString();
- String DSPtown = interactive.display.fields.WRTOWN.toString();
+String DSPname = interactive.display.fields.WRCUNM.toString();
+String DSPaddress = interactive.display.fields.WRCUA1.toString();
+String DSPpostalcode = interactive.display.fields.WRPONO.toString();
+String DSPtown = interactive.display.fields.WRTOWN.toString();
- Map params = [ "SQRY":"CUNM:${DSPname}~ AND CUA1:${DSPaddress} AND PONO:${DSPpostalcode} AND TOWN:{DSPtown}".toString() ] // toString is needed to convert from gstring to string
- String customer = null
- Closure> callback = {
- Map response ->
- logger.info("Response = ${response}")
- if(response.CUNO != null){
- customer = response.CUNO
- }
+Map params = [ "SQRY":"CUNM:${DSPname}~ AND CUA1:${DSPaddress} AND PONO:${DSPpostalcode} AND TOWN:{DSPtown}".toString() ]; // toString is needed to convert from gstring to string
+String customer;
+Closure> callback = {
+ Map response ->
+ logger.info("Response = ${response}");
+ if(response.CUNO != null){
+ customer = response.CUNO;
}
+}
- miCaller.setListMaxRecords(1)
- miCaller.call("CRS610MI","SearchCustomer", params, callback)
-
- interactive.showOkDialog("Customer: " + customer)
- }
-}
+miCaller.setListMaxRecords(1);
+miCaller.call("CRS610MI","SearchCustomer", params, callback);
```
### setDateFormat
The setDateFormat method uses two parameters: character separator and date format. These are the allowed date formats: `YMD8`, `YMD6`, `MDY6`, `DMY6`, and `YWD5`.
Example:
```groovy
-public class TestProgram extends ExtendM3Trigger {
- private final ProgramAPI program
- private final ExtensionAPI extension
- private final InteractiveAPI interactive
- private final MICallerAPI miCaller
- private final LoggerAPI logger
-
- public TestProgram(ProgramAPI program, ExtensionAPI extension, InteractiveAPI interactive, MICallerAPI miCaller, LoggerAPI logger) {
- this.program = program
- this.extension = extension
- this.interactive = interactive
- this.miCaller = miCaller
- this.logger = logger
- }
-
- public void main() {
- if (program.getUser() != "CRIUBA36") {
- return
- }
- String DSPname = interactive.display.fields.WRCUNM.toString();
- String DSPaddress = interactive.display.fields.WRCUA1.toString();
- String DSPpostalcode = interactive.display.fields.WRPONO.toString();
- String DSPtown = interactive.display.fields.WRTOWN.toString();
-
- Map params = [ "SQRY":"CUNM:${DSPname}~ AND CUA1:${DSPaddress} AND PONO:${DSPpostalcode} AND TOWN:{DSPtown}".toString() ] // toString is needed to convert from gstring to string
- String customer = null
- Closure> callback = { Map response ->
- logger.info("Response = ${response}")
- if(response.CUNO != null){
- customer = response.CUNO
- }
- }
-
- miCaller.setDateFormat("/","YMD8")
- miCaller.call("CRS610MI","SearchCustomer", params, callback)
-
- interactive.showOkDialog("Customer: " + customer)
+if (program.getUser() != "CRIUBA36") {
+ return
+}
+String DSPname = interactive.display.fields.WRCUNM.toString();
+String DSPaddress = interactive.display.fields.WRCUA1.toString();
+String DSPpostalcode = interactive.display.fields.WRPONO.toString();
+String DSPtown = interactive.display.fields.WRTOWN.toString();
+
+Map params = [ "SQRY":"CUNM:${DSPname}~ AND CUA1:${DSPaddress} AND PONO:${DSPpostalcode} AND TOWN:{DSPtown}".toString() ]; // toString is needed to convert from gstring to string
+String customer;
+Closure> callback = { Map response ->
+ logger.info("Response = ${response}");
+ if(response.CUNO != null){
+ customer = response.CUNO;
}
-}
-```
-
+}
-## Considerations and Guidelines
+miCaller.setDateFormat("/","YMD8");
+miCaller.call("CRS610MI","SearchCustomer", params, callback);
+```
\ No newline at end of file
diff --git a/docs/documentation/api-specification/program-api.md b/docs/documentation/api-specification/program-api.md
index 21422ee..14c92cd 100644
--- a/docs/documentation/api-specification/program-api.md
+++ b/docs/documentation/api-specification/program-api.md
@@ -22,15 +22,13 @@ nav_order: 2
---
## Description
-The Program API contains APIs that can be used to get information from the current program.
+The Program API contains APIs that can be used to get information from the current program, such as market, program type and more.
## Methods
### Indicator(get)
-Retrieve value of indicators.
-
-Returns: `boolean`
-
+Retrieve value of indicators.
+Returns boolean value of the indicator.
Example:
```groovy
@@ -50,12 +48,8 @@ public class testProgram extends ExtendM3Trigger {
```
### LDAZD(get)
-Retrieve fields mapped in LDAZD.
-
-Parameter: `String 'key'`
-
-Returns: `value of the field, null if get fails`
-
+Retrieve fields mapped in LDAZD.
+Takes a String 'key' as parameter and returns the value of the field.
Example:
```groovy
@@ -67,19 +61,15 @@ public class testProgram extends ExtendM3Trigger {
}
public void main() {
- int currentCompany = (Integer)program.getLDAZD().CONO;
+ int currentCompany = program.LDAZD.get("CONO");
...
}
}
```
### LDAZZ(get)
-Retrieve fields mapped in LDAZZ.
-
-Parameter: `String 'key'`
-
-Returns: `value of the field, null if get fails`
-
+Retrieve fields mapped in LDAZZ.
+Takes a String 'key' as parameter and returns the value of the field.
Example:
```groovy
@@ -91,7 +81,7 @@ public class testProgram extends ExtendM3Trigger {
}
public void main() {
- int orderNum = (Integer)program.getLDAZZ().ORNO;
+ String orderNum = program.LDAZZ.get("ORNO");
...
}
@@ -99,10 +89,7 @@ public class testProgram extends ExtendM3Trigger {
```
### getProgramName
-Retrieve the name of the current program.
-
-Returns: `String 'currentProgram'`
-
+Retrieve the name of the current program.
Example:
```groovy
@@ -122,10 +109,7 @@ public class exampleProgram extends ExtendM3Trigger {
```
### getMarket
-Retrieve the market of the current job. Will always return a valid system component, will never be "ALL".
-
-Returns: `String 'market'`
-
+Retrieve the market of the current job. Will always return a valid system component, will never be "ALL".
Example:
```groovy
@@ -148,10 +132,7 @@ public class exampleProgram extends ExtendM3Trigger {
```
### getUser
-Retrieves the current username.
-
-Returns: `String 'user'`
-
+Retrieves the current username.
Example:
```groovy
@@ -173,10 +154,7 @@ public class exampleProgram extends ExtendM3Trigger {
```
### getProgramType
-Retrieves the current program type(e.g. interactive).
-
-Returns: `String 'programType'`
-
+Retrieves the current program type(e.g. interactive).
Example:
```groovy
@@ -196,10 +174,7 @@ public class exampleProgram extends ExtendM3Trigger {
```
### getNumberOfInputParameters
-Retrieves the programs' number of input parameters.
-
-Returns: `int 'numberOfInputParameters'`
-
+Retrieves the programs' number of input parameters.
Example:
```groovy
@@ -219,10 +194,7 @@ public class exampleProgram extends ExtendM3Trigger {
```
### getJobNumber
-Retrieves the current job number.
-
-Returns: `int 'jobNumber`
-
+Retrieves the current job number.
Example:
```groovy
@@ -242,11 +214,8 @@ public class exampleProgram extends ExtendM3Trigger {
```
### getTableRecord
-Retrieves records from a specific table in the program.
-
-Parameter: `String 'table'`
-
-Returns: `TableRecordAPI`
+Retrieves records from a specific table in the program.
+Takes String 'table' as parameter and returns the table as type 'TableRecordAPI'.
Example:
```groovy
@@ -267,10 +236,7 @@ public class exampleProgram extends ExtendM3Trigger {
```
### getMessageId
-Retrieves the current message ID(program heading).
-
-Returns: `String 'messageID'`
-
+Retrieves the current message ID(program heading).
Example:
```groovy
@@ -290,10 +256,7 @@ public class exampleProgram extends ExtendM3Trigger {
```
### getMessageData
-Retrieve message data.
-
-Returns: `String 'messageData`
-
+Retrieves program message data.
Example:
```groovy
@@ -313,10 +276,7 @@ public class exampleProgram extends ExtendM3Trigger {
```
### getMessage
-Retrieve message.
-
-Returns: `String 'message'`
-
+Retrieves program message.
Example:
```groovy
@@ -336,10 +296,7 @@ public class exampleProgram extends ExtendM3Trigger {
```
### getTenantId
-Retrieve the current tenant ID.
-
-Returns: `String 'tenantID`
-
+Retrieve the current tenant ID.
Example:
```groovy
@@ -359,12 +316,8 @@ public class exampleProgram extends ExtendM3Trigger {
```
### existsInCallStack
-Checks if the given program is in the current call stack.
-
-Parameters: `String program`
-
-Returns: `boolean`
-
+Checks if the given program is in the current call stack.
+Takes String 'program' as parameter and returns true if the program exists in the call stack, else false.
Example:
```groovy
@@ -384,10 +337,7 @@ public class exampleProgram extends ExtendM3Trigger {
```
### isShutdownInProgress
-Checks if program shutdown is in progress.
-
-Returns: `boolean`
-
+Checks if program shutdown is in progress.
Example:
```groovy
@@ -407,10 +357,7 @@ public class exampleProgram extends ExtendM3Trigger {
```
### exitFlag
-Checks if the exit flag is active.
-
-Returns: `boolean`
-
+Checks if the exit flag is active.
Example:
```groovy
@@ -430,10 +377,7 @@ public class exampleProgram extends ExtendM3Trigger {
```
### existsError
-Checks if the error flag is true(alternative to program.indicator.get(60)).
-
-Returns: `boolean`
-
+Checks if the error flag is true(alternative to program.indicator.get(60)).
Example:
```groovy
@@ -453,3 +397,4 @@ public class exampleProgram extends ExtendM3Trigger {
```
## Considerations and Guidelines
+It is considered a good practice to learn about the program you're extending first, to understand the full potential of the Program API.
\ No newline at end of file
diff --git a/docs/documentation/api-specification/session-api.md b/docs/documentation/api-specification/session-api.md
index eaddf3f..4a18eaf 100644
--- a/docs/documentation/api-specification/session-api.md
+++ b/docs/documentation/api-specification/session-api.md
@@ -22,18 +22,17 @@ nav_order: 8
---
## Description
-Session API provides methods for interacting with current session. One of the main usages of this API is a a key-value
+Session API provides methods for interacting with the current session. One of the main usages of this API is a a key-value
storage mechanism for the extension store parameters, calculated values or other information in runtime in memory to
-pass along the another extension or access it later on during the same session.
+pass along to another extension or access it later on during the same session.
The scope of this storage is limited to the session, which means that once the session is terminated all stored
information will be deleted from memory.
A session is started when a program starts by user interaction i.e. from the menu. Subsequent programs that are started
-as a result of related
+as a result of related program are part of that session.
## Features
-
Features of this API.
### session.parameters.put
@@ -42,30 +41,22 @@ anything. The value can be any object, so it is not limited to primitive types.
Example:
```groovy
-double finalSalesPrice = calculateFinalSalesPrice()
-session.parameters.put("salesPrice", finalSalesPrice)
+double finalSalesPrice = calculateFinalSalesPrice();
+session.parameters.put("salesPrice", finalSalesPrice);
```
### session.parameters.get
To check if a parameter has been stored in the session you can try to retrieve the value and check if it is `null` or do
it in the Groovy style by just checking the value.
-Example 1:
+Example:
```groovy
if (session.parameters.get("salesPrice") == null) {
- double finalSalesPrice = calculateFinalSalesPrice()
- session.parameters.put("salesPrice", finalSalesPrice)
-}
-```
-
-Example 2:
-```groovy
-if (session.parameters.get("salesPrice")) {
- double finalSalesPrice = calculateFinalSalesPrice()
- session.parameters.put("salesPrice", finalSalesPrice)
+ double finalSalesPrice = calculateFinalSalesPrice();
+ session.parameters.put("salesPrice", finalSalesPrice);
}
```
## Considerations and Guidelines
Although the size limit of this storage is undocumented, it should be used with considerations. Storing too much
-information in this layer should be avoided and moved to database instead.
+information in this layer should be avoided and moved to the database layer instead.
diff --git a/docs/documentation/api-specification/textfiles-api.md b/docs/documentation/api-specification/textfiles-api.md
index 4c59989..121a533 100644
--- a/docs/documentation/api-specification/textfiles-api.md
+++ b/docs/documentation/api-specification/textfiles-api.md
@@ -25,8 +25,8 @@ nav_order: 9
TextFiles API is used to perform various file processing operations. It can be used to open, read and write in files from current and subdirectories as well as list existing folders and files.
## Features
-### textFiles.open(String subDirectory)
-This method allows the user to open a subDirectory. This can be used when trying to access a file located in another location. Takes name of the subDirectory as a parameter.
+### textFiles.open
+This method allows the user to open a sub directory. This can be used when trying to access a file located in another location. Takes name of the sub directory as a parameter.
Example:
@@ -41,7 +41,7 @@ public void openRecords() {
}
```
-### textFiles.read(String fileName, String encoding, Consumer readTask)
+### textFiles.read
This method is responsible for reading data from the selected file and applying it via the corresponding command using the bufferedReader in the extension.
Parameters:
- String fileName - name of the file
@@ -53,25 +53,25 @@ Example:
```groovy
List resolveFields(String line) {
- List list = new ArrayList<>()
- String[] fields = line.split(resolveDelimiter(line))
+ List list = new ArrayList<>();
+ String[] fields = line.split(resolveDelimiter(line));
for(String field : fields) {
- list.add(field)
+ list.add(field);
}
- return list
+ return list;
}
Closure> readCODEFILE = { BufferedReader reader ->
- List header = resolveFields(reader.readLine())
+ List header = resolveFields(reader.readLine());
while((line = reader.readLine()) != null) {
- reader.println(line)
+ reader.println(line);
}
}
public void readRecords() {
- textFiles.read("CODEFILE.csv", "UTF-16", readCODEFILE)
- }
+ textFiles.read("CODEFILE.csv", "UTF-16", readCODEFILE);
+}
```
-### textFiles.write(String fileName, String encoding, boolean append, Consumer writeTask)
+### textFiles.write
This method allows data to be written inside the selected file.
Parameters:
- String fileName - name of the file
@@ -83,129 +83,82 @@ Example:
```groovy
void log(String message) {
- message = LocalDateTime.now().toString() + " " + XtendM3
- if (mi.in.get("TEST") == 1) {
- Closure> consumer = { PrintWriter printWriter ->
- printWriter.println(message)
- }
- textFiles.write(reportName, "UTF-16", true, consumer)
+ message = LocalDateTime.now().toString() + " " + XtendM3;
+ Closure> consumer = { PrintWriter printWriter ->
+ printWriter.println(message)M
}
+ textFiles.write(reportName, "UTF-16", true, consumer);
}
```
-### textFiles.delete(String fileName)
-This method deletes the selected file. It takes a name from the file as a parameter.
+### textFiles.delete
+This method deletes the selected file. It takes the file name as parameter, in String format.
Example:
```groovy
-public class DeleteExample extends ExtendM3Trigger {
- private final TextFilesAPI textFiles;
-
- public DeleteExample(TextFilesAPI textFiles) {
- this.textFiles=textFiles;
- }
-
- public void main() {
- textFiles.delete("test.txt");
- }
+public void DeleteExample() {
+ textFiles.delete("test.txt");
}
```
-### textFiles.size(String fileName)
+### textFiles.size
This method allows to obtain information about the size of the selected file. The size is displayed as a number of the long type and the units are bytes.
Example:
-```groovy
-public class SizeExample extends ExtendM3Trigger {
- private final InteractiveAPI interactive;
- private final TextFilesAPI textFiles;
-
- public SizeExample(InteractiveAPI interactive, TextFilesAPI textFiles) {
- this.interactive=interactive;
- this.textFiles=textFiles;
- }
-
- public void main() {
- String fileName="test.txt";
- interactive.showOkDialog("Selected file has size of "+textFiles.size(fileName).toString()+"units...");
- }
+```groovy
+public void SizeExample() {
+ String fileName="test.txt";
+ interactive.showOkDialog("Selected file has size of "+textFiles.size(fileName).toString()+"units...");
}
```
-### textFiles.exists(String fileName)
+### textFiles.exists
The method checks if the file is available in the extension file location. A boolean true/false value is returned depending on available files.
Example:
-```groovy
-public class ExistExample extends ExtendM3Trigger {
- private final InteractiveAPI interactive;
- private final TextFilesAPI textFiles;
-
- public ExistExample(InteractiveAPI interactive, TextFilesAPI textFiles) {
- this.interactive=interactive;
- this.textFiles=textFiles;
- }
-
- public void main() {
- if(textFiles.exists("test.txt")) {
- interactive.showOkDialog("Hello! The file test.txt does exist!");
- } else {
- interactive.showWarningDialog("Hello! The file test.txt does not exist!");
- }
- }
+```groovy
+public void ExistExample() {
+ if(textFiles.exists("test.txt")) {
+ interactive.showOkDialog("Hello! The file test.txt does exist!");
+ } else {
+ interactive.showWarningDialog("Hello! The file test.txt does not exist!");
}
```
-### textFiles.listFiles()
+### textFiles.listFiles
The method lists all files at the extension directory.
Example:
```groovy
-public class test extends ExtendM3Trigger {
- private final TextFilesAPI textFiles;
-
- public test(TextFilesAPI textFiles) {
- this.textFiles=textFiles;
- }
+public void ListFiles() {
+ textFiles.open("config_data");
+ StringBuilder sb = new StringBuilder();
+ Iterator list = textFiles.listFiles();
- public void main() {
- textFiles.open("config_data");
- StringBuilder sb = new StringBuilder();
- Iterator list = textFiles.listFiles();
-
- for (String element : list) {
+ for (String element : list) {
sb.append(element);
sb.append(" ");
- }
}
}
```
-### textFiles.listFolders()
+### textFiles.listFolders
The method lists all folders at the extension directory.
Example:
```groovy
-public class test extends ExtendM3Trigger {
- private final TextFilesAPI textFiles;
-
- public test(TextFilesAPI textFiles) {
- this.textFiles=textFiles;
- }
-
- public void main() {
- textFiles.open("config_data");
- StringBuilder sb = new StringBuilder();
- Iterator list = textFiles.listFolders();
+public void ListFolders() {
+ textFiles.open("config_data");
+ StringBuilder sb = new StringBuilder();
+ Iterator list = textFiles.listFolders();
- for (String element : list) {
- sb.append(element);
- sb.append(" ");
- }
+ for (String element : list) {
+ sb.append(element);
+ sb.append(" ");
}
}
```
diff --git a/docs/documentation/api-specification/transaction-api.md b/docs/documentation/api-specification/transaction-api.md
index 5165f7a..f9a8992 100644
--- a/docs/documentation/api-specification/transaction-api.md
+++ b/docs/documentation/api-specification/transaction-api.md
@@ -47,10 +47,8 @@ This method allows to skip the current transaction and takes three string parame
Example:
```groovy
public void main() {
- if (transaction.parameters.USID=="TEST") {
+ if (transaction.parameters.USID == "TEST") {
transaction.abortTransaction("USID","ER001","ER001");
}
}
-```
-
-## Considerations and Guidelines
+```
\ No newline at end of file
diff --git a/docs/documentation/api-specification/utility-api.md b/docs/documentation/api-specification/utility-api.md
index 9ba9f8c..6389d3b 100644
--- a/docs/documentation/api-specification/utility-api.md
+++ b/docs/documentation/api-specification/utility-api.md
@@ -22,15 +22,15 @@ nav_order: 4
---
## Description
-The Utility API allows to create a specific code that can be used more than once. It is useful in case of designing methods/extensions that can be executed multiple times or from diffrent locations in a running session. It is not needed to create multiple pieces of code with the same methodology by using Utility API.
+The Utility API is used to call Utility extensions from other XtendM3 extensions. Utility extensions allow the user to create a specific method that can be used more than once. It is useful in case of designing methods/extensions that can be executed multiple times or from diffrent locations in a running session. It is not needed to create multiple pieces of code with the same methodology by using utilities.
## Features
-With the Utility API a specific part of the code is created separately to execute it with other extensions. This allows for multiple use of designed utility at various points inside the extension. Any piece of code can be considered as a utility if it is a method or set of methods that can be called by other extensions. It is important to include utility as a unique piece of code.
+With the Utilities a specific part of the code is created separately to execute with other extensions. This allows for multiple uses of designed utilities at various points inside the extension. Any piece of code can be considered as a Utility if it is a method or set of methods that can be called by other extensions.
### Utility example
-Utilities can be easily sorted into individual method sets. That makes them easy accessable from all extensions without having to search for specific method or createing it again.
+Utilities can be easily sorted into individual method sets. That makes them easy accessable from all extensions without having to search for specific method or creating it again.
-Example: part of the DateUtil utility (multiple methods related to date operations)
+Example: part of the DateUtil Utility (multiple methods related to date operations).
```groovy
import java.time.Instant
@@ -70,55 +70,36 @@ public class DateUtil extends ExtendM3Utility {
```
### Call method
-The 'Call' method of UtilityAPI is the main method by which operations on previously created utilities are possible to execute. The structure of call method is presented below:
+The 'call' method of UtilityAPI is the main method by which operations on previously created utilities can be executed. The structure of the call method is presented below:
Example: Call method structure
```groovy
- utility.call("- Name of the utility -","- Name of the chosen method inside utility -", objectArgument, ... other arguments depending on the selected method ...);
+ utility.call("- Name of the Utility -","- Name of the chosen Utility method -", objectArgument, ... other arguments depending on the selected method ...);
```
-It is important to know the structure of the chosen method inside the utility.
+It is important to know the structure of the chosen method inside the Utility.
Three elements are required in the 'call' Utility API method:
-- name of the selected utility
-- name of the chosen method inside the selected utility
-- all necessary arguments of the selected method to execute the code
+- name of the selected Utility
+- name of the chosen method inside the selected Utility
+- all necessary arguments of the selected method to execute the code
-### Initialisation of utility methods in an extension
-Utility can be interpreted as a kind of abstract class with fully implemented methods that are ready-to-use. In order to use the utility in an extension, it is only necessary to call the method from created utility inside designed extension and assign the relevant parameters to it.
+### Initialisation of Utility methods in an extension
+Utilities can be interpreted as a kind of abstract class with fully implemented methods that are ready-to-use. In order to use the Utility in an extension, it is only necessary to call the method from created Utility inside designed extension and assign the relevant parameters to it.
Example:
```groovy
-public class ExampleWithUtility extends ExtendM3Trigger {
- private final InteractiveAPI interactive;
- private final UtilityAPI utility;
-
- public ExampleWithUtility(InteractiveAPI interactive, UtilityAPI utility) {
- this.interactive=interactive;
- this.utility=utility;
- }
- public void main() {
- interactive.showOkDialog("Hello, today is "+ utility.call("DateUtil","currentDateY6AsString") +" (yy-mm-dd)");
- }
+public void main() {
+ interactive.showOkDialog("Hello, today is "+ utility.call("DateUtil","currentDateY6AsString") +" (yy-mm-dd)");
}
```
-By using utilities lines of code and time to write code is saved while maintaining full performance of it. In addition, it is not necessary to write needed libraries to execute the code - all are included inside the utility. The same example without using utility below:
+By using utilities lines of code and time to write code is saved while maintaining full performance of it. In addition, it is not necessary to write needed libraries to execute the code - all are included inside the Utility. The same example without using a Utility below:
Example:
```groovy
-import java.time.LocalDate
-import java.time.format.DateTimeFormatter
-
-public class ExampleWithoutUtility extends ExtendM3Trigger {
- private final InteractiveAPI interactive;
-
- public ExampleWithoutUtility(InteractiveAPI interactive) {
- this.interactive=interactive;
- }
- public void main() {
- interactive.showOkDialog("Hello, today is "+ LocalDate.now().format(DateTimeFormatter.ofPattern("yyMMdd")) +" (yy-mm-dd)");
- }
+public void main() {
+ interactive.showOkDialog("Hello, today is "+ LocalDate.now().format(DateTimeFormatter.ofPattern("yyMMdd")) +" (yy-mm-dd)");
}
```
diff --git a/docs/documentation/approval-requirements.md b/docs/documentation/approval-requirements.md
index e77d8ac..46d37a4 100644
--- a/docs/documentation/approval-requirements.md
+++ b/docs/documentation/approval-requirements.md
@@ -2,7 +2,7 @@
layout: default
title: Approval Requirements
parent: Documentation
-nav_order: 10
+nav_order: 11
---
# Approval Requirements
@@ -112,12 +112,10 @@ we will no longer release signed extensions without first being able to bill our
### Billing Specifics
-We bill 1-2 hours for the review of simple to medium complexity extensions.
-For complex extensions, it normally takes more time as it requires multiple cycles of review/discussions/revisions so it will be actual time spent that will be charged.
-We go by GDS/COE Manila Offshore Principal Consultant rates, you can check with your Client Partners or Partner Account Manager as to how much this is exactly per hour.
+We bill 1-2 hours for the review of simple to medium complexity extensions.
+For complex extensions, it normally takes more time as it requires multiple cycles of review/discussions/revisions so it will be actual time spent that will be charged.
+We go by GDS/COE Manila Offshore Principal Consultant rates, you can check with your Client Partners or Partner Account Manager as to how much this is exactly per hour.
-A recommendation,
+A recommendation,
As per standard practice for our projects, we include the review hours in the work estimates for development of extensions.
-On high level, budgeting for 5-10% of each extension development effort is enough time for the review/signing.
-
-
+On high level, budgeting for 5-10% of each extension development effort is enough time for the review/signing.
\ No newline at end of file
diff --git a/docs/documentation/batch-scheduling.md b/docs/documentation/batch-scheduling.md
index 607d451..7546ee5 100644
--- a/docs/documentation/batch-scheduling.md
+++ b/docs/documentation/batch-scheduling.md
@@ -2,7 +2,7 @@
layout: default
title: Batch Scheduling
parent: Documentation
-nav_order: 3
+nav_order: 4
---
# Batch Scheduling
@@ -20,7 +20,7 @@ Scheduling XtendM3 Batch Extensions
---
## SHS010/SHS010MI
-SHS010, or SHS010MI for the non-interactive version, is the scheduler for XtendM3 Batch Extensions. It works in a similar fashion to SHS050, which is used to schedule M3 Batch Jobs, and in the background also schedules executions through this.
+SHS010, or SHS010MI for the non-interactive version, is the scheduler for XtendM3 Batch Extensions. It works in a similar fashion to SHS050, which is used to schedule M3 Batch Jobs. SHS010/SHS010MI schedules executions via SHS050.
### Available parameters
This section lists the available SHS010MI parameters.
diff --git a/docs/documentation/capabilities.md b/docs/documentation/capabilities.md
index fba0df7..72ce535 100644
--- a/docs/documentation/capabilities.md
+++ b/docs/documentation/capabilities.md
@@ -2,13 +2,12 @@
layout: default
title: Capabilities
parent: Documentation
-nav_order: 6
+nav_order: 7
---
# Capabilities
{: .no_toc }
-
XtendM3 Capabilities
{: .fs-6 .fw-300 }
@@ -69,30 +68,32 @@ through extensions and they can be exposed via XtendM3 APIs to the rest of the M
#### Creating extension APIs - new transaction to get, add, update, or list records
It is possible to create new APIs and single/multi transactions via XtendM3. In order to create new transaction the
extension type should be Transaction when creating it.
+
#### Calling extension API from H5 Script, ION API, IEC Mapper, CMS041
If extension API is active, metadata is automatically updated in MRS program and ION API and can be called or used same as a standard API transaction.
### Batch
-Section in progress.
+Batch extensions have the longest time out of all extension types, one hour. This makes Batch type extensions a good candidate for doing longer calculations.
+These extensions can also be scheduled to execute, more information available [here](../batch-scheduling).
### Interactive
-Use H5 Scripting and Mashup SDK to create UI elements and use extension API to perform CRUD operations.
+Use H5 Scripting and Mashup SDK to create UI elements and use extension APIs to perform CRUD operations.
## Integration
### ION API
-It is possible to call ION API from extensions.
+ION APIs can be called from XtendM3 extensions using the [ION API](../api-specification/ion-api).
### M3 API
-It is possible to call M3 API from extensions.
+APIs available in M3 can be called from XtendM3 extensions using the [MICaller API](../api-specification/micaller-api).
### Configurable List & XML
-TBA. Not released yet.
+TBA. Not released yet.
### File Transfer
-It is possible to manage text, csv, json files in MvxFileTransfer directory.
+It is possible to manage text, csv, json files in MvxFileTransfer directory using the [TextFiles API](../api-specification/textfiles-api).
### M3 Database
-It is possible to perform CRUD operations on M3 database.
+It is possible to perform CRUD operations on M3 database using the [Database API](../api-specification/database-api).
### Data Lake Synchronization
TBA. Not released yet.
@@ -107,7 +108,11 @@ Capabilities of various XtendM3 development tools.
### Online IDE
Capabilities specific to the online XtendM3 development environment.
-####
+#### Test Compile
+Test compile your extension with XtendM3s specific compilation rules.
+
+#### Duplicate
+Create a copy of your extension with a new name and/or market.
### Local IDE
Capabilities specific to the local XtendM3 development environment.
@@ -135,6 +140,9 @@ More detailed documentation regarding XtendM3 Local Workspace available [here](.
* Activate your imported extensions.
## Governance
+XtendM3 governance.
+
### Compile Time
+
### Runtime
diff --git a/docs/documentation/exceptions.md b/docs/documentation/exceptions.md
index 9106516..591ecf3 100644
--- a/docs/documentation/exceptions.md
+++ b/docs/documentation/exceptions.md
@@ -2,7 +2,7 @@
layout: default
title: Exceptions
parent: Documentation
-nav_order: 4
+nav_order: 5
---
# Exceptions
@@ -43,7 +43,7 @@ Example code for catching generic Java exceptions.
*NumberFormatException*
```groovy
String aString = null;
-Integer anInteger = "10";
+Integer anInteger = 10;
try {
anInteger = aString.toInteger();
} catch(NumberFormatException e) {
@@ -82,4 +82,4 @@ MI response exceptions are used for throwing exceptions from Transaction context
Can be thrown with just a *String message*. Alternatively a *String field* and *String errorCode* can be added for additional verbosity.
**Adaptive exception**
-The *AdaptiveShortCircuitException* can be thrown from any given XtendM3 context and will adapt to the context of execution.
+The *AdaptiveShortCircuitException* can be thrown from any given XtendM3 context and will adapt to the context of execution.
\ No newline at end of file
diff --git a/docs/documentation/import-export.md b/docs/documentation/import-export.md
index 119cfab..5027e97 100644
--- a/docs/documentation/import-export.md
+++ b/docs/documentation/import-export.md
@@ -2,7 +2,7 @@
layout: default
title: Import and Export of Extensions
parent: Documentation
-nav_order: 2
+nav_order: 3
---
# Import and Export of Extensions
@@ -20,16 +20,18 @@ XtendM3 Import and Export of Extensions
---
## Description
-It is possible to export and import extensions into XtendM3 environment. Current methods are still in development and can be updated.
+It is possible to export and import extensions into XtendM3 environment, either one at a time or in bulk.
+To import extension in bulk, create a zip-file containing the extensions in .json format.
## Import
-Different types of extensions are being saved in JSON files (typical JSON files or signed JSON files, which are a little bit modified while exporting extension). Importing an extension is possible by using an import button above the code sheet. After clicking that button a proper window will open and prompt the user to choose an extension which should be imported.
+Different types of extensions are being saved in JSON files.
+Importing an extension is possible by using the import button above the extension list. After clicking that button a window will open and prompt the user to choose an extension which should be imported, or a zip-file containing several extensions.
### Structure of importing
-Import feature has improvement of a special interface with which you can check the file before adding it to the workspace (The Review button -> it is redirecting the window to proper sheet with the extension). The main import window contains information about the file such as its creator, date of creation and additionally the message contained - in case of a JSON signed file.
+Import feature has improvement of a special interface with which you can check the file before adding it to the workspace (The Review button -> it is redirecting the window to proper sheet with the extension). The main import window contains information about the file such as its creator, date of creation and additionally the message contained - in the case of a signed extension.
### Different imports for diffrent extensions
@@ -38,19 +40,18 @@ All imports are different depending on the type of extension. For example extens
### Name conflicts
-In case of importing an extension,and that name is already included in the list of available extension, it is instantly overriding the older file with the input of imported extension.Therefore, it is important to create a copy of previous file in case there is some useful data to be saved .
+In case of importing an extension, and that name is already included in the list of available extension, it is instantly overriding the older file with the input of imported extension. Therefore, it is important to create a copy of previous file in case there is some useful data to be saved.
## Export
-Extensions can be exported into a Json or a Json signed file. To export an extension select the extension from XtendM3 and click the "Export" button from the tool bar above.
+Extensions can be exported into a JSON file.
+To export an extension select the extension from XtendM3 and click the "Export" button from the tool bar above.
Pop up window will aprear with export options:
-* Message - Inputted message will be displayed when importing the extension
-* Export - fetches the latest version of the extension
* Local export - exports extension cashed in the web browser
-* Signed Export - exports into a signed file.
+* Database Export - fetches the latest version of the extension
@@ -58,6 +59,5 @@ After selecting one of the export options, the file will be automatically saved
## Important notes
-* Files will be overwritten in case of file name conflict. Remember to export previous extension first to save it befor overwriting
-* Imported extensions are being validated, if not valid an error window will appear
-* Current Import/Export method is not a final version. Still in development.
\ No newline at end of file
+* Files will be overwritten in case of file name conflict. Remember to export previous extension first to save it before overwriting
+* Imported extensions are being validated, if not valid an error window will appear
\ No newline at end of file
diff --git a/docs/documentation/limitations.md b/docs/documentation/limitations.md
index f253a9a..215cc42 100644
--- a/docs/documentation/limitations.md
+++ b/docs/documentation/limitations.md
@@ -2,7 +2,7 @@
layout: default
title: Limitations
parent: Documentation
-nav_order: 7
+nav_order: 8
---
# Limitations
@@ -154,40 +154,12 @@ Limitations to the XtendM3 APIs.
Perform the query using either direct database access or via calling CMS100MI/MDBREADMI IONAPI as a last resort option.
-### Configurable List & XML
-
-### File Transfer
-
-### Database
-
-### Data Lake
-
-## Development Tools
-Limitations to the XtendM3 development tools.
-
-### Online IDE
-
-
-### Local IDE
-Limitations specific to XtendM3 development in a local IDE.
-
-#### API SDK
-
-#### Maven Plugin
-
-
## Governance
Governance limitations.
-### Compile Time
-Compile time limitations.
-
-### Runtime
-Runtime limitations.
-
#### Timeouts
* Trigger extensions: _five seconds_.
* Transaction extensions: _two minutes_.
* Batch extensions: _one hour_.
* Utility extensions: _depends on the calling extension_.
- * E.g., a Utility called from a Trigger extension will be able to use up the remaining timeout for that Trigger.
+ * E.g., a Utility called from a Trigger extension will be able to use up the remaining timeout for that Trigger.
\ No newline at end of file
diff --git a/docs/documentation/local-workspace.md b/docs/documentation/local-workspace.md
index 6e4d75f..0fc7992 100644
--- a/docs/documentation/local-workspace.md
+++ b/docs/documentation/local-workspace.md
@@ -2,7 +2,7 @@
layout: default
title: Local XtendM3 Workspace
parent: Documentation
-nav_order: 5
+nav_order: 6
---
# Local XtendM3 Workspace
@@ -100,129 +100,129 @@ Using the information from the credentials(.ionapi) file, setup the authorizatio
#### Body Template
```json
- {
- "programModules": {
- : {
- "program": ,
- "triggers": {
- : {
- "name": ,
- "method": ,
- "advice": ,
- "active": true/false,
- "modified": ,
- "modifiedBy": ,
- "sourceUuid": ,
- "programName": ,
- "utilities": [],
- "type": "METHOD",
- "priority":
- }
- },
- "transactions": {},
- "batches": {}
- },
- : {
- "program": ,
- "triggers": {},
- "transactions": {},
- "batches": {
- "sourceUuid": ,
- "description": ,
- "active": true/false,
- "modified": ,
- "modifiedBy": ,
- "utilities": []
- }
- },
- : {
- "program": ,
- "triggers": [],
- "transactions": {
- : {
- "sourceUuid": ,
- "name": ,
- "program": ,
- "description": ,
- "active": true/false,
- "multi": true/false,
- "modified": ,
- "modifiedBy": ,
- "outputFields": [
- {
- "name": ,
- "description": ,
- "length": ,
- "mandatory": ,
- "type":
- }
- ],
- "inputFields": [
- {
- "name": ,
- "description": ,
- "length": ,
- "mandatory": ,
- "type":
- }
- ],
- "utilities": []
- }
- },
- "batches": {}
+{
+ "programModules": {
+ : {
+ "program": ,
+ "triggers": {
+ : {
+ "name": ,
+ "method": ,
+ "advice": ,
+ "active": true/false,
+ "modified": ,
+ "modifiedBy": ,
+ "sourceUuid": ,
+ "programName": ,
+ "utilities": [],
+ "type": "METHOD",
+ "priority":
+ }
+ },
+ "transactions": {},
+ "batches": {}
+ },
+ : {
+ "program": ,
+ "triggers": {},
+ "transactions": {},
+ "batches": {
+ "sourceUuid": ,
+ "description": ,
+ "active": true/false,
+ "modified": ,
+ "modifiedBy": ,
+ "utilities": []
+ }
+ },
+ : {
+ "program": ,
+ "triggers": [],
+ "transactions": {
+ : {
+ "sourceUuid": ,
+ "name": ,
+ "program": ,
+ "description": ,
+ "active": true/false,
+ "multi": true/false,
+ "modified": ,
+ "modifiedBy": ,
+ "outputFields": [
+ {
+ "name": ,
+ "description": ,
+ "length": ,
+ "mandatory": ,
+ "type":
}
- },
- "utilities": {
- : {
- "name": ,
- "sourceUuid":
+ ],
+ "inputFields": [
+ {
+ "name": ,
+ "description": ,
+ "length": ,
+ "mandatory": ,
+ "type":
}
- },
- "sources": {
- : {
- "uuid": ,
- "updated": ,
- "updatedBy": ,
- "created": ,
- "createdBy": ,
- "apiVersion" ,
- "beVersion": <>,
- "codeHash": ,
- "code": ,
- },
- : {
- "uuid": ,
- "updated": ,
- "updatedBy": ,
- "created": ,
- "createdBy": ,
- "apiVersion" ,
- "beVersion": <>,
- "codeHash": ,
- "code": ,
- },
- : {
- "uuid": ,
- "updated": ,
- "updatedBy": ,
- "created": ,
- "createdBy": ,
- "apiVersion" ,
- "beVersion": <>,
- "codeHash": ,
- "code": ,
- },
- : {
- "uuid": ,
- "updated": ,
- "updatedBy": ,
- "created": ,
- "createdBy": ,
- "apiVersion" ,
- "beVersion": <>,
- "codeHash": ,
- "code": ,
- }
- }
+ ],
+ "utilities": []
}
+ },
+ "batches": {}
+ }
+ },
+ "utilities": {
+ : {
+ "name": ,
+ "sourceUuid":
+ }
+ },
+ "sources": {
+ : {
+ "uuid": ,
+ "updated": ,
+ "updatedBy": ,
+ "created": ,
+ "createdBy": ,
+ "apiVersion" ,
+ "beVersion": <>,
+ "codeHash": ,
+ "code": ,
+ },
+ : {
+ "uuid": ,
+ "updated": ,
+ "updatedBy": ,
+ "created": ,
+ "createdBy": ,
+ "apiVersion" ,
+ "beVersion": <>,
+ "codeHash": ,
+ "code": ,
+ },
+ : {
+ "uuid": ,
+ "updated": ,
+ "updatedBy": ,
+ "created": ,
+ "createdBy": ,
+ "apiVersion" ,
+ "beVersion": <>,
+ "codeHash": ,
+ "code": ,
+ },
+ : {
+ "uuid": ,
+ "updated": ,
+ "updatedBy": ,
+ "created": ,
+ "createdBy": ,
+ "apiVersion" ,
+ "beVersion": <>,
+ "codeHash": ,
+ "code": ,
+ }
+ }
+}
```
\ No newline at end of file
diff --git a/docs/documentation/metadata.md b/docs/documentation/metadata.md
index e792230..1161b10 100644
--- a/docs/documentation/metadata.md
+++ b/docs/documentation/metadata.md
@@ -2,7 +2,7 @@
layout: default
title: Metadata
parent: Documentation
-nav_order: 11
+nav_order: 12
---
# Metadata
diff --git a/docs/documentation/programming-standard.md b/docs/documentation/programming-standard.md
index adfdebf..3db0da1 100644
--- a/docs/documentation/programming-standard.md
+++ b/docs/documentation/programming-standard.md
@@ -2,7 +2,7 @@
layout: default
title: Programming Standard
parent: Documentation
-nav_order: 8
+nav_order: 2
---
# Programming Standard
@@ -19,6 +19,21 @@ Guideline for writing secure, optimized and scalable extensions.
---
+## Importance of programming standards
+Programming standards refer to a set of guidelines and best practices that outline how code should be written, organized, and formatted. These standards are crucial for several reasons:
+
+- Ensures that code is written in a consistent manner, making it easier for future developers to read, understand, and maintain extensions. When code follows a uniform style, other developers can quickly get up to speed, and easily navigate through the code without confusion.
+
+- As projects grow, maintaining code can become a significant challenge. Adhering to programming standards helps in creating a clean and organized codebase, which in turn makes it easier to identify and fix bugs, add new features, and refactor existing code without introducing new issues.
+
+- In a team environment, multiple developers often work on the same project. Programming standards facilitate smoother collaboration by ensuring everyone follows the same set of rules. This reduces the likelihood of conflicts and issues, thereby streamlining the development process.
+
+- Programming standards make the code review process more efficient. Reviewers can focus on the logic and functionality of the code rather than spending time on stylistic issues. This leads to more thorough and productive code reviews, ultimately improving the overall code quality.
+
+- Well-documented code is essential for long-term project success. Programming standards often include requirements for comments and documentation, ensuring that the code is self-explanatory and easy to understand. This is particularly important for future developers who may need to work on the code long after the original authors have moved on.
+
+In conclusion, programming standards are an essential aspect of software development that contribute to the consistency, maintainability, and quality of the code. By adhering to these standards, developmeners can produce more reliable and efficient extensions ultimately leading to better outcomes for both developers and end-users.
+
## Extension Types
There are five types of extensions, below is a short description of each type.
@@ -45,7 +60,8 @@ Indent size: 2 spaces
Continuation indent: 4 spaces
Charset: utf-8
-XtendM3 uses Groovy programming and ending code lines with semicolons are optional.
+XtendM3 uses Groovy programming and ending code lines with semicolons are optional.
+It is however recommended to stick to one standard within one extension, for easier readability.
## Naming
@@ -131,6 +147,12 @@ OOLINE - EXTOLN
Table - EXT001
API - EXT001MI
+- Custom extension tables should contain homogenous data type. Generic tables are not allowed. I.e., if the table contain 'Items' as primary data, the table should not have 'Warehouses' as alternative primary data.
+
+- Custom extension field names should to denote what the column is for, rather than trying to describe the type/length or generic nature of them.
+
+- Generic column names will not be accepted even though the actual columns might have been used correctly for a specific purpose and not in a generic way. The reason is to avoid misunderstandings, because generic tables are not going to be allowed.
+
#### Methods
- Method name should follow Java naming convention for methods
- Names should be in lowerCamelCase, using no underscores and starting with a letter
@@ -299,8 +321,8 @@ Extension approval requires submission of approved Unit test and Functional test
- A sample repository [ACME Corp. XtendM3 Extensions](https://github.com/infor-cloud/acme-corp-extensions) is provided to get you started on setting up project directories for the source codes, test scripts and XtendM3 SDK
### Live
-- If the program extension has been activated in the tenant, it automatically runs and the changes to the program are seen by the users. During unit testing, it is recommended that the extension should execute only for specific users until it is verified working to avoid interrupting other users when running the same program
-- Provided is an example of validating extension to run for specific user/s
+- In the case that the program is a Trigger type extension, it automatically runs and the changes to the program are seen by the users as long as the extension is activated. During unit testing, it is recommended that the extension should execute only for specific users until it is verified to be working in order to avoid interrupting other users running the same program.
+Provided is an example of validating extension to run for specific user(s):
```groovy
private boolean isEnabled() {
if (program.getUser() != "USERNAME") {
@@ -310,20 +332,25 @@ Extension approval requires submission of approved Unit test and Functional test
}
```
+- API or Transaction extensions can be tested via Metadata Publisher.
+
+- Similarly to Transactions, Batch extensions can be tested via Metadata Publisher and SHS010MI.
+
## Version Controlling
-More details are provided at [Version Controlling](https://infor-cloud.github.io/xtendm3/docs/documentation/version-controlling/) page
+More details are provided at [Version Controlling](https://infor-cloud.github.io/xtendm3/docs/documentation/version-controlling/).
### Framework
-Git version control system should be used
+Git version control system should be used.
### Structure
-Refer to the example of an [XtendM3 Extension Repository](https://github.com/infor-cloud/acme-corp-extensions) to version control extensions
+Refer to the example of an [XtendM3 Extension Repository](https://github.com/infor-cloud/acme-corp-extensions) to version control extensions.
### Hosting
-Any git provider that the customer prefers GitHub, GitLab, Bitbucket and etc.
+Any Git provider that the customer prefers GitHub, GitLab, Bitbucket and etc.
-## Documentation
+### Code Documentation
- Extension JavaDoc on top of extension classes is required
+- Extension Methods JavaDoc on top of methods (except for main) is recommended
- Example:
```groovy
@@ -341,6 +368,60 @@ Any git provider that the customer prefers GitHub, GitLab, Bitbucket and etc.
Revision Author 2022-02-02 1.1 Outlining what's been updated
Revision Author 2022-03-03 1.2 In the current revision
******************************************************************************************/
+ public class transactionName extends ExtendM3Transaction {
+ private final LoggerAPI logger;
+ private final MIAPI mi;
+ private final DatabaseAPI database;
+
+ /*
+ * Transaction EXT000MI/transactionName Interface
+ * @param logger - Infor Logging Interface
+ * @param mi - Infor MI Interface
+ * @param database - Infor Database Interface
+ */
+ public transactionName(LoggerAPI logger, MIAPI mi, DatabaseAPI database) {
+ this.logger = logger;
+ this.mi = mi;
+ this.database = database;
+ }
+
+ public void main() {
+ create();
+ }
+
+ /*
+ * Create new record in table
+ */
+ void create() {
+ // code
+ }
+ }
```
-- Extension Methods JavaDoc on top of methods (except for main) is recommended
+## Review Comments
+Common comments brought up during review.
+
+* **Field Validation**
+There should always be validation present for standard M3 fields and date fields.
+
+* **Line endings**
+In an extension there should be consistent use of semicolons, either no semicolons or semicolons on all line endings.
+
+* **Imports**
+Make sure no unused imports are present.
+
+* **Indentation**
+For readability, indentation should be consistent throughout the code.
+See 'Indentation and Formatting' section above.
+
+* **Method Comments**
+Every method(except main) in an extension should have a comment describing the funtionality, it is recommended to comment in JavaDoc style(see above section).
+
+* **Program Header**
+Every extension requires a program header which include the name, type, script author, date, description and revision history(see above section). Remember to update the revision history when updating an existing extension.
+
+* **Table Description**
+Every Dynamic Table should incldude a descritpion.
+
+* **Variable and Method naming**
+Names of variables and methods should be in **lowerCamelCase**.
\ No newline at end of file
diff --git a/docs/documentation/version-controlling.md b/docs/documentation/version-controlling.md
index c5039ff..11661ac 100644
--- a/docs/documentation/version-controlling.md
+++ b/docs/documentation/version-controlling.md
@@ -2,7 +2,7 @@
layout: default
title: Version Controlling
parent: Documentation
-nav_order: 9
+nav_order: 10
---
# Version Controlling
diff --git a/docs/examples/Templates/DatabaseOperations_Temaplate.md b/docs/examples/Templates/DatabaseOperations_Temaplate.md
index 5bc5f51..5b170ce 100644
--- a/docs/examples/Templates/DatabaseOperations_Temaplate.md
+++ b/docs/examples/Templates/DatabaseOperations_Temaplate.md
@@ -34,10 +34,10 @@ void create() {
.index("00")
.build();
DBContainer container = query.getContainer();
- container.set("FIELD1", "DATA1");
- container.set("FIELD2", "DATA2");
- container.set("FIELD3", "DATA3");
- container.set("FIELD4", "DATA4");
+ container.setString("FIELD1", "DATA1");
+ container.setString("FIELD2", "DATA2");
+ container.setInt("FIELD3", 3);
+ container.setChar("FIELD4", '4');
query.insert(container);
}
```
@@ -53,11 +53,11 @@ void read() {
.selection("FIELD3", "FIELD4")
.build();
DBContainer container = query.getContainer();
- container.set("FIELD1", "DATA1");
- container.set("FIELD2", "DATA2");
+ container.setString("FIELD1", "DATA1");
+ container.setDouble("FIELD2", 2.0);
if(query.read(container)) {
- String message = container.get("FIELD3");
- String data = container.get("FIELD4");
+ String message = container.getString("FIELD3");
+ Character character = container.getDouble("FIELD4");
//Use found record(s) as intended
}
}
@@ -70,15 +70,17 @@ void multiRead() {
.selection("FIELD3", "FIELD4")
.build();
DBContainer container = query.getContainer();
- container.set("FIELD1", "DATA1");
- container.set("FIELD2", "DATA2");
+ container.setString("FIELD1", "DATA1");
+ container.setInt("FIELD2", 2);
int nrOfKeys = 2;
int nrOfRecords = mi.getMaxRecords() <= 0 || mi.getMaxRecords() >= 10000? 10000: mi.getMaxRecords();
query.readAll(container, nrOfKeys, nrOfRecords, callback);
}
Closure> callback = { DBContainer container ->
- String message = container.get("FIELD3");
- String data = container.get("FIELD4");
+ String message = container.getString("FIELD3");
+ Integer data = container.getInt("FIELD4");
+ //Note: Integer can store null value, while int can store null value,
+ // keep that in mind while designing your extension
//Use found record(s) as intended
}
```
@@ -93,15 +95,17 @@ void filteredMultiRead() {
.selection("FIELD3", "FIELD4")
.build();
DBContainer container = query.getContainer();
- container.set("FIELD1", "DATA1");
- container.set("FIELD2", "DATA2");
+ container.setString("FIELD1", "DATA1");
+ container.setInt("FIELD2", 2);
int nrOfKeys = 2;
int nrOfRecords = mi.getMaxRecords() <= 0 || mi.getMaxRecords() >= 10000? 10000: mi.getMaxRecords();
query.readAll(container, nrOfKeys, nrOfRecords, callback);
}
Closure> callback = { DBContainer container ->
- String message = container.get("FIELD3");
- String data = container.get("FIELD4");
+ String message = container.getString("FIELD3");
+ Integer data = container.getInt("FIELD4");
+ //Note: 'Integer' can store null value, while 'int' cannnot.
+ // Keep that in mind while designing your extension
//Use found record(s) as intended
}
```
@@ -114,10 +118,10 @@ void update() {
.index("00")
.build();
DBContainer container = query.getContainer();
- container.set("FIELD1", "DATA1");
- container.set("FIELD2", "DATA2");
+ container.setString("FIELD1", "DATA1");
+ container.setInt("FIELD2", 2);
query.insert(container, { LockedResult updateRecord ->
- updateRecord.set("FIELD3", "DATA3");
+ updateRecord.setChar("FIELD3", '3');
updateRecord.update();
});
}
@@ -131,8 +135,8 @@ void delete() {
.index("00")
.build();
DBContainer container = query.getContainer();
- container.set("FIELD1", "DATA1");
- container.set("FIELD2", "DATA2");
+ container.setString("FIELD1", "DATA1");
+ container.setInt("FIELD2", 2);
query.readLock(container, callback);
}
Closure> callback = { LockedResult lockedResult ->
diff --git a/index.md b/index.md
index cc4d0da..ea6ee5f 100644
--- a/index.md
+++ b/index.md
@@ -27,7 +27,7 @@ extension of the logic is possible.
## About the project
### XtendM3
-XtendM3 is a customization tool and service provided by Infor for modifying and extending M3 Business Engine logic in Cloud.
+XtendM3 is a customization tool and service provided by Infor for modifying and extending M3 Business Engine logic in the Cloud.
### Just the Docs