From 1cd5eb1074af68706c31a5b9208b0ee84c46d81c Mon Sep 17 00:00:00 2001 From: Jesper Schulz-Wedde Date: Wed, 19 Jun 2024 13:00:40 +0200 Subject: [PATCH] Syncing with version 25.0.20906.0 (#26687) Fixes [AB#420000](https://dynamicssmb2.visualstudio.com/1fcb79e7-ab07-432a-a3c6-6cf5a88ba4a5/_workitems/edit/420000) --- .github/AL-Go-Settings.json | 2 +- .../GenJnlPostLineHandlerCZZ.Codeunit.al | 10 +- .../PurchAdvLetterManagementCZZ.Codeunit.al | 242 ++---- .../PurchAdvLetterPostCZZ.Codeunit.al | 405 ++++++--- .../SalesAdvLetterManagementCZZ.Codeunit.al | 101 ++- .../SalesAdvLetterPostCZZ.Codeunit.al | 240 ++--- .../UpgradeApplicationCZZ.Codeunit.al | 16 + .../UpgradeTagDefinitionsCZZ.Codeunit.al | 6 + .../Pages/AdvanceLetterApplEditCZZ.Page.al | 7 + .../Pages/AdvanceLetterTemplatesCZZ.Page.al | 5 + .../PurchaseAdvanceVATDocCZZ.Report.al | 9 +- .../PurchaseInvoicewithAdvCZZ.Report.al | 8 + .../Reports/SalesAdvanceVATDocCZZ.Report.al | 9 +- .../Reports/SalesInvoicewithAdvCZZ.Report.al | 8 + .../GenJournalLineCZZ.TableExt.al | 50 +- .../Tables/AdvanceLetterTemplateCZZ.Table.al | 6 + .../Tables/AdvancePostingBufferCZZ.Table.al | 6 + .../Tables/PurchAdvLetterEntryCZZ.Table.al | 7 + .../Tables/PurchAdvLetterHeaderCZZ.Table.al | 16 +- .../Src/Tables/PurchAdvLetterLineCZZ.Table.al | 4 +- .../Tables/SalesAdvLetterEntryCZZ.Table.al | 7 + .../Tables/SalesAdvLetterHeaderCZZ.Table.al | 16 +- .../Src/Tables/SalesAdvLetterLineCZZ.Table.al | 4 +- .../Src/PurchAdvPmtRevChargeCZZ.Codeunit.al | 821 ++++++++++++++++++ .../PurchaseAdvancePaymentsCZZ.Codeunit.al | 31 + .../Src/SalesAdvPmtRevChargeCZZ.Codeunit.al | 755 ++++++++++++++++ .../Src/SalesAdvancePaymentsCZZ.Codeunit.al | 36 + .../CashDeskManagementCZP.Codeunit.al | 113 ++- .../Src/Pages/CashDeskActivitiesCZP.Page.al | 8 +- .../app/Src/Pages/CashDeskListCZP.Page.al | 9 +- .../app/Src/Pages/CashDocumentListCZP.Page.al | 9 +- .../Pages/PostedCashDocumentListCZP.Page.al | 9 +- .../Src/Tables/CashDocumentHeaderCZP.Table.al | 8 +- .../AccSchedExtensionMgtCZL.Codeunit.al | 17 +- .../GenJnlPostLineHandlerCZL.Codeunit.al | 37 +- .../Codeunits/NonDeductibleVATCZL.Codeunit.al | 13 + .../PstdGenJnlLineHandlerCZL.Codeunit.al | 18 + .../Codeunits/VATDateHandlerCZL.Codeunit.al | 8 +- .../AccScheduleOverviewCZL.PageExt.al | 2 +- .../SalesOrderSubformCZL.PageExt.al | 2 +- .../Reports/DocumentationforVATCZL.Report.al | 16 +- .../Src/PurchPostPrepmtHandlerCZL.Codeunit.al | 8 + .../Src/TestInitializeHandlerCZL.Codeunit.al | 26 +- .../ElectronicVATDeclarationDK/app/app.json | 2 +- .../src/Engine/ElecVATDeclInstall.Codeunit.al | 12 + .../src/Engine/ElecVATDeclUpgrade.Codeunit.al | 46 + .../OIOUBLExportSalesCrMemo.Codeunit.al | 8 +- .../OIOUBLExportSalesInvoice.Codeunit.al | 8 +- .../GSTTaxConfiguration.Codeunit.al | 2 +- .../app/GSTBase/src/table/HSNSAC.table.al | 4 +- .../app/Translations/India GST.en-GB.xlf | 2 +- .../app/Translations/India GST.en-US.xlf | 2 +- .../TDSTaxConfiguration.Codeunit.al | 2 +- .../app/Translations/India TDS.en-GB.xlf | 2 +- .../app/Translations/India TDS.en-US.xlf | 2 +- .../src/Codeunits/EnableISCoreApp.Codeunit.al | 12 + .../src/Codeunits/ISCoreUpgrade.Codeunit.al | 24 +- .../src/Pages/ISCoreAppSetupWizard.Page.al | 1 + .../app/src/Printing/IRS 1099 Print.docx | Bin 27144 -> 27310 bytes .../app/Codeunits/AMCBankingMgt.Codeunit.al | 3 + .../app/src/pages/APIV2CustContacts.Page.al | 32 +- .../NavigateBankDepositExt.Codeunit.al | 90 -- .../app/src/pages/BankDepositSubform.Page.al | 3 +- .../src/BankDepositPostingTests.Codeunit.al | 56 ++ .../test/src/UTPageBankDeposit.Codeunit.al | 20 +- .../pages/APIBufICInboxPurchaseLine.Page.al | 10 + .../src/pages/APIBufICInboxSalesLine.Page.al | 10 + .../Copilot/EDocPOCopilotMatching.Codeunit.al | 18 - .../app/src/EmailOAuthClient.Codeunit.al | 43 +- .../DigVoucherIncDocAttach.TableExt.al | 16 + .../DigitalVoucherImpl.Codeunit.al | 36 +- .../VoucherAttachmentCheck.Codeunit.al | 2 +- .../test/src/DigitalVouchersTests.Codeunit.al | 241 +++++ .../FixedAsset/FixedAssetAnalysisExcel.xlsx | Bin 0 -> 58858 bytes .../FixedAsset/FixedAssetDetailsExcel.xlsx | Bin 50963 -> 40885 bytes .../FixedAssetProjectedValueExcel.xlsx | Bin 0 -> 36198 bytes .../ConsolidatedTrialBalanceExcel.xlsx | Bin 68747 -> 59205 bytes .../EXRFixedAssetAnalysisExcel.Report.al | 222 +++++ .../EXRFixedAssetDetailsExcel.Report.al | 1 + .../EXRFixedAssetProjected.Report.al | 282 ++++++ .../Items/GPItemMigrator.codeunit.al | 9 +- .../Support/HelperFunctions.codeunit.al | 4 +- Apps/W1/HybridGP/test/app.json | 2 +- .../MasterDataMgtSubscribers.Codeunit.al | 3 + .../test/src/MigrationQBOTests.Codeunit.al | 8 - .../app/SLSPrompts.Codeunit.al | 11 +- .../BlanketSalesOrderLookup.Codeunit.al | 174 ++++ .../SalesInvoiceLookup.Codeunit.al | 139 +-- .../SalesOrderLookup.Codeunit.al | 120 +-- .../SalesQuoteLookup.Codeunit.al | 120 +-- .../SalesShipmentLookup.Codeunit.al | 139 +-- .../Enums/DocumentLookupTypes.Enum.al | 4 + .../SearchItemsWithFiltersFunc.Codeunit.al | 236 +++++ .../app/SalesLineAISuggestions.Page.al | 29 +- .../app/SalesLineAISuggestions.Table.al | 8 + .../app/SalesLineAISuggestionsSub.Page.al | 4 + .../app/SalesLinesSuggestionsImpl.Codeunit.al | 14 +- .../app/Search/Search.Codeunit.al | 48 +- .../app/Search/SearchAPIResponse.Table.al | 1 + .../app/Search/SearchConfidence.Enum.al | 4 + .../Utilities/SalesLineUtility.Codeunit.al | 55 +- Apps/W1/SalesLinesSuggestions/app/app.json | 2 +- .../app/src/Base/Pages/ShpfyShopCard.Page.al | 7 - .../app/src/Base/Tables/ShpfyShop.Table.al | 6 - .../Codeunits/ShpfyCompanyAPI.Codeunit.al | 1 + .../Companies/Pages/ShpfyCompanyCard.Page.al | 20 +- .../Tables/ShpfyCompanyLocation.Table.al | 5 + .../Codeunits/ShpfyGQLCompany.Codeunit.al | 2 +- .../Codeunits/ShpfyGQLOrderHeader.Codeunit.al | 2 +- .../Codeunits/ShpfyImportOrder.Codeunit.al | 4 +- .../Codeunits/ShpfyOrderEvents.Codeunit.al | 11 + .../Codeunits/ShpfyOrdersAPI.Codeunit.al | 3 +- .../Codeunits/ShpfyProcessOrder.Codeunit.al | 17 +- .../Tables/ShpfyOrderHeader.Table.al | 8 + .../ShpfyShippingCharges.Codeunit.al | 49 +- .../Tables/ShpfyOrderShippingCharges.Table.al | 10 + .../Reports/ShpfySuggestPayments.Report.al | 5 +- .../APIs/SustainabilityLedgEntries.Page.al | 3 + .../Journal/SustainabilityJnlLine.Table.al | 2 +- .../src/SustainabilityAPITests.Codeunit.al | 385 ++++++++ .../src/TransStorageErrorHandler.Codeunit.al | 5 +- .../app/src/TransStorageExportData.Table.al | 49 ++ .../src/TransactStorageExportData.Codeunit.al | 67 +- .../app/src/TransactionStorageABS.Codeunit.al | 65 +- .../DisabledTests/SustainabilityAPITests.json | 7 + 125 files changed, 4995 insertions(+), 1216 deletions(-) create mode 100644 Apps/CZ/AdvancePaymentsLocalization/test/Src/PurchAdvPmtRevChargeCZZ.Codeunit.al create mode 100644 Apps/CZ/AdvancePaymentsLocalization/test/Src/SalesAdvPmtRevChargeCZZ.Codeunit.al create mode 100644 Apps/CZ/CoreLocalizationPack/app/Src/Codeunits/PstdGenJnlLineHandlerCZL.Codeunit.al create mode 100644 Apps/CZ/CoreLocalizationPack/test/Src/PurchPostPrepmtHandlerCZL.Codeunit.al create mode 100644 Apps/DK/ElectronicVATDeclarationDK/app/src/Engine/ElecVATDeclUpgrade.Codeunit.al create mode 100644 Apps/W1/EnforcedDigitalVouchers/app/src/Extensions/DigVoucherIncDocAttach.TableExt.al create mode 100644 Apps/W1/ExcelReports/app/ReportLayouts/Excel/FixedAsset/FixedAssetAnalysisExcel.xlsx create mode 100644 Apps/W1/ExcelReports/app/ReportLayouts/Excel/FixedAsset/FixedAssetProjectedValueExcel.xlsx create mode 100644 Apps/W1/ExcelReports/app/src/Financials/EXRFixedAssetAnalysisExcel.Report.al create mode 100644 Apps/W1/ExcelReports/app/src/Financials/EXRFixedAssetProjected.Report.al create mode 100644 Apps/W1/SalesLinesSuggestions/app/SalesAzureOpenAITools/DocumentLookupImpl/BlanketSalesOrderLookup.Codeunit.al create mode 100644 Apps/W1/SalesLinesSuggestions/app/SalesAzureOpenAITools/FunctionsImpl/SearchItemsWithFiltersFunc.Codeunit.al create mode 100644 Apps/W1/Sustainability/test/src/SustainabilityAPITests.Codeunit.al create mode 100644 Apps/W1/TransactionStorage/app/src/TransStorageExportData.Table.al create mode 100644 Build/DisabledTests/SustainabilityAPITests.json diff --git a/.github/AL-Go-Settings.json b/.github/AL-Go-Settings.json index 667cbffc6b..379ec9f4f4 100644 --- a/.github/AL-Go-Settings.json +++ b/.github/AL-Go-Settings.json @@ -5,7 +5,7 @@ "runs-on": "windows-latest", "cacheImageName": "", "UsePsSession": false, - "artifact": "https://bcinsider-fvh2ekdjecfjd6gk.b02.azurefd.net/sandbox/25.0.20074.0/base", + "artifact": "https://bcinsider-fvh2ekdjecfjd6gk.b02.azurefd.net/sandbox/25.0.20906.0/base", "country": "base", "useProjectDependencies": true, "repoVersion": "25.0", diff --git a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/GenJnlPostLineHandlerCZZ.Codeunit.al b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/GenJnlPostLineHandlerCZZ.Codeunit.al index 19407206f8..d74f0e936b 100644 --- a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/GenJnlPostLineHandlerCZZ.Codeunit.al +++ b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/GenJnlPostLineHandlerCZZ.Codeunit.al @@ -26,19 +26,11 @@ codeunit 31003 "Gen.Jnl.-Post Line Handler CZZ" [EventSubscriber(ObjectType::Codeunit, Codeunit::"Gen. Jnl.-Post Line", 'OnBeforeCreateGLEntriesForTotalAmountsV19', '', false, false)] local procedure GenJnlPostLineOnBeforeCreateGLEntriesForTotalAmounts(GenJournalLine: Record "Gen. Journal Line"; var GLAccNo: Code[20]) - var - SalesAdvLetterManagement: Codeunit "SalesAdvLetterManagement CZZ"; - PurchAdvLetterManagement: Codeunit "PurchAdvLetterManagement CZZ"; begin if not GenJournalLine."Use Advance G/L Account CZZ" then exit; - case GenJournalLine."Account Type" of - GenJournalLine."Account Type"::Customer: - GLAccNo := SalesAdvLetterManagement.GetAdvanceGLAccount(GenJournalLine); - GenJournalLine."Account Type"::Vendor: - GLAccNo := PurchAdvLetterManagement.GetAdvanceGLAccount(GenJournalLine); - end; + GLAccNo := GenJournalLine.GetAdvanceGLAccountNoCZZ(); end; [EventSubscriber(ObjectType::Codeunit, Codeunit::"Gen. Jnl.-Post Line", 'OnBeforePostApply', '', false, false)] diff --git a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/PurchAdvLetterManagementCZZ.Codeunit.al b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/PurchAdvLetterManagementCZZ.Codeunit.al index bb8c20ad71..b9b2628647 100644 --- a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/PurchAdvLetterManagementCZZ.Codeunit.al +++ b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/PurchAdvLetterManagementCZZ.Codeunit.al @@ -23,7 +23,6 @@ codeunit 31019 "PurchAdvLetterManagement CZZ" var PurchAdvLetterEntryCZZGlob: Record "Purch. Adv. Letter Entry CZZ"; TempPurchAdvLetterEntryCZZGlob: Record "Purch. Adv. Letter Entry CZZ" temporary; - CurrencyGlob: Record Currency; PurchAdvLetterPostCZZ: Codeunit "Purch. Adv. Letter-Post CZZ"; DateEmptyErr: Label 'Posting Date and VAT Date cannot be empty.'; DocumentNoOrDatesEmptyErr: Label 'Document No. and Dates cannot be empty.'; @@ -229,7 +228,9 @@ codeunit 31019 "PurchAdvLetterManagement CZZ" AdvanceLetterLink.GetLetterLink(TempAdvanceLetterLinkBuffer); TempAdvanceLetterLinkBuffer.SetFilter(Amount, '>0'); if not TempAdvanceLetterLinkBuffer.IsEmpty() then begin - PostingDate := GetPostingDateUI(VendorLedgerEntry."Posting Date"); + PostingDate := VendorLedgerEntry."Posting Date"; + if not GetPostingDateUI(PostingDate) then + exit; if PostingDate = 0D then Error(PostingDateEmptyErr); LinkAdvancePayment(VendorLedgerEntry, TempAdvanceLetterLinkBuffer, PostingDate); @@ -252,7 +253,9 @@ codeunit 31019 "PurchAdvLetterManagement CZZ" var PostingDate: Date; begin - PostingDate := GetPostingDateUI(VendorLedgerEntry."Posting Date"); + PostingDate := VendorLedgerEntry."Posting Date"; + if not GetPostingDateUI(PostingDate) then + exit; if PostingDate = 0D then Error(PostingDateEmptyErr); @@ -263,7 +266,9 @@ codeunit 31019 "PurchAdvLetterManagement CZZ" var PostingDate: Date; begin - PostingDate := GetPostingDateUI(VendorLedgerEntry."Posting Date"); + PostingDate := VendorLedgerEntry."Posting Date"; + if not GetPostingDateUI(PostingDate) then + exit; if PostingDate = 0D then Error(PostingDateEmptyErr); @@ -289,7 +294,8 @@ codeunit 31019 "PurchAdvLetterManagement CZZ" PurchAdvLetterPostCZZ.PostAdvancePayment( VendorLedgerEntry, PostedGenJournalLine, GenJnlPostLine, AdvancePostingParametersCZZ); end; - +#if not CLEAN25 + [Obsolete('Replaced by GetAdvanceGLAccountNoCZZ function in GenJournalLine.', '25.0')] procedure GetAdvanceGLAccount(var GenJournalLine: Record "Gen. Journal Line"): Code[20] var PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; @@ -301,6 +307,7 @@ codeunit 31019 "PurchAdvLetterManagement CZZ" AdvanceLetterTemplateCZZ.TestField("Advance Letter G/L Account"); exit(AdvanceLetterTemplateCZZ."Advance Letter G/L Account"); end; +#endif procedure PostAdvancePaymentVAT(var PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; PostingDate: Date) var @@ -351,15 +358,24 @@ codeunit 31019 "PurchAdvLetterManagement CZZ" AdvanceLetterTemplateCZZ.Get(PurchAdvLetterHeaderCZZ."Advance Letter Code"); AdvanceLetterTemplateCZZ.TestField("Advance Letter Invoice Nos."); - InitVATAmountLine(TempAdvancePostingBufferCZZ, PurchAdvLetterEntryCZZ."Purch. Adv. Letter No.", PurchAdvLetterEntryCZZ.Amount, PurchAdvLetterEntryCZZ."Currency Factor"); - VATDocumentCZZ.InitDocument(AdvanceLetterTemplateCZZ."Advance Letter Invoice Nos.", '', PurchAdvLetterHeaderCZZ."Document Date", + InitVATAmountLine(TempAdvancePostingBufferCZZ, PurchAdvLetterEntryCZZ."Purch. Adv. Letter No.", + PurchAdvLetterEntryCZZ.Amount, PurchAdvLetterEntryCZZ."Currency Factor"); + + TempAdvancePostingBufferCZZ.Reset(); + TempAdvancePostingBufferCZZ.SetRange("Auxiliary Entry", false); + if TempAdvancePostingBufferCZZ.IsEmpty() then + DocumentNo := PurchAdvLetterHeaderCZZ."No."; + TempAdvancePostingBufferCZZ.Reset(); + + VATDocumentCZZ.InitDocument(AdvanceLetterTemplateCZZ."Advance Letter Invoice Nos.", DocumentNo, PurchAdvLetterHeaderCZZ."Document Date", PostingDate, PurchAdvLetterEntryCZZ."VAT Date", PurchAdvLetterHeaderCZZ."Original Document VAT Date", PurchAdvLetterHeaderCZZ."Currency Code", PurchAdvLetterEntryCZZ."Currency Factor", '', TempAdvancePostingBufferCZZ); if VATDocumentCZZ.RunModal() <> Action::OK then exit; VATDocumentCZZ.SaveNoSeries(); - VATDocumentCZZ.GetDocument(DocumentNo, PostingDate, DocumentDate, VATDate, OriginalDocumentVATDate, ExternalDocumentNo, TempAdvancePostingBufferCZZ); + VATDocumentCZZ.GetDocument(DocumentNo, PostingDate, DocumentDate, VATDate, + OriginalDocumentVATDate, ExternalDocumentNo, TempAdvancePostingBufferCZZ); Clear(AdvancePostingParametersCZZ); AdvancePostingParametersCZZ."Document Type" := Enum::"Gen. Journal Document Type"::Invoice; @@ -413,24 +429,29 @@ codeunit 31019 "PurchAdvLetterManagement CZZ" local procedure BufferAdvanceLines(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ") var + AdvanceLetterTemplateCZZ: Record "Advance Letter Template CZZ"; PurchAdvLetterLineCZZ: Record "Purch. Adv. Letter Line CZZ"; TempAdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ" temporary; begin AdvancePostingBufferCZZ.Reset(); AdvancePostingBufferCZZ.DeleteAll(); + AdvanceLetterTemplateCZZ.Get(PurchAdvLetterHeaderCZZ."Advance Letter Code"); + PurchAdvLetterLineCZZ.SetRange("Document No.", PurchAdvLetterHeaderCZZ."No."); PurchAdvLetterLineCZZ.SetFilter(Amount, '<>0'); if PurchAdvLetterLineCZZ.FindSet() then repeat TempAdvancePostingBufferCZZ.PrepareForPurchAdvLetterLine(PurchAdvLetterLineCZZ); AdvancePostingBufferCZZ.Update(TempAdvancePostingBufferCZZ); - until PurchAdvLetterLineCZZ.Next() = 0; - end; - local procedure GetCurrency(CurrencyCode: Code[10]) - begin - CurrencyGlob.Initialize(CurrencyCode, true); + if (not AdvanceLetterTemplateCZZ."Post VAT Doc. for Rev. Charge") and + (AdvancePostingBufferCZZ."VAT Calculation Type" = "Tax Calculation Type"::"Reverse Charge VAT") + then begin + AdvancePostingBufferCZZ."Auxiliary Entry" := true; + AdvancePostingBufferCZZ.Modify(); + end; + until PurchAdvLetterLineCZZ.Next() = 0; end; procedure LinkAdvanceLetter(AdvLetterUsageDocTypeCZZ: Enum "Adv. Letter Usage Doc.Type CZZ"; DocumentNo: Code[20]; PayToVendorNo: Code[20]; PostingDate: Date; CurrencyCode: Code[10]) @@ -488,7 +509,9 @@ codeunit 31019 "PurchAdvLetterManagement CZZ" begin VendorLedgerEntry.TestField("Advance Letter No. CZZ"); - PostingDate := GetPostingDateUI(VendorLedgerEntry."Posting Date"); + PostingDate := VendorLedgerEntry."Posting Date"; + if not GetPostingDateUI(PostingDate) then + exit; if PostingDate = 0D then Error(PostingDateEmptyErr); @@ -508,7 +531,9 @@ codeunit 31019 "PurchAdvLetterManagement CZZ" PostingDate: Date; begin VendorLedgerEntry.Get(PurchAdvLetterEntryCZZ."Vendor Ledger Entry No."); - PostingDate := GetPostingDateUI(VendorLedgerEntry."Posting Date"); + PostingDate := VendorLedgerEntry."Posting Date"; + if not GetPostingDateUI(PostingDate) then + exit; if PostingDate = 0D then Error(PostingDateEmptyErr); UnlinkAdvancePayment(PurchAdvLetterEntryCZZ, PostingDate); @@ -651,46 +676,6 @@ codeunit 31019 "PurchAdvLetterManagement CZZ" PurchAdvLetterEntryCZZ, TempAdvancePostingBufferCZZ, GenJnlPostLine, AdvancePostingParametersCZZ); end; - local procedure PostExchangeRate(ExchRateAmount: Decimal; ExchRateVATAmount: Decimal; var PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; - var PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; var VATPostingSetup: Record "VAT Posting Setup"; - DocumentNo: Code[20]; PostingDate: Date; VATDate: Date; SourceCode: Code[10]; PostDescription: Text[100]; UsageEntryNo: Integer; Correction: Boolean; - var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; Preview: Boolean) - var - AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; - begin - Clear(AdvancePostingParametersCZZ); - AdvancePostingParametersCZZ."Document No." := DocumentNo; - AdvancePostingParametersCZZ."Posting Date" := PostingDate; - AdvancePostingParametersCZZ."VAT Date" := VATDate; - AdvancePostingParametersCZZ."Source Code" := SourceCode; - AdvancePostingParametersCZZ."Posting Description" := PostDescription; - AdvancePostingParametersCZZ."Temporary Entries Only" := Preview; - - PurchAdvLetterPostCZZ.PostExchangeRate( - PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, VATPostingSetup, - ExchRateAmount, ExchRateVATAmount, UsageEntryNo, Correction, GenJnlPostLine, AdvancePostingParametersCZZ); - end; - - local procedure InitGenJnlLineFromAdvance(var PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; var PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; DocumentNo: Code[20]; ExternalDocumentNo: Code[35]; SourceCode: Code[10]; PostDescription: Text[100]; var GenJournalLine: Record "Gen. Journal Line") - begin - GenJournalLine.Init(); - GenJournalLine."System-Created Entry" := true; - GenJournalLine."Document No." := DocumentNo; - GenJournalLine."External Document No." := ExternalDocumentNo; - GenJournalLine.Description := PostDescription; - GenJournalLine."Source Code" := SourceCode; - GenJournalLine."Bill-to/Pay-to No." := PurchAdvLetterHeaderCZZ."Pay-to Vendor No."; - GenJournalLine."Country/Region Code" := PurchAdvLetterHeaderCZZ."Pay-to Country/Region Code"; - GenJournalLine."VAT Registration No." := PurchAdvLetterHeaderCZZ."VAT Registration No."; - GenJournalLine."Registration No. CZL" := PurchAdvLetterHeaderCZZ."Registration No."; - GenJournalLine."Tax Registration No. CZL" := PurchAdvLetterHeaderCZZ."Tax Registration No."; - GenJournalLine."Shortcut Dimension 1 Code" := PurchAdvLetterEntryCZZ."Global Dimension 1 Code"; - GenJournalLine."Shortcut Dimension 2 Code" := PurchAdvLetterEntryCZZ."Global Dimension 2 Code"; - GenJournalLine."Dimension Set ID" := PurchAdvLetterEntryCZZ."Dimension Set ID"; - GenJournalLine."Adv. Letter No. (Entry) CZZ" := PurchAdvLetterEntryCZZ."Purch. Adv. Letter No."; - OnAfterInitGenJnlLineFromAdvance(PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, GenJournalLine); - end; - procedure GetRemAmtPurchAdvPayment(var PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; BalanceAtDate: Date): Decimal var PurchAdvLetterEntry2: Record "Purch. Adv. Letter Entry CZZ"; @@ -834,6 +819,7 @@ codeunit 31019 "PurchAdvLetterManagement CZZ" VATDocumentCZZ: Page "VAT Document CZZ"; DocumentNo: Code[20]; ExternalDocumentNo: Code[35]; + SourceCode: Code[10]; VATDate: Date; OriginalDocumentVATDate: Date; DocumentDate: Date; @@ -844,7 +830,13 @@ codeunit 31019 "PurchAdvLetterManagement CZZ" PurchAdvLetterHeaderCZZ.Get(PurchAdvLetterEntryCZZ."Purch. Adv. Letter No."); AdvanceLetterTemplateCZZ.Get(PurchAdvLetterHeaderCZZ."Advance Letter Code"); - VATEntry.Get(PurchAdvLetterEntryCZZ."VAT Entry No."); + + // find VAT entry of the VAT document due to source code + SourceCode := ''; + VATEntry.SetRange("Document No.", PurchAdvLetterEntryCZZ."Document No."); + VATEntry.SetRange("Posting Date", PurchAdvLetterEntryCZZ."Posting Date"); + if VATEntry.FindFirst() then + SourceCode := VATEntry."Source Code"; PurchAdvLetterEntryCZZ2.SetRange("Purch. Adv. Letter No.", PurchAdvLetterEntryCZZ."Purch. Adv. Letter No."); PurchAdvLetterEntryCZZ2.SetRange(Cancelled, false); @@ -856,7 +848,13 @@ codeunit 31019 "PurchAdvLetterManagement CZZ" TempAdvancePostingBufferCZZ1.Update(TempAdvancePostingBufferCZZ); until PurchAdvLetterEntryCZZ2.Next() = 0; - VATDocumentCZZ.InitDocument(AdvanceLetterTemplateCZZ."Advance Letter Cr. Memo Nos.", '', PurchAdvLetterEntryCZZ."Posting Date", + TempAdvancePostingBufferCZZ1.Reset(); + TempAdvancePostingBufferCZZ1.SetRange("Auxiliary Entry", false); + if TempAdvancePostingBufferCZZ1.IsEmpty() then + DocumentNo := PurchAdvLetterHeaderCZZ."No."; + TempAdvancePostingBufferCZZ1.Reset(); + + VATDocumentCZZ.InitDocument(AdvanceLetterTemplateCZZ."Advance Letter Cr. Memo Nos.", DocumentNo, PurchAdvLetterEntryCZZ."Posting Date", PurchAdvLetterEntryCZZ."Posting Date", PurchAdvLetterEntryCZZ."VAT Date", PurchAdvLetterEntryCZZ."Original Document VAT Date", PurchAdvLetterHeaderCZZ."Currency Code", PurchAdvLetterEntryCZZ."Currency Factor", PurchAdvLetterEntryCZZ."External Document No.", TempAdvancePostingBufferCZZ1); if VATDocumentCZZ.RunModal() <> Action::OK then @@ -873,7 +871,7 @@ codeunit 31019 "PurchAdvLetterManagement CZZ" AdvancePostingParametersCZZ."Document Type" := "Gen. Journal Document Type"::"Credit Memo"; AdvancePostingParametersCZZ."Document No." := DocumentNo; AdvancePostingParametersCZZ."External Document No." := ExternalDocumentNo; - AdvancePostingParametersCZZ."Source Code" := VATEntry."Source Code"; + AdvancePostingParametersCZZ."Source Code" := SourceCode; AdvancePostingParametersCZZ."Posting Description" := PurchAdvLetterHeaderCZZ."Posting Description"; AdvancePostingParametersCZZ."Posting Date" := PostingDate; AdvancePostingParametersCZZ."Document Date" := PostingDate; @@ -888,105 +886,16 @@ codeunit 31019 "PurchAdvLetterManagement CZZ" procedure PostCancelUsageVAT(var PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ") var - PurchAdvLetterEntryCZZ2: Record "Purch. Adv. Letter Entry CZZ"; - PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; - AdvanceLetterTemplateCZZ: Record "Advance Letter Template CZZ"; - VATPostingSetup: Record "VAT Posting Setup"; - GenJournalLine: Record "Gen. Journal Line"; + AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; - VATPostingSetupHandlerCZZ: Codeunit "VAT Posting Setup Handler CZZ"; begin - PurchAdvLetterEntryCZZ.TestField("Entry Type", PurchAdvLetterEntryCZZ."Entry Type"::"VAT Usage"); - PurchAdvLetterEntryCZZ.TestField(Cancelled, false); - - PurchAdvLetterHeaderCZZ.Get(PurchAdvLetterEntryCZZ."Purch. Adv. Letter No."); - AdvanceLetterTemplateCZZ.Get(PurchAdvLetterHeaderCZZ."Advance Letter Code"); - AdvanceLetterTemplateCZZ.TestField("Advance Letter Cr. Memo Nos."); - - GetCurrency(PurchAdvLetterEntryCZZ."Currency Code"); - - PurchAdvLetterEntryCZZ2.Reset(); - PurchAdvLetterEntryCZZ2.SetRange("Document No.", PurchAdvLetterEntryCZZ."Document No."); - PurchAdvLetterEntryCZZ2.SetFilter("Entry Type", '%1|%2|%3', PurchAdvLetterEntryCZZ2."Entry Type"::"VAT Adjustment", - PurchAdvLetterEntryCZZ2."Entry Type"::"VAT Rate", PurchAdvLetterEntryCZZ2."Entry Type"::"VAT Usage"); - PurchAdvLetterEntryCZZ2.SetRange(Cancelled, false); - PurchAdvLetterEntryCZZ2.Find('+'); - PurchAdvLetterEntryCZZ2.SetFilter("Entry No.", '..%1', PurchAdvLetterEntryCZZ2."Entry No."); - repeat - case PurchAdvLetterEntryCZZ2."Entry Type" of - PurchAdvLetterEntryCZZ2."Entry Type"::"VAT Adjustment": - begin - VATPostingSetup.Get(PurchAdvLetterEntryCZZ2."VAT Bus. Posting Group", PurchAdvLetterEntryCZZ2."VAT Prod. Posting Group"); - PostUnrealizedExchangeRate(PurchAdvLetterEntryCZZ2, PurchAdvLetterHeaderCZZ, VATPostingSetup, -PurchAdvLetterEntryCZZ2."Amount (LCY)", -PurchAdvLetterEntryCZZ2."VAT Amount (LCY)", - PurchAdvLetterEntryCZZ2."Related Entry", 0, PurchAdvLetterEntryCZZ2."Document No.", PurchAdvLetterEntryCZZ2."Posting Date", PurchAdvLetterEntryCZZ2."VAT Date", '', GenJnlPostLine, true, false); - end; - PurchAdvLetterEntryCZZ2."Entry Type"::"VAT Rate": - begin - VATPostingSetup.Get(PurchAdvLetterEntryCZZ2."VAT Bus. Posting Group", PurchAdvLetterEntryCZZ2."VAT Prod. Posting Group"); - PostExchangeRate(-PurchAdvLetterEntryCZZ2."Amount (LCY)", -PurchAdvLetterEntryCZZ2."VAT Amount (LCY)", PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ2, VATPostingSetup, - PurchAdvLetterEntryCZZ2."Document No.", PurchAdvLetterEntryCZZ2."Posting Date", PurchAdvLetterEntryCZZ2."VAT Date", '', - '', PurchAdvLetterEntryCZZ2."Related Entry", true, GenJnlPostLine, false); - end; - PurchAdvLetterEntryCZZ2."Entry Type"::"VAT Usage": - begin - VATPostingSetup.Get(PurchAdvLetterEntryCZZ2."VAT Bus. Posting Group", PurchAdvLetterEntryCZZ2."VAT Prod. Posting Group"); - InitGenJnlLineFromAdvance(PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ2, PurchAdvLetterEntryCZZ2."Document No.", PurchAdvLetterEntryCZZ2."External Document No.", - '', '', GenJournalLine); - GenJournalLine.Validate("Posting Date", PurchAdvLetterEntryCZZ2."Posting Date"); - GenJournalLine.Validate("VAT Reporting Date", PurchAdvLetterEntryCZZ2."VAT Date"); - GenJournalLine.Validate("Original Doc. VAT Date CZL", PurchAdvLetterEntryCZZ2."Original Document VAT Date"); - GenJournalLine."Account No." := VATPostingSetup."Purch. Adv. Letter Account CZZ"; - GenJournalLine.SetCurrencyFactor(PurchAdvLetterEntryCZZ2."Currency Code", PurchAdvLetterEntryCZZ2."Currency Factor"); - GenJournalLine."Gen. Posting Type" := GenJournalLine."Gen. Posting Type"::Purchase; - GenJournalLine."VAT Calculation Type" := PurchAdvLetterEntryCZZ2."VAT Calculation Type"; - GenJournalLine."VAT Bus. Posting Group" := PurchAdvLetterEntryCZZ2."VAT Bus. Posting Group"; - GenJournalLine.Validate("VAT Prod. Posting Group", PurchAdvLetterEntryCZZ2."VAT Prod. Posting Group"); - GenJournalLine.Correction := true; - GenJournalLine.Validate(Amount, -PurchAdvLetterEntryCZZ2.Amount); - GenJournalLine."VAT Amount" := -PurchAdvLetterEntryCZZ2."VAT Amount"; - GenJournalLine."VAT Base Amount" := GenJournalLine.Amount - GenJournalLine."VAT Amount"; - GenJournalLine."VAT Difference" := GenJournalLine."VAT Amount" - Round(GenJournalLine.Amount * GenJournalLine."VAT %" / (100 + GenJournalLine."VAT %"), - CurrencyGlob."Amount Rounding Precision", CurrencyGlob.VATRoundingDirection()); - if GenJournalLine."Currency Code" = '' then begin - GenJournalLine."Amount (LCY)" := GenJournalLine.Amount; - GenJournalLine."VAT Amount (LCY)" := GenJournalLine."VAT Amount"; - GenJournalLine."VAT Base Amount (LCY)" := GenJournalLine."VAT Base Amount"; - end else begin - GenJournalLine."Amount (LCY)" := -PurchAdvLetterEntryCZZ2."Amount (LCY)"; - GenJournalLine."VAT Amount (LCY)" := -PurchAdvLetterEntryCZZ2."VAT Amount (LCY)"; - GenJournalLine."VAT Base Amount (LCY)" := GenJournalLine."Amount (LCY)" - GenJournalLine."VAT Amount (LCY)"; - end; - BindSubscription(VATPostingSetupHandlerCZZ); - GenJnlPostLine.RunWithCheck(GenJournalLine); - UnbindSubscription(VATPostingSetupHandlerCZZ); - - AdvEntryInit(false); - AdvEntryInitRelatedEntry(PurchAdvLetterEntryCZZ2."Related Entry"); - AdvEntryInitCancel(); - AdvEntryInitVAT(GenJournalLine."VAT Bus. Posting Group", GenJournalLine."VAT Prod. Posting Group", - GenJournalLine."VAT Reporting Date", GenJournalLine."Original Doc. VAT Date CZL", - GenJnlPostLine.GetNextVATEntryNo() - 1, GenJournalLine."VAT %", VATPostingSetup."VAT Identifier", GenJournalLine."VAT Calculation Type", - GenJournalLine."VAT Amount", GenJournalLine."VAT Amount (LCY)", GenJournalLine."VAT Base Amount", GenJournalLine."VAT Base Amount (LCY)"); - AdvEntryInsert("Advance Letter Entry Type CZZ"::"VAT Usage", PurchAdvLetterEntryCZZ2."Purch. Adv. Letter No.", GenJournalLine."Posting Date", - GenJournalLine.Amount, GenJournalLine."Amount (LCY)", - GenJournalLine."Currency Code", GenJournalLine."Currency Factor", GenJournalLine."Document No.", GenJournalLine."External Document No.", - GenJournalLine."Shortcut Dimension 1 Code", GenJournalLine."Shortcut Dimension 2 Code", GenJournalLine."Dimension Set ID", false); - - InitGenJnlLineFromAdvance(PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ2, PurchAdvLetterEntryCZZ2."Document No.", PurchAdvLetterEntryCZZ2."External Document No.", '', '', GenJournalLine); - GenJournalLine.Validate("Posting Date", PurchAdvLetterEntryCZZ2."Posting Date"); - GenJournalLine.Validate("VAT Reporting Date", PurchAdvLetterEntryCZZ2."VAT Date"); - GenJournalLine.Validate("Original Doc. VAT Date CZL", PurchAdvLetterEntryCZZ2."Original Document VAT Date"); - GenJournalLine."Account No." := VATPostingSetup."Purch. Adv. Letter Account CZZ"; - GenJournalLine.SetCurrencyFactor(PurchAdvLetterEntryCZZ2."Currency Code", PurchAdvLetterEntryCZZ2."Currency Factor"); - GenJournalLine.Correction := true; - GenJournalLine.Validate(Amount, PurchAdvLetterEntryCZZ2.Amount); - GenJnlPostLine.RunWithCheck(GenJournalLine); - end; - end; - until PurchAdvLetterEntryCZZ2.Next(-1) = 0; + Clear(AdvancePostingParametersCZZ); + AdvancePostingParametersCZZ."Document No." := PurchAdvLetterEntryCZZ."Document No."; + AdvancePostingParametersCZZ."Posting Date" := PurchAdvLetterEntryCZZ."Posting Date"; + AdvancePostingParametersCZZ."VAT Date" := PurchAdvLetterEntryCZZ."VAT Date"; + AdvancePostingParametersCZZ."Original Document VAT Date" := PurchAdvLetterEntryCZZ."Original Document VAT Date"; - PurchAdvLetterEntryCZZ2.ModifyAll(Cancelled, true); - PurchAdvLetterHeaderCZZ.UpdateStatus(PurchAdvLetterHeaderCZZ.Status::"To Use"); + PurchAdvLetterPostCZZ.PostAdvancePaymentUsageVATCancellation(PurchAdvLetterEntryCZZ, GenJnlPostLine, AdvancePostingParametersCZZ); end; procedure PostAdvancePaymentUsagePreview(var PurchaseHeader: Record "Purchase Header"; Amount: Decimal; AmountLCY: Decimal; var PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ") @@ -1190,7 +1099,7 @@ codeunit 31019 "PurchAdvLetterManagement CZZ" repeat VATPostingSetup.Get(TempAdvancePostingBufferCZZ2."VAT Bus. Posting Group", TempAdvancePostingBufferCZZ2."VAT Prod. Posting Group"); PostUnrealizedExchangeRate(PurchAdvLetterEntryCZZ, PurchAdvLetterHeaderCZZ, VATPostingSetup, TempAdvancePostingBufferCZZ2.Amount, TempAdvancePostingBufferCZZ2."VAT Amount", - PurchAdvLetterEntryCZZ."Entry No.", DetEntryNo, DocumentNo, ToDate, ToDate, PostDescription, GenJnlPostLine, false, false); + PurchAdvLetterEntryCZZ."Entry No.", DetEntryNo, DocumentNo, ToDate, ToDate, PostDescription, GenJnlPostLine, false, false, TempAdvancePostingBufferCZZ2."Auxiliary Entry"); until TempAdvancePostingBufferCZZ2.Next() = 0; PurchAdvLetterPostCZZ.BufferAdvanceVATLines(PurchAdvLetterEntryCZZ, TempAdvancePostingBufferCZZ1, 0D); @@ -1246,7 +1155,8 @@ codeunit 31019 "PurchAdvLetterManagement CZZ" VATPostingSetup.Get(PurchAdvLetterEntryCZZ3."VAT Bus. Posting Group", PurchAdvLetterEntryCZZ3."VAT Prod. Posting Group"); PostUnrealizedExchangeRate(PurchAdvLetterEntryCZZ, PurchAdvLetterHeaderCZZ, VATPostingSetup, -AmountToPost, -VATAmountToPost, - PurchAdvLetterEntryCZZ2."Entry No.", 0, DocumentNo, PurchAdvLetterEntryCZZ3."Posting Date", PurchAdvLetterEntryCZZ3."VAT Date", PostDescription, GenJnlPostLine, false, false); + PurchAdvLetterEntryCZZ2."Entry No.", 0, DocumentNo, PurchAdvLetterEntryCZZ3."Posting Date", PurchAdvLetterEntryCZZ3."VAT Date", + PostDescription, GenJnlPostLine, false, false, PurchAdvLetterEntryCZZ3."Auxiliary Entry"); until PurchAdvLetterEntryCZZ3.Next() = 0; until PurchAdvLetterEntryCZZ2.Next() = 0; end; @@ -1255,7 +1165,7 @@ codeunit 31019 "PurchAdvLetterManagement CZZ" local procedure PostUnrealizedExchangeRate(var PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; var PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; var VATPostingSetup: Record "VAT Posting Setup"; Amount: Decimal; VATAmount: Decimal; RelatedEntryNo: Integer; RelatedDetEntryNo: Integer; DocumentNo: Code[20]; PostingDate: Date; VATDate: Date; PostDescription: Text[100]; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; - Correction: Boolean; Preview: Boolean) + Correction: Boolean; Preview: Boolean; AuxiliaryEntry: Boolean) var AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; begin @@ -1267,21 +1177,23 @@ codeunit 31019 "PurchAdvLetterManagement CZZ" AdvancePostingParametersCZZ."Temporary Entries Only" := Preview; PurchAdvLetterPostCZZ.PostUnrealizedExchangeRate( - PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, VATPostingSetup, Amount, VATAmount, RelatedEntryNo, RelatedDetEntryNo, Correction, GenJnlPostLine, AdvancePostingParametersCZZ); + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, VATPostingSetup, Amount, VATAmount, + RelatedEntryNo, RelatedDetEntryNo, Correction, AuxiliaryEntry, GenJnlPostLine, AdvancePostingParametersCZZ); end; - local procedure GetPostingDateUI(DefaultPostingDate: Date): Date + local procedure GetPostingDateUI(var PostingDate: Date): Boolean var GetPostingDateCZZ: Page "Get Posting Date CZZ"; - PostingDate: Date; begin if not GuiAllowed() then - exit(DefaultPostingDate); + exit(true); + + GetPostingDateCZZ.SetValues(PostingDate); + if GetPostingDateCZZ.RunModal() <> Action::OK then + exit(false); - GetPostingDateCZZ.SetValues(DefaultPostingDate); - if GetPostingDateCZZ.RunModal() = Action::OK then - GetPostingDateCZZ.GetValues(PostingDate); - exit(PostingDate); + GetPostingDateCZZ.GetValues(PostingDate); + exit(true); end; #if not CLEAN24 #pragma warning disable AL0432 diff --git a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/PurchAdvLetterPostCZZ.Codeunit.al b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/PurchAdvLetterPostCZZ.Codeunit.al index 102b7f2939..d6ee9a42a3 100644 --- a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/PurchAdvLetterPostCZZ.Codeunit.al +++ b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/PurchAdvLetterPostCZZ.Codeunit.al @@ -262,7 +262,7 @@ codeunit 31142 "Purch. Adv. Letter-Post CZZ" PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; VATPostingSetup: Record "VAT Posting Setup"; VendorLedgerEntry: Record "Vendor Ledger Entry"; - GLEntryNo: Integer; + GLEntryNo, VATEntryNo : Integer; IsHandled: Boolean; begin IsHandled := false; @@ -305,55 +305,60 @@ codeunit 31142 "Purch. Adv. Letter-Post CZZ" AdvancePostingParametersCZZ."Source Code" := VendorLedgerEntry."Source Code"; end; - AdvancePostingBufferCZZ.FindSet(); - repeat - VATPostingSetup.Get(AdvancePostingBufferCZZ."VAT Bus. Posting Group", AdvancePostingBufferCZZ."VAT Prod. Posting Group"); - - // Post VAT amount and VAT base of VAT document - InitGenJournalLine(PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, AdvancePostingParametersCZZ, GenJournalLine); - GenJournalLine."Account No." := VATPostingSetup.GetPurchAdvLetterAccountCZZ(); - GenJournalLine."Gen. Posting Type" := GenJournalLine."Gen. Posting Type"::Purchase; - GenJournalLine.CopyFromAdvancePostingBufferCZZ(AdvancePostingBufferCZZ); - if not AdvancePostingParametersCZZ."Temporary Entries Only" then begin - OnPostAdvancePaymentVATOnBeforePost( - PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, AdvancePostingBufferCZZ, - AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); + if AdvancePostingBufferCZZ.FindSet() then + repeat + GLEntryNo := 0; + VATEntryNo := 0; + + VATPostingSetup.Get(AdvancePostingBufferCZZ."VAT Bus. Posting Group", AdvancePostingBufferCZZ."VAT Prod. Posting Group"); + + // Post VAT amount and VAT base of VAT document + InitGenJournalLine(PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, AdvancePostingParametersCZZ, GenJournalLine); + GenJournalLine."Account No." := VATPostingSetup.GetPurchAdvLetterAccountCZZ(); + GenJournalLine."Gen. Posting Type" := GenJournalLine."Gen. Posting Type"::Purchase; + GenJournalLine.CopyFromAdvancePostingBufferCZZ(AdvancePostingBufferCZZ); + if not AdvancePostingParametersCZZ."Temporary Entries Only" and not AdvancePostingBufferCZZ."Auxiliary Entry" then begin + OnPostAdvancePaymentVATOnBeforePost( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, AdvancePostingBufferCZZ, + AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); #if not CLEAN24 - RaiseOnPostAdvancePaymentVATOnBeforeGenJnlPostLine( - PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, GenJournalLine); + RaiseOnPostAdvancePaymentVATOnBeforeGenJnlPostLine( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, GenJournalLine); #endif - GLEntryNo := RunGenJnlPostLine(GenJournalLine, GenJnlPostLine, true, true, false); - OnPostAdvancePaymentVATOnAfterPost( - PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, AdvancePostingBufferCZZ, - AdvancePostingParametersCZZ, GLEntryNo, GenJnlPostLine, GenJournalLine); - end; - - TempPurchAdvLetterEntryCZZGlob.InitNewEntry(); - TempPurchAdvLetterEntryCZZGlob.InitRelatedEntry(PurchAdvLetterEntryCZZ); - TempPurchAdvLetterEntryCZZGlob.CopyFromGenJnlLine(GenJournalLine); - TempPurchAdvLetterEntryCZZGlob."Entry Type" := "Advance Letter Entry Type CZZ"::"VAT Payment"; - TempPurchAdvLetterEntryCZZGlob."Purch. Adv. Letter No." := PurchAdvLetterHeaderCZZ."No."; - TempPurchAdvLetterEntryCZZGlob."VAT Entry No." := GenJnlPostLine.GetNextVATEntryNo() - 1; - TempPurchAdvLetterEntryCZZGlob."VAT Identifier" := VATPostingSetup."VAT Identifier"; - TempPurchAdvLetterEntryCZZGlob.InsertNewEntry(not AdvancePostingParametersCZZ."Temporary Entries Only"); + GLEntryNo := RunGenJnlPostLine(GenJournalLine, GenJnlPostLine, true, true, false); + VATEntryNo := GenJnlPostLine.GetNextVATEntryNo() - 1; + OnPostAdvancePaymentVATOnAfterPost( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, AdvancePostingBufferCZZ, + AdvancePostingParametersCZZ, GLEntryNo, GenJnlPostLine, GenJournalLine); + end; - // Post balance of VAT document - AdvancePostingParametersCZZ2.InitNew(AdvancePostingParametersCZZ); - AdvancePostingParametersCZZ2."Document Type" := "Gen. Journal Document Type"::" "; - InitGenJournalLine(PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, AdvancePostingParametersCZZ2, GenJournalLine); - GenJournalLine."Account No." := VATPostingSetup.GetPurchAdvLetterAccountCZZ(); - AdvancePostingBufferCZZ.ReverseAmounts(); - GenJournalLine.CopyFromAdvancePostingBufferAmountsCZZ(AdvancePostingBufferCZZ); - if not AdvancePostingParametersCZZ."Temporary Entries Only" then begin - OnPostAdvancePaymentVATOnBeforePostBalance( - PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, AdvancePostingBufferCZZ, - AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); - GLEntryNo := RunGenJnlPostLine(GenJournalLine, GenJnlPostLine, false, false, false); - OnPostAdvancePaymentVATOnAfterPostBalance( - PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, AdvancePostingBufferCZZ, - AdvancePostingParametersCZZ, GLEntryNo, GenJnlPostLine, GenJournalLine); - end; - until AdvancePostingBufferCZZ.Next() = 0; + TempPurchAdvLetterEntryCZZGlob.InitNewEntry(); + TempPurchAdvLetterEntryCZZGlob.InitRelatedEntry(PurchAdvLetterEntryCZZ); + TempPurchAdvLetterEntryCZZGlob.CopyFromGenJnlLine(GenJournalLine); + TempPurchAdvLetterEntryCZZGlob."Entry Type" := "Advance Letter Entry Type CZZ"::"VAT Payment"; + TempPurchAdvLetterEntryCZZGlob."Purch. Adv. Letter No." := PurchAdvLetterHeaderCZZ."No."; + TempPurchAdvLetterEntryCZZGlob."VAT Entry No." := VATEntryNo; + TempPurchAdvLetterEntryCZZGlob."VAT Identifier" := VATPostingSetup."VAT Identifier"; + TempPurchAdvLetterEntryCZZGlob."Auxiliary Entry" := AdvancePostingBufferCZZ."Auxiliary Entry"; + TempPurchAdvLetterEntryCZZGlob.InsertNewEntry(not AdvancePostingParametersCZZ."Temporary Entries Only"); + + // Post balance of VAT document + AdvancePostingParametersCZZ2.InitNew(AdvancePostingParametersCZZ); + AdvancePostingParametersCZZ2."Document Type" := "Gen. Journal Document Type"::" "; + InitGenJournalLine(PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, AdvancePostingParametersCZZ2, GenJournalLine); + GenJournalLine."Account No." := VATPostingSetup.GetPurchAdvLetterAccountCZZ(); + AdvancePostingBufferCZZ.ReverseAmounts(); + GenJournalLine.CopyFromAdvancePostingBufferAmountsCZZ(AdvancePostingBufferCZZ); + if not AdvancePostingParametersCZZ."Temporary Entries Only" and not AdvancePostingBufferCZZ."Auxiliary Entry" then begin + OnPostAdvancePaymentVATOnBeforePostBalance( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, AdvancePostingBufferCZZ, + AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); + GLEntryNo := RunGenJnlPostLine(GenJournalLine, GenJnlPostLine, false, false, false); + OnPostAdvancePaymentVATOnAfterPostBalance( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, AdvancePostingBufferCZZ, + AdvancePostingParametersCZZ, GLEntryNo, GenJnlPostLine, GenJournalLine); + end; + until AdvancePostingBufferCZZ.Next() = 0; OnAfterPostAdvancePaymentVAT( PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, AdvancePostingBufferCZZ, @@ -370,7 +375,7 @@ codeunit 31142 "Purch. Adv. Letter-Post CZZ" AdvancePostingParametersCZZ2: Record "Advance Posting Parameters CZZ"; VATPostingSetup: Record "VAT Posting Setup"; GenJournalLine: Record "Gen. Journal Line"; - EntryNo, GLEntryNo : Integer; + EntryNo, GLEntryNo, VATEntryNo : Integer; IsHandled: Boolean; begin IsHandled := false; @@ -385,17 +390,21 @@ codeunit 31142 "Purch. Adv. Letter-Post CZZ" VATPostingSetup.Get(AdvancePostingBufferCZZ."VAT Bus. Posting Group", AdvancePostingBufferCZZ."VAT Prod. Posting Group"); + GLEntryNo := 0; + VATEntryNo := 0; + // Post advance payment VAT unlinking InitGenJournalLine(PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, AdvancePostingParametersCZZ, GenJournalLine); GenJournalLine."Account No." := VATPostingSetup.GetPurchAdvLetterAccountCZZ(); GenJournalLine."Gen. Posting Type" := GenJournalLine."Gen. Posting Type"::Purchase; AdvancePostingBufferCZZ.ReverseAmounts(); GenJournalLine.CopyFromAdvancePostingBufferCZZ(AdvancePostingBufferCZZ); - if not AdvancePostingParametersCZZ."Temporary Entries Only" then begin + if not AdvancePostingParametersCZZ."Temporary Entries Only" and not AdvancePostingBufferCZZ."Auxiliary Entry" then begin OnPostAdvancePaymentVATUnlinkingOnBeforePost( PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, VATPostingSetup, AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); GLEntryNo := RunGenJnlPostLine(GenJournalLine, GenJnlPostLine, true, true, false); + VATEntryNo := GenJnlPostLine.GetNextVATEntryNo() - 1; OnPostAdvancePaymentVATUnlinkingOnAfterPost( PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, VATPostingSetup, AdvancePostingParametersCZZ, GLEntryNo, GenJnlPostLine, GenJournalLine); @@ -406,8 +415,9 @@ codeunit 31142 "Purch. Adv. Letter-Post CZZ" TempPurchAdvLetterEntryCZZGlob.CopyFromGenJnlLine(GenJournalLine); TempPurchAdvLetterEntryCZZGlob."Entry Type" := "Advance Letter Entry Type CZZ"::"VAT Payment"; TempPurchAdvLetterEntryCZZGlob."Purch. Adv. Letter No." := PurchAdvLetterHeaderCZZ."No."; - TempPurchAdvLetterEntryCZZGlob."VAT Entry No." := GenJnlPostLine.GetNextVATEntryNo() - 1; + TempPurchAdvLetterEntryCZZGlob."VAT Entry No." := VATEntryNo; TempPurchAdvLetterEntryCZZGlob."VAT Identifier" := VATPostingSetup."VAT Identifier"; + TempPurchAdvLetterEntryCZZGlob."Auxiliary Entry" := AdvancePostingBufferCZZ."Auxiliary Entry"; TempPurchAdvLetterEntryCZZGlob.Cancelled := true; EntryNo := TempPurchAdvLetterEntryCZZGlob.InsertNewEntry(not AdvancePostingParametersCZZ."Temporary Entries Only"); @@ -418,7 +428,7 @@ codeunit 31142 "Purch. Adv. Letter-Post CZZ" InitGenJournalLine(PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, AdvancePostingParametersCZZ2, GenJournalLine); GenJournalLine."Account No." := VATPostingSetup.GetPurchAdvLetterAccountCZZ(); GenJournalLine.CopyFromAdvancePostingBufferAmountsCZZ(AdvancePostingBufferCZZ); - if not AdvancePostingParametersCZZ."Temporary Entries Only" then begin + if not AdvancePostingParametersCZZ."Temporary Entries Only" and not AdvancePostingBufferCZZ."Auxiliary Entry" then begin OnPostAdvancePaymentVATUnlinkingOnBeforePostBalance( PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, AdvancePostingBufferCZZ, AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); @@ -577,7 +587,7 @@ codeunit 31142 "Purch. Adv. Letter-Post CZZ" var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ") var - PurchAdvLetterEntryCZZ2: Record "Purch. Adv. Letter Entry CZZ"; + RelatedPurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; IsHandled: Boolean; begin IsHandled := false; @@ -590,18 +600,130 @@ codeunit 31142 "Purch. Adv. Letter-Post CZZ" exit; PurchAdvLetterEntryCZZ.TestField(Cancelled, false); - PurchAdvLetterEntryCZZ2.Get(PurchAdvLetterEntryCZZ."Related Entry"); - if PurchAdvLetterEntryCZZ2."Entry Type" <> PurchAdvLetterEntryCZZ2."Entry Type"::Payment then + RelatedPurchAdvLetterEntryCZZ.Get(PurchAdvLetterEntryCZZ."Related Entry"); + if RelatedPurchAdvLetterEntryCZZ."Entry Type" <> RelatedPurchAdvLetterEntryCZZ."Entry Type"::Payment then exit; ReverseAdvancePaymentVAT( - PurchAdvLetterEntryCZZ2, AdvancePostingBufferCZZ, PurchAdvLetterEntryCZZ."Entry No.", + RelatedPurchAdvLetterEntryCZZ, AdvancePostingBufferCZZ, PurchAdvLetterEntryCZZ."Entry No.", "Advance Letter Entry Type CZZ"::"VAT Usage", GenJnlPostLine, AdvancePostingParametersCZZ); OnAfterPostAdvancePaymentUsageVAT( PurchAdvLetterEntryCZZ, AdvancePostingBufferCZZ, GenJnlPostLine, AdvancePostingParametersCZZ); end; + procedure PostAdvancePaymentUsageVATCancellation( + var PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; + var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; + AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ") + var + AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; + AdvancePostingParametersCZZ2: Record "Advance Posting Parameters CZZ"; + PurchAdvLetterEntryCZZ2: Record "Purch. Adv. Letter Entry CZZ"; + PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; + VATPostingSetup: Record "VAT Posting Setup"; + GenJournalLine: Record "Gen. Journal Line"; + GLEntryNo, VATEntryNo : Integer; + IsHandled: Boolean; + begin + IsHandled := false; + OnBeforePostAdvancePaymentUsageVATCancellation( + PurchAdvLetterEntryCZZ, GenJnlPostLine, AdvancePostingParametersCZZ, IsHandled); + if IsHandled then + exit; + + PurchAdvLetterEntryCZZ.TestField("Entry Type", PurchAdvLetterEntryCZZ."Entry Type"::"VAT Usage"); + PurchAdvLetterEntryCZZ.TestField(Cancelled, false); + + PurchAdvLetterHeaderCZZ.Get(PurchAdvLetterEntryCZZ."Purch. Adv. Letter No."); + + PurchAdvLetterEntryCZZ2.Reset(); + PurchAdvLetterEntryCZZ2.SetRange("Document No.", PurchAdvLetterEntryCZZ."Document No."); + PurchAdvLetterEntryCZZ2.SetFilter("Entry Type", '%1|%2|%3', + PurchAdvLetterEntryCZZ2."Entry Type"::"VAT Adjustment", + PurchAdvLetterEntryCZZ2."Entry Type"::"VAT Rate", + PurchAdvLetterEntryCZZ2."Entry Type"::"VAT Usage"); + PurchAdvLetterEntryCZZ2.SetRange(Cancelled, false); + PurchAdvLetterEntryCZZ2.Find('+'); + PurchAdvLetterEntryCZZ2.SetFilter("Entry No.", '..%1', PurchAdvLetterEntryCZZ2."Entry No."); + VATPostingSetup.Get(PurchAdvLetterEntryCZZ2."VAT Bus. Posting Group", PurchAdvLetterEntryCZZ2."VAT Prod. Posting Group"); + repeat + case PurchAdvLetterEntryCZZ2."Entry Type" of + PurchAdvLetterEntryCZZ2."Entry Type"::"VAT Adjustment": + PostUnrealizedExchangeRate(PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ2, VATPostingSetup, + -PurchAdvLetterEntryCZZ2."Amount (LCY)", -PurchAdvLetterEntryCZZ2."VAT Amount (LCY)", + PurchAdvLetterEntryCZZ2."Related Entry", 0, true, PurchAdvLetterEntryCZZ2."Auxiliary Entry", + GenJnlPostLine, AdvancePostingParametersCZZ); + PurchAdvLetterEntryCZZ2."Entry Type"::"VAT Rate": + PostExchangeRate(PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ2, VATPostingSetup, + -PurchAdvLetterEntryCZZ2."Amount (LCY)", -PurchAdvLetterEntryCZZ2."VAT Amount (LCY)", + PurchAdvLetterEntryCZZ2."Related Entry", true, PurchAdvLetterEntryCZZ2."Auxiliary Entry", + GenJnlPostLine, AdvancePostingParametersCZZ); + PurchAdvLetterEntryCZZ2."Entry Type"::"VAT Usage": + begin + AdvancePostingParametersCZZ2.InitNew(AdvancePostingParametersCZZ); + AdvancePostingParametersCZZ2."Currency Code" := PurchAdvLetterEntryCZZ2."Currency Code"; + AdvancePostingParametersCZZ2."Currency Factor" := PurchAdvLetterEntryCZZ2."Currency Factor"; + + AdvancePostingBufferCZZ.PrepareForPurchAdvLetterEntry(PurchAdvLetterEntryCZZ2); + + // Post advance payment VAT cancellation + InitGenJournalLine(PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ2, AdvancePostingParametersCZZ2, GenJournalLine); + GenJournalLine."Account No." := VATPostingSetup.GetPurchAdvLetterAccountCZZ(); + GenJournalLine."Gen. Posting Type" := GenJournalLine."Gen. Posting Type"::Purchase; + GenJournalLine.Correction := true; + AdvancePostingBufferCZZ.ReverseAmounts(); + GenJournalLine.CopyFromAdvancePostingBufferCZZ(AdvancePostingBufferCZZ); + if not AdvancePostingParametersCZZ2."Temporary Entries Only" and not AdvancePostingBufferCZZ."Auxiliary Entry" then begin + OnPostAdvancePaymentUsageVATCancellationOnBeforePost( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ2, AdvancePostingBufferCZZ, + AdvancePostingParametersCZZ2, GenJnlPostLine, GenJournalLine); + GLEntryNo := RunGenJnlPostLine(GenJournalLine, GenJnlPostLine, true, false, false); + VATEntryNo := GenJnlPostLine.GetNextVATEntryNo() - 1; + OnPostAdvancePaymentUsageVATCancellationOnAfterPost( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ2, AdvancePostingBufferCZZ, + AdvancePostingParametersCZZ2, GLEntryNo, GenJnlPostLine, GenJournalLine); + end; + + TempPurchAdvLetterEntryCZZGlob.InitNewEntry(); + TempPurchAdvLetterEntryCZZGlob.InitRelatedEntry(PurchAdvLetterEntryCZZ2."Related Entry"); + TempPurchAdvLetterEntryCZZGlob.CopyFromGenJnlLine(GenJournalLine); + TempPurchAdvLetterEntryCZZGlob."Entry Type" := "Advance Letter Entry Type CZZ"::"VAT Usage"; + TempPurchAdvLetterEntryCZZGlob."Purch. Adv. Letter No." := PurchAdvLetterHeaderCZZ."No."; + TempPurchAdvLetterEntryCZZGlob."VAT Entry No." := VATEntryNo; + TempPurchAdvLetterEntryCZZGlob."VAT Identifier" := VATPostingSetup."VAT Identifier"; + TempPurchAdvLetterEntryCZZGlob."Auxiliary Entry" := PurchAdvLetterEntryCZZ2."Auxiliary Entry"; + TempPurchAdvLetterEntryCZZGlob.Cancelled := true; + TempPurchAdvLetterEntryCZZGlob.InsertNewEntry(true); + + // Post balance of advance payment VAT cancellation + AdvancePostingBufferCZZ.ReverseAmounts(); + InitGenJournalLine(PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, AdvancePostingParametersCZZ2, GenJournalLine); + GenJournalLine."Account No." := VATPostingSetup.GetPurchAdvLetterAccountCZZ(); + GenJournalLine.Correction := true; + GenJournalLine.CopyFromAdvancePostingBufferAmountsCZZ(AdvancePostingBufferCZZ); + if not AdvancePostingParametersCZZ2."Temporary Entries Only" and not AdvancePostingBufferCZZ."Auxiliary Entry" then begin + OnPostAdvancePaymentUsageVATCancellationOnBeforePostBalance( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ2, AdvancePostingBufferCZZ, + AdvancePostingParametersCZZ2, GenJnlPostLine, GenJournalLine); + GLEntryNo := RunGenJnlPostLine(GenJournalLine, GenJnlPostLine, false, false, false); + OnPostAdvancePaymentUsageVATCancellationOnAfterPostBalance( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ2, AdvancePostingBufferCZZ, + AdvancePostingParametersCZZ2, GLEntryNo, GenJnlPostLine, GenJournalLine); + end; + end; + end; + until PurchAdvLetterEntryCZZ2.Next(-1) = 0; + + if not AdvancePostingParametersCZZ."Temporary Entries Only" then begin + PurchAdvLetterEntryCZZ2.ModifyAll(Cancelled, true); + PurchAdvLetterHeaderCZZ.UpdateStatus(PurchAdvLetterHeaderCZZ.Status::"To Use"); + end; + + OnAfterPostAdvancePaymentUsageVATCancellation( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, GenJnlPostLine, AdvancePostingParametersCZZ); + end; + procedure PostAdvanceCreditMemoVAT( var PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; @@ -610,13 +732,13 @@ codeunit 31142 "Purch. Adv. Letter-Post CZZ" var AdvancePostingParametersCZZ2: Record "Advance Posting Parameters CZZ"; GenJournalLine: Record "Gen. Journal Line"; - PurchAdvLetterEntryCZZ2: Record "Purch. Adv. Letter Entry CZZ"; - PurchAdvLetterEntryCZZ3: Record "Purch. Adv. Letter Entry CZZ"; + RelatedPurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; + VATDocumentPurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; TempAdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ" temporary; VATPostingSetup: Record "VAT Posting Setup"; ExchRateAmount, ExchRateVATAmount : Decimal; - GLEntryNo: Integer; + GLEntryNo, VATEntryNo : Integer; IsHandled: Boolean; begin IsHandled := false; @@ -635,12 +757,15 @@ codeunit 31142 "Purch. Adv. Letter-Post CZZ" Error(NothingToPostErr); if PurchAdvLetterEntryCZZ."Currency Code" <> '' then begin - PurchAdvLetterEntryCZZ2.Get(PurchAdvLetterEntryCZZ."Related Entry"); - BufferAdvanceVATLines(PurchAdvLetterEntryCZZ2, TempAdvancePostingBufferCZZ, 0D); + RelatedPurchAdvLetterEntryCZZ.Get(PurchAdvLetterEntryCZZ."Related Entry"); + BufferAdvanceVATLines(RelatedPurchAdvLetterEntryCZZ, TempAdvancePostingBufferCZZ, 0D); end; AdvancePostingBufferCZZ.FindSet(); repeat + GLEntryNo := 0; + VATEntryNo := 0; + VATPostingSetup.Get(AdvancePostingBufferCZZ."VAT Bus. Posting Group", AdvancePostingBufferCZZ."VAT Prod. Posting Group"); // Post credit memo VAT @@ -649,11 +774,12 @@ codeunit 31142 "Purch. Adv. Letter-Post CZZ" GenJournalLine."Gen. Posting Type" := GenJournalLine."Gen. Posting Type"::Purchase; AdvancePostingBufferCZZ.ReverseAmounts(); GenJournalLine.CopyFromAdvancePostingBufferCZZ(AdvancePostingBufferCZZ); - if not AdvancePostingParametersCZZ."Temporary Entries Only" then begin + if not AdvancePostingParametersCZZ."Temporary Entries Only" and not AdvancePostingBufferCZZ."Auxiliary Entry" then begin OnPostAdvanceCreditMemoVATOnBeforePost( PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, AdvancePostingBufferCZZ, AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); GLEntryNo := RunGenJnlPostLine(GenJournalLine, GenJnlPostLine, true, true, false); + VATEntryNo := GenJnlPostLine.GetNextVATEntryNo() - 1; OnPostAdvanceCreditMemoVATOnAfterPost( PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, AdvancePostingBufferCZZ, AdvancePostingParametersCZZ, GLEntryNo, GenJnlPostLine, GenJournalLine); @@ -664,8 +790,9 @@ codeunit 31142 "Purch. Adv. Letter-Post CZZ" TempPurchAdvLetterEntryCZZGlob.CopyFromGenJnlLine(GenJournalLine); TempPurchAdvLetterEntryCZZGlob."Entry Type" := "Advance Letter Entry Type CZZ"::"VAT Payment"; TempPurchAdvLetterEntryCZZGlob."Purch. Adv. Letter No." := PurchAdvLetterHeaderCZZ."No."; - TempPurchAdvLetterEntryCZZGlob."VAT Entry No." := GenJnlPostLine.GetNextVATEntryNo() - 1; + TempPurchAdvLetterEntryCZZGlob."VAT Entry No." := VATEntryNo; TempPurchAdvLetterEntryCZZGlob."VAT Identifier" := VATPostingSetup."VAT Identifier"; + TempPurchAdvLetterEntryCZZGlob."Auxiliary Entry" := AdvancePostingBufferCZZ."Auxiliary Entry"; TempPurchAdvLetterEntryCZZGlob.Cancelled := true; TempPurchAdvLetterEntryCZZGlob.InsertNewEntry(not AdvancePostingParametersCZZ."Temporary Entries Only"); @@ -682,25 +809,27 @@ codeunit 31142 "Purch. Adv. Letter-Post CZZ" AdvancePostingParametersCZZ2."Currency Code" := ''; AdvancePostingParametersCZZ2."Currency Factor" := 0; - PurchAdvLetterEntryCZZ3.Reset(); - PurchAdvLetterEntryCZZ3.SetRange("Purch. Adv. Letter No.", PurchAdvLetterEntryCZZ."Purch. Adv. Letter No."); - PurchAdvLetterEntryCZZ3.SetRange("Document No.", PurchAdvLetterEntryCZZ."Document No."); - PurchAdvLetterEntryCZZ3.SetRange("Entry Type", "Advance Letter Entry Type CZZ"::"VAT Payment"); - PurchAdvLetterEntryCZZ3.SetRange("VAT Bus. Posting Group", AdvancePostingBufferCZZ."VAT Bus. Posting Group"); - PurchAdvLetterEntryCZZ3.SetRange("VAT Prod. Posting Group", AdvancePostingBufferCZZ."VAT Prod. Posting Group"); - PurchAdvLetterEntryCZZ3.SetRange(Cancelled, false); - PurchAdvLetterEntryCZZ3.CalcSums("Amount (LCY)", "VAT Amount (LCY)"); - - ExchRateAmount := PurchAdvLetterEntryCZZ3."Amount (LCY)" + GenJournalLine."Amount (LCY)"; - ExchRateVATAmount := PurchAdvLetterEntryCZZ3."VAT Amount (LCY)" + GenJournalLine."VAT Amount (LCY)"; + VATDocumentPurchAdvLetterEntryCZZ.Reset(); + VATDocumentPurchAdvLetterEntryCZZ.SetRange("Purch. Adv. Letter No.", PurchAdvLetterEntryCZZ."Purch. Adv. Letter No."); + VATDocumentPurchAdvLetterEntryCZZ.SetRange("Document No.", PurchAdvLetterEntryCZZ."Document No."); + VATDocumentPurchAdvLetterEntryCZZ.SetRange("Entry Type", "Advance Letter Entry Type CZZ"::"VAT Payment"); + VATDocumentPurchAdvLetterEntryCZZ.SetRange("VAT Bus. Posting Group", AdvancePostingBufferCZZ."VAT Bus. Posting Group"); + VATDocumentPurchAdvLetterEntryCZZ.SetRange("VAT Prod. Posting Group", AdvancePostingBufferCZZ."VAT Prod. Posting Group"); + VATDocumentPurchAdvLetterEntryCZZ.SetRange(Cancelled, false); + VATDocumentPurchAdvLetterEntryCZZ.CalcSums("Amount (LCY)", "VAT Amount (LCY)"); + + ExchRateAmount := VATDocumentPurchAdvLetterEntryCZZ."Amount (LCY)" + GenJournalLine."Amount (LCY)"; + ExchRateVATAmount := VATDocumentPurchAdvLetterEntryCZZ."VAT Amount (LCY)" + GenJournalLine."VAT Amount (LCY)"; if (ExchRateAmount <> 0) or (ExchRateVATAmount <> 0) then - PostExchangeRate(PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, VATPostingSetup, -ExchRateAmount, -ExchRateVATAmount, - PurchAdvLetterEntryCZZ."Related Entry", true, GenJnlPostLine, AdvancePostingParametersCZZ2); + PostExchangeRate(PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, VATPostingSetup, + -ExchRateAmount, -ExchRateVATAmount, PurchAdvLetterEntryCZZ."Related Entry", + true, AdvancePostingBufferCZZ."Auxiliary Entry", GenJnlPostLine, AdvancePostingParametersCZZ2); ReverseUnrealizedExchangeRate( - PurchAdvLetterEntryCZZ2, PurchAdvLetterHeaderCZZ, VATPostingSetup, + RelatedPurchAdvLetterEntryCZZ, PurchAdvLetterHeaderCZZ, VATPostingSetup, AdvancePostingBufferCZZ.Amount / TempAdvancePostingBufferCZZ.Amount, - PurchAdvLetterEntryCZZ2."Entry No.", GenJnlPostLine, AdvancePostingParametersCZZ2); + RelatedPurchAdvLetterEntryCZZ."Entry No.", AdvancePostingBufferCZZ."Auxiliary Entry", + GenJnlPostLine, AdvancePostingParametersCZZ2); end; // Post balance of credit memo VAT @@ -709,7 +838,7 @@ codeunit 31142 "Purch. Adv. Letter-Post CZZ" InitGenJournalLine(PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, AdvancePostingParametersCZZ2, GenJournalLine); GenJournalLine."Account No." := VATPostingSetup.GetPurchAdvLetterAccountCZZ(); GenJournalLine.CopyFromAdvancePostingBufferAmountsCZZ(AdvancePostingBufferCZZ); - if not AdvancePostingParametersCZZ."Temporary Entries Only" then begin + if not AdvancePostingParametersCZZ."Temporary Entries Only" and not AdvancePostingBufferCZZ."Auxiliary Entry" then begin OnPostAdvanceCreditMemoVATOnBeforePostBalance( PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, AdvancePostingBufferCZZ, AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); @@ -721,12 +850,12 @@ codeunit 31142 "Purch. Adv. Letter-Post CZZ" until AdvancePostingBufferCZZ.Next() = 0; if not AdvancePostingParametersCZZ."Temporary Entries Only" then begin - PurchAdvLetterEntryCZZ3.Reset(); - PurchAdvLetterEntryCZZ3.SetRange("Purch. Adv. Letter No.", PurchAdvLetterEntryCZZ."Purch. Adv. Letter No."); - PurchAdvLetterEntryCZZ3.SetRange("Document No.", PurchAdvLetterEntryCZZ."Document No."); - PurchAdvLetterEntryCZZ3.SetRange("Entry Type", "Advance Letter Entry Type CZZ"::"VAT Payment"); - PurchAdvLetterEntryCZZ3.SetRange(Cancelled, false); - PurchAdvLetterEntryCZZ3.ModifyAll(Cancelled, true); + VATDocumentPurchAdvLetterEntryCZZ.Reset(); + VATDocumentPurchAdvLetterEntryCZZ.SetRange("Purch. Adv. Letter No.", PurchAdvLetterEntryCZZ."Purch. Adv. Letter No."); + VATDocumentPurchAdvLetterEntryCZZ.SetRange("Document No.", PurchAdvLetterEntryCZZ."Document No."); + VATDocumentPurchAdvLetterEntryCZZ.SetRange("Entry Type", "Advance Letter Entry Type CZZ"::"VAT Payment"); + VATDocumentPurchAdvLetterEntryCZZ.SetRange(Cancelled, false); + VATDocumentPurchAdvLetterEntryCZZ.ModifyAll(Cancelled, true); end; OnAfterPostAdvanceCreditMemoVAT( @@ -798,7 +927,8 @@ codeunit 31142 "Purch. Adv. Letter-Post CZZ" VATPostingSetup.Get(PurchAdvLetterEntryCZZ."VAT Bus. Posting Group", PurchAdvLetterEntryCZZ."VAT Prod. Posting Group"); PostUnrealizedExchangeRate(PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, VATPostingSetup, -PurchAdvLetterEntryCZZ."Amount (LCY)", -PurchAdvLetterEntryCZZ."VAT Amount (LCY)", - PurchAdvLetterEntryCZZ."Related Entry", 0, true, GenJnlPostLine, AdvancePostingParametersCZZ2); + PurchAdvLetterEntryCZZ."Related Entry", 0, true, PurchAdvLetterEntryCZZ."Auxiliary Entry", + GenJnlPostLine, AdvancePostingParametersCZZ2); end; PurchAdvLetterEntryCZZ."Entry Type"::"VAT Rate": begin @@ -807,7 +937,8 @@ codeunit 31142 "Purch. Adv. Letter-Post CZZ" VATPostingSetup.Get(PurchAdvLetterEntryCZZ."VAT Bus. Posting Group", PurchAdvLetterEntryCZZ."VAT Prod. Posting Group"); PostExchangeRate(PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, VATPostingSetup, -PurchAdvLetterEntryCZZ."Amount (LCY)", -PurchAdvLetterEntryCZZ."VAT Amount (LCY)", - PurchAdvLetterEntryCZZ."Related Entry", true, GenJnlPostLine, AdvancePostingParametersCZZ2); + PurchAdvLetterEntryCZZ."Related Entry", true, PurchAdvLetterEntryCZZ."Auxiliary Entry", + GenJnlPostLine, AdvancePostingParametersCZZ2); end; PurchAdvLetterEntryCZZ."Entry Type"::"VAT Usage": begin @@ -852,8 +983,7 @@ codeunit 31142 "Purch. Adv. Letter-Post CZZ" GenJournalLine: Record "Gen. Journal Line"; VATPostingSetup: Record "VAT Posting Setup"; VATEntry: Record "VAT Entry"; - EntryNo: Integer; - GLEntryNo: Integer; + EntryNo, GLEntryNo, VATEntryNo : Integer; IsHandled: Boolean; begin IsHandled := false; @@ -862,6 +992,9 @@ codeunit 31142 "Purch. Adv. Letter-Post CZZ" if IsHandled then exit; + GLEntryNo := 0; + VATEntryNo := 0; + VATPostingSetup.Get(AdvancePostingBufferCZZ."VAT Bus. Posting Group", AdvancePostingBufferCZZ."VAT Prod. Posting Group"); InitGenJournalLine( @@ -875,15 +1008,15 @@ codeunit 31142 "Purch. Adv. Letter-Post CZZ" GenJournalLine."VAT Posting" := GenJournalLine."VAT Posting"::"Manual VAT Entry"; if (GenJournalLine."Currency Code" <> '') and (GenJournalLine."VAT Calculation Type" = GenJournalLine."VAT Calculation Type"::"Reverse Charge VAT") - then begin - VATEntry.Get(PurchAdvLetterEntryCZZ."VAT Entry No."); - GenJournalLine."VAT Amount (LCY)" := -VATEntry.Amount; - end; - if not AdvancePostingParametersCZZ."Temporary Entries Only" then begin + then + if VATEntry.Get(PurchAdvLetterEntryCZZ."VAT Entry No.") then + GenJournalLine."VAT Amount (LCY)" := -VATEntry.Amount; + if not AdvancePostingParametersCZZ."Temporary Entries Only" and not AdvancePostingBufferCZZ."Auxiliary Entry" then begin OnPostAdvanceLetterEntryVATUsageUnapplyingOnBeforePost( PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, AdvancePostingBufferCZZ, AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); GLEntryNo := RunGenJnlPostLine(GenJournalLine, GenJnlPostLine, true, true, false); + VATEntryNo := GenJnlPostLine.GetNextVATEntryNo() - 1; OnPostAdvanceLetterEntryVATUsageUnapplyingOnAfterPost( PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, AdvancePostingBufferCZZ, AdvancePostingParametersCZZ, GLEntryNo, GenJnlPostLine, GenJournalLine); @@ -894,8 +1027,9 @@ codeunit 31142 "Purch. Adv. Letter-Post CZZ" TempPurchAdvLetterEntryCZZGlob.CopyFromGenJnlLine(GenJournalLine); TempPurchAdvLetterEntryCZZGlob."Entry Type" := PurchAdvLetterEntryCZZ."Entry Type"; TempPurchAdvLetterEntryCZZGlob."Purch. Adv. Letter No." := PurchAdvLetterHeaderCZZ."No."; - TempPurchAdvLetterEntryCZZGlob."VAT Entry No." := GenJnlPostLine.GetNextVATEntryNo() - 1; + TempPurchAdvLetterEntryCZZGlob."VAT Entry No." := VATEntryNo; TempPurchAdvLetterEntryCZZGlob."VAT Identifier" := VATPostingSetup."VAT Identifier"; + TempPurchAdvLetterEntryCZZGlob."Auxiliary Entry" := AdvancePostingBufferCZZ."Auxiliary Entry"; TempPurchAdvLetterEntryCZZGlob.Cancelled := true; EntryNo := TempPurchAdvLetterEntryCZZGlob.InsertNewEntry(not AdvancePostingParametersCZZ."Temporary Entries Only"); @@ -907,7 +1041,7 @@ codeunit 31142 "Purch. Adv. Letter-Post CZZ" GenJournalLine."Account No." := VATPostingSetup.GetPurchAdvLetterAccountCZZ(); GenJournalLine.Correction := true; GenJournalLine.CopyFromAdvancePostingBufferAmountsCZZ(AdvancePostingBufferCZZ); - if not AdvancePostingParametersCZZ."Temporary Entries Only" then begin + if not AdvancePostingParametersCZZ."Temporary Entries Only" and not AdvancePostingBufferCZZ."Auxiliary Entry" then begin OnPostAdvanceLetterEntryVATUsageUnapplyingOnBeforePostBalance( PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, AdvancePostingBufferCZZ, AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); @@ -1323,13 +1457,13 @@ codeunit 31142 "Purch. Adv. Letter-Post CZZ" AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ") var AdvancePostingParametersCZZ2: Record "Advance Posting Parameters CZZ"; - PurchAdvLetterEntryCZZ2: Record "Purch. Adv. Letter Entry CZZ"; TempAdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ" temporary; GenJournalLine: Record "Gen. Journal Line"; + VATDocumentPurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; VATPostingSetup: Record "VAT Posting Setup"; PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; CalcVATAmountLCY, CalcAmountLCY, ExchRateAmount, ExchRateVATAmount, AmountToUse : Decimal; - GLEntryNo: Integer; + GLEntryNo, VATEntryNo : Integer; IsHandled: Boolean; begin IsHandled := false; @@ -1345,11 +1479,12 @@ codeunit 31142 "Purch. Adv. Letter-Post CZZ" if PurchAdvLetterEntryCZZ."Entry Type" <> PurchAdvLetterEntryCZZ."Entry Type"::Payment then exit; - PurchAdvLetterEntryCZZ2.SetRange("Purch. Adv. Letter No.", PurchAdvLetterEntryCZZ."Purch. Adv. Letter No."); - PurchAdvLetterEntryCZZ2.SetRange(Cancelled, false); - PurchAdvLetterEntryCZZ2.SetRange("Related Entry", PurchAdvLetterEntryCZZ."Entry No."); - PurchAdvLetterEntryCZZ2.SetRange("Entry Type", PurchAdvLetterEntryCZZ2."Entry Type"::"VAT Payment"); - if PurchAdvLetterEntryCZZ2.IsEmpty() then + VATDocumentPurchAdvLetterEntryCZZ.Reset(); + VATDocumentPurchAdvLetterEntryCZZ.SetRange("Purch. Adv. Letter No.", PurchAdvLetterEntryCZZ."Purch. Adv. Letter No."); + VATDocumentPurchAdvLetterEntryCZZ.SetRange(Cancelled, false); + VATDocumentPurchAdvLetterEntryCZZ.SetRange("Related Entry", PurchAdvLetterEntryCZZ."Entry No."); + VATDocumentPurchAdvLetterEntryCZZ.SetRange("Entry Type", VATDocumentPurchAdvLetterEntryCZZ."Entry Type"::"VAT Payment"); + if VATDocumentPurchAdvLetterEntryCZZ.IsEmpty() then exit; AdvancePostingBufferCZZ.FilterGroup(-1); @@ -1373,6 +1508,9 @@ codeunit 31142 "Purch. Adv. Letter-Post CZZ" AdvancePostingBufferCZZ.FindSet(); repeat + GLEntryNo := 0; + VATEntryNo := 0; + VATPostingSetup.Get(AdvancePostingBufferCZZ."VAT Bus. Posting Group", AdvancePostingBufferCZZ."VAT Prod. Posting Group"); // Post reverse advance payment VAT @@ -1383,11 +1521,12 @@ codeunit 31142 "Purch. Adv. Letter-Post CZZ" GenJournalLine.CopyFromAdvancePostingBufferCZZ(AdvancePostingBufferCZZ); if GenJournalLine."VAT Calculation Type" = GenJournalLine."VAT Calculation Type"::"Reverse Charge VAT" then GenJournalLine."VAT Posting" := GenJournalLine."VAT Posting"::"Manual VAT Entry"; - if not AdvancePostingParametersCZZ."Temporary Entries Only" then begin + if not AdvancePostingParametersCZZ."Temporary Entries Only" and not AdvancePostingBufferCZZ."Auxiliary Entry" then begin OnReverseAdvancePaymentVATOnBeforePost( PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, VATPostingSetup, AdvancePostingBufferCZZ, AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); GLEntryNo := RunGenJnlPostLine(GenJournalLine, GenJnlPostLine, true, true, false); + VATEntryNo := GenJnlPostLine.GetNextVATEntryNo() - 1; OnReverseAdvancePaymentVATOnAfterPost( PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, VATPostingSetup, AdvancePostingBufferCZZ, AdvancePostingParametersCZZ, GLEntryNo, GenJnlPostLine, GenJournalLine); @@ -1403,8 +1542,9 @@ codeunit 31142 "Purch. Adv. Letter-Post CZZ" TempPurchAdvLetterEntryCZZGlob.CopyFromGenJnlLine(GenJournalLine); TempPurchAdvLetterEntryCZZGlob."Entry Type" := EntryType; TempPurchAdvLetterEntryCZZGlob."Purch. Adv. Letter No." := PurchAdvLetterHeaderCZZ."No."; - TempPurchAdvLetterEntryCZZGlob."VAT Entry No." := GenJnlPostLine.GetNextVATEntryNo() - 1; + TempPurchAdvLetterEntryCZZGlob."VAT Entry No." := VATEntryNo; TempPurchAdvLetterEntryCZZGlob."VAT Identifier" := VATPostingSetup."VAT Identifier"; + TempPurchAdvLetterEntryCZZGlob."Auxiliary Entry" := AdvancePostingBufferCZZ."Auxiliary Entry"; TempPurchAdvLetterEntryCZZGlob.InsertNewEntry(not AdvancePostingParametersCZZ."Temporary Entries Only"); AdvancePostingBufferCZZ.ReverseAmounts(); @@ -1426,12 +1566,12 @@ codeunit 31142 "Purch. Adv. Letter-Post CZZ" ExchRateVATAmount := CalcVATAmountLCY + GenJournalLine."VAT Amount (LCY)"; if (ExchRateAmount <> 0) or (ExchRateVATAmount <> 0) then PostExchangeRate(PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, VATPostingSetup, -ExchRateAmount, -ExchRateVATAmount, - RelatedEntryNo, false, GenJnlPostLine, AdvancePostingParametersCZZ2); + RelatedEntryNo, false, AdvancePostingBufferCZZ."Auxiliary Entry", GenJnlPostLine, AdvancePostingParametersCZZ2); AdvancePostingParametersCZZ2."Source Code" := ''; ReverseUnrealizedExchangeRate( PurchAdvLetterEntryCZZ, PurchAdvLetterHeaderCZZ, VATPostingSetup, AdvancePostingBufferCZZ.Amount / AmountToUse, - RelatedEntryNo, GenJnlPostLine, AdvancePostingParametersCZZ2); + RelatedEntryNo, AdvancePostingBufferCZZ."Auxiliary Entry", GenJnlPostLine, AdvancePostingParametersCZZ2); end; // Post balance of reverse advance payment VAT @@ -1440,7 +1580,7 @@ codeunit 31142 "Purch. Adv. Letter-Post CZZ" InitGenJournalLine(PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, AdvancePostingParametersCZZ2, GenJournalLine); GenJournalLine."Account No." := VATPostingSetup.GetPurchAdvLetterAccountCZZ(); GenJournalLine.CopyFromAdvancePostingBufferAmountsCZZ(AdvancePostingBufferCZZ); - if not AdvancePostingParametersCZZ."Temporary Entries Only" then begin + if not AdvancePostingParametersCZZ."Temporary Entries Only" and not AdvancePostingBufferCZZ."Auxiliary Entry" then begin OnReverseAdvancePaymentVATOnBeforePostBalance( PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, VATPostingSetup, AdvancePostingBufferCZZ, AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); @@ -1464,6 +1604,7 @@ codeunit 31142 "Purch. Adv. Letter-Post CZZ" VATPostingSetup: Record "VAT Posting Setup"; Coef: Decimal; RelatedEntryNo: Integer; + AuxiliaryEntry: Boolean; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ") var @@ -1491,7 +1632,7 @@ codeunit 31142 "Purch. Adv. Letter-Post CZZ" PostUnrealizedExchangeRate( PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, VATPostingSetup, -AmountLCY, -VATAmountLCY, - RelatedEntryNo, 0, false, GenJnlPostLine, AdvancePostingParametersCZZ); + RelatedEntryNo, 0, false, AuxiliaryEntry, GenJnlPostLine, AdvancePostingParametersCZZ); end; internal procedure PostExchangeRate( @@ -1502,6 +1643,7 @@ codeunit 31142 "Purch. Adv. Letter-Post CZZ" VATAmount: Decimal; RelatedEntryNo: Integer; Correction: Boolean; + AuxiliaryEntry: Boolean; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ") var @@ -1591,6 +1733,7 @@ codeunit 31142 "Purch. Adv. Letter-Post CZZ" TempPurchAdvLetterEntryCZZGlob."Global Dimension 2 Code" := PurchAdvLetterEntryCZZ."Global Dimension 2 Code"; TempPurchAdvLetterEntryCZZGlob."Dimension Set ID" := PurchAdvLetterEntryCZZ."Dimension Set ID"; TempPurchAdvLetterEntryCZZGlob.Cancelled := Correction; + TempPurchAdvLetterEntryCZZGlob."Auxiliary Entry" := AuxiliaryEntry; OnPostExchangeRateOnBeforeInsertEntry( PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, VATPostingSetup, AdvancePostingParametersCZZ, TempPurchAdvLetterEntryCZZGlob); @@ -1610,6 +1753,7 @@ codeunit 31142 "Purch. Adv. Letter-Post CZZ" RelatedEntryNo: Integer; RelatedDetEntryNo: Integer; Correction: Boolean; + AuxiliaryEntry: Boolean; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ") var @@ -1686,6 +1830,7 @@ codeunit 31142 "Purch. Adv. Letter-Post CZZ" TempPurchAdvLetterEntryCZZGlob."Global Dimension 2 Code" := PurchAdvLetterEntryCZZ."Global Dimension 2 Code"; TempPurchAdvLetterEntryCZZGlob."Dimension Set ID" := PurchAdvLetterEntryCZZ."Dimension Set ID"; TempPurchAdvLetterEntryCZZGlob.Cancelled := Correction; + TempPurchAdvLetterEntryCZZGlob."Auxiliary Entry" := AuxiliaryEntry; OnPostUnrealizedExchangeRateOnBeforeInsertEntry( PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, VATPostingSetup, AdvancePostingParametersCZZ, TempPurchAdvLetterEntryCZZGlob); @@ -2005,7 +2150,12 @@ codeunit 31142 "Purch. Adv. Letter-Post CZZ" GenJournalLine."Posting Group" := VendorLedgerEntry."Vendor Posting Group"; GenJournalLine."Source Currency Code" := DetailedVendorLedgEntry1."Currency Code"; GenJournalLine."System-Created Entry" := true; + OnUnapplyVendLedgEntryOnBeforeUnapplyVendLedgEntry(VendorLedgerEntry, DetailedVendorLedgEntry1, GenJournalLine); +#if not CLEAN25 +#pragma warning disable AL0432 OnUnapplyVendLedgEntryOnBeforePostUnapplyVendLedgEntry(VendorLedgerEntry, DetailedVendorLedgEntry1, GenJournalLine); +#pragma warning restore AL0432 +#endif #if not CLEAN24 RaiseOnUnapplyVendLedgEntryOnBeforePostUnapplyVendLedgEntry(VendorLedgerEntry, DetailedVendorLedgEntry1, GenJournalLine); #endif @@ -2383,6 +2533,36 @@ codeunit 31142 "Purch. Adv. Letter-Post CZZ" begin end; + [IntegrationEvent(false, false)] + local procedure OnBeforePostAdvancePaymentUsageVATCancellation(var PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; var IsHandled: Boolean) + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnAfterPostAdvancePaymentUsageVATCancellation(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; var PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostAdvancePaymentUsageVATCancellationOnBeforePost(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; var PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; var AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostAdvancePaymentUsageVATCancellationOnAfterPost(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; var PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; var AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; GLEntryNo: Integer; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostAdvancePaymentUsageVATCancellationOnBeforePostBalance(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; var PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; var AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostAdvancePaymentUsageVATCancellationOnAfterPostBalance(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; var PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; var AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; GLEntryNo: Integer; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; GenJournalLine: Record "Gen. Journal Line") + begin + end; + [IntegrationEvent(false, false)] local procedure OnBeforePostAdvanceCreditMemoVAT(var PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; var IsHandled: Boolean) begin @@ -2698,9 +2878,16 @@ codeunit 31142 "Purch. Adv. Letter-Post CZZ" local procedure OnAfterInitGenJournalLineFromVendorLedgerEntry(var VendorLedgerEntry: Record "Vendor Ledger Entry"; var GenJournalLine: Record "Gen. Journal Line") begin end; - +#if not CLEAN25 + [Obsolete('Replaced by OnUnapplyVendLedgEntryOnBeforeUnapplyVendLedgEntry event.', '25.0')] [IntegrationEvent(false, false)] local procedure OnUnapplyVendLedgEntryOnBeforePostUnapplyVendLedgEntry(var VendorLedgerEntry: Record "Vendor Ledger Entry"; DetailedVendorLedgEntry1: Record "Detailed Vendor Ledg. Entry"; GenJournalLine: Record "Gen. Journal Line") begin end; +#endif + + [IntegrationEvent(false, false)] + local procedure OnUnapplyVendLedgEntryOnBeforeUnapplyVendLedgEntry(var VendorLedgerEntry: Record "Vendor Ledger Entry"; var DetailedVendorLedgEntry: Record "Detailed Vendor Ledg. Entry"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; } \ No newline at end of file diff --git a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/SalesAdvLetterManagementCZZ.Codeunit.al b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/SalesAdvLetterManagementCZZ.Codeunit.al index 24cd481a5b..3ac27310d0 100644 --- a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/SalesAdvLetterManagementCZZ.Codeunit.al +++ b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/SalesAdvLetterManagementCZZ.Codeunit.al @@ -228,7 +228,9 @@ codeunit 31002 "SalesAdvLetterManagement CZZ" AdvanceLetterLinkCZZ.GetLetterLink(TempAdvanceLetterLinkBufferCZZ); TempAdvanceLetterLinkBufferCZZ.SetFilter(Amount, '>0'); if not TempAdvanceLetterLinkBufferCZZ.IsEmpty() then begin - PostingDate := GetPostingDateUI(CustLedgerEntry."Posting Date"); + PostingDate := CustLedgerEntry."Posting Date"; + if not GetPostingDateUI(PostingDate) then + exit; if PostingDate = 0D then Error(PostingDateEmptyErr); LinkAdvancePayment(CustLedgerEntry, TempAdvanceLetterLinkBufferCZZ, PostingDate); @@ -266,7 +268,9 @@ codeunit 31002 "SalesAdvLetterManagement CZZ" var PostingDate: Date; begin - PostingDate := GetPostingDateUI(CustLedgerEntry."Posting Date"); + PostingDate := CustLedgerEntry."Posting Date"; + if not GetPostingDateUI(PostingDate) then + exit; if PostingDate = 0D then Error(PostingDateEmptyErr); @@ -277,7 +281,9 @@ codeunit 31002 "SalesAdvLetterManagement CZZ" var PostingDate: Date; begin - PostingDate := GetPostingDateUI(CustLedgerEntry."Posting Date"); + PostingDate := CustLedgerEntry."Posting Date"; + if not GetPostingDateUI(PostingDate) then + exit; if PostingDate = 0D then Error(PostingDateEmptyErr); @@ -303,7 +309,8 @@ codeunit 31002 "SalesAdvLetterManagement CZZ" InsertedEntryNo := SalesAdvLetterPostCZZ.PostAdvancePayment( CustLedgerEntry, PostedGenJournalLine, GenJnlPostLine, AdvancePostingParametersCZZ); end; - +#if not CLEAN25 + [Obsolete('Replaced by GetAdvanceGLAccountNoCZZ function in GenJournalLine.', '25.0')] procedure GetAdvanceGLAccount(var GenJournalLine: Record "Gen. Journal Line"): Code[20] var SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; @@ -315,6 +322,7 @@ codeunit 31002 "SalesAdvLetterManagement CZZ" AdvanceLetterTemplateCZZ.TestField("Advance Letter G/L Account"); exit(AdvanceLetterTemplateCZZ."Advance Letter G/L Account"); end; +#endif procedure PostAdvancePaymentVAT(var SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; PostingDate: Date) begin @@ -367,11 +375,18 @@ codeunit 31002 "SalesAdvLetterManagement CZZ" InitVATAmountLine(TempAdvancePostingBufferCZZ, SalesAdvLetterEntryCZZ."Sales Adv. Letter No.", SalesAdvLetterEntryCZZ.Amount, SalesAdvLetterEntryCZZ."Currency Factor"); + TempAdvancePostingBufferCZZ.Reset(); + TempAdvancePostingBufferCZZ.SetRange("Auxiliary Entry", false); + if TempAdvancePostingBufferCZZ.IsEmpty() then + DocumentNo := SalesAdvLetterHeaderCZZ."No."; + TempAdvancePostingBufferCZZ.Reset(); + if Silently or not GuiAllowed then begin - DocumentNo := NoSeries.GetNextNo(AdvanceLetterTemplateCZZ."Advance Letter Invoice Nos.", PostingDate); + if DocumentNo = '' then + DocumentNo := NoSeries.GetNextNo(AdvanceLetterTemplateCZZ."Advance Letter Invoice Nos.", PostingDate); TempAdvancePostingBufferCZZ.SetFilter(Amount, '<>0'); end else begin - VATDocumentCZZ.InitSalesDocument(AdvanceLetterTemplateCZZ."Advance Letter Invoice Nos.", '', + VATDocumentCZZ.InitSalesDocument(AdvanceLetterTemplateCZZ."Advance Letter Invoice Nos.", DocumentNo, SalesAdvLetterHeaderCZZ."Document Date", PostingDate, VATDate, 0D, SalesAdvLetterHeaderCZZ."Currency Code", SalesAdvLetterEntryCZZ."Currency Factor", '', TempAdvancePostingBufferCZZ); if VATDocumentCZZ.RunModal() <> Action::OK then @@ -447,18 +462,28 @@ codeunit 31002 "SalesAdvLetterManagement CZZ" local procedure BufferAdvanceLines(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ") var + AdvanceLetterTemplateCZZ: Record "Advance Letter Template CZZ"; SalesAdvLetterLineCZZ: Record "Sales Adv. Letter Line CZZ"; TempAdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ" temporary; begin AdvancePostingBufferCZZ.Reset(); AdvancePostingBufferCZZ.DeleteAll(); + AdvanceLetterTemplateCZZ.Get(SalesAdvLetterHeaderCZZ."Advance Letter Code"); + SalesAdvLetterLineCZZ.SetRange("Document No.", SalesAdvLetterHeaderCZZ."No."); SalesAdvLetterLineCZZ.SetFilter(Amount, '<>0'); if SalesAdvLetterLineCZZ.FindSet() then repeat TempAdvancePostingBufferCZZ.PrepareForSalesAdvLetterLine(SalesAdvLetterLineCZZ); AdvancePostingBufferCZZ.Update(TempAdvancePostingBufferCZZ); + + if (not AdvanceLetterTemplateCZZ."Post VAT Doc. for Rev. Charge") and + (AdvancePostingBufferCZZ."VAT Calculation Type" = "Tax Calculation Type"::"Reverse Charge VAT") + then begin + AdvancePostingBufferCZZ."Auxiliary Entry" := true; + AdvancePostingBufferCZZ.Modify(); + end; until SalesAdvLetterLineCZZ.Next() = 0; end; @@ -517,7 +542,9 @@ codeunit 31002 "SalesAdvLetterManagement CZZ" begin CustLedgerEntry.TestField("Advance Letter No. CZZ"); - PostingDate := GetPostingDateUI(CustLedgerEntry."Posting Date"); + PostingDate := CustLedgerEntry."Posting Date"; + if not GetPostingDateUI(PostingDate) then + exit; if PostingDate = 0D then Error(PostingDateEmptyErr); @@ -537,7 +564,9 @@ codeunit 31002 "SalesAdvLetterManagement CZZ" PostingDate: Date; begin CustLedgerEntry.Get(SalesAdvLetterEntryCZZ."Cust. Ledger Entry No."); - PostingDate := GetPostingDateUI(CustLedgerEntry."Posting Date"); + PostingDate := CustLedgerEntry."Posting Date"; + if not GetPostingDateUI(PostingDate) then + exit; if PostingDate = 0D then Error(PostingDateEmptyErr); UnlinkAdvancePayment(SalesAdvLetterEntryCZZ, PostingDate); @@ -911,6 +940,8 @@ codeunit 31002 "SalesAdvLetterManagement CZZ" NoSeries: Codeunit "No. Series"; GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; AdvPaymentCloseDialog: Page "Adv. Payment Close Dialog CZZ"; + DocumentNo: Code[20]; + SourceCode: Code[10]; VATDate: Date; PostingDate: Date; CurrencyFactor: Decimal; @@ -939,15 +970,29 @@ codeunit 31002 "SalesAdvLetterManagement CZZ" TempAdvancePostingBufferCZZ.Modify(); until SalesAdvLetterEntryCZZ2.Next() = 0; - VATEntry.Get(SalesAdvLetterEntryCZZ."VAT Entry No."); SalesAdvLetterHeaderCZZ.Get(SalesAdvLetterEntryCZZ."Sales Adv. Letter No."); AdvanceLetterTemplateCZZ.Get(SalesAdvLetterHeaderCZZ."Advance Letter Code"); + // find VAT entry of the VAT document due to source code + SourceCode := ''; + VATEntry.SetRange("Document No.", SalesAdvLetterEntryCZZ."Document No."); + VATEntry.SetRange("Posting Date", SalesAdvLetterEntryCZZ."Posting Date"); + if VATEntry.FindFirst() then + SourceCode := VATEntry."Source Code"; + + TempAdvancePostingBufferCZZ.Reset(); + TempAdvancePostingBufferCZZ.SetRange("Auxiliary Entry", false); + if TempAdvancePostingBufferCZZ.IsEmpty() then + DocumentNo := SalesAdvLetterHeaderCZZ."No."; + TempAdvancePostingBufferCZZ.Reset(); + + if DocumentNo = '' then + DocumentNo := NoSeries.GetNextNo(AdvanceLetterTemplateCZZ."Advance Letter Cr. Memo Nos.", WorkDate()); + Clear(AdvancePostingParametersCZZ); AdvancePostingParametersCZZ."Document Type" := "Gen. Journal Document Type"::"Credit Memo"; - AdvancePostingParametersCZZ."Document No." := - NoSeries.GetNextNo(AdvanceLetterTemplateCZZ."Advance Letter Cr. Memo Nos.", WorkDate()); - AdvancePostingParametersCZZ."Source Code" := VATEntry."Source Code"; + AdvancePostingParametersCZZ."Document No." := DocumentNo; + AdvancePostingParametersCZZ."Source Code" := SourceCode; AdvancePostingParametersCZZ."Posting Description" := SalesAdvLetterHeaderCZZ."Posting Description"; AdvancePostingParametersCZZ."Posting Date" := PostingDate; AdvancePostingParametersCZZ."Document Date" := PostingDate; @@ -1162,8 +1207,10 @@ codeunit 31002 "SalesAdvLetterManagement CZZ" if TempAdvancePostingBufferCZZ2.FindSet() then repeat VATPostingSetup.Get(TempAdvancePostingBufferCZZ2."VAT Bus. Posting Group", TempAdvancePostingBufferCZZ2."VAT Prod. Posting Group"); - PostUnrealizedExchangeRate(SalesAdvLetterEntryCZZ, SalesAdvLetterHeaderCZZ, VATPostingSetup, TempAdvancePostingBufferCZZ2.Amount, TempAdvancePostingBufferCZZ2."VAT Amount", - SalesAdvLetterEntryCZZ."Entry No.", DetEntryNo, DocumentNo, ToDate, ToDate, PostDescription, GenJnlPostLine, false, false); + PostUnrealizedExchangeRate(SalesAdvLetterEntryCZZ, SalesAdvLetterHeaderCZZ, VATPostingSetup, + TempAdvancePostingBufferCZZ2.Amount, TempAdvancePostingBufferCZZ2."VAT Amount", + SalesAdvLetterEntryCZZ."Entry No.", DetEntryNo, DocumentNo, ToDate, ToDate, PostDescription, + GenJnlPostLine, false, false, TempAdvancePostingBufferCZZ2."Auxiliary Entry"); until TempAdvancePostingBufferCZZ2.Next() = 0; SalesAdvLetterPostCZZ.BufferAdvanceVATLines(SalesAdvLetterEntryCZZ, TempAdvancePostingBufferCZZ1, 0D); @@ -1218,8 +1265,10 @@ codeunit 31002 "SalesAdvLetterManagement CZZ" end; VATPostingSetup.Get(SalesAdvLetterEntryCZZ3."VAT Bus. Posting Group", SalesAdvLetterEntryCZZ3."VAT Prod. Posting Group"); - PostUnrealizedExchangeRate(SalesAdvLetterEntryCZZ, SalesAdvLetterHeaderCZZ, VATPostingSetup, -AmountToPost, -VATAmountToPost, - SalesAdvLetterEntryCZZ2."Entry No.", 0, DocumentNo, SalesAdvLetterEntryCZZ3."Posting Date", SalesAdvLetterEntryCZZ3."VAT Date", PostDescription, GenJnlPostLine, false, false); + PostUnrealizedExchangeRate(SalesAdvLetterEntryCZZ, SalesAdvLetterHeaderCZZ, VATPostingSetup, + -AmountToPost, -VATAmountToPost, SalesAdvLetterEntryCZZ2."Entry No.", 0, DocumentNo, + SalesAdvLetterEntryCZZ3."Posting Date", SalesAdvLetterEntryCZZ3."VAT Date", PostDescription, + GenJnlPostLine, false, false, SalesAdvLetterEntryCZZ3."Auxiliary Entry"); until SalesAdvLetterEntryCZZ3.Next() = 0; until SalesAdvLetterEntryCZZ2.Next() = 0; end; @@ -1228,7 +1277,7 @@ codeunit 31002 "SalesAdvLetterManagement CZZ" local procedure PostUnrealizedExchangeRate(var SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; var SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; var VATPostingSetup: Record "VAT Posting Setup"; Amount: Decimal; VATAmount: Decimal; RelatedEntryNo: Integer; RelatedDetEntryNo: Integer; DocumentNo: Code[20]; PostingDate: Date; VATDate: Date; PostDescription: Text[100]; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; - Correction: Boolean; Preview: Boolean) + Correction: Boolean; Preview: Boolean; AuxiliaryEntry: Boolean) var AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; begin @@ -1240,21 +1289,23 @@ codeunit 31002 "SalesAdvLetterManagement CZZ" AdvancePostingParametersCZZ."Temporary Entries Only" := Preview; SalesAdvLetterPostCZZ.PostUnrealizedExchangeRate( - SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, VATPostingSetup, Amount, VATAmount, RelatedEntryNo, RelatedDetEntryNo, Correction, GenJnlPostLine, AdvancePostingParametersCZZ); + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, VATPostingSetup, Amount, VATAmount, + RelatedEntryNo, RelatedDetEntryNo, Correction, AuxiliaryEntry, GenJnlPostLine, AdvancePostingParametersCZZ); end; - local procedure GetPostingDateUI(DefaultPostingDate: Date): Date + local procedure GetPostingDateUI(var PostingDate: Date): Boolean var GetPostingDateCZZ: Page "Get Posting Date CZZ"; - PostingDate: Date; begin if not GuiAllowed() then - exit(DefaultPostingDate); + exit(true); + + GetPostingDateCZZ.SetValues(PostingDate); + if GetPostingDateCZZ.RunModal() <> Action::OK then + exit(false); - GetPostingDateCZZ.SetValues(DefaultPostingDate); - if GetPostingDateCZZ.RunModal() = Action::OK then - GetPostingDateCZZ.GetValues(PostingDate); - exit(PostingDate); + GetPostingDateCZZ.GetValues(PostingDate); + exit(true); end; #if not CLEAN24 #pragma warning disable AL0432 diff --git a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/SalesAdvLetterPostCZZ.Codeunit.al b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/SalesAdvLetterPostCZZ.Codeunit.al index a238f581c1..9ed4f7ae42 100644 --- a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/SalesAdvLetterPostCZZ.Codeunit.al +++ b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/SalesAdvLetterPostCZZ.Codeunit.al @@ -259,7 +259,7 @@ codeunit 31143 "Sales Adv. Letter-Post CZZ" SalesAdvLetterEntryCZZ2: Record "Sales Adv. Letter Entry CZZ"; SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; VATPostingSetup: Record "VAT Posting Setup"; - GLEntryNo: Integer; + GLEntryNo, VATEntryNo : Integer; IsHandled: Boolean; begin IsHandled := false; @@ -298,55 +298,60 @@ codeunit 31143 "Sales Adv. Letter-Post CZZ" AdvancePostingParametersCZZ."Source Code" := CustLedgerEntry."Source Code"; end; - AdvancePostingBufferCZZ.FindSet(); - repeat - VATPostingSetup.Get(AdvancePostingBufferCZZ."VAT Bus. Posting Group", AdvancePostingBufferCZZ."VAT Prod. Posting Group"); - - // Post VAT amount and VAT base of VAT document - InitGenJournalLine(SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, AdvancePostingParametersCZZ, GenJournalLine); - GenJournalLine."Account No." := VATPostingSetup.GetSalesAdvLetterAccountCZZ(); - GenJournalLine."Gen. Posting Type" := GenJournalLine."Gen. Posting Type"::Sale; - GenJournalLine.CopyFromAdvancePostingBufferCZZ(AdvancePostingBufferCZZ); - if not AdvancePostingParametersCZZ."Temporary Entries Only" then begin - OnPostAdvancePaymentVATOnBeforePost( - SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, AdvancePostingBufferCZZ, - AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); + if AdvancePostingBufferCZZ.FindSet() then + repeat + GLEntryNo := 0; + VATEntryNo := 0; + + VATPostingSetup.Get(AdvancePostingBufferCZZ."VAT Bus. Posting Group", AdvancePostingBufferCZZ."VAT Prod. Posting Group"); + + // Post VAT amount and VAT base of VAT document + InitGenJournalLine(SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, AdvancePostingParametersCZZ, GenJournalLine); + GenJournalLine."Account No." := VATPostingSetup.GetSalesAdvLetterAccountCZZ(); + GenJournalLine."Gen. Posting Type" := GenJournalLine."Gen. Posting Type"::Sale; + GenJournalLine.CopyFromAdvancePostingBufferCZZ(AdvancePostingBufferCZZ); + if not AdvancePostingParametersCZZ."Temporary Entries Only" and not AdvancePostingBufferCZZ."Auxiliary Entry" then begin + OnPostAdvancePaymentVATOnBeforePost( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, AdvancePostingBufferCZZ, + AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); #if not CLEAN24 - RaiseOnPostAdvancePaymentVATOnBeforeGenJnlPostLine( - SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, GenJournalLine); + RaiseOnPostAdvancePaymentVATOnBeforeGenJnlPostLine( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, GenJournalLine); #endif - GLEntryNo := RunGenJnlPostLine(GenJournalLine, GenJnlPostLine, true, true, false); - OnPostAdvancePaymentVATOnAfterPost( - SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, AdvancePostingBufferCZZ, - AdvancePostingParametersCZZ, GLEntryNo, GenJnlPostLine, GenJournalLine); - end; - - TempSalesAdvLetterEntryCZZGlob.InitNewEntry(); - TempSalesAdvLetterEntryCZZGlob.InitRelatedEntry(SalesAdvLetterEntryCZZ); - TempSalesAdvLetterEntryCZZGlob.CopyFromGenJnlLine(GenJournalLine); - TempSalesAdvLetterEntryCZZGlob."Entry Type" := "Advance Letter Entry Type CZZ"::"VAT Payment"; - TempSalesAdvLetterEntryCZZGlob."Sales Adv. Letter No." := SalesAdvLetterHeaderCZZ."No."; - TempSalesAdvLetterEntryCZZGlob."VAT Entry No." := GenJnlPostLine.GetNextVATEntryNo() - 1; - TempSalesAdvLetterEntryCZZGlob."VAT Identifier" := VATPostingSetup."VAT Identifier"; - TempSalesAdvLetterEntryCZZGlob.InsertNewEntry(not AdvancePostingParametersCZZ."Temporary Entries Only"); + GLEntryNo := RunGenJnlPostLine(GenJournalLine, GenJnlPostLine, true, true, false); + VATEntryNo := GenJnlPostLine.GetNextVATEntryNo() - 1; + OnPostAdvancePaymentVATOnAfterPost( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, AdvancePostingBufferCZZ, + AdvancePostingParametersCZZ, GLEntryNo, GenJnlPostLine, GenJournalLine); + end; - // Post balance of VAT document - AdvancePostingParametersCZZ2.InitNew(AdvancePostingParametersCZZ); - AdvancePostingParametersCZZ2."Document Type" := "Gen. Journal Document Type"::" "; - InitGenJournalLine(SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, AdvancePostingParametersCZZ2, GenJournalLine); - GenJournalLine."Account No." := VATPostingSetup.GetSalesAdvLetterAccountCZZ(); - AdvancePostingBufferCZZ.ReverseAmounts(); - GenJournalLine.CopyFromAdvancePostingBufferAmountsCZZ(AdvancePostingBufferCZZ); - if not AdvancePostingParametersCZZ."Temporary Entries Only" then begin - OnPostAdvancePaymentVATOnBeforePostBalance( - SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, AdvancePostingBufferCZZ, - AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); - GLEntryNo := RunGenJnlPostLine(GenJournalLine, GenJnlPostLine, false, false, false); - OnPostAdvancePaymentVATOnAfterPostBalance( - SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, AdvancePostingBufferCZZ, - AdvancePostingParametersCZZ, GLEntryNo, GenJnlPostLine, GenJournalLine); - end; - until AdvancePostingBufferCZZ.Next() = 0; + TempSalesAdvLetterEntryCZZGlob.InitNewEntry(); + TempSalesAdvLetterEntryCZZGlob.InitRelatedEntry(SalesAdvLetterEntryCZZ); + TempSalesAdvLetterEntryCZZGlob.CopyFromGenJnlLine(GenJournalLine); + TempSalesAdvLetterEntryCZZGlob."Entry Type" := "Advance Letter Entry Type CZZ"::"VAT Payment"; + TempSalesAdvLetterEntryCZZGlob."Sales Adv. Letter No." := SalesAdvLetterHeaderCZZ."No."; + TempSalesAdvLetterEntryCZZGlob."VAT Entry No." := VATEntryNo; + TempSalesAdvLetterEntryCZZGlob."VAT Identifier" := VATPostingSetup."VAT Identifier"; + TempSalesAdvLetterEntryCZZGlob."Auxiliary Entry" := AdvancePostingBufferCZZ."Auxiliary Entry"; + TempSalesAdvLetterEntryCZZGlob.InsertNewEntry(not AdvancePostingParametersCZZ."Temporary Entries Only"); + + // Post balance of VAT document + AdvancePostingParametersCZZ2.InitNew(AdvancePostingParametersCZZ); + AdvancePostingParametersCZZ2."Document Type" := "Gen. Journal Document Type"::" "; + InitGenJournalLine(SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, AdvancePostingParametersCZZ2, GenJournalLine); + GenJournalLine."Account No." := VATPostingSetup.GetSalesAdvLetterAccountCZZ(); + AdvancePostingBufferCZZ.ReverseAmounts(); + GenJournalLine.CopyFromAdvancePostingBufferAmountsCZZ(AdvancePostingBufferCZZ); + if not AdvancePostingParametersCZZ."Temporary Entries Only" and not AdvancePostingBufferCZZ."Auxiliary Entry" then begin + OnPostAdvancePaymentVATOnBeforePostBalance( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, AdvancePostingBufferCZZ, + AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); + GLEntryNo := RunGenJnlPostLine(GenJournalLine, GenJnlPostLine, false, false, false); + OnPostAdvancePaymentVATOnAfterPostBalance( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, AdvancePostingBufferCZZ, + AdvancePostingParametersCZZ, GLEntryNo, GenJnlPostLine, GenJournalLine); + end; + until AdvancePostingBufferCZZ.Next() = 0; OnAfterPostAdvancePaymentVAT( SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, AdvancePostingBufferCZZ, @@ -363,7 +368,7 @@ codeunit 31143 "Sales Adv. Letter-Post CZZ" AdvancePostingParametersCZZ2: Record "Advance Posting Parameters CZZ"; VATPostingSetup: Record "VAT Posting Setup"; GenJournalLine: Record "Gen. Journal Line"; - EntryNo, GLEntryNo : Integer; + EntryNo, GLEntryNo, VATEntryNo : Integer; IsHandled: Boolean; begin IsHandled := false; @@ -378,17 +383,21 @@ codeunit 31143 "Sales Adv. Letter-Post CZZ" VATPostingSetup.Get(AdvancePostingBufferCZZ."VAT Bus. Posting Group", AdvancePostingBufferCZZ."VAT Prod. Posting Group"); + GLEntryNo := 0; + VATEntryNo := 0; + // Post advance payment VAT unlinking InitGenJournalLine(SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, AdvancePostingParametersCZZ, GenJournalLine); GenJournalLine."Account No." := VATPostingSetup.GetSalesAdvLetterAccountCZZ(); GenJournalLine."Gen. Posting Type" := GenJournalLine."Gen. Posting Type"::Sale; AdvancePostingBufferCZZ.ReverseAmounts(); GenJournalLine.CopyFromAdvancePostingBufferCZZ(AdvancePostingBufferCZZ); - if not AdvancePostingParametersCZZ."Temporary Entries Only" then begin + if not AdvancePostingParametersCZZ."Temporary Entries Only" and not AdvancePostingBufferCZZ."Auxiliary Entry" then begin OnPostAdvancePaymentVATUnlinkingOnBeforePost( SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, VATPostingSetup, AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); GLEntryNo := RunGenJnlPostLine(GenJournalLine, GenJnlPostLine, true, true, false); + VATEntryNo := GenJnlPostLine.GetNextVATEntryNo() - 1; OnPostAdvancePaymentVATUnlinkingOnAfterPost( SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, VATPostingSetup, AdvancePostingParametersCZZ, GLEntryNo, GenJnlPostLine, GenJournalLine); @@ -399,8 +408,9 @@ codeunit 31143 "Sales Adv. Letter-Post CZZ" TempSalesAdvLetterEntryCZZGlob.CopyFromGenJnlLine(GenJournalLine); TempSalesAdvLetterEntryCZZGlob."Entry Type" := "Advance Letter Entry Type CZZ"::"VAT Payment"; TempSalesAdvLetterEntryCZZGlob."Sales Adv. Letter No." := SalesAdvLetterHeaderCZZ."No."; - TempSalesAdvLetterEntryCZZGlob."VAT Entry No." := GenJnlPostLine.GetNextVATEntryNo() - 1; + TempSalesAdvLetterEntryCZZGlob."VAT Entry No." := VATEntryNo; TempSalesAdvLetterEntryCZZGlob."VAT Identifier" := VATPostingSetup."VAT Identifier"; + TempSalesAdvLetterEntryCZZGlob."Auxiliary Entry" := AdvancePostingBufferCZZ."Auxiliary Entry"; TempSalesAdvLetterEntryCZZGlob.Cancelled := true; EntryNo := TempSalesAdvLetterEntryCZZGlob.InsertNewEntry(not AdvancePostingParametersCZZ."Temporary Entries Only"); @@ -411,7 +421,7 @@ codeunit 31143 "Sales Adv. Letter-Post CZZ" InitGenJournalLine(SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, AdvancePostingParametersCZZ2, GenJournalLine); GenJournalLine."Account No." := VATPostingSetup.GetSalesAdvLetterAccountCZZ(); GenJournalLine.CopyFromAdvancePostingBufferAmountsCZZ(AdvancePostingBufferCZZ); - if not AdvancePostingParametersCZZ."Temporary Entries Only" then begin + if not AdvancePostingParametersCZZ."Temporary Entries Only" and not AdvancePostingBufferCZZ."Auxiliary Entry" then begin OnPostAdvancePaymentVATUnlinkingOnBeforePostBalance( SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, AdvancePostingBufferCZZ, AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); @@ -573,7 +583,7 @@ codeunit 31143 "Sales Adv. Letter-Post CZZ" var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ") var - SalesAdvLetterEntryCZZ2: Record "Sales Adv. Letter Entry CZZ"; + RelatedSalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; IsHandled: Boolean; begin IsHandled := false; @@ -586,12 +596,12 @@ codeunit 31143 "Sales Adv. Letter-Post CZZ" exit; SalesAdvLetterEntryCZZ.TestField(Cancelled, false); - SalesAdvLetterEntryCZZ2.Get(SalesAdvLetterEntryCZZ."Related Entry"); - if SalesAdvLetterEntryCZZ2."Entry Type" <> SalesAdvLetterEntryCZZ2."Entry Type"::Payment then + RelatedSalesAdvLetterEntryCZZ.Get(SalesAdvLetterEntryCZZ."Related Entry"); + if RelatedSalesAdvLetterEntryCZZ."Entry Type" <> RelatedSalesAdvLetterEntryCZZ."Entry Type"::Payment then exit; ReverseAdvancePaymentVAT( - SalesAdvLetterEntryCZZ2, AdvancePostingBufferCZZ, SalesAdvLetterEntryCZZ."Entry No.", + RelatedSalesAdvLetterEntryCZZ, AdvancePostingBufferCZZ, SalesAdvLetterEntryCZZ."Entry No.", "Advance Letter Entry Type CZZ"::"VAT Usage", GenJnlPostLine, AdvancePostingParametersCZZ); OnAfterPostAdvancePaymentUsageVAT( @@ -606,13 +616,13 @@ codeunit 31143 "Sales Adv. Letter-Post CZZ" var AdvancePostingParametersCZZ2: Record "Advance Posting Parameters CZZ"; GenJournalLine: Record "Gen. Journal Line"; - SalesAdvLetterEntryCZZ2: Record "Sales Adv. Letter Entry CZZ"; - SalesAdvLetterEntryCZZ3: Record "Sales Adv. Letter Entry CZZ"; + RelatedSalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; + VATDocumentSalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; TempAdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ" temporary; VATPostingSetup: Record "VAT Posting Setup"; ExchRateAmount, ExchRateVATAmount : Decimal; - GLEntryNo: Integer; + GLEntryNo, VATEntryNo : Integer; IsHandled: Boolean; begin IsHandled := false; @@ -631,12 +641,15 @@ codeunit 31143 "Sales Adv. Letter-Post CZZ" Error(NothingToPostErr); if SalesAdvLetterEntryCZZ."Currency Code" <> '' then begin - SalesAdvLetterEntryCZZ2.Get(SalesAdvLetterEntryCZZ."Related Entry"); - BufferAdvanceVATLines(SalesAdvLetterEntryCZZ2, TempAdvancePostingBufferCZZ, 0D); + RelatedSalesAdvLetterEntryCZZ.Get(SalesAdvLetterEntryCZZ."Related Entry"); + BufferAdvanceVATLines(RelatedSalesAdvLetterEntryCZZ, TempAdvancePostingBufferCZZ, 0D); end; AdvancePostingBufferCZZ.FindSet(); repeat + GLEntryNo := 0; + VATEntryNo := 0; + VATPostingSetup.Get(AdvancePostingBufferCZZ."VAT Bus. Posting Group", AdvancePostingBufferCZZ."VAT Prod. Posting Group"); // Post credit memo VAT @@ -645,11 +658,12 @@ codeunit 31143 "Sales Adv. Letter-Post CZZ" GenJournalLine."Gen. Posting Type" := GenJournalLine."Gen. Posting Type"::Sale; AdvancePostingBufferCZZ.ReverseAmounts(); GenJournalLine.CopyFromAdvancePostingBufferCZZ(AdvancePostingBufferCZZ); - if not AdvancePostingParametersCZZ."Temporary Entries Only" then begin + if not AdvancePostingParametersCZZ."Temporary Entries Only" and not AdvancePostingBufferCZZ."Auxiliary Entry" then begin OnPostAdvanceCreditMemoVATOnBeforePost( SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, AdvancePostingBufferCZZ, AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); GLEntryNo := RunGenJnlPostLine(GenJournalLine, GenJnlPostLine, true, true, false); + VATEntryNo := GenJnlPostLine.GetNextVATEntryNo() - 1; OnPostAdvanceCreditMemoVATOnAfterPost( SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, AdvancePostingBufferCZZ, AdvancePostingParametersCZZ, GLEntryNo, GenJnlPostLine, GenJournalLine); @@ -660,8 +674,9 @@ codeunit 31143 "Sales Adv. Letter-Post CZZ" TempSalesAdvLetterEntryCZZGlob.CopyFromGenJnlLine(GenJournalLine); TempSalesAdvLetterEntryCZZGlob."Entry Type" := "Advance Letter Entry Type CZZ"::"VAT Payment"; TempSalesAdvLetterEntryCZZGlob."Sales Adv. Letter No." := SalesAdvLetterHeaderCZZ."No."; - TempSalesAdvLetterEntryCZZGlob."VAT Entry No." := GenJnlPostLine.GetNextVATEntryNo() - 1; + TempSalesAdvLetterEntryCZZGlob."VAT Entry No." := VATEntryNo; TempSalesAdvLetterEntryCZZGlob."VAT Identifier" := VATPostingSetup."VAT Identifier"; + TempSalesAdvLetterEntryCZZGlob."Auxiliary Entry" := AdvancePostingBufferCZZ."Auxiliary Entry"; TempSalesAdvLetterEntryCZZGlob.Cancelled := true; TempSalesAdvLetterEntryCZZGlob.InsertNewEntry(not AdvancePostingParametersCZZ."Temporary Entries Only"); @@ -678,25 +693,27 @@ codeunit 31143 "Sales Adv. Letter-Post CZZ" AdvancePostingParametersCZZ2."Currency Code" := ''; AdvancePostingParametersCZZ2."Currency Factor" := 0; - SalesAdvLetterEntryCZZ3.Reset(); - SalesAdvLetterEntryCZZ3.SetRange("Sales Adv. Letter No.", SalesAdvLetterEntryCZZ."Sales Adv. Letter No."); - SalesAdvLetterEntryCZZ3.SetRange("Document No.", SalesAdvLetterEntryCZZ."Document No."); - SalesAdvLetterEntryCZZ3.SetRange("Entry Type", SalesAdvLetterEntryCZZ."Entry Type"); - SalesAdvLetterEntryCZZ3.SetRange("VAT Bus. Posting Group", AdvancePostingBufferCZZ."VAT Bus. Posting Group"); - SalesAdvLetterEntryCZZ3.SetRange("VAT Prod. Posting Group", AdvancePostingBufferCZZ."VAT Prod. Posting Group"); - SalesAdvLetterEntryCZZ3.SetRange(Cancelled, false); - SalesAdvLetterEntryCZZ3.CalcSums("Amount (LCY)", "VAT Amount (LCY)"); - - ExchRateAmount := -SalesAdvLetterEntryCZZ3."Amount (LCY)" - GenJournalLine."Amount (LCY)"; - ExchRateVATAmount := -SalesAdvLetterEntryCZZ3."VAT Amount (LCY)" - GenJournalLine."VAT Amount (LCY)"; + VATDocumentSalesAdvLetterEntryCZZ.Reset(); + VATDocumentSalesAdvLetterEntryCZZ.SetRange("Sales Adv. Letter No.", SalesAdvLetterEntryCZZ."Sales Adv. Letter No."); + VATDocumentSalesAdvLetterEntryCZZ.SetRange("Document No.", SalesAdvLetterEntryCZZ."Document No."); + VATDocumentSalesAdvLetterEntryCZZ.SetRange("Entry Type", SalesAdvLetterEntryCZZ."Entry Type"); + VATDocumentSalesAdvLetterEntryCZZ.SetRange("VAT Bus. Posting Group", AdvancePostingBufferCZZ."VAT Bus. Posting Group"); + VATDocumentSalesAdvLetterEntryCZZ.SetRange("VAT Prod. Posting Group", AdvancePostingBufferCZZ."VAT Prod. Posting Group"); + VATDocumentSalesAdvLetterEntryCZZ.SetRange(Cancelled, false); + VATDocumentSalesAdvLetterEntryCZZ.CalcSums("Amount (LCY)", "VAT Amount (LCY)"); + + ExchRateAmount := -VATDocumentSalesAdvLetterEntryCZZ."Amount (LCY)" - GenJournalLine."Amount (LCY)"; + ExchRateVATAmount := -VATDocumentSalesAdvLetterEntryCZZ."VAT Amount (LCY)" - GenJournalLine."VAT Amount (LCY)"; if (ExchRateAmount <> 0) or (ExchRateVATAmount <> 0) then PostExchangeRate(SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, VATPostingSetup, ExchRateAmount, ExchRateVATAmount, - SalesAdvLetterEntryCZZ."Related Entry", true, GenJnlPostLine, AdvancePostingParametersCZZ2); + SalesAdvLetterEntryCZZ."Related Entry", true, AdvancePostingBufferCZZ."Auxiliary Entry", + GenJnlPostLine, AdvancePostingParametersCZZ2); ReverseUnrealizedExchangeRate( - SalesAdvLetterEntryCZZ2, SalesAdvLetterHeaderCZZ, VATPostingSetup, + RelatedSalesAdvLetterEntryCZZ, SalesAdvLetterHeaderCZZ, VATPostingSetup, AdvancePostingBufferCZZ.Amount / TempAdvancePostingBufferCZZ.Amount, - SalesAdvLetterEntryCZZ2."Entry No.", GenJnlPostLine, AdvancePostingParametersCZZ2); + RelatedSalesAdvLetterEntryCZZ."Entry No.", AdvancePostingBufferCZZ."Auxiliary Entry", + GenJnlPostLine, AdvancePostingParametersCZZ2); end; // Post balance of credit memo VAT @@ -705,7 +722,7 @@ codeunit 31143 "Sales Adv. Letter-Post CZZ" InitGenJournalLine(SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, AdvancePostingParametersCZZ2, GenJournalLine); GenJournalLine."Account No." := VATPostingSetup.GetSalesAdvLetterAccountCZZ(); GenJournalLine.CopyFromAdvancePostingBufferAmountsCZZ(AdvancePostingBufferCZZ); - if not AdvancePostingParametersCZZ."Temporary Entries Only" then begin + if not AdvancePostingParametersCZZ."Temporary Entries Only" and not AdvancePostingBufferCZZ."Auxiliary Entry" then begin OnPostAdvanceCreditMemoVATOnBeforePostBalance( SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, AdvancePostingBufferCZZ, AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); @@ -717,12 +734,12 @@ codeunit 31143 "Sales Adv. Letter-Post CZZ" until AdvancePostingBufferCZZ.Next() = 0; if not AdvancePostingParametersCZZ."Temporary Entries Only" then begin - SalesAdvLetterEntryCZZ3.Reset(); - SalesAdvLetterEntryCZZ3.SetRange("Sales Adv. Letter No.", SalesAdvLetterEntryCZZ."Sales Adv. Letter No."); - SalesAdvLetterEntryCZZ3.SetRange("Document No.", SalesAdvLetterEntryCZZ."Document No."); - SalesAdvLetterEntryCZZ3.SetRange("Entry Type", SalesAdvLetterEntryCZZ."Entry Type"); - SalesAdvLetterEntryCZZ3.SetRange(Cancelled, false); - SalesAdvLetterEntryCZZ3.ModifyAll(Cancelled, true); + VATDocumentSalesAdvLetterEntryCZZ.Reset(); + VATDocumentSalesAdvLetterEntryCZZ.SetRange("Sales Adv. Letter No.", SalesAdvLetterEntryCZZ."Sales Adv. Letter No."); + VATDocumentSalesAdvLetterEntryCZZ.SetRange("Document No.", SalesAdvLetterEntryCZZ."Document No."); + VATDocumentSalesAdvLetterEntryCZZ.SetRange("Entry Type", SalesAdvLetterEntryCZZ."Entry Type"); + VATDocumentSalesAdvLetterEntryCZZ.SetRange(Cancelled, false); + VATDocumentSalesAdvLetterEntryCZZ.ModifyAll(Cancelled, true); end; OnAfterPostAdvanceCreditMemoVAT( @@ -794,7 +811,8 @@ codeunit 31143 "Sales Adv. Letter-Post CZZ" VATPostingSetup.Get(SalesAdvLetterEntryCZZ."VAT Bus. Posting Group", SalesAdvLetterEntryCZZ."VAT Prod. Posting Group"); PostUnrealizedExchangeRate(SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, VATPostingSetup, -SalesAdvLetterEntryCZZ."Amount (LCY)", -SalesAdvLetterEntryCZZ."VAT Amount (LCY)", - SalesAdvLetterEntryCZZ."Related Entry", 0, true, GenJnlPostLine, AdvancePostingParametersCZZ2); + SalesAdvLetterEntryCZZ."Related Entry", 0, true, SalesAdvLetterEntryCZZ."Auxiliary Entry", + GenJnlPostLine, AdvancePostingParametersCZZ2); end; SalesAdvLetterEntryCZZ."Entry Type"::"VAT Rate": begin @@ -803,7 +821,8 @@ codeunit 31143 "Sales Adv. Letter-Post CZZ" VATPostingSetup.Get(SalesAdvLetterEntryCZZ."VAT Bus. Posting Group", SalesAdvLetterEntryCZZ."VAT Prod. Posting Group"); PostExchangeRate(SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, VATPostingSetup, -SalesAdvLetterEntryCZZ."Amount (LCY)", -SalesAdvLetterEntryCZZ."VAT Amount (LCY)", - SalesAdvLetterEntryCZZ."Related Entry", true, GenJnlPostLine, AdvancePostingParametersCZZ2); + SalesAdvLetterEntryCZZ."Related Entry", true, SalesAdvLetterEntryCZZ."Auxiliary Entry", + GenJnlPostLine, AdvancePostingParametersCZZ2); end; SalesAdvLetterEntryCZZ."Entry Type"::"VAT Usage": begin @@ -845,8 +864,7 @@ codeunit 31143 "Sales Adv. Letter-Post CZZ" AdvancePostingParametersCZZ2: Record "Advance Posting Parameters CZZ"; GenJournalLine: Record "Gen. Journal Line"; VATPostingSetup: Record "VAT Posting Setup"; - EntryNo: Integer; - GLEntryNo: Integer; + EntryNo, GLEntryNo, VATEntryNo : Integer; IsHandled: Boolean; begin IsHandled := false; @@ -855,6 +873,9 @@ codeunit 31143 "Sales Adv. Letter-Post CZZ" if IsHandled then exit; + GLEntryNo := 0; + VATEntryNo := 0; + VATPostingSetup.Get(AdvancePostingBufferCZZ."VAT Bus. Posting Group", AdvancePostingBufferCZZ."VAT Prod. Posting Group"); InitGenJournalLine( @@ -864,11 +885,12 @@ codeunit 31143 "Sales Adv. Letter-Post CZZ" GenJournalLine.Correction := true; AdvancePostingBufferCZZ.ReverseAmounts(); GenJournalLine.CopyFromAdvancePostingBufferCZZ(AdvancePostingBufferCZZ); - if not AdvancePostingParametersCZZ."Temporary Entries Only" then begin + if not AdvancePostingParametersCZZ."Temporary Entries Only" and not AdvancePostingBufferCZZ."Auxiliary Entry" then begin OnPostAdvanceLetterEntryVATUsageUnapplyingOnBeforePost( SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, AdvancePostingBufferCZZ, AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); GLEntryNo := RunGenJnlPostLine(GenJournalLine, GenJnlPostLine, true, true, false); + VATEntryNo := GenJnlPostLine.GetNextVATEntryNo() - 1; OnPostAdvanceLetterEntryVATUsageUnapplyingOnAfterPost( SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, AdvancePostingBufferCZZ, AdvancePostingParametersCZZ, GLEntryNo, GenJnlPostLine, GenJournalLine); @@ -879,8 +901,9 @@ codeunit 31143 "Sales Adv. Letter-Post CZZ" TempSalesAdvLetterEntryCZZGlob.CopyFromGenJnlLine(GenJournalLine); TempSalesAdvLetterEntryCZZGlob."Entry Type" := SalesAdvLetterEntryCZZ."Entry Type"; TempSalesAdvLetterEntryCZZGlob."Sales Adv. Letter No." := SalesAdvLetterHeaderCZZ."No."; - TempSalesAdvLetterEntryCZZGlob."VAT Entry No." := GenJnlPostLine.GetNextVATEntryNo() - 1; + TempSalesAdvLetterEntryCZZGlob."VAT Entry No." := VATEntryNo; TempSalesAdvLetterEntryCZZGlob."VAT Identifier" := VATPostingSetup."VAT Identifier"; + TempSalesAdvLetterEntryCZZGlob."Auxiliary Entry" := AdvancePostingBufferCZZ."Auxiliary Entry"; TempSalesAdvLetterEntryCZZGlob.Cancelled := true; EntryNo := TempSalesAdvLetterEntryCZZGlob.InsertNewEntry(not AdvancePostingParametersCZZ."Temporary Entries Only"); @@ -892,7 +915,7 @@ codeunit 31143 "Sales Adv. Letter-Post CZZ" GenJournalLine."Account No." := VATPostingSetup.GetSalesAdvLetterAccountCZZ(); GenJournalLine.Correction := true; GenJournalLine.CopyFromAdvancePostingBufferAmountsCZZ(AdvancePostingBufferCZZ); - if not AdvancePostingParametersCZZ."Temporary Entries Only" then begin + if not AdvancePostingParametersCZZ."Temporary Entries Only" and not AdvancePostingBufferCZZ."Auxiliary Entry" then begin OnPostAdvanceLetterEntryVATUsageUnapplyingOnBeforePostBalance( SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, AdvancePostingBufferCZZ, AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); @@ -1306,13 +1329,13 @@ codeunit 31143 "Sales Adv. Letter-Post CZZ" AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ") var AdvancePostingParametersCZZ2: Record "Advance Posting Parameters CZZ"; - SalesAdvLetterEntryCZZ2: Record "Sales Adv. Letter Entry CZZ"; + VATDocumentSalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; TempAdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ" temporary; GenJournalLine: Record "Gen. Journal Line"; VATPostingSetup: Record "VAT Posting Setup"; SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; CalcVATAmountLCY, CalcAmountLCY, ExchRateAmount, ExchRateVATAmount, AmountToUse : Decimal; - GLEntryNo: Integer; + GLEntryNo, VATEntryNo : Integer; IsHandled: Boolean; begin IsHandled := false; @@ -1328,11 +1351,12 @@ codeunit 31143 "Sales Adv. Letter-Post CZZ" if SalesAdvLetterEntryCZZ."Entry Type" <> SalesAdvLetterEntryCZZ."Entry Type"::Payment then exit; - SalesAdvLetterEntryCZZ2.SetRange("Sales Adv. Letter No.", SalesAdvLetterEntryCZZ."Sales Adv. Letter No."); - SalesAdvLetterEntryCZZ2.SetRange(Cancelled, false); - SalesAdvLetterEntryCZZ2.SetRange("Related Entry", SalesAdvLetterEntryCZZ."Entry No."); - SalesAdvLetterEntryCZZ2.SetRange("Entry Type", SalesAdvLetterEntryCZZ2."Entry Type"::"VAT Payment"); - if SalesAdvLetterEntryCZZ2.IsEmpty() then + VATDocumentSalesAdvLetterEntryCZZ.Reset(); + VATDocumentSalesAdvLetterEntryCZZ.SetRange("Sales Adv. Letter No.", SalesAdvLetterEntryCZZ."Sales Adv. Letter No."); + VATDocumentSalesAdvLetterEntryCZZ.SetRange(Cancelled, false); + VATDocumentSalesAdvLetterEntryCZZ.SetRange("Related Entry", SalesAdvLetterEntryCZZ."Entry No."); + VATDocumentSalesAdvLetterEntryCZZ.SetRange("Entry Type", VATDocumentSalesAdvLetterEntryCZZ."Entry Type"::"VAT Payment"); + if VATDocumentSalesAdvLetterEntryCZZ.IsEmpty() then exit; AdvancePostingBufferCZZ.FilterGroup(-1); @@ -1352,6 +1376,9 @@ codeunit 31143 "Sales Adv. Letter-Post CZZ" AdvancePostingBufferCZZ.FindSet(); repeat + GLEntryNo := 0; + VATEntryNo := 0; + VATPostingSetup.Get(AdvancePostingBufferCZZ."VAT Bus. Posting Group", AdvancePostingBufferCZZ."VAT Prod. Posting Group"); // Post reverse advance payment VAT @@ -1360,11 +1387,12 @@ codeunit 31143 "Sales Adv. Letter-Post CZZ" GenJournalLine."Gen. Posting Type" := GenJournalLine."Gen. Posting Type"::Sale; AdvancePostingBufferCZZ.ReverseAmounts(); GenJournalLine.CopyFromAdvancePostingBufferCZZ(AdvancePostingBufferCZZ); - if not AdvancePostingParametersCZZ."Temporary Entries Only" then begin + if not AdvancePostingParametersCZZ."Temporary Entries Only" and not AdvancePostingBufferCZZ."Auxiliary Entry" then begin OnReverseAdvancePaymentVATOnBeforePost( SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, VATPostingSetup, AdvancePostingBufferCZZ, AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); GLEntryNo := RunGenJnlPostLine(GenJournalLine, GenJnlPostLine, true, true, false); + VATEntryNo := GenJnlPostLine.GetNextVATEntryNo() - 1; OnReverseAdvancePaymentVATOnAfterPost( SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, VATPostingSetup, AdvancePostingBufferCZZ, AdvancePostingParametersCZZ, GLEntryNo, GenJnlPostLine, GenJournalLine); @@ -1375,8 +1403,9 @@ codeunit 31143 "Sales Adv. Letter-Post CZZ" TempSalesAdvLetterEntryCZZGlob.CopyFromGenJnlLine(GenJournalLine); TempSalesAdvLetterEntryCZZGlob."Entry Type" := EntryType; TempSalesAdvLetterEntryCZZGlob."Sales Adv. Letter No." := SalesAdvLetterHeaderCZZ."No."; - TempSalesAdvLetterEntryCZZGlob."VAT Entry No." := GenJnlPostLine.GetNextVATEntryNo() - 1; + TempSalesAdvLetterEntryCZZGlob."VAT Entry No." := VATEntryNo; TempSalesAdvLetterEntryCZZGlob."VAT Identifier" := VATPostingSetup."VAT Identifier"; + TempSalesAdvLetterEntryCZZGlob."Auxiliary Entry" := AdvancePostingBufferCZZ."Auxiliary Entry"; TempSalesAdvLetterEntryCZZGlob.InsertNewEntry(not AdvancePostingParametersCZZ."Temporary Entries Only"); AdvancePostingBufferCZZ.ReverseAmounts(); @@ -1398,12 +1427,12 @@ codeunit 31143 "Sales Adv. Letter-Post CZZ" ExchRateVATAmount := -CalcVATAmountLCY - GenJournalLine."VAT Amount (LCY)"; if (ExchRateAmount <> 0) or (ExchRateVATAmount <> 0) then PostExchangeRate(SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, VATPostingSetup, ExchRateAmount, ExchRateVATAmount, - RelatedEntryNo, false, GenJnlPostLine, AdvancePostingParametersCZZ2); + RelatedEntryNo, false, AdvancePostingBufferCZZ."Auxiliary Entry", GenJnlPostLine, AdvancePostingParametersCZZ2); AdvancePostingParametersCZZ2."Source Code" := ''; ReverseUnrealizedExchangeRate( SalesAdvLetterEntryCZZ, SalesAdvLetterHeaderCZZ, VATPostingSetup, AdvancePostingBufferCZZ.Amount / AmountToUse, - RelatedEntryNo, GenJnlPostLine, AdvancePostingParametersCZZ2); + RelatedEntryNo, AdvancePostingBufferCZZ."Auxiliary Entry", GenJnlPostLine, AdvancePostingParametersCZZ2); end; // Post balance of reverse advance payment VAT @@ -1412,7 +1441,7 @@ codeunit 31143 "Sales Adv. Letter-Post CZZ" InitGenJournalLine(SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, AdvancePostingParametersCZZ2, GenJournalLine); GenJournalLine."Account No." := VATPostingSetup.GetSalesAdvLetterAccountCZZ(); GenJournalLine.CopyFromAdvancePostingBufferAmountsCZZ(AdvancePostingBufferCZZ); - if not AdvancePostingParametersCZZ."Temporary Entries Only" then begin + if not AdvancePostingParametersCZZ."Temporary Entries Only" and not AdvancePostingBufferCZZ."Auxiliary Entry" then begin OnReverseAdvancePaymentVATOnBeforePostBalance( SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, VATPostingSetup, AdvancePostingBufferCZZ, AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); @@ -1436,6 +1465,7 @@ codeunit 31143 "Sales Adv. Letter-Post CZZ" VATPostingSetup: Record "VAT Posting Setup"; Coef: Decimal; RelatedEntryNo: Integer; + AuxiliaryEntry: Boolean; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ") var @@ -1463,7 +1493,7 @@ codeunit 31143 "Sales Adv. Letter-Post CZZ" PostUnrealizedExchangeRate( SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, VATPostingSetup, -AmountLCY, -VATAmountLCY, - RelatedEntryNo, 0, false, GenJnlPostLine, AdvancePostingParametersCZZ); + RelatedEntryNo, 0, false, AuxiliaryEntry, GenJnlPostLine, AdvancePostingParametersCZZ); end; local procedure PostExchangeRate( @@ -1474,6 +1504,7 @@ codeunit 31143 "Sales Adv. Letter-Post CZZ" VATAmount: Decimal; RelatedEntryNo: Integer; Correction: Boolean; + AuxiliaryEntry: Boolean; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ") var @@ -1561,6 +1592,7 @@ codeunit 31143 "Sales Adv. Letter-Post CZZ" TempSalesAdvLetterEntryCZZGlob."Global Dimension 2 Code" := SalesAdvLetterEntryCZZ."Global Dimension 2 Code"; TempSalesAdvLetterEntryCZZGlob."Dimension Set ID" := SalesAdvLetterEntryCZZ."Dimension Set ID"; TempSalesAdvLetterEntryCZZGlob.Cancelled := Correction; + TempSalesAdvLetterEntryCZZGlob."Auxiliary Entry" := AuxiliaryEntry; OnPostExchangeRateOnBeforeInsertEntry( SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, VATPostingSetup, AdvancePostingParametersCZZ, TempSalesAdvLetterEntryCZZGlob); @@ -1580,6 +1612,7 @@ codeunit 31143 "Sales Adv. Letter-Post CZZ" RelatedEntryNo: Integer; RelatedDetEntryNo: Integer; Correction: Boolean; + AuxiliaryEntry: Boolean; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ") var @@ -1654,6 +1687,7 @@ codeunit 31143 "Sales Adv. Letter-Post CZZ" TempSalesAdvLetterEntryCZZGlob."Global Dimension 2 Code" := SalesAdvLetterEntryCZZ."Global Dimension 2 Code"; TempSalesAdvLetterEntryCZZGlob."Dimension Set ID" := SalesAdvLetterEntryCZZ."Dimension Set ID"; TempSalesAdvLetterEntryCZZGlob.Cancelled := Correction; + TempSalesAdvLetterEntryCZZGlob."Auxiliary Entry" := AuxiliaryEntry; OnPostUnrealizedExchangeRateOnBeforeInsertEntry( SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, VATPostingSetup, AdvancePostingParametersCZZ, TempSalesAdvLetterEntryCZZGlob); diff --git a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/UpgradeApplicationCZZ.Codeunit.al b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/UpgradeApplicationCZZ.Codeunit.al index 1f83d371c2..89f8922b77 100644 --- a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/UpgradeApplicationCZZ.Codeunit.al +++ b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/UpgradeApplicationCZZ.Codeunit.al @@ -46,6 +46,7 @@ codeunit 31088 "Upgrade Application CZZ" InstallApplicationCZZ.CopyData(); UpgradeCustomerNoInSalesAdvLetterEntries(); UpgradeAdvanceLetterApplicationAmountLCY(); + UpgradePostVATDocForReverseCharge(); end; local procedure UpgradeAdvancePaymentsReportReportSelections(); @@ -121,6 +122,21 @@ codeunit 31088 "Upgrade Application CZZ" UpgradeTag.SetUpgradeTag(UpgradeTagDefinitionsCZZ.GetAdvanceLetterApplicationAmountLCYUpgradeTag()); end; + local procedure UpgradePostVATDocForReverseCharge() + var + AdvanceLetterTemplate: Record "Advance Letter Template CZZ"; + AdvLetterTemplateDataTransfer: DataTransfer; + begin + if UpgradeTag.HasUpgradeTag(UpgradeTagDefinitionsCZZ.GetPostVATDocForReverseChargeUpgradeTag()) then + exit; + + AdvLetterTemplateDataTransfer.SetTables(Database::"Advance Letter Template CZZ", Database::"Advance Letter Template CZZ"); + AdvLetterTemplateDataTransfer.AddConstantValue(true, AdvanceLetterTemplate.FieldNo("Post VAT Doc. for Rev. Charge")); + AdvLetterTemplateDataTransfer.CopyFields(); + + UpgradeTag.SetUpgradeTag(UpgradeTagDefinitionsCZZ.GetPostVATDocForReverseChargeUpgradeTag()); + end; + local procedure GetCurrencyFactor(AdvanceLetterType: Enum "Advance Letter Type CZZ"; AdvanceLetterNo: Code[20]): Decimal var PurchAdvLetterHeader: Record "Purch. Adv. Letter Header CZZ"; diff --git a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/UpgradeTagDefinitionsCZZ.Codeunit.al b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/UpgradeTagDefinitionsCZZ.Codeunit.al index af436f1592..13f89997d8 100644 --- a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/UpgradeTagDefinitionsCZZ.Codeunit.al +++ b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/UpgradeTagDefinitionsCZZ.Codeunit.al @@ -24,6 +24,7 @@ codeunit 31089 "Upgrade Tag Definitions CZZ" PerCompanyUpgradeTags.Add(GetDataVersion210PerCompanyUpgradeTag()); PerCompanyUpgradeTags.Add(GetSalesAdvLetterEntryCustomerNoUpgradeTag()); PerCompanyUpgradeTags.Add(GetAdvanceLetterApplicationAmountLCYUpgradeTag()); + PerCompanyUpgradeTags.Add(GetPostVATDocForReverseChargeUpgradeTag()); end; procedure GetDataVersion190PerDatabaseUpgradeTag(): Code[250] @@ -65,4 +66,9 @@ codeunit 31089 "Upgrade Tag Definitions CZZ" begin exit('CZZ-478403-AdvanceLetterApplicationAmountLCYUpgradeTag-20230717'); end; + + procedure GetPostVATDocForReverseChargeUpgradeTag(): Code[250] + begin + exit('CZZ-494279-PostVATDocForReverseChargeUpgradeTag-20240426'); + end; } diff --git a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Pages/AdvanceLetterApplEditCZZ.Page.al b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Pages/AdvanceLetterApplEditCZZ.Page.al index 17afa64d7a..236139c79d 100644 --- a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Pages/AdvanceLetterApplEditCZZ.Page.al +++ b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Pages/AdvanceLetterApplEditCZZ.Page.al @@ -35,6 +35,8 @@ page 31175 "Advance Letter Appl. Edit CZZ" trigger OnLookup(var Text: Text): Boolean begin + OnBeforeOnLookupAdvanceLetterNo(Rec, TempAdvanceLetterApplication); + if Page.RunModal(Page::"Advance Letter Application CZZ", TempAdvanceLetterApplication) = Action::LookupOK then Rec.CopyFrom(TempAdvanceLetterApplication); end; @@ -156,4 +158,9 @@ page 31175 "Advance Letter Appl. Edit CZZ" end; until Rec.Next() = 0; end; + + [IntegrationEvent(true, false)] + local procedure OnBeforeOnLookupAdvanceLetterNo(var AdvanceLetterApplicationCZZ: Record "Advance Letter Application CZZ"; var TempAdvanceLetterApplicationCZZ: Record "Advance Letter Application CZZ" temporary) + begin + end; } diff --git a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Pages/AdvanceLetterTemplatesCZZ.Page.al b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Pages/AdvanceLetterTemplatesCZZ.Page.al index 18a33e3b61..5ba015d3f2 100644 --- a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Pages/AdvanceLetterTemplatesCZZ.Page.al +++ b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Pages/AdvanceLetterTemplatesCZZ.Page.al @@ -64,6 +64,11 @@ page 31179 "Advance Letter Templates CZZ" ApplicationArea = Basic, Suite; ToolTip = 'Specifies automatic post VAT document.'; } + field("Post VAT Doc. for Rev. Charge"; Rec."Post VAT Doc. for Rev. Charge") + { + ApplicationArea = Basic, Suite; + ToolTip = 'Specifies whether the VAT document will be posting for reverse charge.'; + } #if not CLEAN23 #pragma warning disable AL0432,AS0074 field("Document Report ID"; '') diff --git a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Reports/PurchaseAdvanceVATDocCZZ.Report.al b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Reports/PurchaseAdvanceVATDocCZZ.Report.al index 84328cdcca..11c21ab3b7 100644 --- a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Reports/PurchaseAdvanceVATDocCZZ.Report.al +++ b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Reports/PurchaseAdvanceVATDocCZZ.Report.al @@ -270,7 +270,7 @@ report 31017 "Purchase - Advance VAT Doc.CZZ" { DataItemLink = "Purch. Adv. Letter No." = field("Purch. Adv. Letter No."), "Document No." = field("Document No."); DataItemLinkReference = TempPurchAdvLetterEntry; - DataItemTableView = sorting("Document No.") where("Entry Type" = filter("VAT Payment" | "VAT Usage" | "VAT Close")); + DataItemTableView = sorting("Document No.") where("Entry Type" = filter("VAT Payment" | "VAT Usage" | "VAT Close"), "Auxiliary Entry" = const(false)); trigger OnAfterGetRecord() begin @@ -492,9 +492,12 @@ report 31017 "Purchase - Advance VAT Doc.CZZ" NoOfCop: Integer; local procedure IsCreditMemo(PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"): Boolean + var + DocumentAmount: Decimal; begin - exit(((PurchAdvLetterEntryCZZ.CalcDocumentAmount() < 0) and (PurchAdvLetterEntryCZZ."Entry Type" = PurchAdvLetterEntryCZZ."Entry Type"::"VAT Payment")) or - ((PurchAdvLetterEntryCZZ.CalcDocumentAmount() > 0) and (PurchAdvLetterEntryCZZ."Entry Type" = PurchAdvLetterEntryCZZ."Entry Type"::"VAT Usage")) or + DocumentAmount := PurchAdvLetterEntryCZZ.CalcDocumentAmount(); + exit(((PurchAdvLetterEntryCZZ."Entry Type" = PurchAdvLetterEntryCZZ."Entry Type"::"VAT Payment") and (DocumentAmount < 0)) or + ((PurchAdvLetterEntryCZZ."Entry Type" = PurchAdvLetterEntryCZZ."Entry Type"::"VAT Usage") and (DocumentAmount > 0)) or (PurchAdvLetterEntryCZZ."Entry Type" = PurchAdvLetterEntryCZZ."Entry Type"::"VAT Close")); end; } diff --git a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Reports/PurchaseInvoicewithAdvCZZ.Report.al b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Reports/PurchaseInvoicewithAdvCZZ.Report.al index 97de61978b..efb3090c17 100644 --- a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Reports/PurchaseInvoicewithAdvCZZ.Report.al +++ b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Reports/PurchaseInvoicewithAdvCZZ.Report.al @@ -634,7 +634,15 @@ report 31028 "Purchase-Invoice with Adv. CZZ" } trigger OnAfterGetRecord() + var + PurchAdvLetterEntryCZZVATUsage: Record "Purch. Adv. Letter Entry CZZ"; begin + PurchAdvLetterEntryCZZVATUsage.SetRange("Entry Type", PurchAdvLetterEntryCZZVATUsage."Entry Type"::"VAT Usage"); + PurchAdvLetterEntryCZZVATUsage.SetRange("Related Entry", PurchAdvanceUsage."Entry No."); + PurchAdvLetterEntryCZZVATUsage.Setrange("Auxiliary Entry", false); + if PurchAdvLetterEntryCZZVATUsage.IsEmpty() then + CurrReport.Break(); + SetRange("Purch. Adv. Letter No.", "Purch. Adv. Letter No."); SetRange("Document No.", "Document No."); FindLast(); diff --git a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Reports/SalesAdvanceVATDocCZZ.Report.al b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Reports/SalesAdvanceVATDocCZZ.Report.al index f6f667d130..04589af441 100644 --- a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Reports/SalesAdvanceVATDocCZZ.Report.al +++ b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Reports/SalesAdvanceVATDocCZZ.Report.al @@ -290,7 +290,7 @@ report 31015 "Sales - Advance VAT Doc. CZZ" { DataItemLink = "Sales Adv. Letter No." = field("Sales Adv. Letter No."), "Document No." = field("Document No."); DataItemLinkReference = TempSalesAdvLetterEntry; - DataItemTableView = sorting("Document No.") where("Entry Type" = filter("VAT Payment" | "VAT Usage" | "VAT Close")); + DataItemTableView = sorting("Document No.") where("Entry Type" = filter("VAT Payment" | "VAT Usage" | "VAT Close"), "Auxiliary Entry" = const(false)); trigger OnAfterGetRecord() begin @@ -542,9 +542,12 @@ report 31015 "Sales - Advance VAT Doc. CZZ" NoOfCop: Integer; local procedure IsCreditMemo(SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"): Boolean + var + DocumentAmount: Decimal; begin - exit(((SalesAdvLetterEntryCZZ.CalcDocumentAmount() > 0) and (SalesAdvLetterEntryCZZ."Entry Type" = SalesAdvLetterEntryCZZ."Entry Type"::"VAT Payment")) or - ((SalesAdvLetterEntryCZZ.CalcDocumentAmount() < 0) and (SalesAdvLetterEntryCZZ."Entry Type" = SalesAdvLetterEntryCZZ."Entry Type"::"VAT Usage")) or + DocumentAmount := SalesAdvLetterEntryCZZ.CalcDocumentAmount(); + exit(((SalesAdvLetterEntryCZZ."Entry Type" = SalesAdvLetterEntryCZZ."Entry Type"::"VAT Payment") and (DocumentAmount > 0)) or + ((SalesAdvLetterEntryCZZ."Entry Type" = SalesAdvLetterEntryCZZ."Entry Type"::"VAT Usage") and (DocumentAmount < 0)) or (SalesAdvLetterEntryCZZ."Entry Type" = SalesAdvLetterEntryCZZ."Entry Type"::"VAT Close")); end; } diff --git a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Reports/SalesInvoicewithAdvCZZ.Report.al b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Reports/SalesInvoicewithAdvCZZ.Report.al index 21ccb4041b..f11258edcd 100644 --- a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Reports/SalesInvoicewithAdvCZZ.Report.al +++ b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Reports/SalesInvoicewithAdvCZZ.Report.al @@ -462,7 +462,15 @@ report 31018 "Sales - Invoice with Adv. CZZ" } trigger OnAfterGetRecord() + var + SalesAdvLetterEntryCZZVATUsage: Record "Sales Adv. Letter Entry CZZ"; begin + SalesAdvLetterEntryCZZVATUsage.SetRange("Entry Type", SalesAdvLetterEntryCZZVATUsage."Entry Type"::"VAT Usage"); + SalesAdvLetterEntryCZZVATUsage.SetRange("Related Entry", SalesAdvanceUsage."Entry No."); + SalesAdvLetterEntryCZZVATUsage.Setrange("Auxiliary Entry", false); + if SalesAdvLetterEntryCZZVATUsage.IsEmpty() then + CurrReport.Break(); + SetRange("Sales Adv. Letter No.", "Sales Adv. Letter No."); SetRange("Document No.", "Document No."); FindLast(); diff --git a/Apps/CZ/AdvancePaymentsLocalization/app/Src/TableExtensions/GenJournalLineCZZ.TableExt.al b/Apps/CZ/AdvancePaymentsLocalization/app/Src/TableExtensions/GenJournalLineCZZ.TableExt.al index 762ef455c5..b26b42d62a 100644 --- a/Apps/CZ/AdvancePaymentsLocalization/app/Src/TableExtensions/GenJournalLineCZZ.TableExt.al +++ b/Apps/CZ/AdvancePaymentsLocalization/app/Src/TableExtensions/GenJournalLineCZZ.TableExt.al @@ -167,7 +167,12 @@ tableextension 31004 "Gen. Journal Line CZZ" extends "Gen. Journal Line" "Registration No. CZL" := SalesAdvLetterHeaderCZZ."Registration No."; "Tax Registration No. CZL" := SalesAdvLetterHeaderCZZ."Tax Registration No."; "System-Created Entry" := true; +#if not CLEAN25 +#pragma warning disable AL0432 OnAfterCopyGenJnlLineFromSalesAdvLetterHeaderCZZ(SalesAdvLetterHeaderCZZ, Rec); +#pragma warning restore AL0432 +#endif + OnAfterCopyGenJournalLineFromSalesAdvLetterHeaderCZZ(SalesAdvLetterHeaderCZZ, Rec); end; procedure CopyFromSalesAdvLetterEntryCZZ(SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ") @@ -176,7 +181,12 @@ tableextension 31004 "Gen. Journal Line CZZ" extends "Gen. Journal Line" "Shortcut Dimension 2 Code" := SalesAdvLetterEntryCZZ."Global Dimension 2 Code"; "Dimension Set ID" := SalesAdvLetterEntryCZZ."Dimension Set ID"; "Adv. Letter No. (Entry) CZZ" := SalesAdvLetterEntryCZZ."Sales Adv. Letter No."; +#if not CLEAN25 +#pragma warning disable AL0432 OnAfterCopyGenJnlLineFromSalesAdvLetterEntryCZZ(SalesAdvLetterEntryCZZ, Rec); +#pragma warning restore AL0432 +#endif + OnAfterCopyGenJournalLineFromSalesAdvLetterEntryCZZ(SalesAdvLetterEntryCZZ, Rec); end; procedure CopyFromPurchAdvLetterHeaderCZZ(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ") @@ -262,20 +272,58 @@ tableextension 31004 "Gen. Journal Line CZZ" extends "Gen. Journal Line" OnAfterCopyFromVendorLedgerEntryCZZ(VendorLedgerEntry, Rec); end; + procedure GetAdvanceGLAccountNoCZZ(): Code[20] + var + AdvanceLetterTemplateCZZ: Record "Advance Letter Template CZZ"; + PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; + SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; + begin + case "Account Type" of + "Account Type"::Customer: + begin + SalesAdvLetterHeaderCZZ.Get("Adv. Letter No. (Entry) CZZ"); + SalesAdvLetterHeaderCZZ.TestField("Advance Letter Code"); + AdvanceLetterTemplateCZZ.Get(SalesAdvLetterHeaderCZZ."Advance Letter Code"); + end; + "Account Type"::Vendor: + begin + PurchAdvLetterHeaderCZZ.Get("Adv. Letter No. (Entry) CZZ"); + PurchAdvLetterHeaderCZZ.TestField("Advance Letter Code"); + AdvanceLetterTemplateCZZ.Get(PurchAdvLetterHeaderCZZ."Advance Letter Code"); + end; + end; + + AdvanceLetterTemplateCZZ.TestField("Advance Letter G/L Account"); + exit(AdvanceLetterTemplateCZZ."Advance Letter G/L Account"); + end; + [IntegrationEvent(false, false)] local procedure OnAfterInitNewLineCZZ(var GenJournalLine: Record "Gen. Journal Line") begin end; - +#if not CLEAN25 + [Obsolete('Replaced by OnAfterCopyGenJournalLineFromSalesAdvLetterHeaderCZZ event.', '25.0')] [IntegrationEvent(false, false)] local procedure OnAfterCopyGenJnlLineFromSalesAdvLetterHeaderCZZ(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; Rec: Record "Gen. Journal Line") begin end; + [Obsolete('Replaced by OnAfterCopyGenJournalLineFromSalesAdvLetterEntryCZZ event.', '25.0')] [IntegrationEvent(false, false)] local procedure OnAfterCopyGenJnlLineFromSalesAdvLetterEntryCZZ(SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; Rec: Record "Gen. Journal Line") begin end; +#endif + + [IntegrationEvent(false, false)] + local procedure OnAfterCopyGenJournalLineFromSalesAdvLetterHeaderCZZ(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnAfterCopyGenJournalLineFromSalesAdvLetterEntryCZZ(SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; [IntegrationEvent(false, false)] local procedure OnAfterCopyGenJnlLineFromPurchAdvLetterHeaderCZZ(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; var GenJournalLine: Record "Gen. Journal Line") diff --git a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Tables/AdvanceLetterTemplateCZZ.Table.al b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Tables/AdvanceLetterTemplateCZZ.Table.al index fd341e1fc1..8adad0f4de 100644 --- a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Tables/AdvanceLetterTemplateCZZ.Table.al +++ b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Tables/AdvanceLetterTemplateCZZ.Table.al @@ -146,6 +146,12 @@ table 31003 "Advance Letter Template CZZ" Caption = 'Automatic Post VAT Document'; DataClassification = CustomerContent; } + field(26; "Post VAT Doc. for Rev. Charge"; Boolean) + { + Caption = 'Post VAT Document for Reverse Charge'; + DataClassification = CustomerContent; + InitValue = true; + } } keys { diff --git a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Tables/AdvancePostingBufferCZZ.Table.al b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Tables/AdvancePostingBufferCZZ.Table.al index 3f591666ae..87f6e5ce87 100644 --- a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Tables/AdvancePostingBufferCZZ.Table.al +++ b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Tables/AdvancePostingBufferCZZ.Table.al @@ -60,6 +60,10 @@ table 31013 "Advance Posting Buffer CZZ" Caption = 'VAT %'; DecimalPlaces = 1 : 1; } + field(35; "Auxiliary Entry"; Boolean) + { + Caption = 'Auxiliary Entry'; + } } keys @@ -83,6 +87,7 @@ table 31013 "Advance Posting Buffer CZZ" "Amount (ACY)" := PurchAdvLetterEntry."Amount (LCY)"; "VAT Base Amount (ACY)" := PurchAdvLetterEntry."VAT Base Amount (LCY)"; "VAT Amount (ACY)" := PurchAdvLetterEntry."VAT Amount (LCY)"; + "Auxiliary Entry" := PurchAdvLetterEntry."Auxiliary Entry"; OnAfterPrepareForPurchAdvLetterEntry(PurchAdvLetterEntry, Rec); end; @@ -115,6 +120,7 @@ table 31013 "Advance Posting Buffer CZZ" "Amount (ACY)" := SalesAdvLetterEntry."Amount (LCY)"; "VAT Base Amount (ACY)" := SalesAdvLetterEntry."VAT Base Amount (LCY)"; "VAT Amount (ACY)" := SalesAdvLetterEntry."VAT Amount (LCY)"; + "Auxiliary Entry" := SalesAdvLetterEntry."Auxiliary Entry"; OnAfterPrepareForSalesAdvLetterEntry(SalesAdvLetterEntry, Rec); end; diff --git a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Tables/PurchAdvLetterEntryCZZ.Table.al b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Tables/PurchAdvLetterEntryCZZ.Table.al index db413623a8..888b4989eb 100644 --- a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Tables/PurchAdvLetterEntryCZZ.Table.al +++ b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Tables/PurchAdvLetterEntryCZZ.Table.al @@ -189,6 +189,12 @@ table 31009 "Purch. Adv. Letter Entry CZZ" Caption = 'External Document No.'; DataClassification = CustomerContent; } + field(80; "Auxiliary Entry"; Boolean) + { + Caption = 'Auxiliary Entry'; + DataClassification = CustomerContent; + Editable = false; + } field(480; "Dimension Set ID"; Integer) { Caption = 'Dimension Set ID'; @@ -255,6 +261,7 @@ table 31009 "Purch. Adv. Letter Entry CZZ" begin PurchAdvLetterEntryCZZ.SetRange("Document No.", PurchInvHeader."No."); PurchAdvLetterEntryCZZ.SetRange("Entry Type", PurchAdvLetterEntryCZZ."Entry Type"::"VAT Usage"); + PurchAdvLetterEntryCZZ.SetRange("Auxiliary Entry", false); PurchAdvLetterEntryCZZ.SetRange(Cancelled, false); if PurchAdvLetterEntryCZZ.FindSet() then repeat diff --git a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Tables/PurchAdvLetterHeaderCZZ.Table.al b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Tables/PurchAdvLetterHeaderCZZ.Table.al index 1a1eee5d21..847bdca347 100644 --- a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Tables/PurchAdvLetterHeaderCZZ.Table.al +++ b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Tables/PurchAdvLetterHeaderCZZ.Table.al @@ -407,8 +407,8 @@ table 31008 "Purch. Adv. Letter Header CZZ" end; GetSetup(); - GeneralLedgerSetup.UpdateVATDate("Posting Date", Enum::"VAT Reporting Date"::"Posting Date", "VAT Date"); - Validate("VAT Date"); + GeneralLedgerSetup.UpdateVATDate("Posting Date", Enum::"VAT Reporting Date"::"Posting Date", "VAT Date"); + Validate("VAT Date"); GeneralLedgerSetup.UpdateOriginalDocumentVATDateCZL("Posting Date", Enum::"Default Orig.Doc. VAT Date CZL"::"Posting Date", "Original Document VAT Date"); Validate("Original Document VAT Date"); @@ -434,8 +434,8 @@ table 31008 "Purch. Adv. Letter Header CZZ" Validate("Payment Terms Code"); GetSetup(); - if GeneralLedgerSetup."VAT Reporting Date" = GeneralLedgerSetup."VAT Reporting Date"::"Document Date" then - Validate("VAT Date", "Document Date"); + if GeneralLedgerSetup."VAT Reporting Date" = GeneralLedgerSetup."VAT Reporting Date"::"Document Date" then + Validate("VAT Date", "Document Date"); GeneralLedgerSetup.UpdateOriginalDocumentVATDateCZL("Document Date", Enum::"Default Orig.Doc. VAT Date CZL"::"Document Date", "Original Document VAT Date"); Validate("Original Document VAT Date"); @@ -855,6 +855,7 @@ table 31008 "Purch. Adv. Letter Header CZZ" ConfirmChangeQst: Label 'Do you want to change %1?', Comment = '%1 = a Field Caption like Currency Code'; DocumentResetErr: Label 'You cannot reset %1 because the document still has one or more lines.', Comment = '%1 = a Field Caption like Bill-to Contact No.'; DocumentDeleteErr: Label 'You cannot delete this document. Your identification is set up to process from %1 %2 only.', Comment = '%1 = table caption of responsibility center, %2 = code of responsibility center'; + PostedEntriesExistErr: Label 'You cannot delete this document because there are posted entries.'; trigger OnInsert() begin @@ -876,10 +877,16 @@ table 31008 "Purch. Adv. Letter Header CZZ" DocumentDeleteErr, ResponsibilityCenter.TableCaption(), UserSetupManagement.GetPurchasesFilter()); + PurchAdvLetterEntryCZZ.SetRange("Purch. Adv. Letter No.", "No."); + PurchAdvLetterEntryCZZ.SetFilter("Entry Type", '<>%1', PurchAdvLetterEntryCZZ."Entry Type"::"Initial Entry"); + if not PurchAdvLetterEntryCZZ.IsEmpty() then + Error(PostedEntriesExistErr); + PurchAdvLetterLineCZZ.SetRange("Document No.", "No."); if not PurchAdvLetterLineCZZ.IsEmpty() then PurchAdvLetterLineCZZ.DeleteAll(true); + PurchAdvLetterEntryCZZ.Reset(); PurchAdvLetterEntryCZZ.SetRange("Purch. Adv. Letter No.", "No."); if not PurchAdvLetterEntryCZZ.IsEmpty() then PurchAdvLetterEntryCZZ.DeleteAll(); @@ -1474,6 +1481,7 @@ table 31008 "Purch. Adv. Letter Header CZZ" begin PurchAdvLetterEntryCZZ.SetRange("Purch. Adv. Letter No.", "No."); PurchAdvLetterEntryCZZ.SetRange(Cancelled, false); + PurchAdvLetterEntryCZZ.SetRange("Auxiliary Entry", false); PurchAdvLetterEntryCZZ.SetFilter("Entry Type", '<>%1', PurchAdvLetterEntryCZZ."Entry Type"::"Initial Entry"); PurchAdvLetterEntryCZZ.CalcSums("VAT Base Amount", "VAT Amount", "VAT Base Amount (LCY)", "VAT Amount (LCY)"); VATBaseAmount := PurchAdvLetterEntryCZZ."VAT Base Amount"; diff --git a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Tables/PurchAdvLetterLineCZZ.Table.al b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Tables/PurchAdvLetterLineCZZ.Table.al index e9735468d8..13a1e80af2 100644 --- a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Tables/PurchAdvLetterLineCZZ.Table.al +++ b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Tables/PurchAdvLetterLineCZZ.Table.al @@ -230,13 +230,13 @@ table 31011 "Purch. Adv. Letter Line CZZ" var IsHandled: Boolean; begin - TestField("VAT Prod. Posting Group"); - IsHandled := false; OnBeforeUpdateAmounts(Rec, xRec, CurrFieldNo, IsHandled); if IsHandled then exit; + TestField("VAT Prod. Posting Group"); + GetHeader(); "Amount Including VAT" := Round("Amount Including VAT", Currency."Amount Rounding Precision"); case "VAT Calculation Type" of diff --git a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Tables/SalesAdvLetterEntryCZZ.Table.al b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Tables/SalesAdvLetterEntryCZZ.Table.al index 6c624a829b..873efb6050 100644 --- a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Tables/SalesAdvLetterEntryCZZ.Table.al +++ b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Tables/SalesAdvLetterEntryCZZ.Table.al @@ -187,6 +187,12 @@ table 31006 "Sales Adv. Letter Entry CZZ" TableRelation = Customer; Editable = false; } + field(80; "Auxiliary Entry"; Boolean) + { + Caption = 'Auxiliary Entry'; + DataClassification = CustomerContent; + Editable = false; + } field(480; "Dimension Set ID"; Integer) { Caption = 'Dimension Set ID'; @@ -270,6 +276,7 @@ table 31006 "Sales Adv. Letter Entry CZZ" begin SalesAdvLetterEntryCZZ.SetRange("Document No.", SalesInvoiceHeader."No."); SalesAdvLetterEntryCZZ.SetRange("Entry Type", SalesAdvLetterEntryCZZ."Entry Type"::"VAT Usage"); + SalesAdvLetterEntryCZZ.SetRange("Auxiliary Entry", false); SalesAdvLetterEntryCZZ.SetRange(Cancelled, false); if SalesAdvLetterEntryCZZ.FindSet() then repeat diff --git a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Tables/SalesAdvLetterHeaderCZZ.Table.al b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Tables/SalesAdvLetterHeaderCZZ.Table.al index a0c6b957c8..cfc55aa612 100644 --- a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Tables/SalesAdvLetterHeaderCZZ.Table.al +++ b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Tables/SalesAdvLetterHeaderCZZ.Table.al @@ -379,8 +379,8 @@ table 31004 "Sales Adv. Letter Header CZZ" ValidateDocumentDateWithPostingDate(); GetSetup(); - GeneralLedgerSetup.UpdateVATDate("Posting Date", Enum::"VAT Reporting Date"::"Posting Date", "VAT Date"); - Validate("VAT Date"); + GeneralLedgerSetup.UpdateVATDate("Posting Date", Enum::"VAT Reporting Date"::"Posting Date", "VAT Date"); + Validate("VAT Date"); if "Currency Code" <> '' then begin UpdateCurrencyFactor(); @@ -404,8 +404,8 @@ table 31004 "Sales Adv. Letter Header CZZ" Validate("Payment Terms Code"); GetSetup(); - if GeneralLedgerSetup."VAT Reporting Date" = GeneralLedgerSetup."VAT Reporting Date"::"Document Date" then - Validate("VAT Date", "Document Date"); + if GeneralLedgerSetup."VAT Reporting Date" = GeneralLedgerSetup."VAT Reporting Date"::"Document Date" then + Validate("VAT Date", "Document Date"); end; } field(36; "VAT Date"; Date) @@ -821,10 +821,16 @@ table 31004 "Sales Adv. Letter Header CZZ" DocumentDeleteErr, ResponsibilityCenter.TableCaption(), UserSetupManagement.GetSalesFilter()); + SalesAdvLetterEntryCZZ.SetRange("Sales Adv. Letter No.", "No."); + SalesAdvLetterEntryCZZ.SetFilter("Entry Type", '<>%1', SalesAdvLetterEntryCZZ."Entry Type"::"Initial Entry"); + if not SalesAdvLetterEntryCZZ.IsEmpty() then + Error(PostedEntriesExistErr); + SalesAdvLetterLineCZZ.SetRange("Document No.", "No."); if not SalesAdvLetterLineCZZ.IsEmpty() then SalesAdvLetterLineCZZ.DeleteAll(true); + SalesAdvLetterEntryCZZ.Reset(); SalesAdvLetterEntryCZZ.SetRange("Sales Adv. Letter No.", "No."); if not SalesAdvLetterEntryCZZ.IsEmpty() then SalesAdvLetterEntryCZZ.DeleteAll(); @@ -863,6 +869,7 @@ table 31004 "Sales Adv. Letter Header CZZ" ConfirmChangeQst: Label 'Do you want to change %1?', Comment = '%1 = a Field Caption like Currency Code'; DocumentResetErr: Label 'You cannot reset %1 because the document still has one or more lines.', Comment = '%1 = a Field Caption like Bill-to Contact No.'; DocumentDeleteErr: Label 'You cannot delete this document. Your identification is set up to process from %1 %2 only.', Comment = '%1 = table caption of responsibility center, %2 = code of responsibility center'; + PostedEntriesExistErr: Label 'You cannot delete this document because there are posted entries.'; procedure AssistEdit(): Boolean var @@ -1507,6 +1514,7 @@ table 31004 "Sales Adv. Letter Header CZZ" begin SalesAdvLetterEntryCZZ.SetRange("Sales Adv. Letter No.", "No."); SalesAdvLetterEntryCZZ.SetRange(Cancelled, false); + SalesAdvLetterEntryCZZ.SetRange("Auxiliary Entry", false); SalesAdvLetterEntryCZZ.SetFilter("Entry Type", '<>%1', SalesAdvLetterEntryCZZ."Entry Type"::"Initial Entry"); SalesAdvLetterEntryCZZ.CalcSums("VAT Base Amount", "VAT Amount", "VAT Base Amount (LCY)", "VAT Amount (LCY)"); VATBaseAmount := SalesAdvLetterEntryCZZ."VAT Base Amount"; diff --git a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Tables/SalesAdvLetterLineCZZ.Table.al b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Tables/SalesAdvLetterLineCZZ.Table.al index 814a45a55d..5b1ae41ef6 100644 --- a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Tables/SalesAdvLetterLineCZZ.Table.al +++ b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Tables/SalesAdvLetterLineCZZ.Table.al @@ -195,13 +195,13 @@ table 31005 "Sales Adv. Letter Line CZZ" CurrencyExchangeRate: Record "Currency Exchange Rate"; IsHandled: Boolean; begin - TestField("VAT Prod. Posting Group"); - IsHandled := false; OnBeforeUpdateAmounts(Rec, xRec, CurrFieldNo, IsHandled); if IsHandled then exit; + TestField("VAT Prod. Posting Group"); + GetHeader(); "Amount Including VAT" := Round("Amount Including VAT", Currency."Amount Rounding Precision"); case "VAT Calculation Type" of diff --git a/Apps/CZ/AdvancePaymentsLocalization/test/Src/PurchAdvPmtRevChargeCZZ.Codeunit.al b/Apps/CZ/AdvancePaymentsLocalization/test/Src/PurchAdvPmtRevChargeCZZ.Codeunit.al new file mode 100644 index 0000000000..ae56077286 --- /dev/null +++ b/Apps/CZ/AdvancePaymentsLocalization/test/Src/PurchAdvPmtRevChargeCZZ.Codeunit.al @@ -0,0 +1,821 @@ +codeunit 148127 "Purch. Adv. Pmt.Rev.Charge CZZ" +{ + Subtype = Test; + TestPermissions = Disabled; + + trigger OnRun() + begin + // [FEATURE] [Advance Payments] [Purchase] [Feverse Charge] + isInitialized := false; + end; + + var + AdvanceLetterTemplateCZZ: Record "Advance Letter Template CZZ"; + GeneralLedgerSetup: Record "General Ledger Setup"; + Assert: Codeunit Assert; + LibraryDialogHandler: Codeunit "Library - Dialog Handler"; + LibraryPurchAdvancesCZZ: Codeunit "Library - Purch. Advances CZZ"; + LibraryPurchase: Codeunit "Library - Purchase"; + LibraryRandom: Codeunit "Library - Random"; + LibraryVariableStorage: Codeunit "Library - Variable Storage"; + isInitialized: Boolean; + + local procedure Initialize() + var + LibraryTestInitialize: Codeunit "Library - Test Initialize"; + begin + LibraryTestInitialize.OnTestInitialize(Codeunit::"Purch. Adv. Pmt.Rev.Charge CZZ"); + LibraryRandom.Init(); + LibraryVariableStorage.Clear(); + LibraryDialogHandler.ClearVariableStorage(); + if isInitialized then + exit; + LibraryTestInitialize.OnBeforeTestSuiteInitialize(Codeunit::"Purch. Adv. Pmt.Rev.Charge CZZ"); + + GeneralLedgerSetup.Get(); + GeneralLedgerSetup."VAT Reporting Date Usage" := GeneralLedgerSetup."VAT Reporting Date Usage"::Enabled; + GeneralLedgerSetup."Def. Orig. Doc. VAT Date CZL" := GeneralLedgerSetup."Def. Orig. Doc. VAT Date CZL"::"VAT Date"; + GeneralLedgerSetup."Max. VAT Difference Allowed" := 0.5; + GeneralLedgerSetup.Modify(); + + LibraryPurchAdvancesCZZ.CreatePurchAdvanceLetterTemplate(AdvanceLetterTemplateCZZ); + AdvanceLetterTemplateCZZ."Post VAT Doc. for Rev. Charge" := false; + AdvanceLetterTemplateCZZ.Modify(); + + isInitialized := true; + Commit(); + LibraryTestInitialize.OnAfterTestSuiteInitialize(Codeunit::"Purch. Adv. Pmt.Rev.Charge CZZ"); + end; + + [Test] + [HandlerFunctions('ModalVATDocumentHandler')] + procedure PurchAdvLetterWithReverseCharge() + var + PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; + PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; + PurchAdvLetterLineCZZ: Record "Purch. Adv. Letter Line CZZ"; + begin + // [SCENARIO] VAT document of purchase advance letter with reverse charge + Initialize(); + + // [GIVEN] Purchase advance letter has been created + // [GIVEN] Purchase advance letter line with reverse charge has been created + CreatePurchAdvLetter(PurchAdvLetterHeaderCZZ, PurchAdvLetterLineCZZ); + + // [GIVEN] Purchase advance letter has been released + ReleasePurchAdvLetter(PurchAdvLetterHeaderCZZ); + + // [GIVEN] Purchase advance letter has been paid in full by the general journal + CreateAndPostPaymentPurchAdvLetter(PurchAdvLetterHeaderCZZ, PurchAdvLetterLineCZZ."Amount Including VAT"); + + // [WHEN] Post payment VAT + PostPurchAdvancePaymentVAT(PurchAdvLetterHeaderCZZ); + + // [THEN] Purchase advance letter entry of "VAT Payment" type will be created + PurchAdvLetterEntryCZZ.Reset(); + PurchAdvLetterEntryCZZ.SetRange("Purch. Adv. Letter No.", PurchAdvLetterHeaderCZZ."No."); + PurchAdvLetterEntryCZZ.SetRange("Entry Type", PurchAdvLetterEntryCZZ."Entry Type"::"VAT Payment"); + Assert.RecordIsNotEmpty(PurchAdvLetterEntryCZZ); + + // [THEN] VAT entry won't be created for the purchase advance letter entry with reverse charge + PurchAdvLetterEntryCZZ.FindFirst(); + Assert.AreEqual(0, PurchAdvLetterEntryCZZ."VAT Entry No.", 'VAT entry mustn''t be created.'); + + // [THEN] Created purchase advance letter entry will be marked as auxiliary + Assert.AreEqual(true, PurchAdvLetterEntryCZZ."Auxiliary Entry", 'Auxiliary entry must be true.'); + + // [THEN] The document no. will be equal to the advance letter no. + Assert.AreEqual(PurchAdvLetterHeaderCZZ."No.", PurchAdvLetterEntryCZZ."Document No.", 'Document No. must be equal to advance letter no.'); + end; + + [Test] + [HandlerFunctions('ModalVATDocumentHandler')] + procedure LinkPurchAdvLetterWithReverseChargeToInvoice() + var + PurchaseHeader: Record "Purchase Header"; + PurchaseLine: Record "Purchase Line"; + PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; + PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; + PurchAdvLetterLineCZZ: Record "Purch. Adv. Letter Line CZZ"; + VATEntry: Record "VAT Entry"; + PostedDocumentNo: Code[20]; + begin + // [SCENARIO] Link purchase advance letter with reverse charge to purchase invoice + Initialize(); + + // [GIVEN] Purchase advance letter has been created + // [GIVEN] Purchase advance letter line with reverse charge has been created + CreatePurchAdvLetter(PurchAdvLetterHeaderCZZ, PurchAdvLetterLineCZZ); + + // [GIVEN] Purchase advance letter has been released + ReleasePurchAdvLetter(PurchAdvLetterHeaderCZZ); + + // [GIVEN] Purchase advance letter has been paid in full by the general journal + CreateAndPostPaymentPurchAdvLetter(PurchAdvLetterHeaderCZZ, PurchAdvLetterLineCZZ."Amount Including VAT"); + + // [GIVEN] Payment VAT has been posted + PostPurchAdvancePaymentVAT(PurchAdvLetterHeaderCZZ); + + // [GIVEN] Purchase invoice has been created + // [GIVEN] Purchase invoice line with reverse charge has been created + LibraryPurchAdvancesCZZ.CreatePurchInvoice( + PurchaseHeader, PurchaseLine, PurchAdvLetterHeaderCZZ."Pay-to Vendor No.", PurchAdvLetterHeaderCZZ."Posting Date", + PurchAdvLetterLineCZZ."VAT Bus. Posting Group", PurchAdvLetterLineCZZ."VAT Prod. Posting Group", '', 0, + true, PurchAdvLetterLineCZZ."Amount Including VAT"); + + // [GIVEN] Whole advance letter has been linked to purchase invoice + LibraryPurchAdvancesCZZ.LinkPurchAdvanceLetterToDocument( + PurchAdvLetterHeaderCZZ, Enum::"Adv. Letter Usage Doc.Type CZZ"::"Purchase Invoice", PurchaseHeader."No.", + PurchAdvLetterLineCZZ."Amount Including VAT", PurchAdvLetterLineCZZ."Amount Including VAT (LCY)"); + + // [WHEN] Post purchase invoice + PostedDocumentNo := PostPurchaseDocument(PurchaseHeader); + + // [THEN] VAT entries of purchase invoice will exist + VATEntry.Reset(); + VATEntry.SetRange("Document No.", PostedDocumentNo); + VATEntry.SetRange("Posting Date", PurchaseHeader."Posting Date"); + VATEntry.SetRange("Advance Letter No. CZZ", ''); + Assert.RecordIsNotEmpty(VATEntry); + + // [THEN] VAT entries of advance letter won't be exist + VATEntry.SetRange("Advance Letter No. CZZ", PurchAdvLetterHeaderCZZ."No."); + Assert.RecordIsEmpty(VATEntry); + + // [THEN] Purchase advance letter entry of "Usage" type will be created + PurchAdvLetterEntryCZZ.Reset(); + PurchAdvLetterEntryCZZ.SetRange("Purch. Adv. Letter No.", PurchAdvLetterHeaderCZZ."No."); + PurchAdvLetterEntryCZZ.CalcSums("VAT Base Amount", "VAT Base Amount (LCY)"); + Assert.AreNearlyEqual(0, PurchAdvLetterEntryCZZ."VAT Base Amount", 1, 'The sum of VAT base amount must be zero.'); + Assert.AreNearlyEqual(0, PurchAdvLetterEntryCZZ."VAT Base Amount (LCY)", 1, 'The sum of VAT base amount (LCY) must be zero.'); + + // [THEN] Purchase advance letter will be closed + PurchAdvLetterHeaderCZZ.Get(PurchAdvLetterHeaderCZZ."No."); + PurchAdvLetterHeaderCZZ.TestField(Status, PurchAdvLetterHeaderCZZ.Status::Closed); + end; + + [Test] + [HandlerFunctions('ModalVATDocumentHandler')] + procedure PurchAdvLetterWithNormalVAT() + var + PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; + PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; + PurchAdvLetterLineCZZ: Record "Purch. Adv. Letter Line CZZ"; + VATPostingSetup: Record "VAT Posting Setup"; + begin + // [SCENARIO] VAT document of purchase advance letter with normal VAT + Initialize(); + + // [GIVEN] Purchase advance letter has been created + // [GIVEN] Purchase advance letter line with normal VAT has been created + LibraryPurchAdvancesCZZ.FindVATPostingSetup(VATPostingSetup); + CreatePurchAdvLetter(PurchAdvLetterHeaderCZZ, PurchAdvLetterLineCZZ, VATPostingSetup); + + // [GIVEN] Purchase advance letter has been released + ReleasePurchAdvLetter(PurchAdvLetterHeaderCZZ); + + // [GIVEN] Purchase advance letter has been paid in full by the general journal + CreateAndPostPaymentPurchAdvLetter(PurchAdvLetterHeaderCZZ, PurchAdvLetterLineCZZ."Amount Including VAT"); + + // [WHEN] Post payment VAT + PostPurchAdvancePaymentVAT(PurchAdvLetterHeaderCZZ); + + // [THEN] Purchase advance letter entry of "VAT Payment" type will be created + PurchAdvLetterEntryCZZ.Reset(); + PurchAdvLetterEntryCZZ.SetRange("Purch. Adv. Letter No.", PurchAdvLetterHeaderCZZ."No."); + PurchAdvLetterEntryCZZ.SetRange("Entry Type", PurchAdvLetterEntryCZZ."Entry Type"::"VAT Payment"); + Assert.RecordIsNotEmpty(PurchAdvLetterEntryCZZ); + + // [THEN] Created purchase advance letter entry will have VAT amounts + PurchAdvLetterEntryCZZ.FindFirst(); + Assert.AreNotEqual(0, PurchAdvLetterEntryCZZ."VAT Amount", 'VAT amount mustn''t be zero.'); + Assert.AreNotEqual(0, PurchAdvLetterEntryCZZ."VAT Amount (LCY)", 'VAT amount (LCY) mustn''t be zero.'); + Assert.AreNotEqual(0, PurchAdvLetterEntryCZZ."VAT Base Amount", 'VAT base amount mustn''t be zero.'); + Assert.AreNotEqual(0, PurchAdvLetterEntryCZZ."VAT Base Amount (LCY)", 'VAT base amount (LCY) mustn''t be zero.'); + Assert.AreNotEqual(0, PurchAdvLetterEntryCZZ."VAT Entry No.", 'VAT entry must be created.'); + + // [THEN] Created purchase advance letter entry won't be marked as auxiliary + Assert.AreEqual(false, PurchAdvLetterEntryCZZ."Auxiliary Entry", 'Auxiliary entry must be false.'); + + // [THEN] The document no. won't be equal to the advance letter no. + Assert.AreNotEqual(PurchAdvLetterHeaderCZZ."No.", PurchAdvLetterEntryCZZ."Document No.", 'Document No. mustn''t be equal to advance letter no.'); + end; + + [Test] + [HandlerFunctions('ModalVATDocumentHandler')] + procedure PurchAdvLetterWithNormalVATAndReverseCharge() + var + PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; + PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; + PurchAdvLetterLineCZZ: Record "Purch. Adv. Letter Line CZZ"; + VATPostingSetup: Record "VAT Posting Setup"; + begin + // [SCENARIO] VAT document of purchase advance letter with normal VAT and reverse charge + Initialize(); + + // [GIVEN] Purchase advance letter has been created + // [GIVEN] Purchase advance letter line with reverse charge has been created + CreatePurchAdvLetter(PurchAdvLetterHeaderCZZ, PurchAdvLetterLineCZZ); + + // [GIVEN] Purchase advance letter line with normal VAT has been created + LibraryPurchAdvancesCZZ.FindVATPostingSetup(VATPostingSetup); + LibraryPurchAdvancesCZZ.CreatePurchAdvLetterLine( + PurchAdvLetterLineCZZ, PurchAdvLetterHeaderCZZ, + VATPostingSetup."VAT Prod. Posting Group", LibraryRandom.RandDec(1000, 2)); + + // [GIVEN] Purchase advance letter has been released + ReleasePurchAdvLetter(PurchAdvLetterHeaderCZZ); + + // [GIVEN] Purchase advance letter has been paid in full by the general journal + PurchAdvLetterHeaderCZZ.CalcFields("Amount Including VAT"); + CreateAndPostPaymentPurchAdvLetter(PurchAdvLetterHeaderCZZ, PurchAdvLetterHeaderCZZ."Amount Including VAT"); + + // [WHEN] Post payment VAT + PostPurchAdvancePaymentVAT(PurchAdvLetterHeaderCZZ); + + // [THEN] Purchase advance letter entry of "VAT Payment" type with normal VAT will be created + PurchAdvLetterEntryCZZ.Reset(); + PurchAdvLetterEntryCZZ.SetRange("Purch. Adv. Letter No.", PurchAdvLetterHeaderCZZ."No."); + PurchAdvLetterEntryCZZ.SetRange("Entry Type", PurchAdvLetterEntryCZZ."Entry Type"::"VAT Payment"); + PurchAdvLetterEntryCZZ.SetRange("VAT Calculation Type", PurchAdvLetterEntryCZZ."VAT Calculation Type"::"Normal VAT"); + Assert.RecordIsNotEmpty(PurchAdvLetterEntryCZZ); + + // [THEN] Created purchase advance letter entry with normal VAT will have VAT amounts + PurchAdvLetterEntryCZZ.FindFirst(); + Assert.AreNotEqual(0, PurchAdvLetterEntryCZZ."VAT Amount", 'VAT amount mustn''t be zero.'); + Assert.AreNotEqual(0, PurchAdvLetterEntryCZZ."VAT Amount (LCY)", 'VAT amount (LCY) mustn''t be zero.'); + Assert.AreNotEqual(0, PurchAdvLetterEntryCZZ."VAT Base Amount", 'VAT base amount mustn''t be zero.'); + Assert.AreNotEqual(0, PurchAdvLetterEntryCZZ."VAT Base Amount (LCY)", 'VAT base amount (LCY) mustn''t be zero.'); + Assert.AreNotEqual(0, PurchAdvLetterEntryCZZ."VAT Entry No.", 'VAT entry must be created.'); + + // [THEN] Purchase advance letter entry with normal VAT won't be marked as auxiliary + Assert.AreEqual(false, PurchAdvLetterEntryCZZ."Auxiliary Entry", 'Auxiliary entry must be false.'); + + // [THEN] The document no. won't be equal to the advance letter no. + Assert.AreNotEqual(PurchAdvLetterHeaderCZZ."No.", PurchAdvLetterEntryCZZ."Document No.", 'Document No. mustn''t be equal to advance letter no.'); + + // [THEN] Purchase advance letter entry of "VAT Payment" type with reverse charge will be created + PurchAdvLetterEntryCZZ.SetRange("VAT Calculation Type", PurchAdvLetterEntryCZZ."VAT Calculation Type"::"Reverse Charge VAT"); + Assert.RecordIsNotEmpty(PurchAdvLetterEntryCZZ); + + // [THEN] VAT entry won't be created for the purchase advance letter entry with reverse charge + PurchAdvLetterEntryCZZ.FindFirst(); + Assert.AreEqual(0, PurchAdvLetterEntryCZZ."VAT Entry No.", 'VAT entry mustn''t be created.'); + + // [THEN] Purchase advance letter entry with reverse charge will be marked as auxiliary + Assert.AreEqual(true, PurchAdvLetterEntryCZZ."Auxiliary Entry", 'Auxiliary entry must be true.'); + + // [THEN] The document no. won't be equal to the advance letter no. + Assert.AreNotEqual(PurchAdvLetterHeaderCZZ."No.", PurchAdvLetterEntryCZZ."Document No.", 'Document No. mustn''t be equal to advance letter no.'); + end; + + [Test] + [HandlerFunctions('ModalVATDocumentHandler')] + procedure PurchAdvLetterWithNormalVATAndReverseChargePartiallyPaid() + var + PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; + PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; + PurchAdvLetterLineCZZ: Record "Purch. Adv. Letter Line CZZ"; + VATPostingSetup: Record "VAT Posting Setup"; + PaymentAmount: Decimal; + VATPaymentAmount: Decimal; + begin + // [SCENARIO] VAT document of purchase advance letter with normal VAT and reverse charge is partially paid + Initialize(); + + // [GIVEN] Purchase advance letter has been created + // [GIVEN] Purchase advance letter line with reverse charge has been created + CreatePurchAdvLetter(PurchAdvLetterHeaderCZZ, PurchAdvLetterLineCZZ); + + // [GIVEN] Purchase advance letter line with normal VAT has been created + LibraryPurchAdvancesCZZ.FindVATPostingSetup(VATPostingSetup); + LibraryPurchAdvancesCZZ.CreatePurchAdvLetterLine( + PurchAdvLetterLineCZZ, PurchAdvLetterHeaderCZZ, + VATPostingSetup."VAT Prod. Posting Group", LibraryRandom.RandDec(1000, 2)); + + // [GIVEN] Purchase advance letter has been released + ReleasePurchAdvLetter(PurchAdvLetterHeaderCZZ); + + // [GIVEN] Purchase advance letter has been paid in half by the general journal + PurchAdvLetterHeaderCZZ.CalcFields("Amount Including VAT"); + CreateAndPostPaymentPurchAdvLetter(PurchAdvLetterHeaderCZZ, PurchAdvLetterHeaderCZZ."Amount Including VAT" / 2); + + // [WHEN] Post payment VAT + PostPurchAdvancePaymentVAT(PurchAdvLetterHeaderCZZ); + + // [THEN] Purchase advance letter entry of "VAT Payment" type with normal VAT will be created + PurchAdvLetterEntryCZZ.Reset(); + PurchAdvLetterEntryCZZ.SetRange("Purch. Adv. Letter No.", PurchAdvLetterHeaderCZZ."No."); + PurchAdvLetterEntryCZZ.SetRange("Entry Type", PurchAdvLetterEntryCZZ."Entry Type"::"VAT Payment"); + PurchAdvLetterEntryCZZ.SetRange("VAT Calculation Type", PurchAdvLetterEntryCZZ."VAT Calculation Type"::"Normal VAT"); + Assert.RecordIsNotEmpty(PurchAdvLetterEntryCZZ); + + // [THEN] Created purchase advance letter entry with normal VAT will have VAT amounts + PurchAdvLetterEntryCZZ.FindFirst(); + VATPaymentAmount := PurchAdvLetterEntryCZZ."Amount"; + Assert.AreNotEqual(0, PurchAdvLetterEntryCZZ."VAT Amount", 'VAT amount mustn''t be zero.'); + Assert.AreNotEqual(0, PurchAdvLetterEntryCZZ."VAT Amount (LCY)", 'VAT amount (LCY) mustn''t be zero.'); + Assert.AreNotEqual(0, PurchAdvLetterEntryCZZ."VAT Base Amount", 'VAT base amount mustn''t be zero.'); + Assert.AreNotEqual(0, PurchAdvLetterEntryCZZ."VAT Base Amount (LCY)", 'VAT base amount (LCY) mustn''t be zero.'); + Assert.AreNotEqual(0, PurchAdvLetterEntryCZZ."VAT Entry No.", 'VAT entry must be created.'); + + // [THEN] Created purchase advance letter entry with normal VAT won't be marked as auxiliary + Assert.AreEqual(false, PurchAdvLetterEntryCZZ."Auxiliary Entry", 'Auxiliary entry must be false.'); + + // [THEN] The document no. won't be equal to the advance letter no. + Assert.AreNotEqual(PurchAdvLetterHeaderCZZ."No.", PurchAdvLetterEntryCZZ."Document No.", 'Document No. mustn''t be equal to advance letter no.'); + + // [THEN] Purchase advance letter entry of "VAT Payment" type with reverse charge will be created + PurchAdvLetterEntryCZZ.SetRange("VAT Calculation Type", PurchAdvLetterEntryCZZ."VAT Calculation Type"::"Reverse Charge VAT"); + Assert.RecordIsNotEmpty(PurchAdvLetterEntryCZZ); + + // [THEN] VAT entry won't be created for the purchase advance letter entry with reverse charge + PurchAdvLetterEntryCZZ.FindFirst(); + VATPaymentAmount += PurchAdvLetterEntryCZZ."Amount"; + Assert.AreEqual(0, PurchAdvLetterEntryCZZ."VAT Entry No.", 'VAT entry mustn''t be created.'); + + // [THEN] Created purchase advance letter entry with reverse charge will be marked as auxiliary + Assert.AreEqual(true, PurchAdvLetterEntryCZZ."Auxiliary Entry", 'Auxiliary entry must be true.'); + + // [THEN] The document no. won't be equal to the advance letter no. + Assert.AreNotEqual(PurchAdvLetterHeaderCZZ."No.", PurchAdvLetterEntryCZZ."Document No.", 'Document No. mustn''t be equal to advance letter no.'); + + // [THEN] The sum of payment amount must be equal to the sum of VAT payment amount + PurchAdvLetterEntryCZZ.Reset(); + FindLastPaymentAdvanceLetterEntry(PurchAdvLetterHeaderCZZ."No.", PurchAdvLetterEntryCZZ); + PaymentAmount := PurchAdvLetterEntryCZZ."Amount"; + Assert.AreEqual(PaymentAmount, VATPaymentAmount, 'The sum of payment amount must be equal to the sum of VAT payment amount.'); + end; + + [Test] + [HandlerFunctions('ModalVATDocumentHandler')] + procedure LinkPurchAdvLetterWithNormalVATAndReverseChargeToInvoice1() + var + PurchaseHeader: Record "Purchase Header"; + PurchaseLine: Record "Purchase Line"; + PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; + PurchAdvLetterLineCZZ1: Record "Purch. Adv. Letter Line CZZ"; + PurchAdvLetterLineCZZ2: Record "Purch. Adv. Letter Line CZZ"; + VATEntry: Record "VAT Entry"; + VATPostingSetup: Record "VAT Posting Setup"; + PostedDocumentNo: Code[20]; + begin + // [SCENARIO] Link purchase advance letter with normal VAT and reverse charge to purchase invoice with normal VAT + Initialize(); + + // [GIVEN] Purchase advance letter has been created + // [GIVEN] Purchase advance letter line with reverse charge has been created + CreatePurchAdvLetter(PurchAdvLetterHeaderCZZ, PurchAdvLetterLineCZZ1); + + // [GIVEN] Purchase advance letter line with normal VAT has been created + LibraryPurchAdvancesCZZ.FindVATPostingSetup(VATPostingSetup); // normal VAT + LibraryPurchAdvancesCZZ.CreatePurchAdvLetterLine( + PurchAdvLetterLineCZZ2, PurchAdvLetterHeaderCZZ, + VATPostingSetup."VAT Prod. Posting Group", LibraryRandom.RandDec(1000, 2)); + + // [GIVEN] Purchase advance letter has been released + ReleasePurchAdvLetter(PurchAdvLetterHeaderCZZ); + + // [GIVEN] Purchase advance letter has been paid in full by the general journal + PurchAdvLetterHeaderCZZ.CalcFields("Amount Including VAT"); + CreateAndPostPaymentPurchAdvLetter(PurchAdvLetterHeaderCZZ, PurchAdvLetterHeaderCZZ."Amount Including VAT"); + + // [GIVEN] Payment VAT has been posted + PostPurchAdvancePaymentVAT(PurchAdvLetterHeaderCZZ); + + // [GIVEN] Purchase invoice has been created + // [GIVEN] Purchase invoice line with normal VAT has been created + LibraryPurchAdvancesCZZ.CreatePurchInvoice( + PurchaseHeader, PurchaseLine, PurchAdvLetterHeaderCZZ."Pay-to Vendor No.", PurchAdvLetterHeaderCZZ."Posting Date", + PurchAdvLetterLineCZZ2."VAT Bus. Posting Group", PurchAdvLetterLineCZZ2."VAT Prod. Posting Group", '', 0, + true, PurchAdvLetterLineCZZ2."Amount Including VAT"); + + // [GIVEN] Second line with normal VAT has been linked to purchase invoice + LibraryPurchAdvancesCZZ.LinkPurchAdvanceLetterToDocument( + PurchAdvLetterHeaderCZZ, Enum::"Adv. Letter Usage Doc.Type CZZ"::"Purchase Invoice", PurchaseHeader."No.", + PurchAdvLetterHeaderCZZ."Amount Including VAT", PurchAdvLetterHeaderCZZ."Amount Including VAT (LCY)"); + + // [WHEN] Post purchase invoice + PostedDocumentNo := PostPurchaseDocument(PurchaseHeader); + + // [THEN] VAT entries of purchase invoice will exist + VATEntry.Reset(); + VATEntry.SetRange("Document No.", PostedDocumentNo); + VATEntry.SetRange("Posting Date", PurchaseHeader."Posting Date"); + VATEntry.SetRange("Advance Letter No. CZZ", ''); + Assert.RecordIsNotEmpty(VATEntry); + + // [THEN] VAT entries of advance letter will exist + VATEntry.SetRange("Advance Letter No. CZZ", PurchAdvLetterHeaderCZZ."No."); + Assert.RecordIsNotEmpty(VATEntry); + + // [THEN] Sum of base and VAT amounts in VAT entries will be zero + VATEntry.SetRange("Advance Letter No. CZZ"); + VATEntry.CalcSums(Base, Amount); + Assert.AreEqual(0, VATEntry.Base, 'The sum of base amount in VAT Entries must be zero.'); + Assert.AreEqual(0, VATEntry.Amount, 'The sum of VAT amount in VAT Entries must be zero.'); + + // [THEN] VAT entries will have the same VAT calculation type + VATEntry.SetFilter("VAT Calculation Type", '<>%1', PurchAdvLetterLineCZZ2."VAT Calculation Type"); + Assert.RecordIsEmpty(VATEntry); + end; + + [Test] + [HandlerFunctions('ModalVATDocumentHandler')] + procedure LinkPurchAdvLetterWithNormalVATAndReverseChargeToInvoice2() + var + PurchaseHeader: Record "Purchase Header"; + PurchaseLine: Record "Purchase Line"; + PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; + PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; + PurchAdvLetterLineCZZ1: Record "Purch. Adv. Letter Line CZZ"; + PurchAdvLetterLineCZZ2: Record "Purch. Adv. Letter Line CZZ"; + VATEntry: Record "VAT Entry"; + VATPostingSetup: Record "VAT Posting Setup"; + PostedDocumentNo: Code[20]; + begin + // [SCENARIO] Link purchase advance letter with normal VAT and reverse charge to purchase invoice with reverse charge + Initialize(); + + // [GIVEN] Purchase advance letter has been created + // [GIVEN] Purchase advance letter line with reverse charge has been created + CreatePurchAdvLetter(PurchAdvLetterHeaderCZZ, PurchAdvLetterLineCZZ1); + + // [GIVEN] Purchase advance letter line with normal VAT has been created + LibraryPurchAdvancesCZZ.FindVATPostingSetup(VATPostingSetup); + LibraryPurchAdvancesCZZ.CreatePurchAdvLetterLine( + PurchAdvLetterLineCZZ2, PurchAdvLetterHeaderCZZ, + VATPostingSetup."VAT Prod. Posting Group", LibraryRandom.RandDec(1000, 2)); + + // [GIVEN] Purchase advance letter has been released + ReleasePurchAdvLetter(PurchAdvLetterHeaderCZZ); + + // [GIVEN] Purchase advance letter has been paid in full by the general journal + PurchAdvLetterHeaderCZZ.CalcFields("Amount Including VAT"); + CreateAndPostPaymentPurchAdvLetter(PurchAdvLetterHeaderCZZ, PurchAdvLetterHeaderCZZ."Amount Including VAT"); + + // [GIVEN] Payment VAT has been posted + PostPurchAdvancePaymentVAT(PurchAdvLetterHeaderCZZ); + + // [GIVEN] Purchase invoice has been created + // [GIVEN] Purchase invoice line with reverse charge has been created + LibraryPurchAdvancesCZZ.CreatePurchInvoice( + PurchaseHeader, PurchaseLine, PurchAdvLetterHeaderCZZ."Pay-to Vendor No.", PurchAdvLetterHeaderCZZ."Posting Date", + PurchAdvLetterLineCZZ1."VAT Bus. Posting Group", PurchAdvLetterLineCZZ1."VAT Prod. Posting Group", '', 0, + true, PurchAdvLetterLineCZZ1."Amount Including VAT"); + + // [GIVEN] First line with reverse charge has been linked to purchase invoice + LibraryPurchAdvancesCZZ.LinkPurchAdvanceLetterToDocument( + PurchAdvLetterHeaderCZZ, Enum::"Adv. Letter Usage Doc.Type CZZ"::"Purchase Invoice", PurchaseHeader."No.", + PurchAdvLetterHeaderCZZ."Amount Including VAT", PurchAdvLetterHeaderCZZ."Amount Including VAT (LCY)"); + + // [WHEN] Post purchase invoice + PostedDocumentNo := PostPurchaseDocument(PurchaseHeader); + + // [THEN] VAT entries of purchase invoice will exist + VATEntry.Reset(); + VATEntry.SetRange("Document No.", PostedDocumentNo); + VATEntry.SetRange("Posting Date", PurchaseHeader."Posting Date"); + VATEntry.SetRange("Advance Letter No. CZZ", ''); + Assert.RecordIsNotEmpty(VATEntry); + + // [THEN] VAT entries of advance letter won't exist + VATEntry.SetRange("Advance Letter No. CZZ", PurchAdvLetterHeaderCZZ."No."); + Assert.RecordIsEmpty(VATEntry); + + // [THEN] Sum of base and VAT amounts in VAT entries won't be zero + VATEntry.SetRange("Advance Letter No. CZZ"); + VATEntry.CalcSums(Base, Amount); + Assert.AreNotEqual(0, VATEntry.Base, 'The sum of base amount in VAT Entries mustn''t be zero.'); + Assert.AreNotEqual(0, VATEntry.Amount, 'The sum of VAT amount in VAT Entries mustn''t be zero.'); + + // [THEN] Purchase advance letter entry of "VAT Usage" type with reverse charge will be created + PurchAdvLetterEntryCZZ.Reset(); + PurchAdvLetterEntryCZZ.SetRange("Purch. Adv. Letter No.", PurchAdvLetterHeaderCZZ."No."); + PurchAdvLetterEntryCZZ.SetRange("Entry Type", PurchAdvLetterEntryCZZ."Entry Type"::"VAT Usage"); + PurchAdvLetterEntryCZZ.SetRange("VAT Calculation Type", PurchAdvLetterEntryCZZ."VAT Calculation Type"::"Reverse Charge VAT"); + PurchAdvLetterEntryCZZ.SetRange("Auxiliary Entry", true); + Assert.RecordIsNotEmpty(PurchAdvLetterEntryCZZ); + + // [THEN] Purchase advance letter entry of "VAT Usage" type with normal VAT won't be created + PurchAdvLetterEntryCZZ.Reset(); + PurchAdvLetterEntryCZZ.SetRange("Purch. Adv. Letter No.", PurchAdvLetterHeaderCZZ."No."); + PurchAdvLetterEntryCZZ.SetRange("Entry Type", PurchAdvLetterEntryCZZ."Entry Type"::"VAT Usage"); + PurchAdvLetterEntryCZZ.SetRange("VAT Calculation Type", PurchAdvLetterEntryCZZ."VAT Calculation Type"::"Normal VAT"); + Assert.RecordIsEmpty(PurchAdvLetterEntryCZZ); + end; + + [Test] + [HandlerFunctions('ModalVATDocumentHandler')] + procedure LinkPurchAdvLetterWithNormalVATAndReverseChargeToInvoice3() + var + PurchaseHeader: Record "Purchase Header"; + PurchaseLine: Record "Purchase Line"; + PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; + PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; + PurchAdvLetterLineCZZ1: Record "Purch. Adv. Letter Line CZZ"; + PurchAdvLetterLineCZZ2: Record "Purch. Adv. Letter Line CZZ"; + VATEntry: Record "VAT Entry"; + VATPostingSetup: Record "VAT Posting Setup"; + PostedDocumentNo: Code[20]; + VATPaymentAmount, VATPaymentAmountLCY : Decimal; + begin + // [SCENARIO] Link purchase advance letter with normal VAT and reverse charge to purchase invoice with normal VAT and higher amount than the advance letter + Initialize(); + + // [GIVEN] Purchase advance letter has been created + // [GIVEN] Purchase advance letter line with reverse charge has been created + CreatePurchAdvLetter(PurchAdvLetterHeaderCZZ, PurchAdvLetterLineCZZ1); + + // [GIVEN] Purchase advance letter line with normal VAT has been created + LibraryPurchAdvancesCZZ.FindVATPostingSetup(VATPostingSetup); + LibraryPurchAdvancesCZZ.CreatePurchAdvLetterLine( + PurchAdvLetterLineCZZ2, PurchAdvLetterHeaderCZZ, + VATPostingSetup."VAT Prod. Posting Group", LibraryRandom.RandDec(1000, 2)); + + // [GIVEN] Purchase advance letter has been released + ReleasePurchAdvLetter(PurchAdvLetterHeaderCZZ); + + // [GIVEN] Purchase advance letter has been paid in full by the general journal + PurchAdvLetterHeaderCZZ.CalcFields("Amount Including VAT"); + CreateAndPostPaymentPurchAdvLetter(PurchAdvLetterHeaderCZZ, PurchAdvLetterHeaderCZZ."Amount Including VAT"); + + // [GIVEN] Payment VAT has been posted + PostPurchAdvancePaymentVAT(PurchAdvLetterHeaderCZZ); + + // [GIVEN] Purchase invoice has been created + // [GIVEN] Purchase invoice line with normal VAT has been created + LibraryPurchAdvancesCZZ.CreatePurchInvoice( + PurchaseHeader, PurchaseLine, PurchAdvLetterHeaderCZZ."Pay-to Vendor No.", PurchAdvLetterHeaderCZZ."Posting Date", + PurchAdvLetterLineCZZ2."VAT Bus. Posting Group", PurchAdvLetterLineCZZ2."VAT Prod. Posting Group", '', 0, + true, PurchAdvLetterLineCZZ2."Amount Including VAT" + (PurchAdvLetterLineCZZ1."Amount Including VAT" / 2)); + + // [GIVEN] First line with normal VAT has been linked to purchase invoice + LibraryPurchAdvancesCZZ.LinkPurchAdvanceLetterToDocument( + PurchAdvLetterHeaderCZZ, Enum::"Adv. Letter Usage Doc.Type CZZ"::"Purchase Invoice", PurchaseHeader."No.", + PurchAdvLetterHeaderCZZ."Amount Including VAT", PurchAdvLetterHeaderCZZ."Amount Including VAT (LCY)"); + + // [WHEN] Post purchase invoice + PostedDocumentNo := PostPurchaseDocument(PurchaseHeader); + + // [THEN] Purchase advance letter entry of "VAT Usage" type will have amount equal to the amount of "VAT Payment" entry + PurchAdvLetterEntryCZZ.Reset(); + PurchAdvLetterEntryCZZ.SetRange("Purch. Adv. Letter No.", PurchAdvLetterHeaderCZZ."No."); + PurchAdvLetterEntryCZZ.SetRange("Entry Type", PurchAdvLetterEntryCZZ."Entry Type"::"VAT Payment"); + PurchAdvLetterEntryCZZ.SetRange("VAT Calculation Type", PurchAdvLetterLineCZZ2."VAT Calculation Type"); + PurchAdvLetterEntryCZZ.CalcSums(Amount, "Amount (LCY)"); + VATPaymentAmount := PurchAdvLetterEntryCZZ.Amount; + VATPaymentAmountLCY := PurchAdvLetterEntryCZZ."Amount (LCY)"; + + PurchAdvLetterEntryCZZ.Reset(); + PurchAdvLetterEntryCZZ.SetRange("Purch. Adv. Letter No.", PurchAdvLetterHeaderCZZ."No."); + PurchAdvLetterEntryCZZ.SetRange("Entry Type", PurchAdvLetterEntryCZZ."Entry Type"::"VAT Usage"); + PurchAdvLetterEntryCZZ.SetRange("VAT Calculation Type", PurchAdvLetterLineCZZ2."VAT Calculation Type"); + PurchAdvLetterEntryCZZ.FindFirst(); + Assert.AreEqual(VATPaymentAmount, -PurchAdvLetterEntryCZZ.Amount, 'The amount of VAT Payment entry must be equal to the amount of VAT Usage entry.'); + Assert.AreEqual(VATPaymentAmountLCY, -PurchAdvLetterEntryCZZ."Amount (LCY)", 'The amount (LCY) of VAT Payment entry must be equal to the amount (LCY) of VAT Usage entry.'); + + // [THEN] Sum of base and VAT amounts in VAT entries won't be zero + VATEntry.Reset(); + VATEntry.SetRange("Document No.", PostedDocumentNo); + VATEntry.SetRange("Posting Date", PurchaseHeader."Posting Date"); + VATEntry.CalcSums(Base, Amount); + Assert.AreNotEqual(0, VATEntry.Base, 'The sum of base amount in VAT Entries mustn''t be zero.'); + Assert.AreNotEqual(0, VATEntry.Amount, 'The sum of VAT amount in VAT Entries mustn''t be zero.'); + end; + + [Test] + [HandlerFunctions('ModalVATDocumentHandler')] + procedure LinkPurchAdvLetterWithNormalVATAndReverseChargeToInvoice4() + var + PurchaseHeader: Record "Purchase Header"; + PurchaseLine: Record "Purchase Line"; + PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; + PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; + PurchAdvLetterLineCZZ1: Record "Purch. Adv. Letter Line CZZ"; + PurchAdvLetterLineCZZ2: Record "Purch. Adv. Letter Line CZZ"; + VATPostingSetup: Record "VAT Posting Setup"; + begin + // [SCENARIO] Link purchase advance letter with normal VAT and reverse charge to purchase invoice with reverse charge and higher amount than the advance letter + Initialize(); + + // [GIVEN] Purchase advance letter has been created + // [GIVEN] Purchase advance letter line with reverse charge has been created + CreatePurchAdvLetter(PurchAdvLetterHeaderCZZ, PurchAdvLetterLineCZZ1); + + // [GIVEN] Purchase advance letter line with normal VAT has been created + LibraryPurchAdvancesCZZ.FindVATPostingSetup(VATPostingSetup); + LibraryPurchAdvancesCZZ.CreatePurchAdvLetterLine( + PurchAdvLetterLineCZZ2, PurchAdvLetterHeaderCZZ, + VATPostingSetup."VAT Prod. Posting Group", LibraryRandom.RandDec(1000, 2)); + + // [GIVEN] Purchase advance letter has been released + ReleasePurchAdvLetter(PurchAdvLetterHeaderCZZ); + + // [GIVEN] Purchase advance letter has been paid in full by the general journal + PurchAdvLetterHeaderCZZ.CalcFields("Amount Including VAT"); + CreateAndPostPaymentPurchAdvLetter(PurchAdvLetterHeaderCZZ, PurchAdvLetterHeaderCZZ."Amount Including VAT"); + + // [GIVEN] Payment VAT has been posted + PostPurchAdvancePaymentVAT(PurchAdvLetterHeaderCZZ); + + // [GIVEN] Purchase invoice has been created + // [GIVEN] Purchase invoice line with reverse charge has been created + LibraryPurchAdvancesCZZ.CreatePurchInvoice( + PurchaseHeader, PurchaseLine, PurchAdvLetterHeaderCZZ."Pay-to Vendor No.", PurchAdvLetterHeaderCZZ."Posting Date", + PurchAdvLetterLineCZZ1."VAT Bus. Posting Group", PurchAdvLetterLineCZZ1."VAT Prod. Posting Group", '', 0, + true, PurchAdvLetterLineCZZ1."Amount Including VAT" + Round(PurchAdvLetterLineCZZ2."Amount Including VAT" / 2)); + + // [GIVEN] First line with reverse charge has been linked to purchase invoice + LibraryPurchAdvancesCZZ.LinkPurchAdvanceLetterToDocument( + PurchAdvLetterHeaderCZZ, Enum::"Adv. Letter Usage Doc.Type CZZ"::"Purchase Invoice", PurchaseHeader."No.", + PurchAdvLetterHeaderCZZ."Amount Including VAT", PurchAdvLetterHeaderCZZ."Amount Including VAT (LCY)"); + + // [WHEN] Post purchase invoice + PostPurchaseDocument(PurchaseHeader); + + // [THEN] Purchase advance letter entry of "VAT Usage" type will have amount equal to part of the amount of "VAT Payment" entry with normal VAT + PurchAdvLetterEntryCZZ.Reset(); + PurchAdvLetterEntryCZZ.SetRange("Purch. Adv. Letter No.", PurchAdvLetterHeaderCZZ."No."); + PurchAdvLetterEntryCZZ.SetRange("Entry Type", PurchAdvLetterEntryCZZ."Entry Type"::"VAT Usage"); + PurchAdvLetterEntryCZZ.SetRange("VAT Calculation Type", PurchAdvLetterLineCZZ2."VAT Calculation Type"); + PurchAdvLetterEntryCZZ.FindFirst(); + Assert.AreEqual(Round(PurchAdvLetterLineCZZ2."Amount Including VAT" / 2), -PurchAdvLetterEntryCZZ.Amount, 'The amount of VAT Payment entry must be equal to the amount of VAT Usage entry.'); + + // [THEN] Purchase advance letter entry of "VAT Usage" type will have amount equal to the amount of "VAT Payment" entry with reverse charge + PurchAdvLetterEntryCZZ.Reset(); + PurchAdvLetterEntryCZZ.SetRange("Purch. Adv. Letter No.", PurchAdvLetterHeaderCZZ."No."); + PurchAdvLetterEntryCZZ.SetRange("Entry Type", PurchAdvLetterEntryCZZ."Entry Type"::"VAT Usage"); + PurchAdvLetterEntryCZZ.SetRange("VAT Calculation Type", PurchAdvLetterLineCZZ1."VAT Calculation Type"); + PurchAdvLetterEntryCZZ.SetRange("Auxiliary Entry", true); + PurchAdvLetterEntryCZZ.SetRange("VAT Entry No.", 0); + PurchAdvLetterEntryCZZ.FindFirst(); + Assert.AreEqual(PurchAdvLetterLineCZZ1."Amount Including VAT", -PurchAdvLetterEntryCZZ.Amount, 'The amount of VAT Payment entry must be equal to the amount of VAT Usage entry.'); + end; + + [Test] + [HandlerFunctions('ModalVATDocumentHandler')] + procedure LinkPurchAdvLetterWithNormalVATAndReverseChargeToInvoice5() + var + GLAccount: Record "G/L Account"; + PurchaseHeader: Record "Purchase Header"; + PurchaseLine: Record "Purchase Line"; + PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; + PurchAdvLetterLineCZZ1: Record "Purch. Adv. Letter Line CZZ"; + PurchAdvLetterLineCZZ2: Record "Purch. Adv. Letter Line CZZ"; + VATEntry: Record "VAT Entry"; + VATPostingSetup: Record "VAT Posting Setup"; + PostedDocumentNo: Code[20]; + begin + // [SCENARIO] Link purchase advance letter with normal VAT and reverse charge to purchase invoice with normal VAT and reverse charge and lower amount than the advance letter + Initialize(); + + // [GIVEN] Purchase advance letter has been created + // [GIVEN] Purchase advance letter line with reverse charge has been created + CreatePurchAdvLetter(PurchAdvLetterHeaderCZZ, PurchAdvLetterLineCZZ1); + + // [GIVEN] Purchase advance letter line with normal VAT has been created + LibraryPurchAdvancesCZZ.FindVATPostingSetup(VATPostingSetup); + LibraryPurchAdvancesCZZ.CreatePurchAdvLetterLine( + PurchAdvLetterLineCZZ2, PurchAdvLetterHeaderCZZ, + VATPostingSetup."VAT Prod. Posting Group", LibraryRandom.RandDec(1000, 2)); + + // [GIVEN] Purchase advance letter has been released + ReleasePurchAdvLetter(PurchAdvLetterHeaderCZZ); + + // [GIVEN] Purchase advance letter has been paid in full by the general journal + PurchAdvLetterHeaderCZZ.CalcFields("Amount Including VAT"); + CreateAndPostPaymentPurchAdvLetter(PurchAdvLetterHeaderCZZ, PurchAdvLetterHeaderCZZ."Amount Including VAT"); + + // [GIVEN] Payment VAT has been posted + PostPurchAdvancePaymentVAT(PurchAdvLetterHeaderCZZ); + + // [GIVEN] Purchase invoice has been created + // [GIVEN] First purchase invoice line with reverse charge has been created + LibraryPurchAdvancesCZZ.CreatePurchInvoice( + PurchaseHeader, PurchaseLine, PurchAdvLetterHeaderCZZ."Pay-to Vendor No.", PurchAdvLetterHeaderCZZ."Posting Date", + PurchAdvLetterLineCZZ1."VAT Bus. Posting Group", PurchAdvLetterLineCZZ1."VAT Prod. Posting Group", '', 0, + true, PurchAdvLetterLineCZZ1."Amount Including VAT" / 2); + + // [GIVEN] Second purchase invoice line with normal VAT has been created + LibraryPurchAdvancesCZZ.CreateGLAccount(GLAccount); + GLAccount.Validate("VAT Bus. Posting Group", PurchAdvLetterLineCZZ2."VAT Bus. Posting Group"); + GLAccount.Validate("VAT Prod. Posting Group", PurchAdvLetterLineCZZ2."VAT Prod. Posting Group"); + GLAccount.Modify(true); + + LibraryPurchase.CreatePurchaseLine(PurchaseLine, PurchaseHeader, PurchaseLine.Type::"G/L Account", GLAccount."No.", 1); + PurchaseLine.Validate("Direct Unit Cost", PurchAdvLetterLineCZZ2."Amount Including VAT" / 2); + PurchaseLine.Modify(true); + + // [GIVEN] First line with reverse charge has been linked to purchase invoice + LibraryPurchAdvancesCZZ.LinkPurchAdvanceLetterToDocument( + PurchAdvLetterHeaderCZZ, Enum::"Adv. Letter Usage Doc.Type CZZ"::"Purchase Invoice", PurchaseHeader."No.", + PurchAdvLetterHeaderCZZ."Amount Including VAT", PurchAdvLetterHeaderCZZ."Amount Including VAT (LCY)"); + + // [WHEN] Post purchase invoice + PostedDocumentNo := PostPurchaseDocument(PurchaseHeader); + + // [THEN] Sum of base and VAT amounts in VAT entries of invoice won't be zero + VATEntry.Reset(); + VATEntry.SetRange("Document No.", PostedDocumentNo); + VATEntry.SetRange("Posting Date", PurchaseHeader."Posting Date"); + VATEntry.CalcSums(Base, Amount); + Assert.AreNotEqual(0, VATEntry.Base, 'The sum of base amount in VAT Entries mustn''t be zero.'); + Assert.AreNotEqual(0, VATEntry.Amount, 'The sum of VAT amount in VAT Entries mustn''t be zero.'); + + // [THEN] Sum of base and VAT amounts in VAT entries with reverse charge VAT won't be zero + VATEntry.SetRange("VAT Calculation Type", PurchAdvLetterLineCZZ1."VAT Calculation Type"::"Reverse Charge VAT"); + VATEntry.CalcSums(Base, Amount); + Assert.AreNotEqual(0, VATEntry.Base, 'The sum of base amount in VAT Entries mustn''t be zero.'); + Assert.AreNotEqual(0, VATEntry.Amount, 'The sum of VAT amount in VAT Entries mustn''t be zero.'); + + // [THEN] Sum of base and VAT amounts in VAT entries with normal VAT will be zero + VATEntry.SetRange("VAT Calculation Type", PurchAdvLetterLineCZZ1."VAT Calculation Type"::"Normal VAT"); + VATEntry.CalcSums(Base, Amount); + Assert.AreEqual(0, VATEntry.Base, 'The sum of base amount in VAT Entries must be zero.'); + Assert.AreEqual(0, VATEntry.Amount, 'The sum of VAT amount in VAT Entries must be zero.'); + end; + + local procedure CreatePurchAdvLetter(var PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; var PurchAdvLetterLineCZZ: Record "Purch. Adv. Letter Line CZZ"; VATPostingSetup: Record "VAT Posting Setup"; VendorNo: Code[20]) + var + Vendor: Record Vendor; + begin + if VendorNo = '' then begin + LibraryPurchAdvancesCZZ.CreateVendor(Vendor); + Vendor.Validate("VAT Bus. Posting Group", VATPostingSetup."VAT Bus. Posting Group"); + Vendor.Modify(true); + VendorNo := Vendor."No."; + end; + + LibraryPurchAdvancesCZZ.CreatePurchAdvLetterHeader(PurchAdvLetterHeaderCZZ, AdvanceLetterTemplateCZZ.Code, VendorNo, ''); + LibraryPurchAdvancesCZZ.CreatePurchAdvLetterLine(PurchAdvLetterLineCZZ, PurchAdvLetterHeaderCZZ, VATPostingSetup."VAT Prod. Posting Group", LibraryRandom.RandDec(1000, 2)); + end; + + local procedure CreatePurchAdvLetter(var PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; var PurchAdvLetterLineCZZ: Record "Purch. Adv. Letter Line CZZ"; VATPostingSetup: Record "VAT Posting Setup") + begin + CreatePurchAdvLetter(PurchAdvLetterHeaderCZZ, PurchAdvLetterLineCZZ, VATPostingSetup, ''); + end; + + local procedure CreatePurchAdvLetter(var PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; var PurchAdvLetterLineCZZ: Record "Purch. Adv. Letter Line CZZ") + var + VATPostingSetup: Record "VAT Posting Setup"; + begin + LibraryPurchAdvancesCZZ.FindVATPostingSetupEU(VATPostingSetup); + CreatePurchAdvLetter(PurchAdvLetterHeaderCZZ, PurchAdvLetterLineCZZ, VATPostingSetup, ''); + end; + + local procedure CreateAndPostPaymentPurchAdvLetter(var PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; Amount: Decimal; ExchangeRate: Decimal; PostingDate: Date) + var + GenJournalLine: Record "Gen. Journal Line"; + begin + LibraryPurchAdvancesCZZ.CreatePurchAdvancePayment( + GenJournalLine, PurchAdvLetterHeaderCZZ."Pay-to Vendor No.", Amount, PurchAdvLetterHeaderCZZ."Currency Code", + PurchAdvLetterHeaderCZZ."No.", ExchangeRate, PostingDate); + LibraryPurchAdvancesCZZ.PostPurchAdvancePayment(GenJournalLine); + end; + + local procedure CreateAndPostPaymentPurchAdvLetter(var PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; Amount: Decimal) + begin + CreateAndPostPaymentPurchAdvLetter(PurchAdvLetterHeaderCZZ, Amount, 0, 0D); + end; + + local procedure ReleasePurchAdvLetter(var PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ") + begin + LibraryPurchAdvancesCZZ.ReleasePurchAdvLetter(PurchAdvLetterHeaderCZZ); + end; + + local procedure PostPurchaseDocument(var PurchaseHeader: Record "Purchase Header"): Code[20] + begin + exit(LibraryPurchase.PostPurchaseDocument(PurchaseHeader, true, true)); + end; + + local procedure FindLastPaymentAdvanceLetterEntry(AdvanceLetterNo: Code[20]; var PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ") + begin + PurchAdvLetterEntryCZZ.SetRange("Purch. Adv. Letter No.", AdvanceLetterNo); + PurchAdvLetterEntryCZZ.SetRange("Entry Type", PurchAdvLetterEntryCZZ."Entry Type"::Payment); + PurchAdvLetterEntryCZZ.FindLast(); + end; + + local procedure PostPurchAdvancePaymentVAT(var PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"); + var + PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; + begin + FindLastPaymentAdvanceLetterEntry(PurchAdvLetterHeaderCZZ."No.", PurchAdvLetterEntryCZZ); + PostPurchAdvancePaymentVAT(PurchAdvLetterEntryCZZ); + end; + + local procedure PostPurchAdvancePaymentVAT(var PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"); + begin + LibraryVariableStorage.Enqueue(WorkDate()); // original document vat date + LibraryVariableStorage.Enqueue(PurchAdvLetterEntryCZZ."Document No."); // external document no. + LibraryPurchAdvancesCZZ.PostPurchAdvancePaymentVAT(PurchAdvLetterEntryCZZ); + end; + + [ModalPageHandler] + procedure ModalVATDocumentHandler(var VATDocument: TestPage "VAT Document CZZ") + begin + VATDocument.OriginalDocumentVATDate.SetValue(LibraryVariableStorage.DequeueDate()); + VATDocument.ExternalDocumentNo.SetValue(LibraryVariableStorage.DequeueText()); + VATDocument.OK().Invoke(); + end; +} diff --git a/Apps/CZ/AdvancePaymentsLocalization/test/Src/PurchaseAdvancePaymentsCZZ.Codeunit.al b/Apps/CZ/AdvancePaymentsLocalization/test/Src/PurchaseAdvancePaymentsCZZ.Codeunit.al index 4c41130e98..8389c02b81 100644 --- a/Apps/CZ/AdvancePaymentsLocalization/test/Src/PurchaseAdvancePaymentsCZZ.Codeunit.al +++ b/Apps/CZ/AdvancePaymentsLocalization/test/Src/PurchaseAdvancePaymentsCZZ.Codeunit.al @@ -675,6 +675,9 @@ codeunit 148108 "Purchase Advance Payments CZZ" // [SCENARIO] Link purchase advance letter with reverse charge to invoice Initialize(); + // [GIVEN] Posting of VAT documents for reverse charge has been enabled + SetPostVATDocForReverseCharge(true); + // [GIVEN] Purchase advance letter has been created // [GIVEN] Purchase advance letter line with reverse charge has been created CreatePurchAdvLetterWithReverseCharge(PurchAdvLetterHeaderCZZ, PurchAdvLetterLineCZZ); @@ -724,6 +727,8 @@ codeunit 148108 "Purchase Advance Payments CZZ" // [THEN] Purchase advance letter will be closed PurchAdvLetterHeaderCZZ.Get(PurchAdvLetterHeaderCZZ."No."); PurchAdvLetterHeaderCZZ.TestField(Status, PurchAdvLetterHeaderCZZ.Status::Closed); + + SetPostVATDocForReverseCharge(false); end; [Test] @@ -2320,6 +2325,9 @@ codeunit 148108 "Purchase Advance Payments CZZ" // [SCENARIO] Create purchase advance letter with two lines with different VAT rates and link to invoice with line which is the same as second line in advance letter and one VAT rate Initialize(); + // [GIVEN] Posting of VAT documents for reverse charge has been enabled + SetPostVATDocForReverseCharge(true); + // [GIVEN] Purchase advance letter has been created // [GIVEN] Purchase advance letter line with normal VAT has been created CreatePurchAdvLetter(PurchAdvLetterHeaderCZZ, PurchAdvLetterLineCZZ1); @@ -2379,6 +2387,8 @@ codeunit 148108 "Purchase Advance Payments CZZ" VATEntry.SetRange("VAT Bus. Posting Group", VATEntry."VAT Bus. Posting Group"); VATEntry.SetRange("VAT Prod. Posting Group", VATEntry."VAT Prod. Posting Group"); Assert.RecordCount(VATEntry, VATEntryCount); + + SetPostVATDocForReverseCharge(false); end; [Test] @@ -2397,6 +2407,9 @@ codeunit 148108 "Purchase Advance Payments CZZ" // [SCENARIO] Create purchase advance letter with two lines with different VAT rates and link to invoice with line which has the higher amount as first line in advance letter and one VAT rate Initialize(); + // [GIVEN] Posting of VAT documents for reverse charge has been enabled + SetPostVATDocForReverseCharge(true); + // [GIVEN] Purchase advance letter has been created // [GIVEN] Purchase advance letter line with normal VAT has been created CreatePurchAdvLetter(PurchAdvLetterHeaderCZZ, PurchAdvLetterLineCZZ1); @@ -2451,6 +2464,8 @@ codeunit 148108 "Purchase Advance Payments CZZ" purchAdvLetterEntryCZZ2.SetRange("VAT Prod. Posting Group", PurchAdvLetterLineCZZ2."VAT Prod. Posting Group"); purchAdvLetterEntryCZZ2.SetRange("Entry Type", purchAdvLetterEntryCZZ2."Entry Type"::"VAT Usage"); Assert.RecordIsNotEmpty(PurchAdvLetterEntryCZZ2); + + SetPostVATDocForReverseCharge(false); end; [Test] @@ -2469,6 +2484,9 @@ codeunit 148108 "Purchase Advance Payments CZZ" // [SCENARIO] Create purchase advance letter with two lines with different VAT rates and link to invoice with line which has the higher amount as second line in advance letter and one VAT rate Initialize(); + // [GIVEN] Posting of VAT documents for reverse charge has been enabled + SetPostVATDocForReverseCharge(true); + // [GIVEN] Purchase advance letter has been created // [GIVEN] Purchase advance letter line with normal VAT has been created CreatePurchAdvLetter(PurchAdvLetterHeaderCZZ, PurchAdvLetterLineCZZ1); @@ -2523,6 +2541,8 @@ codeunit 148108 "Purchase Advance Payments CZZ" purchAdvLetterEntryCZZ2.SetRange("VAT Prod. Posting Group", PurchAdvLetterLineCZZ1."VAT Prod. Posting Group"); purchAdvLetterEntryCZZ2.SetRange("Entry Type", purchAdvLetterEntryCZZ2."Entry Type"::"VAT Usage"); Assert.RecordIsNotEmpty(PurchAdvLetterEntryCZZ2); + + SetPostVATDocForReverseCharge(false); end; [Test] @@ -2543,6 +2563,9 @@ codeunit 148108 "Purchase Advance Payments CZZ" // [SCENARIO] Create purchase advance letter with two lines with different VAT rates and link to invoice with two lines which have the lower amounts as lines in advance letter Initialize(); + // [GIVEN] Posting of VAT documents for reverse charge has been enabled + SetPostVATDocForReverseCharge(true); + // [GIVEN] Purchase advance letter has been created // [GIVEN] Purchase advance letter line with normal VAT has been created CreatePurchAdvLetter(PurchAdvLetterHeaderCZZ, PurchAdvLetterLineCZZ1); @@ -2616,6 +2639,8 @@ codeunit 148108 "Purchase Advance Payments CZZ" VATEntry.CalcSums(Base, Amount); Assert.AreEqual(0, VATEntry.Base, 'The sum of base amount in VAT Entries must be zero.'); Assert.AreEqual(0, VATEntry.Amount, 'The sum of VAT amount in VAT Entries must be zero.'); + + SetPostVATDocForReverseCharge(false); end; local procedure CreatePurchAdvLetterBase(var PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; var PurchAdvLetterLineCZZ: Record "Purch. Adv. Letter Line CZZ"; VendorNo: Code[20]; CurrencyCode: Code[10]; VATPostingSetup: Record "VAT Posting Setup") @@ -2844,6 +2869,12 @@ codeunit 148108 "Purchase Advance Payments CZZ" LibraryCashDocumentCZP.PostCashDocumentCZP(CashDocumentHeaderCZP); end; + local procedure SetPostVATDocForReverseCharge(Value: Boolean) + begin + AdvanceLetterTemplateCZZ."Post VAT Doc. for Rev. Charge" := Value; + AdvanceLetterTemplateCZZ.Modify(); + end; + local procedure FindNextVATPostingSetup(var VATPostingSetup: Record "VAT Posting Setup") begin LibraryERM.FindVATPostingSetup(VATPostingSetup, VATPostingSetup."VAT Calculation Type"::"Normal VAT"); diff --git a/Apps/CZ/AdvancePaymentsLocalization/test/Src/SalesAdvPmtRevChargeCZZ.Codeunit.al b/Apps/CZ/AdvancePaymentsLocalization/test/Src/SalesAdvPmtRevChargeCZZ.Codeunit.al new file mode 100644 index 0000000000..d703b760b6 --- /dev/null +++ b/Apps/CZ/AdvancePaymentsLocalization/test/Src/SalesAdvPmtRevChargeCZZ.Codeunit.al @@ -0,0 +1,755 @@ +codeunit 148129 "Sales Adv. Pmt.Rev.Charge CZZ" +{ + Subtype = Test; + TestPermissions = Disabled; + + trigger OnRun() + begin + // [FEATURE] [Advance Payments] [Sales] [Feverse Charge] + isInitialized := false; + end; + + var + AdvanceLetterTemplateCZZ: Record "Advance Letter Template CZZ"; + GeneralLedgerSetup: Record "General Ledger Setup"; + Assert: Codeunit Assert; + LibraryDialogHandler: Codeunit "Library - Dialog Handler"; + LibrarySalesAdvancesCZZ: Codeunit "Library - Sales Advances CZZ"; + LibrarySales: Codeunit "Library - Sales"; + LibraryRandom: Codeunit "Library - Random"; + LibraryVariableStorage: Codeunit "Library - Variable Storage"; + isInitialized: Boolean; + + local procedure Initialize() + var + LibraryTestInitialize: Codeunit "Library - Test Initialize"; + begin + LibraryTestInitialize.OnTestInitialize(Codeunit::"Sales Adv. Pmt.Rev.Charge CZZ"); + LibraryRandom.Init(); + LibraryVariableStorage.Clear(); + LibraryDialogHandler.ClearVariableStorage(); + if isInitialized then + exit; + LibraryTestInitialize.OnBeforeTestSuiteInitialize(Codeunit::"Sales Adv. Pmt.Rev.Charge CZZ"); + + GeneralLedgerSetup.Get(); + GeneralLedgerSetup."VAT Reporting Date Usage" := GeneralLedgerSetup."VAT Reporting Date Usage"::Enabled; + GeneralLedgerSetup."Def. Orig. Doc. VAT Date CZL" := GeneralLedgerSetup."Def. Orig. Doc. VAT Date CZL"::"VAT Date"; + GeneralLedgerSetup."Max. VAT Difference Allowed" := 0.5; + GeneralLedgerSetup.Modify(); + + LibrarySalesAdvancesCZZ.CreateSalesAdvanceLetterTemplate(AdvanceLetterTemplateCZZ); + AdvanceLetterTemplateCZZ."Post VAT Doc. for Rev. Charge" := false; + AdvanceLetterTemplateCZZ.Modify(); + + isInitialized := true; + Commit(); + LibraryTestInitialize.OnAfterTestSuiteInitialize(Codeunit::"Sales Adv. Pmt.Rev.Charge CZZ"); + end; + + [Test] + procedure SalesAdvLetterWithReverseCharge() + var + SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; + SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; + SalesAdvLetterLineCZZ: Record "Sales Adv. Letter Line CZZ"; + begin + // [SCENARIO] VAT document of sales advance letter with reverse charge + Initialize(); + + // [GIVEN] Sales advance letter has been created + // [GIVEN] Sales advance letter line with reverse charge has been created + CreateSalesAdvLetter(SalesAdvLetterHeaderCZZ, SalesAdvLetterLineCZZ); + + // [GIVEN] Sales advance letter has been released + ReleaseSalesAdvLetter(SalesAdvLetterHeaderCZZ); + + // [WHEN] Pay sales advance letter in full by the general journal + CreateAndPostPaymentSalesAdvLetter(SalesAdvLetterHeaderCZZ, -SalesAdvLetterLineCZZ."Amount Including VAT"); + + // [THEN] Sales advance letter entry of "VAT Payment" type will be created + SalesAdvLetterEntryCZZ.Reset(); + SalesAdvLetterEntryCZZ.SetRange("Sales Adv. Letter No.", SalesAdvLetterHeaderCZZ."No."); + SalesAdvLetterEntryCZZ.SetRange("Entry Type", SalesAdvLetterEntryCZZ."Entry Type"::"VAT Payment"); + Assert.RecordIsNotEmpty(SalesAdvLetterEntryCZZ); + + // [THEN] VAT entry won't be created for the sales advance letter entry with reverse charge + SalesAdvLetterEntryCZZ.FindFirst(); + Assert.AreEqual(0, SalesAdvLetterEntryCZZ."VAT Entry No.", 'VAT entry mustn''t be created.'); + + // [THEN] Created sales advance letter entry will be marked as auxiliary + Assert.AreEqual(true, SalesAdvLetterEntryCZZ."Auxiliary Entry", 'Auxiliary entry must be true.'); + + // [THEN] The document no. will be equal to the advance letter no. + Assert.AreEqual(SalesAdvLetterHeaderCZZ."No.", SalesAdvLetterEntryCZZ."Document No.", 'Document No. must be equal to advance letter no.'); + end; + + [Test] + procedure LinkSalesAdvLetterWithReverseChargeToInvoice() + var + SalesHeader: Record "Sales Header"; + SalesLine: Record "Sales Line"; + SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; + SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; + SalesAdvLetterLineCZZ: Record "Sales Adv. Letter Line CZZ"; + VATEntry: Record "VAT Entry"; + PostedDocumentNo: Code[20]; + begin + // [SCENARIO] Link sales advance letter with reverse charge to sales invoice + Initialize(); + + // [GIVEN] Sales advance letter has been created + // [GIVEN] Sales advance letter line with reverse charge has been created + CreateSalesAdvLetter(SalesAdvLetterHeaderCZZ, SalesAdvLetterLineCZZ); + + // [GIVEN] Sales advance letter has been released + ReleaseSalesAdvLetter(SalesAdvLetterHeaderCZZ); + + // [GIVEN] Sales advance letter has been paid in full by the general journal + CreateAndPostPaymentSalesAdvLetter(SalesAdvLetterHeaderCZZ, -SalesAdvLetterLineCZZ."Amount Including VAT"); + + // [GIVEN] Sales invoice has been created + // [GIVEN] Sales invoice line with reverse charge has been created + LibrarySalesAdvancesCZZ.CreateSalesInvoice( + SalesHeader, SalesLine, SalesAdvLetterHeaderCZZ."Bill-to Customer No.", SalesAdvLetterHeaderCZZ."Posting Date", + SalesAdvLetterLineCZZ."VAT Bus. Posting Group", SalesAdvLetterLineCZZ."VAT Prod. Posting Group", '', 0, + true, SalesAdvLetterLineCZZ."Amount Including VAT"); + + // [GIVEN] Whole advance letter has been linked to sales invoice + LibrarySalesAdvancesCZZ.LinkSalesAdvanceLetterToDocument( + SalesAdvLetterHeaderCZZ, Enum::"Adv. Letter Usage Doc.Type CZZ"::"Sales Invoice", SalesHeader."No.", + SalesAdvLetterLineCZZ."Amount Including VAT", SalesAdvLetterLineCZZ."Amount Including VAT (LCY)"); + + // [WHEN] Post sales invoice + PostedDocumentNo := PostSalesDocument(SalesHeader); + + // [THEN] VAT entries of sales invoice will exist + VATEntry.Reset(); + VATEntry.SetRange("Document No.", PostedDocumentNo); + VATEntry.SetRange("Posting Date", SalesHeader."Posting Date"); + VATEntry.SetRange("Advance Letter No. CZZ", ''); + Assert.RecordIsNotEmpty(VATEntry); + + // [THEN] VAT entries of advance letter won't be exist + VATEntry.SetRange("Advance Letter No. CZZ", SalesAdvLetterHeaderCZZ."No."); + Assert.RecordIsEmpty(VATEntry); + + // [THEN] Sales advance letter entry of "Usage" type will be created + SalesAdvLetterEntryCZZ.Reset(); + SalesAdvLetterEntryCZZ.SetRange("Sales Adv. Letter No.", SalesAdvLetterHeaderCZZ."No."); + SalesAdvLetterEntryCZZ.CalcSums("VAT Base Amount", "VAT Base Amount (LCY)"); + Assert.AreNearlyEqual(0, SalesAdvLetterEntryCZZ."VAT Base Amount", 1, 'The sum of VAT base amount must be zero.'); + Assert.AreNearlyEqual(0, SalesAdvLetterEntryCZZ."VAT Base Amount (LCY)", 1, 'The sum of VAT base amount (LCY) must be zero.'); + + // [THEN] Sales advance letter will be closed + SalesAdvLetterHeaderCZZ.Get(SalesAdvLetterHeaderCZZ."No."); + SalesAdvLetterHeaderCZZ.TestField(Status, SalesAdvLetterHeaderCZZ.Status::Closed); + end; + + [Test] + procedure SalesAdvLetterWithNormalVAT() + var + SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; + SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; + SalesAdvLetterLineCZZ: Record "Sales Adv. Letter Line CZZ"; + VATPostingSetup: Record "VAT Posting Setup"; + begin + // [SCENARIO] VAT document of sales advance letter with normal VAT + Initialize(); + + // [GIVEN] Sales advance letter has been created + // [GIVEN] Sales advance letter line with normal VAT has been created + LibrarySalesAdvancesCZZ.FindVATPostingSetup(VATPostingSetup); + CreateSalesAdvLetter(SalesAdvLetterHeaderCZZ, SalesAdvLetterLineCZZ, VATPostingSetup); + + // [GIVEN] Sales advance letter has been released + ReleaseSalesAdvLetter(SalesAdvLetterHeaderCZZ); + + // [WHEN] Pay sales advance letter in full by the general journal + CreateAndPostPaymentSalesAdvLetter(SalesAdvLetterHeaderCZZ, -SalesAdvLetterLineCZZ."Amount Including VAT"); + + // [THEN] Sales advance letter entry of "VAT Payment" type will be created + SalesAdvLetterEntryCZZ.Reset(); + SalesAdvLetterEntryCZZ.SetRange("Sales Adv. Letter No.", SalesAdvLetterHeaderCZZ."No."); + SalesAdvLetterEntryCZZ.SetRange("Entry Type", SalesAdvLetterEntryCZZ."Entry Type"::"VAT Payment"); + Assert.RecordIsNotEmpty(SalesAdvLetterEntryCZZ); + + // [THEN] Created sales advance letter entry will have VAT amounts + SalesAdvLetterEntryCZZ.FindFirst(); + Assert.AreNotEqual(0, SalesAdvLetterEntryCZZ."VAT Amount", 'VAT amount mustn''t be zero.'); + Assert.AreNotEqual(0, SalesAdvLetterEntryCZZ."VAT Amount (LCY)", 'VAT amount (LCY) mustn''t be zero.'); + Assert.AreNotEqual(0, SalesAdvLetterEntryCZZ."VAT Base Amount", 'VAT base amount mustn''t be zero.'); + Assert.AreNotEqual(0, SalesAdvLetterEntryCZZ."VAT Base Amount (LCY)", 'VAT base amount (LCY) mustn''t be zero.'); + Assert.AreNotEqual(0, SalesAdvLetterEntryCZZ."VAT Entry No.", 'VAT entry must be created.'); + + // [THEN] Created sales advance letter entry won't be marked as auxiliary + Assert.AreEqual(false, SalesAdvLetterEntryCZZ."Auxiliary Entry", 'Auxiliary entry must be false.'); + + // [THEN] The document no. won't be equal to the advance letter no. + Assert.AreNotEqual(SalesAdvLetterHeaderCZZ."No.", SalesAdvLetterEntryCZZ."Document No.", 'Document No. mustn''t be equal to advance letter no.'); + end; + + [Test] + procedure SalesAdvLetterWithNormalVATAndReverseCharge() + var + SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; + SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; + SalesAdvLetterLineCZZ: Record "Sales Adv. Letter Line CZZ"; + VATPostingSetup: Record "VAT Posting Setup"; + begin + // [SCENARIO] VAT document of sales advance letter with normal VAT and reverse charge + Initialize(); + + // [GIVEN] Sales advance letter has been created + // [GIVEN] Sales advance letter line with reverse charge has been created + CreateSalesAdvLetter(SalesAdvLetterHeaderCZZ, SalesAdvLetterLineCZZ); + + // [GIVEN] Sales advance letter line with normal VAT has been created + LibrarySalesAdvancesCZZ.FindVATPostingSetup(VATPostingSetup); + LibrarySalesAdvancesCZZ.CreateSalesAdvLetterLine( + SalesAdvLetterLineCZZ, SalesAdvLetterHeaderCZZ, + VATPostingSetup."VAT Prod. Posting Group", LibraryRandom.RandDec(1000, 2)); + + // [GIVEN] Sales advance letter has been released + ReleaseSalesAdvLetter(SalesAdvLetterHeaderCZZ); + + // [WHEN] Pay sales advance letter in full by the general journal + SalesAdvLetterHeaderCZZ.CalcFields("Amount Including VAT"); + CreateAndPostPaymentSalesAdvLetter(SalesAdvLetterHeaderCZZ, -SalesAdvLetterHeaderCZZ."Amount Including VAT"); + + // [THEN] Sales advance letter entry of "VAT Payment" type with normal VAT will be created + SalesAdvLetterEntryCZZ.Reset(); + SalesAdvLetterEntryCZZ.SetRange("Sales Adv. Letter No.", SalesAdvLetterHeaderCZZ."No."); + SalesAdvLetterEntryCZZ.SetRange("Entry Type", SalesAdvLetterEntryCZZ."Entry Type"::"VAT Payment"); + SalesAdvLetterEntryCZZ.SetRange("VAT Calculation Type", SalesAdvLetterEntryCZZ."VAT Calculation Type"::"Normal VAT"); + Assert.RecordIsNotEmpty(SalesAdvLetterEntryCZZ); + + // [THEN] Created sales advance letter entry with normal VAT will have VAT amounts + SalesAdvLetterEntryCZZ.FindFirst(); + Assert.AreNotEqual(0, SalesAdvLetterEntryCZZ."VAT Amount", 'VAT amount mustn''t be zero.'); + Assert.AreNotEqual(0, SalesAdvLetterEntryCZZ."VAT Amount (LCY)", 'VAT amount (LCY) mustn''t be zero.'); + Assert.AreNotEqual(0, SalesAdvLetterEntryCZZ."VAT Base Amount", 'VAT base amount mustn''t be zero.'); + Assert.AreNotEqual(0, SalesAdvLetterEntryCZZ."VAT Base Amount (LCY)", 'VAT base amount (LCY) mustn''t be zero.'); + Assert.AreNotEqual(0, SalesAdvLetterEntryCZZ."VAT Entry No.", 'VAT entry must be created.'); + + // [THEN] Sales advance letter entry with normal VAT won't be marked as auxiliary + Assert.AreEqual(false, SalesAdvLetterEntryCZZ."Auxiliary Entry", 'Auxiliary entry must be false.'); + + // [THEN] The document no. won't be equal to the advance letter no. + Assert.AreNotEqual(SalesAdvLetterHeaderCZZ."No.", SalesAdvLetterEntryCZZ."Document No.", 'Document No. mustn''t be equal to advance letter no.'); + + // [THEN] Sales advance letter entry of "VAT Payment" type with reverse charge will be created + SalesAdvLetterEntryCZZ.SetRange("VAT Calculation Type", SalesAdvLetterEntryCZZ."VAT Calculation Type"::"Reverse Charge VAT"); + Assert.RecordIsNotEmpty(SalesAdvLetterEntryCZZ); + + // [THEN] VAT entry won't be created for the sales advance letter entry with reverse charge + SalesAdvLetterEntryCZZ.FindFirst(); + Assert.AreEqual(0, SalesAdvLetterEntryCZZ."VAT Entry No.", 'VAT entry mustn''t be created.'); + + // [THEN] Sales advance letter entry with reverse charge will be marked as auxiliary + Assert.AreEqual(true, SalesAdvLetterEntryCZZ."Auxiliary Entry", 'Auxiliary entry must be true.'); + + // [THEN] The document no. won't be equal to the advance letter no. + Assert.AreNotEqual(SalesAdvLetterHeaderCZZ."No.", SalesAdvLetterEntryCZZ."Document No.", 'Document No. mustn''t be equal to advance letter no.'); + end; + + [Test] + procedure SalesAdvLetterWithNormalVATAndReverseChargePartiallyPaid() + var + SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; + SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; + SalesAdvLetterLineCZZ: Record "Sales Adv. Letter Line CZZ"; + VATPostingSetup: Record "VAT Posting Setup"; + PaymentAmount: Decimal; + VATPaymentAmount: Decimal; + begin + // [SCENARIO] VAT document of sales advance letter with normal VAT and reverse charge is partially paid + Initialize(); + + // [GIVEN] Sales advance letter has been created + // [GIVEN] Sales advance letter line with reverse charge has been created + CreateSalesAdvLetter(SalesAdvLetterHeaderCZZ, SalesAdvLetterLineCZZ); + + // [GIVEN] Sales advance letter line with normal VAT has been created + LibrarySalesAdvancesCZZ.FindVATPostingSetup(VATPostingSetup); + LibrarySalesAdvancesCZZ.CreateSalesAdvLetterLine( + SalesAdvLetterLineCZZ, SalesAdvLetterHeaderCZZ, + VATPostingSetup."VAT Prod. Posting Group", LibraryRandom.RandDec(1000, 2)); + + // [GIVEN] Sales advance letter has been released + ReleaseSalesAdvLetter(SalesAdvLetterHeaderCZZ); + + // [WHEN] Pay sales advance letter in half by the general journal + SalesAdvLetterHeaderCZZ.CalcFields("Amount Including VAT"); + CreateAndPostPaymentSalesAdvLetter(SalesAdvLetterHeaderCZZ, -SalesAdvLetterHeaderCZZ."Amount Including VAT" / 2); + + // [THEN] Sales advance letter entry of "VAT Payment" type with normal VAT will be created + SalesAdvLetterEntryCZZ.Reset(); + SalesAdvLetterEntryCZZ.SetRange("Sales Adv. Letter No.", SalesAdvLetterHeaderCZZ."No."); + SalesAdvLetterEntryCZZ.SetRange("Entry Type", SalesAdvLetterEntryCZZ."Entry Type"::"VAT Payment"); + SalesAdvLetterEntryCZZ.SetRange("VAT Calculation Type", SalesAdvLetterEntryCZZ."VAT Calculation Type"::"Normal VAT"); + Assert.RecordIsNotEmpty(SalesAdvLetterEntryCZZ); + + // [THEN] Created sales advance letter entry with normal VAT will have VAT amounts + SalesAdvLetterEntryCZZ.FindFirst(); + VATPaymentAmount := SalesAdvLetterEntryCZZ."Amount"; + Assert.AreNotEqual(0, SalesAdvLetterEntryCZZ."VAT Amount", 'VAT amount mustn''t be zero.'); + Assert.AreNotEqual(0, SalesAdvLetterEntryCZZ."VAT Amount (LCY)", 'VAT amount (LCY) mustn''t be zero.'); + Assert.AreNotEqual(0, SalesAdvLetterEntryCZZ."VAT Base Amount", 'VAT base amount mustn''t be zero.'); + Assert.AreNotEqual(0, SalesAdvLetterEntryCZZ."VAT Base Amount (LCY)", 'VAT base amount (LCY) mustn''t be zero.'); + Assert.AreNotEqual(0, SalesAdvLetterEntryCZZ."VAT Entry No.", 'VAT entry must be created.'); + + // [THEN] Created sales advance letter entry with normal VAT won't be marked as auxiliary + Assert.AreEqual(false, SalesAdvLetterEntryCZZ."Auxiliary Entry", 'Auxiliary entry must be false.'); + + // [THEN] The document no. won't be equal to the advance letter no. + Assert.AreNotEqual(SalesAdvLetterHeaderCZZ."No.", SalesAdvLetterEntryCZZ."Document No.", 'Document No. mustn''t be equal to advance letter no.'); + + // [THEN] Sales advance letter entry of "VAT Payment" type with reverse charge will be created + SalesAdvLetterEntryCZZ.SetRange("VAT Calculation Type", SalesAdvLetterEntryCZZ."VAT Calculation Type"::"Reverse Charge VAT"); + Assert.RecordIsNotEmpty(SalesAdvLetterEntryCZZ); + + // [THEN] VAT entry won't be created for the sales advance letter entry with reverse charge + SalesAdvLetterEntryCZZ.FindFirst(); + VATPaymentAmount += SalesAdvLetterEntryCZZ."Amount"; + Assert.AreEqual(0, SalesAdvLetterEntryCZZ."VAT Entry No.", 'VAT entry mustn''t be created.'); + + // [THEN] Created sales advance letter entry with reverse charge will be marked as auxiliary + Assert.AreEqual(true, SalesAdvLetterEntryCZZ."Auxiliary Entry", 'Auxiliary entry must be true.'); + + // [THEN] The document no. won't be equal to the advance letter no. + Assert.AreNotEqual(SalesAdvLetterHeaderCZZ."No.", SalesAdvLetterEntryCZZ."Document No.", 'Document No. mustn''t be equal to advance letter no.'); + + // [THEN] The sum of payment amount must be equal to the sum of VAT payment amount + SalesAdvLetterEntryCZZ.Reset(); + FindLastPaymentAdvanceLetterEntry(SalesAdvLetterHeaderCZZ."No.", SalesAdvLetterEntryCZZ); + PaymentAmount := SalesAdvLetterEntryCZZ."Amount"; + Assert.AreEqual(PaymentAmount, VATPaymentAmount, 'The sum of payment amount must be equal to the sum of VAT payment amount.'); + end; + + [Test] + procedure LinkSalesAdvLetterWithNormalVATAndReverseChargeToInvoice1() + var + SalesHeader: Record "Sales Header"; + SalesLine: Record "Sales Line"; + SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; + SalesAdvLetterLineCZZ1: Record "Sales Adv. Letter Line CZZ"; + SalesAdvLetterLineCZZ2: Record "Sales Adv. Letter Line CZZ"; + VATEntry: Record "VAT Entry"; + VATPostingSetup: Record "VAT Posting Setup"; + PostedDocumentNo: Code[20]; + begin + // [SCENARIO] Link sales advance letter with normal VAT and reverse charge to sales invoice with normal VAT + Initialize(); + + // [GIVEN] Sales advance letter has been created + // [GIVEN] Sales advance letter line with reverse charge has been created + CreateSalesAdvLetter(SalesAdvLetterHeaderCZZ, SalesAdvLetterLineCZZ1); + + // [GIVEN] Sales advance letter line with normal VAT has been created + LibrarySalesAdvancesCZZ.FindVATPostingSetup(VATPostingSetup); // normal VAT + LibrarySalesAdvancesCZZ.CreateSalesAdvLetterLine( + SalesAdvLetterLineCZZ2, SalesAdvLetterHeaderCZZ, + VATPostingSetup."VAT Prod. Posting Group", LibraryRandom.RandDec(1000, 2)); + + // [GIVEN] Sales advance letter has been released + ReleaseSalesAdvLetter(SalesAdvLetterHeaderCZZ); + + // [GIVEN] Sales advance letter has been paid in full by the general journal + SalesAdvLetterHeaderCZZ.CalcFields("Amount Including VAT"); + CreateAndPostPaymentSalesAdvLetter(SalesAdvLetterHeaderCZZ, -SalesAdvLetterHeaderCZZ."Amount Including VAT"); + + // [GIVEN] Sales invoice has been created + // [GIVEN] Sales invoice line with normal VAT has been created + LibrarySalesAdvancesCZZ.CreateSalesInvoice( + SalesHeader, SalesLine, SalesAdvLetterHeaderCZZ."Bill-to Customer No.", SalesAdvLetterHeaderCZZ."Posting Date", + SalesAdvLetterLineCZZ2."VAT Bus. Posting Group", SalesAdvLetterLineCZZ2."VAT Prod. Posting Group", '', 0, + true, SalesAdvLetterLineCZZ2."Amount Including VAT"); + + // [GIVEN] Second line with normal VAT has been linked to sales invoice + LibrarySalesAdvancesCZZ.LinkSalesAdvanceLetterToDocument( + SalesAdvLetterHeaderCZZ, Enum::"Adv. Letter Usage Doc.Type CZZ"::"Sales Invoice", SalesHeader."No.", + SalesAdvLetterHeaderCZZ."Amount Including VAT", SalesAdvLetterHeaderCZZ."Amount Including VAT (LCY)"); + + // [WHEN] Post sales invoice + PostedDocumentNo := PostSalesDocument(SalesHeader); + + // [THEN] VAT entries of sales invoice will exist + VATEntry.Reset(); + VATEntry.SetRange("Document No.", PostedDocumentNo); + VATEntry.SetRange("Posting Date", SalesHeader."Posting Date"); + VATEntry.SetRange("Advance Letter No. CZZ", ''); + Assert.RecordIsNotEmpty(VATEntry); + + // [THEN] VAT entries of advance letter will exist + VATEntry.SetRange("Advance Letter No. CZZ", SalesAdvLetterHeaderCZZ."No."); + Assert.RecordIsNotEmpty(VATEntry); + + // [THEN] Sum of base and VAT amounts in VAT entries will be zero + VATEntry.SetRange("Advance Letter No. CZZ"); + VATEntry.CalcSums(Base, Amount); + Assert.AreEqual(0, VATEntry.Base, 'The sum of base amount in VAT Entries must be zero.'); + Assert.AreEqual(0, VATEntry.Amount, 'The sum of VAT amount in VAT Entries must be zero.'); + + // [THEN] VAT entries will have the same VAT calculation type + VATEntry.SetFilter("VAT Calculation Type", '<>%1', SalesAdvLetterLineCZZ2."VAT Calculation Type"); + Assert.RecordIsEmpty(VATEntry); + end; + + [Test] + procedure LinkSalesAdvLetterWithNormalVATAndReverseChargeToInvoice2() + var + SalesHeader: Record "Sales Header"; + SalesLine: Record "Sales Line"; + SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; + SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; + SalesAdvLetterLineCZZ1: Record "Sales Adv. Letter Line CZZ"; + SalesAdvLetterLineCZZ2: Record "Sales Adv. Letter Line CZZ"; + VATEntry: Record "VAT Entry"; + VATPostingSetup: Record "VAT Posting Setup"; + PostedDocumentNo: Code[20]; + begin + // [SCENARIO] Link sales advance letter with normal VAT and reverse charge to sales invoice with reverse charge + Initialize(); + + // [GIVEN] Sales advance letter has been created + // [GIVEN] Sales advance letter line with reverse charge has been created + CreateSalesAdvLetter(SalesAdvLetterHeaderCZZ, SalesAdvLetterLineCZZ1); + + // [GIVEN] Sales advance letter line with normal VAT has been created + LibrarySalesAdvancesCZZ.FindVATPostingSetup(VATPostingSetup); + LibrarySalesAdvancesCZZ.CreateSalesAdvLetterLine( + SalesAdvLetterLineCZZ2, SalesAdvLetterHeaderCZZ, + VATPostingSetup."VAT Prod. Posting Group", LibraryRandom.RandDec(1000, 2)); + + // [GIVEN] Sales advance letter has been released + ReleaseSalesAdvLetter(SalesAdvLetterHeaderCZZ); + + // [GIVEN] Sales advance letter has been paid in full by the general journal + SalesAdvLetterHeaderCZZ.CalcFields("Amount Including VAT"); + CreateAndPostPaymentSalesAdvLetter(SalesAdvLetterHeaderCZZ, -SalesAdvLetterHeaderCZZ."Amount Including VAT"); + + // [GIVEN] Sales invoice has been created + // [GIVEN] Sales invoice line with reverse charge has been created + LibrarySalesAdvancesCZZ.CreateSalesInvoice( + SalesHeader, SalesLine, SalesAdvLetterHeaderCZZ."Bill-to Customer No.", SalesAdvLetterHeaderCZZ."Posting Date", + SalesAdvLetterLineCZZ1."VAT Bus. Posting Group", SalesAdvLetterLineCZZ1."VAT Prod. Posting Group", '', 0, + true, SalesAdvLetterLineCZZ1."Amount Including VAT"); + + // [GIVEN] First line with reverse charge has been linked to sales invoice + LibrarySalesAdvancesCZZ.LinkSalesAdvanceLetterToDocument( + SalesAdvLetterHeaderCZZ, Enum::"Adv. Letter Usage Doc.Type CZZ"::"Sales Invoice", SalesHeader."No.", + SalesAdvLetterHeaderCZZ."Amount Including VAT", SalesAdvLetterHeaderCZZ."Amount Including VAT (LCY)"); + + // [WHEN] Post sales invoice + PostedDocumentNo := PostSalesDocument(SalesHeader); + + // [THEN] VAT entries of sales invoice will exist + VATEntry.Reset(); + VATEntry.SetRange("Document No.", PostedDocumentNo); + VATEntry.SetRange("Posting Date", SalesHeader."Posting Date"); + VATEntry.SetRange("Advance Letter No. CZZ", ''); + Assert.RecordIsNotEmpty(VATEntry); + + // [THEN] VAT entries of advance letter won't exist + VATEntry.SetRange("Advance Letter No. CZZ", SalesAdvLetterHeaderCZZ."No."); + Assert.RecordIsEmpty(VATEntry); + + // [THEN] Sum of base and VAT amounts in VAT entries won't be zero + VATEntry.SetRange("Advance Letter No. CZZ"); + VATEntry.CalcSums(Base, Amount); + Assert.AreNotEqual(0, VATEntry.Base, 'The sum of base amount in VAT Entries mustn''t be zero.'); + + // [THEN] Sales advance letter entry of "VAT Usage" type with reverse charge will be created + SalesAdvLetterEntryCZZ.Reset(); + SalesAdvLetterEntryCZZ.SetRange("Sales Adv. Letter No.", SalesAdvLetterHeaderCZZ."No."); + SalesAdvLetterEntryCZZ.SetRange("Entry Type", SalesAdvLetterEntryCZZ."Entry Type"::"VAT Usage"); + SalesAdvLetterEntryCZZ.SetRange("VAT Calculation Type", SalesAdvLetterEntryCZZ."VAT Calculation Type"::"Reverse Charge VAT"); + SalesAdvLetterEntryCZZ.SetRange("Auxiliary Entry", true); + Assert.RecordIsNotEmpty(SalesAdvLetterEntryCZZ); + + // [THEN] Sales advance letter entry of "VAT Usage" type with normal VAT won't be created + SalesAdvLetterEntryCZZ.Reset(); + SalesAdvLetterEntryCZZ.SetRange("Sales Adv. Letter No.", SalesAdvLetterHeaderCZZ."No."); + SalesAdvLetterEntryCZZ.SetRange("Entry Type", SalesAdvLetterEntryCZZ."Entry Type"::"VAT Usage"); + SalesAdvLetterEntryCZZ.SetRange("VAT Calculation Type", SalesAdvLetterEntryCZZ."VAT Calculation Type"::"Normal VAT"); + Assert.RecordIsEmpty(SalesAdvLetterEntryCZZ); + end; + + [Test] + procedure LinkSalesAdvLetterWithNormalVATAndReverseChargeToInvoice3() + var + SalesHeader: Record "Sales Header"; + SalesLine: Record "Sales Line"; + SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; + SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; + SalesAdvLetterLineCZZ1: Record "Sales Adv. Letter Line CZZ"; + SalesAdvLetterLineCZZ2: Record "Sales Adv. Letter Line CZZ"; + VATEntry: Record "VAT Entry"; + VATPostingSetup: Record "VAT Posting Setup"; + PostedDocumentNo: Code[20]; + VATPaymentAmount, VATPaymentAmountLCY : Decimal; + begin + // [SCENARIO] Link sales advance letter with normal VAT and reverse charge to sales invoice with normal VAT and higher amount than the advance letter + Initialize(); + + // [GIVEN] Sales advance letter has been created + // [GIVEN] Sales advance letter line with reverse charge has been created + CreateSalesAdvLetter(SalesAdvLetterHeaderCZZ, SalesAdvLetterLineCZZ1); + + // [GIVEN] Sales advance letter line with normal VAT has been created + LibrarySalesAdvancesCZZ.FindVATPostingSetup(VATPostingSetup); + LibrarySalesAdvancesCZZ.CreateSalesAdvLetterLine( + SalesAdvLetterLineCZZ2, SalesAdvLetterHeaderCZZ, + VATPostingSetup."VAT Prod. Posting Group", LibraryRandom.RandDec(1000, 2)); + + // [GIVEN] Sales advance letter has been released + ReleaseSalesAdvLetter(SalesAdvLetterHeaderCZZ); + + // [GIVEN] Sales advance letter has been paid in full by the general journal + SalesAdvLetterHeaderCZZ.CalcFields("Amount Including VAT"); + CreateAndPostPaymentSalesAdvLetter(SalesAdvLetterHeaderCZZ, -SalesAdvLetterHeaderCZZ."Amount Including VAT"); + + // [GIVEN] Sales invoice has been created + // [GIVEN] Sales invoice line with normal VAT has been created + LibrarySalesAdvancesCZZ.CreateSalesInvoice( + SalesHeader, SalesLine, SalesAdvLetterHeaderCZZ."Bill-to Customer No.", SalesAdvLetterHeaderCZZ."Posting Date", + SalesAdvLetterLineCZZ2."VAT Bus. Posting Group", SalesAdvLetterLineCZZ2."VAT Prod. Posting Group", '', 0, + true, SalesAdvLetterLineCZZ2."Amount Including VAT" + (SalesAdvLetterLineCZZ1."Amount Including VAT" / 2)); + + // [GIVEN] First line with normal VAT has been linked to sales invoice + LibrarySalesAdvancesCZZ.LinkSalesAdvanceLetterToDocument( + SalesAdvLetterHeaderCZZ, Enum::"Adv. Letter Usage Doc.Type CZZ"::"Sales Invoice", SalesHeader."No.", + SalesAdvLetterHeaderCZZ."Amount Including VAT", SalesAdvLetterHeaderCZZ."Amount Including VAT (LCY)"); + + // [WHEN] Post sales invoice + PostedDocumentNo := PostSalesDocument(SalesHeader); + + // [THEN] Sales advance letter entry of "VAT Usage" type will have amount equal to the amount of "VAT Payment" entry + SalesAdvLetterEntryCZZ.Reset(); + SalesAdvLetterEntryCZZ.SetRange("Sales Adv. Letter No.", SalesAdvLetterHeaderCZZ."No."); + SalesAdvLetterEntryCZZ.SetRange("Entry Type", SalesAdvLetterEntryCZZ."Entry Type"::"VAT Payment"); + SalesAdvLetterEntryCZZ.SetRange("VAT Calculation Type", SalesAdvLetterLineCZZ2."VAT Calculation Type"); + SalesAdvLetterEntryCZZ.CalcSums(Amount, "Amount (LCY)"); + VATPaymentAmount := SalesAdvLetterEntryCZZ.Amount; + VATPaymentAmountLCY := SalesAdvLetterEntryCZZ."Amount (LCY)"; + + SalesAdvLetterEntryCZZ.Reset(); + SalesAdvLetterEntryCZZ.SetRange("Sales Adv. Letter No.", SalesAdvLetterHeaderCZZ."No."); + SalesAdvLetterEntryCZZ.SetRange("Entry Type", SalesAdvLetterEntryCZZ."Entry Type"::"VAT Usage"); + SalesAdvLetterEntryCZZ.SetRange("VAT Calculation Type", SalesAdvLetterLineCZZ2."VAT Calculation Type"); + SalesAdvLetterEntryCZZ.FindFirst(); + Assert.AreEqual(VATPaymentAmount, -SalesAdvLetterEntryCZZ.Amount, 'The amount of VAT Payment entry must be equal to the amount of VAT Usage entry.'); + Assert.AreEqual(VATPaymentAmountLCY, -SalesAdvLetterEntryCZZ."Amount (LCY)", 'The amount (LCY) of VAT Payment entry must be equal to the amount (LCY) of VAT Usage entry.'); + + // [THEN] Sum of base and VAT amounts in VAT entries won't be zero + VATEntry.Reset(); + VATEntry.SetRange("Document No.", PostedDocumentNo); + VATEntry.SetRange("Posting Date", SalesHeader."Posting Date"); + VATEntry.CalcSums(Base, Amount); + Assert.AreNotEqual(0, VATEntry.Base, 'The sum of base amount in VAT Entries mustn''t be zero.'); + Assert.AreNotEqual(0, VATEntry.Amount, 'The sum of VAT amount in VAT Entries mustn''t be zero.'); + end; + + [Test] + procedure LinkSalesAdvLetterWithNormalVATAndReverseChargeToInvoice4() + var + SalesHeader: Record "Sales Header"; + SalesLine: Record "Sales Line"; + SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; + SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; + SalesAdvLetterLineCZZ1: Record "Sales Adv. Letter Line CZZ"; + SalesAdvLetterLineCZZ2: Record "Sales Adv. Letter Line CZZ"; + VATPostingSetup: Record "VAT Posting Setup"; + begin + // [SCENARIO] Link sales advance letter with normal VAT and reverse charge to sales invoice with reverse charge and higher amount than the advance letter + Initialize(); + + // [GIVEN] Sales advance letter has been created + // [GIVEN] Sales advance letter line with reverse charge has been created + CreateSalesAdvLetter(SalesAdvLetterHeaderCZZ, SalesAdvLetterLineCZZ1); + + // [GIVEN] Sales advance letter line with normal VAT has been created + LibrarySalesAdvancesCZZ.FindVATPostingSetup(VATPostingSetup); + LibrarySalesAdvancesCZZ.CreateSalesAdvLetterLine( + SalesAdvLetterLineCZZ2, SalesAdvLetterHeaderCZZ, + VATPostingSetup."VAT Prod. Posting Group", LibraryRandom.RandDec(1000, 2)); + + // [GIVEN] Sales advance letter has been released + ReleaseSalesAdvLetter(SalesAdvLetterHeaderCZZ); + + // [GIVEN] Sales advance letter has been paid in full by the general journal + SalesAdvLetterHeaderCZZ.CalcFields("Amount Including VAT"); + CreateAndPostPaymentSalesAdvLetter(SalesAdvLetterHeaderCZZ, -SalesAdvLetterHeaderCZZ."Amount Including VAT"); + + // [GIVEN] Sales invoice has been created + // [GIVEN] Sales invoice line with reverse charge has been created + LibrarySalesAdvancesCZZ.CreateSalesInvoice( + SalesHeader, SalesLine, SalesAdvLetterHeaderCZZ."Bill-to Customer No.", SalesAdvLetterHeaderCZZ."Posting Date", + SalesAdvLetterLineCZZ1."VAT Bus. Posting Group", SalesAdvLetterLineCZZ1."VAT Prod. Posting Group", '', 0, + true, SalesAdvLetterLineCZZ1."Amount Including VAT" + Round(SalesAdvLetterLineCZZ2."Amount Including VAT" / 2)); + + // [GIVEN] First line with reverse charge has been linked to sales invoice + LibrarySalesAdvancesCZZ.LinkSalesAdvanceLetterToDocument( + SalesAdvLetterHeaderCZZ, Enum::"Adv. Letter Usage Doc.Type CZZ"::"Sales Invoice", SalesHeader."No.", + SalesAdvLetterHeaderCZZ."Amount Including VAT", SalesAdvLetterHeaderCZZ."Amount Including VAT (LCY)"); + + // [WHEN] Post sales invoice + PostSalesDocument(SalesHeader); + + // [THEN] Sales advance letter entry of "VAT Usage" type will have amount equal to part of the amount of "VAT Payment" entry with normal VAT + SalesAdvLetterEntryCZZ.Reset(); + SalesAdvLetterEntryCZZ.SetRange("Sales Adv. Letter No.", SalesAdvLetterHeaderCZZ."No."); + SalesAdvLetterEntryCZZ.SetRange("Entry Type", SalesAdvLetterEntryCZZ."Entry Type"::"VAT Usage"); + SalesAdvLetterEntryCZZ.SetRange("VAT Calculation Type", SalesAdvLetterLineCZZ2."VAT Calculation Type"); + SalesAdvLetterEntryCZZ.FindFirst(); + Assert.AreEqual(Round(SalesAdvLetterLineCZZ2."Amount Including VAT" / 2), SalesAdvLetterEntryCZZ.Amount, 'The amount of VAT Payment entry must be equal to the amount of VAT Usage entry.'); + + // [THEN] Sales advance letter entry of "VAT Usage" type will have amount equal to the amount of "VAT Payment" entry with reverse charge + SalesAdvLetterEntryCZZ.Reset(); + SalesAdvLetterEntryCZZ.SetRange("Sales Adv. Letter No.", SalesAdvLetterHeaderCZZ."No."); + SalesAdvLetterEntryCZZ.SetRange("Entry Type", SalesAdvLetterEntryCZZ."Entry Type"::"VAT Usage"); + SalesAdvLetterEntryCZZ.SetRange("VAT Calculation Type", SalesAdvLetterLineCZZ1."VAT Calculation Type"); + SalesAdvLetterEntryCZZ.SetRange("Auxiliary Entry", true); + SalesAdvLetterEntryCZZ.SetRange("VAT Entry No.", 0); + SalesAdvLetterEntryCZZ.FindFirst(); + Assert.AreEqual(SalesAdvLetterLineCZZ1."Amount Including VAT", SalesAdvLetterEntryCZZ.Amount, 'The amount of VAT Payment entry must be equal to the amount of VAT Usage entry.'); + end; + + [Test] + procedure LinkSalesAdvLetterWithNormalVATAndReverseChargeToInvoice5() + var + GLAccount: Record "G/L Account"; + SalesHeader: Record "Sales Header"; + SalesLine: Record "Sales Line"; + SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; + SalesAdvLetterLineCZZ1: Record "Sales Adv. Letter Line CZZ"; + SalesAdvLetterLineCZZ2: Record "Sales Adv. Letter Line CZZ"; + VATEntry: Record "VAT Entry"; + VATPostingSetup: Record "VAT Posting Setup"; + PostedDocumentNo: Code[20]; + begin + // [SCENARIO] Link sales advance letter with normal VAT and reverse charge to sales invoice with normal VAT and reverse charge and lower amount than the advance letter + Initialize(); + + // [GIVEN] Sales advance letter has been created + // [GIVEN] Sales advance letter line with reverse charge has been created + CreateSalesAdvLetter(SalesAdvLetterHeaderCZZ, SalesAdvLetterLineCZZ1); + + // [GIVEN] Sales advance letter line with normal VAT has been created + LibrarySalesAdvancesCZZ.FindVATPostingSetup(VATPostingSetup); + LibrarySalesAdvancesCZZ.CreateSalesAdvLetterLine( + SalesAdvLetterLineCZZ2, SalesAdvLetterHeaderCZZ, + VATPostingSetup."VAT Prod. Posting Group", LibraryRandom.RandDec(1000, 2)); + + // [GIVEN] Sales advance letter has been released + ReleaseSalesAdvLetter(SalesAdvLetterHeaderCZZ); + + // [GIVEN] Sales advance letter has been paid in full by the general journal + SalesAdvLetterHeaderCZZ.CalcFields("Amount Including VAT"); + CreateAndPostPaymentSalesAdvLetter(SalesAdvLetterHeaderCZZ, -SalesAdvLetterHeaderCZZ."Amount Including VAT"); + + // [GIVEN] Sales invoice has been created + // [GIVEN] First sales invoice line with reverse charge has been created + LibrarySalesAdvancesCZZ.CreateSalesInvoice( + SalesHeader, SalesLine, SalesAdvLetterHeaderCZZ."Bill-to Customer No.", SalesAdvLetterHeaderCZZ."Posting Date", + SalesAdvLetterLineCZZ1."VAT Bus. Posting Group", SalesAdvLetterLineCZZ1."VAT Prod. Posting Group", '', 0, + true, SalesAdvLetterLineCZZ1."Amount Including VAT" / 2); + + // [GIVEN] Second sales invoice line with normal VAT has been created + LibrarySalesAdvancesCZZ.CreateGLAccount(GLAccount); + GLAccount.Validate("VAT Bus. Posting Group", SalesAdvLetterLineCZZ2."VAT Bus. Posting Group"); + GLAccount.Validate("VAT Prod. Posting Group", SalesAdvLetterLineCZZ2."VAT Prod. Posting Group"); + GLAccount.Modify(true); + + LibrarySales.CreateSalesLine(SalesLine, SalesHeader, SalesLine.Type::"G/L Account", GLAccount."No.", 1); + SalesLine.Validate("Unit Price", SalesAdvLetterLineCZZ2."Amount Including VAT" / 2); + SalesLine.Modify(true); + + // [GIVEN] First line with reverse charge has been linked to sales invoice + LibrarySalesAdvancesCZZ.LinkSalesAdvanceLetterToDocument( + SalesAdvLetterHeaderCZZ, Enum::"Adv. Letter Usage Doc.Type CZZ"::"Sales Invoice", SalesHeader."No.", + SalesAdvLetterHeaderCZZ."Amount Including VAT", SalesAdvLetterHeaderCZZ."Amount Including VAT (LCY)"); + + // [WHEN] Post sales invoice + PostedDocumentNo := PostSalesDocument(SalesHeader); + + // [THEN] Sum of base and VAT amounts in VAT entries of invoice won't be zero + VATEntry.Reset(); + VATEntry.SetRange("Document No.", PostedDocumentNo); + VATEntry.SetRange("Posting Date", SalesHeader."Posting Date"); + VATEntry.CalcSums(Base, Amount); + Assert.AreNotEqual(0, VATEntry.Base, 'The sum of base amount in VAT Entries mustn''t be zero.'); + + // [THEN] Sum of base and VAT amounts in VAT entries with reverse charge VAT won't be zero + VATEntry.SetRange("VAT Calculation Type", SalesAdvLetterLineCZZ1."VAT Calculation Type"::"Reverse Charge VAT"); + VATEntry.CalcSums(Base, Amount); + Assert.AreNotEqual(0, VATEntry.Base, 'The sum of base amount in VAT Entries mustn''t be zero.'); + + // [THEN] Sum of base and VAT amounts in VAT entries with normal VAT will be zero + VATEntry.SetRange("VAT Calculation Type", SalesAdvLetterLineCZZ1."VAT Calculation Type"::"Normal VAT"); + VATEntry.CalcSums(Base, Amount); + Assert.AreEqual(0, VATEntry.Base, 'The sum of base amount in VAT Entries must be zero.'); + Assert.AreEqual(0, VATEntry.Amount, 'The sum of VAT amount in VAT Entries must be zero.'); + end; + + local procedure CreateSalesAdvLetter(var SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; var SalesAdvLetterLineCZZ: Record "Sales Adv. Letter Line CZZ"; VATPostingSetup: Record "VAT Posting Setup"; VendorNo: Code[20]) + var + Customer: Record Customer; + begin + if VendorNo = '' then begin + LibrarySalesAdvancesCZZ.CreateCustomer(Customer); + Customer.Validate("VAT Bus. Posting Group", VATPostingSetup."VAT Bus. Posting Group"); + Customer.Modify(true); + VendorNo := Customer."No."; + end; + + LibrarySalesAdvancesCZZ.CreateSalesAdvLetterHeader(SalesAdvLetterHeaderCZZ, AdvanceLetterTemplateCZZ.Code, VendorNo, ''); + LibrarySalesAdvancesCZZ.CreateSalesAdvLetterLine(SalesAdvLetterLineCZZ, SalesAdvLetterHeaderCZZ, VATPostingSetup."VAT Prod. Posting Group", LibraryRandom.RandDec(1000, 2)); + end; + + local procedure CreateSalesAdvLetter(var SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; var SalesAdvLetterLineCZZ: Record "Sales Adv. Letter Line CZZ"; VATPostingSetup: Record "VAT Posting Setup") + begin + CreateSalesAdvLetter(SalesAdvLetterHeaderCZZ, SalesAdvLetterLineCZZ, VATPostingSetup, ''); + end; + + local procedure CreateSalesAdvLetter(var SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; var SalesAdvLetterLineCZZ: Record "Sales Adv. Letter Line CZZ") + var + VATPostingSetup: Record "VAT Posting Setup"; + begin + LibrarySalesAdvancesCZZ.FindVATPostingSetupEU(VATPostingSetup); + CreateSalesAdvLetter(SalesAdvLetterHeaderCZZ, SalesAdvLetterLineCZZ, VATPostingSetup, ''); + end; + + local procedure CreateAndPostPaymentSalesAdvLetter(var SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; Amount: Decimal; ExchangeRate: Decimal; PostingDate: Date) + var + GenJournalLine: Record "Gen. Journal Line"; + begin + LibrarySalesAdvancesCZZ.CreateSalesAdvancePayment( + GenJournalLine, SalesAdvLetterHeaderCZZ."Bill-to Customer No.", Amount, SalesAdvLetterHeaderCZZ."Currency Code", + SalesAdvLetterHeaderCZZ."No.", ExchangeRate, PostingDate); + LibrarySalesAdvancesCZZ.PostSalesAdvancePayment(GenJournalLine); + end; + + local procedure CreateAndPostPaymentSalesAdvLetter(var SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; Amount: Decimal) + begin + CreateAndPostPaymentSalesAdvLetter(SalesAdvLetterHeaderCZZ, Amount, 0, 0D); + end; + + local procedure ReleaseSalesAdvLetter(var SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ") + begin + LibrarySalesAdvancesCZZ.ReleaseSalesAdvLetter(SalesAdvLetterHeaderCZZ); + end; + + local procedure PostSalesDocument(var SalesHeader: Record "Sales Header"): Code[20] + begin + exit(LibrarySales.PostSalesDocument(SalesHeader, true, true)); + end; + + local procedure FindLastPaymentAdvanceLetterEntry(AdvanceLetterNo: Code[20]; var SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ") + begin + SalesAdvLetterEntryCZZ.SetRange("Sales Adv. Letter No.", AdvanceLetterNo); + SalesAdvLetterEntryCZZ.SetRange("Entry Type", SalesAdvLetterEntryCZZ."Entry Type"::Payment); + SalesAdvLetterEntryCZZ.FindLast(); + end; +} diff --git a/Apps/CZ/AdvancePaymentsLocalization/test/Src/SalesAdvancePaymentsCZZ.Codeunit.al b/Apps/CZ/AdvancePaymentsLocalization/test/Src/SalesAdvancePaymentsCZZ.Codeunit.al index 3b77a3e512..31661dd798 100644 --- a/Apps/CZ/AdvancePaymentsLocalization/test/Src/SalesAdvancePaymentsCZZ.Codeunit.al +++ b/Apps/CZ/AdvancePaymentsLocalization/test/Src/SalesAdvancePaymentsCZZ.Codeunit.al @@ -688,6 +688,9 @@ codeunit 148109 "Sales Advance Payments CZZ" // [SCENARIO] Link sales advance letter with reverse charge to invoice Initialize(); + // [GIVEN] Posting of VAT documents for reverse charge has been enabled + SetPostVATDocForReverseCharge(true); + // [GIVEN] Sales advance letter has been created // [GIVEN] Sales advance letter line with reverse charge has been created CreateSalesAdvLetterWithReverseCharge(SalesAdvLetterHeaderCZZ, SalesAdvLetterLineCZZ); @@ -734,6 +737,8 @@ codeunit 148109 "Sales Advance Payments CZZ" // [THEN] Sales advance letter will be closed SalesAdvLetterHeaderCZZ.Get(SalesAdvLetterHeaderCZZ."No."); SalesAdvLetterHeaderCZZ.TestField(Status, SalesAdvLetterHeaderCZZ.Status::Closed); + + SetPostVATDocForReverseCharge(false); end; [Test] @@ -2215,6 +2220,9 @@ codeunit 148109 "Sales Advance Payments CZZ" // with line which is the same as first line in advance letter and one VAT rate Initialize(); + // [GIVEN] Posting of VAT documents for reverse charge has been enabled + SetPostVATDocForReverseCharge(true); + // [GIVEN] Sales advance letter has been created // [GIVEN] Sales advance letter line with normal VAT has been created CreateSalesAdvLetter(SalesAdvLetterHeaderCZZ, SalesAdvLetterLineCZZ1); @@ -2271,6 +2279,8 @@ codeunit 148109 "Sales Advance Payments CZZ" VATEntry.SetRange("VAT Bus. Posting Group", VATEntry."VAT Bus. Posting Group"); VATEntry.SetRange("VAT Prod. Posting Group", VATEntry."VAT Prod. Posting Group"); Assert.RecordCount(VATEntry, VATEntryCount); + + SetPostVATDocForReverseCharge(false); end; [Test] @@ -2289,6 +2299,9 @@ codeunit 148109 "Sales Advance Payments CZZ" // [SCENARIO] Create Sales advance letter with two lines with different VAT rates and link to invoice with line which is the same as second line in advance letter and one VAT rate Initialize(); + // [GIVEN] Posting of VAT documents for reverse charge has been enabled + SetPostVATDocForReverseCharge(true); + // [GIVEN] Sales advance letter has been created // [GIVEN] Sales advance letter line with normal VAT has been created CreateSalesAdvLetter(SalesAdvLetterHeaderCZZ, SalesAdvLetterLineCZZ1); @@ -2345,6 +2358,8 @@ codeunit 148109 "Sales Advance Payments CZZ" VATEntry.SetRange("VAT Bus. Posting Group", VATEntry."VAT Bus. Posting Group"); VATEntry.SetRange("VAT Prod. Posting Group", VATEntry."VAT Prod. Posting Group"); Assert.RecordCount(VATEntry, VATEntryCount); + + SetPostVATDocForReverseCharge(false); end; [Test] @@ -2362,6 +2377,9 @@ codeunit 148109 "Sales Advance Payments CZZ" // [SCENARIO] Create Sales advance letter with two lines with different VAT rates and link to invoice with line which has the higher amount as first line in advance letter and one VAT rate Initialize(); + // [GIVEN] Posting of VAT documents for reverse charge has been enabled + SetPostVATDocForReverseCharge(true); + // [GIVEN] Sales advance letter has been created // [GIVEN] Sales advance letter line with normal VAT has been created CreateSalesAdvLetter(SalesAdvLetterHeaderCZZ, SalesAdvLetterLineCZZ1); @@ -2413,6 +2431,8 @@ codeunit 148109 "Sales Advance Payments CZZ" SalesAdvLetterEntryCZZ2.SetRange("VAT Prod. Posting Group", SalesAdvLetterLineCZZ2."VAT Prod. Posting Group"); SalesAdvLetterEntryCZZ2.SetRange("Entry Type", SalesAdvLetterEntryCZZ2."Entry Type"::"VAT Usage"); Assert.RecordIsNotEmpty(SalesAdvLetterEntryCZZ2); + + SetPostVATDocForReverseCharge(false); end; [Test] @@ -2430,6 +2450,9 @@ codeunit 148109 "Sales Advance Payments CZZ" // [SCENARIO] Create Sales advance letter with two lines with different VAT rates and link to invoice with line which has the higher amount as second line in advance letter and one VAT rate Initialize(); + // [GIVEN] Posting of VAT documents for reverse charge has been enabled + SetPostVATDocForReverseCharge(true); + // [GIVEN] Sales advance letter has been created // [GIVEN] Sales advance letter line with normal VAT has been created CreateSalesAdvLetter(SalesAdvLetterHeaderCZZ, SalesAdvLetterLineCZZ1); @@ -2481,6 +2504,8 @@ codeunit 148109 "Sales Advance Payments CZZ" SalesAdvLetterEntryCZZ2.SetRange("VAT Prod. Posting Group", SalesAdvLetterLineCZZ1."VAT Prod. Posting Group"); SalesAdvLetterEntryCZZ2.SetRange("Entry Type", SalesAdvLetterEntryCZZ2."Entry Type"::"VAT Usage"); Assert.RecordIsNotEmpty(SalesAdvLetterEntryCZZ2); + + SetPostVATDocForReverseCharge(false); end; [Test] @@ -2500,6 +2525,9 @@ codeunit 148109 "Sales Advance Payments CZZ" // [SCENARIO] Create Sales advance letter with two lines with different VAT rates and link to invoice with two lines which have the lower amounts as lines in advance letter Initialize(); + // [GIVEN] Posting of VAT documents for reverse charge has been enabled + SetPostVATDocForReverseCharge(true); + // [GIVEN] Sales advance letter has been created // [GIVEN] Sales advance letter line with normal VAT has been created CreateSalesAdvLetter(SalesAdvLetterHeaderCZZ, SalesAdvLetterLineCZZ1); @@ -2570,6 +2598,8 @@ codeunit 148109 "Sales Advance Payments CZZ" VATEntry.CalcSums(Base, Amount); Assert.AreEqual(0, VATEntry.Base, 'The sum of base amount in VAT Entries must be zero.'); Assert.AreEqual(0, VATEntry.Amount, 'The sum of VAT amount in VAT Entries must be zero.'); + + SetPostVATDocForReverseCharge(false); end; local procedure CreateSalesAdvLetterBase(var SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; var SalesAdvLetterLineCZZ: Record "Sales Adv. Letter Line CZZ"; CustomerNo: Code[20]; CurrencyCode: Code[10]; VATPostingSetup: Record "VAT Posting Setup") @@ -2693,6 +2723,12 @@ codeunit 148109 "Sales Advance Payments CZZ" exit(LibrarySales.PostSalesDocument(SalesHeader, true, true)); end; + local procedure SetPostVATDocForReverseCharge(Value: Boolean) + begin + AdvanceLetterTemplateCZZ."Post VAT Doc. for Rev. Charge" := Value; + AdvanceLetterTemplateCZZ.Modify(); + end; + local procedure FindLastPaymentAdvanceLetterEntry(AdvanceLetterNo: Code[20]; var SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ") begin SalesAdvLetterEntryCZZ.SetRange("Sales Adv. Letter No.", AdvanceLetterNo); diff --git a/Apps/CZ/CashDeskLocalization/app/Src/Codeunits/CashDeskManagementCZP.Codeunit.al b/Apps/CZ/CashDeskLocalization/app/Src/Codeunits/CashDeskManagementCZP.Codeunit.al index 7ee41a931e..f81cc00862 100644 --- a/Apps/CZ/CashDeskLocalization/app/Src/Codeunits/CashDeskManagementCZP.Codeunit.al +++ b/Apps/CZ/CashDeskLocalization/app/Src/Codeunits/CashDeskManagementCZP.Codeunit.al @@ -74,7 +74,6 @@ codeunit 11724 "Cash Desk Management CZP" procedure CashDocumentSelection(var CashDocumentHeaderCZP: Record "Cash Document Header CZP"; var CashDeskSelected: Boolean) var CashDeskCZP: Record "Cash Desk CZP"; - CashDeskFilter: Text; IsHandled: Boolean; begin IsHandled := false; @@ -85,13 +84,8 @@ codeunit 11724 "Cash Desk Management CZP" CashDeskSelected := true; CheckCashDesks(); - CashDeskFilter := GetCashDesksFilter(); + SetCashDeskFilter(CashDeskCZP); - if CashDeskFilter <> '' then begin - CashDeskCZP.FilterGroup(2); - CashDeskCZP.SetFilter("No.", CashDeskFilter); - CashDeskCZP.FilterGroup(0); - end; case CashDeskCZP.Count() of 0: Error(CashDeskNotExistErr); @@ -586,7 +580,7 @@ codeunit 11724 "Cash Desk Management CZP" if User.IsEmpty() then exit; - UserCode := CopyStr(UserId(), 1, 50); + UserCode := GetUserCode(); GetCashDesksForCashDeskUser(UserCode, TempCashDeskCZP); if CashDeskNo <> '' then @@ -607,11 +601,62 @@ codeunit 11724 "Cash Desk Management CZP" end; end; + procedure SetCashDeskFilter(var CashDeskCZP: Record "Cash Desk CZP") + var + CashDeskFilter: Text; + begin + if IsCashDeskUserEmpty() then + exit; + + CashDeskFilter := GetCashDesksFilter(); + CashDeskCZP.FilterGroup(2); + if CashDeskFilter <> '' then + CashDeskCZP.SetFilter("No.", CashDeskFilter) + else + CashDeskCZP.SetRange("No.", ''); + CashDeskCZP.FilterGroup(0); + end; + + procedure SetCashDeskFilter(var CashDeskCueCZP: Record "Cash Desk Cue CZP") + var + CashDeskCZP: Record "Cash Desk CZP"; + begin + SetCashDeskFilter(CashDeskCZP); + CashDeskCZP.FilterGroup(2); + CashDeskCZP.CopyFilter("No.", CashDeskCueCZP."Cash Desk Filter"); + end; + + procedure SetCashDeskFilter(var CashDocumentHeaderCZP: Record "Cash Document Header CZP") + var + CashDeskCZP: Record "Cash Desk CZP"; + begin + SetCashDeskFilter(CashDeskCZP); + CashDeskCZP.FilterGroup(2); + CashDeskCZP.CopyFilter("No.", CashDocumentHeaderCZP."Cash Desk No."); + end; + + procedure SetCashDeskFilter(var PostedCashDocumentHdrCZP: Record "Posted Cash Document Hdr. CZP") + var + CashDeskCZP: Record "Cash Desk CZP"; + begin + SetCashDeskFilter(CashDeskCZP); + CashDeskCZP.FilterGroup(2); + CashDeskCZP.CopyFilter("No.", PostedCashDocumentHdrCZP."Cash Desk No."); + end; + + local procedure IsCashDeskUserEmpty(): Boolean + var + CashDeskUserCZP: Record "Cash Desk User CZP"; + begin + CashDeskUserCZP.Reset(); + exit(CashDeskUserCZP.IsEmpty()); + end; + procedure GetCashDesksFilter(): Text var TempCashDeskCZP: Record "Cash Desk CZP" temporary; begin - GetCashDesks(CopyStr(UserId(), 1, 50), TempCashDeskCZP); + GetCashDesks(GetUserCode(), TempCashDeskCZP); exit(GetCashDesksFilterFromBuffer(TempCashDeskCZP)); end; @@ -630,16 +675,12 @@ codeunit 11724 "Cash Desk Management CZP" CompanyInformation: Record "Company Information"; UserSetup: Record "User Setup"; CashUserRespCenter: Code[10]; - HasGotCashUserSetup: Boolean; - begin - if not HasGotCashUserSetup then begin - CompanyInformation.Get(); - CashUserRespCenter := CompanyInformation."Responsibility Center"; - if UserSetup.Get(UserCode) and (UserCode <> '') then - if UserSetup."Cash Resp. Ctr. Filter CZP" <> '' then - CashUserRespCenter := UserSetup."Cash Resp. Ctr. Filter CZP"; - HasGotCashUserSetup := true; - end; + begin + CompanyInformation.Get(); + CashUserRespCenter := CompanyInformation."Responsibility Center"; + if UserSetup.Get(UserCode) and (UserCode <> '') then + if UserSetup."Cash Resp. Ctr. Filter CZP" <> '' then + CashUserRespCenter := UserSetup."Cash Resp. Ctr. Filter CZP"; exit(CashUserRespCenter); end; @@ -726,6 +767,35 @@ codeunit 11724 "Cash Desk Management CZP" PreviewMode := NewPreviewMode; end; + internal procedure CheckResponsibilityCenter(RespCenter: Code[10]): Boolean + begin + exit(CheckResponsibilityCenter(RespCenter, GetUserCode())); + end; + + internal procedure CheckResponsibilityCenter(RespCenter: Code[10]; UserCode: Code[50]): Boolean + var + UserRespCenter: Code[10]; + IsHandled: Boolean; + Result: Boolean; + begin + OnBeforeCheckResponsibilityCenter(RespCenter, UserCode, IsHandled, Result); + if IsHandled then + exit(Result); + + UserRespCenter := GetUserCashResponsibilityFilter(UserCode); + if (UserRespCenter <> '') and + (RespCenter <> UserRespCenter) + then + exit(false); + + exit(true); + end; + + local procedure GetUserCode(): Code[50] + begin + exit(CopyStr(UserId(), 1, 50)); + end; + [IntegrationEvent(false, false)] local procedure OnBeforeCheckUserRights(CashDeskNo: Code[20]; ActionType: Enum "Cash Document Action CZP"; var IsHandled: Boolean) begin @@ -745,4 +815,9 @@ codeunit 11724 "Cash Desk Management CZP" local procedure OnBeforeGetCashDesksForCashDeskUser(UserCode: Code[50]; var TempCashDeskCZP: Record "Cash Desk CZP" temporary; var IsHandled: Boolean) begin end; + + [IntegrationEvent(false, false)] + local procedure OnBeforeCheckResponsibilityCenter(RespCenter: Code[10]; UserCode: Code[50]; var IsHandled: Boolean; var Result: Boolean) + begin + end; } diff --git a/Apps/CZ/CashDeskLocalization/app/Src/Pages/CashDeskActivitiesCZP.Page.al b/Apps/CZ/CashDeskLocalization/app/Src/Pages/CashDeskActivitiesCZP.Page.al index 118cdda245..747a1abb73 100644 --- a/Apps/CZ/CashDeskLocalization/app/Src/Pages/CashDeskActivitiesCZP.Page.al +++ b/Apps/CZ/CashDeskLocalization/app/Src/Pages/CashDeskActivitiesCZP.Page.al @@ -44,7 +44,6 @@ page 31154 "Cash Desk Activities CZP" trigger OnOpenPage() var CashDeskManagementCZP: Codeunit "Cash Desk Management CZP"; - CashDeskFilter: Text; begin Rec.Reset(); if not Rec.Get() then begin @@ -52,12 +51,9 @@ page 31154 "Cash Desk Activities CZP" Rec.Insert(); end; + CashDeskManagementCZP.SetCashDeskFilter(Rec); + Rec.FilterGroup(2); - CashDeskFilter := CashDeskManagementCZP.GetCashDesksFilter(); - if CashDeskFilter <> '' then - Rec.SetFilter("Cash Desk Filter", CashDeskFilter) - else - Rec.SetRange("Cash Desk Filter", ''); Rec.SetRange("Date Filter", CalcDate('<-30D>', WorkDate()), WorkDate()); Rec.FilterGroup(0); end; diff --git a/Apps/CZ/CashDeskLocalization/app/Src/Pages/CashDeskListCZP.Page.al b/Apps/CZ/CashDeskLocalization/app/Src/Pages/CashDeskListCZP.Page.al index d49753787e..cd357f84d5 100644 --- a/Apps/CZ/CashDeskLocalization/app/Src/Pages/CashDeskListCZP.Page.al +++ b/Apps/CZ/CashDeskLocalization/app/Src/Pages/CashDeskListCZP.Page.al @@ -376,15 +376,8 @@ page 31150 "Cash Desk List CZP" } trigger OnOpenPage() - var - CashDesksFilter: Text; begin - CashDesksFilter := CashDeskManagementCZP.GetCashDesksFilter(); - - Rec.FilterGroup(2); - if CashDesksFilter <> '' then - Rec.SetFilter("No.", CashDesksFilter); - Rec.FilterGroup(0); + CashDeskManagementCZP.SetCashDeskFilter(Rec); end; var diff --git a/Apps/CZ/CashDeskLocalization/app/Src/Pages/CashDocumentListCZP.Page.al b/Apps/CZ/CashDeskLocalization/app/Src/Pages/CashDocumentListCZP.Page.al index c7288f7d03..862876cbcf 100644 --- a/Apps/CZ/CashDeskLocalization/app/Src/Pages/CashDocumentListCZP.Page.al +++ b/Apps/CZ/CashDeskLocalization/app/Src/Pages/CashDocumentListCZP.Page.al @@ -429,16 +429,9 @@ page 31162 "Cash Document List CZP" end; trigger OnOpenPage() - var - CashDeskFilter: Text; begin CashDeskManagementCZP.CheckCashDesks(); - CashDeskFilter := CashDeskManagementCZP.GetCashDesksFilter(); - - Rec.FilterGroup(2); - if CashDeskFilter <> '' then - Rec.SetFilter("Cash Desk No.", CashDeskFilter); - Rec.FilterGroup(0); + CashDeskManagementCZP.SetCashDeskFilter(Rec); end; var diff --git a/Apps/CZ/CashDeskLocalization/app/Src/Pages/PostedCashDocumentListCZP.Page.al b/Apps/CZ/CashDeskLocalization/app/Src/Pages/PostedCashDocumentListCZP.Page.al index 33db82bf1b..0da8a943a7 100644 --- a/Apps/CZ/CashDeskLocalization/app/Src/Pages/PostedCashDocumentListCZP.Page.al +++ b/Apps/CZ/CashDeskLocalization/app/Src/Pages/PostedCashDocumentListCZP.Page.al @@ -245,16 +245,9 @@ page 31167 "Posted Cash Document List CZP" } trigger OnOpenPage() - var - CashDeskFilter: Text; begin CashDeskManagementCZP.CheckCashDesks(); - CashDeskFilter := CashDeskManagementCZP.GetCashDesksFilter(); - - Rec.FilterGroup(2); - if CashDeskFilter <> '' then - Rec.SetFilter("Cash Desk No.", CashDeskFilter); - Rec.FilterGroup(0); + CashDeskManagementCZP.SetCashDeskFilter(Rec); end; var diff --git a/Apps/CZ/CashDeskLocalization/app/Src/Tables/CashDocumentHeaderCZP.Table.al b/Apps/CZ/CashDeskLocalization/app/Src/Tables/CashDocumentHeaderCZP.Table.al index 4c483c3502..0836175e6f 100644 --- a/Apps/CZ/CashDeskLocalization/app/Src/Tables/CashDocumentHeaderCZP.Table.al +++ b/Apps/CZ/CashDeskLocalization/app/Src/Tables/CashDocumentHeaderCZP.Table.al @@ -24,7 +24,6 @@ using Microsoft.Utilities; using System.Automation; using System.Reflection; using System.Security.AccessControl; -using System.Security.User; using System.Utilities; #pragma warning disable AA0232 @@ -323,7 +322,7 @@ table 11732 "Cash Document Header CZP" trigger OnValidate() begin - if not UserSetupManagement.CheckRespCenter(3, "Responsibility Center") then + if not CashDeskManagementCZP.CheckResponsibilityCenter("Responsibility Center") then Error(RespCenterErr, FieldCaption("Responsibility Center"), CashDeskManagementCZP.GetUserCashResponsibilityFilter(CopyStr(UserId(), 1, 50))); CreateDimFromDefaultDim(Rec.FieldNo("Responsibility Center")); @@ -618,7 +617,7 @@ table 11732 "Cash Document Header CZP" DeleteRecordInApprovalRequest(); CashDeskManagementCZP.CheckCashDesks(); - if not UserSetupManagement.CheckRespCenter(3, "Responsibility Center") then + if not CashDeskManagementCZP.CheckResponsibilityCenter("Responsibility Center") then Error(RespCenterDeleteErr, FieldCaption("Responsibility Center"), CashDeskManagementCZP.GetUserCashResponsibilityFilter(CopyStr(UserId(), 1, 50))); CashDocumentPostCZP.DeleteCashDocumentHeader(Rec); @@ -710,7 +709,7 @@ table 11732 "Cash Document Header CZP" trigger OnModify() begin - if not UserSetupManagement.CheckRespCenter(3, "Responsibility Center") then + if not CashDeskManagementCZP.CheckResponsibilityCenter("Responsibility Center") then Error(RespCenterModifyErr, FieldCaption("Responsibility Center"), CashDeskManagementCZP.GetUserCashResponsibilityFilter(CopyStr(UserId(), 1, 50))); end; @@ -731,7 +730,6 @@ table 11732 "Cash Document Header CZP" NoSeriesManagement: Codeunit NoSeriesManagement; #endif DimensionManagement: Codeunit DimensionManagement; - UserSetupManagement: Codeunit "User Setup Management"; ConfirmManagement: Codeunit "Confirm Management"; CashDeskManagementCZP: Codeunit "Cash Desk Management CZP"; RenameErr: Label 'You cannot rename a %1.', Comment = '%1 = TableCaption'; diff --git a/Apps/CZ/CoreLocalizationPack/app/Src/Codeunits/AccSchedExtensionMgtCZL.Codeunit.al b/Apps/CZ/CoreLocalizationPack/app/Src/Codeunits/AccSchedExtensionMgtCZL.Codeunit.al index e774e8ec06..b39f5bca54 100644 --- a/Apps/CZ/CoreLocalizationPack/app/Src/Codeunits/AccSchedExtensionMgtCZL.Codeunit.al +++ b/Apps/CZ/CoreLocalizationPack/app/Src/Codeunits/AccSchedExtensionMgtCZL.Codeunit.al @@ -4,8 +4,10 @@ // ------------------------------------------------------------------------------------------------ namespace Microsoft.Finance.FinancialReports; +using Microsoft.Finance.Analysis; using Microsoft.Finance.GeneralLedger.Setup; using Microsoft.Finance.VAT.Ledger; +using Microsoft.Foundation.Enums; using Microsoft.Foundation.NoSeries; using Microsoft.Foundation.Period; using Microsoft.Inventory.Ledger; @@ -421,6 +423,7 @@ codeunit 31326 "Acc. Sched. Extension Mgt. CZL" var ColumnLayoutCreate: Record "Column Layout"; AccScheduleResultValueCZL: Record "Acc. Schedule Result Value CZL"; + MatrixManagement: Codeunit "Matrix Management"; SaveAccScheduleResultCZL: Page "Save Acc. Schedule Result CZL"; AccSchedName: Code[10]; DimFilter: array[4] of Text[250]; @@ -460,7 +463,11 @@ codeunit 31326 "Acc. Sched. Extension Mgt. CZL" repeat if ColumnLayoutCreate.FindSet() then repeat - Result := AccSchedManagement.CalcCell(AccScheduleLine, ColumnLayoutCreate, UseAmtsInAddCurr); + Result := RoundIfNotNone( + MatrixManagement.RoundAmount( + AccSchedManagement.CalcCell(AccScheduleLine, ColumnLayoutCreate, UseAmtsInAddCurr), + ColumnLayoutCreate."Rounding Factor"), + ColumnLayoutCreate."Rounding Factor"); AccScheduleResultValueCZL."Result Code" := AccScheduleResultHdrCZL."Result Code"; AccScheduleResultValueCZL."Row No." := AccScheduleLine."Line No."; AccScheduleResultValueCZL."Column No." := ColumnLayoutCreate."Line No."; @@ -522,6 +529,14 @@ codeunit 31326 "Acc. Sched. Extension Mgt. CZL" GLSetupRead := true; end; + local procedure RoundIfNotNone(Value: Decimal; RoundingFactor: Enum "Analysis Rounding Factor"): Decimal + begin + if RoundingFactor <> RoundingFactor::None then + exit(Value); + + exit(Round(Value)); + end; + [IntegrationEvent(false, false)] local procedure OnFindSharedAccountScheduleOnBeforeCalcAccSchedLineCellValue(SourceAccScheduleLine: Record "Acc. Schedule Line"; var "; var AccScheduleLine: Record ": Record "Acc. Schedule Line"; var ColumnLayout: Record "Column Layout"; CalcAddCurr: Boolean; var CellValue: Decimal; var IsHandled: Boolean) begin diff --git a/Apps/CZ/CoreLocalizationPack/app/Src/Codeunits/GenJnlPostLineHandlerCZL.Codeunit.al b/Apps/CZ/CoreLocalizationPack/app/Src/Codeunits/GenJnlPostLineHandlerCZL.Codeunit.al index 74e4e35ee5..0e7156404e 100644 --- a/Apps/CZ/CoreLocalizationPack/app/Src/Codeunits/GenJnlPostLineHandlerCZL.Codeunit.al +++ b/Apps/CZ/CoreLocalizationPack/app/Src/Codeunits/GenJnlPostLineHandlerCZL.Codeunit.al @@ -4,14 +4,17 @@ // ------------------------------------------------------------------------------------------------ namespace Microsoft.Finance.GeneralLedger.Posting; -using Microsoft.Sales.Customer; +using Microsoft.Finance.Deferral; using Microsoft.Finance.GeneralLedger.Journal; using Microsoft.Finance.GeneralLedger.Ledger; using Microsoft.Finance.GeneralLedger.Setup; using Microsoft.Finance.ReceivablesPayables; +using Microsoft.Finance.VAT.Calculation; using Microsoft.Finance.VAT.Ledger; using Microsoft.Finance.VAT.Setup; using Microsoft.Foundation.AuditCodes; +using Microsoft.Purchases.Vendor; +using Microsoft.Sales.Customer; using System.Utilities; using System.Security.User; @@ -380,6 +383,8 @@ codeunit 31315 "Gen.Jnl. Post Line Handler CZL" local procedure OnBeforePostDtldCVLedgEntry(sender: Codeunit "Gen. Jnl.-Post Line"; var GenJournalLine: Record "Gen. Journal Line"; var DetailedCVLedgEntryBuffer: Record "Detailed CV Ledg. Entry Buffer"; var AccNo: Code[20]; var IsHandled: Boolean; AddCurrencyCode: Code[10]; MultiplePostingGroups: Boolean) var CustomerPostingGroup: Record "Customer Posting Group"; + VendorPostingGroup: Record "Vendor Posting Group"; + PostingGroupAccountNo: Code[20]; OldCorrection: Boolean; begin if IsHandled then @@ -388,8 +393,22 @@ codeunit 31315 "Gen.Jnl. Post Line Handler CZL" if MultiplePostingGroups and (DetailedCVLedgEntryBuffer."Entry Type" = DetailedCVLedgEntryBuffer."Entry Type"::Application) then begin - CustomerPostingGroup.Get(GenJournalLine."Posting Group"); - if AccNo = CustomerPostingGroup.GetReceivablesAccount() then begin + case GenJournalLine."Account Type" of + GenJournalLine."Account Type"::Customer: + begin + CustomerPostingGroup.Get(GenJournalLine."Posting Group"); + PostingGroupAccountNo := CustomerPostingGroup.GetReceivablesAccount(); + end; + GenJournalLine."Account Type"::Vendor: + begin + VendorPostingGroup.Get(GenJournalLine."Posting Group"); + PostingGroupAccountNo := VendorPostingGroup.GetPayablesAccount(); + end; + else + exit; + end; + + if AccNo = PostingGroupAccountNo then begin OldCorrection := GenJournalLine.Correction; GenJournalLine.Correction := true; sender.CreateGLEntry(GenJournalLine, AccNo, DetailedCVLedgEntryBuffer."Amount (LCY)", 0, DetailedCVLedgEntryBuffer."Currency Code" = AddCurrencyCode); @@ -399,6 +418,18 @@ codeunit 31315 "Gen.Jnl. Post Line Handler CZL" end; end; + [EventSubscriber(ObjectType::Codeunit, Codeunit::"Gen. Jnl.-Post Line", 'OnPostDeferralPostBufferOnAfterFindDeferalPostingBuffer', '', false, false)] + local procedure GetNonDeductibleVATPctOnPostDeferralPostBufferOnAfterFindDeferalPostingBuffer(GenJournalLine: Record "Gen. Journal Line"; var DeferralPostingBuffer: Record "Deferral Posting Buffer"; var NonDeductibleVATPct: Decimal) + var + NonDeductibleVATCZL: Codeunit "Non-Deductible VAT CZL"; + begin + NonDeductibleVATPct := + NonDeductibleVATCZL.GetNonDeductibleVATPct( + GenJournalLine."VAT Bus. Posting Group", GenJournalLine."VAT Prod. Posting Group", + NonDeductibleVATCZL.GetGeneralPostingTypeFromDeferralDocType(DeferralPostingBuffer."Deferral Doc. Type"), + GenJournalLine."VAT Reporting Date"); + end; + [IntegrationEvent(false, false)] local procedure OnBeforeUpdateVATAmountOnAfterInitVAT(var GenJournalLine: Record "Gen. Journal Line"; var GLEntry: Record "G/L Entry"; var IsHandled: Boolean) begin diff --git a/Apps/CZ/CoreLocalizationPack/app/Src/Codeunits/NonDeductibleVATCZL.Codeunit.al b/Apps/CZ/CoreLocalizationPack/app/Src/Codeunits/NonDeductibleVATCZL.Codeunit.al index 6166178a9c..52b7cd76d8 100644 --- a/Apps/CZ/CoreLocalizationPack/app/Src/Codeunits/NonDeductibleVATCZL.Codeunit.al +++ b/Apps/CZ/CoreLocalizationPack/app/Src/Codeunits/NonDeductibleVATCZL.Codeunit.al @@ -4,6 +4,7 @@ // ------------------------------------------------------------------------------------------------ namespace Microsoft.Finance.VAT.Calculation; +using Microsoft.Finance.Deferral; using Microsoft.Finance.GeneralLedger.Journal; using Microsoft.Finance.VAT.Setup; using Microsoft.Foundation.Enums; @@ -107,6 +108,18 @@ codeunit 31147 "Non-Deductible VAT CZL" Error(PurchaseSettlementOnlyErr); end; + internal procedure GetGeneralPostingTypeFromDeferralDocType(DeferralDocType: Enum "Deferral Document Type") GeneralPostingType: Enum "General Posting Type" + begin + case DeferralDocType of + DeferralDocType::"G/L": + exit(GeneralPostingType::" "); + DeferralDocType::Purchase: + exit(GeneralPostingType::Purchase); + DeferralDocType::Sales: + exit(GeneralPostingType::Sale); + end; + end; + [IntegrationEvent(false, false)] local procedure OnBeforeGetNonDeductibleVATPct(VATPostingSetup: Record "VAT Posting Setup"; GeneralPostingType: Enum "General Posting Type"; ToDate: Date; var NonDeductibleVATPct: Decimal; var IsHandled: Boolean) begin diff --git a/Apps/CZ/CoreLocalizationPack/app/Src/Codeunits/PstdGenJnlLineHandlerCZL.Codeunit.al b/Apps/CZ/CoreLocalizationPack/app/Src/Codeunits/PstdGenJnlLineHandlerCZL.Codeunit.al new file mode 100644 index 0000000000..d1f2b90729 --- /dev/null +++ b/Apps/CZ/CoreLocalizationPack/app/Src/Codeunits/PstdGenJnlLineHandlerCZL.Codeunit.al @@ -0,0 +1,18 @@ +// ------------------------------------------------------------------------------------------------ +// 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.GeneralLedger.Journal; + +codeunit 31156 "Pstd.Gen.Jnl.Line Handler CZL" +{ + Access = Internal; + SingleInstance = true; + + [EventSubscriber(ObjectType::Table, Database::"Posted Gen. Journal Line", 'OnAfterInsertFromGenJournalLine', '', false, false)] + local procedure UpdateVATDateOnAfterInsertFromGenJournalLine(GenJournalLine: Record "Gen. Journal Line"; sender: Record "Posted Gen. Journal Line") + begin + sender."VAT Date CZL" := GenJournalLine."VAT Reporting Date"; + sender.Modify(); + end; +} \ No newline at end of file diff --git a/Apps/CZ/CoreLocalizationPack/app/Src/Codeunits/VATDateHandlerCZL.Codeunit.al b/Apps/CZ/CoreLocalizationPack/app/Src/Codeunits/VATDateHandlerCZL.Codeunit.al index d179b1623a..bdcc13ce84 100644 --- a/Apps/CZ/CoreLocalizationPack/app/Src/Codeunits/VATDateHandlerCZL.Codeunit.al +++ b/Apps/CZ/CoreLocalizationPack/app/Src/Codeunits/VATDateHandlerCZL.Codeunit.al @@ -218,14 +218,8 @@ codeunit 11742 "VAT Date Handler CZL" else begin PurchaseHeader.TestField("VAT Reporting Date"); VATPeriodCZLCheck(PurchaseHeader."VAT Reporting Date"); - if PurchaseHeader.Invoice then begin - // FIX - if PurchaseHeader."Original Doc. VAT Date CZL" = 0D then begin - PurchaseHeader."Original Doc. VAT Date CZL" := PurchaseHeader."VAT Reporting Date"; - PurchaseHeader.Modify(); - end; + if PurchaseHeader.Invoice then PurchaseHeader.TestField("Original Doc. VAT Date CZL"); - end; if PurchaseHeader."Original Doc. VAT Date CZL" > PurchaseHeader."VAT Reporting Date" then PurchaseHeader.FieldError("Original Doc. VAT Date CZL", StrSubstNo(MustBeLessOrEqualErr, PurchaseHeader.FieldCaption("VAT Reporting Date"))); end; diff --git a/Apps/CZ/CoreLocalizationPack/app/Src/PageExtensions/AccScheduleOverviewCZL.PageExt.al b/Apps/CZ/CoreLocalizationPack/app/Src/PageExtensions/AccScheduleOverviewCZL.PageExt.al index 0aa10f09ca..2c309046f7 100644 --- a/Apps/CZ/CoreLocalizationPack/app/Src/PageExtensions/AccScheduleOverviewCZL.PageExt.al +++ b/Apps/CZ/CoreLocalizationPack/app/Src/PageExtensions/AccScheduleOverviewCZL.PageExt.al @@ -25,7 +25,7 @@ pageextension 11798 "Acc. Schedule Overview CZL" extends "Acc. Schedule Overview var AccSchedExtensionMgtCZL: Codeunit "Acc. Sched. Extension Mgt. CZL"; begin - AccSchedExtensionMgtCZL.CreateResults(Rec, CurrentColumnName, false); + AccSchedExtensionMgtCZL.CreateResults(Rec, TempFinancialReport."Financial Report Column Group", false); end; } action("Results CZL") diff --git a/Apps/CZ/CoreLocalizationPack/app/Src/PageExtensions/SalesOrderSubformCZL.PageExt.al b/Apps/CZ/CoreLocalizationPack/app/Src/PageExtensions/SalesOrderSubformCZL.PageExt.al index 16381551f4..2f6ed16290 100644 --- a/Apps/CZ/CoreLocalizationPack/app/Src/PageExtensions/SalesOrderSubformCZL.PageExt.al +++ b/Apps/CZ/CoreLocalizationPack/app/Src/PageExtensions/SalesOrderSubformCZL.PageExt.al @@ -8,7 +8,7 @@ pageextension 11790 "Sales Order Subform CZL" extends "Sales Order Subform" { layout { - addafter("Invoice Discount Amount") + addafter("Inv. Discount Amount") { field("Tariff No. CZL"; Rec."Tariff No. CZL") { diff --git a/Apps/CZ/CoreLocalizationPack/app/Src/Reports/DocumentationforVATCZL.Report.al b/Apps/CZ/CoreLocalizationPack/app/Src/Reports/DocumentationforVATCZL.Report.al index 7a90586c62..533e2b0d51 100644 --- a/Apps/CZ/CoreLocalizationPack/app/Src/Reports/DocumentationforVATCZL.Report.al +++ b/Apps/CZ/CoreLocalizationPack/app/Src/Reports/DocumentationforVATCZL.Report.al @@ -251,9 +251,6 @@ report 11757 "Documentation for VAT CZL" } trigger OnAfterGetRecord() begin - if "Original VAT Entry No. CZL" <> 0 then - Base := CalcDeductibleVATBaseCZL(); - VATEntrySubtotalAmt[1] += Base; VATEntrySubtotalAmt[2] += Amount; VATEntrySubtotalAmt[3] += "Original VAT Base CZL"; @@ -410,6 +407,9 @@ report 11757 "Documentation for VAT CZL" VATEntry.Amount := VATEntry."Additional-Currency Amount"; end; + if VATEntry."Original VAT Entry No. CZL" <> 0 then + VATEntry.Base := VATEntry.CalcDeductibleVATBaseCZL(); + if MergeByDocumentNo then begin "VAT Entry".SetRange("VAT Reporting Date", VATEntry."VAT Reporting Date"); "VAT Entry".SetRange("VAT Bus. Posting Group", VATEntry."VAT Bus. Posting Group"); @@ -567,11 +567,11 @@ report 11757 "Documentation for VAT CZL" begin if "VAT Posting Setup".GetFilters() <> '' then VATPostingSetupFilter := "VAT Posting Setup".TableCaption() + ': ' + "VAT Posting Setup".GetFilters(); - if EndDateReq = 0D then - VATEntry.SetFilter("VAT Reporting Date", '%1..', StartDateReq) - else - VATEntry.SetRange("VAT Reporting Date", StartDateReq, EndDateReq); - VATDateFilter := VATEntry.GetFilter("VAT Reporting Date"); + if EndDateReq = 0D then + VATEntry.SetFilter("VAT Reporting Date", '%1..', StartDateReq) + else + VATEntry.SetRange("VAT Reporting Date", StartDateReq, EndDateReq); + VATDateFilter := VATEntry.GetFilter("VAT Reporting Date"); end; var diff --git a/Apps/CZ/CoreLocalizationPack/test/Src/PurchPostPrepmtHandlerCZL.Codeunit.al b/Apps/CZ/CoreLocalizationPack/test/Src/PurchPostPrepmtHandlerCZL.Codeunit.al new file mode 100644 index 0000000000..ac33795f23 --- /dev/null +++ b/Apps/CZ/CoreLocalizationPack/test/Src/PurchPostPrepmtHandlerCZL.Codeunit.al @@ -0,0 +1,8 @@ +codeunit 148128 "Purch.Post Prepmt. Handler CZL" +{ + [EventSubscriber(ObjectType::Codeunit, Codeunit::"Purchase-Post Prepayments", 'OnPostVendorEntryOnAfterInitNewLine', '', false, false)] + local procedure MyProcedure(var GenJnlLine: Record "Gen. Journal Line"; PurchHeader: Record "Purchase Header") + begin + GenJnlLine."Original Doc. VAT Date CZL" := PurchHeader."Original Doc. VAT Date CZL"; + end; +} \ No newline at end of file diff --git a/Apps/CZ/CoreLocalizationPack/test/Src/TestInitializeHandlerCZL.Codeunit.al b/Apps/CZ/CoreLocalizationPack/test/Src/TestInitializeHandlerCZL.Codeunit.al index ab6860f3d6..187a6f04aa 100644 --- a/Apps/CZ/CoreLocalizationPack/test/Src/TestInitializeHandlerCZL.Codeunit.al +++ b/Apps/CZ/CoreLocalizationPack/test/Src/TestInitializeHandlerCZL.Codeunit.al @@ -11,8 +11,6 @@ codeunit 148104 "Test Initialize Handler CZL" case CallerCodeunitID of 137462: // "Phys. Invt. Order Subform UT": UpdateInventorySetup(); - 135300: // "O365 Purch Item Charge Tests" - UpdateGeneralLedgerSetup(); end; end; @@ -39,11 +37,13 @@ codeunit 148104 "Test Initialize Handler CZL" 134992: // ERM Financial Reports IV begin TryBindSuppConfVATEntUpdate(); - UpdateGeneralLedgerSetup(); UpdateUserSetup(); end; + 137161: // SCM Warehouse Orders + DisableVATDateUsage(); end; - if not (CallerCodeunitID = 134045) then + + if not (CallerCodeunitID in [134008, 134045, 134088, 134992]) then TryUnbindSuppConfVATEntUpdate(); end; @@ -79,15 +79,6 @@ codeunit 148104 "Test Initialize Handler CZL" end; end; - local procedure UpdateGeneralLedgerSetup() - var - GeneralLedgerSetup: Record "General Ledger Setup"; - begin - GeneralLedgerSetup.Get(); - GeneralLedgerSetup."Def. Orig. Doc. VAT Date CZL" := GeneralLedgerSetup."Def. Orig. Doc. VAT Date CZL"::"VAT Date"; - GeneralLedgerSetup.Modify(); - end; - local procedure UpdateUserSetup() var UserSetup: Record "User Setup"; @@ -102,6 +93,15 @@ codeunit 148104 "Test Initialize Handler CZL" UserSetup.Modify(); end; + local procedure DisableVATDateUsage() + var + GeneralLedgerSetup: Record "General Ledger Setup"; + begin + GeneralLedgerSetup.Get(); + GeneralLedgerSetup."VAT Reporting Date Usage" := GeneralLedgerSetup."VAT Reporting Date Usage"::Disabled; + GeneralLedgerSetup.Modify(); + end; + local procedure TryBindSuppConfVATEntUpdate(): Boolean begin exit(BindSubscription(SuppConfVATEntUpdate)); diff --git a/Apps/DK/ElectronicVATDeclarationDK/app/app.json b/Apps/DK/ElectronicVATDeclarationDK/app/app.json index de7398de1a..de95ceb05b 100644 --- a/Apps/DK/ElectronicVATDeclarationDK/app/app.json +++ b/Apps/DK/ElectronicVATDeclarationDK/app/app.json @@ -30,7 +30,7 @@ }, { "from": 13668, - "to": 13668 + "to": 13669 } ], "resourceExposurePolicy": { diff --git a/Apps/DK/ElectronicVATDeclarationDK/app/src/Engine/ElecVATDeclInstall.Codeunit.al b/Apps/DK/ElectronicVATDeclarationDK/app/src/Engine/ElecVATDeclInstall.Codeunit.al index 3aee102e00..1d0121e392 100644 --- a/Apps/DK/ElectronicVATDeclarationDK/app/src/Engine/ElecVATDeclInstall.Codeunit.al +++ b/Apps/DK/ElectronicVATDeclarationDK/app/src/Engine/ElecVATDeclInstall.Codeunit.al @@ -3,6 +3,7 @@ namespace Microsoft.Finance.VAT.Reporting; using Microsoft.Foundation.Company; using System.Environment; using System.Privacy; +using System.Upgrade; codeunit 13611 "Elec. VAT Decl. Install" { @@ -35,6 +36,8 @@ codeunit 13611 "Elec. VAT Decl. Install" InsertVATReportsConfiguration(); UpdateVATReportSetup(); InsertEmptySetup(); + + SetAllUpgradeTags(); end; local procedure ApplyEvaluationClassificationsForPrivacy() @@ -91,4 +94,13 @@ codeunit 13611 "Elec. VAT Decl. Install" ElecVATDeclSetup."Use Azure Key Vault" := true; if ElecVATDeclSetup.Modify(true) then; end; + + local procedure SetAllUpgradeTags() + var + UpgradeTag: Codeunit "Upgrade Tag"; + ElecVATDeclUpgrade: Codeunit "Elec. VAT Decl. Upgrade"; + begin + if not UpgradeTag.HasUpgradeTag(ElecVATDeclUpgrade.GetElecVATDeclAKVSetupUpgradeTag()) then + UpgradeTag.SetUpgradeTag(ElecVATDeclUpgrade.GetElecVATDeclAKVSetupUpgradeTag()); + end; } \ No newline at end of file diff --git a/Apps/DK/ElectronicVATDeclarationDK/app/src/Engine/ElecVATDeclUpgrade.Codeunit.al b/Apps/DK/ElectronicVATDeclarationDK/app/src/Engine/ElecVATDeclUpgrade.Codeunit.al new file mode 100644 index 0000000000..b91a7463ce --- /dev/null +++ b/Apps/DK/ElectronicVATDeclarationDK/app/src/Engine/ElecVATDeclUpgrade.Codeunit.al @@ -0,0 +1,46 @@ +namespace Microsoft.Finance.VAT.Reporting; + +using System.Upgrade; + +codeunit 13669 "Elec. VAT Decl. Upgrade" +{ + Subtype = Upgrade; + Access = Internal; + + trigger OnUpgradePerCompany() + begin + UpgradeUseAKVSetup(); + end; + + local procedure UpgradeUseAKVSetup() + var + ElecVATDeclSetup: Record "Elec. VAT Decl. Setup"; + UpgradeTag: Codeunit "Upgrade Tag"; + begin + if UpgradeTag.HasUpgradeTag(GetElecVATDeclAKVSetupUpgradeTag()) then + exit; + + if not ElecVATDeclSetup.Get() then + exit; + + ElecVATDeclSetup."Use Azure Key Vault" := true; + ElecVATDeclSetup.Modify(); + + UpgradeTag.SetUpgradeTag(GetElecVATDeclAKVSetupUpgradeTag()); + end; + + + procedure GetElecVATDeclAKVSetupUpgradeTag(): Code[250]; + begin + exit('MS-537717-ElecVATDeclSetupWithAKVVariableTag-20250609'); + end; + + [EventSubscriber(ObjectType::Codeunit, Codeunit::"Upgrade Tag", 'OnGetPerCompanyUpgradeTags', '', false, false)] + local procedure RegisterPerCompanyags(var PerCompanyUpgradeTags: List of [Code[250]]) + var + UpgradeTag: Codeunit "Upgrade Tag"; + begin + if not UpgradeTag.HasUpgradeTag(GetElecVATDeclAKVSetupUpgradeTag()) then + PerCompanyUpgradeTags.Add(GetElecVATDeclAKVSetupUpgradeTag()); + end; +} \ No newline at end of file diff --git a/Apps/DK/OIOUBL/app/src/SalesCreditMemo/OIOUBLExportSalesCrMemo.Codeunit.al b/Apps/DK/OIOUBL/app/src/SalesCreditMemo/OIOUBLExportSalesCrMemo.Codeunit.al index 42dc23f357..fd011d5572 100644 --- a/Apps/DK/OIOUBL/app/src/SalesCreditMemo/OIOUBLExportSalesCrMemo.Codeunit.al +++ b/Apps/DK/OIOUBL/app/src/SalesCreditMemo/OIOUBLExportSalesCrMemo.Codeunit.al @@ -58,7 +58,7 @@ codeunit 13637 "OIOUBL-Export Sales Cr. Memo" OIOUBLManagement: Codeunit "OIOUBL-Management"; TempBlob: Codeunit "Temp Blob"; FileOutStream: OutStream; - FileName: Text[250]; + FileName: Text; begin TempBlob.CreateOutStream(FileOutStream); CreateXML(SalesCrMemoHeader, FileOutStream); @@ -69,6 +69,7 @@ codeunit 13637 "OIOUBL-Export Sales Cr. Memo" OIOUBLManagement.UpdateRecordExportBuffer(SalesCrMemoHeader.RecordId(), TempBlob, FileName); OIOUBLManagement.ExportXMLFile(SalesCrMemoHeader."No.", TempBlob, SalesSetup."OIOUBL-Cr. Memo Path", FileName); + OnExportXMLOnAfterExportXMLFile(SalesCrMemoHeader, TempBlob, FileName); SalesCrMemoHeader2.Get(SalesCrMemoHeader."No."); SalesCrMemoHeader2."OIOUBL-Electronic Credit Memo Created" := true; @@ -398,4 +399,9 @@ codeunit 13637 "OIOUBL-Export Sales Cr. Memo" local procedure OnCreateXMLOnAfterSalesCrMemoLineSetFilters(var SalesCrMemoLine: Record "Sales Cr.Memo Line"; SalesCrMemoHeader: Record "Sales Cr.Memo Header") begin end; + + [IntegrationEvent(false, false)] + local procedure OnExportXMLOnAfterExportXMLFile(var SalesCrMemoHeader: Record "Sales Cr.Memo Header"; var TempBlob: Codeunit "Temp Blob"; FileName: Text) + begin + end; } diff --git a/Apps/DK/OIOUBL/app/src/SalesInvoice/OIOUBLExportSalesInvoice.Codeunit.al b/Apps/DK/OIOUBL/app/src/SalesInvoice/OIOUBLExportSalesInvoice.Codeunit.al index 67e256e4f3..7e9d7e0a86 100644 --- a/Apps/DK/OIOUBL/app/src/SalesInvoice/OIOUBLExportSalesInvoice.Codeunit.al +++ b/Apps/DK/OIOUBL/app/src/SalesInvoice/OIOUBLExportSalesInvoice.Codeunit.al @@ -59,7 +59,7 @@ codeunit 13636 "OIOUBL-Export Sales Invoice" OIOUBLManagement: Codeunit "OIOUBL-Management"; TempBlob: Codeunit "Temp Blob"; FileOutStream: OutStream; - FileName: Text[250]; + FileName: Text; begin TempBlob.CreateOutStream(FileOutStream); CreateXML(SalesInvoiceHeader, FileOutStream); @@ -70,6 +70,7 @@ codeunit 13636 "OIOUBL-Export Sales Invoice" OIOUBLManagement.UpdateRecordExportBuffer(SalesInvoiceHeader.RecordId(), TempBlob, FileName); OIOUBLManagement.ExportXMLFile(SalesInvoiceHeader."No.", TempBlob, SalesSetup."OIOUBL-Invoice Path", FileName); + OnExportXMLOnAfterExportXMLFile(SalesInvoiceHeader, TempBlob, FileName); SalesInvHeader2.Get(SalesInvoiceHeader."No."); SalesInvHeader2."OIOUBL-Electronic Invoice Created" := true; @@ -491,4 +492,9 @@ codeunit 13636 "OIOUBL-Export Sales Invoice" local procedure OnCreateXMLOnAfterSalesInvLineSetFilters(var SalesInvoiceLine: Record "Sales Invoice Line"; SalesInvoiceHeader: Record "Sales Invoice Header") begin end; + + [IntegrationEvent(false, false)] + local procedure OnExportXMLOnAfterExportXMLFile(var SalesInvoiceHeader: Record "Sales Invoice Header"; var TempBlob: Codeunit "Temp Blob"; FileName: Text) + begin + end; } diff --git a/Apps/IN/INGST/app/GSTBase/src/TaxEngineSetup/GSTTaxConfiguration.Codeunit.al b/Apps/IN/INGST/app/GSTBase/src/TaxEngineSetup/GSTTaxConfiguration.Codeunit.al index 7577d73079..e4eebec3b1 100644 --- a/Apps/IN/INGST/app/GSTBase/src/TaxEngineSetup/GSTTaxConfiguration.Codeunit.al +++ b/Apps/IN/INGST/app/GSTBase/src/TaxEngineSetup/GSTTaxConfiguration.Codeunit.al @@ -309,7 +309,7 @@ codeunit 18017 "GST Tax Configuration" UseCases.Add('{01C97F7D-4263-4387-84E1-610D2EA4A762}', 5); UseCases.Add('{66A099C8-9660-498E-9BEB-61296A76CFAF}', 1); UseCases.Add('{929EB05F-45B5-4F4F-9DD4-61AFAB36F21B}', 3); - UseCases.Add('{E75A7A67-D332-41BE-B7EA-61C8BF69E9F7}', 3); + UseCases.Add('{E75A7A67-D332-41BE-B7EA-61C8BF69E9F7}', 4); UseCases.Add('{4738101C-19E3-418C-A19D-61E67100D199}', 4); UseCases.Add('{4CB6ACCD-BD47-4485-A757-62924EA09524}', 6); UseCases.Add('{8B96F1E1-FC2C-48FD-AD1E-62986961AC0D}', 1); diff --git a/Apps/IN/INGST/app/GSTBase/src/table/HSNSAC.table.al b/Apps/IN/INGST/app/GSTBase/src/table/HSNSAC.table.al index 18e76f5951..547ce184bb 100644 --- a/Apps/IN/INGST/app/GSTBase/src/table/HSNSAC.table.al +++ b/Apps/IN/INGST/app/GSTBase/src/table/HSNSAC.table.al @@ -13,15 +13,13 @@ table 18009 "HSN/SAC" fields { -#pragma warning disable AS0118 - field(1; "GST Group Code"; Code[20]) + field(1; "GST Group Code"; Code[10]) { Caption = 'GST Group Code'; NotBlank = true; DataClassification = CustomerContent; TableRelation = "GST Group"; } -#pragma warning restore AS0118 field(2; "Code"; code[10]) { Caption = 'Code'; diff --git a/Apps/IN/INGST/app/Translations/India GST.en-GB.xlf b/Apps/IN/INGST/app/Translations/India GST.en-GB.xlf index 4c6b2f63f4..fe5bc75753 100644 --- a/Apps/IN/INGST/app/Translations/India GST.en-GB.xlf +++ b/Apps/IN/INGST/app/Translations/India GST.en-GB.xlf @@ -12964,7 +12964,7 @@ GST Use Cases - + Codeunit GST Use Case Labels - Method GetConfig - NamedType {E75A7A67-D332-41BE-B7EA-61C8BF69E9F7}Lbl diff --git a/Apps/IN/INGST/app/Translations/India GST.en-US.xlf b/Apps/IN/INGST/app/Translations/India GST.en-US.xlf index bdcb504533..6c7ab1335d 100644 --- a/Apps/IN/INGST/app/Translations/India GST.en-US.xlf +++ b/Apps/IN/INGST/app/Translations/India GST.en-US.xlf @@ -12964,7 +12964,7 @@ GST Use Cases - + Codeunit GST Use Case Labels - Method GetConfig - NamedType {E75A7A67-D332-41BE-B7EA-61C8BF69E9F7}Lbl diff --git a/Apps/IN/INTDS/app/TDSBase/src/TaxEngineSetup/TDSTaxConfiguration.Codeunit.al b/Apps/IN/INTDS/app/TDSBase/src/TaxEngineSetup/TDSTaxConfiguration.Codeunit.al index 6fbdd14806..0a1f793ee0 100644 --- a/Apps/IN/INTDS/app/TDSBase/src/TaxEngineSetup/TDSTaxConfiguration.Codeunit.al +++ b/Apps/IN/INTDS/app/TDSBase/src/TaxEngineSetup/TDSTaxConfiguration.Codeunit.al @@ -63,7 +63,7 @@ codeunit 18694 "TDS Tax Configuration" UseCases.Add('{B0C259BC-64CC-4818-887A-3337D357CDFF}', 2); UseCases.Add('{33BFBE99-9140-4112-A55B-35EC0D9B61B9}', 2); UseCases.Add('{271D5BC6-17E8-424E-9E34-3BEE548F938F}', 1); - UseCases.Add('{A8E114BF-F8CD-44DB-A2B3-614BC18F4442}', 18); + UseCases.Add('{A8E114BF-F8CD-44DB-A2B3-614BC18F4442}', 19); UseCases.Add('{6FBA1A5C-41A0-4430-976E-6B54E4884164}', 1); UseCases.Add('{FEE5DFFF-0BC1-4246-AD90-6CB3DC44A451}', 1); UseCases.Add('{FA0E357D-1AC0-42AA-94DE-6DACA521D38E}', 2); diff --git a/Apps/IN/INTDS/app/Translations/India TDS.en-GB.xlf b/Apps/IN/INTDS/app/Translations/India TDS.en-GB.xlf index 72f2fbc3c5..e1ec420ee6 100644 --- a/Apps/IN/INTDS/app/Translations/India TDS.en-GB.xlf +++ b/Apps/IN/INTDS/app/Translations/India TDS.en-GB.xlf @@ -1988,7 +1988,7 @@ TDS Use Cases - + Codeunit TDS Tax Engine Setup - Method GetConfig - NamedType {A8E114BF-F8CD-44DB-A2B3-614BC18F4442}Lbl diff --git a/Apps/IN/INTDS/app/Translations/India TDS.en-US.xlf b/Apps/IN/INTDS/app/Translations/India TDS.en-US.xlf index f37fcbbd2a..3134018327 100644 --- a/Apps/IN/INTDS/app/Translations/India TDS.en-US.xlf +++ b/Apps/IN/INTDS/app/Translations/India TDS.en-US.xlf @@ -1988,7 +1988,7 @@ TDS Use Cases - + Codeunit TDS Tax Engine Setup - Method GetConfig - NamedType {A8E114BF-F8CD-44DB-A2B3-614BC18F4442}Lbl diff --git a/Apps/IS/ISCore/app/src/Codeunits/EnableISCoreApp.Codeunit.al b/Apps/IS/ISCore/app/src/Codeunits/EnableISCoreApp.Codeunit.al index f8b75581c5..62d75980d2 100644 --- a/Apps/IS/ISCore/app/src/Codeunits/EnableISCoreApp.Codeunit.al +++ b/Apps/IS/ISCore/app/src/Codeunits/EnableISCoreApp.Codeunit.al @@ -92,8 +92,20 @@ codeunit 14611 "Enable IS Core App" SourceRecRef.Close(); end; + procedure UpdateDocumentRetentionPeriod(); + var + ISCoreInstall: codeunit "IS Core Install"; + begin + ISCoreInstall.UpdateGeneralLedgserSetup(); + end; + procedure GetISCoreAppUpdateTag(): Code[250] begin exit('MS-460511-ISCoreApp-20231118'); end; + + procedure GetISDocRetentionPeriodTag(): Code[250] + begin + exit('MS-534853-DocRetentionPeriod-20240514'); + end; } \ No newline at end of file diff --git a/Apps/IS/ISCore/app/src/Codeunits/ISCoreUpgrade.Codeunit.al b/Apps/IS/ISCore/app/src/Codeunits/ISCoreUpgrade.Codeunit.al index ed61c3304f..978d30e41d 100644 --- a/Apps/IS/ISCore/app/src/Codeunits/ISCoreUpgrade.Codeunit.al +++ b/Apps/IS/ISCore/app/src/Codeunits/ISCoreUpgrade.Codeunit.al @@ -4,9 +4,7 @@ // ------------------------------------------------------------------------------------------------ namespace Microsoft.Finance; -#if CLEAN24 using System.Upgrade; -#endif codeunit 14602 "IS Core Upgrade" { @@ -17,6 +15,7 @@ codeunit 14602 "IS Core Upgrade" var begin TransferISCpecificData(); + UpdateDocumentRetentionPeriod(); end; local procedure TransferISCpecificData() @@ -35,4 +34,25 @@ codeunit 14602 "IS Core Upgrade" UpgradeTag.SetUpgradeTag(EnableISCoreApp.GetISCoreAppUpdateTag()); #endif end; + + local procedure UpdateDocumentRetentionPeriod() + var + UpgradeTag: Codeunit "Upgrade Tag"; + ISCoreInstall: Codeunit "IS Core Install"; + EnableISCoreApp: Codeunit "Enable IS Core App"; + begin + if UpgradeTag.HasUpgradeTag(EnableISCoreApp.GetISDocRetentionPeriodTag()) then + exit; + ISCoreInstall.UpdateGeneralLedgserSetup(); + UpgradeTag.SetUpgradeTag(EnableISCoreApp.GetISDocRetentionPeriodTag()); + end; + + [EventSubscriber(ObjectType::Codeunit, Codeunit::"Upgrade Tag", 'OnGetPerCompanyUpgradeTags', '', false, false)] + local procedure RegisterPerCompanyTags(var PerCompanyUpgradeTags: List of [Code[250]]) + var + EnableISCoreApp: Codeunit "Enable IS Core App"; + begin + PerCompanyUpgradeTags.Add(EnableISCoreApp.GetISCoreAppUpdateTag()); + PerCompanyUpgradeTags.Add(EnableISCoreApp.GetISDocRetentionPeriodTag()); + end; } \ No newline at end of file diff --git a/Apps/IS/ISCore/app/src/Pages/ISCoreAppSetupWizard.Page.al b/Apps/IS/ISCore/app/src/Pages/ISCoreAppSetupWizard.Page.al index 6454c7bf62..dd27cb8adb 100644 --- a/Apps/IS/ISCore/app/src/Pages/ISCoreAppSetupWizard.Page.al +++ b/Apps/IS/ISCore/app/src/Pages/ISCoreAppSetupWizard.Page.al @@ -293,6 +293,7 @@ page 14604 "IS Core App Setup Wizard" OnBeforeFinishAction(); SetupFinished := true; EnableISCoreApp.TransferData(); + EnableISCoreApp.UpdateDocumentRetentionPeriod(); ISCoreAppSetup.Get(); ISCoreAppSetup.Enabled := true; diff --git a/Apps/US/IRSForms/app/src/Printing/IRS 1099 Print.docx b/Apps/US/IRSForms/app/src/Printing/IRS 1099 Print.docx index 6d5d85da6ae5608558fd6f3f7ec6f09996e55857..76965c59edae4915765ff7bf603c46c301ccc95d 100644 GIT binary patch delta 10272 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 AfdBvi delta 10187 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 AegFUf diff --git a/Apps/W1/AMCBanking365Fundamentals/app/Codeunits/AMCBankingMgt.Codeunit.al b/Apps/W1/AMCBanking365Fundamentals/app/Codeunits/AMCBankingMgt.Codeunit.al index 81e091aa49..702cbaff83 100644 --- a/Apps/W1/AMCBanking365Fundamentals/app/Codeunits/AMCBankingMgt.Codeunit.al +++ b/Apps/W1/AMCBanking365Fundamentals/app/Codeunits/AMCBankingMgt.Codeunit.al @@ -229,6 +229,9 @@ codeunit 20105 "AMC Banking Mgt." var AMCBankingSetup: Record "AMC Banking Setup"; begin + if CompanyName() <> CompanyName then + AMCBankingSetup.ChangeCompany(CompanyName); + if (AMCBankingSetup.Get()) then if (IsSolutionSandbox(AMCBankingSetup)) then SetURLsToDefault(AMCBankingSetup); diff --git a/Apps/W1/APIV2/app/src/pages/APIV2CustContacts.Page.al b/Apps/W1/APIV2/app/src/pages/APIV2CustContacts.Page.al index 13244ff3b8..810ddb84cb 100644 --- a/Apps/W1/APIV2/app/src/pages/APIV2CustContacts.Page.al +++ b/Apps/W1/APIV2/app/src/pages/APIV2CustContacts.Page.al @@ -1,3 +1,7 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ namespace Microsoft.API.V2; using Microsoft.CRM.Contact; @@ -17,6 +21,7 @@ page 30089 "APIV2 - CustContacts" PageType = API; SourceTable = Contact; Extensible = false; + InsertAllowed = false; layout { @@ -57,9 +62,8 @@ page 30089 "APIV2 - CustContacts" RegisterFieldSet(Rec.FieldNo("Job Title")); end; } - field(customerId; Customer.SystemId) + field(customerId; CustomerId) { - Editable = false; } field(customerName; Customer.Name) { @@ -78,9 +82,8 @@ page 30089 "APIV2 - CustContacts" Multiplicity = ZeroOrOne; EntityName = 'pdfDocument'; EntitySetName = 'pdfDocument'; - SubPageLink = "Document Id" = field(Systemid), "Document Type" = const("Customer Statemet"); + SubPageLink = "Document Id" = field(SystemId), "Document Type" = const("Customer Statement"); } - } } } @@ -91,6 +94,7 @@ page 30089 "APIV2 - CustContacts" var Customer: Record Customer; TempFieldSet: Record System.Reflection.Field temporary; + CustomerId: Guid; trigger OnAfterGetRecord() begin @@ -98,7 +102,22 @@ page 30089 "APIV2 - CustContacts" end; trigger OnModifyRecord(): Boolean + var + ChangedCustomer: Record Customer; + ContactBusinessRelation: Record "Contact Business Relation"; + CustomerWithProvidedIdDoesNotExistErr: Label 'Customer with provided id - does not exist'; begin + if CustomerId <> Customer.SystemId then begin + if not ChangedCustomer.GetBySystemId(CustomerId) then + Error(CustomerWithProvidedIdDoesNotExistErr); + ContactBusinessRelation.SetRange("Contact No.", Rec."Company No."); + ContactBusinessRelation.SetRange("Link to Table", ContactBusinessRelation."Link to Table"::Customer); + ContactBusinessRelation.SetRange("No.", Customer."No."); + if ContactBusinessRelation.FindFirst() then begin + ContactBusinessRelation.Validate("No.", ChangedCustomer."No."); + ContactBusinessRelation.Modify(true); + end; + end; SetCalculatedFields(); end; @@ -114,8 +133,10 @@ page 30089 "APIV2 - CustContacts" Clear(Customer); ContactBusinessRelation.SetRange("Contact No.", Rec."Company No."); ContactBusinessRelation.SetRange("Link to Table", ContactBusinessRelation."Link to Table"::Customer); - if ContactBusinessRelation.FindFirst() then + if ContactBusinessRelation.FindFirst() then begin Customer.Get(ContactBusinessRelation."No."); + CustomerId := Customer.SystemId; + end; end; local procedure RegisterFieldSet(FieldNo: Integer) @@ -132,6 +153,7 @@ page 30089 "APIV2 - CustContacts" local procedure ClearCalculatedFields() begin Clear(Customer); + Clear(CustomerId); end; trigger OnOpenPage() diff --git a/Apps/W1/BankDeposits/app/src/codeunits/NavigateBankDepositExt.Codeunit.al b/Apps/W1/BankDeposits/app/src/codeunits/NavigateBankDepositExt.Codeunit.al index 3009fd09e4..60f77ec4cd 100644 --- a/Apps/W1/BankDeposits/app/src/codeunits/NavigateBankDepositExt.Codeunit.al +++ b/Apps/W1/BankDeposits/app/src/codeunits/NavigateBankDepositExt.Codeunit.al @@ -9,16 +9,11 @@ using Microsoft.Finance.GeneralLedger.Ledger; using Microsoft.Finance.VAT.Ledger; using Microsoft.Purchases.Payables; using Microsoft.Service.Ledger; -using Microsoft.Sales.Receivables; -using Microsoft.Bank.Ledger; codeunit 1699 "Navigate Bank Deposit Ext." { Access = Internal; - var - RecordWithoutKeysMsg: Label 'Before you can navigate on a deposit, you must create and activate a key group called "NavDep". If you cannot do this yourself, ask your system administrator.'; - local procedure SetPostedBankDepositHeaderFilters(var PostedBankDepositHeader: Record "Posted Bank Deposit Header"; DocNoFilter: Text): Boolean begin if not PostedBankDepositHeader.ReadPermission() then @@ -99,89 +94,4 @@ codeunit 1699 "Navigate Bank Deposit Ext." DocType := CopyStr(PostedBankDepositHeader.TableCaption(), 1, MaxStrLen(DocType)); Sender.SetSource(PostedBankDepositHeader."Posting Date", DocType, PostedBankDepositHeader."No.", 4, PostedBankDepositHeader."Bank Account No."); end; - - // OVERRRIDING HOW TO GET RELATED ENTRIES FOR POSTED BANK DEPOSITS - - // When searching from a Posted Bank Deposit as source, finding the related GL Entries, Customer Ledger Entries, etc. - // is done differently, as their ExtDocNo has the corresponding Bank Deposit No. - - [EventSubscriber(ObjectType::Page, Page::Navigate, 'OnBeforeFindCustLedgerEntry', '', false, false)] - local procedure OnBeforeFindCustLedgerEntry(Sender: Page Navigate; var CustLedgerEntry: Record "Cust. Ledger Entry"; DocNoFilter: Text; PostingDateFilter: Text; ExtDocNo: Text; var IsHandled: Boolean) - begin - if not Sender.GetNavigationFromPostedBankDeposit() then - exit; - if not CustLedgerEntry.ReadPermission() then - exit; - if IsHandled then - exit; - - IsHandled := true; - - CustLedgerEntry.Reset(); - if not CustLedgerEntry.SetCurrentKey("External Document No.", "Posting Date") then - Error(RecordWithoutKeysMsg); - CustLedgerEntry.SetFilter("External Document No.", DocNoFilter); - CustLedgerEntry.SetFilter("Posting Date", PostingDateFilter); - Sender.InsertIntoDocEntry(DATABASE::"Cust. Ledger Entry", CustLedgerEntry.TableCaption(), CustLedgerEntry.Count()); - end; - - [EventSubscriber(ObjectType::Page, Page::Navigate, 'OnBeforeFindVendorLedgerEntry', '', false, false)] - local procedure OnBeforeFindVendorLedgerEntry(Sender: Page Navigate; var VendorLedgerEntry: Record "Vendor Ledger Entry"; DocNoFilter: Text; PostingDateFilter: Text; ExtDocNo: Text; var IsHandled: Boolean) - begin - if not Sender.GetNavigationFromPostedBankDeposit() then - exit; - if not VendorLedgerEntry.ReadPermission() then - exit; - if IsHandled then - exit; - - IsHandled := true; - - VendorLedgerEntry.Reset(); - if not VendorLedgerEntry.SetCurrentKey("External Document No.", "Posting Date") then - Error(RecordWithoutKeysMsg); - VendorLedgerEntry.SetFilter("External Document No.", DocNoFilter); - VendorLedgerEntry.SetFilter("Posting Date", PostingDateFilter); - Sender.InsertIntoDocEntry(DATABASE::"Vendor Ledger Entry", VendorLedgerEntry.TableCaption(), VendorLedgerEntry.Count()); - end; - - [EventSubscriber(ObjectType::Page, Page::Navigate, 'OnBeforeFindBankAccountLedgerEntry', '', false, false)] - local procedure OnBeforeFindBankAccountLedgerEntry(Sender: Page Navigate; var BankAccountLedgerEntry: Record "Bank Account Ledger Entry"; DocNoFilter: Text; PostingDateFilter: Text; ExtDocNo: Text; var IsHandled: Boolean) - begin - if not Sender.GetNavigationFromPostedBankDeposit() then - exit; - if not BankAccountLedgerEntry.ReadPermission() then - exit; - if IsHandled then - exit; - - IsHandled := true; - - BankAccountLedgerEntry.Reset(); - if not BankAccountLedgerEntry.SetCurrentKey("External Document No.", "Posting Date") then - Error(RecordWithoutKeysMsg); - BankAccountLedgerEntry.SetFilter("External Document No.", DocNoFilter); - BankAccountLedgerEntry.SetFilter("Posting Date", PostingDateFilter); - Sender.InsertIntoDocEntry(DATABASE::"Bank Account Ledger Entry", BankAccountLedgerEntry.TableCaption(), BankAccountLedgerEntry.Count()); - end; - - [EventSubscriber(ObjectType::Page, Page::Navigate, 'OnBeforeFindGLEntry', '', false, false)] - local procedure OnBeforeFindGLEntry(Sender: Page Navigate; var GLEntry: Record "G/L Entry"; DocNoFilter: Text; PostingDateFilter: Text; ExtDocNo: Text; var IsHandled: Boolean) - begin - if not Sender.GetNavigationFromPostedBankDeposit() then - exit; - if not GLEntry.ReadPermission() then - exit; - if IsHandled then - exit; - - IsHandled := true; - - GLEntry.Reset(); - if not GLEntry.SetCurrentKey("External Document No.", "Posting Date") then - Error(RecordWithoutKeysMsg); - GLEntry.SetFilter("External Document No.", DocNoFilter); - GLEntry.SetFilter("Posting Date", PostingDateFilter); - Sender.InsertIntoDocEntry(DATABASE::"G/L Entry", GLEntry.TableCaption(), GLEntry.Count()); - end; } \ No newline at end of file diff --git a/Apps/W1/BankDeposits/app/src/pages/BankDepositSubform.Page.al b/Apps/W1/BankDeposits/app/src/pages/BankDepositSubform.Page.al index cce9c1cb02..16907b1ef3 100644 --- a/Apps/W1/BankDeposits/app/src/pages/BankDepositSubform.Page.al +++ b/Apps/W1/BankDeposits/app/src/pages/BankDepositSubform.Page.al @@ -431,7 +431,8 @@ page 1693 "Bank Deposit Subform" Rec."Currency Factor" := BankDepositHeader."Currency Factor"; Rec."Document Date" := BankDepositHeader."Document Date"; Rec."Posting Date" := BankDepositHeader."Posting Date"; - Rec."External Document No." := BankDepositHeader."No."; + Rec."Document No." := BankDepositHeader."No."; + Rec."External Document No." := ''; Rec."Reason Code" := BankDepositHeader."Reason Code"; end; diff --git a/Apps/W1/BankDeposits/test/src/BankDepositPostingTests.Codeunit.al b/Apps/W1/BankDeposits/test/src/BankDepositPostingTests.Codeunit.al index c055d285f4..b51a11dfe5 100644 --- a/Apps/W1/BankDeposits/test/src/BankDepositPostingTests.Codeunit.al +++ b/Apps/W1/BankDeposits/test/src/BankDepositPostingTests.Codeunit.al @@ -490,6 +490,62 @@ codeunit 139769 "Bank Deposit Posting Tests" Assert.AreEqual(-Amount, PostedBankDepositHeader."Total Deposit Lines", 'The total amount of the deposit should be the sum of the lines'); end; + [Test] + [HandlerFunctions('GeneralJournalBatchesPageHandler,ConfirmHandler')] + procedure NavigatePageOfAPostedBankDepositShowsRelatedEntries() + var + BankDepositHeader: Record "Bank Deposit Header"; + GLAccount: Record "G/L Account"; + Customer: Record Customer; + GenJournalBatch: Record "Gen. Journal Batch"; + GenJournalTemplate: Record "Gen. Journal Template"; + GenJournalLine: Record "Gen. Journal Line"; + BankAccountLedgerEntry: Record "Bank Account Ledger Entry"; + CustLedgerEntry: Record "Cust. Ledger Entry"; + BankDeposit: TestPage "Bank Deposit"; + PostedBankDeposit: TestPage "Posted Bank Deposit"; + Navigate: TestPage Navigate; + BankEntryFound, CustomerEntryFound : Boolean; + TableName: Text; + begin + // [SCENARIO 537831] Related entries are shown on the Navigate page of a posted bank deposit + Initialize(); + // [GIVEN] A Posted Bank Deposit with a G/L Account and a Customer. + CreateGenJournalBatch(GenJournalBatch, GenJournalTemplate.Type::"Bank Deposits"); + CreateBankDepositHeaderWithBankAccount(BankDepositHeader, GenJournalBatch); + BankDepositHeader."Total Deposit Amount" := 1000; + BankDepositHeader.Modify(); + BankDeposit.Trap(); + BankDepositHeader.SetRecFilter(); + Page.Run(Page::"Bank Deposit", BankDepositHeader); + LibraryERM.CreateGLAccount(GLAccount); + BankDeposit.Subform."Account Type".SetValue(GenJournalLine."Account Type"::"G/L Account"); + BankDeposit.Subform."Account No.".SetValue(GLAccount."No."); + BankDeposit.Subform."Credit Amount".SetValue(-10); + BankDeposit.Subform.Next(); + LibrarySales.CreateCustomer(Customer); + BankDeposit.Subform."Account Type".SetValue(GenJournalLine."Account Type"::Customer); + BankDeposit.Subform."Account No.".SetValue(Customer."No."); + BankDeposit.Subform."Credit Amount".SetValue(1010); + PostedBankDeposit.Trap(); + BankDeposit.Post.Invoke(); + // [WHEN] Navigate action is invoked from the posted bank deposit + Navigate.Trap(); + PostedBankDeposit."&Navigate".Invoke(); + + repeat + TableName := Navigate."Table Name".Value(); + case TableName of + BankAccountLedgerEntry.TableCaption(): + BankEntryFound := true; + CustLedgerEntry.TableCaption(): + CustomerEntryFound := true; + end; + until (not Navigate.Next()); + // [THEN] The entries posted are found. + Assert.IsTrue(BankEntryFound, 'Bank Account Ledger Entry should be found'); + Assert.IsTrue(CustomerEntryFound, 'Customer Ledger Entry should be found'); + end; local procedure Initialize() var diff --git a/Apps/W1/BankDeposits/test/src/UTPageBankDeposit.Codeunit.al b/Apps/W1/BankDeposits/test/src/UTPageBankDeposit.Codeunit.al index 17532253d8..8b8917a15e 100644 --- a/Apps/W1/BankDeposits/test/src/UTPageBankDeposit.Codeunit.al +++ b/Apps/W1/BankDeposits/test/src/UTPageBankDeposit.Codeunit.al @@ -663,11 +663,11 @@ codeunit 139768 "UT Page Bank Deposit" Page.Run(Page::"Bank Deposit", BankDepositHeader); BankDeposit.Subform."Account Type".SetValue(GenJnlLine."Account Type"::Vendor.AsInteger()); BankDeposit.Subform."Account No.".SetValue(LibraryPurchase.CreateVendorNo()); - BankDeposit.Subform."Document No.".SetValue(LibraryUtility.GenerateRandomNumericText(2)); + BankDeposit.Subform."External Document No.".SetValue(LibraryUtility.GenerateRandomNumericText(2)); BankDeposit.Subform."Credit Amount".SetValue(BankDepositHeader."Total Deposit Amount"); // [GIVEN] Get the created General Jnl Line. - GenJnlLine.SetFilter("External Document No.", BankDepositHeader."No."); + GenJnlLine.SetFilter("Document No.", BankDepositHeader."No."); GenJnlLine.FindFirst(); SourceCodeSetup.Get(); @@ -748,6 +748,22 @@ codeunit 139768 "UT Page Bank Deposit" Assert.AreEqual(GenJournalTemplate.Name, BAnkDepositHeader."Journal Template Name", ''); end; + [Test] + procedure DefaultValueOfDocumentNoForDepositLineIsTheBankDepositNo() + var + BankDepositHeader: Record "Bank Deposit Header"; + BankDeposit: TestPage "Bank Deposit"; + begin + // [SCENARIO 537832] Bank Deposit default values for lines should be the bank deposit number for the "Document No." and blank for the "External Document No." + // [GIVEN] A Bank Deposit Header without lines + CreateBankDepositHeader(BankDepositHeader, ''); + // [WHEN] Opening the Bank Deposit page + OpenDepositPage(BankDeposit, BankDepositHeader); + // [THEN] The default values for the lines are as expected. + Assert.AreEqual(BankDepositHeader."No.", BankDeposit.Subform."Document No.".Value(), 'The default value of Document No. for the Deposit Line should be the Bank Deposit No.'); + Assert.AreEqual('', BankDeposit.Subform."External Document No.".Value(), 'The default value of External Document No. for the Deposit Line should be empty.'); + end; + local procedure GetBankDepositsFeature(var FeatureDataUpdateStatus: Record "Feature Data Update Status"; ID: Text[50]) begin if FeatureDataUpdateStatus.Get(ID, CompanyName()) then diff --git a/Apps/W1/CrossEnvironmentIntercompany/app/src/pages/APIBufICInboxPurchaseLine.Page.al b/Apps/W1/CrossEnvironmentIntercompany/app/src/pages/APIBufICInboxPurchaseLine.Page.al index 8f7a68fa38..24b65b7274 100644 --- a/Apps/W1/CrossEnvironmentIntercompany/app/src/pages/APIBufICInboxPurchaseLine.Page.al +++ b/Apps/W1/CrossEnvironmentIntercompany/app/src/pages/APIBufICInboxPurchaseLine.Page.al @@ -82,6 +82,16 @@ page 30419 "API Buf IC Inbox Purchase Line" Caption = 'Amount Including VAT'; Editable = true; } + field(amount; Rec.Amount) + { + Caption = 'Amount'; + Editable = true; + } + field(invoiceDiscountAmount; Rec."Inv. Discount Amount") + { + Caption = 'Inv. Discount Amount'; + Editable = true; + } field(jobNumber; Rec."Job No.") { Caption = 'Job Number'; diff --git a/Apps/W1/CrossEnvironmentIntercompany/app/src/pages/APIBufICInboxSalesLine.Page.al b/Apps/W1/CrossEnvironmentIntercompany/app/src/pages/APIBufICInboxSalesLine.Page.al index f5704a9876..1766a0848e 100644 --- a/Apps/W1/CrossEnvironmentIntercompany/app/src/pages/APIBufICInboxSalesLine.Page.al +++ b/Apps/W1/CrossEnvironmentIntercompany/app/src/pages/APIBufICInboxSalesLine.Page.al @@ -82,6 +82,16 @@ page 30422 "API Buf IC Inbox Sales Line" Caption = 'Amount Including VAT'; Editable = true; } + field(amount; Rec.Amount) + { + Caption = 'Amount'; + Editable = true; + } + field(invoiceDiscountAmount; Rec."Inv. Discount Amount") + { + Caption = 'Inv. Discount Amount'; + Editable = true; + } field(jobNumber; Rec."Job No.") { Caption = 'Job Number'; diff --git a/Apps/W1/EDocument/app/src/Processing/OrderMatching/Copilot/EDocPOCopilotMatching.Codeunit.al b/Apps/W1/EDocument/app/src/Processing/OrderMatching/Copilot/EDocPOCopilotMatching.Codeunit.al index 9da1edc3b1..74b8e660a5 100644 --- a/Apps/W1/EDocument/app/src/Processing/OrderMatching/Copilot/EDocPOCopilotMatching.Codeunit.al +++ b/Apps/W1/EDocument/app/src/Processing/OrderMatching/Copilot/EDocPOCopilotMatching.Codeunit.al @@ -8,7 +8,6 @@ using Microsoft.eServices.EDocument.OrderMatch; using System.Environment; using System.Telemetry; using System.Upgrade; -using System.Globalization; codeunit 6163 "E-Doc. PO Copilot Matching" { @@ -163,9 +162,6 @@ codeunit 6163 "E-Doc. PO Copilot Matching" if not EnvironmentInformation.IsSaaSInfrastructure() then exit(false); - if not IsSupportedLanguage() then - exit(false); - exit(true); end; @@ -205,20 +201,6 @@ codeunit 6163 "E-Doc. PO Copilot Matching" exit(Prompt); end; - local procedure IsSupportedLanguage(): Boolean - var - LanguageSelection: Record "Language Selection"; - UserSessionSettings: SessionSettings; - begin - UserSessionSettings.Init(); - LanguageSelection.SetLoadFields("Language Tag"); - LanguageSelection.SetRange("Language ID", UserSessionSettings.LanguageId()); - if LanguageSelection.FindFirst() then - if LanguageSelection."Language Tag".StartsWith('pt-') then - exit(false); - exit(true); - end; - local procedure GroundCopilotMatching(var TempEDocumentImportedLine: Record "E-Doc. Imported Line" temporary; var TempPurchaseLine: Record "Purchase Line" temporary; var TempAIProposalBuffer: Record "E-Doc. PO Match Prop. Buffer" temporary) var TempEDocMatchesThatWasMatched: Record "E-Doc. Order Match" temporary; diff --git a/Apps/W1/Email - Outlook REST API/app/src/EmailOAuthClient.Codeunit.al b/Apps/W1/Email - Outlook REST API/app/src/EmailOAuthClient.Codeunit.al index 68e5f36796..04c65b622e 100644 --- a/Apps/W1/Email - Outlook REST API/app/src/EmailOAuthClient.Codeunit.al +++ b/Apps/W1/Email - Outlook REST API/app/src/EmailOAuthClient.Codeunit.al @@ -26,9 +26,12 @@ codeunit 4507 "Email - OAuth Client" implements "Email - OAuth Client v2" [NonDebuggable] [Obsolete('Replaced by GetAccessToken with SecretText data type for AccessToken parameter.', '24.0')] procedure GetAccessToken(var AccessToken: Text) + var + CallerModuleInfo: ModuleInfo; begin + NavApp.GetCallerModuleInfo(CallerModuleInfo); #pragma warning disable AL0432 - TryGetAccessTokenInternal(AccessToken); + TryGetAccessTokenInternal(AccessToken, CallerModuleInfo); #pragma warning restore AL0432 end; @@ -36,8 +39,11 @@ codeunit 4507 "Email - OAuth Client" implements "Email - OAuth Client v2" [Obsolete('Replaced by GetAccessToken with SecretText data type for AccessToken parameter.', '24.0')] procedure TryGetAccessToken(var AccessToken: Text): Boolean + var + CallerModuleInfo: ModuleInfo; begin - exit(TryGetAccessTokenInternal(AccessToken)); + NavApp.GetCallerModuleInfo(CallerModuleInfo); + exit(TryGetAccessTokenInternal(AccessToken, CallerModuleInfo)); end; #endif @@ -47,25 +53,46 @@ codeunit 4507 "Email - OAuth Client" implements "Email - OAuth Client v2" /// Out parameter with the Access token of the account [NonDebuggable] procedure GetAccessToken(var AccessToken: SecretText) + var + CallerModuleInfo: ModuleInfo; begin - TryGetAccessTokenInternal(AccessToken); + NavApp.GetCallerModuleInfo(CallerModuleInfo); + TryGetAccessTokenInternal(AccessToken, CallerModuleInfo); end; [NonDebuggable] procedure TryGetAccessToken(var AccessToken: SecretText): Boolean + var + CallerModuleInfo: ModuleInfo; + begin + NavApp.GetCallerModuleInfo(CallerModuleInfo); + exit(TryGetAccessTokenInternal(AccessToken, CallerModuleInfo)); + end; + + local procedure CheckIfThirdParty(CallerModuleInfo: ModuleInfo) + var + EnvironmentInformation: Codeunit "Environment Information"; + CurrentModuleInfo: ModuleInfo; begin - exit(TryGetAccessTokenInternal(AccessToken)); + NavApp.GetCurrentModuleInfo(CurrentModuleInfo); + + if EnvironmentInformation.IsSaaSInfrastructure() <> true then + exit; + + if CallerModuleInfo.Publisher <> CurrentModuleInfo.Publisher then + Error(ThirdPartyExtensionsNotAllowedErr); end; #if not CLEAN24 // Interfaces do not support properties for the procedures, so using an internal function [TryFunction] [NonDebuggable] - local procedure TryGetAccessTokenInternal(var AccessToken: Text) + local procedure TryGetAccessTokenInternal(var AccessToken: Text; CallerModuleInfo: ModuleInfo) var Token: SecretText; begin - TryGetAccessTokenInternal(Token); + CheckIfThirdParty(CallerModuleInfo); + TryGetAccessTokenInternal(Token, CallerModuleInfo); if not Token.IsEmpty() then AccessToken := Token.Unwrap(); end; @@ -74,13 +101,14 @@ codeunit 4507 "Email - OAuth Client" implements "Email - OAuth Client v2" // Interfaces do not support properties for the procedures, so using an internal function [TryFunction] [NonDebuggable] - local procedure TryGetAccessTokenInternal(var AccessToken: SecretText) + local procedure TryGetAccessTokenInternal(var AccessToken: SecretText; CallerModuleInfo: ModuleInfo) var AzureAdMgt: Codeunit "Azure AD Mgt."; UrlHelper: Codeunit "Url Helper"; EnvironmentInformation: Codeunit "Environment Information"; OAuthErr: Text; begin + CheckIfThirdParty(CallerModuleInfo); Initialize(); ClearLastError(); @@ -165,4 +193,5 @@ codeunit 4507 "Email - OAuth Client" implements "Email - OAuth Client v2" CouldNotGetAccessTokenErr: Label 'Could not get access token.'; EmailCategoryLbl: Label 'EmailOAuth', Locked = true; CouldNotAcquireAccessTokenErr: Label 'Failed to acquire access token.', Locked = true; + ThirdPartyExtensionsNotAllowedErr: Label 'Third-party extensions are restricted from obtaining access tokens. Please contact your system administrator.'; } \ No newline at end of file diff --git a/Apps/W1/EnforcedDigitalVouchers/app/src/Extensions/DigVoucherIncDocAttach.TableExt.al b/Apps/W1/EnforcedDigitalVouchers/app/src/Extensions/DigVoucherIncDocAttach.TableExt.al new file mode 100644 index 0000000000..a86976dc86 --- /dev/null +++ b/Apps/W1/EnforcedDigitalVouchers/app/src/Extensions/DigVoucherIncDocAttach.TableExt.al @@ -0,0 +1,16 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.EServices.EDocument; + +tableextension 5582 "Dig. Voucher Inc. Doc. Attach." extends "Incoming Document Attachment" +{ + fields + { + field(5582; "Is Digital Voucher"; Boolean) + { + DataClassification = SystemMetadata; + } + } +} \ No newline at end of file diff --git a/Apps/W1/EnforcedDigitalVouchers/app/src/Implementation/DigitalVoucherImpl.Codeunit.al b/Apps/W1/EnforcedDigitalVouchers/app/src/Implementation/DigitalVoucherImpl.Codeunit.al index 2f096ea286..8c8d1dbaaf 100644 --- a/Apps/W1/EnforcedDigitalVouchers/app/src/Implementation/DigitalVoucherImpl.Codeunit.al +++ b/Apps/W1/EnforcedDigitalVouchers/app/src/Implementation/DigitalVoucherImpl.Codeunit.al @@ -16,6 +16,7 @@ using Microsoft.Sales.Document; using Microsoft.Sales.History; using Microsoft.Sales.Posting; using Microsoft.Sales.Receivables; +using System.Email; using System.Environment.Configuration; using System.Media; using System.Reflection; @@ -70,6 +71,7 @@ codeunit 5579 "Digital Voucher Impl." procedure HandleDigitalVoucherForPostedGLEntry(GLEntry: Record "G/L Entry"; GenJournalLine: Record "Gen. Journal Line"; GenJournalSourceType: Enum "Gen. Journal Source Type") var DigitalVoucherEntrySetup: Record "Digital Voucher Entry Setup"; + ConnectedGenJournalLine: Record "Gen. Journal Line"; RecRef: RecordRef; DigitalVoucherCheck: Interface "Digital Voucher Check"; begin @@ -78,7 +80,8 @@ codeunit 5579 "Digital Voucher Impl." if DigitalVoucherEntrySetup."Check Type" = DigitalVoucherEntrySetup."Check Type"::"No Check" then exit; DigitalVoucherCheck := DigitalVoucherEntrySetup."Check Type"; - RecRef.GetTable(GenJournalLine); + FindGenJournalLineFromGLEntry(ConnectedGenJournalLine, GenJournalLine, GLEntry); + RecRef.GetTable(ConnectedGenJournalLine); DigitalVoucherCheck.GenerateDigitalVoucherForPostedDocument(DigitalVoucherEntrySetup."Entry Type", RecRef); end; @@ -138,11 +141,15 @@ codeunit 5579 "Digital Voucher Impl." IncomingDocumentAttachment.SetRange("Document No.", DocNo); IncomingDocumentAttachment.SetRange("Posting Date", PostingDate); IncomingDocumentAttachment.SetContentFromBlob(TempBlob); - ImportAttachmentIncDoc.ImportAttachment( + if not ImportAttachmentIncDoc.ImportAttachment( IncomingDocumentAttachment, StrSubstNo( DigitalVoucherFileTxt, DocType, - Format(PostingDate, 0, ''), DocNo), TempBlob); + Format(PostingDate, 0, ''), DocNo), TempBlob) + then + exit; + IncomingDocumentAttachment."Is Digital Voucher" := true; + IncomingDocumentAttachment.Modify(); end; procedure CheckDigitalVoucherForDocument(DigitalVoucherEntryType: Enum "Digital Voucher Entry Type"; RecRef: RecordRef): Boolean @@ -199,10 +206,23 @@ codeunit 5579 "Digital Voucher Impl." RecRef.SetTable(GenJournalLine); GenJournalLine.SetRange("Journal Template Name", GenJournalLine."Journal Template Name"); GenJournalLine.SetRange("Journal Batch Name", GenJournalLine."Journal Batch Name"); + GenJournalLine.SetRange("Posting Date", GenJournalLine."Posting Date"); + GenJournalLine.SetRange("Document No.", GenJournalLine."Document No."); ReportSelections.SaveReportAsPDFInTempBlob(TempBlob, Report::"General Journal - Test", GenJournalLine, '', DummyReportUsage); AttachBlobToIncomingDocument(TempBlob, Format(GenJournalLine."Document Type"), GenJournalLine."Posting Date", GenJournalLine."Document No."); end; + local procedure FindGenJournalLineFromGLEntry(var ConnectedGenJnlLine: Record "Gen. Journal Line"; CurrGenJnlLine: Record "Gen. Journal Line"; GLEntry: Record "G/L Entry") + begin + ConnectedGenJnlLine.SetRange("Journal Template Name", CurrGenJnlLine."Journal Template Name"); + ConnectedGenJnlLine.SetRange("Journal Batch Name", CurrGenJnlLine."Journal Batch Name"); + ConnectedGenJnlLine.SetRange("Posting Date", GLEntry."Posting Date"); + ConnectedGenJnlLine.SetRange("Document No.", GLEntry."Document No."); + if ConnectedGenJnlLine.FindFirst() then + exit; + ConnectedGenJnlLine := CurrGenJnlLine; + end; + [EventSubscriber(ObjectType::Codeunit, Codeunit::"Guided Experience", 'OnRegisterAssistedSetup', '', true, true)] local procedure InsertIntoAssistedSetup() var @@ -323,6 +343,7 @@ codeunit 5579 "Digital Voucher Impl." local procedure OnProcessLinesOnAfterPostGenJnlLines(var GenJournalLine: Record "Gen. Journal Line"; GLRegister: Record "G/L Register"; var GLRegNo: Integer; PreviewMode: Boolean) var GLEntry: Record "G/L Entry"; + GLEntryToHandle: Record "G/L Entry"; CurrPostingDateDocNoCode: Text; PostingDateDocNoCode: Text; GenJournalSourceType: Enum "Gen. Journal Source Type"; @@ -340,9 +361,10 @@ codeunit 5579 "Digital Voucher Impl." PostingDateDocNoCode := Format(GLEntry."Posting Date") + GLEntry."Document No."; if PostingDateDocNoCode <> CurrPostingDateDocNoCode then begin if CurrPostingDateDocNoCode <> '' then - HandleDigitalVoucherForPostedGLEntry(GLEntry, GenJournalLine, GenJournalSourceType); + HandleDigitalVoucherForPostedGLEntry(GLEntryToHandle, GenJournalLine, GenJournalSourceType); CurrPostingDateDocNoCode := PostingDateDocNoCode; GenJournalSourceType := GenJournalSourceType::" "; + GLEntryToHandle := GLEntry; end; if GLEntry."Source Type" <> GLEntry."Source Type"::" " then GenJournalSourceType := GLEntry."Source Type"; @@ -395,6 +417,12 @@ codeunit 5579 "Digital Voucher Impl." DigitalVoucherFeature.CheckIfDigitalVoucherSetupChangeIsAllowed(); end; + [EventSubscriber(ObjectType::Table, Database::"Email Item", 'OnAttachIncomingDocumentsOnAfterSetFilter', '', false, false)] + local procedure ExcludeDigitalVouchersOnAttachIncomingDocumentsOnAfterSetFilter(var IncomingDocumentAttachment: Record "Incoming Document Attachment") + begin + IncomingDocumentAttachment.SetRange("Is Digital Voucher", false); + end; + [EventSubscriber(ObjectType::Table, Database::"Digital Voucher Setup", 'OnBeforeDeleteEvent', '', false, false)] local procedure CheckIfChangeIsAllowedOnDeleteDigitalVoucherSetup(var Rec: Record "Digital Voucher Setup"; RunTrigger: Boolean) begin diff --git a/Apps/W1/EnforcedDigitalVouchers/app/src/Implementation/VoucherAttachmentCheck.Codeunit.al b/Apps/W1/EnforcedDigitalVouchers/app/src/Implementation/VoucherAttachmentCheck.Codeunit.al index c8839742d9..7668aa33ac 100644 --- a/Apps/W1/EnforcedDigitalVouchers/app/src/Implementation/VoucherAttachmentCheck.Codeunit.al +++ b/Apps/W1/EnforcedDigitalVouchers/app/src/Implementation/VoucherAttachmentCheck.Codeunit.al @@ -17,7 +17,7 @@ codeunit 5580 "Voucher Attachment Check" implements "Digital Voucher Check" procedure CheckVoucherIsAttachedToDocument(var ErrorMessageMgt: Codeunit "Error Message Management"; DigitalVoucherEntryType: Enum "Digital Voucher Entry Type"; RecRef: RecordRef) begin if not DigitalVoucherImpl.CheckDigitalVoucherForDocument(DigitalVoucherEntryType, RecRef) then - if DigitalVoucherEntryType = DigitalVoucherEntryType::"General Journal" then + if DigitalVoucherEntryType in [DigitalVoucherEntryType::"General Journal", DigitalVoucherEntryType::"Purchase Journal", DigitalVoucherEntryType::"Sales Journal"] then error(NotPossibleToPostWithoutVoucherErr) else ErrorMessageMgt.LogSimpleErrorMessage(NotPossibleToPostWithoutVoucherErr); diff --git a/Apps/W1/EnforcedDigitalVouchers/test/src/DigitalVouchersTests.Codeunit.al b/Apps/W1/EnforcedDigitalVouchers/test/src/DigitalVouchersTests.Codeunit.al index ed3495fccb..a3d1f90f3e 100644 --- a/Apps/W1/EnforcedDigitalVouchers/test/src/DigitalVouchersTests.Codeunit.al +++ b/Apps/W1/EnforcedDigitalVouchers/test/src/DigitalVouchersTests.Codeunit.al @@ -8,15 +8,22 @@ codeunit 139515 "Digital Vouchers Tests" LibraryTestInitialize: Codeunit "Library - Test Initialize"; LibraryPurchase: Codeunit "Library - Purchase"; LibraryERM: Codeunit "Library - ERM"; + LibraryJournals: Codeunit "Library - Journals"; LibraryUtility: Codeunit "Library - Utility"; LibraryVariableStorage: Codeunit "Library - Variable Storage"; + LibraryInventory: Codeunit "Library - Inventory"; + LibrarySales: Codeunit "Library - Sales"; + LibraryRandom: Codeunit "Library - Random"; Assert: Codeunit Assert; + LibraryWorkflow: Codeunit "Library - Workflow"; + ActiveDirectoryMockEvents: Codeunit "Active Directory Mock Events"; IsInitialized: Boolean; NotPossibleToPostWithoutVoucherErr: Label 'Not possible to post without attaching the digital voucher.'; DialogErrorCodeTok: Label 'Dialog', Locked = true; CannotRemoveReferenceRecordFromIncDocErr: Label 'Cannot remove the reference record from the incoming document because it is used for the enforced digital voucher functionality'; DetachQst: Label 'Do you want to remove the reference from this incoming document to posted document'; RemovePostedRecordManuallyMsg: Label 'The reference to the posted record has been removed.\\Remember to correct the posted record if needed.'; + DoYouWantToPostQst: Label 'Do you want to post the journal lines?'; trigger OnRun() begin @@ -242,6 +249,185 @@ codeunit 139515 "Digital Vouchers Tests" Assert.ExpectedError(CannotRemoveReferenceRecordFromIncDocErr); end; + [Test] + [HandlerFunctions('ConfirmHandler,ErrorMessagePageHandler')] + procedure PostGeneralJournalLineWithRequiredAttachmentAndNoDigitalVoucher() + var + GenJournalLine: Record "Gen. Journal Line"; + DigVouchersDisableEnforce: Codeunit "Dig. Vouchers Disable Enforce"; + BatchProcessingMgt: Codeunit "Batch Processing Mgt."; + begin + // [SCENARIO 537136] Stan cannot post a general journal line with required attachment and no digital voucher + + Initialize(); + BindSubscription(DigVouchersDisableEnforce); + // [GIVEN] Digital voucher entry setup for general journal is "Attachment" + InitSetupCheckOnly("Digital Voucher Entry Type"::"General Journal", "Digital Voucher Check Type"::Attachment); + // [GIVEN] General journal line is created + LibraryJournals.CreateGenJournalLineWithBatch( + GenJournalLine, GenJournalLine."Document Type"::" ", GenJournalLine."Account Type"::"G/L Account", + LibraryERm.CreateGLAccountNo(), LibraryRandom.RandDec(100, 2)); + LibraryVariableStorage.Enqueue(DoYouWantToPostQst); + LibraryVariableStorage.Enqueue(true); + LibraryVariableStorage.Enqueue(NotPossibleToPostWithoutVoucherErr); + // [WHEN] Post general journal + asserterror BatchProcessingMgt.BatchProcessGenJournalLine(GenJournalLine, Codeunit::"Gen. Jnl.-Post"); + + // [THEN] Error "Not possible to post without the voucher" is shown in the error message page + // Verified in the ErrorMessagePageHandler + + LibraryVariableStorage.AssertEmpty(); + UnbindSubscription(DigVouchersDisableEnforce); + end; + + [Test] + [HandlerFunctions('ConfirmHandler,ErrorMessagePageHandler')] + procedure PostSalesJournalLineWithRequiredAttachmentAndNoDigitalVoucher() + var + GenJournalLine: Record "Gen. Journal Line"; + DigVouchersDisableEnforce: Codeunit "Dig. Vouchers Disable Enforce"; + BatchProcessingMgt: Codeunit "Batch Processing Mgt."; + begin + // [SCENARIO 537136] Stan cannot post a sales journal line with required attachment and no digital voucher + + Initialize(); + BindSubscription(DigVouchersDisableEnforce); + // [GIVEN] Digital voucher entry setup for sales journal is "Attachment" + InitSetupCheckOnly("Digital Voucher Entry Type"::"Sales Journal", "Digital Voucher Check Type"::Attachment); + // [GIVEN] Sales journal line is created + LibraryJournals.CreateGenJournalLineWithBatch( + GenJournalLine, GenJournalLine."Document Type"::Invoice, GenJournalLine."Account Type"::Customer, + LibrarySales.CreateCustomerNo(), LibraryRandom.RandDec(100, 2)); + LibraryVariableStorage.Enqueue(DoYouWantToPostQst); + LibraryVariableStorage.Enqueue(true); + LibraryVariableStorage.Enqueue(NotPossibleToPostWithoutVoucherErr); + // [WHEN] Post sales journal + asserterror BatchProcessingMgt.BatchProcessGenJournalLine(GenJournalLine, Codeunit::"Gen. Jnl.-Post"); + + // [THEN] Error "Not possible to post without the voucher" is shown in the error message page + // Verified in the ErrorMessagePageHandler + + LibraryVariableStorage.AssertEmpty(); + UnbindSubscription(DigVouchersDisableEnforce); + end; + + [Test] + [HandlerFunctions('ConfirmHandler,ErrorMessagePageHandler')] + procedure PostPurchaseJournalLineWithRequiredAttachmentAndNoDigitalVoucher() + var + GenJournalLine: Record "Gen. Journal Line"; + DigVouchersDisableEnforce: Codeunit "Dig. Vouchers Disable Enforce"; + BatchProcessingMgt: Codeunit "Batch Processing Mgt."; + begin + // [SCENARIO 537136] Stan cannot post a purchase journal line with required attachment and no digital voucher + + Initialize(); + BindSubscription(DigVouchersDisableEnforce); + // [GIVEN] Digital voucher entry setup for purchase journal is "Attachment" + InitSetupCheckOnly("Digital Voucher Entry Type"::"Purchase Journal", "Digital Voucher Check Type"::Attachment); + // [GIVEN] Purchase journal line is created + LibraryJournals.CreateGenJournalLineWithBatch( + GenJournalLine, GenJournalLine."Document Type"::Invoice, GenJournalLine."Account Type"::Vendor, + LibraryPurchase.CreateVendorNo(), LibraryRandom.RandDec(100, 2)); + LibraryVariableStorage.Enqueue(DoYouWantToPostQst); + LibraryVariableStorage.Enqueue(true); + LibraryVariableStorage.Enqueue(NotPossibleToPostWithoutVoucherErr); + // [WHEN] Post purchase journal + asserterror BatchProcessingMgt.BatchProcessGenJournalLine(GenJournalLine, Codeunit::"Gen. Jnl.-Post"); + + // [THEN] Error "Not possible to post without the voucher" is shown in the error message page + // Verified in the ErrorMessagePageHandler + + LibraryVariableStorage.AssertEmpty(); + UnbindSubscription(DigVouchersDisableEnforce); + end; + + [Test] + [HandlerFunctions('StrMenuHandler,VerifyNoAttachmentsInEmailEditorModalPageHandler')] + procedure PostSalesDocAndSendEmailWithDigitalVoucherAutomaticallyGenerated() + var + SalesHeader: Record "Sales Header"; + SalesLine: Record "Sales Line"; + DigVouchersDisableEnforce: Codeunit "Dig. Vouchers Disable Enforce"; + begin + // [SCENARIO 537262] The automatically generated digital voucher is not suggested as an attachment during emailing + + BindSubscription(DigVouchersDisableEnforce); + // [GIVEN] Email account is set up + LibraryWorkflow.SetUpEmailAccount(); + BindActiveDirectoryMockEvents(); + // [GIVEN] Sales shipment report selections without attachment + PrepareSalesShipmentReportSelectionsForEmailBodyWithoutAttachment(); + // [GIVEN] Digital voucher feature is enabled + EnableDigitalVoucherFeature(); + // [GIVEN] Digital voucher entry setup for sales document is "Attachment" and "Generate Automatically" option is enabled + InitSetupGenerateAutomatically("Digital Voucher Entry Type"::"Sales Document", "Digital Voucher Check Type"::Attachment); + + // [GIVEN] Sales Order + LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Order, ''); + LibrarySales.CreateSalesLineWithUnitPrice( + SalesLine, SalesHeader, LibraryInventory.CreateItemNo(), + LibraryRandom.RandDec(100, 2), LibraryRandom.RandInt(100)); + + // [GIVEN] Custom report selection for the customer for email body + CreateCustomReportSelectionForCustomer(SalesHeader."Sell-to Customer No.", "Report Selection Usage"::"S.Shipment", Report::"Sales - Shipment"); + + LibraryVariableStorage.Enqueue(1); // option for posting only shipment + LibraryVariableStorage.Enqueue(3); // option for emailing to discard and not send any email + // [WHEN] Post sales order and send email + LibrarySales.PostSalesDocumentAndEmail(SalesHeader, true, true); + + // [THEN] No attachments are suggested in the E-mail editor + // Verified in the VerifyNoAttachmentsInEmailEditorModalPageHandler + + UnbindSubscription(DigVouchersDisableEnforce); + end; + + [Test] + procedure PostMultipleGeneralJournalLinesWithGenerateAutomaticallyOption() + var + GenJournalLine: array[2] of Record "Gen. Journal Line"; + GenJournalLineToPost: Record "Gen. Journal Line"; + GenJournalTemplate: Record "Gen. Journal Template"; + GenJournalBatch: Record "Gen. Journal Batch"; + IncomingDocument: Record "Incoming Document"; + DigVouchersEnableEnforce: Codeunit "Dig. Vouchers Enable Enforce"; + i: Integer; + begin + // [SCENARIO 537486] Stan can post multiple general journals lines with different documents and digital voucher set to by automatically generated + + Initialize(); + BindSubscription(DigVouchersEnableEnforce); + // [GIVEN] Digital voucher entry setup for general journal is "Attachment" and "Generate Automatically" option is enabled + InitSetupGenerateAutomatically("Digital Voucher Entry Type"::"General Journal", "Digital Voucher Check Type"::Attachment); + // [GIVEN] General journal lines with the same template and batch are created + // [GIVEN] General journal line "X" with "Posting Date" = 01.01.2024 and "Document No." = "X" + // [GIVEN] General journal line "Y" with "Posting Date" = 01.01.2024 and "Document No." = "Y" + LibraryERM.CreateGenJournalTemplate(GenJournalTemplate); + GenJournalTemplate.Validate("Force Doc. Balance", false); + GenJournalTemplate.Modify(true); + LibraryERM.CreateGenJournalBatch(GenJournalBatch, GenJournalTemplate.Name); + for i := 1 to ArrayLen(GenJournalLine) do + LibraryJournals.CreateGenJournalLine( + GenJournalLine[i], GenJournalTemplate.Name, GenJournalBatch.Name, + GenJournalLine[i]."Document Type"::" ", GenJournalLine[i]."Account Type"::"G/L Account", + LibraryERM.CreateGLAccountNo(), GenJournalLine[i]."Bal. Account Type"::"G/L Account", + LibraryERM.CreateGLAccountNo(), LibraryRandom.RandDec(100, 2)); + GenJournalLineToPost.SetRange("Journal Template Name", GenJournalTemplate.Name); + GenJournalLineToPost.SetRange("Journal Batch Name", GenJournalBatch.Name); + GenJournalLineToPost.FindSet(); + // [WHEN] Post both general journal lines + Codeunit.Run(Codeunit::"Gen. Jnl.-Post Batch", GenJournalLineToPost); + + // [THEN] Two digital vouchers generated for each combination of "Document No." and "Posting Date" + for i := 1 to ArrayLen(GenJournalLine) do + Assert.IsTrue( + IncomingDocument.FindByDocumentNoAndPostingDate( + IncomingDocument, GenJournalLine[i]."Document No.", Format(GenJournalLine[i]."Posting Date")), + 'Digital voucher has not been generated'); + UnbindSubscription(DigVouchersEnableEnforce); + end; + local procedure Initialize() begin LibraryTestInitialize.OnTestInitialize(Codeunit::"Digital Vouchers Tests"); @@ -364,6 +550,41 @@ codeunit 139515 "Digital Vouchers Tests" LibraryERM.FindVendorLedgerEntry(VendorLedgerEntry, VendorLedgerEntry."Document Type"::Invoice, DocNo); end; + local procedure PrepareSalesShipmentReportSelectionsForEmailBodyWithoutAttachment() + var + ReportSelections: Record "Report Selections"; + begin + ReportSelections.SetRange(Usage, ReportSelections.Usage::"S.Shipment"); + ReportSelections.ModifyAll("Use for Email Body", false); + ReportSelections.ModifyAll("Use for Email Attachment", false); + end; + + local procedure CreateCustomReportSelectionForCustomer(CustomerNo: Code[20]; ReportSelectionUsage: Enum "Report Selection Usage"; ReportID: Integer) + var + CustomReportSelection: Record "Custom Report Selection"; + CustomReportLayout: Record "Custom Report Layout"; + begin + CustomReportSelection.Init(); + CustomReportSelection.Validate("Source Type", Database::Customer); + CustomReportSelection.Validate("Source No.", CustomerNo); + CustomReportSelection.Validate(Usage, ReportSelectionUsage); + CustomReportSelection.Validate(Sequence, 1); + CustomReportSelection.Validate("Report ID", ReportID); + CustomReportSelection.Validate("Use for Email Body", true); + CustomReportSelection.Validate("Use for Email Attachment", false); + CustomReportSelection.Validate( + "Email Body Layout Code", CustomReportLayout.InitBuiltInLayout(CustomReportSelection."Report ID", CustomReportLayout.Type::Word.AsInteger())); + CustomReportSelection.Insert(true); + end; + + local procedure BindActiveDirectoryMockEvents() + begin + if ActiveDirectoryMockEvents.Enabled() then + exit; + BindSubscription(ActiveDirectoryMockEvents); + ActiveDirectoryMockEvents.Enable(); + end; + local procedure VerifyIncomingDocumentWithAttachmentsExists(PostingDate: Date; DocNo: Code[20]; AttachmentsCount: Integer) var IncomingDocument: Record "Incoming Document"; @@ -389,4 +610,24 @@ codeunit 139515 "Digital Vouchers Tests" begin Assert.ExpectedMessage(LibraryVariableStorage.DequeueText(), Message); end; + + [PageHandler] + procedure ErrorMessagePageHandler(var ErrorMessagesPage: TestPage "Error Messages") + begin + Assert.AreEqual(LibraryVariableStorage.DequeueText(), ErrorMessagesPage.Description, 'Error message description is not correct'); + end; + + [StrMenuHandler] + [Scope('OnPrem')] + procedure StrMenuHandler(Options: Text[1024]; var Choice: Integer; Instruction: Text[1024]) + begin + Choice := LibraryVariableStorage.DequeueInteger(); + end; + + [ModalPageHandler] + [Scope('OnPrem')] + procedure VerifyNoAttachmentsInEmailEditorModalPageHandler(var TestEmailEditor: TestPage "Email Editor") + begin + TestEmailEditor.Attachments.FileName.AssertEquals(''); + end; } \ No newline at end of file diff --git a/Apps/W1/ExcelReports/app/ReportLayouts/Excel/FixedAsset/FixedAssetAnalysisExcel.xlsx b/Apps/W1/ExcelReports/app/ReportLayouts/Excel/FixedAsset/FixedAssetAnalysisExcel.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..9ea27a44d011c51e0b3af123d0de8f86d9c45f57 GIT binary patch literal 58858 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 literal 0 HcmV?d00001 diff --git a/Apps/W1/ExcelReports/app/ReportLayouts/Excel/GeneralLedger/ConsolidatedTrialBalanceExcel.xlsx b/Apps/W1/ExcelReports/app/ReportLayouts/Excel/GeneralLedger/ConsolidatedTrialBalanceExcel.xlsx index 5832cc4c9480cf0bf56ba082cbc75ec57bf1503e..06f02c1c86cfc7aa3e761567884f26a1d89502f5 100644 GIT binary patch delta 33835 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', EndingDate); + if DepreciationBook.FindFirst() then + DepreciationBookCode := DepreciationBook.Code; + end; + } + rendering + { + layout(FixedAssetAnalysisExcel) + { + Type = Excel; + LayoutFile = './ReportLayouts/Excel/FixedAsset/FixedAssetAnalysisExcel.xlsx'; + Caption = 'Fixed Asset Analysis Excel'; + Summary = 'Built in layout for Fixed Asset Analysis.'; + } + } + labels + { + DataRetrieved = 'Data retrieved:'; + FixedAssetAnalysis = 'Fixed Asset Analysis'; + BeforeStartingDateLabel = 'Before Starting Date'; + AtEndingDateLabel = 'At Ending Date'; + NetChangeLabel = 'Net Change'; + DepreciationBook = 'Depreciation Book'; + Period = 'Period:'; + BookValue = 'Book Value'; + AcquisitionDateLabel = 'Acquisition Date'; + DisposalDateLabel = 'Disposal Date'; + BookValueAnalysis = 'Book Value Analysis'; + AcquisitionCostAfter = 'Acquisition Cost After'; + AcquisitionCostBefore = 'Acquisition Cost Before'; + AcquisitionCostNetChange = 'Addition in Period'; + ProceedsOnDisposalNetChange = 'Disposal in Period'; + DepreciationNetChange = 'Depreciation in Period'; + DepreciationAfter = 'Depreciation After'; + DepreciationBefore = 'Depreciation Before'; + BookValueAfter = 'Book Value After'; + BookValueBefore = 'Book Value Before'; + } + + trigger OnPreReport() + var + DepreciationBook: Record "Depreciation Book"; + begin + DepreciationBook.Get(DepreciationBookCode); + if (StartingDate = 0D) or (EndingDate = 0D) then + Error(SpecifyStartingAndEndingDatesErr); + if StartingDate > EndingDate then + Error(SpecifyStartingAndEndingDatesErr); + end; + + var + DepreciationBookCode: Code[10]; + StartingDate, EndingDate, AcquisitionDate, DisposalDate : Date; + BeforeStartingDate, AtEndingDate, NetChange : Decimal; + Period: Option "Before Starting Date","Net Change","At Ending Date"; + SalesReport, BudgetReport, IncludeInactive : Boolean; + SpecifyStartingAndEndingDatesErr: Label 'Please specify valid starting and ending dates.'; + + local procedure ShouldSkipRecord(): Boolean + var + FADepreciationBook: Record "FA Depreciation Book"; + begin + if not FADepreciationBook.Get(FixedAssetData."No.", DepreciationBookCode) then + exit(true); + if FixedAssetData.Inactive and (not IncludeInactive) then + exit(true); + if FADepreciationBook."Acquisition Date" = 0D then + exit(true); + if FADepreciationBook."Acquisition Date" > EndingDate then + exit(true); + if SalesReport and ((FADepreciationBook."Disposal Date" > EndingDate) or (FADepreciationBook."Disposal Date" < StartingDate)) then + exit(true); + if (not SalesReport) and (FADepreciationBook."Disposal Date" > 0D) and (FADepreciationBook."Disposal Date" < StartingDate) then + exit(true); + exit(false); + end; + + local procedure GetFixedAssetPostedAmount(BeforeAmount: Decimal; EndingAmount: Decimal): Decimal + var + FADepreciationBook: Record "FA Depreciation Book"; + FAGeneralReport: Codeunit "FA General Report"; + begin + if FAPostingType."FA Posting Type No." = FADepreciationBook.FieldNo("Proceeds on Disposal") then + exit(0); + FADepreciationBook.Get(FixedAssetData."No.", DepreciationBookCode); + if not SalesReport and (Period = Period::"at Ending Date") and SoldBeforeEndingDate(FADepreciationBook."Disposal Date") then + exit(0); + exit(FAGeneralReport.CalcFAPostedAmount(FixedAssetData."No.", FAPostingType."FA Posting Type No.", Period, StartingDate, EndingDate, DepreciationBookCode, BeforeAmount, EndingAmount, false, false)); + end; + + local procedure SoldBeforeEndingDate(DisposalDate: Date): Boolean + begin + if DisposalDate = 0D then + exit(false); + exit(DisposalDate <= EndingDate); + end; + +} \ No newline at end of file diff --git a/Apps/W1/ExcelReports/app/src/Financials/EXRFixedAssetDetailsExcel.Report.al b/Apps/W1/ExcelReports/app/src/Financials/EXRFixedAssetDetailsExcel.Report.al index c5d06e1e08..71906ed7d8 100644 --- a/Apps/W1/ExcelReports/app/src/Financials/EXRFixedAssetDetailsExcel.Report.al +++ b/Apps/W1/ExcelReports/app/src/Financials/EXRFixedAssetDetailsExcel.Report.al @@ -26,6 +26,7 @@ report 4411 "EXR Fixed Asset Details Excel" column(AssetDescription; Description) { IncludeCaption = true; } column(FixedAssetClassCode; "FA Class Code") { IncludeCaption = true; } column(FixedAssetSubclassCode; "FA Subclass Code") { IncludeCaption = true; } + column(FixedAssetLocation; "FA Location Code") { IncludeCaption = true; } column(BudgetedAsset; "Budgeted Asset") { IncludeCaption = true; } dataitem(FixedAssetLedgerEntry; "FA Ledger Entry") { diff --git a/Apps/W1/ExcelReports/app/src/Financials/EXRFixedAssetProjected.Report.al b/Apps/W1/ExcelReports/app/src/Financials/EXRFixedAssetProjected.Report.al new file mode 100644 index 0000000000..4d156fec0a --- /dev/null +++ b/Apps/W1/ExcelReports/app/src/Financials/EXRFixedAssetProjected.Report.al @@ -0,0 +1,282 @@ +namespace Microsoft.Finance.ExcelReports; + +using Microsoft.FixedAssets.FixedAsset; +using Microsoft.FixedAssets.Depreciation; +using Microsoft.Foundation.Period; +using Microsoft.FixedAssets.Ledger; + +report 4413 "EXR Fixed Asset Projected" +{ + ApplicationArea = All; + Caption = 'Fixed Asset Projected Value Excel (Preview)'; + DataAccessIntent = ReadOnly; + DefaultRenderingLayout = FixedAssetProjectedValueExcel; + ExcelLayoutMultipleDataSheets = true; + PreviewMode = PrintLayout; + UsageCategory = ReportsAndAnalysis; + MaximumDatasetSize = 1000000; + dataset + { + dataitem(FixedAssetData; "Fixed Asset") + { + DataItemTableView = sorting("No."); + PrintOnlyIfDetail = true; + column(AssetNumber; "No.") { IncludeCaption = true; } + column(AssetDescription; Description) { IncludeCaption = true; } + column(FixedAssetClassCode; "FA Class Code") { IncludeCaption = true; } + column(FixedAssetSubclassCode; "FA Subclass Code") { IncludeCaption = true; } + column(FixedAssetLocationCode; "FA Location Code") { IncludeCaption = true; } + dataitem(FixedAssetLedgerEntries; "FA Ledger Entry") + { + DataItemLink = "FA No." = field("No."); + UseTemporary = true; + column(FixedAssetPostingDate; "FA Posting Date") { IncludeCaption = true; } + column(FixedAssetPostingType; "FA Posting Type") { IncludeCaption = true; } + column(Amount; Amount) { IncludeCaption = true; } + column(BookValue; BookValue) { } + column(ProjectedEntry; ProjectedEntry) { } + column(NumberOfDepreciationDays; "No. of Depreciation Days") { IncludeCaption = true; } + + trigger OnAfterGetRecord() + var + FADepreciationBook: Record "FA Depreciation Book"; + begin + ProjectedEntry := FixedAssetLedgerEntries."Reason Code" = ProjectionTok; + + if FirstFixedAssetLedgerEntry then begin + FADepreciationBook.SetFilter("FA Posting Date Filter", '<%1', FixedAssetLedgerEntries."FA Posting Date"); + FADepreciationBook.SetAutoCalcFields("Book Value"); + FADepreciationBook.Get(FixedAssetData."No.", SelectedDepreciationBookCode); + BookValue := FADepreciationBook."Book Value"; + end; + FirstFixedAssetLedgerEntry := false; + BookValue += FixedAssetLedgerEntries.Amount; + end; + } + trigger OnAfterGetRecord() + begin + if FixedAssetData.Inactive or FixedAssetData.Blocked then + CurrReport.Skip(); + InsertPostedAndProjectedEntries(FixedAssetData."No.", FixedAssetLedgerEntries); + FirstFixedAssetLedgerEntry := true; + end; + } + } + requestpage + { + SaveValues = true; + AboutTitle = 'Fixed Asset Projected Value Excel'; + AboutText = 'This report shows how Fixed Asset Ledger entries would look if depreciated in the given dates.'; + layout + { + area(Content) + { + group(Options) + { + Caption = 'Options'; + field(DepreciationBookCodeField; SelectedDepreciationBookCode) + { + ApplicationArea = All; + Caption = 'Depreciation Book'; + TableRelation = "Depreciation Book"; + ToolTip = 'Specifies the code for the depreciation book to be included in the report or batch job.'; + ShowMandatory = true; + } + field(FirstDepreciationDateField; FirstDepreciationDate) + { + ApplicationArea = All; + Caption = 'First Depreciation Date'; + ToolTip = 'Specifies the date to be used as the first date in the period for which you want to calculate projected depreciation.'; + ShowMandatory = true; + } + field(SecondDepreciationDateField; SecondDepreciationDate) + { + ApplicationArea = All; + Caption = 'Second Depreciation Date'; + ToolTip = 'Specifies the Fixed Asset posting date of the last posted depreciation.'; + ShowMandatory = true; + } + field(PeriodLengthField; PeriodLength) + { + ApplicationArea = FixedAssets; + BlankZero = true; + Caption = 'Number of Days'; + MinValue = 0; + ToolTip = 'Specifies the length of the periods between the first depreciation date and the last depreciation date. The program then calculates depreciation for each period. If you leave this field blank, the program automatically sets the contents of this field to equal the number of days in a fiscal year, normally 360.'; + + trigger OnValidate() + begin + if PeriodLength > 0 then + UseAccountingPeriod := false; + end; + } + field(DaysInFirstPeriodField; DaysInFirstPeriod) + { + ApplicationArea = All; + BlankZero = true; + Caption = 'No. of Days in First Period'; + MinValue = 0; + ToolTip = 'Specifies the number of days that must be used for calculating the depreciation as of the first depreciation date, regardless of the actual number of days from the last depreciation entry. The number you enter in this field does not affect the total number of days from the starting date to the ending date.'; + } + field(IncludePostedFromField; IncludePostedFrom) + { + ApplicationArea = All; + Caption = 'Posted Entries From'; + ToolTip = 'Specifies the fixed asset posting date from which the report includes all types of posted entries.'; + } + field(ProjectedDisposalField; ProjectedDisposal) + { + ApplicationArea = All; + Caption = 'Projected Disposal'; + ToolTip = 'Specifies if you want the report to include projected disposals: the contents of the Projected Proceeds on Disposal field and the Projected Disposal Date field on the FA depreciation book.'; + } + field(UseAccountingPeriodField; UseAccountingPeriod) + { + ApplicationArea = FixedAssets; + Caption = 'Use Accounting Period'; + ToolTip = 'Specifies if you want the periods between the starting date and the ending date to correspond to the accounting periods you have specified in the Accounting Period table. When you select this field, the Number of Days field is cleared.'; + } + } + } + } + } + rendering + { + layout(FixedAssetProjectedValueExcel) + { + Type = Excel; + LayoutFile = './ReportLayouts/Excel/FixedAsset/FixedAssetProjectedValueExcel.xlsx'; + Caption = 'Fixed Asset Projected Value Excel'; + Summary = 'Built in layout for Fixed Asset Projected Value.'; + } + } + labels + { + DataRetrieved = 'Data retrieved:'; + FixedAssetProjectedValue = 'Fixed Asset Projected Value'; + ProjectedValue = 'Projected Value'; + BookValueCaption = 'Book Value'; + ProjectedEntryCaption = 'Projected entry'; + } + + local procedure InsertPostedAndProjectedEntries(FixedAssetNo: Code[20]; var TempFixedAssetLedgerEntry: Record "FA Ledger Entry" temporary) + var + TempProjectedDepreciationDates: Record "Accounting Period" temporary; + begin + TempFixedAssetLedgerEntry.DeleteAll(); + InsertPostedEntries(FixedAssetNo, IncludePostedFrom, SelectedDepreciationBookCode, TempFixedAssetLedgerEntry); + TempProjectedDepreciationDates."Starting Date" := FirstDepreciationDate; + TempProjectedDepreciationDates.Insert(); + + if UseAccountingPeriod then + InsertDatesForAccountingPeriods(TempProjectedDepreciationDates, FirstDepreciationDate, SecondDepreciationDate); + + TempProjectedDepreciationDates."Starting Date" := SecondDepreciationDate; + TempProjectedDepreciationDates.Insert(); + + InsertProjectedEntries(FixedAssetNo, SelectedDepreciationBookCode, TempProjectedDepreciationDates, TempFixedAssetLedgerEntry); + end; + + local procedure InsertProjectedEntries(FixedAssetNo: Code[20]; DepreciationBookCode: Code[10]; var TempProjectedDepreciationDates: Record "Accounting Period" temporary; var TempFixedAssetLedgerEntry: Record "FA Ledger Entry" temporary) + var + DepreciationBook: Record "Depreciation Book"; + FADepreciationBook: Record "FA Depreciation Book"; + CalculateDepreciation: Codeunit "Calculate Depreciation"; + DepreciationCalculation: Codeunit "Depreciation Calculation"; + DateFromProjection: Date; + DepreciationAmount, Custom1Amount : Decimal; + NumberOfDays, Custom1NumberOfDays, DaysInPeriod : Integer; + EntryAmounts: array[4] of Decimal; + First: Boolean; + begin + if TempProjectedDepreciationDates.IsEmpty() then + exit; + + FADepreciationBook.SetAutoCalcFields("Book Value", "Custom 1"); + FADepreciationBook.Get(FixedAssetNo, DepreciationBookCode); + DepreciationBook.Get(DepreciationBookCode); + EntryAmounts[1] := FADepreciationBook."Book Value"; + EntryAmounts[2] := FADepreciationBook."Custom 1"; + EntryAmounts[3] := DepreciationCalculation.DeprInFiscalYear(FixedAssetNo, DepreciationBookCode, FirstDepreciationDate); + DateFromProjection := 0D; + First := true; + TempProjectedDepreciationDates.FindSet(); + repeat + CalculateDepreciation.Calculate(DepreciationAmount, Custom1Amount, NumberOfDays, Custom1NumberOfDays, FixedAssetNo, DepreciationBookCode, TempProjectedDepreciationDates."Starting Date", EntryAmounts, DateFromProjection, DaysInPeriod); + DateFromProjection := DepreciationCalculation.ToMorrow(TempProjectedDepreciationDates."Starting Date", DepreciationBook."Fiscal Year 365 Days"); + EntryAmounts[1] += DepreciationAmount + Custom1Amount; + EntryAmounts[2] += Custom1Amount; + EntryAmounts[3] += DepreciationAmount + Custom1Amount; + if First then begin + EntryAmounts[3] := DepreciationCalculation.DeprInFiscalYear(FixedAssetNo, DepreciationBookCode, TempProjectedDepreciationDates."Starting Date"); + First := false; + end; + TempFixedAssetLedgerEntry."FA No." := FixedAssetNo; + TempFixedAssetLedgerEntry."FA Posting Date" := TempProjectedDepreciationDates."Starting Date"; + TempFixedAssetLedgerEntry."FA Posting Type" := TempFixedAssetLedgerEntry."FA Posting Type"::Depreciation; + TempFixedAssetLedgerEntry.Amount := DepreciationAmount; + TempFixedAssetLedgerEntry."No. of Depreciation Days" := NumberOfDays; + TempFixedAssetLedgerEntry."Entry No." += 1; + TempFixedAssetLedgerEntry."Reason Code" := ProjectionTok; + TempFixedAssetLedgerEntry.Insert(); + until TempProjectedDepreciationDates.Next() = 0; + end; + + local procedure InsertDatesForAccountingPeriods(var TempProjectedDepreciationDates: Record "Accounting Period" temporary; FromDate: Date; ToDate: Date) + var + AccountingPeriod: Record "Accounting Period"; + begin + AccountingPeriod.SetRange("Starting Date", FromDate + 2, ToDate); + if AccountingPeriod.IsEmpty() then + exit; + AccountingPeriod.FindSet(); + repeat + TempProjectedDepreciationDates."Starting Date" := AccountingPeriod."Starting Date" - 1; + TempProjectedDepreciationDates.Insert(); + until AccountingPeriod.Next() = 0; + end; + + local procedure InsertPostedEntries(FixedAssetNo: Code[20]; MinFAPostingDate: Date; FixedAssetDepreciationBookCode: Code[10]; var TempFixedAssetLedgerEntry: Record "FA Ledger Entry" temporary) + var + FixedAssetLedgerEntry: Record "FA Ledger Entry"; + begin + if MinFAPostingDate = 0D then + exit; + FixedAssetLedgerEntry.SetRange("FA No.", FixedAssetNo); + FixedAssetLedgerEntry.SetRange("Depreciation Book Code", FixedAssetDepreciationBookCode); + FixedAssetLedgerEntry.SetFilter("FA Posting Date", '>=%1', MinFAPostingDate); + if FixedAssetLedgerEntry.IsEmpty() then + exit; + FixedAssetLedgerEntry.FindSet(); + repeat + TempFixedAssetLedgerEntry.Copy(FixedAssetLedgerEntry); + Clear(TempFixedAssetLedgerEntry."Reason Code"); + TempFixedAssetLedgerEntry.Insert(); + until FixedAssetLedgerEntry.Next() = 0; + end; + + trigger OnPreReport() + var + DepreciationBook: Record "Depreciation Book"; + begin + DepreciationBook.Get(SelectedDepreciationBookCode); + if (FirstDepreciationDate = 0D) or (SecondDepreciationDate = 0D) then + Error(SpecifyStartingAndEndingDatesErr); + if FirstDepreciationDate > SecondDepreciationDate then + Error(SpecifyStartingAndEndingDatesErr); + end; + + var + ProjectionTok: Label 'PROJECTED', Locked = true; + SelectedDepreciationBookCode: Code[10]; + FirstDepreciationDate, SecondDepreciationDate : Date; + BookValue: Decimal; + PeriodLength: Integer; + DaysInFirstPeriod: Integer; + IncludePostedFrom: Date; + ProjectedDisposal: Boolean; + UseAccountingPeriod: Boolean; + ProjectedEntry: Boolean; + FirstFixedAssetLedgerEntry: Boolean; + SpecifyStartingAndEndingDatesErr: Label 'Please specify valid starting and ending dates.'; +} \ No newline at end of file diff --git a/Apps/W1/HybridGP/app/src/Migration/Items/GPItemMigrator.codeunit.al b/Apps/W1/HybridGP/app/src/Migration/Items/GPItemMigrator.codeunit.al index 5d7a1ab3d1..bfe9697d56 100644 --- a/Apps/W1/HybridGP/app/src/Migration/Items/GPItemMigrator.codeunit.al +++ b/Apps/W1/HybridGP/app/src/Migration/Items/GPItemMigrator.codeunit.al @@ -346,15 +346,20 @@ codeunit 4019 "GP Item Migrator" TempTrackingSpecification: Record "Tracking Specification" temporary; DataMigrationErrorLogging: Codeunit "Data Migration Error Logging"; CreateReserveEntry: Codeunit "Create Reserv. Entry"; +#if CLEAN25 + ItemJnlLineReserve: Codeunit "Item Jnl. Line-Reserve"; +#endif ExpirationDate: Date; begin if GPItem.ItemTrackingCode = '' then exit; DataMigrationErrorLogging.SetLastRecordUnderProcessing(Format(GPItemTransactions.RecordId)); - +#if not CLEAN25 TempTrackingSpecification.InitFromItemJnlLine(ItemJnlLine); - +#else + ItemJnlLineReserve.InitFromItemJnlLine(TempTrackingSpecification, ItemJnlLine); +#endif if GPItemTransactions.ExpirationDate = DMY2Date(1, 1, 1900) then ExpirationDate := 0D else diff --git a/Apps/W1/HybridGP/app/src/Migration/Support/HelperFunctions.codeunit.al b/Apps/W1/HybridGP/app/src/Migration/Support/HelperFunctions.codeunit.al index a940b997dd..75c6c5baf3 100644 --- a/Apps/W1/HybridGP/app/src/Migration/Support/HelperFunctions.codeunit.al +++ b/Apps/W1/HybridGP/app/src/Migration/Support/HelperFunctions.codeunit.al @@ -1317,7 +1317,7 @@ codeunit 4037 "Helper Functions" Session.LogMessage('00007GK', StrSubstNo(FinishedTelemetryTxt, DurationAsInt), Verbosity::Normal, DataClassification::SystemMetadata, TelemetryScope::ExtensionPublisher, 'Category', GetTelemetryCategory()); end; - [Obsolete('This procedure will be soon removed.', '26.0')] + [Obsolete('This procedure will be soon removed.', '25.0')] procedure PostGLBatch(JournalBatchName: Code[10]) var GenJournalLine: Record "Gen. Journal Line"; @@ -1358,7 +1358,7 @@ codeunit 4037 "Helper Functions" end; end; - [Obsolete('This procedure will be soon removed.', '26.0')] + [Obsolete('This procedure will be soon removed.', '25.0')] procedure PostStatisticalAccBatch(JournalBatchName: Code[10]) var StatisticalAccJournalLine: Record "Statistical Acc. Journal Line"; diff --git a/Apps/W1/HybridGP/test/app.json b/Apps/W1/HybridGP/test/app.json index e9b11aa0e6..fcb1918782 100644 --- a/Apps/W1/HybridGP/test/app.json +++ b/Apps/W1/HybridGP/test/app.json @@ -40,7 +40,7 @@ "id": "ea130081-c669-460f-a5f4-5dde14f03131", "name": "Statistical Accounts", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", diff --git a/Apps/W1/MasterDataManagement/app/src/codeunits/MasterDataMgtSubscribers.Codeunit.al b/Apps/W1/MasterDataManagement/app/src/codeunits/MasterDataMgtSubscribers.Codeunit.al index 85737acf50..0d798acd05 100644 --- a/Apps/W1/MasterDataManagement/app/src/codeunits/MasterDataMgtSubscribers.Codeunit.al +++ b/Apps/W1/MasterDataManagement/app/src/codeunits/MasterDataMgtSubscribers.Codeunit.al @@ -104,6 +104,7 @@ codeunit 7237 "Master Data Mgt. Subscribers" [EventSubscriber(ObjectType::Report, Report::"Copy Company", 'OnAfterCreatedNewCompanyByCopyCompany', '', false, false)] local procedure CleanupSetupAfterCreatedNewCompanyByCopyCompany(NewCompanyName: Text[30]) var + MasterDataMgtSubscriber: Record "Master Data Mgt. Subscriber"; MasterDataMgtCoupling: Record "Master Data Mgt. Coupling"; MasterDataManagementSetup: Record "Master Data Management Setup"; begin @@ -111,6 +112,8 @@ codeunit 7237 "Master Data Mgt. Subscribers" MasterDataMgtCoupling.DeleteAll(); MasterDataManagementSetup.ChangeCompany(NewCompanyName); MasterDataManagementSetup.DeleteAll(); + MasterDataMgtSubscriber.ChangeCompany(NewCompanyName); + MasterDataMgtSubscriber.DeleteAll(); end; internal procedure HandleOnFindingIfJobNeedsToBeRun(var Sender: Record "Job Queue Entry"; var Result: Boolean) diff --git a/Apps/W1/QBMigration/test/src/MigrationQBOTests.Codeunit.al b/Apps/W1/QBMigration/test/src/MigrationQBOTests.Codeunit.al index 6be63222d8..145db11533 100644 --- a/Apps/W1/QBMigration/test/src/MigrationQBOTests.Codeunit.al +++ b/Apps/W1/QBMigration/test/src/MigrationQBOTests.Codeunit.al @@ -195,7 +195,6 @@ codeunit 139530 "MigrationQBO Tests" end; [Test] - [HandlerFunctions('ConfirmHandlerNo')] procedure TestQBOCustomerImport() var Customer: Record "Customer"; @@ -792,13 +791,6 @@ codeunit 139530 "MigrationQBO Tests" MigrationQBAccountSetup.PurchServiceChargeAccount := AccountNumber; MigrationQBAccountSetup.Insert(); end; - - [ConfirmHandler] - [Scope('OnPrem')] - procedure ConfirmHandlerNo(Question: Text[1024]; var Reply: Boolean) - begin - Reply := false; - end; } diff --git a/Apps/W1/SalesLinesSuggestions/app/SLSPrompts.Codeunit.al b/Apps/W1/SalesLinesSuggestions/app/SLSPrompts.Codeunit.al index 1545b7f409..12c9dd81a4 100644 --- a/Apps/W1/SalesLinesSuggestions/app/SLSPrompts.Codeunit.al +++ b/Apps/W1/SalesLinesSuggestions/app/SLSPrompts.Codeunit.al @@ -46,6 +46,16 @@ codeunit 7276 "SLS Prompts" exit(BCSLSDocumentLookupPrompt); end; + [NonDebuggable] + internal procedure GetSLSSearchItemsWithFiltersPrompt(): Text + var + BCSLSSearchItemsWithFiltersPrompt: Text; + begin + GetAzureKeyVaultSecret(BCSLSSearchItemsWithFiltersPrompt, 'BCSLSSearchItemsWithFiltersPrompt'); + + exit(BCSLSSearchItemsWithFiltersPrompt); + end; + [NonDebuggable] internal procedure GetSLSSearchItemPrompt(): Text var @@ -69,5 +79,4 @@ codeunit 7276 "SLS Prompts" var ConstructingPromptFailedErr: label 'There was an error with sending the call to Copilot. Log a Business Central support request about this.', Comment = 'Copilot is a Microsoft service name and must not be translated'; TelemetryConstructingPromptFailedErr: label 'There was an error with constructing the chat completion prompt from the Key Vault.', Locked = true; - } \ No newline at end of file diff --git a/Apps/W1/SalesLinesSuggestions/app/SalesAzureOpenAITools/DocumentLookupImpl/BlanketSalesOrderLookup.Codeunit.al b/Apps/W1/SalesLinesSuggestions/app/SalesAzureOpenAITools/DocumentLookupImpl/BlanketSalesOrderLookup.Codeunit.al new file mode 100644 index 0000000000..bcaab100dd --- /dev/null +++ b/Apps/W1/SalesLinesSuggestions/app/SalesAzureOpenAITools/DocumentLookupImpl/BlanketSalesOrderLookup.Codeunit.al @@ -0,0 +1,174 @@ +// ------------------------------------------------------------------------------------------------ +// 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.Document; + +using Microsoft.Inventory.Item; + +codeunit 7281 BlanketSalesOrderLookup implements DocumentLookupSubType +{ + Access = Internal; + + var + NoDocumentFound1Err: Label 'Copilot could not find the requested Blanket Sales Order for %1. Please rephrase the description and try again.', Comment = '%1 = Customer Name'; + NoDocumentFound2Err: Label 'Copilot could not find the requested Blanket Sales Order %1. Please rephrase the description and try again.', Comment = '%1 = Document No.'; + NoLinesFoundInTheDocumentErr: Label 'Copilot found the Blanket Sales Order %1, but it does not have any relevant lines.', Comment = '%1 = Document No.'; + + procedure SearchSalesDocument(CustomDimension: Dictionary of [Text, Text]; var TempSalesLineAiSuggestion: Record "Sales Line AI Suggestions" temporary) + var + SourceSalesHeader: Record "Sales Header"; + SalesHeader: Record "Sales Header"; + DocumentLookup: Codeunit "Document Lookup Function"; + DocumentNo: Text; + StartDateStr: Text; + EndDateStr: Text; + FoundDocNo: Code[20]; + begin + DocumentLookup.GetParametersFromCustomDimension(CustomDimension, SourceSalesHeader, DocumentNo, StartDateStr, EndDateStr); + SalesHeader.SetLoadFields("No."); + // Setup SecurityFilter + SalesHeader.SetSecurityFilterOnRespCenter(); + // Remove the filter on date from RespCenter + SalesHeader.SetFilter("Date Filter", ''); + FoundDocNo := SearchPossibleNo(DocumentNo); + // Set up date range + SetFilterOnDateForSalesHeader(StartDateStr, EndDateStr, SalesHeader); + SalesHeader.SetRange("Document Type", "Sales Document Type"::"Blanket Order"); + if FoundDocNo <> '' then + SalesHeader.SetRange("No.", FoundDocNo) + else begin + SalesHeader.SetRange("Sell-to Customer No.", SourceSalesHeader."Sell-to Customer No."); + if SourceSalesHeader."Document Type" = "Sales Document Type"::"Blanket Order" then + SalesHeader.SetFilter("No.", '<>%1', SourceSalesHeader."No."); // Do not use the same document as the source document when document number is not specified + end; + + SalesHeader.SetCurrentKey("Document Date"); + if SalesHeader.FindLast() then + FoundDocNo := SalesHeader."No." + else + if FoundDocNo = '' then + Error(NoDocumentFound1Err, SourceSalesHeader."Sell-to Customer Name") + else + Error(NoDocumentFound2Err, FoundDocNo); + + GetSalesLinesIntoTempTable(FoundDocNo, TempSalesLineAiSuggestion); + end; + + local procedure SetFilterOnDateForSalesHeader(StartDateStr: Text; EndDateStr: Text; var SalesHeader: Record "Sales Header") + var + StartDate: Date; + EndDate: Date; + begin + // Set up date + Evaluate(StartDate, StartDateStr); + Evaluate(EndDate, EndDateStr); + + if (EndDate = 0D) then EndDate := dmy2date(31, 12, 9999); + SalesHeader.SetRange("Document Date", StartDate, EndDate); + end; + + local procedure SearchPossibleNo(DocumentNo: Text): Code[20] + var + DocNoLen: Integer; + Result: Code[20]; + begin + if DocumentNo = '' then + exit(''); + + DocNoLen := StrLen(DocumentNo); + if SearchPreciseNo(DocumentNo, DocNoLen, Result) then + exit(Result) + else + if SearchAmbiguousNo(DocumentNo, Result) then + exit(Result) + else + Error(NoDocumentFound2Err, DocumentNo); + end; + + local procedure SearchAmbiguousNo(DocumentNo: Text; var Result: Code[20]): Boolean + var + SalesHeader: Record "Sales Header"; + DocumentNoFilter: Text; + begin + DocumentNoFilter := StrSubstNo('*%1*', DocumentNo); + + SalesHeader.SetLoadFields("No."); + SalesHeader.SetRange("Document Type", "Sales Document Type"::"Blanket Order"); + SalesHeader.FilterGroup := -1; + SalesHeader.SetFilter("No.", DocumentNoFilter); + SalesHeader.SetFilter("External Document No.", DocumentNoFilter); + SalesHeader.SetFilter("Quote No.", DocumentNoFilter); + SalesHeader.SetFilter("Your Reference", DocumentNoFilter); + if SalesHeader.FindLast() then begin + Result := SalesHeader."No."; + exit(true); + end; + exit(false); + end; + + local procedure SearchPreciseNo(DocumentNo: Text; DocNoLen: Integer; var Result: Code[20]): Boolean + var + SalesHeader: Record "Sales Header"; + begin + SalesHeader.SetLoadFields("No."); + SalesHeader.SetRange("Document Type", "Sales Document Type"::"Blanket Order"); + SalesHeader.FilterGroup := -1; + if DocNoLen <= MaxStrLen(SalesHeader."No.") then + SalesHeader.SetRange("No.", DocumentNo); + if DocNoLen <= MaxStrLen(SalesHeader."External Document No.") then + SalesHeader.SetRange("External Document No.", DocumentNo); + if DocNoLen <= MaxStrLen(SalesHeader."Quote No.") then + SalesHeader.SetRange("Quote No.", DocumentNo); + if DocNoLen <= MaxStrLen(SalesHeader."Your Reference") then + SalesHeader.SetRange("Your Reference", DocumentNo); + if SalesHeader.GetFilter("No.") + SalesHeader.GetFilter("External Document No.") + SalesHeader.GetFilter("Quote No.") + SalesHeader.GetFilter("Your Reference") <> '' then + if SalesHeader.FindLast() then begin + Result := SalesHeader."No."; + exit(true); + end; + exit(false); + end; + + local procedure GetSalesLinesIntoTempTable(DocumentNo: Code[20]; var TempSalesLineAiSuggestion: Record "Sales Line AI Suggestions" temporary) + var + SalesLine: Record "Sales Line"; + Item: Record Item; + LineNumber: Integer; + begin + if not TempSalesLineAiSuggestion.FindLast() then + LineNumber := 1 + else + LineNumber := TempSalesLineAiSuggestion."Line No."; + + SalesLine.SetLoadFields("No.", "Description", "Type", "Outstanding Quantity", "Outstanding Qty. (Base)", "Unit of Measure Code", "Qty. per Unit of Measure", "Variant Code"); + SalesLine.SetRange("Document Type", Enum::"Sales Document Type"::"Blanket Order"); + SalesLine.SetRange("Document No.", DocumentNo); + SalesLine.SetRange("Type", SalesLine.Type::Item); + SalesLine.SetFilter("Outstanding Quantity", '>0'); + if SalesLine.FindSet() then begin + repeat + Item.SetRange("No.", SalesLine."No."); + Item.SetRange(Blocked, false); + Item.SetRange("Sales Blocked", false); + if not Item.IsEmpty() then begin + TempSalesLineAiSuggestion.Init(); + LineNumber := LineNumber + 1; + TempSalesLineAiSuggestion."Line No." := LineNumber; + TempSalesLineAiSuggestion.Type := SalesLine.Type; + TempSalesLineAiSuggestion."No." := SalesLine."No."; + TempSalesLineAiSuggestion.Description := SalesLine.Description; + TempSalesLineAiSuggestion."Variant Code" := SalesLine."Variant Code"; + TempSalesLineAiSuggestion."Unit of Measure Code" := SalesLine."Unit of Measure Code"; + TempSalesLineAiSuggestion.Quantity := SalesLine."Outstanding Quantity"; + TempSalesLineAiSuggestion.SetSourceDocument(SalesLine.RecordId()); + TempSalesLineAiSuggestion.Insert(); + end; + until SalesLine.Next() = 0; + if TempSalesLineAiSuggestion.IsEmpty() then + Error(NoLinesFoundInTheDocumentErr, DocumentNo); + end + else + Error(NoLinesFoundInTheDocumentErr, DocumentNo); + end; +} \ No newline at end of file diff --git a/Apps/W1/SalesLinesSuggestions/app/SalesAzureOpenAITools/DocumentLookupImpl/SalesInvoiceLookup.Codeunit.al b/Apps/W1/SalesLinesSuggestions/app/SalesAzureOpenAITools/DocumentLookupImpl/SalesInvoiceLookup.Codeunit.al index ba0c678e43..716cb45cb3 100644 --- a/Apps/W1/SalesLinesSuggestions/app/SalesAzureOpenAITools/DocumentLookupImpl/SalesInvoiceLookup.Codeunit.al +++ b/Apps/W1/SalesLinesSuggestions/app/SalesAzureOpenAITools/DocumentLookupImpl/SalesInvoiceLookup.Codeunit.al @@ -6,7 +6,6 @@ namespace Microsoft.Sales.Document; using Microsoft.Sales.History; using Microsoft.Inventory.Item; -using Microsoft.Foundation.UOM; codeunit 7286 SalesInvoiceLookup implements DocumentLookupSubType { @@ -75,70 +74,29 @@ codeunit 7286 SalesInvoiceLookup implements DocumentLookupSubType if SearchPreciseNo(DocumentNo, DocNoLen, Result) then exit(Result) else - if SearchAmbiguousNo(DocumentNo, DocNoLen, Result) then + if SearchAmbiguousNo(DocumentNo, Result) then exit(Result) else Error(NoDocumentFound2Err, DocumentNo); end; - local procedure SearchAmbiguousNo(DocumentNo: Text; DocNoLen: Integer; var Result: Code[20]): Boolean + local procedure SearchAmbiguousNo(DocumentNo: Text; var Result: Code[20]): Boolean var SalesInvoiceHeader: Record "Sales Invoice Header"; + DocumentNoFilter: Text; begin - if DocNoLen <= MaxStrLen(SalesInvoiceHeader."No.") then begin - // 1. Check if it is document no - SalesInvoiceHeader.Reset(); - SalesInvoiceHeader.SetLoadFields("No."); - SalesInvoiceHeader.SetFilter("No.", StrSubstNo('*%1*', DocumentNo)); + DocumentNoFilter := StrSubstNo('*%1*', DocumentNo); - if (SalesInvoiceHeader.FindLast()) then begin - Result := SalesInvoiceHeader."No."; - exit(true); - end; - end; - if DocNoLen <= MaxStrLen(SalesInvoiceHeader."External Document No.") then begin - //2. Check if it is external document no - SalesInvoiceHeader.Reset(); - SalesInvoiceHeader.SetLoadFields("No."); - SalesInvoiceHeader.SetFilter("External Document No.", StrSubstNo('*%1*', DocumentNo)); - - if (SalesInvoiceHeader.FindLast()) then begin - Result := SalesInvoiceHeader."No."; - exit(true); - end; - end; - if DocNoLen <= MaxStrLen(SalesInvoiceHeader."Order No.") then begin - //3. Check if it is order no - SalesInvoiceHeader.Reset(); - SalesInvoiceHeader.SetLoadFields("No."); - SalesInvoiceHeader.SetFilter("Order No.", StrSubstNo('*%1*', DocumentNo)); - - if (SalesInvoiceHeader.FindLast()) then begin - Result := SalesInvoiceHeader."No."; - exit(true); - end; - end; - if DocNoLen <= MaxStrLen(SalesInvoiceHeader."Quote No.") then begin - //4. Check if it is quote no - SalesInvoiceHeader.Reset(); - SalesInvoiceHeader.SetLoadFields("No."); - SalesInvoiceHeader.SetFilter("Quote No.", StrSubstNo('*%1*', DocumentNo)); - - if (SalesInvoiceHeader.FindLast()) then begin - Result := SalesInvoiceHeader."No."; - exit(true); - end; - end; - if DocNoLen <= MaxStrLen(SalesInvoiceHeader."Your Reference") then begin - //5. Check if it is reference no - SalesInvoiceHeader.Reset(); - SalesInvoiceHeader.SetLoadFields("No."); - SalesInvoiceHeader.SetFilter("Your Reference", StrSubstNo('*%1*', DocumentNo)); - - if (SalesInvoiceHeader.FindLast()) then begin - Result := SalesInvoiceHeader."No."; - exit(true); - end; + SalesInvoiceHeader.SetLoadFields("No."); + SalesInvoiceHeader.FilterGroup := -1; + SalesInvoiceHeader.SetFilter("No.", DocumentNoFilter); + SalesInvoiceHeader.SetFilter("External Document No.", DocumentNoFilter); + SalesInvoiceHeader.SetFilter("Order No.", DocumentNoFilter); + SalesInvoiceHeader.SetFilter("Quote No.", DocumentNoFilter); + SalesInvoiceHeader.SetFilter("Your Reference", DocumentNoFilter); + if SalesInvoiceHeader.FindLast() then begin + Result := SalesInvoiceHeader."No."; + exit(true); end; exit(false); end; @@ -147,61 +105,23 @@ codeunit 7286 SalesInvoiceLookup implements DocumentLookupSubType var SalesInvoiceHeader: Record "Sales Invoice Header"; begin - if DocNoLen <= MaxStrLen(SalesInvoiceHeader."No.") then begin - // 1. Check if it is document no - SalesInvoiceHeader.Reset(); - SalesInvoiceHeader.SetLoadFields("No."); + SalesInvoiceHeader.SetLoadFields("No."); + SalesInvoiceHeader.FilterGroup := -1; + if DocNoLen <= MaxStrLen(SalesInvoiceHeader."No.") then SalesInvoiceHeader.SetRange("No.", DocumentNo); - - if (SalesInvoiceHeader.FindLast()) then begin - Result := SalesInvoiceHeader."No."; - exit(true); - end; - end; - if DocNoLen <= MaxStrLen(SalesInvoiceHeader."External Document No.") then begin - //2. Check if it is external document no - SalesInvoiceHeader.Reset(); - SalesInvoiceHeader.SetLoadFields("No."); + if DocNoLen <= MaxStrLen(SalesInvoiceHeader."External Document No.") then SalesInvoiceHeader.SetRange("External Document No.", DocumentNo); - - if (SalesInvoiceHeader.FindLast()) then begin - Result := SalesInvoiceHeader."No."; - exit(true); - end; - end; - if DocNoLen <= MaxStrLen(SalesInvoiceHeader."Order No.") then begin - //3. Check if it is order no - SalesInvoiceHeader.Reset(); - SalesInvoiceHeader.SetLoadFields("No."); + if DocNoLen <= MaxStrLen(SalesInvoiceHeader."Order No.") then SalesInvoiceHeader.SetRange("Order No.", DocumentNo); - - if (SalesInvoiceHeader.FindLast()) then begin - Result := SalesInvoiceHeader."No."; - exit(true); - end; - end; - if DocNoLen <= MaxStrLen(SalesInvoiceHeader."Quote No.") then begin - //4. Check if it is quote no - SalesInvoiceHeader.Reset(); - SalesInvoiceHeader.SetLoadFields("No."); + if DocNoLen <= MaxStrLen(SalesInvoiceHeader."Quote No.") then SalesInvoiceHeader.SetRange("Quote No.", DocumentNo); - - if (SalesInvoiceHeader.FindLast()) then begin - Result := SalesInvoiceHeader."No."; - exit(true); - end; - end; - if DocNoLen <= MaxStrLen(SalesInvoiceHeader."Your Reference") then begin - //5. Check if it is reference no - SalesInvoiceHeader.Reset(); - SalesInvoiceHeader.SetLoadFields("No."); + if DocNoLen <= MaxStrLen(SalesInvoiceHeader."Your Reference") then SalesInvoiceHeader.SetRange("Your Reference", DocumentNo); - - if (SalesInvoiceHeader.FindLast()) then begin + if SalesInvoiceHeader.GetFilter("No.") + SalesInvoiceHeader.GetFilter("External Document No.") + SalesInvoiceHeader.GetFilter("Order No.") + SalesInvoiceHeader.GetFilter("Quote No.") + SalesInvoiceHeader.GetFilter("Your Reference") <> '' then + if SalesInvoiceHeader.FindLast() then begin Result := SalesInvoiceHeader."No."; exit(true); end; - end; exit(false); end; @@ -209,7 +129,6 @@ codeunit 7286 SalesInvoiceLookup implements DocumentLookupSubType var SalesInvoiceLine: Record "Sales Invoice Line"; Item: Record Item; - UoMMgt: Codeunit "Unit of Measure Management"; LineNumber: Integer; begin if not TempSalesLineAiSuggestion.FindLast() then @@ -217,7 +136,6 @@ codeunit 7286 SalesInvoiceLookup implements DocumentLookupSubType else LineNumber := TempSalesLineAiSuggestion."Line No."; - Item.SetLoadFields("No.", "Sales Unit of Measure"); SalesInvoiceLine.SetLoadFields("No.", "Description", "Type", "Quantity", "Quantity (Base)", "Unit of Measure Code", "Qty. per Unit of Measure", "Variant Code"); SalesInvoiceLine.SetRange("Document No.", DocumentNo); SalesInvoiceLine.SetRange("Type", SalesInvoiceLine.Type::Item); @@ -226,7 +144,7 @@ codeunit 7286 SalesInvoiceLookup implements DocumentLookupSubType Item.SetRange("No.", SalesInvoiceLine."No."); Item.SetRange(Blocked, false); Item.SetRange("Sales Blocked", false); - if Item.FindFirst() then begin + if not Item.IsEmpty() then begin TempSalesLineAiSuggestion.Init(); LineNumber := LineNumber + 1; TempSalesLineAiSuggestion."Line No." := LineNumber; @@ -234,13 +152,8 @@ codeunit 7286 SalesInvoiceLookup implements DocumentLookupSubType TempSalesLineAiSuggestion."No." := SalesInvoiceLine."No."; TempSalesLineAiSuggestion.Description := SalesInvoiceLine.Description; TempSalesLineAiSuggestion."Variant Code" := SalesInvoiceLine."Variant Code"; - if Item."Sales Unit of Measure" <> '' then - if SalesInvoiceLine."Unit of Measure Code" = Item."Sales Unit of Measure" then - TempSalesLineAiSuggestion.Quantity := SalesInvoiceLine.Quantity - else - TempSalesLineAiSuggestion.Quantity := UoMMgt.CalcQtyFromBase(SalesInvoiceLine."Quantity (Base)", UoMMgt.GetQtyPerUnitOfMeasure(Item, Item."Sales Unit of Measure")) - else - TempSalesLineAiSuggestion.Quantity := SalesInvoiceLine."Quantity (Base)"; + TempSalesLineAiSuggestion."Unit of Measure Code" := SalesInvoiceLine."Unit of Measure Code"; + TempSalesLineAiSuggestion.Quantity := SalesInvoiceLine.Quantity; TempSalesLineAiSuggestion.SetSourceDocument(SalesInvoiceLine.RecordId()); TempSalesLineAiSuggestion.Insert(); end; diff --git a/Apps/W1/SalesLinesSuggestions/app/SalesAzureOpenAITools/DocumentLookupImpl/SalesOrderLookup.Codeunit.al b/Apps/W1/SalesLinesSuggestions/app/SalesAzureOpenAITools/DocumentLookupImpl/SalesOrderLookup.Codeunit.al index 5f5d24ca53..dfbb0423fa 100644 --- a/Apps/W1/SalesLinesSuggestions/app/SalesAzureOpenAITools/DocumentLookupImpl/SalesOrderLookup.Codeunit.al +++ b/Apps/W1/SalesLinesSuggestions/app/SalesAzureOpenAITools/DocumentLookupImpl/SalesOrderLookup.Codeunit.al @@ -5,7 +5,6 @@ namespace Microsoft.Sales.Document; using Microsoft.Inventory.Item; -using Microsoft.Foundation.UOM; codeunit 7287 SalesOrderLookup implements DocumentLookupSubType { @@ -81,59 +80,29 @@ codeunit 7287 SalesOrderLookup implements DocumentLookupSubType if SearchPreciseNo(DocumentNo, DocNoLen, Result) then exit(Result) else - if SearchAmbiguousNo(DocumentNo, DocNoLen, Result) then + if SearchAmbiguousNo(DocumentNo, Result) then exit(Result) else Error(NoDocumentFound2Err, DocumentNo); end; - local procedure SearchAmbiguousNo(DocumentNo: Text; DocNoLen: Integer; var Result: Code[20]): Boolean + local procedure SearchAmbiguousNo(DocumentNo: Text; var Result: Code[20]): Boolean var SalesHeader: Record "Sales Header"; + DocumentNoFilter: Text; begin - if DocNoLen <= MaxStrLen(SalesHeader."No.") then begin - // 1. Check if it is document no - SalesHeader.Reset(); - SalesHeader.SetLoadFields("No."); - SalesHeader.SetRange("Document Type", "Sales Document Type"::Order); - SalesHeader.SetFilter("No.", StrSubstNo('*%1*', DocumentNo)); - if (SalesHeader.FindLast()) then begin - Result := SalesHeader."No."; - exit(true); - end; - end; - if DocNoLen <= MaxStrLen(SalesHeader."External Document No.") then begin - //2. Check if it is external document no - SalesHeader.Reset(); - SalesHeader.SetLoadFields("No."); - SalesHeader.SetRange("Document Type", "Sales Document Type"::Order); - SalesHeader.SetFilter("External Document No.", StrSubstNo('*%1*', DocumentNo)); - if (SalesHeader.FindLast()) then begin - Result := SalesHeader."No."; - exit(true); - end; - end; - if DocNoLen <= MaxStrLen(SalesHeader."Quote No.") then begin - //3. Check if it is quote no - SalesHeader.Reset(); - SalesHeader.SetLoadFields("No."); - SalesHeader.SetRange("Document Type", "Sales Document Type"::Order); - SalesHeader.SetFilter("Quote No.", StrSubstNo('*%1*', DocumentNo)); - if (SalesHeader.FindLast()) then begin - Result := SalesHeader."No."; - exit(true); - end; - end; - if DocNoLen <= MaxStrLen(SalesHeader."Your Reference") then begin - //4. Check if it is reference no - SalesHeader.Reset(); - SalesHeader.SetLoadFields("No."); - SalesHeader.SetRange("Document Type", "Sales Document Type"::Order); - SalesHeader.SetFilter("Your Reference", StrSubstNo('*%1*', DocumentNo)); - if (SalesHeader.FindLast()) then begin - Result := SalesHeader."No."; - exit(true); - end; + DocumentNoFilter := StrSubstNo('*%1*', DocumentNo); + + SalesHeader.SetLoadFields("No."); + SalesHeader.SetRange("Document Type", "Sales Document Type"::Order); + SalesHeader.FilterGroup := -1; + SalesHeader.SetFilter("No.", DocumentNoFilter); + SalesHeader.SetFilter("External Document No.", DocumentNoFilter); + SalesHeader.SetFilter("Quote No.", DocumentNoFilter); + SalesHeader.SetFilter("Your Reference", DocumentNoFilter); + if SalesHeader.FindLast() then begin + Result := SalesHeader."No."; + exit(true); end; exit(false); end; @@ -142,50 +111,22 @@ codeunit 7287 SalesOrderLookup implements DocumentLookupSubType var SalesHeader: Record "Sales Header"; begin - if DocNoLen <= MaxStrLen(SalesHeader."No.") then begin - // 1. Check if it is document no - SalesHeader.Reset(); - SalesHeader.SetLoadFields("No."); - SalesHeader.SetRange("Document Type", "Sales Document Type"::Order); + SalesHeader.SetLoadFields("No."); + SalesHeader.SetRange("Document Type", "Sales Document Type"::Order); + SalesHeader.FilterGroup := -1; + if DocNoLen <= MaxStrLen(SalesHeader."No.") then SalesHeader.SetRange("No.", DocumentNo); - if (SalesHeader.FindLast()) then begin - Result := SalesHeader."No."; - exit(true); - end; - end; - if DocNoLen <= MaxStrLen(SalesHeader."External Document No.") then begin - //2. Check if it is external document no - SalesHeader.Reset(); - SalesHeader.SetLoadFields("No."); - SalesHeader.SetRange("Document Type", "Sales Document Type"::Order); + if DocNoLen <= MaxStrLen(SalesHeader."External Document No.") then SalesHeader.SetRange("External Document No.", DocumentNo); - if (SalesHeader.FindLast()) then begin - Result := SalesHeader."No."; - exit(true); - end; - end; - if DocNoLen <= MaxStrLen(SalesHeader."Quote No.") then begin - //3. Check if it is quote no - SalesHeader.Reset(); - SalesHeader.SetLoadFields("No."); - SalesHeader.SetRange("Document Type", "Sales Document Type"::Order); + if DocNoLen <= MaxStrLen(SalesHeader."Quote No.") then SalesHeader.SetRange("Quote No.", DocumentNo); - if (SalesHeader.FindLast()) then begin - Result := SalesHeader."No."; - exit(true); - end; - end; - if DocNoLen <= MaxStrLen(SalesHeader."Your Reference") then begin - //4. Check if it is reference no - SalesHeader.Reset(); - SalesHeader.SetLoadFields("No."); - SalesHeader.SetRange("Document Type", "Sales Document Type"::Order); + if DocNoLen <= MaxStrLen(SalesHeader."Your Reference") then SalesHeader.SetRange("Your Reference", DocumentNo); - if (SalesHeader.FindLast()) then begin + if SalesHeader.GetFilter("No.") + SalesHeader.GetFilter("External Document No.") + SalesHeader.GetFilter("Quote No.") + SalesHeader.GetFilter("Your Reference") <> '' then + if SalesHeader.FindLast() then begin Result := SalesHeader."No."; exit(true); end; - end; exit(false); end; @@ -193,7 +134,6 @@ codeunit 7287 SalesOrderLookup implements DocumentLookupSubType var SalesLine: Record "Sales Line"; Item: Record Item; - UoMMgt: Codeunit "Unit of Measure Management"; LineNumber: Integer; begin if not TempSalesLineAiSuggestion.FindLast() then @@ -201,7 +141,6 @@ codeunit 7287 SalesOrderLookup implements DocumentLookupSubType else LineNumber := TempSalesLineAiSuggestion."Line No."; - Item.SetLoadFields("No.", "Sales Unit of Measure"); SalesLine.SetLoadFields("No.", "Description", "Type", "Quantity", "Quantity (Base)", "Unit of Measure Code", "Qty. per Unit of Measure", "Variant Code"); SalesLine.SetRange("Document Type", Enum::"Sales Document Type"::Order); SalesLine.SetRange("Document No.", DocumentNo); @@ -211,7 +150,7 @@ codeunit 7287 SalesOrderLookup implements DocumentLookupSubType Item.SetRange("No.", SalesLine."No."); Item.SetRange(Blocked, false); Item.SetRange("Sales Blocked", false); - if Item.FindFirst() then begin + if not Item.IsEmpty() then begin TempSalesLineAiSuggestion.Init(); LineNumber := LineNumber + 1; TempSalesLineAiSuggestion."Line No." := LineNumber; @@ -219,13 +158,8 @@ codeunit 7287 SalesOrderLookup implements DocumentLookupSubType TempSalesLineAiSuggestion."No." := SalesLine."No."; TempSalesLineAiSuggestion.Description := SalesLine.Description; TempSalesLineAiSuggestion."Variant Code" := SalesLine."Variant Code"; - if Item."Sales Unit of Measure" <> '' then - if SalesLine."Unit of Measure Code" = Item."Sales Unit of Measure" then - TempSalesLineAiSuggestion.Quantity := SalesLine.Quantity - else - TempSalesLineAiSuggestion.Quantity := UoMMgt.CalcQtyFromBase(SalesLine."Quantity (Base)", UoMMgt.GetQtyPerUnitOfMeasure(Item, Item."Sales Unit of Measure")) - else - TempSalesLineAiSuggestion.Quantity := SalesLine."Quantity (Base)"; + TempSalesLineAiSuggestion."Unit of Measure Code" := SalesLine."Unit of Measure Code"; + TempSalesLineAiSuggestion.Quantity := SalesLine.Quantity; TempSalesLineAiSuggestion.SetSourceDocument(SalesLine.RecordId()); TempSalesLineAiSuggestion.Insert(); end; diff --git a/Apps/W1/SalesLinesSuggestions/app/SalesAzureOpenAITools/DocumentLookupImpl/SalesQuoteLookup.Codeunit.al b/Apps/W1/SalesLinesSuggestions/app/SalesAzureOpenAITools/DocumentLookupImpl/SalesQuoteLookup.Codeunit.al index 0996ca9c74..455181aec2 100644 --- a/Apps/W1/SalesLinesSuggestions/app/SalesAzureOpenAITools/DocumentLookupImpl/SalesQuoteLookup.Codeunit.al +++ b/Apps/W1/SalesLinesSuggestions/app/SalesAzureOpenAITools/DocumentLookupImpl/SalesQuoteLookup.Codeunit.al @@ -5,7 +5,6 @@ namespace Microsoft.Sales.Document; using Microsoft.Inventory.Item; -using Microsoft.Foundation.UOM; codeunit 7288 SalesQuoteLookup implements DocumentLookupSubType { @@ -81,59 +80,29 @@ codeunit 7288 SalesQuoteLookup implements DocumentLookupSubType if SearchPreciseNo(DocumentNo, DocNoLen, Result) then exit(Result) else - if SearchAmbiguousNo(DocumentNo, DocNoLen, Result) then + if SearchAmbiguousNo(DocumentNo, Result) then exit(Result) else Error(NoDocumentFound2Err, DocumentNo); end; - local procedure SearchAmbiguousNo(DocumentNo: Text; DocNoLen: Integer; var Result: Code[20]): Boolean + local procedure SearchAmbiguousNo(DocumentNo: Text; var Result: Code[20]): Boolean var SalesHeader: Record "Sales Header"; + DocumentNoFilter: Text; begin - if DocNoLen <= MaxStrLen(SalesHeader."No.") then begin - // 1. Check if it is document no - SalesHeader.Reset(); - SalesHeader.SetLoadFields("No."); - SalesHeader.SetRange("Document Type", "Sales Document Type"::Quote); - SalesHeader.SetFilter("No.", StrSubstNo('*%1*', DocumentNo)); - if (SalesHeader.FindLast()) then begin - Result := SalesHeader."No."; - exit(true); - end; - end; - if DocNoLen <= MaxStrLen(SalesHeader."External Document No.") then begin - //2. Check if it is external document no - SalesHeader.Reset(); - SalesHeader.SetLoadFields("No."); - SalesHeader.SetRange("Document Type", "Sales Document Type"::Quote); - SalesHeader.SetFilter("External Document No.", StrSubstNo('*%1*', DocumentNo)); - if (SalesHeader.FindLast()) then begin - Result := SalesHeader."No."; - exit(true); - end; - end; - if DocNoLen <= MaxStrLen(SalesHeader."Quote No.") then begin - //3. Check if it is quote no - SalesHeader.Reset(); - SalesHeader.SetLoadFields("No."); - SalesHeader.SetRange("Document Type", "Sales Document Type"::Quote); - SalesHeader.SetFilter("Quote No.", StrSubstNo('*%1*', DocumentNo)); - if (SalesHeader.FindLast()) then begin - Result := SalesHeader."No."; - exit(true); - end; - end; - if DocNoLen <= MaxStrLen(SalesHeader."Your Reference") then begin - //4. Check if it is reference no - SalesHeader.Reset(); - SalesHeader.SetLoadFields("No."); - SalesHeader.SetRange("Document Type", "Sales Document Type"::Quote); - SalesHeader.SetFilter("Your Reference", StrSubstNo('*%1*', DocumentNo)); - if (SalesHeader.FindLast()) then begin - Result := SalesHeader."No."; - exit(true); - end; + DocumentNoFilter := StrSubstNo('*%1*', DocumentNo); + + SalesHeader.SetLoadFields("No."); + SalesHeader.SetRange("Document Type", "Sales Document Type"::Quote); + SalesHeader.FilterGroup := -1; + SalesHeader.SetFilter("No.", DocumentNoFilter); + SalesHeader.SetFilter("External Document No.", DocumentNoFilter); + SalesHeader.SetFilter("Quote No.", DocumentNoFilter); + SalesHeader.SetFilter("Your Reference", DocumentNoFilter); + if SalesHeader.FindLast() then begin + Result := SalesHeader."No."; + exit(true); end; exit(false); end; @@ -142,50 +111,22 @@ codeunit 7288 SalesQuoteLookup implements DocumentLookupSubType var SalesHeader: Record "Sales Header"; begin - if DocNoLen <= MaxStrLen(SalesHeader."No.") then begin - // 1. Check if it is document no - SalesHeader.Reset(); - SalesHeader.SetLoadFields("No."); - SalesHeader.SetRange("Document Type", "Sales Document Type"::Quote); + SalesHeader.SetLoadFields("No."); + SalesHeader.SetRange("Document Type", "Sales Document Type"::Quote); + SalesHeader.FilterGroup := -1; + if DocNoLen <= MaxStrLen(SalesHeader."No.") then SalesHeader.SetRange("No.", DocumentNo); - if (SalesHeader.FindLast()) then begin - Result := SalesHeader."No."; - exit(true); - end; - end; - if DocNoLen <= MaxStrLen(SalesHeader."External Document No.") then begin - //2. Check if it is external document no - SalesHeader.Reset(); - SalesHeader.SetLoadFields("No."); - SalesHeader.SetRange("Document Type", "Sales Document Type"::Quote); + if DocNoLen <= MaxStrLen(SalesHeader."External Document No.") then SalesHeader.SetRange("External Document No.", DocumentNo); - if (SalesHeader.FindLast()) then begin - Result := SalesHeader."No."; - exit(true); - end; - end; - if DocNoLen <= MaxStrLen(SalesHeader."Quote No.") then begin - //3. Check if it is quote no - SalesHeader.Reset(); - SalesHeader.SetLoadFields("No."); - SalesHeader.SetRange("Document Type", "Sales Document Type"::Quote); + if DocNoLen <= MaxStrLen(SalesHeader."Quote No.") then SalesHeader.SetRange("Quote No.", DocumentNo); - if (SalesHeader.FindLast()) then begin - Result := SalesHeader."No."; - exit(true); - end; - end; - if DocNoLen <= MaxStrLen(SalesHeader."Your Reference") then begin - //4. Check if it is reference no - SalesHeader.Reset(); - SalesHeader.SetLoadFields("No."); - SalesHeader.SetRange("Document Type", "Sales Document Type"::Quote); + if DocNoLen <= MaxStrLen(SalesHeader."Your Reference") then SalesHeader.SetRange("Your Reference", DocumentNo); - if (SalesHeader.FindLast()) then begin + if SalesHeader.GetFilter("No.") + SalesHeader.GetFilter("External Document No.") + SalesHeader.GetFilter("Quote No.") + SalesHeader.GetFilter("Your Reference") <> '' then + if SalesHeader.FindLast() then begin Result := SalesHeader."No."; exit(true); end; - end; exit(false); end; @@ -193,7 +134,6 @@ codeunit 7288 SalesQuoteLookup implements DocumentLookupSubType var SalesLine: Record "Sales Line"; Item: Record Item; - UoMMgt: Codeunit "Unit of Measure Management"; LineNumber: Integer; begin if not TempSalesLineAiSuggestion.FindLast() then @@ -201,7 +141,6 @@ codeunit 7288 SalesQuoteLookup implements DocumentLookupSubType else LineNumber := TempSalesLineAiSuggestion."Line No."; - Item.SetLoadFields("No.", "Sales Unit of Measure"); SalesLine.SetLoadFields("No.", "Description", "Type", "Quantity", "Quantity (Base)", "Unit of Measure Code", "Qty. per Unit of Measure", "Variant Code"); SalesLine.SetRange("Document Type", Enum::"Sales Document Type"::Quote); SalesLine.SetRange("Document No.", DocumentNo); @@ -211,7 +150,7 @@ codeunit 7288 SalesQuoteLookup implements DocumentLookupSubType Item.SetRange("No.", SalesLine."No."); Item.SetRange(Blocked, false); Item.SetRange("Sales Blocked", false); - if Item.FindFirst() then begin + if not Item.IsEmpty() then begin TempSalesLineAiSuggestion.Init(); LineNumber := LineNumber + 1; TempSalesLineAiSuggestion."Line No." := LineNumber; @@ -219,13 +158,8 @@ codeunit 7288 SalesQuoteLookup implements DocumentLookupSubType TempSalesLineAiSuggestion."No." := SalesLine."No."; TempSalesLineAiSuggestion.Description := SalesLine.Description; TempSalesLineAiSuggestion."Variant Code" := SalesLine."Variant Code"; - if Item."Sales Unit of Measure" <> '' then - if SalesLine."Unit of Measure Code" = Item."Sales Unit of Measure" then - TempSalesLineAiSuggestion.Quantity := SalesLine.Quantity - else - TempSalesLineAiSuggestion.Quantity := UoMMgt.CalcQtyFromBase(SalesLine."Quantity (Base)", UoMMgt.GetQtyPerUnitOfMeasure(Item, Item."Sales Unit of Measure")) - else - TempSalesLineAiSuggestion.Quantity := SalesLine."Quantity (Base)"; + TempSalesLineAiSuggestion."Unit of Measure Code" := SalesLine."Unit of Measure Code"; + TempSalesLineAiSuggestion.Quantity := SalesLine.Quantity; TempSalesLineAiSuggestion.SetSourceDocument(SalesLine.RecordId()); TempSalesLineAiSuggestion.Insert(); end; diff --git a/Apps/W1/SalesLinesSuggestions/app/SalesAzureOpenAITools/DocumentLookupImpl/SalesShipmentLookup.Codeunit.al b/Apps/W1/SalesLinesSuggestions/app/SalesAzureOpenAITools/DocumentLookupImpl/SalesShipmentLookup.Codeunit.al index 21f59c7db9..60970415dc 100644 --- a/Apps/W1/SalesLinesSuggestions/app/SalesAzureOpenAITools/DocumentLookupImpl/SalesShipmentLookup.Codeunit.al +++ b/Apps/W1/SalesLinesSuggestions/app/SalesAzureOpenAITools/DocumentLookupImpl/SalesShipmentLookup.Codeunit.al @@ -5,7 +5,6 @@ namespace Microsoft.Sales.Document; using Microsoft.Inventory.Item; -using Microsoft.Foundation.UOM; using Microsoft.Sales.History; codeunit 7289 SalesShipmentLookup implements DocumentLookupSubType @@ -75,70 +74,29 @@ codeunit 7289 SalesShipmentLookup implements DocumentLookupSubType if SearchPreciseNo(DocumentNo, DocNoLen, Result) then exit(Result) else - if SearchAmbiguousNo(DocumentNo, DocNoLen, Result) then + if SearchAmbiguousNo(DocumentNo, Result) then exit(Result) else Error(NoDocumentFound2Err, DocumentNo); end; - local procedure SearchAmbiguousNo(DocumentNo: Text; DocNoLen: Integer; var Result: Code[20]): Boolean + local procedure SearchAmbiguousNo(DocumentNo: Text; var Result: Code[20]): Boolean var SalesShipmentHeader: Record "Sales Shipment Header"; + DocumentNoFilter: Text; begin - if DocNoLen <= MaxStrLen(SalesShipmentHeader."No.") then begin - // 1. Check if it is document no - SalesShipmentHeader.Reset(); - SalesShipmentHeader.SetLoadFields("No."); - SalesShipmentHeader.SetFilter("No.", StrSubstNo('*%1*', DocumentNo)); + DocumentNoFilter := StrSubstNo('*%1*', DocumentNo); - if (SalesShipmentHeader.FindLast()) then begin - Result := SalesShipmentHeader."No."; - exit(true); - end; - end; - if DocNoLen <= MaxStrLen(SalesShipmentHeader."External Document No.") then begin - //2. Check if it is external document no - SalesShipmentHeader.Reset(); - SalesShipmentHeader.SetLoadFields("No."); - SalesShipmentHeader.SetFilter("External Document No.", StrSubstNo('*%1*', DocumentNo)); - - if (SalesShipmentHeader.FindLast()) then begin - Result := SalesShipmentHeader."No."; - exit(true); - end; - end; - if DocNoLen <= MaxStrLen(SalesShipmentHeader."Order No.") then begin - //3. Check if it is order no - SalesShipmentHeader.Reset(); - SalesShipmentHeader.SetLoadFields("No."); - SalesShipmentHeader.SetFilter("Order No.", StrSubstNo('*%1*', DocumentNo)); - - if (SalesShipmentHeader.FindLast()) then begin - Result := SalesShipmentHeader."No."; - exit(true); - end; - end; - if DocNoLen <= MaxStrLen(SalesShipmentHeader."Quote No.") then begin - //4. Check if it is quote no - SalesShipmentHeader.Reset(); - SalesShipmentHeader.SetLoadFields("No."); - SalesShipmentHeader.SetFilter("Quote No.", StrSubstNo('*%1*', DocumentNo)); - - if (SalesShipmentHeader.FindLast()) then begin - Result := SalesShipmentHeader."No."; - exit(true); - end; - end; - if DocNoLen <= MaxStrLen(SalesShipmentHeader."Your Reference") then begin - //5. Check if it is reference no - SalesShipmentHeader.Reset(); - SalesShipmentHeader.SetLoadFields("No."); - SalesShipmentHeader.SetFilter("Your Reference", StrSubstNo('*%1*', DocumentNo)); - - if (SalesShipmentHeader.FindLast()) then begin - Result := SalesShipmentHeader."No."; - exit(true); - end; + SalesShipmentHeader.SetLoadFields("No."); + SalesShipmentHeader.FilterGroup := -1; + SalesShipmentHeader.SetFilter("No.", DocumentNoFilter); + SalesShipmentHeader.SetFilter("External Document No.", DocumentNoFilter); + SalesShipmentHeader.SetFilter("Order No.", DocumentNoFilter); + SalesShipmentHeader.SetFilter("Quote No.", DocumentNoFilter); + SalesShipmentHeader.SetFilter("Your Reference", DocumentNoFilter); + if SalesShipmentHeader.FindLast() then begin + Result := SalesShipmentHeader."No."; + exit(true); end; exit(false); end; @@ -147,61 +105,23 @@ codeunit 7289 SalesShipmentLookup implements DocumentLookupSubType var SalesShipmentHeader: Record "Sales Shipment Header"; begin - if DocNoLen <= MaxStrLen(SalesShipmentHeader."No.") then begin - // 1. Check if it is document no - SalesShipmentHeader.Reset(); - SalesShipmentHeader.SetLoadFields("No."); + SalesShipmentHeader.SetLoadFields("No."); + SalesShipmentHeader.FilterGroup := -1; + if DocNoLen <= MaxStrLen(SalesShipmentHeader."No.") then SalesShipmentHeader.SetRange("No.", DocumentNo); - - if (SalesShipmentHeader.FindLast()) then begin - Result := SalesShipmentHeader."No."; - exit(true); - end; - end; - if DocNoLen <= MaxStrLen(SalesShipmentHeader."External Document No.") then begin - //2. Check if it is external document no - SalesShipmentHeader.Reset(); - SalesShipmentHeader.SetLoadFields("No."); + if DocNoLen <= MaxStrLen(SalesShipmentHeader."External Document No.") then SalesShipmentHeader.SetRange("External Document No.", DocumentNo); - - if (SalesShipmentHeader.FindLast()) then begin - Result := SalesShipmentHeader."No."; - exit(true); - end; - end; - if DocNoLen <= MaxStrLen(SalesShipmentHeader."Order No.") then begin - //3. Check if it is order no - SalesShipmentHeader.Reset(); - SalesShipmentHeader.SetLoadFields("No."); + if DocNoLen <= MaxStrLen(SalesShipmentHeader."Order No.") then SalesShipmentHeader.SetRange("Order No.", DocumentNo); - - if (SalesShipmentHeader.FindLast()) then begin - Result := SalesShipmentHeader."No."; - exit(true); - end; - end; - if DocNoLen <= MaxStrLen(SalesShipmentHeader."Quote No.") then begin - //4. Check if it is quote no - SalesShipmentHeader.Reset(); - SalesShipmentHeader.SetLoadFields("No."); + if DocNoLen <= MaxStrLen(SalesShipmentHeader."Quote No.") then SalesShipmentHeader.SetRange("Quote No.", DocumentNo); - - if (SalesShipmentHeader.FindLast()) then begin - Result := SalesShipmentHeader."No."; - exit(true); - end; - end; - if DocNoLen <= MaxStrLen(SalesShipmentHeader."Your Reference") then begin - //5. Check if it is reference no - SalesShipmentHeader.Reset(); - SalesShipmentHeader.SetLoadFields("No."); + if DocNoLen <= MaxStrLen(SalesShipmentHeader."Your Reference") then SalesShipmentHeader.SetRange("Your Reference", DocumentNo); - - if (SalesShipmentHeader.FindLast()) then begin + if SalesShipmentHeader.GetFilter("No.") + SalesShipmentHeader.GetFilter("External Document No.") + SalesShipmentHeader.GetFilter("Order No.") + SalesShipmentHeader.GetFilter("Quote No.") + SalesShipmentHeader.GetFilter("Your Reference") <> '' then + if SalesShipmentHeader.FindLast() then begin Result := SalesShipmentHeader."No."; exit(true); end; - end; exit(false); end; @@ -209,7 +129,6 @@ codeunit 7289 SalesShipmentLookup implements DocumentLookupSubType var SalesShipmentLine: Record "Sales Shipment Line"; Item: Record Item; - UoMMgt: Codeunit "Unit of Measure Management"; LineNumber: Integer; begin if not TempSalesLineAiSuggestion.FindLast() then @@ -217,7 +136,6 @@ codeunit 7289 SalesShipmentLookup implements DocumentLookupSubType else LineNumber := TempSalesLineAiSuggestion."Line No."; - Item.SetLoadFields("No.", "Sales Unit of Measure"); SalesShipmentLine.SetLoadFields("No.", "Description", "Type", "Quantity", "Quantity (Base)", "Unit of Measure Code", "Qty. per Unit of Measure", "Variant Code"); SalesShipmentLine.SetRange("Document No.", DocumentNo); SalesShipmentLine.SetRange("Type", SalesShipmentLine.Type::Item); @@ -226,7 +144,7 @@ codeunit 7289 SalesShipmentLookup implements DocumentLookupSubType Item.SetRange("No.", SalesShipmentLine."No."); Item.SetRange(Blocked, false); Item.SetRange("Sales Blocked", false); - if Item.FindFirst() then begin + if not Item.IsEmpty() then begin TempSalesLineAiSuggestion.Init(); LineNumber := LineNumber + 1; TempSalesLineAiSuggestion."Line No." := LineNumber; @@ -234,13 +152,8 @@ codeunit 7289 SalesShipmentLookup implements DocumentLookupSubType TempSalesLineAiSuggestion."No." := SalesShipmentLine."No."; TempSalesLineAiSuggestion.Description := SalesShipmentLine.Description; TempSalesLineAiSuggestion."Variant Code" := SalesShipmentLine."Variant Code"; - if Item."Sales Unit of Measure" <> '' then - if SalesShipmentLine."Unit of Measure Code" = Item."Sales Unit of Measure" then - TempSalesLineAiSuggestion.Quantity := SalesShipmentLine.Quantity - else - TempSalesLineAiSuggestion.Quantity := UoMMgt.CalcQtyFromBase(SalesShipmentLine."Quantity (Base)", UoMMgt.GetQtyPerUnitOfMeasure(Item, Item."Sales Unit of Measure")) - else - TempSalesLineAiSuggestion.Quantity := SalesShipmentLine."Quantity (Base)"; + TempSalesLineAiSuggestion."Unit of Measure Code" := SalesShipmentLine."Unit of Measure Code"; + TempSalesLineAiSuggestion.Quantity := SalesShipmentLine.Quantity; TempSalesLineAiSuggestion.SetSourceDocument(SalesShipmentLine.RecordId()); TempSalesLineAiSuggestion.Insert(); end; diff --git a/Apps/W1/SalesLinesSuggestions/app/SalesAzureOpenAITools/Enums/DocumentLookupTypes.Enum.al b/Apps/W1/SalesLinesSuggestions/app/SalesAzureOpenAITools/Enums/DocumentLookupTypes.Enum.al index aa7cbb6aec..8c48ed8b9f 100644 --- a/Apps/W1/SalesLinesSuggestions/app/SalesAzureOpenAITools/Enums/DocumentLookupTypes.Enum.al +++ b/Apps/W1/SalesLinesSuggestions/app/SalesAzureOpenAITools/Enums/DocumentLookupTypes.Enum.al @@ -25,4 +25,8 @@ enum 7279 "Document Lookup Types" implements DocumentLookupSubType { Implementation = DocumentLookupSubType = SalesQuoteLookup; } + value(4; "Blanket Sales Order") + { + Implementation = DocumentLookupSubType = BlanketSalesOrderLookup; + } } \ No newline at end of file diff --git a/Apps/W1/SalesLinesSuggestions/app/SalesAzureOpenAITools/FunctionsImpl/SearchItemsWithFiltersFunc.Codeunit.al b/Apps/W1/SalesLinesSuggestions/app/SalesAzureOpenAITools/FunctionsImpl/SearchItemsWithFiltersFunc.Codeunit.al new file mode 100644 index 0000000000..67af914f85 --- /dev/null +++ b/Apps/W1/SalesLinesSuggestions/app/SalesAzureOpenAITools/FunctionsImpl/SearchItemsWithFiltersFunc.Codeunit.al @@ -0,0 +1,236 @@ +// ------------------------------------------------------------------------------------------------ +// 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.Document; + +using System.AI; +using System.Telemetry; +using Microsoft.Foundation.UOM; +using Microsoft.Inventory.Item; +using System.Text; + +codeunit 7291 "Search Items With Filters Func" implements "AOAI Function" +{ + Access = Internal; + + var + SourceDocumentRecordId: RecordId; + SearchQuery: Text; + SearchStyle: Enum "Search Style"; + FunctionNameLbl: Label 'search_items_with_filters', Locked = true; + SearchWithFiltersLbl: Label 'function_call: search_items_with_filters', Locked = true; + SourceDocumentRecordIDLbl: Label 'SourceDocumentRecordID', Locked = true; + + [NonDebuggable] + procedure GetPrompt(): JsonObject + var + UnitOfMeasure: Record "Unit of Measure"; + Prompt: Codeunit "SLS Prompts"; + PromptJson: JsonObject; + UnitsOfMeasureText: Text; + begin + UnitsOfMeasureText := ''; + UnitOfMeasure.SetFilter(Description, '<>%1', ''); + if UnitOfMeasure.FindSet() then begin + repeat + UnitsOfMeasureText += '"' + UnitOfMeasure.Description + '",'; + until UnitOfMeasure.Next() = 0; + UnitsOfMeasureText := UnitsOfMeasureText.TrimEnd(','); + end; + + PromptJson.ReadFrom(StrSubstNo(Prompt.GetSLSSearchItemsWithFiltersPrompt(), UnitsOfMeasureText)); + exit(PromptJson); + end; + + [NonDebuggable] + procedure Execute(Arguments: JsonObject): Variant + var + TempSalesLineAiSuggestionFromDocLookup: Record "Sales Line AI Suggestions" temporary; + TempSalesLineAiSuggestionFromItemSearch: Record "Sales Line AI Suggestions" temporary; + TempSalesLineAiSuggestionFiltered: Record "Sales Line AI Suggestions" temporary; + Item: Record Item; + SalesLineAISuggestionImpl: Codeunit "Sales Lines Suggestions Impl."; + FeatureTelemetry: Codeunit "Feature Telemetry"; + NotificationManager: Codeunit "Notification Manager"; + SearchUtility: Codeunit "Search"; + SelectionFilterManagement: Codeunit SelectionFilterManagement; + FeatureTelemetryCD: Dictionary of [Text, Text]; + DocLookupType: Enum "Document Lookup Types"; + DocumentLookupSubType: Interface DocumentLookupSubType; + ItemsResults: JsonToken; + ItemResultsArray: JsonArray; + DocumentNo: Text; + StartDateTxt: Text; + EndDateTxt: Text; + ItemNoFilter: Text; + SearchIntentLbl: Label 'Add products to a sales order.', Locked = true; + begin + if Arguments.Get('results', ItemsResults) then begin + ItemResultsArray := ItemsResults.AsArray(); + + // Find document information from user input + if GetDocumentFromUserInput(DocumentNo, StartDateTxt, EndDateTxt, DocLookupType, ItemResultsArray) then begin + DocumentLookupSubType := DocLookupType; + FeatureTelemetryCD.Add('Document Type', DocLookupType.Names().Get(DocLookupType.Ordinals.IndexOf(DocLookupType.AsInteger()))); + + // Search for the sales document in the system + if SearchSalesDocument(TempSalesLineAiSuggestionFromDocLookup, DocumentLookupSubType, Format(SourceDocumentRecordId), DocumentNo, StartDateTxt, EndDateTxt) then begin + FeatureTelemetry.LogUsage('0000N3I', SalesLineAISuggestionImpl.GetFeatureName(), SearchWithFiltersLbl, FeatureTelemetryCD); + if TempSalesLineAiSuggestionFromDocLookup.IsEmpty() then + NotificationManager.SendNotification(SalesLineAISuggestionImpl.GetNoSalesLinesSuggestionsMsg()); + end + else begin + FeatureTelemetry.LogError('0000N3F', SalesLineAISuggestionImpl.GetFeatureName(), SearchWithFiltersLbl, 'Document lookup resulted in an error', GetLastErrorCallStack(), FeatureTelemetryCD); + NotificationManager.SendNotification(GetLastErrorText()); + exit(TempSalesLineAiSuggestionFromDocLookup); + end; + end; + end; + + // Item search + if Arguments.Get('search_items', ItemsResults) then begin + FeatureTelemetry.LogUsage('0000N3J', SalesLineAISuggestionImpl.GetFeatureName(), SearchWithFiltersLbl + ': Item Search'); + + ItemResultsArray := ItemsResults.AsArray(); + + // If document lookup returned results, filter items based on the document + if TempSalesLineAiSuggestionFromDocLookup.FindSet() then begin + repeat + if Item.Get(TempSalesLineAiSuggestionFromDocLookup."No.") then + Item.Mark(true); + until TempSalesLineAiSuggestionFromDocLookup.Next() = 0; + Item.MarkedOnly(true); + ItemNoFilter := SelectionFilterManagement.GetSelectionFilterForItem(Item); + end; + + if SearchUtility.SearchMultiple(ItemResultsArray, SearchStyle, SearchIntentLbl, SearchQuery, 1, 25, false, true, TempSalesLineAiSuggestionFromItemSearch, ItemNoFilter) then begin + if TempSalesLineAiSuggestionFromItemSearch.IsEmpty() then begin + FeatureTelemetry.LogError('0000N3G', SalesLineAISuggestionImpl.GetFeatureName(), SearchWithFiltersLbl, 'Item search returned no items.'); + NotificationManager.SendNotification(SalesLineAISuggestionImpl.GetNoSalesLinesSuggestionsMsg()); + exit(TempSalesLineAiSuggestionFromDocLookup); + end; + + // If document lookup did not return any results, return the items from the item search + if TempSalesLineAiSuggestionFromDocLookup.IsEmpty() then + exit(TempSalesLineAiSuggestionFromItemSearch); + + // If document lookup returned results, find intersection of items from document and item search + TempSalesLineAiSuggestionFromItemSearch.FindSet(); + repeat + TempSalesLineAiSuggestionFromDocLookup.SetRange("No.", TempSalesLineAiSuggestionFromItemSearch."No."); + if TempSalesLineAiSuggestionFromDocLookup.FindSet() then + repeat + TempSalesLineAiSuggestionFiltered.Init(); + TempSalesLineAiSuggestionFiltered.Copy(TempSalesLineAiSuggestionFromDocLookup); + TempSalesLineAiSuggestionFiltered.Quantity := TempSalesLineAiSuggestionFromDocLookup.Quantity; + TempSalesLineAiSuggestionFiltered.Insert(); + until TempSalesLineAiSuggestionFromDocLookup.Next() = 0; + until TempSalesLineAiSuggestionFromItemSearch.Next() = 0; + TempSalesLineAiSuggestionFiltered.Reset(); + FeatureTelemetry.LogUsage('0000N3K', SalesLineAISuggestionImpl.GetFeatureName(), SearchWithFiltersLbl + ': Item Search inside document returned items.'); + exit(TempSalesLineAiSuggestionFiltered); + end + else begin + FeatureTelemetry.LogError('0000N3H', SalesLineAISuggestionImpl.GetFeatureName(), SearchWithFiltersLbl, 'Item search failed.'); + NotificationManager.SendNotification(SalesLineAISuggestionImpl.GetChatCompletionResponseErr()); + end; + end; + + exit(TempSalesLineAiSuggestionFromDocLookup); + end; + + procedure GetName(): Text + begin + exit(FunctionNameLbl); + end; + + procedure SetSearchQuery(NewSearchQuery: Text) + begin + SearchQuery := NewSearchQuery; + end; + + procedure SetSearchStyle(NewSearchStyle: Enum "Search Style") + begin + SearchStyle := NewSearchStyle; + end; + + procedure SetSourceDocumentRecordId(NewSourceDocumentRecordId: RecordId) + begin + SourceDocumentRecordId := NewSourceDocumentRecordId; + end; + + [TryFunction] + local procedure SearchSalesDocument(var TempSalesLineAiSuggestion: Record "Sales Line AI Suggestions" temporary; var DocumentLookupSubType: Interface DocumentLookupSubType; SourceDocumentRecordIdText: Text; DocumentNo: Text; StartDateTxt: Text; EndDateTxt: Text) + begin + DocumentLookupSubType.SearchSalesDocument(AddParametersToCustomDimension(SourceDocumentRecordIdText, DocumentNo, StartDateTxt, EndDateTxt), TempSalesLineAiSuggestion); + end; + + local procedure AddParametersToCustomDimension(SourceDocumentRecordIdText: Text; DocumentNo: Text; StartDateStr: Text; EndDateStr: Text): Dictionary of [Text, Text] + var + CustomDimension: Dictionary of [Text, Text]; + begin + CustomDimension.Add(SourceDocumentRecordIDLbl, SourceDocumentRecordIdText); + CustomDimension.Add('DocumentNo', DocumentNo); + CustomDimension.Add('StartDateStr', StartDateStr); + CustomDimension.Add('EndDateStr', EndDateStr); + exit(CustomDimension); + end; + + internal procedure GetParametersFromCustomDimension(CustomDimension: Dictionary of [Text, Text]; var SourceSalesHeader: Record "Sales Header"; var DocumentNo: Text; var StartDateStr: Text; var EndDateStr: Text) + var + SourceSalesHeaderRecId: RecordId; + SourceDocumentRecIdTxt: Text; + begin + SourceDocumentRecIdTxt := CustomDimension.Get(SourceDocumentRecordIDLbl); + if SourceDocumentRecIdTxt <> '' then begin + SourceSalesHeader.SetLoadFields("No.", "Sell-to Customer No.", "Sell-to Customer Name"); + Evaluate(SourceSalesHeaderRecId, SourceDocumentRecIdTxt); + if SourceSalesHeaderRecId.TableNo = Database::"Sales Header" then begin + SourceSalesHeaderRecId.GetRecord().SetTable(SourceSalesHeader); + SourceSalesHeader.Get(SourceSalesHeader."Document Type", SourceSalesHeader."No."); + end; + end; + DocumentNo := CustomDimension.Get('DocumentNo'); + StartDateStr := CustomDimension.Get('StartDateStr'); + EndDateStr := CustomDimension.Get('EndDateStr'); + end; + + [TryFunction] + local procedure GetDocumentFromUserInput(var DocumentNo: Text; var StartDate: Text; var EndDate: Text; var DocLookupSubType: Enum "Document Lookup Types"; ItemResultsArray: JsonArray) + var + JsonItem: JsonToken; + DocumentNoToken: JsonToken; + DocumentTypeToken: JsonToken; + UnknownDocTypeErr: Label 'Copilot does not support the specified document type. Please rephrase the description'; + NoDocumentFoundErr: Label 'Copilot could not find the document. Please rephrase the description'; + begin + if ItemResultsArray.Get(0, JsonItem) then + if JsonItem.AsObject().Get('document_type', DocumentTypeToken) then begin + case DocumentTypeToken.AsValue().AsText() of + 'sales_order': + DocLookupSubType := DocLookupSubType::"Sales Order"; + 'sales_invoice': + DocLookupSubType := DocLookupSubType::"Posted Sales Invoice"; + 'sales_shipment': + DocLookupSubType := DocLookupSubType::"Posted Sales Shipment"; + 'sales_quote': + DocLookupSubType := DocLookupSubType::"Sales Quote"; + 'sales_blanket_order': + DocLookupSubType := DocLookupSubType::"Blanket Sales Order"; + else + Error(UnknownDocTypeErr); + end; + + if JsonItem.AsObject().Get('document_number', DocumentNoToken) then + DocumentNo := DocumentNoToken.AsValue().AsText(); + + if JsonItem.AsObject().Get('start_date', DocumentTypeToken) then + StartDate := DocumentTypeToken.AsValue().AsText(); + + if JsonItem.AsObject().Get('end_date', DocumentTypeToken) then + EndDate := DocumentTypeToken.AsValue().AsText(); + end else + Error(NoDocumentFoundErr); + end; +} \ No newline at end of file diff --git a/Apps/W1/SalesLinesSuggestions/app/SalesLineAISuggestions.Page.al b/Apps/W1/SalesLinesSuggestions/app/SalesLineAISuggestions.Page.al index 3af7c45591..15c209d193 100644 --- a/Apps/W1/SalesLinesSuggestions/app/SalesLineAISuggestions.Page.al +++ b/Apps/W1/SalesLinesSuggestions/app/SalesLineAISuggestions.Page.al @@ -141,11 +141,11 @@ page 7275 "Sales Line AI Suggestions" #pragma warning restore AW0005 Caption = 'Copy from order [No.]'; - ToolTip = 'Sample prompt for copying line items from another sales document. Text in brackets specifies the document no.'; + ToolTip = 'Sample prompt for copying line items from another sales order. Text in brackets refers to the order.'; trigger OnAction() var - CopyFromLbl: Label 'Copy from order '; + CopyFromLbl: Label 'Copy from sales order '; begin SearchQueryTxt := CopyFromLbl; CurrPage.Update(false); @@ -156,12 +156,12 @@ page 7275 "Sales Line AI Suggestions" { #pragma warning restore AW0005 - Caption = 'Copy from invoice [No.]'; - ToolTip = 'Sample prompt for copying line items from another sales document. Text in brackets specifies the document no.'; + Caption = 'Copy from posted invoice [No.]'; + ToolTip = 'Sample prompt for copying line items from a posted sales invoice. Text in brackets refers to the invoice.'; trigger OnAction() var - CopyFromLbl: Label 'Copy from invoice '; + CopyFromLbl: Label 'Copy from sales invoice '; begin SearchQueryTxt := CopyFromLbl; CurrPage.Update(false); @@ -171,12 +171,27 @@ page 7275 "Sales Line AI Suggestions" action(DocumentSearchCopyFromLastInvoicePrompt) { #pragma warning restore AW0005 - Caption = 'Copy from the last invoice'; + Caption = 'Copy from the last posted invoice'; ToolTip = 'Sample prompt for copying line items from the customer''s latest posted sales invoice.'; trigger OnAction() var - CopyFromLbl: Label 'Copy from the last invoice'; + CopyFromLbl: Label 'Copy from the last sales invoice'; + begin + SearchQueryTxt := CopyFromLbl; + CurrPage.Update(false); + end; + } +#pragma warning disable AW0005 + action(CopyItemsFromDocumentPrompt) +#pragma warning restore AW0005 + { + Caption = 'Copy items [description] from posted invoice [No.]'; + ToolTip = 'Sample prompt for copying specific items from another posted sales invoice. Texts in brackets specify item description and invoice number.'; + + trigger OnAction() + var + CopyFromLbl: Label 'Copy specific items from sales invoice '; begin SearchQueryTxt := CopyFromLbl; CurrPage.Update(false); diff --git a/Apps/W1/SalesLinesSuggestions/app/SalesLineAISuggestions.Table.al b/Apps/W1/SalesLinesSuggestions/app/SalesLineAISuggestions.Table.al index 75f257ba82..cad8a6533f 100644 --- a/Apps/W1/SalesLinesSuggestions/app/SalesLineAISuggestions.Table.al +++ b/Apps/W1/SalesLinesSuggestions/app/SalesLineAISuggestions.Table.al @@ -12,6 +12,7 @@ table 7275 "Sales Line AI Suggestions" TableType = Temporary; InherentEntitlements = X; InherentPermissions = RIMDX; + Caption = 'Sales Line AI Suggestion'; Access = Internal; fields @@ -63,6 +64,13 @@ table 7275 "Sales Line AI Suggestions" { Caption = 'Source Line Record ID'; } + field(5407; "Unit of Measure Code"; Code[10]) + { + Caption = 'Unit of Measure Code'; + ToolTip = 'Specifies the unit of measure code of the item on the line.'; + TableRelation = "Item Unit of Measure".Code where("Item No." = field("No.")); + ValidateTableRelation = false; + } } keys diff --git a/Apps/W1/SalesLinesSuggestions/app/SalesLineAISuggestionsSub.Page.al b/Apps/W1/SalesLinesSuggestions/app/SalesLineAISuggestionsSub.Page.al index 2fa2aefc8e..ed9165dfda 100644 --- a/Apps/W1/SalesLinesSuggestions/app/SalesLineAISuggestionsSub.Page.al +++ b/Apps/W1/SalesLinesSuggestions/app/SalesLineAISuggestionsSub.Page.al @@ -61,6 +61,10 @@ page 7276 "Sales Line AI Suggestions Sub" { ToolTip = 'Specifies the quantity of the suggested result.'; } + field("Unit of Measure Code"; Rec."Unit of Measure Code") + { + ToolTip = 'Specifies the unit of measure code of the suggested result.'; + } field(Confidence; Rec.Confidence) { StyleExpr = StyleExprText; diff --git a/Apps/W1/SalesLinesSuggestions/app/SalesLinesSuggestionsImpl.Codeunit.al b/Apps/W1/SalesLinesSuggestions/app/SalesLinesSuggestionsImpl.Codeunit.al index 9563c6e742..2da6b0d708 100644 --- a/Apps/W1/SalesLinesSuggestions/app/SalesLinesSuggestionsImpl.Codeunit.al +++ b/Apps/W1/SalesLinesSuggestions/app/SalesLinesSuggestionsImpl.Codeunit.al @@ -97,8 +97,7 @@ codeunit 7275 "Sales Lines Suggestions Impl." AOAIFunctionResponse: Codeunit "AOAI Function Response"; AOAIChatCompletionParams: Codeunit "AOAI Chat Completion Params"; AOAIChatMessages: Codeunit "AOAI Chat Messages"; - DocumentLookup: Codeunit "Document Lookup Function"; - SearchItemsFunction: Codeunit "Search Items Function"; + SearchItemsWithFiltersFunc: Codeunit "Search Items With Filters Func"; MagicFunction: Codeunit "Magic Function"; FeatureTelemetry: Codeunit "Feature Telemetry"; NotificationManager: Codeunit "Notification Manager"; @@ -119,15 +118,12 @@ codeunit 7275 "Sales Lines Suggestions Impl." AOAIChatCompletionParams.SetMaxTokens(MaxTokens()); AOAIChatCompletionParams.SetTemperature(0); - SearchItemsFunction.SetSearchQuery(SearchQuery); - SearchItemsFunction.SetSearchStyle(SearchStyle); - DocumentLookup.SetSearchQuery(SearchQuery); - DocumentLookup.SetSourceDocumentRecordId(SourceSalesHeader.RecordId); - DocumentLookup.SetSearchStyle(SearchStyle); + SearchItemsWithFiltersFunc.SetSearchQuery(SearchQuery); + SearchItemsWithFiltersFunc.SetSourceDocumentRecordId(SourceSalesHeader.RecordId); + SearchItemsWithFiltersFunc.SetSearchStyle(SearchStyle); AOAIChatMessages.AddTool(MagicFunction); - AOAIChatMessages.AddTool(SearchItemsFunction); - AOAIChatMessages.AddTool(DocumentLookup); + AOAIChatMessages.AddTool(SearchItemsWithFiltersFunc); AOAIChatMessages.SetToolChoice('auto'); AOAIChatMessages.SetPrimarySystemMessage(SystemPromptTxt); diff --git a/Apps/W1/SalesLinesSuggestions/app/Search/Search.Codeunit.al b/Apps/W1/SalesLinesSuggestions/app/Search/Search.Codeunit.al index da76030915..40632f761a 100644 --- a/Apps/W1/SalesLinesSuggestions/app/Search/Search.Codeunit.al +++ b/Apps/W1/SalesLinesSuggestions/app/Search/Search.Codeunit.al @@ -6,6 +6,7 @@ namespace Microsoft.Sales.Document; using System; using System.Telemetry; +using Microsoft.Foundation.UOM; using Microsoft.Inventory.Item; using System.AI; using System.Security.Encryption; @@ -34,10 +35,12 @@ codeunit 7282 "Search" SearchProgress: Dialog; ItemToken: JsonToken; QuantityToken: JsonToken; + UOMToken: JsonToken; NameJsonToken: JsonToken; SearchPrimaryKeyWords: List of [Text]; SearchAdditionalKeyWords: List of [Text]; Quantity: Decimal; + UnitOfMeasure: Text; TelemetryCD: Dictionary of [Text, Text]; StartDateTime: DateTime; DurationAsBigInt: BigInteger; @@ -115,10 +118,17 @@ codeunit 7282 "Search" //Process Search Results foreach ItemToken in ItemResultsArray do begin + Quantity := 0; + UnitOfMeasure := ''; + ItemToken.WriteTo(ItemTokentText); if ItemToken.AsObject().Get('quantity', QuantityToken) then if (QuantityToken.IsValue() and (QuantityToken.AsValue().AsText() <> '')) then - Quantity := QuantityToken.AsValue().AsDecimal(); + if not JsonValueAsDecimal(QuantityToken.AsValue(), Quantity) then + Quantity := 0; + if ItemToken.AsObject().Get('unit_of_measure', UOMToken) then + if (UOMToken.IsValue() and (UOMToken.AsValue().AsText() <> '')) then + UnitOfMeasure := UOMToken.AsValue().AsText(); QueryResults := ALSearchResult.GetResultsForQuery(CryptographyManagement.GenerateHash(ItemTokentText, HashAlgorithmType::SHA256)); @@ -132,7 +142,7 @@ codeunit 7282 "Search" SearchPrimaryKeyWords := GetItemNameKeywords(ItemToken); SearchAdditionalKeyWords := GetItemFeaturesKeywords(ItemToken); - GetSalesLineFromItemSystemIds(TempSearchResponse, Quantity, TempSalesLineAiSuggestion, SearchPrimaryKeyWords, SearchAdditionalKeyWords); + GetSalesLineFromItemSystemIds(TempSearchResponse, Quantity, UnitOfMeasure, TempSalesLineAiSuggestion, SearchPrimaryKeyWords, SearchAdditionalKeyWords); end; end; end; @@ -166,10 +176,13 @@ codeunit 7282 "Search" ALSearchQuery.Top := Top; end; - local procedure GetSalesLineFromItemSystemIds(var TempSearchResponse: Record "Search API Response" temporary; Quantity: Decimal; var TempSalesLineAiSuggestion: Record "Sales Line AI Suggestions" temporary; var SearchPrimaryKeyWords: List of [Text]; + local procedure GetSalesLineFromItemSystemIds(var TempSearchResponse: Record "Search API Response" temporary; Quantity: Decimal; UnitOfMeasureText: Text; var TempSalesLineAiSuggestion: Record "Sales Line AI Suggestions" temporary; var SearchPrimaryKeyWords: List of [Text]; var SearchAdditionalKeyWords: List of [Text]) var Item: Record "Item"; + UnitOfMeasure: Record "Unit of Measure"; + ItemUnitOfMeasure: Record "Item Unit of Measure"; + UnitOfMeasureCode: Code[10]; LineNumber: Integer; begin @@ -184,6 +197,17 @@ codeunit 7282 "Search" if Item.GetBySystemId(TempSearchResponse.SysId) then begin Item.SetRecFilter(); + UnitOfMeasureCode := Item."Sales Unit of Measure"; + if UnitOfMeasureCode = '' then + UnitOfMeasureCode := Item."Base Unit of Measure"; + UnitOfMeasure.SetRange(Description, UnitOfMeasureText); + if UnitOfMeasure.FindFirst() then begin + ItemUnitOfMeasure.SetRange("Item No.", Item."No."); + ItemUnitOfMeasure.SetRange(Code, UnitOfMeasure.Code); + if ItemUnitOfMeasure.FindFirst() then + UnitOfMeasureCode := ItemUnitOfMeasure.Code; + end; + TempSalesLineAiSuggestion.Init(); LineNumber := LineNumber + 1; TempSalesLineAiSuggestion."Line No." := LineNumber; @@ -191,6 +215,7 @@ codeunit 7282 "Search" TempSalesLineAiSuggestion.Description := Item.Description; TempSalesLineAiSuggestion.Type := "Sales Line Type"::Item; TempSalesLineAiSuggestion.Quantity := Quantity; + TempSalesLineAiSuggestion."Unit of Measure Code" := UnitOfMeasureCode; TempSalesLineAiSuggestion.Confidence := GetConfidence(TempSearchResponse.Score); TempSalesLineAiSuggestion.SetPrimarySearchTerms(SearchPrimaryKeyWords); TempSalesLineAiSuggestion.SetAdditionalSearchTerms(SearchAdditionalKeyWords); @@ -206,9 +231,14 @@ codeunit 7282 "Search" SearchKeywords: List of [Text]; SearchKeyword: Text; begin - if ItemObjectToken.AsObject().Get('name', JsonToken) then begin - SearchKeyword := JsonToken.AsValue().AsText(); - if ItemObjectToken.AsObject().Get('synonyms', JsonToken) then begin + if ItemObjectToken.AsObject().Get('split_name_terms', JsonToken) then begin + JsonArray := JsonToken.AsArray(); + foreach JsonToken in JsonArray do + if SearchKeyword = '' then + SearchKeyword := JsonToken.AsValue().AsText() + else + SearchKeyword := SearchKeyword + '|' + JsonToken.AsValue().AsText(); + if ItemObjectToken.AsObject().Get('common_synonyms_of_name', JsonToken) then begin JsonArray := JsonToken.AsArray(); foreach JsonToken in JsonArray do SearchKeyword := SearchKeyword + '|' + JsonToken.AsValue().AsText(); @@ -245,4 +275,10 @@ codeunit 7282 "Search" exit("Search Confidence"::None); end; + + [TryFunction] + local procedure JsonValueAsDecimal(JsonValue: JsonValue; var Value: Decimal) + begin + Value := JsonValue.AsDecimal(); + end; } \ No newline at end of file diff --git a/Apps/W1/SalesLinesSuggestions/app/Search/SearchAPIResponse.Table.al b/Apps/W1/SalesLinesSuggestions/app/Search/SearchAPIResponse.Table.al index 0bf2464a02..67835885da 100644 --- a/Apps/W1/SalesLinesSuggestions/app/Search/SearchAPIResponse.Table.al +++ b/Apps/W1/SalesLinesSuggestions/app/Search/SearchAPIResponse.Table.al @@ -10,6 +10,7 @@ table 7276 "Search API Response" TableType = Temporary; InherentEntitlements = X; InherentPermissions = X; + Caption = 'Search API Response'; fields { diff --git a/Apps/W1/SalesLinesSuggestions/app/Search/SearchConfidence.Enum.al b/Apps/W1/SalesLinesSuggestions/app/Search/SearchConfidence.Enum.al index ec1ae8109b..a1d14bae95 100644 --- a/Apps/W1/SalesLinesSuggestions/app/Search/SearchConfidence.Enum.al +++ b/Apps/W1/SalesLinesSuggestions/app/Search/SearchConfidence.Enum.al @@ -11,14 +11,18 @@ enum 7276 "Search Confidence" value(0; "None") { + Caption = 'None'; } value(1; "Low") { + Caption = 'Low'; } value(2; "Medium") { + Caption = 'Medium'; } value(3; "High") { + Caption = 'High'; } } \ No newline at end of file diff --git a/Apps/W1/SalesLinesSuggestions/app/Utilities/SalesLineUtility.Codeunit.al b/Apps/W1/SalesLinesSuggestions/app/Utilities/SalesLineUtility.Codeunit.al index 205c8204d0..d96d8420f9 100644 --- a/Apps/W1/SalesLinesSuggestions/app/Utilities/SalesLineUtility.Codeunit.al +++ b/Apps/W1/SalesLinesSuggestions/app/Utilities/SalesLineUtility.Codeunit.al @@ -16,6 +16,7 @@ codeunit 7280 "Sales Line Utility" ProcessingLinesLbl: Label 'Processing lines... \#1#########################################################################################', Comment = '#1 = PreparingSalesLineLbl or InsertingSalesLineLbl '; PreparingSalesLineLbl: Label 'Preparing %1 of %2', Comment = '%1 = Counter, %2 = Total Lines'; InsertingSalesLineLbl: Label 'Inserting %1 of %2', Comment = '%1 = Counter, %2 = Total Lines'; + CopyingFromBlanketOrderLbl: Label 'Copying from Blanket Order...'; SalesLineValidationErr: Label 'There was an error while validating the line with No. %1, Description %2.\Error: %3', Comment = '%1 = No., %2 = Description, %3 = Error Message'; SalesLineCopyErr: Label 'There was an error while copying the line with No. %1, Description %2, Quantity %3.', Comment = '%1 = No., %2 = Description, %3 = Quantity'; @@ -35,8 +36,12 @@ codeunit 7280 "Sales Line Utility" NextLineNo := 0; LinesNotCopied := 0; - PrepareSalesLine(SalesHeader, TempFromSalesLine, TempSalesLineAiSuggestion, NextLineNo); - CopySalesLineToDoc(SalesHeader, TempFromSalesLine, LinesNotCopied, NextLineNo); + if IsBlanketOrder(TempSalesLineAiSuggestion) then + CreateFromBlanketOrder(SalesHeader, TempSalesLineAiSuggestion, NextLineNo) + else begin + PrepareSalesLine(SalesHeader, TempFromSalesLine, TempSalesLineAiSuggestion, NextLineNo); + CopySalesLineToDoc(SalesHeader, TempFromSalesLine, LinesNotCopied, NextLineNo); + end; end; local procedure CopySalesLineToDoc(var ToSalesHeader: Record "Sales Header"; var FromSalesLine: Record "Sales Line" temporary; var LinesNotCopied: Integer; NextLineNo: Integer) @@ -73,6 +78,52 @@ codeunit 7280 "Sales Line Utility" end; end; + local procedure IsBlanketOrder(var TempSalesLineAiSuggestion: Record "Sales Line AI Suggestions" temporary): Boolean + var + SalesLine: Record "Sales Line"; + begin + if not TempSalesLineAiSuggestion.FindFirst() then + exit(false); + + if TempSalesLineAiSuggestion."Source Line Record ID".TableNo = Database::"Sales Line" then + TempSalesLineAiSuggestion."Source Line Record ID".GetRecord().SetTable(SalesLine); + + exit(SalesLine."Document Type" = SalesLine."Document Type"::"Blanket Order"); + end; + + local procedure CreateFromBlanketOrder(var ToSalesHeader: Record "Sales Header"; var TempSalesLineAiSuggestion: Record "Sales Line AI Suggestions" temporary; NextLineNo: Integer) + var + BlanketSalesHeader: Record "Sales Header"; + BlanketSalesLine: Record "Sales Line"; + FromSalesLine: Record "Sales Line"; + ToSalesLine: Record "Sales Line"; + BlanketSalesOrderToOrder: Codeunit "Blanket Sales Order to Order"; + ProgressDialog: Dialog; + begin + if TempSalesLineAiSuggestion.FindSet() then begin + OpenProgressWindow(ProgressDialog); + ProgressDialog.Update(1, CopyingFromBlanketOrderLbl); + + TempSalesLineAiSuggestion."Source Line Record ID".GetRecord().SetTable(BlanketSalesLine); + BlanketSalesHeader.Get(BlanketSalesLine."Document Type", BlanketSalesLine."Document No."); + + repeat + FromSalesLine.Get(TempSalesLineAiSuggestion."Source Line Record ID"); + FromSalesLine.Validate("Qty. to Ship", TempSalesLineAiSuggestion.Quantity); + FromSalesLine.Modify(true); + FromSalesLine.Mark(true); + until TempSalesLineAiSuggestion.Next() = 0; + + FromSalesLine.MarkedOnly(true); + + BlanketSalesOrderToOrder.SetHideValidationDialog(true); + BlanketSalesOrderToOrder.SetSalesOrderHeader(ToSalesHeader); + BlanketSalesOrderToOrder.CreateSalesOrderLines(BlanketSalesHeader, FromSalesLine, ToSalesHeader, ToSalesLine, NextLineNo); + + ProgressDialog.Close(); + end; + end; + local procedure PrepareSalesLine(SalesHeader: Record "Sales Header"; var TempSalesLine: Record "Sales Line" temporary; var TempSalesLineAiSuggestion: Record "Sales Line AI Suggestions" temporary; LineNo: Integer) var TempPreparedSalesLine: Record "Sales Line" temporary; diff --git a/Apps/W1/SalesLinesSuggestions/app/app.json b/Apps/W1/SalesLinesSuggestions/app/app.json index 815940a75c..2e447d6c4f 100644 --- a/Apps/W1/SalesLinesSuggestions/app/app.json +++ b/Apps/W1/SalesLinesSuggestions/app/app.json @@ -19,7 +19,7 @@ "idRanges": [ { "from": 7275, - "to": 7290 + "to": 7291 } ], "resourceExposurePolicy": { diff --git a/Apps/W1/Shopify/app/src/Base/Pages/ShpfyShopCard.Page.al b/Apps/W1/Shopify/app/src/Base/Pages/ShpfyShopCard.Page.al index 2db501be67..18fa93e076 100644 --- a/Apps/W1/Shopify/app/src/Base/Pages/ShpfyShopCard.Page.al +++ b/Apps/W1/Shopify/app/src/Base/Pages/ShpfyShopCard.Page.al @@ -517,13 +517,6 @@ page 30101 "Shpfy Shop Card" end; } #endif - field(KeepZeroQuantityLines; Rec."Keep Zero Quantity Lines") - { - ApplicationArea = All; - Caption = 'Keep Zero Quantity Lines'; - ToolTip = 'Specifies whether to keep zero quantity lines in the Shopify order. If you do not select this option, zero quantity lines are removed from the Shopify order.'; - Visible = false; - } } group(ReturnsAndRefunds) { diff --git a/Apps/W1/Shopify/app/src/Base/Tables/ShpfyShop.Table.al b/Apps/W1/Shopify/app/src/Base/Tables/ShpfyShop.Table.al index 0cbe7684bf..d521572415 100644 --- a/Apps/W1/Shopify/app/src/Base/Tables/ShpfyShop.Table.al +++ b/Apps/W1/Shopify/app/src/Base/Tables/ShpfyShop.Table.al @@ -778,12 +778,6 @@ table 30102 "Shpfy Shop" end; #endif } - field(128; "Keep Zero Quantity Lines"; Boolean) - { - Caption = 'Keep Zero Quantity Lines'; - DataClassification = SystemMetadata; - InitValue = false; - } field(200; "Shop Id"; Integer) { DataClassification = SystemMetadata; diff --git a/Apps/W1/Shopify/app/src/Companies/Codeunits/ShpfyCompanyAPI.Codeunit.al b/Apps/W1/Shopify/app/src/Companies/Codeunits/ShpfyCompanyAPI.Codeunit.al index 7b440f4430..3e7c83de19 100644 --- a/Apps/W1/Shopify/app/src/Companies/Codeunits/ShpfyCompanyAPI.Codeunit.al +++ b/Apps/W1/Shopify/app/src/Companies/Codeunits/ShpfyCompanyAPI.Codeunit.al @@ -341,6 +341,7 @@ codeunit 30286 "Shpfy Company API" PhoneNo := JsonHelper.GetValueAsText(JItem, 'node.billingAddress.phone'); PhoneNo := CopyStr(DelChr(PhoneNo, '=', DelChr(PhoneNo, '=', '1234567890/+ .()')), 1, MaxStrLen(CompanyLocation."Phone No.")); CompanyLocation."Phone No." := CopyStr(PhoneNo, 1, MaxStrLen(CompanyLocation."Phone No.")); + CompanyLocation."Tax Registration Id" := CopyStr(JsonHelper.GetValueAsText(JItem, 'node.taxRegistrationId', MaxStrLen(CompanyLocation."Tax Registration Id")), 1, MaxStrLen(CompanyLocation."Tax Registration Id")); CompanyLocation.Modify(); end; end; diff --git a/Apps/W1/Shopify/app/src/Companies/Pages/ShpfyCompanyCard.Page.al b/Apps/W1/Shopify/app/src/Companies/Pages/ShpfyCompanyCard.Page.al index 92c2668c82..8980b7073f 100644 --- a/Apps/W1/Shopify/app/src/Companies/Pages/ShpfyCompanyCard.Page.al +++ b/Apps/W1/Shopify/app/src/Companies/Pages/ShpfyCompanyCard.Page.al @@ -39,6 +39,13 @@ page 30157 "Shpfy Company Card" Caption = 'Note'; ToolTip = 'Specifies a note about the customer in Shopify.'; } + field(TaxId; TaxRegistrationId) + { + ApplicationArea = All; + Caption = 'Tax Id'; + ToolTip = 'Specifies the company''s tax ID.'; + Editable = false; + } } group(Mapping) @@ -163,15 +170,14 @@ page 30157 "Shpfy Company Card" var Customer: Record Customer; CustomerNo: Code[20]; + TaxRegistrationId: Text[150]; trigger OnAfterGetCurrRecord() begin GetMappedCustomer(); + GetTaxRegisrationId(); end; - /// - /// Get Mapped Customer. - /// local procedure GetMappedCustomer() begin if IsNullGuid(Rec."Customer SystemId") then begin @@ -185,4 +191,12 @@ page 30157 "Shpfy Company Card" Clear(CustomerNo); end; end; + + local procedure GetTaxRegisrationId() + var + CompanyLocation: Record "Shpfy Company Location"; + begin + if CompanyLocation.Get(Rec."Location Id") then + TaxRegistrationId := CompanyLocation."Tax Registration Id"; + end; } diff --git a/Apps/W1/Shopify/app/src/Companies/Tables/ShpfyCompanyLocation.Table.al b/Apps/W1/Shopify/app/src/Companies/Tables/ShpfyCompanyLocation.Table.al index d73ca0e433..f94a8a2f33 100644 --- a/Apps/W1/Shopify/app/src/Companies/Tables/ShpfyCompanyLocation.Table.al +++ b/Apps/W1/Shopify/app/src/Companies/Tables/ShpfyCompanyLocation.Table.al @@ -68,6 +68,11 @@ table 30151 "Shpfy Company Location" Caption = 'Province Name'; DataClassification = CustomerContent; } + field(12; "Tax Registration Id"; Text[150]) + { + Caption = 'Tax Registration Id'; + DataClassification = CustomerContent; + } } keys { diff --git a/Apps/W1/Shopify/app/src/GraphQL/Codeunits/ShpfyGQLCompany.Codeunit.al b/Apps/W1/Shopify/app/src/GraphQL/Codeunits/ShpfyGQLCompany.Codeunit.al index 1e836f24f7..e6a5806e2a 100644 --- a/Apps/W1/Shopify/app/src/GraphQL/Codeunits/ShpfyGQLCompany.Codeunit.al +++ b/Apps/W1/Shopify/app/src/GraphQL/Codeunits/ShpfyGQLCompany.Codeunit.al @@ -13,7 +13,7 @@ codeunit 30302 "Shpfy GQL Company" implements "Shpfy IGraphQL" /// Return value of type Text. internal procedure GetGraphQL(): Text begin - exit('{"query":"{company(id: \"gid://shopify/Company/{{CompanyId}}\") {name id note createdAt updatedAt mainContact { id customer { id firstName lastName email phone}} locations(first:1, sortKey: CREATED_AT ) {edges { node { id name billingAddress {address1 address2 city countryCode phone province zip zoneCode}}}}}}"}'); + exit('{"query":"{company(id: \"gid://shopify/Company/{{CompanyId}}\") {name id note createdAt updatedAt mainContact { id customer { id firstName lastName email phone}} locations(first:1, sortKey: CREATED_AT ) {edges { node { id name billingAddress {address1 address2 city countryCode phone province zip zoneCode} taxRegistrationId}}}}}"}'); end; /// diff --git a/Apps/W1/Shopify/app/src/GraphQL/Codeunits/ShpfyGQLOrderHeader.Codeunit.al b/Apps/W1/Shopify/app/src/GraphQL/Codeunits/ShpfyGQLOrderHeader.Codeunit.al index e6f4ecc4c8..8dca96eea2 100644 --- a/Apps/W1/Shopify/app/src/GraphQL/Codeunits/ShpfyGQLOrderHeader.Codeunit.al +++ b/Apps/W1/Shopify/app/src/GraphQL/Codeunits/ShpfyGQLOrderHeader.Codeunit.al @@ -6,7 +6,7 @@ codeunit 30207 "Shpfy GQL OrderHeader" implements "Shpfy IGraphQL" procedure GetGraphQL(): Text begin - exit('{"query": "query { order(id: \"gid:\/\/shopify\/Order\/{{OrderId}}\") { legacyResourceId name createdAt confirmed updatedAt cancelReason cancelledAt closed closedAt currentSubtotalLineItemsQuantity test email phone poNumber customer { legacyResourceId email phone defaultAddress { id phone }} displayAddress { id firstName lastName company address1 address2 zip city provinceCode province countryCode country phone } shippingAddress { id name firstName lastName company address1 address2 zip city provinceCode province countryCode country phone latitude longitude } billingAddressMatchesShippingAddress billingAddress { id name firstName lastName company address1 address2 zip city provinceCode province countryCode country phone } publication { name } app { name } currencyCode presentmentCurrencyCode fullyPaid unpaid location physicalLocation { legacyResourceId name } note customAttributes { key value } discountCode displayFinancialStatus displayFulfillmentStatus edited totalWeight refundable returnStatus riskLevel risks(first: 10) { level display message } tags paymentGatewayNames processedAt requiresShipping sourceIdentifier paymentTerms { id dueInDays paymentTermsName paymentTermsType translatedName } taxesIncluded cartDiscountAmountSet { presentmentMoney { amount } shopMoney { amount }} currentCartDiscountAmountSet { presentmentMoney { amount } shopMoney { amount }} currentSubtotalPriceSet { presentmentMoney { amount } shopMoney { amount }} currentTotalDiscountsSet { presentmentMoney { amount } shopMoney { amount }} currentTotalDutiesSet { presentmentMoney { amount } shopMoney { amount }} currentTotalPriceSet { presentmentMoney { amount } shopMoney { amount }} currentTotalTaxSet { presentmentMoney { amount } shopMoney { amount }} netPaymentSet { presentmentMoney { amount } shopMoney { amount }} originalTotalDutiesSet { presentmentMoney { amount } shopMoney { amount }} originalTotalPriceSet { presentmentMoney { amount } shopMoney { amount }} refundDiscrepancySet { presentmentMoney { amount } shopMoney { amount }} subtotalPriceSet { presentmentMoney { amount } shopMoney { amount }} totalCapturableSet { presentmentMoney { amount } shopMoney { amount }} totalDiscountsSet { presentmentMoney { amount } shopMoney { amount }} totalOutstandingSet { presentmentMoney { amount } shopMoney { amount }} totalPriceSet { presentmentMoney { amount } shopMoney { amount }} totalReceivedSet { presentmentMoney { amount } shopMoney { amount }} totalRefundedSet { presentmentMoney { amount } shopMoney { amount }} totalRefundedShippingSet { presentmentMoney { amount } shopMoney { amount }} totalShippingPriceSet { presentmentMoney { amount } shopMoney { amount }} totalTaxSet { presentmentMoney { amount } shopMoney { amount }} totalTipReceivedSet { presentmentMoney { amount } shopMoney { amount }} taxLines { channelLiable rate ratePercentage title priceSet { presentmentMoney { amount } shopMoney { amount }}} refunds { legacyResourceId updatedAt } returns(first: 20) { pageInfo { endCursor hasNextPage } nodes { id }} purchasingEntity { ... on PurchasingCompany { company { id name mainContact { id customer { legacyResourceId email phone }}} location { id }}}}}"}'); + exit('{"query": "query { order(id: \"gid:\/\/shopify\/Order\/{{OrderId}}\") { legacyResourceId name createdAt confirmed updatedAt cancelReason cancelledAt closed closedAt currentSubtotalLineItemsQuantity test email phone poNumber customer { legacyResourceId email phone defaultAddress { id phone }} displayAddress { id firstName lastName company address1 address2 zip city provinceCode province countryCode country phone } shippingAddress { id name firstName lastName company address1 address2 zip city provinceCode province countryCode country phone latitude longitude } billingAddressMatchesShippingAddress billingAddress { id name firstName lastName company address1 address2 zip city provinceCode province countryCode country phone } publication { name } app { name } currencyCode presentmentCurrencyCode fullyPaid unpaid note customAttributes { key value } discountCode displayFinancialStatus displayFulfillmentStatus edited totalWeight refundable returnStatus riskLevel risks(first: 10) { level display message } tags paymentGatewayNames processedAt requiresShipping sourceIdentifier paymentTerms { id dueInDays paymentTermsName paymentTermsType translatedName } taxesIncluded cartDiscountAmountSet { presentmentMoney { amount } shopMoney { amount }} currentCartDiscountAmountSet { presentmentMoney { amount } shopMoney { amount }} currentSubtotalPriceSet { presentmentMoney { amount } shopMoney { amount }} currentTotalDiscountsSet { presentmentMoney { amount } shopMoney { amount }} currentTotalDutiesSet { presentmentMoney { amount } shopMoney { amount }} currentTotalPriceSet { presentmentMoney { amount } shopMoney { amount }} currentTotalTaxSet { presentmentMoney { amount } shopMoney { amount }} netPaymentSet { presentmentMoney { amount } shopMoney { amount }} originalTotalDutiesSet { presentmentMoney { amount } shopMoney { amount }} originalTotalPriceSet { presentmentMoney { amount } shopMoney { amount }} refundDiscrepancySet { presentmentMoney { amount } shopMoney { amount }} subtotalPriceSet { presentmentMoney { amount } shopMoney { amount }} totalCapturableSet { presentmentMoney { amount } shopMoney { amount }} totalDiscountsSet { presentmentMoney { amount } shopMoney { amount }} totalOutstandingSet { presentmentMoney { amount } shopMoney { amount }} totalPriceSet { presentmentMoney { amount } shopMoney { amount }} totalReceivedSet { presentmentMoney { amount } shopMoney { amount }} totalRefundedSet { presentmentMoney { amount } shopMoney { amount }} totalRefundedShippingSet { presentmentMoney { amount } shopMoney { amount }} totalShippingPriceSet { presentmentMoney { amount } shopMoney { amount }} totalTaxSet { presentmentMoney { amount } shopMoney { amount }} totalTipReceivedSet { presentmentMoney { amount } shopMoney { amount }} taxLines { channelLiable rate ratePercentage title priceSet { presentmentMoney { amount } shopMoney { amount }}} refunds { legacyResourceId updatedAt } returns(first: 20) { pageInfo { endCursor hasNextPage } nodes { id }} purchasingEntity { ... on PurchasingCompany { company { id name mainContact { id customer { legacyResourceId email phone }}} location { id }}}}}"}'); end; procedure GetExpectedCost(): Integer diff --git a/Apps/W1/Shopify/app/src/Order handling/Codeunits/ShpfyImportOrder.Codeunit.al b/Apps/W1/Shopify/app/src/Order handling/Codeunits/ShpfyImportOrder.Codeunit.al index a92bb50c4e..7fbd4921da 100644 --- a/Apps/W1/Shopify/app/src/Order handling/Codeunits/ShpfyImportOrder.Codeunit.al +++ b/Apps/W1/Shopify/app/src/Order handling/Codeunits/ShpfyImportOrder.Codeunit.al @@ -112,8 +112,7 @@ codeunit 30161 "Shpfy Import Order" OrderFulfillments.GetFulfillments(Shop, OrderHeader."Shopify Order Id"); ConsiderRefundsInQuantityAndAmounts(OrderHeader); - if not Shop."Keep Zero Quantity Lines" then - DeleteZeroQuantityLines(OrderHeader); + DeleteZeroQuantityLines(OrderHeader); if CheckToCloseOrder(OrderHeader) then CloseOrder(OrderHeader); @@ -207,6 +206,7 @@ codeunit 30161 "Shpfy Import Order" OrderHeader."Presentment Subtotal Amount" -= RefundLine."Presentment Subtotal Amount"; OrderHeader."VAT Amount" -= RefundLine."Total Tax Amount"; OrderHeader."Presentment VAT Amount" -= RefundLine."Presentment Total Tax Amount"; + OrderEvents.OnAfterConsiderRefundsInQuantityAndAmounts(OrderHeader, OrderLine, RefundLine); until OrderLine.Next() = 0; OrderHeader.Modify(); end; diff --git a/Apps/W1/Shopify/app/src/Order handling/Codeunits/ShpfyOrderEvents.Codeunit.al b/Apps/W1/Shopify/app/src/Order handling/Codeunits/ShpfyOrderEvents.Codeunit.al index 0fcc3adfad..2bcf4bc5b1 100644 --- a/Apps/W1/Shopify/app/src/Order handling/Codeunits/ShpfyOrderEvents.Codeunit.al +++ b/Apps/W1/Shopify/app/src/Order handling/Codeunits/ShpfyOrderEvents.Codeunit.al @@ -226,4 +226,15 @@ codeunit 30162 "Shpfy Order Events" internal procedure OnAfterMapCompany(var ShopifyOrderHeader: Record "Shpfy Order Header") begin end; + + [IntegrationEvent(false, false)] + /// + /// Raised after refunds are deducted from the quantity and amounts of the orders. + /// + /// Parameter of type Record "Shopify Order Header". + /// Parameter of type Record "Shopify Order Line". + /// Parameter of type Record "Shopify Refund Line". + internal procedure OnAfterConsiderRefundsInQuantityAndAmounts(OrderHeader: Record "Shpfy Order Header"; var OrderLine: Record "Shpfy Order Line"; RefundLine: Record "Shpfy Refund Line") + begin + end; } diff --git a/Apps/W1/Shopify/app/src/Order handling/Codeunits/ShpfyOrdersAPI.Codeunit.al b/Apps/W1/Shopify/app/src/Order handling/Codeunits/ShpfyOrdersAPI.Codeunit.al index 4af1062b69..a2e7904454 100644 --- a/Apps/W1/Shopify/app/src/Order handling/Codeunits/ShpfyOrdersAPI.Codeunit.al +++ b/Apps/W1/Shopify/app/src/Order handling/Codeunits/ShpfyOrdersAPI.Codeunit.al @@ -113,7 +113,7 @@ codeunit 30165 "Shpfy Orders API" /// Parameter of type Record "Shpfy Shop". internal procedure AddOrderAttribute(OrderHeader: Record "Shpfy Order Header"; KeyName: Text; Value: Text; ShopifyShop: Record "Shpfy Shop") #else - internal procedure AddOrderAttribute(OrderHeader: Record "Shpfy Order Header"; KeyName: Text; Value: Text) + internal procedure AddOrderAttribute(OrderHeader: Record "Shpfy Order Header"; KeyName: Text; Value: Text; ShopifyShop: Record "Shpfy Shop") #endif var OrderAttribute: Record "Shpfy Order Attribute"; @@ -121,6 +121,7 @@ codeunit 30165 "Shpfy Orders API" JAttributes: JsonArray; JAttrib: JsonObject; begin + CommunicationMgt.SetShop(ShopifyShop); if CommunicationMgt.GetTestInProgress() then exit; Clear(OrderAttribute); diff --git a/Apps/W1/Shopify/app/src/Order handling/Codeunits/ShpfyProcessOrder.Codeunit.al b/Apps/W1/Shopify/app/src/Order handling/Codeunits/ShpfyProcessOrder.Codeunit.al index afc8ec9ef4..82209b7f75 100644 --- a/Apps/W1/Shopify/app/src/Order handling/Codeunits/ShpfyProcessOrder.Codeunit.al +++ b/Apps/W1/Shopify/app/src/Order handling/Codeunits/ShpfyProcessOrder.Codeunit.al @@ -58,7 +58,6 @@ codeunit 30166 "Shpfy Process Order" /// Parameter of type Record "Shopify Order Header". local procedure CreateHeaderFromShopifyOrder(var SalesHeader: Record "Sales Header"; ShopifyOrderHeader: Record "Shpfy Order Header") var - ShopLocation: Record "Shpfy Shop Location"; ShopifyTaxArea: Record "Shpfy Tax Area"; DocLinkToBCDoc: Record "Shpfy Doc. Link To Doc."; OrdersAPI: Codeunit "Shpfy Orders API"; @@ -115,8 +114,6 @@ codeunit 30166 "Shpfy Process Order" SalesHeader."Shpfy Order No." := ShopifyOrderHeader."Shopify Order No."; SalesHeader.Validate("Document Date", ShopifyOrderHeader."Document Date"); SalesHeader.Validate("External Document No.", ShopifyOrderHeader."PO Number"); - if ShopLocation.Get(ShopifyOrderHeader."Shop Code", ShopifyOrderHeader."Location Id") and (ShopLocation."Default Location Code" <> '') then - SalesHeader.Validate("Location Code", ShopLocation."Default Location Code"); if OrderMgt.FindTaxArea(ShopifyOrderHeader, ShopifyTaxArea) and (ShopifyTaxArea."Tax Area Code" <> '') then SalesHeader.Validate("Tax Area Code", ShopifyTaxArea."Tax Area Code"); if ShopifyOrderHeader."Shipping Method Code" <> '' then @@ -136,11 +133,7 @@ codeunit 30166 "Shpfy Process Order" if ShopifyOrderHeader."Work Description".HasValue then SalesHeader.SetWorkDescription(ShopifyOrderHeader.GetWorkDescription()); end; -#if not CLEAN24 OrdersAPI.AddOrderAttribute(ShopifyOrderHeader, 'BC Doc. No.', SalesHeader."No.", ShopifyShop); -#else - OrdersAPI.AddOrderAttribute(ShopifyOrderHeader, 'BC Doc. No.', SalesHeader."No."); -#endif DocLinkToBCDoc.Init(); DocLinkToBCDoc."Shopify Document Type" := "Shpfy Shop Document Type"::"Shopify Shop Order"; DocLinkToBCDoc."Shopify Document Id" := ShopifyOrderHeader."Shopify Order Id"; @@ -217,16 +210,10 @@ codeunit 30166 "Shpfy Process Order" end else begin SalesLine.Validate(Type, SalesLine.Type::Item); SalesLine.Validate("No.", ShopifyOrderLine."Item No."); - if Item.Get(SalesLine."No.") then begin + if Item.Get(SalesLine."No.") then if (ShopifyOrderLine."Location Id" <> 0) then - if ShopLocation.Get(ShopifyOrderHeader."Shop Code", ShopifyOrderLine."Location Id") then + if ShopLocation.Get(ShopifyOrderHeader."Shop Code", ShopifyOrderLine."Location Id") and (ShopLocation."Default Location Code" <> '') then SalesLine.Validate("Location Code", ShopLocation."Default Location Code"); - if (ShopifyOrderLine."Location Id" <> 0) - and ShopLocation.Get(ShopifyOrderHeader."Shop Code", ShopifyOrderLine."Location Id") - and (ShopLocation."Default Location Code" <> '') - then - SalesLine.Validate("Location Code", ShopLocation."Default Location Code"); - end; end; SalesLine.Validate("Unit of Measure Code", ShopifyOrderLine."Unit of Measure Code"); SalesLine.Validate("Variant Code", ShopifyOrderLine."Variant Code"); diff --git a/Apps/W1/Shopify/app/src/Order handling/Tables/ShpfyOrderHeader.Table.al b/Apps/W1/Shopify/app/src/Order handling/Tables/ShpfyOrderHeader.Table.al index 16fabfc966..b71f4c1934 100644 --- a/Apps/W1/Shopify/app/src/Order handling/Tables/ShpfyOrderHeader.Table.al +++ b/Apps/W1/Shopify/app/src/Order handling/Tables/ShpfyOrderHeader.Table.al @@ -443,6 +443,14 @@ table 30118 "Shpfy Order Header" Caption = 'Location Id'; DataClassification = CustomerContent; Editable = false; + ObsoleteReason = 'Location Id on Order Header is not used. Instead use Location Id on Order Lines.'; +#if not CLEAN25 + ObsoleteState = Pending; + ObsoleteTag = '25.0'; +#else + ObsoleteState = Removed; + ObsoleteTag = '28.0'; +#endif } field(102; "Channel Name"; Text[100]) { diff --git a/Apps/W1/Shopify/app/src/Shipping/Codeunits/ShpfyShippingCharges.Codeunit.al b/Apps/W1/Shopify/app/src/Shipping/Codeunits/ShpfyShippingCharges.Codeunit.al index 0119c566d3..9b2268da5a 100644 --- a/Apps/W1/Shopify/app/src/Shipping/Codeunits/ShpfyShippingCharges.Codeunit.al +++ b/Apps/W1/Shopify/app/src/Shipping/Codeunits/ShpfyShippingCharges.Codeunit.al @@ -11,36 +11,11 @@ codeunit 30191 "Shpfy Shipping Charges" CommunicationMgt: Codeunit "Shpfy Communication Mgt."; JsonHelper: Codeunit "Shpfy Json Helper"; - /// - /// Description for UpdateShippingCostInfos. - /// - /// Parameter of type BigInteger. - internal procedure UpdateShippingCostInfos(OrderId: BigInteger) - var - OrderHeader: Record "Shpfy Order Header"; - begin - if OrderHeader.Get(OrderId) then - UpdateShippingCostInfos(OrderHeader); - end; - - /// - /// Description for UpdateShippingCostInfos. - /// - /// Parameter of type BigInteger. - /// Parameter of type JsonArray. - internal procedure UpdateShippingCostInfos(OrderId: BigInteger; JShippingLines: JsonArray) - var - OrderHeader: Record "Shpfy Order Header"; - begin - if OrderHeader.Get(OrderId) then - UpdateShippingCostInfos(OrderHeader, JShippingLines); - end; - /// /// Description for UpdateShippingCostInfos. /// /// Parameter of type Record "Shopify Order Header". - internal procedure UpdateShippingCostInfos(OrderHeader: Record "Shpfy Order Header") + internal procedure UpdateShippingCostInfos(var OrderHeader: Record "Shpfy Order Header") var Parameters: Dictionary of [Text, Text]; GraphQLType: Enum "Shpfy GraphQL Type"; @@ -70,7 +45,7 @@ codeunit 30191 "Shpfy Shipping Charges" /// /// Parameter of type Record "Shopify Order Header". /// Parameter of type JsonArray. - internal procedure UpdateShippingCostInfos(OrderHeader: Record "Shpfy Order Header"; JShippingLines: JsonArray) + internal procedure UpdateShippingCostInfos(var OrderHeader: Record "Shpfy Order Header"; JShippingLines: JsonArray) var OrderShippingCharges: Record "Shpfy Order Shipping Charges"; ShipmentMethodMapping: Record "Shpfy Shipment Method Mapping"; @@ -79,9 +54,11 @@ codeunit 30191 "Shpfy Shipping Charges" Id: BigInteger; JToken: JsonToken; IsNew: Boolean; + ShippingLineIds: List of [BigInteger]; begin foreach JToken in JShippingLines do begin Id := CommunicationMgt.GetIdOfGId(JsonHelper.GetValueAsText(JToken, 'id')); + ShippingLineIds.Add(Id); IsNew := not OrderShippingCharges.Get(Id); if IsNew then begin Clear(OrderShippingCharges); @@ -111,6 +88,24 @@ codeunit 30191 "Shpfy Shipping Charges" ShipmentMethodMapping.Insert(); end; end; + + if ShippingLineIds.Count() > 0 then + DeleteRemovedShippingLines(OrderHeader, ShippingLineIds); + end; + + local procedure DeleteRemovedShippingLines(var OrderHeader: Record "Shpfy Order Header"; ShippingLineIds: List of [BigInteger]) + var + OrderShippingCharges: Record "Shpfy Order Shipping Charges"; + begin + OrderShippingCharges.SetRange("Shopify Order Id", OrderHeader."Shopify Order Id"); + if OrderShippingCharges.FindSet() then + repeat + if not ShippingLineIds.Contains(OrderShippingCharges."Shopify Shipping Line Id") then begin + OrderHeader."Shipping Charges Amount" -= OrderShippingCharges.Amount - OrderShippingCharges."Discount Amount"; + OrderHeader."Total Amount" -= OrderShippingCharges.Amount - OrderShippingCharges."Discount Amount"; + OrderShippingCharges.Delete(true); + end; + until OrderShippingCharges.Next() = 0; end; local procedure GetShippingDiscountAmount(JDiscountAllocations: JsonArray; MoneyType: Text) Result: Decimal diff --git a/Apps/W1/Shopify/app/src/Shipping/Tables/ShpfyOrderShippingCharges.Table.al b/Apps/W1/Shopify/app/src/Shipping/Tables/ShpfyOrderShippingCharges.Table.al index abf119098d..c4ace2b63b 100644 --- a/Apps/W1/Shopify/app/src/Shipping/Tables/ShpfyOrderShippingCharges.Table.al +++ b/Apps/W1/Shopify/app/src/Shipping/Tables/ShpfyOrderShippingCharges.Table.al @@ -70,5 +70,15 @@ table 30130 "Shpfy Order Shipping Charges" Clustered = true; } } + + trigger OnDelete() + var + DataCapture: Record "Shpfy Data Capture"; + begin + DataCapture.SetRange("Linked To Table", Database::"Shpfy Order Shipping Charges"); + DataCapture.SetRange("Linked To Id", Rec.SystemId); + if not DataCapture.IsEmpty then + DataCapture.DeleteAll(false); + end; } diff --git a/Apps/W1/Shopify/app/src/Transactions/Reports/ShpfySuggestPayments.Report.al b/Apps/W1/Shopify/app/src/Transactions/Reports/ShpfySuggestPayments.Report.al index 30abf3fbe3..3cfa432ece 100644 --- a/Apps/W1/Shopify/app/src/Transactions/Reports/ShpfySuggestPayments.Report.al +++ b/Apps/W1/Shopify/app/src/Transactions/Reports/ShpfySuggestPayments.Report.al @@ -56,7 +56,7 @@ report 30118 "Shpfy Suggest Payments" ToolTip = 'Specifies the name of the journal template that is used for the posting.'; Visible = not IsGenJournalLineSet; Editable = not IsJournalTemplateFound; - + ShowMandatory = true; trigger OnValidate() begin ValidatePostingDate(); @@ -69,7 +69,7 @@ report 30118 "Shpfy Suggest Payments" Lookup = true; ToolTip = 'Specifies the name of the journal batch that is used for the posting.'; Visible = not IsGenJournalLineSet; - + ShowMandatory = true; trigger OnLookup(var Text: Text): Boolean var GenJnlManagement: Codeunit GenJnlManagement; @@ -91,6 +91,7 @@ report 30118 "Shpfy Suggest Payments" Caption = 'Posting Date'; Importance = Promoted; ToolTip = 'Specifies the date for the posting of this batch job. By default, the working date is entered, but you can change it.'; + ShowMandatory = true; trigger OnValidate() begin diff --git a/Apps/W1/Sustainability/app/src/APIs/SustainabilityLedgEntries.Page.al b/Apps/W1/Sustainability/app/src/APIs/SustainabilityLedgEntries.Page.al index c763d5e4b5..3e46a57fae 100644 --- a/Apps/W1/Sustainability/app/src/APIs/SustainabilityLedgEntries.Page.al +++ b/Apps/W1/Sustainability/app/src/APIs/SustainabilityLedgEntries.Page.al @@ -20,6 +20,9 @@ page 6231 "Sustainability Ledg. Entries" ODataKeyFields = SystemId; SourceTable = "Sustainability Ledger Entry"; Extensible = false; + InsertAllowed = false; + ModifyAllowed = false; + DeleteAllowed = false; layout { diff --git a/Apps/W1/Sustainability/app/src/Journal/SustainabilityJnlLine.Table.al b/Apps/W1/Sustainability/app/src/Journal/SustainabilityJnlLine.Table.al index 8c4291d2c1..a5773a6a1a 100644 --- a/Apps/W1/Sustainability/app/src/Journal/SustainabilityJnlLine.Table.al +++ b/Apps/W1/Sustainability/app/src/Journal/SustainabilityJnlLine.Table.al @@ -310,7 +310,7 @@ table 6214 "Sustainability Jnl. Line" DimMgt: Codeunit DimensionManagement; JnlRecRefLbl: Label '%1 %2 %3', Locked = true; - internal procedure SetupNewLine(PreviousLine: Record "Sustainability Jnl. Line") + procedure SetupNewLine(PreviousLine: Record "Sustainability Jnl. Line") var SustainabilityJnlBatch: Record "Sustainability Jnl. Batch"; SustainabilityJnlLine: Record "Sustainability Jnl. Line"; diff --git a/Apps/W1/Sustainability/test/src/SustainabilityAPITests.Codeunit.al b/Apps/W1/Sustainability/test/src/SustainabilityAPITests.Codeunit.al new file mode 100644 index 0000000000..2af04ea968 --- /dev/null +++ b/Apps/W1/Sustainability/test/src/SustainabilityAPITests.Codeunit.al @@ -0,0 +1,385 @@ +codeunit 148185 "Sustainability API Tests" +{ + Subtype = Test; + TestPermissions = Disabled; + + trigger OnRun() + begin + // [FEATURE] [Sustainability] [API] [UI] + end; + + var + Assert: Codeunit "Assert"; + LibraryGraphMgt: Codeunit "Library - Graph Mgt"; + LibrarySustainability: Codeunit "Library - Sustainability"; + LibraryUtility: Codeunit "Library - Utility"; + IsInitialized: Boolean; + CodeLbl: Label 'code', Locked = true; + NumberLbl: Label 'number', Locked = true; + LineNumberLbl: Label 'lineNumber', Locked = true; + AccountCodeLbl: Label 'AccountCode%1', Locked = true, Comment = '%1 = Number'; + CategoryCodeLbl: Label 'CategoryCode%1', Locked = true, Comment = '%1 = Number'; + SubcategoryCodeLbl: Label 'SubcategoryCode%1', Locked = true, Comment = '%1 = Number'; + SustainabilityAccountCategoriesServiceNameLbl: Label 'sustainabilityAccountCategories', Locked = true; + SustainabilityAccountSubcategoriesServiceNameLbl: Label 'sustainabilityAccountSubcategories', Locked = true; + SustainabilityAccountsServiceNameLbl: Label 'sustainabilityAccounts', Locked = true; + SustainabilityJournalLinesServiceNameLbl: Label 'sustainabilityJournalLines', Locked = true; + CreateRecordErr: Label 'The record hasn''t been created.', Locked = true; + + #region GET methods + [Test] + procedure TestGetSustainabilityCategory() + var + CategoryCode: array[2] of Code[20]; + ResponseText: Text; + i: Integer; + begin + // [SCENARIO 521279] Create two Sustainability Account Categories and use GET method to retrieve them + + Initialize(); + + // [GIVEN] Sustainability Account Category X + // [GIVEN] Sustainability Account Category Y + for i := 1 to ArrayLen(CategoryCode) do + CreateSustainabilityCategory(CategoryCode[i], i); + Commit(); + + // [WHEN] GET request is made to the Sustainability Account Categories API + LibraryGraphMgt.GetFromWebService(ResponseText, LibraryGraphMgt.CreateTargetURL('', Page::"Sust. Account Categories", SustainabilityAccountCategoriesServiceNameLbl)); + + // [THEN] Two Sustainability Account Category Codes have been found in the response + GetAndVerifyIDFromJSON(ResponseText, CategoryCode[1], CategoryCode[2], CodeLbl); + end; + + [Test] + procedure TestGetSustainabilitySubcategory() + var + CategoryCode: array[2] of Code[20]; + SubcategoryCode: array[2] of Code[20]; + ResponseText: Text; + i: Integer; + begin + // [SCENARIO 521279] Create two Sustainability Account Subcategories and use GET method to retrieve them + Initialize(); + + // [GIVEN] Sustainability Account Subcategory X, Sustainability Account Category X + // [GIVEN] Sustainability Account Subcategory Y, Sustainability Account Category Y + for i := 1 to ArrayLen(SubcategoryCode) do + CreateSustainabilitySubcategory(CategoryCode[i], SubcategoryCode[i], i + 2); + Commit(); + + // [WHEN] GET request is made to the Sustainability Account Subcategories API + LibraryGraphMgt.GetFromWebService(ResponseText, LibraryGraphMgt.CreateTargetURL('', Page::"Sust. Acc. Subcategory", SustainabilityAccountSubcategoriesServiceNameLbl)); + + // [THEN] Two Sustainability Account Subcategory Codes have been found in the response + GetAndVerifyIDFromJSON(ResponseText, SubcategoryCode[1], SubcategoryCode[2], CodeLbl); + end; + + [Test] + procedure TestGetSustainabilityAccounts() + var + CategoryCode: array[2] of Code[20]; + SubcategoryCode: array[2] of Code[20]; + AccountCode: array[2] of Code[20]; + ResponseText: Text; + i: Integer; + begin + // [SCENARIO 521279] Create two Sustainability Accounts and use GET method to retrieve them + + Initialize(); + + // [GIVEN] Sustainability Account X, Sustainability Account Subcategory X, Sustainability Account Category X + // [GIVEN] Sustainability Account Y, Sustainability Account Subcategory Y, Sustainability Account Category Y + for i := 1 to ArrayLen(AccountCode) do + CreateSustainabilityAccount(AccountCode[i], CategoryCode[i], SubcategoryCode[i], i + 4); + Commit(); + + // [WHEN] GET request is made to the Sustainability Accounts API + LibraryGraphMgt.GetFromWebService(ResponseText, LibraryGraphMgt.CreateTargetURL('', Page::"Sustainability Accounts", SustainabilityAccountsServiceNameLbl)); + + // [THEN] Two Sustainability Account Codes have been found in the response + GetAndVerifyIDFromJSON(ResponseText, AccountCode[1], AccountCode[2], NumberLbl); + end; + + [Test] + procedure TestGetSustainabilityJournalLines() + var + SustainabilityAccount: array[2] of Record "Sustainability Account"; + SustainabilityJournalLine: array[2] of Record "Sustainability Jnl. Line"; + CategoryCode: array[2] of Code[20]; + SubcategoryCode: array[2] of Code[20]; + AccountCode: array[2] of Code[20]; + ResponseText: Text; + i: Integer; + begin + // [SCENARIO 521279] Create two Sustainability Journal Lines and use GET method to retrieve them + + Initialize(); + + // [GIVEN] Sustainability Journal Line 1, Sustainability Account X, Sustainability Account Subcategory X, Sustainability Account Category X + // [GIVEN] Sustainability Journal Line 2, Sustainability Account Y, Sustainability Account Subcategory Y, Sustainability Account Category Y + for i := 1 to ArrayLen(SustainabilityJournalLine) do begin + SustainabilityAccount[i] := CreateSustainabilityAccount(AccountCode[i], CategoryCode[i], SubcategoryCode[i], i + 6); + SustainabilityJournalLine[i] := CreateSustainabilityJnlLine(SustainabilityAccount[i]); + end; + Commit(); + + // [WHEN] GET request is made to the Sustainability Journal Lines API + LibraryGraphMgt.GetFromWebService(ResponseText, LibraryGraphMgt.CreateTargetURL('', Page::"Sustainability Journal Line", SustainabilityJournalLinesServiceNameLbl)); + + // [THEN] Two Sustainability Journal Line Numbers have been found in the response + GetAndVerifyIDFromJSON(ResponseText, Format(SustainabilityJournalLine[1]."Line No."), Format(SustainabilityJournalLine[2]."Line No."), LineNumberLbl); + end; + + [Test] + procedure TestGetSustainabilityEntries() + var + SustainabilityAccount: array[2] of Record "Sustainability Account"; + SustainabilityJournalLine: array[2] of Record "Sustainability Jnl. Line"; + CategoryCode: array[2] of Code[20]; + SubcategoryCode: array[2] of Code[20]; + AccountCode: array[2] of Code[20]; + ResponseText: Text; + LedgerEntryNo: array[2] of Integer; + i: Integer; + SustainabilityEntriesServiceNameLbl: Label 'sustainabilityLedgerEntries', Locked = true; + EntryNumberLbl: Label 'entryNumber', Locked = true; + begin + // [SCENARIO 521279] Create two Sustainability Entries and use GET method to retrieve them + Initialize(); + + // [GIVEN] Sustainability Lendger Entry 1, Sustainability Account X, Sustainability Account Subcategory X, Sustainability Account Category X + // [GIVEN] Sustainability Lendger Entry 2, Sustainability Account Y, Sustainability Account Subcategory Y, Sustainability Account Category Y + for i := 1 to ArrayLen(LedgerEntryNo) do begin + SustainabilityAccount[i] := CreateSustainabilityAccount(AccountCode[i], CategoryCode[i], SubcategoryCode[i], i + 8); + SustainabilityJournalLine[i] := CreateSustainabilityJnlLine(SustainabilityAccount[i]); + LedgerEntryNo[i] := CreateSustainabilityEntries(SustainabilityJournalLine[i]); + end; + Commit(); + + // [WHEN] GET request is made to the Sustainability Entries API + LibraryGraphMgt.GetFromWebService(ResponseText, LibraryGraphMgt.CreateTargetURL('', Page::"Sustainability Ledg. Entries", SustainabilityEntriesServiceNameLbl)); + + // [THEN] Two Sustainability Entries have been found in the response + GetAndVerifyIDFromJSON(ResponseText, Format(LedgerEntryNo[1]), Format(LedgerEntryNo[2]), EntryNumberLbl); + end; + + #endregion GET methods + + #region POST methods + [Test] + procedure TestPostSustainabilityCategory() + var + SustainAccountCategory: Record "Sustain. Account Category"; + SustainAccountCategoryJSON: Text; + ResponseText: Text; + begin + // [SCENARIO 521279] Create Sustainability Account Category using POST method + Initialize(); + + // [GIVEN] Create JSON file with the data for a new Sustainability Account Category Z + SustainAccountCategoryJSON := CreateSustainabilityJSON(CodeLbl, StrSubstNo(CategoryCodeLbl, 'X')); + + // [WHEN] POST request is made to the Sustainability Account Categories API + LibraryGraphMgt.PostToWebService(LibraryGraphMgt.CreateTargetURL('', Page::"Sust. Account Categories", SustainabilityAccountCategoriesServiceNameLbl), SustainAccountCategoryJSON, ResponseText); + + // [THEN] New Sustainability Account Category Z has been created + Assert.IsTrue(SustainAccountCategory.Get(StrSubstNo(CategoryCodeLbl, 'X')), CreateRecordErr); + end; + + [Test] + procedure TestPostSustainabilitySubcategory() + var + SustainAccountSubcategory: Record "Sustain. Account Subcategory"; + CategoryCode: Code[20]; + SustainAccountSubcategoryJSON: Text; + ResponseText: Text; + CategoryLbl: Label 'category', Locked = true; + begin + // [SCENARIO 521279] Create Sustainability Account Subcategory using POST method + Initialize(); + + // [GIVEN] Create Sustainability Account Category Y + CreateSustainabilityCategory(CategoryCode, 99); + + // [GIVEN] Create JSON file with the data for a new Sustainability Account Subcategory Z + SustainAccountSubcategoryJSON := CreateSustainabilitySubCategoryJSON(CodeLbl, StrSubstNo(SubcategoryCodeLbl, 'Y'), CategoryLbl, CategoryCode); + Commit(); + // [WHEN] POST request is made to the Sustainability Account Subcategory API + LibraryGraphMgt.PostToWebService(LibraryGraphMgt.CreateTargetURL('', Page::"Sust. Acc. Subcategory", SustainabilityAccountSubcategoriesServiceNameLbl), SustainAccountSubcategoryJSON, ResponseText); + + // [THEN] New Sustainability Account Subcategory Z has been created + Assert.IsTrue(SustainAccountSubcategory.Get(CategoryCode, StrSubstNo(SubcategoryCodeLbl, 'Y')), CreateRecordErr); + end; + + [Test] + procedure TestPostSustainabilityAccount() + var + SustainabilityAccount: Record "Sustainability Account"; + SustainabilityAccountJSON: Text; + ResponseText: Text; + begin + // [SCENARIO 521279] Create Sustainability Account using POST method + Initialize(); + + // [GIVEN] Create JSON file with the data for a new Sustainability Account Z + SustainabilityAccountJSON := CreateSustainabilityJSON(NumberLbl, StrSubstNo(AccountCodeLbl, 'Z')); + Commit(); + + // [WHEN] POST request is made to the Sustainability Account API + LibraryGraphMgt.PostToWebService(LibraryGraphMgt.CreateTargetURL('', Page::"Sustainability Accounts", SustainabilityAccountsServiceNameLbl), SustainabilityAccountJSON, ResponseText); + + // [THEN] New Sustainability Account Z has been created + Assert.IsTrue(SustainabilityAccount.Get(StrSubstNo(AccountCodeLbl, 'Z')), CreateRecordErr); + end; + + [Test] + procedure TestPostSustainabilityJournalLine() + var + SustainabilityJnlLine: Record "Sustainability Jnl. Line"; + SustainabilityJnlBatch: Record "Sustainability Jnl. Batch"; + SustainabilityJournalLineJSON: Text; + ResponseText: Text; + LineNo: Integer; + begin + // [SCENARIO 521279] Create Sustainability Jnl. Line using POST method + Initialize(); + + // [GIVEN] Create JSON file with the data for a new Sustainability Jnl. Line + SustainabilityJournalLineJSON := CreateSustainabilityJnlLineJSON(SustainabilityJnlBatch, LineNo); + Commit(); + + // [WHEN] POST request is made to the Sustainability Jnl. Line API + LibraryGraphMgt.PostToWebService(LibraryGraphMgt.CreateTargetURL('', Page::"Sustainability Journal Line", SustainabilityJournalLinesServiceNameLbl), SustainabilityJournalLineJSON, ResponseText); + + // [THEN] New Sustainability Jnl. Line has been created + Assert.IsTrue(SustainabilityJnlLine.Get(SustainabilityJnlBatch."Journal Template Name", SustainabilityJnlBatch.Name, LineNo), CreateRecordErr); + end; + #endregion POST methods + + local procedure Initialize() + var + LibraryTestInitialize: Codeunit "Library - Test Initialize"; + begin + LibraryTestInitialize.OnTestInitialize(Codeunit::"Sustainability API Tests"); + + if IsInitialized then + exit; + + LibrarySustainability.CleanUpBeforeTesting(); + + IsInitialized := true; + + LibraryTestInitialize.OnAfterTestSuiteInitialize(Codeunit::"Sustainability API Tests"); + end; + + local procedure CreateSustainabilityCategory(var CategoryCode: Code[20]; i: Integer) + begin + CategoryCode := StrSubstNo(CategoryCodeLbl, i); + LibrarySustainability.InsertAccountCategory( + CategoryCode, CategoryCode, Enum::"Emission Scope"::"Scope 1", Enum::"Calculation Foundation"::"Fuel/Electricity", + true, true, true, '', false); + end; + + local procedure CreateSustainabilitySubcategory(var CategoryCode: Code[20]; var SubcategoryCode: Code[20]; i: Integer) + begin + CategoryCode := StrSubstNo(CategoryCodeLbl, i); + CreateSustainabilityCategory(CategoryCode, i); + + SubcategoryCode := StrSubstNo(SubcategoryCodeLbl, i); + LibrarySustainability.InsertAccountSubcategory(CategoryCode, SubcategoryCode, SubcategoryCode, 1, 2, 3, false); + end; + + local procedure CreateSustainabilityAccount(var AccountCode: Code[20]; CategoryCode: Code[20]; SubcategoryCode: Code[20]; i: Integer): Record "Sustainability Account" + begin + CreateSustainabilitySubcategory(CategoryCode, SubcategoryCode, i); + AccountCode := StrSubstNo(AccountCodeLbl, i); + exit(LibrarySustainability.InsertSustainabilityAccount( + AccountCode, '', CategoryCode, SubcategoryCode, Enum::"Sustainability Account Type"::Posting, '', true)); + end; + + local procedure CreateSustainabilityJnlLine(SustainabilityAccount: Record "Sustainability Account") SustainabilityJournalLine: Record "Sustainability Jnl. Line"; + var + SustainabilityJnlBatch: Record "Sustainability Jnl. Batch"; + begin + SetSustainabilityJournalLine(SustainabilityJournalLine, SustainabilityJnlBatch); + exit( + LibrarySustainability.InsertSustainabilityJournalLine( + SustainabilityJnlBatch, SustainabilityAccount, GetLastLineNo(SustainabilityJournalLine))); + end; + + local procedure CreateSustainabilityEntries(SustainabilityJournalLine: Record "Sustainability Jnl. Line"): Integer + var + SustainabilityLedgerEntry: Record "Sustainability Ledger Entry"; + SustainabilityPostMgt: Codeunit "Sustainability Post Mgt"; + begin + SustainabilityPostMgt.InsertLedgerEntry(SustainabilityJournalLine); + SustainabilityLedgerEntry.FindLast(); + exit(SustainabilityLedgerEntry."Entry No."); + end; + + local procedure SetSustainabilityJournalLine(var SustainabilityJournalLine: Record "Sustainability Jnl. Line"; var SustainabilityJnlBatch: Record "Sustainability Jnl. Batch") + var + SustainabilityJournalMgt: Codeunit "Sustainability Journal Mgt."; + begin + SustainabilityJnlBatch := SustainabilityJournalMgt.GetASustainabilityJournalBatch(false); + SustainabilityJournalLine."Journal Template Name" := SustainabilityJnlBatch."Journal Template Name"; + SustainabilityJournalLine."Journal Batch Name" := SustainabilityJnlBatch.Name; + end; + + local procedure GetLastLineNo(var SustainabilityJournalLine: Record "Sustainability Jnl. Line"): Integer + var + RecordRef: RecordRef; + begin + RecordRef.GetTable(SustainabilityJournalLine); + exit(LibraryUtility.GetNewLineNo(RecordRef, SustainabilityJournalLine.FieldNo("Line No."))); + end; + + local procedure GetAndVerifyIDFromJSON(ResponseText: Text; Code1: Code[20]; Code2: Code[20]; ObjectIDFieldName: Text) + var + JSONText: array[2] of Text; + DataNonExistErr: Label 'Could not find the data in JSON', Locked = true; + begin + Assert.IsTrue( + LibraryGraphMgt.GetObjectsFromJSONResponse(ResponseText, ObjectIDFieldName, Code1, Code2, JSONText[1], JSONText[2]), DataNonExistErr); + LibraryGraphMgt.VerifyIDInJson(JSONText[1]); + LibraryGraphMgt.VerifyIDInJson(JSONText[2]); + end; + + local procedure CreateSustainabilityJSON(PropertyName: Text; PropertyValue: Variant): Text + var + LineJSON: Text; + begin + LineJSON := LibraryGraphMgt.AddPropertytoJSON('', 'id', CreateGuid()); + LineJSON := LibraryGraphMgt.AddPropertytoJSON(LineJSON, PropertyName, PropertyValue); + exit(LineJSON); + end; + + local procedure CreateSustainabilitySubCategoryJSON(PropertyName: Text; PropertyValue: Variant; PropertyName2: Text; PropertyValue2: Variant): Text + var + LineJSON: Text; + begin + LineJSON := LibraryGraphMgt.AddPropertytoJSON('', 'id', CreateGuid()); + LineJSON := LibraryGraphMgt.AddPropertytoJSON(LineJSON, PropertyName, PropertyValue); + LineJSON := LibraryGraphMgt.AddPropertytoJSON(LineJSON, PropertyName2, PropertyValue2); + exit(LineJSON); + end; + + local procedure CreateSustainabilityJnlLineJSON(var SustainabilityJnlBatch: Record "Sustainability Jnl. Batch"; var LineNo: Integer): Text + var + SustainabilityJournalLine: Record "Sustainability Jnl. Line"; + LineJSON: Text; + JournalTemplateNameLbl: Label 'journalTemplateName', Locked = true; + JournalBatchNameLbl: Label 'journalBatchName', Locked = true; + begin + SetSustainabilityJournalLine(SustainabilityJournalLine, SustainabilityJnlBatch); + + LineNo := GetLastLineNo(SustainabilityJournalLine); + + LineJSON := LibraryGraphMgt.AddPropertytoJSON('', 'id', CreateGuid()); + LineJSON := LibraryGraphMgt.AddPropertytoJSON(LineJSON, JournalTemplateNameLbl, SustainabilityJnlBatch."Journal Template Name"); + LineJSON := LibraryGraphMgt.AddPropertytoJSON(LineJSON, JournalBatchNameLbl, SustainabilityJnlBatch.Name); + LineJSON := LibraryGraphMgt.AddPropertytoJSON(LineJSON, LineNumberLbl, LineNo); + exit(LineJSON); + end; +} diff --git a/Apps/W1/TransactionStorage/app/src/TransStorageErrorHandler.Codeunit.al b/Apps/W1/TransactionStorage/app/src/TransStorageErrorHandler.Codeunit.al index 2424f458ef..81d84ae20c 100644 --- a/Apps/W1/TransactionStorage/app/src/TransStorageErrorHandler.Codeunit.al +++ b/Apps/W1/TransactionStorage/app/src/TransStorageErrorHandler.Codeunit.al @@ -8,7 +8,8 @@ codeunit 6204 "Trans. Storage Error Handler" TableNo = "Transact. Storage Task Entry"; InherentEntitlements = X; InherentPermissions = X; - Permissions = tabledata "Transact. Storage Export State" = RIM; + Permissions = tabledata "Transact. Storage Export State" = RIM, + tabledata "Trans. Storage Export Data" = RD; var TransactionStorageTok: Label 'Transaction Storage', Locked = true; @@ -19,6 +20,7 @@ codeunit 6204 "Trans. Storage Error Handler" trigger OnRun() var TransactStorageExportState: Record "Transact. Storage Export State"; + TransStorageExportData: Record "Trans. Storage Export Data"; TransStorageScheduleTask: Codeunit "Trans. Storage Schedule Task"; FeatureTelemetry: Codeunit "Feature Telemetry"; ExportDateTime: DateTime; @@ -38,6 +40,7 @@ codeunit 6204 "Trans. Storage Error Handler" TransStorageScheduleTask.CreateTaskToExport(ExportDateTime, false); TransactStorageExportState."Number Of Attempts" -= 1; TransactStorageExportState.Modify(); + TransStorageExportData.DeleteAll(true); end; local procedure CheckMultipleTaskFailures() diff --git a/Apps/W1/TransactionStorage/app/src/TransStorageExportData.Table.al b/Apps/W1/TransactionStorage/app/src/TransStorageExportData.Table.al new file mode 100644 index 0000000000..dbc4ec19d8 --- /dev/null +++ b/Apps/W1/TransactionStorage/app/src/TransStorageExportData.Table.al @@ -0,0 +1,49 @@ +namespace System.DataAdministration; + +table 6205 "Trans. Storage Export Data" +{ + Access = Internal; + DataClassification = OrganizationIdentifiableInformation; + InherentEntitlements = rimdX; + InherentPermissions = rimdX; + Permissions = tabledata "Trans. Storage Export Data" = rimd; + + fields + { + field(1; "Table ID"; Integer) + { + } + field(2; Part; Integer) + { + } + field(3; Content; Blob) + { + } + field(4; "Record Count"; Integer) + { + + } + } + + keys + { + key(PK; "Table ID", Part) + { + Clustered = true; + } + } + + internal procedure Add(var NewPart: Integer; var JsonArray: JsonArray; TableID: Integer; RecordCount: Integer) + var + OutStream: OutStream; + begin + Rec.Init(); + Rec."Table ID" := TableID; + NewPart += 1; + Rec.Part := NewPart; + Rec.Content.CreateOutStream(OutStream, TextEncoding::UTF8); + JsonArray.WriteTo(OutStream); + Rec."Record Count" := RecordCount; + Rec.Insert(); + end; +} \ No newline at end of file diff --git a/Apps/W1/TransactionStorage/app/src/TransactStorageExportData.Codeunit.al b/Apps/W1/TransactionStorage/app/src/TransactStorageExportData.Codeunit.al index 1eb1488b93..66e5ab363c 100644 --- a/Apps/W1/TransactionStorage/app/src/TransactStorageExportData.Codeunit.al +++ b/Apps/W1/TransactionStorage/app/src/TransactStorageExportData.Codeunit.al @@ -32,6 +32,7 @@ codeunit 6202 "Transact. Storage Export Data" InherentPermissions = X; Permissions = tabledata "Transact. Storage Table Entry" = RIMD, tabledata "Transact. Storage Task Entry" = RIM, + tabledata "Trans. Storage Export Data" = RIMD, tabledata "G/L Entry" = r, tabledata "VAT Entry" = r, tabledata "Cust. Ledger Entry" = r, @@ -56,34 +57,38 @@ codeunit 6202 "Transact. Storage Export Data" FeatureTelemetry: Codeunit "Feature Telemetry"; TransactStorageExport: Codeunit "Transact. Storage Export"; TransactionStorageTok: Label 'Transaction Storage', Locked = true; - NoOfCollectedRecordsTxt: Label 'Number of collected records.', Locked = true; + NoOfCollectedRecordTxt: Label 'Number of collected records', Locked = true; + NoOfCollectedPartsTxt: Label 'Parts', Locked = true; NoPermissionsForTableErr: Label 'User does not have permissions to read the table %1', Comment = '%1 = table name', Locked = true; procedure ExportData(TaskStartingDateTime: DateTime) var + TransStorageExportData: Record "Trans. Storage Export Data"; TempFieldList: Record Field temporary; TransactionStorageABS: Codeunit "Transaction Storage ABS"; HandledIncomingDocs: Dictionary of [Text, Integer]; MasterData: Dictionary of [Integer, List of [Code[50]]]; - DataJsonArrays: Dictionary of [Integer, JsonArray]; TablesToExport: List of [Integer]; TableID: Integer; begin + TransStorageExportData.DeleteAll(true); TablesToExport := GetTablesToExport(); foreach TableID in TablesToExport do - CollectDataFromTable(DataJsonArrays, HandledIncomingDocs, TempFieldList, MasterData, TaskStartingDateTime, TableID); - LogNumberOfCollectedRecords(DataJsonArrays); - CollectMasterData(DataJsonArrays, MasterData); - if (DataJsonArrays.Count() <> 0) or (HandledIncomingDocs.Count() <> 0) then - TransactionStorageABS.ArchiveTransactionsToABS(DataJsonArrays, HandledIncomingDocs); + CollectDataFromTable(HandledIncomingDocs, TempFieldList, MasterData, TaskStartingDateTime, TableID); + LogNumberOfCollectedRecords(TablesToExport); + CollectMasterData(MasterData); + if (not TransStorageExportData.IsEmpty()) or (HandledIncomingDocs.Count() <> 0) then + TransactionStorageABS.ArchiveTransactionsToABS(HandledIncomingDocs); end; - local procedure CollectDataFromTable(var DataJsonArrays: Dictionary of [Integer, JsonArray]; var HandledIncomingDocs: Dictionary of [Text, Integer]; var TempFieldList: Record Field temporary; var MasterData: Dictionary of [Integer, List of [Code[50]]]; TaskStartingDateTime: DateTime; TableID: Integer) + local procedure CollectDataFromTable(var HandledIncomingDocs: Dictionary of [Text, Integer]; var TempFieldList: Record Field temporary; var MasterData: Dictionary of [Integer, List of [Code[50]]]; TaskStartingDateTime: DateTime; TableID: Integer) var TransactStorageTableEntry: Record "Transact. Storage Table Entry"; RecRef: RecordRef; RecordJsonObject: JsonObject; TableJsonArray: JsonArray; + RecordsHandled: Integer; + Part: Integer; begin RecRef.Open(TableID); if not RecRef.ReadPermission() then begin @@ -98,12 +103,14 @@ codeunit 6202 "Transact. Storage Export Data" if RecRef.FindSet() then begin Clear(TableJsonArray); repeat + RecordsHandled += 1; TransactStorageTableEntry."No. Of Records Exported" += 1; HandleTableFieldSet(RecordJsonObject, MasterData, TempFieldList, RecRef, true); TableJsonArray.Add(RecordJsonObject); + AddJsonArrayToTransStorageExportData(Part, TableJsonArray, RecordsHandled, GetRecordChunkSize(), RecRef.Number()); TransactStorageExport.HandleIncomingDocuments(HandledIncomingDocs, RecRef); until RecRef.Next() = 0; - DataJsonArrays.Add(RecRef.Number, TableJsonArray); + AddJsonArrayToTransStorageExportData(Part, TableJsonArray, RecordsHandled, 0, RecRef.Number()); end else TransactStorageExport.SetTableEntryProcessed(TransactStorageTableEntry, TransactStorageTableEntry."Filter Record To DT", false, ''); TransactStorageExport.CheckTimeDeadline(TaskStartingDateTime); @@ -112,7 +119,7 @@ codeunit 6202 "Transact. Storage Export Data" RecRef.Close(); end; - local procedure CollectMasterData(var DataJsonArrays: Dictionary of [Integer, JsonArray]; var MasterData: Dictionary of [Integer, List of [Code[50]]]) + local procedure CollectMasterData(var MasterData: Dictionary of [Integer, List of [Code[50]]]) var TempFieldList: Record Field temporary; RecRef: RecordRef; @@ -123,8 +130,12 @@ codeunit 6202 "Transact. Storage Export Data" MasterDataCode: Code[50]; RecordJsonObject: JsonObject; TableJsonArray: JsonArray; + RecordsHandled: Integer; + Part: Integer; begin foreach MasterDataTableNo in MasterData.Keys() do begin + Part := 0; + RecordsHandled := 0; MasterDataCodes := MasterData.Get(MasterDataTableNo); RecRef.Open(MasterDataTableNo); if not RecRef.ReadPermission() then begin @@ -140,17 +151,30 @@ codeunit 6202 "Transact. Storage Export Data" foreach MasterDataCode in MasterDataCodes do begin FieldRef.SetRange(MasterDataCode); if RecRef.FindFirst() then begin + RecordsHandled += 1; HandleTableFieldSet(RecordJsonObject, MasterData, TempFieldList, RecRef, false); TableJsonArray.Add(RecordJsonObject); + AddJsonArrayToTransStorageExportData(Part, TableJsonArray, RecordsHandled, GetRecordChunkSize(), RecRef.Number()); end; end; - DataJsonArrays.Add(RecRef.Number, TableJsonArray); + AddJsonArrayToTransStorageExportData(Part, TableJsonArray, RecordsHandled, 0, RecRef.Number()); end; RecRef.Close(); Commit(); end; end; + local procedure AddJsonArrayToTransStorageExportData(var Part: Integer; var TableJsonArray: JsonArray; var RecordsHandled: Integer; ChunkSize: Integer; TableID: Integer) + var + TransStorageExportData: Record "Trans. Storage Export Data"; + begin + if RecordsHandled < ChunkSize then + exit; + TransStorageExportData.Add(Part, TableJsonArray, TableID, RecordsHandled); + RecordsHandled := 0; + Clear(TableJsonArray); + end; + local procedure SetRangeOnDataTable(var RecRef: RecordRef; var TransactStorageTableEntry: Record "Transact. Storage Table Entry"; TaskStartingDateTime: DateTime) var SystemCreateAtFieldRef: FieldRef; @@ -224,17 +248,23 @@ codeunit 6202 "Transact. Storage Export Data" UpdateTempFieldList(TempFieldList, TableID, FieldID); end; - local procedure LogNumberOfCollectedRecords(var DataJsonArrays: Dictionary of [Integer, JsonArray]) + local procedure LogNumberOfCollectedRecords(TablesToExport: List of [Integer]) var + TransStorageExportData: Record "Trans. Storage Export Data"; TableMetadata: Record "Table Metadata"; - CustomDimensions: Dictionary of [Text, Text]; + RecordsCustomDimensions: Dictionary of [Text, Text]; + PartsCustomDimensions: Dictionary of [Text, Text]; TableID: Integer; begin - foreach TableID in DataJsonArrays.Keys() do begin + foreach TableID in TablesToExport do begin TableMetadata.Get(TableID); - CustomDimensions.Add(TableMetadata.Name, Format(DataJsonArrays.Get(TableID).Count())); + TransStorageExportData.SetRange("Table ID", TableID); + TransStorageExportData.CalcSums("Record Count"); + RecordsCustomDimensions.Add(TableMetadata.Name, Format(TransStorageExportData."Record Count")); + PartsCustomDimensions.Add(TableMetadata.Name, Format(TransStorageExportData.Count())); end; - FeatureTelemetry.LogUsage('0000LK7', TransactionStorageTok, NoOfCollectedRecordsTxt, CustomDimensions); + FeatureTelemetry.LogUsage('0000LK7', TransactionStorageTok, NoOfCollectedRecordTxt, RecordsCustomDimensions); + FeatureTelemetry.LogUsage('0000N1I', TransactionStorageTok, NoOfCollectedPartsTxt, PartsCustomDimensions); end; local procedure GetTablesToExport() TablesToExport: List of [Integer] @@ -1230,4 +1260,9 @@ codeunit 6202 "Transact. Storage Export Data" RecRef.SetLoadFields(TempFieldList."No."); until TempFieldList.Next() = 0; end; + + local procedure GetRecordChunkSize(): Integer + begin + exit(200000); + end; } \ No newline at end of file diff --git a/Apps/W1/TransactionStorage/app/src/TransactionStorageABS.Codeunit.al b/Apps/W1/TransactionStorage/app/src/TransactionStorageABS.Codeunit.al index 50b369dd30..18b2e29f44 100644 --- a/Apps/W1/TransactionStorage/app/src/TransactionStorageABS.Codeunit.al +++ b/Apps/W1/TransactionStorage/app/src/TransactionStorageABS.Codeunit.al @@ -20,6 +20,7 @@ codeunit 6205 "Transaction Storage ABS" InherentPermissions = X; Permissions = tabledata "Transact. Storage Task Entry" = R, tabledata "Transact. Storage Table Entry" = RM, + tabledata "Trans. Storage Export Data" = RD, tabledata "Table Metadata" = r, tabledata "Incoming Document Attachment" = r, tabledata "ABS Container" = ri; @@ -37,11 +38,11 @@ codeunit 6205 "Transaction Storage ABS" CollectedDocsCountTxt: Label 'Collected docs count', Locked = true; ExportedDocsCountTxt: Label 'Exported docs count', Locked = true; TablesExportedTxt: Label 'Tables were exported.', Locked = true; - CollectedTablesCountTxt: Label 'Collected tables count', Locked = true; ExportedTablesCountTxt: Label 'Exported tables count', Locked = true; ExportedToABSTxt: Label 'Exported to Azure Blob Storage using certificate authorized Azure Function', Locked = true; BlobFolderNameTxt: Label '%1_%2/%3', Comment = '%1 - aad tenant id, %2 - environment name, %3 - date', Locked = true; JsonBlobNameTxt: Label '%1/%2.json', Comment = '%1 - blob folder name, %2 - table name', Locked = true; + JsonBlobNameWithPartTxt: Label '%1/%2_%3.json', Comment = '%1 - blob folder name, %2 - table name, %3 - part', Locked = true; IncomingDocBlobNameTxt: Label '%1/%2-%3.%4', Comment = '%1 - blob folder name, %2 - incoming document entry no., %3 - incoming document name, %4 - incoming document extension', Locked = true; CannotGetAuthorityURLFromKeyVaultErr: Label 'Cannot get Authority URL from Azure Key Vault using key %1', Locked = true; CannotGetClientIdFromKeyVaultErr: Label 'Cannot get Client ID from Azure Key Vault using key %1', Locked = true; @@ -60,7 +61,7 @@ codeunit 6205 "Transaction Storage ABS" AzFuncEndpointBase64KeyTok: Label 'TransactionStorage-AzFuncEndpointBase64', Locked = true; [NonDebuggable] - procedure ArchiveTransactionsToABS(DataJsonArrays: Dictionary of [Integer, JsonArray]; IncomingDocs: Dictionary of [Text, Integer]) + procedure ArchiveTransactionsToABS(IncomingDocs: Dictionary of [Text, Integer]) var AzureFunctionsAuthentication: Codeunit "Azure Functions Authentication"; AzureFunctionsAuthForJson: Interface "Azure Functions Authentication"; @@ -76,51 +77,73 @@ codeunit 6205 "Transaction Storage ABS" AzureFunctionsAuthForDoc := AzureFunctionsAuthentication.CreateOAuth2WithCert(EndpointBase64, '', ClientID, Cert, AuthURL, '', ResourceURL); CurrentDate := Today(); - WriteJsonBlobsToABS(DataJsonArrays, AzureFunctionsAuthForJson, CurrentDate, ExportLog); + WriteJsonBlobsToABS(AzureFunctionsAuthForJson, CurrentDate, ExportLog); WriteIncomingDocumentsToABS(IncomingDocs, AzureFunctionsAuthForDoc, CurrentDate, ExportLog); WriteExportLog(ExportLog, AzureFunctionsAuthForJson, CurrentDate); FeatureTelemetry.LogUsage('0000LQ4', TransactionStorageTok, ExportedToABSTxt); end; [NonDebuggable] - local procedure WriteJsonBlobsToABS(DataJsonArrays: Dictionary of [Integer, JsonArray]; AzureFunctionsAuth: Interface "Azure Functions Authentication"; CurrentDate: Date; var ExportLog: JsonObject) + local procedure WriteJsonBlobsToABS(AzureFunctionsAuth: Interface "Azure Functions Authentication"; CurrentDate: Date; var ExportLog: JsonObject) var TableMetadata: Record "Table Metadata"; + TransStorageExportData: Record "Trans. Storage Export Data"; TransactStorageTableEntry: Record "Transact. Storage Table Entry"; - TransactStorageExport: Codeunit "Transact. Storage Export"; AzureFunctionsResponse: Codeunit "Azure Functions Response"; StringConversionManagement: Codeunit StringConversionManagement; - TableDataJsonArray: JsonArray; - TableID: Integer; ExportedTableCount: Integer; + TotalRecordCount: Integer; ContainerName: Text; BlobFolder: Text; BlobName: Text; JsonData: Text; CustomDimensions: Dictionary of [Text, Text]; BlobExpirationDate: Date; + InStream: InStream; begin + TransStorageExportData.SetAutoCalcFields(Content); + if not TransStorageExportData.FindSet() then + exit; + ContainerName := GetCompanyCVRNumber(); BlobFolder := GetBlobFolder(CurrentDate); BlobExpirationDate := GetBlobExpirationDate(CurrentDate); - foreach TableID in DataJsonArrays.Keys() do begin - TableDataJsonArray := DataJsonArrays.Get(TableID); - TableDataJsonArray.WriteTo(JsonData); - TableMetadata.Get(TableID); - BlobName := StrSubstNo(JsonBlobNameTxt, BlobFolder, StringConversionManagement.RemoveNonAlphaNumericCharacters(TableMetadata.Name)); - AzureFunctionsResponse := SendJsonTextToAzureFunction(AzureFunctionsAuth, ContainerName, BlobName, JsonData, BlobExpirationDate); - HandleAzureFunctionResponse(AzureFunctionsResponse, StrSubstNo(SendBlobBlockForTableTok, TableID, BlobName), TableID); - ExportedTableCount += 1; - ExportLog.Add(BlobName, TableDataJsonArray.Count()); - - if TransactStorageTableEntry.Get(TableID) then - TransactStorageExport.SetTableEntryProcessed(TransactStorageTableEntry, TransactStorageTableEntry."Filter Record To DT", true, CopyStr(BlobName, 1, MaxStrLen(TransactStorageTableEntry."Blob Name in ABS"))); - end; - CustomDimensions.Add(CollectedTablesCountTxt, Format(DataJsonArrays.Count())); + repeat + TransStorageExportData.SetRange("Table ID", TransStorageExportData."Table ID"); + TotalRecordCount := 0; + repeat + TotalRecordCount += TransStorageExportData."Record Count"; + TransStorageExportData.Content.CreateInStream(InStream); + InStream.ReadText(JsonData); + TableMetadata.Get(TransStorageExportData."Table ID"); + BlobName := + StrSubstNo( + JsonBlobNameWithPartTxt, BlobFolder, + StringConversionManagement.RemoveNonAlphaNumericCharacters(TableMetadata.Name), + TransStorageExportData.Part); + AzureFunctionsResponse := SendJsonTextToAzureFunction(AzureFunctionsAuth, ContainerName, BlobName, JsonData, BlobExpirationDate); + HandleAzureFunctionResponse( + AzureFunctionsResponse, StrSubstNo(SendBlobBlockForTableTok, TransStorageExportData."Table ID", BlobName), TransStorageExportData."Table ID"); + until TransStorageExportData.Next() = 0; + UpdateExportedTableData( + TransStorageExportData, TransactStorageTableEntry, ExportLog, ExportedTableCount, BlobName, TotalRecordCount); + until TransStorageExportData.Next() = 0; + TransStorageExportData.DeleteAll(true); CustomDimensions.Add(ExportedTablesCountTxt, Format(ExportedTableCount)); FeatureTelemetry.LogUsage('0000LQ6', TransactionStorageTok, TablesExportedTxt, CustomDimensions); end; + local procedure UpdateExportedTableData(var TransStorageExportData: Record "Trans. Storage Export Data"; var TransactStorageTableEntry: Record "Transact. Storage Table Entry"; var ExportLog: JsonObject; var ExportedTableCount: Integer; BlobName: Text; TotalRecordCount: Integer) + var + TransactStorageExport: Codeunit "Transact. Storage Export"; + begin + ExportedTableCount += 1; + ExportLog.Add(BlobName, TotalRecordCount); + if TransactStorageTableEntry.Get(TransStorageExportData."Table ID") then + TransactStorageExport.SetTableEntryProcessed(TransactStorageTableEntry, TransactStorageTableEntry."Filter Record To DT", true, CopyStr(BlobName, 1, MaxStrLen(TransactStorageTableEntry."Blob Name in ABS"))); + TransStorageExportData.SetRange("Table ID"); + end; + [NonDebuggable] local procedure WriteIncomingDocumentsToABS(IncomingDocs: Dictionary of [Text, Integer]; AzureFunctionsAuth: Interface "Azure Functions Authentication"; CurrentDate: Date; var ExportLog: JsonObject) var diff --git a/Build/DisabledTests/SustainabilityAPITests.json b/Build/DisabledTests/SustainabilityAPITests.json new file mode 100644 index 0000000000..5a6f777e04 --- /dev/null +++ b/Build/DisabledTests/SustainabilityAPITests.json @@ -0,0 +1,7 @@ +[ + { + "codeunitId": 148185, + "CodeunitName": "Sustainability API Tests", + "Method": "*" + } +] \ No newline at end of file