Codeunit 205 Alt. Cust. VAT Reg. Doc. Impl., source in 29

Source29

src/Layers/W1/BaseApp/Finance/VAT/Registration/AltCustVATRegDocImpl.Codeunit.al347 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.Finance.VAT.Registration;

using Microsoft.Finance.GeneralLedger.Setup;
using Microsoft.Sales.Customer;
using Microsoft.Sales.Document;
using System.Diagnostics;
using System.Environment.Configuration;
using System.Telemetry;

codeunit 205 "Alt. Cust. VAT Reg. Doc. Impl." implements "Alt. Cust. VAT Reg. Doc."
{
    Access = Internal;
    InherentEntitlements = X;
    InherentPermissions = X;
    EventSubscriberInstance = Manual;

    var
        AltCustVATRegFacade: Codeunit "Alt. Cust. VAT. Reg. Facade";
        FeatureTelemetry: Codeunit "Feature Telemetry";
        SalesLinesRecreated: Boolean;
        InstructionTxt: Label 'The following data is taken from the Alternative VAT Registration setup. It will override values in the document and affect the posting. Do you want to continue?';
        DocumentValueTxt: Label 'Document value';
        AlternativeValueTxt: Label 'Alternative value';
        CannotChangeVATDataWhenPrepmtErr: Label 'You cannot make this change because it leads to a different VAT Registration No., Gen. Bus. Posting Group or VAT Bus. Posting Group than in the sales document. Since you have posted a prepayment invoice, such a change will cause an inconsistency in the ledger entries.';
        CannotChangeVATDataWhenPartiallyPostedErr: Label 'You cannot make this change because it leads to a different VAT Registration No., Gen. Bus. Posting Group or VAT Bus. Posting Group than in the sales document. Since you have posted a partial shipment, such a change will cause an inconsistency in the ledger entries.';
        VATDataTakenFromCustomerMsg: Label 'The VAT Country/Region code has been changed to the value that does not have an alternative VAT registration.\\The following fields have been updated from the customer card: %1', Comment = '%1 = list of the fields';
        FeatureNameTxt: Label 'Alternative Customer VAT Registration', Locked = true;
        ConfirmAltCustVATRegNotificationNameTok: Label 'Confirm an alternative customer VAT registration.';
        ConfirmAltCustVATRegNotificationDescTok: Label 'Show the user the page to confirm an alternative customer VAT registration when choosing either ship-to address or the VAT country different from the customer''s';
        AddAlternativeCustVATRegQst: Label 'The VAT country is different than the customer''s. Do you want to add an alternative VAT registration for this VAT country?';
        AddAlternativeCustVATRegMsg: Label 'Add';
        DontShowMsg: Label 'Don''t show';
        AddAltCustVATRegNotificationNameTok: Label 'Suggest an alternative customer VAT registration from sales document';
        AddAltCustVATRegNotificationDescTok: Label 'Suggest the user to add an alternative customer VAT registration when choosing a VAT country different from the customer''s';

    procedure Init(var SalesHeader: Record "Sales Header"; xSalesHeader: Record "Sales Header")
    begin
        if xSalesHeader."Bill-to Customer No." = '' then
            exit;
        SalesHeader.Validate("Alt. VAT Registration No.", false);
        SalesHeader.Validate("Alt. Gen. Bus Posting Group", false);
        SalesHeader.Validate("Alt. VAT Bus Posting Group", false);
    end;

    procedure CopyFromCustomer(var SalesHeader: Record "Sales Header"; xSalesHeader: Record "Sales Header")
    var
        Customer: Record Customer;
    begin
        if not IsAltVATRegUsed(SalesHeader) then
            exit;
        RunChecks(SalesHeader);
        Customer.SetLoadFields("Country/Region Code", "VAT Registration No.", "Gen. Bus. Posting Group", "VAT Bus. Posting Group");
        if not GetCustVATCalc(Customer, SalesHeader) then
            exit;
        CopyFromCustomer(SalesHeader, xSalesHeader, Customer);
    end;

    local procedure CopyFromCustomer(var SalesHeader: Record "Sales Header"; xSalesHeader: Record "Sales Header"; Customer: Record Customer)
    var
        ChangedFieldsList: Text;
    begin
        if (SalesHeader."Alt. VAT Registration No." or SalesHeader."Alt. VAT Bus Posting Group") and
           (SalesHeader."VAT Country/Region Code" <> Customer."Country/Region Code") and
           (xSalesHeader."VAT Country/Region Code" = SalesHeader."VAT Country/Region Code")
        then begin
            SalesHeader."VAT Country/Region Code" := Customer."Country/Region Code";
            AddStringToCommaSeparatedList(ChangedFieldsList, SalesHeader.FieldCaption("VAT Country/Region Code"));
        end;
        if SalesHeader."Alt. VAT Registration No." then begin
            SalesHeader.Validate("Alt. VAT Registration No.", false);
            SalesHeader.Validate("VAT Registration No.", Customer."VAT Registration No.");
            AddStringToCommaSeparatedList(ChangedFieldsList, SalesHeader.FieldCaption("VAT Registration No."));
        end;
        if SalesHeader."Alt. Gen. Bus Posting Group" then begin
            SalesHeader.Validate("Alt. Gen. Bus Posting Group", false);
            SalesHeader.Validate("Gen. Bus. Posting Group", Customer."Gen. Bus. Posting Group");
            AddStringToCommaSeparatedList(ChangedFieldsList, SalesHeader.FieldCaption("Gen. Bus. Posting Group"));
        end;
        if SalesHeader."Alt. VAT Bus Posting Group" then begin
            SalesHeader.Validate("Alt. VAT Bus Posting Group", false);
            SalesHeader.Validate("VAT Bus. Posting Group", Customer."VAT Bus. Posting Group");
            AddStringToCommaSeparatedList(ChangedFieldsList, SalesHeader.FieldCaption("VAT Bus. Posting Group"));
        end;
        if GuiAllowed() then
            Message(VATDataTakenFromCustomerMsg, ChangedFieldsList);
    end;

    procedure UpdateSetupOnShipToCountryChangeInSalesHeader(var SalesHeader: Record "Sales Header"; xSalesHeader: Record "Sales Header")
    var
        AltCustVATReg: Record "Alt. Cust. VAT Reg.";
        VATCustomer: Record Customer;
    begin
        GetCustVATCalc(VATCustomer, SalesHeader);
        if AltCustVATRegFacade.GetAlternativeCustVATReg(AltCustVATReg, VATCustomer."No.", SalesHeader."Ship-to Country/Region Code") then
            SalesHeader.Validate("VAT Country/Region Code", AltCustVATReg."VAT Country/Region Code")
        else
            CopyFromCustomer(SalesHeader, xSalesHeader);
    end;

    procedure UpdateSetupOnVATCountryChangeInSalesHeader(var SalesHeader: Record "Sales Header"; xSalesHeader: Record "Sales Header")
    var
        Customer: Record Customer;
    begin
        if AlternativeCustVATRegIsBlank(SalesHeader) then begin
            CopyFromCustomer(SalesHeader, xSalesHeader);
            if not GetCustVATCalc(Customer, SalesHeader) then
                exit;
            if Customer."Country/Region Code" = SalesHeader."VAT Country/Region Code" then
                exit;
            ThrowAddAltCustVATRegNotification(Customer."No.", SalesHeader."VAT Country/Region Code");
            exit;
        end;
        RunChecks(SalesHeader);
        if SalesHeader.SystemCreatedAt <> 0DT then
            if not ConfirmChanges(SalesHeader) then
                error('');
        UpdateAltCustVATRegInSalesHeader(SalesHeader);
    end;

    procedure UpdateSetupOnBillToCustomerChangeInSalesHeader(var SalesHeader: Record "Sales Header"; xSalesHeader: Record "Sales Header"; BillToCustomer: Record Customer)
    var
        GLSetup: Record "General Ledger Setup";
        AltCustVATReg: Record "Alt. Cust. VAT Reg.";
    begin
        GLSetup.Get();
        if GLSetup."Bill-to/Sell-to VAT Calc." <> GLSetup."Bill-to/Sell-to VAT Calc."::"Bill-to/Pay-to No." then
            exit;

        if IsAltVATRegUsed(SalesHeader) then begin
            if SalesHeader."Bill-to Customer No." = SalesHeader."Sell-to Customer No." then
                exit;
            CopyFromCustomer(SalesHeader, xSalesHeader, BillToCustomer);
            exit;
        end;
        if AltCustVATRegFacade.GetAlternativeCustVATReg(AltCustVATReg, BillToCustomer."No.", SalesHeader."Ship-to Country/Region Code") then begin
            SalesHeader.Validate("VAT Country/Region Code", AltCustVATReg."VAT Country/Region Code");
            exit;
        end;
        AltCustVATRegFacade.CopyBillToCustomerToSalesHeader(SalesHeader, BillToCustomer);
    end;

    local procedure IsAltVATRegUsed(SalesHeader: Record "Sales Header"): Boolean
    begin
        exit(SalesHeader."Alt. VAT Registration No." or SalesHeader."Alt. Gen. Bus Posting Group" or SalesHeader."Alt. VAT Bus Posting Group");
    end;

    local procedure AlternativeCustVATRegIsBlank(SalesHeader: Record "Sales Header"): Boolean
    var
        AltCustVATReg: Record "Alt. Cust. VAT Reg.";
    begin
        exit(not GetAlternativeCustVATReg(AltCustVATReg, SalesHeader));
    end;

    local procedure GetAlternativeCustVATReg(var AltCustVATReg: Record "Alt. Cust. VAT Reg."; SalesHeader: Record "Sales Header"): Boolean
    var
        Customer: Record Customer;
    begin
        Customer.SetLoadFields("No.");
        GetCustVATCalc(Customer, SalesHeader);
        exit(AltCustVATRegFacade.GetAlternativeCustVATReg(AltCustVATReg, Customer."No.", SalesHeader."VAT Country/Region Code"));
    end;

    local procedure ConfirmChanges(var SalesHeader: Record "Sales Header") Confirmed: Boolean
    var
        TempChangeLogEntry: Record "Change Log Entry" temporary;
        ConfirmAltCustVATRegPage: Page "Confirm Alt. Cust. VAT Reg.";
    begin
        FeatureTelemetry.LogUsage('0000NHM', FeatureNameTxt, 'Confirm changes');
        if not BuildFieldChangeBuffer(TempChangeLogEntry, SalesHeader) then
            exit(true);
        if not GuiAllowed() then
            exit(true);
        if SalesHeader.GetHideValidationDialog() then
            exit(true);
        if not ShowConfirmation() then
            exit(true);
        ConfirmAltCustVATRegPage.SetUIControls(InstructionTxt, DocumentValueTxt, AlternativeValueTxt);
        ConfirmAltCustVATRegPage.SetSource(TempChangeLogEntry);
        Confirmed := ConfirmAltCustVATRegPage.RunModal() = Action::Ok;
        if ConfirmAltCustVATRegPage.DontShowAgainOptionSelected() then
            DisableConfirmation();
        exit(Confirmed);
    end;

    local procedure ShowConfirmation(): Boolean
    var
        MyNotifications: Record "My Notifications";
    begin
        if Database.IsInWriteTransaction() then
            exit(false);
        exit(MyNotifications.IsEnabled(GetConfirmChangesNotificationId()));
    end;

    local procedure DisableConfirmation()
    var
        MyNotifications: Record "My Notifications";
    begin
        if not MyNotifications.Disable(GetConfirmChangesNotificationId()) then
            MyNotifications.InsertDefault(GetConfirmChangesNotificationId(), ConfirmAltCustVATRegNotificationNameTok, ConfirmAltCustVATRegNotificationDescTok, false);
    end;

    local procedure UpdateAltCustVATRegInSalesHeader(var SalesHeader: Record "Sales Header")
    var
        AltCustVATReg: Record "Alt. Cust. VAT Reg.";
    begin
        GetAlternativeCustVATReg(AltCustVATReg, SalesHeader);
        BindSubscription(this);
        AltCustVATRegFacade.CopyAltCustVATRegToSalesHeader(SalesHeader, AltCustVATReg);
        UnbindSubscription(this);
        FeatureTelemetry.LogUptake('0000NHG', FeatureNameTxt, Enum::"Feature Uptake Status"::Used);
    end;

    local procedure BuildFieldChangeBuffer(var TempChangeLogEntry: Record "Change Log Entry" temporary; SalesHeader: Record "Sales Header"): Boolean
    var
        AltCustVATReg: Record "Alt. Cust. VAT Reg.";
    begin
        GetAlternativeCustVATReg(AltCustVATReg, SalesHeader);
        AltCustVATRegFacade.AddTempChangeLogEntryForAltCustVATRegChanges(TempChangeLogEntry, SalesHeader, AltCustVATReg);
        exit(not TempChangeLogEntry.IsEmpty());
    end;

    local procedure RunChecks(SalesHeader: Record "Sales Header")
    begin
        CheckPrepayment(SalesHeader);
        CheckPartialPosting(SalesHeader);
    end;

    local procedure CheckPrepayment(SalesHeader: Record "Sales Header")
    var
        SalesLine: Record "Sales Line";
    begin
        SalesLine.SetRange("Document Type", SalesHeader."Document Type");
        SalesLine.SetRange("Document No.", SalesHeader."No.");
        SalesLine.SetFilter("Prepmt. Amt. Inv.", '<>%1', 0);
        if not SalesLine.IsEmpty() then
            error(CannotChangeVATDataWhenPrepmtErr);
    end;

    local procedure CheckPartialPosting(SalesHeader: Record "Sales Header")
    var
        SalesLine: Record "Sales Line";
    begin
        SalesLine.SetRange("Document Type", SalesHeader."Document Type");
        SalesLine.SetRange("Document No.", SalesHeader."No.");
        SalesLine.SetFilter("Quantity Shipped", '<>%1', 0);
        if not SalesLine.IsEmpty() then
            error(CannotChangeVATDataWhenPartiallyPostedErr);
    end;

    local procedure GetCustVATCalc(var VATCustomer: Record Customer; SalesHeader: Record "Sales Header"): Boolean
    var
        GLSetup: Record "General Ledger Setup";
    begin
        GLSetup.GetRecordOnce();
        case GLSetup."Bill-to/Sell-to VAT Calc." of
            GLSetup."Bill-to/Sell-to VAT Calc."::"Bill-to/Pay-to No.":
                begin
                    if not VATCustomer.Get(SalesHeader."Bill-to Customer No.") then
                        exit(VATCustomer.Get(SalesHeader."Sell-to Customer No."));
                    exit(true);
                end;
            GLSetup."Bill-to/Sell-to VAT Calc."::"Sell-to/Buy-from No.":
                exit(VATCustomer.Get(SalesHeader."Sell-to Customer No."));
        end;
    end;

    local procedure GetConfirmChangesNotificationId(): Guid
    begin
        exit('5a911b76-547b-49f4-ba6f-ffc64d75077d');
    end;

    local procedure AddStringToCommaSeparatedList(var List: Text; Value: Text)
    begin
        if List <> '' then
            List += ', ';
        List += Value;
    end;

    local procedure ThrowAddAltCustVATRegNotification(CustNo: Code[20]; VATCountryRegionCode: Code[10])
    var
        MyNotifications: Record "My Notifications";
        AltCustVATReg: Record "Alt. Cust. VAT Reg.";
        Notification: Notification;
    begin
        if not MyNotifications.IsEnabled(AddAltCustVATRegNotificationId()) then
            exit;
        Notification.Id(AddAltCustVATRegNotificationId());
        Notification.Message(AddAlternativeCustVATRegQst);
        Notification.SetData(AltCustVATReg.FieldName("Customer No."), CustNo);
        Notification.SetData(AltCustVATReg.FieldName("VAT Country/Region Code"), VATCountryRegionCode);
        Notification.AddAction(AddAlternativeCustVATRegMsg, Codeunit::"Alt. Cust. VAT Reg. Doc. Impl.", 'AddAltCustVATRegFromNotification');
        Notification.AddAction(DontShowMsg, Codeunit::"Alt. Cust. VAT Reg. Doc. Impl.", 'DisableAddAltCustVATRegNotification');
        Notification.Send();
    end;

    procedure AddAltCustVATRegFromNotification(Notification: Notification)
    var
        AltCustVATReg: Record "Alt. Cust. VAT Reg.";
        NewId: Integer;
    begin
        if AltCustVATReg.FindLast() then
            NewId := AltCustVATReg.Id;
        NewId += 1;
        AltCustVATReg.Init();
        AltCustVATReg.Validate(Id, NewId);
        AltCustVATReg.Validate("Customer No.",
            CopyStr(Notification.GetData(AltCustVATReg.FieldName("Customer No.")), 1, MaxStrLen(AltCustVATReg."Customer No.")));
        AltCustVATReg.Validate("VAT Country/Region Code",
            CopyStr(Notification.GetData(AltCustVATReg.FieldName("VAT Country/Region Code")), 1, MaxStrLen(AltCustVATReg."VAT Country/Region Code")));
        AltCustVATReg.Insert(true);
        Commit();
        Page.RunModal(0, AltCustVATReg);
    end;

    procedure DisableAddAltCustVATRegNotification(Notification: Notification)
    var
        MyNotifications: Record "My Notifications";
    begin
        if not MyNotifications.Disable(Notification.Id()) then
            MyNotifications.InsertDefault(Notification.Id(), AddAltCustVATRegNotificationNameTok, AddAltCustVATRegNotificationDescTok, false);
    end;

    local procedure AddAltCustVATRegNotificationId(): Text
    begin
        exit('44c9f482-ed1e-4882-9c96-3135915b566d')
    end;

    [EventSubscriber(ObjectType::Table, Database::"Sales Header", 'OnRecreateSalesLinesOnBeforeConfirm', '', false, false)]
    local procedure AvoidDoubleConfirmationOnRecreateSalesLinesOnBeforeConfirm(var SalesHeader: Record "Sales Header"; xSalesHeader: Record "Sales Header"; var Confirmed: Boolean; var IsHandled: Boolean)
    begin
        if not SalesLinesRecreated then
            exit;
        Confirmed := true;
        IsHandled := true;
        SalesLinesRecreated := false;
    end;

    [EventSubscriber(ObjectType::Table, Database::"Sales Header", 'OnAfterRecreateSalesLines', '', false, false)]
    local procedure SetSalesLineRecreatedOnAfterRecreateSalesLines()
    begin
        SalesLinesRecreated := true;
    end;
}