Skip to content
24 changes: 24 additions & 0 deletions src/Apps/W1/ExpenseAgent/app/src/APIs/ExpenseVATSpecAPI.Page.al
Original file line number Diff line number Diff line change
Expand Up @@ -105,4 +105,28 @@ page 7085 "Expense VAT Spec. API"
begin
ExpenseAgentAPIValidation.VerifyAgentAccess();
end;

trigger OnNewRecord(BelowxRec: Boolean)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$\textbf{🟡\ Medium\ Severity\ —\ Testing}$

The PR adds a new agent-only insert path on Expense VAT Spec. API and stamps new rows as Source::Agent, but no test covers either the reject path for non-agent callers or the success path that verifies the Source value is set correctly. Add an API/page test for both cases so regressions in caller validation or source initialization are caught.

👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.33.4

begin
VerifyExpenseAgentCaller();
Rec.Source := Rec.Source::Agent;
end;

trigger OnInsertRecord(BelowxRec: Boolean): Boolean
begin
VerifyExpenseAgentCaller();
Rec.Source := Rec.Source::Agent;
exit(true);
end;

var
ExpenseAgentCallerRequiredErr: Label 'Only the Expense Agent application can create agent-authored VAT specifications.';

local procedure VerifyExpenseAgentCaller()
var
ExpenseAgentAPIValidation: Codeunit "Expense Agent API Validation";
begin
if not ExpenseAgentAPIValidation.IsCurrentUserExpenseAgent() then
Error(ExpenseAgentCallerRequiredErr);
end;
}
Original file line number Diff line number Diff line change
Expand Up @@ -66,4 +66,10 @@ page 7084 "Expense VAT Specification"
}
}
}

trigger OnInsertRecord(BelowxRec: Boolean): Boolean
begin
Rec.Source := Rec.Source::"Manual";
exit(true);
end;
}
80 changes: 54 additions & 26 deletions src/Apps/W1/ExpenseAgent/app/src/Expense/Tables/Expense.Table.al
Original file line number Diff line number Diff line change
Expand Up @@ -788,6 +788,7 @@ table 6900 Expense
NonRefundableAmountCannotBeNegativeErr: Label '%1 cannot be in negative on Expense No. %2.', Comment = '%1 = Field Caption, %2 = Expense No.';
ExpenseUserMustBeLinkedToAnEmployeeErr: Label 'Expense User %1 must be linked to an Employee No.', Comment = '%1 = Expense User No.';
BillableCustomerAndProjectErr: Label 'You cannot use both %1 and %2 at the same time.', Comment = '%1 = Billable to Customer field caption, %2 = Project No. field caption';
ModifyOrDeleteErr: Label 'Modifications and delete are not allowed for records created by the Expense Agent API.';

procedure AssistEdit() Result: Boolean
begin
Expand Down Expand Up @@ -1309,6 +1310,7 @@ table 6900 Expense

internal procedure UpdateVATSpecification(ExpenseNo: Code[20])
var
ExpenseCategory: Record "Expense Category";
ExpenseItemization: Record "Expense Itemization";
ExpenseVATSpec: Record "Expense VAT Specification";
TempExpenseVATSpec: Record "Expense VAT Specification" temporary;
Expand All @@ -1318,33 +1320,59 @@ table 6900 Expense
if ExpenseAgentSetup."Default VAT Bus. Posting Group" = '' then
exit;

ExpenseItemization.SetRange("Expense No.", ExpenseNo);
if ExpenseItemization.IsEmpty() then
exit;
Comment thread
Alexander-Ya marked this conversation as resolved.

ExpenseVATSpec.SetRange("Expense No.", ExpenseNo);
ExpenseVATSpec.DeleteAll();

