diff --git a/Apps/W1/ApplicationTestLibrary/Assert.Codeunit.al b/Apps/W1/ApplicationTestLibrary/Assert.Codeunit.al
new file mode 100644
index 0000000000..03f088a86b
--- /dev/null
+++ b/Apps/W1/ApplicationTestLibrary/Assert.Codeunit.al
@@ -0,0 +1,565 @@
+///
+/// Provides assertion functions for verifying test conditions and comparing expected versus actual values in test scenarios.
+///
+codeunit 130000 Assert
+{
+
+ trigger OnRun()
+ begin
+ end;
+
+ var
+ IsTrueFailedMsg: Label 'Assert.IsTrue failed. %1';
+ IsFalseFailedMsg: Label 'Assert.IsFalse failed. %1';
+ AreEqualFailedMsg: Label 'Assert.AreEqual failed. Expected:<%1> (%2). Actual:<%3> (%4). %5.', Locked = true;
+ AreNotEqualFailedMsg: Label 'Assert.AreNotEqual failed. Expected any value except:<%1> (%2). Actual:<%3> (%4). %5.', Locked = true;
+ AreNearlyEqualFailedMsg: Label 'Assert.AreNearlyEqual failed. Expected a difference no greater than <%1> between expected value <%2> and actual value <%3>. %4';
+ AreNotNearlyEqualFailedMsg: Label 'Assert.AreNotNearlyEqual failed. Expected a difference greater than <%1> between expected value <%2> and actual value <%3>. %4';
+ RecordsAreEqualExceptCertainFieldsErr: Label 'Assert.RecordsAreEqualExceptCertainFields failed. Expected the records to match. Difference found in <%1>. Left value <%2>, Right value <%3>. %4';
+ FailFailedMsg: Label 'Assert.Fail failed. %1';
+ TableIsEmptyErr: Label 'Assert.TableIsEmpty failed. Table <%1> with filter <%2> must not contain records.', Locked = true;
+ TableIsNotEmptyErr: Label 'Assert.TableIsNotEmpty failed. Table <%1> with filter <%2> must contain records.', Locked = true;
+ ExpectedErrorFailed: Label 'Assert.ExpectedError failed. Expected: %1. Actual: %2.';
+ ExpectedTestFieldFailedErr: Label 'Assert.ExpectedError failed. Could not find the value: %1 in the raised error text: %2.';
+ WrongErrorCodeErr: Label 'Assert.ExpectedErrorCode failed. Error code raised: %1. Actual error message: %2.', Comment = '%1 - Error code that was raised. %2 - Error message reported.', Locked = true;
+ ExpectedErrorCodeFailed: Label 'Assert.ExpectedErrorCode failed. Expected: %1. Actual: %2. Actual error message: %3.';
+ ExpectedMessageFailedErr: Label 'Assert.ExpectedMessage failed. Expected: %1. Actual: %2.';
+ ExpectedConfirmFailedErr: Label 'Assert.ExpectedConfirm failed. Expected: %1. Actual: %2.';
+ ExpectedStrMenuInstructionFailedErr: Label 'Assert.ExpectedStrMenu failed. Expected instruction: %1. Actual instruction: %2.';
+ ExpectedStrMenuOptionsFailedErr: Label 'Assert.ExpectedStrMenu failed. Expected options: %1. Actual options: %2.';
+ IsSubstringFailedErr: Label 'Assert.IsSubstring failed. Expected <%1> to be a substring of <%2>.';
+ RecordCountErr: Label 'Assert.RecordCount failed. Expected number of %1 entries: %2. Actual: %3. Filters: %4.', Locked = true;
+ RecordCountWithListErr: Label 'Assert.RecordCount failed. Expected number of %1 entries: %2. Actual: %3. Filters: %4. Records: %5', Locked = true;
+ UnsupportedTypeErr: Label 'Equality assertions only support Boolean, Option, Integer, BigInteger, Decimal, Code, Text, Date, DateFormula, Time, Duration, and DateTime values. Current value:%1.';
+ RecordNotFoundErrorCode: Label 'DB:RecordNotFound';
+ RecordAlreadyExistsErrorCode: Label 'DB:RecordExists';
+ RecordNothingInsideFilterErrorCode: Label 'DB:NothingInsideFilter';
+ AssertErrorMsg: Label 'Expected error %1 actual %2';
+ PrimRecordNotFoundErrorCode: Label 'DB:PrimRecordNotFound';
+ NoFilterErrorCode: Label 'DB:NoFilter';
+ ErrorHasNotBeenThrownErr: Label 'The error has not been thrown.';
+ TextEndsWithErr: Label 'Assert.TextEndsWith failed. The text <%1> must end with <%2>';
+ TextEndSubstringIsBlankErr: Label 'Substring must not be blank.';
+ TestFieldFormat1Tok: Label ' must be ';
+ TestFieldFormat1Part2Tok: Label 'Currently it''s';
+ TestFieldFormat2Tok: Label ' must have a value in ';
+ TestFieldFormat2Part2Tok: Label 'It can''t be zero or empty.';
+ TestFieldFormat3Tok: Label ' can''t be ';
+ //CantFindTok: Label 'Can''t find ';
+ TestFieldValidationCodeTxt: Label 'TestValidation';
+ NCLCSRTSTableErrorStrTxt: Label 'NCLCSRTS:TableErrorStr';
+ TestWrappedTxt: Label 'TestWrapped';
+ TestWrappedCSideRecordNotFoundTxt: Label 'TestWrapped:CSideRecordNotFound';
+ TestFieldCodeTxt: Label 'TestField';
+ DialogTxt: Label 'Dialog';
+ ErrorMessageIsNotMatchingExpectedErrorFormatErr: Label 'Assert.ExpectedError failed. The error message is not matching the expected error format. Error message: %1', Comment = '%1 error message that was raised.';
+
+ procedure IsTrue(Condition: Boolean; Msg: Text)
+ begin
+ if not Condition then
+ Error(IsTrueFailedMsg, Msg)
+ end;
+
+ procedure IsFalse(Condition: Boolean; Msg: Text)
+ begin
+ if Condition then
+ Error(IsFalseFailedMsg, Msg)
+ end;
+
+ procedure AreEqual(Expected: Variant; Actual: Variant; Msg: Text)
+ begin
+ if not Equal(Expected, Actual) then
+ Error(AreEqualFailedMsg, Expected, TypeNameOf(Expected), Actual, TypeNameOf(Actual), Msg)
+ end;
+
+ procedure AreNotEqual(Expected: Variant; Actual: Variant; Msg: Text)
+ begin
+ if Equal(Expected, Actual) then
+ Error(AreNotEqualFailedMsg, Expected, TypeNameOf(Expected), Actual, TypeNameOf(Actual), Msg)
+ end;
+
+ procedure AreNearlyEqual(Expected: Decimal; Actual: Decimal; Delta: Decimal; Msg: Text)
+ begin
+ if Abs(Expected - Actual) > Abs(Delta) then
+ Error(AreNearlyEqualFailedMsg, Delta, Expected, Actual, Msg)
+ end;
+
+ procedure AreNotNearlyEqual(Expected: Decimal; Actual: Decimal; Delta: Decimal; Msg: Text)
+ begin
+ if Abs(Expected - Actual) <= Abs(Delta) then
+ Error(AreNotNearlyEqualFailedMsg, Delta, Expected, Actual, Msg)
+ end;
+
+ procedure Fail(Msg: Text)
+ begin
+ Error(FailFailedMsg, Msg)
+ end;
+
+ procedure RecordIsEmpty(RecVariant: Variant)
+ var
+ RecRef: RecordRef;
+ begin
+ RecRef.GetTable(RecVariant);
+ RecRefIsEmpty(RecRef);
+ end;
+
+ procedure RecordIsEmpty(RecVariant: Variant; CompanyName: Text)
+ var
+ RecRef: RecordRef;
+ begin
+ RecRef.GetTable(RecVariant);
+ RecRef.ChangeCompany(CompanyName);
+ RecRefIsEmpty(RecRef);
+ end;
+
+ procedure RecordIsNotEmpty(RecVariant: Variant; CompanyName: Text)
+ var
+ RecRef: RecordRef;
+ begin
+ RecRef.GetTable(RecVariant);
+ RecRef.ChangeCompany(CompanyName);
+ RecRefIsNotEmpty(RecRef);
+ end;
+
+ procedure RecordIsNotEmpty(RecVariant: Variant)
+ var
+ RecRef: RecordRef;
+ begin
+ RecRef.GetTable(RecVariant);
+ RecRefIsNotEmpty(RecRef);
+ end;
+
+ procedure TableIsEmpty(TableNo: Integer)
+ var
+ RecRef: RecordRef;
+ begin
+ RecRef.Open(TableNo);
+ RecRefIsEmpty(RecRef);
+ RecRef.Close();
+ end;
+
+ procedure TableIsNotEmpty(TableNo: Integer)
+ var
+ RecRef: RecordRef;
+ begin
+ RecRef.Open(TableNo);
+ RecRefIsNotEmpty(RecRef);
+ RecRef.Close();
+ end;
+
+ local procedure RecRefIsEmpty(var RecRef: RecordRef)
+ begin
+ if not RecRef.IsEmpty() then
+ Error(TableIsEmptyErr, RecRef.Caption, RecRef.GetFilters);
+ end;
+
+ local procedure RecRefIsNotEmpty(var RecRef: RecordRef)
+ begin
+ if RecRef.IsEmpty() then
+ Error(TableIsNotEmptyErr, RecRef.Caption, RecRef.GetFilters);
+ end;
+
+ procedure RecordCount(RecVariant: Variant; ExpectedCount: Integer)
+ var
+ RecRef: RecordRef;
+ RecordsList: TextBuilder;
+ FieldIndex: Integer;
+ RecordIndex: Integer;
+ begin
+ RecRef.GetTable(RecVariant);
+ if ExpectedCount <> RecRef.Count then begin
+ if RecRef.FindFirst() then begin
+ repeat
+ RecordIndex += 1;
+ for FieldIndex := 1 to RecRef.FieldCount() do begin
+ RecordsList.Append(RecRef.FieldIndex(FieldIndex).Value());
+ RecordsList.Append(', ')
+ end;
+ RecordsList.Append('; ');
+ until (RecRef.Next() = 0) or (RecordIndex = 50);
+ Error(RecordCountWithListErr, RecRef.Caption, ExpectedCount, RecRef.Count, RecRef.GetFilters, RecordsList.ToText());
+ end;
+ Error(RecordCountErr, RecRef.Caption, ExpectedCount, RecRef.Count, RecRef.GetFilters);
+ end;
+ RecRef.Close();
+ end;
+
+ procedure ExpectedError(Expected: Text)
+ begin
+ if (GetLastErrorText = '') and (Expected = '') then begin
+ if GetLastErrorCallstack = '' then
+ Error(ErrorHasNotBeenThrownErr);
+ end else
+ if StrPos(GetLastErrorText, Expected) = 0 then
+ Error(ExpectedErrorFailed, Expected, GetLastErrorText);
+ end;
+
+ ///
+ /// Checks for the field error that it cannot find the record
+ ///
+ /// Old formats: The {0} does not exist. Identification fields and values: {1}.
+ /// New format: Can't find {0} in {1}.
+ /// Table ID Raising the erro
+ procedure ExpectedErrorCannotFind(TableID: Integer)
+ begin
+ ExpectedErrorCannotFind(TableID, '');
+ end;
+
+ ///
+ /// Checks for the field error that it cannot find the record
+ ///
+ /// Old formats: The {0} does not exist. Identification fields and values: {1}.
+ /// New format: Can't find {0} in {1}.
+ /// Table ID Raising the erro
+ /// Identification text of the record that it cannot find
+ procedure ExpectedErrorCannotFind(TableID: Integer; RecordIndentificationText: Text)
+ var
+ LastErrorText: Text;
+ LastErrorCode: Text;
+ begin
+ LastErrorText := GetLastErrorText();
+ if (GetLastErrorText() = '') then
+ if GetLastErrorCallStack() = '' then
+ Error(ErrorHasNotBeenThrownErr);
+
+ LastErrorCode := GetLastErrorCode();
+ if (LastErrorCode <> RecordNotFoundErrorCode) and
+ (LastErrorCode <> PrimRecordNotFoundErrorCode) and
+ (LastErrorCode <> TestWrappedCSideRecordNotFoundTxt) and
+ (not LastErrorCode.Contains(TestFieldValidationCodeTxt))
+ then
+ Error(WrongErrorCodeErr, LastErrorCode, LastErrorText);
+
+ ExpectedMessageCannotFind(LastErrorText, TableID, RecordIndentificationText);
+ end;
+
+ procedure ExpectedMessageCannotFind(LastErrorText: Text; TableID: Integer; RecordIndentificationText: Text)
+ var
+ AllObjWithCaption: Record AllObjWithCaption;
+ TableCaption: Text;
+ IsCantFindError: Boolean;
+ begin
+ AllObjWithCaption.SetRange("Object Type", AllObjWithCaption."Object Type"::Table);
+ AllObjWithCaption.SetRange("Object ID", TableID);
+ AllObjWithCaption.FindFirst();
+ TableCaption := AllObjWithCaption."Object Caption";
+
+ IsCantFindError := true;
+ if not IsCantFindError then
+ Error(ErrorMessageIsNotMatchingExpectedErrorFormatErr, LastErrorText);
+
+ if TableCaption <> '' then
+ if StrPos(LastErrorText, TableCaption) = 0 then
+ Error(ExpectedTestFieldFailedErr, TableCaption, LastErrorText);
+
+ if RecordIndentificationText <> '' then
+ if StrPos(LastErrorText, RecordIndentificationText) = 0 then
+ Error(ExpectedTestFieldFailedErr, TableCaption, LastErrorText);
+ end;
+
+ ///
+ /// Checks for the test filed errors.
+ /// Old formats: {0} must not be {1} in {2} {3}.
+ /// {0} must have a value in {1}: {2}. It cannot be zero or empty.
+ /// {0} must be equal to “{2}” in {1}: {4}. Current value is “{3}”.
+ /// New format: {0} can’t be {1} in {2}.
+ /// {0} must have a value in {1}: {2}. It can’t be zero or empty.
+ /// {0} must be {2} for {1}: {4}. Currently it’s {3}.
+ ///
+ /// Name of the field raising the error
+ /// Expected value in the error message
+ procedure ExpectedTestFieldError(FieldCaptionTested: Text; ExpectedValue: Text)
+ begin
+ ExpectedTestFieldError(FieldCaptionTested, ExpectedValue, '', '');
+ end;
+
+ ///
+ /// Checks for the test filed errors.
+ /// New format: {0} can’t be {1} in {2}.
+ /// {0} must have a value in {1}: {2}. It can’t be zero or empty.
+ /// {0} must be {2} for {1}: {4}. Currently it’s {3}.
+ /// Old formats: {0} must not be {1} in {2} {3}.
+ /// {0} must have a value in {1}: {2}. It cannot be zero or empty.
+ /// {0} must be equal to “{2}” in {1}: {4}. Current value is “{3}”.
+ ///
+ /// Name of the field raising the error
+ /// Expected value in the error message
+ /// Actual value in the error message
+ /// Name of the table raising the error
+ procedure ExpectedTestFieldError(FieldCaptionTested: Text; ExpectedValue: Text; ActualValue: Text; TableCaptionTested: Text)
+ var
+ LastErrorText: Text;
+ LastErrorCode: Text;
+ begin
+ LastErrorText := GetLastErrorText();
+ if (GetLastErrorText() = '') then
+ if GetLastErrorCallStack() = '' then
+ Error(ErrorHasNotBeenThrownErr);
+
+ LastErrorCode := GetLastErrorCode();
+ if not (LastErrorCode.Contains(TestFieldValidationCodeTxt) or
+ (LastErrorCode in [NCLCSRTSTableErrorStrTxt, TestWrappedTxt]) or
+ (LastErrorCode.Contains(TestFieldCodeTxt)) or
+ (LastErrorCode.Contains(DialogTxt)))
+ then
+ Error(WrongErrorCodeErr, LastErrorCode, LastErrorText);
+
+ ExpectedTestFieldMessage(LastErrorText, FieldCaptionTested, ExpectedValue, ActualValue, TableCaptionTested);
+ end;
+
+ procedure ExpectedTestFieldMessage(LastErrorText: Text; FieldCaptionTested: Text; ExpectedValue: Text; ActualValue: Text; TableCaptionTested: Text)
+ var
+ IsTestFieldError: Boolean;
+ begin
+ if ExpectedValue <> '' then
+ if StrPos(LastErrorText, ExpectedValue) = 0 then
+ Error(ExpectedTestFieldFailedErr, ExpectedValue, LastErrorText);
+
+ if ActualValue <> '' then
+ if StrPos(LastErrorText, ActualValue) = 0 then
+ Error(ExpectedTestFieldFailedErr, ActualValue, LastErrorText);
+
+ if FieldCaptionTested <> '' then
+ if StrPos(LastErrorText, FieldCaptionTested) = 0 then
+ Error(ExpectedTestFieldFailedErr, FieldCaptionTested, LastErrorText);
+
+ if TableCaptionTested <> '' then
+ if StrPos(LastErrorText, TableCaptionTested) = 0 then
+ Error(ExpectedTestFieldFailedErr, TableCaptionTested, LastErrorText);
+
+ IsTestFieldError := true;
+
+ if not IsTestFieldError then
+ Error(ErrorMessageIsNotMatchingExpectedErrorFormatErr, LastErrorText);
+ end;
+
+ internal procedure MatchesTestFieldMessageFormat(ErrorMessage: Text): Boolean
+ begin
+ if (StrPos(ErrorMessage, TestFieldFormat1Tok) > 0) and (StrPos(ErrorMessage, TestFieldFormat1Part2Tok) > 0) then
+ exit(true);
+
+ if (StrPos(ErrorMessage, TestFieldFormat2Tok) > 0) and (StrPos(ErrorMessage, TestFieldFormat2Part2Tok) > 0) then
+ exit(true);
+
+ if StrPos(ErrorMessage, TestFieldFormat3Tok) > 0 then
+ exit(true);
+
+ exit(false);
+ end;
+
+ procedure ExpectedErrorCode(Expected: Text)
+ begin
+ if StrPos(GetLastErrorCode, Expected) = 0 then
+ Error(ExpectedErrorCodeFailed, Expected, GetLastErrorCode, GetLastErrorText);
+ end;
+
+ procedure ExpectedMessage(Expected: Text; Actual: Text)
+ begin
+ ExpectedDialog(Expected, Actual, ExpectedMessageFailedErr);
+ end;
+
+ procedure ExpectedConfirm(Expected: Text; Actual: Text)
+ begin
+ ExpectedDialog(Expected, Actual, ExpectedConfirmFailedErr);
+ end;
+
+ procedure ExpectedStrMenu(ExpectedInstruction: Text; ExpectedOptions: Text; ActualInstruction: Text; ActualOptions: Text)
+ begin
+ ExpectedDialog(ExpectedInstruction, ActualInstruction, ExpectedStrMenuInstructionFailedErr);
+ ExpectedDialog(ExpectedOptions, ActualOptions, ExpectedStrMenuOptionsFailedErr);
+ end;
+
+ local procedure ExpectedDialog(Expected: Text; Actual: Text; ErrorMessage: Text)
+ begin
+ if Expected = Actual then
+ exit;
+ if StrPos(Actual, Expected) = 0 then
+ Error(ErrorMessage, Expected, Actual);
+ end;
+
+ procedure IsDataTypeSupported(Value: Variant): Boolean
+ begin
+ exit(Value.IsBoolean or
+ Value.IsOption or
+ Value.IsInteger or
+ Value.IsDecimal or
+ Value.IsText or
+ Value.IsCode or
+ Value.IsDate or
+ Value.IsDateTime or
+ Value.IsDateFormula or
+ Value.IsGuid or
+ Value.IsDuration or
+ Value.IsRecordId or
+ Value.IsBigInteger or
+ Value.IsChar or
+ Value.IsTime);
+ end;
+
+ procedure TextEndsWith(OriginalText: Text; Substring: Text)
+ var
+ ErrorMessage: Text;
+ begin
+ if Substring = '' then
+ Error(TextEndSubstringIsBlankErr);
+ ErrorMessage := StrSubstNo(TextEndsWithErr, OriginalText, Substring);
+ AreEqual(StrLen(OriginalText) - StrLen(Substring) + 1, StrPos(OriginalText, Substring), ErrorMessage);
+ end;
+
+ procedure IsSubstring(OriginalText: Text; Substring: Text)
+ begin
+ if Substring = '' then
+ Error(TextEndSubstringIsBlankErr);
+
+ if StrPos(OriginalText, Substring) <= 0 then
+ Error(IsSubstringFailedErr, Substring, OriginalText);
+ end;
+
+ local procedure TypeOf(Value: Variant): Integer
+ var
+ "Field": Record "Field";
+ begin
+ case true of
+ Value.IsBoolean:
+ exit(Field.Type::Boolean);
+ Value.IsOption or Value.IsInteger or Value.IsByte:
+ exit(Field.Type::Integer);
+ Value.IsBigInteger:
+ exit(Field.Type::BigInteger);
+ Value.IsDecimal:
+ exit(Field.Type::Decimal);
+ Value.IsText or Value.IsCode or Value.IsChar or Value.IsTextConstant:
+ exit(Field.Type::Text);
+ Value.IsDate:
+ exit(Field.Type::Date);
+ Value.IsTime:
+ exit(Field.Type::Time);
+ Value.IsDuration:
+ exit(Field.Type::Duration);
+ Value.IsDateTime:
+ exit(Field.Type::DateTime);
+ Value.IsDateFormula:
+ exit(Field.Type::DateFormula);
+ Value.IsGuid:
+ exit(Field.Type::GUID);
+ Value.IsRecordId:
+ exit(Field.Type::RecordID);
+ else
+ Error(UnsupportedTypeErr, UnsupportedTypeName(Value))
+ end
+ end;
+
+ local procedure TypeNameOf(Value: Variant): Text
+ var
+ "Field": Record "Field";
+ begin
+ Field.Type := TypeOf(Value);
+ exit(Format(Field.Type));
+ end;
+
+ local procedure UnsupportedTypeName(Value: Variant): Text
+ begin
+ case true of
+ Value.IsRecord:
+ exit('Record');
+ Value.IsRecordRef:
+ exit('RecordRef');
+ Value.IsFieldRef:
+ exit('FieldRef');
+ Value.IsCodeunit:
+ exit('Codeunit');
+ Value.IsAutomation:
+ exit('Automation');
+ Value.IsFile:
+ exit('File');
+ end;
+ exit('Unsupported Type');
+ end;
+
+ procedure Compare(Left: Variant; Right: Variant): Boolean
+ begin
+ exit(Equal(Left, Right))
+ end;
+
+ procedure Equal(Left: Variant; Right: Variant): Boolean
+ begin
+ if IsNumber(Left) and IsNumber(Right) then
+ exit(EqualNumbers(Left, Right));
+
+ if Left.IsDotNet or Right.IsDotNet then
+ exit((Format(Left, 0, 2) = Format(Right, 0, 2)));
+
+ exit((TypeOf(Left) = TypeOf(Right)) and (Format(Left, 0, 2) = Format(Right, 0, 2)))
+ end;
+
+ local procedure EqualNumbers(Left: Decimal; Right: Decimal): Boolean
+ begin
+ exit(Left = Right)
+ end;
+
+ local procedure IsNumber(Value: Variant): Boolean
+ begin
+ exit(Value.IsDecimal or Value.IsInteger or Value.IsChar)
+ end;
+
+ procedure VerifyFailure(expectedErrorCode: Text; failureText: Text)
+ var
+ errorCode: Text;
+ begin
+ errorCode := GetLastErrorCode;
+
+ IsTrue(errorCode = expectedErrorCode, failureText);
+ ClearLastError();
+ end;
+
+ procedure AssertRecordNotFound()
+ begin
+ VerifyFailure(RecordNotFoundErrorCode, StrSubstNo(AssertErrorMsg, RecordNotFoundErrorCode, GetLastErrorCode));
+ end;
+
+ procedure AssertRecordAlreadyExists()
+ begin
+ VerifyFailure(RecordAlreadyExistsErrorCode, StrSubstNo(AssertErrorMsg, RecordAlreadyExistsErrorCode, GetLastErrorCode));
+ end;
+
+ procedure AssertNothingInsideFilter()
+ begin
+ VerifyFailure(RecordNothingInsideFilterErrorCode, StrSubstNo(AssertErrorMsg, RecordNothingInsideFilterErrorCode, GetLastErrorCode));
+ end;
+
+ procedure AssertNoFilter()
+ begin
+ VerifyFailure(NoFilterErrorCode, StrSubstNo(AssertErrorMsg, NoFilterErrorCode, GetLastErrorCode));
+ end;
+
+ procedure AssertPrimRecordNotFound()
+ begin
+ VerifyFailure(PrimRecordNotFoundErrorCode, StrSubstNo(AssertErrorMsg, PrimRecordNotFoundErrorCode, GetLastErrorCode));
+ end;
+
+ procedure RecordsAreEqualExceptCertainFields(var RecordRefLeft: RecordRef; var RecordRefRight: RecordRef; var TempFieldToIgnore: Record "Field" temporary; Msg: Text): Boolean
+ var
+ LeftFieldRef: FieldRef;
+ RightFieldRef: FieldRef;
+ i: Integer;
+ begin
+ // Records and are considered equal when each (Normal) field
+ // has the same value as the field with the same index.
+ // Note that for performance reasons this function does not take into account,
+ // whether the two records have the same number of fields.
+ // It assumes that the records belong to the same table.
+
+ for i := 1 to RecordRefLeft.FieldCount do begin
+ LeftFieldRef := RecordRefLeft.FieldIndex(i);
+ if LeftFieldRef.Class = FieldClass::Normal then begin
+ RightFieldRef := RecordRefRight.FieldIndex(i);
+
+ if not TempFieldToIgnore.Get(RecordRefLeft.Number, LeftFieldRef.Number) then
+ if LeftFieldRef.Value <> RightFieldRef.Value then
+ Error(RecordsAreEqualExceptCertainFieldsErr, LeftFieldRef.Name, LeftFieldRef.Value, RightFieldRef.Value, Msg);
+ end;
+ end;
+ exit(true);
+ end;
+}
+
diff --git a/Apps/W1/ApplicationTestLibrary/LibraryAssembly.Codeunit.al b/Apps/W1/ApplicationTestLibrary/LibraryAssembly.Codeunit.al
new file mode 100644
index 0000000000..931321e208
--- /dev/null
+++ b/Apps/W1/ApplicationTestLibrary/LibraryAssembly.Codeunit.al
@@ -0,0 +1,3299 @@
+///
+/// Provides utility functions for creating and managing assembly-related entities in test scenarios, including assembly orders, BOMs, and assembly items.
+///
+codeunit 132207 "Library - Assembly"
+{
+ Subtype = Normal;
+
+ trigger OnRun()
+ begin
+ end;
+
+ var
+ LibraryUtility: Codeunit "Library - Utility";
+ LibraryCosting: Codeunit "Library - Costing";
+ LibraryPurchase: Codeunit "Library - Purchase";
+ LibraryInventory: Codeunit "Library - Inventory";
+ LibraryERM: Codeunit "Library - ERM";
+ LibraryDimension: Codeunit "Library - Dimension";
+ LibraryResource: Codeunit "Library - Resource";
+ LibraryWarehouse: Codeunit "Library - Warehouse";
+ Assert: Codeunit Assert;
+ LibraryRandom: Codeunit "Library - Random";
+ ChangeType: Option " ",Add,Replace,Delete,Edit,"Delete all","Edit cards";
+ ErrorZeroQty: Label 'Quantity must have a value in Assembly Header: Document Type=Order, No.=%1. It cannot be zero or empty.';
+ ErrorStdCost: Label 'Changing Unit Cost or Cost Amount is not allowed when Costing Method is Standard.';
+ BlockType: Option Dimension,"Dimension Value","Dimension Combination","None";
+ ClearType: Option "Posting Group","Location Posting Setup","Posting Group Setup";
+ AdjSource: Option Purchase,Revaluation,"Item Card","Order Lines",Resource,"None";
+ ErrorDimCombination: Label 'The combination of dimensions used in Order %1%2 is blocked. Dimensions %3 and %4 can''t be used concurrently.', Comment = '%1=OrderNo, %2=LineNo, %3=DimensionCode[1], %4=DimensionCode[2]';
+ ErrorPostingSetup: Label 'The General Posting Setup does not exist. ';
+ ErrorInvtPostingSetup: Label 'The Inventory Posting Setup does not exist.';
+
+ procedure AddCompInventory(AssemblyHeader: Record "Assembly Header"; PostingDate: Date; QtySupplement: Decimal)
+ var
+ AssemblyLine: Record "Assembly Line";
+ Item: Record Item;
+ begin
+ AssemblyLine.Reset();
+ AssemblyLine.SetRange("Document Type", AssemblyHeader."Document Type");
+ AssemblyLine.SetRange("Document No.", AssemblyHeader."No.");
+ AssemblyLine.SetRange(Type, AssemblyLine.Type::Item);
+ if AssemblyLine.FindSet() then
+ repeat
+ Item.Get(AssemblyLine."No.");
+ if Item.IsInventoriableType() then
+ AddItemInventory(
+ AssemblyLine, PostingDate, AssemblyLine."Location Code", AssemblyLine."Bin Code", AssemblyLine.Quantity + QtySupplement);
+ until AssemblyLine.Next() = 0;
+ end;
+
+ procedure AddCompInventoryToBin(AssemblyHeader: Record "Assembly Header"; PostingDate: Date; QtySupplement: Decimal; LocationCode: Code[10]; BinCode: Code[20])
+ var
+ AssemblyLine: Record "Assembly Line";
+ Bin: Record Bin;
+ Location: Record Location;
+ ItemJournalTemplate: Record "Item Journal Template";
+ ItemJournalBatch: Record "Item Journal Batch";
+ ItemJournalLine: Record "Item Journal Line";
+ WarehouseJournalTemplate: Record "Warehouse Journal Template";
+ WarehouseJournalBatch: Record "Warehouse Journal Batch";
+ WarehouseJournalLine: Record "Warehouse Journal Line";
+ Item: Record Item;
+ isDirected: Boolean;
+ begin
+ isDirected := false;
+
+ if BinCode <> '' then begin
+ Bin.SetRange(Code, BinCode);
+ Bin.SetRange("Location Code", LocationCode);
+ Bin.FindFirst();
+
+ Location.Get(LocationCode);
+ if Location."Directed Put-away and Pick" then
+ isDirected := true;
+ end;
+
+ SetupItemJournal(ItemJournalTemplate, ItemJournalBatch);
+ if isDirected then begin
+ LibraryWarehouse.WarehouseJournalSetup(LocationCode, WarehouseJournalTemplate, WarehouseJournalBatch);
+
+ AssemblyLine.Reset();
+ AssemblyLine.SetRange("Document Type", AssemblyHeader."Document Type");
+ AssemblyLine.SetRange("Document No.", AssemblyHeader."No.");
+ AssemblyLine.SetRange(Type, AssemblyLine.Type::Item);
+ if AssemblyLine.FindSet() then
+ repeat
+ LibraryWarehouse.CreateWhseJournalLine(WarehouseJournalLine, WarehouseJournalTemplate.Name, WarehouseJournalBatch.Name,
+ LocationCode, Bin."Zone Code", BinCode,
+ WarehouseJournalLine."Entry Type"::"Positive Adjmt.", AssemblyLine."No.", AssemblyLine.Quantity + QtySupplement);
+ until AssemblyLine.Next() = 0;
+
+ LibraryWarehouse.RegisterWhseJournalLine(WarehouseJournalTemplate.Name, WarehouseJournalBatch.Name, LocationCode,
+ true);
+
+ // Add to inventory
+ Item.SetRange("Location Filter", LocationCode);
+ LibraryWarehouse.CalculateWhseAdjustment(Item, ItemJournalBatch);
+ end else begin
+ AssemblyLine.Reset();
+ AssemblyLine.SetRange("Document Type", AssemblyHeader."Document Type");
+ AssemblyLine.SetRange("Document No.", AssemblyHeader."No.");
+ AssemblyLine.SetRange(Type, AssemblyLine.Type::Item);
+ if AssemblyLine.FindSet() then
+ repeat
+ LibraryInventory.CreateItemJournalLine(ItemJournalLine, ItemJournalTemplate.Name, ItemJournalBatch.Name,
+ ItemJournalLine."Entry Type"::"Positive Adjmt.", AssemblyLine."No.", AssemblyLine.Quantity + QtySupplement);
+ ItemJournalLine.Validate("Posting Date", CalcDate('<-1D>', PostingDate));
+ ItemJournalLine.Validate("Document Date", CalcDate('<-1D>', ItemJournalLine."Posting Date"));
+ ItemJournalLine.Validate("Unit of Measure Code", AssemblyLine."Unit of Measure Code");
+ ItemJournalLine.Validate("Variant Code", AssemblyLine."Variant Code");
+ ItemJournalLine.Validate("Unit Cost", LibraryRandom.RandDec(50, 2));
+ ItemJournalLine.Validate("Location Code", LocationCode);
+ ItemJournalLine.Validate("Bin Code", BinCode);
+ ItemJournalLine.Modify(true);
+
+ until AssemblyLine.Next() = 0;
+ end;
+
+ LibraryInventory.PostItemJournalLine(ItemJournalTemplate.Name, ItemJournalBatch.Name);
+ end;
+
+ procedure AddItemInventory(AssemblyLine: Record "Assembly Line"; PostingDate: Date; LocationCode: Code[10]; BinCode: Code[20]; Qty: Decimal)
+ var
+ ItemJournalLine: Record "Item Journal Line";
+ ItemJournalTemplate: Record "Item Journal Template";
+ ItemJournalBatch: Record "Item Journal Batch";
+ Location: Record Location;
+ Bin: Record Bin;
+ WarehouseJournalLine: Record "Warehouse Journal Line";
+ WarehouseJournalTemplate: Record "Warehouse Journal Template";
+ WarehouseJournalBatch: Record "Warehouse Journal Batch";
+ Item: Record Item;
+ isDirected: Boolean;
+ begin
+ isDirected := false;
+
+ if BinCode <> '' then begin
+ Bin.SetRange(Code, BinCode);
+ Bin.SetRange("Location Code", LocationCode);
+ Bin.FindFirst();
+
+ Location.Get(LocationCode);
+ if Location."Directed Put-away and Pick" then
+ isDirected := true;
+ end;
+
+ SetupItemJournal(ItemJournalTemplate, ItemJournalBatch);
+ if isDirected then begin
+ LibraryWarehouse.WarehouseJournalSetup(LocationCode, WarehouseJournalTemplate, WarehouseJournalBatch);
+
+ LibraryWarehouse.CreateWhseJournalLine(WarehouseJournalLine, WarehouseJournalTemplate.Name, WarehouseJournalBatch.Name,
+ LocationCode, Bin."Zone Code", BinCode,
+ WarehouseJournalLine."Entry Type"::"Positive Adjmt.", AssemblyLine."No.", Qty);
+ LibraryWarehouse.RegisterWhseJournalLine(WarehouseJournalTemplate.Name, WarehouseJournalBatch.Name, LocationCode,
+ true);
+
+ // Add to inventory
+ Item.SetRange("No.", AssemblyLine."No.");
+ Item.SetRange("Location Filter", LocationCode);
+ LibraryWarehouse.CalculateWhseAdjustment(Item, ItemJournalBatch);
+ end else begin
+ LibraryInventory.CreateItemJournalLine(ItemJournalLine, ItemJournalTemplate.Name, ItemJournalBatch.Name,
+ ItemJournalLine."Entry Type"::"Positive Adjmt.", AssemblyLine."No.", Qty);
+ ItemJournalLine.Validate("Posting Date", CalcDate('<-1D>', PostingDate));
+ ItemJournalLine.Validate("Document Date", CalcDate('<-1D>', ItemJournalLine."Posting Date"));
+ ItemJournalLine.Validate("Unit of Measure Code", AssemblyLine."Unit of Measure Code");
+ ItemJournalLine.Validate("Variant Code", AssemblyLine."Variant Code");
+ ItemJournalLine.Validate("Unit Cost", LibraryRandom.RandDec(50, 2));
+ ItemJournalLine.Validate("Location Code", LocationCode);
+ ItemJournalLine.Validate("Bin Code", BinCode);
+ ItemJournalLine.Modify(true);
+ end;
+
+ LibraryInventory.PostItemJournalLine(ItemJournalTemplate.Name, ItemJournalBatch.Name);
+ end;
+
+ procedure AddAssemblyHeaderComment(AssemblyHeader: Record "Assembly Header"; AssemblyLineNo: Integer)
+ var
+ AssemblyCommentLine: Record "Assembly Comment Line";
+ begin
+ Clear(AssemblyCommentLine);
+ AssemblyCommentLine.Init();
+ AssemblyCommentLine.Validate("Document Type", AssemblyHeader."Document Type");
+ AssemblyCommentLine.Validate("Document No.", AssemblyHeader."No.");
+ AssemblyCommentLine.Validate("Document Line No.", AssemblyLineNo);
+ AssemblyCommentLine.Validate(Comment, 'Order:' + AssemblyHeader."No." + ', Line:' + Format(AssemblyLineNo));
+ AssemblyCommentLine.Insert(true);
+ end;
+
+ procedure AddAssemblyLineComment(var AssemblyCommentLine: Record "Assembly Comment Line"; DocType: Option; DocumentNo: Code[20]; DocumentLineNo: Integer; Date: Date; Comment: Text[80])
+ var
+ RecRef: RecordRef;
+ begin
+ Clear(AssemblyCommentLine);
+ AssemblyCommentLine.Validate("Document Type", DocType);
+ AssemblyCommentLine.Validate("Document No.", DocumentNo);
+ AssemblyCommentLine.Validate("Document Line No.", DocumentLineNo);
+ RecRef.GetTable(AssemblyCommentLine);
+ AssemblyCommentLine.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, AssemblyCommentLine.FieldNo("Line No.")));
+ AssemblyCommentLine.Insert(true);
+ AssemblyCommentLine.Validate(Date, Date);
+ AssemblyCommentLine.Validate(Comment, Comment);
+ AssemblyCommentLine.Modify(true);
+ end;
+
+ procedure AddEntityDimensions(Type: Enum "BOM Component Type"; No: Code[20])
+ var
+ TempDimension: Record Dimension temporary;
+ TempDimensionValue: Record "Dimension Value" temporary;
+ DefaultDimension: Record "Default Dimension";
+ AssemblyLine: Record "Assembly Line";
+ begin
+ CreateDimensionSetup(TempDimension, TempDimensionValue);
+ TempDimension.FindSet();
+ TempDimensionValue.FindSet();
+ repeat
+ case Type of
+ AssemblyLine.Type::Item:
+ LibraryDimension.CreateDefaultDimensionItem(DefaultDimension, No, TempDimension.Code, TempDimensionValue.Code);
+ AssemblyLine.Type::Resource:
+ LibraryDimension.CreateDefaultDimensionResource(DefaultDimension, No, TempDimension.Code, TempDimensionValue.Code);
+ end;
+ TempDimensionValue.Next();
+ until TempDimension.Next() = 0;
+ end;
+
+ procedure BatchPostAssemblyHeaders(var AssemblyHeader: Record "Assembly Header"; PostingDate: Date; ReplacePostingDate: Boolean; ExpectedError: Text[1024])
+ var
+ BatchPostAssemblyOrders: Report "Batch Post Assembly Orders";
+ begin
+ BatchPostAssemblyOrders.UseRequestPage(false);
+ BatchPostAssemblyOrders.InitializeRequest(PostingDate, ReplacePostingDate);
+ BatchPostAssemblyOrders.SetTableView(AssemblyHeader);
+ if ExpectedError = '' then
+ BatchPostAssemblyOrders.RunModal()
+ else begin
+ asserterror BatchPostAssemblyOrders.RunModal();
+ Assert.IsTrue(StrPos(GetLastErrorText, ExpectedError) > 0, 'Actual:' + GetLastErrorText);
+ ClearLastError();
+ end;
+ end;
+
+ procedure BlockDimensions(TableID: Integer; DimBlockType: Option; EntityNo: Code[20]; OrderNo: Code[20]; LineNo: Text[30]): Text[1024]
+ var
+ Dimension: Record Dimension;
+ DimensionValue: Record "Dimension Value";
+ DimensionCombination: Record "Dimension Combination";
+ DefaultDimension: Record "Default Dimension";
+ DimensionCode: array[5] of Code[20];
+ "Count": Integer;
+ ExpectedError: Text[1024];
+ begin
+ LibraryDimension.FindDefaultDimension(DefaultDimension, TableID, EntityNo);
+ DefaultDimension.FindSet();
+ for Count := 1 to DefaultDimension.Count do begin
+ DimensionCode[Count] := DefaultDimension."Dimension Code";
+ DefaultDimension.Next();
+ end;
+
+ ExpectedError := '';
+ case DimBlockType of
+ BlockType::Dimension:
+ begin
+ Dimension.Get(DefaultDimension."Dimension Code");
+ Dimension.Validate(Blocked, true);
+ Dimension.Modify(true);
+ ExpectedError := 'Dimension ' + Dimension.Code + ' is blocked.';
+ end;
+ BlockType::"Dimension Value":
+ begin
+ DimensionValue.Get(DefaultDimension."Dimension Code", DefaultDimension."Dimension Value Code");
+ DimensionValue.Validate(Blocked, true);
+ DimensionValue.Modify(true);
+ ExpectedError := 'Dimension Value ' + DimensionValue."Dimension Code" + ' - ' + DimensionValue.Code + ' is blocked.';
+ end;
+ BlockType::"Dimension Combination":
+ begin
+ DimensionCombination.Get(DimensionCode[1], DimensionCode[2]);
+ DimensionCombination.Validate("Combination Restriction", DimensionCombination."Combination Restriction"::Blocked);
+ DimensionCombination.Modify(true);
+ ExpectedError := StrSubstNo(ErrorDimCombination, OrderNo, LineNo, DimensionCode[1], DimensionCode[2]);
+ end;
+ end;
+
+ exit(ExpectedError);
+ end;
+
+ procedure BlockOrderDimensions(AssemblyHeader: Record "Assembly Header"; HeaderBlockType: Option; CompBlockType: Option): Text[1024]
+ var
+ AssemblyLine: Record "Assembly Line";
+ TableID: Integer;
+ HeaderError: Text[1024];
+ CompError: Text[1024];
+ begin
+ AssemblyLine.SetRange("Document Type", AssemblyHeader."Document Type");
+ AssemblyLine.SetRange("Document No.", AssemblyHeader."No.");
+ if AssemblyLine.FindFirst() then begin
+ case AssemblyLine.Type of
+ AssemblyLine.Type::Item:
+ TableID := 27;
+ AssemblyLine.Type::Resource:
+ TableID := 156;
+ AssemblyLine.Type::" ":
+ begin
+ TableID := 0;
+ AssemblyLine.TestField("Dimension Set ID", 0);
+ end;
+ end;
+ CompError := BlockDimensions(TableID, CompBlockType, AssemblyLine."No.",
+ AssemblyLine."Document No.", ', line no. ' + Format(AssemblyLine."Line No."));
+ end;
+
+ HeaderError := BlockDimensions(27, HeaderBlockType, AssemblyHeader."Item No.", AssemblyHeader."No.", '');
+
+ if HeaderError <> '' then
+ exit(HeaderError);
+ if CompError <> '' then
+ exit(CompError);
+ exit('');
+ end;
+
+ procedure CalcExpectedStandardCost(var MaterialCost: Decimal; var CapacityCost: Decimal; var CapOverhead: Decimal; ParentItemNo: Code[20]): Decimal
+ var
+ BOMComponent: Record "BOM Component";
+ Item: Record Item;
+ Item1: Record Item;
+ Resource: Record Resource;
+ ItemUnitOfMeasure: Record "Item Unit of Measure";
+ ResourceUnitOfMeasure: Record "Resource Unit of Measure";
+ ExpectedCost: Decimal;
+ LotSize: Decimal;
+ LineCost: Decimal;
+ begin
+ ExpectedCost := 0;
+ MaterialCost := 0;
+ CapacityCost := 0;
+ CapOverhead := 0;
+ BOMComponent.SetRange("Parent Item No.", ParentItemNo);
+ Item.Get(ParentItemNo);
+
+ if BOMComponent.FindSet() then
+ repeat
+ case BOMComponent.Type of
+ BOMComponent.Type::Item:
+ begin
+ Item1.Get(BOMComponent."No.");
+ ItemUnitOfMeasure.Get(Item1."No.", BOMComponent."Unit of Measure Code");
+ LineCost := Item1."Unit Cost" * BOMComponent."Quantity per" * ItemUnitOfMeasure."Qty. per Unit of Measure";
+ ExpectedCost += LineCost;
+ MaterialCost += LineCost;
+ end;
+ BOMComponent.Type::Resource:
+ begin
+ Resource.Get(BOMComponent."No.");
+ ResourceUnitOfMeasure.Get(Resource."No.", BOMComponent."Unit of Measure Code");
+ if (BOMComponent."Resource Usage Type" = BOMComponent."Resource Usage Type"::Direct) or (Item."Lot Size" = 0) then
+ LotSize := 1
+ else
+ LotSize := Item."Lot Size";
+
+ LineCost := (Resource."Unit Cost" * BOMComponent."Quantity per" * ResourceUnitOfMeasure."Qty. per Unit of Measure"
+ ) / LotSize;
+ CapOverhead += LineCost - Resource."Direct Unit Cost" *
+ BOMComponent."Quantity per" * ResourceUnitOfMeasure."Qty. per Unit of Measure" / LotSize;
+ CapacityCost += LineCost;
+ ExpectedCost += LineCost;
+ end
+ end;
+ until BOMComponent.Next() = 0;
+
+ if ExpectedCost = 0 then
+ exit(Item."Standard Cost");
+ ExpectedCost := ExpectedCost * (1 + Item."Indirect Cost %" / 100) + Item."Overhead Rate";
+
+ MaterialCost := Round(MaterialCost, LibraryERM.GetUnitAmountRoundingPrecision());
+ CapacityCost := Round(CapacityCost, LibraryERM.GetUnitAmountRoundingPrecision());
+ CapOverhead := Round(CapOverhead, LibraryERM.GetUnitAmountRoundingPrecision());
+ exit(Round(ExpectedCost, LibraryERM.GetUnitAmountRoundingPrecision()));
+ end;
+
+ procedure CalcExpectedPrice(ParentItemNo: Code[20]): Decimal
+ var
+ Item: Record Item;
+ BOMComponent: Record "BOM Component";
+ ItemUnitOfMeasure: Record "Item Unit of Measure";
+ Resource: Record Resource;
+ ResUnitOfMeasure: Record "Resource Unit of Measure";
+ ExpectedPrice: Decimal;
+ begin
+ ExpectedPrice := 0;
+ BOMComponent.SetRange("Parent Item No.", ParentItemNo);
+ BOMComponent.SetRange(Type, BOMComponent.Type::Item);
+ if BOMComponent.FindSet() then
+ repeat
+ Item.Get(BOMComponent."No.");
+ ItemUnitOfMeasure.Get(Item."No.", BOMComponent."Unit of Measure Code");
+ ExpectedPrice += Item."Unit Price" * BOMComponent."Quantity per" * ItemUnitOfMeasure."Qty. per Unit of Measure";
+ until BOMComponent.Next() = 0;
+
+ Item.Get(ParentItemNo);
+ BOMComponent.SetRange(Type, BOMComponent.Type::Resource);
+ if BOMComponent.FindSet() then
+ repeat
+ Resource.Get(BOMComponent."No.");
+ ResUnitOfMeasure.Get(Resource."No.", BOMComponent."Unit of Measure Code");
+ ExpectedPrice += Resource."Unit Price" * BOMComponent."Quantity per" * ResUnitOfMeasure."Qty. per Unit of Measure"
+ until BOMComponent.Next() = 0;
+
+ if ExpectedPrice = 0 then
+ exit(Item."Unit Price");
+ exit(Round(ExpectedPrice, LibraryERM.GetUnitAmountRoundingPrecision()));
+ end;
+
+ procedure CalcOrderCostAmount(var MaterialCost: Decimal; var ResourceCost: Decimal; var ResourceOvhd: Decimal; var AssemblyOvhd: Decimal; AssemblyHeaderNo: Code[20]): Decimal
+ var
+ Item: Record Item;
+ AssemblyLine: Record "Assembly Line";
+ AssemblyHeader: Record "Assembly Header";
+ ExpectedCost: Decimal;
+ Overhead: Decimal;
+ IndirectCost: Decimal;
+ UnitCost: Decimal;
+ LineCost: Decimal;
+ LineOverhead: Decimal;
+ begin
+ ExpectedCost := 0;
+ MaterialCost := 0;
+ ResourceCost := 0;
+ ResourceOvhd := 0;
+
+ AssemblyLine.SetCurrentKey("Document Type", "Document No.", Type);
+ AssemblyLine.SetRange("Document Type", AssemblyLine."Document Type"::Order);
+ AssemblyLine.SetRange("Document No.", AssemblyHeaderNo);
+ AssemblyLine.SetFilter(Type, '<>%1', AssemblyLine.Type::" ");
+ if AssemblyLine.FindSet() then
+ repeat
+ GetCostInformation(UnitCost, Overhead, IndirectCost, AssemblyLine.Type, AssemblyLine."No.", '', '');
+ LineOverhead := Overhead * AssemblyLine.Quantity * AssemblyLine."Qty. per Unit of Measure";
+ LineCost := AssemblyLine."Unit Cost" * AssemblyLine.Quantity;
+ if AssemblyLine.Type = AssemblyLine.Type::Item then
+ MaterialCost += LineCost
+ else begin
+ ResourceCost += LineCost;
+ ResourceOvhd += LineOverhead;
+ end
+ until AssemblyLine.Next() = 0;
+
+ AssemblyHeader.Get(AssemblyHeader."Document Type"::Order, AssemblyHeaderNo);
+ Item.Get(AssemblyHeader."Item No.");
+ AssemblyOvhd := Item."Indirect Cost %" / 100 * (MaterialCost + ResourceCost + ResourceOvhd) +
+ Item."Overhead Rate" * AssemblyHeader.Quantity * AssemblyHeader."Qty. per Unit of Measure";
+
+ if Item."Costing Method" = Item."Costing Method"::Standard then
+ exit((Item."Standard Cost" * (100 + Item."Indirect Cost %") / 100 + Item."Overhead Rate") *
+ AssemblyHeader.Quantity * AssemblyHeader."Qty. per Unit of Measure");
+
+ MaterialCost := Round(MaterialCost, LibraryERM.GetAmountRoundingPrecision());
+ ResourceCost := Round(ResourceCost, LibraryERM.GetAmountRoundingPrecision());
+ ResourceOvhd := Round(ResourceOvhd, LibraryERM.GetAmountRoundingPrecision());
+ AssemblyOvhd := Round(AssemblyOvhd, LibraryERM.GetAmountRoundingPrecision());
+ ExpectedCost := MaterialCost + ResourceCost + ResourceOvhd + AssemblyOvhd;
+ exit(Round(ExpectedCost, LibraryERM.GetAmountRoundingPrecision()));
+ end;
+
+ procedure ChangeResourceUsage(AssemblyHeaderNo: Code[20])
+ var
+ AssemblyLine: Record "Assembly Line";
+ begin
+ AssemblyLine.SetCurrentKey("Document Type", "Document No.", Type);
+ AssemblyLine.SetRange("Document Type", AssemblyLine."Document Type"::Order);
+ AssemblyLine.SetRange("Document No.", AssemblyHeaderNo);
+ AssemblyLine.SetRange(Type, AssemblyLine.Type::Resource);
+ AssemblyLine.Next(LibraryRandom.RandInt(AssemblyLine.Count));
+
+ if AssemblyLine."Resource Usage Type" = AssemblyLine."Resource Usage Type"::Fixed then
+ AssemblyLine.Validate("Resource Usage Type", AssemblyLine."Resource Usage Type"::Direct)
+ else
+ AssemblyLine.Validate("Resource Usage Type", AssemblyLine."Resource Usage Type"::Fixed)
+ end;
+
+ procedure ClearOrderPostingSetup(OrderClearType: Option; InvtPostingGroup: Code[20]; GenProdPostingGroup: Code[20]; LocationCode: Code[10]): Text[1024]
+ var
+ InventoryPostingSetup: Record "Inventory Posting Setup";
+ GeneralPostingSetup: Record "General Posting Setup";
+ ExpectedError: Text[1024];
+ begin
+ ExpectedError := '';
+ case OrderClearType of
+ ClearType::"Posting Group Setup":
+ begin
+ InventoryPostingSetup.SetRange("Invt. Posting Group Code", InvtPostingGroup);
+ if InventoryPostingSetup.FindFirst() then
+ InventoryPostingSetup.DeleteAll();
+ GeneralPostingSetup.SetRange("Gen. Prod. Posting Group", GenProdPostingGroup);
+ if GeneralPostingSetup.FindFirst() then
+ GeneralPostingSetup.DeleteAll();
+ ExpectedError := ErrorPostingSetup;
+ end;
+ ClearType::"Location Posting Setup":
+ begin
+ InventoryPostingSetup.SetRange("Location Code", LocationCode);
+ InventoryPostingSetup.SetRange("Invt. Posting Group Code", InvtPostingGroup);
+ if InventoryPostingSetup.FindFirst() then
+ InventoryPostingSetup.DeleteAll();
+ ExpectedError := ErrorInvtPostingSetup;
+ end;
+ end;
+ exit(ExpectedError);
+ end;
+
+ local procedure CreateAssemblyHeaderLocal(var AssemblyHeader: Record "Assembly Header"; DueDate: Date; ParentItemNo: Code[20]; LocationCode: Code[10]; Quantity: Decimal; DocumentType: Enum "Assembly Document Type"; VariantCode: Code[10]): Code[20]
+ begin
+ Clear(AssemblyHeader);
+ AssemblyHeader."Document Type" := DocumentType;
+ AssemblyHeader.Insert(true);
+ AssemblyHeader.Validate("Item No.", ParentItemNo);
+ AssemblyHeader.Validate("Location Code", LocationCode);
+ AssemblyHeader.Validate("Due Date", DueDate);
+ AssemblyHeader.Validate(Quantity, Quantity);
+ if VariantCode <> '' then
+ AssemblyHeader.Validate("Variant Code", VariantCode);
+ AssemblyHeader.Modify(true);
+
+ exit(AssemblyHeader."No.");
+ end;
+
+ procedure CreateAssemblyHeader(var AssemblyHeader: Record "Assembly Header"; DueDate: Date; ParentItemNo: Code[20]; LocationCode: Code[10]; Quantity: Decimal; VariantCode: Code[10]): Code[20]
+ begin
+ exit(
+ CreateAssemblyHeaderLocal(
+ AssemblyHeader, DueDate, ParentItemNo, LocationCode, Quantity, AssemblyHeader."Document Type"::Order, VariantCode));
+ end;
+
+ procedure CreateAssemblyQuote(var AssemblyHeader: Record "Assembly Header"; DueDate: Date; ParentItemNo: Code[20]; LocationCode: Code[10]; Quantity: Decimal; VariantCode: Code[10]): Code[20]
+ begin
+ exit(
+ CreateAssemblyHeaderLocal(
+ AssemblyHeader, DueDate, ParentItemNo, LocationCode, Quantity, AssemblyHeader."Document Type"::Quote, VariantCode));
+ end;
+
+ procedure CreateAssemblyLine(AssemblyHeader: Record "Assembly Header"; var AssemblyLine: Record "Assembly Line"; Type: Enum "BOM Component Type"; No: Code[20]; UOMCode: Code[10]; Quantity: Decimal; QtyPer: Decimal; Desc: Text[100])
+ var
+ RecRef: RecordRef;
+ begin
+ Clear(AssemblyLine);
+ AssemblyLine."Document Type" := AssemblyHeader."Document Type";
+ AssemblyLine."Document No." := AssemblyHeader."No.";
+ RecRef.GetTable(AssemblyLine);
+ AssemblyLine.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, AssemblyLine.FieldNo("Line No.")));
+ AssemblyLine.Insert(true);
+ AssemblyLine.Validate(Type, Type);
+ AssemblyLine.Validate("No.", No);
+ if AssemblyHeader.Quantity <> 0 then
+ AssemblyLine."Quantity per" := AssemblyLine.CalcQuantityPer(Quantity);
+ AssemblyLine.Validate(Quantity, Quantity);
+ AssemblyLine.Validate("Unit of Measure Code", UOMCode);
+ if QtyPer <> 0 then
+ AssemblyLine.Validate("Quantity per", QtyPer);
+ AssemblyLine.Validate(Description, Desc);
+ AssemblyLine.Modify(true);
+ end;
+
+ procedure CreateAssemblyLines(CostingMethod: Enum "Costing Method"; AssemblyHeaderNo: Code[20]; NoOfItems: Integer; NoOfResources: Integer)
+ var
+ AssemblyHeader: Record "Assembly Header";
+ TempItem: Record Item temporary;
+ TempResource: Record Resource temporary;
+ AssemblyLine: Record "Assembly Line";
+ begin
+ SetupComponents(TempItem, TempResource, CostingMethod, NoOfItems, NoOfResources, '', '');
+ AssemblyHeader.Get(AssemblyHeader."Document Type"::Order, AssemblyHeaderNo);
+
+ if TempItem.FindSet() then
+ repeat
+ CreateAssemblyLine(AssemblyHeader, AssemblyLine, "BOM Component Type"::Item, TempItem."No.",
+ GetUnitOfMeasureCode("BOM Component Type"::Item, TempItem."No.", true), LibraryRandom.RandDec(20, 2), 0, '');
+ until TempItem.Next() = 0;
+
+ if TempResource.FindSet() then
+ repeat
+ CreateAssemblyLine(AssemblyHeader, AssemblyLine, "BOM Component Type"::Resource, TempResource."No.",
+ GetUnitOfMeasureCode("BOM Component Type"::Resource, TempResource."No.", true), LibraryRandom.RandDec(20, 2), 0, '');
+ until TempResource.Next() = 0;
+ end;
+
+ procedure CreateAssemblyList(CostingMethod: Enum "Costing Method"; ParentItemNo: Code[20]; UseBaseUnitOfMeasure: Boolean; NoOfItems: Integer; NoOfResources: Integer; NoOfTexts: Integer; QtyPerFactor: Integer; GenProdPostingGroup: Code[20]; InventoryPostingGroup: Code[20])
+ var
+ BOMComponent: Record "BOM Component";
+ TempItem: Record Item temporary;
+ TempResource: Record Resource temporary;
+ CompCount: Integer;
+ begin
+ SetupComponents(TempItem, TempResource, CostingMethod, NoOfItems, NoOfResources, GenProdPostingGroup, InventoryPostingGroup);
+
+ if TempItem.FindSet() then
+ repeat
+ CreateAssemblyListComponent(BOMComponent.Type::Item, TempItem."No.", ParentItemNo, '',
+ BOMComponent."Resource Usage Type"::Direct, QtyPerFactor * LibraryRandom.RandDec(20, 5), UseBaseUnitOfMeasure);
+ until TempItem.Next() = 0;
+
+ CompCount := 1;
+ if TempResource.FindSet() then
+ repeat
+ if CompCount mod 2 = 0 then
+ CreateAssemblyListComponent(BOMComponent.Type::Resource, TempResource."No.", ParentItemNo, '',
+ BOMComponent."Resource Usage Type"::Direct, QtyPerFactor * LibraryRandom.RandDec(20, 5), UseBaseUnitOfMeasure)
+ else
+ CreateAssemblyListComponent(BOMComponent.Type::Resource, TempResource."No.", ParentItemNo, '',
+ BOMComponent."Resource Usage Type"::Fixed, QtyPerFactor * LibraryRandom.RandDec(20, 5), UseBaseUnitOfMeasure);
+ CompCount += 1;
+ until TempResource.Next() = 0;
+
+ for CompCount := 1 to NoOfTexts do
+ CreateAssemblyListComponent(BOMComponent.Type::" ", '', ParentItemNo, '',
+ BOMComponent."Resource Usage Type"::Direct, 0, UseBaseUnitOfMeasure);
+
+ Commit();
+ end;
+
+ procedure CreateAssemblyListComponent(ComponentType: Enum "BOM Component Type"; ComponentNo: Code[20]; ParentItemNo: Code[20]; VariantCode: Code[10]; ResourceUsage: Option; Qty: Decimal; UseBaseUnitOfMeasure: Boolean)
+ var
+ BOMComponent: Record "BOM Component";
+ begin
+ LibraryInventory.CreateBOMComponent(
+ BOMComponent, ParentItemNo, ComponentType, ComponentNo, Qty, GetUnitOfMeasureCode(ComponentType, ComponentNo, UseBaseUnitOfMeasure));
+ if ComponentType = BOMComponent.Type::Resource then
+ BOMComponent.Validate("Resource Usage Type", ResourceUsage);
+ BOMComponent.Validate("Variant Code", VariantCode);
+ BOMComponent.Validate(
+ Description, LibraryUtility.GenerateRandomCode(BOMComponent.FieldNo(Description), DATABASE::"BOM Component"));
+ BOMComponent.Modify(true);
+ Commit();
+ end;
+
+ procedure CreateAssemblySetup(var AssemblySetup: Record "Assembly Setup"; LocationCode: Code[10]; DimensionsFrom: Option; PostedOrdersNo: Code[20])
+ begin
+ if AssemblySetup."Assembly Order Nos." = '' then
+ AssemblySetup.Validate("Assembly Order Nos.",
+ LibraryUtility.GetGlobalNoSeriesCode());
+ if AssemblySetup."Posted Assembly Order Nos." = '' then
+ AssemblySetup.Validate("Posted Assembly Order Nos.", LibraryUtility.GetGlobalNoSeriesCode());
+ if AssemblySetup."Assembly Quote Nos." = '' then
+ AssemblySetup.Validate("Assembly Quote Nos.", LibraryUtility.GetGlobalNoSeriesCode());
+ if AssemblySetup."Blanket Assembly Order Nos." = '' then
+ AssemblySetup.Validate("Blanket Assembly Order Nos.", LibraryUtility.GetGlobalNoSeriesCode());
+ AssemblySetup.Validate("Default Location for Orders", LocationCode);
+ AssemblySetup.Validate("Copy Component Dimensions from", DimensionsFrom);
+ AssemblySetup.Validate("Posted Assembly Order Nos.", PostedOrdersNo);
+ AssemblySetup.Modify(true);
+ end;
+
+#if not CLEAN26
+ [Obsolete('Moved to codeunit Library Manufacturing as CreateProductionBOM', '26.0')]
+ procedure CreateBOM(var Item: Record Item; NoOfComps: Integer)
+ var
+ LibraryManufacturing: Codeunit "Library - Manufacturing";
+ begin
+ LibraryManufacturing.CreateProductionBOM(Item, NoOfComps);
+ end;
+#endif
+
+#if not CLEAN26
+ [Obsolete('Moved to codeunit Library Manufacturing as CreateProductionRouting', '26.0')]
+ procedure CreateRouting(var Item: Record Item; NoOfLines: Integer)
+ var
+ LibraryManufacturing: Codeunit "Library - Manufacturing";
+ begin
+ LibraryManufacturing.CreateProductionRouting(Item, NoOfLines);
+ end;
+#endif
+
+ procedure CreateDimensionSetup(var TempDimension: Record Dimension temporary; var TempDimensionValue: Record "Dimension Value" temporary)
+ var
+ DimensionValue: Record "Dimension Value";
+ DimensionCombination: Record "Dimension Combination";
+ Dimension: Record Dimension;
+ "Count": Integer;
+ DimensionCode: array[5] of Code[20];
+ begin
+ for Count := 1 to 2 do begin
+ LibraryDimension.CreateDimension(Dimension);
+ DimensionCode[Count] := Dimension.Code;
+ TempDimension := Dimension;
+ TempDimension.Insert();
+ LibraryDimension.CreateDimensionValue(DimensionValue, Dimension.Code);
+ TempDimensionValue := DimensionValue;
+ TempDimensionValue.Insert();
+ end;
+ LibraryDimension.CreateDimensionCombination(DimensionCombination, DimensionCode[1], DimensionCode[2]);
+ end;
+
+ procedure CreateGLAccount(var GLAccount: Record "G/L Account"; IncomeBalance: Enum "G/L Account Report Type"; Name: Text[30])
+ begin
+ LibraryERM.CreateGLAccount(GLAccount);
+ GLAccount.Validate("Income/Balance", IncomeBalance);
+ GLAccount.Validate("Debit/Credit", GLAccount."Debit/Credit"::Both);
+ GLAccount.Validate("Account Type", GLAccount."Account Type"::Posting);
+ GLAccount.Validate(Name, Name);
+ GLAccount.Modify(true);
+ end;
+
+ procedure CreateItem(var Item: Record Item; CostingMethod: Enum "Costing Method"; ReplenishmentMethod: Enum "Replenishment System"; GenProdPostingGroup: Code[20]; InventoryPostingGroup: Code[20]): Code[20]
+ var
+ GeneralPostingSetup: Record "General Posting Setup";
+ ItemUnitOfMeasure: Record "Item Unit of Measure";
+ UnitOfMeasure: Record "Unit of Measure";
+ VATPostingSetup: Record "VAT Posting Setup";
+ begin
+ LibraryInventory.CreateItem(Item);
+ Item.Validate("Replenishment System", ReplenishmentMethod);
+ Item.Validate("Costing Method", CostingMethod);
+
+ if ReplenishmentMethod <> Item."Replenishment System"::Assembly then begin
+ if CostingMethod = Item."Costing Method"::Standard then
+ Item.Validate("Standard Cost", LibraryRandom.RandDec(25, 2))
+ else
+ Item.Validate("Unit Cost", LibraryRandom.RandDec(25, 2));
+ Item.Validate("Unit Price", Item."Unit Cost" + LibraryRandom.RandDec(25, 2));
+ end else begin
+ Item.Validate("Standard Cost", 0);
+ Item.Validate("Unit Cost", 0);
+ Item.Validate("Unit Price", 0);
+ end;
+
+ Item.Validate("Last Direct Cost", Item."Unit Cost");
+ if InventoryPostingGroup <> '' then
+ Item.Validate("Inventory Posting Group", InventoryPostingGroup);
+ if GenProdPostingGroup = '' then begin
+ LibraryERM.FindGeneralPostingSetupInvtToGL(GeneralPostingSetup);
+ GenProdPostingGroup := GeneralPostingSetup."Gen. Prod. Posting Group";
+ end;
+ Item.Validate("Gen. Prod. Posting Group", GenProdPostingGroup);
+ Clear(VATPostingSetup);
+ LibraryERM.FindVATPostingSetup(VATPostingSetup, VATPostingSetup."VAT Calculation Type"::"Normal VAT");
+ Item.Validate("VAT Prod. Posting Group", VATPostingSetup."VAT Prod. Posting Group");
+ Item.Modify(true);
+
+ UnitOfMeasure.SetFilter(Code, '<>%1', Item."Base Unit of Measure");
+ UnitOfMeasure.FindFirst();
+ LibraryInventory.CreateItemUnitOfMeasure(
+ ItemUnitOfMeasure, Item."No.", UnitOfMeasure.Code, LibraryRandom.RandInt(10));
+ exit(Item."No.");
+ end;
+
+ procedure CreateInvtPostingSetup(var InventoryPostingSetup: Record "Inventory Posting Setup"; LocationCode: Code[10]; InvtPostingGroupCode: Code[20]; InvtAccount: Code[20]; MatVarAccount: Code[20]; CapVarAcc: Code[20]; CapOvhdVarAcc: Code[20]; MfgOvhdVarAcc: Code[20]; InvtAccInterim: Code[20])
+ var
+ GLAccount: Record "G/L Account";
+ begin
+ Clear(InventoryPostingSetup);
+ InventoryPostingSetup.Init();
+ InventoryPostingSetup.Validate("Location Code", LocationCode);
+ InventoryPostingSetup.Validate("Invt. Posting Group Code", InvtPostingGroupCode);
+ InventoryPostingSetup.Validate("Inventory Account", InvtAccount);
+ InventoryPostingSetup.Validate("Material Variance Account", MatVarAccount);
+ InventoryPostingSetup.Validate("Capacity Variance Account", CapVarAcc);
+ InventoryPostingSetup.Validate("Cap. Overhead Variance Account", CapOvhdVarAcc);
+ InventoryPostingSetup.Validate("Mfg. Overhead Variance Account", MfgOvhdVarAcc);
+ InventoryPostingSetup.Validate("Inventory Account (Interim)", InvtAccInterim);
+ LibraryERM.CreateGLAccount(GLAccount);
+ InventoryPostingSetup.Validate("WIP Account", GLAccount."No.");
+ OnBeforeInsertInventoryPostingSetup(InventoryPostingSetup);
+ InventoryPostingSetup.Insert(true);
+ end;
+
+ procedure CreateInvtMovement(AssemblyHeaderNo: Code[20]; NewCreateInvtPutAway: Boolean; NewCreateInvtPick: Boolean; NewCreateInvtMovement: Boolean)
+ var
+ TmpWarehouseRequest: Record "Warehouse Request";
+ WarehouseRequest: Record "Warehouse Request";
+ CreateInvtPutAwayPick: Report "Create Invt Put-away/Pick/Mvmt";
+ begin
+ WarehouseRequest.SetCurrentKey("Source Document", "Source No.");
+ WarehouseRequest.SetRange("Source Document", WarehouseRequest."Source Document"::"Assembly Consumption");
+ WarehouseRequest.SetRange("Source No.", AssemblyHeaderNo);
+
+ Commit();
+ CreateInvtPutAwayPick.InitializeRequest(
+ NewCreateInvtPutAway, NewCreateInvtPick, NewCreateInvtMovement, false, false);
+ if WarehouseRequest.HasFilter then
+ TmpWarehouseRequest.CopyFilters(WarehouseRequest)
+ else begin
+ WarehouseRequest.Get(WarehouseRequest.Type,
+ WarehouseRequest."Location Code",
+ WarehouseRequest."Source Type",
+ WarehouseRequest."Source Subtype",
+ WarehouseRequest."Source No.");
+ TmpWarehouseRequest.SetRange(Type, WarehouseRequest.Type);
+ TmpWarehouseRequest.SetRange("Location Code", WarehouseRequest."Location Code");
+ TmpWarehouseRequest.SetRange("Source Type", WarehouseRequest."Source Type");
+ TmpWarehouseRequest.SetRange("Source Subtype", WarehouseRequest."Source Subtype");
+ TmpWarehouseRequest.SetRange("Source No.", WarehouseRequest."Source No.");
+ end;
+ CreateInvtPutAwayPick.SetTableView(TmpWarehouseRequest);
+ CreateInvtPutAwayPick.UseRequestPage(false);
+ CreateInvtPutAwayPick.RunModal();
+ end;
+
+ procedure AsmOrder_CreateInvtMovement(var WarehouseRequest: Record "Warehouse Request"; NewCreateInvtPutAway: Boolean; NewCreateInvtPick: Boolean; NewCreateInvtMovement: Boolean; NewPrintDocument: Boolean; NewShowError: Boolean)
+ var
+ TmpWarehouseRequest: Record "Warehouse Request";
+ CreateInvtPutAwayPick: Report "Create Invt Put-away/Pick/Mvmt";
+ begin
+ Commit();
+ CreateInvtPutAwayPick.InitializeRequest(
+ NewCreateInvtPutAway, NewCreateInvtPick, NewCreateInvtMovement, NewPrintDocument, NewShowError);
+ if WarehouseRequest.HasFilter then
+ TmpWarehouseRequest.CopyFilters(WarehouseRequest)
+ else begin
+ WarehouseRequest.Get(WarehouseRequest.Type,
+ WarehouseRequest."Location Code",
+ WarehouseRequest."Source Type",
+ WarehouseRequest."Source Subtype",
+ WarehouseRequest."Source No.");
+ TmpWarehouseRequest.SetRange(Type, WarehouseRequest.Type);
+ TmpWarehouseRequest.SetRange("Location Code", WarehouseRequest."Location Code");
+ TmpWarehouseRequest.SetRange("Source Type", WarehouseRequest."Source Type");
+ TmpWarehouseRequest.SetRange("Source Subtype", WarehouseRequest."Source Subtype");
+ TmpWarehouseRequest.SetRange("Source No.", WarehouseRequest."Source No.");
+ end;
+ CreateInvtPutAwayPick.SetTableView(TmpWarehouseRequest);
+ CreateInvtPutAwayPick.UseRequestPage(false);
+ CreateInvtPutAwayPick.RunModal();
+ end;
+
+ procedure CreateWhsePick(AssemblyHeader: Record "Assembly Header"; AssignedUserID: Code[50]; SortingMethod: Option; SetBreakBulkFilter: Boolean; DoNotFillQtyToHandle: Boolean; PrintDocument: Boolean)
+ begin
+ AssemblyHeader.CreatePick(false, AssignedUserID, SortingMethod, SetBreakBulkFilter, DoNotFillQtyToHandle, PrintDocument);
+ end;
+
+ procedure CreateMultipleLvlTree(var Item: Record Item; var Item1: Record Item; ReplenishmentMethod: Enum "Replenishment System"; CostingMethod: Enum "Costing Method"; TreeDepth: Integer; NoOfComps: Integer)
+ var
+ BOMComponent: Record "BOM Component";
+ Item2: Record Item;
+ Depth: Integer;
+ BOMCreated: Boolean;
+ begin
+ CreateItem(Item, CostingMethod, ReplenishmentMethod, '', '');
+ BOMCreated := false;
+ OnCreateMultipleLvlTreeOnCreateBOM(Item, NoOfComps, BOMCreated);
+ if not BOMCreated then
+ CreateAssemblyList(Item."Costing Method"::Standard, Item."No.", true, NoOfComps, NoOfComps, NoOfComps, 1, '', '');
+
+ CreateItem(Item1, Item."Costing Method"::Standard, Item."Replenishment System"::Assembly, '', '');
+ CreateAssemblyList(Item."Costing Method"::Standard, Item1."No.", true, 2, 1, 0, 1, '', '');
+ CreateAssemblyListComponent(
+ BOMComponent.Type::Item, Item."No.", Item1."No.", '', BOMComponent."Resource Usage Type"::Direct,
+ LibraryRandom.RandDec(20, 2), true);
+
+ for Depth := 2 to TreeDepth do begin
+ CreateItem(Item2, Item."Costing Method"::Standard, Item."Replenishment System"::Assembly, '', '');
+ CreateAssemblyList(Item."Costing Method"::Standard, Item2."No.", true, 2, 1, 0, 1, '', '');
+ CreateAssemblyListComponent(BOMComponent.Type::Item, Item1."No.", Item2."No.", '', BOMComponent."Resource Usage Type"::Direct,
+ LibraryRandom.RandDec(20, 2), true);
+ Item := Item1;
+ Item1 := Item2;
+ Item.Find();
+ Item.Validate("Replenishment System", ReplenishmentMethod);
+ Item.Modify(true);
+ OnCreateMultipleLvlTreeOnCreateBOM(Item, NoOfComps, BOMCreated);
+ end;
+ Commit();
+ end;
+
+ procedure CreateItemSubstitution(var ItemSubstitution: Record "Item Substitution"; ItemNo: Code[20])
+ var
+ Item1: Record Item;
+ begin
+ CreateItem(Item1, Item1."Costing Method"::Standard, Item1."Replenishment System"::Purchase, '', '');
+ Clear(ItemSubstitution);
+ ItemSubstitution.Init();
+ ItemSubstitution.Validate(Type, ItemSubstitution.Type::Item);
+ ItemSubstitution.Validate("No.", ItemNo);
+ ItemSubstitution.Validate("Substitute Type", ItemSubstitution."Substitute Type"::Item);
+ ItemSubstitution.Validate("Substitute No.", Item1."No.");
+ ItemSubstitution.Insert();
+ end;
+
+ procedure CreateAdjustmentSource(AssemblyHeader: Record "Assembly Header"; PostingDate: Date; AdjustHeader: Boolean; AdjustmentSource: Option; ItemNo: Code[20]; ResourceNo: Code[20])
+ var
+ PurchaseHeader: Record "Purchase Header";
+ PurchaseLine: Record "Purchase Line";
+ Item: Record Item;
+ ItemJournalLine: Record "Item Journal Line";
+ Resource: Record Resource;
+ begin
+ if AdjustHeader then
+ ItemNo := AssemblyHeader."Item No.";
+ Item.Get(ItemNo);
+
+ case AdjustmentSource of
+ AdjSource::Purchase:
+ begin
+ LibraryPurchase.CreatePurchHeader(
+ PurchaseHeader, PurchaseHeader."Document Type"::Order, '');
+ LibraryPurchase.CreatePurchaseLine(
+ PurchaseLine, PurchaseHeader, PurchaseLine.Type::Item, ItemNo, LibraryRandom.RandInt(10));
+ PurchaseHeader.Validate(
+ "Vendor Invoice No.", LibraryUtility.GenerateRandomCode(PurchaseHeader.FieldNo("Vendor Invoice No."),
+ DATABASE::"Purchase Header"));
+ PurchaseHeader.Modify(true);
+ LibraryPurchase.PostPurchaseDocument(PurchaseHeader, true, true);
+ end;
+ AdjSource::Revaluation:
+ begin
+ RevaluateItem(Item, ItemJournalLine, Item."Unit Cost", PostingDate);
+ LibraryInventory.PostItemJournalLine(ItemJournalLine."Journal Template Name", ItemJournalLine."Journal Batch Name");
+ end;
+ AdjSource::"Item Card":
+ begin
+ Item."Unit Cost" := Item."Unit Cost" + LibraryRandom.RandDec(10, 2);
+ if Item."Costing Method" = Item."Costing Method"::Standard then
+ Item."Standard Cost" := Item."Standard Cost" + LibraryRandom.RandDec(10, 2);
+ Item.Modify(true);
+ end;
+ AdjSource::"Order Lines":
+ begin
+ ResourceNo := CreateResource(Resource, true, Item."Gen. Prod. Posting Group");
+ EditAssemblyLines(ChangeType::Add, "BOM Component Type"::Resource, "BOM Component Type"::Resource, ResourceNo,
+ AssemblyHeader."No.", true);
+ end;
+ AdjSource::Resource:
+ begin
+ Resource.Get(ResourceNo);
+ Resource."Unit Cost" := Resource."Unit Cost" + LibraryRandom.RandDec(10, 2);
+ Resource.Modify(true);
+ end
+ end;
+ end;
+
+ procedure CreateItemWithSKU(var Item: Record Item; CostingMethod: Enum "Costing Method"; ReplenishmentSystem: Enum "Replenishment System"; CreatePer: Enum "SKU Creation Method"; GenProdPostingGr: Code[20]; InvtPostingGr: Code[20]; LocationCode: Code[10])
+ var
+ ItemVariant: Record "Item Variant";
+ begin
+ CreateItem(Item, CostingMethod, ReplenishmentSystem, GenProdPostingGr, InvtPostingGr);
+ if CreatePer <> CreatePer::Location then
+ LibraryInventory.CreateVariant(ItemVariant, Item);
+ Item."Location Filter" := LocationCode;
+ Item.Modify();
+ Item.SetRange("Location Filter", LocationCode);
+ Item.SetRecFilter();
+ LibraryInventory.CreateStockKeepingUnit(Item, CreatePer, false, true);
+ UpdateSKUCards(Item);
+ end;
+
+ procedure CheckOrderDimensions(AssemblyHeader: Record "Assembly Header"; DimensionsFrom: Option)
+ var
+ AssemblyLine: Record "Assembly Line";
+ AssemblySetup: Record "Assembly Setup";
+ TableID: Integer;
+ begin
+ VerifyEntityDimensions(
+ DATABASE::Item, AssemblyHeader."Item No.", AssemblyHeader."Item No.", true, AssemblyHeader."Dimension Set ID");
+
+ AssemblyLine.SetRange("Document Type", AssemblyHeader."Document Type");
+ AssemblyLine.SetRange("Document No.", AssemblyHeader."No.");
+ if AssemblyLine.FindSet() then
+ repeat
+ case AssemblyLine.Type of
+ AssemblyLine.Type::Item:
+ TableID := DATABASE::Item;
+ AssemblyLine.Type::Resource:
+ TableID := DATABASE::Resource;
+ AssemblyLine.Type::" ":
+ begin
+ TableID := 0;
+ AssemblyLine.TestField("Dimension Set ID", 0);
+ end;
+ end;
+ VerifyEntityDimensions(
+ TableID, AssemblyLine."No.", AssemblyHeader."Item No.",
+ DimensionsFrom = AssemblySetup."Copy Component Dimensions from"::"Order Header",
+ AssemblyLine."Dimension Set ID");
+ until AssemblyLine.Next() = 0;
+ end;
+
+ procedure CreateResource(var Resource: Record Resource; UseRelatedUnitOfMeasure: Boolean; GenProdPostingGroup: Code[20]): Code[20]
+ var
+ GeneralPostingSetup: Record "General Posting Setup";
+ ResourceUnitOfMeasure: Record "Resource Unit of Measure";
+ UnitOfMeasure: Record "Unit of Measure";
+ VATPostingSetup: Record "VAT Posting Setup";
+ begin
+ LibraryERM.FindVATPostingSetup(VATPostingSetup, VATPostingSetup."VAT Calculation Type"::"Normal VAT");
+ LibraryResource.CreateResource(Resource, VATPostingSetup."VAT Bus. Posting Group");
+ UnitOfMeasure.SetFilter(Code, '<>%1', Resource."Base Unit of Measure");
+ UnitOfMeasure.FindFirst();
+
+ // Add a second non-base unit of measure.
+ Clear(ResourceUnitOfMeasure);
+ ResourceUnitOfMeasure.Init();
+ ResourceUnitOfMeasure.Validate("Resource No.", Resource."No.");
+ ResourceUnitOfMeasure.Validate(Code, UnitOfMeasure.Code);
+ ResourceUnitOfMeasure.Insert(true);
+ ResourceUnitOfMeasure.Validate("Qty. per Unit of Measure", LibraryRandom.RandInt(10));
+ ResourceUnitOfMeasure.Validate("Related to Base Unit of Meas.", UseRelatedUnitOfMeasure);
+ ResourceUnitOfMeasure.Modify(true);
+
+ if GenProdPostingGroup = '' then begin
+ LibraryERM.FindGeneralPostingSetupInvtToGL(GeneralPostingSetup);
+ GenProdPostingGroup := GeneralPostingSetup."Gen. Prod. Posting Group";
+ end;
+ Resource.Validate("Gen. Prod. Posting Group", GenProdPostingGroup);
+ Resource.Modify(true);
+
+ exit(Resource."No.")
+ end;
+
+ procedure DeleteAssemblyLine(ComponentType: Enum "BOM Component Type"; AssemblyHeaderNo: Code[20])
+ var
+ AssemblyLine: Record "Assembly Line";
+ begin
+ AssemblyLine.SetCurrentKey("Document Type", "Document No.", Type);
+ AssemblyLine.SetRange("Document Type", AssemblyLine."Document Type"::Order);
+ AssemblyLine.SetRange("Document No.", AssemblyHeaderNo);
+ AssemblyLine.SetRange(Type, ComponentType);
+ if not AssemblyLine.FindSet() then
+ exit;
+ AssemblyLine.Next(LibraryRandom.RandInt(AssemblyLine.Count));
+ AssemblyLine.Delete();
+ end;
+
+ procedure DeleteAssemblyLines(AssemblyHeaderNo: Code[20])
+ var
+ AssemblyLine: Record "Assembly Line";
+ begin
+ AssemblyLine.SetRange("Document No.", AssemblyHeaderNo);
+ AssemblyLine.DeleteAll();
+ end;
+
+ procedure DeleteAssemblyListComponent(ComponentType: Enum "BOM Component Type"; ParentItemNo: Code[20])
+ var
+ BOMComponent: Record "BOM Component";
+ begin
+ BOMComponent.SetRange("Parent Item No.", ParentItemNo);
+ BOMComponent.SetRange(Type, ComponentType);
+ if not BOMComponent.FindSet() then
+ exit;
+ BOMComponent.Next(LibraryRandom.RandInt(BOMComponent.Count));
+ BOMComponent.Delete();
+ end;
+
+ procedure DeleteAssemblyList(ParentItemNo: Code[20])
+ var
+ BOMComponent: Record "BOM Component";
+ begin
+ BOMComponent.SetRange("Parent Item No.", ParentItemNo);
+ BOMComponent.DeleteAll();
+ end;
+
+ procedure EditAssemblyListComponent(ComponentType: Enum "BOM Component Type"; NewComponentType: Enum "BOM Component Type"; NewComponentNo: Code[20]; ParentItemNo: Code[20]; ResourceUsage: Option; Qty: Decimal; UseBaseUnitOfMeasure: Boolean)
+ var
+ BOMComponent: Record "BOM Component";
+ begin
+ BOMComponent.SetRange("Parent Item No.", ParentItemNo);
+ BOMComponent.SetRange(Type, ComponentType);
+ if not BOMComponent.FindSet() then
+ exit;
+
+ BOMComponent.Next(LibraryRandom.RandInt(BOMComponent.Count));
+ if NewComponentNo <> '' then begin
+ BOMComponent.Validate(Type, NewComponentType);
+ BOMComponent.Validate("No.", NewComponentNo);
+ BOMComponent.Validate("Unit of Measure Code", GetUnitOfMeasureCode(NewComponentType, NewComponentNo, UseBaseUnitOfMeasure));
+ end else
+ BOMComponent.Validate("Unit of Measure Code", GetUnitOfMeasureCode(BOMComponent.Type, BOMComponent."No.", UseBaseUnitOfMeasure));
+ if ComponentType = BOMComponent.Type::Resource then
+ BOMComponent.Validate("Resource Usage Type", ResourceUsage);
+ BOMComponent.Validate("Quantity per", Qty);
+ BOMComponent.Validate(
+ Description, LibraryUtility.GenerateRandomCode(BOMComponent.FieldNo(Description), DATABASE::"BOM Component"));
+ BOMComponent.Modify(true);
+ end;
+
+ procedure EditAssemblyList(ChangeType: Option " ",Add,Replace,Delete,Edit,"Delete all","Edit cards"; ComponentType: Enum "BOM Component Type"; NewComponentType: Enum "BOM Component Type"; NewComponentNo: Code[20]; ParentItemNo: Code[20])
+ var
+ BOMComponent: Record "BOM Component";
+ begin
+ case ChangeType of
+ ChangeType::Add:
+ CreateAssemblyListComponent(
+ NewComponentType, NewComponentNo, ParentItemNo, '', BOMComponent."Resource Usage Type"::Direct,
+ LibraryRandom.RandDec(20, 2), true);
+ ChangeType::Replace:
+ EditAssemblyListComponent(
+ ComponentType, NewComponentType, NewComponentNo, ParentItemNo, BOMComponent."Resource Usage Type"::Direct,
+ LibraryRandom.RandDec(20, 2), true);
+ ChangeType::Delete:
+ DeleteAssemblyListComponent(ComponentType, ParentItemNo);
+ ChangeType::Edit:
+ EditAssemblyListComponent(
+ ComponentType, NewComponentType, '', ParentItemNo, BOMComponent."Resource Usage Type"::Direct,
+ LibraryRandom.RandDec(20, 2), false);
+ ChangeType::"Delete all":
+ DeleteAssemblyList(ParentItemNo);
+ ChangeType::"Edit cards":
+ ModifyCostParams(ParentItemNo, false, 0, 0);
+ end;
+ end;
+
+ procedure EditAssemblyLine(ComponentType: Enum "BOM Component Type"; NewComponentType: Enum "BOM Component Type"; NewComponentNo: Code[20]; AssemblyHeaderNo: Code[20]; Qty: Decimal; UseBaseUnitOfMeasure: Boolean)
+ var
+ AssemblyLine: Record "Assembly Line";
+ begin
+ AssemblyLine.SetCurrentKey("Document Type", "Document No.", Type);
+ AssemblyLine.SetRange("Document Type", AssemblyLine."Document Type"::Order);
+ AssemblyLine.SetRange("Document No.", AssemblyHeaderNo);
+ AssemblyLine.SetRange(Type, ComponentType);
+ if not AssemblyLine.FindSet() then
+ exit;
+ AssemblyLine.Next(LibraryRandom.RandInt(AssemblyLine.Count));
+
+ if AssemblyLine.Type = AssemblyLine.Type::Item then
+ AssemblyLine.Validate("Variant Code", LibraryInventory.GetVariant(AssemblyLine."No.", AssemblyLine."Variant Code"));
+ AssemblyLine.Validate(Description,
+ LibraryUtility.GenerateRandomCode(AssemblyLine.FieldNo(Description), DATABASE::"Assembly Line"));
+ AssemblyLine.Validate("Quantity per", Qty);
+
+ if NewComponentNo <> '' then begin
+ AssemblyLine.Validate(Type, NewComponentType);
+ AssemblyLine.Validate("No.", NewComponentNo);
+ AssemblyLine.Validate("Unit of Measure Code", GetUnitOfMeasureCode(NewComponentType, NewComponentNo, UseBaseUnitOfMeasure));
+ end else
+ AssemblyLine.Validate("Unit of Measure Code",
+ GetUnitOfMeasureCode(AssemblyLine.Type, AssemblyLine."No.", UseBaseUnitOfMeasure));
+
+ AssemblyLine.Modify(true);
+ end;
+
+ procedure EditAssemblyLines(ChangeType: Option " ",Add,Replace,Delete,Edit,"Delete all","Edit cards",Usage; ComponentType: Enum "BOM Component Type"; NewComponentType: Enum "BOM Component Type"; NewComponentNo: Code[20]; AssemblyHeaderNo: Code[20]; UseBaseUnitOfMeasure: Boolean)
+ var
+ AssemblyHeader: Record "Assembly Header";
+ AssemblyLine: Record "Assembly Line";
+ begin
+ AssemblyHeader.Get(AssemblyHeader."Document Type"::Order, AssemblyHeaderNo);
+ case ChangeType of
+ ChangeType::Add:
+ CreateAssemblyLine(AssemblyHeader, AssemblyLine, NewComponentType, NewComponentNo,
+ GetUnitOfMeasureCode(NewComponentType, NewComponentNo, true), AssemblyHeader.Quantity, 1, '');
+ ChangeType::Replace:
+ EditAssemblyLine(
+ ComponentType, NewComponentType, NewComponentNo, AssemblyHeaderNo, LibraryRandom.RandDec(20, 2),
+ UseBaseUnitOfMeasure);
+ ChangeType::Delete:
+ DeleteAssemblyLine(ComponentType, AssemblyHeaderNo);
+ ChangeType::Edit:
+ EditAssemblyLine(
+ ComponentType, NewComponentType, '', AssemblyHeaderNo, LibraryRandom.RandDec(20, 2), UseBaseUnitOfMeasure);
+ ChangeType::"Delete all":
+ DeleteAssemblyLines(AssemblyHeaderNo);
+ ChangeType::"Edit cards":
+ ModifyCostParams(AssemblyHeaderNo, false, 0, 0);
+ ChangeType::Usage:
+ ChangeResourceUsage(AssemblyHeaderNo);
+ end;
+ Commit();
+ end;
+
+ procedure EditOrderDimensions(AssemblyHeader: Record "Assembly Header")
+ var
+ TempDimension: Record Dimension temporary;
+ TempDimensionValue: Record "Dimension Value" temporary;
+ begin
+ CreateDimensionSetup(TempDimension, TempDimensionValue);
+ AssemblyHeader.Validate("Dimension Set ID",
+ LibraryDimension.CreateDimSet(AssemblyHeader."Dimension Set ID", TempDimension.Code, TempDimensionValue.Code));
+ end;
+
+ local procedure FindHeaderValueEntries(var ValueEntry: Record "Value Entry"; PostedAssemblyHeader: Record "Posted Assembly Header"; EntryType: Enum "Cost Entry Type"; ItemLedgerEntryType: Enum "Item Ledger Entry Type")
+ begin
+ ValueEntry.Reset();
+ ValueEntry.SetRange("Item No.", PostedAssemblyHeader."Item No.");
+ ValueEntry.SetRange("Item Ledger Entry Type", ItemLedgerEntryType);
+ ValueEntry.SetRange("Entry Type", EntryType);
+ ValueEntry.SetRange("Document No.", PostedAssemblyHeader."No.");
+ ValueEntry.SetRange("Location Code", PostedAssemblyHeader."Location Code");
+ ValueEntry.SetRange("Variant Code", PostedAssemblyHeader."Variant Code");
+ ValueEntry.SetRange("Inventory Posting Group", PostedAssemblyHeader."Inventory Posting Group");
+ ValueEntry.SetRange("Gen. Prod. Posting Group", PostedAssemblyHeader."Gen. Prod. Posting Group");
+ ValueEntry.SetRange("Item Ledger Entry Quantity", 0);
+ ValueEntry.SetRange("Invoiced Quantity", 0);
+ ValueEntry.SetRange("Valued Quantity", PostedAssemblyHeader.Quantity);
+ ValueEntry.SetRange("Order Type", ValueEntry."Order Type"::Assembly);
+ ValueEntry.SetRange("Order No.", PostedAssemblyHeader."Order No.");
+ ValueEntry.SetRange("Order Line No.", 0);
+ end;
+
+ local procedure FindLineValueEntries(var ValueEntry: Record "Value Entry"; PostedAssemblyLine: Record "Posted Assembly Line"; EntryType: Enum "Cost Entry Type"; ItemLedgerEntryType: Enum "Item Ledger Entry Type")
+ begin
+ ValueEntry.Reset();
+ if PostedAssemblyLine.Type = PostedAssemblyLine.Type::Item then
+ ValueEntry.SetRange("Item No.", PostedAssemblyLine."No.")
+ else begin
+ ValueEntry.SetRange(Type, ValueEntry.Type::Resource);
+ ValueEntry.SetRange("No.", PostedAssemblyLine."No.");
+ end;
+ ValueEntry.SetRange("Item Ledger Entry Type", ItemLedgerEntryType);
+ ValueEntry.SetRange("Entry Type", EntryType);
+ ValueEntry.SetRange("Document No.", PostedAssemblyLine."Document No.");
+ ValueEntry.SetRange("Location Code", PostedAssemblyLine."Location Code");
+ ValueEntry.SetRange("Variant Code", PostedAssemblyLine."Variant Code");
+ if ItemLedgerEntryType = "Item Ledger Entry Type"::"Assembly Consumption" then
+ ValueEntry.SetRange("Valued Quantity", -PostedAssemblyLine.Quantity)
+ else
+ ValueEntry.SetRange("Valued Quantity", PostedAssemblyLine.Quantity);
+ ValueEntry.SetRange("Order Type", ValueEntry."Order Type"::Assembly);
+ ValueEntry.SetRange("Order No.", PostedAssemblyLine."Order No.");
+ ValueEntry.SetRange("Order Line No.", PostedAssemblyLine."Order Line No.");
+ end;
+
+ procedure FindLinkedAssemblyOrder(var AssemblyHeader: Record "Assembly Header"; DocumentType: Enum "Sales Document Type"; DocumentNo: Code[20]; DocumentLineNo: Integer)
+ var
+ AssembleToOrderLink: Record "Assemble-to-Order Link";
+ begin
+ AssembleToOrderLink.SetRange(Type, AssembleToOrderLink.Type::Sale);
+ AssembleToOrderLink.SetRange("Document Type", DocumentType);
+ AssembleToOrderLink.SetRange("Document No.", DocumentNo);
+ AssembleToOrderLink.SetRange("Document Line No.", DocumentLineNo);
+ AssembleToOrderLink.FindFirst();
+ AssemblyHeader.Get(AssembleToOrderLink."Assembly Document Type", AssembleToOrderLink."Assembly Document No.");
+ end;
+
+ procedure FindPostedAssemblyLines(var PostedAssemblyLine: Record "Posted Assembly Line"; PostedAssemblyHeader: Record "Posted Assembly Header")
+ begin
+ PostedAssemblyLine.Reset();
+ PostedAssemblyLine.SetRange("Document No.", PostedAssemblyHeader."No.");
+ PostedAssemblyLine.SetRange("Order No.", PostedAssemblyHeader."Order No.");
+ PostedAssemblyLine.SetRange(Type, PostedAssemblyLine.Type::Item);
+ end;
+
+ procedure FindPostedAssemblyHeaders(var PostedAssemblyHeader: Record "Posted Assembly Header"; AssemblyHeader: Record "Assembly Header")
+ begin
+ PostedAssemblyHeader.Reset();
+ PostedAssemblyHeader.SetRange("Order No.", AssemblyHeader."No.");
+ PostedAssemblyHeader.SetRange("Item No.", AssemblyHeader."Item No.");
+ end;
+
+ procedure GetBOMComponentLines(var TempBOMComponent: Record "BOM Component" temporary; ParentItemNo: Code[20])
+ var
+ BOMComponent: Record "BOM Component";
+ Item: Record Item;
+ begin
+ BOMComponent.SetRange("Parent Item No.", ParentItemNo);
+ BOMComponent.SetRange(Type, BOMComponent.Type::Item);
+ if BOMComponent.FindSet() then
+ repeat
+ Item.Get(BOMComponent."No.");
+ if Item."Assembly BOM" then
+ GetBOMComponentLines(TempBOMComponent, Item."No.")
+ else begin
+ TempBOMComponent := BOMComponent;
+ TempBOMComponent.Insert();
+ end;
+ until BOMComponent.Next() = 0;
+
+ BOMComponent.SetRange(Type, BOMComponent.Type::Resource);
+ if BOMComponent.FindSet() then
+ repeat
+ TempBOMComponent := BOMComponent;
+ TempBOMComponent.Insert();
+ until BOMComponent.Next() = 0;
+ end;
+
+ procedure GetCostInformation(var UnitCost: Decimal; var Overhead: Decimal; var IndirectCost: Decimal; Type: Enum "BOM Component Type"; No: Code[20]; VariantCode: Code[10]; LocationCode: Code[10]): Boolean
+ var
+ Resource: Record Resource;
+ Item: Record Item;
+ StockkeepingUnit: Record "Stockkeeping Unit";
+ begin
+ case Type of
+ "BOM Component Type"::Item:
+ begin
+ Item.Get(No);
+ StockkeepingUnit.SetCurrentKey("Location Code", "Item No.", "Variant Code");
+ if StockkeepingUnit.Get(LocationCode, Item."No.", VariantCode) then
+ UnitCost := StockkeepingUnit."Unit Cost"
+ else
+ UnitCost := Item."Unit Cost";
+ Overhead := Item."Overhead Rate";
+ IndirectCost := Item."Indirect Cost %";
+ exit(Item."Cost is Adjusted");
+ end;
+ "BOM Component Type"::Resource:
+ begin
+ Resource.Get(No);
+ UnitCost := Resource."Unit Cost";
+ Overhead := Resource."Unit Cost" - Resource."Direct Unit Cost";
+ IndirectCost := Resource."Indirect Cost %";
+ exit(false);
+ end;
+ end;
+ end;
+
+ procedure GetUnitOfMeasureCode(ComponentType: Enum "BOM Component Type"; ComponentNo: Code[20]; UseBaseUnitOfMeasure: Boolean): Code[10]
+ var
+ Item: Record Item;
+ Resource: Record Resource;
+ ItemUnitOfMeasure: Record "Item Unit of Measure";
+ ResourceUnitOfMeasure: Record "Resource Unit of Measure";
+ BOMComponent: Record "BOM Component";
+ begin
+ case ComponentType of
+ BOMComponent.Type::Item:
+ begin
+ Item.Get(ComponentNo);
+ if UseBaseUnitOfMeasure then
+ exit(Item."Base Unit of Measure");
+ ItemUnitOfMeasure.SetRange("Item No.", Item."No.");
+ ItemUnitOfMeasure.SetFilter(Code, '<>%1', Item."Base Unit of Measure");
+ if ItemUnitOfMeasure.FindFirst() then
+ exit(ItemUnitOfMeasure.Code);
+ end;
+ BOMComponent.Type::Resource:
+ begin
+ Resource.Get(ComponentNo);
+ if UseBaseUnitOfMeasure then
+ exit(Resource."Base Unit of Measure");
+ ResourceUnitOfMeasure.SetRange("Resource No.", Resource."No.");
+ ResourceUnitOfMeasure.SetFilter(Code, '<>%1', Resource."Base Unit of Measure");
+ if ResourceUnitOfMeasure.FindFirst() then
+ exit(ResourceUnitOfMeasure.Code);
+ end
+ end;
+ exit('');
+ end;
+
+ procedure GetAdjAmounts(var VarianceAmount: Decimal; var AdjAmount: Decimal; PostedAssemblyHeader: Record "Posted Assembly Header")
+ var
+ ValueEntry: Record "Value Entry";
+ DirectCostAmount: Decimal;
+ OutputNotAdjAmount: Decimal;
+ begin
+ ValueEntry.Reset();
+ ValueEntry.SetRange("Document No.", PostedAssemblyHeader."No.");
+ ValueEntry.SetRange("Order Type", ValueEntry."Order Type"::Assembly);
+ ValueEntry.SetRange("Order No.", PostedAssemblyHeader."Order No.");
+ ValueEntry.SetRange("Entry Type", ValueEntry."Entry Type"::"Direct Cost");
+ DirectCostAmount := 0;
+ OutputNotAdjAmount := 0;
+
+ if ValueEntry.FindSet() then
+ repeat
+ case ValueEntry."Item Ledger Entry Type" of
+ ValueEntry."Item Ledger Entry Type"::" ":
+ DirectCostAmount += -ValueEntry."Cost Amount (Actual)";
+ ValueEntry."Item Ledger Entry Type"::"Assembly Consumption":
+ DirectCostAmount += ValueEntry."Cost Amount (Actual)";
+ ValueEntry."Item Ledger Entry Type"::"Assembly Output":
+ if not ValueEntry.Adjustment then
+ OutputNotAdjAmount += ValueEntry."Cost Amount (Actual)";
+ end;
+ until ValueEntry.Next() = 0;
+
+ AdjAmount := DirectCostAmount + OutputNotAdjAmount;
+ VarianceAmount := DirectCostAmount + PostedAssemblyHeader."Cost Amount";
+ end;
+
+ procedure GetCompsToAdjust(var ItemNo: array[10] of Code[20]; var ResourceNo: array[10] of Code[20]; AssemblyHeader: Record "Assembly Header"): Text[250]
+ var
+ AssemblyLine: Record "Assembly Line";
+ ItemFilter: Text[250];
+ i: Integer;
+ begin
+ AssemblyLine.SetRange("Document Type", AssemblyHeader."Document Type");
+ AssemblyLine.SetRange("Document No.", AssemblyHeader."No.");
+ AssemblyLine.SetRange(Type, AssemblyLine.Type::Item);
+ ItemFilter := AssemblyHeader."Item No.";
+ i := 1;
+ if AssemblyLine.FindSet() then
+ repeat
+ ItemNo[i] := AssemblyLine."No.";
+ ItemFilter += '|' + ItemNo[i];
+ i += 1;
+ until AssemblyLine.Next() = 0;
+ ItemFilter := DelChr(ItemFilter, '>', '|');
+
+ i := 1;
+ AssemblyLine.SetRange(Type, AssemblyLine.Type::Resource);
+ if AssemblyLine.FindSet() then
+ repeat
+ ResourceNo[i] := AssemblyLine."No.";
+ i += 1;
+ until AssemblyLine.Next() = 0;
+
+ exit(ItemFilter)
+ end;
+
+ local procedure GetValueEntriesAmount(PostedAssemblyHeader: Record "Posted Assembly Header"; ItemLedgerEntryType: Enum "Item Ledger Entry Type"; EntryType: Enum "Cost Entry Type"; VarianceType: Enum "Cost Variance Type"; ItemNo: Code[20]; PostedToGL: Boolean): Decimal
+ var
+ ValueEntry: Record "Value Entry";
+ Amount: Decimal;
+ begin
+ ValueEntry.Reset();
+ ValueEntry.SetRange("Document No.", PostedAssemblyHeader."No.");
+ ValueEntry.SetRange("Order Type", ValueEntry."Order Type"::Assembly);
+ ValueEntry.SetRange("Order No.", PostedAssemblyHeader."Order No.");
+ ValueEntry.SetRange("Item Ledger Entry Type", ItemLedgerEntryType);
+ ValueEntry.SetRange("Variance Type", VarianceType);
+ ValueEntry.SetRange("Entry Type", EntryType);
+ if ItemNo <> '' then
+ ValueEntry.SetRange("Item No.", ItemNo);
+ if PostedToGL then
+ ValueEntry.SetFilter("Cost Posted to G/L", '<>%1', 0);
+ Amount := 0;
+ if ValueEntry.FindSet() then
+ repeat
+ Amount += ValueEntry."Cost Amount (Actual)";
+ until ValueEntry.Next() = 0;
+ exit(Amount);
+ end;
+
+ procedure GetPostingSetup(var GeneralPostingSetup: Record "General Posting Setup"; var InventoryPostingSetup: Record "Inventory Posting Setup"; GenProdPostingGr: Code[20]; InvtPostingGroup: Code[20]; LocationCode: Code[10])
+ begin
+ GeneralPostingSetup.Get('', GenProdPostingGr);
+ InventoryPostingSetup.Get(LocationCode, InvtPostingGroup);
+ end;
+
+ procedure ModifyCostParams(ParentItemNo: Code[20]; CostAdjNeeded: Boolean; IndirectCost: Decimal; Overhead: Decimal)
+ var
+ Resource: Record Resource;
+ BOMComponent: Record "BOM Component";
+ begin
+ BOMComponent.SetRange("Parent Item No.", ParentItemNo);
+ if BOMComponent.FindSet() then
+ repeat
+ case BOMComponent.Type of
+ BOMComponent.Type::Item:
+ ModifyItem(BOMComponent."No.", CostAdjNeeded, IndirectCost, Overhead);
+ BOMComponent.Type::Resource:
+ begin
+ Resource.Get(BOMComponent."No.");
+ Resource.Validate("Unit Price", Resource."Unit Price" + LibraryRandom.RandDec(10, 2));
+ if CostAdjNeeded then begin
+ Resource.Validate("Direct Unit Cost", Resource."Direct Unit Cost" + LibraryRandom.RandDec(10, 2));
+ Resource.Validate("Indirect Cost %", IndirectCost);
+ end;
+ Resource.Modify(true);
+ end
+ end;
+ until BOMComponent.Next() = 0;
+ end;
+
+ procedure ModifyItem(ItemNo: Code[20]; CostAdjNeeded: Boolean; IndirectCost: Decimal; Overhead: Decimal)
+ var
+ Item: Record Item;
+ begin
+ Item.Get(ItemNo);
+ if CostAdjNeeded then begin
+ Item.Validate("Indirect Cost %", IndirectCost);
+ Item.Validate("Overhead Rate", Overhead);
+ if Item."Costing Method" = Item."Costing Method"::Standard then
+ Item.Validate("Standard Cost", Item."Standard Cost" + LibraryRandom.RandDec(10, 2))
+ else
+ Item.Validate("Unit Cost", Item."Unit Cost" + LibraryRandom.RandDec(10, 2));
+ end;
+
+ Item.Validate("Unit Price", Item."Unit Price" + LibraryRandom.RandDec(10, 2));
+ Item.Validate("Lot Size", Item."Lot Size" + LibraryRandom.RandInt(10));
+ Item.Modify(true);
+ end;
+
+ procedure ModifyOrderCostParams(AssemblyHeaderNo: Code[20]; CostAdjNeeded: Boolean; IndirectCost: Decimal; Overhead: Decimal)
+ var
+ Resource: Record Resource;
+ AssemblyLine: Record "Assembly Line";
+ begin
+ AssemblyLine.SetRange("Document Type", AssemblyLine."Document Type"::Order);
+ AssemblyLine.SetRange("Document No.", AssemblyHeaderNo);
+ if AssemblyLine.FindSet() then
+ repeat
+ case AssemblyLine.Type of
+ AssemblyLine.Type::Item:
+ ModifyItem(AssemblyLine."No.", CostAdjNeeded, IndirectCost, Overhead);
+ AssemblyLine.Type::Resource:
+ begin
+ Resource.Get(AssemblyLine."No.");
+ Resource.Validate("Indirect Cost %", IndirectCost);
+ Resource.Validate("Unit Price", Resource."Unit Price" + LibraryRandom.RandDec(10, 2));
+ Resource.Validate("Unit Cost", Resource."Unit Cost" + LibraryRandom.RandDec(10, 2));
+ Resource.Modify(true);
+ end
+ end;
+ until AssemblyLine.Next() = 0;
+ end;
+
+ procedure NeedsAdjustment(var AdjUnitCost: Decimal; Item: Record Item; PostedAssemblyLine: Record "Posted Assembly Line"; FinalAdjSource: Option; UnitCost: Decimal): Boolean
+ begin
+ if FinalAdjSource = AdjSource::Revaluation then
+ AdjUnitCost := GetDirectUnitCost(Item."No.") - PostedAssemblyLine."Unit Cost"
+ else
+ AdjUnitCost := GetInboundItemCost(Item."No.") - PostedAssemblyLine."Unit Cost";
+
+ exit(
+ Item."Cost is Adjusted" and
+ (Abs(AdjUnitCost) > LibraryERM.GetAmountRoundingPrecision()) and
+ (Abs(AdjUnitCost * PostedAssemblyLine.Quantity) >= LibraryERM.GetAmountRoundingPrecision())
+ );
+ end;
+
+ local procedure GetInboundItemCost(ItemNo: Code[20]): Decimal
+ var
+ ItemLedgerEntry: Record "Item Ledger Entry";
+ begin
+ ItemLedgerEntry.SetRange("Item No.", ItemNo);
+ ItemLedgerEntry.SetRange("Entry Type", ItemLedgerEntry."Entry Type"::"Positive Adjmt.");
+ ItemLedgerEntry.SetLoadFields(Quantity, "Cost Amount (Actual)", "Remaining Quantity");
+ ItemLedgerEntry.SetAutoCalcFields("Cost Amount (Actual)");
+ ItemLedgerEntry.FindFirst();
+ exit(ItemLedgerEntry.GetUnitCostLCY());
+ end;
+
+ local procedure GetDirectUnitCost(ItemNo: Code[20]): Decimal
+ var
+ ValueEntry: Record "Value Entry";
+ begin
+ ValueEntry.SetRange("Item No.", ItemNo);
+ ValueEntry.SetRange("Entry Type", ValueEntry."Item Ledger Entry Type"::"Positive Adjmt.");
+ ValueEntry.SetRange("Entry Type", ValueEntry."Entry Type"::"Direct Cost");
+ ValueEntry.SetLoadFields("Cost per Unit");
+ ValueEntry.FindFirst();
+ exit(ValueEntry."Cost per Unit");
+ end;
+
+ procedure PostAssemblyHeader(AssemblyHeader: Record "Assembly Header"; ExpectedError: Text[1024])
+ var
+ AssemblyPost: Codeunit "Assembly-Post";
+ begin
+ if ExpectedError = '' then
+ AssemblyPost.Run(AssemblyHeader)
+ else begin
+ asserterror AssemblyPost.Run(AssemblyHeader);
+ Assert.IsTrue(StrPos(GetLastErrorText, ExpectedError) > 0,
+ 'Expected:' + ExpectedError + '. Actual:' + GetLastErrorText);
+ ClearLastError();
+ end;
+ Commit();
+ end;
+
+ procedure PrepareOrderPosting(var AssemblyHeader: Record "Assembly Header"; var TempAssemblyLine: Record "Assembly Line" temporary; HeaderQtyFactor: Integer; CompQtyFactor: Integer; UpdateAllComps: Boolean; PostingDate: Date)
+ var
+ AssemblyLine: Record "Assembly Line";
+ begin
+ TempAssemblyLine.DeleteAll();
+ AssemblyHeader.Validate("Quantity to Assemble", AssemblyHeader."Quantity to Assemble" * HeaderQtyFactor / 100);
+ AssemblyHeader.Validate(Description,
+ LibraryUtility.GenerateRandomCode(AssemblyHeader.FieldNo(Description), DATABASE::"Assembly Header"));
+ AssemblyHeader.Validate("Posting Date", PostingDate);
+ AddAssemblyHeaderComment(AssemblyHeader, 0);
+ AssemblyHeader.Modify(true);
+
+ AssemblyLine.SetRange("Document Type", AssemblyHeader."Document Type");
+ AssemblyLine.SetRange("Document No.", AssemblyHeader."No.");
+ if AssemblyLine.FindSet() then
+ repeat
+ AssemblyLine.Validate("Quantity to Consume", AssemblyLine.Quantity * CompQtyFactor / 100);
+ AssemblyLine.Validate(Description,
+ LibraryUtility.GenerateRandomCode(AssemblyLine.FieldNo(Description), DATABASE::"Assembly Line"));
+ AddAssemblyHeaderComment(AssemblyHeader, AssemblyLine."Line No.");
+ AssemblyLine.Modify(true);
+ if AssemblyLine."Quantity to Consume" > 0 then begin
+ TempAssemblyLine := AssemblyLine;
+ TempAssemblyLine.Insert();
+ end;
+ until (AssemblyLine.Next() = 0) or (not UpdateAllComps);
+ end;
+
+ procedure ReopenAO(var AssemblyHeader: Record "Assembly Header")
+ var
+ ReleaseAssemblyDoc: Codeunit "Release Assembly Document";
+ begin
+ ReleaseAssemblyDoc.Reopen(AssemblyHeader);
+ end;
+
+ procedure ReleaseAO(var AssemblyHeader: Record "Assembly Header")
+ begin
+ CODEUNIT.Run(CODEUNIT::"Release Assembly Document", AssemblyHeader);
+ end;
+
+ procedure RevaluateItem(var Item: Record Item; var ItemJournalLine: Record "Item Journal Line"; OldUnitCost: Decimal; PostingDate: Date)
+ var
+ ItemJournalTemplate: Record "Item Journal Template";
+ ItemJournalBatch: Record "Item Journal Batch";
+ begin
+ LibraryInventory.SelectItemJournalTemplateName(ItemJournalTemplate, ItemJournalTemplate.Type::Revaluation);
+ LibraryInventory.SelectItemJournalBatchName(ItemJournalBatch, ItemJournalTemplate.Type::Revaluation, ItemJournalTemplate.Name);
+ LibraryInventory.CreateItemJournalLine(ItemJournalLine, ItemJournalBatch."Journal Template Name", ItemJournalBatch.Name,
+ ItemJournalLine."Entry Type"::Purchase, Item."No.", 0);
+ Item.SetRange("No.", Item."No.");
+ LibraryCosting.CreateRevaluationJnlLines(
+ Item, ItemJournalLine, ItemJournalLine."Document No.", "Inventory Value Calc. Per"::Item,
+ "Inventory Value Calc. Base"::" ", true, true, true, PostingDate);
+
+ ItemJournalLine.Reset();
+ ItemJournalLine.SetRange("Journal Template Name", ItemJournalLine."Journal Template Name");
+ ItemJournalLine.SetRange("Journal Batch Name", ItemJournalLine."Journal Batch Name");
+ ItemJournalLine.SetRange("Item No.", Item."No.");
+ ItemJournalLine.FindFirst();
+ ItemJournalLine.Validate("Unit Cost (Revalued)", OldUnitCost + LibraryRandom.RandInt(50));
+ ItemJournalLine.Modify(true);
+ end;
+
+ procedure RollUpAsmCost(var SalesLine: Record "Sales Line")
+ begin
+ SalesLine.RollUpAsmCost();
+ end;
+
+ procedure RollUpAsmPrice(var SalesLine: Record "Sales Line")
+ begin
+ SalesLine.RollupAsmPrice();
+ end;
+
+ procedure SetupComponents(var TempItem: Record Item temporary; var TempResource: Record Resource temporary; CostingMethod: Enum "Costing Method"; NoOfItems: Integer; NoOfResources: Integer; GenProdPostingGroup: Code[20]; InventoryPostingGroup: Code[20])
+ var
+ Item: Record Item;
+ Resource: Record Resource;
+ AssemblyLine: Record "Assembly Line";
+ CompCount: Integer;
+ begin
+ TempItem.DeleteAll();
+ TempResource.DeleteAll();
+
+ for CompCount := 1 to NoOfItems do begin
+ Clear(Item);
+ CreateItem(Item, CostingMethod, Item."Replenishment System"::Purchase, GenProdPostingGroup, InventoryPostingGroup);
+ AddEntityDimensions(AssemblyLine.Type::Item, Item."No.");
+ TempItem := Item;
+ TempItem.Insert();
+ end;
+
+ for CompCount := 1 to NoOfResources do begin
+ CreateResource(Resource, true, GenProdPostingGroup);
+ AddEntityDimensions(AssemblyLine.Type::Resource, Resource."No.");
+ TempResource := Resource;
+ TempResource.Insert();
+ end;
+ end;
+
+ procedure CreateAssemblyOrder(var AssemblyHeader: Record "Assembly Header"; DueDate: Date; LocationCode: Code[10]; NoOfItems: Integer)
+ var
+ Item: Record Item;
+ begin
+ SetupAssemblyItem(
+ Item, Item."Costing Method"::Standard, Item."Costing Method"::Standard, Item."Replenishment System"::Assembly, LocationCode, false,
+ NoOfItems,
+ LibraryRandom.RandIntInRange(1, 3),
+ LibraryRandom.RandIntInRange(1, 3),
+ LibraryRandom.RandIntInRange(1, 10));
+
+ CreateAssemblyHeader(AssemblyHeader, DueDate, Item."No.", LocationCode, LibraryRandom.RandDec(10, 2), '');
+ end;
+
+ procedure SetStockoutWarning(StockoutWarning: Boolean)
+ var
+ AssemblySetup: Record "Assembly Setup";
+ begin
+ AssemblySetup.Get();
+ AssemblySetup.Validate("Stockout Warning", StockoutWarning);
+ AssemblySetup.Modify(true);
+ end;
+
+ procedure SetupAssemblyData(var AssemblyHeader: Record "Assembly Header"; DueDate: Date; ParentCostingMethod: Enum "Costing Method"; CompCostingMethod: Enum "Costing Method"; ReplenishmentSystem: Enum "Replenishment System"; LocationCode: Code[10]; UpdateUnitCost: Boolean)
+ var
+ Item: Record Item;
+ begin
+ SetupAssemblyItem(Item, ParentCostingMethod, CompCostingMethod, ReplenishmentSystem, LocationCode, UpdateUnitCost, 1, 1, 1, 1);
+
+ CreateAssemblyHeader(AssemblyHeader, DueDate, Item."No.", LocationCode, LibraryRandom.RandDec(10, 2), '');
+ end;
+
+ procedure SetupAssemblyItem(var Item: Record Item; ParentCostingMethod: Enum "Costing Method"; CompCostingMethod: Enum "Costing Method"; ReplenishmentSystem: Enum "Replenishment System"; LocationCode: Code[10]; UpdateUnitCost: Boolean; NoOfItems: Integer; NoOfResources: Integer; NoOfTexts: Integer; QtyPerFactor: Integer)
+ var
+ AssemblyLine: Record "Assembly Line";
+ CalculateStandardCost: Codeunit "Calculate Standard Cost";
+ GenProdPostingGr: Code[20];
+ AsmInvtPostingGr: Code[20];
+ CompInvtPostingGr: Code[20];
+ begin
+ SetupPostingToGL(GenProdPostingGr, AsmInvtPostingGr, CompInvtPostingGr, LocationCode);
+ CreateItem(Item, ParentCostingMethod, ReplenishmentSystem, GenProdPostingGr, AsmInvtPostingGr);
+ AddEntityDimensions(AssemblyLine.Type::Item, Item."No.");
+ CreateAssemblyList(
+ CompCostingMethod, Item."No.", true, NoOfItems, NoOfResources, NoOfTexts, QtyPerFactor, GenProdPostingGr, CompInvtPostingGr);
+
+ if UpdateUnitCost then begin
+ CalculateStandardCost.CalcItem(Item."No.", true);
+ CalculateStandardCost.CalcAssemblyItemPrice(Item."No.");
+ end;
+ end;
+
+ procedure SetupItemJournal(var ItemJournalTemplate: Record "Item Journal Template"; var ItemJournalBatch: Record "Item Journal Batch")
+ var
+ NoSeries: Record "No. Series";
+ NoSeriesLine: Record "No. Series Line";
+ begin
+ Clear(ItemJournalTemplate);
+ ItemJournalTemplate.Init();
+ LibraryInventory.SelectItemJournalTemplateName(ItemJournalTemplate, ItemJournalTemplate.Type::Item);
+
+ Clear(ItemJournalBatch);
+ ItemJournalBatch.Init();
+ LibraryInventory.SelectItemJournalBatchName(ItemJournalBatch, ItemJournalTemplate.Type, ItemJournalTemplate.Name);
+ if ItemJournalBatch."No. Series" = '' then begin
+ LibraryUtility.CreateNoSeries(NoSeries, true, true, true);
+ LibraryUtility.CreateNoSeriesLine(NoSeriesLine, NoSeries.Code, '', '');
+ ItemJournalBatch.Validate("No. Series", NoSeries.Code);
+ ItemJournalBatch.Modify(true);
+ end;
+ end;
+
+ procedure SetupPostingToGL(var GenProdPostingGr: Code[20]; var AsmInvtPostingGr: Code[20]; var CompInvtPostingGr: Code[20]; LocationCode: Code[10])
+ var
+ InventoryPostingGroup: Record "Inventory Posting Group";
+ GLAccount: Record "G/L Account";
+ GLAccount2: Record "G/L Account";
+ GLAccount3: Record "G/L Account";
+ GLAccount4: Record "G/L Account";
+ GLAccount5: Record "G/L Account";
+ GLAccount6: Record "G/L Account";
+ GeneralPostingSetup: Record "General Posting Setup";
+ InvtPostingSetup: Record "Inventory Posting Setup";
+ begin
+ // Create Inventory posting setup accounts.
+ // Assembly Item Inventory.
+ CreateGLAccount(GLAccount, GLAccount."Income/Balance"::"Balance Sheet", 'Output Inventory');
+ // Material Variance.
+ CreateGLAccount(GLAccount2, GLAccount."Income/Balance"::"Income Statement", 'Material Variance');
+ // Capacity Variance.
+ CreateGLAccount(GLAccount3, GLAccount."Income/Balance"::"Income Statement", 'Capacity Variance');
+ // Capacity Overhead Variance.
+ CreateGLAccount(GLAccount4, GLAccount."Income/Balance"::"Income Statement", 'Capacity Overhead Variance');
+ // Mfg. Overhead Variance.
+ CreateGLAccount(GLAccount5, GLAccount."Income/Balance"::"Income Statement", 'Mfg. Overhead Variance');
+ // Inventory account (Interim)
+ CreateGLAccount(GLAccount6, GLAccount."Income/Balance"::"Balance Sheet", 'Inventory Account (Interim)');
+
+ // Create Inventory Posting Group for Assembly Item.
+ LibraryInventory.CreateInventoryPostingGroup(InventoryPostingGroup);
+ AsmInvtPostingGr := InventoryPostingGroup.Code;
+
+ // Create Inventory Posting Setup for Assembly Item.
+ CreateInvtPostingSetup(InvtPostingSetup, LocationCode, InventoryPostingGroup.Code, GLAccount."No.", GLAccount2."No.",
+ GLAccount3."No.", GLAccount4."No.", GLAccount5."No.", GLAccount6."No.");
+
+ // Component Inventory Account.
+ CreateGLAccount(GLAccount, GLAccount."Income/Balance"::"Balance Sheet", 'Component Item Inventory');
+
+ // Create Inventory Posting Group for Component.
+ LibraryInventory.CreateInventoryPostingGroup(InventoryPostingGroup);
+ CompInvtPostingGr := InventoryPostingGroup.Code;
+
+ // Create Inventory Posting Setup for Assembly Item.
+ CreateInvtPostingSetup(InvtPostingSetup, LocationCode, InventoryPostingGroup.Code, GLAccount."No.", GLAccount2."No.",
+ GLAccount3."No.", GLAccount4."No.", GLAccount5."No.", GLAccount6."No.");
+
+ LibraryERM.FindGeneralPostingSetupInvtToGL(GeneralPostingSetup);
+ GenProdPostingGr := GeneralPostingSetup."Gen. Prod. Posting Group";
+ end;
+
+ procedure UndoPostedAssembly(var PostedAssemblyHeader: Record "Posted Assembly Header"; RestoreAO: Boolean; ExpectedError: Text[1024])
+ var
+ AsmPostCtrl: Codeunit "Assembly-Post";
+ begin
+ Clear(AsmPostCtrl);
+ if ExpectedError = '' then
+ AsmPostCtrl.Undo(PostedAssemblyHeader, RestoreAO)
+ else begin
+ asserterror AsmPostCtrl.Undo(PostedAssemblyHeader, RestoreAO);
+ Assert.IsTrue(StrPos(GetLastErrorText, ExpectedError) > 0, 'Actual:' + GetLastErrorText);
+ ClearLastError();
+ end;
+ end;
+
+ procedure UpdateOrderCost(var AssemblyHeader: Record "Assembly Header")
+ var
+ Item: Record Item;
+ begin
+ Commit();
+ if AssemblyHeader.Quantity = 0 then begin
+ asserterror AssemblyHeader.UpdateUnitCost();
+ Assert.AreEqual(
+ StrSubstNo(ErrorZeroQty, AssemblyHeader."No."), GetLastErrorText,
+ 'Actual:' + GetLastErrorText + '; Expected:' + StrSubstNo(ErrorZeroQty, AssemblyHeader."No."));
+ ClearLastError();
+ exit;
+ end;
+
+ Item.Get(AssemblyHeader."Item No.");
+ if Item."Costing Method" <> Item."Costing Method"::Standard then
+ AssemblyHeader.UpdateUnitCost()
+ else begin
+ asserterror AssemblyHeader.UpdateUnitCost();
+ Assert.IsTrue(StrPos(GetLastErrorText, ErrorStdCost) > 0, 'Actual:' + GetLastErrorText + '; Expected:' + ErrorStdCost);
+ ClearLastError();
+ end;
+
+ Commit();
+ end;
+
+ procedure UpdateAssemblySetup(var AssemblySetup: Record "Assembly Setup"; LocationCode: Code[10]; DimensionsFrom: Option; PostedOrdersNos: Code[20])
+ begin
+ AssemblySetup.Get();
+ if AssemblySetup."Assembly Order Nos." = '' then
+ AssemblySetup.Validate("Assembly Order Nos.", LibraryUtility.GetGlobalNoSeriesCode());
+ AssemblySetup.Validate("Copy Component Dimensions from", DimensionsFrom);
+ AssemblySetup.Validate("Default Location for Orders", LocationCode);
+ AssemblySetup.Validate("Posted Assembly Order Nos.", PostedOrdersNos);
+ AssemblySetup.Modify(true);
+ end;
+
+ procedure UpdateInventorySetup(var InventorySetup: Record "Inventory Setup"; AutomaticCostPosting: Boolean; ExpectedCostPostingtoGL: Boolean; AutomaticCostAdjustment: Enum "Automatic Cost Adjustment Type"; AverageCostCalcType: Enum "Average Cost Calculation Type"; AverageCostPeriod: Enum "Average Cost Period Type")
+ begin
+ InventorySetup.Get();
+ InventorySetup."Automatic Cost Posting" := AutomaticCostPosting;
+ InventorySetup."Expected Cost Posting to G/L" := ExpectedCostPostingtoGL;
+ InventorySetup."Automatic Cost Adjustment" := AutomaticCostAdjustment;
+ InventorySetup."Average Cost Calc. Type" := AverageCostCalcType;
+ InventorySetup."Average Cost Period" := AverageCostPeriod;
+ InventorySetup.Modify(true);
+ end;
+
+ procedure UpdateAssemblyLine(var AssemblyLine: Record "Assembly Line"; FieldNo: Integer; Value: Variant)
+ var
+ RecRef: RecordRef;
+ FieldRef: FieldRef;
+ begin
+ RecRef.GetTable(AssemblyLine);
+ FieldRef := RecRef.Field(FieldNo);
+ FieldRef.Validate(Value);
+ RecRef.SetTable(AssemblyLine);
+ AssemblyLine.Modify(true);
+ end;
+
+ procedure UpdateAssemblyHeader(var AssemblyHeader: Record "Assembly Header"; FieldNo: Integer; Value: Variant)
+ var
+ RecRef: RecordRef;
+ FieldRef: FieldRef;
+ begin
+ RecRef.GetTable(AssemblyHeader);
+ FieldRef := RecRef.Field(FieldNo);
+ FieldRef.Validate(Value);
+ RecRef.SetTable(AssemblyHeader);
+ AssemblyHeader.Modify(true);
+ end;
+
+ procedure UpdateInvtPeriod(var InventoryPeriod: Record "Inventory Period"; ReOpen: Boolean)
+ var
+ ItemLedgerEntry: Record "Item Ledger Entry";
+ CloseInventoryPeriod: Codeunit "Close Inventory Period";
+ begin
+ LibraryCosting.AdjustCostItemEntries('', '');
+ ItemLedgerEntry.SetRange(Open, true);
+ if ItemLedgerEntry.FindFirst() then
+ ItemLedgerEntry.Delete();
+
+ CloseInventoryPeriod.SetReOpen(ReOpen);
+ CloseInventoryPeriod.SetHideDialog(true);
+ CloseInventoryPeriod.Run(InventoryPeriod);
+
+ if ReOpen then
+ InventoryPeriod.Delete();
+ end;
+
+ procedure UpdateSKUCards(Item: Record Item)
+ var
+ StockkeepingUnit: Record "Stockkeeping Unit";
+ begin
+ StockkeepingUnit.SetRange("Item No.", Item."No.");
+ if StockkeepingUnit.FindSet() then
+ repeat
+ if Item."Costing Method" = Item."Costing Method"::Standard then
+ StockkeepingUnit.Validate("Standard Cost", Item."Standard Cost" + LibraryRandom.RandDec(10, 2))
+ else
+ StockkeepingUnit.Validate("Unit Cost", Item."Unit Cost" + LibraryRandom.RandDec(10, 2));
+ StockkeepingUnit.Modify(true);
+ until StockkeepingUnit.Next() = 0;
+ end;
+
+ procedure VerifytAsmReservationEntryATO(AssemblyHeader: Record "Assembly Header"): Integer
+ var
+ ReservationEntry: Record "Reservation Entry";
+ begin
+ Clear(ReservationEntry);
+ ReservationEntry.SetRange(Positive, true);
+ ReservationEntry.SetRange("Item No.", AssemblyHeader."Item No.");
+ ReservationEntry.SetRange(Description, AssemblyHeader.Description);
+ ReservationEntry.SetRange("Location Code", AssemblyHeader."Location Code");
+ ReservationEntry.SetRange("Reservation Status", ReservationEntry."Reservation Status"::Reservation);
+ ReservationEntry.SetRange("Source Type", DATABASE::"Assembly Header");
+ ReservationEntry.SetRange("Source Subtype", AssemblyHeader."Document Type");
+ ReservationEntry.SetRange("Source Ref. No.", 0);
+ ReservationEntry.SetRange("Source ID", AssemblyHeader."No.");
+ ReservationEntry.SetRange(Quantity, AssemblyHeader.Quantity);
+ ReservationEntry.SetRange(Binding, ReservationEntry.Binding::"Order-to-Order");
+ ReservationEntry.SetRange("Planning Flexibility", ReservationEntry."Planning Flexibility"::None);
+ ReservationEntry.SetRange("Shipment Date", AssemblyHeader."Due Date");
+ ReservationEntry.SetRange("Variant Code", AssemblyHeader."Variant Code");
+ ReservationEntry.SetRange("Disallow Cancellation", true);
+ Assert.AreEqual(1, ReservationEntry.Count, 'Couldn''t find the AO reservation entry with the filters: ' +
+ ReservationEntry.GetFilters);
+
+ exit(ReservationEntry."Entry No.");
+ end;
+
+ procedure VerifyHardLinkEntry(SalesLine: Record "Sales Line"; AssemblyHeader: Record "Assembly Header"; NoOfEntries: Integer)
+ var
+ ATOLink: Record "Assemble-to-Order Link";
+ begin
+ Clear(ATOLink);
+ ATOLink.SetRange("Assembly Document Type", AssemblyHeader."Document Type");
+ ATOLink.SetRange("Assembly Document No.", AssemblyHeader."No.");
+ ATOLink.SetRange(Type, ATOLink.Type::Sale);
+ ATOLink.SetRange("Document Type", SalesLine."Document Type");
+ ATOLink.SetRange("Document No.", SalesLine."Document No.");
+ ATOLink.SetRange("Document Line No.", SalesLine."Line No.");
+ ATOLink.SetRange("Assembled Quantity", AssemblyHeader."Assembled Quantity");
+
+ Assert.AreEqual(NoOfEntries, ATOLink.Count, 'There are no ' + Format(NoOfEntries) + ' entries within the filter ' +
+ ATOLink.GetFilters);
+ end;
+
+ procedure VerifySaleReservationEntryATO(SalesLine: Record "Sales Line"): Integer
+ var
+ ReservationEntry: Record "Reservation Entry";
+ begin
+ Clear(ReservationEntry);
+ ReservationEntry.SetRange(Positive, false);
+ ReservationEntry.SetRange("Item No.", SalesLine."No.");
+ ReservationEntry.SetRange(Description, SalesLine.Description);
+ ReservationEntry.SetRange("Location Code", SalesLine."Location Code");
+ ReservationEntry.SetRange("Reservation Status", ReservationEntry."Reservation Status"::Reservation);
+ ReservationEntry.SetRange("Source Type", DATABASE::"Sales Line");
+ ReservationEntry.SetRange("Source Subtype", SalesLine."Document Type");
+ ReservationEntry.SetRange("Source Ref. No.", SalesLine."Line No.");
+ ReservationEntry.SetRange("Source ID", SalesLine."Document No.");
+ ReservationEntry.SetRange(Quantity, -SalesLine."Qty. to Assemble to Order");
+ ReservationEntry.SetRange(Binding, ReservationEntry.Binding::"Order-to-Order");
+ ReservationEntry.SetRange("Planning Flexibility", ReservationEntry."Planning Flexibility"::None);
+ ReservationEntry.SetRange("Shipment Date", SalesLine."Shipment Date");
+ ReservationEntry.SetRange("Variant Code", SalesLine."Variant Code");
+ ReservationEntry.SetRange("Disallow Cancellation", true);
+
+ Assert.AreEqual(1, ReservationEntry.Count, 'Couldn''t find the SOL reservation entry with the filters: ' +
+ ReservationEntry.GetFilters);
+
+ exit(ReservationEntry."Entry No.");
+ end;
+
+ procedure VerifyEntityDimensions(TableID: Integer; EntityNo: Code[20]; ParentItemNo: Code[20]; CopyFromHeader: Boolean; DimensionSetID: Integer)
+ var
+ DefaultDimension: Record "Default Dimension";
+ DimensionSetEntry: Record "Dimension Set Entry";
+ begin
+ if (TableID <= 0) or (DimensionSetID <= 0) then
+ exit;
+ LibraryDimension.FindDefaultDimension(DefaultDimension, TableID, EntityNo);
+ if CopyFromHeader then
+ LibraryDimension.FindDefaultDimension(DefaultDimension, 27, ParentItemNo);
+
+ LibraryDimension.FindDimensionSetEntry(DimensionSetEntry, DimensionSetID);
+ repeat
+ DimensionSetEntry.SetRange("Dimension Code", DefaultDimension."Dimension Code");
+ DimensionSetEntry.SetRange("Dimension Value Code", DefaultDimension."Dimension Value Code");
+ Assert.AreEqual(
+ 1, DimensionSetEntry.Count, 'Wrong no. of dimension set entries for dimension ' + Format(DefaultDimension."Dimension Code"));
+ until DefaultDimension.Next() = 0;
+ end;
+
+ procedure VerifyILEs(var TempAssemblyLine: Record "Assembly Line" temporary; AssemblyHeader: Record "Assembly Header"; AssembledQty: Decimal)
+ begin
+ VerifyILEsGeneric(TempAssemblyLine, AssemblyHeader, AssembledQty, false);
+ end;
+
+ procedure VerifyILEsGeneric(var TempAssemblyLine: Record "Assembly Line" temporary; AssemblyHeader: Record "Assembly Header"; AssembledQty: Decimal; IsATO: Boolean)
+ var
+ ItemLedgerEntry: Record "Item Ledger Entry";
+ begin
+ // General filtering.
+ ItemLedgerEntry.Reset();
+ ItemLedgerEntry.SetRange("Posting Date", AssemblyHeader."Posting Date");
+ ItemLedgerEntry.SetRange("Source No.", AssemblyHeader."Item No.");
+ ItemLedgerEntry.SetRange("Source Type", ItemLedgerEntry."Source Type"::Item);
+ ItemLedgerEntry.SetRange("Order Type", ItemLedgerEntry."Order Type"::Assembly);
+ ItemLedgerEntry.SetRange("Order No.", AssemblyHeader."No.");
+ ItemLedgerEntry.SetRange("Cost Amount (Expected)", 0);
+
+ // Output entry.
+ ItemLedgerEntry.SetRange("Item No.", AssemblyHeader."Item No.");
+ ItemLedgerEntry.SetRange("Variant Code", AssemblyHeader."Variant Code");
+ ItemLedgerEntry.SetRange("Entry Type", ItemLedgerEntry."Entry Type"::"Assembly Output");
+ ItemLedgerEntry.SetRange("Location Code", AssemblyHeader."Location Code");
+ ItemLedgerEntry.SetRange(Quantity, AssembledQty);
+ ItemLedgerEntry.SetRange("Invoiced Quantity", AssembledQty);
+ ItemLedgerEntry.SetRange("Unit of Measure Code", AssemblyHeader."Unit of Measure Code");
+ ItemLedgerEntry.SetRange("Document Line No.", 0);
+ ItemLedgerEntry.SetRange("Order Line No.", 0);
+ ItemLedgerEntry.SetRange("Dimension Set ID", AssemblyHeader."Dimension Set ID");
+ ItemLedgerEntry.SetRange("Assemble to Order", false);
+ if IsATO then begin
+ ItemLedgerEntry.SetRange("Remaining Quantity", 0);
+ ItemLedgerEntry.SetRange(Open, false);
+ end else begin
+ ItemLedgerEntry.SetRange("Remaining Quantity", AssembledQty);
+ ItemLedgerEntry.SetRange(Open, true);
+ end;
+ Assert.AreEqual(1, ItemLedgerEntry.Count, 'Wrong no. of output entries for item ' + AssemblyHeader."Item No.");
+ ItemLedgerEntry.FindFirst();
+ VerifyApplicationEntry(ItemLedgerEntry);
+
+ // Consumption entries.
+ // Find posted assembly lines.
+ TempAssemblyLine.SetRange(Type, TempAssemblyLine.Type::Item);
+
+ if TempAssemblyLine.FindSet() then
+ repeat
+ Clear(ItemLedgerEntry);
+ ItemLedgerEntry.SetRange("Item No.", TempAssemblyLine."No.");
+ ItemLedgerEntry.SetRange("Variant Code", TempAssemblyLine."Variant Code");
+ ItemLedgerEntry.SetRange("Entry Type", ItemLedgerEntry."Entry Type"::"Assembly Consumption");
+ ItemLedgerEntry.SetRange("Location Code", TempAssemblyLine."Location Code");
+ ItemLedgerEntry.SetRange(Quantity, -TempAssemblyLine."Quantity to Consume (Base)");
+ ItemLedgerEntry.SetRange("Remaining Quantity", 0);
+ ItemLedgerEntry.SetRange("Invoiced Quantity", -TempAssemblyLine."Quantity to Consume (Base)");
+ ItemLedgerEntry.SetRange("Unit of Measure Code", TempAssemblyLine."Unit of Measure Code");
+ ItemLedgerEntry.SetRange(Open, false);
+ ItemLedgerEntry.SetRange("Document Line No.", TempAssemblyLine."Line No.");
+ ItemLedgerEntry.SetRange("Order Line No.", TempAssemblyLine."Line No.");
+ ItemLedgerEntry.SetRange("Dimension Set ID", TempAssemblyLine."Dimension Set ID");
+ ItemLedgerEntry.SetRange("Assemble to Order", false);
+ Assert.AreEqual(1, ItemLedgerEntry.Count, 'Wrong no. of consumpt. ILEs for item ' + TempAssemblyLine."No.");
+ ItemLedgerEntry.FindFirst();
+ VerifyApplicationEntry(ItemLedgerEntry);
+ until TempAssemblyLine.Next() = 0;
+ end;
+
+ procedure VerifyILEsForAsmOnATO(var TempAssemblyLine: Record "Assembly Line" temporary; AssemblyHeader: Record "Assembly Header"; AssembledQty: Decimal)
+ begin
+ VerifyILEsGeneric(TempAssemblyLine, AssemblyHeader, AssembledQty, true);
+ end;
+
+ procedure VerifyILEsUndo(var TempPostedAssemblyHeader: Record "Posted Assembly Header" temporary; var TempPostedAssemblyLine: Record "Posted Assembly Line" temporary; UndoEntries: Boolean)
+ var
+ ItemLedgerEntry: Record "Item Ledger Entry";
+ begin
+ // General filtering.
+ ItemLedgerEntry.Reset();
+ ItemLedgerEntry.SetRange("Posting Date", TempPostedAssemblyHeader."Posting Date");
+ ItemLedgerEntry.SetRange("Source No.", TempPostedAssemblyHeader."Item No.");
+ ItemLedgerEntry.SetRange("Source Type", ItemLedgerEntry."Source Type"::Item);
+ ItemLedgerEntry.SetRange("Order Type", ItemLedgerEntry."Order Type"::Assembly);
+ ItemLedgerEntry.SetRange("Order No.", TempPostedAssemblyHeader."Order No.");
+ ItemLedgerEntry.SetRange("Cost Amount (Expected)", 0);
+
+ // Output entry.
+ ItemLedgerEntry.SetRange("Item No.", TempPostedAssemblyHeader."Item No.");
+ ItemLedgerEntry.SetRange("Variant Code", TempPostedAssemblyHeader."Variant Code");
+ ItemLedgerEntry.SetRange("Entry Type", ItemLedgerEntry."Entry Type"::"Assembly Output");
+ ItemLedgerEntry.SetRange("Location Code", TempPostedAssemblyHeader."Location Code");
+ if UndoEntries then begin
+ ItemLedgerEntry.SetRange(Quantity, -TempPostedAssemblyHeader."Quantity (Base)");
+ ItemLedgerEntry.SetRange("Invoiced Quantity", -TempPostedAssemblyHeader."Quantity (Base)");
+ end else begin
+ ItemLedgerEntry.SetRange(Quantity, TempPostedAssemblyHeader."Quantity (Base)");
+ ItemLedgerEntry.SetRange("Invoiced Quantity", TempPostedAssemblyHeader."Quantity (Base)");
+ end;
+
+ ItemLedgerEntry.SetRange("Assemble to Order", false);
+ ItemLedgerEntry.SetRange("Unit of Measure Code", TempPostedAssemblyHeader."Unit of Measure Code");
+ ItemLedgerEntry.SetRange("Document Line No.", 0);
+ ItemLedgerEntry.SetRange("Order Line No.", 0);
+ ItemLedgerEntry.SetRange("Dimension Set ID", TempPostedAssemblyHeader."Dimension Set ID");
+ ItemLedgerEntry.SetRange("Remaining Quantity", 0);
+ ItemLedgerEntry.SetRange(Open, false);
+ ItemLedgerEntry.SetRange(Correction, UndoEntries);
+ Assert.AreEqual(1, ItemLedgerEntry.Count, 'Wrong no. of output entries for item ' + TempPostedAssemblyHeader."Item No.");
+
+ // Verify application entries
+ ItemLedgerEntry.FindFirst();
+ VerifyApplicationEntryUndo(ItemLedgerEntry);
+
+ // Consumption entries.
+ // Find posted assembly lines.
+ TempPostedAssemblyLine.SetRange(Type, TempPostedAssemblyLine.Type::Item);
+
+ if TempPostedAssemblyLine.FindSet() then
+ repeat
+ Clear(ItemLedgerEntry);
+ ItemLedgerEntry.SetRange("Order Type", ItemLedgerEntry."Order Type"::Assembly);
+ ItemLedgerEntry.SetRange("Order No.", TempPostedAssemblyHeader."Order No.");
+ ItemLedgerEntry.SetRange("Item No.", TempPostedAssemblyLine."No.");
+ ItemLedgerEntry.SetRange("Variant Code", TempPostedAssemblyLine."Variant Code");
+ ItemLedgerEntry.SetRange("Entry Type", ItemLedgerEntry."Entry Type"::"Assembly Consumption");
+ ItemLedgerEntry.SetRange("Location Code", TempPostedAssemblyLine."Location Code");
+ if UndoEntries then begin
+ ItemLedgerEntry.SetRange(Quantity, TempPostedAssemblyLine."Quantity (Base)");
+ ItemLedgerEntry.SetRange("Remaining Quantity", TempPostedAssemblyLine."Quantity (Base)");
+ ItemLedgerEntry.SetRange("Invoiced Quantity", TempPostedAssemblyLine."Quantity (Base)");
+ end else begin
+ ItemLedgerEntry.SetRange(Quantity, -TempPostedAssemblyLine."Quantity (Base)");
+ ItemLedgerEntry.SetRange("Remaining Quantity", 0);
+ ItemLedgerEntry.SetRange("Invoiced Quantity", -TempPostedAssemblyLine."Quantity (Base)");
+ end;
+ ItemLedgerEntry.SetRange("Assemble to Order", false);
+ ItemLedgerEntry.SetRange("Unit of Measure Code", TempPostedAssemblyLine."Unit of Measure Code");
+ ItemLedgerEntry.SetRange(Open, UndoEntries);
+ ItemLedgerEntry.SetRange(Correction, UndoEntries);
+ ItemLedgerEntry.SetRange("Document Line No.", TempPostedAssemblyLine."Line No.");
+ ItemLedgerEntry.SetRange("Order Line No.", TempPostedAssemblyLine."Line No.");
+ ItemLedgerEntry.SetRange("Dimension Set ID", TempPostedAssemblyLine."Dimension Set ID");
+ Assert.AreEqual(1, ItemLedgerEntry.Count, 'Wrong no. of consumpt. ILEs for item ' + TempPostedAssemblyLine."No.");
+ ItemLedgerEntry.FindFirst();
+ VerifyApplicationEntryUndo(ItemLedgerEntry);
+ until TempPostedAssemblyLine.Next() = 0;
+ end;
+
+ procedure VerifyILEATOAndSale(AssemblyHeader: Record "Assembly Header"; SalesLine: Record "Sales Line"; AssembledQty: Decimal; Invoiced: Boolean; NoOfLines: Integer)
+ var
+ ItemLedgerEntry: Record "Item Ledger Entry";
+ begin
+ // General filtering.
+ ItemLedgerEntry.Reset();
+ ItemLedgerEntry.SetRange("Posting Date", AssemblyHeader."Posting Date");
+ ItemLedgerEntry.SetRange("Source No.", AssemblyHeader."Item No.");
+ ItemLedgerEntry.SetRange("Source Type", ItemLedgerEntry."Source Type"::Item);
+ ItemLedgerEntry.SetRange("Order Type", ItemLedgerEntry."Order Type"::Assembly);
+ ItemLedgerEntry.SetRange("Order No.", AssemblyHeader."No.");
+ ItemLedgerEntry.SetRange("Cost Amount (Expected)", 0);
+
+ // Output entry.
+ ItemLedgerEntry.SetRange("Item No.", AssemblyHeader."Item No.");
+ ItemLedgerEntry.SetRange("Variant Code", AssemblyHeader."Variant Code");
+ ItemLedgerEntry.SetRange("Entry Type", ItemLedgerEntry."Entry Type"::"Assembly Output");
+ ItemLedgerEntry.SetRange("Location Code", AssemblyHeader."Location Code");
+ ItemLedgerEntry.SetRange(Quantity, AssembledQty);
+ ItemLedgerEntry.SetRange("Invoiced Quantity", AssembledQty);
+ ItemLedgerEntry.SetRange("Unit of Measure Code", AssemblyHeader."Unit of Measure Code");
+ ItemLedgerEntry.SetRange("Document Line No.", 0);
+ ItemLedgerEntry.SetRange("Order Line No.", 0);
+ ItemLedgerEntry.SetRange("Dimension Set ID", AssemblyHeader."Dimension Set ID");
+ ItemLedgerEntry.SetRange("Assemble to Order", false);
+ ItemLedgerEntry.SetRange("Remaining Quantity", 0);
+ ItemLedgerEntry.SetRange(Open, false);
+ Assert.AreEqual(NoOfLines, ItemLedgerEntry.Count, 'Wrong no. of output entries for item ' + AssemblyHeader."Item No.");
+ if ItemLedgerEntry.FindSet() then
+ repeat
+ VerifyILESale(SalesLine, AssembledQty, ItemLedgerEntry."Entry No.", true, Invoiced);
+ until ItemLedgerEntry.Next() = 0;
+ end;
+
+ procedure VerifyILESale(SalesLine: Record "Sales Line"; AssembledQty: Decimal; EntryNo: Integer; IsAto: Boolean; Invoiced: Boolean)
+ var
+ ItemLedgerEntry: Record "Item Ledger Entry";
+ begin
+ // General filtering.
+ ItemLedgerEntry.Reset();
+ ItemLedgerEntry.SetRange("Source No.", SalesLine."Sell-to Customer No.");
+ ItemLedgerEntry.SetRange("Source Type", ItemLedgerEntry."Source Type"::Customer);
+ ItemLedgerEntry.SetRange("Order Type", ItemLedgerEntry."Order Type"::" ");
+ ItemLedgerEntry.SetRange("Cost Amount (Expected)", 0);
+
+ // Output entry.
+ ItemLedgerEntry.SetRange("Item No.", SalesLine."No.");
+ ItemLedgerEntry.SetRange("Variant Code", SalesLine."Variant Code");
+ ItemLedgerEntry.SetRange("Entry Type", ItemLedgerEntry."Entry Type"::Sale);
+ ItemLedgerEntry.SetRange("Location Code", SalesLine."Location Code");
+ ItemLedgerEntry.SetRange(Quantity, -AssembledQty);
+ if Invoiced then
+ ItemLedgerEntry.SetRange("Invoiced Quantity", -AssembledQty)
+ else
+ ItemLedgerEntry.SetRange("Invoiced Quantity", 0);
+ ItemLedgerEntry.SetRange("Unit of Measure Code", SalesLine."Unit of Measure Code");
+ ItemLedgerEntry.SetRange("Document Line No.", SalesLine."Line No.");
+ ItemLedgerEntry.SetRange("Order Line No.", 0);
+ ItemLedgerEntry.SetRange("Dimension Set ID", SalesLine."Dimension Set ID");
+ ItemLedgerEntry.SetRange("Assemble to Order", IsAto);
+ ItemLedgerEntry.SetRange(Open, not IsAto);
+ if IsAto then
+ ItemLedgerEntry.SetRange("Remaining Quantity", 0)
+ else
+ ItemLedgerEntry.SetRange("Remaining Quantity", -AssembledQty);
+ ItemLedgerEntry.SetRange("Applies-to Entry", EntryNo);
+ Assert.AreEqual(1, ItemLedgerEntry.Count, 'Wrong no. of sale entries for item ' + SalesLine."No.");
+ end;
+
+ procedure VerifySKUCost(var TempAssemblyLine: Record "Assembly Line" temporary; AssemblyHeader: Record "Assembly Header")
+ var
+ Item: Record Item;
+ UnitCost: Decimal;
+ Overhead: Decimal;
+ IndirectCost: Decimal;
+ begin
+ // Check header item SKU cost.
+ Item.Get(AssemblyHeader."Item No.");
+ GetCostInformation(UnitCost, Overhead, IndirectCost, "BOM Component Type"::Item, AssemblyHeader."Item No.",
+ AssemblyHeader."Variant Code", AssemblyHeader."Location Code");
+ if Item."Costing Method" = Item."Costing Method"::Standard then
+ AssemblyHeader.TestField("Unit Cost", UnitCost);
+
+ // Check item components SKU cost.
+ TempAssemblyLine.SetRange(Type, TempAssemblyLine.Type::Item);
+ if TempAssemblyLine.FindSet() then
+ repeat
+ GetCostInformation(UnitCost, Overhead, IndirectCost, "BOM Component Type"::Item, TempAssemblyLine."No.",
+ TempAssemblyLine."Variant Code", TempAssemblyLine."Location Code");
+ TempAssemblyLine.TestField("Unit Cost", UnitCost);
+ until TempAssemblyLine.Next() = 0
+ end;
+
+ procedure VerifyValueEntries(var TempAssemblyLine: Record "Assembly Line" temporary; AssemblyHeader: Record "Assembly Header"; AssembledQty: Decimal)
+ begin
+ VerifyValueEntriesAsm(TempAssemblyLine, AssemblyHeader, AssembledQty);
+ end;
+
+ procedure VerifyValueEntriesAsm(var TempAssemblyLine: Record "Assembly Line" temporary; AssemblyHeader: Record "Assembly Header"; AssembledQty: Decimal)
+ var
+ ValueEntry: Record "Value Entry";
+ begin
+ ValueEntry.Reset();
+ // General filtering.
+ ValueEntry.SetRange("Posting Date", AssemblyHeader."Posting Date");
+ ValueEntry.SetRange("Source No.", AssemblyHeader."Item No.");
+ ValueEntry.SetRange("Source Type", ValueEntry."Source Type"::Item);
+ ValueEntry.SetRange("Order Type", ValueEntry."Order Type"::Assembly);
+ ValueEntry.SetRange("Order No.", AssemblyHeader."No.");
+ ValueEntry.SetRange("Entry Type", ValueEntry."Entry Type"::"Direct Cost");
+
+ // Output entry.
+ ValueEntry.SetRange("Item No.", AssemblyHeader."Item No.");
+ ValueEntry.SetRange("Variant Code", AssemblyHeader."Variant Code");
+ ValueEntry.SetRange("Item Ledger Entry Type", ValueEntry."Item Ledger Entry Type"::"Assembly Output");
+ ValueEntry.SetRange("Location Code", AssemblyHeader."Location Code");
+ ValueEntry.SetRange("Valued Quantity", AssembledQty);
+ ValueEntry.SetRange("Item Ledger Entry Quantity", AssembledQty);
+ ValueEntry.SetRange("Invoiced Quantity", AssembledQty);
+ ValueEntry.SetRange("Document Line No.", 0);
+ ValueEntry.SetRange("Order Line No.", 0);
+ ValueEntry.SetRange("Dimension Set ID", AssemblyHeader."Dimension Set ID");
+
+ ValueEntry.SetRange(Adjustment, false);
+ Assert.AreEqual(1, ValueEntry.Count, 'Wrong no. of output value entries for item' + AssemblyHeader."Item No.");
+ ValueEntry.FindFirst();
+ Assert.AreNearlyEqual(Round(AssemblyHeader."Cost Amount" * AssembledQty / AssemblyHeader.Quantity,
+ LibraryERM.GetAmountRoundingPrecision()),
+ ValueEntry."Cost Amount (Actual)", LibraryERM.GetAmountRoundingPrecision(), 'Wrong value entry cost amount for header.');
+
+ // Consumption value entries for items.
+ TempAssemblyLine.SetRange(Type, TempAssemblyLine.Type::Item);
+ if TempAssemblyLine.FindSet() then
+ repeat
+ ValueEntry.SetRange("Item No.", TempAssemblyLine."No.");
+ ValueEntry.SetRange("Variant Code", TempAssemblyLine."Variant Code");
+ ValueEntry.SetRange("Item Ledger Entry Type", ValueEntry."Item Ledger Entry Type"::"Assembly Consumption");
+ ValueEntry.SetRange("Location Code", TempAssemblyLine."Location Code");
+ ValueEntry.SetRange("Valued Quantity", -TempAssemblyLine."Quantity to Consume (Base)");
+ ValueEntry.SetRange("Item Ledger Entry Quantity", -TempAssemblyLine."Quantity to Consume (Base)");
+ ValueEntry.SetRange("Invoiced Quantity", -TempAssemblyLine."Quantity to Consume (Base)");
+ ValueEntry.SetRange("Document Line No.", TempAssemblyLine."Line No.");
+ ValueEntry.SetRange("Order Line No.", TempAssemblyLine."Line No.");
+ ValueEntry.SetRange("Dimension Set ID", TempAssemblyLine."Dimension Set ID");
+ Assert.AreEqual(1, ValueEntry.Count, 'Wrong no. of consumpt. value entries for item' + TempAssemblyLine."No.");
+ ValueEntry.FindFirst();
+ Assert.AreNearlyEqual(
+ TempAssemblyLine."Cost Amount" * Round(TempAssemblyLine."Quantity to Consume" / TempAssemblyLine.Quantity),
+ -ValueEntry."Cost Amount (Actual)", LibraryERM.GetAmountRoundingPrecision(),
+ 'Wrong value entry cost amount for item ' + TempAssemblyLine."No.");
+ until TempAssemblyLine.Next() = 0;
+
+ // Consumption value entries for resources.
+ TempAssemblyLine.SetRange(Type, TempAssemblyLine.Type::Resource);
+ if TempAssemblyLine.FindSet() then
+ repeat
+ ValueEntry.SetRange("Item No.", '');
+ ValueEntry.SetRange("Variant Code", TempAssemblyLine."Variant Code");
+ ValueEntry.SetRange("Item Ledger Entry Type", ValueEntry."Item Ledger Entry Type"::" ");
+ ValueEntry.SetRange("Location Code", TempAssemblyLine."Location Code");
+ ValueEntry.SetRange(Description, TempAssemblyLine.Description);
+ ValueEntry.SetRange("Valued Quantity", TempAssemblyLine."Quantity to Consume");
+ ValueEntry.SetRange("Item Ledger Entry Quantity", 0);
+ ValueEntry.SetRange("Invoiced Quantity", TempAssemblyLine."Quantity to Consume");
+ ValueEntry.SetRange("Document Line No.", TempAssemblyLine."Line No.");
+ ValueEntry.SetRange("Order Line No.", TempAssemblyLine."Line No.");
+ ValueEntry.SetRange("Dimension Set ID", TempAssemblyLine."Dimension Set ID");
+ ValueEntry.SetRange(Type, ValueEntry.Type::Resource);
+ ValueEntry.SetRange("No.", TempAssemblyLine."No.");
+ Assert.AreEqual(1, ValueEntry.Count, 'Wrong no. of res. consumpt. value entries for res. ' + TempAssemblyLine."No.");
+ ValueEntry.FindFirst();
+ Assert.AreNearlyEqual(TempAssemblyLine."Cost Amount" * TempAssemblyLine."Quantity to Consume" /
+ TempAssemblyLine.Quantity, ValueEntry."Cost Amount (Actual)",
+ LibraryERM.GetAmountRoundingPrecision(), 'Wrong value entry cost amount for res. ' + TempAssemblyLine."No.");
+ until TempAssemblyLine.Next() = 0;
+ end;
+
+ procedure VerifyValueEntriesATO(var TempAssemblyLine: Record "Assembly Line" temporary; SalesHeader: Record "Sales Header"; AssemblyHeader: Record "Assembly Header"; AssembledQty: Decimal)
+ begin
+ VerifyValueEntriesAsm(TempAssemblyLine, AssemblyHeader, AssembledQty);
+ VerifyValueEntriesSale(SalesHeader, AssemblyHeader, AssembledQty);
+ end;
+
+ procedure VerifyValueEntriesSale(SalesHeader: Record "Sales Header"; AssemblyHeader: Record "Assembly Header"; AssembledQty: Decimal)
+ var
+ ValueEntry: Record "Value Entry";
+ begin
+ ValueEntry.Reset();
+ ValueEntry.SetRange("Posting Date", AssemblyHeader."Posting Date");
+ ValueEntry.SetRange("Source No.", SalesHeader."Sell-to Customer No.");
+ ValueEntry.SetRange("Source Type", ValueEntry."Source Type"::Customer);
+ ValueEntry.SetRange("Order Type", ValueEntry."Order Type"::" ");
+ ValueEntry.SetRange("Order No.", '');
+ ValueEntry.SetRange("Entry Type", ValueEntry."Entry Type"::"Direct Cost");
+ ValueEntry.SetRange("Item No.", AssemblyHeader."Item No.");
+ ValueEntry.SetRange("Variant Code", AssemblyHeader."Variant Code");
+ ValueEntry.SetRange("Item Ledger Entry Type", ValueEntry."Item Ledger Entry Type"::Sale);
+ ValueEntry.SetRange("Location Code", AssemblyHeader."Location Code");
+ ValueEntry.SetRange("Valued Quantity", -AssembledQty);
+ ValueEntry.SetRange("Item Ledger Entry Quantity", -AssembledQty);
+ ValueEntry.SetRange("Invoiced Quantity", -AssembledQty);
+ ValueEntry.SetRange(Adjustment, false);
+
+ Assert.AreEqual(1, ValueEntry.Count, 'Wrong no. of sales value entries for item' + AssemblyHeader."Item No.");
+ ValueEntry.FindFirst();
+
+ Assert.AreNearlyEqual(Round(AssemblyHeader."Cost Amount" * AssembledQty / AssemblyHeader.Quantity,
+ LibraryERM.GetAmountRoundingPrecision()),
+ ValueEntry."Cost Amount (Actual)", LibraryERM.GetAmountRoundingPrecision(), 'Wrong value entry cost amount for header.');
+ end;
+
+ procedure VerifyValueEntriesUndo(var TempAssemblyLine: Record "Assembly Line" temporary; AssemblyHeader: Record "Assembly Header"; AssembledQty: Decimal)
+ var
+ ValueEntry: Record "Value Entry";
+ begin
+ ValueEntry.Reset();
+ // General filtering.
+ ValueEntry.SetRange("Posting Date", AssemblyHeader."Posting Date");
+ ValueEntry.SetRange("Source No.", AssemblyHeader."Item No.");
+ ValueEntry.SetRange("Source Type", ValueEntry."Source Type"::Item);
+ ValueEntry.SetRange("Order Type", ValueEntry."Order Type"::Assembly);
+ ValueEntry.SetRange("Order No.", AssemblyHeader."No.");
+ ValueEntry.SetRange("Entry Type", ValueEntry."Entry Type"::"Direct Cost");
+
+ // Output entry.
+ ValueEntry.SetRange("Item No.", AssemblyHeader."Item No.");
+ ValueEntry.SetRange("Variant Code", AssemblyHeader."Variant Code");
+ ValueEntry.SetRange("Item Ledger Entry Type", ValueEntry."Item Ledger Entry Type"::"Assembly Output");
+ ValueEntry.SetRange("Location Code", AssemblyHeader."Location Code");
+ ValueEntry.SetRange("Valued Quantity", AssembledQty);
+ ValueEntry.SetRange("Item Ledger Entry Quantity", AssembledQty);
+ ValueEntry.SetRange("Invoiced Quantity", AssembledQty);
+ ValueEntry.SetRange("Document Line No.", 0);
+ ValueEntry.SetRange("Order Line No.", 0);
+ ValueEntry.SetRange("Dimension Set ID", AssemblyHeader."Dimension Set ID");
+
+ ValueEntry.SetRange(Adjustment, false);
+ Assert.AreEqual(1, ValueEntry.Count, 'Wrong no. of output value entries for item' + AssemblyHeader."Item No.");
+ ValueEntry.FindFirst();
+ Assert.AreNearlyEqual(Round(AssemblyHeader."Cost Amount" * AssembledQty / AssemblyHeader.Quantity,
+ LibraryERM.GetAmountRoundingPrecision()),
+ ValueEntry."Cost Amount (Actual)", LibraryERM.GetAmountRoundingPrecision(), 'Wrong value entry cost amount for header.');
+
+ // Consumption value entries for items.
+ TempAssemblyLine.SetRange(Type, TempAssemblyLine.Type::Item);
+ if TempAssemblyLine.FindSet() then
+ repeat
+ ValueEntry.SetRange("Item No.", TempAssemblyLine."No.");
+ ValueEntry.SetRange("Variant Code", TempAssemblyLine."Variant Code");
+ ValueEntry.SetRange("Item Ledger Entry Type", ValueEntry."Item Ledger Entry Type"::"Assembly Consumption");
+ ValueEntry.SetRange("Location Code", TempAssemblyLine."Location Code");
+ ValueEntry.SetRange("Valued Quantity", -TempAssemblyLine."Quantity to Consume (Base)");
+ ValueEntry.SetRange("Item Ledger Entry Quantity", -TempAssemblyLine."Quantity to Consume (Base)");
+ ValueEntry.SetRange("Invoiced Quantity", -TempAssemblyLine."Quantity to Consume (Base)");
+ ValueEntry.SetRange("Document Line No.", TempAssemblyLine."Line No.");
+ ValueEntry.SetRange("Order Line No.", TempAssemblyLine."Line No.");
+ ValueEntry.SetRange("Dimension Set ID", TempAssemblyLine."Dimension Set ID");
+ Assert.AreEqual(1, ValueEntry.Count, 'Wrong no. of consumpt. value entries for item' + TempAssemblyLine."No.");
+ ValueEntry.FindFirst();
+ Assert.AreNearlyEqual(Round(TempAssemblyLine."Cost Amount" * TempAssemblyLine."Quantity to Consume" /
+ TempAssemblyLine.Quantity, LibraryERM.GetAmountRoundingPrecision()),
+ -ValueEntry."Cost Amount (Actual)", LibraryERM.GetAmountRoundingPrecision(),
+ 'Wrong value entry cost amount for item ' + TempAssemblyLine."No.");
+ until TempAssemblyLine.Next() = 0;
+
+ // Consumption value entries for resources.
+ TempAssemblyLine.SetRange(Type, TempAssemblyLine.Type::Resource);
+ if TempAssemblyLine.FindSet() then
+ repeat
+ ValueEntry.SetRange("Item No.", '');
+ ValueEntry.SetRange("Variant Code", TempAssemblyLine."Variant Code");
+ ValueEntry.SetRange("Item Ledger Entry Type", ValueEntry."Item Ledger Entry Type"::" ");
+ ValueEntry.SetRange("Location Code", TempAssemblyLine."Location Code");
+ ValueEntry.SetRange(Description, TempAssemblyLine.Description);
+ ValueEntry.SetRange("Valued Quantity", TempAssemblyLine."Quantity to Consume");
+ ValueEntry.SetRange("Item Ledger Entry Quantity", 0);
+ ValueEntry.SetRange("Invoiced Quantity", TempAssemblyLine."Quantity to Consume");
+ ValueEntry.SetRange("Document Line No.", TempAssemblyLine."Line No.");
+ ValueEntry.SetRange("Order Line No.", TempAssemblyLine."Line No.");
+ ValueEntry.SetRange("Dimension Set ID", TempAssemblyLine."Dimension Set ID");
+ ValueEntry.SetRange(Type, ValueEntry.Type::Resource);
+ ValueEntry.SetRange("No.", TempAssemblyLine."No.");
+ Assert.AreEqual(1, ValueEntry.Count, 'Wrong no. of res. consumpt. value entries for res. ' + TempAssemblyLine."No.");
+ ValueEntry.FindFirst();
+ Assert.AreNearlyEqual(TempAssemblyLine."Cost Amount" * TempAssemblyLine."Quantity to Consume" /
+ TempAssemblyLine.Quantity, ValueEntry."Cost Amount (Actual)",
+ LibraryERM.GetAmountRoundingPrecision(), 'Wrong value entry cost amount for res. ' + TempAssemblyLine."No.");
+ until TempAssemblyLine.Next() = 0;
+ end;
+
+ procedure VerifyResEntries(var TempAssemblyLine: Record "Assembly Line" temporary; AssemblyHeader: Record "Assembly Header")
+ begin
+ VerifyResEntriesGeneric(TempAssemblyLine, AssemblyHeader, false);
+ end;
+
+ procedure VerifyResEntriesATO(var TempAssemblyLine: Record "Assembly Line" temporary; AssemblyHeader: Record "Assembly Header")
+ begin
+ VerifyResEntriesGeneric(TempAssemblyLine, AssemblyHeader, true);
+ end;
+
+ procedure VerifyResEntriesGeneric(var TempAssemblyLine: Record "Assembly Line" temporary; AssemblyHeader: Record "Assembly Header"; IsATO: Boolean)
+ var
+ ResLedgerEntry: Record "Res. Ledger Entry";
+ SourceCodeSetup: Record "Source Code Setup";
+ begin
+ SourceCodeSetup.Get();
+ ResLedgerEntry.Reset();
+ // General filtering.
+ ResLedgerEntry.SetRange("Posting Date", AssemblyHeader."Posting Date");
+ ResLedgerEntry.SetRange("Order Type", ResLedgerEntry."Order Type"::Assembly);
+ ResLedgerEntry.SetRange("Order No.", AssemblyHeader."No.");
+ ResLedgerEntry.SetRange("Entry Type", ResLedgerEntry."Entry Type"::Usage);
+ if IsATO then
+ ResLedgerEntry.SetRange("Source Code", SourceCodeSetup.Sales)
+ else
+ ResLedgerEntry.SetRange("Source Code", SourceCodeSetup.Assembly);
+
+ // Usage entries.
+ TempAssemblyLine.SetRange(Type, TempAssemblyLine.Type::Resource);
+ if TempAssemblyLine.FindSet() then
+ repeat
+ ResLedgerEntry.SetRange("Resource No.", TempAssemblyLine."No.");
+ ResLedgerEntry.SetRange(Quantity, TempAssemblyLine."Quantity to Consume");
+ ResLedgerEntry.SetRange("Unit of Measure Code", TempAssemblyLine."Unit of Measure Code");
+ if not IsATO then begin // if ATO then dimensions can come from SOL also - skip checking them
+ ResLedgerEntry.SetRange("Global Dimension 1 Code", TempAssemblyLine."Shortcut Dimension 1 Code");
+ ResLedgerEntry.SetRange("Global Dimension 2 Code", TempAssemblyLine."Shortcut Dimension 2 Code");
+ ResLedgerEntry.SetRange("Dimension Set ID", TempAssemblyLine."Dimension Set ID");
+ end;
+ ResLedgerEntry.SetRange("Order Line No.", TempAssemblyLine."Line No.");
+ Assert.AreEqual(1, ResLedgerEntry.Count, 'Wrong no. of res ledger entries for res. ' + TempAssemblyLine."No.");
+ ResLedgerEntry.FindFirst();
+ Assert.AreNearlyEqual(Round(TempAssemblyLine."Cost Amount" * TempAssemblyLine."Quantity to Consume" /
+ TempAssemblyLine.Quantity, LibraryERM.GetAmountRoundingPrecision()), ResLedgerEntry."Total Cost",
+ LibraryERM.GetAmountRoundingPrecision(), 'Wrong Res. Ledger Cost amount for res. ' + TempAssemblyLine."No.")
+ until TempAssemblyLine.Next() = 0;
+ end;
+
+ procedure VerifyCapEntries(var TempAssemblyLine: Record "Assembly Line" temporary; AssemblyHeader: Record "Assembly Header")
+ begin
+ VerifyCapEntriesGeneric(TempAssemblyLine, AssemblyHeader, false);
+ end;
+
+ procedure VerifyCapEntriesATO(var TempAssemblyLine: Record "Assembly Line" temporary; AssemblyHeader: Record "Assembly Header")
+ begin
+ VerifyCapEntriesGeneric(TempAssemblyLine, AssemblyHeader, true);
+ end;
+
+ procedure VerifyCapEntriesGeneric(var TempAssemblyLine: Record "Assembly Line" temporary; AssemblyHeader: Record "Assembly Header"; IsATO: Boolean)
+ var
+ CapacityLedgerEntry: Record "Capacity Ledger Entry";
+ begin
+ CapacityLedgerEntry.Reset();
+ // General filtering.
+ CapacityLedgerEntry.SetRange("Posting Date", AssemblyHeader."Posting Date");
+ CapacityLedgerEntry.SetRange(Type, CapacityLedgerEntry.Type::Resource);
+ CapacityLedgerEntry.SetRange("Item No.", AssemblyHeader."Item No.");
+ CapacityLedgerEntry.SetRange("Variant Code", AssemblyHeader."Variant Code");
+ CapacityLedgerEntry.SetRange("Unit of Measure Code", AssemblyHeader."Unit of Measure Code");
+ CapacityLedgerEntry.SetRange("Order Type", CapacityLedgerEntry."Order Type"::Assembly);
+ CapacityLedgerEntry.SetRange("Order No.", AssemblyHeader."No.");
+
+ // Usage entries.
+ TempAssemblyLine.SetRange(Type, TempAssemblyLine.Type::Resource);
+ if TempAssemblyLine.FindSet() then
+ repeat
+ CapacityLedgerEntry.SetRange("No.", TempAssemblyLine."No.");
+ CapacityLedgerEntry.SetRange(Description, TempAssemblyLine.Description);
+ CapacityLedgerEntry.SetRange(Quantity, TempAssemblyLine."Quantity to Consume");
+ CapacityLedgerEntry.SetRange("Invoiced Quantity", TempAssemblyLine."Quantity to Consume");
+ CapacityLedgerEntry.SetRange("Cap. Unit of Measure Code", TempAssemblyLine."Unit of Measure Code");
+ if not IsATO then begin // if ATO then dimensions can come from SOL also - skip checking them
+ CapacityLedgerEntry.SetRange("Global Dimension 1 Code", TempAssemblyLine."Shortcut Dimension 1 Code");
+ CapacityLedgerEntry.SetRange("Global Dimension 2 Code", TempAssemblyLine."Shortcut Dimension 2 Code");
+ CapacityLedgerEntry.SetRange("Dimension Set ID", TempAssemblyLine."Dimension Set ID");
+ end;
+ Assert.AreEqual(1, CapacityLedgerEntry.Count, 'Wrong no. of capacity ledger entries for res. ' + TempAssemblyLine."No.");
+ CapacityLedgerEntry.FindFirst();
+ CapacityLedgerEntry.CalcFields("Direct Cost");
+ Assert.AreNearlyEqual(TempAssemblyLine."Cost Amount" * TempAssemblyLine."Quantity to Consume" /
+ TempAssemblyLine.Quantity, CapacityLedgerEntry."Direct Cost",
+ LibraryERM.GetAmountRoundingPrecision(), 'Wrong Cap. Ledger Cost amount for res. ' + TempAssemblyLine."No.")
+ until TempAssemblyLine.Next() = 0;
+ end;
+
+ procedure VerifyCapEntriesUndo(var TempPostedAssemblyHeader: Record "Posted Assembly Header" temporary; var TempPostedAssemblyLine: Record "Posted Assembly Line" temporary; IsUndo: Boolean)
+ var
+ CapacityLedgerEntry: Record "Capacity Ledger Entry";
+ begin
+ CapacityLedgerEntry.Reset();
+ // General filtering.
+ CapacityLedgerEntry.SetRange("Posting Date", TempPostedAssemblyHeader."Posting Date");
+ CapacityLedgerEntry.SetRange(Type, CapacityLedgerEntry.Type::Resource);
+ CapacityLedgerEntry.SetRange("Item No.", TempPostedAssemblyHeader."Item No.");
+ CapacityLedgerEntry.SetRange("Variant Code", TempPostedAssemblyHeader."Variant Code");
+ CapacityLedgerEntry.SetRange("Unit of Measure Code", TempPostedAssemblyHeader."Unit of Measure Code");
+ CapacityLedgerEntry.SetRange("Order Type", CapacityLedgerEntry."Order Type"::Assembly);
+ CapacityLedgerEntry.SetRange("Order No.", TempPostedAssemblyHeader."Order No.");
+
+ // Usage entries.
+ TempPostedAssemblyLine.SetRange(Type, TempPostedAssemblyLine.Type::Resource);
+ if TempPostedAssemblyLine.FindSet() then
+ repeat
+ CapacityLedgerEntry.SetRange("No.", TempPostedAssemblyLine."No.");
+ CapacityLedgerEntry.SetRange(Description, TempPostedAssemblyLine.Description);
+ CapacityLedgerEntry.SetRange("Cap. Unit of Measure Code", TempPostedAssemblyLine."Unit of Measure Code");
+ CapacityLedgerEntry.SetRange("Global Dimension 1 Code", TempPostedAssemblyLine."Shortcut Dimension 1 Code");
+ CapacityLedgerEntry.SetRange("Global Dimension 2 Code", TempPostedAssemblyLine."Shortcut Dimension 2 Code");
+ CapacityLedgerEntry.SetRange("Dimension Set ID", TempPostedAssemblyLine."Dimension Set ID");
+ if IsUndo then begin
+ CapacityLedgerEntry.SetRange(Quantity, -TempPostedAssemblyLine."Quantity (Base)");
+ CapacityLedgerEntry.SetRange("Invoiced Quantity", -TempPostedAssemblyLine."Quantity (Base)");
+ end else begin
+ CapacityLedgerEntry.SetRange(Quantity, TempPostedAssemblyLine."Quantity (Base)");
+ CapacityLedgerEntry.SetRange("Invoiced Quantity", TempPostedAssemblyLine."Quantity (Base)");
+ end;
+ Assert.AreEqual(1, CapacityLedgerEntry.Count, 'Wrong no. of capacity ledger entries for res. ' + TempPostedAssemblyLine."No.");
+ until TempPostedAssemblyLine.Next() = 0;
+ end;
+
+ procedure VerifyComments(AssemblyHeader: Record "Assembly Header")
+ var
+ AssemblyLine: Record "Assembly Line";
+ begin
+ VerifyLineComment(AssemblyHeader, 0);
+
+ AssemblyLine.SetRange("Document Type", AssemblyHeader."Document Type");
+ AssemblyLine.SetRange("Document No.", AssemblyHeader."No.");
+ if AssemblyLine.FindSet() then
+ repeat
+ VerifyLineComment(AssemblyHeader, AssemblyLine."Line No.");
+ until AssemblyLine.Next() = 0;
+ end;
+
+ procedure VerifyLineComment(AssemblyHeader: Record "Assembly Header"; AssemblyLineNo: Integer)
+ var
+ AssemblyCommentLine: Record "Assembly Comment Line";
+ begin
+ AssemblyCommentLine.Reset();
+ AssemblyCommentLine.SetRange("Document Type", AssemblyCommentLine."Document Type"::"Assembly Order");
+ AssemblyCommentLine.SetRange("Document No.", AssemblyHeader."No.");
+ AssemblyCommentLine.SetRange("Document Line No.", AssemblyLineNo);
+ AssemblyCommentLine.SetRange(Comment, 'Order:' + AssemblyHeader."No." + ', Line:' + Format(AssemblyLineNo));
+ AssemblyCommentLine.FindFirst();
+ Assert.AreEqual(1, AssemblyCommentLine.Count, 'Wrong no. of comment lines.');
+ end;
+
+ procedure VerifyItemRegister(AssemblyHeader: Record "Assembly Header")
+ var
+ SourceCodeSetup: Record "Source Code Setup";
+ ItemLedgerEntry: Record "Item Ledger Entry";
+ CapacityLedgerEntry: Record "Capacity Ledger Entry";
+ ValueEntry: Record "Value Entry";
+ ItemRegister: Record "Item Register";
+ ILEMin: Integer;
+ ILEMax: Integer;
+ ValueEntryMin: Integer;
+ ValueEntryMax: Integer;
+ CapEntryMin: Integer;
+ CapEntryMax: Integer;
+ begin
+ SourceCodeSetup.Get();
+ ItemLedgerEntry.Reset();
+ ItemLedgerEntry.SetRange("Order Type", ItemLedgerEntry."Order Type"::Assembly);
+ ItemLedgerEntry.SetRange("Order No.", AssemblyHeader."No.");
+ ItemLedgerEntry.SetRange("Posting Date", AssemblyHeader."Posting Date");
+ if ItemLedgerEntry.FindFirst() then
+ ILEMin := ItemLedgerEntry."Entry No.";
+ if ItemLedgerEntry.FindLast() then
+ ILEMax := ItemLedgerEntry."Entry No.";
+
+ ValueEntry.Reset();
+ ValueEntry.SetRange("Order Type", ValueEntry."Order Type"::Assembly);
+ ValueEntry.SetRange("Order No.", AssemblyHeader."No.");
+ ValueEntry.SetRange("Posting Date", AssemblyHeader."Posting Date");
+ ValueEntry.SetRange("Source Code", SourceCodeSetup.Assembly);
+ if ValueEntry.FindFirst() then
+ ValueEntryMin := ValueEntry."Entry No.";
+ if ValueEntry.FindLast() then
+ ValueEntryMax := ValueEntry."Entry No.";
+
+ CapacityLedgerEntry.Reset();
+ CapacityLedgerEntry.SetRange("Order Type", CapacityLedgerEntry."Order Type"::Assembly);
+ CapacityLedgerEntry.SetRange("Order No.", AssemblyHeader."No.");
+ CapacityLedgerEntry.SetRange("Posting Date", AssemblyHeader."Posting Date");
+ if CapacityLedgerEntry.FindFirst() then
+ CapEntryMin := CapacityLedgerEntry."Entry No.";
+ if CapacityLedgerEntry.FindLast() then
+ CapEntryMax := CapacityLedgerEntry."Entry No.";
+
+ ItemRegister.Reset();
+ ItemRegister.SetRange("From Entry No.", ILEMin);
+ ItemRegister.SetRange("To Entry No.", ILEMax);
+ ItemRegister.SetRange("From Value Entry No.", ValueEntryMin);
+ ItemRegister.SetRange("To Value Entry No.", ValueEntryMax);
+ ItemRegister.SetRange("From Capacity Entry No.", CapEntryMin);
+ ItemRegister.SetRange("To Capacity Entry No.", CapEntryMax);
+ ItemRegister.SetRange("Source Code", SourceCodeSetup.Assembly);
+ ItemRegister.FindFirst();
+ end;
+
+ procedure VerifyApplicationEntry(ItemLedgerEntry: Record "Item Ledger Entry")
+ var
+ ItemApplicationEntry: Record "Item Application Entry";
+ begin
+ ItemApplicationEntry.Reset();
+ ItemApplicationEntry.SetRange("Item Ledger Entry No.", ItemLedgerEntry."Entry No.");
+ ItemApplicationEntry.SetRange(Quantity, ItemLedgerEntry.Quantity);
+ case ItemLedgerEntry."Entry Type" of
+ ItemLedgerEntry."Entry Type"::"Assembly Consumption":
+ ItemApplicationEntry.SetRange("Outbound Item Entry No.", ItemLedgerEntry."Entry No.");
+ ItemLedgerEntry."Entry Type"::"Assembly Output":
+ begin
+ ItemApplicationEntry.SetRange("Inbound Item Entry No.", ItemLedgerEntry."Entry No.");
+ ItemApplicationEntry.SetRange("Outbound Item Entry No.", 0);
+ end;
+ end;
+ ItemApplicationEntry.FindFirst();
+ Assert.AreEqual(1, ItemApplicationEntry.Count,
+ 'Wrong no. of application entries for ILE no ' + Format(ItemLedgerEntry."Entry No."));
+ end;
+
+ procedure VerifyApplicationEntryUndo(ItemLedgerEntry: Record "Item Ledger Entry")
+ var
+ ItemApplicationEntry: Record "Item Application Entry";
+ begin
+ ItemApplicationEntry.Reset();
+ case ItemLedgerEntry."Entry Type" of
+ ItemLedgerEntry."Entry Type"::"Assembly Consumption":
+ if ItemLedgerEntry.Correction then begin
+ // Check reversed entry
+ ItemApplicationEntry.SetRange("Item Ledger Entry No.", ItemLedgerEntry."Entry No.");
+ ItemApplicationEntry.SetRange("Inbound Item Entry No.", ItemLedgerEntry."Entry No.");
+ ItemApplicationEntry.SetRange(Quantity, ItemLedgerEntry.Quantity);
+ ItemApplicationEntry.FindFirst();
+ Assert.AreEqual(
+ 1, ItemApplicationEntry.Count, 'Wrong no. of application entries for ILE no ' + Format(ItemLedgerEntry."Entry No."));
+ end else begin
+ // Check initial posted entry
+ ItemApplicationEntry.SetRange("Item Ledger Entry No.", ItemLedgerEntry."Entry No.");
+ ItemApplicationEntry.SetRange("Outbound Item Entry No.", ItemLedgerEntry."Entry No.");
+ ItemApplicationEntry.SetRange(Quantity, ItemLedgerEntry.Quantity);
+ ItemApplicationEntry.FindFirst();
+ Assert.AreEqual(
+ 1, ItemApplicationEntry.Count, 'Wrong no. of application entries for ILE no ' + Format(ItemLedgerEntry."Entry No."));
+ end;
+ ItemLedgerEntry."Entry Type"::"Assembly Output":
+ if ItemLedgerEntry.Correction then begin
+ // Check reversed entry
+ ItemApplicationEntry.SetRange("Item Ledger Entry No.", ItemLedgerEntry."Entry No.");
+ ItemApplicationEntry.SetRange("Outbound Item Entry No.", ItemLedgerEntry."Entry No.");
+ ItemApplicationEntry.SetRange(Quantity, ItemLedgerEntry.Quantity);
+ ItemApplicationEntry.FindFirst();
+ Assert.AreEqual(
+ 1, ItemApplicationEntry.Count, 'Wrong no. of application entries for ILE no ' + Format(ItemLedgerEntry."Entry No."));
+ end else begin
+ // Check initial posted entry
+ ItemApplicationEntry.SetRange("Item Ledger Entry No.", ItemLedgerEntry."Entry No.");
+ ItemApplicationEntry.SetRange("Outbound Item Entry No.", 0);
+ ItemApplicationEntry.SetRange("Inbound Item Entry No.", ItemLedgerEntry."Entry No.");
+ ItemApplicationEntry.SetRange(Quantity, ItemLedgerEntry.Quantity);
+ Assert.AreEqual(
+ 1, ItemApplicationEntry.Count, 'Wrong no. of application entries for ILE no ' + Format(ItemLedgerEntry."Entry No."));
+ end;
+ end;
+ end;
+
+ procedure VerifyPostedLineComment(PostedAssemblyHeader: Record "Posted Assembly Header"; PostedAssemblyLineNo: Integer)
+ var
+ AssemblyCommentLine: Record "Assembly Comment Line";
+ begin
+ AssemblyCommentLine.Reset();
+ AssemblyCommentLine.SetRange("Document Type", AssemblyCommentLine."Document Type"::"Posted Assembly");
+ AssemblyCommentLine.SetRange("Document No.", PostedAssemblyHeader."No.");
+ AssemblyCommentLine.SetRange("Document Line No.", PostedAssemblyLineNo);
+ AssemblyCommentLine.SetRange(Comment, 'Order:' + PostedAssemblyHeader."Order No." + ', Line:' + Format(PostedAssemblyLineNo));
+ AssemblyCommentLine.FindFirst();
+ Assert.AreEqual(1, AssemblyCommentLine.Count, 'Wrong no. of comment lines.');
+ end;
+
+ procedure VerifyGLEntries(PostedAssemblyHeader: Record "Posted Assembly Header"; PerPostingGroup: Boolean)
+ var
+ GLEntry: Record "G/L Entry";
+ PostedAssemblyLine: Record "Posted Assembly Line";
+ InventoryPostingSetup: Record "Inventory Posting Setup";
+ GeneralPostingSetup: Record "General Posting Setup";
+ ValueEntry: Record "Value Entry";
+ TotalAmount: Decimal;
+ OutputDirectCost: Decimal;
+ ResDirectCost: Decimal;
+ ItemDirectCost: Decimal;
+ CompDirectCost: Decimal;
+ OutputIndirectCost: Decimal;
+ CompIndirectCost: Decimal;
+ MaterialVariance: Decimal;
+ CapacityVariance: Decimal;
+ CapOverhead: Decimal;
+ ManufOverhead: Decimal;
+ begin
+ // Get expected posting accounts for assembly item.
+ GetPostingSetup(GeneralPostingSetup, InventoryPostingSetup, PostedAssemblyHeader."Gen. Prod. Posting Group",
+ PostedAssemblyHeader."Inventory Posting Group", PostedAssemblyHeader."Location Code");
+
+ // Get output costs.
+ OutputDirectCost := GetValueEntriesAmount(PostedAssemblyHeader, ValueEntry."Item Ledger Entry Type"::"Assembly Output",
+ ValueEntry."Entry Type"::"Direct Cost", ValueEntry."Variance Type"::" ", PostedAssemblyHeader."Item No.", true);
+
+ OutputIndirectCost := GetValueEntriesAmount(PostedAssemblyHeader, ValueEntry."Item Ledger Entry Type"::"Assembly Output",
+ ValueEntry."Entry Type"::"Indirect Cost", ValueEntry."Variance Type"::" ", PostedAssemblyHeader."Item No.", true);
+
+ MaterialVariance := GetValueEntriesAmount(PostedAssemblyHeader, ValueEntry."Item Ledger Entry Type"::"Assembly Output",
+ ValueEntry."Entry Type"::Variance, ValueEntry."Variance Type"::Material, PostedAssemblyHeader."Item No.", true);
+
+ CapacityVariance := GetValueEntriesAmount(PostedAssemblyHeader, ValueEntry."Item Ledger Entry Type"::"Assembly Output",
+ ValueEntry."Entry Type"::Variance, ValueEntry."Variance Type"::Capacity, PostedAssemblyHeader."Item No.", true);
+
+ CapOverhead := GetValueEntriesAmount(PostedAssemblyHeader, ValueEntry."Item Ledger Entry Type"::"Assembly Output",
+ ValueEntry."Entry Type"::Variance, ValueEntry."Variance Type"::"Capacity Overhead", PostedAssemblyHeader."Item No.", true);
+
+ ManufOverhead := GetValueEntriesAmount(PostedAssemblyHeader, ValueEntry."Item Ledger Entry Type"::"Assembly Output",
+ ValueEntry."Entry Type"::Variance, ValueEntry."Variance Type"::"Manufacturing Overhead", PostedAssemblyHeader."Item No.", true);
+
+ // Get component costs.
+ ResDirectCost :=
+ GetValueEntriesAmount(PostedAssemblyHeader, ValueEntry."Item Ledger Entry Type"::" ",
+ ValueEntry."Entry Type"::"Direct Cost", ValueEntry."Variance Type"::" ", '', true);
+
+ ItemDirectCost :=
+ GetValueEntriesAmount(PostedAssemblyHeader, ValueEntry."Item Ledger Entry Type"::"Assembly Consumption",
+ ValueEntry."Entry Type"::"Direct Cost", ValueEntry."Variance Type"::" ", '', true);
+
+ // Get consumption direct and indirect costs.
+ CompDirectCost := -ItemDirectCost + ResDirectCost;
+
+ CompIndirectCost :=
+ GetValueEntriesAmount(PostedAssemblyHeader, ValueEntry."Item Ledger Entry Type"::"Assembly Consumption",
+ ValueEntry."Entry Type"::"Indirect Cost", ValueEntry."Variance Type"::" ", '', true) +
+ GetValueEntriesAmount(PostedAssemblyHeader, ValueEntry."Item Ledger Entry Type"::" ",
+ ValueEntry."Entry Type"::"Indirect Cost", ValueEntry."Variance Type"::" ", '', true);
+
+ // Verify GL entries.
+
+ // Verify Inventory Account for output.
+ VerifyGLEntry(PostedAssemblyHeader."No.", InventoryPostingSetup."Inventory Account", PostedAssemblyHeader."Posting Date",
+ OutputDirectCost + OutputIndirectCost + MaterialVariance + CapacityVariance + CapOverhead + ManufOverhead, '<>');
+
+ // Verify Material variance account for header.
+ VerifyGLEntry(PostedAssemblyHeader."No.", InventoryPostingSetup."Material Variance Account", PostedAssemblyHeader."Posting Date",
+ -MaterialVariance, '<>');
+
+ // Verify Capacity variance account for header.
+ VerifyGLEntry(PostedAssemblyHeader."No.", InventoryPostingSetup."Capacity Variance Account", PostedAssemblyHeader."Posting Date",
+ -CapacityVariance, '<>');
+
+ // Verify Capacity overhead variance account for header.
+ VerifyGLEntry(PostedAssemblyHeader."No.", InventoryPostingSetup."Cap. Overhead Variance Account", PostedAssemblyHeader.
+ "Posting Date",
+ -CapOverhead, '<>');
+
+ // Verify Mfg. overhead variance account for header.
+ VerifyGLEntry(PostedAssemblyHeader."No.", InventoryPostingSetup."Mfg. Overhead Variance Account", PostedAssemblyHeader.
+ "Posting Date",
+ -ManufOverhead, '<>');
+
+ // Verify Inventory Adjustment account, both header and component.
+ VerifyGLEntry(PostedAssemblyHeader."No.", GeneralPostingSetup."Inventory Adjmt. Account", PostedAssemblyHeader."Posting Date",
+ CompDirectCost + CompIndirectCost - OutputDirectCost, '<>');
+
+ // Verify Overhead applied account, both header and component.
+ VerifyGLEntry(PostedAssemblyHeader."No.", GeneralPostingSetup."Overhead Applied Account", PostedAssemblyHeader."Posting Date",
+ -OutputIndirectCost - CompIndirectCost, '<>');
+
+ // Verify consumption entries.
+ PostedAssemblyLine.Reset();
+ PostedAssemblyLine.SetRange("Document No.", PostedAssemblyHeader."No.");
+ PostedAssemblyLine.SetRange("Order No.", PostedAssemblyHeader."Order No.");
+ PostedAssemblyLine.SetRange(Type, PostedAssemblyLine.Type::Item);
+ if PostedAssemblyLine.FindFirst() then
+ GetPostingSetup(GeneralPostingSetup, InventoryPostingSetup, PostedAssemblyLine."Gen. Prod. Posting Group",
+ PostedAssemblyLine."Inventory Posting Group", PostedAssemblyLine."Location Code");
+
+ // Verify cost aggregation under the document no. for 'Per posting group' option in posting.
+ ValueEntry.SetRange("Item No.", PostedAssemblyLine."No.");
+ ValueEntry.SetRange("Variant Code", PostedAssemblyLine."Variant Code");
+ ValueEntry.SetRange("Location Code", PostedAssemblyLine."Location Code");
+ ValueEntry.SetRange("Item Ledger Entry Type", ValueEntry."Item Ledger Entry Type"::"Positive Adjmt.");
+ ValueEntry.SetRange("Entry Type", ValueEntry."Entry Type"::"Direct Cost");
+ if ValueEntry.FindFirst() and PerPostingGroup then
+ VerifyGLEntry(PostedAssemblyHeader."No.", GeneralPostingSetup."Inventory Adjmt. Account", ValueEntry."Posting Date",
+ -ValueEntry."Cost Amount (Actual)", '<>');
+
+ // Verify Inventory account for item consumption.
+ VerifyGLEntry(PostedAssemblyHeader."No.", InventoryPostingSetup."Inventory Account", PostedAssemblyHeader."Posting Date",
+ ItemDirectCost, '<>');
+
+ // Verify Direct Cost account for resource consumption.
+ VerifyGLEntry(PostedAssemblyHeader."No.", GeneralPostingSetup."Direct Cost Applied Account", PostedAssemblyHeader."Posting Date",
+ -ResDirectCost, '<>');
+
+ // Check G/L transaction is balanced.
+ GLEntry.SetCurrentKey("Document No.", "Posting Date");
+ GLEntry.SetRange("Document No.", PostedAssemblyHeader."No.");
+ GLEntry.SetRange("Posting Date", PostedAssemblyHeader."Posting Date");
+ GLEntry.FindSet();
+ repeat
+ TotalAmount += GLEntry.Amount;
+ until GLEntry.Next() = 0;
+
+ Assert.AreEqual(0, TotalAmount, 'Transaction must be balanced:' + PostedAssemblyHeader."No.");
+ end;
+
+ procedure VerifyGLEntry(DocumentNo: Code[20]; AccountNo: Code[20]; PostingDate: Date; Amount: Decimal; Sign: Text[30])
+ var
+ GLEntry: Record "G/L Entry";
+ ActualAmount: Decimal;
+ begin
+ ActualAmount := 0;
+ GLEntry.Reset();
+ GLEntry.SetRange("Document No.", DocumentNo);
+ GLEntry.SetRange("G/L Account No.", AccountNo);
+ GLEntry.SetRange("Posting Date", PostingDate);
+ GLEntry.SetFilter(Amount, Sign + '%1', 0);
+ if GLEntry.FindSet() then
+ repeat
+ ActualAmount += GLEntry.Amount;
+ until GLEntry.Next() = 0;
+ Assert.AreNearlyEqual(Amount, ActualAmount, LibraryERM.GetAmountRoundingPrecision(), 'Account:' + AccountNo);
+ end;
+
+ procedure VerifyLineAdjustmentEntry(PostedAssemblyLine: Record "Posted Assembly Line"; FinalAdjSource: Option)
+ var
+ Item: Record Item;
+ ValueEntry: Record "Value Entry";
+ UnitCost: Decimal;
+ Overhead: Decimal;
+ IndirectCost: Decimal;
+ AdjUnitCost: Decimal;
+ begin
+ Item.Get(PostedAssemblyLine."No.");
+ GetCostInformation(UnitCost, Overhead, IndirectCost, "BOM Component Type"::Item,
+ PostedAssemblyLine."No.", PostedAssemblyLine."Variant Code", PostedAssemblyLine."Location Code");
+ FindLineValueEntries(ValueEntry, PostedAssemblyLine, ValueEntry."Entry Type"::"Direct Cost",
+ ValueEntry."Item Ledger Entry Type"::"Assembly Consumption");
+ ValueEntry.SetRange(Adjustment, true);
+
+ if NeedsAdjustment(AdjUnitCost, Item, PostedAssemblyLine, FinalAdjSource, UnitCost) then begin
+ Assert.AreEqual(1, ValueEntry.Count, 'Different than 1 entry for comp. item no. ' + PostedAssemblyLine."No.");
+ ValueEntry.FindFirst();
+ Assert.AreNearlyEqual(Abs(AdjUnitCost), Abs(ValueEntry."Cost per Unit"),
+ LibraryERM.GetAmountRoundingPrecision(), 'Wrong unit cost for adj.');
+ // Currently system's absolute error for "Cost Amount (Actual)" depends on ValueEntry."Valued Quantity" and GLSetup."Unit-amount rounding precision"
+ Assert.AreNearlyEqual(
+ ValueEntry."Cost Amount (Actual)", ValueEntry."Cost per Unit" * ValueEntry."Valued Quantity",
+ LibraryERM.GetUnitAmountRoundingPrecision() * ValueEntry."Valued Quantity",
+ 'Wrong adj. entry cost amount.');
+ end else begin
+ // For differences in adj. amount less than 0.01, eliminate rounding adjustment entries.
+ ValueEntry.SetFilter("Cost Amount (Actual)", '>%1', LibraryERM.GetAmountRoundingPrecision());
+ Assert.IsTrue(ValueEntry.IsEmpty, 'Unexpected adj. entries for comp item no. ' + PostedAssemblyLine."No.");
+ end;
+ end;
+
+ procedure VerifyAdjustmentEntries(AssemblyHeader: Record "Assembly Header"; FinalAdjSource: Option)
+ var
+ PostedAssemblyHeader: Record "Posted Assembly Header";
+ PostedAssemblyLine: Record "Posted Assembly Line";
+ Item: Record Item;
+ StockkeepingUnit: Record "Stockkeeping Unit";
+ AdjAmount: Decimal;
+ VarianceAmount: Decimal;
+ begin
+ Commit();
+ PostedAssemblyHeader.Reset();
+ PostedAssemblyHeader.SetRange("Order No.", AssemblyHeader."No.");
+ PostedAssemblyHeader.SetRange("Item No.", AssemblyHeader."Item No.");
+ PostedAssemblyHeader.SetRange("Variant Code", AssemblyHeader."Variant Code");
+ PostedAssemblyHeader.FindFirst();
+
+ PostedAssemblyLine.Reset();
+ PostedAssemblyLine.SetRange("Document No.", PostedAssemblyHeader."No.");
+ PostedAssemblyLine.SetRange("Order No.", AssemblyHeader."No.");
+ PostedAssemblyLine.SetRange(Type, PostedAssemblyLine.Type::Item);
+ PostedAssemblyLine.SetFilter("No.", '<>%1', AssemblyHeader."Item No."); // Skip validation for auto consumption.
+
+ if PostedAssemblyLine.FindSet() then
+ repeat
+ VerifyLineAdjustmentEntry(PostedAssemblyLine, FinalAdjSource);
+ until PostedAssemblyLine.Next() = 0;
+
+ GetAdjAmounts(VarianceAmount, AdjAmount, PostedAssemblyHeader);
+ VerifyHeaderAdjustmentEntry(PostedAssemblyHeader, AdjAmount);
+ Item.Get(AssemblyHeader."Item No.");
+ if Item."Costing Method" = Item."Costing Method"::Standard then begin
+ if StockkeepingUnit.Get(PostedAssemblyHeader."Location Code", Item."No.", PostedAssemblyHeader."Variant Code") then
+ VarianceAmount := VarianceAmount - PostedAssemblyHeader."Cost Amount" + Item."Standard Cost" * PostedAssemblyHeader.Quantity;
+ VerifyHeaderVarianceEntry(PostedAssemblyHeader, VarianceAmount);
+ end;
+ end;
+
+ procedure VerifyHeaderAdjustmentEntry(PostedAssemblyHeader: Record "Posted Assembly Header"; AdjAmount: Decimal)
+ var
+ ValueEntry: Record "Value Entry";
+ begin
+ FindHeaderValueEntries(ValueEntry, PostedAssemblyHeader, ValueEntry."Entry Type"::"Direct Cost",
+ ValueEntry."Item Ledger Entry Type"::"Assembly Output");
+ ValueEntry.SetRange(Adjustment, true);
+
+ if AdjAmount <> 0 then begin
+ ValueEntry.FindFirst();
+ Assert.AreEqual(1, ValueEntry.Count, 'Wrong no. of adjustment entries for header.');
+ Assert.AreNearlyEqual(-AdjAmount, ValueEntry."Cost Amount (Actual)",
+ LibraryERM.GetAmountRoundingPrecision(), 'Wrong header adj. entry cost amount.');
+ // Currently system's absolute error for "Cost Amount (Actual)" depends on ValueEntry."Valued Quantity" and GLSetup."Unit-amount rounding precision"
+ Assert.AreNearlyEqual(
+ ValueEntry."Cost Amount (Actual)", ValueEntry."Cost per Unit" * ValueEntry."Valued Quantity",
+ LibraryERM.GetUnitAmountRoundingPrecision() * ValueEntry."Valued Quantity",
+ 'Wrong header adj. entry cost per unit.');
+ end else
+ Assert.IsTrue(ValueEntry.IsEmpty, 'Unexpected adj. entries for header ' + PostedAssemblyHeader."No.");
+ end;
+
+ procedure VerifyHeaderVarianceEntry(PostedAssemblyHeader: Record "Posted Assembly Header"; VarianceAmount: Decimal)
+ var
+ ValueEntry: Record "Value Entry";
+ ActualVarianceAmount: Decimal;
+ begin
+ FindHeaderValueEntries(ValueEntry, PostedAssemblyHeader, ValueEntry."Entry Type"::Variance,
+ ValueEntry."Item Ledger Entry Type"::"Assembly Output");
+ ValueEntry.SetRange(Adjustment, true);
+ if VarianceAmount <> 0 then begin
+ ValueEntry.FindSet();
+ ActualVarianceAmount := 0;
+ repeat
+ ActualVarianceAmount += ValueEntry."Cost Amount (Actual)";
+ until ValueEntry.Next() = 0;
+ Assert.AreNearlyEqual(VarianceAmount, ActualVarianceAmount, LibraryERM.GetAmountRoundingPrecision(),
+ 'Wrong variance entry cost amount for header.');
+ end else
+ Assert.IsTrue(ValueEntry.IsEmpty, 'Unexpected variance entry for ' + PostedAssemblyHeader."No.");
+ end;
+
+ procedure VerifyIndirectCostEntries(AssemblyHeader: Record "Assembly Header")
+ var
+ ValueEntry: Record "Value Entry";
+ PostedAssemblyLine: Record "Posted Assembly Line";
+ PostedAssemblyHeader: Record "Posted Assembly Header";
+ Resource: Record Resource;
+ IndirectCostAmount: Decimal;
+ UnitCost: Decimal;
+ Overhead: Decimal;
+ IndirectCost: Decimal;
+ ActualIndirectCostAmount: Decimal;
+ begin
+ GetCostInformation(UnitCost, Overhead, IndirectCost, PostedAssemblyLine.Type::Item, AssemblyHeader."Item No.",
+ AssemblyHeader."Variant Code", AssemblyHeader."Location Code");
+ PostedAssemblyHeader.Reset();
+ PostedAssemblyHeader.SetRange("Order No.", AssemblyHeader."No.");
+ PostedAssemblyHeader.FindFirst();
+
+ // Output indirect cost.
+ IndirectCostAmount :=
+ GetValueEntriesAmount(PostedAssemblyHeader, ValueEntry."Item Ledger Entry Type"::"Assembly Output",
+ ValueEntry."Entry Type"::"Direct Cost", ValueEntry."Variance Type"::" ", PostedAssemblyHeader."Item No.", false) *
+ IndirectCost / 100;
+
+ ActualIndirectCostAmount :=
+ GetValueEntriesAmount(PostedAssemblyHeader, ValueEntry."Item Ledger Entry Type"::"Assembly Output",
+ ValueEntry."Entry Type"::"Indirect Cost", ValueEntry."Variance Type"::" ", PostedAssemblyHeader."Item No.", false);
+
+ Assert.AreNearlyEqual(IndirectCostAmount, ActualIndirectCostAmount, LibraryERM.GetAmountRoundingPrecision(),
+ 'Wrong Output indirect cost');
+
+ // Resource component indirect cost.
+ PostedAssemblyLine.Reset();
+ PostedAssemblyLine.SetRange("Document No.", PostedAssemblyHeader."No.");
+ PostedAssemblyLine.SetRange("Order No.", PostedAssemblyHeader."Order No.");
+ PostedAssemblyLine.SetRange(Type, PostedAssemblyLine.Type::Resource);
+ if PostedAssemblyLine.FindSet() then
+ repeat
+ FindLineValueEntries(ValueEntry, PostedAssemblyLine, ValueEntry."Entry Type"::"Direct Cost",
+ ValueEntry."Item Ledger Entry Type"::" ");
+ ValueEntry.FindFirst();
+ Resource.Get(PostedAssemblyLine."No.");
+ IndirectCostAmount := ValueEntry."Cost Amount (Actual)" * Resource."Indirect Cost %" / 100;
+ FindLineValueEntries(ValueEntry, PostedAssemblyLine, ValueEntry."Entry Type"::"Indirect Cost",
+ ValueEntry."Item Ledger Entry Type"::" ");
+ if ValueEntry.FindFirst() then
+ Assert.AreNearlyEqual(IndirectCostAmount, ValueEntry."Cost Amount (Actual)", LibraryERM.GetAmountRoundingPrecision(),
+ 'Wrong component indirect cost');
+ until PostedAssemblyLine.Next() = 0;
+ end;
+
+ procedure VerifyPartialPosting(AssemblyHeader: Record "Assembly Header"; HeaderQtyFactor: Decimal)
+ var
+ AssemblyLine: Record "Assembly Line";
+ begin
+ if HeaderQtyFactor <> 100 then begin
+ AssemblyHeader.Get(AssemblyHeader."Document Type", AssemblyHeader."No.");
+ AssemblyHeader.TestField("Quantity to Assemble", AssemblyHeader.Quantity * (100 - HeaderQtyFactor) / 100);
+ AssemblyHeader.TestField("Remaining Quantity", AssemblyHeader."Quantity to Assemble");
+ AssemblyLine.SetRange("Document Type", AssemblyHeader."Document Type");
+ AssemblyLine.SetRange("Document No.", AssemblyHeader."No.");
+ AssemblyLine.FindSet();
+ repeat
+ if AssemblyLine."Resource Usage Type" <> AssemblyLine."Resource Usage Type"::Fixed then begin
+ Assert.AreNearlyEqual(AssemblyHeader.Quantity * AssemblyHeader."Qty. per Unit of Measure" *
+ AssemblyLine."Quantity per", AssemblyLine.Quantity,
+ LibraryERM.GetUnitAmountRoundingPrecision(), 'Wrong partial line quantity.');
+ Assert.AreNearlyEqual(
+ AssemblyHeader."Remaining Quantity" * AssemblyHeader."Qty. per Unit of Measure" * AssemblyLine."Quantity per",
+ AssemblyLine."Quantity to Consume",
+ LibraryERM.GetUnitAmountRoundingPrecision(), 'Wrong partial line qty. to consume.');
+ end else begin
+ Assert.AreNearlyEqual(AssemblyLine."Quantity per", AssemblyLine.Quantity,
+ LibraryERM.GetUnitAmountRoundingPrecision(), 'Wrong partial line qty. - fixed.');
+ Assert.AreNearlyEqual(
+ AssemblyLine.Quantity - AssemblyLine."Consumed Quantity", AssemblyLine."Quantity to Consume",
+ LibraryERM.GetUnitAmountRoundingPrecision(), 'Wrong partial line qty. to consume - fixed.');
+ end;
+ until AssemblyLine.Next() = 0;
+ end;
+ end;
+
+ procedure VerifyPostedAssemblyHeader(var TempAssemblyLine: Record "Assembly Line" temporary; AssemblyHeader: Record "Assembly Header"; AssembledQty: Decimal)
+ var
+ PostedAssemblyLine: Record "Posted Assembly Line";
+ PostedAssemblyHeader: Record "Posted Assembly Header";
+ begin
+ PostedAssemblyHeader.Reset();
+ PostedAssemblyHeader.SetRange("Order No.", AssemblyHeader."No.");
+ PostedAssemblyHeader.SetRange("Item No.", AssemblyHeader."Item No.");
+ PostedAssemblyHeader.SetRange("Variant Code", AssemblyHeader."Variant Code");
+ PostedAssemblyHeader.SetRange(Description, AssemblyHeader.Description);
+ PostedAssemblyHeader.SetRange("Inventory Posting Group", AssemblyHeader."Inventory Posting Group");
+ PostedAssemblyHeader.SetRange("Gen. Prod. Posting Group", AssemblyHeader."Gen. Prod. Posting Group");
+ PostedAssemblyHeader.SetRange("Location Code", AssemblyHeader."Location Code");
+ PostedAssemblyHeader.SetRange("Shortcut Dimension 1 Code", AssemblyHeader."Shortcut Dimension 1 Code");
+ PostedAssemblyHeader.SetRange("Shortcut Dimension 2 Code", AssemblyHeader."Shortcut Dimension 2 Code");
+ PostedAssemblyHeader.SetRange("Posting Date", AssemblyHeader."Posting Date");
+ PostedAssemblyHeader.SetRange(Quantity, AssembledQty);
+ PostedAssemblyHeader.SetRange("Unit Cost", AssemblyHeader."Unit Cost");
+ PostedAssemblyHeader.SetRange("Unit of Measure Code", AssemblyHeader."Unit of Measure Code");
+ PostedAssemblyHeader.SetRange("Dimension Set ID", AssemblyHeader."Dimension Set ID");
+ Assert.AreEqual(1, PostedAssemblyHeader.Count, 'Wrong no. of posted assembly order records!');
+ PostedAssemblyHeader.FindFirst();
+ Assert.AreNearlyEqual(AssemblyHeader."Cost Amount" * AssembledQty / AssemblyHeader.Quantity, PostedAssemblyHeader."Cost Amount",
+ LibraryERM.GetAmountRoundingPrecision(), 'Wrong posted cost amount.');
+ if TempAssemblyLine.FindSet() then
+ repeat
+ PostedAssemblyLine.Reset();
+ PostedAssemblyLine.SetRange("Document No.", PostedAssemblyHeader."No.");
+ PostedAssemblyLine.SetRange("Order Line No.", TempAssemblyLine."Line No.");
+ PostedAssemblyLine.SetRange(Type, TempAssemblyLine.Type);
+ PostedAssemblyLine.SetRange("No.", TempAssemblyLine."No.");
+ PostedAssemblyLine.SetRange("Variant Code", TempAssemblyLine."Variant Code");
+ PostedAssemblyLine.SetRange(Description, TempAssemblyLine.Description);
+ PostedAssemblyLine.SetRange("Resource Usage Type", TempAssemblyLine."Resource Usage Type");
+ PostedAssemblyLine.SetRange("Location Code", TempAssemblyLine."Location Code");
+ PostedAssemblyLine.SetRange("Shortcut Dimension 1 Code", TempAssemblyLine."Shortcut Dimension 1 Code");
+ PostedAssemblyLine.SetRange("Shortcut Dimension 2 Code", TempAssemblyLine."Shortcut Dimension 2 Code");
+ PostedAssemblyLine.SetRange(Quantity, TempAssemblyLine."Quantity to Consume");
+ PostedAssemblyLine.SetRange("Unit of Measure Code", TempAssemblyLine."Unit of Measure Code");
+ PostedAssemblyLine.SetRange("Dimension Set ID", TempAssemblyLine."Dimension Set ID");
+ PostedAssemblyLine.SetRange("Unit Cost", TempAssemblyLine."Unit Cost");
+ Assert.AreEqual(1, PostedAssemblyLine.Count, 'Wrong no. of posted lines for ' + TempAssemblyLine."No.");
+ PostedAssemblyLine.FindFirst();
+ // Do not check cost amount for comment lines.
+ if TempAssemblyLine.Type <> TempAssemblyLine.Type::" " then
+ Assert.AreNearlyEqual(
+ TempAssemblyLine."Cost Amount" * TempAssemblyLine."Quantity to Consume" / TempAssemblyLine.Quantity,
+ PostedAssemblyLine."Cost Amount", LibraryERM.GetAmountRoundingPrecision(), 'Wrong posted line cost amount.');
+ until TempAssemblyLine.Next() = 0;
+ end;
+
+ procedure VerifyPostedComments(AssemblyHeader: Record "Assembly Header")
+ var
+ PostedAssemblyLine: Record "Posted Assembly Line";
+ PostedAssemblyHeader: Record "Posted Assembly Header";
+ begin
+ FindPostedAssemblyHeaders(PostedAssemblyHeader, AssemblyHeader);
+ PostedAssemblyHeader.FindFirst();
+ VerifyPostedLineComment(PostedAssemblyHeader, 0);
+
+ FindPostedAssemblyLines(PostedAssemblyLine, PostedAssemblyHeader);
+ if PostedAssemblyLine.FindSet() then
+ repeat
+ VerifyPostedLineComment(PostedAssemblyHeader, PostedAssemblyLine."Line No.");
+ until PostedAssemblyLine.Next() = 0;
+ end;
+
+ procedure VerifyWarehouseEntries(var TempAssemblyHeader: Record "Assembly Header" temporary; var TempAssemblyLine: Record "Assembly Line" temporary; IsUndo: Boolean)
+ var
+ WarehouseEntry: Record "Warehouse Entry";
+ SourceCodeSetup: Record "Source Code Setup";
+ begin
+ SourceCodeSetup.Get();
+ WarehouseEntry.Reset();
+ WarehouseEntry.SetRange("Source Code", SourceCodeSetup.Assembly);
+ WarehouseEntry.SetRange("Source No.", TempAssemblyHeader."No.");
+ WarehouseEntry.SetRange("Registering Date", TempAssemblyHeader."Posting Date");
+ WarehouseEntry.SetRange("User ID", UserId);
+ WarehouseEntry.SetRange("Variant Code", TempAssemblyHeader."Variant Code");
+ WarehouseEntry.SetRange("Unit of Measure Code", TempAssemblyHeader."Unit of Measure Code");
+ if IsUndo then begin
+ WarehouseEntry.SetRange(Quantity, -TempAssemblyHeader."Quantity to Assemble");
+ WarehouseEntry.SetRange("Entry Type", WarehouseEntry."Entry Type"::"Negative Adjmt.")
+ end else begin
+ WarehouseEntry.SetRange("Entry Type", WarehouseEntry."Entry Type"::"Positive Adjmt.");
+ WarehouseEntry.SetRange(Quantity, TempAssemblyHeader."Quantity to Assemble");
+ end;
+ WarehouseEntry.SetRange("Location Code", TempAssemblyHeader."Location Code");
+ WarehouseEntry.SetRange("Bin Code", TempAssemblyHeader."Bin Code");
+ WarehouseEntry.SetRange(
+ "Zone Code", LibraryWarehouse.GetZoneForBin(TempAssemblyHeader."Location Code", TempAssemblyHeader."Bin Code"));
+ WarehouseEntry.SetRange("Item No.", TempAssemblyHeader."Item No.");
+
+ Assert.AreEqual(1, WarehouseEntry.Count, 'Incorect number of warehouse entries for assembly ' + TempAssemblyHeader."No.");
+
+ // Verify warehouse entries for components
+ TempAssemblyLine.Reset();
+ TempAssemblyLine.SetRange(Type, TempAssemblyLine.Type::Item);
+ TempAssemblyLine.FindSet();
+ repeat
+ WarehouseEntry.Reset();
+ WarehouseEntry.SetRange("Source Code", SourceCodeSetup.Assembly);
+ WarehouseEntry.SetRange("Source No.", TempAssemblyHeader."No.");
+ WarehouseEntry.SetRange("Registering Date", TempAssemblyHeader."Posting Date");
+ WarehouseEntry.SetRange("User ID", UserId);
+ WarehouseEntry.SetRange("Variant Code", TempAssemblyLine."Variant Code");
+ WarehouseEntry.SetRange("Unit of Measure Code", TempAssemblyLine."Unit of Measure Code");
+ if IsUndo then begin
+ WarehouseEntry.SetRange(Quantity, TempAssemblyLine."Quantity to Consume");
+ WarehouseEntry.SetRange("Entry Type", WarehouseEntry."Entry Type"::"Positive Adjmt.")
+ end else begin
+ WarehouseEntry.SetRange(Quantity, -TempAssemblyLine."Quantity to Consume");
+ WarehouseEntry.SetRange("Entry Type", WarehouseEntry."Entry Type"::"Negative Adjmt.");
+ end;
+ WarehouseEntry.SetRange("Location Code", TempAssemblyLine."Location Code");
+ WarehouseEntry.SetRange("Bin Code", TempAssemblyLine."Bin Code");
+ WarehouseEntry.SetRange("Item No.", TempAssemblyLine."No.");
+ Assert.AreEqual(1, WarehouseEntry.Count, 'Incorrect number of warehouse entries for assembly line ' + TempAssemblyLine."No.");
+ until TempAssemblyLine.Next() = 0;
+ end;
+
+ procedure VerifyBinContent(LocationCode: Code[20]; BinCode: Code[20]; ItemNo: Code[20]; VariantCode: Code[10]; UOMCode: Code[10]; Quantity: Decimal)
+ var
+ BinContent: Record "Bin Content";
+ begin
+ BinContent.Reset();
+ BinContent.SetRange("Location Code", LocationCode);
+ BinContent.SetRange("Bin Code", BinCode);
+ BinContent.SetRange("Item No.", ItemNo);
+ BinContent.SetRange("Variant Code", VariantCode);
+ BinContent.SetRange("Unit of Measure Code", UOMCode);
+ if BinContent.FindFirst() then begin
+ BinContent.CalcFields(Quantity);
+ BinContent.TestField(Quantity, Quantity);
+ end else
+ Assert.AreEqual(Quantity, 0, 'Incorrect Bin Code Qty for Item: ' + ItemNo + ' in Bin: ' + BinCode);
+ end;
+
+ procedure VerifyBinContents(var TempAssemblyHeader: Record "Assembly Header" temporary; var TempAssemblyLine: Record "Assembly Line" temporary; AdditionalQty: Decimal)
+ begin
+ // This function has to be called after the AO has been posted and no other "output" qtities exist in inventory
+
+ // Verify bin content for header assembly item does not exist
+ VerifyBinContent(
+ TempAssemblyHeader."Location Code", TempAssemblyHeader."Bin Code", TempAssemblyHeader."Item No.",
+ TempAssemblyHeader."Variant Code", TempAssemblyHeader."Unit of Measure Code", 0);
+
+ // Verify bin contents for components
+ TempAssemblyLine.Reset();
+ TempAssemblyLine.SetRange(Type, TempAssemblyLine.Type::Item);
+ TempAssemblyLine.FindSet();
+ repeat
+ VerifyBinContent(
+ TempAssemblyLine."Location Code", TempAssemblyLine."Bin Code", TempAssemblyLine."No.", TempAssemblyLine."Variant Code",
+ TempAssemblyLine."Unit of Measure Code",
+ AdditionalQty + TempAssemblyLine.Quantity);
+ until TempAssemblyLine.Next() = 0;
+ end;
+
+ procedure SetLinkToLines(AsmHeader: Record "Assembly Header"; var AsmLine: Record "Assembly Line")
+ begin
+ AsmLine.SetRange("Document Type", AsmHeader."Document Type");
+ AsmLine.SetRange("Document No.", AsmHeader."No.");
+ end;
+
+ procedure EarliestAvailableDate(AsmHeader: Record "Assembly Header"; var AssemblyLine: Record "Assembly Line"; var ReturnQtyAvailable: Decimal; var EarliestDueDate: Date)
+ var
+ Item: Record Item;
+ ReqLine: Record "Requisition Line";
+ LeadTimeMgt: Codeunit "Lead-Time Management";
+ LineAvailabilityDate: Date;
+ LineStartingDate: Date;
+ EarliestEndingDate: Date;
+ EarliestStartingDate: Date;
+ LineProportion: Decimal;
+ Proportion: Decimal;
+ GrossRequirement: Decimal;
+ ScheduledRcpt: Decimal;
+ ExpectedInventory: Decimal;
+ LineAbleToAssemble: Decimal;
+ LineInventory: Decimal;
+ begin
+ SetLinkToLines(AsmHeader, AssemblyLine);
+ AssemblyLine.SetRange(Type, AssemblyLine.Type::Item);
+ AssemblyLine.SetFilter("No.", '<>%1', '');
+ AssemblyLine.SetFilter("Quantity per", '<>%1', 0);
+ Proportion := AsmHeader."Remaining Quantity";
+ if AssemblyLine.FindFirst() then
+ repeat
+ AssemblyLine.CalcAvailToAssemble(
+ AsmHeader,
+ Item,
+ GrossRequirement,
+ ScheduledRcpt,
+ ExpectedInventory,
+ LineInventory,
+ LineAvailabilityDate,
+ LineAbleToAssemble);
+
+ LineProportion := LineAbleToAssemble;
+ if LineProportion < Proportion then
+ Proportion := LineProportion;
+ if LineAvailabilityDate > 0D then begin
+ LineStartingDate := CalcDate(AssemblyLine."Lead-Time Offset", LineAvailabilityDate);
+ if LineStartingDate > EarliestStartingDate then
+ EarliestStartingDate := LineStartingDate; // latest of all line starting dates
+ end;
+ until AssemblyLine.Next() = 0;
+
+ ReturnQtyAvailable := Proportion;
+ EarliestDueDate := 0D;
+ if EarliestStartingDate > 0D then begin
+ EarliestEndingDate :=
+ // earliest starting date + lead time calculation
+ LeadTimeMgt.GetPlannedEndingDate(
+ AsmHeader."Item No.", AsmHeader."Location Code", AsmHeader."Variant Code",
+ '', LeadTimeMgt.ManufacturingLeadTime(AsmHeader."Item No.", AsmHeader."Location Code", AsmHeader."Variant Code"),
+ ReqLine."Ref. Order Type"::Assembly, EarliestStartingDate);
+ EarliestDueDate :=
+ // earliest ending date + (default) safety lead time
+ LeadTimeMgt.GetPlannedDueDate(
+ AsmHeader."Item No.", AsmHeader."Location Code", AsmHeader."Variant Code",
+ EarliestEndingDate, '', ReqLine."Ref. Order Type"::Assembly);
+ end;
+ end;
+
+ procedure ComponentsAvailable(AssemblyHeader: Record "Assembly Header"): Boolean
+ var
+ AssemblyLine: Record "Assembly Line";
+ ItemCheckAvail: Codeunit "Item-Check Avail.";
+ Inventory: Decimal;
+ GrossRequirement: Decimal;
+ ReservedRequirement: Decimal;
+ ScheduledReceipts: Decimal;
+ ReservedReceipts: Decimal;
+ QtyAvailToMake: Decimal;
+ EarliestAvailableDateX: Date;
+ begin
+ SetLinkToLines(AssemblyHeader, AssemblyLine);
+ ItemCheckAvail.AsmOrderCalculate(AssemblyHeader, Inventory,
+ GrossRequirement, ReservedRequirement, ScheduledReceipts, ReservedReceipts);
+ EarliestAvailableDate(AssemblyHeader, AssemblyLine, QtyAvailToMake, EarliestAvailableDateX);
+ exit(QtyAvailToMake >= AssemblyHeader."Remaining Quantity");
+ end;
+
+ procedure LineCount(AssemblyHeader: Record "Assembly Header"): Integer
+ var
+ AssemblyLine: Record "Assembly Line";
+ begin
+ SetLinkToLines(AssemblyHeader, AssemblyLine);
+ exit(AssemblyLine.Count);
+ end;
+
+ [IntegrationEvent(false, false)]
+ local procedure OnBeforeInsertInventoryPostingSetup(var InventoryPostingSetup: Record "Inventory Posting Setup")
+ begin
+ end;
+
+ [IntegrationEvent(false, false)]
+ local procedure OnCreateMultipleLvlTreeOnCreateBOM(var Item: Record Item; NoOfComps: Integer; var BOMCreated: Boolean)
+ begin
+ end;
+}
+
diff --git a/Apps/W1/ApplicationTestLibrary/LibraryCashFlow.Codeunit.al b/Apps/W1/ApplicationTestLibrary/LibraryCashFlow.Codeunit.al
new file mode 100644
index 0000000000..82bebd6930
--- /dev/null
+++ b/Apps/W1/ApplicationTestLibrary/LibraryCashFlow.Codeunit.al
@@ -0,0 +1,159 @@
+///
+/// Provides utility functions for creating and managing cash flow forecasts and related test scenarios.
+///
+codeunit 131331 "Library - Cash Flow"
+{
+
+ trigger OnRun()
+ begin
+ end;
+
+ var
+ LibraryUtility: Codeunit "Library - Utility";
+ LibraryERM: Codeunit "Library - ERM";
+ LibrarySales: Codeunit "Library - Sales";
+ LibraryRandom: Codeunit "Library - Random";
+
+ procedure FindCashFlowCard(var CashFlowForecast: Record "Cash Flow Forecast")
+ begin
+ CashFlowForecast.FindFirst();
+ end;
+
+ procedure FindCashFlowAccount(var CashFlowAccount: Record "Cash Flow Account")
+ begin
+ CashFlowAccount.SetRange("Account Type", CashFlowAccount."Account Type"::Entry);
+ CashFlowAccount.FindFirst();
+ end;
+
+ procedure FindCashFlowAnalysisView(var AnalysisView: Record "Analysis View")
+ begin
+ AnalysisView.Reset();
+ AnalysisView.SetRange("Account Source", AnalysisView."Account Source"::"Cash Flow Account");
+ AnalysisView.FindFirst();
+ end;
+
+ procedure CreateJournalLine(var CFWorksheetLine: Record "Cash Flow Worksheet Line"; CFNo: Code[20]; CFAccountNo: Code[20])
+ var
+ LibraryUtility: Codeunit "Library - Utility";
+ RecRef: RecordRef;
+ begin
+ RecRef.GetTable(CFWorksheetLine);
+ CFWorksheetLine.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, CFWorksheetLine.FieldNo("Line No.")));
+ CFWorksheetLine.Insert(true);
+ CFWorksheetLine.Validate("Cash Flow Forecast No.", CFNo);
+ CFWorksheetLine.Validate("Cash Flow Account No.", CFAccountNo);
+ CFWorksheetLine.Validate("Cash Flow Date", WorkDate()); // Defaults to work date.
+ CFWorksheetLine.Modify(true);
+ end;
+
+ procedure DeleteJournalLine()
+ begin
+ end;
+
+ procedure FillJournal(ConsiderSource: array[16] of Boolean; CFNo: Code[20]; GroupByDocumentType: Boolean)
+ var
+ CFWorksheetLine: Record "Cash Flow Worksheet Line";
+ SuggestWorksheetLines: Report "Suggest Worksheet Lines";
+ begin
+ CFWorksheetLine.Init();
+ SuggestWorksheetLines.InitializeRequest(ConsiderSource, CFNo, '', GroupByDocumentType);
+ SuggestWorksheetLines.UseRequestPage := false;
+ SuggestWorksheetLines.Run();
+ end;
+
+ procedure FillBudgetJournal(CFFunds: Boolean; CFNo: Code[20]; GLBudgetName: Code[10])
+ var
+ CFWorksheetLine: Record "Cash Flow Worksheet Line";
+ SuggestWorksheetLines: Report "Suggest Worksheet Lines";
+ ConsiderSource: array[16] of Boolean;
+ SourceType: Option ,Customer,Vendor,"Liquid Funds","Cash Flow Manual Expense","Cash Flow Manual Revenue","Sales Order","Purchase Order","Budgeted Fixed Asset","Sale of Fixed Asset","Service Order","G/L Budget",,,Jobs,Tax;
+ begin
+ CFWorksheetLine.Init();
+ ConsiderSource[SourceType::"Liquid Funds"] := CFFunds;
+ ConsiderSource[SourceType::"G/L Budget"] := true;
+ SuggestWorksheetLines.InitializeRequest(ConsiderSource, CFNo, GLBudgetName, false);
+ SuggestWorksheetLines.UseRequestPage := false;
+ SuggestWorksheetLines.Run();
+ end;
+
+ procedure ClearJournal()
+ var
+ CFWorksheetLine: Record "Cash Flow Worksheet Line";
+ begin
+ CFWorksheetLine.DeleteAll(true);
+ end;
+
+ procedure PostJournal()
+ var
+ CFWorksheetLine: Record "Cash Flow Worksheet Line";
+ begin
+ CODEUNIT.Run(CODEUNIT::"Cash Flow Wksh.-Register Batch", CFWorksheetLine);
+ end;
+
+ procedure PostJournalLines(var CFWorksheetLine: Record "Cash Flow Worksheet Line")
+ begin
+ CFWorksheetLine.FindSet();
+ CODEUNIT.Run(CODEUNIT::"Cash Flow Wksh.-Register Batch", CFWorksheetLine);
+ end;
+
+ procedure CreateManualLinePayment(var CFManualExpense: Record "Cash Flow Manual Expense"; CFAccountNo: Code[20])
+ begin
+ CFManualExpense.Init();
+ CFManualExpense.Validate("Cash Flow Account No.", CFAccountNo);
+ CFManualExpense.Validate(Code,
+ LibraryUtility.GenerateRandomCode(CFManualExpense.FieldNo(Code), DATABASE::"Cash Flow Manual Expense"));
+ CFManualExpense.Validate("Starting Date", WorkDate()); // Required field to post
+ CFManualExpense.Insert(true);
+ end;
+
+ procedure CreateManualLineRevenue(var CFManualRevenue: Record "Cash Flow Manual Revenue"; CFAccountNo: Code[20])
+ begin
+ CFManualRevenue.Init();
+ CFManualRevenue.Validate("Cash Flow Account No.", CFAccountNo);
+ CFManualRevenue.Validate(Code,
+ LibraryUtility.GenerateRandomCode(CFManualRevenue.FieldNo(Code), DATABASE::"Cash Flow Manual Revenue"));
+ CFManualRevenue.Validate("Starting Date", WorkDate()); // Required field to post
+ CFManualRevenue.Insert(true);
+ end;
+
+ procedure DeleteManualLine()
+ begin
+ end;
+
+ procedure CreateCashFlowCard(var CashFlowForecast: Record "Cash Flow Forecast")
+ begin
+ CashFlowForecast.Init();
+ CashFlowForecast.Validate(
+ "No.", LibraryUtility.GenerateRandomCode(CashFlowForecast.FieldNo("No."), DATABASE::"Cash Flow Forecast"));
+ CashFlowForecast.Insert(true);
+ end;
+
+ procedure CreateCashFlowAccount(var CashFlowAccount: Record "Cash Flow Account"; AccountType: Enum "Cash Flow Account Type")
+ begin
+ CashFlowAccount.Init();
+ CashFlowAccount.Validate("No.",
+ LibraryUtility.GenerateRandomCode(CashFlowAccount.FieldNo("No."), DATABASE::"Cash Flow Account"));
+ CashFlowAccount.Validate("Account Type", AccountType);
+ CashFlowAccount.Validate(Name,
+ LibraryUtility.GenerateRandomCode(CashFlowAccount.FieldNo(Name), DATABASE::"Cash Flow Account"));
+ CashFlowAccount.Insert(true);
+ end;
+
+ procedure MockCashFlowCustOverdueData()
+ var
+ GenJournalLine: Record "Gen. Journal Line";
+ GenJournalBatch: Record "Gen. Journal Batch";
+ begin
+ LibraryERM.SelectLastGenJnBatch(GenJournalBatch);
+ LibraryERM.ClearGenJournalLines(GenJournalBatch);
+ LibraryERM.CreateGeneralJnlLineWithBalAcc(
+ GenJournalLine, GenJournalBatch."Journal Template Name", GenJournalBatch.Name,
+ GenJournalLine."Document Type"::Invoice, GenJournalLine."Account Type"::Customer, LibrarySales.CreateCustomerNo(),
+ GenJournalLine."Bal. Account Type"::"G/L Account", LibraryERM.CreateGLAccountNo(),
+ LibraryRandom.RandDecInRange(100, 200, 2));
+ GenJournalLine."Due Date" := GenJournalLine."Posting Date" - 1;
+ GenJournalLine.Modify();
+ LibraryERM.PostGeneralJnlLine(GenJournalLine);
+ end;
+}
+
diff --git a/Apps/W1/ApplicationTestLibrary/LibraryCashFlowHelper.Codeunit.al b/Apps/W1/ApplicationTestLibrary/LibraryCashFlowHelper.Codeunit.al
new file mode 100644
index 0000000000..500464e68b
--- /dev/null
+++ b/Apps/W1/ApplicationTestLibrary/LibraryCashFlowHelper.Codeunit.al
@@ -0,0 +1,1190 @@
+///
+/// Provides helper functions for filling and managing cash flow journal entries in test scenarios.
+///
+codeunit 131332 "Library - Cash Flow Helper"
+{
+
+ Subtype = Normal;
+
+ trigger OnRun()
+ begin
+ end;
+
+ var
+ LibraryRandom: Codeunit "Library - Random";
+ LibraryCashFlowForecast: Codeunit "Library - Cash Flow";
+ LibraryERM: Codeunit "Library - ERM";
+ LibrarySales: Codeunit "Library - Sales";
+ LibraryPurchase: Codeunit "Library - Purchase";
+ LibraryUtility: Codeunit "Library - Utility";
+ LibraryFA: Codeunit "Library - Fixed Asset";
+ LibraryJob: Codeunit "Library - Job";
+ Assert: Codeunit Assert;
+ DocumentType: Option Sale,Purchase,Service;
+ UnhandledDocumentType: Label 'Unhandled document type.';
+ UnexpectedCFAmount: Label 'Unexpected cash flow amount.';
+ UnexpectedCFDate: Label 'Unexpected cash flow date in Document No. %1.';
+
+ procedure AddAndPostSOPrepaymentInvoice(var SalesHeader: Record "Sales Header"; PrepaymentPercentage: Decimal) PrepmtInvNo: Code[20]
+ begin
+ AddSOPrepayment(SalesHeader, PrepaymentPercentage);
+ PrepmtInvNo := PostSOPrepaymentInvoice(SalesHeader);
+ end;
+
+ procedure AddSOPrepayment(var SalesHeader: Record "Sales Header"; PrepaymentPercentage: Decimal)
+ begin
+ SalesHeader.Validate("Prepayment %", PrepaymentPercentage);
+ SalesHeader.Modify(true);
+ end;
+
+ procedure PostSOPrepaymentInvoice(var SalesHeader: Record "Sales Header"): Code[20]
+ var
+ SalesPostPrepayments: Codeunit "Sales-Post Prepayments";
+ begin
+ SalesPostPrepayments.Invoice(SalesHeader);
+ exit(SalesHeader."Last Prepayment No.");
+ end;
+
+ procedure AddAndPostPOPrepaymentInvoice(var PurchaseHeader: Record "Purchase Header"; PrepaymentPercentage: Decimal) PrepmtInvNo: Code[20]
+ begin
+ AddPOPrepayment(PurchaseHeader, PrepaymentPercentage);
+ PrepmtInvNo := PostPOPrepaymentInvoice(PurchaseHeader);
+ end;
+
+ procedure AddPOPrepayment(var PurchaseHeader: Record "Purchase Header"; PrepaymentPercentage: Decimal)
+ begin
+ PurchaseHeader.Validate("Prepayment %", PrepaymentPercentage);
+ PurchaseHeader.Modify(true);
+ end;
+
+ procedure PostPOPrepaymentInvoice(var PurchaseHeader: Record "Purchase Header"): Code[20]
+ var
+ PurchasePostPrepayments: Codeunit "Purchase-Post Prepayments";
+ begin
+ PurchasePostPrepayments.Invoice(PurchaseHeader);
+ exit(PurchaseHeader."Last Prepayment No.");
+ end;
+
+ procedure AssignCFPaymentTermToCustomer(var Customer: Record Customer; PaymentTermsCode: Code[10])
+ begin
+ // An empty payment terms code creates a default payment term code
+ Customer.Validate("Cash Flow Payment Terms Code", GetPaymentTermsCode(PaymentTermsCode));
+ Customer.Modify(true);
+ end;
+
+ procedure AssignPaymentTermToCustomer(var Customer: Record Customer; PaymentTermsCode: Code[10])
+ begin
+ // An empty payment terms code creates a default payment term code
+ Customer.Validate("Payment Terms Code", GetPaymentTermsCode(PaymentTermsCode));
+ Customer.Modify(true);
+ end;
+
+ procedure AssignCFPaymentTermToVendor(var Vendor: Record Vendor; PaymentTermsCode: Code[10])
+ begin
+ // An empty payment terms code creates a default payment term code
+ Vendor.Validate("Cash Flow Payment Terms Code", GetPaymentTermsCode(PaymentTermsCode));
+ Vendor.Modify(true);
+ end;
+
+ procedure AssignPaymentTermToVendor(var Vendor: Record Vendor; PaymentTermsCode: Code[10])
+ begin
+ // An empty payment terms code creates a default payment term code
+ Vendor.Validate("Payment Terms Code", GetPaymentTermsCode(PaymentTermsCode));
+ Vendor.Modify(true);
+ end;
+
+ procedure ApplyInvoicePayment(var GenJournalLine: Record "Gen. Journal Line"; PartnerNo: Code[20]; PartnerAccountType: Enum "Gen. Journal Account Type"; InvoiceNoToApply: Code[20]; AmountToApply: Decimal)
+ var
+ GenJournalBatch: Record "Gen. Journal Batch";
+ begin
+ SelectAndClearGenJournalBatch(GenJournalBatch);
+ LibraryERM.CreateGeneralJnlLine(
+ GenJournalLine, GenJournalBatch."Journal Template Name", GenJournalBatch.Name, GenJournalLine."Document Type"::Payment,
+ PartnerAccountType, PartnerNo, AmountToApply);
+ // GenJournalLine.VALIDATE("Posting Date",PaymentDate);
+ // GenJournalLine.VALIDATE("Document Date",PaymentDate);
+ GenJournalLine.Validate("Applies-to Doc. Type", GenJournalLine."Applies-to Doc. Type"::Invoice);
+ GenJournalLine.Validate("Applies-to Doc. No.", InvoiceNoToApply);
+ GenJournalLine.Modify(true);
+ LibraryERM.PostGeneralJnlLine(GenJournalLine);
+ end;
+
+ procedure CalcDiscAmtFromGenJnlLine(GenJnlLine: Record "Gen. Journal Line"; DiscountPercentage: Decimal): Decimal
+ begin
+ if GenJnlLine."Account Type" = GenJnlLine."Account Type"::Vendor then
+ GenJnlLine.Amount := -GenJnlLine.Amount;
+ exit(CalculateDiscountAmount(GenJnlLine.Amount, DiscountPercentage));
+ end;
+
+ procedure CalcCustDiscAmtLCY(CustLedgEntry: Record "Cust. Ledger Entry"; DiscountPercentage: Decimal; ExchRateAmount: Decimal): Decimal
+ begin
+ exit(
+ Round(CalcCustDiscAmt(CustLedgEntry, DiscountPercentage) * ExchRateAmount, LibraryERM.GetAmountRoundingPrecision()));
+ end;
+
+ procedure CalcVendDiscAmtLCY(VendLedgEntry: Record "Vendor Ledger Entry"; DiscountPercentage: Decimal; ExchRateAmount: Decimal): Decimal
+ begin
+ exit(
+ Round(CalcVendDiscAmt(VendLedgEntry, DiscountPercentage) * ExchRateAmount, LibraryERM.GetAmountRoundingPrecision()));
+ end;
+
+ procedure CalcCustDiscAmt(CustLedgEntry: Record "Cust. Ledger Entry"; DiscountPercentage: Decimal): Decimal
+ begin
+ exit(
+ Round(CustLedgEntry.Amount * DiscountPercentage / 100, LibraryERM.GetAmountRoundingPrecision()));
+ end;
+
+ procedure CalcVendDiscAmt(VendLedgEntry: Record "Vendor Ledger Entry"; DiscountPercentage: Decimal): Decimal
+ begin
+ exit(
+ Round(VendLedgEntry.Amount * DiscountPercentage / 100, LibraryERM.GetAmountRoundingPrecision()));
+ end;
+
+ procedure CalcSalesExpectedPrepmtAmounts(SalesHeader: Record "Sales Header"; DiscountPercentage: Decimal; var ExpectedOrderAmount: Decimal; var ExpectedPrePmtAmount: Decimal)
+ var
+ TotalOrderAmount: Decimal;
+ begin
+ TotalOrderAmount := GetTotalSalesAmount(SalesHeader, false);
+ ExpectedPrePmtAmount := Round(TotalOrderAmount / 100 * SalesHeader."Prepayment %");
+ ExpectedOrderAmount := TotalOrderAmount - ExpectedPrePmtAmount;
+ if DiscountPercentage > 0 then begin
+ ExpectedOrderAmount -= CalculateDiscountAmount(ExpectedOrderAmount, DiscountPercentage);
+ ExpectedPrePmtAmount -= CalculateDiscountAmount(ExpectedPrePmtAmount, DiscountPercentage);
+ end;
+ end;
+
+ procedure CalcPurchExpectedPrepmtAmounts(PurchaseHeader: Record "Purchase Header"; DiscountPercentage: Decimal; var ExpectedOrderAmount: Decimal; var ExpectedPrePmtAmount: Decimal)
+ var
+ TotalOrderAmount: Decimal;
+ begin
+ TotalOrderAmount := GetTotalPurchaseAmount(PurchaseHeader, false);
+ ExpectedPrePmtAmount := Round(TotalOrderAmount / 100 * PurchaseHeader."Prepayment %");
+ ExpectedOrderAmount := TotalOrderAmount - ExpectedPrePmtAmount;
+ if DiscountPercentage > 0 then begin
+ ExpectedOrderAmount -= CalculateDiscountAmount(ExpectedOrderAmount, DiscountPercentage);
+ ExpectedPrePmtAmount -= CalculateDiscountAmount(ExpectedPrePmtAmount, DiscountPercentage);
+ end;
+ end;
+
+ procedure CalculateDiscountAmount(Amount: Decimal; DiscountPercentage: Decimal): Decimal
+ begin
+ exit(Round(Amount / 100 * DiscountPercentage, LibraryERM.GetAmountRoundingPrecision()));
+ end;
+
+ procedure ChangeWorkdateByDateFormula(BaseDateFormula: DateFormula; CustomDateFormula: DateFormula; AdditionalDateFormula: DateFormula) OldWorkDate: Date
+ begin
+ OldWorkDate := ChangeWorkdate(GenerateDateFromFormulas(WorkDate(), BaseDateFormula, AdditionalDateFormula, CustomDateFormula));
+ end;
+
+ procedure ChangeWorkdate(NewWorkDate: Date) OldWorkDate: Date
+ begin
+ OldWorkDate := WorkDate();
+ WorkDate := NewWorkDate;
+ end;
+
+ procedure CreateLedgerEntry(var GenJournalLine: Record "Gen. Journal Line"; PartnerNo: Code[20]; Amount: Decimal; AccountType: Enum "Gen. Journal Account Type"; DocumentType: Enum "Gen. Journal Document Type")
+ var
+ GenJournalBatch: Record "Gen. Journal Batch";
+ begin
+ SelectAndClearGenJournalBatch(GenJournalBatch);
+ LibraryERM.CreateGeneralJnlLine(
+ GenJournalLine, GenJournalBatch."Journal Template Name", GenJournalBatch.Name, DocumentType,
+ AccountType, PartnerNo, Amount);
+ LibraryERM.PostGeneralJnlLine(GenJournalLine);
+ end;
+
+ procedure CreateAndApplySalesInvPayment(var GenJournalLine: Record "Gen. Journal Line"; CustomerNo: Code[20]; SalesInvoiceAmount: Decimal; AmountToApply: Decimal; DateFormula1: DateFormula; DateFormula2: DateFormula; DateFormula3: DateFormula)
+ var
+ GenJournalBatch: Record "Gen. Journal Batch";
+ PaymentDate: Date;
+ begin
+ PaymentDate := GenerateDateFromFormulas(WorkDate(), DateFormula1, DateFormula2, DateFormula3);
+ SelectAndClearGenJournalBatch(GenJournalBatch);
+ LibraryERM.CreateGeneralJnlLine(
+ GenJournalLine, GenJournalBatch."Journal Template Name", GenJournalBatch.Name, GenJournalLine."Document Type"::Invoice,
+ GenJournalLine."Account Type"::Customer, CustomerNo, SalesInvoiceAmount);
+ LibraryERM.CreateGeneralJnlLine(
+ GenJournalLine, GenJournalBatch."Journal Template Name", GenJournalBatch.Name, GenJournalLine."Document Type"::Payment,
+ GenJournalLine."Account Type"::Customer, CustomerNo, AmountToApply);
+ GenJournalLine.Validate("Posting Date", PaymentDate);
+ GenJournalLine.Validate("Document Date", PaymentDate);
+ GenJournalLine.Validate("Applies-to Doc. Type", GenJournalLine."Applies-to Doc. Type"::Invoice);
+ GenJournalLine.Validate("Applies-to Doc. No.", GenJournalLine."Document No.");
+ GenJournalLine.Modify(true);
+ LibraryERM.PostGeneralJnlLine(GenJournalLine);
+ end;
+
+ procedure CreateAndApplyVendorInvPmt(var GenJournalLine: Record "Gen. Journal Line"; VendorNo: Code[20]; InvoiceAmount: Decimal; AmountToApply: Decimal; DateFormula1: DateFormula; DateFormula2: DateFormula; DateFormula3: DateFormula)
+ var
+ GenJournalBatch: Record "Gen. Journal Batch";
+ PaymentDate: Date;
+ begin
+ PaymentDate := GenerateDateFromFormulas(WorkDate(), DateFormula1, DateFormula2, DateFormula3);
+ SelectAndClearGenJournalBatch(GenJournalBatch);
+ LibraryERM.CreateGeneralJnlLine(
+ GenJournalLine, GenJournalBatch."Journal Template Name", GenJournalBatch.Name, GenJournalLine."Document Type"::Invoice,
+ GenJournalLine."Account Type"::Vendor, VendorNo, InvoiceAmount);
+ LibraryERM.CreateGeneralJnlLine(
+ GenJournalLine, GenJournalBatch."Journal Template Name", GenJournalBatch.Name, GenJournalLine."Document Type"::Payment,
+ GenJournalLine."Account Type"::Vendor, VendorNo, AmountToApply);
+ GenJournalLine.Validate("Posting Date", PaymentDate);
+ GenJournalLine.Validate("Document Date", PaymentDate);
+ GenJournalLine.Validate("Applies-to Doc. Type", GenJournalLine."Applies-to Doc. Type"::Invoice);
+ GenJournalLine.Validate("Applies-to Doc. No.", GenJournalLine."Document No.");
+ GenJournalLine.Modify(true);
+ LibraryERM.PostGeneralJnlLine(GenJournalLine);
+ end;
+
+ procedure CreateBudgetEntry(var GLBudgetEntry: Record "G/L Budget Entry"; BudgetDate: Date)
+ var
+ GLBudgetName: Record "G/L Budget Name";
+ GLAccount: Record "G/L Account";
+ CFAccount: Record "Cash Flow Account";
+ begin
+ LibraryERM.CreateGLBudgetName(GLBudgetName);
+ FindCFBudgetAccount(CFAccount);
+ FindFirstGLAccFromCFAcc(GLAccount, CFAccount);
+ LibraryERM.CreateGLBudgetEntry(GLBudgetEntry, BudgetDate, GLAccount."No.", GLBudgetName.Name);
+ GLBudgetEntry.Validate(Amount, LibraryRandom.RandDec(100, 2));
+ GLBudgetEntry.Modify(true);
+ end;
+
+ procedure CreateDefaultPaymentTerms(var PaymentTerms: Record "Payment Terms")
+ begin
+ LibraryERM.CreatePaymentTerms(PaymentTerms);
+ Evaluate(PaymentTerms."Due Date Calculation", '<0D>');
+ Evaluate(PaymentTerms."Discount Date Calculation", '<0D>');
+ PaymentTerms.Validate("Discount %", 0);
+ PaymentTerms.Modify(true);
+ end;
+
+ procedure CreateCustWithCFDsctPmtTerm(var Customer: Record Customer; var PaymentTerms: Record "Payment Terms")
+ begin
+ LibrarySales.CreateCustomer(Customer);
+ LibraryERM.GetDiscountPaymentTerm(PaymentTerms);
+ AssignCFPaymentTermToCustomer(Customer, PaymentTerms.Code);
+ end;
+
+ procedure CreateVendorWithCFDsctPmtTerm(var Vendor: Record Vendor; var PaymentTerms: Record "Payment Terms")
+ begin
+ LibraryPurchase.CreateVendor(Vendor);
+ LibraryERM.GetDiscountPaymentTerm(PaymentTerms);
+ AssignCFPaymentTermToVendor(Vendor, PaymentTerms.Code);
+ end;
+
+ procedure CreateFixedAssetForInvestment(var FixedAsset: Record "Fixed Asset"; DepreciationBookCode: Code[10]; FAPostingDateFormula: DateFormula; InvestmentAmount: Decimal)
+ var
+ FADepreciationBook: Record "FA Depreciation Book";
+ FAJournalTemplate: Record "FA Journal Template";
+ FAJournalBatch: Record "FA Journal Batch";
+ FAJournalLine: Record "FA Journal Line";
+ NoSeries: Record "No. Series";
+ NoSeriesCodeunit: Codeunit "No. Series";
+ begin
+ LibraryFA.CreateFixedAsset(FixedAsset);
+ FixedAsset.Validate("Budgeted Asset", true);
+ FixedAsset.Modify(true);
+ LibraryFA.CreateFADepreciationBook(FADepreciationBook, FixedAsset."No.", DepreciationBookCode);
+ FAJournalTemplate.SetRange(Recurring, false);
+ LibraryFA.FindFAJournalTemplate(FAJournalTemplate);
+ LibraryFA.CreateFAJournalBatch(FAJournalBatch, FAJournalTemplate.Name);
+ FAJournalBatch.Validate("No. Series", LibraryUtility.GetGlobalNoSeriesCode());
+ FAJournalBatch.Modify(true);
+ LibraryFA.CreateFAJournalLine(FAJournalLine, FAJournalTemplate.Name, FAJournalBatch.Name);
+ FAJournalLine."Document Type" := FAJournalLine."Document Type"::Invoice;
+ NoSeries.Get(FAJournalBatch."No. Series");
+ FAJournalLine.Validate("Document No.", NoSeriesCodeunit.PeekNextNo(FAJournalBatch."No. Series"));
+ FAJournalLine.Validate("FA No.", FixedAsset."No.");
+ FAJournalLine.Validate("Depreciation Book Code", FADepreciationBook."Depreciation Book Code");
+ FAJournalLine.Validate(Amount, InvestmentAmount);
+ FAJournalLine.Validate("FA Posting Date", CalcDate(FAPostingDateFormula, WorkDate()));
+ FAJournalLine.Modify(true);
+ LibraryFA.PostFAJournalLine(FAJournalLine);
+ end;
+
+ procedure CreateFixedAssetForDisposal(var FixedAsset: Record "Fixed Asset"; DepreciationBookCode: Code[10]; DepreciationStartDateFormula: DateFormula; DepreciationEndDateFormula: DateFormula; DisposalDateFormula: DateFormula; ExpDisposalAmount: Decimal)
+ var
+ FADepreciationBook: Record "FA Depreciation Book";
+ begin
+ LibraryFA.CreateFixedAsset(FixedAsset);
+ LibraryFA.CreateFADepreciationBook(FADepreciationBook, FixedAsset."No.", DepreciationBookCode);
+ FADepreciationBook."Depreciation Starting Date" := CalcDate(DepreciationStartDateFormula, WorkDate());
+ FADepreciationBook."Depreciation Ending Date" := CalcDate(DepreciationEndDateFormula, WorkDate());
+ FADepreciationBook."Projected Disposal Date" := CalcDate(DisposalDateFormula, WorkDate());
+ FADepreciationBook."Projected Proceeds on Disposal" := ExpDisposalAmount;
+ FADepreciationBook.Modify(true);
+ end;
+
+ procedure CreateManualPayment(var CFManualExpense: Record "Cash Flow Manual Expense")
+ var
+ CashFlowAccount: Record "Cash Flow Account";
+ begin
+ LibraryCashFlowForecast.CreateCashFlowAccount(CashFlowAccount, CashFlowAccount."Account Type"::Entry);
+ LibraryCashFlowForecast.CreateManualLinePayment(CFManualExpense, CashFlowAccount."No.");
+
+ Evaluate(CFManualExpense."Recurring Frequency", '<1D>');
+
+ CFManualExpense.Validate(Amount, LibraryRandom.RandInt(500));
+ CFManualExpense.Modify(true);
+ end;
+
+ procedure CreateManualRevenue(var CFManualRevenue: Record "Cash Flow Manual Revenue")
+ var
+ CashFlowAccount: Record "Cash Flow Account";
+ begin
+ LibraryCashFlowForecast.CreateCashFlowAccount(CashFlowAccount, CashFlowAccount."Account Type"::Entry);
+ LibraryCashFlowForecast.CreateManualLineRevenue(CFManualRevenue, CashFlowAccount."No.");
+
+ Evaluate(CFManualRevenue."Recurring Frequency", '<1D>');
+
+ CFManualRevenue.Validate(Amount, LibraryRandom.RandInt(500));
+ CFManualRevenue.Modify(true);
+ end;
+
+ procedure CreateRandomDateFormula(var ResultDateFormula: DateFormula)
+ begin
+ Evaluate(ResultDateFormula, StrSubstNo('<%1D>', LibraryRandom.RandInt(5)));
+ end;
+
+ procedure CreateSpecificCashFlowCard(var CashFlowForecast: Record "Cash Flow Forecast"; ConsiderDiscount: Boolean; ConsiderPmtTerms: Boolean)
+ begin
+ LibraryCashFlowForecast.CreateCashFlowCard(CashFlowForecast);
+ CashFlowForecast."Manual Payments To" := CashFlowForecast."Manual Payments From";
+ CashFlowForecast.Validate("Consider Discount", ConsiderDiscount);
+ CashFlowForecast.Validate("Consider CF Payment Terms", ConsiderPmtTerms);
+ CashFlowForecast.Modify(true);
+ end;
+
+ procedure CreateCashFlowForecastDefault(var CashFlowForecast: Record "Cash Flow Forecast")
+ begin
+ CreateSpecificCashFlowCard(CashFlowForecast, false, false);
+ end;
+
+ procedure CreateCashFlowForecastConsiderDiscount(var CashFlowForecast: Record "Cash Flow Forecast")
+ begin
+ CreateSpecificCashFlowCard(CashFlowForecast, true, false);
+ end;
+
+ procedure CreateCashFlowForecastConsiderCFPmtTerms(var CashFlowForecast: Record "Cash Flow Forecast")
+ begin
+ CreateSpecificCashFlowCard(CashFlowForecast, false, true);
+ end;
+
+ procedure CreateCashFlowForecastConsiderDiscountAndCFPmtTerms(var CashFlowForecast: Record "Cash Flow Forecast")
+ begin
+ CreateSpecificCashFlowCard(CashFlowForecast, true, true);
+ end;
+
+ procedure CreateSalesOrder(var SalesHeader: Record "Sales Header"; GLAccount: Record "G/L Account"; PaymentTermsCode: Code[10]; CFPaymentTermsCode: Code[10])
+ var
+ Customer: Record Customer;
+ begin
+ Customer.Get(
+ LibrarySales.CreateCustomerWithBusPostingGroups(
+ GLAccount."Gen. Bus. Posting Group", GLAccount."VAT Bus. Posting Group"));
+ AssignPaymentTermToCustomer(Customer, PaymentTermsCode);
+ AssignCFPaymentTermToCustomer(Customer, CFPaymentTermsCode);
+
+ LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Order, Customer."No.");
+
+ CreateSalesLine(SalesHeader, GLAccount);
+ CreateSalesLine(SalesHeader, GLAccount);
+ CreateSalesLine(SalesHeader, GLAccount);
+ end;
+
+ procedure CreateSpecificSalesOrder(var SalesHeader: Record "Sales Header"; PaymentTermsCode: Code[10]; CFPaymentTermsCode: Code[10])
+ var
+ GLAccount: Record "G/L Account";
+ begin
+ GLAccount.Get(LibraryERM.CreateGLAccountWithSalesSetup());
+ CreateSalesOrder(SalesHeader, GLAccount, PaymentTermsCode, CFPaymentTermsCode);
+ end;
+
+ procedure CreateDefaultSalesOrder(var SalesHeader: Record "Sales Header")
+ begin
+ CreateSpecificSalesOrder(SalesHeader, '', '');
+ end;
+
+ procedure CreatePrepmtSalesOrder(var SalesHeader: Record "Sales Header"; PaymentTermsCode: Code[10]; CFPaymentTermsCode: Code[10])
+ var
+ GLAccount: Record "G/L Account";
+ VATPostingSetup: Record "VAT Posting Setup";
+ begin
+ LibrarySales.CreatePrepaymentVATSetup(GLAccount, VATPostingSetup."VAT Calculation Type"::"Normal VAT");
+ CreateSalesOrder(SalesHeader, GLAccount, PaymentTermsCode, CFPaymentTermsCode);
+ end;
+
+ procedure CreateSalesLine(SalesHeader: Record "Sales Header"; GLAccount: Record "G/L Account")
+ var
+ SalesLine: Record "Sales Line";
+ VATPostingSetup: Record "VAT Posting Setup";
+ GLAccountNo: Code[20];
+ begin
+ GLAccountNo := GLAccount."No.";
+ if GLAccountNo = '' then begin
+ VATPostingSetup.SetRange("VAT Bus. Posting Group", SalesHeader."VAT Bus. Posting Group");
+ VATPostingSetup.SetFilter("VAT Calculation Type", '<>%1', VATPostingSetup."VAT Calculation Type"::"Full VAT");
+ VATPostingSetup.SetFilter("Sales VAT Account", '<>%1', '');
+ VATPostingSetup.FindFirst();
+ GLAccountNo := LibraryERM.CreateGLAccountWithVATPostingSetup(VATPostingSetup, GLAccount."Gen. Posting Type"::Purchase);
+ end;
+ LibrarySales.CreateSalesLine(
+ SalesLine, SalesHeader, SalesLine.Type::"G/L Account", GLAccountNo, LibraryRandom.RandInt(10));
+ SalesLine.Validate("Unit Price", LibraryRandom.RandInt(100));
+ SalesLine.Modify(true);
+ end;
+
+ procedure CreatePurchaseOrder(var PurchaseHeader: Record "Purchase Header"; GLAccount: Record "G/L Account"; PaymentTermsCode: Code[10]; CFPaymentTermsCode: Code[10])
+ var
+ Vendor: Record Vendor;
+ begin
+ Vendor.Get(
+ LibraryPurchase.CreateVendorWithBusPostingGroups(
+ GLAccount."Gen. Bus. Posting Group", GLAccount."VAT Bus. Posting Group"));
+ AssignPaymentTermToVendor(Vendor, PaymentTermsCode);
+ AssignCFPaymentTermToVendor(Vendor, CFPaymentTermsCode);
+
+ LibraryPurchase.CreatePurchHeader(PurchaseHeader, PurchaseHeader."Document Type"::Order, Vendor."No.");
+
+ CreatePurchaseLine(PurchaseHeader, GLAccount);
+ CreatePurchaseLine(PurchaseHeader, GLAccount);
+ CreatePurchaseLine(PurchaseHeader, GLAccount);
+ end;
+
+ procedure CreateSpecificPurchaseOrder(var PurchaseHeader: Record "Purchase Header"; PaymentTermsCode: Code[10]; CFPaymentTermsCode: Code[10])
+ var
+ GLAccount: Record "G/L Account";
+ begin
+ GLAccount.Get(LibraryERM.CreateGLAccountWithPurchSetup());
+ CreatePurchaseOrder(PurchaseHeader, GLAccount, PaymentTermsCode, CFPaymentTermsCode);
+ end;
+
+ procedure CreateDefaultPurchaseOrder(var PurchaseHeader: Record "Purchase Header")
+ begin
+ CreateSpecificPurchaseOrder(PurchaseHeader, '', '');
+ end;
+
+ procedure CreatePrepmtPurchaseOrder(var PurchaseHeader: Record "Purchase Header"; PaymentTermsCode: Code[10]; CFPaymentTermsCode: Code[10])
+ var
+ GLAccount: Record "G/L Account";
+ VATPostingSetup: Record "VAT Posting Setup";
+ begin
+ LibraryPurchase.CreatePrepaymentVATSetup(GLAccount, VATPostingSetup."VAT Calculation Type"::"Normal VAT");
+ CreatePurchaseOrder(PurchaseHeader, GLAccount, PaymentTermsCode, CFPaymentTermsCode);
+ end;
+
+ procedure CreatePurchaseLine(PurchaseHeader: Record "Purchase Header"; GLAccount: Record "G/L Account")
+ var
+ PurchaseLine: Record "Purchase Line";
+ VATPostingSetup: Record "VAT Posting Setup";
+ GLAccountNo: Code[20];
+ Handled: Boolean;
+ begin
+ OnBeforeCreatePurchaseLine(PurchaseHeader, GLAccount, Handled);
+ if Handled then
+ exit;
+
+ GLAccountNo := GLAccount."No.";
+ if GLAccountNo = '' then begin
+ LibraryERM.CreateVATPostingSetupWithAccounts(
+ VATPostingSetup, VATPostingSetup."VAT Calculation Type"::"Normal VAT", LibraryRandom.RandIntInRange(10, 25));
+ VATPostingSetup."VAT Bus. Posting Group" := PurchaseHeader."VAT Bus. Posting Group";
+ VATPostingSetup.Insert();
+ GLAccountNo := LibraryERM.CreateGLAccountWithVATPostingSetup(VATPostingSetup, GLAccount."Gen. Posting Type"::Purchase);
+ end;
+ LibraryPurchase.CreatePurchaseLine(
+ PurchaseLine, PurchaseHeader, PurchaseLine.Type::"G/L Account", GLAccountNo, LibraryRandom.RandInt(10));
+ PurchaseLine.Validate("Direct Unit Cost", LibraryRandom.RandInt(100));
+ PurchaseLine.Modify(true);
+
+ OnAfterCreatePurchaseLine(PurchaseHeader, GLAccount);
+ end;
+
+#if not CLEAN27
+ [Obsolete('Moved to codeunit Library Service', '27.0')]
+ procedure CreateSpecificServiceOrder(var ServiceHeader: Record "Service Header"; PaymentTermsCode: Code[10]; CFPaymentTermsCode: Code[10])
+ var
+ LibraryService: Codeunit "Library - Service";
+ begin
+ LibraryService.CreateSpecificServiceOrder(ServiceHeader, PaymentTermsCode, CFPaymentTermsCode);
+ end;
+#endif
+
+#if not CLEAN27
+ [Obsolete('Moved to codeunit Library Service', '27.0')]
+ procedure CreateDefaultServiceOrder(var ServiceHeader: Record "Service Header")
+ begin
+#pragma warning disable AL0432
+ CreateSpecificServiceOrder(ServiceHeader, '', '');
+#pragma warning restore AL0432
+ end;
+#endif
+
+#if not CLEAN27
+ [Obsolete('Moved to codeunit Library Service', '27.0')]
+ procedure CreateServiceLines(ServiceHeader: Record "Service Header")
+ var
+ LibraryService: Codeunit "Library - Service";
+ begin
+ LibraryService.CreateServiceLines(ServiceHeader);
+ end;
+#endif
+
+ procedure CreatePrepaymentAccount(GeneralPostingSetup: Record "General Posting Setup"; VATBusPostingGroup: Code[20]; VATProdPostingGroup: Code[20]): Code[20]
+ var
+ GLAccount: Record "G/L Account";
+ begin
+ LibraryERM.CreateGLAccount(GLAccount);
+ GLAccount.Validate("Gen. Bus. Posting Group", GeneralPostingSetup."Gen. Bus. Posting Group");
+ GLAccount.Validate("Gen. Prod. Posting Group", GeneralPostingSetup."Gen. Prod. Posting Group");
+ GLAccount.Validate("VAT Bus. Posting Group", VATBusPostingGroup);
+ GLAccount.Validate("VAT Prod. Posting Group", VATProdPostingGroup);
+ GLAccount.Modify(true);
+ exit(GLAccount."No.");
+ end;
+
+ procedure CreateDefaultJob(var Job: Record Job)
+ var
+ JobTask: Record "Job Task";
+ JobPlanningLine: Record "Job Planning Line";
+ begin
+ LibraryJob.CreateJob(Job);
+ LibraryJob.CreateJobTask(Job, JobTask);
+
+ CreateDefaultJobPlanningLine(JobTask, JobPlanningLine."Line Type"::Budget, JobPlanningLine);
+ CreateDefaultJobPlanningLine(JobTask, JobPlanningLine."Line Type"::Billable, JobPlanningLine);
+ CreateDefaultJobPlanningLine(JobTask, JobPlanningLine."Line Type"::"Both Budget and Billable", JobPlanningLine);
+ end;
+
+ procedure CreateDefaultJobForCustomer(var Job: Record Job; CustomerNo: Code[20])
+ var
+ JobTask: Record "Job Task";
+ JobPlanningLine: Record "Job Planning Line";
+ begin
+ LibraryJob.CreateJob(Job, CustomerNo);
+ LibraryJob.CreateJobTask(Job, JobTask);
+
+ CreateDefaultJobPlanningLine(JobTask, JobPlanningLine."Line Type"::Budget, JobPlanningLine);
+ CreateDefaultJobPlanningLine(JobTask, JobPlanningLine."Line Type"::Billable, JobPlanningLine);
+ CreateDefaultJobPlanningLine(JobTask, JobPlanningLine."Line Type"::"Both Budget and Billable", JobPlanningLine);
+ end;
+
+ procedure CreateJobPlanningLine(Job: Record Job; LineType: Enum "Job Planning Line Line Type"; var JobPlanningLine: Record "Job Planning Line")
+ var
+ JobTask: Record "Job Task";
+ begin
+ JobTask.SetRange("Job No.", Job."No.");
+ JobTask.FindFirst();
+ CreateDefaultJobPlanningLine(JobTask, LineType, JobPlanningLine);
+ end;
+
+ local procedure CreateDefaultJobPlanningLine(JobTask: Record "Job Task"; LineType: Enum "Job Planning Line Line Type"; var JobPlanningLine: Record "Job Planning Line")
+ begin
+ LibraryJob.CreateJobPlanningLine(LineType, JobPlanningLine.Type::Resource, JobTask, JobPlanningLine);
+ end;
+
+ procedure FillJournal(ConsiderSource: array[16] of Boolean; CFNo: Code[20]; GroupByDocumentType: Boolean)
+ begin
+ LibraryCashFlowForecast.ClearJournal();
+ LibraryCashFlowForecast.FillJournal(ConsiderSource, CFNo, GroupByDocumentType);
+ end;
+
+ procedure FillJnlOnCertDateFormulas(ConsiderSource: array[16] of Boolean; CFNo: Code[20]; BaseDateFormula: DateFormula; CustomDateFormula: DateFormula; AdditionalDateFormula: DateFormula)
+ var
+ ForecastDate: Date;
+ begin
+ ForecastDate := GenerateDateFromFormulas(WorkDate(), BaseDateFormula, AdditionalDateFormula, CustomDateFormula);
+ FillJournalOnCertainDate(ConsiderSource, CFNo, ForecastDate);
+ end;
+
+ procedure FillJournalOnCertainDate(ConsiderSource: array[16] of Boolean; CFNo: Code[20]; ForecastDate: Date)
+ var
+ OldWorkDate: Date;
+ begin
+ OldWorkDate := ChangeWorkdate(ForecastDate);
+ FillJournal(ConsiderSource, CFNo, false);
+ WorkDate := OldWorkDate;
+ end;
+
+ procedure FilterSingleJournalLine(var CFWorksheetLine: Record "Cash Flow Worksheet Line"; DocumentNo: Code[20]; SourceType: Enum "Cash Flow Source Type"; CashFlowNo: Code[20]): Integer
+ begin
+ // Filters cash flow journal lines based on the given parameters
+ // Returns the number of lines found based on the filter
+
+ CFWorksheetLine.SetRange("Cash Flow Forecast No.", CashFlowNo);
+ CFWorksheetLine.SetRange("Source Type", SourceType);
+ CFWorksheetLine.SetRange("Document No.", DocumentNo);
+ if CFWorksheetLine.FindFirst() then;
+ exit(CFWorksheetLine.Count);
+ end;
+
+ procedure FindCFLiquidFundAccount(var CFAccount: Record "Cash Flow Account")
+ begin
+ FindFirstCFAccWithGLIntegration(CFAccount, CFAccount."G/L Integration"::Balance);
+ end;
+
+ procedure FindCFBudgetAccount(var CFAccount: Record "Cash Flow Account")
+ begin
+ FindFirstCFAccWithGLIntegration(CFAccount, CFAccount."G/L Integration"::Budget);
+ end;
+
+ local procedure FindFirstCFAccWithGLIntegration(var CFAccount: Record "Cash Flow Account"; GLIntegration: Option)
+ begin
+ CFAccount.SetFilter("G/L Integration", '%1|%2', GLIntegration, CFAccount."G/L Integration"::Both);
+ CFAccount.SetFilter("G/L Account Filter", '<>%1', '');
+ CFAccount.FindFirst();
+ end;
+
+ procedure FindFirstGLAccFromCFAcc(var GLAccount: Record "G/L Account"; CFAccount: Record "Cash Flow Account")
+ begin
+ GLAccount.SetFilter("No.", CFAccount."G/L Account Filter");
+ GLAccount.FindFirst();
+ end;
+
+ procedure FindFirstCustLEFromSO(var CustLedgerEntry: Record "Cust. Ledger Entry"; SalesOrderNo: Code[20])
+ var
+ SalesInvoiceHeader: Record "Sales Invoice Header";
+ begin
+ SalesInvoiceHeader.SetRange("Order No.", SalesOrderNo);
+ SalesInvoiceHeader.FindFirst();
+ CustLedgerEntry.SetRange("Document No.", SalesInvoiceHeader."No.");
+ CustLedgerEntry.FindFirst();
+ end;
+
+ procedure FindFirstVendorLEFromPO(var VendorLedgerEntry: Record "Vendor Ledger Entry"; PurchaseOrderNo: Code[20])
+ var
+ PurchInvHeader: Record "Purch. Inv. Header";
+ begin
+ PurchInvHeader.SetRange("Order No.", PurchaseOrderNo);
+ PurchInvHeader.FindFirst();
+ VendorLedgerEntry.SetRange("Document No.", PurchInvHeader."No.");
+ VendorLedgerEntry.FindFirst();
+ end;
+
+ procedure FindCustomerCFPaymentTerms(var PaymentTerms: Record "Payment Terms"; CustomerNo: Code[20])
+ var
+ Customer: Record Customer;
+ begin
+ Customer.Get(CustomerNo);
+ PaymentTerms.Get(Customer."Cash Flow Payment Terms Code");
+ end;
+
+ procedure FindSalesLine(var SalesLine: Record "Sales Line"; SalesHeader: Record "Sales Header")
+ begin
+ SalesLine.SetRange("Document Type", SalesHeader."Document Type");
+ SalesLine.SetRange("Document No.", SalesHeader."No.");
+ SalesLine.FindSet();
+ end;
+
+ procedure FindPurchaseLine(var PurchaseLine: Record "Purchase Line"; PurchaseHeader: Record "Purchase Header")
+ begin
+ PurchaseLine.SetRange("Document Type", PurchaseHeader."Document Type");
+ PurchaseLine.SetRange("Document No.", PurchaseHeader."No.");
+ PurchaseLine.FindSet();
+ end;
+
+ procedure GenerateDateFromFormulaArray(BaseDate: Date; DateFormulas: array[3] of DateFormula): Date
+ var
+ TempDate: Date;
+ I: Integer;
+ begin
+ TempDate := BaseDate;
+ for I := 1 to ArrayLen(DateFormulas) do
+ TempDate := CalcDate(DateFormulas[I], TempDate);
+ exit(TempDate);
+ end;
+
+ procedure GenerateDateFromFormulas(BaseDate: Date; DateFormula1: DateFormula; DateFormula2: DateFormula; DateFormula3: DateFormula): Date
+ var
+ TempDate: Date;
+ begin
+ TempDate := BaseDate;
+ TempDate := CalcDate(DateFormula1, TempDate);
+ TempDate := CalcDate(DateFormula2, TempDate);
+ TempDate := CalcDate(DateFormula3, TempDate);
+ exit(TempDate);
+ end;
+
+ procedure GetDifferentDsctPaymentTerms(var PaymentTerms: Record "Payment Terms"; PmtTermsCodeToDifferFrom: Code[20])
+ var
+ PaymentTerms2: Record "Payment Terms";
+ begin
+ PaymentTerms2.Get(PmtTermsCodeToDifferFrom);
+ LibraryERM.CreatePaymentTerms(PaymentTerms);
+ Evaluate(PaymentTerms."Due Date Calculation", Format(PaymentTerms2."Due Date Calculation") + '+<1M>');
+ Evaluate(PaymentTerms."Discount Date Calculation", Format(PaymentTerms2."Discount Date Calculation") + '+<1D>');
+ PaymentTerms.Validate("Discount %", PaymentTerms2."Discount %" + 1);
+ PaymentTerms.Modify(true);
+ end;
+
+ procedure GetTotalSalesAmount(SalesHeader: Record "Sales Header"; ConsiderDefaultPmtDiscount: Boolean): Decimal
+ var
+ SalesLine: Record "Sales Line";
+ TotalAmount: Decimal;
+ TotalDiscountAmount: Decimal;
+ LineAmount: Decimal;
+ begin
+ TotalAmount := 0;
+ TotalDiscountAmount := 0;
+ SalesLine.SetRange("Document No.", SalesHeader."No.");
+ SalesLine.SetRange("Document Type", SalesHeader."Document Type");
+ SalesLine.FindSet();
+ repeat
+ LineAmount := SalesLine."Outstanding Amount (LCY)";
+ TotalAmount += LineAmount;
+ if ConsiderDefaultPmtDiscount then
+ TotalDiscountAmount +=
+ CalculateDiscountAmount(LineAmount, SalesHeader."Payment Discount %");
+ until SalesLine.Next() = 0;
+ exit(TotalAmount - TotalDiscountAmount);
+ end;
+
+ procedure GetTotalPurchaseAmount(PurchaseHeader: Record "Purchase Header"; ConsiderDefaultPmtDiscount: Boolean): Decimal
+ var
+ PurchaseLine: Record "Purchase Line";
+ TotalAmount: Decimal;
+ TotalDiscountAmount: Decimal;
+ LineAmount: Decimal;
+ begin
+ TotalAmount := 0;
+ TotalDiscountAmount := 0;
+ PurchaseLine.SetRange("Document No.", PurchaseHeader."No.");
+ PurchaseLine.SetRange("Document Type", PurchaseHeader."Document Type");
+ PurchaseLine.FindSet();
+ repeat
+ LineAmount := PurchaseLine."Outstanding Amount (LCY)";
+ TotalAmount += LineAmount;
+ if ConsiderDefaultPmtDiscount then
+ TotalDiscountAmount += CalculateDiscountAmount(LineAmount, PurchaseHeader."Payment Discount %");
+ until PurchaseLine.Next() = 0;
+ exit(TotalAmount - TotalDiscountAmount);
+ end;
+
+ procedure GetTotalServiceAmount(ServiceHeader: Record "Service Header"; ConsiderDefaultPmtDiscount: Boolean): Decimal
+ var
+ ServiceLine: Record "Service Line";
+ TotalAmount: Decimal;
+ TotalDiscountAmount: Decimal;
+ LineAmount: Decimal;
+ begin
+ TotalAmount := 0;
+ TotalDiscountAmount := 0;
+ ServiceLine.SetRange("Document No.", ServiceHeader."No.");
+ ServiceLine.SetRange("Document Type", ServiceHeader."Document Type");
+ ServiceLine.FindSet();
+ repeat
+ LineAmount := ServiceLine."Outstanding Amount (LCY)";
+ TotalAmount += LineAmount;
+ if ConsiderDefaultPmtDiscount then
+ TotalDiscountAmount +=
+ CalculateDiscountAmount(LineAmount, ServiceHeader."Payment Discount %");
+ until ServiceLine.Next() = 0;
+
+ exit(TotalAmount - TotalDiscountAmount);
+ end;
+
+ procedure GetTotalAmountForSalesOrderWithCashFlowPaymentTermsDiscount(SalesHeader: Record "Sales Header"): Decimal
+ var
+ SalesLine: Record "Sales Line";
+ Customer: Record Customer;
+ PaymentTermsCashFlow: Record "Payment Terms";
+ TotalAmount: Decimal;
+ TotalDiscountAmount: Decimal;
+ LineAmount: Decimal;
+ begin
+ Customer.Get(SalesHeader."Sell-to Customer No.");
+ PaymentTermsCashFlow.Get(Customer."Cash Flow Payment Terms Code");
+ TotalAmount := 0;
+ TotalDiscountAmount := 0;
+ SalesLine.SetRange("Document No.", SalesHeader."No.");
+ SalesLine.SetRange("Document Type", SalesHeader."Document Type");
+ if SalesLine.FindSet() then
+ repeat
+ LineAmount := SalesLine."Outstanding Amount (LCY)";
+ TotalAmount += LineAmount;
+ TotalDiscountAmount += CalculateDiscountAmount(LineAmount, PaymentTermsCashFlow."Discount %");
+ until SalesLine.Next() = 0;
+ exit(TotalAmount - TotalDiscountAmount);
+ end;
+
+ procedure GetTotalAmountForPurchaseOrderWithCashFlowPaymentTermsDiscount(PurchaseHeader: Record "Purchase Header"): Decimal
+ var
+ PurchaseLine: Record "Purchase Line";
+ Vendor: Record Vendor;
+ PaymentTermsCashFlow: Record "Payment Terms";
+ TotalAmount: Decimal;
+ TotalDiscountAmount: Decimal;
+ LineAmount: Decimal;
+ begin
+ Vendor.Get(PurchaseHeader."Buy-from Vendor No.");
+ PaymentTermsCashFlow.Get(Vendor."Cash Flow Payment Terms Code");
+ TotalAmount := 0;
+ TotalDiscountAmount := 0;
+ PurchaseLine.SetRange("Document No.", PurchaseHeader."No.");
+ PurchaseLine.SetRange("Document Type", PurchaseHeader."Document Type");
+ if PurchaseLine.FindSet() then
+ repeat
+ LineAmount := PurchaseLine."Outstanding Amount (LCY)";
+ TotalAmount += LineAmount;
+ TotalDiscountAmount += CalculateDiscountAmount(LineAmount, PaymentTermsCashFlow."Discount %");
+ until PurchaseLine.Next() = 0;
+ exit(TotalAmount - TotalDiscountAmount);
+ end;
+
+ procedure GetTotalAmountForServiceOrderWithCashFlowPaymentTermsDiscount(ServiceHeader: Record "Service Header"): Decimal
+ var
+ ServiceLine: Record "Service Line";
+ Customer: Record Customer;
+ PaymentTermsCashFlow: Record "Payment Terms";
+ TotalAmount: Decimal;
+ TotalDiscountAmount: Decimal;
+ LineAmount: Decimal;
+ begin
+ Customer.Get(ServiceHeader."Bill-to Customer No.");
+ PaymentTermsCashFlow.Get(Customer."Cash Flow Payment Terms Code");
+ TotalAmount := 0;
+ TotalDiscountAmount := 0;
+ ServiceLine.SetRange("Document No.", ServiceHeader."No.");
+ ServiceLine.SetRange("Document Type", ServiceHeader."Document Type");
+ if ServiceLine.FindSet() then
+ repeat
+ LineAmount := ServiceLine."Outstanding Amount (LCY)";
+ TotalAmount += LineAmount;
+ TotalDiscountAmount += CalculateDiscountAmount(LineAmount, PaymentTermsCashFlow."Discount %");
+ until ServiceLine.Next() = 0;
+ exit(TotalAmount - TotalDiscountAmount);
+ end;
+
+ procedure GetTotalJobsAmount(Job: Record Job; PlanningDate: Date): Decimal
+ var
+ JobTask: Record "Job Task";
+ JobPlanningLine: Record "Job Planning Line";
+ TotalAmount: Decimal;
+ TotalInvoicedAmount: Decimal;
+ LineAmount: Decimal;
+ begin
+ TotalAmount := 0;
+ TotalInvoicedAmount := 0;
+ JobTask.SetRange("Job No.", Job."No.");
+ JobTask.FindFirst();
+ JobPlanningLine.SetRange("Job No.", Job."No.");
+ JobPlanningLine.SetRange("Job Task No.", JobTask."Job Task No.");
+ JobPlanningLine.SetFilter(
+ "Line Type", StrSubstNo('%1|%2', JobPlanningLine."Line Type"::Billable, JobPlanningLine."Line Type"::"Both Budget and Billable"));
+ JobPlanningLine.SetRange("Planning Date", PlanningDate);
+ JobPlanningLine.FindSet();
+ repeat
+ LineAmount := JobPlanningLine."Line Amount (LCY)";
+ TotalAmount += LineAmount;
+ JobPlanningLine.CalcFields("Invoiced Amount (LCY)");
+ TotalInvoicedAmount += JobPlanningLine."Invoiced Amount (LCY)";
+ until JobPlanningLine.Next() = 0;
+ exit(TotalAmount - TotalInvoicedAmount);
+ end;
+
+ procedure GetTotalTaxAmount(TaxDueDate: Date; SourceTableNum: Integer): Decimal
+ var
+ CashFlowSetup: Record "Cash Flow Setup";
+ SalesHeader: Record "Sales Header";
+ SalesLine: Record "Sales Line";
+ PurchaseHeader: Record "Purchase Header";
+ PurchaseLine: Record "Purchase Line";
+ TotalAmount: Decimal;
+ StartDate: Date;
+ EndDate: Date;
+ begin
+ TotalAmount := 0;
+
+ CashFlowSetup.GetTaxPeriodStartEndDates(TaxDueDate, StartDate, EndDate);
+ case SourceTableNum of
+ DATABASE::"Purchase Header":
+ begin
+ PurchaseHeader.SetFilter("Document Date", StrSubstNo('%1..%2', StartDate, EndDate));
+ if PurchaseHeader.FindSet() then
+ repeat
+ PurchaseLine.SetRange("Document Type", PurchaseHeader."Document Type");
+ PurchaseLine.SetRange("Document No.", PurchaseHeader."No.");
+ PurchaseLine.CalcSums("Amount Including VAT", Amount);
+ TotalAmount += PurchaseLine."Amount Including VAT" - PurchaseLine.Amount;
+ until PurchaseHeader.Next() = 0;
+ end;
+ DATABASE::"Sales Header":
+ begin
+ SalesHeader.SetFilter("Document Date", StrSubstNo('%1..%2', StartDate, EndDate));
+ if SalesHeader.FindSet() then
+ repeat
+ SalesLine.SetRange("Document Type", SalesHeader."Document Type");
+ SalesLine.SetRange("Document No.", SalesHeader."No.");
+ SalesLine.CalcSums("Amount Including VAT", Amount);
+ TotalAmount += SalesLine.Amount - SalesLine."Amount Including VAT";
+ until SalesHeader.Next() = 0;
+ end;
+ end;
+ exit(TotalAmount);
+ end;
+
+ local procedure GetPaymentTermsCode(PaymentTermsCode: Code[20]): Code[20]
+ var
+ PaymentTerms: Record "Payment Terms";
+ begin
+ // An empty payment terms code creates a default payment term code
+ if PaymentTermsCode = '' then begin
+ CreateDefaultPaymentTerms(PaymentTerms); // no due, no discount
+ exit(PaymentTerms.Code);
+ end;
+ exit(PaymentTermsCode);
+ end;
+
+ local procedure GetCFAccountNo(SourceType: Enum "Cash Flow Source Type"): Code[20]
+ var
+ CFAccount: Record "Cash Flow Account";
+ begin
+ CFAccount.SetRange("Account Type", CFAccount."Account Type"::Entry);
+ CFAccount.FindSet();
+ CFAccount.Next(SourceType.AsInteger());
+ exit(CFAccount."No.");
+ end;
+
+ procedure InsertCFLedgerEntry(CFNo: Code[20]; AccountNo: Code[20]; SourceType: Enum "Cash Flow Source Type"; CFDate: Date; Amount: Decimal)
+ var
+ CFForecastEntry: Record "Cash Flow Forecast Entry";
+ EntryNo: Integer;
+ begin
+ if CFForecastEntry.FindLast() then
+ EntryNo := CFForecastEntry."Entry No.";
+
+ CFForecastEntry.Init();
+ CFForecastEntry."Entry No." := EntryNo + 1;
+ CFForecastEntry."Cash Flow Forecast No." := CFNo;
+ CFForecastEntry."Source Type" := SourceType;
+ if AccountNo <> '' then
+ CFForecastEntry."Cash Flow Account No." := AccountNo
+ else
+ CFForecastEntry."Cash Flow Account No." := GetCFAccountNo(SourceType);
+ CFForecastEntry."Cash Flow Date" := CFDate;
+ CFForecastEntry.Validate("Amount (LCY)", Amount);
+ CFForecastEntry.Insert();
+ end;
+
+ procedure SelectAndClearGenJournalBatch(var GenJournalBatch: Record "Gen. Journal Batch")
+ begin
+ LibraryERM.SelectGenJnlBatch(GenJournalBatch);
+ LibraryERM.ClearGenJournalLines(GenJournalBatch)
+ end;
+
+ procedure SetExpectedDsctAPmtTermValues(DocType: Option; DocumentNo: Code[20]; PartnerNo: Code[20]; CFSourceDate: Date; ConsiderDsctAndCFPmtTerms: Boolean; var ExpectedCFDate: Date; var ExpectedAmount: Decimal)
+ var
+ PaymentTerms: Record "Payment Terms";
+ Vendor: Record Vendor;
+ SalesHeader: Record "Sales Header";
+ PurchaseHeader: Record "Purchase Header";
+ ServiceHeader: Record "Service Header";
+ TotalAmount: Decimal;
+ begin
+ case DocType of
+ DocumentType::Sale:
+ begin
+ SalesHeader.Get(SalesHeader."Document Type"::Order, DocumentNo);
+ FindCustomerCFPaymentTerms(PaymentTerms, PartnerNo);
+ TotalAmount := GetTotalSalesAmount(SalesHeader, false);
+ end;
+ DocumentType::Service:
+ begin
+ ServiceHeader.Get(ServiceHeader."Document Type"::Order, DocumentNo);
+ FindCustomerCFPaymentTerms(PaymentTerms, PartnerNo);
+ TotalAmount := GetTotalServiceAmount(ServiceHeader, false);
+ end;
+ DocumentType::Purchase:
+ begin
+ Vendor.Get(PartnerNo);
+ PaymentTerms.Get(Vendor."Cash Flow Payment Terms Code");
+ PurchaseHeader.Get(PurchaseHeader."Document Type"::Order, DocumentNo);
+ TotalAmount := GetTotalPurchaseAmount(PurchaseHeader, false);
+ end;
+ else
+ Error(UnhandledDocumentType);
+ end;
+
+ if ConsiderDsctAndCFPmtTerms then begin
+ ExpectedCFDate := CalcDate(PaymentTerms."Discount Date Calculation", CFSourceDate);
+ ExpectedAmount := TotalAmount - CalculateDiscountAmount(TotalAmount, PaymentTerms."Discount %");
+ end else begin
+ ExpectedCFDate := CalcDate(PaymentTerms."Due Date Calculation", CFSourceDate);
+ ExpectedAmount := TotalAmount;
+ end;
+
+ if DocType = DocumentType::Purchase then
+ ExpectedAmount *= -1;
+ end;
+
+ procedure SetDefaultDepreciationBook(DepreciationBookCode: Code[10])
+ var
+ FASetup: Record "FA Setup";
+ begin
+ FASetup.Get();
+
+ FASetup.Validate("Default Depr. Book", DepreciationBookCode);
+ FASetup.Modify(true);
+ end;
+
+ procedure SetPmtToleranceOptionsOnCashFlowForecast(var CashFlowForecast: Record "Cash Flow Forecast"; ConsiderPmtDiscTolDate: Boolean; ConsiderPmtTolAmount: Boolean)
+ begin
+ CashFlowForecast.Validate("Consider Pmt. Disc. Tol. Date", ConsiderPmtDiscTolDate);
+ CashFlowForecast.Validate("Consider Pmt. Tol. Amount", ConsiderPmtTolAmount);
+ CashFlowForecast.Modify(true);
+ end;
+
+ procedure SetupPmtDsctGracePeriod(NewDscGracePeriodFormula: DateFormula)
+ var
+ GeneralLedgerSetup: Record "General Ledger Setup";
+ begin
+ GeneralLedgerSetup.Get();
+ GeneralLedgerSetup.Validate("Payment Discount Grace Period", NewDscGracePeriodFormula);
+ GeneralLedgerSetup.Modify(true);
+ end;
+
+ procedure SetupPmtTolPercentage(NewPmtTolPercentage: Decimal)
+ var
+ GeneralLedgerSetup: Record "General Ledger Setup";
+ begin
+ GeneralLedgerSetup.Get();
+ GeneralLedgerSetup.Validate("Payment Tolerance %", NewPmtTolPercentage);
+ GeneralLedgerSetup.Modify(true);
+ end;
+
+ procedure SetupPmtTolAmount(NewPmtTolAmount: Decimal)
+ var
+ GeneralLedgerSetup: Record "General Ledger Setup";
+ begin
+ GeneralLedgerSetup.Get();
+ GeneralLedgerSetup.Validate("Max. Payment Tolerance Amount", NewPmtTolAmount);
+ GeneralLedgerSetup.Modify(true);
+ end;
+
+ procedure SetupCustomerPmtTolAmtTestCase(var CashFlowForecast: Record "Cash Flow Forecast"; var Customer: Record Customer; var Amount: Decimal; PmtTolAmtPercentMultiplier: Decimal; PmtTolPercentage: Decimal)
+ begin
+ LibrarySales.CreateCustomer(Customer);
+ SetupPmtTolAmtTestCase(CashFlowForecast, Amount, PmtTolAmtPercentMultiplier, PmtTolPercentage);
+ end;
+
+ procedure SetupVendorPmtTolAmtTestCase(var CashFlowForecast: Record "Cash Flow Forecast"; var Vendor: Record Vendor; var Amount: Decimal; PmtTolAmtPercentMultiplier: Decimal; PmtTolPercentage: Decimal)
+ begin
+ LibraryPurchase.CreateVendor(Vendor);
+ SetupPmtTolAmtTestCase(CashFlowForecast, Amount, PmtTolAmtPercentMultiplier, PmtTolPercentage);
+ end;
+
+ local procedure SetupPmtTolAmtTestCase(var CashFlowForecast: Record "Cash Flow Forecast"; var Amount: Decimal; PmtTolAmtPercentMultiplier: Decimal; PmtTolPercentage: Decimal)
+ begin
+ CreateCashFlowForecastDefault(CashFlowForecast);
+ SetPmtToleranceOptionsOnCashFlowForecast(CashFlowForecast, false, true);
+ Amount := LibraryRandom.RandInt(2000);
+ SetupPmtTolPercentage(PmtTolPercentage);
+ SetupPmtTolAmount(Round(Amount * PmtTolAmtPercentMultiplier));
+ end;
+
+ procedure SetupPmtDsctTolCustLETest(var CashFlowForecast: Record "Cash Flow Forecast"; var Customer: Record Customer; var PaymentTerms: Record "Payment Terms"; NewPmtDiscountGracePeriod: DateFormula; var Amount: Decimal; var DiscountedAmount: Decimal)
+ begin
+ CreateCashFlowForecastConsiderDiscountAndCFPmtTerms(CashFlowForecast);
+ SetPmtToleranceOptionsOnCashFlowForecast(CashFlowForecast, true, false);
+ SetupPmtDsctGracePeriod(NewPmtDiscountGracePeriod);
+ CreateCustWithCFDsctPmtTerm(Customer, PaymentTerms);
+ Amount := LibraryRandom.RandDec(2000, 2);
+ DiscountedAmount := Amount - CalculateDiscountAmount(Amount, PaymentTerms."Discount %");
+ end;
+
+ procedure SetupPmtDsctTolVendorLETest(var CashFlowForecast: Record "Cash Flow Forecast"; var Vendor: Record Vendor; var PaymentTerms: Record "Payment Terms"; NewPmtDiscountGracePeriod: DateFormula; var Amount: Decimal; var DiscountedAmount: Decimal)
+ begin
+ CreateCashFlowForecastConsiderDiscountAndCFPmtTerms(CashFlowForecast);
+ SetPmtToleranceOptionsOnCashFlowForecast(CashFlowForecast, true, false);
+ SetupPmtDsctGracePeriod(NewPmtDiscountGracePeriod);
+ CreateVendorWithCFDsctPmtTerm(Vendor, PaymentTerms);
+ Amount := LibraryRandom.RandDec(2000, 2);
+ DiscountedAmount := Amount - CalculateDiscountAmount(Amount, PaymentTerms."Discount %");
+ end;
+
+ procedure SetupDsctPmtTermsCustLETest(var CashFlowForecast: Record "Cash Flow Forecast"; var Customer: Record Customer; var PaymentTerms: Record "Payment Terms"; var Amount: Decimal; var DiscountedAmount: Decimal)
+ begin
+ CreateCashFlowForecastConsiderDiscountAndCFPmtTerms(CashFlowForecast);
+ CreateCustWithCFDsctPmtTerm(Customer, PaymentTerms);
+ Amount := LibraryRandom.RandDec(2000, 2);
+ DiscountedAmount := Amount - CalculateDiscountAmount(Amount, PaymentTerms."Discount %");
+ end;
+
+ procedure VerifyCFDateOnCFJnlLine(CFWorksheetLine: Record "Cash Flow Worksheet Line"; ExpectedCFDate: Date)
+ begin
+ Assert.AreEqual(ExpectedCFDate, CFWorksheetLine."Cash Flow Date", StrSubstNo(UnexpectedCFDate, CFWorksheetLine."Document No."));
+ end;
+
+ procedure VerifyExpectedCFAmount(ExpectedAmount: Decimal; ActualAmount: Decimal)
+ begin
+ Assert.AreEqual(ExpectedAmount, ActualAmount, UnexpectedCFAmount);
+ end;
+
+ procedure VerifyExpectedCFAmtNearlyEqual(ExpectedAmount: Decimal; ActualAmount: Decimal; Delta: Decimal)
+ begin
+ Assert.AreNearlyEqual(ExpectedAmount, ActualAmount, Delta, UnexpectedCFAmount);
+ end;
+
+ procedure VerifyCFDataOnSnglJnlLine(var CFWorksheetLine: Record "Cash Flow Worksheet Line"; DocumentNo: Code[20]; SourceType: Enum "Cash Flow Source Type"; CFNo: Code[20]; ExpectedCFAmount: Decimal; ExpectedCFDate: Date)
+ begin
+ VerifyCFDataOnSnglJnlLineWithDates(
+ CFWorksheetLine, DocumentNo, SourceType, CFNo, ExpectedCFDate, ExpectedCFAmount, ExpectedCFDate);
+ end;
+
+ procedure VerifyCFDataOnSnglJnlLineWithDates(var CFWorksheetLine: Record "Cash Flow Worksheet Line"; DocumentNo: Code[20]; SourceType: Enum "Cash Flow Source Type"; CFNo: Code[20]; DocumentDate: Date; ExpectedCFAmount: Decimal; ExpectedCFDate: Date)
+ begin
+ FilterSingleJournalLine(CFWorksheetLine, DocumentNo, SourceType, CFNo);
+ if SourceType = CFWorksheetLine."Source Type"::Job then begin
+ CFWorksheetLine.SetRange("Document No.");
+ CFWorksheetLine.SetRange("Source No.", DocumentNo);
+ CFWorksheetLine.SetRange("Document Date", DocumentDate);
+ if CFWorksheetLine.FindFirst() then;
+ end;
+ CFWorksheetLine.CalcSums("Amount (LCY)");
+ VerifyExpectedCFAmtNearlyEqual(ExpectedCFAmount, CFWorksheetLine."Amount (LCY)", LibraryERM.GetAmountRoundingPrecision());
+ VerifyCFDateOnCFJnlLine(CFWorksheetLine, ExpectedCFDate);
+ end;
+
+ procedure UpdateDueDateOnCustomerLedgerEntry(var CustLedgerEntry: Record "Cust. Ledger Entry")
+ begin
+ CustLedgerEntry.Validate("Due Date", GetAnyDateAfter(CustLedgerEntry."Due Date"));
+ CustLedgerEntry.Modify(true);
+ end;
+
+ procedure UpdatePmtDiscountDateOnCustomerLedgerEntry(var CustLedgerEntry: Record "Cust. Ledger Entry")
+ begin
+ CustLedgerEntry.Validate("Pmt. Discount Date", GetAnyDateAfter(CustLedgerEntry."Pmt. Discount Date"));
+ CustLedgerEntry.Modify(true);
+ end;
+
+ procedure UpdateDueDateOnVendorLedgerEntry(var VendorLedgerEntry: Record "Vendor Ledger Entry")
+ begin
+ VendorLedgerEntry.Validate("Due Date", GetAnyDateAfter(VendorLedgerEntry."Due Date"));
+ VendorLedgerEntry.Modify(true);
+ end;
+
+ procedure UpdatePmtDiscountDateOnVendorLedgerEntry(var VendorLedgerEntry: Record "Vendor Ledger Entry")
+ begin
+ VendorLedgerEntry.Validate("Pmt. Discount Date", GetAnyDateAfter(VendorLedgerEntry."Pmt. Discount Date"));
+ VendorLedgerEntry.Modify(true);
+ end;
+
+ local procedure GetAnyDateAfter(ReferenceDate: Date): Date
+ var
+ DateDelta: DateFormula;
+ begin
+ Evaluate(DateDelta, '<' + Format(LibraryRandom.RandInt(10)) + 'D>');
+ exit(CalcDate(DateDelta, ReferenceDate));
+ end;
+
+ [IntegrationEvent(false, false)]
+ local procedure OnBeforeCreatePurchaseLine(PurchaseHeader: Record "Purchase Header"; GLAccount: Record "G/L Account"; var Handled: Boolean)
+ begin
+ end;
+
+ [IntegrationEvent(false, false)]
+ local procedure OnAfterCreatePurchaseLine(PurchaseHeader: Record "Purchase Header"; GLAccount: Record "G/L Account")
+ begin
+ end;
+}
+
diff --git a/Apps/W1/ApplicationTestLibrary/LibraryCostAccounting.Codeunit.al b/Apps/W1/ApplicationTestLibrary/LibraryCostAccounting.Codeunit.al
new file mode 100644
index 0000000000..50920b4f41
--- /dev/null
+++ b/Apps/W1/ApplicationTestLibrary/LibraryCostAccounting.Codeunit.al
@@ -0,0 +1,982 @@
+///
+/// Provides utility functions for creating and managing cost accounting entities in test scenarios, including cost centers, cost objects, and cost types.
+///
+codeunit 131340 "Library - Cost Accounting"
+{
+
+ trigger OnRun()
+ begin
+ end;
+
+ var
+ Assert: Codeunit Assert;
+ LibraryUtility: Codeunit "Library - Utility";
+ LibraryERM: Codeunit "Library - ERM";
+ LibraryDimension: Codeunit "Library - Dimension";
+ LibraryRandom: Codeunit "Library - Random";
+ AllocSourceID: Label 'AS%1';
+ AllocValuesNotMatchingErr: Label 'Amount = %1, CostEntryAmount = %2, Percent = %3, TotalAmount = %4, AllocatedCost = %5, Percent * TotalAmount = %6.';
+ GetCostTypesFromGLErr: Label 'Mapping G/L Accounts to Chart of Cost Types Causes Inconsistency.';
+ GLAccountFilterDefinition: Label '%1..%2', Locked = true;
+ IncorrectGLAccountNo: Label 'The G/L Account No. %1 is aligned to Cost Type No. %2 although G/L Account No. %3 was expected.';
+ IncorrectPercentValueErr: Label 'For the Allocation Source %1, the Allocation Target %2 has its Percent field set to %3, although the expected value was %4, when values are rounded to 0.1 precision.';
+ NoRecordsInFilterErr: Label 'There are no records within the filters specified for table %1. The filters are: %2.';
+ NumberOfRecordsNotMatchingErr: Label 'The number of records %1 of %2 do not match the the number of recods %3 of %4.';
+ CostEntriesCountErr: Label 'Incorrect number of cost entries.';
+ ExpectedValueIsDifferentErr: Label 'Expected value of %1 field is different than the actual one.';
+
+ procedure AllocateCostsFromTo(var CostAllocation: TestRequestPage "Cost Allocation"; FromLevel: Integer; ToLevel: Integer; AllocDate: Date; AllocGroup: Code[10]; CostBudgetName: Code[10])
+ begin
+ CostAllocation."From Alloc. Level".SetValue(FromLevel);
+ CostAllocation."To Alloc. Level".SetValue(ToLevel);
+ CostAllocation."Allocation Date".SetValue(AllocDate);
+ CostAllocation.Group.SetValue(AllocGroup);
+ CostAllocation."Budget Name".SetValue(CostBudgetName);
+ end;
+
+ procedure CheckAllocTargetSharePercent(CostAllocationSource: Record "Cost Allocation Source")
+ var
+ CostAllocationTarget: Record "Cost Allocation Target";
+ CurrentValue: Decimal;
+ ExpectedValue: Decimal;
+ begin
+ CostAllocationSource.CalcFields("Total Share");
+ CostAllocationTarget.SetFilter(ID, '%1', CostAllocationSource.ID);
+ if CostAllocationTarget.FindSet() then
+ repeat
+ CurrentValue := Round(CostAllocationTarget.Percent, 0.1, '=');
+ ExpectedValue := Round(100 * CostAllocationTarget.Share / CostAllocationSource."Total Share", 0.1, '=');
+ Assert.AreEqual(
+ CurrentValue, ExpectedValue,
+ StrSubstNo(IncorrectPercentValueErr, CostAllocationSource.ID, CostAllocationTarget."Line No.", CurrentValue, ExpectedValue));
+ until CostAllocationTarget.Next() = 0
+ else
+ Error(NoRecordsInFilterErr, CostAllocationTarget.TableCaption(), CostAllocationTarget.GetFilters);
+ end;
+
+ procedure CheckBlockedDimCombination()
+ var
+ DimensionCombination: Record "Dimension Combination";
+ begin
+ DimensionCombination.SetFilter("Dimension 1 Code", '%1|%2', CostCenterDimension(), CostObjectDimension());
+ DeleteBlockedDimCombinations(DimensionCombination);
+
+ Clear(DimensionCombination);
+ DimensionCombination.SetFilter("Dimension 2 Code", '%1|%2', CostCenterDimension(), CostObjectDimension());
+ DeleteBlockedDimCombinations(DimensionCombination);
+ end;
+
+ procedure CheckBlockedDimensionValues(AccountNo: Code[20])
+ var
+ DimensionValue: Record "Dimension Value";
+ DefaultDimension: Record "Default Dimension";
+ begin
+ // Un-block any blocked default dimension values for an account
+
+ LibraryDimension.FindDefaultDimension(DefaultDimension, DATABASE::"G/L Account", AccountNo);
+ if DefaultDimension.FindSet() then
+ repeat
+ DimensionValue.Get(DefaultDimension."Dimension Code", DefaultDimension."Dimension Value Code");
+ if DimensionValue.Blocked then begin
+ DimensionValue.Validate(Blocked, false);
+ DimensionValue.Modify(true);
+ end;
+ until DefaultDimension.Next() = 0;
+ end;
+
+ procedure CheckCostJnlLineConsistency(var CostJournalLine: Record "Cost Journal Line")
+ var
+ CostCenter: Record "Cost Center";
+ begin
+ if (CostJournalLine."Cost Center Code" = '') and (CostJournalLine."Cost Object Code" = '') then begin
+ // either Cost Center or Cost Object must be set in order to post
+ CreateCostCenter(CostCenter);
+ CostJournalLine.Validate("Cost Center Code", CostCenter.Code);
+ end;
+
+ if (CostJournalLine."Bal. Cost Center Code" = '') and (CostJournalLine."Bal. Cost Object Code" = '') then begin
+ // either Bal. Cost Center or Bal. Cost Object must be set in order to post
+ CreateCostCenter(CostCenter);
+ CostJournalLine.Validate("Bal. Cost Center Code", CostCenter.Code);
+ end;
+
+ if (CostJournalLine."Cost Center Code" <> '') and (CostJournalLine."Cost Object Code" <> '') then
+ // only one of Cost Center or Cost Object must be set in order to post
+ CostJournalLine.Validate("Cost Object Code", '');
+
+ if (CostJournalLine."Bal. Cost Center Code" <> '') and (CostJournalLine."Bal. Cost Object Code" <> '') then
+ // only one of Bal. Cost Center or Bal. Cost Object fields must be set in order to post
+ CostJournalLine.Validate("Bal. Cost Object Code", '');
+
+ CostJournalLine.Modify(true);
+ end;
+
+ procedure ClearCostJournalLines(CostJournalBatch: Record "Cost Journal Batch")
+ var
+ CostJournalLine: Record "Cost Journal Line";
+ begin
+ CostJournalLine.SetRange("Journal Template Name", CostJournalBatch."Journal Template Name");
+ CostJournalLine.SetRange("Journal Batch Name", CostJournalBatch.Name);
+ CostJournalLine.DeleteAll(true);
+ end;
+
+ procedure CopyCABudgetToCABudget(var CopyCAToCARP: TestRequestPage "Copy Cost Budget"; SourceCostBudget: Code[10]; TargetCostBudget: Code[10]; AmtMultiplicationRatio: Decimal; DateFormula: Text[30]; NoOfCopies: Integer)
+ begin
+ CopyCAToCARP."Budget Name".SetValue(TargetCostBudget);
+ CopyCAToCARP."Amount multiplication factor".SetValue(AmtMultiplicationRatio);
+ CopyCAToCARP."Date Change Formula".SetValue(DateFormula);
+ CopyCAToCARP."No. of Copies".SetValue(NoOfCopies);
+ CopyCAToCARP."Cost Budget Entry".SetFilter("Budget Name", SourceCostBudget);
+ end;
+
+ procedure CopyCABudgetToGLBudget(var CopyCAToGLRP: TestRequestPage "Copy Cost Acctg. Budget to G/L"; SourceCostBudget: Code[10]; TargetCostBudget: Code[10]; AmtMultiplicationRatio: Decimal; DateFormula: Text[30]; NoOfCopies: Integer)
+ begin
+ CopyCAToGLRP."Allocation Target Budget Name".SetValue(TargetCostBudget);
+ CopyCAToGLRP."Amount multiplication factor".SetValue(AmtMultiplicationRatio);
+ CopyCAToGLRP."Date Change Formula".SetValue(DateFormula);
+ CopyCAToGLRP."No. of Copies".SetValue(NoOfCopies);
+ CopyCAToGLRP."Cost Budget Entry".SetFilter("Budget Name", SourceCostBudget);
+ end;
+
+ procedure CopyGLBudgetToCABudget(var CopyGLToCARP: TestRequestPage "Copy G/L Budget to Cost Acctg."; SourceGLBudget: Code[10]; TargetCostBudget: Code[10])
+ begin
+ CopyGLToCARP."Budget Name".SetValue(TargetCostBudget);
+ CopyGLToCARP."G/L Budget Entry".SetFilter("Budget Name", SourceGLBudget);
+ end;
+
+ procedure CostCenterDimension(): Code[20]
+ var
+ CostAccountingSetup: Record "Cost Accounting Setup";
+ begin
+ CostAccountingSetup.Get();
+ exit(CostAccountingSetup."Cost Center Dimension");
+ end;
+
+ procedure CostObjectDimension(): Code[20]
+ var
+ CostAccountingSetup: Record "Cost Accounting Setup";
+ begin
+ CostAccountingSetup.Get();
+ exit(CostAccountingSetup."Cost Object Dimension");
+ end;
+
+ procedure CreateAllocSource(var CostAllocationSource: Record "Cost Allocation Source"; TypeOfID: Option "Auto Generated",Custom)
+ var
+ CostType: Record "Cost Type";
+ begin
+ FindCostType(CostType);
+
+ CostAllocationSource.Init();
+ if TypeOfID = TypeOfID::Custom then
+ CostAllocationSource.Validate(ID, (LastAllocSourceID() + StrSubstNo(AllocSourceID, CostAllocationSource.Count)));
+ CostAllocationSource.Validate(Level, LibraryRandom.RandInt(10));
+ CostAllocationSource.Validate("Credit to Cost Type", CostType."No.");
+ CostAllocationSource.Insert(true);
+ end;
+
+ procedure CreateAllocSourceWithCCenter(var CostAllocationSource: Record "Cost Allocation Source"; TypeOfID: Option)
+ begin
+ CreateAllocSource(CostAllocationSource, TypeOfID);
+ UpdateAllocSourceWithCCenter(CostAllocationSource);
+ end;
+
+ procedure CreateAllocSourceWithCObject(var CostAllocationSource: Record "Cost Allocation Source"; TypeOfID: Option)
+ begin
+ CreateAllocSource(CostAllocationSource, TypeOfID);
+ UpdateAllocSourceWithCObject(CostAllocationSource);
+ end;
+
+ procedure CreateAllocTarget(var CostAllocationTarget: Record "Cost Allocation Target"; CostAllocationSource: Record "Cost Allocation Source"; Share: Decimal; Base: Enum "Cost Allocation Target Base"; AllocationType: Enum "Cost Allocation Target Type")
+ var
+ LineNo: Integer;
+ begin
+ LineNo := LastAllocTargetID(CostAllocationSource) + 1;
+
+ CostAllocationTarget.Init();
+ CostAllocationTarget.Validate(ID, CostAllocationSource.ID);
+ CostAllocationTarget.Validate("Line No.", LineNo);
+ CostAllocationTarget.Validate("Target Cost Type", CostAllocationSource."Credit to Cost Type");
+ CostAllocationTarget.Validate(Base, Base);
+ CostAllocationTarget.Validate("Allocation Target Type", AllocationType);
+ CostAllocationTarget.Insert(true);
+
+ // The Share field cannot be updated unless the Allocation Target exists.
+ Clear(CostAllocationTarget);
+ CostAllocationTarget.Get(CostAllocationSource.ID, LineNo);
+ CostAllocationTarget.Validate(Share, Share);
+ CostAllocationTarget.Modify(true);
+ end;
+
+ procedure CreateAllocTargetWithCCenter(var CostAllocationTarget: Record "Cost Allocation Target"; CostAllocationSource: Record "Cost Allocation Source"; Share: Decimal; Base: Enum "Cost Allocation Target Base"; AllocationType: Enum "Cost Allocation Target Type")
+ begin
+ CreateAllocTarget(CostAllocationTarget, CostAllocationSource, Share, Base, AllocationType);
+ UpdateAllocTargetWithCCenter(CostAllocationTarget);
+ end;
+
+ procedure CreateAllocTargetWithCObject(var CostAllocationTarget: Record "Cost Allocation Target"; CostAllocationSource: Record "Cost Allocation Source"; Share: Decimal; Base: Enum "Cost Allocation Target Base"; AllocationType: Enum "Cost Allocation Target Type")
+ begin
+ CreateAllocTarget(CostAllocationTarget, CostAllocationSource, Share, Base, AllocationType);
+ UpdateAllocTargetWithCObject(CostAllocationTarget);
+ end;
+
+ procedure CreateBalanceSheetGLAccount(var GLAccount: Record "G/L Account")
+ var
+ CostAccountingSetup: Record "Cost Accounting Setup";
+ AlignGLAccount: Option;
+ begin
+ CostAccountingSetup.Get();
+ AlignGLAccount := CostAccountingSetup."Align G/L Account";
+ CostAccountingSetup.Validate("Align G/L Account", CostAccountingSetup."Align G/L Account"::"No Alignment");
+ CostAccountingSetup.Modify(true);
+
+ LibraryERM.CreateGLAccount(GLAccount);
+ GLAccount.TestField("Cost Type No.", '');
+ GLAccount.Validate("Income/Balance", GLAccount."Income/Balance"::"Balance Sheet");
+ GLAccount.Modify(true);
+
+ CostAccountingSetup.Get();
+ CostAccountingSetup.Validate("Align G/L Account", AlignGLAccount);
+ CostAccountingSetup.Modify(true);
+ end;
+
+ procedure CreateCostBudgetEntry(var CostBudgetEntry: Record "Cost Budget Entry"; CostBudgetName: Code[10])
+ var
+ CostType: Record "Cost Type";
+ CostCenter: Record "Cost Center";
+ begin
+ FindCostType(CostType);
+ FindCostCenter(CostCenter);
+
+ CostBudgetEntry.Init();
+ CostBudgetEntry.Validate(Date, WorkDate());
+ CostBudgetEntry.Validate("Budget Name", CostBudgetName);
+ CostBudgetEntry.Validate("Cost Type No.", CostType."No.");
+ CostBudgetEntry.Validate("Cost Center Code", CostCenter.Code);
+ CostBudgetEntry.Validate(Amount, LibraryRandom.RandDec(100, 2));
+ CostBudgetEntry.Insert(true);
+ end;
+
+ procedure CreateCostBudgetName(var CostBudgetName: Record "Cost Budget Name")
+ begin
+ CostBudgetName.Init();
+ CostBudgetName.Validate(
+ Name, LibraryUtility.GenerateRandomCode(CostBudgetName.FieldNo(Description), DATABASE::"Cost Budget Name"));
+ CostBudgetName.Validate(Description, CostBudgetName.Name);
+ CostBudgetName.Insert(true);
+ end;
+
+ procedure CreateCostCenter(var CostCenter: Record "Cost Center")
+ begin
+ CostCenter.Init();
+ CostCenter.Validate(Code, LibraryUtility.GenerateRandomCode(CostCenter.FieldNo(Code), DATABASE::"Cost Center"));
+ CostCenter.Validate("Line Type", CostCenter."Line Type"::"Cost Center");
+ CostCenter.Insert(true);
+ end;
+
+ procedure CreateCostCenterFromDimension(var CostCenter: Record "Cost Center")
+ var
+ CostAccountingSetup: Record "Cost Accounting Setup";
+ DimensionValue: Record "Dimension Value";
+ begin
+ CostAccountingSetup.Get();
+ SetAlignment(
+ CostAccountingSetup.FieldNo("Align Cost Center Dimension"), CostAccountingSetup."Align Cost Center Dimension"::Automatic);
+ LibraryDimension.CreateDimensionValue(DimensionValue, CostAccountingSetup."Cost Center Dimension");
+ CostCenter.Get(DimensionValue.Code);
+ end;
+
+ procedure CreateCostJournalBatch(var CostJournalBatch: Record "Cost Journal Batch"; CostJournalTemplateName: Code[10])
+ begin
+ CreateCostJnlBatchWithDelOpt(CostJournalBatch, CostJournalTemplateName, true);
+ end;
+
+ procedure CreateCostJournalTemplate(var CostJournalTemplate: Record "Cost Journal Template")
+ begin
+ CostJournalTemplate.Init();
+ CostJournalTemplate.Validate(
+ Name, LibraryUtility.GenerateRandomCode(CostJournalTemplate.FieldNo(Name), DATABASE::"Cost Journal Template"));
+ CostJournalTemplate.Insert(true);
+ end;
+
+ procedure CreateCostJnlBatchWithDelOpt(var CostJournalBatch: Record "Cost Journal Batch"; CostJournalTemplateName: Code[10]; DeleteAfterPosting: Boolean)
+ begin
+ CostJournalBatch.Init();
+ CostJournalBatch.Validate("Journal Template Name", CostJournalTemplateName);
+ CostJournalBatch.Validate("Delete after Posting", DeleteAfterPosting);
+ CostJournalBatch.Validate(Name, LibraryUtility.GenerateRandomCode(CostJournalBatch.FieldNo(Name), DATABASE::"Cost Journal Batch"));
+ CostJournalBatch.Validate(Description, CostJournalBatch.Name); // Validating Name as Description because value is not important.
+ if CostJournalBatch.Insert(true) then;
+ end;
+
+ procedure CreateCostJournalLine(var CostJournalLine: Record "Cost Journal Line"; CostJournalTemplateName: Code[10]; CostJournalBatchName: Code[10])
+ var
+ CostType: Record "Cost Type";
+ BalCostType: Record "Cost Type";
+ begin
+ FindCostType(CostType);
+ FindCostType(BalCostType);
+
+ CreateCostJournalLineBasic(
+ CostJournalLine, CostJournalTemplateName, CostJournalBatchName, WorkDate(), CostType."No.", BalCostType."No.");
+
+ CheckCostJnlLineConsistency(CostJournalLine);
+ end;
+
+ procedure CreateCostJournalLineBasic(var CostJournalLine: Record "Cost Journal Line"; CostJournalTemplateName: Code[10]; CostJournalBatchName: Code[10]; PostingDate: Date; CostTypeNo: Code[20]; BalCostTypeNo: Code[20])
+ var
+ RecRef: RecordRef;
+ begin
+ CostJournalLine.Init();
+ CostJournalLine.Validate("Journal Template Name", CostJournalTemplateName);
+ CostJournalLine.Validate("Journal Batch Name", CostJournalBatchName);
+ RecRef.GetTable(CostJournalLine);
+ CostJournalLine.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, CostJournalLine.FieldNo("Line No.")));
+ CostJournalLine.Insert(true);
+
+ CostJournalLine.Validate("Posting Date", PostingDate);
+ CostJournalLine.Validate("Document No.", CostTypeNo);
+ CostJournalLine.Validate("Cost Type No.", CostTypeNo);
+ CostJournalLine.Validate("Bal. Cost Type No.", BalCostTypeNo);
+ CostJournalLine.Validate(Amount, LibraryRandom.RandInt(1000));
+ CostJournalLine.Modify(true);
+ end;
+
+ procedure CreateCostObject(var CostObject: Record "Cost Object")
+ begin
+ CostObject.Init();
+ CostObject.Validate(Code, LibraryUtility.GenerateRandomCode(CostObject.FieldNo(Code), DATABASE::"Cost Object"));
+ CostObject.Validate("Line Type", CostObject."Line Type"::"Cost Object");
+ CostObject.Insert(true);
+ end;
+
+ procedure CreateCostObjectFromDimension(var CostObject: Record "Cost Object")
+ var
+ CostAccountingSetup: Record "Cost Accounting Setup";
+ DimensionValue: Record "Dimension Value";
+ begin
+ CostAccountingSetup.Get();
+ SetAlignment(
+ CostAccountingSetup.FieldNo("Align Cost Object Dimension"), CostAccountingSetup."Align Cost Object Dimension"::Automatic);
+ LibraryDimension.CreateDimensionValue(DimensionValue, CostAccountingSetup."Cost Object Dimension");
+ CostObject.Get(DimensionValue.Code);
+ end;
+
+ [Normal]
+ procedure CreateCostType(var CostType: Record "Cost Type")
+ begin
+ CreateCostTypeWithGLRange(CostType, false);
+ end;
+
+ procedure CreateCostTypeNoGLRange(var CostType: Record "Cost Type")
+ begin
+ CostType.Init();
+ CostType.Validate("No.", LibraryUtility.GenerateRandomCode(CostType.FieldNo("No."), DATABASE::"Cost Type"));
+ CostType.Validate(Type, CostType.Type::"Cost Type");
+ CostType.Validate("Combine Entries", CostType."Combine Entries"::None);
+ CostType.Insert(true);
+ end;
+
+ procedure CreateCostTypeWithCombine(var CostType: Record "Cost Type"; CombineEntries: Option)
+ begin
+ CreateCostTypeWithGLRange(CostType, true);
+ CostType.Validate("Combine Entries", CombineEntries);
+ CostType.Modify(true);
+ end;
+
+ procedure CreateCostTypeWithGLRange(var CostType: Record "Cost Type"; MultipleGLAccounts: Boolean)
+ var
+ CostAccountingSetup: Record "Cost Accounting Setup";
+ GLAccount: Record "G/L Account";
+ GLAccountFilter: Text[50];
+ Index: Integer;
+ begin
+ SetAlignment(CostAccountingSetup.FieldNo("Align G/L Account"), CostAccountingSetup."Align G/L Account"::Automatic);
+ CreateIncomeStmtGLAccount(GLAccount);
+ CostType.Get(GLAccount."Cost Type No.");
+ CostType.TestField("G/L Account Range", GLAccount."No.");
+ GLAccount.TestField("Cost Type No.", CostType."No.");
+
+ if MultipleGLAccounts then begin
+ SetAlignment(CostAccountingSetup.FieldNo("Align G/L Account"), CostAccountingSetup."Align G/L Account"::"No Alignment");
+
+ for Index := 1 to LibraryRandom.RandInt(5) do begin
+ Clear(GLAccount);
+ CreateIncomeStmtGLAccount(GLAccount);
+ end;
+
+ GLAccountFilter := StrSubstNo(GLAccountFilterDefinition, CostType."G/L Account Range", GLAccount."No.");
+ Assert.AreEqual(MaxStrLen(CostType."G/L Account Range"), MaxStrLen(GLAccountFilter), 'Passing filter must fit field length');
+ CostType.Validate("G/L Account Range", GLAccountFilter);
+ CostType.Modify(true);
+ end;
+ end;
+
+ procedure CreateIncomeStmtGLAccount(var GLAccount: Record "G/L Account")
+ var
+ CostType: Record "Cost Type";
+ begin
+ LibraryERM.CreateGLAccount(GLAccount);
+ GLAccount.Validate("Income/Balance", GLAccount."Income/Balance"::"Income Statement");
+ GLAccount.Modify(true);
+
+ if CostType.Get(GLAccount."Cost Type No.") then
+ if CostType."G/L Account Range" <> GLAccount."No." then
+ if CostType."G/L Account Range" = '' then begin
+ CostType.Validate("G/L Account Range", GLAccount."No.");
+ CostType.Modify(true);
+ end else
+ Error(IncorrectGLAccountNo, CostType."G/L Account Range", CostType."No.", GLAccount."No.");
+ end;
+
+ procedure CreateJnlLine(var GenJournalLine: Record "Gen. Journal Line"; AccountNo: Code[20])
+ var
+ GenJournalBatch: Record "Gen. Journal Batch";
+ begin
+ SetupGeneralJnlBatch(GenJournalBatch);
+
+ // Create General Journal Line.
+ LibraryERM.CreateGeneralJnlLine(
+ GenJournalLine, GenJournalBatch."Journal Template Name", GenJournalBatch.Name, GenJournalLine."Document Type"::Payment,
+ GenJournalLine."Account Type"::"G/L Account", AccountNo, LibraryRandom.RandDec(1000, 2));
+
+ // Update journal line to avoid Posting errors
+ GenJournalLine.Validate("Gen. Posting Type", GenJournalLine."Gen. Posting Type"::" ");
+ GenJournalLine.Validate("Gen. Bus. Posting Group", '');
+ GenJournalLine.Validate("Gen. Prod. Posting Group", '');
+ GenJournalLine.Modify(true);
+ end;
+
+ procedure DeleteAllCostTypeEntries()
+ var
+ CostType: Record "Cost Type";
+ begin
+ if CostType.IsEmpty() then
+ exit;
+
+ CostType.DeleteAll(true);
+ end;
+
+ procedure DeleteCostBudgetRegEntries()
+ var
+ CostBudgetRegister: Record "Cost Budget Register";
+ begin
+ if CostBudgetRegister.FindFirst() then
+ DeleteCostBudgetRegEntriesFrom(CostBudgetRegister."No.");
+ end;
+
+ procedure DeleteCostBudgetRegEntriesFrom(StartEntry: Integer)
+ var
+ CostBudgetRegister: Record "Cost Budget Register";
+ DeleteCostBudgetEntries: Report "Delete Cost Budget Entries";
+ begin
+ if CostBudgetRegister.FindLast() then begin
+ DeleteCostBudgetEntries.InitializeRequest(StartEntry, CostBudgetRegister."No.");
+ DeleteCostBudgetEntries.UseRequestPage := false;
+ DeleteCostBudgetEntries.RunModal();
+ end;
+ end;
+
+ procedure DeleteCostRegisterEntries()
+ var
+ CostRegister: Record "Cost Register";
+ begin
+ if CostRegister.FindFirst() then
+ DeleteCostRegisterEntriesFrom(CostRegister."No.");
+ end;
+
+ procedure DeleteCostRegisterEntriesFrom(StartEntry: Integer)
+ var
+ CostRegister: Record "Cost Register";
+ DeleteCostEntries: Report "Delete Cost Entries";
+ begin
+ if CostRegister.FindLast() then begin
+ DeleteCostEntries.InitializeRequest(StartEntry, CostRegister."No.");
+ DeleteCostEntries.UseRequestPage := false;
+ DeleteCostEntries.RunModal();
+ end;
+ end;
+
+ procedure DeleteBlockedDimCombinations(var DimensionCombination: Record "Dimension Combination")
+ begin
+ if DimensionCombination.FindSet() then
+ repeat
+ if DimensionCombination."Combination Restriction" = DimensionCombination."Combination Restriction"::Blocked then
+ DimensionCombination.Delete(true);
+ until DimensionCombination.Next() = 0;
+ end;
+
+ procedure FindAllocSource(var CostAllocationSource: Record "Cost Allocation Source")
+ begin
+ CostAllocationSource.SetFilter("Credit to Cost Type", '<>%1', '');
+ CostAllocationSource.SetFilter("Cost Center Code", '<>%1', '');
+
+ if CostAllocationSource.IsEmpty() then begin
+ CostAllocationSource.SetRange("Cost Center Code");
+ CostAllocationSource.SetFilter("Cost Object Code", '<>%1', '');
+ end;
+
+ if CostAllocationSource.IsEmpty() then
+ Error(NoRecordsInFilterErr, CostAllocationSource.TableCaption(), CostAllocationSource.GetFilters);
+
+ CostAllocationSource.Next(LibraryRandom.RandInt(CostAllocationSource.Count));
+ end;
+
+ procedure FindCostType(var CostType: Record "Cost Type")
+ begin
+ GetAllCostTypes(CostType);
+ if CostType.IsEmpty() then
+ Error(NoRecordsInFilterErr, CostType.TableCaption(), CostType.GetFilters);
+
+ CostType.Next(LibraryRandom.RandInt(CostType.Count));
+ end;
+
+ procedure FindCostTypeLinkedToGLAcc(var CostType: Record "Cost Type")
+ var
+ GLAccount: Record "G/L Account";
+ begin
+ GLAccount.SetFilter("Cost Type No.", '<>%1', '');
+ if GLAccount.IsEmpty() then
+ Error(NoRecordsInFilterErr, GLAccount.TableCaption(), GLAccount.GetFilters);
+
+ GLAccount.FindSet();
+ GLAccount.Next(LibraryRandom.RandInt(GLAccount.Count));
+ CostType.Get(GLAccount."Cost Type No.");
+ end;
+
+ procedure FindCostTypeWithCostCenter(var CostType: Record "Cost Type")
+ begin
+ GetAllCostTypes(CostType);
+ CostType.SetFilter("Cost Center Code", '<>%1', '');
+ CostType.SetFilter("Cost Object Code", '%1', '');
+ if CostType.IsEmpty() then
+ Error(NoRecordsInFilterErr, CostType.TableCaption(), CostType.GetFilters);
+
+ CostType.Next(LibraryRandom.RandInt(CostType.Count));
+ end;
+
+ procedure FindCostCenter(var CostCenter: Record "Cost Center")
+ begin
+ CostCenter.SetFilter("Line Type", Format(CostCenter."Line Type"::"Cost Center"));
+ CostCenter.SetFilter(Blocked, '%1', false);
+ CostCenter.SetFilter("Net Change", '<>%1', 0);
+ CostCenter.SetFilter("Balance at Date", '<>%1', 0);
+ if CostCenter.IsEmpty() then
+ Error(NoRecordsInFilterErr, CostCenter.TableCaption(), CostCenter.GetFilters);
+
+ CostCenter.Next(LibraryRandom.RandInt(CostCenter.Count));
+ end;
+
+ procedure FindCostJournalBatch(var CostJournalBatch: Record "Cost Journal Batch"; CostJournalTemplateName: Code[10])
+ begin
+ FindCostJnlBatchWithDelOption(CostJournalBatch, CostJournalTemplateName, true);
+ end;
+
+ procedure FindCostJnlBatchWithDelOption(var CostJournalBatch: Record "Cost Journal Batch"; CostJournalTemplateName: Code[10]; DeleteAfterPosting: Boolean)
+ begin
+ CostJournalBatch.SetRange("Journal Template Name", CostJournalTemplateName);
+ CostJournalBatch.SetRange("Delete after Posting", DeleteAfterPosting);
+ if CostJournalBatch.IsEmpty() then
+ CreateCostJournalBatch(CostJournalBatch, CostJournalTemplateName)
+ else
+ CostJournalBatch.FindFirst();
+ end;
+
+ procedure FindCostJournalTemplate(var CostJournalTemplate: Record "Cost Journal Template")
+ begin
+ CostJournalTemplate.FindFirst();
+ end;
+
+ procedure FindCostObject(var CostObject: Record "Cost Object")
+ begin
+ CostObject.SetFilter("Line Type", Format(CostObject."Line Type"::"Cost Object"));
+ CostObject.SetFilter(Blocked, '%1', false);
+ CostObject.SetFilter("Net Change", '<>%1', 0);
+ CostObject.SetFilter("Balance at Date", '<>%1', 0);
+ if CostObject.IsEmpty() then
+ Error(NoRecordsInFilterErr, CostObject.TableCaption(), CostObject.GetFilters);
+
+ CostObject.Next(LibraryRandom.RandInt(CostObject.Count));
+ end;
+
+ procedure FindGLAccLinkedToCostType(var GLAccount: Record "G/L Account")
+ begin
+ LibraryERM.FindGLAccount(GLAccount);
+ GLAccount.SetFilter("Cost Type No.", '<>%1', '');
+ if GLAccount.IsEmpty() then
+ Error(NoRecordsInFilterErr, GLAccount.TableCaption(), GLAccount.GetFilters);
+
+ GLAccount.Next(LibraryRandom.RandInt(GLAccount.Count));
+ end;
+
+ procedure FindGLAccountsByCostType(var GLAccount: Record "G/L Account"; GLAccountRange: Text[50])
+ begin
+ GLAccount.SetFilter("No.", GLAccountRange);
+ if GLAccount.IsEmpty() then
+ Error(NoRecordsInFilterErr, GLAccount.TableCaption(), GLAccount.GetFilters);
+
+ GLAccount.FindSet();
+ end;
+
+ procedure FindIncomeStmtGLAccount(var GLAccount: Record "G/L Account")
+ begin
+ GetAllIncomeStmtGLAccounts(GLAccount);
+ GLAccount.Next(LibraryRandom.RandInt(GLAccount.Count));
+ end;
+
+ procedure GetAllCostTypes(var CostType: Record "Cost Type")
+ begin
+ CostType.Init();
+ CostType.SetFilter(Type, Format(CostType.Type::"Cost Type"));
+ CostType.SetFilter("G/L Account Range", '<>%1', '');
+ if CostType.IsEmpty() then
+ Error(NoRecordsInFilterErr, CostType.TableCaption(), CostType.GetFilters);
+ CostType.FindSet();
+ end;
+
+ procedure GetAllIncomeStmtGLAccounts(var GLAccount: Record "G/L Account")
+ begin
+ LibraryERM.FindGLAccount(GLAccount);
+ GLAccount.SetFilter("Income/Balance", Format(GLAccount."Income/Balance"::"Income Statement"));
+ if GLAccount.IsEmpty() then
+ Error(NoRecordsInFilterErr, GLAccount.TableCaption(), GLAccount.GetFilters);
+ GLAccount.FindSet();
+ end;
+
+ procedure GetAllocTargetEntryAmount(var CostAllocationTarget: Record "Cost Allocation Target"; TotalAmount: Decimal; TableNumber: Integer; KeyFieldNumber: Integer; AmountFieldNumber: Integer; FromValue: Integer; ToValue: Integer) TotalDebitValue: Decimal
+ var
+ AmountFieldRef: FieldRef;
+ KeyFieldRef: FieldRef;
+ RecordRef: RecordRef;
+ AllocatedCost: Decimal;
+ EntryAmount: Decimal;
+ FieldRefAmount: Decimal;
+ begin
+ RecordRef.Open(TableNumber);
+ KeyFieldRef := RecordRef.Field(KeyFieldNumber);
+ KeyFieldRef.SetRange(FromValue, (ToValue - 1));
+ RecordRef.FindSet();
+
+ if RecordRef.IsEmpty() then
+ Error(NoRecordsInFilterErr, RecordRef.Name, RecordRef.GetFilters);
+
+ if RecordRef.Count <> CostAllocationTarget.Count then
+ Error(
+ StrSubstNo(
+ NumberOfRecordsNotMatchingErr, RecordRef.Count, RecordRef.Name, CostAllocationTarget.Count, CostAllocationTarget.TableCaption()));
+
+ AmountFieldRef := RecordRef.Field(AmountFieldNumber);
+
+ repeat
+ // To avoid the rounding errors, approximate the decimal numbers by cutting out the fractional part.
+ FieldRefAmount := AmountFieldRef.Value();
+ EntryAmount := Round(FieldRefAmount, 1);
+ AllocatedCost := Round(TotalAmount * (CostAllocationTarget.Percent / 100), 1);
+
+ if EntryAmount <> AllocatedCost then
+ if -EntryAmount <> AllocatedCost then
+ Error(
+ StrSubstNo(
+ AllocValuesNotMatchingErr, FieldRefAmount, EntryAmount, CostAllocationTarget.Percent,
+ TotalAmount, AllocatedCost, (CostAllocationTarget.Percent * TotalAmount)));
+
+ TotalDebitValue := TotalDebitValue + FieldRefAmount;
+ CostAllocationTarget.Next();
+ until RecordRef.Next() = 0;
+
+ exit(TotalDebitValue);
+ end;
+
+ procedure InitializeCASetup()
+ var
+ CostAccountingSetup: Record "Cost Accounting Setup";
+ begin
+ CostAccountingSetup.Get();
+ CostAccountingSetup.Validate("Align G/L Account", CostAccountingSetup."Align G/L Account"::Automatic);
+ CostAccountingSetup.Validate("Align Cost Center Dimension", CostAccountingSetup."Align Cost Center Dimension"::Automatic);
+ CostAccountingSetup.Validate("Align Cost Object Dimension", CostAccountingSetup."Align Cost Object Dimension"::Automatic);
+ CostAccountingSetup.Validate("Auto Transfer from G/L", false);
+ if CostAccountingSetup."Last Allocation ID" = '' then
+ CostAccountingSetup.Validate("Last Allocation ID", 'A0');
+ if CostAccountingSetup."Last Allocation Doc. No." = '' then
+ CostAccountingSetup.Validate("Last Allocation Doc. No.", 'ALLOC0');
+ CostAccountingSetup.Modify(true);
+
+ InitializeCASourceCodes();
+ end;
+
+ procedure InitializeCASourceCodes()
+ var
+ SourceCodeSetup: Record "Source Code Setup";
+ SourceCode: Record "Source Code";
+ Modified: Boolean;
+ begin
+ SourceCodeSetup.Get();
+
+ if SourceCodeSetup."G/L Entry to CA" = '' then begin
+ LibraryERM.CreateSourceCode(SourceCode);
+ SourceCodeSetup.Validate("G/L Entry to CA", SourceCode.Code);
+ Modified := true;
+ end;
+ if SourceCodeSetup."Cost Journal" = '' then begin
+ LibraryERM.CreateSourceCode(SourceCode);
+ SourceCodeSetup.Validate("Cost Journal", SourceCode.Code);
+ Modified := true;
+ end;
+ if SourceCodeSetup."Cost Allocation" = '' then begin
+ LibraryERM.CreateSourceCode(SourceCode);
+ SourceCodeSetup.Validate("Cost Allocation", SourceCode.Code);
+ Modified := true;
+ end;
+
+ if Modified then
+ SourceCodeSetup.Modify(true);
+ end;
+
+ procedure LastAllocSourceID(): Code[10]
+ var
+ CostAccountingSetup: Record "Cost Accounting Setup";
+ begin
+ CostAccountingSetup.Get();
+ exit(CostAccountingSetup."Last Allocation ID");
+ end;
+
+ procedure LastAllocTargetID(CostAllocationSource: Record "Cost Allocation Source"): Integer
+ var
+ CostAllocationTarget: Record "Cost Allocation Target";
+ begin
+ CostAllocationTarget.SetFilter(ID, '%1', CostAllocationSource.ID);
+ if CostAllocationTarget.FindLast() then
+ exit(CostAllocationTarget."Line No.");
+
+ exit(0);
+ end;
+
+ procedure PostCostJournalLine(CostJournalLine: Record "Cost Journal Line")
+ begin
+ CODEUNIT.Run(CODEUNIT::"CA Jnl.-Post Batch", CostJournalLine);
+ end;
+
+ procedure PostGenJournalLine(AccountNo: Code[20])
+ var
+ GenJournalLine: Record "Gen. Journal Line";
+ begin
+ CreateJnlLine(GenJournalLine, AccountNo);
+ LibraryERM.PostGeneralJnlLine(GenJournalLine);
+ end;
+
+ procedure SetAlignment(FieldNo: Integer; FieldOptionValue: Option)
+ var
+ CostAccountingSetup: Record "Cost Accounting Setup";
+ "Field": Record "Field";
+ RecordRef: RecordRef;
+ FieldRef: FieldRef;
+ begin
+ CostAccountingSetup.Get();
+ RecordRef.GetTable(CostAccountingSetup);
+ FieldRef := RecordRef.Field(FieldNo);
+ Field.Get(RecordRef.Number, FieldRef.Number);
+ if Field.Type = Field.Type::Option then begin
+ FieldRef.Validate(FieldOptionValue);
+ RecordRef.Modify(true);
+ end;
+ end;
+
+ procedure SetAutotransferFromGL(Autotransfer: Boolean)
+ var
+ CostAccountingSetup: Record "Cost Accounting Setup";
+ begin
+ CostAccountingSetup.Get();
+ CostAccountingSetup.Validate("Auto Transfer from G/L", Autotransfer);
+ CostAccountingSetup.Modify(true);
+ end;
+
+ procedure SetDefaultDimension(GLAccountNo: Code[20])
+ var
+ CostCenter: Record "Cost Center";
+ DimValue: Record "Dimension Value";
+ DefaultDimension: Record "Default Dimension";
+ begin
+ if not DefaultDimension.Get(DATABASE::"G/L Account", GLAccountNo, CostCenterDimension()) then begin
+ LibraryDimension.FindDimensionValue(DimValue, CostCenterDimension());
+ LibraryDimension.CreateDefaultDimensionGLAcc(DefaultDimension, GLAccountNo, DimValue."Dimension Code", DimValue.Code);
+ end;
+
+ // Make sure corresponding cost center exists
+ if not CostCenter.Get(DefaultDimension."Dimension Value Code") then begin
+ CostCenter.Init();
+ CostCenter.Validate(Code, DefaultDimension."Dimension Value Code");
+ CostCenter.Validate("Line Type", CostCenter."Line Type"::"Cost Center");
+ CostCenter.Insert(true);
+ end;
+
+ CheckBlockedDimensionValues(GLAccountNo); // check for blocked default dimension values, which prevent posting
+ CheckBlockedDimCombination(); // check for blocked dimension combinations, which prevent posting
+ end;
+
+ procedure SetupGeneralJnlBatch(var GenJournalBatch: Record "Gen. Journal Batch")
+ var
+ GLAccount: Record "G/L Account";
+ begin
+ LibraryERM.SelectGenJnlBatch(GenJournalBatch);
+ CreateBalanceSheetGLAccount(GLAccount);
+ GenJournalBatch.Validate("Bal. Account No.", GLAccount."No.");
+ GenJournalBatch.Modify(true);
+
+ LibraryERM.ClearGenJournalLines(GenJournalBatch);
+ end;
+
+ procedure SetupGLAccount(var GLAccount: Record "G/L Account")
+ begin
+ FindGLAccLinkedToCostType(GLAccount);
+ SetDefaultDimension(GLAccount."No.");
+ end;
+
+ procedure TransferBudgetToActual(var TransferToActual: TestRequestPage "Transfer Budget to Actual"; BudgetName: Code[10]; DateRange: Text[30])
+ begin
+ TransferToActual."Cost Budget Entry".SetFilter("Budget Name", BudgetName);
+ TransferToActual."Cost Budget Entry".SetFilter(Date, DateRange);
+ end;
+
+ procedure TransferGLEntries()
+ begin
+ CODEUNIT.Run(CODEUNIT::"Transfer GL Entries to CA");
+ end;
+
+ procedure UpdateAllocSourceWithCCenter(var CostAllocationSource: Record "Cost Allocation Source")
+ var
+ CostCenter: Record "Cost Center";
+ begin
+ FindCostCenter(CostCenter);
+ CostAllocationSource.Validate("Cost Center Code", CostCenter.Code);
+ CostAllocationSource.Modify(true);
+ end;
+
+ procedure UpdateAllocSourceWithCObject(var CostAllocationSource: Record "Cost Allocation Source")
+ var
+ CostObject: Record "Cost Object";
+ begin
+ FindCostObject(CostObject);
+ CostAllocationSource.Validate("Cost Object Code", CostObject.Code);
+ CostAllocationSource.Modify(true);
+ end;
+
+ procedure UpdateAllocTargetWithCCenter(var CostAllocationTarget: Record "Cost Allocation Target")
+ var
+ CostCenter: Record "Cost Center";
+ begin
+ FindCostCenter(CostCenter);
+ CostAllocationTarget.Validate("Target Cost Center", CostCenter.Code);
+ CostAllocationTarget.Modify(true);
+ end;
+
+ procedure UpdateAllocTargetWithCObject(var CostAllocationTarget: Record "Cost Allocation Target")
+ var
+ CostObject: Record "Cost Object";
+ begin
+ FindCostObject(CostObject);
+ CostAllocationTarget.Validate("Target Cost Object", CostObject.Code);
+ CostAllocationTarget.Modify(true);
+ end;
+
+ [Normal]
+ procedure UpdateCostTypeWithCostCenter(var CostType: Record "Cost Type")
+ var
+ CostCenter: Record "Cost Center";
+ begin
+ FindCostCenter(CostCenter);
+ CostType.Validate("Cost Center Code", CostCenter.Code);
+ CostType.Modify(true);
+ end;
+
+ [Normal]
+ procedure UpdateCostTypeWithCostObject(var CostType: Record "Cost Type")
+ var
+ CostObject: Record "Cost Object";
+ begin
+ FindCostObject(CostObject);
+ CostType.Validate("Cost Object Code", CostObject.Code);
+ CostType.Modify(true);
+ end;
+
+ procedure ValidateEntriesTransfered()
+ var
+ GLRegister: Record "G/L Register";
+ GLEntry: Record "G/L Entry";
+ CostRegister: Record "Cost Register";
+ CostEntry: Record "Cost Entry";
+ GLAccount: Record "G/L Account";
+ begin
+ GLRegister.FindLast();
+ GLEntry.Get(GLRegister."From Entry No.");
+ CostRegister.SetFilter(Source, Format(CostRegister.Source::"Transfer from G/L"));
+ CostRegister.FindLast();
+ CostEntry.Get(CostRegister."From Cost Entry No.");
+ GLAccount.Get(CostEntry."G/L Account");
+
+ // Validate Cost Register Entry
+ Assert.AreEqual(1, CostRegister."No. of Entries",
+ StrSubstNo(ExpectedValueIsDifferentErr, CostRegister.FieldName("No. of Entries")));
+ Assert.AreEqual(0, CostRegister."To Cost Entry No." - CostRegister."From Cost Entry No.", CostEntriesCountErr);
+ Assert.AreEqual(GLEntry.Amount, CostRegister."Debit Amount",
+ StrSubstNo(ExpectedValueIsDifferentErr, CostRegister.FieldName("Debit Amount")));
+
+ // Validate Cost Entry
+ Assert.AreEqual(GLEntry.Amount, CostEntry.Amount, StrSubstNo(ExpectedValueIsDifferentErr, CostEntry.FieldName(Amount)));
+ Assert.AreEqual(GLEntry."Entry No.", CostEntry."G/L Entry No.",
+ StrSubstNo(ExpectedValueIsDifferentErr, CostEntry.FieldName("G/L Entry No.")));
+ Assert.AreEqual(GLAccount."Cost Type No.", CostEntry."Cost Type No.",
+ StrSubstNo(ExpectedValueIsDifferentErr, CostEntry.FieldName("Cost Type No.")));
+ Assert.AreEqual(GLEntry."G/L Account No.", CostEntry."G/L Account",
+ StrSubstNo(ExpectedValueIsDifferentErr, CostEntry.FieldName("G/L Account")));
+ Assert.AreEqual(GLEntry."Document No.", CostEntry."Document No.",
+ StrSubstNo(ExpectedValueIsDifferentErr, CostEntry.FieldName("Document No.")));
+ Assert.AreEqual(false, CostEntry.Allocated, StrSubstNo(ExpectedValueIsDifferentErr, CostEntry.FieldName(Allocated)));
+ end;
+
+ procedure ValidateGLAccountCostTypeRef(CostTypeNo: Code[20])
+ var
+ CostType: Record "Cost Type";
+ GLAccount: Record "G/L Account";
+ begin
+ // The Cost Type has the G/L Account Range filled in.
+ CostType.Get(CostTypeNo);
+ CostType.TestField("G/L Account Range");
+
+ // The G/L Accounts have the Cost Type No. filled in.
+ FindGLAccountsByCostType(GLAccount, CostType."G/L Account Range");
+ repeat
+ GLAccount.TestField("Cost Type No.", CostType."No.");
+ until GLAccount.Next() = 0;
+ end;
+
+ procedure ValidateGLAccountIsIncomeStmt(var CostType: Record "Cost Type")
+ var
+ GLAccount: Record "G/L Account";
+ begin
+ repeat
+ FindGLAccountsByCostType(GLAccount, CostType."G/L Account Range");
+ repeat
+ GLAccount.TestField("Income/Balance", GLAccount."Income/Balance"::"Income Statement");
+ until GLAccount.Next() = 0;
+ until CostType.Next() = 0;
+ end;
+
+ procedure VerifyCostTypeIntegrity()
+ var
+ CostType: Record "Cost Type";
+ GLAccount: Record "G/L Account";
+ begin
+ GetAllCostTypes(CostType);
+ repeat
+ GLAccount.SetFilter("No.", CostType."G/L Account Range");
+ if GLAccount.Count > 1 then begin
+ GLAccount.FindSet();
+ repeat
+ if GLAccount."Cost Type No." <> CostType."No." then
+ Error(GetCostTypesFromGLErr);
+ until GLAccount.Next() = 0;
+ end;
+ until CostType.Next() = 0;
+ end;
+}
+
diff --git a/Apps/W1/ApplicationTestLibrary/LibraryCosting.Codeunit.al b/Apps/W1/ApplicationTestLibrary/LibraryCosting.Codeunit.al
new file mode 100644
index 0000000000..3b5d549d44
--- /dev/null
+++ b/Apps/W1/ApplicationTestLibrary/LibraryCosting.Codeunit.al
@@ -0,0 +1,658 @@
+///
+/// Provides utility functions for inventory costing operations in test scenarios, including cost adjustment, posting, and validation.
+///
+codeunit 132200 "Library - Costing"
+{
+
+ trigger OnRun()
+ begin
+ end;
+
+ var
+ Assert: Codeunit Assert;
+ LibraryERM: Codeunit "Library - ERM";
+ IncorrectCostTxt: Label 'Incorrect Cost Amount in Entry No. %1.';
+ IncorrectRoundingTxt: Label 'Rounding mismatch of %1 for Inbound Entry No. %2.';
+ ShouldBeOfRecordTypeErr: Label 'Applies-To should be of type Record.';
+ WrongRecordTypeErr: Label 'Wrong Record Type.';
+
+ procedure AdjustCostItemEntries(ItemNoFilter: Text[250]; ItemCategoryFilter: Text[250])
+ var
+ AdjustCostItemEntriesReport: Report "Adjust Cost - Item Entries";
+ begin
+ Commit();
+ AdjustCostItemEntriesReport.InitializeRequest(ItemNoFilter, ItemCategoryFilter);
+ AdjustCostItemEntriesReport.UseRequestPage(false);
+ AdjustCostItemEntriesReport.RunModal();
+ end;
+
+ local procedure CalculateApplUnitCost(ItemLedgerEntryNo: Integer; PostingDate: Date; FirstOutboundValuePostingDate: Date; FirstOutboundValueEntryNo: Integer): Decimal
+ var
+ ValueEntry: Record "Value Entry";
+ CostWithoutRevaluation: Decimal;
+ ILEQuantity: Decimal;
+ RevaluationUnitCost: Decimal;
+ begin
+ ValueEntry.SetCurrentKey("Item Ledger Entry No.", "Entry Type");
+ ValueEntry.SetRange("Item Ledger Entry No.", ItemLedgerEntryNo);
+ ValueEntry.SetRange("Valuation Date", 0D, PostingDate);
+ if ValueEntry.FindSet() then
+ repeat
+ if ValueEntry."Entry Type" = ValueEntry."Entry Type"::Revaluation then begin
+ if (FirstOutboundValueEntryNo > ValueEntry."Entry No.") or (FirstOutboundValuePostingDate > ValueEntry."Posting Date") then
+ RevaluationUnitCost +=
+ (ValueEntry."Cost Amount (Actual)" + ValueEntry."Cost Amount (Expected)") / ValueEntry."Valued Quantity";
+ end else begin
+ CostWithoutRevaluation += ValueEntry."Cost Amount (Actual)" + ValueEntry."Cost Amount (Expected)";
+ ILEQuantity += ValueEntry."Item Ledger Entry Quantity";
+ end;
+ until ValueEntry.Next() = 0;
+ exit(CostWithoutRevaluation / ILEQuantity + RevaluationUnitCost);
+ end;
+
+ local procedure CalculateCostAmount(var ItemApplicationEntry: Record "Item Application Entry"; var TempItemJournalBuffer: Record "Item Journal Buffer" temporary; OutbndComplInvoiced: Boolean): Decimal
+ var
+ ItemLedgerEntry: Record "Item Ledger Entry";
+ RefCostAmount: Decimal;
+ RefInbILECostAmount: Decimal;
+ ValuationDate: Date;
+ FirstValuePostingDate: Date;
+ FirstValueEntryNo: Integer;
+ begin
+ if ItemApplicationEntry.FindSet() then begin
+ ValuationDate := FindLastValuationDate(ItemApplicationEntry."Outbound Item Entry No.");
+ FindFirstValueEntry(ItemApplicationEntry."Outbound Item Entry No.", FirstValueEntryNo, FirstValuePostingDate);
+ repeat
+ // Get the inbound Item Ledger Entry located at the other end of the application.
+ if ItemLedgerEntry.Get(ItemApplicationEntry."Inbound Item Entry No.") then begin
+ // Add cost according to how much of the inbound ILE quantity was applied to the outbound ILE.
+ RefInbILECostAmount :=
+ RoundAmount(
+ CalculateApplUnitCost(ItemLedgerEntry."Entry No.", ValuationDate, FirstValuePostingDate, FirstValueEntryNo) *
+ ItemApplicationEntry.Quantity);
+ RefCostAmount += RefInbILECostAmount;
+ if OutbndComplInvoiced then
+ UpdateBufferforRoundingCheck(
+ TempItemJournalBuffer, ItemLedgerEntry."Entry No.", ItemApplicationEntry.Quantity, RefInbILECostAmount);
+ end;
+ until ItemApplicationEntry.Next() = 0;
+ end;
+
+ exit(RefCostAmount);
+ end;
+
+ procedure CalculateInventoryValue(var ItemJournalLine: Record "Item Journal Line"; var Item: Record Item; NewPostingDate: Date; NewDocNo: Code[20]; NewCalculatePer: Enum "Inventory Value Calc. Per"; NewByLocation: Boolean; NewByVariant: Boolean; NewUpdStdCost: Boolean; NewCalcBase: Enum "Inventory Value Calc. Base"; NewShowDialog: Boolean)
+ var
+ CalculateInventoryValueReport: Report "Calculate Inventory Value";
+ begin
+ CalculateInventoryValueReport.SetParameters(
+ NewPostingDate, NewDocNo, true, NewCalculatePer, NewByLocation, NewByVariant, NewUpdStdCost, NewCalcBase, NewShowDialog);
+ Commit();
+ CalculateInventoryValueReport.UseRequestPage(false);
+ CalculateInventoryValueReport.SetItemJnlLine(ItemJournalLine);
+ CalculateInventoryValueReport.SetTableView(Item);
+ CalculateInventoryValueReport.RunModal();
+ end;
+
+ procedure CopyStandardCostWorksheet(FromStandardCostWorksheetName: Code[10]; ToStandardCostWorksheetName: Code[10])
+ var
+ CopyStandardCostWorksheetReport: Report "Copy Standard Cost Worksheet";
+ begin
+ Clear(CopyStandardCostWorksheetReport);
+ CopyStandardCostWorksheetReport.Initialize(FromStandardCostWorksheetName, ToStandardCostWorksheetName, true);
+ CopyStandardCostWorksheetReport.UseRequestPage(false);
+ CopyStandardCostWorksheetReport.Run();
+ end;
+
+ procedure CheckAdjustment(Item: Record Item)
+ var
+ TempItemJournalBuffer: Record "Item Journal Buffer" temporary;
+ begin
+ PrepareBufferforRoundingCheck(Item, TempItemJournalBuffer);
+ if Item."Costing Method" = Item."Costing Method"::Average then
+ CheckAverageCosting(Item, TempItemJournalBuffer)
+ else
+ CheckNonAverageCosting(Item, TempItemJournalBuffer);
+
+ VerifyInboundEntriesRounding(TempItemJournalBuffer);
+ end;
+
+ local procedure CheckAverageCosting(Item: Record Item; var TempItemJournalBuffer: Record "Item Journal Buffer" temporary)
+ var
+ AvgCostAdjmtEntryPoint: Record "Avg. Cost Adjmt. Entry Point";
+ ValueEntry: Record "Value Entry";
+ OutboundItemLedgerEntry: Record "Item Ledger Entry";
+ FixedAppItemLedgerEntry: Record "Item Ledger Entry";
+ OutboundValueEntry: Record "Value Entry";
+ FixedAppValueEntry: Record "Value Entry";
+ TempValueEntry: Record "Value Entry" temporary;
+ CurrPeriodInboundCost: Decimal;
+ CurrPeriodInboundQty: Decimal;
+ PrevPeriodCost: Decimal;
+ PrevPeriodQty: Decimal;
+ RefCostAmount: Decimal;
+ OutboundCostAmount: Decimal;
+ RevaluationUnitCost: Decimal;
+ RefCostAmountwoReval: Decimal;
+ PeriodStartDate: Date;
+ begin
+ PrevPeriodCost := 0;
+ PrevPeriodQty := 0;
+ PeriodStartDate := 0D;
+ AvgCostAdjmtEntryPoint.SetRange("Item No.", Item."No.");
+ AvgCostAdjmtEntryPoint.FindSet();
+ ValueEntry.SetCurrentKey("Item No.", "Valuation Date", "Location Code", "Variant Code");
+ ValueEntry.SetRange("Item No.", Item."No.");
+ repeat
+ // Add cost and quantity of all inbound non-revaluation entries for the period
+ ValueEntry.SetRange("Valuation Date", PeriodStartDate, AvgCostAdjmtEntryPoint."Valuation Date");
+ ValueEntry.SetFilter("Valued Quantity", '>%1', 0);
+ ValueEntry.SetFilter("Entry Type", '<>%1', ValueEntry."Entry Type"::Revaluation);
+ ValueEntry.CalcSums("Cost Amount (Actual)", "Cost Amount (Expected)", "Item Ledger Entry Quantity");
+ CurrPeriodInboundCost := ValueEntry."Cost Amount (Actual)" + ValueEntry."Cost Amount (Expected)";
+ CurrPeriodInboundQty := ValueEntry."Item Ledger Entry Quantity";
+
+ // Reduce cost and quantity of inbound entries in the period, which are fixed applied
+ if ValueEntry.FindSet() then
+ repeat
+ // Only loop through the quantity entries and add up the cost without revaluation
+ if ValueEntry."Item Ledger Entry Quantity" <> 0 then begin
+ FixedAppItemLedgerEntry.SetRange("Item No.", Item."No.");
+ FixedAppItemLedgerEntry.SetRange("Applies-to Entry", ValueEntry."Item Ledger Entry No.");
+ if FixedAppItemLedgerEntry.FindFirst() then begin
+ FixedAppItemLedgerEntry.CalcSums(Quantity);
+ FixedAppValueEntry.SetCurrentKey("Item Ledger Entry No.", "Entry Type");
+ FixedAppValueEntry.SetRange("Item Ledger Entry No.", ValueEntry."Item Ledger Entry No.");
+ FixedAppValueEntry.SetFilter("Entry Type", '<>%1', FixedAppValueEntry."Entry Type"::Revaluation);
+ FixedAppValueEntry.SetRange("Valuation Date", PeriodStartDate, AvgCostAdjmtEntryPoint."Valuation Date");
+ FixedAppValueEntry.SetFilter("Valued Quantity", '>%1', 0);
+ FixedAppValueEntry.CalcSums("Cost Amount (Actual)", "Cost Amount (Expected)", "Item Ledger Entry Quantity");
+ CurrPeriodInboundCost +=
+ Round((FixedAppValueEntry."Cost Amount (Expected)" + FixedAppValueEntry."Cost Amount (Actual)") /
+ FixedAppValueEntry."Item Ledger Entry Quantity" * FixedAppItemLedgerEntry.Quantity,
+ LibraryERM.GetAmountRoundingPrecision());
+ CurrPeriodInboundQty += FixedAppItemLedgerEntry.Quantity;
+ end;
+ end;
+ until ValueEntry.Next() = 0;
+
+ // Store the revaluation entries
+ ValueEntry.SetRange("Entry Type", ValueEntry."Entry Type"::Revaluation);
+ TempValueEntry.DeleteAll();
+ if ValueEntry.FindSet() then
+ repeat
+ TempValueEntry := ValueEntry;
+ TempValueEntry.Insert();
+ until ValueEntry.Next() = 0;
+
+ // Add cost and quantity from previous period
+ CurrPeriodInboundCost += PrevPeriodCost;
+ CurrPeriodInboundQty += PrevPeriodQty;
+
+ // Validate Outbound entries for the period
+ OutboundValueEntry.SetRange("Item No.", Item."No.");
+ OutboundValueEntry.SetRange("Valuation Date", PeriodStartDate, AvgCostAdjmtEntryPoint."Valuation Date");
+ OutboundValueEntry.SetFilter("Item Ledger Entry Quantity", '<%1', 0);
+ if OutboundValueEntry.FindSet() then
+ repeat
+ OutboundItemLedgerEntry.Get(OutboundValueEntry."Item Ledger Entry No.");
+ if OutboundItemLedgerEntry."Applies-to Entry" = 0 then begin
+ // If not fixed applied, unit cost should be equal to average cost for the period
+
+ // Add applied revaluation
+ RevaluationUnitCost := 0;
+ if TempValueEntry.FindSet() then
+ repeat
+ if (OutboundValueEntry."Entry No." > TempValueEntry."Entry No.") or
+ (OutboundValueEntry."Posting Date" > TempValueEntry."Posting Date")
+ then
+ RevaluationUnitCost +=
+ (TempValueEntry."Cost Amount (Actual)" + TempValueEntry."Cost Amount (Expected)") /
+ TempValueEntry."Valued Quantity";
+ until TempValueEntry.Next() = 0;
+
+ RefCostAmountwoReval := (CurrPeriodInboundCost / CurrPeriodInboundQty) * OutboundItemLedgerEntry.Quantity;
+ RefCostAmount :=
+ Round(
+ RevaluationUnitCost * OutboundItemLedgerEntry.Quantity + RefCostAmountwoReval, LibraryERM.GetAmountRoundingPrecision());
+
+ OutboundItemLedgerEntry.CalcFields("Cost Amount (Expected)", "Cost Amount (Actual)");
+ OutboundCostAmount := OutboundItemLedgerEntry."Cost Amount (Expected)" + OutboundItemLedgerEntry."Cost Amount (Actual)";
+
+ // Reduce the inbound cost and quantity for validating with the next outboud ILE
+ CurrPeriodInboundCost += Round(RefCostAmountwoReval, LibraryERM.GetAmountRoundingPrecision());
+ CurrPeriodInboundQty += OutboundItemLedgerEntry.Quantity;
+ Assert.AreNearlyEqual(RefCostAmount, OutboundCostAmount, LibraryERM.GetAmountRoundingPrecision(),
+ StrSubstNo(IncorrectCostTxt, OutboundItemLedgerEntry."Entry No."));
+ end else begin
+ // If fixed applied, verification is same as non-average cost items
+ FixedAppItemLedgerEntry.Get(OutboundItemLedgerEntry."Entry No.");
+ FixedAppItemLedgerEntry.SetRecFilter();
+ CheckCostAmount(FixedAppItemLedgerEntry, TempItemJournalBuffer);
+ end;
+ until OutboundValueEntry.Next() = 0;
+
+ // Prepare carry forward values for the next period
+ PeriodStartDate := AvgCostAdjmtEntryPoint."Valuation Date" + 1;
+ ValueEntry.SetRange("Valued Quantity");
+ ValueEntry.SetRange("Entry Type");
+ ValueEntry.CalcSums("Cost Amount (Actual)", "Cost Amount (Expected)", "Item Ledger Entry Quantity");
+ PrevPeriodCost += ValueEntry."Cost Amount (Actual)" + ValueEntry."Cost Amount (Expected)";
+ PrevPeriodQty += ValueEntry."Item Ledger Entry Quantity";
+ until AvgCostAdjmtEntryPoint.Next() = 0;
+ end;
+
+ local procedure CheckCostAmount(var ItemLedgerEntry: Record "Item Ledger Entry"; var TempItemJournalBuffer: Record "Item Journal Buffer" temporary)
+ var
+ ItemApplicationEntry: Record "Item Application Entry";
+ RefCostAmount: Decimal;
+ begin
+ if ItemLedgerEntry.FindSet() then
+ repeat
+ // Find all applications pointing to the ILE.
+ ItemApplicationEntry.SetRange("Outbound Item Entry No.", ItemLedgerEntry."Entry No.");
+ ItemApplicationEntry.SetFilter(Quantity, '<%1', 0);
+
+ // Calculate the reference cost amount on the ValuationDate
+ RefCostAmount := CalculateCostAmount(ItemApplicationEntry, TempItemJournalBuffer, ItemLedgerEntry."Completely Invoiced");
+
+ // Compare to actuals.
+ ItemLedgerEntry.CalcFields("Cost Amount (Expected)", "Cost Amount (Actual)");
+ Assert.AreEqual(
+ RefCostAmount, ItemLedgerEntry."Cost Amount (Actual)" + ItemLedgerEntry."Cost Amount (Expected)",
+ StrSubstNo(IncorrectCostTxt, ItemLedgerEntry."Entry No."));
+ until ItemLedgerEntry.Next() = 0;
+ end;
+
+ local procedure CheckNonAverageCosting(Item: Record Item; var TempItemJournalBuffer: Record "Item Journal Buffer" temporary)
+ var
+ ItemLedgerEntry: Record "Item Ledger Entry";
+ begin
+ // Check all outbound ILEs.
+ ItemLedgerEntry.Reset();
+ ItemLedgerEntry.SetRange("Item No.", Item."No.");
+ ItemLedgerEntry.SetRange(Positive, false);
+ CheckCostAmount(ItemLedgerEntry, TempItemJournalBuffer);
+ end;
+
+ procedure CheckInboundEntriesCost(var TempItemLedgerEntry: Record "Item Ledger Entry" temporary)
+ var
+ RefCostPerUnit: Decimal;
+ RefCost: Decimal;
+ ActualCost: Decimal;
+ begin
+ TempItemLedgerEntry.FindFirst();
+ TempItemLedgerEntry.CalcFields("Cost Amount (Expected)", "Cost Amount (Actual)");
+ RefCostPerUnit :=
+ (TempItemLedgerEntry."Cost Amount (Expected)" + TempItemLedgerEntry."Cost Amount (Actual)") / TempItemLedgerEntry.Quantity;
+
+ // Check if the subsequent inbound entries have the same cost as the original inbound entry - to make sure the cost modification has been propagated
+ while TempItemLedgerEntry.Next() <> 0 do begin
+ TempItemLedgerEntry.CalcFields("Cost Amount (Expected)", "Cost Amount (Actual)");
+ ActualCost := TempItemLedgerEntry."Cost Amount (Expected)" + TempItemLedgerEntry."Cost Amount (Actual)";
+ RefCost := Round(RefCostPerUnit * TempItemLedgerEntry.Quantity, LibraryERM.GetAmountRoundingPrecision());
+ Assert.AreEqual(RefCost, ActualCost, StrSubstNo(IncorrectCostTxt, TempItemLedgerEntry."Entry No."));
+ end;
+ end;
+
+#if not CLEAN27
+#pragma warning disable AL0801
+ [Obsolete('Moved to codeunit LibraryManufacturing', '27.0')]
+ procedure CheckProductionOrderCost(ProdOrder: Record "Production Order"; VerifyVarianceinOutput: Boolean)
+ var
+ LibraryManufacturing: Codeunit "Library - Manufacturing";
+ begin
+ LibraryManufacturing.CheckProductionOrderCost(ProdOrder, VerifyVarianceinOutput);
+ end;
+#pragma warning restore AL0801
+#endif
+
+ procedure CreatePurchasePrice(var PurchasePrice: Record "Purchase Price"; VendorNo: Code[20]; ItemNo: Code[20]; StartingDate: Date; CurrencyCode: Code[10]; VariantCode: Code[10]; UnitOfMeasureCode: Code[10]; MinimumQuantity: Decimal)
+ begin
+ PurchasePrice.Init();
+ PurchasePrice.Validate("Vendor No.", VendorNo);
+ PurchasePrice.Validate("Item No.", ItemNo);
+ PurchasePrice.Validate("Starting Date", StartingDate);
+ PurchasePrice.Validate("Currency Code", CurrencyCode);
+ PurchasePrice.Validate("Variant Code", VariantCode);
+ PurchasePrice.Validate("Unit of Measure Code", UnitOfMeasureCode);
+ PurchasePrice.Validate("Minimum Quantity", MinimumQuantity);
+ PurchasePrice.Insert(true);
+ end;
+
+ procedure CreateRevaluationJournal(var ItemJournalBatch: Record "Item Journal Batch"; var Item: Record Item; NewPostingDate: Date; NewDocNo: Code[20]; NewCalculatePer: Enum "Inventory Value Calc. Per"; NewByLocation: Boolean; NewByVariant: Boolean; NewUpdStdCost: Boolean; NewCalcBase: Enum "Inventory Value Calc. Base"; NewShowDialog: Boolean)
+ var
+ ItemJournalLine: Record "Item Journal Line";
+ begin
+ ItemJournalLine.Validate("Journal Template Name", ItemJournalBatch."Journal Template Name");
+ ItemJournalLine.Validate("Journal Batch Name", ItemJournalBatch.Name);
+ CalculateInventoryValue(
+ ItemJournalLine, Item, NewPostingDate, NewDocNo, NewCalculatePer, NewByLocation,
+ NewByVariant, NewUpdStdCost, NewCalcBase, NewShowDialog);
+ end;
+
+ procedure CreateRevaluationJnlLines(var Item: Record Item; ItemJournalLine: Record "Item Journal Line"; DocNo: Code[20]; CalculatePer: Enum "Inventory Value Calc. Per"; ReCalcStdCost: Enum "Inventory Value Calc. Base"; ByLocation: Boolean; ByVariant: Boolean; UpdStdCost: Boolean; PostingDate: Date)
+ var
+ TmpItem: Record Item;
+ CalcInvtValue: Report "Calculate Inventory Value";
+ begin
+ ItemJournalLine.DeleteAll();
+ CalcInvtValue.SetItemJnlLine(ItemJournalLine);
+ if Item.HasFilter then
+ TmpItem.CopyFilters(Item)
+ else begin
+ Item.Get(Item."No.");
+ TmpItem.SetRange("No.", Item."No.");
+ end;
+ CalcInvtValue.SetTableView(TmpItem);
+ CalcInvtValue.SetParameters(PostingDate, DocNo, true, CalculatePer, ByLocation, ByVariant, UpdStdCost, ReCalcStdCost, true);
+ CalcInvtValue.UseRequestPage(false);
+ CalcInvtValue.RunModal();
+ end;
+
+ procedure CreateSalesPrice(var SalesPrice: Record "Sales Price"; SalesType: Enum "Sales Price Type"; SalesCode: Code[20]; ItemNo: Code[20]; StartingDate: Date; CurrencyCode: Code[10]; VariantCode: Code[10]; UnitOfMeasureCode: Code[10]; MinimumQuantity: Decimal)
+ begin
+ SalesPrice.Init();
+ SalesPrice.Validate("Sales Type", SalesType);
+ SalesPrice.Validate("Sales Code", SalesCode);
+ SalesPrice.Validate("Item No.", ItemNo);
+ SalesPrice.Validate("Starting Date", StartingDate);
+ SalesPrice.Validate("Currency Code", CurrencyCode);
+ SalesPrice.Validate("Variant Code", VariantCode);
+ SalesPrice.Validate("Unit of Measure Code", UnitOfMeasureCode);
+ SalesPrice.Validate("Minimum Quantity", MinimumQuantity);
+ SalesPrice.Insert(true);
+ end;
+
+ procedure ImplementPriceChange(SalesPriceWorksheet: Record "Sales Price Worksheet")
+ var
+ ImplementPriceChangeReport: Report "Implement Price Change";
+ begin
+ Clear(ImplementPriceChangeReport);
+ ImplementPriceChangeReport.InitializeRequest(true);
+ ImplementPriceChangeReport.UseRequestPage(false);
+ ImplementPriceChangeReport.SetTableView(SalesPriceWorksheet);
+ ImplementPriceChangeReport.RunModal();
+ end;
+
+ local procedure FindFirstValueEntry(ItemLedgerEntryNo: Integer; var FirstEntryNo: Integer; var FirstPostingDate: Date)
+ var
+ ValueEntry: Record "Value Entry";
+ begin
+ ValueEntry.SetCurrentKey("Item Ledger Entry No.", "Entry Type");
+ ValueEntry.SetRange("Item Ledger Entry No.", ItemLedgerEntryNo);
+ ValueEntry.FindSet();
+ repeat
+ if (ValueEntry."Item Ledger Entry Quantity" <> 0) and
+ ((FirstEntryNo = 0) or (FirstEntryNo > ValueEntry."Entry No."))
+ then begin
+ FirstEntryNo := ValueEntry."Entry No.";
+ FirstPostingDate := ValueEntry."Posting Date";
+ end;
+ until (ValueEntry.Next() = 0);
+ end;
+
+ local procedure FindLastValuationDate(ItemLedgerEntryNo: Integer) LastValuationDate: Date
+ var
+ ValueEntry: Record "Value Entry";
+ begin
+ ValueEntry.SetCurrentKey("Item Ledger Entry No.", "Entry Type");
+ ValueEntry.SetRange("Item Ledger Entry No.", ItemLedgerEntryNo);
+ ValueEntry.FindSet();
+ repeat
+ if LastValuationDate < ValueEntry."Valuation Date" then
+ LastValuationDate := ValueEntry."Valuation Date";
+ until (ValueEntry.Next() = 0);
+ exit(LastValuationDate);
+ end;
+
+ procedure PostInvtCostToGLTest(PostMethod: Option; ItemNo: Code[20]; DocumentNo: Code[20]; ShowDim: Boolean; ShowOnlyWarnings: Boolean)
+ var
+ PostValueEntryToGL: Record "Post Value Entry to G/L";
+ PostInvtCostToGLTestReport: Report "Post Invt. Cost to G/L - Test";
+ begin
+ Commit();
+ PostValueEntryToGL.SetRange("Item No.", ItemNo);
+ PostInvtCostToGLTestReport.InitializeRequest(PostMethod, DocumentNo, ShowDim, ShowOnlyWarnings);
+ PostInvtCostToGLTestReport.SetTableView(PostValueEntryToGL);
+ PostInvtCostToGLTestReport.UseRequestPage(false);
+ end;
+
+ local procedure PrepareBufferforRoundingCheck(Item: Record Item; var TempItemJnlBuffer: Record "Item Journal Buffer" temporary)
+ var
+ InboundItemLedgerEntry: Record "Item Ledger Entry";
+ begin
+ // Create a buffer entry for each inbound entry - only consider invoiced quantity and cost
+ // Note: Rounding entries are created only after inbound and outbound entries have been invoiced completely
+ TempItemJnlBuffer.DeleteAll();
+ InboundItemLedgerEntry.SetRange("Item No.", Item."No.");
+ InboundItemLedgerEntry.SetRange(Positive, true);
+ InboundItemLedgerEntry.SetRange("Completely Invoiced", true);
+ if InboundItemLedgerEntry.FindSet() then
+ repeat
+ TempItemJnlBuffer.Init();
+ TempItemJnlBuffer."Line No." := InboundItemLedgerEntry."Entry No.";
+ TempItemJnlBuffer.Quantity := InboundItemLedgerEntry."Invoiced Quantity";
+ InboundItemLedgerEntry.CalcFields("Cost Amount (Actual)");
+ TempItemJnlBuffer."Inventory Value (Calculated)" := InboundItemLedgerEntry."Cost Amount (Actual)";
+ TempItemJnlBuffer.Insert();
+ until InboundItemLedgerEntry.Next() = 0;
+ end;
+
+ local procedure RoundAmount(Amount: Decimal): Decimal
+ begin
+ exit(Round(Amount, LibraryERM.GetAmountRoundingPrecision(), '='));
+ end;
+
+#if not CLEAN27
+#pragma warning disable AL0801
+ [Obsolete('Moved to codeunit LibraryManufacturing', '27.0')]
+ procedure SuggestCapacityStandardCost(var WorkCenter: Record "Work Center"; var MachineCenter: Record "Machine Center"; StandardCostWorksheetName: Code[10]; StandardCostAdjustmentFactor: Integer; StandardCostRoundingMethod: Code[10])
+ var
+ LibraryManufacturing: Codeunit "Library - Manufacturing";
+ begin
+ LibraryManufacturing.SuggestCapacityStandardCost(WorkCenter, MachineCenter, StandardCostWorksheetName, StandardCostAdjustmentFactor, StandardCostRoundingMethod);
+ end;
+#pragma warning restore AL0801
+#endif
+
+ procedure SuggestSalesPriceWorksheet(Item: Record Item; SalesCode: Code[20]; SalesType: Enum "Sales Price Type"; PriceLowerLimit: Decimal; UnitPriceFactor: Decimal)
+ var
+ SalesPrice: Record "Sales Price";
+ SuggestSalesPriceOnWksh: Report "Suggest Sales Price on Wksh.";
+ begin
+ Clear(SuggestSalesPriceOnWksh);
+ SuggestSalesPriceOnWksh.InitializeRequest2(
+ SalesType.AsInteger(), SalesCode, WorkDate(), WorkDate(), '', Item."Base Unit of Measure", false, PriceLowerLimit, UnitPriceFactor, '');
+ SuggestSalesPriceOnWksh.UseRequestPage(false);
+ SalesPrice.SetRange("Item No.", Item."No.");
+ SuggestSalesPriceOnWksh.SetTableView(SalesPrice);
+ SuggestSalesPriceOnWksh.RunModal();
+ end;
+
+ procedure SuggestItemPriceWorksheet(Item: Record Item; SalesCode: Code[20]; SalesType: Enum "Sales Price Type"; PriceLowerLimit: Decimal; UnitPriceFactor: Decimal)
+ var
+ SuggestItemPriceOnWksh: Report "Suggest Item Price on Wksh.";
+ begin
+ Clear(SuggestItemPriceOnWksh);
+ SuggestItemPriceOnWksh.InitializeRequest2(
+ SalesType.AsInteger(), SalesCode, WorkDate(), WorkDate(), '', Item."Base Unit of Measure", PriceLowerLimit, UnitPriceFactor, '', true);
+ SuggestItemPriceOnWksh.UseRequestPage(false);
+ Item.SetRange("No.", Item."No.");
+ SuggestItemPriceOnWksh.SetTableView(Item);
+ SuggestItemPriceOnWksh.RunModal();
+ end;
+
+ procedure SuggestItemPriceWorksheet2(Item: Record Item; SalesCode: Code[20]; SalesType: Enum "Sales Price Type"; PriceLowerLimit: Decimal; UnitPriceFactor: Decimal; CurrencyCode: Code[10])
+ var
+ TmpItem: Record Item;
+ SuggestItemPriceOnWksh: Report "Suggest Item Price on Wksh.";
+ begin
+ Clear(SuggestItemPriceOnWksh);
+ SuggestItemPriceOnWksh.InitializeRequest2(
+ SalesType.AsInteger(), SalesCode, WorkDate(), WorkDate(), CurrencyCode, Item."Base Unit of Measure", PriceLowerLimit, UnitPriceFactor, '', true);
+ if Item.HasFilter then
+ TmpItem.CopyFilters(Item)
+ else begin
+ Item.Get(Item."No.");
+ TmpItem.SetRange("No.", Item."No.");
+ end;
+ SuggestItemPriceOnWksh.SetTableView(TmpItem);
+ SuggestItemPriceOnWksh.UseRequestPage(false);
+ SuggestItemPriceOnWksh.RunModal();
+ end;
+
+ procedure SuggestItemStandardCost(var Item: Record Item; StandardCostWorksheetName: Code[10]; StandardCostAdjustmentFactor: Integer; StandardCostRoundingMethod: Code[10])
+ var
+ TmpItem: Record Item;
+ SuggestItemStandardCostReport: Report "Suggest Item Standard Cost";
+ begin
+ Clear(SuggestItemStandardCostReport);
+ SuggestItemStandardCostReport.Initialize(StandardCostWorksheetName, StandardCostAdjustmentFactor, 0, 0, StandardCostRoundingMethod, '', '');
+ if Item.HasFilter then
+ TmpItem.CopyFilters(Item)
+ else begin
+ Item.Get(Item."No.");
+ TmpItem.SetRange("No.", Item."No.");
+ end;
+ SuggestItemStandardCostReport.SetTableView(TmpItem);
+ SuggestItemStandardCostReport.UseRequestPage(false);
+ SuggestItemStandardCostReport.Run();
+ end;
+
+#if not CLEAN27
+#pragma warning disable AL0801
+ [Obsolete('Moved to codeunit LibraryManufacturing', '27.0')]
+ procedure UpdateUnitCost(var ProductionOrder: Record "Production Order"; CalcMethod: Option; UpdateReservations: Boolean)
+ var
+ LibraryManufacturing: Codeunit "Library - Manufacturing";
+ begin
+ LibraryManufacturing.UpdateUnitCost(ProductionOrder, CalcMethod, UpdateReservations);
+ end;
+#pragma warning restore AL0801
+#endif
+
+ local procedure UpdateBufferforRoundingCheck(var TempItemJournalBuffer: Record "Item Journal Buffer" temporary; EntryNo: Integer; Quantity: Decimal; CostAmount: Decimal)
+ begin
+ // Reduce the cost and quantity of outbound entry from the inbound buffer - only for completely invoiced outbound entries
+ if TempItemJournalBuffer.Get(EntryNo) then begin
+ TempItemJournalBuffer.Quantity += Quantity;
+ TempItemJournalBuffer."Inventory Value (Calculated)" += CostAmount;
+ TempItemJournalBuffer.Modify();
+ end;
+ end;
+
+ local procedure VerifyInboundEntriesRounding(var TempItemJournalBuffer: Record "Item Journal Buffer" temporary)
+ begin
+ // Verify that if the residual quantity is zero, the residual cost should also be zero
+ TempItemJournalBuffer.SetRange(Quantity, 0);
+ TempItemJournalBuffer.SetFilter("Inventory Value (Calculated)", '>%1', 0.01);
+ // Throws only the first rounding error
+ if TempItemJournalBuffer.FindFirst() then
+ Assert.Fail(
+ StrSubstNo(IncorrectRoundingTxt, TempItemJournalBuffer."Inventory Value (Calculated)", TempItemJournalBuffer."Line No."));
+ end;
+
+ procedure AssignItemChargePurch(PurchaseLineCharge: Record "Purchase Line"; AppliesTo: Variant)
+ var
+ ItemChargeAssignmentPurch: Record "Item Charge Assignment (Purch)";
+ DocumentType: Option;
+ ItemNo: Code[20];
+ DocumentNo: Code[20];
+ LineNo: Integer;
+ begin
+ GetAppliesToValues(AppliesTo, DocumentType, DocumentNo, LineNo, ItemNo);
+ ItemChargeAssignmentPurch.Init();
+ ItemChargeAssignmentPurch.Validate("Document Type", PurchaseLineCharge."Document Type");
+ ItemChargeAssignmentPurch.Validate("Document No.", PurchaseLineCharge."Document No.");
+ ItemChargeAssignmentPurch.Validate("Document Line No.", PurchaseLineCharge."Line No.");
+ ItemChargeAssignmentPurch.Validate("Item Charge No.", PurchaseLineCharge."No.");
+
+ ItemChargeAssignmentPurch.Validate("Applies-to Doc. Type", DocumentType);
+ ItemChargeAssignmentPurch.Validate("Applies-to Doc. No.", DocumentNo);
+ ItemChargeAssignmentPurch.Validate("Applies-to Doc. Line No.", LineNo);
+
+ ItemChargeAssignmentPurch.Validate("Unit Cost", PurchaseLineCharge."Unit Cost");
+ ItemChargeAssignmentPurch.Validate("Item No.", ItemNo);
+ ItemChargeAssignmentPurch.Validate("Qty. to Assign", PurchaseLineCharge.Quantity);
+ ItemChargeAssignmentPurch.Insert(true);
+ end;
+
+ procedure AssignItemChargeSales(SalesLineCharge: Record "Sales Line"; AppliesTo: Variant)
+ var
+ ItemChargeAssignmentSales: Record "Item Charge Assignment (Sales)";
+ DocumentType: Option;
+ ItemNo: Code[20];
+ DocumentNo: Code[20];
+ LineNo: Integer;
+ begin
+ GetAppliesToValues(AppliesTo, DocumentType, DocumentNo, LineNo, ItemNo);
+ ItemChargeAssignmentSales.Init();
+ ItemChargeAssignmentSales.Validate("Document Type", SalesLineCharge."Document Type");
+ ItemChargeAssignmentSales.Validate("Document No.", SalesLineCharge."Document No.");
+ ItemChargeAssignmentSales.Validate("Document Line No.", SalesLineCharge."Line No.");
+ ItemChargeAssignmentSales.Validate("Item Charge No.", SalesLineCharge."No.");
+
+ ItemChargeAssignmentSales.Validate("Applies-to Doc. Type", DocumentType);
+ ItemChargeAssignmentSales.Validate("Applies-to Doc. No.", DocumentNo);
+ ItemChargeAssignmentSales.Validate("Applies-to Doc. Line No.", LineNo);
+
+ ItemChargeAssignmentSales.Validate("Unit Cost", SalesLineCharge."Unit Cost");
+ ItemChargeAssignmentSales.Validate("Item No.", ItemNo);
+ ItemChargeAssignmentSales.Validate("Qty. to Assign", SalesLineCharge.Quantity);
+ ItemChargeAssignmentSales.Insert(true);
+ end;
+
+ local procedure GetAppliesToValues(AppliesTo: Variant; var DocumentType: Option; var DocumentNo: Code[20]; var LineNo: Integer; var ItemNo: Code[20])
+ var
+ PurchaseLine: Record "Purchase Line";
+ PurchRcptLine: Record "Purch. Rcpt. Line";
+ SalesLine: Record "Sales Line";
+ SalesShptLine: Record "Sales Shipment Line";
+ ItemChargeAssignmentPurch: Record "Item Charge Assignment (Purch)";
+ ItemChargeAssignmentSales: Record "Item Charge Assignment (Sales)";
+ RecRef: RecordRef;
+ begin
+ if not AppliesTo.IsRecord then
+ Error(ShouldBeOfRecordTypeErr);
+
+ RecRef.GetTable(AppliesTo);
+ case RecRef.Number of
+ DATABASE::"Purchase Line":
+ begin
+ PurchaseLine := AppliesTo;
+ DocumentType := PurchaseLine."Document Type".AsInteger();
+ DocumentNo := PurchaseLine."Document No.";
+ LineNo := PurchaseLine."Line No.";
+ ItemNo := PurchaseLine."No.";
+ end;
+ DATABASE::"Purch. Rcpt. Line":
+ begin
+ PurchRcptLine := AppliesTo;
+ DocumentType := ItemChargeAssignmentPurch."Applies-to Doc. Type"::Receipt.AsInteger();
+ DocumentNo := PurchRcptLine."Document No.";
+ LineNo := PurchRcptLine."Line No.";
+ ItemNo := PurchRcptLine."No.";
+ end;
+ DATABASE::"Sales Line":
+ begin
+ SalesLine := AppliesTo;
+ DocumentType := SalesLine."Document Type".AsInteger();
+ DocumentNo := SalesLine."Document No.";
+ LineNo := SalesLine."Line No.";
+ ItemNo := SalesLine."No.";
+ end;
+ DATABASE::"Sales Shipment Line":
+ begin
+ SalesShptLine := AppliesTo;
+ DocumentType := ItemChargeAssignmentSales."Applies-to Doc. Type"::Shipment.AsInteger();
+ DocumentNo := SalesShptLine."Document No.";
+ LineNo := SalesShptLine."Line No.";
+ ItemNo := SalesShptLine."No.";
+ end;
+ else
+ Error(WrongRecordTypeErr);
+ end;
+ end;
+}
+
diff --git a/Apps/W1/ApplicationTestLibrary/LibraryDialogHandler.Codeunit.al b/Apps/W1/ApplicationTestLibrary/LibraryDialogHandler.Codeunit.al
new file mode 100644
index 0000000000..81dde4b0b8
--- /dev/null
+++ b/Apps/W1/ApplicationTestLibrary/LibraryDialogHandler.Codeunit.al
@@ -0,0 +1,51 @@
+///
+/// Provides handler functions for managing dialog messages and prompts in automated test scenarios.
+///
+codeunit 131005 "Library - Dialog Handler"
+{
+ var
+ Assert: Codeunit Assert;
+ LibraryVariableStorage: Codeunit "Library - Variable Storage";
+
+ procedure HandleMessage(Message: Text)
+ begin
+ Assert.ExpectedMessage(LibraryVariableStorage.DequeueText(), Message);
+ end;
+
+ procedure HandleConfirm(Question: Text; var Reply: Boolean)
+ begin
+ Assert.ExpectedConfirm(LibraryVariableStorage.DequeueText(), Question);
+ Reply := LibraryVariableStorage.DequeueBoolean();
+ end;
+
+ procedure HandleStrMenu(Options: Text; var Choice: Integer; Instruction: Text)
+ begin
+ Assert.ExpectedStrMenu(
+ LibraryVariableStorage.DequeueText(), LibraryVariableStorage.DequeueText(),
+ Instruction, Options);
+ Choice := LibraryVariableStorage.DequeueInteger();
+ end;
+
+ procedure SetExpectedMessage(Message: Text)
+ begin
+ LibraryVariableStorage.Enqueue(Message);
+ end;
+
+ procedure SetExpectedConfirm(Question: Text; Reply: Boolean)
+ begin
+ LibraryVariableStorage.Enqueue(Question);
+ LibraryVariableStorage.Enqueue(Reply);
+ end;
+
+ procedure SetExpectedStrMenu(Options: Text; Choice: Integer; Instruction: Text)
+ begin
+ LibraryVariableStorage.Enqueue(Instruction);
+ LibraryVariableStorage.Enqueue(Options);
+ LibraryVariableStorage.Enqueue(Choice);
+ end;
+
+ procedure ClearVariableStorage()
+ begin
+ LibraryVariableStorage.Clear();
+ end;
+}
\ No newline at end of file
diff --git a/Apps/W1/ApplicationTestLibrary/LibraryDimension.Codeunit.al b/Apps/W1/ApplicationTestLibrary/LibraryDimension.Codeunit.al
new file mode 100644
index 0000000000..9fbb88cdd2
--- /dev/null
+++ b/Apps/W1/ApplicationTestLibrary/LibraryDimension.Codeunit.al
@@ -0,0 +1,503 @@
+///
+/// Provides utility functions for creating and managing dimensions, dimension values, and dimension sets in test scenarios.
+///
+codeunit 131001 "Library - Dimension"
+{
+
+ EventSubscriberInstance = Manual;
+
+ trigger OnRun()
+ begin
+ end;
+
+ var
+ LibraryUtility: Codeunit "Library - Utility";
+ LibraryERM: Codeunit "Library - ERM";
+ LibraryDim: Codeunit "Library - Dimension";
+ ChangeGlobalDimensions: Codeunit "Change Global Dimensions";
+
+ procedure BlockDimension(var Dimension: Record Dimension)
+ begin
+ Dimension.Validate(Blocked, true);
+ Dimension.Modify(true);
+ end;
+
+ procedure BlockDimensionValue(var DimensionValue: Record "Dimension Value")
+ begin
+ DimensionValue.Validate(Blocked, true);
+ DimensionValue.Modify(true);
+ end;
+
+ procedure InitGlobalDimChange()
+ begin
+ ChangeGlobalDimensions.ResetState();
+ end;
+
+ procedure RunChangeGlobalDimensions(GlobalDimension1Code: Code[20]; GlobalDimension2Code: Code[20])
+ var
+ ChangeGlobalDimHeader: Record "Change Global Dim. Header";
+ begin
+ InitGlobalDimChange();
+ ChangeGlobalDimHeader.Get();
+ ChangeGlobalDimHeader.Validate("Global Dimension 1 Code", GlobalDimension1Code);
+ ChangeGlobalDimHeader.Validate("Global Dimension 2 Code", GlobalDimension2Code);
+ ChangeGlobalDimHeader.Modify();
+ ChangeGlobalDimensions.StartSequential();
+ end;
+
+ procedure RunChangeGlobalDimensionsParallel(GlobalDimension1Code: Code[20]; GlobalDimension2Code: Code[20])
+ var
+ ChangeGlobalDimHeader: Record "Change Global Dim. Header";
+ ChangeGlobalDimLogEntry: Record "Change Global Dim. Log Entry";
+ LibraryDimension: Codeunit "Library - Dimension";
+ begin
+ InitGlobalDimChange();
+ ChangeGlobalDimHeader.Get();
+ ChangeGlobalDimHeader."Parallel Processing" := true;
+ ChangeGlobalDimHeader.Validate("Global Dimension 1 Code", GlobalDimension1Code);
+ ChangeGlobalDimHeader.Validate("Global Dimension 2 Code", GlobalDimension2Code);
+ ChangeGlobalDimHeader.Modify();
+ BindSubscription(LibraryDimension); // to mock taks scheduling and single session
+ ChangeGlobalDimensions.Prepare();
+ ChangeGlobalDimensions.Start();
+ if ChangeGlobalDimensions.FindTablesForScheduling(ChangeGlobalDimLogEntry) then
+ repeat
+ CODEUNIT.Run(CODEUNIT::"Change Global Dimensions", ChangeGlobalDimLogEntry);
+ until ChangeGlobalDimLogEntry.Next() = 0;
+ InitGlobalDimChange();
+ end;
+
+ procedure CreateDimension(var Dimension: Record Dimension)
+ begin
+ Dimension.Init();
+ Dimension.Validate(
+ Code, LibraryUtility.GenerateRandomCode20(Dimension.FieldNo(Code), DATABASE::Dimension));
+ Dimension.Insert(true);
+ end;
+
+ procedure CreateDimensionCombination(var DimensionCombination: Record "Dimension Combination"; Dimension1Code: Code[20]; Dimension2Code: Code[20])
+ begin
+ DimensionCombination.Init();
+ DimensionCombination.Validate("Dimension 1 Code", Dimension1Code);
+ DimensionCombination.Validate("Dimension 2 Code", Dimension2Code);
+ DimensionCombination.Insert(true);
+ end;
+
+ procedure CreateDimensionValue(var DimensionValue: Record "Dimension Value"; DimensionCode: Code[20])
+ begin
+ DimensionValue.Init();
+ DimensionValue.Validate("Dimension Code", DimensionCode);
+ DimensionValue.Validate(
+ Code,
+ CopyStr(
+ LibraryUtility.GenerateRandomCode(DimensionValue.FieldNo(Code), DATABASE::"Dimension Value"),
+ 1,
+ LibraryUtility.GetFieldLength(DATABASE::"Dimension Value", DimensionValue.FieldNo(Code))));
+ DimensionValue.Insert(true);
+ end;
+
+ procedure CreateDimensionValueWithCode(var DimensionValue: Record "Dimension Value"; DimensionValueCode: Code[20]; DimensionCode: Code[20])
+ begin
+ DimensionValue.Init();
+ DimensionValue.Validate("Dimension Code", DimensionCode);
+ DimensionValue.Validate(Code,
+ CopyStr(DimensionValueCode, 1, LibraryUtility.GetFieldLength(DATABASE::"Dimension Value", DimensionValue.FieldNo(Code))));
+ DimensionValue.Insert(true);
+ end;
+
+ procedure CreateDimWithDimValue(var DimensionValue: Record "Dimension Value")
+ var
+ Dimension: Record Dimension;
+ begin
+ CreateDimension(Dimension);
+ CreateDimensionValue(DimensionValue, Dimension.Code);
+ end;
+
+ procedure CreateDimValueCombination(var DimensionValueCombination: Record "Dimension Value Combination"; Dimension1Code: Code[20]; Dimension2Code: Code[20]; Dimension1ValueCode: Code[20]; Dimension2ValueCode: Code[20])
+ begin
+ DimensionValueCombination.Init();
+ DimensionValueCombination.Validate("Dimension 1 Code", Dimension1Code);
+ DimensionValueCombination.Validate("Dimension 1 Value Code", Dimension1ValueCode);
+ DimensionValueCombination.Validate("Dimension 2 Code", Dimension2Code);
+ DimensionValueCombination.Validate("Dimension 2 Value Code", Dimension2ValueCode);
+ DimensionValueCombination.Insert(true);
+ end;
+
+ procedure CreateDefaultDimension(var DefaultDimension: Record "Default Dimension"; TableID: Integer; No: Code[20]; DimensionCode: Code[20]; DimensionValueCode: Code[20])
+ begin
+ DefaultDimension.Init();
+ DefaultDimension.Validate("Table ID", TableID);
+ DefaultDimension.Validate("No.", No);
+ DefaultDimension.Validate("Dimension Code", DimensionCode);
+ DefaultDimension.Validate("Dimension Value Code", DimensionValueCode);
+ DefaultDimension.Insert(true);
+ end;
+
+ procedure CreateDefaultDimensionPriority(var DefaultDimensionPriority: Record "Default Dimension Priority"; SourceCode: Code[10]; TableID: Integer)
+ begin
+ DefaultDimensionPriority.Init();
+ DefaultDimensionPriority.Validate("Source Code", SourceCode);
+ DefaultDimensionPriority.Validate("Table ID", TableID);
+ DefaultDimensionPriority.Insert(true);
+ end;
+
+ procedure CreateICDimension(var ICDimension: Record "IC Dimension")
+ begin
+ ICDimension.Init();
+ ICDimension.Validate(
+ Code,
+ CopyStr(
+ LibraryUtility.GenerateRandomCode(ICDimension.FieldNo(Code), DATABASE::"IC Dimension"), 1,
+ LibraryUtility.GetFieldLength(DATABASE::"IC Dimension", ICDimension.FieldNo(Code))));
+ ICDimension.Insert(true);
+ end;
+
+ procedure CreateICDimensionValue(var ICDimensionValue: Record "IC Dimension Value"; ICDimensionCode: Code[20])
+ begin
+ ICDimensionValue.Init();
+ ICDimensionValue.Validate("Dimension Code", ICDimensionCode);
+ ICDimensionValue.Validate(
+ Code,
+ CopyStr(
+ LibraryUtility.GenerateRandomCode(ICDimensionValue.FieldNo(Code), DATABASE::"IC Dimension Value"), 1,
+ LibraryUtility.GetFieldLength(DATABASE::"IC Dimension Value", ICDimensionValue.FieldNo(Code))));
+ ICDimensionValue.Insert(true);
+ end;
+
+ procedure CreateAndMapICDimFromDim(var ICDimension: Record "IC Dimension"; DimensionCode: Code[20])
+ begin
+ ICDimension.Init();
+ ICDimension.Validate(Code, DimensionCode);
+ ICDimension.Validate("Map-to Dimension Code", DimensionCode);
+ ICDimension.Insert(true);
+ end;
+
+ procedure CreateAndMapICDimValueFromDimValue(var ICDimensionValue: Record "IC Dimension Value"; DimensionValueCode: Code[20]; DimensionCode: Code[20])
+ begin
+ ICDimensionValue.Init();
+ ICDimensionValue.Validate("Dimension Code", DimensionCode);
+ ICDimensionValue.Validate(Code, DimensionValueCode);
+ ICDimensionValue.Validate("Map-to Dimension Code", DimensionCode);
+ ICDimensionValue.Validate("Map-to Dimension Value Code", DimensionValueCode);
+ ICDimensionValue.Insert(true);
+ end;
+
+ procedure CreateServiceContractDimension(var ServiceContractHeader: Record "Service Contract Header"; DimensionCode: Code[20]; DimensionValueCode: Code[20])
+ var
+ DimSetID: Integer;
+ begin
+ DimSetID := CreateDimSet(ServiceContractHeader."Dimension Set ID", DimensionCode, DimensionValueCode);
+ ServiceContractHeader.Validate("Dimension Set ID", DimSetID);
+ ServiceContractHeader.Modify(true);
+ end;
+
+ procedure CreateAccTypeDefaultDimension(var DefaultDimension: Record "Default Dimension"; TableID: Integer; DimensionCode: Code[20]; DimensionValueCode: Code[20]; ValuePosting: Enum "Default Dimension Value Posting Type")
+ begin
+ CreateDefaultDimension(DefaultDimension, TableID, ' ', DimensionCode, DimensionValueCode);
+ DefaultDimension.Validate("Value Posting", ValuePosting);
+ DefaultDimension.Modify(true);
+ end;
+
+ procedure CreateDefaultDimensionCustomer(var DefaultDimension: Record "Default Dimension"; CustomerNo: Code[20]; DimensionCode: Code[20]; DimensionValueCode: Code[20])
+ begin
+ CreateDefaultDimension(DefaultDimension, DATABASE::Customer, CustomerNo, DimensionCode, DimensionValueCode);
+ end;
+
+ procedure CreateDefaultDimensionGLAcc(var DefaultDimension: Record "Default Dimension"; GLAccountNo: Code[20]; DimensionCode: Code[20]; DimensionValueCode: Code[20])
+ begin
+ CreateDefaultDimension(DefaultDimension, DATABASE::"G/L Account", GLAccountNo, DimensionCode, DimensionValueCode);
+ end;
+
+ procedure CreateDefaultDimensionItem(var DefaultDimension: Record "Default Dimension"; ItemNo: Code[20]; DimensionCode: Code[20]; DimensionValueCode: Code[20])
+ begin
+ CreateDefaultDimension(DefaultDimension, DATABASE::Item, ItemNo, DimensionCode, DimensionValueCode);
+ end;
+
+ procedure CreateDefaultDimensionResource(var DefaultDimension: Record "Default Dimension"; ResourceNo: Code[20]; DimensionCode: Code[20]; DimensionValueCode: Code[20])
+ begin
+ CreateDefaultDimension(DefaultDimension, DATABASE::Resource, ResourceNo, DimensionCode, DimensionValueCode);
+ end;
+
+ procedure CreateDefaultDimensionVendor(var DefaultDimension: Record "Default Dimension"; VendorNo: Code[20]; DimensionCode: Code[20]; DimensionValueCode: Code[20])
+ begin
+ CreateDefaultDimension(DefaultDimension, DATABASE::Vendor, VendorNo, DimensionCode, DimensionValueCode);
+ end;
+
+ procedure CreateDefaultDimensionWithNewDimValue(var DefaultDimension: Record "Default Dimension"; TableID: Integer; No: Code[20]; ValuePosting: Enum "Default Dimension Value Posting Type")
+ var
+ DimValue: Record "Dimension Value";
+ begin
+ CreateDimWithDimValue(DimValue);
+ CreateDefaultDimension(DefaultDimension, TableID, No, DimValue."Dimension Code", DimValue.Code);
+ DefaultDimension.Validate("Value Posting", ValuePosting);
+ DefaultDimension.Modify(true);
+ end;
+
+ procedure CreateSelectedDimension(var SelectedDimension: Record "Selected Dimension"; ObjectType: Option; ObjectID: Integer; AnalysisViewCode: Code[10]; DimensionCode: Text[30])
+ begin
+ Clear(SelectedDimension);
+ SelectedDimension."User ID" := CopyStr(UserId(), 1, MaxStrLen(SelectedDimension."User ID"));
+ SelectedDimension.Validate("Object Type", ObjectType);
+ SelectedDimension.Validate("Object ID", ObjectID);
+ SelectedDimension.Validate("Analysis View Code", AnalysisViewCode);
+ SelectedDimension.Validate("Dimension Code", DimensionCode);
+ SelectedDimension.Insert(true);
+ end;
+
+ procedure CreateDimensionsTemplate(var DimensionsTemplate: Record "Dimensions Template"; TemplateCode: Code[10]; TableID: Integer; DimensionCode: Code[20]; DimensionValueCode: Code[20])
+ begin
+ DimensionsTemplate.Init();
+ DimensionsTemplate.Validate(
+ Code,
+ CopyStr(
+ LibraryUtility.GenerateRandomCode(DimensionsTemplate.FieldNo(Code), DATABASE::"Dimensions Template"),
+ 1,
+ LibraryUtility.GetFieldLength(DATABASE::"Dimensions Template", DimensionsTemplate.FieldNo(Code))));
+ DimensionsTemplate.Validate("Master Record Template Code", TemplateCode);
+ DimensionsTemplate.Validate("Dimension Code", DimensionCode);
+ DimensionsTemplate.Validate("Dimension Value Code", DimensionValueCode);
+ DimensionsTemplate.Validate("Table Id", TableID);
+ DimensionsTemplate.SetRange("Master Record Template Code", DimensionsTemplate."Master Record Template Code");
+ DimensionsTemplate.Insert(true);
+ end;
+
+ procedure EditDimSet(DimSetID: Integer; DimCode: Code[20]; DimValCode: Code[20]): Integer
+ var
+ TempDimSetEntry: Record "Dimension Set Entry" temporary;
+ DimVal: Record "Dimension Value";
+ DimMgt: Codeunit DimensionManagement;
+ NewDimSetID: Integer;
+ begin
+ // Edit existing dimension value for the given dimension on document, document line and journal
+ // DimSetID: existing dimension set ID on document, document line and journal
+ // Return new Dimension Set ID.
+
+ DimMgt.GetDimensionSet(TempDimSetEntry, DimSetID);
+
+ DimVal.Get(DimCode, DimValCode);
+ TempDimSetEntry.SetRange("Dimension Code", DimVal."Dimension Code");
+ TempDimSetEntry.FindFirst();
+ TempDimSetEntry.Validate("Dimension Value Code", DimVal.Code);
+ TempDimSetEntry.Validate("Dimension Value ID", DimVal."Dimension Value ID");
+ TempDimSetEntry.Modify(true);
+
+ TempDimSetEntry.Reset();
+ NewDimSetID := DimMgt.GetDimensionSetID(TempDimSetEntry);
+ TempDimSetEntry.DeleteAll();
+ exit(NewDimSetID);
+ end;
+
+ procedure DeleteDimSet(DimSetID: Integer; DimCode: Code[20]): Integer
+ var
+ TempDimSetEntry: Record "Dimension Set Entry" temporary;
+ DimMgt: Codeunit DimensionManagement;
+ NewDimSetID: Integer;
+ begin
+ // Delete existing dimension and dimension value on document, document line and journal
+ // DimSetID: existing dimension set ID on document, document line and journal
+ // Return new Dimension Set ID.
+
+ DimMgt.GetDimensionSet(TempDimSetEntry, DimSetID);
+
+ TempDimSetEntry.SetRange("Dimension Code", DimCode);
+ TempDimSetEntry.FindFirst();
+ TempDimSetEntry.Delete(true);
+
+ TempDimSetEntry.Reset();
+ NewDimSetID := DimMgt.GetDimensionSetID(TempDimSetEntry);
+ TempDimSetEntry.DeleteAll();
+ exit(NewDimSetID);
+ end;
+
+ procedure CreateDimSet(DimSetID: Integer; DimCode: Code[20]; DimValCode: Code[20]): Integer
+ var
+ TempDimSetEntry: Record "Dimension Set Entry" temporary;
+ DimVal: Record "Dimension Value";
+ DimMgt: Codeunit DimensionManagement;
+ NewDimSetID: Integer;
+ begin
+ // Insert new dimension and dimension value on document, document line and journal
+ // DimSetID: existing dimension set ID on document, document line and journal
+ // Return new Dimension Set ID.
+
+ DimMgt.GetDimensionSet(TempDimSetEntry, DimSetID);
+ DimVal.Get(DimCode, DimValCode);
+
+ TempDimSetEntry.Validate("Dimension Code", DimVal."Dimension Code");
+ TempDimSetEntry.Validate("Dimension Value Code", DimValCode);
+ TempDimSetEntry.Validate("Dimension Value ID", DimVal."Dimension Value ID");
+ TempDimSetEntry.Insert(true);
+
+ NewDimSetID := DimMgt.GetDimensionSetID(TempDimSetEntry);
+ TempDimSetEntry.DeleteAll();
+ exit(NewDimSetID);
+ end;
+
+ procedure FindDefaultDimension(var DefaultDimension: Record "Default Dimension"; TableID: Integer; No: Code[20]): Boolean
+ begin
+ DefaultDimension.SetRange("Table ID", TableID);
+ DefaultDimension.SetRange("No.", No);
+ exit(DefaultDimension.FindSet());
+ end;
+
+ procedure FindDimension(var Dimension: Record Dimension)
+ begin
+ Dimension.SetRange(Blocked, false);
+ Dimension.FindSet();
+ end;
+
+ procedure FindDimensionValue(var DimensionValue: Record "Dimension Value"; DimensionCode: Code[20])
+ begin
+ DimensionValue.SetRange("Dimension Code", DimensionCode);
+ DimensionValue.SetRange(Blocked, false);
+ DimensionValue.SetRange("Dimension Value Type", DimensionValue."Dimension Value Type"::Standard);
+ DimensionValue.FindSet();
+ end;
+
+ procedure FindDifferentDimensionValue(DimensionCode: Code[20]; DimensionValueCode: Code[20]): Code[20]
+ var
+ DimensionValue: Record "Dimension Value";
+ begin
+ DimensionValue.SetFilter(Code, '<>%1', DimensionValueCode);
+ FindDimensionValue(DimensionValue, DimensionCode);
+ exit(DimensionValue.Code);
+ end;
+
+ procedure FindDimensionSetEntry(var DimensionSetEntry: Record "Dimension Set Entry"; DimensionSetID: Integer)
+ begin
+ DimensionSetEntry.SetRange("Dimension Set ID", DimensionSetID);
+ DimensionSetEntry.FindSet();
+ end;
+
+ procedure GetNextDimensionValue(var DimensionValue: Record "Dimension Value")
+ begin
+ DimensionValue.Next();
+ end;
+
+ [Scope('OnPrem')]
+ procedure GetLocalTablesWithDimSetIDValidationIgnored(var CountOfTablesIgnored: Integer)
+ begin
+ OnGetLocalTablesWithDimSetIDValidationIgnored(CountOfTablesIgnored);
+ end;
+
+ procedure ResetDefaultDimensions(TableID: Integer; No: Code[20])
+ var
+ DefaultDimension: Record "Default Dimension";
+ begin
+ DefaultDimension.SetRange("Table ID", TableID);
+ DefaultDimension.SetRange("No.", No);
+ DefaultDimension.DeleteAll();
+ end;
+
+ procedure GetGlobalDimCodeValue(DimNo: Integer; var DimValue: Record "Dimension Value")
+ var
+ Dimension: Record Dimension;
+ begin
+ if LibraryERM.GetGlobalDimensionCode(DimNo) = '' then begin
+ LibraryDim.CreateDimension(Dimension);
+ LibraryERM.SetGlobalDimensionCode(DimNo, Dimension.Code);
+ LibraryDim.CreateDimensionValue(DimValue, Dimension.Code);
+ end else begin
+ DimValue.SetRange("Dimension Code", LibraryERM.GetGlobalDimensionCode(DimNo));
+ DimValue.SetRange("Dimension Value Type", DimValue."Dimension Value Type"::Standard);
+ DimValue.SetRange(Blocked, false);
+ DimValue.FindFirst();
+ end;
+ end;
+
+ procedure VerifyShorcutDimCodesUpdatedOnDimSetIDValidation(var TempAllObj: Record AllObj temporary; "Record": Variant; DimSetIDFieldID: Integer; ShortcutDimCode1FieldID: Integer; ShortcutDimCode2FieldID: Integer; DimSetID: Integer; ExpectedShortcutDimCode1: Code[20]; ExpectedShortcutDimCode2: Code[20])
+ var
+ RecRef: RecordRef;
+ DimSetIDFieldRef: FieldRef;
+ ShortcutDim1CodeFieldRef: FieldRef;
+ ShortcutDim2CodeFieldRef: FieldRef;
+ begin
+ RecRef.GetTable(Record);
+
+ TempAllObj."Object Type" := TempAllObj."Object Type"::Table;
+ TempAllObj."Object ID" := RecRef.Number;
+ TempAllObj.Insert();
+
+ DimSetIDFieldRef := RecRef.Field(DimSetIDFieldID);
+ DimSetIDFieldRef.Validate(DimSetID);
+
+ ShortcutDim1CodeFieldRef := RecRef.Field(ShortcutDimCode1FieldID);
+ ShortcutDim1CodeFieldRef.TestField(ExpectedShortcutDimCode1);
+ ShortcutDim2CodeFieldRef := RecRef.Field(ShortcutDimCode2FieldID);
+ ShortcutDim2CodeFieldRef.TestField(ExpectedShortcutDimCode2);
+ end;
+
+ [Scope('OnPrem')]
+ procedure VerifyShorcutDimCodesUpdatedOnDimSetIDValidationLocal(var TempAllObj: Record AllObj temporary; DimSetID: Integer; GlobalDim1ValueCode: Code[20]; GlobalDim2ValueCode: Code[20])
+ begin
+ OnVerifyShorcutDimCodesUpdatedOnDimSetIDValidationLocal(TempAllObj, DimSetID, GlobalDim1ValueCode, GlobalDim2ValueCode);
+ end;
+
+ [Scope('OnPrem')]
+ procedure GetTableNosWithGlobalDimensionCode(var TableBuffer: Record "Integer" temporary)
+ begin
+ AddTable(TableBuffer, DATABASE::"Salesperson/Purchaser");
+ AddTable(TableBuffer, DATABASE::"G/L Account");
+ AddTable(TableBuffer, DATABASE::Customer);
+ AddTable(TableBuffer, DATABASE::Vendor);
+ AddTable(TableBuffer, DATABASE::Item);
+ AddTable(TableBuffer, DATABASE::"Resource Group");
+ AddTable(TableBuffer, DATABASE::Resource);
+ AddTable(TableBuffer, DATABASE::Job);
+ AddTable(TableBuffer, DATABASE::"Bank Account");
+ AddTable(TableBuffer, DATABASE::"Cash Flow Manual Revenue");
+ AddTable(TableBuffer, DATABASE::"Cash Flow Manual Expense");
+ AddTable(TableBuffer, DATABASE::Campaign);
+ AddTable(TableBuffer, DATABASE::Employee);
+ AddTable(TableBuffer, DATABASE::"Fixed Asset");
+ AddTable(TableBuffer, DATABASE::Insurance);
+ AddTable(TableBuffer, DATABASE::"Responsibility Center");
+ AddTable(TableBuffer, DATABASE::"Item Charge");
+
+ OnGetTableNosWithGlobalDimensionCode(TableBuffer);
+ end;
+
+ procedure ChunkDimSetFilters(var TempDimensionSetEntry: Record "Dimension Set Entry" temporary): List of [Text]
+ var
+ DimensionManagement: Codeunit DimensionManagement;
+ begin
+ exit(DimensionManagement.ChunkDimSetFilters(TempDimensionSetEntry));
+ end;
+
+ procedure AddTable(var TableBuffer: Record "Integer" temporary; TableID: Integer)
+ begin
+ if not TableBuffer.Get(TableID) then begin
+ TableBuffer.Number := TableID;
+ TableBuffer.Insert();
+ end;
+ end;
+
+ [EventSubscriber(ObjectType::Codeunit, Codeunit::"Change Global Dimensions", 'OnBeforeScheduleTask', '', false, false)]
+ local procedure OnBeforeScheduleTask(TableNo: Integer; var DoNotScheduleTask: Boolean; var TaskID: Guid)
+ begin
+ DoNotScheduleTask := true;
+ TaskID := CreateGuid();
+ end;
+
+ [EventSubscriber(ObjectType::Codeunit, Codeunit::"Change Global Dimensions", 'OnCountingActiveSessions', '', false, false)]
+ local procedure OnCountingActiveSessionsHandler(var IsCurrSessionActiveOnly: Boolean)
+ begin
+ IsCurrSessionActiveOnly := true;
+ end;
+
+ [IntegrationEvent(false, false)]
+ local procedure OnGetLocalTablesWithDimSetIDValidationIgnored(var CountOfTablesIgnored: Integer)
+ begin
+ end;
+
+ [IntegrationEvent(false, false)]
+ local procedure OnVerifyShorcutDimCodesUpdatedOnDimSetIDValidationLocal(var TempAllObj: Record AllObj temporary; DimSetID: Integer; GlobalDim1ValueCode: Code[20]; GlobalDim2ValueCode: Code[20])
+ begin
+ end;
+
+ [IntegrationEvent(true, false)]
+ local procedure OnGetTableNosWithGlobalDimensionCode(var TableBuffer: Record "Integer" temporary)
+ begin
+ end;
+}
+
diff --git a/Apps/W1/ApplicationTestLibrary/LibraryERM.Codeunit.al b/Apps/W1/ApplicationTestLibrary/LibraryERM.Codeunit.al
new file mode 100644
index 0000000000..fa616b0b5b
--- /dev/null
+++ b/Apps/W1/ApplicationTestLibrary/LibraryERM.Codeunit.al
@@ -0,0 +1,3124 @@
+///
+/// Provides utility functions for Enterprise Resource Management (ERM) test scenarios, including general ledger, journal processing, and financial posting operations.
+///
+codeunit 131300 "Library - ERM"
+{
+
+ Permissions = TableData Currency = rimd,
+ TableData "Cust. Ledger Entry" = rimd,
+ TableData "Vendor Ledger Entry" = rimd,
+ TableData "Gen. Journal Template" = rimd,
+ TableData "VAT Posting Setup" = rimd;
+
+ trigger OnRun()
+ begin
+ end;
+
+ var
+ GeneralLedgerSetup: Record "General Ledger Setup";
+ LibraryUtility: Codeunit "Library - Utility";
+ LibraryERMUnapply: Codeunit "Library - ERM Unapply";
+ LibraryRandom: Codeunit "Library - Random";
+ LibraryJournals: Codeunit "Library - Journals";
+ SearchPostingType: Option All,Sales,Purchase;
+
+ procedure ApplicationAmountRounding(ApplicationAmount: Decimal; CurrencyCode: Code[10]): Decimal
+ var
+ Currency: Record Currency;
+ begin
+ // Round Application Entry Amount.
+ Currency.Initialize(CurrencyCode);
+
+ // Case of Appln. Rounding Precision is equals to zero, use Amount Rounding Precision.
+ if Currency."Appln. Rounding Precision" = 0 then
+ Currency."Appln. Rounding Precision" := Currency."Amount Rounding Precision";
+
+ exit(Round(ApplicationAmount, Currency."Appln. Rounding Precision", Currency.InvoiceRoundingDirection()));
+ end;
+
+ procedure ApplyCustomerLedgerEntries(ApplyingDocumentType: Enum "Gen. Journal Document Type"; DocumentType: Enum "Gen. Journal Document Type"; ApplyingDocumentNo: Code[20]; DocumentNo: Code[20])
+ var
+ ApplyingCustLedgerEntry: Record "Cust. Ledger Entry";
+ CustLedgerEntry: Record "Cust. Ledger Entry";
+ begin
+ FindCustomerLedgerEntry(ApplyingCustLedgerEntry, ApplyingDocumentType, ApplyingDocumentNo);
+ ApplyingCustLedgerEntry.CalcFields("Remaining Amount");
+ SetApplyCustomerEntry(ApplyingCustLedgerEntry, ApplyingCustLedgerEntry."Remaining Amount");
+ FindCustomerLedgerEntry(CustLedgerEntry, DocumentType, DocumentNo);
+ CustLedgerEntry.CalcFields("Remaining Amount");
+ CustLedgerEntry.Validate("Amount to Apply", CustLedgerEntry."Remaining Amount");
+ CustLedgerEntry.Modify(true);
+ SetAppliestoIdCustomer(CustLedgerEntry);
+ PostCustLedgerApplication(ApplyingCustLedgerEntry);
+ end;
+
+ procedure ApplyVendorLedgerEntries(ApplyingDocumentType: Enum "Gen. Journal Document Type"; DocumentType: Enum "Gen. Journal Document Type"; ApplyingDocumentNo: Code[20]; DocumentNo: Code[20])
+ var
+ ApplyingVendorLedgerEntry: Record "Vendor Ledger Entry";
+ VendorLedgerEntry: Record "Vendor Ledger Entry";
+ begin
+ FindVendorLedgerEntry(ApplyingVendorLedgerEntry, ApplyingDocumentType, ApplyingDocumentNo);
+ ApplyingVendorLedgerEntry.CalcFields("Remaining Amount");
+ SetApplyVendorEntry(ApplyingVendorLedgerEntry, ApplyingVendorLedgerEntry."Remaining Amount");
+ FindVendorLedgerEntry(VendorLedgerEntry, DocumentType, DocumentNo);
+ VendorLedgerEntry.CalcFields("Remaining Amount");
+ VendorLedgerEntry.Validate("Amount to Apply");
+ VendorLedgerEntry.Modify(true);
+ SetAppliestoIdVendor(VendorLedgerEntry);
+ PostVendLedgerApplication(ApplyingVendorLedgerEntry);
+ end;
+
+ procedure ClearAdjustPmtDiscInVATSetup()
+ var
+ VATPostingSetup: Record "VAT Posting Setup";
+ begin
+ VATPostingSetup.SetRange("Adjust for Payment Discount", true);
+ if VATPostingSetup.FindSet() then
+ repeat
+ VATPostingSetup.Validate("Adjust for Payment Discount", false);
+ VATPostingSetup.Modify(true);
+ until VATPostingSetup.Next() = 0;
+ end;
+
+ procedure CheckPreview(PaymentJournal: TestPage "Payment Journal"): Text
+ var
+ CheckPreviewPage: TestPage "Check Preview";
+ begin
+ CheckPreviewPage.Trap();
+ PaymentJournal.PreviewCheck.Invoke();
+ exit(CheckPreviewPage.AmountText.Value);
+ end;
+
+ procedure ClearGenJournalLines(GenJournalBatch: Record "Gen. Journal Batch")
+ var
+ GenJournalLine: Record "Gen. Journal Line";
+ begin
+ GenJournalLine.SetRange("Journal Template Name", GenJournalBatch."Journal Template Name");
+ GenJournalLine.SetRange("Journal Batch Name", GenJournalBatch.Name);
+ GenJournalLine.DeleteAll(true);
+ end;
+
+ procedure ConvertCurrency(Amount: Decimal; FromCur: Code[10]; ToCur: Code[10]; ConversionDate: Date) NewAmount: Decimal
+ var
+ CurrencyExchangeRate: Record "Currency Exchange Rate";
+ CurrencyExchangeRate2: Record "Currency Exchange Rate";
+ begin
+ // Converts an Amount from one currency to another.
+ // A blank currency code means LCY.
+ NewAmount := Amount;
+
+ // Convert to LCY.
+ if FromCur <> '' then begin
+ FindExchRate(CurrencyExchangeRate, FromCur, ConversionDate);
+ NewAmount := NewAmount * CurrencyExchangeRate."Relational Exch. Rate Amount" / CurrencyExchangeRate."Exchange Rate Amount";
+ end;
+
+ // Convert into new currency.
+ if ToCur <> '' then begin
+ FindExchRate(CurrencyExchangeRate2, ToCur, ConversionDate);
+ NewAmount := NewAmount * CurrencyExchangeRate2."Exchange Rate Amount" / CurrencyExchangeRate2."Relational Exch. Rate Amount";
+ end;
+ end;
+
+ procedure CreateAnalysisColumn(var AnalysisColumn: Record "Analysis Column"; AnalysisArea: Enum "Analysis Area Type"; AnalysisColumnTemplate: Code[10])
+ var
+ RecRef: RecordRef;
+ begin
+ AnalysisColumn.Init();
+ AnalysisColumn.Validate("Analysis Area", AnalysisArea);
+ AnalysisColumn.Validate("Analysis Column Template", AnalysisColumnTemplate);
+ RecRef.GetTable(AnalysisColumn);
+ AnalysisColumn.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, AnalysisColumn.FieldNo("Line No.")));
+ AnalysisColumn.Insert(true);
+ end;
+
+ procedure CreateAnalysisView(var AnalysisView: Record "Analysis View")
+ begin
+ AnalysisView.Init();
+ AnalysisView.Validate(
+ Code,
+ CopyStr(
+ LibraryUtility.GenerateRandomCode(AnalysisView.FieldNo(Code), DATABASE::"Analysis View"),
+ 1,
+ LibraryUtility.GetFieldLength(DATABASE::"Analysis View", AnalysisView.FieldNo(Code))));
+
+ // Validating Name as Code because value is not important.
+ AnalysisView.Validate(Name, AnalysisView.Code);
+ AnalysisView.Insert(true);
+ end;
+
+ procedure CreateAndPostTwoGenJourLinesWithSameBalAccAndDocNo(var GenJournalLine: Record "Gen. Journal Line"; BalAccType: Enum "Gen. Journal Account Type"; BalAccNo: Code[20]; Amount: Decimal): Code[20]
+ var
+ GenJournalTemplate: Record "Gen. Journal Template";
+ GenJournalBatch: Record "Gen. Journal Batch";
+ DocNo: Code[20];
+ begin
+ CreateGenJournalTemplate(GenJournalTemplate);
+ CreateGenJournalBatch(GenJournalBatch, GenJournalTemplate.Name);
+ CreateGeneralJnlLineWithBalAcc(
+ GenJournalLine, GenJournalTemplate.Name, GenJournalBatch.Name, GenJournalLine."Document Type"::Invoice,
+ GenJournalLine."Account Type"::"G/L Account", CreateGLAccountNo(), BalAccType, BalAccNo, Amount);
+ DocNo := GenJournalLine."Document No.";
+ CreateGeneralJnlLineWithBalAcc(
+ GenJournalLine, GenJournalTemplate.Name, GenJournalBatch.Name, GenJournalLine."Document Type"::Payment,
+ GenJournalLine."Account Type"::"G/L Account", CreateGLAccountNo(), BalAccType, BalAccNo, -Amount);
+ GenJournalLine.Validate("Document No.", DocNo);
+ GenJournalLine.Modify(true);
+ PostGeneralJnlLine(GenJournalLine);
+
+ exit(DocNo);
+ end;
+
+ procedure CreateAccScheduleName(var AccScheduleName: Record "Acc. Schedule Name")
+ var
+ FinancialReport: Record "Financial Report";
+ NewAccSchedName: Code[10];
+ begin
+ NewAccSchedName := CopyStr(LibraryUtility.GenerateRandomCode(AccScheduleName.FieldNo(Name), DATABASE::"Acc. Schedule Name"),
+ 1, LibraryUtility.GetFieldLength(DATABASE::"Acc. Schedule Name", AccScheduleName.FieldNo(Name)));
+ AccScheduleName.Init();
+ AccScheduleName.Validate(Name, NewAccSchedName);
+ AccScheduleName.Insert(true);
+ FinancialReport.Init();
+ FinancialReport.Name := NewAccSchedName;
+ FinancialReport."Financial Report Row Group" := NewAccSchedName;
+ FinancialReport.Insert(true);
+ end;
+
+ procedure CreateAccScheduleLine(var AccScheduleLine: Record "Acc. Schedule Line"; ScheduleName: Code[10])
+ var
+ RecRef: RecordRef;
+ begin
+ AccScheduleLine.Init();
+ AccScheduleLine.Validate("Schedule Name", ScheduleName);
+ RecRef.GetTable(AccScheduleLine);
+ AccScheduleLine.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, AccScheduleLine.FieldNo("Line No.")));
+ AccScheduleLine.Insert(true);
+ end;
+
+ procedure CreateAccountMapping(var TextToAccMapping: Record "Text-to-Account Mapping"; MappingText: Text[250])
+ var
+ RecRef: RecordRef;
+ begin
+ TextToAccMapping.Init();
+ RecRef.GetTable(TextToAccMapping);
+ TextToAccMapping.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, TextToAccMapping.FieldNo("Line No.")));
+ TextToAccMapping.Validate("Mapping Text", MappingText);
+ TextToAccMapping.Insert(true);
+ end;
+
+ procedure CreateAccountMappingCustomer(var TextToAccMapping: Record "Text-to-Account Mapping"; MappingText: Text[250]; SourceNo: Code[20])
+ begin
+ CreateAccountMapping(TextToAccMapping, MappingText);
+ TextToAccMapping.Validate("Bal. Source Type", TextToAccMapping."Bal. Source Type"::Customer);
+ TextToAccMapping.Validate("Bal. Source No.", SourceNo);
+ TextToAccMapping.Modify(true);
+ end;
+
+ procedure CreateAccountMappingGLAccount(var TextToAccMapping: Record "Text-to-Account Mapping"; MappingText: Text[250]; CreditNo: Code[20]; DebitNo: Code[20])
+ begin
+ CreateAccountMapping(TextToAccMapping, MappingText);
+ TextToAccMapping.Validate("Bal. Source Type", TextToAccMapping."Bal. Source Type"::"G/L Account");
+ TextToAccMapping.Validate("Debit Acc. No.", DebitNo);
+ TextToAccMapping.Validate("Credit Acc. No.", CreditNo);
+ TextToAccMapping.Modify(true);
+ end;
+
+ procedure CreateAccountMappingVendor(var TextToAccMapping: Record "Text-to-Account Mapping"; MappingText: Text[250]; SourceNo: Code[20])
+ begin
+ CreateAccountMapping(TextToAccMapping, MappingText);
+ TextToAccMapping.Validate("Bal. Source Type", TextToAccMapping."Bal. Source Type"::Vendor);
+ TextToAccMapping.Validate("Bal. Source No.", SourceNo);
+ TextToAccMapping.Modify(true);
+ end;
+
+ procedure CreateBankAccount(var BankAccount: Record "Bank Account")
+ var
+ BankAccountPostingGroup: Record "Bank Account Posting Group";
+ BankContUpdate: Codeunit "BankCont-Update";
+ begin
+ FindBankAccountPostingGroup(BankAccountPostingGroup);
+ BankAccount.Init();
+ BankAccount.Validate("No.", LibraryUtility.GenerateRandomCode(BankAccount.FieldNo("No."), DATABASE::"Bank Account"));
+ BankAccount.Validate(Name, BankAccount."No."); // Validating No. as Name because value is not important.
+ BankAccount.Insert(true);
+ BankAccount.Validate("Bank Acc. Posting Group", BankAccountPostingGroup.Code);
+ BankAccount.Modify(true);
+ BankContUpdate.OnModify(BankAccount);
+ end;
+
+ procedure CreateBankAccount(var BankAccount: Record "Bank Account"; GLAccount: Record "G/L Account")
+ var
+ BankAccountPostingGroup: Record "Bank Account Posting Group";
+ BankContUpdate: Codeunit "BankCont-Update";
+ begin
+ CreateBankAccountPostingGroup(BankAccountPostingGroup, GLAccount);
+ Clear(BankAccount);
+ BankAccount.Validate("No.", LibraryUtility.GenerateRandomCode(BankAccount.FieldNo("No."), DATABASE::"Bank Account"));
+ BankAccount.Validate(Name, BankAccount."No."); // Validating No. as Name because value is not important.
+ BankAccount.Insert(true);
+ BankAccount.Validate("Bank Acc. Posting Group", BankAccountPostingGroup.Code);
+ BankAccount.IBAN := LibraryUtility.GenerateRandomCode(BankAccount.FieldNo(IBAN), DATABASE::"Bank Account"); // Bypass CheckIBAN fired in OnValidate Trigger.
+ BankAccount.Modify(true);
+ BankContUpdate.OnModify(BankAccount);
+ end;
+
+ procedure CreateBankAccountNo(): Code[20]
+ var
+ BankAccount: Record "Bank Account";
+ begin
+ CreateBankAccount(BankAccount);
+ exit(BankAccount."No.");
+ end;
+
+ procedure CreateBankAccountNoWithNewPostingGroup(GLAccount: Record "G/L Account"): Code[20]
+ var
+ BankAccount: Record "Bank Account";
+ begin
+ CreateBankAccount(BankAccount, GLAccount);
+ exit(BankAccount."No.");
+ end;
+
+ procedure CreateBankAccReconciliation(var BankAccReconciliation: Record "Bank Acc. Reconciliation"; BankAccountNo: Code[20]; StatementType: Enum "Bank Acc. Rec. Stmt. Type")
+ begin
+ BankAccReconciliation.Init();
+ BankAccReconciliation.Validate("Statement Type", StatementType);
+ BankAccReconciliation.Validate("Bank Account No.", BankAccountNo);
+ BankAccReconciliation.Insert(true);
+ BankAccReconciliation.TestField("Statement No.");
+ end;
+
+ procedure CreateBankAccReconciliationLn(var BankAccReconciliationLine: Record "Bank Acc. Reconciliation Line"; BankAccReconciliation: Record "Bank Acc. Reconciliation")
+ var
+ RecRef: RecordRef;
+ begin
+ BankAccReconciliationLine.Init();
+ BankAccReconciliationLine.Validate("Bank Account No.", BankAccReconciliation."Bank Account No.");
+ BankAccReconciliationLine.Validate("Statement No.", BankAccReconciliation."Statement No.");
+ BankAccReconciliationLine.Validate("Statement Type", BankAccReconciliation."Statement Type");
+ RecRef.GetTable(BankAccReconciliationLine);
+ BankAccReconciliationLine.Validate(
+ "Statement Line No.", LibraryUtility.GetNewLineNo(RecRef, BankAccReconciliationLine.FieldNo("Statement Line No.")));
+ BankAccReconciliationLine."Transaction Date" := BankAccReconciliation."Statement Date";
+ BankAccReconciliationLine.Insert(true);
+ end;
+
+ procedure CreateBankAccountPostingGroup(var BankAccountPostingGroup: Record "Bank Account Posting Group")
+ begin
+ BankAccountPostingGroup.Init();
+ BankAccountPostingGroup.Validate(
+ Code,
+ CopyStr(LibraryUtility.GenerateRandomCode(BankAccountPostingGroup.FieldNo(Code), DATABASE::"Bank Account Posting Group"),
+ 1, LibraryUtility.GetFieldLength(DATABASE::"Bank Account Posting Group", BankAccountPostingGroup.FieldNo(Code))));
+ BankAccountPostingGroup.Insert(true);
+ end;
+
+ procedure CreateBankAccountPostingGroup(var BankAccountPostingGroup: Record "Bank Account Posting Group"; GLAccount: Record "G/L Account")
+ begin
+ Clear(BankAccountPostingGroup);
+ BankAccountPostingGroup.Validate(
+ Code,
+ CopyStr(LibraryUtility.GenerateRandomCode(BankAccountPostingGroup.FieldNo(Code), DATABASE::"Bank Account Posting Group"),
+ 1, LibraryUtility.GetFieldLength(DATABASE::"Bank Account Posting Group", BankAccountPostingGroup.FieldNo(Code))));
+ BankAccountPostingGroup.Validate("G/L Account No.", GLAccount."No.");
+ BankAccountPostingGroup.Insert(true);
+ end;
+
+ procedure CreateBusinessUnit(var BusinessUnit: Record "Business Unit")
+ begin
+ BusinessUnit.Init();
+ BusinessUnit.Validate(Code, LibraryUtility.GenerateRandomCode(BusinessUnit.FieldNo(Code), DATABASE::"Business Unit"));
+ BusinessUnit.Insert(true);
+ end;
+
+ procedure CreateChangeLogField(var ChangeLogSetupField: Record "Change Log Setup (Field)"; TableNo: Integer; FieldNo: Integer)
+ begin
+ ChangeLogSetupField.Init();
+ ChangeLogSetupField.Validate("Table No.", TableNo);
+ ChangeLogSetupField.Validate("Field No.", FieldNo);
+ ChangeLogSetupField.Insert(true);
+ end;
+
+ procedure CreateChangeLogTable(var ChangeLogSetupTable: Record "Change Log Setup (Table)"; TableNo: Integer)
+ begin
+ ChangeLogSetupTable.Init();
+ ChangeLogSetupTable.Validate("Table No.", TableNo);
+ ChangeLogSetupTable.Insert(true);
+ end;
+
+ procedure CreateColumnLayout(var ColumnLayout: Record "Column Layout"; ColumnLayoutName: Code[10])
+ var
+ RecRef: RecordRef;
+ begin
+ ColumnLayout.Init();
+ ColumnLayout.Validate("Column Layout Name", ColumnLayoutName);
+ RecRef.GetTable(ColumnLayout);
+ ColumnLayout.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, ColumnLayout.FieldNo("Line No.")));
+ ColumnLayout.Insert(true);
+ end;
+
+ procedure CreateColumnLayoutName(var ColumnLayoutName: Record "Column Layout Name")
+ begin
+ ColumnLayoutName.Init();
+ ColumnLayoutName.Validate(
+ Name,
+ CopyStr(LibraryUtility.GenerateRandomCode(ColumnLayoutName.FieldNo(Name), DATABASE::"Column Layout Name"),
+ 1, LibraryUtility.GetFieldLength(DATABASE::"Column Layout Name", ColumnLayoutName.FieldNo(Name))));
+ ColumnLayoutName.Insert(true);
+ end;
+
+ procedure CreateCountryRegion(var CountryRegion: Record "Country/Region")
+ begin
+ CountryRegion.Init();
+ CountryRegion.Validate(
+ Code,
+ CopyStr(LibraryUtility.GenerateRandomCode(CountryRegion.FieldNo(Code), DATABASE::"Country/Region"),
+ 1, LibraryUtility.GetFieldLength(DATABASE::"Country/Region", CountryRegion.FieldNo(Code))));
+ CountryRegion.Insert(true);
+ end;
+
+ procedure CreateCountryRegion(): Code[10]
+ var
+ CountryRegion: Record "Country/Region";
+ begin
+ CreateCountryRegion(CountryRegion);
+ exit(CountryRegion.Code);
+ end;
+
+ procedure CreateCountryRegionTranslation(CountryRegionCode: Code[10]; var CountryRegionTranslation: Record "Country/Region Translation")
+ var
+ LanguageCode: Code[10];
+ NameTranslation: Text[50];
+ begin
+ LanguageCode := GetAnyLanguageDifferentFromCurrent();
+ NameTranslation := CopyStr(LibraryRandom.RandText(MaxStrLen(NameTranslation)), 1, MaxStrLen(NameTranslation));
+ CreateCountryRegionTranslation(CountryRegionCode, LanguageCode, NameTranslation, CountryRegionTranslation);
+ end;
+
+ procedure CreateCountryRegionTranslation(CountryRegionCode: Code[10]; LanguageCode: Code[10]; NameTranslation: Text[50]; var CountryRegionTranslation: Record "Country/Region Translation")
+ begin
+ CountryRegionTranslation.Init();
+ CountryRegionTranslation.Validate("Country/Region Code", CountryRegionCode);
+ CountryRegionTranslation.Validate("Language Code", LanguageCode);
+ CountryRegionTranslation.Validate(Name, NameTranslation);
+ CountryRegionTranslation.Insert(true);
+ end;
+
+ procedure CreateTerritory(var Territory: Record Territory)
+ begin
+ Territory.Init();
+ Territory.Validate(
+ Code,
+ CopyStr(LibraryUtility.GenerateRandomCode(Territory.FieldNo(Code), DATABASE::Territory),
+ 1, LibraryUtility.GetFieldLength(DATABASE::Territory, Territory.FieldNo(Code))));
+ Territory.Insert(true);
+ end;
+
+ procedure CreateCurrency(var Currency: Record Currency)
+ begin
+ Currency.Init();
+ Currency.Validate(Code, LibraryUtility.GenerateRandomCode(Currency.FieldNo(Code), DATABASE::Currency));
+ Currency.Insert(true);
+ end;
+
+ procedure CreateCurrencyWithRandomExchRates(): Code[10]
+ var
+ CurrencyCode: Code[10];
+ begin
+ CurrencyCode := CreateCurrencyWithGLAccountSetup();
+ CreateRandomExchangeRate(CurrencyCode);
+ exit(CurrencyCode);
+ end;
+
+ procedure CreateCurrencyWithRounding(): Code[10]
+ var
+ Currency: Record Currency;
+ Decimals: Integer;
+ begin
+ Decimals := LibraryRandom.RandInt(5);
+ Currency.Get(
+ CreateCurrencyWithExchangeRate(
+ WorkDate(), LibraryRandom.RandDec(100, Decimals), LibraryRandom.RandDec(100, Decimals)));
+ Currency.Validate("Amount Rounding Precision", LibraryRandom.RandPrecision());
+ Currency.Modify(true);
+ exit(Currency.Code);
+ end;
+
+ procedure CreateCurrencyWithExchangeRate(StartingDate: Date; ExchangeRateAmount: Decimal; AdjustmentExchangeRateAmount: Decimal) CurrencyCode: Code[10]
+ begin
+ CurrencyCode := CreateCurrencyWithGLAccountSetup();
+ CreateExchangeRate(CurrencyCode, StartingDate, ExchangeRateAmount, AdjustmentExchangeRateAmount);
+ exit(CurrencyCode);
+ end;
+
+ procedure CreateCurrencyWithGLAccountSetup(): Code[10]
+ var
+ Currency: Record Currency;
+ begin
+ CreateCurrency(Currency);
+ Currency.Validate("Residual Gains Account", CreateGLAccountNo());
+ Currency.Validate("Residual Losses Account", Currency."Residual Gains Account");
+ Currency.Validate("Realized G/L Gains Account", CreateGLAccountNo());
+ Currency.Validate("Realized G/L Losses Account", Currency."Realized G/L Gains Account");
+ Currency.Validate("Realized Gains Acc.", CreateGLAccountNo());
+ Currency.Validate("Realized Losses Acc.", Currency."Realized Gains Acc.");
+ Currency.Validate("Unrealized Gains Acc.", CreateGLAccountNo());
+ Currency.Validate("Unrealized Losses Acc.", Currency."Unrealized Gains Acc.");
+ Currency.Validate("Conv. LCY Rndg. Debit Acc.", CreateGLAccountNo());
+ Currency.Validate("Conv. LCY Rndg. Credit Acc.", CreateGLAccountNo());
+ Currency.Modify(true);
+ exit(Currency.Code);
+ end;
+
+ procedure CreateCurrencyForReminderLevel(var CurrencyForReminderLevel: Record "Currency for Reminder Level"; ReminderTermsCode: Code[10]; CurrencyCode: Code[10])
+ var
+ RecRef: RecordRef;
+ begin
+ CurrencyForReminderLevel.Init();
+ CurrencyForReminderLevel.Validate("Reminder Terms Code", ReminderTermsCode);
+ RecRef.GetTable(CurrencyForReminderLevel);
+ CurrencyForReminderLevel.Validate("No.", LibraryUtility.GetNewLineNo(RecRef, CurrencyForReminderLevel.FieldNo("No.")));
+ CurrencyForReminderLevel.Validate("Currency Code", CurrencyCode);
+ CurrencyForReminderLevel.Insert(true);
+ end;
+
+ procedure CreateCustomerDiscountGroup(var CustomerDiscountGroup: Record "Customer Discount Group")
+ begin
+ CustomerDiscountGroup.Init();
+ CustomerDiscountGroup.Validate(
+ Code, LibraryUtility.GenerateRandomCode(CustomerDiscountGroup.FieldNo(Code), DATABASE::"Customer Discount Group"));
+ CustomerDiscountGroup.Validate(Description, CustomerDiscountGroup.Code); // Validating Code as Description because value is not important.
+ CustomerDiscountGroup.Insert(true);
+ end;
+
+ procedure CreateItemDiscountGroup(var ItemDiscountGroup: Record "Item Discount Group")
+ begin
+ ItemDiscountGroup.Init();
+ ItemDiscountGroup.Validate(
+ Code, LibraryUtility.GenerateRandomCode(ItemDiscountGroup.FieldNo(Code), DATABASE::"Item Discount Group"));
+ ItemDiscountGroup.Validate(Description, ItemDiscountGroup.Code); // Validating Code as Description because value is not important.
+ ItemDiscountGroup.Insert(true);
+ end;
+
+ procedure CreateDeferralTemplate(var DeferralTemplate: Record "Deferral Template"; CalcMethod: Enum "Deferral Calculation Method"; StartDate: Enum "Deferral Calculation Start Date"; NumOfPeriods: Integer)
+ begin
+ DeferralTemplate.Init();
+ DeferralTemplate."Deferral Code" :=
+ LibraryUtility.GenerateRandomCode(DeferralTemplate.FieldNo("Deferral Code"), DATABASE::"Deferral Template");
+ DeferralTemplate."Deferral Account" := CreateGLAccountNo();
+ DeferralTemplate."Calc. Method" := CalcMethod;
+ DeferralTemplate."Start Date" := StartDate;
+ DeferralTemplate."No. of Periods" := NumOfPeriods;
+ DeferralTemplate."Period Description" := DeferralTemplate."Deferral Code";
+ DeferralTemplate.Insert(true);
+ end;
+
+ procedure CreateDeferralTemplateCode(CalcMethod: Enum "Deferral Calculation Method"; StartDate: Enum "Deferral Calculation Start Date"; NumOfPeriods: Integer): Code[10]
+ var
+ DeferralTemplate: Record "Deferral Template";
+ begin
+ CreateDeferralTemplate(DeferralTemplate, CalcMethod, StartDate, NumOfPeriods);
+ exit(DeferralTemplate."Deferral Code");
+ end;
+
+ procedure CreateFinanceChargeMemoHeader(var FinanceChargeMemoHeader: Record "Finance Charge Memo Header"; CustomerNo: Code[20])
+ begin
+ FinanceChargeMemoHeader.Init();
+ FinanceChargeMemoHeader.Insert(true);
+ FinanceChargeMemoHeader.Validate("Customer No.", CustomerNo);
+ FinanceChargeMemoHeader.Modify(true);
+ end;
+
+ procedure CreateFinanceChargeMemoLine(var FinanceChargeMemoLine: Record "Finance Charge Memo Line"; FinanceChargeMemoHeaderNo: Code[20]; Type: Option)
+ var
+ RecRef: RecordRef;
+ begin
+ FinanceChargeMemoLine.Init();
+ FinanceChargeMemoLine.Validate("Finance Charge Memo No.", FinanceChargeMemoHeaderNo);
+ RecRef.GetTable(FinanceChargeMemoLine);
+ FinanceChargeMemoLine.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, FinanceChargeMemoLine.FieldNo("Line No.")));
+ FinanceChargeMemoLine.Insert(true);
+ FinanceChargeMemoLine.Validate(Type, Type);
+ FinanceChargeMemoLine.Modify(true);
+ end;
+
+ procedure CreateFinanceChargeTerms(var FinanceChargeTerms: Record "Finance Charge Terms")
+ begin
+ FinanceChargeTerms.Init();
+ FinanceChargeTerms.Validate(
+ Code,
+ CopyStr(LibraryUtility.GenerateRandomCode(FinanceChargeTerms.FieldNo(Code), DATABASE::"Finance Charge Terms"),
+ 1,
+ LibraryUtility.GetFieldLength(DATABASE::"Finance Charge Terms", FinanceChargeTerms.FieldNo(Code))));
+ FinanceChargeTerms.Insert(true);
+ end;
+
+ procedure CreateFinanceChargeText(var FinanceChargeText: Record "Finance Charge Text"; FinChargeTermsCode: Code[10]; Position: Option; Text: Text[100])
+ var
+ RecRef: RecordRef;
+ begin
+ FinanceChargeText.Init();
+ FinanceChargeText.Validate("Fin. Charge Terms Code", FinChargeTermsCode);
+ FinanceChargeText.Validate(Position, Position);
+ RecRef.GetTable(FinanceChargeText);
+ FinanceChargeText.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, FinanceChargeText.FieldNo("Line No.")));
+ FinanceChargeText.Insert(true);
+ FinanceChargeText.Validate(Text, Text);
+ FinanceChargeText.Modify(true);
+ end;
+
+ procedure CreateExchRate(var CurrencyExchangeRate: Record "Currency Exchange Rate"; CurrencyCode: Code[10]; StartingDate: Date)
+ begin
+ CurrencyExchangeRate.Init();
+ CurrencyExchangeRate.Validate("Currency Code", CurrencyCode);
+ CurrencyExchangeRate.Validate("Starting Date", StartingDate);
+ CurrencyExchangeRate.Insert(true);
+ end;
+
+ procedure CreateExchangeRate(CurrencyCode: Code[10]; StartingDate: Date; ExchangeRateAmount: Decimal; AdjustmentExchangeRateAmount: Decimal)
+ var
+ CurrencyExchangeRate: Record "Currency Exchange Rate";
+ begin
+ CurrencyExchangeRate.Init();
+ CurrencyExchangeRate.Validate("Currency Code", CurrencyCode);
+ CurrencyExchangeRate.Validate("Starting Date", StartingDate);
+ CurrencyExchangeRate.Insert(true);
+
+ CurrencyExchangeRate.Validate("Exchange Rate Amount", ExchangeRateAmount);
+ CurrencyExchangeRate.Validate("Adjustment Exch. Rate Amount", AdjustmentExchangeRateAmount);
+ CurrencyExchangeRate.Validate("Relational Exch. Rate Amount", 1);
+ CurrencyExchangeRate.Validate("Relational Adjmt Exch Rate Amt", 1);
+ CurrencyExchangeRate.Modify(true);
+ end;
+
+ procedure CreateGenBusPostingGroup(var GenBusinessPostingGroup: Record "Gen. Business Posting Group")
+ begin
+ GenBusinessPostingGroup.Init();
+ GenBusinessPostingGroup.Validate(
+ Code,
+ CopyStr(LibraryUtility.GenerateRandomCode(GenBusinessPostingGroup.FieldNo(Code), DATABASE::"Gen. Business Posting Group"),
+ 1, LibraryUtility.GetFieldLength(DATABASE::"Gen. Business Posting Group", GenBusinessPostingGroup.FieldNo(Code))));
+
+ // Validating Code as Name because value is not important.
+ GenBusinessPostingGroup.Validate(Description, GenBusinessPostingGroup.Code);
+ GenBusinessPostingGroup.Insert(true);
+ end;
+
+ procedure CreateGeneralPostingSetup(var GeneralPostingSetup: Record "General Posting Setup"; GenBusPostingGroup: Code[20]; GenProdPostingGroup: Code[20])
+ begin
+ GeneralPostingSetup.Init();
+ GeneralPostingSetup.Validate("Gen. Bus. Posting Group", GenBusPostingGroup);
+ GeneralPostingSetup.Validate("Gen. Prod. Posting Group", GenProdPostingGroup);
+ GeneralPostingSetup.Insert(true);
+ end;
+
+ procedure CreateGeneralPostingSetupInvt(var GeneralPostingSetup: Record "General Posting Setup")
+ var
+ GenBusinessPostingGroup: Record "Gen. Business Posting Group";
+ GenProductPostingGroup: Record "Gen. Product Posting Group";
+ begin
+ CreateGenBusPostingGroup(GenBusinessPostingGroup);
+ CreateGenProdPostingGroup(GenProductPostingGroup);
+ CreateGeneralPostingSetup(GeneralPostingSetup, GenBusinessPostingGroup.Code, GenProductPostingGroup.Code);
+ GeneralPostingSetup.Validate("Sales Account", CreateGLAccountNo());
+ GeneralPostingSetup.Validate("Purch. Account", CreateGLAccountNo());
+ GeneralPostingSetup.Validate("COGS Account", CreateGLAccountNo());
+ GeneralPostingSetup.Validate("Inventory Adjmt. Account", CreateGLAccountNo());
+ GeneralPostingSetup.Modify(true);
+ end;
+
+ procedure CreateGenProdPostingGroup(var GenProductPostingGroup: Record "Gen. Product Posting Group")
+ begin
+ GenProductPostingGroup.Init();
+ GenProductPostingGroup.Validate(
+ Code,
+ CopyStr(LibraryUtility.GenerateRandomCode(GenProductPostingGroup.FieldNo(Code), DATABASE::"Gen. Product Posting Group"),
+ 1, LibraryUtility.GetFieldLength(DATABASE::"Gen. Product Posting Group", GenProductPostingGroup.FieldNo(Code))));
+
+ // Validating Code as Name because value is not important.
+ GenProductPostingGroup.Validate(Description, GenProductPostingGroup.Code);
+ GenProductPostingGroup.Insert(true);
+ end;
+
+ procedure CreateInsurance(var Insurance: Record Insurance)
+ begin
+ Insurance.Init();
+ Insurance.Insert(true);
+ Insurance.Validate(Description, Insurance."No."); // Validating No as Description because value is not important.
+ Insurance.Modify(true);
+ end;
+
+ procedure CreateRandomExchangeRate(CurrencyCode: Code[10])
+ var
+ CurrencyExchangeRate: Record "Currency Exchange Rate";
+ begin
+ CurrencyExchangeRate.Init();
+ CurrencyExchangeRate.Validate("Currency Code", CurrencyCode);
+ CurrencyExchangeRate.Validate("Starting Date", FindEarliestDateForExhRate());
+ CurrencyExchangeRate.Insert(true);
+
+ // Using RANDOM Exchange Rate Amount and Adjustment Exchange Rate, between 100 and 400 (Standard Value).
+ CurrencyExchangeRate.Validate("Exchange Rate Amount", 100 * LibraryRandom.RandInt(4));
+ CurrencyExchangeRate.Validate("Adjustment Exch. Rate Amount", CurrencyExchangeRate."Exchange Rate Amount");
+
+ // Relational Exch. Rate Amount and Relational Adjmt Exch Rate Amt always greater than Exchange Rate Amount.
+ CurrencyExchangeRate.Validate("Relational Exch. Rate Amount", 2 * CurrencyExchangeRate."Exchange Rate Amount");
+ CurrencyExchangeRate.Validate("Relational Adjmt Exch Rate Amt", CurrencyExchangeRate."Relational Exch. Rate Amount");
+ CurrencyExchangeRate.Modify(true);
+ end;
+
+ procedure CreateGeneralJnlLine(var GenJournalLine: Record "Gen. Journal Line"; JournalTemplateName: Code[10]; JournalBatchName: Code[10]; DocumentType: Enum "Gen. Journal Document Type"; AccountType: Enum "Gen. Journal Account Type"; AccountNo: Code[20]; Amount: Decimal)
+ var
+ GenJournalBatch: Record "Gen. Journal Batch";
+ begin
+ GenJournalBatch.Get(JournalTemplateName, JournalBatchName);
+ CreateGeneralJnlLineWithBalAcc(
+ GenJournalLine, JournalTemplateName, JournalBatchName, DocumentType, AccountType, AccountNo,
+ GenJournalBatch."Bal. Account Type", GenJournalBatch."Bal. Account No.", Amount);
+ end;
+
+ procedure CreateGeneralJnlLineWithBalAcc(var GenJournalLine: Record "Gen. Journal Line"; JournalTemplateName: Code[10]; JournalBatchName: Code[10]; DocumentType: Enum "Gen. Journal Document Type"; AccountType: Enum "Gen. Journal Account Type"; AccountNo: Code[20]; BalAccountType: Enum "Gen. Journal Account Type"; BalAccountNo: Code[20]; Amount: Decimal)
+ begin
+ LibraryJournals.CreateGenJournalLine(GenJournalLine, JournalTemplateName, JournalBatchName, DocumentType, AccountType, AccountNo,
+ BalAccountType, BalAccountNo, Amount);
+ end;
+
+ procedure CreateGeneralJnlLine2(var GenJournalLine: Record "Gen. Journal Line"; JournalTemplateName: Code[10]; JournalBatchName: Code[10]; DocumentType: Enum "Gen. Journal Document Type"; AccountType: Enum "Gen. Journal Account Type"; AccountNo: Code[20]; Amount: Decimal)
+ var
+ GenJournalBatch: Record "Gen. Journal Batch";
+ begin
+ // This function should replace the identical one above, but it requires a lot of changes to existing tests so I'm keeping both for now and will refactor when time permits
+ GenJournalBatch.Get(JournalTemplateName, JournalBatchName);
+ CreateGeneralJnlLine2WithBalAcc(GenJournalLine, JournalTemplateName, JournalBatchName, DocumentType, AccountType, AccountNo,
+ GenJournalBatch."Bal. Account Type", GenJournalBatch."Bal. Account No.", Amount);
+ end;
+
+ procedure CreateGeneralJnlLine2WithBalAcc(var GenJournalLine: Record "Gen. Journal Line"; JournalTemplateName: Code[10]; JournalBatchName: Code[10]; DocumentType: Enum "Gen. Journal Document Type"; AccountType: Enum "Gen. Journal Account Type"; AccountNo: Code[20]; BalAccountType: Enum "Gen. Journal Account Type"; BalAccountNo: Code[20]; Amount: Decimal)
+ begin
+ // This function should replace the identical one above, but it requires a lot of changes to existing tests so I'm keeping both for now and will refactor when time permits
+ LibraryJournals.CreateGenJournalLine2(GenJournalLine, JournalTemplateName, JournalBatchName, DocumentType, AccountType, AccountNo,
+ BalAccountType, BalAccountNo, Amount);
+ end;
+
+ procedure CreateFAJournalLine(var FAJournalLine: Record "FA Journal Line"; JournalTemplateName: Code[10]; JournalBatchName: Code[10]; DocumentType: Enum "Gen. Journal Document Type"; FAPostingType: Enum "Gen. Journal Line FA Posting Type"; FANo: Code[20]; Amount: Decimal)
+ var
+ FAJournalBatch: Record "FA Journal Batch";
+ NoSeries: Record "No. Series";
+ NoSeriesCodeunit: Codeunit "No. Series";
+ RecRef: RecordRef;
+ begin
+ // Find a balanced template/batch pair.
+ FAJournalBatch.Get(JournalTemplateName, JournalBatchName);
+
+ // Create a General Journal Entry.
+ FAJournalLine.Init();
+ FAJournalLine.Validate("Journal Template Name", JournalTemplateName);
+ FAJournalLine.Validate("Journal Batch Name", JournalBatchName);
+ RecRef.GetTable(FAJournalLine);
+ FAJournalLine.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, FAJournalLine.FieldNo("Line No.")));
+ FAJournalLine.Insert(true);
+ FAJournalLine.Validate("Posting Date", WorkDate()); // Defaults to work date.
+ FAJournalLine.Validate("Document Type", DocumentType);
+ FAJournalLine.Validate("FA No.", FANo);
+ FAJournalLine.Validate("FA Posting Type", FAPostingType);
+ FAJournalLine.Validate("FA Posting Date", WorkDate());
+ FAJournalLine.Validate(Amount, Amount);
+ if NoSeries.Get(FAJournalBatch."No. Series") then
+ FAJournalLine.Validate(
+ "Document No.", NoSeriesCodeunit.PeekNextNo(FAJournalBatch."No. Series")); // Unused but required field for posting.
+ FAJournalLine.Validate("External Document No.", FAJournalLine."Document No."); // Unused but required for vendor posting.
+ FAJournalLine.Modify(true);
+ end;
+
+ procedure CreateGLAccount(var GLAccount: Record "G/L Account")
+ begin
+ GLAccount.Init();
+ // Prefix a number to fix errors for local build.
+ GLAccount.Validate(
+ "No.",
+ PadStr(
+ '1' + LibraryUtility.GenerateRandomCode(GLAccount.FieldNo("No."), DATABASE::"G/L Account"), MaxStrLen(GLAccount."No."), '0'));
+ GLAccount.Validate(Name, GLAccount."No."); // Enter No. as Name because value is not important.
+ GLAccount.Insert(true);
+ end;
+
+ procedure CreateGLAccountNo(): Code[20]
+ var
+ GLAccount: Record "G/L Account";
+ begin
+ CreateGLAccount(GLAccount);
+ exit(GLAccount."No.");
+ end;
+
+ procedure CreateGLAccountNoWithDirectPosting(): Code[20]
+ var
+ GLAccount: Record "G/L Account";
+ begin
+ CreateGLAccount(GLAccount);
+ GLAccount.Validate("Direct Posting", true);
+ GLAccount.Modify();
+ exit(GLAccount."No.");
+ end;
+
+ procedure CreateGLAccountWithSalesSetup(): Code[20]
+ var
+ GLAccount: Record "G/L Account";
+ VATPostingSetup: Record "VAT Posting Setup";
+ begin
+ FindVATPostingSetup(VATPostingSetup, VATPostingSetup."VAT Calculation Type"::"Normal VAT");
+ exit(CreateGLAccountWithVATPostingSetup(VATPostingSetup, GLAccount."Gen. Posting Type"::Sale));
+ end;
+
+ procedure CreateGLAccountWithPurchSetup(): Code[20]
+ var
+ GLAccount: Record "G/L Account";
+ VATPostingSetup: Record "VAT Posting Setup";
+ begin
+ FindVATPostingSetup(VATPostingSetup, VATPostingSetup."VAT Calculation Type"::"Normal VAT");
+ exit(CreateGLAccountWithVATPostingSetup(VATPostingSetup, GLAccount."Gen. Posting Type"::Purchase));
+ end;
+
+ procedure CreateGLAccountWithVATPostingSetup(var VATPostingSetup: Record "VAT Posting Setup"; GenPostingType: Enum "General Posting Type"): Code[20]
+ var
+ GLAccount: Record "G/L Account";
+ GeneralPostingSetup: Record "General Posting Setup";
+ begin
+ FindGeneralPostingSetup(GeneralPostingSetup);
+ CreateGLAccount(GLAccount);
+ GLAccount.Validate("Account Type", GLAccount."Account Type"::Posting);
+ UpdateGLAccountWithPostingSetup(GLAccount, GenPostingType, GeneralPostingSetup, VATPostingSetup);
+ exit(GLAccount."No.");
+ end;
+
+ procedure CreateGLAccountCategory(var GLAccountCategory: Record "G/L Account Category")
+ begin
+ GLAccountCategory.Init();
+ GLAccountCategory."Entry No." := 0;
+ GLAccountCategory."System Generated" := false;
+ GLAccountCategory.Validate("Account Category", LibraryRandom.RandIntInRange(1, 7));
+ GLAccountCategory.Validate("Additional Report Definition", LibraryRandom.RandIntInRange(1, 7));
+ GLAccountCategory.Validate(Description, LibraryUtility.GenerateRandomText(MaxStrLen(GLAccountCategory.Description)));
+ GLAccountCategory.Insert();
+ end;
+
+ procedure CreateGLBudgetEntry(var GLBudgetEntry2: Record "G/L Budget Entry"; BudgetDate: Date; GLAccountNo: Code[20]; BudgetName: Code[10])
+ var
+ GLBudgetEntry: Record "G/L Budget Entry";
+ begin
+ if GLBudgetEntry.FindLast() then;
+ GLBudgetEntry2.Init();
+ GLBudgetEntry2.Validate("Entry No.", GLBudgetEntry."Entry No." + 1);
+ GLBudgetEntry2.Validate("Budget Name", BudgetName);
+ GLBudgetEntry2.Validate("G/L Account No.", GLAccountNo);
+ GLBudgetEntry2.Validate(Date, BudgetDate);
+ GLBudgetEntry2.Insert(true);
+ end;
+
+ procedure CreateGLBudgetName(var GLBudgetName: Record "G/L Budget Name")
+ begin
+ GLBudgetName.Init();
+ GLBudgetName.Validate(Name, LibraryUtility.GenerateRandomCode(GLBudgetName.FieldNo(Name), DATABASE::"G/L Budget Name"));
+ GLBudgetName.Validate(Description, GLBudgetName.Name);
+ GLBudgetName.Insert(true);
+ end;
+
+ procedure CreateGenJnlAllocation(var GenJnlAllocation: Record "Gen. Jnl. Allocation"; JournalTemplateName: Code[10]; JournalBatchName: Code[10]; LineNo: Integer)
+ var
+ RecRef: RecordRef;
+ begin
+ GenJnlAllocation.Init();
+ GenJnlAllocation.Validate("Journal Template Name", JournalTemplateName);
+ GenJnlAllocation.Validate("Journal Batch Name", JournalBatchName);
+ GenJnlAllocation.Validate("Journal Line No.", LineNo);
+ RecRef.GetTable(GenJnlAllocation);
+ GenJnlAllocation.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, GenJnlAllocation.FieldNo("Line No.")));
+ GenJnlAllocation.Insert(true);
+ end;
+
+ procedure CreateGenJournalBatch(var GenJournalBatch: Record "Gen. Journal Batch"; JournalTemplateName: Code[10])
+ begin
+ // creates a new Gen. Journal Batch named with the next available number (if it does not yet exist), OR
+ // returns the Gen. Journal batch named with the next available number
+ // calling ConvertNumericToText to avoid auto-removal of the batch during posting by COD13
+ GenJournalBatch.Init();
+ GenJournalBatch.Validate("Journal Template Name", JournalTemplateName);
+ GenJournalBatch.Validate(
+ Name,
+ LibraryUtility.ConvertNumericToText(
+ CopyStr(
+ LibraryUtility.GenerateRandomCode(GenJournalBatch.FieldNo(Name), DATABASE::"Gen. Journal Batch"),
+ 1,
+ LibraryUtility.GetFieldLength(DATABASE::"Gen. Journal Batch", GenJournalBatch.FieldNo(Name)))));
+ GenJournalBatch.Validate(Description, GenJournalBatch.Name); // Validating Name as Description because value is not important.
+ if GenJournalBatch.Insert(true) then;
+ end;
+
+ procedure CreateGenJournalTemplate(var GenJournalTemplate: Record "Gen. Journal Template")
+ begin
+ GenJournalTemplate.Init();
+ GenJournalTemplate.Validate(
+ Name,
+ CopyStr(
+ LibraryUtility.GenerateRandomCode(GenJournalTemplate.FieldNo(Name), DATABASE::"Gen. Journal Template"),
+ 1,
+ LibraryUtility.GetFieldLength(DATABASE::"Gen. Journal Template", GenJournalTemplate.FieldNo(Name))));
+ GenJournalTemplate.Validate(Description, GenJournalTemplate.Name);
+ // Validating Name as Description because value is not important.
+ GenJournalTemplate.Insert(true);
+
+ if not GenJournalTemplate."Force Doc. Balance" then begin
+ GenJournalTemplate.Validate("Force Doc. Balance", true); // This field is FALSE by default in ES. Setting this to TRUE to match ES with W1.
+ GenJournalTemplate.Modify(true);
+ end;
+ end;
+
+ procedure CreateICGLAccount(var ICGLAccount: Record "IC G/L Account")
+ begin
+ ICGLAccount.Init();
+ ICGLAccount.Validate(
+ "No.",
+ CopyStr(
+ LibraryUtility.GenerateRandomCode(ICGLAccount.FieldNo("No."), DATABASE::"IC G/L Account"), 1,
+ LibraryUtility.GetFieldLength(DATABASE::"IC G/L Account", ICGLAccount.FieldNo("No."))));
+ ICGLAccount.Validate(Name, ICGLAccount."No."); // Validating No. as Name because value is not important.
+ ICGLAccount.Insert(true);
+ end;
+
+ procedure CreateDimension(var Dimension: Record Dimension)
+ begin
+ Dimension.Init();
+ Dimension.Validate(
+ "Code",
+ CopyStr(
+ LibraryUtility.GenerateRandomCode(Dimension.FieldNo("Code"), DATABASE::Dimension), 1,
+ LibraryUtility.GetFieldLength(DATABASE::Dimension, Dimension.FieldNo("Code"))));
+ Dimension.Validate(Name, Dimension."Code"); // Validating Code as Name because value is not important.
+ Dimension.Insert(true);
+ end;
+
+ procedure CreateDimensionValue(var DimensionValue: Record "Dimension Value")
+ var
+ Dimension: Record Dimension;
+ begin
+ CreateDimension(Dimension);
+ CreateDimensionValue(DimensionValue, Dimension.Code);
+ end;
+
+ procedure CreateDimensionValue(var DimensionValue: Record "Dimension Value"; DimensionCode: Code[20])
+ begin
+ DimensionValue.Init();
+ DimensionValue.Validate(
+ "Code",
+ CopyStr(
+ LibraryUtility.GenerateRandomCode(DimensionValue.FieldNo("Code"), DATABASE::"Dimension Value"), 1,
+ LibraryUtility.GetFieldLength(DATABASE::"Dimension Value", DimensionValue.FieldNo("Code"))));
+ DimensionValue.Validate("Dimension Code", DimensionCode);
+ DimensionValue.Validate(Name, DimensionValue."Code"); // Validating Code as Name because value is not important.
+ DimensionValue.Insert(true);
+ end;
+
+ procedure CreateICDimension(var ICDimension: Record "IC Dimension")
+ begin
+ ICDimension.Init();
+ ICDimension.Validate(
+ "Code",
+ CopyStr(
+ LibraryUtility.GenerateRandomCode(ICDimension.FieldNo("Code"), DATABASE::"IC Dimension"), 1,
+ LibraryUtility.GetFieldLength(DATABASE::"IC Dimension", ICDimension.FieldNo("Code"))));
+ ICDimension.Validate(Name, ICDimension."Code"); // Validating Code as Name because value is not important.
+ ICDimension.Insert(true);
+ end;
+
+ procedure CreateICDimensionValue(var ICDimensionValue: Record "IC Dimension Value")
+ var
+ ICDimension: Record "IC Dimension";
+ begin
+ CreateICDimension(ICDimension);
+ CreateICDimensionValue(ICDimensionValue, ICDimension.Code);
+ end;
+
+ procedure CreateICDimensionValue(var ICDimensionValue: Record "IC Dimension Value"; DimensionCode: Code[20])
+ begin
+ ICDimensionValue.Init();
+ ICDimensionValue.Validate(
+ "Code",
+ CopyStr(
+ LibraryUtility.GenerateRandomCode(ICDimensionValue.FieldNo("Code"), DATABASE::"IC Dimension Value"), 1,
+ LibraryUtility.GetFieldLength(DATABASE::"IC Dimension Value", ICDimensionValue.FieldNo("Code"))));
+ ICDimensionValue.Validate("Dimension Code", DimensionCode);
+ ICDimensionValue.Validate(Name, ICDimensionValue."Code"); // Validating Code as Name because value is not important.
+ ICDimensionValue.Insert(true);
+ end;
+
+ procedure CreateICPartner(var ICPartner: Record "IC Partner")
+ begin
+ ICPartner.Init();
+ ICPartner.Validate(
+ Code,
+ CopyStr(
+ LibraryUtility.GenerateRandomCode(ICPartner.FieldNo(Code), DATABASE::"IC Partner"), 1,
+ LibraryUtility.GetFieldLength(DATABASE::"IC Partner", ICPartner.FieldNo(Code))));
+ ICPartner.Validate(Name, ICPartner.Code); // Validating Name as Code because value is not important.
+ ICPartner."Payables Account" := CreateGLAccountNo();
+ ICPartner."Receivables Account" := CreateGLAccountNo();
+ ICPartner.Insert(true);
+ end;
+
+ procedure CreateICPartnerNo(): Code[20]
+ var
+ ICPartner: Record "IC Partner";
+ begin
+ CreateICPartner(ICPartner);
+ exit(ICPartner.Code);
+ end;
+
+ procedure CreateInvDiscForCustomer(var CustInvoiceDisc: Record "Cust. Invoice Disc."; "Code": Code[20]; CurrencyCode: Code[10]; MinimumAmount: Decimal)
+ begin
+ CustInvoiceDisc.Init();
+ CustInvoiceDisc.Validate(Code, Code);
+ CustInvoiceDisc.Validate("Currency Code", CurrencyCode);
+ CustInvoiceDisc.Validate("Minimum Amount", MinimumAmount);
+ CustInvoiceDisc.Insert(true);
+ end;
+
+ procedure CreateInvDiscForVendor(var VendorInvoiceDisc: Record "Vendor Invoice Disc."; "Code": Code[20]; CurrencyCode: Code[10]; MinimumAmount: Decimal)
+ begin
+ VendorInvoiceDisc.Init();
+ VendorInvoiceDisc.Validate(Code, Code);
+ VendorInvoiceDisc.Validate("Currency Code", CurrencyCode);
+ VendorInvoiceDisc.Validate("Minimum Amount", MinimumAmount);
+ VendorInvoiceDisc.Insert(true);
+ end;
+
+ procedure CreateItemAnalysisView(var ItemAnalysisView: Record "Item Analysis View"; AnalysisArea: Enum "Analysis Area Type")
+ begin
+ ItemAnalysisView.Init();
+ ItemAnalysisView.Validate("Analysis Area", AnalysisArea);
+ ItemAnalysisView.Validate(Code, LibraryUtility.GenerateRandomCode(ItemAnalysisView.FieldNo(Code), DATABASE::"Item Analysis View"));
+ // Validating Name as Code because value is not important.
+ ItemAnalysisView.Validate(Name, ItemAnalysisView.Code);
+ ItemAnalysisView.Insert(true);
+ end;
+
+ procedure GetAnyLanguageDifferentFromCurrent(): Code[10]
+ var
+ Language: Record Language;
+ begin
+ Language.SetFilter("Windows Language ID", '<>%1', GlobalLanguage());
+ Language.SetFilter(Code, 'CSY|DAN|DEU|ESP|FRA|FRC|ENU|ITA|NOR|SVE');
+ Language.FindFirst();
+ Language.Next(LibraryRandom.RandIntInRange(1, Language.Count()));
+ exit(Language.Code);
+ end;
+
+ procedure CreateLineDiscForCustomer(var SalesLineDiscount: Record "Sales Line Discount"; Type: Enum "Sales Line Discount Type"; "Code": Code[20]; SalesType: Option; SalesCode: Code[20]; StartingDate: Date; CurrencyCode: Code[10]; VariantCode: Code[10]; UnitOfMeasureCode: Code[10]; MinimumQuantity: Decimal)
+ begin
+ SalesLineDiscount.Init();
+ SalesLineDiscount.Validate(Type, Type);
+ SalesLineDiscount.Validate(Code, Code);
+ SalesLineDiscount.Validate("Sales Type", SalesType);
+ SalesLineDiscount.Validate("Sales Code", SalesCode);
+ SalesLineDiscount.Validate("Starting Date", StartingDate);
+ SalesLineDiscount.Validate("Currency Code", CurrencyCode);
+ if Type = SalesLineDiscount.Type::Item then begin
+ SalesLineDiscount.Validate("Variant Code", VariantCode);
+ SalesLineDiscount.Validate("Unit of Measure Code", UnitOfMeasureCode);
+ end;
+ SalesLineDiscount.Validate("Minimum Quantity", MinimumQuantity);
+ SalesLineDiscount.Insert(true);
+ end;
+
+ procedure CreateLineDiscForVendor(var PurchaseLineDiscount: Record "Purchase Line Discount"; ItemNo: Code[20]; VendorNo: Code[20]; StartingDate: Date; CurrencyCode: Code[10]; VariantCode: Code[10]; UnitofMeasureCode: Code[10]; MinimumQuantity: Decimal)
+ begin
+ PurchaseLineDiscount.Init();
+ PurchaseLineDiscount.Validate("Item No.", ItemNo);
+ PurchaseLineDiscount.Validate("Vendor No.", VendorNo);
+ PurchaseLineDiscount.Validate("Starting Date", StartingDate);
+ PurchaseLineDiscount.Validate("Currency Code", CurrencyCode);
+ PurchaseLineDiscount.Validate("Variant Code", VariantCode);
+ PurchaseLineDiscount.Validate("Unit of Measure Code", UnitofMeasureCode);
+ PurchaseLineDiscount.Validate("Minimum Quantity", MinimumQuantity);
+ PurchaseLineDiscount.Insert(true);
+ end;
+
+ procedure CreateNoSeriesCode(): Code[20]
+ var
+ NoSeries: Record "No. Series";
+ NoSeriesLine: Record "No. Series Line";
+ begin
+ // Create Number Series and Number Series Line and return the No. Series Code.
+ LibraryUtility.CreateNoSeries(NoSeries, true, true, false);
+ LibraryUtility.CreateNoSeriesLine(NoSeriesLine, NoSeries.Code, '', '');
+ exit(NoSeries.Code);
+ end;
+
+ procedure CreateNoSeriesCode(Prefix: Code[3]): Code[20]
+ var
+ NoSeries: Record "No. Series";
+ NoSeriesLine: Record "No. Series Line";
+ begin
+ // Create Number Series and Number Series Line and return the No. Series Code.
+ NoSeries.Code := Prefix;
+ LibraryUtility.CreateNoSeries(NoSeries, true, true, false);
+ LibraryUtility.CreateNoSeriesLine(NoSeriesLine, NoSeries.Code, '', '');
+ exit(NoSeries.Code);
+ end;
+
+ procedure CreatePaymentMethod(var PaymentMethod: Record "Payment Method")
+ begin
+ PaymentMethod.Init();
+ PaymentMethod.Validate(
+ Code,
+ CopyStr(
+ LibraryUtility.GenerateRandomCode(PaymentMethod.FieldNo(Code), DATABASE::"Payment Method"), 1,
+ LibraryUtility.GetFieldLength(DATABASE::"Payment Method", PaymentMethod.FieldNo(Code))));
+ PaymentMethod.Validate(Description, LibraryUtility.GenerateGUID());
+ PaymentMethod.Insert(true);
+ end;
+
+ procedure CreatePaymentMethodWithBalAccount(var PaymentMethod: Record "Payment Method")
+ begin
+ CreatePaymentMethod(PaymentMethod);
+ PaymentMethod.Validate("Bal. Account Type", PaymentMethod."Bal. Account Type"::"G/L Account");
+ PaymentMethod.Validate("Bal. Account No.", CreateGLAccountNo());
+ PaymentMethod.Modify(true);
+ end;
+
+ [Scope('OnPrem')]
+ procedure CreatePaymentMethodTranslation(PaymentMethodCode: Code[10]): Code[10]
+ var
+ PaymentMethodTranslation: Record "Payment Method Translation";
+ begin
+ PaymentMethodTranslation.Init();
+ PaymentMethodTranslation.Validate("Payment Method Code", PaymentMethodCode);
+ PaymentMethodTranslation.Validate("Language Code", GetAnyLanguageDifferentFromCurrent());
+ PaymentMethodTranslation.Validate(Description, LibraryUtility.GenerateGUID());
+ PaymentMethodTranslation.Insert(true);
+ exit(PaymentMethodTranslation."Language Code");
+ end;
+
+ procedure CreatePaymentTerms(var PaymentTerms: Record "Payment Terms")
+ begin
+ PaymentTerms.Init();
+ PaymentTerms.Validate(
+ Code,
+ CopyStr(
+ LibraryUtility.GenerateRandomCode(PaymentTerms.FieldNo(Code), DATABASE::"Payment Terms"),
+ 1,
+ LibraryUtility.GetFieldLength(DATABASE::"Payment Terms", PaymentTerms.FieldNo(Code))));
+ PaymentTerms.Insert(true);
+
+ OnAfterCreatePaymentTerms(PaymentTerms);
+ end;
+
+ procedure CreatePaymentTermsDiscount(var PaymentTerms: Record "Payment Terms"; CalcPmtDiscOnCrMemos: Boolean)
+ begin
+ CreatePaymentTerms(PaymentTerms);
+ PaymentTerms.Validate("Calc. Pmt. Disc. on Cr. Memos", CalcPmtDiscOnCrMemos);
+ Evaluate(PaymentTerms."Due Date Calculation", '<' + Format(LibraryRandom.RandInt(5)) + 'M>');
+ Evaluate(PaymentTerms."Discount Date Calculation", '<' + Format(LibraryRandom.RandInt(10)) + 'D>');
+ PaymentTerms.Validate("Due Date Calculation", PaymentTerms."Due Date Calculation");
+ PaymentTerms.Validate("Discount Date Calculation", PaymentTerms."Discount Date Calculation");
+ PaymentTerms.Validate("Discount %", LibraryRandom.RandInt(10));
+ PaymentTerms.Modify(true);
+ end;
+
+ procedure CreatePostCode(var PostCode: Record "Post Code")
+ var
+ CountryRegion: Record "Country/Region";
+ begin
+ PostCode.Init();
+ PostCode.Validate(
+ Code,
+ CopyStr(
+ LibraryUtility.GenerateRandomCode(PostCode.FieldNo(Code), DATABASE::"Post Code"),
+ 1,
+ LibraryUtility.GetFieldLength(DATABASE::"Post Code", PostCode.FieldNo(Code))));
+ PostCode.Validate(
+ City,
+ CopyStr(
+ LibraryUtility.GenerateRandomCode(PostCode.FieldNo(City), DATABASE::"Post Code"),
+ 1,
+ LibraryUtility.GetFieldLength(DATABASE::"Post Code", PostCode.FieldNo(City))));
+ CountryRegion.Next(LibraryRandom.RandInt(CountryRegion.Count()));
+ PostCode.Validate("Country/Region Code", CountryRegion.Code);
+ PostCode.Insert(true);
+
+ OnAfterCreatePostCode(PostCode);
+ end;
+
+ local procedure CreatePrepaymentVATPostingSetup(var VATPostingSetup: Record "VAT Posting Setup"; VATCalcType: Enum "Tax Calculation Type"; GenPostingType: Enum "General Posting Type"; SetupGLAccount: Record "G/L Account"; VATAccountNo: Code[20])
+ var
+ VATBusinessPostingGroup: Record "VAT Business Posting Group";
+ VATProductPostingGroup: Record "VAT Product Posting Group";
+ Handled: Boolean;
+ begin
+ OnBeforeCreatePrepaymentVATPostingSetup(VATPostingSetup, VATCalcType, GenPostingType, SetupGLAccount, VATAccountNo, Handled);
+ if Handled then
+ exit;
+
+ if (SetupGLAccount."VAT Bus. Posting Group" <> '') and (SetupGLAccount."VAT Prod. Posting Group" <> '') then
+ if VATPostingSetup.Get(SetupGLAccount."VAT Bus. Posting Group", SetupGLAccount."VAT Prod. Posting Group") then
+ exit;
+
+ VATPostingSetup.Init();
+ if SetupGLAccount."VAT Bus. Posting Group" <> '' then
+ VATPostingSetup."VAT Bus. Posting Group" := SetupGLAccount."VAT Bus. Posting Group"
+ else begin
+ CreateVATBusinessPostingGroup(VATBusinessPostingGroup);
+ VATPostingSetup."VAT Bus. Posting Group" := VATBusinessPostingGroup.Code;
+ end;
+ CreateVATProductPostingGroup(VATProductPostingGroup);
+ VATPostingSetup."VAT Prod. Posting Group" := VATProductPostingGroup.Code;
+ VATPostingSetup."VAT Identifier" := VATPostingSetup."VAT Prod. Posting Group";
+ VATPostingSetup."VAT Calculation Type" := VATCalcType;
+ if VATPostingSetup."VAT Calculation Type" <> VATPostingSetup."VAT Calculation Type"::"Full VAT" then begin
+ VATPostingSetup."VAT %" := LibraryRandom.RandIntInRange(5, 25);
+ VATAccountNo := CreateGLAccountNo();
+ end;
+ if GenPostingType = GenPostingType::Purchase then
+ VATPostingSetup."Purchase VAT Account" := VATAccountNo
+ else
+ VATPostingSetup."Sales VAT Account" := VATAccountNo;
+ VATPostingSetup.Insert();
+
+ OnAfterCreatePrepaymentVATPostingSetup(VATPostingSetup, VATCalcType, GenPostingType, SetupGLAccount, VATAccountNo);
+ end;
+
+ local procedure CreatePrepaymentGenPostingSetup(var GenPostingSetup: Record "General Posting Setup"; var PrepmtGLAccount: Record "G/L Account"; GenPostingType: Enum "General Posting Type"; SetupGLAccount: Record "G/L Account")
+ var
+ GenBusPostingGroup: Record "Gen. Business Posting Group";
+ GenProdPostingGroup: Record "Gen. Product Posting Group";
+ begin
+ if (SetupGLAccount."Gen. Bus. Posting Group" <> '') and (SetupGLAccount."Gen. Prod. Posting Group" <> '') then
+ if GenPostingSetup.Get(SetupGLAccount."Gen. Bus. Posting Group", SetupGLAccount."Gen. Prod. Posting Group") then
+ exit;
+
+ GenPostingSetup.Init();
+ if SetupGLAccount."Gen. Bus. Posting Group" <> '' then
+ GenPostingSetup."Gen. Bus. Posting Group" := SetupGLAccount."Gen. Bus. Posting Group"
+ else begin
+ CreateGenBusPostingGroup(GenBusPostingGroup);
+ GenPostingSetup."Gen. Bus. Posting Group" := GenBusPostingGroup.Code;
+ end;
+ CreateGenProdPostingGroup(GenProdPostingGroup);
+ GenPostingSetup."Gen. Prod. Posting Group" := GenProdPostingGroup.Code;
+ CreateGLAccount(PrepmtGLAccount);
+ case GenPostingType of
+ GenPostingType::Purchase:
+ begin
+ GenPostingSetup."Direct Cost Applied Account" := CreateGLAccountNo();
+ GenPostingSetup."Purch. Account" := CreateGLAccountNo();
+ GenPostingSetup."Purch. Prepayments Account" := PrepmtGLAccount."No.";
+ GenPostingSetup."Purch. Line Disc. Account" := CreateGLAccountNo();
+ end;
+ GenPostingType::Sale:
+ begin
+ GenPostingSetup."COGS Account" := CreateGLAccountNo();
+ GenPostingSetup."Sales Account" := CreateGLAccountNo();
+ GenPostingSetup."Sales Prepayments Account" := PrepmtGLAccount."No.";
+ GenPostingSetup."Sales Line Disc. Account" := CreateGLAccountNo();
+ end;
+ end;
+ GenPostingSetup.Insert();
+ end;
+
+ procedure CreatePrepaymentVATSetup(var LineGLAccount: Record "G/L Account"; var PrepmtGLAccount: Record "G/L Account"; GenPostingType: Enum "General Posting Type"; VATCalcType: Enum "Tax Calculation Type"; PrepmtVATCalcType: Enum "Tax Calculation Type")
+ var
+ GenPostingSetup: Record "General Posting Setup";
+ PassedGLAccount: Record "G/L Account";
+ Handled: Boolean;
+ begin
+ PassedGLAccount := LineGLAccount;
+ CreatePrepaymentGenPostingSetup(GenPostingSetup, PrepmtGLAccount, GenPostingType, PassedGLAccount);
+ SetPostingGroupsOnPrepmtGLAccount(PrepmtGLAccount, GenPostingSetup, GenPostingType, PrepmtVATCalcType, PassedGLAccount);
+
+ CreateGLAccount(LineGLAccount);
+
+ OnBeforeSetPostingGroupsOnPrepmtGLAccount(LineGLAccount, PrepmtGLAccount, GenPostingType, VATCalcType.AsInteger(), PrepmtVATCalcType.AsInteger(), Handled);
+
+ if Handled then
+ exit;
+
+ if (PrepmtVATCalcType = VATCalcType) and (VATCalcType <> VATCalcType::"Full VAT") then
+ SetPostingGroupsOnPrepmtGLAccount(LineGLAccount, GenPostingSetup, GenPostingType, VATCalcType, PrepmtGLAccount)
+ else begin
+ PassedGLAccount."Gen. Bus. Posting Group" := PrepmtGLAccount."Gen. Bus. Posting Group";
+ PassedGLAccount."VAT Bus. Posting Group" := PrepmtGLAccount."VAT Bus. Posting Group";
+ SetPostingGroupsOnPrepmtGLAccount(LineGLAccount, GenPostingSetup, GenPostingType, VATCalcType, PassedGLAccount);
+ end;
+
+ OnAfterSetPostingGroupsOnPrepmtGLAccount(LineGLAccount, PrepmtGLAccount, GenPostingType, VATCalcType.AsInteger(), PrepmtVATCalcType.AsInteger());
+ end;
+
+ procedure CreateReasonCode(var ReasonCode: Record "Reason Code")
+ begin
+ ReasonCode.Init();
+ ReasonCode.Validate(
+ Code,
+ CopyStr(
+ LibraryUtility.GenerateRandomCode(ReasonCode.FieldNo(Code), DATABASE::"Reason Code"),
+ 1, LibraryUtility.GetFieldLength(DATABASE::"Reason Code", ReasonCode.FieldNo(Code))));
+ ReasonCode.Validate(Description, ReasonCode.Code); // Validating Description as Code because value is not important.
+ ReasonCode.Insert(true);
+ end;
+
+ procedure CreateReminderHeader(var ReminderHeader: Record "Reminder Header")
+ begin
+ ReminderHeader.Init();
+ ReminderHeader.Insert(true);
+ end;
+
+ procedure CreateReminderLevel(var ReminderLevel: Record "Reminder Level"; ReminderTermsCode: Code[10])
+ begin
+ ReminderLevel.Init();
+ ReminderLevel.Validate("Reminder Terms Code", ReminderTermsCode);
+ ReminderLevel.NewRecord();
+ ReminderLevel.Insert(true);
+ end;
+
+ procedure CreateReminderLine(var ReminderLine: Record "Reminder Line"; ReminderNo: Code[20]; Type: Enum "Reminder Source Type")
+ var
+ RecRef: RecordRef;
+ begin
+ ReminderLine.Init();
+ ReminderLine.Validate("Reminder No.", ReminderNo);
+ RecRef.GetTable(ReminderLine);
+ ReminderLine.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, ReminderLine.FieldNo("Line No.")));
+ ReminderLine.Insert(true);
+ ReminderLine.Validate(Type, Type);
+ ReminderLine.Modify(true);
+ end;
+
+ procedure CreateReminderTerms(var ReminderTerms: Record "Reminder Terms")
+ begin
+ ReminderTerms.Init();
+ ReminderTerms.Validate(Code, LibraryUtility.GenerateRandomCode(ReminderTerms.FieldNo(Code), DATABASE::"Reminder Terms"));
+ ReminderTerms.Validate(Description, ReminderTerms.Code);
+ ReminderTerms.Insert(true);
+ end;
+
+ procedure CreateReminderText(var ReminderText: Record "Reminder Text"; ReminderTermsCode: Code[10]; ReminderLevel: Integer; Position: Enum "Reminder Text Position"; Text: Text[100])
+ var
+ RecRef: RecordRef;
+ begin
+ ReminderText.Init();
+ ReminderText.Validate("Reminder Terms Code", ReminderTermsCode);
+ ReminderText.Validate("Reminder Level", ReminderLevel);
+ ReminderText.Validate(Position, Position);
+ RecRef.GetTable(ReminderText);
+ ReminderText.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, ReminderText.FieldNo("Line No.")));
+ ReminderText.Insert(true);
+ ReminderText.Validate(Text, Text);
+ ReminderText.Modify(true);
+ end;
+
+ procedure CreateRecurringTemplateName(var GenJournalTemplate: Record "Gen. Journal Template")
+ begin
+ GenJournalTemplate.Init();
+ GenJournalTemplate.Validate(
+ Name,
+ CopyStr(LibraryUtility.GenerateRandomCode(GenJournalTemplate.FieldNo(Name), DATABASE::"Gen. Journal Template"),
+ 1, LibraryUtility.GetFieldLength(DATABASE::"Gen. Journal Template", GenJournalTemplate.FieldNo(Name))));
+ GenJournalTemplate.Insert(true);
+ GenJournalTemplate.Validate("Posting No. Series", LibraryUtility.GetGlobalNoSeriesCode());
+ GenJournalTemplate.Validate(Recurring, true);
+ GenJournalTemplate.Modify(true);
+ end;
+
+ procedure CreateRecurringBatchName(var GenJournalBatch: Record "Gen. Journal Batch"; JournalTemplateName: Code[10])
+ var
+ GenJournalTemplate: Record "Gen. Journal Template";
+ begin
+ // Create New General Journal Batch with a random Name of String length less than 10.
+ GenJournalTemplate.Get(JournalTemplateName);
+ GenJournalBatch.Init();
+ GenJournalBatch.Validate("Journal Template Name", GenJournalTemplate.Name);
+ GenJournalBatch.Validate(
+ Name,
+ CopyStr(LibraryUtility.GenerateRandomCode(GenJournalBatch.FieldNo(Name), DATABASE::"Gen. Journal Batch"),
+ 1, LibraryUtility.GetFieldLength(DATABASE::"Gen. Journal Batch", GenJournalBatch.FieldNo(Name))));
+ GenJournalBatch.Insert(true);
+ GenJournalBatch.Validate("Posting No. Series", GenJournalTemplate."Posting No. Series");
+ GenJournalBatch.Modify(true);
+ end;
+
+ procedure CreateReturnReasonCode(var ReturnReason: Record "Return Reason")
+ begin
+ ReturnReason.Init();
+ ReturnReason.Validate(
+ Code,
+ CopyStr(
+ LibraryUtility.GenerateRandomCode(ReturnReason.FieldNo(Code), DATABASE::"Return Reason"),
+ 1, LibraryUtility.GetFieldLength(DATABASE::"Return Reason", ReturnReason.FieldNo(Code))));
+ ReturnReason.Validate(Description, ReturnReason.Code); // Validating Description as Code because value is not important.
+ ReturnReason.Insert(true);
+ end;
+
+ procedure CreateSourceCode(var SourceCode: Record "Source Code")
+ begin
+ SourceCode.Init();
+ SourceCode.Validate(
+ Code,
+ CopyStr(LibraryUtility.GenerateRandomCode(SourceCode.FieldNo(Code), DATABASE::"Source Code"),
+ 1, LibraryUtility.GetFieldLength(DATABASE::"Source Code", SourceCode.FieldNo(Code))));
+ SourceCode.Insert(true);
+ end;
+
+ procedure CreateRelatedVATPostingSetup(GLAccount: Record "G/L Account"): Code[20]
+ var
+ VATPostingSetup: Record "VAT Posting Setup";
+ VATProductPostingGroup: Record "VAT Product Posting Group";
+ begin
+ VATPostingSetup.Get(GLAccount."VAT Bus. Posting Group", GLAccount."VAT Prod. Posting Group");
+ CreateVATProductPostingGroup(VATProductPostingGroup);
+ VATPostingSetup."VAT Prod. Posting Group" := VATProductPostingGroup.Code;
+ VATPostingSetup."Sales VAT Account" := CreateGLAccountNo();
+ VATPostingSetup."Purchase VAT Account" := CreateGLAccountNo();
+ VATPostingSetup.Insert();
+ exit(VATPostingSetup."VAT Prod. Posting Group");
+ end;
+
+ procedure CreateVATBusinessPostingGroup(var VATBusinessPostingGroup: Record "VAT Business Posting Group")
+ begin
+ VATBusinessPostingGroup.Init();
+ VATBusinessPostingGroup.Validate(
+ Code,
+ CopyStr(LibraryUtility.GenerateRandomCode(VATBusinessPostingGroup.FieldNo(Code), DATABASE::"VAT Business Posting Group"),
+ 1, LibraryUtility.GetFieldLength(DATABASE::"VAT Business Posting Group", VATBusinessPostingGroup.FieldNo(Code))));
+
+ // Validating Code as Name because value is not important.
+ VATBusinessPostingGroup.Validate(Description, VATBusinessPostingGroup.Code);
+ VATBusinessPostingGroup.Insert(true);
+ end;
+
+ procedure CreateRandomVATIdentifierAndGetCode(): Text
+ var
+ VATPostingSetup: Record "VAT Posting Setup";
+ begin
+ exit(LibraryUtility.GenerateRandomCode(VATPostingSetup.FieldNo("VAT Identifier"), DATABASE::"VAT Posting Setup"));
+ end;
+
+ procedure CreateVATPostingSetup(var VATPostingSetup: Record "VAT Posting Setup"; VATBusPostingGroup: Code[20]; VATProdPostingGroup: Code[20])
+ var
+ Handled: Boolean;
+ begin
+ OnBeforeCreateVATPostingSetup(VATPostingSetup, Handled);
+ if Handled then
+ exit;
+
+ VATPostingSetup.Init();
+ VATPostingSetup.Validate("VAT Bus. Posting Group", VATBusPostingGroup);
+ VATPostingSetup.Validate("VAT Prod. Posting Group", VATProdPostingGroup);
+ VATPostingSetup.Insert(true);
+
+ OnAfterCreateVATPostingSetup(VATPostingSetup);
+ end;
+
+ procedure CreateVATPostingSetupWithAccounts(var VATPostingSetup: Record "VAT Posting Setup"; VATCalculationType: Enum "Tax Calculation Type"; VATRate: Decimal)
+ var
+ VATBusinessPostingGroup: Record "VAT Business Posting Group";
+ VATProductPostingGroup: Record "VAT Product Posting Group";
+ IsHandled: Boolean;
+ begin
+ IsHandled := false;
+ OnBeforeCreateVATPostingSetupWithAccounts(VATPostingSetup, VATCalculationType, VATRate, IsHandled);
+ if IsHandled then
+ exit;
+
+ VATPostingSetup.Init();
+ CreateVATBusinessPostingGroup(VATBusinessPostingGroup);
+ CreateVATProductPostingGroup(VATProductPostingGroup);
+ VATPostingSetup.Validate("VAT Bus. Posting Group", VATBusinessPostingGroup.Code);
+ VATPostingSetup.Validate("VAT Prod. Posting Group", VATProductPostingGroup.Code);
+ VATPostingSetup.Validate("VAT Calculation Type", VATCalculationType);
+ VATPostingSetup.Validate("VAT %", VATRate);
+ VATPostingSetup.Validate("VAT Identifier",
+ LibraryUtility.GenerateRandomCode(VATPostingSetup.FieldNo("VAT Identifier"), DATABASE::"VAT Posting Setup"));
+ VATPostingSetup.Validate("Sales VAT Account", CreateGLAccountNo());
+ VATPostingSetup.Validate("Purchase VAT Account", CreateGLAccountNo());
+ VATPostingSetup.Validate("Tax Category", 'S');
+ VATPostingSetup.Insert(true);
+ end;
+
+ procedure CreateVATProductPostingGroup(var VATProductPostingGroup: Record "VAT Product Posting Group")
+ var
+ IsHandled: Boolean;
+ begin
+ OnBeforeCreateVATProductPostingGroup(VATProductPostingGroup, IsHandled);
+ if IsHandled then
+ exit;
+
+ VATProductPostingGroup.Init();
+ VATProductPostingGroup.Validate(
+ Code,
+ CopyStr(LibraryUtility.GenerateRandomCode(VATProductPostingGroup.FieldNo(Code), DATABASE::"VAT Product Posting Group"),
+ 1, LibraryUtility.GetFieldLength(DATABASE::"VAT Product Posting Group", VATProductPostingGroup.FieldNo(Code))));
+
+ // Validating Code as Name because value is not important.
+ VATProductPostingGroup.Validate(Description, VATProductPostingGroup.Code);
+ VATProductPostingGroup.Insert(true);
+
+ OnAfterCreateVATProductPostingGroup(VATProductPostingGroup);
+ end;
+
+ procedure CreateVATRegistrationNoFormat(var VATRegistrationNoFormat: Record "VAT Registration No. Format"; CountryRegionCode: Code[10])
+ var
+ RecRef: RecordRef;
+ begin
+ VATRegistrationNoFormat.Init();
+ VATRegistrationNoFormat.Validate("Country/Region Code", CountryRegionCode);
+ RecRef.GetTable(VATRegistrationNoFormat);
+ VATRegistrationNoFormat.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, VATRegistrationNoFormat.FieldNo("Line No.")));
+ VATRegistrationNoFormat.Insert(true);
+ end;
+
+ procedure CreateVATClause(var VATClause: Record "VAT Clause")
+ begin
+ VATClause.Init();
+ VATClause.Validate(Code,
+ CopyStr(LibraryUtility.GenerateRandomCode(VATClause.FieldNo(Code), DATABASE::"VAT Clause"),
+ 1, LibraryUtility.GetFieldLength(DATABASE::"VAT Clause", VATClause.FieldNo(Code))));
+ VATClause.Validate(Description, LibraryUtility.GenerateGUID());
+ VATClause.Validate("Description 2", LibraryUtility.GenerateGUID());
+ VATClause.Insert(true);
+ end;
+
+ procedure GenerateVATRegistrationNo(CountryRegionCode: Code[10]) VATRegNo: Text[20]
+ var
+ VATRegistrationNoFormat: Record "VAT Registration No. Format";
+ FormatType: Text[1];
+ i: Integer;
+ RandomCharacter: Char;
+ begin
+ // Generate VAT Registration No. as per VAT Registration No. format.
+ VATRegistrationNoFormat.SetRange("Country/Region Code", CountryRegionCode);
+ if VATRegistrationNoFormat.FindFirst() then
+ for i := 1 to StrLen(VATRegistrationNoFormat.Format) do begin
+ FormatType := CopyStr(VATRegistrationNoFormat.Format, i, 1);
+ case FormatType of
+ 'A' .. 'Z', '0' .. '9', '.', '-':
+ VATRegNo := InsStr(VATRegNo, FormatType, i);
+ '#':
+ VATRegNo := InsStr(VATRegNo, Format(LibraryRandom.RandInt(9)), i);
+ '@':
+ begin
+ RandomCharacter := LibraryRandom.RandInt(25) + 65; // For the generation of random character.
+ VATRegNo := InsStr(VATRegNo, Format(RandomCharacter), i); // Used as constant as VAT Registration validation is not important.
+ end;
+ ' ':
+ VATRegNo := VATRegNo + ' '
+ else
+ VATRegNo := InsStr(VATRegNo, Format(LibraryRandom.RandInt(9)), i);
+ end;
+ end
+ else
+ VATRegNo :=
+ CopyStr(LibraryUtility.GenerateRandomCode(VATRegistrationNoFormat.FieldNo(Format), DATABASE::"VAT Registration No. Format"),
+ 1, LibraryUtility.GetFieldLength(DATABASE::"VAT Registration No. Format", VATRegistrationNoFormat.FieldNo(Format)));
+ end;
+
+ procedure CreateStandardGeneralJournal(var StandardGeneralJournal: Record "Standard General Journal"; JournalTemplateName: Code[10])
+ begin
+ StandardGeneralJournal.Init();
+ StandardGeneralJournal.Validate("Journal Template Name", JournalTemplateName);
+ StandardGeneralJournal.Validate(
+ Code,
+ CopyStr(
+ LibraryUtility.GenerateRandomCode(StandardGeneralJournal.FieldNo(Code), DATABASE::"Standard General Journal"),
+ 1,
+ LibraryUtility.GetFieldLength(DATABASE::"Standard General Journal", StandardGeneralJournal.FieldNo(Code))));
+
+ // Validating Code as Description because value is not important.
+ StandardGeneralJournal.Validate(Description, StandardGeneralJournal.Code);
+ StandardGeneralJournal.Insert(true);
+ end;
+
+ procedure CreateStandardItemJournal(var StandardItemJournal: Record "Standard Item Journal"; JournalTemplateName: Code[10])
+ begin
+ StandardItemJournal.Init();
+ StandardItemJournal.Validate("Journal Template Name", JournalTemplateName);
+ StandardItemJournal.Validate(
+ Code,
+ CopyStr(
+ LibraryUtility.GenerateRandomCode(StandardItemJournal.FieldNo(Code), DATABASE::"Standard Item Journal"),
+ 1,
+ LibraryUtility.GetFieldLength(DATABASE::"Standard Item Journal", StandardItemJournal.FieldNo(Code))));
+
+ // Validating Code as Description because value is not important.
+ StandardItemJournal.Validate(Description, StandardItemJournal.Code);
+ StandardItemJournal.Insert(true);
+ end;
+
+ procedure CreateVATStatementLine(var VATStatementLine: Record "VAT Statement Line"; StatementTemplateName: Code[10]; StatementName: Code[10])
+ var
+ RecRef: RecordRef;
+ begin
+ VATStatementLine.Init();
+ VATStatementLine.Validate("Statement Template Name", StatementTemplateName);
+ VATStatementLine.Validate("Statement Name", StatementName);
+ RecRef.GetTable(VATStatementLine);
+ VATStatementLine.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, VATStatementLine.FieldNo("Line No.")));
+ VATStatementLine.Insert(true);
+ end;
+
+ procedure CreateVATStatementName(var VATStatementName: Record "VAT Statement Name"; StatementTemplateName: Code[10])
+ begin
+ VATStatementName.Init();
+ VATStatementName.Validate("Statement Template Name", StatementTemplateName);
+ VATStatementName.Validate(
+ Name,
+ CopyStr(
+ LibraryUtility.GenerateRandomCode(VATStatementName.FieldNo(Name), DATABASE::"VAT Statement Name"), 1,
+ LibraryUtility.GetFieldLength(DATABASE::"VAT Statement Name", VATStatementName.FieldNo(Name))));
+ VATStatementName.Validate(Description, VATStatementName.Name); // Validating Name as Description because value is not important.
+ VATStatementName.Insert(true);
+ end;
+
+ procedure CreateVATStatementTemplate(var VATStatementTemplate: Record "VAT Statement Template")
+ begin
+ VATStatementTemplate.Init();
+ VATStatementTemplate.Validate(
+ Name,
+ CopyStr(
+ LibraryUtility.GenerateRandomCode(VATStatementTemplate.FieldNo(Name), DATABASE::"VAT Statement Template"), 1,
+ LibraryUtility.GetFieldLength(DATABASE::"VAT Statement Template", VATStatementTemplate.FieldNo(Name))));
+ VATStatementTemplate.Validate(Description, VATStatementTemplate.Name); // Validating Name as Description because value is not important.
+ VATStatementTemplate.Insert(true);
+ end;
+
+ procedure CreateVATStatementNameWithTemplate(var VATStatementName: Record "VAT Statement Name")
+ var
+ VATStatementTemplate: Record "VAT Statement Template";
+ begin
+ CreateVATStatementTemplate(VATStatementTemplate);
+ CreateVATStatementName(VATStatementName, VATStatementTemplate.Name);
+ end;
+
+ procedure CreateTaxArea(var TaxArea: Record "Tax Area")
+ begin
+ TaxArea.Init();
+ TaxArea.Validate(
+ Code,
+ CopyStr(
+ LibraryUtility.GenerateRandomCode(TaxArea.FieldNo(Code), DATABASE::"Tax Area"),
+ 1,
+ LibraryUtility.GetFieldLength(DATABASE::"Tax Area", TaxArea.FieldNo(Code))));
+ TaxArea.Validate(Description, TaxArea.Code); // Validating Code as Description because value is not important.
+ TaxArea.Insert(true);
+ end;
+
+ procedure CreateTaxAreaLine(var TaxAreaLine: Record "Tax Area Line"; TaxAreaCode: Code[20]; TaxJurisdictionCode: Code[10])
+ begin
+ TaxAreaLine.Init();
+ TaxAreaLine.Validate("Tax Area", TaxAreaCode);
+ TaxAreaLine.Validate("Tax Jurisdiction Code", TaxJurisdictionCode);
+ TaxAreaLine.Insert(true);
+ end;
+
+ procedure CreateTaxGroup(var TaxGroup: Record "Tax Group")
+ begin
+ TaxGroup.Init();
+ TaxGroup.Validate(
+ Code,
+ CopyStr(
+ LibraryUtility.GenerateRandomCode(TaxGroup.FieldNo(Code), DATABASE::"Tax Group"),
+ 1,
+ LibraryUtility.GetFieldLength(DATABASE::"Tax Group", TaxGroup.FieldNo(Code))));
+ TaxGroup.Validate(Description, TaxGroup.Code); // Validating Code as Description because value is not important.
+ TaxGroup.Insert(true);
+ end;
+
+ procedure CreateTaxJurisdiction(var TaxJurisdiction: Record "Tax Jurisdiction")
+ begin
+ TaxJurisdiction.Init();
+ TaxJurisdiction.Validate(
+ Code,
+ CopyStr(
+ LibraryUtility.GenerateRandomCode(TaxJurisdiction.FieldNo(Code), DATABASE::"Tax Jurisdiction"),
+ 1,
+ LibraryUtility.GetFieldLength(DATABASE::"Tax Jurisdiction", TaxJurisdiction.FieldNo(Code))));
+ TaxJurisdiction.Validate(Description, TaxJurisdiction.Code); // Validating Code as Description because value is not important.
+ TaxJurisdiction.Insert(true);
+ end;
+
+ procedure CreateTaxDetail(var TaxDetail: Record "Tax Detail"; TaxJurisdictionCode: Code[10]; TaxGroupCode: Code[20]; TaxType: Option; EffectiveDate: Date)
+ begin
+ TaxDetail.Init();
+ TaxDetail.Validate("Tax Jurisdiction Code", TaxJurisdictionCode);
+ TaxDetail.Validate("Tax Group Code", TaxGroupCode);
+ TaxDetail.Validate("Tax Type", TaxType);
+ TaxDetail.Validate("Effective Date", EffectiveDate);
+ TaxDetail.Insert(true);
+ end;
+
+ procedure CreateCountryRegionWithIntrastatCode(): Code[10]
+ var
+ CountryRegion: Record "Country/Region";
+ begin
+ CreateCountryRegion(CountryRegion);
+ CountryRegion.Validate(Name, LibraryUtility.GenerateGUID());
+ CountryRegion.Validate("Intrastat Code", LibraryUtility.GenerateGUID());
+ CountryRegion.Modify(true);
+ exit(CountryRegion.Code);
+ end;
+
+ procedure CreateItemBudgetName(var ItemBudgetName: Record "Item Budget Name"; AnalysisArea: Enum "Analysis Area Type")
+ begin
+ ItemBudgetName.Init();
+ ItemBudgetName.Validate("Analysis Area", AnalysisArea);
+ ItemBudgetName.Validate(Name, LibraryUtility.GenerateGUID());
+ ItemBudgetName.Insert(true);
+ end;
+
+ procedure DisableClosingUnreleasedOrdersMsg()
+ var
+ InstructionMgt: Codeunit "Instruction Mgt.";
+ begin
+ InstructionMgt.DisableMessageForCurrentUser(InstructionMgt.ClosingUnreleasedOrdersCode());
+ end;
+
+ procedure DisableMyNotifications(UserId: Code[50]; NotificationId: Guid)
+ var
+ MyNotifications: Record "My Notifications";
+ begin
+ if not MyNotifications.Get(UserId, NotificationId) then begin
+ MyNotifications.Init();
+ MyNotifications."User Id" := UserId;
+ MyNotifications."Notification Id" := NotificationId;
+ MyNotifications.Enabled := false;
+ MyNotifications.Insert();
+ end else begin
+ MyNotifications.Enabled := false;
+ MyNotifications.Modify();
+ end;
+ end;
+
+ procedure FindRecurringTemplateName(var GenJournalTemplate: Record "Gen. Journal Template")
+ begin
+ GenJournalTemplate.SetRange(Type, GenJournalTemplate.Type::General);
+ GenJournalTemplate.SetRange(Recurring, true);
+ if not GenJournalTemplate.FindFirst() then
+ CreateRecurringTemplateName(GenJournalTemplate);
+ end;
+
+ procedure FindBankAccount(var BankAccount: Record "Bank Account")
+ begin
+ BankAccount.SetFilter("Bank Acc. Posting Group", '<>%1', '');
+ BankAccount.SetRange("Currency Code", '');
+ BankAccount.SetRange(Blocked, false);
+ if not BankAccount.FindFirst() then
+ CreateBankAccount(BankAccount);
+ end;
+
+ procedure FindBankAccountPostingGroup(var BankAccountPostingGroup: Record "Bank Account Posting Group")
+ begin
+ if not BankAccountPostingGroup.FindFirst() then
+ CreateBankAccountPostingGroup(BankAccountPostingGroup);
+ end;
+
+ procedure FindCountryRegion(var CountryRegion: Record "Country/Region")
+ begin
+ if not CountryRegion.FindFirst() then
+ CreateCountryRegion(CountryRegion);
+ end;
+
+ procedure FindCurrency(var Currency: Record Currency)
+ begin
+ if not Currency.FindFirst() then
+ CreateCurrency(Currency);
+ end;
+
+ procedure FindCustomerLedgerEntry(var CustLedgerEntry: Record "Cust. Ledger Entry"; DocumentType: Enum "Gen. Journal Document Type"; DocumentNo: Code[20])
+ begin
+ // Finds the matching Customer Ledger Entry from a General Journal Line.
+ CustLedgerEntry.SetRange("Document Type", DocumentType);
+ CustLedgerEntry.SetRange("Document No.", DocumentNo);
+ CustLedgerEntry.FindFirst();
+ end;
+
+ procedure MinDate(Date1: Date; Date2: Date): Date
+ begin
+ if Date1 < Date2 then
+ exit(Date1);
+ exit(Date2);
+ end;
+
+ procedure MaxDate(Date1: Date; Date2: Date): Date
+ begin
+ if Date1 > Date2 then
+ exit(Date1);
+ exit(Date2);
+ end;
+
+ procedure FindEarliestDateForExhRate() Date: Date
+ var
+ GLEntry: Record "G/L Entry";
+ begin
+ Date := MinDate(WorkDate(), Today);
+ GLEntry.SetCurrentKey("Posting Date");
+ if GLEntry.FindFirst() then
+ Date := MinDate(Date, NormalDate(GLEntry."Posting Date"));
+ exit(Date);
+ end;
+
+ procedure FindExchRate(var CurrencyExchangeRate: Record "Currency Exchange Rate"; Currency: Code[10]; ConversionDate: Date)
+ begin
+ // Returns the Exchange Rate for a specified Currency at a specified Date. If multiple Exchange Rates exists it picks the latest.
+ CurrencyExchangeRate.SetRange("Currency Code", Currency);
+ CurrencyExchangeRate.SetRange("Starting Date", 0D, ConversionDate);
+ CurrencyExchangeRate.FindLast();
+ end;
+
+ procedure FindGLAccount(var GLAccount: Record "G/L Account"): Code[20]
+ begin
+ // Filter G/L Account so that errors are not generated due to mandatory fields.
+ SetGLAccountDirectPostingFilter(GLAccount);
+ SetGLAccountNotBlankGroupsFilter(GLAccount);
+ GLAccount.FindFirst();
+ exit(GLAccount."No.");
+ end;
+
+ procedure FindGLAccountDataSet(var GLAccount: Record "G/L Account")
+ begin
+ SetGLAccountDirectPostingFilter(GLAccount);
+ SetGLAccountNotBlankGroupsFilter(GLAccount);
+ GLAccount.FindSet();
+ end;
+
+ procedure FindDirectPostingGLAccount(var GLAccount: Record "G/L Account"): Code[20]
+ begin
+ SetGLAccountDirectPostingFilter(GLAccount);
+ GLAccount.FindFirst();
+ exit(GLAccount."No.");
+ end;
+
+ procedure FindGenBusinessPostingGroup(var GenBusinessPostingGroup: Record "Gen. Business Posting Group")
+ begin
+ if not GenBusinessPostingGroup.FindFirst() then
+ CreateGenBusPostingGroup(GenBusinessPostingGroup);
+ end;
+
+ procedure FindGenJournalBatch(var GenJournalBatch: Record "Gen. Journal Batch"; JournalTemplateName: Code[10])
+ begin
+ GenJournalBatch.SetRange("Journal Template Name", JournalTemplateName);
+ if not GenJournalBatch.FindFirst() then
+ CreateGenJournalBatch(GenJournalBatch, JournalTemplateName);
+ end;
+
+ procedure FindGenJournalTemplate(var GenJournalTemplate: Record "Gen. Journal Template")
+ begin
+ GenJournalTemplate.SetRange(Recurring, false);
+ if not GenJournalTemplate.FindFirst() then begin
+ CreateGenJournalTemplate(GenJournalTemplate);
+ if GenJournalTemplate.GetRangeMin(Type) = GenJournalTemplate.GetRangeMax(Type) then begin
+ GenJournalTemplate.Validate(Type, GenJournalTemplate.GetRangeMin(Type));
+ GenJournalTemplate.Modify(true);
+ end;
+ end;
+ end;
+
+ procedure FindGenJournalTemplateWithGenName(var GenJournalTemplate: Record "Gen. Journal Template")
+ begin
+ GenJournalTemplate.SetRange(Recurring, false);
+ GenJournalTemplate.SetRange(Name, 'GENERAL');
+ if not GenJournalTemplate.FindFirst() then begin
+ CreateGenJournalTemplate(GenJournalTemplate);
+ if GenJournalTemplate.GetRangeMin(Type) = GenJournalTemplate.GetRangeMax(Type) then begin
+ GenJournalTemplate.Validate(Type, GenJournalTemplate.GetRangeMin(Type));
+ GenJournalTemplate.Modify(true);
+ end;
+ end;
+ end;
+
+ procedure FindGenProductPostingGroup(var GenProductPostingGroup: Record "Gen. Product Posting Group")
+ begin
+ if not GenProductPostingGroup.FindFirst() then
+ CreateGenProdPostingGroup(GenProductPostingGroup);
+ end;
+
+ procedure FindGeneralPostingSetup(var GeneralPostingSetup: Record "General Posting Setup"): Boolean
+ begin
+ GeneralPostingSetup.SetFilter("Gen. Bus. Posting Group", '<>%1', '');
+ GeneralPostingSetup.SetFilter("Gen. Prod. Posting Group", '<>%1', '');
+ GeneralPostingSetup.FindFirst();
+ exit(true);
+ end;
+
+ procedure FindGeneralPostingSetupInvtBase(var GeneralPostingSetup: Record "General Posting Setup")
+ begin
+ GeneralPostingSetup.SetFilter("Gen. Bus. Posting Group", '<>%1', '');
+ GeneralPostingSetup.SetFilter("Gen. Prod. Posting Group", '<>%1', '');
+ GeneralPostingSetup.SetFilter("COGS Account", '<>%1', '');
+ GeneralPostingSetup.SetFilter("Inventory Adjmt. Account", '<>%1', '');
+ if SearchPostingType <> SearchPostingType::Purchase then
+ GeneralPostingSetup.SetFilter("Sales Account", '<>%1', '');
+ if SearchPostingType <> SearchPostingType::Sales then
+ GeneralPostingSetup.SetFilter("Purch. Account", '<>%1', '');
+ if not GeneralPostingSetup.FindFirst() then begin
+ GeneralPostingSetup.SetRange("Purch. Account");
+ GeneralPostingSetup.SetRange("Inventory Adjmt. Account");
+ if GeneralPostingSetup.FindFirst() then begin
+ GeneralPostingSetup.Validate("Purch. Account", CreateGLAccountNo());
+ GeneralPostingSetup.Validate("Inventory Adjmt. Account", CreateGLAccountNo());
+ GeneralPostingSetup.Modify(true);
+ end else
+ CreateGeneralPostingSetupInvt(GeneralPostingSetup);
+ end;
+ end;
+
+ procedure FindGeneralPostingSetupInvtFull(var GeneralPostingSetup: Record "General Posting Setup")
+ begin
+ GeneralPostingSetup.SetFilter("Gen. Bus. Posting Group", '<>%1', '');
+ GeneralPostingSetup.SetFilter("Gen. Prod. Posting Group", '<>%1', '');
+ if SearchPostingType <> SearchPostingType::Purchase then begin
+ GeneralPostingSetup.SetFilter("Sales Account", '<>%1', '');
+ GeneralPostingSetup.SetFilter("Sales Credit Memo Account", '<>%1', '');
+ GeneralPostingSetup.SetFilter("Sales Prepayments Account", '<>%1', '');
+ end;
+ if SearchPostingType <> SearchPostingType::Sales then begin
+ GeneralPostingSetup.SetFilter("Purch. Account", '<>%1', '');
+ GeneralPostingSetup.SetFilter("Purch. Credit Memo Account", '<>%1', '');
+ GeneralPostingSetup.SetFilter("Purch. Prepayments Account", '<>%1', '');
+ end;
+ GeneralPostingSetup.SetFilter("COGS Account", '<>%1', '');
+ GeneralPostingSetup.SetFilter("COGS Account (Interim)", '<>''''');
+ GeneralPostingSetup.SetFilter("Inventory Adjmt. Account", '<>%1', '');
+ GeneralPostingSetup.SetFilter("Direct Cost Applied Account", '<>%1', '');
+ GeneralPostingSetup.SetFilter("Overhead Applied Account", '<>%1', '');
+ GeneralPostingSetup.SetFilter("Purchase Variance Account", '<>%1', '');
+ if not GeneralPostingSetup.FindFirst() then begin
+ GeneralPostingSetup.SetRange("Sales Prepayments Account");
+ GeneralPostingSetup.SetRange("Purch. Prepayments Account");
+ if GeneralPostingSetup.FindFirst() then begin
+ SetGeneralPostingSetupPrepAccounts(GeneralPostingSetup);
+ GeneralPostingSetup.Modify(true);
+ end else begin
+ GeneralPostingSetup.SetRange("COGS Account (Interim)");
+ GeneralPostingSetup.SetRange("Direct Cost Applied Account");
+ GeneralPostingSetup.SetRange("Overhead Applied Account");
+ GeneralPostingSetup.SetRange("Purchase Variance Account");
+ if GeneralPostingSetup.FindFirst() then begin
+ SetGeneralPostingSetupInvtAccounts(GeneralPostingSetup);
+ SetGeneralPostingSetupMfgAccounts(GeneralPostingSetup);
+ SetGeneralPostingSetupPrepAccounts(GeneralPostingSetup);
+ GeneralPostingSetup.Modify(true);
+ end else begin
+ GeneralPostingSetup.SetRange("Purch. Account");
+ GeneralPostingSetup.SetRange("Purch. Credit Memo Account");
+ if GeneralPostingSetup.FindFirst() then begin
+ SetGeneralPostingSetupInvtAccounts(GeneralPostingSetup);
+ SetGeneralPostingSetupMfgAccounts(GeneralPostingSetup);
+ SetGeneralPostingSetupPrepAccounts(GeneralPostingSetup);
+ SetGeneralPostingSetupPurchAccounts(GeneralPostingSetup);
+ GeneralPostingSetup.Modify(true);
+ end else
+ FindGeneralPostingSetupInvtBase(GeneralPostingSetup);
+ end;
+ end;
+ end;
+ end;
+
+ procedure FindGeneralPostingSetupInvtToGL(var GeneralPostingSetup: Record "General Posting Setup")
+ begin
+ GeneralPostingSetup.SetRange("Gen. Bus. Posting Group", '');
+ GeneralPostingSetup.SetFilter("Gen. Prod. Posting Group", '<>%1', '');
+ GeneralPostingSetup.SetFilter("COGS Account", '<>%1', '');
+ GeneralPostingSetup.SetFilter("COGS Account (Interim)", '<>%1', '');
+ GeneralPostingSetup.SetFilter("Inventory Adjmt. Account", '<>%1', '');
+ GeneralPostingSetup.SetFilter("Direct Cost Applied Account", '<>%1', '');
+ GeneralPostingSetup.SetFilter("Overhead Applied Account", '<>%1', '');
+ GeneralPostingSetup.SetFilter("Purchase Variance Account", '<>%1', '');
+ GeneralPostingSetup.SetFilter("Invt. Accrual Acc. (Interim)", '<>%1', '');
+ if not GeneralPostingSetup.FindFirst() then begin
+ GeneralPostingSetup.SetRange("COGS Account (Interim)");
+ GeneralPostingSetup.SetRange("Direct Cost Applied Account");
+ GeneralPostingSetup.SetRange("Overhead Applied Account");
+ GeneralPostingSetup.SetRange("Purchase Variance Account");
+ GeneralPostingSetup.SetRange("Invt. Accrual Acc. (Interim)");
+ if GeneralPostingSetup.FindFirst() then begin
+ SetGeneralPostingSetupInvtAccounts(GeneralPostingSetup);
+ SetGeneralPostingSetupMfgAccounts(GeneralPostingSetup);
+ GeneralPostingSetup.Modify(true);
+ end else
+ FindGeneralPostingSetupInvtBase(GeneralPostingSetup);
+ end;
+ end;
+
+ procedure FindGenPostingSetupWithDefVAT(var GeneralPostingSetup: Record "General Posting Setup")
+ var
+ VATPostingSetup: Record "VAT Posting Setup";
+ GenBusPostingGroup: Record "Gen. Business Posting Group";
+ GenProdPostingGroup: Record "Gen. Product Posting Group";
+ begin
+ FindGeneralPostingSetupInvtFull(GeneralPostingSetup);
+ FindVATPostingSetupInvt(VATPostingSetup);
+ GenBusPostingGroup.Get(GeneralPostingSetup."Gen. Bus. Posting Group");
+ GenBusPostingGroup.Validate("Def. VAT Bus. Posting Group", VATPostingSetup."VAT Bus. Posting Group");
+ GenBusPostingGroup.Modify();
+ GenProdPostingGroup.Get(GeneralPostingSetup."Gen. Prod. Posting Group");
+ GenProdPostingGroup.Validate("Def. VAT Prod. Posting Group", VATPostingSetup."VAT Prod. Posting Group");
+ GenProdPostingGroup.Modify();
+ end;
+
+ procedure FindPaymentMethod(var PaymentMethod: Record "Payment Method")
+ begin
+ PaymentMethod.SetRange("Bal. Account No.", '');
+ if not PaymentMethod.FindFirst() then
+ CreatePaymentMethod(PaymentMethod);
+ end;
+
+ procedure FindPaymentTerms(var PaymentTerms: Record "Payment Terms")
+ begin
+ if not PaymentTerms.FindFirst() then
+ CreatePaymentTerms(PaymentTerms);
+ end;
+
+ procedure FindPaymentTermsCode(): Code[10]
+ var
+ PaymentTerms: Record "Payment Terms";
+ DateFormular_0D: DateFormula;
+ begin
+ Evaluate(DateFormular_0D, '<0D>');
+
+ if PaymentTerms.FieldActive("Due Date Calculation") then // Field is disabled on IT build
+ PaymentTerms.SetRange("Due Date Calculation", DateFormular_0D);
+ if not PaymentTerms.FindFirst() then
+ CreatePaymentTerms(PaymentTerms);
+ exit(PaymentTerms.Code);
+ end;
+
+ procedure FindPostCode(var PostCode: Record "Post Code")
+ begin
+ if not PostCode.FindFirst() then
+ CreatePostCode(PostCode);
+ end;
+
+ procedure FindGeneralJournalSourceCode(): Code[10]
+ var
+ GenJournalTemplate: Record "Gen. Journal Template";
+ begin
+ GenJournalTemplate.SetRange(Type, GenJournalTemplate.Type::General);
+ GenJournalTemplate.SetRange(Recurring, false);
+ GenJournalTemplate.SetFilter("Source Code", '<>%1', '');
+ GenJournalTemplate.FindFirst();
+ exit(GenJournalTemplate."Source Code");
+ end;
+
+ procedure FindVATBusinessPostingGroup(var VATBusinessPostingGroup: Record "VAT Business Posting Group")
+ begin
+ if not VATBusinessPostingGroup.FindFirst() then
+ CreateVATBusinessPostingGroup(VATBusinessPostingGroup);
+ end;
+
+ procedure FindVATProductPostingGroup(var VATProductPostingGroup: Record "VAT Product Posting Group")
+ begin
+ if not VATProductPostingGroup.FindFirst() then
+ CreateVATProductPostingGroup(VATProductPostingGroup);
+ end;
+
+ procedure FindVATPostingSetup(var VATPostingSetup: Record "VAT Posting Setup"; VATCalculationType: Enum "Tax Calculation Type")
+ begin
+ VATPostingSetup.SetFilter("VAT Bus. Posting Group", '<>%1', '');
+ VATPostingSetup.SetFilter("VAT Prod. Posting Group", '<>%1', '');
+ VATPostingSetup.SetFilter("Sales VAT Account", '<>%1', '');
+ VATPostingSetup.SetFilter("Purchase VAT Account", '<>%1', '');
+ VATPostingSetup.SetRange("VAT Calculation Type", VATCalculationType);
+ VATPostingSetup.SetFilter("VAT %", '>%1', 0);
+ if not VATPostingSetup.FindFirst() then
+ CreateVATPostingSetupWithAccounts(VATPostingSetup, VATCalculationType, LibraryRandom.RandDecInDecimalRange(10, 25, 0));
+ end;
+
+ procedure FindVATPostingSetupInvt(var VATPostingSetup: Record "VAT Posting Setup")
+ begin
+ VATPostingSetup.SetFilter("VAT Prod. Posting Group", '<>%1', '');
+ VATPostingSetup.SetFilter("VAT %", '<>%1', 0);
+ VATPostingSetup.SetRange("VAT Calculation Type", VATPostingSetup."VAT Calculation Type"::"Normal VAT");
+ if SearchPostingType <> SearchPostingType::Purchase then
+ VATPostingSetup.SetFilter("Sales VAT Account", '<>%1', '');
+ if SearchPostingType <> SearchPostingType::Sales then
+ VATPostingSetup.SetFilter("Purchase VAT Account", '<>%1', '');
+ if not VATPostingSetup.FindFirst() then
+ CreateVATPostingSetupWithAccounts(VATPostingSetup,
+ VATPostingSetup."VAT Calculation Type"::"Normal VAT", LibraryRandom.RandDecInDecimalRange(10, 25, 0));
+ end;
+
+ procedure FindZeroVATPostingSetup(var VATPostingSetup: Record "VAT Posting Setup"; VATCalculationType: Enum "Tax Calculation Type")
+ begin
+ VATPostingSetup.SetFilter("VAT Bus. Posting Group", '<>%1', '');
+ VATPostingSetup.SetFilter("VAT Prod. Posting Group", '<>%1', '');
+ VATPostingSetup.SetRange("VAT Calculation Type", VATCalculationType);
+ VATPostingSetup.SetRange("VAT %", 0);
+ if not VATPostingSetup.FindFirst() then
+ CreateVATPostingSetupWithAccounts(VATPostingSetup, VATCalculationType, 0);
+ end;
+
+ procedure FindUnrealVATPostingSetup(var VATPostingSetup: Record "VAT Posting Setup"; UnrealizedVATType: Option)
+ begin
+ VATPostingSetup.SetFilter("VAT Bus. Posting Group", '<>%1', '');
+ VATPostingSetup.SetFilter("VAT Prod. Posting Group", '<>%1', '');
+ VATPostingSetup.SetRange("VAT Calculation Type", VATPostingSetup."VAT Calculation Type"::"Normal VAT");
+ VATPostingSetup.SetRange("Unrealized VAT Type", UnrealizedVATType);
+ VATPostingSetup.SetFilter("VAT %", '>%1', 0);
+ if not VATPostingSetup.FindFirst() then begin
+ VATPostingSetup.SetRange("Unrealized VAT Type");
+ VATPostingSetup.FindFirst();
+ VATPostingSetup."Unrealized VAT Type" := UnrealizedVATType;
+ if VATPostingSetup."Sales VAT Unreal. Account" = '' then
+ VATPostingSetup.Validate("Sales VAT Unreal. Account", CreateGLAccountNo());
+ if VATPostingSetup."Purch. VAT Unreal. Account" = '' then
+ VATPostingSetup.Validate("Purch. VAT Unreal. Account", CreateGLAccountNo());
+ VATPostingSetup.Modify(true);
+ end;
+ end;
+
+ procedure FindVendorLedgerEntry(var VendorLedgerEntry: Record "Vendor Ledger Entry"; DocumentType: Enum "Gen. Journal Document Type"; DocumentNo: Code[20])
+ begin
+ // Finds the matching Vendor Ledger Entry from a General Journal Line.
+ VendorLedgerEntry.SetRange("Document Type", DocumentType);
+ VendorLedgerEntry.SetRange("Document No.", DocumentNo);
+ VendorLedgerEntry.FindFirst();
+ end;
+
+ procedure FindEmployeeLedgerEntry(var EmployeeLedgerEntry: Record "Employee Ledger Entry"; DocumentType: Enum "Gen. Journal Document Type"; DocumentNo: Code[20])
+ begin
+ // Finds the matching Vendor Ledger Entry from a General Journal Line.
+ EmployeeLedgerEntry.SetRange("Document Type", DocumentType);
+ EmployeeLedgerEntry.SetRange("Document No.", DocumentNo);
+ EmployeeLedgerEntry.FindFirst();
+ end;
+
+ procedure FindDeferralLine(var DeferralLine: Record "Deferral Line"; DeferralDocType: Enum "Deferral Document Type"; GenJnlBatchName: Code[10]; GenJnlTemplateName: Code[10]; DocType: Integer; DocNo: Code[20]; LineNo: Integer)
+ begin
+ DeferralLine.SetRange("Deferral Doc. Type", DeferralDocType);
+ DeferralLine.SetRange("Gen. Jnl. Batch Name", GenJnlBatchName);
+ DeferralLine.SetRange("Gen. Jnl. Template Name", GenJnlTemplateName);
+ DeferralLine.SetRange("Document Type", DocType);
+ DeferralLine.SetRange("Document No.", DocNo);
+ DeferralLine.SetRange("Line No.", LineNo);
+ DeferralLine.FindFirst();
+ end;
+
+ procedure GetAddReportingCurrency(): Code[10]
+ begin
+ GeneralLedgerSetup.Get();
+ exit(GeneralLedgerSetup."Additional Reporting Currency");
+ end;
+
+ procedure GetAllowPostingFrom(): Date
+ begin
+ GeneralLedgerSetup.Get();
+ exit(GeneralLedgerSetup."Allow Posting From");
+ end;
+
+ procedure GetAllowPostingTo(): Date
+ begin
+ GeneralLedgerSetup.Get();
+ exit(GeneralLedgerSetup."Allow Posting To");
+ end;
+
+ procedure GetAmountRoundingPrecision(): Decimal
+ begin
+ GeneralLedgerSetup.Get();
+ exit(GeneralLedgerSetup."Amount Rounding Precision");
+ end;
+
+ procedure GetCurrencyAmountRoundingPrecision(CurrencyCode: Code[10]): Decimal
+ var
+ Currency: Record Currency;
+ begin
+ Currency.Initialize(CurrencyCode);
+ exit(Currency."Amount Rounding Precision");
+ end;
+
+ procedure GetCurrencyCode("Code": Code[10]): Code[10]
+ begin
+ GeneralLedgerSetup.Get();
+ exit(GeneralLedgerSetup.GetCurrencyCode(Code));
+ end;
+
+ procedure GetDiscountPaymentTerm(var PaymentTerms: Record "Payment Terms")
+ begin
+ PaymentTerms.SetFilter("Due Date Calculation", '<>''''');
+ PaymentTerms.SetFilter("Discount Date Calculation", '<>''''');
+ PaymentTerms.SetFilter("Discount %", '>%1', 0);
+ if not PaymentTerms.FindFirst() then
+ CreatePaymentTermsDiscount(PaymentTerms, false);
+ end;
+
+ procedure GetGlobalDimensionCode(DimNo: Integer): Code[20]
+ begin
+ GeneralLedgerSetup.Get();
+ case DimNo of
+ 1:
+ exit(GeneralLedgerSetup."Global Dimension 1 Code");
+ 2:
+ exit(GeneralLedgerSetup."Global Dimension 2 Code");
+ end;
+ end;
+
+ procedure GetInvoiceRoundingPrecisionLCY(): Decimal
+ begin
+ GeneralLedgerSetup.Get();
+ exit(GeneralLedgerSetup."Inv. Rounding Precision (LCY)");
+ end;
+
+ procedure GetLCYCode(): Code[10]
+ begin
+ GeneralLedgerSetup.Get();
+ exit(GeneralLedgerSetup."LCY Code");
+ end;
+
+ procedure GetPaymentTermsDiscountPct(PaymentTerms: Record "Payment Terms"): Decimal
+ begin
+ exit(PaymentTerms."Discount %");
+ end;
+
+ procedure GetShortcutDimensionCode(DimNo: Integer): Code[20]
+ begin
+ GeneralLedgerSetup.Get();
+ case DimNo of
+ 1:
+ exit(GeneralLedgerSetup."Shortcut Dimension 1 Code");
+ 2:
+ exit(GeneralLedgerSetup."Shortcut Dimension 2 Code");
+ 3:
+ exit(GeneralLedgerSetup."Shortcut Dimension 3 Code");
+ 4:
+ exit(GeneralLedgerSetup."Shortcut Dimension 4 Code");
+ 5:
+ exit(GeneralLedgerSetup."Shortcut Dimension 5 Code");
+ 6:
+ exit(GeneralLedgerSetup."Shortcut Dimension 6 Code");
+ 7:
+ exit(GeneralLedgerSetup."Shortcut Dimension 7 Code");
+ 8:
+ exit(GeneralLedgerSetup."Shortcut Dimension 8 Code");
+ end;
+ end;
+
+ procedure GetUnitAmountRoundingPrecision(): Decimal
+ begin
+ GeneralLedgerSetup.Get();
+ exit(GeneralLedgerSetup."Unit-Amount Rounding Precision");
+ end;
+
+ procedure GetCombinedPostedDeferralLines(var TempPostedDeferralLine: Record "Posted Deferral Line" temporary; DocNo: Code[20])
+ var
+ PostedDeferralLine: Record "Posted Deferral Line";
+ begin
+ PostedDeferralLine.SetRange("Document No.", DocNo);
+ PostedDeferralLine.FindSet();
+ repeat
+ TempPostedDeferralLine.SetRange("Document No.", DocNo);
+ TempPostedDeferralLine.SetRange("Posting Date", PostedDeferralLine."Posting Date");
+ if not TempPostedDeferralLine.FindFirst() then begin
+ TempPostedDeferralLine.Init();
+ TempPostedDeferralLine."Document No." := DocNo;
+ TempPostedDeferralLine."Posting Date" := PostedDeferralLine."Posting Date";
+ TempPostedDeferralLine.Insert();
+ end;
+ TempPostedDeferralLine.Amount += PostedDeferralLine.Amount;
+ TempPostedDeferralLine.Modify();
+ until PostedDeferralLine.Next() = 0;
+ TempPostedDeferralLine.SetRange("Document No.");
+ TempPostedDeferralLine.SetRange("Posting Date");
+ end;
+
+ procedure GetCountryIntrastatCode(CountryRegionCode: Code[10]): Code[10]
+ var
+ CountryRegion: Record "Country/Region";
+ begin
+ CountryRegion.Get(CountryRegionCode);
+ exit(CountryRegion."Intrastat Code");
+ end;
+
+ procedure InvoiceAmountRounding(InvoiceAmont: Decimal; CurrencyCode: Code[10]): Decimal
+ var
+ Currency: Record Currency;
+ begin
+ // Round Invoice Amount.
+ Currency.Initialize(CurrencyCode);
+ exit(Round(InvoiceAmont, Currency."Invoice Rounding Precision", Currency.InvoiceRoundingDirection()));
+ end;
+
+ procedure IssueFinanceChargeMemo(FinanceChargeMemoHeader: Record "Finance Charge Memo Header")
+ var
+ IssueFinanceChargeMemos: Report "Issue Finance Charge Memos";
+ begin
+ FinanceChargeMemoHeader.SetRange("No.", FinanceChargeMemoHeader."No.");
+ Clear(IssueFinanceChargeMemos);
+ IssueFinanceChargeMemos.SetTableView(FinanceChargeMemoHeader);
+ IssueFinanceChargeMemos.UseRequestPage(false);
+ IssueFinanceChargeMemos.Run();
+ end;
+
+ procedure PostCustLedgerApplication(CustLedgerEntry: Record "Cust. Ledger Entry")
+ begin
+ // Post Application Entries.
+ CODEUNIT.Run(CODEUNIT::"CustEntry-Apply Posted Entries", CustLedgerEntry);
+ end;
+
+ procedure PostGeneralJnlLine(GenJournalLine: Record "Gen. Journal Line")
+ begin
+ CODEUNIT.Run(CODEUNIT::"Gen. Jnl.-Post Batch", GenJournalLine);
+ end;
+
+ procedure PostFAJournalLine(FAJournalLine: Record "FA Journal Line")
+ begin
+ CODEUNIT.Run(CODEUNIT::"FA Jnl.-Post Batch", FAJournalLine);
+ end;
+
+ procedure PostVendLedgerApplication(VendorLedgerEntry: Record "Vendor Ledger Entry")
+ begin
+ // Post Application Entries.
+ CODEUNIT.Run(CODEUNIT::"VendEntry-Apply Posted Entries", VendorLedgerEntry);
+ end;
+
+ procedure PostEmplLedgerApplication(EmployeeLedgerEntry: Record "Employee Ledger Entry")
+ begin
+ // Post Application Entries.
+ CODEUNIT.Run(CODEUNIT::"EmplEntry-Apply Posted Entries", EmployeeLedgerEntry);
+ end;
+
+ procedure PostBankAccReconciliation(BankAccReconciliation: Record "Bank Acc. Reconciliation")
+ begin
+ CODEUNIT.Run(CODEUNIT::"Bank Acc. Reconciliation Post", BankAccReconciliation);
+ end;
+
+ procedure ReverseTransaction(TransactionNo: Integer)
+ var
+ ReversalEntry: Record "Reversal Entry";
+ begin
+ ReversalEntry.SetHideDialog(true);
+ ReversalEntry.ReverseTransaction(TransactionNo);
+ end;
+
+ procedure RunAddnlReportingCurrency(CurrencyCode: Code[10]; DocumentNo: Code[20]; NewRetainedEarningsGLAccNo: Code[20])
+ var
+ AdjustAddReportingCurrency: Report "Adjust Add. Reporting Currency";
+ begin
+ // Run Additional Currency Reporting Report for ACY.
+ AdjustAddReportingCurrency.SetAddCurr(CurrencyCode);
+ AdjustAddReportingCurrency.InitializeRequest(DocumentNo, NewRetainedEarningsGLAccNo);
+ AdjustAddReportingCurrency.UseRequestPage(false);
+ AdjustAddReportingCurrency.Run();
+ end;
+
+ // New Exch. rate adjustment for v.20
+ procedure RunExchRateAdjustmentForDocNo(CurrencyCode: Code[10]; DocumentNo: Code[20])
+ begin
+ RunExchRateAdjustment(CurrencyCode, 0D, WorkDate(), 'Test', WorkDate(), DocumentNo, false);
+ end;
+
+ procedure RunExchRateAdjustmentForDocNo(CurrencyCode: Code[10]; DocumentNo: Code[20]; EndDate: Date)
+ begin
+ RunExchRateAdjustment(CurrencyCode, 0D, EndDate, 'Test', EndDate, DocumentNo, false);
+ end;
+
+ procedure RunExchRateAdjustmentSimple(CurrencyCode: Code[10]; EndDate: Date; PostingDate: Date)
+ begin
+ RunExchRateAdjustment(
+ CurrencyCode, 0D, EndDate, 'Test', PostingDate, LibraryUtility.GenerateGUID(), false);
+ end;
+
+ procedure RunExchRateAdjustment(CurrencyCode: Code[10]; StartDate: Date; EndDate: Date; PostingDescription: Text[50]; PostingDate: Date; PostingDocNo: Code[20]; AdjGLAcc: Boolean)
+ var
+ Currency: Record Currency;
+ ExchRateAdjustment: Report "Exch. Rate Adjustment";
+ begin
+ Currency.SetRange(Code, CurrencyCode);
+ ExchRateAdjustment.SetTableView(Currency);
+ ExchRateAdjustment.InitializeRequest2(
+ StartDate, EndDate, PostingDescription, PostingDate, PostingDocNo, true, AdjGLAcc);
+ ExchRateAdjustment.UseRequestPage(false);
+ ExchRateAdjustment.SetHideUI(true);
+ ExchRateAdjustment.Run();
+ end;
+
+ procedure RunAdjustGenJournalBalance(var GenJournalLine: Record "Gen. Journal Line")
+ begin
+ CODEUNIT.Run(CODEUNIT::"Adjust Gen. Journal Balance", GenJournalLine);
+ end;
+
+ [Scope('OnPrem')]
+ procedure RunReminderIssue(var ReminderIssue: Codeunit "Reminder-Issue")
+ begin
+ ReminderIssue.Run();
+ end;
+
+ [Scope('OnPrem')]
+ procedure RunFinChrgMemoIssue(var FinChrgMemoIssue: Codeunit "FinChrgMemo-Issue")
+ begin
+ FinChrgMemoIssue.Run();
+ end;
+
+ procedure SelectLastGenJnBatch(var GenJournalBatch: Record "Gen. Journal Batch")
+ var
+ GLAccount: Record "G/L Account";
+ begin
+ GenJournalBatch.SetRange("Journal Template Name", SelectGenJnlTemplate());
+ GenJournalBatch.SetRange("Bal. Account Type", GenJournalBatch."Bal. Account Type"::"G/L Account");
+ CreateGLAccount(GLAccount);
+ GenJournalBatch.FindLast();
+ GenJournalBatch.Validate("Bal. Account No.", GLAccount."No.");
+ GenJournalBatch.Modify(true);
+ end;
+
+ procedure SelectGenJnlBatch(var GenJournalBatch: Record "Gen. Journal Batch")
+ begin
+ LibraryJournals.SelectGenJournalBatch(GenJournalBatch, SelectGenJnlTemplate());
+ end;
+
+ procedure SelectGenJnlTemplate(): Code[10]
+ var
+ GenJournalTemplate: Record "Gen. Journal Template";
+ begin
+ exit(LibraryJournals.SelectGenJournalTemplate(GenJournalTemplate.Type::General, PAGE::"General Journal"));
+ end;
+
+ procedure SelectFAJournalBatch(var FAJournalBatch: Record "FA Journal Batch")
+ begin
+ // Select FA Journal Batch Name for FA Journal Line.
+ FAJournalBatch.SetRange("Journal Template Name", SelectFAJournalTemplate());
+ if FAJournalBatch.FindFirst() then
+ exit;
+ // Create New FA Journal Batch.
+ FAJournalBatch.Init();
+ FAJournalBatch.Validate("Journal Template Name", SelectFAJournalTemplate());
+ FAJournalBatch.Validate(Name,
+ CopyStr(LibraryUtility.GenerateRandomCode(FAJournalBatch.FieldNo(Name), DATABASE::"FA Journal Batch"),
+ 1, LibraryUtility.GetFieldLength(DATABASE::"FA Journal Batch", FAJournalBatch.FieldNo(Name))));
+ FAJournalBatch.Insert(true);
+ FAJournalBatch.Validate("No. Series", CreateNoSeriesCode());
+ FAJournalBatch.Modify(true);
+ end;
+
+ procedure SelectFAJournalTemplate(): Code[10]
+ var
+ FAJournalTemplate: Record "FA Journal Template";
+ begin
+ // Select FA Journal Template Name for FA Journal Line.
+ FAJournalTemplate.SetRange(Recurring, false);
+ if not FAJournalTemplate.FindFirst() then begin
+ FAJournalTemplate.Init();
+ FAJournalTemplate.Validate(
+ Name, CopyStr(LibraryUtility.GenerateRandomCode(FAJournalTemplate.FieldNo(Name), DATABASE::"FA Journal Template"),
+ 1, LibraryUtility.GetFieldLength(DATABASE::"FA Journal Template", FAJournalTemplate.FieldNo(Name))));
+ FAJournalTemplate.Validate(Recurring, false);
+ FAJournalTemplate.Insert(true);
+ end;
+ exit(FAJournalTemplate.Name);
+ end;
+
+ procedure SetBlockDeleteGLAccount(NewValue: Boolean) OldValue: Boolean
+ begin
+ GeneralLedgerSetup.SetLoadFields("Block Deletion of G/L Accounts");
+ GeneralLedgerSetup.Get();
+ OldValue := GeneralLedgerSetup."Block Deletion of G/L Accounts";
+ GeneralLedgerSetup.Validate("Block Deletion of G/L Accounts", NewValue);
+ GeneralLedgerSetup.Modify(true);
+ end;
+
+ procedure SetCurrencyGainLossAccounts(var Currency: Record Currency)
+ begin
+ Currency.Validate("Realized Losses Acc.", CreateGLAccountNo());
+ Currency.Validate("Realized Gains Acc.", CreateGLAccountNo());
+ Currency.Validate("Unrealized Losses Acc.", CreateGLAccountNo());
+ Currency.Validate("Unrealized Gains Acc.", CreateGLAccountNo());
+ Currency.Modify(true);
+ end;
+
+ procedure SetAddReportingCurrency(AdditionalReportingCurrency: Code[10])
+ begin
+ GeneralLedgerSetup.Get();
+ GeneralLedgerSetup."Additional Reporting Currency" := AdditionalReportingCurrency;
+ GeneralLedgerSetup.Modify(true);
+ end;
+
+ procedure SetAllowDDExportWitoutIBANAndSWIFT(ExportWithoutIBANAndSWIFT: Boolean)
+ begin
+ GeneralLedgerSetup.Get();
+ GeneralLedgerSetup.Validate("SEPA Export w/o Bank Acc. Data", ExportWithoutIBANAndSWIFT);
+ GeneralLedgerSetup.Modify(true);
+ end;
+
+ procedure SetAllowNonEuroExport(AllowNonEuroExport: Boolean)
+ begin
+ GeneralLedgerSetup.Get();
+ GeneralLedgerSetup.Validate("SEPA Non-Euro Export", AllowNonEuroExport);
+ GeneralLedgerSetup.Modify(true);
+ end;
+
+ procedure SetAllowPostingFromTo(FromDate: Date; ToDate: Date)
+ begin
+ GeneralLedgerSetup.Get();
+ GeneralLedgerSetup."Allow Posting From" := FromDate;
+ GeneralLedgerSetup."Allow Posting To" := ToDate;
+ GeneralLedgerSetup.Modify(true);
+ end;
+
+ procedure SetAllowPostingTo(ToDate: Date)
+ begin
+ GeneralLedgerSetup.Get();
+ GeneralLedgerSetup."Allow Posting To" := ToDate;
+ GeneralLedgerSetup.Modify(true);
+ end;
+
+ procedure SetAmountRoundingPrecision(AmountRoundingPrecision: Decimal)
+ begin
+ GeneralLedgerSetup.Get();
+ GeneralLedgerSetup."Amount Rounding Precision" := AmountRoundingPrecision;
+ GeneralLedgerSetup.Modify(true);
+ end;
+
+ procedure SetApplnRoundingPrecision(ApplnRoundingPrecision: Decimal)
+ begin
+ GeneralLedgerSetup.Get();
+ GeneralLedgerSetup.Validate("Appln. Rounding Precision", ApplnRoundingPrecision);
+ GeneralLedgerSetup.Modify(true);
+ end;
+
+ procedure SetBillToSellToVATCalc(BillToSellToVATCalc: Enum "G/L Setup VAT Calculation")
+ begin
+ GeneralLedgerSetup.Get();
+ GeneralLedgerSetup.Validate("Bill-to/Sell-to VAT Calc.", BillToSellToVATCalc);
+ GeneralLedgerSetup.Modify(true);
+ end;
+
+ procedure SetGlobalDimensionCode(DimNo: Integer; DimCode: Code[20])
+ begin
+ GeneralLedgerSetup.Get();
+ case DimNo of
+ 1:
+ GeneralLedgerSetup.Validate("Global Dimension 1 Code", DimCode);
+ 2:
+ GeneralLedgerSetup.Validate("Global Dimension 2 Code", DimCode);
+ end;
+ GeneralLedgerSetup.Modify(true);
+ end;
+
+ procedure SetAppliestoIdCustomer(var CustLedgerEntry: Record "Cust. Ledger Entry")
+ begin
+ // Set Applies-to ID.
+ CustLedgerEntry.LockTable();
+ CustLedgerEntry.FindFirst();
+ repeat
+ CustLedgerEntry.TestField(Open, true);
+ CustLedgerEntry.Validate("Applies-to ID", UserId);
+ if CustLedgerEntry."Amount to Apply" = 0 then begin
+ CustLedgerEntry.CalcFields("Remaining Amount");
+ CustLedgerEntry.Validate("Amount to Apply", CustLedgerEntry."Remaining Amount");
+ end;
+ CustLedgerEntry.Modify(true);
+ until CustLedgerEntry.Next() = 0;
+ end;
+
+ procedure SetAppliestoIdVendor(var VendorLedgerEntry: Record "Vendor Ledger Entry")
+ begin
+ // Set Applies-to ID.
+ VendorLedgerEntry.LockTable();
+ VendorLedgerEntry.FindFirst();
+ repeat
+ VendorLedgerEntry.TestField(Open, true);
+ VendorLedgerEntry.Validate("Applies-to ID", UserId);
+ if VendorLedgerEntry."Amount to Apply" = 0 then begin
+ VendorLedgerEntry.CalcFields("Remaining Amount");
+ VendorLedgerEntry.Validate("Amount to Apply", VendorLedgerEntry."Remaining Amount");
+ end;
+ VendorLedgerEntry.Modify(true);
+ until VendorLedgerEntry.Next() = 0;
+ end;
+
+ procedure SetAppliestoIdEmployee(var EmployeeLedgerEntry: Record "Employee Ledger Entry")
+ begin
+ // Set Applies-to ID.
+ EmployeeLedgerEntry.LockTable();
+ EmployeeLedgerEntry.FindFirst();
+ repeat
+ EmployeeLedgerEntry.TestField(Open, true);
+ EmployeeLedgerEntry.Validate("Applies-to ID", UserId);
+ if EmployeeLedgerEntry."Amount to Apply" = 0 then begin
+ EmployeeLedgerEntry.CalcFields("Remaining Amount");
+ EmployeeLedgerEntry.Validate("Amount to Apply", EmployeeLedgerEntry."Remaining Amount");
+ end;
+ EmployeeLedgerEntry.Modify(true);
+ until EmployeeLedgerEntry.Next() = 0;
+ end;
+
+ procedure SetApplyCustomerEntry(var CustLedgerEntry: Record "Cust. Ledger Entry"; AmountToApply: Decimal)
+ var
+ CustLedgerEntry2: Record "Cust. Ledger Entry";
+ begin
+ // Clear any existing applying entries.
+ CustLedgerEntry2.SetRange("Applying Entry", true);
+ CustLedgerEntry2.SetFilter("Entry No.", '<>%1', CustLedgerEntry."Entry No.");
+ if CustLedgerEntry2.FindSet() then
+ repeat
+ CustLedgerEntry2.Validate("Applying Entry", false);
+ CustLedgerEntry2.Modify(true);
+ until CustLedgerEntry2.Next() = 0;
+
+ // Clear Applies-to IDs
+ CustLedgerEntry2.Reset();
+ CustLedgerEntry2.SetFilter("Applies-to ID", '<>%1', '');
+ if CustLedgerEntry2.FindSet() then
+ repeat
+ CustLedgerEntry2.Validate("Applies-to ID", '');
+ CustLedgerEntry2.Modify(true);
+ until CustLedgerEntry2.Next() = 0;
+
+ // Apply Payment Entry on Posted Invoice.
+ CustLedgerEntry.Validate("Applying Entry", true);
+ CustLedgerEntry.Validate("Applies-to ID", UserId);
+ CustLedgerEntry.Validate("Amount to Apply", AmountToApply);
+ CustLedgerEntry.Modify(true);
+ CODEUNIT.Run(CODEUNIT::"Cust. Entry-Edit", CustLedgerEntry);
+ Commit();
+ end;
+
+ procedure SetApplyVendorEntry(var VendorLedgerEntry: Record "Vendor Ledger Entry"; AmountToApply: Decimal)
+ var
+ VendorLedgerEntry2: Record "Vendor Ledger Entry";
+ begin
+ // Clear any existing applying entries.
+ VendorLedgerEntry2.SetRange("Applying Entry", true);
+ VendorLedgerEntry2.SetFilter("Entry No.", '<>%1', VendorLedgerEntry."Entry No.");
+ if VendorLedgerEntry2.FindSet() then
+ repeat
+ VendorLedgerEntry2.Validate("Applying Entry", false);
+ VendorLedgerEntry2.Modify(true);
+ until VendorLedgerEntry2.Next() = 0;
+
+ // Clear Applies-to IDs.
+ VendorLedgerEntry2.Reset();
+ VendorLedgerEntry2.SetFilter("Applies-to ID", '<>%1', '');
+ if VendorLedgerEntry2.FindSet() then
+ repeat
+ VendorLedgerEntry2.Validate("Applies-to ID", '');
+ VendorLedgerEntry2.Modify(true);
+ until VendorLedgerEntry2.Next() = 0;
+
+ // Apply Payment Entry on Posted Invoice.
+ VendorLedgerEntry.Validate("Applying Entry", true);
+ VendorLedgerEntry.Validate("Applies-to ID", UserId);
+ VendorLedgerEntry.Validate("Amount to Apply", AmountToApply);
+ VendorLedgerEntry.Modify(true);
+ CODEUNIT.Run(CODEUNIT::"Vend. Entry-Edit", VendorLedgerEntry);
+ end;
+
+ procedure SetApplyEmployeeEntry(var EmployeeLedgerEntry: Record "Employee Ledger Entry"; AmountToApply: Decimal)
+ var
+ EmployeeLedgerEntry2: Record "Employee Ledger Entry";
+ begin
+ // Clear any existing applying entries.
+ EmployeeLedgerEntry2.SetRange("Applying Entry", true);
+ EmployeeLedgerEntry2.SetFilter("Entry No.", '<>%1', EmployeeLedgerEntry."Entry No.");
+ if EmployeeLedgerEntry2.FindSet() then
+ repeat
+ EmployeeLedgerEntry2.Validate("Applying Entry", false);
+ EmployeeLedgerEntry2.Modify(true);
+ until EmployeeLedgerEntry2.Next() = 0;
+
+ // Clear Applies-to IDs.
+ EmployeeLedgerEntry2.Reset();
+ EmployeeLedgerEntry2.SetFilter("Applies-to ID", '<>%1', '');
+ if EmployeeLedgerEntry2.FindSet() then
+ repeat
+ EmployeeLedgerEntry2.Validate("Applies-to ID", '');
+ EmployeeLedgerEntry2.Modify(true);
+ until EmployeeLedgerEntry2.Next() = 0;
+
+ // Apply Payment Entry on Posted Invoice.
+ EmployeeLedgerEntry.Validate("Applying Entry", true);
+ EmployeeLedgerEntry.Validate("Applies-to ID", UserId);
+ EmployeeLedgerEntry.Validate("Amount to Apply", AmountToApply);
+ EmployeeLedgerEntry.Modify(true);
+ CODEUNIT.Run(CODEUNIT::"Empl. Entry-Edit", EmployeeLedgerEntry);
+ end;
+
+ procedure SetEnableDataCheck(EnableDataCheck: Boolean)
+ begin
+ GeneralLedgerSetup.Get();
+ if GeneralLedgerSetup."Enable Data Check" <> EnableDataCheck then begin
+ GeneralLedgerSetup."Enable Data Check" := EnableDataCheck;
+ GeneralLedgerSetup.Modify();
+ end;
+ end;
+
+ procedure SetGLAccountDirectPostingFilter(var GLAccount: Record "G/L Account")
+ begin
+ GLAccount.SetRange(Blocked, false);
+ GLAccount.SetRange("Account Type", GLAccount."Account Type"::Posting);
+ GLAccount.SetRange("Direct Posting", true);
+ end;
+
+ procedure SetGLAccountNotBlankGroupsFilter(var GLAccount: Record "G/L Account")
+ begin
+ GLAccount.SetFilter("Gen. Bus. Posting Group", '<>%1', '');
+ GLAccount.SetFilter("Gen. Prod. Posting Group", '<>%1', '');
+ GLAccount.SetFilter("VAT Prod. Posting Group", '<>%1', '');
+ end;
+
+ procedure SetGeneralPostingSetupInvtAccounts(var GeneralPostingSetup: Record "General Posting Setup")
+ begin
+ if GeneralPostingSetup."COGS Account" = '' then
+ GeneralPostingSetup.Validate("COGS Account", CreateGLAccountNo());
+ if GeneralPostingSetup."COGS Account (Interim)" = '' then
+ GeneralPostingSetup.Validate("COGS Account (Interim)", CreateGLAccountNo());
+ if GeneralPostingSetup."Inventory Adjmt. Account" = '' then
+ GeneralPostingSetup.Validate("Inventory Adjmt. Account", CreateGLAccountNo());
+ if GeneralPostingSetup."Invt. Accrual Acc. (Interim)" = '' then
+ GeneralPostingSetup.Validate("Invt. Accrual Acc. (Interim)", CreateGLAccountNo());
+ end;
+
+ procedure SetGeneralPostingSetupMfgAccounts(var GeneralPostingSetup: Record "General Posting Setup")
+ begin
+ if GeneralPostingSetup."Direct Cost Applied Account" = '' then
+ GeneralPostingSetup.Validate("Direct Cost Applied Account", CreateGLAccountNo());
+ if GeneralPostingSetup."Overhead Applied Account" = '' then
+ GeneralPostingSetup.Validate("Overhead Applied Account", CreateGLAccountNo());
+ if GeneralPostingSetup."Purchase Variance Account" = '' then
+ GeneralPostingSetup.Validate("Purchase Variance Account", CreateGLAccountNo());
+ end;
+
+ procedure SetGeneralPostingSetupPrepAccounts(var GeneralPostingSetup: Record "General Posting Setup")
+ begin
+ if GeneralPostingSetup."Sales Prepayments Account" = '' then
+ GeneralPostingSetup.Validate("Sales Prepayments Account", CreateGLAccountNo());
+ if GeneralPostingSetup."Purch. Prepayments Account" = '' then
+ GeneralPostingSetup.Validate("Purch. Prepayments Account", CreateGLAccountNo());
+ end;
+
+ procedure SetGeneralPostingSetupPurchAccounts(var GeneralPostingSetup: Record "General Posting Setup")
+ begin
+ if GeneralPostingSetup."Purch. Account" = '' then
+ GeneralPostingSetup.Validate("Purch. Account", CreateGLAccountNo());
+ if GeneralPostingSetup."Purch. Line Disc. Account" = '' then
+ GeneralPostingSetup.Validate("Purch. Line Disc. Account", CreateGLAccountNo());
+ if GeneralPostingSetup."Purch. Inv. Disc. Account" = '' then
+ GeneralPostingSetup.Validate("Purch. Inv. Disc. Account", CreateGLAccountNo());
+ if GeneralPostingSetup."Purch. Credit Memo Account" = '' then
+ GeneralPostingSetup.Validate("Purch. Credit Memo Account", CreateGLAccountNo());
+ end;
+
+ procedure SetGeneralPostingSetupPurchPmtDiscAccounts(var GeneralPostingSetup: Record "General Posting Setup")
+ begin
+ if GeneralPostingSetup."Purch. Pmt. Disc. Debit Acc." = '' then
+ GeneralPostingSetup.Validate("Purch. Pmt. Disc. Debit Acc.", CreateGLAccountNo());
+ if GeneralPostingSetup."Purch. Pmt. Disc. Credit Acc." = '' then
+ GeneralPostingSetup.Validate("Purch. Pmt. Disc. Credit Acc.", CreateGLAccountNo());
+ if GeneralPostingSetup."Purch. Pmt. Tol. Debit Acc." = '' then
+ GeneralPostingSetup.Validate("Purch. Pmt. Tol. Debit Acc.", CreateGLAccountNo());
+ if GeneralPostingSetup."Purch. Pmt. Tol. Credit Acc." = '' then
+ GeneralPostingSetup.Validate("Purch. Pmt. Tol. Credit Acc.", CreateGLAccountNo());
+ end;
+
+ procedure SetGeneralPostingSetupSalesAccounts(var GeneralPostingSetup: Record "General Posting Setup")
+ begin
+ if GeneralPostingSetup."Sales Account" = '' then
+ GeneralPostingSetup.Validate("Sales Account", CreateGLAccountNo());
+ if GeneralPostingSetup."Sales Line Disc. Account" = '' then
+ GeneralPostingSetup.Validate("Sales Line Disc. Account", CreateGLAccountNo());
+ if GeneralPostingSetup."Sales Inv. Disc. Account" = '' then
+ GeneralPostingSetup.Validate("Sales Inv. Disc. Account", CreateGLAccountNo());
+ if GeneralPostingSetup."Sales Credit Memo Account" = '' then
+ GeneralPostingSetup.Validate("Sales Credit Memo Account", CreateGLAccountNo());
+ end;
+
+ procedure SetGeneralPostingSetupSalesPmtDiscAccounts(var GeneralPostingSetup: Record "General Posting Setup")
+ begin
+ if GeneralPostingSetup."Sales Pmt. Disc. Debit Acc." = '' then
+ GeneralPostingSetup.Validate("Sales Pmt. Disc. Debit Acc.", CreateGLAccountNo());
+ if GeneralPostingSetup."Sales Pmt. Disc. Credit Acc." = '' then
+ GeneralPostingSetup.Validate("Sales Pmt. Disc. Credit Acc.", CreateGLAccountNo());
+ if GeneralPostingSetup."Sales Pmt. Tol. Debit Acc." = '' then
+ GeneralPostingSetup.Validate("Sales Pmt. Tol. Debit Acc.", CreateGLAccountNo());
+ if GeneralPostingSetup."Sales Pmt. Tol. Credit Acc." = '' then
+ GeneralPostingSetup.Validate("Sales Pmt. Tol. Credit Acc.", CreateGLAccountNo());
+ end;
+
+ local procedure SetPostingGroupsOnPrepmtGLAccount(var GLAccount: Record "G/L Account"; GenPostingSetup: Record "General Posting Setup"; GenPostingType: Enum "General Posting Type"; VATCalcType: Enum "Tax Calculation Type"; SetupGLAccount: Record "G/L Account")
+ var
+ VATPostingSetup: Record "VAT Posting Setup";
+ begin
+ GLAccount."Gen. Posting Type" := GenPostingType;
+ GLAccount."Gen. Bus. Posting Group" := GenPostingSetup."Gen. Bus. Posting Group";
+ GLAccount."Gen. Prod. Posting Group" := GenPostingSetup."Gen. Prod. Posting Group";
+ CreatePrepaymentVATPostingSetup(VATPostingSetup, VATCalcType, GenPostingType, SetupGLAccount, GLAccount."No.");
+ GLAccount."VAT Bus. Posting Group" := VATPostingSetup."VAT Bus. Posting Group";
+ GLAccount."VAT Prod. Posting Group" := VATPostingSetup."VAT Prod. Posting Group";
+ GLAccount."Income/Balance" := GLAccount."Income/Balance"::"Balance Sheet";
+ GLAccount."Direct Posting" := true;
+ GLAccount.Modify();
+ end;
+
+ procedure SetInvRoundingPrecisionLCY(InvRoundingPrecisionLCY: Decimal)
+ begin
+ GeneralLedgerSetup.Get();
+ GeneralLedgerSetup.Validate("Inv. Rounding Precision (LCY)", InvRoundingPrecisionLCY);
+ GeneralLedgerSetup.Modify(true);
+ end;
+
+ procedure SetMaxVATDifferenceAllowed(MaxVATDifferenceAllowed: Decimal)
+ begin
+ GeneralLedgerSetup.Get();
+ GeneralLedgerSetup.Validate("Max. VAT Difference Allowed", MaxVATDifferenceAllowed);
+ GeneralLedgerSetup.Modify(true);
+ end;
+
+ procedure SetLCYCode(LCYCode: Code[10])
+ begin
+ GeneralLedgerSetup.Get();
+ GeneralLedgerSetup."LCY Code" := ''; // to avoid error on updating LCY Code
+ GeneralLedgerSetup.Validate("LCY Code", LCYCode);
+ GeneralLedgerSetup.Modify(true);
+ end;
+
+ procedure SetSearchGenPostingTypeAll()
+ begin
+ SearchPostingType := SearchPostingType::All;
+ end;
+
+ procedure SetSearchGenPostingTypePurch()
+ begin
+ SearchPostingType := SearchPostingType::Purchase;
+ end;
+
+ procedure SetSearchGenPostingTypeSales()
+ begin
+ SearchPostingType := SearchPostingType::Sales;
+ end;
+
+ procedure SetShortcutDimensionCode(DimNo: Integer; DimCode: Code[20])
+ begin
+ GeneralLedgerSetup.Get();
+ case DimNo of
+ 1:
+ GeneralLedgerSetup.Validate("Shortcut Dimension 1 Code", DimCode);
+ 2:
+ GeneralLedgerSetup.Validate("Shortcut Dimension 2 Code", DimCode);
+ 3:
+ GeneralLedgerSetup.Validate("Shortcut Dimension 3 Code", DimCode);
+ 4:
+ GeneralLedgerSetup.Validate("Shortcut Dimension 4 Code", DimCode);
+ 5:
+ GeneralLedgerSetup.Validate("Shortcut Dimension 5 Code", DimCode);
+ 6:
+ GeneralLedgerSetup.Validate("Shortcut Dimension 6 Code", DimCode);
+ 7:
+ GeneralLedgerSetup.Validate("Shortcut Dimension 7 Code", DimCode);
+ 8:
+ GeneralLedgerSetup.Validate("Shortcut Dimension 8 Code", DimCode);
+ end;
+ GeneralLedgerSetup.Modify(true);
+ end;
+
+ procedure SetUnrealizedVAT(UnrealizedVAT: Boolean)
+ begin
+ GeneralLedgerSetup.Get();
+ GeneralLedgerSetup.Validate("Unrealized VAT", UnrealizedVAT);
+ GeneralLedgerSetup.Modify(true);
+ end;
+
+ procedure SetVATRoundingType(Direction: Text[1])
+ begin
+ GeneralLedgerSetup.Get();
+ case Direction of
+ '<':
+ GeneralLedgerSetup."VAT Rounding Type" := GeneralLedgerSetup."VAT Rounding Type"::Down;
+ '>':
+ GeneralLedgerSetup."VAT Rounding Type" := GeneralLedgerSetup."VAT Rounding Type"::Up;
+ '=':
+ GeneralLedgerSetup."VAT Rounding Type" := GeneralLedgerSetup."VAT Rounding Type"::Nearest;
+ end;
+ GeneralLedgerSetup.Modify(true);
+ end;
+
+ procedure SetWorkDate()
+ var
+ GLEntry: Record "G/L Entry";
+ OK: Boolean;
+ begin
+ // Set workdate to date of last transaction or today
+ GLEntry.SetCurrentKey("G/L Account No.", "Posting Date");
+ OK := true;
+ repeat
+ GLEntry.SetFilter("G/L Account No.", '>%1', GLEntry."G/L Account No.");
+ GLEntry.SetFilter("Posting Date", '>%1', GLEntry."Posting Date");
+ if GLEntry.FindFirst() then begin
+ GLEntry.SetRange("G/L Account No.", GLEntry."G/L Account No.");
+ GLEntry.SetRange("Posting Date");
+ GLEntry.FindLast();
+ end else
+ OK := false
+ until not OK;
+
+ if GLEntry."Posting Date" = 0D then
+ WorkDate := Today
+ else
+ WorkDate := NormalDate(GLEntry."Posting Date");
+ end;
+
+ procedure SetupReportSelection(ReportUsage: Enum "Report Selection Usage"; ReportId: Integer)
+ var
+ ReportSelections: Record "Report Selections";
+ begin
+ ReportSelections.SetRange(Usage, ReportUsage);
+ ReportSelections.DeleteAll();
+ ReportSelections.Init();
+ ReportSelections.Validate(Usage, ReportUsage);
+ ReportSelections.Validate(Sequence, '1');
+ ReportSelections.Validate("Report ID", ReportId);
+ ReportSelections.Insert(true);
+ end;
+
+ procedure SuggestBankAccountReconciliation(var BankAccReconciliation: Record "Bank Acc. Reconciliation"; BankAccount: Record "Bank Account"; StatementType: Enum "Bank Acc. Rec. Stmt. Type"; IncludeChecks: Boolean)
+ var
+ SuggestBankAccReconLines: Report "Suggest Bank Acc. Recon. Lines";
+ begin
+ CreateBankAccReconciliation(BankAccReconciliation, BankAccount."No.", StatementType);
+
+ SuggestBankAccReconLines.SetStmt(BankAccReconciliation);
+ SuggestBankAccReconLines.SetTableView(BankAccount);
+ SuggestBankAccReconLines.InitializeRequest(WorkDate(), WorkDate(), IncludeChecks);
+ SuggestBankAccReconLines.UseRequestPage(false);
+
+ SuggestBankAccReconLines.Run();
+ end;
+
+ procedure UnapplyCustomerLedgerEntry(CustLedgerEntry: Record "Cust. Ledger Entry")
+ begin
+ LibraryERMUnapply.UnapplyCustomerLedgerEntry(CustLedgerEntry);
+ end;
+
+ procedure UnapplyVendorLedgerEntry(VendorLedgerEntry: Record "Vendor Ledger Entry")
+ begin
+ LibraryERMUnapply.UnapplyVendorLedgerEntry(VendorLedgerEntry);
+ end;
+
+ procedure UnapplyEmployeeLedgerEntry(EmployeeLedgerEntry: Record "Employee Ledger Entry")
+ begin
+ LibraryERMUnapply.UnapplyEmployeeLedgerEntry(EmployeeLedgerEntry);
+ end;
+
+ procedure UpdateAnalysisView(var AnalysisView: Record "Analysis View")
+ begin
+ CODEUNIT.Run(CODEUNIT::"Update Analysis View", AnalysisView)
+ end;
+
+ procedure UpdateGenPostingSetupPrepmtAccounts(var GeneralPostingSetup: Record "General Posting Setup")
+ begin
+ GeneralPostingSetup.Validate("Sales Prepayments Account", CreateGLAccountWithSalesSetup());
+ GeneralPostingSetup.Validate("Purch. Prepayments Account", CreateGLAccountWithPurchSetup());
+ GeneralPostingSetup.Modify();
+ end;
+
+ procedure UpdateGLAccountWithPostingSetup(var GLAccount: Record "G/L Account"; GenPostingType: Enum "General Posting Type"; GeneralPostingSetup: Record "General Posting Setup"; VATPostingSetup: Record "VAT Posting Setup")
+ begin
+ GLAccount.Validate("Gen. Posting Type", GenPostingType);
+ GLAccount.Validate("Gen. Bus. Posting Group", GeneralPostingSetup."Gen. Bus. Posting Group");
+ GLAccount.Validate("Gen. Prod. Posting Group", GeneralPostingSetup."Gen. Prod. Posting Group");
+ GLAccount.Validate("VAT Bus. Posting Group", VATPostingSetup."VAT Bus. Posting Group");
+ GLAccount.Validate("VAT Prod. Posting Group", VATPostingSetup."VAT Prod. Posting Group");
+ GLAccount.Modify(true);
+ end;
+
+ procedure UpdateVATPostingSetup(var VATPostingSetup: Record "VAT Posting Setup"; VATPercent: Integer)
+ begin
+ FindVATPostingSetup(VATPostingSetup, VATPostingSetup."VAT Calculation Type"::"Normal VAT");
+ VATPostingSetup."VAT %" := VATPercent;
+ VATPostingSetup.Modify(true);
+ end;
+
+ procedure UpdateCompanyAddress()
+ var
+ CompanyInformation: Record "Company Information";
+ PostCode: Record "Post Code";
+ begin
+ if not CompanyInformation.Get() then
+ CompanyInformation.Insert(true);
+
+ CompanyInformation.Validate(Name, LibraryUtility.GenerateRandomText(MaxStrLen(CompanyInformation.Name)));
+ CompanyInformation.Validate("Name 2", LibraryUtility.GenerateRandomText(MaxStrLen(CompanyInformation."Name 2")));
+ CompanyInformation.Validate(Address, LibraryUtility.GenerateRandomText(MaxStrLen(CompanyInformation.Address)));
+ CompanyInformation.Validate("Address 2", LibraryUtility.GenerateRandomText(MaxStrLen(CompanyInformation."Address 2")));
+ CompanyInformation.Validate(Name, LibraryUtility.GenerateRandomText(MaxStrLen(CompanyInformation.Name)));
+ FindPostCode(PostCode);
+
+ CompanyInformation.Validate("Post Code", PostCode.Code);
+ CompanyInformation.Modify(true);
+ end;
+
+ procedure UpdateSalesPrepmtAccountVATGroup(GenBusPostingGroupCode: Code[20]; GenProdPostingGroupCode: Code[20]; NewVATProdPostingGroupCode: Code[20])
+ var
+ GeneralPostingSetup: Record "General Posting Setup";
+ GLAccount: Record "G/L Account";
+ begin
+ GeneralPostingSetup.Get(GenBusPostingGroupCode, GenProdPostingGroupCode);
+ GLAccount.Get(GeneralPostingSetup."Sales Prepayments Account");
+ GLAccount."VAT Prod. Posting Group" := NewVATProdPostingGroupCode;
+ GLAccount.Modify();
+ end;
+
+ procedure UpdatePurchPrepmtAccountVATGroup(GenBusPostingGroupCode: Code[20]; GenProdPostingGroupCode: Code[20]; NewVATProdPostingGroupCode: Code[20])
+ var
+ GeneralPostingSetup: Record "General Posting Setup";
+ GLAccount: Record "G/L Account";
+ begin
+ GeneralPostingSetup.Get(GenBusPostingGroupCode, GenProdPostingGroupCode);
+ GLAccount.Get(GeneralPostingSetup."Purch. Prepayments Account");
+ GLAccount."VAT Prod. Posting Group" := NewVATProdPostingGroupCode;
+ GLAccount.Modify();
+ end;
+
+ procedure VATAmountRounding(VATAmount: Decimal; CurrencyCode: Code[10]): Decimal
+ var
+ Currency: Record Currency;
+ begin
+ // Round VAT Entry Amount.
+ Currency.InitRoundingPrecision();
+ if CurrencyCode <> '' then
+ Currency.Get(CurrencyCode);
+
+ exit(Round(VATAmount, Currency."Amount Rounding Precision", Currency.VATRoundingDirection()));
+ end;
+
+ procedure VerifyVendApplnWithZeroTransNo(DocumentNo: Code[20]; DocumentType: Enum "Gen. Journal Document Type"; AmountLCY: Decimal)
+ var
+ DtldVendLedgEntry: Record "Detailed Vendor Ledg. Entry";
+ begin
+ DtldVendLedgEntry.SetRange("Document Type", DocumentType);
+ DtldVendLedgEntry.SetRange("Document No.", DocumentNo);
+ DtldVendLedgEntry.SetRange("Entry Type", DtldVendLedgEntry."Entry Type"::Application);
+ DtldVendLedgEntry.FindLast();
+ DtldVendLedgEntry.TestField("Transaction No.", 0);
+ DtldVendLedgEntry.TestField("Application No.");
+ DtldVendLedgEntry.TestField("Amount (LCY)", AmountLCY);
+ end;
+
+ procedure VerifyCustApplnWithZeroTransNo(DocumentNo: Code[20]; DocumentType: Enum "Gen. Journal Document Type"; AmountLCY: Decimal)
+ var
+ DtldCustLedgEntry: Record "Detailed Cust. Ledg. Entry";
+ begin
+ DtldCustLedgEntry.SetRange("Document Type", DocumentType);
+ DtldCustLedgEntry.SetRange("Document No.", DocumentNo);
+ DtldCustLedgEntry.SetRange("Entry Type", DtldCustLedgEntry."Entry Type"::Application);
+ DtldCustLedgEntry.FindLast();
+ DtldCustLedgEntry.TestField("Transaction No.", 0);
+ DtldCustLedgEntry.TestField("Application No.");
+ DtldCustLedgEntry.TestField("Amount (LCY)", AmountLCY);
+ end;
+
+ procedure UpdateAmountOnGenJournalLine(GenJournalBatch: Record "Gen. Journal Batch"; var GeneralJournal: TestPage "General Journal")
+ var
+ GenJournalLine: Record "Gen. Journal Line";
+ begin
+ GeneralJournal.OK().Invoke(); // Need to close the Page to ensure changes are reflected on Record Variable.
+ GenJournalLine.SetRange("Journal Template Name", GenJournalBatch."Journal Template Name");
+ GenJournalLine.SetRange("Journal Batch Name", GenJournalBatch.Name);
+ GenJournalLine.FindFirst();
+ GenJournalLine.Validate(Amount, LibraryRandom.RandDec(100, 2)); // Update Random Amount.
+ GenJournalLine.Modify(true);
+ GeneralJournal.OpenEdit();
+ GeneralJournal.CurrentJnlBatchName.SetValue(GenJournalBatch.Name);
+ end;
+
+ procedure FillSalesHeaderExcludedFieldList(var FieldListToExclude: List of [Text])
+ var
+ SalesHeaderRef: Record "Sales Header";
+ begin
+ FieldListToExclude.Add(SalesHeaderRef.FieldName("Document Type"));
+ FieldListToExclude.Add(SalesHeaderRef.FieldName("Quote No."));
+ FieldListToExclude.Add(SalesHeaderRef.FieldName("No."));
+ FieldListToExclude.Add(SalesHeaderRef.FieldName("Posting Date"));
+ FieldListToExclude.Add(SalesHeaderRef.FieldName("VAT Reporting Date"));
+ FieldListToExclude.Add(SalesHeaderRef.FieldName("Posting Description"));
+ FieldListToExclude.Add(SalesHeaderRef.FieldName("No. Series"));
+ FieldListToExclude.Add(SalesHeaderRef.FieldName("Prepayment No. Series"));
+ FieldListToExclude.Add(SalesHeaderRef.FieldName("Prepmt. Cr. Memo No. Series"));
+ FieldListToExclude.Add(SalesHeaderRef.FieldName("Shipping No. Series"));
+
+ OnAfterFillSalesHeaderExcludedFieldList(FieldListToExclude);
+ end;
+
+ procedure GetDeletionBlockedAfterDate(): Date
+ var
+ DocumentsRetentionPeriod: Interface "Documents - Retention Period";
+ DeletionBlockedAfterDate: Date;
+ begin
+ GeneralLedgerSetup.Get();
+ DocumentsRetentionPeriod := GeneralLedgerSetup."Document Retention Period";
+ DeletionBlockedAfterDate := DocumentsRetentionPeriod.GetDeletionBlockedAfterDate();
+ if DeletionBlockedAfterDate = 0D then
+ exit(WorkDate());
+ exit(DeletionBlockedAfterDate);
+ end;
+
+ procedure UpdateDirectCostNonInventoryAppliedAccountInGeneralPostingSetup(var GeneralPostingSetup: Record "General Posting Setup")
+ begin
+ GeneralPostingSetup.Validate("Direct Cost Non-Inv. App. Acc.", CreateGLAccountNo());
+ GeneralPostingSetup.Modify();
+ end;
+
+ [IntegrationEvent(false, false)]
+ local procedure OnAfterCreatePaymentTerms(var PaymentTerms: Record "Payment Terms")
+ begin
+ end;
+
+ [IntegrationEvent(false, false)]
+ local procedure OnAfterCreatePostCode(var PostCode: Record "Post Code")
+ begin
+ end;
+
+ [IntegrationEvent(false, false)]
+ local procedure OnBeforeCreatePrepaymentVATPostingSetup(var VATPostingSetup: Record "VAT Posting Setup"; VATCalcType: Enum "Tax Calculation Type"; GenPostingType: Enum "General Posting Type"; SetupGLAccount: Record "G/L Account"; VATAccountNo: Code[20]; var Handled: Boolean)
+ begin
+ end;
+
+ [IntegrationEvent(false, false)]
+ local procedure OnAfterCreatePrepaymentVATPostingSetup(var VATPostingSetup: Record "VAT Posting Setup"; VATCalcType: Enum "Tax Calculation Type"; GenPostingType: Enum "General Posting Type"; SetupGLAccount: Record "G/L Account"; VATAccountNo: Code[20])
+ begin
+ end;
+
+ [IntegrationEvent(false, false)]
+ local procedure OnBeforeCreateVATPostingSetupWithAccounts(var VATPostingSetup: Record "VAT Posting Setup"; VATCalculationType: Enum "Tax Calculation Type"; VATRate: Decimal; var IsHandled: Boolean)
+ begin
+ end;
+
+ [IntegrationEvent(false, false)]
+ local procedure OnBeforeSetPostingGroupsOnPrepmtGLAccount(var LineGLAccount: Record "G/L Account"; var PrepmtGLAccount: Record "G/L Account"; GenPostingType: Enum "General Posting Type"; VATCalcType: Option "Normal VAT","Reverse Charge VAT","Full VAT","Sales Tax"; PrepmtVATCalcType: Option; var Handled: Boolean)
+ begin
+ end;
+
+ [IntegrationEvent(false, false)]
+ local procedure OnAfterSetPostingGroupsOnPrepmtGLAccount(var LineGLAccount: Record "G/L Account"; var PrepmtGLAccount: Record "G/L Account"; GenPostingType: Enum "General Posting Type"; VATCalcType: Option "Normal VAT","Reverse Charge VAT","Full VAT","Sales Tax"; PrepmtVATCalcType: Option)
+ begin
+ end;
+
+ [IntegrationEvent(false, false)]
+ local procedure OnBeforeCreateVATPostingSetup(var VATPostingSetup: Record "VAT Posting Setup"; var Handled: Boolean)
+ begin
+ end;
+
+ [IntegrationEvent(false, false)]
+ local procedure OnAfterCreateVATPostingSetup(var VATPostingSetup: Record "VAT Posting Setup")
+ begin
+ end;
+
+ [IntegrationEvent(false, false)]
+ local procedure OnBeforeCreateVATProductPostingGroup(var VATProductPostingGroup: Record "VAT Product Posting Group"; var Handled: Boolean)
+ begin
+ end;
+
+ [IntegrationEvent(false, false)]
+ local procedure OnAfterCreateVATProductPostingGroup(var VATProductPostingGroup: Record "VAT Product Posting Group")
+ begin
+ end;
+
+ [IntegrationEvent(false, false)]
+ local procedure OnAfterFillSalesHeaderExcludedFieldList(var FieldListToExclude: List of [Text])
+ begin
+ end;
+}
+
diff --git a/Apps/W1/ApplicationTestLibrary/LibraryERMCountryData.Codeunit.al b/Apps/W1/ApplicationTestLibrary/LibraryERMCountryData.Codeunit.al
new file mode 100644
index 0000000000..2171ff258d
--- /dev/null
+++ b/Apps/W1/ApplicationTestLibrary/LibraryERMCountryData.Codeunit.al
@@ -0,0 +1,305 @@
+///
+/// Provides procedures to create and initialize country-specific demo data for ERM scenarios that exists in W1 but may be missing in localized versions.
+///
+codeunit 131305 "Library - ERM Country Data"
+{
+
+ trigger OnRun()
+ begin
+ end;
+
+ procedure InitializeCountry()
+ begin
+ exit;
+ end;
+
+ procedure CreateVATData()
+ begin
+ exit;
+ end;
+
+ procedure GetVATCalculationType(): Enum "Tax Calculation Type"
+ begin
+ exit("Tax Calculation Type"::"Normal VAT");
+ end;
+
+ [Scope('OnPrem')]
+ procedure GetReportSelectionsUsagePurchaseQuote(): Integer
+ var
+ ReportSelections: Record "Report Selections";
+ begin
+ exit(ReportSelections.Usage::"P.Quote".AsInteger());
+ end;
+
+ [Scope('OnPrem')]
+ procedure GetReportSelectionsUsageSalesQuote(): Integer
+ var
+ ReportSelections: Record "Report Selections";
+ begin
+ exit(ReportSelections.Usage::"S.Quote".AsInteger());
+ end;
+
+ procedure SetupCostAccounting()
+ begin
+ exit;
+ end;
+
+ procedure SetupReportSelections()
+ var
+ DummyReportSelections: Record "Report Selections";
+ LibraryERM: Codeunit "Library - ERM";
+ begin
+ LibraryERM.SetupReportSelection(DummyReportSelections.Usage::"S.Quote", REPORT::"Standard Sales - Quote");
+ LibraryERM.SetupReportSelection(DummyReportSelections.Usage::"S.Invoice", REPORT::"Standard Sales - Invoice");
+ LibraryERM.SetupReportSelection(DummyReportSelections.Usage::"S.Cr.Memo", REPORT::"Standard Sales - Credit Memo");
+ LibraryERM.SetupReportSelection(DummyReportSelections.Usage::"SM.Invoice", REPORT::"Service - Invoice");
+ LibraryERM.SetupReportSelection(DummyReportSelections.Usage::"SM.Credit Memo", REPORT::"Service - Credit Memo");
+ end;
+
+ procedure UpdateAccountInCustomerPostingGroup()
+ begin
+ exit;
+ end;
+
+ procedure UpdateAccountInVendorPostingGroups()
+ begin
+ exit;
+ end;
+
+ procedure UpdateAccountsInServiceContractAccountGroups()
+ begin
+ exit;
+ end;
+
+ procedure UpdateAccountInServiceCosts()
+ begin
+ exit;
+ end;
+
+ procedure UpdateCalendarSetup()
+ begin
+ exit;
+ end;
+
+ procedure UpdateGeneralPostingSetup()
+ begin
+ exit;
+ end;
+
+ procedure UpdateInventoryPostingSetup()
+ begin
+ exit;
+ end;
+
+ procedure UpdateGenJournalTemplate()
+ begin
+ exit;
+ end;
+
+ procedure UpdateGeneralLedgerSetup()
+ begin
+ exit;
+ end;
+
+ procedure UpdatePrepaymentAccounts()
+ begin
+ UpdateVATPostingSetupOnPrepAccount();
+ UpdateGenProdPostingSetupOnPrepAccount();
+ end;
+
+ procedure UpdatePurchasesPayablesSetup()
+ begin
+ UpdatePostingDateCheckonPostingPurchase();
+ end;
+
+ procedure SetDiscountPostingInPurchasePayablesSetup()
+ begin
+ exit;
+ end;
+
+ procedure UpdateSalesReceivablesSetup()
+ begin
+ UpdatePostingDateCheckonPostingSales();
+ end;
+
+ procedure SetDiscountPostingInSalesReceivablesSetup()
+ begin
+ exit;
+ end;
+
+ procedure UpdateGenProdPostingGroup()
+ begin
+ exit;
+ end;
+
+ procedure CreateGeneralPostingSetupData()
+ begin
+ exit;
+ end;
+
+ procedure CreateUnitsOfMeasure()
+ begin
+ exit;
+ end;
+
+ procedure CreateTransportMethodTableData()
+ begin
+ exit;
+ end;
+
+ procedure UpdateFAPostingGroup()
+ begin
+ exit;
+ end;
+
+ procedure UpdateFAPostingType()
+ begin
+ exit;
+ end;
+
+ procedure UpdateFAJnlTemplateName()
+ begin
+ exit;
+ end;
+
+ procedure UpdateJournalTemplMandatory(Mandatory: Boolean)
+ var
+ GeneralLedgerSetup: Record "General Ledger Setup";
+ begin
+ GeneralLedgerSetup.Get();
+ GeneralLedgerSetup.Validate("Journal Templ. Name Mandatory", Mandatory);
+ GeneralLedgerSetup.Modify(true);
+ end;
+
+ procedure CreateNewFiscalYear()
+ begin
+ exit;
+ end;
+
+ procedure UpdateVATPostingSetup()
+ begin
+ exit;
+ end;
+
+ procedure DisableActivateChequeNoOnGeneralLedgerSetup()
+ begin
+ exit;
+ end;
+
+ procedure RemoveBlankGenJournalTemplate()
+ begin
+ exit;
+ end;
+
+ procedure UpdateLocalPostingSetup()
+ begin
+ exit;
+ end;
+
+ procedure UpdateLocalData()
+ begin
+ exit;
+ end;
+
+ local procedure UpdateGenProdPostingSetupOnPrepAccount()
+ var
+ GeneralPostingSetup: Record "General Posting Setup";
+ GLAccount: Record "G/L Account";
+ begin
+ GeneralPostingSetup.SetFilter("Sales Prepayments Account", '<>%1', '');
+ if GeneralPostingSetup.FindSet() then
+ repeat
+ GLAccount.Get(GeneralPostingSetup."Sales Prepayments Account");
+ if GLAccount."Gen. Prod. Posting Group" = '' then begin
+ GLAccount.Validate("Gen. Prod. Posting Group", GeneralPostingSetup."Gen. Prod. Posting Group");
+ GLAccount.Modify(true);
+ end;
+ until GeneralPostingSetup.Next() = 0;
+ GeneralPostingSetup.Reset();
+ GeneralPostingSetup.SetFilter("Purch. Prepayments Account", '<>%1', '');
+ if GeneralPostingSetup.FindSet() then
+ repeat
+ GLAccount.Get(GeneralPostingSetup."Purch. Prepayments Account");
+ if GLAccount."Gen. Prod. Posting Group" = '' then begin
+ GLAccount.Validate("Gen. Prod. Posting Group", GeneralPostingSetup."Gen. Prod. Posting Group");
+ GLAccount.Modify(true);
+ end;
+ until GeneralPostingSetup.Next() = 0;
+ end;
+
+ local procedure UpdateVATPostingSetupOnPrepAccount()
+ var
+ GeneralPostingSetup: Record "General Posting Setup";
+ GenProdPostingGroup: Record "Gen. Product Posting Group";
+ GLAccount: Record "G/L Account";
+ begin
+ GeneralPostingSetup.SetFilter("Sales Prepayments Account", '<>%1', '');
+ if GeneralPostingSetup.FindSet() then
+ repeat
+ GLAccount.Get(GeneralPostingSetup."Sales Prepayments Account");
+ if GLAccount."VAT Prod. Posting Group" = '' then begin
+ GenProdPostingGroup.Get(GeneralPostingSetup."Gen. Prod. Posting Group");
+ GLAccount.Validate("VAT Prod. Posting Group", GenProdPostingGroup."Def. VAT Prod. Posting Group");
+ GLAccount.Modify(true);
+ end;
+ until GeneralPostingSetup.Next() = 0;
+ GeneralPostingSetup.Reset();
+ GeneralPostingSetup.SetFilter("Purch. Prepayments Account", '<>%1', '');
+ if GeneralPostingSetup.FindSet() then
+ repeat
+ GLAccount.Get(GeneralPostingSetup."Purch. Prepayments Account");
+ if GLAccount."VAT Prod. Posting Group" = '' then begin
+ GenProdPostingGroup.Get(GeneralPostingSetup."Gen. Prod. Posting Group");
+ GLAccount.Validate("VAT Prod. Posting Group", GenProdPostingGroup."Def. VAT Prod. Posting Group");
+ GLAccount.Modify(true);
+ end;
+ until GeneralPostingSetup.Next() = 0;
+ end;
+
+ procedure CompanyInfoSetVATRegistrationNo()
+ var
+ CompanyInformation: Record "Company Information";
+ LibraryERM: Codeunit "Library - ERM";
+ begin
+ CompanyInformation.Get();
+ CompanyInformation."VAT Registration No." := LibraryERM.GenerateVATRegistrationNo(CompanyInformation."Country/Region Code");
+ CompanyInformation.Modify();
+ end;
+
+ procedure AmountOnBankAccountLedgerEntriesPage(var BankAccountLedgerEntries: TestPage "Bank Account Ledger Entries"): Decimal
+ var
+ EntryRemainingAmount: Decimal;
+ begin
+ if BankAccountLedgerEntries.Amount.Visible() then
+ EntryRemainingAmount := BankAccountLedgerEntries.Amount.AsDecimal()
+ else
+ if BankAccountLedgerEntries."Credit Amount".AsDecimal() <> 0 then
+ EntryRemainingAmount := -BankAccountLedgerEntries."Credit Amount".AsDecimal()
+ else
+ EntryRemainingAmount := BankAccountLedgerEntries."Debit Amount".AsDecimal();
+ exit(EntryRemainingAmount);
+ end;
+
+ procedure InsertRecordsToProtectedTables()
+ begin
+ end;
+
+ local procedure UpdatePostingDateCheckonPostingSales()
+ var
+ SalesReceivablesSetup: Record "Sales & Receivables Setup";
+ begin
+ SalesReceivablesSetup.Get();
+ SalesReceivablesSetup.Validate("Posting Date Check on Posting", false);
+ SalesReceivablesSetup.Modify(true);
+ end;
+
+ local procedure UpdatePostingDateCheckonPostingPurchase()
+ var
+ PurchasesPayablesSetup: Record "Purchases & Payables Setup";
+ begin
+ PurchasesPayablesSetup.Get();
+ PurchasesPayablesSetup.Validate("Posting Date Check on Posting", false);
+ PurchasesPayablesSetup.Modify(true);
+ end;
+}
+
diff --git a/Apps/W1/ApplicationTestLibrary/LibraryERMUnapply.Codeunit.al b/Apps/W1/ApplicationTestLibrary/LibraryERMUnapply.Codeunit.al
new file mode 100644
index 0000000000..3c99e46372
--- /dev/null
+++ b/Apps/W1/ApplicationTestLibrary/LibraryERMUnapply.Codeunit.al
@@ -0,0 +1,137 @@
+///
+/// Provides utility functions for unapplying customer and vendor ledger entries in test scenarios. This is an extension library for Library - ERM.
+///
+codeunit 131301 "Library - ERM Unapply"
+{
+
+ trigger OnRun()
+ begin
+ end;
+
+ procedure UnapplyCustomerLedgerEntry(CustLedgerEntry: Record "Cust. Ledger Entry")
+ begin
+ UnapplyCustomerLedgerEntryBase(CustLedgerEntry, 0D);
+ end;
+
+ procedure UnapplyVendorLedgerEntry(VendorLedgerEntry: Record "Vendor Ledger Entry")
+ begin
+ UnapplyVendorLedgerEntryBase(VendorLedgerEntry, 0D);
+ end;
+
+ procedure UnapplyEmployeeLedgerEntry(EmployeeLedgerEntry: Record "Employee Ledger Entry")
+ begin
+ UnapplyEmployeeLedgerEntryBase(EmployeeLedgerEntry, 0D);
+ end;
+
+ procedure UnapplyCustomerLedgerEntryBase(CustLedgerEntry: Record "Cust. Ledger Entry"; PostingDate: Date)
+ var
+ DetailedCustLedgEntry: Record "Detailed Cust. Ledg. Entry";
+ GenJournalLine: Record "Gen. Journal Line";
+ SourceCodeSetup: Record "Source Code Setup";
+ GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line";
+ begin
+#pragma warning disable AA0210
+ DetailedCustLedgEntry.SetRange("Entry Type", DetailedCustLedgEntry."Entry Type"::Application);
+ DetailedCustLedgEntry.SetRange("Customer No.", CustLedgerEntry."Customer No.");
+ DetailedCustLedgEntry.SetRange("Document No.", CustLedgerEntry."Document No.");
+ DetailedCustLedgEntry.SetRange("Cust. Ledger Entry No.", CustLedgerEntry."Entry No.");
+ DetailedCustLedgEntry.SetRange(Unapplied, false);
+#pragma warning restore AA0210
+ DetailedCustLedgEntry.FindFirst();
+ if PostingDate = 0D then
+ PostingDate := DetailedCustLedgEntry."Posting Date";
+ SourceCodeSetup.Get();
+ CustLedgerEntry.Get(DetailedCustLedgEntry."Cust. Ledger Entry No.");
+ GenJournalLine.Validate("Document No.", DetailedCustLedgEntry."Document No.");
+ GenJournalLine.Validate("Posting Date", PostingDate);
+ GenJournalLine.Validate("Account Type", GenJournalLine."Account Type"::Customer);
+ GenJournalLine.Validate("Account No.", DetailedCustLedgEntry."Customer No.");
+ GenJournalLine.Validate(Correction, true);
+ GenJournalLine.Validate("Document Type", GenJournalLine."Document Type"::" ");
+ GenJournalLine.Validate(Description, CustLedgerEntry.Description);
+ GenJournalLine.Validate("Shortcut Dimension 1 Code", CustLedgerEntry."Global Dimension 1 Code");
+ GenJournalLine.Validate("Shortcut Dimension 2 Code", CustLedgerEntry."Global Dimension 2 Code");
+ GenJournalLine.Validate("Posting Group", CustLedgerEntry."Customer Posting Group");
+ GenJournalLine.Validate("Source Type", GenJournalLine."Source Type"::Vendor);
+ GenJournalLine.Validate("Source No.", DetailedCustLedgEntry."Customer No.");
+ GenJournalLine.Validate("Source Code", SourceCodeSetup."Unapplied Sales Entry Appln.");
+ GenJournalLine.Validate("Source Currency Code", DetailedCustLedgEntry."Currency Code");
+ GenJournalLine.Validate("System-Created Entry", true);
+ GenJnlPostLine.UnapplyCustLedgEntry(GenJournalLine, DetailedCustLedgEntry);
+ end;
+
+ procedure UnapplyVendorLedgerEntryBase(VendorLedgerEntry: Record "Vendor Ledger Entry"; PostingDate: Date)
+ var
+ DetailedVendorLedgEntry: Record "Detailed Vendor Ledg. Entry";
+ GenJournalLine: Record "Gen. Journal Line";
+ SourceCodeSetup: Record "Source Code Setup";
+ GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line";
+ begin
+#pragma warning disable AA0210
+ DetailedVendorLedgEntry.SetRange("Entry Type", DetailedVendorLedgEntry."Entry Type"::Application);
+ DetailedVendorLedgEntry.SetRange("Vendor No.", VendorLedgerEntry."Vendor No.");
+ DetailedVendorLedgEntry.SetRange("Document No.", VendorLedgerEntry."Document No.");
+ DetailedVendorLedgEntry.SetRange("Vendor Ledger Entry No.", VendorLedgerEntry."Entry No.");
+ DetailedVendorLedgEntry.SetRange(Unapplied, false);
+#pragma warning restore AA0210
+ DetailedVendorLedgEntry.FindFirst();
+ if PostingDate = 0D then
+ PostingDate := DetailedVendorLedgEntry."Posting Date";
+ SourceCodeSetup.Get();
+ VendorLedgerEntry.Get(DetailedVendorLedgEntry."Vendor Ledger Entry No.");
+ GenJournalLine.Validate("Document No.", DetailedVendorLedgEntry."Document No.");
+ GenJournalLine.Validate("Posting Date", PostingDate);
+ GenJournalLine.Validate("Account Type", GenJournalLine."Account Type"::Vendor);
+ GenJournalLine.Validate("Account No.", DetailedVendorLedgEntry."Vendor No.");
+ GenJournalLine.Validate(Correction, true);
+ GenJournalLine.Validate("Document Type", GenJournalLine."Document Type"::" ");
+ GenJournalLine.Validate(Description, VendorLedgerEntry.Description);
+ GenJournalLine.Validate("Shortcut Dimension 1 Code", VendorLedgerEntry."Global Dimension 1 Code");
+ GenJournalLine.Validate("Shortcut Dimension 2 Code", VendorLedgerEntry."Global Dimension 2 Code");
+ GenJournalLine.Validate("Posting Group", VendorLedgerEntry."Vendor Posting Group");
+ GenJournalLine.Validate("Source Type", GenJournalLine."Source Type"::Vendor);
+ GenJournalLine.Validate("Source No.", DetailedVendorLedgEntry."Vendor No.");
+ GenJournalLine.Validate("Source Code", SourceCodeSetup."Unapplied Purch. Entry Appln.");
+ GenJournalLine.Validate("Source Currency Code", DetailedVendorLedgEntry."Currency Code");
+ GenJournalLine.Validate("System-Created Entry", true);
+ GenJnlPostLine.UnapplyVendLedgEntry(GenJournalLine, DetailedVendorLedgEntry);
+ end;
+
+ procedure UnapplyEmployeeLedgerEntryBase(EmployeeLedgerEntry: Record "Employee Ledger Entry"; PostingDate: Date)
+ var
+ DetailedEmployeeLedgerEntry: Record "Detailed Employee Ledger Entry";
+ GenJournalLine: Record "Gen. Journal Line";
+ SourceCodeSetup: Record "Source Code Setup";
+ GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line";
+ begin
+#pragma warning disable AA0210
+ DetailedEmployeeLedgerEntry.SetRange("Entry Type", DetailedEmployeeLedgerEntry."Entry Type"::Application);
+ DetailedEmployeeLedgerEntry.SetRange("Employee No.", EmployeeLedgerEntry."Employee No.");
+ DetailedEmployeeLedgerEntry.SetRange("Document No.", EmployeeLedgerEntry."Document No.");
+ DetailedEmployeeLedgerEntry.SetRange("Employee Ledger Entry No.", EmployeeLedgerEntry."Entry No.");
+ DetailedEmployeeLedgerEntry.SetRange(Unapplied, false);
+#pragma warning restore AA0210
+ DetailedEmployeeLedgerEntry.FindFirst();
+ if PostingDate = 0D then
+ PostingDate := DetailedEmployeeLedgerEntry."Posting Date";
+ SourceCodeSetup.Get();
+ EmployeeLedgerEntry.Get(DetailedEmployeeLedgerEntry."Employee Ledger Entry No.");
+ GenJournalLine.Validate("Document No.", DetailedEmployeeLedgerEntry."Document No.");
+ GenJournalLine.Validate("Posting Date", PostingDate);
+ GenJournalLine.Validate("Account Type", GenJournalLine."Account Type"::Employee);
+ GenJournalLine.Validate("Account No.", DetailedEmployeeLedgerEntry."Employee No.");
+ GenJournalLine.Validate(Correction, true);
+ GenJournalLine.Validate("Document Type", GenJournalLine."Document Type"::" ");
+ GenJournalLine.Validate(Description, EmployeeLedgerEntry.Description);
+ GenJournalLine.Validate("Posting Group", EmployeeLedgerEntry."Employee Posting Group");
+ GenJournalLine.Validate("Shortcut Dimension 1 Code", EmployeeLedgerEntry."Global Dimension 1 Code");
+ GenJournalLine.Validate("Shortcut Dimension 2 Code", EmployeeLedgerEntry."Global Dimension 2 Code");
+ GenJournalLine.Validate("Source Type", GenJournalLine."Source Type"::Vendor);
+ GenJournalLine.Validate("Source No.", DetailedEmployeeLedgerEntry."Employee No.");
+ GenJournalLine.Validate("Source Code", SourceCodeSetup."Unapplied Purch. Entry Appln.");
+ GenJournalLine.Validate("Source Currency Code", DetailedEmployeeLedgerEntry."Currency Code");
+ GenJournalLine.Validate("System-Created Entry", true);
+ GenJnlPostLine.UnapplyEmplLedgEntry(GenJournalLine, DetailedEmployeeLedgerEntry);
+ end;
+}
+
diff --git a/Apps/W1/ApplicationTestLibrary/LibraryFinanceChargeMemo.Codeunit.al b/Apps/W1/ApplicationTestLibrary/LibraryFinanceChargeMemo.Codeunit.al
new file mode 100644
index 0000000000..b5e2946b2f
--- /dev/null
+++ b/Apps/W1/ApplicationTestLibrary/LibraryFinanceChargeMemo.Codeunit.al
@@ -0,0 +1,61 @@
+///
+/// Provides utility functions for creating and managing finance charge memos in test scenarios.
+///
+codeunit 131350 "Library - Finance Charge Memo"
+{
+
+ trigger OnRun()
+ begin
+ end;
+
+ var
+ LibraryERM: Codeunit "Library - ERM";
+ LibraryRandom: Codeunit "Library - Random";
+ BegininingText: Label 'Posting Date must be %9.';
+ EndingText: Label 'Please pay the total of %7.';
+ LineDescription: Label '%4% finance Charge with Currency (%8) of %6.';
+ LineDescriptionNew: Label '%1% finance Charge with Currency (%2) of %3.';
+ PrecisionText: Label '', Locked = true;
+
+ procedure ComputeDescription(FinanceChargeTerms: Record "Finance Charge Terms"; var Description: Text[100]; var DocumentDate: Date; PostedDocumentNo: Code[20])
+ var
+ Currency: Record Currency;
+ CustLedgerEntry: Record "Cust. Ledger Entry";
+ Amount: Decimal;
+ begin
+ // To fetch the Decimal Places from the computed Amount, used Format with Currency Decimal Precision.
+ LibraryERM.FindCustomerLedgerEntry(CustLedgerEntry, CustLedgerEntry."Document Type"::Invoice, PostedDocumentNo);
+ CustLedgerEntry.CalcFields(Amount);
+ Currency.Get(CustLedgerEntry."Currency Code");
+ DocumentDate := CalcDate('<1D>', CalcDate(FinanceChargeTerms."Due Date Calculation", CustLedgerEntry."Due Date"));
+ Amount :=
+ Round(CustLedgerEntry.Amount * (DocumentDate - CustLedgerEntry."Due Date") / FinanceChargeTerms."Interest Period (Days)");
+ Description :=
+ StrSubstNo(
+ LineDescriptionNew, FinanceChargeTerms."Interest Rate", Currency.Code,
+ Format(Amount, 0, StrSubstNo(PrecisionText, Currency."Amount Decimal Places")));
+ end;
+
+ procedure CreateFinanceChargeTermAndText(var FinanceChargeTerms: Record "Finance Charge Terms")
+ var
+ FinanceChargeText: Record "Finance Charge Text";
+ begin
+ // Create Finance Charge Term with Random Interest Rate, Minimum Amount, Additional Amount, Grace Period, Interest Period and
+ // Due Date Calculation. Add Beginning, Ending Text for it. Take Minimum Amount less so that Finance Charge Memo can generate.
+ LibraryERM.CreateFinanceChargeTerms(FinanceChargeTerms);
+ FinanceChargeTerms.Validate("Interest Rate", LibraryRandom.RandInt(5));
+ FinanceChargeTerms.Validate("Minimum Amount (LCY)", 1 + LibraryRandom.RandDec(1, 2));
+ FinanceChargeTerms.Validate("Additional Fee (LCY)", LibraryRandom.RandInt(5));
+ Evaluate(FinanceChargeTerms."Grace Period", '<' + Format(LibraryRandom.RandInt(5)) + 'D>');
+ FinanceChargeTerms.Validate("Interest Period (Days)", LibraryRandom.RandInt(30));
+ Evaluate(FinanceChargeTerms."Due Date Calculation", '<' + Format(10 + LibraryRandom.RandInt(20)) + 'D>');
+ FinanceChargeTerms.Validate("Line Description", LineDescription);
+ FinanceChargeTerms.Validate("Post Additional Fee", true);
+ FinanceChargeTerms.Validate("Post Interest", true);
+ FinanceChargeTerms.Modify(true);
+ LibraryERM.CreateFinanceChargeText(
+ FinanceChargeText, FinanceChargeTerms.Code, FinanceChargeText.Position::Beginning, BegininingText);
+ LibraryERM.CreateFinanceChargeText(FinanceChargeText, FinanceChargeTerms.Code, FinanceChargeText.Position::Ending, EndingText);
+ end;
+}
+
diff --git a/Apps/W1/ApplicationTestLibrary/LibraryFiscalYear.Codeunit.al b/Apps/W1/ApplicationTestLibrary/LibraryFiscalYear.Codeunit.al
new file mode 100644
index 0000000000..4240b0464c
--- /dev/null
+++ b/Apps/W1/ApplicationTestLibrary/LibraryFiscalYear.Codeunit.al
@@ -0,0 +1,179 @@
+///
+/// Provides utility functions for creating, managing, and closing fiscal years in test scenarios.
+///
+codeunit 131302 "Library - Fiscal Year"
+{
+
+ trigger OnRun()
+ begin
+ end;
+
+ procedure CloseFiscalYear()
+ var
+ AccountingPeriod: Record "Accounting Period";
+ Counter: Integer;
+ begin
+ // Close All opened Fiscal Years.
+ AccountingPeriod.SetRange("New Fiscal Year", true);
+ AccountingPeriod.SetRange(Closed, false);
+ for Counter := 1 to AccountingPeriod.Count - 1 do begin
+ CODEUNIT.Run(CODEUNIT::"Fiscal Year-Close", AccountingPeriod);
+ if Counter < AccountingPeriod.Count then
+ AccountingPeriod.Next();
+ end;
+ Commit(); // Required because Modal Page Pops Up.
+ end;
+
+ procedure CloseAccountingPeriod()
+ var
+ AccountingPeriod: Record "Accounting Period";
+ begin
+ AccountingPeriod.SetRange(Closed, false);
+ AccountingPeriod.ModifyAll(Closed, true);
+ end;
+
+ procedure CreateFiscalYear()
+ var
+ Date: Record Date;
+ CreateFiscalYear: Report "Create Fiscal Year";
+ PeriodLength: DateFormula;
+ begin
+ // Find a Date to create a new Fiscal Year if no Fiscal Year exists in Demo Data.
+ Date.SetRange("Period Type", Date."Period Type"::Year);
+ Date.SetRange("Period No.", Date2DMY(WorkDate(), 3));
+ Date.FindFirst();
+
+ // Create a new Fiscal Year With Number of Periods = 12, Period Length = 1M.
+ Clear(CreateFiscalYear);
+ Evaluate(PeriodLength, '<1M>');
+ CreateFiscalYear.InitializeRequest(12, PeriodLength, Date."Period Start");
+ CreateFiscalYear.UseRequestPage(false);
+ CreateFiscalYear.HideConfirmationDialog(true);
+ CreateFiscalYear.Run();
+ end;
+
+ procedure CheckPostingDate(PostingDate: Date)
+ var
+ AccountingPeriod: Record "Accounting Period";
+ begin
+ // Check if Posting Date is outside the Accounting Period then Create New Fiscal Year and close it.
+ AccountingPeriod.FindLast();
+ if PostingDate > AccountingPeriod."Starting Date" then begin
+ CreateFiscalYear();
+ CloseFiscalYear();
+ end;
+ end;
+
+ procedure GetFirstPostingDate(Closed: Boolean): Date
+ var
+ AccountingPeriod: Record "Accounting Period";
+ begin
+ AccountingPeriod.SetRange(Closed, Closed);
+ AccountingPeriod.FindFirst();
+ exit(AccountingPeriod."Starting Date");
+ end;
+
+ procedure GetLastPostingDate(Closed: Boolean): Date
+ var
+ AccountingPeriod: Record "Accounting Period";
+ begin
+ AccountingPeriod.SetRange(Closed, Closed);
+ AccountingPeriod.FindLast();
+ exit(AccountingPeriod."Starting Date");
+ end;
+
+ procedure GetStatisticsPeriod(): Text
+ begin
+ exit('');
+ end;
+
+ procedure GetAccountingPeriodDate(PostingDate: Date): Date
+ var
+ AccountingPeriod: Record "Accounting Period";
+ begin
+ AccountingPeriod.SetRange("Starting Date", 0D, PostingDate);
+ AccountingPeriod.FindLast();
+ exit(AccountingPeriod."Starting Date");
+ end;
+
+ [Scope('OnPrem')]
+ procedure GetPastNewYearDate(NumberOfPastYears: Integer): Date
+ begin
+ exit(CalcDate(StrSubstNo('<-%1Y-CY>', NumberOfPastYears), WorkDate()));
+ end;
+
+ [Scope('OnPrem')]
+ procedure UpdateAllowGAccDeletionBeforeDateOnGLSetup(NewDate: Date)
+ var
+ GeneralLedgerSetup: Record "General Ledger Setup";
+ begin
+ GeneralLedgerSetup.Get();
+ GeneralLedgerSetup."Allow G/L Acc. Deletion Before" := NewDate;
+ GeneralLedgerSetup.Modify();
+ end;
+
+ procedure IdentifyOpenAccountingPeriod(): Date
+ var
+ AccountingPeriod: Record "Accounting Period";
+ begin
+ Clear(AccountingPeriod);
+ CloseAccountingPeriod();
+ AccountingPeriod.Init();
+ AccountingPeriod.Validate("Starting Date", CalcDate('<+1M>', GetLastPostingDate(true)));
+ AccountingPeriod.Insert(true);
+ exit(AccountingPeriod."Starting Date");
+ end;
+
+ procedure GetInitialPostingDate(): Date
+ begin
+ exit(GetFirstPostingDate(true));
+ end;
+
+ procedure FindAccountingPeriodStartEndDate(var StartDate: Date; var EndDate: Date; NumberOfPeriods: Integer)
+ var
+ AccountingPeriod: Record "Accounting Period";
+ begin
+ AccountingPeriod.FindSet();
+ StartDate := AccountingPeriod."Starting Date";
+ AccountingPeriod.Next(NumberOfPeriods);
+ EndDate := AccountingPeriod."Starting Date" - 1;
+ end;
+
+ procedure AccountingPeriodsExists(): Boolean
+ var
+ AccountingPeriod: Record "Accounting Period";
+ begin
+ exit(not AccountingPeriod.IsEmpty);
+ end;
+
+ procedure CreateClosedAccountingPeriods()
+ var
+ AccountingPeriod: Record "Accounting Period";
+ GLEntry: Record "G/L Entry";
+ CreateFiscalYear: Report "Create Fiscal Year";
+ Period: DateFormula;
+ i, j : integer;
+ begin
+ AccountingPeriod.DeleteAll();
+ Evaluate(Period, '<1M>');
+
+ GLEntry.SetCurrentKey("Posting Date");
+ GLEntry.SetAscending("Posting Date", true);
+ if GLEntry.FindFirst() then;
+ j := ((Date2DMY(Today(), 3) - Date2DMY(GLEntry."Posting Date", 3))) + 3;
+ if j < 10 then
+ j := 10;
+
+ for i := j downto 0 do begin
+ CreateFiscalYear.UseRequestPage(false);
+ CreateFiscalYear.InitializeRequest(12, Period, DMY2Date(1, 1, Date2DMY(Today, 3) + 3 - i));
+ CreateFiscalYear.HideConfirmationDialog(true);
+ CreateFiscalYear.Run();
+ clear(CreateFiscalYear);
+
+ AccountingPeriod.ModifyAll(Closed, true);
+ AccountingPeriod.ModifyAll("Date Locked", true);
+ end;
+ end;
+}
+
diff --git a/Apps/W1/ApplicationTestLibrary/LibraryFixedAsset.Codeunit.al b/Apps/W1/ApplicationTestLibrary/LibraryFixedAsset.Codeunit.al
new file mode 100644
index 0000000000..6510e58869
--- /dev/null
+++ b/Apps/W1/ApplicationTestLibrary/LibraryFixedAsset.Codeunit.al
@@ -0,0 +1,533 @@
+///
+/// Provides utility functions for creating and managing fixed assets, depreciation books, and FA posting in test scenarios.
+///
+codeunit 131330 "Library - Fixed Asset"
+{
+ Permissions = tabledata "FA Depreciation Book" = rimd,
+ tabledata "G/L Entry" = r;
+
+ trigger OnRun()
+ begin
+ end;
+
+ var
+ FASetup: Record "FA Setup";
+ LibraryERM: Codeunit "Library - ERM";
+ LibraryUtility: Codeunit "Library - Utility";
+ LibraryRandom: Codeunit "Library - Random";
+ Assert: Codeunit Assert;
+ FARegisterGLRegisterErr: Label 'There should be only one FA Register related to the last GL register.';
+
+ procedure CreateCommentLine(var CommentLine: Record "Comment Line"; TableName: Enum "Comment Line Table Name"; No: Code[20])
+ var
+ RecRef: RecordRef;
+ begin
+ CommentLine.Init();
+ CommentLine.Validate("Table Name", TableName);
+ CommentLine.Validate("No.", No);
+ RecRef.GetTable(CommentLine);
+ CommentLine.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, CommentLine.FieldNo("Line No.")));
+ CommentLine.Insert(true);
+ end;
+
+ procedure CreateDepreciationBook(var DepreciationBook: Record "Depreciation Book")
+ begin
+ DepreciationBook.Init();
+ DepreciationBook.Validate(
+ Code,
+ CopyStr(
+ LibraryUtility.GenerateRandomCode(DepreciationBook.FieldNo(Code), DATABASE::"Depreciation Book"),
+ 1, LibraryUtility.GetFieldLength(DATABASE::"Depreciation Book", DepreciationBook.FieldNo(Code))));
+ DepreciationBook.Validate(Description, DepreciationBook.Code); // Validating Description as Code because value is not important.
+ DepreciationBook.Insert(true);
+ end;
+
+ procedure CreateFADepreciationBook(var FADepreciationBook: Record "FA Depreciation Book"; FANo: Code[20]; DepreciationBookCode: Code[10])
+ begin
+ FADepreciationBook.Init();
+ FADepreciationBook.Validate("FA No.", FANo);
+ FADepreciationBook.Validate("Depreciation Book Code", DepreciationBookCode);
+ FADepreciationBook.Insert(true);
+ end;
+
+ procedure CreateFAAllocation(var FAAllocation: Record "FA Allocation"; "Code": Code[20]; AllocationType: Enum "FA Allocation Type")
+ var
+ RecRef: RecordRef;
+ begin
+ FAAllocation.Init();
+ FAAllocation.Validate(Code, Code);
+ FAAllocation.Validate("Allocation Type", AllocationType);
+ RecRef.GetTable(FAAllocation);
+ FAAllocation.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, FAAllocation.FieldNo("Line No.")));
+ FAAllocation.Insert(true);
+ end;
+
+ procedure CreateFAJournalLine(var FAJournalLine: Record "FA Journal Line"; JournalTemplateName: Code[10]; JournalBatchName: Code[10])
+ var
+ RecRef: RecordRef;
+ begin
+ // Create a Fixed Asset General Journal Entry.
+ FAJournalLine.Init();
+ FAJournalLine.Validate("Journal Template Name", JournalTemplateName);
+ FAJournalLine.Validate("Journal Batch Name", JournalBatchName);
+ RecRef.GetTable(FAJournalLine);
+ FAJournalLine.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, FAJournalLine.FieldNo("Line No.")));
+ FAJournalLine.Insert(true);
+ end;
+
+ procedure CreateFAJournalSetup(var FAJournalSetup: Record "FA Journal Setup"; DepreciationBookCode: Code[10]; UserID: Code[50])
+ begin
+ FAJournalSetup.Init();
+ FAJournalSetup.Validate("Depreciation Book Code", DepreciationBookCode);
+ FAJournalSetup.Validate("User ID", UserID);
+ FAJournalSetup.Insert(true);
+ end;
+
+ procedure CreateFAPostingGroup(var FAPostingGroup: Record "FA Posting Group")
+ begin
+ FAPostingGroup.Init();
+ FAPostingGroup.Validate(
+ Code,
+ CopyStr(
+ LibraryUtility.GenerateRandomCode(FAPostingGroup.FieldNo(Code), DATABASE::"FA Posting Group"),
+ 1, LibraryUtility.GetFieldLength(DATABASE::"FA Posting Group", FAPostingGroup.FieldNo(Code))));
+ FAPostingGroup.Validate("Acquisition Cost Account", LibraryERM.CreateGLAccountWithPurchSetup());
+ FAPostingGroup.Validate("Accum. Depreciation Account", LibraryERM.CreateGLAccountNo());
+ FAPostingGroup.Validate("Write-Down Account", LibraryERM.CreateGLAccountNo());
+ FAPostingGroup.Validate("Appreciation Account", LibraryERM.CreateGLAccountWithPurchSetup());
+ FAPostingGroup.Validate("Custom 1 Account", LibraryERM.CreateGLAccountNo());
+ FAPostingGroup.Validate("Custom 2 Account", LibraryERM.CreateGLAccountNo());
+ FAPostingGroup.Validate("Acq. Cost Acc. on Disposal", LibraryERM.CreateGLAccountWithPurchSetup());
+ FAPostingGroup.Validate("Accum. Depr. Acc. on Disposal", LibraryERM.CreateGLAccountNo());
+ FAPostingGroup.Validate("Write-Down Acc. on Disposal", LibraryERM.CreateGLAccountNo());
+ FAPostingGroup.Validate("Appreciation Acc. on Disposal", LibraryERM.CreateGLAccountNo());
+ FAPostingGroup.Validate("Custom 1 Account on Disposal", LibraryERM.CreateGLAccountNo());
+ FAPostingGroup.Validate("Custom 2 Account on Disposal", LibraryERM.CreateGLAccountNo());
+ FAPostingGroup.Validate("Gains Acc. on Disposal", LibraryERM.CreateGLAccountNo());
+ FAPostingGroup.Validate("Losses Acc. on Disposal", LibraryERM.CreateGLAccountNo());
+ FAPostingGroup.Validate("Book Val. Acc. on Disp. (Gain)", LibraryERM.CreateGLAccountNo());
+ FAPostingGroup.Validate("Sales Acc. on Disp. (Gain)", LibraryERM.CreateGLAccountNo());
+ FAPostingGroup.Validate("Write-Down Bal. Acc. on Disp.", LibraryERM.CreateGLAccountNo());
+ FAPostingGroup.Validate("Apprec. Bal. Acc. on Disp.", LibraryERM.CreateGLAccountNo());
+ FAPostingGroup.Validate("Custom 1 Bal. Acc. on Disposal", LibraryERM.CreateGLAccountNo());
+ FAPostingGroup.Validate("Custom 2 Bal. Acc. on Disposal", LibraryERM.CreateGLAccountNo());
+ FAPostingGroup.Validate("Maintenance Expense Account", LibraryERM.CreateGLAccountWithPurchSetup());
+ FAPostingGroup.Validate("Maintenance Bal. Acc.", LibraryERM.CreateGLAccountNo());
+ FAPostingGroup.Validate("Acquisition Cost Bal. Acc.", LibraryERM.CreateGLAccountNo());
+ FAPostingGroup.Validate("Depreciation Expense Acc.", LibraryERM.CreateGLAccountNo());
+ FAPostingGroup.Validate("Write-Down Expense Acc.", LibraryERM.CreateGLAccountNo());
+ FAPostingGroup.Validate("Appreciation Bal. Account", LibraryERM.CreateGLAccountNo());
+ FAPostingGroup.Validate("Custom 1 Expense Acc.", LibraryERM.CreateGLAccountNo());
+ FAPostingGroup.Validate("Custom 2 Expense Acc.", LibraryERM.CreateGLAccountNo());
+ FAPostingGroup.Validate("Sales Bal. Acc.", LibraryERM.CreateGLAccountNo());
+ FAPostingGroup.Validate("Sales Acc. on Disp. (Loss)", LibraryERM.CreateGLAccountNo());
+ FAPostingGroup.Validate("Book Val. Acc. on Disp. (Loss)", LibraryERM.CreateGLAccountNo());
+
+ FAPostingGroup.Insert(true);
+ end;
+
+ procedure CreateFAReclassJournal(var FAReclassJournalLine: Record "FA Reclass. Journal Line"; JournalTemplateName: Code[10]; JournalBatchName: Code[10])
+ var
+ RecRef: RecordRef;
+ begin
+ // Create a Fixed Asset Reclass Journal Entry.
+ FAReclassJournalLine.Init();
+ FAReclassJournalLine.Validate("Journal Template Name", JournalTemplateName);
+ FAReclassJournalLine.Validate("Journal Batch Name", JournalBatchName);
+ RecRef.GetTable(FAReclassJournalLine);
+ FAReclassJournalLine.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, FAReclassJournalLine.FieldNo("Line No.")));
+ FAReclassJournalLine.Insert(true);
+ end;
+
+ [Scope('OnPrem')]
+ procedure CreateFAReclassJournalTemplate(var FAReclassJournalTemplate: Record "FA Reclass. Journal Template")
+ begin
+ FAReclassJournalTemplate.Init();
+ FAReclassJournalTemplate.Name := LibraryUtility.GenerateGUID();
+ FAReclassJournalTemplate.Insert();
+ end;
+
+ procedure CreateFAReclassJournalBatch(var FAReclassJournalBatch: Record "FA Reclass. Journal Batch"; JournalTemplateName: Code[10])
+ begin
+ FAReclassJournalBatch.Init();
+ FAReclassJournalBatch.Validate("Journal Template Name", JournalTemplateName);
+ FAReclassJournalBatch.Validate(
+ Name,
+ CopyStr(
+ LibraryUtility.GenerateRandomCode(FAReclassJournalBatch.FieldNo(Name), DATABASE::"FA Reclass. Journal Batch"),
+ 1,
+ LibraryUtility.GetFieldLength(DATABASE::"FA Journal Batch", FAReclassJournalBatch.FieldNo(Name))));
+
+ // Validating Description as Name because value is not important.
+ FAReclassJournalBatch.Validate(Description, FAReclassJournalBatch.Name);
+ FAReclassJournalBatch.Insert(true);
+ end;
+
+ procedure CreateFAJournalBatch(var FAJournalBatch: Record "FA Journal Batch"; JournalTemplateName: Code[10])
+ begin
+ // creates a new FA Journal Batch named with the next available number (if it does not yet exist), OR
+ // returns the FA Journal batch named with the next available number
+
+ FAJournalBatch.Init();
+ FAJournalBatch.Validate("Journal Template Name", JournalTemplateName);
+ FAJournalBatch.Validate(
+ Name,
+ CopyStr(
+ LibraryUtility.GenerateRandomCode(FAJournalBatch.FieldNo(Name), DATABASE::"FA Journal Batch"),
+ 1,
+ LibraryUtility.GetFieldLength(DATABASE::"FA Journal Batch", FAJournalBatch.FieldNo(Name))));
+ FAJournalBatch.Validate(Description, FAJournalBatch.Name); // Validating Description as Name because value is not important.
+ if FAJournalBatch.Insert(true) then;
+ end;
+
+ procedure CreateFixedAsset(var FixedAsset: Record "Fixed Asset")
+ begin
+ LibraryUtility.UpdateSetupNoSeriesCode(DATABASE::"FA Setup", FASetup.FieldNo("Fixed Asset Nos."));
+
+ FixedAsset.Init();
+ FixedAsset.Insert(true);
+ FixedAsset.Validate(Description, FixedAsset."No."); // Validating Description as No because value is not important.
+ FixedAsset.Modify(true);
+ end;
+
+ procedure CreateFAWithPostingGroup(var FixedAsset: Record "Fixed Asset")
+ var
+ FAPostingGroup: Record "FA Posting Group";
+ begin
+ CreateFAPostingGroup(FAPostingGroup);
+ CreateFixedAsset(FixedAsset);
+ FixedAsset.Validate("FA Posting Group", FAPostingGroup.Code);
+ FixedAsset.Modify(true);
+ end;
+
+ procedure CreateFixedAssetWithSetup(var FixedAsset: Record "Fixed Asset")
+ var
+ FADeprBook: Record "FA Depreciation Book";
+ FAPostingGroup: Record "FA Posting Group";
+ VATPostingSetup: Record "VAT Posting Setup";
+ begin
+ CreateFixedAsset(FixedAsset);
+ CreateFAPostingGroup(FAPostingGroup);
+ LibraryERM.FindVATPostingSetupInvt(VATPostingSetup);
+ UpdateFAPostingGroupGLAccounts(FAPostingGroup, VATPostingSetup);
+ FADeprBook.ModifyAll("FA Posting Group", FAPostingGroup.Code);
+ FADeprBook.ModifyAll("No. of Depreciation Years", LibraryRandom.RandIntInRange(2, 5));
+ end;
+
+ procedure CreateFixedAssetNo(): Code[20]
+ var
+ FixedAsset: Record "Fixed Asset";
+ begin
+ CreateFixedAssetWithSetup(FixedAsset);
+ exit(FixedAsset."No.");
+ end;
+
+ procedure CreateGLBudgetName(var GLBudgetName: Record "G/L Budget Name")
+ begin
+ GLBudgetName.Init();
+ GLBudgetName.Validate(
+ Name,
+ CopyStr(
+ LibraryUtility.GenerateRandomCode(GLBudgetName.FieldNo(Name), DATABASE::"G/L Budget Name"),
+ 1,
+ LibraryUtility.GetFieldLength(DATABASE::"G/L Budget Name", GLBudgetName.FieldNo(Name))));
+
+ // Validating Description as Name because value is not important.
+ GLBudgetName.Validate(Description, GLBudgetName.Name);
+ GLBudgetName.Insert(true);
+ end;
+
+ procedure CreateInsurance(var Insurance: Record Insurance)
+ begin
+ LibraryUtility.UpdateSetupNoSeriesCode(DATABASE::"FA Setup", FASetup.FieldNo("Insurance Nos."));
+
+ Insurance.Init();
+ Insurance.Insert(true);
+ Insurance.Validate(Description, Insurance."No."); // Validating Description as No because value is not important.
+ Insurance.Modify(true);
+ end;
+
+ [Scope('OnPrem')]
+ procedure CreateInsuranceJournalTemplate(var InsuranceJournalTemplate: Record "Insurance Journal Template")
+ begin
+ InsuranceJournalTemplate.Init();
+ InsuranceJournalTemplate.Name := LibraryUtility.GenerateGUID();
+ InsuranceJournalTemplate.Insert();
+ end;
+
+ procedure CreateInsuranceJournalBatch(var InsuranceJournalBatch: Record "Insurance Journal Batch"; JournalTemplateName: Code[10])
+ begin
+ InsuranceJournalBatch.Init();
+ InsuranceJournalBatch.Validate("Journal Template Name", JournalTemplateName);
+ InsuranceJournalBatch.Validate(
+ Name,
+ CopyStr(
+ LibraryUtility.GenerateRandomCode(InsuranceJournalBatch.FieldNo(Name), DATABASE::"Insurance Journal Batch"),
+ 1,
+ LibraryUtility.GetFieldLength(DATABASE::"Insurance Journal Batch", InsuranceJournalBatch.FieldNo(Name))));
+
+ // Validating Description as Name because value is not important.
+ InsuranceJournalBatch.Validate(Description, InsuranceJournalBatch.Name);
+ InsuranceJournalBatch.Insert(true);
+ end;
+
+ procedure CreateInsuranceJournalLine(var InsuranceJournalLine: Record "Insurance Journal Line"; JournalTemplateName: Code[10]; JournalBatchName: Code[10])
+ var
+ RecRef: RecordRef;
+ begin
+ // Create an Insurance Journal Entry.
+ InsuranceJournalLine.Init();
+ InsuranceJournalLine.Validate("Journal Template Name", JournalTemplateName);
+ InsuranceJournalLine.Validate("Journal Batch Name", JournalBatchName);
+ RecRef.GetTable(InsuranceJournalLine);
+ InsuranceJournalLine.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, InsuranceJournalLine.FieldNo("Line No.")));
+ InsuranceJournalLine.Insert(true);
+ end;
+
+ procedure CreateMaintenance(var Maintenance: Record Maintenance)
+ begin
+ Maintenance.Init();
+ Maintenance.Validate(
+ Code,
+ CopyStr(
+ LibraryUtility.GenerateRandomCode(Maintenance.FieldNo(Code), DATABASE::Maintenance),
+ 1,
+ LibraryUtility.GetFieldLength(DATABASE::Maintenance, Maintenance.FieldNo(Code))));
+
+ // Validating Description as Code because value is not important.
+ Maintenance.Validate(Description, Maintenance.Code);
+ Maintenance.Insert(true);
+ end;
+
+ procedure CreateInsuranceType(var InsuranceType: Record "Insurance Type")
+ begin
+ InsuranceType.Init();
+ InsuranceType.Validate(
+ Code,
+ CopyStr(
+ LibraryUtility.GenerateRandomCode(InsuranceType.FieldNo(Code), DATABASE::"Insurance Type"),
+ 1,
+ LibraryUtility.GetFieldLength(DATABASE::"Insurance Type", InsuranceType.FieldNo(Code))));
+
+ // Validating Description as Code because value is not important.
+ InsuranceType.Validate(Description, InsuranceType.Code);
+ InsuranceType.Insert(true);
+ end;
+
+ procedure CreateJournalTemplate(var FAJournalTemplate: Record "FA Journal Template")
+ begin
+ FAJournalTemplate.Init();
+ FAJournalTemplate.Validate(
+ Name,
+ CopyStr(
+ LibraryUtility.GenerateRandomCode(FAJournalTemplate.FieldNo(Name), DATABASE::"FA Journal Template"),
+ 1,
+ LibraryUtility.GetFieldLength(DATABASE::"FA Journal Template", FAJournalTemplate.FieldNo(Name))));
+
+ // Validating Description as Name because value is not important.
+ FAJournalTemplate.Validate(Description, FAJournalTemplate.Name);
+ FAJournalTemplate.Insert(true);
+ end;
+
+ procedure CreateDepreciationTableHeader(var DepreciationTableHeader: Record "Depreciation Table Header")
+ begin
+ DepreciationTableHeader.Init();
+ DepreciationTableHeader.Validate(
+ Code,
+ CopyStr(
+ LibraryUtility.GenerateRandomCode(DepreciationTableHeader.FieldNo(Code), DATABASE::"Depreciation Table Header"),
+ 1,
+ LibraryUtility.GetFieldLength(DATABASE::"Depreciation Table Header", DepreciationTableHeader.FieldNo(Code))));
+
+ // Validating Description as Code because value is not important.
+ DepreciationTableHeader.Validate(Description, DepreciationTableHeader.Code);
+ DepreciationTableHeader.Insert(true);
+ end;
+
+ procedure CreateDepreciationTableLine(var DepreciationTableLine: Record "Depreciation Table Line"; DepreciationTableCode: Code[10])
+ begin
+ DepreciationTableLine.SetRange("Depreciation Table Code", DepreciationTableCode);
+ // Check if Lines are alredy exist.
+ if DepreciationTableLine.FindLast() then;
+ DepreciationTableLine.Init();
+ DepreciationTableLine.Validate("Depreciation Table Code", DepreciationTableCode);
+ DepreciationTableLine.Validate("Period No.", DepreciationTableLine."Period No." + 1);
+ DepreciationTableLine.Insert(true);
+ end;
+
+ procedure CreateMainAssetComponent(var MainAssetComponent: Record "Main Asset Component"; MainAssetNo: Code[20]; FANo: Code[20])
+ begin
+ MainAssetComponent.Init();
+ MainAssetComponent.Validate("Main Asset No.", MainAssetNo);
+ MainAssetComponent.Validate("FA No.", FANo);
+ MainAssetComponent.Insert(true);
+ end;
+
+ procedure CreateFAClass(var FAClass: Record "FA Class")
+ begin
+ FAClass.Init();
+ FAClass.Validate(
+ Code,
+ CopyStr(
+ LibraryUtility.GenerateRandomCode(FAClass.FieldNo(Code), DATABASE::"FA Class"),
+ 1,
+ LibraryUtility.GetFieldLength(DATABASE::"FA Class", FAClass.FieldNo(Code))));
+
+ FAClass.Validate(Name, 'NameOf' + FAClass.Code);
+ FAClass.Insert(true);
+ end;
+
+ procedure CreateFASubclass(var FASubclass: Record "FA Subclass")
+ begin
+ FASubclass.Init();
+ FASubclass.Validate(
+ Code,
+ CopyStr(
+ LibraryUtility.GenerateRandomCode(FASubclass.FieldNo(Code), DATABASE::"FA Subclass"),
+ 1,
+ LibraryUtility.GetFieldLength(DATABASE::"FA Subclass", FASubclass.FieldNo(Code))));
+
+ FASubclass.Validate(Name, 'NameOf' + FASubclass.Code);
+ FASubclass.Insert(true);
+ end;
+
+ procedure CreateFASubclassDetailed(var FASubclass: Record "FA Subclass"; FAClassCode: Code[10]; FAPostingGroupCode: Code[20])
+ begin
+ FASubclass.Init();
+ FASubclass.Validate(
+ Code,
+ CopyStr(
+ LibraryUtility.GenerateRandomCode(FASubclass.FieldNo(Code), DATABASE::"FA Subclass"),
+ 1,
+ LibraryUtility.GetFieldLength(DATABASE::"FA Subclass", FASubclass.FieldNo(Code))));
+
+ FASubclass.Validate(Name, 'NameOf' + FASubclass.Code);
+ FASubclass.Validate("FA Class Code", FAClassCode);
+ FASubclass.Validate("Default FA Posting Group", FAPostingGroupCode);
+ FASubclass.Insert(true);
+ end;
+
+ procedure FindEmployee(var Employee: Record Employee)
+ begin
+ Employee.FindSet();
+ end;
+
+ procedure FindFAClass(var FAClass: Record "FA Class")
+ begin
+ FAClass.FindSet();
+ end;
+
+ procedure FindFAJournalBatch(var FAJournalBatch: Record "FA Journal Batch"; JournalTemplateName: Code[10])
+ begin
+ FAJournalBatch.SetRange("Journal Template Name", JournalTemplateName);
+ FAJournalBatch.FindFirst();
+ end;
+
+ procedure FindFAJournalTemplate(var FAJournalTemplate: Record "FA Journal Template")
+ begin
+ FAJournalTemplate.FindFirst();
+ end;
+
+ procedure FindFALocation(var FALocation: Record "FA Location")
+ begin
+ FALocation.FindSet();
+ end;
+
+ procedure FindFASubclass(var FASubclass: Record "FA Subclass")
+ begin
+ FASubclass.FindSet();
+ end;
+
+ procedure FindInsurance(var Insurance: Record Insurance)
+ begin
+ Insurance.FindSet();
+ end;
+
+ procedure GetDefaultDeprBook(): Code[10]
+ begin
+ FASetup.Get();
+ exit(FASetup."Default Depr. Book");
+ end;
+
+ procedure PostFAJournalLine(var FAJournalLine: Record "FA Journal Line")
+ begin
+ FAJournalLine.SetRange("Journal Template Name", FAJournalLine."Journal Template Name");
+ FAJournalLine.SetRange("Journal Batch Name", FAJournalLine."Journal Batch Name");
+ CODEUNIT.Run(CODEUNIT::"FA Jnl.-Post Batch", FAJournalLine);
+ end;
+
+ procedure PostInsuranceJournal(var InsuranceJournalLine: Record "Insurance Journal Line")
+ begin
+ InsuranceJournalLine.SetRange("Journal Template Name", InsuranceJournalLine."Journal Template Name");
+ InsuranceJournalLine.SetRange("Journal Batch Name", InsuranceJournalLine."Journal Batch Name");
+ CODEUNIT.Run(CODEUNIT::"Insurance Jnl.-Post Batch", InsuranceJournalLine);
+ end;
+
+ procedure PostFAJournalLineBatch(var FAJournalBatch: Record "FA Journal Batch")
+ begin
+ CODEUNIT.Run(CODEUNIT::"FA. Jnl.-B.Post", FAJournalBatch);
+ end;
+
+ procedure UpdateFAPostingGroupGLAccounts(var FAPostingGroup: Record "FA Posting Group"; VATPostingSetup: Record "VAT Posting Setup")
+ begin
+ FAPostingGroup.Validate("Acquisition Cost Account", LibraryERM.CreateGLAccountWithVATPostingSetup(VATPostingSetup, "General Posting Type"::" "));
+ FAPostingGroup.Validate("Acq. Cost Acc. on Disposal", FAPostingGroup."Acquisition Cost Account");
+ FAPostingGroup.Validate("Accum. Depreciation Account", LibraryERM.CreateGLAccountNo());
+ FAPostingGroup.Validate("Accum. Depr. Acc. on Disposal", FAPostingGroup."Accum. Depreciation Account");
+ FAPostingGroup.Validate("Depreciation Expense Acc.", LibraryERM.CreateGLAccountNo());
+ FAPostingGroup.Validate("Gains Acc. on Disposal", LibraryERM.CreateGLAccountNo());
+ FAPostingGroup.Validate("Losses Acc. on Disposal", LibraryERM.CreateGLAccountNo());
+ FAPostingGroup.Validate("Sales Bal. Acc.", LibraryERM.CreateGLAccountWithVATPostingSetup(VATPostingSetup, "General Posting Type"::" "));
+ FAPostingGroup.Modify(true);
+ end;
+
+ procedure UpdateFASetupDefaultDeprBook(DefaultDeprBook: Code[10])
+ var
+ FASetup: Record "FA Setup";
+ begin
+ FASetup.Get();
+ FASetup.Validate("Default Depr. Book", DefaultDeprBook);
+ FASetup.Modify(true);
+ end;
+
+ procedure VerifyLastFARegisterGLRegisterOneToOneRelation()
+ var
+ FARegister: Record "FA Register";
+ GLRegister: Record "G/L Register";
+ GLEntry: Record "G/L Entry";
+ begin
+ GLRegister.FindLast();
+ FARegister.FindLast();
+ Assert.AreEqual(GLRegister."No.", FARegister."G/L Register No.", FARegisterGLRegisterErr);
+
+ GLEntry.SetRange("Entry No.", GLRegister."From Entry No.", GLRegister."To Entry No.");
+ GLEntry.SetRange("FA Entry Type", GLEntry."FA Entry Type"::"Fixed Asset");
+ GLEntry.FindSet();
+ repeat
+ Assert.IsTrue(
+ GLEntry."FA Entry No." in [FARegister."From Entry No." .. FARegister."To Entry No."],
+ FARegisterGLRegisterErr);
+ until GLEntry.Next() = 0;
+ end;
+
+ procedure VerifyMaintenanceLastFARegisterGLRegisterOneToOneRelation()
+ var
+ FARegister: Record "FA Register";
+ GLRegister: Record "G/L Register";
+ GLEntry: Record "G/L Entry";
+ begin
+ GLRegister.FindLast();
+ FARegister.FindLast();
+ Assert.AreEqual(GLRegister."No.", FARegister."G/L Register No.", FARegisterGLRegisterErr);
+
+ GLEntry.SetRange("Entry No.", GLRegister."From Entry No.", GLRegister."To Entry No.");
+ GLEntry.SetRange("FA Entry Type", GLEntry."FA Entry Type"::Maintenance);
+ GLEntry.FindSet();
+ repeat
+ Assert.IsTrue(
+ GLEntry."FA Entry No." in [FARegister."From Maintenance Entry No." .. FARegister."To Maintenance Entry No."],
+ FARegisterGLRegisterErr);
+ until GLEntry.Next() = 0;
+ end;
+}
+
diff --git a/Apps/W1/ApplicationTestLibrary/LibraryHumanResource.Codeunit.al b/Apps/W1/ApplicationTestLibrary/LibraryHumanResource.Codeunit.al
new file mode 100644
index 0000000000..626964be0a
--- /dev/null
+++ b/Apps/W1/ApplicationTestLibrary/LibraryHumanResource.Codeunit.al
@@ -0,0 +1,271 @@
+///
+/// Provides utility functions for creating and managing human resource entities in test scenarios, including employees, employee absence, and HR setup.
+///
+codeunit 131901 "Library - Human Resource"
+{
+
+ trigger OnRun()
+ begin
+ end;
+
+ var
+ LibraryUtility: Codeunit "Library - Utility";
+ LibraryERM: Codeunit "Library - ERM";
+ FirstNameTxt: Label 'First Name';
+ NameTxt: Label 'Name';
+
+ procedure CreateAlternativeAddress(var AlternativeAddress: Record "Alternative Address"; EmployeeNo: Code[20])
+ begin
+ AlternativeAddress.Init();
+ AlternativeAddress.Validate("Employee No.", EmployeeNo);
+ AlternativeAddress.Validate(
+ Code,
+ CopyStr(
+ LibraryUtility.GenerateRandomCode(AlternativeAddress.FieldNo(Code), DATABASE::"Alternative Address"),
+ 1,
+ LibraryUtility.GetFieldLength(DATABASE::"Alternative Address", AlternativeAddress.FieldNo(Code))));
+ AlternativeAddress.Insert(true);
+ end;
+
+ procedure CreateEmployee(var Employee: Record Employee)
+ begin
+ Employee.Init();
+ Employee.Validate("Employee Posting Group", FindEmployeePostingGroup());
+ Employee.Insert(true);
+ UpdateEmployeeName(Employee);
+ Employee.Modify(true);
+ end;
+
+ procedure CreateEmployeeNo(): Code[20]
+ var
+ Employee: Record Employee;
+ begin
+ CreateEmployee(Employee);
+ exit(Employee."No.");
+ end;
+
+ procedure CreateEmployeeNoWithBankAccount(): Code[20]
+ var
+ Employee: Record Employee;
+ begin
+ CreateEmployeeWithBankAccount(Employee);
+ exit(Employee."No.");
+ end;
+
+ procedure CreateEmployeeWithBankAccount(var Employee: Record Employee)
+ var
+ EmployeePostingGroup: Record "Employee Posting Group";
+ begin
+ CreateEmployee(Employee);
+ Employee."Bank Account No." := LibraryUtility.GenerateGUID();
+ Employee.IBAN := LibraryUtility.GenerateGUID();
+ Employee."SWIFT Code" := LibraryUtility.GenerateGUID();
+ Employee."Bank Branch No." := LibraryUtility.GenerateGUID();
+ EmployeePostingGroup.Init();
+ EmployeePostingGroup.Validate(Code, LibraryUtility.GenerateGUID());
+ EmployeePostingGroup.Validate("Payables Account", LibraryERM.CreateGLAccountNoWithDirectPosting());
+ EmployeePostingGroup.Insert(true);
+ Employee.Validate("Employee Posting Group", EmployeePostingGroup.Code);
+ Employee.Modify(true);
+ end;
+
+ procedure CreateMiscArticle(var MiscArticle: Record "Misc. Article")
+ begin
+ MiscArticle.Init();
+ MiscArticle.Validate(
+ Code,
+ CopyStr(
+ LibraryUtility.GenerateRandomCode(MiscArticle.FieldNo(Code), DATABASE::"Misc. Article"),
+ 1,
+ LibraryUtility.GetFieldLength(DATABASE::"Misc. Article", MiscArticle.FieldNo(Code))));
+ MiscArticle.Validate(Description, MiscArticle.Code);
+ MiscArticle.Insert(true);
+ end;
+
+ procedure CreateMiscArticleInformation(var MiscArticleInformation: Record "Misc. Article Information"; EmployeeNo: Code[20]; MiscArticleCode: Code[10])
+ var
+ RecRef: RecordRef;
+ begin
+ MiscArticleInformation.Init();
+ MiscArticleInformation.Validate("Employee No.", EmployeeNo);
+ MiscArticleInformation.Validate("Misc. Article Code", MiscArticleCode);
+ RecRef.GetTable(MiscArticleInformation);
+ MiscArticleInformation.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, MiscArticleInformation.FieldNo("Line No.")));
+ MiscArticleInformation.Insert(true);
+ end;
+
+ procedure CreateEmployeeQualification(var EmployeeQualification: Record "Employee Qualification"; EmployeeNo: Code[20])
+ var
+ RecRef: RecordRef;
+ begin
+ EmployeeQualification.Init();
+ EmployeeQualification.Validate("Employee No.", EmployeeNo);
+ RecRef.GetTable(EmployeeQualification);
+ EmployeeQualification.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, EmployeeQualification.FieldNo("Line No.")));
+ EmployeeQualification.Insert(true);
+ end;
+
+ procedure CreateEmployeeAbsence(var EmployeeAbsence: Record "Employee Absence")
+ begin
+ EmployeeAbsence.Init();
+ EmployeeAbsence.Insert(true);
+ end;
+
+ procedure CreateEmployeeRelative(var EmployeeRelative: Record "Employee Relative"; EmployeeNo: Code[20])
+ var
+ RecRef: RecordRef;
+ begin
+ EmployeeRelative.Init();
+ EmployeeRelative.Validate("Employee No.", EmployeeNo);
+ RecRef.GetTable(EmployeeRelative);
+ EmployeeRelative.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, EmployeeRelative.FieldNo("Line No.")));
+ EmployeeRelative.Insert(true);
+ end;
+
+ procedure CreateEmployeeStatGroup(var EmployeeStatisticsGroup: Record "Employee Statistics Group")
+ begin
+ EmployeeStatisticsGroup.Init();
+ EmployeeStatisticsGroup.Validate(
+ Code,
+ CopyStr(
+ LibraryUtility.GenerateRandomCode(EmployeeStatisticsGroup.FieldNo(Code), DATABASE::"Employee Statistics Group"),
+ 1,
+ LibraryUtility.GetFieldLength(DATABASE::"Employee Statistics Group", EmployeeStatisticsGroup.FieldNo(Code))));
+ EmployeeStatisticsGroup.Validate(Description, EmployeeStatisticsGroup.Code);
+ EmployeeStatisticsGroup.Insert(true);
+ end;
+
+ procedure CreateEmploymentContract(var EmploymentContract: Record "Employment Contract")
+ begin
+ EmploymentContract.Init();
+ EmploymentContract.Validate(
+ Code,
+ CopyStr(
+ LibraryUtility.GenerateRandomCode(EmploymentContract.FieldNo(Code), DATABASE::"Employment Contract"),
+ 1,
+ LibraryUtility.GetFieldLength(DATABASE::"Employment Contract", EmploymentContract.FieldNo(Code))));
+ EmploymentContract.Validate(Description, EmploymentContract.Code);
+ EmploymentContract.Insert(true);
+ end;
+
+ procedure CreateConfidential(var Confidential: Record Confidential)
+ begin
+ Confidential.Init();
+ Confidential.Validate(
+ Code,
+ CopyStr(
+ LibraryUtility.GenerateRandomCode(Confidential.FieldNo(Code), DATABASE::Confidential),
+ 1,
+ LibraryUtility.GetFieldLength(DATABASE::Confidential, Confidential.FieldNo(Code))));
+ Confidential.Validate(Description, Confidential.Code);
+ Confidential.Insert(true);
+ end;
+
+ procedure CreateConfidentialInformation(var ConfidentialInformation: Record "Confidential Information"; EmployeeNo: Code[20]; ConfidentialCode: Code[10])
+ var
+ RecRef: RecordRef;
+ begin
+ ConfidentialInformation.Init();
+ ConfidentialInformation.Validate("Employee No.", EmployeeNo);
+ ConfidentialInformation.Validate("Confidential Code", ConfidentialCode);
+ RecRef.GetTable(ConfidentialInformation);
+ ConfidentialInformation.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, ConfidentialInformation.FieldNo("Line No.")));
+ ConfidentialInformation.Insert(true);
+ end;
+
+ procedure CreateQualification(var Qualification: Record Qualification)
+ begin
+ Qualification.Init();
+ Qualification.Validate(
+ Code,
+ CopyStr(
+ LibraryUtility.GenerateRandomCode(Qualification.FieldNo(Code), DATABASE::Qualification),
+ 1,
+ LibraryUtility.GetFieldLength(DATABASE::Qualification, Qualification.FieldNo(Code))));
+ Qualification.Validate(Description, Qualification.Code);
+ Qualification.Insert(true);
+ end;
+
+ procedure CreateRelative(var Relative: Record Relative)
+ begin
+ Relative.Init();
+ Relative.Validate(
+ Code,
+ CopyStr(
+ LibraryUtility.GenerateRandomCode(Relative.FieldNo(Code), DATABASE::Relative),
+ 1,
+ LibraryUtility.GetFieldLength(DATABASE::Relative, Relative.FieldNo(Code))));
+ Relative.Validate(Description, Relative.Code);
+ Relative.Insert(true);
+ end;
+
+ procedure CreateUnion(var Union: Record Union)
+ begin
+ Union.Init();
+ Union.Validate(
+ Code,
+ CopyStr(
+ LibraryUtility.GenerateRandomCode(Union.FieldNo(Code), DATABASE::Union),
+ 1,
+ LibraryUtility.GetFieldLength(DATABASE::Union, Union.FieldNo(Code))));
+ Union.Validate(Name, Union.Code);
+ Union.Insert(true);
+ end;
+
+ local procedure UpdateEmployeeName(var Employee: Record Employee)
+ var
+ RecRef: RecordRef;
+ FieldRef: FieldRef;
+ begin
+ RecRef.GetTable(Employee);
+ if LibraryUtility.CheckFieldExistenceInTable(DATABASE::Employee, NameTxt) then
+ FieldRef := RecRef.Field(LibraryUtility.FindFieldNoInTable(DATABASE::Employee, NameTxt))
+ else
+ FieldRef := RecRef.Field(LibraryUtility.FindFieldNoInTable(DATABASE::Employee, FirstNameTxt));
+ FieldRef.Validate(Employee."No."); // Validating Name as No. because value is not important.
+ RecRef.SetTable(Employee);
+ end;
+
+ procedure SetupEmployeeNumberSeries(): Code[10]
+ var
+ HumanResourcesSetup: Record "Human Resources Setup";
+ begin
+ HumanResourcesSetup.Get();
+ if HumanResourcesSetup."Employee Nos." = '' then
+ HumanResourcesSetup.Validate("Employee Nos.", LibraryUtility.GetGlobalNoSeriesCode());
+ HumanResourcesSetup.Modify(true);
+ exit(HumanResourcesSetup."Employee Nos.");
+ end;
+
+ procedure CreateEmployeePostingGroup(var EmployeePostingGroup: Record "Employee Posting Group")
+ begin
+ EmployeePostingGroup.Init();
+ EmployeePostingGroup.Validate(Code,
+ LibraryUtility.GenerateRandomCode(EmployeePostingGroup.FieldNo(Code), Database::"Employee Posting Group"));
+ EmployeePostingGroup.Validate("Payables Account", LibraryERM.CreateGLAccountNo());
+ EmployeePostingGroup.Validate("Debit Rounding Account", LibraryERM.CreateGLAccountNo());
+ EmployeePostingGroup.Validate("Credit Rounding Account", LibraryERM.CreateGLAccountNo());
+ EmployeePostingGroup.Validate("Debit Curr. Appln. Rndg. Acc.", LibraryERM.CreateGLAccountNo());
+ EmployeePostingGroup.Validate("Credit Curr. Appln. Rndg. Acc.", LibraryERM.CreateGLAccountNo());
+ EmployeePostingGroup.Insert(true);
+ end;
+
+ procedure FindEmployeePostingGroup(): Code[20]
+ var
+ EmployeePostingGroup: Record "Employee Posting Group";
+ begin
+ if not EmployeePostingGroup.FindFirst() then
+ CreateEmployeePostingGroup(EmployeePostingGroup);
+ exit(EmployeePostingGroup.Code);
+ end;
+
+ procedure CreateAltEmployeePostingGroup(ParentCode: Code[20]; AltCode: Code[20])
+ var
+ AltEmployeePostingGroup: Record "Alt. Employee Posting Group";
+ begin
+ AltEmployeePostingGroup.Init();
+ AltEmployeePostingGroup."Employee Posting Group" := ParentCode;
+ AltEmployeePostingGroup."Alt. Employee Posting Group" := AltCode;
+ AltEmployeePostingGroup.Insert();
+ end;
+}
diff --git a/Apps/W1/ApplicationTestLibrary/LibraryInventory.Codeunit.al b/Apps/W1/ApplicationTestLibrary/LibraryInventory.Codeunit.al
new file mode 100644
index 0000000000..3095af3296
--- /dev/null
+++ b/Apps/W1/ApplicationTestLibrary/LibraryInventory.Codeunit.al
@@ -0,0 +1,1827 @@
+///
+/// Provides utility functions for creating and managing inventory-related entities in test scenarios, including items, item journals, locations, and inventory postings.
+///
+codeunit 132201 "Library - Inventory"
+{
+
+ trigger OnRun()
+ begin
+ end;
+
+ var
+ InventorySetup: Record "Inventory Setup";
+ LibraryERM: Codeunit "Library - ERM";
+ LibraryPurchase: Codeunit "Library - Purchase";
+ LibraryRandom: Codeunit "Library - Random";
+ LibraryUtility: Codeunit "Library - Utility";
+ LibraryWarehouse: Codeunit "Library - Warehouse";
+ JOURNALTxt: Label ' journal';
+ ReserveConfirmMsg: Label 'Do you want to reserve specific tracking numbers?';
+
+ procedure CalculateInventory(ItemJournalLine: Record "Item Journal Line"; var Item: Record Item; PostingDate: Date; ItemsNotOnInvt: Boolean; ItemsWithNoTransactions: Boolean)
+ var
+ CalculateInventoryReport: Report "Calculate Inventory";
+ begin
+ Clear(CalculateInventoryReport);
+ CalculateInventoryReport.UseRequestPage(false);
+ CalculateInventoryReport.SetTableView(Item);
+ CalculateInventoryReport.SetItemJnlLine(ItemJournalLine);
+ CalculateInventoryReport.InitializeRequest(PostingDate, ItemJournalLine."Document No.", ItemsNotOnInvt, ItemsWithNoTransactions);
+ CalculateInventoryReport.Run();
+ end;
+
+ procedure CalculateInventoryForSingleItem(ItemJournalLine: Record "Item Journal Line"; ItemNo: Code[20]; PostingDate: Date; ItemsNotOnInvt: Boolean; ItemsWithNoTransactions: Boolean)
+ var
+ Item: Record Item;
+ begin
+ Item.SetRange("No.", ItemNo);
+ CalculateInventory(ItemJournalLine, Item, PostingDate, ItemsNotOnInvt, ItemsWithNoTransactions);
+ end;
+
+ procedure CreateAnalysisColumnTemplate(var AnalysisColumnTemplate: Record "Analysis Column Template"; AnalysisArea: Enum "Analysis Area Type")
+ begin
+ AnalysisColumnTemplate.Init();
+ AnalysisColumnTemplate.Validate("Analysis Area", AnalysisArea);
+ AnalysisColumnTemplate.Validate(
+ Name, LibraryUtility.GenerateRandomCode(AnalysisColumnTemplate.FieldNo(Name), DATABASE::"Analysis Column Template"));
+ AnalysisColumnTemplate.Insert(true);
+ end;
+
+ procedure CreateAnalysisColumn(var AnalysisColumn: Record "Analysis Column"; AnalysisArea: Enum "Analysis Area Type"; AnalysisColumnTemplateName: Code[10])
+ var
+ RecRef: RecordRef;
+ begin
+ AnalysisColumn.Init();
+ AnalysisColumn.Validate("Analysis Area", AnalysisArea);
+ AnalysisColumn.Validate("Analysis Column Template", AnalysisColumnTemplateName);
+ RecRef.GetTable(AnalysisColumn);
+ AnalysisColumn.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, AnalysisColumn.FieldNo("Line No.")));
+ AnalysisColumn.Insert(true);
+ end;
+
+ procedure CreateBaseCalendarChange(var BaseCalendarChange: Record "Base Calendar Change"; BaseCalendarCode: Code[10]; RecurringSystem: Option; Date: Date; Day: Option)
+ begin
+ BaseCalendarChange.Init();
+ BaseCalendarChange.Validate("Base Calendar Code", BaseCalendarCode);
+ BaseCalendarChange.Validate("Recurring System", RecurringSystem);
+ BaseCalendarChange.Validate(Date, Date);
+ BaseCalendarChange.Validate(Day, Day);
+ BaseCalendarChange.Insert(true);
+ end;
+
+ procedure CreateBOMComponent(var BOMComponent: Record "BOM Component"; ParentItemNo: Code[20]; Type: Enum "BOM Component Type"; No: Code[20]; QuantityPer: Decimal; UnitOfMeasureCode: Code[10])
+ var
+ RecRef: RecordRef;
+ begin
+ BOMComponent.Init();
+ BOMComponent.Validate("Parent Item No.", ParentItemNo);
+ RecRef.GetTable(BOMComponent);
+ BOMComponent.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, BOMComponent.FieldNo("Line No.")));
+ BOMComponent.Insert(true);
+ BOMComponent.Validate(Type, Type);
+ if BOMComponent.Type <> BOMComponent.Type::" " then begin
+ BOMComponent.Validate("No.", No);
+ BOMComponent.Validate("Quantity per", QuantityPer);
+ if UnitOfMeasureCode <> '' then
+ BOMComponent.Validate("Unit of Measure Code", UnitOfMeasureCode);
+ end;
+ BOMComponent.Modify(true);
+ end;
+
+ procedure ClearItemJournal(ItemJournalTemplate: Record "Item Journal Template"; ItemJournalBatch: Record "Item Journal Batch")
+ var
+ ItemJournalLine: Record "Item Journal Line";
+ SequenceNoMgt: Codeunit "Sequence No. Mgt.";
+ begin
+ Clear(ItemJournalLine);
+ Clear(SequenceNoMgt);
+ ItemJournalLine.SetRange("Journal Template Name", ItemJournalTemplate.Name);
+ ItemJournalLine.SetRange("Journal Batch Name", ItemJournalBatch.Name);
+ ItemJournalLine.DeleteAll();
+ end;
+
+ procedure CreateAnalysisLine(var AnalysisLine: Record "Analysis Line"; AnalysisArea: Enum "Analysis Area Type"; AnalysisLineTemplateName: Code[10])
+ var
+ RecRef: RecordRef;
+ begin
+ AnalysisLine.Init();
+ AnalysisLine.Validate("Analysis Area", AnalysisArea);
+ AnalysisLine.Validate("Analysis Line Template Name", AnalysisLineTemplateName);
+ RecRef.GetTable(AnalysisLine);
+ AnalysisLine.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, AnalysisLine.FieldNo("Line No.")));
+ AnalysisLine.Insert(true);
+ end;
+
+ procedure CreateAnalysisLineTemplate(var AnalysisLineTemplate: Record "Analysis Line Template"; AnalysisArea: Enum "Analysis Area Type")
+ begin
+ AnalysisLineTemplate.Init();
+ AnalysisLineTemplate.Validate("Analysis Area", AnalysisArea);
+ AnalysisLineTemplate.Validate(
+ Name, LibraryUtility.GenerateRandomCode(AnalysisLineTemplate.FieldNo(Name), DATABASE::"Analysis Line Template"));
+ AnalysisLineTemplate.Insert(true);
+ end;
+
+ procedure CreateAnalysisReportName(var AnalysisReportName: Record "Analysis Report Name"; AnalysisArea: Enum "Analysis Area Type")
+ begin
+ AnalysisReportName.Init();
+ AnalysisReportName.Validate("Analysis Area", AnalysisArea);
+ AnalysisReportName.Validate(
+ Name, LibraryUtility.GenerateRandomCode(AnalysisReportName.FieldNo(Name), DATABASE::"Analysis Report Name"));
+ AnalysisReportName.Insert(true);
+ end;
+
+ procedure CreateAndUpdateTransferRoute(var TransferRoute: Record "Transfer Route"; TransferFrom: Code[10]; TransferTo: Code[10]; InTransitCode: Code[10]; ShippingAgentCode: Code[10]; ShippingAgentServiceCode: Code[10])
+ begin
+ CreateTransferRoute(TransferRoute, TransferFrom, TransferTo);
+ TransferRoute.Validate("In-Transit Code", InTransitCode);
+ TransferRoute.Validate("Shipping Agent Code", ShippingAgentCode);
+ TransferRoute.Validate("Shipping Agent Service Code", ShippingAgentServiceCode);
+ TransferRoute.Modify(true);
+ end;
+
+ procedure CreateSerialNoInformation(var SerialNoInformation: Record "Serial No. Information"; ItemNo: Code[20]; VariantCode: Code[10]; SerialNo: Code[50])
+ begin
+ Clear(SerialNoInformation);
+ SerialNoInformation.Init();
+ SerialNoInformation.Validate("Item No.", ItemNo);
+ SerialNoInformation.Validate("Variant Code", VariantCode);
+ SerialNoInformation.Validate("Serial No.", SerialNo);
+ SerialNoInformation.Insert(true);
+ end;
+
+ procedure CreateLotNoInformation(var LotNoInformation: Record "Lot No. Information"; ItemNo: Code[20]; VariantCode: Code[10]; LotNo: Code[50])
+ begin
+ Clear(LotNoInformation);
+ LotNoInformation.Init();
+ LotNoInformation.Validate("Item No.", ItemNo);
+ LotNoInformation.Validate("Variant Code", VariantCode);
+ LotNoInformation.Validate("Lot No.", LotNo);
+ LotNoInformation.Insert(true);
+ end;
+
+ procedure CreateInventoryPostingGroup(var InventoryPostingGroup: Record "Inventory Posting Group")
+ begin
+ Clear(InventoryPostingGroup);
+ InventoryPostingGroup.Init();
+ InventoryPostingGroup.Validate(Code,
+ LibraryUtility.GenerateRandomCode(InventoryPostingGroup.FieldNo(Code), DATABASE::"Inventory Posting Group"));
+ InventoryPostingGroup.Validate(Description, InventoryPostingGroup.Code);
+ InventoryPostingGroup.Insert(true);
+ end;
+
+ procedure CreateInventoryPeriod(var InventoryPeriod: Record "Inventory Period"; EndingDate: Date)
+ begin
+ Clear(InventoryPeriod);
+ if InventoryPeriod.Get(EndingDate) then
+ exit;
+ InventoryPeriod.Init();
+ InventoryPeriod.Validate("Ending Date", EndingDate);
+ InventoryPeriod.Insert(true);
+ end;
+
+ procedure CreateInventoryPostingSetup(var InventoryPostingSetup: Record "Inventory Posting Setup"; LocationCode: Text[10]; PostingGroupCode: Text[20])
+ begin
+ Clear(InventoryPostingSetup);
+ InventoryPostingSetup.Init();
+ InventoryPostingSetup.Validate("Location Code", LocationCode);
+ InventoryPostingSetup.Validate("Invt. Posting Group Code", PostingGroupCode);
+ InventoryPostingSetup.Insert(true);
+ end;
+
+ [Scope('OnPrem')]
+ procedure CreatePhysInvtOrderHeader(var PhysInvtOrderHeader: Record "Phys. Invt. Order Header")
+ begin
+ PhysInvtOrderHeader.Init();
+ PhysInvtOrderHeader.Insert(true);
+ end;
+
+ [Scope('OnPrem')]
+ procedure CreatePhysInvtOrderLine(var PhysInvtOrderLine: Record "Phys. Invt. Order Line"; CountNo: Code[20]; ItemNo: Code[20])
+ begin
+ PhysInvtOrderLine.Validate("Document No.", CountNo);
+ PhysInvtOrderLine.Validate("Line No.", LibraryUtility.GetNewRecNo(PhysInvtOrderLine, PhysInvtOrderLine.FieldNo("Line No.")));
+ PhysInvtOrderLine.Validate("Item No.", ItemNo);
+ PhysInvtOrderLine.Insert(true);
+ end;
+
+ [Scope('OnPrem')]
+ procedure CreatePhysInvtRecordHeader(var PhysInvtRecordHeader: Record "Phys. Invt. Record Header"; CountNo: Code[20])
+ begin
+ PhysInvtRecordHeader.Validate("Order No.", CountNo);
+ PhysInvtRecordHeader.Validate("Recording No.", LibraryUtility.GetNewRecNo(PhysInvtRecordHeader, PhysInvtRecordHeader.FieldNo("Recording No.")));
+ PhysInvtRecordHeader.Insert(true);
+ end;
+
+ [Scope('OnPrem')]
+ procedure CreatePhysInvtRecordLine(var PhysInvtRecordLine: Record "Phys. Invt. Record Line"; PhysInvtOrderLine: Record "Phys. Invt. Order Line"; RecordingNo: Integer; Qty: Decimal)
+ begin
+ PhysInvtRecordLine.Validate("Order No.", PhysInvtOrderLine."Document No.");
+ PhysInvtRecordLine.Validate("Order Line No.", PhysInvtOrderLine."Line No.");
+ PhysInvtRecordLine.Validate("Recording No.", RecordingNo);
+ PhysInvtRecordLine.Validate("Line No.", LibraryUtility.GetNewRecNo(PhysInvtRecordLine, PhysInvtRecordLine.FieldNo("Line No.")));
+ PhysInvtRecordLine.Validate("Item No.", PhysInvtOrderLine."Item No.");
+ PhysInvtRecordLine.Validate(Quantity, Qty);
+ PhysInvtRecordLine.Validate(Recorded, true);
+ PhysInvtRecordLine.Insert(true);
+ end;
+
+ procedure CreateItemWithoutVAT(var Item: Record Item)
+ var
+ ItemUnitOfMeasure: Record "Item Unit of Measure";
+ GeneralPostingSetup: Record "General Posting Setup";
+ InventoryPostingGroup: Record "Inventory Posting Group";
+ TaxGroup: Record "Tax Group";
+ InventoryPostingSetup: Record "Inventory Posting Setup";
+ begin
+ ItemNoSeriesSetup(InventorySetup);
+ Clear(Item);
+ Item.Insert(true);
+
+ CreateItemUnitOfMeasure(ItemUnitOfMeasure, Item."No.", '', 1);
+ LibraryERM.FindGeneralPostingSetupInvtFull(GeneralPostingSetup);
+
+ if not InventoryPostingGroup.FindFirst() then
+ CreateInventoryPostingGroup(InventoryPostingGroup);
+
+ InventoryPostingSetup.SetRange("Invt. Posting Group Code", InventoryPostingGroup.Code);
+ if not InventoryPostingSetup.FindFirst() then
+ CreateInventoryPostingSetup(InventoryPostingSetup, '', InventoryPostingGroup.Code);
+
+ Item.Validate(Description, Item."No."); // Validation Description as No. because value is not important.
+ Item.Validate("Base Unit of Measure", ItemUnitOfMeasure.Code);
+ Item.Validate("Gen. Prod. Posting Group", GeneralPostingSetup."Gen. Prod. Posting Group");
+ Item.Validate("Inventory Posting Group", InventoryPostingGroup.Code);
+
+ if TaxGroup.FindFirst() then
+ Item.Validate("Tax Group Code", TaxGroup.Code);
+
+ Item.Modify(true);
+ end;
+
+ procedure CreateItem(var Item: Record Item): Code[20]
+ var
+ VATPostingSetup: Record "VAT Posting Setup";
+ begin
+ CreateItemWithoutVAT(Item);
+
+ LibraryERM.FindVATPostingSetupInvt(VATPostingSetup);
+ Item.Validate("VAT Prod. Posting Group", VATPostingSetup."VAT Prod. Posting Group");
+
+ Item.Modify(true);
+ OnAfterCreateItem(Item);
+ exit(Item."No.");
+ end;
+
+ procedure CreateItemNo(): Code[20]
+ var
+ Item: Record Item;
+ begin
+ CreateItem(Item);
+ exit(Item."No.");
+ end;
+
+ procedure CreateItemNoWithoutVAT(): Code[20]
+ var
+ Item: Record Item;
+ begin
+ CreateItemWithoutVAT(Item);
+ exit(Item."No.");
+ end;
+
+ procedure CreateItemWithTariffNo(var Item: Record Item; TariffNo: Code[20])
+ begin
+ CreateItem(Item);
+ Item.Validate("Tariff No.", TariffNo);
+ Item.Modify(true);
+ end;
+
+ procedure CreateItemWithUnitPriceAndUnitCost(var Item: Record Item; UnitPrice: Decimal; UnitCost: Decimal)
+ begin
+ CreateItem(Item);
+ Item.Validate("Unit Price", UnitPrice);
+ Item.Validate("Unit Cost", UnitCost);
+ Item.Modify(true);
+ end;
+
+ procedure CreateItemWithUnitPriceUnitCostAndPostingGroup(var Item: Record Item; UnitPrice: Decimal; UnitCost: Decimal)
+ begin
+ CreateItemWithUnitPriceAndUnitCost(Item, UnitPrice, UnitCost);
+ end;
+
+ procedure CreateItemWithPostingSetup(var Item: Record Item; GenProdPostingGroup: Code[20]; VATProductPostingGroup: Code[20])
+ begin
+ CreateItem(Item);
+ Item.Validate("Gen. Prod. Posting Group", GenProdPostingGroup);
+ Item.Validate("VAT Prod. Posting Group", VATProductPostingGroup);
+ Item.Modify(true);
+ end;
+
+ procedure CreateItemNoWithPostingSetup(GenProdPostingGroup: Code[20]; VATProductPostingGroup: Code[20]): Code[20]
+ var
+ Item: Record Item;
+ begin
+ CreateItemWithPostingSetup(Item, GenProdPostingGroup, VATProductPostingGroup);
+ exit(Item."No.");
+ end;
+
+ procedure CreateItemNoWithVATProdPostingGroup(VATProdPostGroupCode: Code[20]): Code[20]
+ var
+ Item: Record Item;
+ begin
+ CreateItem(Item);
+ Item.Validate("VAT Prod. Posting Group", VATProdPostGroupCode);
+ Item.Modify(true);
+ exit(Item."No.");
+ end;
+
+ procedure CreateItemAttribute(var ItemAttribute: Record "Item Attribute"; AttributeType: Option; UnitOfMeasure: Text[30])
+ begin
+ Clear(ItemAttribute);
+ ItemAttribute.Validate(Name, LibraryUtility.GenerateRandomCode(ItemAttribute.FieldNo(Name), DATABASE::"Item Attribute"));
+ ItemAttribute.Validate(Type, AttributeType);
+ ItemAttribute.Validate("Unit of Measure", UnitOfMeasure);
+ ItemAttribute.Insert(true);
+ end;
+
+ procedure CreateItemAttributeWithValue(var ItemAttribute: Record "Item Attribute"; var ItemAttributeValue: Record "Item Attribute Value"; Type: Option Option,Text,"Integer",Decimal; Value: Text[250])
+ begin
+ CreateItemAttribute(ItemAttribute, Type, '');
+ CreateItemAttributeValue(ItemAttributeValue, ItemAttribute.ID, Value);
+ end;
+
+ procedure CreateItemAttributeValue(var ItemAttributeValue: Record "Item Attribute Value"; AttributeID: Integer; AttributeValue: Text[250])
+ begin
+ Clear(ItemAttributeValue);
+ ItemAttributeValue.Validate("Attribute ID", AttributeID);
+ ItemAttributeValue.Validate(Value, AttributeValue);
+ ItemAttributeValue.Insert(true);
+ end;
+
+ procedure CreateItemAttributeValueMapping(TableID: Integer; No: Code[20]; AttributeID: Integer; AttributeValueID: Integer)
+ var
+ ItemAttributeValueMapping: Record "Item Attribute Value Mapping";
+ begin
+ ItemAttributeValueMapping.Validate("Table ID", TableID);
+ ItemAttributeValueMapping.Validate("No.", No);
+ ItemAttributeValueMapping.Validate("Item Attribute ID", AttributeID);
+ ItemAttributeValueMapping.Validate("Item Attribute Value ID", AttributeValueID);
+ ItemAttributeValueMapping.Insert(true);
+ end;
+
+ procedure CreateUpdateItemTranslation(ItemNo: Code[20]; VariantCode: Code[10]; LanguageCode: Code[10]; Description: Text[100]; Description2: Text[50])
+ var
+ ItemTranslation: Record "Item Translation";
+ begin
+ if not ItemTranslation.Get(ItemNo, VariantCode, LanguageCode) then begin
+ ItemTranslation.Init();
+ ItemTranslation.Validate("Item No.", ItemNo);
+ ItemTranslation.Validate("Variant Code", VariantCode);
+ ItemTranslation.Validate("Language Code", LanguageCode);
+ ItemTranslation.Insert(true);
+ end;
+ ItemTranslation.Validate(Description, Description);
+ ItemTranslation.Validate("Description 2", Description2);
+ ItemTranslation.Modify(true);
+ end;
+
+ procedure CreateItemWithVATProdPostingGroup(VATProdPostingGroup: Code[20]): Code[20]
+ var
+ Item: Record Item;
+ begin
+ CreateItem(Item);
+ Item.Validate("VAT Prod. Posting Group", VATProdPostingGroup);
+ Item.Modify(true);
+ exit(Item."No.");
+ end;
+
+ procedure CreateItemBudgetEntry(var ItemBudgetEntry: Record "Item Budget Entry"; AnalysisArea: Enum "Analysis Area Type"; BudgetName: Code[10]; Date: Date; ItemNo: Code[20])
+ begin
+ Clear(ItemBudgetEntry);
+ ItemBudgetEntry.Validate("Analysis Area", AnalysisArea);
+ ItemBudgetEntry.Validate("Budget Name", BudgetName);
+ ItemBudgetEntry.Validate(Date, Date);
+ ItemBudgetEntry.Validate("Item No.", ItemNo);
+ ItemBudgetEntry.Insert(true);
+ end;
+
+ procedure CreateItemCategory(var ItemCategory: Record "Item Category")
+ begin
+ ItemCategory.Init();
+ ItemCategory.Validate(Code, LibraryUtility.GenerateRandomCode(ItemCategory.FieldNo(Code), DATABASE::"Item Category"));
+ ItemCategory.Insert(true);
+ end;
+
+ procedure CreateInvtDocument(var InvtDocumentHeader: Record "Invt. Document Header"; DocumentType: Enum "Invt. Doc. Document Type"; LocationCode: Code[10])
+ begin
+ InvtDocumentHeader.Init();
+ InvtDocumentHeader."Document Type" := DocumentType;
+ InvtDocumentHeader.Insert(true);
+ InvtDocumentHeader.Validate("Location Code", LocationCode);
+ InvtDocumentHeader.Modify();
+ end;
+
+ procedure CreateInvtDocumentLine(var InvtDocumentHeader: Record "Invt. Document Header"; var InvtDocumentLine: Record "Invt. Document Line"; ItemNo: Code[20]; UnitCost: Decimal; Quantity: Decimal)
+ var
+ RecRef: RecordRef;
+ begin
+ InvtDocumentLine.Init();
+ InvtDocumentLine.Validate("Document Type", InvtDocumentHeader."Document Type");
+ InvtDocumentLine.Validate("Document No.", InvtDocumentHeader."No.");
+ RecRef.GetTable(InvtDocumentLine);
+ InvtDocumentLine.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, InvtDocumentLine.FieldNo("Line No.")));
+ InvtDocumentLine.Insert(true);
+ InvtDocumentLine.Validate("Item No.", ItemNo);
+ InvtDocumentLine.Validate("Unit Cost", UnitCost);
+ InvtDocumentLine.Validate(Quantity, Quantity);
+ InvtDocumentLine.Modify(true);
+ end;
+
+ procedure PostInvtDocument(InvtDocumentHeader: Record "Invt. Document Header")
+ var
+ InvtDocPostReceipt: Codeunit "Invt. Doc.-Post Receipt";
+ InvtDocPostShipment: Codeunit "Invt. Doc.-Post Shipment";
+ begin
+ case InvtDocumentHeader."Document Type" of
+ InvtDocumentHeader."Document Type"::Receipt:
+ InvtDocPostReceipt.Run(InvtDocumentHeader);
+ InvtDocumentHeader."Document Type"::Shipment:
+ InvtDocPostShipment.Run(InvtDocumentHeader);
+ end;
+ end;
+
+ procedure CreateItemChargeWithoutVAT(var ItemCharge: Record "Item Charge")
+ var
+ GeneralPostingSetup: Record "General Posting Setup";
+ begin
+ Clear(ItemCharge);
+ ItemCharge.Init();
+ ItemCharge.Validate("No.", LibraryUtility.GenerateRandomCode(ItemCharge.FieldNo("No."), DATABASE::"Item Charge"));
+ ItemCharge.Insert(true);
+
+ LibraryERM.FindGeneralPostingSetupInvtBase(GeneralPostingSetup);
+
+ ItemCharge.Validate(Description, ItemCharge."No."); // Validation Description as No. because value is not important.
+ ItemCharge.Validate("Gen. Prod. Posting Group", GeneralPostingSetup."Gen. Prod. Posting Group");
+ ItemCharge.Modify(true);
+ end;
+
+ procedure CreateItemCharge(var ItemCharge: Record "Item Charge")
+ var
+ VATPostingSetup: Record "VAT Posting Setup";
+ begin
+ CreateItemChargeWithoutVAT(ItemCharge);
+
+ LibraryERM.FindZeroVATPostingSetup(VATPostingSetup, VATPostingSetup."VAT Calculation Type"::"Normal VAT");
+ ItemCharge.Validate("VAT Prod. Posting Group", VATPostingSetup."VAT Prod. Posting Group");
+ ItemCharge.Modify(true);
+ end;
+
+ procedure CreateItemChargeNo(): Code[20]
+ var
+ ItemCharge: Record "Item Charge";
+ begin
+ CreateItemCharge(ItemCharge);
+ exit(ItemCharge."No.")
+ end;
+
+ procedure CreateItemChargeNoWithoutVAT(): Code[20]
+ var
+ ItemCharge: Record "Item Charge";
+ begin
+ CreateItemChargeWithoutVAT(ItemCharge);
+ exit(ItemCharge."No.");
+ end;
+
+ procedure CreateItemChargeAssignment(var ItemChargeAssignmentSales: Record "Item Charge Assignment (Sales)"; SalesLine: Record "Sales Line"; DocType: Enum "Sales Document Type"; DocNo: Code[20]; DocLineNo: Integer; ItemNo: Code[20])
+ var
+ ItemChargeAssgntSales: Codeunit "Item Charge Assgnt. (Sales)";
+ RecRef: RecordRef;
+ LineNo: Integer;
+ begin
+ ItemChargeAssignmentSales.Init();
+
+ ItemChargeAssignmentSales."Document Type" := SalesLine."Document Type";
+ ItemChargeAssignmentSales."Document No." := SalesLine."Document No.";
+ ItemChargeAssignmentSales."Document Line No." := SalesLine."Line No.";
+ ItemChargeAssignmentSales."Item Charge No." := SalesLine."No.";
+ ItemChargeAssignmentSales."Unit Cost" := SalesLine."Unit Cost";
+
+ RecRef.GetTable(ItemChargeAssignmentSales);
+ LineNo := LibraryUtility.GetNewLineNo(RecRef, ItemChargeAssignmentSales.FieldNo("Line No."));
+ ItemChargeAssgntSales.InsertItemChargeAssignment(ItemChargeAssignmentSales, DocType,
+ DocNo, DocLineNo, ItemNo, '', LineNo);
+
+ ItemChargeAssignmentSales.Get(SalesLine."Document Type", SalesLine."Document No.",
+ SalesLine."Line No.", LineNo);
+ ItemChargeAssignmentSales.Validate("Qty. to Assign", SalesLine.Quantity);
+ ItemChargeAssignmentSales.Modify(true);
+ end;
+
+ procedure CreateItemChargeAssignPurchase(var ItemChargeAssignmentPurch: Record "Item Charge Assignment (Purch)"; PurchaseLine: Record "Purchase Line"; DocType: Enum "Purchase Document Type"; DocNo: Code[20]; DocLineNo: Integer; ItemNo: Code[20])
+ var
+ ItemChargeAssgntPurch: Codeunit "Item Charge Assgnt. (Purch.)";
+ RecRef: RecordRef;
+ LineNo: Integer;
+ begin
+ ItemChargeAssignmentPurch.Init();
+
+ ItemChargeAssignmentPurch."Document Type" := PurchaseLine."Document Type";
+ ItemChargeAssignmentPurch."Document No." := PurchaseLine."Document No.";
+ ItemChargeAssignmentPurch."Document Line No." := PurchaseLine."Line No.";
+ ItemChargeAssignmentPurch."Item Charge No." := PurchaseLine."No.";
+ ItemChargeAssignmentPurch."Unit Cost" := PurchaseLine."Unit Cost";
+
+ RecRef.GetTable(ItemChargeAssignmentPurch);
+ LineNo := LibraryUtility.GetNewLineNo(RecRef, ItemChargeAssignmentPurch.FieldNo("Line No."));
+ ItemChargeAssgntPurch.InsertItemChargeAssignment(
+ ItemChargeAssignmentPurch, DocType, DocNo, DocLineNo, ItemNo, '', LineNo);
+
+ ItemChargeAssignmentPurch.Get(PurchaseLine."Document Type", PurchaseLine."Document No.", PurchaseLine."Line No.", LineNo);
+ ItemChargeAssignmentPurch.Validate("Qty. to Assign", PurchaseLine.Quantity);
+ ItemChargeAssignmentPurch.Modify(true);
+ end;
+
+#if not CLEAN26
+ [Obsolete('Moved to codeunit Library Manufacturing', '26.0')]
+ procedure CreateItemJournal(var ItemJournalBatch: Record "Item Journal Batch"; ItemNo: Code[20]; ItemJournalTemplateType: Enum "Item Journal Template Type"; ProductionOrderNo: Code[20])
+ var
+ LibraryManufacturing: Codeunit "Library - Manufacturing";
+ begin
+ LibraryManufacturing.CreateProdItemJournal(ItemJournalBatch, ItemNo, ItemJournalTemplateType, ProductionOrderNo);
+ end;
+#endif
+
+ procedure CreateItemJournalTemplate(var ItemJournalTemplate: Record "Item Journal Template")
+ begin
+ ItemJournalTemplate.Init();
+ ItemJournalTemplate.Validate(
+ Name,
+ CopyStr(
+ LibraryUtility.GenerateRandomCode(ItemJournalTemplate.FieldNo(Name), DATABASE::"Item Journal Template"),
+ 1,
+ LibraryUtility.GetFieldLength(DATABASE::"Item Journal Template", ItemJournalTemplate.FieldNo(Name))));
+ ItemJournalTemplate.Validate(Description, ItemJournalTemplate.Name);
+ // Validating Name as Description because value is not important.
+ ItemJournalTemplate.Insert(true);
+ end;
+
+ procedure CreateItemJournalTemplateByType(var ItemJournalTemplate: Record "Item Journal Template"; TemplateType: Enum "Item Journal Template Type")
+ begin
+ CreateItemJournalTemplate(ItemJournalTemplate);
+ ItemJournalTemplate.Validate(Type, TemplateType);
+ ItemJournalTemplate.Modify(true);
+ end;
+
+ procedure CreateItemJournalBatch(var ItemJournalBatch: Record "Item Journal Batch"; ItemJournalTemplateName: Code[10])
+ begin
+ // Create Item Journal Batch with a random Name of String length less than 10.
+ ItemJournalBatch.Init();
+ ItemJournalBatch.Validate("Journal Template Name", ItemJournalTemplateName);
+ ItemJournalBatch.Validate(
+ Name, CopyStr(LibraryUtility.GenerateRandomCode(ItemJournalBatch.FieldNo(Name), DATABASE::"Item Journal Batch"), 1,
+ MaxStrLen(ItemJournalBatch.Name)));
+ ItemJournalBatch.Insert(true);
+ end;
+
+ procedure CreateItemJournalBatchByType(var ItemJournalBatch: Record "Item Journal Batch"; TemplateType: Enum "Item Journal Template Type")
+ var
+ ItemJournalTemplate: Record "Item Journal Template";
+ begin
+ Clear(ItemJournalBatch);
+ SelectItemJournalTemplateName(ItemJournalTemplate, TemplateType);
+ ItemJournalBatch."Journal Template Name" := ItemJournalTemplate.Name;
+ ItemJournalBatch.Name := LibraryUtility.GenerateRandomCode(ItemJournalBatch.FieldNo(Name), DATABASE::"Item Journal Batch");
+ ItemJournalBatch.Insert(true);
+ end;
+
+ procedure CreateItemJournalLine(var ItemJournalLine: Record "Item Journal Line"; JournalTemplateName: Code[10]; JournalBatchName: Code[10]; EntryType: Enum "Item Ledger Entry Type"; ItemNo: Text[20]; NewQuantity: Decimal)
+ var
+ ItemJournalBatch: Record "Item Journal Batch";
+ begin
+ if not ItemJournalBatch.Get(JournalTemplateName, JournalBatchName) then begin
+ ItemJournalBatch.Init();
+ ItemJournalBatch.Validate("Journal Template Name", JournalTemplateName);
+ ItemJournalBatch.SetupNewBatch();
+ ItemJournalBatch.Validate(Name, JournalBatchName);
+ ItemJournalBatch.Validate(Description, JournalBatchName + JOURNALTxt);
+ ItemJournalBatch.Insert(true);
+ end;
+ CreateItemJnlLineWithNoItem(ItemJournalLine, ItemJournalBatch, JournalTemplateName, JournalBatchName, EntryType);
+ ItemJournalLine.Validate("Item No.", ItemNo);
+ ItemJournalLine.Validate(Quantity, NewQuantity);
+ ItemJournalLine.Modify(true);
+ end;
+
+ procedure CreateItemJournalLineInItemTemplate(var ItemJournalLine: Record "Item Journal Line"; ItemNo: Code[20]; LocationCode: Code[10]; BinCode: Code[20]; Qty: Decimal)
+ var
+ ItemJournalTemplate: Record "Item Journal Template";
+ ItemJournalBatch: Record "Item Journal Batch";
+ begin
+ SelectItemJournalTemplateName(ItemJournalTemplate, ItemJournalTemplate.Type::Item);
+ SelectItemJournalBatchName(ItemJournalBatch, ItemJournalTemplate.Type::Item, ItemJournalTemplate.Name);
+ CreateItemJournalLine(
+ ItemJournalLine, ItemJournalTemplate.Name, ItemJournalBatch.Name, ItemJournalLine."Entry Type"::"Positive Adjmt.", ItemNo, Qty);
+ ItemJournalLine.Validate("Location Code", LocationCode);
+ ItemJournalLine.Validate("Bin Code", BinCode);
+ ItemJournalLine.Modify(true);
+ end;
+
+ procedure CreateItemJnlLine(var ItemJnlLine: Record "Item Journal Line"; EntryType: Enum "Item Ledger Entry Type"; PostingDate: Date; ItemNo: Code[20]; Qty: Decimal; LocationCode: Code[10])
+ var
+ ItemJnlTemplate: Record "Item Journal Template";
+ ItemJnlBatch: Record "Item Journal Batch";
+ begin
+ FindItemJournalTemplate(ItemJnlTemplate);
+ FindItemJournalBatch(ItemJnlBatch, ItemJnlTemplate);
+ CreateItemJournalLine(ItemJnlLine, ItemJnlTemplate.Name, ItemJnlBatch.Name, EntryType, ItemNo, Qty);
+ ItemJnlLine."Posting Date" := PostingDate;
+ ItemJnlLine."Location Code" := LocationCode;
+ ItemJnlLine.Modify();
+ end;
+
+ procedure CreateItemJnlLine(var ItemJnlLine: Record "Item Journal Line"; EntryType: Enum "Item Ledger Entry Type"; PostingDate: Date; ItemNo: Code[20]; Qty: Decimal; LocationCode: Code[10]; NewDocNo: Code[20])
+ begin
+ CreateItemJnlLine(ItemJnlLine, EntryType, PostingDate, ItemNo, Qty, LocationCode);
+ ItemJnlLine."Document No." := NewDocNo;
+ ItemJnlLine.Modify();
+ end;
+
+ procedure CreateItemJnlLineWithNoItem(var ItemJournalLine: Record "Item Journal Line"; ItemJournalBatch: Record "Item Journal Batch"; JournalTemplateName: Code[10]; JournalBatchName: Code[10]; EntryType: Enum "Item Ledger Entry Type")
+ var
+ NoSeries: Record "No. Series";
+ NoSeriesCodeunit: Codeunit "No. Series";
+ RecRef: RecordRef;
+ DocumentNo: Code[20];
+ begin
+ Clear(ItemJournalLine);
+ ItemJournalLine.Init();
+ ItemJournalLine.Validate("Journal Template Name", JournalTemplateName);
+ ItemJournalLine.Validate("Journal Batch Name", JournalBatchName);
+ RecRef.GetTable(ItemJournalLine);
+ ItemJournalLine.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, ItemJournalLine.FieldNo("Line No.")));
+ ItemJournalLine.Insert(true);
+ ItemJournalLine.Validate("Posting Date", WorkDate());
+ ItemJournalLine.Validate("Entry Type", EntryType);
+ if NoSeries.Get(ItemJournalBatch."No. Series") then
+ DocumentNo := NoSeriesCodeunit.PeekNextNo(ItemJournalBatch."No. Series", ItemJournalLine."Posting Date")
+ else
+ DocumentNo := LibraryUtility.GenerateRandomCode(ItemJournalLine.FieldNo("Document No."), DATABASE::"Item Journal Line");
+ ItemJournalLine.Validate("Document No.", DocumentNo);
+ ItemJournalLine.Modify(true);
+
+ OnAfterCreateItemJnlLineWithNoItem(ItemJournalLine, ItemJournalBatch, JournalTemplateName, JournalBatchName, EntryType.AsInteger());
+ end;
+
+ procedure CreateItemManufacturing(var Item: Record Item): Code[20]
+ var
+ ItemUnitOfMeasure: Record "Item Unit of Measure";
+ GeneralPostingSetup: Record "General Posting Setup";
+ InventoryPostingGroup: Record "Inventory Posting Group";
+ TaxGroup: Record "Tax Group";
+ VATPostingSetup: Record "VAT Posting Setup";
+ InventoryPostingSetup: Record "Inventory Posting Setup";
+ begin
+ ItemNoSeriesSetup(InventorySetup);
+ Clear(Item);
+ Item.Insert(true);
+
+ CreateItemUnitOfMeasure(ItemUnitOfMeasure, Item."No.", '', 1);
+
+ LibraryERM.FindGeneralPostingSetupInvtToGL(GeneralPostingSetup);
+ LibraryERM.FindVATPostingSetupInvt(VATPostingSetup);
+ InventoryPostingGroup.FindFirst();
+
+ InventoryPostingSetup.SetRange("Invt. Posting Group Code", InventoryPostingGroup.Code);
+ if not InventoryPostingSetup.FindFirst() then
+ CreateInventoryPostingSetup(InventoryPostingSetup, '', InventoryPostingGroup.Code);
+
+ Item.Validate(Description, Item."No."); // Validation Description as No. because value is not important.
+ Item.Validate("Base Unit of Measure", ItemUnitOfMeasure.Code);
+ Item.Validate("Gen. Prod. Posting Group", GeneralPostingSetup."Gen. Prod. Posting Group");
+ Item.Validate("VAT Prod. Posting Group", VATPostingSetup."VAT Prod. Posting Group");
+ Item.Validate("Inventory Posting Group", InventoryPostingGroup.Code);
+
+ if TaxGroup.FindFirst() then
+ Item.Validate("Tax Group Code", TaxGroup.Code);
+
+ Item.Modify(true);
+ OnAfterCreateItemManufacturing(Item);
+ exit(Item."No.");
+ end;
+
+ procedure CreateItemTrackingCode(var ItemTrackingCode: Record "Item Tracking Code")
+ begin
+ ItemTrackingCode.Init();
+ ItemTrackingCode.Validate(Code, LibraryUtility.GenerateRandomCode(ItemTrackingCode.FieldNo(Code), DATABASE::"Item Tracking Code"));
+ ItemTrackingCode.Insert(true);
+ end;
+
+ procedure CreateItemUnitOfMeasure(var ItemUnitOfMeasure: Record "Item Unit of Measure"; ItemNo: Code[20]; UnitOfMeasureCode: Code[10]; QtyPerUoM: Decimal)
+ begin
+ CreateItemUnitOfMeasure(ItemUnitOfMeasure, ItemNo, UnitOfMeasureCode, QtyPerUoM, 0);
+ end;
+
+ procedure CreateItemUnitOfMeasure(var ItemUnitOfMeasure: Record "Item Unit of Measure"; ItemNo: Code[20]; UnitOfMeasureCode: Code[10]; QtyPerUoM: Decimal; QtyRndPrecision: Decimal)
+ var
+ UnitOfMeasure: Record "Unit of Measure";
+ begin
+ ItemUnitOfMeasure.Init();
+ ItemUnitOfMeasure.Validate("Item No.", ItemNo);
+
+ // The IF condition is important because it grants flexibility to the function.
+ if UnitOfMeasureCode = '' then begin
+ UnitOfMeasure.SetFilter(Code, '<>%1', UnitOfMeasureCode);
+ if not UnitOfMeasure.FindFirst() then
+ CreateUnitOfMeasureCode(UnitOfMeasure);
+ ItemUnitOfMeasure.Validate(Code, UnitOfMeasure.Code);
+ end else
+ ItemUnitOfMeasure.Validate(Code, UnitOfMeasureCode);
+ if QtyPerUoM = 0 then
+ QtyPerUoM := 1;
+ ItemUnitOfMeasure.Validate("Qty. per Unit of Measure", QtyPerUoM);
+
+ if QtyRndPrecision <> 0 then
+ ItemUnitOfMeasure.Validate("Qty. Rounding Precision", QtyRndPrecision);
+ ItemUnitOfMeasure.Insert(true);
+ end;
+
+ procedure CreateItemUnitOfMeasureCode(var ItemUnitOfMeasure: Record "Item Unit of Measure"; ItemNo: Code[20]; QtyPerUoM: Decimal)
+ var
+ UnitOfMeasure: Record "Unit of Measure";
+ begin
+ CreateUnitOfMeasureCode(UnitOfMeasure);
+ CreateItemUnitOfMeasure(ItemUnitOfMeasure, ItemNo, UnitOfMeasure.Code, QtyPerUoM);
+ end;
+
+ procedure CreateItemVariant(var ItemVariant: Record "Item Variant"; ItemNo: Code[20]): Code[10]
+ var
+ Handled: Boolean;
+ begin
+ OnBeforeCreateItemVariant(ItemVariant, ItemNo, Handled);
+ if Handled then
+ exit(ItemVariant.Code);
+
+ ItemVariant.Init();
+ ItemVariant.Validate("Item No.", ItemNo);
+ ItemVariant.Validate(Code, LibraryUtility.GenerateRandomCode(ItemVariant.FieldNo(Code), DATABASE::"Item Variant"));
+ ItemVariant.Validate(Description, ItemVariant.Code);
+ ItemVariant.Insert(true);
+ OnAfterCreateItemVariant(ItemVariant, ItemNo);
+
+ exit(ItemVariant.Code)
+ end;
+
+ procedure CreateItemVendor(var ItemVendor: Record "Item Vendor"; VendorNo: Code[20]; ItemNo: Code[20])
+ begin
+ ItemVendor.Init();
+ ItemVendor.Validate("Vendor No.", VendorNo);
+ ItemVendor.Validate("Item No.", ItemNo);
+ ItemVendor.Insert(true);
+ end;
+
+ procedure CreateNonStock(var NonstockItem: Record "Nonstock Item")
+ begin
+ NonstockItem.Init();
+ NonstockItem.Validate(
+ "Entry No.", LibraryUtility.GenerateRandomCode(NonstockItem.FieldNo("Entry No."), DATABASE::"Nonstock Item"));
+ NonstockItem.Insert(true);
+ end;
+
+ procedure CreateNonStockItem(var NonstockItem: Record "Nonstock Item")
+ var
+ ItemCategory: Record "Item Category";
+ ItemTemplate: Record "Item Templ.";
+ UnitOfMeasure: Record "Unit of Measure";
+ CatalogItemManagement: Codeunit "Catalog Item Management";
+ begin
+ ItemCategory.FindFirst();
+ CreateUnitOfMeasureCode(UnitOfMeasure);
+ ItemTemplate.FindFirst();
+
+ CreateNonStock(NonstockItem);
+ NonstockItem.Validate("Vendor No.", LibraryPurchase.CreateVendorNo());
+ NonstockItem.Validate(
+ "Vendor Item No.", LibraryUtility.GenerateRandomCode(NonstockItem.FieldNo("Vendor Item No."), DATABASE::"Nonstock Item"));
+ NonstockItem.Validate("Item Templ. Code", ItemTemplate.Code);
+ NonstockItem.Validate("Unit of Measure", UnitOfMeasure.Code);
+ NonstockItem.Validate(Description, NonstockItem."Entry No.");
+ NonstockItem.Modify(true);
+ CatalogItemManagement.NonstockAutoItem(NonstockItem);
+ end;
+
+ procedure CreateNonStockItemWithItemTemplateCode(var NonstockItem: Record "Nonstock Item"; ItemTemplateCode: Code[20])
+ var
+ ItemCategory: Record "Item Category";
+ UnitOfMeasure: Record "Unit of Measure";
+ CatalogItemManagement: Codeunit "Catalog Item Management";
+ begin
+ ItemCategory.FindFirst();
+ CreateUnitOfMeasureCode(UnitOfMeasure);
+
+ CreateNonStock(NonstockItem);
+ NonstockItem.Validate("Vendor No.", LibraryPurchase.CreateVendorNo());
+ NonstockItem.Validate(
+ "Vendor Item No.", LibraryUtility.GenerateRandomCode(NonstockItem.FieldNo("Vendor Item No."), DATABASE::"Nonstock Item"));
+ NonstockItem.Validate("Item Templ. Code", ItemTemplateCode);
+ NonstockItem.Validate("Unit of Measure", UnitOfMeasure.Code);
+ NonstockItem.Validate(Description, NonstockItem."Entry No.");
+ NonstockItem.Modify(true);
+ CatalogItemManagement.NonstockAutoItem(NonstockItem);
+ end;
+
+ procedure CreateServiceTypeItem(var Item: Record Item)
+ begin
+ CreateItem(Item);
+ Item.Validate(Type, Item.Type::Service);
+ Item.Modify(true);
+ end;
+
+ procedure CreateNonInventoryTypeItem(var Item: Record Item)
+ begin
+ CreateItem(Item);
+ Item.Validate(Type, Item.Type::"Non-Inventory");
+ Item.Modify(true);
+ end;
+
+ procedure CreateStockKeepingUnit(var Item: Record Item; CreationMethod: Enum "SKU Creation Method"; NewItemInInventoryOnly: Boolean; NewReplacePreviousSKUs: Boolean)
+ var
+ TmpItem: Record Item;
+ CreateStockkeepingUnitReport: Report "Create Stockkeeping Unit";
+ begin
+ CreateStockkeepingUnitReport.SetParameters(CreationMethod, NewItemInInventoryOnly, NewReplacePreviousSKUs);
+ if Item.HasFilter then
+ TmpItem.CopyFilters(Item)
+ else begin
+ Item.Get(Item."No.");
+ TmpItem.SetRange("No.", Item."No.");
+ end;
+
+ CreateStockkeepingUnitReport.SetTableView(TmpItem);
+ CreateStockkeepingUnitReport.UseRequestPage(false);
+ CreateStockkeepingUnitReport.Run();
+ end;
+
+ procedure CreateStockkeepingUnitForLocationAndVariant(var StockkeepingUnit: Record "Stockkeeping Unit"; LocationCode: Code[10]; ItemNo: Code[20]; VariantCode: Code[10])
+ begin
+ StockkeepingUnit.Init();
+ StockkeepingUnit.Validate("Location Code", LocationCode);
+ StockkeepingUnit.Validate("Item No.", ItemNo);
+ StockkeepingUnit.Validate("Variant Code", VariantCode);
+ StockkeepingUnit.Insert(true);
+ end;
+
+ procedure CreateShippingAgent(var ShippingAgent: Record "Shipping Agent")
+ begin
+ ShippingAgent.Init();
+ ShippingAgent.Validate(Code, LibraryUtility.GenerateRandomCode(ShippingAgent.FieldNo(Code), DATABASE::"Shipping Agent"));
+ ShippingAgent.Insert(true);
+ end;
+
+ procedure CreateShippingAgentService(var ShippingAgentServices: Record "Shipping Agent Services"; ShippingAgentCode: Code[10]; ShippingTime: DateFormula)
+ begin
+ ShippingAgentServices.Init();
+ ShippingAgentServices.Validate("Shipping Agent Code", ShippingAgentCode);
+ ShippingAgentServices.Validate(
+ Code, LibraryUtility.GenerateRandomCode(ShippingAgentServices.FieldNo(Code), DATABASE::"Shipping Agent Services"));
+ ShippingAgentServices.Insert(true);
+ ShippingAgentServices.Validate("Shipping Time", ShippingTime);
+ ShippingAgentServices.Modify(true);
+ end;
+
+ procedure CreateShippingAgentServiceUsingPages(ShippingAgentCode: Code[10]) ShippingAgentServiceCode: Code[10]
+ var
+ ShippingAgentServices: Record "Shipping Agent Services";
+ ShippingTime: DateFormula;
+ ShippingAgents: TestPage "Shipping Agents";
+ ShippingAgentServicesPage: TestPage "Shipping Agent Services";
+ begin
+ ShippingAgents.OpenEdit();
+ ShippingAgents.GotoKey(ShippingAgentCode);
+
+ ShippingAgentServicesPage.Trap();
+ ShippingAgents.ShippingAgentServices.Invoke();
+
+ ShippingAgentServiceCode :=
+ LibraryUtility.GenerateRandomCode(ShippingAgentServices.FieldNo(Code), DATABASE::"Shipping Agent Services");
+ Evaluate(ShippingTime, '<1M>');
+
+ ShippingAgentServicesPage.New();
+ ShippingAgentServicesPage.Code.SetValue(ShippingAgentServiceCode);
+ ShippingAgentServicesPage."Shipping Time".SetValue(ShippingTime);
+
+ ShippingAgentServicesPage.Close();
+ end;
+
+ procedure CreateStandardCostWorksheetName(var StandardCostWorksheetName: Record "Standard Cost Worksheet Name")
+ begin
+ StandardCostWorksheetName.Init();
+ StandardCostWorksheetName.Validate(
+ Name, LibraryUtility.GenerateRandomCode(StandardCostWorksheetName.FieldNo(Name), DATABASE::"Standard Cost Worksheet Name"));
+ StandardCostWorksheetName.Insert(true);
+ end;
+
+ procedure CreateTrackedItem(var Item: Record Item; LotNos: Code[20]; SerialNos: Code[20]; ItemTrackingCode: Code[10])
+ begin
+ CreateItem(Item);
+ Item.Validate("Item Tracking Code", ItemTrackingCode);
+ Item.Validate("Serial Nos.", SerialNos);
+ Item.Validate("Lot Nos.", LotNos);
+ Item.Modify(true);
+ end;
+
+ procedure CreateTransferHeader(var TransferHeader: Record "Transfer Header")
+ var
+ Location: Record Location;
+ FromLocationCode, ToLocationCode, InTransitLocationCode : Text[10];
+ begin
+ FromLocationCode := LibraryWarehouse.CreateLocationWithInventoryPostingSetup(Location);
+ ToLocationCode := LibraryWarehouse.CreateLocationWithInventoryPostingSetup(Location);
+ LibraryWarehouse.CreateInTransitLocation(Location);
+ InTransitLocationCode := Location.Code;
+
+ CreateTransferHeader(TransferHeader, FromLocationCode, ToLocationCode, InTransitLocationCode);
+ end;
+
+ procedure CreateTransferHeader(var TransferHeader: Record "Transfer Header"; FromLocation: Text[10]; ToLocation: Text[10]; InTransitCode: Text[10])
+ var
+ Handled: Boolean;
+ begin
+ OnBeforeCreateTransferHeader(TransferHeader, FromLocation, ToLocation, InTransitCode, Handled);
+ if Handled then
+ exit;
+
+ Clear(TransferHeader);
+ TransferHeader.Init();
+ TransferHeader.Insert(true);
+ TransferHeader.Validate("Transfer-from Code", FromLocation);
+ TransferHeader.Validate("Transfer-to Code", ToLocation);
+ TransferHeader.Validate("In-Transit Code", InTransitCode);
+ TransferHeader.Modify(true);
+
+ OnAfterCreateTransferHeader(TransferHeader, FromLocation, ToLocation, InTransitCode);
+ end;
+
+ procedure CreateTransferLine(var TransferHeader: Record "Transfer Header"; var TransferLine: Record "Transfer Line"; ItemNo: Text[20]; Quantity: Decimal)
+ var
+ RecRef: RecordRef;
+ begin
+ Clear(TransferLine);
+ TransferLine.Init();
+ TransferLine.Validate("Document No.", TransferHeader."No.");
+ RecRef.GetTable(TransferLine);
+ TransferLine.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, TransferLine.FieldNo("Line No.")));
+ TransferLine.Insert(true);
+ TransferLine.Validate("Item No.", ItemNo);
+ TransferLine.Validate(Quantity, Quantity);
+ TransferLine.Modify(true);
+ end;
+
+ procedure CreateTransferOrder(var TransferHeader: Record "Transfer Header"; var TransferLine: Record "Transfer Line"; Item: Record Item; FromLocation: Record Location; ToLocation: Record Location; InTransitLocation: Record Location; VariantCode: Code[10]; Qty: Decimal; PostingDate: Date; ShipmentDate: Date)
+ begin
+ CreateTransferHeader(TransferHeader, FromLocation.Code, ToLocation.Code, InTransitLocation.Code);
+ TransferHeader.Validate("Posting Date", PostingDate);
+ TransferHeader.Validate("Shipment Date", ShipmentDate);
+ TransferHeader.Modify();
+ CreateTransferLine(TransferHeader, TransferLine, Item."No.", Qty);
+ TransferLine.Validate("Shipment Date", ShipmentDate);
+ TransferLine.Validate("Variant Code", VariantCode);
+ TransferLine.Modify();
+ end;
+
+ procedure CreateTransferRoute(var TransferRoute: Record "Transfer Route"; TransferFrom: Code[10]; TransferTo: Code[10])
+ begin
+ Clear(TransferRoute);
+ TransferRoute.Init();
+ TransferRoute.Validate("Transfer-from Code", TransferFrom);
+ TransferRoute.Validate("Transfer-to Code", TransferTo);
+ TransferRoute.Insert(true);
+ end;
+
+ procedure CreateAndPostTransferOrder(var TransferHeader: Record "Transfer Header"; Item: Record Item; FromLocation: Record Location; ToLocation: Record Location; InTransitLocation: Record Location; VariantCode: Code[10]; Qty: Decimal; PostingDate: Date; ShipmentDate: Date; Ship: Boolean; Receive: Boolean)
+ var
+ TransferLine: Record "Transfer Line";
+ begin
+ CreateTransferOrder(
+ TransferHeader, TransferLine, Item, FromLocation, ToLocation, InTransitLocation, VariantCode, Qty, PostingDate, ShipmentDate);
+ PostTransferHeader(TransferHeader, Ship, Receive);
+ end;
+
+ procedure CreateUnitOfMeasureCode(var UnitOfMeasure: Record "Unit of Measure")
+ begin
+ UnitOfMeasure.Init();
+ UnitOfMeasure.Validate(Code, LibraryUtility.GenerateRandomCode(UnitOfMeasure.FieldNo(Code), DATABASE::"Unit of Measure"));
+ UnitOfMeasure.Validate(Description, UnitOfMeasure.Code);
+ UnitOfMeasure.Validate("International Standard Code",
+ LibraryUtility.GenerateRandomCode(UnitOfMeasure.FieldNo("International Standard Code"), DATABASE::"Unit of Measure"));
+ UnitOfMeasure.Validate(Symbol,
+ LibraryUtility.GenerateRandomCode(UnitOfMeasure.FieldNo(Symbol), DATABASE::"Unit of Measure"));
+ UnitOfMeasure.Insert(true);
+ end;
+
+ procedure CreateVariant(var ItemVariant: Record "Item Variant"; Item: Record Item)
+ var
+ Handled: Boolean;
+ begin
+ OnBeforeCreateVariant(ItemVariant, Item, Handled);
+ if Handled then
+ exit;
+
+ Clear(ItemVariant);
+ ItemVariant.Init();
+ ItemVariant.Validate("Item No.", Item."No.");
+ ItemVariant.Validate(Code, LibraryUtility.GenerateRandomCode(ItemVariant.FieldNo(Code), DATABASE::"Item Variant"));
+ ItemVariant.Validate(Description, ItemVariant.Code);
+ ItemVariant.Insert();
+
+ OnAfterCreateVariant(ItemVariant, Item);
+ end;
+
+ procedure CreatePhysicalInventoryCountingPeriod(var PhysInvtCountingPeriod: Record "Phys. Invt. Counting Period")
+ begin
+ Clear(PhysInvtCountingPeriod);
+ PhysInvtCountingPeriod.Init();
+ PhysInvtCountingPeriod.Validate(
+ Code, LibraryUtility.GenerateRandomCode(PhysInvtCountingPeriod.FieldNo(Code), DATABASE::"Phys. Invt. Counting Period"));
+ PhysInvtCountingPeriod.Insert(true);
+ end;
+
+ procedure CreatePaymentTerms(var PaymentTerms: Record "Payment Terms")
+ begin
+ PaymentTerms.Init();
+ PaymentTerms.Validate(Code, LibraryUtility.GenerateRandomCode(PaymentTerms.FieldNo(Code), DATABASE::"Payment Terms"));
+ PaymentTerms.Validate(Description, PaymentTerms.Code);
+ PaymentTerms.Insert(true);
+ end;
+
+ procedure CreatePaymentMethod(var PaymentMethod: Record "Payment Method")
+ begin
+ PaymentMethod.Init();
+ PaymentMethod.Validate(Code, LibraryUtility.GenerateRandomCode(PaymentMethod.FieldNo(Code), DATABASE::"Payment Method"));
+ PaymentMethod.Validate(Description, PaymentMethod.Code);
+ PaymentMethod.Insert(true);
+ end;
+
+ procedure CreateExtendedTextForItem(ItemNo: Code[20]): Text
+ var
+ ExtendedTextHeader: Record "Extended Text Header";
+ ExtendedTextLine: Record "Extended Text Line";
+ begin
+ CreateExtendedTextHeaderItem(ExtendedTextHeader, ItemNo);
+ CreateExtendedTextLineItem(ExtendedTextLine, ExtendedTextHeader);
+ ExtendedTextLine.Validate(Text, LibraryUtility.GenerateGUID());
+ ExtendedTextLine.Modify();
+ exit(ExtendedTextLine.Text);
+ end;
+
+ procedure CreateExtendedTextHeaderItem(var ExtendedTextHeader: Record "Extended Text Header"; ItemNo: Code[20])
+ begin
+ ExtendedTextHeader.Init();
+ ExtendedTextHeader.Validate("Table Name", ExtendedTextHeader."Table Name"::Item);
+ ExtendedTextHeader.Validate("No.", ItemNo);
+ ExtendedTextHeader.Insert(true);
+ end;
+
+ procedure CreateExtendedTextLineItem(var ExtendedTextLine: Record "Extended Text Line"; ExtendedTextHeader: Record "Extended Text Header")
+ var
+ RecRef: RecordRef;
+ begin
+ ExtendedTextLine.Init();
+ ExtendedTextLine.Validate("Table Name", ExtendedTextHeader."Table Name");
+ ExtendedTextLine.Validate("No.", ExtendedTextHeader."No.");
+ ExtendedTextLine.Validate("Language Code", ExtendedTextHeader."Language Code");
+ ExtendedTextLine.Validate("Text No.", ExtendedTextHeader."Text No.");
+ RecRef.GetTable(ExtendedTextLine);
+ ExtendedTextLine.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, ExtendedTextLine.FieldNo("Line No.")));
+ ExtendedTextLine.Insert(true);
+ end;
+
+ procedure CopyItemAttributeToFilterItemAttributesBuffer(var TempFilterItemAttributesBuffer: Record "Filter Item Attributes Buffer" temporary; ItemAttributeValue: Record "Item Attribute Value")
+ begin
+ ItemAttributeValue.CalcFields("Attribute Name");
+ TempFilterItemAttributesBuffer.Init();
+ TempFilterItemAttributesBuffer.Attribute := ItemAttributeValue."Attribute Name";
+ TempFilterItemAttributesBuffer.Value := ItemAttributeValue.Value;
+ TempFilterItemAttributesBuffer.Insert();
+ end;
+
+ procedure CalculateCountingPeriod(var ItemJournalLine: Record "Item Journal Line")
+ var
+ PhysInvtCountManagement: Codeunit "Phys. Invt. Count.-Management";
+ begin
+ Clear(PhysInvtCountManagement);
+ PhysInvtCountManagement.InitFromItemJnl(ItemJournalLine);
+ PhysInvtCountManagement.Run();
+ end;
+
+ procedure DateComprItemBudgetEntries(var ItemBudgetEntry: Record "Item Budget Entry"; AnalysisAreaSelection: Option; StartDate: Date; EndDate: Date; PeriodLength: Option; Description: Text[50])
+ var
+ TmpItemBudgetEntry: Record "Item Budget Entry";
+ AnalysisView: Record "Analysis View";
+ DateCompItemBudgetEntries: Report "Date Comp. Item Budget Entries";
+ RetainDimensions: Text;
+ begin
+ SetAnalysisViewDimensions(3 /*ObjectType::Report*/, Report::"Date Comp. Item Budget Entries", RetainDimensions);
+ AnalysisView.UpdateAllAnalysisViews(true);
+ DateCompItemBudgetEntries.InitializeRequest(AnalysisAreaSelection, StartDate, EndDate, PeriodLength, Description, RetainDimensions);
+ if ItemBudgetEntry.HasFilter then
+ TmpItemBudgetEntry.CopyFilters(ItemBudgetEntry)
+ else begin
+ ItemBudgetEntry.Get(ItemBudgetEntry."Entry No.");
+ TmpItemBudgetEntry.SetRange("Entry No.", ItemBudgetEntry."Entry No.");
+ end;
+ DateCompItemBudgetEntries.SetTableView(TmpItemBudgetEntry);
+ DateCompItemBudgetEntries.SetSkipAnalysisViewUpdateCheck();
+ DateCompItemBudgetEntries.UseRequestPage(false);
+ DateCompItemBudgetEntries.RunModal();
+ end;
+
+ local procedure SetAnalysisViewDimensions(ObjectType: Option; ObjectId: Integer; var RetainDimensions: Text[250])
+ var
+ SelectedDimension: Record "Selected Dimension";
+ AnalysisView: Record "Analysis View";
+ DimensionSelectionBuffer: Record "Dimension Selection Buffer";
+ begin
+ if AnalysisView.FindSet() then begin
+ repeat
+ if not SelectedDimension.Get(UserId, ObjectType, ObjectId, '', AnalysisView."Dimension 1 Code") then
+ InsertSelectedDimension(ObjectType, ObjectId, AnalysisView."Dimension 1 Code");
+ if not SelectedDimension.Get(UserId, ObjectType, ObjectId, '', AnalysisView."Dimension 2 Code") then
+ InsertSelectedDimension(ObjectType, ObjectId, AnalysisView."Dimension 2 Code");
+ if not SelectedDimension.Get(UserId, ObjectType, ObjectId, '', AnalysisView."Dimension 3 Code") then
+ InsertSelectedDimension(ObjectType, ObjectId, AnalysisView."Dimension 3 Code");
+ if not SelectedDimension.Get(UserId, ObjectType, ObjectId, '', AnalysisView."Dimension 4 Code") then
+ InsertSelectedDimension(ObjectType, ObjectId, AnalysisView."Dimension 4 Code");
+ until AnalysisView.Next() = 0;
+
+ RetainDimensions := DimensionSelectionBuffer.GetDimSelectionText(ObjectType, ObjectId, '');
+ end;
+ end;
+
+ local procedure InsertSelectedDimension(ObjectType: Option; ObjectId: Integer; DimensionCode: Text)
+ var
+ SelectedDimension: Record "Selected Dimension";
+ begin
+ if DimensionCode = '' then
+ exit;
+
+ SelectedDimension.Init();
+ SelectedDimension."User ID" := CopyStr(UserId, 1, MaxStrLen(SelectedDimension."User ID"));
+ SelectedDimension."Object Type" := ObjectType;
+ SelectedDimension."Object ID" := ObjectId;
+ SelectedDimension."Analysis View Code" := '';
+ SelectedDimension."Dimension Code" := CopyStr(DimensionCode, 1, MaxStrLen(SelectedDimension."Dimension Code"));
+ SelectedDimension.Insert();
+ end;
+
+ procedure FindItemJournalBatch(var ItemJnlBatch: Record "Item Journal Batch"; ItemJnlTemplate: Record "Item Journal Template")
+ var
+ NoSeries: Record "No. Series";
+ NoSeriesLine: Record "No. Series Line";
+ begin
+ ItemJnlBatch.SetRange("Template Type", ItemJnlTemplate.Type);
+ ItemJnlBatch.SetRange("Journal Template Name", ItemJnlTemplate.Name);
+
+ if not ItemJnlBatch.FindFirst() then
+ CreateItemJournalBatch(ItemJnlBatch, ItemJnlTemplate.Name);
+
+ if ItemJnlBatch."No. Series" = '' then begin
+ LibraryUtility.CreateNoSeries(NoSeries, true, false, false);
+ LibraryUtility.CreateNoSeriesLine(NoSeriesLine, NoSeries.Code, '', '');
+ ItemJnlBatch."No. Series" := NoSeries.Code;
+ end;
+ end;
+
+ procedure FindItemJournalTemplate(var ItemJournalTemplate: Record "Item Journal Template")
+ begin
+ ItemJournalTemplate.SetRange(Type, ItemJournalTemplate.Type::Item);
+ ItemJournalTemplate.SetRange(Recurring, false);
+ if not ItemJournalTemplate.FindFirst() then begin
+ CreateItemJournalTemplate(ItemJournalTemplate);
+ ItemJournalTemplate.Validate(Type, ItemJournalTemplate.Type::Item);
+ ItemJournalTemplate.Modify(true);
+ end;
+ end;
+
+ procedure FindItemJournalLine(var ItemJournalLine: Record "Item Journal Line"; ItemJournalBatch: Record "Item Journal Batch")
+ begin
+ ItemJournalLine.SetRange("Journal Template Name", ItemJournalBatch."Journal Template Name");
+ ItemJournalLine.SetRange("Journal Batch Name", ItemJournalBatch.Name);
+ ItemJournalLine.FindFirst();
+ end;
+
+ procedure FindUnitOfMeasure(var UnitOfMeasure: Record "Unit of Measure")
+ begin
+ if not UnitOfMeasure.FindFirst() then
+ CreateUnitOfMeasureCode(UnitOfMeasure);
+ end;
+
+ procedure GetQtyPerForItemUOM(ItemNo: Code[20]; UOMCode: Code[10]): Decimal
+ var
+ ItemUnitOfMeasure: Record "Item Unit of Measure";
+ begin
+ Clear(ItemUnitOfMeasure);
+ ItemUnitOfMeasure.Get(ItemNo, UOMCode);
+
+ exit(ItemUnitOfMeasure."Qty. per Unit of Measure");
+ end;
+
+ procedure GetVariant(ItemNo: Code[20]; OldVariantCode: Code[10]): Code[10]
+ var
+ ItemVariant: Record "Item Variant";
+ begin
+ ItemVariant.SetRange("Item No.", ItemNo);
+ ItemVariant.SetFilter(Code, '<>%1', OldVariantCode);
+ if ItemVariant.Count = 0 then
+ exit('');
+ ItemVariant.Next(LibraryRandom.RandInt(ItemVariant.Count));
+ exit(ItemVariant.Code);
+ end;
+
+ procedure GetReservConfirmText(): Text
+ begin
+ exit(ReserveConfirmMsg);
+ end;
+
+ procedure NoSeriesSetup(var InventorySetup2: Record "Inventory Setup")
+ begin
+ InventorySetup2.Get();
+ InventorySetup2.Validate("Internal Movement Nos.", LibraryUtility.GetGlobalNoSeriesCode());
+ InventorySetup2.Validate("Inventory Movement Nos.", LibraryUtility.GetGlobalNoSeriesCode());
+ InventorySetup2.Validate("Inventory Pick Nos.", LibraryUtility.GetGlobalNoSeriesCode());
+ InventorySetup2.Validate("Inventory Put-away Nos.", LibraryUtility.GetGlobalNoSeriesCode());
+ InventorySetup2.Validate("Item Nos.", LibraryUtility.GetGlobalNoSeriesCode());
+ InventorySetup2.Validate("Posted Invt. Pick Nos.", LibraryUtility.GetGlobalNoSeriesCode());
+ InventorySetup2.Validate("Posted Transfer Rcpt. Nos.", LibraryUtility.GetGlobalNoSeriesCode());
+ InventorySetup2.Validate("Posted Transfer Shpt. Nos.", LibraryUtility.GetGlobalNoSeriesCode());
+ InventorySetup2.Validate("Registered Invt. Movement Nos.", LibraryUtility.GetGlobalNoSeriesCode());
+ InventorySetup2.Validate("Transfer Order Nos.", LibraryUtility.GetGlobalNoSeriesCode());
+ InventorySetup2.Validate("Posted Invt. Put-away Nos.", LibraryUtility.GetGlobalNoSeriesCode());
+ InventorySetup2.Modify(true);
+ end;
+
+ local procedure ItemNoSeriesSetup(var InventorySetup2: Record "Inventory Setup")
+ var
+ NoSeriesCode: Code[20];
+ begin
+ InventorySetup2.Get();
+ NoSeriesCode := LibraryUtility.GetGlobalNoSeriesCode();
+ if NoSeriesCode <> InventorySetup2."Item Nos." then begin
+ InventorySetup2.Validate("Item Nos.", LibraryUtility.GetGlobalNoSeriesCode());
+ InventorySetup2.Modify(true);
+ end;
+ end;
+
+ procedure CreateItemJournalLine(var ItemJournalLine: Record "Item Journal Line"; ItemJournalBatch: Record "Item Journal Batch"; Item: Record Item; LocationCode: Code[10]; VariantCode: Code[10]; PostingDate: Date; EntryType: Enum "Item Ledger Entry Type"; Qty: Decimal; UnitAmount: Decimal)
+ begin
+ MakeItemJournalLine(ItemJournalLine, ItemJournalBatch, Item, PostingDate, EntryType, Qty);
+ ItemJournalLine."Location Code" := LocationCode;
+ ItemJournalLine."Variant Code" := VariantCode;
+ ItemJournalLine.Validate("Unit Amount", UnitAmount);
+ ItemJournalLine.Insert();
+ end;
+
+ procedure CreateItemJournalLineWithApplication(var ItemJournalLine: Record "Item Journal Line"; ItemJournalBatch: Record "Item Journal Batch"; Item: Record Item; LocationCode: Code[10]; VariantCode: Code[10]; PostingDate: Date; EntryType: Enum "Item Ledger Entry Type"; Qty: Decimal; UnitAmount: Decimal; AppltoEntryNo: Integer)
+ begin
+ MakeItemJournalLine(ItemJournalLine, ItemJournalBatch, Item, PostingDate, EntryType, Qty);
+ ItemJournalLine."Location Code" := LocationCode;
+ ItemJournalLine."Variant Code" := VariantCode;
+ ItemJournalLine.Validate("Unit Amount", UnitAmount);
+ ItemJournalLine.Validate("Applies-to Entry", AppltoEntryNo);
+ ItemJournalLine.Insert();
+ end;
+
+ procedure CreateItemReclassificationJournalLine(var ItemJournalLine: Record "Item Journal Line"; ItemJournalBatch: Record "Item Journal Batch"; Item: Record Item; VariantCode: Code[10]; LocationCode: Code[10]; NewLocationCode: Code[10]; BinCode: Code[20]; NewBinCode: Code[20]; PostingDate: Date; Quantity: Decimal)
+ begin
+ MakeItemJournalLine(ItemJournalLine, ItemJournalBatch, Item, PostingDate, ItemJournalLine."Entry Type"::Transfer, Quantity);
+ ItemJournalLine."Location Code" := LocationCode;
+ ItemJournalLine."Variant Code" := VariantCode;
+ ItemJournalLine."New Location Code" := NewLocationCode;
+ ItemJournalLine."Bin Code" := BinCode;
+ ItemJournalLine."New Bin Code" := NewBinCode;
+ ItemJournalLine.Insert();
+ end;
+
+ procedure CreateRevaluationJournalLine(var ItemJournalBatch: Record "Item Journal Batch"; var Item: Record Item; NewPostingDate: Date; NewCalculatePer: Enum "Inventory Value Calc. Per"; NewByLocation: Boolean; NewByVariant: Boolean; NewUpdStdCost: Boolean; NewCalcBase: Enum "Inventory Value Calc. Base")
+ var
+ ItemJournalLine: Record "Item Journal Line";
+ NewDocNo: Code[20];
+ begin
+ NewDocNo := LibraryUtility.GenerateRandomCode(ItemJournalLine.FieldNo("Document No."), DATABASE::"Item Journal Line");
+ RevaluationJournalCalcInventory(
+ ItemJournalBatch, Item, NewPostingDate, NewDocNo, NewCalculatePer, NewByLocation, NewByVariant, NewUpdStdCost, NewCalcBase);
+ end;
+
+ procedure RevaluationJournalCalcInventory(var ItemJournalBatch: Record "Item Journal Batch"; var Item: Record Item; NewPostingDate: Date; NewDocNo: Code[20]; NewCalculatePer: Enum "Inventory Value Calc. Per"; NewByLocation: Boolean; NewByVariant: Boolean; NewUpdStdCost: Boolean; NewCalcBase: Enum "Inventory Value Calc. Base")
+ var
+ TmpItem: Record Item;
+ ItemJournalLine: Record "Item Journal Line";
+ CalculateInventoryValue: Report "Calculate Inventory Value";
+ ItemJnlMgt: Codeunit ItemJnlManagement;
+ JnlSelected: Boolean;
+ begin
+ Commit();
+ CalculateInventoryValue.SetParameters(
+ NewPostingDate, NewDocNo, true, NewCalculatePer, NewByLocation, NewByVariant,
+ NewUpdStdCost, NewCalcBase, true);
+
+ CreateItemJournalBatchByType(ItemJournalBatch, ItemJournalBatch."Template Type"::Revaluation);
+
+ ItemJournalLine.Init();
+ ItemJnlMgt.TemplateSelection(PAGE::"Revaluation Journal", 3, false, ItemJournalLine, JnlSelected); // 3 = FormTemplate::Revaluation
+ ItemJnlMgt.OpenJnl(ItemJournalBatch.Name, ItemJournalLine);
+
+ ItemJournalLine.Validate("Journal Template Name", ItemJournalBatch."Journal Template Name");
+ ItemJournalLine.Validate("Journal Batch Name", ItemJournalBatch.Name);
+ ItemJournalLine.SetUpNewLine(ItemJournalLine);
+ CalculateInventoryValue.SetItemJnlLine(ItemJournalLine);
+
+ if Item.HasFilter then
+ TmpItem.CopyFilters(Item)
+ else begin
+ Item.Get(Item."No.");
+ TmpItem.SetRange("No.", Item."No.");
+ end;
+ CalculateInventoryValue.SetTableView(TmpItem);
+ CalculateInventoryValue.UseRequestPage(false);
+ CalculateInventoryValue.RunModal();
+ end;
+
+ procedure MakeItemJournalLine(var ItemJournalLine: Record "Item Journal Line"; ItemJournalBatch: Record "Item Journal Batch"; Item: Record Item; PostingDate: Date; EntryType: Enum "Item Ledger Entry Type"; Quantity: Decimal)
+ var
+ RecRef: RecordRef;
+ begin
+ Clear(ItemJournalLine);
+ ItemJournalLine."Journal Template Name" := ItemJournalBatch."Journal Template Name";
+ ItemJournalLine."Journal Batch Name" := ItemJournalBatch.Name;
+ ItemJournalLine."Posting Date" := PostingDate;
+ ItemJournalLine."Entry Type" := EntryType;
+ ItemJournalBatch.CalcFields("Template Type");
+ if ItemJournalBatch."Template Type" = ItemJournalBatch."Template Type"::Revaluation then
+ ItemJournalLine."Value Entry Type" := ItemJournalLine."Value Entry Type"::Revaluation;
+ if Item.IsNonInventoriableType() then
+ ItemJournalLine."Order Type" := ItemJournalLine."Order Type"::Production;
+ ItemJournalLine.Validate("Item No.", Item."No.");
+ ItemJournalLine.Validate(Quantity, Quantity);
+ ItemJournalLine."Document No." :=
+ LibraryUtility.GenerateRandomCode(ItemJournalLine.FieldNo("Document No."), DATABASE::"Item Journal Line");
+ RecRef.GetTable(ItemJournalLine);
+ ItemJournalLine."Line No." := LibraryUtility.GetNewLineNo(RecRef, ItemJournalLine.FieldNo("Line No."));
+ end;
+
+#if not CLEAN26
+ [Obsolete('Moved to codeunit Library Manufacturing', '26.0')]
+ procedure OutputJnlExplRoute(var ItemJournalLine: Record "Item Journal Line")
+ var
+ LibraryManufacturing: Codeunit "Library - Manufacturing";
+ begin
+ LibraryManufacturing.OutputJnlExplodeRoute(ItemJournalLine);
+ end;
+#endif
+
+ procedure PostDirectTransferOrder(var TransferHeader: Record "Transfer Header")
+ var
+ TransferOrderPostTransfer: Codeunit "TransferOrder-Post Transfer";
+ begin
+ InventorySetup.Get();
+ case InventorySetup."Direct Transfer Posting" of
+ InventorySetup."Direct Transfer Posting"::"Receipt and Shipment":
+ PostTransferHeader(TransferHeader, true, true);
+ InventorySetup."Direct Transfer Posting"::"Direct Transfer":
+ begin
+ TransferOrderPostTransfer.SetHideValidationDialog(true);
+ TransferOrderPostTransfer.Run(TransferHeader);
+ end;
+ end;
+ end;
+
+ procedure PostItemJournalBatch(ItemJournalBatch: Record "Item Journal Batch")
+ begin
+ PostItemJournalLine(ItemJournalBatch."Journal Template Name", ItemJournalBatch.Name);
+ end;
+
+ procedure PostItemJournalLine(JournalTemplateName: Text[10]; JournalBatchName: Text[10])
+ var
+ ItemJournalLine: Record "Item Journal Line";
+ begin
+ ItemJournalLine.Init();
+ ItemJournalLine.Validate("Journal Template Name", JournalTemplateName);
+ ItemJournalLine.Validate("Journal Batch Name", JournalBatchName);
+ CODEUNIT.Run(CODEUNIT::"Item Jnl.-Post Batch", ItemJournalLine);
+ end;
+
+ procedure PostItemJnlLineWithCheck(ItemJnlLine: Record "Item Journal Line")
+ var
+ ItemJnlPostLine: Codeunit "Item Jnl.-Post Line";
+ begin
+ ItemJnlPostLine.RunWithCheck(ItemJnlLine);
+ end;
+
+ procedure PostItemJournalLine(TemplateType: Enum "Item Journal Template Type"; EntryType: Enum "Item Ledger Entry Type"; Item: Record Item; LocationCode: Code[10]; VariantCode: Code[10]; BinCode: Code[20]; Qty: Decimal; PostingDate: Date; UnitAmount: Decimal)
+ var
+ ItemJournalLine: Record "Item Journal Line";
+ ItemJournalBatch: Record "Item Journal Batch";
+ begin
+ CreateItemJournalBatchByType(ItemJournalBatch, TemplateType);
+ CreateItemJournalLine(ItemJournalLine, ItemJournalBatch, Item, LocationCode, VariantCode, PostingDate, EntryType, Qty, UnitAmount);
+ ItemJournalLine."Bin Code" := BinCode;
+ ItemJournalLine.Modify();
+ PostItemJournalBatch(ItemJournalBatch);
+ end;
+
+ procedure PostNegativeAdjustment(Item: Record Item; LocationCode: Code[10]; VariantCode: Code[10]; BinCode: Code[20]; Qty: Decimal; PostingDate: Date; UnitAmount: Decimal)
+ var
+ ItemJournalTemplate: Record "Item Journal Template";
+ ItemJournalLine: Record "Item Journal Line";
+ begin
+ PostItemJournalLine(
+ ItemJournalTemplate.Type::Item, ItemJournalLine."Entry Type"::"Negative Adjmt.", Item,
+ LocationCode, VariantCode, BinCode, Qty, PostingDate, UnitAmount);
+ end;
+
+ procedure PostPositiveAdjustment(Item: Record Item; LocationCode: Code[10]; VariantCode: Code[10]; BinCode: Code[20]; Qty: Decimal; PostingDate: Date; UnitAmount: Decimal)
+ var
+ ItemJournalTemplate: Record "Item Journal Template";
+ ItemJournalLine: Record "Item Journal Line";
+ begin
+ PostItemJournalLine(
+ ItemJournalTemplate.Type::Item, ItemJournalLine."Entry Type"::"Positive Adjmt.", Item,
+ LocationCode, VariantCode, BinCode, Qty, PostingDate, UnitAmount);
+ end;
+
+ procedure PostReclassificationJournalLine(Item: Record Item; StartDate: Date; FromLocationCode: Code[10]; ToLocationCode: Code[10]; VariantCode: Code[10]; BinCode: Code[20]; NewBinCode: Code[20]; Quantity: Decimal)
+ var
+ ItemJnlBatch: Record "Item Journal Batch";
+ ItemJnlLine: Record "Item Journal Line";
+ begin
+ CreateItemJournalBatchByType(ItemJnlBatch, ItemJnlBatch."Template Type"::Transfer);
+ CreateItemReclassificationJournalLine(ItemJnlLine, ItemJnlBatch, Item, VariantCode, FromLocationCode, ToLocationCode,
+ BinCode, NewBinCode, StartDate, Quantity);
+ PostItemJournalBatch(ItemJnlBatch);
+ end;
+
+ procedure PostTransferHeader(var TransferHeader: Record "Transfer Header"; Ship: Boolean; Receive: Boolean)
+ var
+ TransferOrderPostShipment: Codeunit "TransferOrder-Post Shipment";
+ TransferOrderPostReceipt: Codeunit "TransferOrder-Post Receipt";
+ begin
+ Clear(TransferOrderPostShipment);
+ if Ship then begin
+ TransferOrderPostShipment.SetHideValidationDialog(true);
+ TransferOrderPostShipment.Run(TransferHeader);
+ end;
+ if Receive then begin
+ TransferOrderPostReceipt.SetHideValidationDialog(true);
+ TransferOrderPostReceipt.Run(TransferHeader);
+ end;
+ end;
+
+ procedure UndoTransferShipments(TransferOrderNo: Code[20])
+ var
+ TransferShipmentLine: Record "Transfer Shipment Line";
+ begin
+ TransferShipmentLine.SetFilter("Transfer Order No.", TransferOrderNo);
+ TransferShipmentLine.SetRange("Correction Line", false);
+ UndoTransferShipmentLinesInFilter(TransferShipmentLine);
+ end;
+
+ procedure UndoTransferShipmentLinesInFilter(var TransferShipmentLine: Record "Transfer Shipment Line")
+ begin
+ CODEUNIT.Run(CODEUNIT::"Undo Transfer Shipment", TransferShipmentLine);
+ end;
+
+ procedure ReleaseTransferOrder(var TransferHeader: Record "Transfer Header")
+ var
+ ReleaseTransferDocument: Codeunit "Release Transfer Document";
+ begin
+ Clear(ReleaseTransferDocument);
+ ReleaseTransferDocument.Run(TransferHeader);
+ end;
+
+ procedure ReopenTransferOrder(var TransferHeader: Record "Transfer Header")
+ var
+ ReleaseTransferDocument: Codeunit "Release Transfer Document";
+ begin
+ ReleaseTransferDocument.Reopen(TransferHeader);
+ end;
+
+ procedure SaveAsStandardJournal(var GenJournalBatch: Record "Gen. Journal Batch"; "Code": Code[10]; SaveAmount: Boolean)
+ var
+ GenJournalLine: Record "Gen. Journal Line";
+ StandardGeneralJournal: Record "Standard General Journal";
+ SaveAsStandardGenJournal: Report "Save as Standard Gen. Journal";
+ begin
+ GenJournalLine.SetRange("Journal Template Name", GenJournalBatch."Journal Template Name");
+ GenJournalLine.SetRange("Journal Batch Name", GenJournalBatch.Name);
+ SaveAsStandardGenJournal.Initialise(GenJournalLine, GenJournalBatch);
+ SaveAsStandardGenJournal.InitializeRequest(Code, '', SaveAmount);
+ SaveAsStandardGenJournal.UseRequestPage(false);
+ SaveAsStandardGenJournal.RunModal();
+ if not SaveAsStandardGenJournal.GetStdGeneralJournal(StandardGeneralJournal) then;
+ end;
+
+ procedure SelectItemJournalTemplateName(var ItemJournalTemplate: Record "Item Journal Template"; ItemJournalTemplateType: Enum "Item Journal Template Type")
+ begin
+ // Find Item Journal Template for the given Template Type.
+ ItemJournalTemplate.SetRange(Type, ItemJournalTemplateType);
+ ItemJournalTemplate.SetRange(Recurring, false);
+ if not ItemJournalTemplate.FindFirst() then
+ CreateItemJournalTemplateByType(ItemJournalTemplate, ItemJournalTemplateType);
+ end;
+
+ procedure SelectItemJournalBatchName(var ItemJournalBatch: Record "Item Journal Batch"; ItemJournalBatchTemplateType: Enum "Item Journal Template Type"; ItemJournalTemplateName: Code[10])
+ begin
+ // Find Name for Batch Name.
+ ItemJournalBatch.SetRange("Template Type", ItemJournalBatchTemplateType);
+ ItemJournalBatch.SetRange("Journal Template Name", ItemJournalTemplateName);
+
+ // If Item Journal Batch not found then create it.
+ if not ItemJournalBatch.FindFirst() then
+ CreateItemJournalBatch(ItemJournalBatch, ItemJournalTemplateName);
+ end;
+
+ procedure SetAutomaticCostAdjmtAlways()
+ begin
+ InventorySetup.Get();
+ InventorySetup."Automatic Cost Adjustment" := InventorySetup."Automatic Cost Adjustment"::Always;
+ InventorySetup.Modify();
+ end;
+
+ procedure SetAutomaticCostAdjmtNever()
+ begin
+ InventorySetup.Get();
+ InventorySetup."Automatic Cost Adjustment" := InventorySetup."Automatic Cost Adjustment"::Never;
+ InventorySetup.Modify();
+ end;
+
+ procedure SetAutomaticCostPosting(AutomaticCostPosting: Boolean)
+ begin
+ InventorySetup.Get();
+ InventorySetup."Automatic Cost Posting" := AutomaticCostPosting;
+ InventorySetup.Modify();
+ end;
+
+ procedure SetAverageCostSetup(AverageCostCalcType: Enum "Average Cost Calculation Type"; AverageCostPeriod: Enum "Average Cost Period Type")
+ begin
+ InventorySetup.Get();
+ InventorySetup."Average Cost Calc. Type" := AverageCostCalcType;
+ InventorySetup."Average Cost Period" := AverageCostPeriod;
+ InventorySetup.Modify();
+ end;
+
+ procedure SetAverageCostSetupInAccPeriods(AverageCostCalcType: Enum "Average Cost Calculation Type"; AverageCostPeriod: Enum "Average Cost Period Type")
+ var
+ AccountingPeriod: Record "Accounting Period";
+ begin
+ AccountingPeriod.SetRange("New Fiscal Year", true);
+ AccountingPeriod.ModifyAll("Average Cost Calc. Type", AverageCostCalcType);
+ AccountingPeriod.ModifyAll("Average Cost Period", AverageCostPeriod);
+ end;
+
+ procedure SetExpectedCostPosting(ExpectedCostPosting: Boolean)
+ begin
+ InventorySetup.Get();
+ InventorySetup."Expected Cost Posting to G/L" := ExpectedCostPosting;
+ InventorySetup.Modify();
+ end;
+
+ procedure SetLocationMandatory(LocationMandatory: Boolean)
+ begin
+ InventorySetup.Get();
+ InventorySetup."Location Mandatory" := LocationMandatory;
+ InventorySetup.Modify();
+ end;
+
+ procedure SetPreventNegativeInventory(PreventNegativeInventory: Boolean)
+ begin
+ InventorySetup.Get();
+ InventorySetup."Prevent Negative Inventory" := PreventNegativeInventory;
+ InventorySetup.Modify();
+ end;
+
+ procedure UpdateAverageCostSettings(AverageCostCalcType: Enum "Average Cost Calculation Type"; AverageCostPeriod: Enum "Average Cost Period Type")
+ begin
+ InventorySetup.Get();
+ InventorySetup."Average Cost Calc. Type" := AverageCostCalcType;
+ InventorySetup."Average Cost Period" := AverageCostPeriod;
+ CODEUNIT.Run(CODEUNIT::"Change Average Cost Setting", InventorySetup);
+ end;
+
+ procedure UpdateGenProdPostingSetup()
+ var
+ GeneralPostingSetup: Record "General Posting Setup";
+ begin
+ if GeneralPostingSetup.FindSet() then
+ repeat
+ if GeneralPostingSetup."Sales Account" = '' then
+ GeneralPostingSetup.Validate("Sales Account", LibraryERM.CreateGLAccountNo());
+ if GeneralPostingSetup."Purch. Account" = '' then
+ GeneralPostingSetup.Validate("Purch. Account", GeneralPostingSetup."Sales Account");
+ if GeneralPostingSetup."COGS Account" = '' then
+ GeneralPostingSetup.Validate("COGS Account", GeneralPostingSetup."Sales Account");
+ if GeneralPostingSetup."Inventory Adjmt. Account" = '' then
+ GeneralPostingSetup.Validate("Inventory Adjmt. Account", GeneralPostingSetup."Sales Account");
+ if GeneralPostingSetup."COGS Account (Interim)" = '' then
+ GeneralPostingSetup.Validate("COGS Account (Interim)", GeneralPostingSetup."Sales Account");
+ if GeneralPostingSetup."Direct Cost Applied Account" = '' then
+ GeneralPostingSetup.Validate("Direct Cost Applied Account", GeneralPostingSetup."Sales Account");
+ if GeneralPostingSetup."Purchase Variance Account" = '' then
+ GeneralPostingSetup.Validate("Purchase Variance Account", GeneralPostingSetup."Sales Account");
+ if GeneralPostingSetup."Purch. Credit Memo Account" = '' then
+ GeneralPostingSetup.Validate("Purch. Credit Memo Account", GeneralPostingSetup."Sales Account");
+ if GeneralPostingSetup."Sales Credit Memo Account" = '' then
+ GeneralPostingSetup.Validate("Sales Credit Memo Account", GeneralPostingSetup."Sales Account");
+ if GeneralPostingSetup."Sales Prepayments Account" = '' then
+ GeneralPostingSetup.Validate("Sales Prepayments Account", LibraryERM.CreateGLAccountWithSalesSetup());
+ if GeneralPostingSetup."Purch. Prepayments Account" = '' then
+ GeneralPostingSetup.Validate("Purch. Prepayments Account", LibraryERM.CreateGLAccountWithPurchSetup());
+ GeneralPostingSetup.Modify(true);
+ until GeneralPostingSetup.Next() = 0;
+ end;
+
+ procedure UpdateInventorySetup(var InventorySetup2: Record "Inventory Setup"; AutomaticCostPosting: Boolean; ExpectedCostPostingtoGL: Boolean; AutomaticCostAdjustment: Enum "Automatic Cost Adjustment Type"; AverageCostCalcType: Enum "Average Cost Calculation Type"; AverageCostPeriod: Enum "Average Cost Period Type")
+ begin
+ InventorySetup2.Get();
+ InventorySetup2.Validate("Automatic Cost Posting", AutomaticCostPosting);
+ InventorySetup2.Validate("Expected Cost Posting to G/L", ExpectedCostPostingtoGL);
+ InventorySetup2.Validate("Automatic Cost Adjustment", AutomaticCostAdjustment);
+ InventorySetup2.Validate("Average Cost Calc. Type", AverageCostCalcType);
+ InventorySetup2.Validate("Average Cost Period", AverageCostPeriod);
+ InventorySetup2.Modify(true);
+ end;
+
+ procedure UpdateInventoryPostingSetup(Location: Record Location)
+ var
+ InventoryPostingGroup: Record "Inventory Posting Group";
+ begin
+ if InventoryPostingGroup.FindSet() then
+ repeat
+ UpdateInventoryPostingSetup(Location, InventoryPostingGroup.Code);
+ until InventoryPostingGroup.Next() = 0;
+ end;
+
+ procedure UpdateInventoryPostingSetup(Location: Record Location; InventoryPostingGroupCode: Code[20])
+ var
+ InventoryPostingSetup: Record "Inventory Posting Setup";
+ begin
+ InventoryPostingSetup.SetRange("Location Code", Location.Code);
+ InventoryPostingSetup.SetRange("Invt. Posting Group Code", InventoryPostingGroupCode);
+ if not InventoryPostingSetup.FindFirst() then
+ CreateInventoryPostingSetup(InventoryPostingSetup, Location.Code, InventoryPostingGroupCode);
+ InventoryPostingSetup.Validate("Inventory Account", LibraryERM.CreateGLAccountNo());
+ InventoryPostingSetup.Validate("Inventory Account (Interim)", LibraryERM.CreateGLAccountNo());
+ InventoryPostingSetup.Validate("WIP Account", LibraryERM.CreateGLAccountNo());
+ InventoryPostingSetup.Validate("Material Variance Account", LibraryERM.CreateGLAccountNo());
+ InventoryPostingSetup.Validate("Capacity Variance Account", LibraryERM.CreateGLAccountNo());
+ OnBeforeModifyInventoryPostingSetup(InventoryPostingSetup);
+ InventoryPostingSetup.Modify(true);
+ end;
+
+ procedure UpdateSalesLine(var SalesLine: Record "Sales Line"; FieldNo: Integer; Value: Variant)
+ var
+ RecRef: RecordRef;
+ FieldRef: FieldRef;
+ begin
+ // Update Sales Line base on Field and its corresponding value.
+ RecRef.GetTable(SalesLine);
+ FieldRef := RecRef.Field(FieldNo);
+ FieldRef.Validate(Value);
+ RecRef.SetTable(SalesLine);
+ SalesLine.Modify(true);
+ end;
+
+ procedure ItemJournalSetup(var ItemJournalTemplate: Record "Item Journal Template"; var ItemJournalBatch: Record "Item Journal Batch")
+ begin
+ Clear(ItemJournalTemplate);
+ ItemJournalTemplate.Init();
+ SelectItemJournalTemplateName(ItemJournalTemplate, ItemJournalTemplate.Type::Item);
+ ItemJournalTemplate.Validate("No. Series", LibraryUtility.GetGlobalNoSeriesCode());
+ ItemJournalTemplate.Modify(true);
+
+ Clear(ItemJournalBatch);
+ ItemJournalBatch.Init();
+ SelectItemJournalBatchName(ItemJournalBatch, ItemJournalTemplate.Type, ItemJournalTemplate.Name);
+ ItemJournalBatch.Validate("No. Series", ''); // Value required to avoid the Document No mismatch.
+ ItemJournalBatch.Modify(true);
+ end;
+
+ procedure OutputJournalSetup(var ItemJournalTemplate: Record "Item Journal Template"; var ItemJournalBatch: Record "Item Journal Batch")
+ begin
+ SelectItemJournalTemplateName(ItemJournalTemplate, ItemJournalTemplate.Type::Output);
+ SelectItemJournalBatchName(ItemJournalBatch, ItemJournalTemplate.Type, ItemJournalTemplate.Name);
+ end;
+
+ procedure ConsumptionJournalSetup(var ItemJournalTemplate: Record "Item Journal Template"; var ItemJournalBatch: Record "Item Journal Batch")
+ begin
+ SelectItemJournalTemplateName(ItemJournalTemplate, ItemJournalTemplate.Type::Consumption);
+ SelectItemJournalBatchName(ItemJournalBatch, ItemJournalTemplate.Type, ItemJournalTemplate.Name);
+ end;
+
+ procedure VerifyReservationEntryWithLotExists(SourceType: Option; SourceSubtype: Option; SourceID: Code[20]; SourceRefNo: Integer; ItemNo: Code[20]; ExpectedQty: Decimal)
+ var
+ ReservationEntry: Record "Reservation Entry";
+ begin
+ ReservationEntry.SetRange("Source Type", SourceType);
+ ReservationEntry.SetRange("Source Subtype", SourceSubtype);
+ ReservationEntry.SetRange("Source ID", SourceID);
+ ReservationEntry.SetRange("Source Ref. No.", SourceRefNo);
+ ReservationEntry.SetRange("Item No.", ItemNo);
+ ReservationEntry.FindFirst();
+ ReservationEntry.TestField("Quantity (Base)", ExpectedQty);
+ ReservationEntry.TestField("Lot No.");
+ end;
+
+ procedure UpdateMaterialNonInvVarianceAccountInInventoryPostingSetup(var InventoryPostingSetup: Record "Inventory Posting Setup")
+ begin
+ InventoryPostingSetup.Validate("Mat. Non-Inv. Variance Acc.", LibraryERM.CreateGLAccountNo());
+ InventoryPostingSetup.Modify();
+ end;
+
+ procedure CreateItem(var Item: Record Item; CostingMethod: Enum "Costing Method"; UnitCost: Decimal; OverheadRate: Decimal; IndirectCostPercent: Decimal; ItemTrackingCode: Code[10])
+ begin
+ CreateItem(Item);
+ Item."Costing Method" := CostingMethod;
+ if Item."Costing Method" = Item."Costing Method"::Standard then
+ Item."Standard Cost" := UnitCost;
+ Item."Unit Cost" := UnitCost;
+ Item."Overhead Rate" := OverheadRate;
+ Item."Indirect Cost %" := IndirectCostPercent;
+ Item."Item Tracking Code" := ItemTrackingCode;
+ Item.Description := Item."No.";
+ Item.Modify();
+ end;
+
+ procedure CreateItemSimple(var Item: Record Item; CostingMethod: Enum "Costing Method"; UnitCost: Decimal)
+ begin
+ CreateItem(Item, CostingMethod, UnitCost, 0, 0, '');
+ end;
+
+ procedure CreateItemWithExtendedText(var Item: Record Item; ExtText: Text; CostingMethod: Enum "Costing Method"; UnitCost: Decimal)
+ var
+ ExtendedTextHeader: Record "Extended Text Header";
+ ExtendedTextLine: Record "Extended Text Line";
+ begin
+ // Create Item.
+ CreateItem(Item, CostingMethod, UnitCost, 0, 0, '');
+ Item.Validate("Automatic Ext. Texts", true);
+ Item.Modify();
+
+ // Create Extended Text Header and Line.
+ CreateExtendedTextHeaderItem(ExtendedTextHeader, Item."No.");
+ ExtendedTextHeader.Validate("All Language Codes", true);
+ ExtendedTextHeader.Modify();
+ CreateExtendedTextLineItem(ExtendedTextLine, ExtendedTextHeader);
+ ExtendedTextLine.Validate(Text, CopyStr(ExtText, 1, MaxStrLen(ExtendedTextLine.Text)));
+ ExtendedTextLine.Modify();
+ end;
+
+ [IntegrationEvent(false, false)]
+ local procedure OnAfterCreateItem(var Item: Record Item)
+ begin
+ end;
+
+ [IntegrationEvent(false, false)]
+ local procedure OnAfterCreateItemJnlLineWithNoItem(var ItemJournalLine: Record "Item Journal Line"; ItemJournalBatch: Record "Item Journal Batch"; JournalTemplateName: Code[10]; JournalBatchName: Code[10]; EntryType: Option)
+ begin
+ end;
+
+ [IntegrationEvent(false, false)]
+ local procedure OnAfterCreateItemManufacturing(var Item: Record Item)
+ begin
+ end;
+
+ [IntegrationEvent(false, false)]
+ local procedure OnBeforeCreateItemVariant(var ItemVariant: Record "Item Variant"; ItemNo: Code[20]; var Handled: Boolean)
+ begin
+ end;
+
+ [IntegrationEvent(false, false)]
+ local procedure OnAfterCreateItemVariant(var ItemVariant: Record "Item Variant"; ItemNo: Code[20])
+ begin
+ end;
+
+ [IntegrationEvent(false, false)]
+ local procedure OnBeforeCreateTransferHeader(var TransferHeader: Record "Transfer Header"; FromLocation: Text[10]; ToLocation: Text[10]; InTransitCode: Text[10]; var Handled: Boolean)
+ begin
+ end;
+
+ [IntegrationEvent(false, false)]
+ local procedure OnAfterCreateTransferHeader(var TransferHeader: Record "Transfer Header"; FromLocation: Text[10]; ToLocation: Text[10]; InTransitCode: Text[10])
+ begin
+ end;
+
+ [IntegrationEvent(false, false)]
+ local procedure OnBeforeCreateVariant(var ItemVariant: Record "Item Variant"; Item: Record Item; var Handled: Boolean)
+ begin
+ end;
+
+ [IntegrationEvent(false, false)]
+ local procedure OnAfterCreateVariant(var ItemVariant: Record "Item Variant"; Item: Record Item)
+ begin
+ end;
+
+ [IntegrationEvent(false, false)]
+ local procedure OnBeforeModifyInventoryPostingSetup(var InventoryPostingSetup: Record "Inventory Posting Setup")
+ begin
+ end;
+}
+
diff --git a/Apps/W1/ApplicationTestLibrary/LibraryItemReference.Codeunit.al b/Apps/W1/ApplicationTestLibrary/LibraryItemReference.Codeunit.al
new file mode 100644
index 0000000000..98b5e2d232
--- /dev/null
+++ b/Apps/W1/ApplicationTestLibrary/LibraryItemReference.Codeunit.al
@@ -0,0 +1,64 @@
+///
+/// Provides utility functions for creating and managing item references (cross-references) in test scenarios.
+///
+codeunit 132225 "Library - Item Reference"
+{
+
+ trigger OnRun()
+ begin
+ end;
+
+ var
+ LibraryUtility: Codeunit "Library - Utility";
+
+ procedure CreateItemReference(var ItemReference: Record "Item Reference"; ItemNo: Code[20]; ReferenceType: Enum "Item Reference Type"; ReferenceTypeNo: Code[20])
+ begin
+ CreateItemReferenceWithNo(
+ ItemReference, LibraryUtility.GenerateRandomCode(ItemReference.FieldNo("Reference No."), DATABASE::"Item Reference"),
+ ItemNo, ReferenceType, ReferenceTypeNo);
+ end;
+
+ procedure CreateItemReference(var ItemReference: Record "Item Reference"; ItemNo: Code[20]; VariantCode: Code[10]; UnitOfMeasureCode: Code[10]; ReferenceType: Enum "Item Reference Type"; ReferenceTypeNo: Code[20]; ReferenceNo: Code[50])
+ begin
+ ItemReference.Init();
+ ItemReference.Validate("Item No.", ItemNo);
+ ItemReference.Validate("Variant Code", VariantCode);
+ ItemReference.Validate("Unit of Measure", UnitOfMeasureCode);
+ ItemReference.Validate("Reference Type", ReferenceType);
+ ItemReference.Validate("Reference Type No.", ReferenceTypeNo);
+ ItemReference.Validate("Reference No.", ReferenceNo);
+ ItemReference.Insert(true);
+ end;
+
+ procedure CreateItemReferenceWithNo(var ItemReference: Record "Item Reference"; ItemRefNo: Code[50]; ItemNo: Code[20]; ItemRefType: Enum "Item Reference Type"; ItemRefTypeNo: Code[20])
+ begin
+ ItemReference.Init();
+ ItemReference.Validate("Item No.", ItemNo);
+ ItemReference.Validate("Reference Type", ItemRefType);
+ ItemReference.Validate("Reference Type No.", ItemRefTypeNo);
+ ItemReference.Validate("Reference No.", ItemRefNo);
+ ItemReference.Insert(true);
+ end;
+
+ procedure CreateItemReferenceWithNoAndDates(var ItemReference: Record "Item Reference"; ItemRefNo: Code[50]; ItemNo: Code[20]; ItemRefType: Enum "Item Reference Type"; ItemRefTypeNo: Code[20]; StartingDate: Date; EndingDate: Date)
+ begin
+ CreateItemReferenceWithNo(ItemReference, ItemRefNo, ItemNo, ItemRefType, ItemRefTypeNo);
+ ItemReference.Validate("Starting Date", StartingDate);
+ ItemReference.Validate("Ending Date", EndingDate);
+ ItemReference.Modify(true);
+ end;
+
+#if not CLEAN26
+ [Obsolete('Functionality is enabled permanently.', '23.0')]
+ procedure EnableFeature(Bind: Boolean)
+ begin
+ end;
+#endif
+
+#if not CLEAN26
+ [Obsolete('Functionality is enabled permanently.', '23.0')]
+ procedure DisableFeature()
+ begin
+ end;
+#endif
+}
diff --git a/Apps/W1/ApplicationTestLibrary/LibraryItemTracking.Codeunit.al b/Apps/W1/ApplicationTestLibrary/LibraryItemTracking.Codeunit.al
new file mode 100644
index 0000000000..ebef4de2d1
--- /dev/null
+++ b/Apps/W1/ApplicationTestLibrary/LibraryItemTracking.Codeunit.al
@@ -0,0 +1,1155 @@
+///
+/// Provides utility functions for creating and managing item tracking (serial numbers, lot numbers) in test scenarios.
+///
+codeunit 130502 "Library - Item Tracking"
+{
+
+ Permissions = TableData "Whse. Item Tracking Line" = rimd;
+
+ trigger OnRun()
+ begin
+ end;
+
+ var
+ Assert: Codeunit Assert;
+ LibraryInventory: Codeunit "Library - Inventory";
+ LibraryUtility: Codeunit "Library - Utility";
+ Text001: Label 'Not implemented. Source Type = %1.';
+ Text002: Label 'Qty Base for Serial No. %1 is %2.';
+ Text031: Label 'You cannot define item tracking on this line because it is linked to production order %1.';
+ Text048: Label 'You cannot use item tracking on a %1 created from a %2.';
+ LedgerEntryFoundErr: Label '%1 is not found, filters: %2.';
+ LedgerEntryQtyErr: Label 'Incorrect quantity for %1, filters: %2.';
+
+ procedure AddSerialNoTrackingInfo(var Item: Record Item)
+ var
+ ItemTrackingCode: Record "Item Tracking Code";
+ begin
+ CreateItemTrackingCode(ItemTrackingCode, true, false);
+ Item.Validate("Item Tracking Code", ItemTrackingCode.Code);
+ Item.Validate("Serial Nos.", LibraryUtility.GetGlobalNoSeriesCode());
+ Item.Modify(true);
+ end;
+
+ procedure AddLotNoTrackingInfo(var Item: Record Item)
+ var
+ ItemTrackingCode: Record "Item Tracking Code";
+ begin
+ CreateItemTrackingCode(ItemTrackingCode, false, true);
+ Item.Validate("Item Tracking Code", ItemTrackingCode.Code);
+ Item.Validate("Lot Nos.", LibraryUtility.GetGlobalNoSeriesCode());
+ Item.Modify(true);
+ end;
+
+ procedure CheckLastItemLedgerEntry(var ItemLedgerEntry: Record "Item Ledger Entry"; ItemNo: Code[20]; LocationCode: Code[10]; SerialNo: Code[50]; LotNo: Code[50]; PackageNo: Code[50]; Qty: Decimal): Boolean
+ var
+ ItemTrackingSetup: Record "Item Tracking Setup";
+ begin
+ ItemTrackingSetup."Serial No." := SerialNo;
+ ItemTrackingSetup."Lot No." := LotNo;
+ ItemTrackingSetup."Package No." := PackageNo;
+ CheckLastItemLedgerEntry(ItemLedgerEntry, ItemNo, LocationCode, ItemTrackingSetup, Qty);
+ end;
+
+ procedure CheckLastItemLedgerEntry(var ItemLedgerEntry: Record "Item Ledger Entry"; ItemNo: Code[20]; LocationCode: Code[10]; ItemTrackingSetup: Record "Item Tracking Setup"; Qty: Decimal): Boolean
+ begin
+ ItemLedgerEntry.SetCurrentKey("Item No.", Open, "Variant Code", "Location Code", "Item Tracking", "Lot No.", "Serial No.", "Package No.");
+ ItemLedgerEntry.SetRange("Item No.", ItemNo);
+ ItemLedgerEntry.SetRange("Location Code", LocationCode);
+ ItemLedgerEntry.SetTrackingFilterFromItemTrackingSetup(ItemTrackingSetup);
+ Assert.IsTrue(
+ ItemLedgerEntry.FindLast(),
+ StrSubstNo(LedgerEntryFoundErr, ItemLedgerEntry.TableCaption(), ItemLedgerEntry.GetFilters));
+ Assert.AreEqual(
+ Qty, ItemLedgerEntry.Quantity, StrSubstNo(LedgerEntryQtyErr, ItemLedgerEntry.GetFilters()));
+ ItemLedgerEntry.Reset();
+ end;
+
+ procedure CheckReservationEntry(SourceType: Integer; SourceSubtype: Integer; SourceID: Code[20]; SourceRefNo: Integer; ItemNo: Code[20]; LocationCode: Code[10]; ItemTrackingSetup: Record "Item Tracking Setup"; Qty: Decimal; ResStatus: Enum "Reservation Status"): Boolean
+ var
+ ReservationEntry: Record "Reservation Entry";
+ begin
+ ReservationEntry.SetCurrentKey("Item No.", "Source Type", "Source Subtype");
+ ReservationEntry.SetSourceFilter(SourceType, SourceSubtype, SourceID, SourceRefNo, false);
+ ReservationEntry.SetRange("Reservation Status", ResStatus);
+
+ ReservationEntry.SetRange("Item No.", ItemNo);
+ ReservationEntry.SetRange("Location Code", LocationCode);
+ ReservationEntry.SetTrackingFilterFromItemTrackingSetup(ItemTrackingSetup);
+ Assert.IsTrue(
+ ReservationEntry.FindLast(),
+ StrSubstNo(LedgerEntryFoundErr, ReservationEntry.TableCaption(), ReservationEntry.GetFilters()));
+ Assert.AreEqual(
+ Qty, ReservationEntry.Quantity, StrSubstNo(LedgerEntryQtyErr, ReservationEntry.GetFilters()));
+ end;
+
+ procedure CheckSalesReservationEntry(SalesLine: Record "Sales Line"; SerialNo: Code[50]; LotNo: Code[50]; PackageNo: Code[50]; Qty: Decimal; ResStatus: Enum "Reservation Status"): Boolean
+ var
+ ItemTrackingSetup: Record "Item Tracking Setup";
+ begin
+ ItemTrackingSetup."Serial No." := SerialNo;
+ ItemTrackingSetup."Lot No." := LotNo;
+ ItemTrackingSetup."Package No." := PackageNo;
+ CheckReservationEntry(
+ DATABASE::"Sales Line", SalesLine."Document Type".AsInteger(), SalesLine."Document No.", SalesLine."Line No.",
+ SalesLine."No.", SalesLine."Location Code", ItemTrackingSetup, Qty, ResStatus);
+ end;
+
+ procedure CheckPurchReservationEntry(PurchLine: Record "Purchase Line"; SerialNo: Code[50]; LotNo: Code[50]; PackageNo: Code[50]; Qty: Decimal; ResStatus: Enum "Reservation Status"): Boolean
+ var
+ ItemTrackingSetup: Record "Item Tracking Setup";
+ begin
+ ItemTrackingSetup."Serial No." := SerialNo;
+ ItemTrackingSetup."Lot No." := LotNo;
+ ItemTrackingSetup."Package No." := PackageNo;
+ CheckReservationEntry(
+ DATABASE::"Purchase Line", PurchLine."Document Type".AsInteger(), PurchLine."Document No.", PurchLine."Line No.",
+ PurchLine."No.", PurchLine."Location Code", ItemTrackingSetup, Qty, ResStatus);
+ end;
+
+ procedure CheckInvtDocReservationEntry(InvtDocLine: Record "Invt. Document Line"; SerialNo: Code[50]; LotNo: Code[50]; PackageNo: Code[50]; Qty: Decimal; ResStatus: Enum "Reservation Status"): Boolean
+ var
+ ItemTrackingSetup: Record "Item Tracking Setup";
+ begin
+ ItemTrackingSetup."Serial No." := SerialNo;
+ ItemTrackingSetup."Lot No." := LotNo;
+ ItemTrackingSetup."Package No." := PackageNo;
+ CheckReservationEntry(
+ DATABASE::"Invt. Document Line", InvtDocLine."Document Type".AsInteger(), InvtDocLine."Document No.", InvtDocLine."Line No.",
+ InvtDocLine."Item No.", InvtDocLine."Location Code", ItemTrackingSetup, Qty, ResStatus);
+ end;
+
+ procedure CreateAssemblyHeaderItemTracking(var ReservEntry: Record "Reservation Entry"; AssemblyHeader: Record "Assembly Header"; SerialNo: Code[50]; LotNo: Code[50]; QtyBase: Decimal)
+ var
+ ItemTrackingSetup: Record "Item Tracking Setup";
+ begin
+ ItemTrackingSetup."Serial No." := SerialNo;
+ ItemTrackingSetup."Lot No." := LotNo;
+ CreateAssemblyHeaderItemTracking(ReservEntry, AssemblyHeader, ItemTrackingSetup, QtyBase);
+ end;
+
+ procedure CreateAssemblyHeaderItemTracking(var ReservEntry: Record "Reservation Entry"; AssemblyHeader: Record "Assembly Header"; ItemTrackingSetup: Record "Item Tracking Setup"; QtyBase: Decimal)
+ var
+ RecRef: RecordRef;
+ begin
+ RecRef.GetTable(AssemblyHeader);
+ ItemTracking(ReservEntry, RecRef, ItemTrackingSetup, QtyBase);
+ end;
+
+ procedure CreateAssemblyLineItemTracking(var ReservEntry: Record "Reservation Entry"; AssemblyLine: Record "Assembly Line"; SerialNo: Code[50]; LotNo: Code[50]; QtyBase: Decimal)
+ var
+ ItemTrackingSetup: Record "Item Tracking Setup";
+ begin
+ ItemTrackingSetup."Serial No." := SerialNo;
+ ItemTrackingSetup."Lot No." := LotNo;
+ CreateAssemblyLineItemTracking(ReservEntry, AssemblyLine, ItemTrackingSetup, QtyBase);
+ end;
+
+ procedure CreateAssemblyLineItemTracking(var ReservEntry: Record "Reservation Entry"; AssemblyLine: Record "Assembly Line"; ItemTrackingSetup: Record "Item Tracking Setup"; QtyBase: Decimal)
+ var
+ RecRef: RecordRef;
+ begin
+ RecRef.GetTable(AssemblyLine);
+ ItemTracking(ReservEntry, RecRef, ItemTrackingSetup, QtyBase);
+ end;
+
+ procedure CreateItemJournalLineItemTracking(var ReservEntry: Record "Reservation Entry"; ItemJournalLine: Record "Item Journal Line"; SerialNo: Code[50]; LotNo: Code[50]; QtyBase: Decimal)
+ var
+ ItemTrackingSetup: Record "Item Tracking Setup";
+ begin
+ ItemTrackingSetup."Serial No." := SerialNo;
+ ItemTrackingSetup."Lot No." := LotNo;
+ CreateItemJournalLineItemTracking(ReservEntry, ItemJournalLine, ItemTrackingSetup, QtyBase);
+ end;
+
+ procedure CreateItemJournalLineItemTracking(var ReservEntry: Record "Reservation Entry"; ItemJournalLine: Record "Item Journal Line"; SerialNo: Code[50]; LotNo: Code[50]; PackageNo: Code[50]; QtyBase: Decimal)
+ var
+ ItemTrackingSetup: Record "Item Tracking Setup";
+ begin
+ ItemTrackingSetup."Serial No." := SerialNo;
+ ItemTrackingSetup."Lot No." := LotNo;
+ ItemTrackingSetup."Package No." := PackageNo;
+ CreateItemJournalLineItemTracking(ReservEntry, ItemJournalLine, ItemTrackingSetup, QtyBase);
+ end;
+
+ procedure CreateItemJournalLineItemTracking(var ReservEntry: Record "Reservation Entry"; ItemJournalLine: Record "Item Journal Line"; ItemTrackingSetup: Record "Item Tracking Setup"; QtyBase: Decimal)
+ var
+ RecRef: RecordRef;
+ begin
+ if ItemJournalLine."Entry Type" = ItemJournalLine."Entry Type"::Transfer then // cannot create this type from UI
+ Error(Text001, RecRef.Number);
+ RecRef.GetTable(ItemJournalLine);
+ ItemTracking(ReservEntry, RecRef, ItemTrackingSetup, QtyBase);
+ end;
+
+ procedure CreateItemTrackingLines(var ItemJournalLine: Record "Item Journal Line"; var ItemTrackingLines: Page Microsoft.Inventory.Tracking."Item Tracking Lines")
+ var
+ TrackingSpecification: Record "Tracking Specification";
+ ItemJnlLineReserve: Codeunit "Item Jnl. Line-Reserve";
+ begin
+ ItemJnlLineReserve.InitFromItemJnlLine(TrackingSpecification, ItemJournalLine);
+ ItemTrackingLines.SetSourceSpec(TrackingSpecification, ItemJournalLine."Posting Date");
+ ItemTrackingLines.SetInbound(ItemJournalLine.IsInbound());
+ ItemTrackingLines.RunModal();
+ end;
+
+ procedure CreateItemTrackingCodeWithExpirationDate(var ItemTrackingCode: Record "Item Tracking Code"; SNSpecific: Boolean; LNSpecific: Boolean)
+ begin
+ CreateItemTrackingCode(ItemTrackingCode, SNSpecific, LNSpecific);
+ ItemTrackingCode.Validate("Use Expiration Dates", true);
+ ItemTrackingCode.Modify();
+ end;
+
+ procedure CreateItemTrackingCode(var ItemTrackingCode: Record "Item Tracking Code"; SNSpecific: Boolean; LNSpecific: Boolean)
+ var
+ ItemTrackingSetup: Record "Item Tracking Setup";
+ begin
+ ItemTrackingSetup."Serial No. Required" := SNSpecific;
+ ItemTrackingSetup."Lot No. Required" := LNSpecific;
+ CreateItemTrackingCode(ItemTrackingCode, ItemTrackingSetup);
+ end;
+
+ procedure CreateItemTrackingCode(var ItemTrackingCode: Record "Item Tracking Code"; SNSpecific: Boolean; LNSpecific: Boolean; PNSpecific: Boolean)
+ var
+ ItemTrackingSetup: Record "Item Tracking Setup";
+ begin
+ ItemTrackingSetup."Serial No. Required" := SNSpecific;
+ ItemTrackingSetup."Lot No. Required" := LNSpecific;
+ ItemTrackingSetup."Package No. Required" := PNSpecific;
+ CreateItemTrackingCode(ItemTrackingCode, ItemTrackingSetup);
+ end;
+
+ procedure CreateItemTrackingCode(var ItemTrackingCode: Record "Item Tracking Code"; ItemTrackingSetup: Record "Item Tracking Setup")
+ begin
+ Clear(ItemTrackingCode);
+ ItemTrackingCode.Validate(Code,
+ LibraryUtility.GenerateRandomCode(ItemTrackingCode.FieldNo(Code), DATABASE::"Item Tracking Code"));
+ ItemTrackingCode.Validate("SN Specific Tracking", ItemTrackingSetup."Serial No. Required");
+ ItemTrackingCode.Validate("Lot Specific Tracking", ItemTrackingSetup."Lot No. Required");
+ ItemTrackingCode.Validate("Package Specific Tracking", ItemTrackingSetup."Package No. Required");
+ ItemTrackingCode.Insert(true);
+ end;
+
+ procedure CreateItemReceiptItemTracking(var ReservEntry: Record "Reservation Entry"; InvtDocumentLine: Record "Invt. Document Line"; SerialNo: Code[50]; LotNo: Code[50]; QtyBase: Decimal)
+ var
+ ItemTrackingSetup: Record "Item Tracking Setup";
+ begin
+ ItemTrackingSetup."Serial No." := SerialNo;
+ ItemTrackingSetup."Lot No." := LotNo;
+ CreateItemReceiptItemTracking(ReservEntry, InvtDocumentLine, ItemTrackingSetup, QtyBase);
+ end;
+
+ procedure CreateItemReceiptItemTracking(var ReservEntry: Record "Reservation Entry"; InvtDocumentLine: Record "Invt. Document Line"; SerialNo: Code[50]; LotNo: Code[50]; PackageNo: Code[20]; QtyBase: Decimal)
+ var
+ ItemTrackingSetup: Record "Item Tracking Setup";
+ begin
+ ItemTrackingSetup."Serial No." := SerialNo;
+ ItemTrackingSetup."Lot No." := LotNo;
+ ItemTrackingSetup."Package No." := PackageNo;
+ CreateItemReceiptItemTracking(ReservEntry, InvtDocumentLine, ItemTrackingSetup, QtyBase);
+ end;
+
+ procedure CreateItemReceiptItemTracking(var ReservEntry: Record "Reservation Entry"; InvtDocumentLine: Record "Invt. Document Line"; ItemTrackingSetup: Record "Item Tracking Setup"; QtyBase: Decimal)
+ var
+ RecRef: RecordRef;
+ begin
+ RecRef.GetTable(InvtDocumentLine);
+ ItemTracking(ReservEntry, RecRef, ItemTrackingSetup, QtyBase);
+ end;
+
+ procedure CreateItemReclassJnLineItemTracking(var ReservEntry: Record "Reservation Entry"; ItemJournalLine: Record "Item Journal Line"; SerialNo: Code[50]; LotNo: Code[50]; QtyBase: Decimal)
+ var
+ ItemTrackingSetup: Record "Item Tracking Setup";
+ begin
+ ItemTrackingSetup."Serial No." := SerialNo;
+ ItemTrackingSetup."Lot No." := LotNo;
+ CreateItemReclassJnLineItemTracking(ReservEntry, ItemJournalLine, ItemTrackingSetup, QtyBase);
+ end;
+
+ procedure CreateItemReclassJnLineItemTracking(var ReservEntry: Record "Reservation Entry"; ItemJournalLine: Record "Item Journal Line"; SerialNo: Code[50]; LotNo: Code[50]; PackageNo: Code[20]; QtyBase: Decimal)
+ var
+ ItemTrackingSetup: Record "Item Tracking Setup";
+ begin
+ ItemTrackingSetup."Serial No." := SerialNo;
+ ItemTrackingSetup."Lot No." := LotNo;
+ ItemTrackingSetup."Package No." := PackageNo;
+ CreateItemReclassJnLineItemTracking(ReservEntry, ItemJournalLine, ItemTrackingSetup, QtyBase);
+ end;
+
+ procedure CreateItemReclassJnLineItemTracking(var ReservEntry: Record "Reservation Entry"; ItemJournalLine: Record "Item Journal Line"; ItemTrackingSetup: Record "Item Tracking Setup"; QtyBase: Decimal)
+ var
+ RecRef: RecordRef;
+ begin
+ RecRef.GetTable(ItemJournalLine);
+ ItemTracking(ReservEntry, RecRef, ItemTrackingSetup, QtyBase);
+ end;
+
+ procedure CreateItemWithItemTrackingCode(var Item: Record Item; ItemTrackingCode: Record "Item Tracking Code"): Code[20]
+ begin
+ LibraryInventory.CreateItem(Item);
+ Item.Validate("Item Tracking Code", ItemTrackingCode.Code);
+ Item.Modify(true);
+ exit(Item."No.");
+ end;
+
+ procedure CreateLotItem(var Item: Record Item): Code[20]
+ begin
+ LibraryInventory.CreateItem(Item);
+ AddLotNoTrackingInfo(Item);
+ exit(Item."No.");
+ end;
+
+ procedure CreateLotNoInformation(var LotNoInformation: Record "Lot No. Information"; ItemNo: Code[20]; VariantCode: Code[10]; LotNo: Code[50])
+ begin
+ Clear(LotNoInformation);
+ LotNoInformation.Init();
+ LotNoInformation.Validate("Item No.", ItemNo);
+ LotNoInformation.Validate("Variant Code", VariantCode);
+ LotNoInformation.Validate("Lot No.", LotNo);
+ LotNoInformation.Insert(true);
+ end;
+
+ procedure CreatePackageNoInformation(var PackageNoInformation: Record "Package No. Information"; ItemNo: Code[20]; PackageNo: Code[50])
+ begin
+ Clear(PackageNoInformation);
+ PackageNoInformation.Init();
+ PackageNoInformation.Validate("Item No.", ItemNo);
+ PackageNoInformation.Validate("Package No.", PackageNo);
+ PackageNoInformation.Insert(true);
+ end;
+
+ procedure CreatePlanningWkshItemTracking(var ReservEntry: Record "Reservation Entry"; ReqLine: Record "Requisition Line"; SerialNo: Code[50]; LotNo: Code[50]; QtyBase: Decimal)
+ var
+ ItemTrackingSetup: Record "Item Tracking Setup";
+ begin
+ ItemTrackingSetup."Serial No." := SerialNo;
+ ItemTrackingSetup."Lot No." := LotNo;
+ CreatePlanningWkshItemTracking(ReservEntry, ReqLine, ItemTrackingSetup, QtyBase);
+ end;
+
+ procedure CreatePlanningWkshItemTracking(var ReservEntry: Record "Reservation Entry"; ReqLine: Record "Requisition Line"; ItemTrackingSetup: Record "Item Tracking Setup"; QtyBase: Decimal)
+ var
+ RecRef: RecordRef;
+ begin
+ RecRef.GetTable(ReqLine);
+ ItemTracking(ReservEntry, RecRef, ItemTrackingSetup, QtyBase);
+ end;
+
+#if not CLEAN27
+#pragma warning disable AL0801
+ [Obsolete('Moved to codeunit LibraryManufacturing', '27.0')]
+ procedure CreateProdOrderItemTracking(var ReservEntry: Record "Reservation Entry"; ProdOrderLine: Record "Prod. Order Line"; SerialNo: Code[50]; LotNo: Code[50]; QtyBase: Decimal)
+ var
+ ItemTrackingSetup: Record "Item Tracking Setup";
+ begin
+ ItemTrackingSetup."Serial No." := SerialNo;
+ ItemTrackingSetup."Lot No." := LotNo;
+#pragma warning disable AL0432
+ CreateProdOrderItemTracking(ReservEntry, ProdOrderLine, ItemTrackingSetup, QtyBase);
+#pragma warning restore AL0432
+ end;
+#pragma warning restore AL0801
+#endif
+
+#if not CLEAN27
+#pragma warning disable AL0801
+ [Obsolete('Moved to codeunit LibraryManufacturing', '27.0')]
+ procedure CreateProdOrderItemTracking(var ReservEntry: Record "Reservation Entry"; ProdOrderLine: Record "Prod. Order Line"; ItemTrackingSetup: Record "Item Tracking Setup"; QtyBase: Decimal)
+ var
+ RecRef: RecordRef;
+ begin
+ RecRef.GetTable(ProdOrderLine);
+ ItemTracking(ReservEntry, RecRef, ItemTrackingSetup, QtyBase);
+ end;
+#pragma warning restore AL0801
+#endif
+
+#if not CLEAN27
+#pragma warning disable AL0801
+ [Obsolete('Moved to codeunit LibraryManufacturing', '27.0')]
+ procedure CreateProdOrderCompItemTracking(var ReservEntry: Record "Reservation Entry"; ProdOrderComp: Record "Prod. Order Component"; SerialNo: Code[50]; LotNo: Code[50]; QtyBase: Decimal)
+ var
+ ITemTrackingSetup: Record "Item Tracking Setup";
+ begin
+ ItemTrackingSetup."Serial No." := SerialNo;
+ ItemTrackingSetup."Lot No." := LotNo;
+#pragma warning disable AL0432
+ CreateProdOrderCompItemTracking(ReservEntry, ProdOrderComp, ITemTrackingSetup, QtyBase);
+#pragma warning restore AL0432
+ end;
+#pragma warning restore AL0801
+#endif
+
+#if not CLEAN27
+#pragma warning disable AL0801
+ [Obsolete('Moved to codeunit LibraryManufacturing', '27.0')]
+ procedure CreateProdOrderCompItemTracking(var ReservEntry: Record "Reservation Entry"; ProdOrderComp: Record "Prod. Order Component"; ItemTrackingSetup: Record "Item Tracking Setup"; QtyBase: Decimal)
+ var
+ RecRef: RecordRef;
+ begin
+ RecRef.GetTable(ProdOrderComp);
+ ItemTracking(ReservEntry, RecRef, ItemTrackingSetup, QtyBase);
+ end;
+#pragma warning restore AL0801
+#endif
+
+ procedure CreatePurchOrderItemTracking(var ReservEntry: Record "Reservation Entry"; PurchLine: Record "Purchase Line"; SerialNo: Code[50]; LotNo: Code[50]; QtyBase: Decimal)
+ var
+ ItemTrackingSetup: Record "Item Tracking Setup";
+ begin
+ ItemTrackingSetup."Serial No." := SerialNo;
+ ItemTrackingSetup."Lot No." := LotNo;
+ CreatePurchOrderItemTracking(ReservEntry, PurchLine, ItemTrackingSetup, QtyBase);
+ end;
+
+ procedure CreatePurchOrderItemTracking(var ReservEntry: Record "Reservation Entry"; PurchLine: Record "Purchase Line"; SerialNo: Code[50]; LotNo: Code[50]; PackageNo: Code[50]; QtyBase: Decimal)
+ var
+ ItemTrackingSetup: Record "Item Tracking Setup";
+ begin
+ ItemTrackingSetup."Serial No." := SerialNo;
+ ItemTrackingSetup."Lot No." := LotNo;
+ ItemTrackingSetup."Package No." := PackageNo;
+ CreatePurchOrderItemTracking(ReservEntry, PurchLine, ItemTrackingSetup, QtyBase);
+ end;
+
+ procedure CreatePurchOrderItemTracking(var ReservEntry: Record "Reservation Entry"; PurchLine: Record "Purchase Line"; ItemTrackingSetup: Record "Item Tracking Setup"; QtyBase: Decimal)
+ var
+ RecRef: RecordRef;
+ begin
+ if PurchLine."Document Type" = PurchLine."Document Type"::"Blanket Order" then // cannot create IT for this line from UI
+ Error(Text001, RecRef.Number);
+ RecRef.GetTable(PurchLine);
+ ItemTracking(ReservEntry, RecRef, ItemTrackingSetup, QtyBase);
+ end;
+
+ procedure CreateReqWkshItemTracking(var ReservEntry: Record "Reservation Entry"; ReqLine: Record "Requisition Line"; SerialNo: Code[50]; LotNo: Code[50]; QtyBase: Decimal)
+ begin
+ CreatePlanningWkshItemTracking(ReservEntry, ReqLine, SerialNo, LotNo, QtyBase);
+ end;
+
+ procedure CreateSalesOrderItemTracking(var ReservEntry: Record "Reservation Entry"; SalesLine: Record "Sales Line"; SerialNo: Code[50]; LotNo: Code[50]; QtyBase: Decimal)
+ var
+ ItemTrackingSetup: Record "Item Tracking Setup";
+ begin
+ ItemTrackingSetup."Serial No." := SerialNo;
+ ItemTrackingSetup."Lot No." := LotNo;
+ CreateSalesOrderItemTracking(ReservEntry, SalesLine, ItemTrackingSetup, QtyBase);
+ end;
+
+ procedure CreateSalesOrderItemTracking(var ReservEntry: Record "Reservation Entry"; SalesLine: Record "Sales Line"; SerialNo: Code[50]; LotNo: Code[50]; PackageNo: Code[50]; QtyBase: Decimal)
+ var
+ ItemTrackingSetup: Record "Item Tracking Setup";
+ begin
+ ItemTrackingSetup."Serial No." := SerialNo;
+ ItemTrackingSetup."Lot No." := LotNo;
+ ItemTrackingSetup."Package No." := PackageNo;
+ CreateSalesOrderItemTracking(ReservEntry, SalesLine, ItemTrackingSetup, QtyBase);
+ end;
+
+ procedure CreateSalesOrderItemTracking(var ReservEntry: Record "Reservation Entry"; SalesLine: Record "Sales Line"; ItemTrackingSetup: Record "Item Tracking Setup"; QtyBase: Decimal)
+ var
+ RecRef: RecordRef;
+ begin
+ if SalesLine."Document Type" = SalesLine."Document Type"::"Blanket Order" then // cannot create IT for this line from UI
+ Error(Text001, RecRef.Number);
+ RecRef.GetTable(SalesLine);
+ ItemTracking(ReservEntry, RecRef, ItemTrackingSetup, QtyBase);
+ end;
+
+ procedure CreateSerialItem(var Item: Record Item): Code[20]
+ begin
+ LibraryInventory.CreateItem(Item);
+ AddSerialNoTrackingInfo(Item);
+ exit(Item."No.");
+ end;
+
+ procedure CreateSerialNoInformation(var SerialNoInformation: Record "Serial No. Information"; ItemNo: Code[20]; VariantCode: Code[10]; SerialNo: Code[50])
+ begin
+ Clear(SerialNoInformation);
+ SerialNoInformation.Init();
+ SerialNoInformation.Validate("Item No.", ItemNo);
+ SerialNoInformation.Validate("Variant Code", VariantCode);
+ SerialNoInformation.Validate("Serial No.", SerialNo);
+ SerialNoInformation.Insert(true);
+ end;
+
+ procedure CreateTransferOrderItemTracking(var ReservEntry: Record "Reservation Entry"; TransferLine: Record "Transfer Line"; SerialNo: Code[50]; LotNo: Code[50]; QtyBase: Decimal)
+ var
+ ItemTrackingSetup: Record "Item Tracking Setup";
+ begin
+ ItemTrackingSetup."Serial No." := SerialNo;
+ ItemTrackingSetup."Lot No." := LotNo;
+ CreateTransferOrderItemTracking(ReservEntry, TransferLine, ItemTrackingSetup, QtyBase);
+ end;
+
+ procedure CreateTransferOrderItemTracking(var ReservEntry: Record "Reservation Entry"; TransferLine: Record "Transfer Line"; SerialNo: Code[50]; LotNo: Code[50]; PackageNo: Code[50]; QtyBase: Decimal)
+ var
+ ItemTrackingSetup: Record "Item Tracking Setup";
+ begin
+ ItemTrackingSetup."Serial No." := SerialNo;
+ ItemTrackingSetup."Lot No." := LotNo;
+ ItemTrackingSetup."Package No." := PackageNo;
+ CreateTransferOrderItemTracking(ReservEntry, TransferLine, ItemTrackingSetup, QtyBase);
+ end;
+
+ procedure CreateTransferOrderItemTracking(var ReservEntry: Record "Reservation Entry"; TransferLine: Record "Transfer Line"; ItemTrackingSetup: Record "Item Tracking Setup"; QtyBase: Decimal)
+ var
+ RecRef: RecordRef;
+ begin
+ // Only creates IT lines for Transfer order shipment! IT lines for receipt cannot be added in form.
+ // Note that the ReservEntry returned has two lines - one for TRANSFER-FROM and one for TRANSFER-TO
+ RecRef.GetTable(TransferLine);
+ ItemTracking(ReservEntry, RecRef, ItemTrackingSetup, QtyBase);
+ end;
+
+ procedure CreateWhseInvtPickItemTracking(var WhseItemTrackingLine: Record "Whse. Item Tracking Line"; WhseInternalPickLine: Record "Whse. Internal Pick Line"; SerialNo: Code[50]; LotNo: Code[50]; QtyBase: Decimal)
+ var
+ WhseItemTrackingSetup: Record "Item Tracking Setup";
+ begin
+ WhseItemTrackingSetup."Serial No." := SerialNo;
+ WhseItemTrackingSetup."Lot No." := LotNo;
+ CreateWhseInvtPickItemTracking(WhseItemTrackingLine, WhseInternalPickLine, WhseItemTrackingSetup, QtyBase);
+ end;
+
+ procedure CreateWhseInvtPickItemTracking(var WhseItemTrackingLine: Record "Whse. Item Tracking Line"; WhseInternalPickLine: Record "Whse. Internal Pick Line"; WhseItemTrackingSetup: Record "Item Tracking Setup"; QtyBase: Decimal)
+ var
+ RecRef: RecordRef;
+ begin
+ RecRef.GetTable(WhseInternalPickLine);
+ WhseItemTracking(WhseItemTrackingLine, RecRef, WhseItemTrackingSetup, QtyBase);
+ end;
+
+ procedure CreateWhseInvtPutawayItemTracking(var WhseItemTrackingLine: Record "Whse. Item Tracking Line"; WhseInternalPutAwayLine: Record "Whse. Internal Put-away Line"; SerialNo: Code[50]; LotNo: Code[50]; QtyBase: Decimal)
+ var
+ WhseItemTrackingSetup: Record "Item Tracking Setup";
+ begin
+ WhseItemTrackingSetup."Serial No." := SerialNo;
+ WhseItemTrackingSetup."Lot No." := LotNo;
+ CreateWhseInvtPutawayItemTracking(WhseItemTrackingLine, WhseInternalPutAwayLine, WhseItemTrackingSetup, QtyBase);
+ end;
+
+ procedure CreateWhseInvtPutawayItemTracking(var WhseItemTrackingLine: Record "Whse. Item Tracking Line"; WhseInternalPutAwayLine: Record "Whse. Internal Put-away Line"; WhseItemTrackingSetup: Record "Item Tracking Setup"; QtyBase: Decimal)
+ var
+ RecRef: RecordRef;
+ begin
+ RecRef.GetTable(WhseInternalPutAwayLine);
+ WhseItemTracking(WhseItemTrackingLine, RecRef, WhseItemTrackingSetup, QtyBase);
+ end;
+
+ procedure CreateWhseJournalLineItemTracking(var WhseItemTrackingLine: Record "Whse. Item Tracking Line"; WhseJnlLine: Record "Warehouse Journal Line"; SerialNo: Code[50]; LotNo: Code[50]; QtyBase: Decimal)
+ var
+ WhseItemTrackingSetup: Record "Item Tracking Setup";
+ begin
+ WhseItemTrackingSetup."Serial No." := SerialNo;
+ WhseItemTrackingSetup."Lot No." := LotNo;
+ CreateWhseJournalLineItemTracking(WhseItemTrackingLine, WhseJnlLine, WhseItemTrackingSetup, QtyBase);
+ end;
+
+ procedure CreateWhseJournalLineItemTracking(var WhseItemTrackingLine: Record "Whse. Item Tracking Line"; WhseJnlLine: Record "Warehouse Journal Line"; WhseItemTrackingSetup: Record "Item Tracking Setup"; QtyBase: Decimal)
+ var
+ RecRef: RecordRef;
+ begin
+ RecRef.GetTable(WhseJnlLine);
+ WhseItemTracking(WhseItemTrackingLine, RecRef, WhseItemTrackingSetup, QtyBase);
+ end;
+
+ procedure CreateWhseReceiptItemTracking(var ReservEntry: Record "Reservation Entry"; WhseRcptLine: Record "Warehouse Receipt Line"; SerialNo: Code[50]; LotNo: Code[50]; QtyBase: Decimal)
+ var
+ WhseItemTrackingSetup: Record "Item Tracking Setup";
+ begin
+ WhseItemTrackingSetup."Serial No." := SerialNo;
+ WhseItemTrackingSetup."Lot No." := LotNo;
+ CreateWhseReceiptItemTracking(ReservEntry, WhseRcptLine, WhseItemTrackingSetup, QtyBase);
+ end;
+
+ procedure CreateWhseReceiptItemTracking(var ReservEntry: Record "Reservation Entry"; WhseRcptLine: Record "Warehouse Receipt Line"; WhseItemTrackingSetup: Record "Item Tracking Setup"; QtyBase: Decimal)
+ var
+ RecRef: RecordRef;
+ begin
+ RecRef.GetTable(WhseRcptLine);
+ ItemTracking(ReservEntry, RecRef, WhseItemTrackingSetup, QtyBase);
+ end;
+
+ procedure CreateWhseShipmentItemTracking(var ReservEntry: Record "Reservation Entry"; WhseShptLine: Record "Warehouse Shipment Line"; SerialNo: Code[50]; LotNo: Code[50]; QtyBase: Decimal)
+ var
+ WhseItemTrackingSetup: Record "Item Tracking Setup";
+ begin
+ WhseItemTrackingSetup."Serial No." := SerialNo;
+ WhseItemTrackingSetup."Lot No." := LotNo;
+ CreateWhseShipmentItemTracking(ReservEntry, WhseShptLine, WhseItemTrackingSetup, QtyBase);
+ end;
+
+ procedure CreateWhseShipmentItemTracking(var ReservEntry: Record "Reservation Entry"; WhseShptLine: Record "Warehouse Shipment Line"; WhseItemTrackingSetup: Record "Item Tracking Setup"; QtyBase: Decimal)
+ var
+ RecRef: RecordRef;
+ begin
+ RecRef.GetTable(WhseShptLine);
+ ItemTracking(ReservEntry, RecRef, WhseItemTrackingSetup, QtyBase);
+ end;
+
+ procedure CreateWhseWkshItemTracking(var WhseItemTrackingLine: Record "Whse. Item Tracking Line"; WhseWkshLine: Record "Whse. Worksheet Line"; SerialNo: Code[50]; LotNo: Code[50]; QtyBase: Decimal)
+ var
+ WhseItemTrackingSetup: Record "Item Tracking Setup";
+ begin
+ WhseItemTrackingSetup."Serial No." := SerialNo;
+ WhseItemTrackingSetup."Lot No." := LotNo;
+ CreateWhseWkshItemTracking(WhseItemTrackingLine, WhseWkshLine, WhseItemTrackingSetup, QtyBase);
+ end;
+
+ procedure CreateWhseWkshItemTracking(var WhseItemTrackingLine: Record "Whse. Item Tracking Line"; WhseWkshLine: Record "Whse. Worksheet Line"; WhseItemTrackingSetup: Record "Item Tracking Setup"; QtyBase: Decimal)
+ var
+ RecRef: RecordRef;
+ begin
+ RecRef.GetTable(WhseWkshLine);
+ WhseItemTracking(WhseItemTrackingLine, RecRef, WhseItemTrackingSetup, QtyBase);
+ end;
+
+ procedure ItemJournal_CalcWhseAdjmnt(var Item: Record Item; NewPostingDate: Date; DocumentNo: Text[20])
+ var
+ ItemJournalLine: Record "Item Journal Line";
+ TmpItem: Record Item;
+ ItemJournalTemplate: Record "Item Journal Template";
+ ItemJournalBatch: Record "Item Journal Batch";
+ CalcWhseAdjmnt: Report "Calculate Whse. Adjustment";
+ NoSeries: Codeunit "No. Series";
+ LibraryAssembly: Codeunit "Library - Assembly";
+ begin
+ LibraryAssembly.SetupItemJournal(ItemJournalTemplate, ItemJournalBatch);
+ ItemJournalLine.Validate("Journal Template Name", ItemJournalBatch."Journal Template Name");
+ ItemJournalLine.Validate("Journal Batch Name", ItemJournalBatch.Name);
+
+ Commit();
+ CalcWhseAdjmnt.SetItemJnlLine(ItemJournalLine);
+ if DocumentNo = '' then
+ DocumentNo := NoSeries.PeekNextNo(ItemJournalBatch."No. Series", NewPostingDate);
+ CalcWhseAdjmnt.InitializeRequest(NewPostingDate, DocumentNo);
+ if Item.HasFilter then
+ TmpItem.CopyFilters(Item)
+ else begin
+ Item.Get(Item."No.");
+ TmpItem.SetRange("No.", Item."No.");
+ end;
+
+ CalcWhseAdjmnt.SetTableView(TmpItem);
+ CalcWhseAdjmnt.UseRequestPage(false);
+ CalcWhseAdjmnt.RunModal();
+ end;
+
+ procedure ItemTracking(var ReservEntry: Record "Reservation Entry"; RecRef: RecordRef; ItemTrackingSetup: Record "Item Tracking Setup"; QtyBase: Decimal)
+ var
+ SalesLine: Record "Sales Line";
+ PurchLine: Record "Purchase Line";
+ AssemblyLine: Record "Assembly Line";
+ AssemblyHeader: Record "Assembly Header";
+ TransLine: Record "Transfer Line";
+ ItemJournalLine: Record "Item Journal Line";
+ ReqLine: Record "Requisition Line";
+ WhseShptLine: Record "Warehouse Shipment Line";
+ WhseRcptLine: Record "Warehouse Receipt Line";
+ InvtDocumentLine: Record "Invt. Document Line";
+ Job: Record Job;
+ Item: Record Item;
+ OutgoingEntryNo: Integer;
+ IncomingEntryNo: Integer;
+ IsHandled: Boolean;
+ begin
+ // remove leading spaces
+ ItemTrackingSetup."Serial No." := DelChr(ItemTrackingSetup."Serial No.", '<', ' ');
+ ItemTrackingSetup."Lot No." := DelChr(ItemTrackingSetup."Lot No.", '<', ' ');
+ ItemTrackingSetup."Package No." := DelChr(ItemTrackingSetup."Package No.", '<', ' ');
+ case RecRef.Number of
+ DATABASE::"Sales Line":
+ begin
+ RecRef.SetTable(SalesLine);
+ // COPY FROM TAB 37: OpenItemTrackingLines
+ SalesLine.TestField(Type, SalesLine.Type::Item);
+ SalesLine.TestField("No.");
+ SalesLine.TestField("Quantity (Base)");
+ if SalesLine."Job Contract Entry No." <> 0 then
+ Error(Text048, SalesLine.TableCaption(), Job.TableCaption());
+ // COPY END
+ InsertItemTracking(
+ ReservEntry, SalesLine.SignedXX(SalesLine.Quantity) > 0,
+ SalesLine."No.", SalesLine."Location Code", SalesLine."Variant Code",
+ SalesLine.SignedXX(QtyBase), SalesLine."Qty. per Unit of Measure", ItemTrackingSetup,
+ DATABASE::"Sales Line", SalesLine."Document Type".AsInteger(), SalesLine."Document No.",
+ '', 0, SalesLine."Line No.", SalesLine."Shipment Date");
+ end;
+ DATABASE::"Purchase Line":
+ begin
+ RecRef.SetTable(PurchLine);
+ // COPY FROM TAB 39: OpenItemTrackingLines
+ PurchLine.TestField(Type, PurchLine.Type::Item);
+ PurchLine.TestField("No.");
+ if PurchLine."Prod. Order No." <> '' then
+ Error(Text031, PurchLine."Prod. Order No.");
+ PurchLine.TestField("Quantity (Base)");
+ // COPY END
+ InsertItemTracking(
+ ReservEntry, PurchLine.Signed(PurchLine.Quantity) > 0,
+ PurchLine."No.", PurchLine."Location Code", PurchLine."Variant Code",
+ PurchLine.Signed(QtyBase), PurchLine."Qty. per Unit of Measure", ItemTrackingSetup,
+ DATABASE::"Purchase Line", PurchLine."Document Type".AsInteger(), PurchLine."Document No.",
+ '', 0, PurchLine."Line No.", PurchLine."Expected Receipt Date");
+ end;
+ DATABASE::"Assembly Line":
+ begin
+ RecRef.SetTable(AssemblyLine);
+ AssemblyLine.TestField(Type, AssemblyLine.Type::Item);
+ AssemblyLine.TestField("No.");
+ AssemblyLine.TestField("Quantity (Base)");
+ InsertItemTracking(
+ ReservEntry, AssemblyLine.Quantity < 0,
+ AssemblyLine."No.", AssemblyLine."Location Code", AssemblyLine."Variant Code",
+ -QtyBase, AssemblyLine."Qty. per Unit of Measure", ItemTrackingSetup,
+ DATABASE::"Assembly Line", AssemblyLine."Document Type".AsInteger(), AssemblyLine."Document No.",
+ '', 0, AssemblyLine."Line No.", AssemblyLine."Due Date");
+ end;
+ DATABASE::"Assembly Header":
+ begin
+ RecRef.SetTable(AssemblyHeader);
+ AssemblyHeader.TestField("Document Type", AssemblyHeader."Document Type"::Order);
+ AssemblyHeader.TestField("Item No.");
+ AssemblyHeader.TestField("Quantity (Base)");
+ InsertItemTracking(
+ ReservEntry, AssemblyHeader.Quantity > 0,
+ AssemblyHeader."Item No.", AssemblyHeader."Location Code", AssemblyHeader."Variant Code",
+ QtyBase, AssemblyHeader."Qty. per Unit of Measure", ItemTrackingSetup,
+ DATABASE::"Assembly Header", AssemblyHeader."Document Type".AsInteger(), AssemblyHeader."No.",
+ '', 0, 0, AssemblyHeader."Due Date");
+ end;
+ DATABASE::"Transfer Line":
+ begin
+ RecRef.SetTable(TransLine);
+ // COPY FROM TAB 5741: OpenItemTrackingLines
+ TransLine.TestField("Item No.");
+ TransLine.TestField("Quantity (Base)");
+ // COPY END
+ // creates 2 lines- one for Transfer-from and another for Transfer-to
+ // first, outgoing line
+ InsertItemTracking(
+ ReservEntry, false,
+ TransLine."Item No.", TransLine."Transfer-from Code", TransLine."Variant Code",
+ -QtyBase, TransLine."Qty. per Unit of Measure", ItemTrackingSetup,
+ DATABASE::"Transfer Line", 0, TransLine."Document No.",
+ '', 0, TransLine."Line No.", TransLine."Shipment Date");
+ OutgoingEntryNo := ReservEntry."Entry No.";
+ // next, incoming line
+ InsertItemTracking(
+ ReservEntry, true,
+ TransLine."Item No.", TransLine."Transfer-to Code", TransLine."Variant Code",
+ QtyBase, TransLine."Qty. per Unit of Measure", ItemTrackingSetup,
+ DATABASE::"Transfer Line", 1, TransLine."Document No.",
+ '', 0, TransLine."Line No.", TransLine."Receipt Date");
+ IncomingEntryNo := ReservEntry."Entry No.";
+ Clear(ReservEntry);
+ ReservEntry.SetFilter("Entry No.", '%1|%2', OutgoingEntryNo, IncomingEntryNo);
+ ReservEntry.FindSet(); // returns both entries
+ end;
+ DATABASE::"Item Journal Line":
+ begin
+ RecRef.SetTable(ItemJournalLine);
+ InsertItemTracking(
+ ReservEntry, ItemJournalLine.Signed(ItemJournalLine.Quantity) > 0,
+ ItemJournalLine."Item No.", ItemJournalLine."Location Code", ItemJournalLine."Variant Code",
+ ItemJournalLine.Signed(QtyBase), ItemJournalLine."Qty. per Unit of Measure", ItemTrackingSetup,
+ DATABASE::"Item Journal Line", ItemJournalLine."Entry Type".AsInteger(), ItemJournalLine."Journal Template Name",
+ ItemJournalLine."Journal Batch Name", 0, ItemJournalLine."Line No.", ItemJournalLine."Posting Date");
+ end;
+ DATABASE::"Requisition Line":
+ begin
+ RecRef.SetTable(ReqLine);
+ // COPY FROM TAB 246: OpenItemTrackingLines
+ ReqLine.TestField(Type, ReqLine.Type::Item);
+ ReqLine.TestField("No.");
+ ReqLine.TestField("Quantity (Base)");
+ // COPY END
+ InsertItemTracking(
+ ReservEntry, ReqLine.Quantity > 0,
+ ReqLine."No.", ReqLine."Location Code", ReqLine."Variant Code",
+ QtyBase, ReqLine."Qty. per Unit of Measure", ItemTrackingSetup,
+ DATABASE::"Requisition Line", 0, ReqLine."Worksheet Template Name",
+ ReqLine."Journal Batch Name", ReqLine."Prod. Order Line No.", ReqLine."Line No.", ReqLine."Due Date");
+ end;
+ DATABASE::"Warehouse Shipment Line":
+ begin
+ WhseShptLine.Init();
+ RecRef.SetTable(WhseShptLine);
+ // COPY FROM TAB 7321: OpenItemTrackingLines
+ WhseShptLine.TestField("No.");
+ WhseShptLine.TestField("Qty. (Base)");
+ Item.Get(WhseShptLine."Item No.");
+ Item.TestField("Item Tracking Code");
+ // COPY END
+ case WhseShptLine."Source Type" of
+ DATABASE::"Sales Line":
+ if SalesLine.Get(WhseShptLine."Source Subtype", WhseShptLine."Source No.", WhseShptLine."Source Line No.") then
+ CreateSalesOrderItemTracking(ReservEntry, SalesLine, ItemTrackingSetup, QtyBase);
+ DATABASE::"Purchase Line":
+ if PurchLine.Get(WhseShptLine."Source Subtype", WhseShptLine."Source No.", WhseShptLine."Source Line No.") then
+ CreatePurchOrderItemTracking(ReservEntry, PurchLine, ItemTrackingSetup, QtyBase);
+ DATABASE::"Transfer Line":
+ // Outbound only
+ if TransLine.Get(WhseShptLine."Source No.", WhseShptLine."Source Line No.") then
+ CreateTransferOrderItemTracking(ReservEntry, TransLine, ItemTrackingSetup, QtyBase);
+ end;
+ end;
+ DATABASE::"Warehouse Receipt Line":
+ begin
+ WhseRcptLine.Init();
+ RecRef.SetTable(WhseRcptLine);
+ // COPY FROM TAB 7317: OpenItemTrackingLines
+ WhseRcptLine.TestField("No.");
+ WhseRcptLine.TestField("Qty. (Base)");
+ Item.Get(WhseRcptLine."Item No.");
+ Item.TestField("Item Tracking Code");
+ // COPY END
+ case WhseRcptLine."Source Type" of
+ DATABASE::"Purchase Line":
+ if PurchLine.Get(WhseRcptLine."Source Subtype", WhseRcptLine."Source No.", WhseRcptLine."Source Line No.") then
+ CreatePurchOrderItemTracking(ReservEntry, PurchLine, ItemTrackingSetup, QtyBase);
+ DATABASE::"Sales Line":
+ if SalesLine.Get(WhseRcptLine."Source Subtype", WhseRcptLine."Source No.", WhseRcptLine."Source Line No.") then
+ CreateSalesOrderItemTracking(ReservEntry, SalesLine, ItemTrackingSetup, QtyBase);
+ DATABASE::"Transfer Line":
+ // Inbound only - not possible to ADD item tracking lines- so throw error
+ Error(Text001, RecRef.Number);
+ end;
+ end;
+ DATABASE::"Invt. Document Line":
+ begin
+ RecRef.SetTable(InvtDocumentLine);
+ InsertItemTracking(ReservEntry,
+ InvtDocumentLine.Signed(InvtDocumentLine.Quantity) > 0,
+ InvtDocumentLine."Item No.", InvtDocumentLine."Location Code", InvtDocumentLine."Variant Code",
+ InvtDocumentLine.Signed(QtyBase), InvtDocumentLine."Qty. per Unit of Measure", ItemTrackingSetup,
+ DATABASE::"Invt. Document Line", InvtDocumentLine."Document Type".AsInteger(),
+ InvtDocumentLine."Document No.", '', 0, InvtDocumentLine."Line No.", InvtDocumentLine."Posting Date");
+ end;
+ else begin
+ IsHandled := true;
+ OnItemTracking(RecRef, ReservEntry, ItemTrackingSetup, QtyBase, IsHandled);
+ if not IsHandled then
+ Error(Text001, RecRef.Number);
+ end;
+ end;
+ end;
+
+ procedure InsertItemTracking(var ReservEntry: Record "Reservation Entry"; Positive2: Boolean; Item: Code[20]; Location: Code[10]; Variant: Code[10]; QtyBase: Decimal; QtyperUOM: Decimal; ItemTrackingSetup: Record "Item Tracking Setup"; SourceType: Integer; SourceSubType: Integer; SourceID: Code[20]; SourceBatchName: Code[10]; SourceProdOrderLine: Integer; SourceRefNo: Integer; DueDate: Date)
+ var
+ SalesLine: Record "Sales Line";
+ PurchLine: Record "Purchase Line";
+ ItemJnlLine: Record "Item Journal Line";
+ LastEntryNo: Integer;
+ begin
+ if (ItemTrackingSetup."Serial No." <> '') and (Abs(QtyBase) > 1) then
+ Error(Text002, ItemTrackingSetup."Serial No.", QtyBase);
+ Clear(ReservEntry);
+ if ReservEntry.FindLast() then
+ LastEntryNo := ReservEntry."Entry No." + 1
+ else
+ LastEntryNo := 1;
+ ReservEntry.Init();
+ ReservEntry."Entry No." := LastEntryNo;
+ ReservEntry.Positive := Positive2;
+ if (SourceType = DATABASE::"Item Journal Line") or
+#pragma warning disable AL0801
+ ((SourceType = DATABASE::"Prod. Order Line") and (SourceSubType in [0, 1])) or
+ // simulated or planned prod line
+ ((SourceType = DATABASE::"Prod. Order Component") and (SourceSubType in [0, 1])) or
+ // simulated or planned prod comp
+#pragma warning restore AL0801
+ (SourceType = DATABASE::"Requisition Line")
+ then
+ ReservEntry.Validate("Reservation Status", ReservEntry."Reservation Status"::Prospect)
+ else
+ ReservEntry.Validate("Reservation Status", ReservEntry."Reservation Status"::Surplus);
+
+ ReservEntry.Validate("Item No.", Item);
+ ReservEntry.Validate("Location Code", Location);
+ ReservEntry.Validate("Variant Code", Variant);
+ ReservEntry.Validate("Qty. per Unit of Measure", QtyperUOM);
+ ReservEntry.Validate("Quantity (Base)", QtyBase);
+
+ case SourceType of
+ DATABASE::"Item Journal Line":
+ case "Item Ledger Entry Type".FromInteger(SourceSubType) of
+ ItemJnlLine."Entry Type"::Purchase,
+ ItemJnlLine."Entry Type"::"Positive Adjmt.",
+ ItemJnlLine."Entry Type"::Output:
+ ReservEntry.Validate("Expected Receipt Date", DueDate);
+ ItemJnlLine."Entry Type"::Sale,
+ ItemJnlLine."Entry Type"::"Negative Adjmt.",
+ ItemJnlLine."Entry Type"::Consumption:
+ ReservEntry.Validate("Shipment Date", DueDate);
+ end;
+ 5406: // DATABASE::"Prod. Order Line"
+ ReservEntry.Validate("Expected Receipt Date", DueDate);
+ 5407: // DATABASE::"Prod. Order Component"
+ ReservEntry.Validate("Shipment Date", DueDate);
+ DATABASE::"Requisition Line":
+ ReservEntry.Validate("Shipment Date", DueDate);
+ DATABASE::"Sales Line":
+ case SourceSubType of
+ SalesLine."Document Type"::Order.AsInteger(),
+ SalesLine."Document Type"::Invoice.AsInteger(),
+ SalesLine."Document Type"::Quote.AsInteger():
+ ReservEntry.Validate("Shipment Date", DueDate);
+ SalesLine."Document Type"::"Return Order".AsInteger(),
+ SalesLine."Document Type"::"Credit Memo".AsInteger():
+ ReservEntry.Validate("Expected Receipt Date", DueDate);
+ end;
+ DATABASE::"Purchase Line":
+ case SourceSubType of
+ PurchLine."Document Type"::Order.AsInteger(),
+ PurchLine."Document Type"::Invoice.AsInteger(),
+ PurchLine."Document Type"::Quote.AsInteger():
+ ReservEntry.Validate("Expected Receipt Date", DueDate);
+ PurchLine."Document Type"::"Return Order".AsInteger(),
+ PurchLine."Document Type"::"Credit Memo".AsInteger():
+ ReservEntry.Validate("Shipment Date", DueDate);
+ end;
+ else
+ if Positive2 then
+ ReservEntry.Validate("Expected Receipt Date", DueDate)
+ else
+ ReservEntry.Validate("Shipment Date", DueDate);
+ end;
+ ReservEntry.Validate("Creation Date", WorkDate());
+ ReservEntry."Created By" := CopyStr(UserId(), 1, MaxStrLen(ReservEntry."Created By"));
+
+ ReservEntry.Validate("Serial No.", ItemTrackingSetup."Serial No.");
+ ReservEntry.Validate("Lot No.", ItemTrackingSetup."Lot No.");
+ ReservEntry.Validate("Package No.", ItemTrackingSetup."Package No.");
+
+ ReservEntry.UpdateItemTracking();
+
+ ReservEntry.Validate("Source Type", SourceType);
+ ReservEntry.Validate("Source Subtype", SourceSubType);
+ ReservEntry.Validate("Source ID", SourceID);
+ ReservEntry.Validate("Source Batch Name", SourceBatchName);
+ ReservEntry.Validate("Source Prod. Order Line", SourceProdOrderLine);
+ ReservEntry.Validate("Source Ref. No.", SourceRefNo);
+
+ ReservEntry.Insert(true);
+ end;
+
+ local procedure WhseItemTracking(var WhseItemTrackingLine: Record "Whse. Item Tracking Line"; RecRef: RecordRef; WhseItemTrackingSetup: Record "Item Tracking Setup"; QtyBase: Decimal)
+ var
+ WhseJnlLine: Record "Warehouse Journal Line";
+ WhseWkshLine: Record "Whse. Worksheet Line";
+ WhseInternalPutAwayLine: Record "Whse. Internal Put-away Line";
+ WhseInternalPickLine: Record "Whse. Internal Pick Line";
+ SourceType: Integer;
+ SourceID: Code[20];
+ SourceBatchName: Code[10];
+ SourceRefNo: Integer;
+ begin
+ // remove leading spaces
+ WhseItemTrackingSetup."Serial No." := DelChr(WhseItemTrackingSetup."Serial No.", '<', ' ');
+ WhseItemTrackingSetup."Lot No." := DelChr(WhseItemTrackingSetup."Lot No.", '<', ' ');
+ WhseItemTrackingSetup."Package No." := DelChr(WhseItemTrackingSetup."Package No.", '<', ' ');
+ case RecRef.Number of
+ DATABASE::"Warehouse Journal Line":
+ begin
+ WhseJnlLine.Init();
+ RecRef.SetTable(WhseJnlLine);
+ // COPY FROM TAB 7311: OpenItemTrackingLines
+ WhseJnlLine.TestField("Item No.");
+ WhseJnlLine.TestField("Qty. (Base)");
+ // COPY END
+ WhseInsertItemTracking(WhseItemTrackingLine,
+ WhseJnlLine."Item No.",
+ WhseJnlLine."Location Code",
+ WhseJnlLine."Variant Code",
+ QtyBase,
+ WhseJnlLine."Qty. per Unit of Measure",
+ WhseItemTrackingSetup,
+ DATABASE::"Warehouse Journal Line",
+ 0,
+ WhseJnlLine."Journal Batch Name",
+ WhseJnlLine."Journal Template Name",
+ 0,
+ WhseJnlLine."Line No.");
+ end;
+ DATABASE::"Whse. Worksheet Line":
+ begin
+ RecRef.SetTable(WhseWkshLine);
+ // COPY FROM TAB 7326: OpenItemTrackingLines
+ WhseWkshLine.TestField("Item No.");
+ WhseWkshLine.TestField("Qty. (Base)");
+ case WhseWkshLine."Whse. Document Type" of
+ WhseWkshLine."Whse. Document Type"::Receipt:
+ begin
+ SourceType := DATABASE::"Posted Whse. Receipt Line";
+ SourceID := WhseWkshLine."Whse. Document No.";
+ SourceBatchName := '';
+ SourceRefNo := WhseWkshLine."Whse. Document Line No.";
+ end;
+ WhseWkshLine."Whse. Document Type"::Shipment:
+ begin
+ SourceType := DATABASE::"Warehouse Shipment Line";
+ SourceID := WhseWkshLine."Whse. Document No.";
+ SourceBatchName := '';
+ SourceRefNo := WhseWkshLine."Whse. Document Line No.";
+ end;
+ WhseWkshLine."Whse. Document Type"::"Internal Put-away":
+ begin
+ SourceType := DATABASE::"Whse. Internal Put-away Line";
+ SourceID := WhseWkshLine."Whse. Document No.";
+ SourceBatchName := '';
+ SourceRefNo := WhseWkshLine."Whse. Document Line No.";
+ end;
+ WhseWkshLine."Whse. Document Type"::"Internal Pick":
+ begin
+ SourceType := DATABASE::"Whse. Internal Pick Line";
+ SourceID := WhseWkshLine."Whse. Document No.";
+ SourceBatchName := '';
+ SourceRefNo := WhseWkshLine."Whse. Document Line No.";
+ end;
+ WhseWkshLine."Whse. Document Type"::Production:
+ begin
+ SourceType := 5407; // DATABASE::"Prod. Order Component";
+ SourceID := WhseWkshLine."Whse. Document No.";
+ SourceBatchName := '';
+ SourceRefNo := WhseWkshLine."Whse. Document Line No.";
+ end;
+ WhseWkshLine."Whse. Document Type"::Assembly:
+ begin
+ SourceType := DATABASE::"Assembly Line";
+ SourceID := WhseWkshLine."Whse. Document No.";
+ SourceBatchName := '';
+ SourceRefNo := WhseWkshLine."Whse. Document Line No.";
+ end;
+ else begin
+ SourceType := DATABASE::"Whse. Worksheet Line";
+ SourceID := WhseWkshLine.Name;
+ SourceBatchName := WhseWkshLine."Worksheet Template Name";
+ SourceRefNo := WhseWkshLine."Line No.";
+ end;
+ end;
+ // COPY END
+ WhseInsertItemTracking(WhseItemTrackingLine,
+ WhseWkshLine."Item No.",
+ WhseWkshLine."Location Code",
+ WhseWkshLine."Variant Code",
+ QtyBase,
+ WhseWkshLine."Qty. per Unit of Measure",
+ WhseItemTrackingSetup,
+ SourceType,
+ 0,
+ SourceID,
+ SourceBatchName,
+ 0,
+ SourceRefNo);
+ end;
+ DATABASE::"Whse. Internal Put-away Line":
+ begin
+ WhseInternalPutAwayLine.Init();
+ RecRef.SetTable(WhseInternalPutAwayLine);
+ // COPY FROM TAB 7332: OpenItemTrackingLines
+ WhseInternalPutAwayLine.TestField("Item No.");
+ WhseInternalPutAwayLine.TestField("Qty. (Base)");
+ WhseWkshLine.Init();
+ WhseWkshLine."Whse. Document Type" :=
+ WhseWkshLine."Whse. Document Type"::"Internal Put-away";
+ WhseWkshLine."Whse. Document No." := WhseInternalPutAwayLine."No.";
+ WhseWkshLine."Whse. Document Line No." := WhseInternalPutAwayLine."Line No.";
+ WhseWkshLine."Location Code" := WhseInternalPutAwayLine."Location Code";
+ WhseWkshLine."Item No." := WhseInternalPutAwayLine."Item No.";
+ WhseWkshLine."Qty. (Base)" := WhseInternalPutAwayLine."Qty. (Base)";
+ WhseWkshLine."Qty. to Handle (Base)" :=
+ WhseInternalPutAwayLine."Qty. (Base)" - WhseInternalPutAwayLine."Qty. Put Away (Base)" -
+ WhseInternalPutAwayLine."Put-away Qty. (Base)";
+ WhseWkshLine."Qty. per Unit of Measure" := WhseInternalPutAwayLine."Qty. per Unit of Measure";
+ // COPY END
+ RecRef.GetTable(WhseWkshLine);
+ WhseItemTracking(WhseItemTrackingLine, RecRef, WhseItemTrackingSetup, QtyBase);
+ end;
+ DATABASE::"Whse. Internal Pick Line":
+ begin
+ WhseInternalPickLine.Init();
+ RecRef.SetTable(WhseInternalPickLine);
+ // COPY FROM TAB 7334: OpenItemTrackingLines
+ WhseInternalPickLine.TestField("Item No.");
+ WhseInternalPickLine.TestField("Qty. (Base)");
+ WhseWkshLine.Init();
+ WhseWkshLine."Whse. Document Type" :=
+ WhseWkshLine."Whse. Document Type"::"Internal Pick";
+ WhseWkshLine."Whse. Document No." := WhseInternalPickLine."No.";
+ WhseWkshLine."Whse. Document Line No." := WhseInternalPickLine."Line No.";
+ WhseWkshLine."Location Code" := WhseInternalPickLine."Location Code";
+ WhseWkshLine."Item No." := WhseInternalPickLine."Item No.";
+ WhseWkshLine."Qty. (Base)" := WhseInternalPickLine."Qty. (Base)";
+ WhseWkshLine."Qty. to Handle (Base)" :=
+ WhseInternalPickLine."Qty. (Base)" - WhseInternalPickLine."Qty. Picked (Base)" -
+ WhseInternalPickLine."Pick Qty. (Base)";
+ // WhseWkshLine."Qty. per Unit of Measure" := WhseInternalPickLine."Qty. per Unit of Measure";
+ // COPY END
+ RecRef.GetTable(WhseWkshLine);
+ WhseItemTracking(WhseItemTrackingLine, RecRef, WhseItemTrackingSetup, QtyBase);
+ end;
+ end;
+ end;
+
+ local procedure WhseInsertItemTracking(var WhseItemTrackingLine: Record "Whse. Item Tracking Line"; Item: Code[20]; Location: Code[10]; Variant: Code[10]; QtyBase: Decimal; QtyperUOM: Decimal; WhseItemTrackingSetup: Record "Item Tracking Setup"; SourceType: Integer; SourceSubType: Integer; SourceID: Code[20]; SourceBatchName: Code[10]; SourceProdOrderLine: Integer; SourceRefNo: Integer)
+ var
+ LastEntryNo: Integer;
+ begin
+ if (WhseItemTrackingSetup."Serial No." <> '') and (Abs(QtyBase) > 1) then
+ Error(Text002, WhseItemTrackingSetup."Serial No.", QtyBase);
+ Clear(WhseItemTrackingLine);
+ if WhseItemTrackingLine.FindLast() then
+ LastEntryNo := WhseItemTrackingLine."Entry No." + 1
+ else
+ LastEntryNo := 1;
+ WhseItemTrackingLine.Init();
+ WhseItemTrackingLine."Entry No." := LastEntryNo;
+
+ WhseItemTrackingLine.Validate("Item No.", Item);
+ WhseItemTrackingLine.Validate("Location Code", Location);
+ WhseItemTrackingLine.Validate("Variant Code", Variant);
+ WhseItemTrackingLine.Validate("Qty. per Unit of Measure", QtyperUOM);
+ WhseItemTrackingLine.Validate("Quantity (Base)", Abs(QtyBase));
+
+ WhseItemTrackingLine.Validate("Serial No.", WhseItemTrackingSetup."Serial No.");
+ WhseItemTrackingLine.Validate("Lot No.", WhseItemTrackingSetup."Lot No.");
+ WhseItemTrackingLine.Validate("Package No.", WhseItemTrackingSetup."Package No.");
+
+ WhseItemTrackingLine.Validate("Source Type", SourceType);
+ WhseItemTrackingLine.Validate("Source Subtype", SourceSubType);
+ WhseItemTrackingLine.Validate("Source ID", SourceID);
+ WhseItemTrackingLine.Validate("Source Batch Name", SourceBatchName);
+ WhseItemTrackingLine.Validate("Source Prod. Order Line", SourceProdOrderLine);
+ WhseItemTrackingLine.Validate("Source Ref. No.", SourceRefNo);
+
+ WhseItemTrackingLine.Insert(true);
+ end;
+
+ procedure CreateSalesTrackingFromReservation(SalesHeader: Record "Sales Header"; HideDialog: Boolean)
+ var
+ ItemTrackingDocMgt: Codeunit "Item Tracking Doc. Management";
+ begin
+ ItemTrackingDocMgt.CopyDocTrkgFromReservation(DATABASE::"Sales Header", SalesHeader."Document Type".AsInteger(), SalesHeader."No.", HideDialog);
+ end;
+
+ procedure PostPositiveAdjustmentWithItemTracking(Item: Record Item; LocationCode: Code[10]; VariantCode: Code[10]; Qty: Decimal; PostingDate: Date; SerialNo: Code[50]; LotNo: Code[50])
+ var
+ ReservEntry: Record "Reservation Entry";
+ ItemJournalTemplate: Record "Item Journal Template";
+ ItemJournalLine: Record "Item Journal Line";
+ ItemJournalBatch: Record "Item Journal Batch";
+ begin
+ LibraryInventory.CreateItemJournalBatchByType(ItemJournalBatch, ItemJournalTemplate.Type::Item);
+ LibraryInventory.CreateItemJournalLine(ItemJournalLine, ItemJournalBatch, Item, LocationCode, VariantCode, PostingDate,
+ ItemJournalLine."Entry Type"::"Positive Adjmt.", Qty, 0);
+ CreateItemJournalLineItemTracking(ReservEntry, ItemJournalLine, SerialNo, LotNo, Qty);
+ LibraryInventory.PostItemJournalBatch(ItemJournalBatch);
+ end;
+
+ [InternalEvent(true)]
+ local procedure OnItemTracking(RecRef: RecordRef; var ReservEntry: Record "Reservation Entry"; ItemTrackingSetup: Record "Item Tracking Setup"; QtyBase: Decimal; var IsHandled: Boolean)
+ begin
+ end;
+}
+
diff --git a/Apps/W1/ApplicationTestLibrary/LibraryJob.Codeunit.al b/Apps/W1/ApplicationTestLibrary/LibraryJob.Codeunit.al
new file mode 100644
index 0000000000..47a9205455
--- /dev/null
+++ b/Apps/W1/ApplicationTestLibrary/LibraryJob.Codeunit.al
@@ -0,0 +1,1285 @@
+///
+/// Provides utility functions for creating and managing job (project) entities in test scenarios, including job tasks, job planning lines, and job journals.
+///
+codeunit 131920 "Library - Job"
+{
+
+ trigger OnRun()
+ begin
+ end;
+
+ var
+ Assert: Codeunit Assert;
+ LibraryUtility: Codeunit "Library - Utility";
+ LibraryERM: Codeunit "Library - ERM";
+ LibrarySales: Codeunit "Library - Sales";
+ LibraryPurchase: Codeunit "Library - Purchase";
+ LibraryRandom: Codeunit "Library - Random";
+ LibraryResource: Codeunit "Library - Resource";
+ LibraryInventory: Codeunit "Library - Inventory";
+ ConsumptionSource: Option Job,Service,GenJournal,Purchase;
+ PrefixTxt: Label 'ZZZ';
+ TemplateNameTxt: Label 'T';
+ NoSeriesCodeTxt: Label 'JOBTEST';
+ JobNosTok: Label 'JOB NOS', Locked = true;
+ ErrorMsg: Label 'Unsupported type.';
+ JobNoErr: Label 'GLEntry."Job No."';
+
+ procedure CreateJob(var Job: Record Job)
+ begin
+ CreateJob(Job, CreateCustomer());
+ end;
+
+ procedure CreateJob(var Job: Record Job; SellToCustomerNo: Code[20])
+ var
+ JobNo: Code[20];
+ begin
+ // create a (LCY) job for a random customer
+
+ // Find the next available job no.
+ JobNo := PrefixTxt + 'J000';
+ repeat
+ JobNo := IncStr(JobNo);
+ until not Job.Get(JobNo);
+
+ Job.Init();
+ Job.Validate("No.", JobNo);
+ Job.Insert(true);
+ Job.Validate("Sell-to Customer No.", SellToCustomerNo);
+ Job.Validate("Job Posting Group", FindJobPostingGroup());
+ Job.Modify(true)
+ end;
+
+ procedure CreateJobTask(Job: Record Job; var JobTask: Record "Job Task")
+ var
+ JobTaskLocal: Record "Job Task";
+ JobTaskNo: Code[20];
+ begin
+ // Create a (posting) task for a job
+
+ JobTaskNo := PrefixTxt + 'JT001';
+
+ // Find the last task no. (as an integer)
+ JobTaskLocal.SetRange("Job No.", Job."No.");
+ if JobTaskLocal.FindLast() then
+ JobTaskNo := IncStr(JobTaskLocal."Job Task No.");
+
+ JobTask.Init();
+ JobTask.Validate("Job No.", Job."No.");
+ JobTask.Validate("Job Task No.", JobTaskNo);
+ JobTask.Insert(true);
+
+ JobTask.Validate("Job Task Type", JobTask."Job Task Type"::Posting);
+ JobTask.Modify(true)
+ end;
+
+ procedure CreateJobPlanningLine(LineType: Enum "Job Planning Line Line Type"; Type: Enum "Job Planning Line Type"; JobTask: Record "Job Task"; var JobPlanningLine: Record "Job Planning Line")
+ begin
+ // Create a job planning line for job task of type for consumable type
+
+ JobPlanningLine.Init();
+ JobPlanningLine.Validate("Job No.", JobTask."Job No.");
+ JobPlanningLine.Validate("Job Task No.", JobTask."Job Task No.");
+ JobPlanningLine.Validate("Line No.", GetNextLineNo(JobPlanningLine));
+ JobPlanningLine.Insert(true);
+
+ JobPlanningLine.Validate("Planning Date", WorkDate());
+ JobPlanningLine.Validate("Line Type", LineType);
+ JobPlanningLine.Validate(Type, Type);
+ if JobPlanningLine.Type <> JobPlanningLine.Type::Text then begin
+ JobPlanningLine.Validate("No.", FindConsumable(Type));
+ JobPlanningLine.Validate(Quantity, LibraryRandom.RandInt(100)); // 1 <= Quantity <= 100
+ if Type = GLAccountType() then begin
+ JobPlanningLine.Validate("Unit Cost", LibraryRandom.RandInt(10)); // 1 <= Unit Cost <= 10
+ JobPlanningLine.Validate("Unit Price", JobPlanningLine."Unit Cost" * (LibraryRandom.RandIntInRange(2, 10) / 10)); // 10% <= Markup <= 100%
+ end;
+ end;
+ JobPlanningLine.Validate(Description, LibraryUtility.GenerateGUID());
+ JobPlanningLine.Modify(true);
+
+ JobPlanningLine.SetRange("Job No.", JobTask."Job No.");
+ JobPlanningLine.SetRange("Job Task No.", JobTask."Job Task No.")
+ end;
+
+ procedure CreateJobPlanningLine(JobTask: Record "Job Task"; LineType: Enum "Job Planning Line Line Type"; Type: Enum "Job Planning Line Type"; No: Code[20]; Quantity: Decimal; var JobPlanningLine: Record "Job Planning Line")
+ begin
+ JobPlanningLine.Init();
+ JobPlanningLine.Validate("Job No.", JobTask."Job No.");
+ JobPlanningLine.Validate("Job Task No.", JobTask."Job Task No.");
+ JobPlanningLine.Validate("Line No.", GetNextLineNo(JobPlanningLine));
+ JobPlanningLine.Insert(true);
+ JobPlanningLine.Validate("Planning Date", WorkDate());
+ JobPlanningLine.Validate("Line Type", LineType);
+ JobPlanningLine.Validate(Type, Type);
+ JobPlanningLine.Validate("No.", No);
+ JobPlanningLine.Validate(Quantity, Quantity);
+ JobPlanningLine.Modify(true);
+ end;
+
+ procedure CreateJobJournalLine(LineType: Enum "Job Line Type"; JobTask: Record "Job Task"; var JobJournalLine: Record "Job Journal Line")
+ var
+ JobJournalTemplate: Record "Job Journal Template";
+ JobJournalBatch: Record "Job Journal Batch";
+ NoSeries: Codeunit "No. Series";
+ begin
+ // Create a job journal line for a job task.
+ // This helper function allows to easily create multiple journal lines in a single batch.
+ JobJournalLine.SetRange("Job No.", JobTask."Job No.");
+ // Setup primary keys and filters.
+ if JobJournalLine.FindLast() then
+ // A job journal line for this task already exists: increase line and document nos.
+ JobJournalLine.Validate("Line No.", JobJournalLine."Line No." + 1)
+ else begin
+ // No job journal lines exist for this task: setup the first one.
+ CreateJobJournalBatch(GetJobJournalTemplate(JobJournalTemplate), JobJournalBatch);
+ JobJournalLine.Validate("Journal Template Name", JobJournalTemplate.Name);
+ JobJournalLine.Validate("Journal Batch Name", JobJournalBatch.Name);
+ JobJournalLine.Validate("Line No.", 1);
+ // Only use these template and batch.
+ JobJournalLine.SetRange("Journal Template Name", JobJournalLine."Journal Template Name");
+ JobJournalLine.SetRange("Journal Batch Name", JobJournalLine."Journal Batch Name");
+ end;
+
+ JobJournalLine.Init();
+ JobJournalLine.Insert(true);
+
+ JobJournalLine.Validate("Line Type", LineType);
+ JobJournalLine.Validate("Posting Date", WorkDate());
+ JobJournalLine.Validate("Job No.", JobTask."Job No.");
+ JobJournalLine.Validate("Job Task No.", JobTask."Job Task No.");
+ JobJournalBatch.Get(GetJobJournalTemplate(JobJournalTemplate), JobJournalLine."Journal Batch Name");
+ JobJournalLine.Validate("Document No.", NoSeries.PeekNextNo(JobJournalBatch."No. Series", JobJournalLine."Posting Date"));
+ JobJournalLine.Modify(true)
+ end;
+
+ procedure CreateJobJournalLineForType(LineType: Enum "Job Line Type"; ConsumableType: Enum "Job Planning Line Type"; JobTask: Record "Job Task"; var JobJournalLine: Record "Job Journal Line")
+ begin
+ CreateJobJournalLine(LineType, JobTask, JobJournalLine);
+
+ // Attach requested consumable type to the created job journal line
+ Attach2JobJournalLine(ConsumableType, JobJournalLine);
+ JobJournalLine.Validate(Description, Format(LibraryUtility.GenerateGUID()));
+ JobJournalLine.Modify(true)
+ end;
+
+ procedure CreateJobJournalLineForPlan(JobPlanningLine: Record "Job Planning Line"; UsageLineType: Enum "Job Line Type"; Fraction: Decimal; var JobJournalLine: Record "Job Journal Line")
+ var
+ JobTask: Record "Job Task";
+ ChangeFactor: Decimal;
+ begin
+ Assert.IsTrue(JobPlanningLine."Usage Link", 'Usage link should be enabled');
+
+ JobTask.Get(JobPlanningLine."Job No.", JobPlanningLine."Job Task No.");
+ CreateJobJournalLine(UsageLineType, JobTask, JobJournalLine);
+ JobJournalLine.Validate(Type, JobPlanningLine.Type);
+ JobJournalLine.Validate("No.", JobPlanningLine."No.");
+ JobJournalLine.Validate(Description, LibraryUtility.GenerateGUID());
+ JobJournalLine.Validate(Quantity, Round(Fraction * JobPlanningLine."Remaining Qty."));
+ // unit costs, prices may change (e.g., +/- 10%)
+ if not IsStandardCosting(JobJournalLine.Type, JobJournalLine."No.") then begin
+ ChangeFactor := Round((1 + (LibraryRandom.RandInt(21) - 11) / 100));
+ JobJournalLine.Validate("Unit Cost", Round(ChangeFactor * JobPlanningLine."Unit Cost") / JobPlanningLine.Quantity);
+ JobJournalLine.Validate("Unit Price", Round(ChangeFactor * JobPlanningLine."Unit Price") / JobPlanningLine.Quantity)
+ end;
+ JobJournalLine.Modify(true)
+ end;
+
+ procedure CreateGenJournalLineForPlan(JobPlanningLine: Record "Job Planning Line"; UsageLineType: Enum "Job Line Type"; Fraction: Decimal; var GenJournalLine: Record "Gen. Journal Line")
+ var
+ JobTask: Record "Job Task";
+ begin
+ Assert.IsTrue(JobPlanningLine."Usage Link", 'Usage link should be enabled');
+
+ JobTask.Get(JobPlanningLine."Job No.", JobPlanningLine."Job Task No.");
+ CreateJobGLJournalLine(UsageLineType, JobTask, GenJournalLine);
+
+ GenJournalLine."Account No." := JobPlanningLine."No.";
+ GenJournalLine.Validate(Description, LibraryUtility.GenerateGUID());
+ GenJournalLine.Validate("Job Planning Line No.", JobPlanningLine."Line No.");
+ GenJournalLine.Validate("Job Quantity", Round(Fraction * JobPlanningLine."Remaining Qty."));
+ GenJournalLine.Modify(true)
+ end;
+
+ procedure CreateJobWIPMethod(var JobWIPMethod: Record "Job WIP Method")
+ begin
+ JobWIPMethod.Init();
+ JobWIPMethod.Validate(
+ Code,
+ CopyStr(
+ LibraryUtility.GenerateRandomCode(JobWIPMethod.FieldNo(Code), DATABASE::"Job WIP Method"), 1,
+ LibraryUtility.GetFieldLength(DATABASE::"Job WIP Method", JobWIPMethod.FieldNo(Code))));
+ JobWIPMethod.Insert(true)
+ end;
+
+ procedure CreatePurchaseLineForPlan(JobPlanningLine: Record "Job Planning Line"; UsageLineType: Enum "Job Line Type"; Fraction: Decimal; var PurchaseLine: Record "Purchase Line")
+ var
+ Job: Record Job;
+ JobTask: Record "Job Task";
+ PurchaseHeader: Record "Purchase Header";
+ begin
+ Assert.IsTrue(JobPlanningLine."Usage Link", 'Usage link should be enabled');
+
+ JobTask.Get(JobPlanningLine."Job No.", JobPlanningLine."Job Task No.");
+ Job.Get(JobPlanningLine."Job No.");
+
+ LibraryPurchase.CreatePurchHeader(PurchaseHeader, PurchaseHeader."Document Type"::Order, '');
+ LibraryPurchase.CreatePurchaseLine(PurchaseLine, PurchaseHeader, Job2PurchaseConsumableType(JobPlanningLine.Type),
+ JobPlanningLine."No.", Round(Fraction * JobPlanningLine."Remaining Qty."));
+ // VALIDATE(Description,LibraryUtility.GenerateGUID());
+ PurchaseLine.Validate(Description, JobPlanningLine."No.");
+ PurchaseLine.Validate("Unit of Measure Code", JobPlanningLine."Unit of Measure Code");
+ PurchaseLine.Validate("Job Line Type", UsageLineType);
+ PurchaseLine.Validate("Job No.", JobPlanningLine."Job No.");
+ PurchaseLine.Validate("Job Task No.", JobPlanningLine."Job Task No.");
+ PurchaseLine.Validate("Job Planning Line No.", JobPlanningLine."Line No.");
+ PurchaseLine.Modify(true)
+ end;
+
+#if not CLEAN27
+ [Obsolete('Moved to codeunit Library Service', '27.0')]
+ procedure CreateServiceLineForPlan(JobPlanningLine: Record "Job Planning Line"; UsageLineType: Enum "Job Line Type"; Fraction: Decimal; var ServiceLine: Record "Service Line")
+ var
+ LibraryService: Codeunit "Library - Service";
+ begin
+ LibraryService.CreateServiceLineForPlan(JobPlanningLine, UsageLineType, Fraction, ServiceLine);
+ end;
+#endif
+
+ procedure CreateJobGLAccountPrice(var JobGLAccountPrice: Record "Job G/L Account Price"; JobNo: Code[20]; JobTaskNo: Code[20]; GLAccountNo: Code[20]; CurrencyCode: Code[10])
+ begin
+ JobGLAccountPrice.Init();
+ JobGLAccountPrice.Validate("Job No.", JobNo);
+ JobGLAccountPrice.Validate("Job Task No.", JobTaskNo);
+ JobGLAccountPrice.Validate("G/L Account No.", GLAccountNo);
+ JobGLAccountPrice.Validate("Currency Code", CurrencyCode);
+ JobGLAccountPrice.Insert(true);
+ end;
+
+ procedure CreateJobItemPrice(var JobItemPrice: Record "Job Item Price"; JobNo: Code[20]; JobTaskNo: Code[20]; ItemNo: Code[20]; CurrencyCode: Code[10]; VariantCode: Code[10]; UnitOfMeasureCode: Code[10])
+ begin
+ JobItemPrice.Init();
+ JobItemPrice.Validate("Job No.", JobNo);
+ JobItemPrice.Validate("Job Task No.", JobTaskNo);
+ JobItemPrice.Validate("Item No.", ItemNo);
+ JobItemPrice.Validate("Currency Code", CurrencyCode);
+ JobItemPrice.Validate("Variant Code", VariantCode);
+ JobItemPrice.Validate("Unit of Measure Code", UnitOfMeasureCode);
+ JobItemPrice.Insert(true);
+ end;
+
+ procedure CreateJobResourcePrice(var JobResourcePrice: Record "Job Resource Price"; JobNo: Code[20]; JobTaskNo: Code[20]; Type: Option; "Code": Code[20]; WorkTypeCode: Code[10]; CurrencyCode: Code[10])
+ begin
+ JobResourcePrice.Init();
+ JobResourcePrice.Validate("Job No.", JobNo);
+ JobResourcePrice.Validate("Job Task No.", JobTaskNo);
+ JobResourcePrice.Validate(Type, Type);
+ JobResourcePrice.Validate(Code, Code);
+ JobResourcePrice.Validate("Work Type Code", WorkTypeCode);
+ JobResourcePrice.Validate("Currency Code", CurrencyCode);
+ JobResourcePrice.Insert(true);
+ end;
+
+ procedure CreateJobJournalBatch(JobJournalTemplateName: Code[10]; var JobJournalBatch: Record "Job Journal Batch") BatchName: Code[10]
+ begin
+ Clear(JobJournalBatch);
+
+ // Find a unique batch name (wrt existing and previously posted batches)
+ BatchName := PrefixTxt + 'B000';
+ repeat
+ BatchName := IncStr(BatchName);
+ until not JobJournalBatch.Get(JobJournalTemplateName, BatchName);
+
+ JobJournalBatch.Validate("Journal Template Name", JobJournalTemplateName);
+ JobJournalBatch.Validate(Name, BatchName);
+ JobJournalBatch.SetupNewBatch();
+ JobJournalBatch.Insert(true)
+ end;
+
+ procedure CreateJobJournalTemplate(var JobJournalTemplate: Record "Job Journal Template")
+ begin
+ JobJournalTemplate.Init();
+ JobJournalTemplate.Validate(
+ Name, LibraryUtility.GenerateRandomCode(JobJournalTemplate.FieldNo(Name), DATABASE::"Job Journal Template"));
+ JobJournalTemplate.Insert(true);
+ end;
+
+ procedure CreateJobPostingGroup(var JobPostingGroup: Record "Job Posting Group")
+ begin
+ Clear(JobPostingGroup);
+ JobPostingGroup.Validate(Code,
+ LibraryUtility.GenerateRandomCode(JobPostingGroup.FieldNo(Code), DATABASE::"Job Posting Group"));
+ JobPostingGroup.Validate("WIP Costs Account", LibraryERM.CreateGLAccountNo());
+ JobPostingGroup.Validate("WIP Accrued Costs Account", LibraryERM.CreateGLAccountNo());
+ JobPostingGroup.Validate("Job Costs Applied Account", LibraryERM.CreateGLAccountNo());
+ JobPostingGroup.Validate("Job Costs Adjustment Account", LibraryERM.CreateGLAccountNo());
+ JobPostingGroup.Validate("G/L Expense Acc. (Contract)", LibraryERM.CreateGLAccountNo());
+ JobPostingGroup.Validate("Job Sales Adjustment Account", LibraryERM.CreateGLAccountNo());
+ JobPostingGroup.Validate("WIP Accrued Sales Account", LibraryERM.CreateGLAccountNo());
+ JobPostingGroup.Validate("WIP Invoiced Sales Account", LibraryERM.CreateGLAccountNo());
+ JobPostingGroup.Validate("Job Sales Applied Account", LibraryERM.CreateGLAccountNo());
+ JobPostingGroup.Validate("Recognized Costs Account", LibraryERM.CreateGLAccountNo());
+ JobPostingGroup.Validate("Recognized Sales Account", LibraryERM.CreateGLAccountNo());
+ JobPostingGroup.Validate("Item Costs Applied Account", LibraryERM.CreateGLAccountNo());
+ JobPostingGroup.Validate("Resource Costs Applied Account", LibraryERM.CreateGLAccountNo());
+ JobPostingGroup.Validate("G/L Costs Applied Account", LibraryERM.CreateGLAccountNo());
+ JobPostingGroup.Insert(true);
+ end;
+
+ procedure GetJobJournalTemplate(var JobJournalTemplate: Record "Job Journal Template"): Code[10]
+ begin
+ Clear(JobJournalTemplate);
+ if not JobJournalTemplate.Get(PrefixTxt + TemplateNameTxt) then begin
+ JobJournalTemplate.Validate(Name, PrefixTxt + TemplateNameTxt);
+ JobJournalTemplate.Insert(true)
+ end;
+
+ JobJournalTemplate.Validate("No. Series", GetJobTestNoSeries());
+ JobJournalTemplate.Modify(true);
+ exit(JobJournalTemplate.Name)
+ end;
+
+ procedure DeleteJobJournalTemplate()
+ var
+ JobJournalTemplate: Record "Job Journal Template";
+ begin
+ if JobJournalTemplate.Get(PrefixTxt + TemplateNameTxt) then
+ JobJournalTemplate.Delete(true);
+ end;
+
+ procedure CreateJobGLJournalLine(JobLineType: Enum "Job Line Type"; JobTask: Record "Job Task"; var GenJournalLine: Record "Gen. Journal Line")
+ var
+ GenJournalTemplate: Record "Gen. Journal Template";
+ GenJournalBatch: Record "Gen. Journal Batch";
+ GLAccount: Record "G/L Account";
+ NoSeries: Codeunit "No. Series";
+ begin
+ // Create a general journal line for a job task.
+ // This helper function allows to easily create multiple journal lines in a single batch.
+ // These journal lines can be traced using their document number and batch.
+ LibraryERM.CreateGLAccount(GLAccount);
+ GenJournalLine.SetRange("Job No.", JobTask."Job No.");
+ if GenJournalLine.FindLast() then
+ GenJournalLine.Validate("Line No.", GenJournalLine."Line No." + 1)
+ else begin
+ Clear(GenJournalLine);
+ CreateGenJournalBatch(GetGenJournalTemplate(GenJournalTemplate), GenJournalBatch);
+ GenJournalLine.Validate("Journal Template Name", GenJournalTemplate.Name);
+ GenJournalLine.Validate("Journal Batch Name", GenJournalBatch.Name);
+ GenJournalLine.Validate("Line No.", 1);
+ GenJournalLine.SetRange("Journal Template Name", GenJournalLine."Journal Template Name");
+ GenJournalLine.SetRange("Journal Batch Name", GenJournalLine."Journal Batch Name");
+ end;
+
+ GenJournalLine.Init();
+ GenJournalLine.Insert(true);
+
+ GenJournalLine.Validate("Posting Date", WorkDate());
+ GenJournalLine.Validate("Account Type", GenJournalLine."Account Type"::"G/L Account");
+ GenJournalLine.Validate("Account No.", GLAccount."No.");
+ GenJournalLine.Validate(Description, GLAccount."No.");
+ LibraryERM.CreateGLAccount(GLAccount);
+ GenJournalLine.Validate("Bal. Account No.", GLAccount."No.");
+ GenJournalLine.Validate(Amount, LibraryRandom.RandDec(100, 2));
+ GenJournalLine.Validate("Job Line Type", JobLineType);
+ GenJournalLine.Validate("Job No.", JobTask."Job No.");
+ GenJournalLine.Validate("Job Task No.", JobTask."Job Task No.");
+ GenJournalLine.Validate("Job Quantity", LibraryRandom.RandInt(10));
+ GenJournalBatch.Get(GetGenJournalTemplate(GenJournalTemplate), GenJournalLine."Journal Batch Name");
+ GenJournalLine.Validate("Document No.", NoSeries.PeekNextNo(GenJournalBatch."No. Series", GenJournalLine."Posting Date"));
+ GenJournalLine.Validate("Source Code", GenJournalTemplate."Source Code");
+ GenJournalLine.Modify(true)
+ end;
+
+ procedure CreateGenJournalBatch(GenJournalTemplateName: Code[10]; var GenJournalBatch: Record "Gen. Journal Batch")
+ var
+ GLEntry: Record "G/L Entry";
+ JobLedgerEntry: Record "Job Ledger Entry";
+ BatchName: Code[10];
+ begin
+ Clear(GenJournalBatch);
+
+ // Find a unique name (wrt existing and previously posted batches)
+ BatchName := PrefixTxt + 'B000';
+ repeat
+ BatchName := IncStr(BatchName);
+ GLEntry.SetRange("Journal Batch Name", BatchName);
+ JobLedgerEntry.SetRange("Journal Batch Name", BatchName);
+ until GLEntry.IsEmpty() and JobLedgerEntry.IsEmpty() and not GenJournalBatch.Get(GenJournalTemplateName, BatchName);
+
+ GenJournalBatch.Validate("Journal Template Name", GenJournalTemplateName);
+ GenJournalBatch.Validate(Name, BatchName);
+ GenJournalBatch.SetupNewBatch();
+ GenJournalBatch.Insert(true)
+ end;
+
+ procedure GetGenJournalTemplate(var GenJournalTemplate: Record "Gen. Journal Template"): Code[10]
+ var
+ SourceCode: Record "Source Code";
+ begin
+ // In this test codeunit we always use the same gen. journal template
+
+ Clear(GenJournalTemplate);
+ if not GenJournalTemplate.Get(PrefixTxt + TemplateNameTxt) then begin
+ GenJournalTemplate.Validate(Name, PrefixTxt + TemplateNameTxt);
+ GenJournalTemplate.Insert(true)
+ end;
+
+ LibraryERM.CreateSourceCode(SourceCode);
+ GenJournalTemplate.Validate("Source Code", SourceCode.Code);
+ GenJournalTemplate.Validate("No. Series", GetJobTestNoSeries());
+ GenJournalTemplate.Modify(true);
+
+ exit(GenJournalTemplate.Name)
+ end;
+
+ procedure GetJobTestNoSeries(): Code[20]
+ var
+ NoSeries: Record "No. Series";
+ NoSeriesLine: Record "No. Series Line";
+ begin
+ if not NoSeries.Get(NoSeriesCodeTxt) then begin
+ LibraryUtility.CreateNoSeries(NoSeriesCodeTxt, true, false, false);
+ LibraryUtility.CreateNoSeriesLine(NoSeriesLine, NoSeriesCodeTxt, '', '')
+ end;
+
+ exit(NoSeriesCodeTxt)
+ end;
+
+ procedure SetJobNoSeriesCode()
+ var
+ JobsSetup: Record "Jobs Setup";
+ NoSeriesLine: Record "No. Series Line";
+ begin
+ JobsSetup.Get();
+ if JobsSetup."Job Nos." = '' then begin
+ LibraryUtility.CreateNoSeries(JobNosTok, true, true, false);
+ LibraryUtility.CreateNoSeriesLine(NoSeriesLine, JobNosTok, 'J0000001', 'J9999991');
+ JobsSetup.Validate("Job Nos.", JobNosTok);
+ JobsSetup.Modify(true);
+ end;
+ end;
+
+ procedure CreateConsumable(Type: Enum "Job Planning Line Type"): Code[20]
+ var
+ Item: Record Item;
+ ItemUnitOfMeasure: Record "Item Unit of Measure";
+ Resource: Record Resource;
+ ResourceUnitOfMeasure: Record "Resource Unit of Measure";
+ GLAccount: Record "G/L Account";
+ begin
+ case Type of
+ "Job Planning Line Type"::Resource:
+ begin
+ Resource.Get(FindConsumable(Type));
+ ResourceUnitOfMeasure.Get(Resource."No.", Resource."Base Unit of Measure");
+ Resource."No." := '';
+ Resource.Insert(true);
+ ResourceUnitOfMeasure."Resource No." := Resource."No.";
+ ResourceUnitOfMeasure.Insert(true);
+ exit(Resource."No.")
+ end;
+ "Job Planning Line Type"::Item:
+ begin
+ Item.Get(FindConsumable(Type));
+ ItemUnitOfMeasure.Get(Item."No.", Item."Base Unit of Measure");
+ Item."No." := '';
+ Item.Insert(true);
+ ItemUnitOfMeasure."Item No." := Item."No.";
+ ItemUnitOfMeasure.Insert(true);
+ exit(Item."No.")
+ end;
+ GLAccountType():
+ begin
+ GLAccount.Get(FindConsumable(Type));
+ GLAccount."No." := '';
+ GLAccount.Insert(true);
+ exit(GLAccount."No.")
+ end;
+ else
+ Assert.Fail('Unsupported consumable type');
+ end
+ end;
+
+ procedure Attach2PurchaseLine(ConsumableType: Enum "Purchase Line Type"; var PurchaseLine: Record "Purchase Line")
+ begin
+ // Attach a random number of random consumables to the purchase line.
+ PurchaseLine.Validate(Type, ConsumableType);
+ PurchaseLine.Validate("No.", FindConsumable(Purchase2JobConsumableType(ConsumableType)));
+ PurchaseLine.Validate(Quantity, LibraryRandom.RandInt(100));
+ if PurchaseLine.Type = PurchaseLine.Type::"G/L Account" then
+ PurchaseLine.Validate("Direct Unit Cost", LibraryRandom.RandInt(100));
+ PurchaseLine.Modify(true)
+ end;
+
+ local procedure Attach2JobJournalLine(ConsumableType: Enum "Job Planning Line Type"; var JobJournalLine: Record "Job Journal Line")
+ begin
+ // Attach a random number of random consumables to the job journal line.
+ JobJournalLine.Validate(Type, ConsumableType);
+ JobJournalLine.Validate("No.", FindConsumable(ConsumableType));
+ JobJournalLine.Validate(Quantity, LibraryRandom.RandInt(100));
+ if JobJournalLine.Type = JobJournalLine.Type::"G/L Account" then
+ JobJournalLine.Validate("Unit Price", LibraryRandom.RandInt(100));
+ JobJournalLine.Modify(true)
+ end;
+
+ procedure AttachJobTask2PurchaseLine(JobTask: Record "Job Task"; var PurchaseLine: Record "Purchase Line")
+ begin
+ // Attach the job task to the purchase line.
+ PurchaseLine.Validate("Job No.", JobTask."Job No.");
+ PurchaseLine.Validate("Job Task No.", JobTask."Job Task No.");
+ PurchaseLine.Modify(true)
+ end;
+
+ local procedure CreateCustomer(): Code[20]
+ var
+ Customer: Record Customer;
+ begin
+ LibrarySales.CreateCustomer(Customer);
+ exit(Customer."No.")
+ end;
+
+ procedure FindConsumable(Type: Enum "Job Planning Line Type"): Code[20]
+ begin
+ case Type of
+ "Job Planning Line Type"::Resource:
+ exit(LibraryResource.CreateResourceNo());
+ "Job Planning Line Type"::Item:
+ exit(FindItem());
+ "Job Planning Line Type"::"G/L Account":
+ exit(LibraryERM.CreateGLAccountWithSalesSetup());
+ else
+ Error(ErrorMsg);
+ end
+ end;
+
+ procedure FindItem(): Code[20]
+ var
+ Item: Record Item;
+ begin
+ LibraryInventory.CreateItem(Item);
+ Item.Validate("Unit Price", LibraryRandom.RandDec(100, 2));
+ Item.Validate("Unit Cost", LibraryRandom.RandDec(100, 2));
+ Item.Modify(true);
+ exit(Item."No.");
+ end;
+
+ procedure FindJobPostingGroup(): Code[20]
+ var
+ JobPostingGroup: Record "Job Posting Group";
+ begin
+ if not JobPostingGroup.FindFirst() then
+ CreateJobPostingGroup(JobPostingGroup);
+ exit(JobPostingGroup.Code);
+ end;
+
+ procedure UseJobPlanningLine(JobPlanningLine: Record "Job Planning Line"; UsageLineType: Enum "Job Line Type"; Fraction: Decimal; var JobJournalLine: Record "Job Journal Line")
+ begin
+ CreateJobJournalLineForPlan(JobPlanningLine, UsageLineType, Fraction, JobJournalLine);
+ PostJobJournal(JobJournalLine)
+ end;
+
+ procedure UseJobPlanningLineExplicit(JobPlanningLine: Record "Job Planning Line"; UsageLineType: Enum "Job Line Type"; Fraction: Decimal; Source: Option; var JobJournalLine: Record "Job Journal Line")
+ var
+ PurchaseHeader: Record "Purchase Header";
+ PurchaseLine: Record "Purchase Line";
+ GenJournalLine: Record "Gen. Journal Line";
+ begin
+ case Source of
+ JobConsumption():
+ begin
+ CreateJobJournalLineForPlan(JobPlanningLine, UsageLineType, Fraction, JobJournalLine);
+ JobJournalLine.Validate("Job Planning Line No.", JobPlanningLine."Line No.");
+ JobJournalLine.Modify(true);
+ PostJobJournal(JobJournalLine)
+ end;
+ GenJournalConsumption():
+ begin
+ Assert.AreEqual(GLAccountType(), JobPlanningLine.Type, 'Can only consume G/L Account via Job Gen. Journal.');
+ CreateGenJournalLineForPlan(JobPlanningLine, UsageLineType, Fraction, GenJournalLine);
+ LibraryERM.PostGeneralJnlLine(GenJournalLine);
+ JobJournalLine."Line Type" := GenJournalLine."Job Line Type";
+ JobJournalLine."Remaining Qty." := GenJournalLine."Job Remaining Qty.";
+ JobJournalLine.Quantity := GenJournalLine."Job Quantity";
+ JobJournalLine.Description := GenJournalLine.Description;
+ JobJournalLine."Total Cost" := GenJournalLine."Job Total Cost";
+ JobJournalLine."Total Cost (LCY)" := GenJournalLine."Job Total Cost (LCY)";
+ JobJournalLine."Line Amount" := GenJournalLine."Job Line Amount";
+ end;
+ PurchaseConsumption():
+ begin
+ CreatePurchaseLineForPlan(JobPlanningLine, UsageLineType, Fraction, PurchaseLine);
+ PurchaseHeader.Get(PurchaseLine."Document Type", PurchaseLine."Document No.");
+ LibraryPurchase.PostPurchaseDocument(PurchaseHeader, true, true);
+ JobJournalLine."Line Type" := PurchaseLine."Job Line Type";
+ JobJournalLine."Remaining Qty." := PurchaseLine."Job Remaining Qty.";
+ JobJournalLine.Quantity := PurchaseLine."Qty. to Invoice";
+ JobJournalLine.Description := PurchaseLine.Description;
+ JobJournalLine."Total Cost" := PurchaseLine."Qty. to Invoice" * PurchaseLine."Unit Cost (LCY)";
+ JobJournalLine."Total Cost (LCY)" := PurchaseLine."Qty. to Invoice" * PurchaseLine."Unit Cost (LCY)";
+ JobJournalLine."Total Price" := PurchaseLine."Job Total Price";
+ JobJournalLine."Line Amount" := PurchaseLine."Job Line Amount";
+ end;
+ else
+ Assert.Fail('Consumption method not supported');
+ end
+ end;
+
+ procedure PostJobJournal(var JobJournalLine: Record "Job Journal Line")
+ var
+ JobJournalLine2: Record "Job Journal Line";
+ begin
+ // Post a job journal.
+ JobJournalLine2 := JobJournalLine;
+ CODEUNIT.Run(CODEUNIT::"Job Jnl.-Post", JobJournalLine2)
+ end;
+
+ local procedure GetGLEntry(var JobLedgerEntry: Record "Job Ledger Entry"; var GLEntry: Record "G/L Entry")
+ var
+ Item: Record Item;
+ GeneralPostingSetup: Record "General Posting Setup";
+ begin
+ GLEntry.Reset();
+ GLEntry.SetRange("Posting Date", JobLedgerEntry."Posting Date");
+ GLEntry.SetRange("Document No.", JobLedgerEntry."Document No.");
+ GLEntry.SetRange("Job No.", JobLedgerEntry."Job No.");
+
+ case JobLedgerEntry."Ledger Entry Type" of
+ JobLedgerEntry."Ledger Entry Type"::"G/L Account":
+ GLEntry.SetRange("G/L Account No.", JobLedgerEntry."No.");
+ JobLedgerEntry."Ledger Entry Type"::Item:
+ begin
+ GeneralPostingSetup.Get(JobLedgerEntry."Gen. Bus. Posting Group", JobLedgerEntry."Gen. Prod. Posting Group");
+ Item.Get(JobLedgerEntry."No.");
+ GLEntry.SetRange("Gen. Prod. Posting Group", JobLedgerEntry."Gen. Prod. Posting Group");
+ GLEntry.SetRange("Gen. Bus. Posting Group", JobLedgerEntry."Gen. Bus. Posting Group");
+ GLEntry.SetRange("VAT Prod. Posting Group", Item."VAT Prod. Posting Group");
+ GLEntry.SetRange("G/L Account No.", GeneralPostingSetup."Purch. Account");
+ end;
+ else
+ Assert.Fail(StrSubstNo('Unsupported entry type: %1', JobLedgerEntry."Ledger Entry Type"));
+ end;
+
+ GLEntry.FindFirst();
+ end;
+
+ procedure VerifyGLEntries(var JobLedgerEntry: Record "Job Ledger Entry")
+ var
+ GLEntry: Record "G/L Entry";
+ begin
+ // Verify that each job entry has corresponding g/l entry with a job no.
+ JobLedgerEntry.FindSet();
+ repeat
+ GetGLEntry(JobLedgerEntry, GLEntry);
+ Assert.AreEqual(JobLedgerEntry."Job No.", GLEntry."Job No.", JobNoErr);
+ until JobLedgerEntry.Next() = 0
+ end;
+
+ procedure VerifyPurchaseDocPostingForJob(var PurchaseLine: Record "Purchase Line")
+ var
+ TempJobJournalLine: Record "Job Journal Line" temporary;
+ Job: Record Job;
+ begin
+ // Verify posting of a purchase line for a job.
+ PurchaseLine.SetFilter("Job No.", '<>''''');
+ PurchaseLine.FindSet();
+ Job.Get(PurchaseLine."Job No.");
+
+ repeat
+ TempJobJournalLine."Line No." := PurchaseLine."Line No.";
+ TempJobJournalLine."Job No." := PurchaseLine."Job No.";
+ TempJobJournalLine."Job Task No." := PurchaseLine."Job Task No.";
+ TempJobJournalLine.Description := PurchaseLine.Description;
+ TempJobJournalLine."Line Type" := PurchaseLine."Job Line Type";
+ TempJobJournalLine.Quantity := PurchaseLine.Quantity;
+ TempJobJournalLine."Unit Cost (LCY)" := PurchaseLine."Unit Cost (LCY)";
+ TempJobJournalLine."Unit Price (LCY)" := PurchaseLine."Unit Price (LCY)";
+ TempJobJournalLine."Currency Code" := Job."Currency Code";
+ TempJobJournalLine.Insert();
+ until PurchaseLine.Next() = 0;
+
+ VerifyJobJournalPosting(false, TempJobJournalLine)
+ end;
+
+ procedure VerifyJobJournalPosting(UsageLink: Boolean; var JobJournalLine: Record "Job Journal Line")
+ begin
+ // Verify that the journal lines were posted correctly.
+
+ Assert.IsFalse(JobJournalLine.IsEmpty, 'Not verifying any Job Journal Lines!');
+ JobJournalLine.FindSet();
+ repeat
+ VerifyJobLedger(JobJournalLine);
+ VerifyPlanningLines(JobJournalLine, UsageLink)
+ until JobJournalLine.Next() = 0
+ end;
+
+ procedure VerifyJobLedger(JobJournalLine: Record "Job Journal Line")
+ var
+ JobLedgerEntry: Record "Job Ledger Entry";
+ Precision: Decimal;
+ begin
+ // A posted job journal line gives one corresponding entry in the job ledger.
+ JobLedgerEntry.SetRange(Description, JobJournalLine.Description);
+
+ Assert.AreEqual(
+ 1, JobLedgerEntry.Count(),
+ StrSubstNo('Invalid Job Ledger Entry for Batch %1 Document %2', JobJournalLine."Journal Batch Name", JobJournalLine."Document No."));
+
+ JobLedgerEntry.FindFirst();
+ Precision := max(GetAmountRoundingPrecision(''), GetAmountRoundingPrecision(JobJournalLine."Currency Code"));
+ Assert.AreEqual(JobJournalLine."Job No.", JobLedgerEntry."Job No.", JobLedgerEntry.FieldCaption("Job No."));
+ Assert.AreEqual(JobJournalLine."Job Task No.", JobLedgerEntry."Job Task No.", JobLedgerEntry.FieldCaption("Job Task No."));
+ Assert.AreNearlyEqual(JobJournalLine."Unit Cost (LCY)", JobLedgerEntry."Unit Cost (LCY)", Precision * 10, JobLedgerEntry.FieldCaption("Unit Cost (LCY)"));
+ Assert.AreNearlyEqual(JobJournalLine."Unit Price (LCY)", JobLedgerEntry."Unit Price (LCY)", Precision, JobLedgerEntry.FieldCaption("Unit Price (LCY)"));
+ Assert.AreEqual(JobJournalLine.Quantity, JobLedgerEntry.Quantity, JobLedgerEntry.FieldCaption(Quantity));
+ end;
+
+ procedure VerifyPlanningLines(JobJournalLine: Record "Job Journal Line"; UsageLink: Boolean)
+ var
+ JobPlanningLine: Record "Job Planning Line";
+ Precision: Decimal;
+ begin
+ // A posted job journal line gives
+ // 0 (Blank),
+ // 1 (Contract or Schedule), or
+ // 2 (Both)
+ // corresponding planning lines.
+ JobPlanningLine.SetRange(Description, JobJournalLine.Description);
+ // Verify line count and type
+ case JobJournalLine."Line Type" of
+ UsageLineTypeBlank():
+ VerifyPlanningLineCountBlank(JobJournalLine, UsageLink);
+ UsageLineTypeSchedule():
+ VerifyPlanningLineCountSchedul(JobJournalLine);
+ UsageLineTypeContract():
+ VerifyPlanningLineCountContrac(JobJournalLine, UsageLink);
+ UsageLineTypeBoth():
+ VerifyPlanningLineCountBoth(JobJournalLine);
+ else
+ Assert.Fail('Invalid line type.');
+ end;
+ // Verify Unit Cost, Price.
+ Precision := max(GetAmountRoundingPrecision(''), GetAmountRoundingPrecision(JobJournalLine."Currency Code"));
+ if JobPlanningLine.FindSet() then
+ repeat
+ Assert.AreEqual(JobJournalLine.Quantity, JobPlanningLine.Quantity, JobPlanningLine.FieldCaption(Quantity));
+ Assert.AreEqual(JobJournalLine."Job No.", JobPlanningLine."Job No.", JobPlanningLine.FieldCaption("Job No."));
+ Assert.AreEqual(JobJournalLine."Job Task No.", JobPlanningLine."Job Task No.", JobPlanningLine.FieldCaption("Job Task No."));
+ Assert.AreNearlyEqual(JobJournalLine."Unit Cost (LCY)", JobPlanningLine."Unit Cost (LCY)", Precision * 10, JobPlanningLine.FieldCaption("Unit Cost (LCY)"));
+ Assert.AreNearlyEqual(JobJournalLine."Unit Price (LCY)", JobPlanningLine."Unit Price (LCY)", Precision, JobPlanningLine.FieldCaption("Unit Price (LCY)"))
+ until JobPlanningLine.Next() = 0
+ end;
+
+ local procedure VerifyPlanningLineCountBlank(JobJournalLine: Record "Job Journal Line"; UsageLink: Boolean)
+ var
+ JobPlanningLine: Record "Job Planning Line";
+ Job: Record Job;
+ begin
+ JobPlanningLine.SetRange(Description, JobJournalLine.Description);
+ Job.Get(JobJournalLine."Job No.");
+ if UsageLink then begin
+ Assert.AreEqual(1, JobPlanningLine.Count, StrSubstNo('# planning lines for Line Type %1.', JobJournalLine."Line Type"));
+ JobPlanningLine.FindFirst();
+ Assert.AreEqual(PlanningLineTypeSchedule(), JobPlanningLine."Line Type", JobPlanningLine.FieldCaption("Line Type"))
+ end else
+ Assert.IsTrue(JobPlanningLine.IsEmpty, StrSubstNo('No planning lines should be created for %1.', JobJournalLine."Line Type"));
+ end;
+
+ local procedure VerifyPlanningLineCountSchedul(JobJournalLine: Record "Job Journal Line")
+ var
+ JobPlanningLine: Record "Job Planning Line";
+ begin
+ JobPlanningLine.SetRange(Description, JobJournalLine.Description);
+ Assert.AreEqual(1, JobPlanningLine.Count, StrSubstNo('# planning lines for Line Type %1.', JobJournalLine."Line Type"));
+ JobPlanningLine.FindFirst();
+ Assert.AreEqual(PlanningLineTypeSchedule(), JobPlanningLine."Line Type", JobPlanningLine.FieldCaption("Line Type"))
+ end;
+
+ local procedure VerifyPlanningLineCountContrac(JobJournalLine: Record "Job Journal Line"; UsageLink: Boolean)
+ var
+ Job: Record Job;
+ JobPlanningLine: Record "Job Planning Line";
+ begin
+ JobPlanningLine.SetRange(Description, JobJournalLine.Description);
+ if UsageLink then begin
+ Job.Get(JobJournalLine."Job No.");
+ if Job."Allow Schedule/Contract Lines" then begin
+ Assert.AreEqual(1, JobPlanningLine.Count, StrSubstNo('# planning lines for Line Type %1.', JobJournalLine."Line Type"));
+ JobPlanningLine.FindFirst();
+ Assert.AreEqual(PlanningLineTypeBoth(), JobPlanningLine."Line Type", JobPlanningLine.FieldCaption("Line Type"))
+ end else begin
+ Assert.AreEqual(2, JobPlanningLine.Count, StrSubstNo('# planning lines for Line Type %1.', JobJournalLine."Line Type"));
+ JobPlanningLine.SetRange("Line Type", PlanningLineTypeSchedule());
+ Assert.AreEqual(1, JobPlanningLine.Count, StrSubstNo('# schedule planning line for Line Type %1.', JobJournalLine."Line Type"));
+ JobPlanningLine.SetRange("Line Type", PlanningLineTypeContract());
+ Assert.AreEqual(1, JobPlanningLine.Count, StrSubstNo('# contract planning lines for Line Type %1.', JobJournalLine."Line Type"))
+ end
+ end else begin
+ Assert.AreEqual(1, JobPlanningLine.Count, StrSubstNo('# planning lines for Line Type %1.', JobJournalLine."Line Type"));
+ JobPlanningLine.FindFirst();
+ Assert.AreEqual(PlanningLineTypeContract(), JobPlanningLine."Line Type", JobPlanningLine.FieldCaption("Line Type"))
+ end
+ end;
+
+ local procedure VerifyPlanningLineCountBoth(JobJournalLine: Record "Job Journal Line")
+ var
+ Job: Record Job;
+ JobPlanningLine: Record "Job Planning Line";
+ begin
+ JobPlanningLine.SetRange(Description, JobJournalLine.Description);
+ Job.Get(JobJournalLine."Job No.");
+ if Job."Allow Schedule/Contract Lines" then begin
+ Assert.AreEqual(1, JobPlanningLine.Count, StrSubstNo('# planning lines for Line Type %1.', JobJournalLine."Line Type"));
+ JobPlanningLine.FindFirst();
+ Assert.AreEqual(PlanningLineTypeBoth(), JobPlanningLine."Line Type", JobPlanningLine.FieldCaption("Line Type"))
+ end else begin
+ Assert.AreEqual(2, JobPlanningLine.Count, StrSubstNo('# planning lines for Line Type %1.', JobJournalLine."Line Type"));
+ JobPlanningLine.SetRange("Line Type", PlanningLineTypeSchedule());
+ Assert.AreEqual(1, JobPlanningLine.Count, StrSubstNo('# schedule planning line for Line Type %1.', JobJournalLine."Line Type"));
+ JobPlanningLine.SetRange("Line Type", PlanningLineTypeContract());
+ Assert.AreEqual(1, JobPlanningLine.Count, StrSubstNo('# contract planning lines for Line Type %1.', JobJournalLine."Line Type"))
+ end
+ end;
+
+ procedure UpdateJobPostingGroup(var JobPostingGroup: Record "Job Posting Group")
+ var
+ GLAccount: Record "G/L Account";
+ begin
+ LibraryERM.CreateGLAccount(GLAccount);
+ JobPostingGroup.Validate("WIP Costs Account", GLAccount."No.");
+ JobPostingGroup.Validate("WIP Invoiced Sales Account", GLAccount."No.");
+ JobPostingGroup.Validate("WIP Accrued Costs Account", GLAccount."No.");
+ JobPostingGroup.Validate("WIP Accrued Sales Account", GLAccount."No.");
+ JobPostingGroup.Validate("Job Costs Applied Account", GLAccount."No.");
+ JobPostingGroup.Validate("Job Costs Adjustment Account", GLAccount."No.");
+ JobPostingGroup.Validate("Job Sales Applied Account", GLAccount."No.");
+ JobPostingGroup.Validate("Job Sales Adjustment Account", GLAccount."No.");
+ JobPostingGroup.Validate("Resource Costs Applied Account", GLAccount."No.");
+ JobPostingGroup.Validate("Recognized Costs Account", GLAccount."No.");
+ JobPostingGroup.Validate("Recognized Sales Account", GLAccount."No.");
+ JobPostingGroup.Validate("G/L Costs Applied Account", GLAccount."No.");
+ JobPostingGroup.Modify(true);
+ end;
+
+ procedure ConfigureGeneralPosting()
+ var
+ GeneralPostingSetup: Record "General Posting Setup";
+ GenProductPostingGroup: Record "Gen. Product Posting Group";
+ GenBusinessPostingGroup: Record "Gen. Business Posting Group";
+ RecordRef: RecordRef;
+ GenBusinessPostingGroupCode: Code[20];
+ begin
+ // create a posting setup for each combination of product and business group
+ // including "empty" business group (in the first iteration)
+
+ repeat
+ GenBusinessPostingGroupCode := GenBusinessPostingGroup.Code;
+ GenProductPostingGroup.FindSet();
+ repeat
+ if not GeneralPostingSetup.Get(GenBusinessPostingGroupCode, GenProductPostingGroup.Code) then
+ CreateGeneralPostingSetup(GenBusinessPostingGroupCode, GenProductPostingGroup.Code, GeneralPostingSetup);
+
+ RecordRef.GetTable(GeneralPostingSetup);
+ // general posting => income statement
+ SetIncomeStatementGLAccounts(RecordRef);
+ until GenProductPostingGroup.Next() = 0;
+ until GenBusinessPostingGroup.Next() = 0;
+ end;
+
+ procedure CreateGeneralPostingSetup(GenBusinessPostingGroupCode: Code[20]; GenProductPostingGroupCode: Code[20]; var GeneralPostingSetup: Record "General Posting Setup")
+ begin
+ GeneralPostingSetup."Gen. Bus. Posting Group" := GenBusinessPostingGroupCode;
+ GeneralPostingSetup."Gen. Prod. Posting Group" := GenProductPostingGroupCode;
+ GeneralPostingSetup.Init();
+ GeneralPostingSetup.Insert(true);
+ end;
+
+ procedure ConfigureVATPosting()
+ var
+ VATPostingSetup: Record "VAT Posting Setup";
+ VATProductPostingGroup: Record "VAT Product Posting Group";
+ VATBusinessPostingGroup: Record "VAT Business Posting Group";
+ RecordRef: RecordRef;
+ VATBusinessPostingGroupCode: Code[20];
+ VATProductPostingGroupCode: Code[20];
+ begin
+ // create a posting setup for each combination of product and business group
+ // including "empty" business and product group combinations
+
+ repeat
+ VATBusinessPostingGroupCode := VATBusinessPostingGroup.Code;
+ Clear(VATProductPostingGroup);
+ repeat
+ VATProductPostingGroupCode := VATProductPostingGroup.Code;
+ if not VATPostingSetup.Get(VATBusinessPostingGroupCode, VATProductPostingGroupCode) then
+ CreateVATPostingSetup(VATBusinessPostingGroupCode, VATProductPostingGroupCode, VATPostingSetup);
+
+ RecordRef.GetTable(VATPostingSetup);
+ // VAT posting => income statement
+ SetIncomeStatementGLAccounts(RecordRef);
+ until VATProductPostingGroup.Next() = 0;
+ until VATBusinessPostingGroup.Next() = 0;
+ end;
+
+ procedure CreateVATPostingSetup(VATBusinessPostingGroupCode: Code[20]; VATProductPostingGroupCode: Code[20]; var VATPostingSetup: Record "VAT Posting Setup")
+ begin
+ VATPostingSetup."VAT Bus. Posting Group" := VATBusinessPostingGroupCode;
+ VATPostingSetup."VAT Prod. Posting Group" := VATProductPostingGroupCode;
+ VATPostingSetup.Init();
+ VATPostingSetup."VAT %" := LibraryRandom.RandIntInRange(10, 25);
+ // 10 <= VAT % <= 25
+ VATPostingSetup."VAT Identifier" := Format(VATPostingSetup."VAT %");
+ VATPostingSetup."Sales VAT Account" := LibraryERM.CreateGLAccountWithSalesSetup();
+ VATPostingSetup."Sales VAT Unreal. Account" := VATPostingSetup."Sales VAT Account";
+ VATPostingSetup."Purchase VAT Account" := VATPostingSetup."Sales VAT Account";
+ VATPostingSetup."Purch. VAT Unreal. Account" := VATPostingSetup."Sales VAT Account";
+ VATPostingSetup.Insert(true);
+ end;
+
+ procedure SetAutomaticUpdateJobItemCost(IsEnabled: Boolean)
+ var
+ JobsSetup: Record "Jobs Setup";
+ begin
+ JobsSetup.Get();
+ JobsSetup.Validate("Automatic Update Job Item Cost", IsEnabled);
+ JobsSetup.Modify(true);
+ end;
+
+ procedure SetIncomeStatementGLAccounts(RecordRef: RecordRef)
+ var
+ GLAccount: Record "G/L Account";
+ FieldRef: FieldRef;
+ Idx: Integer;
+ begin
+ // Set all GLAccount fields in RecordRef to a (different) account
+ for Idx := 1 to RecordRef.FieldCount do begin
+ FieldRef := RecordRef.FieldIndex(Idx);
+ if FieldRef.Relation = DATABASE::"G/L Account" then begin
+ GLAccount.Get(LibraryERM.CreateGLAccountWithSalesSetup());
+ GLAccount."Income/Balance" := GLAccount."Income/Balance"::"Income Statement";
+ GLAccount.Modify(true);
+ FieldRef.Value := GLAccount."No.";
+ FieldRef.TestField();
+ RecordRef.Modify();
+ end
+ end
+ end;
+
+ procedure GetNextLineNo(JobPlanningLine: Record "Job Planning Line"): Integer
+ begin
+ JobPlanningLine.Reset();
+ JobPlanningLine.SetRange("Job No.", JobPlanningLine."Job No.");
+ JobPlanningLine.SetRange("Job Task No.", JobPlanningLine."Job Task No.");
+ if JobPlanningLine.FindLast() then
+ exit(JobPlanningLine."Line No." + 10000);
+ exit(10000)
+ end;
+
+ local procedure IsStandardCosting(Type: Enum "Job Planning Line Type"; No: Code[20]): Boolean
+ var
+ Item: Record Item;
+ begin
+ if Type <> "Job Planning Line Type"::Item then
+ exit(false);
+
+ Item.Get(No);
+ exit(Item."Costing Method" = Item."Costing Method"::Standard)
+ end;
+
+ procedure Service2JobConsumableType(Type: Enum "Service Line Type"): Enum "Job Planning Line Type"
+ var
+ ServiceLine: Record "Service Line";
+ begin
+ case Type of
+ ServiceLine.Type::Item:
+ exit("Job Planning Line Type"::Item);
+ ServiceLine.Type::Resource:
+ exit("Job Planning Line Type"::Resource);
+ ServiceLine.Type::"G/L Account":
+ exit("Job Planning Line Type"::"G/L Account");
+ else
+ Assert.Fail('Unsupported consumable type');
+ end
+ end;
+
+ procedure Purchase2JobConsumableType(Type: Enum "Purchase Line Type"): Enum "Job Planning Line Type"
+ var
+ PurchaseLine: Record "Purchase Line";
+ begin
+ case Type of
+ PurchaseLine.Type::Item:
+ exit("Job Planning Line Type"::Item);
+ PurchaseLine.Type::"G/L Account":
+ exit("Job Planning Line Type"::"G/L Account");
+ else
+ Assert.Fail('Unsupported consumable type');
+ end
+ end;
+
+ procedure Job2PurchaseConsumableType(Type: Enum "Job Planning Line Type"): Enum "Purchase Line Type"
+ var
+ PurchaseLine: Record "Purchase Line";
+ begin
+ case Type of
+ "Job Planning Line Type"::Item:
+ exit(PurchaseLine.Type::Item);
+ "Job Planning Line Type"::"G/L Account":
+ exit(PurchaseLine.Type::"G/L Account");
+ else
+ Assert.Fail('Unsupported consumable type');
+ end
+ end;
+
+ procedure Job2SalesConsumableType(Type: Enum "Job Planning Line Type"): Enum "Sales Line Type"
+ var
+ SalesLine: Record "Sales Line";
+ begin
+ case Type of
+ "Job Planning Line Type"::Resource:
+ exit(SalesLine.Type::Resource);
+ "Job Planning Line Type"::Item:
+ exit(SalesLine.Type::Item);
+ "Job Planning Line Type"::"G/L Account":
+ exit(SalesLine.Type::"G/L Account");
+ else
+ Assert.Fail('Unsupported consumable type');
+ end
+ end;
+
+#if not CLEAN27
+ [Obsolete('Moved to codeunit Library Service', '27.0')]
+ procedure Job2ServiceConsumableType(Type: Enum "Job Planning Line Type"): Enum "Service Line Type"
+ var
+ LibraryService: Codeunit "Library - Service";
+ begin
+ exit(LibraryService.Job2ServiceConsumableType(Type));
+ end;
+#endif
+
+ procedure GetUnitAmountRoundingPrecision(CurrencyCode: Code[10]): Decimal
+ var
+ Currency: Record Currency;
+ begin
+ if CurrencyCode = '' then
+ exit(LibraryERM.GetUnitAmountRoundingPrecision());
+ Currency.Get(CurrencyCode);
+ exit(Currency."Unit-Amount Rounding Precision")
+ end;
+
+ procedure GetAmountRoundingPrecision(CurrencyCode: Code[10]): Decimal
+ var
+ Currency: Record Currency;
+ begin
+ if CurrencyCode = '' then
+ exit(LibraryERM.GetAmountRoundingPrecision());
+ Currency.Get(CurrencyCode);
+ exit(Currency."Amount Rounding Precision")
+ end;
+
+ procedure CopyPurchaseLines(var FromPurchaseLine: Record "Purchase Line"; var ToPurchaseLine: Record "Purchase Line")
+ begin
+ FromPurchaseLine.FindSet();
+ repeat
+ ToPurchaseLine := FromPurchaseLine;
+ ToPurchaseLine.Insert();
+ until FromPurchaseLine.Next() = 0
+ end;
+
+ procedure CopyJobJournalLines(var FromJobJournalLine: Record "Job Journal Line"; var ToJobJournalLine: Record "Job Journal Line")
+ begin
+ FromJobJournalLine.FindSet();
+ repeat
+ ToJobJournalLine := FromJobJournalLine;
+ ToJobJournalLine.Insert(true);
+ until FromJobJournalLine.Next() = 0;
+ ToJobJournalLine.CopyFilters(FromJobJournalLine)
+ end;
+
+ procedure UsageLineType(PlanningLineType2: Enum "Job Planning Line Line Type"): Enum "Job Line Type"
+ begin
+ case PlanningLineType2 of
+ PlanningLineTypeSchedule():
+ exit(UsageLineTypeSchedule());
+ PlanningLineTypeContract():
+ exit(UsageLineTypeContract());
+ PlanningLineTypeBoth():
+ exit(UsageLineTypeBoth());
+ else
+ Assert.Fail(StrSubstNo('Invalid job planning line type: %1', PlanningLineType2));
+ end
+ end;
+
+ procedure UsageLineTypeBlank(): Enum "Job Line Type"
+ var
+ JobJournalLine: Record "Job Journal Line";
+ begin
+ exit(JobJournalLine."Line Type"::" ")
+ end;
+
+ procedure UsageLineTypeSchedule(): Enum "Job Line Type"
+ var
+ JobJournalLine: Record "Job Journal Line";
+ begin
+ exit(JobJournalLine."Line Type"::Budget)
+ end;
+
+ procedure UsageLineTypeContract(): Enum "Job Line Type"
+ var
+ JobJournalLine: Record "Job Journal Line";
+ begin
+ exit(JobJournalLine."Line Type"::Billable)
+ end;
+
+ procedure UsageLineTypeBoth(): Enum "Job Line Type"
+ var
+ JobJournalLine: Record "Job Journal Line";
+ begin
+ exit(JobJournalLine."Line Type"::"Both Budget and Billable")
+ end;
+
+ procedure PlanningLineType(UsageLineType2: Enum "Job Line Type"): Enum "Job Planning Line Line Type"
+ begin
+ case UsageLineType2 of
+ UsageLineTypeSchedule():
+ exit(PlanningLineTypeSchedule());
+ UsageLineTypeContract():
+ exit(PlanningLineTypeContract());
+ UsageLineTypeBoth():
+ exit(PlanningLineTypeContract());
+ else
+ Assert.Fail(StrSubstNo('No matching job planning line type exists for job usage line type: %1', UsageLineType2));
+ end
+ end;
+
+ procedure PlanningLineTypeSchedule(): Enum "Job Planning Line Line Type"
+ var
+ JobPlanningLine: Record "Job Planning Line";
+ begin
+ exit(JobPlanningLine."Line Type"::Budget)
+ end;
+
+ procedure PlanningLineTypeContract(): Enum "Job Planning Line Line Type"
+ var
+ JobPlanningLine: Record "Job Planning Line";
+ begin
+ exit(JobPlanningLine."Line Type"::Billable)
+ end;
+
+ procedure PlanningLineTypeBoth(): Enum "Job Planning Line Line Type"
+ var
+ JobPlanningLine: Record "Job Planning Line";
+ begin
+ exit(JobPlanningLine."Line Type"::"Both Budget and Billable")
+ end;
+
+ procedure ItemType(): Enum "Job Planning Line Type"
+ var
+ JobPlanningLine: Record "Job Planning Line";
+ begin
+ exit(JobPlanningLine.Type::Item)
+ end;
+
+ procedure ResourceType(): Enum "Job Planning Line Type"
+ var
+ JobPlanningLine: Record "Job Planning Line";
+ begin
+ exit(JobPlanningLine.Type::Resource)
+ end;
+
+ procedure GLAccountType(): Enum "Job Planning Line Type"
+ var
+ JobPlanningLine: Record "Job Planning Line";
+ begin
+ exit(JobPlanningLine.Type::"G/L Account")
+ end;
+
+ procedure TextType(): Enum "Job Planning Line Type"
+ var
+ JobPlanningLine: Record "Job Planning Line";
+ begin
+ exit(JobPlanningLine.Type::Text)
+ end;
+
+ procedure "Max"(Left: Decimal; Right: Decimal): Decimal
+ begin
+ if Left > Right then
+ exit(Left);
+
+ exit(Right)
+ end;
+
+#if not CLEAN27
+ [Obsolete('Moved to codeunit Library Service', '27.0')]
+ procedure ServiceConsumption(): Integer
+ begin
+ exit(ConsumptionSource::Service)
+ end;
+#endif
+
+ procedure JobConsumption(): Integer
+ begin
+ exit(ConsumptionSource::Job)
+ end;
+
+ procedure GenJournalConsumption(): Integer
+ begin
+ exit(ConsumptionSource::GenJournal)
+ end;
+
+ procedure PurchaseConsumption(): Integer
+ begin
+ exit(ConsumptionSource::Purchase)
+ end;
+
+ procedure FindLocation(var Location: Record Location): Code[10]
+ begin
+ Location.SetRange("Use As In-Transit", false);
+ Location.SetRange("Bin Mandatory", false);
+ Location.Next(LibraryRandom.RandInt(Location.Count));
+ exit(Location.Code);
+ end;
+
+ [Normal]
+ procedure GetJobWIPMethod(var JobWIPMethod: Record "Job WIP Method"; Method: Option "Completed Contract","Cost of Sales","Cost Value",POC,"Sales Value")
+ begin
+ case Method of
+ Method::"Completed Contract":
+ begin
+ JobWIPMethod.SetRange("Recognized Costs", JobWIPMethod."Recognized Costs"::"At Completion");
+ JobWIPMethod.SetRange("Recognized Sales", JobWIPMethod."Recognized Sales"::"At Completion");
+ end;
+ Method::"Cost of Sales":
+ begin
+ JobWIPMethod.SetRange("Recognized Costs", JobWIPMethod."Recognized Costs"::"Cost of Sales");
+ JobWIPMethod.SetRange("Recognized Sales", JobWIPMethod."Recognized Sales"::"Contract (Invoiced Price)");
+ end;
+ Method::"Cost Value":
+ begin
+ JobWIPMethod.SetRange("Recognized Costs", JobWIPMethod."Recognized Costs"::"Cost Value");
+ JobWIPMethod.SetRange("Recognized Sales", JobWIPMethod."Recognized Sales"::"Contract (Invoiced Price)");
+ end;
+ Method::POC:
+ begin
+ JobWIPMethod.SetRange("Recognized Costs", JobWIPMethod."Recognized Costs"::"Usage (Total Cost)");
+ JobWIPMethod.SetRange("Recognized Sales", JobWIPMethod."Recognized Sales"::"Percentage of Completion");
+ end;
+ Method::"Sales Value":
+ begin
+ JobWIPMethod.SetRange("Recognized Costs", JobWIPMethod."Recognized Costs"::"Usage (Total Cost)");
+ JobWIPMethod.SetRange("Recognized Sales", JobWIPMethod."Recognized Sales"::"Sales Value");
+ end;
+ end;
+ JobWIPMethod.FindFirst();
+ end;
+
+ procedure RunUpdateJobItemCost(JobNo: Code[20])
+ var
+ Job: Record Job;
+ UpdateJobItemCost: Report "Update Job Item Cost";
+ begin
+ Clear(UpdateJobItemCost);
+ Job.SetRange("No.", JobNo);
+ UpdateJobItemCost.SetTableView(Job);
+ UpdateJobItemCost.UseRequestPage(false);
+ UpdateJobItemCost.Run();
+ end;
+}
diff --git a/Apps/W1/ApplicationTestLibrary/LibraryJournals.Codeunit.al b/Apps/W1/ApplicationTestLibrary/LibraryJournals.Codeunit.al
new file mode 100644
index 0000000000..c584463a50
--- /dev/null
+++ b/Apps/W1/ApplicationTestLibrary/LibraryJournals.Codeunit.al
@@ -0,0 +1,220 @@
+///
+/// Provides utility functions for creating and managing various journal types in test scenarios, including general journals, item journals, and resource journals.
+///
+codeunit 131306 "Library - Journals"
+{
+
+ trigger OnRun()
+ begin
+ end;
+
+ var
+ LibraryUtility: Codeunit "Library - Utility";
+ LibraryERM: Codeunit "Library - ERM";
+
+ procedure CreateGenJournalLine(var GenJournalLine: Record "Gen. Journal Line"; JournalTemplateName: Code[10]; JournalBatchName: Code[10]; DocumentType: Enum "Gen. Journal Document Type"; AccountType: Enum "Gen. Journal Account Type"; AccountNo: Code[20]; BalAccountType: Enum "Gen. Journal Account Type"; BalAccountNo: Code[20]; Amount: Decimal)
+ var
+ GenJournalBatch: Record "Gen. Journal Batch";
+ NoSeries: Record "No. Series";
+ NoSeriesCodeunit: Codeunit "No. Series";
+ RecRef: RecordRef;
+ begin
+ // Find a balanced template/batch pair.
+ GenJournalBatch.Get(JournalTemplateName, JournalBatchName);
+
+ // Create a General Journal Entry.
+ GenJournalLine.Init();
+ GenJournalLine.Validate("Journal Template Name", JournalTemplateName);
+ GenJournalLine.Validate("Journal Batch Name", JournalBatchName);
+ RecRef.GetTable(GenJournalLine);
+ GenJournalLine.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, GenJournalLine.FieldNo("Line No.")));
+ GenJournalLine.Insert(true);
+ GenJournalLine.Validate("Posting Date", WorkDate()); // Defaults to work date.
+ GenJournalLine.Validate("VAT Reporting Date", WorkDate());
+ GenJournalLine.Validate("Document Type", DocumentType);
+ GenJournalLine.Validate("Account Type", AccountType);
+ GenJournalLine.Validate("Account No.", AccountNo);
+ GenJournalLine.Validate(Amount, Amount);
+ if NoSeries.Get(GenJournalBatch."No. Series") then
+ GenJournalLine.Validate("Document No.", NoSeriesCodeunit.PeekNextNo(GenJournalBatch."No. Series")) // Unused but required field for posting.
+ else
+ GenJournalLine.Validate(
+ "Document No.", LibraryUtility.GenerateRandomCode(GenJournalLine.FieldNo("Document No."), DATABASE::"Gen. Journal Line"));
+ GenJournalLine.Validate("External Document No.", GenJournalLine."Document No."); // Unused but required for vendor posting.
+ GenJournalLine.Validate("Source Code", LibraryERM.FindGeneralJournalSourceCode()); // Unused but required for AU, NZ builds
+ GenJournalLine.Validate("Bal. Account Type", BalAccountType);
+ GenJournalLine.Validate("Bal. Account No.", BalAccountNo);
+ OnBeforeModifyGenJnlLineWhenCreate(GenJournalLine);
+ GenJournalLine.Modify(true);
+ end;
+
+ procedure CreateGenJournalLine2(var GenJournalLine: Record "Gen. Journal Line"; JournalTemplateName: Code[10]; JournalBatchName: Code[10]; DocumentType: Enum "Gen. Journal Document Type"; AccountType: Enum "Gen. Journal Account Type"; AccountNo: Code[20]; BalAccountType: Enum "Gen. Journal Account Type"; BalAccountNo: Code[20]; Amount: Decimal)
+ var
+ GenJournalBatch: Record "Gen. Journal Batch";
+ LastGenJnlLine: Record "Gen. Journal Line";
+ RecRef: RecordRef;
+ Balance: Decimal;
+ begin
+ // This function should replace the one above, but it requires a lot of changes to existing tests so I'm keeping both for now and will refactor when time permits
+
+ // Find a balanced template/batch pair.
+ GenJournalBatch.Get(JournalTemplateName, JournalBatchName);
+
+ // get the last Gen Jnl Line as template or insert a new doc no (to avoid CODEUNIT.RUN in WRITE transaction error)
+ Clear(GenJournalLine);
+ GenJournalLine.SetRange("Journal Template Name", JournalTemplateName);
+ GenJournalLine.SetRange("Journal Batch Name", JournalBatchName);
+ if not GetLastGenJnlLineAndBalance(GenJournalLine, LastGenJnlLine, Balance, JournalTemplateName, JournalBatchName) then
+ SetLastGenJnlLineFields(LastGenJnlLine, GenJournalBatch);
+
+ // Create a General Journal Entry.
+ GenJournalLine.Validate("Journal Template Name", JournalTemplateName);
+ GenJournalLine.Validate("Journal Batch Name", JournalBatchName);
+ RecRef.GetTable(GenJournalLine);
+ GenJournalLine.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, GenJournalLine.FieldNo("Line No.")));
+ GenJournalLine.Insert(true);
+
+ // Initialize the new line
+ GenJournalLine.SetUpNewLine(LastGenJnlLine, Balance, true);
+
+ // fill in additional fields
+ GenJournalLine.Validate("Document Type", DocumentType);
+ GenJournalLine.Validate("Account Type", AccountType);
+ GenJournalLine.Validate("Account No.", AccountNo);
+ GenJournalLine.Validate(Amount, Amount);
+ GenJournalLine.Validate("External Document No.", GenJournalLine."Document No."); // Unused but required for vendor posting.
+ GenJournalLine.Validate("Source Code", LibraryERM.FindGeneralJournalSourceCode()); // Unused but required for AU, NZ builds
+ GenJournalLine.Validate("Bal. Account Type", BalAccountType);
+ GenJournalLine.Validate("Bal. Account No.", BalAccountNo);
+ OnBeforeModifyGenJnlLineWhenCreate(GenJournalLine);
+ GenJournalLine.Modify(true);
+ end;
+
+ procedure CreateGenJournalLineWithBatch(var GenJournalLine: Record "Gen. Journal Line"; DocumentType: Enum "Gen. Journal Document Type"; AccountType: Enum "Gen. Journal Account Type"; AccountNo: Code[20]; LineAmount: Decimal)
+ var
+ GenJournalBatch: Record "Gen. Journal Batch";
+ GLAccount: Record "G/L Account";
+ begin
+ CreateGenJournalBatch(GenJournalBatch);
+ LibraryERM.CreateGLAccount(GLAccount);
+ CreateGenJournalLine(
+ GenJournalLine,
+ GenJournalBatch."Journal Template Name",
+ GenJournalBatch.Name,
+ DocumentType,
+ AccountType,
+ AccountNo,
+ GenJournalLine."Bal. Account Type"::"G/L Account",
+ GLAccount."No.",
+ LineAmount);
+ end;
+
+ procedure CreateGenJournalBatch(var GenJournalBatch: Record "Gen. Journal Batch")
+ var
+ GenJournalTemplate: Record "Gen. Journal Template";
+ begin
+ LibraryERM.CreateGenJournalTemplate(GenJournalTemplate);
+ LibraryERM.CreateGenJournalBatch(GenJournalBatch, GenJournalTemplate.Name);
+ end;
+
+ procedure CreateGenJournalBatchWithType(var GenJournalBatch: Record "Gen. Journal Batch"; TemplateType: Enum "Gen. Journal Template Type")
+ var
+ GenJournalTemplate: Record "Gen. Journal Template";
+ begin
+ LibraryERM.CreateGenJournalTemplate(GenJournalTemplate);
+ GenJournalTemplate.Validate(Type, TemplateType);
+ GenJournalTemplate.Modify(true);
+ LibraryERM.CreateGenJournalBatch(GenJournalBatch, GenJournalTemplate.Name);
+ end;
+
+ procedure SelectGenJournalBatch(var GenJournalBatch: Record "Gen. Journal Batch"; GenJournalTemplateCode: Code[10])
+ var
+ GLAccount: Record "G/L Account";
+ begin
+ // Select General Journal Batch Name for General Journal Line.
+ GenJournalBatch.SetRange("Journal Template Name", GenJournalTemplateCode);
+ GenJournalBatch.SetRange("Bal. Account Type", GenJournalBatch."Bal. Account Type"::"G/L Account");
+ LibraryERM.CreateGLAccount(GLAccount);
+
+ if not GenJournalBatch.FindFirst() then begin
+ // Create New General Journal Batch.
+ LibraryERM.CreateGenJournalBatch(GenJournalBatch, GenJournalTemplateCode);
+ GenJournalBatch.Validate("No. Series", LibraryERM.CreateNoSeriesCode());
+ GenJournalBatch.Validate("Bal. Account Type", GenJournalBatch."Bal. Account Type"::"G/L Account");
+ end;
+
+ GenJournalBatch.Validate("Bal. Account No.", GLAccount."No.");
+ GenJournalBatch.Modify(true);
+ end;
+
+ procedure SelectGenJournalTemplate(Type: Enum "Gen. Journal Template Type"; PageID: Integer): Code[10]
+ var
+ GenJournalTemplate: Record "Gen. Journal Template";
+ begin
+ GenJournalTemplate.SetRange(Type, Type);
+ GenJournalTemplate.SetRange(Recurring, false);
+ GenJournalTemplate.SetRange("Page ID", PageID);
+
+ if not GenJournalTemplate.FindFirst() then begin
+ GenJournalTemplate.Init();
+ GenJournalTemplate.Validate(
+ Name, LibraryUtility.GenerateRandomCode(GenJournalTemplate.FieldNo(Name), DATABASE::"Gen. Journal Template"));
+ GenJournalTemplate.Validate(Type, Type);
+ GenJournalTemplate.Validate("Page ID", PageID);
+ GenJournalTemplate.Validate(Recurring, false);
+ GenJournalTemplate.Insert(true);
+ end;
+
+ exit(GenJournalTemplate.Name);
+ end;
+
+ local procedure GetLastGenJnlLineAndBalance(var GenJournalLine: Record "Gen. Journal Line"; var LastGenJnlLine: Record "Gen. Journal Line"; var Balance: Decimal; JournalTemplateName: Code[20]; JournalBatchName: Code[20]) LineExists: Boolean
+ var
+ GenJnlManagement: Codeunit GenJnlManagement;
+ TotalBalance: Decimal;
+ ShowBalance: Boolean;
+ ShowTotalBalance: Boolean;
+ begin
+ LastGenJnlLine.SetRange("Journal Template Name", JournalTemplateName);
+ LastGenJnlLine.SetRange("Journal Batch Name", JournalBatchName);
+ LineExists := LastGenJnlLine.FindLast();
+ GenJnlManagement.CalcBalance(GenJournalLine, LastGenJnlLine, Balance, TotalBalance, ShowBalance, ShowTotalBalance);
+ exit(LineExists);
+ end;
+
+ local procedure SetLastGenJnlLineFields(var LastGenJnlLine: Record "Gen. Journal Line"; GenJournalBatch: Record "Gen. Journal Batch")
+ var
+ NoSeries: Codeunit "No. Series";
+ begin
+ if GenJournalBatch."No. Series" <> '' then
+ LastGenJnlLine."Document No." := NoSeries.PeekNextNo(GenJournalBatch."No. Series")
+ else
+ LastGenJnlLine."Document No." :=
+ LibraryUtility.GenerateRandomCode(LastGenJnlLine.FieldNo("Document No."), DATABASE::"Gen. Journal Line");
+ LastGenJnlLine."Posting Date" := WorkDate();
+ LastGenJnlLine."VAT Reporting Date" := WorkDate();
+ end;
+
+ procedure SetPostWithJobQueue(PostWithJobQueue: Boolean)
+ var
+ GeneralLedgerSetup: Record "General Ledger Setup";
+ begin
+ GeneralLedgerSetup.Get();
+ GeneralLedgerSetup.Validate("Post with Job Queue", PostWithJobQueue);
+ GeneralLedgerSetup.Modify(true);
+ end;
+
+ procedure SetPostAndPrintWithJobQueue(PostAndPrintWithJobQueue: Boolean)
+ var
+ GeneralLedgerSetup: Record "General Ledger Setup";
+ begin
+ GeneralLedgerSetup.Get();
+ GeneralLedgerSetup.Validate("Post & Print with Job Queue", PostAndPrintWithJobQueue);
+ GeneralLedgerSetup.Modify(true);
+ end;
+
+ [IntegrationEvent(false, false)]
+ internal procedure OnBeforeModifyGenJnlLineWhenCreate(var GenJournalLine: Record "Gen. Journal Line")
+ begin
+ end;
+}
\ No newline at end of file
diff --git a/Apps/W1/ApplicationTestLibrary/LibraryManufacturing.Codeunit.al b/Apps/W1/ApplicationTestLibrary/LibraryManufacturing.Codeunit.al
new file mode 100644
index 0000000000..98f27af562
--- /dev/null
+++ b/Apps/W1/ApplicationTestLibrary/LibraryManufacturing.Codeunit.al
@@ -0,0 +1,1575 @@
+#pragma warning disable AL0801
+///
+/// Provides utility functions for creating and managing manufacturing-related entities in test scenarios, including production orders, BOMs, routings, and work centers.
+///
+codeunit 132202 "Library - Manufacturing"
+{
+
+ trigger OnRun()
+ begin
+ end;
+
+ var
+ ManufacturingSetup: Record "Manufacturing Setup";
+ LibraryERM: Codeunit "Library - ERM";
+ LibraryRandom: Codeunit "Library - Random";
+ LibraryUtility: Codeunit "Library - Utility";
+ LibraryInventory: Codeunit "Library - Inventory";
+ LibraryItemTracking: Codeunit "Library - Item Tracking";
+ Assert: Codeunit Assert;
+ BOMItemLineNo: Integer;
+ BatchName: Label 'DEFAULT', Comment = 'Default Batch';
+ OutputConsumpMismatchTxt: Label 'Output Cost in Prod. Order %1, line %2 does not match Consumption.';
+ OutputVarianceMismatchTxt: Label 'Output Cost including Variance in Prod. Order %1, line %2 does not match total Standard Cost of Produced Item.';
+ Text003Msg: Label 'Inbound Whse. Requests are created.';
+ Text004Msg: Label 'No Inbound Whse. Request is created.';
+ Text005Msg: Label 'Inbound Whse. Requests have already been created.';
+
+ procedure AddProdBOMItem(var MfgItem: Record Item; SubItemNo: Code[20]; Qty: Decimal)
+ var
+ ProdBOMHeader: Record "Production BOM Header";
+ ProdBOMLine: Record "Production BOM Line";
+ subItem: Record Item;
+ begin
+ if MfgItem.IsMfgItem() then
+ ProdBOMHeader.Get(MfgItem."Production BOM No.")
+ else begin
+ ProdBOMHeader."No." := CopyStr(MfgItem."No." + 'BOM', 1, MaxStrLen(ProdBOMHeader."No."));
+ ProdBOMHeader.Status := ProdBOMHeader.Status::Certified;
+ ProdBOMHeader.Insert();
+ MfgItem."Production BOM No." := ProdBOMHeader."No.";
+ MfgItem."Replenishment System" := MfgItem."Replenishment System"::"Prod. Order";
+ MfgItem.Modify();
+ end;
+ ProdBOMLine."Production BOM No." := ProdBOMHeader."No.";
+ BOMItemLineNo += 1;
+ ProdBOMLine."Line No." := BOMItemLineNo;
+ ProdBOMLine.Type := ProdBOMLine.Type::Item;
+ ProdBOMLine."No." := SubItemNo;
+ subItem.Get(SubItemNo);
+ ProdBOMLine."Unit of Measure Code" := subItem."Base Unit of Measure";
+ ProdBOMLine.Quantity := Qty;
+ ProdBOMLine.Insert();
+ end;
+
+ procedure CalculateConsumption(ProductionOrderNo: Code[20]; ItemJournalTemplateName: Code[10]; ItemJournalBatchName: Code[10])
+ var
+ ProductionOrder: Record "Production Order";
+ CalcConsumption: Report "Calc. Consumption";
+ CalcBasedOn: Option "Actual Output","Expected Output";
+ begin
+ CalcConsumption.InitializeRequest(WorkDate(), CalcBasedOn::"Expected Output");
+ CalcConsumption.SetTemplateAndBatchName(ItemJournalTemplateName, ItemJournalBatchName);
+ ProductionOrder.SetRange(Status, ProductionOrder.Status::Released);
+ ProductionOrder.SetRange("No.", ProductionOrderNo);
+ CalcConsumption.SetTableView(ProductionOrder);
+ CalcConsumption.UseRequestPage(false);
+ CalcConsumption.RunModal();
+ end;
+
+ procedure CalculateConsumptionForJournal(var ProductionOrder: Record "Production Order"; var ProdOrderComponent: Record "Prod. Order Component"; PostingDate: Date; ActualOutput: Boolean)
+ var
+ TmpProductionOrder: Record "Production Order";
+ TmpProdOrderComponent: Record "Prod. Order Component";
+ ItemJournalTemplate: Record "Item Journal Template";
+ ItemJournalBatch: Record "Item Journal Batch";
+ CalcConsumption: Report "Calc. Consumption";
+ CalcBasedOn: Option "Actual Output","Expected Output";
+ begin
+ Commit();
+ if ActualOutput then
+ CalcBasedOn := CalcBasedOn::"Actual Output"
+ else
+ CalcBasedOn := CalcBasedOn::"Expected Output";
+ CalcConsumption.InitializeRequest(PostingDate, CalcBasedOn);
+ ItemJournalTemplate.SetRange(Type, ItemJournalTemplate.Type::Consumption);
+ ItemJournalTemplate.FindFirst();
+ ItemJournalBatch.SetRange("Journal Template Name", ItemJournalTemplate.Name);
+ ItemJournalBatch.FindFirst();
+ CalcConsumption.SetTemplateAndBatchName(ItemJournalBatch."Journal Template Name", ItemJournalBatch.Name);
+ if ProductionOrder.HasFilter then
+ TmpProductionOrder.CopyFilters(ProductionOrder)
+ else begin
+ ProductionOrder.Get(ProductionOrder.Status, ProductionOrder."No.");
+ TmpProductionOrder.SetRange(Status, ProductionOrder.Status);
+ TmpProductionOrder.SetRange("No.", ProductionOrder."No.");
+ end;
+ CalcConsumption.SetTableView(TmpProductionOrder);
+ if ProdOrderComponent.HasFilter then
+ TmpProdOrderComponent.CopyFilters(ProdOrderComponent)
+ else begin
+ ProdOrderComponent.Get(ProdOrderComponent.Status, ProdOrderComponent."Prod. Order No.",
+ ProdOrderComponent."Prod. Order Line No.", ProdOrderComponent."Line No.");
+ TmpProdOrderComponent.SetRange(Status, ProdOrderComponent.Status);
+ TmpProdOrderComponent.SetRange("Prod. Order No.", ProdOrderComponent."Prod. Order No.");
+ TmpProdOrderComponent.SetRange("Prod. Order Line No.", ProdOrderComponent."Prod. Order Line No.");
+ TmpProdOrderComponent.SetRange("Line No.", ProdOrderComponent."Line No.");
+ end;
+ CalcConsumption.SetTableView(TmpProdOrderComponent);
+ CalcConsumption.UseRequestPage(false);
+ CalcConsumption.RunModal();
+ end;
+
+ procedure CalculateMachCenterCalendar(var MachineCenter: Record "Machine Center"; StartingDate: Date; EndingDate: Date)
+ var
+ TmpMachineCenter: Record "Machine Center";
+ CalcMachineCenterCalendar: Report "Calc. Machine Center Calendar";
+ begin
+ Commit();
+ CalcMachineCenterCalendar.InitializeRequest(StartingDate, EndingDate);
+ if MachineCenter.HasFilter then
+ TmpMachineCenter.CopyFilters(MachineCenter)
+ else begin
+ MachineCenter.Get(MachineCenter."No.");
+ TmpMachineCenter.SetRange("No.", MachineCenter."No.");
+ end;
+ CalcMachineCenterCalendar.SetTableView(TmpMachineCenter);
+ CalcMachineCenterCalendar.UseRequestPage(false);
+ CalcMachineCenterCalendar.RunModal();
+ end;
+
+ procedure CalculateWorksheetPlan(var Item: Record Item; OrderDate: Date; ToDate: Date)
+ var
+ TempItem: Record Item temporary;
+ ReqWkshTemplate: Record "Req. Wksh. Template";
+ RequisitionWkshName: Record "Requisition Wksh. Name";
+ CalculatePlanPlanWksh: Report "Calculate Plan - Plan. Wksh.";
+ begin
+ Commit();
+ CalculatePlanPlanWksh.InitializeRequest(OrderDate, ToDate, false);
+ ReqWkshTemplate.SetRange(Type, ReqWkshTemplate.Type::Planning);
+ ReqWkshTemplate.FindFirst();
+ RequisitionWkshName.SetRange("Worksheet Template Name", ReqWkshTemplate.Name);
+ RequisitionWkshName.FindFirst();
+ CalculatePlanPlanWksh.SetTemplAndWorksheet(RequisitionWkshName."Worksheet Template Name", RequisitionWkshName.Name, true);
+ if Item.HasFilter then
+ TempItem.CopyFilters(Item)
+ else begin
+ Item.Get(Item."No.");
+ TempItem.SetRange("No.", Item."No.");
+ end;
+ CalculatePlanPlanWksh.SetTableView(TempItem);
+ CalculatePlanPlanWksh.UseRequestPage(false);
+ CalculatePlanPlanWksh.RunModal();
+ end;
+
+ procedure CalculateSubcontractOrder(var WorkCenter: Record "Work Center")
+ var
+ RequisitionLine: Record "Requisition Line";
+ CalculateSubcontracts: Report "Calculate Subcontracts";
+ begin
+ RequisitionLineForSubcontractOrder(RequisitionLine);
+ CalculateSubcontracts.SetWkShLine(RequisitionLine);
+ CalculateSubcontracts.SetTableView(WorkCenter);
+ CalculateSubcontracts.UseRequestPage(false);
+ CalculateSubcontracts.RunModal();
+ end;
+
+ procedure CalculateWorkCenterCalendar(var WorkCenter: Record "Work Center"; StartingDate: Date; EndingDate: Date)
+ var
+ TmpWorkCenter: Record "Work Center";
+ CalculateWorkCenterCalendarReport: Report "Calculate Work Center Calendar";
+ begin
+ Commit();
+ CalculateWorkCenterCalendarReport.InitializeRequest(StartingDate, EndingDate);
+ if WorkCenter.HasFilter then
+ TmpWorkCenter.CopyFilters(WorkCenter)
+ else begin
+ WorkCenter.Get(WorkCenter."No.");
+ TmpWorkCenter.SetRange("No.", WorkCenter."No.");
+ end;
+ CalculateWorkCenterCalendarReport.SetTableView(TmpWorkCenter);
+ CalculateWorkCenterCalendarReport.UseRequestPage(false);
+ CalculateWorkCenterCalendarReport.RunModal();
+ end;
+
+ procedure CalculateSubcontractOrderWithProdOrderRoutingLine(var ProdOrderRoutingLine: Record "Prod. Order Routing Line")
+ var
+ RequisitionLine: Record "Requisition Line";
+ TmpProdOrderRoutingLine: Record "Prod. Order Routing Line";
+ CalculateSubcontracts: Report "Calculate Subcontracts";
+ begin
+ if ProdOrderRoutingLine.HasFilter then
+ TmpProdOrderRoutingLine.CopyFilters(ProdOrderRoutingLine)
+ else begin
+ ProdOrderRoutingLine.Get(ProdOrderRoutingLine."No.");
+ TmpProdOrderRoutingLine.SetRange("No.", ProdOrderRoutingLine."No.");
+ end;
+
+ RequisitionLineForSubcontractOrder(RequisitionLine);
+ CalculateSubcontracts.SetWkShLine(RequisitionLine);
+ CalculateSubcontracts.SetTableView(TmpProdOrderRoutingLine);
+ CalculateSubcontracts.UseRequestPage(false);
+ CalculateSubcontracts.RunModal();
+ end;
+
+ procedure ChangeProdOrderStatus(var ProductionOrder: Record "Production Order"; NewStatus: Enum "Production Order Status"; PostingDate: Date; UpdateUnitCost: Boolean)
+ var
+ ProdOrderStatusMgt: Codeunit "Prod. Order Status Management";
+ begin
+ ProdOrderStatusMgt.ChangeProdOrderStatus(ProductionOrder, NewStatus, PostingDate, UpdateUnitCost);
+ end;
+
+ procedure ChangeStatusPlannedToFinished(ProductionOrderNo: Code[20]): Code[20]
+ var
+ ProductionOrder: Record "Production Order";
+ begin
+ ProductionOrder.Get(ProductionOrder.Status::Planned, ProductionOrderNo);
+ ChangeProdOrderStatus(ProductionOrder, ProductionOrder.Status::Released, WorkDate(), false);
+ ProductionOrder.SetRange(Status, ProductionOrder.Status::Released);
+ ProductionOrder.SetRange("Source No.", ProductionOrder."Source No.");
+ ProductionOrder.FindFirst();
+ ChangeProdOrderStatus(ProductionOrder, ProductionOrder.Status::Finished, WorkDate(), false);
+ exit(ProductionOrder."No.");
+ end;
+
+ procedure ChangeStatusReleasedToFinished(ProductionOrderNo: Code[20])
+ var
+ ProductionOrder: Record "Production Order";
+ begin
+ ProductionOrder.Get(ProductionOrder.Status::Released, ProductionOrderNo);
+ ChangeProdOrderStatus(ProductionOrder, ProductionOrder.Status::Finished, WorkDate(), false);
+ end;
+
+ procedure ChangeProuctionOrderStatus(ProductionOrderNo: Code[20]; FromStatus: Enum "Production Order Status"; ToStatus: Enum "Production Order Status"): Code[20]
+ var
+ ProductionOrder: Record "Production Order";
+ begin
+ ProductionOrder.Get(FromStatus, ProductionOrderNo);
+ ChangeProdOrderStatus(ProductionOrder, ToStatus, WorkDate(), true);
+ ProductionOrder.SetRange(Status, ToStatus);
+ ProductionOrder.SetRange("Source No.", ProductionOrder."Source No.");
+ ProductionOrder.FindFirst();
+ exit(ProductionOrder."No.");
+ end;
+
+ procedure ChangeStatusFirmPlanToReleased(ProductionOrderNo: Code[20]): Code[20]
+ var
+ ProductionOrder: Record "Production Order";
+ begin
+ exit(ChangeProuctionOrderStatus(ProductionOrderNo, ProductionOrder.Status::"Firm Planned", ProductionOrder.Status::Released));
+ end;
+
+ procedure ChangeStatusSimulatedToReleased(ProductionOrderNo: Code[20]): Code[20]
+ var
+ ProductionOrder: Record "Production Order";
+ begin
+ exit(ChangeProuctionOrderStatus(ProductionOrderNo, ProductionOrder.Status::Simulated, ProductionOrder.Status::Released));
+ end;
+
+ procedure CheckProductionOrderCost(ProdOrder: Record "Production Order"; VerifyVarianceinOutput: Boolean)
+ var
+ ItemLedgerEntry: Record "Item Ledger Entry";
+ ValueEntry: Record "Value Entry";
+ ProdOrderLine: Record "Prod. Order Line";
+ ConsumptionCost: Decimal;
+ OutpuCostwithoutVariance: Decimal;
+ OutputCostinclVariance: Decimal;
+ RefOutputCostinclVariance: Decimal;
+ begin
+ ProdOrderLine.SetRange(Status, ProdOrder.Status);
+ ProdOrderLine.SetRange("Prod. Order No.", ProdOrder."No.");
+ ItemLedgerEntry.SetRange("Order Type", ItemLedgerEntry."Order Type"::Production);
+ ItemLedgerEntry.SetRange("Order No.", ProdOrder."No.");
+ if ProdOrderLine.FindSet() then begin
+ OutpuCostwithoutVariance := 0;
+ ConsumptionCost := 0;
+ repeat
+ ItemLedgerEntry.SetRange("Order Line No.", ProdOrderLine."Line No.");
+ if ItemLedgerEntry.FindSet() then
+ repeat
+ ItemLedgerEntry.CalcFields("Cost Amount (Expected)", "Cost Amount (Actual)");
+ if ItemLedgerEntry."Entry Type" = ItemLedgerEntry."Entry Type"::Consumption then
+ ConsumptionCost += ItemLedgerEntry."Cost Amount (Expected)" + ItemLedgerEntry."Cost Amount (Actual)"
+ else
+ if ItemLedgerEntry."Entry Type" = ItemLedgerEntry."Entry Type"::Output then begin
+ ValueEntry.SetCurrentKey("Item Ledger Entry No.", "Entry Type");
+ if VerifyVarianceinOutput then begin
+ ValueEntry.SetRange("Item Ledger Entry No.", ItemLedgerEntry."Entry No.");
+ ValueEntry.CalcSums("Cost Amount (Actual)");
+ OutputCostinclVariance := Round(ValueEntry."Cost Amount (Actual)", LibraryERM.GetAmountRoundingPrecision());
+ end;
+ ValueEntry.SetFilter("Entry Type", '<>%1', ValueEntry."Entry Type"::Variance);
+ ValueEntry.CalcSums("Cost Amount (Actual)");
+ OutpuCostwithoutVariance += ValueEntry."Cost Amount (Actual)";
+ end;
+ until ItemLedgerEntry.Next() = 0;
+ Assert.AreEqual(
+ -ConsumptionCost, OutpuCostwithoutVariance,
+ StrSubstNo(OutputConsumpMismatchTxt, ProdOrderLine."Prod. Order No.", ProdOrderLine."Line No."));
+ if VerifyVarianceinOutput then begin
+ RefOutputCostinclVariance :=
+ Round(ProdOrderLine."Unit Cost" * ProdOrderLine.Quantity, LibraryERM.GetAmountRoundingPrecision());
+ Assert.AreEqual(
+ -RefOutputCostinclVariance, OutputCostinclVariance,
+ StrSubstNo(OutputVarianceMismatchTxt, ProdOrderLine."Prod. Order No.", ProdOrderLine."Line No."));
+ end;
+ until ProdOrderLine.Next() = 0;
+ end;
+ end;
+
+ procedure CreateAndRefreshProductionOrder(var ProductionOrder: Record "Production Order"; ProdOrderStatus: Enum "Production Order Status"; SourceType: Enum "Prod. Order Source Type"; SourceNo: Code[20]; Quantity: Decimal)
+ begin
+ CreateProductionOrder(ProductionOrder, ProdOrderStatus, SourceType, SourceNo, Quantity);
+ RefreshProdOrder(ProductionOrder, false, true, true, true, false);
+ end;
+
+#if not CLEAN26
+ [Obsolete('Moved to LibraryInventory', '26.0')]
+ procedure CreateBOMComponent(var BOMComponent: Record "BOM Component"; ParentItemNo: Code[20]; Type: Enum "BOM Component Type"; No: Code[20]; QuantityPer: Decimal; UnitOfMeasureCode: Code[10])
+ begin
+ LibraryInventory.CreateBOMComponent(BOMComponent, ParentItemNo, Type, No, QuantityPer, UnitOfMeasureCode);
+ end;
+#endif
+
+ procedure CreateCalendarAbsenceEntry(var CalendarAbsenceEntry: Record "Calendar Absence Entry"; CapacityType: Enum "Capacity Type"; No: Code[20]; Date: Date; StartingTime: Time; EndingTime: Time; Capacity: Decimal)
+ begin
+ CalendarAbsenceEntry.Init();
+ CalendarAbsenceEntry.Validate("Capacity Type", CapacityType);
+ CalendarAbsenceEntry.Validate("No.", No);
+ CalendarAbsenceEntry.Validate(Date, Date);
+ CalendarAbsenceEntry.Validate("Starting Time", StartingTime);
+ CalendarAbsenceEntry.Validate("Ending Time", EndingTime);
+ CalendarAbsenceEntry.Insert(true);
+ CalendarAbsenceEntry.Validate(Capacity, Capacity);
+ CalendarAbsenceEntry.Modify(true);
+ end;
+
+ procedure CreateCapacityConstrainedResource(var CapacityConstrainedResource: Record "Capacity Constrained Resource"; CapacityType: Enum "Capacity Type"; CapacityNo: Code[20])
+ begin
+ Clear(CapacityConstrainedResource);
+ CapacityConstrainedResource.Init();
+ CapacityConstrainedResource.Validate("Capacity Type", CapacityType);
+ CapacityConstrainedResource.Validate("Capacity No.", CapacityNo);
+ CapacityConstrainedResource.Insert(true);
+ end;
+
+ procedure CreateCapacityUnitOfMeasure(var CapacityUnitOfMeasure: Record "Capacity Unit of Measure"; Type: Enum "Capacity Unit of Measure")
+ begin
+ CapacityUnitOfMeasure.Init();
+ CapacityUnitOfMeasure.Validate(
+ Code, LibraryUtility.GenerateRandomCode(CapacityUnitOfMeasure.FieldNo(Code), DATABASE::"Capacity Unit of Measure"));
+ CapacityUnitOfMeasure.Insert(true);
+ CapacityUnitOfMeasure.Validate(Type, Type);
+ CapacityUnitOfMeasure.Modify(true);
+ end;
+
+ procedure CreateFamily(var Family: Record Family)
+ begin
+ Family.Init();
+ Family.Validate("No.", LibraryUtility.GenerateRandomCode(Family.FieldNo("No."), DATABASE::Family));
+ Family.Insert(true);
+ Family.Validate(Description, Family."No.");
+ Family.Modify(true);
+ end;
+
+ procedure CreateFamilyLine(var FamilyLine: Record "Family Line"; FamilyNo: Code[20]; ItemNo: Code[20]; Qty: Decimal)
+ var
+ RecRef: RecordRef;
+ begin
+ FamilyLine.Init();
+ FamilyLine.Validate("Family No.", FamilyNo);
+ RecRef.GetTable(FamilyLine);
+ FamilyLine.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, FamilyLine.FieldNo("Line No.")));
+ FamilyLine.Insert(true);
+ FamilyLine.Validate("Item No.", ItemNo);
+ FamilyLine.Validate(Quantity, Qty);
+ FamilyLine.Modify(true);
+ end;
+
+ procedure CreateProdItemJournal(var ItemJournalBatch: Record "Item Journal Batch"; ItemNo: Code[20]; ItemJournalTemplateType: Enum "Item Journal Template Type"; ProductionOrderNo: Code[20])
+ var
+ ItemJournalLine: Record "Item Journal Line";
+ ItemJournalTemplate: Record "Item Journal Template";
+ begin
+ // Create Journals for Consumption and Output.
+ LibraryInventory.SelectItemJournalTemplateName(ItemJournalTemplate, ItemJournalTemplateType);
+ LibraryInventory.SelectItemJournalBatchName(ItemJournalBatch, ItemJournalTemplateType, ItemJournalTemplate.Name);
+ if ItemJournalTemplateType = ItemJournalTemplateType::Consumption then
+ CalculateConsumption(ProductionOrderNo, ItemJournalTemplate.Name, ItemJournalBatch.Name)
+ else begin
+ CreateOutputJournal(ItemJournalLine, ItemJournalTemplate, ItemJournalBatch, ItemNo, ProductionOrderNo);
+ OutputJnlExplodeRoute(ItemJournalLine);
+ UpdateOutputJournal(ProductionOrderNo);
+ end;
+ end;
+
+ procedure CreateItemManufacturing(var Item: Record Item; CostingMethod: Enum "Costing Method"; UnitCost: Decimal; ReorderPolicy: Enum "Reordering Policy"; FlushingMethod: Enum "Flushing Method"; RoutingNo: Code[20]; ProductionBOMNo: Code[20])
+ var
+ InventoryPostingSetup: Record "Inventory Posting Setup";
+ begin
+ // Create Item extended for Manufacturing.
+ LibraryInventory.CreateItemManufacturing(Item);
+ Item.Validate("Costing Method", CostingMethod);
+ if Item."Costing Method" = Item."Costing Method"::Standard then
+ Item.Validate("Standard Cost", UnitCost)
+ else begin
+ Item.Validate("Unit Cost", UnitCost);
+ Item.Validate("Last Direct Cost", Item."Unit Cost");
+ end;
+
+ Item.Validate("Reordering Policy", ReorderPolicy);
+ Item.Validate("Flushing Method", FlushingMethod);
+
+ if ProductionBOMNo <> '' then begin
+ InventoryPostingSetup.FindLast();
+ Item.Validate("Replenishment System", Item."Replenishment System"::"Prod. Order");
+ Item.Validate("Routing No.", RoutingNo);
+ Item.Validate("Production BOM No.", ProductionBOMNo);
+ Item.Validate("Inventory Posting Group", InventoryPostingSetup."Invt. Posting Group Code");
+ end;
+ Item.Modify(true);
+ end;
+
+ procedure CreateMachineCenter(var MachineCenter: Record "Machine Center"; WorkCenterNo: Code[20]; Capacity: Decimal)
+ var
+ GeneralPostingSetup: Record "General Posting Setup";
+ begin
+ LibraryERM.FindGeneralPostingSetupInvtToGL(GeneralPostingSetup);
+ LibraryUtility.UpdateSetupNoSeriesCode(
+ DATABASE::"Manufacturing Setup", ManufacturingSetup.FieldNo("Machine Center Nos."));
+
+ Clear(MachineCenter);
+ MachineCenter.Insert(true);
+ MachineCenter.Validate("Work Center No.", WorkCenterNo);
+ MachineCenter.Validate(Capacity, Capacity);
+ MachineCenter.Validate("Gen. Prod. Posting Group", GeneralPostingSetup."Gen. Prod. Posting Group");
+ MachineCenter.Modify(true);
+ end;
+
+ procedure CreateMachineCenterWithCalendar(var MachineCenter: Record "Machine Center"; WorkCenterNo: Code[20]; Capacity: Decimal)
+ begin
+ CreateMachineCenter(MachineCenter, WorkCenterNo, Capacity);
+ CalculateMachCenterCalendar(MachineCenter, CalcDate('<-1M>', WorkDate()), CalcDate('<1M>', WorkDate()));
+ end;
+
+ procedure CreateOutputJournal(var ItemJournalLine: Record "Item Journal Line"; ItemJournalTemplate: Record "Item Journal Template"; ItemJournalBatch: Record "Item Journal Batch"; ItemNo: Code[20]; ProductionOrderNo: Code[20])
+ begin
+ // Create Output Journal.
+ if ItemJournalTemplate.Type <> ItemJournalTemplate.Type::Output then
+ exit;
+ ItemJournalLine."Entry Type" := ItemJournalLine."Entry Type"::Output;
+
+ LibraryInventory.CreateItemJnlLineWithNoItem(
+ ItemJournalLine, ItemJournalBatch, ItemJournalTemplate.Name, ItemJournalBatch.Name, ItemJournalLine."Entry Type");
+ ItemJournalLine.Validate("Order Type", ItemJournalLine."Order Type"::Production);
+ ItemJournalLine.Validate("Order No.", ProductionOrderNo);
+ ItemJournalLine.Validate("Item No.", ItemNo);
+ ItemJournalLine.Modify(true);
+ Commit();
+ end;
+
+ procedure CreateProdOrderLine(var ProdOrderLine: Record "Prod. Order Line"; ProdOrderStatus: Enum "Production Order Status"; ProdOrderNo: Code[20]; ItemNo: Code[20]; VariantCode: Code[10]; LocationCode: Code[10]; Qty: Decimal)
+ begin
+ ProdOrderLine.Init();
+ ProdOrderLine.Validate(Status, ProdOrderStatus);
+ ProdOrderLine.Validate("Prod. Order No.", ProdOrderNo);
+ ProdOrderLine.Validate("Line No.", LibraryUtility.GetNewRecNo(ProdOrderLine, ProdOrderLine.FieldNo("Line No.")));
+ ProdOrderLine.Validate("Item No.", ItemNo);
+ ProdOrderLine.Validate("Variant Code", VariantCode);
+ ProdOrderLine.Validate("Location Code", LocationCode);
+ ProdOrderLine.Validate(Quantity, Qty);
+
+ ProdOrderLine.Insert(true);
+ end;
+
+ procedure CreateProductionBOMCommentLine(ProductionBOMLine: Record "Production BOM Line")
+ var
+ ProductionBOMCommentLine: Record "Production BOM Comment Line";
+ LineNo: Integer;
+ begin
+ ProductionBOMCommentLine.SetRange("Production BOM No.", ProductionBOMLine."Production BOM No.");
+ ProductionBOMCommentLine.SetRange("Version Code", ProductionBOMLine."Version Code");
+ ProductionBOMCommentLine.SetRange("BOM Line No.", ProductionBOMLine."Line No.");
+ if ProductionBOMCommentLine.FindLast() then;
+ LineNo := ProductionBOMCommentLine."Line No." + 10000;
+
+ ProductionBOMCommentLine.Init();
+ ProductionBOMCommentLine.Validate("Production BOM No.", ProductionBOMLine."Production BOM No.");
+ ProductionBOMCommentLine.Validate("BOM Line No.", ProductionBOMLine."Line No.");
+ ProductionBOMCommentLine.Validate("Version Code", ProductionBOMLine."Version Code");
+ ProductionBOMCommentLine.Validate("Line No.", LineNo);
+ ProductionBOMCommentLine.Validate(Comment, LibraryUtility.GenerateGUID());
+ ProductionBOMCommentLine.Insert(true);
+ end;
+
+ procedure CreateProductionBOM(var Item: Record Item; NoOfComps: Integer)
+ var
+ Item1: Record Item;
+ ProductionBOMHeader: Record "Production BOM Header";
+ ProductionBOMLine: Record "Production BOM Line";
+ LibraryAssembly: Codeunit "Library - Assembly";
+ "count": Integer;
+ begin
+ CreateProductionBOMHeader(ProductionBOMHeader, Item."Base Unit of Measure");
+
+ for count := 1 to NoOfComps do begin
+ LibraryAssembly.CreateItem(Item1, Item."Costing Method"::Standard, Item."Replenishment System"::Purchase, '', '');
+ CreateProductionBOMLine(
+ ProductionBOMHeader, ProductionBOMLine, '', ProductionBOMLine.Type::Item, Item1."No.", 1);
+ end;
+
+ ProductionBOMHeader.Validate(Status, ProductionBOMHeader.Status::Certified);
+ ProductionBOMHeader.Modify(true);
+ Item.Validate("Production BOM No.", ProductionBOMHeader."No.");
+ Item.Modify(true);
+ end;
+
+ procedure CreateProductionBOMHeader(var ProductionBOMHeader: Record "Production BOM Header"; UnitOfMeasureCode: Code[10]): Code[20]
+ begin
+ LibraryUtility.UpdateSetupNoSeriesCode(
+ DATABASE::"Manufacturing Setup", ManufacturingSetup.FieldNo("Production BOM Nos."));
+
+ Clear(ProductionBOMHeader);
+ ProductionBOMHeader.Insert(true);
+ ProductionBOMHeader.Validate("Unit of Measure Code", UnitOfMeasureCode);
+ ProductionBOMHeader.Validate(Status, ProductionBOMHeader.Status::New);
+ ProductionBOMHeader.Modify(true);
+ exit(ProductionBOMHeader."No.");
+ end;
+
+ procedure CreateProductionBOMLine(var ProductionBOMHeader: Record "Production BOM Header"; var ProductionBOMLine: Record "Production BOM Line"; VersionCode: Code[20]; Type: Enum "Production BOM Line Type"; No: Code[20]; QuantityPer: Decimal)
+ var
+ RecRef: RecordRef;
+ begin
+ ProductionBOMLine.Init();
+ ProductionBOMLine.Validate("Production BOM No.", ProductionBOMHeader."No.");
+ ProductionBOMLine.Validate("Version Code", VersionCode);
+ RecRef.GetTable(ProductionBOMLine);
+ ProductionBOMLine.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, ProductionBOMLine.FieldNo("Line No.")));
+ ProductionBOMLine.Insert(true);
+ ProductionBOMLine.Validate(Type, Type);
+ ProductionBOMLine.Validate("No.", No);
+ ProductionBOMLine.Validate("Quantity per", QuantityPer);
+ ProductionBOMLine.Modify(true);
+ end;
+
+ procedure CreateCertifiedProductionBOM(var ProductionBOMHeader: Record "Production BOM Header"; ItemNo: Code[20]; QuantityPer: Decimal): Code[20]
+ var
+ Item: Record Item;
+ ProductionBOMLine: Record "Production BOM Line";
+ begin
+ Item.Get(ItemNo);
+ CreateProductionBOMHeader(ProductionBOMHeader, Item."Base Unit of Measure");
+ CreateProductionBOMLine(ProductionBOMHeader, ProductionBOMLine, '', ProductionBOMLine.Type::Item, ItemNo, QuantityPer);
+ UpdateProductionBOMStatus(ProductionBOMHeader, ProductionBOMHeader.Status::Certified);
+ exit(ProductionBOMHeader."No.");
+ end;
+
+ procedure CreateCertifProdBOMWithTwoComp(var ProductionBOMHeader: Record "Production BOM Header"; ItemNo: Code[20]; ItemNo2: Code[20]; QuantityPer: Decimal): Code[20]
+ var
+ Item: Record Item;
+ ProductionBOMLine: Record "Production BOM Line";
+ begin
+ // Create Production BOM.
+ Item.Get(ItemNo);
+ CreateProductionBOMHeader(ProductionBOMHeader, Item."Base Unit of Measure");
+ CreateProductionBOMLine(ProductionBOMHeader, ProductionBOMLine, '', ProductionBOMLine.Type::Item, ItemNo, QuantityPer);
+ CreateProductionBOMLine(ProductionBOMHeader, ProductionBOMLine, '', ProductionBOMLine.Type::Item, ItemNo2, QuantityPer);
+ UpdateProductionBOMStatus(ProductionBOMHeader, ProductionBOMHeader.Status::Certified);
+ exit(ProductionBOMHeader."No.");
+ end;
+
+ procedure CreateProductionBOMVersion(var ProductionBomVersion: Record "Production BOM Version"; BomNo: Code[20]; Version: Code[20]; UOMCode: Code[10])
+ begin
+ ProductionBomVersion.Init();
+ ProductionBomVersion.Validate("Production BOM No.", BomNo);
+ ProductionBomVersion.Validate("Version Code", Version);
+ ProductionBomVersion.Insert(true);
+ ProductionBomVersion.Validate("Unit of Measure Code", UOMCode);
+ ProductionBomVersion.Modify(true);
+ end;
+
+ procedure CreateProductionBOMVersion(var ProductionBomVersion: Record "Production BOM Version"; BomNo: Code[20]; Version: Code[20]; UOMCode: Code[10]; StartingDate: Date)
+ begin
+ CreateProductionBOMVersion(ProductionBomVersion, BomNo, Version, UOMCode);
+ ProductionBomVersion.Validate("Starting Date", StartingDate);
+ ProductionBomVersion.Modify(true);
+ end;
+
+ procedure CreateProductionForecastEntry(var ProductionForecastEntry: Record "Production Forecast Entry"; ProductionForecastName: Code[10]; ItemNo: Code[20]; LocationCode: Code[10]; ForecastDate: Date; ComponentForecast: Boolean)
+ begin
+ Clear(ProductionForecastEntry);
+ ProductionForecastEntry.Init();
+ ProductionForecastEntry.Validate("Production Forecast Name", ProductionForecastName);
+ ProductionForecastEntry.Validate("Item No.", ItemNo);
+ ProductionForecastEntry.Validate("Location Code", LocationCode);
+ ProductionForecastEntry.Validate("Forecast Date", ForecastDate);
+ ProductionForecastEntry.Validate("Component Forecast", ComponentForecast);
+ ProductionForecastEntry.Insert(true);
+ end;
+
+ procedure CreateProductionForecastEntry(var ProductionForecastEntry: Record "Production Forecast Entry"; ProductionForecastName: Code[10]; ItemNo: Code[20]; VariantCode: Code[10]; LocationCode: Code[10]; ForecastDate: Date; ComponentForecast: Boolean)
+ begin
+ ProductionForecastEntry.Init();
+ ProductionForecastEntry.Validate("Production Forecast Name", ProductionForecastName);
+ ProductionForecastEntry.Validate("Item No.", ItemNo);
+ ProductionForecastEntry.Validate("Variant Code", VariantCode);
+ ProductionForecastEntry.Validate("Location Code", LocationCode);
+ ProductionForecastEntry.Validate("Forecast Date", ForecastDate);
+ ProductionForecastEntry.Validate("Component Forecast", ComponentForecast);
+ ProductionForecastEntry.Insert(true);
+ end;
+
+ procedure CreateProductionForecastName(var ProductionForecastName: Record "Production Forecast Name")
+ begin
+ Clear(ProductionForecastName);
+ ProductionForecastName.Init();
+ ProductionForecastName.Validate(
+ Name, LibraryUtility.GenerateRandomCode(ProductionForecastName.FieldNo(Name), DATABASE::"Production Forecast Name"));
+ ProductionForecastName.Validate(Description, ProductionForecastName.Name);
+ ProductionForecastName.Insert(true);
+ end;
+
+ procedure CreateProductionOrder(var ProductionOrder: Record "Production Order"; Status: Enum "Production Order Status"; SourceType: Enum "Prod. Order Source Type"; SourceNo: Code[20]; Quantity: Decimal)
+ begin
+ case Status of
+ ProductionOrder.Status::Simulated:
+ LibraryUtility.UpdateSetupNoSeriesCode(
+ DATABASE::"Manufacturing Setup", ManufacturingSetup.FieldNo("Simulated Order Nos."));
+ ProductionOrder.Status::Planned:
+ LibraryUtility.UpdateSetupNoSeriesCode(
+ DATABASE::"Manufacturing Setup", ManufacturingSetup.FieldNo("Planned Order Nos."));
+ ProductionOrder.Status::"Firm Planned":
+ LibraryUtility.UpdateSetupNoSeriesCode(
+ DATABASE::"Manufacturing Setup", ManufacturingSetup.FieldNo("Firm Planned Order Nos."));
+ ProductionOrder.Status::Released:
+ LibraryUtility.UpdateSetupNoSeriesCode(
+ DATABASE::"Manufacturing Setup", ManufacturingSetup.FieldNo("Released Order Nos."));
+ end;
+
+ Clear(ProductionOrder);
+ ProductionOrder.Init();
+ ProductionOrder.Validate(Status, Status);
+ ProductionOrder.Insert(true);
+ ProductionOrder.Validate("Source Type", SourceType);
+ ProductionOrder.Validate("Source No.", SourceNo);
+ ProductionOrder.Validate(Quantity, Quantity);
+ ProductionOrder.Modify(true);
+ end;
+
+ procedure CreateProductionOrderComponent(var ProdOrderComponent: Record "Prod. Order Component"; Status: Enum "Production Order Status"; ProdOrderNo: Code[20]; ProdOrderLineNo: Integer)
+ var
+ RecRef: RecordRef;
+ begin
+ ProdOrderComponent.Init();
+ ProdOrderComponent.Validate(Status, Status);
+ ProdOrderComponent.Validate("Prod. Order No.", ProdOrderNo);
+ ProdOrderComponent.Validate("Prod. Order Line No.", ProdOrderLineNo);
+ RecRef.GetTable(ProdOrderComponent);
+ ProdOrderComponent.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, ProdOrderComponent.FieldNo("Line No.")));
+ ProdOrderComponent.Insert(true);
+ end;
+
+ procedure CreateProductionOrderFromSalesOrder(SalesHeader: Record "Sales Header"; ProdOrderStatus: Enum "Production Order Status"; OrderType: Enum "Create Production Order Type")
+ var
+ SalesLine: Record "Sales Line";
+ CreateProdOrderFromSale: Codeunit "Create Prod. Order from Sale";
+ EndLoop: Boolean;
+ begin
+ SalesLine.SetRange("Document Type", SalesHeader."Document Type");
+ SalesLine.SetRange("Document No.", SalesHeader."No.");
+ SalesLine.FindSet();
+ repeat
+ CreateProdOrderFromSale.CreateProductionOrder(SalesLine, ProdOrderStatus, OrderType);
+ if OrderType = OrderType::ProjectOrder then
+ EndLoop := true;
+ until (SalesLine.Next() = 0) or EndLoop;
+ end;
+
+ procedure CreateProductionRouting(var Item: Record Item; NoOfLines: Integer)
+ var
+ MachineCenter: Record "Machine Center";
+ WorkCenter: Record "Work Center";
+ RoutingHeader: Record "Routing Header";
+ RoutingLine: Record "Routing Line";
+ "count": Integer;
+ begin
+ CreateRoutingHeader(RoutingHeader, RoutingHeader.Type::Serial);
+ CreateWorkCenter(WorkCenter);
+
+ for count := 1 to NoOfLines do
+ if count mod 2 = 0 then begin
+ RoutingLine.Validate(Type, RoutingLine.Type::"Work Center");
+ CreateRoutingLineSetup(RoutingLine, RoutingHeader, WorkCenter."No.",
+ CopyStr(
+ LibraryUtility.GenerateRandomCode(RoutingLine.FieldNo("Operation No."), DATABASE::"Routing Line"), 1,
+ LibraryUtility.GetFieldLength(DATABASE::"Routing Line", RoutingLine.FieldNo("Operation No."))),
+ LibraryRandom.RandDec(10, 2), LibraryRandom.RandDec(10, 2));
+ end else begin
+ CreateMachineCenter(MachineCenter, WorkCenter."No.", LibraryRandom.RandInt(5));
+ RoutingLine.Validate(Type, RoutingLine.Type::"Machine Center");
+ CreateRoutingLineSetup(RoutingLine, RoutingHeader, MachineCenter."No.",
+ CopyStr(
+ LibraryUtility.GenerateRandomCode(RoutingLine.FieldNo("Operation No."), DATABASE::"Routing Line"), 1,
+ LibraryUtility.GetFieldLength(DATABASE::"Routing Line", RoutingLine.FieldNo("Operation No."))),
+ LibraryRandom.RandDec(10, 2), LibraryRandom.RandDec(10, 2));
+ end;
+
+ RoutingHeader.Validate(Status, RoutingHeader.Status::Certified);
+ RoutingHeader.Modify(true);
+ Item.Validate("Routing No.", RoutingHeader."No.");
+ Item.Modify(true);
+ end;
+
+ procedure CreateRegisteredAbsence(var RegisteredAbsence: Record "Registered Absence"; CapacityType: Enum "Capacity Type"; No: Code[20]; Date: Date; StartingTime: Time; EndingTime: Time)
+ begin
+ RegisteredAbsence.Init();
+ RegisteredAbsence.Validate("Capacity Type", CapacityType);
+ RegisteredAbsence.Validate("No.", No);
+ RegisteredAbsence.Validate(Date, Date);
+ RegisteredAbsence.Validate("Starting Time", StartingTime);
+ RegisteredAbsence.Validate("Ending Time", EndingTime);
+ RegisteredAbsence.Insert(true);
+ end;
+
+ procedure CreateRoutingHeader(var RoutingHeader: Record "Routing Header"; Type: Option)
+ begin
+ LibraryUtility.UpdateSetupNoSeriesCode(
+ DATABASE::"Manufacturing Setup", ManufacturingSetup.FieldNo("Routing Nos."));
+
+ Clear(RoutingHeader);
+ RoutingHeader.Insert(true);
+ RoutingHeader.Validate(Type, Type);
+ RoutingHeader.Validate(Status, RoutingHeader.Status::New);
+ RoutingHeader.Modify(true);
+ end;
+
+ procedure CreateRoutingLine(var RoutingHeader: Record "Routing Header"; var RoutingLine: Record "Routing Line"; VersionCode: Code[20]; OperationNo: Code[10]; Type: Enum "Capacity Type Routing"; No: Code[20])
+ begin
+ RoutingLine.Init();
+ RoutingLine.Validate("Routing No.", RoutingHeader."No.");
+ RoutingLine.Validate("Version Code", VersionCode);
+ if OperationNo = '' then
+ OperationNo := LibraryUtility.GenerateRandomCode(RoutingLine.FieldNo("Operation No."), DATABASE::"Routing Line");
+ RoutingLine.Validate("Operation No.", OperationNo);
+ RoutingLine.Insert(true);
+ RoutingLine.Validate(Type, Type);
+ RoutingLine.Validate("No.", No);
+ RoutingLine.Modify(true);
+ end;
+
+ procedure CreateRoutingLineSetup(var RoutingLine: Record "Routing Line"; RoutingHeader: Record "Routing Header"; CenterNo: Code[20]; OperationNo: Code[10]; SetupTime: Decimal; RunTime: Decimal)
+ begin
+ // Create Routing Lines with required fields.
+ CreateRoutingLine(
+ RoutingHeader, RoutingLine, '', OperationNo, RoutingLine.Type, CenterNo);
+ RoutingLine.Validate("Setup Time", SetupTime);
+ RoutingLine.Validate("Run Time", RunTime);
+ RoutingLine.Validate("Concurrent Capacities", 1);
+ RoutingLine.Modify(true);
+ end;
+
+ procedure CreateRoutingLink(var RoutingLink: Record "Routing Link")
+ begin
+ RoutingLink.Init();
+ RoutingLink.Validate(Code, LibraryUtility.GenerateRandomCode(RoutingLink.FieldNo(Code), DATABASE::"Routing Link"));
+ RoutingLink.Insert(true);
+ end;
+
+ procedure CreateQualityMeasure(var QualityMeasure: Record "Quality Measure")
+ begin
+ QualityMeasure.Init();
+ QualityMeasure.Validate(Code, LibraryUtility.GenerateRandomCode(QualityMeasure.FieldNo(Code), DATABASE::"Quality Measure"));
+ QualityMeasure.Insert(true);
+ end;
+
+ procedure CreateRoutingQualityMeasureLine(var RoutingQualityMeasure: Record "Routing Quality Measure"; RoutingLine: Record "Routing Line"; QualityMeasure: Record "Quality Measure")
+ begin
+ RoutingQualityMeasure.Init();
+ RoutingQualityMeasure.Validate("Routing No.", RoutingLine."Routing No.");
+ RoutingQualityMeasure.Validate("Operation No.", RoutingLine."Operation No.");
+ RoutingQualityMeasure.Validate("Qlty Measure Code", QualityMeasure.Code);
+ RoutingQualityMeasure.Insert(true);
+ end;
+
+ procedure CreateRoutingVersion(var RoutingVersion: Record "Routing Version"; RoutingNo: Code[20]; VersionCode: Code[20])
+ begin
+ RoutingVersion.Init();
+ RoutingVersion.Validate("Routing No.", RoutingNo);
+ RoutingVersion.Validate("Version Code", VersionCode);
+ RoutingVersion.Insert(true);
+ end;
+
+ procedure CreateShopCalendarCode(var ShopCalendar: Record "Shop Calendar"): Code[10]
+ begin
+ ShopCalendar.Init();
+ ShopCalendar.Validate(Code, LibraryUtility.GenerateRandomCode(ShopCalendar.FieldNo(Code), DATABASE::"Shop Calendar"));
+ ShopCalendar.Insert(true);
+ exit(ShopCalendar.Code);
+ end;
+
+ local procedure CreateShopCalendarCustomTime(FromDay: Option; ToDay: Option; FromTime: Time; ToTime: Time): Code[10]
+ var
+ ShopCalendarWorkingDays: Record "Shop Calendar Working Days";
+ ShopCalendar: Record "Shop Calendar";
+ WorkShift: Record "Work Shift";
+ ShopCalendarCode: Code[10];
+ WorkShiftCode: Code[10];
+ Day: Integer;
+ begin
+ // Create Shop Calendar Working Days.
+ ShopCalendarCode := CreateShopCalendarCode(ShopCalendar);
+ WorkShiftCode := CreateWorkShiftCode(WorkShift);
+ ShopCalendarWorkingDays.SetRange("Shop Calendar Code", ShopCalendarCode);
+
+ for Day := FromDay to ToDay do
+ CreateShopCalendarWorkingDays(
+ ShopCalendarWorkingDays, ShopCalendarCode, Day, WorkShiftCode, FromTime, ToTime);
+
+ exit(ShopCalendarCode);
+ end;
+
+ procedure CreateShopCalendarWorkingDays(var ShopCalendarWorkingDays: Record "Shop Calendar Working Days"; ShopCalendarCode: Code[10]; Day: Option; WorkShiftCode: Code[10]; StartingTime: Time; EndingTime: Time)
+ begin
+ ShopCalendarWorkingDays.Init();
+ ShopCalendarWorkingDays.Validate("Shop Calendar Code", ShopCalendarCode);
+ ShopCalendarWorkingDays.Validate(Day, Day);
+ ShopCalendarWorkingDays.Validate("Starting Time", StartingTime);
+ ShopCalendarWorkingDays.Validate("Ending Time", EndingTime);
+ ShopCalendarWorkingDays.Validate("Work Shift Code", WorkShiftCode);
+ ShopCalendarWorkingDays.Insert(true);
+ end;
+
+ procedure CreateStandardTask(var StandardTask: Record "Standard Task")
+ begin
+ StandardTask.Init();
+ StandardTask.Validate(Code, LibraryUtility.GenerateRandomCode(StandardTask.FieldNo(Code), DATABASE::"Standard Task"));
+ StandardTask.Insert(true);
+ end;
+
+ procedure CreateWorkCenter(var WorkCenter: Record "Work Center")
+ begin
+ CreateWorkCenterCustomTime(WorkCenter, 080000T, 160000T);
+ end;
+
+ procedure CreateWorkCenterCustomTime(var WorkCenter: Record "Work Center"; FromTime: Time; ToTime: Time)
+ begin
+ CreateWorkCenterWithoutShopCalendar(WorkCenter);
+ WorkCenter.Validate(
+ "Shop Calendar Code", UpdateShopCalendarWorkingDaysCustomTime(FromTime, ToTime));
+ WorkCenter.Modify(true);
+ end;
+
+ procedure CreateWorkCenterFullWorkingWeek(var WorkCenter: Record "Work Center"; FromTime: Time; ToTime: Time)
+ begin
+ CreateWorkCenterWithoutShopCalendar(WorkCenter);
+ WorkCenter.Validate(
+ "Shop Calendar Code", UpdateShopCalendarFullWorkingWeekCustomTime(FromTime, ToTime));
+ WorkCenter.Modify(true);
+ end;
+
+ procedure CreateWorkCenterGroup(var WorkCenterGroup: Record "Work Center Group")
+ begin
+ WorkCenterGroup.Init();
+ WorkCenterGroup.Validate(Code, LibraryUtility.GenerateRandomCode(WorkCenterGroup.FieldNo(Code), DATABASE::"Work Center Group"));
+ WorkCenterGroup.Insert(true);
+ end;
+
+ procedure CreateWorkCenterWithCalendar(var WorkCenter: Record "Work Center")
+ begin
+ CreateWorkCenter(WorkCenter);
+ CalculateWorkCenterCalendar(WorkCenter, CalcDate('<-1M>', WorkDate()), CalcDate('<1M>', WorkDate()));
+ end;
+
+ local procedure CreateWorkCenterWithoutShopCalendar(var WorkCenter: Record "Work Center")
+ var
+ GeneralPostingSetup: Record "General Posting Setup";
+ CapacityUnitOfMeasure: Record "Capacity Unit of Measure";
+ WorkCenterGroup: Record "Work Center Group";
+ begin
+ CreateWorkCenterGroup(WorkCenterGroup);
+ CreateCapacityUnitOfMeasure(CapacityUnitOfMeasure, CapacityUnitOfMeasure.Type::Minutes);
+ LibraryERM.FindGeneralPostingSetupInvtToGL(GeneralPostingSetup);
+ LibraryUtility.UpdateSetupNoSeriesCode(
+ DATABASE::"Manufacturing Setup", ManufacturingSetup.FieldNo("Work Center Nos."));
+
+ Clear(WorkCenter);
+ WorkCenter.Insert(true);
+ WorkCenter.Validate("Work Center Group Code", WorkCenterGroup.Code);
+ WorkCenter.Validate("Unit of Measure Code", CapacityUnitOfMeasure.Code);
+ WorkCenter.Validate("Gen. Prod. Posting Group", GeneralPostingSetup."Gen. Prod. Posting Group");
+ WorkCenter.Modify(true);
+ end;
+
+ procedure CreateWorkShiftCode(var WorkShift: Record "Work Shift"): Code[10]
+ begin
+ WorkShift.Init();
+ WorkShift.Validate(Code, LibraryUtility.GenerateRandomCode(WorkShift.FieldNo(Code), DATABASE::"Work Shift"));
+ WorkShift.Insert(true);
+ exit(WorkShift.Code);
+ end;
+
+ procedure CreateInboundWhseReqFromProdOrder(ProductionOrder: Record "Production Order")
+ var
+ WhseOutputProdRelease: Codeunit "Whse.-Output Prod. Release";
+ begin
+ if WhseOutputProdRelease.CheckWhseRqst(ProductionOrder) then
+ Message(Text005Msg)
+ else begin
+ Clear(WhseOutputProdRelease);
+ if WhseOutputProdRelease.Release(ProductionOrder) then
+ Message(Text003Msg)
+ else
+ Message(Text004Msg);
+ end;
+ end;
+
+ procedure CreateWhsePickFromProduction(ProductionOrder: Record "Production Order")
+ begin
+ ProductionOrder.SetHideValidationDialog(true);
+ ProductionOrder.CreatePick(CopyStr(UserId(), 1, 50), 0, false, false, false);
+ end;
+
+ procedure OpenProductionJournal(ProductionOrder: Record "Production Order"; ProductionOrderLineNo: Integer)
+ var
+ ProductionJournalMgt: Codeunit "Production Journal Mgt";
+ begin
+ ProductionJournalMgt.Handling(ProductionOrder, ProductionOrderLineNo);
+ end;
+
+ procedure OutputJournalExplodeRouting(ProductionOrder: Record "Production Order")
+ var
+ ItemJournalLine: Record "Item Journal Line";
+ ItemJournalTemplate: Record "Item Journal Template";
+ ItemJournalBatch: Record "Item Journal Batch";
+ begin
+ ItemJournalTemplate.SetRange(Type, ItemJournalTemplate.Type::Output);
+ ItemJournalTemplate.FindFirst();
+ ItemJournalBatch.SetRange("Journal Template Name", ItemJournalTemplate.Name);
+ ItemJournalBatch.FindFirst();
+ LibraryInventory.CreateItemJournalLine(
+ ItemJournalLine, ItemJournalBatch."Journal Template Name", ItemJournalBatch.Name,
+ ItemJournalLine."Entry Type"::Output, '', 0);
+ ItemJournalLine.Validate("Order Type", ItemJournalLine."Order Type"::Production);
+ ItemJournalLine.Validate("Order No.", ProductionOrder."No.");
+ ItemJournalLine.Modify(true);
+ CODEUNIT.Run(CODEUNIT::"Output Jnl.-Expl. Route", ItemJournalLine);
+ end;
+
+ procedure OutputJnlExplodeRoute(var ItemJournalLine: Record "Item Journal Line")
+ var
+ OutputJnlExplRouteCodeunit: Codeunit "Output Jnl.-Expl. Route";
+ begin
+ Clear(OutputJnlExplRouteCodeunit);
+ OutputJnlExplRouteCodeunit.Run(ItemJournalLine);
+ end;
+
+ procedure OutputJournalExplodeOrderLineRouting(var ItemJournalBatch: Record "Item Journal Batch"; ProdOrderLine: Record "Prod. Order Line"; PostingDate: Date)
+ var
+ ItemJournalLine: Record "Item Journal Line";
+ ItemJournalTemplate: Record "Item Journal Template";
+ begin
+ ItemJournalTemplate.SetRange(Type, ItemJournalTemplate.Type::Output);
+ ItemJournalTemplate.FindFirst();
+ ItemJournalBatch.SetRange("Journal Template Name", ItemJournalTemplate.Name);
+ ItemJournalBatch.FindFirst();
+ LibraryInventory.CreateItemJournalLine(
+ ItemJournalLine, ItemJournalBatch."Journal Template Name", ItemJournalBatch.Name,
+ ItemJournalLine."Entry Type"::Output, '', 0);
+ ItemJournalLine.Validate("Posting Date", PostingDate);
+ ItemJournalLine.Validate("Order Type", ItemJournalLine."Order Type"::Production);
+ ItemJournalLine.Validate("Order No.", ProdOrderLine."Prod. Order No.");
+ ItemJournalLine.Validate("Order Line No.", ProdOrderLine."Line No.");
+ ItemJournalLine.Modify(true);
+ CODEUNIT.Run(CODEUNIT::"Output Jnl.-Expl. Route", ItemJournalLine);
+ end;
+
+ procedure PostConsumptionJournal()
+ var
+ ItemJournalTemplate: Record "Item Journal Template";
+ ItemJournalBatch: Record "Item Journal Batch";
+ begin
+ ItemJournalTemplate.SetRange(Type, ItemJournalTemplate.Type::Consumption);
+ ItemJournalTemplate.FindFirst();
+ ItemJournalBatch.SetRange("Journal Template Name", ItemJournalTemplate.Name);
+ ItemJournalBatch.FindFirst();
+ LibraryInventory.PostItemJournalLine(ItemJournalBatch."Journal Template Name", ItemJournalBatch.Name);
+ end;
+
+ procedure PostOutputJournal()
+ var
+ ItemJournalTemplate: Record "Item Journal Template";
+ ItemJournalBatch: Record "Item Journal Batch";
+ begin
+ ItemJournalTemplate.SetRange(Type, ItemJournalTemplate.Type::Output);
+ ItemJournalTemplate.FindFirst();
+ ItemJournalBatch.SetRange("Journal Template Name", ItemJournalTemplate.Name);
+ ItemJournalBatch.FindFirst();
+ LibraryInventory.PostItemJournalLine(ItemJournalBatch."Journal Template Name", ItemJournalBatch.Name);
+ end;
+
+ procedure RefreshProdOrder(var ProductionOrder: Record "Production Order"; Forward: Boolean; CalcLines: Boolean; CalcRoutings: Boolean; CalcComponents: Boolean; CreateInbRqst: Boolean)
+ var
+ TmpProductionOrder: Record "Production Order";
+ RefreshProductionOrder: Report "Refresh Production Order";
+ TempTransactionType: TransactionType;
+ Direction: Option Forward,Backward;
+ begin
+ Commit();
+ TempTransactionType := CurrentTransactionType;
+ CurrentTransactionType(TRANSACTIONTYPE::Update);
+
+ if Forward then
+ Direction := Direction::Forward
+ else
+ Direction := Direction::Backward;
+ if ProductionOrder.HasFilter then
+ TmpProductionOrder.CopyFilters(ProductionOrder)
+ else begin
+ ProductionOrder.Get(ProductionOrder.Status, ProductionOrder."No.");
+ TmpProductionOrder.SetRange(Status, ProductionOrder.Status);
+ TmpProductionOrder.SetRange("No.", ProductionOrder."No.");
+ end;
+ RefreshProductionOrder.InitializeRequest(Direction, CalcLines, CalcRoutings, CalcComponents, CreateInbRqst);
+ RefreshProductionOrder.SetTableView(TmpProductionOrder);
+ RefreshProductionOrder.UseRequestPage := false;
+ RefreshProductionOrder.RunModal();
+
+ Commit();
+ CurrentTransactionType(TempTransactionType);
+ end;
+
+ procedure RunReplanProductionOrder(var ProductionOrder: Record "Production Order"; NewDirection: Option; NewCalcMethod: Option)
+ var
+ TmpProductionOrder: Record "Production Order";
+ ReplanProductionOrder: Report "Replan Production Order";
+ begin
+ Commit();
+ ReplanProductionOrder.InitializeRequest(NewDirection, NewCalcMethod);
+ if ProductionOrder.HasFilter then
+ TmpProductionOrder.CopyFilters(ProductionOrder)
+ else begin
+ ProductionOrder.Get(ProductionOrder.Status, ProductionOrder."No.");
+ TmpProductionOrder.SetRange(Status, ProductionOrder.Status);
+ TmpProductionOrder.SetRange("No.", ProductionOrder."No.");
+ end;
+ ReplanProductionOrder.SetTableView(TmpProductionOrder);
+ ReplanProductionOrder.UseRequestPage(false);
+ ReplanProductionOrder.RunModal();
+ end;
+
+ procedure RunRollUpStandardCost(var Item: Record Item; StandardCostWorksheetName: Code[10])
+ var
+ Item2: Record Item;
+ RollUpStandardCost: Report "Roll Up Standard Cost";
+ begin
+ Commit();
+ if Item.HasFilter then
+ Item2.CopyFilters(Item)
+ else begin
+ Item2.Get(Item."No.");
+ Item2.SetRange("No.", Item."No.");
+ end;
+ RollUpStandardCost.SetTableView(Item2);
+ RollUpStandardCost.SetStdCostWksh(StandardCostWorksheetName);
+ RollUpStandardCost.UseRequestPage(false);
+ RollUpStandardCost.RunModal();
+ end;
+
+ local procedure RequisitionLineForSubcontractOrder(var RequisitionLine: Record "Requisition Line")
+ var
+ ReqJnlManagement: Codeunit ReqJnlManagement;
+ JnlSelected: Boolean;
+ Handled: Boolean;
+ begin
+ ReqJnlManagement.WkshTemplateSelection(PAGE::"Subcontracting Worksheet", false, "Req. Worksheet Template Type"::"For. Labor", RequisitionLine, JnlSelected);
+ if not JnlSelected then
+ Error('');
+ RequisitionLine."Worksheet Template Name" := CopyStr(Format("Req. Worksheet Template Type"::"For. Labor"), 1, MaxStrLen(RequisitionLine."Worksheet Template Name"));
+ RequisitionLine."Journal Batch Name" := BatchName;
+ OnBeforeOpenJournal(RequisitionLine, Handled);
+ if Handled then
+ exit;
+ ReqJnlManagement.OpenJnl(RequisitionLine."Journal Batch Name", RequisitionLine);
+ end;
+
+ procedure SuggestCapacityStandardCost(var WorkCenter: Record "Work Center"; var MachineCenter: Record "Machine Center"; StandardCostWorksheetName: Code[10]; StandardCostAdjustmentFactor: Integer; StandardCostRoundingMethod: Code[10])
+ var
+ TmpWorkCenter: Record "Work Center";
+ TmpMachineCenter: Record "Machine Center";
+ SuggestCapacityStandardCostReport: Report "Suggest Capacity Standard Cost";
+ begin
+ Clear(SuggestCapacityStandardCostReport);
+ SuggestCapacityStandardCostReport.Initialize(
+ StandardCostWorksheetName, StandardCostAdjustmentFactor, 0, 0, StandardCostRoundingMethod, '', '');
+ if WorkCenter.HasFilter then
+ TmpWorkCenter.CopyFilters(WorkCenter)
+ else begin
+ WorkCenter.Get(WorkCenter."No.");
+ TmpWorkCenter.SetRange("No.", WorkCenter."No.");
+ end;
+ SuggestCapacityStandardCostReport.SetTableView(TmpWorkCenter);
+
+ if MachineCenter.HasFilter then
+ TmpMachineCenter.CopyFilters(MachineCenter)
+ else begin
+ MachineCenter.Get(MachineCenter."No.");
+ TmpMachineCenter.SetRange("No.", MachineCenter."No.");
+ end;
+ SuggestCapacityStandardCostReport.SetTableView(TmpMachineCenter);
+ SuggestCapacityStandardCostReport.UseRequestPage(false);
+ SuggestCapacityStandardCostReport.Run();
+ end;
+
+ procedure UpdateManufacturingSetup(var ManufacturingSetup: Record "Manufacturing Setup"; ShowCapacityIn: Code[10]; ComponentsAtLocation: Code[10]; DocNoIsProdOrderNo: Boolean; CostInclSetup: Boolean; DynamicLowLevelCode: Boolean)
+ begin
+ // Update Manufacturing Setup.
+ ManufacturingSetup.Get();
+ ManufacturingSetup.Validate("Doc. No. Is Prod. Order No.", DocNoIsProdOrderNo);
+ ManufacturingSetup.Validate("Cost Incl. Setup", CostInclSetup);
+ ManufacturingSetup.Validate("Show Capacity In", ShowCapacityIn);
+ ManufacturingSetup.Validate("Components at Location", ComponentsAtLocation);
+ ManufacturingSetup.Validate("Dynamic Low-Level Code", DynamicLowLevelCode);
+ ManufacturingSetup.Modify(true);
+ end;
+
+ procedure UpdateOutputJournal(ProductionOrderNo: Code[20])
+ var
+ ItemJournalLine: Record "Item Journal Line";
+ ProdOrderRoutingLine: Record "Prod. Order Routing Line";
+ begin
+ ItemJournalLine.SetRange("Order Type", ItemJournalLine."Order Type"::Production);
+ ItemJournalLine.SetRange("Order No.", ProductionOrderNo);
+ ItemJournalLine.FindSet();
+ repeat
+ ProdOrderRoutingLine.SetRange("Routing No.", ItemJournalLine."Routing No.");
+ case ItemJournalLine.Type of
+ ItemJournalLine.Type::"Work Center":
+ ProdOrderRoutingLine.SetRange(Type, ProdOrderRoutingLine.Type::"Work Center");
+ ItemJournalLine.Type::"Machine Center":
+ ProdOrderRoutingLine.SetRange(Type, ProdOrderRoutingLine.Type::"Machine Center");
+ end;
+ ProdOrderRoutingLine.SetRange("No.", ItemJournalLine."No.");
+ ProdOrderRoutingLine.FindFirst();
+ ItemJournalLine.Validate("Setup Time", ProdOrderRoutingLine."Setup Time");
+ ItemJournalLine.Validate("Run Time", ProdOrderRoutingLine."Run Time");
+ ItemJournalLine.Modify(true);
+ until ItemJournalLine.Next() = 0;
+ end;
+
+ procedure UpdateProductionBOMStatus(var ProductionBOMHeader: Record "Production BOM Header"; NewStatus: Enum "BOM Status")
+ begin
+ ProductionBOMHeader.Validate(Status, NewStatus);
+ ProductionBOMHeader.Modify(true);
+ end;
+
+ procedure UpdateProductionBOMVersionStatus(var ProductionBOMVersion: Record "Production BOM Version"; NewStatus: Enum "BOM Status")
+ begin
+ ProductionBOMVersion.Validate(Status, NewStatus);
+ ProductionBOMVersion.Modify(true);
+ end;
+
+ procedure UpdateRoutingStatus(var RoutingHeader: Record "Routing Header"; NewStatus: Enum "Routing Status")
+ begin
+ RoutingHeader.Validate(Status, NewStatus);
+ RoutingHeader.Modify(true);
+ end;
+
+ procedure UpdateShopCalendarFullWorkingWeekCustomTime(FromTime: Time; ToTime: Time): Code[10]
+ var
+ ShopCalendarWorkingDays: Record "Shop Calendar Working Days";
+ begin
+ exit(CreateShopCalendarCustomTime(ShopCalendarWorkingDays.Day::Monday, ShopCalendarWorkingDays.Day::Sunday, FromTime, ToTime));
+ end;
+
+ procedure UpdateShopCalendarWorkingDays(): Code[10]
+ begin
+ // Create Shop Calendar Working Days using 8 hrs daily work shift.
+ exit(UpdateShopCalendarWorkingDaysCustomTime(080000T, 160000T));
+ end;
+
+ procedure UpdateShopCalendarWorkingDaysCustomTime(FromTime: Time; ToTime: Time): Code[10]
+ var
+ ShopCalendarWorkingDays: Record "Shop Calendar Working Days";
+ begin
+ exit(CreateShopCalendarCustomTime(ShopCalendarWorkingDays.Day::Monday, ShopCalendarWorkingDays.Day::Friday, FromTime, ToTime));
+ end;
+
+ procedure UpdateFinishOrderWithoutOutputInManufacturingSetup(FinishOrderWithoutOutput: Boolean)
+ begin
+ ManufacturingSetup.Get();
+ ManufacturingSetup.Validate("Finish Order without Output", FinishOrderWithoutOutput);
+ ManufacturingSetup.Modify(true);
+ end;
+
+ procedure UpdateUnitCost(var ProductionOrder: Record "Production Order"; CalcMethod: Option; UpdateReservations: Boolean)
+ var
+ TmpProductionOrder: Record "Production Order";
+ UpdateUnitCostReport: Report "Update Unit Cost";
+ begin
+ Clear(UpdateUnitCostReport);
+ UpdateUnitCostReport.InitializeRequest(CalcMethod, UpdateReservations);
+ if ProductionOrder.HasFilter then
+ TmpProductionOrder.CopyFilters(ProductionOrder)
+ else begin
+ ProductionOrder.Get(ProductionOrder.Status, ProductionOrder."No.");
+ TmpProductionOrder.SetRange(Status, ProductionOrder.Status);
+ TmpProductionOrder.SetRange("No.", ProductionOrder."No.");
+ end;
+ UpdateUnitCostReport.SetTableView(TmpProductionOrder);
+ UpdateUnitCostReport.UseRequestPage(false);
+ UpdateUnitCostReport.Run();
+ end;
+
+ procedure FindLastOperationNo(RoutingNo: Code[20]): Code[10]
+ var
+ RoutingLine: Record "Routing Line";
+ begin
+ RoutingLine.SetLoadFields("Routing No.", "Operation No.");
+ RoutingLine.SetRange("Routing No.", RoutingNo);
+ if RoutingLine.FindLast() then
+ exit(RoutingLine."Operation No.");
+ end;
+
+ procedure UpdateNonInventoryCostToProductionInManufacturingSetup(IncludeNonInventoryCostToProduction: Boolean)
+ begin
+ ManufacturingSetup.Get();
+ ManufacturingSetup.Validate("Inc. Non. Inv. Cost To Prod", IncludeNonInventoryCostToProduction);
+ ManufacturingSetup.Modify(true);
+ end;
+
+ procedure UpdateLoadSKUCostOnManufacturingInManufacturingSetup(LoadSKUCostOnManufacturing: Boolean)
+ begin
+ ManufacturingSetup.Get();
+ ManufacturingSetup.Validate("Load SKU Cost on Manufacturing", LoadSKUCostOnManufacturing);
+ ManufacturingSetup.Modify(true);
+ end;
+
+ [Normal]
+ procedure UpdateProdOrderLine(var ProdOrderLine: Record "Prod. Order Line"; FieldNo: Integer; Value: Variant)
+ var
+ RecRef: RecordRef;
+ FieldRef: FieldRef;
+ begin
+ RecRef.GetTable(ProdOrderLine);
+ FieldRef := RecRef.Field(FieldNo);
+ FieldRef.Validate(Value);
+ RecRef.SetTable(ProdOrderLine);
+ ProdOrderLine.Modify(true);
+ end;
+
+ [Normal]
+ procedure UpdateProdOrderComp(var ProdOrderComponent: Record "Prod. Order Component"; FieldNo: Integer; Value: Variant)
+ var
+ RecRef: RecordRef;
+ FieldRef: FieldRef;
+ begin
+ RecRef.GetTable(ProdOrderComponent);
+ FieldRef := RecRef.Field(FieldNo);
+ FieldRef.Validate(Value);
+ RecRef.SetTable(ProdOrderComponent);
+ ProdOrderComponent.Modify(true);
+ end;
+
+ [IntegrationEvent(false, false)]
+ local procedure OnBeforeOpenJournal(var RequisitionLine: Record "Requisition Line"; var Handled: Boolean)
+ begin
+ end;
+
+ // Move from Library Patterns
+
+ procedure CreateConsumptionJournalLine(var ItemJournalBatch: Record "Item Journal Batch"; ProdOrderLine: Record "Prod. Order Line"; ComponentItem: Record Item; PostingDate: Date; LocationCode: Code[10]; VariantCode: Code[10]; Qty: Decimal; UnitCost: Decimal)
+ var
+ ItemJournalLine: Record "Item Journal Line";
+ EntryType: Enum "Item Ledger Entry Type";
+ begin
+ LibraryInventory.CreateItemJournalBatchByType(ItemJournalBatch, ItemJournalBatch."Template Type"::Consumption);
+ EntryType := ItemJournalLine."Entry Type"::"Negative Adjmt.";
+ if ComponentItem.IsNonInventoriableType() then
+ EntryType := ItemJournalLine."Entry Type"::Consumption;
+ LibraryInventory.CreateItemJournalLine(
+ ItemJournalLine, ItemJournalBatch, ComponentItem, LocationCode, VariantCode, PostingDate,
+ EntryType, Qty, 0);
+ ItemJournalLine.Validate("Entry Type", ItemJournalLine."Entry Type"::Consumption);
+ ItemJournalLine.Validate("Order Type", ItemJournalLine."Order Type"::Production);
+ ItemJournalLine.Validate("Order No.", ProdOrderLine."Prod. Order No.");
+ ItemJournalLine.Validate("Order Line No.", ProdOrderLine."Line No.");
+ if ItemJournalLine."Location Code" <> LocationCode then // required for CH
+ ItemJournalLine.Validate("Location Code", LocationCode);
+ ItemJournalLine.Validate("Unit Cost", UnitCost);
+ ItemJournalLine.Modify(true);
+ end;
+
+ procedure CreateOutputJournalLine(var ItemJournalBatch: Record "Item Journal Batch"; ProdOrderLine: Record "Prod. Order Line"; PostingDate: Date; Qty: Decimal; UnitCost: Decimal)
+ var
+ ItemJournalLine: Record "Item Journal Line";
+ Item: Record Item;
+ RoutingLine: Record "Routing Line";
+ begin
+ LibraryInventory.CreateItemJournalBatchByType(ItemJournalBatch, ItemJournalBatch."Template Type"::Output);
+ Item.Get(ProdOrderLine."Item No.");
+ LibraryInventory.CreateItemJournalLine(
+ ItemJournalLine, ItemJournalBatch, Item, ProdOrderLine."Location Code", ProdOrderLine."Variant Code", PostingDate,
+ ItemJournalLine."Entry Type"::"Positive Adjmt.", 0, 0);
+ ItemJournalLine.Validate("Entry Type", ItemJournalLine."Entry Type"::Output);
+ ItemJournalLine.Validate("Order Type", ItemJournalLine."Order Type"::Production);
+ ItemJournalLine.Validate("Order No.", ProdOrderLine."Prod. Order No.");
+ ItemJournalLine.Validate("Order Line No.", ProdOrderLine."Line No.");
+ ItemJournalLine.Validate("Item No.", ProdOrderLine."Item No.");
+ RoutingLine.SetRange("Routing No.", ProdOrderLine."Routing No.");
+ if RoutingLine.FindFirst() then
+ ItemJournalLine.Validate("Operation No.", RoutingLine."Operation No.");
+ ItemJournalLine.Validate("Output Quantity", Qty);
+ ItemJournalLine.Validate("Unit Cost", UnitCost);
+ ItemJournalLine.Modify();
+ end;
+
+ procedure CreateProductionBOM(var ProductionBOMHeader: Record "Production BOM Header"; var ParentItem: Record Item; ChildItem: Record Item; ChildItemQtyPer: Decimal; RoutingLinkCode: Code[10])
+ var
+ ProductionBOMLine: Record "Production BOM Line";
+ begin
+ CreateProductionBOMHeader(ProductionBOMHeader, ParentItem."Base Unit of Measure");
+ CreateProductionBOMLine(
+ ProductionBOMHeader, ProductionBOMLine, '', ProductionBOMLine.Type::Item, ChildItem."No.", ChildItemQtyPer);
+ ProductionBOMLine.Validate("Routing Link Code", RoutingLinkCode);
+ ProductionBOMLine.Modify();
+
+ ProductionBOMHeader.Validate(Status, ProductionBOMHeader.Status::Certified);
+ ProductionBOMHeader.Modify();
+
+ ParentItem.Validate("Production BOM No.", ProductionBOMHeader."No.");
+ ParentItem.Modify();
+ end;
+
+ procedure CreateProductionOrder(var ProductionOrder: Record "Production Order"; ProdOrderStatus: Enum "Production Order Status"; Item: Record Item; LocationCode: Code[10]; VariantCode: Code[10]; Qty: Decimal; DueDate: Date)
+ var
+ ProdOrderLine: Record "Prod. Order Line";
+ NoSeries: Codeunit "No. Series";
+ ProdNoSeries: Code[20];
+ begin
+ ProdNoSeries := LibraryUtility.GetGlobalNoSeriesCode();
+ ManufacturingSetup.Get();
+ case ProdOrderStatus of
+ ProductionOrder.Status::Simulated:
+ if ManufacturingSetup."Simulated Order Nos." <> ProdNoSeries then begin
+ ManufacturingSetup."Simulated Order Nos." := ProdNoSeries;
+ ManufacturingSetup.Modify();
+ end;
+ ProductionOrder.Status::Planned:
+ if ManufacturingSetup."Planned Order Nos." <> ProdNoSeries then begin
+ ManufacturingSetup."Planned Order Nos." := ProdNoSeries;
+ ManufacturingSetup.Modify();
+ end;
+ ProductionOrder.Status::"Firm Planned":
+ if ManufacturingSetup."Firm Planned Order Nos." <> ProdNoSeries then begin
+ ManufacturingSetup."Firm Planned Order Nos." := ProdNoSeries;
+ ManufacturingSetup.Modify();
+ end;
+ ProductionOrder.Status::Released:
+ if ManufacturingSetup."Released Order Nos." <> ProdNoSeries then begin
+ ManufacturingSetup."Released Order Nos." := ProdNoSeries;
+ ManufacturingSetup.Modify();
+ end;
+ end;
+
+ Clear(ProductionOrder);
+ ProductionOrder."No." := NoSeries.GetNextNo(ProdNoSeries);
+ ProductionOrder.Status := ProdOrderStatus;
+ ProductionOrder.Validate("Source Type", ProductionOrder."Source Type"::Item);
+ ProductionOrder.Validate("Source No.", Item."No.");
+ ProductionOrder.Validate(Quantity, Qty);
+ ProductionOrder.Validate("Location Code", LocationCode);
+ ProductionOrder.Validate("Due Date", DueDate);
+ ProductionOrder.Insert(true);
+ RefreshProdOrder(ProductionOrder, false, true, true, true, true);
+ ProdOrderLine.SetRange(Status, ProductionOrder.Status);
+ ProdOrderLine.SetRange("Prod. Order No.", ProductionOrder."No.");
+ ProdOrderLine.ModifyAll("Variant Code", VariantCode);
+ end;
+
+ procedure CreateRouting(var RoutingHeader: Record "Routing Header"; var Item: Record Item; RoutingLinkCode: Code[10]; DirectUnitCost: Decimal)
+ var
+ RoutingLine: Record "Routing Line";
+ WorkCenter: Record "Work Center";
+ begin
+ CreateRoutingHeader(RoutingHeader, RoutingHeader.Type::Serial);
+
+ WorkCenter.FindFirst();
+ WorkCenter.Validate("Direct Unit Cost", DirectUnitCost);
+ WorkCenter.Modify();
+
+ CreateRoutingLine(RoutingHeader, RoutingLine, '', '', RoutingLine.Type::"Work Center", WorkCenter."No.");
+ RoutingLine.Validate("Routing Link Code", RoutingLinkCode);
+ RoutingLine.Validate("Run Time", 1);
+ RoutingLine.Modify();
+
+ RoutingHeader.Validate(Status, RoutingHeader.Status::Certified);
+ RoutingHeader.Modify();
+
+ Item.Validate("Routing No.", RoutingHeader."No.");
+ Item.Modify();
+ end;
+
+ procedure CreateRoutingforWorkCenter(var RoutingHeader: Record "Routing Header"; var Item: Record Item; WorkCenterNo: Code[20])
+ var
+ RoutingLine: Record "Routing Line";
+ begin
+ CreateRoutingHeader(RoutingHeader, RoutingHeader.Type::Serial);
+
+ CreateRoutingLine(RoutingHeader, RoutingLine, '', '', RoutingLine.Type::"Work Center", WorkCenterNo);
+ RoutingLine.Validate("Run Time", 1);
+ RoutingLine.Modify();
+
+ RoutingHeader.Validate(Status, RoutingHeader.Status::Certified);
+ RoutingHeader.Modify();
+
+ Item.Validate("Routing No.", RoutingHeader."No.");
+ Item.Modify();
+ end;
+
+ procedure CreateProdOrderUsingPlanning(var ProductionOrder: Record "Production Order"; Status: Enum "Production Order Status"; DocumentNo: Code[20]; SourceNo: Code[20])
+ var
+ SalesOrderPlanning: Page "Sales Order Planning";
+ begin
+ SalesOrderPlanning.SetSalesOrder(DocumentNo);
+ SalesOrderPlanning.BuildForm();
+ SalesOrderPlanning.CreateProdOrder();
+ Clear(ProductionOrder);
+ ProductionOrder.SetRange(Status, Status);
+ ProductionOrder.SetRange("Source No.", SourceNo);
+ ProductionOrder.FindLast();
+ end;
+
+ procedure CreatePlanningRoutingLine(var PlanningRoutingLine: Record "Planning Routing Line"; var RequisitionLine: Record "Requisition Line"; OperationNo: Code[10])
+ begin
+ PlanningRoutingLine.Init();
+ PlanningRoutingLine.Validate("Worksheet Template Name", RequisitionLine."Worksheet Template Name");
+ PlanningRoutingLine.Validate("Worksheet Batch Name", RequisitionLine."Journal Batch Name");
+ PlanningRoutingLine.Validate("Worksheet Line No.", RequisitionLine."Line No.");
+ PlanningRoutingLine.Validate("Operation No.", OperationNo);
+ PlanningRoutingLine.Insert(true);
+ end;
+
+ procedure PostConsumption(ProdOrderLine: Record "Prod. Order Line"; Item: Record Item; LocationCode: Code[10]; VariantCode: Code[10]; Qty: Decimal; PostingDate: Date; UnitCost: Decimal)
+ var
+ ItemJournalBatch: Record "Item Journal Batch";
+ begin
+ CreateConsumptionJournalLine(ItemJournalBatch, ProdOrderLine, Item, PostingDate, LocationCode, VariantCode, Qty, UnitCost);
+ LibraryInventory.PostItemJournalBatch(ItemJournalBatch);
+ end;
+
+ procedure PostOutput(ProdOrderLine: Record "Prod. Order Line"; Qty: Decimal; PostingDate: Date; UnitCost: Decimal)
+ var
+ ItemJournalBatch: Record "Item Journal Batch";
+ Item: Record Item;
+ begin
+ Item.Get(ProdOrderLine."Item No.");
+ CreateOutputJournalLine(ItemJournalBatch, ProdOrderLine, PostingDate, Qty, UnitCost);
+ LibraryInventory.PostItemJournalBatch(ItemJournalBatch);
+ end;
+
+ procedure CreateProdOrderItemTracking(var ReservEntry: Record "Reservation Entry"; ProdOrderLine: Record "Prod. Order Line"; SerialNo: Code[50]; LotNo: Code[50]; QtyBase: Decimal)
+ var
+ ItemTrackingSetup: Record "Item Tracking Setup";
+ begin
+ ItemTrackingSetup."Serial No." := SerialNo;
+ ItemTrackingSetup."Lot No." := LotNo;
+ CreateProdOrderItemTracking(ReservEntry, ProdOrderLine, ItemTrackingSetup, QtyBase);
+ end;
+
+ procedure CreateProdOrderItemTracking(var ReservEntry: Record "Reservation Entry"; ProdOrderLine: Record "Prod. Order Line"; ItemTrackingSetup: Record "Item Tracking Setup"; QtyBase: Decimal)
+ var
+ RecRef: RecordRef;
+ begin
+ RecRef.GetTable(ProdOrderLine);
+ LibraryItemTracking.ItemTracking(ReservEntry, RecRef, ItemTrackingSetup, QtyBase);
+ end;
+
+ procedure CreateProdOrderCompItemTracking(var ReservEntry: Record "Reservation Entry"; ProdOrderComp: Record "Prod. Order Component"; SerialNo: Code[50]; LotNo: Code[50]; QtyBase: Decimal)
+ var
+ ITemTrackingSetup: Record "Item Tracking Setup";
+ begin
+ ItemTrackingSetup."Serial No." := SerialNo;
+ ItemTrackingSetup."Lot No." := LotNo;
+ CreateProdOrderCompItemTracking(ReservEntry, ProdOrderComp, ITemTrackingSetup, QtyBase);
+ end;
+
+ procedure CreateProdOrderCompItemTracking(var ReservEntry: Record "Reservation Entry"; ProdOrderComp: Record "Prod. Order Component"; ItemTrackingSetup: Record "Item Tracking Setup"; QtyBase: Decimal)
+ var
+ RecRef: RecordRef;
+ begin
+ RecRef.GetTable(ProdOrderComp);
+ LibraryItemTracking.ItemTracking(ReservEntry, RecRef, ItemTrackingSetup, QtyBase);
+ end;
+
+ procedure PostOutputWithItemTracking(ProdOrderLine: Record "Prod. Order Line"; Qty: Decimal; RunTime: Decimal; PostingDate: Date; UnitCost: Decimal; SerialNo: Code[50]; LotNo: Code[50])
+ var
+ ItemJournalBatch: Record "Item Journal Batch";
+ ItemJournalLine: Record "Item Journal Line";
+ Item: Record Item;
+ ReservEntry: Record "Reservation Entry";
+ begin
+ Item.Get(ProdOrderLine."Item No.");
+ CreateOutputJournalLine(ItemJournalBatch, ProdOrderLine, PostingDate, Qty, UnitCost);
+ ItemJournalLine.SetRange("Journal Template Name", ItemJournalBatch."Journal Template Name");
+ ItemJournalLine.SetRange("Journal Batch Name", ItemJournalBatch.Name);
+ ItemJournalLine.FindFirst();
+ ItemJournalLine.Validate("Run Time", RunTime);
+ ItemJournalLine.Modify();
+ LibraryItemTracking.CreateItemJournalLineItemTracking(ReservEntry, ItemJournalLine, SerialNo, LotNo, Qty);
+ LibraryInventory.PostItemJournalBatch(ItemJournalBatch);
+ end;
+
+ procedure SetComponentsAtLocation(LocationCode: Code[10])
+ begin
+ ManufacturingSetup.Get();
+ ManufacturingSetup.Validate("Components at Location", LocationCode);
+ ManufacturingSetup.Modify();
+ end;
+
+ [EventSubscriber(ObjectType::Codeunit, Codeunit::"Library - Item Tracking", 'OnItemTracking', '', false, false)]
+ local procedure OnItemTracking(RecRef: RecordRef; var ReservEntry: Record "Reservation Entry"; ItemTrackingSetup: Record "Item Tracking Setup"; QtyBase: Decimal; sender: Codeunit "Library - Item Tracking")
+ var
+ ProdOrderLine: Record "Prod. Order Line";
+ ProdOrderCompLine: Record "Prod. Order Component";
+ begin
+ case RecRef.Number of
+ DATABASE::"Prod. Order Line":
+ begin
+ RecRef.SetTable(ProdOrderLine);
+ // COPY FROM COD 99000837: CallItemTracking
+ if ProdOrderLine.Status = ProdOrderLine.Status::Finished then
+ exit;
+ ProdOrderLine.TestField("Item No.");
+ // COPY END
+ sender.InsertItemTracking(
+ ReservEntry, ProdOrderLine.Quantity > 0,
+ ProdOrderLine."Item No.", ProdOrderLine."Location Code", ProdOrderLine."Variant Code",
+ QtyBase, ProdOrderLine."Qty. per Unit of Measure", ItemTrackingSetup,
+ DATABASE::"Prod. Order Line", ProdOrderLine.Status.AsInteger(), ProdOrderLine."Prod. Order No.",
+ '', ProdOrderLine."Line No.", 0, ProdOrderLine."Due Date");
+ end;
+ DATABASE::"Prod. Order Component":
+ begin
+ RecRef.SetTable(ProdOrderCompLine);
+ // COPY FROM COD 99000838: CallItemTracking
+ if ProdOrderCompLine.Status = ProdOrderCompLine.Status::Finished then
+ exit;
+ ProdOrderCompLine.TestField("Item No.");
+ // COPY END
+ sender.InsertItemTracking(
+ ReservEntry, ProdOrderCompLine.Quantity < 0,
+ ProdOrderCompLine."Item No.", ProdOrderCompLine."Location Code", ProdOrderCompLine."Variant Code",
+ -QtyBase, ProdOrderCompLine."Qty. per Unit of Measure", ItemTrackingSetup,
+ DATABASE::"Prod. Order Component", ProdOrderCompLine.Status.AsInteger(), ProdOrderCompLine."Prod. Order No.",
+ '', ProdOrderCompLine."Prod. Order Line No.", ProdOrderCompLine."Line No.", ProdOrderCompLine."Due Date");
+ end;
+ end;
+ end;
+
+ [EventSubscriber(ObjectType::Codeunit, Codeunit::"Library - Assembly", 'OnCreateMultipleLvlTreeOnCreateBOM', '', false, false)]
+ local procedure OnCreateMultipleLvlTreeOnCreateBOM(var Item: Record Item; NoOfComps: Integer; var BOMCreated: Boolean)
+ begin
+ if Item."Replenishment System" = Item."Replenishment System"::"Prod. Order" then begin
+ CreateProductionBOM(Item, NoOfComps);
+ BOMCreated := true;
+ end;
+ end;
+
+ [EventSubscriber(ObjectType::Codeunit, Codeunit::"Library - Dimension", 'OnGetTableNosWithGlobalDimensionCode', '', false, false)]
+ local procedure OnGetTableNosWithGlobalDimensionCode(var TableBuffer: Record "Integer" temporary; sender: Codeunit "Library - Dimension")
+ begin
+ sender.AddTable(TableBuffer, DATABASE::"Work Center");
+ end;
+}
diff --git a/Apps/W1/ApplicationTestLibrary/LibraryMarketing.Codeunit.al b/Apps/W1/ApplicationTestLibrary/LibraryMarketing.Codeunit.al
new file mode 100644
index 0000000000..6061fd0696
--- /dev/null
+++ b/Apps/W1/ApplicationTestLibrary/LibraryMarketing.Codeunit.al
@@ -0,0 +1,648 @@
+///
+/// Provides utility functions for creating and managing marketing-related entities in test scenarios, including contacts, campaigns, and segments.
+///
+codeunit 131900 "Library - Marketing"
+{
+
+ trigger OnRun()
+ begin
+ end;
+
+ var
+ LibraryUtility: Codeunit "Library - Utility";
+ LibraryRandom: Codeunit "Library - Random";
+ LibraryERM: Codeunit "Library - ERM";
+ LibrarySales: Codeunit "Library - Sales";
+ LibraryPurchase: Codeunit "Library - Purchase";
+
+ procedure CreateActivity(var Activity: Record Activity)
+ begin
+ Activity.Init();
+ Activity.Validate(Code, LibraryUtility.GenerateRandomCode(Activity.FieldNo(Code), DATABASE::Activity));
+ Activity.Validate(Description, Activity.Code); // Validating Code as Description because value is not important.
+ Activity.Insert(true);
+ end;
+
+ procedure CreateActivityStep(var ActivityStep: Record "Activity Step"; ActivityCode: Code[10])
+ var
+ RecRef: RecordRef;
+ begin
+ ActivityStep.Init();
+ ActivityStep.Validate("Activity Code", ActivityCode);
+ RecRef.GetTable(ActivityStep);
+ ActivityStep.Validate("Step No.", LibraryUtility.GetNewLineNo(RecRef, ActivityStep.FieldNo("Step No.")));
+ ActivityStep.Insert(true);
+ end;
+
+ procedure CreateAttachment(var Attachment: Record Attachment)
+ var
+ No: Integer;
+ begin
+ Clear(Attachment);
+
+ if Attachment.FindLast() then
+ No := Attachment."No." + 1;
+
+ Attachment.Init();
+ Attachment."No." := No;
+ Attachment.Insert(true);
+ end;
+
+ procedure CreateBusinessRelation(var BusinessRelation: Record "Business Relation")
+ begin
+ BusinessRelation.Init();
+ BusinessRelation.Validate(Code, LibraryUtility.GenerateRandomCode(BusinessRelation.FieldNo(Code), DATABASE::"Business Relation"));
+ BusinessRelation.Validate(Description, BusinessRelation.Code); // Validating Code as Description because value is not important.
+ BusinessRelation.Insert(true);
+ end;
+
+ procedure CreateCampaign(var Campaign: Record Campaign)
+ var
+ MarketingSetup: Record "Marketing Setup";
+ begin
+ MarketingSetup.Get();
+ if MarketingSetup."Campaign Nos." = '' then begin
+ MarketingSetup.Validate("Campaign Nos.", LibraryUtility.GetGlobalNoSeriesCode());
+ MarketingSetup.Modify(true);
+ end;
+
+ Clear(Campaign);
+ Campaign.Init();
+ Campaign.Insert(true);
+ Campaign.Validate(Description, Campaign."No."); // Validating No. as Description because value is not important.
+ Campaign.Modify(true);
+ end;
+
+ procedure CreateCampaignStatus(var CampaignStatus: Record "Campaign Status")
+ begin
+ CampaignStatus.Init();
+ CampaignStatus.Validate(Code, LibraryUtility.GenerateRandomCode(CampaignStatus.FieldNo(Code), DATABASE::"Campaign Status"));
+ CampaignStatus.Validate(Description, CampaignStatus.Code); // Validating Code as Description because value is not important.
+ CampaignStatus.Insert(true);
+ end;
+
+ procedure CreateCloseOpportunityCode(var CloseOpportunityCode: Record "Close Opportunity Code")
+ begin
+ CloseOpportunityCode.Init();
+ CloseOpportunityCode.Validate(
+ Code, LibraryUtility.GenerateRandomCode(CloseOpportunityCode.FieldNo(Code), DATABASE::"Close Opportunity Code"));
+ // Validating Code as Description because value is not important.
+ CloseOpportunityCode.Validate(Description, CloseOpportunityCode.Code);
+ CloseOpportunityCode.Insert(true);
+ end;
+
+ procedure CreateCompanyContact(var Contact: Record Contact)
+ begin
+ CreateContact(Contact, Contact.Type::Company);
+ end;
+
+ procedure CreateCompanyContactNo(): Code[20]
+ var
+ Contact: Record Contact;
+ begin
+ CreateCompanyContact(Contact);
+ exit(Contact."No.");
+ end;
+
+ procedure CreateCompanyContactTask(var Task: Record "To-do"; TaskType: Option)
+ var
+ Salesperson: Record "Salesperson/Purchaser";
+ begin
+ LibrarySales.CreateSalesperson(Salesperson);
+ Task.Init();
+ Task.Validate(Description, Salesperson.Code);
+ Task.Validate(Type, TaskType);
+ Task.Validate("Contact No.", CreateCompanyContactNo());
+ Task.Validate("Salesperson Code", Salesperson.Code);
+ Task.Validate(Date, WorkDate());
+ Task.Validate("Start Time", Time);
+ Task.Validate(Duration, LibraryRandom.RandIntInRange(60000, 60000000));
+ Task.Insert(true);
+ end;
+
+ procedure CreatePersonContact(var Contact: Record Contact)
+ begin
+ CreateContact(Contact, Contact.Type::Person);
+ end;
+
+ procedure CreatePersonContactNo(): Code[20]
+ var
+ Contact: Record Contact;
+ begin
+ CreatePersonContact(Contact);
+ exit(Contact."No.");
+ end;
+
+ [Scope('OnPrem')]
+ procedure CreatePersonContactWithCompanyNo(var Contact: Record Contact)
+ begin
+ CreatePersonContact(Contact);
+ Contact.Validate("Company No.", CreateCompanyContactNo());
+ Contact.Modify(true);
+ end;
+
+ local procedure CreateContact(var Contact: Record Contact; Type: Enum "Contact Type")
+ var
+ MarketingSetup: Record "Marketing Setup";
+ SalespersonPurchaser: Record "Salesperson/Purchaser";
+ begin
+ MarketingSetup.Get();
+ if MarketingSetup."Contact Nos." = '' then begin
+ MarketingSetup.Validate("Contact Nos.", LibraryUtility.GetGlobalNoSeriesCode());
+ MarketingSetup.Modify(true);
+ end;
+
+ SalespersonPurchaser.FindFirst();
+ Contact.Init();
+ Contact.Insert(true);
+ Contact.Validate(Name, Contact."No."); // Validating Name as No. because value is not important.
+ Contact.Validate("Salesperson Code", SalespersonPurchaser.Code);
+ Contact.Validate(Type, Type);
+ Contact.TypeChange();
+ Contact.Modify(true);
+ end;
+
+ procedure CreateContactAltAddress(var ContactAltAddress: Record "Contact Alt. Address"; ContactNo: Code[20])
+ begin
+ ContactAltAddress.Init();
+ ContactAltAddress.Validate("Contact No.", ContactNo);
+ ContactAltAddress.Validate(
+ Code, LibraryUtility.GenerateRandomCode(ContactAltAddress.FieldNo(Code), DATABASE::"Contact Alt. Address"));
+ ContactAltAddress.Insert(true);
+ end;
+
+ procedure CreateContactAltAddrDateRange(var ContactAltAddrDateRange: Record "Contact Alt. Addr. Date Range"; ContactNo: Code[20]; StartingDate: Date)
+ begin
+ ContactAltAddrDateRange.Init();
+ ContactAltAddrDateRange.Validate("Contact No.", ContactNo);
+ ContactAltAddrDateRange.Validate("Starting Date", StartingDate);
+ ContactAltAddrDateRange.Insert(true);
+ end;
+
+ procedure CreateContactBusinessRelation(var ContactBusinessRelation: Record "Contact Business Relation"; ContactNo: Code[20]; BusinessRelationCode: Code[10])
+ begin
+ ContactBusinessRelation.Init();
+ ContactBusinessRelation.Validate("Contact No.", ContactNo);
+ ContactBusinessRelation.Validate("Business Relation Code", BusinessRelationCode);
+ ContactBusinessRelation.Insert(true);
+ end;
+
+ procedure CreateContactIndustryGroup(var ContactIndustryGroup: Record "Contact Industry Group"; ContactNo: Code[20]; IndustryGroupCode: Code[10])
+ begin
+ ContactIndustryGroup.Init();
+ ContactIndustryGroup.Validate("Contact No.", ContactNo);
+ ContactIndustryGroup.Validate("Industry Group Code", IndustryGroupCode);
+ ContactIndustryGroup.Insert(true);
+ end;
+
+ procedure CreateContactJobResponsibility(var ContactJobResponsibility: Record "Contact Job Responsibility"; ContactNo: Code[20]; JobResponsibilityCode: Code[10])
+ begin
+ ContactJobResponsibility.Init();
+ ContactJobResponsibility.Validate("Contact No.", ContactNo);
+ ContactJobResponsibility.Validate("Job Responsibility Code", JobResponsibilityCode);
+ ContactJobResponsibility.Insert(true);
+ end;
+
+ procedure CreateContactMailingGroup(var ContactMailingGroup: Record "Contact Mailing Group"; ContactNo: Code[20]; MailingGroupCode: Code[10])
+ begin
+ ContactMailingGroup.Init();
+ ContactMailingGroup.Validate("Contact No.", ContactNo);
+ ContactMailingGroup.Validate("Mailing Group Code", MailingGroupCode);
+ ContactMailingGroup.Insert(true);
+ end;
+
+ procedure CreateContactWebSource(var ContactWebSource: Record "Contact Web Source"; ContactNo: Code[20]; WebSourceCode: Code[10])
+ begin
+ ContactWebSource.Init();
+ ContactWebSource.Validate("Contact No.", ContactNo);
+ ContactWebSource.Validate("Web Source Code", WebSourceCode);
+ ContactWebSource.Insert(true);
+ end;
+
+ procedure CreateBusinessRelationWithContact(var ContactBusinessRelation: Record "Contact Business Relation"; ContactNo: Code[20])
+ var
+ BusinessRelation: Record "Business Relation";
+ begin
+ CreateBusinessRelation(BusinessRelation);
+ CreateContactBusinessRelation(ContactBusinessRelation, ContactNo, BusinessRelation.Code);
+ ContactBusinessRelation."Link to Table" := ContactBusinessRelation."Link to Table"::Customer;
+ ContactBusinessRelation."No." := LibrarySales.CreateCustomerNo();
+ ContactBusinessRelation.Modify(true);
+ end;
+
+ procedure CreateBusinessRelationBetweenContactAndCustomer(var ContactBusinessRelation: Record "Contact Business Relation"; ContactNo: Code[20]; CustomerNo: Code[20])
+ var
+ BusinessRelation: Record "Business Relation";
+ begin
+ CreateBusinessRelation(BusinessRelation);
+ CreateContactBusinessRelation(ContactBusinessRelation, ContactNo, BusinessRelation.Code);
+ ContactBusinessRelation."Link to Table" := ContactBusinessRelation."Link to Table"::Customer;
+ ContactBusinessRelation."No." := CustomerNo;
+ ContactBusinessRelation.Modify(true);
+ end;
+
+ procedure CreateBusinessRelationBetweenContactAndVendor(var ContactBusinessRelation: Record "Contact Business Relation"; ContactNo: Code[20]; VendorNo: Code[20])
+ var
+ BusinessRelation: Record "Business Relation";
+ begin
+ CreateBusinessRelation(BusinessRelation);
+ CreateContactBusinessRelation(ContactBusinessRelation, ContactNo, BusinessRelation.Code);
+ ContactBusinessRelation."Link to Table" := ContactBusinessRelation."Link to Table"::Vendor;
+ ContactBusinessRelation."No." := VendorNo;
+ ContactBusinessRelation.Modify(true);
+ end;
+
+ procedure CreateContactWithCustomer(var Contact: Record Contact; var Customer: Record Customer)
+ var
+ ContactBusinessRelation: Record "Contact Business Relation";
+ begin
+ CreateCompanyContact(Contact);
+ LibrarySales.CreateCustomer(Customer);
+ CreateBusinessRelationBetweenContactAndCustomer(ContactBusinessRelation, Contact."No.", Customer."No.");
+ end;
+
+ procedure CreateContactWithVendor(var Contact: Record Contact; var Vendor: Record Vendor)
+ var
+ ContactBusinessRelation: Record "Contact Business Relation";
+ begin
+ CreateCompanyContact(Contact);
+ LibraryPurchase.CreateVendor(Vendor);
+ CreateBusinessRelationBetweenContactAndVendor(ContactBusinessRelation, Contact."No.", Vendor."No.");
+ end;
+
+ procedure CreateInteractionGroup(var InteractionGroup: Record "Interaction Group")
+ begin
+ InteractionGroup.Init();
+ InteractionGroup.Validate(Code, LibraryUtility.GenerateRandomCode(InteractionGroup.FieldNo(Code), DATABASE::"Interaction Group"));
+ InteractionGroup.Validate(Description, InteractionGroup.Code); // Validating Code as Description because value is not important.
+ InteractionGroup.Insert(true);
+ end;
+
+ procedure CreateInteractionLogEntry(var InteractionLogEntry: Record "Interaction Log Entry"; DocumentType: Enum "Interaction Log Entry Document Type"; DocumentNo: Code[20])
+ var
+ NextInteractLogEntryNo: Integer;
+ begin
+ NextInteractLogEntryNo := 1;
+ if InteractionLogEntry.FindLast() then
+ NextInteractLogEntryNo := InteractionLogEntry."Entry No." + 1;
+
+ InteractionLogEntry.Init();
+ InteractionLogEntry."Entry No." := NextInteractLogEntryNo;
+ InteractionLogEntry.Insert();
+ InteractionLogEntry."Document Type" := DocumentType;
+ InteractionLogEntry."Document No." := DocumentNo;
+ InteractionLogEntry."Version No." := 1;
+ InteractionLogEntry.Canceled := true;
+ InteractionLogEntry.Modify();
+ end;
+
+ procedure CreateInteractionTemplate(var InteractionTemplate: Record "Interaction Template")
+ var
+ InteractionGroup: Record "Interaction Group";
+ begin
+ InteractionGroup.FindFirst();
+ InteractionTemplate.Init();
+ InteractionTemplate.Validate(
+ Code, LibraryUtility.GenerateRandomCode(InteractionTemplate.FieldNo(Code), DATABASE::"Interaction Template"));
+ InteractionTemplate.Validate("Interaction Group Code", InteractionGroup.Code);
+ // Validating Code as Description because value is not important.
+ InteractionTemplate.Validate(Description, InteractionTemplate.Code + InteractionTemplate."Interaction Group Code");
+ InteractionTemplate.Validate("Correspondence Type (Default)", "Correspondence Type"::" ");
+ InteractionTemplate.Insert(true);
+ end;
+
+ procedure CreateJobResponsibility(var JobResponsibility: Record "Job Responsibility")
+ begin
+ JobResponsibility.Init();
+ JobResponsibility.Validate(
+ Code, LibraryUtility.GenerateRandomCode(JobResponsibility.FieldNo(Code), DATABASE::"Job Responsibility"));
+ JobResponsibility.Validate(Description, JobResponsibility.Code); // Validating Code as Description because value is not important.
+ JobResponsibility.Insert(true);
+ end;
+
+ procedure CreateMailingGroup(var MailingGroup: Record "Mailing Group")
+ begin
+ MailingGroup.Init();
+ MailingGroup.Validate(Code, LibraryUtility.GenerateRandomCode(MailingGroup.FieldNo(Code), DATABASE::"Mailing Group"));
+ MailingGroup.Validate(Description, MailingGroup.Code); // Validating Code as Description because value is not important.
+ MailingGroup.Insert(true);
+ end;
+
+ procedure CreateOpportunity(var Opportunity: Record Opportunity; ContactNo: Code[20])
+ var
+ Contact: Record Contact;
+ SalespersonPurchaser: Record "Salesperson/Purchaser";
+ SalesCycle: Record "Sales Cycle";
+ begin
+ Opportunity.Init();
+ Opportunity."No." := LibraryUtility.GenerateGUID();
+ Opportunity.Validate("Contact No.", ContactNo);
+ Contact.Get(ContactNo);
+ if Contact."Salesperson Code" <> '' then
+ SalespersonPurchaser.Code := Contact."Salesperson Code"
+ else
+ SalespersonPurchaser.FindFirst();
+ Opportunity.Validate("Salesperson Code", SalespersonPurchaser.Code);
+ Opportunity.Validate(Description, Opportunity."No." + Opportunity."Contact No.");
+ // Validating No. as Description because value is not important.
+ SalesCycle.FindFirst();
+ Opportunity.Validate("Sales Cycle Code", SalesCycle.Code);
+ Opportunity.Insert(true);
+ end;
+
+ procedure CreateQuestionnaireHeader(var ProfileQuestionnaireHeader: Record "Profile Questionnaire Header")
+ begin
+ ProfileQuestionnaireHeader.Init();
+ ProfileQuestionnaireHeader.Validate(
+ Code, LibraryUtility.GenerateRandomCode(ProfileQuestionnaireHeader.FieldNo(Code), DATABASE::"Profile Questionnaire Header"));
+
+ // Validating Code as Description because value is not important.
+ ProfileQuestionnaireHeader.Validate(Description, ProfileQuestionnaireHeader.Code);
+ ProfileQuestionnaireHeader.Insert(true);
+ end;
+
+ procedure CreateProfileQuestionnaireLine(var ProfileQuestionnaireLine: Record "Profile Questionnaire Line"; ProfileQuestionnaireCode: Code[20])
+ var
+ RecRef: RecordRef;
+ begin
+ ProfileQuestionnaireLine.Init();
+ ProfileQuestionnaireLine.Validate("Profile Questionnaire Code", ProfileQuestionnaireCode);
+ RecRef.GetTable(ProfileQuestionnaireLine);
+ // Use the function GetLastLineNo to get the value of the Line No. field.
+ ProfileQuestionnaireLine.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, ProfileQuestionnaireLine.FieldNo("Line No.")));
+ ProfileQuestionnaireLine.Insert(true);
+ end;
+
+ procedure CreateContactProfileAnswer(ContactNo: Code[20]; ProfileQuestionnaireCode: Code[20]; LineNo: Integer; NewProfileQuestionnaireValue: Text)
+ var
+ ContactProfileAnswer: Record "Contact Profile Answer";
+ begin
+ ContactProfileAnswer.Init();
+ ContactProfileAnswer.Validate("Contact No.", ContactNo);
+ ContactProfileAnswer.Validate("Profile Questionnaire Code", ProfileQuestionnaireCode);
+ ContactProfileAnswer.Validate("Line No.", LineNo);
+ ContactProfileAnswer.Validate("Profile Questionnaire Value", CopyStr(NewProfileQuestionnaireValue, 1, MaxStrLen(ContactProfileAnswer."Profile Questionnaire Value")));
+ ContactProfileAnswer.Insert(true);
+ end;
+
+ procedure CreateRlshpMgtCommentLine(var RlshpMgtCommentLine: Record "Rlshp. Mgt. Comment Line"; TableName: Enum "Rlshp. Mgt. Comment Line Table Name"; No: Code[20]; SubNo: Integer)
+ var
+ RecRef: RecordRef;
+ begin
+ RlshpMgtCommentLine.Init();
+ RlshpMgtCommentLine.Validate("Table Name", TableName);
+ RlshpMgtCommentLine.Validate("No.", No);
+ RlshpMgtCommentLine.Validate("Sub No.", SubNo);
+ RecRef.GetTable(RlshpMgtCommentLine);
+ RlshpMgtCommentLine.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, RlshpMgtCommentLine.FieldNo("Line No.")));
+ RlshpMgtCommentLine.Insert(true);
+ end;
+
+ procedure CreateRlshpMgtCommentContact(var RlshpMgtCommentLine: Record "Rlshp. Mgt. Comment Line"; ContactNo: Code[20])
+ begin
+ CreateRlshpMgtCommentLine(RlshpMgtCommentLine, RlshpMgtCommentLine."Table Name"::Contact, ContactNo, 0);
+ // Sub No. is 0 for Contact.
+ end;
+
+ procedure CreateRlshpMgtCommentSales(var RlshpMgtCommentLine: Record "Rlshp. Mgt. Comment Line"; SalesCycleCode: Code[10])
+ begin
+ CreateRlshpMgtCommentLine(RlshpMgtCommentLine, RlshpMgtCommentLine."Table Name"::"Sales Cycle", SalesCycleCode, 0);
+ // Sub No. is 0 for Sales Cycle.
+ end;
+
+ procedure CreateSalutation(var Salutation: Record Salutation)
+ begin
+ Salutation.Init();
+ Salutation.Validate(Code, LibraryUtility.GenerateRandomCode(Salutation.FieldNo(Code), DATABASE::Salutation));
+ Salutation.Validate(Description, Salutation.Code); // Validating Code as Description because value is not important.
+ Salutation.Insert(true);
+ end;
+
+ procedure CreateSalutationFormula(var SalutationFormula: Record "Salutation Formula"; SalutationCode: Code[10]; LanguageCode: Code[10]; SalutationType: Enum "Salutation Formula Salutation Type")
+ begin
+ SalutationFormula.Init();
+ SalutationFormula.Validate("Salutation Code", SalutationCode);
+ SalutationFormula.Validate("Language Code", LanguageCode);
+ SalutationFormula.Validate("Salutation Type", SalutationType);
+ SalutationFormula.Insert(true);
+ end;
+
+ procedure CreateSalesCycle(var SalesCycle: Record "Sales Cycle")
+ begin
+ SalesCycle.Init();
+ SalesCycle.Validate(Code, LibraryUtility.GenerateRandomCode(SalesCycle.FieldNo(Code), DATABASE::"Sales Cycle"));
+ SalesCycle.Validate(Description, SalesCycle.Code);
+ SalesCycle.Insert(true);
+ end;
+
+ procedure CreateSalesCycleStage(var SalesCycleStage: Record "Sales Cycle Stage"; SalesCycleCode: Code[10])
+ var
+ Stage: Integer;
+ begin
+ SalesCycleStage.SetRange("Sales Cycle Code", SalesCycleCode);
+ // Use 1 to Increase Stage.
+ if SalesCycleStage.FindLast() then
+ Stage := SalesCycleStage.Stage + 1
+ else
+ Stage := 1;
+ SalesCycleStage.Init();
+ SalesCycleStage.Validate("Sales Cycle Code", SalesCycleCode);
+ SalesCycleStage.Validate(Stage, Stage);
+ SalesCycleStage.Insert(true);
+ end;
+
+ procedure CreateSalesHeaderWithContact(var SalesHeader: Record "Sales Header"; SellToContactNo: Code[20]; SellToCustomerTemplateCode: Code[10])
+ begin
+ SalesHeader.Init();
+ SalesHeader.Insert(true);
+ SalesHeader.Validate("Sell-to Contact No.", SellToContactNo);
+ SalesHeader.Modify(true);
+ end;
+
+ procedure CreateSalesQuoteWithContact(var SalesHeader: Record "Sales Header"; SellToContactNo: Code[20]; SellToCustomerTemplateCode: Code[10])
+ begin
+ SalesHeader.Init();
+ SalesHeader.Insert(true);
+ SalesHeader.SetHideValidationDialog(true);
+ SalesHeader.Validate("Document Type", SalesHeader."Document Type"::Quote);
+ SalesHeader.Validate("Sell-to Contact No.", SellToContactNo);
+ SalesHeader.Modify(true);
+ end;
+
+ procedure CreateSalesLineDiscount(var SalesLineDiscount: Record "Sales Line Discount"; CampaignNo: Code[20]; ItemNo: Code[20])
+ begin
+ SalesLineDiscount.Init();
+ SalesLineDiscount.Validate(Type, SalesLineDiscount.Type::Item);
+ SalesLineDiscount.Validate(Code, ItemNo);
+ SalesLineDiscount.Validate("Sales Type", SalesLineDiscount."Sales Type"::Campaign);
+ SalesLineDiscount.Validate("Sales Code", CampaignNo);
+ SalesLineDiscount.Insert(true);
+ end;
+
+ procedure CreateSalesPriceForCampaign(var SalesPrice: Record "Sales Price"; ItemNo: Code[20]; CampaignNo: Code[20])
+ begin
+ SalesPrice.Init();
+ SalesPrice.Validate("Item No.", ItemNo);
+ SalesPrice.Validate("Sales Type", SalesPrice."Sales Type"::Campaign);
+ SalesPrice.Validate("Sales Code", CampaignNo);
+ SalesPrice.Insert(true);
+ end;
+
+ procedure CreateSegmentHeader(var SegmentHeader: Record "Segment Header")
+ var
+ MarketingSetup: Record "Marketing Setup";
+ begin
+ MarketingSetup.Get();
+ if MarketingSetup."Segment Nos." = '' then begin
+ MarketingSetup.Validate("Segment Nos.", LibraryUtility.GetGlobalNoSeriesCode());
+ MarketingSetup.Modify(true);
+ end;
+
+ SegmentHeader.Init();
+ SegmentHeader.Insert(true);
+ SegmentHeader.Validate(Description, SegmentHeader."No."); // Validating No. as Description because value is not important.
+ SegmentHeader.Modify(true);
+ end;
+
+ procedure CreateSegmentLine(var SegmentLine: Record "Segment Line"; SegmentHeaderNo: Code[20])
+ var
+ RecRef: RecordRef;
+ begin
+ SegmentLine.Init();
+ SegmentLine.Validate("Segment No.", SegmentHeaderNo);
+ RecRef.GetTable(SegmentLine);
+ SegmentLine.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, SegmentLine.FieldNo("Line No.")));
+ SegmentLine.Insert(true);
+ end;
+
+ procedure CreateTeam(var Team: Record Team)
+ begin
+ Team.Init();
+ Team.Validate(Code, LibraryUtility.GenerateRandomCode(Team.FieldNo(Code), DATABASE::Team));
+ Team.Insert(true);
+ end;
+
+ procedure CreateTeamSalesperson(var TeamSalesperson: Record "Team Salesperson"; TeamCode: Code[10]; SalespersonCode: Code[20])
+ begin
+ TeamSalesperson.Init();
+ TeamSalesperson.Validate("Team Code", TeamCode);
+ TeamSalesperson.Validate("Salesperson Code", SalespersonCode);
+ TeamSalesperson.Insert(true);
+ end;
+
+ procedure CreateTask(var Task: Record "To-do")
+ begin
+ Task.Init();
+ Task.Insert(true);
+ Task.Validate(Description, Task."No.");
+ Task.Modify(true);
+ end;
+
+ procedure CreateWebSource(var WebSource: Record "Web Source")
+ begin
+ WebSource.Init();
+ WebSource.Validate(Code, LibraryUtility.GenerateRandomCode(WebSource.FieldNo(Code), DATABASE::"Web Source"));
+ WebSource.Validate(Description, WebSource.Code); // Validating Code as Description because value is not important.
+ WebSource.Insert(true);
+ end;
+
+ procedure CreateEmailMergeCustomLayoutNo(): Code[20]
+ var
+ CustomReportLayout: Record "Custom Report Layout";
+ begin
+ CustomReportLayout.Init();
+ CustomReportLayout."Report ID" := REPORT::"Email Merge";
+ CustomReportLayout.Type := CustomReportLayout.Type::Word;
+ CustomReportLayout.Description := StrSubstNo('%1-%2', Format(REPORT::"Email Merge"), CustomReportLayout.Code);
+ CustomReportLayout.Insert(true);
+ exit(CustomReportLayout.Code);
+ end;
+
+ procedure CreateEmailMergeAttachment(var Attachment: Record Attachment) ContentBodyText: Text
+ begin
+ Attachment.Init();
+ Attachment."No." := LibraryUtility.GetNewRecNo(Attachment, Attachment.FieldNo("No."));
+ Attachment."Storage Type" := Attachment."Storage Type"::Embedded;
+ Attachment."File Extension" := 'HTML';
+ Attachment.Insert(true);
+
+ ContentBodyText := LibraryUtility.GenerateRandomAlphabeticText(LibraryRandom.RandIntInRange(2000, 3000), 0);
+ Attachment.WriteHTMLCustomLayoutAttachment(ContentBodyText, FindEmailMergeCustomLayoutName());
+ end;
+
+ procedure CreateIntrastatContact(CountryRegionCode: Code[10]): Code[20]
+ var
+ Contact: Record Contact;
+ begin
+ CreateCompanyContact(Contact);
+ Contact.Validate(Address, LibraryUtility.GenerateGUID());
+ Contact.Validate("Country/Region Code", CountryRegionCode);
+ Contact.Validate("Post Code", LibraryUtility.GenerateGUID());
+ Contact.Validate(City, LibraryUtility.GenerateGUID());
+ Contact.Validate("Phone No.", LibraryUtility.GenerateRandomPhoneNo());
+ Contact.Validate("Fax No.", LibraryUtility.GenerateGUID());
+ Contact.Validate("E-Mail", LibraryUtility.GenerateGUID() + '@' + LibraryUtility.GenerateGUID());
+ Contact.Modify(true);
+ exit(Contact."No.");
+ end;
+
+ procedure FindContact(var Contact: Record Contact)
+ begin
+ Contact.FindSet();
+ end;
+
+ procedure FindEmailMergeCustomLayoutNo(): Code[20]
+ var
+ CustomReportLayout: Record "Custom Report Layout";
+ begin
+ CustomReportLayout.SetRange("Report ID", REPORT::"Email Merge");
+ CustomReportLayout.SetFilter(Code, 'MS-*');
+ CustomReportLayout.FindFirst();
+ exit(CustomReportLayout.Code);
+ end;
+
+ procedure FindEmailMergeCustomLayoutName(): Text[250]
+ var
+ ReportLayoutList: Record "Report Layout List";
+ begin
+ ReportLayoutList.SetRange("Report ID", REPORT::"Email Merge");
+ ReportLayoutList.SetRange(Name, 'DefaultEmailMergeDoc.docx');
+ if ReportLayoutList.FindFirst() then
+ exit(ReportLayoutList.Name);
+ ReportLayoutList.SetRange(Name);
+ if ReportLayoutList.FindFirst() then
+ exit(ReportLayoutList.Name);
+ exit('');
+ end;
+
+ procedure RunAddContactsReport(LibraryVariableStorage: Codeunit "Library - Variable Storage"; UseRequestPage: Boolean)
+ var
+ AddContacts: Report "Add Contacts";
+ RecVar: Variant;
+ begin
+ while LibraryVariableStorage.Length() > 0 do begin
+ LibraryVariableStorage.Dequeue(RecVar);
+ AddContacts.SetTableView(RecVar);
+ end;
+ AddContacts.UseRequestPage(UseRequestPage);
+ AddContacts.RunModal();
+ end;
+
+ procedure UpdateContactAddress(var Contact: Record Contact)
+ var
+ CountryRegion: Record "Country/Region";
+ begin
+ Contact.Name := CopyStr(LibraryUtility.GenerateRandomText(10), 1, MaxStrLen(Contact.Name));
+ Contact.Address := CopyStr(LibraryUtility.GenerateRandomText(10), 1, MaxStrLen(Contact.Address));
+ Contact."Address 2" := CopyStr(LibraryUtility.GenerateRandomText(10), 1, MaxStrLen(Contact."Address 2"));
+ Contact."Post Code" := CopyStr(LibraryUtility.GenerateRandomText(10), 1, MaxStrLen(Contact."Post Code"));
+ Contact.City := CopyStr(LibraryUtility.GenerateRandomText(10), 1, MaxStrLen(Contact.City));
+ Contact.County := CopyStr(LibraryUtility.GenerateRandomText(10), 1, MaxStrLen(Contact.County));
+ LibraryERM.CreateCountryRegion(CountryRegion);
+ CountryRegion.Name := CopyStr(LibraryUtility.GenerateRandomText(10), 1, MaxStrLen(CountryRegion.Name));
+ CountryRegion.Modify();
+ Contact."Country/Region Code" := CountryRegion.Code;
+ Contact.Modify();
+ end;
+}
+
diff --git a/Apps/W1/ApplicationTestLibrary/LibraryNotificationMgt.Codeunit.al b/Apps/W1/ApplicationTestLibrary/LibraryNotificationMgt.Codeunit.al
new file mode 100644
index 0000000000..759a6dfe66
--- /dev/null
+++ b/Apps/W1/ApplicationTestLibrary/LibraryNotificationMgt.Codeunit.al
@@ -0,0 +1,83 @@
+///
+/// Provides utility functions for managing and handling notifications in test scenarios.
+///
+codeunit 132222 "Library - Notification Mgt."
+{
+
+ trigger OnRun()
+ begin
+ end;
+
+ procedure RecallNotificationsForRecord(RecVarToRecall: Variant)
+ var
+ RecRef: RecordRef;
+ begin
+ RecRef.GetTable(RecVarToRecall);
+ RecallNotificationsForRecordID(RecRef.RecordId);
+ end;
+
+ procedure RecallNotificationsForRecordID(RecordIDToRecall: RecordID)
+ var
+ NotificationLifecycleMgt: Codeunit "Notification Lifecycle Mgt.";
+ begin
+ NotificationLifecycleMgt.RecallNotificationsForRecord(RecordIDToRecall, false);
+ end;
+
+ procedure DisableAllNotifications()
+ begin
+ DisableImageAnalyzerNotifications();
+ DisableUpdateFinancialReportNotifications();
+ end;
+
+ local procedure DisableImageAnalyzerNotifications()
+ var
+ NAVAppInstalledApp: Record "NAV App Installed App";
+ begin
+ NAVAppInstalledApp.SetRange("App ID", 'e868ad92-21b8-4e08-af2b-8975a8b06e04'); // IMAGE ANALYZER app ID
+ if NAVAppInstalledApp.FindFirst() then
+ DisableNotification('e54eb2c9-ebc2-4934-91d9-97af900e89b2',
+ 'Image Analysis notification name',
+ 'Image Analysis notification description');
+ end;
+
+ local procedure DisableUpdateFinancialReportNotifications()
+ begin
+ DisableNotification('cc02b894-bef8-4945-8042-f177422f8906',
+ 'Update Financial Report Notification name',
+ 'Update Financial Report Notification description');
+ end;
+
+ local procedure DisableNotification(NotificationGuid: Guid; NotificationName: Text[128]; NotificationDescription: Text)
+ var
+ MyNotifications: Record "My Notifications";
+ begin
+ if MyNotifications.Get(UserId, NotificationGuid) then begin
+ MyNotifications.Enabled := false;
+ MyNotifications.Modify(true);
+ end else
+ MyNotifications.InsertDefault(
+ NotificationGuid,
+ NotificationName,
+ NotificationDescription,
+ false);
+ end;
+
+ procedure DisableMyNotification(NotificationID: Guid)
+ var
+ MyNotifications: Record "My Notifications";
+ begin
+ MyNotifications.InsertDefault(NotificationID, '', '', false);
+ MyNotifications.Disable(NotificationID);
+ end;
+
+ procedure ClearTemporaryNotificationContext()
+ var
+ TempNotificationContext: Record "Notification Context" temporary;
+ NotificationLifecycleMgt: Codeunit "Notification Lifecycle Mgt.";
+ begin
+ NotificationLifecycleMgt.GetTmpNotificationContext(TempNotificationContext);
+ TempNotificationContext.Reset();
+ TempNotificationContext.DeleteAll();
+ end;
+}
+
diff --git a/Apps/W1/ApplicationTestLibrary/LibraryPatterns.Codeunit.al b/Apps/W1/ApplicationTestLibrary/LibraryPatterns.Codeunit.al
new file mode 100644
index 0000000000..42078758b0
--- /dev/null
+++ b/Apps/W1/ApplicationTestLibrary/LibraryPatterns.Codeunit.al
@@ -0,0 +1,1371 @@
+///
+/// Provides utility functions implementing common test patterns for inventory, purchase, and sales scenarios.
+///
+codeunit 132212 "Library - Patterns"
+{
+
+ trigger OnRun()
+ begin
+ end;
+
+ var
+ LibraryCosting: Codeunit "Library - Costing";
+ LibraryERM: Codeunit "Library - ERM";
+ LibraryInventory: Codeunit "Library - Inventory";
+ LibraryPurchase: Codeunit "Library - Purchase";
+ LibrarySales: Codeunit "Library - Sales";
+ LibraryUtility: Codeunit "Library - Utility";
+ LibraryItemTracking: Codeunit "Library - Item Tracking";
+#if not CLEAN26
+ LibraryManufacturing: Codeunit "Library - Manufacturing";
+ LibraryWarehouse: Codeunit "Library - Warehouse";
+#endif
+ LibraryRandom: Codeunit "Library - Random";
+ Assert: Codeunit Assert;
+ TXTIncorrectEntry: Label 'Incorrect %1 in Entry No. %2.';
+ TXTUnexpectedLine: Label 'Unexpected line after getting posted line to reverse.';
+ TXTLineCountMismatch: Label 'Line count mismatch in revaluation for Item %1.';
+
+#if not CLEAN26
+ [Obsolete('Replaced by LibraryItemTracking.AddSerialNoTrackingInfo()', '26.0')]
+ procedure ADDSerialNoTrackingInfo(ItemNo: Code[20])
+ var
+ Item: Record Item;
+ begin
+ Item.Get(ItemNo);
+ LibraryItemTracking.AddSerialNoTrackingInfo(Item);
+ end;
+#endif
+
+#if not CLEAN26
+ [Obsolete('Moved to Library Purchase', '26.0')]
+ procedure ASSIGNPurchChargeToPurchRcptLine(PurchaseHeader: Record "Purchase Header"; PurchRcptLine: Record "Purch. Rcpt. Line"; Qty: Decimal; DirectUnitCost: Decimal)
+ begin
+ LibraryPurchase.AssignPurchChargeToPurchRcptLine(PurchaseHeader, PurchRcptLine, Qty, DirectUnitCost);
+ end;
+#endif
+
+#if not CLEAN26
+ [Obsolete('Moved to Library Purchase', '26.0')]
+ procedure ASSIGNPurchChargeToPurchInvoiceLine(PurchaseHeader: Record "Purchase Header"; PurchInvLine: Record "Purch. Inv. Line"; Qty: Decimal; DirectUnitCost: Decimal)
+ begin
+ LibraryPurchase.AssignPurchChargeToPurchInvoiceLine(PurchaseHeader, PurchInvLine, Qty, DirectUnitCost);
+ end;
+#endif
+
+#if not CLEAN26
+ [Obsolete('Moved to Library Purchase', '26.0')]
+ procedure ASSIGNPurchChargeToPurchaseLine(PurchaseHeader: Record "Purchase Header"; PurchaseLine: Record "Purchase Line"; Qty: Decimal; DirectUnitCost: Decimal)
+ begin
+ LibraryPurchase.AssignPurchChargeToPurchaseLine(PurchaseHeader, PurchaseLine, Qty, DirectUnitCost);
+ end;
+#endif
+
+#if not CLEAN26
+ [Obsolete('Moved to Library Purchase', '26.0')]
+ procedure ASSIGNPurchChargeToPurchReturnLine(PurchaseHeader: Record "Purchase Header"; PurchaseLine: Record "Purchase Line"; Qty: Decimal; DirectUnitCost: Decimal)
+ begin
+ LibraryPurchase.AssignPurchChargeToPurchReturnLine(PurchaseHeader, PurchaseLine, Qty, DirectUnitCost);
+ end;
+#endif
+
+#if not CLEAN26
+ [Obsolete('Moved to Library Sales', '26.0')]
+ procedure ASSIGNSalesChargeToSalesShptLine(SalesHeader: Record "Sales Header"; SalesShptLine: Record "Sales Shipment Line"; Qty: Decimal; UnitCost: Decimal)
+ begin
+ LibrarySales.AssignSalesChargeToSalesShptLine(SalesHeader, SalesShptLine, Qty, UnitCost);
+ end;
+#endif
+
+#if not CLEAN26
+ [Obsolete('Moved to Library Sales', '26.0')]
+ procedure ASSIGNSalesChargeToSalesLine(SalesHeader: Record "Sales Header"; SalesLine: Record "Sales Line"; Qty: Decimal; UnitCost: Decimal)
+ begin
+ LibrarySales.AssignSalesChargeToSalesLine(SalesHeader, SalesLine, Qty, UnitCost);
+ end;
+#endif
+
+#if not CLEAN26
+ [Obsolete('Moved to Library Sales', '26.0')]
+ procedure ASSIGNSalesChargeToSalesReturnLine(SalesHeader: Record "Sales Header"; SalesLine: Record "Sales Line"; Qty: Decimal; UnitCost: Decimal)
+ begin
+ LibrarySales.ASSIGNSalesChargeToSalesReturnLine(SalesHeader, SalesLine, Qty, UnitCost);
+ end;
+#endif
+
+#if not CLEAN26
+#pragma warning disable AL0801
+ [Obsolete('Moved to codeunit Library Manufacturing', '26.0')]
+ procedure MAKEConsumptionJournalLine(var ItemJournalBatch: Record "Item Journal Batch"; ProdOrderLine: Record "Prod. Order Line"; ComponentItem: Record Item; PostingDate: Date; LocationCode: Code[10]; VariantCode: Code[10]; Qty: Decimal; UnitCost: Decimal)
+ begin
+ LibraryManufacturing.CreateConsumptionJournalLine(ItemJournalBatch, ProdOrderLine, ComponentItem, PostingDate, LocationCode, VariantCode, Qty, UnitCost);
+ end;
+#pragma warning restore AL0801
+#endif
+
+#if not CLEAN26
+ [Obsolete('Moved to codeunit Library Inventory', '26.0')]
+ procedure MAKEItem(var Item: Record Item; CostingMethod: Enum "Costing Method"; UnitCost: Decimal; OverheadRate: Decimal; IndirectCostPercent: Decimal; ItemTrackingCode: Code[10])
+ begin
+ LibraryInventory.CreateItem(Item, CostingMethod, UnitCost, OverheadRate, IndirectCostPercent, ItemTrackingCode);
+ end;
+#endif
+
+#if not CLEAN26
+ [Obsolete('Moved to codeunit Library Inventory', '26.0')]
+ procedure MAKEItemSimple(var Item: Record Item; CostingMethod: Enum "Costing Method"; UnitCost: Decimal)
+ begin
+ LibraryInventory.CreateItemSimple(Item, CostingMethod, UnitCost);
+ end;
+#endif
+
+#if not CLEAN26
+ [Obsolete('Moved to codeunit Library Inventory', '26.0')]
+ procedure MAKEItemWithExtendedText(var Item: Record Item; ExtText: Text; CostingMethod: Enum "Costing Method"; UnitCost: Decimal)
+ begin
+ LibraryInventory.CreateItemWithExtendedText(Item, ExtText, CostingMethod, UnitCost);
+ end;
+#endif
+
+#if not CLEAN26
+ [Obsolete('Replaced by LibraryInventory.CreateItemUnitOfMeasureCode', '26.0')]
+ procedure MAKEAdditionalItemUOM(var NewItemUOM: Record "Item Unit of Measure"; ItemNo: Code[20]; QtyPer: Decimal)
+ begin
+ LibraryInventory.CreateItemUnitOfMeasureCode(NewItemUOM, ItemNo, QtyPer);
+ end;
+#endif
+
+#if not CLEAN26
+ [Obsolete('Moved to Library Purchase', '26.0')]
+ procedure MAKEItemChargePurchaseLine(var PurchaseLine: Record "Purchase Line"; var ItemCharge: Record "Item Charge"; PurchaseHeader: Record "Purchase Header"; Qty: Decimal; DirectUnitCost: Decimal)
+ begin
+ LibraryPurchase.CreateItemChargePurchaseLine(PurchaseLine, ItemCharge, PurchaseHeader, Qty, DirectUnitCost);
+ end;
+#endif
+
+#if not CLEAN26
+ [Obsolete('Moved to Library Purchase', '26.0')]
+ procedure MAKEItemChargeSalesLine(var SalesLine: Record "Sales Line"; var ItemCharge: Record "Item Charge"; SalesHeader: Record "Sales Header"; Qty: Decimal; UnitCost: Decimal)
+ begin
+ LibrarySales.CreateItemChargeSalesLine(SalesLine, ItemCharge, SalesHeader, Qty, UnitCost);
+ end;
+#endif
+
+#if not CLEAN26
+ [Obsolete('Moved to codeunit Library Inventory as CreateItemJournalLine', '26.0')]
+ procedure MAKEItemJournalLine(var ItemJournalLine: Record "Item Journal Line"; ItemJournalBatch: Record "Item Journal Batch"; Item: Record Item; LocationCode: Code[10]; VariantCode: Code[10]; PostingDate: Date; EntryType: Enum "Item Ledger Entry Type"; Qty: Decimal; UnitAmount: Decimal)
+ begin
+ LibraryInventory.CreateItemJournalLine(ItemJournalLine, ItemJournalBatch, Item, LocationCode, VariantCode, PostingDate, EntryType, Qty, UnitAmount);
+ end;
+#endif
+
+#if not CLEAN26
+ [Obsolete('Moved to codeunit Library Inventory', '26.0')]
+ procedure MAKEItemJournalLineWithApplication(var ItemJournalLine: Record "Item Journal Line"; ItemJournalBatch: Record "Item Journal Batch"; Item: Record Item; LocationCode: Code[10]; VariantCode: Code[10]; PostingDate: Date; EntryType: Enum "Item Ledger Entry Type"; Qty: Decimal; UnitAmount: Decimal; AppltoEntryNo: Integer)
+ begin
+ LibraryInventory.CreateItemJournalLineWithApplication(
+ ItemJournalLine, ItemJournalBatch, Item, LocationCode, VariantCode, PostingDate, EntryType, Qty, UnitAmount, AppltoEntryNo);
+ end;
+#endif
+
+#if not CLEAN26
+ [Obsolete('Moved to codeunit Library Inventory', '26.0')]
+ procedure MAKEItemReclassificationJournalLine(var ItemJournalLine: Record "Item Journal Line"; ItemJournalBatch: Record "Item Journal Batch"; Item: Record Item; VariantCode: Code[10]; LocationCode: Code[10]; NewLocationCode: Code[10]; BinCode: Code[20]; NewBinCode: Code[20]; PostingDate: Date; Quantity: Decimal)
+ begin
+ LibraryInventory.CreateItemReclassificationJournalLine(ItemJournalLine, ItemJournalBatch, Item, VariantCode, LocationCode, NewLocationCode, BinCode, NewBinCode, PostingDate, Quantity);
+ end;
+#endif
+
+#if not CLEAN26
+#pragma warning disable AL0801
+ [Obsolete('Moved to codeunit Library Manufacturing', '26.0')]
+ procedure MAKEOutputJournalLine(var ItemJournalBatch: Record "Item Journal Batch"; ProdOrderLine: Record "Prod. Order Line"; PostingDate: Date; Qty: Decimal; UnitCost: Decimal)
+ begin
+ LibraryManufacturing.CreateOutputJournalLine(ItemJournalBatch, ProdOrderLine, PostingDate, Qty, UnitCost);
+ end;
+#pragma warning restore AL0801
+#endif
+
+#if not CLEAN26
+#pragma warning disable AL0801
+ [Obsolete('Moved to codeunit Library Manufacturing', '26.0')]
+ procedure MAKEProductionBOM(var ProductionBOMHeader: Record "Production BOM Header"; var ParentItem: Record Item; ChildItem: Record Item; ChildItemQtyPer: Decimal; RoutingLinkCode: Code[10])
+ begin
+ LibraryManufacturing.CreateProductionBOM(ProductionBOMHeader, ParentItem, ChildItem, ChildItemQtyPer, RoutingLinkCode);
+ end;
+#pragma warning restore AL0801
+#endif
+
+#if not CLEAN26
+#pragma warning disable AL0801
+ [Obsolete('Moved to codeunit Library Manufacturing', '26.0')]
+ procedure MAKEProductionOrder(var ProductionOrder: Record "Production Order"; ProdOrderStatus: Enum "Production Order Status"; Item: Record Item; LocationCode: Code[10]; VariantCode: Code[10]; Qty: Decimal; DueDate: Date)
+ begin
+ LibraryManufacturing.CreateProductionOrder(ProductionOrder, ProdOrderStatus, Item, LocationCode, VariantCode, Qty, DueDate);
+ end;
+#pragma warning restore AL0801
+#endif
+
+#if not CLEAN26
+ [Obsolete('Moved to codeunit Library Manufacturing', '26.0')]
+ procedure MAKEPurchaseDoc(var PurchaseHeader: Record "Purchase Header"; var PurchaseLine: Record "Purchase Line"; DocType: Enum "Purchase Document Type"; Item: Record Item; LocationCode: Code[10]; VariantCode: Code[10]; Qty: Decimal; PostingDate: Date; DirectUnitCost: Decimal)
+ begin
+ LibraryPurchase.CreatePurchaseDocument(
+ PurchaseHeader, PurchaseLine, DocType, Item, LocationCode, VariantCode, Qty, PostingDate, DirectUnitCost);
+ end;
+#endif
+
+#if not CLEAN26
+ [Obsolete('Moved to codeunit Library Purchase', '26.0')]
+ procedure MAKEPurchaseOrder(var PurchaseHeader: Record "Purchase Header"; var PurchaseLine: Record "Purchase Line"; Item: Record Item; LocationCode: Code[10]; VariantCode: Code[10]; Qty: Decimal; PostingDate: Date; DirectUnitCost: Decimal)
+ begin
+ LibraryPurchase.CreatePurchaseOrder(
+ PurchaseHeader, PurchaseLine, Item, LocationCode, VariantCode, Qty, PostingDate, DirectUnitCost);
+ end;
+#endif
+
+#if not CLEAN26
+ [Obsolete('Moved to codeunit Library Purchase', '26.0')]
+ procedure MAKEPurchaseQuote(var PurchaseHeader: Record "Purchase Header"; var PurchaseLine: Record "Purchase Line"; Item: Record Item; LocationCode: Code[10]; VariantCode: Code[10]; Qty: Decimal; PostingDate: Date; DirectUnitCost: Decimal)
+ begin
+ LibraryPurchase.CreatePurchaseQuote(
+ PurchaseHeader, PurchaseLine, Item, LocationCode, VariantCode, Qty, PostingDate, DirectUnitCost);
+ end;
+#endif
+
+#if not CLEAN26
+ [Obsolete('Moved to codeunit Library Purchase', '26.0')]
+ procedure MAKEPurchaseBlanketOrder(var PurchaseHeader: Record "Purchase Header"; var PurchaseLine: Record "Purchase Line"; Item: Record Item; LocationCode: Code[10]; VariantCode: Code[10]; Qty: Decimal; PostingDate: Date; DirectUnitCost: Decimal)
+ begin
+ LibraryPurchase.CreatePurchaseBlanketOrder(
+ PurchaseHeader, PurchaseLine, Item, LocationCode, VariantCode, Qty, PostingDate, DirectUnitCost);
+ end;
+#endif
+
+#if not CLEAN26
+ [Obsolete('Moved to codeunit Library Purchase', '26.0')]
+ procedure MAKEPurchaseReturnOrder(var PurchaseHeader: Record "Purchase Header"; var PurchaseLine: Record "Purchase Line"; Item: Record Item; LocationCode: Code[10]; VariantCode: Code[10]; Qty: Decimal; PostingDate: Date; DirectUnitCost: Decimal)
+ begin
+ LibraryPurchase.CreatePurchaseReturnOrder(
+ PurchaseHeader, PurchaseLine, Item, LocationCode, VariantCode, Qty, PostingDate, DirectUnitCost);
+ end;
+#endif
+
+#if not CLEAN26
+ [Obsolete('Moved to codeunit Library Purchase', '26.0')]
+ procedure MAKEPurchaseCreditMemo(var PurchaseHeader: Record "Purchase Header"; var PurchaseLine: Record "Purchase Line"; Item: Record Item; LocationCode: Code[10]; VariantCode: Code[10]; Qty: Decimal; PostingDate: Date; DirectUnitCost: Decimal)
+ begin
+ LibraryPurchase.CreatePurchaseCreditMemo(
+ PurchaseHeader, PurchaseLine, Item, LocationCode, VariantCode, Qty, PostingDate, DirectUnitCost);
+ end;
+#endif
+
+#if not CLEAN26
+ [Obsolete('Moved to codeunit Library Purchase', '26.0')]
+ procedure MAKEPurchaseInvoice(var PurchaseHeader: Record "Purchase Header"; var PurchaseLine: Record "Purchase Line"; Item: Record Item; LocationCode: Code[10]; VariantCode: Code[10]; Qty: Decimal; PostingDate: Date; DirectUnitCost: Decimal)
+ begin
+ LibraryPurchase.CreatePurchaseInvoice(
+ PurchaseHeader, PurchaseLine, Item, LocationCode, VariantCode, Qty, PostingDate, DirectUnitCost);
+ end;
+#endif
+
+#if not CLEAN26
+ [Obsolete('Moved to codeunit Library Inventory', '26.0')]
+ procedure MAKERevaluationJournalLine(var ItemJournalBatch: Record "Item Journal Batch"; var Item: Record Item; NewPostingDate: Date; NewCalculatePer: Enum "Inventory Value Calc. Per"; NewByLocation: Boolean; NewByVariant: Boolean; NewUpdStdCost: Boolean; NewCalcBase: Enum "Inventory Value Calc. Base")
+ begin
+ LibraryInventory.CreateRevaluationJournalLine(ItemJournalBatch, Item, NewPostingDate, NewCalculatePer, NewByLocation, NewByVariant, NewUpdStdCost, NewCalcBase);
+ end;
+#endif
+
+#if not CLEAN26
+#pragma warning disable AL0801
+ [Obsolete('Moved to codeunit Library Manufacturing', '26.0')]
+ procedure MAKERouting(var RoutingHeader: Record "Routing Header"; var Item: Record Item; RoutingLinkCode: Code[10]; DirectUnitCost: Decimal)
+ begin
+ LibraryManufacturing.CreateRouting(RoutingHeader, Item, RoutingLinkCode, DirectUnitCost);
+ end;
+#pragma warning restore AL0801
+#endif
+
+#if not CLEAN26
+#pragma warning disable AL0801
+ [Obsolete('Moved to codeunit Library Manufacturing', '26.0')]
+ procedure MAKERoutingforWorkCenter(var RoutingHeader: Record "Routing Header"; var Item: Record Item; WorkCenterNo: Code[20])
+ begin
+ LibraryManufacturing.CreateRoutingforWorkCenter(RoutingHeader, Item, WorkCenterNo);
+ end;
+#pragma warning restore AL0801
+#endif
+
+#if not CLEAN26
+ [Obsolete('Moved to codeunit Library Sales procedure CreateSalesDocument()', '26.0')]
+ procedure MAKESalesDoc(var SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; DocType: Enum "Sales Document Type"; Item: Record Item; LocationCode: Code[10]; VariantCode: Code[10]; Qty: Decimal; PostingDate: Date; UnitPrice: Decimal)
+ begin
+ LibrarySales.CreateSalesDocument(
+ SalesHeader, SalesLine, DocType, Item, LocationCode, VariantCode, Qty, PostingDate, UnitPrice);
+ end;
+#endif
+
+#if not CLEAN26
+ [Obsolete('Moved to codeunit Library Sales procedure CreateSalesDocument()', '26.0')]
+ procedure MAKESalesOrder(var SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; Item: Record Item; LocationCode: Code[10]; VariantCode: Code[10]; Qty: Decimal; PostingDate: Date; UnitPrice: Decimal)
+ begin
+ LibrarySales.CreateSalesOrder(
+ SalesHeader, SalesLine, Item, LocationCode, VariantCode, Qty, PostingDate, UnitPrice);
+ end;
+#endif
+
+#if not CLEAN26
+ [Obsolete('Moved to codeunit Library Sales procedure CreateSalesInvoice()', '26.0')]
+ procedure MAKESalesInvoice(var SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; Item: Record Item; LocationCode: Code[10]; VariantCode: Code[10]; Qty: Decimal; PostingDate: Date; UnitPrice: Decimal)
+ begin
+ LibrarySales.CreateSalesInvoice(
+ SalesHeader, SalesLine, Item, LocationCode, VariantCode, Qty, PostingDate, UnitPrice);
+ end;
+#endif
+
+#if not CLEAN26
+ [Obsolete('Moved to codeunit Library Sales procedure CreateSalesQuote()', '26.0')]
+ procedure MAKESalesQuote(var SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; Item: Record Item; LocationCode: Code[10]; VariantCode: Code[10]; Qty: Decimal; PostingDate: Date; UnitPrice: Decimal)
+ begin
+ LibrarySales.CreateSalesQuote(
+ SalesHeader, SalesLine, Item, LocationCode, VariantCode, Qty, PostingDate, UnitPrice);
+ end;
+#endif
+
+#if not CLEAN26
+ [Obsolete('Moved to codeunit Library Sales procedure CreateBlanketSalesOrder()', '26.0')]
+ procedure MAKESalesBlanketOrder(var SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; Item: Record Item; LocationCode: Code[10]; VariantCode: Code[10]; Qty: Decimal; PostingDate: Date; UnitPrice: Decimal)
+ begin
+ LibrarySales.CreateSalesBlanketOrder(
+ SalesHeader, SalesLine, Item, LocationCode, VariantCode, Qty, PostingDate, UnitPrice);
+ end;
+#endif
+
+#if not CLEAN26
+ [Obsolete('Moved to codeunit Library Sales procedure CreateSalesReturnOrder()', '26.0')]
+ procedure MAKESalesReturnOrder(var SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; Item: Record Item; LocationCode: Code[10]; VariantCode: Code[10]; Qty: Decimal; PostingDate: Date; UnitCost: Decimal; UnitPrice: Decimal)
+ begin
+ LibrarySales.CreateSalesReturnOrder(
+ SalesHeader, SalesLine, Item, LocationCode, VariantCode, Qty, PostingDate, UnitCost, UnitPrice);
+ end;
+#endif
+
+#if not CLEAN26
+ [Obsolete('Moved to codeunit Library Sales procedure CreateSalesCreditMemo()', '26.0')]
+ procedure MAKESalesCreditMemo(var SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; Item: Record Item; LocationCode: Code[10]; VariantCode: Code[10]; Qty: Decimal; PostingDate: Date; UnitCost: Decimal; UnitPrice: Decimal)
+ begin
+ LibrarySales.CreateSalesCreditMemo(
+ SalesHeader, SalesLine, Item, LocationCode, VariantCode, Qty, PostingDate, UnitCost, UnitPrice);
+ end;
+#endif
+
+#if not CLEAN26
+ [Obsolete('Moved to codeunit Library Warehouse procedure CreateStockkeepingUnit', '26.0')]
+ procedure MAKEStockkeepingUnit(var StockkeepingUnit: Record "Stockkeeping Unit"; Item: Record Item)
+ begin
+ LibraryWarehouse.CreateStockkeepingUnit(StockkeepingUnit, Item);
+ end;
+#endif
+
+#if not CLEAN26
+ [Obsolete('Moved to codeunit Library Inventory procedure CreateTransferOrder', '26.0')]
+ procedure MAKETransferOrder(var TransferHeader: Record "Transfer Header"; var TransferLine: Record "Transfer Line"; Item: Record Item; FromLocation: Record Location; ToLocation: Record Location; InTransitLocation: Record Location; VariantCode: Code[10]; Qty: Decimal; PostingDate: Date; ShipmentDate: Date)
+ begin
+ LibraryInventory.CreateTransferOrder(
+ TransferHeader, TransferLine, Item, FromLocation, ToLocation, InTransitLocation, VariantCode, Qty, PostingDate, ShipmentDate);
+ end;
+#endif
+
+#if not CLEAN26
+#pragma warning disable AL0801
+ [Obsolete('Moved to codeunit Library Manufacturing', '26.0')]
+ procedure POSTConsumption(ProdOrderLine: Record "Prod. Order Line"; Item: Record Item; LocationCode: Code[10]; VariantCode: Code[10]; Qty: Decimal; PostingDate: Date; UnitCost: Decimal)
+ begin
+ LibraryManufacturing.POSTConsumption(ProdOrderLine, Item, LocationCode, VariantCode, Qty, PostingDate, UnitCost);
+ end;
+#pragma warning restore AL0801
+#endif
+
+#if not CLEAN26
+ [Obsolete('Moved to codeunit Library Inventory', '26.0')]
+ procedure POSTItemJournalLine(TemplateType: Enum "Item Journal Template Type"; EntryType: Enum "Item Ledger Entry Type"; Item: Record Item; LocationCode: Code[10]; VariantCode: Code[10]; BinCode: Code[20]; Qty: Decimal; PostingDate: Date; UnitAmount: Decimal)
+ begin
+ LibraryInventory.PostItemJournalLine(TemplateType, EntryType, Item, LocationCode, VariantCode, BinCode, Qty, PostingDate, UnitAmount);
+ end;
+#endif
+
+ procedure POSTItemJournalLineWithApplication(TemplateType: Enum "Item Journal Template Type"; EntryType: Enum "Item Ledger Entry Type"; Item: Record Item; LocationCode: Code[10]; VariantCode: Code[10]; Qty: Decimal; PostingDate: Date; UnitAmount: Decimal; AppltoEntryNo: Integer)
+ var
+ ItemJournalLine: Record "Item Journal Line";
+ ItemJournalBatch: Record "Item Journal Batch";
+ begin
+ LibraryInventory.CreateItemJournalBatchByType(ItemJournalBatch, TemplateType);
+ LibraryInventory.CreateItemJournalLineWithApplication(
+ ItemJournalLine, ItemJournalBatch, Item, LocationCode, VariantCode, PostingDate, EntryType, Qty, UnitAmount, AppltoEntryNo);
+ LibraryInventory.PostItemJournalBatch(ItemJournalBatch);
+ end;
+
+#if not CLEAN26
+ [Obsolete('Moved to codeunit Library Inventory', '26.0')]
+ procedure POSTNegativeAdjustment(Item: Record Item; LocationCode: Code[10]; VariantCode: Code[10]; BinCode: Code[20]; Qty: Decimal; PostingDate: Date; UnitAmount: Decimal)
+ begin
+ LibraryInventory.PostItemJournalLine(
+ "Item Journal Template Type"::Item, "Item Ledger Entry Type"::"Negative Adjmt.", Item,
+ LocationCode, VariantCode, BinCode, Qty, PostingDate, UnitAmount);
+ end;
+#endif
+
+ procedure POSTNegativeAdjustmentWithItemTracking(Item: Record Item; LocationCode: Code[10]; VariantCode: Code[10]; Qty: Decimal; PostingDate: Date; SerialNo: Code[50]; LotNo: Code[50])
+ var
+ ReservEntry: Record "Reservation Entry";
+ ItemJournalTemplate: Record "Item Journal Template";
+ ItemJournalLine: Record "Item Journal Line";
+ ItemJournalBatch: Record "Item Journal Batch";
+ begin
+ LibraryInventory.CreateItemJournalBatchByType(ItemJournalBatch, ItemJournalTemplate.Type::Item);
+ LibraryInventory.CreateItemJournalLine(ItemJournalLine, ItemJournalBatch, Item, LocationCode, VariantCode, PostingDate,
+ ItemJournalLine."Entry Type"::"Negative Adjmt.", Qty, 0);
+ LibraryItemTracking.CreateItemJournalLineItemTracking(ReservEntry, ItemJournalLine, SerialNo, LotNo, Qty);
+ LibraryInventory.PostItemJournalBatch(ItemJournalBatch);
+ end;
+
+ procedure POSTNegativeAdjustmentAmount(Item: Record Item; LocationCode: Code[10]; VariantCode: Code[10]; Qty: Decimal; PostingDate: Date; Amount: Decimal)
+ var
+ ItemJournalTemplate: Record "Item Journal Template";
+ ItemJournalLine: Record "Item Journal Line";
+ ItemJournalBatch: Record "Item Journal Batch";
+ begin
+ LibraryInventory.CreateItemJournalBatchByType(ItemJournalBatch, ItemJournalTemplate.Type::Item);
+ LibraryInventory.CreateItemJournalLine(ItemJournalLine, ItemJournalBatch, Item, LocationCode, VariantCode, PostingDate,
+ ItemJournalLine."Entry Type"::"Negative Adjmt.", Qty, 0);
+ ItemJournalLine.Validate(Amount, Amount);
+ ItemJournalLine.Modify();
+ LibraryInventory.PostItemJournalBatch(ItemJournalBatch);
+ end;
+
+#if not CLEAN26
+#pragma warning disable AL0801
+ [Obsolete('Moved to codeunit Library Manufacturing', '26.0')]
+ procedure POSTOutput(ProdOrderLine: Record "Prod. Order Line"; Qty: Decimal; PostingDate: Date; UnitCost: Decimal)
+ begin
+ LibraryManufacturing.POSTOutput(ProdOrderLine, Qty, PostingDate, UnitCost);
+ end;
+#pragma warning restore AL0801
+#endif
+
+#if not CLEAN26
+#pragma warning disable AL0801
+ [Obsolete('Moved to codeunit Library Manufacturing', '26.0')]
+ procedure POSTOutputWithItemTracking(ProdOrderLine: Record "Prod. Order Line"; Qty: Decimal; RunTime: Decimal; PostingDate: Date; UnitCost: Decimal; SerialNo: Code[50]; LotNo: Code[50])
+ begin
+ LibraryManufacturing.POSTOutputWithItemTracking(ProdOrderLine, Qty, RunTime, PostingDate, UnitCost, SerialNo, LotNo);
+ end;
+#pragma warning restore AL0801
+#endif
+
+#if not CLEAN26
+ [Obsolete('Moved to codeunit Library Inventory', '26.0')]
+ procedure POSTPositiveAdjustment(Item: Record Item; LocationCode: Code[10]; VariantCode: Code[10]; BinCode: Code[20]; Qty: Decimal; PostingDate: Date; UnitAmount: Decimal)
+ begin
+ LibraryInventory.PostPositiveAdjustment(Item, LocationCode, VariantCode, BinCode, Qty, PostingDate, UnitAmount);
+ end;
+#endif
+
+ procedure POSTPositiveAdjustmentAmount(Item: Record Item; LocationCode: Code[10]; VariantCode: Code[10]; Qty: Decimal; PostingDate: Date; Amount: Decimal)
+ var
+ ItemJournalTemplate: Record "Item Journal Template";
+ ItemJournalLine: Record "Item Journal Line";
+ ItemJournalBatch: Record "Item Journal Batch";
+ begin
+ LibraryInventory.CreateItemJournalBatchByType(ItemJournalBatch, ItemJournalTemplate.Type::Item);
+ LibraryInventory.CreateItemJournalLine(ItemJournalLine, ItemJournalBatch, Item, LocationCode, VariantCode, PostingDate,
+ ItemJournalLine."Entry Type"::"Positive Adjmt.", Qty, 0);
+ ItemJournalLine.Validate(Amount, Amount);
+ ItemJournalLine.Modify();
+ LibraryInventory.PostItemJournalBatch(ItemJournalBatch);
+ end;
+
+#if not CLEAN26
+ [Obsolete('Moved to codeunit Library Item Tracking', '26.0')]
+ procedure POSTPositiveAdjustmentWithItemTracking(Item: Record Item; LocationCode: Code[10]; VariantCode: Code[10]; Qty: Decimal; PostingDate: Date; SerialNo: Code[50]; LotNo: Code[50])
+ begin
+ LibraryItemTracking.PostPositiveAdjustmentWithItemTracking(Item, LocationCode, VariantCode, Qty, PostingDate, SerialNo, LotNo);
+ end;
+#endif
+
+#if not CLEAN26
+ [Obsolete('Replaced by LibraryInventory.PostItemJournalLine()', '26.0')]
+ procedure POSTPurchaseJournal(Item: Record Item; LocationCode: Code[10]; VariantCode: Code[10]; BinCode: Code[20]; Qty: Decimal; PostingDate: Date; UnitAmount: Decimal)
+ begin
+ LibraryInventory.PostItemJournalLine(
+ "Item Journal Template Type"::Item, "Item Ledger Entry Type"::Purchase, Item,
+ LocationCode, VariantCode, BinCode, Qty, PostingDate, UnitAmount);
+ end;
+#endif
+
+#if not CLEAN26
+ [Obsolete('Moved to codeunit Library Purchase', '26.0')]
+ procedure POSTPurchaseOrder(var PurchaseHeader: Record "Purchase Header"; Item: Record Item; LocationCode: Code[10]; VariantCode: Code[10]; Qty: Decimal; PostingDate: Date; DirectUnitCost: Decimal; Receive: Boolean; Invoice: Boolean)
+ begin
+ LibraryPurchase.PostPurchaseOrderPartially(
+ PurchaseHeader, Item, LocationCode, VariantCode, Qty, PostingDate, DirectUnitCost, Receive, Qty, Invoice, Qty);
+ end;
+#endif
+
+#if not CLEAN26
+ [Obsolete('Moved to codeunit Library Purchase', '26.0')]
+ procedure POSTPurchaseOrderWithItemTracking(var PurchaseHeader: Record "Purchase Header"; Item: Record Item; LocationCode: Code[10]; VariantCode: Code[10]; Qty: Decimal; PostingDate: Date; DirectUnitCost: Decimal; Receive: Boolean; Invoice: Boolean; SerialNo: Code[50]; LotNo: Code[50])
+ begin
+ LibraryPurchase.PostPurchaseOrderWithItemTracking(
+ PurchaseHeader, Item, LocationCode, VariantCode, Qty, PostingDate, DirectUnitCost, Receive, Invoice, SerialNo, LotNo);
+ end;
+#endif
+
+#if not CLEAN26
+ [Obsolete('Moved to codeunit Library Purchase', '26.0')]
+ procedure POSTPurchaseOrderPartially(var PurchaseHeader: Record "Purchase Header"; Item: Record Item; LocationCode: Code[10]; VariantCode: Code[10]; Qty: Decimal; PostingDate: Date; DirectUnitCost: Decimal; Receive: Boolean; ReceiveQty: Decimal; Invoice: Boolean; InvoiceQty: Decimal)
+ begin
+ LibraryPurchase.PostPurchaseOrderPartially(
+ PurchaseHeader, Item, LocationCode, VariantCode, Qty, PostingDate, DirectUnitCost, Receive, ReceiveQty, Invoice, InvoiceQty);
+ end;
+#endif
+
+#if not CLEAN26
+ [Obsolete('Moved to codeunit Library Inventory', '26.0')]
+ procedure POSTReclassificationJournalLine(Item: Record Item; StartDate: Date; FromLocationCode: Code[10]; ToLocationCode: Code[10]; VariantCode: Code[10]; BinCode: Code[20]; NewBinCode: Code[20]; Quantity: Decimal)
+ begin
+ LibraryInventory.PostReclassificationJournalLine(Item, StartDate, FromLocationCode, ToLocationCode, VariantCode, BinCode, NewBinCode, Quantity);
+ end;
+#endif
+
+#if not CLEAN26
+ [Obsolete('Replaced by LibraryInventory.PostItemJournalLine()', '26.0')]
+ procedure POSTSaleJournal(Item: Record Item; LocationCode: Code[10]; VariantCode: Code[10]; BinCode: Code[10]; Qty: Decimal; PostingDate: Date; UnitAmount: Decimal)
+ begin
+ LibraryInventory.PostItemJournalLine(
+ "Item Journal Template Type"::Item, "Item Ledger Entry Type"::Sale, Item,
+ LocationCode, VariantCode, BinCode, Qty, PostingDate, UnitAmount);
+ end;
+#endif
+
+#if not CLEAN26
+ [Obsolete('Moved to codeunit Library Sales', '26.0')]
+ procedure POSTSalesOrder(var SalesHeader: Record "Sales Header"; Item: Record Item; LocationCode: Code[10]; VariantCode: Code[10]; Qty: Decimal; PostingDate: Date; UnitCost: Decimal; Ship: Boolean; Invoice: Boolean)
+ begin
+ LibrarySales.PostSalesOrder(
+ SalesHeader, Item, LocationCode, VariantCode, Qty, PostingDate, UnitCost, Ship, Invoice);
+ end;
+#endif
+
+#if not CLEAN26
+ [Obsolete('Moved to codeunit Library Sales', '26.0')]
+ procedure POSTSalesOrderPartially(var SalesHeader: Record "Sales Header"; Item: Record Item; LocationCode: Code[10]; VariantCode: Code[10]; Qty: Decimal; PostingDate: Date; UnitCost: Decimal; Ship: Boolean; ShipQty: Decimal; Invoice: Boolean; InvoiceQty: Decimal)
+ begin
+ LibrarySales.PostSalesOrderPartially(
+ SalesHeader, Item, LocationCode, VariantCode, Qty, PostingDate, UnitCost, Ship, ShipQty, Invoice, InvoiceQty);
+ end;
+#endif
+
+#if not CLEAN26
+ [Obsolete('Moved to codeunit Library Inventory procedure CreateAndPostTransferOrder()', '26.0')]
+ procedure POSTTransferOrder(var TransferHeader: Record "Transfer Header"; Item: Record Item; FromLocation: Record Location; ToLocation: Record Location; InTransitLocation: Record Location; VariantCode: Code[10]; Qty: Decimal; PostingDate: Date; ShipmentDate: Date; Ship: Boolean; Receive: Boolean)
+ begin
+ LibraryInventory.CreateAndPostTransferOrder(
+ TransferHeader, Item, FromLocation, ToLocation, InTransitLocation, VariantCode, Qty, PostingDate, ShipmentDate, Ship, Receive);
+ end;
+#endif
+
+ procedure SETInventorySetup(AutomaticCostAdjustment: Option; AvgCostCalcType: Option; AvgCostPeriod: Option)
+ var
+ InventorySetup: Record "Inventory Setup";
+ begin
+ InventorySetup.Get();
+ InventorySetup."Automatic Cost Posting" := false;
+ InventorySetup."Expected Cost Posting to G/L" := false;
+ InventorySetup.Validate("Automatic Cost Adjustment", AutomaticCostAdjustment);
+ InventorySetup.Validate("Average Cost Calc. Type", AvgCostCalcType);
+ InventorySetup.Validate("Average Cost Period", AvgCostPeriod);
+ InventorySetup.Modify();
+ end;
+
+ procedure SETNoSeries()
+ var
+ InventorySetup: Record "Inventory Setup";
+#if not CLEAN27
+#pragma warning disable AL0801
+ ManufacturingSetup: Record "Manufacturing Setup";
+#pragma warning restore AL0801
+#endif
+ SalesReceivablesSetup: Record "Sales & Receivables Setup";
+ MarketingSetup: Record "Marketing Setup";
+ NoSeries: Code[20];
+ begin
+ NoSeries := LibraryUtility.GetGlobalNoSeriesCode();
+
+ InventorySetup.Get();
+ if InventorySetup."Item Nos." <> NoSeries then begin
+ InventorySetup.Validate("Item Nos.", NoSeries);
+ InventorySetup.Modify();
+ end;
+ if InventorySetup."Transfer Order Nos." <> NoSeries then begin
+ InventorySetup.Validate("Transfer Order Nos.", NoSeries);
+ InventorySetup.Modify();
+ end;
+
+#if not CLEAN27
+#pragma warning disable AL0801
+ ManufacturingSetup.Get();
+ if ManufacturingSetup."Simulated Order Nos." <> NoSeries then begin
+ ManufacturingSetup."Simulated Order Nos." := NoSeries;
+ ManufacturingSetup.Modify();
+ end;
+ if ManufacturingSetup."Planned Order Nos." <> NoSeries then begin
+ ManufacturingSetup."Planned Order Nos." := NoSeries;
+ ManufacturingSetup.Modify();
+ end;
+ if ManufacturingSetup."Firm Planned Order Nos." <> NoSeries then begin
+ ManufacturingSetup."Firm Planned Order Nos." := NoSeries;
+ ManufacturingSetup.Modify();
+ end;
+ if ManufacturingSetup."Released Order Nos." <> NoSeries then begin
+ ManufacturingSetup."Released Order Nos." := NoSeries;
+ ManufacturingSetup.Modify();
+ end;
+#pragma warning restore AL0801
+#endif
+
+ SalesReceivablesSetup.Get();
+ if SalesReceivablesSetup."Quote Nos." <> NoSeries then begin
+ SalesReceivablesSetup."Quote Nos." := NoSeries;
+ SalesReceivablesSetup.Modify();
+ end;
+ if SalesReceivablesSetup."Order Nos." <> NoSeries then begin
+ SalesReceivablesSetup."Order Nos." := NoSeries;
+ SalesReceivablesSetup.Modify();
+ end;
+ if SalesReceivablesSetup."Invoice Nos." <> NoSeries then begin
+ SalesReceivablesSetup."Invoice Nos." := NoSeries;
+ SalesReceivablesSetup.Modify();
+ end;
+ if SalesReceivablesSetup."Credit Memo Nos." <> NoSeries then begin
+ SalesReceivablesSetup."Credit Memo Nos." := NoSeries;
+ SalesReceivablesSetup.Modify();
+ end;
+ if SalesReceivablesSetup."Return Order Nos." <> NoSeries then begin
+ SalesReceivablesSetup."Return Order Nos." := NoSeries;
+ SalesReceivablesSetup.Modify();
+ end;
+ if SalesReceivablesSetup."Customer Nos." <> NoSeries then begin
+ SalesReceivablesSetup."Customer Nos." := NoSeries;
+ SalesReceivablesSetup.Modify();
+ end;
+
+ MarketingSetup.Get();
+ if MarketingSetup."Contact Nos." <> NoSeries then begin
+ MarketingSetup."Contact Nos." := NoSeries;
+ MarketingSetup.Modify();
+ end;
+ end;
+
+ local procedure GRPH1Outbound1Purchase(var TempItemLedgerEntry: Record "Item Ledger Entry" temporary; var PurchaseLine: Record "Purchase Line"; Item: Record Item; LocationCode: Code[10]; VariantCode: Code[10]; InvoicePurchase: Boolean)
+ var
+ PurchaseHeader1: Record "Purchase Header";
+ PurchaseHeader2: Record "Purchase Header";
+ Day1: Date;
+ OutboundQty: Decimal;
+ begin
+ Clear(TempItemLedgerEntry);
+ Day1 := WorkDate();
+
+ OutboundQty := LibraryRandom.RandInt(10);
+ LibraryInventory.PostNegativeAdjustment(
+ Item, LocationCode, VariantCode, '', OutboundQty, Day1, LibraryRandom.RandDec(100, 2));
+ InsertTempILEFromLast(TempItemLedgerEntry);
+
+ LibraryPurchase.PostPurchaseOrder(
+ PurchaseHeader1, Item, LocationCode, VariantCode,
+ LibraryRandom.RandIntInRange(OutboundQty, OutboundQty + LibraryRandom.RandInt(10)), Day1 + 1,
+ LibraryRandom.RandDec(100, 2), true, InvoicePurchase);
+ InsertTempILEFromLast(TempItemLedgerEntry);
+
+ LibraryPurchase.CreatePurchaseOrder(
+ PurchaseHeader2, PurchaseLine, Item, LocationCode, VariantCode, LibraryRandom.RandInt(10), Day1 + 2,
+ LibraryRandom.RandDec(100, 2));
+ end;
+
+ procedure GRPH1Outbound1PurchRcvd(var TempItemLedgerEntry: Record "Item Ledger Entry" temporary; var PurchaseLine: Record "Purchase Line"; Item: Record Item; LocationCode: Code[10]; VariantCode: Code[10])
+ begin
+ GRPH1Outbound1Purchase(TempItemLedgerEntry, PurchaseLine, Item, LocationCode, VariantCode, false);
+ end;
+
+ procedure GRPH1Outbound1PurchInvd(var TempItemLedgerEntry: Record "Item Ledger Entry" temporary; var PurchaseLine: Record "Purchase Line"; Item: Record Item; LocationCode: Code[10]; VariantCode: Code[10])
+ begin
+ GRPH1Outbound1Purchase(TempItemLedgerEntry, PurchaseLine, Item, LocationCode, VariantCode, true);
+ end;
+
+ procedure GRPHPurchPartialRcvd1PurchReturn(var TempItemLedgerEntry: Record "Item Ledger Entry" temporary; var PurchaseLine: Record "Purchase Line"; var PurchaseLine1: Record "Purchase Line"; Item: Record Item; LocationCode: Code[10]; VariantCode: Code[10]; InvoicePurchase: Boolean)
+ var
+ PurchaseHeader: Record "Purchase Header";
+ PurchaseHeader1: Record "Purchase Header";
+ Day1: Date;
+ InboundQty: Decimal;
+ begin
+ Clear(TempItemLedgerEntry);
+ Day1 := WorkDate();
+
+ // Receive partially the Purchase Line, with or without invoicing.
+ InboundQty := LibraryRandom.RandIntInRange(10, 20);
+ LibraryPurchase.CreatePurchaseOrder(
+ PurchaseHeader, PurchaseLine, Item, LocationCode, VariantCode, InboundQty, Day1 + 2, LibraryRandom.RandDec(100, 2));
+ PurchaseLine.Validate("Qty. to Receive", LibraryRandom.RandInt(PurchaseLine."Outstanding Quantity" - 5));
+ PurchaseLine.Modify();
+ if InvoicePurchase then
+ SetVendorDocNo(PurchaseHeader);
+ LibraryPurchase.PostPurchaseDocument(PurchaseHeader, true, InvoicePurchase);
+ InsertTempILEFromLast(TempItemLedgerEntry);
+
+ // Repeat the receipt.
+ PurchaseLine.Get(PurchaseLine."Document Type", PurchaseLine."Document No.", PurchaseLine."Line No.");
+ PurchaseLine.Validate("Qty. to Receive", LibraryRandom.RandInt(PurchaseLine."Outstanding Quantity" - 1));
+ PurchaseLine.Validate("Direct Unit Cost", PurchaseLine."Direct Unit Cost" + LibraryRandom.RandDec(10, 2));
+ PurchaseLine.Modify();
+ PurchaseHeader.Get(PurchaseHeader."Document Type", PurchaseHeader."No.");
+ if InvoicePurchase then
+ SetVendorDocNo(PurchaseHeader);
+ LibraryPurchase.PostPurchaseDocument(PurchaseHeader, true, InvoicePurchase);
+ InsertTempILEFromLast(TempItemLedgerEntry);
+
+ // Create Purchase Return Header and Line with 0 quantity. Actual qty to be added in calling test.
+ LibraryPurchase.CreatePurchaseReturnOrder(
+ PurchaseHeader1, PurchaseLine1, Item, LocationCode, VariantCode, 0, Day1 + 2, LibraryRandom.RandDec(100, 5));
+ end;
+
+ procedure GRPHPurchItemTracked(var TempItemLedgerEntry: Record "Item Ledger Entry" temporary; var PurchaseLine: Record "Purchase Line"; var ReservEntry: Record "Reservation Entry"; Item: Record Item; LocationCode: Code[10]; VariantCode: Code[10]; Invoice: Boolean)
+ var
+ PurchaseHeader: Record "Purchase Header";
+ Day1: Date;
+ InboundQty: Decimal;
+ begin
+ Clear(TempItemLedgerEntry);
+ Day1 := WorkDate();
+
+ InboundQty := LibraryRandom.RandInt(10);
+ LibraryPurchase.CreatePurchaseOrder(
+ PurchaseHeader, PurchaseLine, Item, LocationCode, VariantCode, InboundQty, Day1, LibraryRandom.RandDec(100, 2));
+ LibraryItemTracking.CreatePurchOrderItemTracking(ReservEntry, PurchaseLine, '',
+ CopyStr(LibraryUtility.GenerateRandomCode(ReservEntry.FieldNo("Lot No."), DATABASE::"Reservation Entry"), 1, 10), InboundQty);
+ if Invoice then
+ SetVendorDocNo(PurchaseHeader);
+ LibraryPurchase.PostPurchaseDocument(PurchaseHeader, true, Invoice);
+ InsertTempILEFromLast(TempItemLedgerEntry);
+ end;
+
+ procedure GRPHSalesItemTracked(var TempItemLedgerEntry: Record "Item Ledger Entry" temporary; var SalesLine: Record "Sales Line"; var ReservEntry: Record "Reservation Entry"; Item: Record Item; LocationCode: Code[10]; VariantCode: Code[10]; Invoice: Boolean)
+ var
+ SalesHeader: Record "Sales Header";
+ ReservEntry2: Record "Reservation Entry";
+ Day1: Date;
+ OutboundQty: Decimal;
+ begin
+ Clear(TempItemLedgerEntry);
+ Day1 := WorkDate();
+
+ OutboundQty := LibraryRandom.RandInt(ReservEntry.Quantity);
+ LibrarySales.CreateSalesOrder(SalesHeader, SalesLine, Item, LocationCode, VariantCode, OutboundQty, Day1, LibraryRandom.RandDec(100, 2));
+ LibraryItemTracking.CreateSalesOrderItemTracking(ReservEntry2, SalesLine, '', ReservEntry."Lot No.", OutboundQty);
+
+ LibrarySales.PostSalesDocument(SalesHeader, true, Invoice);
+ ReservEntry := ReservEntry2;
+ InsertTempILEFromLast(TempItemLedgerEntry);
+ end;
+
+ procedure GRPH3Purch1SalesItemTracked(var SalesLine: Record "Sales Line"; Item: Record Item; LocationCode: Code[10]; VariantCode: Code[10]; InvoicePurchase: Boolean; InvoiceSales: Boolean)
+ var
+ TempItemLedgerEntry: Record "Item Ledger Entry" temporary;
+ ReservEntry: Record "Reservation Entry";
+ ReservEntry2: Record "Reservation Entry";
+ PurchaseLine: Record "Purchase Line";
+ begin
+ // Purchase 3 times.
+ GRPHPurchItemTracked(TempItemLedgerEntry, PurchaseLine, ReservEntry2, Item, LocationCode, VariantCode, InvoicePurchase);
+ GRPHPurchItemTracked(TempItemLedgerEntry, PurchaseLine, ReservEntry, Item, LocationCode, VariantCode, InvoicePurchase);
+ GRPHPurchItemTracked(TempItemLedgerEntry, PurchaseLine, ReservEntry2, Item, LocationCode, VariantCode, InvoicePurchase);
+
+ // Make the sales for the item tracking in 2nd purchase line
+ GRPHSalesItemTracked(TempItemLedgerEntry, SalesLine, ReservEntry, Item, LocationCode, VariantCode, InvoiceSales);
+ end;
+
+ procedure GRPHSplitApplication(Item: Record Item; SalesLine: Record "Sales Line"; SalesLineSplit: Record "Sales Line")
+ var
+ TempItemJournalLine: Record "Item Journal Line" temporary;
+ QtyPurch1: Decimal;
+ QtyPurch2: Decimal;
+ QtySales1: Decimal;
+ QtySales2: Decimal;
+ begin
+ QtyPurch1 := RandDec(10, 20, 2);
+ QtyPurch2 := RandDec(10, 20, 2);
+ QtySales1 := RandDec(0, QtyPurch1, 2);
+ QtySales2 := RandDec(QtyPurch1 - QtySales1, QtyPurch1 - QtySales1 + QtyPurch2, 2);
+
+ MAKEInbound(Item, QtyPurch1, WorkDate(), TempItemJournalLine);
+ MAKEInbound(Item, QtyPurch2, WorkDate(), TempItemJournalLine);
+
+ SHIPSales(SalesLine, Item, QtySales1, WorkDate());
+ SHIPSales(SalesLineSplit, Item, QtySales2, WorkDate() + 1);
+ end;
+
+ procedure GRPHSeveralSplitApplicationWithCosts(Item: Record Item; var SalesLine: Record "Sales Line"; var TempItemJournalLine: Record "Item Journal Line" temporary; var Cost1: Decimal; var Cost2: Decimal; var Cost3: Decimal)
+ var
+ UnitCost1: Decimal;
+ UnitCost2: Decimal;
+ UnitCost3: Decimal;
+ Qty1: Decimal;
+ Qty2: Decimal;
+ Qty3: Decimal;
+ QtyOut1: Decimal;
+ QtyOut2: Decimal;
+ RemainingQty2: Decimal;
+ begin
+ Qty1 := RandDec(10, 20, 2);
+ Qty2 := RandDec(10, 20, 2);
+ Qty3 := RandDec(10, 20, 2);
+
+ MAKEInbound(Item, Qty1, WorkDate(), TempItemJournalLine);
+ UnitCost1 := TempItemJournalLine."Unit Amount";
+ MAKEInbound(Item, Qty2, WorkDate() + 1, TempItemJournalLine);
+ UnitCost2 := TempItemJournalLine."Unit Amount";
+ MAKEInbound(Item, Qty3, WorkDate() + 2, TempItemJournalLine);
+ UnitCost3 := TempItemJournalLine."Unit Amount";
+
+ QtyOut1 := Qty1 + RandDec(0, Qty2 / 2, 2);
+ RemainingQty2 := Qty2 + Qty1 - QtyOut1;
+ QtyOut2 := RandDec(0, RemainingQty2, 2);
+
+ MAKEOutbound(Item, QtyOut1, WorkDate() + 3, TempItemJournalLine);
+ Cost1 := (Qty1 * UnitCost1 + (QtyOut1 - Qty1) * UnitCost2) / QtyOut1;
+ MAKEOutbound(Item, QtyOut2, WorkDate() + 4, TempItemJournalLine);
+ Cost2 := UnitCost2;
+
+ RemainingQty2 -= QtyOut2;
+ SHIPSales(SalesLine, Item, RemainingQty2 + RandDec(0, Qty3, 2), WorkDate() + 5);
+ Cost3 := (RemainingQty2 * UnitCost2 + (SalesLine.Quantity - RemainingQty2) * UnitCost3) / SalesLine.Quantity;
+
+ TempItemJournalLine.FindSet();
+ end;
+
+ procedure GRPHSplitJoinApplication(Item: Record Item; var SalesLine: Record "Sales Line"; var SalesLineReturn: Record "Sales Line"; var TempItemJournalLine: Record "Item Journal Line" temporary)
+ var
+ Qty: Decimal;
+ begin
+ Qty := RandDec(10, 20, 2);
+
+ MAKEInbound(Item, Qty, WorkDate(), TempItemJournalLine);
+
+ SHIPSales(SalesLine, Item, Qty / 2, WorkDate());
+ LibrarySales.PostSalesLine(SalesLine, true, true);
+
+ RECEIVESalesReturn(SalesLineReturn, SalesLine, WorkDate());
+ SHIPSales(SalesLine, Item, Qty, WorkDate());
+ end;
+
+ procedure GRPHSeveralSplitApplication(Item: Record Item; var SalesLine: Record "Sales Line"; var TempItemJournalLine: Record "Item Journal Line" temporary)
+ var
+ Unused: Decimal;
+ begin
+ GRPHSeveralSplitApplicationWithCosts(Item, SalesLine, TempItemJournalLine, Unused, Unused, Unused);
+ end;
+
+ procedure GRPHSalesOnly(Item: Record Item; var SalesLine: Record "Sales Line")
+ begin
+ SHIPSales(SalesLine, Item, RandDec(10, 20, 2), WorkDate());
+ end;
+
+ procedure GRPHApplyInboundToUnappliedOutbound(var Item: Record Item; var SalesLine: Record "Sales Line")
+ var
+ TempItemJournalLine: Record "Item Journal Line" temporary;
+ QtyOut: Decimal;
+ QtyIn1: Decimal;
+ QtyIn2: Decimal;
+ begin
+ QtyOut := RandDec(10, 20, 2);
+ QtyIn1 := RandDec(0, QtyOut / 2, 2);
+ QtyIn2 := QtyOut - QtyIn1 + RandDec(0, 10, 2);
+
+ SHIPSales(SalesLine, Item, QtyOut, WorkDate());
+
+ MAKEInbound(Item, QtyIn1, WorkDate() - 1, TempItemJournalLine);
+ MAKEInbound(Item, QtyIn2, WorkDate() - 2, TempItemJournalLine);
+ end;
+
+ procedure GRPHSimpleApplication(Item: Record Item; var SalesLine: Record "Sales Line"; var TempItemJournalLine: Record "Item Journal Line" temporary)
+ var
+ QtyIn: Decimal;
+ begin
+ QtyIn := RandDec(10, 20, 2);
+ MAKEInbound(Item, QtyIn, WorkDate(), TempItemJournalLine);
+ SHIPSales(SalesLine, Item, RandDec(0, QtyIn, 2), WorkDate() + 1);
+ end;
+
+ procedure GRPHSalesReturnOnly(var Item: Record Item; var ReturnReceiptLine: Record "Return Receipt Line")
+ var
+ SalesHeader: Record "Sales Header";
+ SalesLine: Record "Sales Line";
+ begin
+ LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::"Return Order", '');
+ LibrarySales.CreateSalesLine(SalesLine, SalesHeader, SalesLine.Type::Item, Item."No.", RandDec(10, 20, 2));
+ Commit();
+
+ LibrarySales.PostSalesDocument(SalesHeader, true, true);
+
+ ReturnReceiptLine.SetFilter("No.", Item."No.");
+ ReturnReceiptLine.FindLast();
+ end;
+
+ procedure GRPHSalesFromReturnReceipts(var Item: Record Item; var SalesLine: Record "Sales Line")
+ var
+ ReturnReceiptLine1: Record "Return Receipt Line";
+ ReturnReceiptLine2: Record "Return Receipt Line";
+ begin
+ GRPHSalesReturnOnly(Item, ReturnReceiptLine1);
+ GRPHSalesReturnOnly(Item, ReturnReceiptLine2);
+ SHIPSales(SalesLine, Item, ReturnReceiptLine1.Quantity + RandDec(0, ReturnReceiptLine2.Quantity, 2), WorkDate());
+ end;
+
+ procedure InsertTempILEFromLast(var TempItemLedgerEntry: Record "Item Ledger Entry" temporary)
+ var
+ ItemLedgerEntry: Record "Item Ledger Entry";
+ begin
+ ItemLedgerEntry.FindLast();
+ TempItemLedgerEntry := ItemLedgerEntry;
+ TempItemLedgerEntry.Insert();
+ end;
+
+ procedure CHECKValueEntry(var RefValueEntry: Record "Value Entry"; ValueEntry: Record "Value Entry")
+ begin
+ ValueEntry.TestField("Cost Amount (Expected)", RefValueEntry."Cost Amount (Expected)");
+ ValueEntry.TestField("Cost Amount (Actual)", RefValueEntry."Cost Amount (Actual)");
+ ValueEntry.TestField("Valued Quantity", RefValueEntry."Valued Quantity");
+ ValueEntry.TestField("Cost per Unit", RefValueEntry."Cost per Unit");
+ ValueEntry.TestField("Valuation Date", RefValueEntry."Valuation Date");
+ ValueEntry.TestField("Entry Type", RefValueEntry."Entry Type");
+ ValueEntry.TestField("Variance Type", RefValueEntry."Variance Type");
+ end;
+
+ procedure CHECKItemLedgerEntry(var RefItemLedgerEntry: Record "Item Ledger Entry")
+ var
+ ItemLedgerEntry: Record "Item Ledger Entry";
+ begin
+ RefItemLedgerEntry.FindSet();
+ ItemLedgerEntry.SetRange("Item No.", RefItemLedgerEntry."Item No.");
+ ItemLedgerEntry.SetRange("Location Code", RefItemLedgerEntry."Location Code");
+ ItemLedgerEntry.SetRange("Variant Code", RefItemLedgerEntry."Variant Code");
+ ItemLedgerEntry.FindSet();
+ repeat
+ ItemLedgerEntry.TestField("Cost Amount (Expected)", RefItemLedgerEntry."Cost Amount (Expected)");
+ ItemLedgerEntry.TestField("Cost Amount (Actual)", RefItemLedgerEntry."Cost Amount (Actual)");
+ ItemLedgerEntry.TestField("Remaining Quantity", RefItemLedgerEntry."Remaining Quantity");
+ ItemLedgerEntry.TestField("Invoiced Quantity", RefItemLedgerEntry."Invoiced Quantity");
+ ItemLedgerEntry.TestField("Applies-to Entry", RefItemLedgerEntry."Applies-to Entry");
+ RefItemLedgerEntry.Next();
+ until ItemLedgerEntry.Next() = 0;
+ end;
+
+ procedure RandDec("Min": Decimal; "Max": Decimal; Precision: Integer): Decimal
+ var
+ Min2: Integer;
+ Max2: Integer;
+ Pow: Integer;
+ begin
+ Pow := Power(10, Precision);
+ Min2 := Round(Min * Pow, 1);
+ Max2 := Round(Max * Pow, 1);
+ exit(Round(LibraryRandom.RandDecInRange(Min2, Max2, 1) / Pow, 1 / Pow));
+ end;
+
+ procedure RandCost(Item: Record Item): Decimal
+ var
+ Precision: Decimal;
+ begin
+ Precision := LibraryERM.GetAmountRoundingPrecision();
+ if Item."Unit Cost" <> 0 then
+ exit(Round(Item."Unit Cost" * RandDec(0, 2, 5), Precision));
+ exit(Round(RandDec(0, 100, 5), Precision));
+ end;
+
+ local procedure SHIPSales(var SalesLine: Record "Sales Line"; Item: Record Item; Qty: Decimal; PostingDate: Date)
+ var
+ SalesHeader: Record "Sales Header";
+ begin
+ LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Order, '');
+ SalesHeader.Validate("Posting Date", PostingDate);
+ SalesHeader.Modify(true);
+
+ LibrarySales.CreateSalesLine(SalesLine, SalesHeader, SalesLine.Type::Item, Item."No.", Qty);
+ SalesLine.Validate("Shipment Date", PostingDate);
+ SalesLine.Modify(true);
+
+ LibrarySales.PostSalesDocument(SalesHeader, true, false);
+ end;
+
+ local procedure RECEIVESalesReturn(var SalesLineReturn: Record "Sales Line"; FromSalesLine: Record "Sales Line"; PostingDate: Date)
+ var
+ SalesHeader: Record "Sales Header";
+ SalesShipmentLine: Record "Sales Shipment Line";
+ CopyDocMgt: Codeunit "Copy Document Mgt.";
+ LinesNotCopied: Integer;
+ MissingExCostRevLink: Boolean;
+ begin
+ LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::"Return Order", '');
+ SalesHeader.Validate("Posting Date", PostingDate);
+ SalesHeader.Modify(true);
+
+ SalesShipmentLine.SetRange("Order No.", FromSalesLine."Document No.");
+ SalesShipmentLine.FindFirst();
+ CopyDocMgt.SetProperties(false, true, false, false, true, true, true);
+ CopyDocMgt.CopySalesShptLinesToDoc(
+ SalesHeader, SalesShipmentLine, LinesNotCopied, MissingExCostRevLink);
+
+ LibrarySales.PostSalesDocument(SalesHeader, true, false);
+
+ SalesLineReturn.SetRange("Document Type", SalesHeader."Document Type");
+ SalesLineReturn.SetRange("Document No.", SalesHeader."No.");
+ SalesLineReturn.SetRange(Type, SalesLineReturn.Type::Item);
+ Assert.AreEqual(1, SalesLineReturn.Count, TXTUnexpectedLine);
+ SalesLineReturn.FindFirst();
+ end;
+
+ procedure CHECKCalcInvPost(Item: Record Item; ItemJnlBatch: Record "Item Journal Batch"; PostingDate: Date; CalculatePer: Enum "Inventory Value Calc. Per"; ByLocation: Boolean; ByVariant: Boolean; LocationFilter: Code[20]; VariantFilter: Code[20])
+ var
+ TempRefItemJnlLine: Record "Item Journal Line" temporary;
+ ItemJnlLine: Record "Item Journal Line";
+ begin
+ // Verify journal lines created by Calculate Inventory Value report
+ CreateRefJnlforCalcInvPost(Item, TempRefItemJnlLine, PostingDate, CalculatePer, ByLocation, ByVariant, LocationFilter, VariantFilter);
+
+ ItemJnlLine.SetRange("Journal Template Name", ItemJnlBatch."Journal Template Name");
+ ItemJnlLine.SetRange("Journal Batch Name", ItemJnlBatch.Name);
+ ItemJnlLine.SetRange("Item No.", Item."No.");
+
+ Assert.AreEqual(TempRefItemJnlLine.Count, ItemJnlLine.Count, StrSubstNo(TXTLineCountMismatch, Item."No."));
+
+ if CalculatePer = CalculatePer::Item then begin
+ if ItemJnlLine.FindSet() then
+ repeat
+ TempRefItemJnlLine.SetRange("Location Code", ItemJnlLine."Location Code");
+ TempRefItemJnlLine.SetRange("Variant Code", ItemJnlLine."Variant Code");
+ TempRefItemJnlLine.FindFirst();
+ Assert.AreEqual(
+ TempRefItemJnlLine.Quantity, ItemJnlLine.Quantity,
+ StrSubstNo(TXTIncorrectEntry, TempRefItemJnlLine.FieldName(Quantity), ItemJnlLine."Line No."));
+ Assert.AreEqual(TempRefItemJnlLine."Inventory Value (Calculated)", ItemJnlLine."Inventory Value (Calculated)",
+ StrSubstNo(TXTIncorrectEntry, TempRefItemJnlLine.FieldName("Inventory Value (Calculated)"), ItemJnlLine."Line No."));
+ until ItemJnlLine.Next() = 0;
+ end else
+ if ItemJnlLine.FindSet() then
+ repeat
+ TempRefItemJnlLine.SetRange("Applies-to Entry", ItemJnlLine."Applies-to Entry");
+ TempRefItemJnlLine.FindFirst();
+ Assert.AreEqual(
+ TempRefItemJnlLine."Location Code", ItemJnlLine."Location Code",
+ StrSubstNo(TXTIncorrectEntry, TempRefItemJnlLine.FieldName("Location Code"), ItemJnlLine."Applies-to Entry"));
+ Assert.AreEqual(
+ TempRefItemJnlLine."Variant Code", ItemJnlLine."Variant Code",
+ StrSubstNo(TXTIncorrectEntry, TempRefItemJnlLine.FieldName("Variant Code"), ItemJnlLine."Applies-to Entry"));
+ Assert.AreEqual(
+ TempRefItemJnlLine.Quantity, ItemJnlLine.Quantity,
+ StrSubstNo(TXTIncorrectEntry, TempRefItemJnlLine.FieldName(Quantity), ItemJnlLine."Applies-to Entry"));
+ Assert.AreEqual(
+ TempRefItemJnlLine."Inventory Value (Calculated)", ItemJnlLine."Inventory Value (Calculated)",
+ StrSubstNo(TXTIncorrectEntry, TempRefItemJnlLine.FieldName("Inventory Value (Calculated)"), ItemJnlLine."Applies-to Entry"));
+ until ItemJnlLine.Next() = 0;
+ end;
+
+ local procedure CreateRefJnlforCalcInvPost(Item: Record Item; var TempRefItemJnlLine: Record "Item Journal Line" temporary; PostingDate: Date; CalculatePer: Enum "Inventory Value Calc. Per"; ByLocation: Boolean; ByVariant: Boolean; LocationFilter: Code[20]; VariantFilter: Code[20])
+ var
+ ItemLedgerEntry: Record "Item Ledger Entry";
+ TempItemLedgerEntry: Record "Item Ledger Entry" temporary;
+ TempLocation: Record Location temporary;
+ TempItemVariant: Record "Item Variant" temporary;
+ begin
+ ItemLedgerEntry.SetRange("Item No.", Item."No.");
+ ItemLedgerEntry.SetRange(Positive, true);
+ ItemLedgerEntry.SetFilter("Location Code", LocationFilter);
+ ItemLedgerEntry.SetFilter("Variant Code", VariantFilter);
+ ItemLedgerEntry.SetFilter("Posting Date", '<=%1', PostingDate);
+ if Item."Costing Method" <> Item."Costing Method"::Standard then begin
+ ItemLedgerEntry.SetRange("Completely Invoiced", true);
+ ItemLedgerEntry.SetRange("Last Invoice Date", 0D, PostingDate);
+ end;
+ if CalculatePer = CalculatePer::Item then begin
+ if LocationFilter <> '' then
+ ByLocation := true;
+ if VariantFilter <> '' then
+ ByVariant := true;
+
+ TempLocation.Code := '';
+ TempLocation.Insert();
+ TempItemVariant.Code := '';
+ TempItemVariant.Insert();
+
+ if ItemLedgerEntry.FindSet() then
+ repeat
+ TempItemLedgerEntry := ItemLedgerEntry;
+ TempItemLedgerEntry.Insert();
+ TempLocation.Code := ItemLedgerEntry."Location Code";
+ if not TempLocation.Insert() then;
+ TempItemVariant.Code := ItemLedgerEntry."Variant Code";
+ if not TempItemVariant.Insert() then;
+ until ItemLedgerEntry.Next() = 0;
+
+ if ByLocation then begin
+ TempLocation.FindSet();
+ repeat
+ TempItemLedgerEntry.SetRange("Location Code", TempLocation.Code);
+ if ByVariant then begin
+ TempItemVariant.FindSet();
+ repeat
+ TempItemLedgerEntry.SetRange("Variant Code", TempItemVariant.Code);
+ CreateRefJournalLinePerItem(TempItemLedgerEntry, TempRefItemJnlLine, PostingDate, ByLocation, ByVariant);
+ until TempItemVariant.Next() = 0;
+ end else
+ CreateRefJournalLinePerItem(TempItemLedgerEntry, TempRefItemJnlLine, PostingDate, ByLocation, ByVariant);
+ until TempLocation.Next() = 0;
+ end else
+ if ByVariant then begin
+ TempItemVariant.FindSet();
+ repeat
+ TempItemLedgerEntry.SetRange("Variant Code", TempItemVariant.Code);
+ CreateRefJournalLinePerItem(TempItemLedgerEntry, TempRefItemJnlLine, PostingDate, ByLocation, ByVariant);
+ until TempItemVariant.Next() = 0;
+ end else
+ CreateRefJournalLinePerItem(TempItemLedgerEntry, TempRefItemJnlLine, PostingDate, ByLocation, ByVariant);
+ end else begin
+ if ItemLedgerEntry.FindSet() then
+ repeat
+ TempItemLedgerEntry := ItemLedgerEntry;
+ TempItemLedgerEntry.Insert();
+ until ItemLedgerEntry.Next() = 0;
+ CreateRefJournalLinePerILE(TempItemLedgerEntry, TempRefItemJnlLine, PostingDate);
+ end;
+ end;
+
+ local procedure CreateRefJournalLinePerItem(var TempItemLedgerEntry: Record "Item Ledger Entry" temporary; var TempRefItemJnlLine: Record "Item Journal Line" temporary; PostingDate: Date; ByLocation: Boolean; ByVariant: Boolean)
+ var
+ OutboundItemLedgerEntry: Record "Item Ledger Entry";
+ ItemApplicationEntry: Record "Item Application Entry";
+ RefQuantity: Decimal;
+ RefCostAmount: Decimal;
+ begin
+ if TempItemLedgerEntry.FindSet() then
+ repeat
+ RefQuantity += TempItemLedgerEntry.Quantity;
+ RefCostAmount += CalculateCostAtDate(TempItemLedgerEntry."Entry No.", PostingDate);
+ ItemApplicationEntry.SetRange("Inbound Item Entry No.", TempItemLedgerEntry."Entry No.");
+ ItemApplicationEntry.SetFilter("Posting Date", '<=%1', PostingDate);
+ if ItemApplicationEntry.FindSet() then
+ repeat
+ if (ItemApplicationEntry."Outbound Item Entry No." <> 0) and (ItemApplicationEntry.Quantity < 0) then begin
+ OutboundItemLedgerEntry.Get(ItemApplicationEntry."Outbound Item Entry No.");
+ RefQuantity += ItemApplicationEntry.Quantity;
+ RefCostAmount += CalculateCostAtDate(OutboundItemLedgerEntry."Entry No.", PostingDate) /
+ OutboundItemLedgerEntry.Quantity * ItemApplicationEntry.Quantity;
+ end;
+ until ItemApplicationEntry.Next() = 0;
+ until TempItemLedgerEntry.Next() = 0;
+
+ if RefQuantity = 0 then
+ exit;
+
+ TempRefItemJnlLine."Line No." += 10000;
+ TempRefItemJnlLine."Item No." := TempItemLedgerEntry."Item No.";
+ if ByLocation then
+ TempRefItemJnlLine."Location Code" := TempItemLedgerEntry."Location Code";
+ if ByVariant then
+ TempRefItemJnlLine."Variant Code" := TempItemLedgerEntry."Variant Code";
+ TempRefItemJnlLine.Quantity := RefQuantity;
+ TempRefItemJnlLine."Inventory Value (Calculated)" := Round(RefCostAmount, LibraryERM.GetAmountRoundingPrecision());
+ TempRefItemJnlLine.Insert();
+ end;
+
+ local procedure CreateRefJournalLinePerILE(var TempItemLedgerEntry: Record "Item Ledger Entry" temporary; var TempRefItemJnlLine: Record "Item Journal Line" temporary; PostingDate: Date)
+ var
+ ItemApplicationEntry: Record "Item Application Entry";
+ begin
+ if TempItemLedgerEntry.FindSet() then
+ repeat
+ TempItemLedgerEntry.CalcFields("Cost Amount (Expected)", "Cost Amount (Actual)", "Cost Amount (Non-Invtbl.)");
+ ItemApplicationEntry.SetRange("Inbound Item Entry No.", TempItemLedgerEntry."Entry No.");
+ ItemApplicationEntry.SetFilter("Posting Date", '<=%1', PostingDate);
+ ItemApplicationEntry.CalcSums(Quantity);
+
+ if ItemApplicationEntry.Quantity > 0 then begin
+ TempRefItemJnlLine."Line No." += 10000;
+ TempRefItemJnlLine."Item No." := TempItemLedgerEntry."Item No.";
+ TempRefItemJnlLine."Location Code" := TempItemLedgerEntry."Location Code";
+ TempRefItemJnlLine."Variant Code" := TempItemLedgerEntry."Variant Code";
+
+ TempRefItemJnlLine.Quantity := ItemApplicationEntry.Quantity;
+ TempRefItemJnlLine."Inventory Value (Calculated)" :=
+ Round(
+ CalculateCostAtDate(TempItemLedgerEntry."Entry No.", PostingDate) /
+ TempItemLedgerEntry.Quantity * ItemApplicationEntry.Quantity, LibraryERM.GetAmountRoundingPrecision());
+ TempRefItemJnlLine."Applies-to Entry" := TempItemLedgerEntry."Entry No.";
+ TempRefItemJnlLine.Insert();
+ end;
+ until TempItemLedgerEntry.Next() = 0;
+ end;
+
+ local procedure CalculateCostAtDate(ItemLedgerEntryNo: Integer; PostingDate: Date): Decimal
+ var
+ ValueEntry: Record "Value Entry";
+ begin
+ ValueEntry.SetCurrentKey("Item Ledger Entry No.", "Entry Type");
+ ValueEntry.SetRange("Item Ledger Entry No.", ItemLedgerEntryNo);
+ ValueEntry.SetRange("Valuation Date", 0D, PostingDate);
+ ValueEntry.CalcSums("Cost Amount (Actual)", "Cost Amount (Expected)");
+ exit(ValueEntry."Cost Amount (Actual)" + ValueEntry."Cost Amount (Expected)");
+ end;
+
+ procedure ExecutePostRevalueInboundILE(Item: Record Item; var TempItemLedgerEntry: Record "Item Ledger Entry" temporary; Factor: Decimal)
+ var
+ ItemJnlBatch: Record "Item Journal Batch";
+ ItemJnlLine: Record "Item Journal Line";
+ EntryNo: Integer;
+ begin
+ LibraryCosting.AdjustCostItemEntries(Item."No.", '');
+ LibraryCosting.CheckAdjustment(Item);
+
+ LibraryInventory.CreateItemJournalBatchByType(ItemJnlBatch, ItemJnlBatch."Template Type"::Revaluation);
+ LibraryInventory.MakeItemJournalLine(ItemJnlLine, ItemJnlBatch, Item, WorkDate(), ItemJnlLine."Entry Type"::Purchase, 0);
+ TempItemLedgerEntry.FindFirst();
+ EntryNo := TempItemLedgerEntry."Entry No.";
+ ItemJnlLine.Validate("Applies-to Entry", EntryNo);
+ ItemJnlLine.Validate("Inventory Value (Revalued)", ItemJnlLine."Inventory Value (Revalued)" * Factor);
+ ItemJnlLine.Insert();
+
+ LibraryInventory.PostItemJournalBatch(ItemJnlBatch);
+ LibraryCosting.AdjustCostItemEntries(Item."No.", '');
+ end;
+
+ procedure CalculateInventoryValueRun(var ItemJnlBatch: Record "Item Journal Batch"; var Item: Record Item; PostingDate: Date; CalculatePer: Enum "Inventory Value Calc. Per"; ByLocation: Boolean; ByVariant: Boolean; UpdStdCost: Boolean; CalcBase: Enum "Inventory Value Calc. Base"; ShowDialog: Boolean; LocationFilter: Code[20]; VariantFilter: Code[20])
+ var
+ RevalueItem: Record Item;
+ ItemJournalLine: Record "Item Journal Line";
+ CalculateInventoryValue: Report "Calculate Inventory Value";
+ DocumentNo: Code[20];
+ begin
+ LibraryInventory.CreateItemJournalBatchByType(ItemJnlBatch, ItemJnlBatch."Template Type"::Revaluation);
+ DocumentNo := LibraryUtility.GenerateRandomCode(ItemJournalLine.FieldNo("Document No."), DATABASE::"Item Journal Line");
+ ItemJournalLine.Validate("Journal Template Name", ItemJnlBatch."Journal Template Name");
+ ItemJournalLine.Validate("Journal Batch Name", ItemJnlBatch.Name);
+ Item.SetFilter("Location Filter", LocationFilter);
+ Item.SetFilter("Variant Filter", VariantFilter);
+ CalculateInventoryValue.UseRequestPage(false);
+ CalculateInventoryValue.SetItemJnlLine(ItemJournalLine);
+ RevalueItem.Copy(Item);
+ if Item."No." <> '' then
+ RevalueItem.SetRange("No.", Item."No.");
+ CalculateInventoryValue.SetTableView(RevalueItem);
+ CalculateInventoryValue.SetParameters(
+ PostingDate, DocumentNo, true, CalculatePer, ByLocation, ByVariant, UpdStdCost, CalcBase, ShowDialog);
+ CalculateInventoryValue.RunModal();
+ end;
+
+ procedure ModifyPostRevaluation(var ItemJnlBatch: Record "Item Journal Batch"; Factor: Decimal)
+ var
+ ItemJnlLine: Record "Item Journal Line";
+ begin
+ ItemJnlLine.SetRange("Journal Template Name", ItemJnlBatch."Journal Template Name");
+ ItemJnlLine.SetRange("Journal Batch Name", ItemJnlBatch.Name);
+ if ItemJnlLine.FindSet() then
+ repeat
+ ItemJnlLine.Validate("Inventory Value (Revalued)",
+ Round(ItemJnlLine."Inventory Value (Revalued)" * Factor, LibraryERM.GetAmountRoundingPrecision()));
+ ItemJnlLine.Modify();
+ until ItemJnlLine.Next() = 0;
+ LibraryInventory.PostItemJournalBatch(ItemJnlBatch);
+ end;
+
+ procedure ModifyAppliesToPostRevaluation(var ItemJnlBatch: Record "Item Journal Batch"; Factor: Decimal; AppliesToEntry: Integer)
+ var
+ ItemJnlLine: Record "Item Journal Line";
+ begin
+ ItemJnlLine.SetRange("Journal Template Name", ItemJnlBatch."Journal Template Name");
+ ItemJnlLine.SetRange("Journal Batch Name", ItemJnlBatch.Name);
+ if ItemJnlLine.FindSet() then
+ repeat
+ ItemJnlLine.Validate("Inventory Value (Revalued)",
+ Round(ItemJnlLine."Inventory Value (Revalued)" * Factor, LibraryERM.GetAmountRoundingPrecision()));
+ ItemJnlLine.Validate("Applies-to Entry", AppliesToEntry);
+ ItemJnlLine.Modify();
+ until ItemJnlLine.Next() = 0;
+ LibraryInventory.PostItemJournalBatch(ItemJnlBatch);
+ end;
+
+ local procedure MAKEXBound(Item: Record Item; Qty: Decimal; Date: Date; EntryType: Enum "Item Ledger Entry Type"; var TempItemJournalLine: Record "Item Journal Line" temporary)
+ var
+ ItemJournalTemplate: Record "Item Journal Template";
+ ItemJournalBatch: Record "Item Journal Batch";
+ ItemJournalLine: Record "Item Journal Line";
+ begin
+ LibraryInventory.CreateItemJournalBatchByType(ItemJournalBatch, ItemJournalTemplate.Type::Item);
+ LibraryInventory.MakeItemJournalLine(ItemJournalLine, ItemJournalBatch, Item, Date, EntryType, Qty);
+ ItemJournalLine.Insert(true);
+ ItemJournalLine.Validate("Posting Date", Date);
+ ItemJournalLine.Validate("Unit Amount", RandCost(Item));
+ ItemJournalLine.Modify(true);
+
+ TempItemJournalLine := ItemJournalLine;
+ TempItemJournalLine.Insert();
+
+ LibraryInventory.PostItemJournalBatch(ItemJournalBatch);
+ end;
+
+ local procedure MAKEInbound(Item: Record Item; Qty: Decimal; Date: Date; var TempItemJournalLine: Record "Item Journal Line" temporary)
+ var
+ ItemJournalLine: Record "Item Journal Line";
+ begin
+ MAKEXBound(Item, Qty, Date, ItemJournalLine."Entry Type"::Purchase, TempItemJournalLine);
+ end;
+
+ local procedure MAKEOutbound(Item: Record Item; Qty: Decimal; Date: Date; var TempItemJournalLine: Record "Item Journal Line" temporary)
+ var
+ ItemJournalLine: Record "Item Journal Line";
+ begin
+ MAKEXBound(Item, Qty, Date, ItemJournalLine."Entry Type"::Sale, TempItemJournalLine);
+ end;
+
+#if not CLEAN26
+ [Obsolete('Moved to codeunit Library Sales', '26.0')]
+ procedure POSTSalesLine(SalesLine: Record "Sales Line"; Ship: Boolean; Invoice: Boolean)
+ begin
+ LibrarySales.PostSalesLine(SalesLine, Ship, Invoice);
+ end;
+#endif
+
+ procedure Minimum(Value1: Decimal; Value2: Decimal): Decimal
+ begin
+ if Value1 < Value2 then
+ exit(Value1);
+
+ exit(Value2);
+ end;
+
+#if not CLEAN26
+ [Obsolete('Moved to codeunit Library Inventory', '26.0')]
+ procedure RevaluationJournalCalcInventory(var ItemJournalBatch: Record "Item Journal Batch"; var Item: Record Item; NewPostingDate: Date; NewDocNo: Code[20]; NewCalculatePer: Enum "Inventory Value Calc. Per"; NewByLocation: Boolean; NewByVariant: Boolean; NewUpdStdCost: Boolean; NewCalcBase: Enum "Inventory Value Calc. Base")
+ begin
+ LibraryInventory.RevaluationJournalCalcInventory(ItemJournalBatch, Item, NewPostingDate, NewDocNo, NewCalculatePer, NewByLocation, NewByVariant, NewUpdStdCost, NewCalcBase);
+ end;
+#endif
+
+ local procedure SetVendorDocNo(var PurchaseHeader: Record "Purchase Header")
+ begin
+ PurchaseHeader."Vendor Invoice No." := LibraryUtility.GenerateGUID();
+ PurchaseHeader."Vendor Cr. Memo No." := LibraryUtility.GenerateGUID();
+ PurchaseHeader.Modify();
+ end;
+}
+
diff --git a/Apps/W1/ApplicationTestLibrary/LibraryPaymentFormat.Codeunit.al b/Apps/W1/ApplicationTestLibrary/LibraryPaymentFormat.Codeunit.al
new file mode 100644
index 0000000000..1d271c2fbe
--- /dev/null
+++ b/Apps/W1/ApplicationTestLibrary/LibraryPaymentFormat.Codeunit.al
@@ -0,0 +1,71 @@
+///
+/// Provides utility functions for creating and managing payment formats and data exchange definitions in test scenarios.
+///
+codeunit 130101 "Library - Payment Format"
+{
+
+ trigger OnRun()
+ begin
+ end;
+
+ var
+ LibraryUtility: Codeunit "Library - Utility";
+
+ procedure CreateDataExchDef(var DataExchDef: Record "Data Exch. Def"; DataHandlingCodeunit: Integer; ValidationCodeunit: Integer; ReadingWritingCodeunit: Integer; ReadingWritingXMLport: Integer; ExternalDataHandlingCodeunit: Integer; UserFeedbackCodeunit: Integer)
+ begin
+ DataExchDef.InsertRecForExport(
+ LibraryUtility.GenerateGUID(), LibraryUtility.GenerateGUID(), DataExchDef.Type::"Payment Export".AsInteger(),
+ ReadingWritingXMLport, DataExchDef."File Type"::"Variable Text");
+ DataExchDef.Validate("Ext. Data Handling Codeunit", ExternalDataHandlingCodeunit);
+ DataExchDef.Validate("Reading/Writing Codeunit", ReadingWritingCodeunit);
+ DataExchDef.Validate("Validation Codeunit", ValidationCodeunit);
+ DataExchDef.Validate("Data Handling Codeunit", DataHandlingCodeunit);
+ DataExchDef.Validate("User Feedback Codeunit", UserFeedbackCodeunit);
+ DataExchDef.Modify(true);
+ end;
+
+ procedure CreateDataExchColumnDef(var DataExchColumnDef: Record "Data Exch. Column Def"; DataExchDefCode: Code[20]; DataExchLineDefCode: Code[20])
+ var
+ GenJnlLine: Record "Gen. Journal Line";
+ begin
+ DataExchColumnDef.InsertRec(DataExchDefCode, DataExchLineDefCode, 1, GenJnlLine.FieldCaption(Description),
+ true, DataExchColumnDef."Data Type"::Text, '', '', GenJnlLine.FieldName(Description));
+ DataExchColumnDef.InsertRec(DataExchDefCode, DataExchLineDefCode, 2, GenJnlLine.FieldCaption("Posting Date"),
+ true, DataExchColumnDef."Data Type"::Date, '', '', GenJnlLine.FieldName("Posting Date"));
+ DataExchColumnDef.InsertRec(DataExchDefCode, DataExchLineDefCode, 3, GenJnlLine.FieldCaption(Amount),
+ true, DataExchColumnDef."Data Type"::Decimal, '', '',
+ GenJnlLine.FieldName(Amount));
+ DataExchColumnDef.Modify(true);
+ end;
+
+ procedure CreateDataExchMapping(var DataExchMapping: Record "Data Exch. Mapping"; DataExchDefCode: Code[20]; DataExchLineDefCode: Code[20]; PreMappingCodeunit: Integer; MappingCodeunit: Integer; PostMappingCodeunit: Integer)
+ begin
+ DataExchMapping.InsertRecForExport(DataExchDefCode, DataExchLineDefCode,
+ DATABASE::"Payment Export Data", LibraryUtility.GenerateGUID(), MappingCodeunit);
+ DataExchMapping.Validate("Pre-Mapping Codeunit", PreMappingCodeunit);
+ DataExchMapping.Validate("Post-Mapping Codeunit", PostMappingCodeunit);
+ DataExchMapping.Modify(true);
+ end;
+
+ procedure CreateDataExchFieldMapping(var DataExchFieldMapping: Record "Data Exch. Field Mapping"; DataExchDefCode: Code[20]; DataExchLineDefCode: Code[20])
+ var
+ PaymentExportData: Record "Payment Export Data";
+ begin
+ DataExchFieldMapping.InsertRec(DataExchDefCode, DataExchLineDefCode,
+ DATABASE::"Payment Export Data", 1, PaymentExportData.FieldNo("Document No."), false, 0);
+ DataExchFieldMapping.InsertRec(DataExchDefCode, DataExchLineDefCode,
+ DATABASE::"Payment Export Data", 2, PaymentExportData.FieldNo("Transfer Date"), false, 0);
+ DataExchFieldMapping.InsertRec(DataExchDefCode, DataExchLineDefCode,
+ DATABASE::"Payment Export Data", 3, PaymentExportData.FieldNo(Amount), false, 1);
+ end;
+
+ procedure CreateBankExportImportSetup(var BankExportImportSetup: Record "Bank Export/Import Setup"; DataExchDef: Record "Data Exch. Def")
+ begin
+ BankExportImportSetup.Validate(Code, LibraryUtility.GenerateGUID());
+ BankExportImportSetup.Validate(Name, DataExchDef.Name);
+ BankExportImportSetup.Validate(Direction, BankExportImportSetup.Direction::Export);
+ BankExportImportSetup.Validate("Data Exch. Def. Code", DataExchDef.Code);
+ BankExportImportSetup.Insert(true);
+ end;
+}
+
diff --git a/Apps/W1/ApplicationTestLibrary/LibraryPlanning.Codeunit.al b/Apps/W1/ApplicationTestLibrary/LibraryPlanning.Codeunit.al
new file mode 100644
index 0000000000..641c8076d3
--- /dev/null
+++ b/Apps/W1/ApplicationTestLibrary/LibraryPlanning.Codeunit.al
@@ -0,0 +1,454 @@
+///
+/// Provides utility functions for creating and managing planning-related entities in test scenarios, including requisition worksheets and planning components.
+///
+codeunit 132203 "Library - Planning"
+{
+
+ trigger OnRun()
+ begin
+ end;
+
+ var
+ InventorySetup: Record "Inventory Setup";
+ LibraryUtility: Codeunit "Library - Utility";
+
+#if not CLEAN27
+#pragma warning disable AL0801
+ [Obsolete('Moved to codeunit LibraryManufacturing', '27.0')]
+ procedure CreateProdOrderUsingPlanning(var ProductionOrder: Record "Production Order"; Status: Enum "Production Order Status"; DocumentNo: Code[20]; SourceNo: Code[20])
+ var
+ LibraryManufacturing: Codeunit "Library - Manufacturing";
+ begin
+ LibraryManufacturing.CreateProdOrderUsingPlanning(ProductionOrder, Status, DocumentNo, SourceNo);
+ end;
+#pragma warning restore AL0801
+#endif
+
+ [Normal]
+ procedure CreateRequisitionWkshName(var RequisitionWkshName: Record "Requisition Wksh. Name"; WorksheetTemplateName: Code[10])
+ begin
+ // Create Requisition Wksh. Name with a random Name of String length less than 10.
+ RequisitionWkshName.Init();
+ RequisitionWkshName.Validate("Worksheet Template Name", WorksheetTemplateName);
+ RequisitionWkshName.Validate(
+ Name,
+ CopyStr(
+ LibraryUtility.GenerateRandomCode(RequisitionWkshName.FieldNo(Name), DATABASE::"Requisition Wksh. Name"),
+ 1, LibraryUtility.GetFieldLength(DATABASE::"Requisition Wksh. Name", RequisitionWkshName.FieldNo(Name))));
+ RequisitionWkshName.Insert(true);
+ end;
+
+ procedure CalculateLowLevelCode()
+ var
+ LowLevelCodeCalculator: Codeunit "Low-Level Code Calculator";
+ begin
+ Clear(LowLevelCodeCalculator);
+ LowLevelCodeCalculator.Run();
+ end;
+
+ procedure CalculateOrderPlanProduction(var RequisitionLine: Record "Requisition Line")
+ var
+ OrderPlanningMgt: Codeunit "Order Planning Mgt.";
+ begin
+ OrderPlanningMgt.SetDemandType("Demand Order Source Type"::"Production Demand");
+ OrderPlanningMgt.GetOrdersToPlan(RequisitionLine);
+ end;
+
+ procedure CalculateOrderPlanAssembly(var RequisitionLine: Record "Requisition Line")
+ var
+ OrderPlanningMgt: Codeunit "Order Planning Mgt.";
+ begin
+ OrderPlanningMgt.SetDemandType("Demand Order Source Type"::"Assembly Demand");
+ OrderPlanningMgt.GetOrdersToPlan(RequisitionLine);
+ end;
+
+ procedure CalculateOrderPlanSales(var RequisitionLine: Record "Requisition Line")
+ var
+ OrderPlanningMgt: Codeunit "Order Planning Mgt.";
+ begin
+ OrderPlanningMgt.SetDemandType("Demand Order Source Type"::"Sales Demand");
+ OrderPlanningMgt.GetOrdersToPlan(RequisitionLine);
+ end;
+
+ procedure CalculateOrderPlanService(var RequisitionLine: Record "Requisition Line")
+ var
+ OrderPlanningMgt: Codeunit "Order Planning Mgt.";
+ begin
+ OrderPlanningMgt.SetDemandType("Demand Order Source Type"::"Service Demand");
+ OrderPlanningMgt.GetOrdersToPlan(RequisitionLine);
+ end;
+
+ procedure CalculateOrderPlanJob(var RequisitionLine: Record "Requisition Line")
+ var
+ OrderPlanningMgt: Codeunit "Order Planning Mgt.";
+ begin
+ OrderPlanningMgt.SetDemandType("Demand Order Source Type"::"Job Demand");
+ OrderPlanningMgt.GetOrdersToPlan(RequisitionLine);
+ end;
+
+ procedure CalculatePlanForReqWksh(var Item: Record Item; TemplateName: Code[10]; WorksheetName: Code[10]; StartDate: Date; EndDate: Date)
+ var
+ TmpItem: Record Item;
+ CalculatePlanReqWksh: Report "Calculate Plan - Req. Wksh.";
+ begin
+ CalculatePlanReqWksh.SetTemplAndWorksheet(TemplateName, WorksheetName);
+ CalculatePlanReqWksh.InitializeRequest(StartDate, EndDate);
+ if Item.HasFilter then
+ TmpItem.CopyFilters(Item)
+ else begin
+ Item.Get(Item."No.");
+ TmpItem.SetRange("No.", Item."No.");
+ end;
+ CalculatePlanReqWksh.SetTableView(TmpItem);
+ CalculatePlanReqWksh.UseRequestPage(false);
+ CalculatePlanReqWksh.RunModal();
+ end;
+
+ procedure CalcRequisitionPlanForReqWksh(var Item: Record Item; StartDate: Date; EndDate: Date)
+ var
+ RequisitionWkshName: Record "Requisition Wksh. Name";
+ begin
+ SelectRequisitionWkshName(RequisitionWkshName, RequisitionWkshName."Template Type"::"Req.");
+ CalculatePlanForReqWksh(Item, RequisitionWkshName."Worksheet Template Name", RequisitionWkshName.Name, StartDate, EndDate);
+ end;
+
+ procedure CalcRequisitionPlanForReqWkshAndGetLines(var RequisitionLine: Record "Requisition Line"; var Item: Record Item; StartDate: Date; EndDate: Date)
+ var
+ RequisitionWkshName: Record "Requisition Wksh. Name";
+ begin
+ SelectRequisitionWkshName(RequisitionWkshName, RequisitionWkshName."Template Type"::"Req.");
+ CalculatePlanForReqWksh(Item, RequisitionWkshName."Worksheet Template Name", RequisitionWkshName.Name, StartDate, EndDate);
+
+ FindRequisitionLine(RequisitionLine, RequisitionWkshName, Item."No.");
+ end;
+
+ local procedure CalculatePlanOnPlanningWorksheet(var ItemRec: Record Item; OrderDate: Date; ToDate: Date; RespectPlanningParameters: Boolean; Regenerative: Boolean)
+ var
+ TmpItemRec: Record Item;
+ RequisitionWkshName: Record "Requisition Wksh. Name";
+ CalculatePlanPlanWksh: Report "Calculate Plan - Plan. Wksh.";
+ begin
+ SelectRequisitionWkshName(RequisitionWkshName, RequisitionWkshName."Template Type"::Planning); // Find Requisition Worksheet Name to Calculate Plan.
+ Commit();
+ CalculatePlanPlanWksh.InitializeRequest(OrderDate, ToDate, RespectPlanningParameters);
+ CalculatePlanPlanWksh.SetTemplAndWorksheet(RequisitionWkshName."Worksheet Template Name", RequisitionWkshName.Name, Regenerative);
+ if ItemRec.HasFilter then
+ TmpItemRec.CopyFilters(ItemRec)
+ else begin
+ ItemRec.Get(ItemRec."No.");
+ TmpItemRec.SetRange("No.", ItemRec."No.");
+ end;
+ CalculatePlanPlanWksh.SetTableView(TmpItemRec);
+ CalculatePlanPlanWksh.UseRequestPage(false);
+ CalculatePlanPlanWksh.RunModal();
+ end;
+
+ procedure CalcRegenPlanForPlanWksh(var ItemRec: Record Item; OrderDate: Date; ToDate: Date)
+ begin
+ CalcRegenPlanForPlanWkshPlanningParams(ItemRec, OrderDate, ToDate, false);
+ end;
+
+ procedure CalcRegenPlanForPlanWkshPlanningParams(var ItemRec: Record Item; OrderDate: Date; ToDate: Date; RespectPlanningParameters: Boolean)
+ begin
+ CalculatePlanOnPlanningWorksheet(ItemRec, OrderDate, ToDate, RespectPlanningParameters, true); // Passing True for Regenerative Boolean.
+ end;
+
+ procedure CalcNetChangePlanForPlanWksh(var ItemRec: Record Item; OrderDate: Date; ToDate: Date; RespectPlanningParameters: Boolean)
+ begin
+ CalculatePlanOnPlanningWorksheet(ItemRec, OrderDate, ToDate, RespectPlanningParameters, false); // Passing False for Regenerative Boolean.
+ end;
+
+ procedure CarryOutActionMsgPlanWksh(var ReqLineRec: Record "Requisition Line")
+ var
+ TmpReqLineRec: Record "Requisition Line";
+ CarryOutActionMsgPlan: Report "Carry Out Action Msg. - Plan.";
+ begin
+ Commit();
+ CarryOutActionMsgPlan.InitializeRequest(2, 1, 1, 1);
+ if ReqLineRec.HasFilter then
+ TmpReqLineRec.CopyFilters(ReqLineRec)
+ else begin
+ ReqLineRec.Get(ReqLineRec."Worksheet Template Name",
+ ReqLineRec."Journal Batch Name", ReqLineRec."Line No.");
+ TmpReqLineRec.SetRange("Worksheet Template Name", ReqLineRec."Worksheet Template Name");
+ TmpReqLineRec.SetRange("Journal Batch Name", ReqLineRec."Journal Batch Name");
+ TmpReqLineRec.SetRange("Line No.", ReqLineRec."Line No.");
+ end;
+ CarryOutActionMsgPlan.SetReqWkshLine(ReqLineRec);
+ CarryOutActionMsgPlan.SetTableView(TmpReqLineRec);
+ CarryOutActionMsgPlan.UseRequestPage(false);
+ CarryOutActionMsgPlan.RunModal();
+ end;
+
+ procedure CarryOutPlanWksh(var RequisitionLine: Record "Requisition Line"; NewProdOrderChoice: Option; NewPurchOrderChoice: Option; NewTransOrderChoice: Option; NewAsmOrderChoice: Option; NewReqWkshTemp: Code[10]; NewReqWksh: Code[10]; NewTransWkshTemp: Code[10]; NewTransWkshName: Code[10])
+ var
+ CarryOutActionMsgPlan: Report "Carry Out Action Msg. - Plan.";
+ begin
+ CarryOutActionMsgPlan.SetReqWkshLine(RequisitionLine);
+ CarryOutActionMsgPlan.InitializeRequest2(
+ NewProdOrderChoice, NewPurchOrderChoice, NewTransOrderChoice, NewAsmOrderChoice,
+ NewReqWkshTemp, NewReqWksh, NewTransWkshTemp, NewTransWkshName);
+ CarryOutActionMsgPlan.SetTableView(RequisitionLine);
+ CarryOutActionMsgPlan.UseRequestPage(false);
+ CarryOutActionMsgPlan.Run();
+ end;
+
+ procedure CarryOutReqWksh(var RequisitionLine: Record "Requisition Line"; ExpirationDate: Date; OrderDate: Date; PostingDate: Date; ExpectedReceiptDate: Date; YourRef: Text[50])
+ var
+ CarryOutActionMsgReq: Report "Carry Out Action Msg. - Req.";
+ begin
+ CarryOutActionMsgReq.SetReqWkshLine(RequisitionLine);
+ CarryOutActionMsgReq.InitializeRequest(ExpirationDate, OrderDate, PostingDate, ExpectedReceiptDate, YourRef);
+ CarryOutActionMsgReq.UseRequestPage(false);
+ CarryOutActionMsgReq.Run();
+ CarryOutActionMsgReq.GetReqWkshLine(RequisitionLine);
+ end;
+
+ procedure CarryOutAMSubcontractWksh(var RequisitionLine: Record "Requisition Line")
+ var
+ CarryOutActionMsgReq: Report "Carry Out Action Msg. - Req.";
+ begin
+ CarryOutActionMsgReq.SetReqWkshLine(RequisitionLine);
+ CarryOutActionMsgReq.UseRequestPage(false);
+ CarryOutActionMsgReq.RunModal();
+ end;
+
+ procedure CreateManufUserTemplate(var ManufacturingUserTemplate: Record "Manufacturing User Template"; UserID: Code[50]; MakeOrders: Option; CreatePurchaseOrder: Enum "Planning Create Purchase Order"; CreateProductionOrder: Enum "Planning Create Prod. Order"; CreateTransferOrder: Enum "Planning Create Transfer Order")
+ begin
+ ManufacturingUserTemplate.Init();
+ ManufacturingUserTemplate."User ID" := UserID;
+ ManufacturingUserTemplate.Insert(true);
+ ManufacturingUserTemplate.Validate("Make Orders", MakeOrders);
+ ManufacturingUserTemplate.Validate("Create Purchase Order", CreatePurchaseOrder);
+ ManufacturingUserTemplate.Validate("Create Production Order", CreateProductionOrder);
+ ManufacturingUserTemplate.Validate("Create Transfer Order", CreateTransferOrder);
+ ManufacturingUserTemplate.Modify(true);
+ end;
+
+ procedure CreateRequisitionLine(var RequisitionLine: Record "Requisition Line"; WorksheetTemplateName: Code[10]; JournalBatchName: Code[10])
+ var
+ RecRef: RecordRef;
+ begin
+ RequisitionLine.Init();
+ RequisitionLine.Validate("Worksheet Template Name", WorksheetTemplateName);
+ RequisitionLine.Validate("Journal Batch Name", JournalBatchName);
+ RecRef.GetTable(RequisitionLine);
+ RequisitionLine.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, RequisitionLine.FieldNo("Line No.")));
+ RequisitionLine.Insert(true);
+ end;
+
+ procedure CreatePlanningComponent(var PlanningComponent: Record "Planning Component"; var RequisitionLine: Record "Requisition Line")
+ var
+ RecRef: RecordRef;
+ begin
+ PlanningComponent.Init();
+ PlanningComponent.Validate("Worksheet Template Name", RequisitionLine."Worksheet Template Name");
+ PlanningComponent.Validate("Worksheet Batch Name", RequisitionLine."Journal Batch Name");
+ PlanningComponent.Validate("Worksheet Line No.", RequisitionLine."Line No.");
+ RecRef.GetTable(PlanningComponent);
+ PlanningComponent.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, PlanningComponent.FieldNo("Line No.")));
+ PlanningComponent.Insert(true);
+ end;
+
+#if not CLEAN27
+#pragma warning disable AL0801
+ [Obsolete('Moved to codeunit LibraryManufacturing', '27.0')]
+ procedure CreatePlanningRoutingLine(var PlanningRoutingLine: Record "Planning Routing Line"; var RequisitionLine: Record "Requisition Line"; OperationNo: Code[10])
+ var
+ LibraryManfacturing: Codeunit "Library - Manufacturing";
+ begin
+ LibraryManfacturing.CreatePlanningRoutingLine(PlanningRoutingLine, RequisitionLine, OperationNo);
+ end;
+#pragma warning restore AL0801
+#endif
+
+ local procedure FindRequisitionLine(var RequisitionLine: Record "Requisition Line"; RequisitionWkshName: Record "Requisition Wksh. Name"; ItemNo: Code[20])
+ begin
+ RequisitionLine.SetRange("Worksheet Template Name", RequisitionWkshName."Worksheet Template Name");
+ RequisitionLine.SetRange("Journal Batch Name", RequisitionWkshName.Name);
+ RequisitionLine.SetRange("No.", ItemNo);
+ RequisitionLine.FindFirst();
+ end;
+
+ procedure GetActionMessages(var Item: Record Item)
+ var
+ TmpItem: Record Item;
+ RequisitionWkshName: Record "Requisition Wksh. Name";
+ GetActionMessagesReport: Report "Get Action Messages";
+ begin
+ SelectRequisitionWkshName(RequisitionWkshName, RequisitionWkshName."Template Type"::Planning);
+ GetActionMessagesReport.SetTemplAndWorksheet(RequisitionWkshName."Worksheet Template Name", RequisitionWkshName.Name);
+ GetActionMessagesReport.UseRequestPage(false);
+ if Item.HasFilter then
+ TmpItem.CopyFilters(Item)
+ else begin
+ Item.Get(Item."No.");
+ TmpItem.SetRange("No.", Item."No.");
+ end;
+ GetActionMessagesReport.SetTableView(TmpItem);
+ GetActionMessagesReport.Run();
+ end;
+
+ procedure GetSalesOrders(SalesLine: Record "Sales Line"; RequisitionLine: Record "Requisition Line"; RetrieveDimensionsFrom: Option)
+ var
+ GetSalesOrdersReport: Report "Get Sales Orders";
+ begin
+ SalesLine.SetRange("Document Type", SalesLine."Document Type");
+ SalesLine.SetRange("Document No.", SalesLine."Document No.");
+ Clear(GetSalesOrdersReport);
+ GetSalesOrdersReport.SetTableView(SalesLine);
+ GetSalesOrdersReport.InitializeRequest(RetrieveDimensionsFrom);
+ GetSalesOrdersReport.SetReqWkshLine(RequisitionLine, 0);
+ GetSalesOrdersReport.UseRequestPage(false);
+ GetSalesOrdersReport.RunModal();
+ end;
+
+ procedure GetSpecialOrder(var RequisitionLine: Record "Requisition Line"; No: Code[20])
+ var
+ SalesLine: Record "Sales Line";
+ GetSalesOrdersReport: Report "Get Sales Orders";
+ NewRetrieveDimensionsFrom: Option Item,SalesLine;
+ begin
+ SalesLine.SetRange("No.", No);
+ GetSalesOrdersReport.SetReqWkshLine(RequisitionLine, 1); // Value required.
+ GetSalesOrdersReport.SetTableView(SalesLine);
+ GetSalesOrdersReport.InitializeRequest(NewRetrieveDimensionsFrom::Item);
+ GetSalesOrdersReport.UseRequestPage(false);
+ GetSalesOrdersReport.Run();
+ end;
+
+ procedure MakeSupplyOrders(var ManufacturingUserTemplate: Record "Manufacturing User Template"; var RequisitionLine: Record "Requisition Line")
+ var
+ MakeSupplyOrdersYesNo: Codeunit "Make Supply Orders (Yes/No)";
+ begin
+ MakeSupplyOrdersYesNo.SetManufUserTemplate(ManufacturingUserTemplate);
+ MakeSupplyOrdersYesNo.Run(RequisitionLine);
+ end;
+
+ procedure RefreshPlanningLine(var RequisitionLine: Record "Requisition Line"; SchDirection: Option; CalcRouting: Boolean; CalcCompNeed: Boolean)
+ var
+ TmpRequisitionLine: Record "Requisition Line";
+ RefreshPlanningDemand: Report "Refresh Planning Demand";
+ begin
+ RefreshPlanningDemand.InitializeRequest(SchDirection, CalcRouting, CalcCompNeed);
+ if RequisitionLine.HasFilter then
+ TmpRequisitionLine.CopyFilters(RequisitionLine)
+ else begin
+ RequisitionLine.Get(RequisitionLine."Worksheet Template Name",
+ RequisitionLine."Journal Batch Name", RequisitionLine."Line No.");
+ TmpRequisitionLine.SetRange("Worksheet Template Name", RequisitionLine."Worksheet Template Name");
+ TmpRequisitionLine.SetRange("Journal Batch Name", RequisitionLine."Journal Batch Name");
+ TmpRequisitionLine.SetRange("Line No.", RequisitionLine."Line No.");
+ end;
+ RefreshPlanningDemand.SetTableView(TmpRequisitionLine);
+ RefreshPlanningDemand.UseRequestPage(false);
+ RefreshPlanningDemand.RunModal();
+ end;
+
+ procedure SelectRequisitionTemplateName(): Code[10]
+ var
+ ReqWkshTemplate: Record "Req. Wksh. Template";
+ begin
+ ReqWkshTemplate.SetRange(Type, ReqWkshTemplate.Type::Planning);
+ ReqWkshTemplate.SetRange(Recurring, false);
+ if not ReqWkshTemplate.FindFirst() then begin
+ ReqWkshTemplate.Init();
+ ReqWkshTemplate.Validate(
+ Name, LibraryUtility.GenerateRandomCode(ReqWkshTemplate.FieldNo(Name), DATABASE::"Req. Wksh. Template"));
+ ReqWkshTemplate.Insert(true);
+ ReqWkshTemplate.Validate(Type, ReqWkshTemplate.Type::Planning);
+ ReqWkshTemplate.Modify(true);
+ end;
+ exit(ReqWkshTemplate.Name);
+ end;
+
+ procedure SelectRequisitionWkshName(var RequisitionWkshName: Record "Requisition Wksh. Name"; TemplateType: Enum "Req. Worksheet Template Type")
+ begin
+ RequisitionWkshName.SetRange("Template Type", TemplateType);
+ RequisitionWkshName.SetRange(Recurring, false);
+ if not RequisitionWkshName.FindFirst() then
+ CreateRequisitionWkshName(RequisitionWkshName, SelectRequisitionTemplateName());
+ end;
+
+ procedure SetDemandForecast(CurrentDemandForecast: Code[10])
+ begin
+ InventorySetup.Get();
+ InventorySetup.Validate("Current Demand Forecast", CurrentDemandForecast);
+ InventorySetup.Modify();
+ end;
+
+ procedure SetUseForecastOnVariants(UseForecastOnVariants: Boolean)
+ begin
+ InventorySetup.Get();
+ InventorySetup.Validate("Use Forecast on Variants", UseForecastOnVariants);
+ InventorySetup.Modify();
+ end;
+
+ procedure SetUseForecastOnLocations(UseForecastOnLocations: Boolean)
+ begin
+ InventorySetup.Get();
+ InventorySetup.Validate("Use Forecast on Locations", UseForecastOnLocations);
+ InventorySetup.Modify();
+ end;
+
+ procedure SetDefaultDampenerPercent(DampenerPercent: Decimal)
+ begin
+ InventorySetup.Get();
+ InventorySetup.Validate("Default Dampener %", DampenerPercent);
+ InventorySetup.Modify();
+ end;
+
+ procedure SetDefaultDampenerPeriod(DampenerPeriod: Text)
+ begin
+ InventorySetup.Get();
+ Evaluate(InventorySetup."Default Dampener Period", DampenerPeriod);
+ InventorySetup.Modify();
+ end;
+
+ procedure SetDefaultSafetyLeadTime(SafetyLeadTime: DateFormula)
+ begin
+ InventorySetup.Get();
+ InventorySetup.Validate("Default Safety Lead Time", SafetyLeadTime);
+ InventorySetup.Modify();
+ end;
+
+ procedure SetDefaultSafetyLeadTime(SafetyLeadTime: Text)
+ begin
+ InventorySetup.Get();
+ Evaluate(InventorySetup."Default Safety Lead Time", SafetyLeadTime);
+ InventorySetup.Modify();
+ end;
+
+ procedure SetSafetyWorkDate(): Date
+ begin
+ InventorySetup.Get();
+ exit(CalcDate(InventorySetup."Default Safety Lead Time", WorkDate()));
+ end;
+
+ procedure SetBlankOverflowLevel(BlankOverflowLevel: Option)
+ begin
+ InventorySetup.Get();
+ InventorySetup.Validate("Blank Overflow Level", BlankOverflowLevel);
+ InventorySetup.Modify();
+ end;
+
+ procedure SetCombinedMPSMRPCalculation(CombinedMPSMRPCalculation: Boolean)
+ begin
+ InventorySetup.Get();
+ InventorySetup.Validate("Combined MPS/MRP Calculation", CombinedMPSMRPCalculation);
+ InventorySetup.Modify();
+ end;
+
+#if not CLEAN27
+#pragma warning disable AL0801
+ [Obsolete('Moved to codeunit LibraryManufacturing', '27.0')]
+ procedure SetComponentsAtLocation(LocationCode: Code[10])
+ var
+ LibraryManufacturing: Codeunit "Library - Manufacturing";
+ begin
+ LibraryManufacturing.SetComponentsAtLocation(LocationCode);
+ end;
+#pragma warning restore AL0801
+#endif
+}
+
diff --git a/Apps/W1/ApplicationTestLibrary/LibraryPmtDiscSetup.Codeunit.al b/Apps/W1/ApplicationTestLibrary/LibraryPmtDiscSetup.Codeunit.al
new file mode 100644
index 0000000000..7dff4be0ba
--- /dev/null
+++ b/Apps/W1/ApplicationTestLibrary/LibraryPmtDiscSetup.Codeunit.al
@@ -0,0 +1,117 @@
+///
+/// Provides utility functions for setting up and managing payment discount scenarios in test cases.
+///
+codeunit 131303 "Library - Pmt Disc Setup"
+{
+
+ trigger OnRun()
+ begin
+ end;
+
+ var
+ GeneralLedgerSetup: Record "General Ledger Setup";
+
+ procedure ClearAdjustPmtDiscInVATSetup()
+ var
+ VATPostingSetup: Record "VAT Posting Setup";
+ begin
+ VATPostingSetup.SetRange("Adjust for Payment Discount", true);
+ VATPostingSetup.ModifyAll("Adjust for Payment Discount", false, true);
+ end;
+
+ procedure GetPmtDiscGracePeriod(): Text
+ begin
+ GeneralLedgerSetup.Get();
+ exit(Format(GeneralLedgerSetup."Payment Discount Grace Period"));
+ end;
+
+ procedure GetPmtTolerancePct(): Decimal
+ begin
+ GeneralLedgerSetup.Get();
+ exit(GeneralLedgerSetup."Payment Tolerance %");
+ end;
+
+ procedure GetPaymentTermsDiscountPct(PaymentTermsCode: Code[10]): Decimal
+ var
+ PaymentTerms: Record "Payment Terms";
+ begin
+ PaymentTerms.Get(PaymentTermsCode);
+ exit(PaymentTerms."Discount %");
+ end;
+
+ procedure GetPaymentTermsDiscountDate(PaymentTermsCode: Code[10]): Date
+ var
+ PaymentTerms: Record "Payment Terms";
+ begin
+ PaymentTerms.Get(PaymentTermsCode);
+ exit(CalcDate(PaymentTerms."Discount Date Calculation", WorkDate()));
+ end;
+
+ procedure SetAdjustForPaymentDisc(AdjustForPaymentDisc: Boolean)
+ begin
+ GeneralLedgerSetup.Get();
+ GeneralLedgerSetup.Validate("Adjust for Payment Disc.", AdjustForPaymentDisc);
+ GeneralLedgerSetup.Modify(true);
+ end;
+
+ procedure SetPmtDiscExclVAT(PmtDiscExclVAT: Boolean)
+ begin
+ GeneralLedgerSetup.Get();
+ GeneralLedgerSetup.Validate("Pmt. Disc. Excl. VAT", PmtDiscExclVAT);
+ GeneralLedgerSetup.Modify(true);
+ end;
+
+ procedure SetPmtDiscGracePeriod(GracePeriod: DateFormula)
+ begin
+ GeneralLedgerSetup.Get();
+ GeneralLedgerSetup.Validate("Payment Discount Grace Period", GracePeriod);
+ GeneralLedgerSetup.Modify(true);
+ end;
+
+ procedure SetPmtDiscGracePeriodByText(DateFormulaText: Text)
+ var
+ GracePeriod: DateFormula;
+ begin
+ Evaluate(GracePeriod, DateFormulaText);
+ SetPmtDiscGracePeriod(GracePeriod);
+ end;
+
+ procedure SetPmtTolerance(PaymentTolerancePct: Decimal)
+ begin
+ SetPmtDiscGracePeriodByText('<5D>');
+ GeneralLedgerSetup.Validate("Payment Tolerance %", PaymentTolerancePct);
+ GeneralLedgerSetup.Validate("Max. Payment Tolerance Amount", 5);
+ SetPmtTolerancePostings();
+ SetPmtToleranceWarnings();
+ GeneralLedgerSetup.Modify(true);
+ end;
+
+ local procedure SetPmtTolerancePostings()
+ begin
+ GeneralLedgerSetup.Validate(
+ "Pmt. Disc. Tolerance Posting", GeneralLedgerSetup."Pmt. Disc. Tolerance Posting"::"Payment Discount Accounts");
+ GeneralLedgerSetup.Validate(
+ "Payment Tolerance Posting", GeneralLedgerSetup."Payment Tolerance Posting"::"Payment Discount Accounts");
+ end;
+
+ local procedure SetPmtToleranceWarnings()
+ begin
+ GeneralLedgerSetup.Validate("Pmt. Disc. Tolerance Warning", true);
+ GeneralLedgerSetup.Validate("Payment Tolerance Warning", true);
+ end;
+
+ procedure SetPmtToleranceWarning(PmtToleranceWarning: Boolean)
+ begin
+ GeneralLedgerSetup.Get();
+ GeneralLedgerSetup.Validate("Payment Tolerance Warning", PmtToleranceWarning);
+ GeneralLedgerSetup.Modify(true);
+ end;
+
+ procedure SetPmtDiscToleranceWarning(PmtDiscToleranceWarning: Boolean)
+ begin
+ GeneralLedgerSetup.Get();
+ GeneralLedgerSetup.Validate("Pmt. Disc. Tolerance Warning", PmtDiscToleranceWarning);
+ GeneralLedgerSetup.Modify(true);
+ end;
+}
+
diff --git a/Apps/W1/ApplicationTestLibrary/LibraryPriceCalculation.Codeunit.al b/Apps/W1/ApplicationTestLibrary/LibraryPriceCalculation.Codeunit.al
new file mode 100644
index 0000000000..c8eb06f183
--- /dev/null
+++ b/Apps/W1/ApplicationTestLibrary/LibraryPriceCalculation.Codeunit.al
@@ -0,0 +1,395 @@
+///
+/// Provides utility functions for creating and managing price calculation setup and testing various pricing scenarios.
+///
+codeunit 130510 "Library - Price Calculation"
+{
+
+ EventSubscriberInstance = Manual;
+
+ trigger OnRun()
+ begin
+ end;
+
+ var
+ LibraryPriceCalculation: Codeunit "Library - Price Calculation";
+ LibraryRandom: Codeunit "Library - Random";
+ LibraryUtility: Codeunit "Library - Utility";
+ LastHandlerId: Enum "Price Calculation Handler";
+ DefaultPriceListTok: Label 'Default price list.';
+
+ procedure AddSetup(var PriceCalculationSetup: Record "Price Calculation Setup"; NewMethod: Enum "Price Calculation Method"; PriceType: Enum "Price Type"; AssetType: Enum "Price Asset Type"; NewImplementation: Enum "Price Calculation Handler"; NewDefault: Boolean): Code[100];
+ begin
+ PriceCalculationSetup.Init();
+ PriceCalculationSetup.Method := NewMethod;
+ PriceCalculationSetup.Type := PriceType;
+ PriceCalculationSetup."Asset Type" := AssetType;
+ PriceCalculationSetup.Implementation := NewImplementation;
+ PriceCalculationSetup.Default := NewDefault;
+ PriceCalculationSetup.Enabled := true;
+ PriceCalculationSetup.Insert(true);
+ exit(PriceCalculationSetup.Code)
+ end;
+
+ procedure AddDtldSetup(var DtldPriceCalculationSetup: Record "Dtld. Price Calculation Setup"; PriceType: Enum "Price Type"; AssetType: Enum "Price Asset Type"; AssetNo: code[20]; SourceGroup: Enum "Price Source Group"; SourceNo: Code[20])
+ begin
+ if DtldPriceCalculationSetup.IsTemporary then
+ DtldPriceCalculationSetup."Line No." += 1
+ else
+ DtldPriceCalculationSetup."Line No." := 0;
+ DtldPriceCalculationSetup.Type := PriceType;
+ DtldPriceCalculationSetup."Asset Type" := AssetType;
+ DtldPriceCalculationSetup."Asset No." := AssetNo;
+ DtldPriceCalculationSetup.Validate("Source Group", SourceGroup);
+ DtldPriceCalculationSetup."Source No." := SourceNo;
+ DtldPriceCalculationSetup.Enabled := true;
+ DtldPriceCalculationSetup.Insert(true);
+ end;
+
+ procedure AddDtldSetup(var DtldPriceCalculationSetup: Record "Dtld. Price Calculation Setup"; SetupCode: Code[100]; AssetNo: code[20]; SourceGroup: Enum "Price Source Group"; SourceNo: Code[20])
+ begin
+ if DtldPriceCalculationSetup.IsTemporary then
+ DtldPriceCalculationSetup."Line No." += 1
+ else
+ DtldPriceCalculationSetup."Line No." := 0;
+ DtldPriceCalculationSetup.Validate("Setup Code", SetupCode);
+ DtldPriceCalculationSetup."Asset No." := AssetNo;
+ DtldPriceCalculationSetup.Validate("Source Group", SourceGroup);
+ DtldPriceCalculationSetup."Source No." := SourceNo;
+ DtldPriceCalculationSetup.Enabled := true;
+ DtldPriceCalculationSetup.Insert(true);
+ end;
+
+ procedure DisableSetup(var PriceCalculationSetup: Record "Price Calculation Setup")
+ begin
+ PriceCalculationSetup.Enabled := false;
+ PriceCalculationSetup.Modify();
+ end;
+
+ procedure DisableDtldSetup(var DtldPriceCalculationSetup: Record "Dtld. Price Calculation Setup")
+ begin
+ DtldPriceCalculationSetup.Enabled := false;
+ DtldPriceCalculationSetup.Modify();
+ end;
+
+ procedure DisableExtendedPriceCalculation()
+ begin
+ // turn off ExtendedPriceCalculationEnabledHandler
+ UnbindSubscription(LibraryPriceCalculation);
+ end;
+
+ procedure EnableExtendedPriceCalculation()
+ begin
+ // turn on ExtendedPriceCalculationEnabledHandler
+ UnbindSubscription(LibraryPriceCalculation);
+ BindSubscription(LibraryPriceCalculation);
+ end;
+
+ procedure EnableExtendedPriceCalculation(Enable: Boolean)
+ begin
+ // turn on/off ExtendedPriceCalculationEnabledHandler
+ UnbindSubscription(LibraryPriceCalculation);
+ if Enable then
+ BindSubscription(LibraryPriceCalculation);
+ end;
+
+ procedure SetupDefaultHandler(NewImplementation: Enum "Price Calculation Handler") xImplementation: Enum "Price Calculation Handler";
+ var
+ PriceCalculationSetup: Record "Price Calculation Setup";
+ PriceCalculationMgt: Codeunit "Price Calculation Mgt.";
+ begin
+ if LastHandlerId = NewImplementation then
+ exit;
+ PriceCalculationSetup.SetRange(Default, true);
+ if PriceCalculationSetup.FindFirst() then
+ xImplementation := PriceCalculationSetup.Implementation
+ else
+ xImplementation := NewImplementation;
+
+ PriceCalculationSetup.Reset();
+ PriceCalculationSetup.DeleteAll();
+ PriceCalculationMgt.Run();
+ PriceCalculationSetup.Modifyall(Default, false);
+
+ PriceCalculationSetup.SetRange(Implementation, NewImplementation);
+ PriceCalculationSetup.Modifyall(Default, true, true);
+
+ LastHandlerId := NewImplementation;
+ end;
+
+ procedure AllowEditingActiveSalesPrice()
+ begin
+ AllowEditingActiveSalesPrice(true);
+ end;
+
+ local procedure AllowEditingActiveSalesPrice(AllowEditingActivePrice: Boolean)
+ var
+ SalesReceivablesSetup: Record "Sales & Receivables Setup";
+ begin
+ SalesReceivablesSetup.Get();
+ SalesReceivablesSetup."Allow Editing Active Price" := AllowEditingActivePrice;
+ SalesReceivablesSetup.Modify();
+ end;
+
+ procedure AllowEditingActivePurchPrice()
+ begin
+ AllowEditingActivePurchPrice(true);
+ end;
+
+ local procedure AllowEditingActivePurchPrice(AllowEditingActivePrice: Boolean)
+ var
+ PurchasesPayablesSetup: Record "Purchases & Payables Setup";
+ begin
+ PurchasesPayablesSetup.Get();
+ PurchasesPayablesSetup."Allow Editing Active Price" := AllowEditingActivePrice;
+ PurchasesPayablesSetup.Modify();
+ end;
+
+ procedure DisallowEditingActiveSalesPrice()
+ begin
+ AllowEditingActiveSalesPrice(false);
+ end;
+
+ procedure DisallowEditingActivePurchPrice()
+ begin
+ AllowEditingActivePurchPrice(false);
+ end;
+
+ local procedure CreateDefaultPriceList(PriceType: Enum "Price Type"; SourceGroup: Enum "Price Source Group"): Code[20]
+ var
+ PriceListHeader: Record "Price List Header";
+ begin
+ PriceListHeader.Validate("Price Type", PriceType);
+ PriceListHeader.Validate("Source Group", SourceGroup);
+ PriceListHeader.Description := DefaultPriceListTok;
+ case SourceGroup of
+ SourceGroup::Customer:
+ PriceListHeader.Validate("Source Type", PriceListHeader."Source Type"::"All Customers");
+ SourceGroup::Vendor:
+ PriceListHeader.Validate("Source Type", PriceListHeader."Source Type"::"All Vendors");
+ SourceGroup::Job:
+ PriceListHeader.Validate("Source Type", PriceListHeader."Source Type"::"All Jobs");
+ end;
+ PriceListHeader."Allow Updating Defaults" := true;
+ PriceListHeader.Status := "Price Status"::Active;
+ if PriceListHeader.Insert(true) then
+ exit(PriceListHeader.Code);
+ end;
+
+ procedure SetDefaultPriceList(PriceType: Enum "Price Type"; SourceGroup: Enum "Price Source Group") DefaultPriceListCode: Code[20];
+ begin
+ case SourceGroup of
+ SourceGroup::Customer:
+ DefaultPriceListCode := DefineSalesDefaultPriceList();
+ SourceGroup::Vendor:
+ DefaultPriceListCode := DefinePurchDefaultPriceList();
+ SourceGroup::Job:
+ DefaultPriceListCode := DefineJobDefaultPriceList(PriceType);
+ end
+ end;
+
+ local procedure DefineJobDefaultPriceList(PriceType: Enum "Price Type") DefaultPriceListCode: Code[20];
+ var
+ JobsSetup: Record "Jobs Setup";
+ begin
+ JobsSetup.Get();
+ DefaultPriceListCode := CreateDefaultPriceList(PriceType, "Price Source Group"::Job);
+ case PriceType of
+ PriceType::Purchase:
+ JobsSetup."Default Purch Price List Code" := DefaultPriceListCode;
+ PriceType::Sale:
+ JobsSetup."Default Sales Price List Code" := DefaultPriceListCode;
+ end;
+ JobsSetup.Modify();
+ end;
+
+ local procedure DefinePurchDefaultPriceList() DefaultPriceListCode: Code[20];
+ var
+ PurchasesPayablesSetup: Record "Purchases & Payables Setup";
+ begin
+ PurchasesPayablesSetup.Get();
+ DefaultPriceListCode := CreateDefaultPriceList("Price Type"::Purchase, "Price Source Group"::Vendor);
+ PurchasesPayablesSetup."Default Price List Code" := DefaultPriceListCode;
+ PurchasesPayablesSetup."Allow Editing Active Price" := true;
+ PurchasesPayablesSetup.Modify();
+ end;
+
+ local procedure DefineSalesDefaultPriceList() DefaultPriceListCode: Code[20];
+ var
+ SalesReceivablesSetup: Record "Sales & Receivables Setup";
+ begin
+ SalesReceivablesSetup.Get();
+ DefaultPriceListCode := CreateDefaultPriceList("Price Type"::Sale, "Price Source Group"::Customer);
+ SalesReceivablesSetup."Default Price List Code" := DefaultPriceListCode;
+ SalesReceivablesSetup."Allow Editing Active Price" := true;
+ SalesReceivablesSetup.Modify();
+ exit(SalesReceivablesSetup."Default Price List Code");
+ end;
+
+ procedure ClearDefaultPriceList(PriceType: Enum "Price Type"; SourceGroup: Enum "Price Source Group")
+ var
+ JobsSetup: Record "Jobs Setup";
+ PurchasesPayablesSetup: Record "Purchases & Payables Setup";
+ SalesReceivablesSetup: Record "Sales & Receivables Setup";
+ begin
+ case SourceGroup of
+ SourceGroup::Job:
+ begin
+ JobsSetup.Get();
+ case PriceType of
+ PriceType::Purchase:
+ JobsSetup."Default Purch Price List Code" := '';
+ PriceType::Sale:
+ JobsSetup."Default Sales Price List Code" := '';
+ end;
+ JobsSetup.Modify();
+ end;
+ SourceGroup::Vendor:
+ begin
+ PurchasesPayablesSetup.Get();
+ PurchasesPayablesSetup."Default Price List Code" := '';
+ PurchasesPayablesSetup.Modify();
+ end;
+ SourceGroup::Customer:
+ begin
+ SalesReceivablesSetup.Get();
+ SalesReceivablesSetup."Default Price List Code" := '';
+ SalesReceivablesSetup.Modify();
+ end;
+ end;
+ end;
+
+ procedure SetUseCustomLookup(NewValue: Boolean) OldValue: Boolean;
+ var
+ SalesReceivablesSetup: Record "Sales & Receivables Setup";
+ begin
+ SalesReceivablesSetup.Get();
+ OldValue := SalesReceivablesSetup."Use Customized Lookup";
+ if OldValue = NewValue then
+ exit;
+ SalesReceivablesSetup."Use Customized Lookup" := NewValue;
+ SalesReceivablesSetup.Modify();
+ end;
+
+ procedure SetMethodInSalesSetup()
+ var
+ SalesReceivablesSetup: Record "Sales & Receivables Setup";
+ begin
+ SalesReceivablesSetup.Get();
+ SalesReceivablesSetup."Price Calculation Method" := SalesReceivablesSetup."Price Calculation Method"::"Lowest Price";
+ SalesReceivablesSetup.Modify();
+ end;
+
+ procedure SetMethodInPurchSetup()
+ var
+ PurchasesPayablesSetup: Record "Purchases & Payables Setup";
+ begin
+ PurchasesPayablesSetup.Get();
+ PurchasesPayablesSetup."Price Calculation Method" := PurchasesPayablesSetup."Price Calculation Method"::"Lowest Price";
+ PurchasesPayablesSetup.Modify();
+ end;
+
+ procedure CreatePriceHeader(var PriceListHeader: Record "Price List Header"; PriceType: Enum "Price Type"; SourceType: Enum "Price Source Type"; SourceNo: code[20])
+ begin
+ PriceListHeader.Init();
+ PriceListHeader.Code := LibraryUtility.GenerateGUID();
+ PriceListHeader.Description := StrSubstNo('%1%2', PriceListHeader.FieldName(Description), PriceListHeader.Code);
+ PriceListHeader."Price Type" := PriceType;
+ PriceListHeader.Validate("Source Type", SourceType);
+ PriceListHeader.Validate("Source No.", SourceNo);
+ PriceListHeader.Insert(true);
+ end;
+
+ procedure CreatePriceHeader(var PriceListHeader: Record "Price List Header"; PriceType: Enum "Price Type"; SourceType: Enum "Price Source Type"; ParentSourceNo: code[20]; SourceNo: code[20])
+ begin
+ PriceListHeader.Init();
+ PriceListHeader.Code := LibraryUtility.GenerateGUID();
+ PriceListHeader.Description := StrSubstNo('%1%2', PriceListHeader.FieldName(Description), PriceListHeader.Code);
+ PriceListHeader."Price Type" := PriceType;
+ PriceListHeader.Validate("Source Type", SourceType);
+ PriceListHeader.Validate("Parent Source No.", ParentSourceNo);
+ PriceListHeader.Validate("Source No.", SourceNo);
+ PriceListHeader.Insert(true);
+ end;
+
+ procedure CreatePriceListLine(var PriceListLine: Record "Price List Line"; PriceListHeader: Record "Price List Header"; AmountType: Enum "Price Amount Type"; AssetType: enum "Price Asset Type"; AssetNo: Code[20])
+ begin
+ CreatePriceListLine(
+ PriceListLine,
+ PriceListHeader.Code, PriceListHeader."Price Type",
+ PriceListHeader."Source Type", PriceListHeader."Parent Source No.", PriceListHeader."Source No.",
+ AmountType, AssetType, AssetNo);
+ end;
+
+ procedure CreatePriceListLine(var PriceListLine: Record "Price List Line"; PriceListCode: Code[20]; PriceType: Enum "Price Type"; SourceType: Enum "Price Source Type"; SourceNo: Code[20]; AmountType: Enum "Price Amount Type"; AssetType: enum "Price Asset Type"; AssetNo: Code[20])
+ begin
+ // to skip blank "Parent Source No."
+ CreatePriceListLine(
+ PriceListLine, PriceListCode, PriceType, SourceType, '', SourceNo, AmountType, AssetType, AssetNo);
+ end;
+
+ procedure CreatePriceListLine(var PriceListLine: Record "Price List Line"; PriceListCode: Code[20]; PriceType: Enum "Price Type"; SourceType: Enum "Price Source Type"; ParentSourceNo: Code[20]; SourceNo: Code[20]; AmountType: Enum "Price Amount Type"; AssetType: enum "Price Asset Type"; AssetNo: Code[20])
+ begin
+ PriceListLine.Init();
+ PriceListLine."Line No." := 0;
+ PriceListLine."Price List Code" := PriceListCode;
+ PriceListLine."Price Type" := PriceType;
+ PriceListLine.Validate("Source Type", SourceType);
+ PriceListLine.Validate("Parent Source No.", ParentSourceNo);
+ PriceListLine.Validate("Source No.", SourceNo);
+ PriceListLine.Validate("Asset Type", AssetType);
+ PriceListLine.Validate("Asset No.", AssetNo);
+ PriceListLine.Validate("Amount Type", AmountType);
+ if AmountType in [AmountType::Discount, AmountType::Any] then
+ PriceListLine.Validate("Line Discount %", LibraryRandom.RandDec(100, 2));
+ if AmountType in [AmountType::Price, AmountType::Any] then
+ case PriceType of
+ PriceType::Sale:
+ PriceListLine.Validate("Unit Price", LibraryRandom.RandDec(1000, 2));
+ PriceType::Purchase:
+ PriceListLine.Validate("Direct Unit Cost", LibraryRandom.RandDec(1000, 2));
+ end;
+ PriceListLine.Insert(true);
+ end;
+
+ procedure CreatePurchDiscountLine(var PriceListLine: Record "Price List Line"; PriceListCode: Code[20]; SourceType: Enum "Price Source Type"; SourceNo: code[20];
+ AssetType: enum "Price Asset Type";
+ AssetNo: Code[20])
+ begin
+ CreatePriceListLine(
+ PriceListLine, PriceListCode, PriceListLine."Price Type"::Purchase, SourceType, SourceNo,
+ PriceListLine."Amount Type"::Discount, AssetType, AssetNo);
+ end;
+
+ procedure CreatePurchPriceLine(var PriceListLine: Record "Price List Line"; PriceListCode: Code[20]; SourceType: Enum "Price Source Type"; SourceNo: code[20];
+ AssetType: enum "Price Asset Type";
+ AssetNo: Code[20])
+ begin
+ CreatePriceListLine(
+ PriceListLine, PriceListCode, PriceListLine."Price Type"::Purchase, SourceType, SourceNo,
+ PriceListLine."Amount Type"::Price, AssetType, AssetNo);
+ end;
+
+ procedure CreateSalesDiscountLine(var PriceListLine: Record "Price List Line"; PriceListCode: Code[20]; SourceType: Enum "Price Source Type"; SourceNo: code[20];
+ AssetType: enum "Price Asset Type";
+ AssetNo: Code[20])
+ begin
+ CreatePriceListLine(
+ PriceListLine, PriceListCode, PriceListLine."Price Type"::Sale, SourceType, SourceNo,
+ PriceListLine."Amount Type"::Discount, AssetType, AssetNo);
+ end;
+
+ procedure CreateSalesPriceLine(var PriceListLine: Record "Price List Line"; PriceListCode: Code[20]; SourceType: Enum "Price Source Type"; SourceNo: code[20];
+ AssetType: enum "Price Asset Type";
+ AssetNo: Code[20])
+ begin
+ CreatePriceListLine(
+ PriceListLine, PriceListCode, PriceListLine."Price Type"::Sale, SourceType, SourceNo,
+ PriceListLine."Amount Type"::Price, AssetType, AssetNo);
+ end;
+
+ [EventSubscriber(ObjectType::Codeunit, Codeunit::"Price Calculation Mgt.", 'OnIsExtendedPriceCalculationEnabled', '', false, false)]
+ procedure ExtendedPriceCalculationEnabledHandler(var Result: Boolean);
+ begin
+ Result := true;
+ end;
+}
\ No newline at end of file
diff --git a/Apps/W1/ApplicationTestLibrary/LibraryPurchase.Codeunit.al b/Apps/W1/ApplicationTestLibrary/LibraryPurchase.Codeunit.al
new file mode 100644
index 0000000000..022e9cb7b2
--- /dev/null
+++ b/Apps/W1/ApplicationTestLibrary/LibraryPurchase.Codeunit.al
@@ -0,0 +1,1301 @@
+///
+/// Provides utility functions for creating and managing purchase documents in test scenarios, including purchase orders, invoices, and credit memos.
+///
+codeunit 130512 "Library - Purchase"
+{
+
+ Permissions = TableData "Purchase Header" = rimd,
+ TableData "Purchase Line" = rimd;
+
+ trigger OnRun()
+ begin
+ end;
+
+ var
+ PurchasesPayablesSetup: Record "Purchases & Payables Setup";
+ Assert: Codeunit Assert;
+ LibraryUtility: Codeunit "Library - Utility";
+ LibraryERM: Codeunit "Library - ERM";
+ LibraryInventory: Codeunit "Library - Inventory";
+ LibraryItemTracking: Codeunit "Library - Item Tracking";
+ LibraryJournals: Codeunit "Library - Journals";
+ LibraryRandom: Codeunit "Library - Random";
+ LibraryResource: Codeunit "Library - Resource";
+ LibraryFixedAsset: Codeunit "Library - Fixed Asset";
+ WrongDocumentTypeErr: Label 'Document type not supported: %1', Locked = true;
+
+ procedure AssignPurchChargeToPurchRcptLine(PurchaseHeader: Record "Purchase Header"; PurchRcptLine: Record "Purch. Rcpt. Line"; Qty: Decimal; DirectUnitCost: Decimal)
+ var
+ ItemCharge: Record "Item Charge";
+ PurchaseLine: Record "Purchase Line";
+ ItemChargeAssignmentPurch: Record "Item Charge Assignment (Purch)";
+ LibraryPurchase: Codeunit "Library - Purchase";
+ begin
+ CreateItemChargePurchaseLine(PurchaseLine, ItemCharge, PurchaseHeader, Qty, DirectUnitCost);
+
+ PurchRcptLine.TestField(Type, PurchRcptLine.Type::Item);
+
+ LibraryPurchase.CreateItemChargeAssignment(ItemChargeAssignmentPurch, PurchaseLine, ItemCharge,
+ ItemChargeAssignmentPurch."Applies-to Doc. Type"::Receipt,
+ PurchRcptLine."Document No.", PurchRcptLine."Line No.",
+ PurchRcptLine."No.", Qty, DirectUnitCost);
+ ItemChargeAssignmentPurch.Insert();
+ end;
+
+ procedure AssignPurchChargeToPurchInvoiceLine(PurchaseHeader: Record "Purchase Header"; PurchInvLine: Record "Purch. Inv. Line"; Qty: Decimal; DirectUnitCost: Decimal)
+ var
+ ItemCharge: Record "Item Charge";
+ PurchaseLine: Record "Purchase Line";
+ ItemChargeAssignmentPurch: Record "Item Charge Assignment (Purch)";
+ LibraryPurchase: Codeunit "Library - Purchase";
+ begin
+ CreateItemChargePurchaseLine(PurchaseLine, ItemCharge, PurchaseHeader, Qty, DirectUnitCost);
+
+ PurchInvLine.TestField(Type, PurchInvLine.Type::Item);
+
+ LibraryPurchase.CreateItemChargeAssignment(ItemChargeAssignmentPurch, PurchaseLine, ItemCharge,
+ ItemChargeAssignmentPurch."Applies-to Doc. Type"::Invoice,
+ PurchInvLine."Document No.", PurchInvLine."Line No.",
+ PurchInvLine."No.", Qty, DirectUnitCost);
+ ItemChargeAssignmentPurch.Insert();
+ end;
+
+ procedure AssignPurchChargeToPurchaseLine(PurchaseHeader: Record "Purchase Header"; PurchaseLine: Record "Purchase Line"; Qty: Decimal; DirectUnitCost: Decimal)
+ var
+ ItemCharge: Record "Item Charge";
+ PurchaseLine1: Record "Purchase Line";
+ ItemChargeAssignmentPurch: Record "Item Charge Assignment (Purch)";
+ LibraryPurchase: Codeunit "Library - Purchase";
+ begin
+ CreateItemChargePurchaseLine(PurchaseLine1, ItemCharge, PurchaseHeader, Qty, DirectUnitCost);
+
+ PurchaseLine.TestField(Type, PurchaseLine.Type::Item);
+
+ LibraryPurchase.CreateItemChargeAssignment(ItemChargeAssignmentPurch, PurchaseLine1, ItemCharge,
+ ItemChargeAssignmentPurch."Applies-to Doc. Type"::Order,
+ PurchaseLine."Document No.", PurchaseLine."Line No.",
+ PurchaseLine."No.", Qty, DirectUnitCost);
+ ItemChargeAssignmentPurch.Insert();
+ end;
+
+ procedure AssignPurchChargeToPurchReturnLine(PurchaseHeader: Record "Purchase Header"; PurchaseLine: Record "Purchase Line"; Qty: Decimal; DirectUnitCost: Decimal)
+ var
+ ItemCharge: Record "Item Charge";
+ PurchaseLine1: Record "Purchase Line";
+ ItemChargeAssignmentPurch: Record "Item Charge Assignment (Purch)";
+ LibraryPurchase: Codeunit "Library - Purchase";
+ begin
+ CreateItemChargePurchaseLine(PurchaseLine1, ItemCharge, PurchaseHeader, Qty, DirectUnitCost);
+
+ PurchaseLine.TestField(Type, PurchaseLine.Type::Item);
+
+ LibraryPurchase.CreateItemChargeAssignment(ItemChargeAssignmentPurch, PurchaseLine1, ItemCharge,
+ ItemChargeAssignmentPurch."Applies-to Doc. Type"::"Return Order",
+ PurchaseLine."Document No.", PurchaseLine."Line No.",
+ PurchaseLine."No.", Qty, DirectUnitCost);
+ ItemChargeAssignmentPurch.Insert();
+ end;
+
+ procedure CreateItemChargePurchaseLine(var PurchaseLine: Record "Purchase Line"; var ItemCharge: Record "Item Charge"; PurchaseHeader: Record "Purchase Header"; Qty: Decimal; DirectUnitCost: Decimal)
+ var
+ LibraryPurchase: Codeunit "Library - Purchase";
+ begin
+ LibraryInventory.CreateItemCharge(ItemCharge);
+ LibraryPurchase.CreatePurchaseLine(PurchaseLine, PurchaseHeader, PurchaseLine.Type::"Charge (Item)", ItemCharge."No.", Qty);
+ PurchaseLine.Validate("Direct Unit Cost", DirectUnitCost);
+ PurchaseLine.Modify(true);
+ end;
+
+ procedure BlanketPurchaseOrderMakeOrder(var PurchaseHeader: Record "Purchase Header"): Code[20]
+ var
+ PurchOrderHeader: Record "Purchase Header";
+ BlanketPurchOrderToOrder: Codeunit "Blanket Purch. Order to Order";
+ begin
+ Clear(BlanketPurchOrderToOrder);
+ BlanketPurchOrderToOrder.Run(PurchaseHeader);
+ BlanketPurchOrderToOrder.GetPurchOrderHeader(PurchOrderHeader);
+ exit(PurchOrderHeader."No.");
+ end;
+
+ procedure CopyPurchaseDocument(PurchaseHeader: Record "Purchase Header"; FromDocType: Enum "Purchase Document Type From"; FromDocNo: Code[20]; NewIncludeHeader: Boolean; NewRecalcLines: Boolean)
+ var
+ CopyPurchaseDocumentReport: Report "Copy Purchase Document";
+ begin
+ CopyPurchaseDocumentReport.SetPurchHeader(PurchaseHeader);
+ CopyPurchaseDocumentReport.SetParameters(FromDocType, FromDocNo, NewIncludeHeader, NewRecalcLines);
+ CopyPurchaseDocumentReport.UseRequestPage(false);
+ CopyPurchaseDocumentReport.Run();
+ end;
+
+ procedure CreateItemChargeAssignment(var ItemChargeAssignmentPurch: Record "Item Charge Assignment (Purch)"; PurchaseLine: Record "Purchase Line"; ItemCharge: Record "Item Charge"; DocType: Enum "Purchase Applies-to Document Type"; DocNo: Code[20]; DocLineNo: Integer; ItemNo: Code[20]; Qty: Decimal; UnitCost: Decimal)
+ var
+ RecRef: RecordRef;
+ begin
+ Clear(ItemChargeAssignmentPurch);
+
+ ItemChargeAssignmentPurch."Document Type" := PurchaseLine."Document Type";
+ ItemChargeAssignmentPurch."Document No." := PurchaseLine."Document No.";
+ ItemChargeAssignmentPurch."Document Line No." := PurchaseLine."Line No.";
+ ItemChargeAssignmentPurch."Item Charge No." := PurchaseLine."No.";
+ ItemChargeAssignmentPurch."Unit Cost" := PurchaseLine."Unit Cost";
+ RecRef.GetTable(ItemChargeAssignmentPurch);
+ ItemChargeAssignmentPurch."Line No." := LibraryUtility.GetNewLineNo(RecRef, ItemChargeAssignmentPurch.FieldNo("Line No."));
+ ItemChargeAssignmentPurch."Item Charge No." := ItemCharge."No.";
+ ItemChargeAssignmentPurch."Applies-to Doc. Type" := DocType;
+ ItemChargeAssignmentPurch."Applies-to Doc. No." := DocNo;
+ ItemChargeAssignmentPurch."Applies-to Doc. Line No." := DocLineNo;
+ ItemChargeAssignmentPurch."Item No." := ItemNo;
+ ItemChargeAssignmentPurch."Unit Cost" := UnitCost;
+ ItemChargeAssignmentPurch.Validate("Qty. to Assign", Qty);
+ end;
+
+ procedure CreateOrderAddress(var OrderAddress: Record "Order Address"; VendorNo: Code[20])
+ var
+ PostCode: Record "Post Code";
+ begin
+ LibraryERM.CreatePostCode(PostCode);
+ OrderAddress.Init();
+ OrderAddress.Validate("Vendor No.", VendorNo);
+ OrderAddress.Validate(
+ Code,
+ CopyStr(
+ LibraryUtility.GenerateRandomCode(OrderAddress.FieldNo(Code), DATABASE::"Order Address"),
+ 1,
+ LibraryUtility.GetFieldLength(DATABASE::"Order Address", OrderAddress.FieldNo(Code))));
+ OrderAddress.Validate(Name, LibraryUtility.GenerateRandomText(MaxStrLen(OrderAddress.Name)));
+ OrderAddress.Validate(Address, LibraryUtility.GenerateRandomText(MaxStrLen(OrderAddress.Address)));
+ OrderAddress.Validate("Post Code", PostCode.Code);
+ OrderAddress.Insert(true);
+ end;
+
+ procedure CreateRemitToAddress(var RemitToAddress: Record "Remit Address"; VendorNo: Code[20])
+ var
+ PostCode: Record "Post Code";
+ begin
+ LibraryERM.CreatePostCode(PostCode);
+ RemitToAddress.Init();
+ RemitToAddress.Validate("Vendor No.", VendorNo);
+ RemitToAddress.Validate(
+ Code,
+ CopyStr(
+ LibraryUtility.GenerateRandomCode(RemitToAddress.FieldNo(Code), DATABASE::"Remit Address"),
+ 1,
+ LibraryUtility.GetFieldLength(DATABASE::"Remit Address", RemitToAddress.FieldNo(Code))));
+ RemitToAddress.Validate(Name, LibraryUtility.GenerateRandomText(MaxStrLen(RemitToAddress.Name)));
+ RemitToAddress.Validate(Address, LibraryUtility.GenerateRandomText(MaxStrLen(RemitToAddress.Address)));
+ RemitToAddress.Validate("Post Code", PostCode.Code);
+ RemitToAddress.Insert(true);
+ end;
+
+ procedure CreatePrepaymentVATSetup(var LineGLAccount: Record "G/L Account"; VATCalculationType: Enum "Tax Calculation Type"): Code[20]
+ var
+ PrepmtGLAccount: Record "G/L Account";
+ begin
+ LibraryERM.CreatePrepaymentVATSetup(
+ LineGLAccount, PrepmtGLAccount, LineGLAccount."Gen. Posting Type"::Purchase, VATCalculationType, VATCalculationType);
+ exit(PrepmtGLAccount."No.");
+ end;
+
+ procedure CreatePurchasingCode(var Purchasing: Record Purchasing)
+ begin
+ Purchasing.Init();
+ Purchasing.Validate(
+ Code,
+ CopyStr(
+ LibraryUtility.GenerateRandomCode(Purchasing.FieldNo(Code), DATABASE::Purchasing),
+ 1,
+ LibraryUtility.GetFieldLength(DATABASE::Purchasing, Purchasing.FieldNo(Code))));
+ Purchasing.Insert(true);
+ end;
+
+ procedure CreateDropShipmentPurchasingCode(var Purchasing: Record Purchasing)
+ begin
+ CreatePurchasingCode(Purchasing);
+ Purchasing.Validate("Drop Shipment", true);
+ Purchasing.Modify(true);
+ end;
+
+ procedure CreateSpecialOrderPurchasingCode(var Purchasing: Record Purchasing)
+ begin
+ CreatePurchasingCode(Purchasing);
+ Purchasing.Validate("Special Order", true);
+ Purchasing.Modify(true);
+ end;
+
+ procedure CreatePurchHeader(var PurchaseHeader: Record "Purchase Header"; DocumentType: Enum "Purchase Document Type"; BuyfromVendorNo: Code[20])
+ begin
+ DisableWarningOnCloseUnpostedDoc();
+ DisableWarningOnCloseUnreleasedDoc();
+ DisableConfirmOnPostingDoc();
+ Clear(PurchaseHeader);
+ OnBeforeCreatePurchaseHeader(PurchaseHeader, DocumentType, BuyFromVendorNo);
+ PurchaseHeader.Validate("Document Type", DocumentType);
+ PurchaseHeader.Insert(true);
+ if BuyfromVendorNo = '' then
+ BuyfromVendorNo := CreateVendorNo();
+ PurchaseHeader.Validate("Buy-from Vendor No.", BuyfromVendorNo);
+ if PurchaseHeader."Document Type" in [PurchaseHeader."Document Type"::"Credit Memo",
+ PurchaseHeader."Document Type"::"Return Order"]
+ then
+ PurchaseHeader.Validate("Vendor Cr. Memo No.", LibraryUtility.GenerateGUID())
+ else
+ PurchaseHeader.Validate("Vendor Invoice No.", LibraryUtility.GenerateGUID());
+ PurchaseHeader.Modify(true);
+ OnAfterCreatePurchHeader(PurchaseHeader, DocumentType, BuyfromVendorNo);
+ end;
+
+ procedure CreatePurchHeaderWithDocNo(var PurchaseHeader: Record "Purchase Header"; DocumentType: Enum "Purchase Document Type"; BuyfromVendorNo: Code[20]; DocNo: Code[20])
+ begin
+ Clear(PurchaseHeader);
+ PurchaseHeader.Validate("Document Type", DocumentType);
+ PurchaseHeader."No." := DocNo;
+ PurchaseHeader.Insert(true);
+ if BuyfromVendorNo = '' then
+ BuyfromVendorNo := CreateVendorNo();
+ PurchaseHeader.Validate("Buy-from Vendor No.", BuyfromVendorNo);
+ PurchaseHeader.Validate("Vendor Invoice No.", LibraryUtility.GenerateGUID());
+ PurchaseHeader.Modify(true);
+ end;
+
+ procedure CreatePurchaseLine(var PurchaseLine: Record "Purchase Line"; PurchaseHeader: Record "Purchase Header"; LineType: Enum "Purchase Line Type"; No: Code[20]; Quantity: Decimal)
+ begin
+ CreatePurchaseLineSimple(PurchaseLine, PurchaseHeader);
+
+ PurchaseLine.Validate(Type, LineType);
+ case LineType of
+ PurchaseLine.Type::Item:
+ if No = '' then
+ No := LibraryInventory.CreateItemNo();
+ PurchaseLine.Type::"G/L Account":
+ if No = '' then
+ No := LibraryERM.CreateGLAccountWithPurchSetup();
+ PurchaseLine.Type::"Charge (Item)":
+ if No = '' then
+ No := LibraryInventory.CreateItemChargeNo();
+ PurchaseLine.Type::Resource:
+ if No = '' then
+ No := LibraryResource.CreateResourceNo();
+ PurchaseLine.Type::"Fixed Asset":
+ if No = '' then
+ No := LibraryFixedAsset.CreateFixedAssetNo();
+ end;
+ PurchaseLine.Validate("No.", No);
+ if LineType <> PurchaseLine.Type::" " then
+ PurchaseLine.Validate(Quantity, Quantity);
+ PurchaseLine.Modify(true);
+
+ OnAfterCreatePurchaseLine(PurchaseLine, PurchaseHeader, LineType, No, Quantity);
+ end;
+
+ procedure CreatePurchaseLineSimple(var PurchaseLine: Record "Purchase Line"; PurchaseHeader: Record "Purchase Header")
+ var
+ RecRef: RecordRef;
+ begin
+ PurchaseLine.Init();
+ PurchaseLine.Validate("Document Type", PurchaseHeader."Document Type");
+ PurchaseLine.Validate("Document No.", PurchaseHeader."No.");
+ RecRef.GetTable(PurchaseLine);
+ PurchaseLine.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, PurchaseLine.FieldNo("Line No.")));
+ PurchaseLine.Insert(true);
+ end;
+
+ procedure CreatePurchaseLineWithUnitCost(var PurchaseLine: Record "Purchase Line"; PurchaseHeader: Record "Purchase Header"; ItemNo: Code[20]; UnitCost: Decimal; Quantity: Decimal)
+ begin
+ CreatePurchaseLine(PurchaseLine, PurchaseHeader, PurchaseLine.Type::Item, ItemNo, Quantity);
+ PurchaseLine.Validate("Direct Unit Cost", UnitCost);
+ PurchaseLine.Modify();
+ end;
+
+ procedure CreatePurchaseQuote(var PurchaseHeader: Record "Purchase Header")
+ var
+ PurchaseLine: Record "Purchase Line";
+ begin
+ CreatePurchHeader(PurchaseHeader, PurchaseHeader."Document Type"::Quote, CreateVendorNo());
+ CreatePurchaseLine(
+ PurchaseLine, PurchaseHeader, PurchaseLine.Type::Item, LibraryInventory.CreateItemNo(), LibraryRandom.RandInt(100));
+ PurchaseLine.Validate("Direct Unit Cost", LibraryRandom.RandDecInRange(1, 99, 2));
+ PurchaseLine.Modify(true);
+ end;
+
+ procedure CreatePurchaseInvoice(var PurchaseHeader: Record "Purchase Header")
+ begin
+ CreatePurchaseInvoiceForVendorNo(PurchaseHeader, CreateVendorNo());
+ end;
+
+ procedure CreatePurchaseInvoiceForVendorNo(var PurchaseHeader: Record "Purchase Header"; VendorNo: Code[20])
+ var
+ PurchaseLine: Record "Purchase Line";
+ begin
+ CreatePurchHeader(PurchaseHeader, PurchaseHeader."Document Type"::Invoice, VendorNo);
+ CreatePurchaseLine(PurchaseLine, PurchaseHeader, PurchaseLine.Type::Item, LibraryInventory.CreateItemNo(), LibraryRandom.RandInt(100));
+ PurchaseLine.Validate("Direct Unit Cost", LibraryRandom.RandDecInRange(1, 100, 2));
+ PurchaseLine.Modify(true);
+ end;
+
+ procedure CreatePurchaseOrder(var PurchaseHeader: Record "Purchase Header")
+ begin
+ CreatePurchaseOrderForVendorNo(PurchaseHeader, CreateVendorNo());
+ end;
+
+ procedure CreatePurchaseOrderForVendorNo(var PurchaseHeader: Record "Purchase Header"; VendorNo: Code[20])
+ var
+ PurchaseLine: Record "Purchase Line";
+ begin
+ CreatePurchHeader(PurchaseHeader, PurchaseHeader."Document Type"::Order, VendorNo);
+ CreatePurchaseLine(PurchaseLine, PurchaseHeader, PurchaseLine.Type::Item, LibraryInventory.CreateItemNo(), LibraryRandom.RandInt(100));
+ PurchaseLine.Validate("Direct Unit Cost", LibraryRandom.RandDecInRange(1, 100, 2));
+ PurchaseLine.Modify(true);
+ end;
+
+ procedure CreatePurchaseCreditMemo(var PurchaseHeader: Record "Purchase Header")
+ begin
+ CreatePurchaseCreditMemoForVendorNo(PurchaseHeader, CreateVendorNo());
+ end;
+
+ procedure CreatePurchaseCreditMemoForVendorNo(var PurchaseHeader: Record "Purchase Header"; VendorNo: Code[20])
+ var
+ PurchaseLine: Record "Purchase Line";
+ begin
+ CreatePurchHeader(PurchaseHeader, PurchaseHeader."Document Type"::"Credit Memo", VendorNo);
+ CreatePurchaseLine(PurchaseLine, PurchaseHeader, PurchaseLine.Type::Item, LibraryInventory.CreateItemNo(), LibraryRandom.RandInt(100));
+ PurchaseLine.Validate("Direct Unit Cost", LibraryRandom.RandDecInRange(1, 100, 2));
+ PurchaseLine.Modify(true);
+ end;
+
+ procedure CreatePurchaseOrderWithLocation(var PurchaseHeader: Record "Purchase Header"; VendorNo: Code[20]; LocationCode: Code[10])
+ begin
+ CreatePurchHeader(PurchaseHeader, PurchaseHeader."Document Type"::Order, VendorNo);
+ PurchaseHeader.Validate("Vendor Invoice No.", PurchaseHeader."No.");
+ PurchaseHeader.Validate("Location Code", LocationCode);
+ PurchaseHeader.Modify();
+ end;
+
+ procedure CreatePurchaseReturnOrderWithLocation(var PurchaseHeader: Record "Purchase Header"; VendorNo: Code[20]; LocationCode: Code[10])
+ begin
+ CreatePurchHeader(PurchaseHeader, PurchaseHeader."Document Type"::"Return Order", VendorNo);
+ PurchaseHeader.Validate("Vendor Cr. Memo No.", PurchaseHeader."No.");
+ PurchaseHeader.Validate("Location Code", LocationCode);
+ PurchaseHeader.Modify();
+ end;
+
+ procedure CreatePurchaseCreditMemoWithLocation(var PurchaseHeader: Record "Purchase Header"; VendorNo: Code[20]; LocationCode: Code[10])
+ begin
+ CreatePurchHeader(PurchaseHeader, PurchaseHeader."Document Type"::"Credit Memo", VendorNo);
+ PurchaseHeader.Validate("Vendor Cr. Memo No.", PurchaseHeader."No.");
+ PurchaseHeader.Validate("Location Code", LocationCode);
+ PurchaseHeader.Modify();
+ end;
+
+ procedure CreatePurchaseReturnOrder(var PurchaseHeader: Record "Purchase Header")
+ var
+ PurchaseLine: Record "Purchase Line";
+ begin
+ CreatePurchHeader(PurchaseHeader, PurchaseHeader."Document Type"::"Return Order", CreateVendorNo());
+ CreatePurchaseLine(PurchaseLine, PurchaseHeader, PurchaseLine.Type::Item, LibraryInventory.CreateItemNo(), LibraryRandom.RandInt(100));
+ PurchaseLine.Validate("Direct Unit Cost", LibraryRandom.RandDecInRange(1, 100, 2));
+ PurchaseLine.Modify(true);
+ end;
+
+ procedure CreatePurchaseDocument(var PurchaseHeader: Record "Purchase Header"; var PurchaseLine: Record "Purchase Line"; DocType: Enum "Purchase Document Type"; Item: Record Item; LocationCode: Code[10]; VariantCode: Code[10]; Qty: Decimal; PostingDate: Date; DirectUnitCost: Decimal)
+ begin
+ CreatePurchHeader(PurchaseHeader, DocType, '');
+ PurchaseHeader.Validate("Posting Date", PostingDate);
+ PurchaseHeader.Modify(true);
+ CreatePurchaseLine(PurchaseLine, PurchaseHeader, PurchaseLine.Type::Item, Item."No.", Qty);
+ PurchaseLine."Location Code" := LocationCode;
+ PurchaseLine."Variant Code" := VariantCode;
+ PurchaseLine.Validate("Direct Unit Cost", DirectUnitCost);
+ PurchaseLine.Modify(true);
+ end;
+
+ procedure CreatePurchaseOrder(var PurchaseHeader: Record "Purchase Header"; var PurchaseLine: Record "Purchase Line"; Item: Record Item; LocationCode: Code[10]; VariantCode: Code[10]; Qty: Decimal; PostingDate: Date; DirectUnitCost: Decimal)
+ begin
+ CreatePurchaseDocument(
+ PurchaseHeader, PurchaseLine, PurchaseHeader."Document Type"::Order, Item, LocationCode, VariantCode, Qty, PostingDate,
+ DirectUnitCost);
+ end;
+
+ procedure CreatePurchaseQuote(var PurchaseHeader: Record "Purchase Header"; var PurchaseLine: Record "Purchase Line"; Item: Record Item; LocationCode: Code[10]; VariantCode: Code[10]; Qty: Decimal; PostingDate: Date; DirectUnitCost: Decimal)
+ begin
+ CreatePurchaseDocument(
+ PurchaseHeader, PurchaseLine, PurchaseHeader."Document Type"::Quote,
+ Item, LocationCode, VariantCode, Qty, PostingDate, DirectUnitCost);
+ end;
+
+ procedure CreatePurchaseBlanketOrder(var PurchaseHeader: Record "Purchase Header"; var PurchaseLine: Record "Purchase Line"; Item: Record Item; LocationCode: Code[10]; VariantCode: Code[10]; Qty: Decimal; PostingDate: Date; DirectUnitCost: Decimal)
+ begin
+ CreatePurchaseDocument(
+ PurchaseHeader, PurchaseLine, PurchaseHeader."Document Type"::"Blanket Order",
+ Item, LocationCode, VariantCode, Qty, PostingDate, DirectUnitCost);
+ end;
+
+ procedure CreatePurchaseReturnOrder(var PurchaseHeader: Record "Purchase Header"; var PurchaseLine: Record "Purchase Line"; Item: Record Item; LocationCode: Code[10]; VariantCode: Code[10]; Qty: Decimal; PostingDate: Date; DirectUnitCost: Decimal)
+ begin
+ CreatePurchaseDocument(
+ PurchaseHeader, PurchaseLine, PurchaseHeader."Document Type"::"Return Order", Item, LocationCode, VariantCode, Qty, PostingDate,
+ DirectUnitCost);
+ end;
+
+ procedure CreatePurchaseCreditMemo(var PurchaseHeader: Record "Purchase Header"; var PurchaseLine: Record "Purchase Line"; Item: Record Item; LocationCode: Code[10]; VariantCode: Code[10]; Qty: Decimal; PostingDate: Date; DirectUnitCost: Decimal)
+ begin
+ CreatePurchaseDocument(
+ PurchaseHeader, PurchaseLine, PurchaseHeader."Document Type"::"Credit Memo",
+ Item, LocationCode, VariantCode, Qty, PostingDate, DirectUnitCost);
+ end;
+
+ procedure CreatePurchaseInvoice(var PurchaseHeader: Record "Purchase Header"; var PurchaseLine: Record "Purchase Line"; Item: Record Item; LocationCode: Code[10]; VariantCode: Code[10]; Qty: Decimal; PostingDate: Date; DirectUnitCost: Decimal)
+ begin
+ CreatePurchaseDocument(
+ PurchaseHeader, PurchaseLine, PurchaseHeader."Document Type"::Invoice, Item, LocationCode, VariantCode, Qty, PostingDate,
+ DirectUnitCost);
+ end;
+
+ procedure CreatePurchCommentLine(var PurchCommentLine: Record "Purch. Comment Line"; DocumentType: Enum "Purchase Comment Document Type"; No: Code[20]; DocumentLineNo: Integer)
+ var
+ RecRef: RecordRef;
+ begin
+ PurchCommentLine.Init();
+ PurchCommentLine.Validate("Document Type", DocumentType);
+ PurchCommentLine.Validate("No.", No);
+ PurchCommentLine.Validate("Document Line No.", DocumentLineNo);
+ RecRef.GetTable(PurchCommentLine);
+ PurchCommentLine.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, PurchCommentLine.FieldNo("Line No.")));
+ PurchCommentLine.Insert(true);
+ // Validate Comment as primary key to enable user to distinguish between comments because value is not important.
+ PurchCommentLine.Validate(
+ Comment, Format(PurchCommentLine."Document Type") + PurchCommentLine."No." +
+ Format(PurchCommentLine."Document Line No.") + Format(PurchCommentLine."Line No."));
+ PurchCommentLine.Modify(true);
+ end;
+
+ procedure CreatePurchaseDocumentWithItem(var PurchaseHeader: Record "Purchase Header"; var PurchaseLine: Record "Purchase Line"; DocumentType: Enum "Purchase Document Type"; VendorNo: Code[20]; ItemNo: Code[20]; Quantity: Decimal; LocationCode: Code[10]; ExpectedReceiptDate: Date)
+ begin
+ CreateFCYPurchaseDocumentWithItem(
+ PurchaseHeader, PurchaseLine, DocumentType, VendorNo, ItemNo, Quantity, LocationCode, ExpectedReceiptDate, '');
+ end;
+
+ procedure CreateFCYPurchaseDocumentWithItem(var PurchaseHeader: Record "Purchase Header"; var PurchaseLine: Record "Purchase Line"; DocumentType: Enum "Purchase Document Type"; VendorNo: Code[20]; ItemNo: Code[20]; Quantity: Decimal; LocationCode: Code[10]; ExpectedReceiptDate: Date; CurrencyCode: Code[10])
+ begin
+ CreatePurchHeader(PurchaseHeader, DocumentType, VendorNo);
+ if LocationCode <> '' then
+ PurchaseHeader.Validate("Location Code", LocationCode);
+ PurchaseHeader.Validate("Currency Code", CurrencyCode);
+ PurchaseHeader.Modify(true);
+ if ItemNo = '' then
+ ItemNo := LibraryInventory.CreateItemNo();
+ CreatePurchaseLine(PurchaseLine, PurchaseHeader, PurchaseLine.Type::Item, ItemNo, Quantity);
+ if LocationCode <> '' then
+ PurchaseLine.Validate("Location Code", LocationCode);
+ if ExpectedReceiptDate <> 0D then
+ PurchaseLine.Validate("Expected Receipt Date", ExpectedReceiptDate);
+ PurchaseLine.Modify(true);
+ end;
+
+ procedure CreatePurchasePrepaymentPct(var PurchasePrepaymentPct: Record "Purchase Prepayment %"; ItemNo: Code[20]; VendorNo: Code[20]; StartingDate: Date)
+ begin
+ PurchasePrepaymentPct.Init();
+ PurchasePrepaymentPct.Validate("Item No.", ItemNo);
+ PurchasePrepaymentPct.Validate("Vendor No.", VendorNo);
+ PurchasePrepaymentPct.Validate("Starting Date", StartingDate);
+ PurchasePrepaymentPct.Insert(true);
+ end;
+
+ procedure CreateStandardPurchaseCode(var StandardPurchaseCode: Record "Standard Purchase Code")
+ begin
+ StandardPurchaseCode.Init();
+ StandardPurchaseCode.Validate(
+ Code,
+ CopyStr(
+ LibraryUtility.GenerateRandomCode(StandardPurchaseCode.FieldNo(Code), DATABASE::"Standard Purchase Code"),
+ 1,
+ LibraryUtility.GetFieldLength(DATABASE::"Standard Purchase Code", StandardPurchaseCode.FieldNo(Code))));
+ // Validating Description as Code because value is not important.
+ StandardPurchaseCode.Validate(Description, StandardPurchaseCode.Code);
+ StandardPurchaseCode.Insert(true);
+ end;
+
+ procedure CreateStandardPurchaseLine(var StandardPurchaseLine: Record "Standard Purchase Line"; StandardPurchaseCode: Code[10])
+ var
+ RecRef: RecordRef;
+ begin
+ StandardPurchaseLine.Init();
+ StandardPurchaseLine.Validate("Standard Purchase Code", StandardPurchaseCode);
+ RecRef.GetTable(StandardPurchaseLine);
+ StandardPurchaseLine.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, StandardPurchaseLine.FieldNo("Line No.")));
+ StandardPurchaseLine.Insert(true);
+ end;
+
+ procedure CreateVendorDocumentLayout(VendorNo: Code[20]; ReportSelectionUsage: Enum "Report Selection Usage"; ReportID: Integer; CustomReportLayoutCode: Code[20]; EmailAddress: Text)
+ var
+ CustomReportSelection: Record "Custom Report Selection";
+ begin
+ CustomReportSelection.Init();
+ CustomReportSelection.Validate("Source Type", Database::Vendor);
+ CustomReportSelection.Validate("Source No.", VendorNo);
+ CustomReportSelection.Validate(Usage, ReportSelectionUsage);
+ CustomReportSelection.Validate("Report ID", ReportID);
+ CustomReportSelection.Validate("Custom Report Layout Code", CustomReportLayoutCode);
+ CustomReportSelection.Validate("Send To Email", CopyStr(EmailAddress, 1, MaxStrLen(CustomReportSelection."Send To Email")));
+ CustomReportSelection.Insert(true);
+ end;
+
+ procedure CreateSubcontractor(var Vendor: Record Vendor)
+ begin
+ CreateVendor(Vendor);
+ end;
+
+ procedure CreateVendor(var Vendor: Record Vendor): Code[20]
+ var
+ PaymentMethod: Record "Payment Method";
+ GeneralPostingSetup: Record "General Posting Setup";
+ VATPostingSetup: Record "VAT Posting Setup";
+ VendContUpdate: Codeunit "VendCont-Update";
+ begin
+ LibraryERM.FindPaymentMethod(PaymentMethod);
+ LibraryERM.SetSearchGenPostingTypePurch();
+ LibraryERM.FindGeneralPostingSetupInvtFull(GeneralPostingSetup);
+ LibraryERM.FindVATPostingSetupInvt(VATPostingSetup);
+ LibraryUtility.UpdateSetupNoSeriesCode(
+ DATABASE::"Purchases & Payables Setup", PurchasesPayablesSetup.FieldNo("Vendor Nos."));
+
+ Clear(Vendor);
+ Vendor.Insert(true);
+ Vendor.Validate(Name, Vendor."No."); // Validating Name as No. because value is not important.
+ Vendor.Validate("Gen. Bus. Posting Group", GeneralPostingSetup."Gen. Bus. Posting Group");
+ Vendor.Validate("VAT Bus. Posting Group", VATPostingSetup."VAT Bus. Posting Group");
+ Vendor.Validate("Vendor Posting Group", FindVendorPostingGroup());
+ Vendor.Validate("Payment Terms Code", LibraryERM.FindPaymentTermsCode());
+ Vendor.Validate("Payment Method Code", PaymentMethod.Code);
+ Vendor.Modify(true);
+ VendContUpdate.OnModify(Vendor);
+
+ OnAfterCreateVendor(Vendor);
+ exit(Vendor."No.");
+ end;
+
+ procedure CreateVendorNo(): Code[20]
+ var
+ Vendor: Record Vendor;
+ begin
+ CreateVendor(Vendor);
+ exit(Vendor."No.");
+ end;
+
+ procedure CreateVendorPostingGroup(var VendorPostingGroup: Record "Vendor Posting Group")
+ begin
+ VendorPostingGroup.Init();
+ VendorPostingGroup.Validate(Code,
+ LibraryUtility.GenerateRandomCode(VendorPostingGroup.FieldNo(Code), DATABASE::"Vendor Posting Group"));
+ VendorPostingGroup.Validate("Payables Account", LibraryERM.CreateGLAccountNo());
+ VendorPostingGroup.Validate("Service Charge Acc.", LibraryERM.CreateGLAccountWithPurchSetup());
+ VendorPostingGroup.Validate("Invoice Rounding Account", LibraryERM.CreateGLAccountWithPurchSetup());
+ VendorPostingGroup.Validate("Debit Rounding Account", LibraryERM.CreateGLAccountNo());
+ VendorPostingGroup.Validate("Credit Rounding Account", LibraryERM.CreateGLAccountNo());
+ VendorPostingGroup.Validate("Payment Disc. Debit Acc.", LibraryERM.CreateGLAccountNo());
+ VendorPostingGroup.Validate("Payment Disc. Credit Acc.", LibraryERM.CreateGLAccountNo());
+ VendorPostingGroup.Validate("Payment Tolerance Debit Acc.", LibraryERM.CreateGLAccountNo());
+ VendorPostingGroup.Validate("Payment Tolerance Credit Acc.", LibraryERM.CreateGLAccountNo());
+ VendorPostingGroup.Validate("Debit Curr. Appln. Rndg. Acc.", LibraryERM.CreateGLAccountNo());
+ VendorPostingGroup.Validate("Credit Curr. Appln. Rndg. Acc.", LibraryERM.CreateGLAccountNo());
+ VendorPostingGroup.Insert(true);
+ end;
+
+ procedure CreateAltVendorPostingGroup(ParentCode: Code[10]; AltCode: Code[10])
+ var
+ AltVendorPostingGroup: Record "Alt. Vendor Posting Group";
+ begin
+ AltVendorPostingGroup.Init();
+ AltVendorPostingGroup."Vendor Posting Group" := ParentCode;
+ AltVendorPostingGroup."Alt. Vendor Posting Group" := AltCode;
+ AltVendorPostingGroup.Insert();
+ end;
+
+ procedure CreateVendorWithLocationCode(var Vendor: Record Vendor; LocationCode: Code[10]): Code[20]
+ begin
+ CreateVendor(Vendor);
+ Vendor.Validate("Location Code", LocationCode);
+ Vendor.Modify(true);
+ exit(Vendor."No.");
+ end;
+
+ procedure CreateVendorWithBusPostingGroups(GenBusPostGroupCode: Code[20]; VATBusPostGroupCode: Code[20]): Code[20]
+ var
+ Vendor: Record Vendor;
+ begin
+ CreateVendor(Vendor);
+ Vendor.Validate("Gen. Bus. Posting Group", GenBusPostGroupCode);
+ Vendor.Validate("VAT Bus. Posting Group", VATBusPostGroupCode);
+ Vendor.Modify(true);
+ exit(Vendor."No.");
+ end;
+
+ procedure CreateVendorWithVATBusPostingGroup(VATBusPostGroupCode: Code[20]): Code[20]
+ var
+ Vendor: Record Vendor;
+ begin
+ CreateVendor(Vendor);
+ Vendor.Validate("VAT Bus. Posting Group", VATBusPostGroupCode);
+ Vendor.Modify(true);
+ exit(Vendor."No.");
+ end;
+
+ procedure CreateVendorWithVATRegNo(var Vendor: Record Vendor): Code[20]
+ var
+ CountryRegion: Record "Country/Region";
+ begin
+ CreateVendor(Vendor);
+ LibraryERM.CreateCountryRegion(CountryRegion);
+ Vendor.Validate("Country/Region Code", CountryRegion.Code);
+ Vendor."VAT Registration No." := LibraryERM.GenerateVATRegistrationNo(CountryRegion.Code);
+ Vendor.Modify(true);
+ exit(Vendor."No.");
+ end;
+
+ procedure CreateVendorWithAddress(var Vendor: Record Vendor)
+ var
+ PostCode: Record "Post Code";
+ begin
+ LibraryERM.CreatePostCode(PostCode);
+ CreateVendor(Vendor);
+ Vendor.Validate(Name, LibraryUtility.GenerateRandomText(MaxStrLen(Vendor.Name)));
+ Vendor.Validate(Address, LibraryUtility.GenerateRandomText(MaxStrLen(Vendor.Address)));
+ Vendor.Validate("Address 2", LibraryUtility.GenerateRandomText(MaxStrLen(Vendor."Address 2")));
+ Vendor.Validate("Country/Region Code", PostCode."Country/Region Code");
+ Vendor.Validate(City, PostCode.City);
+ Vendor.Validate(County, LibraryUtility.GenerateRandomText(MaxStrLen(Vendor.County)));
+ Vendor.Validate("Post Code", PostCode.Code);
+ Vendor.Contact := CopyStr(LibraryUtility.GenerateRandomText(MaxStrLen(Vendor.Contact)), 1, MaxStrLen(Vendor.Contact));
+ Vendor.Modify(true);
+ end;
+
+ procedure CreateVendorBankAccount(var VendorBankAccount: Record "Vendor Bank Account"; VendorNo: Code[20])
+ begin
+ VendorBankAccount.Init();
+ VendorBankAccount.Validate("Vendor No.", VendorNo);
+ VendorBankAccount.Validate(
+ Code,
+ CopyStr(
+ LibraryUtility.GenerateRandomCode(VendorBankAccount.FieldNo(Code), DATABASE::"Vendor Bank Account"),
+ 1,
+ LibraryUtility.GetFieldLength(DATABASE::"Vendor Bank Account", VendorBankAccount.FieldNo(Code))));
+ VendorBankAccount.Insert(true);
+ end;
+
+ procedure CreateVendorPurchaseCode(var StandardVendorPurchaseCode: Record "Standard Vendor Purchase Code"; VendorNo: Code[20]; "Code": Code[10])
+ begin
+ StandardVendorPurchaseCode.Init();
+ StandardVendorPurchaseCode.Validate("Vendor No.", VendorNo);
+ StandardVendorPurchaseCode.Validate(Code, Code);
+ StandardVendorPurchaseCode.Insert(true);
+ end;
+
+ procedure CreatePurchaseHeaderPostingJobQueueEntry(var JobQueueEntry: Record "Job Queue Entry"; PurchaseHeader: Record "Purchase Header")
+ begin
+ JobQueueEntry.Init();
+ JobQueueEntry.ID := CreateGuid();
+ JobQueueEntry."Earliest Start Date/Time" := CreateDateTime(Today, 0T);
+ JobQueueEntry."Object Type to Run" := JobQueueEntry."Object Type to Run"::Codeunit;
+ JobQueueEntry."Object ID to Run" := CODEUNIT::"Purchase Post via Job Queue";
+ JobQueueEntry."Record ID to Process" := PurchaseHeader.RecordId;
+ JobQueueEntry."Run in User Session" := true;
+ JobQueueEntry.Insert(true);
+ end;
+
+ procedure CreateIntrastatContact(CountryRegionCode: Code[10]): Code[20]
+ var
+ Vendor: Record Vendor;
+ begin
+ CreateVendor(Vendor);
+ Vendor.Validate(Name, LibraryUtility.GenerateGUID());
+ Vendor.Validate(Address, LibraryUtility.GenerateGUID());
+ Vendor.Validate("Country/Region Code", CountryRegionCode);
+ Vendor.Validate("Post Code", LibraryUtility.GenerateGUID());
+ Vendor.Validate(City, LibraryUtility.GenerateGUID());
+ Vendor.Validate("Phone No.", Format(LibraryRandom.RandIntInRange(100000000, 999999999)));
+ Vendor.Validate("Fax No.", LibraryUtility.GenerateGUID());
+ Vendor.Validate("E-Mail", LibraryUtility.GenerateGUID() + '@' + LibraryUtility.GenerateGUID());
+ Vendor.Modify(true);
+ exit(Vendor."No.");
+ end;
+
+ procedure DeleteInvoicedPurchOrders(var PurchaseHeader: Record "Purchase Header")
+ var
+ PurchaseHeader2: Record "Purchase Header";
+ DeleteInvoicedPurchOrdersReport: Report "Delete Invoiced Purch. Orders";
+ begin
+ if PurchaseHeader.HasFilter then
+ PurchaseHeader2.CopyFilters(PurchaseHeader)
+ else begin
+ PurchaseHeader.Get(PurchaseHeader."Document Type", PurchaseHeader."No.");
+ PurchaseHeader2.SetRange("Document Type", PurchaseHeader."Document Type");
+ PurchaseHeader2.SetRange("No.", PurchaseHeader."No.");
+ end;
+ Clear(DeleteInvoicedPurchOrdersReport);
+ DeleteInvoicedPurchOrdersReport.SetTableView(PurchaseHeader2);
+ DeleteInvoicedPurchOrdersReport.UseRequestPage(false);
+ DeleteInvoicedPurchOrdersReport.RunModal();
+ end;
+
+ procedure ExplodeBOM(var PurchaseLine: Record "Purchase Line")
+ var
+ PurchExplodeBOM: Codeunit "Purch.-Explode BOM";
+ begin
+ Clear(PurchExplodeBOM);
+ PurchExplodeBOM.Run(PurchaseLine);
+ end;
+
+ procedure FilterPurchaseHeaderArchive(var PurchaseHeaderArchive: Record "Purchase Header Archive"; DocumentType: Enum "Purchase Document Type"; DocumentNo: Code[20]; DocNoOccurance: Integer; Version: Integer)
+ begin
+ PurchaseHeaderArchive.SetRange("Document Type", DocumentType);
+ PurchaseHeaderArchive.SetRange("No.", DocumentNo);
+ PurchaseHeaderArchive.SetRange("Doc. No. Occurrence", DocNoOccurance);
+ PurchaseHeaderArchive.SetRange("Version No.", Version);
+ end;
+
+ procedure FilterPurchaseLineArchive(var PurchaseLineArchive: Record "Purchase Line Archive"; DocumentType: Enum "Purchase Document Type"; DocumentNo: Code[20]; DocNoOccurance: Integer; Version: Integer)
+ begin
+ PurchaseLineArchive.SetRange("Document Type", DocumentType);
+ PurchaseLineArchive.SetRange("Document No.", DocumentNo);
+ PurchaseLineArchive.SetRange("Doc. No. Occurrence", DocNoOccurance);
+ PurchaseLineArchive.SetRange("Version No.", Version);
+ end;
+
+ procedure FindVendorPostingGroup(): Code[20]
+ var
+ VendorPostingGroup: Record "Vendor Posting Group";
+ begin
+ if not VendorPostingGroup.FindFirst() then
+ CreateVendorPostingGroup(VendorPostingGroup);
+ exit(VendorPostingGroup.Code);
+ end;
+
+ procedure FindFirstPurchLine(var PurchaseLine: Record "Purchase Line"; PurchaseHeader: Record "Purchase Header")
+ begin
+ PurchaseLine.SetRange("Document Type", PurchaseHeader."Document Type");
+ PurchaseLine.SetRange("Document No.", PurchaseHeader."No.");
+ PurchaseLine.FindFirst();
+ end;
+
+ procedure FindReturnShipmentHeader(var ReturnShipmentHeader: Record "Return Shipment Header"; ReturnOrderNo: Code[20])
+ begin
+ ReturnShipmentHeader.SetRange("Return Order No.", ReturnOrderNo);
+ ReturnShipmentHeader.FindFirst();
+ end;
+
+ procedure GetDropShipment(var PurchaseHeader: Record "Purchase Header")
+ var
+ PurchGetDropShpt: Codeunit "Purch.-Get Drop Shpt.";
+ begin
+ Clear(PurchGetDropShpt);
+ PurchGetDropShpt.Run(PurchaseHeader);
+ end;
+
+ procedure GetInvRoundingAccountOfVendPostGroup(VendorPostingGroupCode: Code[20]): Code[20]
+ var
+ VendorPostingGroup: Record "Vendor Posting Group";
+ begin
+ VendorPostingGroup.Get(VendorPostingGroupCode);
+ exit(VendorPostingGroup."Invoice Rounding Account");
+ end;
+
+ procedure GetPurchaseReturnShipmentLine(var PurchaseLine: Record "Purchase Line")
+ var
+ PurchGetReturnShipments: Codeunit "Purch.-Get Return Shipments";
+ begin
+ PurchGetReturnShipments.Run(PurchaseLine);
+ end;
+
+ procedure GetPurchaseReceiptLine(var PurchaseLine: Record "Purchase Line")
+ var
+ PurchGetReceipt: Codeunit "Purch.-Get Receipt";
+ begin
+ Clear(PurchGetReceipt);
+ PurchGetReceipt.Run(PurchaseLine);
+ end;
+
+ procedure GetSpecialOrder(var PurchaseHeader: Record "Purchase Header")
+ var
+ DistIntegration: Codeunit "Dist. Integration";
+ begin
+ Clear(DistIntegration);
+ DistIntegration.GetSpecialOrders(PurchaseHeader);
+ end;
+
+ procedure GegVendorLedgerEntryUniqueExternalDocNo(): Code[10]
+ var
+ VendorLedgerEntry: Record "Vendor Ledger Entry";
+ begin
+ exit(
+ LibraryUtility.GenerateRandomCodeWithLength(
+ VendorLedgerEntry.FieldNo("External Document No."),
+ DATABASE::"Vendor Ledger Entry",
+ 10));
+ end;
+
+ procedure PostPurchaseOrder(var PurchaseHeader: Record "Purchase Header"; Item: Record Item; LocationCode: Code[10]; VariantCode: Code[10]; Qty: Decimal; PostingDate: Date; DirectUnitCost: Decimal; Receive: Boolean; Invoice: Boolean)
+ begin
+ PostPurchaseOrderPartially(PurchaseHeader, Item, LocationCode, VariantCode, Qty, PostingDate, DirectUnitCost, Receive, Qty, Invoice, Qty);
+ end;
+
+ procedure PostPurchaseOrderWithItemTracking(var PurchaseHeader: Record "Purchase Header"; Item: Record Item; LocationCode: Code[10]; VariantCode: Code[10]; Qty: Decimal; PostingDate: Date; DirectUnitCost: Decimal; Receive: Boolean; Invoice: Boolean; SerialNo: Code[50]; LotNo: Code[50])
+ var
+ PurchaseLine: Record "Purchase Line";
+ ReservEntry: Record "Reservation Entry";
+ begin
+ CreatePurchaseOrder(PurchaseHeader, PurchaseLine, Item, LocationCode, VariantCode, Qty, PostingDate, DirectUnitCost);
+ PurchaseLine.Validate("Qty. to Receive", Qty);
+ PurchaseLine.Validate("Qty. to Invoice", Qty);
+ PurchaseLine.Modify();
+ LibraryItemTracking.CreatePurchOrderItemTracking(ReservEntry, PurchaseLine, SerialNo, LotNo, Qty);
+ if Invoice then
+ SetVendorDocNo(PurchaseHeader);
+ PostPurchaseDocument(PurchaseHeader, Receive, Invoice);
+ end;
+
+ procedure PostPurchaseOrderPartially(var PurchaseHeader: Record "Purchase Header"; Item: Record Item; LocationCode: Code[10]; VariantCode: Code[10]; Qty: Decimal; PostingDate: Date; DirectUnitCost: Decimal; Receive: Boolean; ReceiveQty: Decimal; Invoice: Boolean; InvoiceQty: Decimal)
+ var
+ PurchaseLine: Record "Purchase Line";
+ begin
+ CreatePurchaseOrder(PurchaseHeader, PurchaseLine, Item, LocationCode, VariantCode, Qty, PostingDate, DirectUnitCost);
+ PurchaseLine.Validate("Qty. to Receive", ReceiveQty);
+ PurchaseLine.Validate("Qty. to Invoice", InvoiceQty);
+ PurchaseLine.Modify();
+ if Invoice then
+ SetVendorDocNo(PurchaseHeader);
+ PostPurchaseDocument(PurchaseHeader, Receive, Invoice);
+ end;
+
+ procedure PostPurchasePrepaymentCrMemo(var PurchaseHeader: Record "Purchase Header")
+ var
+ PurchPostPrepayments: Codeunit "Purchase-Post Prepayments";
+ begin
+ PurchPostPrepayments.CreditMemo(PurchaseHeader);
+ end;
+
+ procedure PostPurchasePrepaymentCreditMemo(var PurchaseHeader: Record "Purchase Header") DocumentNo: Code[20]
+ var
+ PurchPostPrepayments: Codeunit "Purchase-Post Prepayments";
+ NoSeries: Codeunit "No. Series";
+ NoSeriesCode: Code[20];
+ begin
+ NoSeriesCode := PurchaseHeader."Prepmt. Cr. Memo No. Series";
+ if PurchaseHeader."Prepmt. Cr. Memo No." = '' then
+ DocumentNo := NoSeries.PeekNextNo(NoSeriesCode, LibraryUtility.GetNextNoSeriesPurchaseDate(NoSeriesCode))
+ else
+ DocumentNo := PurchaseHeader."Prepmt. Cr. Memo No.";
+ PurchPostPrepayments.CreditMemo(PurchaseHeader);
+ end;
+
+ procedure PostPurchasePrepaymentInvoice(var PurchaseHeader: Record "Purchase Header") DocumentNo: Code[20]
+ var
+ PurchasePostPrepayments: Codeunit "Purchase-Post Prepayments";
+ NoSeries: Codeunit "No. Series";
+ NoSeriesCode: Code[20];
+ begin
+ NoSeriesCode := PurchaseHeader."Prepayment No. Series";
+ if PurchaseHeader."Prepayment No." = '' then
+ DocumentNo := NoSeries.PeekNextNo(NoSeriesCode, LibraryUtility.GetNextNoSeriesPurchaseDate(NoSeriesCode))
+ else
+ DocumentNo := PurchaseHeader."Prepayment No.";
+ PurchasePostPrepayments.Invoice(PurchaseHeader);
+ end;
+
+ procedure PostPurchaseDocument(var PurchaseHeader: Record "Purchase Header"; NewShipReceive: Boolean; NewInvoice: Boolean) DocumentNo: Code[20]
+ var
+ NoSeries: Codeunit "No. Series";
+ PurchPost: Codeunit "Purch.-Post";
+ RecRef: RecordRef;
+ FieldRef: FieldRef;
+ DocumentFieldNo: Integer;
+ begin
+ // Post the purchase document.
+ // Depending on the document type and posting type return the number of the:
+ // - purchase receipt,
+ // - posted purchase invoice,
+ // - purchase return shipment, or
+ // - posted credit memo
+ PurchaseHeader.Validate(Receive, NewShipReceive);
+ PurchaseHeader.Validate(Ship, NewShipReceive);
+ PurchaseHeader.Validate(Invoice, NewInvoice);
+ PurchPost.SetPostingFlags(PurchaseHeader);
+
+ case PurchaseHeader."Document Type" of
+ PurchaseHeader."Document Type"::Invoice, PurchaseHeader."Document Type"::"Credit Memo":
+ if PurchaseHeader.Invoice and (PurchaseHeader."Posting No. Series" <> '') then begin
+ if (PurchaseHeader."Posting No." = '') then
+ PurchaseHeader."Posting No." := NoSeries.GetNextNo(PurchaseHeader."Posting No. Series", LibraryUtility.GetNextNoSeriesPurchaseDate(PurchaseHeader."Posting No. Series"));
+ DocumentFieldNo := PurchaseHeader.FieldNo("Last Posting No.");
+ end;
+ PurchaseHeader."Document Type"::Order:
+ begin
+ if PurchaseHeader.Receive and (PurchaseHeader."Receiving No. Series" <> '') then begin
+ if (PurchaseHeader."Receiving No." = '') then
+ PurchaseHeader."Receiving No." := NoSeries.GetNextNo(PurchaseHeader."Receiving No. Series", LibraryUtility.GetNextNoSeriesPurchaseDate(PurchaseHeader."Receiving No. Series"));
+ DocumentFieldNo := PurchaseHeader.FieldNo("Last Receiving No.");
+ end;
+ if PurchaseHeader.Invoice and (PurchaseHeader."Posting No. Series" <> '') then begin
+ if (PurchaseHeader."Posting No." = '') then
+ PurchaseHeader."Posting No." := NoSeries.GetNextNo(PurchaseHeader."Posting No. Series", LibraryUtility.GetNextNoSeriesPurchaseDate(PurchaseHeader."Posting No. Series"));
+ DocumentFieldNo := PurchaseHeader.FieldNo("Last Posting No.");
+ end;
+ end;
+ PurchaseHeader."Document Type"::"Return Order":
+ begin
+ if PurchaseHeader.Ship and (PurchaseHeader."Return Shipment No. Series" <> '') then begin
+ if (PurchaseHeader."Return Shipment No." = '') then
+ PurchaseHeader."Return Shipment No." := NoSeries.GetNextNo(PurchaseHeader."Return Shipment No. Series", LibraryUtility.GetNextNoSeriesPurchaseDate(PurchaseHeader."Return Shipment No. Series"));
+ DocumentFieldNo := PurchaseHeader.FieldNo("Last Return Shipment No.");
+ end;
+ if PurchaseHeader.Invoice and (PurchaseHeader."Posting No. Series" <> '') then begin
+ if (PurchaseHeader."Posting No." = '') then
+ PurchaseHeader."Posting No." := NoSeries.GetNextNo(PurchaseHeader."Posting No. Series", LibraryUtility.GetNextNoSeriesPurchaseDate(PurchaseHeader."Posting No. Series"));
+ DocumentFieldNo := PurchaseHeader.FieldNo("Last Posting No.");
+ end;
+ end;
+ else
+ Assert.Fail(StrSubstNo(WrongDocumentTypeErr, PurchaseHeader."Document Type"))
+ end;
+
+ CODEUNIT.Run(CODEUNIT::"Purch.-Post", PurchaseHeader);
+
+ RecRef.GetTable(PurchaseHeader);
+ FieldRef := RecRef.Field(DocumentFieldNo);
+ DocumentNo := FieldRef.Value();
+ end;
+
+ procedure QuoteMakeOrder(var PurchaseHeader: Record "Purchase Header"): Code[20]
+ var
+ PurchaseOrderHeader: Record "Purchase Header";
+ PurchQuoteToOrder: Codeunit "Purch.-Quote to Order";
+ begin
+ Clear(PurchQuoteToOrder);
+ PurchQuoteToOrder.Run(PurchaseHeader);
+ PurchQuoteToOrder.GetPurchOrderHeader(PurchaseOrderHeader);
+ exit(PurchaseOrderHeader."No.");
+ end;
+
+ procedure ReleasePurchaseDocument(var PurchaseHeader: Record "Purchase Header")
+ var
+ ReleasePurchDoc: Codeunit "Release Purchase Document";
+ begin
+ ReleasePurchDoc.PerformManualRelease(PurchaseHeader);
+ end;
+
+ procedure ReopenPurchaseDocument(var PurchaseHeader: Record "Purchase Header")
+ var
+ ReleasePurchDoc: Codeunit "Release Purchase Document";
+ begin
+ ReleasePurchDoc.PerformManualReopen(PurchaseHeader);
+ end;
+
+ procedure CalcPurchaseDiscount(PurchaseHeader: Record "Purchase Header")
+ var
+ PurchaseLine: Record "Purchase Line";
+ begin
+ PurchaseLine."Document Type" := PurchaseHeader."Document Type";
+ PurchaseLine."Document No." := PurchaseHeader."No.";
+ CODEUNIT.Run(CODEUNIT::"Purch.-Calc.Discount", PurchaseLine);
+ end;
+
+ procedure RunBatchPostPurchaseReturnOrdersReport(var PurchaseHeader: Record "Purchase Header")
+ var
+ BatchPostPurchRetOrders: Report "Batch Post Purch. Ret. Orders";
+ begin
+ Clear(BatchPostPurchRetOrders);
+ BatchPostPurchRetOrders.SetTableView(PurchaseHeader);
+ Commit(); // COMMIT is required to run this report.
+ BatchPostPurchRetOrders.UseRequestPage(true);
+ BatchPostPurchRetOrders.Run();
+ end;
+
+ procedure RunDeleteInvoicedPurchaseReturnOrdersReport(var PurchaseHeader: Record "Purchase Header")
+ var
+ DeleteInvdPurchRetOrders: Report "Delete Invd Purch. Ret. Orders";
+ begin
+ Clear(DeleteInvdPurchRetOrders);
+ DeleteInvdPurchRetOrders.SetTableView(PurchaseHeader);
+ DeleteInvdPurchRetOrders.UseRequestPage(false);
+ DeleteInvdPurchRetOrders.Run();
+ end;
+
+ procedure RunMoveNegativePurchaseLinesReport(var PurchaseHeader: Record "Purchase Header"; FromDocType: Option; ToDocType: Option; ToDocType2: Option)
+ var
+ MoveNegativePurchaseLines: Report "Move Negative Purchase Lines";
+ begin
+ Clear(MoveNegativePurchaseLines);
+ MoveNegativePurchaseLines.SetPurchHeader(PurchaseHeader);
+ MoveNegativePurchaseLines.InitializeRequest(FromDocType, ToDocType, ToDocType2);
+ MoveNegativePurchaseLines.UseRequestPage(false);
+ MoveNegativePurchaseLines.Run();
+ end;
+
+ procedure SetAllowVATDifference(AllowVATDifference: Boolean)
+ begin
+ PurchasesPayablesSetup.Get();
+ PurchasesPayablesSetup.Validate("Allow VAT Difference", AllowVATDifference);
+ PurchasesPayablesSetup.Modify(true);
+ end;
+
+ procedure SetAllowDocumentDeletionBeforeDate(Date: Date)
+ begin
+ PurchasesPayablesSetup.Get();
+ PurchasesPayablesSetup.Validate("Allow Document Deletion Before", Date);
+ PurchasesPayablesSetup.Modify(true);
+ end;
+
+ procedure SetApplnBetweenCurrencies(ApplnBetweenCurrencies: Option)
+ begin
+ PurchasesPayablesSetup.Get();
+ PurchasesPayablesSetup.Validate("Appln. between Currencies", ApplnBetweenCurrencies);
+ PurchasesPayablesSetup.Modify(true);
+ end;
+
+ procedure SetArchiveQuotesAlways()
+ begin
+ PurchasesPayablesSetup.Get();
+ PurchasesPayablesSetup.Validate("Archive Quotes", PurchasesPayablesSetup."Archive Quotes"::Always);
+ PurchasesPayablesSetup.Modify(true);
+ end;
+
+ procedure SetArchiveOrders(ArchiveOrders: Boolean)
+ begin
+ PurchasesPayablesSetup.Get();
+ PurchasesPayablesSetup.Validate("Archive Orders", ArchiveOrders);
+ PurchasesPayablesSetup.Modify(true);
+ end;
+
+ procedure SetArchiveBlanketOrders(ArchiveBlanketOrders: Boolean)
+ begin
+ PurchasesPayablesSetup.Get();
+ PurchasesPayablesSetup.Validate("Archive Blanket Orders", ArchiveBlanketOrders);
+ PurchasesPayablesSetup.Modify(true);
+ end;
+
+ procedure SetArchiveReturnOrders(ArchiveReturnOrders: Boolean)
+ begin
+ PurchasesPayablesSetup.Get();
+ PurchasesPayablesSetup.Validate("Archive Return Orders", ArchiveReturnOrders);
+ PurchasesPayablesSetup.Modify(true);
+ end;
+
+#if not CLEAN27
+ [Obsolete('Discontinued functionality', '27.0')]
+ procedure SetCreateItemFromItemNo(NewValue: Boolean)
+ begin
+ PurchasesPayablesSetup.Get();
+ PurchasesPayablesSetup.Validate("Create Item from Item No.", NewValue);
+ PurchasesPayablesSetup.Modify(true);
+ end;
+#endif
+ procedure SetDefaultPostingDateWorkDate()
+ begin
+ PurchasesPayablesSetup.Get();
+ PurchasesPayablesSetup.Validate("Default Posting Date", PurchasesPayablesSetup."Default Posting Date"::"Work Date");
+ PurchasesPayablesSetup.Modify(true);
+ end;
+
+ procedure SetDefaultPostingDateNoDate()
+ begin
+ PurchasesPayablesSetup.Get();
+ PurchasesPayablesSetup.Validate("Default Posting Date", PurchasesPayablesSetup."Default Posting Date"::"No Date");
+ PurchasesPayablesSetup.Modify(true);
+ end;
+
+ procedure SetDiscountPosting(DiscountPosting: Option)
+ begin
+ PurchasesPayablesSetup.Get();
+ PurchasesPayablesSetup.Validate("Discount Posting", DiscountPosting);
+ PurchasesPayablesSetup.Modify(true);
+ end;
+
+ procedure SetDiscountPostingSilent(DiscountPosting: Option)
+ begin
+ PurchasesPayablesSetup.Get();
+ PurchasesPayablesSetup."Discount Posting" := DiscountPosting;
+ PurchasesPayablesSetup.Modify();
+ end;
+
+ procedure SetCalcInvDiscount(CalcInvDiscount: Boolean)
+ begin
+ PurchasesPayablesSetup.Get();
+ PurchasesPayablesSetup.Validate("Calc. Inv. Discount", CalcInvDiscount);
+ PurchasesPayablesSetup.Modify(true);
+ end;
+
+ procedure SetInvoiceRounding(InvoiceRounding: Boolean)
+ begin
+ PurchasesPayablesSetup.Get();
+ PurchasesPayablesSetup.Validate("Invoice Rounding", InvoiceRounding);
+ PurchasesPayablesSetup.Modify(true);
+ end;
+
+ procedure SetExactCostReversingMandatory(ExactCostReversingMandatory: Boolean)
+ begin
+ PurchasesPayablesSetup.Get();
+ PurchasesPayablesSetup.Validate("Exact Cost Reversing Mandatory", ExactCostReversingMandatory);
+ PurchasesPayablesSetup.Modify(true);
+ end;
+
+ procedure SetExtDocNo(ExtDocNoMandatory: Boolean)
+ begin
+ PurchasesPayablesSetup.Get();
+ PurchasesPayablesSetup.Validate("Ext. Doc. No. Mandatory", ExtDocNoMandatory);
+ PurchasesPayablesSetup.Modify(true);
+ end;
+
+ procedure SetPostWithJobQueue(PostWithJobQueue: Boolean)
+ begin
+ PurchasesPayablesSetup.Get();
+ PurchasesPayablesSetup.Validate("Post with Job Queue", PostWithJobQueue);
+ PurchasesPayablesSetup.Modify(true);
+ end;
+
+ procedure SetPostAndPrintWithJobQueue(PostAndPrintWithJobQueue: Boolean)
+ begin
+ PurchasesPayablesSetup.Get();
+ PurchasesPayablesSetup.Validate("Post & Print with Job Queue", PostAndPrintWithJobQueue);
+ PurchasesPayablesSetup.Modify(true);
+ end;
+
+ procedure SetOrderNoSeriesInSetup()
+ begin
+ PurchasesPayablesSetup.Get();
+ PurchasesPayablesSetup.Validate("Order Nos.", LibraryERM.CreateNoSeriesCode());
+ PurchasesPayablesSetup.Modify(true);
+ end;
+
+ procedure SetPostedNoSeriesInSetup()
+ begin
+ PurchasesPayablesSetup.Get();
+ PurchasesPayablesSetup.Validate("Posted Invoice Nos.", LibraryERM.CreateNoSeriesCode());
+ PurchasesPayablesSetup.Validate("Posted Receipt Nos.", LibraryERM.CreateNoSeriesCode());
+ PurchasesPayablesSetup.Validate("Posted Credit Memo Nos.", LibraryERM.CreateNoSeriesCode());
+ PurchasesPayablesSetup.Modify(true);
+ end;
+
+ procedure SetQuoteNoSeriesInSetup()
+ begin
+ PurchasesPayablesSetup.Get();
+ PurchasesPayablesSetup.Validate("Quote Nos.", LibraryERM.CreateNoSeriesCode());
+ PurchasesPayablesSetup.Modify(true);
+ end;
+
+ procedure SetReturnOrderNoSeriesInSetup()
+ begin
+ PurchasesPayablesSetup.Get();
+ PurchasesPayablesSetup.Validate("Return Order Nos.", LibraryERM.CreateNoSeriesCode());
+ PurchasesPayablesSetup.Validate("Posted Return Shpt. Nos.", LibraryERM.CreateNoSeriesCode());
+ PurchasesPayablesSetup.Modify(true);
+ end;
+
+ procedure SetCopyCommentsOrderToInvoiceInSetup(CopyCommentsOrderToInvoice: Boolean)
+ begin
+ PurchasesPayablesSetup.Get();
+ PurchasesPayablesSetup.Validate("Copy Comments Order to Invoice", CopyCommentsOrderToInvoice);
+ PurchasesPayablesSetup.Modify(true);
+ end;
+
+ local procedure SetVendorDocNo(var PurchaseHeader: Record "Purchase Header")
+ begin
+ PurchaseHeader."Vendor Invoice No." := LibraryUtility.GenerateGUID();
+ PurchaseHeader."Vendor Cr. Memo No." := LibraryUtility.GenerateGUID();
+ PurchaseHeader.Modify();
+ end;
+
+ procedure SelectPmtJnlBatch(var GenJournalBatch: Record "Gen. Journal Batch")
+ begin
+ LibraryJournals.SelectGenJournalBatch(GenJournalBatch, SelectPmtJnlTemplate());
+ end;
+
+ procedure SelectPmtJnlTemplate(): Code[10]
+ var
+ GenJournalTemplate: Record "Gen. Journal Template";
+ begin
+ exit(LibraryJournals.SelectGenJournalTemplate(GenJournalTemplate.Type::Payments, PAGE::"Payment Journal"));
+ end;
+
+ procedure UndoPurchaseReceiptLine(var PurchRcptLine: Record "Purch. Rcpt. Line")
+ begin
+ CODEUNIT.Run(CODEUNIT::"Undo Purchase Receipt Line", PurchRcptLine);
+ end;
+
+ procedure UndoReturnShipmentLine(var ReturnShipmentLine: Record "Return Shipment Line")
+ begin
+ CODEUNIT.Run(CODEUNIT::"Undo Return Shipment Line", ReturnShipmentLine);
+ end;
+
+ procedure DisableConfirmOnPostingDoc()
+ var
+ InstructionMgt: Codeunit "Instruction Mgt.";
+ begin
+ InstructionMgt.DisableMessageForCurrentUser(InstructionMgt.ShowPostedConfirmationMessageCode());
+ end;
+
+ procedure DisableWarningOnCloseUnreleasedDoc()
+ begin
+ LibraryERM.DisableClosingUnreleasedOrdersMsg();
+ end;
+
+ procedure DisableWarningOnCloseUnpostedDoc()
+ var
+ InstructionMgt: Codeunit "Instruction Mgt.";
+ begin
+ InstructionMgt.DisableMessageForCurrentUser(InstructionMgt.QueryPostOnCloseCode());
+ end;
+
+ procedure EnablePurchSetupIgnoreUpdatedAddresses()
+ var
+ PurchSetup: Record "Purchases & Payables Setup";
+ begin
+ PurchSetup.Get();
+ PurchSetup."Ignore Updated Addresses" := true;
+ PurchSetup.Modify();
+ end;
+
+ procedure DisablePurchSetupIgnoreUpdatedAddresses()
+ var
+ PurchSetup: Record "Purchases & Payables Setup";
+ begin
+ PurchSetup.Get();
+ PurchSetup."Ignore Updated Addresses" := false;
+ PurchSetup.Modify();
+ end;
+
+ procedure PreviewPostPurchaseDocument(var PurchaseHeader: Record "Purchase Header")
+ var
+ PurchPostYesNo: Codeunit "Purch.-Post (Yes/No)";
+ begin
+ PurchPostYesNo.Preview(PurchaseHeader);
+ end;
+
+ procedure CreatePostVendorLedgerEntry(var VendorLedgerEntry: Record "Vendor Ledger Entry")
+ var
+ GenJournalLine: Record "Gen. Journal Line";
+ begin
+ LibraryJournals.CreateGenJournalLineWithBatch(
+ GenJournalLine, GenJournalLine."Document Type"::Invoice,
+ GenJournalLine."Account Type"::Vendor, CreateVendorNo(), -LibraryRandom.RandDec(100, 2));
+ LibraryERM.PostGeneralJnlLine(GenJournalLine);
+ LibraryERM.FindVendorLedgerEntry(VendorLedgerEntry, VendorLedgerEntry."Document Type"::Invoice, GenJournalLine."Document No.");
+ end;
+
+ [IntegrationEvent(false, false)]
+ local procedure OnAfterCreatePurchHeader(var PurchaseHeader: Record "Purchase Header"; DocumentType: Enum "Purchase Document Type"; BuyfromVendorNo: Code[20])
+ begin
+ end;
+
+ [IntegrationEvent(false, false)]
+ local procedure OnAfterCreatePurchaseLine(var PurchaseLine: Record "Purchase Line"; PurchaseHeader: Record "Purchase Header"; Type: Enum "Purchase Line Type"; No: Code[20]; Quantity: Decimal)
+ begin
+ end;
+
+ [IntegrationEvent(false, false)]
+ local procedure OnAfterCreateVendor(var Vendor: Record Vendor)
+ begin
+ end;
+
+ [IntegrationEvent(false, false)]
+ local procedure OnBeforeCreatePurchaseHeader(var PurchaseHeader: Record "Purchase Header"; DocumentType: Enum "Purchase Document Type"; BuyfromPurchaseNo: Code[20])
+ begin
+ end;
+}
diff --git a/Apps/W1/ApplicationTestLibrary/LibraryRandom.Codeunit.al b/Apps/W1/ApplicationTestLibrary/LibraryRandom.Codeunit.al
new file mode 100644
index 0000000000..374e43b9a1
--- /dev/null
+++ b/Apps/W1/ApplicationTestLibrary/LibraryRandom.Codeunit.al
@@ -0,0 +1,118 @@
+///
+/// Provides pseudo-random number generation functions for test data creation.
+///
+codeunit 130440 "Library - Random"
+{
+
+ SingleInstance = true;
+
+ trigger OnRun()
+ begin
+ end;
+
+ var
+ Seed: Integer;
+ SeedSet: Boolean;
+
+ procedure RandDec(Range: Integer; Decimals: Integer): Decimal
+ begin
+ exit(RandInt(Range * Power(10, Decimals)) / Power(10, Decimals));
+ end;
+
+ procedure RandDecInRange("Min": Integer; "Max": Integer; Decimals: Integer): Decimal
+ begin
+ // Returns a pseudo random decimal in the interval (Min,Max]
+ exit(Min + RandDec(Max - Min, Decimals));
+ end;
+
+ procedure RandDecInDecimalRange("Min": Decimal; "Max": Decimal; Precision: Integer): Decimal
+ var
+ Min2: Integer;
+ Max2: Integer;
+ Pow: Integer;
+ begin
+ Pow := Power(10, Precision);
+ Min2 := Round(Min * Pow, 1, '>');
+ Max2 := Round(Max * Pow, 1, '<');
+ exit(RandIntInRange(Min2, Max2) / Pow);
+ end;
+
+ procedure RandInt(Range: Integer): Integer
+ begin
+ // Returns a pseudo random integer in the interval [1,Range]
+ if Range < 1 then
+ exit(1);
+
+ exit(GetNextValue(Range));
+ end;
+
+ procedure RandIntInRange("Min": Integer; "Max": Integer): Integer
+ begin
+ exit(Min - 1 + RandInt(Max - Min + 1));
+ end;
+
+ procedure RandDate(Delta: Integer): Date
+ begin
+ if Delta = 0 then
+ exit(WorkDate());
+ exit(CalcDate(StrSubstNo('<%1D>', Delta / Abs(Delta) * RandInt(Abs(Delta))), WorkDate()));
+ end;
+
+ procedure RandDateFrom(FromDate: Date; Range: Integer): Date
+ begin
+ if Range = 0 then
+ exit(FromDate);
+ exit(CalcDate(StrSubstNo('<%1D>', Range / Abs(Range) * RandInt(Range)), FromDate));
+ end;
+
+ procedure RandDateFromInRange(FromDate: Date; FromRange: Integer; ToRange: Integer): Date
+ begin
+ if FromRange >= ToRange then
+ exit(FromDate);
+ exit(CalcDate(StrSubstNo('<+%1D>', RandIntInRange(FromRange, ToRange)), FromDate));
+ end;
+
+ procedure RandPrecision(): Decimal
+ begin
+ exit(1 / Power(10, RandInt(5)));
+ end;
+
+ procedure RandText(Length: Integer): Text
+ var
+ GuidTxt: Text;
+ begin
+ while StrLen(GuidTxt) < Length do
+ GuidTxt += LowerCase(DelChr(Format(CreateGuid()), '=', '{}-'));
+ exit(CopyStr(GuidTxt, 1, Length));
+ end;
+
+ procedure Init(): Integer
+ begin
+ // Updates the seed from the current time
+ exit(SetSeed(Time - 000000T));
+ end;
+
+ procedure SetSeed(Val: Integer): Integer
+ begin
+ // Set the random seed to reproduce pseudo random sequence
+ Seed := Val;
+ SeedSet := true;
+ Randomize(Seed);
+ exit(Seed);
+ end;
+
+ local procedure GetNextValue(MaxValue: Integer): Integer
+ begin
+ if (not SeedSet) then
+ SetSeed(1);
+
+ exit(Random(MaxValue));
+ end;
+
+ [EventSubscriber(ObjectType::Codeunit, Codeunit::"CAL Test Runner Publisher", 'OnSetSeed', '', false, false)]
+ local procedure OnSetSeedHandler(NewSeed: Integer)
+ begin
+ SetSeed(NewSeed);
+ end;
+}
+
diff --git a/Apps/W1/ApplicationTestLibrary/LibraryRapidStart.Codeunit.al b/Apps/W1/ApplicationTestLibrary/LibraryRapidStart.Codeunit.al
new file mode 100644
index 0000000000..ae2c228b5e
--- /dev/null
+++ b/Apps/W1/ApplicationTestLibrary/LibraryRapidStart.Codeunit.al
@@ -0,0 +1,314 @@
+///
+/// Provides utility functions for creating and managing Rapid Implementation Methodology (RapidStart) configurations in test scenarios.
+///
+codeunit 131903 "Library - Rapid Start"
+{
+
+ trigger OnRun()
+ begin
+ end;
+
+ var
+ LibraryUtility: Codeunit "Library - Utility";
+ TemplateSelectionRuleTxt: Label 'SORTING(Field1) WHERE(Field%2=1(%3))', Locked = true;
+
+ procedure CleanUp(PackageCode: Code[20])
+ var
+ ConfigLine: Record "Config. Line";
+ ConfigPackage: Record "Config. Package";
+ ConfigPackageError: Record "Config. Package Error";
+ begin
+ if PackageCode <> '' then begin
+ ConfigPackage.SetRange(Code, PackageCode);
+ ConfigLine.SetRange("Package Code", PackageCode);
+ ConfigPackageError.SetRange("Package Code", PackageCode);
+ end;
+ ConfigPackage.DeleteAll(true);
+ ConfigLine.DeleteAll(true);
+ ConfigPackageError.DeleteAll();
+ ClearLastError();
+ end;
+
+ procedure CreateConfigTemplateHeader(var ConfigTemplateHeader: Record "Config. Template Header")
+ begin
+ ConfigTemplateHeader.Init();
+ ConfigTemplateHeader.Validate(
+ Code,
+ LibraryUtility.GenerateRandomCode(ConfigTemplateHeader.FieldNo(Code), DATABASE::"Config. Template Header"));
+ // Validating Code as Description because value is not important.
+ ConfigTemplateHeader.Validate(Description, ConfigTemplateHeader.Code);
+ ConfigTemplateHeader.Insert(true);
+ end;
+
+ procedure CreateConfigTemplateLine(var ConfigTemplateLine: Record "Config. Template Line"; ConfigTemplateCode: Code[10])
+ var
+ RecRef: RecordRef;
+ begin
+ ConfigTemplateLine.Init();
+ ConfigTemplateLine.Validate("Data Template Code", ConfigTemplateCode);
+ RecRef.GetTable(ConfigTemplateLine);
+ ConfigTemplateLine.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, ConfigTemplateLine.FieldNo("Line No.")));
+ ConfigTemplateLine.Insert(true);
+ end;
+
+ procedure CreateTemplateSelectionRule(var ConfigTmplSelectionRules: Record "Config. Tmpl. Selection Rules"; FieldNo: Integer; FieldValue: Text; "Order": Integer; PageID: Integer; ConfigTemplateHeader: Record "Config. Template Header")
+ var
+ TableMetadata: Record "Table Metadata";
+ CriteriaOutStream: OutStream;
+ begin
+ ConfigTmplSelectionRules.Init();
+ ConfigTmplSelectionRules.Order := Order;
+ ConfigTmplSelectionRules."Table ID" := ConfigTemplateHeader."Table ID";
+ ConfigTmplSelectionRules."Template Code" := ConfigTemplateHeader.Code;
+ ConfigTmplSelectionRules."Page ID" := PageID;
+ ConfigTmplSelectionRules."Selection Criteria".CreateOutStream(CriteriaOutStream);
+ TableMetadata.Get(ConfigTmplSelectionRules."Table ID");
+ CriteriaOutStream.WriteText(StrSubstNo(TemplateSelectionRuleTxt, TableMetadata.Caption, FieldNo, FieldValue));
+ ConfigTmplSelectionRules.Insert(true);
+ end;
+
+ procedure CreateQuestionnaire(var ConfigQuestionnaire: Record "Config. Questionnaire")
+ begin
+ ConfigQuestionnaire.Init();
+ ConfigQuestionnaire.Validate(
+ Code,
+ LibraryUtility.GenerateRandomCode(ConfigQuestionnaire.FieldNo(Code), DATABASE::"Config. Questionnaire"));
+ // Validating Code as Description because value is not important.
+ ConfigQuestionnaire.Validate(Description, ConfigQuestionnaire.Code);
+ ConfigQuestionnaire.Insert(true);
+ end;
+
+ procedure CreateQuestion(var ConfigQuestion: Record "Config. Question"; ConfigQuestionArea: Record "Config. Question Area")
+ var
+ ConfigQuestion2: Record "Config. Question";
+ begin
+ ConfigQuestion2.SetRange("Questionnaire Code", ConfigQuestionArea."Questionnaire Code");
+ ConfigQuestion2.SetRange("Question Area Code", ConfigQuestionArea.Code);
+ if ConfigQuestion2.FindLast() then; // IF condition is required because Question may not be found.
+
+ ConfigQuestion.Init();
+ ConfigQuestion.Validate("Questionnaire Code", ConfigQuestionArea."Questionnaire Code");
+ ConfigQuestion.Validate("Question Area Code", ConfigQuestionArea.Code);
+ ConfigQuestion.Validate("No.", ConfigQuestion2."No." + 1);
+ ConfigQuestion.Insert(true);
+ end;
+
+ procedure CreateQuestionArea(var ConfigQuestionArea: Record "Config. Question Area"; QuestionnaireCode: Code[10])
+ begin
+ ConfigQuestionArea.Init();
+ ConfigQuestionArea.Validate("Questionnaire Code", QuestionnaireCode);
+ ConfigQuestionArea.Validate(
+ Code,
+ LibraryUtility.GenerateRandomCode(ConfigQuestionArea.FieldNo(Code), DATABASE::"Config. Question Area"));
+ // Validating Primary Key as Description because value is not important.
+ ConfigQuestionArea.Validate(Description, ConfigQuestionArea."Questionnaire Code" + ConfigQuestionArea.Code);
+ ConfigQuestionArea.Insert(true);
+ end;
+
+ procedure CreatePackage(var ConfigPackage: Record "Config. Package")
+ var
+ RecRef: RecordRef;
+ begin
+ RecRef.Open(DATABASE::"Config. Package");
+ ConfigPackage.Init();
+ ConfigPackage.Validate(
+ Code,
+ LibraryUtility.GenerateRandomCode(ConfigPackage.FieldNo(Code), DATABASE::"Config. Package"));
+ ConfigPackage.Validate("Package Name", 'Package ' + Format(ConfigPackage.Code));
+ ConfigPackage.Insert(true);
+ end;
+
+ procedure CreatePackageTable(var ConfigPackageTable: Record "Config. Package Table"; PackageCode: Code[20]; TableID: Integer)
+ begin
+ ConfigPackageTable.Init();
+ ConfigPackageTable.Validate("Package Code", PackageCode);
+ ConfigPackageTable.Validate("Table ID", TableID);
+ ConfigPackageTable.Insert(true);
+ end;
+
+ procedure CreatePackageTableRule(var ConfigTableProcessingRule: Record "Config. Table Processing Rule"; ConfigPackageTable: Record "Config. Package Table"; ProcessingAction: Option; CodeunitID: Integer)
+ begin
+ ConfigTableProcessingRule.Init();
+ ConfigTableProcessingRule.Validate("Package Code", ConfigPackageTable."Package Code");
+ ConfigTableProcessingRule.Validate("Table ID", ConfigPackageTable."Table ID");
+ ConfigTableProcessingRule."Rule No." += 10000;
+ ConfigTableProcessingRule.Validate(Action, ProcessingAction);
+ ConfigTableProcessingRule.Validate("Custom Processing Codeunit ID", CodeunitID);
+ ConfigTableProcessingRule.Insert(true);
+ end;
+
+ procedure CreatePackageTableRuleFilter(var ConfigPackageFilter: Record "Config. Package Filter"; ConfigTableProcessingRule: Record "Config. Table Processing Rule"; FieldID: Integer; FilterValue: Text[250])
+ begin
+ ConfigPackageFilter.Init();
+ ConfigPackageFilter.Validate("Package Code", ConfigTableProcessingRule."Package Code");
+ ConfigPackageFilter.Validate("Table ID", ConfigTableProcessingRule."Table ID");
+ ConfigPackageFilter.Validate("Processing Rule No.", ConfigTableProcessingRule."Rule No.");
+ ConfigPackageFilter.Validate("Field ID", FieldID);
+ ConfigPackageFilter.Validate("Field Filter", FilterValue);
+ ConfigPackageFilter.Insert(true);
+ end;
+
+ procedure CreatePackageRecord(var ConfigPackageRecord: Record "Config. Package Record"; PackageCode: Code[20]; TableID: Integer; RecNo: Integer)
+ begin
+ ConfigPackageRecord.Init();
+ ConfigPackageRecord.Validate("Package Code", PackageCode);
+ ConfigPackageRecord.Validate("Table ID", TableID);
+ ConfigPackageRecord.Validate("No.", RecNo);
+ if ConfigPackageRecord.Insert() then;
+ end;
+
+ procedure CreatePackageFieldData(ConfigPackageRecord: Record "Config. Package Record"; FieldID: Integer; Value: Text[250])
+ var
+ ConfigPackageData: Record "Config. Package Data";
+ begin
+ ConfigPackageData.Init();
+ ConfigPackageData.Validate("Package Code", ConfigPackageRecord."Package Code");
+ ConfigPackageData.Validate("Table ID", ConfigPackageRecord."Table ID");
+ ConfigPackageData.Validate("No.", ConfigPackageRecord."No.");
+ ConfigPackageData.Validate("Field ID", FieldID);
+ ConfigPackageData.Validate(Value, Value);
+ ConfigPackageData.Insert(true);
+ end;
+
+ procedure CreatePackageData(PackageCode: Code[20]; TableID: Integer; RecNo: Integer; FieldID: Integer; Value: Text[250])
+ var
+ ConfigPackageRecord: Record "Config. Package Record";
+ begin
+ CreatePackageRecord(ConfigPackageRecord, PackageCode, TableID, RecNo);
+ CreatePackageFieldData(ConfigPackageRecord, FieldID, Value);
+ end;
+
+ procedure CreatePackageDataForField(var ConfigPackage: Record "Config. Package"; var ConfigPackageTable: Record "Config. Package Table"; TableID: Integer; FieldID: Integer; Value: Code[250]; RecNo: Integer)
+ begin
+ if ConfigPackage.Code = '' then
+ CreatePackage(ConfigPackage);
+
+ if ConfigPackageTable."Table ID" = 0 then
+ CreatePackageTable(ConfigPackageTable, ConfigPackage.Code, TableID);
+
+ CreatePackageData(ConfigPackage.Code, TableID, RecNo, FieldID, Value);
+ end;
+
+ procedure CreateConfigLine(var ConfigLine: Record "Config. Line"; LineType: Option "Area",Group,"Table"; TableID: Integer; LineName: Text[50]; PackageCode: Code[20]; Dimensions: Boolean)
+ var
+ ConfigMgt: Codeunit "Config. Management";
+ ConfigPackageManagement: Codeunit "Config. Package Management";
+ NextLineNo: Integer;
+ begin
+ NextLineNo := 0;
+ ConfigLine.Reset();
+ if ConfigLine.FindLast() then
+ NextLineNo := ConfigLine."Line No." + 10000;
+
+ ConfigLine.Init();
+ ConfigLine.Validate("Line No.", NextLineNo);
+ ConfigLine.Validate("Line Type", LineType);
+ if LineType = LineType::Table then
+ ConfigLine.Validate("Table ID", TableID)
+ else
+ ConfigLine.Validate(Name, LineName);
+ ConfigLine.Insert(true);
+
+ ConfigMgt.AssignParentLineNos();
+
+ if PackageCode <> '' then begin
+ ConfigLine.SetRange("Line No.", ConfigLine."Line No.");
+ ConfigPackageManagement.AssignPackage(ConfigLine, PackageCode);
+ ConfigLine.SetRange("Line No.");
+ end;
+
+ if Dimensions then begin
+ ConfigLine.Get(NextLineNo);
+ ConfigLine.Validate("Dimensions as Columns", true);
+ ConfigLine.Modify(true);
+ end;
+ end;
+
+ procedure SetIncludeOneField(PackageCode: Code[20]; TableID: Integer; FieldID: Integer; SetInclude: Boolean)
+ var
+ ConfigPackageField: Record "Config. Package Field";
+ begin
+ ConfigPackageField.Get(PackageCode, TableID, FieldID);
+ ConfigPackageField.Validate("Include Field", SetInclude);
+ ConfigPackageField.Modify();
+ end;
+
+ procedure SetIncludeFields(PackageCode: Code[20]; TableID: Integer; FromFieldID: Integer; ToFieldID: Integer; SetInclude: Boolean)
+ var
+ ConfigPackageField: Record "Config. Package Field";
+ begin
+ ConfigPackageField.Reset();
+ ConfigPackageField.SetRange("Package Code", PackageCode);
+ ConfigPackageField.SetRange("Table ID", TableID);
+ ConfigPackageField.SetRange("Field ID", FromFieldID, ToFieldID);
+ ConfigPackageField.ModifyAll("Include Field", SetInclude, true);
+ end;
+
+ procedure SetIncludeAllFields(CoonfigPackageCode: Code[20]; TableNo: Integer; SetInclude: Boolean)
+ var
+ ConfigPackageField: Record "Config. Package Field";
+ begin
+ ConfigPackageField.SetRange("Package Code", CoonfigPackageCode);
+ ConfigPackageField.SetRange("Table ID", TableNo);
+ ConfigPackageField.SetRange("Primary Key", false);
+ ConfigPackageField.ModifyAll("Include Field", SetInclude, true);
+ end;
+
+ procedure SetValidateOneField(PackageCode: Code[20]; TableID: Integer; FieldID: Integer; SetValidate: Boolean)
+ var
+ ConfigPackageField: Record "Config. Package Field";
+ begin
+ ConfigPackageField.Get(PackageCode, TableID, FieldID);
+ ConfigPackageField.Validate("Validate Field", SetValidate);
+ ConfigPackageField.Modify();
+ end;
+
+ procedure SetProcessingOrderForRecord(PackageCode: Code[20]; TableID: Integer; ProcessingNo: Integer)
+ var
+ ConfigPackageTable: Record "Config. Package Table";
+ begin
+ ConfigPackageTable.Get(PackageCode, TableID);
+ ConfigPackageTable."Processing Order" := ProcessingNo;
+ ConfigPackageTable.Modify();
+ end;
+
+ procedure SetProcessingOrderForField(PackageCode: Code[20]; TableID: Integer; FieldID: Integer; ProcessingNo: Integer)
+ var
+ ConfigPackageField: Record "Config. Package Field";
+ begin
+ ConfigPackageField.Get(PackageCode, TableID, FieldID);
+ ConfigPackageField."Processing Order" := ProcessingNo;
+ ConfigPackageField.Modify();
+ end;
+
+ procedure SetCreateMissingCodesForField(PackageCode: Code[20]; TableID: Integer; FieldID: Integer; SetCreateMissingCodes: Boolean)
+ var
+ ConfigPackageField: Record "Config. Package Field";
+ begin
+ ConfigPackageField.Get(PackageCode, TableID, FieldID);
+ ConfigPackageField.Validate("Create Missing Codes", SetCreateMissingCodes);
+ ConfigPackageField.Modify();
+ end;
+
+ procedure ApplyPackage(ConfigPackage: Record "Config. Package"; SetupProcessingOrderForTables: Boolean)
+ var
+ ConfigPackageTable: Record "Config. Package Table";
+ ConfigPackageMgt: Codeunit "Config. Package Management";
+ begin
+ ConfigPackageMgt.SetHideDialog(true);
+ ConfigPackageTable.SetRange("Package Code", ConfigPackage.Code);
+ ConfigPackageMgt.ApplyPackage(ConfigPackage, ConfigPackageTable, SetupProcessingOrderForTables);
+ end;
+
+ procedure ValidatePackage(ConfigPackage: Record "Config. Package"; SetupProcessingOrderForTables: Boolean)
+ var
+ ConfigPackageTable: Record "Config. Package Table";
+ TempConfigPackageTable: Record "Config. Package Table" temporary;
+ ConfigPackageMgt: Codeunit "Config. Package Management";
+ begin
+ ConfigPackageMgt.SetHideDialog(true);
+ ConfigPackageTable.SetRange("Package Code", ConfigPackage.Code);
+ ConfigPackageMgt.ValidatePackageRelations(ConfigPackageTable, TempConfigPackageTable, SetupProcessingOrderForTables);
+ end;
+}
+
diff --git a/Apps/W1/ApplicationTestLibrary/LibraryResource.Codeunit.al b/Apps/W1/ApplicationTestLibrary/LibraryResource.Codeunit.al
new file mode 100644
index 0000000000..8b7ee132af
--- /dev/null
+++ b/Apps/W1/ApplicationTestLibrary/LibraryResource.Codeunit.al
@@ -0,0 +1,256 @@
+///
+/// Provides utility functions for creating and managing resource entities in test scenarios, including resources, resource groups, and resource prices.
+///
+codeunit 130511 "Library - Resource"
+{
+
+ trigger OnRun()
+ begin
+ end;
+
+ var
+ LibraryERM: Codeunit "Library - ERM";
+ LibraryRandom: Codeunit "Library - Random";
+ LibraryUtility: Codeunit "Library - Utility";
+
+ procedure CreateResource(var Resource: Record Resource; VATBusPostingGroup: Code[20])
+ var
+ GeneralPostingSetup: Record "General Posting Setup";
+ VATPostingSetup: Record "VAT Posting Setup";
+ UnitOfMeasure: Record "Unit of Measure";
+ LibraryInventory: Codeunit "Library - Inventory";
+ begin
+ Resource.Init();
+ Resource.Validate("No.", LibraryUtility.GenerateRandomCode(Resource.FieldNo("No."), DATABASE::Resource));
+ Resource.Insert(true);
+
+ LibraryInventory.FindUnitOfMeasure(UnitOfMeasure);
+
+ GeneralPostingSetup.SetFilter("Gen. Bus. Posting Group", '<>%1', '');
+ GeneralPostingSetup.SetFilter("Gen. Prod. Posting Group", '<>%1', '');
+ GeneralPostingSetup.SetFilter("Sales Account", '<>%1', '');
+ GeneralPostingSetup.FindFirst();
+
+ Resource.Validate(Name, Resource."No."); // Validate Name as No. because value is not important.
+ Resource.Validate("Base Unit of Measure", UnitOfMeasure.Code);
+ Resource.Validate("Direct Unit Cost", LibraryRandom.RandInt(100)); // Required field - value is not important.
+ Resource.Validate("Unit Price", LibraryRandom.RandInt(100)); // Required field - value is not important.
+ Resource.Validate("Gen. Prod. Posting Group", GeneralPostingSetup."Gen. Prod. Posting Group");
+
+ VATPostingSetup.SetRange("VAT Bus. Posting Group", VATBusPostingGroup);
+ VATPostingSetup.SetRange("VAT Calculation Type", VATPostingSetup."VAT Calculation Type"::"Normal VAT");
+ if VATPostingSetup.FindFirst() then
+ Resource.Validate("VAT Prod. Posting Group", VATPostingSetup."VAT Prod. Posting Group");
+ Resource.Modify(true);
+ end;
+
+ procedure CreateResourceNew(var Resource: Record Resource)
+ var
+ GeneralPostingSetup: Record "General Posting Setup";
+ VATPostingSetup: Record "VAT Posting Setup";
+ UnitOfMeasure: Record "Unit of Measure";
+ LibraryInventory: Codeunit "Library - Inventory";
+ begin
+ ResNoSeriesSetup();
+ LibraryInventory.FindUnitOfMeasure(UnitOfMeasure);
+ LibraryERM.FindGeneralPostingSetupInvtFull(GeneralPostingSetup);
+ LibraryERM.FindVATPostingSetupInvt(VATPostingSetup);
+
+ Clear(Resource);
+ Resource.Insert(true);
+ Resource.Validate(Name, Resource."No."); // Validate Name as No. because value is not important.
+ Resource.Validate("Base Unit of Measure", UnitOfMeasure.Code);
+ Resource.Validate("Direct Unit Cost", LibraryRandom.RandInt(100)); // Required field - value is not important.
+ Resource.Validate("Unit Price", LibraryRandom.RandInt(100)); // Required field - value is not important.
+ Resource.Validate("Gen. Prod. Posting Group", GeneralPostingSetup."Gen. Prod. Posting Group");
+ Resource.Validate("VAT Prod. Posting Group", VATPostingSetup."VAT Prod. Posting Group");
+ Resource.Modify(true);
+ end;
+
+ procedure CreateResourceNo(): Code[20]
+ var
+ Resource: Record Resource;
+ begin
+ CreateResourceNew(Resource);
+ exit(Resource."No.");
+ end;
+
+ procedure CreateResourceGroup(var ResourceGroup: Record "Resource Group")
+ begin
+ ResourceGroup.Init();
+ ResourceGroup.Validate("No.", LibraryUtility.GenerateRandomCode(ResourceGroup.FieldNo("No."), DATABASE::"Resource Group"));
+ ResourceGroup.Validate(Name, ResourceGroup."No."); // Validate Name as No. because value is not important.
+ ResourceGroup.Insert(true);
+ end;
+
+ procedure CreateResourcePrice(var ResourcePrice: Record "Resource Price"; Type: Option; "Code": Code[20]; WorkTypeCode: Code[10]; CurrencyCode: Code[10])
+ begin
+ ResourcePrice.Init();
+ ResourcePrice.Validate(Type, Type);
+ ResourcePrice.Validate(Code, Code);
+ ResourcePrice.Validate("Work Type Code", WorkTypeCode);
+ ResourcePrice.Validate("Currency Code", CurrencyCode);
+ ResourcePrice.Insert(true);
+ end;
+
+ procedure CreateResJournalLine(var ResJournalLine: Record "Res. Journal Line"; JournalTemplateName: Code[10]; JournalBatchName: Code[10])
+ var
+ RecRef: RecordRef;
+ begin
+ ResJournalLine.Init();
+ ResJournalLine.Validate("Journal Template Name", JournalTemplateName);
+ ResJournalLine.Validate("Journal Batch Name", JournalBatchName);
+ RecRef.GetTable(ResJournalLine);
+ ResJournalLine.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, ResJournalLine.FieldNo("Line No.")));
+ ResJournalLine.Insert(true);
+ end;
+
+ procedure CreateResourceSkill(var ResourceSkill: Record "Resource Skill"; Type: Enum "Resource Skill Type"; No: Code[20]; SkillCode: Code[10])
+ begin
+ ResourceSkill.Init();
+ ResourceSkill.Validate(Type, Type);
+ ResourceSkill.Validate("No.", No);
+ ResourceSkill.Validate("Skill Code", SkillCode);
+ ResourceSkill.Insert(true);
+ end;
+
+ procedure CreateResourceUnitOfMeasure(var ResourceUnitOfMeasure: Record "Resource Unit of Measure"; ResourceNo: Code[20]; UnitOfMeasureCode: Code[10]; QtyPerUoM: Decimal)
+ begin
+ ResourceUnitOfMeasure.Init();
+ ResourceUnitOfMeasure.Validate("Resource No.", ResourceNo);
+ ResourceUnitOfMeasure.Validate(Code, UnitOfMeasureCode);
+ if QtyPerUoM = 0 then
+ QtyPerUoM := 1;
+ ResourceUnitOfMeasure.Validate("Qty. per Unit of Measure", QtyPerUoM);
+ ResourceUnitOfMeasure.Insert(true);
+ end;
+
+ procedure CreateResourceWithUsers(var Resource: Record Resource)
+ begin
+ CreateResource(Resource, '');
+ Resource."Time Sheet Owner User ID" := UserId;
+ Resource."Time Sheet Approver User ID" := UserId;
+ Resource.Modify();
+ end;
+
+ procedure CreateSkillCode(var SkillCode: Record "Skill Code")
+ begin
+ SkillCode.Init();
+ SkillCode.Validate(Code, LibraryUtility.GenerateRandomCode(SkillCode.FieldNo(Code), DATABASE::"Skill Code"));
+ SkillCode.Insert(true);
+ SkillCode.Validate(Description, SkillCode.Code); // Validate Description as Code because value is not important.
+ SkillCode.Modify(true);
+ end;
+
+ procedure CreateResourceJournalTemplate(var ResJournalTemplate: Record "Res. Journal Template")
+ begin
+ ResJournalTemplate.Init();
+ ResJournalTemplate.Validate(
+ Name,
+ CopyStr(LibraryUtility.GenerateRandomCode(ResJournalTemplate.FieldNo(Name), DATABASE::"Res. Journal Template"),
+ 1,
+ LibraryUtility.GetFieldLength(DATABASE::"Res. Journal Template", ResJournalTemplate.FieldNo(Name))));
+ ResJournalTemplate.Validate(Description, ResJournalTemplate.Name); // Validate Description as Name because value is not important.
+ ResJournalTemplate.Insert(true);
+ end;
+
+ procedure CreateResourceJournalBatch(var ResJournalBatch: Record "Res. Journal Batch"; JournalTemplateName: Code[10])
+ begin
+ ResJournalBatch.Init();
+ ResJournalBatch.Validate("Journal Template Name", JournalTemplateName);
+ ResJournalBatch.Validate(
+ Name,
+ CopyStr(LibraryUtility.GenerateRandomCode(ResJournalBatch.FieldNo(Name), DATABASE::"Res. Journal Batch"),
+ 1,
+ LibraryUtility.GetFieldLength(DATABASE::"Res. Journal Batch", ResJournalBatch.FieldNo(Name))));
+ // Validate Description as Primary Key because value is not important.
+ ResJournalBatch.Validate(Description, ResJournalBatch."Journal Template Name" + ResJournalBatch.Name);
+ ResJournalBatch.Insert(true);
+ end;
+
+ procedure CreateWorkType(var WorkType: Record "Work Type")
+ var
+ UnitOfMeasure: Record "Unit of Measure";
+ LibraryInventory: Codeunit "Library - Inventory";
+ begin
+ LibraryInventory.FindUnitOfMeasure(UnitOfMeasure);
+
+ WorkType.Init();
+ WorkType.Validate(
+ Code,
+ CopyStr(
+ LibraryUtility.GenerateRandomCode(WorkType.FieldNo(Code), DATABASE::"Work Type"),
+ 1,
+ LibraryUtility.GetFieldLength(DATABASE::"Work Type", WorkType.FieldNo(Code))));
+
+ // Validating Description as Code because value is not important.
+ WorkType.Validate(Description, WorkType.Code);
+ WorkType.Validate("Unit of Measure Code", UnitOfMeasure.Code);
+ WorkType.Insert(true);
+ end;
+
+ procedure CreateWorkHourTemplate(var WorkHourTemplate: Record "Work-Hour Template")
+ begin
+ WorkHourTemplate.Init();
+ WorkHourTemplate.Validate(
+ Code,
+ CopyStr(
+ LibraryUtility.GenerateRandomCode(WorkHourTemplate.FieldNo(Code), DATABASE::"Work-Hour Template"), 1,
+ LibraryUtility.GetFieldLength(DATABASE::"Work-Hour Template", WorkHourTemplate.FieldNo(Code))));
+ WorkHourTemplate.Insert(true);
+ end;
+
+ procedure FindResource(var Resource: Record Resource)
+ begin
+ // Filter Resource so that errors are not generated due to mandatory fields.
+ Resource.SetFilter("Gen. Prod. Posting Group", '<>''''');
+ Resource.SetFilter("VAT Prod. Posting Group", '<>''''');
+ Resource.SetRange(Blocked, false);
+
+ Resource.FindSet();
+ end;
+
+ procedure FindResJournalBatch(var ResJournalBatch: Record "Res. Journal Batch"; JournalTemplateName: Code[10])
+ begin
+ ResJournalBatch.SetRange("Journal Template Name", JournalTemplateName);
+ ResJournalBatch.FindFirst();
+ end;
+
+ procedure FindResJournalTemplate(var ResJournalTemplate: Record "Res. Journal Template")
+ begin
+ ResJournalTemplate.FindFirst();
+ end;
+
+ procedure FindWorkType(var WorkType: Record "Work Type")
+ begin
+ WorkType.FindSet();
+ end;
+
+ [Normal]
+ procedure PostResourceJournalLine(var ResJournalLine: Record "Res. Journal Line")
+ begin
+ ResJournalLine.SetRange("Journal Template Name", ResJournalLine."Journal Template Name");
+ ResJournalLine.SetRange("Journal Batch Name", ResJournalLine."Journal Batch Name");
+ CODEUNIT.Run(CODEUNIT::"Res. Jnl.-Post", ResJournalLine);
+ end;
+
+ local procedure ResNoSeriesSetup()
+ var
+ ResourcesSetup: Record "Resources Setup";
+ NoSeriesCode: Code[20];
+ begin
+ ResourcesSetup.Get();
+ NoSeriesCode := LibraryUtility.GetGlobalNoSeriesCode();
+ if NoSeriesCode <> ResourcesSetup."Resource Nos." then begin
+ ResourcesSetup.Validate("Resource Nos.", LibraryUtility.GetGlobalNoSeriesCode());
+ ResourcesSetup.Modify(true);
+ end;
+ end;
+
+ procedure SetResourceBlocked(var Resource: Record Resource)
+ begin
+ Resource.Validate(Blocked, true);
+ Resource.Modify(true);
+ end;
+}
+
diff --git a/Apps/W1/ApplicationTestLibrary/LibrarySales.Codeunit.al b/Apps/W1/ApplicationTestLibrary/LibrarySales.Codeunit.al
new file mode 100644
index 0000000000..33f52c8e64
--- /dev/null
+++ b/Apps/W1/ApplicationTestLibrary/LibrarySales.Codeunit.al
@@ -0,0 +1,2321 @@
+///
+/// Provides utility functions for creating and managing sales documents in test scenarios, including sales orders, invoices, and credit memos.
+///
+codeunit 130509 "Library - Sales"
+{
+
+ trigger OnRun()
+ begin
+ end;
+
+ var
+ SalesReceivablesSetup: Record "Sales & Receivables Setup";
+ LibraryUtility: Codeunit "Library - Utility";
+ LibraryERM: Codeunit "Library - ERM";
+ LibraryInventory: Codeunit "Library - Inventory";
+ LibraryResource: Codeunit "Library - Resource";
+ LibraryRandom: Codeunit "Library - Random";
+ LibraryJournals: Codeunit "Library - Journals";
+ LibrarySmallBusiness: Codeunit "Library - Small Business";
+ WrongDocumentTypeErr: Label 'Document type not supported: %1', Locked = true;
+
+ ///
+ /// Assigns an item charge to a sales shipment line.
+ ///
+ /// The sales header for creating the charge line.
+ /// The sales shipment line to assign the charge to.
+ /// The quantity to assign.
+ /// The unit cost of the charge.
+ procedure AssignSalesChargeToSalesShptLine(SalesHeader: Record "Sales Header"; SalesShptLine: Record "Sales Shipment Line"; Qty: Decimal; UnitCost: Decimal)
+ var
+ ItemCharge: Record "Item Charge";
+ SalesLine: Record "Sales Line";
+ ItemChargeAssignmentSales: Record "Item Charge Assignment (Sales)";
+ LibrarySales: Codeunit "Library - Sales";
+ begin
+ CreateItemChargeSalesLine(SalesLine, ItemCharge, SalesHeader, Qty, UnitCost);
+
+ SalesShptLine.TestField(Type, SalesShptLine.Type::Item);
+
+ LibrarySales.CreateItemChargeAssignment(ItemChargeAssignmentSales, SalesLine, ItemCharge,
+ ItemChargeAssignmentSales."Applies-to Doc. Type"::Shipment,
+ SalesShptLine."Document No.", SalesShptLine."Line No.",
+ SalesShptLine."No.", Qty, UnitCost);
+ ItemChargeAssignmentSales.Insert();
+ end;
+
+ ///
+ /// Assigns an item charge to a sales line.
+ ///
+ /// The sales header for creating the charge line.
+ /// The sales line to assign the charge to.
+ /// The quantity to assign.
+ /// The unit cost of the charge.
+ procedure AssignSalesChargeToSalesLine(SalesHeader: Record "Sales Header"; SalesLine: Record "Sales Line"; Qty: Decimal; UnitCost: Decimal)
+ var
+ ItemCharge: Record "Item Charge";
+ SalesLine1: Record "Sales Line";
+ ItemChargeAssignmentSales: Record "Item Charge Assignment (Sales)";
+ LibrarySales: Codeunit "Library - Sales";
+ begin
+ CreateItemChargeSalesLine(SalesLine1, ItemCharge, SalesHeader, Qty, UnitCost);
+
+ SalesLine.TestField(Type, SalesLine.Type::Item);
+
+ LibrarySales.CreateItemChargeAssignment(ItemChargeAssignmentSales, SalesLine1, ItemCharge,
+ ItemChargeAssignmentSales."Applies-to Doc. Type"::Order,
+ SalesLine."Document No.", SalesLine."Line No.",
+ SalesLine."No.", Qty, UnitCost);
+ ItemChargeAssignmentSales.Insert();
+ end;
+
+ ///
+ /// Assigns an item charge to a sales return line.
+ ///
+ /// The sales header for creating the charge line.
+ /// The sales return line to assign the charge to.
+ /// The quantity to assign.
+ /// The unit cost of the charge.
+ procedure AssignSalesChargeToSalesReturnLine(SalesHeader: Record "Sales Header"; SalesLine: Record "Sales Line"; Qty: Decimal; UnitCost: Decimal)
+ var
+ ItemCharge: Record "Item Charge";
+ SalesLine1: Record "Sales Line";
+ ItemChargeAssignmentSales: Record "Item Charge Assignment (Sales)";
+ LibrarySales: Codeunit "Library - Sales";
+ begin
+ CreateItemChargeSalesLine(SalesLine1, ItemCharge, SalesHeader, Qty, UnitCost);
+
+ SalesLine.TestField(Type, SalesLine.Type::Item);
+
+ LibrarySales.CreateItemChargeAssignment(ItemChargeAssignmentSales, SalesLine1, ItemCharge,
+ ItemChargeAssignmentSales."Applies-to Doc. Type"::"Return Order",
+ SalesLine."Document No.", SalesLine."Line No.",
+ SalesLine."No.", Qty, UnitCost);
+ ItemChargeAssignmentSales.Insert();
+ end;
+
+ ///
+ /// Creates a sales line with an item charge.
+ ///
+ /// The sales line record to create.
+ /// The item charge record to create.
+ /// The sales header to link the line to.
+ /// The quantity of the item charge.
+ /// The unit cost of the item charge.
+ procedure CreateItemChargeSalesLine(var SalesLine: Record "Sales Line"; var ItemCharge: Record "Item Charge"; SalesHeader: Record "Sales Header"; Qty: Decimal; UnitCost: Decimal)
+ var
+ LibrarySales: Codeunit "Library - Sales";
+ begin
+ LibraryInventory.CreateItemCharge(ItemCharge);
+ LibrarySales.CreateSalesLine(SalesLine, SalesHeader, SalesLine.Type::"Charge (Item)", ItemCharge."No.", Qty);
+ SalesLine.Validate("Unit Price", UnitCost);
+ SalesLine.Validate("Unit Cost", UnitCost);
+ SalesLine.Modify(true);
+ end;
+
+ ///
+ /// Batch posts multiple sales orders using the Batch Post Sales Orders report.
+ ///
+ /// The sales headers to post.
+ /// Specifies whether to ship the orders.
+ /// Specifies whether to invoice the orders.
+ /// The posting date to use.
+ /// Specifies whether to replace the posting date.
+ /// Specifies whether to replace the document date.
+ /// Specifies whether to calculate invoice discount.
+ procedure BatchPostSalesHeaders(var SalesHeader: Record "Sales Header"; Ship: Boolean; Invoice: Boolean; PostingDate: Date; ReplacePostingDate: Boolean; ReplaceDocumentDate: Boolean; CalcInvDiscount: Boolean)
+ var
+ BatchPostSalesOrders: Report "Batch Post Sales Orders";
+ begin
+ BatchPostSalesOrders.UseRequestPage(false);
+ BatchPostSalesOrders.InitializeRequest(Ship, Invoice, PostingDate, PostingDate, ReplacePostingDate, ReplaceDocumentDate, ReplacePostingDate, CalcInvDiscount);
+ BatchPostSalesOrders.SetTableView(SalesHeader);
+ BatchPostSalesOrders.RunModal();
+ end;
+
+ ///
+ /// Converts a blanket sales order to a sales order.
+ ///
+ /// The blanket sales order to convert.
+ /// The number of the created sales order.
+ procedure BlanketSalesOrderMakeOrder(var SalesHeader: Record "Sales Header"): Code[20]
+ var
+ SalesOrderHeader: Record "Sales Header";
+ BlanketSalesOrderToOrder: Codeunit "Blanket Sales Order to Order";
+ begin
+ Clear(BlanketSalesOrderToOrder);
+ BlanketSalesOrderToOrder.Run(SalesHeader);
+ BlanketSalesOrderToOrder.GetSalesOrderHeader(SalesOrderHeader);
+ exit(SalesOrderHeader."No.");
+ end;
+
+ ///
+ /// Copies a sales document to another sales document.
+ ///
+ /// The target sales header to copy to.
+ /// The document type to copy from.
+ /// The document number to copy from.
+ /// Specifies whether to include header information.
+ /// Specifies whether to recalculate lines.
+ procedure CopySalesDocument(SalesHeader: Record "Sales Header"; FromDocType: Enum "Sales Document Type From"; FromDocNo: Code[20]; IncludeHeader: Boolean; RecalcLines: Boolean)
+ var
+ CopySalesDocumentReport: Report "Copy Sales Document";
+ begin
+ CopySalesDocumentReport.SetSalesHeader(SalesHeader);
+ CopySalesDocumentReport.SetParameters(FromDocType, FromDocNo, IncludeHeader, RecalcLines);
+ CopySalesDocumentReport.UseRequestPage(false);
+ CopySalesDocumentReport.Run();
+ end;
+
+ ///
+ /// Copies ship-to address information from a customer to a sales header.
+ ///
+ /// The sales header to update.
+ /// The customer to copy address information from.
+ procedure CopySalesHeaderShipToAddressFromCustomer(var SalesHeader: Record "Sales Header"; Customer: Record Customer)
+ begin
+ SalesHeader.Validate("Ship-to Name", Customer.Name);
+ SalesHeader.Validate("Ship-to Address", Customer.Address);
+ SalesHeader.Validate("Ship-to Address 2", Customer."Address 2");
+ SalesHeader.Validate("Ship-to City", Customer.City);
+ SalesHeader.Validate("Ship-to Post Code", Customer."Post Code");
+ SalesHeader.Validate("Ship-to Country/Region Code", Customer."Country/Region Code");
+ SalesHeader.Validate("Ship-to County", Customer.County);
+ SalesHeader.Modify(true);
+ end;
+
+ ///
+ /// Creates a new customer with default setup.
+ ///
+ /// The customer record to create.
+ procedure CreateCustomer(var Customer: Record Customer)
+ var
+ PaymentMethod: Record "Payment Method";
+ GeneralPostingSetup: Record "General Posting Setup";
+ VATPostingSetup: Record "VAT Posting Setup";
+ CustContUpdate: Codeunit "CustCont-Update";
+ begin
+ LibraryERM.FindPaymentMethod(PaymentMethod);
+ LibraryERM.SetSearchGenPostingTypeSales();
+ LibraryERM.FindGeneralPostingSetupInvtFull(GeneralPostingSetup);
+ LibraryERM.FindVATPostingSetupInvt(VATPostingSetup);
+ LibraryUtility.UpdateSetupNoSeriesCode(
+ DATABASE::"Sales & Receivables Setup", SalesReceivablesSetup.FieldNo("Customer Nos."));
+
+ Clear(Customer);
+ OnCreateCustomerOnBeforeInsertCustomer(Customer);
+ Customer.Insert(true);
+ Customer.Validate(Name, Customer."No."); // Validating Name as No. because value is not important.
+ Customer.Validate("Payment Method Code", PaymentMethod.Code); // Mandatory for posting in ES build
+ Customer.Validate("Payment Terms Code", LibraryERM.FindPaymentTermsCode()); // Mandatory for posting in ES build
+ Customer.Validate("Gen. Bus. Posting Group", GeneralPostingSetup."Gen. Bus. Posting Group");
+ Customer.Validate("VAT Bus. Posting Group", VATPostingSetup."VAT Bus. Posting Group");
+ Customer.Validate("Customer Posting Group", FindCustomerPostingGroup());
+ Customer.Modify(true);
+ CustContUpdate.OnModify(Customer);
+
+ OnAfterCreateCustomer(Customer);
+ end;
+
+ ///
+ /// Creates a new customer with specified contact type.
+ ///
+ /// The customer record to create.
+ /// The contact type to assign to the customer.
+ procedure CreateCustomer(var Customer: Record Customer; ContactType: Enum "Contact Type")
+ begin
+ LibraryUtility.UpdateSetupNoSeriesCode(
+ DATABASE::"Sales & Receivables Setup", SalesReceivablesSetup.FieldNo("Customer Nos."));
+
+ Clear(Customer);
+ Customer.Validate("Contact Type", ContactType);
+ Customer.Insert(true);
+ end;
+
+ ///
+ /// Creates a new customer with country code and VAT registration number.
+ ///
+ /// The customer record to create.
+ procedure CreateCustomerWithCountryCodeAndVATRegNo(var Customer: Record Customer)
+ begin
+ CreateCustomer(Customer);
+ Customer.Validate("Country/Region Code", LibraryERM.CreateCountryRegion());
+ Customer."VAT Registration No." := LibraryERM.GenerateVATRegistrationNo(Customer."Country/Region Code");
+ Customer.Modify(true);
+ end;
+
+ ///
+ /// Creates a new customer with country code and VAT registration number and returns the customer number.
+ ///
+ /// The customer number of the created customer.
+ procedure CreateCustomerWithCountryCodeAndVATRegNo(): Code[20]
+ var
+ Customer: Record Customer;
+ begin
+ CreateCustomerWithCountryCodeAndVATRegNo(Customer);
+ exit(Customer."No.");
+ end;
+
+ ///
+ /// Creates a new customer with address information.
+ ///
+ /// The customer record to create.
+ procedure CreateCustomerWithAddress(var Customer: Record Customer)
+ begin
+ CreateCustomer(Customer);
+ CreateCustomerAddress(Customer);
+ end;
+
+ ///
+ /// Adds address information to an existing customer.
+ ///
+ /// The customer to update with address information.
+ procedure CreateCustomerAddress(var Customer: Record Customer)
+ var
+ PostCode: Record "Post Code";
+ CustContUpdate: Codeunit "CustCont-Update";
+ begin
+ Customer.Validate(Address, CopyStr(LibraryUtility.GenerateGUID(), 1, MaxStrLen(Customer.Address)));
+ Customer.Validate("Address 2", CopyStr(LibraryUtility.GenerateGUID(), 1, MaxStrLen(Customer."Address 2")));
+
+ LibraryERM.CreatePostCode(PostCode);
+ Customer.Validate("Country/Region Code", PostCode."Country/Region Code");
+ Customer.Validate(City, PostCode.City);
+ Customer.Validate(County, PostCode.County);
+ Customer.Validate("Post Code", PostCode.Code);
+ Customer.Modify(true);
+ CustContUpdate.OnModify(Customer);
+ end;
+
+ ///
+ /// Creates a new customer with address and contact information.
+ ///
+ /// The customer record to create.
+ procedure CreateCustomerWithAddressAndContactInfo(var Customer: Record Customer)
+ begin
+ CreateCustomerWithAddress(Customer);
+ CreateCustomerContactInfo(Customer);
+ end;
+
+ ///
+ /// Adds contact information to an existing customer.
+ ///
+ /// The customer to update with contact information.
+ procedure CreateCustomerContactInfo(var Customer: Record Customer)
+ var
+ CustContUpdate: Codeunit "CustCont-Update";
+ begin
+ Customer.Validate("Phone No.", LibraryUtility.GenerateRandomPhoneNo());
+ Customer.Modify(true);
+ CustContUpdate.OnModify(Customer);
+ end;
+
+ ///
+ /// Creates a new customer and returns the customer number.
+ ///
+ /// The customer number of the created customer.
+ procedure CreateCustomerNo(): Code[20]
+ var
+ Customer: Record Customer;
+ begin
+ CreateCustomer(Customer);
+ exit(Customer."No.");
+ end;
+
+ ///
+ /// Creates a customer bank account.
+ ///
+ /// The customer bank account record to create.
+ /// The customer number to link the bank account to.
+ procedure CreateCustomerBankAccount(var CustomerBankAccount: Record "Customer Bank Account"; CustomerNo: Code[20])
+ begin
+ CustomerBankAccount.Init();
+ CustomerBankAccount.Validate("Customer No.", CustomerNo);
+ CustomerBankAccount.Validate(
+ Code,
+ CopyStr(
+ LibraryUtility.GenerateRandomCode(CustomerBankAccount.FieldNo(Code), DATABASE::"Customer Bank Account"),
+ 1,
+ LibraryUtility.GetFieldLength(DATABASE::"Customer Bank Account", CustomerBankAccount.FieldNo(Code))));
+ CustomerBankAccount.Insert(true);
+ end;
+
+ ///
+ /// Creates a customer posting group with all required GL accounts.
+ ///
+ /// The customer posting group record to create.
+ procedure CreateCustomerPostingGroup(var CustomerPostingGroup: Record "Customer Posting Group")
+ begin
+ CustomerPostingGroup.Init();
+ CustomerPostingGroup.Validate(Code,
+ LibraryUtility.GenerateRandomCode(CustomerPostingGroup.FieldNo(Code), DATABASE::"Customer Posting Group"));
+ CustomerPostingGroup.Validate("Receivables Account", LibraryERM.CreateGLAccountNo());
+ CustomerPostingGroup.Validate("Invoice Rounding Account", LibraryERM.CreateGLAccountWithSalesSetup());
+ CustomerPostingGroup.Validate("Debit Rounding Account", LibraryERM.CreateGLAccountNo());
+ CustomerPostingGroup.Validate("Credit Rounding Account", LibraryERM.CreateGLAccountNo());
+ CustomerPostingGroup.Validate("Payment Disc. Debit Acc.", LibraryERM.CreateGLAccountNo());
+ CustomerPostingGroup.Validate("Payment Disc. Credit Acc.", LibraryERM.CreateGLAccountNo());
+ CustomerPostingGroup.Validate("Payment Tolerance Debit Acc.", LibraryERM.CreateGLAccountNo());
+ CustomerPostingGroup.Validate("Payment Tolerance Credit Acc.", LibraryERM.CreateGLAccountNo());
+ CustomerPostingGroup.Validate("Debit Curr. Appln. Rndg. Acc.", LibraryERM.CreateGLAccountNo());
+ CustomerPostingGroup.Validate("Credit Curr. Appln. Rndg. Acc.", LibraryERM.CreateGLAccountNo());
+ CustomerPostingGroup.Validate("Interest Account", LibraryERM.CreateGLAccountWithSalesSetup());
+ CustomerPostingGroup.Validate("Additional Fee Account", LibraryERM.CreateGLAccountWithSalesSetup());
+ CustomerPostingGroup.Validate("Add. Fee per Line Account", LibraryERM.CreateGLAccountWithSalesSetup());
+ CustomerPostingGroup.Insert(true);
+ end;
+
+ ///
+ /// Creates an alternative customer posting group link.
+ ///
+ /// The parent customer posting group code.
+ /// The alternative customer posting group code.
+ procedure CreateAltCustomerPostingGroup(ParentCode: Code[20]; AltCode: Code[20])
+ var
+ AltCustomerPostingGroup: Record "Alt. Customer Posting Group";
+ begin
+ AltCustomerPostingGroup.Init();
+ AltCustomerPostingGroup."Customer Posting Group" := ParentCode;
+ AltCustomerPostingGroup."Alt. Customer Posting Group" := AltCode;
+ AltCustomerPostingGroup.Insert();
+ end;
+
+ ///
+ /// Creates a customer price group.
+ ///
+ /// The customer price group record to create.
+ procedure CreateCustomerPriceGroup(var CustomerPriceGroup: Record "Customer Price Group")
+ begin
+ CustomerPriceGroup.Init();
+ CustomerPriceGroup.Validate(
+ Code, LibraryUtility.GenerateRandomCode(CustomerPriceGroup.FieldNo(Code), DATABASE::"Customer Price Group"));
+ CustomerPriceGroup.Validate(Description, CustomerPriceGroup.Code);
+ // Validating Description as Code because value is not important.
+ CustomerPriceGroup.Insert(true);
+ end;
+
+ ///
+ /// Creates a new customer with a specified location code.
+ ///
+ /// The customer record to create.
+ /// The location code to assign to the customer.
+ /// The customer number of the created customer.
+ procedure CreateCustomerWithLocationCode(var Customer: Record Customer; LocationCode: Code[10]): Code[20]
+ begin
+ CreateCustomer(Customer);
+ Customer.Validate("Location Code", LocationCode);
+ Customer.Modify(true);
+ exit(Customer."No.");
+ end;
+
+ ///
+ /// Creates a new customer with specified business posting groups.
+ ///
+ /// The general business posting group code to assign.
+ /// The VAT business posting group code to assign.
+ /// The customer number of the created customer.
+ procedure CreateCustomerWithBusPostingGroups(GenBusPostingGroupCode: Code[20]; VATBusPostingGroupCode: Code[20]): Code[20]
+ var
+ Customer: Record Customer;
+ begin
+ CreateCustomer(Customer);
+ Customer.Validate("Gen. Bus. Posting Group", GenBusPostingGroupCode);
+ Customer.Validate("VAT Bus. Posting Group", VATBusPostingGroupCode);
+ Customer.Modify(true);
+ exit(Customer."No.");
+ end;
+
+ ///
+ /// Creates a new customer with specified VAT business posting group.
+ ///
+ /// The VAT business posting group code to assign.
+ /// The customer number of the created customer.
+ procedure CreateCustomerWithVATBusPostingGroup(VATBusPostingGroupCode: Code[20]): Code[20]
+ var
+ Customer: Record Customer;
+ begin
+ CreateCustomer(Customer);
+ Customer.Validate("VAT Bus. Posting Group", VATBusPostingGroupCode);
+ Customer.Modify(true);
+ exit(Customer."No.");
+ end;
+
+ ///
+ /// Creates a new customer with country code and VAT registration number.
+ ///
+ /// The customer record to create.
+ /// The customer number of the created customer.
+ procedure CreateCustomerWithVATRegNo(var Customer: Record Customer): Code[20]
+ var
+ CountryRegion: Record "Country/Region";
+ begin
+ CreateCustomer(Customer);
+ LibraryERM.CreateCountryRegion(CountryRegion);
+ Customer.Validate("Country/Region Code", CountryRegion.Code);
+ Customer."VAT Registration No." := LibraryERM.GenerateVATRegistrationNo(CountryRegion.Code);
+ Customer.Modify(true);
+ exit(Customer."No.");
+ end;
+
+ ///
+ /// Filters sales header archive records by document type, number, occurrence, and version.
+ ///
+ /// The sales header archive record to filter.
+ /// The document type to filter by.
+ /// The document number to filter by.
+ /// The document number occurrence to filter by.
+ /// The version number to filter by.
+ procedure FilterSalesHeaderArchive(var SalesHeaderArchive: Record "Sales Header Archive"; DocumentType: Enum "Sales Document Type"; DocumentNo: Code[20]; DocNoOccurence: Integer; Version: Integer)
+ begin
+ SalesHeaderArchive.SetRange("Document Type", DocumentType);
+ SalesHeaderArchive.SetRange("No.", DocumentNo);
+ SalesHeaderArchive.SetRange("Doc. No. Occurrence", DocNoOccurence);
+ SalesHeaderArchive.SetRange("Version No.", Version);
+ end;
+
+ ///
+ /// Filters sales line archive records by document type, number, occurrence, and version.
+ ///
+ /// The sales line archive record to filter.
+ /// The document type to filter by.
+ /// The document number to filter by.
+ /// The document number occurrence to filter by.
+ /// The version number to filter by.
+ procedure FilterSalesLineArchive(var SalesLineArchive: Record "Sales Line Archive"; DocumentType: Enum "Sales Document Type"; DocumentNo: Code[20]; DocNoOccurence: Integer; Version: Integer)
+ begin
+ SalesLineArchive.SetRange("Document Type", DocumentType);
+ SalesLineArchive.SetRange("Document No.", DocumentNo);
+ SalesLineArchive.SetRange("Doc. No. Occurrence", DocNoOccurence);
+ SalesLineArchive.SetRange("Version No.", Version);
+ end;
+
+ local procedure CreateGeneralJournalBatch(var GenJournalBatch: Record "Gen. Journal Batch")
+ var
+ GenJournalTemplate: Record "Gen. Journal Template";
+ begin
+ GenJournalTemplate.SetRange(Recurring, false);
+ GenJournalTemplate.SetRange(Type, GenJournalTemplate.Type::General);
+ LibraryERM.FindGenJournalTemplate(GenJournalTemplate);
+ LibraryERM.CreateGenJournalBatch(GenJournalBatch, GenJournalTemplate.Name);
+ end;
+
+ ///
+ /// Creates an item charge assignment for a sales line.
+ ///
+ /// The item charge assignment record to create.
+ /// The sales line with the item charge.
+ /// The item charge record.
+ /// The document type to apply the charge to.
+ /// The document number to apply the charge to.
+ /// The document line number to apply the charge to.
+ /// The item number to assign the charge to.
+ /// The quantity to assign.
+ /// The unit cost of the charge.
+ procedure CreateItemChargeAssignment(var ItemChargeAssignmentSales: Record "Item Charge Assignment (Sales)"; SalesLine: Record "Sales Line"; ItemCharge: Record "Item Charge"; DocType: Enum "Sales Document Type"; DocNo: Code[20]; DocLineNo: Integer; ItemNo: Code[20]; Qty: Decimal; UnitCost: Decimal)
+ var
+ RecRef: RecordRef;
+ begin
+ Clear(ItemChargeAssignmentSales);
+
+ ItemChargeAssignmentSales."Document Type" := SalesLine."Document Type";
+ ItemChargeAssignmentSales."Document No." := SalesLine."Document No.";
+ ItemChargeAssignmentSales."Document Line No." := SalesLine."Line No.";
+ ItemChargeAssignmentSales."Item Charge No." := SalesLine."No.";
+ ItemChargeAssignmentSales."Unit Cost" := SalesLine."Unit Cost";
+ RecRef.GetTable(ItemChargeAssignmentSales);
+ ItemChargeAssignmentSales."Line No." := LibraryUtility.GetNewLineNo(RecRef, ItemChargeAssignmentSales.FieldNo("Line No."));
+ ItemChargeAssignmentSales."Item Charge No." := ItemCharge."No.";
+ ItemChargeAssignmentSales."Applies-to Doc. Type" := DocType;
+ ItemChargeAssignmentSales."Applies-to Doc. No." := DocNo;
+ ItemChargeAssignmentSales."Applies-to Doc. Line No." := DocLineNo;
+ ItemChargeAssignmentSales."Item No." := ItemNo;
+ ItemChargeAssignmentSales."Unit Cost" := UnitCost;
+ ItemChargeAssignmentSales.Validate("Qty. to Assign", Qty);
+ end;
+
+ ///
+ /// Creates a payment journal line and applies it to a posted sales invoice.
+ ///
+ /// The general journal line record to create.
+ /// The customer number for the payment.
+ /// The posted invoice number to apply the payment to.
+ /// The payment amount.
+ procedure CreatePaymentAndApplytoInvoice(var GenJournalLine: Record "Gen. Journal Line"; CustomerNo: Code[20]; AppliesToDocNo: Code[20]; Amount: Decimal)
+ var
+ GenJournalBatch: Record "Gen. Journal Batch";
+ GLAccount: Record "G/L Account";
+ begin
+ CreateGeneralJournalBatch(GenJournalBatch);
+ LibraryERM.CreateGLAccount(GLAccount);
+ LibraryERM.CreateGeneralJnlLine(
+ GenJournalLine, GenJournalBatch."Journal Template Name", GenJournalBatch.Name, GenJournalLine."Document Type"::Payment,
+ GenJournalLine."Account Type"::Customer, CustomerNo, Amount);
+
+ // Value of Document No. is not important.
+ GenJournalLine.Validate("Document No.", GenJournalLine."Journal Batch Name" + Format(GenJournalLine."Line No."));
+ GenJournalLine.Validate("Applies-to Doc. Type", GenJournalLine."Applies-to Doc. Type"::Invoice);
+ GenJournalLine.Validate("Applies-to Doc. No.", AppliesToDocNo);
+ GenJournalLine.Validate("Bal. Account No.", GLAccount."No.");
+ GenJournalLine.Modify(true);
+ LibraryERM.PostGeneralJnlLine(GenJournalLine);
+ end;
+
+ ///
+ /// Creates a prepayment VAT setup with specified VAT calculation type.
+ ///
+ /// The G/L account for the line.
+ /// The VAT calculation type to use.
+ /// The prepayment G/L account number.
+ procedure CreatePrepaymentVATSetup(var LineGLAccount: Record "G/L Account"; VATCalculationType: Enum "Tax Calculation Type"): Code[20]
+ var
+ PrepmtGLAccount: Record "G/L Account";
+ begin
+ LibraryERM.CreatePrepaymentVATSetup(
+ LineGLAccount, PrepmtGLAccount, LineGLAccount."Gen. Posting Type"::Sale, VATCalculationType, VATCalculationType);
+ exit(PrepmtGLAccount."No.");
+ end;
+
+ ///
+ /// Creates a sales document with specified parameters.
+ ///
+ /// The sales header record to create.
+ /// The sales line record to create.
+ /// The document type to create.
+ /// The item for the sales line.
+ /// The location code for the sales line.
+ /// The variant code for the sales line.
+ /// The quantity for the sales line.
+ /// The posting date for the sales document.
+ /// The unit price for the sales line.
+ procedure CreateSalesDocument(var SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; DocType: Enum "Sales Document Type"; Item: Record Item; LocationCode: Code[10]; VariantCode: Code[10]; Qty: Decimal; PostingDate: Date; UnitPrice: Decimal)
+ begin
+ CreateSalesHeader(SalesHeader, DocType, '');
+ SalesHeader.Validate("Posting Date", PostingDate);
+ SalesHeader.Modify(true);
+ CreateSalesLine(SalesLine, SalesHeader, SalesLine.Type::Item, Item."No.", Qty);
+ SalesLine."Location Code" := LocationCode;
+ SalesLine."Variant Code" := VariantCode;
+ SalesLine.Validate("Unit Price", UnitPrice);
+ SalesLine.Modify(true);
+ end;
+
+ ///
+ /// Creates a sales order with specified parameters.
+ ///
+ /// The sales header record to create.
+ /// The sales line record to create.
+ /// The item for the sales line.
+ /// The location code for the sales line.
+ /// The variant code for the sales line.
+ /// The quantity for the sales line.
+ /// The posting date for the sales order.
+ /// The unit price for the sales line.
+ procedure CreateSalesOrder(var SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; Item: Record Item; LocationCode: Code[10]; VariantCode: Code[10]; Qty: Decimal; PostingDate: Date; UnitPrice: Decimal)
+ begin
+ CreateSalesDocument(
+ SalesHeader, SalesLine, SalesHeader."Document Type"::Order, Item, LocationCode, VariantCode, Qty, PostingDate, UnitPrice);
+ end;
+
+ ///
+ /// Creates a sales invoice with specified parameters.
+ ///
+ /// The sales header record to create.
+ /// The sales line record to create.
+ /// The item for the sales line.
+ /// The location code for the sales line.
+ /// The variant code for the sales line.
+ /// The quantity for the sales line.
+ /// The posting date for the sales invoice.
+ /// The unit price for the sales line.
+ procedure CreateSalesInvoice(var SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; Item: Record Item; LocationCode: Code[10]; VariantCode: Code[10]; Qty: Decimal; PostingDate: Date; UnitPrice: Decimal)
+ begin
+ CreateSalesDocument(
+ SalesHeader, SalesLine, SalesHeader."Document Type"::Invoice, Item, LocationCode, VariantCode, Qty, PostingDate, UnitPrice);
+ end;
+
+ ///
+ /// Creates a sales quote with specified parameters.
+ ///
+ /// The sales header record to create.
+ /// The sales line record to create.
+ /// The item for the sales line.
+ /// The location code for the sales line.
+ /// The variant code for the sales line.
+ /// The quantity for the sales line.
+ /// The posting date for the sales quote.
+ /// The unit price for the sales line.
+ procedure CreateSalesQuote(var SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; Item: Record Item; LocationCode: Code[10]; VariantCode: Code[10]; Qty: Decimal; PostingDate: Date; UnitPrice: Decimal)
+ begin
+ CreateSalesDocument(
+ SalesHeader, SalesLine, SalesHeader."Document Type"::Quote, Item, LocationCode, VariantCode, Qty, PostingDate, UnitPrice);
+ end;
+
+ ///
+ /// Creates a sales blanket order with specified parameters.
+ ///
+ /// The sales header record to create.
+ /// The sales line record to create.
+ /// The item for the sales line.
+ /// The location code for the sales line.
+ /// The variant code for the sales line.
+ /// The quantity for the sales line.
+ /// The posting date for the blanket order.
+ /// The unit price for the sales line.
+ procedure CreateSalesBlanketOrder(var SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; Item: Record Item; LocationCode: Code[10]; VariantCode: Code[10]; Qty: Decimal; PostingDate: Date; UnitPrice: Decimal)
+ begin
+ CreateSalesDocument(
+ SalesHeader, SalesLine, SalesHeader."Document Type"::"Blanket Order", Item, LocationCode, VariantCode, Qty, PostingDate, UnitPrice);
+ end;
+
+ ///
+ /// Creates a sales return order with specified parameters.
+ ///
+ /// The sales header record to create.
+ /// The sales line record to create.
+ /// The item for the sales line.
+ /// The location code for the sales line.
+ /// The variant code for the sales line.
+ /// The quantity for the sales line.
+ /// The posting date for the return order.
+ /// The unit cost for the sales line.
+ /// The unit price for the sales line.
+ procedure CreateSalesReturnOrder(var SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; Item: Record Item; LocationCode: Code[10]; VariantCode: Code[10]; Qty: Decimal; PostingDate: Date; UnitCost: Decimal; UnitPrice: Decimal)
+ begin
+ CreateSalesDocument(
+ SalesHeader, SalesLine, SalesHeader."Document Type"::"Return Order", Item, LocationCode, VariantCode, Qty, PostingDate, UnitPrice);
+ SalesLine.Validate("Unit Cost (LCY)", UnitCost);
+ SalesLine.Modify();
+ end;
+
+ ///
+ /// Creates a sales credit memo with specified parameters.
+ ///
+ /// The sales header record to create.
+ /// The sales line record to create.
+ /// The item for the sales line.
+ /// The location code for the sales line.
+ /// The variant code for the sales line.
+ /// The quantity for the sales line.
+ /// The posting date for the credit memo.
+ /// The unit cost for the sales line.
+ /// The unit price for the sales line.
+ procedure CreateSalesCreditMemo(var SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; Item: Record Item; LocationCode: Code[10]; VariantCode: Code[10]; Qty: Decimal; PostingDate: Date; UnitCost: Decimal; UnitPrice: Decimal)
+ begin
+ CreateSalesDocument(
+ SalesHeader, SalesLine, SalesHeader."Document Type"::"Credit Memo", Item, LocationCode, VariantCode, Qty, PostingDate, UnitPrice);
+ SalesLine.Validate("Unit Cost (LCY)", UnitCost);
+ SalesLine.Modify();
+ end;
+
+ ///
+ /// Creates a sales document with an item line.
+ ///
+ /// The sales header record to create.
+ /// The sales line record to create.
+ /// The document type to create.
+ /// The customer number for the document.
+ /// The item number for the sales line.
+ /// The quantity for the sales line.
+ /// The location code for the sales line.
+ /// The shipment date for the sales line.
+ procedure CreateSalesDocumentWithItem(var SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; DocumentType: Enum "Sales Document Type"; CustomerNo: Code[20]; ItemNo: Code[20]; Quantity: Decimal; LocationCode: Code[10]; ShipmentDate: Date)
+ begin
+ CreateFCYSalesDocumentWithItem(SalesHeader, SalesLine, DocumentType, CustomerNo, ItemNo, Quantity, LocationCode, ShipmentDate, '');
+ end;
+
+ ///
+ /// Creates a sales document with an item line in foreign currency.
+ ///
+ /// The sales header record to create.
+ /// The sales line record to create.
+ /// The document type to create.
+ /// The customer number for the document.
+ /// The item number for the sales line.
+ /// The quantity for the sales line.
+ /// The location code for the sales line.
+ /// The shipment date for the sales line.
+ /// The currency code for the document.
+ procedure CreateFCYSalesDocumentWithItem(var SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; DocumentType: Enum "Sales Document Type"; CustomerNo: Code[20]; ItemNo: Code[20]; Quantity: Decimal; LocationCode: Code[10]; ShipmentDate: Date; CurrencyCode: Code[10])
+ begin
+ CreateSalesHeader(SalesHeader, DocumentType, CustomerNo);
+ if LocationCode <> '' then
+ SalesHeader.Validate("Location Code", LocationCode);
+ SalesHeader.Validate("Currency Code", CurrencyCode);
+ SalesHeader.Modify(true);
+ if ItemNo = '' then
+ ItemNo := LibraryInventory.CreateItemNo();
+ CreateSalesLine(SalesLine, SalesHeader, SalesLine.Type::Item, ItemNo, Quantity);
+ if LocationCode <> '' then
+ SalesLine.Validate("Location Code", LocationCode);
+ if ShipmentDate <> 0D then
+ SalesLine.Validate("Shipment Date", ShipmentDate);
+ SalesLine.Validate("Unit Price", LibraryRandom.RandDec(100, 2));
+ SalesLine.Modify(true);
+ end;
+
+ ///
+ /// Creates a sales header with the specified document type and customer number.
+ ///
+ /// The sales header record to create.
+ /// The document type to create.
+ /// The sell-to customer number for the document.
+ procedure CreateSalesHeader(var SalesHeader: Record "Sales Header"; DocumentType: Enum "Sales Document Type"; SellToCustomerNo: Code[20])
+ begin
+ DisableWarningOnCloseUnreleasedDoc();
+ DisableWarningOnCloseUnpostedDoc();
+ DisableConfirmOnPostingDoc();
+ Clear(SalesHeader);
+ OnBeforeCreateSalesHeader(SalesHeader, DocumentType, SellToCustomerNo);
+ SalesHeader.Validate("Document Type", DocumentType);
+ SalesHeader.Insert(true);
+ if SellToCustomerNo = '' then
+ SellToCustomerNo := CreateCustomerNo();
+ SalesHeader.Validate("Sell-to Customer No.", SellToCustomerNo);
+ SalesHeader.Validate(
+ "External Document No.",
+ CopyStr(LibraryUtility.GenerateRandomCode(SalesHeader.FieldNo("External Document No."), DATABASE::"Sales Header"), 1, 20));
+ SalesHeader.Modify(true);
+
+ OnAfterCreateSalesHeader(SalesHeader, DocumentType.AsInteger(), SellToCustomerNo);
+ end;
+
+ ///
+ /// Creates a sales line with specified type, number, and quantity using the shipment date from the header.
+ ///
+ /// The sales line record to create.
+ /// The sales header to link the line to.
+ /// The line type (Item, G/L Account, Resource, etc.).
+ /// The number of the item, account, or resource.
+ /// The quantity for the line.
+ procedure CreateSalesLine(var SalesLine: Record "Sales Line"; SalesHeader: Record "Sales Header"; Type: Enum "Sales Line Type"; No: Code[20]; Quantity: Decimal)
+ begin
+ CreateSalesLineWithShipmentDate(SalesLine, SalesHeader, Type, No, SalesHeader."Shipment Date", Quantity);
+ end;
+
+ ///
+ /// Creates a sales line with specified type, number, quantity, and shipment date.
+ ///
+ /// The sales line record to create.
+ /// The sales header to link the line to.
+ /// The line type (Item, G/L Account, Resource, etc.).
+ /// The number of the item, account, or resource.
+ /// The shipment date for the line.
+ /// The quantity for the line.
+ procedure CreateSalesLineWithShipmentDate(var SalesLine: Record "Sales Line"; SalesHeader: Record "Sales Header"; Type: Enum "Sales Line Type"; No: Code[20]; ShipmentDate: Date; Quantity: Decimal)
+ begin
+ CreateSalesLineSimple(SalesLine, SalesHeader);
+
+ SalesLine.Validate(Type, Type);
+ case Type of
+ SalesLine.Type::Item:
+ if No = '' then
+ No := LibraryInventory.CreateItemNo();
+ SalesLine.Type::Resource:
+ if No = '' then
+ No := LibraryResource.CreateResourceNo();
+ SalesLine.Type::"Charge (Item)":
+ if No = '' then
+ No := LibraryInventory.CreateItemChargeNo();
+ SalesLine.Type::"G/L Account":
+ if No = '' then
+ No := LibraryERM.CreateGLAccountWithSalesSetup();
+ end;
+ SalesLine.Validate("No.", No);
+ SalesLine.Validate("Shipment Date", ShipmentDate);
+ if Quantity <> 0 then
+ SalesLine.Validate(Quantity, Quantity);
+ SalesLine.Modify(true);
+
+ OnAfterCreateSalesLineWithShipmentDate(SalesLine, SalesHeader, Type.AsInteger(), No, ShipmentDate, Quantity);
+ end;
+
+ ///
+ /// Creates a simple sales line without validating type or number.
+ ///
+ /// The sales line record to create.
+ /// The sales header to link the line to.
+ procedure CreateSalesLineSimple(var SalesLine: Record "Sales Line"; SalesHeader: Record "Sales Header")
+ var
+ RecRef: RecordRef;
+ begin
+ SalesLine.Init();
+ SalesLine.Validate("Document Type", SalesHeader."Document Type");
+ SalesLine.Validate("Document No.", SalesHeader."No.");
+ RecRef.GetTable(SalesLine);
+ SalesLine.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, SalesLine.FieldNo("Line No.")));
+ SalesLine.Insert(true);
+ end;
+
+ ///
+ /// Creates a simple sales line with only the type validated.
+ ///
+ /// The sales line record to create.
+ /// The sales header to link the line to.
+ /// The line type (Item, G/L Account, Resource, etc.).
+ procedure CreateSimpleItemSalesLine(var SalesLine: Record "Sales Line"; SalesHeader: Record "Sales Header"; Type: Enum "Sales Line Type")
+ begin
+ CreateSalesLineSimple(SalesLine, SalesHeader);
+ SalesLine.Validate(Type, Type);
+ SalesLine.Modify(true);
+ end;
+
+ ///
+ /// Creates a sales invoice with a random customer and item.
+ ///
+ /// The sales header record to create.
+ procedure CreateSalesInvoice(var SalesHeader: Record "Sales Header")
+ begin
+ CreateSalesInvoiceForCustomerNo(SalesHeader, CreateCustomerNo());
+ end;
+
+ ///
+ /// Creates a sales invoice with a specified customer and random item.
+ ///
+ /// The sales header record to create.
+ /// The customer number for the invoice.
+ procedure CreateSalesInvoiceForCustomerNo(var SalesHeader: Record "Sales Header"; CustomerNo: Code[20])
+ var
+ Item: Record Item;
+ SalesLine: Record "Sales Line";
+ begin
+ CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Invoice, CustomerNo);
+ LibraryInventory.CreateItemWithUnitPriceAndUnitCost(
+ Item, LibraryRandom.RandDecInRange(1, 100, 2), LibraryRandom.RandDecInRange(1, 100, 2));
+ CreateSalesLine(SalesLine, SalesHeader, SalesLine.Type::Item, Item."No.", LibraryRandom.RandInt(100));
+ end;
+
+ ///
+ /// Creates a sales order with a random customer and item.
+ ///
+ /// The sales header record to create.
+ procedure CreateSalesOrder(var SalesHeader: Record "Sales Header")
+ begin
+ CreateSalesOrderForCustomerNo(SalesHeader, CreateCustomerNo());
+ end;
+
+ ///
+ /// Creates a sales order with a specified customer and random item.
+ ///
+ /// The sales header record to create.
+ /// The customer number for the order.
+ procedure CreateSalesOrderForCustomerNo(var SalesHeader: Record "Sales Header"; CustomerNo: Code[20])
+ var
+ Item: Record Item;
+ SalesLine: Record "Sales Line";
+ begin
+ CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Order, CustomerNo);
+ LibraryInventory.CreateItemWithUnitPriceAndUnitCost(
+ Item, LibraryRandom.RandDecInRange(1, 100, 2), LibraryRandom.RandDecInRange(1, 100, 2));
+ CreateSalesLine(SalesLine, SalesHeader, SalesLine.Type::Item, Item."No.", LibraryRandom.RandInt(100));
+ end;
+
+ ///
+ /// Creates a sales credit memo with a random customer and item.
+ ///
+ /// The sales header record to create.
+ procedure CreateSalesCreditMemo(var SalesHeader: Record "Sales Header")
+ begin
+ CreateSalesCreditMemoForCustomerNo(SalesHeader, CreateCustomerNo());
+ end;
+
+ ///
+ /// Creates a sales credit memo with a specified customer and random item.
+ ///
+ /// The sales header record to create.
+ /// The customer number for the credit memo.
+ procedure CreateSalesCreditMemoForCustomerNo(var SalesHeader: Record "Sales Header"; CustomerNo: Code[20])
+ var
+ Item: Record Item;
+ SalesLine: Record "Sales Line";
+ begin
+ CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::"Credit Memo", CustomerNo);
+ LibraryInventory.CreateItemWithUnitPriceAndUnitCost(
+ Item, LibraryRandom.RandDecInRange(1, 100, 2), LibraryRandom.RandDecInRange(1, 100, 2));
+ CreateSalesLine(SalesLine, SalesHeader, SalesLine.Type::Item, Item."No.", LibraryRandom.RandInt(100));
+ end;
+
+ ///
+ /// Creates a sales quote with a specified customer and random item.
+ ///
+ /// The sales header record to create.
+ /// The customer number for the quote.
+ procedure CreateSalesQuoteForCustomerNo(var SalesHeader: Record "Sales Header"; CustomerNo: Code[20])
+ var
+ Item: Record Item;
+ SalesLine: Record "Sales Line";
+ begin
+ CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Quote, CustomerNo);
+ LibraryInventory.CreateItemWithUnitPriceAndUnitCost(
+ Item, LibraryRandom.RandDecInRange(1, 100, 2), LibraryRandom.RandDecInRange(1, 100, 2));
+ CreateSalesLine(SalesLine, SalesHeader, SalesLine.Type::Item, Item."No.", LibraryRandom.RandInt(100));
+ end;
+
+ ///
+ /// Creates a sales order with specified customer and location.
+ ///
+ /// The sales header record to create.
+ /// The customer number for the order.
+ /// The location code for the order.
+ procedure CreateSalesOrderWithLocation(var SalesHeader: Record "Sales Header"; CustomerNo: Code[20]; LocationCode: Code[10])
+ begin
+ CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Order, CustomerNo);
+ SalesHeader.Validate("Location Code", LocationCode);
+ SalesHeader.Modify();
+ end;
+
+ ///
+ /// Creates a sales return order with specified customer and location.
+ ///
+ /// The sales header record to create.
+ /// The customer number for the return order.
+ /// The location code for the return order.
+ procedure CreateSalesReturnOrderWithLocation(var SalesHeader: Record "Sales Header"; CustomerNo: Code[20]; LocationCode: Code[10])
+ begin
+ CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::"Return Order", CustomerNo);
+ SalesHeader.Validate("Location Code", LocationCode);
+ SalesHeader.Modify();
+ end;
+
+ ///
+ /// Creates a sales return order with a random customer and item.
+ ///
+ /// The sales header record to create.
+ procedure CreateSalesReturnOrder(var SalesHeader: Record "Sales Header")
+ begin
+ CreateSalesReturnOrderForCustomerNo(SalesHeader, CreateCustomerNo());
+ end;
+
+ ///
+ /// Creates a sales return order with a specified customer and random item.
+ ///
+ /// The sales header record to create.
+ /// The customer number for the return order.
+ procedure CreateSalesReturnOrderForCustomerNo(var SalesHeader: Record "Sales Header"; CustomerNo: Code[20])
+ var
+ Item: Record Item;
+ SalesLine: Record "Sales Line";
+ begin
+ CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::"Return Order", CustomerNo);
+ LibraryInventory.CreateItemWithUnitPriceAndUnitCost(
+ Item, LibraryRandom.RandDecInRange(1, 100, 2), LibraryRandom.RandDecInRange(1, 100, 2));
+ CreateSalesLine(SalesLine, SalesHeader, SalesLine.Type::Item, Item."No.", LibraryRandom.RandInt(100));
+ end;
+
+ ///
+ /// Creates a sales line with a specified unit price.
+ ///
+ /// The sales line record to create.
+ /// The sales header to link the line to.
+ /// The item number for the line.
+ /// The unit price for the line.
+ /// The quantity for the line.
+ procedure CreateSalesLineWithUnitPrice(var SalesLine: Record "Sales Line"; SalesHeader: Record "Sales Header"; ItemNo: Code[20]; UnitPrice: Decimal; Quantity: Decimal)
+ begin
+ CreateSalesLine(SalesLine, SalesHeader, SalesLine.Type::Item, ItemNo, Quantity);
+ SalesLine.Validate("Unit Price", UnitPrice);
+ SalesLine.Modify();
+ end;
+
+ ///
+ /// Creates a salesperson/purchaser record.
+ ///
+ /// The salesperson/purchaser record to create.
+ procedure CreateSalesperson(var SalespersonPurchaser: Record "Salesperson/Purchaser")
+ begin
+ SalespersonPurchaser.Init();
+ SalespersonPurchaser.Validate(
+ Code, LibraryUtility.GenerateRandomCode(SalespersonPurchaser.FieldNo(Code), DATABASE::"Salesperson/Purchaser"));
+ SalespersonPurchaser.Validate(Name, SalespersonPurchaser.Code); // Validating Name as Code because value is not important.
+ SalespersonPurchaser.Insert(true);
+ end;
+
+ ///
+ /// Creates a sales prepayment percentage record.
+ ///
+ /// The sales prepayment percentage record to create.
+ /// The sales type (Customer, Customer Price Group, All Customers, Campaign).
+ /// The sales code (customer number, price group code, etc.).
+ /// The item number.
+ /// The starting date for the prepayment percentage.
+ procedure CreateSalesPrepaymentPct(var SalesPrepaymentPct: Record "Sales Prepayment %"; SalesType: Option; SalesCode: Code[20]; ItemNo: Code[20]; StartingDate: Date)
+ begin
+ SalesPrepaymentPct.Init();
+ SalesPrepaymentPct.Validate("Item No.", ItemNo);
+ SalesPrepaymentPct.Validate("Sales Type", SalesType);
+ SalesPrepaymentPct.Validate("Sales Code", SalesCode);
+ SalesPrepaymentPct.Validate("Starting Date", StartingDate);
+ SalesPrepaymentPct.Insert(true);
+ end;
+
+ ///
+ /// Creates a sales comment line.
+ ///
+ /// The sales comment line record to create.
+ /// The document type for the comment.
+ /// The document number for the comment.
+ /// The document line number for the comment.
+ procedure CreateSalesCommentLine(var SalesCommentLine: Record "Sales Comment Line"; DocumentType: Enum "Sales Document Type"; No: Code[20]; DocumentLineNo: Integer)
+ var
+ RecRef: RecordRef;
+ begin
+ SalesCommentLine.Init();
+ SalesCommentLine.Validate("Document Type", DocumentType);
+ SalesCommentLine.Validate("No.", No);
+ SalesCommentLine.Validate("Document Line No.", DocumentLineNo);
+ RecRef.GetTable(SalesCommentLine);
+ SalesCommentLine.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, SalesCommentLine.FieldNo("Line No.")));
+ SalesCommentLine.Insert(true);
+ // Validate Comment as primary key to enable user to distinguish between comments because value is not important.
+ SalesCommentLine.Validate(
+ Comment, Format(SalesCommentLine."Document Type") + SalesCommentLine."No." +
+ Format(SalesCommentLine."Document Line No.") + Format(SalesCommentLine."Line No."));
+ SalesCommentLine.Modify(true);
+ end;
+
+ ///
+ /// Creates a sales price record.
+ ///
+ /// The sales price record to create.
+ /// The item number.
+ /// The sales type (Customer, Customer Price Group, All Customers, Campaign).
+ /// The sales code (customer number, price group code, etc.).
+ /// The starting date for the price.
+ /// The currency code.
+ /// The variant code.
+ /// The unit of measure code.
+ /// The minimum quantity.
+ /// The unit price.
+ procedure CreateSalesPrice(var SalesPrice: Record "Sales Price"; ItemNo: Code[20]; SalesType: Enum "Sales Price Type"; SalesCode: Code[20]; StartingDate: Date; CurrencyCode: Code[10]; VariantCode: Code[10]; UOMCode: Code[10]; MinQty: Decimal; UnitPrice: Decimal)
+ begin
+ Clear(SalesPrice);
+ SalesPrice.Validate("Item No.", ItemNo);
+ SalesPrice.Validate("Sales Type", SalesType);
+ SalesPrice.Validate("Sales Code", SalesCode);
+ SalesPrice.Validate("Starting Date", StartingDate);
+ SalesPrice.Validate("Currency Code", CurrencyCode);
+ SalesPrice.Validate("Variant Code", VariantCode);
+ SalesPrice.Validate("Unit of Measure Code", UOMCode);
+ SalesPrice.Validate("Minimum Quantity", MinQty);
+ SalesPrice.Insert(true);
+ SalesPrice.Validate("Unit Price", UnitPrice);
+ SalesPrice.Modify(true);
+
+ OnAfterCreateSalesPrice(SalesPrice, ItemNo, SalesType.AsInteger(), SalesCode, StartingDate, CurrencyCode, VariantCode, UOMCode, MinQty, UnitPrice);
+ end;
+
+ ///
+ /// Creates a ship-to address for a customer.
+ ///
+ /// The ship-to address record to create.
+ /// The customer number.
+ procedure CreateShipToAddress(var ShipToAddress: Record "Ship-to Address"; CustomerNo: Code[20])
+ begin
+ ShipToAddress.Init();
+ ShipToAddress.Validate("Customer No.", CustomerNo);
+ ShipToAddress.Validate(
+ Code,
+ CopyStr(
+ LibraryUtility.GenerateRandomCode(ShipToAddress.FieldNo(Code), DATABASE::"Ship-to Address"),
+ 1,
+ LibraryUtility.GetFieldLength(DATABASE::"Ship-to Address", ShipToAddress.FieldNo(Code))));
+ ShipToAddress.Insert(true);
+ end;
+
+ ///
+ /// Creates a ship-to address with a random country/region code.
+ ///
+ /// The ship-to address record to create.
+ /// The customer number.
+ procedure CreateShipToAddressWithRandomCountryCode(var ShipToAddress: Record "Ship-to Address"; CustomerNo: Code[20])
+ begin
+ CreateShipToAddress(ShipToAddress, CustomerNo);
+ ShipToAddress.Validate("Country/Region Code", LibraryERM.CreateCountryRegion());
+ ShipToAddress.Modify(true);
+ end;
+
+ ///
+ /// Creates a ship-to address with a specified country/region code.
+ ///
+ /// The ship-to address record to create.
+ /// The customer number.
+ /// The country/region code.
+ procedure CreateShipToAddressWithCountryCode(var ShipToAddress: Record "Ship-to Address"; CustomerNo: Code[20]; CountryCode: Code[10])
+ begin
+ CreateShipToAddress(ShipToAddress, CustomerNo);
+ ShipToAddress.Validate("Country/Region Code", CountryCode);
+ ShipToAddress.Modify(true);
+ end;
+
+ ///
+ /// Creates a standard sales code record.
+ ///
+ /// The standard sales code record to create.
+ procedure CreateStandardSalesCode(var StandardSalesCode: Record "Standard Sales Code")
+ begin
+ StandardSalesCode.Init();
+ StandardSalesCode.Validate(
+ Code,
+ CopyStr(
+ LibraryUtility.GenerateRandomCode(StandardSalesCode.FieldNo(Code), DATABASE::"Standard Sales Code"),
+ 1,
+ LibraryUtility.GetFieldLength(DATABASE::"Standard Sales Code", StandardSalesCode.FieldNo(Code))));
+ // Validating Description as Code because value is not important.
+ StandardSalesCode.Validate(Description, StandardSalesCode.Code);
+ StandardSalesCode.Insert(true);
+ end;
+
+ ///
+ /// Creates a standard sales line for a standard sales code.
+ ///
+ /// The standard sales line record to create.
+ /// The standard sales code.
+ procedure CreateStandardSalesLine(var StandardSalesLine: Record "Standard Sales Line"; StandardSalesCode: Code[10])
+ var
+ RecRef: RecordRef;
+ begin
+ StandardSalesLine.Init();
+ StandardSalesLine.Validate("Standard Sales Code", StandardSalesCode);
+ RecRef.GetTable(StandardSalesLine);
+ StandardSalesLine.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, StandardSalesLine.FieldNo("Line No.")));
+ StandardSalesLine.Insert(true);
+ end;
+
+ ///
+ /// Creates a standard customer sales code linking a customer to a standard sales code.
+ ///
+ /// The standard customer sales code record to create.
+ /// The customer number.
+ /// The standard sales code.
+ procedure CreateCustomerSalesCode(var StandardCustomerSalesCode: Record "Standard Customer Sales Code"; CustomerNo: Code[20]; "Code": Code[10])
+ begin
+ StandardCustomerSalesCode.Init();
+ StandardCustomerSalesCode.Validate("Customer No.", CustomerNo);
+ StandardCustomerSalesCode.Validate(Code, Code);
+ StandardCustomerSalesCode.Insert(true);
+ end;
+
+ ///
+ /// Creates a SEPA Direct Debit Mandate for a customer.
+ ///
+ /// The SEPA Direct Debit Mandate record to create.
+ /// The customer number.
+ /// The customer bank account code.
+ /// The valid from date.
+ /// The valid to date.
+ procedure CreateCustomerMandate(var SEPADirectDebitMandate: Record "SEPA Direct Debit Mandate"; CustomerNo: Code[20]; CustomerBankCode: Code[20]; FromDate: Date; ToDate: Date)
+ begin
+ SEPADirectDebitMandate.Init();
+ SEPADirectDebitMandate.Validate("Customer No.", CustomerNo);
+ SEPADirectDebitMandate.Validate("Customer Bank Account Code", CustomerBankCode);
+ SEPADirectDebitMandate.Validate("Valid From", FromDate);
+ SEPADirectDebitMandate.Validate("Valid To", ToDate);
+ SEPADirectDebitMandate.Validate("Date of Signature", FromDate);
+ SEPADirectDebitMandate.Insert(true);
+ end;
+
+ ///
+ /// Creates a standard text record.
+ ///
+ /// The standard text record to create.
+ /// The code of the created standard text.
+ procedure CreateStandardText(var StandardText: Record "Standard Text"): Code[20]
+ begin
+ StandardText.Init();
+ StandardText.Code := LibraryUtility.GenerateRandomCode(StandardText.FieldNo(Code), DATABASE::"Standard Text");
+ StandardText.Description := LibraryUtility.GenerateGUID();
+ StandardText.Insert();
+ exit(StandardText.Code);
+ end;
+
+ ///
+ /// Creates a standard text record with extended text.
+ ///
+ /// The standard text record to create.
+ /// The extended text associated with the standard text.
+ /// The code of the created standard text.
+ procedure CreateStandardTextWithExtendedText(var StandardText: Record "Standard Text"; var ExtendedText: Text): Code[20]
+ var
+ ExtendedTextHeader: Record "Extended Text Header";
+ ExtendedTextLine: Record "Extended Text Line";
+ begin
+ StandardText.Init();
+ StandardText.Code := LibraryUtility.GenerateRandomCode(StandardText.FieldNo(Code), DATABASE::"Standard Text");
+ StandardText.Description := LibraryUtility.GenerateGUID();
+ StandardText.Insert();
+ LibrarySmallBusiness.CreateExtendedTextHeader(
+ ExtendedTextHeader, ExtendedTextHeader."Table Name"::"Standard Text", StandardText.Code);
+ LibrarySmallBusiness.CreateExtendedTextLine(ExtendedTextLine, ExtendedTextHeader);
+ ExtendedText := ExtendedTextLine.Text;
+ exit(StandardText.Code);
+ end;
+
+ ///
+ /// Creates a custom report selection for a customer.
+ ///
+ /// The customer number.
+ /// The report selection usage.
+ /// The report ID.
+ /// The custom report layout code.
+ /// The email address for sending the report.
+ procedure CreateCustomerDocumentLayout(CustomerNo: Code[20]; UsageValue: Enum "Report Selection Usage"; ReportID: Integer; CustomReportLayoutCode: Code[20]; EmailAddress: Text)
+ var
+ CustomReportSelection: Record "Custom Report Selection";
+ begin
+ CustomReportSelection.Init();
+ CustomReportSelection.Validate("Source Type", DATABASE::Customer);
+ CustomReportSelection.Validate("Source No.", CustomerNo);
+ CustomReportSelection.Validate(Usage, UsageValue);
+ CustomReportSelection.Validate("Report ID", ReportID);
+ CustomReportSelection.Validate("Custom Report Layout Code", CustomReportLayoutCode);
+ CustomReportSelection.Validate("Send To Email", CopyStr(EmailAddress, 1, MaxStrLen(CustomReportSelection."Send To Email")));
+ CustomReportSelection.Insert();
+ end;
+
+ ///
+ /// Combines return receipts into a credit memo using the Combine Return Receipts report.
+ ///
+ /// The sales header to use for the credit memo.
+ /// The return receipt header to combine.
+ /// The posting date for the credit memo.
+ /// The document date for the credit memo.
+ /// Whether to calculate invoice discount.
+ /// Whether to post the credit memos.
+ procedure CombineReturnReceipts(var SalesHeader: Record "Sales Header"; var ReturnReceiptHeader: Record "Return Receipt Header"; PostingDate: Date; DocDate: Date; CalcInvDiscount: Boolean; PostCreditMemos: Boolean)
+ var
+ TmpSalesHeader: Record "Sales Header";
+ TmpReturnReceiptHeader: Record "Return Receipt Header";
+ CombineReturnReceiptsReport: Report "Combine Return Receipts";
+ begin
+ CombineReturnReceiptsReport.InitializeRequest(PostingDate, DocDate, CalcInvDiscount, PostCreditMemos);
+ if SalesHeader.HasFilter then
+ TmpSalesHeader.CopyFilters(SalesHeader)
+ else begin
+ SalesHeader.Get(SalesHeader."Document Type", SalesHeader."No.");
+ TmpSalesHeader.SetRange("Document Type", SalesHeader."Document Type");
+ TmpSalesHeader.SetRange("No.", SalesHeader."No.");
+ end;
+ CombineReturnReceiptsReport.SetTableView(TmpSalesHeader);
+ if ReturnReceiptHeader.HasFilter then
+ TmpReturnReceiptHeader.CopyFilters(ReturnReceiptHeader)
+ else begin
+ ReturnReceiptHeader.Get(ReturnReceiptHeader."No.");
+ TmpReturnReceiptHeader.SetRange("No.", ReturnReceiptHeader."No.");
+ end;
+ CombineReturnReceiptsReport.SetTableView(TmpReturnReceiptHeader);
+ CombineReturnReceiptsReport.UseRequestPage(false);
+ CombineReturnReceiptsReport.RunModal();
+ end;
+
+ ///
+ /// Combines sales shipments into an invoice using the Combine Shipments report.
+ ///
+ /// The sales header to use for the invoice.
+ /// The sales shipment header to combine.
+ /// The posting date for the invoice.
+ /// The document date for the invoice.
+ /// Whether to calculate invoice discount.
+ /// Whether to post the invoices.
+ /// Whether to include only standard payment terms.
+ /// Whether to copy text lines.
+ procedure CombineShipments(var SalesHeader: Record "Sales Header"; var SalesShipmentHeader: Record "Sales Shipment Header"; PostingDate: Date; DocumentDate: Date; CalcInvDisc: Boolean; PostInvoices: Boolean; OnlyStdPmtTerms: Boolean; CopyTextLines: Boolean)
+ var
+ TmpSalesHeader: Record "Sales Header";
+ TmpSalesShipmentHeader: Record "Sales Shipment Header";
+ CombineShipmentsReport: Report "Combine Shipments";
+ begin
+ CombineShipmentsReport.InitializeRequest(PostingDate, DocumentDate, CalcInvDisc, PostInvoices, OnlyStdPmtTerms, CopyTextLines);
+ if SalesHeader.HasFilter then
+ TmpSalesHeader.CopyFilters(SalesHeader)
+ else begin
+ SalesHeader.Get(SalesHeader."Document Type", SalesHeader."No.");
+ TmpSalesHeader.SetRange("Document Type", SalesHeader."Document Type");
+ TmpSalesHeader.SetRange("No.", SalesHeader."No.");
+ end;
+ CombineShipmentsReport.SetTableView(TmpSalesHeader);
+ if SalesShipmentHeader.HasFilter then
+ TmpSalesShipmentHeader.CopyFilters(SalesShipmentHeader)
+ else begin
+ SalesShipmentHeader.Get(SalesShipmentHeader."No.");
+ TmpSalesShipmentHeader.SetRange("No.", SalesShipmentHeader."No.");
+ end;
+ CombineShipmentsReport.SetTableView(TmpSalesShipmentHeader);
+ CombineShipmentsReport.UseRequestPage(false);
+ CombineShipmentsReport.RunModal();
+ end;
+
+ ///
+ /// Deletes invoiced sales orders using the Delete Invoiced Sales Orders report.
+ ///
+ /// The sales header to delete.
+ procedure DeleteInvoicedSalesOrders(var SalesHeader: Record "Sales Header")
+ var
+ TmpSalesHeader: Record "Sales Header";
+ DeleteInvoicedSalesOrdersReport: Report "Delete Invoiced Sales Orders";
+ begin
+ if SalesHeader.HasFilter then
+ TmpSalesHeader.CopyFilters(SalesHeader)
+ else begin
+ SalesHeader.Get(SalesHeader."Document Type", SalesHeader."No.");
+ TmpSalesHeader.SetRange("Document Type", SalesHeader."Document Type");
+ TmpSalesHeader.SetRange("No.", SalesHeader."No.");
+ end;
+ DeleteInvoicedSalesOrdersReport.SetTableView(TmpSalesHeader);
+ DeleteInvoicedSalesOrdersReport.UseRequestPage(false);
+ DeleteInvoicedSalesOrdersReport.RunModal();
+ end;
+
+ ///
+ /// Deletes invoiced sales return orders using the Delete Invd Sales Ret. Orders report.
+ ///
+ /// The sales header to delete.
+ procedure DeleteInvoicedSalesReturnOrders(var SalesHeader: Record "Sales Header")
+ var
+ TmpSalesHeader: Record "Sales Header";
+ DeleteInvdSalesRetOrders: Report "Delete Invd Sales Ret. Orders";
+ begin
+ if SalesHeader.HasFilter then
+ TmpSalesHeader.CopyFilters(SalesHeader)
+ else begin
+ SalesHeader.Get(SalesHeader."Document Type", SalesHeader."No.");
+ TmpSalesHeader.SetRange("Document Type", SalesHeader."Document Type");
+ TmpSalesHeader.SetRange("No.", SalesHeader."No.");
+ end;
+ DeleteInvdSalesRetOrders.SetTableView(TmpSalesHeader);
+ DeleteInvdSalesRetOrders.UseRequestPage(false);
+ DeleteInvdSalesRetOrders.RunModal();
+ end;
+
+ ///
+ /// Explodes a BOM (Bill of Materials) on a sales line.
+ ///
+ /// The sales line containing the BOM item to explode.
+ procedure ExplodeBOM(var SalesLine: Record "Sales Line")
+ var
+ SalesExplodeBOM: Codeunit "Sales-Explode BOM";
+ begin
+ Clear(SalesExplodeBOM);
+ SalesExplodeBOM.Run(SalesLine);
+ end;
+
+ ///
+ /// Finds or creates a customer posting group.
+ ///
+ /// The code of the customer posting group.
+ procedure FindCustomerPostingGroup(): Code[20]
+ var
+ CustomerPostingGroup: Record "Customer Posting Group";
+ begin
+ if not CustomerPostingGroup.FindFirst() then
+ CreateCustomerPostingGroup(CustomerPostingGroup);
+ exit(CustomerPostingGroup.Code);
+ end;
+
+ ///
+ /// Finds the first sales line for a given sales header.
+ ///
+ /// The sales line record to find.
+ /// The sales header to find the line for.
+ procedure FindFirstSalesLine(var SalesLine: Record "Sales Line"; SalesHeader: Record "Sales Header")
+ begin
+ SalesLine.SetRange("Document Type", SalesHeader."Document Type");
+ SalesLine.SetRange("Document No.", SalesHeader."No.");
+ SalesLine.FindFirst();
+ end;
+
+ ///
+ /// Finds an item that meets basic criteria for testing (not blocked, has posting groups, no item tracking).
+ ///
+ /// The item record to find.
+ procedure FindItem(var Item: Record Item)
+ begin
+ // Filter Item so that errors are not generated due to mandatory fields or Item Tracking.
+ Item.SetFilter("Inventory Posting Group", '<>''''');
+ Item.SetFilter("Gen. Prod. Posting Group", '<>''''');
+ Item.SetRange("Item Tracking Code", '');
+ Item.SetRange(Blocked, false);
+ Item.SetFilter("Unit Price", '<>0');
+ Item.SetFilter(Reserve, '<>%1', Item.Reserve::Always);
+
+ Item.FindSet();
+ end;
+
+ ///
+ /// Gets the invoice rounding account from a customer posting group.
+ ///
+ /// The customer posting group code.
+ /// The invoice rounding account code.
+ procedure GetInvRoundingAccountOfCustPostGroup(CustPostingGroupCode: Code[20]): Code[20]
+ var
+ CustPostingGroup: Record "Customer Posting Group";
+ begin
+ CustPostingGroup.Get(CustPostingGroupCode);
+ exit(CustPostingGroup."Invoice Rounding Account");
+ end;
+
+ ///
+ /// Gets return receipt lines for a sales line using the Sales-Get Return Receipts function.
+ ///
+ /// The sales line to get return receipt lines for.
+ procedure GetReturnReceiptLines(var SalesLine: Record "Sales Line")
+ var
+ SalesGetReturnReceipts: Codeunit "Sales-Get Return Receipts";
+ begin
+ SalesGetReturnReceipts.Run(SalesLine);
+ end;
+
+ ///
+ /// Gets shipment lines for a sales line using the Sales-Get Shipment function.
+ ///
+ /// The sales line to get shipment lines for.
+ procedure GetShipmentLines(var SalesLine: Record "Sales Line")
+ var
+ SalesGetShipment: Codeunit "Sales-Get Shipment";
+ begin
+ Clear(SalesGetShipment);
+ SalesGetShipment.Run(SalesLine);
+ end;
+
+ ///
+ /// Posts a sales order with full quantities.
+ ///
+ /// The sales header to post.
+ /// The item for the sales line.
+ /// The location code.
+ /// The variant code.
+ /// The quantity.
+ /// The posting date.
+ /// The unit cost.
+ /// Whether to ship.
+ /// Whether to invoice.
+ procedure PostSalesOrder(var SalesHeader: Record "Sales Header"; Item: Record Item; LocationCode: Code[10]; VariantCode: Code[10]; Qty: Decimal; PostingDate: Date; UnitCost: Decimal; Ship: Boolean; Invoice: Boolean)
+ begin
+ PostSalesOrderPartially(SalesHeader, Item, LocationCode, VariantCode, Qty, PostingDate, UnitCost, Ship, Qty, Invoice, Qty);
+ end;
+
+ ///
+ /// Posts a sales order with specified partial quantities.
+ ///
+ /// The sales header to post.
+ /// The item for the sales line.
+ /// The location code.
+ /// The variant code.
+ /// The quantity.
+ /// The posting date.
+ /// The unit cost.
+ /// Whether to ship.
+ /// The quantity to ship.
+ /// Whether to invoice.
+ /// The quantity to invoice.
+ procedure PostSalesOrderPartially(var SalesHeader: Record "Sales Header"; Item: Record Item; LocationCode: Code[10]; VariantCode: Code[10]; Qty: Decimal; PostingDate: Date; UnitCost: Decimal; Ship: Boolean; ShipQty: Decimal; Invoice: Boolean; InvoiceQty: Decimal)
+ var
+ SalesLine: Record "Sales Line";
+ begin
+ CreateSalesOrder(SalesHeader, SalesLine, Item, LocationCode, VariantCode, Qty, PostingDate, UnitCost);
+ SalesLine.Validate("Qty. to Ship", ShipQty);
+ SalesLine.Validate("Qty. to Invoice", InvoiceQty);
+ SalesLine.Modify();
+ PostSalesDocument(SalesHeader, Ship, Invoice);
+ end;
+
+ ///
+ /// Posts a sales line by posting its parent sales document.
+ ///
+ /// The sales line to post.
+ /// Whether to ship.
+ /// Whether to invoice.
+ procedure PostSalesLine(SalesLine: Record "Sales Line"; Ship: Boolean; Invoice: Boolean)
+ var
+ SalesHeader: Record "Sales Header";
+ begin
+ SalesHeader.Get(SalesLine."Document Type", SalesLine."Document No.");
+ PostSalesDocument(SalesHeader, Ship, Invoice);
+ end;
+
+ ///
+ /// Posts a sales document.
+ ///
+ /// The sales header to post.
+ /// Whether to ship/receive.
+ /// Whether to invoice.
+ /// The document number of the posted document.
+ procedure PostSalesDocument(var SalesHeader: Record "Sales Header"; NewShipReceive: Boolean; NewInvoice: Boolean): Code[20]
+ begin
+ exit(DoPostSalesDocument(SalesHeader, NewShipReceive, NewInvoice, false));
+ end;
+
+ ///
+ /// Posts a sales document and sends it via email.
+ ///
+ /// The sales header to post.
+ /// Whether to ship/receive.
+ /// Whether to invoice.
+ /// The document number of the posted document.
+ procedure PostSalesDocumentAndEmail(var SalesHeader: Record "Sales Header"; NewShipReceive: Boolean; NewInvoice: Boolean): Code[20]
+ begin
+ exit(DoPostSalesDocument(SalesHeader, NewShipReceive, NewInvoice, true));
+ end;
+
+ local procedure DoPostSalesDocument(var SalesHeader: Record "Sales Header"; NewShipReceive: Boolean; NewInvoice: Boolean; AfterPostSalesDocumentSendAsEmail: Boolean) DocumentNo: Code[20]
+ var
+ SalesPost: Codeunit "Sales-Post";
+ SalesPostPrint: Codeunit "Sales-Post + Print";
+ Assert: Codeunit Assert;
+ NoSeries: Codeunit "No. Series";
+ RecRef: RecordRef;
+ FieldRef: FieldRef;
+ DocumentFieldNo: Integer;
+ begin
+ OnBeforePostSalesDocument(SalesHeader, NewShipReceive, NewInvoice, AfterPostSalesDocumentSendAsEmail);
+
+ // Taking name as NewInvoice to avoid conflict with table field name.
+ // Post the sales document.
+ // Depending on the document type and posting type return the number of the:
+ // - sales shipment,
+ // - posted sales invoice,
+ // - sales return receipt, or
+ // - posted credit memo
+ SalesHeader.Validate(Ship, NewShipReceive);
+ SalesHeader.Validate(Receive, NewShipReceive);
+ SalesHeader.Validate(Invoice, NewInvoice);
+ SalesPost.SetPostingFlags(SalesHeader);
+
+ case SalesHeader."Document Type" of
+ SalesHeader."Document Type"::Invoice, SalesHeader."Document Type"::"Credit Memo":
+ if SalesHeader.Invoice and (SalesHeader."Posting No. Series" <> '') then begin
+ if (SalesHeader."Posting No." = '') then
+ SalesHeader."Posting No." := NoSeries.GetNextNo(SalesHeader."Posting No. Series", LibraryUtility.GetNextNoSeriesSalesDate(SalesHeader."Posting No. Series"));
+ DocumentFieldNo := SalesHeader.FieldNo("Last Posting No.");
+ end;
+ SalesHeader."Document Type"::Order:
+ begin
+ if SalesHeader.Ship and (SalesHeader."Shipping No. Series" <> '') then begin
+ if (SalesHeader."Shipping No." = '') then
+ SalesHeader."Shipping No." := NoSeries.GetNextNo(SalesHeader."Shipping No. Series", LibraryUtility.GetNextNoSeriesSalesDate(SalesHeader."Shipping No. Series"));
+ DocumentFieldNo := SalesHeader.FieldNo("Last Shipping No.");
+ end;
+ if SalesHeader.Invoice and (SalesHeader."Posting No. Series" <> '') then begin
+ if (SalesHeader."Posting No." = '') then
+ SalesHeader."Posting No." := NoSeries.GetNextNo(SalesHeader."Posting No. Series", LibraryUtility.GetNextNoSeriesSalesDate(SalesHeader."Posting No. Series"));
+ DocumentFieldNo := SalesHeader.FieldNo("Last Posting No.");
+ end;
+ end;
+ SalesHeader."Document Type"::"Return Order":
+ begin
+ if SalesHeader.Receive and (SalesHeader."Return Receipt No. Series" <> '') then begin
+ if (SalesHeader."Return Receipt No." = '') then
+ SalesHeader."Return Receipt No." := NoSeries.GetNextNo(SalesHeader."Return Receipt No. Series", LibraryUtility.GetNextNoSeriesSalesDate(SalesHeader."Return Receipt No. Series"));
+ DocumentFieldNo := SalesHeader.FieldNo("Last Return Receipt No.");
+ end;
+ if SalesHeader.Invoice and (SalesHeader."Posting No. Series" <> '') then begin
+ if (SalesHeader."Posting No." = '') then
+ SalesHeader."Posting No." := NoSeries.GetNextNo(SalesHeader."Posting No. Series", LibraryUtility.GetNextNoSeriesSalesDate(SalesHeader."Posting No. Series"));
+ DocumentFieldNo := SalesHeader.FieldNo("Last Posting No.");
+ end;
+ end;
+ else
+ Assert.Fail(StrSubstNo(WrongDocumentTypeErr, SalesHeader."Document Type"));
+ end;
+
+ if AfterPostSalesDocumentSendAsEmail then
+ SalesPostPrint.PostAndEmail(SalesHeader)
+ else
+ SalesPost.Run(SalesHeader);
+
+ RecRef.GetTable(SalesHeader);
+ FieldRef := RecRef.Field(DocumentFieldNo);
+ DocumentNo := FieldRef.Value();
+ end;
+
+ ///
+ /// Posts a sales prepayment credit memo.
+ ///
+ /// The sales header to post.
+ procedure PostSalesPrepaymentCrMemo(var SalesHeader: Record "Sales Header")
+ var
+ SalesPostPrepayments: Codeunit "Sales-Post Prepayments";
+ begin
+ SalesPostPrepayments.CreditMemo(SalesHeader);
+ end;
+
+ ///
+ /// Posts a sales prepayment credit memo and returns the document number.
+ ///
+ /// The sales header to post.
+ /// The document number of the posted prepayment credit memo.
+ procedure PostSalesPrepaymentCreditMemo(var SalesHeader: Record "Sales Header") DocumentNo: Code[20]
+ var
+ SalesPostPrepayments: Codeunit "Sales-Post Prepayments";
+ NoSeries: Codeunit "No. Series";
+ NoSeriesCode: Code[20];
+ begin
+ NoSeriesCode := SalesHeader."Prepmt. Cr. Memo No. Series";
+ if SalesHeader."Prepmt. Cr. Memo No." = '' then
+ DocumentNo := NoSeries.PeekNextNo(NoSeriesCode, LibraryUtility.GetNextNoSeriesSalesDate(NoSeriesCode))
+ else
+ DocumentNo := SalesHeader."Prepmt. Cr. Memo No.";
+ SalesPostPrepayments.CreditMemo(SalesHeader);
+ end;
+
+ ///
+ /// Posts a sales prepayment invoice and returns the document number.
+ ///
+ /// The sales header to post.
+ /// The document number of the posted prepayment invoice.
+ procedure PostSalesPrepaymentInvoice(var SalesHeader: Record "Sales Header") DocumentNo: Code[20]
+ var
+ SalesPostPrepayments: Codeunit "Sales-Post Prepayments";
+ NoSeries: Codeunit "No. Series";
+ NoSeriesCode: Code[20];
+ begin
+ NoSeriesCode := SalesHeader."Prepayment No. Series";
+ if SalesHeader."Prepayment No." = '' then
+ DocumentNo := NoSeries.PeekNextNo(NoSeriesCode, LibraryUtility.GetNextNoSeriesSalesDate(NoSeriesCode))
+ else
+ DocumentNo := SalesHeader."Prepayment No.";
+ SalesPostPrepayments.Invoice(SalesHeader);
+ end;
+
+ ///
+ /// Converts a sales quote to a sales order.
+ ///
+ /// The sales quote header to convert.
+ /// The number of the created sales order.
+ procedure QuoteMakeOrder(var SalesHeader: Record "Sales Header"): Code[20]
+ var
+ SalesOrderHeader: Record "Sales Header";
+ SalesQuoteToOrder: Codeunit "Sales-Quote to Order";
+ begin
+ Clear(SalesQuoteToOrder);
+ SalesQuoteToOrder.Run(SalesHeader);
+ SalesQuoteToOrder.GetSalesOrderHeader(SalesOrderHeader);
+ exit(SalesOrderHeader."No.");
+ end;
+
+ ///
+ /// Releases a sales document.
+ ///
+ /// The sales header to release.
+ procedure ReleaseSalesDocument(var SalesHeader: Record "Sales Header")
+ var
+ ReleaseSalesDoc: Codeunit "Release Sales Document";
+ begin
+ ReleaseSalesDoc.PerformManualRelease(SalesHeader);
+ end;
+
+ ///
+ /// Reopens a released sales document.
+ ///
+ /// The sales header to reopen.
+ procedure ReopenSalesDocument(var SalesHeader: Record "Sales Header")
+ var
+ ReleaseSalesDoc: Codeunit "Release Sales Document";
+ begin
+ ReleaseSalesDoc.PerformManualReopen(SalesHeader);
+ end;
+
+ ///
+ /// Calculates sales discount for a sales document.
+ ///
+ /// The sales header to calculate discount for.
+ procedure CalcSalesDiscount(SalesHeader: Record "Sales Header")
+ var
+ SalesLine: Record "Sales Line";
+ begin
+ SalesLine."Document Type" := SalesHeader."Document Type";
+ SalesLine."Document No." := SalesHeader."No.";
+ CODEUNIT.Run(CODEUNIT::"Sales-Calc. Discount", SalesLine);
+ end;
+
+ ///
+ /// Sets the Allow VAT Difference option in Sales and Receivables Setup.
+ ///
+ /// Whether to allow VAT difference.
+ procedure SetAllowVATDifference(AllowVATDifference: Boolean)
+ begin
+ SalesReceivablesSetup.Get();
+ SalesReceivablesSetup.Validate("Allow VAT Difference", AllowVATDifference);
+ SalesReceivablesSetup.Modify(true);
+ end;
+
+ ///
+ /// Sets the Allow Document Deletion Before date in Sales and Receivables Setup.
+ ///
+ /// The date before which documents can be deleted.
+ procedure SetAllowDocumentDeletionBeforeDate(Date: Date)
+ begin
+ SalesReceivablesSetup.Get();
+ SalesReceivablesSetup.Validate("Allow Document Deletion Before", Date);
+ SalesReceivablesSetup.Modify(true);
+ end;
+
+ ///
+ /// Sets the Application between Currencies option in Sales and Receivables Setup.
+ ///
+ /// The application between currencies option.
+ procedure SetApplnBetweenCurrencies(ApplnBetweenCurrencies: Option)
+ begin
+ SalesReceivablesSetup.Get();
+ SalesReceivablesSetup.Validate("Appln. between Currencies", ApplnBetweenCurrencies);
+ SalesReceivablesSetup.Modify(true);
+ end;
+
+#if not CLEAN27
+ [Obsolete('Discontinued functionality', '27.0')]
+ procedure SetCreateItemFromItemNo(NewValue: Boolean)
+ begin
+ SalesReceivablesSetup.Get();
+ SalesReceivablesSetup.Validate("Create Item from Item No.", NewValue);
+ SalesReceivablesSetup.Modify(true);
+ end;
+#endif
+ ///
+ /// Sets the Create Item from Description option in Sales and Receivables Setup.
+ ///
+ /// Whether to create items from description.
+ procedure SetCreateItemFromDescription(NewValue: Boolean)
+ begin
+ SalesReceivablesSetup.Get();
+ SalesReceivablesSetup.Validate("Create Item from Description", NewValue);
+ SalesReceivablesSetup.Modify(true);
+ end;
+
+ ///
+ /// Sets the Discount Posting option in Sales and Receivables Setup.
+ ///
+ /// The discount posting option.
+ procedure SetDiscountPosting(DiscountPosting: Option)
+ begin
+ SalesReceivablesSetup.Get();
+ SalesReceivablesSetup.Validate("Discount Posting", DiscountPosting);
+ SalesReceivablesSetup.Modify(true);
+ end;
+
+ ///
+ /// Sets the Discount Posting option in Sales and Receivables Setup silently.
+ ///
+ /// The discount posting option.
+ procedure SetDiscountPostingSilent(DiscountPosting: Option)
+ begin
+ SalesReceivablesSetup.Get();
+ SalesReceivablesSetup."Discount Posting" := DiscountPosting;
+ SalesReceivablesSetup.Modify();
+ end;
+
+ ///
+ /// Sets the Calc. Invoice Discount option in Sales and Receivables Setup.
+ ///
+ /// Whether to calculate invoice discount automatically.
+ procedure SetCalcInvDiscount(CalcInvDiscount: Boolean)
+ begin
+ SalesReceivablesSetup.Get();
+ SalesReceivablesSetup.Validate("Calc. Inv. Discount", CalcInvDiscount);
+ SalesReceivablesSetup.Modify(true);
+ end;
+
+ ///
+ /// Sets the Credit Warnings option in Sales and Receivables Setup.
+ ///
+ /// The credit warnings option.
+ procedure SetCreditWarnings(CreditWarnings: Option)
+ begin
+ SalesReceivablesSetup.Get();
+ SalesReceivablesSetup.Validate("Credit Warnings", CreditWarnings);
+ SalesReceivablesSetup.Modify(true);
+ end;
+
+ ///
+ /// Sets the Credit Warnings option to No Warnings in Sales and Receivables Setup.
+ ///
+ procedure SetCreditWarningsToNoWarnings()
+ begin
+ SalesReceivablesSetup.Get();
+ SalesReceivablesSetup.Validate("Credit Warnings", SalesReceivablesSetup."Credit Warnings"::"No Warning");
+ SalesReceivablesSetup.Modify(true);
+ end;
+
+ ///
+ /// Sets the Exact Cost Reversing Mandatory option in Sales and Receivables Setup.
+ ///
+ /// Whether exact cost reversing is mandatory.
+ procedure SetExactCostReversingMandatory(ExactCostReversingMandatory: Boolean)
+ begin
+ SalesReceivablesSetup.Get();
+ SalesReceivablesSetup.Validate("Exact Cost Reversing Mandatory", ExactCostReversingMandatory);
+ SalesReceivablesSetup.Modify(true);
+ end;
+
+ ///
+ /// Sets the Freight G/L Account No. in Sales and Receivables Setup.
+ ///
+ /// The G/L account number for freight.
+ procedure SetGLFreightAccountNo(GLFreightAccountNo: Code[20])
+ begin
+ SalesReceivablesSetup.Get();
+ SalesReceivablesSetup.Validate("Freight G/L Acc. No.", GLFreightAccountNo);
+ SalesReceivablesSetup.Modify(true);
+ end;
+
+ ///
+ /// Sets the Invoice Rounding option in Sales and Receivables Setup.
+ ///
+ /// Whether invoice rounding is enabled.
+ procedure SetInvoiceRounding(InvoiceRounding: Boolean)
+ begin
+ SalesReceivablesSetup.Get();
+ SalesReceivablesSetup.Validate("Invoice Rounding", InvoiceRounding);
+ SalesReceivablesSetup.Modify(true);
+ end;
+
+ ///
+ /// Sets the Stockout Warning option in Sales and Receivables Setup.
+ ///
+ /// Whether stockout warning is enabled.
+ procedure SetStockoutWarning(StockoutWarning: Boolean)
+ begin
+ SalesReceivablesSetup.Get();
+ SalesReceivablesSetup.Validate("Stockout Warning", StockoutWarning);
+ SalesReceivablesSetup.Modify(true);
+ end;
+
+ ///
+ /// Sets the Prevent Negative Inventory option in Inventory Setup.
+ ///
+ /// Whether to prevent negative inventory.
+ procedure SetPreventNegativeInventory(PreventNegativeInventory: Boolean)
+ var
+ InventorySetup: Record "Inventory Setup";
+ begin
+ InventorySetup.Get();
+ InventorySetup.Validate("Prevent Negative Inventory", PreventNegativeInventory);
+ InventorySetup.Modify(true);
+ end;
+
+ ///
+ /// Sets the Archive Quotes option to Always in Sales and Receivables Setup.
+ ///
+ procedure SetArchiveQuoteAlways()
+ begin
+ SalesReceivablesSetup.Get();
+ SalesReceivablesSetup.Validate("Archive Quotes", SalesReceivablesSetup."Archive Quotes"::Always);
+ SalesReceivablesSetup.Modify(true);
+ end;
+
+ ///
+ /// Sets the Archive Orders option in Sales and Receivables Setup.
+ ///
+ /// Whether to archive orders.
+ procedure SetArchiveOrders(ArchiveOrders: Boolean)
+ begin
+ SalesReceivablesSetup.Get();
+ SalesReceivablesSetup.Validate("Archive Orders", ArchiveOrders);
+ SalesReceivablesSetup.Modify(true);
+ end;
+
+ ///
+ /// Sets the Archive Blanket Orders option in Sales and Receivables Setup.
+ ///
+ /// Whether to archive blanket orders.
+ procedure SetArchiveBlanketOrders(ArchiveBlanketOrders: Boolean)
+ begin
+ SalesReceivablesSetup.Get();
+ SalesReceivablesSetup.Validate("Archive Blanket Orders", ArchiveBlanketOrders);
+ SalesReceivablesSetup.Modify(true);
+ end;
+
+ ///
+ /// Sets the Archive Return Orders option in Sales and Receivables Setup.
+ ///
+ /// Whether to archive return orders.
+ procedure SetArchiveReturnOrders(ArchiveReturnOrders: Boolean)
+ begin
+ SalesReceivablesSetup.Get();
+ SalesReceivablesSetup.Validate("Archive Return Orders", ArchiveReturnOrders);
+ SalesReceivablesSetup.Modify(true);
+ end;
+
+ ///
+ /// Sets the External Document No. Mandatory option in Sales and Receivables Setup.
+ ///
+ /// Whether external document number is mandatory.
+ procedure SetExtDocNo(ExtDocNoMandatory: Boolean)
+ begin
+ SalesReceivablesSetup.Get();
+ SalesReceivablesSetup.Validate("Ext. Doc. No. Mandatory", ExtDocNoMandatory);
+ SalesReceivablesSetup.Modify(true);
+ end;
+
+ ///
+ /// Sets the Post with Job Queue option in Sales and Receivables Setup.
+ ///
+ /// Whether to post with job queue.
+ procedure SetPostWithJobQueue(PostWithJobQueue: Boolean)
+ begin
+ SalesReceivablesSetup.Get();
+ SalesReceivablesSetup.Validate("Post with Job Queue", PostWithJobQueue);
+ SalesReceivablesSetup.Modify(true);
+ end;
+
+ ///
+ /// Sets the Post and Print with Job Queue option in Sales and Receivables Setup.
+ ///
+ /// Whether to post and print with job queue.
+ procedure SetPostAndPrintWithJobQueue(PostAndPrintWithJobQueue: Boolean)
+ begin
+ SalesReceivablesSetup.Get();
+ SalesReceivablesSetup.Validate("Post & Print with Job Queue", PostAndPrintWithJobQueue);
+ SalesReceivablesSetup.Modify(true);
+ end;
+
+ ///
+ /// Sets a new Order Nos. series in Sales and Receivables Setup.
+ ///
+ procedure SetOrderNoSeriesInSetup()
+ begin
+ SalesReceivablesSetup.Get();
+ SalesReceivablesSetup.Validate("Order Nos.", LibraryERM.CreateNoSeriesCode());
+ SalesReceivablesSetup.Modify();
+ end;
+
+ ///
+ /// Sets new Posted Invoice, Shipment, and Credit Memo number series in Sales and Receivables Setup.
+ ///
+ procedure SetPostedNoSeriesInSetup()
+ begin
+ SalesReceivablesSetup.Get();
+ SalesReceivablesSetup.Validate("Posted Invoice Nos.", LibraryERM.CreateNoSeriesCode());
+ SalesReceivablesSetup.Validate("Posted Shipment Nos.", LibraryERM.CreateNoSeriesCode());
+ SalesReceivablesSetup.Validate("Posted Credit Memo Nos.", LibraryERM.CreateNoSeriesCode());
+ SalesReceivablesSetup.Modify();
+ end;
+
+ ///
+ /// Sets new Return Order and Posted Return Receipt number series in Sales and Receivables Setup.
+ ///
+ procedure SetReturnOrderNoSeriesInSetup()
+ begin
+ SalesReceivablesSetup.Get();
+ SalesReceivablesSetup.Validate("Return Order Nos.", LibraryERM.CreateNoSeriesCode());
+ SalesReceivablesSetup.Validate("Posted Return Receipt Nos.", LibraryERM.CreateNoSeriesCode());
+ SalesReceivablesSetup.Modify();
+ end;
+
+ ///
+ /// Sets the Copy Comments Order to Invoice option in Sales and Receivables Setup.
+ ///
+ /// Whether to copy comments from order to invoice.
+ procedure SetCopyCommentsOrderToInvoiceInSetup(CopyCommentsOrderToInvoice: Boolean)
+ begin
+ SalesReceivablesSetup.Get();
+ SalesReceivablesSetup.Validate("Copy Comments Order to Invoice", CopyCommentsOrderToInvoice);
+ SalesReceivablesSetup.Modify(true);
+ end;
+
+ ///
+ /// Modifies a posted sales invoice header with random values for payment and shipping fields.
+ ///
+ /// The posted sales invoice header to modify.
+ procedure ModifySalesInvoiceHeader(var SalesInvoiceHeader: Record "Sales Invoice Header")
+ var
+ BankAccount: Record "Bank Account";
+ PaymentMethod: Record "Payment Method";
+ ShippingAgent: Record "Shipping Agent";
+ begin
+ LibraryERM.CreatePaymentMethod(PaymentMethod);
+ LibraryInventory.CreateShippingAgent(ShippingAgent);
+ LibraryERM.CreateBankAccount(BankAccount);
+ BankAccount."Currency Code" := SalesInvoiceHeader."Currency Code";
+ BankAccount.Modify();
+
+ SalesInvoiceHeader."Payment Method Code" := PaymentMethod.Code;
+ SalesInvoiceHeader."Payment Reference" := LibraryRandom.RandText(MaxStrLen(SalesInvoiceHeader."Payment Reference")).ToUpper();
+ SalesInvoiceHeader."Company Bank Account Code" := BankAccount."No.";
+ SalesInvoiceHeader."Posting Description" := LibraryRandom.RandText(MaxStrLen(SalesInvoiceHeader."Posting Description"));
+ SalesInvoiceHeader."Shipping Agent Code" := ShippingAgent.Code;
+ SalesInvoiceHeader."Package Tracking No." := LibraryRandom.RandText(MaxStrLen(SalesInvoiceHeader."Package Tracking No."));
+ SalesInvoiceHeader."Shipping Agent Service Code" := LibraryRandom.RandText(MaxStrLen(SalesInvoiceHeader."Shipping Agent Service Code")).ToUpper();
+ end;
+
+ ///
+ /// Updates a posted sales invoice header using the Sales Inv. Header - Edit codeunit.
+ ///
+ /// The posted sales invoice header to update.
+ procedure UpdateSalesInvoiceHeader(SalesInvoiceHeaderEdit: Record "Sales Invoice Header")
+ begin
+ Codeunit.Run(Codeunit::"Sales Inv. Header - Edit", SalesInvoiceHeaderEdit);
+ end;
+
+ ///
+ /// Undoes a posted sales shipment line.
+ ///
+ /// The sales shipment line to undo.
+ procedure UndoSalesShipmentLine(var SalesShipmentLine: Record "Sales Shipment Line")
+ begin
+ CODEUNIT.Run(CODEUNIT::"Undo Sales Shipment Line", SalesShipmentLine);
+ end;
+
+ ///
+ /// Undoes a posted return receipt line.
+ ///
+ /// The return receipt line to undo.
+ procedure UndoReturnReceiptLine(var ReturnReceiptLine: Record "Return Receipt Line")
+ begin
+ CODEUNIT.Run(CODEUNIT::"Undo Return Receipt Line", ReturnReceiptLine);
+ end;
+
+ ///
+ /// Automatically reserves a sales line against inventory.
+ ///
+ /// The sales line to auto-reserve.
+ procedure AutoReserveSalesLine(SalesLine: Record "Sales Line")
+ begin
+ SalesLine.AutoReserve();
+ end;
+
+ ///
+ /// Selects a cash receipt journal batch.
+ ///
+ /// Returns the selected journal batch.
+ procedure SelectCashReceiptJnlBatch(var GenJournalBatch: Record "Gen. Journal Batch")
+ begin
+ LibraryJournals.SelectGenJournalBatch(GenJournalBatch, SelectCashReceiptJnlTemplate());
+ end;
+
+ ///
+ /// Selects a cash receipt journal template.
+ ///
+ /// The code of the cash receipt journal template.
+ procedure SelectCashReceiptJnlTemplate(): Code[10]
+ var
+ GenJournalTemplate: Record "Gen. Journal Template";
+ begin
+ exit(LibraryJournals.SelectGenJournalTemplate(GenJournalTemplate.Type::"Cash Receipts", PAGE::"Cash Receipt Journal"));
+ end;
+
+ ///
+ /// Disables the posting confirmation message for the current user.
+ ///
+ procedure DisableConfirmOnPostingDoc()
+ var
+ InstructionMgt: Codeunit "Instruction Mgt.";
+ begin
+ InstructionMgt.DisableMessageForCurrentUser(InstructionMgt.ShowPostedConfirmationMessageCode());
+ end;
+
+ ///
+ /// Enables the posting confirmation message for the current user.
+ ///
+ procedure EnableConfirmOnPostingDoc()
+ var
+ InstructionMgt: Codeunit "Instruction Mgt.";
+ begin
+ InstructionMgt.EnableMessageForCurrentUser(InstructionMgt.ShowPostedConfirmationMessageCode());
+ end;
+
+ ///
+ /// Disables the warning on closing unreleased documents.
+ ///
+ procedure DisableWarningOnCloseUnreleasedDoc()
+ begin
+ LibraryERM.DisableClosingUnreleasedOrdersMsg();
+ end;
+
+ ///
+ /// Disables the warning on closing unposted documents.
+ ///
+ procedure DisableWarningOnCloseUnpostedDoc()
+ var
+ InstructionMgt: Codeunit "Instruction Mgt.";
+ begin
+ InstructionMgt.DisableMessageForCurrentUser(InstructionMgt.QueryPostOnCloseCode());
+ end;
+
+ ///
+ /// Enables the warning on closing unposted documents.
+ ///
+ procedure EnableWarningOnCloseUnpostedDoc()
+ var
+ InstructionMgt: Codeunit "Instruction Mgt.";
+ begin
+ InstructionMgt.DisableMessageForCurrentUser(InstructionMgt.QueryPostOnCloseCode());
+ end;
+
+ ///
+ /// Enables the Ignore Updated Addresses option in Sales and Receivables Setup.
+ ///
+ procedure EnableSalesSetupIgnoreUpdatedAddresses()
+ var
+ SalesSetup: Record "Sales & Receivables Setup";
+ begin
+ SalesSetup.Get();
+ SalesSetup."Ignore Updated Addresses" := true;
+ SalesSetup.Modify();
+ end;
+
+ ///
+ /// Disables the Ignore Updated Addresses option in Sales and Receivables Setup.
+ ///
+ procedure DisableSalesSetupIgnoreUpdatedAddresses()
+ var
+ SalesSetup: Record "Sales & Receivables Setup";
+ begin
+ SalesSetup.Get();
+ SalesSetup."Ignore Updated Addresses" := false;
+ SalesSetup.Modify();
+ end;
+
+ ///
+ /// Creates a mock customer ledger entry for testing purposes.
+ ///
+ /// Returns the created customer ledger entry.
+ /// The customer number to use.
+ procedure MockCustLedgerEntry(var CustLedgerEntry: Record "Cust. Ledger Entry"; CustomerNo: Code[20])
+ begin
+ CustLedgerEntry.Init();
+ CustLedgerEntry."Entry No." := LibraryUtility.GetNewRecNo(CustLedgerEntry, CustLedgerEntry.FieldNo("Entry No."));
+ CustLedgerEntry."Customer No." := CustomerNo;
+ CustLedgerEntry."Posting Date" := WorkDate();
+ CustLedgerEntry.Insert();
+ end;
+
+ ///
+ /// Creates a mock customer ledger entry with an amount for testing purposes.
+ ///
+ /// Returns the created customer ledger entry.
+ /// The customer number to use.
+ procedure MockCustLedgerEntryWithAmount(var CustLedgerEntry: Record "Cust. Ledger Entry"; CustomerNo: Code[20])
+ begin
+ MockCustLedgerEntry(CustLedgerEntry, CustomerNo);
+ MockDetailedCustLedgEntry(CustLedgerEntry);
+ end;
+
+ ///
+ /// Creates a mock customer ledger entry with zero balance for testing purposes.
+ ///
+ /// Returns the created customer ledger entry.
+ /// The customer number to use.
+ procedure MockCustLedgerEntryWithZeroBalance(var CustLedgerEntry: Record "Cust. Ledger Entry"; CustomerNo: Code[20])
+ begin
+ MockCustLedgerEntry(CustLedgerEntry, CustomerNo);
+ MockDetailedCustLedgEntryZeroBalance(CustLedgerEntry);
+ end;
+
+ ///
+ /// Creates a mock detailed customer ledger entry with an amount for testing purposes.
+ ///
+ /// Returns the created detailed customer ledger entry.
+ /// The customer ledger entry to link to.
+ procedure MockDetailedCustLedgerEntryWithAmount(var DetailedCustLedgEntry: Record "Detailed Cust. Ledg. Entry"; CustLedgerEntry: Record "Cust. Ledger Entry")
+ begin
+ DetailedCustLedgEntry.Init();
+ DetailedCustLedgEntry."Entry No." := LibraryUtility.GetNewRecNo(DetailedCustLedgEntry, DetailedCustLedgEntry.FieldNo("Entry No."));
+ DetailedCustLedgEntry."Cust. Ledger Entry No." := CustLedgerEntry."Entry No.";
+ DetailedCustLedgEntry."Customer No." := CustLedgerEntry."Customer No.";
+ DetailedCustLedgEntry."Posting Date" := WorkDate();
+ DetailedCustLedgEntry."Entry Type" := DetailedCustLedgEntry."Entry Type"::"Initial Entry";
+ DetailedCustLedgEntry."Document Type" := DetailedCustLedgEntry."Document Type"::Invoice;
+ DetailedCustLedgEntry.Amount := LibraryRandom.RandDec(100, 2);
+ DetailedCustLedgEntry."Amount (LCY)" := DetailedCustLedgEntry.Amount;
+ DetailedCustLedgEntry.Insert();
+ end;
+
+ ///
+ /// Creates mock detailed customer ledger entries for a customer ledger entry.
+ ///
+ /// The customer ledger entry to create detailed entries for.
+ procedure MockDetailedCustLedgEntry(CustLedgerEntry: Record "Cust. Ledger Entry")
+ var
+ DetailedCustLedgEntry: Record "Detailed Cust. Ledg. Entry";
+ begin
+ MockDetailedCustLedgerEntryWithAmount(DetailedCustLedgEntry, CustLedgerEntry);
+ MockApplnDetailedCustLedgerEntry(DetailedCustLedgEntry, true, WorkDate());
+ MockApplnDetailedCustLedgerEntry(DetailedCustLedgEntry, false, WorkDate());
+ end;
+
+ ///
+ /// Creates mock detailed customer ledger entries with zero balance for testing.
+ ///
+ /// The customer ledger entry to create detailed entries for.
+ procedure MockDetailedCustLedgEntryZeroBalance(CustLedgerEntry: Record "Cust. Ledger Entry")
+ var
+ DetailedCustLedgEntry: Record "Detailed Cust. Ledg. Entry";
+ begin
+ MockDetailedCustLedgerEntryWithAmount(DetailedCustLedgEntry, CustLedgerEntry);
+ MockApplnDetailedCustLedgerEntry(DetailedCustLedgEntry, true, WorkDate());
+ MockApplnDetailedCustLedgerEntry(DetailedCustLedgEntry, true, WorkDate() + 1);
+ end;
+
+ ///
+ /// Creates a mock application detailed customer ledger entry for testing.
+ ///
+ /// The detailed customer ledger entry to create application for.
+ /// Whether this is an unapplied entry.
+ /// The posting date to use.
+ procedure MockApplnDetailedCustLedgerEntry(DetailedCustLedgEntry: Record "Detailed Cust. Ledg. Entry"; UnappliedEntry: Boolean; PostingDate: Date)
+ var
+ ApplnDetailedCustLedgEntry: Record "Detailed Cust. Ledg. Entry";
+ begin
+ ApplnDetailedCustLedgEntry.Init();
+ ApplnDetailedCustLedgEntry.Copy(DetailedCustLedgEntry);
+ ApplnDetailedCustLedgEntry."Entry No." := LibraryUtility.GetNewRecNo(DetailedCustLedgEntry, DetailedCustLedgEntry.FieldNo("Entry No."));
+ ApplnDetailedCustLedgEntry."Entry Type" := ApplnDetailedCustLedgEntry."Entry Type"::Application;
+ ApplnDetailedCustLedgEntry."Posting Date" := PostingDate;
+ ApplnDetailedCustLedgEntry.Amount := -ApplnDetailedCustLedgEntry.Amount;
+ ApplnDetailedCustLedgEntry."Amount (LCY)" := ApplnDetailedCustLedgEntry.Amount;
+ ApplnDetailedCustLedgEntry.Unapplied := UnappliedEntry;
+ ApplnDetailedCustLedgEntry.Insert();
+ end;
+
+ ///
+ /// Previews the posting of a sales document without actually posting it.
+ ///
+ /// The sales document to preview posting for.
+ procedure PreviewPostSalesDocument(var SalesHeader: Record "Sales Header")
+ var
+ SalesPostYesNo: Codeunit "Sales-Post (Yes/No)";
+ begin
+ SalesPostYesNo.Preview(SalesHeader);
+ end;
+
+ ///
+ /// Sets a default cancel reason code for Sales and Receivables Setup.
+ ///
+ procedure SetDefaultCancelReasonCodeForSalesAndReceivablesSetup()
+ begin
+ end;
+
+ [IntegrationEvent(false, false)]
+ local procedure OnAfterCreateCustomer(var Customer: Record Customer)
+ begin
+ end;
+
+ [IntegrationEvent(false, false)]
+ local procedure OnAfterCreateSalesHeader(var SalesHeader: Record "Sales Header"; DocumentType: Option; SellToCustomerNo: Code[20])
+ begin
+ end;
+
+ [IntegrationEvent(false, false)]
+ local procedure OnAfterCreateSalesLineWithShipmentDate(var SalesLine: Record "Sales Line"; SalesHeader: Record "Sales Header"; Type: Option; No: Code[20]; ShipmentDate: Date; Quantity: Decimal)
+ begin
+ end;
+
+ [IntegrationEvent(false, false)]
+ local procedure OnAfterCreateSalesPrice(var SalesPrice: Record "Sales Price"; ItemNo: Code[20]; SalesType: Option; SalesCode: Code[20]; StartingDate: Date; CurrencyCode: Code[10]; VariantCode: Code[10]; UOMCode: Code[10]; MinQty: Decimal; UnitPrice: Decimal)
+ begin
+ end;
+
+ [IntegrationEvent(false, false)]
+ local procedure OnBeforePostSalesDocument(var SalesHeader: Record "Sales Header"; NewShipReceive: Boolean; NewInvoice: Boolean; AfterPostSalesDocumentSendAsEmail: Boolean)
+ begin
+ end;
+
+ [IntegrationEvent(false, false)]
+ local procedure OnBeforeCreateSalesHeader(var SalesHeader: Record "Sales Header"; DocumentType: Enum "Sales Document Type"; SellToCustomerNo: Code[20])
+ begin
+ end;
+
+ [IntegrationEvent(false, false)]
+ local procedure OnCreateCustomerOnBeforeInsertCustomer(var Customer: Record Customer)
+ begin
+ end;
+}
+
diff --git a/Apps/W1/ApplicationTestLibrary/LibraryService.Codeunit.al b/Apps/W1/ApplicationTestLibrary/LibraryService.Codeunit.al
new file mode 100644
index 0000000000..5f2cb51811
--- /dev/null
+++ b/Apps/W1/ApplicationTestLibrary/LibraryService.Codeunit.al
@@ -0,0 +1,1239 @@
+namespace Microsoft.Service.Test;
+
+using Microsoft.Bank.BankAccount;
+using Microsoft.Finance.VAT.Setup;
+using Microsoft.Foundation.AuditCodes;
+using Microsoft.Foundation.Calendar;
+using Microsoft.Foundation.PaymentTerms;
+using Microsoft.Inventory.Location;
+using Microsoft.Sales.Customer;
+using Microsoft.Sales.Pricing;
+using Microsoft.Service.Comment;
+using Microsoft.Service.Contract;
+using Microsoft.Service.Document;
+using Microsoft.Service.History;
+using Microsoft.Service.Item;
+using Microsoft.Service.Loaner;
+using Microsoft.Service.Maintenance;
+using Microsoft.Service.Posting;
+using Microsoft.Service.Pricing;
+using Microsoft.Service.Setup;
+using Microsoft.Warehouse.Setup;
+using Microsoft.Projects.Project.Planning;
+using Microsoft.Projects.Project.Job;
+using Microsoft.Inventory.Item;
+using Microsoft.Projects.TimeSheet;
+using Microsoft.Projects.Resources.Resource;
+
+///
+/// Provides utility functions for creating and managing service-related entities in test scenarios, including service orders, contracts, and items.
+///
+codeunit 131902 "Library - Service"
+{
+
+ trigger OnRun()
+ begin
+ end;
+
+ var
+ LibraryERM: Codeunit "Library - ERM";
+ LibraryInventory: Codeunit "Library - Inventory";
+ LibraryRandom: Codeunit "Library - Random";
+ LibraryResource: Codeunit "Library - Resource";
+ LibrarySales: Codeunit "Library - Sales";
+ LibraryTimesheet: Codeunit "Library - Time Sheet";
+ LibraryCashFlowHelper: Codeunit "Library - Cash Flow Helper";
+ LibraryUtility: Codeunit "Library - Utility";
+ Assert: Codeunit Assert;
+ ServicePeriodOneMonthTxt: Label '<1M>', Locked = true;
+ PaymentChannelTxt: Label 'Payment Channel';
+ NonWorkDayWorkDaySequenceNotFoundErr: Label 'No non-working day followed by a working day found within an interval of %1 days.', Locked = true;
+ TimeSheetFieldValueErr: Label 'Time Sheet field %1 value is incorrect.', Locked = true;
+
+ procedure CreateBaseCalendar(var BaseCalendar: Record "Base Calendar")
+ begin
+ BaseCalendar.Init();
+ // Use the function GenerateRandomCode to get random and unique value for the Code field.
+ BaseCalendar.Validate(Code, LibraryUtility.GenerateRandomCode(BaseCalendar.FieldNo(Code), DATABASE::"Base Calendar"));
+ BaseCalendar.Insert(true);
+ end;
+
+ procedure CreateContractGroup(var ContractGroup: Record "Contract Group")
+ begin
+ ContractGroup.Init();
+
+ // Use the function GenerateRandomCode to get random and unique value for the Code field.
+ ContractGroup.Validate(
+ Code,
+ CopyStr(
+ LibraryUtility.GenerateRandomCode(ContractGroup.FieldNo(Code), DATABASE::"Base Calendar"),
+ 1, LibraryUtility.GetFieldLength(DATABASE::"Base Calendar", ContractGroup.FieldNo(Code))));
+ ContractGroup.Insert(true);
+ end;
+
+ procedure CreateContractLineCreditMemo(var ServiceContractLine: Record "Service Contract Line"; Deleting: Boolean): Code[20]
+ var
+ ServContractManagement: Codeunit ServContractManagement;
+ CreditMemoNo: Code[20];
+ begin
+ CreditMemoNo := ServContractManagement.CreateContractLineCreditMemo(ServiceContractLine, Deleting);
+ exit(CreditMemoNo);
+ end;
+
+ procedure CreateContractServiceDiscount(var ContractServiceDiscount: Record "Contract/Service Discount"; ServiceContractHeader: Record "Service Contract Header"; Type: Enum "Service Contract Discount Type"; No: Code[20])
+ begin
+ ContractServiceDiscount.Init();
+ ContractServiceDiscount.Validate("Contract Type", ServiceContractHeader."Contract Type");
+ ContractServiceDiscount.Validate("Contract No.", ServiceContractHeader."Contract No.");
+ ContractServiceDiscount.Validate(Type, Type);
+ ContractServiceDiscount.Validate("No.", No);
+ ContractServiceDiscount.Validate("Starting Date", ServiceContractHeader."Starting Date");
+ ContractServiceDiscount.Validate("Discount %", LibraryRandom.RandInt(100)); // Validating as random because value is not important.
+ ContractServiceDiscount.Insert(true);
+ end;
+
+#if not CLEAN26
+ [Obsolete('Moved to codeunit Library Inventory', '26.0')]
+ procedure CreateExtendedTextForItem(ItemNo: Code[20]): Text
+ begin
+ exit(LibraryInventory.CreateExtendedTextForItem(ItemNo));
+ end;
+#endif
+
+#if not CLEAN26
+ [Obsolete('Moved to codeunit Library Inventory', '26.0')]
+ procedure CreateExtendedTextHeaderItem(var ExtendedTextHeader: Record Microsoft.Foundation.ExtendedText."Extended Text Header"; ItemNo: Code[20])
+ begin
+ LibraryInventory.CreateExtendedTextHeaderItem(ExtendedTextHeader, ItemNo);
+ end;
+#endif
+
+#if not CLEAN26
+ [Obsolete('Moved to codeunit Library Inventory', '26.0')]
+ procedure CreateExtendedTextLineItem(var ExtendedTextLine: Record Microsoft.Foundation.ExtendedText."Extended Text Line"; ExtendedTextHeader: Record Microsoft.Foundation.ExtendedText."Extended Text Header")
+ begin
+ LibraryInventory.CreateExtendedTextLineItem(ExtendedTextLine, ExtendedTextHeader);
+ end;
+#endif
+
+ procedure CreateFaultArea(var FaultArea: Record "Fault Area")
+ begin
+ FaultArea.Init();
+ // Use the function GenerateRandomCode to get random and unique value for the Code field.
+ FaultArea.Validate(Code, LibraryUtility.GenerateRandomCode(FaultArea.FieldNo(Code), DATABASE::"Fault Area"));
+ FaultArea.Validate(Description, FaultArea.Code); // Validating Code as Description because value is not important.
+ FaultArea.Insert(true);
+ end;
+
+ procedure CreateFaultCode(var FaultCode: Record "Fault Code"; FaultAreaCode: Code[10]; SymptomCode: Code[10])
+ begin
+ FaultCode.Init();
+ FaultCode.Validate("Fault Area Code", FaultAreaCode);
+ FaultCode.Validate("Symptom Code", SymptomCode);
+ FaultCode.Validate(Code, LibraryUtility.GenerateRandomCode(FaultCode.FieldNo(Code), DATABASE::"Fault Code"));
+ FaultCode.Validate(Description, FaultCode.Code); // Validating Code as Description because value is not important.
+ FaultCode.Insert(true);
+ end;
+
+ procedure CreateFaultReasonCode(var FaultReasonCode: Record "Fault Reason Code"; ExcludeWarrantyDiscount: Boolean; ExcludeContractDiscount: Boolean)
+ begin
+ FaultReasonCode.Validate(Code, LibraryUtility.GenerateRandomCode(FaultReasonCode.FieldNo(Code), DATABASE::"Fault Reason Code"));
+ FaultReasonCode.Validate(Description, FaultReasonCode.Code);
+ FaultReasonCode.Validate("Exclude Warranty Discount", ExcludeWarrantyDiscount);
+ FaultReasonCode.Validate("Exclude Contract Discount", ExcludeContractDiscount);
+ FaultReasonCode.Insert(true);
+ end;
+
+ procedure CreateFaultResolCodesRlship(var FaultResolCodRelationship: Record "Fault/Resol. Cod. Relationship"; FaultCode: Record "Fault Code"; ResolutionCode: Code[10]; ServiceItemGroupCode: Code[10])
+ begin
+ FaultResolCodRelationship.Init();
+ FaultResolCodRelationship.Validate("Fault Area Code", FaultCode."Fault Area Code");
+ FaultResolCodRelationship.Validate("Symptom Code", FaultCode."Symptom Code");
+ FaultResolCodRelationship.Validate("Fault Code", FaultCode.Code);
+ FaultResolCodRelationship.Validate("Resolution Code", ResolutionCode);
+ FaultResolCodRelationship.Validate("Service Item Group Code", ServiceItemGroupCode);
+ FaultResolCodRelationship.Insert(true);
+ end;
+
+ procedure CreateLoaner(var Loaner: Record Loaner)
+ begin
+ Loaner.Init();
+ Loaner.Insert(true);
+ end;
+
+ procedure CreateReasonCode(var ReasonCode: Record "Reason Code")
+ begin
+ ReasonCode.Init();
+ ReasonCode.Validate(Code, LibraryUtility.GenerateRandomCode(ReasonCode.FieldNo(Code), DATABASE::"Reason Code"));
+ ReasonCode.Validate(Description, ReasonCode.Code); // Validating Code as Description because value is not important.
+ ReasonCode.Insert(true);
+ end;
+
+ procedure CreateRepairStatus(var RepairStatus: Record "Repair Status")
+ begin
+ RepairStatus.Init();
+ // Use the function GenerateRandomCode to get random and unique value for the Code field.
+ RepairStatus.Validate(Code, LibraryUtility.GenerateRandomCode(RepairStatus.FieldNo(Code), DATABASE::"Repair Status"));
+ RepairStatus.Validate(Description, RepairStatus.Code); // Validating Code as Description because value is not important.
+ RepairStatus.Insert(true);
+ end;
+
+ procedure CreateResolutionCode(var ResolutionCode: Record "Resolution Code")
+ begin
+ ResolutionCode.Init();
+ // Use the function GenerateRandomCode to get random and unique value for the Code field.
+ ResolutionCode.Validate(Code, LibraryUtility.GenerateRandomCode(ResolutionCode.FieldNo(Code), DATABASE::"Resolution Code"));
+ ResolutionCode.Validate(Description, ResolutionCode.Code); // Validating Code as Description because value is not important.
+ ResolutionCode.Insert(true);
+ end;
+
+ procedure CreateResponsibilityCenter(var ResponsibilityCenter: Record "Responsibility Center")
+ begin
+ ResponsibilityCenter.Init();
+ ResponsibilityCenter.Validate(
+ Code, LibraryUtility.GenerateRandomCode(ResponsibilityCenter.FieldNo(Code), DATABASE::"Responsibility Center"));
+ ResponsibilityCenter.Validate(Name, ResponsibilityCenter.Code); // Validating Code as Name because value is not important.
+ ResponsibilityCenter.Insert(true);
+ end;
+
+ procedure CreateServiceCommentLine(var ServiceCommentLine: Record "Service Comment Line"; TableName: Enum "Service Comment Table Name"; TableSubtype: Option; No: Code[20]; Type: Enum "Service Comment Line Type"; TableLineNo: Integer)
+ var
+ RecRef: RecordRef;
+ begin
+ ServiceCommentLine.Init();
+ ServiceCommentLine.Validate("Table Name", TableName);
+ ServiceCommentLine.Validate("Table Subtype", TableSubtype);
+ ServiceCommentLine.Validate("No.", No);
+ ServiceCommentLine.Validate(Type, Type);
+ ServiceCommentLine.Validate("Table Line No.", TableLineNo);
+ RecRef.GetTable(ServiceCommentLine);
+ ServiceCommentLine.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, ServiceCommentLine.FieldNo("Line No.")));
+ ServiceCommentLine.Insert(true);
+ // Validate Comment as primary key to enable user to distinguish between comments because value is not important.
+ ServiceCommentLine.Validate(
+ Comment, Format(ServiceCommentLine."Table Name") + Format(ServiceCommentLine."Table Subtype") + ServiceCommentLine."No." +
+ Format(ServiceCommentLine.Type) + Format(ServiceCommentLine."Table Line No.") + Format(ServiceCommentLine."Line No."));
+ ServiceCommentLine.Modify(true);
+ end;
+
+ procedure CreateCommentLineForServHeader(var ServiceCommentLine: Record "Service Comment Line"; ServiceItemLine: Record "Service Item Line"; Type: Enum "Service Comment Line Type")
+ begin
+ CreateServiceCommentLine(
+ ServiceCommentLine, ServiceCommentLine."Table Name"::"Service Header", ServiceItemLine."Document Type".AsInteger(),
+ ServiceItemLine."Document No.", Type, ServiceItemLine."Line No.");
+ end;
+
+ procedure CreateCommentLineForServCntrct(var ServiceCommentLine: Record "Service Comment Line"; ServiceContractLine: Record "Service Contract Line"; Type: Enum "Service Comment Line Type")
+ begin
+ CreateServiceCommentLine(
+ ServiceCommentLine, ServiceCommentLine."Table Name"::"Service Contract", ServiceContractLine."Contract Type".AsInteger(),
+ ServiceContractLine."Contract No.", Type, ServiceContractLine."Line No.");
+ end;
+
+ procedure CreateOrderFromQuote(ServiceHeader: Record "Service Header")
+ begin
+ CODEUNIT.Run(CODEUNIT::"Service-Quote to Order", ServiceHeader);
+ end;
+
+ procedure CreateServiceContractAcctGrp(var ServiceContractAccountGroup: Record "Service Contract Account Group")
+ begin
+ // Create Service Contract Account Group.
+ ServiceContractAccountGroup.Init();
+ // Use the function GenerateRandomCode to get random and unique value for the Code field.
+ ServiceContractAccountGroup.Validate(
+ Code, LibraryUtility.GenerateRandomCode(ServiceContractAccountGroup.FieldNo(Code), DATABASE::"Service Contract Account Group"));
+ ServiceContractAccountGroup.Insert(true);
+
+ // Input Accounts as they are mandatory.
+ ServiceContractAccountGroup.Validate("Non-Prepaid Contract Acc.", LibraryERM.CreateGLAccountWithSalesSetup());
+ ServiceContractAccountGroup.Validate("Prepaid Contract Acc.", LibraryERM.CreateGLAccountWithSalesSetup());
+ ServiceContractAccountGroup.Modify(true);
+ end;
+
+ procedure CreateServiceContractHeader(var ServiceContractHeader: Record "Service Contract Header"; ContractType: Enum "Service Contract Type"; CustomerNo: Code[20])
+ var
+ ServiceContractAccountGroup: Record "Service Contract Account Group";
+ begin
+ ServiceContractHeader.Init();
+ ServiceContractHeader.Validate("Contract Type", ContractType);
+ ServiceContractHeader.Insert(true);
+ if CustomerNo = '' then
+ CustomerNo := LibrarySales.CreateCustomerNo();
+ ServiceContractHeader.Validate("Customer No.", CustomerNo);
+ // Validate one month as the default value of the Service Period.
+ Evaluate(ServiceContractHeader."Service Period", ServicePeriodOneMonthTxt);
+ // Validate default value of Service Contract Acc. Gr. Code. This field is a mandatory field for signing Contract.
+ CreateServiceContractAcctGrp(ServiceContractAccountGroup);
+ ServiceContractHeader.Validate("Serv. Contract Acc. Gr. Code", ServiceContractAccountGroup.Code);
+ ServiceContractHeader.Validate("Your Reference", ServiceContractHeader."Customer No."); // Value is not important.
+ UpdatePaymentChannelContract(ServiceContractHeader);
+ ServiceContractHeader.Modify(true);
+ end;
+
+ procedure CreateServiceContractLine(var ServiceContractLine: Record "Service Contract Line"; ServiceContractHeader: Record "Service Contract Header"; ServiceItemNo: Code[20])
+ var
+ RecRef: RecordRef;
+ begin
+ ServiceContractLine.Init();
+ ServiceContractLine.Validate("Contract Type", ServiceContractHeader."Contract Type");
+ ServiceContractLine.Validate("Contract No.", ServiceContractHeader."Contract No.");
+ RecRef.GetTable(ServiceContractLine);
+ // Use the function GetLastLineNo to get the value of the Line No. field.
+ ServiceContractLine.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, ServiceContractLine.FieldNo("Line No.")));
+ ServiceContractLine.Validate("Customer No.", ServiceContractHeader."Customer No.");
+ ServiceContractLine.Validate("Service Item No.", ServiceItemNo);
+ ServiceContractLine.Insert(true);
+ end;
+
+ procedure CreateServiceContractTemplate(var ServiceContractTemplate: Record "Service Contract Template"; DefaultServicePeriod: DateFormula)
+ var
+ ServiceContractAccountGroup: Record "Service Contract Account Group";
+ begin
+ FindContractAccountGroup(ServiceContractAccountGroup);
+
+ ServiceContractTemplate.Init();
+ ServiceContractTemplate.Validate("Default Service Period", DefaultServicePeriod);
+ // Service Contract Account Group is required for signing Contracts.
+ ServiceContractTemplate.Validate("Serv. Contract Acc. Gr. Code", ServiceContractAccountGroup.Code);
+ ServiceContractTemplate.Insert(true);
+ end;
+
+ procedure CreateServiceCost(var ServiceCost: Record "Service Cost")
+ begin
+ ServiceCost.Init();
+ // Use the function GenerateRandomCode to get random and unique value for the Code field.
+ ServiceCost.Validate(Code, LibraryUtility.GenerateRandomCode(ServiceCost.FieldNo(Code), DATABASE::"Service Cost"));
+ ServiceCost.Validate(Description, ServiceCost.Code); // Validating Code as Description because value is not important.
+ ServiceCost.Validate("Account No.", LibraryERM.CreateGLAccountWithSalesSetup());
+ ServiceCost.Insert(true);
+ end;
+
+ procedure CreateServiceCreditMemoHeaderUsingPage() ServiceCreditMemoNo: Code[20]
+ var
+ ServiceCreditMemo: TestPage "Service Credit Memo";
+ begin
+ ServiceCreditMemo.OpenNew();
+ ServiceCreditMemo."Customer No.".Activate();
+ ServiceCreditMemoNo := CopyStr(ServiceCreditMemo."No.".Value(), 1, MaxStrLen(ServiceCreditMemoNo));
+ ServiceCreditMemo.OK().Invoke();
+ end;
+
+ procedure CreateServiceHeader(var ServiceHeader: Record "Service Header"; DocumentType: Enum "Service Document Type"; CustomerNo: Code[20])
+ var
+ PaymentMethod: Record "Payment Method";
+ PaymentTerms: Record "Payment Terms";
+ begin
+ ServiceHeader.Init();
+ ServiceHeader.Validate("Document Type", DocumentType);
+ ServiceHeader.Insert(true);
+ if CustomerNo = '' then
+ CustomerNo := LibrarySales.CreateCustomerNo();
+ ServiceHeader.Validate("Customer No.", CustomerNo);
+ ServiceHeader.Validate("Your Reference", ServiceHeader."Customer No.");
+ // Input mandatory fields for local builds.
+ if ServiceHeader."Payment Terms Code" = '' then begin
+ LibraryERM.FindPaymentTerms(PaymentTerms);
+ ServiceHeader.Validate("Payment Terms Code", PaymentTerms.Code);
+ end;
+ if ServiceHeader."Payment Method Code" = '' then begin
+ LibraryERM.FindPaymentMethod(PaymentMethod);
+ ServiceHeader.Validate("Payment Method Code", PaymentMethod.Code);
+ end;
+ SetCorrDocNoService(ServiceHeader);
+ ServiceHeader.Modify(true);
+ end;
+
+ procedure CreateServiceOrder(var ServiceHeader: Record "Service Header"; PostingDate: Date)
+ var
+ Customer: Record Customer;
+ ServiceItemLine: Record "Service Item Line";
+ ServiceItem: Record "Service Item";
+ begin
+ LibrarySales.CreateCustomer(Customer);
+ CreateServiceHeader(ServiceHeader, ServiceHeader."Document Type"::Order, Customer."No.");
+ ServiceHeader.Validate("Posting Date", PostingDate);
+ ServiceHeader.Modify();
+ CreateServiceItem(ServiceItem, Customer."No.");
+ CreateServiceItemLine(ServiceItemLine, ServiceHeader, ServiceItem."No.");
+ end;
+
+ procedure CreateServiceOrderHeaderUsingPage() ServiceOrderNo: Code[20]
+ var
+ ServiceOrder: TestPage "Service Order";
+ begin
+ ServiceOrder.OpenNew();
+ ServiceOrder."Customer No.".Activate();
+ ServiceOrderNo := CopyStr(ServiceOrder."No.".Value(), 1, MaxStrLen(ServiceOrderNo));
+ ServiceOrder.OK().Invoke();
+ end;
+
+ procedure CreateServiceDocumentWithItemServiceLine(var ServiceHeader: Record "Service Header"; DocumentType: Enum "Service Document Type")
+ begin
+ CreateServiceDocumentForCustomerNo(ServiceHeader, DocumentType, LibrarySales.CreateCustomerNo());
+ end;
+
+ procedure CreateServiceDocumentForCustomerNo(var ServiceHeader: Record "Service Header"; DocumentType: Enum "Service Document Type"; CustomerNo: Code[20])
+ var
+ ServiceItem: Record "Service Item";
+ ServiceItemLine: Record "Service Item Line";
+ ServiceLine: Record "Service Line";
+ begin
+ CreateServiceHeader(ServiceHeader, DocumentType, CustomerNo);
+
+ CreateServiceItem(ServiceItem, ServiceHeader."Bill-to Customer No.");
+ ServiceItem.Validate("Response Time (Hours)", LibraryRandom.RandDecInRange(5, 10, 2));
+ ServiceItem.Modify(true);
+
+ if ServiceHeader."Document Type" = ServiceHeader."Document Type"::Order then
+ CreateServiceItemLine(ServiceItemLine, ServiceHeader, ServiceItem."No.");
+
+ CreateServiceLineWithQuantity(
+ ServiceLine, ServiceHeader, ServiceLine.Type::Item, ServiceItem."Item No.", LibraryRandom.RandIntInRange(5, 10));
+ ServiceLine.Validate("Service Item Line No.", ServiceItemLine."Line No.");
+ ServiceLine.Validate("Unit Price", LibraryRandom.RandIntInRange(3, 5));
+ ServiceLine.Modify(true);
+ end;
+
+ procedure CreateDefaultServiceHour(var ServiceHour: Record "Service Hour"; Day: Option)
+ begin
+ ServiceHour.Init();
+ // Use a random Starting Time that does not cause Ending Time to fall in the next day.
+ ServiceHour.Validate(
+ "Starting Time",
+ 000000T + LibraryRandom.RandInt(LibraryUtility.ConvertHoursToMilliSec(12)));
+ // Use a random Ending Time that does not fall in the next day.
+ ServiceHour.Validate(
+ "Ending Time",
+ ServiceHour."Starting Time" + LibraryRandom.RandInt(LibraryUtility.ConvertHoursToMilliSec(12)) - 1);
+ ServiceHour.Validate(Day, Day);
+ ServiceHour.Insert(true);
+ end;
+
+ procedure CreateServiceHour(var ServiceHour: Record "Service Hour"; ServiceContractHeader: Record "Service Contract Header"; Day: Option)
+ begin
+ ServiceHour.Init();
+ ServiceHour.Validate("Service Contract Type", ServiceContractHeader."Contract Type".AsInteger() + 1);
+ ServiceHour.Validate("Service Contract No.", ServiceContractHeader."Contract No.");
+ ServiceHour.Validate("Starting Date", ServiceContractHeader."Starting Date");
+ // Use a random Starting Time that does not cause Ending Time to fall in the next day.
+ ServiceHour.Validate(
+ "Starting Time",
+ 000000T + LibraryRandom.RandInt(LibraryUtility.ConvertHoursToMilliSec(12)));
+ // Use a random Ending Time that does not fall in the next day.
+ ServiceHour.Validate(
+ "Ending Time",
+ ServiceHour."Starting Time" + LibraryRandom.RandInt(LibraryUtility.ConvertHoursToMilliSec(12)) - 1);
+ ServiceHour.Validate(Day, Day);
+ ServiceHour.Insert(true);
+ end;
+
+ procedure CreateServiceItem(var ServiceItem: Record "Service Item"; CustomerNo: Code[20])
+ begin
+ ServiceItem.Init();
+ ServiceItem.Insert(true);
+ if CustomerNo = '' then
+ CustomerNo := LibrarySales.CreateCustomerNo();
+ ServiceItem.Validate("Customer No.", CustomerNo);
+ ServiceItem.Validate(Description, ServiceItem."No."); // Validating No. as Description because value is not important.
+ ServiceItem.Modify(true);
+ end;
+
+ procedure CreateServiceItemComponent(var ServiceItemComponent: Record "Service Item Component"; ServiceItemNo: Code[20]; Type: Enum "Service Item Component Type"; No: Code[20])
+ var
+ RecRef: RecordRef;
+ begin
+ ServiceItemComponent.Init();
+ ServiceItemComponent.Validate(Active, true);
+ ServiceItemComponent.Validate("Parent Service Item No.", ServiceItemNo);
+ RecRef.GetTable(ServiceItemComponent);
+ ServiceItemComponent.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, ServiceItemComponent.FieldNo("Line No.")));
+ ServiceItemComponent.Validate(Type, Type);
+ ServiceItemComponent.Validate("No.", No);
+ ServiceItemComponent.Insert(true);
+ end;
+
+ procedure CreateServiceItemGroup(var ServiceItemGroup: Record "Service Item Group")
+ begin
+ ServiceItemGroup.Init();
+ // Use the function GenerateRandomCode to get random and unique value for the Code field.
+ ServiceItemGroup.Validate(Code, LibraryUtility.GenerateRandomCode(ServiceItemGroup.FieldNo(Code), DATABASE::"Service Item Group"));
+ ServiceItemGroup.Validate(Description, ServiceItemGroup.Code); // Validating Code as Description because value is not important.
+ ServiceItemGroup.Insert(true);
+ end;
+
+ procedure CreateServiceItemLine(var ServiceItemLine: Record "Service Item Line"; ServiceHeader: Record "Service Header"; ServiceItemNo: Code[20])
+ var
+ RecRef: RecordRef;
+ begin
+ ServiceItemLine.Init();
+ ServiceItemLine.Validate("Document Type", ServiceHeader."Document Type");
+ ServiceItemLine.Validate("Document No.", ServiceHeader."No.");
+ RecRef.GetTable(ServiceItemLine);
+ // Use the function GetLastLineNo to get the value of the Line No. field.
+ ServiceItemLine.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, ServiceItemLine.FieldNo("Line No.")));
+ ServiceItemLine.Insert(true);
+ ServiceItemLine.Validate("Service Item No.", ServiceItemNo);
+ ServiceItemLine.Validate(
+ Description, Format(ServiceItemLine."Document Type") + ServiceItemLine."Document No." + Format(ServiceItemLine."Line No."));
+ ServiceItemLine.Modify(true);
+ end;
+
+ procedure CreateServiceLineWithQuantity(var ServiceLine: Record "Service Line"; ServiceHeader: Record "Service Header"; Type: Enum "Service Line Type"; No: Code[20]; Quantity: Decimal)
+ begin
+ CreateServiceLine(ServiceLine, ServiceHeader, Type, No);
+ ServiceLine.Validate(Quantity, Quantity);
+ ServiceLine.Modify(true);
+ end;
+
+ procedure CreateServiceLine(var ServiceLine: Record "Service Line"; ServiceHeader: Record "Service Header"; Type: Enum "Service Line Type"; No: Code[20])
+ var
+ Item: Record Microsoft.Inventory.Item.Item;
+ Customer: Record Microsoft.Sales.Customer.Customer;
+ VATPostingSetup: Record "VAT Posting Setup";
+ LibraryJob: Codeunit "Library - Job";
+ RecRef: RecordRef;
+ begin
+ // Create Service Line.
+ Clear(ServiceLine);
+ ServiceLine.Init();
+ ServiceLine.Validate("Document Type", ServiceHeader."Document Type");
+ ServiceLine.Validate("Document No.", ServiceHeader."No.");
+ RecRef.GetTable(ServiceLine);
+ if (Type = ServiceLine.Type::Item) and (Item.Get(No) and Customer.Get(ServiceHeader."Customer No.")) then begin
+ VATPostingSetup.SetRange("VAT Prod. Posting Group", Item."VAT Prod. Posting Group");
+ VATPostingSetup.SetFilter("VAT Bus. Posting Group", Customer."VAT Bus. Posting Group");
+ if false = VATPostingSetup.FindFirst() then
+ LibraryJob.CreateVATPostingSetup(Customer."VAT Bus. Posting Group", Item."VAT Prod. Posting Group", VATPostingSetup);
+ OnBeforeCustomerModifyCreateServiceLine(Customer);
+ Customer.Modify(true);
+ end;
+
+ // Use the function GetLastLineNo to get the value of the Line No. field.
+ ServiceLine.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, ServiceLine.FieldNo("Line No.")));
+ ServiceLine.Insert(true);
+ ServiceLine.Validate(Type, Type);
+ case Type of
+ ServiceLine.Type::Item:
+ if No = '' then
+ No := LibraryInventory.CreateItemNo();
+ ServiceLine.Type::Resource:
+ if No = '' then
+ No := LibraryResource.CreateResourceNo();
+ end;
+ ServiceLine.Validate("No.", No);
+ ServiceLine.Modify(true);
+ end;
+
+ procedure CreateServiceLineForPlan(JobPlanningLine: Record "Job Planning Line"; UsageLineType: Enum "Job Line Type"; Fraction: Decimal; var ServiceLine: Record "Service Line")
+ var
+ Job: Record Job;
+ JobTask: Record "Job Task";
+ ServiceHeader: Record "Service Header";
+ ServiceItemLine: Record "Service Item Line";
+ begin
+ Assert.IsTrue(JobPlanningLine."Usage Link", 'Usage link should be enabled');
+
+ JobTask.Get(JobPlanningLine."Job No.", JobPlanningLine."Job Task No.");
+ Job.Get(JobPlanningLine."Job No.");
+
+ CreateServiceHeader(ServiceHeader, ServiceHeader."Document Type"::Order, Job."Bill-to Customer No.");
+ CreateServiceItemLine(ServiceItemLine, ServiceHeader, '');
+ CreateServiceLine(
+ ServiceLine, ServiceHeader, Job2ServiceConsumableType(JobPlanningLine.Type), JobPlanningLine."No.");
+
+ ServiceLine.Validate("Service Item Line No.", ServiceItemLine."Line No.");
+ ServiceLine.Validate(Description, LibraryUtility.GenerateGUID());
+ ServiceLine.Validate("Location Code", FindLocationForPostingGroup(ServiceLine));
+ ServiceLine.Validate(Quantity, Round(Fraction * JobPlanningLine."Remaining Qty."));
+ ServiceLine.Validate("Unit of Measure Code", JobPlanningLine."Unit of Measure Code");
+ ServiceLine.Validate("Qty. to Consume", ServiceLine.Quantity);
+ ServiceLine.Validate("Job No.", JobPlanningLine."Job No.");
+ ServiceLine.Validate("Job Task No.", JobPlanningLine."Job Task No.");
+ ServiceLine.Validate("Job Line Type", UsageLineType);
+ ServiceLine.Validate("Job Planning Line No.", JobPlanningLine."Line No.");
+ ServiceLine.Modify(true)
+ end;
+
+ procedure CreateServiceOrderFromReport(ServiceContractHeader: Record "Service Contract Header"; StartDate: Date; EndDate: Date; UseRequestPage: Boolean)
+ var
+ CreateContractServiceOrders: Report "Create Contract Service Orders";
+ begin
+ CreateContractServiceOrders.SetTableView(ServiceContractHeader);
+ CreateContractServiceOrders.InitializeRequest(StartDate, EndDate, 0);
+ CreateContractServiceOrders.UseRequestPage(UseRequestPage);
+ CreateContractServiceOrders.RunModal();
+ end;
+
+ procedure CreateServiceOrderType(var ServiceOrderType: Record "Service Order Type")
+ begin
+ ServiceOrderType.Init();
+ ServiceOrderType.Validate(Code, LibraryUtility.GenerateRandomCode(ServiceOrderType.FieldNo(Code), DATABASE::"Service Order Type"));
+ ServiceOrderType.Validate(Description, ServiceOrderType.Code); // Validating Code as Description because value is not important.
+ ServiceOrderType.Insert(true);
+ end;
+
+ procedure CreateServicePriceGroup(var ServicePriceGroup: Record "Service Price Group")
+ begin
+ ServicePriceGroup.Init();
+ // Use the function GenerateRandomCode to get random and unique value for the Code field.
+ ServicePriceGroup.Validate(
+ Code, LibraryUtility.GenerateRandomCode(ServicePriceGroup.FieldNo(Code), DATABASE::"Service Price Group"));
+ ServicePriceGroup.Validate(Description, ServicePriceGroup.Code); // Validating Code as Description because value is not important.
+ ServicePriceGroup.Insert(true);
+ end;
+
+ procedure CreateServPriceAdjustmntDetail(var ServPriceAdjustmentDetail: Record "Serv. Price Adjustment Detail"; ServPriceAdjmtGrCode: Code[10]; Type: Option; No: Code[20])
+ begin
+ ServPriceAdjustmentDetail.Init();
+ ServPriceAdjustmentDetail.Validate("Serv. Price Adjmt. Gr. Code", ServPriceAdjmtGrCode);
+ ServPriceAdjustmentDetail.Validate(Type, Type);
+ ServPriceAdjustmentDetail.Validate("No.", No);
+ ServPriceAdjustmentDetail.Insert(true);
+ end;
+
+ procedure CreateServPriceAdjustmentGroup(var ServicePriceAdjustmentGroup: Record "Service Price Adjustment Group")
+ begin
+ ServicePriceAdjustmentGroup.Init();
+ ServicePriceAdjustmentGroup.Validate(
+ Code, LibraryUtility.GenerateRandomCode(ServicePriceAdjustmentGroup.FieldNo(Code), DATABASE::"Service Price Adjustment Group"));
+ ServicePriceAdjustmentGroup.Validate(
+ Description, ServicePriceAdjustmentGroup.Code); // Validating Code as Description because value is not important.
+ ServicePriceAdjustmentGroup.Insert(true);
+ end;
+
+ procedure CreateServPriceGroupSetup(var ServPriceGroupSetup: Record "Serv. Price Group Setup"; ServicePriceGroupCode: Code[10]; FaultAreaCode: Code[10]; CustPriceGroupCode: Code[10])
+ begin
+ ServPriceGroupSetup.Init();
+ ServPriceGroupSetup.Validate("Service Price Group Code", ServicePriceGroupCode);
+ ServPriceGroupSetup.Validate("Fault Area Code", FaultAreaCode);
+ ServPriceGroupSetup.Validate("Cust. Price Group Code", CustPriceGroupCode);
+ ServPriceGroupSetup.Validate("Starting Date", WorkDate());
+ ServPriceGroupSetup.Validate(Amount, LibraryRandom.RandInt(100)); // Validating as random because value is not important.
+ ServPriceGroupSetup.Insert(true);
+ end;
+
+ procedure CreateServiceZone(var ServiceZone: Record "Service Zone")
+ begin
+ ServiceZone.Init();
+ // Use the function GenerateRandomCode to get random and unique value for the Code field.
+ ServiceZone.Validate(Code, LibraryUtility.GenerateRandomCode(ServiceZone.FieldNo(Code), DATABASE::"Service Zone"));
+ ServiceZone.Insert(true);
+ end;
+
+ procedure CreateStandardServiceCode(var StandardServiceCode: Record "Standard Service Code")
+ begin
+ StandardServiceCode.Init();
+ // Use the function GenerateRandomCode to get random and unique value for the Code field.
+ StandardServiceCode.Validate(
+ Code, LibraryUtility.GenerateRandomCode(StandardServiceCode.FieldNo(Code), DATABASE::"Standard Service Code"));
+ // Validating Code as Description because value is not important.
+ StandardServiceCode.Validate(Description, StandardServiceCode.Code);
+ StandardServiceCode.Insert(true);
+ end;
+
+ procedure CreateStandardServiceLine(var StandardServiceLine: Record "Standard Service Line"; StandardServiceCode: Code[10])
+ var
+ RecRef: RecordRef;
+ begin
+ StandardServiceLine.Init();
+ StandardServiceLine.Validate("Standard Service Code", StandardServiceCode);
+ RecRef.GetTable(StandardServiceLine);
+ StandardServiceLine.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, StandardServiceLine.FieldNo("Line No.")));
+ StandardServiceLine.Insert(true);
+ end;
+
+ procedure CreateStandardServiceItemGr(var StandardServiceItemGrCode: Record "Standard Service Item Gr. Code"; ServiceItemGroupCode: Code[10]; StandardServiceCode: Code[10])
+ begin
+ StandardServiceItemGrCode.Init();
+ StandardServiceItemGrCode.Validate("Service Item Group Code", ServiceItemGroupCode);
+ StandardServiceItemGrCode.Validate(Code, StandardServiceCode);
+ StandardServiceItemGrCode.Insert(true);
+ end;
+
+ procedure CreateSymptomCode(var SymptomCode: Record "Symptom Code")
+ begin
+ SymptomCode.Init();
+ // Use the function GenerateRandomCode to get random and unique value for the Code field.
+ SymptomCode.Validate(Code, LibraryUtility.GenerateRandomCode(SymptomCode.FieldNo(Code), DATABASE::"Symptom Code"));
+ SymptomCode.Validate(Description, SymptomCode.Code); // Validating Code as Description because value is not important.
+ SymptomCode.Insert(true);
+ end;
+
+ procedure CreateTroubleshootingHeader(var TroubleshootingHeader: Record "Troubleshooting Header")
+ begin
+ TroubleshootingHeader.Init();
+ TroubleshootingHeader.Insert(true);
+ end;
+
+ procedure CreateTroubleshootingLine(var TroubleshootingLine: Record "Troubleshooting Line"; TroubleshootingHeaderNo: Code[20])
+ var
+ RecRef: RecordRef;
+ begin
+ TroubleshootingLine.Init();
+ TroubleshootingLine.Validate("No.", TroubleshootingHeaderNo);
+ RecRef.GetTable(TroubleshootingLine);
+ TroubleshootingLine.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, TroubleshootingLine.FieldNo("Line No.")));
+
+ // Comment is blank so validate the Comment as a string containing the Troubleshooting Header No. and the Line No. as the
+ // text for Comment is not important here. This enables the user to distinguish between different Comments.
+ TroubleshootingLine.Validate(Comment, TroubleshootingLine."No." + Format(TroubleshootingLine."Line No."));
+ TroubleshootingLine.Insert(true);
+ end;
+
+ procedure CreateTroubleshootingSetup(var TroubleshootingSetup: Record "Troubleshooting Setup"; Type: Enum "Troubleshooting Item Type"; No: Code[20]; TroubleshootingNo: Code[20])
+ begin
+ TroubleshootingSetup.Init();
+ TroubleshootingSetup.Validate(Type, Type);
+ TroubleshootingSetup.Validate("No.", No);
+ TroubleshootingSetup.Validate("Troubleshooting No.", TroubleshootingNo);
+ TroubleshootingSetup.Insert(true);
+ end;
+
+ procedure ChangeCustomer(ServiceContractHeader: Record "Service Contract Header"; NewCustomerNo: Code[20])
+ var
+ ServContractManagement: Codeunit ServContractManagement;
+ begin
+ // Change Customer on Service Contract.
+ ServContractManagement.ChangeCustNoOnServContract(NewCustomerNo, '', ServiceContractHeader)
+ end;
+
+ procedure CheckServiceTimeSheetLine(TimeSheetHeader: Record "Time Sheet Header"; ServiceHeaderNo: Code[20]; ServiceLineNo: Integer; ServiceLineQuantity: Decimal; Chargeable: Boolean)
+ var
+ TimeSheetLine: Record "Time Sheet Line";
+ begin
+ TimeSheetLine.SetRange("Time Sheet No.", TimeSheetHeader."No.");
+ TimeSheetLine.SetRange("Service Order No.", ServiceHeaderNo);
+ TimeSheetLine.SetRange("Service Order Line No.", ServiceLineNo);
+ TimeSheetLine.FindLast();
+ TimeSheetLine.CalcFields("Total Quantity");
+
+ Assert.AreEqual(ServiceLineQuantity, TimeSheetLine."Total Quantity",
+ StrSubstNo(TimeSheetFieldValueErr, TimeSheetLine.FieldCaption("Total Quantity")));
+ Assert.AreEqual(Chargeable, TimeSheetLine.Chargeable,
+ StrSubstNo(TimeSheetFieldValueErr, TimeSheetLine.FieldCaption(Chargeable)));
+ Assert.AreEqual(TimeSheetLine.Status::Approved, TimeSheetLine.Status,
+ StrSubstNo(TimeSheetFieldValueErr, TimeSheetLine.FieldCaption(Status)));
+ Assert.IsTrue(TimeSheetLine.Posted, StrSubstNo(TimeSheetFieldValueErr, TimeSheetLine.FieldCaption(Posted)));
+ end;
+
+ procedure FindContractAccountGroup(var ServiceContractAccountGroup: Record "Service Contract Account Group")
+ begin
+ // Filter Service Contract Account Group so that errors are not generated due to mandatory fields.
+ ServiceContractAccountGroup.SetFilter("Non-Prepaid Contract Acc.", '<>''''');
+ ServiceContractAccountGroup.SetFilter("Prepaid Contract Acc.", '<>''''');
+
+ ServiceContractAccountGroup.FindSet();
+ end;
+
+ local procedure FindLocationForPostingGroup(ServiceLine: Record "Service Line"): Code[10]
+ var
+ InventoryPostingSetup: Record "Inventory Posting Setup";
+ Location: Record Location;
+ begin
+ if ServiceLine.Type <> ServiceLine.Type::Item then
+ exit(ServiceLine."Location Code");
+
+ InventoryPostingSetup.SetRange("Invt. Posting Group Code", ServiceLine."Posting Group");
+ InventoryPostingSetup.SetFilter("Location Code", '<>%1', '');
+ InventoryPostingSetup.FindSet();
+ repeat
+ Location.Get(InventoryPostingSetup."Location Code");
+ if not Location."Use As In-Transit" and not Location."Bin Mandatory" and not Location."Require Shipment" then
+ exit(Location.Code)
+ until InventoryPostingSetup.Next() = 0;
+ exit('');
+ end;
+
+ procedure FindServiceCost(var ServiceCost: Record "Service Cost")
+ begin
+ // Filter Service Cost so that errors are not generated due to mandatory fields.
+ ServiceCost.SetFilter("Account No.", '<>''''');
+ ServiceCost.SetRange("Service Zone Code", '');
+
+ ServiceCost.FindSet();
+ end;
+
+ procedure FindServiceItemGroup(var ServiceItemGroup: Record "Service Item Group")
+ begin
+ ServiceItemGroup.FindSet();
+ end;
+
+ procedure FindResolutionCode(var ResolutionCode: Record "Resolution Code")
+ begin
+ ResolutionCode.FindSet();
+ end;
+
+ procedure FindFaultReasonCode(var FaultReasonCode: Record "Fault Reason Code")
+ begin
+ FaultReasonCode.FindSet();
+ end;
+
+ procedure FindServiceContractLine(var ServiceContractLine: Record "Service Contract Line"; ContractType: Enum "Service Contract Type"; ContractNo: Code[20])
+ begin
+ ServiceContractLine.SetRange("Contract Type", ContractType);
+ ServiceContractLine.SetRange("Contract No.", ContractNo);
+ ServiceContractLine.FindFirst();
+ end;
+
+ procedure FindServiceInvoiceHeader(var ServiceInvoiceHeader: Record "Service Invoice Header"; PreAssignedNo: Code[20])
+ begin
+ ServiceInvoiceHeader.SetRange("Pre-Assigned No.", PreAssignedNo);
+ ServiceInvoiceHeader.FindFirst();
+ end;
+
+ procedure FindServiceCrMemoHeader(var ServiceCrMemoHeader: Record "Service Cr.Memo Header"; PreAssignedNo: Code[20])
+ begin
+ ServiceCrMemoHeader.SetRange("Pre-Assigned No.", PreAssignedNo);
+ ServiceCrMemoHeader.FindFirst();
+ end;
+
+ procedure PostServiceOrder(var ServiceHeader: Record "Service Header"; Ship: Boolean; Consume: Boolean; Invoice: Boolean)
+ var
+ TempServiceLine: Record "Service Line" temporary;
+ ServicePost: Codeunit "Service-Post";
+ begin
+ ServiceHeader.Find();
+ SetCorrDocNoService(ServiceHeader);
+ OnBeforePostServiceOrder(ServiceHeader);
+ ServicePost.PostWithLines(ServiceHeader, TempServiceLine, Ship, Consume, Invoice);
+ end;
+
+ procedure PostServiceOrderWithPassedLines(var ServiceHeader: Record "Service Header"; var TempServiceLine: Record "Service Line" temporary; Ship: Boolean; Consume: Boolean; Invoice: Boolean)
+ var
+ ServicePost: Codeunit "Service-Post";
+ begin
+ ServiceHeader.Find();
+ SetCorrDocNoService(ServiceHeader);
+ ServicePost.PostWithLines(ServiceHeader, TempServiceLine, Ship, Consume, Invoice);
+ end;
+
+ procedure ReleaseServiceDocument(var ServiceHeader: Record "Service Header")
+ var
+ ReleaseServiceDoc: Codeunit "Release Service Document";
+ begin
+ ReleaseServiceDoc.PerformManualRelease(ServiceHeader);
+ end;
+
+ procedure ReopenServiceDocument(var ServiceHeader: Record "Service Header")
+ var
+ ReleaseServiceDoc: Codeunit "Release Service Document";
+ begin
+ ReleaseServiceDoc.PerformManualReopen(ServiceHeader);
+ end;
+
+ procedure SetCorrDocNoService(var ServiceHeader: Record "Service Header")
+ begin
+ if ServiceHeader."Document Type" = ServiceHeader."Document Type"::"Credit Memo" then;
+ end;
+
+ procedure SetShipmentOnInvoice(ShipmentOnInvoice: Boolean)
+ var
+ ServiceMgtSetup: Record "Service Mgt. Setup";
+ begin
+ ServiceMgtSetup.Get();
+ ServiceMgtSetup.Validate("Shipment on Invoice", ShipmentOnInvoice);
+ ServiceMgtSetup.Modify(true);
+ end;
+
+ procedure SetupServiceMgtNoSeries()
+ var
+ ServiceMgtSetup: Record "Service Mgt. Setup";
+ BaseCalender: Record "Base Calendar";
+ begin
+ // Setup Service Management.
+ ServiceMgtSetup.Get();
+
+ // Use GetGlobalNoSeriesCode to get No. Series code.
+ if ServiceMgtSetup."Service Item Nos." = '' then
+ ServiceMgtSetup.Validate("Service Item Nos.", LibraryUtility.GetGlobalNoSeriesCode());
+ if ServiceMgtSetup."Service Order Nos." = '' then
+ ServiceMgtSetup.Validate("Service Order Nos.", LibraryUtility.GetGlobalNoSeriesCode());
+ if ServiceMgtSetup."Service Invoice Nos." = '' then
+ ServiceMgtSetup.Validate("Service Invoice Nos.", LibraryUtility.GetGlobalNoSeriesCode());
+ if ServiceMgtSetup."Service Credit Memo Nos." = '' then
+ ServiceMgtSetup.Validate("Service Credit Memo Nos.", LibraryUtility.GetGlobalNoSeriesCode());
+ if ServiceMgtSetup."Posted Service Shipment Nos." = '' then
+ ServiceMgtSetup.Validate("Posted Service Shipment Nos.", LibraryUtility.GetGlobalNoSeriesCode());
+ if ServiceMgtSetup."Posted Service Invoice Nos." = '' then
+ ServiceMgtSetup.Validate("Posted Service Invoice Nos.", LibraryUtility.GetGlobalNoSeriesCode());
+ if ServiceMgtSetup."Posted Serv. Credit Memo Nos." = '' then
+ ServiceMgtSetup.Validate("Posted Serv. Credit Memo Nos.", LibraryUtility.GetGlobalNoSeriesCode());
+ if ServiceMgtSetup."Troubleshooting Nos." = '' then
+ ServiceMgtSetup.Validate("Troubleshooting Nos.", LibraryUtility.GetGlobalNoSeriesCode());
+ if ServiceMgtSetup."Service Contract Nos." = '' then
+ ServiceMgtSetup.Validate("Service Contract Nos.", LibraryUtility.GetGlobalNoSeriesCode());
+ if ServiceMgtSetup."Service Quote Nos." = '' then
+ ServiceMgtSetup.Validate("Service Quote Nos.", LibraryUtility.GetGlobalNoSeriesCode());
+ if ServiceMgtSetup."Contract Invoice Nos." = '' then
+ ServiceMgtSetup.Validate("Contract Invoice Nos.", LibraryUtility.GetGlobalNoSeriesCode());
+ if ServiceMgtSetup."Contract Credit Memo Nos." = '' then
+ ServiceMgtSetup.Validate("Contract Credit Memo Nos.", LibraryUtility.GetGlobalNoSeriesCode());
+ if ServiceMgtSetup."Prepaid Posting Document Nos." = '' then
+ ServiceMgtSetup.Validate("Prepaid Posting Document Nos.", LibraryUtility.GetGlobalNoSeriesCode());
+ if ServiceMgtSetup."Contract Credit Memo Nos." = '' then
+ ServiceMgtSetup.Validate("Contract Credit Memo Nos.", LibraryUtility.GetGlobalNoSeriesCode());
+ if ServiceMgtSetup."Posted Service Shipment Nos." = '' then
+ ServiceMgtSetup.Validate("Posted Service Shipment Nos.", LibraryUtility.GetGlobalNoSeriesCode());
+ if ServiceMgtSetup."Contract Template Nos." = '' then
+ ServiceMgtSetup.Validate("Contract Template Nos.", LibraryUtility.GetGlobalNoSeriesCode());
+ if ServiceMgtSetup."Loaner Nos." = '' then
+ ServiceMgtSetup.Validate("Loaner Nos.", LibraryUtility.GetGlobalNoSeriesCode());
+ ServiceMgtSetup.Validate("Contract Serv. Ord. Max. Days", 365); // Using Default 365 Days.
+
+ // Create and Validate Base Calendar.
+ if ServiceMgtSetup."Base Calendar Code" = '' then begin
+ CreateBaseCalendar(BaseCalender);
+ ServiceMgtSetup.Validate("Base Calendar Code", BaseCalender.Code);
+ end;
+
+ ServiceMgtSetup.Modify(true);
+
+ LibrarySales.SetCreditWarningsToNoWarnings();
+ end;
+
+ procedure GetFirstWorkingDay(WorkingDate: Date): Date
+ var
+ ServiceHour: Record "Service Hour";
+ begin
+ // Gets the first working day.
+ while not (IsWorking(WorkingDate) and GetServiceHourForDate(ServiceHour, WorkingDate)) do
+ WorkingDate := CalcDate('<1D>', WorkingDate);
+ exit(WorkingDate);
+ end;
+
+ procedure GetNextWorkingDay(WorkingDate: Date): Date
+ var
+ ServiceHour: Record "Service Hour";
+ begin
+ // Gets the next working day from the specified date.
+ repeat
+ WorkingDate := CalcDate('<1D>', WorkingDate);
+ until (
+ IsWorking(WorkingDate) and GetServiceHourForDate(ServiceHour, WorkingDate)) or
+ (not IsWorking(WorkingDate) and IsValidOnHolidays(WorkingDate));
+ exit(WorkingDate);
+ end;
+
+ procedure GetNonWrkngDayFollwdByWrkngDay(): Date
+ var
+ ServiceHour: Record "Service Hour";
+ WorkingDate: Date;
+ LoopCounter: Integer;
+ MaxLoops: Integer;
+ begin
+ // Returns a non-working day followed by a working day.
+ WorkingDate := WorkDate();
+ LoopCounter := 0;
+ MaxLoops := 366;
+ repeat
+ LoopCounter += 1;
+ if LoopCounter > MaxLoops then
+ Error(NonWorkDayWorkDaySequenceNotFoundErr, MaxLoops);
+ WorkingDate := CalcDate('<1D>', WorkingDate);
+ until
+ not (IsWorking(WorkingDate) or IsValidOnHolidays(WorkingDate)) and
+ (IsWorking(CalcDate('<1D>', WorkingDate)) and GetServiceHourForDate(ServiceHour, CalcDate('<1D>', WorkingDate)));
+ exit(WorkingDate);
+ end;
+
+ procedure GetServiceHourForDate(var ServiceHour: Record "Service Hour"; OrderDate: Date): Boolean
+ var
+ Date: Record System.Utilities.Date;
+ begin
+ // Finds the Service Hour related to the Date and returns a Boolean.
+ Date.Get(Date."Period Type"::Date, OrderDate);
+ ServiceHour.SetRange("Service Contract Type", ServiceHour."Service Contract Type"::" ");
+ ServiceHour.SetRange("Service Contract No.", '');
+ ServiceHour.SetFilter(Day, Date."Period Name");
+ exit(ServiceHour.FindFirst())
+ end;
+
+ procedure GetServiceOrderReportGrossAmount(ServiceLine: Record "Service Line"): Decimal
+ var
+ CustInvDisc: Record "Cust. Invoice Disc.";
+ begin
+ CustInvDisc.Get(ServiceLine."Customer No.", ServiceLine."Currency Code", 0);
+ exit(ServiceLine."Amount Including VAT" - (ServiceLine."Amount Including VAT" * CustInvDisc."Discount %" / 100));
+ end;
+
+ procedure GetShipmentLines(var ServiceLine: Record "Service Line")
+ var
+ ServiceGetShipment: Codeunit "Service-Get Shipment";
+ begin
+ ServiceGetShipment.Run(ServiceLine);
+ end;
+
+ procedure IsWorking(DateToCheck: Date): Boolean
+ var
+ CustomizedCalendarChange: Record "Customized Calendar Change";
+ ServiceMgtSetup: Record "Service Mgt. Setup";
+ CalendarManagement: Codeunit "Calendar Management";
+ begin
+ // Checks if the day is a working day.
+ ServiceMgtSetup.Get();
+ CalendarManagement.SetSource(ServiceMgtSetup, CustomizedCalendarChange);
+ CustomizedCalendarChange.Date := DateToCheck;
+ CalendarManagement.CheckDateStatus(CustomizedCalendarChange);
+ exit(not CustomizedCalendarChange.Nonworking);
+ end;
+
+ procedure IsValidOnHolidays(DateToCheck: Date): Boolean
+ var
+ ServiceHour: Record "Service Hour";
+ begin
+ // Checks if the Service Hour for the date has Valid on Holidays checked.
+ if GetServiceHourForDate(ServiceHour, DateToCheck) then
+ exit(ServiceHour."Valid on Holidays");
+ exit(false);
+ end;
+
+ procedure SignContract(ServiceContractHeader: Record "Service Contract Header")
+ var
+ SignServContractDoc: Codeunit SignServContractDoc;
+ begin
+ SignServContractDoc.SignContract(ServiceContractHeader);
+ end;
+
+ procedure SignContract(ServiceContractHeader: Record "Service Contract Header"; HideDialog: Boolean)
+ var
+ SignServContractDoc: Codeunit SignServContractDoc;
+ begin
+ SignServContractDoc.SetHideDialog(HideDialog);
+ SignServContractDoc.SignContract(ServiceContractHeader);
+ end;
+
+ local procedure UpdatePaymentChannelContract(var ServiceContractHeader: Record "Service Contract Header")
+ var
+ RecRef: RecordRef;
+ FieldRef: FieldRef;
+ begin
+ if LibraryUtility.CheckFieldExistenceInTable(DATABASE::"Service Contract Header", PaymentChannelTxt) then begin
+ RecRef.GetTable(ServiceContractHeader);
+ FieldRef := RecRef.Field(LibraryUtility.FindFieldNoInTable(DATABASE::"Service Contract Header", PaymentChannelTxt));
+ FieldRef.Validate(2); // Input Option as Account Transfer.
+ RecRef.SetTable(ServiceContractHeader);
+ end;
+ end;
+
+ procedure AutoReserveServiceLine(ServiceLine: Record "Service Line")
+ begin
+ ServiceLine.AutoReserve();
+ end;
+
+ procedure UndoShipmentLinesByServiceOrderNo(ServiceOrderNo: Code[20])
+ var
+ ServiceShipmentLine: Record "Service Shipment Line";
+ begin
+ ServiceShipmentLine.SetRange("Order No.", ServiceOrderNo);
+ CODEUNIT.Run(CODEUNIT::"Undo Service Shipment Line", ServiceShipmentLine);
+ end;
+
+ procedure UndoShipmentLinesByServiceDocNo(ServiceDocumentNo: Code[20])
+ var
+ ServiceShipmentLine: Record "Service Shipment Line";
+ begin
+ ServiceShipmentLine.SetRange("Document No.", ServiceDocumentNo);
+ CODEUNIT.Run(CODEUNIT::"Undo Service Shipment Line", ServiceShipmentLine);
+ end;
+
+ procedure UndoConsumptionLinesByServiceOrderNo(ServiceOrderNo: Code[20])
+ var
+ ServiceShipmentLine: Record "Service Shipment Line";
+ begin
+ ServiceShipmentLine.SetRange("Order No.", ServiceOrderNo);
+ CODEUNIT.Run(CODEUNIT::"Undo Service Consumption Line", ServiceShipmentLine);
+ end;
+
+ procedure UndoConsumptionLinesByServiceDocNo(ServiceDocumentNo: Code[20])
+ var
+ ServiceShipmentLine: Record "Service Shipment Line";
+ begin
+ ServiceShipmentLine.SetRange("Document No.", ServiceDocumentNo);
+ CODEUNIT.Run(CODEUNIT::"Undo Service Consumption Line", ServiceShipmentLine);
+ end;
+
+ procedure CreateDefaultYellowLocation(var Location: Record Location): Code[10]
+ var
+ WarehouseEmployee: Record "Warehouse Employee";
+ LibraryWarehouse: Codeunit "Library - Warehouse";
+ begin
+ LibraryWarehouse.CreateLocationWithInventoryPostingSetup(Location);
+ Location.Validate("Require Receive", true);
+ Location.Validate("Require Shipment", true);
+ Location.Validate("Require Put-away", true);
+ Location.Validate("Require Pick", true);
+
+ Location.Validate("Bin Mandatory", false);
+ Location.Validate("Use Put-away Worksheet", false);
+ Location.Validate("Directed Put-away and Pick", false);
+ Location.Validate("Use ADCS", false);
+
+ Location.Modify(true);
+
+ LibraryWarehouse.CreateWarehouseEmployee(WarehouseEmployee, Location.Code, false);
+
+ exit(Location.Code);
+ end;
+
+ procedure CreateFullWarehouseLocation(var Location: Record Location; NumberOfBinsPerZone: Integer)
+ var
+ WarehouseEmployee: Record "Warehouse Employee";
+ LibraryWarehouse: Codeunit "Library - Warehouse";
+ begin
+ LibraryWarehouse.CreateFullWMSLocation(Location, NumberOfBinsPerZone); // Value used for number of bin per zone.
+ LibraryWarehouse.CreateWarehouseEmployee(WarehouseEmployee, Location.Code, false);
+ end;
+
+ procedure CreateCustomizedCalendarChange(BaseCalendarCode: Code[10]; var CustomizedCalendarChange: Record "Customized Calendar Change"; SourceType: Option; SourceCode: Code[10]; AdditionalSourceCode: Code[10]; RecurringSystem: Option; WeekDay: Option; IsNonWorking: Boolean)
+ begin
+ CustomizedCalendarChange.Init();
+ CustomizedCalendarChange.Validate("Source Type", SourceType);
+ CustomizedCalendarChange.Validate("Source Code", SourceCode);
+ CustomizedCalendarChange.Validate("Additional Source Code", AdditionalSourceCode);
+ CustomizedCalendarChange.Validate("Base Calendar Code", BaseCalendarCode);
+ CustomizedCalendarChange.Validate("Recurring System", RecurringSystem);
+ CustomizedCalendarChange.Validate(Day, WeekDay);
+ CustomizedCalendarChange.Validate(Nonworking, IsNonWorking);
+ CustomizedCalendarChange.Insert(true);
+ end;
+
+ procedure CombineShipments(var ServiceHeader: Record "Service Header"; var ServiceShipmentHeader: Record "Service Shipment Header"; PostingDate: Date; DocumentDate: Date; CalcInvDisc: Boolean; PostInvoices: Boolean; OnlyStdPmtTerms: Boolean; CopyTextLines: Boolean)
+ var
+ TmpServiceHeader: Record "Service Header";
+ TmpServiceShipmentHeader: Record "Service Shipment Header";
+ CombineShipmentsReport: Report "Combine Service Shipments";
+ begin
+ CombineShipmentsReport.InitializeRequest(PostingDate, DocumentDate, CalcInvDisc, PostInvoices, OnlyStdPmtTerms, CopyTextLines);
+ if ServiceHeader.HasFilter then
+ TmpServiceHeader.CopyFilters(ServiceHeader)
+ else begin
+ ServiceHeader.Get(ServiceHeader."Document Type", ServiceHeader."No.");
+ TmpServiceHeader.SetRange("Document Type", ServiceHeader."Document Type");
+ TmpServiceHeader.SetRange("No.", ServiceHeader."No.");
+ end;
+ CombineShipmentsReport.SetTableView(TmpServiceHeader);
+ if ServiceShipmentHeader.HasFilter then
+ TmpServiceShipmentHeader.CopyFilters(ServiceShipmentHeader)
+ else begin
+ ServiceShipmentHeader.Get(ServiceShipmentHeader."No.");
+ TmpServiceShipmentHeader.SetRange("No.", ServiceShipmentHeader."No.");
+ end;
+ CombineShipmentsReport.SetTableView(TmpServiceShipmentHeader);
+ CombineShipmentsReport.UseRequestPage(false);
+ CombineShipmentsReport.RunModal();
+ end;
+
+ procedure Job2ServiceConsumableType(Type: Enum "Job Planning Line Type"): Enum "Service Line Type"
+ var
+ ServiceLine: Record "Service Line";
+ begin
+ case Type of
+ "Job Planning Line Type"::Resource:
+ exit(ServiceLine.Type::Resource);
+ "Job Planning Line Type"::Item:
+ exit(ServiceLine.Type::Item);
+ "Job Planning Line Type"::"G/L Account":
+ exit(ServiceLine.Type::"G/L Account");
+ else
+ Assert.Fail('Unsupported consumable type');
+ end
+ end;
+
+ procedure InitScenarioWTForServiceOrder(var TimeSheetHeader: Record "Time Sheet Header"; var ServiceHeader: Record "Service Header")
+ var
+ TimeSheetLine: Record "Time Sheet Line";
+ Resource: Record Resource;
+ begin
+ // create time sheet
+ LibraryTimesheet.CreateTimeSheet(TimeSheetHeader, false);
+
+ // create work type
+ Resource.Get(TimeSheetHeader."Resource No.");
+
+ CreateServiceOrder(ServiceHeader, CalcDate('<+3D>', TimeSheetHeader."Starting Date"));
+
+ // create time sheets' lines with type Resource, some kind of Work Type and different chargeables
+ LibraryTimesheet.CreateTimeSheetLine(TimeSheetHeader, TimeSheetLine, TimeSheetLine.Type::Service, '', '', ServiceHeader."No.", '');
+ TimeSheetLine.Validate("Service Order No.", ServiceHeader."No.");
+ TimeSheetLine.Modify();
+ // set quantities for lines
+ LibraryTimesheet.CreateTimeSheetDetail(TimeSheetLine, TimeSheetHeader."Starting Date", LibraryTimesheet.GetRandomDecimal());
+ LibraryTimesheet.SubmitTimeSheetLine(TimeSheetLine);
+ end;
+
+ procedure InitServiceScenario(var TimeSheetHeader: Record "Time Sheet Header"; var TimeSheetLine: Record "Time Sheet Line"; var ServiceHeader: Record "Service Header")
+ begin
+ // create time sheet
+ LibraryTimesheet.CreateTimeSheet(TimeSheetHeader, false);
+
+ // create service order
+ if ServiceHeader."No." = '' then
+ CreateServiceOrder(ServiceHeader, CalcDate('<+3D>', TimeSheetHeader."Starting Date"));
+
+ // create time sheet line with type Service
+ LibraryTimesheet.CreateTimeSheetLine(TimeSheetHeader, TimeSheetLine, TimeSheetLine.Type::Service, '', '', ServiceHeader."No.", '');
+ TimeSheetLine.Validate("Service Order No.", ServiceHeader."No.");
+ LibraryTimesheet.CreateTimeSheetDetail(TimeSheetLine, TimeSheetHeader."Starting Date", LibraryTimesheet.GetRandomDecimal());
+ LibraryTimesheet.SubmitAndApproveTimeSheetLine(TimeSheetLine);
+ end;
+
+ procedure InitBackwayScenario(var TimeSheetHeader: Record "Time Sheet Header"; var ServiceHeader: Record "Service Header"; var ServiceLine: Record "Service Line")
+ begin
+ // create time sheet
+ LibraryTimesheet.CreateTimeSheet(TimeSheetHeader, false);
+
+ // create service order
+ CreateServiceOrder(ServiceHeader, CalcDate('<+3D>', TimeSheetHeader."Starting Date"));
+ // create service line
+ CreateServiceLine(ServiceLine, ServiceHeader, ServiceLine.Type::Resource, TimeSheetHeader."Resource No.");
+ ServiceLine.Validate("Service Item Line No.", 10000);
+ ServiceLine.Validate(Quantity, LibraryRandom.RandInt(9999) / 100);
+ ServiceLine.Modify();
+ end;
+
+ procedure CreateSpecificServiceOrder(var ServiceHeader: Record "Service Header"; PaymentTermsCode: Code[10]; CFPaymentTermsCode: Code[10])
+ var
+ Customer: Record Customer;
+ begin
+ LibrarySales.CreateCustomer(Customer);
+ LibraryCashFlowHelper.AssignCFPaymentTermToCustomer(Customer, PaymentTermsCode);
+ LibraryCashFlowHelper.AssignCFPaymentTermToCustomer(Customer, CFPaymentTermsCode);
+
+ CreateServiceHeader(ServiceHeader, ServiceHeader."Document Type"::Order, Customer."No.");
+
+ CreateServiceLines(ServiceHeader);
+ CreateServiceLines(ServiceHeader);
+ CreateServiceLines(ServiceHeader);
+ end;
+
+ procedure CreateDefaultServiceOrder(var ServiceHeader: Record "Service Header")
+ begin
+ CreateSpecificServiceOrder(ServiceHeader, '', '');
+ end;
+
+ procedure CreateServiceLines(ServiceHeader: Record "Service Header")
+ var
+ ServiceLine: Record "Service Line";
+ ServiceItemLine: Record "Service Item Line";
+ Item: Record Item;
+ begin
+ // simple wrapper for LibraryPurchase.CreateServiceLine
+ LibrarySales.FindItem(Item);
+ CreateServiceItemLine(ServiceItemLine, ServiceHeader, '');
+ CreateServiceLine(ServiceLine, ServiceHeader, ServiceLine.Type::Item, Item."No.");
+ ServiceLine.Validate("Service Item Line No.", ServiceItemLine."Line No.");
+ ServiceLine.Validate(Quantity, LibraryRandom.RandInt(50));
+ ServiceLine.Modify(true);
+ end;
+
+ [IntegrationEvent(false, false)]
+ local procedure OnBeforeCustomerModifyCreateServiceLine(var Customer: Record Customer)
+ begin
+ end;
+
+ [IntegrationEvent(false, false)]
+ local procedure OnBeforePostServiceOrder(var ServiceHeader: Record "Service Header")
+ begin
+ end;
+}
+
diff --git a/Apps/W1/ApplicationTestLibrary/LibrarySetupStorage.Codeunit.al b/Apps/W1/ApplicationTestLibrary/LibrarySetupStorage.Codeunit.al
new file mode 100644
index 0000000000..17630f84ad
--- /dev/null
+++ b/Apps/W1/ApplicationTestLibrary/LibrarySetupStorage.Codeunit.al
@@ -0,0 +1,125 @@
+///
+/// Provides utility functions for saving and restoring setup table data in test scenarios to ensure test isolation.
+///
+codeunit 131009 "Library - Setup Storage"
+{
+ Permissions = TableData "General Ledger Setup" = rimd;
+
+ trigger OnRun()
+ begin
+ end;
+
+ var
+ TempIntegerStoredTables: Record "Integer" temporary;
+ Assert: Codeunit Assert;
+ TableBackupErr: Label 'Table %1 already added to backup', Comment = '%1 = Table Caption';
+ OnlyOneEntryAllowedErr: Label 'Setup table with only one entry is allowed';
+ CompositePrimaryKeyErr: Label 'Composite primary key is not allowed';
+ RecordRefStorage: array[100] of RecordRef;
+
+ procedure Save(TableId: Integer)
+ var
+ RecRef: RecordRef;
+ begin
+ if TempIntegerStoredTables.Get(TableId) then
+ Error(TableBackupErr, TableId);
+
+ RecRef.Open(TableId);
+ Assert.AreEqual(1, RecRef.Count, OnlyOneEntryAllowedErr);
+ RecRef.Find();
+ ValidatePrimaryKey(RecRef);
+
+ TempIntegerStoredTables.Number := TableId;
+ TempIntegerStoredTables.Insert(true);
+ RecordRefStorage[TempIntegerStoredTables.Count] := RecRef;
+ end;
+
+ [Scope('OnPrem')]
+ procedure SaveSalesSetup()
+ begin
+ Save(Database::"Sales & Receivables Setup");
+ end;
+
+ [Scope('OnPrem')]
+ procedure SavePurchasesSetup()
+ begin
+ Save(Database::"Purchases & Payables Setup");
+ end;
+
+ [Scope('OnPrem')]
+ procedure SaveGeneralLedgerSetup()
+ begin
+ Save(Database::"General Ledger Setup");
+ end;
+
+ [Scope('OnPrem')]
+ procedure SaveCompanyInformation()
+ begin
+ Save(Database::"Company Information");
+ end;
+
+ [Scope('OnPrem')]
+ procedure SaveManufacturingSetup()
+ begin
+ Save(99000765); // DATABASE::"Manufacturing Setup"
+ end;
+
+ [Scope('OnPrem')]
+ procedure SaveInventorySetup()
+ begin
+ Save(Database::"Inventory Setup");
+ end;
+
+ [Scope('OnPrem')]
+ procedure SaveServiceMgtSetup()
+ begin
+ Save(Database::"Service Mgt. Setup");
+ end;
+
+ [Scope('OnPrem')]
+ procedure SaveVATSetup()
+ begin
+ Save(Database::"VAT Setup");
+ end;
+
+ procedure Restore()
+ var
+ RecordRefSource: RecordRef;
+ RecordRefDestination: RecordRef;
+ Index: Integer;
+ begin
+ Index := TempIntegerStoredTables.Count();
+ while Index > 0 do begin
+ RecordRefSource := RecordRefStorage[Index];
+ RecordRefDestination.Open(RecordRefSource.Number);
+ CopyFields(RecordRefSource, RecordRefDestination);
+ RecordRefDestination.Modify();
+ RecordRefDestination.Close();
+ Index -= 1;
+ end;
+ end;
+
+ local procedure ValidatePrimaryKey(var RecRef: RecordRef)
+ var
+ KeyRef: KeyRef;
+ begin
+ KeyRef := RecRef.KeyIndex(1);
+ Assert.AreEqual(1, KeyRef.FieldCount, CompositePrimaryKeyErr);
+ end;
+
+ local procedure CopyFields(RecordRefSource: RecordRef; var RecordRefDestination: RecordRef)
+ var
+ SourceFieldRef: FieldRef;
+ DestinationFieldRef: FieldRef;
+ i: Integer;
+ begin
+ for i := 1 to RecordRefSource.FieldCount do begin
+ SourceFieldRef := RecordRefSource.FieldIndex(i);
+ if SourceFieldRef.Class = FieldClass::Normal then begin
+ DestinationFieldRef := RecordRefDestination.Field(SourceFieldRef.Number);
+ DestinationFieldRef.Value(SourceFieldRef.Value)
+ end;
+ end
+ end;
+}
+
diff --git a/Apps/W1/ApplicationTestLibrary/LibrarySmallBusiness.Codeunit.al b/Apps/W1/ApplicationTestLibrary/LibrarySmallBusiness.Codeunit.al
new file mode 100644
index 0000000000..e6ec3e6e77
--- /dev/null
+++ b/Apps/W1/ApplicationTestLibrary/LibrarySmallBusiness.Codeunit.al
@@ -0,0 +1,599 @@
+///
+/// Provides utility functions for small business scenarios in test cases, including simplified setup and common operations.
+///
+codeunit 132213 "Library - Small Business"
+{
+
+ trigger OnRun()
+ begin
+ end;
+
+ var
+ LibraryERM: Codeunit "Library - ERM";
+ LibraryInventory: Codeunit "Library - Inventory";
+ LibraryJob: Codeunit "Library - Job";
+ LibrarySales: Codeunit "Library - Sales";
+ LibraryPurchase: Codeunit "Library - Purchase";
+ LibraryRapidStart: Codeunit "Library - Rapid Start";
+ LibraryUtility: Codeunit "Library - Utility";
+ LibraryRandom: Codeunit "Library - Random";
+ LibraryDimension: Codeunit "Library - Dimension";
+
+ procedure CreateCommentLine(var CommentLine: Record "Comment Line"; TableName: Enum "Comment Line Table Name"; No: Code[20])
+ var
+ RecRef: RecordRef;
+ begin
+ Clear(CommentLine);
+ CommentLine.Validate("Table Name", TableName);
+ CommentLine.Validate("No.", No);
+ RecRef.GetTable(CommentLine);
+ CommentLine.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, CommentLine.FieldNo("Line No.")));
+ CommentLine.Insert(true);
+ end;
+
+ procedure CreateSalesCommentLine(var SalesCommentLine: Record "Sales Comment Line"; SalesLine: Record "Sales Line")
+ var
+ NextLineNo: Integer;
+ begin
+ Clear(SalesCommentLine);
+ SalesCommentLine.SetRange("Document Type", SalesLine."Document Type".AsInteger());
+ SalesCommentLine.SetRange("No.", SalesLine."No.");
+ SalesCommentLine.SetRange("Document Line No.", SalesLine."Line No.");
+ if SalesCommentLine.FindLast() then
+ NextLineNo := SalesCommentLine."Line No." + 10000
+ else
+ NextLineNo := 10000;
+
+ Clear(SalesCommentLine);
+ SalesCommentLine.Init();
+ SalesCommentLine."Document Type" := SalesLine."Document Type";
+ SalesCommentLine."No." := SalesLine."Document No.";
+ SalesCommentLine."Document Line No." := SalesLine."Line No.";
+ SalesCommentLine."Line No." := NextLineNo;
+ SalesCommentLine.Date := LibraryUtility.GenerateRandomDate(WorkDate() + 10, WorkDate() + 20);
+ SalesCommentLine.Comment := LibraryUtility.GenerateRandomCode(SalesCommentLine.FieldNo(Comment), DATABASE::"Sales Comment Line");
+ SalesCommentLine.Insert(true);
+ end;
+
+ procedure CreateCustomer(var Customer: Record Customer)
+ begin
+ LibrarySales.CreateCustomer(Customer);
+ end;
+
+ procedure CreateCustomerSalesCode(var StandardCustomerSalesCode: Record "Standard Customer Sales Code"; CustomerNo: Code[20]; "Code": Code[10])
+ begin
+ StandardCustomerSalesCode.Init();
+ StandardCustomerSalesCode.Validate("Customer No.", CustomerNo);
+ StandardCustomerSalesCode.Validate(Code, Code);
+ StandardCustomerSalesCode.Insert(true);
+ end;
+
+ procedure CreateCustomerTemplateLine(ConfigTemplateHeader: Record "Config. Template Header"; FieldNo: Integer; FieldName: Text[30]; DefaultValue: Text[50])
+ var
+ ConfigTemplateLine: Record "Config. Template Line";
+ begin
+ LibraryRapidStart.CreateConfigTemplateLine(ConfigTemplateLine, ConfigTemplateHeader.Code);
+ ConfigTemplateLine.Validate("Field ID", FieldNo);
+ ConfigTemplateLine.Validate("Field Name", FieldName);
+ if DefaultValue <> '' then
+ ConfigTemplateLine.Validate("Default Value", DefaultValue)
+ else
+ ConfigTemplateLine.Validate("Default Value", Format(LibraryRandom.RandIntInRange(100000000, 999999999)));
+ ConfigTemplateLine.Validate("Skip Relation Check", false);
+ ConfigTemplateLine.Modify(true);
+ end;
+
+ procedure CreateCustomerTemplate(var ConfigTemplateHeader: Record "Config. Template Header")
+ var
+ Customer: Record Customer;
+ begin
+ LibraryRapidStart.CreateConfigTemplateHeader(ConfigTemplateHeader);
+ ConfigTemplateHeader.Validate("Table ID", DATABASE::Customer);
+ ConfigTemplateHeader.Modify(true);
+
+ CreateCustomerTemplateLine(ConfigTemplateHeader, Customer.FieldNo("Phone No."),
+ Customer.FieldName("Phone No."), '');
+ CreateCustomerTemplateLine(ConfigTemplateHeader, Customer.FieldNo("Our Account No."),
+ Customer.FieldName("Our Account No."), '');
+ CreateCustomerTemplateLine(ConfigTemplateHeader, Customer.FieldNo("Gen. Bus. Posting Group"),
+ Customer.FieldName("Gen. Bus. Posting Group"), FindGenBusPostingGroup());
+ CreateCustomerTemplateLine(ConfigTemplateHeader, Customer.FieldNo("Customer Posting Group"),
+ Customer.FieldName("Customer Posting Group"), LibrarySales.FindCustomerPostingGroup());
+ end;
+
+ procedure CreateCurrencyExchangeRate(var CurrencyExchangeRate: Record "Currency Exchange Rate"; CurrencyCode: Code[10]; StartingDate: Date)
+ begin
+ Clear(CurrencyExchangeRate);
+ CurrencyExchangeRate.Validate("Currency Code", CurrencyCode);
+ CurrencyExchangeRate.Validate("Starting Date", StartingDate);
+ CurrencyExchangeRate.Validate("Exchange Rate Amount", LibraryRandom.RandDec(10, 2));
+ CurrencyExchangeRate.Validate("Relational Exch. Rate Amount",
+ CurrencyExchangeRate."Exchange Rate Amount" * LibraryRandom.RandDec(10, 2));
+
+ CurrencyExchangeRate.Insert(true);
+ end;
+
+ procedure CreateExtendedTextHeader(var ExtendedTextHeader: Record "Extended Text Header"; TableNameOption: Enum "Extended Text Table Name"; No: Code[20])
+ begin
+ Clear(ExtendedTextHeader);
+ ExtendedTextHeader.Validate("Table Name", TableNameOption);
+ ExtendedTextHeader.Validate("No.", No);
+ ExtendedTextHeader.Validate("Sales Invoice", true);
+ ExtendedTextHeader.Validate("Sales Quote", true);
+ ExtendedTextHeader.Insert(true);
+ end;
+
+ procedure CreateExtendedTextLine(var ExtendedTextLine: Record "Extended Text Line"; ExtendedTextHeader: Record "Extended Text Header")
+ var
+ RecRef: RecordRef;
+ begin
+ Clear(ExtendedTextLine);
+ ExtendedTextLine.Validate("Table Name", ExtendedTextHeader."Table Name");
+ ExtendedTextLine.Validate("No.", ExtendedTextHeader."No.");
+ ExtendedTextLine.Validate("Language Code", ExtendedTextHeader."Language Code");
+ ExtendedTextLine.Validate("Text No.", ExtendedTextHeader."Text No.");
+ RecRef.GetTable(ExtendedTextLine);
+ ExtendedTextLine.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, ExtendedTextLine.FieldNo("Line No.")));
+ ExtendedTextLine.Validate(Text, LibraryUtility.GenerateRandomCode(ExtendedTextLine.FieldNo(Text),
+ DATABASE::"Extended Text Line"));
+ ExtendedTextLine.Insert(true);
+ end;
+
+ procedure CreateItem(var Item: Record Item)
+ begin
+ LibraryInventory.CreateItemWithUnitPriceAndUnitCost(Item, LibraryRandom.RandDecInDecimalRange(1, 10000, 2), 0);
+ end;
+
+ procedure CreateItemAsService(var Item: Record Item)
+ var
+ ItemNew: Record Item;
+ Item2: Record Item;
+ begin
+ LibraryInventory.CreateItem(Item2);
+ ItemNew.Init();
+ ItemNew.Insert(true);
+ ItemNew.Validate("Base Unit of Measure", FindUnitOfMeasure());
+ ItemNew.Validate("Unit Price", LibraryRandom.RandDecInDecimalRange(1.0, 10000.0, 2));
+ ItemNew.Validate(Type, Item.Type::Service);
+ ItemNew.Validate("Gen. Prod. Posting Group", Item2."Gen. Prod. Posting Group");
+ if ItemNew."VAT Prod. Posting Group" = '' then
+ ItemNew.Validate("VAT Prod. Posting Group", Item2."VAT Prod. Posting Group");
+ ItemNew.Description := ItemNew."No.";
+ ItemNew.Modify();
+ OnBeforeCreateItemAsServiceItemGet(ItemNew);
+ Item.Get(ItemNew."No.");
+ end;
+
+ procedure CreateJob(var Job: Record Job)
+ begin
+ LibraryJob.CreateJob(Job);
+ end;
+
+ procedure CreateResponsabilityCenter(var ResponsibilityCenter: Record "Responsibility Center")
+ begin
+ Clear(ResponsibilityCenter);
+ ResponsibilityCenter.Validate(Code, LibraryUtility.GenerateRandomCode(ResponsibilityCenter.FieldNo(Code),
+ DATABASE::"Responsibility Center"));
+ ResponsibilityCenter.Insert();
+ end;
+
+ procedure CreateSalesInvoiceHeader(var SalesHeader: Record "Sales Header"; Customer: Record Customer)
+ begin
+ LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Invoice, Customer."No.");
+ end;
+
+ procedure CreateSalesCrMemoHeader(var SalesHeader: Record "Sales Header"; Customer: Record Customer)
+ begin
+ LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::"Credit Memo", Customer."No.");
+ end;
+
+ procedure CreateSalesQuoteHeaderWithLines(var SalesHeader: Record "Sales Header"; Customer: Record Customer; Item: Record Item; NumberOfLines: Integer; ItemQuantity: Integer)
+ var
+ SalesLine: Record "Sales Line";
+ I: Integer;
+ begin
+ LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Quote, Customer."No.");
+
+ for I := 1 to NumberOfLines do
+ LibrarySales.CreateSalesLine(SalesLine, SalesHeader, SalesLine.Type::Item, Item."No.", ItemQuantity);
+ end;
+
+ procedure CreateSalesQuoteHeader(var SalesHeader: Record "Sales Header"; Customer: Record Customer)
+ begin
+ LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Quote, Customer."No.");
+ end;
+
+ procedure CreateSalesOrderHeader(var SalesHeader: Record "Sales Header"; Customer: Record Customer)
+ begin
+ LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Order, Customer."No.");
+ end;
+
+ procedure CreateSalesLine(var SalesLine: Record "Sales Line"; SalesHeader: Record "Sales Header"; Item: Record Item; Quantity: Decimal)
+ begin
+ // unable to use the page testability to perform this action because of following reason
+ // PageTestability can't handle modal dialogs such as availability warnings when creating a sales invoice line.
+ // Also, it can currently not return the Sales Line record (we need additional GetRecord or GetKey capability in PageTestability)
+ LibrarySales.CreateSalesLine(SalesLine, SalesHeader, SalesLine.Type::Item, Item."No.", Quantity);
+ end;
+
+ procedure CreatePurchaseInvoiceHeader(var PurchHeader: Record "Purchase Header"; Vend: Record Vendor)
+ begin
+ LibraryPurchase.CreatePurchHeader(PurchHeader, PurchHeader."Document Type"::Invoice, Vend."No.");
+ end;
+
+ procedure CreatePurchaseLine(var PurchaseLine: Record "Purchase Line"; PurchaseHeader: Record "Purchase Header"; Item: Record Item; Qty: Decimal)
+ begin
+ // unable to use the page testability to perform this action because of following reason
+ // PageTestability can't handle modal dialogs such as availability warnings when creating a sales invoice line.
+ // Also, it can currently not return the Sales Line record (we need additional GetRecord or GetKey capability in PageTestability)
+ LibraryPurchase.CreatePurchaseLine(PurchaseLine, PurchaseHeader, PurchaseLine.Type::Item, Item."No.", Qty);
+ end;
+
+ procedure CreatePurchaseCrMemoHeader(var PurchHeader: Record "Purchase Header"; Vend: Record Vendor)
+ begin
+ LibraryPurchase.CreatePurchHeader(PurchHeader, PurchHeader."Document Type"::"Credit Memo", Vend."No.");
+ end;
+
+ procedure CreateStandardSalesCode(var StandardSalesCode: Record "Standard Sales Code")
+ begin
+ StandardSalesCode.Init();
+ StandardSalesCode.Validate(
+ Code,
+ CopyStr(
+ LibraryUtility.GenerateRandomCode(StandardSalesCode.FieldNo(Code), DATABASE::"Standard Sales Code"),
+ 1,
+ LibraryUtility.GetFieldLength(DATABASE::"Standard Sales Code", StandardSalesCode.FieldNo(Code))));
+ StandardSalesCode.Validate(Description, StandardSalesCode.Code);
+ StandardSalesCode.Insert(true);
+ end;
+
+ procedure CreateStandardSalesLine(var StandardSalesLine: Record "Standard Sales Line"; StandardSalesCode: Code[10])
+ var
+ RecRef: RecordRef;
+ begin
+ StandardSalesLine.Init();
+ StandardSalesLine.Validate("Standard Sales Code", StandardSalesCode);
+ RecRef.GetTable(StandardSalesLine);
+ StandardSalesLine.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, StandardSalesLine.FieldNo("Line No.")));
+ StandardSalesLine.Insert(true);
+ end;
+
+ procedure CreateStandardPurchaseCode(var StandardPurchaseCode: Record "Standard Purchase Code")
+ begin
+ StandardPurchaseCode.Init();
+ StandardPurchaseCode.Validate(
+ Code,
+ CopyStr(
+ LibraryUtility.GenerateRandomCode(StandardPurchaseCode.FieldNo(Code), DATABASE::"Standard Purchase Code"),
+ 1,
+ LibraryUtility.GetFieldLength(DATABASE::"Standard Purchase Code", StandardPurchaseCode.FieldNo(Code))));
+ StandardPurchaseCode.Validate(Description, StandardPurchaseCode.Code);
+ StandardPurchaseCode.Insert(true);
+ end;
+
+ procedure CreateStandardPurchaseLine(var StandardPurchaseLine: Record "Standard Purchase Line"; StandardPurchaseCode: Code[10])
+ var
+ RecRef: RecordRef;
+ begin
+ StandardPurchaseLine.Init();
+ StandardPurchaseLine.Validate("Standard Purchase Code", StandardPurchaseCode);
+ RecRef.GetTable(StandardPurchaseLine);
+ StandardPurchaseLine.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, StandardPurchaseLine.FieldNo("Line No.")));
+ StandardPurchaseLine.Insert(true);
+ end;
+
+ procedure CreateVendor(var Vendor: Record Vendor)
+ begin
+ LibraryPurchase.CreateVendor(Vendor);
+ end;
+
+ procedure CreateVendorPurchaseCode(var StandardVendorPurchaseCode: Record "Standard Vendor Purchase Code"; VendorNo: Code[20]; "Code": Code[10])
+ begin
+ StandardVendorPurchaseCode.Init();
+ StandardVendorPurchaseCode.Validate("Vendor No.", VendorNo);
+ StandardVendorPurchaseCode.Validate(Code, Code);
+ StandardVendorPurchaseCode.Insert(true);
+ end;
+
+ procedure CreateVendorTemplate(var ConfigTemplateHeader: Record "Config. Template Header")
+ var
+ Vend: Record Vendor;
+ begin
+ LibraryRapidStart.CreateConfigTemplateHeader(ConfigTemplateHeader);
+ ConfigTemplateHeader.Validate("Table ID", DATABASE::Vendor);
+ ConfigTemplateHeader.Modify(true);
+
+ CreateVendorTemplateLine(ConfigTemplateHeader, Vend.FieldNo("Phone No."),
+ Vend.FieldName("Phone No."), '');
+ CreateVendorTemplateLine(ConfigTemplateHeader, Vend.FieldNo("Our Account No."),
+ Vend.FieldName("Our Account No."), '');
+ CreateVendorTemplateLine(ConfigTemplateHeader, Vend.FieldNo("Gen. Bus. Posting Group"),
+ Vend.FieldName("Gen. Bus. Posting Group"), FindGenBusPostingGroup());
+ CreateVendorTemplateLine(ConfigTemplateHeader, Vend.FieldNo("Vendor Posting Group"),
+ Vend.FieldName("Vendor Posting Group"), LibraryPurchase.FindVendorPostingGroup());
+ end;
+
+ procedure CreateVendorTemplateLine(ConfigTemplateHeader: Record "Config. Template Header"; FieldNo: Integer; FieldName: Text[30]; DefaultValue: Text[50])
+ var
+ ConfigTemplateLine: Record "Config. Template Line";
+ begin
+ LibraryRapidStart.CreateConfigTemplateLine(ConfigTemplateLine, ConfigTemplateHeader.Code);
+ ConfigTemplateLine.Validate("Field ID", FieldNo);
+ ConfigTemplateLine.Validate("Field Name", FieldName);
+ if DefaultValue <> '' then
+ ConfigTemplateLine.Validate("Default Value", DefaultValue)
+ else
+ ConfigTemplateLine.Validate("Default Value", Format(LibraryRandom.RandIntInRange(100000000, 999999999)));
+ ConfigTemplateLine.Validate("Skip Relation Check", false);
+ ConfigTemplateLine.Modify(true);
+ end;
+
+ local procedure FindGenBusPostingGroup(): Code[20]
+ var
+ GeneralPostingSetup: Record "General Posting Setup";
+ begin
+ GeneralPostingSetup.FindLast();
+ exit(GeneralPostingSetup."Gen. Bus. Posting Group");
+ end;
+
+ local procedure FindUnitOfMeasure(): Code[10]
+ var
+ UnitOfMeasure: Record "Unit of Measure";
+ begin
+ UnitOfMeasure.FindFirst();
+ exit(UnitOfMeasure.Code);
+ end;
+
+ procedure FindVATBusPostingGroupZeroVAT(VATProdPostingGroupCode: Code[20]): Code[20]
+ var
+ VATPostingSetup: Record "VAT Posting Setup";
+ begin
+ VATPostingSetup.SetFilter("VAT Bus. Posting Group", '<>%1', '');
+ VATPostingSetup.SetRange("VAT Prod. Posting Group", VATProdPostingGroupCode);
+ VATPostingSetup.SetRange("VAT Calculation Type", VATPostingSetup."VAT Calculation Type"::"Normal VAT");
+ VATPostingSetup.SetRange("VAT %", 0);
+ if not VATPostingSetup.FindLast() then
+ CreateZeroVATPostingSetupByProdGroupCode(VATPostingSetup, VATProdPostingGroupCode);
+ exit(VATPostingSetup."VAT Bus. Posting Group");
+ end;
+
+ procedure PostSalesInvoice(var SalesHeader: Record "Sales Header"): Code[20]
+ begin
+ exit(LibrarySales.PostSalesDocument(SalesHeader, false, true));
+ end;
+
+ procedure PostPurchaseInvoice(var PurchaseHeader: Record "Purchase Header"): Code[20]
+ begin
+ exit(LibraryPurchase.PostPurchaseDocument(PurchaseHeader, false, true));
+ end;
+
+ procedure SetInvoiceDiscountToCustomer(var Customer: Record Customer; DiscPct: Decimal; MinimumAmount: Decimal; CurrencyCode: Code[10])
+ var
+ CustInvoiceDisc: Record "Cust. Invoice Disc.";
+ begin
+ LibraryERM.CreateInvDiscForCustomer(CustInvoiceDisc, Customer."No.", CurrencyCode, MinimumAmount);
+ CustInvoiceDisc.Validate("Discount %", DiscPct);
+ CustInvoiceDisc.Modify(true);
+ end;
+
+ procedure SetInvoiceDiscountToVendor(var Vendor: Record Vendor; DiscPct: Decimal; MinimumAmount: Decimal; CurrencyCode: Code[10])
+ var
+ VendorInvoiceDisc: Record "Vendor Invoice Disc.";
+ begin
+ LibraryERM.CreateInvDiscForVendor(VendorInvoiceDisc, Vendor."No.", CurrencyCode, MinimumAmount);
+ VendorInvoiceDisc.Validate("Discount %", DiscPct);
+ VendorInvoiceDisc.Modify(true);
+ end;
+
+ procedure SetVATBusPostingGrPriceSetup(VATProdPostingGroupCode: Code[20]; PricesIncludingVAT: Boolean)
+ var
+ VATPostingSetup: Record "VAT Posting Setup";
+ SalesSetup: Record "Sales & Receivables Setup";
+ begin
+ if not PricesIncludingVAT then
+ exit;
+
+ SalesSetup.Get();
+ if not VATPostingSetup.Get(SalesSetup."VAT Bus. Posting Gr. (Price)", VATProdPostingGroupCode) then begin
+ VATPostingSetup.Init();
+ VATPostingSetup.Validate("VAT Bus. Posting Group", SalesSetup."VAT Bus. Posting Gr. (Price)");
+ VATPostingSetup.Validate("VAT Prod. Posting Group", VATProdPostingGroupCode);
+ VATPostingSetup.Insert();
+ end;
+ end;
+
+ procedure CreateVATPostingSetup(var VATPostingSetup: Record "VAT Posting Setup")
+ begin
+ LibraryERM.CreateVATPostingSetupWithAccounts(
+ VATPostingSetup, VATPostingSetup."VAT Calculation Type"::"Normal VAT", LibraryRandom.RandIntInRange(1, 25));
+ end;
+
+ procedure CreateGLAccount(): Code[20]
+ begin
+ exit(LibraryERM.CreateGLAccountNo());
+ end;
+
+ procedure FindVATProdPostingGroupZeroVAT(VATBusPostingGroupCode: Code[20]): Code[20]
+ var
+ VATPostingSetup: Record "VAT Posting Setup";
+ begin
+ VATPostingSetup.SetFilter("VAT Bus. Posting Group", VATBusPostingGroupCode);
+ VATPostingSetup.SetFilter("VAT Prod. Posting Group", '<>%1', '');
+ VATPostingSetup.SetRange("VAT Calculation Type", VATPostingSetup."VAT Calculation Type"::"Normal VAT");
+ VATPostingSetup.SetRange("VAT %", 0);
+ if not VATPostingSetup.FindLast() then
+ CreateZeroVATPostingSetupByBusGroupCode(VATPostingSetup, VATBusPostingGroupCode);
+ exit(VATPostingSetup."VAT Prod. Posting Group");
+ end;
+
+ procedure CreateGLAccountWithPostingSetup(var GLAccount: Record "G/L Account")
+ var
+ VATPostingSetup: Record "VAT Posting Setup";
+ begin
+ VATPostingSetup.SetFilter("VAT %", '<>%1', 0);
+ if not VATPostingSetup.FindLast() then
+ CreateVATPostingSetup(VATPostingSetup);
+
+ GLAccount.Get(CreateGLAccount());
+ GLAccount.Validate(Name, GLAccount."No.");
+ GLAccount.Validate("Direct Posting", true);
+ GLAccount.Validate("VAT Bus. Posting Group", VATPostingSetup."VAT Bus. Posting Group");
+ GLAccount.Validate("VAT Prod. Posting Group", VATPostingSetup."VAT Prod. Posting Group");
+ GLAccount.Modify();
+ end;
+
+ local procedure CreateZeroVATPostingSetupByProdGroupCode(var VATPostingSetup: Record "VAT Posting Setup"; VATProdPostingGroupCode: Code[20])
+ var
+ VATBusPostingGroup: Record "VAT Business Posting Group";
+ begin
+ VATBusPostingGroup.Init();
+ VATBusPostingGroup.Validate(
+ Code,
+ LibraryUtility.GenerateRandomCode(
+ VATBusPostingGroup.FieldNo(Code), DATABASE::"VAT Business Posting Group"));
+ VATBusPostingGroup.Insert();
+
+ CreateZeroVATPostingSetup(VATPostingSetup, VATBusPostingGroup.Code, VATProdPostingGroupCode);
+ end;
+
+ local procedure CreateZeroVATPostingSetupByBusGroupCode(var VATPostingSetup: Record "VAT Posting Setup"; VATBusPostingGroupCode: Code[20])
+ var
+ VATProdPostingGroup: Record "VAT Product Posting Group";
+ begin
+ VATProdPostingGroup.Init();
+ VATProdPostingGroup.Validate(
+ Code,
+ LibraryUtility.GenerateRandomCode(
+ VATProdPostingGroup.FieldNo(Code), DATABASE::"VAT Product Posting Group"));
+ VATProdPostingGroup.Insert();
+
+ CreateZeroVATPostingSetup(VATPostingSetup, VATBusPostingGroupCode, VATProdPostingGroup.Code);
+ end;
+
+ local procedure CreateZeroVATPostingSetup(var VATPostingSetup: Record "VAT Posting Setup"; VATBusPostingGroupCode: Code[20]; VATProdPostingGroupCode: Code[20])
+ begin
+ VATPostingSetup.Init();
+ VATPostingSetup.Validate("VAT Bus. Posting Group", VATBusPostingGroupCode);
+ VATPostingSetup.Validate("VAT Prod. Posting Group", VATProdPostingGroupCode);
+ VATPostingSetup.Validate(
+ "VAT Identifier",
+ LibraryUtility.GenerateRandomCode(
+ VATPostingSetup.FieldNo("VAT Identifier"), DATABASE::"VAT Posting Setup"));
+ VATPostingSetup.Validate("VAT %", 0);
+ VATPostingSetup.Validate("Sales VAT Account", CreateGLAccount());
+ VATPostingSetup.Validate("Purchase VAT Account", CreateGLAccount());
+ VATPostingSetup.Insert();
+ end;
+
+ procedure InitGlobalDimCodeValue(var DimValue: Record "Dimension Value"; DimNumber: Integer): Code[20]
+ var
+ GLSetup: Record "General Ledger Setup";
+ Dimension: Record Dimension;
+ RecRef: RecordRef;
+ GlobalDimCodeFieldRef: FieldRef;
+ begin
+ RecRef.Open(DATABASE::"General Ledger Setup");
+ RecRef.Find();
+ case DimNumber of
+ 1:
+ GlobalDimCodeFieldRef := RecRef.Field(GLSetup.FieldNo("Global Dimension 1 Code"));
+ 2:
+ GlobalDimCodeFieldRef := RecRef.Field(GLSetup.FieldNo("Global Dimension 2 Code"));
+ else
+ exit;
+ end;
+
+ if Format(GlobalDimCodeFieldRef.Value) = '' then begin
+ LibraryDimension.CreateDimension(Dimension);
+ GlobalDimCodeFieldRef.Validate(Dimension.Code);
+ RecRef.Modify(true);
+ LibraryDimension.CreateDimensionValue(DimValue, Dimension.Code);
+ end else begin
+ DimValue.SetRange("Dimension Code", Format(GlobalDimCodeFieldRef.Value));
+ DimValue.SetRange(Blocked, false);
+ DimValue.FindFirst();
+ end;
+ exit(DimValue.Code);
+ end;
+
+ procedure FindSalesCorrectiveInvoice(var SalesInvHeader: Record "Sales Invoice Header"; SalesCrMemoHeader: Record "Sales Cr.Memo Header")
+ var
+ CancelledDocument: Record "Cancelled Document";
+ begin
+ CancelledDocument.FindSalesCancelledCrMemo(SalesCrMemoHeader."No.");
+ SalesInvHeader.Get(CancelledDocument."Cancelled By Doc. No.");
+ end;
+
+ procedure FindSalesCorrectiveCrMemo(var SalesCrMemoHeader: Record "Sales Cr.Memo Header"; SalesInvHeader: Record "Sales Invoice Header")
+ var
+ CancelledDocument: Record "Cancelled Document";
+ begin
+ CancelledDocument.FindSalesCancelledInvoice(SalesInvHeader."No.");
+ SalesCrMemoHeader.Get(CancelledDocument."Cancelled By Doc. No.");
+ end;
+
+ procedure FindPurchCorrectiveInvoice(var PurchInvHeader: Record "Purch. Inv. Header"; PurchCrMemoHdr: Record "Purch. Cr. Memo Hdr.")
+ var
+ CancelledDocument: Record "Cancelled Document";
+ begin
+ CancelledDocument.FindPurchCancelledCrMemo(PurchCrMemoHdr."No.");
+ PurchInvHeader.Get(CancelledDocument."Cancelled By Doc. No.");
+ end;
+
+ procedure FindPurchCorrectiveCrMemo(var PurchCrMemoHdr: Record "Purch. Cr. Memo Hdr."; PurchInvHeader: Record "Purch. Inv. Header")
+ var
+ CancelledDocument: Record "Cancelled Document";
+ begin
+ CancelledDocument.FindPurchCancelledInvoice(PurchInvHeader."No.");
+ PurchCrMemoHdr.Get(CancelledDocument."Cancelled By Doc. No.");
+ end;
+
+ procedure MockCancelledDocument(TableId: Integer; DocumentNo: code[20]; CancelledByDocNo: code[20])
+ var
+ CancelledDocument: Record "Cancelled Document";
+ begin
+ CancelledDocument.Init();
+ CancelledDocument."Source ID" := TableId;
+ CancelledDocument."Cancelled Doc. No." := DocumentNo;
+ CancelledDocument."Cancelled By Doc. No." := CancelledByDocNo;
+ CancelledDocument.Insert();
+ end;
+
+ procedure UpdateInvRoundingAccountWithSalesSetup(CustomerPostingGroupCode: Code[20]; GenBusPostGroupCode: Code[20])
+ var
+ GenPostingSetup: Record "General Posting Setup";
+ GLAccount: Record "G/L Account";
+ begin
+ GLAccount.Get(
+ LibrarySales.GetInvRoundingAccountOfCustPostGroup(CustomerPostingGroupCode));
+ GenPostingSetup.Get(GenBusPostGroupCode, GLAccount."Gen. Prod. Posting Group");
+ GenPostingSetup.Validate("Sales Account", LibraryERM.CreateGLAccountNo());
+ GenPostingSetup.Validate("Sales Credit Memo Account", LibraryERM.CreateGLAccountNo());
+ GenPostingSetup.Modify(true);
+ end;
+
+ procedure UpdateInvRoundingAccountWithPurchSetup(CustomerPostingGroupCode: Code[20]; GenBusPostGroupCode: Code[20])
+ var
+ GenPostingSetup: Record "General Posting Setup";
+ GLAccount: Record "G/L Account";
+ begin
+ GLAccount.Get(
+ LibrarySales.GetInvRoundingAccountOfCustPostGroup(CustomerPostingGroupCode));
+ GenPostingSetup.Get(GenBusPostGroupCode, GLAccount."Gen. Prod. Posting Group");
+ GenPostingSetup.Validate("Purch. Account", LibraryERM.CreateGLAccountNo());
+ GenPostingSetup.Validate("Purch. Credit Memo Account", LibraryERM.CreateGLAccountNo());
+ GenPostingSetup.Modify(true);
+ end;
+
+ procedure GetAvgDaysToPayLabel(): Text
+ var
+ CustomerCardCalculations: Codeunit "Customer Card Calculations";
+ begin
+ exit(CustomerCardCalculations.GetAvgDaysToPayLabel())
+ end;
+
+ [IntegrationEvent(false, false)]
+ local procedure OnBeforeCreateItemAsServiceItemGet(var Item: Record Item)
+ begin
+ end;
+}
diff --git a/Apps/W1/ApplicationTestLibrary/LibraryTemplates.Codeunit.al b/Apps/W1/ApplicationTestLibrary/LibraryTemplates.Codeunit.al
new file mode 100644
index 0000000000..b3fe68f443
--- /dev/null
+++ b/Apps/W1/ApplicationTestLibrary/LibraryTemplates.Codeunit.al
@@ -0,0 +1,234 @@
+///
+/// Provides utility functions for creating and managing configuration templates in test scenarios.
+///
+codeunit 132210 "Library - Templates"
+{
+ EventSubscriberInstance = Manual;
+
+ trigger OnRun()
+ begin
+ end;
+
+ var
+ LibraryTemplates: Codeunit "Library - Templates";
+ LibraryERM: Codeunit "Library - ERM";
+ LibraryDimension: Codeunit "Library - Dimension";
+ LibraryPurchase: Codeunit "Library - Purchase";
+ LibrarySales: Codeunit "Library - Sales";
+ LibraryInventory: Codeunit "Library - Inventory";
+ LibraryRandom: Codeunit "Library - Random";
+ LibraryUtility: Codeunit "Library - Utility";
+ TemplatesFeatureEnabled: Boolean;
+
+ procedure DisableTemplatesFeature()
+ begin
+ UnbindSubscription(LibraryTemplates);
+ BindSubscription(LibraryTemplates);
+ LibraryTemplates.SetTemplatesFeatureEnabled(false);
+ end;
+
+ procedure EnableTemplatesFeature()
+ begin
+ UnbindSubscription(LibraryTemplates);
+ BindSubscription(LibraryTemplates);
+ LibraryTemplates.SetTemplatesFeatureEnabled(true);
+ end;
+
+ procedure CreateVendorTemplate(var VendorTempl: Record "Vendor Templ.")
+ begin
+ VendorTempl.Init();
+ VendorTempl.Validate(Code, LibraryUtility.GenerateRandomCode(VendorTempl.FieldNo(Code), Database::"Vendor Templ."));
+ VendorTempl.Validate(Description, VendorTempl.Code);
+ VendorTempl.Insert(true);
+ end;
+
+ procedure CreateVendorTemplateWithData(var VendorTempl: Record "Vendor Templ.")
+ var
+ GeneralPostingSetup: Record "General Posting Setup";
+ VATPostingSetup: Record "VAT Posting Setup";
+ VendorPostingGroup: Record "Vendor Posting Group";
+ PaymentMethod: Record "Payment Method";
+ begin
+ CreateVendorTemplate(VendorTempl);
+
+ LibraryPurchase.CreateVendorPostingGroup(VendorPostingGroup);
+ LibraryERM.FindGeneralPostingSetupInvtFull(GeneralPostingSetup);
+ LibraryERM.FindVATPostingSetupInvt(VATPostingSetup);
+ LibraryERM.FindPaymentMethod(PaymentMethod);
+
+ VendorTempl.Validate("Vendor Posting Group", VendorPostingGroup.Code);
+ VendorTempl.Validate("Gen. Bus. Posting Group", GeneralPostingSetup."Gen. Bus. Posting Group");
+ VendorTempl.Validate("VAT Bus. Posting Group", VATPostingSetup."VAT Bus. Posting Group");
+ VendorTempl.Validate("Payment Method Code", PaymentMethod.Code);
+ VendorTempl.Validate("Payment Terms Code", LibraryERM.FindPaymentTermsCode());
+ VendorTempl.Modify(true);
+ end;
+
+ procedure CreateVendorTemplateWithDataAndDimensions(var VendorTempl: Record "Vendor Templ.")
+ begin
+ CreateVendorTemplateWithData(VendorTempl);
+ CreateTemplateGlobalDimensions(Database::"Vendor Templ.", VendorTempl.Code);
+ CreateTemplateDimensions(Database::"Vendor Templ.", VendorTempl.Code);
+ end;
+
+ procedure CreateCustomerTemplate(var CustomerTempl: Record "Customer Templ.")
+ begin
+ CustomerTempl.Init();
+ CustomerTempl.Validate(Code, LibraryUtility.GenerateRandomCode(CustomerTempl.FieldNo(Code), Database::"Customer Templ."));
+ CustomerTempl.Validate(Description, CustomerTempl.Code);
+ CustomerTempl.Insert(true);
+ end;
+
+ procedure CreateCustomerTemplateWithData(var CustomerTempl: Record "Customer Templ.")
+ var
+ GeneralPostingSetup: Record "General Posting Setup";
+ VATPostingSetup: Record "VAT Posting Setup";
+ CustomerPostingGroup: Record "Customer Posting Group";
+ PaymentMethod: Record "Payment Method";
+ begin
+ CreateCustomerTemplate(CustomerTempl);
+
+ LibrarySales.CreateCustomerPostingGroup(CustomerPostingGroup);
+ LibraryERM.FindGeneralPostingSetupInvtFull(GeneralPostingSetup);
+ LibraryERM.FindVATPostingSetupInvt(VATPostingSetup);
+ LibraryERM.FindPaymentMethod(PaymentMethod);
+
+ CustomerTempl.Validate("Customer Posting Group", CustomerPostingGroup.Code);
+ CustomerTempl.Validate("Gen. Bus. Posting Group", GeneralPostingSetup."Gen. Bus. Posting Group");
+ CustomerTempl.Validate("VAT Bus. Posting Group", VATPostingSetup."VAT Bus. Posting Group");
+ CustomerTempl.Validate("Payment Method Code", PaymentMethod.Code);
+ CustomerTempl.Validate("Payment Terms Code", LibraryERM.FindPaymentTermsCode());
+ CustomerTempl.Modify(true);
+ end;
+
+ procedure CreateCustomerTemplateWithDataAndDimensions(var CustomerTempl: Record "Customer Templ.")
+ begin
+ CreateCustomerTemplateWithData(CustomerTempl);
+ CreateTemplateGlobalDimensions(Database::"Customer Templ.", CustomerTempl.Code);
+ CreateTemplateDimensions(Database::"Customer Templ.", CustomerTempl.Code);
+ end;
+
+ procedure CreateItemTemplate(var ItemTempl: Record "Item Templ.")
+ begin
+ ItemTempl.Init();
+ ItemTempl.Validate(Code, LibraryUtility.GenerateRandomCode(ItemTempl.FieldNo(Code), Database::"Item Templ."));
+ ItemTempl.Validate(Description, ItemTempl.Code);
+ ItemTempl.Insert(true);
+ end;
+
+ procedure CreateItemTemplateWithData(var ItemTempl: Record "Item Templ.")
+ var
+ GeneralPostingSetup: Record "General Posting Setup";
+ VATPostingSetup: Record "VAT Posting Setup";
+ InventoryPostingGroup: Record "Inventory Posting Group";
+ UnitofMeasure: Record "Unit of Measure";
+ begin
+ CreateItemTemplate(ItemTempl);
+
+ if not InventoryPostingGroup.FindFirst() then
+ LibraryInventory.CreateInventoryPostingGroup(InventoryPostingGroup);
+ LibraryERM.FindGeneralPostingSetupInvtFull(GeneralPostingSetup);
+ LibraryERM.FindVATPostingSetupInvt(VATPostingSetup);
+ LibraryInventory.CreateUnitOfMeasureCode(UnitofMeasure);
+
+ ItemTempl.Validate("Inventory Posting Group", InventoryPostingGroup.Code);
+ ItemTempl.Validate("Gen. Prod. Posting Group", GeneralPostingSetup."Gen. Prod. Posting Group");
+ ItemTempl.Validate("VAT Prod. Posting Group", VATPostingSetup."VAT Prod. Posting Group");
+ ItemTempl.Validate("Base Unit of Measure", UnitofMeasure.Code);
+ ItemTempl.Modify(true);
+ end;
+
+ procedure CreateItemTemplateWithDataAndDimensions(var ItemTempl: Record "Item Templ.")
+ begin
+ CreateItemTemplateWithData(ItemTempl);
+ CreateTemplateGlobalDimensions(Database::"Item Templ.", ItemTempl.Code);
+ CreateTemplateDimensions(Database::"Item Templ.", ItemTempl.Code);
+ end;
+
+ procedure CreateEmployeeTemplate(var EmployeeTempl: Record "Employee Templ.")
+ begin
+ EmployeeTempl.Init();
+ EmployeeTempl.Validate(Code, LibraryUtility.GenerateRandomCode(EmployeeTempl.FieldNo(Code), Database::"Employee Templ."));
+ EmployeeTempl.Validate(Description, EmployeeTempl.Code);
+ EmployeeTempl.Insert(true);
+ end;
+
+ procedure CreateEmployeeTemplateWithData(var EmployeeTempl: Record "Employee Templ.")
+ var
+ EmployeePostingGroup: Record "Employee Posting Group";
+ EmployeeStatisticsGroup: Record "Employee Statistics Group";
+ begin
+ CreateEmployeeTemplate(EmployeeTempl);
+
+ EmployeePostingGroup.Init();
+ EmployeePostingGroup.Validate(Code, LibraryUtility.GenerateRandomCode(EmployeePostingGroup.FieldNo(Code), Database::"Employee Posting Group"));
+ EmployeePostingGroup.Insert();
+
+ EmployeeStatisticsGroup.Init();
+ EmployeeStatisticsGroup.Validate(Code, LibraryUtility.GenerateRandomCode(EmployeeStatisticsGroup.FieldNo(Code), Database::"Employee Statistics Group"));
+ EmployeeStatisticsGroup.Insert();
+
+ EmployeeTempl.Validate("Employee Posting Group", EmployeePostingGroup.Code);
+ EmployeeTempl.Validate("Statistics Group Code", EmployeeStatisticsGroup.Code);
+ EmployeeTempl.Modify(true);
+ end;
+
+ procedure CreateEmployeeTemplateWithDataAndDimensions(var EmployeeTempl: Record "Employee Templ.")
+ begin
+ CreateEmployeeTemplateWithData(EmployeeTempl);
+ CreateTemplateGlobalDimensions(Database::"Employee Templ.", EmployeeTempl.Code);
+ CreateTemplateDimensions(Database::"Employee Templ.", EmployeeTempl.Code);
+ end;
+
+ procedure CreateTemplateGlobalDimensions(TemplateTableId: Integer; TemplateCode: Code[20])
+ var
+ DimensionValue: Record "Dimension Value";
+ DefaultDimension: Record "Default Dimension";
+ i: Integer;
+ begin
+ for i := 1 to 2 do begin
+ LibraryDimension.GetGlobalDimCodeValue(i, DimensionValue);
+ LibraryDimension.CreateDefaultDimension(DefaultDimension, TemplateTableId, TemplateCode, DimensionValue."Dimension Code", DimensionValue.Code);
+ end;
+ end;
+
+ procedure CreateTemplateDimensions(TemplateTableId: Integer; TemplateCode: Code[20])
+ var
+ DimensionValue: Record "Dimension Value";
+ DefaultDimension: Record "Default Dimension";
+ i: Integer;
+ begin
+ for i := 1 to LibraryRandom.RandIntInRange(2, 5) do begin
+ LibraryDimension.CreateDimWithDimValue(DimensionValue);
+ LibraryDimension.CreateDefaultDimension(DefaultDimension, TemplateTableId, TemplateCode, DimensionValue."Dimension Code", DimensionValue.Code);
+ end;
+ end;
+
+ procedure SetTemplatesFeatureEnabled(NewTemplatesFeatureEnabled: Boolean)
+ begin
+ TemplatesFeatureEnabled := NewTemplatesFeatureEnabled;
+ end;
+
+ procedure UpdateTemplatesVATGroups()
+ var
+ VATPostingSetup: Record "VAT Posting Setup";
+ CustomerTempl: Record "Customer Templ.";
+ VendorTempl: Record "Vendor Templ.";
+ ItemTempl: Record "Item Templ.";
+ begin
+ LibraryERM.FindVATPostingSetup(VATPostingSetup, VATPostingSetup."VAT Calculation Type"::"Normal VAT");
+
+ CustomerTempl.SetRange("VAT Bus. Posting Group", '');
+ CustomerTempl.ModifyAll("VAT Bus. Posting Group", VATPostingSetup."VAT Bus. Posting Group");
+ VendorTempl.SetRange("VAT Bus. Posting Group", '');
+ VendorTempl.ModifyAll("VAT Bus. Posting Group", VATPostingSetup."VAT Bus. Posting Group");
+ ItemTempl.SetRange("VAT Prod. Posting Group", '');
+ ItemTempl.ModifyAll("VAT Prod. Posting Group", VATPostingSetup."VAT Prod. Posting Group");
+ end;
+
+ [EventSubscriber(ObjectType::Codeunit, Codeunit::"Template Feature Mgt.", 'OnAfterIsEnabled', '', false, false)]
+ local procedure OnAfterIsEnabledHandler(var Result: Boolean)
+ begin
+ Result := TemplatesFeatureEnabled;
+ end;
+}
\ No newline at end of file
diff --git a/Apps/W1/ApplicationTestLibrary/LibraryTestInitialize.Codeunit.al b/Apps/W1/ApplicationTestLibrary/LibraryTestInitialize.Codeunit.al
new file mode 100644
index 0000000000..05b40638d1
--- /dev/null
+++ b/Apps/W1/ApplicationTestLibrary/LibraryTestInitialize.Codeunit.al
@@ -0,0 +1,26 @@
+///
+/// Provides test initialization integration events for coordinating test setup across different test libraries.
+///
+codeunit 132250 "Library - Test Initialize"
+{
+
+ trigger OnRun()
+ begin
+ end;
+
+ [IntegrationEvent(false, false)]
+ procedure OnTestInitialize(CallerCodeunitID: Integer)
+ begin
+ end;
+
+ [IntegrationEvent(false, false)]
+ procedure OnBeforeTestSuiteInitialize(CallerCodeunitID: Integer)
+ begin
+ end;
+
+ [IntegrationEvent(true, false)]
+ procedure OnAfterTestSuiteInitialize(CallerCodeunitID: Integer)
+ begin
+ end;
+}
+
diff --git a/Apps/W1/ApplicationTestLibrary/LibraryTimeSheet.Codeunit.al b/Apps/W1/ApplicationTestLibrary/LibraryTimeSheet.Codeunit.al
new file mode 100644
index 0000000000..ceff3b9dea
--- /dev/null
+++ b/Apps/W1/ApplicationTestLibrary/LibraryTimeSheet.Codeunit.al
@@ -0,0 +1,571 @@
+///
+/// Provides utility functions for creating and managing timesheets in test scenarios, including time sheet lines and resource time sheets.
+///
+codeunit 131904 "Library - Time Sheet"
+{
+ EventSubscriberInstance = Manual;
+
+ trigger OnRun()
+ begin
+ end;
+
+ var
+ ResourcesSetup: Record "Resources Setup";
+ TempTimeSheetLine: Record "Time Sheet Line" temporary;
+ Assert: Codeunit Assert;
+ LibraryRandom: Codeunit "Library - Random";
+ LibraryUtility: Codeunit "Library - Utility";
+ LibraryERM: Codeunit "Library - ERM";
+ LibraryResource: Codeunit "Library - Resource";
+ LibraryInventory: Codeunit "Library - Inventory";
+ LibraryWarehouse: Codeunit "Library - Warehouse";
+ LibraryAssembly: Codeunit "Library - Assembly";
+ TimeSheetApprovalMgt: Codeunit "Time Sheet Approval Management";
+ Initialized: Boolean;
+ NoSeriesCode: Label 'TS';
+ TimeSheetFieldValueErr: Label 'Time Sheet field %1 value is incorrect.';
+
+ procedure Initialize()
+ var
+ LibraryERMCountryData: Codeunit "Library - ERM Country Data";
+ begin
+ if Initialized then
+ exit;
+
+ if not ResourcesSetup.Get() then begin
+ ResourcesSetup.Init();
+ ResourcesSetup.Insert();
+ end;
+
+ if ResourcesSetup."Time Sheet Nos." = '' then begin
+ ResourcesSetup.Validate("Time Sheet Nos.", GetTimeSheetNoSeries());
+ ResourcesSetup.Modify();
+ end;
+
+ Initialized := true;
+ LibraryERMCountryData.CreateVATData();
+
+ Commit();
+ end;
+
+ procedure CheckAssemblyTimeSheetLine(TimeSheetHeader: Record "Time Sheet Header"; AssemblyHeaderNo: Code[20]; AssemblyLineNo: Integer; AssemblyLineQuantity: Decimal)
+ var
+ TimeSheetLine: Record "Time Sheet Line";
+ begin
+ TimeSheetLine.SetRange("Time Sheet No.", TimeSheetHeader."No.");
+ TimeSheetLine.SetRange("Assembly Order No.", AssemblyHeaderNo);
+ TimeSheetLine.SetRange("Assembly Order Line No.", AssemblyLineNo);
+ TimeSheetLine.FindLast();
+ TimeSheetLine.CalcFields("Total Quantity");
+
+ Assert.AreEqual(AssemblyLineQuantity, TimeSheetLine."Total Quantity",
+ StrSubstNo(TimeSheetFieldValueErr, TimeSheetLine.FieldCaption("Total Quantity")));
+ Assert.IsTrue(TimeSheetLine.Chargeable, StrSubstNo(TimeSheetFieldValueErr, TimeSheetLine.FieldCaption(Chargeable)));
+ Assert.AreEqual(TimeSheetLine.Status::Approved, TimeSheetLine.Status,
+ StrSubstNo(TimeSheetFieldValueErr, TimeSheetLine.FieldCaption(Status)));
+ Assert.IsTrue(TimeSheetLine.Posted, StrSubstNo(TimeSheetFieldValueErr, TimeSheetLine.FieldCaption(Posted)));
+ end;
+
+#if not CLEAN27
+ [Obsolete('Moved to codeunit Library Service', '27.0')]
+ procedure CheckServiceTimeSheetLine(TimeSheetHeader: Record "Time Sheet Header"; ServiceHeaderNo: Code[20]; ServiceLineNo: Integer; ServiceLineQuantity: Decimal; Chargeable: Boolean)
+ var
+ LibraryService: Codeunit "Library - Service";
+ begin
+ LibraryService.CheckServiceTimeSheetLine(TimeSheetHeader, ServiceHeaderNo, ServiceLineNo, ServiceLineQuantity, Chargeable);
+ end;
+#endif
+
+ procedure CreateJobJournalLine(var JobJournalLine: Record "Job Journal Line"; JournalTemplateName: Code[10]; JournalBatchName: Code[10])
+ var
+ RecRef: RecordRef;
+ begin
+ JobJournalLine.Init();
+ JobJournalLine.Validate("Journal Template Name", JournalTemplateName);
+ JobJournalLine.Validate("Journal Batch Name", JournalBatchName);
+ RecRef.GetTable(JobJournalLine);
+ JobJournalLine.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, JobJournalLine.FieldNo("Line No.")));
+ JobJournalLine.Insert(true);
+ end;
+
+ procedure CreateJobPlanningLine(var JobPlanningLine: Record "Job Planning Line"; JobNo: Code[20]; JobTaskNo: Code[20]; ResourceNo: Code[20]; PlanningDate: Date)
+ var
+ LineNo: Integer;
+ begin
+ JobPlanningLine.SetRange("Job No.", JobNo);
+ JobPlanningLine.SetRange("Job Task No.", JobTaskNo);
+ if JobPlanningLine.FindLast() then;
+ LineNo := JobPlanningLine."Line No." + 10000;
+
+ JobPlanningLine.Init();
+ JobPlanningLine."Job No." := JobNo;
+ JobPlanningLine."Job Task No." := JobTaskNo;
+ JobPlanningLine."Line No." := LineNo;
+ JobPlanningLine.Type := JobPlanningLine.Type::Resource;
+ JobPlanningLine."No." := ResourceNo;
+ JobPlanningLine."Planning Date" := PlanningDate;
+ JobPlanningLine.Insert();
+ end;
+
+ procedure CreateTimeSheet(var TimeSheetHeader: Record "Time Sheet Header"; UseCurrentUserID: Boolean)
+ var
+ UserSetup: Record "User Setup";
+ Resource: Record Resource;
+ AccountingPeriod: Record "Accounting Period";
+ Date: Record Date;
+ CreateTimeSheets: Report "Create Time Sheets";
+ begin
+ // function creates user setup, time sheet resource and time sheet header
+
+ // create user setup
+ CreateUserSetup(UserSetup, UseCurrentUserID);
+
+ // resource - person
+ CreateTimeSheetResource(Resource);
+ Resource.Validate("Time Sheet Owner User ID", UserSetup."User ID");
+ Resource.Validate("Time Sheet Approver User ID", UserId);
+ Resource.Modify();
+
+ // find first open accounting period
+ GetAccountingPeriod(AccountingPeriod);
+
+ // find first DOW after accounting period starting date
+ Date.SetRange("Period Type", Date."Period Type"::Date);
+ Date.SetFilter("Period Start", '%1..', AccountingPeriod."Starting Date");
+ Date.SetRange("Period No.", ResourcesSetup."Time Sheet First Weekday" + 1);
+ Date.FindFirst();
+
+ WorkDate := Date."Period Start";
+
+ // create time sheet
+ CreateTimeSheets.InitParameters(Date."Period Start", 1, Resource."No.", false, true);
+ CreateTimeSheets.UseRequestPage(false);
+ CreateTimeSheets.Run();
+
+ // find created time sheet
+ TimeSheetHeader.SetRange("Resource No.", Resource."No.");
+ TimeSheetHeader.FindFirst();
+ end;
+
+ procedure CreateTimeSheetLine(TimeSheetHeader: Record "Time Sheet Header"; var TimeSheetLine: Record "Time Sheet Line"; Type: Enum "Time Sheet Line Type"; JobNo: Code[20]; JobTaskNo: Code[20]; ServiceOrderNo: Code[20]; CauseOfAbsenceCode: Code[10])
+ var
+ LineNo: Integer;
+ begin
+ LineNo := TimeSheetHeader.GetLastLineNo() + 10000;
+
+ TimeSheetLine.Init();
+ TimeSheetLine."Time Sheet No." := TimeSheetHeader."No.";
+ TimeSheetLine."Line No." := LineNo;
+ TimeSheetLine.Type := Type;
+ case Type of
+ Type::Job:
+ begin
+ TimeSheetLine.Validate("Job No.", JobNo);
+ TimeSheetLine.Validate("Job Task No.", JobTaskNo);
+ end;
+ Type::Service:
+ TimeSheetLine.Validate("Service Order No.", ServiceOrderNo);
+ Type::Absence:
+ TimeSheetLine.Validate("Cause of Absence Code", CauseOfAbsenceCode);
+ end;
+ TimeSheetLine.Insert(true);
+ end;
+
+ procedure CreateTimeSheetDetail(TimeSheetLine: Record "Time Sheet Line"; Date: Date; Quantity: Decimal)
+ var
+ TimeSheetDetail: Record "Time Sheet Detail";
+ begin
+ TimeSheetDetail.Init();
+ TimeSheetDetail."Time Sheet No." := TimeSheetLine."Time Sheet No.";
+ TimeSheetDetail."Time Sheet Line No." := TimeSheetLine."Line No.";
+ TimeSheetDetail.Date := Date;
+ TimeSheetDetail.CopyFromTimeSheetLine(TimeSheetLine);
+ TimeSheetDetail.Quantity := Quantity;
+ TimeSheetDetail.Insert();
+ end;
+
+ procedure CreateTimeSheetResource(var Resource: Record Resource)
+ var
+ ResourceUnitOfMeasure: Record "Resource Unit of Measure";
+ HumanResourceUnitOfMeasure: Record "Human Resource Unit of Measure";
+ VATPostingSetup: Record "VAT Posting Setup";
+ begin
+ LibraryERM.FindVATPostingSetup(VATPostingSetup, VATPostingSetup."VAT Calculation Type"::"Normal VAT");
+ LibraryResource.CreateResource(Resource, VATPostingSetup."VAT Bus. Posting Group");
+ // take base unit of measure from table 5220 to be allowed register employee absence
+ FindHRUnitOfMeasure(HumanResourceUnitOfMeasure);
+ if not ResourceUnitOfMeasure.Get(Resource."No.", HumanResourceUnitOfMeasure.Code) then
+ LibraryResource.CreateResourceUnitOfMeasure(
+ ResourceUnitOfMeasure, Resource."No.", HumanResourceUnitOfMeasure.Code, 1);
+ Resource.Validate("Base Unit of Measure", HumanResourceUnitOfMeasure.Code);
+ Resource."Use Time Sheet" := true;
+ Resource.Modify();
+ end;
+
+#if not CLEAN27
+ [Obsolete('Moved to codeunit Library Service', '27.0')]
+ procedure CreateServiceOrder(var ServiceHeader: Record "Service Header"; PostingDate: Date)
+ var
+ LibraryService: Codeunit "Library - Service";
+ begin
+ LibraryService.CreateServiceOrder(ServiceHeader, PostingDate);
+ end;
+#endif
+
+ procedure CreateUserSetup(var UserSetup: Record "User Setup"; CurrUserID: Boolean)
+ begin
+ UserSetup.Init();
+ if CurrUserID then begin
+ UserSetup."User ID" := CopyStr(UserId(), 1, MaxStrLen(UserSetup."User ID"));
+ UserSetup."Time Sheet Admin." := true;
+ end else
+ UserSetup."User ID" :=
+ CopyStr(
+ LibraryUtility.GenerateRandomCode(UserSetup.FieldNo("User ID"), DATABASE::"User Setup"), 1, MaxStrLen(UserSetup."User ID"));
+ if UserSetup.Insert() then;
+ end;
+
+ procedure CreateWorkType(var WorkType: Record "Work Type"; ResourceBUOM: Code[10])
+ begin
+ WorkType.Init();
+ WorkType.Validate(Code, CopyStr(Format(CreateGuid()), 1, MaxStrLen(WorkType.Code)));
+ WorkType.Insert(true);
+ WorkType.Validate(Description, 'test work type');
+ WorkType.Validate("Unit of Measure Code", ResourceBUOM);
+ WorkType.Modify();
+ end;
+
+ procedure CreateHRUnitOfMeasure(var HumanResourceUnitOfMeasure: Record "Human Resource Unit of Measure"; QtyPerUnitOfMeasure: Decimal)
+ var
+ UnitOfMeasure: Record "Unit of Measure";
+ begin
+ LibraryInventory.CreateUnitOfMeasureCode(UnitOfMeasure);
+ HumanResourceUnitOfMeasure.Init();
+ HumanResourceUnitOfMeasure.Validate(Code, UnitOfMeasure.Code);
+ HumanResourceUnitOfMeasure.Validate("Qty. per Unit of Measure", QtyPerUnitOfMeasure);
+ HumanResourceUnitOfMeasure.Insert(true);
+ end;
+
+ procedure CreateCauseOfAbsence(var CauseOfAbsence: Record "Cause of Absence")
+ var
+ HumanResourceUnitOfMeasure: Record "Human Resource Unit of Measure";
+ begin
+ CreateHRUnitOfMeasure(HumanResourceUnitOfMeasure, 1);
+
+ CauseOfAbsence.Init();
+ CauseOfAbsence.Validate(Code, LibraryUtility.GenerateGUID());
+ CauseOfAbsence.Validate(Description, LibraryUtility.GenerateGUID());
+ CauseOfAbsence.Validate("Unit of Measure Code", HumanResourceUnitOfMeasure.Code);
+ CauseOfAbsence.Insert(true);
+ end;
+
+ procedure FindCauseOfAbsence(var CauseOfAbsence: Record "Cause of Absence")
+ var
+ HumanResourceUnitOfMeasure: Record "Human Resource Unit of Measure";
+ begin
+ CauseOfAbsence.FindFirst();
+ if CauseOfAbsence."Unit of Measure Code" = '' then begin
+ HumanResourceUnitOfMeasure.FindFirst();
+ CauseOfAbsence.Validate("Unit of Measure Code", HumanResourceUnitOfMeasure.Code);
+ CauseOfAbsence.Modify(true);
+ end;
+ end;
+
+ procedure FindHRUnitOfMeasure(var HumanResourceUnitOfMeasure: Record "Human Resource Unit of Measure")
+ begin
+ HumanResourceUnitOfMeasure.FindFirst();
+ end;
+
+ procedure FindJobJournalBatch(var JobJournalBatch: Record "Job Journal Batch"; JournalTemplateName: Code[10])
+ begin
+ JobJournalBatch.SetRange("Journal Template Name", JournalTemplateName);
+ JobJournalBatch.FindFirst();
+ end;
+
+ procedure FindJobJournalTemplate(var JobJournalTemplate: Record "Job Journal Template")
+ begin
+ JobJournalTemplate.FindFirst();
+ end;
+
+ procedure FindJob(var Job: Record Job)
+ begin
+ Job.SetFilter("Person Responsible", '<>''''');
+ Job.SetFilter(Status, '<>%1', Job.Status::Completed);
+ Job.FindFirst();
+ end;
+
+ procedure FindJobTask(JobNo: Code[20]; var JobTask: Record "Job Task")
+ begin
+ JobTask.SetRange("Job No.", JobNo);
+ JobTask.SetRange("Job Task Type", JobTask."Job Task Type"::Posting);
+ JobTask.FindFirst();
+ end;
+
+ procedure GetAccountingPeriod(var AccountingPeriod: Record "Accounting Period")
+ var
+ StartingDate: Date;
+ begin
+ // find first open accounting period
+ AccountingPeriod.SetRange(Closed, false);
+ if not AccountingPeriod.FindFirst() then begin
+ // if accounting period is not found then create new one
+ AccountingPeriod.Reset();
+ if AccountingPeriod.FindLast() then
+ StartingDate := CalcDate('<+1M>', AccountingPeriod."Starting Date")
+ else
+ StartingDate := CalcDate('', Today);
+ AccountingPeriod.Init();
+ AccountingPeriod."Starting Date" := StartingDate;
+ AccountingPeriod.Insert();
+ end;
+ end;
+
+ procedure GetRandomDecimal(): Decimal
+ begin
+ exit(LibraryRandom.RandInt(9999) / 100);
+ end;
+
+ procedure GetTimeSheetNoSeries(): Code[20]
+ var
+ NoSeries: Record "No. Series";
+ NoSeriesLine: Record "No. Series Line";
+ begin
+ if not NoSeries.Get(NoSeriesCode) then begin
+ LibraryUtility.CreateNoSeries(NoSeries, true, false, false);
+ NoSeries.Rename(NoSeriesCode);
+ LibraryUtility.CreateNoSeriesLine(NoSeriesLine, NoSeries.Code, '', '')
+ end;
+
+ exit(NoSeries.Code)
+ end;
+
+ [Scope('OnPrem')]
+ procedure GetTimeSheetLineBuffer(var TimeSheetLine: Record "Time Sheet Line")
+ begin
+ if TempTimeSheetLine.FindSet() then
+ repeat
+ TimeSheetLine := TempTimeSheetLine;
+ TimeSheetLine.Insert();
+ until TempTimeSheetLine.Next() = 0;
+ end;
+
+ procedure InitAssemblyBackwayScenario(var TimeSheetHeader: Record "Time Sheet Header"; var AssemblyHeader: Record "Assembly Header"; var AssemblyLine: Record "Assembly Line"; TimeSheetExists: Boolean)
+ var
+ Location: Record Location;
+ UserSetup: Record "User Setup";
+ Resource: Record Resource;
+ Item: array[2] of Record Item;
+ BOMComponent: Record "BOM Component";
+ ItemJournalLine: Record "Item Journal Line";
+ ItemJournalTemplate: Record "Item Journal Template";
+ ItemJournalBatch: Record "Item Journal Batch";
+ GeneralPostingSetup: Record "General Posting Setup";
+ ItemCount: Integer;
+ Date: Date;
+ begin
+ if TimeSheetExists then begin
+ // create time sheet
+ CreateTimeSheet(TimeSheetHeader, false);
+ Resource.Get(TimeSheetHeader."Resource No.");
+ Date := TimeSheetHeader."Starting Date";
+ end else begin
+ // set up without tine sheet; create resource
+ Date := WorkDate();
+ CreateUserSetup(UserSetup, false);
+ CreateTimeSheetResource(Resource);
+ Resource.Validate("Time Sheet Owner User ID", UserSetup."User ID");
+ Resource.Validate("Time Sheet Approver User ID", UserId);
+ end;
+
+ LibraryERM.FindGeneralPostingSetupInvtFull(GeneralPostingSetup);
+ Resource.Validate("Gen. Prod. Posting Group", GeneralPostingSetup."Gen. Prod. Posting Group");
+ Resource.Modify();
+
+ LibraryWarehouse.CreateLocationWithInventoryPostingSetup(Location);
+
+ // get items on the location (pos.adjmt.)
+ LibraryInventory.SelectItemJournalTemplateName(ItemJournalTemplate, ItemJournalTemplate.Type::Item);
+ LibraryInventory.SelectItemJournalBatchName(ItemJournalBatch, ItemJournalTemplate.Type, ItemJournalTemplate.Name);
+ LibraryInventory.ClearItemJournal(ItemJournalTemplate, ItemJournalBatch);
+
+ for ItemCount := 1 to 2 do begin
+ LibraryInventory.CreateItem(Item[ItemCount]);
+ LibraryInventory.CreateItemJournalLine(ItemJournalLine, ItemJournalBatch."Journal Template Name", ItemJournalBatch.Name,
+ ItemJournalLine."Entry Type"::"Positive Adjmt.", Item[ItemCount]."No.", 10);
+ ItemJournalLine.Validate("Location Code", Location.Code);
+ ItemJournalLine.Modify();
+ end;
+
+ LibraryInventory.PostItemJournalLine(ItemJournalBatch."Journal Template Name", ItemJournalBatch.Name);
+
+ // create complicated item
+ LibraryInventory.CreateBOMComponent(BOMComponent, Item[1]."No.", BOMComponent.Type::Item, Item[2]."No.", 2, '');
+
+ // create assembly order with lines
+ LibraryAssembly.CreateAssemblyHeader(AssemblyHeader, CalcDate('<+7D>', Date), Item[1]."No.", Location.Code, 2, '');
+ AssemblyHeader.Validate("Posting Date", CalcDate('<+3D>', Date));
+ AssemblyHeader.Modify();
+ LibraryAssembly.CreateAssemblyLine(
+ AssemblyHeader, AssemblyLine, "BOM Component Type"::Resource, Resource."No.", Resource."Base Unit of Measure", 8, 8, 'Working resource');
+ end;
+
+#if not CLEAN27
+ [Obsolete('Moved to codeunit Library Service', '27.0')]
+ procedure InitBackwayScenario(var TimeSheetHeader: Record "Time Sheet Header"; var ServiceHeader: Record "Service Header"; var ServiceLine: Record "Service Line")
+ var
+ LibraryService: Codeunit "Library - Service";
+ begin
+ LibraryService.InitBackwayScenario(TimeSheetHeader, ServiceHeader, ServiceLine);
+ end;
+#endif
+
+ procedure InitJobScenario(var TimeSheetHeader: Record "Time Sheet Header"; var TimeSheetLine: Record "Time Sheet Line")
+ var
+ Resource: Record Resource;
+ Job: Record Job;
+ JobTask: Record "Job Task";
+ begin
+ // create time sheet
+ CreateTimeSheet(TimeSheetHeader, false);
+
+ // create time sheet line with type Job
+ // find job and task
+ FindJob(Job);
+ FindJobTask(Job."No.", JobTask);
+ // job's responsible person (resource) must have Owner ID filled in
+ Resource.Get(Job."Person Responsible");
+ Resource."Time Sheet Owner User ID" := CopyStr(UserId(), 1, MaxStrLen(Resource."Time Sheet Owner User ID"));
+ Resource.Modify();
+ CreateTimeSheetLine(TimeSheetHeader, TimeSheetLine, TimeSheetLine.Type::Job, Job."No.",
+ JobTask."Job Task No.", '', '');
+
+ // set quantity for line
+ CreateTimeSheetDetail(TimeSheetLine, TimeSheetHeader."Starting Date", GetRandomDecimal());
+ // submit and approve line
+ TimeSheetApprovalMgt.Submit(TimeSheetLine);
+ TimeSheetApprovalMgt.Approve(TimeSheetLine);
+ end;
+
+ procedure InitResourceScenario(var TimeSheetHeader: Record "Time Sheet Header"; var TimeSheetLine: Record "Time Sheet Line"; UseCurrentUserID: Boolean)
+ begin
+ // create time sheet
+ CreateTimeSheet(TimeSheetHeader, UseCurrentUserID);
+
+ // create time sheet lines with type Resource
+ CreateTimeSheetLine(TimeSheetHeader, TimeSheetLine, TimeSheetLine.Type::Resource, '', '', '', '');
+ TimeSheetLine.Description := TimeSheetHeader."Resource No.";
+ TimeSheetLine.Modify();
+
+ // set quantity for line
+ CreateTimeSheetDetail(TimeSheetLine, TimeSheetHeader."Starting Date", GetRandomDecimal());
+ // submit and approve line
+ TimeSheetApprovalMgt.Submit(TimeSheetLine);
+ TimeSheetApprovalMgt.Approve(TimeSheetLine);
+ end;
+
+ procedure InitScenarioWTForJob(var TimeSheetHeader: Record "Time Sheet Header")
+ var
+ TimeSheetLine: array[2] of Record "Time Sheet Line";
+ Resource: Record Resource;
+ Job: Record Job;
+ JobTask: Record "Job Task";
+ WorkType: Record "Work Type";
+ RowCount: Integer;
+ begin
+ // create time sheet
+ CreateTimeSheet(TimeSheetHeader, false);
+
+ for RowCount := 1 to 2 do begin
+ // create time sheet line with type Job
+ // find job and task
+ FindJob(Job);
+ FindJobTask(Job."No.", JobTask);
+ // job's responsible person (resource) must have Owner ID filled in
+ Resource.Get(Job."Person Responsible");
+ Resource."Time Sheet Owner User ID" := CopyStr(UserId(), 1, MaxStrLen(Resource."Time Sheet Owner User ID"));
+ Resource.Modify();
+ CreateTimeSheetLine(TimeSheetHeader, TimeSheetLine[RowCount], TimeSheetLine[RowCount].Type::Job, Job."No.",
+ JobTask."Job Task No.", '', '');
+ // change work type
+ if RowCount = 2 then begin
+ // create work type
+ Resource.Get(TimeSheetHeader."Resource No.");
+ CreateWorkType(WorkType, Resource."Base Unit of Measure");
+ TimeSheetLine[RowCount].Validate(Chargeable, false);
+ TimeSheetLine[RowCount].Validate("Work Type Code", WorkType.Code);
+ end;
+ TimeSheetLine[RowCount].Modify();
+ CreateTimeSheetDetail(TimeSheetLine[RowCount], TimeSheetHeader."Starting Date", GetRandomDecimal());
+ CreateTimeSheetDetail(TimeSheetLine[RowCount], TimeSheetHeader."Starting Date" + 1, GetRandomDecimal());
+ TimeSheetApprovalMgt.Submit(TimeSheetLine[RowCount]);
+ end;
+ end;
+
+#if not CLEAN27
+ [Obsolete('Moved to codeunit Library Service', '27.0')]
+ procedure InitScenarioWTForServiceOrder(var TimeSheetHeader: Record "Time Sheet Header"; var ServiceHeader: Record "Service Header")
+ var
+ LibraryService: Codeunit "Library - Service";
+ begin
+ LibraryService.InitScenarioWTForServiceOrder(TimeSheetHeader, ServiceHeader);
+ end;
+#endif
+
+#if not CLEAN27
+ [Obsolete('Moved to codeunit Library Service', '27.0')]
+ procedure InitServiceScenario(var TimeSheetHeader: Record "Time Sheet Header"; var TimeSheetLine: Record "Time Sheet Line"; var ServiceHeader: Record "Service Header")
+ var
+ LibraryService: Codeunit "Library - Service";
+ begin
+ LibraryService.InitServiceScenario(TimeSheetHeader, TimeSheetLine, ServiceHeader);
+ end;
+#endif
+
+ procedure SubmitTimeSheetLine(var TimeSheetLine: Record "Time Sheet Line")
+ begin
+ TimeSheetApprovalMgt.Submit(TimeSheetLine);
+ end;
+
+ procedure SubmitAndApproveTimeSheetLine(var TimeSheetLine: Record "Time Sheet Line")
+ begin
+ TimeSheetApprovalMgt.Submit(TimeSheetLine);
+ TimeSheetApprovalMgt.Approve(TimeSheetLine);
+ end;
+
+ procedure RunSuggestJobJnlLinesReportForResourceInPeriod(JobJournalLine: Record "Job Journal Line"; ResourceNo: Code[20]; StartingDate: Date; EndingDate: Date)
+ var
+ SuggestJobJnlLines: Report "Suggest Job Jnl. Lines";
+ begin
+ Commit();
+ Clear(SuggestJobJnlLines);
+ SuggestJobJnlLines.InitParameters(JobJournalLine, ResourceNo, '', '', StartingDate, EndingDate);
+ SuggestJobJnlLines.Run();
+ end;
+
+ procedure RunCreateTimeSheetsReport(StartDate: Date; NewNoOfPeriods: Integer; ResourceNo: Code[20])
+ var
+ CreateTimeSheets: Report "Create Time Sheets";
+ begin
+ Clear(CreateTimeSheets);
+ CreateTimeSheets.InitParameters(StartDate, NewNoOfPeriods, ResourceNo, false, true);
+ CreateTimeSheets.UseRequestPage(false);
+ CreateTimeSheets.Run();
+ end;
+
+ [EventSubscriber(ObjectType::Page, Page::"Manager Time Sheet", 'OnAfterProcess', '', false, false)]
+ local procedure OnAfterProcessManagerTimeSheet(var TimeSheetLine: Record "Time Sheet Line"; "Action": Option "Approve Selected","Approve All","Reopen Selected","Reopen All","Reject Selected","Reject All")
+ var
+ TimeSheetMgt: Codeunit "Time Sheet Management";
+ begin
+ TimeSheetMgt.CopyFilteredTimeSheetLinesToBuffer(TimeSheetLine, TempTimeSheetLine);
+ end;
+
+ [EventSubscriber(ObjectType::Page, Page::"Manager Time Sheet by Job", 'OnAfterProcess', '', false, false)]
+ local procedure OnAfterProcessManagerTimeSheetByJob(var TimeSheetLine: Record "Time Sheet Line"; "Action": Option "Approve Selected","Approve All","Reopen Selected","Reopen All","Reject Selected","Reject All")
+ var
+ TimeSheetMgt: Codeunit "Time Sheet Management";
+ begin
+ TimeSheetMgt.CopyFilteredTimeSheetLinesToBuffer(TimeSheetLine, TempTimeSheetLine);
+ end;
+}
+
diff --git a/Apps/W1/ApplicationTestLibrary/LibraryUtility.Codeunit.al b/Apps/W1/ApplicationTestLibrary/LibraryUtility.Codeunit.al
new file mode 100644
index 0000000000..a61e289e6d
--- /dev/null
+++ b/Apps/W1/ApplicationTestLibrary/LibraryUtility.Codeunit.al
@@ -0,0 +1,687 @@
+///
+/// Provides generic utility functions for test automation including record manipulation, field comparison, and no series management.
+///
+codeunit 131000 "Library - Utility"
+{
+
+ Permissions = TableData "FA Setup" = m;
+
+ trigger OnRun()
+ begin
+ end;
+
+ var
+ KeyNotFoundError: Label 'Field "%1" must be part of the primary key in the Table "%2".';
+ ERR_NotCompatible: Label 'The two records are not compatible to compare. Field number %1 has a type mismatch. Type %2 cannot be compared with type %3.';
+ PrimaryKeyNotCodeFieldErr: Label 'The primary key must be a single field of type Code to use this function.';
+ LibraryRandom: Codeunit "Library - Random";
+ LibraryNoSeries: Codeunit "Library - No. Series";
+ FieldOptionTypeErr: Label 'Field %1 in Table %2 must be option type.', Comment = '%1 - Field Name, %2 - Table Name';
+ GlobalNoSeriesCodeTok: Label 'GLOBAL', Locked = true;
+ GUIDTok: Label 'GUID', Locked = true;
+
+ procedure CreateNoSeries(var NoSeries: Record "No. Series"; Default: Boolean; Manual: Boolean; DateOrder: Boolean)
+ var
+ NoSeriesCode: Code[20];
+ begin
+ NoSeriesCode := NoSeries.Code + GenerateRandomCode(NoSeries.FieldNo(Code), DATABASE::"No. Series");
+ CreateNoSeries(NoSeriesCode, Default, Manual, DateOrder);
+ NoSeries.Get(NoSeriesCode);
+ end;
+
+ procedure CreateNoSeries(NoSeriesCode: Code[20]; Default: Boolean; Manual: Boolean; DateOrder: Boolean)
+ begin
+ LibraryNoSeries.CreateNoSeries(NoSeriesCode, Default, Manual, DateOrder);
+ end;
+
+ procedure CreateNoSeriesLine(var NoSeriesLine: Record "No. Series Line"; SeriesCode: Code[20]; StartingNo: Code[20]; EndingNo: Code[20])
+ begin
+ if StartingNo = '' then
+ StartingNo := PadStr(InsStr(SeriesCode, '00000000', 3), 10);
+ if EndingNo = '' then
+ EndingNo := PadStr(InsStr(SeriesCode, '99999999', 3), 10);
+ LibraryNoSeries.CreateNoSeriesLine(SeriesCode, 1, StartingNo, EndingNo);
+ NoSeriesLine.SetRange("Series Code", SeriesCode);
+ if NoSeriesLine.FindLast() then;
+ end;
+
+ procedure CreateRecordLink(RecVar: Variant): Integer
+ var
+ RecordLink: Record "Record Link";
+ begin
+ exit(CreateRecordLink(RecVar, RecordLink.Type::Note));
+ end;
+
+ procedure CreateRecordLink(RecVar: Variant; LinkType: Option): Integer
+ var
+ RecordLink: Record "Record Link";
+ PageManagement: Codeunit "Page Management";
+ RecRef: RecordRef;
+ begin
+ RecRef.GetTable(RecVar);
+ RecordLink."Record ID" := RecRef.RecordId();
+ RecordLink.URL1 := GetUrl(DefaultClientType, CompanyName, OBJECTTYPE::Page, PageManagement.GetPageID(RecVar), RecRef);
+ RecordLink.Type := LinkType;
+ RecordLink.Notify := true;
+ RecordLink.Company := CompanyName();
+ RecordLink."User ID" := UserId();
+ RecordLink."To User ID" := UserId();
+ RecordLink.Insert();
+ exit(RecordLink."Link ID");
+ end;
+
+ procedure CheckFieldExistenceInTable(TableNo: Integer; FieldName: Text[30]): Boolean
+ var
+ "Field": Record "Field";
+ begin
+ Field.SetRange(TableNo, TableNo);
+ Field.SetRange(FieldName, FieldName);
+ exit(Field.FindFirst())
+ end;
+
+ procedure CompareTwoRecords(RecRef1: RecordRef; RecRef2: RecordRef; FieldCountsToBeIgnored: Integer; DiscardDateTimeFields: Boolean; var FieldNumbersNotMatched: array[200] of Integer; var Value1: array[200] of Variant; var Value2: array[200] of Variant; var MismatchCount: Integer): Boolean
+ var
+ FieldRef1: FieldRef;
+ FieldRef2: FieldRef;
+ index1: Integer;
+ index2: Integer;
+ FldCount: Integer;
+ continue: Boolean;
+ begin
+ index1 := RecRef1.KeyIndex(1).FieldCount + 1;
+ index2 := RecRef2.KeyIndex(1).FieldCount + 1;
+ FldCount := RecRef1.FieldCount;
+ if RecRef2.FieldCount < RecRef1.FieldCount then
+ FldCount := RecRef2.FieldCount;
+ Clear(FieldNumbersNotMatched);
+ Clear(Value1);
+ Clear(Value2);
+ MismatchCount := 0;
+ while (index1 <= FldCount) and (index2 <= FldCount) do begin
+ if RecRef1.FieldIndex(index1).Number > RecRef2.FieldIndex(index2).Number then begin
+ index2 := index2 + 1;
+ continue := true;
+ end else
+ if RecRef2.FieldIndex(index2).Number > RecRef1.FieldIndex(index1).Number then begin
+ index1 := index1 + 1;
+ continue := true;
+ end;
+ if not continue then begin
+ FieldRef1 := RecRef1.FieldIndex(index1);
+ FieldRef2 := RecRef2.FieldIndex(index2);
+ if FieldRef1.Type <> FieldRef2.Type then
+ Error(ERR_NotCompatible, FieldRef1.Number, FieldRef1.Type, FieldRef2.Type);
+ if DiscardDateTimeFields and (FieldRef1.Type in [FieldType::Date, FieldType::Time, FieldType::DateTime]) then
+ continue := true;
+ if not continue then
+ if FieldRef1.Value <> FieldRef2.Value then begin
+ MismatchCount := MismatchCount + 1;
+ FieldNumbersNotMatched[MismatchCount] := FieldRef1.Number;
+ Value1[MismatchCount] := FieldRef1.Value();
+ Value2[MismatchCount] := FieldRef2.Value();
+ end;
+ index1 := index1 + 1;
+ index2 := index2 + 1;
+ end;
+ continue := false;
+ end;
+ if MismatchCount > FieldCountsToBeIgnored then
+ exit(false);
+ exit(true);
+ end;
+
+ procedure ConvertMilliSecToHours(TimePeriod: Decimal): Decimal
+ begin
+ exit(TimePeriod / 3600000);
+ end;
+
+ procedure ConvertHoursToMilliSec(TimePeriod: Decimal): Decimal
+ begin
+ exit(TimePeriod * 3600000);
+ end;
+
+ procedure ConvertNumericToText(NumericCode: Text): Text
+ begin
+ exit(ConvertStr(NumericCode, '0123456789', 'ABCDEFGHIJ'));
+ end;
+
+ procedure ConvertCRLFToBackSlash(TextIn: Text): Text
+ var
+ CRLF: Text;
+ Position: Integer;
+ begin
+ CRLF[1] := 13;
+ CRLF[2] := 10;
+ Position := StrPos(TextIn, CRLF);
+ while Position <> 0 do begin
+ TextIn := DelStr(TextIn, Position, StrLen(CRLF));
+ TextIn := InsStr(TextIn, '\', Position);
+ Position := StrPos(TextIn, CRLF);
+ end;
+ exit(TextIn);
+ end;
+
+ procedure FindFieldNoInTable(TableNo: Integer; FieldName: Text[30]): Integer
+ var
+ "Field": Record "Field";
+ begin
+ Field.SetRange(TableNo, TableNo);
+ Field.SetRange(FieldName, FieldName);
+ Field.FindFirst();
+ exit(Field."No.");
+ end;
+
+ procedure GetFieldLength(TableNo: Integer; FieldNo: Integer): Integer
+ var
+ RecRef: RecordRef;
+ FieldRef: FieldRef;
+ begin
+ RecRef.Open(TableNo);
+ FieldRef := RecRef.Field(FieldNo);
+ exit(FieldRef.Length);
+ end;
+
+ procedure GetLastTransactionNo(): Integer
+ var
+ GLEntry: Record "G/L Entry";
+ begin
+ if GLEntry.FindLast() then
+ exit(GLEntry."Transaction No.");
+
+ exit(0);
+ end;
+
+ procedure GetNewRecNo(RecVariant: Variant; FieldNo: Integer): Integer
+ var
+ RecRef: RecordRef;
+ begin
+ RecRef.GetTable(RecVariant);
+ exit(GetNewLineNo(RecRef, FieldNo));
+ end;
+
+ procedure GetNewLineNo(RecRef: RecordRef; FieldNo: Integer): Integer
+ var
+ RecRef2: RecordRef;
+ FieldRef: FieldRef;
+ FieldRef2: FieldRef;
+ KeyRef: KeyRef;
+ FieldCount: Integer;
+ LineNumberFound: Boolean;
+ begin
+ // Find the value of Line No. for a new line in the Record passed as Record Ref.
+ // 1. It is assumed that the field passed is part of the primary key.
+ // 2. It is assumed that all the primary key fields except Line No. field are already validated on the record.
+ RecRef2.Open(RecRef.Number, false, CompanyName);
+ KeyRef := RecRef.KeyIndex(1); // The Primary Key always has index as 1.
+ for FieldCount := 1 to KeyRef.FieldCount do begin
+ FieldRef := KeyRef.FieldIndex(FieldCount);
+ if FieldRef.Number <> FieldNo then begin
+ FieldRef2 := RecRef2.Field(FieldRef.Number);
+ FieldRef2.SetRange(FieldRef.Value); // Set filter on fields other than Line No with value as filled in on RecRef.
+ end else
+ LineNumberFound := true;
+ end;
+
+ if not LineNumberFound then begin
+ FieldRef := RecRef2.Field(FieldNo);
+ Error(KeyNotFoundError, FieldRef.Name, RecRef2.Name);
+ end;
+
+ if RecRef2.FindLast() then begin
+ FieldRef := RecRef2.Field(FieldNo);
+ FieldCount := FieldRef.Value();
+ end else
+ FieldCount := 0;
+ exit(FieldCount + 10000); // Add 10000 to the last Line No.
+ end;
+
+ procedure GetGlobalNoSeriesCode(): Code[20]
+ var
+ NoSeries: Record "No. Series";
+ begin
+ // Init, get the global no series
+ if not NoSeries.Get(GlobalNoSeriesCodeTok) then begin
+ LibraryNoSeries.CreateNoSeries(GlobalNoSeriesCodeTok, true, true, false);
+ LibraryNoSeries.CreateNoSeriesLine(GlobalNoSeriesCodeTok, 1,
+ PadStr(InsStr(GlobalNoSeriesCodeTok, '00000000', 3), 10),
+ PadStr(InsStr(GlobalNoSeriesCodeTok, '99999999', 3), 10));
+ end;
+
+ exit(GlobalNoSeriesCodeTok)
+ end;
+
+ procedure GetNextNoSeriesSalesDate(NoSeriesCode: Code[20]): Date
+ var
+ NoSeries: Record "No. Series";
+ begin
+ if NoSeriesCode <> '' then begin
+ NoSeries.Get(NoSeriesCode);
+ NoSeries.TestField("Date Order", false); // Use of Date Order is only tested on IT
+ end;
+ exit(WorkDate());
+ end;
+
+ procedure GetNextNoSeriesPurchaseDate(NoSeriesCode: Code[20]): Date
+ var
+ NoSeries: Record "No. Series";
+ begin
+ if NoSeriesCode <> '' then begin
+ NoSeries.Get(NoSeriesCode);
+ NoSeries.TestField("Date Order", false); // Use of Date Order is only tested on IT
+ end;
+ exit(WorkDate());
+ end;
+
+ procedure GetNextNoFromNoSeries(NoSeriesCode: Code[20]; PostingDate: Date): Code[20]
+ var
+ NoSeries: Codeunit "No. Series";
+ begin
+ exit(NoSeries.PeekNextNo(NoSeriesCode, PostingDate));
+ end;
+
+ procedure GenerateRandomCode(FieldNo: Integer; TableNo: Integer): Code[10]
+ var
+ RecRef: RecordRef;
+ FieldRef: FieldRef;
+ begin
+ // Create a random and unique code for the any code field.
+ RecRef.Open(TableNo, true, CompanyName);
+ Clear(FieldRef);
+ FieldRef := RecRef.Field(FieldNo);
+
+ repeat
+ if FieldRef.Length < 10 then
+ FieldRef.SetRange(CopyStr(GenerateGUID(), 10 - FieldRef.Length + 1)) // Cut characters on the left side.
+ else
+ FieldRef.SetRange(GenerateGUID());
+ until RecRef.IsEmpty();
+
+ exit(FieldRef.GetFilter)
+ end;
+
+ procedure GenerateRandomCodeWithLength(FieldNo: Integer; TableNo: Integer; CodeLength: Integer): Code[10]
+ var
+ RecRef: RecordRef;
+ FieldRef: FieldRef;
+ NewCode: Code[10];
+ begin
+ // Create a random and unique code for the any code field.
+ RecRef.Open(TableNo, false, CompanyName);
+ Clear(FieldRef);
+ FieldRef := RecRef.Field(FieldNo);
+ repeat
+ NewCode := CopyStr(GenerateRandomXMLText(CodeLength), 1, MaxStrLen(NewCode));
+ FieldRef.SetRange(NewCode);
+ until RecRef.IsEmpty();
+
+ exit(NewCode);
+ end;
+
+ procedure GenerateRandomCode20(FieldNo: Integer; TableNo: Integer): Code[20]
+ var
+ RecRef: RecordRef;
+ FieldRef: FieldRef;
+ begin
+ // Create a random and unique 20 code for the any code field.
+ RecRef.Open(TableNo, false, CompanyName);
+ Clear(FieldRef);
+ FieldRef := RecRef.Field(FieldNo);
+ repeat
+ FieldRef.SetRange(PadStr(GenerateGUID(), FieldRef.Length, '0'));
+ until RecRef.IsEmpty();
+
+ exit(FieldRef.GetFilter);
+ end;
+
+ procedure GenerateRandomText(Length: Integer) String: Text
+ var
+ i: Integer;
+ begin
+ // Create a random string of length .
+ for i := 1 to Length do
+ String[i] := LibraryRandom.RandIntInRange(33, 126); // ASCII: ! (33) to ~ (126)
+
+ exit(String)
+ end;
+
+ procedure GenerateRandomUnicodeText(Length: Integer) String: Text
+ var
+ i: Integer;
+ begin
+ // Create a random string of length with Unicode characters.
+ for i := 1 to Length do
+ String[i] := LibraryRandom.RandIntInRange(1072, 1103); // Cyrillic alphabet (to guarantee only printable chars)
+
+ exit(String)
+ end;
+
+ procedure GenerateRandomXMLText(Length: Integer) String: Text
+ var
+ i: Integer;
+ Number: Integer;
+ begin
+ // Create a random string of length containing characters allowed by XML
+ for i := 1 to Length do begin
+ Number := LibraryRandom.RandIntInRange(0, 1000) mod 61;
+ case Number of
+ 0 .. 9:
+ Number += 48; // 0-9
+ 10 .. 35:
+ Number += 65 - 10; // A-Z
+ 36 .. 61:
+ Number += 97 - 36; // a-z
+ end;
+ String[i] := Number;
+ end;
+ end;
+
+ procedure GenerateRandomNumericText(Length: Integer) String: Text
+ var
+ i: Integer;
+ begin
+ for i := 1 to Length do
+ String[i] := LibraryRandom.RandIntInRange(48, 57);
+ end;
+
+ procedure GenerateRandomAlphabeticText(Length: Integer; Option: Option Capitalized,Literal) String: Text
+ var
+ ASCIICodeFrom: Integer;
+ ASCIICodeTo: Integer;
+ Number: Integer;
+ i: Integer;
+ begin
+ case Option of
+ Option::Capitalized:
+ begin
+ ASCIICodeFrom := 65;
+ ASCIICodeTo := 90;
+ end;
+ Option::Literal:
+ begin
+ ASCIICodeFrom := 97;
+ ASCIICodeTo := 122;
+ end;
+ else
+ exit;
+ end;
+ for i := 1 to Length do begin
+ Number := LibraryRandom.RandIntInRange(ASCIICodeFrom, ASCIICodeTo);
+ String[i] := Number;
+ end;
+ end;
+
+ procedure GenerateRandomEmail(): Text[45]
+ begin
+ exit(GenerateRandomAlphabeticText(20, 1) + '@' + GenerateRandomAlphabeticText(20, 1) + '.' + GenerateRandomAlphabeticText(3, 1));
+ end;
+
+ procedure GenerateRandomEmails(): Text[80]
+ begin
+ exit(
+ StrSubstNo('%1@%2.%3; ', GenerateRandomXMLText(10), GenerateRandomXMLText(10), GenerateRandomXMLText(3)) +
+ StrSubstNo('%1@%2.%3; ', GenerateRandomXMLText(10), GenerateRandomXMLText(10), GenerateRandomXMLText(3)) +
+ StrSubstNo('%1@%2.%3', GenerateRandomXMLText(10), GenerateRandomXMLText(10), GenerateRandomXMLText(3)));
+ end;
+
+ procedure GenerateRandomPhoneNo(): Text[20]
+ var
+ PlusSign: Text[1];
+ OpenBracket: Text[1];
+ CloseBracket: Text[1];
+ Delimiter: Text[1];
+ begin
+ // +123 (456) 1234-1234
+ // 123 456 12341234
+ if LibraryRandom.RandInt(100) > 50 then begin
+ PlusSign := '+';
+ OpenBracket := '(';
+ CloseBracket := ')';
+ Delimiter := '-';
+ end;
+ exit(
+ PlusSign + GenerateRandomNumericText(3) + ' ' +
+ OpenBracket + GenerateRandomNumericText(3) + CloseBracket + ' ' +
+ GenerateRandomNumericText(4) + Delimiter + GenerateRandomNumericText(4));
+ end;
+
+ procedure GenerateRandomFraction(): Decimal
+ begin
+ exit(LibraryRandom.RandInt(99) / 100); // Generate any fraction between 0.01 to .99.
+ end;
+
+ procedure GenerateRandomDate(MinDate: Date; MaxDate: Date): Date
+ var
+ DateFormulaRandomDate: DateFormula;
+ DateFormulaMinDate: DateFormula;
+ begin
+ Evaluate(DateFormulaMinDate, '<-1D>');
+ Evaluate(DateFormulaRandomDate, '<' + Format(LibraryRandom.RandInt(MaxDate - MinDate + 1)) + 'D>');
+ exit(CalcDate(DateFormulaRandomDate, CalcDate(DateFormulaMinDate, MinDate)));
+ end;
+
+ procedure GenerateGUID(): Code[10]
+ var
+ NoSeries: Record "No. Series";
+ NoSeriesCodeunit: Codeunit "No. Series";
+ begin
+ NoSeries.ReadIsolation(IsolationLevel::UpdLock);
+ if not NoSeries.Get(GUIDTok) then begin
+ LibraryNoSeries.CreateNoSeries(GUIDTok, true, true, false);
+ LibraryNoSeries.CreateNoSeriesLine(GUIDTok, 1,
+ PadStr(InsStr(GUIDTok, '00000000', 3), 10),
+ PadStr(InsStr(GUIDTok, '99999999', 3), 10));
+ end;
+ exit(CopyStr(NoSeriesCodeunit.GetNextNo(GUIDTok), 1, 10));
+ end;
+
+ procedure GetEmptyGuid(): Guid
+ var
+ EmptyGuid: Guid;
+ begin
+ exit(EmptyGuid);
+ end;
+
+ procedure GenerateRandomRec(var RecRef: RecordRef)
+ var
+ FieldRef: FieldRef;
+ i: Integer;
+ begin
+ for i := 1 to RecRef.FieldCount do begin
+ FieldRef := RecRef.FieldIndex(i);
+ if FieldRef.Class = FieldClass::Normal then
+ case FieldRef.Type of
+ FieldType::Text:
+ FieldRef.Value := GenerateRandomXMLText(FieldRef.Length);
+ FieldType::Date:
+ FieldRef.Value := GenerateRandomDate(Today, CalcDate('<1Y>'));
+ FieldType::Decimal:
+ FieldRef.Value := LibraryRandom.RandDec(9999999, 2);
+ end;
+ end;
+ end;
+
+ procedure GenerateMOD97CompliantCode() CodeMod97Compliant: Code[10]
+ var
+ CompliantCodeBody: Integer;
+ begin
+ CompliantCodeBody := LibraryRandom.RandIntInRange(1, 100000000);
+ CodeMod97Compliant := ConvertStr(Format(CompliantCodeBody, 8, ''), ' ', '0');
+ CodeMod97Compliant += ConvertStr(Format(97 - CompliantCodeBody mod 97, 2, ''), ' ', '0');
+ end;
+
+ procedure ExistsDecimalValueInArray(RowValueSet: array[250] of Text[250]; Value: Decimal): Boolean
+ var
+ Counter: Integer;
+ CurrentValue: Decimal;
+ begin
+ repeat
+ Counter += 1;
+ if Evaluate(CurrentValue, RowValueSet[Counter]) then;
+ until (CurrentValue = Value) or (Counter = ArrayLen(RowValueSet));
+ exit(CurrentValue = Value);
+ end;
+
+ procedure FindRecord(var RecRef: RecordRef)
+ begin
+ RecRef.FindFirst();
+ end;
+
+ procedure LineBreak(): Text
+ var
+ NewLine: Char;
+ begin
+ NewLine := 10;
+ exit(Format(NewLine));
+ end;
+
+ procedure FindOrCreateCodeRecord(TableID: Integer): Code[10]
+ var
+ RecRef: RecordRef;
+ FieldRef: FieldRef;
+ begin
+ VerifyRecordHasCodeKey(TableID, RecRef, FieldRef);
+ if not RecRef.FindFirst() then begin
+ FieldRef.Validate(GenerateRandomCode(FieldRef.Number, TableID));
+ RecRef.Insert(true);
+ end;
+ exit(FieldRef.Value);
+ end;
+
+ procedure CreateCodeRecord(TableID: Integer): Code[10]
+ var
+ RecRef: RecordRef;
+ FieldRef: FieldRef;
+ begin
+ VerifyRecordHasCodeKey(TableID, RecRef, FieldRef);
+ FieldRef.Validate(GenerateRandomCode(FieldRef.Number, TableID));
+ RecRef.Insert(true);
+ exit(FieldRef.Value);
+ end;
+
+ procedure UpdateSetupNoSeriesCode(TableID: Integer; FieldID: Integer)
+ var
+ RecRef: RecordRef;
+ FieldRef: FieldRef;
+ NoSeriesCode: Code[20];
+ begin
+ RecRef.Open(TableID);
+ RecRef.Find();
+ FieldRef := RecRef.Field(FieldID);
+ NoSeriesCode := GetGlobalNoSeriesCode();
+ if Format(FieldRef.Value) <> NoSeriesCode then begin
+ FieldRef.Value(NoSeriesCode);
+ RecRef.Modify();
+ end;
+ end;
+
+ procedure AddTempField(var TempField: Record "Field" temporary; FieldNo: Integer; TableNo: Integer)
+ var
+ "Field": Record "Field";
+ begin
+ Clear(TempField);
+ Field.Get(TableNo, FieldNo);
+ TempField.TransferFields(Field, true);
+ TempField.Insert();
+ end;
+
+ local procedure VerifyRecordHasCodeKey(TableID: Integer; var RecRef: RecordRef; var FieldRef: FieldRef)
+ var
+ "Field": Record "Field";
+ KeyRef: KeyRef;
+ begin
+ RecRef.Open(TableID);
+ KeyRef := RecRef.KeyIndex(1);
+ FieldRef := KeyRef.FieldIndex(1);
+
+ Field.Get(TableID, FieldRef.Number);
+ if (KeyRef.FieldCount <> 1) or (Field.Type <> Field.Type::Code) then
+ Error(PrimaryKeyNotCodeFieldErr);
+ end;
+
+ procedure GetMaxOptionIndex(OptionString: Text): Integer
+ begin
+ exit(StrLen(DelChr(OptionString, '=', DelChr(OptionString, '=', ','))));
+ end;
+
+ procedure GetMaxFieldOptionIndex(TableNo: Integer; FieldNo: Integer): Integer
+ var
+ "Field": Record "Field";
+ RecRef: RecordRef;
+ FieldRef: FieldRef;
+ begin
+ RecRef.Open(TableNo);
+ FieldRef := RecRef.Field(FieldNo);
+
+ Field.Get(TableNo, FieldNo);
+ if Field.Type <> Field.Type::Option then
+ Error(FieldOptionTypeErr, FieldRef.Name, RecRef.Name);
+ exit(GetMaxOptionIndex(FieldRef.OptionCaption));
+ end;
+
+ procedure FillFieldMaxText(RecVar: Variant; FieldNo: Integer)
+ var
+ RecRef: RecordRef;
+ FieldRef: FieldRef;
+ begin
+ RecRef.GetTable(RecVar);
+ FieldRef := RecRef.Field(FieldNo);
+ FieldRef.Value := GenerateRandomText(FieldRef.Length);
+ RecRef.Modify();
+ end;
+
+ // Does the opposite of IncStr, i.e. decrements the last number in a string.
+ // NOTE: Expects the string actually contains a number.
+ // NOTE: The implementation is not guaranteed to be correcet. Works for most common cases.
+ // Verify the result like shown here:
+ // decStr := DecStr(str);
+ // Assert.AreEqual(str, IncStr(decStr)), 'DecStr not working.');
+ procedure DecStr(str: Text): Text
+ var
+ Index: Integer;
+ StartIndex: Integer;
+ EndIndex: Integer;
+ Number: Integer;
+ Digits: Text;
+ ZeroPadding: Text;
+ NewStr: Text;
+ begin
+ StartIndex := 1;
+ EndIndex := 0;
+
+ // Find integer suffix.
+ for Index := StrLen(str) downto 1 do
+ if Evaluate(Number, str.Substring(Index, 1)) then begin
+ Digits := str.Substring(Index, 1) + Digits;
+ if EndIndex = 0 then
+ EndIndex := Index;
+ end else
+ if StrLen(Digits) > 0 then begin
+ StartIndex := Index + 1;
+ break;
+ end;
+
+ // Get zero padding in the digits.
+ for Index := 1 to StrLen(Digits) do
+ if Digits.Substring(Index, 1) = '0' then
+ ZeroPadding := ZeroPadding + '0'
+ else
+ break;
+
+ Evaluate(Number, Digits);
+ Number := Number - 1;
+
+ // Replace old integer suffix with new.
+ NewStr := Str.Substring(1, StartIndex - 1) + ZeroPadding + Format(Number);
+ if EndIndex < StrLen(str) then
+ NewStr := NewStr + Str.Substring(EndIndex + 1, StrLen(str) - EndIndex);
+
+ exit(NewStr);
+ end;
+
+ procedure GetNoSeriesLine(noSeriesCode: Code[20]; var noSeriesLine: Record "No. Series Line"): Boolean
+ var
+ NoSeries: Codeunit "No. Series";
+ begin
+ exit(NoSeries.GetNoSeriesLine(noSeriesLine, noSeriesCode, WorkDate(), true));
+ end;
+}
diff --git a/Apps/W1/ApplicationTestLibrary/LibraryWarehouse.Codeunit.al b/Apps/W1/ApplicationTestLibrary/LibraryWarehouse.Codeunit.al
new file mode 100644
index 0000000000..d5ec9c9e09
--- /dev/null
+++ b/Apps/W1/ApplicationTestLibrary/LibraryWarehouse.Codeunit.al
@@ -0,0 +1,1782 @@
+///
+/// Provides utility functions for creating and managing warehouse-related entities in test scenarios, including locations, bins, warehouse documents, and warehouse activities.
+///
+codeunit 132204 "Library - Warehouse"
+{
+
+ trigger OnRun()
+ begin
+ end;
+
+ var
+ LibraryInventory: Codeunit "Library - Inventory";
+ LibraryAssembly: Codeunit "Library - Assembly";
+ LibraryUtility: Codeunit "Library - Utility";
+ Assert: Codeunit Assert;
+
+ procedure AutoFillQtyHandleWhseActivity(WarehouseActivityHeaderRec: Record "Warehouse Activity Header")
+ var
+ WarehouseActivityLine: Record "Warehouse Activity Line";
+ begin
+ Clear(WarehouseActivityLine);
+ WarehouseActivityLine.SetRange("Activity Type", WarehouseActivityHeaderRec.Type);
+ WarehouseActivityLine.SetRange("No.", WarehouseActivityHeaderRec."No.");
+ WarehouseActivityLine.AutofillQtyToHandle(WarehouseActivityLine);
+ end;
+
+ procedure AutoFillQtyInventoryActivity(WarehouseActivityHeader: Record "Warehouse Activity Header")
+ begin
+ AutoFillQtyHandleWhseActivity(WarehouseActivityHeader);
+ end;
+
+ procedure AutofillQtyToShipWhseShipment(var WarehouseShipmentHeader: Record "Warehouse Shipment Header")
+ var
+ WarehouseShipmentLine: Record "Warehouse Shipment Line";
+ WarehouseShipmentLine2: Record "Warehouse Shipment Line";
+ begin
+ Clear(WarehouseShipmentLine);
+ WarehouseShipmentLine.SetRange("No.", WarehouseShipmentHeader."No.");
+ WarehouseShipmentLine.FindLast();
+ WarehouseShipmentLine2.Copy(WarehouseShipmentLine);
+ WarehouseShipmentLine.AutofillQtyToHandle(WarehouseShipmentLine2);
+ end;
+
+ procedure AutofillQtyToRecvWhseReceipt(var WarehouseReceiptHeader: Record "Warehouse Receipt Header")
+ var
+ WarehouseReceiptLine: Record "Warehouse Receipt Line";
+ WarehouseReceiptLine2: Record "Warehouse Receipt Line";
+ begin
+ Clear(WarehouseReceiptLine);
+ WarehouseReceiptLine.SetRange("No.", WarehouseReceiptHeader."No.");
+ WarehouseReceiptLine.FindLast();
+ WarehouseReceiptLine2.Copy(WarehouseReceiptLine);
+ WarehouseReceiptLine.AutofillQtyToReceive(WarehouseReceiptLine2);
+ end;
+
+ procedure CalculateCountingPeriodOnWarehousePhysicalInventoryJournal(var WarehouseJournalLine: Record "Warehouse Journal Line")
+ var
+ PhysInvtCountManagement: Codeunit "Phys. Invt. Count.-Management";
+ begin
+ Commit(); // Commit is required.
+ Clear(PhysInvtCountManagement);
+ PhysInvtCountManagement.InitFromWhseJnl(WarehouseJournalLine);
+ PhysInvtCountManagement.Run();
+ end;
+
+ procedure CalculatePlannedDate(OrgDateExpression: Text[30]; OrgDate: Date; CustomCalendarChange: array[2] of Record "Customized Calendar Change"; CheckBothCalendars: Boolean) PlannedDate: Date
+ var
+ CalendarManagement: Codeunit "Calendar Management";
+ begin
+ PlannedDate := CalendarManagement.CalcDateBOC(OrgDateExpression, OrgDate, CustomCalendarChange, CheckBothCalendars);
+ end;
+
+ procedure CalculateWhseAdjustment(var Item: Record Item; ItemJournalBatch: Record "Item Journal Batch")
+ var
+ ItemJournalLine: Record "Item Journal Line";
+ TmpItem: Record Item;
+ CalcWhseAdjmt: Report "Calculate Whse. Adjustment";
+ NoSeries: Codeunit "No. Series";
+ DocumentNo: Text[20];
+ begin
+ Clear(ItemJournalLine);
+ ItemJournalLine.Init();
+ ItemJournalLine.Validate("Journal Template Name", ItemJournalBatch."Journal Template Name");
+ ItemJournalLine.Validate("Journal Batch Name", ItemJournalBatch.Name);
+
+ Commit();
+ CalcWhseAdjmt.SetItemJnlLine(ItemJournalLine);
+ if (DocumentNo = '') and (ItemJournalBatch."No. Series" <> '') then
+ DocumentNo := NoSeries.PeekNextNo(ItemJournalBatch."No. Series");
+ CalcWhseAdjmt.InitializeRequest(WorkDate(), DocumentNo);
+ if Item.HasFilter then
+ TmpItem.CopyFilters(Item)
+ else begin
+ Item.Get(Item."No.");
+ TmpItem.SetRange("No.", Item."No.");
+ end;
+
+ CalcWhseAdjmt.SetTableView(TmpItem);
+ CalcWhseAdjmt.UseRequestPage(false);
+ CalcWhseAdjmt.RunModal();
+ end;
+
+ procedure CalculateWhseAdjustmentItemJournal(var Item: Record Item; NewPostingDate: Date; DocumentNo: Text[20])
+ var
+ ItemJournalLine: Record "Item Journal Line";
+ TmpItem: Record Item;
+ ItemJournalTemplate: Record "Item Journal Template";
+ ItemJournalBatch: Record "Item Journal Batch";
+ CalculateWhseAdjustmentReport: Report "Calculate Whse. Adjustment";
+ NoSeries: Codeunit "No. Series";
+ begin
+ LibraryAssembly.SetupItemJournal(ItemJournalTemplate, ItemJournalBatch);
+ ItemJournalLine.Validate("Journal Template Name", ItemJournalBatch."Journal Template Name");
+ ItemJournalLine.Validate("Journal Batch Name", ItemJournalBatch.Name);
+
+ Commit();
+ CalculateWhseAdjustmentReport.SetItemJnlLine(ItemJournalLine);
+ if DocumentNo = '' then
+ DocumentNo := NoSeries.PeekNextNo(ItemJournalBatch."No. Series", NewPostingDate);
+ CalculateWhseAdjustmentReport.InitializeRequest(NewPostingDate, DocumentNo);
+ if Item.HasFilter then
+ TmpItem.CopyFilters(Item)
+ else begin
+ Item.Get(Item."No.");
+ TmpItem.SetRange("No.", Item."No.");
+ end;
+
+ CalculateWhseAdjustmentReport.SetTableView(TmpItem);
+ CalculateWhseAdjustmentReport.UseRequestPage(false);
+ CalculateWhseAdjustmentReport.RunModal();
+ end;
+
+ procedure CalculateBinReplenishment(BinContent: Record "Bin Content"; WhseWorksheetName: Record "Whse. Worksheet Name"; LocationCode: Code[10]; AllowBreakBulk: Boolean; HideDialog: Boolean; DoNotFillQtyToHandle: Boolean)
+ var
+ CalculateBinReplenishmentReport: Report "Calculate Bin Replenishment";
+ begin
+ CalculateBinReplenishmentReport.InitializeRequest(
+ WhseWorksheetName."Worksheet Template Name", WhseWorksheetName.Name, LocationCode, AllowBreakBulk, HideDialog,
+ DoNotFillQtyToHandle);
+ CalculateBinReplenishmentReport.SetTableView(BinContent);
+ CalculateBinReplenishmentReport.UseRequestPage(false);
+ CalculateBinReplenishmentReport.Run();
+ end;
+
+ procedure CalculateCrossDockLines(var WhseCrossDockOpportunity: Record "Whse. Cross-Dock Opportunity"; NewTemplateName: Code[10]; NewNameNo: Code[20]; NewLocationCode: Code[10])
+ var
+ WhseCrossDockManagement: Codeunit "Whse. Cross-Dock Management";
+ begin
+ WhseCrossDockManagement.CalculateCrossDockLines(WhseCrossDockOpportunity, NewTemplateName, NewNameNo, NewLocationCode);
+ end;
+
+ procedure ChangeUnitOfMeasure(var WarehouseActivityLine: Record "Warehouse Activity Line")
+ var
+ WarehouseActivityLine2: Record "Warehouse Activity Line";
+ WhseChangeUnitOfMeasure: Report "Whse. Change Unit of Measure";
+ begin
+ Commit();
+ Clear(WhseChangeUnitOfMeasure);
+ WhseChangeUnitOfMeasure.DefWhseActLine(WarehouseActivityLine);
+ WhseChangeUnitOfMeasure.RunModal();
+ if WhseChangeUnitOfMeasure.ChangeUOMCode(WarehouseActivityLine2) then
+ WarehouseActivityLine.ChangeUOMCode(WarehouseActivityLine, WarehouseActivityLine2);
+ end;
+
+ procedure CreateFullWMSLocation(var Location: Record Location; BinsPerZone: Integer)
+ var
+ PutAwayTemplateHeader: Record "Put-away Template Header";
+ PutAwayTemplateLine: Record "Put-away Template Line";
+ Zone: Record Zone;
+ Bin: Record Bin;
+ begin
+ Clear(Location);
+ Location.Init();
+
+ CreateLocationWithInventoryPostingSetup(Location);
+ // Skip validate trigger for bin mandatory to improve performance.
+ Location."Bin Mandatory" := true;
+ Location.Validate("Directed Put-away and Pick", true);
+ Location.Validate("Use Cross-Docking", true);
+ if Location."Require Pick" then
+ if Location."Require Shipment" then begin
+ Location."Prod. Consump. Whse. Handling" := Location."Prod. Consump. Whse. Handling"::"Warehouse Pick (mandatory)";
+ Location."Asm. Consump. Whse. Handling" := Location."Asm. Consump. Whse. Handling"::"Warehouse Pick (mandatory)";
+ Location."Job Consump. Whse. Handling" := Location."Job Consump. Whse. Handling"::"Warehouse Pick (mandatory)";
+ end else begin
+ Location."Prod. Consump. Whse. Handling" := Location."Prod. Consump. Whse. Handling"::"Inventory Pick/Movement";
+ Location."Asm. Consump. Whse. Handling" := Location."Asm. Consump. Whse. Handling"::"Inventory Movement";
+ Location."Job Consump. Whse. Handling" := Location."Job Consump. Whse. Handling"::"Inventory Pick";
+ end
+ else begin
+ Location."Prod. Consump. Whse. Handling" := Location."Prod. Consump. Whse. Handling"::"Warehouse Pick (optional)";
+ Location."Asm. Consump. Whse. Handling" := Location."Asm. Consump. Whse. Handling"::"Warehouse Pick (optional)";
+ Location."Job Consump. Whse. Handling" := Location."Job Consump. Whse. Handling"::"Warehouse Pick (optional)";
+ end;
+
+ if Location."Require Put-away" and not Location."Require Receive" then
+ Location."Prod. Output Whse. Handling" := Location."Prod. Output Whse. Handling"::"Inventory Put-away";
+ Location.Modify(true);
+
+ // Create Zones and bins
+ // Fill in Bins fast tab
+ // 1. Adjustment
+ CreateZone(Zone, 'ADJUSTMENT', Location.Code, SelectBinType(false, false, false, false), '', '', 0, false);
+ CreateNumberOfBins(Location.Code, Zone.Code, SelectBinType(false, false, false, false), BinsPerZone, false);
+ FindBin(Bin, Location.Code, Zone.Code, 1);
+ Location.Validate("Adjustment Bin Code", Bin.Code);
+
+ // 2. Bulk zone
+ CreateZone(Zone, 'BULK', Location.Code, SelectBinType(false, false, true, false), '', '', 50, false);
+ CreateNumberOfBins(Location.Code, Zone.Code, SelectBinType(false, false, true, false), BinsPerZone, false);
+
+ // 3. Cross-dock zone
+ CreateZone(Zone, 'CROSS-DOCK', Location.Code, SelectBinType(false, false, true, true), '', '', 0, true);
+ CreateNumberOfBins(Location.Code, Zone.Code, SelectBinType(false, false, true, true), BinsPerZone, true);
+ FindBin(Bin, Location.Code, Zone.Code, 1);
+ Location.Validate("Cross-Dock Bin Code", Bin.Code);
+
+ // 4. Pick zone
+ CreateZone(Zone, 'PICK', Location.Code, SelectBinType(false, false, true, true), '', '', 100, false);
+ CreateNumberOfBins(Location.Code, Zone.Code, SelectBinType(false, false, true, true), BinsPerZone, false);
+
+ // 5. Production zone
+ CreateZone(Zone, 'PRODUCTION', Location.Code, SelectBinType(false, false, false, false), '', '', 5, false);
+ CreateNumberOfBins(Location.Code, Zone.Code, SelectBinType(false, false, false, false), BinsPerZone, false);
+ FindBin(Bin, Location.Code, Zone.Code, 1);
+ Location.Validate("Open Shop Floor Bin Code", Bin.Code);
+ FindBin(Bin, Location.Code, Zone.Code, 2);
+ Location.Validate("To-Production Bin Code", Bin.Code);
+ FindBin(Bin, Location.Code, Zone.Code, 3);
+ Location.Validate("From-Production Bin Code", Bin.Code);
+
+ // 6. QC zone
+ CreateZone(Zone, 'QC', Location.Code, SelectBinType(false, false, false, false), '', '', 0, false);
+ CreateNumberOfBins(Location.Code, Zone.Code, SelectBinType(false, false, false, false), BinsPerZone, false);
+ FindBin(Bin, Location.Code, Zone.Code, 1);
+ Location.Validate("To-Assembly Bin Code", Bin.Code);
+ FindBin(Bin, Location.Code, Zone.Code, 2);
+ Location.Validate("From-Assembly Bin Code", Bin.Code);
+
+ // 7. Receive Zone
+ CreateZone(Zone, 'RECEIVE', Location.Code, SelectBinType(true, false, false, false), '', '', 10, false);
+ CreateNumberOfBins(Location.Code, Zone.Code, SelectBinType(true, false, false, false), BinsPerZone, false);
+ FindBin(Bin, Location.Code, Zone.Code, 1);
+ Location.Validate("Receipt Bin Code", Bin.Code);
+
+ // 8. Ship Zone
+ CreateZone(Zone, 'SHIP', Location.Code, SelectBinType(false, true, false, false), '', '', 200, false);
+ CreateNumberOfBins(Location.Code, Zone.Code, SelectBinType(false, true, false, false), BinsPerZone, false);
+ FindBin(Bin, Location.Code, Zone.Code, 1);
+ Location.Validate("Shipment Bin Code", Bin.Code);
+
+ // 9. Stage zone
+ CreateZone(Zone, 'STAGE', Location.Code, SelectBinType(false, true, false, false), '', '', 5, false);
+ CreateNumberOfBins(Location.Code, Zone.Code, SelectBinType(false, true, false, false), BinsPerZone, false);
+
+ // Bin policies fast tab
+ // Created the STD put-away template - same as the one in the demo data
+ CreatePutAwayTemplateHeader(PutAwayTemplateHeader);
+ CreatePutAwayTemplateLine(PutAwayTemplateHeader, PutAwayTemplateLine, true, false, true, true, true, false);
+ CreatePutAwayTemplateLine(PutAwayTemplateHeader, PutAwayTemplateLine, true, false, true, true, false, false);
+ CreatePutAwayTemplateLine(PutAwayTemplateHeader, PutAwayTemplateLine, false, true, true, true, false, false);
+ CreatePutAwayTemplateLine(PutAwayTemplateHeader, PutAwayTemplateLine, false, true, true, false, false, false);
+ CreatePutAwayTemplateLine(PutAwayTemplateHeader, PutAwayTemplateLine, false, true, false, false, false, true);
+ CreatePutAwayTemplateLine(PutAwayTemplateHeader, PutAwayTemplateLine, false, true, false, false, false, false);
+ Location.Validate("Put-away Template Code", PutAwayTemplateHeader.Code);
+
+ Location.Validate("Allow Breakbulk", true);
+
+ Location.Modify(true);
+
+ OnAfterCreateFullWMSLocation(Location, BinsPerZone);
+ end;
+
+ procedure CreateBin(var Bin: Record Bin; LocationCode: Code[10]; BinCode: Code[20]; ZoneCode: Code[10]; BinTypeCode: Code[10])
+ begin
+ Clear(Bin);
+ Bin.Init();
+ Bin.Validate("Location Code", LocationCode);
+ if BinCode = '' then
+ BinCode := LibraryUtility.GenerateRandomCode(Bin.FieldNo(Code), DATABASE::Bin);
+ Bin.Validate(Code, BinCode);
+ Bin.Validate("Bin Type Code", BinTypeCode);
+ Bin.Validate("Zone Code", ZoneCode);
+ Bin.Insert(true);
+
+ OnAfterCreateBin(Bin, LocationCode, BinCode, ZoneCode, BinTypeCode);
+ end;
+
+ procedure CreateBinContent(var BinContent: Record "Bin Content"; LocationCode: Code[10]; ZoneCode: Code[10]; BinCode: Code[20]; ItemNo: Code[20]; VariantCode: Code[10]; UnitOfMeasureCode: Code[10])
+ var
+ Bin: Record Bin;
+ begin
+ BinContent.Init();
+ BinContent.Validate("Location Code", LocationCode);
+ BinContent.Validate("Bin Code", BinCode);
+ BinContent.Validate("Item No.", ItemNo);
+ BinContent.Validate("Variant Code", VariantCode);
+ BinContent.Validate("Unit of Measure Code", UnitOfMeasureCode);
+ if ZoneCode = '' then begin
+ Bin.Get(LocationCode, BinCode);
+ ZoneCode := Bin."Zone Code";
+ end;
+ BinContent.Validate("Zone Code", ZoneCode);
+ BinContent.Insert(true);
+ end;
+
+ procedure CreateBinCreationWorksheetLine(var BinCreationWorksheetLine: Record "Bin Creation Worksheet Line"; WorksheetTemplateName: Code[10]; Name: Code[10]; LocationCode: Code[10]; BinCode: Code[20])
+ var
+ RecRef: RecordRef;
+ begin
+ BinCreationWorksheetLine.Init();
+ BinCreationWorksheetLine.Validate("Worksheet Template Name", WorksheetTemplateName);
+ BinCreationWorksheetLine.Validate(Name, Name);
+ BinCreationWorksheetLine.Validate("Location Code", LocationCode);
+ BinCreationWorksheetLine.Validate("Bin Code", BinCode);
+ RecRef.GetTable(BinCreationWorksheetLine);
+ BinCreationWorksheetLine.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, BinCreationWorksheetLine.FieldNo("Line No.")));
+ BinCreationWorksheetLine.Insert(true);
+ end;
+
+ procedure CreateBinTemplate(var BinTemplate: Record "Bin Template"; LocationCode: Code[10])
+ begin
+ BinTemplate.Init();
+ BinTemplate.Validate(Code, LibraryUtility.GenerateRandomCode(BinTemplate.FieldNo(Code), DATABASE::Location));
+ BinTemplate.Insert(true);
+ BinTemplate.Validate("Location Code", LocationCode);
+ BinTemplate.Modify(true);
+ end;
+
+ procedure CreateBinType(var BinType: Record "Bin Type"; Receive: Boolean; Ship: Boolean; PutAway: Boolean; Pick: Boolean)
+ begin
+ Clear(BinType);
+ BinType.Init();
+
+ BinType.Code := LibraryUtility.GenerateRandomCode(BinType.FieldNo(Code), DATABASE::"Bin Type");
+ BinType.Description := BinType.Code;
+ BinType.Receive := Receive;
+ BinType.Ship := Ship;
+ BinType."Put Away" := PutAway;
+ BinType.Pick := Pick;
+ BinType.Insert(true);
+ end;
+
+#if not CLEAN27
+#pragma warning disable AL0801
+ [Obsolete('Moved to codeunit LibraryManufacturing', '27.0')]
+ procedure CreateInboundWhseReqFromProdO(ProductionOrder: Record "Production Order")
+ var
+ LibraryManufacturing: Codeunit "Library - Manufacturing";
+ begin
+ LibraryManufacturing.CreateInboundWhseReqFromProdOrder(ProductionOrder);
+ end;
+#pragma warning restore AL0801
+#endif
+
+ procedure CreateInternalMovementHeader(var InternalMovementHeader: Record "Internal Movement Header"; LocationCode: Code[10]; ToBinCode: Code[20])
+ begin
+ Clear(InternalMovementHeader);
+ InternalMovementHeader.Validate("Location Code", LocationCode);
+ InternalMovementHeader.Validate("To Bin Code", ToBinCode);
+ InternalMovementHeader.Insert(true);
+ end;
+
+ procedure CreateInternalMovementLine(InternalMovementHeader: Record "Internal Movement Header"; var InternalMovementLine: Record "Internal Movement Line"; ItemNo: Code[20]; FromBinCode: Code[20]; ToBinCode: Code[20]; Qty: Decimal)
+ var
+ RecRef: RecordRef;
+ begin
+ Clear(InternalMovementLine);
+ InternalMovementLine.Validate("No.", InternalMovementHeader."No.");
+ RecRef.GetTable(InternalMovementLine);
+ InternalMovementLine.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, InternalMovementLine.FieldNo("Line No.")));
+ InternalMovementLine.Validate("Item No.", ItemNo);
+ InternalMovementLine.Validate("From Bin Code", FromBinCode);
+ InternalMovementLine.Validate("To Bin Code", ToBinCode);
+ InternalMovementLine.Validate(Quantity, Qty);
+ InternalMovementLine.Insert(true);
+ end;
+
+ procedure CreateInTransitLocation(var Location: Record Location)
+ begin
+ CreateLocationWithInventoryPostingSetup(Location);
+ Location.Validate("Use As In-Transit", true);
+ Location.Modify(true);
+ end;
+
+ procedure CreateInventoryMovementHeader(var WarehouseActivityHeader: Record "Warehouse Activity Header"; LocationCode: Code[10])
+ begin
+ Clear(WarehouseActivityHeader);
+ WarehouseActivityHeader.Validate("Location Code", LocationCode);
+ WarehouseActivityHeader.Validate(Type, WarehouseActivityHeader.Type::"Invt. Movement");
+ WarehouseActivityHeader.Insert(true);
+ end;
+
+ procedure CreateInvtMvmtFromInternalMvmt(var InternalMovementHeader: Record "Internal Movement Header")
+ var
+ CreateInvtPickMovement: Codeunit "Create Inventory Pick/Movement";
+ begin
+ CreateInvtPickMovement.CreateInvtMvntWithoutSource(InternalMovementHeader);
+ end;
+
+ procedure CreateInvtPutPickMovement(SourceDocument: Enum "Warehouse Request Source Document"; SourceNo: Code[20]; PutAway: Boolean; Pick: Boolean; Movement: Boolean)
+ var
+ WhseRequest: Record "Warehouse Request";
+ CreateInvtPutAwayPickMvmt: Report "Create Invt Put-away/Pick/Mvmt";
+ begin
+ WhseRequest.Reset();
+ WhseRequest.Init();
+ WhseRequest.SetCurrentKey("Source Document", "Source No.");
+ WhseRequest.SetRange("Source Document", SourceDocument);
+ WhseRequest.SetRange("Source No.", SourceNo);
+ CreateInvtPutAwayPickMvmt.SetTableView(WhseRequest);
+ CreateInvtPutAwayPickMvmt.InitializeRequest(PutAway, Pick, Movement, false, false);
+ CreateInvtPutAwayPickMvmt.UseRequestPage(false);
+ CreateInvtPutAwayPickMvmt.RunModal();
+ end;
+
+ procedure CreateInvtPutPickPurchaseOrder(var PurchaseHeader: Record "Purchase Header")
+ var
+ WhseRequest: Record "Warehouse Request";
+ CreateInvtPutPick: Report "Create Invt Put-away/Pick/Mvmt";
+ begin
+ PurchaseHeader.TestField(Status, PurchaseHeader.Status::Released);
+
+ WhseRequest.Reset();
+ WhseRequest.SetCurrentKey("Source Document", "Source No.");
+ case PurchaseHeader."Document Type" of
+ PurchaseHeader."Document Type"::Order:
+ WhseRequest.SetRange("Source Document", WhseRequest."Source Document"::"Purchase Order");
+ PurchaseHeader."Document Type"::"Return Order":
+ WhseRequest.SetRange("Source Document", WhseRequest."Source Document"::"Purchase Return Order");
+ end;
+ WhseRequest.SetRange("Source No.", PurchaseHeader."No.");
+ CreateInvtPutPick.SetTableView(WhseRequest);
+ CreateInvtPutPick.InitializeRequest(true, true, false, false, false);
+ CreateInvtPutPick.UseRequestPage(false);
+ CreateInvtPutPick.RunModal();
+ end;
+
+ procedure CreateInvtPutPickSalesOrder(var SalesHeader: Record "Sales Header")
+ var
+ WhseRequest: Record "Warehouse Request";
+ CreateInvtPutPick: Report "Create Invt Put-away/Pick/Mvmt";
+ begin
+ SalesHeader.TestField(Status, SalesHeader.Status::Released);
+
+ WhseRequest.Reset();
+ WhseRequest.SetCurrentKey("Source Document", "Source No.");
+ case SalesHeader."Document Type" of
+ SalesHeader."Document Type"::Order:
+ WhseRequest.SetRange("Source Document", WhseRequest."Source Document"::"Sales Order");
+ SalesHeader."Document Type"::"Return Order":
+ WhseRequest.SetRange("Source Document", WhseRequest."Source Document"::"Sales Return Order");
+ end;
+ WhseRequest.SetRange("Source No.", SalesHeader."No.");
+ CreateInvtPutPick.SetTableView(WhseRequest);
+ CreateInvtPutPick.InitializeRequest(true, true, false, false, false);
+ CreateInvtPutPick.UseRequestPage(false);
+ CreateInvtPutPick.RunModal();
+ end;
+
+ procedure CreateInvtPutAwayPick(var WarehouseRequest: Record "Warehouse Request"; PutAway: Boolean; Pick: Boolean; Movement: Boolean)
+ var
+ TmpWarehouseRequest: Record "Warehouse Request";
+ CreateInvtPutAwayPickMvmt: Report "Create Invt Put-away/Pick/Mvmt";
+ begin
+ Commit();
+ CreateInvtPutAwayPickMvmt.InitializeRequest(PutAway, Pick, Movement, false, false);
+ if WarehouseRequest.HasFilter then
+ TmpWarehouseRequest.CopyFilters(WarehouseRequest)
+ else begin
+ WarehouseRequest.Get(WarehouseRequest.Type,
+ WarehouseRequest."Location Code",
+ WarehouseRequest."Source Type",
+ WarehouseRequest."Source Subtype",
+ WarehouseRequest."Source No.");
+ TmpWarehouseRequest.SetRange(Type, WarehouseRequest.Type);
+ TmpWarehouseRequest.SetRange("Location Code", WarehouseRequest."Location Code");
+ TmpWarehouseRequest.SetRange("Source Type", WarehouseRequest."Source Type");
+ TmpWarehouseRequest.SetRange("Source Subtype", WarehouseRequest."Source Subtype");
+ TmpWarehouseRequest.SetRange("Source No.", WarehouseRequest."Source No.");
+ end;
+ CreateInvtPutAwayPickMvmt.SetTableView(TmpWarehouseRequest);
+ CreateInvtPutAwayPickMvmt.UseRequestPage(false);
+ CreateInvtPutAwayPickMvmt.RunModal();
+ end;
+
+ procedure CreateLocation(var Location: Record Location): Code[10]
+ begin
+ CreateLocationCodeAndName(Location);
+ exit(Location.Code);
+ end;
+
+ procedure CreateLocationWMS(var Location: Record Location; BinMandatory: Boolean; RequirePutAway: Boolean; RequirePick: Boolean; RequireReceive: Boolean; RequireShipment: Boolean)
+ begin
+ CreateLocationWithInventoryPostingSetup(Location);
+ if RequirePutAway then begin
+ Location.Validate("Require Put-away", true);
+ Location.Validate("Always Create Put-away Line", true);
+ end;
+ if RequirePick then
+ Location.Validate("Require Pick", true);
+ if RequireReceive then
+ Location.Validate("Require Receive", true);
+ if RequireShipment then
+ Location.Validate("Require Shipment", true);
+ Location."Bin Mandatory" := BinMandatory;
+
+ if RequirePick then
+ if RequireShipment then begin
+ Location."Prod. Consump. Whse. Handling" := Location."Prod. Consump. Whse. Handling"::"Warehouse Pick (mandatory)";
+ Location."Asm. Consump. Whse. Handling" := Location."Asm. Consump. Whse. Handling"::"Warehouse Pick (mandatory)";
+ Location."Job Consump. Whse. Handling" := Location."Job Consump. Whse. Handling"::"Warehouse Pick (mandatory)";
+ end else begin
+ Location."Prod. Consump. Whse. Handling" := Location."Prod. Consump. Whse. Handling"::"Inventory Pick/Movement";
+ Location."Asm. Consump. Whse. Handling" := Location."Asm. Consump. Whse. Handling"::"Inventory Movement";
+ Location."Job Consump. Whse. Handling" := Location."Job Consump. Whse. Handling"::"Inventory Pick";
+ end
+ else begin
+ Location."Prod. Consump. Whse. Handling" := Location."Prod. Consump. Whse. Handling"::"Warehouse Pick (optional)";
+ Location."Asm. Consump. Whse. Handling" := Location."Asm. Consump. Whse. Handling"::"Warehouse Pick (optional)";
+ Location."Job Consump. Whse. Handling" := Location."Job Consump. Whse. Handling"::"Warehouse Pick (optional)";
+ end;
+
+ if RequirePutAway and not RequireReceive then
+ Location."Prod. Output Whse. Handling" := Location."Prod. Output Whse. Handling"::"Inventory Put-away";
+
+ Location.Modify();
+
+ OnAfterCreateLocationWMS(Location, BinMandatory, RequirePutAway, RequirePick, RequireReceive, RequireShipment);
+ end;
+
+ local procedure CreateLocationCodeAndName(var Location: Record Location): Code[10]
+ begin
+ Location.Init();
+ Location.Validate(Code, LibraryUtility.GenerateRandomCode(Location.FieldNo(Code), DATABASE::Location));
+ Location.Validate(Name, Location.Code);
+ Location.Insert(true);
+ OnAfterCreateLocationCodeAndName(Location);
+ exit(Location.Code);
+ end;
+
+ procedure CreateLocationWithInventoryPostingSetup(var Location: Record Location): Code[10]
+ begin
+ CreateLocationCodeAndName(Location);
+ LibraryInventory.UpdateInventoryPostingSetup(Location);
+ exit(Location.Code);
+ end;
+
+ procedure CreateLocationWithAddress(var Location: Record Location): Code[10]
+ begin
+ CreateLocation(Location);
+ Location.Validate("Name 2", LibraryUtility.GenerateRandomText(MaxStrLen(Location."Name 2")));
+ Location.Validate(Address, LibraryUtility.GenerateRandomText(MaxStrLen(Location.Address)));
+ Location.Validate("Address 2", LibraryUtility.GenerateRandomText(MaxStrLen(Location."Address 2")));
+ Location.Modify(true);
+
+ exit(Location.Code);
+ end;
+
+ procedure CreateMovementWorksheetLine(var WhseWorksheetLine: Record "Whse. Worksheet Line"; FromBin: Record Bin; ToBin: Record Bin; ItemNo: Code[20]; VariantCode: Code[10]; Quantity: Decimal)
+ var
+ WhseWorksheetTemplate: Record "Whse. Worksheet Template";
+ WhseWorksheetName: Record "Whse. Worksheet Name";
+ begin
+ SelectWhseWorksheetTemplate(WhseWorksheetTemplate, "Warehouse Worksheet Template Type"::Movement);
+ SelectWhseWorksheetName(WhseWorksheetName, WhseWorksheetTemplate.Name, FromBin."Location Code");
+ CreateWhseWorksheetLine(
+ WhseWorksheetLine, WhseWorksheetName."Worksheet Template Name", WhseWorksheetName.Name, WhseWorksheetName."Location Code",
+ "Warehouse Worksheet Document Type"::" ");
+ WhseWorksheetLine.Validate("Item No.", ItemNo);
+ WhseWorksheetLine.Validate("Variant Code", VariantCode);
+ WhseWorksheetLine.Validate("From Zone Code", FromBin."Zone Code");
+ WhseWorksheetLine.Validate("From Bin Code", FromBin.Code);
+ WhseWorksheetLine.Validate("To Zone Code", ToBin."Zone Code");
+ WhseWorksheetLine.Validate("To Bin Code", ToBin.Code);
+ WhseWorksheetLine.Validate(Quantity, Quantity);
+ WhseWorksheetLine.Modify(true);
+ end;
+
+ procedure CreateNumberOfBins(LocationCode: Code[10]; ZoneCode: Code[10]; BinTypeCode: Code[10]; NoOfBins: Integer; IsCrossDock: Boolean)
+ var
+ Bin: Record Bin;
+ i: Integer;
+ ExistingBinCount: Integer;
+ begin
+ Clear(Bin);
+ Bin.Init();
+ Bin.SetRange("Location Code", LocationCode);
+ ExistingBinCount := Bin.Count + 1;
+
+ for i := 1 to NoOfBins do begin
+ CreateBin(Bin, LocationCode, 'Bin' + Format(ExistingBinCount), ZoneCode, BinTypeCode);
+ ExistingBinCount := ExistingBinCount + 1;
+ if IsCrossDock then begin
+ Bin.Validate("Cross-Dock Bin", true);
+ Bin.Modify(true);
+ end;
+ end;
+ end;
+
+ procedure CreatePick(var WarehouseShipmentHeader: Record "Warehouse Shipment Header")
+ var
+ WarehouseShipmentLine: Record "Warehouse Shipment Line";
+ WhseShptHeader: Record "Warehouse Shipment Header";
+ WhseShptLine: Record "Warehouse Shipment Line";
+ WhseShipmentRelease: Codeunit "Whse.-Shipment Release";
+ begin
+ WarehouseShipmentLine.SetRange("No.", WarehouseShipmentHeader."No.");
+ WarehouseShipmentLine.FindFirst();
+ WhseShptLine.Copy(WarehouseShipmentLine);
+ WhseShptHeader.Get(WhseShptLine."No.");
+ if WhseShptHeader.Status = WhseShptHeader.Status::Open then
+ WhseShipmentRelease.Release(WhseShptHeader);
+ WarehouseShipmentLine.SetHideValidationDialog(true);
+ WarehouseShipmentLine.CreatePickDoc(WhseShptLine, WhseShptHeader);
+ end;
+
+ procedure CreatePickFromPickWorksheet(var WhseWorksheetLine: Record "Whse. Worksheet Line"; LineNo: Integer; WkshTemplateName: Code[10]; Name: Code[10]; LocationCode: Code[10]; AssignedID: Code[10]; MaxNoOfLines: Integer; MaxNoOfSourceDoc: Integer; SortPick: Enum "Whse. Activity Sorting Method"; PerShipTo: Boolean; PerItem: Boolean; PerZone: Boolean; PerBin: Boolean; PerWhseDoc: Boolean; PerDate: Boolean; PrintPick: Boolean)
+ var
+ WhseWorksheetLine2: Record "Whse. Worksheet Line";
+ CreatePickReport: Report "Create Pick";
+ begin
+ WhseWorksheetLine2 := WhseWorksheetLine;
+ WhseWorksheetLine2.SetRange("Worksheet Template Name", WkshTemplateName);
+ WhseWorksheetLine2.SetRange(Name, Name);
+ WhseWorksheetLine2.SetRange("Location Code", LocationCode);
+ if LineNo <> 0 then
+ WhseWorksheetLine2.SetRange("Line No.", LineNo);
+
+ CreatePickReport.InitializeReport(
+ AssignedID, MaxNoOfLines, MaxNoOfSourceDoc, SortPick, PerShipTo, PerItem,
+ PerZone, PerBin, PerWhseDoc, PerDate, PrintPick, false, false);
+ CreatePickReport.UseRequestPage(false);
+ CreatePickReport.SetWkshPickLine(WhseWorksheetLine2);
+ CreatePickReport.RunModal();
+ Clear(CreatePickReport);
+
+ WhseWorksheetLine := WhseWorksheetLine2;
+ end;
+
+ procedure CreatePutAwayTemplateHeader(var PutAwayTemplateHeader: Record "Put-away Template Header")
+ begin
+ Clear(PutAwayTemplateHeader);
+ PutAwayTemplateHeader.Init();
+
+ PutAwayTemplateHeader.Validate(Code,
+ LibraryUtility.GenerateRandomCode(PutAwayTemplateHeader.FieldNo(Code), DATABASE::"Put-away Template Header"));
+ PutAwayTemplateHeader.Validate(Description, PutAwayTemplateHeader.Code);
+ PutAwayTemplateHeader.Insert(true);
+ end;
+
+ procedure CreatePutAwayTemplateLine(PutAwayTemplateHeader: Record "Put-away Template Header"; var PutAwayTemplateLine: Record "Put-away Template Line"; FindFixedBin: Boolean; FindFloatingBin: Boolean; FindSameItem: Boolean; FindUnitofMeasureMatch: Boolean; FindBinLessthanMinQty: Boolean; FindEmptyBin: Boolean)
+ var
+ RecRef: RecordRef;
+ begin
+ Clear(PutAwayTemplateLine);
+ PutAwayTemplateLine.Init();
+
+ PutAwayTemplateLine.Validate("Put-away Template Code", PutAwayTemplateHeader.Code);
+ RecRef.GetTable(PutAwayTemplateLine);
+ PutAwayTemplateLine.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, PutAwayTemplateLine.FieldNo("Line No.")));
+ PutAwayTemplateLine.Validate("Find Fixed Bin", FindFixedBin);
+ PutAwayTemplateLine.Validate("Find Floating Bin", FindFloatingBin);
+ PutAwayTemplateLine.Validate("Find Same Item", FindSameItem);
+ PutAwayTemplateLine.Validate("Find Unit of Measure Match", FindUnitofMeasureMatch);
+ PutAwayTemplateLine.Validate("Find Bin w. Less than Min. Qty", FindBinLessthanMinQty);
+ PutAwayTemplateLine.Validate("Find Empty Bin", FindEmptyBin);
+ PutAwayTemplateLine.Insert(true);
+ end;
+
+ procedure CreateStockkeepingUnit(var StockkeepingUnit: Record "Stockkeeping Unit"; Item: Record Item)
+ var
+ Location: Record Location;
+ ItemVariant: Record "Item Variant";
+ begin
+ Clear(StockkeepingUnit);
+ CreateLocationWithInventoryPostingSetup(Location);
+ LibraryInventory.CreateItemVariant(ItemVariant, Item."No.");
+ LibraryInventory.CreateStockkeepingUnitForLocationAndVariant(StockkeepingUnit, Location.Code, Item."No.", ItemVariant.Code);
+ StockkeepingUnit."Unit Cost" := Item."Unit Cost";
+ StockkeepingUnit."Standard Cost" := Item."Standard Cost";
+ StockkeepingUnit.Modify();
+ end;
+
+ procedure CreateTransferHeader(var TransferHeader: Record "Transfer Header"; FromLocation: Text[10]; ToLocation: Text[10]; InTransitCode: Text[10])
+ var
+ Handled: Boolean;
+ begin
+ Clear(TransferHeader);
+ TransferHeader.Init();
+ TransferHeader.Insert(true);
+ OnAfterCreateTransferHeaderInsertTransferHeader(TransferHeader, FromLocation, ToLocation, InTransitCode, Handled);
+ if Handled then
+ exit;
+
+ TransferHeader.Validate("Transfer-from Code", FromLocation);
+ TransferHeader.Validate("Transfer-to Code", ToLocation);
+ TransferHeader.Validate("In-Transit Code", InTransitCode);
+ TransferHeader.Modify(true);
+ OnAfterCreateTransferHeader(TransferHeader, FromLocation, ToLocation, InTransitCode, Handled);
+ end;
+
+ procedure CreateTransferLine(var TransferHeader: Record "Transfer Header"; var TransferLine: Record "Transfer Line"; ItemNo: Text[20]; Quantity: Decimal)
+ var
+ RecRef: RecordRef;
+ begin
+ Clear(TransferLine);
+ TransferLine.Init();
+ TransferLine.Validate("Document No.", TransferHeader."No.");
+ RecRef.GetTable(TransferLine);
+ TransferLine.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, TransferLine.FieldNo("Line No.")));
+ TransferLine.Insert(true);
+ TransferLine.Validate("Item No.", ItemNo);
+ OnAfterValidateItemNo(TransferHeader, TransferLine, ItemNo, Quantity);
+
+ TransferLine.Validate(Quantity, Quantity);
+ TransferLine.Modify(true);
+ end;
+
+ procedure CreateTransferLocations(var FromLocation: Record Location; var ToLocation: Record Location; var InTransitLocation: Record Location)
+ begin
+ CreateLocationWithInventoryPostingSetup(FromLocation);
+ CreateLocationWithInventoryPostingSetup(ToLocation);
+ CreateInTransitLocation(InTransitLocation);
+ end;
+
+ procedure CreateTransferRoute(var TransferRoute: Record "Transfer Route"; TransferFrom: Code[10]; TransferTo: Code[10])
+ begin
+ Clear(TransferRoute);
+ TransferRoute.Init();
+ TransferRoute.Validate("Transfer-from Code", TransferFrom);
+ TransferRoute.Validate("Transfer-to Code", TransferTo);
+ TransferRoute.Insert(true);
+ end;
+
+ procedure CreateAndUpdateTransferRoute(var TransferRoute: Record "Transfer Route"; TransferFrom: Code[10]; TransferTo: Code[10]; InTransitCode: Code[10]; ShippingAgentCode: Code[10]; ShippingAgentServiceCode: Code[10])
+ begin
+ CreateTransferRoute(TransferRoute, TransferFrom, TransferTo);
+ TransferRoute.Validate("In-Transit Code", InTransitCode);
+ TransferRoute.Validate("Shipping Agent Code", ShippingAgentCode);
+ TransferRoute.Validate("Shipping Agent Service Code", ShippingAgentServiceCode);
+ TransferRoute.Modify(true);
+ end;
+
+ procedure CreateZone(var Zone: Record Zone; ZoneCode: Code[10]; LocationCode: Code[10]; BinTypeCode: Code[10]; WhseClassCode: Code[10]; SpecialEquip: Code[10]; ZoneRank: Integer; IsCrossDockZone: Boolean)
+ begin
+ Clear(Zone);
+ Zone.Init();
+
+ if ZoneCode = '' then
+ Zone.Validate(Code, LibraryUtility.GenerateRandomCode(Zone.FieldNo(Code), DATABASE::Zone))
+ else
+ Zone.Validate(Code, ZoneCode);
+
+ Zone.Validate("Location Code", LocationCode);
+ Zone.Validate(Description, Zone.Code);
+ Zone.Validate("Bin Type Code", BinTypeCode);
+ Zone.Validate("Warehouse Class Code", WhseClassCode);
+ Zone.Validate("Special Equipment Code", SpecialEquip);
+ Zone.Validate("Zone Ranking", ZoneRank);
+ Zone.Validate("Cross-Dock Bin Zone", IsCrossDockZone);
+
+ Zone.Insert(true);
+ end;
+
+ procedure CreateWarehouseEmployee(var WarehouseEmployee: Record "Warehouse Employee"; LocationCode: Code[10]; IsDefault: Boolean)
+ begin
+ Clear(WarehouseEmployee);
+ if UserId = '' then
+ exit; // for native database
+ if WarehouseEmployee.Get(UserId, LocationCode) then
+ exit;
+
+ if IsDefault then begin
+ WarehouseEmployee.SetRange("User ID", UserId);
+ WarehouseEmployee.SetRange(Default, true);
+ if WarehouseEmployee.FindFirst() then
+ exit;
+ end;
+
+ WarehouseEmployee.Reset();
+ WarehouseEmployee.Init();
+ WarehouseEmployee.Validate("User ID", UserId);
+ WarehouseEmployee.Validate("Location Code", LocationCode);
+ WarehouseEmployee.Validate(Default, IsDefault);
+ WarehouseEmployee.Insert(true);
+ end;
+
+ procedure CreateWarehouseClass(var WarehouseClass: Record "Warehouse Class")
+ begin
+ Clear(WarehouseClass);
+ WarehouseClass.Init();
+ WarehouseClass.Validate(Code, LibraryUtility.GenerateRandomCode(WarehouseClass.FieldNo(Code), DATABASE::"Warehouse Class"));
+ WarehouseClass.Insert(true);
+ end;
+
+ procedure CreateWarehouseReceiptHeader(var WarehouseReceiptHeader: Record "Warehouse Receipt Header")
+ begin
+ WarehouseReceiptHeader.Init();
+ WarehouseReceiptHeader.Insert(true);
+ end;
+
+ procedure CreateWarehouseShipmentHeader(var WarehouseShipmentHeader: Record "Warehouse Shipment Header")
+ begin
+ WarehouseShipmentHeader.Init();
+ WarehouseShipmentHeader.Insert(true);
+ end;
+
+ procedure CreateWarehouseShipmentLine(var WhseShptLine: Record "Warehouse Shipment Line"; WhseShptHeader: Record "Warehouse Shipment Header")
+ var
+ RecRef: RecordRef;
+ begin
+ Clear(WhseShptLine);
+ WhseShptLine."No." := WhseShptHeader."No.";
+ RecRef.GetTable(WhseShptLine);
+ WhseShptLine."Line No." := LibraryUtility.GetNewLineNo(RecRef, WhseShptLine.FieldNo("Line No."));
+ WhseShptLine.Insert(true);
+ end;
+
+ procedure CreateWarehouseSourceFilter(var WarehouseSourceFilter: Record "Warehouse Source Filter"; Type: Option)
+ begin
+ // Create Warehouse source filter to get Source Document.
+ WarehouseSourceFilter.Init();
+ WarehouseSourceFilter.Validate(Type, Type);
+ WarehouseSourceFilter.Validate(
+ Code, LibraryUtility.GenerateRandomCode(WarehouseSourceFilter.FieldNo(Code), DATABASE::"Warehouse Source Filter"));
+ WarehouseSourceFilter.Insert(true);
+ end;
+
+ procedure CreateWhseInternalPickHeader(var WhseInternalPickHeader: Record "Whse. Internal Pick Header"; LocationCode: Code[10])
+ begin
+ Clear(WhseInternalPickHeader);
+ WhseInternalPickHeader.Validate("Location Code", LocationCode);
+ WhseInternalPickHeader.Insert(true);
+ end;
+
+ procedure CreateWhseInternalPickLine(WhseInternalPickHeader: Record "Whse. Internal Pick Header"; var WhseInternalPickLine: Record "Whse. Internal Pick Line"; ItemNo: Code[20]; Qty: Decimal)
+ var
+ RecRef: RecordRef;
+ begin
+ Clear(WhseInternalPickLine);
+ WhseInternalPickLine.Validate("No.", WhseInternalPickHeader."No.");
+ RecRef.GetTable(WhseInternalPickLine);
+ WhseInternalPickLine.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, WhseInternalPickLine.FieldNo("Line No.")));
+ WhseInternalPickLine.Validate("Item No.", ItemNo);
+ WhseInternalPickLine.Validate(Quantity, Qty);
+ WhseInternalPickLine.Insert(true);
+ end;
+
+ procedure CreateWhseInternalPutawayHdr(var WhseInternalPutAwayHeader: Record "Whse. Internal Put-away Header"; LocationCode: Code[10])
+ begin
+ Clear(WhseInternalPutAwayHeader);
+ WhseInternalPutAwayHeader.Validate("Location Code", LocationCode);
+ WhseInternalPutAwayHeader.Insert(true);
+ end;
+
+ procedure CreateWhseInternalPutawayLine(WhseInternalPutAwayHeader: Record "Whse. Internal Put-away Header"; var WhseInternalPutAwayLine: Record "Whse. Internal Put-away Line"; ItemNo: Code[20]; Qty: Decimal)
+ var
+ RecRef: RecordRef;
+ begin
+ Clear(WhseInternalPutAwayLine);
+ WhseInternalPutAwayLine.Validate("No.", WhseInternalPutAwayHeader."No.");
+ RecRef.GetTable(WhseInternalPutAwayLine);
+ WhseInternalPutAwayLine.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, WhseInternalPutAwayLine.FieldNo("Line No.")));
+ WhseInternalPutAwayLine.Validate("Item No.", ItemNo);
+ WhseInternalPutAwayLine.Validate(Quantity, Qty);
+ WhseInternalPutAwayLine.Insert(true);
+ end;
+
+ procedure CreateWhseJournalTemplate(var WarehouseJournalTemplate: Record "Warehouse Journal Template"; WarehouseJournalTemplateType: Enum "Warehouse Journal Template Type")
+ begin
+ WarehouseJournalTemplate.Init();
+ WarehouseJournalTemplate.Validate(Name, LibraryUtility.GenerateGUID());
+ WarehouseJournalTemplate.Validate(Type, WarehouseJournalTemplateType);
+ WarehouseJournalTemplate.Insert(true);
+ end;
+
+ procedure CreateWarehouseJournalBatch(var WarehouseJournalBatch: Record "Warehouse Journal Batch"; WarehouseJournalTemplateType: Enum "Warehouse Journal Template Type"; LocationCode: Code[10])
+ var
+ WarehouseJournalTemplate: Record "Warehouse Journal Template";
+ begin
+ SelectWhseJournalTemplateName(WarehouseJournalTemplate, WarehouseJournalTemplateType);
+ WarehouseJournalTemplate."Increment Batch Name" := true; // for compatibility with batch name auto increment
+ WarehouseJournalTemplate.Modify();
+ CreateWhseJournalBatch(WarehouseJournalBatch, WarehouseJournalTemplate.Name, LocationCode);
+ end;
+
+ procedure CreateWhseJournalBatch(var WarehouseJournalBatch: Record "Warehouse Journal Batch"; WarehouseJournalTemplateName: Code[10]; LocationCode: Code[10])
+ begin
+ // Create Item Journal Batch with a random Name of String length less than 10.
+ WarehouseJournalBatch.Init();
+ WarehouseJournalBatch.Validate("Journal Template Name", WarehouseJournalTemplateName);
+ WarehouseJournalBatch.Validate(
+ Name, CopyStr(LibraryUtility.GenerateRandomCode(WarehouseJournalBatch.FieldNo(Name), DATABASE::"Warehouse Journal Batch"), 1,
+ MaxStrLen(WarehouseJournalBatch.Name)));
+ WarehouseJournalBatch.Validate("Location Code", LocationCode);
+ WarehouseJournalBatch.Insert(true);
+ end;
+
+ procedure CreateWhseJournalLine(var WarehouseJournalLine: Record "Warehouse Journal Line"; JournalTemplateName: Code[10]; JournalBatchName: Code[10]; LocationCode: Code[10]; ZoneCode: Code[10]; BinCode: Code[20]; EntryType: Option; ItemNo: Text[20]; NewQuantity: Decimal)
+ var
+ NoSeries: Record "No. Series";
+ WarehouseJournalBatch: Record "Warehouse Journal Batch";
+ NoSeriesCodeunit: Codeunit "No. Series";
+ RecRef: RecordRef;
+ DocumentNo: Code[20];
+ JnlSelected: Boolean;
+ begin
+ if not WarehouseJournalBatch.Get(JournalTemplateName, JournalBatchName, LocationCode) then begin
+ WarehouseJournalBatch.Init();
+ WarehouseJournalBatch.Validate("Journal Template Name", JournalTemplateName);
+ WarehouseJournalBatch.SetupNewBatch();
+ WarehouseJournalBatch.Validate(Name, JournalBatchName);
+ WarehouseJournalBatch.Validate(Description, JournalBatchName + ' journal');
+ WarehouseJournalBatch.Validate("Location Code", LocationCode);
+ WarehouseJournalBatch.Insert(true);
+ end;
+
+ Clear(WarehouseJournalLine);
+ WarehouseJournalLine.Init();
+ WarehouseJournalLine.Validate("Journal Template Name", JournalTemplateName);
+ WarehouseJournalLine.Validate("Journal Batch Name", JournalBatchName);
+ WarehouseJournalLine.Validate("Location Code", LocationCode);
+ WarehouseJournalLine.Validate("Zone Code", ZoneCode);
+ WarehouseJournalLine.Validate("Bin Code", BinCode);
+
+ JnlSelected :=
+ WarehouseJournalLine.TemplateSelection(
+ PAGE::"Whse. Item Journal", "Warehouse Journal Template Type"::Item, WarehouseJournalLine);
+ Assert.IsTrue(JnlSelected, 'Journal was not selected');
+ WarehouseJournalLine.OpenJnl(JournalBatchName, LocationCode, WarehouseJournalLine);
+ Commit();
+ WarehouseJournalLine.SetUpNewLine(WarehouseJournalLine);
+
+ RecRef.GetTable(WarehouseJournalLine);
+ WarehouseJournalLine.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, WarehouseJournalLine.FieldNo("Line No.")));
+ WarehouseJournalLine.Insert(true);
+ WarehouseJournalLine.Validate("Registering Date", WorkDate());
+ WarehouseJournalLine.Validate("Entry Type", EntryType);
+ if NoSeries.Get(WarehouseJournalBatch."No. Series") then
+ DocumentNo := NoSeriesCodeunit.PeekNextNo(WarehouseJournalBatch."No. Series", WarehouseJournalLine."Registering Date")
+ else
+ DocumentNo := 'Default Document No.';
+ WarehouseJournalLine.Validate("Whse. Document No.", DocumentNo);
+ WarehouseJournalLine.Validate("Item No.", ItemNo);
+ WarehouseJournalLine.Validate(Quantity, NewQuantity);
+ WarehouseJournalLine.Modify(true);
+ end;
+
+ procedure CreateWhseMovement(BatchName: Text[30]; LocationCode: Text[30]; SortActivity: Enum "Whse. Activity Sorting Method"; BreakBulkFilter: Boolean; DoNotFillQtyToHandle: Boolean)
+ var
+ WhseWorksheetLine: Record "Whse. Worksheet Line";
+ WarehouseActivityHeader: Record "Warehouse Activity Header";
+ WhseWorksheetTemplate: Record "Whse. Worksheet Template";
+ WhseSrcCreateDocument: Report "Whse.-Source - Create Document";
+ begin
+ WhseWorksheetLine.SetFilter(Quantity, '>0');
+ WhseWorksheetTemplate.SetRange(Type, WhseWorksheetTemplate.Type::Movement);
+ WhseWorksheetTemplate.FindFirst();
+ WhseWorksheetLine.SetRange("Worksheet Template Name", WhseWorksheetTemplate.Name);
+ WhseWorksheetLine.SetRange(Name, BatchName);
+ WhseWorksheetLine.SetRange("Location Code", LocationCode);
+ WhseWorksheetLine.FindFirst();
+
+ WhseSrcCreateDocument.SetWhseWkshLine(WhseWorksheetLine);
+ WhseSrcCreateDocument.Initialize(CopyStr(UserId(), 1, 50), SortActivity, false, DoNotFillQtyToHandle, BreakBulkFilter);
+ WhseSrcCreateDocument.UseRequestPage(false);
+ WhseSrcCreateDocument.RunModal();
+ WhseSrcCreateDocument.GetResultMessage(WarehouseActivityHeader.Type::Movement.AsInteger());
+ end;
+
+ procedure CreateWhsePick(var WarehouseShipmentHeader: Record "Warehouse Shipment Header")
+ var
+ WarehouseShipmentLineRec: Record "Warehouse Shipment Line";
+ WhseShptHeader: Record "Warehouse Shipment Header";
+ WhseShptLine: Record "Warehouse Shipment Line";
+ WhseShipmentRelease: Codeunit "Whse.-Shipment Release";
+ begin
+ WarehouseShipmentLineRec.SetRange("No.", WarehouseShipmentHeader."No.");
+ WarehouseShipmentLineRec.FindFirst();
+ WhseShptLine.Copy(WarehouseShipmentLineRec);
+ WhseShptHeader.Get(WhseShptLine."No.");
+ if WhseShptHeader.Status = WhseShptHeader.Status::Open then
+ WhseShipmentRelease.Release(WhseShptHeader);
+ WarehouseShipmentLineRec.SetHideValidationDialog(true);
+ WarehouseShipmentLineRec.CreatePickDoc(WhseShptLine, WhseShptHeader);
+ end;
+
+#if not CLEAN27
+#pragma warning disable AL0801
+ [Obsolete('Moved to codeunit LibraryManufacturing', '27.0')]
+ procedure CreateWhsePickFromProduction(ProductionOrder: Record "Production Order")
+ var
+ LibraryManufacturing: Codeunit "Library - Manufacturing";
+ begin
+ LibraryManufacturing.CreateWhsePickFromProduction(ProductionOrder);
+ end;
+#pragma warning restore AL0801
+#endif
+
+ procedure CreateWhseReceiptFromPO(var PurchaseHeader: Record "Purchase Header")
+ var
+ GetSourceDocInbound: Codeunit "Get Source Doc. Inbound";
+ begin
+ GetSourceDocInbound.CreateFromPurchOrderHideDialog(PurchaseHeader);
+ OnAfterCreateWhseReceiptFromPO(PurchaseHeader);
+ end;
+
+ procedure CreateWhseReceiptFromSalesReturnOrder(var SalesHeader: Record "Sales Header")
+ var
+ GetSourceDocInbound: Codeunit "Get Source Doc. Inbound";
+ begin
+ GetSourceDocInbound.CreateFromSalesReturnOrderHideDialog(SalesHeader);
+ end;
+
+ procedure CreateWhseShipmentFromPurchaseReturnOrder(var PurchaseHeader: Record "Purchase Header")
+ var
+ GetSourceDocOutbound: Codeunit "Get Source Doc. Outbound";
+ begin
+ GetSourceDocOutbound.CreateFromPurchReturnOrderHideDialog(PurchaseHeader);
+ end;
+
+ procedure CreateWhseShipmentFromServiceOrder(ServiceHeader: Record "Service Header")
+ var
+ ServGetSourceDocOutbound: Codeunit "Serv. Get Source Doc. Outbound";
+ begin
+ ServGetSourceDocOutbound.CreateFromServiceOrderHideDialog(ServiceHeader);
+ end;
+
+ procedure CreateWhseShipmentFromSO(var SalesHeader: Record "Sales Header")
+ var
+ GetSourceDocOutbound: Codeunit "Get Source Doc. Outbound";
+ begin
+ GetSourceDocOutbound.CreateFromSalesOrderHideDialog(SalesHeader);
+ end;
+
+ procedure CreateWhseReceiptFromTO(var TransferHeader: Record "Transfer Header")
+ var
+ GetSourceDocInbound: Codeunit "Get Source Doc. Inbound";
+ begin
+ GetSourceDocInbound.CreateFromInbndTransferOrderHideDialog(TransferHeader);
+ end;
+
+ procedure CreateWhseShipmentFromTO(var TransferHeader: Record "Transfer Header")
+ var
+ GetSourceDocOutbound: Codeunit "Get Source Doc. Outbound";
+ begin
+ GetSourceDocOutbound.CreateFromOutbndTransferOrderHideDialog(TransferHeader);
+ end;
+
+ procedure CreateWhseWorksheetName(var WhseWorksheetName: Record "Whse. Worksheet Name"; WhseWorkSheetTemplateName: Code[10]; LocationCode: Code[10])
+ begin
+ // Create Item Journal Batch with a random Name of String length less than 10.
+ WhseWorksheetName.Init();
+ WhseWorksheetName.Validate("Worksheet Template Name", WhseWorkSheetTemplateName);
+ WhseWorksheetName.Validate(
+ Name, CopyStr(LibraryUtility.GenerateRandomCode(WhseWorksheetName.FieldNo(Name), DATABASE::"Whse. Worksheet Name"), 1,
+ MaxStrLen(WhseWorksheetName.Name)));
+ WhseWorksheetName.Validate("Location Code", LocationCode);
+ WhseWorksheetName.Insert(true);
+ end;
+
+ procedure CreateWhseWorksheetLine(var WhseWorksheetLine: Record "Whse. Worksheet Line"; WorksheetTemplateName: Code[10]; Name: Code[10]; LocationCode: Code[10]; WhseDocumentType: Enum "Warehouse Worksheet Document Type")
+ var
+ RecRef: RecordRef;
+ begin
+ Clear(WhseWorksheetLine);
+ WhseWorksheetLine.Init();
+ WhseWorksheetLine.Validate("Worksheet Template Name", WorksheetTemplateName);
+ WhseWorksheetLine.Validate(Name, Name);
+ WhseWorksheetLine.Validate("Location Code", LocationCode);
+ RecRef.GetTable(WhseWorksheetLine);
+ WhseWorksheetLine.Validate("Line No.", LibraryUtility.GetNewLineNo(RecRef, WhseWorksheetLine.FieldNo("Line No.")));
+ WhseWorksheetLine.Insert(true);
+ WhseWorksheetLine.Validate("Whse. Document Type", WhseDocumentType);
+ WhseWorksheetLine.Modify(true);
+ end;
+
+ procedure DeleteEmptyWhseRegisters()
+ var
+ DeleteEmptyWhseRegistersReport: Report "Delete Empty Whse. Registers";
+ begin
+ Commit(); // Commit required for batch job report.
+ Clear(DeleteEmptyWhseRegistersReport);
+ DeleteEmptyWhseRegistersReport.UseRequestPage(false);
+ DeleteEmptyWhseRegistersReport.Run();
+ end;
+
+ procedure FindBin(var Bin: Record Bin; LocationCode: Code[10]; ZoneCode: Code[10]; BinIndex: Integer)
+ begin
+ Bin.Init();
+ Bin.Reset();
+ Bin.SetCurrentKey("Location Code", "Zone Code", Code);
+ Bin.SetRange("Location Code", LocationCode);
+ Bin.SetRange("Zone Code", ZoneCode);
+ Bin.FindSet(true);
+
+ if BinIndex > 1 then
+ Bin.Next(BinIndex - 1);
+ end;
+
+ procedure FindWhseReceiptNoBySourceDoc(SourceType: Option; SourceSubtype: Option; SourceNo: Code[20]): Code[20]
+ var
+ WhseRcptLine: Record "Warehouse Receipt Line";
+ begin
+ WhseRcptLine.SetRange("Source Type", SourceType);
+ WhseRcptLine.SetRange("Source Subtype", SourceSubtype);
+ WhseRcptLine.SetRange("Source No.", SourceNo);
+ if WhseRcptLine.FindFirst() then
+ exit(WhseRcptLine."No.");
+
+ exit('');
+ end;
+
+ procedure FindWhseActivityNoBySourceDoc(SourceType: Option; SourceSubtype: Option; SourceNo: Code[20]): Code[20]
+ var
+ WhseActivityLine: Record "Warehouse Activity Line";
+ begin
+ WhseActivityLine.SetRange("Source Type", SourceType);
+ WhseActivityLine.SetRange("Source Subtype", SourceSubtype);
+ WhseActivityLine.SetRange("Source No.", SourceNo);
+ if WhseActivityLine.FindFirst() then
+ exit(WhseActivityLine."No.");
+
+ exit('');
+ end;
+
+ procedure FindWhseShipmentNoBySourceDoc(SourceType: Option; SourceSubtype: Option; SourceNo: Code[20]): Code[20]
+ var
+ WhseShptLine: Record "Warehouse Shipment Line";
+ begin
+ WhseShptLine.SetRange("Source Type", SourceType);
+ WhseShptLine.SetRange("Source Subtype", SourceSubtype);
+ WhseShptLine.SetRange("Source No.", SourceNo);
+ if WhseShptLine.FindFirst() then
+ exit(WhseShptLine."No.");
+
+ exit('');
+ end;
+
+ procedure FindWhseActivityBySourceDoc(var WarehouseActivityHeader: Record "Warehouse Activity Header"; SourceType: Option; SourceSubtype: Option; SourceNo: Code[20]; SourceLineNo: Integer): Boolean
+ var
+ WarehouseActivityLine: Record "Warehouse Activity Line";
+ begin
+ if not FindWhseActivityLineBySourceDoc(WarehouseActivityLine, SourceType, SourceSubtype, SourceNo, SourceLineNo) then
+ exit(false);
+
+ WarehouseActivityHeader.Get(WarehouseActivityLine."Activity Type", WarehouseActivityLine."No.");
+ exit(true);
+ end;
+
+ procedure FindWhseActivityLineBySourceDoc(var WarehouseActivityLine: Record "Warehouse Activity Line"; SourceType: Option; SourceSubtype: Option; SourceNo: Code[20]; SourceLineNo: Integer): Boolean
+ begin
+ WarehouseActivityLine.SetRange("Source Type", SourceType);
+ WarehouseActivityLine.SetRange("Source Subtype", SourceSubtype);
+ WarehouseActivityLine.SetRange("Source No.", SourceNo);
+ WarehouseActivityLine.SetRange("Source Line No.", SourceLineNo);
+ exit(WarehouseActivityLine.FindFirst())
+ end;
+
+ procedure FindZone(var Zone: Record Zone; LocationCode: Code[10]; BinTypeCode: Code[10]; CrossDockBinZone: Boolean)
+ begin
+ Zone.SetRange("Location Code", LocationCode);
+ Zone.SetRange("Bin Type Code", BinTypeCode);
+ Zone.SetRange("Cross-Dock Bin Zone", CrossDockBinZone);
+ Zone.FindFirst();
+ end;
+
+ procedure GetBinContentInternalMovement(InternalMovementHeader: Record "Internal Movement Header"; LocationCodeFilter: Text[30]; ItemFilter: Text[30]; BinCodeFilter: Text[100])
+ var
+ BinContent: Record "Bin Content";
+ WhseGetBinContentReport: Report "Whse. Get Bin Content";
+ begin
+ BinContent.Init();
+ BinContent.Reset();
+ if LocationCodeFilter <> '' then
+ BinContent.SetRange("Location Code", LocationCodeFilter);
+ if ItemFilter <> '' then
+ BinContent.SetFilter("Item No.", ItemFilter);
+ if BinCodeFilter <> '' then
+ BinContent.SetFilter("Bin Code", BinCodeFilter);
+ WhseGetBinContentReport.SetTableView(BinContent);
+ WhseGetBinContentReport.InitializeInternalMovement(InternalMovementHeader);
+ WhseGetBinContentReport.UseRequestPage(false);
+ WhseGetBinContentReport.RunModal();
+ end;
+
+ procedure GetBinContentTransferOrder(var TransferHeader: Record "Transfer Header"; LocationCodeFilter: Text[30]; ItemFilter: Text[30]; BinCodeFilter: Text[100])
+ var
+ BinContent: Record "Bin Content";
+ WhseGetBinContentReport: Report "Whse. Get Bin Content";
+ begin
+ BinContent.Init();
+ BinContent.Reset();
+ if LocationCodeFilter <> '' then
+ BinContent.SetRange("Location Code", LocationCodeFilter);
+ if ItemFilter <> '' then
+ BinContent.SetFilter("Item No.", ItemFilter);
+ if BinCodeFilter <> '' then
+ BinContent.SetFilter("Bin Code", BinCodeFilter);
+ WhseGetBinContentReport.SetTableView(BinContent);
+ WhseGetBinContentReport.InitializeTransferHeader(TransferHeader);
+ WhseGetBinContentReport.UseRequestPage(false);
+ WhseGetBinContentReport.Run();
+ end;
+
+ procedure GetInboundSourceDocuments(var WhsePutAwayRqst: Record "Whse. Put-away Request"; WhseWorksheetName: Record "Whse. Worksheet Name"; LocationCode: Code[10])
+ var
+ GetInboundSourceDocumentsReport: Report "Get Inbound Source Documents";
+ begin
+ Clear(GetInboundSourceDocumentsReport);
+ GetInboundSourceDocumentsReport.SetWhseWkshName(WhseWorksheetName."Worksheet Template Name", WhseWorksheetName.Name, LocationCode);
+ GetInboundSourceDocumentsReport.UseRequestPage(false);
+ GetInboundSourceDocumentsReport.SetTableView(WhsePutAwayRqst);
+ GetInboundSourceDocumentsReport.Run();
+ end;
+
+ procedure GetOutboundSourceDocuments(var WhsePickRequest: Record "Whse. Pick Request"; WhseWorksheetName: Record "Whse. Worksheet Name"; LocationCode: Code[10])
+ var
+ GetOutboundSourceDocumentsReport: Report "Get Outbound Source Documents";
+ begin
+ Clear(GetOutboundSourceDocumentsReport);
+ GetOutboundSourceDocumentsReport.SetPickWkshName(WhseWorksheetName."Worksheet Template Name", WhseWorksheetName.Name, LocationCode);
+ GetOutboundSourceDocumentsReport.UseRequestPage(false);
+ GetOutboundSourceDocumentsReport.SetTableView(WhsePickRequest);
+ GetOutboundSourceDocumentsReport.Run();
+ end;
+
+ procedure GetSourceDocumentsShipment(var WarehouseShipmentHeader: Record "Warehouse Shipment Header"; var WarehouseSourceFilter: Record "Warehouse Source Filter"; LocationCode: Code[10])
+ var
+ GetSourceDocuments: Report "Get Source Documents";
+ begin
+ // Get Shipment Lines for the required Order in matching criteria.
+ GetSourceDocuments.SetOneCreatedShptHeader(WarehouseShipmentHeader);
+ WarehouseSourceFilter.SetFilters(GetSourceDocuments, LocationCode);
+ GetSourceDocuments.SetSkipBlockedItem(true);
+ GetSourceDocuments.UseRequestPage(false);
+ GetSourceDocuments.RunModal();
+ end;
+
+ procedure GetSourceDocumentsReceipt(var WarehouseReceiptHeader: Record "Warehouse Receipt Header"; var WarehouseSourceFilter: Record "Warehouse Source Filter"; LocationCode: Code[10])
+ var
+ GetSourceDocuments: Report "Get Source Documents";
+ begin
+ // Get Receipt Lines for the required Order in matching criteria.
+ GetSourceDocuments.SetOneCreatedReceiptHeader(WarehouseReceiptHeader);
+ WarehouseSourceFilter.SetFilters(GetSourceDocuments, LocationCode);
+ GetSourceDocuments.SetSkipBlockedItem(true);
+ GetSourceDocuments.UseRequestPage(false);
+ GetSourceDocuments.RunModal();
+ end;
+
+ procedure GetSourceDocInventoryMovement(var WarehouseActivityHeader: Record "Warehouse Activity Header")
+ var
+ CreateInvtPickMovement: Codeunit "Create Inventory Pick/Movement";
+ begin
+ Clear(CreateInvtPickMovement);
+ CreateInvtPickMovement.SetInvtMovement(true);
+ CreateInvtPickMovement.Run(WarehouseActivityHeader);
+ end;
+
+ procedure GetSourceDocInventoryPick(WarehouseActivityHeader: Record "Warehouse Activity Header")
+ var
+ CreateInventoryPickMovement: Codeunit "Create Inventory Pick/Movement";
+ begin
+ Assert.AreEqual(WarehouseActivityHeader.Type::"Invt. Pick", WarehouseActivityHeader.Type, 'Only processes Inventory Pick');
+ Clear(CreateInventoryPickMovement);
+ CreateInventoryPickMovement.Run(WarehouseActivityHeader);
+ end;
+
+ procedure GetSourceDocInventoryPutAway(WarehouseActivityHeader: Record "Warehouse Activity Header")
+ var
+ CreateInventoryPickMovement: Codeunit "Create Inventory Pick/Movement";
+ begin
+ Assert.AreEqual(WarehouseActivityHeader.Type::"Invt. Put-away", WarehouseActivityHeader.Type, 'Only processes Inventory Put-away');
+ Clear(CreateInventoryPickMovement);
+ CreateInventoryPickMovement.Run(WarehouseActivityHeader);
+ end;
+
+ procedure GetWhseDocsPickWorksheet(var WhseWkshLine: Record "Whse. Worksheet Line"; WhsePickRequest: Record "Whse. Pick Request"; Name: Code[10]): Integer
+ var
+ WhsePickRqst2: Record "Whse. Pick Request";
+ WhseWkshTemplate: Record "Whse. Worksheet Template";
+ WhseWkshName: Record "Whse. Worksheet Name";
+ GetOutboundSourceDocumentsReport: Report "Get Outbound Source Documents";
+ begin
+ WhsePickRequest.TestField("Location Code");
+ WhsePickRequest.TestField("Completely Picked", false);
+
+ WhseWkshTemplate.SetRange(Type, WhseWkshTemplate.Type::Pick);
+ WhseWkshTemplate.FindFirst(); // expected to be present as Distribution demo data has been called.
+ if not WhseWkshName.Get(WhseWkshTemplate.Name, Name, WhsePickRequest."Location Code") then begin
+ WhseWkshName.Init();
+ WhseWkshName.Validate("Worksheet Template Name", WhseWkshTemplate.Name);
+ WhseWkshName.Validate(Name, Name);
+ WhseWkshName.Validate("Location Code", WhsePickRequest."Location Code");
+ WhseWkshName.Insert(true);
+ end;
+
+ WhsePickRqst2 := WhsePickRequest;
+ GetOutboundSourceDocumentsReport.SetPickWkshName(WhseWkshTemplate.Name, WhseWkshName.Name, WhsePickRequest."Location Code");
+ WhsePickRqst2.MarkedOnly(true);
+ if not WhsePickRqst2.FindFirst() then begin
+ WhsePickRqst2.MarkedOnly(false);
+ WhsePickRqst2.SetRecFilter();
+ end;
+
+ GetOutboundSourceDocumentsReport.UseRequestPage(false);
+ GetOutboundSourceDocumentsReport.SetTableView(WhsePickRqst2);
+ GetOutboundSourceDocumentsReport.RunModal();
+
+ Clear(WhseWkshLine);
+ WhseWkshLine.SetRange("Worksheet Template Name", WhseWkshTemplate.Name);
+ WhseWkshLine.SetRange(Name, WhseWkshName.Name);
+ WhseWkshLine.SetRange("Location Code", WhsePickRequest."Location Code");
+ WhseWkshLine.SetRange("Whse. Document No.", WhsePickRequest."Document No.");
+ exit(WhseWkshLine.Count);
+ end;
+
+ procedure GetZoneForBin(LocationCode: Code[10]; BinCode: Code[20]): Code[10]
+ var
+ Bin: Record Bin;
+ begin
+ if Bin.Get(LocationCode, BinCode) then
+ exit(Bin."Zone Code");
+
+ exit('');
+ end;
+
+ procedure NoSeriesSetup(var WarehouseSetup: Record "Warehouse Setup")
+ begin
+ WarehouseSetup.Get();
+ WarehouseSetup.Validate("Posted Whse. Receipt Nos.", LibraryUtility.GetGlobalNoSeriesCode());
+ WarehouseSetup.Validate("Posted Whse. Shipment Nos.", LibraryUtility.GetGlobalNoSeriesCode());
+ WarehouseSetup.Validate("Registered Whse. Movement Nos.", LibraryUtility.GetGlobalNoSeriesCode());
+ WarehouseSetup.Validate("Registered Whse. Pick Nos.", LibraryUtility.GetGlobalNoSeriesCode());
+ WarehouseSetup.Validate("Registered Whse. Put-away Nos.", LibraryUtility.GetGlobalNoSeriesCode());
+ WarehouseSetup.Validate("Whse. Movement Nos.", LibraryUtility.GetGlobalNoSeriesCode());
+ WarehouseSetup.Validate("Whse. Pick Nos.", LibraryUtility.GetGlobalNoSeriesCode());
+ WarehouseSetup.Validate("Whse. Put-away Nos.", LibraryUtility.GetGlobalNoSeriesCode());
+ WarehouseSetup.Validate("Whse. Receipt Nos.", LibraryUtility.GetGlobalNoSeriesCode());
+ WarehouseSetup.Validate("Whse. Ship Nos.", LibraryUtility.GetGlobalNoSeriesCode());
+ WarehouseSetup.Validate("Whse. Internal Pick Nos.", LibraryUtility.GetGlobalNoSeriesCode());
+ WarehouseSetup.Validate("Whse. Internal Put-away Nos.", LibraryUtility.GetGlobalNoSeriesCode());
+ WarehouseSetup.Modify(true);
+ end;
+
+ procedure PostInventoryActivity(var WarehouseActivityHeader: Record "Warehouse Activity Header"; Invoice: Boolean)
+ begin
+ PostAndPrintInventoryActivity(WarehouseActivityHeader, Invoice, false);
+ end;
+
+ procedure PostAndPrintInventoryActivity(var WarehouseActivityHeader: Record "Warehouse Activity Header"; Invoice: Boolean; Print: Boolean)
+ var
+ WarehouseActivityLine: Record "Warehouse Activity Line";
+ WhseActivityPost: Codeunit "Whse.-Activity-Post";
+ begin
+ WarehouseActivityLine.SetRange("Activity Type", WarehouseActivityHeader.Type);
+ WarehouseActivityLine.SetRange("No.", WarehouseActivityHeader."No.");
+ WarehouseActivityLine.FindFirst();
+
+ WhseActivityPost.SetInvoiceSourceDoc(Invoice);
+ WhseActivityPost.PrintDocument(Print);
+ WhseActivityPost.Run(WarehouseActivityLine);
+ Clear(WhseActivityPost);
+ end;
+
+ procedure PostTransferOrder(var TransferHeader: Record "Transfer Header"; Ship: Boolean; Receive: Boolean)
+ var
+ TransferOrderPostShipment: Codeunit "TransferOrder-Post Shipment";
+ TransferOrderPostReceipt: Codeunit "TransferOrder-Post Receipt";
+ begin
+ Clear(TransferOrderPostShipment);
+ if Ship then
+ TransferOrderPostShipment.Run(TransferHeader);
+ if Receive then begin
+ TransferOrderPostReceipt.SetHideValidationDialog(true);
+ TransferOrderPostReceipt.Run(TransferHeader);
+ end;
+ end;
+
+ procedure PostWhseAdjustment(var Item: Record Item)
+ var
+ ItemJournalTemplate: Record "Item Journal Template";
+ ItemJournalBatch: Record "Item Journal Batch";
+ begin
+ LibraryAssembly.SetupItemJournal(ItemJournalTemplate, ItemJournalBatch);
+ CalculateWhseAdjustment(Item, ItemJournalBatch);
+ LibraryInventory.PostItemJournalLine(ItemJournalBatch."Journal Template Name", ItemJournalBatch.Name);
+ end;
+
+ procedure PostWhseJournalLine(JournalTemplateName: Text[30]; JournalBatchName: Text[30]; Location: Text[30])
+ var
+ WarehouseJournalLine: Record "Warehouse Journal Line";
+ WhseJnlRegisterBatch: Codeunit "Whse. Jnl.-Register Batch";
+ begin
+ Clear(WhseJnlRegisterBatch);
+ WarehouseJournalLine.SetRange("Journal Template Name", JournalTemplateName);
+ WarehouseJournalLine.SetRange("Journal Batch Name", JournalBatchName);
+ WarehouseJournalLine.SetRange("Location Code", Location);
+ if WarehouseJournalLine.FindFirst() then
+ WhseJnlRegisterBatch.Run(WarehouseJournalLine);
+ end;
+
+ procedure PostWhseReceipt(var WarehouseReceiptHeader: Record "Warehouse Receipt Header")
+ var
+ WarehouseReceiptLine: Record "Warehouse Receipt Line";
+ WhsePostReceipt: Codeunit "Whse.-Post Receipt";
+ begin
+ WarehouseReceiptLine.SetRange("No.", WarehouseReceiptHeader."No.");
+ if WarehouseReceiptLine.FindFirst() then
+ WhsePostReceipt.Run(WarehouseReceiptLine);
+ end;
+
+ procedure PostWhseRcptWithConfirmMsg(No: Code[20])
+ var
+ WarehouseReceiptLine: Record "Warehouse Receipt Line";
+ WhsePostReceiptYesNo: Codeunit "Whse.-Post Receipt (Yes/No)";
+ begin
+ Clear(WhsePostReceiptYesNo);
+ WarehouseReceiptLine.SetRange("No.", No);
+ if WarehouseReceiptLine.FindFirst() then
+ WhsePostReceiptYesNo.Run(WarehouseReceiptLine);
+ end;
+
+ procedure PostWhseShipment(WarehouseShipmentHeader: Record "Warehouse Shipment Header"; Invoice: Boolean)
+ var
+ WarehouseShipmentLine: Record "Warehouse Shipment Line";
+ WhsePostShipment: Codeunit "Whse.-Post Shipment";
+ begin
+ WhsePostShipment.SetPostingSettings(Invoice);
+ WarehouseShipmentLine.SetRange("No.", WarehouseShipmentHeader."No.");
+ if WarehouseShipmentLine.FindFirst() then
+ WhsePostShipment.Run(WarehouseShipmentLine);
+ end;
+
+ procedure PostWhseShptWithShipInvoiceMsg(No: Code[20])
+ var
+ WarehouseShipmentLine: Record "Warehouse Shipment Line";
+ WhsePostShipmentYesNo: Codeunit "Whse.-Post Shipment (Yes/No)";
+ begin
+ Clear(WhsePostShipmentYesNo);
+ WarehouseShipmentLine.SetRange("No.", No);
+ if WarehouseShipmentLine.FindFirst() then
+ WhsePostShipmentYesNo.Run(WarehouseShipmentLine);
+ end;
+
+ procedure RegisterWhseActivity(var WarehouseActivityHeader: Record "Warehouse Activity Header")
+ var
+ WarehouseActivityLine: Record "Warehouse Activity Line";
+ WhseActivityRegister: Codeunit "Whse.-Activity-Register";
+ WMSMgt: Codeunit "WMS Management";
+ begin
+ WarehouseActivityLine.SetRange("Activity Type", WarehouseActivityHeader.Type);
+ WarehouseActivityLine.SetRange("No.", WarehouseActivityHeader."No.");
+ WarehouseActivityLine.FindFirst();
+ WMSMgt.CheckBalanceQtyToHandle(WarehouseActivityLine);
+ WhseActivityRegister.Run(WarehouseActivityLine);
+ end;
+
+ procedure RegisterWhseJournalLine(JournalTemplateName: Text[10]; JournalBatchName: Text[10]; LocationCode: Code[10]; UseBatchJob: Boolean)
+ var
+ WarehouseJournalLine: Record "Warehouse Journal Line";
+ begin
+ WarehouseJournalLine.Init();
+ WarehouseJournalLine.Validate("Journal Template Name", JournalTemplateName);
+ WarehouseJournalLine.Validate("Journal Batch Name", JournalBatchName);
+ WarehouseJournalLine.Validate("Location Code", LocationCode);
+ // Batch job doesn't show confirmation dialog about registering journal lines and message dialog that they have been registered.
+ if UseBatchJob then
+ CODEUNIT.Run(CODEUNIT::"Whse. Jnl.-Register Batch", WarehouseJournalLine)
+ else
+ CODEUNIT.Run(CODEUNIT::"Whse. Jnl.-Register", WarehouseJournalLine);
+ end;
+
+ procedure ReleaseTransferOrder(var TransferHeader: Record "Transfer Header")
+ var
+ ReleaseTransferDocument: Codeunit "Release Transfer Document";
+ begin
+ Clear(ReleaseTransferDocument);
+ ReleaseTransferDocument.Run(TransferHeader);
+ end;
+
+ procedure ReleaseWarehouseShipment(var WarehouseShipmentHeader: Record "Warehouse Shipment Header")
+ var
+ WhseShipmentRelease: Codeunit "Whse.-Shipment Release";
+ begin
+ WhseShipmentRelease.Release(WarehouseShipmentHeader);
+ end;
+
+ procedure ReleaseWarehouseInternalPick(var WhseInternalPickHeader: Record "Whse. Internal Pick Header")
+ var
+ WhseInternalPickRelease: Codeunit "Whse. Internal Pick Release";
+ begin
+ WhseInternalPickRelease.Release(WhseInternalPickHeader);
+ end;
+
+ procedure ReleaseWarehouseInternalPutAway(var WhseInternalPutAwayHeader: Record "Whse. Internal Put-away Header")
+ var
+ WhseIntPutAwayRelease: Codeunit "Whse. Int. Put-away Release";
+ begin
+ WhseIntPutAwayRelease.Release(WhseInternalPutAwayHeader);
+ end;
+
+ procedure ReopenTransferOrder(var TransferHeader: Record "Transfer Header")
+ var
+ ReleaseTransferDocument: Codeunit "Release Transfer Document";
+ begin
+ ReleaseTransferDocument.Reopen(TransferHeader);
+ end;
+
+ procedure ReopenWhseShipment(var WhseShipmentHeader: Record "Warehouse Shipment Header")
+ var
+ WhseShipmentRelease: Codeunit "Whse.-Shipment Release";
+ begin
+ WhseShipmentRelease.Reopen(WhseShipmentHeader);
+ end;
+
+ procedure RunDateCompressWhseEntries(ItemNo: Code[20])
+ var
+ WarehouseEntry: Record "Warehouse Entry";
+ DateCompressWhseEntries: Report "Date Compress Whse. Entries";
+ begin
+ Commit(); // Commit required for batch job report.
+ Clear(DateCompressWhseEntries);
+ WarehouseEntry.SetRange("Item No.", ItemNo);
+ DateCompressWhseEntries.SetTableView(WarehouseEntry);
+ DateCompressWhseEntries.Run();
+ end;
+
+ procedure SelectBinType(Receive: Boolean; Ship: Boolean; PutAway: Boolean; Pick: Boolean): Code[10]
+ var
+ BinType: Record "Bin Type";
+ begin
+ Clear(BinType);
+ BinType.Init();
+
+ BinType.SetRange(Receive, Receive);
+ BinType.SetRange(Ship, Ship);
+ BinType.SetRange("Put Away", PutAway);
+ BinType.SetRange(Pick, Pick);
+ if not BinType.FindFirst() then
+ CreateBinType(BinType, Receive, Ship, PutAway, Pick);
+
+ exit(BinType.Code);
+ end;
+
+ procedure SelectWhseJournalTemplateName(var WarehouseJournalTemplate: Record "Warehouse Journal Template"; WarehouseJournalTemplateType: Enum "Warehouse Journal Template Type")
+ begin
+ // Find Item Journal Template for the given Template Type.
+ WarehouseJournalTemplate.SetRange(Type, WarehouseJournalTemplateType);
+ if not WarehouseJournalTemplate.FindFirst() then
+ CreateWhseJournalTemplate(WarehouseJournalTemplate, WarehouseJournalTemplateType);
+ end;
+
+ procedure SelectWhseJournalBatchName(var WarehouseJournalBatch: Record "Warehouse Journal Batch"; WhseJournalBatchTemplateType: Enum "Warehouse Journal Template Type"; WarehouseJournalTemplateName: Code[10]; LocationCode: Code[10])
+ begin
+ // Find Name for Batch Name.
+ WarehouseJournalBatch.SetRange("Template Type", WhseJournalBatchTemplateType);
+ WarehouseJournalBatch.SetRange("Journal Template Name", WarehouseJournalTemplateName);
+ WarehouseJournalBatch.SetRange("Location Code", LocationCode);
+
+ // If Warehouse Journal Batch not found then create it.
+ if not WarehouseJournalBatch.FindFirst() then
+ CreateWhseJournalBatch(WarehouseJournalBatch, WarehouseJournalTemplateName, LocationCode);
+ end;
+
+ procedure SelectWhseWorksheetTemplate(var WhseWorksheetTemplate: Record "Whse. Worksheet Template"; TemplateType: Enum "Warehouse Worksheet Template Type")
+ begin
+ // Find Item Journal Template for the given Template Type.
+ WhseWorksheetTemplate.SetRange(Type, TemplateType);
+ WhseWorksheetTemplate.FindFirst();
+ end;
+
+ procedure SelectWhseWorksheetName(var WhseWorksheetName: Record "Whse. Worksheet Name"; WhseWorkSheetTemplateName: Code[10]; LocationCode: Code[10])
+ begin
+ // Find Name for Warehouse Worksheet Name.
+ WhseWorksheetName.SetRange("Worksheet Template Name", WhseWorkSheetTemplateName);
+ WhseWorksheetName.SetRange("Location Code", LocationCode);
+
+ // If Warehouse Worksheet Name not found then create it.
+ if not WhseWorksheetName.FindFirst() then
+ CreateWhseWorksheetName(WhseWorksheetName, WhseWorkSheetTemplateName, LocationCode);
+ end;
+
+ procedure SetQtyToHandleInternalMovement(InternalMovementHeader: Record "Internal Movement Header"; Qty: Decimal)
+ var
+ InternalMovementLine: Record "Internal Movement Line";
+ begin
+ Clear(InternalMovementLine);
+ InternalMovementLine.SetRange("No.", InternalMovementHeader."No.");
+ InternalMovementLine.FindSet();
+ repeat
+ InternalMovementLine.Validate(Quantity, Qty);
+ InternalMovementLine.Modify(true);
+ until InternalMovementLine.Next() = 0;
+ end;
+
+ procedure SetQtyHandleInventoryMovement(WarehouseActivityHeader: Record "Warehouse Activity Header"; Qty: Decimal)
+ begin
+ SetQtyToHandleWhseActivity(WarehouseActivityHeader, Qty);
+ end;
+
+ procedure SetQtyToHandleWhseActivity(WhseActivityHdr: Record "Warehouse Activity Header"; Qty: Decimal)
+ var
+ WhseActivityLine: Record "Warehouse Activity Line";
+ begin
+ Clear(WhseActivityLine);
+ WhseActivityLine.SetRange("Activity Type", WhseActivityHdr.Type);
+ WhseActivityLine.SetRange("No.", WhseActivityHdr."No.");
+ WhseActivityLine.FindSet();
+ repeat
+ WhseActivityLine.Validate(Quantity, Qty);
+ WhseActivityLine.Modify(true);
+ until WhseActivityLine.Next() = 0;
+ end;
+
+ procedure SetRequireShipmentOnWarehouseSetup(RequireShipment: Boolean)
+ var
+ WarehouseSetup: Record "Warehouse Setup";
+ begin
+ WarehouseSetup.Get();
+ WarehouseSetup.Validate("Require Shipment", RequireShipment);
+ WarehouseSetup.Modify(true);
+ end;
+
+ procedure SetRequireReceiveOnWarehouseSetup(RequireReceive: Boolean)
+ var
+ WarehouseSetup: Record "Warehouse Setup";
+ begin
+ WarehouseSetup.Get();
+ WarehouseSetup.Validate("Require Receive", RequireReceive);
+ WarehouseSetup.Modify(true);
+ end;
+
+ procedure UpdateInventoryOnLocationWithDirectedPutAwayAndPick(ItemNo: Code[20]; LocationCode: Code[10]; Quantity: Decimal; WithItemTracking: Boolean)
+ var
+ Zone: Record Zone;
+ Bin: Record Bin;
+ begin
+ FindZone(Zone, LocationCode, SelectBinType(false, false, true, true), false);
+ FindBin(Bin, LocationCode, Zone.Code, 1);
+ UpdateInventoryInBinUsingWhseJournal(Bin, ItemNo, Quantity, WithItemTracking);
+ end;
+
+ procedure UpdateInventoryInBinUsingWhseJournal(Bin: Record Bin; ItemNo: Code[20]; Quantity: Decimal; WithItemTracking: Boolean)
+ var
+ Item: Record Item;
+ begin
+ UpdateWarehouseStockOnBin(Bin, ItemNo, Quantity, WithItemTracking);
+
+ Item.Get(ItemNo);
+ PostWhseAdjustment(Item);
+ end;
+
+ procedure UpdateWarehouseStockOnBin(Bin: Record Bin; ItemNo: Code[20]; Quantity: Decimal; WithItemTracking: Boolean)
+ var
+ WarehouseJournalTemplate: Record "Warehouse Journal Template";
+ WarehouseJournalBatch: Record "Warehouse Journal Batch";
+ WarehouseJournalLine: Record "Warehouse Journal Line";
+ begin
+ SelectWhseJournalTemplateName(WarehouseJournalTemplate, WarehouseJournalTemplate.Type::Item);
+ WarehouseJournalTemplate.Validate("No. Series", LibraryUtility.GetGlobalNoSeriesCode());
+ WarehouseJournalTemplate.Modify(true);
+ SelectWhseJournalBatchName(
+ WarehouseJournalBatch, WarehouseJournalTemplate.Type, WarehouseJournalTemplate.Name, Bin."Location Code");
+ WarehouseJournalBatch.Validate("No. Series", LibraryUtility.GetGlobalNoSeriesCode());
+ WarehouseJournalBatch.Modify(true);
+
+ CreateWhseJournalLine(
+ WarehouseJournalLine, WarehouseJournalBatch."Journal Template Name", WarehouseJournalBatch.Name,
+ Bin."Location Code", Bin."Zone Code", Bin.Code,
+ WarehouseJournalLine."Entry Type"::"Positive Adjmt.", ItemNo, Quantity);
+ if WithItemTracking then
+ WarehouseJournalLine.OpenItemTrackingLines();
+
+ RegisterWhseJournalLine(
+ WarehouseJournalBatch."Journal Template Name", WarehouseJournalBatch.Name, Bin."Location Code", true);
+ end;
+
+ procedure WhseCalculateInventory(WarehouseJournalLine: Record "Warehouse Journal Line"; var BinContent: Record "Bin Content"; NewRegisteringDate: Date; WhseDocNo: Code[20]; ItemsNotOnInvt: Boolean)
+ var
+ WhseCalculateInventoryReport: Report "Whse. Calculate Inventory";
+ begin
+ Commit(); // Commit is required to run the report.
+ WhseCalculateInventoryReport.SetWhseJnlLine(WarehouseJournalLine);
+ WhseCalculateInventoryReport.InitializeRequest(NewRegisteringDate, WhseDocNo, ItemsNotOnInvt);
+ WhseCalculateInventoryReport.SetTableView(BinContent);
+ WhseCalculateInventoryReport.UseRequestPage(false);
+ WhseCalculateInventoryReport.Run();
+ end;
+
+ procedure WhseSourceCreateDocument(var WhseWorksheetLine: Record "Whse. Worksheet Line"; SortActivity: Enum "Whse. Activity Sorting Method"; PrintDoc: Boolean;
+ DoNotFillQtytoHandle: Boolean;
+ BreakbulkFilter: Boolean)
+ var
+ WhseSourceCreateDocumentReport: Report "Whse.-Source - Create Document";
+ begin
+ WhseSourceCreateDocumentReport.Initialize(CopyStr(UserId(), 1, 50), SortActivity, PrintDoc, DoNotFillQtytoHandle, BreakbulkFilter);
+ WhseSourceCreateDocumentReport.UseRequestPage(false);
+ WhseSourceCreateDocumentReport.SetWhseWkshLine(WhseWorksheetLine);
+ WhseSourceCreateDocumentReport.Run();
+ end;
+
+ procedure WhseGetBinContent(var BinContent: Record "Bin Content"; WhseWorksheetLine: Record "Whse. Worksheet Line"; WhseInternalPutAwayHeader: Record "Whse. Internal Put-away Header"; DestinationType: Enum "Warehouse Destination Type 2")
+ var
+ WhseGetBinContentReport: Report "Whse. Get Bin Content";
+ begin
+ WhseGetBinContentReport.SetParameters(WhseWorksheetLine, WhseInternalPutAwayHeader, DestinationType);
+ WhseGetBinContentReport.SetTableView(BinContent);
+ WhseGetBinContentReport.UseRequestPage(false);
+ WhseGetBinContentReport.Run();
+ end;
+
+ procedure WhseGetBinContentFromItemJournalLine(var BinContent: Record "Bin Content"; ItemJournalLine: Record "Item Journal Line")
+ var
+ WhseGetBinContentReport: Report "Whse. Get Bin Content";
+ begin
+ Clear(WhseGetBinContentReport);
+ WhseGetBinContentReport.SetTableView(BinContent);
+ WhseGetBinContentReport.InitializeItemJournalLine(ItemJournalLine);
+ WhseGetBinContentReport.UseRequestPage(false);
+ WhseGetBinContentReport.Run();
+ end;
+
+ procedure WarehouseJournalSetup(LocationCode: Code[10]; var WarehouseJournalTemplate: Record "Warehouse Journal Template"; var WarehouseJournalBatch: Record "Warehouse Journal Batch")
+ begin
+ Clear(WarehouseJournalTemplate);
+ WarehouseJournalTemplate.Init();
+ SelectWhseJournalTemplateName(WarehouseJournalTemplate, WarehouseJournalTemplate.Type::Item);
+ WarehouseJournalTemplate.Validate("No. Series", LibraryUtility.GetGlobalNoSeriesCode());
+ WarehouseJournalTemplate.Modify(true);
+
+ Clear(WarehouseJournalBatch);
+ WarehouseJournalBatch.Init();
+ SelectWhseJournalBatchName(
+ WarehouseJournalBatch, WarehouseJournalTemplate.Type, WarehouseJournalTemplate.Name, LocationCode);
+ WarehouseJournalBatch.Validate("No. Series", LibraryUtility.GetGlobalNoSeriesCode());
+ WarehouseJournalBatch.Modify(true);
+ end;
+
+ [IntegrationEvent(false, false)]
+ local procedure OnAfterCreateBin(var Bin: Record Bin; LocationCode: Code[10]; BinCode: Code[20]; ZoneCode: Code[10]; BinTypeCode: Code[10])
+ begin
+ end;
+
+ [IntegrationEvent(false, false)]
+ local procedure OnAfterCreateFullWMSLocation(var Location: Record Location; BinsPerZone: Integer)
+ begin
+ end;
+
+ [IntegrationEvent(false, false)]
+ local procedure OnAfterCreateLocationCodeAndName(var Location: Record Location)
+ begin
+ end;
+
+ [IntegrationEvent(false, false)]
+ local procedure OnAfterCreateLocationWMS(var Location: Record Location; BinMandatory: Boolean; RequirePutAway: Boolean; RequirePick: Boolean; RequireReceive: Boolean; RequireShipment: Boolean)
+ begin
+ end;
+
+ [IntegrationEvent(false, false)]
+ local procedure OnAfterCreateTransferHeaderInsertTransferHeader(var TransferHeader: Record "Transfer Header"; FromLocation: Text[10]; ToLocation: Text[10]; InTransitCode: Text[10]; var Handled: Boolean)
+ begin
+ end;
+
+ [IntegrationEvent(false, false)]
+ local procedure OnAfterCreateTransferHeader(var TransferHeader: Record "Transfer Header"; FromLocation: Text[10]; ToLocation: Text[10]; InTransitCode: Text[10]; var Handled: Boolean)
+ begin
+ end;
+
+ [IntegrationEvent(false, false)]
+ local procedure OnAfterValidateItemNo(var TransferHeader: Record "Transfer Header"; var TransferLine: Record "Transfer Line"; ItemNo: Text[20]; Quantity: Decimal)
+ begin
+ end;
+
+ [IntegrationEvent(false, false)]
+ local procedure OnAfterCreateWhseReceiptFromPO(var PurchaseHeader: Record "Purchase Header")
+ begin
+ end;
+}
+
diff --git a/Apps/W1/ApplicationTestLibrary/LibraryWorkflow.Codeunit.al b/Apps/W1/ApplicationTestLibrary/LibraryWorkflow.Codeunit.al
new file mode 100644
index 0000000000..d60320d476
--- /dev/null
+++ b/Apps/W1/ApplicationTestLibrary/LibraryWorkflow.Codeunit.al
@@ -0,0 +1,608 @@
+///
+/// Provides utility functions for creating and managing workflows in test scenarios, including workflow steps, workflow events, and workflow responses.
+///
+codeunit 131101 "Library - Workflow"
+{
+ Permissions = TableData "Workflow Step" = d,
+ TableData "Workflow Step Instance" = d,
+ TableData "Workflow Table Relation Value" = d,
+ TableData "Workflow Step Argument" = d,
+ TableData "Workflow Rule" = d,
+ TableData "Workflow - Record Change" = d,
+ TableData "Workflow Record Change Archive" = d,
+ TableData "Workflow Step Instance Archive" = d,
+ TableData "Workflow Step Argument Archive" = d;
+
+ trigger OnRun()
+ begin
+ end;
+
+ var
+ LibraryUtility: Codeunit "Library - Utility";
+ InvalidEventCondErr: Label 'No event conditions are specified.';
+
+ procedure CreateWorkflow(var Workflow: Record Workflow)
+ begin
+ Workflow.Init();
+ Workflow.Code := GenerateRandomWorkflowCode();
+ Workflow.Description := CopyStr(LibraryUtility.GenerateRandomXMLText(MaxStrLen(Workflow.Description)), 1, MaxStrLen(Workflow.Description));
+ Workflow.Category := CreateWorkflowCategory();
+ Workflow.Template := false;
+ Workflow.Insert(true);
+ end;
+
+ procedure CreateTemplateWorkflow(var Workflow: Record Workflow)
+ begin
+ CreateWorkflow(Workflow);
+ Workflow.Validate(Template, true);
+ Workflow.Modify();
+ end;
+
+ procedure CreateEnabledWorkflow(var Workflow: Record Workflow; WorkflowCode: Code[17])
+ var
+ WorkflowSetup: Codeunit "Workflow Setup";
+ begin
+ CopyWorkflow(Workflow, WorkflowSetup.GetWorkflowTemplateCode(WorkflowCode));
+ EnableWorkflow(Workflow);
+ end;
+
+ procedure CreateWorkflowTableRelation(var WorkflowTableRelation: Record "Workflow - Table Relation"; TableId: Integer; FieldId: Integer; RelatedTableId: Integer; RelatedFieldId: Integer)
+ begin
+ WorkflowTableRelation.Init();
+ WorkflowTableRelation."Table ID" := TableId;
+ WorkflowTableRelation."Field ID" := FieldId;
+ WorkflowTableRelation."Related Table ID" := RelatedTableId;
+ WorkflowTableRelation."Related Field ID" := RelatedFieldId;
+ if WorkflowTableRelation.Insert(true) then;
+ end;
+
+ procedure CreateWorkflowStepArgument(var WorkflowStepArgument: Record "Workflow Step Argument"; Type: Option; UserID: Code[50]; TemplateName: Code[10]; BatchName: Code[10]; ApproverType: Enum "Workflow Approver Type"; InformUser: Boolean)
+ begin
+ WorkflowStepArgument.Init();
+ WorkflowStepArgument.Type := Type;
+ WorkflowStepArgument."General Journal Template Name" := TemplateName;
+ WorkflowStepArgument."General Journal Batch Name" := BatchName;
+ WorkflowStepArgument."Notification User ID" := UserID;
+ WorkflowStepArgument."Approver Type" := ApproverType;
+ WorkflowStepArgument."Approver Limit Type" := WorkflowStepArgument."Approver Limit Type"::"Approver Chain";
+ WorkflowStepArgument."Show Confirmation Message" := InformUser;
+ WorkflowStepArgument.Insert(true);
+ end;
+
+ procedure CreateNotificationSetup(var NotificationSetup: Record "Notification Setup"; UserID: Code[50]; NotificationType: Enum "Notification Entry Type"; NotificationMethod: Enum "Notification Method Type")
+ begin
+ NotificationSetup.Init();
+ NotificationSetup."User ID" := UserID;
+ NotificationSetup."Notification Type" := NotificationType;
+ NotificationSetup."Notification Method" := NotificationMethod;
+ NotificationSetup.Insert(true);
+ end;
+
+ procedure SetNotifySenderInResponse(WorkflowCode: Code[20]; StepID: Integer)
+ var
+ WorkflowStep: Record "Workflow Step";
+ WorkflowStepArgument: Record "Workflow Step Argument";
+ begin
+ WorkflowStep.Get(WorkflowCode, StepID);
+ WorkflowStepArgument.Get(WorkflowStep.Argument);
+ WorkflowStepArgument.Validate("Notify Sender", true);
+ WorkflowStepArgument.Modify();
+ end;
+
+ procedure DeleteAllExistingWorkflows()
+ var
+ Workflow: Record Workflow;
+ WorkflowStep: Record "Workflow Step";
+ WorkflowStepInstance: Record "Workflow Step Instance";
+ WorkflowTableRelationValue: Record "Workflow Table Relation Value";
+ WorkflowStepArgument: Record "Workflow Step Argument";
+ WorkflowStepArgumentArchive: Record "Workflow Step Argument Archive";
+ WorkflowStepInstanceArchive: Record "Workflow Step Instance Archive";
+ WorkflowRule: Record "Workflow Rule";
+ WorkflowRecordChange: Record "Workflow - Record Change";
+ WorkflowRecordChangeArchive: Record "Workflow Record Change Archive";
+ begin
+ WorkflowRecordChange.DeleteAll();
+ WorkflowRecordChangeArchive.DeleteAll();
+
+ WorkflowTableRelationValue.DeleteAll();
+
+ WorkflowStepArgument.DeleteAll();
+ WorkflowStepArgumentArchive.DeleteAll();
+
+ WorkflowRule.DeleteAll();
+ WorkflowStepInstanceArchive.DeleteAll();
+
+ WorkflowStepInstance.DeleteAll();
+ WorkflowStep.DeleteAll();
+
+ Workflow.DeleteAll();
+ end;
+
+ procedure DisableAllWorkflows()
+ var
+ Workflow: Record Workflow;
+ begin
+ Workflow.SetRange(Template, false);
+ Workflow.ModifyAll(Enabled, false, true);
+ end;
+
+ procedure EnableWorkflow(var Workflow: Record Workflow)
+ begin
+ Workflow.Validate(Enabled, true);
+ Workflow.Modify(true);
+ end;
+
+ procedure DeleteNotifications()
+ var
+ NotificationEntry: Record "Notification Entry";
+ begin
+ NotificationEntry.DeleteAll();
+ end;
+
+ procedure GetGeneralJournalTemplateAndBatch(var GeneralJnlTemplateCode: Code[10]; var GeneralJnlBatchCode: Code[10])
+ var
+ GenJournalTemplate: Record "Gen. Journal Template";
+ GenJournalBatch: Record "Gen. Journal Batch";
+ LibraryERM: Codeunit "Library - ERM";
+ begin
+ GenJournalTemplate.SetRange(Type, GenJournalTemplate.Type::Payments);
+ GenJournalTemplate.FindFirst();
+
+ GeneralJnlTemplateCode := GenJournalTemplate.Name;
+
+ LibraryERM.CreateGenJournalBatch(GenJournalBatch, GeneralJnlTemplateCode);
+
+ GeneralJnlBatchCode := GenJournalBatch.Name;
+ end;
+
+ procedure InsertEntryPointEventStep(Workflow: Record Workflow; ActivityName: Code[128]): Integer
+ var
+ WorkflowStep: Record "Workflow Step";
+ begin
+ InsertStep(WorkflowStep, Workflow.Code, WorkflowStep.Type::"Event", ActivityName);
+ WorkflowStep.Validate("Entry Point", true);
+ WorkflowStep.Modify(true);
+ exit(WorkflowStep.ID);
+ end;
+
+ procedure InsertEventStep(Workflow: Record Workflow; ActivityName: Code[128]; PreviousStepID: Integer): Integer
+ var
+ WorkflowStep: Record "Workflow Step";
+ begin
+ InsertStep(WorkflowStep, Workflow.Code, WorkflowStep.Type::"Event", ActivityName);
+ WorkflowStep."Sequence No." := GetNextSequenceNo(Workflow, PreviousStepID);
+ WorkflowStep.Validate("Previous Workflow Step ID", PreviousStepID);
+ WorkflowStep.Modify(true);
+ exit(WorkflowStep.ID);
+ end;
+
+ procedure InsertResponseStep(Workflow: Record Workflow; ActivityName: Code[128]; PreviousStepID: Integer): Integer
+ var
+ WorkflowStep: Record "Workflow Step";
+ begin
+ InsertStep(WorkflowStep, Workflow.Code, WorkflowStep.Type::Response, ActivityName);
+ WorkflowStep."Sequence No." := GetNextSequenceNo(Workflow, PreviousStepID);
+ WorkflowStep.Validate("Previous Workflow Step ID", PreviousStepID);
+ WorkflowStep.Modify(true);
+ exit(WorkflowStep.ID);
+ end;
+
+ procedure InsertSubWorkflowStep(Workflow: Record Workflow; WorkflowCode: Code[20]; PreviousStepID: Integer): Integer
+ var
+ WorkflowStep: Record "Workflow Step";
+ begin
+ InsertStep(WorkflowStep, Workflow.Code, WorkflowStep.Type::"Sub-Workflow", WorkflowCode);
+ WorkflowStep."Sequence No." := GetNextSequenceNo(Workflow, PreviousStepID);
+ WorkflowStep.Validate("Previous Workflow Step ID", PreviousStepID);
+ WorkflowStep.Modify(true);
+ exit(WorkflowStep.ID);
+ end;
+
+ local procedure InsertStep(var WorkflowStep: Record "Workflow Step"; WorkflowCode: Code[20]; StepType: Option; FunctionName: Code[128])
+ begin
+ WorkflowStep.Validate("Workflow Code", WorkflowCode);
+ WorkflowStep.Validate(Type, StepType);
+ WorkflowStep.Validate("Function Name", FunctionName);
+ WorkflowStep.Insert(true);
+ end;
+
+ local procedure GetNextSequenceNo(Workflow: Record Workflow; PreviousStepID: Integer): Integer
+ var
+ WorkflowStep: Record "Workflow Step";
+ begin
+ WorkflowStep.SetRange("Workflow Code", Workflow.Code);
+ WorkflowStep.SetRange("Previous Workflow Step ID", PreviousStepID);
+ WorkflowStep.SetCurrentKey("Sequence No.");
+ if WorkflowStep.FindLast() then
+ exit(WorkflowStep."Sequence No." + 1);
+ exit(1);
+ end;
+
+ procedure SetSequenceNo(Workflow: Record Workflow; WorkflowStepID: Integer; SequenceNo: Integer)
+ var
+ WorkflowStep: Record "Workflow Step";
+ begin
+ WorkflowStep.Get(Workflow.Code, WorkflowStepID);
+ WorkflowStep.Validate("Sequence No.", SequenceNo);
+ WorkflowStep.Modify(true);
+ end;
+
+ procedure SetNextStep(Workflow: Record Workflow; WorkflowStepID: Integer; NextStepID: Integer)
+ var
+ WorkflowStep: Record "Workflow Step";
+ begin
+ WorkflowStep.Get(Workflow.Code, WorkflowStepID);
+ WorkflowStep.Validate("Next Workflow Step ID", NextStepID);
+ WorkflowStep.Modify(true);
+ end;
+
+ procedure SetEventStepAsEntryPoint(Workflow: Record Workflow; WorkflowStepID: Integer)
+ var
+ WorkflowStep: Record "Workflow Step";
+ begin
+ WorkflowStep.Get(Workflow.Code, WorkflowStepID);
+ WorkflowStep.TestField(Type, WorkflowStep.Type::"Event");
+ WorkflowStep.Validate("Entry Point", true);
+ WorkflowStep.Modify(true);
+ end;
+
+ procedure SetSubWorkflowStepAsEntryPoint(Workflow: Record Workflow; WorkflowStepID: Integer)
+ var
+ WorkflowStep: Record "Workflow Step";
+ begin
+ WorkflowStep.Get(Workflow.Code, WorkflowStepID);
+ WorkflowStep.TestField(Type, WorkflowStep.Type::"Sub-Workflow");
+ WorkflowStep.Validate("Entry Point", true);
+ WorkflowStep.Modify(true);
+ end;
+
+ procedure FindWorkflowStepForCreateApprovalRequests(var WorkflowStep: Record "Workflow Step"; WorkflowCode: Code[20])
+ var
+ WorkflowResponseHandling: Codeunit "Workflow Response Handling";
+ begin
+ WorkflowStep.SetRange("Workflow Code", WorkflowCode);
+ WorkflowStep.SetRange(Type, WorkflowStep.Type::Response);
+ WorkflowStep.SetRange("Function Name", WorkflowResponseHandling.CreateApprovalRequestsCode());
+ WorkflowStep.FindFirst();
+ end;
+
+ procedure UpdateWorkflowStepArgumentWithDirectApproverLimitType(Argument: Guid)
+ var
+ WorkflowStepArgument: Record "Workflow Step Argument";
+ begin
+ UpdateWorkflowStepArgumentApproverLimitType(
+ Argument, WorkflowStepArgument."Approver Type"::Approver,
+ WorkflowStepArgument."Approver Limit Type"::"Direct Approver", '', '');
+ end;
+
+ procedure UpdateWorkflowStepArgumentApproverLimitType(Argument: Guid; ApproverType: Enum "Workflow Approver Type"; ApproverLimitType: Enum "Workflow Approver Limit Type"; WorkflowUserGroupCode: Code[20]; ApproverUserID: Code[50])
+ var
+ WorkflowStepArgument: Record "Workflow Step Argument";
+ begin
+ WorkflowStepArgument.Get(Argument);
+ WorkflowStepArgument."Approver Type" := ApproverType;
+ WorkflowStepArgument."Approver Limit Type" := ApproverLimitType;
+ WorkflowStepArgument."Workflow User Group Code" := WorkflowUserGroupCode;
+ WorkflowStepArgument."Approver User ID" := ApproverUserID;
+ WorkflowStepArgument.Modify();
+ end;
+
+ procedure SetWorkflowDirectApprover(WorkflowCode: Code[20])
+ var
+ WorkflowStep: Record "Workflow Step";
+ WorkflowStepArgument: Record "Workflow Step Argument";
+ begin
+ FindWorkflowStepForCreateApprovalRequests(WorkflowStep, WorkflowCode);
+ UpdateWorkflowStepArgumentApproverLimitType(
+ WorkflowStep.Argument, WorkflowStepArgument."Approver Type"::Approver,
+ WorkflowStepArgument."Approver Limit Type"::"Direct Approver", '', '');
+ end;
+
+ procedure SetWorkflowSpecificApprover(WorkflowCode: Code[20]; ApproverID: Code[50])
+ var
+ WorkflowStep: Record "Workflow Step";
+ WorkflowStepArgument: Record "Workflow Step Argument";
+ begin
+ FindWorkflowStepForCreateApprovalRequests(WorkflowStep, WorkflowCode);
+ UpdateWorkflowStepArgumentApproverLimitType(
+ WorkflowStep.Argument, WorkflowStepArgument."Approver Type"::Approver,
+ WorkflowStepArgument."Approver Limit Type"::"Specific Approver", '', ApproverID);
+ end;
+
+ procedure SetWorkflowGroupApprover(WorkflowCode: Code[20]; GroupCode: Code[20])
+ var
+ WorkflowStep: Record "Workflow Step";
+ WorkflowStepArgument: Record "Workflow Step Argument";
+ begin
+ FindWorkflowStepForCreateApprovalRequests(WorkflowStep, WorkflowCode);
+ UpdateWorkflowStepArgumentApproverLimitType(
+ WorkflowStep.Argument, WorkflowStepArgument."Approver Type"::"Workflow User Group",
+ WorkflowStepArgument."Approver Limit Type"::"Approver Chain", GroupCode, '');
+ end;
+
+ procedure SetWorkflowChainApprover(WorkflowCode: Code[20])
+ var
+ WorkflowStep: Record "Workflow Step";
+ WorkflowStepArgument: Record "Workflow Step Argument";
+ begin
+ FindWorkflowStepForCreateApprovalRequests(WorkflowStep, WorkflowCode);
+ UpdateWorkflowStepArgumentApproverLimitType(
+ WorkflowStep.Argument, WorkflowStepArgument."Approver Type"::Approver,
+ WorkflowStepArgument."Approver Limit Type"::"Approver Chain", '', '');
+ end;
+
+ procedure InsertTableRelation(TableId: Integer; FieldId: Integer; RelatedTableId: Integer; RelatedFieldId: Integer)
+ var
+ WorkflowTableRelation: Record "Workflow - Table Relation";
+ begin
+ WorkflowTableRelation.Init();
+ WorkflowTableRelation."Table ID" := TableId;
+ WorkflowTableRelation."Field ID" := FieldId;
+ WorkflowTableRelation."Related Table ID" := RelatedTableId;
+ WorkflowTableRelation."Related Field ID" := RelatedFieldId;
+ WorkflowTableRelation.Insert();
+ end;
+
+ procedure InsertEventArgument(WorkflowStepID: Integer; EventConditions: Text)
+ var
+ WorkflowStep: Record "Workflow Step";
+ WorkflowStepArgument: Record "Workflow Step Argument";
+ begin
+ if EventConditions = '' then
+ Error(InvalidEventCondErr);
+
+ WorkflowStepArgument.Type := WorkflowStepArgument.Type::"Event";
+ WorkflowStepArgument.Insert(true);
+ WorkflowStepArgument.SetEventFilters(EventConditions);
+
+ WorkflowStep.SetRange(ID, WorkflowStepID);
+ WorkflowStep.FindFirst();
+ WorkflowStep.Validate(Argument, WorkflowStepArgument.ID);
+ WorkflowStep.Modify(true);
+ end;
+
+ procedure InsertNotificationArgument(WorkflowStepID: Integer; NotifUserID: Code[50]; LinkTargetPage: Integer; CustomLink: Text[250])
+ var
+ WorkflowStepArgument: Record "Workflow Step Argument";
+ begin
+ InsertStepArgument(WorkflowStepArgument, WorkflowStepID);
+
+ WorkflowStepArgument."Notification User ID" := NotifUserID;
+ WorkflowStepArgument."Link Target Page" := LinkTargetPage;
+ WorkflowStepArgument."Custom Link" := CustomLink;
+ WorkflowStepArgument.Modify(true);
+ end;
+
+ procedure InsertMessageArgument(WorkflowStepID: Integer; Msg: Text[250])
+ var
+ WorkflowStepArgument: Record "Workflow Step Argument";
+ begin
+ InsertStepArgument(WorkflowStepArgument, WorkflowStepID);
+
+ WorkflowStepArgument.Message := Msg;
+ WorkflowStepArgument.Modify(true);
+ end;
+
+ procedure InsertPmtLineCreationArgument(WorkflowStepID: Integer; GenJnlTemplateName: Code[10]; GenJnlBatchName: Code[10])
+ var
+ WorkflowStepArgument: Record "Workflow Step Argument";
+ begin
+ InsertStepArgument(WorkflowStepArgument, WorkflowStepID);
+
+ WorkflowStepArgument."General Journal Template Name" := GenJnlTemplateName;
+ WorkflowStepArgument."General Journal Batch Name" := GenJnlBatchName;
+ WorkflowStepArgument.Modify(true);
+ end;
+
+ procedure InsertApprovalArgument(WorkflowStepID: Integer; ApproverType: Enum "Workflow Approver Type"; ApproverLimitType: Enum "Workflow Approver Limit Type"; WorkflowUserGroupCode: Text[20]; InformUser: Boolean)
+ var
+ WorkflowStepArgument: Record "Workflow Step Argument";
+ begin
+ InsertStepArgument(WorkflowStepArgument, WorkflowStepID);
+
+ WorkflowStepArgument."Approver Type" := ApproverType;
+ WorkflowStepArgument."Approver Limit Type" := ApproverLimitType;
+ WorkflowStepArgument."Workflow User Group Code" := WorkflowUserGroupCode;
+ WorkflowStepArgument."Show Confirmation Message" := InformUser;
+ WorkflowStepArgument.Modify(true);
+ end;
+
+ procedure InsertRecChangeValueArgument(WorkflowStepID: Integer; TableNo: Integer; FieldNo: Integer)
+ var
+ WorkflowStepArgument: Record "Workflow Step Argument";
+ begin
+ InsertStepArgument(WorkflowStepArgument, WorkflowStepID);
+
+ WorkflowStepArgument."Table No." := TableNo;
+ WorkflowStepArgument."Field No." := FieldNo;
+ WorkflowStepArgument.Modify(true);
+ end;
+
+ local procedure InsertStepArgument(var WorkflowStepArgument: Record "Workflow Step Argument"; WorkflowStepID: Integer)
+ var
+ WorkflowStep: Record "Workflow Step";
+ begin
+ WorkflowStep.SetRange(ID, WorkflowStepID);
+ WorkflowStep.FindFirst();
+
+ if WorkflowStepArgument.Get(WorkflowStep.Argument) then
+ exit;
+
+ WorkflowStepArgument.Type := WorkflowStepArgument.Type::Response;
+ WorkflowStepArgument.Validate("Response Function Name", WorkflowStep."Function Name");
+ WorkflowStepArgument.Insert(true);
+
+ WorkflowStep.Validate(Argument, WorkflowStepArgument.ID);
+ WorkflowStep.Modify(true);
+ end;
+
+ procedure InsertEventRule(WorkflowStepId: Integer; FieldNo: Integer; Operator: Option)
+ var
+ WorkflowStep: Record "Workflow Step";
+ WorkflowRule: Record "Workflow Rule";
+ WorkflowEvent: Record "Workflow Event";
+ begin
+ WorkflowStep.SetRange(ID, WorkflowStepId);
+ WorkflowStep.FindFirst();
+
+ WorkflowRule.Init();
+ WorkflowRule."Workflow Code" := WorkflowStep."Workflow Code";
+ WorkflowRule."Workflow Step ID" := WorkflowStep.ID;
+ WorkflowRule.Operator := Operator;
+
+ if WorkflowEvent.Get(WorkflowStep."Function Name") then
+ WorkflowRule."Table ID" := WorkflowEvent."Table ID";
+ WorkflowRule."Field No." := FieldNo;
+ WorkflowRule.Insert(true);
+ end;
+
+ procedure CreateDynamicRequestPageEntity(Name: Code[20]; TableID: Integer; RelatedTableID: Integer): Code[20]
+ var
+ DynamicRequestPageEntity: Record "Dynamic Request Page Entity";
+ begin
+ DynamicRequestPageEntity.Init();
+ DynamicRequestPageEntity.Validate(Name, Name);
+ DynamicRequestPageEntity.Validate("Table ID", TableID);
+ DynamicRequestPageEntity.Validate("Related Table ID", RelatedTableID);
+ DynamicRequestPageEntity.Insert(true);
+ exit(DynamicRequestPageEntity.Name);
+ end;
+
+ procedure CreateDynamicRequestPageField(TableID: Integer; FieldID: Integer)
+ var
+ DynamicRequestPageField: Record "Dynamic Request Page Field";
+ begin
+ DynamicRequestPageField.Init();
+ DynamicRequestPageField.Validate("Table ID", TableID);
+ DynamicRequestPageField.Validate("Field ID", FieldID);
+ DynamicRequestPageField.Insert(true);
+ end;
+
+ procedure DeleteDynamicRequestPageFields(TableID: Integer)
+ var
+ DynamicRequestPageField: Record "Dynamic Request Page Field";
+ begin
+ DynamicRequestPageField.SetRange("Table ID", TableID);
+ DynamicRequestPageField.DeleteAll(true);
+ end;
+
+ procedure CopyWorkflow(var Workflow: Record Workflow; FromWorkflowCode: Code[20])
+ var
+ FromWorkflow: Record Workflow;
+ begin
+ FromWorkflow.Get(FromWorkflowCode);
+
+ CreateWorkflow(Workflow);
+
+ if Workflow.Description = '' then
+ Workflow.Description := FromWorkflow.Description;
+ Workflow.Modify();
+
+ CopyWorkflowSteps(Workflow, FromWorkflowCode);
+ end;
+
+ procedure CopyWorkflowTemplate(var Workflow: Record Workflow; FromWorkflowTemplateCode: Code[17])
+ var
+ FromWorkflow: Record Workflow;
+ WorkflowSetup: Codeunit "Workflow Setup";
+ begin
+ FromWorkflow.Get(WorkflowSetup.GetWorkflowTemplateCode(FromWorkflowTemplateCode));
+
+ CreateWorkflow(Workflow);
+
+ if Workflow.Description = '' then
+ Workflow.Description := FromWorkflow.Description;
+ Workflow.Modify();
+
+ CopyWorkflowSteps(Workflow, FromWorkflow.Code);
+ end;
+
+ local procedure CopyWorkflowSteps(Workflow: Record Workflow; FromTemplateCode: Code[20])
+ var
+ FromWorkflowStep: Record "Workflow Step";
+ FromWorkflowStepArgument: Record "Workflow Step Argument";
+ ToWorkflowStep: Record "Workflow Step";
+ begin
+ ToWorkflowStep.SetRange("Workflow Code", Workflow.Code);
+ ToWorkflowStep.DeleteAll(true);
+
+ FromWorkflowStep.SetRange("Workflow Code", FromTemplateCode);
+ if FromWorkflowStep.FindSet() then
+ repeat
+ ToWorkflowStep.Copy(FromWorkflowStep);
+
+ ToWorkflowStep."Workflow Code" := Workflow.Code;
+ if FromWorkflowStepArgument.Get(FromWorkflowStep.Argument) then
+ ToWorkflowStep.Argument := FromWorkflowStepArgument.Clone();
+ ToWorkflowStep.Insert(true);
+
+ CopyWorkflowRules(FromWorkflowStep, ToWorkflowStep);
+ until FromWorkflowStep.Next() = 0;
+ end;
+
+ local procedure CopyWorkflowRules(FromWorkflowStep: Record "Workflow Step"; ToWorkflowStep: Record "Workflow Step")
+ var
+ FromWorkflowRule: Record "Workflow Rule";
+ ToWorkflowRule: Record "Workflow Rule";
+ begin
+ FromWorkflowStep.FindWorkflowRules(FromWorkflowRule);
+ if FromWorkflowRule.FindSet() then
+ repeat
+ ToWorkflowRule.Copy(FromWorkflowRule);
+ ToWorkflowRule.ID := 0;
+ ToWorkflowRule."Workflow Code" := ToWorkflowStep."Workflow Code";
+ ToWorkflowRule."Workflow Step ID" := ToWorkflowStep.ID;
+ ToWorkflowRule.Insert(true);
+ until FromWorkflowRule.Next() = 0;
+ end;
+
+ procedure CreatePredecessor(Type: Option; FunctionName: Code[128]; PredecessorType: Option; PredecessorFunctionName: Code[128])
+ var
+ WFEventResponseCombination: Record "WF Event/Response Combination";
+ begin
+ WFEventResponseCombination.Init();
+ WFEventResponseCombination.Type := Type;
+ WFEventResponseCombination."Function Name" := FunctionName;
+ WFEventResponseCombination."Predecessor Type" := PredecessorType;
+ WFEventResponseCombination."Predecessor Function Name" := PredecessorFunctionName;
+ if WFEventResponseCombination.Insert() then;
+ end;
+
+ procedure CreateEventPredecessor(FunctionName: Code[128]; PredecessorFunctionName: Code[128])
+ var
+ WFEventResponseCombination: Record "WF Event/Response Combination";
+ begin
+ CreatePredecessor(WFEventResponseCombination.Type::"Event", FunctionName,
+ WFEventResponseCombination."Predecessor Type"::"Event", PredecessorFunctionName);
+ end;
+
+ procedure CreateResponsePredecessor(FunctionName: Code[128]; PredecessorFunctionName: Code[128])
+ var
+ WFEventResponseCombination: Record "WF Event/Response Combination";
+ begin
+ CreatePredecessor(WFEventResponseCombination.Type::Response, FunctionName,
+ WFEventResponseCombination."Predecessor Type"::"Event", PredecessorFunctionName);
+ end;
+
+ procedure CreateWorkflowCategory(): Code[20]
+ var
+ WorkflowCategory: Record "Workflow Category";
+ begin
+ WorkflowCategory.Code := LibraryUtility.GenerateRandomCode(WorkflowCategory.FieldNo(Code), DATABASE::"Workflow Category");
+ WorkflowCategory.Description :=
+ CopyStr(LibraryUtility.GenerateRandomXMLText(MaxStrLen(WorkflowCategory.Description)), 1, MaxStrLen(WorkflowCategory.Description));
+ WorkflowCategory.Insert();
+ exit(WorkflowCategory.Code);
+ end;
+
+ local procedure GenerateRandomWorkflowCode() ReturnCode: Code[20]
+ var
+ Workflow: Record Workflow;
+ begin
+ repeat
+ ReturnCode := LibraryUtility.GenerateRandomCode(Workflow.FieldNo(Code), DATABASE::Workflow);
+ until not Workflow.Get(ReturnCode);
+ end;
+}
+
diff --git a/Apps/W1/ApplicationTestLibrary/TestLibrariesSaaSInstall.Codeunit.al b/Apps/W1/ApplicationTestLibrary/TestLibrariesSaaSInstall.Codeunit.al
new file mode 100644
index 0000000000..d626a93c9f
--- /dev/null
+++ b/Apps/W1/ApplicationTestLibrary/TestLibrariesSaaSInstall.Codeunit.al
@@ -0,0 +1,37 @@
+///
+/// Handles installation verification for test libraries in SaaS environments.
+///
+codeunit 132221 "Test Libraries SaaS Install"
+{
+ Access = Internal;
+ InherentEntitlements = X;
+ InherentPermissions = X;
+ Subtype = Install;
+
+ trigger OnInstallAppPerCompany()
+ begin
+ VerifyCanRunOnCurrentEnvironment();
+ end;
+
+ local procedure VerifyCanRunOnCurrentEnvironment()
+ var
+ UnsupportedEnvironmentErr: Label 'This functionality is only available in sandbox SaaS environments.';
+ begin
+ if not IsSupportedEnvironment() then
+ Error(UnsupportedEnvironmentErr);
+ end;
+
+
+ procedure IsSupportedEnvironment(): Boolean
+ var
+ EnvironmentInformation: Codeunit "Environment Information";
+ begin
+ if not EnvironmentInformation.IsSaaS() then
+ exit(true);
+
+ if not EnvironmentInformation.IsSandbox() then
+ exit(false);
+
+ exit(true);
+ end;
+}
\ No newline at end of file
diff --git a/Apps/W1/ApplicationTestLibrary/app.json b/Apps/W1/ApplicationTestLibrary/app.json
new file mode 100644
index 0000000000..77c940f05c
--- /dev/null
+++ b/Apps/W1/ApplicationTestLibrary/app.json
@@ -0,0 +1,41 @@
+{
+ "id": "d852d5d2-a39d-4179-baeb-f99a19e32510",
+ "name": "Application Test Library",
+ "publisher": "Microsoft",
+ "version": "$(app_currentVersion)",
+ "platform": "$(app_platformVersion)",
+ "dependencies": [
+ {
+ "id": "e7320ebb-08b3-4406-b1ec-b4927d3e280b",
+ "publisher": "Microsoft",
+ "name": "Any",
+ "version": "$(app_minimumVersion)"
+ },
+ {
+ "id": "dd0be2ea-f733-4d65-bb34-a28f4624fb14",
+ "publisher": "Microsoft",
+ "name": "Library Assert",
+ "version": "$(app_minimumVersion)"
+ },
+ {
+ "id": "5095f467-0a01-4b99-99d1-9ff1237d286f",
+ "publisher": "Microsoft",
+ "name": "Library Variable Storage",
+ "version": "$(app_minimumVersion)"
+ },
+ {
+ "id": "bee8cf2f-494a-42f4-aabd-650e87934d39",
+ "name": "Business Foundation Test Libraries",
+ "publisher": "Microsoft",
+ "version": "$(app_minimumVersion)"
+ }
+ ],
+ "target": "Cloud",
+ "resourceExposurePolicy": {
+ "allowDebugging": true,
+ "allowDownloadingSource": true,
+ "includeSourceInSymbolFile": true
+ },
+ "propagateDependencies": true,
+ "application": "$(app_minimumVersion)"
+}
\ No newline at end of file