Rewards Extension
Neil Haddley • August 30, 2023
Rewards Extension
The Microsoft Dynamics 365 Business Central Extension described here allows users to create a list of "Rewards" and to associate rewards with Business Central Customers.

I added the idRange needed for the Rewards extension
Rewards table
I created a Rewards.al file. In the Rewards.al file I added code to created a Business Central "Reward" table, a Business Central "Reward Card" page and a Business Central "Reward List" page.

I navigated to http://bcserver/BC/?tenant=default&page=50102 to view the Reward table using the Reward List page

I added a Reward item

The reward item has been stored in the Reward Table

I added the Minimum Purchase field to the Reward List page

I added the Minimum Purchase field to the Reward Card page

I added a Customer Ext (table extension) and a Customer Card Ext (card extension) to associate a Reward value with an Business Central Customer
Documentation
I used Meta's codellama language model to create the AL code documentation.

LM Studio code llama instruct 7B
code llama instruct 7B
Please explain this Business Central AL code
This code creates a new table called "Reward" with four fields: "Reward ID", "Description", "Discount Percentage", and "Minimum Purchase". The "Reward ID" field is the primary key of the table. The "Description" field can contain a string with up to 250 characters, the "Discount Percentage" field is a Decimal numeric value that represents the discount that will be applied for this reward, and the "Minimum Purchase" field is also a Decimal numeric value that represents the minimum purchase amount required to qualify for this reward.
The code also creates two pages: "Reward Card" and "Reward List". The "Reward Card" page is of type "Card" and will render as a card, while the "Reward List" page is of type "List" and will render as a list. The source table for both pages is the "Reward" table.
The "Reward Card" page has a layout that includes a group called "Reward" with four fields: "Reward ID", "Description", "Discount Percentage", and "Minimum Purchase". The "Reward ID" field is a text box that displays the value of the "Reward ID" field from the "Reward" table, while the other three fields are also text boxes that display the corresponding values.
The "Reward List" page has a layout that includes a repeater called "Rewards". The repeater contains four fields: "Reward ID", "Description", "Minimum Purchase", and "Discount Percentage". Each record in the "Reward" table will be displayed as a separate row in the list.
The code also includes a table extension called "Customer Ext" that extends the "Customer" table with an additional field called "Reward ID". The "Reward ID" field is set to have a table relation to the "Reward ID" field in the "Reward" table, and it is also set to validate the table relationship.
Finally, the code includes a page extension called "Customer Card Ext" that extends the "Customer Card" page with an additional text box called "Reward ID". The "Reward ID" text box displays the value of the "Reward ID" field from the "Customer" table and allows users to select a reward from a lookup window. The "Rewards" action is also added to the Navigation group, which will run the "Reward List" page when activated.
Rewards.al
TEXT
1table 50100 Reward 2{ 3 DataClassification = ToBeClassified; 4 5 6 fields 7 { 8 // The "Reward ID" field represents the unique identifier 9 // of the reward and can contain up to 30 Code characters. 10 field(1; "Reward ID"; Code[30]) 11 { 12 DataClassification = ToBeClassified; 13 } 14 15 16 // The "Description" field can contain a string 17 // with up to 250 characters. 18 field(2; Description; Text[250]) 19 { 20 // This property specified that 21 // this field cannot be left empty. 22 NotBlank = true; 23 } 24 25 26 // The "Discount Percentage" field is a Decimal numeric value 27 // that represents the discount that will 28 // be applied for this reward. 29 field(3; "Discount Percentage"; Decimal) 30 { 31 // The "MinValue" property sets the minimum value for the "Discount Percentage" 32 // field. 33 MinValue = 0; 34 35 36 // The "MaxValue" property sets the maximum value for the "Discount Percentage" 37 // field. 38 MaxValue = 100; 39 40 41 // The "DecimalPlaces" property is set to 2 to display discount values with 42 // exactly 2 decimals. 43 DecimalPlaces = 2; 44 } 45 } 46 47 48 keys 49 { 50 // The field "Reward ID" is used as the primary key of this table. 51 key(PK; "Reward ID") 52 { 53 // Create a clustered index from this key. 54 Clustered = true; 55 } 56 } 57} 58 59 60page 50101 "Reward Card" 61{ 62 // The page will be of type "Card" and will render as a card. 63 PageType = Card; 64 65 66 // The page will be part of the "Tasks" group of search results. 67 UsageCategory = Tasks; 68 69 70 // The source table shows data from the "Reward" table. 71 SourceTable = Reward; 72 73 74 // The layout describes the visual parts on the page. 75 layout 76 { 77 area(content) 78 { 79 group(Reward) 80 { 81 field("Reward Id"; Rec."Reward ID") 82 { 83 // ApplicationArea sets the application area that 84 // applies to the page field and action controls. 85 // Setting the property to All means that the control 86 // will always appear in the user interface. 87 ApplicationArea = All; 88 } 89 90 91 field(Description; Rec.Description) 92 { 93 ApplicationArea = All; 94 } 95 96 97 field("Discount Percentage"; Rec."Discount Percentage") 98 { 99 ApplicationArea = All; 100 } 101 } 102 } 103 } 104} 105 106 107page 50102 "Reward List" 108{ 109 // Specify that this page will be a list page. 110 PageType = List; 111 112 113 // The page will be part of the "Lists" group of search results. 114 UsageCategory = Lists; 115 116 117 // The data of this page is taken from the "Reward" table. 118 SourceTable = Reward; 119 120 121 // The "CardPageId" is set to the Reward Card previously created. 122 // This will allow users to open records from the list in the "Reward Card" page. 123 CardPageId = "Reward Card"; 124 125 126 layout 127 { 128 area(content) 129 { 130 repeater(Rewards) 131 { 132 field("Reward ID"; Rec."Reward ID") 133 { 134 ApplicationArea = All; 135 ToolTip = 'Specifies the level of reward that the customer has at this point.'; 136 } 137 138 139 field(Description; Rec.Description) 140 { 141 ApplicationArea = All; 142 } 143 144 145 field("Discount Percentage"; Rec."Discount Percentage") 146 { 147 ApplicationArea = All; 148 } 149 } 150 } 151 } 152}
Rewards.al updated
TEXT
1table 50100 Reward 2{ 3 DataClassification = ToBeClassified; 4 5 6 fields 7 { 8 // The "Reward ID" field represents the unique identifier 9 // of the reward and can contain up to 30 Code characters. 10 field(1; "Reward ID"; Code[30]) 11 { 12 DataClassification = ToBeClassified; 13 } 14 15 16 // The "Description" field can contain a string 17 // with up to 250 characters. 18 field(2; Description; Text[250]) 19 { 20 // This property specified that 21 // this field cannot be left empty. 22 NotBlank = true; 23 } 24 25 26 // The "Discount Percentage" field is a Decimal numeric value 27 // that represents the discount that will 28 // be applied for this reward. 29 field(3; "Discount Percentage"; Decimal) 30 { 31 // The "MinValue" property sets the minimum value for the "Discount Percentage" 32 // field. 33 MinValue = 0; 34 35 36 // The "MaxValue" property sets the maximum value for the "Discount Percentage" 37 // field. 38 MaxValue = 100; 39 40 41 // The "DecimalPlaces" property is set to 2 to display discount values with 42 // exactly 2 decimals. 43 DecimalPlaces = 2; 44 } 45 46 47 field(4; "Minimum Purchase"; Decimal) 48 { 49 MinValue = 0; 50 DecimalPlaces = 2; 51 } 52 53 54 } 55 56 57 keys 58 { 59 // The field "Reward ID" is used as the primary key of this table. 60 key(PK; "Reward ID") 61 { 62 // Create a clustered index from this key. 63 Clustered = true; 64 } 65 } 66} 67 68 69page 50101 "Reward Card" 70{ 71 // The page will be of type "Card" and will render as a card. 72 PageType = Card; 73 74 75 // The page will be part of the "Tasks" group of search results. 76 UsageCategory = Tasks; 77 78 79 // The source table shows data from the "Reward" table. 80 SourceTable = Reward; 81 82 83 // The layout describes the visual parts on the page. 84 layout 85 { 86 area(content) 87 { 88 group(Reward) 89 { 90 field("Reward Id"; Rec."Reward ID") 91 { 92 // ApplicationArea sets the application area that 93 // applies to the page field and action controls. 94 // Setting the property to All means that the control 95 // will always appear in the user interface. 96 ApplicationArea = All; 97 } 98 99 100 field(Description; Rec.Description) 101 { 102 ApplicationArea = All; 103 } 104 105 106 field("Minimum Purchase"; Rec."Minimum Purchase") 107 { 108 ApplicationArea = All; 109 } 110 111 112 field("Discount Percentage"; Rec."Discount Percentage") 113 { 114 ApplicationArea = All; 115 } 116 } 117 } 118 } 119} 120 121 122page 50102 "Reward List" 123{ 124 // Specify that this page will be a list page. 125 PageType = List; 126 127 128 // The page will be part of the "Lists" group of search results. 129 UsageCategory = Lists; 130 131 132 // The data of this page is taken from the "Reward" table. 133 SourceTable = Reward; 134 135 136 // The "CardPageId" is set to the Reward Card previously created. 137 // This will allow users to open records from the list in the "Reward Card" page. 138 CardPageId = "Reward Card"; 139 140 141 layout 142 { 143 area(content) 144 { 145 repeater(Rewards) 146 { 147 field("Reward ID"; Rec."Reward ID") 148 { 149 ApplicationArea = All; 150 ToolTip = 'Specifies the level of reward that the customer has at this point.'; 151 } 152 153 154 field(Description; Rec.Description) 155 { 156 ApplicationArea = All; 157 } 158 159 160 field("Minimum Purchase"; Rec."Minimum Purchase") 161 { 162 ApplicationArea = All; 163 } 164 165 166 field("Discount Percentage"; Rec."Discount Percentage") 167 { 168 ApplicationArea = All; 169 } 170 } 171 } 172 } 173} 174 175 176tableextension 50103 "Customer Ext" extends Customer 177{ 178 fields 179 { 180 field(50100; "Reward ID"; Code[30]) 181 { 182 // Set links to the "Reward ID" from the Reward table. 183 TableRelation = Reward."Reward ID"; 184 185 186 // Set whether to validate a table relationship. 187 ValidateTableRelation = true; 188 189 190 // "OnValidate" trigger executes when data is entered in a field. 191 trigger OnValidate(); 192 begin 193 194 195 // If the "Reward ID" changed and the new record is blocked, an error is thrown. 196 if (Rec."Reward ID" <> xRec."Reward ID") and 197 (Rec.Blocked <> Blocked::" ") then begin 198 Error('Cannot update the rewards status of a blocked customer.') 199 end; 200 end; 201 } 202 } 203} 204 205 206pageextension 50104 "Customer Card Ext" extends "Customer Card" 207{ 208 layout 209 { 210 // The "addlast" construct adds the field control as the last control in the General 211 // group. 212 addlast(General) 213 { 214 field("Reward ID"; Rec."Reward ID") 215 { 216 ApplicationArea = All; 217 218 219 // Lookup property is used to provide a lookup window for 220 // a text box. It is set to true, because a lookup for 221 // the field is needed. 222 Lookup = true; 223 } 224 } 225 } 226 227 228 actions 229 { 230 // The "addfirst" construct will add the action as the first action 231 // in the Navigation group. 232 addfirst(Navigation) 233 { 234 action("Rewards") 235 { 236 ApplicationArea = All; 237 238 239 // "RunObject" sets the "Reward List" page as the object 240 // that will run when the action is activated. 241 RunObject = page "Reward List"; 242 } 243 } 244 } 245}