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