LineNo := 0;
ExpenseItemization.FindSet();
repeat
TempExpenseVATSpec.SetRange("Expense Category", ExpenseItemization."Expense Category Code");
TempExpenseVATSpec.SetRange("Expense Subcategory", ExpenseItemization."Expense Subcategory Code");
if TempExpenseVATSpec.FindFirst() then begin
TempExpenseVATSpec."Amount" += ExpenseItemization."Amount";
TempExpenseVATSpec.Modify();
end else begin
TempExpenseVATSpec.Init();
TempExpenseVATSpec."Expense No." := ExpenseNo;
LineNo += 1;
TempExpenseVATSpec."Line No." := LineNo;
TempExpenseVATSpec.Validate("Expense Category", ExpenseItemization."Expense Category Code");
TempExpenseVATSpec.Validate("Expense Subcategory", ExpenseItemization."Expense Subcategory Code");
TempExpenseVATSpec.Validate("VAT Bus. Posting Group", ExpenseAgentSetup."Default VAT Bus. Posting Group");
TempExpenseVATSpec.Validate("Amount", ExpenseItemization.Amount);
TempExpenseVATSpec.Insert();
end;
until ExpenseItemization.Next() = 0;
ExpenseVATSpec.SetRange(Source, ExpenseVATSpec.Source::Agent);
Comment thread
Alexander-Ya marked this conversation as resolved.
if not ExpenseVATSpec.IsEmpty() then
error(ModifyOrDeleteErr);

ExpenseCategory.Get("Expense Category");
case ExpenseCategory."Expense Detail Required" of
ExpenseCategory."Expense Detail Required"::Itemize:
begin
ExpenseItemization.SetRange("Expense No.", ExpenseNo);
if not ExpenseItemization.IsEmpty() then begin
ExpenseVATSpec.SetRange(Source);
ExpenseVATSpec.DeleteAll();

LineNo := 0;
ExpenseItemization.FindSet();
repeat
TempExpenseVATSpec.SetRange("Expense Category", ExpenseItemization."Expense Category Code");
TempExpenseVATSpec.SetRange("Expense Subcategory", ExpenseItemization."Expense Subcategory Code");
if TempExpenseVATSpec.FindFirst() then begin
TempExpenseVATSpec.Validate(Amount, TempExpenseVATSpec.Amount + ExpenseItemization.Amount);
TempExpenseVATSpec.Modify();
end else begin
TempExpenseVATSpec.Init();
TempExpenseVATSpec.Source := TempExpenseVATSpec.Source::Manual;
TempExpenseVATSpec."Expense No." := ExpenseNo;
LineNo += 1;
TempExpenseVATSpec."Line No." := LineNo;
TempExpenseVATSpec.Validate("Expense Category", ExpenseItemization."Expense Category Code");
TempExpenseVATSpec.Validate("Expense Subcategory", ExpenseItemization."Expense Subcategory Code");
TempExpenseVATSpec.Validate("VAT Bus. Posting Group", ExpenseAgentSetup."Default VAT Bus. Posting Group");
TempExpenseVATSpec.Validate("Amount", ExpenseItemization.Amount);
TempExpenseVATSpec.Insert();
end;
until ExpenseItemization.Next() = 0;
end;
end;
else
if ExpenseCategory."VAT Prod. Posting Group" <> '' then begin
ExpenseVATSpec.SetRange(Source);
ExpenseVATSpec.DeleteAll();

TempExpenseVATSpec.Init();
TempExpenseVATSpec.Source := TempExpenseVATSpec.Source::Manual;
TempExpenseVATSpec."Expense No." := ExpenseNo;
LineNo += 1;
TempExpenseVATSpec."Line No." := LineNo;
TempExpenseVATSpec.Validate("Expense Category", "Expense Category");
TempExpenseVATSpec.Validate("VAT Bus. Posting Group", ExpenseAgentSetup."Default VAT Bus. Posting Group");
TempExpenseVATSpec.Validate("Amount", Amount);
TempExpenseVATSpec.Insert();
end;
end;

TempExpenseVATSpec.Reset();
if TempExpenseVATSpec.FindSet() then
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,12 @@ table 6918 "Expense VAT Specification"
trigger OnValidate()
begin
GetExpense();
if Expense."Expense Category" <> '' then
Validate("Expense Category", "Expense Category");
if Expense."Expense Subcategory" <> '' then
Validate("Expense Subcategory", "Expense Subcategory");
if Source <> Source::Agent then begin
if Expense."Expense Category" <> '' then
Validate("Expense Category", "Expense Category");
if Expense."Expense Subcategory" <> '' then
Validate("Expense Subcategory", "Expense Subcategory");
end;
end;
}
field(2; "Line No."; Integer)
Expand All @@ -57,12 +59,14 @@ table 6918 "Expense VAT Specification"

trigger OnValidate()
begin
InitializeCurrency();
"VAT Amount" := Round(Amount * "VAT %" / (100 + "VAT %"), Currency."Amount Rounding Precision", Currency.VATRoundingDirection());
"VAT Base Amount" := Round(Amount - "VAT Amount", Currency."Amount Rounding Precision");
"VAT Difference" := 0;
"VAT Amount (LCY)" := CalcVATAmountLCY();
"VAT Base Amount (LCY)" := "Amount (LCY)" - "VAT Amount (LCY)";
if Source <> Source::Agent then begin
InitializeCurrency();
"VAT Amount" := Round(Amount * "VAT %" / (100 + "VAT %"), Currency."Amount Rounding Precision", Currency.VATRoundingDirection());
"VAT Base Amount" := Round(Amount - "VAT Amount", Currency."Amount Rounding Precision");
"VAT Difference" := 0;
"VAT Amount (LCY)" := CalcVATAmountLCY();
"VAT Base Amount (LCY)" := "Amount (LCY)" - "VAT Amount (LCY)";
end;
end;
}
field(11; "VAT Base Amount"; Decimal)
Expand Down Expand Up @@ -91,7 +95,8 @@ table 6918 "Expense VAT Specification"

trigger OnValidate()
begin
ValidateAmount();
if Source <> Source::Agent then
ValidateAmount();
end;
}
/// <summary>
Expand Down Expand Up @@ -151,17 +156,17 @@ table 6918 "Expense VAT Specification"

trigger OnValidate()
begin
GetExpense();
if Expense."Currency Code" = '' then begin
Amount := "Amount (LCY)";
Validate(Amount);
end else begin
Comment thread
Alexander-Ya marked this conversation as resolved.
TestField("Amount (LCY)");
TestField(Amount);
Expense."Currency Factor" := Amount / "Amount (LCY)";
if Source <> Source::Agent then begin
GetExpense();
if Expense."Currency Code" = '' then begin
Amount := "Amount (LCY)";
Validate(Amount);
end else begin
TestField("Amount (LCY)");
TestField(Amount);
end;
Validate("VAT %");
end;

Validate("VAT %");
end;
}
field(27; "Expense Category"; Code[20])
Expand All @@ -174,14 +179,16 @@ table 6918 "Expense VAT Specification"
var
ExpenseCategory: Record "Expense Category";
begin
if "Expense Category" = '' then
exit;
if "Expense Subcategory" <> '' then
exit;
if ExpenseCategory.Get("Expense Category") then begin
"VAT Prod. Posting Group" := ExpenseCategory."VAT Prod. Posting Group";
"VAT %" := ExpenseCategory."Default VAT %";
Validate("VAT %");
if Source <> Source::Agent then begin
if "Expense Category" = '' then
exit;
if "Expense Subcategory" <> '' then
exit;
if ExpenseCategory.Get("Expense Category") then begin
"VAT Prod. Posting Group" := ExpenseCategory."VAT Prod. Posting Group";
"VAT %" := ExpenseCategory."Default VAT %";
Validate("VAT %");
end;
end;
end;
}
Expand All @@ -196,6 +203,9 @@ table 6918 "Expense VAT Specification"
ExpenseSubcategory: Record "Expense Subcategory";
ExpenseCategory: Record "Expense Category";
begin
if Source = Source::Agent then
exit;

