Task 1 → Extension flow (text diagram):
User opens page (PettyCashLogList.Page.al).
Table enforces data rules and edit restrictions (PettyCashLog.Table.al).
Page action calls business logic (MarkReconciled in PettyCashMgt.Codeunit.al).
Test protects behavior (PettyCashMgtTests.Codeunit.al).
Permission sets control access (PettyCashView.PermissionSet.al, PettyCashFull.PermissionSet.al).
Field classification supports compliance (PettyCashLog.Table.al data classifications).
Task 2 → Implemented in:
PettyCashLog.Table.al
PettyCashLogList.Page.al
PettyCashMgt.Codeunit.al
PettyCashView.PermissionSet.al
PettyCashFull.PermissionSet.al
PettyCashMgtTests.Codeunit.al
Task 3 → A composite key is unnecessary because entries are independent transactions and do not belong to a natural grouped sequence like installments within one loan.
table 50110 "Petty Cash Log"
{
DataClassification = CustomerContent;
fields
{
field(1; "Entry No."; Integer)
{
DataClassification = SystemMetadata;
AutoIncrement = true;
}
field(2; "Received By"; Code[20])
{
DataClassification = EndUserIdentifiableInformation;
TableRelation = Employee."No.";
}
field(3; Amount; Decimal)
{
DataClassification = CustomerContent;
MinValue = 0.01;
}
field(4; Purpose; Text[100])
{
DataClassification = CustomerContent;
NotBlank = true;
}
field(5; "Entry Date"; Date)
{
DataClassification = CustomerContent;
}
field(6; Reconciled; Boolean)
{
DataClassification = CustomerContent;
}
}
keys
{
key(PK; "Entry No.")
{
Clustered = true;
}
}
trigger OnModify()
begin
if xRec.Reconciled then
Error('A reconciled petty cash entry cannot be changed.');
end;
}
page 50110 "Petty Cash Log List"
{
PageType = List;
SourceTable = "Petty Cash Log";
ApplicationArea = All;
UsageCategory = Lists;
Caption = 'Petty Cash Log';
layout
{
area(Content)
{
repeater(General)
{
field("Entry No."; Rec."Entry No.")
{
ApplicationArea = All;
}
field("Received By"; Rec."Received By")
{
ApplicationArea = All;
}
field(Amount; Rec.Amount)
{
ApplicationArea = All;
}
field(Purpose; Rec.Purpose)
{
ApplicationArea = All;
}
field("Entry Date"; Rec."Entry Date")
{
ApplicationArea = All;
}
field(Reconciled; Rec.Reconciled)
{
ApplicationArea = All;
}
}
}
}
actions
{
area(Processing)
{
action(MarkReconciled)
{
ApplicationArea = All;
Caption = 'Mark Reconciled';
Image = Approve;
trigger OnAction()
var
PettyCashMgt: Codeunit "Petty Cash Mgt.";
begin
PettyCashMgt.MarkReconciled(Rec);
CurrPage.Update(false);
end;
}
}
}
}
codeunit 50111 "Petty Cash Mgt."
{
procedure MarkReconciled(var PettyCashLog: Record "Petty Cash Log")
begin
PettyCashLog.Reconciled := true;
PettyCashLog.Modify(true);
end;
}
permissionset 50112 "Petty Cash - View"
{
Assignable = true;
Caption = 'Petty Cash (View Only)';
Permissions =
table "Petty Cash Log" = X,
tabledata "Petty Cash Log" = R,
page "Petty Cash Log List" = X;
}
permissionset 50113 "Petty Cash - Full"
{
Assignable = true;
Caption = 'Petty Cash (Full Access)';
IncludedPermissionSets = "Petty Cash - View";
Permissions =
tabledata "Petty Cash Log" = IMD,
codeunit "Petty Cash Mgt." = X;
}
codeunit 50114 "Petty Cash Mgt. Tests"
{
Subtype = Test;
[Test]
procedure MarkReconciledSetsFlag()
var
PettyCashLog: Record "Petty Cash Log";
PettyCashMgt: Codeunit "Petty Cash Mgt.";
Assert: Codeunit Assert;
begin
PettyCashLog.Init();
PettyCashLog."Received By" := 'E0001';
PettyCashLog.Amount := 20;
PettyCashLog.Purpose := 'Office supplies';
PettyCashLog."Entry Date" := Today;
PettyCashLog.Insert(true);
PettyCashMgt.MarkReconciled(PettyCashLog);
Assert.IsTrue(PettyCashLog.Reconciled, 'Entry should be marked reconciled.');
end;
}