formatted nav patterns 2 to 4
This commit is contained in:
parent
2fad891a77
commit
f1f4aab1d7
55 changed files with 788 additions and 506 deletions
|
|
@ -18,8 +18,6 @@ If the table is empty, it means that either the upgrade has run, or there was no
|
||||||
|
|
||||||
**Solution:** if using an upgrade table, always validate that the table contains data before doing anything.
|
**Solution:** if using an upgrade table, always validate that the table contains data before doing anything.
|
||||||
|
|
||||||
****
|
|
||||||
|
|
||||||
### Upgrade code, can it be rerun safely?
|
### Upgrade code, can it be rerun safely?
|
||||||
|
|
||||||
**Problem**: if the upgrade code is not written in a way that makes it runnable twice ([idempotent][anchor1]), then several failures can happen, including something as critical as data corruption.
|
**Problem**: if the upgrade code is not written in a way that makes it runnable twice ([idempotent][anchor1]), then several failures can happen, including something as critical as data corruption.
|
||||||
|
|
|
||||||
|
|
@ -8,18 +8,18 @@ Unintentional value changes might propagate. Also, it might lead people to belie
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
LOCAL PROCEDURE ShowMessage@15(VAR Text@1000 : Text\[250\]);
|
LOCAL PROCEDURE ShowMessage@15(VAR Text@1000 : Text[250]);
|
||||||
BEGIN
|
BEGIN
|
||||||
Text := GetMessageText;
|
Text := GetMessageText;
|
||||||
IF (Text <\> '') AND GenJnlLineInserted THEN
|
IF (Text <> '') AND GenJnlLineInserted THEN
|
||||||
MESSAGE(Text);
|
MESSAGE(Text);
|
||||||
END;
|
END;
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
LOCAL PROCEDURE ShowMessage@15(Text@1000 : Text\[250\]);
|
LOCAL PROCEDURE ShowMessage@15(Text@1000 : Text[250]);
|
||||||
BEGIN
|
BEGIN
|
||||||
Text := GetMessageText;
|
Text := GetMessageText;
|
||||||
IF (Text <\> '') AND GenJnlLineInserted THEN
|
IF (Text <> '') AND GenJnlLineInserted THEN
|
||||||
MESSAGE(Text);
|
MESSAGE(Text);
|
||||||
END;
|
END;
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ Do not write functions that have high class coupling. This makes the code hard t
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
Any procedure / trigger that has class coupling of \> 30
|
Any procedure / trigger that has class coupling of > 30
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ Do not write functions that have high cyclomatic complexity. This makes the code
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
Any procedure / trigger that has a cyclomatic complexity \> 25, using the CC3 version mentioned in [this article][anchor0].
|
Any procedure / trigger that has a cyclomatic complexity > 25, using the CC3 version mentioned in [this article][anchor0].
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,23 +7,23 @@ FINDSET, FIND('+') or FIND('-') should only be used when NEXT is used and vice v
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
IF Cust.FIND('-') THEN
|
IF Cust.FIND('-') THEN
|
||||||
ERROR(CustIsBlockErr)
|
ERROR(CustIsBlockErr)
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
IF Cust.FINDFIRST THEN
|
IF Cust.FINDFIRST THEN
|
||||||
ERROR(CustIsBlockErr)
|
ERROR(CustIsBlockErr)
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
IF Cust.FINDFIRST THEN
|
IF Cust.FINDFIRST THEN
|
||||||
REPEAT
|
REPEAT
|
||||||
...
|
...
|
||||||
UNTIL Cust.NEXT = 0;
|
UNTIL Cust.NEXT = 0;
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
IF Cust.FINDSET THEN
|
IF Cust.FINDSET THEN
|
||||||
REPEAT
|
REPEAT
|
||||||
...
|
...
|
||||||
UNTIL Cust.NEXT = 0;
|
UNTIL Cust.NEXT = 0;
|
||||||
|
|
|
||||||
|
|
@ -8,25 +8,25 @@ Bad code
|
||||||
|
|
||||||
PROCEDURE SetPurchLine@22(VAR CurrentPurchLine@1000 : Record 39);
|
PROCEDURE SetPurchLine@22(VAR CurrentPurchLine@1000 : Record 39);
|
||||||
VAR
|
VAR
|
||||||
Pegging@1001 : Boolean;
|
Pegging@1001 : Boolean;
|
||||||
BEGIN
|
BEGIN
|
||||||
IF Pegging THEN
|
IF Pegging THEN
|
||||||
CurrQuantity := CurrentPurchLine."Quantity (Base)"
|
CurrQuantity := CurrentPurchLine."Quantity (Base)"
|
||||||
ELSE
|
ELSE
|
||||||
CurrQuantity := CurrentPurchLine."Outstanding Qty. (Base)";
|
CurrQuantity := CurrentPurchLine."Outstanding Qty. (Base)";
|
||||||
END;
|
END;
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
PROCEDURE SetPurchLine@22(VAR CurrentPurchLine@1000 : Record 39);
|
PROCEDURE SetPurchLine@22(VAR CurrentPurchLine@1000 : Record 39);
|
||||||
VAR
|
VAR
|
||||||
Pegging@1001 : Boolean;
|
Pegging@1001 : Boolean;
|
||||||
BEGIN
|
BEGIN
|
||||||
Pegging := IsPegging(CurrentPurchLine);
|
Pegging := IsPegging(CurrentPurchLine);
|
||||||
IF Pegging THEN
|
IF Pegging THEN
|
||||||
CurrQuantity := CurrentPurchLine."Quantity (Base)"
|
CurrQuantity := CurrentPurchLine."Quantity (Base)"
|
||||||
ELSE
|
ELSE
|
||||||
CurrQuantity := CurrentPurchLine."Outstanding Qty. (Base)";
|
CurrQuantity := CurrentPurchLine."Outstanding Qty. (Base)";
|
||||||
END;
|
END;
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
@ -34,16 +34,16 @@ Bad code
|
||||||
// In the example below, the function will always return FALSE.
|
// In the example below, the function will always return FALSE.
|
||||||
PROCEDURE GetItemsToPlan@22() : Boolean;
|
PROCEDURE GetItemsToPlan@22() : Boolean;
|
||||||
BEGIN
|
BEGIN
|
||||||
SETRANGE("Document Type","Document Type"::Order);
|
SETRANGE("Document Type","Document Type"::Order);
|
||||||
...
|
...
|
||||||
FINDSET
|
FINDSET
|
||||||
END;
|
END;
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
PROCEDURE GetItemsToPlan@22() : Boolean;
|
PROCEDURE GetItemsToPlan@22() : Boolean;
|
||||||
BEGIN
|
BEGIN
|
||||||
SETRANGE("Document Type","Document Type"::Order);
|
SETRANGE("Document Type","Document Type"::Order);
|
||||||
...
|
...
|
||||||
EXIT(FINDSET)
|
EXIT(FINDSET)
|
||||||
END;
|
END;
|
||||||
|
|
|
||||||
|
|
@ -12,11 +12,11 @@ Bad code
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
Any procedure / trigger that has a maintainability index \>= 20\.
|
Any procedure / trigger that has a maintainability index >= 20\.
|
||||||
The Maintainability Index is computed as a function:
|
The Maintainability Index is computed as a function:
|
||||||
- Lines Of Code (inverse proportional)
|
- Lines Of Code (inverse proportional)
|
||||||
- the Halstead Volume
|
- the Halstead Volume
|
||||||
- Cyclomatic Complexity (inverse proportional).
|
- Cyclomatic Complexity (inverse proportional).
|
||||||
|
|
||||||
More info
|
More info
|
||||||
|
|
||||||
|
|
@ -25,7 +25,7 @@ More info
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
Any procedure / trigger that is \> 100 lines of code
|
Any procedure / trigger that is > 100 lines of code
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,6 @@ weight = 920
|
||||||
+++
|
+++
|
||||||
The number of parameters passed to a string must match the placeholders.
|
The number of parameters passed to a string must match the placeholders.
|
||||||
|
|
||||||
****
|
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
CannotDeleteLineErr@1005 : TextConst 'ENU=You cannot delete this line because one or more rating values exists.';
|
CannotDeleteLineErr@1005 : TextConst 'ENU=You cannot delete this line because one or more rating values exists.';
|
||||||
|
|
@ -18,7 +16,7 @@ Good code
|
||||||
...
|
...
|
||||||
ERROR(CannotDeleteLineErr);
|
ERROR(CannotDeleteLineErr);
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,14 +8,14 @@ Bad code
|
||||||
|
|
||||||
LOCAL PROCEDURE Code@1();
|
LOCAL PROCEDURE Code@1();
|
||||||
VAR
|
VAR
|
||||||
CAJnlPostBatch@1001 : Codeunit 1103;
|
CAJnlPostBatch@1001 : Codeunit 1103;
|
||||||
BEGIN
|
BEGIN
|
||||||
CAJnlPostBatch.Run(CostJnlLine);
|
CAJnlPostBatch.Run(CostJnlLine);
|
||||||
END;
|
END;
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
LOCAL PROCEDURE Code@1();
|
LOCAL PROCEDURE Code@1();
|
||||||
BEGIN
|
BEGIN
|
||||||
CODEUNIT.RUN(CODEUNIT::"CA Jnl.-Post Batch",CostJnlLine);
|
CODEUNIT.RUN(CODEUNIT::"CA Jnl.-Post Batch",CostJnlLine);
|
||||||
END;
|
END;
|
||||||
|
|
|
||||||
|
|
@ -8,18 +8,18 @@ It affects code readability and can lead to wrong assumptions.
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
IF Type <\> Type::FIELD THEN BEGIN
|
IF Type <> Type::FIELD THEN BEGIN
|
||||||
...
|
...
|
||||||
ERROR(...);
|
ERROR(...);
|
||||||
RecRef.CLOSE;
|
RecRef.CLOSE;
|
||||||
END;
|
END;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
IF Type <\> Type::FIELD THEN BEGIN
|
IF Type <> Type::FIELD THEN BEGIN
|
||||||
...
|
...
|
||||||
RecRef.CLOSE;
|
RecRef.CLOSE;
|
||||||
ERROR(...);
|
ERROR(...);
|
||||||
END;
|
END;
|
||||||
|
|
|
||||||
|
|
@ -6,33 +6,33 @@ The value assigned to a variable must be used. Else the variable is not necessar
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
PROCEDURE AddEntities@1(FilterStr@1000 : Text\[250\]);
|
PROCEDURE AddEntities@1(FilterStr@1000 : Text[250]);
|
||||||
VAR
|
VAR
|
||||||
Vendor@1001 : Record 23;
|
Vendor@1001 : Record 23;
|
||||||
Count@1002 : Integer;
|
Count@1002 : Integer;
|
||||||
BEGIN
|
BEGIN
|
||||||
Count := 0;
|
Count := 0;
|
||||||
Vendor.SETFILTER("No.",FilterStr);
|
Vendor.SETFILTER("No.",FilterStr);
|
||||||
IF Vendor.FINDSET THEN
|
IF Vendor.FINDSET THEN
|
||||||
REPEAT
|
REPEAT
|
||||||
"User ID" := USERID;
|
"User ID" := USERID;
|
||||||
"Vendor No." := Vendor."No.";
|
"Vendor No." := Vendor."No.";
|
||||||
IF INSERT THEN
|
IF INSERT THEN
|
||||||
Count += 1;
|
Count += 1;
|
||||||
UNTIL Vendor.NEXT = 0;
|
UNTIL Vendor.NEXT = 0;
|
||||||
END;
|
END;
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
PROCEDURE AddEntities@1(FilterStr@1000 : Text\[250\]);
|
PROCEDURE AddEntities@1(FilterStr@1000 : Text[250]);
|
||||||
VAR
|
VAR
|
||||||
Vendor@1001 : Record 23;
|
Vendor@1001 : Record 23;
|
||||||
BEGIN
|
BEGIN
|
||||||
Vendor.SETFILTER("No.",FilterStr);
|
Vendor.SETFILTER("No.",FilterStr);
|
||||||
IF Vendor.FINDSET THEN
|
IF Vendor.FINDSET THEN
|
||||||
REPEAT
|
REPEAT
|
||||||
"User ID" := USERID;
|
"User ID" := USERID;
|
||||||
"Vendor No." := Vendor."No.";
|
"Vendor No." := Vendor."No.";
|
||||||
IF INSERT THEN;
|
IF INSERT THEN;
|
||||||
UNTIL Vendor.NEXT = 0;
|
UNTIL Vendor.NEXT = 0;
|
||||||
END;
|
END;
|
||||||
|
|
|
||||||
|
|
@ -8,37 +8,37 @@ Unused variables affect readability.
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
PROCEDURE CheckPostingDate@23(CaptionEntryNo@1005 : Text\[50\]);
|
PROCEDURE CheckPostingDate@23(CaptionEntryNo@1005 : Text[50]);
|
||||||
BEGIN
|
BEGIN
|
||||||
IF GenJnlCheckLine.DateNotAllowed(PostingDate) THEN
|
IF GenJnlCheckLine.DateNotAllowed(PostingDate) THEN
|
||||||
ERROR(DateNotAllowedErr,Caption,EntryNo)
|
ERROR(DateNotAllowedErr,Caption,EntryNo)
|
||||||
IF PostingDate \> MaxPostingDate THEN
|
IF PostingDate > MaxPostingDate THEN
|
||||||
MaxPostingDate := PostingDate;
|
MaxPostingDate := PostingDate;
|
||||||
END
|
END
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
PROCEDURE CheckPostingDate@23();
|
PROCEDURE CheckPostingDate@23();
|
||||||
BEGIN
|
BEGIN
|
||||||
IF GenJnlCheckLine.DateNotAllowed(PostingDate) THEN
|
IF GenJnlCheckLine.DateNotAllowed(PostingDate) THEN
|
||||||
ERROR(DateNotAllowedErr,Caption,EntryNo);
|
ERROR(DateNotAllowedErr,Caption,EntryNo);
|
||||||
IF PostingDate \> MaxPostingDate THEN
|
IF PostingDate > MaxPostingDate THEN
|
||||||
MaxPostingDate := PostingDate;
|
MaxPostingDate := PostingDate;
|
||||||
END;
|
END;
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
PROCEDURE IsReturned@14(EntryNo@1002 : Integer) : Decimal;
|
PROCEDURE IsReturned@14(EntryNo@1002 : Integer) : Decimal;
|
||||||
VAR
|
VAR
|
||||||
ItemEntry@1000 : Record 32;
|
ItemEntry@1000 : Record 32;
|
||||||
Quantity@1003 : Integer;
|
Quantity@1003 : Integer;
|
||||||
BEGIN
|
BEGIN
|
||||||
EXIT(-OutboundApplied(EntryNo,TRUE) - InboundApplied(EntryNo,TRUE));
|
EXIT(-OutboundApplied(EntryNo,TRUE) - InboundApplied(EntryNo,TRUE));
|
||||||
END;
|
END;
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
PROCEDURE IsReturned@14(EntryNo@1002 : Integer) : Decimal;
|
PROCEDURE IsReturned@14(EntryNo@1002 : Integer) : Decimal;
|
||||||
BEGIN
|
BEGIN
|
||||||
EXIT(-OutboundApplied(EntryNo,TRUE) - InboundApplied(EntryNo,TRUE));
|
EXIT(-OutboundApplied(EntryNo,TRUE) - InboundApplied(EntryNo,TRUE));
|
||||||
END;
|
END;
|
||||||
|
|
|
||||||
|
|
@ -8,52 +8,52 @@ It will throw an error at runtime.
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
FileName@1010 : Text\[250\];
|
FileName@1010 : Text[250];
|
||||||
...
|
...
|
||||||
UploadedFileName@1016 : Text\[1024\];
|
UploadedFileName@1016 : Text[1024];
|
||||||
...
|
...
|
||||||
FileName := UploadedFileName;
|
FileName := UploadedFileName;
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
FileName@1010 : Text\[1024\];
|
FileName@1010 : Text[1024];
|
||||||
...
|
...
|
||||||
UploadedFileName@1016 : Text\[1024\];
|
UploadedFileName@1016 : Text[1024];
|
||||||
...
|
...
|
||||||
FileName := UploadedFileName;
|
FileName := UploadedFileName;
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
FileName@1010 : Text\[250\];
|
FileName@1010 : Text[250];
|
||||||
...
|
...
|
||||||
UploadedFileName@1016 : Text\[1024\];
|
UploadedFileName@1016 : Text[1024];
|
||||||
...
|
...
|
||||||
FileName := UploadedFileName;
|
FileName := UploadedFileName;
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
FileName@1010 : Text\[250\];
|
FileName@1010 : Text[250];
|
||||||
...
|
...
|
||||||
UploadedFileName@1016 : Text\[1024\];
|
UploadedFileName@1016 : Text[1024];
|
||||||
...
|
...
|
||||||
FileName := COPYSTR(UploadedFileName,1,250); // In case only the first 250 chars are needed. Similar for fields
|
FileName := COPYSTR(UploadedFileName,1,250); // In case only the first 250 chars are needed. Similar for fields
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
VAR
|
VAR
|
||||||
ExceededNumberTxt@001 : 'ENU=Warning: Exceeded number of unsent documents/requests'
|
ExceededNumberTxt@001 : 'ENU=Warning: Exceeded number of unsent documents/requests'
|
||||||
Subject@1002 : Text\[50\];
|
Subject@1002 : Text[50];
|
||||||
...
|
...
|
||||||
BEGIN
|
BEGIN
|
||||||
...
|
...
|
||||||
Subject := ExceededNumberTxt;
|
Subject := ExceededNumberTxt;
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
VAR
|
VAR
|
||||||
ExceededNumberTxt@001 : 'ENU=Warning: Exceeded number of unsent documents/requests'
|
ExceededNumberTxt@001 : 'ENU=Warning: Exceeded number of unsent documents/requests'
|
||||||
Subject@1002 : Text\[100\];
|
Subject@1002 : Text[100];
|
||||||
...
|
...
|
||||||
BEGIN
|
BEGIN
|
||||||
...
|
...
|
||||||
Subject := ExceededNumberTxt';
|
Subject := ExceededNumberTxt';
|
||||||
|
|
|
||||||
|
|
@ -4,17 +4,18 @@ weight = 1450
|
||||||
+++
|
+++
|
||||||
Do not use the WITH scope when it has a variable whose name is the same as a local variable. This can lead to wrong code assumptions.
|
Do not use the WITH scope when it has a variable whose name is the same as a local variable. This can lead to wrong code assumptions.
|
||||||
|
|
||||||
**Given that** "Contract Type" is a field on table ServiceContractHeader, then in the following example there is a parameter name clash with the field name. Which one will be used?
|
**Given that**
|
||||||
|
"Contract Type" is a field on table ServiceContractHeader, then in the following example there is a parameter name clash with the field name. Which one will be used?
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
PROCEDURE InsertData@1("Contract Type"@1000 : Option...);
|
PROCEDURE InsertData@1("Contract Type"@1000 : Option...);
|
||||||
...
|
...
|
||||||
BEGIN
|
BEGIN
|
||||||
...
|
...
|
||||||
WITH ServiceContractHeader DO BEGIN
|
WITH ServiceContractHeader DO BEGIN
|
||||||
...
|
...
|
||||||
DimMgt.InsertServContractDim(...,"Contract Type","Contract No.",0,...);
|
DimMgt.InsertServContractDim(...,"Contract Type","Contract No.",0,...);
|
||||||
END;
|
END;
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
@ -22,8 +23,8 @@ Good code
|
||||||
PROCEDURE InsertData@1(ContractType@1000 : Option...);
|
PROCEDURE InsertData@1(ContractType@1000 : Option...);
|
||||||
...
|
...
|
||||||
BEGIN
|
BEGIN
|
||||||
...
|
...
|
||||||
WITH ServiceContractHeader DO BEGIN
|
WITH ServiceContractHeader DO BEGIN
|
||||||
...
|
...
|
||||||
DimMgt.InsertServContractDim(...,ContractType,"Contract No.",0,...);
|
DimMgt.InsertServContractDim(...,ContractType,"Contract No.",0,...);
|
||||||
END;
|
END;
|
||||||
|
|
|
||||||
|
|
@ -2,15 +2,16 @@
|
||||||
title = "Using Calcdate"
|
title = "Using Calcdate"
|
||||||
weight = 1370
|
weight = 1370
|
||||||
+++
|
+++
|
||||||
CALCDATE should only be used with DateFormula variables. Alternatively the string should be enclosed using the <\> symbols.
|
CALCDATE should only be used with DateFormula variables. Alternatively the string should be enclosed using the <> symbols.
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
IF ReservEntry."Expected Receipt Date" \>
|
IF ReservEntry."Expected Receipt Date" >
|
||||||
CALCDATE('-' + FORMAT("Dampener (Time)") + FirstDate)
|
CALCDATE('-' + FORMAT("Dampener (Time)") + FirstDate)
|
||||||
THEN
|
THEN
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
IF ReservEntry."Expected Receipt Date" \>
|
IF ReservEntry."Expected Receipt Date" >
|
||||||
CALCDATE('<-' + FORMAT("Dampener (Time)") + FirstDate + '\>')
|
CALCDATE('<-' + FORMAT("Dampener (Time)") + FirstDate + '>')
|
||||||
THEN
|
THEN
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,12 @@ Reason:
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
IF NOT CONFIRM(UpdateLocationQst,TRUE,FIELDNAME("Location Code"),...)
|
```al
|
||||||
|
IF NOT CONFIRM(UpdateLocationQst,TRUE,FIELDNAME("Location Code"),...)
|
||||||
|
```
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
IF NOT CONFIRM(UpdateLocationQst,TRUE,FIELDCAPTION("Location Code"),...)
|
```al
|
||||||
|
IF NOT CONFIRM(UpdateLocationQst,TRUE,FIELDCAPTION("Location Code"),...)
|
||||||
|
```
|
||||||
|
|
|
||||||
|
|
@ -6,15 +6,19 @@ Declare Text Constant as global variables.
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
PROCEDURE GetRequirementText@6(...) : Text\[50\];
|
```al
|
||||||
VAR
|
PROCEDURE GetRequirementText@6(...) : Text\[50\];
|
||||||
|
VAR
|
||||||
RequirementOptionsTxt@1002 : TextConst 'ENU=Shipment,Receive,Pick,Put-Away';
|
RequirementOptionsTxt@1002 : TextConst 'ENU=Shipment,Receive,Pick,Put-Away';
|
||||||
BEGIN
|
BEGIN
|
||||||
|
```
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
VAR
|
```al
|
||||||
|
VAR
|
||||||
RequirementOptionsTxt@1002 : TextConst 'ENU=Shipment,Receive,Pick,Put-Away';
|
RequirementOptionsTxt@1002 : TextConst 'ENU=Shipment,Receive,Pick,Put-Away';
|
||||||
...
|
...
|
||||||
PROCEDURE GetRequirementText@6(...) : Text\[50\];
|
PROCEDURE GetRequirementText@6(...) : Text\[50\];
|
||||||
BEGIN
|
BEGIN
|
||||||
|
```
|
||||||
|
|
|
||||||
|
|
@ -6,32 +6,40 @@ Pass user messages using Text Constants. It makes translation easy.
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
ImportAttachmentQst@1021 : TextConst 'ENU="Import attachment "';
|
```al
|
||||||
...
|
ImportAttachmentQst@1021 : TextConst 'ENU="Import attachment "';
|
||||||
IF CONFIRM(ImportAttachmentQst + Caption +'?',TRUE) THEN BEGIN
|
...
|
||||||
|
IF CONFIRM(ImportAttachmentQst + Caption +'?',TRUE) THEN BEGIN
|
||||||
|
```
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
ImportAttachmentQst@1021 : TextConst 'ENU="Import attachment %1?"';
|
```al
|
||||||
...
|
ImportAttachmentQst@1021 : TextConst 'ENU="Import attachment %1?"';
|
||||||
IF CONFIRM(STRSUBSTNO(ImportAttachmentQst, Caption),TRUE) THEN BEGIN
|
...
|
||||||
|
IF CONFIRM(STRSUBSTNO(ImportAttachmentQst, Caption),TRUE) THEN BEGIN
|
||||||
|
```
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
...
|
```al
|
||||||
|
...
|
||||||
IF NOT
|
IF NOT
|
||||||
CONFIRM(
|
CONFIRM(
|
||||||
STRSUBSTNO(
|
STRSUBSTNO(
|
||||||
'Difference on Periodic entries: %1 on %2' +
|
'Difference on Periodic entries: %1 on %2' +
|
||||||
'Do you want to continue?',Balance,Date),
|
'Do you want to continue?',Balance,Date),
|
||||||
TRUE)
|
TRUE)
|
||||||
THEN
|
THEN
|
||||||
ERROR('Program terminated by the user');
|
ERROR('Program terminated by the user');
|
||||||
|
```
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
DiffOnPeriodEntiesQst@100 : TextConst 'ENU="Difference on Periodic entries: %1 on %2\\ Do you want to continue?"';
|
```al
|
||||||
ProgramTerminatedErr@200 : TextConst 'ENU="Program terminated by the user"';
|
DiffOnPeriodEntiesQst@100 : TextConst 'ENU="Difference on Periodic entries: %1 on %2\\ Do you want to continue?"';
|
||||||
...
|
ProgramTerminatedErr@200 : TextConst 'ENU="Program terminated by the user"';
|
||||||
|
...
|
||||||
IF NOT CONFIRM(STRSUBSTNO(DiffOnPeriodEntiesQst,Balance,Date),TRUE) THEN
|
IF NOT CONFIRM(STRSUBSTNO(DiffOnPeriodEntiesQst,Balance,Date),TRUE) THEN
|
||||||
ERROR(ProgramTerminatedErr);
|
ERROR(ProgramTerminatedErr);
|
||||||
|
```
|
||||||
|
|
|
||||||
|
|
@ -2,15 +2,21 @@
|
||||||
title = "Begin as an 'After Word'"
|
title = "Begin as an 'After Word'"
|
||||||
weight = 230
|
weight = 230
|
||||||
+++
|
+++
|
||||||
When BEGIN follows THEN, ELSE, DO, it should be on the same line, preceded by one space character. Bad code
|
When BEGIN follows THEN, ELSE, DO, it should be on the same line, preceded by one space character.
|
||||||
|
|
||||||
IF ICPartnerRefType = ICPartnerRefType::"Common Item No." THEN
|
Bad code
|
||||||
|
|
||||||
|
```al
|
||||||
|
IF ICPartnerRefType = ICPartnerRefType::"Common Item No." THEN
|
||||||
BEGIN
|
BEGIN
|
||||||
...
|
...
|
||||||
END;
|
END;
|
||||||
|
```
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
IF ICPartnerRefType = ICPartnerRefType::"Common Item No." THEN BEGIN
|
```
|
||||||
|
IF ICPartnerRefType = ICPartnerRefType::"Common Item No." THEN BEGIN
|
||||||
...
|
...
|
||||||
END;
|
END;
|
||||||
|
```
|
||||||
|
|
|
||||||
|
|
@ -3,52 +3,67 @@ title = "Begin-End - Compound Only"
|
||||||
weight = 240
|
weight = 240
|
||||||
+++
|
+++
|
||||||
Only use BEGIN..END to enclose compound statements.
|
Only use BEGIN..END to enclose compound statements.
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
IF FINDSET THEN BEGIN
|
```al
|
||||||
|
IF FINDSET THEN BEGIN
|
||||||
REPEAT
|
REPEAT
|
||||||
...
|
...
|
||||||
UNTIL NEXT = 0;
|
UNTIL NEXT = 0;
|
||||||
END;
|
END;
|
||||||
|
```
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
IF FINDSET THEN
|
```al
|
||||||
|
IF FINDSET THEN
|
||||||
REPEAT
|
REPEAT
|
||||||
...
|
...
|
||||||
UNTIL NEXT = 0;
|
UNTIL NEXT = 0;
|
||||||
|
```
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
IF IsAssemblyOutputLine THEN BEGIN
|
```al
|
||||||
|
IF IsAssemblyOutputLine THEN BEGIN
|
||||||
TESTFIELD("Order Line No.",0);
|
TESTFIELD("Order Line No.",0);
|
||||||
END;
|
END;
|
||||||
|
```
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
IF IsAssemblyOutputLine THEN
|
```al
|
||||||
|
IF IsAssemblyOutputLine THEN
|
||||||
TESTFIELD("Order Line No.",0);
|
TESTFIELD("Order Line No.",0);
|
||||||
|
```
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
IF FINDSET THEN
|
```al
|
||||||
|
IF FINDSET THEN
|
||||||
REPEAT
|
REPEAT
|
||||||
BEGIN
|
BEGIN
|
||||||
...
|
...
|
||||||
END;
|
END;
|
||||||
UNTIL NEXT = 0;
|
UNTIL NEXT = 0;
|
||||||
|
```
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
IF FINDSET THEN
|
```al
|
||||||
|
IF FINDSET THEN
|
||||||
REPEAT
|
REPEAT
|
||||||
...
|
...
|
||||||
UNTIL NEXT = 0;
|
UNTIL NEXT = 0;
|
||||||
|
```
|
||||||
|
|
||||||
Exception
|
Exception
|
||||||
|
|
||||||
// Except for this case
|
```al
|
||||||
IF X THEN BEGIN
|
// Except for this case
|
||||||
|
IF X THEN BEGIN
|
||||||
IF Y THEN
|
IF Y THEN
|
||||||
DO SOMETHING;
|
DO SOMETHING;
|
||||||
END ELSE (not X)
|
END ELSE (not X)
|
||||||
|
```
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,20 @@
|
||||||
title = "Binary Operator to Start Line"
|
title = "Binary Operator to Start Line"
|
||||||
weight = 250
|
weight = 250
|
||||||
+++
|
+++
|
||||||
Do not start a line with a binary operator. Bad code
|
Do not start a line with a binary operator.
|
||||||
|
|
||||||
"Quantity to Ship" :=
|
Bad code
|
||||||
|
|
||||||
|
```al
|
||||||
|
"Quantity to Ship" :=
|
||||||
Quantity
|
Quantity
|
||||||
- "Quantity Shipped"
|
- "Quantity Shipped"
|
||||||
|
```
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
"Quantity to Ship" :=
|
```al
|
||||||
|
"Quantity to Ship" :=
|
||||||
Quantity -
|
Quantity -
|
||||||
"Quantity Shipped"
|
"Quantity Shipped"
|
||||||
|
```
|
||||||
|
|
|
||||||
|
|
@ -2,30 +2,43 @@
|
||||||
title = "Blank Lines"
|
title = "Blank Lines"
|
||||||
weight = 260
|
weight = 260
|
||||||
+++
|
+++
|
||||||
Do not use blank lines at the beginning or end of any functions, after BEGIN, before END, or inside multiline expressions. Bad code
|
Do not use blank lines at the beginning or end of any functions, after BEGIN, before END, or inside multiline expressions.
|
||||||
|
|
||||||
PROCEDURE MATRIX\_OnDrillDown@1133(MATRIX\_ColumnOrdinal : Integer);
|
|
||||||
BEGIN
|
|
||||||
SetupDrillDownCol(MATRIX\_ColumnOrdinal);
|
|
||||||
DrillDown(FALSE,ValueType);
|
|
||||||
END;
|
|
||||||
|
|
||||||
Good code
|
|
||||||
|
|
||||||
PROCEDURE MATRIX\_OnDrillDown@1133(MATRIX\_ColumnOrdinal : Integer);
|
|
||||||
BEGIN
|
|
||||||
SetupDrillDownCol(MATRIX\_ColumnOrdinal);
|
|
||||||
DrillDown(FALSE,ValueType);
|
|
||||||
END;
|
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
IF NameIsValid AND
|
```al
|
||||||
Name2IsValid
|
PROCEDURE MATRIX_OnDrillDown@1133(MATRIX_ColumnOrdinal : Integer);
|
||||||
THEN
|
BEGIN
|
||||||
|
|
||||||
|
SetupDrillDownCol(MATRIX_ColumnOrdinal);
|
||||||
|
DrillDown(FALSE,ValueType);
|
||||||
|
|
||||||
|
END;
|
||||||
|
```
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
IF NameIsValid AND
|
```al
|
||||||
|
PROCEDURE MATRIX_OnDrillDown@1133(MATRIX_ColumnOrdinal : Integer);
|
||||||
|
BEGIN
|
||||||
|
SetupDrillDownCol(MATRIX_ColumnOrdinal);
|
||||||
|
DrillDown(FALSE,ValueType);
|
||||||
|
END;
|
||||||
|
```
|
||||||
|
|
||||||
|
Bad code
|
||||||
|
|
||||||
|
```al
|
||||||
|
IF NameIsValid AND
|
||||||
|
|
||||||
Name2IsValid
|
Name2IsValid
|
||||||
THEN
|
THEN
|
||||||
|
```
|
||||||
|
|
||||||
|
Good code
|
||||||
|
|
||||||
|
```al
|
||||||
|
IF NameIsValid AND
|
||||||
|
Name2IsValid
|
||||||
|
THEN
|
||||||
|
```
|
||||||
|
|
|
||||||
|
|
@ -2,16 +2,22 @@
|
||||||
title = "CASE Action"
|
title = "CASE Action"
|
||||||
weight = 310
|
weight = 310
|
||||||
+++
|
+++
|
||||||
A CASE action should start on a line after the possibility. Bad code
|
A CASE action should start on a line after the possibility.
|
||||||
|
|
||||||
CASE Letter OF
|
Bad code
|
||||||
|
|
||||||
|
```al
|
||||||
|
CASE Letter OF
|
||||||
'A': Letter2 := '10';
|
'A': Letter2 := '10';
|
||||||
'B': Letter2 := '11';
|
'B': Letter2 := '11';
|
||||||
|
```
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
CASE Letter OF
|
```al
|
||||||
|
CASE Letter OF
|
||||||
'A':
|
'A':
|
||||||
Letter2 := '10';
|
Letter2 := '10';
|
||||||
'B':
|
'B':
|
||||||
Letter2 := '11';
|
Letter2 := '11';
|
||||||
|
```
|
||||||
|
|
@ -2,14 +2,20 @@
|
||||||
title = "Colon usage in CASE"
|
title = "Colon usage in CASE"
|
||||||
weight = 340
|
weight = 340
|
||||||
+++
|
+++
|
||||||
The last possibility on a CASE statement must be immediately followed by a colon. Bad code
|
The last possibility on a CASE statement must be immediately followed by a colon.
|
||||||
|
|
||||||
CASE DimOption OF
|
Bad code
|
||||||
|
|
||||||
|
```al
|
||||||
|
CASE DimOption OF
|
||||||
DimOption::"Global Dimension 1" :
|
DimOption::"Global Dimension 1" :
|
||||||
DimValue."Dimension Code" := GLSetup."Global Dimension 1 Code";
|
DimValue."Dimension Code" := GLSetup."Global Dimension 1 Code";
|
||||||
|
```
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
CASE DimOption OF
|
```al
|
||||||
|
CASE DimOption OF
|
||||||
DimOption::"Global Dimension 1":
|
DimOption::"Global Dimension 1":
|
||||||
DimValue."Dimension Code" := GLSetup."Global Dimension 1 Code";
|
DimValue."Dimension Code" := GLSetup."Global Dimension 1 Code";
|
||||||
|
```
|
||||||
|
|
|
||||||
|
|
@ -2,38 +2,45 @@
|
||||||
title = "Comments inside Curly Brackets"
|
title = "Comments inside Curly Brackets"
|
||||||
weight = 350
|
weight = 350
|
||||||
+++
|
+++
|
||||||
Never use curly bracket comments. During development, the "Block comment" functionality can be used instead. However, in production code, block comments are not recommended. Bad code
|
Never use curly bracket comments. During development, the "Block comment" functionality can be used instead. However, in production code, block comments are not recommended.
|
||||||
|
|
||||||
PeriodTxt: {Period}
|
|
||||||
|
|
||||||
|
Bad code
|
||||||
|
|
||||||
|
```al
|
||||||
|
PeriodTxt: {Period}
|
||||||
|
```
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
PeriodTxt: // Period
|
```al
|
||||||
|
PeriodTxt: // Period
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
PROCEDURE MATRIX\_OnAfterGetRecord@10(MATRIX\_ColumnOrdinal : Integer);
|
```al
|
||||||
BEGIN
|
PROCEDURE MATRIX_OnAfterGetRecord@10(MATRIX_ColumnOrdinal : Integer);
|
||||||
|
BEGIN
|
||||||
{
|
{
|
||||||
IF ShowColumnName THEN
|
IF ShowColumnName THEN
|
||||||
MatrixHeader := MatrixRecords\[MATRIX\_ColumnOrdinal\].Name
|
MatrixHeader := MatrixRecords[MATRIX_ColumnOrdinal].Name
|
||||||
ELSE
|
ELSE
|
||||||
MatrixHeader := MatrixRecords\[MATRIX\_ColumnOrdinal\].Code;
|
MatrixHeader := MatrixRecords[MATRIX_ColumnOrdinal].Code;
|
||||||
}
|
}
|
||||||
MatrixRecord := MatrixRecords\[MATRIX\_ColumnOrdinal\];
|
MatrixRecord := MatrixRecords[MATRIX_ColumnOrdinal];
|
||||||
AnalysisValue := CalcAmt(ValueType,TRUE);
|
AnalysisValue := CalcAmt(ValueType,TRUE);
|
||||||
MATRIX\_CellData\[MATRIX\_ColumnOrdinal\] := AnalysisValue;
|
MATRIX_CellData[MATRIX_ColumnOrdinal] := AnalysisValue;
|
||||||
END;
|
END;
|
||||||
|
```
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
PROCEDURE MATRIX\_OnAfterGetRecord@10(MATRIX\_ColumnOrdinal : Integer);
|
```al
|
||||||
BEGIN
|
PROCEDURE MATRIX_OnAfterGetRecord@10(MATRIX_ColumnOrdinal : Integer);
|
||||||
MatrixRecord := MatrixRecords\[MATRIX\_ColumnOrdinal\];
|
BEGIN
|
||||||
|
MatrixRecord := MatrixRecords[MATRIX_ColumnOrdinal];
|
||||||
AnalysisValue := CalcAmt(ValueType,TRUE);
|
AnalysisValue := CalcAmt(ValueType,TRUE);
|
||||||
MATRIX\_CellData\[MATRIX\_ColumnOrdinal\] := AnalysisValue;
|
MATRIX_CellData[MATRIX_ColumnOrdinal] := AnalysisValue;
|
||||||
END;
|
END;
|
||||||
|
```
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,16 @@ title = "Comment Spacing"
|
||||||
weight = 360
|
weight = 360
|
||||||
+++
|
+++
|
||||||
Always start comments with // followed by one space character.
|
Always start comments with // followed by one space character.
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
RowNo += 1000; //Move way below the budget
|
```al
|
||||||
|
RowNo += 1000; //Move way below the budget
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
RowNo += 1000; // Move way below the budget
|
```al
|
||||||
|
RowNo += 1000; // Move way below the budget
|
||||||
|
```
|
||||||
|
|
|
||||||
|
|
@ -3,19 +3,24 @@ title = "END ELSE Pair"
|
||||||
weight = 540
|
weight = 540
|
||||||
+++
|
+++
|
||||||
The END ELSE pair should always appear on the same line.
|
The END ELSE pair should always appear on the same line.
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
IF OppEntry.FIND('-') THEN
|
```al
|
||||||
|
IF OppEntry.FIND('-') THEN
|
||||||
IF SalesCycleStage.FIND('-') THEN BEGIN
|
IF SalesCycleStage.FIND('-') THEN BEGIN
|
||||||
...
|
...
|
||||||
END
|
END
|
||||||
ELSE
|
ELSE
|
||||||
...
|
...
|
||||||
|
```
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
IF OppEntry.FIND('-') THEN
|
```al
|
||||||
|
IF OppEntry.FIND('-') THEN
|
||||||
IF SalesCycleStage.FIND('-') THEN BEGIN
|
IF SalesCycleStage.FIND('-') THEN BEGIN
|
||||||
|
...
|
||||||
|
END ELSE
|
||||||
...
|
...
|
||||||
END ELSE
|
```
|
||||||
...
|
|
||||||
|
|
@ -3,82 +3,110 @@ title = "Indentation"
|
||||||
weight = 650
|
weight = 650
|
||||||
+++
|
+++
|
||||||
In general, use an indentation of two space characters. Logical expressions in the IF, WHILE, and UNTIL parts are indented at least 3, 6, and 6 spaces respectively.
|
In general, use an indentation of two space characters. Logical expressions in the IF, WHILE, and UNTIL parts are indented at least 3, 6, and 6 spaces respectively.
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
IF GLSetup."Unrealized VAT" OR
|
```al
|
||||||
(GLSetup."Prepayment Unrealized VAT" AND NewCVLedgEntryBuf.Prepayment)
|
IF GLSetup."Unrealized VAT" OR
|
||||||
|
(GLSetup."Prepayment Unrealized VAT" AND NewCVLedgEntryBuf.Prepayment)
|
||||||
Good code
|
```
|
||||||
|
|
||||||
IF GLSetup."Unrealized VAT" OR
|
Good code
|
||||||
|
|
||||||
|
```al
|
||||||
|
IF GLSetup."Unrealized VAT" OR
|
||||||
(GLSetup."Prepayment Unrealized VAT" AND NewCVLedgEntryBuf.Prepayment)
|
(GLSetup."Prepayment Unrealized VAT" AND NewCVLedgEntryBuf.Prepayment)
|
||||||
|
```
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
IF GenJnlLine."Account No." <\> ICPartner.Code THEN
|
```al
|
||||||
ICPartner.GET("Account No.");
|
IF GenJnlLine."Account No." <> ICPartner.Code THEN
|
||||||
IF GenJnlLine.Amount \> 0 THEN BEGIN
|
ICPartner.GET("Account No.");
|
||||||
|
IF GenJnlLine.Amount \> 0 THEN BEGIN
|
||||||
...
|
...
|
||||||
|
```
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
IF GenJnlLine."Account No." <\> ICPartner.Code THEN
|
```al
|
||||||
ICPartner.GET("Account No.");
|
IF GenJnlLine."Account No." <> ICPartner.Code THEN
|
||||||
IF GenJnlLine.Amount \> 0 THEN BEGIN
|
ICPartner.GET("Account No.");
|
||||||
...
|
IF GenJnlLine.Amount > 0 THEN BEGIN
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
Dialog.OPEN(WindowTxt +
|
```al
|
||||||
'@1@@@@@@@@@@@@@@@@@@@@@@@');
|
Dialog.OPEN(WindowTxt +
|
||||||
|
'@1@@@@@@@@@@@@@@@@@@@@@@@');
|
||||||
|
```
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
Dialog.OPEN(
|
```al
|
||||||
|
Dialog.OPEN(
|
||||||
WindowTxt +
|
WindowTxt +
|
||||||
'@1@@@@@@@@@@@@@@@@@@@@@@@');
|
'@1@@@@@@@@@@@@@@@@@@@@@@@');
|
||||||
|
```
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
TempOldCustLedgEntry.DELETE;
|
```al
|
||||||
// Find the next old entry for application of the new entry
|
TempOldCustLedgEntry.DELETE;
|
||||||
|
// Find the next old entry for application of the new entry
|
||||||
|
```
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
TempOldCustLedgEntry.DELETE;
|
```al
|
||||||
// Find the next old entry for application of the new entry
|
TempOldCustLedgEntry.DELETE;
|
||||||
|
// Find the next old entry for application of the new entry
|
||||||
|
```
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
IF NOT ("Applies-to Doc. Type" IN
|
```al
|
||||||
\["Applies-to Doc. Type"::Receipt,
|
IF NOT ("Applies-to Doc. Type" IN
|
||||||
"Applies-to Doc. Type"::"Return Shipment"\])
|
["Applies-to Doc. Type"::Receipt,
|
||||||
|
"Applies-to Doc. Type"::"Return Shipment"])
|
||||||
|
```
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
IF NOT ("Applies-to Doc. Type" IN
|
```al
|
||||||
\["Applies-to Doc. Type"::Receipt,
|
IF NOT ("Applies-to Doc. Type" IN
|
||||||
"Applies-to Doc. Type"::"Return Shipment"\])
|
["Applies-to Doc. Type"::Receipt,
|
||||||
|
"Applies-to Doc. Type"::"Return Shipment"])
|
||||||
|
```
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
WHILE (RemAmt \> 0) OR
|
```al
|
||||||
(RemAmtLCY \> 0)
|
WHILE (RemAmt > 0) OR
|
||||||
DO
|
(RemAmtLCY > 0)
|
||||||
|
DO
|
||||||
|
```
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
WHILE (RemAmt \> 0) OR
|
```al
|
||||||
(RemAmtLCY \> 0)
|
WHILE (RemAmt > 0) OR
|
||||||
DO
|
(RemAmtLCY > 0)
|
||||||
|
DO
|
||||||
|
```
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
UNTIL (RemAmt \> 0) AND
|
```al
|
||||||
(RemAmtLCY \> 0);
|
UNTIL (RemAmt > 0) AND
|
||||||
|
(RemAmtLCY > 0);
|
||||||
|
```
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
UNTIL (RemAmt \> 0) AND
|
```al
|
||||||
(RemAmtLCY \> 0)
|
UNTIL (RemAmt > 0) AND
|
||||||
|
(RemAmtLCY > 0)
|
||||||
|
```
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,19 @@
|
||||||
title = "Keyword Pairs - Indentation"
|
title = "Keyword Pairs - Indentation"
|
||||||
weight = 730
|
weight = 730
|
||||||
+++
|
+++
|
||||||
The IF..THEN pair, WHILE..DO pair, and FOR..DO pair must appear on the same line or the same level of indentation. Bad code
|
The IF..THEN pair, WHILE..DO pair, and FOR..DO pair must appear on the same line or the same level of indentation.
|
||||||
|
|
||||||
IF (x = y) AND
|
Bad code
|
||||||
(a = b) THEN
|
|
||||||
|
```al
|
||||||
|
IF (x = y) AND
|
||||||
|
(a = b) THEN
|
||||||
|
```
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
IF (x = y) AND
|
```al
|
||||||
(a = b)
|
IF (x = y) AND
|
||||||
THEN
|
(a = b)
|
||||||
|
THEN
|
||||||
|
```
|
||||||
|
|
|
||||||
|
|
@ -2,19 +2,25 @@
|
||||||
title = "Line Start Keywords"
|
title = "Line Start Keywords"
|
||||||
weight = 740
|
weight = 740
|
||||||
+++
|
+++
|
||||||
The END, IF, REPEAT, FOR, WHILE, ELSE and CASE statement should always start a line. Bad code
|
The END, IF, REPEAT, FOR, WHILE, ELSE and CASE statement should always start a line.
|
||||||
|
|
||||||
IF IsContactName THEN ValidateContactName
|
Bad code
|
||||||
ELSE IF IsSalespersonCode THEN ValidateSalespersonCode
|
|
||||||
|
```al
|
||||||
|
IF IsContactName THEN ValidateContactName
|
||||||
|
ELSE IF IsSalespersonCode THEN ValidateSalespersonCode
|
||||||
ELSE IF IsSalesCycleCode THEN ValidatSalesCycleCode;
|
ELSE IF IsSalesCycleCode THEN ValidatSalesCycleCode;
|
||||||
|
```
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
IF IsContactName THEN
|
```al
|
||||||
ValidateContactName
|
IF IsContactName THEN
|
||||||
ELSE
|
ValidateContactName
|
||||||
IF IsSalespersonCode THEN
|
ELSE
|
||||||
|
IF IsSalespersonCode THEN
|
||||||
ValidateSalespersonCode
|
ValidateSalespersonCode
|
||||||
ELSE
|
ELSE
|
||||||
IF IsSalesCycleCode THEN
|
IF IsSalesCycleCode THEN
|
||||||
ValidatSalesCycleCode;
|
ValidatSalesCycleCode;
|
||||||
|
```
|
||||||
|
|
|
||||||
|
|
@ -3,13 +3,18 @@ title = "Lonely Repeat"
|
||||||
weight = 760
|
weight = 760
|
||||||
+++
|
+++
|
||||||
The REPEAT statement should always be alone on a line.
|
The REPEAT statement should always be alone on a line.
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
IF ReservEntry.FINDSET THEN REPEAT
|
```al
|
||||||
|
IF ReservEntry.FINDSET THEN REPEAT
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
IF ReservEntry.FINDSET THEN
|
```al
|
||||||
REPEAT
|
IF ReservEntry.FINDSET THEN
|
||||||
|
REPEAT
|
||||||
|
```
|
||||||
|
|
@ -3,12 +3,16 @@ title = "Named Invocations"
|
||||||
weight = 830
|
weight = 830
|
||||||
+++
|
+++
|
||||||
When calling an object statically use the name, not the number
|
When calling an object statically use the name, not the number
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
PAGE.RUNMODAL(525,SalesShptLine)
|
```al
|
||||||
|
PAGE.RUNMODAL(525,SalesShptLine)
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
PAGE.RUNMODAL(PAGE::"Posted Sales Shipment Lines",SalesShptLine)
|
```al
|
||||||
|
PAGE.RUNMODAL(PAGE::"Posted Sales Shipment Lines",SalesShptLine)
|
||||||
|
```
|
||||||
|
|
|
||||||
|
|
@ -3,19 +3,24 @@ title = "Nested WITHs"
|
||||||
weight = 850
|
weight = 850
|
||||||
+++
|
+++
|
||||||
Do not nest WITHs that reference different types of objects.
|
Do not nest WITHs that reference different types of objects.
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
WITH PostedWhseShptLine DO BEGIN
|
```al
|
||||||
...
|
WITH PostedWhseShptLine DO BEGIN
|
||||||
WITH ItemLedgEntry DO
|
...
|
||||||
|
WITH ItemLedgEntry DO
|
||||||
InsertBufferRec(...,"Serial No.","Lot No.",...);
|
InsertBufferRec(...,"Serial No.","Lot No.",...);
|
||||||
...
|
...
|
||||||
END;
|
END;
|
||||||
|
```
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
WITH PostedWhseShptLine DO BEGIN
|
```al
|
||||||
...
|
WITH PostedWhseShptLine DO BEGIN
|
||||||
InsertBufferRec(...,ItemLedgEntry."Serial No.",ItemLedgEntry."Lot No.",...);
|
...
|
||||||
...
|
InsertBufferRec(...,ItemLedgEntry."Serial No.",ItemLedgEntry."Lot No.",...);
|
||||||
END;
|
...
|
||||||
|
END;
|
||||||
|
```
|
||||||
|
|
|
||||||
|
|
@ -3,26 +3,34 @@ title = "One Statement Per Line"
|
||||||
weight = 910
|
weight = 910
|
||||||
+++
|
+++
|
||||||
A line of code should not have more than one statement.
|
A line of code should not have more than one statement.
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
IF OppEntry.FIND('-') THEN EXIT
|
```al
|
||||||
|
IF OppEntry.FIND('-') THEN EXIT
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
IF OppEntry.FIND('-') THEN
|
```al
|
||||||
EXIT
|
IF OppEntry.FIND('-') THEN
|
||||||
|
EXIT
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
TotalCost += Cost; TotalAmt += Amt;
|
```al
|
||||||
|
TotalCost += Cost; TotalAmt += Amt;
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
TotalCost += Cost;
|
```al
|
||||||
TotalAmt += Amt;
|
TotalCost += Cost;
|
||||||
|
TotalAmt += Amt;
|
||||||
|
```
|
||||||
|
|
|
||||||
|
|
@ -2,16 +2,22 @@
|
||||||
title = "Separate IF and ELSE"
|
title = "Separate IF and ELSE"
|
||||||
weight = 1050
|
weight = 1050
|
||||||
+++
|
+++
|
||||||
IF and ELSE statements should be on separate lines. Bad code
|
IF and ELSE statements should be on separate lines.
|
||||||
|
|
||||||
IF Atom\[i+1\] = '\>' THEN HasLogicalOperator := TRUE ELSE BEGIN
|
Bad code
|
||||||
|
|
||||||
|
```al
|
||||||
|
IF Atom[i+1] = '>' THEN HasLogicalOperator := TRUE ELSE BEGIN
|
||||||
...
|
...
|
||||||
END;
|
END;
|
||||||
|
```
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
IF Atom\[i+1\] = '\>' THEN
|
```al
|
||||||
|
IF Atom[i+1] = '>' THEN
|
||||||
HasLogicalOperator := TRUE
|
HasLogicalOperator := TRUE
|
||||||
ELSE BEGIN
|
ELSE BEGIN
|
||||||
...
|
...
|
||||||
END;
|
END;
|
||||||
|
```
|
||||||
|
|
|
||||||
|
|
@ -3,36 +3,44 @@ title = "Spacing Binary Operators"
|
||||||
weight = 1120
|
weight = 1120
|
||||||
+++
|
+++
|
||||||
There must be exactly one space character on each side of a binary operator such as = + - AND OR =. The parameter comma operator however, should have no spaces.
|
There must be exactly one space character on each side of a binary operator such as = + - AND OR =. The parameter comma operator however, should have no spaces.
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
"Line Discount %" := "Line Discount Amount"/"Line Value"\*100
|
```al
|
||||||
|
"Line Discount %" := "Line Discount Amount"/"Line Value"*100
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
"Line Discount %" := "Line Discount Amount" / "Line Value" \* 100;
|
```al
|
||||||
|
"Line Discount %" := "Line Discount Amount" / "Line Value" * 100;
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
StartDate := CALCDATE('<+'+FORMAT(Days + i)+'D\>', StartDate);
|
```al
|
||||||
|
StartDate := CALCDATE('<+'+FORMAT(Days + i)+'D>', StartDate);
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
StartDate := CALCDATE('<+' + FORMAT(Days + i) + 'D\>',StartDate);
|
```al
|
||||||
|
StartDate := CALCDATE('<+' + FORMAT(Days + i) + 'D>',StartDate);
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
StartDate := 0D; // Initialize
|
```al
|
||||||
|
StartDate := 0D; // Initialize
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
StartDate := 0D; // Initialize
|
```al
|
||||||
|
StartDate := 0D; // Initialize
|
||||||
|
```
|
||||||
|
|
|
||||||
|
|
@ -3,36 +3,44 @@ title = "Spacing Brackets and ::"
|
||||||
weight = 1130
|
weight = 1130
|
||||||
+++
|
+++
|
||||||
There must be no spaces characters before and after \[\] dimension brackets symbols or :: option symbols.
|
There must be no spaces characters before and after \[\] dimension brackets symbols or :: option symbols.
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
A\[i\] \[j\] := Amt;
|
```al
|
||||||
|
A[i] [j] := Amt;
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
A\[i\]\[j\] := Amt;
|
```al
|
||||||
|
A[i][j] := Amt;
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
"Currency Exchange Rate"."Fix Exchange Rate Amount" :: Currency:
|
```al
|
||||||
|
"Currency Exchange Rate"."Fix Exchange Rate Amount" :: Currency:
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
"Currency Exchange Rate"."Fix Exchange Rate Amount"::Currency:
|
```al
|
||||||
|
"Currency Exchange Rate"."Fix Exchange Rate Amount"::Currency:
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
IF FIND (Which) THEN
|
```al
|
||||||
|
IF FIND (Which) THEN
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
IF FIND(Which) THEN
|
```al
|
||||||
|
IF FIND(Which) THEN
|
||||||
|
```
|
||||||
|
|
@ -3,24 +3,30 @@ title = "Spacing Unary Operators"
|
||||||
weight = 1140
|
weight = 1140
|
||||||
+++
|
+++
|
||||||
There must be no space between a unary operator and its argument (except for the NOT keyword).
|
There must be no space between a unary operator and its argument (except for the NOT keyword).
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
IF NOT(Type = Type::Item) THEN
|
```al
|
||||||
|
IF NOT(Type = Type::Item) THEN
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
IF NOT (Type = Type::Item) THEN
|
```al
|
||||||
|
IF NOT (Type = Type::Item) THEN
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
DiscAmt := - "Discount Amount";
|
```al
|
||||||
|
DiscAmt := - "Discount Amount";
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
DiscAmt := -"Discount Amount";
|
```al
|
||||||
|
DiscAmt := -"Discount Amount";
|
||||||
|
```
|
||||||
|
|
|
||||||
|
|
@ -2,23 +2,30 @@
|
||||||
title = "Temporary Variable Naming"
|
title = "Temporary Variable Naming"
|
||||||
weight = 1200
|
weight = 1200
|
||||||
+++
|
+++
|
||||||
The name of a temporary variable must be prefixed with the word Temp and not otherwise. Bad code
|
The name of a temporary variable must be prefixed with the word Temp and not otherwise.
|
||||||
|
|
||||||
JobWIPBuffer@1002 : TEMPORARY Record 1018;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Good code
|
|
||||||
|
|
||||||
TempJobWIPBuffer@1002 : TEMPORARY Record 1018;
|
|
||||||
|
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
TempJobWIPBuffer@1002 : Record 1018;
|
```al
|
||||||
|
JobWIPBuffer@1002 : TEMPORARY Record 1018;
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
CopyOfJobWIPBuffer@1002 : Record 1018;
|
```al
|
||||||
|
TempJobWIPBuffer@1002 : TEMPORARY Record 1018;
|
||||||
|
```
|
||||||
|
|
||||||
|
Bad code
|
||||||
|
|
||||||
|
```al
|
||||||
|
TempJobWIPBuffer@1002 : Record 1018;
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
Good code
|
||||||
|
|
||||||
|
```al
|
||||||
|
CopyOfJobWIPBuffer@1002 : Record 1018;
|
||||||
|
```
|
||||||
|
|
|
||||||
|
|
@ -3,88 +3,113 @@ title = "TextConst Suffixes"
|
||||||
weight = 1210
|
weight = 1210
|
||||||
+++
|
+++
|
||||||
TextConst variable names should have a suffix (an approved three-letter suffix: Msg, Tok, Err, Qst, Lbl, Txt) describing usage.
|
TextConst variable names should have a suffix (an approved three-letter suffix: Msg, Tok, Err, Qst, Lbl, Txt) describing usage.
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
CannotDeleteLine@1005 : TextConst 'ENU=You cannot delete this line because one or more rating values exists.';
|
```al
|
||||||
...
|
CannotDeleteLine@1005 : TextConst 'ENU=You cannot delete this line because one or more rating values exists.';
|
||||||
ERROR(CannotDeleteLine,TABLECAPTION);
|
...
|
||||||
|
ERROR(CannotDeleteLine,TABLECAPTION);
|
||||||
|
```
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
CannotDeleteLineErr@1005 : TextConst 'ENU=You cannot delete this line because one or more rating values exists.';
|
```al
|
||||||
...
|
CannotDeleteLineErr@1005 : TextConst 'ENU=You cannot delete this line because one or more rating values exists.';
|
||||||
ERROR(CannotDeleteLineErr,TABLECAPTION);
|
...
|
||||||
|
ERROR(CannotDeleteLineErr,TABLECAPTION);
|
||||||
|
```
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
Text000@1011 : TextConst 'ENU="has been changed (initial a %1: %2= %3, %4= %5)"';
|
```al
|
||||||
...
|
Text000@1011 : TextConst 'ENU="has been changed (initial a %1: %2= %3, %4= %5)"';
|
||||||
SalesLine.FIELDERROR(Type,STRSUBSTNO(Text000,...);
|
...
|
||||||
...
|
SalesLine.FIELDERROR(Type,STRSUBSTNO(Text000,...);
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
TypeHasBeenChangedErr@1011 : TextConst 'ENU="has been changed (initial a %1: %2= %3, %4= %5)"';
|
```al
|
||||||
...
|
TypeHasBeenChangedErr@1011 : TextConst 'ENU="has been changed (initial a %1: %2= %3, %4= %5)"';
|
||||||
SalesLine.FIELDERROR(Type,STRSUBSTNO(TypeHasBeenChangedErr,...);
|
...
|
||||||
...
|
SalesLine.FIELDERROR(Type,STRSUBSTNO(TypeHasBeenChangedErr,...);
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
Text004@1004 : TextConst 'ENU=Indenting the Job Tasks \#1\#\#\#\#\#\#\#\#\#\#.';
|
```al
|
||||||
...
|
Text004@1004 : TextConst 'ENU=Indenting the Job Tasks \#1\#\#\#\#\#\#\#\#\#\#.';
|
||||||
Window@1007 : Dialog;
|
...
|
||||||
...
|
Window@1007 : Dialog;
|
||||||
|
...
|
||||||
Window.OPEN(Text004);
|
Window.OPEN(Text004);
|
||||||
|
```
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
IndentingMsg@1004 : TextConst 'ENU=Indenting the Job Tasks \#1\#\#\#\#\#\#\#\#\#\#.';
|
```al
|
||||||
...
|
IndentingMsg@1004 : TextConst 'ENU=Indenting the Job Tasks \#1\#\#\#\#\#\#\#\#\#\#.';
|
||||||
Window@1007 : Dialog;
|
...
|
||||||
...
|
Window@1007 : Dialog;
|
||||||
|
...
|
||||||
Window.OPEN(IndentingMsg);
|
Window.OPEN(IndentingMsg);
|
||||||
|
```
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
Text002@1005 : TextConst 'ENU=You cannot delete a %1 that is used in one or more setup windows.\\ Do you want to open the G/L Account No. Where-Used List Window?';
|
```al
|
||||||
...
|
Text002@1005 : TextConst 'ENU=You cannot delete a %1 that is used in one or more setup windows.\\ Do you want to open the G/L Account No. Where-Used List Window?';
|
||||||
IF CONFIRM(Text002,TRUE,GLAcc.TABLECAPTION) THEN
|
...
|
||||||
|
IF CONFIRM(Text002,TRUE,GLAcc.TABLECAPTION) THEN
|
||||||
|
```
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
OpenWhereUsedWindowQst@1005 : TextConst 'ENU=You cannot delete a %1 that is used in one or more setup windows.\\ Do you want to open the G/L Account No. Where-Used List Window?';
|
```al
|
||||||
...
|
OpenWhereUsedWindowQst@1005 : TextConst 'ENU=You cannot delete a %1 that is used in one or more setup windows.\\ Do you want to open the G/L Account No. Where-Used List Window?';
|
||||||
IF CONFIRM(OpenWhereUsedWindowQst,TRUE,GLAcc.TABLECAPTION) THEN
|
...
|
||||||
|
IF CONFIRM(OpenWhereUsedWindowQst,TRUE,GLAcc.TABLECAPTION) THEN
|
||||||
|
```
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
Selection := STRMENU(Text003,2);
|
```al
|
||||||
...
|
Selection := STRMENU(Text003,2);
|
||||||
Text003@1002 : TextConst 'ENU=&Copy dimensions from BOM,&Retrieve dimensions from components';
|
...
|
||||||
|
Text003@1002 : TextConst 'ENU=&Copy dimensions from BOM,&Retrieve dimensions from components';
|
||||||
|
```
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
|
```al
|
||||||
Selection := STRMENU(CopyFromQst,2);
|
Selection := STRMENU(CopyFromQst,2);
|
||||||
...
|
...
|
||||||
CopyFromQst@1002 : TextConst 'ENU=&Copy dimensions from BOM,&Retrieve dimensions from components';
|
CopyFromQst@1002 : TextConst 'ENU=&Copy dimensions from BOM,&Retrieve dimensions from components';
|
||||||
|
```
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
DATASET
|
```al
|
||||||
{
|
DATASET
|
||||||
...
|
{
|
||||||
{ 1 ;1 ;Column ;Chart\_of\_AccountsCaption;
|
...
|
||||||
SourceExpr=Chart\_of\_AccountsCaption }
|
{ 1 ;1 ;Column ;Chart_of_AccountsCaption;
|
||||||
...
|
SourceExpr=Chart_of_AccountsCaption }
|
||||||
Chart\_of\_AccountsCaption@9647 : TextConst 'ENU=Chart of Accounts';
|
...
|
||||||
|
Chart_of_AccountsCaption@9647 : TextConst 'ENU=Chart of Accounts';
|
||||||
|
```
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
DATASET
|
```al
|
||||||
{
|
DATASET
|
||||||
...
|
{
|
||||||
{ 1 ;1 ;Column ;Chart\_of\_AccountsCaption;
|
...
|
||||||
SourceExpr=ChartOfAccountsLbl }
|
{ 1 ;1 ;Column ;Chart_of_AccountsCaption;
|
||||||
...
|
SourceExpr=ChartOfAccountsLbl }
|
||||||
ChartOfAccountsLbl@9647 : TextConst 'ENU=Chart of Accounts';
|
...
|
||||||
|
ChartOfAccountsLbl@9647 : TextConst 'ENU=Chart of Accounts';
|
||||||
|
```
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,17 @@ title = "Unary Operator Line End"
|
||||||
weight = 1250
|
weight = 1250
|
||||||
+++
|
+++
|
||||||
Do not end a line with unary operator.
|
Do not end a line with unary operator.
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
"Quantity Handled (Base)" := -
|
```al
|
||||||
|
"Quantity Handled (Base)" := -
|
||||||
"Quantity Handled (Base)");
|
"Quantity Handled (Base)");
|
||||||
|
```
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
"Quantity Handled (Base)" :=
|
```al
|
||||||
|
"Quantity Handled (Base)" :=
|
||||||
- "Quantity Handled (Base)");
|
- "Quantity Handled (Base)");
|
||||||
|
```
|
||||||
|
|
|
||||||
|
|
@ -3,26 +3,30 @@ title = "Unnecessary Compound Parenthesis"
|
||||||
weight = 1260
|
weight = 1260
|
||||||
+++
|
+++
|
||||||
Use parenthesis only to enclose compound expressions inside compound expressions.
|
Use parenthesis only to enclose compound expressions inside compound expressions.
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
IF ("Costing Method" = "Costing Method"::Standard) THEN
|
```al
|
||||||
|
IF ("Costing Method" = "Costing Method"::Standard) THEN
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
IF "Costing Method" = "Costing Method"::Standard THEN
|
```al
|
||||||
|
IF "Costing Method" = "Costing Method"::Standard THEN
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
####
|
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
ProfitPct = -(Profit) / CostAmt \* 100;
|
```al
|
||||||
|
ProfitPct = -(Profit) / CostAmt * 100;
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
ProfitPct = -Profit / CostAmt \* 100;
|
```al
|
||||||
|
ProfitPct = -Profit / CostAmt * 100;
|
||||||
|
```
|
||||||
|
|
|
||||||
|
|
@ -2,15 +2,21 @@
|
||||||
title = "Unnecessary ELSE"
|
title = "Unnecessary ELSE"
|
||||||
weight = 1270
|
weight = 1270
|
||||||
+++
|
+++
|
||||||
ELSE should not be used when the last action in the THEN part is an EXIT, BREAK, SKIP, QUIT, ERROR. Bad code
|
ELSE should not be used when the last action in the THEN part is an EXIT, BREAK, SKIP, QUIT, ERROR.
|
||||||
|
|
||||||
IF IsAdjmtBinCodeChanged THEN
|
Bad code
|
||||||
|
|
||||||
|
```al
|
||||||
|
IF IsAdjmtBinCodeChanged THEN
|
||||||
ERROR(AdjmtBinCodeChangeNotAllowedErr,...)
|
ERROR(AdjmtBinCodeChangeNotAllowedErr,...)
|
||||||
ELSE
|
ELSE
|
||||||
ERROR(BinCodeChangeNotAllowedErr,...);
|
ERROR(BinCodeChangeNotAllowedErr,...);
|
||||||
|
```
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
IF IsAdjmtBinCodeChanged THEN
|
```al
|
||||||
|
IF IsAdjmtBinCodeChanged THEN
|
||||||
ERROR(AdjmtBinCodeChangeNotAllowedErr,...)
|
ERROR(AdjmtBinCodeChangeNotAllowedErr,...)
|
||||||
ERROR(BinCodeChangeNotAllowedErr,...);
|
ERROR(BinCodeChangeNotAllowedErr,...);
|
||||||
|
```
|
||||||
|
|
|
||||||
|
|
@ -3,24 +3,30 @@ title = "Unnecessary Function Parenthesis"
|
||||||
weight = 1280
|
weight = 1280
|
||||||
+++
|
+++
|
||||||
Do not use parenthesis in a function call if the function does not have any parameters.
|
Do not use parenthesis in a function call if the function does not have any parameters.
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
IF ReservMgt.IsPositive() THEN
|
```al
|
||||||
|
IF ReservMgt.IsPositive() THEN
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
IF ReservMgt.IsPositive THEN
|
```al
|
||||||
|
IF ReservMgt.IsPositive THEN
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
IF ChangeStatusForm.RUNMODAL() <\> ACTION::Yes THEN
|
```al
|
||||||
|
IF ChangeStatusForm.RUNMODAL() <> ACTION::Yes THEN
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
IF ChangeStatusForm.RUNMODAL <\> ACTION::Yes THEN
|
```al
|
||||||
|
IF ChangeStatusForm.RUNMODAL <> ACTION::Yes THEN
|
||||||
|
```
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,17 @@
|
||||||
title = "Unnecessary Separators"
|
title = "Unnecessary Separators"
|
||||||
weight = 1290
|
weight = 1290
|
||||||
+++
|
+++
|
||||||
There should be no unnecessary separators. Bad code
|
There should be no unnecessary separators.
|
||||||
|
|
||||||
IF Customer.FINDFIRST THEN;;
|
Bad code
|
||||||
|
|
||||||
|
```al
|
||||||
|
IF Customer.FINDFIRST THEN;;
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
IF Customer.FINDFIRST THEN;
|
```al
|
||||||
|
IF Customer.FINDFIRST THEN;
|
||||||
|
```
|
||||||
|
|
|
||||||
|
|
@ -3,24 +3,30 @@ title = "Unnecessary TRUE/FALSE"
|
||||||
weight = 1300
|
weight = 1300
|
||||||
+++
|
+++
|
||||||
Do not use TRUE or FALSE keywords unnecessarily if the expression is already an logical expression.
|
Do not use TRUE or FALSE keywords unnecessarily if the expression is already an logical expression.
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
IF IsPositive() = TRUE THEN
|
```al
|
||||||
|
IF IsPositive() = TRUE THEN
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
IF IsPositive THEN
|
```al
|
||||||
|
IF IsPositive THEN
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
IF Complete <\> TRUE THEN
|
```
|
||||||
|
IF Complete <> TRUE THEN
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
IF NOT Complete THEN
|
```al
|
||||||
|
IF NOT Complete THEN
|
||||||
|
```
|
||||||
|
|
|
||||||
|
|
@ -3,30 +3,37 @@ title = "Variable Already Scoped"
|
||||||
weight = 1400
|
weight = 1400
|
||||||
+++
|
+++
|
||||||
Do not use scope ''.'' qualifier unnecessarily when a variable is already implicitly or explicitly scoped. It keeps the code simpler.
|
Do not use scope ''.'' qualifier unnecessarily when a variable is already implicitly or explicitly scoped. It keeps the code simpler.
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
ReturnRcptHeader.SETRANGE(ReturnRcptHeader."Return Order No.","Document No.");
|
```al
|
||||||
|
ReturnRcptHeader.SETRANGE(ReturnRcptHeader."Return Order No.","Document No.");
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
ReturnRcptHeader.SETRANGE("Return Order No.","Document No.");
|
```al
|
||||||
|
ReturnRcptHeader.SETRANGE("Return Order No.","Document No.");
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
WITH ChangeLogSetupTable DO BEGIN
|
```al
|
||||||
|
WITH ChangeLogSetupTable DO BEGIN
|
||||||
...
|
...
|
||||||
IF ChangeLogSetupTable.DELETE THEN
|
IF ChangeLogSetupTable.DELETE THEN
|
||||||
...
|
...
|
||||||
END;
|
END;
|
||||||
|
```
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
WITH ChangeLogSetupTable DO BEGIN
|
```al
|
||||||
|
WITH ChangeLogSetupTable DO BEGIN
|
||||||
...
|
...
|
||||||
IF DELETE THEN
|
IF DELETE THEN
|
||||||
...
|
...
|
||||||
END;
|
END;
|
||||||
|
```
|
||||||
|
|
|
||||||
|
|
@ -9,48 +9,61 @@ A variable must begin with a capital letter.
|
||||||
Blanks, periods, and other characters (such as parentheses) that would make quotation marks around a variable necessary must be omitted.
|
Blanks, periods, and other characters (such as parentheses) that would make quotation marks around a variable necessary must be omitted.
|
||||||
|
|
||||||
If a variable is a compound of two or more words or abbreviations, each word or abbreviation should begin with a capital letter.
|
If a variable is a compound of two or more words or abbreviations, each word or abbreviation should begin with a capital letter.
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
...
|
```al
|
||||||
|
...
|
||||||
WIPBuffer@1002 : Record 1018
|
WIPBuffer@1002 : Record 1018
|
||||||
...
|
...
|
||||||
OBJECT Table Job WIP Buffer
|
OBJECT Table Job WIP Buffer
|
||||||
|
```
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
...
|
```al
|
||||||
|
...
|
||||||
JobWIPBuffer@1002 : Record 1018
|
JobWIPBuffer@1002 : Record 1018
|
||||||
...
|
...
|
||||||
OBJECT Table Job WIP Buffer
|
OBJECT Table Job WIP Buffer
|
||||||
|
```
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
...
|
```al
|
||||||
|
...
|
||||||
Postline@1004 : Codeunit 12;
|
Postline@1004 : Codeunit 12;
|
||||||
...
|
...
|
||||||
OBJECT Codeunit Gen. Jnl.-Post Line
|
OBJECT Codeunit Gen. Jnl.-Post Line
|
||||||
|
```
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
...
|
```al
|
||||||
|
...
|
||||||
GenJnlPostLine@1004 : Codeunit 12;
|
GenJnlPostLine@1004 : Codeunit 12;
|
||||||
...
|
...
|
||||||
OBJECT Codeunit Gen. Jnl.-Post Line
|
OBJECT Codeunit Gen. Jnl.-Post Line
|
||||||
|
```
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
LOCAL PROCEDURE HandleCustDebitCredit@17(...;"Amount (LCY)"@1001 : Decimal;...);
|
```al
|
||||||
BEGIN
|
LOCAL PROCEDURE HandleCustDebitCredit@17(...;"Amount (LCY)"@1001 : Decimal;...);
|
||||||
|
BEGIN
|
||||||
IF ((... ("Amount (LCY)" \> 0)) ...) OR
|
IF ((... ("Amount (LCY)" \> 0)) ...) OR
|
||||||
((... ("Amount (LCY)" < 0)) ...)
|
((... ("Amount (LCY)" < 0)) ...)
|
||||||
THEN BEGIN
|
THEN BEGIN
|
||||||
...
|
...
|
||||||
|
```
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
LOCAL PROCEDURE HandleCustDebitCredit@17(...;AmountLCY@1001 : Decimal;...);
|
```al
|
||||||
BEGIN
|
LOCAL PROCEDURE HandleCustDebitCredit@17(...;AmountLCY@1001 : Decimal;...);
|
||||||
|
BEGIN
|
||||||
IF ((... (AmountLCY \> 0)) ...) OR
|
IF ((... (AmountLCY \> 0)) ...) OR
|
||||||
((... (AmountLCY < 0)) ...)
|
((... (AmountLCY < 0)) ...)
|
||||||
THEN BEGIN
|
THEN BEGIN
|
||||||
...
|
...
|
||||||
|
```
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,18 @@
|
||||||
title = "Variables Declarations Order"
|
title = "Variables Declarations Order"
|
||||||
weight = 1430
|
weight = 1430
|
||||||
+++
|
+++
|
||||||
Variables declarations should be ordered by type. In general, object and complex variable types are listed first followed by simple variables. The order should be the same as the object list in the object designer for C/AL objects. Afterwards come the complex variables like RecordRef, .NET, FieldRef etc. At the end come all the simple data types in no particular order. Bad code
|
Variables declarations should be ordered by type. In general, object and complex variable types are listed first followed by simple variables. The order should be the same as the object list in the object designer for C/AL objects. Afterwards come the complex variables like RecordRef, .NET, FieldRef etc. At the end come all the simple data types in no particular order.
|
||||||
|
|
||||||
StartingDateFilter@1002 : Text\[30\];
|
Bad code
|
||||||
Vend@1003 : Record 23;
|
|
||||||
|
```al
|
||||||
|
StartingDateFilter@1002 : Text[30];
|
||||||
|
Vend@1003 : Record 23;
|
||||||
|
```
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
Vend@1003 : Record 23;
|
```al
|
||||||
StartingDateFilter@1002 : Text\[30\];
|
Vend@1003 : Record 23;
|
||||||
|
StartingDateFilter@1002 : Text[30];
|
||||||
|
```
|
||||||
|
|
|
||||||
|
|
@ -3,15 +3,20 @@ title = "Actions - Images"
|
||||||
weight = 200
|
weight = 200
|
||||||
+++
|
+++
|
||||||
All actions must have an image assigned to them.
|
All actions must have an image assigned to them.
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
{ 7 ;1 ;Action ;
|
```al
|
||||||
CaptionML=ENU=Customer - &Balance;
|
{ 7 ;1 ;Action ;
|
||||||
RunObject=Report 121 }
|
CaptionML=ENU=Customer - &Balance;
|
||||||
|
RunObject=Report 121 }
|
||||||
|
```
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
{ 7 ;1 ;Action ;
|
```al
|
||||||
CaptionML=ENU=Customer - &Balance;
|
{ 7 ;1 ;Action ;
|
||||||
RunObject=Report 121 }
|
CaptionML=ENU=Customer - &Balance;
|
||||||
Image=Report }
|
RunObject=Report 121 }
|
||||||
|
Image=Report }
|
||||||
|
```
|
||||||
|
|
|
||||||
|
|
@ -3,14 +3,19 @@ title = "CONFIRM"
|
||||||
weight = 380
|
weight = 380
|
||||||
+++
|
+++
|
||||||
Always end CONFIRM with a question mark.
|
Always end CONFIRM with a question mark.
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
ChangeAllOpenedEntriesQst@1000 : TextConst 'ENU=Do you want to change all open entries for every customer and vendor that are not blocked';
|
```al
|
||||||
...
|
ChangeAllOpenedEntriesQst@1000 : TextConst 'ENU=Do you want to change all open entries for every customer and vendor that are not blocked';
|
||||||
IF CONFIRM(ChangeAllOpenedEntriesQst,TRUE) THEN
|
...
|
||||||
|
IF CONFIRM(ChangeAllOpenedEntriesQst,TRUE) THEN
|
||||||
|
```
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
ChangeAllOpenedEntriesQst@1000 : TextConst 'ENU=Do you want to change all open entries for every customer and vendor that are not blocked?';
|
```al
|
||||||
...
|
ChangeAllOpenedEntriesQst@1000 : TextConst 'ENU=Do you want to change all open entries for every customer and vendor that are not blocked?';
|
||||||
IF CONFIRM(ChangeAllOpenedEntriesQst,TRUE) THEN
|
...
|
||||||
|
IF CONFIRM(ChangeAllOpenedEntriesQst,TRUE) THEN
|
||||||
|
```
|
||||||
|
|
|
||||||
|
|
@ -3,14 +3,19 @@ title = "FIELDERROR"
|
||||||
weight = 590
|
weight = 590
|
||||||
+++
|
+++
|
||||||
Never use FIELDERROR with a period as it is automatically inserted.
|
Never use FIELDERROR with a period as it is automatically inserted.
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
InvalidValue@1025 : TextConst 'ENU=is invalid.';
|
```al
|
||||||
...
|
InvalidValue@1025 : TextConst 'ENU=is invalid.';
|
||||||
Cust.FIELDERROR("No.",InvalidValue);
|
...
|
||||||
|
Cust.FIELDERROR("No.",InvalidValue);
|
||||||
|
```
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
InvalidValue@1025 : TextConst 'ENU=is invalid';
|
```al
|
||||||
...
|
InvalidValue@1025 : TextConst 'ENU=is invalid';
|
||||||
Cust.FIELDERROR("No.",InvalidValue);
|
...
|
||||||
|
Cust.FIELDERROR("No.",InvalidValue);
|
||||||
|
```
|
||||||
|
|
|
||||||
|
|
@ -3,14 +3,19 @@ title = "MESSAGE and ERROR"
|
||||||
weight = 790
|
weight = 790
|
||||||
+++
|
+++
|
||||||
Always end MESSAGE or ERROR with a period.
|
Always end MESSAGE or ERROR with a period.
|
||||||
|
|
||||||
Bad code
|
Bad code
|
||||||
|
|
||||||
CustIsBlockedErr@1025 : TextConst 'ENU=You cannot %1 this type of document when Customer %2 is blocked with type %3';
|
```al
|
||||||
...
|
CustIsBlockedErr@1025 : TextConst 'ENU=You cannot %1 this type of document when Customer %2 is blocked with type %3';
|
||||||
ERROR(CustIsBlockedErr,...);
|
...
|
||||||
|
ERROR(CustIsBlockedErr,...);
|
||||||
|
```
|
||||||
|
|
||||||
Good code
|
Good code
|
||||||
|
|
||||||
CustIsBlockedErr@1025 : TextConst 'ENU=You cannot %1 this type of document when Customer %2 is blocked with type %3.';
|
```al
|
||||||
...
|
CustIsBlockedErr@1025 : TextConst 'ENU=You cannot %1 this type of document when Customer %2 is blocked with type %3.';
|
||||||
ERROR(CustIsBlockedErr,...);
|
...
|
||||||
|
ERROR(CustIsBlockedErr,...);
|
||||||
|
```
|
||||||
|
|
|
||||||
|
|
@ -29,14 +29,14 @@ We are working on creating a set of rules, which would help keeping the content
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[anchor0]: /nav/w/designpatterns/74.no-series.aspx "No. Series"
|
[anchor0]: /navpatterns/1-patterns/no-series/ "No. Series"
|
||||||
[anchor1]: /nav/w/designpatterns/76.single-record-setup-table.aspx "Setup Table"
|
[anchor1]: /navpatterns/1-patterns/singleton/singleton-table/setup-table/ "Setup Table"
|
||||||
[anchor2]: /nav/w/designpatterns/117.hooks-pattern.aspx "Hooks"
|
[anchor2]: /navpatterns/1-patterns/hooks/ "Hooks"
|
||||||
[anchor3]: /nav/w/designpatterns/122.implementation-of-surrogate-keys-using-autoincrement-pattern.aspx
|
[anchor3]: /navpatterns/1-patterns/implementation-of-surrogate-keys-using-autoincrement-pattern/
|
||||||
[anchor4]: /nav/w/designpatterns/104.easy-update-of-setup-or-supplementary-information.aspx
|
[anchor4]: /navpatterns/1-patterns/easy-update-of-setup-or-supplementary-information/
|
||||||
[anchor5]: /nav/w/designpatterns/155.totals-and-discounts-on-subpages-sales-and-purchases.aspx
|
[anchor5]: /navpatterns/1-patterns/totals-and-discounts-on-subpages-sales-and-purchases/
|
||||||
[anchor6]: /nav/w/designpatterns/123.using-cal-query-objects-instead-of-nested-loops.aspx
|
[anchor6]: /navpatterns/1-patterns/queries/use-queries-to-replace-nested-loops/
|
||||||
[anchor7]: /members/bogdana-botez/default.aspx
|
[anchor7]: /members/bogdana-botez/default.aspx
|
||||||
[anchor8]: /nav/w/designpatterns/107.template-for-writing-nav-design-patterns.aspx
|
[anchor8]: /navpatterns/4-get-involved/template-for-writing-nav-design-patterns/
|
||||||
[anchor9]: /members/bogdana-botez/default.aspx "Bogdana Botez"
|
[anchor9]: /members/bogdana-botez/default.aspx "Bogdana Botez"
|
||||||
[anchor10]: /nav/w/designpatterns/239.rules-of-conduct.aspx "Find the rules here"
|
[anchor10]: /navpatterns/4-get-involved/code-of-conduct/ "Find the rules here"
|
||||||
|
|
|
||||||
|
|
@ -163,5 +163,5 @@ And last but not least, we have collaborated with Plataan who hired Eric Wauters
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[anchor0]: /nav/w/designpatterns/106.be-a-nav-pattern-author.aspx
|
[anchor0]: /navpatterns/4-get-involved/
|
||||||
[anchor1]: /members/bogdana-botez/default.aspx "NAV Design Patterns project administrator"
|
[anchor1]: /members/bogdana-botez/default.aspx "NAV Design Patterns project administrator"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue