Table 7190 Sales Shipment Buffer, source in 29

Source29

src/Layers/W1/BaseApp/Sales/History/SalesShipmentBuffer.Table.al383 lines, Copyright (c) Microsoft Corporation. MIT

// ------------------------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
// ------------------------------------------------------------------------------------------------
namespace Microsoft.Sales.History;

using Microsoft.Finance.GeneralLedger.Account;
using Microsoft.FixedAssets.FixedAsset;
using Microsoft.Foundation.UOM;
using Microsoft.Inventory.Item;
using Microsoft.Inventory.Ledger;
using Microsoft.Projects.Resources.Resource;
using Microsoft.Sales.Document;

/// <summary>
/// Provides temporary storage for sales shipment data during invoice printing and document processing.
/// </summary>
table 7190 "Sales Shipment Buffer"
{
    Caption = 'Sales Shipment Buffer';
    ReplicateData = false;
    DataClassification = CustomerContent;

    fields
    {
        /// <summary>
        /// Specifies the document number of the related shipment or receipt.
        /// </summary>
        field(1; "Document No."; Code[20])
        {
            Caption = 'Document No.';
            DataClassification = SystemMetadata;
            TableRelation = "Sales Invoice Header";
        }
        /// <summary>
        /// Specifies the line number from the source document.
        /// </summary>
        field(2; "Line No."; Integer)
        {
            Caption = 'Line No.';
            DataClassification = SystemMetadata;
        }
        /// <summary>
        /// Specifies a unique sequential entry number for the buffer record.
        /// </summary>
        field(3; "Entry No."; Integer)
        {
            Caption = 'Entry No.';
            DataClassification = SystemMetadata;
        }
        /// <summary>
        /// Specifies the type of the line such as Item, G/L Account, or Resource.
        /// </summary>
        field(5; Type; Enum "Sales Line Type")
        {
            Caption = 'Type';
            DataClassification = SystemMetadata;
        }
        /// <summary>
        /// Specifies the number of the item, G/L account, or resource on the line.
        /// </summary>
        field(6; "No."; Code[20])
        {
            Caption = 'No.';
            DataClassification = SystemMetadata;
            TableRelation = if (Type = const("G/L Account")) "G/L Account"
            else
            if (Type = const(Item)) Item
            else
            if (Type = const(Resource)) Resource
            else
            if (Type = const("Fixed Asset")) "Fixed Asset"
            else
            if (Type = const("Charge (Item)")) "Item Charge";
        }
        /// <summary>
        /// Specifies the quantity shipped or received for the line.
        /// </summary>
        field(7; Quantity; Decimal)
        {
            AutoFormatType = 0;
            Caption = 'Quantity';
            DataClassification = SystemMetadata;
        }
        /// <summary>
        /// Specifies the posting date of the shipment or receipt.
        /// </summary>
        field(8; "Posting Date"; Date)
        {
            Caption = 'Posting Date';
            DataClassification = SystemMetadata;
        }
    }

    keys
    {
        key(Key1; "Document No.", "Line No.", "Entry No.")
        {
            Clustered = true;
        }
        key(Key2; "Document No.", "Line No.", "Posting Date")
        {
        }
    }

    fieldgroups
    {
    }

    var
        UOMMgt: Codeunit "Unit of Measure Management";
        NextEntryNo: Integer;

    /// <summary>
    /// Populates the buffer with shipment information for a sales invoice line.
    /// </summary>
    /// <param name="SalesInvoiceLine">The sales invoice line to get shipment data for.</param>
    /// <param name="SalesInvoiceHeader">The sales invoice header.</param>
    procedure GetLinesForSalesInvoiceLine(var SalesInvoiceLine: Record "Sales Invoice Line"; var SalesInvoiceHeader: Record "Sales Invoice Header")
    var
        ValueEntry: Record "Value Entry";
    begin
        case SalesInvoiceLine.Type of
            SalesInvoiceLine.Type::Item:
                GenerateBufferFromValueEntry(
                  ValueEntry."Document Type"::"Sales Invoice",
                  SalesInvoiceLine."Document No.",
                  SalesInvoiceLine."Line No.",
                  SalesInvoiceLine.Type,
                  SalesInvoiceLine."No.",
                  SalesInvoiceHeader."Posting Date",
                  SalesInvoiceLine."Quantity (Base)",
                  SalesInvoiceLine."Qty. per Unit of Measure");
            SalesInvoiceLine.Type::"G/L Account", SalesInvoiceLine.Type::Resource,
          SalesInvoiceLine.Type::"Charge (Item)", SalesInvoiceLine.Type::"Fixed Asset":
                GenerateBufferFromShipment(SalesInvoiceLine, SalesInvoiceHeader);
        end;
    end;

    /// <summary>
    /// Populates the buffer with shipment information for a sales credit memo line.
    /// </summary>
    /// <param name="SalesCrMemoLine">The sales credit memo line to get shipment data for.</param>
    /// <param name="SalesCrMemoHeader">The sales credit memo header.</param>
    procedure GetLinesForSalesCreditMemoLine(SalesCrMemoLine: Record "Sales Cr.Memo Line"; SalesCrMemoHeader: Record "Sales Cr.Memo Header")
    var
        ValueEntry: Record "Value Entry";
    begin
        case SalesCrMemoLine.Type of
            SalesCrMemoLine.Type::Item:
                GenerateBufferFromValueEntry(
                  ValueEntry."Document Type"::"Sales Credit Memo",
                  SalesCrMemoLine."Document No.",
                  SalesCrMemoLine."Line No.",
                  SalesCrMemoLine.Type,
                  SalesCrMemoLine."No.",
                  SalesCrMemoHeader."Posting Date",
                  -SalesCrMemoLine."Quantity (Base)",
                  SalesCrMemoLine."Qty. per Unit of Measure");
            SalesCrMemoLine.Type::"G/L Account", SalesCrMemoLine.Type::Resource,
            SalesCrMemoLine.Type::"Charge (Item)", SalesCrMemoLine.Type::"Fixed Asset":
                GenerateBufferFromReceipt(SalesCrMemoLine, SalesCrMemoHeader);
        end;
    end;

    local procedure GenerateBufferFromValueEntry(ValueEntryDocType: Enum "Item Ledger Document Type"; DocNo: Code[20]; DocLineNo: Integer; LineType: Enum "Sales Line Type"; ItemNo: Code[20]; PostingDate: Date; QtyBase: Decimal; QtyPerUOM: Decimal)
    var
        ValueEntry: Record "Value Entry";
        ItemLedgerEntry: Record "Item Ledger Entry";
        TotalQuantity: Decimal;
        Quantity: Decimal;
    begin
        TotalQuantity := QtyBase;
        ValueEntry.SetRange("Document Type", ValueEntryDocType);
        ValueEntry.SetRange("Document No.", DocNo);
        ValueEntry.SetRange("Document Line No.", DocLineNo);
        ValueEntry.SetRange("Posting Date", PostingDate);
        ValueEntry.SetRange("Item Charge No.", '');
        ValueEntry.SetRange("Item No.", ItemNo);
        if ValueEntry.Find('-') then
            repeat
                if ItemLedgerEntry.Get(ValueEntry."Item Ledger Entry No.") then begin
                    if QtyPerUOM <> 0 then
                        Quantity := Round(ValueEntry."Invoiced Quantity" / QtyPerUOM, UOMMgt.QtyRndPrecision())
                    else
                        Quantity := ValueEntry."Invoiced Quantity";
                    AddBufferEntry(
                      Abs(Quantity),
                      ItemLedgerEntry."Posting Date",
                      ItemLedgerEntry."Document No.",
                      DocLineNo, LineType, ItemNo);
                    TotalQuantity := TotalQuantity + ValueEntry."Invoiced Quantity";
                end;
            until (ValueEntry.Next() = 0) or (TotalQuantity = 0);
    end;

    local procedure GenerateBufferFromShipment(SalesInvoiceLine2: Record "Sales Invoice Line"; SalesInvoiceHeader2: Record "Sales Invoice Header")
    var
        SalesInvoiceHeader: Record "Sales Invoice Header";
        SalesInvoiceLine: Record "Sales Invoice Line";
        SalesShipmentHeader: Record "Sales Shipment Header";
        SalesShipmentLine: Record "Sales Shipment Line";
        TotalQuantity: Decimal;
        Quantity: Decimal;
    begin
        if SalesInvoiceHeader2."Order No." = '' then
            exit;

        TotalQuantity := 0;
        SalesInvoiceHeader.SetCurrentKey("Order No.");
        SalesInvoiceHeader.SetFilter("No.", '..%1', SalesInvoiceHeader2."No.");
        SalesInvoiceHeader.SetRange("Order No.", SalesInvoiceHeader2."Order No.");
        if SalesInvoiceHeader.FindSet() then
            repeat
                SalesInvoiceLine.SetRange("Document No.", SalesInvoiceHeader."No.");
                SalesInvoiceLine.SetRange("Line No.", SalesInvoiceLine2."Line No.");
                SalesInvoiceLine.SetRange(Type, SalesInvoiceLine2.Type);
                SalesInvoiceLine.SetRange("No.", SalesInvoiceLine2."No.");
                SalesInvoiceLine.SetRange("Unit of Measure Code", SalesInvoiceLine2."Unit of Measure Code");
                if not SalesInvoiceLine.IsEmpty() then begin
                    SalesInvoiceLine.CalcSums(Quantity);
                    TotalQuantity += SalesInvoiceLine.Quantity;
                end;
            until SalesInvoiceHeader.Next() = 0;

        SalesShipmentLine.SetCurrentKey("Order No.", "Order Line No.", "Posting Date");
        SalesShipmentLine.SetRange("Order No.", SalesInvoiceHeader2."Order No.");
        SalesShipmentLine.SetRange("Order Line No.", SalesInvoiceLine2."Line No.");
        SalesShipmentLine.SetRange("Line No.", SalesInvoiceLine2."Line No.");
        SalesShipmentLine.SetRange(Type, SalesInvoiceLine2.Type);
        SalesShipmentLine.SetRange("No.", SalesInvoiceLine2."No.");
        SalesShipmentLine.SetRange("Unit of Measure Code", SalesInvoiceLine2."Unit of Measure Code");
        SalesShipmentLine.SetFilter(Quantity, '<>%1', 0);
        if SalesShipmentLine.FindSet() then
            repeat
                if SalesInvoiceHeader2."Get Shipment Used" then
                    CorrectShipment(SalesShipmentLine);
                if Abs(SalesShipmentLine.Quantity) <= Abs(TotalQuantity - SalesInvoiceLine2.Quantity) then
                    TotalQuantity := TotalQuantity - SalesShipmentLine.Quantity
                else begin
                    if Abs(SalesShipmentLine.Quantity) > Abs(TotalQuantity) then
                        SalesShipmentLine.Quantity := TotalQuantity;
                    Quantity :=
                      SalesShipmentLine.Quantity - (TotalQuantity - SalesInvoiceLine2.Quantity);

                    TotalQuantity := TotalQuantity - SalesShipmentLine.Quantity;
                    SalesInvoiceLine.Quantity := SalesInvoiceLine.Quantity - Quantity;

                    if SalesShipmentHeader.Get(SalesShipmentLine."Document No.") then
                        AddBufferEntry(
                          Quantity,
                          SalesShipmentHeader."Posting Date",
                          SalesShipmentHeader."No.",
                          SalesInvoiceLine2."Line No.",
                          SalesInvoiceLine2.Type,
                          SalesInvoiceLine2."No.");
                end;
            until (SalesShipmentLine.Next() = 0) or (TotalQuantity = 0);
    end;

    local procedure GenerateBufferFromReceipt(SalesCrMemoLine: Record "Sales Cr.Memo Line"; SalesCrMemoHeader: Record "Sales Cr.Memo Header")
    var
        SalesCrMemoHeader2: Record "Sales Cr.Memo Header";
        SalesCrMemoLine2: Record "Sales Cr.Memo Line";
        ReturnReceiptHeader: Record "Return Receipt Header";
        ReturnReceiptLine: Record "Return Receipt Line";
        TotalQuantity: Decimal;
        Quantity: Decimal;
    begin
        if SalesCrMemoHeader."Return Order No." = '' then
            exit;

        TotalQuantity := 0;
        SalesCrMemoHeader2.SetCurrentKey("Return Order No.");
        SalesCrMemoHeader2.SetFilter("No.", '..%1', SalesCrMemoHeader."No.");
        SalesCrMemoHeader2.SetRange("Return Order No.", SalesCrMemoHeader."Return Order No.");
        if SalesCrMemoHeader2.Find('-') then
            repeat
                SalesCrMemoLine2.SetRange("Document No.", SalesCrMemoHeader2."No.");
                SalesCrMemoLine2.SetRange("Line No.", SalesCrMemoLine."Line No.");
                SalesCrMemoLine2.SetRange(Type, SalesCrMemoLine.Type);
                SalesCrMemoLine2.SetRange("No.", SalesCrMemoLine."No.");
                SalesCrMemoLine2.SetRange("Unit of Measure Code", SalesCrMemoLine."Unit of Measure Code");
                SalesCrMemoLine2.CalcSums(Quantity);
                TotalQuantity := TotalQuantity + SalesCrMemoLine2.Quantity;
            until SalesCrMemoHeader2.Next() = 0;

        ReturnReceiptLine.SetCurrentKey("Return Order No.", "Return Order Line No.");
        ReturnReceiptLine.SetRange("Return Order No.", SalesCrMemoHeader."Return Order No.");
        ReturnReceiptLine.SetRange("Return Order Line No.", SalesCrMemoLine."Line No.");
        ReturnReceiptLine.SetRange("Line No.", SalesCrMemoLine."Line No.");
        ReturnReceiptLine.SetRange(Type, SalesCrMemoLine.Type);
        ReturnReceiptLine.SetRange("No.", SalesCrMemoLine."No.");
        ReturnReceiptLine.SetRange("Unit of Measure Code", SalesCrMemoLine."Unit of Measure Code");
        ReturnReceiptLine.SetFilter(Quantity, '<>%1', 0);

        if ReturnReceiptLine.Find('-') then
            repeat
                if SalesCrMemoHeader."Get Return Receipt Used" then
                    CorrectReceipt(ReturnReceiptLine);
                if Abs(ReturnReceiptLine.Quantity) <= Abs(TotalQuantity - SalesCrMemoLine.Quantity) then
                    TotalQuantity := TotalQuantity - ReturnReceiptLine.Quantity
                else begin
                    if Abs(ReturnReceiptLine.Quantity) > Abs(TotalQuantity) then
                        ReturnReceiptLine.Quantity := TotalQuantity;
                    Quantity :=
                      ReturnReceiptLine.Quantity - (TotalQuantity - SalesCrMemoLine.Quantity);

                    SalesCrMemoLine.Quantity := SalesCrMemoLine.Quantity - Quantity;
                    TotalQuantity := TotalQuantity - ReturnReceiptLine.Quantity;

                    if ReturnReceiptHeader.Get(ReturnReceiptLine."Document No.") then
                        AddBufferEntry(
                          Quantity,
                          ReturnReceiptHeader."Posting Date",
                          ReturnReceiptHeader."No.",
                          SalesCrMemoLine."Line No.",
                          SalesCrMemoLine.Type,
                          SalesCrMemoLine."No.");
                end;
            until (ReturnReceiptLine.Next() = 0) or (TotalQuantity = 0);
    end;

    local procedure AddBufferEntry(QtyOnShipment: Decimal; PostingDate: Date; ShipmentNo: Code[20]; DocLineNo: Integer; LineType: Enum "Sales Line Type"; ItemNo: Code[20])
    begin
        SetRange("Document No.", ShipmentNo);
        SetRange("Line No.", DocLineNo);
        SetRange("Posting Date", PostingDate);
        if FindFirst() then begin
            Quantity += QtyOnShipment;
            Modify();
            exit;
        end;

        NextEntryNo := NextEntryNo + 1;
        "Document No." := ShipmentNo;
        "Line No." := DocLineNo;
        "Entry No." := NextEntryNo;
        Type := LineType;
        "No." := ItemNo;
        Quantity := QtyOnShipment;
        "Posting Date" := PostingDate;
        Insert();
    end;

    local procedure CorrectShipment(var SalesShipmentLine: Record "Sales Shipment Line")
    var
        SalesInvoiceLine: Record "Sales Invoice Line";
    begin
        SalesInvoiceLine.SetCurrentKey("Shipment No.", "Shipment Line No.");
        SalesInvoiceLine.SetRange("Shipment No.", SalesShipmentLine."Document No.");
        SalesInvoiceLine.SetRange("Shipment Line No.", SalesShipmentLine."Line No.");
        SalesInvoiceLine.CalcSums(Quantity);
        SalesShipmentLine.Quantity := SalesShipmentLine.Quantity - SalesInvoiceLine.Quantity;

        OnAfterCorrectShipment(SalesInvoiceLine, SalesShipmentLine);
    end;

    local procedure CorrectReceipt(var ReturnReceiptLine: Record "Return Receipt Line")
    var
        SalesCrMemoLine: Record "Sales Cr.Memo Line";
    begin
        SalesCrMemoLine.SetCurrentKey("Return Receipt No.", "Return Receipt Line No.");
        SalesCrMemoLine.SetRange("Return Receipt No.", ReturnReceiptLine."Document No.");
        SalesCrMemoLine.SetRange("Return Receipt Line No.", ReturnReceiptLine."Line No.");
        SalesCrMemoLine.CalcSums(Quantity);
        ReturnReceiptLine.Quantity := ReturnReceiptLine.Quantity - SalesCrMemoLine.Quantity;

        OnAfterCorrectReceipt(SalesCrMemoLine, ReturnReceiptLine);
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterCorrectShipment(var SalesInvoiceLine: Record "Sales Invoice Line"; var SalesShipmentLine: Record "Sales Shipment Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterCorrectReceipt(var SalesCrMemoLine: Record "Sales Cr.Memo Line"; var ReturnReceiptLine: Record "Return Receipt Line")
    begin
    end;
}