if "Expense Subcategory" <> '' then begin
if ExpenseSubcategory.Get("Expense Category", "Expense Subcategory") then begin
"VAT Prod. Posting Group" := ExpenseSubcategory."VAT Prod. Posting Group";
Expand All @@ -214,6 +224,8 @@ table 6918 "Expense VAT Specification"
field(40; Source; Enum "Expense VAT Spec Source")
{
Caption = 'Source';
Editable = false;
Comment thread
Alexander-Ya marked this conversation as resolved.
Comment thread
Alexander-Ya marked this conversation as resolved.
DataClassification = SystemMetadata;
ToolTip = 'Specifies how this VAT specification line was created, for example whether it was entered manually or extracted automatically from a receipt.';
}
field(41; Confidence; Decimal)
Expand Down Expand Up @@ -249,11 +261,24 @@ table 6918 "Expense VAT Specification"
end;
end;

trigger OnModify()
Comment thread
Alexander-Ya marked this conversation as resolved.
Comment thread
Alexander-Ya marked this conversation as resolved.
Comment thread
Alexander-Ya marked this conversation as resolved.
begin
if Source = Source::Agent then
error(ModifyOrDeleteErr);
end;

trigger OnDelete()
begin
if Source = Source::Agent then
error(ModifyOrDeleteErr);
end;

var
Currency: Record Currency;
CurrExchRate: Record "Currency Exchange Rate";
Expense: Record Expense;
ExpenseAgentSetup: Record "Expense Agent Setup";
ModifyOrDeleteErr: Label 'Modifications and delete are not allowed for records created by the Expense Agent API.';

local procedure CalcVATAmountLCY(): Decimal
var
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ codeunit 6983 "Create Expense Report"
ExpenseReportLine.Validate("Expense User No.", Expense."Expense User No.");
ExpenseReportLine.Validate("Expense Category", Expense."Expense Category");
ExpenseReportLine.Validate("Expense Subcategory Code", Expense."Expense Subcategory");
ExpenseReportLine.Validate("Expense Location", Expense."Expense Location");
ExpenseReportLine.Validate("Expense Location", CopyStr(Expense."Expense Location", 1, 20));
if Expense.Description <> '' then
ExpenseReportLine.Validate(Description, Expense.Description);
if ExpenseReportLine."Expense Subcategory Code" <> '' then
Expand Down Expand Up @@ -327,6 +327,8 @@ codeunit 6983 "Create Expense Report"
ExpenseReportLineVATSpec."VAT Amount" := ExpenseVATSpec."VAT Amount";
ExpenseReportLineVATSpec.Amount := ExpenseVATSpec.Amount;
ExpenseReportLineVATSpec."VAT Difference" := ExpenseVATSpec."VAT Difference";
ExpenseReportLineVATSpec."Currency Code" := Expense."Currency Code";
ExpenseReportLineVATSpec."Currency Factor" := Expense."Currency Factor";
ExpenseReportLineVATSpec."VAT Bus. Posting Group" := ExpenseVATSpec."VAT Bus. Posting Group";
ExpenseReportLineVATSpec."VAT Prod. Posting Group" := ExpenseVATSpec."VAT Prod. Posting Group";
ExpenseReportLineVATSpec."VAT Amount (LCY)" := ExpenseVATSpec."VAT Amount (LCY)";
Expand All @@ -340,6 +342,7 @@ codeunit 6983 "Create Expense Report"
else
if ExpenseCategory.Get(ExpenseVATSpec."Expense Category") then
ExpenseReportLineVATSpec.Validate("Reclaim %", ExpenseCategory."Default VAT Reclaim %");
ExpenseReportLineVATSpec.UpdateReimbursementAmounts();
ExpenseReportLineVATSpec.Insert();
until ExpenseVATSpec.Next() = 0;

Expand Down
Loading
Loading