microsoft / ALAppExtensions

Repository for collaboration on Microsoft AL application add-on and localization extensions for Microsoft Dynamics 365 Business Central.
MIT License
770 stars 610 forks source link

[Event Request] CU 5988 Serv-Documents Mgt. - OnAfterPostDocumentLines2 #16259

Closed SevCharnay closed 2 years ago

SevCharnay commented 2 years ago

Hi, Would it be possible to get an OnBeforeGetLotNoInfo event in codeunit 5988 (Serv-Documents Mgt.), like this:

procedure PostDocumentLines(var Window: Dialog)
    var
        ServiceLineACY: Record "Service Line";
        TotalServiceLine: Record "Service Line";
        TotalServiceLineLCY: Record "Service Line";
        ServLineOld: Record "Service Line";
        TempServLine: Record "Service Line" temporary;
        TempVATAmountLine: Record "VAT Amount Line" temporary;
        TempVATAmountLineForSLE: Record "VAT Amount Line" temporary;
        TempVATAmountLineRemainder: Record "VAT Amount Line" temporary;
        InvPostingBuffer: array[2] of Record "Invoice Post. Buffer" temporary;
        DummyTrackingSpecification: Record "Tracking Specification";
        Item: Record Item;
        ServItemMgt: Codeunit ServItemManagement;
        RemQtyToBeInvoiced: Decimal;
        RemQtyToBeInvoicedBase: Decimal;
        RemQtyToBeConsumed: Decimal;
        RemQtyToBeConsumedBase: Decimal;
        LineCount: Integer;
        ApplToServEntryNo: Integer;
        WarrantyNo: Integer;
        BiggestLineNo: Integer;
        LastLineRetrieved: Boolean;
    begin
        LineCount := 0;

        // init cu for posting SLE type Usage
        ServPostingJnlsMgt.InitServiceRegister(NextServLedgerEntryNo, NextWarrantyLedgerEntryNo);
        if not ApplicationAreaMgmt.IsSalesTaxEnabled then begin
            ServLine.CalcVATAmountLines(1, ServHeader, ServLine, TempVATAmountLine, Ship);
            ServLine.CalcVATAmountLines(2, ServHeader, ServLine, TempVATAmountLineForSLE, Ship);
        end;

        ServLine.Reset();
        SortLines(ServLine);
        ServLedgEntryNo := FindFirstServLedgEntry(ServLine);
        if ServLine.Find('-') then
            repeat
                ServPostingJnlsMgt.SetItemJnlRollRndg(false);
                if ServLine.Type = ServLine.Type::Item then
                    DummyTrackingSpecification.CheckItemTrackingQuantity(
                      DATABASE::"Service Line", ServLine."Document Type".AsInteger(), ServLine."Document No.", ServLine."Line No.",
                      ServLine."Qty. to Ship (Base)", ServLine."Qty. to Invoice (Base)", Ship, Invoice);
                LineCount += 1;
                Window.Update(2, LineCount);

                with ServLine do begin
                    OnPostDocumentLinesOnBeforeCheckServLine(ServHeader, ServLine, Ship, Invoice);

                    if Ship and ("Qty. to Ship" <> 0) or Invoice and ("Qty. to Invoice" <> 0) then
                        ServOrderMgt.CheckServItemRepairStatus(ServHeader, ServItemLine, ServLine);

                    ServLineOld := ServLine;
                    if "Spare Part Action" in
                       ["Spare Part Action"::"Component Replaced",
                        "Spare Part Action"::Permanent,
                        "Spare Part Action"::"Temporary"]
                    then begin
                        "Spare Part Action" := "Spare Part Action"::"Component Installed";
                        Modify
                    end;

                    // post Service Ledger Entry of type Usage, on shipment
                    if (Ship and ("Document Type" = "Document Type"::Order) or
                        ("Document Type" = "Document Type"::Invoice)) and
                       ("Qty. to Ship" <> 0) and not ServAmountsMgt.RoundingLineInserted
                    then begin
                        TempServLine := ServLine;
                        ServPostingJnlsMgt.CalcSLEDivideAmount("Qty. to Ship", ServHeader, TempServLine, TempVATAmountLineForSLE);

                        ApplToServEntryNo :=
                          ServPostingJnlsMgt.InsertServLedgerEntry(NextServLedgerEntryNo,
                            ServHeader, TempServLine, ServItemLine, "Qty. to Ship", ServHeader."Shipping No.");

                        if "Appl.-to Service Entry" = 0 then
                            "Appl.-to Service Entry" := ApplToServEntryNo;
                    end;

                    if (Type = Type::Item) and ("No." <> '') then begin
                        GetServLineItem(ServLine, Item);
                        if (Item."Costing Method" = Item."Costing Method"::Standard) and not IsShipment then
                            GetUnitCost;
                    end;

                    if CheckCloseCondition(
                         Quantity, "Qty. to Invoice", "Qty. to Consume", "Quantity Invoiced", "Quantity Consumed") = false
                    then
                        CloseCondition := false;

                    if Quantity = 0 then
                        TestField("Line Amount", 0)
                    else begin
                        TestBinCode;
                        TestField("No.");
                        TestField(Type);
                        if not ApplicationAreaMgmt.IsSalesTaxEnabled then begin
                            TestField("Gen. Bus. Posting Group");
                            TestField("Gen. Prod. Posting Group");
                        end;
                        ServAmountsMgt.DivideAmount(1, "Qty. to Invoice", ServHeader, ServLine,
                          TempVATAmountLine, TempVATAmountLineRemainder);
                    end;

                    OnPostDocumentLinesOnBeforeRoundAmount(ServLine);

                    ServAmountsMgt.RoundAmount("Qty. to Invoice", ServHeader, ServLine,
                      TempServiceLine, TotalServiceLine, TotalServiceLineLCY, ServiceLineACY);

                    if "Document Type" <> "Document Type"::"Credit Memo" then begin
                        ServAmountsMgt.ReverseAmount(ServLine);
                        ServAmountsMgt.ReverseAmount(ServiceLineACY);
                    end;

                    // post Service Ledger Entry of type Sale, on invoice
                    if "Document Type" = "Document Type"::"Credit Memo" then begin
                        CheckIfServDuplicateLine(ServLine);
                        ServPostingJnlsMgt.CreateCreditEntry(NextServLedgerEntryNo,
                          ServHeader, ServLine, GenJnlLineDocNo);
                    end else
                        if (Invoice or ("Document Type" = "Document Type"::Invoice)) and
                           ("Qty. to Invoice" <> 0) and not ServAmountsMgt.RoundingLineInserted
                        then begin
                            CheckIfServDuplicateLine(ServLine);
                            ServPostingJnlsMgt.InsertServLedgerEntrySale(NextServLedgerEntryNo,
                              ServHeader, ServLine, ServItemLine, "Qty. to Invoice", "Qty. to Invoice", GenJnlLineDocNo, "Line No.");
                        end;

                    if Consume and ("Document Type" = "Document Type"::Order) and
                       ("Qty. to Consume" <> 0)
                    then
                        ServPostingJnlsMgt.InsertServLedgerEntrySale(NextServLedgerEntryNo,
                          ServHeader, ServLine, ServItemLine, "Qty. to Consume", 0, ServHeader."Shipping No.", "Line No.");

                    RemQtyToBeInvoiced := "Qty. to Invoice";
                    RemQtyToBeConsumed := "Qty. to Consume";
                    RemQtyToBeInvoicedBase := "Qty. to Invoice (Base)";
                    RemQtyToBeConsumedBase := "Qty. to Consume (Base)";

                    if Invoice then
                        if "Qty. to Invoice" = 0 then
                            TrackingSpecificationExists := false
                        else
                            TrackingSpecificationExists :=
                              ServITRMgt.RetrieveInvoiceSpecification(ServLine, TempInvoicingSpecification, false);

                    if Consume then
                        if "Qty. to Consume" = 0 then
                            TrackingSpecificationExists := false
                        else
                            TrackingSpecificationExists :=
                              ServITRMgt.RetrieveInvoiceSpecification(ServLine, TempInvoicingSpecification, true);

                    // update previously shipped lines with invoicing information.
                    if "Document Type" = "Document Type"::"Credit Memo" then
                        UpdateRcptLinesOnInv
                    else // Order or Invoice
                        UpdateShptLinesOnInv(ServLine,
                          RemQtyToBeInvoiced, RemQtyToBeInvoicedBase,
                          RemQtyToBeConsumed, RemQtyToBeConsumedBase);

                    if TrackingSpecificationExists then
                        ServITRMgt.SaveInvoiceSpecification(TempInvoicingSpecification, TempTrackingSpecification);

                    // post service line via journals
                    case Type of
                        Type::Item:
                            PostServiceItemLine(
                              ServHeader, ServLine, RemQtyToBeInvoicedBase, RemQtyToBeInvoiced, RemQtyToBeConsumedBase, RemQtyToBeConsumed,
                              WarrantyNo);
                        Type::Resource:
                            PostServiceResourceLine(ServLine, WarrantyNo);
                    end;

                    if Consume and ("Document Type" = "Document Type"::Order) then begin
                        OnPostDocumentLinesOnBeforePostRemQtyToBeConsumed(ServHeader, ServLine);
                        if ServPostingJnlsMgt.PostJobJnlLine(ServHeader, ServLine, RemQtyToBeConsumed) then
                            UpdateServiceLedgerEntry(NextServLedgerEntryNo - 1)
                        else
                            if (Type = Type::Resource) and (RemQtyToBeConsumed <> 0) then
                                ServPostingJnlsMgt.PostResJnlLineConsume(ServLine, ServShptHeader);
                    end;

                    if Ship and ("Document Type" = "Document Type"::Order) then begin
                        // component spare part action
                        ServItemMgt.AddOrReplaceSIComponent(ServLineOld, ServHeader,
                          ServHeader."Shipping No.", ServLineOld."Line No.", TempTrackingSpecification);
                        // allocations
                        ServAllocMgt.SetServLineAllocStatus(TempServiceLine);
                    end;

                    if (Type <> Type::" ") and ("Qty. to Invoice" <> 0) then
                        // Copy sales to buffer
                        ServAmountsMgt.FillInvPostingBuffer(InvPostingBuffer, ServLine, ServiceLineACY, ServHeader);

                    OnPostDocumentLinesOnAfterFillInvPostingBuffer(ServHeader, ServLine);

                    // prepare posted document lines
                    if Ship then
                        PrepareShipmentLine(TempServiceLine, WarrantyNo);
                    if Invoice then
                        if "Document Type" in ["Document Type"::Order, "Document Type"::Invoice] then
                            PrepareInvoiceLine(TempServiceLine)
                        else
                            PrepareCrMemoLine(TempServiceLine);

                    if Invoice or Consume then
                        CollectValueEntryRelation;

                    if ServAmountsMgt.RoundingLineInserted then
                        LastLineRetrieved := true
                    else begin
                        BiggestLineNo := ServAmountsMgt.MAX(ServAmountsMgt.GetLastLineNo(ServLine), "Line No.");
                        LastLineRetrieved := Next() = 0; // ServLine
                        if LastLineRetrieved and SalesSetup."Invoice Rounding" then
                            ServAmountsMgt.InvoiceRounding(ServHeader, ServLine, TotalServiceLine,
                              LastLineRetrieved, false, BiggestLineNo);
                    end;
                end; // With ServLine
            until LastLineRetrieved;

        with ServHeader do begin
            // again reverse amount
            if "Document Type" <> "Document Type"::"Credit Memo" then begin
                ServAmountsMgt.ReverseAmount(TotalServiceLine);
                ServAmountsMgt.ReverseAmount(TotalServiceLineLCY);
                TotalServiceLineLCY."Unit Cost (LCY)" := -TotalServiceLineLCY."Unit Cost (LCY)";
            end;

            ServPostingJnlsMgt.FinishServiceRegister(NextServLedgerEntryNo, NextWarrantyLedgerEntryNo);

            if Invoice or ("Document Type" = "Document Type"::Invoice) then begin
                Clear(ServDocReg);
                // fake service register entry to be used in the following PostServSalesDocument()
                if Invoice and ("Document Type" = "Document Type"::Order) and (ServLine."Contract No." <> '') then
                    ServDocReg.InsertServSalesDocument(
                      ServDocReg."Source Document Type"::Contract, ServLine."Contract No.",
                      ServDocReg."Destination Document Type"::Invoice, ServLine."Document No.");
                ServDocReg.PostServSalesDocument(
                  ServDocReg."Destination Document Type"::Invoice,
                  ServLine."Document No.", ServInvHeader."No.");
            end;
            if Invoice or ("Document Type" = "Document Type"::"Credit Memo") then begin
                Clear(ServDocReg);
                ServDocReg.PostServSalesDocument(
                  ServDocReg."Destination Document Type"::"Credit Memo",
                  ServLine."Document No.",
                  ServCrMemoHeader."No.");
            end;

            // Post sales and VAT to G/L entries from posting buffer
            if Invoice then begin
                OnPostDocumentLinesOnBeforePostInvoicePostBuffer(
                  ServHeader, InvPostingBuffer[1], TotalServiceLine, TotalServiceLineLCY);
                LineCount := 0;
                if InvPostingBuffer[1].Find('+') then
                    repeat
                        LineCount += 1;
                        Window.Update(3, LineCount);
                        ServPostingJnlsMgt.SetPostingDate("Posting Date");
                        ServPostingJnlsMgt.PostInvoicePostBufferLine(
                          InvPostingBuffer[1], GenJnlLineDocType, GenJnlLineDocNo, GenJnlLineExtDocNo);
                    until InvPostingBuffer[1].Next(-1) = 0;

                // Post customer entry
                Window.Update(4, 1);
                ServPostingJnlsMgt.SetPostingDate("Posting Date");
                ServPostingJnlsMgt.PostCustomerEntry(
                  TotalServiceLine, TotalServiceLineLCY,
                  GenJnlLineDocType, GenJnlLineDocNo, GenJnlLineExtDocNo);

                // post Balancing account
                if "Bal. Account No." <> '' then begin
                    Window.Update(5, 1);
                    ServPostingJnlsMgt.SetPostingDate("Posting Date");
                    ServPostingJnlsMgt.PostBalancingEntry(
                      TotalServiceLine, TotalServiceLineLCY,
                      GenJnlLineDocType, GenJnlLineDocNo, GenJnlLineExtDocNo);
                end;
            end; // end posting sales,receivables,balancing

            MakeInvtAdjustment;
            if Ship then begin
                "Last Shipping No." := "Shipping No.";
                "Shipping No." := '';
            end;

            if Invoice then begin
                "Last Posting No." := "Posting No.";
                "Posting No." := '';
            end;

            Modify;
        end;// with header

        OnAfterPostDocumentLines(ServHeader, ServInvHeader, ServInvLine, ServCrMemoHeader, ServCrMemoLine);
        //********START
        OnAfterPostDocumentLines2(ServHeader, GenJnlLineDocType, GenJnlLineDocNo);
        //********END
    end;
[IntegrationEvent(false, false)]
    local procedure OnAfterPostDocumentLines2(var ServHeader: Record "Service Header"; DocType: Integer; DocNo: Code[20])
    begin
    end;
JesperSchulz commented 2 years ago

Thanks for reporting this. We agree, and we’ll publish a fix asap, either in an update for the current version or in the next major release. Please do not reply to this, as we do not monitor closed issues. If you have follow-up questions or requests, please create a new issue where you reference this one.