Skip to content

Commit

Permalink
Merge pull request #75 from infor-cloud/CompilationRules
Browse files Browse the repository at this point in the history
Documentation Updates
  • Loading branch information
filiphakansson1 authored Oct 20, 2024
2 parents 0edb049 + 123df45 commit a5026d1
Show file tree
Hide file tree
Showing 29 changed files with 699 additions and 969 deletions.
Binary file modified assets/attachments/export/window.PNG
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 3 additions & 3 deletions docs/documentation/api-specification/batch-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -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).
<br>

Expand All @@ -52,7 +52,7 @@ Example:
<br>
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:
Expand All @@ -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.
87 changes: 43 additions & 44 deletions docs/documentation/api-specification/database-api.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
layout: default
title: Database APIs
title: Database API
parent: API Specification
grand_parent: Documentation
nav_order: 7
Expand Down Expand Up @@ -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");
}
}
```
Expand All @@ -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
}
```
Expand All @@ -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");
}
```

Expand All @@ -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();
}
}
Expand All @@ -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);
}
Expand All @@ -221,22 +220,22 @@ 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;
DBAction query = database.table("MITMAS")
.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();
}
```
Expand All @@ -247,17 +246,18 @@ 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;
DBAction query = database.table("MITMAS")
.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 ->
Expand All @@ -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.
60 changes: 20 additions & 40 deletions docs/documentation/api-specification/exception-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
```

Expand Down Expand Up @@ -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);
}
}
```
Expand Down
1 change: 0 additions & 1 deletion docs/documentation/api-specification/extension-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Loading

0 comments on commit a5026d1

Please sign in to comment.