From 31d64a2452b1f578c772406b2ca85f116d4d7473 Mon Sep 17 00:00:00 2001 From: aholstrup1 Date: Mon, 18 Mar 2024 12:40:37 +0100 Subject: [PATCH] Syncing with version 25.0.17516.0 --- .github/AL-Go-Settings.json | 2 +- .../ContosoCoffeeDemoDatasetAT/app/app.json | 8 +- Apps/AT/HybridBCLast_AT/app/app.json | 10 +- Apps/AT/IntrastatAT/app/app.json | 8 +- .../ContosoCoffeeDemoDatasetAU/app/app.json | 8 +- Apps/AU/HybridBCLast_AU/app/app.json | 10 +- Apps/AU/Onprem Permissions AU/app/app.json | 6 +- .../ContosoCoffeeDemoDatasetBE/app/app.json | 8 +- Apps/BE/HybridBCLast_BE/app/app.json | 10 +- Apps/BE/IntrastatBE/app/app.json | 8 +- .../Codeunits/CreateCAGLAccounts.Codeunit.al | 2 +- .../ContosoCoffeeDemoDatasetCA/app/app.json | 8 +- Apps/CA/HybridBCLast_CA/app/app.json | 10 +- .../ContosoCoffeeDemoDatasetCH/app/app.json | 8 +- Apps/CH/HybridBCLast_CH/app/app.json | 10 +- Apps/CH/SwissQRBill/app/app.json | 6 +- .../SwissQRBillPurchases.Codeunit.al | 2 +- Apps/CH/SwissQRBill/test/app.json | 12 +- .../src/SwissQRBillTestPurchases.Codeunit.al | 39 +- .../CashDocumentPostHandlerCZZ.Codeunit.al | 12 + .../CrossApplicationHandlerCZZ.Codeunit.al | 157 +- .../GenJnlCheckLnHandlerCZZ.Codeunit.al | 14 + .../GenJnlPostBatchHandlerCZZ.Codeunit.al | 12 + .../PaymentOrderMgtHandlerCZZ.Codeunit.al | 15 +- .../PurchAdvLetterManagementCZZ.Codeunit.al | 1977 ++---------- .../PurchAdvLetterPostCZZ.Codeunit.al | 2745 +++++++++++++++++ .../Codeunits/PurchPostHandlerCZZ.Codeunit.al | 14 +- .../RelPurchAdvLetterDocCZZ.Codeunit.al | 4 +- .../RelSalesAdvLetterDocCZZ.Codeunit.al | 5 +- .../SalesAdvLetterManagementCZZ.Codeunit.al | 1786 ++--------- .../SalesAdvLetterPostCZZ.Codeunit.al | 2664 ++++++++++++++++ .../Codeunits/SalesPostHandlerCZZ.Codeunit.al | 14 +- .../VATAmountLineHandlerCZZ.Codeunit.al | 19 + .../VATPostingSetupHandlerCZZ.Codeunit.al | 6 +- .../PurchaseOrderCZZ.PageExt.al | 3 +- .../PageExtensions/SalesOrderCZZ.PageExt.al | 3 +- .../Pages/AdvanceLetterApplEditCZZ.Page.al | 19 +- .../Src/Pages/PurchAdvUsageFactBoxCZZ.Page.al | 23 +- .../Src/Pages/PurchAdvanceLetterCZZ.Page.al | 18 + .../Src/Pages/PurchAdvanceLettersCZZ.Page.al | 5 + .../Src/Pages/SalesAdvUsageFactBoxCZZ.Page.al | 23 +- .../app/Src/Pages/VATDocumentCZZ.Page.al | 19 +- .../SuggestWorksheetLinesCZZ.ReportExt.al | 17 +- .../app/Src/Reports/PurchAdvLettersRecap.xlsx | Bin 0 -> 36652 bytes .../Reports/PurchAdvLettersRecapCZZ.Report.al | 21 +- .../app/Src/Reports/PurchAdvanceLetters.xlsx | Bin 0 -> 37826 bytes .../Reports/PurchAdvanceLettersCZZ.Report.al | 21 +- .../PurchaseAdvanceLetterCZZ.Report.al | 16 +- .../PurchaseAdvanceVATDocCZZ.Report.al | 26 +- .../PurchaseInvoicewithAdvCZZ.Report.al | 74 +- .../app/Src/Reports/SalesAdvLettersRecap.xlsx | Bin 0 -> 45574 bytes .../Reports/SalesAdvLettersRecapCZZ.Report.al | 21 +- .../app/Src/Reports/SalesAdvanceLetter.rdl | 86 +- .../Reports/SalesAdvanceLetterCZZ.Report.al | 47 +- .../app/Src/Reports/SalesAdvanceLetters.xlsx | Bin 0 -> 44334 bytes .../Reports/SalesAdvanceLettersCZZ.Report.al | 21 +- .../Reports/SalesAdvanceVATDocCZZ.Report.al | 28 +- .../app/Src/Reports/SalesInvoiceWithAdv.rdl | 88 +- .../Reports/SalesInvoicewithAdvCZZ.Report.al | 67 +- .../CustLedgerEntryCZZ.TableExt.al | 19 + .../GenJournalLineCZZ.TableExt.al | 179 ++ .../PaymentOrderLineCZZ.TableExt.al | 40 +- .../PurchaseHeaderCZZ.TableExt.al | 34 +- .../SalesHeaderCZZ.TableExt.al | 34 +- .../VATPostingSetupCZZ.TableExt.al | 92 + .../VendorLedgerEntryCZZ.TableExt.al | 19 + .../AdvanceLetterApplicationCZZ.Table.al | 88 +- .../Tables/AdvancePostingBufferCZZ.Table.al | 16 +- .../AdvancePostingParametersCZZ.Table.al | 210 ++ .../Tables/PurchAdvLetterEntryCZZ.Table.al | 179 ++ .../Tables/PurchAdvLetterHeaderCZZ.Table.al | 48 +- .../Tables/SalesAdvLetterEntryCZZ.Table.al | 178 ++ .../Tables/SalesAdvLetterHeaderCZZ.Table.al | 149 +- .../AdvancePaymentsLocalization/app/app.json | 12 +- .../AdvancePaymentsLocalization/test/app.json | 20 +- .../CarryOutActionMsgReqCZA.ReportExt.al | 11 +- .../app/Src/Reports/OpenGLEntriesToDate.xlsx | Bin 0 -> 46407 bytes .../Reports/OpenGLEntriesToDateCZA.Report.al | 21 +- Apps/CZ/AdvancedLocalizationPack/app/app.json | 8 +- .../CZ/AdvancedLocalizationPack/test/app.json | 14 +- .../CrossApplicationHandlerCZB.Codeunit.al | 121 +- .../Codeunits/InstructionMgtCZB.Codeunit.al | 21 + .../IssueBankStatCreateJnlCZB.Codeunit.al | 6 +- .../IssueBankStatementCZB.Codeunit.al | 4 +- .../IssueBankStatementYesNoCZB.Codeunit.al | 6 +- .../IssuePaymentOrderCZB.Codeunit.al | 4 +- .../PaymentOrderManagementCZB.Codeunit.al | 30 +- .../app/Src/Pages/BankStatementCZB.Page.al | 27 + .../app/Src/Pages/BankStatementsCZB.Page.al | 27 + .../app/Src/Pages/IssBankStatementCZB.Page.al | 17 +- .../Src/Pages/IssBankStatementsCZB.Page.al | 17 +- .../Reports/CreateGeneralJournalCZB.Report.al | 32 +- .../CreatePaymentReconJnlCZB.Report.al | 49 +- .../Tables/BankStatementHeaderCZB.Table.al | 13 +- .../Tables/IssBankStatementHeaderCZB.Table.al | 48 +- .../Src/Tables/PaymentOrderHeaderCZB.Table.al | 13 +- .../Src/Tables/PaymentOrderLineCZB.Table.al | 221 +- .../BankingDocumentsLocalization/app/app.json | 8 +- .../test/app.json | 14 +- .../CashDeskManagementCZP.Codeunit.al | 17 +- .../CrossApplicationHandlerCZP.Codeunit.al | 131 +- .../Codeunits/PurchaseHandlerCZP.Codeunit.al | 3 +- .../Src/Codeunits/SalesHandlerCZP.Codeunit.al | 3 +- .../Src/Pages/CashDocumentSubformCZP.Page.al | 20 - .../PostedRcptCashDocumentCZP.Report.al | 6 +- .../PostedWdrlCashDocumentCZP.Report.al | 8 +- .../Reports/ReceiptCashDocumentCZP.Report.al | 8 +- .../WithdrawalCashDocumentCZP.Report.al | 8 +- .../app/Src/Tables/CashDeskCZP.Table.al | 12 +- .../Src/Tables/CashDocumentHeaderCZP.Table.al | 23 +- .../Src/Tables/CashDocumentLineCZP.Table.al | 147 +- Apps/CZ/CashDeskLocalization/app/app.json | 8 +- Apps/CZ/CashDeskLocalization/test/app.json | 14 +- .../CrossApplicationHandlerCZC.Codeunit.al | 95 +- .../app/Src/Reports/CompensationCZC.Report.al | 12 +- .../Src/Tables/CompensationHeaderCZC.Table.al | 8 +- .../Src/Tables/CompensationLineCZC.Table.al | 37 +- Apps/CZ/CompensationLocalization/app/app.json | 8 +- .../CZ/CompensationLocalization/test/app.json | 14 +- .../AccSchedExtensionMgtCZL.Codeunit.al | 5 +- .../CrossApplicationMgtCZL.Codeunit.al | 147 +- .../FormatAddressHandlerCZL.Codeunit.al | 33 + .../GenJnlPostLineHandlerCZL.Codeunit.al | 12 + .../GenJournalLineHandlerCZL.Codeunit.al | 10 + .../ItemJnlCheckLineHandlerCZL.Codeunit.al | 11 +- .../ReleaseSalesDocHandlerCZL.Codeunit.al | 6 + .../ServicePostingHandlerCZL.Codeunit.al | 6 + .../SubstituteReportHandlerCZL.Codeunit.al | 3 + .../PaymentMethodsCZL.PageExt.al | 15 + .../SalesReceivablesSetupCZL.PageExt.al | 26 +- .../CZCorePackObjectsCZL.PermissionSet.al | 1 + .../InventoryValuationCZL.ReportExt.al | 13 + .../InventoryValuationCZL.xlsx | Bin 0 -> 36945 bytes .../Reports/BlanketPurchaseOrderCZL.Report.al | 24 +- .../CreateStockkeepingUnitCZL.Report.al | 6 +- .../app/Src/Reports/CustBalReconciliation.rdl | 102 +- .../CustBalReconciliationCZL.Report.al | 2 +- .../app/Src/Reports/DocumentationForVAT.xlsx | Bin 0 -> 43788 bytes .../Reports/DocumentationforVATCZL.Report.al | 21 +- .../Reports/FinanceChargeMemoCZL.Report.al | 18 +- .../Src/Reports/OpenCustEntriestoDate.xlsx | Bin 0 -> 55817 bytes .../OpenCustEntriestoDateCZL.Report.al | 20 +- .../Src/Reports/OpenVendEntriestoDate.xlsx | Bin 0 -> 55862 bytes .../OpenVendEntriestoDateCZL.Report.al | 20 +- .../Src/Reports/PurchaseOrderCZL.Report.al | 24 +- .../Src/Reports/PurchaseQuoteCZL.Report.al | 24 +- .../app/Src/Reports/ReminderCZL.Report.al | 24 +- .../Src/Reports/SalesCreditMemoCZL.Report.al | 36 +- .../app/Src/Reports/SalesInvoice.rdl | 121 +- .../app/Src/Reports/SalesInvoiceCZL.Report.al | 67 +- .../SalesOrderConfirmationCZL.Report.al | 24 +- .../app/Src/Reports/SalesQuoteCZL.Report.al | 24 +- .../SalesReturnOrderConfirmCZL.Report.al | 24 +- .../Reports/SalesReturnRecieptCZL.Report.al | 20 +- .../Src/Reports/SalesShipmentCZL.Report.al | 32 +- .../Src/Reports/ServiceContractCZL.Report.al | 16 +- .../Reports/ServiceContractQuoteCZL.Report.al | 16 +- .../Reports/ServiceCreditMemoCZL.Report.al | 34 +- .../app/Src/Reports/ServiceInvoice.rdl | 111 +- .../Src/Reports/ServiceInvoiceCZL.Report.al | 64 +- .../app/Src/Reports/ServiceOrderCZL.Report.al | 24 +- .../app/Src/Reports/ServiceQuoteCZL.Report.al | 26 +- .../Src/Reports/ServiceShipmentCZL.Report.al | 20 +- .../Src/Reports/VendorBalReconciliation.rdl | 24 +- .../VendorBalReconciliationCZL.Report.al | 2 +- .../CustLedgerEntryCZL.TableExt.al | 18 +- .../EmployeeLedgerEntryCZL.TableExt.al | 18 +- .../IntrastatJnlBatchCZL.TableExt.al | 4 +- .../PaymentMethodCZL.TableExt.al | 13 + .../SalesHeaderCZL.TableExt.al | 71 +- .../SalesInvoiceHeaderCZL.TableExt.al | 67 + .../SalesReceivablesSetupCZL.TableExt.al | 24 + .../ServiceHeaderCZL.TableExt.al | 70 + .../ServiceInvoiceHeaderCZL.TableExt.al | 67 + .../VATAmountLineCZL.TableExt.al | 6 + .../VendorLedgerEntryCZL.TableExt.al | 18 +- .../Src/Tables/CompanyOfficialCZL.Table.al | 16 +- .../Tables/CrossApplicationBufferCZL.Table.al | 28 + .../app/Src/Tables/EETEntryCZL.Table.al | 4 +- .../Tables/VATCtrlReportHeaderCZL.Table.al | 12 +- .../Tables/VIESDeclarationHeaderCZL.Table.al | 6 +- Apps/CZ/CoreLocalizationPack/app/app.json | 22 +- Apps/CZ/CoreLocalizationPack/test/app.json | 12 +- .../CalcNormalDeprHandlerCZF.Codeunit.al | 11 +- .../FADisposalHandlerCZF.Codeunit.al | 11 + .../Codeunits/FAHistoryHandlerCZF.Codeunit.al | 4 +- .../FAHistoryManagementCZF.Codeunit.al | 4 +- .../Reports/InitializeFAHistoryCZF.Report.al | 5 +- Apps/CZ/FixedAssetLocalization/app/app.json | 8 +- .../test/Src/FixedAssetsCZF.Codeunit.al | 8 +- Apps/CZ/FixedAssetLocalization/test/app.json | 14 +- Apps/CZ/HybridBCLast_CZ/app/app.json | 10 +- Apps/CZ/IntrastatCZ/app/app.json | 18 +- Apps/CZ/Onprem Permissions CZ/app/app.json | 6 +- .../DACH/Onprem Permissions DACH/app/app.json | 6 +- .../ContosoCoffeeDemoDatasetDE/app/app.json | 8 +- Apps/DE/Elster/app/app.json | 6 +- .../src/Tables/SalesVATAdvanceNotif.Table.al | 18 +- Apps/DE/Elster/test/app.json | 14 +- Apps/DE/HybridBCLast_DE/app/app.json | 10 +- Apps/DE/IntrastatDE/app/app.json | 8 +- Apps/DK/C52012DataMigration/app/app.json | 6 +- Apps/DK/C52012DataMigration/test/app.json | 10 +- .../ContosoCoffeeDemoDatasetDK/app/app.json | 8 +- Apps/DK/DKCore/app/app.json | 6 +- Apps/DK/DKCore/test/app.json | 14 +- Apps/DK/EDocumentFormatOIOUBL/app/app.json | 32 +- .../ElectronicVATDeclarationDK/app/app.json | 25 +- .../ElecVATDeclCryptography.Codeunit.al | 6 +- .../ElectronicVATDeclarationDK/test/app.json | 60 +- .../DK/EnforcedDigitalVouchersDK/app/app.json | 86 +- .../src/DigitalVoucherDKInstall.Codeunit.al | 3 + .../EnforcedDigitalVouchersDK/test/app.json | 116 +- Apps/DK/FIK/app/app.json | 6 +- Apps/DK/FIK/test/app.json | 12 +- Apps/DK/ImportDKPayroll/app/app.json | 6 +- Apps/DK/ImportDKPayroll/test/app.json | 10 +- Apps/DK/NemhandelNotification/app/app.json | 90 +- Apps/DK/NemhandelNotification/test/app.json | 96 +- Apps/DK/OIOUBL/app/app.json | 6 +- .../OIOUBLCreateElecCrMemos.Report.al | 12 +- .../OIOUBLCreateElecInvoices.Report.al | 12 +- Apps/DK/OIOUBL/test/app.json | 14 +- .../OIOUBLCheckSalesandService.Codeunit.al | 4 +- .../OIOUBLERMElecDocumentSales.Codeunit.al | 2 +- .../src/OIOUBLERMMiscElecInvoice.Codeunit.al | 8 +- Apps/DK/SAFTModificationDK/app/app.json | 10 +- Apps/DK/SAFTModificationDK/test/app.json | 16 +- Apps/DK/VATReportsDK/app/app.json | 6 +- Apps/DK/VATReportsDK/test/app.json | 10 +- .../ContosoCoffeeDemoDatasetES/app/app.json | 8 +- Apps/ES/HybridBCLast_ES/app/app.json | 10 +- Apps/ES/IntrastatES/app/app.json | 8 +- Apps/ES/Onprem Permissions ES/app/app.json | 6 +- .../ContosoCoffeeDemoDatasetFI/app/app.json | 8 +- Apps/FI/FICore/app/app.json | 6 +- Apps/FI/FICore/test/app.json | 10 +- Apps/FI/IntrastatFI/app/app.json | 8 +- .../ContosoCoffeeDemoDatasetFR/app/app.json | 8 +- Apps/FR/FECAuditFile/app/app.json | 12 +- Apps/FR/FECAuditFile/test/app.json | 14 +- Apps/FR/HybridBCLast_FR/app/app.json | 10 +- Apps/FR/IntrastatFR/app/app.json | 8 +- Apps/FR/IntrastatFR/test/app.json | 18 +- Apps/FR/Onprem Permissions FR/app/app.json | 6 +- Apps/FR/ServiceDeclarationFR/app/app.json | 8 +- Apps/FR/ServiceDeclarationFR/test/app.json | 16 +- .../ContosoCoffeeDemoDatasetGB/app/app.json | 8 +- Apps/GB/IntrastatGB/app/app.json | 8 +- Apps/GB/IntrastatGB/test/app.json | 18 +- Apps/GB/UKMakingTaxDigital/app/app.json | 6 +- .../src/Connection/MTDOAuth20Mgt.Codeunit.al | 37 +- Apps/GB/UKMakingTaxDigital/test/app.json | 14 +- .../src/LibraryMakingTaxDigital.Codeunit.al | 22 +- Apps/GB/UKPostcodeGetAddressIO/app/app.json | 6 +- .../app/src/GetAddressioConfig.Page.al | 3 +- .../src/PostcodeGetAddressioConfig.Table.al | 30 +- .../PostcodeServiceGetAddressio.Codeunit.al | 21 +- Apps/GB/UKPostcodeGetAddressIO/test/app.json | 12 +- .../app/ChargeGroupBase/app.json | 10 +- .../app/ChargeOnPurchase/app.json | 12 +- .../ThirdPartyPurchaseMgmt.Codeunit.al | 4 +- .../INChargeGroup/app/ChargeOnSales/app.json | 12 +- Apps/IN/INChargeGroup/app/app.json | 10 +- Apps/IN/INChargeGroup/test/app.json | 22 +- Apps/IN/INDataMigration/app.json | 16 +- Apps/IN/INFADepreciation/app/app.json | 6 +- Apps/IN/INFADepreciation/test/app.json | 12 +- .../test/src/FADepreciation.Codeunit.al | 6 +- Apps/IN/INGST/app/GSTApplication/app.json | 18 +- Apps/IN/INGST/app/GSTBase/app.json | 10 +- .../Codeunit/GSTBaseValidation.Codeunit.al | 42 + .../src/Codeunit/GSTStatistics.Codeunit.al | 172 ++ .../GSTTaxConfiguration.Codeunit.al | 10 +- Apps/IN/INGST/app/GSTDistribution/app.json | 12 +- .../src/Codeunit/GSTDistribution.Codeunit.al | 6 +- .../GSTDistributionSubcsribers.codeunit.al | 4 +- .../src/table/GSTDistributionHeader.table.al | 7 +- Apps/IN/INGST/app/GSTPayments/app.json | 16 +- Apps/IN/INGST/app/GSTPurchase/app.json | 12 +- .../GSTPurchaseOrderStats.PageExt.al | 26 + Apps/IN/INGST/app/GSTReconcilation/app.json | 12 +- .../GSTReconcilationMatch.Codeunit.al | 16 + .../IN/INGST/app/GSTReturnSettlement/app.json | 18 +- .../src/codeunit/GSTJournalPost.Codeunit.al | 21 +- .../src/codeunit/GSTSettlement.Codeunit.al | 20 +- .../src/page/GSTCreditAdjustment.page.al | 7 +- .../src/page/GSTLiabilityAdjustment.page.al | 4 +- .../src/table/GSTJournalLine.table.al | 9 +- Apps/IN/INGST/app/GSTSales/app.json | 12 +- .../src/Codeunit/GSTShiptoAddress.Codeunit.al | 14 +- .../GSTSalesOrderStats.PageExt.al | 26 + Apps/IN/INGST/app/GSTService/app.json | 12 +- .../GSTServiceShiptoAddress.Codeunit.al | 5 +- .../GSTServiceValidations.Codeunit.al | 20 + .../GSTServiceCrMemoSubform.PageExt.al | 5 + .../GSTServiceCreditMemo.PageExt.al | 18 + Apps/IN/INGST/app/GSTServiceTransfer/app.json | 12 +- .../codeunit/ServiceTransferPost.codeunit.al | 10 +- .../src/table/ServiceTransferHeader.table.al | 8 +- Apps/IN/INGST/app/GSTStockTransfer/app.json | 12 +- .../EInvJsonHandlerForTransShpt.Codeunit.al | 663 ++++ .../EInvTransShptJsonManagement.Codeunit.al | 123 + .../GSTTransferOrderReceipt.Codeunit.al | 26 +- .../GSTTransferOrderShipment.Codeunit.al | 34 +- .../src/page/TransferShipmentDialog.Page.al | 67 + .../src/page/TransferShipmentQRCode.Page.al | 42 + .../GSTPostedTransShipmentExt.PageExt.al | 160 +- .../GSTTransShipmentHeaderExt.TableExt.al | 42 + .../GSTTransferHeaderExt.TableExt.al | 42 + Apps/IN/INGST/app/GSTSubcontracting/app.json | 10 +- .../Codeunit/SubcontractingPost.Codeunit.al | 2 +- .../SubcontractingPostGSTLiab.Codeunit.al | 6 +- .../src/Table/DeliveryChallanHeader.Table.al | 21 +- .../Table/MultipleSubconOrderDetails.Table.al | 20 +- .../SubcontractorDeliveryChallan.Table.al | 9 +- .../INAdvanceObjectsIndiaGST.PermissionSet.al | 2 + .../app/Translations/India GST.en-GB.xlf | 15 +- .../app/Translations/India GST.en-US.xlf | 15 +- Apps/IN/INGST/app/app.json | 12 +- Apps/IN/INGST/test/GSTBase/app.json | 16 +- .../CalculateDepreciationTests.Codeunit.al | 4 +- .../src/GSTStockTransferTests.Codeunit.al | 101 +- Apps/IN/INGST/test/GSTPayments/app.json | 20 +- Apps/IN/INGST/test/GSTPurchase/app.json | 18 +- .../src/GSTPurchaseReg.Codeunit.al | 4 +- .../GSTAdjustmentJournalTests.Codeunit.al | 4 +- Apps/IN/INGST/test/GSTSales/app.json | 22 +- .../GSTServiceShipToAddrTests.Codeunit.al | 86 +- Apps/IN/INGST/test/GSTSubcontracting/app.json | 20 +- .../src/GSTSubcontracting.Codeunit.al | 4 +- Apps/IN/INGST/test/app.json | 18 +- Apps/IN/INGateEntry/app/app.json | 10 +- .../src/codeunit/GateEntryPost.Codeunit.al | 5 +- .../app/src/table/GateEntryHeader.Table.al | 24 +- Apps/IN/INGateEntry/test/app.json | 14 +- .../test/src/GateEntryLibrary.Codeunit.al | 6 +- Apps/IN/INReports/app/app.json | 18 +- Apps/IN/INReports/test/app.json | 24 +- Apps/IN/INTCS/app/TCSBase/app.json | 10 +- Apps/IN/INTCS/app/TCSOnReceipt/app.json | 12 +- .../TCSOnReceiptOfPmtHandler.Codeunit.al | 4 +- Apps/IN/INTCS/app/TCSOnSales/app.json | 12 +- .../codeunit/TCSSalesManagement.Codeunit.al | 58 + .../SalesOrderStatistics.PageExt.al | 25 + .../INTCS/app/TCSReturnAndSettlement/app.json | 12 +- .../codeunit/PostTCSJnlLine.codeunit.al | 32 +- .../TCS-Journal/table/TCSJournalLine.table.al | 8 +- Apps/IN/INTCS/app/app.json | 10 +- Apps/IN/INTCS/test/TCSBase/app.json | 16 +- Apps/IN/INTCS/test/TCSOnReceipt/app.json | 22 +- Apps/IN/INTCS/test/TCSOnSales/app.json | 20 +- .../TCSOnSales/src/TCSOnSales.Codeunit.al | 14 +- .../src/TCSOnSalesDocuments.Codeunit.al | 2 +- .../test/TCSReturnAndSettlement/app.json | 18 +- Apps/IN/INTCS/test/app.json | 20 +- Apps/IN/INTDS/app/TDSBase/app.json | 10 +- .../TDSTaxConfiguration.Codeunit.al | 2 +- Apps/IN/INTDS/app/TDSForCustomer/app.json | 12 +- Apps/IN/INTDS/app/TDSOnPayments/app.json | 14 +- Apps/IN/INTDS/app/TDSOnPurchase/app.json | 12 +- .../src/codeunit/TDSStatistics.Codeunit.al | 58 + .../PurchaseOrderStatistics.PageExt.al | 26 + .../INTDS/app/TDSReturnAndSettlement/app.json | 14 +- .../TDS-Journal/TDSAdjustmentPost.codeunit.al | 33 +- .../src/TDS-Journal/TDSJournalLine.table.al | 8 +- .../app/Translations/India TDS.en-GB.xlf | 2 +- .../app/Translations/India TDS.en-US.xlf | 2 +- Apps/IN/INTDS/app/app.json | 10 +- Apps/IN/INTDS/test/TDSBase/app.json | 16 +- Apps/IN/INTDS/test/TDSOnCustomer/app.json | 24 +- Apps/IN/INTDS/test/TDSOnPayments/app.json | 16 +- Apps/IN/INTDS/test/TDSOnPurchase/app.json | 16 +- .../test/TDSReturnAndSettlement/app.json | 20 +- Apps/IN/INTDS/test/app.json | 20 +- Apps/IN/INTaxBase/app/app.json | 8 +- .../codeunit/CalculateStatistics.Codeunit.al | 157 +- .../PurchOrdStatistics.PageExt.al | 24 + .../SalesOrdStatistics.PageExt.al | 24 + .../app/src/table/PostingNoSeries.table.al | 108 +- Apps/IN/INTaxBase/test/app.json | 10 +- Apps/IN/INVoucherInterface/app/app.json | 10 +- Apps/IN/INVoucherInterface/test/app.json | 20 +- Apps/IN/QRGeneration/app/app.json | 6 +- .../ContosoCoffeeDemoDatasetIS/app/app.json | 8 +- Apps/IS/ISCore/app/app.json | 6 +- .../src/Codeunits/EnableISCoreApp.Codeunit.al | 2 + .../app/src/Codeunits/ISCore.Codeunit.al | 58 +- .../ISPostedPurchCreditMemo.PageExt.al | 6 + .../ISPostedPurchaseInvoice.PageExt.al | 7 + Apps/IS/ISCore/test/app.json | 20 +- .../ContosoCoffeeDemoDatasetIT/app/app.json | 8 +- Apps/IT/HybridBCLast_IT/app/app.json | 10 +- Apps/IT/IntrastatIT/app/app.json | 8 +- Apps/IT/IntrastatIT/test/app.json | 16 +- .../test/src/LibraryITIntrastat.Codeunit.al | 4 +- Apps/IT/ServiceDeclarationIT/app/app.json | 8 +- Apps/IT/ServiceDeclarationIT/test/app.json | 16 +- .../src/LibraryITServDeclaration.Codeunit.al | 4 +- .../ContosoCoffeeDemoDatasetMX/app/app.json | 8 +- Apps/MX/HybridBCLast_MX/app/app.json | 10 +- Apps/NA/Ceridian/app.json | 6 +- Apps/NA/EnvestnetYodleeBankFeeds/app/app.json | 7 +- .../app/src/MSYodleeBankServiceSetup.Table.al | 1 + .../app/src/MSYodleeServiceMgt.Codeunit.al | 66 +- .../app/src/PasswordHelper.Codeunit.al | 37 +- .../app/src/YodleeAPIStrings.Codeunit.al | 22 + .../NA/EnvestnetYodleeBankFeeds/test/app.json | 14 +- .../src/MSYodleeBankServiceTests.Codeunit.al | 12 +- Apps/NA/MX_DIOT/app/app.json | 8 +- Apps/NA/MX_DIOT/test/app.json | 12 +- .../Permissions/bankrecpost.permissionset.al | 2 + Apps/NA/Onprem Permissions NA/app/app.json | 6 +- .../ContosoCoffeeDemoDatasetNL/app/app.json | 8 +- Apps/NL/IntrastatNL/app/app.json | 8 +- Apps/NL/NLDigitalTaxDeclaration/app/app.json | 6 +- Apps/NL/NLDigitalTaxDeclaration/test/app.json | 14 +- .../test/src/DigipoortXML.Codeunit.al | 4 +- .../ContosoCoffeeDemoDatasetNO/app/app.json | 8 +- ...lectronicvatsubmission.permissionsetext.al | 2 +- ...lectronicvatsubmission.permissionsetext.al | 2 +- ...lectronicvatsubmission.permissionsetext.al | 2 +- Apps/NO/ElectronicVATSubmission/app/app.json | 8 +- .../Connection/ElecVATOAuthMgt.Codeunit.al | 51 +- .../app/src/Setup/ElecVATSetup.Table.al | 11 +- .../app/src/Setup/ElecVATUpgrade.Codeunit.al | 29 + .../ElectronicVATInstallation.Codeunit.al | 6 +- .../src/Setup/ElectronicVATSetupCard.Page.al | 5 + .../ElecVATDataMgt.Codeunit.al | 2 +- Apps/NO/ElectronicVATSubmission/test/app.json | 12 +- .../src/ElecVATSubmissionDemodata.Codeunit.al | 2 + Apps/NO/ImportNOPayroll/app/app.json | 6 +- Apps/NO/ImportNOPayroll/test/app.json | 12 +- Apps/NO/NorwegianSAFT/app/app.json | 6 +- .../Export Engine/SAFTExportMgt.Codeunit.al | 2 +- Apps/NO/NorwegianSAFT/test/app.json | 12 +- .../ContosoCoffeeDemoDatasetNZ/app/app.json | 8 +- Apps/NZ/HybridBCLast_NZ/app/app.json | 10 +- Apps/RU/CDTracking/app/app.json | 6 +- Apps/RU/CDTracking/test/app.json | 14 +- .../test/src/LibraryCDTracking.Codeunit.al | 4 +- Apps/RU/Onprem Permissions RU/app/app.json | 6 +- .../ContosoCoffeeDemoDatasetSE/app/app.json | 8 +- Apps/SE/IntrastatSE/app/app.json | 8 +- Apps/SE/SECore/app/app.json | 6 +- Apps/SE/SECore/test/app.json | 10 +- Apps/SE/SIE/app/app.json | 8 +- .../src/ImportEngineSIE/ImportSIE.Report.al | 6 +- Apps/SE/SIE/test/app.json | 16 +- .../ContosoCoffeeDemoDatasetUS/app/app.json | 8 +- Apps/US/HybridBCLast_US/app/app.json | 10 +- Apps/US/HybridGP_US/app/app.json | 10 +- .../GPPopulateVendor1099Data.Codeunit.al | 14 +- Apps/US/HybridGP_US/test/app.json | 12 +- .../src/MigrationVendor1099Tests.Codeunit.al | 6 + Apps/US/IRS1096/app/app.json | 6 +- .../src/Processing/IRS1096FormHeader.Table.al | 11 +- .../src/Processing/IRS1096FormLine.Table.al | 7 + .../src/Processing/IRS1096FormMgt.Codeunit.al | 20 + .../src/Processing/IRS1096FormSubform.Page.al | 2 + Apps/US/IRS1096/test/app.json | 14 +- .../test/src/Create1096FormsTest.Codeunit.al | 7 +- Apps/US/IRSForms/app/ExtensionLogo.png | Bin 0 -> 5446 bytes .../D365BasicIRSForms.PermissionsetExt.al | 12 + .../D365BasicISVIRSForms.PermissionsetExt.al | 12 + .../D365ReadIRSForms.PermissionsetExt.al | 12 + ...D365TeamMemberIRSForms.PermissionsetExt.al | 12 + .../Permissions/IRSFormsEdit.PermissionSet.al | 27 + .../IRSFormsObjects.PermissionSet.al | 51 + .../Permissions/IRSFormsRead.PermissionSet.al | 26 + ...telligentCloudIRSForms.PermissionsetExt.al | 12 + .../LocalIRSForms.PermissionsetExt.al | 12 + Apps/US/IRSForms/app/app.json | 40 + .../src/Document/IRS1099CalcParams.Table.al | 35 + .../Document/IRS1099CreateFormDocs.Report.al | 145 + .../Document/IRS1099FormDocHeader.Table.al | 160 + .../src/Document/IRS1099FormDocLine.Table.al | 135 + .../IRS1099FormDocLineDetail.Table.al | 62 + .../IRS1099FormDocLineDetails.Page.al | 43 + .../src/Document/IRS1099FormDocStatus.Enum.al | 24 + .../Document/IRS1099FormDocSubform.Page.al | 59 + .../Document/IRS1099FormDocsImpl.Codeunit.al | 151 + .../Document/IRS1099FormDocument.Codeunit.al | 102 + .../src/Document/IRS1099FormDocument.Page.al | 277 ++ .../src/Document/IRS1099FormDocuments.Page.al | 162 + .../src/Emailing/IRS1099EmailQueue.Table.al | 36 + .../Emailing/IRS1099EmailReportType.Enum.al | 20 + .../IRS1099ProcessEmailQueue.Codeunit.al | 54 + .../src/Emailing/IRS1099SendEmail.Codeunit.al | 223 ++ .../src/Emailing/IRS1099SendEmail.Report.al | 123 + .../Emailing/IRS1099VendorEmail.Codeunit.al | 97 + .../IRS1099BaseAppSubscribers.Codeunit.al | 187 ++ .../Extensions/IRS1099GenJnlLine.TableExt.al | 49 + .../IRS1099GeneralJournal.PageExt.al | 74 + .../IRS1099PostedGenJnlLine.TableExt.al | 33 + .../IRS1099PostedPurchCrMemo.PageExt.al | 63 + .../IRS1099PostedPurchInv.PageExt.al | 63 + .../Extensions/IRS1099PurchCrMemo.PageExt.al | 82 + .../IRS1099PurchCrMemoHeader.TableExt.al | 39 + .../Extensions/IRS1099PurchHeader.TableExt.al | 40 + .../IRS1099PurchHeaderArchive.TableExt.al | 29 + .../src/Extensions/IRS1099PurchInv.PageExt.al | 82 + .../IRS1099PurchInvHeader.TableExt.al | 39 + .../Extensions/IRS1099PurchOrder.PageExt.al | 82 + .../IRS1099PurchaseJournal.PageExt.al | 53 + .../src/Extensions/IRS1099Vendor.TableExt.al | 77 + .../Extensions/IRS1099VendorCard.PageExt.al | 135 + .../IRS1099VendorLedgerEntries.PageExt.al | 73 + .../IRS1099VendorLedgerEntry.TableExt.al | 74 + .../Extensions/IRS1099VendorList.PageExt.al | 80 + .../IRS1099CreateFormDocs.Interface.al | 18 + .../Interface/IRS1099FormBoxCalc.Interface.al | 18 + .../Interface/IRS1099FormInstruction.Table.al | 43 + .../Interface/IRS1099Printing.Interface.al | 24 + .../src/Interface/IRSFormsFacade.Codeunit.al | 33 + .../Interface/IRSFormsImplementation.Enum.al | 18 + .../IRSFormsOrchestrator.Codeunit.al | 35 + .../app/src/Printing/IRS 1099 Print.docx | Bin 0 -> 27144 bytes .../src/Printing/IRS1099Dataset.Codeunit.al | 79 + .../Printing/IRS1099FormInstructions.Page.al | 41 + .../src/Printing/IRS1099FormReport.Table.al | 53 + .../Printing/IRS1099FormReportType.Enum.al | 25 + .../src/Printing/IRS1099FormReports.Page.al | 30 + .../src/Printing/IRS1099FormStatement.Page.al | 64 + .../IRS1099FormStatementLine.Table.al | 124 + .../app/src/Printing/IRS1099Print.Report.al | 192 ++ .../src/Printing/IRS1099PrintParams.Table.al | 19 + .../Printing/IRS1099PrintValueType.Enum.al | 20 + .../Printing/IRS1099PrintingImpl.Codeunit.al | 54 + .../Printing/IRS1099ProtectTINType.Enum.al | 24 + .../src/Printing/IRS1099ReportLine.Table.al | 37 + .../src/Setup/IRS1099CopySetupFrom.Report.al | 63 + .../app/src/Setup/IRS1099Form.Table.al | 76 + .../app/src/Setup/IRS1099FormBox.Table.al | 66 + .../app/src/Setup/IRS1099FormBoxes.Page.al | 56 + .../app/src/Setup/IRS1099Forms.Page.al | 100 + .../IRS1099TransErrorHandler.Codeunit.al | 33 + .../IRS1099TransferFromBaseApp.Codeunit.al | 217 ++ .../app/src/Setup/IRSFormsData.Codeunit.al | 276 ++ .../app/src/Setup/IRSFormsFeature.Codeunit.al | 165 + .../app/src/Setup/IRSFormsGuide.Page.al | 554 ++++ .../app/src/Setup/IRSFormsInstall.Codeunit.al | 41 + .../app/src/Setup/IRSFormsSetup.Page.al | 77 + .../app/src/Setup/IRSFormsSetup.Table.al | 117 + .../src/Setup/IRSReportingPeriod.Codeunit.al | 132 + .../app/src/Setup/IRSReportingPeriod.Table.al | 104 + .../app/src/Setup/IRSReportingPeriods.Page.al | 147 + .../IRS1099FormBoxBufferType.Enum.al | 19 + .../IRS1099FormBoxCalcImpl.Codeunit.al | 276 ++ .../IRS1099PropagateVendSetup.Report.al | 144 + .../IRS1099SuggestVendors.Report.al | 41 + .../IRS1099VendFormBoxAdjmts.Page.al | 69 + .../IRS1099VendFormBoxBuffer.Table.al | 77 + .../IRS1099VendorFormBox.Codeunit.al | 27 + .../IRS1099VendorFormBoxAdj.Table.al | 54 + .../IRS1099VendorFormBoxSetup.Page.al | 121 + .../IRS1099VendorFormBoxSetup.Table.al | 53 + .../IRSForms/test library/ExtensionLogo.png | Bin 0 -> 5446 bytes Apps/US/IRSForms/test library/app.json | 46 + .../src/IRSFormsEnableFeature.Codeunit.al | 21 + .../src/LibraryIRS1099Document.Codeunit.al | 211 ++ .../src/LibraryIRS1099FormBox.Codeunit.al | 182 ++ .../src/LibraryIRSReportingPeriod.Codeunit.al | 46 + Apps/US/IRSForms/test/ExtensionLogo.png | Bin 0 -> 5446 bytes Apps/US/IRSForms/test/app.json | 63 + .../test/src/IRS1099DocumentTests.Codeunit.al | 394 +++ .../test/src/IRS1099E2ETests.Codeunit.al | 142 + .../test/src/IRS1099FormCalcTests.Codeunit.al | 467 +++ .../test/src/IRS1099PrintingTests.Codeunit.al | 268 ++ .../test/src/IRS1099VendorTests.Codeunit.al | 346 +++ .../src/IRSReportingPeriodTests.Codeunit.al | 169 + .../W1/AMCBanking365Fundamentals/app/app.json | 6 +- .../AMCBanking365Fundamentals/test/app.json | 14 +- Apps/W1/APIReportsFinance/App/app.json | 6 +- Apps/W1/APIV1/app/app.json | 6 +- ...tedBCAdminAgentPartnerAPIV1.Entitlement.al | 9 + ...nternalBCAdministratorAPIV1.Entitlement.al | 9 + Apps/W1/APIV1/test/app.json | 14 +- .../test/src/APIV1EmployeesE2E.Codeunit.al | 12 +- Apps/W1/APIV2/app/app.json | 6 +- ...tedBCAdminAgentPartnerAPIV2.Entitlement.al | 9 + ...nternalBCAdministratorAPIV2.Entitlement.al | 9 + .../APIV2/app/src/pages/APIV2Contacts.Page.al | 10 + .../app/src/pages/APIV2DisputeStatus.Page.al | 40 + .../app/src/pages/APIV2SalesInvoices.Page.al | 47 + Apps/W1/APIV2/test/app.json | 14 +- .../test/src/APIV2ContactsE2E.Codeunit.al | 14 +- .../test/src/APIV2EmployeesE2E.Codeunit.al | 12 +- Apps/W1/AuditFileExport/app/app.json | 6 +- Apps/W1/AuditFileExport/test/app.json | 12 +- Apps/W1/AutomaticAccountCodes/app/app.json | 6 +- Apps/W1/AutomaticAccountCodes/test/app.json | 14 +- Apps/W1/BankAccRecWithAI/app/app.json | 81 +- .../app/src/BankAccRecTransToAcc.Codeunit.al | 20 +- .../BankAccReconciliationListExt.PageExt.al | 22 +- .../app/src/BankRecAIMatchingImpl.Codeunit.al | 4 +- Apps/W1/BankAccRecWithAI/test/app.json | 108 +- Apps/W1/BankDeposits/app/app.json | 6 +- .../app/src/tables/BankDepositHeader.Table.al | 11 +- Apps/W1/BankDeposits/test/app.json | 12 +- Apps/W1/BasicExperience/app/app.json | 6 +- Apps/W1/BasicExperience/test/app.json | 10 +- Apps/W1/ClientAddIns/app.json | 6 +- ...tedBCAdminAgentPartnerCOHUB.Entitlement.al | 10 + ...nternalBCAdministratorCOHUB.Entitlement.al | 10 + Apps/W1/CompanyHub/app/app.json | 6 +- Apps/W1/ConnectivityApps/app/app.json | 8 +- Apps/W1/ConnectivityApps/test/app.json | 14 +- .../CreateCommonNoSeries.Codeunit.al | 63 + .../CreateCommonPurchaseSetup.Codeunit.al | 12 + .../CreateCommonSalesSetup.Codeunit.al | 6 + .../Jobs/3.Transactions/CreateJob.Codeunit.al | 90 +- .../CreateSvcNoSeries.Codeunit.al | 16 + .../1.Setup Data/CreateSvcSetup.Codeunit.al | 4 + .../Warehousing/WhseDemoDataSetup.Table.al | 1 + .../Contoso Helpers/ContosoItem.Codeunit.al | 6 +- .../Contoso Helpers/ContosoJob.Codeunit.al | 21 +- .../ContosoPurchase.Codeunit.al | 10 +- .../ContosoUtilities.Codeunit.al | 2 +- .../DemoTool/ContosoDemoDataModule.Enum.al | 4 - Apps/W1/ContosoCoffeeDemoDataset/app/app.json | 93 +- .../W1/ContosoCoffeeDemoDataset/test/app.json | 82 +- .../CrossEnvironmentIntercompany/app/app.json | 48 +- Apps/W1/DataArchive/App/app.json | 6 +- Apps/W1/DataArchive/test/app.json | 10 +- Apps/W1/DataCorrectionFA/app/app.json | 10 +- .../App/DataSearchEvents.codeunit.al | 14 + .../App/DataSearchInTable.codeunit.al | 6 + .../App/DataSearchObjectMapping.Codeunit.al | 59 + Apps/W1/DataSearch/App/app.json | 6 +- Apps/W1/DataSearch/test/app.json | 28 +- Apps/W1/DynamicsGPHistoricalData/app/app.json | 6 +- .../W1/DynamicsGPHistoricalData/test/app.json | 10 +- .../DynamicsGPHistorySmartLists/app/app.json | 8 +- .../EDocCoreBasic.PermissionSet.al | 4 +- .../EDocCoreObjects.PermissionSet.al | 9 +- Apps/W1/EDocument/app/app.json | 70 +- .../app/src/Document/EDocument.Page.al | 131 +- .../app/src/Document/EDocument.Table.al | 2 +- .../Document/EDocumentServiceStatus.Enum.al | 4 +- .../app/src/Document/EDocuments.Page.al | 32 +- .../app/src/EDocumentInstall.Codeunit.al | 21 +- .../Extensions/EDocOrderMapActivities.Page.al | 47 +- .../Extensions/EDocPostedSalesInv.PageExt.al | 1 - .../EDocPurchPayablesSetup.PageExt.al | 21 + .../EDocPurchPayablesSetup.TableExt.al | 12 + .../Extensions/EDocPurchaseOrder.PageExt.al | 46 +- .../EDocPurchaseOrderList.PageExt.al | 45 +- .../Extensions/EDocumentActivities.Page.al | 8 +- .../Format/EDocImportPEPPOLBIS30.Codeunit.al | 3 + .../Helpers/EDocumentErrorHelper.Codeunit.al | 13 + .../Helpers/EDocumentImportHelper.Codeunit.al | 21 + .../app/src/Processing/EDocImport.Codeunit.al | 228 +- .../EDocumentCopilotCapability.EnumExt.al | 11 + .../EDocumentCreateJnlLine.Codeunit.al | 4 +- .../EDocumentProcessing.Codeunit.al | 24 +- .../EDocumentSubscription.Codeunit.al | 43 +- .../Copilot/EDocAOAITools.Interface.al | 28 + .../Copilot/EDocPOAOAIFunction.Codeunit.al | 93 + .../Copilot/EDocPOCopilotMatching.Codeunit.al | 384 +++ .../Copilot/EDocPOCopilotProp.Page.al | 318 ++ .../Copilot/EDocPOMatchPropBuffer.Table.al | 111 + .../Copilot/EDocPOMatchPropSub.Page.al | 100 + .../OrderMatching/EDocImportedLine.Table.al | 13 +- .../EDocLineMatching.Codeunit.al | 71 +- .../EDocOrderLineMatching.Page.al | 107 +- .../OrderMatching/EDocOrderMatch.Page.al | 21 +- .../OrderMatching/EDocOrderMatch.Table.al | 40 +- .../OrderMatching/EDocOrderMatchAct.Page.al | 44 + .../app/src/Service/EDocumentService.Table.al | 11 + .../Service/EDocumentServiceStatus.Table.al | 3 + .../Setup/EDocumentSendingProfile.PageExt.al | 2 +- .../CreateEDocumentSetup.Codeunit.al | 116 + .../CreateEDocumentMasterData.Codeunit.al | 88 + .../CreateEDocumentTransactions.Codeunit.al | 161 + .../EDocumentContosoModule.Codeunit.al | 40 + .../EDocumentContosoModule.EnumExt.al | 7 + .../demo data/EDocumentModuleSetup.Page.al | 37 + .../demo data/EDocumentModuleSetup.Table.al | 86 + Apps/W1/EDocument/demo data/ExtensionLogo.png | Bin 0 -> 5201 bytes Apps/W1/EDocument/demo data/app.json | 43 + Apps/W1/EDocument/test/app.json | 14 +- .../Matching/EDocLineMatchingTest.Codeunit.al | 15 +- .../test/src/Mock/EDocImplState.Codeunit.al | 1 + .../test/src/Mock/EDocTestBuffer.Codeunit.al | 11 + .../src/Processing/EDocE2ETest.Codeunit.al | 30 + .../src/Receive/EDocReceiveTest.Codeunit.al | 381 +++ Apps/W1/EDocumentsConnector/app/app.json | 20 +- .../src/E3Party/EDocExtEDocument.PageExt.al | 17 +- .../app/src/Pagero/PageroAuth.Codeunit.al | 51 +- Apps/W1/EU3PartyTradePurchase/app/app.json | 6 +- Apps/W1/EU3PartyTradePurchase/test/app.json | 14 +- .../app/app.json | 8 +- .../app/src/CurrentUserConnector.Codeunit.al | 8 +- .../test/app.json | 18 +- .../app/app.json | 8 +- .../test/app.json | 16 +- Apps/W1/Email - Outlook REST API/app/app.json | 8 +- .../app/src/EmailOAuthClient.Codeunit.al | 61 +- .../app/src/EmailOAuthClient.Interface.al | 8 +- .../app/src/EmailOAuthClientv2.Interface.al | 23 + .../app/src/EmailOutlookAPIClient.Codeunit.al | 83 +- .../src/EmailOutlookAPIClient.Interface.al | 8 +- .../src/EmailOutlookAPIClientv2.Interface.al | 12 + .../app/src/EmailOutlookAPIHelper.Codeunit.al | 36 +- .../app/src/EmailOutlookAPISetup.Page.al | 20 +- .../test/Mocks/OAuthClientMock.Codeunit.al | 31 +- .../Mocks/OutlookAPIClientMock.Codeunit.al | 29 +- .../OutlookMockInitSubscribers.Codeunit.al | 11 +- .../test/OutlookAPIHelperTests.Codeunit.al | 9 +- .../W1/Email - Outlook REST API/test/app.json | 14 +- Apps/W1/Email - SMTP API/app/app.json | 6 +- .../Authentication/BasicSMTPAuth.Codeunit.al | 2 +- .../Authentication/NTLMSMTPAuth.Codeunit.al | 2 +- .../Authentication/OAuth2SMTPAuth.Codeunit.al | 4 +- .../SMTPAuthentication.Codeunit.al | 40 +- .../W1/Email - SMTP API/test library/app.json | 6 +- Apps/W1/Email - SMTP API/test/app.json | 14 +- Apps/W1/Email - SMTP Connector/app/app.json | 8 +- .../OAuth2SMTPAuthentication.Codeunit.al | 10 +- .../app/src/SMTPAccount.table.al | 4 +- .../app/src/SMTPConnectorImpl.Codeunit.al | 2 +- Apps/W1/Email - SMTP Connector/test/app.json | 18 +- .../test/src/SMTPAccountAuthTests.Codeunit.al | 13 +- Apps/W1/EmailLogging/app/app.json | 6 +- ...minAgentPartnerEmailLogging.Entitlement.al | 10 + ...BCAdministratorEmailLogging.Entitlement.al | 10 + Apps/W1/EmailLogging/test/app.json | 10 +- Apps/W1/EnforcedDigitalVouchers/app/app.json | 80 +- .../test library/app.json | 72 +- Apps/W1/EnforcedDigitalVouchers/test/app.json | 116 +- .../app/app.json | 6 +- .../test/app.json | 14 +- .../EssentialBusinessHeadlines/app/app.json | 6 +- .../EssentialBusinessHeadlines/test/app.json | 10 +- Apps/W1/ExcelReports/app/ExtensionLogo.png | Bin 0 -> 5446 bytes .../Excel/Customer/CustomerTopListExcel.xlsx | Bin 0 -> 40454 bytes .../TrialBalanceBudgetExcel.xlsx | Bin 0 -> 43174 bytes .../GeneralLedger/TrialBalanceExcel.xlsx | Bin 0 -> 65675 bytes .../TrialBalancePrevYearExcel.xlsx | Bin 0 -> 53096 bytes .../TrialBalancebyPeriodExcel.xlsx | Bin 0 -> 43481 bytes .../Purchase/AgedAccountsPayableExcel.xlsx | Bin 0 -> 61462 bytes .../Sales/AgedAccountsReceivableExcel.xlsx | Bin 0 -> 72638 bytes .../Excel/Vendor/VendorTopListExcel.xlsx | Bin 0 -> 37616 bytes Apps/W1/ExcelReports/app/app.json | 28 + .../src/Customer/EXRCustomerTopList.Report.al | 257 ++ .../Customer/EXRTopCustomerBalance.Query.al | 44 + .../EXRTopCustomerReportBuffer.Table.al | 128 + .../src/Customer/EXRTopCustomerSales.Query.al | 43 + .../ExtTopCustCaptionHandler.Codeunit.al | 49 + .../EXRAgedAccPayableExcel.Report.al | 363 +++ .../EXRAgedAccountsRecExcel.Report.al | 363 +++ .../Financials/EXRAgingReportBuffer.Table.al | 222 ++ .../EXRTrialBalPrevYearExcel.Report.al | 195 ++ .../EXRTrialBalanceBudgetExcel.Report.al | 159 + .../Financials/EXRTrialBalanceBuffer.Table.al | 336 ++ .../Financials/EXRTrialBalanceExcel.Report.al | 167 + .../EXRTrialBalbyPeriodExcel.Report.al | 194 ++ .../EXTAgedAccCaptionHandler.Codeunit.al | 26 + .../RoleCenters/EXRARRoleCenter.PageExt.al | 63 + .../EXRAccountantRoleCenter.PageExt.al | 85 + .../RoleCenters/EXRFinRoleCenter.PageExt.al | 78 + .../ExtBusManagerRoleCenter.PageExt.al | 85 + .../RoleCenters/ExtCompanyDetail.PageExt.al | 85 + .../src/Vendor/EXRTopVendorBalance.Query.al | 45 + .../src/Vendor/EXRTopVendorPurchase.Query.al | 44 + .../Vendor/EXRTopVendorReportBuffer.Table.al | 128 + .../app/src/Vendor/EXRVendorTopList.Report.al | 258 ++ .../ExtTopVendorCaptionHandler.Codeunit.al | 49 + .../D365BASICISVFEReports.PermissionSetExt.al | 13 + ...BUSFULLACCESSFEReports.PermissionSetExt.al | 8 + ...365BUSPREMIUMFEReports.PermissionSetExt.al | 13 + ...365FULLACCESSFEReports.PermissionSetExt.al | 13 + .../D365READFEReports.PermissionSetExt.al | 13 + .../ExcelReportsObjects.PermissionSet.al | 35 + Apps/W1/ExternalEvents/app/app.json | 6 +- Apps/W1/ExternalEvents/test/app.json | 16 +- Apps/W1/HybridAPI/app/app.json | 8 +- .../app/src/CloudMigrationStatusAPI.Page.al | 3 +- Apps/W1/HybridBC/app/app.json | 8 +- Apps/W1/HybridBC/test/app.json | 16 +- Apps/W1/HybridBCLast/app/app.json | 8 +- .../src/codeunits/W1Management.Codeunit.al | 13 + Apps/W1/HybridBCLast/test/app.json | 18 +- Apps/W1/HybridBaseDeployment/app/app.json | 32 +- .../HybridCloudManagement.Codeunit.al | 10 + .../pages/AddMigrationTableMappings.Page.al | 1 + .../src/pages/HybridCloudSetupWizard.Page.al | 6 + Apps/W1/HybridBaseDeployment/test/app.json | 14 +- .../HybridGPObjects.PermissionSet.al | 2 + Apps/W1/HybridGP/app/app.json | 12 +- .../pages/HybridGPErrorsOverviewFb.page.al | 2 +- .../app/src/pages/HybridGPOverviewFb.Page.al | 2 +- .../IntelligentCloudExtension.PageExt.al | 2 +- Apps/W1/HybridGP/test/app.json | 20 +- .../INTaxEngine/app/TaxEngine-Core/app.json | 6 +- .../ArchiveManagementHandler.Codeunit.al | 62 + .../app/TaxEngine-JsonExchange/app.json | 16 +- .../app/TaxEngine-PostingHandler/app.json | 14 +- .../codeunit/TaxDocumentGLPosting.Codeunit.al | 1 + .../codeunit/TaxPostingBufferMgmt.Codeunit.al | 2 + .../app/TaxEngine-ScriptHandler/app.json | 8 +- .../app/TaxEngine-TaxTypeHandler/app.json | 10 +- .../table/TaxTransactionValue.Table.al | 39 + .../app/TaxEngine-UseCaseBuilder/app.json | 12 +- .../codeunit/UseCaseEventHandling.Codeunit.al | 1 + Apps/W1/INTaxEngine/app/app.json | 6 +- .../INTaxEngine/test/TaxEngine-Core/app.json | 12 +- .../test/TaxEngine-JsonExchange/app.json | 10 +- .../test/TaxEngine-PostingHandler/app.json | 14 +- .../test/TaxEngine-ScriptHandler/app.json | 14 +- .../test/TaxEngine-TaxTypeHandler/app.json | 10 +- .../test/TaxEngine-UseCaseBuilder/app.json | 14 +- Apps/W1/INTaxEngine/test/app.json | 12 +- Apps/W1/ImageAnalysis/app/app.json | 6 +- .../pages/ContactPicAnalyzerExt.PageExt.al | 13 +- Apps/W1/ImageAnalysis/test/app.json | 12 +- Apps/W1/Intrastat/app/app.json | 6 +- .../app/src/IntrastatReportHeader.Table.al | 11 +- .../src/IntrastatReportManagement.Codeunit.al | 11 + .../app/src/IntrastatReportSubform.Page.al | 18 +- Apps/W1/Intrastat/test/app.json | 14 +- .../test/src/LibraryIntrastat.Codeunit.al | 4 +- Apps/W1/LatePaymentPredictor/app/app.json | 6 +- Apps/W1/LatePaymentPredictor/test/app.json | 12 +- .../test/src/LPMLInputDataTest.Codeunit.al | 8 + .../test/src/LPPredictionTest.Codeunit.al | 98 +- Apps/W1/LibraryNoTransactions/app.json | 4 +- Apps/W1/MSWalletPayments/app/app.json | 6 +- Apps/W1/MasterDataManagement/app/app.json | 6 +- .../MasterDataManagement.Codeunit.al | 35 +- .../MasterDataMgtSetupDefault.Codeunit.al | 15 +- .../src/pages/MasterDataSynchTables.Page.al | 8 + .../src/xmlports/ExportMDMSetup.XmlPort.al | 2 +- .../test library/app.json | 8 +- Apps/W1/MasterDataManagement/test/app.json | 14 +- .../src/MasterDataMgtSetupTests.Codeunit.al | 18 +- Apps/W1/MicrosoftUniversalPrint/app.json | 6 +- Apps/W1/OnPrem Permissions/app/app.json | 6 +- Apps/W1/OnPrem Permissions/test/app.json | 10 +- Apps/W1/OnboardingSignals/app/app.json | 6 +- Apps/W1/OnboardingSignals/test/app.json | 12 +- Apps/W1/PayPalPaymentsStandard/app/app.json | 6 +- Apps/W1/PayPalPaymentsStandard/test/app.json | 14 +- Apps/W1/PaymentPractices/app/app.json | 6 +- Apps/W1/PaymentPractices/test/app.json | 14 +- ...entPartnerPlanConfiguration.Entitlement.al | 15 + ...inistratorPlanConfiguration.Entitlement.al | 16 + Apps/W1/PlanConfiguration/app/app.json | 6 +- .../src/UpgradeCustomUserGroups.Codeunit.al | 1 + Apps/W1/PlanConfiguration/test/app.json | 16 +- .../src/AzureADPlanModuleTest.codeunit.al | 189 +- Apps/W1/QBMigration/app/app.json | 8 +- .../src/Support/MSQBODataMigration.Page.al | 2 +- Apps/W1/QBMigration/test/app.json | 10 +- .../QuickbooksPayrollFileImport/app/app.json | 6 +- .../QuickbooksPayrollFileImport/test/app.json | 10 +- Apps/W1/RecommendedApps/app/app.json | 6 +- Apps/W1/RecommendedApps/test/app.json | 14 +- Apps/W1/ReportLayouts/app/app.json | 6 +- Apps/W1/ReportLayouts/test/app.json | 12 +- Apps/W1/ReviewGLEntries/app/app.json | 6 +- Apps/W1/ReviewGLEntries/test/app.json | 12 +- Apps/W1/SAF-T/app/app.json | 32 +- Apps/W1/SAF-T/test/app.json | 16 +- .../W1/SalesAndInventoryForecast/app/app.json | 6 +- .../SalesAndInventoryForecast/test/app.json | 12 +- .../SalesInvoiceSubFormExt.PageExt.al | 53 + .../SalesOrderSubFormExt.PageExt.al | 54 + .../SalesQuoteSubFormExt.PageExt.al | 53 + .../app/ExtensionLogo.png | Bin 0 -> 5446 bytes .../app/SLSPrompts.Codeunit.al | 73 + .../DocumentLookupSubType.Interface.al | 17 + .../SalesInvoiceLookup.Codeunit.al | 254 ++ .../SalesOrderLookup.Codeunit.al | 239 ++ .../SalesQuoteLookup.Codeunit.al | 239 ++ .../SalesShipmentLookup.Codeunit.al | 254 ++ .../Enums/DocumentLookupTypes.Enum.al | 28 + .../Enums/SalesSupportedTools.Enum.al | 24 + .../DocumentLookupFunction.Codeunit.al | 149 + .../FunctionsImpl/MagicFunction.Codeunit.al | 36 + .../SearchItemsFunction.Codeunit.al | 64 + .../SalesAzureOpenAITools.Interface.al | 28 + .../app/SalesLineAISuggestions.Page.al | 365 +++ .../app/SalesLineAISuggestions.Table.al | 245 ++ .../app/SalesLineAISuggestionsSub.Page.al | 148 + .../app/SalesLinesSuggestionsImpl.Codeunit.al | 235 ++ .../app/Search/ItemSearchSetup.Page.al | 112 + .../app/Search/Search.Codeunit.al | 232 ++ .../app/Search/SearchAPIResponse.Table.al | 34 + .../app/Search/SearchConfidence.Enum.al | 24 + .../app/Search/SearchStyle.Enum.al | 24 + .../SalesLineSuggestionsInstall.Codeunit.al | 20 + .../SalesLineSuggestionsUpgrade.Codeunit.al | 37 + .../SalesLinesCopilotCapability.EnumExt.al | 15 + .../Utilities/NotificationManager.Codeunit.al | 33 + .../PrepareSalesLineForCopying.Codeunit.al | 46 + .../Utilities/SalesLineUtility.Codeunit.al | 114 + Apps/W1/SalesLinesSuggestions/app/app.json | 41 + .../test/DocumentLookupPromptTest.Codeunit.al | 1215 ++++++++ .../test/DocumentLookupTest.Codeunit.al | 2122 +++++++++++++ .../test/ExtensionLogo.png | Bin 0 -> 5446 bytes .../test/MagicFunctionPromptTest.Codeunit.al | 597 ++++ .../test/SLSTestUtility.Codeunit.al | 171 + .../test/SearchItemPromptTest.Codeunit.al | 1190 +++++++ .../test/SearchItemTest.Codeunit.al | 730 +++++ Apps/W1/SalesLinesSuggestions/test/app.json | 54 + Apps/W1/SendToEmailPrinter/app.json | 6 +- Apps/W1/ServiceDeclaration/app/app.json | 6 +- .../ServiceDeclarationHeader.Table.al | 13 +- Apps/W1/ServiceDeclaration/test/app.json | 14 +- .../src/LibraryServiceDeclaration.Codeunit.al | 4 +- .../src/ServiceDeclarationUITests.Codeunit.al | 4 +- Apps/W1/Shopify/app/app.json | 10 +- .../ShpfyCommunicationMgt.Codeunit.al | 2 +- .../Codeunits/ShpfyUpgradeMgt.Codeunit.al | 40 +- .../src/Base/Pages/ShpfyActivities.Page.al | 17 +- .../app/src/Base/Pages/ShpfyShopCard.Page.al | 94 +- .../app/src/Base/Tables/ShpfyCue.Table.al | 12 +- .../app/src/Base/Tables/ShpfyShop.Table.al | 6 +- .../Codeunits/ShpfyCatalogAPI.Codeunit.al | 74 +- .../ShpfySyncCatalogPrices.Codeunit.al | 11 +- .../src/Catalogs/Pages/ShpfyCatalogs.Page.al | 10 +- .../Reports/ShpfySyncCatalogPrices.Report.al | 8 + .../Codeunits/ShpfyCompanyAPI.Codeunit.al | 6 + .../Codeunits/ShpfyCompanyExport.Codeunit.al | 40 +- .../Tables/ShpfyCompanyLocation.Table.al | 10 + .../Codeunits/ShpfyCountyCode.Codeunit.al | 12 + .../Codeunits/ShpfyCountyName.Codeunit.al | 12 + .../Codeunits/ShpfyCreateCustomer.Codeunit.al | 54 +- .../Codeunits/ShpfyCustomerAPI.Codeunit.al | 16 +- .../Codeunits/ShpfyUpdateCustomer.Codeunit.al | 17 +- .../Interfaces/ShpfyICounty.Interface.al | 7 + .../Pages/ShpfyCustomerTemplates.Page.al | 2 + .../ShpfyGQLCatalogPrices.Codeunit.al | 4 +- .../ShpfyGQLCatalogProducts.Codeunit.al | 27 + .../Codeunits/ShpfyGQLCompany.Codeunit.al | 2 +- .../Codeunits/ShpfyGQLCustomer.Codeunit.al | 2 +- .../ShpfyGQLFFOrdersFromOrder.Codeunit.al | 4 +- .../ShpfyGQLNextCatalogProducts.Codeunit.al | 27 + .../ShpfyGQLNextFFOrdersFromOrd.Codeunit.al | 4 +- .../ShpfyGQLNextOpenFFOrders.Codeunit.al | 4 +- .../ShpfyGQLOpenFulfillmOrders.Codeunit.al | 4 +- .../Codeunits/ShpfyGQLOrderHeader.Codeunit.al | 4 +- .../GraphQL/Enums/ShpfyGraphQLType.Enum.al | 10 + .../Pages/ShpfyAuthentication.Page.al | 2 +- .../ShpfyFulfillmentOrdersAPI.Codeunit.al | 63 +- .../Enums/ShpfyDeliveryMethodType.Enum.al | 35 + .../Enums/ShpfyOrderFulfillStatus.Enum.al | 4 + .../ShpfyFulFillmentOrderHeader.Table.al | 6 + .../Tables/ShpfyFulFillmentOrderLine.Table.al | 6 + .../Codeunits/ShpfyRefundsAPI.Codeunit.al | 15 +- .../Codeunits/ShpfyImportOrder.Codeunit.al | 242 +- .../Codeunits/ShpfyOrderMapping.Codeunit.al | 2 +- .../Codeunits/ShpfyOrdersAPI.Codeunit.al | 9 +- .../Codeunits/ShpfyProcessOrder.Codeunit.al | 6 +- .../Codeunits/ShpfyProcessOrders.Codeunit.al | 8 + .../Order handling/Pages/ShpfyOrder.Page.al | 50 +- .../Order handling/Pages/ShpfyOrders.Page.al | 2 +- .../Tables/ShpfyOrderHeader.Table.al | 27 +- .../Tables/ShpfyOrderLine.Table.al | 6 + .../ShpfyExportShipments.Codeunit.al | 11 +- .../Queries/ShpfyShipmentLocation.Query.al | 2 + .../Codeunits/ShpfyWebhooksMgt.Codeunit.al | 32 +- .../Catalogs/ShpfyCatalogAPITest.Codeunit.al | 9 +- .../ShpfyCatalogInitialize.Codeunit.al | 6 +- .../ShpfyCustomerInitTest.Codeunit.al | 4 +- .../Shipping/ShpfyShippingTest.Codeunit.al | 15 +- Apps/W1/Shopify/test/app.json | 24 +- .../app/app.json | 6 +- .../test/app.json | 12 +- Apps/W1/SmartList/app.json | 6 +- Apps/W1/StatisticalAccounts/app/app.json | 6 +- Apps/W1/StatisticalAccounts/test/app.json | 16 +- Apps/W1/Sustainability/app/app.json | 78 +- .../src/Account/CalculationFoundation.Enum.al | 2 - .../Account/ChartOfSustainAccounts.Page.al | 20 +- .../Account/SustainAccountCategories.Page.al | 12 +- .../Account/SustainAccountCategory.Table.al | 17 + .../SustainAccountSubcategories.Page.al | 18 +- .../SustainAccountSubcategory.Table.al | 7 + .../Account/SustainCategoryFactBox.Page.al | 4 +- .../Account/SustainSubcategoryFactBox.Page.al | 10 +- .../Account/SustainabilityAccount.Table.al | 16 +- .../Account/SustainabilityAccountCard.Page.al | 8 +- .../CollectAmountFromGLEntry.Page.al | 12 +- .../src/Calculation/GLAccountsSubform.Page.al | 2 +- .../SustainabilityCalcMgt.Codeunit.al | 17 +- .../Journal/SustainJnlErrorsFactbox.Page.al | 220 ++ .../Journal/SustainJnlErrorsMgt.Codeunit.al | 153 + .../src/Journal/SustainJnlRecurMethod.Enum.al | 2 + .../Journal/SustainabilityJnlLine.Table.al | 13 +- .../src/Journal/SustainabilityJournal.Page.al | 103 +- .../SustainabilityJournalMgt.Codeunit.al | 24 +- .../SustainabilityLedgerEntries.Page.al | 38 +- .../Ledger/SustainabilityLedgerEntry.Table.al | 2 +- .../SustainabilityObjects.permissionset.al | 3 + .../CheckSustJnlLineBackgr.Codeunit.al | 47 + .../SustainabilityJnlCheck.Codeunit.al | 3 - .../Posting/SustainabilityJnlPost.Codeunit.al | 11 +- .../Posting/SustainabilityPostMgt.Codeunit.al | 21 + .../SustainabilityRecurJnlPost.Codeunit.al | 16 +- .../src/Reports/EmissionByCategory.Report.al | 36 +- .../app/src/Reports/EmissionByCategory.rdlc | 331 +- .../app/src/Reports/EmissionByCategory.xlsx | Bin 110035 -> 71210 bytes .../src/Reports/EmissionPerFacility.Report.al | 25 +- .../app/src/Reports/EmissionPerFacility.rdlc | 230 +- .../app/src/Reports/EmissionPerFacility.xlsx | Bin 77744 -> 48397 bytes .../app/src/Reports/TotalEmissions.Report.al | 30 +- .../app/src/Reports/TotalEmissions.rdlc | 579 +++- .../app/src/Reports/TotalEmissions.xlsx | Bin 99237 -> 71324 bytes .../app/src/Setup/SustainabilitySetup.Page.al | 56 +- .../src/Setup/SustainabilitySetup.Table.al | 24 +- Apps/W1/Sustainability/test/app.json | 94 +- .../CreateSustainJnlSetup.Codeunit.al | 109 + .../CreateSustainNoSeries.Codeunit.al | 33 + .../CreateSustainSubcategory.Codeunit.al | 389 +++ .../CreateSustainabilityAccount.Codeunit.al | 506 +++ .../CreateSustainabilityCategory.Codeunit.al | 150 + .../CreateSustainabilitySetup.Codeunit.al | 44 + .../CreateSustainabilityJournal.Codeunit.al | 69 + .../CreateSustainabilityEntry.Codeunit.al | 71 + .../SustainabilityModule.Codeunit.al | 39 + .../ContosoSustainability.Codeunit.al | 201 ++ .../SustContosoDemoDataModule.EnumExt.al | 7 + .../app/ExtensionLogo.png | Bin 0 -> 5446 bytes .../app/app.json | 50 + Apps/W1/SyncBase/app.json | 6 +- Apps/W1/TransactionStorage/app/app.json | 66 +- .../src/TransStorageErrorHandler.Codeunit.al | 16 +- .../src/TransStorageScheduleTask.Codeunit.al | 174 ++ .../app/src/TransactStorageExport.Codeunit.al | 135 + .../src/TransactStorageExportData.Codeunit.al | 61 +- .../src/TransactStorageTableEntry.Table.al | 3 + .../app/src/TransactionStorageABS.Codeunit.al | 56 +- .../app/src/TransactionStorageSetup.Table.al | 7 + .../src/TransactionStorageUpgrade.Codeunit.al | 44 + Apps/W1/UKSendRemittanceAdvice/app/app.json | 6 +- Apps/W1/UKSendRemittanceAdvice/test/app.json | 12 +- Apps/W1/VATGroupManagement/app/app.json | 6 +- .../VATGroupCommunication.Codeunit.al | 14 +- .../Codeunits/VATGroupSettlement.Codeunit.al | 4 +- .../Pages/VATReportSetupExtension.PageExt.al | 25 +- .../VATReportSetupExtension.TableExt.al | 19 +- Apps/W1/VATGroupManagement/test/app.json | 14 +- .../VATGroupRepresentativeLogic.Codeunit.al | 6 +- Apps/W1/WorldPayPaymentsStandard/app/app.json | 8 +- .../W1/WorldPayPaymentsStandard/test/app.json | 14 +- 1048 files changed, 46978 insertions(+), 8519 deletions(-) create mode 100644 Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/PurchAdvLetterPostCZZ.Codeunit.al create mode 100644 Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/SalesAdvLetterPostCZZ.Codeunit.al create mode 100644 Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/VATAmountLineHandlerCZZ.Codeunit.al create mode 100644 Apps/CZ/AdvancePaymentsLocalization/app/Src/Reports/PurchAdvLettersRecap.xlsx create mode 100644 Apps/CZ/AdvancePaymentsLocalization/app/Src/Reports/PurchAdvanceLetters.xlsx create mode 100644 Apps/CZ/AdvancePaymentsLocalization/app/Src/Reports/SalesAdvLettersRecap.xlsx create mode 100644 Apps/CZ/AdvancePaymentsLocalization/app/Src/Reports/SalesAdvanceLetters.xlsx create mode 100644 Apps/CZ/AdvancePaymentsLocalization/app/Src/Tables/AdvancePostingParametersCZZ.Table.al create mode 100644 Apps/CZ/AdvancedLocalizationPack/app/Src/Reports/OpenGLEntriesToDate.xlsx create mode 100644 Apps/CZ/CoreLocalizationPack/app/Src/Codeunits/FormatAddressHandlerCZL.Codeunit.al create mode 100644 Apps/CZ/CoreLocalizationPack/app/Src/PageExtensions/PaymentMethodsCZL.PageExt.al create mode 100644 Apps/CZ/CoreLocalizationPack/app/Src/ReportExtensions/InventoryValuationCZL.ReportExt.al create mode 100644 Apps/CZ/CoreLocalizationPack/app/Src/ReportExtensions/InventoryValuationCZL.xlsx create mode 100644 Apps/CZ/CoreLocalizationPack/app/Src/Reports/DocumentationForVAT.xlsx create mode 100644 Apps/CZ/CoreLocalizationPack/app/Src/Reports/OpenCustEntriestoDate.xlsx create mode 100644 Apps/CZ/CoreLocalizationPack/app/Src/Reports/OpenVendEntriestoDate.xlsx create mode 100644 Apps/CZ/CoreLocalizationPack/app/Src/TableExtensions/PaymentMethodCZL.TableExt.al create mode 100644 Apps/IN/INGST/app/GSTStockTransfer/src/codeunit/EInvJsonHandlerForTransShpt.Codeunit.al create mode 100644 Apps/IN/INGST/app/GSTStockTransfer/src/codeunit/EInvTransShptJsonManagement.Codeunit.al create mode 100644 Apps/IN/INGST/app/GSTStockTransfer/src/page/TransferShipmentDialog.Page.al create mode 100644 Apps/IN/INGST/app/GSTStockTransfer/src/page/TransferShipmentQRCode.Page.al create mode 100644 Apps/IS/ISCore/app/src/PageExtensions/ISPostedPurchCreditMemo.PageExt.al create mode 100644 Apps/IS/ISCore/app/src/PageExtensions/ISPostedPurchaseInvoice.PageExt.al create mode 100644 Apps/US/IRSForms/app/ExtensionLogo.png create mode 100644 Apps/US/IRSForms/app/Permissions/D365BasicIRSForms.PermissionsetExt.al create mode 100644 Apps/US/IRSForms/app/Permissions/D365BasicISVIRSForms.PermissionsetExt.al create mode 100644 Apps/US/IRSForms/app/Permissions/D365ReadIRSForms.PermissionsetExt.al create mode 100644 Apps/US/IRSForms/app/Permissions/D365TeamMemberIRSForms.PermissionsetExt.al create mode 100644 Apps/US/IRSForms/app/Permissions/IRSFormsEdit.PermissionSet.al create mode 100644 Apps/US/IRSForms/app/Permissions/IRSFormsObjects.PermissionSet.al create mode 100644 Apps/US/IRSForms/app/Permissions/IRSFormsRead.PermissionSet.al create mode 100644 Apps/US/IRSForms/app/Permissions/IntelligentCloudIRSForms.PermissionsetExt.al create mode 100644 Apps/US/IRSForms/app/Permissions/LocalIRSForms.PermissionsetExt.al create mode 100644 Apps/US/IRSForms/app/app.json create mode 100644 Apps/US/IRSForms/app/src/Document/IRS1099CalcParams.Table.al create mode 100644 Apps/US/IRSForms/app/src/Document/IRS1099CreateFormDocs.Report.al create mode 100644 Apps/US/IRSForms/app/src/Document/IRS1099FormDocHeader.Table.al create mode 100644 Apps/US/IRSForms/app/src/Document/IRS1099FormDocLine.Table.al create mode 100644 Apps/US/IRSForms/app/src/Document/IRS1099FormDocLineDetail.Table.al create mode 100644 Apps/US/IRSForms/app/src/Document/IRS1099FormDocLineDetails.Page.al create mode 100644 Apps/US/IRSForms/app/src/Document/IRS1099FormDocStatus.Enum.al create mode 100644 Apps/US/IRSForms/app/src/Document/IRS1099FormDocSubform.Page.al create mode 100644 Apps/US/IRSForms/app/src/Document/IRS1099FormDocsImpl.Codeunit.al create mode 100644 Apps/US/IRSForms/app/src/Document/IRS1099FormDocument.Codeunit.al create mode 100644 Apps/US/IRSForms/app/src/Document/IRS1099FormDocument.Page.al create mode 100644 Apps/US/IRSForms/app/src/Document/IRS1099FormDocuments.Page.al create mode 100644 Apps/US/IRSForms/app/src/Emailing/IRS1099EmailQueue.Table.al create mode 100644 Apps/US/IRSForms/app/src/Emailing/IRS1099EmailReportType.Enum.al create mode 100644 Apps/US/IRSForms/app/src/Emailing/IRS1099ProcessEmailQueue.Codeunit.al create mode 100644 Apps/US/IRSForms/app/src/Emailing/IRS1099SendEmail.Codeunit.al create mode 100644 Apps/US/IRSForms/app/src/Emailing/IRS1099SendEmail.Report.al create mode 100644 Apps/US/IRSForms/app/src/Emailing/IRS1099VendorEmail.Codeunit.al create mode 100644 Apps/US/IRSForms/app/src/Extensions/IRS1099BaseAppSubscribers.Codeunit.al create mode 100644 Apps/US/IRSForms/app/src/Extensions/IRS1099GenJnlLine.TableExt.al create mode 100644 Apps/US/IRSForms/app/src/Extensions/IRS1099GeneralJournal.PageExt.al create mode 100644 Apps/US/IRSForms/app/src/Extensions/IRS1099PostedGenJnlLine.TableExt.al create mode 100644 Apps/US/IRSForms/app/src/Extensions/IRS1099PostedPurchCrMemo.PageExt.al create mode 100644 Apps/US/IRSForms/app/src/Extensions/IRS1099PostedPurchInv.PageExt.al create mode 100644 Apps/US/IRSForms/app/src/Extensions/IRS1099PurchCrMemo.PageExt.al create mode 100644 Apps/US/IRSForms/app/src/Extensions/IRS1099PurchCrMemoHeader.TableExt.al create mode 100644 Apps/US/IRSForms/app/src/Extensions/IRS1099PurchHeader.TableExt.al create mode 100644 Apps/US/IRSForms/app/src/Extensions/IRS1099PurchHeaderArchive.TableExt.al create mode 100644 Apps/US/IRSForms/app/src/Extensions/IRS1099PurchInv.PageExt.al create mode 100644 Apps/US/IRSForms/app/src/Extensions/IRS1099PurchInvHeader.TableExt.al create mode 100644 Apps/US/IRSForms/app/src/Extensions/IRS1099PurchOrder.PageExt.al create mode 100644 Apps/US/IRSForms/app/src/Extensions/IRS1099PurchaseJournal.PageExt.al create mode 100644 Apps/US/IRSForms/app/src/Extensions/IRS1099Vendor.TableExt.al create mode 100644 Apps/US/IRSForms/app/src/Extensions/IRS1099VendorCard.PageExt.al create mode 100644 Apps/US/IRSForms/app/src/Extensions/IRS1099VendorLedgerEntries.PageExt.al create mode 100644 Apps/US/IRSForms/app/src/Extensions/IRS1099VendorLedgerEntry.TableExt.al create mode 100644 Apps/US/IRSForms/app/src/Extensions/IRS1099VendorList.PageExt.al create mode 100644 Apps/US/IRSForms/app/src/Interface/IRS1099CreateFormDocs.Interface.al create mode 100644 Apps/US/IRSForms/app/src/Interface/IRS1099FormBoxCalc.Interface.al create mode 100644 Apps/US/IRSForms/app/src/Interface/IRS1099FormInstruction.Table.al create mode 100644 Apps/US/IRSForms/app/src/Interface/IRS1099Printing.Interface.al create mode 100644 Apps/US/IRSForms/app/src/Interface/IRSFormsFacade.Codeunit.al create mode 100644 Apps/US/IRSForms/app/src/Interface/IRSFormsImplementation.Enum.al create mode 100644 Apps/US/IRSForms/app/src/Interface/IRSFormsOrchestrator.Codeunit.al create mode 100644 Apps/US/IRSForms/app/src/Printing/IRS 1099 Print.docx create mode 100644 Apps/US/IRSForms/app/src/Printing/IRS1099Dataset.Codeunit.al create mode 100644 Apps/US/IRSForms/app/src/Printing/IRS1099FormInstructions.Page.al create mode 100644 Apps/US/IRSForms/app/src/Printing/IRS1099FormReport.Table.al create mode 100644 Apps/US/IRSForms/app/src/Printing/IRS1099FormReportType.Enum.al create mode 100644 Apps/US/IRSForms/app/src/Printing/IRS1099FormReports.Page.al create mode 100644 Apps/US/IRSForms/app/src/Printing/IRS1099FormStatement.Page.al create mode 100644 Apps/US/IRSForms/app/src/Printing/IRS1099FormStatementLine.Table.al create mode 100644 Apps/US/IRSForms/app/src/Printing/IRS1099Print.Report.al create mode 100644 Apps/US/IRSForms/app/src/Printing/IRS1099PrintParams.Table.al create mode 100644 Apps/US/IRSForms/app/src/Printing/IRS1099PrintValueType.Enum.al create mode 100644 Apps/US/IRSForms/app/src/Printing/IRS1099PrintingImpl.Codeunit.al create mode 100644 Apps/US/IRSForms/app/src/Printing/IRS1099ProtectTINType.Enum.al create mode 100644 Apps/US/IRSForms/app/src/Printing/IRS1099ReportLine.Table.al create mode 100644 Apps/US/IRSForms/app/src/Setup/IRS1099CopySetupFrom.Report.al create mode 100644 Apps/US/IRSForms/app/src/Setup/IRS1099Form.Table.al create mode 100644 Apps/US/IRSForms/app/src/Setup/IRS1099FormBox.Table.al create mode 100644 Apps/US/IRSForms/app/src/Setup/IRS1099FormBoxes.Page.al create mode 100644 Apps/US/IRSForms/app/src/Setup/IRS1099Forms.Page.al create mode 100644 Apps/US/IRSForms/app/src/Setup/IRS1099TransErrorHandler.Codeunit.al create mode 100644 Apps/US/IRSForms/app/src/Setup/IRS1099TransferFromBaseApp.Codeunit.al create mode 100644 Apps/US/IRSForms/app/src/Setup/IRSFormsData.Codeunit.al create mode 100644 Apps/US/IRSForms/app/src/Setup/IRSFormsFeature.Codeunit.al create mode 100644 Apps/US/IRSForms/app/src/Setup/IRSFormsGuide.Page.al create mode 100644 Apps/US/IRSForms/app/src/Setup/IRSFormsInstall.Codeunit.al create mode 100644 Apps/US/IRSForms/app/src/Setup/IRSFormsSetup.Page.al create mode 100644 Apps/US/IRSForms/app/src/Setup/IRSFormsSetup.Table.al create mode 100644 Apps/US/IRSForms/app/src/Setup/IRSReportingPeriod.Codeunit.al create mode 100644 Apps/US/IRSForms/app/src/Setup/IRSReportingPeriod.Table.al create mode 100644 Apps/US/IRSForms/app/src/Setup/IRSReportingPeriods.Page.al create mode 100644 Apps/US/IRSForms/app/src/VendorFormBox/IRS1099FormBoxBufferType.Enum.al create mode 100644 Apps/US/IRSForms/app/src/VendorFormBox/IRS1099FormBoxCalcImpl.Codeunit.al create mode 100644 Apps/US/IRSForms/app/src/VendorFormBox/IRS1099PropagateVendSetup.Report.al create mode 100644 Apps/US/IRSForms/app/src/VendorFormBox/IRS1099SuggestVendors.Report.al create mode 100644 Apps/US/IRSForms/app/src/VendorFormBox/IRS1099VendFormBoxAdjmts.Page.al create mode 100644 Apps/US/IRSForms/app/src/VendorFormBox/IRS1099VendFormBoxBuffer.Table.al create mode 100644 Apps/US/IRSForms/app/src/VendorFormBox/IRS1099VendorFormBox.Codeunit.al create mode 100644 Apps/US/IRSForms/app/src/VendorFormBox/IRS1099VendorFormBoxAdj.Table.al create mode 100644 Apps/US/IRSForms/app/src/VendorFormBox/IRS1099VendorFormBoxSetup.Page.al create mode 100644 Apps/US/IRSForms/app/src/VendorFormBox/IRS1099VendorFormBoxSetup.Table.al create mode 100644 Apps/US/IRSForms/test library/ExtensionLogo.png create mode 100644 Apps/US/IRSForms/test library/app.json create mode 100644 Apps/US/IRSForms/test library/src/IRSFormsEnableFeature.Codeunit.al create mode 100644 Apps/US/IRSForms/test library/src/LibraryIRS1099Document.Codeunit.al create mode 100644 Apps/US/IRSForms/test library/src/LibraryIRS1099FormBox.Codeunit.al create mode 100644 Apps/US/IRSForms/test library/src/LibraryIRSReportingPeriod.Codeunit.al create mode 100644 Apps/US/IRSForms/test/ExtensionLogo.png create mode 100644 Apps/US/IRSForms/test/app.json create mode 100644 Apps/US/IRSForms/test/src/IRS1099DocumentTests.Codeunit.al create mode 100644 Apps/US/IRSForms/test/src/IRS1099E2ETests.Codeunit.al create mode 100644 Apps/US/IRSForms/test/src/IRS1099FormCalcTests.Codeunit.al create mode 100644 Apps/US/IRSForms/test/src/IRS1099PrintingTests.Codeunit.al create mode 100644 Apps/US/IRSForms/test/src/IRS1099VendorTests.Codeunit.al create mode 100644 Apps/US/IRSForms/test/src/IRSReportingPeriodTests.Codeunit.al create mode 100644 Apps/W1/APIV1/app/src/Entitlements/DelegatedBCAdminAgentPartnerAPIV1.Entitlement.al create mode 100644 Apps/W1/APIV1/app/src/Entitlements/InternalBCAdministratorAPIV1.Entitlement.al create mode 100644 Apps/W1/APIV2/app/src/Entitlements/DelegatedBCAdminAgentPartnerAPIV2.Entitlement.al create mode 100644 Apps/W1/APIV2/app/src/Entitlements/InternalBCAdministratorAPIV2.Entitlement.al create mode 100644 Apps/W1/APIV2/app/src/pages/APIV2DisputeStatus.Page.al create mode 100644 Apps/W1/CompanyHub/app/Entitlements/DelegatedBCAdminAgentPartnerCOHUB.Entitlement.al create mode 100644 Apps/W1/CompanyHub/app/Entitlements/InternalBCAdministratorCOHUB.Entitlement.al create mode 100644 Apps/W1/EDocument/app/src/Extensions/EDocPurchPayablesSetup.PageExt.al create mode 100644 Apps/W1/EDocument/app/src/Extensions/EDocPurchPayablesSetup.TableExt.al create mode 100644 Apps/W1/EDocument/app/src/Processing/EDocumentCopilotCapability.EnumExt.al create mode 100644 Apps/W1/EDocument/app/src/Processing/OrderMatching/Copilot/EDocAOAITools.Interface.al create mode 100644 Apps/W1/EDocument/app/src/Processing/OrderMatching/Copilot/EDocPOAOAIFunction.Codeunit.al create mode 100644 Apps/W1/EDocument/app/src/Processing/OrderMatching/Copilot/EDocPOCopilotMatching.Codeunit.al create mode 100644 Apps/W1/EDocument/app/src/Processing/OrderMatching/Copilot/EDocPOCopilotProp.Page.al create mode 100644 Apps/W1/EDocument/app/src/Processing/OrderMatching/Copilot/EDocPOMatchPropBuffer.Table.al create mode 100644 Apps/W1/EDocument/app/src/Processing/OrderMatching/Copilot/EDocPOMatchPropSub.Page.al create mode 100644 Apps/W1/EDocument/app/src/Processing/OrderMatching/EDocOrderMatchAct.Page.al create mode 100644 Apps/W1/EDocument/demo data/1.Setup Data/CreateEDocumentSetup.Codeunit.al create mode 100644 Apps/W1/EDocument/demo data/2.Master Data/CreateEDocumentMasterData.Codeunit.al create mode 100644 Apps/W1/EDocument/demo data/3.Transactions/CreateEDocumentTransactions.Codeunit.al create mode 100644 Apps/W1/EDocument/demo data/EDocumentContosoModule.Codeunit.al create mode 100644 Apps/W1/EDocument/demo data/EDocumentContosoModule.EnumExt.al create mode 100644 Apps/W1/EDocument/demo data/EDocumentModuleSetup.Page.al create mode 100644 Apps/W1/EDocument/demo data/EDocumentModuleSetup.Table.al create mode 100644 Apps/W1/EDocument/demo data/ExtensionLogo.png create mode 100644 Apps/W1/EDocument/demo data/app.json create mode 100644 Apps/W1/Email - Outlook REST API/app/src/EmailOAuthClientv2.Interface.al create mode 100644 Apps/W1/Email - Outlook REST API/app/src/EmailOutlookAPIClientv2.Interface.al create mode 100644 Apps/W1/EmailLogging/app/src/entitlements/DelegatedBCAdminAgentPartnerEmailLogging.Entitlement.al create mode 100644 Apps/W1/EmailLogging/app/src/entitlements/InternalBCAdministratorEmailLogging.Entitlement.al create mode 100644 Apps/W1/ExcelReports/app/ExtensionLogo.png create mode 100644 Apps/W1/ExcelReports/app/ReportLayouts/Excel/Customer/CustomerTopListExcel.xlsx create mode 100644 Apps/W1/ExcelReports/app/ReportLayouts/Excel/GeneralLedger/TrialBalanceBudgetExcel.xlsx create mode 100644 Apps/W1/ExcelReports/app/ReportLayouts/Excel/GeneralLedger/TrialBalanceExcel.xlsx create mode 100644 Apps/W1/ExcelReports/app/ReportLayouts/Excel/GeneralLedger/TrialBalancePrevYearExcel.xlsx create mode 100644 Apps/W1/ExcelReports/app/ReportLayouts/Excel/GeneralLedger/TrialBalancebyPeriodExcel.xlsx create mode 100644 Apps/W1/ExcelReports/app/ReportLayouts/Excel/Purchase/AgedAccountsPayableExcel.xlsx create mode 100644 Apps/W1/ExcelReports/app/ReportLayouts/Excel/Sales/AgedAccountsReceivableExcel.xlsx create mode 100644 Apps/W1/ExcelReports/app/ReportLayouts/Excel/Vendor/VendorTopListExcel.xlsx create mode 100644 Apps/W1/ExcelReports/app/app.json create mode 100644 Apps/W1/ExcelReports/app/src/Customer/EXRCustomerTopList.Report.al create mode 100644 Apps/W1/ExcelReports/app/src/Customer/EXRTopCustomerBalance.Query.al create mode 100644 Apps/W1/ExcelReports/app/src/Customer/EXRTopCustomerReportBuffer.Table.al create mode 100644 Apps/W1/ExcelReports/app/src/Customer/EXRTopCustomerSales.Query.al create mode 100644 Apps/W1/ExcelReports/app/src/Customer/ExtTopCustCaptionHandler.Codeunit.al create mode 100644 Apps/W1/ExcelReports/app/src/Financials/EXRAgedAccPayableExcel.Report.al create mode 100644 Apps/W1/ExcelReports/app/src/Financials/EXRAgedAccountsRecExcel.Report.al create mode 100644 Apps/W1/ExcelReports/app/src/Financials/EXRAgingReportBuffer.Table.al create mode 100644 Apps/W1/ExcelReports/app/src/Financials/EXRTrialBalPrevYearExcel.Report.al create mode 100644 Apps/W1/ExcelReports/app/src/Financials/EXRTrialBalanceBudgetExcel.Report.al create mode 100644 Apps/W1/ExcelReports/app/src/Financials/EXRTrialBalanceBuffer.Table.al create mode 100644 Apps/W1/ExcelReports/app/src/Financials/EXRTrialBalanceExcel.Report.al create mode 100644 Apps/W1/ExcelReports/app/src/Financials/EXRTrialBalbyPeriodExcel.Report.al create mode 100644 Apps/W1/ExcelReports/app/src/Financials/EXTAgedAccCaptionHandler.Codeunit.al create mode 100644 Apps/W1/ExcelReports/app/src/RoleCenters/EXRARRoleCenter.PageExt.al create mode 100644 Apps/W1/ExcelReports/app/src/RoleCenters/EXRAccountantRoleCenter.PageExt.al create mode 100644 Apps/W1/ExcelReports/app/src/RoleCenters/EXRFinRoleCenter.PageExt.al create mode 100644 Apps/W1/ExcelReports/app/src/RoleCenters/ExtBusManagerRoleCenter.PageExt.al create mode 100644 Apps/W1/ExcelReports/app/src/RoleCenters/ExtCompanyDetail.PageExt.al create mode 100644 Apps/W1/ExcelReports/app/src/Vendor/EXRTopVendorBalance.Query.al create mode 100644 Apps/W1/ExcelReports/app/src/Vendor/EXRTopVendorPurchase.Query.al create mode 100644 Apps/W1/ExcelReports/app/src/Vendor/EXRTopVendorReportBuffer.Table.al create mode 100644 Apps/W1/ExcelReports/app/src/Vendor/EXRVendorTopList.Report.al create mode 100644 Apps/W1/ExcelReports/app/src/Vendor/ExtTopVendorCaptionHandler.Codeunit.al create mode 100644 Apps/W1/ExcelReports/app/src/permissions/D365BASICISVFEReports.PermissionSetExt.al create mode 100644 Apps/W1/ExcelReports/app/src/permissions/D365BUSFULLACCESSFEReports.PermissionSetExt.al create mode 100644 Apps/W1/ExcelReports/app/src/permissions/D365BUSPREMIUMFEReports.PermissionSetExt.al create mode 100644 Apps/W1/ExcelReports/app/src/permissions/D365FULLACCESSFEReports.PermissionSetExt.al create mode 100644 Apps/W1/ExcelReports/app/src/permissions/D365READFEReports.PermissionSetExt.al create mode 100644 Apps/W1/ExcelReports/app/src/permissions/ExcelReportsObjects.PermissionSet.al create mode 100644 Apps/W1/INTaxEngine/app/TaxEngine-Core/src/Core/Codeunit/ArchiveManagementHandler.Codeunit.al create mode 100644 Apps/W1/PlanConfiguration/app/Entitlements/DelegatedBCAdminAgentPartnerPlanConfiguration.Entitlement.al create mode 100644 Apps/W1/PlanConfiguration/app/Entitlements/InternalBCAdministratorPlanConfiguration.Entitlement.al create mode 100644 Apps/W1/SalesLinesSuggestions/app/BaseAppExtensions/SalesInvoiceSubFormExt.PageExt.al create mode 100644 Apps/W1/SalesLinesSuggestions/app/BaseAppExtensions/SalesOrderSubFormExt.PageExt.al create mode 100644 Apps/W1/SalesLinesSuggestions/app/BaseAppExtensions/SalesQuoteSubFormExt.PageExt.al create mode 100644 Apps/W1/SalesLinesSuggestions/app/ExtensionLogo.png create mode 100644 Apps/W1/SalesLinesSuggestions/app/SLSPrompts.Codeunit.al create mode 100644 Apps/W1/SalesLinesSuggestions/app/SalesAzureOpenAITools/DocumentLookupImpl/DocumentLookupSubType.Interface.al create mode 100644 Apps/W1/SalesLinesSuggestions/app/SalesAzureOpenAITools/DocumentLookupImpl/SalesInvoiceLookup.Codeunit.al create mode 100644 Apps/W1/SalesLinesSuggestions/app/SalesAzureOpenAITools/DocumentLookupImpl/SalesOrderLookup.Codeunit.al create mode 100644 Apps/W1/SalesLinesSuggestions/app/SalesAzureOpenAITools/DocumentLookupImpl/SalesQuoteLookup.Codeunit.al create mode 100644 Apps/W1/SalesLinesSuggestions/app/SalesAzureOpenAITools/DocumentLookupImpl/SalesShipmentLookup.Codeunit.al create mode 100644 Apps/W1/SalesLinesSuggestions/app/SalesAzureOpenAITools/Enums/DocumentLookupTypes.Enum.al create mode 100644 Apps/W1/SalesLinesSuggestions/app/SalesAzureOpenAITools/Enums/SalesSupportedTools.Enum.al create mode 100644 Apps/W1/SalesLinesSuggestions/app/SalesAzureOpenAITools/FunctionsImpl/DocumentLookupFunction.Codeunit.al create mode 100644 Apps/W1/SalesLinesSuggestions/app/SalesAzureOpenAITools/FunctionsImpl/MagicFunction.Codeunit.al create mode 100644 Apps/W1/SalesLinesSuggestions/app/SalesAzureOpenAITools/FunctionsImpl/SearchItemsFunction.Codeunit.al create mode 100644 Apps/W1/SalesLinesSuggestions/app/SalesAzureOpenAITools/SalesAzureOpenAITools.Interface.al create mode 100644 Apps/W1/SalesLinesSuggestions/app/SalesLineAISuggestions.Page.al create mode 100644 Apps/W1/SalesLinesSuggestions/app/SalesLineAISuggestions.Table.al create mode 100644 Apps/W1/SalesLinesSuggestions/app/SalesLineAISuggestionsSub.Page.al create mode 100644 Apps/W1/SalesLinesSuggestions/app/SalesLinesSuggestionsImpl.Codeunit.al create mode 100644 Apps/W1/SalesLinesSuggestions/app/Search/ItemSearchSetup.Page.al create mode 100644 Apps/W1/SalesLinesSuggestions/app/Search/Search.Codeunit.al create mode 100644 Apps/W1/SalesLinesSuggestions/app/Search/SearchAPIResponse.Table.al create mode 100644 Apps/W1/SalesLinesSuggestions/app/Search/SearchConfidence.Enum.al create mode 100644 Apps/W1/SalesLinesSuggestions/app/Search/SearchStyle.Enum.al create mode 100644 Apps/W1/SalesLinesSuggestions/app/Setup/SalesLineSuggestionsInstall.Codeunit.al create mode 100644 Apps/W1/SalesLinesSuggestions/app/Setup/SalesLineSuggestionsUpgrade.Codeunit.al create mode 100644 Apps/W1/SalesLinesSuggestions/app/Setup/SalesLinesCopilotCapability.EnumExt.al create mode 100644 Apps/W1/SalesLinesSuggestions/app/Utilities/NotificationManager.Codeunit.al create mode 100644 Apps/W1/SalesLinesSuggestions/app/Utilities/PrepareSalesLineForCopying.Codeunit.al create mode 100644 Apps/W1/SalesLinesSuggestions/app/Utilities/SalesLineUtility.Codeunit.al create mode 100644 Apps/W1/SalesLinesSuggestions/app/app.json create mode 100644 Apps/W1/SalesLinesSuggestions/test/DocumentLookupPromptTest.Codeunit.al create mode 100644 Apps/W1/SalesLinesSuggestions/test/DocumentLookupTest.Codeunit.al create mode 100644 Apps/W1/SalesLinesSuggestions/test/ExtensionLogo.png create mode 100644 Apps/W1/SalesLinesSuggestions/test/MagicFunctionPromptTest.Codeunit.al create mode 100644 Apps/W1/SalesLinesSuggestions/test/SLSTestUtility.Codeunit.al create mode 100644 Apps/W1/SalesLinesSuggestions/test/SearchItemPromptTest.Codeunit.al create mode 100644 Apps/W1/SalesLinesSuggestions/test/SearchItemTest.Codeunit.al create mode 100644 Apps/W1/SalesLinesSuggestions/test/app.json create mode 100644 Apps/W1/Shopify/app/src/GraphQL/Codeunits/ShpfyGQLCatalogProducts.Codeunit.al create mode 100644 Apps/W1/Shopify/app/src/GraphQL/Codeunits/ShpfyGQLNextCatalogProducts.Codeunit.al create mode 100644 Apps/W1/Shopify/app/src/Order Fulfillments/Enums/ShpfyDeliveryMethodType.Enum.al create mode 100644 Apps/W1/Sustainability/app/src/Journal/SustainJnlErrorsFactbox.Page.al create mode 100644 Apps/W1/Sustainability/app/src/Journal/SustainJnlErrorsMgt.Codeunit.al create mode 100644 Apps/W1/Sustainability/app/src/Posting/CheckSustJnlLineBackgr.Codeunit.al create mode 100644 Apps/W1/SustainabilityContosoCoffeeDemoDataset/app/DemoData/Sustainability/1.Setup Data/CreateSustainJnlSetup.Codeunit.al create mode 100644 Apps/W1/SustainabilityContosoCoffeeDemoDataset/app/DemoData/Sustainability/1.Setup Data/CreateSustainNoSeries.Codeunit.al create mode 100644 Apps/W1/SustainabilityContosoCoffeeDemoDataset/app/DemoData/Sustainability/1.Setup Data/CreateSustainSubcategory.Codeunit.al create mode 100644 Apps/W1/SustainabilityContosoCoffeeDemoDataset/app/DemoData/Sustainability/1.Setup Data/CreateSustainabilityAccount.Codeunit.al create mode 100644 Apps/W1/SustainabilityContosoCoffeeDemoDataset/app/DemoData/Sustainability/1.Setup Data/CreateSustainabilityCategory.Codeunit.al create mode 100644 Apps/W1/SustainabilityContosoCoffeeDemoDataset/app/DemoData/Sustainability/1.Setup Data/CreateSustainabilitySetup.Codeunit.al create mode 100644 Apps/W1/SustainabilityContosoCoffeeDemoDataset/app/DemoData/Sustainability/3. Transactions/CreateSustainabilityJournal.Codeunit.al create mode 100644 Apps/W1/SustainabilityContosoCoffeeDemoDataset/app/DemoData/Sustainability/4. Historical/CreateSustainabilityEntry.Codeunit.al create mode 100644 Apps/W1/SustainabilityContosoCoffeeDemoDataset/app/DemoData/Sustainability/SustainabilityModule.Codeunit.al create mode 100644 Apps/W1/SustainabilityContosoCoffeeDemoDataset/app/DemoTool/Contoso Helpers/ContosoSustainability.Codeunit.al create mode 100644 Apps/W1/SustainabilityContosoCoffeeDemoDataset/app/DemoTool/SustContosoDemoDataModule.EnumExt.al create mode 100644 Apps/W1/SustainabilityContosoCoffeeDemoDataset/app/ExtensionLogo.png create mode 100644 Apps/W1/SustainabilityContosoCoffeeDemoDataset/app/app.json create mode 100644 Apps/W1/TransactionStorage/app/src/TransStorageScheduleTask.Codeunit.al create mode 100644 Apps/W1/TransactionStorage/app/src/TransactStorageExport.Codeunit.al create mode 100644 Apps/W1/TransactionStorage/app/src/TransactionStorageUpgrade.Codeunit.al diff --git a/.github/AL-Go-Settings.json b/.github/AL-Go-Settings.json index 1a40817251..36a5b601a2 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.azureedge.net/sandbox/24.0.16034.0/base", + "artifact": "https://bcinsider.azureedge.net/sandbox/25.0.17516.0/base", "country": "base", "useProjectDependencies": true, "repoVersion": "24.0", diff --git a/Apps/AT/ContosoCoffeeDemoDatasetAT/app/app.json b/Apps/AT/ContosoCoffeeDemoDatasetAT/app/app.json index 256bfc530f..7026766d59 100644 --- a/Apps/AT/ContosoCoffeeDemoDatasetAT/app/app.json +++ b/Apps/AT/ContosoCoffeeDemoDatasetAT/app/app.json @@ -2,7 +2,7 @@ "id": "4b0b41f9-7a13-4231-d521-1465186cfb32", "name": "Contoso Coffee Demo Dataset (AT)", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "To help partners demonstrate the capabilities of Business Central, we are making new and extensive demo data available for various scenarios.", "description": "Presales specialists can run the tool on top of Cronus or My Company and get the setup and demo data they'll need when they demonstrate various scenarios.", "privacyStatement": "https://go.microsoft.com/fwlink/?linkid=724009", @@ -16,14 +16,14 @@ "id": "5a0b41e9-7a42-4123-d521-2265186cfb31", "name": "Contoso Coffee Demo Dataset", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 11140, diff --git a/Apps/AT/HybridBCLast_AT/app/app.json b/Apps/AT/HybridBCLast_AT/app/app.json index 17c27c43fa..4a4369bfd5 100644 --- a/Apps/AT/HybridBCLast_AT/app/app.json +++ b/Apps/AT/HybridBCLast_AT/app/app.json @@ -2,7 +2,7 @@ "id": "f4065a83-c2eb-4658-886e-c25a80dcad45", "name": "Business Central Cloud Migration - Previous Release (AT)", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Enables data migration from the previous version of Dynamics BC (n-1) to the current release of Dynamics 365 Business Central SaaS.", "description": "This extension, in conjuction with the Business Central Cloud Migration Previous Release, will enable you to migrate data from your Business Central on-premises solution for Austria to your Dynamics 365 Business Central cloud tenant for Austria. This extension is required to update country specific tables. Once you have walked through the cloud migration wizard in assisted setup, you will be able to migrate your data from your on-premises environment to your cloud tenant.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -15,25 +15,25 @@ { "publisher": "Microsoft", "name": "Intelligent Cloud Base", - "version": "24.0.0.0", + "version": "25.0.0.0", "id": "58623bfa-0559-4bc2-ae1c-0979c29fd9e0" }, { "publisher": "Microsoft", "name": "Business Central Cloud Migration - Previous Release", - "version": "24.0.0.0", + "version": "25.0.0.0", "id": "6992416f-3f39-4d3c-8242-3fff61350bea" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "resourceExposurePolicy": { "allowDebugging": false, "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, "target": "OnPrem", - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/AT/IntrastatAT/app/app.json b/Apps/AT/IntrastatAT/app/app.json index 5faa58780a..017e55a161 100644 --- a/Apps/AT/IntrastatAT/app/app.json +++ b/Apps/AT/IntrastatAT/app/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "The Intrastat extension makes it easy to export the Intrastat report in the format that the authorities in your country require.", "description": "The formats that businesses must use to report Intrastat vary from country to country. The Intrastat extension makes it easy to export the Intrastat report in the format that the authorities in your country require.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=2204541", @@ -16,13 +16,13 @@ "id": "70912191-3c4c-49fc-a1de-bc6ea1ac9da6", "name": "Intrastat Core", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 11150, @@ -34,6 +34,6 @@ "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0", + "application": "25.0.0.0", "target": "Cloud" } \ No newline at end of file diff --git a/Apps/AU/ContosoCoffeeDemoDatasetAU/app/app.json b/Apps/AU/ContosoCoffeeDemoDatasetAU/app/app.json index a3a7dd9e46..57cf70e595 100644 --- a/Apps/AU/ContosoCoffeeDemoDatasetAU/app/app.json +++ b/Apps/AU/ContosoCoffeeDemoDatasetAU/app/app.json @@ -2,7 +2,7 @@ "id": "4b0b41f9-7a13-4231-d521-2465186cfb32", "name": "Contoso Coffee Demo Dataset (AU)", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "To help partners demonstrate the capabilities of Business Central, we are making new and extensive demo data available for various scenarios.", "description": "Presales specialists can run the tool on top of Cronus or My Company and get the setup and demo data they'll need when they demonstrate various scenarios.", "privacyStatement": "https://go.microsoft.com/fwlink/?linkid=724009", @@ -16,14 +16,14 @@ "id": "5a0b41e9-7a42-4123-d521-2265186cfb31", "name": "Contoso Coffee Demo Dataset", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 17107, diff --git a/Apps/AU/HybridBCLast_AU/app/app.json b/Apps/AU/HybridBCLast_AU/app/app.json index 0d3d1ba3ad..20f8ae0308 100644 --- a/Apps/AU/HybridBCLast_AU/app/app.json +++ b/Apps/AU/HybridBCLast_AU/app/app.json @@ -2,7 +2,7 @@ "id": "155ea293-b0a3-4cae-a690-d832421dd180", "name": "Business Central Cloud Migration - Previous Release (AU)", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Enables data migration from the previous version of Dynamics BC (n-1) to the current release of Dynamics 365 Business Central SaaS.", "description": "This extension, in conjuction with the Business Central Cloud Migration Previous Release, will enable you to migrate data from your Business Central on-premises solution for Australia to your Dynamics 365 Business Central cloud tenant for Australia. This extension is required to update country specific tables. Once you have walked through the cloud migration wizard in assisted setup, you will be able to migrate your data from your on-premises environment to your cloud tenant.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -15,25 +15,25 @@ { "publisher": "Microsoft", "name": "Intelligent Cloud Base", - "version": "24.0.0.0", + "version": "25.0.0.0", "id": "58623bfa-0559-4bc2-ae1c-0979c29fd9e0" }, { "publisher": "Microsoft", "name": "Business Central Cloud Migration - Previous Release", - "version": "24.0.0.0", + "version": "25.0.0.0", "id": "6992416f-3f39-4d3c-8242-3fff61350bea" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "resourceExposurePolicy": { "allowDebugging": false, "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, "target": "OnPrem", - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/AU/Onprem Permissions AU/app/app.json b/Apps/AU/Onprem Permissions AU/app/app.json index 61af872e9f..123792396c 100644 --- a/Apps/AU/Onprem Permissions AU/app/app.json +++ b/Apps/AU/Onprem Permissions AU/app/app.json @@ -2,7 +2,7 @@ "id": "0a9956d8-3754-4e02-aaa2-84bb44da09aa", "name": "OnPrem Permissions (AU)", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "This extension includes permission set for on premise systems.", "description": "This extension includes permission set for on premise systems.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -17,12 +17,12 @@ "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "resourceExposurePolicy": { "allowDebugging": false, "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, "target": "OnPrem", - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/BE/ContosoCoffeeDemoDatasetBE/app/app.json b/Apps/BE/ContosoCoffeeDemoDatasetBE/app/app.json index 718d21acb1..faeee80426 100644 --- a/Apps/BE/ContosoCoffeeDemoDatasetBE/app/app.json +++ b/Apps/BE/ContosoCoffeeDemoDatasetBE/app/app.json @@ -2,7 +2,7 @@ "id": "5b0b41a1-7b42-4123-a521-2265186cfb33", "name": "Contoso Coffee Demo Dataset (BE)", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "To help partners demonstrate the capabilities of Business Central, we are making new and extensive demo data available for various scenarios.", "description": "Presales specialists can run the tool on top of Cronus or My Company and get the setup and demo data they'll need when they demonstrate various scenarios.", "privacyStatement": "https://go.microsoft.com/fwlink/?linkid=724009", @@ -16,14 +16,14 @@ "id": "5a0b41e9-7a42-4123-d521-2265186cfb31", "name": "Contoso Coffee Demo Dataset", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 11345, diff --git a/Apps/BE/HybridBCLast_BE/app/app.json b/Apps/BE/HybridBCLast_BE/app/app.json index d3e796d918..cf1c54d70d 100644 --- a/Apps/BE/HybridBCLast_BE/app/app.json +++ b/Apps/BE/HybridBCLast_BE/app/app.json @@ -2,7 +2,7 @@ "id": "620725d3-2ed5-424a-bd9b-7d4b44bfcc9b", "name": "Business Central Cloud Migration - Previous Release (BE)", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Enables data migration from the previous version of Dynamics BC (n-1) to the current release of Dynamics 365 Business Central SaaS.", "description": "This extension, in conjuction with the Business Central Cloud Migration Previous Release, will enable you to migrate data from your Business Central on-premises solution for Belgium to your Dynamics 365 Business Central cloud tenant for Belgium. This extension is required to update country specific tables. Once you have walked through the cloud migration wizard in assisted setup, you will be able to migrate your data from your on-premises environment to your cloud tenant.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -15,25 +15,25 @@ { "publisher": "Microsoft", "name": "Intelligent Cloud Base", - "version": "24.0.0.0", + "version": "25.0.0.0", "id": "58623bfa-0559-4bc2-ae1c-0979c29fd9e0" }, { "publisher": "Microsoft", "name": "Business Central Cloud Migration - Previous Release", - "version": "24.0.0.0", + "version": "25.0.0.0", "id": "6992416f-3f39-4d3c-8242-3fff61350bea" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "resourceExposurePolicy": { "allowDebugging": false, "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, "target": "OnPrem", - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/BE/IntrastatBE/app/app.json b/Apps/BE/IntrastatBE/app/app.json index 4f43b68634..9e1188588e 100644 --- a/Apps/BE/IntrastatBE/app/app.json +++ b/Apps/BE/IntrastatBE/app/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "The Intrastat extension makes it easy to export the Intrastat report in the format that the authorities in your country require.", "description": "The formats that businesses must use to report Intrastat vary from country to country. The Intrastat extension makes it easy to export the Intrastat report in the format that the Belgium authorities require.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=2204541", @@ -16,13 +16,13 @@ "id": "70912191-3c4c-49fc-a1de-bc6ea1ac9da6", "name": "Intrastat Core", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 11346, @@ -34,6 +34,6 @@ "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0", + "application": "25.0.0.0", "target": "Cloud" } \ No newline at end of file diff --git a/Apps/CA/ContosoCoffeeDemoDatasetCA/app/Codeunits/CreateCAGLAccounts.Codeunit.al b/Apps/CA/ContosoCoffeeDemoDatasetCA/app/Codeunits/CreateCAGLAccounts.Codeunit.al index 9baed83cae..de591c8b7e 100644 --- a/Apps/CA/ContosoCoffeeDemoDatasetCA/app/Codeunits/CreateCAGLAccounts.Codeunit.al +++ b/Apps/CA/ContosoCoffeeDemoDatasetCA/app/Codeunits/CreateCAGLAccounts.Codeunit.al @@ -15,7 +15,7 @@ codeunit 27009 "Create CA GL Accounts" ContosoGLAccount.AddAccountForLocalization(CommonGLAccount.CustomerDomesticName(), '13100'); ContosoGLAccount.AddAccountForLocalization(CommonGLAccount.VendorDomesticName(), '22300'); - ContosoGLAccount.AddAccountForLocalization(CommonGLAccount.SalesDomesticName(), '44100'); + ContosoGLAccount.AddAccountForLocalization(CommonGLAccount.SalesDomesticName(), '41100'); ContosoGLAccount.AddAccountForLocalization(CommonGLAccount.PurchaseDomesticName(), '54100'); ContosoGLAccount.AddAccountForLocalization(CommonGLAccount.SalesVATStandardName(), ''); diff --git a/Apps/CA/ContosoCoffeeDemoDatasetCA/app/app.json b/Apps/CA/ContosoCoffeeDemoDatasetCA/app/app.json index 4af6d9051f..34f61b25b9 100644 --- a/Apps/CA/ContosoCoffeeDemoDatasetCA/app/app.json +++ b/Apps/CA/ContosoCoffeeDemoDatasetCA/app/app.json @@ -2,7 +2,7 @@ "id": "5b0b41a1-7b42-3113-a521-2265186cfb33", "name": "Contoso Coffee Demo Dataset (CA)", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "To help partners demonstrate the capabilities of Business Central, we are making new and extensive demo data available for various scenarios.", "description": "Presales specialists can run the tool on top of Cronus or My Company and get the setup and demo data they'll need when they demonstrate various scenarios.", "privacyStatement": "https://go.microsoft.com/fwlink/?linkid=724009", @@ -16,14 +16,14 @@ "id": "5a0b41e9-7a42-4123-d521-2265186cfb31", "name": "Contoso Coffee Demo Dataset", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 27009, diff --git a/Apps/CA/HybridBCLast_CA/app/app.json b/Apps/CA/HybridBCLast_CA/app/app.json index c47506adc6..f0a7af754c 100644 --- a/Apps/CA/HybridBCLast_CA/app/app.json +++ b/Apps/CA/HybridBCLast_CA/app/app.json @@ -2,7 +2,7 @@ "id": "3cb4ddcd-36ed-4043-8194-b40efdb46165", "name": "Business Central Cloud Migration - Previous Release (CA)", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Enables data migration from the previous version of Dynamics BC (n-1) to the current release of Dynamics 365 Business Central SaaS.", "description": "This extension, in conjuction with the Business Central Cloud Migration Previous Release, will enable you to migrate data from your Business Central on-premises solution for Canada to your Dynamics 365 Business Central cloud tenant for Canada. This extension is required to update country specific tables. Once you have walked through the cloud migration wizard in assisted setup, you will be able to migrate your data from your on-premises environment to your cloud tenant.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -15,25 +15,25 @@ { "publisher": "Microsoft", "name": "Intelligent Cloud Base", - "version": "24.0.0.0", + "version": "25.0.0.0", "id": "58623bfa-0559-4bc2-ae1c-0979c29fd9e0" }, { "publisher": "Microsoft", "name": "Business Central Cloud Migration - Previous Release", - "version": "24.0.0.0", + "version": "25.0.0.0", "id": "6992416f-3f39-4d3c-8242-3fff61350bea" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "resourceExposurePolicy": { "allowDebugging": false, "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, "target": "OnPrem", - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/CH/ContosoCoffeeDemoDatasetCH/app/app.json b/Apps/CH/ContosoCoffeeDemoDatasetCH/app/app.json index 2b327677ee..515c1061fa 100644 --- a/Apps/CH/ContosoCoffeeDemoDatasetCH/app/app.json +++ b/Apps/CH/ContosoCoffeeDemoDatasetCH/app/app.json @@ -2,7 +2,7 @@ "id": "4b1c41f9-7a13-4231-d521-2465194cfb32", "name": "Contoso Coffee Demo Dataset (CH)", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "To help partners demonstrate the capabilities of Business Central, we are making new and extensive demo data available for various scenarios.", "description": "Presales specialists can run the tool on top of Cronus or My Company and get the setup and demo data they'll need when they demonstrate various scenarios.", "privacyStatement": "https://go.microsoft.com/fwlink/?linkid=724009", @@ -16,14 +16,14 @@ "id": "5a0b41e9-7a42-4123-d521-2265186cfb31", "name": "Contoso Coffee Demo Dataset", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 11580, diff --git a/Apps/CH/HybridBCLast_CH/app/app.json b/Apps/CH/HybridBCLast_CH/app/app.json index 22c74a326c..6080d6e16e 100644 --- a/Apps/CH/HybridBCLast_CH/app/app.json +++ b/Apps/CH/HybridBCLast_CH/app/app.json @@ -2,7 +2,7 @@ "id": "56c71df0-7b09-4c5e-97a1-f2a3feda4dff", "name": "Business Central Cloud Migration - Previous Release (CH)", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Enables data migration from the previous version of Dynamics BC (n-1) to the current release of Dynamics 365 Business Central SaaS.", "description": "This extension, in conjuction with the Business Central Cloud Migration Previous Release, will enable you to migrate data from your Business Central on-premises solution for Switzerland to your Dynamics 365 Business Central cloud tenant for Switzerland. This extension is required to update country specific tables. Once you have walked through the cloud migration wizard in assisted setup, you will be able to migrate your data from your on-premises environment to your cloud tenant.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -15,25 +15,25 @@ { "publisher": "Microsoft", "name": "Intelligent Cloud Base", - "version": "24.0.0.0", + "version": "25.0.0.0", "id": "58623bfa-0559-4bc2-ae1c-0979c29fd9e0" }, { "publisher": "Microsoft", "name": "Business Central Cloud Migration - Previous Release", - "version": "24.0.0.0", + "version": "25.0.0.0", "id": "6992416f-3f39-4d3c-8242-3fff61350bea" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "resourceExposurePolicy": { "allowDebugging": false, "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, "target": "OnPrem", - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/CH/SwissQRBill/app/app.json b/Apps/CH/SwissQRBill/app/app.json index 222d67c7a6..6fa04d9fcb 100644 --- a/Apps/CH/SwissQRBill/app/app.json +++ b/Apps/CH/SwissQRBill/app/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "Easily generate, send, and import QR-bills in Dynamics 365 Business Central", "description": "QR-bills enable easier processing and payment of received invoices from vendors. The QR-Bill Management app for Switzerland allows you to generate QR-bills that are compliant with the Swiss standard to receive QR-bills either via file import or direct input scan. All received QR-bills are handled via the Incoming Documents feature from where purchase journals can be created directly from the imported QR-bills. Finally, this app ensures that all payment references from QR-bill are carried through SEPA files to and from the bank and back to the issuer of the QR-bill for easy reconciliation. With this app, you can easily comply with the Swiss requirements for the QR-bills.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=2194212", @@ -30,12 +30,12 @@ "to": 11520 } ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "target": "OnPrem", "resourceExposurePolicy": { "allowDebugging": false, "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/CH/SwissQRBill/app/src/purchases/SwissQRBillPurchases.Codeunit.al b/Apps/CH/SwissQRBill/app/src/purchases/SwissQRBillPurchases.Codeunit.al index 18b6f472e8..0f3ded6443 100644 --- a/Apps/CH/SwissQRBill/app/src/purchases/SwissQRBillPurchases.Codeunit.al +++ b/Apps/CH/SwissQRBill/app/src/purchases/SwissQRBillPurchases.Codeunit.al @@ -532,7 +532,7 @@ codeunit 11502 "Swiss QR-Bill Purchases" PurchaseHeader.TestField("Pay-to Vendor No."); if Confirm(StrSubstNo(PurhDocVendBankAccountQst, IncomingDocument."Vendor IBAN")) then begin VendorBankAccount."Vendor No." := PurchaseHeader."Pay-to Vendor No."; - VendorBankAccount.IBAN := IncomingDocument."Vendor IBAN"; + VendorBankAccount.Validate(IBAN, IncomingDocument."Vendor IBAN"); VendorBankAccount."Payment Form" := VendorBankAccount."Payment Form"::"Bank Payment Domestic"; SwissQRBillCreateVendBank.LookupMode(true); SwissQRBillCreateVendBank.SetDetails(VendorBankAccount); diff --git a/Apps/CH/SwissQRBill/test/app.json b/Apps/CH/SwissQRBill/test/app.json index 4813c61a8e..7478fbaf2a 100644 --- a/Apps/CH/SwissQRBill/test/app.json +++ b/Apps/CH/SwissQRBill/test/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "Tests for QR-bill management for Switzerland", "description": "Tests for QR-bill management for Switzerland", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=2115702", @@ -16,25 +16,25 @@ "id": "98860128-1333-4598-a3da-0590804648b7", "name": "QR-Bill Management for Switzerland", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5095f467-0a01-4b99-99d1-9ff1237d286f", "publisher": "Microsoft", "name": "Library Variable Storage", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 148090, @@ -47,5 +47,5 @@ "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/CH/SwissQRBill/test/src/SwissQRBillTestPurchases.Codeunit.al b/Apps/CH/SwissQRBill/test/src/SwissQRBillTestPurchases.Codeunit.al index 36dfb7987c..2e3010712b 100644 --- a/Apps/CH/SwissQRBill/test/src/SwissQRBillTestPurchases.Codeunit.al +++ b/Apps/CH/SwissQRBill/test/src/SwissQRBillTestPurchases.Codeunit.al @@ -484,7 +484,7 @@ codeunit 148096 "Swiss QR-Bill Test Purchases" // [SCENARIO 351182] Scan QR-Bill into Purchase Invoice, confirm create a new vendor bank account // [SCENARIO 362130] A new vendor bank account "Payment Form" = "Bank Payment Domestic" Initialize(); - IBAN := SwissQRBillTestLibrary.GetRandomIBAN(); + IBAN := SwissQRBillTestLibrary.GetFixedIBAN(); PaymentReference := SwissQRBillTestLibrary.GetRandomQRPaymentReference(); BillInfo := 'S1/10/DOCNO123'; QRCodeText := SwissQRBillTestLibrary.CreateQRCodeText(IBAN, 123.45, 'CHF', PaymentReference, 'Unstr Msg', BillInfo); @@ -849,7 +849,7 @@ codeunit 148096 "Swiss QR-Bill Test Purchases" // [FEATURE] [UI] // [SCENARIO 351182] Scan QR-Bill into Purchase Order, confirm create a new vendor bank account Initialize(); - IBAN := SwissQRBillTestLibrary.GetRandomIBAN(); + IBAN := SwissQRBillTestLibrary.GetFixedIBAN(); PaymentReference := SwissQRBillTestLibrary.GetRandomQRPaymentReference(); BillInfo := 'S1/10/DOCNO123'; QRCodeText := SwissQRBillTestLibrary.CreateQRCodeText(IBAN, 123.45, 'CHF', PaymentReference, 'Unstr Msg', BillInfo); @@ -1470,6 +1470,41 @@ codeunit 148096 "Swiss QR-Bill Test Purchases" LibraryVariableStorage.AssertEmpty(); end; + [Test] + [HandlerFunctions('QRBillScanMPH,ConfirmHandler')] + procedure InvoiceScanCreateBankAccountWrongIBAN() + var + PurchaseHeader: Record "Purchase Header"; + QRCodeText: Text; + PaymentReference: Code[50]; + IBAN: Code[50]; + BillInfo: Text; + begin + // [SCENARIO 501997] Scan QR-Bill into Purchase Invoice, confirm create a new vendor bank account when Incoming Document has IBAN in incorrect format. + Initialize(); + IBAN := 'CH5800791123000889013'; // IBAN fails mod97 validation + PaymentReference := SwissQRBillTestLibrary.GetRandomQRPaymentReference(); + BillInfo := 'S1/10/DOCNO123'; + QRCodeText := SwissQRBillTestLibrary.CreateQRCodeText(IBAN, 123.45, 'CHF', PaymentReference, 'Unstr Msg', BillInfo); + CreatePurchaseHeader(PurchaseHeader, DocumentType::Invoice, '', false, '123'); + + LibraryVariableStorage.Enqueue(QRCodeText); + LibraryVariableStorage.Enqueue(true); // confirm to create a new bank account + LibraryVariableStorage.Enqueue(false); // refuse to coninue on incorrect IBAN + ScanToInvoice(PurchaseHeader); + + // [THEN] IBAN is validated with mod97 operation when copied from Incoming Document to Vendor Bank Account. + // [THEN] Confirm message is shown "Then entered number may not be a valid IBAN. Do you want to continue?" + Assert.ExpectedMessage('Do you want to create a new vendor bank account?', LibraryVariableStorage.DequeueText()); + Assert.ExpectedMessage( + 'The number CH5800791123000889013 that you entered may not be a valid International Bank Account Number (IBAN)', + LibraryVariableStorage.DequeueText()); + + LibraryVariableStorage.AssertEmpty(); + PurchaseHeader.Delete(); + SwissQRBillTestLibrary.ClearVendor(PurchaseHeader."Buy-from Vendor No."); + end; + local procedure Initialize() begin LibraryVariableStorage.Clear(); diff --git a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/CashDocumentPostHandlerCZZ.Codeunit.al b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/CashDocumentPostHandlerCZZ.Codeunit.al index 3290b9bc26..041b814fe4 100644 --- a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/CashDocumentPostHandlerCZZ.Codeunit.al +++ b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/CashDocumentPostHandlerCZZ.Codeunit.al @@ -44,6 +44,18 @@ codeunit 31065 "Cash Document-Post Handler CZZ" end; end; + [EventSubscriber(ObjectType::Table, Database::"Sales Adv. Letter Entry CZZ", 'OnAfterInsertNewEntry', '', false, false)] + local procedure InsertTempSalesAdvLetterEntryOnAfterInsertAdvEntry(WriteToDatabase: Boolean; var SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ") + begin + if (not WriteToDatabase) or (not UseBuffer) then + exit; + + if SalesAdvLetterEntryCZZ."Entry Type" = SalesAdvLetterEntryCZZ."Entry Type"::Payment then begin + TempSalesAdvLetterEntryCZZ := SalesAdvLetterEntryCZZ; + TempSalesAdvLetterEntryCZZ.Insert(); + end; + end; + [EventSubscriber(ObjectType::Codeunit, Codeunit::"Cash Document-Post CZP", 'OnAfterPostLines', '', false, false)] local procedure PostAdvancePaymentVATOnAfterPostLines() var diff --git a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/CrossApplicationHandlerCZZ.Codeunit.al b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/CrossApplicationHandlerCZZ.Codeunit.al index 2ada097b71..fc0ee0644e 100644 --- a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/CrossApplicationHandlerCZZ.Codeunit.al +++ b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/CrossApplicationHandlerCZZ.Codeunit.al @@ -11,123 +11,118 @@ using System.Utilities; codeunit 31418 "Cross Application Handler CZZ" { +#if not CLEAN25 + ObsoleteState = Pending; + ObsoleteReason = 'The Access property will be changed to Internal.'; + ObsoleteTag = '25.0'; +#else + Access = Internal; +#endif + var ConfirmManagement: Codeunit "Confirm Management"; - [EventSubscriber(ObjectType::Table, Database::"Cash Document Line CZP", 'OnBeforeFindRelatedAmoutToApply', '', false, false)] - local procedure AddCashDocumentLineCZPOnBeforeFindRelatedAmoutToApply(CashDocumentLineCZP: Record "Cash Document Line CZP"; var AppliesToAdvanceLetterNo: Code[20]) + [EventSubscriber(ObjectType::Table, Database::"Cash Document Line CZP", 'OnAfterCollectSuggestedApplication', '', false, false)] + local procedure OnAfterCollectSuggestedApplicationCashDocumentLine(CashDocumentLineCZP: Record "Cash Document Line CZP"; var CrossApplicationBufferCZL: Record "Cross Application Buffer CZL") + begin + CollectSuggestedApplicationForPurchAdvLetter( + CashDocumentLineCZP."Advance Letter No. CZZ", CashDocumentLineCZP, CrossApplicationBufferCZL); + end; + + [EventSubscriber(ObjectType::Table, Database::"Payment Order Line CZB", 'OnAfterCollectSuggestedApplication', '', false, false)] + local procedure OnAfterCollectSuggestedApplicationPaymentOrderLine(PaymentOrderLineCZB: Record "Payment Order Line CZB"; var CrossApplicationBufferCZL: Record "Cross Application Buffer CZL") begin - AppliesToAdvanceLetterNo := CashDocumentLineCZP."Advance Letter No. CZZ"; + CollectSuggestedApplicationForPurchAdvLetter( + PaymentOrderLineCZB."Purch. Advance Letter No. CZZ", PaymentOrderLineCZB, CrossApplicationBufferCZL); end; - [EventSubscriber(ObjectType::Codeunit, Codeunit::"Cross Application Mgt. CZL", 'OnGetSuggestedAmountForPurchAdvLetterHeader', '', false, false)] - local procedure AddCashDocumentLineCZPOnGetSuggestedAmountForPurchAdvLetterHeader(var TempCrossApplicationBufferCZL: Record "Cross Application Buffer CZL" temporary; - PurchAdvLetterHeaderNo: Code[20]; - ExcludeTableID: Integer; ExcludeDocumentNo: Code[20]; ExcludeLineNo: Integer) + local procedure CollectSuggestedApplicationForPurchAdvLetter(PurchAdvanceLetterNo: Code[20]; CalledFrom: Variant; var CrossApplicationBufferCZL: Record "Cross Application Buffer CZL") + var + PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; + begin + if PurchAdvanceLetterNo = '' then + exit; + PurchAdvLetterHeaderCZZ.Get(PurchAdvanceLetterNo); + PurchAdvLetterHeaderCZZ.CollectSuggestedApplication(CalledFrom, CrossApplicationBufferCZL); + end; + + [EventSubscriber(ObjectType::Codeunit, Codeunit::"Cross Application Mgt. CZL", 'OnCollectSuggestedApplication', '', false, false)] + local procedure AddApplicationOnCollectSuggestedApplication( + CollectedForTableID: Integer; CollectedFor: Variant; var CrossApplicationBufferCZL: Record "Cross Application Buffer CZL") var CashDocumentLineCZP: Record "Cash Document Line CZP"; + PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; + IssPaymentOrderLineCZB: Record "Iss. Payment Order Line CZB"; begin - CashDocumentLineCZP.SetRange("Advance Letter No. CZZ", PurchAdvLetterHeaderNo); + if CollectedForTableID <> Database::"Purch. Adv. Letter Header CZZ" then + exit; + + PurchAdvLetterHeaderCZZ := CollectedFor; + + IssPaymentOrderLineCZB.SetRange("Purch. Advance Letter No. CZZ", PurchAdvLetterHeaderCZZ."No."); + IssPaymentOrderLineCZB.SetFilter(Status, '<>%1', IssPaymentOrderLineCZB.Status::Canceled); + if IssPaymentOrderLineCZB.FindSet() then + repeat + AddIssPaymentOrderLineToBuffer(IssPaymentOrderLineCZB, CrossApplicationBufferCZL); + until IssPaymentOrderLineCZB.Next() = 0; + + CashDocumentLineCZP.SetRange("Advance Letter No. CZZ", PurchAdvLetterHeaderCZZ."No."); if CashDocumentLineCZP.FindSet() then repeat - AddCashDocumentLineToBuffer(TempCrossApplicationBufferCZL, CashDocumentLineCZP, ExcludeTableID, ExcludeDocumentNo, ExcludeLineNo); + AddCashDocumentLineToBuffer(CashDocumentLineCZP, CrossApplicationBufferCZL); until CashDocumentLineCZP.Next() = 0; end; - local procedure AddCashDocumentLineToBuffer(var TempCrossApplicationBufferCZL: Record "Cross Application Buffer CZL" temporary; - CashDocumentLineCZP: Record "Cash Document Line CZP"; - ExcludeTableID: Integer; ExcludeDocumentNo: Code[20]; ExcludeLineNo: Integer) + local procedure AddCashDocumentLineToBuffer( + CashDocumentLineCZP: Record "Cash Document Line CZP"; + var CrossApplicationBufferCZL: Record "Cross Application Buffer CZL") var CashDocumentHeaderCZP: Record "Cash Document Header CZP"; begin - if (ExcludeTableID = Database::"Cash Document Line CZP") and - (ExcludeDocumentNo = CashDocumentLineCZP."Cash Document No.") and - (ExcludeLineNo = CashDocumentLineCZP."Line No.") - then - exit; - CashDocumentHeaderCZP.Get(CashDocumentLineCZP."Cash Desk No.", CashDocumentLineCZP."Cash Document No."); if CashDocumentHeaderCZP.Status <> CashDocumentHeaderCZP.Status::Released then exit; - TempCrossApplicationBufferCZL.Init(); - TempCrossApplicationBufferCZL."Entry No." := TempCrossApplicationBufferCZL.Count() + 1; - TempCrossApplicationBufferCZL."Table ID" := Database::"Cash Document Line CZP"; - TempCrossApplicationBufferCZL."Applied Document No." := CashDocumentLineCZP."Cash Document No."; - TempCrossApplicationBufferCZL."Applied Document Line No." := CashDocumentLineCZP."Line No."; - TempCrossApplicationBufferCZL."Applied Document Date" := CashDocumentHeaderCZP."Document Date"; + CrossApplicationBufferCZL.Init(); + CrossApplicationBufferCZL."Entry No." := CrossApplicationBufferCZL.Count() + 1; + CrossApplicationBufferCZL."Table ID" := Database::"Cash Document Line CZP"; + CrossApplicationBufferCZL."Applied Document No." := CashDocumentLineCZP."Cash Document No."; + CrossApplicationBufferCZL."Applied Document Line No." := CashDocumentLineCZP."Line No."; + CrossApplicationBufferCZL."Applied Document Date" := CashDocumentHeaderCZP."Document Date"; case CashDocumentHeaderCZP."Document Type" of CashDocumentHeaderCZP."Document Type"::Receipt: - TempCrossApplicationBufferCZL."Amount (LCY)" := CashDocumentLineCZP."Amount Including VAT (LCY)"; + CrossApplicationBufferCZL."Amount (LCY)" := CashDocumentLineCZP."Amount Including VAT (LCY)"; CashDocumentHeaderCZP."Document Type"::Withdrawal: - TempCrossApplicationBufferCZL."Amount (LCY)" := -CashDocumentLineCZP."Amount Including VAT (LCY)"; + CrossApplicationBufferCZL."Amount (LCY)" := -CashDocumentLineCZP."Amount Including VAT (LCY)"; end; - TempCrossApplicationBufferCZL.Insert(); + CrossApplicationBufferCZL.Insert(); end; - [EventSubscriber(ObjectType::Codeunit, Codeunit::"Cash Document-Release CZP", 'OnBeforeCheckCashDocumentLine', '', false, false)] - local procedure CheckSuggestedAmountToApplyOnBeforeCheckCashDocumentLine(CashDocumentLineCZP: Record "Cash Document Line CZP") - var - SuggestedAmountToApplyQst: Label 'Purchase Advance %1 is suggested to application on other documents in the system.\Do you want to use it for this Cash Document?', Comment = '%1 = Advance Letter No.'; - begin - if (CashDocumentLineCZP."Account Type" = CashDocumentLineCZP."Account Type"::Vendor) and (CashDocumentLineCZP."Advance Letter No. CZZ" <> '') then - if CashDocumentLineCZP.CalcRelatedAmountToApply() <> 0 then - if not ConfirmManagement.GetResponseOrDefault(StrSubstNo(SuggestedAmountToApplyQst, CashDocumentLineCZP."Advance Letter No. CZZ"), false) then - Error(''); - end; - - [EventSubscriber(ObjectType::Table, Database::"Payment Order Line CZB", 'OnBeforeFindRelatedAmoutToApply', '', false, false)] - local procedure AddPaymentOrderLineCZBOnBeforeFindRelatedAmoutToApply(PaymentOrderLineCZB: Record "Payment Order Line CZB"; var AppliesToAdvanceLetterNo: Code[20]) - begin - AppliesToAdvanceLetterNo := PaymentOrderLineCZB."Purch. Advance Letter No. CZZ"; - end; - - [EventSubscriber(ObjectType::Codeunit, Codeunit::"Cross Application Mgt. CZL", 'OnGetSuggestedAmountForPurchAdvLetterHeader', '', false, false)] - local procedure AddIssPaymentOrderLineCZBOnGetSuggestedAmountForPurchAdvLetterHeader(var TempCrossApplicationBufferCZL: Record "Cross Application Buffer CZL" temporary; - PurchAdvLetterHeaderNo: Code[20]; - ExcludeTableID: Integer; ExcludeDocumentNo: Code[20]; ExcludeLineNo: Integer) - var + local procedure AddIssPaymentOrderLineToBuffer( IssPaymentOrderLineCZB: Record "Iss. Payment Order Line CZB"; - begin - IssPaymentOrderLineCZB.SetRange("Purch. Advance Letter No. CZZ", PurchAdvLetterHeaderNo); - IssPaymentOrderLineCZB.SetFilter(Status, '<>%1', IssPaymentOrderLineCZB.Status::Canceled); - if IssPaymentOrderLineCZB.FindSet() then - repeat - AddPaymentOrderLineToBuffer(TempCrossApplicationBufferCZL, IssPaymentOrderLineCZB, ExcludeTableID, ExcludeDocumentNo, ExcludeLineNo); - until IssPaymentOrderLineCZB.Next() = 0; - end; - - local procedure AddPaymentOrderLineToBuffer(var TempCrossApplicationBufferCZL: Record "Cross Application Buffer CZL" temporary; - IssPaymentOrderLineCZB: Record "Iss. Payment Order Line CZB"; - ExcludeTableID: Integer; ExcludeDocumentNo: Code[20]; ExcludeLineNo: Integer) + var CrossApplicationBufferCZL: Record "Cross Application Buffer CZL") var IssPaymentOrderHeaderCZB: Record "Iss. Payment Order Header CZB"; begin - if (ExcludeTableID = Database::"Iss. Payment Order Line CZB") and - (ExcludeDocumentNo = IssPaymentOrderLineCZB."Payment Order No.") and - (ExcludeLineNo = IssPaymentOrderLineCZB."Line No.") - then - exit; - IssPaymentOrderHeaderCZB.Get(IssPaymentOrderLineCZB."Payment Order No."); - TempCrossApplicationBufferCZL.Init(); - TempCrossApplicationBufferCZL."Entry No." := TempCrossApplicationBufferCZL.Count() + 1; - TempCrossApplicationBufferCZL."Table ID" := Database::"Iss. Payment Order Line CZB"; - TempCrossApplicationBufferCZL."Applied Document No." := IssPaymentOrderLineCZB."Payment Order No."; - TempCrossApplicationBufferCZL."Applied Document Line No." := IssPaymentOrderLineCZB."Line No."; - TempCrossApplicationBufferCZL."Applied Document Date" := IssPaymentOrderHeaderCZB."Document Date"; - TempCrossApplicationBufferCZL."Amount (LCY)" := -IssPaymentOrderLineCZB."Amount (LCY)"; - TempCrossApplicationBufferCZL.Insert(); + CrossApplicationBufferCZL.Init(); + CrossApplicationBufferCZL."Entry No." := CrossApplicationBufferCZL.Count() + 1; + CrossApplicationBufferCZL."Table ID" := Database::"Iss. Payment Order Line CZB"; + CrossApplicationBufferCZL."Applied Document No." := IssPaymentOrderLineCZB."Payment Order No."; + CrossApplicationBufferCZL."Applied Document Line No." := IssPaymentOrderLineCZB."Line No."; + CrossApplicationBufferCZL."Applied Document Date" := IssPaymentOrderHeaderCZB."Document Date"; + CrossApplicationBufferCZL."Amount (LCY)" := -IssPaymentOrderLineCZB."Amount (LCY)"; + CrossApplicationBufferCZL.Insert(); end; - [EventSubscriber(ObjectType::Codeunit, Codeunit::"Issue Payment Order CZB", 'OnBeforeCheckPaymentOrderLine', '', false, false)] - local procedure CheckSuggestedAmountToApplyOnBeforeCheckPaymentOrderLine(var PaymentOrderLineCZB: Record "Payment Order Line CZB") + [EventSubscriber(ObjectType::Codeunit, Codeunit::"Cash Document-Release CZP", 'OnBeforeCheckCashDocumentLine', '', false, false)] + local procedure CheckSuggestedAmountToApplyOnBeforeCheckCashDocumentLine(CashDocumentLineCZP: Record "Cash Document Line CZP") var - SuggestedAmountToApplyQst: Label 'Purchase Advance %1 is suggested to application on other documents in the system.\Do you want to use it for this Payment Order?', Comment = '%1 = Purch. Advance Letter No.'; + SuggestedAmountToApplyQst: Label 'Purchase Advance %1 is suggested to application on other documents in the system.\Do you want to use it for this Cash Document?', Comment = '%1 = Advance Letter No.'; begin - if (PaymentOrderLineCZB.Type = PaymentOrderLineCZB.Type::Vendor) and (PaymentOrderLineCZB."Purch. Advance Letter No. CZZ" <> '') then - if PaymentOrderLineCZB.CalcRelatedAmountToApply() <> 0 then - if not ConfirmManagement.GetResponseOrDefault(StrSubstNo(SuggestedAmountToApplyQst, PaymentOrderLineCZB."Purch. Advance Letter No. CZZ"), false) then + if (CashDocumentLineCZP."Account Type" = CashDocumentLineCZP."Account Type"::Vendor) and (CashDocumentLineCZP."Advance Letter No. CZZ" <> '') then + if CashDocumentLineCZP.CalcRelatedAmountToApply() <> 0 then + if not ConfirmManagement.GetResponseOrDefault(StrSubstNo(SuggestedAmountToApplyQst, CashDocumentLineCZP."Advance Letter No. CZZ"), false) then Error(''); end; } diff --git a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/GenJnlCheckLnHandlerCZZ.Codeunit.al b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/GenJnlCheckLnHandlerCZZ.Codeunit.al index 0b17033d7e..80a9ad7a0c 100644 --- a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/GenJnlCheckLnHandlerCZZ.Codeunit.al +++ b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/GenJnlCheckLnHandlerCZZ.Codeunit.al @@ -40,4 +40,18 @@ codeunit 31109 "Gen.Jnl.-Check Ln. Handler CZZ" begin NewTransaction := false; end; + + [EventSubscriber(ObjectType::Codeunit, Codeunit::"Gen. Jnl.-Post Line", 'OnBeforeCheckVendMultiplePostingGroups', '', false, false)] + local procedure SuppressMultiplePostingGroupsOnBeforeCheckVendMultiplePostingGroups(var IsMultiplePostingGroups: Boolean; var IsHandled: Boolean) + begin + IsHandled := true; + IsMultiplePostingGroups := false; + end; + + [EventSubscriber(ObjectType::Codeunit, Codeunit::"Gen. Jnl.-Post Line", 'OnBeforeCheckCustMultiplePostingGroups', '', false, false)] + local procedure SuppressMultiplePostingGroupsOnBeforeCheckCustMultiplePostingGroups(var IsMultiplePostingGroups: Boolean; var IsHandled: Boolean) + begin + IsHandled := true; + IsMultiplePostingGroups := false; + end; } diff --git a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/GenJnlPostBatchHandlerCZZ.Codeunit.al b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/GenJnlPostBatchHandlerCZZ.Codeunit.al index 92e2ff8985..2332268f77 100644 --- a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/GenJnlPostBatchHandlerCZZ.Codeunit.al +++ b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/GenJnlPostBatchHandlerCZZ.Codeunit.al @@ -35,6 +35,18 @@ codeunit 31006 "Gen.Jnl-Post Batch Handler CZZ" end; end; + [EventSubscriber(ObjectType::Table, Database::"Sales Adv. Letter Entry CZZ", 'OnAfterInsertNewEntry', '', false, false)] + local procedure InsertTempSalesAdvLetterEntryOnAfterInsertAdvEntry(WriteToDatabase: Boolean; var SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ") + begin + if (not WriteToDatabase) or (not UseBuffer) then + exit; + + if SalesAdvLetterEntryCZZ."Entry Type" = SalesAdvLetterEntryCZZ."Entry Type"::Payment then begin + TempSalesAdvLetterEntryCZZ := SalesAdvLetterEntryCZZ; + TempSalesAdvLetterEntryCZZ.Insert(); + end; + end; + [EventSubscriber(ObjectType::Codeunit, Codeunit::"Gen. Jnl.-Post Batch", 'OnAfterProcessLines', '', false, false)] local procedure GenJnlPostBatchOnAfterProcessLines() begin diff --git a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/PaymentOrderMgtHandlerCZZ.Codeunit.al b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/PaymentOrderMgtHandlerCZZ.Codeunit.al index 3fcd70a119..2d29805e56 100644 --- a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/PaymentOrderMgtHandlerCZZ.Codeunit.al +++ b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/PaymentOrderMgtHandlerCZZ.Codeunit.al @@ -12,18 +12,16 @@ codeunit 31398 "Payment Order Mgt. Handler CZZ" [EventSubscriber(ObjectType::Codeunit, Codeunit::"Payment Order Management CZB", 'OnBeforeCheckPaymentOrderLineApplyToOtherEntries', '', false, false)] local procedure IsPurchAdvanceAppliedOnBeforeCheckPaymentOrderLineApplyToOtherEntries(var PaymentOrderLineCZB: Record "Payment Order Line CZB"; var TempErrorMessage: Record "Error Message"; var IsHandled: Boolean) var - IssPaymentOrderLineCZB: Record "Iss. Payment Order Line CZB"; PaymentOrderLineCZB2: Record "Payment Order Line CZB"; - PurchAdvanceAlreadyAppliedErr: Label '%1 %2 in %3 is already applied on other or the same payment order.', Comment = '%1 = Purch. Advance Letter No. CZZ FieldCaption; %2 = Purch. Advance Letter No. CZZ; %3 = RecordId'; + SuggestedAmountToApplyErr: Label 'Purchase Advance %1 is suggested to application on other documents in the system.', Comment = '%1 = Advance Letter No.'; begin if IsHandled then exit; if PaymentOrderLineCZB."Purch. Advance Letter No. CZZ" = '' then exit; - IssPaymentOrderLineCZB.SetRange("Purch. Advance Letter No. CZZ", PaymentOrderLineCZB."Purch. Advance Letter No. CZZ"); - IssPaymentOrderLineCZB.SetRange(Status, IssPaymentOrderLineCZB.Status::" "); - IsHandled := not IssPaymentOrderLineCZB.IsEmpty(); + IsHandled := PaymentOrderLineCZB.CalcRelatedAmountToApply() <> 0; + if not IsHandled then begin PaymentOrderLineCZB2.SetRange("Purch. Advance Letter No. CZZ", PaymentOrderLineCZB."Purch. Advance Letter No. CZZ"); PaymentOrderLineCZB2.SetFilter("Payment Order No.", '<>%1', PaymentOrderLineCZB."Payment Order No."); @@ -37,8 +35,9 @@ codeunit 31398 "Payment Order Mgt. Handler CZZ" if IsHandled then TempErrorMessage.LogMessage( - PaymentOrderLineCZB, PaymentOrderLineCZB.FieldNo(PaymentOrderLineCZB."Purch. Advance Letter No. CZZ"), TempErrorMessage."Message Type"::Warning, - StrSubstNo(PurchAdvanceAlreadyAppliedErr, - PaymentOrderLineCZB.FieldCaption(PaymentOrderLineCZB."Purch. Advance Letter No. CZZ"), PaymentOrderLineCZB."Purch. Advance Letter No. CZZ", PaymentOrderLineCZB.RecordId())); + PaymentOrderLineCZB, + PaymentOrderLineCZB.FieldNo(PaymentOrderLineCZB."Purch. Advance Letter No. CZZ"), + TempErrorMessage."Message Type"::Warning, + StrSubstNo(SuggestedAmountToApplyErr, PaymentOrderLineCZB."Purch. Advance Letter No. CZZ")); end; } diff --git a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/PurchAdvLetterManagementCZZ.Codeunit.al b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/PurchAdvLetterManagementCZZ.Codeunit.al index 19305682a3..5564672360 100644 --- a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/PurchAdvLetterManagementCZZ.Codeunit.al +++ b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/PurchAdvLetterManagementCZZ.Codeunit.al @@ -12,7 +12,6 @@ using Microsoft.Finance.VAT.Calculation; #endif using Microsoft.Finance.VAT.Ledger; using Microsoft.Finance.VAT.Setup; -using Microsoft.Foundation.AuditCodes; using Microsoft.Foundation.Enums; using Microsoft.Foundation.NoSeries; using Microsoft.Purchases.Document; @@ -29,6 +28,7 @@ codeunit 31019 "PurchAdvLetterManagement CZZ" 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"; #if not CLEAN22 #pragma warning disable AL0432 ReplaceVATDateMgtCZL: Codeunit "Replace VAT Date Mgt. CZL"; @@ -37,11 +37,11 @@ codeunit 31019 "PurchAdvLetterManagement CZZ" DateEmptyErr: Label 'Posting Date and VAT Date cannot be empty.'; DocumentNoOrDatesEmptyErr: Label 'Document No. and Dates cannot be empty.'; ExternalDocumentNoEmptyErr: Label 'External Document No. cannot be empty.'; - OriginalDocVATDateMustBeLessOrVATDateErr: Label 'Original Document VAT Date (%1) must be less or equal to VAT Date (%2).', Comment = '%1 = OriginalDocVATDate, %2 = VATDate'; NothingToPostErr: Label 'Nothing to Post.'; VATDocumentExistsErr: Label 'VAT Document already exists.'; PostingDateEmptyErr: Label 'Posting Date cannot be empty.'; LaterPostingDateQst: Label 'The linked advance letter %1 is paid after %2. If you continue, the advance letter won''t be deducted.\\Do you want to continue?', Comment = '%1 = advance letter no., %2 = posting date'; + ExceededUsageAmountErr: Label 'Post VAT Document higher than usage is not possible.'; procedure AdvEntryInit(Preview: Boolean) begin @@ -289,82 +289,14 @@ codeunit 31019 "PurchAdvLetterManagement CZZ" procedure PostAdvancePayment(var VendorLedgerEntry: Record "Vendor Ledger Entry"; PostedGenJournalLine: Record "Gen. Journal Line"; LinkAmount: Decimal; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; PostingDate: Date) var - PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; - GenJournalLine: Record "Gen. Journal Line"; - VendorLedgerEntry2: Record "Vendor Ledger Entry"; - ApplId: Code[50]; - Amount: Decimal; - AmountLCY: Decimal; - IsHandled: Boolean; - RemainingAmountExceededErr: Label 'The amount cannot be higher than remaining amount on ledger entry.'; - ToPayAmountExceededErr: Label 'The amount cannot be higher than to pay on advance letter.'; + AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; begin - OnBeforePostAdvancePayment(VendorLedgerEntry, PostedGenJournalLine, LinkAmount, GenJnlPostLine, IsHandled); - if IsHandled then - exit; + Clear(AdvancePostingParametersCZZ); + AdvancePostingParametersCZZ."Posting Date" := PostingDate; + AdvancePostingParametersCZZ."Amount to Link" := LinkAmount; - VendorLedgerEntry.TestField("Advance Letter No. CZZ", ''); - PurchAdvLetterHeaderCZZ.Get(PostedGenJournalLine."Advance Letter No. CZZ"); - PurchAdvLetterHeaderCZZ.CheckPurchaseAdvanceLetterPostRestrictions(); - PurchAdvLetterHeaderCZZ.TestField("Currency Code", VendorLedgerEntry."Currency Code"); - PurchAdvLetterHeaderCZZ.TestField("Pay-to Vendor No.", VendorLedgerEntry."Vendor No."); - if LinkAmount = 0 then begin - VendorLedgerEntry.CalcFields("Remaining Amount", "Remaining Amt. (LCY)"); - Amount := VendorLedgerEntry."Remaining Amount"; - AmountLCY := VendorLedgerEntry."Remaining Amt. (LCY)"; - end else begin - VendorLedgerEntry.CalcFields("Remaining Amount"); - if LinkAmount > VendorLedgerEntry."Remaining Amount" then - Error(RemainingAmountExceededErr); - - Amount := LinkAmount; - AmountLCY := Round(Amount / VendorLedgerEntry."Original Currency Factor"); - end; - PurchAdvLetterHeaderCZZ.CalcFields("To Pay"); - if Amount > PurchAdvLetterHeaderCZZ."To Pay" then - Error(ToPayAmountExceededErr); - - InitGenJnlLineFromVendLedgEntry(VendorLedgerEntry, GenJournalLine, GenJournalLine."Document Type"::" "); - GenJournalLine."Posting Date" := PostingDate; - GenJournalLine."Adv. Letter Template Code CZZ" := PurchAdvLetterHeaderCZZ."Advance Letter Code"; - GenJournalLine.Correction := true; - GenJournalLine.SetCurrencyFactor(VendorLedgerEntry."Currency Code", VendorLedgerEntry."Original Currency Factor"); - GenJournalLine.Amount := -Amount; - GenJournalLine."Amount (LCY)" := -AmountLCY; - - ApplId := CopyStr(VendorLedgerEntry."Document No." + Format(VendorLedgerEntry."Entry No.", 0, ''), 1, MaxStrLen(ApplId)); - VendorLedgerEntry.CalcFields("Remaining Amount"); - VendorLedgerEntry."Amount to Apply" := VendorLedgerEntry."Remaining Amount"; - VendorLedgerEntry."Applies-to ID" := ApplId; - VendorLedgerEntry."Adv. Letter Template Code CZZ" := PurchAdvLetterHeaderCZZ."Advance Letter Code"; - Codeunit.Run(Codeunit::"Vend. Entry-Edit", VendorLedgerEntry); - - GenJournalLine."Applies-to ID" := ApplId; - OnBeforePostPaymentRepos(GenJournalLine, PurchAdvLetterHeaderCZZ, PostedGenJournalLine); - GenJnlPostLine.RunWithCheck(GenJournalLine); - OnAfterPostPaymentRepos(GenJournalLine, PurchAdvLetterHeaderCZZ, PostedGenJournalLine); - - InitGenJnlLineFromVendLedgEntry(VendorLedgerEntry, GenJournalLine, GenJournalLine."Document Type"::" "); - GenJournalLine."Posting Date" := PostingDate; - GenJournalLine."Adv. Letter Template Code CZZ" := PurchAdvLetterHeaderCZZ."Advance Letter Code"; - GenJournalLine."Adv. Letter No. (Entry) CZZ" := PurchAdvLetterHeaderCZZ."No."; - GenJournalLine."Use Advance G/L Account CZZ" := true; - GenJournalLine.SetCurrencyFactor(VendorLedgerEntry."Currency Code", VendorLedgerEntry."Original Currency Factor"); - GenJournalLine.Amount := Amount; - GenJournalLine."Amount (LCY)" := AmountLCY; - OnBeforePostPayment(GenJournalLine, PurchAdvLetterHeaderCZZ, PostedGenJournalLine); - GenJnlPostLine.RunWithCheck(GenJournalLine); - OnAfterPostPayment(GenJournalLine, PurchAdvLetterHeaderCZZ, PostedGenJournalLine); - - VendorLedgerEntry2.FindLast(); - AdvEntryInit(false); - AdvEntryInitVendLedgEntryNo(VendorLedgerEntry2."Entry No."); - AdvEntryInsert("Advance Letter Entry Type CZZ"::Payment, PurchAdvLetterHeaderCZZ."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); - - UpdateStatus(PurchAdvLetterHeaderCZZ, PurchAdvLetterHeaderCZZ.Status::"To Use") + PurchAdvLetterPostCZZ.PostAdvancePayment( + VendorLedgerEntry, PostedGenJournalLine, GenJnlPostLine, AdvancePostingParametersCZZ); end; procedure GetAdvanceGLAccount(var GenJournalLine: Record "Gen. Journal Line"): Code[20] @@ -381,17 +313,13 @@ codeunit 31019 "PurchAdvLetterManagement CZZ" procedure PostAdvancePaymentVAT(var PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; PostingDate: Date) var - PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; - PurchAdvLetterEntryCZZ2: Record "Purch. Adv. Letter Entry CZZ"; AdvanceLetterTemplateCZZ: Record "Advance Letter Template CZZ"; + AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; + PurchAdvLetterEntryCZZ2: Record "Purch. Adv. Letter Entry CZZ"; + PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; TempAdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ" temporary; - GenJournalLine: Record "Gen. Journal Line"; - VATPostingSetup: Record "VAT Posting Setup"; VendorLedgerEntry: Record "Vendor Ledger Entry"; - PurchasesPayablesSetup: Record "Purchases & Payables Setup"; - DocumentTypeHandlerCZZ: Codeunit "Document Type Handler CZZ"; GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; - VATPostingSetupHandlerCZZ: Codeunit "VAT Posting Setup Handler CZZ"; ConfirmManagement: Codeunit "Confirm Management"; VATDocumentCZZ: Page "VAT Document CZZ"; DocumentNo: Code[20]; @@ -401,8 +329,8 @@ codeunit 31019 "PurchAdvLetterManagement CZZ" OriginalDocumentVATDate: Date; ExternalDocumentNo: Code[35]; VATDocumentExistsQst: Label 'VAT Document already exists.\Continue?'; - ExceededAmountErr: Label 'Amount has been exceeded.'; begin + IsHandled := false; OnBeforePostPaymentVAT(PurchAdvLetterEntryCZZ, PostingDate, IsHandled); if IsHandled then exit; @@ -441,124 +369,28 @@ codeunit 31019 "PurchAdvLetterManagement CZZ" VATDocumentCZZ.SaveNoSeries(); VATDocumentCZZ.GetDocument(DocumentNo, PostingDate, DocumentDate, VATDate, OriginalDocumentVATDate, ExternalDocumentNo, TempAdvancePostingBufferCZZ); - if (DocumentNo = '') or (PostingDate = 0D) or (VATDate = 0D) or (OriginalDocumentVATDate = 0D) then - Error(DocumentNoOrDatesEmptyErr); - if OriginalDocumentVATDate > VATDate then - Error(OriginalDocVATDateMustBeLessOrVATDateErr, OriginalDocumentVATDate, VATDate); - PurchasesPayablesSetup.Get(); - if PurchasesPayablesSetup."Ext. Doc. No. Mandatory" and (ExternalDocumentNo = '') then - Error(ExternalDocumentNoEmptyErr); + Clear(AdvancePostingParametersCZZ); + AdvancePostingParametersCZZ."Document Type" := Enum::"Gen. Journal Document Type"::Invoice; + AdvancePostingParametersCZZ."Document No." := DocumentNo; + AdvancePostingParametersCZZ."External Document No." := ExternalDocumentNo; + AdvancePostingParametersCZZ."Posting Description" := PurchAdvLetterHeaderCZZ."Posting Description"; + AdvancePostingParametersCZZ."Posting Date" := PostingDate; + AdvancePostingParametersCZZ."Document Date" := DocumentDate; + AdvancePostingParametersCZZ."VAT Date" := VATDate; + AdvancePostingParametersCZZ."Original Document VAT Date" := OriginalDocumentVATDate; + AdvancePostingParametersCZZ."Currency Code" := PurchAdvLetterEntryCZZ."Currency Code"; + AdvancePostingParametersCZZ."Currency Factor" := PurchAdvLetterEntryCZZ."Currency Factor"; -#pragma warning disable AA0210 - TempAdvancePostingBufferCZZ.SetFilter(Amount, '<>0'); -#pragma warning restore AA0210 - if TempAdvancePostingBufferCZZ.IsEmpty() then - Error(NothingToPostErr); - - PurchAdvLetterEntryCZZ2.CalcSums(Amount); - TempAdvancePostingBufferCZZ.CalcSums(Amount); - if (PurchAdvLetterEntryCZZ.Amount - PurchAdvLetterEntryCZZ2.Amount) < TempAdvancePostingBufferCZZ.Amount then - Error(ExceededAmountErr); - - GetCurrency(PurchAdvLetterEntryCZZ."Currency Code"); - - TempAdvancePostingBufferCZZ.FindSet(); - repeat - VATPostingSetup.Get(TempAdvancePostingBufferCZZ."VAT Bus. Posting Group", TempAdvancePostingBufferCZZ."VAT Prod. Posting Group"); - VATPostingSetup.TestField("Purch. Adv. Letter Account CZZ"); - VATPostingSetup.TestField("Purch. Adv.Letter VAT Acc. CZZ"); - - InitGenJnlLineFromAdvance(PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, DocumentNo, ExternalDocumentNo, VendorLedgerEntry."Source Code", PurchAdvLetterHeaderCZZ."Posting Description", GenJournalLine); - GenJournalLine."Document Type" := GenJournalLine."Document Type"::Invoice; - GenJournalLine.Validate("Posting Date", PostingDate); -#if not CLEAN22 -#pragma warning disable AL0432 - if not ReplaceVATDateMgtCZL.IsEnabled() then - GenJournalLine.Validate("VAT Date CZL", VATDate) - else -#pragma warning restore AL0432 -#endif - GenJournalLine.Validate("VAT Reporting Date", VATDate); - GenJournalLine.Validate("Original Doc. VAT Date CZL", OriginalDocumentVATDate); - GenJournalLine."Document Date" := DocumentDate; - GenJournalLine."Account No." := VATPostingSetup."Purch. Adv. Letter Account CZZ"; - GenJournalLine.SetCurrencyFactor(PurchAdvLetterEntryCZZ."Currency Code", PurchAdvLetterEntryCZZ."Currency Factor"); - GenJournalLine."Gen. Posting Type" := GenJournalLine."Gen. Posting Type"::Purchase; - GenJournalLine."VAT Calculation Type" := TempAdvancePostingBufferCZZ."VAT Calculation Type"; - GenJournalLine."VAT Bus. Posting Group" := TempAdvancePostingBufferCZZ."VAT Bus. Posting Group"; - GenJournalLine.Validate("VAT Prod. Posting Group", TempAdvancePostingBufferCZZ."VAT Prod. Posting Group"); - GenJournalLine.Validate(Amount, TempAdvancePostingBufferCZZ.Amount); - GenJournalLine."VAT Amount" := TempAdvancePostingBufferCZZ."VAT Amount"; - GenJournalLine."VAT Base Amount" := TempAdvancePostingBufferCZZ."VAT Base 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)" := TempAdvancePostingBufferCZZ."Amount (ACY)"; - GenJournalLine."VAT Amount (LCY)" := TempAdvancePostingBufferCZZ."VAT Amount (ACY)"; - GenJournalLine."VAT Base Amount (LCY)" := TempAdvancePostingBufferCZZ."VAT Base Amount (ACY)"; - GenJournalLine."Currency Factor" := GenJournalLine.Amount / GenJournalLine."Amount (LCY)"; - end else begin - GenJournalLine."Amount (LCY)" := GenJournalLine.Amount; - GenJournalLine."VAT Amount (LCY)" := GenJournalLine."VAT Amount"; - GenJournalLine."VAT Base Amount (LCY)" := GenJournalLine."VAT Base Amount"; - end; - 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."; - OnPostAdvancePaymentVATOnBeforeGenJnlPostLine(PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, GenJournalLine); - - BindSubscription(VATPostingSetupHandlerCZZ); - BindSubscription(DocumentTypeHandlerCZZ); - GenJnlPostLine.RunWithCheck(GenJournalLine); - UnbindSubscription(VATPostingSetupHandlerCZZ); - UnbindSubscription(DocumentTypeHandlerCZZ); - -#if not CLEAN22 -#pragma warning disable AL0432 - if not ReplaceVATDateMgtCZL.IsEnabled() then - GenJournalLine."VAT Reporting Date" := GenJournalLine."VAT Date CZL"; -#pragma warning restore AL0432 -#endif - AdvEntryInit(false); - AdvEntryInitRelatedEntry(PurchAdvLetterEntryCZZ."Entry No."); - 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 Payment", PurchAdvLetterHeaderCZZ."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, PurchAdvLetterEntryCZZ, DocumentNo, ExternalDocumentNo, VendorLedgerEntry."Source Code", PurchAdvLetterHeaderCZZ."Posting Description", GenJournalLine); - GenJournalLine.Validate("Posting Date", PostingDate); -#if not CLEAN22 -#pragma warning disable AL0432 - if not ReplaceVATDateMgtCZL.IsEnabled() then - GenJournalLine.Validate("VAT Date CZL", VATDate) - else -#pragma warning restore AL0432 -#endif - GenJournalLine.Validate("VAT Reporting Date", VATDate); - GenJournalLine.Validate("Original Doc. VAT Date CZL", OriginalDocumentVATDate); - GenJournalLine."Account No." := VATPostingSetup."Purch. Adv. Letter Account CZZ"; - GenJournalLine.SetCurrencyFactor(PurchAdvLetterEntryCZZ."Currency Code", PurchAdvLetterEntryCZZ."Currency Factor"); - GenJournalLine.Validate(Amount, -TempAdvancePostingBufferCZZ.Amount); - if GenJournalLine."Currency Code" <> '' then begin - GenJournalLine."Amount (LCY)" := -TempAdvancePostingBufferCZZ."Amount (ACY)"; - GenJournalLine."Currency Factor" := GenJournalLine.Amount / GenJournalLine."Amount (LCY)"; - end; - GenJnlPostLine.RunWithCheck(GenJournalLine); - until TempAdvancePostingBufferCZZ.Next() = 0; + PurchAdvLetterPostCZZ.PostAdvancePaymentVAT( + PurchAdvLetterEntryCZZ, TempAdvancePostingBufferCZZ, GenJnlPostLine, AdvancePostingParametersCZZ); end; local procedure InitVATAmountLine(var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; PurchAdvanceNo: Code[20]; Amount: Decimal; CurrencyFactor: Decimal) var PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; TempAdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ" temporary; + AmountRemainder: Decimal; Coeff: Decimal; begin AdvancePostingBufferCZZ.Reset(); @@ -571,6 +403,7 @@ codeunit 31019 "PurchAdvLetterManagement CZZ" PurchAdvLetterHeaderCZZ.CalcFields("Amount Including VAT"); Coeff := Amount / PurchAdvLetterHeaderCZZ."Amount Including VAT"; + AmountRemainder := 0; BufferAdvanceLines(PurchAdvLetterHeaderCZZ, TempAdvancePostingBufferCZZ); TempAdvancePostingBufferCZZ.SetFilter(Amount, '<>0'); @@ -578,9 +411,12 @@ codeunit 31019 "PurchAdvLetterManagement CZZ" repeat AdvancePostingBufferCZZ.Init(); AdvancePostingBufferCZZ := TempAdvancePostingBufferCZZ; - AdvancePostingBufferCZZ.RecalcAmountsByCoefficient(Coeff); + AmountRemainder += AdvancePostingBufferCZZ.Amount * Coeff; + AdvancePostingBufferCZZ.Amount := AmountRemainder; + AdvancePostingBufferCZZ.UpdateVATAmounts(); AdvancePostingBufferCZZ.UpdateLCYAmounts(PurchAdvLetterHeaderCZZ."Currency Code", CurrencyFactor); AdvancePostingBufferCZZ.Insert(); + AmountRemainder -= AdvancePostingBufferCZZ.Amount; until TempAdvancePostingBufferCZZ.Next() = 0; end; @@ -689,19 +525,10 @@ codeunit 31019 "PurchAdvLetterManagement CZZ" procedure UnlinkAdvancePayment(var PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; PostingDate: Date) var + AdvancePostingParametersCZZ: 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"; - VendorLedgerEntryPay: Record "Vendor Ledger Entry"; - VendorLedgerEntryAdv: Record "Vendor Ledger Entry"; - VendorLedgerEntry: Record "Vendor Ledger Entry"; AdvanceLetterApplicationCZZ: Record "Advance Letter Application CZZ"; - DocumentTypeHandlerCZZ: Codeunit "Document Type Handler CZZ"; GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; - VATPostingSetupHandlerCZZ: Codeunit "VAT Posting Setup Handler CZZ"; - GenJnlCheckLnHandlerCZZ: Codeunit "Gen.Jnl.-Check Ln. Handler CZZ"; - ApplId: Code[50]; UsedOnDocument: Text; UnlinkIsNotPossibleErr: Label 'Unlink is not possible, because %1 entry exists.', Comment = '%1 = Entry type'; UsedOnDocumentQst: Label 'Advance is used on document(s) %1.\Continue?', Comment = '%1 = Advance No. list'; @@ -727,709 +554,44 @@ codeunit 31019 "PurchAdvLetterManagement CZZ" if not Confirm(UsedOnDocumentQst, false, UsedOnDocument) then Error(''); - PurchAdvLetterHeaderCZZ.Get(PurchAdvLetterEntryCZZ."Purch. Adv. Letter No."); - GetCurrency(PurchAdvLetterHeaderCZZ."Currency Code"); - - PurchAdvLetterEntryCZZ2.SetRange("Entry Type", PurchAdvLetterEntryCZZ2."Entry Type"::"VAT Payment"); - if PurchAdvLetterEntryCZZ2.FindSet() then begin - repeat - VATPostingSetup.Get(PurchAdvLetterEntryCZZ2."VAT Bus. Posting Group", PurchAdvLetterEntryCZZ2."VAT Prod. Posting Group"); - VATPostingSetup.TestField("Purch. Adv. Letter Account CZZ"); - VATPostingSetup.TestField("Purch. Adv.Letter VAT Acc. CZZ"); - - InitGenJnlLineFromAdvance(PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ2, PurchAdvLetterEntryCZZ2."Document No.", PurchAdvLetterEntryCZZ2."External Document No.", '', '', GenJournalLine); - GenJournalLine."Document Type" := GenJournalLine."Document Type"::Invoice; - GenJournalLine.Validate("Posting Date", PurchAdvLetterEntryCZZ2."Posting 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.Validate(Amount, -PurchAdvLetterEntryCZZ2.Amount); - GenJournalLine."VAT Amount" := -PurchAdvLetterEntryCZZ2."VAT Amount"; - GenJournalLine."VAT Base Amount" := -PurchAdvLetterEntryCZZ2."VAT Base Amount"; - GenJournalLine."VAT Difference" := GenJournalLine."VAT Amount" - Round(GenJournalLine.Amount * GenJournalLine."VAT %" / (100 + GenJournalLine."VAT %"), - CurrencyGlob."Amount Rounding Precision", CurrencyGlob.VATRoundingDirection()); - GenJournalLine."Amount (LCY)" := -PurchAdvLetterEntryCZZ2."Amount (LCY)"; - GenJournalLine."VAT Amount (LCY)" := -PurchAdvLetterEntryCZZ2."VAT Amount (LCY)"; - GenJournalLine."VAT Base Amount (LCY)" := -PurchAdvLetterEntryCZZ2."VAT Base Amount (LCY)"; - BindSubscription(VATPostingSetupHandlerCZZ); - BindSubscription(DocumentTypeHandlerCZZ); - GenJnlPostLine.RunWithCheck(GenJournalLine); - UnbindSubscription(VATPostingSetupHandlerCZZ); - UnbindSubscription(DocumentTypeHandlerCZZ); - -#if not CLEAN22 -#pragma warning disable AL0432 - if not ReplaceVATDateMgtCZL.IsEnabled() then - GenJournalLine."VAT Reporting Date" := GenJournalLine."VAT Date CZL"; -#pragma warning restore AL0432 -#endif - AdvEntryInit(false); - AdvEntryInitRelatedEntry(PurchAdvLetterEntryCZZ."Entry No."); - 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(PurchAdvLetterEntryCZZ2."Entry Type", 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.", PurchAdvLetterEntryCZZ."External Document No.", '', '', GenJournalLine); - GenJournalLine.Validate("Posting Date", PurchAdvLetterEntryCZZ2."Posting Date"); - GenJournalLine."Account No." := VATPostingSetup."Purch. Adv. Letter Account CZZ"; - GenJournalLine.SetCurrencyFactor(PurchAdvLetterEntryCZZ2."Currency Code", PurchAdvLetterEntryCZZ2."Currency Factor"); - GenJournalLine.Amount := PurchAdvLetterEntryCZZ2.Amount; - GenJournalLine."Amount (LCY)" := PurchAdvLetterEntryCZZ2."Amount (LCY)"; - GenJnlPostLine.RunWithCheck(GenJournalLine); - until PurchAdvLetterEntryCZZ2.Next() = 0; - PurchAdvLetterEntryCZZ2.ModifyAll(Cancelled, true); - end; - - VendorLedgerEntryAdv.Get(PurchAdvLetterEntryCZZ."Vendor Ledger Entry No."); - VendorLedgerEntryPay := VendorLedgerEntryAdv; -#pragma warning disable AA0181 - VendorLedgerEntryPay.Next(-1); -#pragma warning restore AA0181 - UnapplyVendLedgEntry(VendorLedgerEntryPay, GenJnlPostLine); - - InitGenJnlLineFromVendLedgEntry(VendorLedgerEntryAdv, GenJournalLine, GenJournalLine."Document Type"::" "); - GenJournalLine."Posting Date" := PostingDate; - GenJournalLine."Adv. Letter Template Code CZZ" := PurchAdvLetterHeaderCZZ."Advance Letter Code"; - GenJournalLine.Correction := true; - GenJournalLine."Adv. Letter No. (Entry) CZZ" := PurchAdvLetterEntryCZZ."Purch. Adv. Letter No."; - GenJournalLine."Use Advance G/L Account CZZ" := true; - GenJournalLine.SetCurrencyFactor(PurchAdvLetterEntryCZZ."Currency Code", PurchAdvLetterEntryCZZ."Currency Factor"); - GenJournalLine.Amount := -PurchAdvLetterEntryCZZ.Amount; - GenJournalLine."Amount (LCY)" := -PurchAdvLetterEntryCZZ."Amount (LCY)"; - ApplId := CopyStr(VendorLedgerEntryAdv."Document No." + Format(VendorLedgerEntryAdv."Entry No.", 0, ''), 1, MaxStrLen(ApplId)); - VendorLedgerEntryAdv.Prepayment := false; - VendorLedgerEntryAdv."Advance Letter No. CZZ" := PurchAdvLetterEntryCZZ."Purch. Adv. Letter No."; - VendorLedgerEntryAdv.CalcFields("Remaining Amount"); - VendorLedgerEntryAdv."Amount to Apply" := VendorLedgerEntryAdv."Remaining Amount"; - VendorLedgerEntryAdv."Applies-to ID" := ApplId; - Codeunit.Run(Codeunit::"Vend. Entry-Edit", VendorLedgerEntryAdv); - GenJournalLine."Applies-to ID" := ApplId; - GenJnlPostLine.RunWithCheck(GenJournalLine); - - VendorLedgerEntry.FindLast(); + Clear(AdvancePostingParametersCZZ); + AdvancePostingParametersCZZ."Posting Date" := PostingDate; - AdvEntryInit(false); - AdvEntryInitVendLedgEntryNo(VendorLedgerEntry."Entry No."); - AdvEntryInitCancel(); - AdvEntryInitRelatedEntry(PurchAdvLetterEntryCZZ."Entry No."); - AdvEntryInsert(PurchAdvLetterEntryCZZ."Entry Type", GenJournalLine."Adv. Letter No. (Entry) CZZ", 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); - - InitGenJnlLineFromVendLedgEntry(VendorLedgerEntryAdv, GenJournalLine, GenJournalLine."Document Type"::" "); - GenJournalLine."Posting Date" := PostingDate; - GenJournalLine."Adv. Letter Template Code CZZ" := PurchAdvLetterHeaderCZZ."Advance Letter Code"; - GenJournalLine.SetCurrencyFactor(PurchAdvLetterEntryCZZ."Currency Code", PurchAdvLetterEntryCZZ."Currency Factor"); - GenJournalLine.Amount := PurchAdvLetterEntryCZZ.Amount; - GenJournalLine."Amount (LCY)" := PurchAdvLetterEntryCZZ."Amount (LCY)"; - ApplId := CopyStr(VendorLedgerEntryPay."Document No." + Format(VendorLedgerEntryPay."Entry No.", 0, ''), 1, MaxStrLen(ApplId)); - VendorLedgerEntryPay.CalcFields("Remaining Amount"); - VendorLedgerEntryPay."Amount to Apply" := VendorLedgerEntryPay."Remaining Amount"; - VendorLedgerEntryPay."Applies-to ID" := ApplId; - Codeunit.Run(Codeunit::"Vend. Entry-Edit", VendorLedgerEntryPay); - GenJournalLine."Applies-to ID" := ApplId; - GenJnlPostLine.RunWithCheck(GenJournalLine); - UnbindSubscription(GenJnlCheckLnHandlerCZZ); - - PurchAdvLetterEntryCZZ.Cancelled := true; - PurchAdvLetterEntryCZZ.Modify(); - - UpdateStatus(PurchAdvLetterHeaderCZZ, PurchAdvLetterHeaderCZZ.Status::"To Pay"); + PurchAdvLetterPostCZZ.PostAdvancePaymentUnlinking(PurchAdvLetterEntryCZZ, GenJnlPostLine, AdvancePostingParametersCZZ); end; procedure PostAdvancePaymentUsage(AdvLetterUsageDocTypeCZZ: Enum "Adv. Letter Usage Doc.Type CZZ"; DocumentNo: Code[20]; var PurchInvHeader: Record "Purch. Inv. Header"; var VendorLedgerEntry: Record "Vendor Ledger Entry"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; Preview: Boolean) var AdvanceLetterApplicationCZZ: Record "Advance Letter Application CZZ"; - TempAdvanceLetterApplicationCZZ: Record "Advance Letter Application CZZ" temporary; - TempPurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ" temporary; - PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; - PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; - AdvanceLetterTypeCZZ: Enum "Advance Letter Type CZZ"; - AmountToUse, UseAmount, UseAmountLCY : Decimal; - IsHandled: Boolean; + AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; begin - OnBeforePostAdvancePaymentUsage(AdvLetterUsageDocTypeCZZ, DocumentNo, PurchInvHeader, VendorLedgerEntry, GenJnlPostLine, Preview, IsHandled); - if IsHandled then - exit; - - if VendorLedgerEntry."Remaining Amount" = 0 then - VendorLedgerEntry.CalcFields("Remaining Amount"); - - if VendorLedgerEntry."Remaining Amount" = 0 then - exit; + AdvancePostingParametersCZZ."Temporary Entries Only" := Preview; AdvanceLetterApplicationCZZ.SetRange("Document Type", AdvLetterUsageDocTypeCZZ); AdvanceLetterApplicationCZZ.SetRange("Document No.", DocumentNo); - if AdvanceLetterApplicationCZZ.IsEmpty() then - exit; - - AdvanceLetterApplicationCZZ.FindSet(); - repeat - PurchAdvLetterHeaderCZZ.Get(AdvanceLetterApplicationCZZ."Advance Letter No."); - PurchAdvLetterHeaderCZZ.TestField("Currency Code", PurchInvHeader."Currency Code"); - PurchAdvLetterHeaderCZZ.TestField("Pay-to Vendor No.", PurchInvHeader."Pay-to Vendor No."); - - PurchAdvLetterEntryCZZ.SetRange("Purch. Adv. Letter No.", AdvanceLetterApplicationCZZ."Advance Letter No."); - PurchAdvLetterEntryCZZ.SetRange(Cancelled, false); - PurchAdvLetterEntryCZZ.SetRange("Entry Type", PurchAdvLetterEntryCZZ."Entry Type"::Payment); - PurchAdvLetterEntryCZZ.SetFilter("Posting Date", '..%1', PurchInvHeader."Posting Date"); - OnPostAdvancePaymentUsageOnBeforeLoopPurchAdvLetterEntry(AdvanceLetterApplicationCZZ, PurchAdvLetterEntryCZZ); - if PurchAdvLetterEntryCZZ.FindSet() then - repeat - TempPurchAdvLetterEntryCZZ := PurchAdvLetterEntryCZZ; - TempPurchAdvLetterEntryCZZ.Amount := GetRemAmtPurchAdvPayment(PurchAdvLetterEntryCZZ, 0D); - if TempPurchAdvLetterEntryCZZ.Amount <> 0 then - TempPurchAdvLetterEntryCZZ.Insert(); - until PurchAdvLetterEntryCZZ.Next() = 0; - TempAdvanceLetterApplicationCZZ.Init(); - TempAdvanceLetterApplicationCZZ."Advance Letter No." := AdvanceLetterApplicationCZZ."Advance Letter No."; - TempAdvanceLetterApplicationCZZ.Amount := AdvanceLetterApplicationCZZ.Amount; - TempAdvanceLetterApplicationCZZ."Amount (LCY)" := AdvanceLetterApplicationCZZ."Amount (LCY)"; - TempAdvanceLetterApplicationCZZ.Insert(); - until AdvanceLetterApplicationCZZ.Next() = 0; - - AmountToUse := -VendorLedgerEntry."Remaining Amount"; - TempPurchAdvLetterEntryCZZ.Reset(); - TempPurchAdvLetterEntryCZZ.SetCurrentKey("Posting Date"); - if TempPurchAdvLetterEntryCZZ.FindSet() then - repeat - TempAdvanceLetterApplicationCZZ.Get(0, TempPurchAdvLetterEntryCZZ."Purch. Adv. Letter No."); - if TempAdvanceLetterApplicationCZZ.Amount < TempPurchAdvLetterEntryCZZ.Amount then - TempPurchAdvLetterEntryCZZ.Amount := TempAdvanceLetterApplicationCZZ.Amount; - - if AmountToUse > TempPurchAdvLetterEntryCZZ.Amount then - UseAmount := TempPurchAdvLetterEntryCZZ.Amount - else - UseAmount := AmountToUse; - - if UseAmount <> 0 then begin - PurchAdvLetterEntryCZZ.Get(TempPurchAdvLetterEntryCZZ."Entry No."); - UseAmountLCY := Round(GetRemAmtLCYPurchAdvPayment(PurchAdvLetterEntryCZZ, 0D) * UseAmount / GetRemAmtPurchAdvPayment(PurchAdvLetterEntryCZZ, 0D)); - ReverseAdvancePayment(PurchAdvLetterEntryCZZ, PurchInvHeader, UseAmount, UseAmountLCY, VendorLedgerEntry, GenJnlPostLine, Preview); - AmountToUse -= UseAmount; - TempAdvanceLetterApplicationCZZ.Amount -= UseAmount; - TempAdvanceLetterApplicationCZZ."Amount (LCY)" -= UseAmountLCY; - TempAdvanceLetterApplicationCZZ.Modify(); - - if not Preview then - if AdvanceLetterApplicationCZZ.Get(AdvanceLetterTypeCZZ::Purchase, PurchAdvLetterEntryCZZ."Purch. Adv. Letter No.", AdvLetterUsageDocTypeCZZ, DocumentNo) then - if AdvanceLetterApplicationCZZ.Amount <= UseAmount then - AdvanceLetterApplicationCZZ.Delete(true) - else begin - AdvanceLetterApplicationCZZ.Amount -= UseAmount; - AdvanceLetterApplicationCZZ.Modify(); - end; - end; - until (TempPurchAdvLetterEntryCZZ.Next() = 0) or (AmountToUse = 0); - end; - - local procedure ReverseAdvancePayment(var PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; PurchInvHeader: Record "Purch. Inv. Header"; ReverseAmount: Decimal; ReverseAmountLCY: Decimal; var VendorLedgerEntry: Record "Vendor Ledger Entry"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; Preview: Boolean) - var - GenJournalLine: Record "Gen. Journal Line"; - PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; - VendorLedgerEntry2: Record "Vendor Ledger Entry"; - DocumentTypeHandlerCZZ: Codeunit "Document Type Handler CZZ"; - GenJnlCheckLnHandlerCZZ: Codeunit "Gen.Jnl.-Check Ln. Handler CZZ"; - RemainingAmount: Decimal; - RemainingAmountLCY: Decimal; - ApplId: Code[50]; - ReverseErr: Label 'Reverse amount %1 is not posible on entry %2.', Comment = '%1 = Reverse Amount, %2 = Purchase Advance Entry No.'; - begin - RemainingAmount := GetRemAmtPurchAdvPayment(PurchAdvLetterEntryCZZ, 0D); - RemainingAmountLCY := GetRemAmtLCYPurchAdvPayment(PurchAdvLetterEntryCZZ, 0D); - - if ReverseAmount <> 0 then begin - if ReverseAmount > RemainingAmount then - Error(ReverseErr, ReverseAmount, PurchAdvLetterEntryCZZ."Entry No."); - end else begin - ReverseAmount := RemainingAmount; - ReverseAmountLCY := RemainingAmountLCY; - end; - - PurchAdvLetterHeaderCZZ.Get(PurchAdvLetterEntryCZZ."Purch. Adv. Letter No."); - - InitGenJnlLineFromVendLedgEntry(VendorLedgerEntry, GenJournalLine, GenJournalLine."Document Type"::" "); - GenJournalLine."Adv. Letter Template Code CZZ" := PurchAdvLetterHeaderCZZ."Advance Letter Code"; - GenJournalLine.Correction := true; - GenJournalLine.SetCurrencyFactor(PurchAdvLetterEntryCZZ."Currency Code", PurchAdvLetterEntryCZZ."Currency Factor"); - GenJournalLine.Amount := ReverseAmount; - GenJournalLine."Amount (LCY)" := ReverseAmountLCY; - - if not Preview then begin - ApplId := CopyStr(VendorLedgerEntry."Document No." + Format(VendorLedgerEntry."Entry No.", 0, ''), 1, MaxStrLen(ApplId)); - VendorLedgerEntry.CalcFields("Remaining Amount"); - VendorLedgerEntry."Adv. Letter Template Code CZZ" := PurchAdvLetterHeaderCZZ."Advance Letter Code"; - VendorLedgerEntry."Amount to Apply" := VendorLedgerEntry."Remaining Amount"; - VendorLedgerEntry."Applies-to ID" := ApplId; - Codeunit.Run(Codeunit::"Vend. Entry-Edit", VendorLedgerEntry); - GenJournalLine."Applies-to ID" := ApplId; - - OnBeforePostReversePaymentRepos(GenJournalLine, PurchAdvLetterHeaderCZZ); - BindSubscription(GenJnlCheckLnHandlerCZZ); - GenJnlPostLine.RunWithCheck(GenJournalLine); - OnAfterPostReversePaymentRepos(GenJournalLine, PurchAdvLetterHeaderCZZ); - end; - - InitGenJnlLineFromVendLedgEntry(VendorLedgerEntry, GenJournalLine, GenJournalLine."Document Type"::Invoice); - GenJournalLine."Adv. Letter Template Code CZZ" := PurchAdvLetterHeaderCZZ."Advance Letter Code"; - GenJournalLine."Adv. Letter No. (Entry) CZZ" := PurchAdvLetterEntryCZZ."Purch. Adv. Letter No."; - GenJournalLine."Use Advance G/L Account CZZ" := true; - GenJournalLine.SetCurrencyFactor(PurchAdvLetterEntryCZZ."Currency Code", PurchAdvLetterEntryCZZ."Currency Factor"); - GenJournalLine.Amount := -ReverseAmount; - GenJournalLine."Amount (LCY)" := -ReverseAmountLCY; - - VendorLedgerEntry2.Get(PurchAdvLetterEntryCZZ."Vendor Ledger Entry No."); - if not Preview then begin - ApplId := CopyStr(VendorLedgerEntry2."Document No." + Format(VendorLedgerEntry2."Entry No.", 0, ''), 1, MaxStrLen(ApplId)); - VendorLedgerEntry2.Prepayment := false; - VendorLedgerEntry2."Advance Letter No. CZZ" := PurchAdvLetterEntryCZZ."Purch. Adv. Letter No."; - VendorLedgerEntry2.Modify(); - VendorLedgerEntry2.CalcFields("Remaining Amount"); - VendorLedgerEntry2."Amount to Apply" := VendorLedgerEntry2."Remaining Amount"; - VendorLedgerEntry2."Applies-to ID" := ApplId; - Codeunit.Run(Codeunit::"Vend. Entry-Edit", VendorLedgerEntry2); - GenJournalLine."Applies-to ID" := ApplId; - - OnBeforePostReversePayment(GenJournalLine, PurchAdvLetterHeaderCZZ); - BindSubscription(DocumentTypeHandlerCZZ); - GenJnlPostLine.RunWithCheck(GenJournalLine); - UnbindSubscription(GenJnlCheckLnHandlerCZZ); - UnbindSubscription(DocumentTypeHandlerCZZ); - OnAfterPostReversePayment(GenJournalLine, PurchAdvLetterHeaderCZZ); - - VendorLedgerEntry2.FindLast(); - end; - - AdvEntryInit(Preview); - AdvEntryInitVendLedgEntryNo(VendorLedgerEntry2."Entry No."); - AdvEntryInitRelatedEntry(PurchAdvLetterEntryCZZ."Entry No."); - AdvEntryInsert("Advance Letter Entry Type CZZ"::Usage, GenJournalLine."Adv. Letter No. (Entry) CZZ", 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", Preview); - - if PurchAdvLetterHeaderCZZ."Automatic Post VAT Usage" then - ReverseAdvancePaymentVAT(PurchAdvLetterEntryCZZ, VendorLedgerEntry."Source Code", VendorLedgerEntry.Description, - PurchInvHeader."VAT Currency Factor CZL", Enum::"Gen. Journal Document Type"::Invoice, - VendorLedgerEntry."Document No.", VendorLedgerEntry."External Document No.", - VendorLedgerEntry."Posting Date", VendorLedgerEntry."VAT Date CZL", PurchInvHeader."Original Doc. VAT Date CZL", - ReverseAmount, PurchAdvLetterEntryCZZGlob."Entry No.", VendorLedgerEntry."Document No.", - "Advance Letter Entry Type CZZ"::"VAT Usage", true, GenJnlPostLine, Preview); - - if not Preview then begin - PurchAdvLetterHeaderCZZ.Get(PurchAdvLetterEntryCZZ."Purch. Adv. Letter No."); - UpdateStatus(PurchAdvLetterHeaderCZZ, PurchAdvLetterHeaderCZZ.Status::Closed); - end; - end; - - local procedure ReverseAdvancePaymentVAT(var PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; SourceCode: Code[10]; PostDescription: Text[100]; CurrencyFactor: Decimal; DocumentType: Enum "Gen. Journal Document Type"; DocumentNo: Code[20]; ExternalDocumentNo: Code[35]; PostingDate: Date; VATDate: Date; OriginalDocumentVATDate: Date; ReverseAmount: Decimal; UsageEntryNo: Integer; InvoiceNo: Code[20]; EntryType: enum "Advance Letter Entry Type CZZ"; AutoPostVATUsage: Boolean; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; Preview: Boolean) - var - PurchAdvLetterEntryCZZ2: Record "Purch. Adv. Letter Entry CZZ"; - TempAdvancePostingBufferCZZ1: Record "Advance Posting Buffer CZZ" temporary; - TempAdvancePostingBufferCZZ2: Record "Advance Posting Buffer CZZ" temporary; - GenJournalLine: Record "Gen. Journal Line"; - VATPostingSetup: Record "VAT Posting Setup"; - PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; - PurchasesPayablesSetup: Record "Purchases & Payables Setup"; - DocumentTypeHandlerCZZ: Codeunit "Document Type Handler CZZ"; - VATPostingSetupHandlerCZZ: Codeunit "VAT Posting Setup Handler CZZ"; - VATDocumentCZZ: Page "VAT Document CZZ"; - CalcVATAmountLCY: Decimal; - CalcAmountLCY: Decimal; - ExchRateAmount: Decimal; - ExchRateVATAmount: Decimal; - AmountToUse: Decimal; - DocumentDate: Date; - IsHandled: Boolean; - UsedMoreAmountErr: Label 'Post VAT Document higher than usage is not possible.'; - begin - OnBeforePostReversePaymentVAT(PurchAdvLetterEntryCZZ, PostingDate, Preview, IsHandled); - if IsHandled then - exit; - - 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 - exit; - - GetCurrency(PurchAdvLetterEntryCZZ."Currency Code"); - PurchAdvLetterHeaderCZZ.Get(PurchAdvLetterEntryCZZ."Purch. Adv. Letter No."); - - BufferAdvanceVATLines(PurchAdvLetterEntryCZZ, TempAdvancePostingBufferCZZ1, 0D); - SuggestUsageVAT(PurchAdvLetterEntryCZZ, TempAdvancePostingBufferCZZ1, InvoiceNo, ReverseAmount, CurrencyFactor, Preview); - - if not AutoPostVATUsage then begin - VATDocumentCZZ.InitDocument('', DocumentNo, PostingDate, PostingDate, VATDate, - OriginalDocumentVATDate, PurchAdvLetterHeaderCZZ."Currency Code", CurrencyFactor, ExternalDocumentNo, TempAdvancePostingBufferCZZ1); - if VATDocumentCZZ.RunModal() <> Action::OK then - exit; - - VATDocumentCZZ.GetDocument(DocumentNo, PostingDate, DocumentDate, VATDate, OriginalDocumentVATDate, ExternalDocumentNo, TempAdvancePostingBufferCZZ1); - if (DocumentNo = '') or (PostingDate = 0D) or (VATDate = 0D) or (OriginalDocumentVATDate = 0D) then - Error(DocumentNoOrDatesEmptyErr); - - if OriginalDocumentVATDate > VATDate then - Error(OriginalDocVATDateMustBeLessOrVATDateErr, OriginalDocumentVATDate, VATDate); - PurchasesPayablesSetup.Get(); - if PurchasesPayablesSetup."Ext. Doc. No. Mandatory" and (ExternalDocumentNo = '') then - Error(ExternalDocumentNoEmptyErr); - - TempAdvancePostingBufferCZZ1.SetFilter(Amount, '<>0'); - if TempAdvancePostingBufferCZZ1.IsEmpty() then - Error(NothingToPostErr); - - if ReverseAmount <> 0 then begin - TempAdvancePostingBufferCZZ1.CalcSums(Amount); - if TempAdvancePostingBufferCZZ1.Amount > ReverseAmount then - Error(UsedMoreAmountErr); - end; - end; - - if OriginalDocumentVATDate = 0D then - OriginalDocumentVATDate := VATDate; - - TempAdvancePostingBufferCZZ1.FilterGroup(-1); -#pragma warning disable AA0210 - TempAdvancePostingBufferCZZ1.SetFilter("VAT Base Amount", '<>0'); - TempAdvancePostingBufferCZZ1.SetFilter("VAT Amount", '<>0'); -#pragma warning restore AA0210 - TempAdvancePostingBufferCZZ1.FilterGroup(0); - if TempAdvancePostingBufferCZZ1.IsEmpty() then - exit; - - if PurchAdvLetterEntryCZZ."Currency Code" <> '' then begin - BufferAdvanceVATLines(PurchAdvLetterEntryCZZ, TempAdvancePostingBufferCZZ2, 0D); - TempAdvancePostingBufferCZZ2.CalcSums(Amount); - AmountToUse := TempAdvancePostingBufferCZZ2.Amount; - end; - - CalculateVATAmountInBuffer(PostingDate, PurchAdvLetterEntryCZZ."Currency Code", CurrencyFactor, TempAdvancePostingBufferCZZ1); - - TempAdvancePostingBufferCZZ1.FindSet(); - repeat - VATPostingSetup.Get(TempAdvancePostingBufferCZZ1."VAT Bus. Posting Group", TempAdvancePostingBufferCZZ1."VAT Prod. Posting Group"); - VATPostingSetup.TestField("Purch. Adv. Letter Account CZZ"); - VATPostingSetup.TestField("Purch. Adv.Letter VAT Acc. CZZ"); - - InitGenJnlLineFromAdvance(PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, DocumentNo, ExternalDocumentNo, SourceCode, PostDescription, GenJournalLine); - GenJournalLine."Document Type" := DocumentType; - GenJournalLine.Validate("Posting Date", PostingDate); -#if not CLEAN22 -#pragma warning disable AL0432 - if not ReplaceVATDateMgtCZL.IsEnabled() then - GenJournalLine.Validate("VAT Date CZL", VATDate) - else -#pragma warning restore AL0432 -#endif - GenJournalLine.Validate("VAT Reporting Date", VATDate); - GenJournalLine.Validate("Original Doc. VAT Date CZL", OriginalDocumentVATDate); - GenJournalLine."Document Date" := DocumentDate; - GenJournalLine."Account No." := VATPostingSetup."Purch. Adv. Letter Account CZZ"; - GenJournalLine.SetCurrencyFactor(PurchAdvLetterEntryCZZ."Currency Code", CurrencyFactor); - GenJournalLine."Gen. Posting Type" := GenJournalLine."Gen. Posting Type"::Purchase; - GenJournalLine."VAT Calculation Type" := TempAdvancePostingBufferCZZ1."VAT Calculation Type"; - if GenJournalLine."VAT Calculation Type" = GenJournalLine."VAT Calculation Type"::"Reverse Charge VAT" then - GenJournalLine."VAT Posting" := GenJournalLine."VAT Posting"::"Manual VAT Entry"; - GenJournalLine."VAT Bus. Posting Group" := TempAdvancePostingBufferCZZ1."VAT Bus. Posting Group"; - GenJournalLine.Validate("VAT Prod. Posting Group", TempAdvancePostingBufferCZZ1."VAT Prod. Posting Group"); - GenJournalLine.Validate(Amount, -TempAdvancePostingBufferCZZ1.Amount); - GenJournalLine."VAT Amount" := -TempAdvancePostingBufferCZZ1."VAT Amount"; - GenJournalLine."VAT Base Amount" := -TempAdvancePostingBufferCZZ1."VAT Base 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)" := -TempAdvancePostingBufferCZZ1."Amount (ACY)"; - GenJournalLine."VAT Amount (LCY)" := -TempAdvancePostingBufferCZZ1."VAT Amount (ACY)"; - GenJournalLine."VAT Base Amount (LCY)" := -TempAdvancePostingBufferCZZ1."VAT Base Amount (ACY)"; - GenJournalLine."Currency Factor" := GenJournalLine.Amount / GenJournalLine."Amount (LCY)"; - end else begin - GenJournalLine."Amount (LCY)" := GenJournalLine.Amount; - GenJournalLine."VAT Amount (LCY)" := GenJournalLine."VAT Amount"; - GenJournalLine."VAT Base Amount (LCY)" := GenJournalLine."VAT Base Amount"; - end; - if not Preview then begin - BindSubscription(VATPostingSetupHandlerCZZ); - BindSubscription(DocumentTypeHandlerCZZ); - GenJnlPostLine.RunWithCheck(GenJournalLine); - UnbindSubscription(VATPostingSetupHandlerCZZ); - UnbindSubscription(DocumentTypeHandlerCZZ); - end; - - if TempAdvancePostingBufferCZZ1."VAT Calculation Type" = TempAdvancePostingBufferCZZ1."VAT Calculation Type"::"Reverse Charge VAT" then begin - GenJournalLine."VAT Amount" := 0; - GenJournalLine."VAT Amount (LCY)" := 0; - end; - -#if not CLEAN22 -#pragma warning disable AL0432 - if not ReplaceVATDateMgtCZL.IsEnabled() then - GenJournalLine."VAT Reporting Date" := GenJournalLine."VAT Date CZL"; -#pragma warning restore AL0432 -#endif - AdvEntryInit(Preview); - AdvEntryInitRelatedEntry(UsageEntryNo); - 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(EntryType, PurchAdvLetterEntryCZZ."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", Preview); - - if GenJournalLine."Currency Code" <> '' then begin - TempAdvancePostingBufferCZZ2.Reset(); - TempAdvancePostingBufferCZZ2.SetRange("VAT Bus. Posting Group", TempAdvancePostingBufferCZZ1."VAT Bus. Posting Group"); - TempAdvancePostingBufferCZZ2.SetRange("VAT Prod. Posting Group", TempAdvancePostingBufferCZZ1."VAT Prod. Posting Group"); - if TempAdvancePostingBufferCZZ2.FindFirst() then begin - CalcAmountLCY := Round(TempAdvancePostingBufferCZZ2."Amount (ACY)" * TempAdvancePostingBufferCZZ1.Amount / TempAdvancePostingBufferCZZ2.Amount); - CalcVATAmountLCY := Round(TempAdvancePostingBufferCZZ2."VAT Amount (ACY)" * TempAdvancePostingBufferCZZ1.Amount / TempAdvancePostingBufferCZZ2.Amount); - - ExchRateAmount := CalcAmountLCY + GenJournalLine."Amount (LCY)"; - ExchRateVATAmount := CalcVATAmountLCY + GenJournalLine."VAT Amount (LCY)"; - if (ExchRateAmount <> 0) or (ExchRateVATAmount <> 0) then - PostExchangeRate(-ExchRateAmount, -ExchRateVATAmount, PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, VATPostingSetup, - DocumentNo, PostingDate, VATDate, SourceCode, PostDescription, UsageEntryNo, false, GenJnlPostLine, Preview); - - ReverseUnrealizedExchangeRate(PurchAdvLetterEntryCZZ, PurchAdvLetterHeaderCZZ, VATPostingSetup, TempAdvancePostingBufferCZZ1.Amount / AmountToUse, - UsageEntryNo, DocumentNo, PostingDate, VATDate, PostDescription, GenJnlPostLine, Preview); - end; - end; - - InitGenJnlLineFromAdvance(PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, DocumentNo, ExternalDocumentNo, SourceCode, PostDescription, GenJournalLine); - GenJournalLine.Validate("Posting Date", PostingDate); -#if not CLEAN22 -#pragma warning disable AL0432 - if not ReplaceVATDateMgtCZL.IsEnabled() then - GenJournalLine.Validate("VAT Date CZL", VATDate) - else -#pragma warning restore AL0432 -#endif - GenJournalLine.Validate("VAT Reporting Date", VATDate); - GenJournalLine.Validate("Original Doc. VAT Date CZL", OriginalDocumentVATDate); - GenJournalLine."Document Date" := DocumentDate; - GenJournalLine."Account No." := VATPostingSetup."Purch. Adv. Letter Account CZZ"; - GenJournalLine.SetCurrencyFactor(PurchAdvLetterEntryCZZ."Currency Code", CurrencyFactor); - GenJournalLine.Validate(Amount, TempAdvancePostingBufferCZZ1.Amount); - if GenJournalLine."Currency Code" <> '' then - GenJournalLine."Amount (LCY)" := TempAdvancePostingBufferCZZ1."Amount (ACY)"; - if not Preview then - GenJnlPostLine.RunWithCheck(GenJournalLine); - until TempAdvancePostingBufferCZZ1.Next() = 0; - - if not Preview then - UpdateStatus(PurchAdvLetterHeaderCZZ, PurchAdvLetterHeaderCZZ.Status::Closed); - end; - - local procedure CalculateVATAmountInBuffer(PostingDate: Date; CurrencyCode: Code[10]; CurrencyFactor: Decimal; var TempAdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ" temporary) - var - VATPostingSetup: Record "VAT Posting Setup"; - CurrExchRate: Record "Currency Exchange Rate"; - VATAmount: Decimal; - VATAmountRemainder: Decimal; - begin - VATAmountRemainder := 0; - - GetCurrency(CurrencyCode); - - if TempAdvancePostingBufferCZZ.FindSet() then - repeat - if TempAdvancePostingBufferCZZ."VAT Calculation Type" = TempAdvancePostingBufferCZZ."VAT Calculation Type"::"Reverse Charge VAT" then begin - VATPostingSetup.Get(TempAdvancePostingBufferCZZ."VAT Bus. Posting Group", TempAdvancePostingBufferCZZ."VAT Prod. Posting Group"); - - VATAmount := TempAdvancePostingBufferCZZ."VAT Base Amount" * VATPostingSetup."VAT %" / 100; - - VATAmountRemainder += VATAmount; - TempAdvancePostingBufferCZZ."VAT Amount" := Round(VATAmountRemainder, CurrencyGlob."Amount Rounding Precision"); - TempAdvancePostingBufferCZZ."VAT Amount (ACY)" := TempAdvancePostingBufferCZZ."VAT Amount"; - VATAmountRemainder -= TempAdvancePostingBufferCZZ."VAT Amount"; - - if CurrencyCode <> '' then - TempAdvancePostingBufferCZZ."VAT Amount (ACY)" := - Round( - CurrExchRate.ExchangeAmtFCYToLCY( - PostingDate, CurrencyCode, TempAdvancePostingBufferCZZ."VAT Amount", CurrencyFactor)); - TempAdvancePostingBufferCZZ.Modify(); - end - until TempAdvancePostingBufferCZZ.Next() = 0; - end; - - local procedure SuggestUsageVAT(var PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; InvoiceNo: Code[20]; UsedAmount: Decimal; CurrencyFactor: Decimal; Preview: Boolean) - var - PurchInvLine: Record "Purch. Inv. Line"; - PurchaseLine: Record "Purchase Line"; - TempAdvancePostingBufferCZZ1: Record "Advance Posting Buffer CZZ" temporary; - TempAdvancePostingBufferCZZ2: Record "Advance Posting Buffer CZZ" temporary; - TotalAmount: Decimal; - UseAmount: Decimal; - UseBaseAmount: Decimal; - i: Integer; - Continue: Boolean; - begin - AdvancePostingBufferCZZ.CalcSums(Amount); - TotalAmount := AdvancePostingBufferCZZ.Amount; - if (UsedAmount <> 0) and (TotalAmount > UsedAmount) then begin - Continue := InvoiceNo <> ''; - if Continue then - if Preview then begin - PurchaseLine.SetFilter("Document Type", '%1|%2', PurchaseLine."Document Type"::Order, PurchaseLine."Document Type"::Invoice); - PurchaseLine.SetRange("Document No.", InvoiceNo); - Continue := PurchaseLine.FindSet(); - end else begin - PurchInvLine.SetRange("Document No.", InvoiceNo); - Continue := PurchInvLine.FindSet(); - end; - - if Continue then begin - BufferAdvanceVATLines(PurchAdvLetterEntryCZZ, TempAdvancePostingBufferCZZ2, 0D); - - if Preview then - repeat - TempAdvancePostingBufferCZZ1.Init(); - TempAdvancePostingBufferCZZ1."VAT Bus. Posting Group" := PurchaseLine."VAT Bus. Posting Group"; - TempAdvancePostingBufferCZZ1."VAT Prod. Posting Group" := PurchaseLine."VAT Prod. Posting Group"; - if TempAdvancePostingBufferCZZ1.Find() then begin - TempAdvancePostingBufferCZZ1.Amount += PurchaseLine."Amount Including VAT"; - TempAdvancePostingBufferCZZ1."VAT Base Amount" += PurchaseLine.Amount; - TempAdvancePostingBufferCZZ1.Modify(); - end else begin - TempAdvancePostingBufferCZZ1."VAT Calculation Type" := PurchaseLine."VAT Calculation Type"; - TempAdvancePostingBufferCZZ1."VAT %" := PurchaseLine."VAT %"; - TempAdvancePostingBufferCZZ1.Amount := PurchaseLine."Amount Including VAT"; - TempAdvancePostingBufferCZZ1."VAT Base Amount" := PurchaseLine.Amount; - TempAdvancePostingBufferCZZ1.Insert(); - end; - until PurchaseLine.Next() = 0 - else - repeat - TempAdvancePostingBufferCZZ1.Init(); - TempAdvancePostingBufferCZZ1."VAT Bus. Posting Group" := PurchInvLine."VAT Bus. Posting Group"; - TempAdvancePostingBufferCZZ1."VAT Prod. Posting Group" := PurchInvLine."VAT Prod. Posting Group"; - if TempAdvancePostingBufferCZZ1.Find() then begin - TempAdvancePostingBufferCZZ1.Amount += PurchInvLine."Amount Including VAT"; - TempAdvancePostingBufferCZZ1."VAT Base Amount" += PurchInvLine.Amount; - TempAdvancePostingBufferCZZ1.Modify(); - end else begin - TempAdvancePostingBufferCZZ1."VAT Calculation Type" := PurchInvLine."VAT Calculation Type"; - TempAdvancePostingBufferCZZ1."VAT %" := PurchInvLine."VAT %"; - TempAdvancePostingBufferCZZ1.Amount := PurchInvLine."Amount Including VAT"; - TempAdvancePostingBufferCZZ1."VAT Base Amount" := PurchInvLine.Amount; - TempAdvancePostingBufferCZZ1.Insert(); - end; - until PurchInvLine.Next() = 0; - - GetCurrency(PurchAdvLetterEntryCZZ."Currency Code"); - - for i := 1 to 3 do begin - TempAdvancePostingBufferCZZ1.FindSet(); - repeat - case i of - 1: - begin - TempAdvancePostingBufferCZZ2.SetRange("VAT Bus. Posting Group", TempAdvancePostingBufferCZZ1."VAT Bus. Posting Group"); - TempAdvancePostingBufferCZZ2.SetRange("VAT Prod. Posting Group", TempAdvancePostingBufferCZZ1."VAT Prod. Posting Group"); - end; - 2: - begin - TempAdvancePostingBufferCZZ2.SetRange("VAT Calculation Type", TempAdvancePostingBufferCZZ1."VAT Calculation Type"); - TempAdvancePostingBufferCZZ2.SetRange("VAT %", TempAdvancePostingBufferCZZ1."VAT %"); - end; - end; - TempAdvancePostingBufferCZZ2.SetFilter(Amount, '<>%1', 0); - if TempAdvancePostingBufferCZZ2.FindSet() then - repeat - UseAmount := TempAdvancePostingBufferCZZ1.Amount; - UseBaseAmount := TempAdvancePostingBufferCZZ1."VAT Base Amount"; - if Abs(TempAdvancePostingBufferCZZ2.Amount) < Abs(UseAmount) then begin - UseAmount := TempAdvancePostingBufferCZZ2.Amount; - UseBaseAmount := TempAdvancePostingBufferCZZ2."VAT Base Amount"; - end; - if Abs(UsedAmount) < Abs(UseAmount) then begin - UseAmount := UsedAmount; - UseBaseAmount := Round(TempAdvancePostingBufferCZZ2."VAT Base Amount" * UseAmount / TempAdvancePostingBufferCZZ2.Amount, CurrencyGlob."Amount Rounding Precision", CurrencyGlob.VATRoundingDirection()); - end; - if TempAdvancePostingBufferCZZ1."VAT %" <> TempAdvancePostingBufferCZZ2."VAT %" then - UseBaseAmount := Round(TempAdvancePostingBufferCZZ2."VAT Base Amount" * UseAmount / TempAdvancePostingBufferCZZ2.Amount, CurrencyGlob."Amount Rounding Precision", CurrencyGlob.VATRoundingDirection()); - - TempAdvancePostingBufferCZZ2.Amount -= UseAmount; - TempAdvancePostingBufferCZZ2."VAT Base Amount" -= UseBaseAmount; - TempAdvancePostingBufferCZZ2.Modify(); - TempAdvancePostingBufferCZZ1.Amount -= UseAmount; - TempAdvancePostingBufferCZZ1."VAT Base Amount" -= UseBaseAmount; - TempAdvancePostingBufferCZZ1.Modify(); - UsedAmount -= UseAmount; - until (TempAdvancePostingBufferCZZ2.Next() = 0) or (UsedAmount = 0); - TempAdvancePostingBufferCZZ2.Reset(); - until TempAdvancePostingBufferCZZ1.Next() = 0; - end; - - if AdvancePostingBufferCZZ.FindSet() then - repeat - TempAdvancePostingBufferCZZ2.Get(AdvancePostingBufferCZZ."VAT Bus. Posting Group", AdvancePostingBufferCZZ."VAT Prod. Posting Group"); - case true of - TempAdvancePostingBufferCZZ2.Amount = 0: - ; - TempAdvancePostingBufferCZZ2.Amount <> AdvancePostingBufferCZZ.Amount: - begin - AdvancePostingBufferCZZ.Amount := AdvancePostingBufferCZZ.Amount - TempAdvancePostingBufferCZZ2.Amount; - AdvancePostingBufferCZZ."VAT Base Amount" := AdvancePostingBufferCZZ."VAT Base Amount" - TempAdvancePostingBufferCZZ2."VAT Base Amount"; - AdvancePostingBufferCZZ."VAT Amount" := AdvancePostingBufferCZZ.Amount - AdvancePostingBufferCZZ."VAT Base Amount"; - AdvancePostingBufferCZZ.Modify(); - end; - TempAdvancePostingBufferCZZ2.Amount = AdvancePostingBufferCZZ.Amount: - begin - AdvancePostingBufferCZZ.Amount := 0; - AdvancePostingBufferCZZ."VAT Base Amount" := 0; - AdvancePostingBufferCZZ."VAT Amount" := 0; - AdvancePostingBufferCZZ.Modify(); - end; - end; - until AdvancePostingBufferCZZ.Next() = 0; - end else begin - AdvancePostingBufferCZZ.FindSet(); - repeat - AdvancePostingBufferCZZ.Amount := Round(AdvancePostingBufferCZZ.Amount * UsedAmount / TotalAmount, CurrencyGlob."Amount Rounding Precision"); - AdvancePostingBufferCZZ."VAT Amount" := Round(AdvancePostingBufferCZZ."VAT Amount" * UsedAmount / TotalAmount, CurrencyGlob."Amount Rounding Precision", CurrencyGlob.VATRoundingDirection()); - AdvancePostingBufferCZZ."VAT Base Amount" := AdvancePostingBufferCZZ.Amount - AdvancePostingBufferCZZ."VAT Amount"; - AdvancePostingBufferCZZ.Modify(); - until AdvancePostingBufferCZZ.Next() = 0; - end; - end; - - if AdvancePostingBufferCZZ.FindSet() then - repeat - AdvancePostingBufferCZZ.UpdateLCYAmounts(PurchAdvLetterEntryCZZ."Currency Code", CurrencyFactor); - AdvancePostingBufferCZZ.Modify(); - until AdvancePostingBufferCZZ.Next() = 0; + PurchAdvLetterPostCZZ.PostAdvancePaymentUsage(PurchInvHeader, AdvanceLetterApplicationCZZ, GenJnlPostLine, AdvancePostingParametersCZZ); end; procedure PostAdvancePaymentUsageVAT(var PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ") var + AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; PurchAdvLetterEntryCZZ2: Record "Purch. Adv. Letter Entry CZZ"; VendorLedgerEntry: Record "Vendor Ledger Entry"; TempAdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ" temporary; + PurchasesPayablesSetup: Record "Purchases & Payables Setup"; PurchInvHeader: Record "Purch. Inv. Header"; GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; + VATDocumentCZZ: Page "VAT Document CZZ"; + DocumentNo: Code[20]; + PostingDate: Date; + DocumentDate: Date; + VATDate: Date; + OriginalDocumentVATDate: Date; + ExternalDocumentNo: Code[35]; CurrencyFactor: Decimal; + UsedAmount: Decimal; begin - if PurchAdvLetterEntryCZZ."Entry Type" <> PurchAdvLetterEntryCZZ."Entry Type"::Usage then - exit; - + PurchAdvLetterEntryCZZ.TestField("Entry Type", PurchAdvLetterEntryCZZ."Entry Type"::Usage); PurchAdvLetterEntryCZZ.TestField(Cancelled, false); PurchAdvLetterEntryCZZ2.SetRange("Purch. Adv. Letter No.", PurchAdvLetterEntryCZZ."Purch. Adv. Letter No."); @@ -1442,11 +604,6 @@ codeunit 31019 "PurchAdvLetterManagement CZZ" PurchAdvLetterEntryCZZ2.Get(PurchAdvLetterEntryCZZ."Related Entry"); PurchAdvLetterEntryCZZ2.TestField(PurchAdvLetterEntryCZZ2."Entry Type", PurchAdvLetterEntryCZZ2."Entry Type"::Payment); - BufferAdvanceVATLines(PurchAdvLetterEntryCZZ2, TempAdvancePostingBufferCZZ, 0D); - TempAdvancePostingBufferCZZ.SetFilter(Amount, '<>0'); - if TempAdvancePostingBufferCZZ.IsEmpty() then - Error(NothingToPostErr); - VendorLedgerEntry.Get(PurchAdvLetterEntryCZZ."Vendor Ledger Entry No."); if PurchInvHeader.Get(VendorLedgerEntry."Document No.") then @@ -1454,158 +611,73 @@ codeunit 31019 "PurchAdvLetterManagement CZZ" else CurrencyFactor := VendorLedgerEntry."Original Currency Factor"; - ReverseAdvancePaymentVAT(PurchAdvLetterEntryCZZ2, VendorLedgerEntry."Source Code", VendorLedgerEntry.Description, - CurrencyFactor, Enum::"Gen. Journal Document Type"::Invoice, PurchAdvLetterEntryCZZ."Document No.", - VendorLedgerEntry."External Document No.", VendorLedgerEntry."Posting Date", VendorLedgerEntry."VAT Date CZL", - VendorLedgerEntry."VAT Date CZL", -PurchAdvLetterEntryCZZ.Amount, PurchAdvLetterEntryCZZ."Entry No.", - VendorLedgerEntry."Document No.", "Advance Letter Entry Type CZZ"::"VAT Usage", false, GenJnlPostLine, false); - end; + UsedAmount := -PurchAdvLetterEntryCZZ.Amount; + PurchAdvLetterPostCZZ.BufferAdvanceVATLines(PurchAdvLetterEntryCZZ2, TempAdvancePostingBufferCZZ, 0D); + PurchAdvLetterPostCZZ.SuggestUsageVAT(PurchAdvLetterEntryCZZ2, TempAdvancePostingBufferCZZ, VendorLedgerEntry."Document No.", + UsedAmount, CurrencyFactor, false); - 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 - GenJournalLine: Record "Gen. Journal Line"; - begin - if (ExchRateAmount = 0) and (ExchRateVATAmount = 0) then + VATDocumentCZZ.InitDocument('', VendorLedgerEntry."Document No.", VendorLedgerEntry."Posting Date", + VendorLedgerEntry."Document Date", VendorLedgerEntry."VAT Date CZL", PurchInvHeader."Original Doc. VAT Date CZL", + VendorLedgerEntry."Currency Code", CurrencyFactor, VendorLedgerEntry."External Document No.", + TempAdvancePostingBufferCZZ); + if VATDocumentCZZ.RunModal() <> Action::OK then exit; - if ExchRateVATAmount <> 0 then begin - GetCurrency(PurchAdvLetterHeaderCZZ."Currency Code"); + VATDocumentCZZ.GetDocument(DocumentNo, PostingDate, DocumentDate, VATDate, OriginalDocumentVATDate, ExternalDocumentNo, TempAdvancePostingBufferCZZ); - InitGenJnlLineFromAdvance(PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, DocumentNo, '', SourceCode, PostDescription, GenJournalLine); - GenJournalLine.Correction := Correction; - GenJournalLine.Validate("Posting Date", PostingDate); -#if not CLEAN22 -#pragma warning disable AL0432 - if not ReplaceVATDateMgtCZL.IsEnabled() then - GenJournalLine.Validate("VAT Date CZL", VATDate) - else -#pragma warning restore AL0432 -#endif - GenJournalLine.Validate("VAT Reporting Date", VATDate); - GenJournalLine."Account No." := VATPostingSetup."Purch. Adv. Letter Account CZZ"; - GenJournalLine.Validate(Amount, ExchRateAmount - ExchRateVATAmount); - if not Preview then - GenJnlPostLine.RunWithCheck(GenJournalLine); - - InitGenJnlLineFromAdvance(PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, DocumentNo, '', SourceCode, PostDescription, GenJournalLine); - GenJournalLine.Correction := true; - GenJournalLine.Validate("Posting Date", PostingDate); -#if not CLEAN22 -#pragma warning disable AL0432 - if not ReplaceVATDateMgtCZL.IsEnabled() then - GenJournalLine.Validate("VAT Date CZL", VATDate) - else -#pragma warning restore AL0432 -#endif - GenJournalLine.Validate("VAT Reporting Date", VATDate); - if ExchRateVATAmount < 0 then begin - CurrencyGlob.TestField("Realized Losses Acc."); - GenJournalLine."Account No." := CurrencyGlob."Realized Losses Acc."; - end else begin - CurrencyGlob.TestField("Realized Gains Acc."); - GenJournalLine."Account No." := CurrencyGlob."Realized Gains Acc."; - end; - GenJournalLine.Validate(Amount, ExchRateVATAmount); - if not Preview then - GenJnlPostLine.RunWithCheck(GenJournalLine); + TempAdvancePostingBufferCZZ.SetFilter(Amount, '<>0'); + if TempAdvancePostingBufferCZZ.IsEmpty() then + Error(NothingToPostErr); - InitGenJnlLineFromAdvance(PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, DocumentNo, '', SourceCode, PostDescription, GenJournalLine); - GenJournalLine.Correction := Correction; - GenJournalLine.Validate("Posting Date", PostingDate); -#if not CLEAN22 -#pragma warning disable AL0432 - if not ReplaceVATDateMgtCZL.IsEnabled() then - GenJournalLine.Validate("VAT Date CZL", VATDate) - else -#pragma warning restore AL0432 -#endif - GenJournalLine.Validate("VAT Reporting Date", VATDate); - GenJournalLine."Account No." := VATPostingSetup."Purch. Adv. Letter Account CZZ"; - GenJournalLine.Validate(Amount, -ExchRateAmount); - if not Preview then - GenJnlPostLine.RunWithCheck(GenJournalLine); + if UsedAmount <> 0 then begin + TempAdvancePostingBufferCZZ.CalcSums(Amount); + if TempAdvancePostingBufferCZZ.Amount > UsedAmount then + Error(ExceededUsageAmountErr); end; - AdvEntryInit(Preview); - if Correction then - AdvEntryInitCancel(); - AdvEntryInitRelatedEntry(UsageEntryNo); - AdvEntryInitVAT(VATPostingSetup."VAT Bus. Posting Group", VATPostingSetup."VAT Prod. Posting Group", VATDate, VATDate, - 0, VATPostingSetup."VAT %", VATPostingSetup."VAT Identifier", VATPostingSetup."VAT Calculation Type", - 0, ExchRateVATAmount, 0, ExchRateAmount - ExchRateVATAmount); - AdvEntryInsert("Advance Letter Entry Type CZZ"::"VAT Rate", PurchAdvLetterEntryCZZ."Purch. Adv. Letter No.", PostingDate, - 0, ExchRateAmount, '', 0, DocumentNo, GenJournalLine."External Document No.", - PurchAdvLetterEntryCZZ."Global Dimension 1 Code", PurchAdvLetterEntryCZZ."Global Dimension 2 Code", PurchAdvLetterEntryCZZ."Dimension Set ID", Preview); - end; + Clear(AdvancePostingParametersCZZ); + AdvancePostingParametersCZZ.CopyFromVendorLedgerEntry(VendorLedgerEntry); + AdvancePostingParametersCZZ."Document Type" := "Gen. Journal Document Type"::Invoice; + AdvancePostingParametersCZZ."Document No." := DocumentNo; + AdvancePostingParametersCZZ."External Document No." := ExternalDocumentNo; + AdvancePostingParametersCZZ."Posting Date" := PostingDate; + AdvancePostingParametersCZZ."Document Date" := DocumentDate; + AdvancePostingParametersCZZ."VAT Date" := VATDate; + AdvancePostingParametersCZZ."Original Document VAT Date" := VATDate; + if OriginalDocumentVATDate <> 0D then + AdvancePostingParametersCZZ."Original Document VAT Date" := OriginalDocumentVATDate; + AdvancePostingParametersCZZ."Currency Code" := PurchAdvLetterEntryCZZ2."Currency Code"; + AdvancePostingParametersCZZ."Currency Factor" := CurrencyFactor; + + AdvancePostingParametersCZZ.CheckDocumentNo(); + AdvancePostingParametersCZZ.CheckPurchaseDates(); - local procedure BufferAdvanceVATLines(var PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; BalanceAtDate: Date) - begin - BufferAdvanceVATLines(PurchAdvLetterEntryCZZ, AdvancePostingBufferCZZ, BalanceAtDate, true); + PurchasesPayablesSetup.Get(); + if PurchasesPayablesSetup."Ext. Doc. No. Mandatory" then + AdvancePostingParametersCZZ.CheckExternalDocumentNo(); + + PurchAdvLetterPostCZZ.PostAdvancePaymentUsageVAT( + PurchAdvLetterEntryCZZ, TempAdvancePostingBufferCZZ, GenJnlPostLine, AdvancePostingParametersCZZ); end; - local procedure BufferAdvanceVATLines(var PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; BalanceAtDate: Date; ResetBuffer: Boolean) + 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 - PurchAdvLetterEntryCZZ2: Record "Purch. Adv. Letter Entry CZZ"; - TempAdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ" temporary; + AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; begin - if ResetBuffer then begin - AdvancePostingBufferCZZ.Reset(); - AdvancePostingBufferCZZ.DeleteAll(); - end; - - PurchAdvLetterEntryCZZ2.SetRange("Purch. Adv. Letter No.", PurchAdvLetterEntryCZZ."Purch. Adv. Letter No."); - PurchAdvLetterEntryCZZ2.SetRange(Cancelled, false); - PurchAdvLetterEntryCZZ2.SetRange("Related Entry", PurchAdvLetterEntryCZZ."Entry No."); - PurchAdvLetterEntryCZZ2.SetFilter("Entry Type", '<>%1', PurchAdvLetterEntryCZZ2."Entry Type"::"VAT Adjustment"); - if BalanceAtDate <> 0D then - PurchAdvLetterEntryCZZ2.SetFilter("Posting Date", '..%1', BalanceAtDate); - if PurchAdvLetterEntryCZZ2.FindSet() then - repeat - if PurchAdvLetterEntryCZZ2."Entry Type" in - [PurchAdvLetterEntryCZZ2."Entry Type"::Payment, - PurchAdvLetterEntryCZZ2."Entry Type"::Usage, - PurchAdvLetterEntryCZZ2."Entry Type"::Close] - then - BufferAdvanceVATLines(PurchAdvLetterEntryCZZ2, AdvancePostingBufferCZZ, BalanceAtDate, false) - else begin - TempAdvancePostingBufferCZZ.PrepareForPurchAdvLetterEntry(PurchAdvLetterentryCZZ2); - AdvancePostingBufferCZZ.Update(TempAdvancePostingBufferCZZ); - end; - until PurchAdvLetterEntryCZZ2.Next() = 0; - end; + 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; - local procedure InitGenJnlLineFromVendLedgEntry(var VendorLedgerEntry: Record "Vendor Ledger Entry"; var GenJournalLine: Record "Gen. Journal Line"; GenJournalDocumentType: Enum "Gen. Journal Document Type") - begin - GenJournalLine.InitNewLine( - VendorLedgerEntry."Posting Date", VendorLedgerEntry."Document Date", VendorLedgerEntry."VAT Date CZL", VendorLedgerEntry.Description, - VendorLedgerEntry."Global Dimension 1 Code", VendorLedgerEntry."Global Dimension 2 Code", - VendorLedgerEntry."Dimension Set ID", VendorLedgerEntry."Reason Code"); - GenJournalLine."System-Created Entry" := true; - GenJournalLine.CopyDocumentFields(GenJournalDocumentType, VendorLedgerEntry."Document No.", VendorLedgerEntry."External Document No.", VendorLedgerEntry."Source Code", ''); - GenJournalLine."Account Type" := GenJournalLine."Account Type"::Vendor; - GenJournalLine."Account No." := VendorLedgerEntry."Vendor No."; - GenJournalLine."Source Currency Code" := VendorLedgerEntry."Currency Code"; - GenJournalLine."Currency Factor" := VendorLedgerEntry."Original Currency Factor"; - GenJournalLine."Sell-to/Buy-from No." := VendorLedgerEntry."Buy-from Vendor No."; - GenJournalLine."Bill-to/Pay-to No." := VendorLedgerEntry."Vendor No."; - GenJournalLine."IC Partner Code" := VendorLedgerEntry."IC Partner Code"; - GenJournalLine."Salespers./Purch. Code" := VendorLedgerEntry."Purchaser Code"; - GenJournalLine."On Hold" := VendorLedgerEntry."On Hold"; - GenJournalLine."Posting Group" := VendorLedgerEntry."Vendor Posting Group"; -#if not CLEAN22 -#pragma warning disable AL0432 - if not ReplaceVATDateMgtCZL.IsEnabled() then - GenJournalLine.Validate("VAT Date CZL", VendorLedgerEntry."VAT Date CZL") - else -#pragma warning restore AL0432 -#endif - GenJournalLine.Validate("VAT Reporting Date", VendorLedgerEntry."VAT Date CZL"); - GenJournalLine.Validate("Original Doc. VAT Date CZL", VendorLedgerEntry."VAT Date CZL"); - GenJournalLine."System-Created Entry" := true; - OnAfterInitGenJnlLineFromVendLedgEntry(VendorLedgerEntry, GenJournalLine); + 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") @@ -1615,9 +687,9 @@ codeunit 31019 "PurchAdvLetterManagement CZZ" 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."Source Code" := SourceCode; GenJournalLine."VAT Registration No." := PurchAdvLetterHeaderCZZ."VAT Registration No."; GenJournalLine."Registration No. CZL" := PurchAdvLetterHeaderCZZ."Registration No."; GenJournalLine."Tax Registration No. CZL" := PurchAdvLetterHeaderCZZ."Tax Registration No."; @@ -1704,7 +776,7 @@ codeunit 31019 "PurchAdvLetterManagement CZZ" exit; if PurchAdvLetterHeaderCZZ.Status = PurchAdvLetterHeaderCZZ.Status::New then begin - UpdateStatus(PurchAdvLetterHeaderCZZ, PurchAdvLetterHeaderCZZ.Status::Closed); + PurchAdvLetterHeaderCZZ.UpdateStatus(PurchAdvLetterHeaderCZZ.Status::Closed); exit; end; @@ -1721,166 +793,52 @@ codeunit 31019 "PurchAdvLetterManagement CZZ" procedure CloseAdvanceLetter(var PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; PostingDate: Date; VATDate: Date; OriginalDocumentVATDate: Date; CurrencyFactor: Decimal; ExternalDocumentNo: Code[35]) var - AdvanceLetterApplicationCZZ: Record "Advance Letter Application CZZ"; + AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; CurrencyExchangeRate: Record "Currency Exchange Rate"; - PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; - GenJournalLine: Record "Gen. Journal Line"; - VendorLedgerEntry1: Record "Vendor Ledger Entry"; - VendorLedgerEntry2: Record "Vendor Ledger Entry"; - AdvanceLetterTemplateCZZ: Record "Advance Letter Template CZZ"; PurchasesPayablesSetup: Record "Purchases & Payables Setup"; GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; - NoSeriesManagement: Codeunit NoSeriesManagement; - ApplId: Code[50]; - VATDocumentNo: Code[20]; - RemAmount: Decimal; - RemAmountLCY: Decimal; - UsageEntryNo: Integer; begin if PurchAdvLetterHeaderCZZ.Status = PurchAdvLetterHeaderCZZ.Status::Closed then exit; - if PurchAdvLetterHeaderCZZ.Status = PurchAdvLetterHeaderCZZ.Status::New then begin - UpdateStatus(PurchAdvLetterHeaderCZZ, PurchAdvLetterHeaderCZZ.Status::Closed); - exit; - end; - - if PostingDate = 0D then - PostingDate := WorkDate(); - if VATDate = 0D then - VATDate := WorkDate(); - if OriginalDocumentVATDate = 0D then - OriginalDocumentVATDate := WorkDate(); - if CurrencyFactor = 0 then - CurrencyFactor := CurrencyExchangeRate.ExchangeRate(PostingDate, PurchAdvLetterHeaderCZZ."Currency Code"); - PurchasesPayablesSetup.Get(); - if PurchasesPayablesSetup."Ext. Doc. No. Mandatory" and (ExternalDocumentNo = '') then - Error(ExternalDocumentNoEmptyErr); - - VATDocumentNo := ''; - - PurchAdvLetterEntryCZZ.SetRange("Purch. Adv. Letter No.", PurchAdvLetterHeaderCZZ."No."); - PurchAdvLetterEntryCZZ.SetRange("Entry Type", PurchAdvLetterEntryCZZ."Entry Type"::Payment); - PurchAdvLetterEntryCZZ.SetRange(Cancelled, false); - if PurchAdvLetterEntryCZZ.FindSet() then - repeat - RemAmount := GetRemAmtPurchAdvPayment(PurchAdvLetterEntryCZZ, 0D); - RemAmountLCY := GetRemAmtLCYPurchAdvPayment(PurchAdvLetterEntryCZZ, 0D); - - if RemAmount <> 0 then begin - if VATDocumentNo = '' then begin - AdvanceLetterTemplateCZZ.Get(PurchAdvLetterHeaderCZZ."Advance Letter Code"); - AdvanceLetterTemplateCZZ.TestField("Advance Letter Cr. Memo Nos."); - VATDocumentNo := NoSeriesManagement.GetNextNo(AdvanceLetterTemplateCZZ."Advance Letter Cr. Memo Nos.", PostingDate, true); - end; - - PurchAdvLetterHeaderCZZ.Get(PurchAdvLetterEntryCZZ."Purch. Adv. Letter No."); - VendorLedgerEntry1.Get(PurchAdvLetterEntryCZZ."Vendor Ledger Entry No."); - if RemAmount <> 0 then begin - InitGenJnlLineFromVendLedgEntry(VendorLedgerEntry1, GenJournalLine, GenJournalLine."Document Type"::" "); - GenJournalLine."Adv. Letter Template Code CZZ" := PurchAdvLetterHeaderCZZ."Advance Letter Code"; - GenJournalLine.Correction := true; - GenJournalLine."External Document No." := ExternalDocumentNo; - GenJournalLine."Document No." := VATDocumentNo; - GenJournalLine."Posting Date" := PostingDate; - GenJournalLine."Document Date" := PostingDate; -#if not CLEAN22 -#pragma warning disable AL0432 - if not ReplaceVATDateMgtCZL.IsEnabled() then - GenJournalLine.Validate("VAT Date CZL", VATDate) - else -#pragma warning restore AL0432 -#endif - GenJournalLine.Validate("VAT Reporting Date", VATDate); - GenJournalLine.Validate("Original Doc. VAT Date CZL", OriginalDocumentVATDate); - GenJournalLine."Adv. Letter No. (Entry) CZZ" := PurchAdvLetterEntryCZZ."Purch. Adv. Letter No."; - GenJournalLine."Use Advance G/L Account CZZ" := true; - GenJournalLine.SetCurrencyFactor(PurchAdvLetterEntryCZZ."Currency Code", CurrencyFactor); - GenJournalLine.Validate(Amount, -RemAmount); - - ApplId := CopyStr(VendorLedgerEntry1."Document No." + Format(VendorLedgerEntry1."Entry No.", 0, ''), 1, MaxStrLen(ApplId)); - VendorLedgerEntry1.Prepayment := false; - VendorLedgerEntry1."Advance Letter No. CZZ" := PurchAdvLetterEntryCZZ."Purch. Adv. Letter No."; - VendorLedgerEntry1.Modify(); - VendorLedgerEntry1.CalcFields("Remaining Amount"); - VendorLedgerEntry1."Amount to Apply" := VendorLedgerEntry1."Remaining Amount"; - VendorLedgerEntry1."Applies-to ID" := ApplId; - Codeunit.Run(Codeunit::"Vend. Entry-Edit", VendorLedgerEntry1); - GenJournalLine."Applies-to ID" := ApplId; - - OnBeforePostClosePayment(GenJournalLine, PurchAdvLetterHeaderCZZ); - GenJnlPostLine.RunWithCheck(GenJournalLine); - OnAfterPostClosePayment(GenJournalLine, PurchAdvLetterHeaderCZZ); - - VendorLedgerEntry2.FindLast(); - AdvEntryInit(false); - AdvEntryInitVendLedgEntryNo(VendorLedgerEntry2."Entry No."); - AdvEntryInitRelatedEntry(PurchAdvLetterEntryCZZ."Entry No."); - AdvEntryInsert("Advance Letter Entry Type CZZ"::Close, GenJournalLine."Adv. Letter No. (Entry) CZZ", GenJournalLine."Posting Date", - GenJournalLine.Amount, -RemAmountLCY, - 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); - - UsageEntryNo := PurchAdvLetterEntryCZZGlob."Entry No."; - end else begin - VendorLedgerEntry2.Init(); - UsageEntryNo := 0; - end; - - ReverseAdvancePaymentVAT(PurchAdvLetterEntryCZZ, VendorLedgerEntry1."Source Code", - PurchAdvLetterHeaderCZZ."Posting Description", CurrencyFactor, Enum::"Gen. Journal Document Type"::"Credit Memo", - VATDocumentNo, ExternalDocumentNo, PostingDate, VATDate, OriginalDocumentVATDate, 0, UsageEntryNo, '', - "Advance Letter Entry Type CZZ"::"VAT Close", true, GenJnlPostLine, false); - - if RemAmount <> 0 then begin - InitGenJnlLineFromVendLedgEntry(VendorLedgerEntry1, GenJournalLine, GenJournalLine."Document Type"::Payment); - GenJournalLine.Correction := true; - GenJournalLine."External Document No." := ExternalDocumentNo; - GenJournalLine."Document No." := VATDocumentNo; - GenJournalLine."Posting Date" := PostingDate; - GenJournalLine."Document Date" := PostingDate; -#if not CLEAN22 -#pragma warning disable AL0432 - if not ReplaceVATDateMgtCZL.IsEnabled() then - GenJournalLine.Validate("VAT Date CZL", VATDate) - else -#pragma warning restore AL0432 -#endif - GenJournalLine.Validate("VAT Reporting Date", VATDate); - GenJournalLine.Validate("Original Doc. VAT Date CZL", OriginalDocumentVATDate); - GenJournalLine.SetCurrencyFactor(PurchAdvLetterEntryCZZ."Currency Code", CurrencyFactor); - GenJournalLine.Validate(Amount, RemAmount); - GenJournalLine."Variable Symbol CZL" := PurchAdvLetterHeaderCZZ."Variable Symbol"; - OnBeforePostClosePaymentRepos(GenJournalLine, PurchAdvLetterHeaderCZZ); - GenJnlPostLine.RunWithCheck(GenJournalLine); - OnAfterPostClosePaymentRepos(GenJournalLine, PurchAdvLetterHeaderCZZ); - end; - end; - until PurchAdvLetterEntryCZZ.Next() = 0; + if PurchAdvLetterHeaderCZZ.Status = PurchAdvLetterHeaderCZZ.Status::New then begin + PurchAdvLetterHeaderCZZ.UpdateStatus(PurchAdvLetterHeaderCZZ.Status::Closed); + exit; + end; + + if PostingDate = 0D then + PostingDate := WorkDate(); + if VATDate = 0D then + VATDate := WorkDate(); + if OriginalDocumentVATDate = 0D then + OriginalDocumentVATDate := WorkDate(); + if CurrencyFactor = 0 then + CurrencyFactor := CurrencyExchangeRate.ExchangeRate(PostingDate, PurchAdvLetterHeaderCZZ."Currency Code"); + PurchasesPayablesSetup.Get(); + if PurchasesPayablesSetup."Ext. Doc. No. Mandatory" and (ExternalDocumentNo = '') then + Error(ExternalDocumentNoEmptyErr); - CancelInitEntry(PurchAdvLetterHeaderCZZ, PostingDate, false); - PurchAdvLetterHeaderCZZ.Find(); - UpdateStatus(PurchAdvLetterHeaderCZZ, PurchAdvLetterHeaderCZZ.Status::Closed); + Clear(AdvancePostingParametersCZZ); + AdvancePostingParametersCZZ."External Document No." := ExternalDocumentNo; + AdvancePostingParametersCZZ."Posting Date" := PostingDate; + AdvancePostingParametersCZZ."Document Date" := PostingDate; + AdvancePostingParametersCZZ."VAT Date" := VATDate; + AdvancePostingParametersCZZ."Original Document VAT Date" := OriginalDocumentVATDate; + AdvancePostingParametersCZZ."Currency Code" := PurchAdvLetterHeaderCZZ."Currency Code"; + AdvancePostingParametersCZZ."Currency Factor" := CurrencyFactor; - AdvanceLetterApplicationCZZ.SetRange("Advance Letter Type", AdvanceLetterApplicationCZZ."Advance Letter Type"::Purchase); - AdvanceLetterApplicationCZZ.SetRange("Advance Letter No.", PurchAdvLetterHeaderCZZ."No."); - AdvanceLetterApplicationCZZ.DeleteAll(true); + PurchAdvLetterPostCZZ.PostAdvanceLetterClosing(PurchAdvLetterHeaderCZZ, GenJnlPostLine, AdvancePostingParametersCZZ); end; procedure PostAdvanceCreditMemoVAT(var PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ") var + AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; PurchAdvLetterEntryCZZ2: Record "Purch. Adv. Letter Entry CZZ"; - PurchAdvLetterEntryCZZ3: Record "Purch. Adv. Letter Entry CZZ"; TempAdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ" temporary; TempAdvancePostingBufferCZZ1: Record "Advance Posting Buffer CZZ" temporary; - TempAdvancePostingBufferCZZ2: Record "Advance Posting Buffer CZZ" temporary; - VATPostingSetup: Record "VAT Posting Setup"; PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; - GenJournalLine: Record "Gen. Journal Line"; AdvanceLetterTemplateCZZ: Record "Advance Letter Template CZZ"; VATEntry: Record "VAT Entry"; - DocumentTypeHandlerCZZ: Codeunit "Document Type Handler CZZ"; - VATPostingSetupHandlerCZZ: Codeunit "VAT Posting Setup Handler CZZ"; GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; VATDocumentCZZ: Page "VAT Document CZZ"; DocumentNo: Code[20]; @@ -1889,8 +847,6 @@ codeunit 31019 "PurchAdvLetterManagement CZZ" OriginalDocumentVATDate: Date; DocumentDate: Date; PostingDate: Date; - ExchRateAmount: Decimal; - ExchRateVATAmount: Decimal; begin PurchAdvLetterEntryCZZ.TestField("Entry Type", PurchAdvLetterEntryCZZ."Entry Type"::"VAT Payment"); PurchAdvLetterEntryCZZ.TestField(Cancelled, false); @@ -1922,122 +878,21 @@ codeunit 31019 "PurchAdvLetterManagement CZZ" OnPostAdvanceCreditMemoVATOnAfterGetDocument(PurchAdvLetterEntryCZZ, PostingDate, VATDate, OriginalDocumentVATDate); - TempAdvancePostingBufferCZZ1.SetFilter(Amount, '<>0'); - if not TempAdvancePostingBufferCZZ1.FindSet() then - Error(NothingToPostErr); - - GetCurrency(PurchAdvLetterEntryCZZ."Currency Code"); - - if PurchAdvLetterEntryCZZ."Currency Code" <> '' then begin - PurchAdvLetterEntryCZZ3.Get(PurchAdvLetterEntryCZZ."Related Entry"); - BufferAdvanceVATLines(PurchAdvLetterEntryCZZ3, TempAdvancePostingBufferCZZ2, 0D); - end; - - PurchAdvLetterEntryCZZ2.FindSet(true); - repeat - TempAdvancePostingBufferCZZ1.Reset(); - TempAdvancePostingBufferCZZ1.SetRange("VAT Bus. Posting Group", PurchAdvLetterEntryCZZ2."VAT Bus. Posting Group"); - TempAdvancePostingBufferCZZ1.SetRange("VAT Prod. Posting Group", PurchAdvLetterEntryCZZ2."VAT Prod. Posting Group"); - TempAdvancePostingBufferCZZ1.FindFirst(); - PurchAdvLetterEntryCZZ2.TestField(Amount, TempAdvancePostingBufferCZZ1.Amount); - - VATPostingSetup.Get(TempAdvancePostingBufferCZZ1."VAT Bus. Posting Group", TempAdvancePostingBufferCZZ1."VAT Prod. Posting Group"); - VATPostingSetup.TestField("Purch. Adv. Letter Account CZZ"); - VATPostingSetup.TestField("Purch. Adv.Letter VAT Acc. CZZ"); - - InitGenJnlLineFromAdvance(PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, DocumentNo, ExternalDocumentNo, VATEntry."Source Code", PurchAdvLetterHeaderCZZ."Posting Description", GenJournalLine); - GenJournalLine."Document Type" := GenJournalLine."Document Type"::"Credit Memo"; - GenJournalLine.Validate("Posting Date", PostingDate); -#if not CLEAN22 -#pragma warning disable AL0432 - if not ReplaceVATDateMgtCZL.IsEnabled() then - GenJournalLine.Validate("VAT Date CZL", VATDate) - else -#pragma warning restore AL0432 -#endif - GenJournalLine.Validate("VAT Reporting Date", VATDate); - GenJournalLine.Validate("Original Doc. VAT Date CZL", OriginalDocumentVATDate); - GenJournalLine."Account No." := VATPostingSetup."Purch. Adv. Letter Account CZZ"; - GenJournalLine.SetCurrencyFactor(PurchAdvLetterEntryCZZ."Currency Code", PurchAdvLetterEntryCZZ."Currency Factor"); - GenJournalLine."Gen. Posting Type" := GenJournalLine."Gen. Posting Type"::Purchase; - GenJournalLine."VAT Calculation Type" := TempAdvancePostingBufferCZZ1."VAT Calculation Type"; - GenJournalLine."VAT Bus. Posting Group" := TempAdvancePostingBufferCZZ1."VAT Bus. Posting Group"; - GenJournalLine.validate("VAT Prod. Posting Group", TempAdvancePostingBufferCZZ1."VAT Prod. Posting Group"); - GenJournalLine.Validate(Amount, -TempAdvancePostingBufferCZZ1.Amount); - GenJournalLine."VAT Amount" := -TempAdvancePostingBufferCZZ1."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)" := -TempAdvancePostingBufferCZZ1."Amount (ACY)"; - GenJournalLine."VAT Amount (LCY)" := -TempAdvancePostingBufferCZZ1."VAT Amount (ACY)"; - GenJournalLine."VAT Base Amount (LCY)" := -TempAdvancePostingBufferCZZ1."VAT Base Amount (ACY)"; - GenJournalLine."Currency Factor" := GenJournalLine.Amount / GenJournalLine."Amount (LCY)"; - end else begin - GenJournalLine."Amount (LCY)" := GenJournalLine.Amount; - GenJournalLine."VAT Amount (LCY)" := GenJournalLine."VAT Amount"; - GenJournalLine."VAT Base Amount (LCY)" := GenJournalLine."VAT Base Amount"; - end; - BindSubscription(VATPostingSetupHandlerCZZ); - BindSubscription(DocumentTypeHandlerCZZ); - GenJnlPostLine.RunWithCheck(GenJournalLine); - UnbindSubscription(VATPostingSetupHandlerCZZ); - UnbindSubscription(DocumentTypeHandlerCZZ); - -#if not CLEAN22 -#pragma warning disable AL0432 - if not ReplaceVATDateMgtCZL.IsEnabled() then - GenJournalLine."VAT Reporting Date" := GenJournalLine."VAT Date CZL"; -#pragma warning restore AL0432 -#endif - AdvEntryInit(false); - AdvEntryInitRelatedEntry(PurchAdvLetterEntryCZZ."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 Payment", PurchAdvLetterEntryCZZ."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); - - if GenJournalLine."Currency Code" <> '' then begin - ExchRateAmount := PurchAdvLetterEntryCZZ2."Amount (LCY)" + GenJournalLine."Amount (LCY)"; - ExchRateVATAmount := PurchAdvLetterEntryCZZ2."VAT Amount (LCY)" + GenJournalLine."VAT Amount (LCY)"; - if (ExchRateAmount <> 0) or (ExchRateVATAmount <> 0) then - PostExchangeRate(ExchRateAmount, ExchRateVATAmount, PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, VATPostingSetup, - DocumentNo, PostingDate, VATDate, '', PurchAdvLetterHeaderCZZ."Posting Description", PurchAdvLetterEntryCZZ2."Related Entry", true, GenJnlPostLine, false); - - TempAdvancePostingBufferCZZ2.Reset(); - TempAdvancePostingBufferCZZ2.SetRange("VAT Bus. Posting Group", PurchAdvLetterEntryCZZ2."VAT Bus. Posting Group"); - TempAdvancePostingBufferCZZ2.SetRange("VAT Prod. Posting Group", PurchAdvLetterEntryCZZ2."VAT Prod. Posting Group"); - TempAdvancePostingBufferCZZ2.FindFirst(); - - ReverseUnrealizedExchangeRate(PurchAdvLetterEntryCZZ, PurchAdvLetterHeaderCZZ, VATPostingSetup, TempAdvancePostingBufferCZZ1.Amount / TempAdvancePostingBufferCZZ2.Amount, - PurchAdvLetterEntryCZZ."Related Entry", DocumentNo, PostingDate, VATDate, PurchAdvLetterHeaderCZZ."Posting Description", GenJnlPostLine, false); - end; - - InitGenJnlLineFromAdvance(PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, DocumentNo, ExternalDocumentNo, VATEntry."Source Code", PurchAdvLetterHeaderCZZ."Posting Description", GenJournalLine); - GenJournalLine.Validate("Posting Date", PostingDate); -#if not CLEAN22 -#pragma warning disable AL0432 - if not ReplaceVATDateMgtCZL.IsEnabled() then - GenJournalLine.Validate("VAT Date CZL", VATDate) - else -#pragma warning restore AL0432 -#endif - GenJournalLine.Validate("VAT Reporting Date", VATDate); - GenJournalLine.Validate("Original Doc. VAT Date CZL", OriginalDocumentVATDate); - GenJournalLine."Account No." := VATPostingSetup."Purch. Adv. Letter Account CZZ"; - GenJournalLine.SetCurrencyFactor(PurchAdvLetterEntryCZZ."Currency Code", PurchAdvLetterEntryCZZ."Currency Factor"); - GenJournalLine.Validate(Amount, TempAdvancePostingBufferCZZ1.Amount); - GenJournalLine."Amount (LCY)" := TempAdvancePostingBufferCZZ1."Amount (ACY)"; - GenJournalLine."Currency Factor" := GenJournalLine.Amount / GenJournalLine."Amount (LCY)"; - GenJnlPostLine.RunWithCheck(GenJournalLine); - until PurchAdvLetterEntryCZZ2.Next() = 0; + Clear(AdvancePostingParametersCZZ); + 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."Posting Description" := PurchAdvLetterHeaderCZZ."Posting Description"; + AdvancePostingParametersCZZ."Posting Date" := PostingDate; + AdvancePostingParametersCZZ."Document Date" := PostingDate; + AdvancePostingParametersCZZ."VAT Date" := VATDate; + AdvancePostingParametersCZZ."Original Document VAT Date" := OriginalDocumentVATDate; + AdvancePostingParametersCZZ."Currency Code" := PurchAdvLetterEntryCZZ."Currency Code"; + AdvancePostingParametersCZZ."Currency Factor" := PurchAdvLetterEntryCZZ."Currency Factor"; - PurchAdvLetterEntryCZZ2.ModifyAll(Cancelled, true); + PurchAdvLetterPostCZZ.PostAdvanceCreditMemoVAT( + PurchAdvLetterEntryCZZ, TempAdvancePostingBufferCZZ1, GenJnlPostLine, AdvancePostingParametersCZZ); end; procedure PostCancelUsageVAT(var PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ") @@ -2048,7 +903,7 @@ codeunit 31019 "PurchAdvLetterManagement CZZ" VATPostingSetup: Record "VAT Posting Setup"; GenJournalLine: Record "Gen. Journal Line"; GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; - NoSeriesManagement: Codeunit NoSeriesManagement; + NoSeries: Codeunit "No. Series"; VATPostingSetupHandlerCZZ: Codeunit "VAT Posting Setup Handler CZZ"; DocumentNo: Code[20]; begin @@ -2058,7 +913,7 @@ codeunit 31019 "PurchAdvLetterManagement CZZ" PurchAdvLetterHeaderCZZ.Get(PurchAdvLetterEntryCZZ."Purch. Adv. Letter No."); AdvanceLetterTemplateCZZ.Get(PurchAdvLetterHeaderCZZ."Advance Letter Code"); AdvanceLetterTemplateCZZ.TestField("Advance Letter Cr. Memo Nos."); - DocumentNo := NoSeriesManagement.GetNextNo(AdvanceLetterTemplateCZZ."Advance Letter Cr. Memo Nos.", 0D, true); + DocumentNo := NoSeries.GetNextNo(AdvanceLetterTemplateCZZ."Advance Letter Cr. Memo Nos."); GetCurrency(PurchAdvLetterEntryCZZ."Currency Code"); @@ -2163,92 +1018,22 @@ codeunit 31019 "PurchAdvLetterManagement CZZ" until PurchAdvLetterEntryCZZ2.Next(-1) = 0; PurchAdvLetterEntryCZZ2.ModifyAll(Cancelled, true); - UpdateStatus(PurchAdvLetterHeaderCZZ, PurchAdvLetterHeaderCZZ.Status::"To Use"); + PurchAdvLetterHeaderCZZ.UpdateStatus(PurchAdvLetterHeaderCZZ.Status::"To Use"); end; procedure PostAdvancePaymentUsagePreview(var PurchaseHeader: Record "Purchase Header"; Amount: Decimal; AmountLCY: Decimal; var PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ") - var - PurchInvHeader: Record "Purch. Inv. Header"; - VendorLedgerEntry: Record "Vendor Ledger Entry"; - GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; - AdvLetterUsageDocTypeCZZ: Enum "Adv. Letter Usage Doc.Type CZZ"; begin - PurchAdvLetterEntryCZZ.Reset(); - PurchAdvLetterEntryCZZ.DeleteAll(); - - if not TempPurchAdvLetterEntryCZZGlob.IsEmpty() then - TempPurchAdvLetterEntryCZZGlob.DeleteAll(); - - case PurchaseHeader."Document Type" of - PurchaseHeader."Document Type"::Order: - AdvLetterUsageDocTypeCZZ := AdvLetterUsageDocTypeCZZ::"Purchase Order"; - PurchaseHeader."Document Type"::Invoice: - AdvLetterUsageDocTypeCZZ := AdvLetterUsageDocTypeCZZ::"Purchase Invoice"; - else - exit; - end; - - PurchInvHeader.TransferFields(PurchaseHeader); - VendorLedgerEntry.Init(); - VendorLedgerEntry."Vendor No." := PurchaseHeader."Pay-to Vendor No."; - VendorLedgerEntry."Posting Date" := PurchaseHeader."Posting Date"; - VendorLedgerEntry."Document Date" := PurchaseHeader."Document Date"; - VendorLedgerEntry."Document Type" := PurchaseHeader."Document Type"; - VendorLedgerEntry."Document No." := PurchaseHeader."No."; - VendorLedgerEntry."External Document No." := PurchaseHeader."Vendor Order No."; - VendorLedgerEntry.Description := PurchaseHeader."Posting Description"; - VendorLedgerEntry."Currency Code" := PurchaseHeader."Currency Code"; - VendorLedgerEntry."Buy-from Vendor No." := PurchaseHeader."Buy-from Vendor No."; - VendorLedgerEntry."Vendor Posting Group" := PurchaseHeader."Vendor Posting Group"; - VendorLedgerEntry."Global Dimension 1 Code" := PurchaseHeader."Shortcut Dimension 1 Code"; - VendorLedgerEntry."Global Dimension 2 Code" := PurchaseHeader."Shortcut Dimension 2 Code"; - VendorLedgerEntry."Dimension Set ID" := PurchaseHeader."Dimension Set ID"; - VendorLedgerEntry."Purchaser Code" := PurchaseHeader."Purchaser Code"; - VendorLedgerEntry."Due Date" := PurchaseHeader."Due Date"; - VendorLedgerEntry."Payment Method Code" := PurchaseHeader."Payment Method Code"; -#if not CLEAN22 -#pragma warning disable AL0432 - if not ReplaceVATDateMgtCZL.IsEnabled() then - PurchaseHeader."VAT Reporting Date" := PurchaseHeader."VAT Date CZL"; -#pragma warning restore AL0432 -#endif - VendorLedgerEntry."VAT Date CZL" := PurchaseHeader."VAT Reporting Date"; - VendorLedgerEntry."Original Currency Factor" := PurchaseHeader."Currency Factor"; - VendorLedgerEntry.Amount := -Amount; - VendorLedgerEntry."Amount (LCY)" := -AmountLCY; - VendorLedgerEntry."Remaining Amount" := -Amount; - VendorLedgerEntry."Remaining Amt. (LCY)" := -AmountLCY; - - PostAdvancePaymentUsage(AdvLetterUsageDocTypeCZZ, PurchaseHeader."No.", PurchInvHeader, VendorLedgerEntry, GenJnlPostLine, true); - - if TempPurchAdvLetterEntryCZZGlob.FindSet() then begin - repeat - PurchAdvLetterEntryCZZ := TempPurchAdvLetterEntryCZZGlob; - PurchAdvLetterEntryCZZ.Insert(); - until TempPurchAdvLetterEntryCZZGlob.Next() = 0; - - TempPurchAdvLetterEntryCZZGlob.DeleteAll(); - end; + PurchAdvLetterPostCZZ.PostAdvancePaymentUsageForStatistics(PurchaseHeader, Amount, AmountLCY, PurchAdvLetterEntryCZZ); end; procedure UnapplyAdvanceLetter(var PurchInvHeader: Record "Purch. Inv. Header") var + AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; - PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; TempPurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ" temporary; - GenJournalLine: Record "Gen. Journal Line"; - VATEntry: Record "VAT Entry"; - VATPostingSetup: Record "VAT Posting Setup"; - VendorLedgerEntry: Record "Vendor Ledger Entry"; - VendorLedgerEntryInv: Record "Vendor Ledger Entry"; - DocumentTypeHandlerCZZ: Codeunit "Document Type Handler CZZ"; GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; - VATPostingSetupHandlerCZZ: Codeunit "VAT Posting Setup Handler CZZ"; - GenJnlCheckLnHandlerCZZ: Codeunit "Gen.Jnl.-Check Ln. Handler CZZ"; ConfirmManagement: Codeunit "Confirm Management"; - ApplId: Code[50]; AdvLetters: Text; - UnapplyIsNotPossibleErr: Label 'Unapply is not possible.'; UnapplyAdvLetterQst: Label 'Unapply advance letter: %1\Continue?', Comment = '%1 = Advance Letters'; begin PurchAdvLetterEntryCZZ.SetRange(PurchAdvLetterEntryCZZ."Entry Type", PurchAdvLetterEntryCZZ."Entry Type"::Usage); @@ -2274,247 +1059,16 @@ codeunit 31019 "PurchAdvLetterManagement CZZ" if not ConfirmManagement.GetResponseOrDefault(StrSubstNo(UnapplyAdvLetterQst, AdvLetters), false) then exit; - PurchAdvLetterEntryCZZ.Reset(); - PurchAdvLetterEntryCZZ.SetRange("Document No.", PurchInvHeader."No."); - PurchAdvLetterEntryCZZ.SetRange(Cancelled, false); - PurchAdvLetterEntryCZZ.Find('+'); - PurchAdvLetterEntryCZZ.SetFilter("Entry No.", '..%1', PurchAdvLetterEntryCZZ."Entry No."); - repeat - PurchAdvLetterHeaderCZZ.Get(PurchAdvLetterEntryCZZ."Purch. Adv. Letter No."); - case PurchAdvLetterEntryCZZ."Entry Type" of - PurchAdvLetterEntryCZZ."Entry Type"::"VAT Adjustment": - begin - VATPostingSetup.Get(PurchAdvLetterEntryCZZ."VAT Bus. Posting Group", PurchAdvLetterEntryCZZ."VAT Prod. Posting Group"); - PostUnrealizedExchangeRate(PurchAdvLetterEntryCZZ, PurchAdvLetterHeaderCZZ, VATPostingSetup, -PurchAdvLetterEntryCZZ."Amount (LCY)", -PurchAdvLetterEntryCZZ."VAT Amount (LCY)", - PurchAdvLetterEntryCZZ."Related Entry", 0, PurchAdvLetterEntryCZZ."Document No.", PurchAdvLetterEntryCZZ."Posting Date", PurchAdvLetterEntryCZZ."VAT Date", PurchInvHeader."Posting Description", GenJnlPostLine, true, false); - end; - PurchAdvLetterEntryCZZ."Entry Type"::"VAT Rate": - begin - VATPostingSetup.Get(PurchAdvLetterEntryCZZ."VAT Bus. Posting Group", PurchAdvLetterEntryCZZ."VAT Prod. Posting Group"); - PostExchangeRate(-PurchAdvLetterEntryCZZ."Amount (LCY)", -PurchAdvLetterEntryCZZ."VAT Amount (LCY)", PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, VATPostingSetup, - PurchAdvLetterEntryCZZ."Document No.", PurchAdvLetterEntryCZZ."Posting Date", PurchAdvLetterEntryCZZ."VAT Date", PurchInvHeader."Source Code", - PurchInvHeader."Posting Description", PurchAdvLetterEntryCZZ."Related Entry", true, GenJnlPostLine, false); - end; - PurchAdvLetterEntryCZZ."Entry Type"::"VAT Usage": - begin - VATPostingSetup.Get(PurchAdvLetterEntryCZZ."VAT Bus. Posting Group", PurchAdvLetterEntryCZZ."VAT Prod. Posting Group"); - InitGenJnlLineFromAdvance(PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, PurchAdvLetterEntryCZZ."Document No.", PurchAdvLetterEntryCZZ."External Document No.", - PurchInvHeader."Source Code", PurchInvHeader."Posting Description", GenJournalLine); - GenJournalLine."Document Type" := GenJournalLine."Document Type"::Invoice; - GenJournalLine.Validate("Posting Date", PurchAdvLetterEntryCZZ."Posting Date"); -#if not CLEAN22 -#pragma warning disable AL0432 - if not ReplaceVATDateMgtCZL.IsEnabled() then - GenJournalLine.Validate("VAT Date CZL", PurchInvHeader."VAT Date CZL") - else -#pragma warning restore AL0432 -#endif - GenJournalLine.Validate("VAT Reporting Date", PurchInvHeader."VAT Reporting Date"); - GenJournalLine."Original Doc. VAT Date CZL" := PurchInvHeader."Original Doc. VAT Date CZL"; - GenJournalLine."Account No." := VATPostingSetup."Purch. Adv. Letter Account CZZ"; - GenJournalLine.SetCurrencyFactor(PurchAdvLetterEntryCZZ."Currency Code", PurchAdvLetterEntryCZZ."Currency Factor"); - GenJournalLine."Gen. Posting Type" := GenJournalLine."Gen. Posting Type"::Purchase; - GenJournalLine."VAT Calculation Type" := PurchAdvLetterEntryCZZ."VAT Calculation Type"; - if GenJournalLine."VAT Calculation Type" = GenJournalLine."VAT Calculation Type"::"Reverse Charge VAT" then - GenJournalLine."VAT Posting" := GenJournalLine."VAT Posting"::"Manual VAT Entry"; - GenJournalLine."VAT Bus. Posting Group" := PurchAdvLetterEntryCZZ."VAT Bus. Posting Group"; - GenJournalLine.validate("VAT Prod. Posting Group", PurchAdvLetterEntryCZZ."VAT Prod. Posting Group"); - GenJournalLine.Correction := true; - GenJournalLine.Validate(Amount, -PurchAdvLetterEntryCZZ.Amount); - GenJournalLine."VAT Amount" := -PurchAdvLetterEntryCZZ."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 - if 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 else - GenJournalLine."VAT Amount (LCY)" := -PurchAdvLetterEntryCZZ."VAT Amount (LCY)"; - GenJournalLine."Amount (LCY)" := -PurchAdvLetterEntryCZZ."Amount (LCY)"; - GenJournalLine."VAT Base Amount (LCY)" := -PurchAdvLetterEntryCZZ."VAT Base Amount (LCY)"; - end; - BindSubscription(VATPostingSetupHandlerCZZ); - BindSubscription(DocumentTypeHandlerCZZ); - GenJnlPostLine.RunWithCheck(GenJournalLine); - UnbindSubscription(VATPostingSetupHandlerCZZ); - UnbindSubscription(DocumentTypeHandlerCZZ); - -#if not CLEAN22 -#pragma warning disable AL0432 - if not ReplaceVATDateMgtCZL.IsEnabled() then - GenJournalLine."VAT Reporting Date" := GenJournalLine."VAT Date CZL"; -#pragma warning restore AL0432 -#endif - AdvEntryInit(false); - AdvEntryInitRelatedEntry(PurchAdvLetterEntryCZZ."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", PurchAdvLetterEntryCZZ."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, PurchAdvLetterEntryCZZ, PurchAdvLetterEntryCZZ."Document No.", PurchAdvLetterEntryCZZ."External Document No.", PurchInvHeader."Source Code", PurchInvHeader."Posting Description", GenJournalLine); - GenJournalLine.Validate("Posting Date", PurchAdvLetterEntryCZZ."Posting Date"); -#if not CLEAN22 -#pragma warning disable AL0432 - if not ReplaceVATDateMgtCZL.IsEnabled() then - GenJournalLine.Validate("VAT Date CZL", PurchInvHeader."VAT Date CZL") - else -#pragma warning restore AL0432 -#endif - GenJournalLine.Validate("VAT Reporting Date", PurchInvHeader."VAT Reporting Date"); - GenJournalLine."Original Doc. VAT Date CZL" := PurchInvHeader."Original Doc. VAT Date CZL"; - GenJournalLine."Account No." := VATPostingSetup."Purch. Adv. Letter Account CZZ"; - GenJournalLine.SetCurrencyFactor(PurchInvHeader."Currency Code", PurchAdvLetterEntryCZZ."Currency Factor"); - GenJournalLine.Correction := true; - GenJournalLine.Validate(Amount, PurchAdvLetterEntryCZZ.Amount); - GenJnlPostLine.RunWithCheck(GenJournalLine); - end; - PurchAdvLetterEntryCZZ."Entry Type"::Usage: - begin - VendorLedgerEntry.Get(PurchAdvLetterEntryCZZ."Vendor Ledger Entry No."); - VendorLedgerEntryInv := VendorLedgerEntry; -#pragma warning disable AA0181 - VendorLedgerEntryInv.Next(-1); -#pragma warning restore AA0181 - UnapplyVendLedgEntry(VendorLedgerEntry, GenJnlPostLine); - - InitGenJnlLineFromVendLedgEntry(VendorLedgerEntry, GenJournalLine, VendorLedgerEntry."Document Type"::" "); - GenJournalLine."Adv. Letter Template Code CZZ" := PurchAdvLetterHeaderCZZ."Advance Letter Code"; - GenJournalLine."Adv. Letter No. (Entry) CZZ" := PurchAdvLetterEntryCZZ."Purch. Adv. Letter No."; - GenJournalLine."Use Advance G/L Account CZZ" := true; - GenJournalLine.SetCurrencyFactor(PurchAdvLetterEntryCZZ."Currency Code", PurchAdvLetterEntryCZZ."Currency Factor"); - GenJournalLine.Correction := true; - GenJournalLine.Amount := -PurchAdvLetterEntryCZZ.Amount; - GenJournalLine."Amount (LCY)" := -PurchAdvLetterEntryCZZ."Amount (LCY)"; - - ApplId := CopyStr(VendorLedgerEntry."Document No." + Format(VendorLedgerEntry."Entry No.", 0, ''), 1, MaxStrLen(ApplId)); - VendorLedgerEntry.CalcFields("Remaining Amount"); - VendorLedgerEntry."Amount to Apply" := VendorLedgerEntry."Remaining Amount"; - VendorLedgerEntry."Applies-to ID" := ApplId; - Codeunit.Run(Codeunit::"Vend. Entry-Edit", VendorLedgerEntry); - GenJournalLine."Applies-to ID" := ApplId; - - BindSubscription(GenJnlCheckLnHandlerCZZ); - GenJnlPostLine.RunWithCheck(GenJournalLine); - - VendorLedgerEntry.FindLast(); - AdvEntryInit(false); - AdvEntryInitCancel(); - AdvEntryInitVendLedgEntryNo(VendorLedgerEntry."Entry No."); - AdvEntryInitRelatedEntry(PurchAdvLetterEntryCZZ."Entry No."); - AdvEntryInsert("Advance Letter Entry Type CZZ"::Usage, GenJournalLine."Adv. Letter No. (Entry) CZZ", 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); - - InitGenJnlLineFromVendLedgEntry(VendorLedgerEntry, GenJournalLine, GenJournalLine."Document Type"::" "); - GenJournalLine."Adv. Letter Template Code CZZ" := PurchAdvLetterHeaderCZZ."Advance Letter Code"; - GenJournalLine.SetCurrencyFactor(PurchAdvLetterEntryCZZ."Currency Code", PurchAdvLetterEntryCZZ."Currency Factor"); - GenJournalLine.Correction := true; - GenJournalLine.Amount := PurchAdvLetterEntryCZZ.Amount; - GenJournalLine."Amount (LCY)" := PurchAdvLetterEntryCZZ."Amount (LCY)"; - - ApplId := CopyStr(VendorLedgerEntryInv."Document No." + Format(VendorLedgerEntryInv."Entry No.", 0, ''), 1, MaxStrLen(ApplId)); - VendorLedgerEntryInv.Prepayment := false; - VendorLedgerEntryInv."Advance Letter No. CZZ" := ''; - VendorLedgerEntryInv.CalcFields("Remaining Amount"); - VendorLedgerEntryInv."Amount to Apply" := VendorLedgerEntryInv."Remaining Amount"; - VendorLedgerEntryInv."Applies-to ID" := ApplId; - Codeunit.Run(Codeunit::"Vend. Entry-Edit", VendorLedgerEntryInv); - GenJournalLine."Applies-to ID" := ApplId; - - GenJnlPostLine.RunWithCheck(GenJournalLine); - UnbindSubscription(GenJnlCheckLnHandlerCZZ); - - UpdateStatus(PurchAdvLetterHeaderCZZ, PurchAdvLetterHeaderCZZ.Status::"To Use"); - end; - else - Error(UnapplyIsNotPossibleErr); - end; - until PurchAdvLetterEntryCZZ.Next(-1) = 0; - - PurchAdvLetterEntryCZZ.ModifyAll(Cancelled, true); - end; - - local procedure UnapplyVendLedgEntry(var VendorLedgerEntry: Record "Vendor Ledger Entry"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line") - var - DetailedVendorLedgEntry1: Record "Detailed Vendor Ledg. Entry"; - DetailedVendorLedgEntry2: Record "Detailed Vendor Ledg. Entry"; - DetailedVendorLedgEntry3: Record "Detailed Vendor Ledg. Entry"; - GenJournalLine: Record "Gen. Journal Line"; - Succes: Boolean; - UnapplyLastInvoicesErr: Label 'First you must unapply invoces that were applied to advance last time.'; - begin - DetailedVendorLedgEntry1.SetCurrentKey("Vendor Ledger Entry No.", "Entry Type"); - DetailedVendorLedgEntry1.SetRange("Vendor Ledger Entry No.", VendorLedgerEntry."Entry No."); - DetailedVendorLedgEntry1.SetRange("Entry Type", DetailedVendorLedgEntry1."Entry Type"::Application); - DetailedVendorLedgEntry1.SetRange(Unapplied, false); - Succes := false; - repeat - if DetailedVendorLedgEntry1.FindLast() then begin - DetailedVendorLedgEntry2.Reset(); - DetailedVendorLedgEntry2.SetCurrentKey("Transaction No.", "Vendor No.", "Entry Type"); - DetailedVendorLedgEntry2.SetRange("Transaction No.", DetailedVendorLedgEntry1."Transaction No."); - DetailedVendorLedgEntry2.SetRange("Vendor No.", DetailedVendorLedgEntry1."Vendor No."); - if DetailedVendorLedgEntry2.FindSet() then - repeat - if (DetailedVendorLedgEntry2."Entry Type" <> DetailedVendorLedgEntry2."Entry Type"::"Initial Entry") and - not DetailedVendorLedgEntry2.Unapplied - then begin - DetailedVendorLedgEntry3.Reset(); - DetailedVendorLedgEntry3.SetCurrentKey("Vendor Ledger Entry No.", "Entry Type"); - DetailedVendorLedgEntry3.SetRange("Vendor Ledger Entry No.", DetailedVendorLedgEntry2."Vendor Ledger Entry No."); - DetailedVendorLedgEntry3.SetRange(Unapplied, false); - if DetailedVendorLedgEntry3.FindLast() and - (DetailedVendorLedgEntry3."Transaction No." > DetailedVendorLedgEntry2."Transaction No.") - then - Error(UnapplyLastInvoicesErr); - end; - until DetailedVendorLedgEntry2.Next() = 0; + Clear(AdvancePostingParametersCZZ); + AdvancePostingParametersCZZ."Document No." := PurchInvHeader."No."; - GenJournalLine.Init(); - GenJournalLine."Document No." := DetailedVendorLedgEntry1."Document No."; - GenJournalLine."Posting Date" := DetailedVendorLedgEntry1."Posting Date"; -#if not CLEAN22 -#pragma warning disable AL0432 - if not ReplaceVATDateMgtCZL.IsEnabled() then - GenJournalLine.Validate("VAT Date CZL", VendorLedgerEntry."VAT Date CZL") - else -#pragma warning restore AL0432 -#endif - GenJournalLine.Validate("VAT Reporting Date", VendorLedgerEntry."VAT Date CZL"); - GenJournalLine.Validate("Original Doc. VAT Date CZL", VendorLedgerEntry."VAT Date CZL"); - GenJournalLine."Account Type" := GenJournalLine."Account Type"::Vendor; - GenJournalLine."Account No." := DetailedVendorLedgEntry1."Vendor No."; - GenJournalLine.Correction := true; - GenJournalLine."Document Type" := GenJournalLine."Document Type"::" "; - GenJournalLine.Description := VendorLedgerEntry.Description; - GenJournalLine."Shortcut Dimension 1 Code" := VendorLedgerEntry."Global Dimension 1 Code"; - GenJournalLine."Shortcut Dimension 2 Code" := VendorLedgerEntry."Global Dimension 2 Code"; - GenJournalLine."Dimension Set ID" := VendorLedgerEntry."Dimension Set ID"; - GenJournalLine."Posting Group" := VendorLedgerEntry."Vendor Posting Group"; - GenJournalLine."Source Currency Code" := DetailedVendorLedgEntry1."Currency Code"; - GenJournalLine."System-Created Entry" := true; - OnUnapplyVendLedgEntryOnBeforePostUnapplyVendLedgEntry(VendorLedgerEntry, DetailedVendorLedgEntry1, GenJournalLine); - GenJnlPostLine.UnapplyVendLedgEntry(GenJournalLine, DetailedVendorLedgEntry1); - end else - Succes := true; - until Succes; + PurchAdvLetterPostCZZ.PostAdvanceLetterUnapplying(PurchInvHeader, GenJnlPostLine, AdvancePostingParametersCZZ); end; procedure ApplyAdvanceLetter(var PurchInvHeader: Record "Purch. Inv. Header") var AdvanceLetterApplication: Record "Advance Letter Application CZZ"; + AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; VendorLedgerEntry: Record "Vendor Ledger Entry"; ConfirmManagement: Codeunit "Confirm Management"; GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; @@ -2543,8 +1097,7 @@ codeunit 31019 "PurchAdvLetterManagement CZZ" if AdvanceLetterApplication.Amount > -VendorLedgerEntry."Remaining Amount" then Error(CannotApplyErr, -VendorLedgerEntry."Remaining Amount"); - PostAdvancePaymentUsage(AdvanceLetterApplication."Document Type"::"Posted Purchase Invoice", PurchInvHeader."No.", PurchInvHeader, - VendorLedgerEntry, GenJnlPostLine, false); + PurchAdvLetterPostCZZ.PostAdvanceLetterApplying(PurchInvHeader, GenJnlPostLine, AdvancePostingParametersCZZ); end; #if not CLEAN24 [Obsolete('Replaced by CheckAdvancePayment with Variant parameter.', '24.0')] @@ -2629,6 +1182,7 @@ codeunit 31019 "PurchAdvLetterManagement CZZ" PurchAdvLetterEntryCZZ2: Record "Purch. Adv. Letter Entry CZZ"; PurchAdvLetterEntryCZZ3: Record "Purch. Adv. Letter Entry CZZ"; GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; + AmountRemainder: Decimal; AmountToDivide: Decimal; AmountToPost: Decimal; AmountTotal: Decimal; @@ -2647,17 +1201,21 @@ codeunit 31019 "PurchAdvLetterManagement CZZ" PurchAdvLetterHeaderCZZ.Get(PurchAdvLetterEntryCZZ."Purch. Adv. Letter No."); - BufferAdvanceVATLines(PurchAdvLetterEntryCZZ, TempAdvancePostingBufferCZZ1, ToDate); + PurchAdvLetterPostCZZ.BufferAdvanceVATLines(PurchAdvLetterEntryCZZ, TempAdvancePostingBufferCZZ1, ToDate); TempAdvancePostingBufferCZZ1.CalcSums(Amount); VATDocAmtToDate := TempAdvancePostingBufferCZZ1.Amount; if VATDocAmtToDate <> 0 then begin Coeff := Amount / VATDocAmtToDate; + AmountRemainder := 0; TempAdvancePostingBufferCZZ1.FindSet(); repeat TempAdvancePostingBufferCZZ2.Init(); TempAdvancePostingBufferCZZ2 := TempAdvancePostingBufferCZZ1; - TempAdvancePostingBufferCZZ2.RecalcAmountsByCoefficient(Coeff); + AmountRemainder += TempAdvancePostingBufferCZZ2.Amount * Coeff; + TempAdvancePostingBufferCZZ2.Amount := AmountRemainder; + TempAdvancePostingBufferCZZ2.UpdateVATAmounts(); TempAdvancePostingBufferCZZ2.Insert(); + AmountRemainder -= TempAdvancePostingBufferCZZ2.Amount; until TempAdvancePostingBufferCZZ1.Next() = 0; if TempAdvancePostingBufferCZZ2.FindSet() then @@ -2667,7 +1225,7 @@ codeunit 31019 "PurchAdvLetterManagement CZZ" PurchAdvLetterEntryCZZ."Entry No.", DetEntryNo, DocumentNo, ToDate, ToDate, PostDescription, GenJnlPostLine, false, false); until TempAdvancePostingBufferCZZ2.Next() = 0; - BufferAdvanceVATLines(PurchAdvLetterEntryCZZ, TempAdvancePostingBufferCZZ1, 0D); + PurchAdvLetterPostCZZ.BufferAdvanceVATLines(PurchAdvLetterEntryCZZ, TempAdvancePostingBufferCZZ1, 0D); TempAdvancePostingBufferCZZ1.CalcSums(Amount); TempAdvancePostingBufferCZZ2.CalcSums(Amount); if TempAdvancePostingBufferCZZ1.Amount = 0 then @@ -2731,82 +1289,17 @@ codeunit 31019 "PurchAdvLetterManagement CZZ" 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) var - GenJournalLine: Record "Gen. Journal Line"; - SourceCodeSetup: Record "Source Code Setup"; - begin - SourceCodeSetup.Get(); - GetCurrency(PurchAdvLetterHeaderCZZ."Currency Code"); - - if VATAmount <> 0 then begin - InitGenJnlLineFromAdvance(PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, DocumentNo, '', SourceCodeSetup."Exchange Rate Adjmt.", PostDescription, GenJournalLine); - GenJournalLine.Validate("Posting Date", PostingDate); -#if not CLEAN22 -#pragma warning disable AL0432 - if not ReplaceVATDateMgtCZL.IsEnabled() then - GenJournalLine.Validate("VAT Date CZL", VATDate) - else -#pragma warning restore AL0432 -#endif - GenJournalLine.Validate("VAT Reporting Date", VATDate); - if VATAmount > 0 then begin - CurrencyGlob.TestField("Unrealized Losses Acc."); - GenJournalLine."Account No." := CurrencyGlob."Unrealized Losses Acc."; - end else begin - CurrencyGlob.TestField("Unrealized Gains Acc."); - GenJournalLine."Account No." := CurrencyGlob."Unrealized Gains Acc."; - end; - GenJournalLine.Validate(Amount, VATAmount); - if not Preview then - GenJnlPostLine.RunWithCheck(GenJournalLine); - - InitGenJnlLineFromAdvance(PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, DocumentNo, '', SourceCodeSetup."Exchange Rate Adjmt.", PostDescription, GenJournalLine); - GenJournalLine.Validate("Posting Date", PostingDate); -#if not CLEAN22 -#pragma warning disable AL0432 - if not ReplaceVATDateMgtCZL.IsEnabled() then - GenJournalLine.Validate("VAT Date CZL", VATDate) - else -#pragma warning restore AL0432 -#endif - GenJournalLine.Validate("VAT Reporting Date", VATDate); - GenJournalLine."Account No." := VATPostingSetup."Purch. Adv. Letter Account CZZ"; - GenJournalLine.Validate(Amount, -VATAmount); - if not Preview then - GenJnlPostLine.RunWithCheck(GenJournalLine); - end; - - AdvEntryInit(Preview); - if Correction then - AdvEntryInitCancel(); - AdvEntryInitRelatedEntry(RelatedEntryNo); - AdvEntryInitDetVendLedgEntryNo(RelatedDetEntryNo); - AdvEntryInitVAT(VATPostingSetup."VAT Bus. Posting Group", VATPostingSetup."VAT Prod. Posting Group", VATDate, VATDate, - 0, VATPostingSetup."VAT %", VATPostingSetup."VAT Identifier", VATPostingSetup."VAT Calculation Type", - 0, VATAmount, 0, Amount - VATAmount); - AdvEntryInsert("Advance Letter Entry Type CZZ"::"VAT Adjustment", PurchAdvLetterEntryCZZ."Purch. Adv. Letter No.", PostingDate, - 0, Amount, '', 0, DocumentNo, GenJournalLine."External Document No.", - PurchAdvLetterEntryCZZ."Global Dimension 1 Code", PurchAdvLetterEntryCZZ."Global Dimension 2 Code", PurchAdvLetterEntryCZZ."Dimension Set ID", Preview); - end; - - local procedure ReverseUnrealizedExchangeRate(var PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; var PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; - var VATPostingSetup: Record "VAT Posting Setup"; Coef: Decimal; RelatedEntryNo: Integer; - DocumentNo: Code[20]; PostingDate: Date; VATDate: Date; PostDescription: Text[100]; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; Preview: Boolean) - var - AmountLCY: Decimal; - VATAmountLCY: Decimal; + AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; begin - if PurchAdvLetterEntryCZZ."Entry Type" <> PurchAdvLetterEntryCZZ."Entry Type"::Payment then - exit; - - GetRemAmtLCYVATAdjust(AmountLCY, VATAmountLCY, PurchAdvLetterEntryCZZ, PostingDate, VATPostingSetup."VAT Bus. Posting Group", VATPostingSetup."VAT Prod. Posting Group"); - if (AmountLCY = 0) and (VATAmountLCY = 0) then - exit; - - AmountLCY := Round(AmountLCY * Coef); - VATAmountLCY := Round(VATAmountLCY * Coef); + Clear(AdvancePostingParametersCZZ); + AdvancePostingParametersCZZ."Document No." := DocumentNo; + AdvancePostingParametersCZZ."Posting Date" := PostingDate; + AdvancePostingParametersCZZ."VAT Date" := VATDate; + AdvancePostingParametersCZZ."Posting Description" := PostDescription; + AdvancePostingParametersCZZ."Temporary Entries Only" := Preview; - PostUnrealizedExchangeRate(PurchAdvLetterEntryCZZ, PurchAdvLetterHeaderCZZ, VATPostingSetup, -AmountLCY, -VATAmountLCY, - RelatedEntryNo, 0, DocumentNo, PostingDate, VATDate, PostDescription, GenJnlPostLine, false, Preview); + PurchAdvLetterPostCZZ.PostUnrealizedExchangeRate( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, VATPostingSetup, Amount, VATAmount, RelatedEntryNo, RelatedDetEntryNo, Correction, GenJnlPostLine, AdvancePostingParametersCZZ); end; local procedure GetPostingDateUI(DefaultPostingDate: Date): Date @@ -2822,6 +1315,110 @@ codeunit 31019 "PurchAdvLetterManagement CZZ" GetPostingDateCZZ.GetValues(PostingDate); exit(PostingDate); end; +#if not CLEAN24 +#pragma warning disable AL0432 + internal procedure RaiseOnBeforePostPaymentRepos(var GenJournalLine: Record "Gen. Journal Line"; var PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; PostedGenJournalLine: Record "Gen. Journal Line") + begin + OnBeforePostPaymentRepos(GenJournalLine, purchAdvLetterHeaderCZZ, PostedGenJournalLine); + end; + + internal procedure RaiseOnAfterPostPaymentRepos(var GenJournalLine: Record "Gen. Journal Line"; var PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; PostedGenJournalLine: Record "Gen. Journal Line") + begin + OnAfterPostPaymentRepos(GenJournalLine, purchAdvLetterHeaderCZZ, PostedGenJournalLine); + end; + + internal procedure RaiseOnBeforePostPayment(var GenJournalLine: Record "Gen. Journal Line"; var PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; PostedGenJournalLine: Record "Gen. Journal Line") + begin + OnBeforePostPayment(GenJournalLine, purchAdvLetterHeaderCZZ, PostedGenJournalLine); + end; + + internal procedure RaiseOnAfterPostPayment(var GenJournalLine: Record "Gen. Journal Line"; var PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; PostedGenJournalLine: Record "Gen. Journal Line") + begin + OnAfterPostPayment(GenJournalLine, purchAdvLetterHeaderCZZ, PostedGenJournalLine); + end; + + internal procedure RaiseOnAfterInitGenJnlLineFromVendLedgEntry(var VendorLedgerEntry: Record "Vendor Ledger Entry"; var GenJournalLine: Record "Gen. Journal Line") + begin + OnAfterInitGenJnlLineFromVendLedgEntry(VendorLedgerEntry, GenJournalLine); + end; + + internal procedure RaiseOnAfterInitGenJnlLineFromAdvance(var PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; var PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; var GenJournalLine: Record "Gen. Journal Line") + begin + OnAfterInitGenJnlLineFromAdvance(PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, GenJournalLine); + end; + + internal procedure RaiseOnPostAdvancePaymentVATOnBeforeGenJnlPostLine(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; var GenJournalLine: Record "Gen. Journal Line") + begin + OnPostAdvancePaymentVATOnBeforeGenJnlPostLine(PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, GenJournalLine); + end; + + internal procedure RaiseOnBeforePostAdvancePaymentUsage(AdvLetterUsageDocTypeCZZ: Enum "Adv. Letter Usage Doc.Type CZZ"; DocumentNo: Code[20]; var PurchInvHeader: Record "Purch. Inv. Header"; var VendorLedgerEntry: Record "Vendor Ledger Entry"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; Preview: Boolean; var IsHandled: Boolean) + begin + OnBeforePostAdvancePaymentUsage( + AdvLetterUsageDocTypeCZZ, DocumentNo, PurchInvHeader, VendorLedgerEntry, GenJnlPostLine, Preview, IsHandled); + end; + + internal procedure RaiseOnPostAdvancePaymentUsageOnBeforeLoopPurchAdvLetterEntry(var AdvanceLetterApplicationCZZ: Record "Advance Letter Application CZZ"; var PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ") + begin + OnPostAdvancePaymentUsageOnBeforeLoopPurchAdvLetterEntry(AdvanceLetterApplicationCZZ, PurchAdvLetterEntryCZZ); + end; + + internal procedure RaiseOnBeforePostAdvancePayment(VendorLedgerEntry: Record "Vendor Ledger Entry"; GenJournalLine: Record "Gen. Journal Line"; LinkAmount: Decimal; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var IsHandled: Boolean); + begin + OnBeforePostAdvancePayment(VendorLedgerEntry, GenJournalLine, LinkAmount, GenJnlPostLine, IsHandled); + end; + + internal procedure RaiseOnBeforePostClosePayment(var GenJournalLine: Record "Gen. Journal Line"; var PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ") + begin + OnBeforePostClosePayment(GenJournalLine, PurchAdvLetterHeaderCZZ); + end; + + internal procedure RaiseOnAfterPostClosePayment(var GenJournalLine: Record "Gen. Journal Line"; var PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ") + begin + OnAfterPostClosePayment(GenJournalLine, PurchAdvLetterHeaderCZZ); + end; + + internal procedure RaiseOnBeforePostClosePaymentRepos(var GenJournalLine: Record "Gen. Journal Line"; var PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ") + begin + OnBeforePostClosePaymentRepos(GenJournalLine, PurchAdvLetterHeaderCZZ); + end; + + internal procedure RaiseOnAfterPostClosePaymentRepos(var GenJournalLine: Record "Gen. Journal Line"; var PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ") + begin + OnAfterPostClosePaymentRepos(GenJournalLine, PurchAdvLetterHeaderCZZ); + end; + + internal procedure RaiseOnBeforePostReversePaymentRepos(var GenJournalLine: Record "Gen. Journal Line"; var PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ") + begin + OnBeforePostReversePaymentRepos(GenJournalLine, PurchAdvLetterHeaderCZZ); + end; + + internal procedure RaiseOnAfterPostReversePaymentRepos(var GenJournalLine: Record "Gen. Journal Line"; var PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ") + begin + OnAfterPostReversePaymentRepos(GenJournalLine, PurchAdvLetterHeaderCZZ); + end; + + internal procedure RaiseOnBeforePostReversePayment(var GenJournalLine: Record "Gen. Journal Line"; var PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ") + begin + OnBeforePostReversePayment(GenJournalLine, PurchAdvLetterHeaderCZZ); + end; + + internal procedure RaiseOnAfterPostReversePayment(var GenJournalLine: Record "Gen. Journal Line"; var PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ") + begin + OnAfterPostReversePayment(GenJournalLine, PurchAdvLetterHeaderCZZ); + end; + + internal procedure RaiseOnBeforePostReversePaymentVAT(var PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; PostingDate: Date; var Preview: Boolean; var IsHandled: Boolean) + begin + OnBeforePostReversePaymentVAT(PurchAdvLetterEntryCZZ, PostingDate, Preview, IsHandled); + end; + + internal procedure RaiseOnUnapplyVendLedgEntryOnBeforePostUnapplyVendLedgEntry(var VendorLedgerEntry: Record "Vendor Ledger Entry"; var DetailedVendorLedgEntry: Record "Detailed Vendor Ledg. Entry"; var GenJournalLine: Record "Gen. Journal Line") + begin + OnUnapplyVendLedgEntryOnBeforePostUnapplyVendLedgEntry(VendorLedgerEntry, DetailedVendorLedgEntry, GenJournalLine); + end; +#pragma warning restore AL0432 +#endif [IntegrationEvent(false, false)] local procedure OnBeforeInsertAdvEntry(var PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; var Preview: Boolean) @@ -2843,21 +1440,25 @@ codeunit 31019 "PurchAdvLetterManagement CZZ" begin end; + [Obsolete('Replaced by OnPostAdvancePaymentOnBeforePostPaymentApplication event in "Purch. Adv. Letter-Post CZZ" codeunit.', '24.0')] [IntegrationEvent(false, false)] local procedure OnBeforePostPaymentRepos(var GenJournalLine: Record "Gen. Journal Line"; var PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; PostedGenJournalLine: Record "Gen. Journal Line") begin end; + [Obsolete('Replaced by OnPostAdvancePaymentOnAfterPostPaymentApplication event in "Purch. Adv. Letter-Post CZZ" codeunit.', '24.0')] [IntegrationEvent(false, false)] local procedure OnAfterPostPaymentRepos(var GenJournalLine: Record "Gen. Journal Line"; var PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; PostedGenJournalLine: Record "Gen. Journal Line") begin end; + [Obsolete('Replaced by OnPostAdvancePaymentOnBeforePostAdvancePayment event in "Purch. Adv. Letter-Post CZZ" codeunit.', '24.0')] [IntegrationEvent(false, false)] local procedure OnBeforePostPayment(var GenJournalLine: Record "Gen. Journal Line"; var PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; PostedGenJournalLine: Record "Gen. Journal Line") begin end; + [Obsolete('Replaced by OnPostAdvancePaymentOnAfterPostAdvancePayment event in "Purch. Adv. Letter-Post CZZ" codeunit.', '24.0')] [IntegrationEvent(false, false)] local procedure OnAfterPostPayment(var GenJournalLine: Record "Gen. Journal Line"; var PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; PostedGenJournalLine: Record "Gen. Journal Line") begin @@ -2868,61 +1469,73 @@ codeunit 31019 "PurchAdvLetterManagement CZZ" begin end; + [Obsolete('Replaced by OnReverseAdvancePaymentOnBeforePostInvoiceApplication event in "Purch. Adv. Letter-Post CZZ" codeunit.', '24.0')] [IntegrationEvent(false, false)] local procedure OnBeforePostReversePaymentRepos(var GenJournalLine: Record "Gen. Journal Line"; var PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ") begin end; + [Obsolete('Replaced by OnReverseAdvancePaymentOnAfterPostInvoiceApplication event in "Purch. Adv. Letter-Post CZZ" codeunit.', '24.0')] [IntegrationEvent(false, false)] local procedure OnAfterPostReversePaymentRepos(var GenJournalLine: Record "Gen. Journal Line"; var PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ") begin end; + [Obsolete('Replaced by OnReverseAdvancePaymentOnBeforePostAdvancePaymentUsage event in "Purch. Adv. Letter-Post CZZ" codeunit.', '24.0')] [IntegrationEvent(false, false)] local procedure OnBeforePostReversePayment(var GenJournalLine: Record "Gen. Journal Line"; var PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ") begin end; + [Obsolete('Replaced by OnReverseAdvancePaymentOnAfterPostAdvancePaymentUsage event in "Purch. Adv. Letter-Post CZZ" codeunit.', '24.0')] [IntegrationEvent(false, false)] local procedure OnAfterPostReversePayment(var GenJournalLine: Record "Gen. Journal Line"; var PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ") begin end; + [Obsolete('Replaced by OnBeforeReverseAdvancePaymentVAT event in "Purch. Adv. Letter-Post CZZ" codeunit.', '24.0')] [IntegrationEvent(false, false)] local procedure OnBeforePostReversePaymentVAT(var PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; PostingDate: Date; var Preview: Boolean; var IsHandled: Boolean) begin end; + [Obsolete('Replaced by OnPostAdvancePaymentClosingEntryOnBeforePostBalance event in "Purch. Adv. Letter-Post CZZ" codeunit.', '24.0')] [IntegrationEvent(false, false)] local procedure OnBeforePostClosePaymentRepos(var GenJournalLine: Record "Gen. Journal Line"; var PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ") begin end; + [Obsolete('Replaced by OnPostAdvancePaymentClosingEntryOnAfterPostBalance event in "Purch. Adv. Letter-Post CZZ" codeunit.', '24.0')] [IntegrationEvent(false, false)] local procedure OnAfterPostClosePaymentRepos(var GenJournalLine: Record "Gen. Journal Line"; var PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ") begin end; + [Obsolete('Replaced by OnPostAdvancePaymentClosingEntryOnBeforePost event in "Purch. Adv. Letter-Post CZZ" codeunit.', '24.0')] [IntegrationEvent(false, false)] local procedure OnBeforePostClosePayment(var GenJournalLine: Record "Gen. Journal Line"; var PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ") begin end; + [Obsolete('Replaced by OnPostAdvancePaymentClosingEntryOnAfterPost event in "Purch. Adv. Letter-Post CZZ" codeunit.', '24.0')] [IntegrationEvent(false, false)] local procedure OnAfterPostClosePayment(var GenJournalLine: Record "Gen. Journal Line"; var PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ") begin end; + [Obsolete('Replaced by OnUnapplyVendLedgEntryOnBeforePostUnapplyVendLedgEntry event in "Purch. Adv. Letter-Post CZZ" codeunit.', '24.0')] [IntegrationEvent(true, false)] local procedure OnUnapplyVendLedgEntryOnBeforePostUnapplyVendLedgEntry(var VendorLedgerEntry: Record "Vendor Ledger Entry"; var DetailedVendorLedgEntry: Record "Detailed Vendor Ledg. Entry"; var GenJournalLine: Record "Gen. Journal Line") begin end; + [Obsolete('Replaced by events in "Gen. Journal Line CZZ" table extension, e.g. one of the events OnAfterCopyFromVendorLedgerEntryCZZ.', '24.0')] [IntegrationEvent(true, false)] local procedure OnAfterInitGenJnlLineFromVendLedgEntry(var VendorLedgerEntry: Record "Vendor Ledger Entry"; var GenJournalLine: Record "Gen. Journal Line") begin end; + [Obsolete('Replaced by events in "Gen. Journal Line CZZ" table extension, e.g. one of the events OnAfterCopyGenJnlLineFromPurchAdvLetterHeaderCZZ.', '24.0')] [IntegrationEvent(true, false)] local procedure OnAfterInitGenJnlLineFromAdvance(var PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; var PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; var GenJournalLine: Record "Gen. Journal Line") begin @@ -2933,6 +1546,7 @@ codeunit 31019 "PurchAdvLetterManagement CZZ" begin end; + [Obsolete('Replaced by OnBeforePostAdvancePayment event in "Purch. Adv. Letter-Post CZZ" codeunit.', '24.0')] [IntegrationEvent(false, false)] local procedure OnBeforePostAdvancePayment(VendorLedgerEntry: Record "Vendor Ledger Entry"; GenJournalLine: Record "Gen. Journal Line"; LinkAmount: Decimal; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var IsHandled: Boolean); begin @@ -2948,6 +1562,7 @@ codeunit 31019 "PurchAdvLetterManagement CZZ" begin end; + [Obsolete('Replaced by OnPostAdvancePaymentUsageOnAfterSetPurchAdvLetterEntryFilter event in "Purch. Adv. Letter-Post CZZ" codeunit.', '24.0')] [IntegrationEvent(false, false)] local procedure OnPostAdvancePaymentUsageOnBeforeLoopPurchAdvLetterEntry(var AdvanceLetterApplicationCZZ: Record "Advance Letter Application CZZ"; var PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ") begin @@ -2958,11 +1573,13 @@ codeunit 31019 "PurchAdvLetterManagement CZZ" begin end; + [Obsolete('Replaced by OnBeforePostAdvancePaymentUsage event in "Purch. Adv. Letter-Post CZZ" codeunit.', '24.0')] [IntegrationEvent(true, false)] local procedure OnBeforePostAdvancePaymentUsage(AdvLetterUsageDocTypeCZZ: Enum "Adv. Letter Usage Doc.Type CZZ"; DocumentNo: Code[20]; var PurchInvHeader: Record "Purch. Inv. Header"; var VendorLedgerEntry: Record "Vendor Ledger Entry"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; Preview: Boolean; var IsHandled: Boolean) begin end; + [Obsolete('Replaced by OnPostAdvancePaymentVATOnBeforePostVATDocumentAmounts event in "Purch. Adv. Letter-Post CZZ" codeunit.', '24.0')] [IntegrationEvent(true, false)] local procedure OnPostAdvancePaymentVATOnBeforeGenJnlPostLine(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; var GenJournalLine: Record "Gen. Journal Line") begin diff --git a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/PurchAdvLetterPostCZZ.Codeunit.al b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/PurchAdvLetterPostCZZ.Codeunit.al new file mode 100644 index 0000000000..f384dbedeb --- /dev/null +++ b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/PurchAdvLetterPostCZZ.Codeunit.al @@ -0,0 +1,2745 @@ +// ------------------------------------------------------------------------------------------------ +// 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.AdvancePayments; + +using Microsoft.Finance.Currency; +using Microsoft.Finance.GeneralLedger.Journal; +using Microsoft.Finance.GeneralLedger.Posting; +#if not CLEAN22 +using Microsoft.Finance.VAT.Calculation; +#endif +using Microsoft.Finance.VAT.Ledger; +using Microsoft.Finance.VAT.Setup; +using Microsoft.Foundation.AuditCodes; +using Microsoft.Foundation.NoSeries; +using Microsoft.Purchases.Document; +using Microsoft.Purchases.History; +using Microsoft.Purchases.Payables; +using Microsoft.Purchases.Setup; + +codeunit 31142 "Purch. Adv. Letter-Post CZZ" +{ + Permissions = tabledata "Purch. Adv. Letter Entry CZZ" = im; + + var + CurrencyGlob: Record Currency; + TempPurchAdvLetterEntryCZZGlob: Record "Purch. Adv. Letter Entry CZZ" temporary; + PurchasesPayablesSetup: Record "Purchases & Payables Setup"; + PurchAdvLetterManagementCZZ: Codeunit "PurchAdvLetterManagement CZZ"; + ExceededAmountErr: Label 'Amount has been exceeded.'; + ExceededAmountToPayErr: Label 'The amount cannot be higher than to pay on advance letter.'; + ExceededRemainingAmountErr: Label 'The amount cannot be higher than remaining amount on ledger entry.'; + ReverseAmountErr: Label 'Reverse amount %1 is not posible on entry %2.', Comment = '%1 = Reverse Amount, %2 = Purchase Advance Entry No.'; + NothingToPostErr: Label 'Nothing to Post.'; + TemporaryRecordErr: Label 'The record of "Purch. Adv. Letter Entry CZZ" must be temporary.'; + UnlinkIsNotPossibleErr: Label 'Unlink is not possible, because %1 entry exists.', Comment = '%1 = Entry type'; + UnapplyIsNotPossibleErr: Label 'Unapply is not possible.'; + UnapplyLastInvoicesErr: Label 'First you must unapply invoces that were applied to advance last time.'; + + procedure PostAdvancePayment( + var VendorLedgerEntry: Record "Vendor Ledger Entry"; + PostedGenJournalLine: Record "Gen. Journal Line"; + var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; + AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ") + var + GenJournalLine: Record "Gen. Journal Line"; + PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; + VendorLedgerEntryPayment: Record "Vendor Ledger Entry"; + Amount, AmountLCY : Decimal; + EntryNo, GLEntryNo : Integer; + IsHandled: Boolean; + begin + IsHandled := false; + OnBeforePostAdvancePayment(VendorLedgerEntry, PostedGenJournalLine, GenJnlPostLine, AdvancePostingParametersCZZ, IsHandled); +#if not CLEAN24 + RaiseOnBeforePostAdvancePayment( + VendorLedgerEntry, PostedGenJournalLine, AdvancePostingParametersCZZ."Amount to Link", GenJnlPostLine, IsHandled); +#endif + if IsHandled then + exit; + + VendorLedgerEntry.TestField("Advance Letter No. CZZ", ''); + PurchAdvLetterHeaderCZZ.Get(PostedGenJournalLine."Advance Letter No. CZZ"); + PurchAdvLetterHeaderCZZ.CheckPurchaseAdvanceLetterPostRestrictions(); + PurchAdvLetterHeaderCZZ.TestField("Currency Code", VendorLedgerEntry."Currency Code"); + PurchAdvLetterHeaderCZZ.TestField("Pay-to Vendor No.", VendorLedgerEntry."Vendor No."); + + VendorLedgerEntry.CalcFields("Remaining Amount", "Remaining Amt. (LCY)"); + if AdvancePostingParametersCZZ."Amount to Link" = 0 then begin + Amount := VendorLedgerEntry."Remaining Amount"; + AmountLCY := VendorLedgerEntry."Remaining Amt. (LCY)"; + end else begin + if AdvancePostingParametersCZZ."Amount to Link" > VendorLedgerEntry."Remaining Amount" then + Error(ExceededRemainingAmountErr); + + Amount := AdvancePostingParametersCZZ."Amount to Link"; + AmountLCY := Round(Amount / VendorLedgerEntry."Original Currency Factor"); + end; + + PurchAdvLetterHeaderCZZ.CalcFields("To Pay"); + if Amount > PurchAdvLetterHeaderCZZ."To Pay" then + Error(ExceededAmountToPayErr); + + // Post payment application + InitGenJournalLine(VendorLedgerEntry, GenJournalLine); + GenJournalLine."Posting Date" := AdvancePostingParametersCZZ."Posting Date"; + GenJournalLine."Adv. Letter Template Code CZZ" := PurchAdvLetterHeaderCZZ."Advance Letter Code"; + GenJournalLine.Correction := true; + GenJournalLine.Amount := -Amount; + GenJournalLine."Amount (LCY)" := -AmountLCY; + if not AdvancePostingParametersCZZ."Temporary Entries Only" then begin + VendorLedgerEntry.SetApplication(PurchAdvLetterHeaderCZZ."Advance Letter Code", ''); + GenJournalLine."Applies-to ID" := VendorLedgerEntry."Applies-to ID"; + OnPostAdvancePaymentOnBeforePostPaymentApplication( + PurchAdvLetterHeaderCZZ, PostedGenJournalLine, AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); +#if not CLEAN24 + RaiseOnBeforePostPaymentRepos(GenJournalLine, PurchAdvLetterHeaderCZZ, PostedGenJournalLine); +#endif + GLEntryNo := RunGenJnlPostLine(GenJournalLine, GenJnlPostLine, false, false, false); + OnPostAdvancePaymentOnAfterPostPaymentApplication(PurchAdvLetterHeaderCZZ, PostedGenJournalLine, + AdvancePostingParametersCZZ, GLEntryNo, GenJnlPostLine, GenJournalLine); +#if not CLEAN24 + RaiseOnAfterPostPaymentRepos(GenJournalLine, PurchAdvLetterHeaderCZZ, PostedGenJournalLine); +#endif + end; + + // Post advance payment + InitGenJournalLine(VendorLedgerEntry, GenJournalLine); + GenJournalLine."Posting Date" := AdvancePostingParametersCZZ."Posting Date"; + GenJournalLine."Adv. Letter Template Code CZZ" := PurchAdvLetterHeaderCZZ."Advance Letter Code"; + GenJournalLine."Adv. Letter No. (Entry) CZZ" := PurchAdvLetterHeaderCZZ."No."; + GenJournalLine."Use Advance G/L Account CZZ" := true; + GenJournalLine.Amount := Amount; + GenJournalLine."Amount (LCY)" := AmountLCY; + if not AdvancePostingParametersCZZ."Temporary Entries Only" then begin + OnPostAdvancePaymentOnBeforePostAdvancePayment(PurchAdvLetterHeaderCZZ, PostedGenJournalLine, AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); +#if not CLEAN24 + RaiseOnBeforePostPayment(GenJournalLine, PurchAdvLetterHeaderCZZ, PostedGenJournalLine); +#endif + GLEntryNo := RunGenJnlPostLine(GenJournalLine, GenJnlPostLine, false, false, false); + OnPostAdvancePaymentOnAfterPostAdvancePayment(PurchAdvLetterHeaderCZZ, PostedGenJournalLine, + AdvancePostingParametersCZZ, GLEntryNo, GenJnlPostLine, GenJournalLine); +#if not CLEAN24 + RaiseOnAfterPostPayment(GenJournalLine, PurchAdvLetterHeaderCZZ, PostedGenJournalLine); +#endif + end; + + VendorLedgerEntryPayment.FindLast(); + + TempPurchAdvLetterEntryCZZGlob.InitNewEntry(); + TempPurchAdvLetterEntryCZZGlob.InitVendorLedgerEntry(VendorLedgerEntryPayment); + TempPurchAdvLetterEntryCZZGlob.CopyFromGenJnlLine(GenJournalLine); + TempPurchAdvLetterEntryCZZGlob."Entry Type" := "Advance Letter Entry Type CZZ"::Payment; + TempPurchAdvLetterEntryCZZGlob."Purch. Adv. Letter No." := PurchAdvLetterHeaderCZZ."No."; + EntryNo := TempPurchAdvLetterEntryCZZGlob.InsertNewEntry(not AdvancePostingParametersCZZ."Temporary Entries Only"); + + if not AdvancePostingParametersCZZ."Temporary Entries Only" then + PurchAdvLetterHeaderCZZ.UpdateStatus(PurchAdvLetterHeaderCZZ.Status::"To Use"); + + OnAfterPostAdvancePayment(PurchAdvLetterHeaderCZZ, VendorLedgerEntry, PostedGenJournalLine, EntryNo, GenJnlPostLine, AdvancePostingParametersCZZ); + end; + + procedure PostAdvancePaymentUnlinking( + 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"; + GenJournalLine: Record "Gen. Journal Line"; + PurchAdvLetterEntryCZZ2: Record "Purch. Adv. Letter Entry CZZ"; + PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; + VendorLedgerEntry: Record "Vendor Ledger Entry"; + VendorLedgerEntryAdv: Record "Vendor Ledger Entry"; + VendorLedgerEntryPay: Record "Vendor Ledger Entry"; + GLEntryNo: Integer; + IsHandled: Boolean; + begin + IsHandled := false; + OnBeforePostAdvancePaymentUnlinking(PurchAdvLetterEntryCZZ, GenJnlPostLine, AdvancePostingParametersCZZ, IsHandled); + if IsHandled then + exit; + + PurchAdvLetterEntryCZZ.TestField("Entry Type", PurchAdvLetterEntryCZZ."Entry Type"::Payment); + PurchAdvLetterEntryCZZ.TestField(Cancelled, false); + + PurchAdvLetterEntryCZZ2.SetRange("Purch. Adv. Letter No.", PurchAdvLetterEntryCZZ."Purch. Adv. Letter No."); + PurchAdvLetterEntryCZZ2.SetRange("Related Entry", PurchAdvLetterEntryCZZ."Entry No."); + PurchAdvLetterEntryCZZ2.SetRange(Cancelled, false); + PurchAdvLetterEntryCZZ2.SetFilter("Entry Type", '<>%1', PurchAdvLetterEntryCZZ2."Entry Type"::"VAT Payment"); + if PurchAdvLetterEntryCZZ2.FindFirst() then + Error(UnlinkIsNotPossibleErr, PurchAdvLetterEntryCZZ2."Entry Type"); + + PurchAdvLetterHeaderCZZ.Get(PurchAdvLetterEntryCZZ."Purch. Adv. Letter No."); + + PurchAdvLetterEntryCZZ2.SetRange("Entry Type", PurchAdvLetterEntryCZZ2."Entry Type"::"VAT Payment"); + if PurchAdvLetterEntryCZZ2.FindSet() then + repeat + Clear(AdvancePostingBufferCZZ); + AdvancePostingBufferCZZ.PrepareForPurchAdvLetterEntry(PurchAdvLetterEntryCZZ2); + Clear(AdvancePostingParametersCZZ2); + AdvancePostingParametersCZZ2.CopyFromPurchAdvLetterEntry(PurchAdvLetterEntryCZZ2); + AdvancePostingParametersCZZ2."Document Type" := "Gen. Journal Document Type"::Invoice; + PostAdvancePaymentVATUnlinking( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ2, AdvancePostingBufferCZZ, GenJnlPostLine, AdvancePostingParametersCZZ2); + until PurchAdvLetterEntryCZZ2.Next() = 0; + + VendorLedgerEntryAdv.Get(PurchAdvLetterEntryCZZ."Vendor Ledger Entry No."); + VendorLedgerEntryPay := VendorLedgerEntryAdv; +#pragma warning disable AA0181 + VendorLedgerEntryPay.Next(-1); +#pragma warning restore AA0181 + UnapplyVendLedgEntry(VendorLedgerEntryPay, GenJnlPostLine); + + // Post advance payment application + InitGenJournalLine(VendorLedgerEntryAdv, GenJournalLine); + GenJournalLine."Posting Date" := AdvancePostingParametersCZZ."Posting Date"; + GenJournalLine."Adv. Letter Template Code CZZ" := PurchAdvLetterHeaderCZZ."Advance Letter Code"; + GenJournalLine."Adv. Letter No. (Entry) CZZ" := PurchAdvLetterHeaderCZZ."No."; + GenJournalLine."Use Advance G/L Account CZZ" := true; + GenJournalLine.Correction := true; + GenJournalLine.SetCurrencyFactor( + PurchAdvLetterEntryCZZ."Currency Code", PurchAdvLetterEntryCZZ."Currency Factor"); + GenJournalLine.Amount := -PurchAdvLetterEntryCZZ.Amount; + GenJournalLine."Amount (LCY)" := -PurchAdvLetterEntryCZZ."Amount (LCY)"; + if not AdvancePostingParametersCZZ."Temporary Entries Only" then begin + VendorLedgerEntryAdv.SetApplication('', PurchAdvLetterHeaderCZZ."No."); + GenJournalLine."Applies-to ID" := VendorLedgerEntryAdv."Applies-to ID"; + OnPostAdvancePaymentUnlinkingOnBeforePostAdvancePaymentApplication( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); + GLEntryNo := RunGenJnlPostLine(GenJournalLine, GenJnlPostLine, false, false, false); + OnPostAdvancePaymentUnlinkingOnAfterPostAdvancePaymentApplication( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, + AdvancePostingParametersCZZ, GLEntryNo, GenJnlPostLine, GenJournalLine); + end; + + VendorLedgerEntry.FindLast(); + + TempPurchAdvLetterEntryCZZGlob.InitNewEntry(); + TempPurchAdvLetterEntryCZZGlob.InitVendorLedgerEntry(VendorLedgerEntry); + TempPurchAdvLetterEntryCZZGlob.InitRelatedEntry(PurchAdvLetterEntryCZZ); + TempPurchAdvLetterEntryCZZGlob.CopyFromGenJnlLine(GenJournalLine); + TempPurchAdvLetterEntryCZZGlob."Entry Type" := PurchAdvLetterEntryCZZ."Entry Type"; + TempPurchAdvLetterEntryCZZGlob."Purch. Adv. Letter No." := PurchAdvLetterHeaderCZZ."No."; + TempPurchAdvLetterEntryCZZGlob.Cancelled := true; + TempPurchAdvLetterEntryCZZGlob.InsertNewEntry(not AdvancePostingParametersCZZ."Temporary Entries Only"); + + // Post payment application balance + InitGenJournalLine(VendorLedgerEntryAdv, GenJournalLine); + GenJournalLine."Posting Date" := AdvancePostingParametersCZZ."Posting Date"; + GenJournalLine."Adv. Letter Template Code CZZ" := PurchAdvLetterHeaderCZZ."Advance Letter Code"; + GenJournalLine.SetCurrencyFactor( + PurchAdvLetterEntryCZZ."Currency Code", PurchAdvLetterEntryCZZ."Currency Factor"); + GenJournalLine.Amount := PurchAdvLetterEntryCZZ.Amount; + GenJournalLine."Amount (LCY)" := PurchAdvLetterEntryCZZ."Amount (LCY)"; + if not AdvancePostingParametersCZZ."Temporary Entries Only" then begin + VendorLedgerEntryPay.SetApplication('', ''); + GenJournalLine."Applies-to ID" := VendorLedgerEntryPay."Applies-to ID"; + OnPostAdvancePaymentUnlinkingOnBeforePostPaymentApplication( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); + GLEntryNo := RunGenJnlPostLine(GenJournalLine, GenJnlPostLine, false, false, false); + OnPostAdvancePaymentUnlinkingOnAfterPostPaymentApplication( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, + AdvancePostingParametersCZZ, GLEntryNo, GenJnlPostLine, GenJournalLine); + + PurchAdvLetterEntryCZZ.Cancelled := true; + PurchAdvLetterEntryCZZ.Modify(); + + PurchAdvLetterHeaderCZZ.UpdateStatus(PurchAdvLetterHeaderCZZ.Status::"To Pay"); + end; + + OnAfterPostAdvancePaymentUnlinking(PurchAdvLetterEntryCZZ, GenJnlPostLine, AdvancePostingParametersCZZ); + end; + + procedure PostAdvancePaymentVAT( + var PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; + var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; + var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; + AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ") + var + AdvancePostingParametersCZZ2: Record "Advance Posting Parameters CZZ"; + GenJournalLine: Record "Gen. Journal Line"; + PurchAdvLetterEntryCZZ2: Record "Purch. Adv. Letter Entry CZZ"; + PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; + VATPostingSetup: Record "VAT Posting Setup"; + VendorLedgerEntry: Record "Vendor Ledger Entry"; + GLEntryNo: Integer; + IsHandled: Boolean; + begin + IsHandled := false; + OnBeforePostAdvancePaymentVAT(PurchAdvLetterEntryCZZ, AdvancePostingBufferCZZ, GenJnlPostLine, AdvancePostingParametersCZZ, IsHandled); + if IsHandled then + exit; + + if PurchAdvLetterEntryCZZ."Entry Type" <> PurchAdvLetterEntryCZZ."Entry Type"::Payment then + exit; + + PurchAdvLetterEntryCZZ.TestField(Cancelled, false); + + AdvancePostingParametersCZZ.CheckPurchaseDates(); + AdvancePostingParametersCZZ.CheckDocumentNo(); + + PurchasesPayablesSetup.Get(); + if PurchasesPayablesSetup."Ext. Doc. No. Mandatory" then + AdvancePostingParametersCZZ.CheckExternalDocumentNo(); + + PurchAdvLetterHeaderCZZ.Get(PurchAdvLetterEntryCZZ."Purch. Adv. Letter No."); + PurchAdvLetterHeaderCZZ.CalcFields("Amount Including VAT"); + if PurchAdvLetterHeaderCZZ."Amount Including VAT" = 0 then + exit; + + AdvancePostingBufferCZZ.SetFilter(Amount, '<>0'); + if AdvancePostingBufferCZZ.IsEmpty() then + Error(NothingToPostErr); + + 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"); + PurchAdvLetterEntryCZZ2.CalcSums(Amount); + AdvancePostingBufferCZZ.CalcSums(Amount); + if Abs(PurchAdvLetterEntryCZZ.Amount - PurchAdvLetterEntryCZZ2.Amount) < Abs(AdvancePostingBufferCZZ.Amount) then + Error(ExceededAmountErr); + + if AdvancePostingParametersCZZ."Source Code" = '' then begin + VendorLedgerEntry.Get(PurchAdvLetterEntryCZZ."Vendor Ledger Entry No."); + 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 not CLEAN24 + 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"); + + // 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; + + OnAfterPostAdvancePaymentVAT( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, AdvancePostingBufferCZZ, + GenJnlPostLine, AdvancePostingParametersCZZ); + end; + + local procedure PostAdvancePaymentVATUnlinking( + PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; + var PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; + var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; + var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; + AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ") + var + AdvancePostingParametersCZZ2: Record "Advance Posting Parameters CZZ"; + VATPostingSetup: Record "VAT Posting Setup"; + GenJournalLine: Record "Gen. Journal Line"; + EntryNo, GLEntryNo : Integer; + IsHandled: Boolean; + begin + IsHandled := false; + OnBeforePostAdvancePaymentVATUnlinking( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, AdvancePostingBufferCZZ, + GenJnlPostLine, AdvancePostingParametersCZZ, IsHandled); + if IsHandled then + exit; + + PurchAdvLetterEntryCZZ.TestField("Entry Type", PurchAdvLetterEntryCZZ."Entry Type"::"VAT Payment"); + PurchAdvLetterEntryCZZ.TestField(Cancelled, false); + + VATPostingSetup.Get(AdvancePostingBufferCZZ."VAT Bus. Posting Group", AdvancePostingBufferCZZ."VAT Prod. Posting Group"); + + // 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 + OnPostAdvancePaymentVATUnlinkingOnBeforePost( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, VATPostingSetup, + AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); + GLEntryNo := RunGenJnlPostLine(GenJournalLine, GenJnlPostLine, true, true, false); + OnPostAdvancePaymentVATUnlinkingOnAfterPost( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, VATPostingSetup, + AdvancePostingParametersCZZ, GLEntryNo, GenJnlPostLine, GenJournalLine); + end; + + TempPurchAdvLetterEntryCZZGlob.InitNewEntry(); + TempPurchAdvLetterEntryCZZGlob.InitRelatedEntry(PurchAdvLetterEntryCZZ."Related Entry"); + 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.Cancelled := true; + EntryNo := TempPurchAdvLetterEntryCZZGlob.InsertNewEntry(not AdvancePostingParametersCZZ."Temporary Entries Only"); + + // Post balance of advance payment VAT unlinking + AdvancePostingBufferCZZ.ReverseAmounts(); + AdvancePostingParametersCZZ2.InitNew(AdvancePostingParametersCZZ); + AdvancePostingParametersCZZ2."Document Type" := "Gen. Journal Document Type"::" "; + InitGenJournalLine(PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, AdvancePostingParametersCZZ2, GenJournalLine); + GenJournalLine."Account No." := VATPostingSetup.GetPurchAdvLetterAccountCZZ(); + GenJournalLine.CopyFromAdvancePostingBufferAmountsCZZ(AdvancePostingBufferCZZ); + if not AdvancePostingParametersCZZ."Temporary Entries Only" then begin + OnPostAdvancePaymentVATUnlinkingOnBeforePostBalance( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, AdvancePostingBufferCZZ, + AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); + GLEntryNo := RunGenJnlPostLine(GenJournalLine, GenJnlPostLine, false, false, false); + OnPostAdvancePaymentVATUnlinkingOnAfterPostBalance( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, AdvancePostingBufferCZZ, + AdvancePostingParametersCZZ, GLEntryNo, GenJnlPostLine, GenJournalLine); + + PurchAdvLetterEntryCZZ.Cancelled := true; + PurchAdvLetterEntryCZZ.Modify(true); + end; + + OnAfterPostAdvancePaymentVATUnlinking( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, AdvancePostingBufferCZZ, + EntryNo, GenJnlPostLine, AdvancePostingParametersCZZ); + end; + + procedure PostAdvancePaymentUsage( + var PurchInvHeader: Record "Purch. Inv. Header"; + var AdvanceLetterApplicationCZZ: Record "Advance Letter Application CZZ"; + var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; + AdvancePostingParameters: Record "Advance Posting Parameters CZZ") + var + PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; + PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; + TempAdvanceLetterApplicationCZZ: Record "Advance Letter Application CZZ" temporary; + TempPurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ" temporary; + AmountToUse, UseAmount, UseAmountLCY : Decimal; + IsHandled: Boolean; + begin + IsHandled := false; + OnBeforePostAdvancePaymentUsage(PurchInvHeader, AdvanceLetterApplicationCZZ, GenJnlPostLine, AdvancePostingParameters, IsHandled); +#if not CLEAN24 + RaiseOnBeforePostAdvancePaymentUsage(PurchInvHeader, AdvanceLetterApplicationCZZ, GenJnlPostLine, AdvancePostingParameters, IsHandled); +#endif + if IsHandled then + exit; + + if PurchInvHeader."Remaining Amount" = 0 then + PurchInvHeader.CalcFields("Remaining Amount"); + + AmountToUse := PurchInvHeader."Remaining Amount"; + if AmountToUse = 0 then + exit; + + if AdvanceLetterApplicationCZZ.IsEmpty() then + exit; + + AdvanceLetterApplicationCZZ.FindSet(); + repeat + PurchAdvLetterHeaderCZZ.Get(AdvanceLetterApplicationCZZ."Advance Letter No."); + PurchAdvLetterHeaderCZZ.TestField("Currency Code", PurchInvHeader."Currency Code"); + PurchAdvLetterHeaderCZZ.TestField("Pay-to Vendor No.", PurchInvHeader."Pay-to Vendor No."); + + PurchAdvLetterEntryCZZ.SetRange("Purch. Adv. Letter No.", AdvanceLetterApplicationCZZ."Advance Letter No."); + PurchAdvLetterEntryCZZ.SetRange(Cancelled, false); + PurchAdvLetterEntryCZZ.SetRange("Entry Type", PurchAdvLetterEntryCZZ."Entry Type"::Payment); + PurchAdvLetterEntryCZZ.SetFilter("Posting Date", '..%1', PurchInvHeader."Posting Date"); + OnPostAdvancePaymentUsageOnAfterSetPurchAdvLetterEntryFilter(AdvanceLetterApplicationCZZ, PurchAdvLetterEntryCZZ); +#if not CLEAN24 + RaiseOnPostAdvancePaymentUsageOnBeforeLoopPurchAdvLetterEntry(AdvanceLetterApplicationCZZ, PurchAdvLetterEntryCZZ); +#endif + if PurchAdvLetterEntryCZZ.FindSet() then + repeat + TempPurchAdvLetterEntryCZZ.Init(); + TempPurchAdvLetterEntryCZZ := PurchAdvLetterEntryCZZ; + TempPurchAdvLetterEntryCZZ.Amount := PurchAdvLetterEntryCZZ.GetRemainingAmount(); + TempPurchAdvLetterEntryCZZ."Amount (LCY)" := PurchAdvLetterEntryCZZ.GetRemainingAmountLCY(); + if TempPurchAdvLetterEntryCZZ.Amount <> 0 then + TempPurchAdvLetterEntryCZZ.Insert(); + until PurchAdvLetterEntryCZZ.Next() = 0; + + TempAdvanceLetterApplicationCZZ.Add(AdvanceLetterApplicationCZZ); + until AdvanceLetterApplicationCZZ.Next() = 0; + + TempPurchAdvLetterEntryCZZ.Reset(); + TempPurchAdvLetterEntryCZZ.SetCurrentKey("Posting Date"); + if TempPurchAdvLetterEntryCZZ.FindSet() then begin + repeat + TempAdvanceLetterApplicationCZZ.SetRange("Advance Letter No.", TempPurchAdvLetterEntryCZZ."Purch. Adv. Letter No."); + TempAdvanceLetterApplicationCZZ.FindFirst(); + if TempAdvanceLetterApplicationCZZ.Amount < TempPurchAdvLetterEntryCZZ.Amount then + TempPurchAdvLetterEntryCZZ.Amount := TempAdvanceLetterApplicationCZZ.Amount; + + if AmountToUse > TempPurchAdvLetterEntryCZZ.Amount then + UseAmount := TempPurchAdvLetterEntryCZZ.Amount + else + UseAmount := AmountToUse; + + if UseAmount <> 0 then begin + UseAmountLCY := Round(UseAmount / TempPurchAdvLetterEntryCZZ."Currency Factor"); + ReverseAdvancePayment(TempPurchAdvLetterEntryCZZ, PurchInvHeader, UseAmount, UseAmountLCY, GenJnlPostLine, AdvancePostingParameters); + AmountToUse -= UseAmount; + TempAdvanceLetterApplicationCZZ.Amount -= UseAmount; + TempAdvanceLetterApplicationCZZ."Amount (LCY)" -= UseAmountLCY; + TempAdvanceLetterApplicationCZZ.Modify(); + end; + until (TempPurchAdvLetterEntryCZZ.Next() = 0) or (AmountToUse = 0); + + if not AdvancePostingParameters."Temporary Entries Only" then begin + TempAdvanceLetterApplicationCZZ.Reset(); + if TempAdvanceLetterApplicationCZZ.FindSet() then + repeat + TempAdvanceLetterApplicationCZZ.ApplyChanges(); + until TempAdvanceLetterApplicationCZZ.Next() = 0; + end; + end; + + OnAfterPostAdvancePaymentUsage(PurchInvHeader, AdvanceLetterApplicationCZZ, GenJnlPostLine, AdvancePostingParameters); + end; + + internal procedure PostAdvancePaymentUsageForStatistics( + var PurchaseHeader: Record "Purchase Header"; + Amount: Decimal; + AmountLCY: Decimal; + var PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ") + var + AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; + AdvanceLetterApplicationCZZ: Record "Advance Letter Application CZZ"; + PurchInvHeader: Record "Purch. Inv. Header"; + GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; + begin + if not PurchAdvLetterEntryCZZ.IsTemporary then + Error(TemporaryRecordErr); + + PurchAdvLetterEntryCZZ.Reset(); + PurchAdvLetterEntryCZZ.DeleteAll(); + + if not TempPurchAdvLetterEntryCZZGlob.IsEmpty() then + TempPurchAdvLetterEntryCZZGlob.DeleteAll(); + + if not PurchaseHeader.IsAdvanceLetterDocTypeCZZ() then + exit; + + PurchInvHeader.TransferFields(PurchaseHeader); + PurchInvHeader."Remaining Amount" := Amount; + + AdvancePostingParametersCZZ."Temporary Entries Only" := true; + AdvanceLetterApplicationCZZ.SetRange("Document Type", PurchaseHeader.GetAdvLetterUsageDocTypeCZZ()); + AdvanceLetterApplicationCZZ.SetRange("Document No.", PurchaseHeader."No."); + PostAdvancePaymentUsage(PurchInvHeader, AdvanceLetterApplicationCZZ, GenJnlPostLine, AdvancePostingParametersCZZ); + + if TempPurchAdvLetterEntryCZZGlob.FindSet() then begin + repeat + PurchAdvLetterEntryCZZ := TempPurchAdvLetterEntryCZZGlob; + PurchAdvLetterEntryCZZ.Insert(); + until TempPurchAdvLetterEntryCZZGlob.Next() = 0; + + TempPurchAdvLetterEntryCZZGlob.DeleteAll(); + end; + end; + + procedure PostAdvancePaymentUsageVAT( + var PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; + var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; + var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; + AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ") + var + PurchAdvLetterEntryCZZ2: Record "Purch. Adv. Letter Entry CZZ"; + IsHandled: Boolean; + begin + IsHandled := false; + OnBeforePostAdvancePaymentUsageVAT( + PurchAdvLetterEntryCZZ, AdvancePostingBufferCZZ, GenJnlPostLine, AdvancePostingParametersCZZ, IsHandled); + if IsHandled then + exit; + + if PurchAdvLetterEntryCZZ."Entry Type" <> PurchAdvLetterEntryCZZ."Entry Type"::Usage then + exit; + PurchAdvLetterEntryCZZ.TestField(Cancelled, false); + + PurchAdvLetterEntryCZZ2.Get(PurchAdvLetterEntryCZZ."Related Entry"); + if PurchAdvLetterEntryCZZ2."Entry Type" <> PurchAdvLetterEntryCZZ2."Entry Type"::Payment then + exit; + + ReverseAdvancePaymentVAT( + PurchAdvLetterEntryCZZ2, AdvancePostingBufferCZZ, PurchAdvLetterEntryCZZ."Entry No.", + "Advance Letter Entry Type CZZ"::"VAT Usage", GenJnlPostLine, AdvancePostingParametersCZZ); + + OnAfterPostAdvancePaymentUsageVAT( + PurchAdvLetterEntryCZZ, AdvancePostingBufferCZZ, GenJnlPostLine, AdvancePostingParametersCZZ); + end; + + procedure PostAdvanceCreditMemoVAT( + var PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; + var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; + var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; + AdvancePostingParametersCZZ: Record "Advance Posting Parameters 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"; + PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; + TempAdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ" temporary; + VATPostingSetup: Record "VAT Posting Setup"; + ExchRateAmount, ExchRateVATAmount : Decimal; + GLEntryNo: Integer; + IsHandled: Boolean; + begin + IsHandled := false; + OnBeforePostAdvanceCreditMemoVAT( + PurchAdvLetterEntryCZZ, AdvancePostingBufferCZZ, GenJnlPostLine, AdvancePostingParametersCZZ, IsHandled); + if IsHandled then + exit; + + PurchAdvLetterEntryCZZ.TestField("Entry Type", PurchAdvLetterEntryCZZ."Entry Type"::"VAT Payment"); + PurchAdvLetterEntryCZZ.TestField(Cancelled, false); + + PurchAdvLetterHeaderCZZ.Get(PurchAdvLetterEntryCZZ."Purch. Adv. Letter No."); + + AdvancePostingBufferCZZ.SetFilter(Amount, '<>0'); + if AdvancePostingBufferCZZ.IsEmpty() then + Error(NothingToPostErr); + + if PurchAdvLetterEntryCZZ."Currency Code" <> '' then begin + PurchAdvLetterEntryCZZ2.Get(PurchAdvLetterEntryCZZ."Related Entry"); + BufferAdvanceVATLines(PurchAdvLetterEntryCZZ2, TempAdvancePostingBufferCZZ, 0D); + end; + + AdvancePostingBufferCZZ.FindSet(); + repeat + VATPostingSetup.Get(AdvancePostingBufferCZZ."VAT Bus. Posting Group", AdvancePostingBufferCZZ."VAT Prod. Posting Group"); + + // Post credit memo VAT + 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 + OnPostAdvanceCreditMemoVATOnBeforePost( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, AdvancePostingBufferCZZ, + AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); + GLEntryNo := RunGenJnlPostLine(GenJournalLine, GenJnlPostLine, true, true, false); + OnPostAdvanceCreditMemoVATOnAfterPost( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, AdvancePostingBufferCZZ, + AdvancePostingParametersCZZ, GLEntryNo, GenJnlPostLine, GenJournalLine); + end; + + TempPurchAdvLetterEntryCZZGlob.InitNewEntry(); + TempPurchAdvLetterEntryCZZGlob.InitRelatedEntry(PurchAdvLetterEntryCZZ."Related Entry"); + 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.Cancelled := true; + TempPurchAdvLetterEntryCZZGlob.InsertNewEntry(not AdvancePostingParametersCZZ."Temporary Entries Only"); + + AdvancePostingBufferCZZ.ReverseAmounts(); + if GenJournalLine."Currency Code" <> '' then + if TempAdvancePostingBufferCZZ.Get( + AdvancePostingBufferCZZ."VAT Bus. Posting Group", + AdvancePostingBufferCZZ."VAT Prod. Posting Group") + then begin + AdvancePostingParametersCZZ2.InitNew(AdvancePostingParametersCZZ); + AdvancePostingParametersCZZ2."Document Type" := "Gen. Journal Document Type"::" "; + AdvancePostingParametersCZZ2."External Document No." := ''; + AdvancePostingParametersCZZ2."Source Code" := ''; + 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)"; + if (ExchRateAmount <> 0) or (ExchRateVATAmount <> 0) then + PostExchangeRate(PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, VATPostingSetup, ExchRateAmount, ExchRateVATAmount, + PurchAdvLetterEntryCZZ."Related Entry", true, GenJnlPostLine, AdvancePostingParametersCZZ2); + + ReverseUnrealizedExchangeRate( + PurchAdvLetterEntryCZZ2, PurchAdvLetterHeaderCZZ, VATPostingSetup, + AdvancePostingBufferCZZ.Amount / TempAdvancePostingBufferCZZ.Amount, + PurchAdvLetterEntryCZZ2."Entry No.", GenJnlPostLine, AdvancePostingParametersCZZ2); + end; + + // Post balance of credit memo VAT + AdvancePostingParametersCZZ2.InitNew(AdvancePostingParametersCZZ); + AdvancePostingParametersCZZ2."Document Type" := "Gen. Journal Document Type"::" "; + InitGenJournalLine(PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, AdvancePostingParametersCZZ2, GenJournalLine); + GenJournalLine."Account No." := VATPostingSetup.GetPurchAdvLetterAccountCZZ(); + GenJournalLine.CopyFromAdvancePostingBufferAmountsCZZ(AdvancePostingBufferCZZ); + if not AdvancePostingParametersCZZ."Temporary Entries Only" then begin + OnPostAdvanceCreditMemoVATOnBeforePostBalance( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, AdvancePostingBufferCZZ, + AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); + GLEntryNo := RunGenJnlPostLine(GenJournalLine, GenJnlPostLine, false, false, false); + OnPostAdvanceCreditMemoVATOnAfterPostBalance( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, AdvancePostingBufferCZZ, + AdvancePostingParametersCZZ, GLEntryNo, GenJnlPostLine, GenJournalLine); + end; + 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); + end; + + OnAfterPostAdvanceCreditMemoVAT( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, AdvancePostingBufferCZZ, + GenJnlPostLine, AdvancePostingParametersCZZ); + end; + + procedure PostAdvanceLetterApplying( + var PurchInvHeader: Record "Purch. Inv. Header"; + var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; + AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ") + var + AdvanceLetterApplication: Record "Advance Letter Application CZZ"; + IsHandled: Boolean; + begin + IsHandled := false; + OnBeforePostAdvanceLetterApplying(PurchInvHeader, GenJnlPostLine, AdvancePostingParametersCZZ, IsHandled); + if IsHandled then + exit; + + AdvanceLetterApplication.SetRange("Document Type", AdvanceLetterApplication."Document Type"::"Posted Purchase Invoice"); + AdvanceLetterApplication.SetRange("Document No.", PurchInvHeader."No."); + if AdvanceLetterApplication.IsEmpty() then + exit; + + PostAdvancePaymentUsage(PurchInvHeader, AdvanceLetterApplication, GenJnlPostLine, AdvancePostingParametersCZZ); + + OnAfterPostAdvanceLetterApplying(PurchInvHeader, GenJnlPostLine, AdvancePostingParametersCZZ); + end; + + procedure PostAdvanceLetterUnapplying( + var PurchInvHeader: Record "Purch. Inv. Header"; + 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"; + PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; + PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; + VATPostingSetup: Record "VAT Posting Setup"; +#if not CLEAN22 +#pragma warning disable AL0432 + ReplaceVATDateMgtCZL: Codeunit "Replace VAT Date Mgt. CZL"; +#pragma warning restore AL0432 +#endif + IsHandled: Boolean; + begin + IsHandled := false; + OnBeforePostAdvanceLetterUnapplying(PurchInvHeader, GenJnlPostLine, AdvancePostingParametersCZZ, IsHandled); + if IsHandled then + exit; + + PurchAdvLetterEntryCZZ.SetRange("Entry Type", PurchAdvLetterEntryCZZ."Entry Type"::Usage); + PurchAdvLetterEntryCZZ.SetRange("Document No.", PurchInvHeader."No."); + PurchAdvLetterEntryCZZ.SetRange(Cancelled, false); + if not PurchAdvLetterEntryCZZ.FindLast() then + exit; + + PurchAdvLetterEntryCZZ.Reset(); + PurchAdvLetterEntryCZZ.SetRange("Document No.", PurchInvHeader."No."); + PurchAdvLetterEntryCZZ.SetRange(Cancelled, false); + PurchAdvLetterEntryCZZ.Find('+'); + PurchAdvLetterEntryCZZ.SetFilter("Entry No.", '..%1', PurchAdvLetterEntryCZZ."Entry No."); + repeat + AdvancePostingParametersCZZ2.InitNew(AdvancePostingParametersCZZ); + AdvancePostingParametersCZZ2."Posting Date" := PurchAdvLetterEntryCZZ."Posting Date"; + AdvancePostingParametersCZZ2."VAT Date" := PurchAdvLetterEntryCZZ."VAT Date"; + AdvancePostingParametersCZZ2."Posting Description" := PurchInvHeader."Posting Description"; + + PurchAdvLetterHeaderCZZ.Get(PurchAdvLetterEntryCZZ."Purch. Adv. Letter No."); + case PurchAdvLetterEntryCZZ."Entry Type" of + PurchAdvLetterEntryCZZ."Entry Type"::"VAT Adjustment": + begin + 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); + end; + PurchAdvLetterEntryCZZ."Entry Type"::"VAT Rate": + begin + AdvancePostingParametersCZZ2."Source Code" := PurchInvHeader."Source Code"; + + 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); + end; + PurchAdvLetterEntryCZZ."Entry Type"::"VAT Usage": + begin + AdvancePostingParametersCZZ2."Document Type" := "Gen. Journal Document Type"::Invoice; + AdvancePostingParametersCZZ2."External Document No." := PurchAdvLetterEntryCZZ."External Document No."; + AdvancePostingParametersCZZ2."Source Code" := PurchInvHeader."Source Code"; +#if not CLEAN22 +#pragma warning disable AL0432 + if not ReplaceVATDateMgtCZL.IsEnabled() then + AdvancePostingParametersCZZ2."VAT Date" := PurchInvHeader."VAT Date CZL" + else +#pragma warning restore AL0432 +#endif + AdvancePostingParametersCZZ2."VAT Date" := PurchInvHeader."VAT Reporting Date"; + AdvancePostingParametersCZZ2."Original Document VAT Date" := PurchInvHeader."Original Doc. VAT Date CZL"; + AdvancePostingParametersCZZ2."Currency Code" := PurchAdvLetterEntryCZZ."Currency Code"; + + Clear(AdvancePostingBufferCZZ); + AdvancePostingBufferCZZ.PrepareForPurchAdvLetterEntry(PurchAdvLetterEntryCZZ); + + PostAdvanceLetterEntryVATUsageUnapplying( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, AdvancePostingBufferCZZ, GenJnlPostLine, AdvancePostingParametersCZZ2) + end; + PurchAdvLetterEntryCZZ."Entry Type"::Usage: + begin + AdvancePostingParametersCZZ2.InitNew(AdvancePostingParametersCZZ); + + PostAdvanceLetterEntryUsageUnapplying( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, AdvancePostingBufferCZZ, GenJnlPostLine, AdvancePostingParametersCZZ2); + end; + else + Error(UnapplyIsNotPossibleErr); + end; + until PurchAdvLetterEntryCZZ.Next(-1) = 0; + + PurchAdvLetterEntryCZZ.ModifyAll(Cancelled, true); + + OnAfterPostAdvanceLetterUnapplying(PurchInvHeader, GenJnlPostLine, AdvancePostingParametersCZZ); + end; + + local procedure PostAdvanceLetterEntryVATUsageUnapplying( + PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; + PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; + var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; + var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; + AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ") + var + AdvancePostingParametersCZZ2: Record "Advance Posting Parameters CZZ"; + GenJournalLine: Record "Gen. Journal Line"; + VATPostingSetup: Record "VAT Posting Setup"; + VATEntry: Record "VAT Entry"; + EntryNo: Integer; + GLEntryNo: Integer; + IsHandled: Boolean; + begin + IsHandled := false; + OnBeforePostAdvanceLetterEntryVATUsageUnapplying( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, AdvancePostingBufferCZZ, GenJnlPostLine, AdvancePostingParametersCZZ, IsHandled); + if IsHandled then + exit; + + VATPostingSetup.Get(AdvancePostingBufferCZZ."VAT Bus. Posting Group", AdvancePostingBufferCZZ."VAT Prod. Posting Group"); + + InitGenJournalLine( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, AdvancePostingParametersCZZ, GenJournalLine); + GenJournalLine."Account No." := VATPostingSetup.GetPurchAdvLetterAccountCZZ(); + GenJournalLine."Gen. Posting Type" := GenJournalLine."Gen. Posting Type"::Purchase; + GenJournalLine.Correction := true; + AdvancePostingBufferCZZ.ReverseAmounts(); + 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 (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 + OnPostAdvanceLetterEntryVATUsageUnapplyingOnBeforePost( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, AdvancePostingBufferCZZ, + AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); + GLEntryNo := RunGenJnlPostLine(GenJournalLine, GenJnlPostLine, true, true, false); + OnPostAdvanceLetterEntryVATUsageUnapplyingOnAfterPost( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, AdvancePostingBufferCZZ, + AdvancePostingParametersCZZ, GLEntryNo, GenJnlPostLine, GenJournalLine); + end; + + TempPurchAdvLetterEntryCZZGlob.InitNewEntry(); + TempPurchAdvLetterEntryCZZGlob.InitRelatedEntry(PurchAdvLetterEntryCZZ."Related Entry"); + 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 Identifier" := VATPostingSetup."VAT Identifier"; + TempPurchAdvLetterEntryCZZGlob.Cancelled := true; + EntryNo := TempPurchAdvLetterEntryCZZGlob.InsertNewEntry(not AdvancePostingParametersCZZ."Temporary Entries Only"); + + AdvancePostingBufferCZZ.ReverseAmounts(); + + AdvancePostingParametersCZZ2.InitNew(AdvancePostingParametersCZZ); + AdvancePostingParametersCZZ2."Document Type" := "Gen. Journal Document Type"::" "; + InitGenJournalLine(PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, AdvancePostingParametersCZZ2, GenJournalLine); + GenJournalLine."Account No." := VATPostingSetup.GetPurchAdvLetterAccountCZZ(); + GenJournalLine.Correction := true; + GenJournalLine.CopyFromAdvancePostingBufferAmountsCZZ(AdvancePostingBufferCZZ); + if not AdvancePostingParametersCZZ."Temporary Entries Only" then begin + OnPostAdvanceLetterEntryVATUsageUnapplyingOnBeforePostBalance( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, AdvancePostingBufferCZZ, + AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); + GLEntryNo := RunGenJnlPostLine(GenJournalLine, GenJnlPostLine, false, false, false); + OnPostAdvanceLetterEntryVATUsageUnapplyingOnAfterPostBalance( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, AdvancePostingBufferCZZ, + AdvancePostingParametersCZZ, GLEntryNo, GenJnlPostLine, GenJournalLine); + end; + + OnAfterPostAdvanceLetterEntryVATUsageUnapplying( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, AdvancePostingBufferCZZ, + EntryNo, GenJnlPostLine, AdvancePostingParametersCZZ) + end; + + local procedure PostAdvanceLetterEntryUsageUnapplying( + PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; + PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; + var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; + var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; + AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ") + var + GenJournalLine: Record "Gen. Journal Line"; + VendorLedgerEntry: Record "Vendor Ledger Entry"; + VendorLedgerEntryInv: Record "Vendor Ledger Entry"; + EntryNo, GLEntryNo : Integer; + IsHandled: Boolean; + begin + IsHandled := false; + OnBeforePostAdvanceLetterEntryUsageUnapplying( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, AdvancePostingBufferCZZ, GenJnlPostLine, AdvancePostingParametersCZZ, IsHandled); + if IsHandled then + exit; + + VendorLedgerEntry.Get(PurchAdvLetterEntryCZZ."Vendor Ledger Entry No."); + VendorLedgerEntryInv := VendorLedgerEntry; +#pragma warning disable AA0181 + VendorLedgerEntryInv.Next(-1); +#pragma warning restore AA0181 + UnapplyVendLedgEntry(VendorLedgerEntry, GenJnlPostLine); + + InitGenJournalLine(VendorLedgerEntry, GenJournalLine); + GenJournalLine."Adv. Letter Template Code CZZ" := PurchAdvLetterHeaderCZZ."Advance Letter Code"; + GenJournalLine.Correction := true; + GenJournalLine."Adv. Letter No. (Entry) CZZ" := PurchAdvLetterHeaderCZZ."No."; + GenJournalLine."Use Advance G/L Account CZZ" := true; + GenJournalLine.SetCurrencyFactor( + PurchAdvLetterEntryCZZ."Currency Code", PurchAdvLetterEntryCZZ."Currency Factor"); + GenJournalLine.Amount := -PurchAdvLetterEntryCZZ.Amount; + GenJournalLine."Amount (LCY)" := -PurchAdvLetterEntryCZZ."Amount (LCY)"; + if not AdvancePostingParametersCZZ."Temporary Entries Only" then begin + VendorLedgerEntry.SetApplication('', ''); + GenJournalLine."Applies-to ID" := VendorLedgerEntry."Applies-to ID"; + OnPostAdvanceLetterEntryUsageUnapplyingOnBeforePostAdvancePaymentApplication( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, + AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); + GLEntryNo := RunGenJnlPostLine(GenJournalLine, GenJnlPostLine, false, false, true); + OnPostAdvanceLetterEntryUsageUnapplyingOnAfterPostAdvancePaymentApplication( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, + AdvancePostingParametersCZZ, GLEntryNo, GenJnlPostLine, GenJournalLine); + end; + + VendorLedgerEntry.FindLast(); + + TempPurchAdvLetterEntryCZZGlob.InitNewEntry(); + TempPurchAdvLetterEntryCZZGlob.InitVendorLedgerEntry(VendorLedgerEntry); + TempPurchAdvLetterEntryCZZGlob.InitRelatedEntry(PurchAdvLetterEntryCZZ); + TempPurchAdvLetterEntryCZZGlob.CopyFromGenJnlLine(GenJournalLine); + TempPurchAdvLetterEntryCZZGlob."Entry Type" := PurchAdvLetterEntryCZZ."Entry Type"; + TempPurchAdvLetterEntryCZZGlob."Purch. Adv. Letter No." := PurchAdvLetterHeaderCZZ."No."; + TempPurchAdvLetterEntryCZZGlob.Cancelled := true; + EntryNo := TempPurchAdvLetterEntryCZZGlob.InsertNewEntry(not AdvancePostingParametersCZZ."Temporary Entries Only"); + + InitGenJournalLine(VendorLedgerEntry, GenJournalLine); + GenJournalLine."Adv. Letter Template Code CZZ" := PurchAdvLetterHeaderCZZ."Advance Letter Code"; + GenJournalLine.Correction := true; + GenJournalLine.SetCurrencyFactor( + PurchAdvLetterEntryCZZ."Currency Code", PurchAdvLetterEntryCZZ."Currency Factor"); + GenJournalLine.Amount := PurchAdvLetterEntryCZZ.Amount; + GenJournalLine."Amount (LCY)" := PurchAdvLetterEntryCZZ."Amount (LCY)"; + if not AdvancePostingParametersCZZ."Temporary Entries Only" then begin + VendorLedgerEntryInv."Advance Letter No. CZZ" := ''; + VendorLedgerEntryInv.SetApplication('', ''); + GenJournalLine."Applies-to ID" := VendorLedgerEntryInv."Applies-to ID"; + OnPostAdvanceLetterEntryUsageUnapplyingOnBeforePostInvoiceApplication( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, + AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); + GLEntryNo := RunGenJnlPostLine(GenJournalLine, GenJnlPostLine, false, false, true); + OnPostAdvanceLetterEntryUsageUnapplyingOnAfterPostInvoiceApplication( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, + AdvancePostingParametersCZZ, GLEntryNo, GenJnlPostLine, GenJournalLine); + end; + + PurchAdvLetterHeaderCZZ.UpdateStatus(PurchAdvLetterHeaderCZZ.Status::"To Use"); + + OnAfterPostAdvanceLetterEntryUsageUnapplying( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, AdvancePostingBufferCZZ, + EntryNo, GenJnlPostLine, AdvancePostingParametersCZZ) + end; + + procedure PostAdvanceLetterClosing( + PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; + var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; + AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ") + var + AdvanceLetterApplicationCZZ: Record "Advance Letter Application CZZ"; + AdvanceLetterTemplateCZZ: Record "Advance Letter Template CZZ"; + PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; + NoSeriesBatch: Codeunit "No. Series - Batch"; + NextEntryNo: Integer; + IsHandled: Boolean; + begin + IsHandled := false; + OnBeforePostAdvanceLetterClosing(PurchAdvLetterHeaderCZZ, GenJnlPostLine, AdvancePostingParametersCZZ, IsHandled); + if IsHandled then + exit; + + if PurchAdvLetterHeaderCZZ.Status = PurchAdvLetterHeaderCZZ.Status::Closed then + exit; + + if PurchAdvLetterHeaderCZZ.Status = PurchAdvLetterHeaderCZZ.Status::New then begin + PurchAdvLetterHeaderCZZ.UpdateStatus(PurchAdvLetterHeaderCZZ.Status::Closed); + exit; + end; + + if AdvancePostingParametersCZZ."Document No." = '' then begin + AdvanceLetterTemplateCZZ.Get(PurchAdvLetterHeaderCZZ."Advance Letter Code"); + AdvanceLetterTemplateCZZ.TestField("Advance Letter Cr. Memo Nos."); + AdvancePostingParametersCZZ."Document No." := + NoSeriesBatch.GetNextNo( + AdvanceLetterTemplateCZZ."Advance Letter Cr. Memo Nos.", AdvancePostingParametersCZZ."Posting Date"); + NextEntryNo := GenJnlPostLine.GetNextEntryNo(); + end; + + PurchAdvLetterEntryCZZ.SetRange("Purch. Adv. Letter No.", PurchAdvLetterHeaderCZZ."No."); + PurchAdvLetterEntryCZZ.SetRange("Entry Type", PurchAdvLetterEntryCZZ."Entry Type"::Payment); + PurchAdvLetterEntryCZZ.SetRange(Cancelled, false); + if PurchAdvLetterEntryCZZ.FindSet() then + repeat + PostAdvanceLetterEntryClosing( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, GenJnlPostLine, AdvancePostingParametersCZZ); + until PurchAdvLetterEntryCZZ.Next() = 0; + + if (NextEntryNo <> 0) and (NextEntryNo <> GenJnlPostLine.GetNextEntryNo()) then + NoSeriesBatch.SaveState(); + + PurchAdvLetterManagementCZZ.CancelInitEntry(PurchAdvLetterHeaderCZZ, AdvancePostingParametersCZZ."Posting Date", false); + PurchAdvLetterHeaderCZZ.Get(PurchAdvLetterHeaderCZZ."No."); + PurchAdvLetterHeaderCZZ.UpdateStatus(PurchAdvLetterHeaderCZZ.Status::Closed); + + AdvanceLetterApplicationCZZ.SetRange("Advance Letter Type", AdvanceLetterApplicationCZZ."Advance Letter Type"::Purchase); + AdvanceLetterApplicationCZZ.SetRange("Advance Letter No.", PurchAdvLetterHeaderCZZ."No."); + AdvanceLetterApplicationCZZ.DeleteAll(true); + + OnAfterPostAdvanceLetterClosing(PurchAdvLetterHeaderCZZ, GenJnlPostLine, AdvancePostingParametersCZZ) + end; + + local procedure PostAdvanceLetterEntryClosing( + PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; + PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; + var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; + AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ") + var + AdvancePostingParametersCZZ2: Record "Advance Posting Parameters CZZ"; + GenJournalLine: Record "Gen. Journal Line"; + TempAdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ" temporary; + VendorLedgerEntry: Record "Vendor Ledger Entry"; + VendorLedgerEntry2: Record "Vendor Ledger Entry"; + RemainingAmount, RemainingAmountLCY : Decimal; + EntryNo, GLEntryNo : Integer; + IsHandled: Boolean; + begin + IsHandled := false; + OnBeforePostAdvanceLetterEntryClosing(PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, GenJnlPostLine, AdvancePostingParametersCZZ, IsHandled); + if IsHandled then + exit; + + if PurchAdvLetterEntryCZZ."Entry Type" <> PurchAdvLetterEntryCZZ."Entry Type"::Payment then + exit; + + RemainingAmount := PurchAdvLetterEntryCZZ.GetRemainingAmount(); + RemainingAmountLCY := PurchAdvLetterEntryCZZ.GetRemainingAmountLCY(); + + VendorLedgerEntry.Get(PurchAdvLetterEntryCZZ."Vendor Ledger Entry No."); + if RemainingAmount <> 0 then begin + InitGenJournalLine(VendorLedgerEntry, GenJournalLine); + GenJournalLine."Adv. Letter Template Code CZZ" := PurchAdvLetterHeaderCZZ."Advance Letter Code"; + GenJournalLine.Correction := true; + GenJournalLine."Document Type" := AdvancePostingParametersCZZ."Document Type"; + GenJournalLine."Document No." := AdvancePostingParametersCZZ."Document No."; + GenJournalLine."External Document No." := AdvancePostingParametersCZZ."External Document No."; + GenJournalLine."Posting Date" := AdvancePostingParametersCZZ."Posting Date"; + GenJournalLine."Document Date" := AdvancePostingParametersCZZ."Document Date"; +#if not CLEAN22 +#pragma warning disable AL0432 + GenJournalLine."VAT Date CZL" := AdvancePostingParametersCZZ."VAT Date"; +#pragma warning restore AL0432 +#endif + GenJournalLine."VAT Reporting Date" := AdvancePostingParametersCZZ."VAT Date"; + GenJournalLine."Original Doc. VAT Date CZL" := AdvancePostingParametersCZZ."Original Document VAT Date"; + GenJournalLine."Adv. Letter No. (Entry) CZZ" := PurchAdvLetterEntryCZZ."Purch. Adv. Letter No."; + GenJournalLine."Use Advance G/L Account CZZ" := true; + GenJournalLine.SetCurrencyFactor( + AdvancePostingParametersCZZ."Currency Code", AdvancePostingParametersCZZ."Currency Factor"); + GenJournalLine.Amount := -RemainingAmount; + GenJournalLine."Amount (LCY)" := -RemainingAmountLCY; + if not AdvancePostingParametersCZZ."Temporary Entries Only" then begin + VendorLedgerEntry.SetApplication('', PurchAdvLetterEntryCZZ."Purch. Adv. Letter No."); + GenJournalLine."Applies-to ID" := VendorLedgerEntry."Applies-to ID"; + OnPostAdvanceLetterEntryClosingOnBeforePost( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, VendorLedgerEntry, + AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); +#if not CLEAN24 + RaiseOnBeforePostClosePayment(GenJournalLine, PurchAdvLetterHeaderCZZ); +#endif + GLEntryNo := RunGenJnlPostLine(GenJournalLine, GenJnlPostLine, false, false, false); + OnPostAdvanceLetterEntryClosingOnAfterPost( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, VendorLedgerEntry, + AdvancePostingParametersCZZ, GLEntryNo, GenJnlPostLine, GenJournalLine); +#if not CLEAN24 + RaiseOnAfterPostClosePayment(GenJournalLine, PurchAdvLetterHeaderCZZ); +#endif + end; + + VendorLedgerEntry2.FindLast(); + + TempPurchAdvLetterEntryCZZGlob.InitNewEntry(); + TempPurchAdvLetterEntryCZZGlob.InitVendorLedgerEntry(VendorLedgerEntry2); + TempPurchAdvLetterEntryCZZGlob.InitRelatedEntry(PurchAdvLetterEntryCZZ); + TempPurchAdvLetterEntryCZZGlob.CopyFromGenJnlLine(GenJournalLine); + TempPurchAdvLetterEntryCZZGlob."Entry Type" := "Advance Letter Entry Type CZZ"::Close; + TempPurchAdvLetterEntryCZZGlob."Purch. Adv. Letter No." := PurchAdvLetterHeaderCZZ."No."; + EntryNo := TempPurchAdvLetterEntryCZZGlob.InsertNewEntry(not AdvancePostingParametersCZZ."Temporary Entries Only"); + end; + + AdvancePostingParametersCZZ2.InitNew(AdvancePostingParametersCZZ); + AdvancePostingParametersCZZ2."Document Type" := "Gen. Journal Document Type"::"Credit Memo"; + + BufferAdvanceVATLines(PurchAdvLetterEntryCZZ, TempAdvancePostingBufferCZZ, 0D); + SuggestUsageVAT(PurchAdvLetterEntryCZZ, TempAdvancePostingBufferCZZ, VendorLedgerEntry."Document No.", + 0, AdvancePostingParametersCZZ."Currency Factor", AdvancePostingParametersCZZ2."Temporary Entries Only"); + + ReverseAdvancePaymentVAT(PurchAdvLetterEntryCZZ, TempAdvancePostingBufferCZZ, EntryNo, + "Advance Letter Entry Type CZZ"::"VAT Close", GenJnlPostLine, AdvancePostingParametersCZZ2); + + if RemainingAmount <> 0 then begin + InitGenJournalLine(VendorLedgerEntry, GenJournalLine); + GenJournalLine."Document Type" := GenJournalLine."Document Type"::Payment; + GenJournalLine.Correction := true; + GenJournalLine."Document No." := AdvancePostingParametersCZZ."Document No."; + GenJournalLine."External Document No." := AdvancePostingParametersCZZ."External Document No."; + GenJournalLine."Posting Date" := AdvancePostingParametersCZZ."Posting Date"; + GenJournalLine."Document Date" := AdvancePostingParametersCZZ."Document Date"; +#if not CLEAN22 +#pragma warning disable AL0432 + GenJournalLine."VAT Date CZL" := AdvancePostingParametersCZZ."VAT Date"; +#pragma warning restore AL0432 +#endif + GenJournalLine."VAT Reporting Date" := AdvancePostingParametersCZZ."VAT Date"; + GenJournalLine."Original Doc. VAT Date CZL" := AdvancePostingParametersCZZ."Original Document VAT Date"; + GenJournalLine.SetCurrencyFactor( + AdvancePostingParametersCZZ."Currency Code", AdvancePostingParametersCZZ."Currency Factor"); + GenJournalLine.Amount := RemainingAmount; + GenJournalLine."Amount (LCY)" := RemainingAmountLCY; + GenJournalLine."Variable Symbol CZL" := PurchAdvLetterHeaderCZZ."Variable Symbol"; + if not AdvancePostingParametersCZZ."Temporary Entries Only" then begin + OnPostAdvanceLetterEntryClosingOnBeforePostBalance( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, VendorLedgerEntry, + AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); +#if not CLEAN24 + RaiseOnBeforePostClosePaymentRepos(GenJournalLine, PurchAdvLetterHeaderCZZ); +#endif + GLEntryNo := RunGenJnlPostLine(GenJournalLine, GenJnlPostLine, false, false, false); + OnPostAdvanceLetterEntryClosingOnAfterPostBalance( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, VendorLedgerEntry, + AdvancePostingParametersCZZ, GLEntryNo, GenJnlPostLine, GenJournalLine); +#if not CLEAN24 + RaiseOnAfterPostClosePaymentRepos(GenJournalLine, PurchAdvLetterHeaderCZZ); +#endif + end; + end; + + OnAfterPostAdvanceLetterEntryClosing( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, GenJnlPostLine, AdvancePostingParametersCZZ); + end; + + local procedure ReverseAdvancePayment( + PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; + PurchInvHeader: Record "Purch. Inv. Header"; + ReverseAmount: Decimal; + ReverseAmountLCY: Decimal; + var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; + AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ") + var + AdvancePostingParametersCZZ2: Record "Advance Posting Parameters CZZ"; + GenJournalLine: Record "Gen. Journal Line"; + PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; + TempAdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ" temporary; + VendorLedgerEntry: Record "Vendor Ledger Entry"; + VendorLedgerEntry2: Record "Vendor Ledger Entry"; + EntryNo, GLEntryNo : Integer; + IsHandled: Boolean; + begin + IsHandled := false; + OnBeforeReverseAdvancePayment( + PurchAdvLetterEntryCZZ, PurchInvHeader, ReverseAmount, ReverseAmountLCY, + GenJnlPostLine, AdvancePostingParametersCZZ, IsHandled); + if IsHandled then + exit; + + if ReverseAmount <> 0 then begin + if ReverseAmount > PurchAdvLetterEntryCZZ.Amount then + Error(ReverseAmountErr, ReverseAmount, PurchAdvLetterEntryCZZ."Entry No."); + end else begin + ReverseAmount := PurchAdvLetterEntryCZZ.Amount; + ReverseAmountLCY := PurchAdvLetterEntryCZZ."Amount (LCY)"; + end; + + if not AdvancePostingParametersCZZ."Temporary Entries Only" then + VendorLedgerEntry.Get(PurchInvHeader."Vendor Ledger Entry No.") + else + InitVendorLedgerEntryFromPurchInvHeader(PurchInvHeader, VendorLedgerEntry); + + PurchAdvLetterHeaderCZZ.Get(PurchAdvLetterEntryCZZ."Purch. Adv. Letter No."); + + // Post invoice application + InitGenJournalLine(VendorLedgerEntry, GenJournalLine); + GenJournalLine."Adv. Letter Template Code CZZ" := PurchAdvLetterHeaderCZZ."Advance Letter Code"; + GenJournalLine.Correction := true; + GenJournalLine.Amount := ReverseAmount; + GenJournalLine."Amount (LCY)" := ReverseAmountLCY; + if not AdvancePostingParametersCZZ."Temporary Entries Only" then begin + VendorLedgerEntry.SetApplication(PurchAdvLetterHeaderCZZ."Advance Letter Code", ''); + GenJournalLine."Applies-to ID" := VendorLedgerEntry."Applies-to ID"; + + OnReverseAdvancePaymentOnBeforePostInvoiceApplication( + PurchAdvLetterHeaderCZZ, VendorLedgerEntry, AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); +#if not CLEAN24 + RaiseOnBeforePostReversePaymentRepos(GenJournalLine, PurchAdvLetterHeaderCZZ); +#endif + GLEntryNo := RunGenJnlPostLine(GenJournalLine, GenJnlPostLine, false, false, true); + OnReverseAdvancePaymentOnAfterPostInvoiceApplication(PurchAdvLetterHeaderCZZ, VendorLedgerEntry, + AdvancePostingParametersCZZ, GLEntryNo, GenJnlPostLine, GenJournalLine); +#if not CLEAN24 + RaiseOnAfterPostReversePaymentRepos(GenJournalLine, PurchAdvLetterHeaderCZZ); +#endif + end; + + // Post advance payment usage + InitGenJournalLine(VendorLedgerEntry, GenJournalLine); + GenJournalLine."Document Type" := GenJournalLine."Document Type"::Invoice; + GenJournalLine."Adv. Letter Template Code CZZ" := PurchAdvLetterHeaderCZZ."Advance Letter Code"; + GenJournalLine."Adv. Letter No. (Entry) CZZ" := PurchAdvLetterEntryCZZ."Purch. Adv. Letter No."; + GenJournalLine."Use Advance G/L Account CZZ" := true; + GenJournalLine.Amount := -ReverseAmount; + GenJournalLine."Amount (LCY)" := -ReverseAmountLCY; + + VendorLedgerEntry2.Get(PurchAdvLetterEntryCZZ."Vendor Ledger Entry No."); + if not AdvancePostingParametersCZZ."Temporary Entries Only" then begin + VendorLedgerEntry2.SetApplication('', PurchAdvLetterEntryCZZ."Purch. Adv. Letter No."); + GenJournalLine."Applies-to ID" := VendorLedgerEntry2."Applies-to ID"; + + OnReverseAdvancePaymentOnBeforePostAdvancePaymentUsage( + PurchAdvLetterHeaderCZZ, VendorLedgerEntry, AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); +#if not CLEAN24 + RaiseOnBeforePostReversePayment(GenJournalLine, PurchAdvLetterHeaderCZZ); +#endif + GLEntryNo := RunGenJnlPostLine(GenJournalLine, GenJnlPostLine, false, true, true); + OnReverseAdvancePaymentOnAfterPostAdvancePaymentUsage(PurchAdvLetterHeaderCZZ, VendorLedgerEntry, + AdvancePostingParametersCZZ, GLEntryNo, GenJnlPostLine, GenJournalLine); +#if not CLEAN24 + RaiseOnAfterPostReversePayment(GenJournalLine, PurchAdvLetterHeaderCZZ); +#endif + + VendorLedgerEntry2.FindLast(); + end; + + TempPurchAdvLetterEntryCZZGlob.InitNewEntry(); + TempPurchAdvLetterEntryCZZGlob.InitVendorLedgerEntry(VendorLedgerEntry2); + TempPurchAdvLetterEntryCZZGlob.InitRelatedEntry(PurchAdvLetterEntryCZZ); + TempPurchAdvLetterEntryCZZGlob.CopyFromGenJnlLine(GenJournalLine); + TempPurchAdvLetterEntryCZZGlob."Entry Type" := "Advance Letter Entry Type CZZ"::Usage; + TempPurchAdvLetterEntryCZZGlob."Purch. Adv. Letter No." := PurchAdvLetterHeaderCZZ."No."; + EntryNo := TempPurchAdvLetterEntryCZZGlob.InsertNewEntry(not AdvancePostingParametersCZZ."Temporary Entries Only"); + + if PurchAdvLetterHeaderCZZ."Automatic Post VAT Usage" then begin + Clear(AdvancePostingParametersCZZ2); + AdvancePostingParametersCZZ2.CopyFromVendorLedgerEntry(VendorLedgerEntry); + AdvancePostingParametersCZZ2."Document Type" := "Gen. Journal Document Type"::Invoice; + if PurchInvHeader."Original Doc. VAT Date CZL" <> 0D then + AdvancePostingParametersCZZ2."Original Document VAT Date" := PurchInvHeader."Original Doc. VAT Date CZL"; + AdvancePostingParametersCZZ2."Currency Code" := PurchAdvLetterEntryCZZ."Currency Code"; + AdvancePostingParametersCZZ2."Currency Factor" := PurchInvHeader."VAT Currency Factor CZL"; + AdvancePostingParametersCZZ2."Temporary Entries Only" := AdvancePostingParametersCZZ."Temporary Entries Only"; + + BufferAdvanceVATLines(PurchAdvLetterEntryCZZ, TempAdvancePostingBufferCZZ, 0D); + SuggestUsageVAT(PurchAdvLetterEntryCZZ, TempAdvancePostingBufferCZZ, VendorLedgerEntry."Document No.", + ReverseAmount, PurchInvHeader."VAT Currency Factor CZL", AdvancePostingParametersCZZ2."Temporary Entries Only"); + + ReverseAdvancePaymentVAT(PurchAdvLetterEntryCZZ, TempAdvancePostingBufferCZZ, EntryNo, + "Advance Letter Entry Type CZZ"::"VAT Usage", GenJnlPostLine, AdvancePostingParametersCZZ2); + end; + + if not AdvancePostingParametersCZZ."Temporary Entries Only" then begin + PurchAdvLetterHeaderCZZ.Get(PurchAdvLetterEntryCZZ."Purch. Adv. Letter No."); + PurchAdvLetterHeaderCZZ.UpdateStatus(PurchAdvLetterHeaderCZZ.Status::Closed); + end; + + OnAfterReverseAdvancePayment( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, + PurchInvHeader, EntryNo, GenJnlPostLine, AdvancePostingParametersCZZ); + end; + + local procedure ReverseAdvancePaymentVAT( + var PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; + var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; + RelatedEntryNo: Integer; + EntryType: Enum "Advance Letter Entry Type CZZ"; + var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; + 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"; + VATPostingSetup: Record "VAT Posting Setup"; + PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; + CalcVATAmountLCY, CalcAmountLCY, ExchRateAmount, ExchRateVATAmount, AmountToUse : Decimal; + GLEntryNo: Integer; + IsHandled: Boolean; + begin + IsHandled := false; + OnBeforeReverseAdvancePaymentVAT( + PurchAdvLetterEntryCZZ, AdvancePostingBufferCZZ, RelatedEntryNo, GenJnlPostLine, AdvancePostingParametersCZZ, IsHandled); +#if not CLEAN24 + RaiseOnBeforePostReversePaymentVAT( + PurchAdvLetterEntryCZZ, AdvancePostingParametersCZZ."Posting Date", AdvancePostingParametersCZZ."Temporary Entries Only", IsHandled); +#endif + if IsHandled then + exit; + + 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 + exit; + + AdvancePostingBufferCZZ.FilterGroup(-1); + AdvancePostingBufferCZZ.SetFilter("VAT Base Amount", '<>0'); + AdvancePostingBufferCZZ.SetFilter("VAT Amount", '<>0'); + AdvancePostingBufferCZZ.FilterGroup(0); + if AdvancePostingBufferCZZ.IsEmpty() then + exit; + + PurchAdvLetterHeaderCZZ.Get(PurchAdvLetterEntryCZZ."Purch. Adv. Letter No."); + + if PurchAdvLetterEntryCZZ."Currency Code" <> '' then begin + BufferAdvanceVATLines(PurchAdvLetterEntryCZZ, TempAdvancePostingBufferCZZ, 0D); + TempAdvancePostingBufferCZZ.CalcSums(Amount); + AmountToUse := TempAdvancePostingBufferCZZ.Amount; + end; + + CalculateVATAmountInBuffer( + AdvancePostingParametersCZZ."Posting Date", AdvancePostingParametersCZZ."Currency Code", + AdvancePostingParametersCZZ."Currency Factor", AdvancePostingBufferCZZ); + + AdvancePostingBufferCZZ.FindSet(); + repeat + VATPostingSetup.Get(AdvancePostingBufferCZZ."VAT Bus. Posting Group", AdvancePostingBufferCZZ."VAT Prod. Posting Group"); + + // Post reverse advance payment VAT + 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 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 + OnReverseAdvancePaymentVATOnBeforePost( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, VATPostingSetup, + AdvancePostingBufferCZZ, AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); + GLEntryNo := RunGenJnlPostLine(GenJournalLine, GenJnlPostLine, true, true, false); + OnReverseAdvancePaymentVATOnAfterPost( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, VATPostingSetup, AdvancePostingBufferCZZ, + AdvancePostingParametersCZZ, GLEntryNo, GenJnlPostLine, GenJournalLine); + end; + + if AdvancePostingBufferCZZ."VAT Calculation Type" = AdvancePostingBufferCZZ."VAT Calculation Type"::"Reverse Charge VAT" then begin + GenJournalLine."VAT Amount" := 0; + GenJournalLine."VAT Amount (LCY)" := 0; + end; + + TempPurchAdvLetterEntryCZZGlob.InitNewEntry(); + TempPurchAdvLetterEntryCZZGlob.InitRelatedEntry(RelatedEntryNo); + TempPurchAdvLetterEntryCZZGlob.CopyFromGenJnlLine(GenJournalLine); + TempPurchAdvLetterEntryCZZGlob."Entry Type" := EntryType; + 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"); + + AdvancePostingBufferCZZ.ReverseAmounts(); + if GenJournalLine."Currency Code" <> '' then + if TempAdvancePostingBufferCZZ.Get( + AdvancePostingBufferCZZ."VAT Bus. Posting Group", + AdvancePostingBufferCZZ."VAT Prod. Posting Group") + then begin + AdvancePostingParametersCZZ2.InitNew(AdvancePostingParametersCZZ); + AdvancePostingParametersCZZ2."Document Type" := "Gen. Journal Document Type"::" "; + AdvancePostingParametersCZZ2."External Document No." := ''; + AdvancePostingParametersCZZ2."Currency Code" := ''; + AdvancePostingParametersCZZ2."Currency Factor" := 0; + + CalcAmountLCY := Round(TempAdvancePostingBufferCZZ."Amount (ACY)" * AdvancePostingBufferCZZ.Amount / TempAdvancePostingBufferCZZ.Amount); + CalcVATAmountLCY := Round(TempAdvancePostingBufferCZZ."VAT Amount (ACY)" * AdvancePostingBufferCZZ.Amount / TempAdvancePostingBufferCZZ.Amount); + + ExchRateAmount := CalcAmountLCY + GenJournalLine."Amount (LCY)"; + ExchRateVATAmount := CalcVATAmountLCY + GenJournalLine."VAT Amount (LCY)"; + if (ExchRateAmount <> 0) or (ExchRateVATAmount <> 0) then + PostExchangeRate(PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, VATPostingSetup, -ExchRateAmount, -ExchRateVATAmount, + RelatedEntryNo, false, GenJnlPostLine, AdvancePostingParametersCZZ2); + + AdvancePostingParametersCZZ2."Source Code" := ''; + ReverseUnrealizedExchangeRate( + PurchAdvLetterEntryCZZ, PurchAdvLetterHeaderCZZ, VATPostingSetup, AdvancePostingBufferCZZ.Amount / AmountToUse, + RelatedEntryNo, GenJnlPostLine, AdvancePostingParametersCZZ2); + end; + + // Post balance of reverse advance payment VAT + AdvancePostingParametersCZZ2.InitNew(AdvancePostingParametersCZZ); + AdvancePostingParametersCZZ2."Document Type" := "Gen. Journal Document Type"::" "; + InitGenJournalLine(PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, AdvancePostingParametersCZZ2, GenJournalLine); + GenJournalLine."Account No." := VATPostingSetup.GetPurchAdvLetterAccountCZZ(); + GenJournalLine.CopyFromAdvancePostingBufferAmountsCZZ(AdvancePostingBufferCZZ); + if not AdvancePostingParametersCZZ."Temporary Entries Only" then begin + OnReverseAdvancePaymentVATOnBeforePostBalance( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, VATPostingSetup, + AdvancePostingBufferCZZ, AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); + GLEntryNo := RunGenJnlPostLine(GenJournalLine, GenJnlPostLine, false, false, false); + OnReverseAdvancePaymentVATOnAfterPostBalance( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, VATPostingSetup, AdvancePostingBufferCZZ, + AdvancePostingParametersCZZ, GLEntryNo, GenJnlPostLine, GenJournalLine); + end; + until AdvancePostingBufferCZZ.Next() = 0; + + if not AdvancePostingParametersCZZ."Temporary Entries Only" then + PurchAdvLetterHeaderCZZ.UpdateStatus(PurchAdvLetterHeaderCZZ.Status::Closed); + + OnAfterReverseAdvancePaymentVAT(PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, + AdvancePostingBufferCZZ, GenJnlPostLine, AdvancePostingParametersCZZ); + end; + + local procedure ReverseUnrealizedExchangeRate( + PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; + PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; + VATPostingSetup: Record "VAT Posting Setup"; + Coef: Decimal; + RelatedEntryNo: Integer; + var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; + AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ") + var + AmountLCY, VATAmountLCY : Decimal; + IsHandled: Boolean; + begin + IsHandled := false; + OnBeforeReverseUnrealizedExchangeRate( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, VATPostingSetup, Coef, + RelatedEntryNo, GenJnlPostLine, AdvancePostingParametersCZZ, IsHandled); + if IsHandled then + exit; + + if PurchAdvLetterEntryCZZ."Entry Type" <> PurchAdvLetterEntryCZZ."Entry Type"::Payment then + exit; + + PurchAdvLetterManagementCZZ.GetRemAmtLCYVATAdjust( + AmountLCY, VATAmountLCY, PurchAdvLetterEntryCZZ, AdvancePostingParametersCZZ."Posting Date", + VATPostingSetup."VAT Bus. Posting Group", VATPostingSetup."VAT Prod. Posting Group"); + if (AmountLCY = 0) and (VATAmountLCY = 0) then + exit; + + AmountLCY := Round(AmountLCY * Coef); + VATAmountLCY := Round(VATAmountLCY * Coef); + + PostUnrealizedExchangeRate( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, VATPostingSetup, -AmountLCY, -VATAmountLCY, + RelatedEntryNo, 0, false, GenJnlPostLine, AdvancePostingParametersCZZ); + end; + + internal procedure PostExchangeRate( + PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; + PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; + VATPostingSetup: Record "VAT Posting Setup"; + Amount: Decimal; + VATAmount: Decimal; + RelatedEntryNo: Integer; + Correction: Boolean; + var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; + AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ") + var + GenJournalLine: Record "Gen. Journal Line"; + EntryNo, GLEntryNo : Integer; + IsHandled: Boolean; + begin + IsHandled := false; + OnBeforePostExchangeRate( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, VATPostingSetup, Amount, VATAmount, + RelatedEntryNo, Correction, GenJnlPostLine, AdvancePostingParametersCZZ, IsHandled); + if IsHandled then + exit; + + if (Amount = 0) and (VATAmount = 0) then + exit; + + if VATAmount <> 0 then begin + GetCurrency(PurchAdvLetterHeaderCZZ."Currency Code"); + + // Post exchange rate of VAT Base + InitGenJournalLine(PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, AdvancePostingParametersCZZ, GenJournalLine); + GenJournalLine.Correction := Correction; + GenJournalLine."Account No." := VATPostingSetup.GetPurchAdvLetterAccountCZZ(); + GenJournalLine.Validate(Amount, Amount - VATAmount); + if not AdvancePostingParametersCZZ."Temporary Entries Only" then begin + OnPostExchangeRateOnBeforePostVATBase( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, VATPostingSetup, Amount, VATAmount, + AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); + GLEntryNo := RunGenJnlPostLine(GenJournalLine, GenJnlPostLine, false, false, false); + OnPostExchangeRateOnAfterPostVATBase( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, VATPostingSetup, Amount, VATAmount, + AdvancePostingParametersCZZ, GLEntryNo, GenJnlPostLine, GenJournalLine); + end; + + // Post exchange rate of VAT Amount + InitGenJournalLine(PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, AdvancePostingParametersCZZ, GenJournalLine); + GenJournalLine.Correction := true; + if VATAmount < 0 then + GenJournalLine."Account No." := CurrencyGlob.GetRealizedLossesAccount() + else + GenJournalLine."Account No." := CurrencyGlob.GetRealizedGainsAccount(); + GenJournalLine.Validate(Amount, VATAmount); + if not AdvancePostingParametersCZZ."Temporary Entries Only" then begin + OnPostExchangeRateOnBeforePostVATAmount( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, VATPostingSetup, Amount, VATAmount, + AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); + GLEntryNo := RunGenJnlPostLine(GenJournalLine, GenJnlPostLine, false, false, false); + OnPostExchangeRateOnAfterPostVATAmount( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, VATPostingSetup, Amount, VATAmount, + AdvancePostingParametersCZZ, GLEntryNo, GenJnlPostLine, GenJournalLine); + end; + + // Post balance of exchange rate + InitGenJournalLine(PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, AdvancePostingParametersCZZ, GenJournalLine); + GenJournalLine.Correction := Correction; + GenJournalLine."Account No." := VATPostingSetup.GetPurchAdvLetterAccountCZZ(); + GenJournalLine.Validate(Amount, -Amount); + if not AdvancePostingParametersCZZ."Temporary Entries Only" then begin + OnPostExchangeRateOnBeforePostBalance( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, VATPostingSetup, Amount, VATAmount, + AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); + GLEntryNo := RunGenJnlPostLine(GenJournalLine, GenJnlPostLine, false, false, false); + OnPostExchangeRateOnAfterPostBalance( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, VATPostingSetup, Amount, VATAmount, + AdvancePostingParametersCZZ, GLEntryNo, GenJnlPostLine, GenJournalLine); + end; + end; + + TempPurchAdvLetterEntryCZZGlob.InitNewEntry(); + TempPurchAdvLetterEntryCZZGlob.InitRelatedEntry(RelatedEntryNo); + TempPurchAdvLetterEntryCZZGlob.CopyFromVATPostingSetup(VATPostingSetup); + TempPurchAdvLetterEntryCZZGlob."Entry Type" := "Advance Letter Entry Type CZZ"::"VAT Rate"; + TempPurchAdvLetterEntryCZZGlob."Purch. Adv. Letter No." := PurchAdvLetterHeaderCZZ."No."; + TempPurchAdvLetterEntryCZZGlob."Document No." := AdvancePostingParametersCZZ."Document No."; + TempPurchAdvLetterEntryCZZGlob."External Document No." := AdvancePostingParametersCZZ."External Document No."; + TempPurchAdvLetterEntryCZZGlob."Posting Date" := AdvancePostingParametersCZZ."Posting Date"; + TempPurchAdvLetterEntryCZZGlob."VAT Date" := AdvancePostingParametersCZZ."VAT Date"; + TempPurchAdvLetterEntryCZZGlob."Original Document VAT Date" := AdvancePostingParametersCZZ."Original Document VAT Date"; + TempPurchAdvLetterEntryCZZGlob."Amount (LCY)" := Amount; + TempPurchAdvLetterEntryCZZGlob."VAT Amount (LCY)" := VATAmount; + TempPurchAdvLetterEntryCZZGlob."VAT Base Amount (LCY)" := Amount - VATAmount; + TempPurchAdvLetterEntryCZZGlob."Global Dimension 1 Code" := PurchAdvLetterEntryCZZ."Global Dimension 1 Code"; + TempPurchAdvLetterEntryCZZGlob."Global Dimension 2 Code" := PurchAdvLetterEntryCZZ."Global Dimension 2 Code"; + TempPurchAdvLetterEntryCZZGlob."Dimension Set ID" := PurchAdvLetterEntryCZZ."Dimension Set ID"; + TempPurchAdvLetterEntryCZZGlob.Cancelled := Correction; + OnPostExchangeRateOnBeforeInsertEntry( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, VATPostingSetup, + AdvancePostingParametersCZZ, TempPurchAdvLetterEntryCZZGlob); + EntryNo := TempPurchAdvLetterEntryCZZGlob.InsertNewEntry(not AdvancePostingParametersCZZ."Temporary Entries Only"); + + OnAfterPostExchangeRate( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, VATPostingSetup, + EntryNo, GenJnlPostLine, AdvancePostingParametersCZZ, TempPurchAdvLetterEntryCZZGlob); + end; + + internal procedure PostUnrealizedExchangeRate( + PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; + PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; + VATPostingSetup: Record "VAT Posting Setup"; + Amount: Decimal; + VATAmount: Decimal; + RelatedEntryNo: Integer; + RelatedDetEntryNo: Integer; + Correction: Boolean; + var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; + AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ") + var + GenJournalLine: Record "Gen. Journal Line"; + SourceCodeSetup: Record "Source Code Setup"; + EntryNo, GLEntryNo : Integer; + IsHandled: Boolean; + begin + IsHandled := false; + OnBeforePostUnrealizedExchangeRate( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, VATPostingSetup, Amount, VATAmount, + RelatedEntryNo, RelatedDetEntryNo, Correction, GenJnlPostLine, AdvancePostingParametersCZZ, IsHandled); + if IsHandled then + exit; + + if AdvancePostingParametersCZZ."Source Code" = '' then begin + SourceCodeSetup.Get(); + AdvancePostingParametersCZZ."Source Code" := SourceCodeSetup."Exchange Rate Adjmt."; + end; + + if VATAmount <> 0 then begin + GetCurrency(PurchAdvLetterHeaderCZZ."Currency Code"); + + // Post unrealized exchange rate + InitGenJournalLine(PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, AdvancePostingParametersCZZ, GenJournalLine); + if VATAmount > 0 then + GenJournalLine."Account No." := CurrencyGlob.GetUnrealizedLossesAccount() + else + GenJournalLine."Account No." := CurrencyGlob.GetUnrealizedGainsAccount(); + GenJournalLine.Validate(Amount, VATAmount); + if not AdvancePostingParametersCZZ."Temporary Entries Only" then begin + OnPostUnrealizedExchangeRateOnBeforePost( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, VATPostingSetup, Amount, VATAmount, + AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); + GLEntryNo := RunGenJnlPostLine(GenJournalLine, GenJnlPostLine, false, false, false); + OnPostUnrealizedExchangeRateOnAfterPost( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, VATPostingSetup, Amount, VATAmount, + AdvancePostingParametersCZZ, GLEntryNo, GenJnlPostLine, GenJournalLine); + end; + + // Post unrealized exchange rate balance + InitGenJournalLine(PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, AdvancePostingParametersCZZ, GenJournalLine); + GenJournalLine."Account No." := VATPostingSetup.GetPurchAdvLetterAccountCZZ(); + GenJournalLine.Validate(Amount, -VATAmount); + if not AdvancePostingParametersCZZ."Temporary Entries Only" then begin + OnPostUnrealizedExchangeRateOnBeforePostBalance( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, VATPostingSetup, Amount, VATAmount, + AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); + GLEntryNo := RunGenJnlPostLine(GenJournalLine, GenJnlPostLine, false, false, false); + OnPostUnrealizedExchangeRateOnAfterPostBalance( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, VATPostingSetup, Amount, VATAmount, + AdvancePostingParametersCZZ, GLEntryNo, GenJnlPostLine, GenJournalLine); + end; + end; + + TempPurchAdvLetterEntryCZZGlob.InitNewEntry(); + TempPurchAdvLetterEntryCZZGlob.InitRelatedEntry(RelatedEntryNo); + TempPurchAdvLetterEntryCZZGlob.InitDetailedVendorLedgerEntry(RelatedDetEntryNo); + TempPurchAdvLetterEntryCZZGlob.CopyFromVATPostingSetup(VATPostingSetup); + TempPurchAdvLetterEntryCZZGlob."Entry Type" := "Advance Letter Entry Type CZZ"::"VAT Adjustment"; + TempPurchAdvLetterEntryCZZGlob."Purch. Adv. Letter No." := PurchAdvLetterHeaderCZZ."No."; + TempPurchAdvLetterEntryCZZGlob."Document No." := AdvancePostingParametersCZZ."Document No."; + TempPurchAdvLetterEntryCZZGlob."External Document No." := AdvancePostingParametersCZZ."External Document No."; + TempPurchAdvLetterEntryCZZGlob."Posting Date" := AdvancePostingParametersCZZ."Posting Date"; + TempPurchAdvLetterEntryCZZGlob."VAT Date" := AdvancePostingParametersCZZ."VAT Date"; + TempPurchAdvLetterEntryCZZGlob."Original Document VAT Date" := AdvancePostingParametersCZZ."Original Document VAT Date"; + TempPurchAdvLetterEntryCZZGlob."Amount (LCY)" := Amount; + TempPurchAdvLetterEntryCZZGlob."VAT Amount (LCY)" := VATAmount; + TempPurchAdvLetterEntryCZZGlob."VAT Base Amount (LCY)" := Amount - VATAmount; + TempPurchAdvLetterEntryCZZGlob."Global Dimension 1 Code" := PurchAdvLetterEntryCZZ."Global Dimension 1 Code"; + TempPurchAdvLetterEntryCZZGlob."Global Dimension 2 Code" := PurchAdvLetterEntryCZZ."Global Dimension 2 Code"; + TempPurchAdvLetterEntryCZZGlob."Dimension Set ID" := PurchAdvLetterEntryCZZ."Dimension Set ID"; + TempPurchAdvLetterEntryCZZGlob.Cancelled := Correction; + OnPostUnrealizedExchangeRateOnBeforeInsertEntry( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, VATPostingSetup, + AdvancePostingParametersCZZ, TempPurchAdvLetterEntryCZZGlob); + EntryNo := TempPurchAdvLetterEntryCZZGlob.InsertNewEntry(not AdvancePostingParametersCZZ."Temporary Entries Only"); + + OnAfterPostUnrealizedExchangeRate( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, VATPostingSetup, + EntryNo, GenJnlPostLine, AdvancePostingParametersCZZ, TempPurchAdvLetterEntryCZZGlob); + end; + + internal procedure BufferAdvanceVATLines( + var PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; + var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; + BalanceAtDate: Date) + begin + BufferAdvanceVATLines(PurchAdvLetterEntryCZZ, AdvancePostingBufferCZZ, BalanceAtDate, true); + end; + + local procedure BufferAdvanceVATLines( + var PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; + var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; + BalanceAtDate: Date; + ResetBuffer: Boolean) + var + PurchAdvLetterEntryCZZ2: Record "Purch. Adv. Letter Entry CZZ"; + TempAdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ" temporary; + begin + if ResetBuffer then begin + AdvancePostingBufferCZZ.Reset(); + AdvancePostingBufferCZZ.DeleteAll(); + end; + + PurchAdvLetterEntryCZZ2.SetRange("Purch. Adv. Letter No.", PurchAdvLetterEntryCZZ."Purch. Adv. Letter No."); + PurchAdvLetterEntryCZZ2.SetRange(Cancelled, false); + PurchAdvLetterEntryCZZ2.SetRange("Related Entry", PurchAdvLetterEntryCZZ."Entry No."); + PurchAdvLetterEntryCZZ2.SetFilter("Entry Type", '<>%1', PurchAdvLetterEntryCZZ2."Entry Type"::"VAT Adjustment"); + if BalanceAtDate <> 0D then + PurchAdvLetterEntryCZZ2.SetFilter("Posting Date", '..%1', BalanceAtDate); + if PurchAdvLetterEntryCZZ2.FindSet() then + repeat + if PurchAdvLetterEntryCZZ2."Entry Type" in + [PurchAdvLetterEntryCZZ2."Entry Type"::Payment, + PurchAdvLetterEntryCZZ2."Entry Type"::Usage, + PurchAdvLetterEntryCZZ2."Entry Type"::Close] + then + BufferAdvanceVATLines(PurchAdvLetterEntryCZZ2, AdvancePostingBufferCZZ, BalanceAtDate, false) + else begin + TempAdvancePostingBufferCZZ.PrepareForPurchAdvLetterEntry(PurchAdvLetterentryCZZ2); + AdvancePostingBufferCZZ.Update(TempAdvancePostingBufferCZZ); + end; + until PurchAdvLetterEntryCZZ2.Next() = 0; + end; + + local procedure CalculateVATAmountInBuffer( + PostingDate: Date; + CurrencyCode: Code[10]; + CurrencyFactor: Decimal; + var TempAdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ" temporary) + var + VATPostingSetup: Record "VAT Posting Setup"; + CurrExchRate: Record "Currency Exchange Rate"; + VATAmount: Decimal; + VATAmountRemainder: Decimal; + IsHandled: Boolean; + begin + IsHandled := false; + OnBeforeCalculateVATAmountInBuffer(PostingDate, CurrencyCode, CurrencyFactor, TempAdvancePostingBufferCZZ, IsHandled); + if IsHandled then + exit; + + VATAmountRemainder := 0; + + GetCurrency(CurrencyCode); + + if TempAdvancePostingBufferCZZ.FindSet() then + repeat + if TempAdvancePostingBufferCZZ."VAT Calculation Type" = TempAdvancePostingBufferCZZ."VAT Calculation Type"::"Reverse Charge VAT" then begin + VATPostingSetup.Get(TempAdvancePostingBufferCZZ."VAT Bus. Posting Group", TempAdvancePostingBufferCZZ."VAT Prod. Posting Group"); + + VATAmount := TempAdvancePostingBufferCZZ."VAT Base Amount" * VATPostingSetup."VAT %" / 100; + + VATAmountRemainder += VATAmount; + TempAdvancePostingBufferCZZ."VAT Amount" := Round(VATAmountRemainder, CurrencyGlob."Amount Rounding Precision"); + TempAdvancePostingBufferCZZ."VAT Amount (ACY)" := TempAdvancePostingBufferCZZ."VAT Amount"; + VATAmountRemainder -= TempAdvancePostingBufferCZZ."VAT Amount"; + + if CurrencyCode <> '' then + TempAdvancePostingBufferCZZ."VAT Amount (ACY)" := + Round( + CurrExchRate.ExchangeAmtFCYToLCY( + PostingDate, CurrencyCode, TempAdvancePostingBufferCZZ."VAT Amount", CurrencyFactor)); + TempAdvancePostingBufferCZZ.Modify(); + end + until TempAdvancePostingBufferCZZ.Next() = 0; + end; + + internal procedure SuggestUsageVAT( + var PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; + var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; + InvoiceNo: Code[20]; + UsedAmount: Decimal; + CurrencyFactor: Decimal; + TemporaryEntriesOnly: Boolean) + var + PurchInvLine: Record "Purch. Inv. Line"; + PurchaseLine: Record "Purchase Line"; + TempAdvancePostingBufferCZZ1: Record "Advance Posting Buffer CZZ" temporary; + TempAdvancePostingBufferCZZ2: Record "Advance Posting Buffer CZZ" temporary; + TotalAmount: Decimal; + UseAmount: Decimal; + UseBaseAmount: Decimal; + i: Integer; + Continue: Boolean; + begin + AdvancePostingBufferCZZ.CalcSums(Amount); + TotalAmount := AdvancePostingBufferCZZ.Amount; + if (UsedAmount <> 0) and (TotalAmount > UsedAmount) then begin + Continue := InvoiceNo <> ''; + if Continue then + if TemporaryEntriesOnly then begin + PurchaseLine.SetFilter("Document Type", '%1|%2', + PurchaseLine."Document Type"::Order, + PurchaseLine."Document Type"::Invoice); + PurchaseLine.SetRange("Document No.", InvoiceNo); + Continue := PurchaseLine.FindSet(); + end else begin + PurchInvLine.SetRange("Document No.", InvoiceNo); + Continue := PurchInvLine.FindSet(); + end; + + if Continue then begin + BufferAdvanceVATLines(PurchAdvLetterEntryCZZ, TempAdvancePostingBufferCZZ2, 0D); + + if TemporaryEntriesOnly then + repeat + TempAdvancePostingBufferCZZ1.Init(); + TempAdvancePostingBufferCZZ1."VAT Bus. Posting Group" := PurchaseLine."VAT Bus. Posting Group"; + TempAdvancePostingBufferCZZ1."VAT Prod. Posting Group" := PurchaseLine."VAT Prod. Posting Group"; + if TempAdvancePostingBufferCZZ1.Find() then begin + TempAdvancePostingBufferCZZ1.Amount += PurchaseLine."Amount Including VAT"; + TempAdvancePostingBufferCZZ1."VAT Base Amount" += PurchaseLine.Amount; + TempAdvancePostingBufferCZZ1.Modify(); + end else begin + TempAdvancePostingBufferCZZ1."VAT Calculation Type" := PurchaseLine."VAT Calculation Type"; + TempAdvancePostingBufferCZZ1."VAT %" := PurchaseLine."VAT %"; + TempAdvancePostingBufferCZZ1.Amount := PurchaseLine."Amount Including VAT"; + TempAdvancePostingBufferCZZ1."VAT Base Amount" := PurchaseLine.Amount; + TempAdvancePostingBufferCZZ1.Insert(); + end; + until PurchaseLine.Next() = 0 + else + repeat + TempAdvancePostingBufferCZZ1.Init(); + TempAdvancePostingBufferCZZ1."VAT Bus. Posting Group" := PurchInvLine."VAT Bus. Posting Group"; + TempAdvancePostingBufferCZZ1."VAT Prod. Posting Group" := PurchInvLine."VAT Prod. Posting Group"; + if TempAdvancePostingBufferCZZ1.Find() then begin + TempAdvancePostingBufferCZZ1.Amount += PurchInvLine."Amount Including VAT"; + TempAdvancePostingBufferCZZ1."VAT Base Amount" += PurchInvLine.Amount; + TempAdvancePostingBufferCZZ1.Modify(); + end else begin + TempAdvancePostingBufferCZZ1."VAT Calculation Type" := PurchInvLine."VAT Calculation Type"; + TempAdvancePostingBufferCZZ1."VAT %" := PurchInvLine."VAT %"; + TempAdvancePostingBufferCZZ1.Amount := PurchInvLine."Amount Including VAT"; + TempAdvancePostingBufferCZZ1."VAT Base Amount" := PurchInvLine.Amount; + TempAdvancePostingBufferCZZ1.Insert(); + end; + until PurchInvLine.Next() = 0; + + GetCurrency(PurchAdvLetterEntryCZZ."Currency Code"); + + for i := 1 to 3 do begin + TempAdvancePostingBufferCZZ1.FindSet(); + repeat + case i of + 1: + begin + TempAdvancePostingBufferCZZ2.SetRange("VAT Bus. Posting Group", TempAdvancePostingBufferCZZ1."VAT Bus. Posting Group"); + TempAdvancePostingBufferCZZ2.SetRange("VAT Prod. Posting Group", TempAdvancePostingBufferCZZ1."VAT Prod. Posting Group"); + end; + 2: + begin + TempAdvancePostingBufferCZZ2.SetRange("VAT Calculation Type", TempAdvancePostingBufferCZZ1."VAT Calculation Type"); + TempAdvancePostingBufferCZZ2.SetRange("VAT %", TempAdvancePostingBufferCZZ1."VAT %"); + end; + end; + TempAdvancePostingBufferCZZ2.SetFilter(Amount, '<>%1', 0); + if TempAdvancePostingBufferCZZ2.FindSet() then + repeat + UseAmount := TempAdvancePostingBufferCZZ1.Amount; + UseBaseAmount := TempAdvancePostingBufferCZZ1."VAT Base Amount"; + if Abs(TempAdvancePostingBufferCZZ2.Amount) < Abs(UseAmount) then begin + UseAmount := TempAdvancePostingBufferCZZ2.Amount; + UseBaseAmount := TempAdvancePostingBufferCZZ2."VAT Base Amount"; + end; + if Abs(UsedAmount) < Abs(UseAmount) then begin + UseAmount := UsedAmount; + UseBaseAmount := + Round(TempAdvancePostingBufferCZZ2."VAT Base Amount" * UseAmount / + TempAdvancePostingBufferCZZ2.Amount, + CurrencyGlob."Amount Rounding Precision", CurrencyGlob.VATRoundingDirection()); + end; + if TempAdvancePostingBufferCZZ1."VAT %" <> TempAdvancePostingBufferCZZ2."VAT %" then + UseBaseAmount := + Round(TempAdvancePostingBufferCZZ2."VAT Base Amount" * UseAmount / + TempAdvancePostingBufferCZZ2.Amount, + CurrencyGlob."Amount Rounding Precision", CurrencyGlob.VATRoundingDirection()); + + TempAdvancePostingBufferCZZ2.Amount -= UseAmount; + TempAdvancePostingBufferCZZ2."VAT Base Amount" -= UseBaseAmount; + TempAdvancePostingBufferCZZ2.Modify(); + TempAdvancePostingBufferCZZ1.Amount -= UseAmount; + TempAdvancePostingBufferCZZ1."VAT Base Amount" -= UseBaseAmount; + TempAdvancePostingBufferCZZ1.Modify(); + UsedAmount -= UseAmount; + until (TempAdvancePostingBufferCZZ2.Next() = 0) or (UsedAmount = 0); + TempAdvancePostingBufferCZZ2.Reset(); + until TempAdvancePostingBufferCZZ1.Next() = 0; + end; + + if AdvancePostingBufferCZZ.FindSet() then + repeat + TempAdvancePostingBufferCZZ2.Get( + AdvancePostingBufferCZZ."VAT Bus. Posting Group", AdvancePostingBufferCZZ."VAT Prod. Posting Group"); + case true of + TempAdvancePostingBufferCZZ2.Amount = 0: + ; + TempAdvancePostingBufferCZZ2.Amount <> AdvancePostingBufferCZZ.Amount: + begin + AdvancePostingBufferCZZ.Amount := + AdvancePostingBufferCZZ.Amount - TempAdvancePostingBufferCZZ2.Amount; + AdvancePostingBufferCZZ."VAT Base Amount" := + AdvancePostingBufferCZZ."VAT Base Amount" - TempAdvancePostingBufferCZZ2."VAT Base Amount"; + AdvancePostingBufferCZZ."VAT Amount" := + AdvancePostingBufferCZZ.Amount - AdvancePostingBufferCZZ."VAT Base Amount"; + AdvancePostingBufferCZZ.Modify(); + end; + TempAdvancePostingBufferCZZ2.Amount = AdvancePostingBufferCZZ.Amount: + begin + AdvancePostingBufferCZZ.Amount := 0; + AdvancePostingBufferCZZ."VAT Base Amount" := 0; + AdvancePostingBufferCZZ."VAT Amount" := 0; + AdvancePostingBufferCZZ.Modify(); + end; + end; + until AdvancePostingBufferCZZ.Next() = 0; + end else begin + AdvancePostingBufferCZZ.FindSet(); + repeat + AdvancePostingBufferCZZ.Amount := + Round(AdvancePostingBufferCZZ.Amount * UsedAmount / TotalAmount, + CurrencyGlob."Amount Rounding Precision"); + AdvancePostingBufferCZZ."VAT Amount" := + Round(AdvancePostingBufferCZZ."VAT Amount" * UsedAmount / TotalAmount, + CurrencyGlob."Amount Rounding Precision", CurrencyGlob.VATRoundingDirection()); + AdvancePostingBufferCZZ."VAT Base Amount" := + AdvancePostingBufferCZZ.Amount - AdvancePostingBufferCZZ."VAT Amount"; + AdvancePostingBufferCZZ.Modify(); + until AdvancePostingBufferCZZ.Next() = 0; + end; + end; + + if AdvancePostingBufferCZZ.FindSet() then + repeat + AdvancePostingBufferCZZ.UpdateLCYAmounts(PurchAdvLetterEntryCZZ."Currency Code", CurrencyFactor); + AdvancePostingBufferCZZ.Modify(); + until AdvancePostingBufferCZZ.Next() = 0; + end; + + local procedure UnapplyVendLedgEntry(var VendorLedgerEntry: Record "Vendor Ledger Entry"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line") + var + DetailedVendorLedgEntry1: Record "Detailed Vendor Ledg. Entry"; + DetailedVendorLedgEntry2: Record "Detailed Vendor Ledg. Entry"; + DetailedVendorLedgEntry3: Record "Detailed Vendor Ledg. Entry"; + GenJournalLine: Record "Gen. Journal Line"; +#if not CLEAN22 +#pragma warning disable AL0432 + ReplaceVATDateMgtCZL: Codeunit "Replace VAT Date Mgt. CZL"; +#pragma warning restore AL0432 +#endif + Succes: Boolean; + begin + DetailedVendorLedgEntry1.SetCurrentKey("Vendor Ledger Entry No.", "Entry Type"); + DetailedVendorLedgEntry1.SetRange("Vendor Ledger Entry No.", VendorLedgerEntry."Entry No."); + DetailedVendorLedgEntry1.SetRange("Entry Type", DetailedVendorLedgEntry1."Entry Type"::Application); + DetailedVendorLedgEntry1.SetRange(Unapplied, false); + Succes := false; + repeat + if DetailedVendorLedgEntry1.FindLast() then begin + DetailedVendorLedgEntry2.Reset(); + DetailedVendorLedgEntry2.SetCurrentKey("Transaction No.", "Vendor No.", "Entry Type"); + DetailedVendorLedgEntry2.SetRange("Transaction No.", DetailedVendorLedgEntry1."Transaction No."); + DetailedVendorLedgEntry2.SetRange("Vendor No.", DetailedVendorLedgEntry1."Vendor No."); + if DetailedVendorLedgEntry2.FindSet() then + repeat + if (DetailedVendorLedgEntry2."Entry Type" <> DetailedVendorLedgEntry2."Entry Type"::"Initial Entry") and + not DetailedVendorLedgEntry2.Unapplied + then begin + DetailedVendorLedgEntry3.Reset(); + DetailedVendorLedgEntry3.SetCurrentKey("Vendor Ledger Entry No.", "Entry Type"); + DetailedVendorLedgEntry3.SetRange("Vendor Ledger Entry No.", DetailedVendorLedgEntry2."Vendor Ledger Entry No."); + DetailedVendorLedgEntry3.SetRange(Unapplied, false); + if DetailedVendorLedgEntry3.FindLast() and + (DetailedVendorLedgEntry3."Transaction No." > DetailedVendorLedgEntry2."Transaction No.") + then + Error(UnapplyLastInvoicesErr); + end; + until DetailedVendorLedgEntry2.Next() = 0; + + GenJournalLine.Init(); + GenJournalLine."Document No." := DetailedVendorLedgEntry1."Document No."; + GenJournalLine."Posting Date" := DetailedVendorLedgEntry1."Posting Date"; +#if not CLEAN22 +#pragma warning disable AL0432 + if not ReplaceVATDateMgtCZL.IsEnabled() then + GenJournalLine.Validate("VAT Date CZL", VendorLedgerEntry."VAT Date CZL") + else +#pragma warning restore AL0432 +#endif + GenJournalLine.Validate("VAT Reporting Date", VendorLedgerEntry."VAT Date CZL"); + GenJournalLine.Validate("Original Doc. VAT Date CZL", VendorLedgerEntry."VAT Date CZL"); + GenJournalLine."Account Type" := GenJournalLine."Account Type"::Vendor; + GenJournalLine."Account No." := DetailedVendorLedgEntry1."Vendor No."; + GenJournalLine.Correction := true; + GenJournalLine."Document Type" := GenJournalLine."Document Type"::" "; + GenJournalLine.Description := VendorLedgerEntry.Description; + GenJournalLine."Shortcut Dimension 1 Code" := VendorLedgerEntry."Global Dimension 1 Code"; + GenJournalLine."Shortcut Dimension 2 Code" := VendorLedgerEntry."Global Dimension 2 Code"; + GenJournalLine."Dimension Set ID" := VendorLedgerEntry."Dimension Set ID"; + GenJournalLine."Posting Group" := VendorLedgerEntry."Vendor Posting Group"; + GenJournalLine."Source Currency Code" := DetailedVendorLedgEntry1."Currency Code"; + GenJournalLine."System-Created Entry" := true; + OnUnapplyVendLedgEntryOnBeforePostUnapplyVendLedgEntry(VendorLedgerEntry, DetailedVendorLedgEntry1, GenJournalLine); +#if not CLEAN24 + RaiseOnUnapplyVendLedgEntryOnBeforePostUnapplyVendLedgEntry(VendorLedgerEntry, DetailedVendorLedgEntry1, GenJournalLine); +#endif + GenJnlPostLine.UnapplyVendLedgEntry(GenJournalLine, DetailedVendorLedgEntry1); + end else + Succes := true; + until Succes; + end; + + local procedure InitGenJournalLine( + var PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; + var PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; + var AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; + var GenJournalLine: Record "Gen. Journal Line") + begin + GenJournalLine.InitNewLineCZZ( + AdvancePostingParametersCZZ."Posting Date", AdvancePostingParametersCZZ."Document Date", + AdvancePostingParametersCZZ."VAT Date", AdvancePostingParametersCZZ."Original Document VAT Date", + AdvancePostingParametersCZZ."Posting Description"); + GenJournalLine.CopyDocumentFields( + AdvancePostingParametersCZZ."Document Type", AdvancePostingParametersCZZ."Document No.", + AdvancePostingParametersCZZ."External Document No.", AdvancePostingParametersCZZ."Source Code", ''); + GenJournalLine.CopyFromPurchAdvLetterHeaderCZZ(PurchAdvLetterHeaderCZZ); + GenJournalLine.CopyFromPurchAdvLetterEntryCZZ(PurchAdvLetterEntryCZZ); +#if not CLEAN24 + RaiseOnAfterInitGenJnlLineFromAdvance( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, GenJournalLine); +#endif + GenJournalLine.SetCurrencyFactor( + AdvancePostingParametersCZZ."Currency Code", AdvancePostingParametersCZZ."Currency Factor"); + OnAfterInitGenJournalLine( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, AdvancePostingParametersCZZ, GenJournalLine); + end; + + local procedure InitGenJournalLine( + var VendorLedgerEntry: Record "Vendor Ledger Entry"; + var GenJournalLine: Record "Gen. Journal Line") + begin + GenJournalLine.InitNewLineCZZ(VendorLedgerEntry); + GenJournalLine.CopyFromVendorLedgerEntryCZZ(VendorLedgerEntry); +#if not CLEAN24 + RaiseOnAfterInitGenJnlLineFromVendLedgEntry(VendorLedgerEntry, GenJournalLine); +#endif + OnAfterInitGenJournalLineFromVendorLedgerEntry(VendorLedgerEntry, GenJournalLine); + end; + + local procedure RunGenJnlPostLine( + var GenJnlLine: Record "Gen. Journal Line"; + var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; + UseAdvLetterVATAccounts: Boolean; + UseEmptyDocumentType: Boolean; + ActivateGenJnlCheckLnHandler: Boolean) GLEntryNo: Integer + var + DocumentTypeHandlerCZZ: Codeunit "Document Type Handler CZZ"; + GenJnlCheckLnHandlerCZZ: Codeunit "Gen.Jnl.-Check Ln. Handler CZZ"; + VATPostingSetupHandlerCZZ: Codeunit "VAT Posting Setup Handler CZZ"; + IsHandled: Boolean; + begin + IsHandled := false; + OnBeforeRunGenJnlPostLine(GenJnlLine, GenJnlPostLine, GLEntryNo, IsHandled); + if IsHandled then + exit; + + if UseAdvLetterVATAccounts then + BindSubscription(VATPostingSetupHandlerCZZ); + if UseEmptyDocumentType then + BindSubscription(DocumentTypeHandlerCZZ); + if ActivateGenJnlCheckLnHandler then + BindSubscription(GenJnlCheckLnHandlerCZZ); + GLEntryNo := GenJnlPostLine.RunWithCheck(GenJnlLine); + if UseAdvLetterVATAccounts then + UnbindSubscription(VATPostingSetupHandlerCZZ); + if UseEmptyDocumentType then + UnbindSubscription(DocumentTypeHandlerCZZ); + if ActivateGenJnlCheckLnHandler then + UnbindSubscription(GenJnlCheckLnHandlerCZZ); + OnAfterRunGenJnlPostLine(GenJnlLine, GenJnlPostLine, GLEntryNo); + end; + + local procedure GetCurrency(CurrencyCode: Code[10]) + begin + CurrencyGlob.Initialize(CurrencyCode, true); + end; + + local procedure InitVendorLedgerEntryFromPurchInvHeader(PurchInvHeader: Record "Purch. Inv. Header"; var VendorLedgerEntry: Record "Vendor Ledger Entry") +#if not CLEAN22 +#pragma warning disable AL0432 + var + ReplaceVATDateMgtCZL: Codeunit "Replace VAT Date Mgt. CZL"; +#pragma warning restore AL0432 +#endif + begin + VendorLedgerEntry.Init(); + VendorLedgerEntry."Vendor No." := PurchInvHeader."Pay-to Vendor No."; + VendorLedgerEntry."Posting Date" := PurchInvHeader."Posting Date"; + VendorLedgerEntry."Document Date" := PurchInvHeader."Document Date"; + VendorLedgerEntry."Document Type" := VendorLedgerEntry."Document Type"::Invoice; + VendorLedgerEntry."Document No." := PurchInvHeader."No."; + VendorLedgerEntry."External Document No." := PurchInvHeader."Vendor Order No."; + VendorLedgerEntry.Description := PurchInvHeader."Posting Description"; + VendorLedgerEntry."Currency Code" := PurchInvHeader."Currency Code"; + VendorLedgerEntry."Buy-from Vendor No." := PurchInvHeader."Buy-from Vendor No."; + VendorLedgerEntry."Vendor Posting Group" := PurchInvHeader."Vendor Posting Group"; + VendorLedgerEntry."Global Dimension 1 Code" := PurchInvHeader."Shortcut Dimension 1 Code"; + VendorLedgerEntry."Global Dimension 2 Code" := PurchInvHeader."Shortcut Dimension 2 Code"; + VendorLedgerEntry."Dimension Set ID" := PurchInvHeader."Dimension Set ID"; + VendorLedgerEntry."Purchaser Code" := PurchInvHeader."Purchaser Code"; + VendorLedgerEntry."Due Date" := PurchInvHeader."Due Date"; + VendorLedgerEntry."Payment Method Code" := PurchInvHeader."Payment Method Code"; +#if not CLEAN22 +#pragma warning disable AL0432 + if not ReplaceVATDateMgtCZL.IsEnabled() then + PurchInvHeader."VAT Reporting Date" := PurchInvHeader."VAT Date CZL"; +#pragma warning restore AL0432 +#endif + VendorLedgerEntry."VAT Date CZL" := PurchInvHeader."VAT Reporting Date"; + VendorLedgerEntry."Original Currency Factor" := PurchInvHeader."Currency Factor"; + end; +#if not CLEAN24 + + local procedure RaiseOnBeforePostPaymentRepos(var GenJournalLine: Record "Gen. Journal Line"; var PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; PostedGenJournalLine: Record "Gen. Journal Line") + begin + PurchAdvLetterManagementCZZ.RaiseOnBeforePostPaymentRepos( + GenJournalLine, purchAdvLetterHeaderCZZ, PostedGenJournalLine); + end; + + local procedure RaiseOnAfterPostPaymentRepos(var GenJournalLine: Record "Gen. Journal Line"; var PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; PostedGenJournalLine: Record "Gen. Journal Line") + begin + PurchAdvLetterManagementCZZ.RaiseOnAfterPostPaymentRepos( + GenJournalLine, purchAdvLetterHeaderCZZ, PostedGenJournalLine); + end; + + local procedure RaiseOnBeforePostPayment(var GenJournalLine: Record "Gen. Journal Line"; var PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; PostedGenJournalLine: Record "Gen. Journal Line") + begin + PurchAdvLetterManagementCZZ.RaiseOnBeforePostPayment( + GenJournalLine, purchAdvLetterHeaderCZZ, PostedGenJournalLine); + end; + + local procedure RaiseOnAfterPostPayment(var GenJournalLine: Record "Gen. Journal Line"; var PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; PostedGenJournalLine: Record "Gen. Journal Line") + begin + PurchAdvLetterManagementCZZ.RaiseOnAfterPostPayment( + GenJournalLine, purchAdvLetterHeaderCZZ, PostedGenJournalLine); + end; + + local procedure RaiseOnAfterInitGenJnlLineFromVendLedgEntry(var VendorLedgerEntry: Record "Vendor Ledger Entry"; var GenJournalLine: Record "Gen. Journal Line") + begin + PurchAdvLetterManagementCZZ.RaiseOnAfterInitGenJnlLineFromVendLedgEntry(VendorLedgerEntry, GenJournalLine); + end; + + local procedure RaiseOnAfterInitGenJnlLineFromAdvance(var PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; var PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; var GenJournalLine: Record "Gen. Journal Line") + begin + PurchAdvLetterManagementCZZ.RaiseOnAfterInitGenJnlLineFromAdvance( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, GenJournalLine); + end; + + local procedure RaiseOnPostAdvancePaymentVATOnBeforeGenJnlPostLine(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; var GenJournalLine: Record "Gen. Journal Line") + begin + PurchAdvLetterManagementCZZ.RaiseOnPostAdvancePaymentVATOnBeforeGenJnlPostLine( + PurchAdvLetterHeaderCZZ, PurchAdvLetterEntryCZZ, GenJournalLine); + end; + + local procedure RaiseOnBeforePostAdvancePaymentUsage( + var PurchInvHeader: Record "Purch. Inv. Header"; + var AdvanceLetterApplicationCZZ: Record "Advance Letter Application CZZ"; + var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; + AdvancePostingParametersCZ: Record "Advance Posting Parameters CZZ"; + var IsHandled: Boolean) + var + VendorLedgerEntry: Record "Vendor Ledger Entry"; + begin + if not VendorLedgerEntry.Get(PurchInvHeader."Vendor Ledger Entry No.") then + InitVendorLedgerEntryFromPurchInvHeader(PurchInvHeader, VendorLedgerEntry); + PurchAdvLetterManagementCZZ.RaiseOnBeforePostAdvancePaymentUsage( + AdvanceLetterApplicationCZZ."Document Type", AdvanceLetterApplicationCZZ."Document No.", PurchInvHeader, + VendorLedgerEntry, GenJnlPostLine, AdvancePostingParametersCZ."Temporary Entries Only", IsHandled); + end; + + local procedure RaiseOnPostAdvancePaymentUsageOnBeforeLoopPurchAdvLetterEntry(var AdvanceLetterApplicationCZZ: Record "Advance Letter Application CZZ"; var PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ") + begin + PurchAdvLetterManagementCZZ.RaiseOnPostAdvancePaymentUsageOnBeforeLoopPurchAdvLetterEntry( + AdvanceLetterApplicationCZZ, PurchAdvLetterEntryCZZ); + end; + + local procedure RaiseOnBeforePostAdvancePayment(VendorLedgerEntry: Record "Vendor Ledger Entry"; GenJournalLine: Record "Gen. Journal Line"; LinkAmount: Decimal; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var IsHandled: Boolean); + begin + PurchAdvLetterManagementCZZ.RaiseOnBeforePostAdvancePayment(VendorLedgerEntry, GenJournalLine, LinkAmount, GenJnlPostLine, IsHandled); + end; + + local procedure RaiseOnBeforePostClosePayment(var GenJournalLine: Record "Gen. Journal Line"; var PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ") + begin + PurchAdvLetterManagementCZZ.RaiseOnBeforePostClosePayment(GenJournalLine, PurchAdvLetterHeaderCZZ); + end; + + local procedure RaiseOnAfterPostClosePayment(var GenJournalLine: Record "Gen. Journal Line"; var PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ") + begin + PurchAdvLetterManagementCZZ.RaiseOnAfterPostClosePayment(GenJournalLine, PurchAdvLetterHeaderCZZ); + end; + + local procedure RaiseOnBeforePostClosePaymentRepos(var GenJournalLine: Record "Gen. Journal Line"; var PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ") + begin + PurchAdvLetterManagementCZZ.RaiseOnBeforePostClosePaymentRepos(GenJournalLine, PurchAdvLetterHeaderCZZ); + end; + + local procedure RaiseOnAfterPostClosePaymentRepos(var GenJournalLine: Record "Gen. Journal Line"; var PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ") + begin + PurchAdvLetterManagementCZZ.RaiseOnAfterPostClosePaymentRepos(GenJournalLine, PurchAdvLetterHeaderCZZ); + end; + + local procedure RaiseOnBeforePostReversePaymentRepos(var GenJournalLine: Record "Gen. Journal Line"; var PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ") + begin + PurchAdvLetterManagementCZZ.RaiseOnBeforePostReversePaymentRepos(GenJournalLine, PurchAdvLetterHeaderCZZ); + end; + + local procedure RaiseOnAfterPostReversePaymentRepos(var GenJournalLine: Record "Gen. Journal Line"; var PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ") + begin + PurchAdvLetterManagementCZZ.RaiseOnAfterPostReversePaymentRepos(GenJournalLine, PurchAdvLetterHeaderCZZ); + end; + + local procedure RaiseOnBeforePostReversePayment(var GenJournalLine: Record "Gen. Journal Line"; var PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ") + begin + PurchAdvLetterManagementCZZ.RaiseOnBeforePostReversePayment(GenJournalLine, PurchAdvLetterHeaderCZZ); + end; + + local procedure RaiseOnAfterPostReversePayment(var GenJournalLine: Record "Gen. Journal Line"; var PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ") + begin + PurchAdvLetterManagementCZZ.RaiseOnAfterPostReversePayment(GenJournalLine, PurchAdvLetterHeaderCZZ); + end; + + local procedure RaiseOnBeforePostReversePaymentVAT(var PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; PostingDate: Date; var Preview: Boolean; var IsHandled: Boolean) + begin + PurchAdvLetterManagementCZZ.RaiseOnBeforePostReversePaymentVAT(PurchAdvLetterEntryCZZ, PostingDate, Preview, IsHandled); + end; + + local procedure RaiseOnUnapplyVendLedgEntryOnBeforePostUnapplyVendLedgEntry(var VendorLedgerEntry: Record "Vendor Ledger Entry"; var DetailedVendorLedgEntry: Record "Detailed Vendor Ledg. Entry"; var GenJournalLine: Record "Gen. Journal Line") + begin + PurchAdvLetterManagementCZZ.RaiseOnUnapplyVendLedgEntryOnBeforePostUnapplyVendLedgEntry(VendorLedgerEntry, DetailedVendorLedgEntry, GenJournalLine); + end; +#endif + + [IntegrationEvent(false, false)] + local procedure OnBeforePostAdvancePayment(var VendorLedgerEntry: Record "Vendor Ledger Entry"; PostedGenJournalLine: Record "Gen. Journal Line"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var AdvancePostingParameters: Record "Advance Posting Parameters CZZ"; var IsHandled: Boolean) + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnAfterPostAdvancePayment(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; VendorLedgerEntry: Record "Vendor Ledger Entry"; PostedGenJournalLine: Record "Gen. Journal Line"; EntryNo: Integer; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnBeforePostAdvancePaymentUnlinking(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 OnAfterPostAdvancePaymentUnlinking(PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostAdvancePaymentUnlinkingOnBeforePostAdvancePaymentApplication(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; var PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; var AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostAdvancePaymentUnlinkingOnAfterPostAdvancePaymentApplication(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; var PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; 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 OnPostAdvancePaymentUnlinkingOnBeforePostPaymentApplication(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; var PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; var AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostAdvancePaymentUnlinkingOnAfterPostPaymentApplication(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; var PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; 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 OnPostAdvancePaymentOnBeforePostPaymentApplication(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; PostedGenJournalLine: Record "Gen. Journal Line"; AdvancePostingParameters: Record "Advance Posting Parameters CZZ"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostAdvancePaymentOnAfterPostPaymentApplication(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; PostedGenJournalLine: Record "Gen. Journal Line"; AdvancePostingParameters: Record "Advance Posting Parameters CZZ"; GLEntryNo: Integer; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostAdvancePaymentOnBeforePostAdvancePayment(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; PostedGenJournalLine: Record "Gen. Journal Line"; AdvancePostingParameters: Record "Advance Posting Parameters CZZ"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostAdvancePaymentOnAfterPostAdvancePayment(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; PostedGenJournalLine: Record "Gen. Journal Line"; AdvancePostingParameters: Record "Advance Posting Parameters CZZ"; GLEntryNo: Integer; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostAdvancePaymentVATOnBeforePost(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; AdvancePostingParameters: Record "Advance Posting Parameters CZZ"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostAdvancePaymentVATOnAfterPost(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; AdvancePostingParameters: Record "Advance Posting Parameters CZZ"; GLEntryNo: Integer; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostAdvancePaymentVATOnBeforePostBalance(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; AdvancePostingParameters: Record "Advance Posting Parameters CZZ"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostAdvancePaymentVATOnAfterPostBalance(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; AdvancePostingParameters: Record "Advance Posting Parameters CZZ"; GLEntryNo: Integer; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnBeforePostAdvancePaymentVAT(var PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var AdvancePostingParameters: Record "Advance Posting Parameters CZZ"; var IsHandled: Boolean) + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnAfterPostAdvancePaymentVAT(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnBeforePostAdvancePaymentVATUnlinking(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; 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 + end; + + [IntegrationEvent(false, false)] + local procedure OnAfterPostAdvancePaymentVATUnlinking(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; var PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; EntryNo: Integer; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostAdvancePaymentVATUnlinkingOnBeforePost(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; var PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; VATPostingSetup: Record "VAT Posting Setup"; var AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostAdvancePaymentVATUnlinkingOnAfterPost(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; var PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; VATPostingSetup: Record "VAT Posting Setup"; 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 OnPostAdvancePaymentVATUnlinkingOnBeforePostBalance(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"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostAdvancePaymentVATUnlinkingOnAfterPostBalance(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; var PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; 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 OnBeforeRunGenJnlPostLine(var GenJnlLine: Record "Gen. Journal Line"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var GLEntryNo: Integer; var IsHandled: Boolean) + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnBeforePostAdvancePaymentUsage(var PurchInvHeader: Record "Purch. Inv. Header"; var AdvanceLetterApplicationCZZ: Record "Advance Letter Application CZZ"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var AdvancePostingParameters: Record "Advance Posting Parameters CZZ"; var IsHandled: Boolean) + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnAfterPostAdvancePaymentUsage(PurchInvHeader: Record "Purch. Inv. Header"; var AdvanceLetterApplicationCZZ: Record "Advance Letter Application CZZ"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; AdvancePostingParameters: Record "Advance Posting Parameters CZZ") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostAdvancePaymentUsageOnAfterSetPurchAdvLetterEntryFilter(AdvanceLetterApplicationCZZ: Record "Advance Letter Application CZZ"; var PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnBeforePostAdvancePaymentUsageVAT(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 + end; + + [IntegrationEvent(false, false)] + local procedure OnAfterPostAdvancePaymentUsageVAT(var PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ") + 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 + end; + + [IntegrationEvent(false, false)] + local procedure OnAfterPostAdvanceCreditMemoVAT(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; var PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostAdvanceCreditMemoVATOnBeforePost(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; 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"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostAdvanceCreditMemoVATOnAfterPost(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; 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 OnPostAdvanceCreditMemoVATOnBeforePostBalance(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; 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"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostAdvanceCreditMemoVATOnAfterPostBalance(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; 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 OnBeforePostAdvanceLetterApplying(var PurchInvHeader: Record "Purch. Inv. Header"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; var IsHandled: Boolean) + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnAfterPostAdvanceLetterApplying(PurchInvHeader: Record "Purch. Inv. Header"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnBeforePostAdvanceLetterUnapplying(var PurchInvHeader: Record "Purch. Inv. Header"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; var IsHandled: Boolean) + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnAfterPostAdvanceLetterUnapplying(PurchInvHeader: Record "Purch. Inv. Header"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnBeforePostAdvanceLetterEntryVATUsageUnapplying(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; 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 + end; + + [IntegrationEvent(false, false)] + local procedure OnAfterPostAdvanceLetterEntryVATUsageUnapplying(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; EntryNo: Integer; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostAdvanceLetterEntryVATUsageUnapplyingOnBeforePost(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostAdvanceLetterEntryVATUsageUnapplyingOnAfterPost(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; 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 OnPostAdvanceLetterEntryVATUsageUnapplyingOnBeforePostBalance(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostAdvanceLetterEntryVATUsageUnapplyingOnAfterPostBalance(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; 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 OnBeforePostAdvanceLetterEntryUsageUnapplying(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; 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 + end; + + [IntegrationEvent(false, false)] + local procedure OnAfterPostAdvanceLetterEntryUsageUnapplying(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; EntryNo: Integer; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostAdvanceLetterEntryUsageUnapplyingOnBeforePostAdvancePaymentApplication(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostAdvanceLetterEntryUsageUnapplyingOnAfterPostAdvancePaymentApplication(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; 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 OnPostAdvanceLetterEntryUsageUnapplyingOnBeforePostInvoiceApplication(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostAdvanceLetterEntryUsageUnapplyingOnAfterPostInvoiceApplication(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; 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 OnBeforePostAdvanceLetterClosing(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header 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 OnAfterPostAdvanceLetterClosing(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ") + begin + end; + + + [IntegrationEvent(false, false)] + local procedure OnBeforePostAdvanceLetterEntryClosing(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; 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 OnAfterPostAdvanceLetterEntryClosing(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostAdvanceLetterEntryClosingOnBeforePost(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; VendorLedgerEntry: Record "Vendor Ledger Entry"; var AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostAdvanceLetterEntryClosingOnAfterPost(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; VendorLedgerEntry: Record "Vendor Ledger Entry"; 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 OnPostAdvanceLetterEntryClosingOnBeforePostBalance(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; VendorLedgerEntry: Record "Vendor Ledger Entry"; var AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostAdvanceLetterEntryClosingOnAfterPostBalance(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; VendorLedgerEntry: Record "Vendor Ledger Entry"; 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 OnBeforeReverseAdvancePayment(PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; PurchInvHeader: Record "Purch. Inv. Header"; var ReverseAmount: Decimal; var ReverseAmountLCY: Decimal; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var AdvancePostingParameters: Record "Advance Posting Parameters CZZ"; var IsHandled: Boolean) + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnAfterReverseAdvancePayment(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; PurchInvHeader: Record "Purch. Inv. Header"; CreatedEntryNo: Integer; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnReverseAdvancePaymentOnBeforePostInvoiceApplication(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; VendorLedgerEntry: Record "Vendor Ledger Entry"; AdvancePostingParameters: Record "Advance Posting Parameters CZZ"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnReverseAdvancePaymentOnAfterPostInvoiceApplication(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; VendorLedgerEntry: Record "Vendor Ledger Entry"; AdvancePostingParameters: Record "Advance Posting Parameters CZZ"; GLEntryNo: Integer; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnReverseAdvancePaymentOnBeforePostAdvancePaymentUsage(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; VendorLedgerEntry: Record "Vendor Ledger Entry"; AdvancePostingParameters: Record "Advance Posting Parameters CZZ"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnReverseAdvancePaymentOnAfterPostAdvancePaymentUsage(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; VendorLedgerEntry: Record "Vendor Ledger Entry"; AdvancePostingParameters: Record "Advance Posting Parameters CZZ"; GLEntryNo: Integer; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnBeforeReverseAdvancePaymentVAT(var PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; var RelatedEntryNo: Integer; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; var IsHandled: Boolean) + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnAfterReverseAdvancePaymentVAT(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnReverseAdvancePaymentVATOnBeforePost(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; VATPostingSetup: Record "VAT Posting Setup"; AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnReverseAdvancePaymentVATOnAfterPost(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; VATPostingSetup: Record "VAT Posting Setup"; AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; GLEntryNo: Integer; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnReverseAdvancePaymentVATOnBeforePostBalance(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; VATPostingSetup: Record "VAT Posting Setup"; AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnReverseAdvancePaymentVATOnAfterPostBalance(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; VATPostingSetup: Record "VAT Posting Setup"; AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; GLEntryNo: Integer; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnBeforeCalculateVATAmountInBuffer(var PostingDate: Date; var CurrencyCode: Code[10]; var CurrencyFactor: Decimal; var TempAdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; var IsHandled: Boolean) + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnBeforeReverseUnrealizedExchangeRate(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; VATPostingSetup: Record "VAT Posting Setup"; var Coef: Decimal; var RelatedEntryNo: Integer; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; var IsHandled: Boolean) + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnBeforePostExchangeRate(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; VATPostingSetup: Record "VAT Posting Setup"; ExchRateAmount: Decimal; ExchRateVATAmount: Decimal; UsageEntryNo: Integer; Correction: Boolean; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ" temporary; var IsHandled: Boolean) + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnAfterPostExchangeRate(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; VATPostingSetup: Record "VAT Posting Setup"; EntryNo: Integer; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; TempPurchAdvLetterEntryCZZGlob: Record "Purch. Adv. Letter Entry CZZ") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostExchangeRateOnBeforePostVATBase(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; VATPostingSetup: Record "VAT Posting Setup"; Amount: Decimal; VATAmount: Decimal; AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostExchangeRateOnAfterPostVATBase(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; VATPostingSetup: Record "VAT Posting Setup"; Amount: Decimal; VATAmount: Decimal; AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; GLEntryNo: Integer; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostExchangeRateOnBeforePostVATAmount(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; VATPostingSetup: Record "VAT Posting Setup"; Amount: Decimal; VATAmount: Decimal; AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostExchangeRateOnAfterPostVATAmount(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; VATPostingSetup: Record "VAT Posting Setup"; Amount: Decimal; VATAmount: Decimal; AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; GLEntryNo: Integer; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostExchangeRateOnBeforePostBalance(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; VATPostingSetup: Record "VAT Posting Setup"; Amount: Decimal; VATAmount: Decimal; AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostExchangeRateOnAfterPostBalance(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; VATPostingSetup: Record "VAT Posting Setup"; Amount: Decimal; VATAmount: Decimal; AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; GLEntryNo: Integer; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnBeforePostUnrealizedExchangeRate(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; VATPostingSetup: Record "VAT Posting Setup"; var Amount: Decimal; var VATAmount: Decimal; var RelatedEntryNo: Integer; var RelatedDetEntryNo: Integer; var Correction: Boolean; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; var IsHandled: Boolean) + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnAfterPostUnrealizedExchangeRate(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; VATPostingSetup: Record "VAT Posting Setup"; EntryNo: Integer; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; TempPurchAdvLetterEntryCZZGlob: Record "Purch. Adv. Letter Entry CZZ") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostUnrealizedExchangeRateOnBeforePost(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; VATPostingSetup: Record "VAT Posting Setup"; Amount: Decimal; VATAmount: Decimal; AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostUnrealizedExchangeRateOnAfterPost(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; VATPostingSetup: Record "VAT Posting Setup"; Amount: Decimal; VATAmount: Decimal; AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; GLEntryNo: Integer; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostUnrealizedExchangeRateOnBeforePostBalance(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; VATPostingSetup: Record "VAT Posting Setup"; Amount: Decimal; VATAmount: Decimal; AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostUnrealizedExchangeRateOnAfterPostBalance(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; VATPostingSetup: Record "VAT Posting Setup"; Amount: Decimal; VATAmount: Decimal; AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; GLEntryNo: Integer; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostExchangeRateOnBeforeInsertEntry(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; VATPostingSetup: Record "VAT Posting Setup"; AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; var TempPurchAdvLetterEntryCZZGlob: Record "Purch. Adv. Letter Entry CZZ") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostUnrealizedExchangeRateOnBeforeInsertEntry(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; VATPostingSetup: Record "VAT Posting Setup"; AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; var TempPurchAdvLetterEntryCZZGlob: Record "Purch. Adv. Letter Entry CZZ") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnAfterRunGenJnlPostLine(var GenJnlLine: Record "Gen. Journal Line"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var GLEntryNo: Integer) + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnAfterInitGenJournalLine(var PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; var PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"; var AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnAfterInitGenJournalLineFromVendorLedgerEntry(var VendorLedgerEntry: Record "Vendor Ledger Entry"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [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; +} \ No newline at end of file diff --git a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/PurchPostHandlerCZZ.Codeunit.al b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/PurchPostHandlerCZZ.Codeunit.al index a86863b362..ae5fac89c9 100644 --- a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/PurchPostHandlerCZZ.Codeunit.al +++ b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/PurchPostHandlerCZZ.Codeunit.al @@ -18,13 +18,10 @@ codeunit 31022 "Purch.-Post Handler CZZ" var PurchAdvLetterManagement: Codeunit "PurchAdvLetterManagement CZZ"; begin - if (not PurchaseHeader.Invoice) or (not (PurchaseHeader."Document Type" in [PurchaseHeader."Document Type"::Order, PurchaseHeader."Document Type"::Invoice])) then + if (not PurchaseHeader.Invoice) or (not PurchaseHeader.IsAdvanceLetterDocTypeCZZ()) then exit; - if PurchaseHeader."Document Type" = PurchaseHeader."Document Type"::Order then - PurchAdvLetterManagement.CheckAdvancePayment("Adv. Letter Usage Doc.Type CZZ"::"Purchase Order", PurchaseHeader) - else - PurchAdvLetterManagement.CheckAdvancePayment("Adv. Letter Usage Doc.Type CZZ"::"Purchase Invoice", PurchaseHeader); + PurchAdvLetterManagement.CheckAdvancePayment(PurchaseHeader.GetAdvLetterUsageDocTypeCZZ(), PurchaseHeader) end; [EventSubscriber(ObjectType::Codeunit, Codeunit::"Purchase Handler CZP", 'OnBeforeCreateCashDocument', '', false, false)] @@ -42,13 +39,10 @@ codeunit 31022 "Purch.-Post Handler CZZ" PurchAdvLetterManagementCZZ: Codeunit "PurchAdvLetterManagement CZZ"; AdvLetterUsageDocTypeCZZ: Enum "Adv. Letter Usage Doc.Type CZZ"; begin - if (not PurchHeader.Invoice) or (not (PurchHeader."Document Type" in [PurchHeader."Document Type"::Order, PurchHeader."Document Type"::Invoice])) then + if (not PurchHeader.Invoice) or (not PurchHeader.IsAdvanceLetterDocTypeCZZ()) then exit; - if PurchHeader."Document Type" = PurchHeader."Document Type"::Order then - AdvLetterUsageDocTypeCZZ := AdvLetterUsageDocTypeCZZ::"Purchase Order" - else - AdvLetterUsageDocTypeCZZ := AdvLetterUsageDocTypeCZZ::"Purchase Invoice"; + AdvLetterUsageDocTypeCZZ := PurchHeader.GetAdvLetterUsageDocTypeCZZ(); VendorLedgerEntry.Get(PurchInvHeader."Vendor Ledger Entry No."); BindSubscription(GetLastGLEntryNoCZZ); diff --git a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/RelPurchAdvLetterDocCZZ.Codeunit.al b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/RelPurchAdvLetterDocCZZ.Codeunit.al index b616d7d1f8..4ad3f311d8 100644 --- a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/RelPurchAdvLetterDocCZZ.Codeunit.al +++ b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/RelPurchAdvLetterDocCZZ.Codeunit.al @@ -57,7 +57,7 @@ codeunit 31018 "Rel. Purch.Adv.Letter Doc. CZZ" PurchAdvLetterHeaderCZZ."Currency Code", PurchAdvLetterHeaderCZZ."Currency Factor", PurchAdvLetterHeaderCZZ."No.", '', PurchAdvLetterHeaderCZZ."Shortcut Dimension 1 Code", PurchAdvLetterHeaderCZZ."Shortcut Dimension 2 Code", PurchAdvLetterHeaderCZZ."Dimension Set ID", false); - PurchAdvLetterManagementCZZ.UpdateStatus(PurchAdvLetterHeaderCZZ, PurchAdvLetterHeaderCZZ.Status::"To Pay"); + PurchAdvLetterHeaderCZZ.UpdateStatus(PurchAdvLetterHeaderCZZ.Status::"To Pay"); OnAfterReleaseDoc(PurchAdvLetterHeaderCZZ); end; @@ -85,7 +85,7 @@ codeunit 31018 "Rel. Purch.Adv.Letter Doc. CZZ" exit; PurchAdvLetterManagementCZZ.CancelInitEntry(PurchAdvLetterHeaderCZZ, 0D, true); - PurchAdvLetterManagementCZZ.UpdateStatus(PurchAdvLetterHeaderCZZ, PurchAdvLetterHeaderCZZ.Status::New); + PurchAdvLetterHeaderCZZ.UpdateStatus(PurchAdvLetterHeaderCZZ.Status::New); OnAfterReopenDoc(PurchAdvLetterHeaderCZZ); end; diff --git a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/RelSalesAdvLetterDocCZZ.Codeunit.al b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/RelSalesAdvLetterDocCZZ.Codeunit.al index 2cf81fa174..e1cf5a8c6f 100644 --- a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/RelSalesAdvLetterDocCZZ.Codeunit.al +++ b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/RelSalesAdvLetterDocCZZ.Codeunit.al @@ -50,6 +50,7 @@ codeunit 31001 "Rel. Sales Adv.Letter Doc. CZZ" OnUpdateVariableSymbol(SalesAdvLetterHeaderCZZ, VariableSymbol); SalesAdvLetterHeaderCZZ."Variable Symbol" := VariableSymbol; end; + SalesAdvLetterHeaderCZZ.CheckPaymentQRCodePrintIBAN(); SalesAdvLetterManagementCZZ.AdvEntryInit(false); SalesAdvLetterManagementCZZ.AdvEntryInsert("Advance Letter Entry Type CZZ"::"Initial Entry", SalesAdvLetterHeaderCZZ."No.", SalesAdvLetterHeaderCZZ."Posting Date", @@ -57,7 +58,7 @@ codeunit 31001 "Rel. Sales Adv.Letter Doc. CZZ" SalesAdvLetterHeaderCZZ."Currency Code", SalesAdvLetterHeaderCZZ."Currency Factor", SalesAdvLetterHeaderCZZ."No.", SalesAdvLetterHeaderCZZ."Shortcut Dimension 1 Code", SalesAdvLetterHeaderCZZ."Shortcut Dimension 2 Code", SalesAdvLetterHeaderCZZ."Dimension Set ID", false); - SalesAdvLetterManagementCZZ.UpdateStatus(SalesAdvLetterHeaderCZZ, SalesAdvLetterHeaderCZZ.Status::"To Pay"); + SalesAdvLetterHeaderCZZ.UpdateStatus(SalesAdvLetterHeaderCZZ.Status::"To Pay"); OnAfterReleaseDoc(SalesAdvLetterHeaderCZZ); end; @@ -84,7 +85,7 @@ codeunit 31001 "Rel. Sales Adv.Letter Doc. CZZ" exit; SalesAdvLetterManagementCZZ.CancelInitEntry(SalesAdvLetterHeaderCZZ, 0D, true); - SalesAdvLetterManagementCZZ.UpdateStatus(SalesAdvLetterHeaderCZZ, SalesAdvLetterHeaderCZZ.Status::New); + SalesAdvLetterHeaderCZZ.UpdateStatus(SalesAdvLetterHeaderCZZ.Status::New); OnAfterReopenDoc(SalesAdvLetterHeaderCZZ); end; diff --git a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/SalesAdvLetterManagementCZZ.Codeunit.al b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/SalesAdvLetterManagementCZZ.Codeunit.al index 3fb9d313c2..71dc73b007 100644 --- a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/SalesAdvLetterManagementCZZ.Codeunit.al +++ b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/SalesAdvLetterManagementCZZ.Codeunit.al @@ -12,7 +12,6 @@ using Microsoft.Finance.VAT.Calculation; #endif using Microsoft.Finance.VAT.Ledger; using Microsoft.Finance.VAT.Setup; -using Microsoft.Foundation.AuditCodes; using Microsoft.Foundation.Enums; using Microsoft.Foundation.NoSeries; using Microsoft.Sales.Customer; @@ -29,14 +28,13 @@ codeunit 31002 "SalesAdvLetterManagement CZZ" var SalesAdvLetterEntryCZZGlob: Record "Sales Adv. Letter Entry CZZ"; TempSalesAdvLetterEntryCZZGlob: Record "Sales Adv. Letter Entry CZZ" temporary; - CurrencyGlob: Record Currency; #if not CLEAN22 #pragma warning disable AL0432 ReplaceVATDateMgtCZL: Codeunit "Replace VAT Date Mgt. CZL"; #pragma warning restore AL0432 #endif + SalesAdvLetterPostCZZ: Codeunit "Sales Adv. Letter-Post CZZ"; DocumentNoOrDatesEmptyErr: Label 'Document No. and Dates cannot be empty.'; - NothingToPostErr: Label 'Nothing to Post.'; VATDocumentExistsErr: Label 'VAT Document already exists.'; DateEmptyErr: Label 'Posting Date and VAT Date cannot be empty.'; PostingDateEmptyErr: Label 'Posting Date cannot be empty.'; @@ -304,82 +302,14 @@ codeunit 31002 "SalesAdvLetterManagement CZZ" procedure PostAdvancePayment(var CustLedgerEntry: Record "Cust. Ledger Entry"; PostedGenJournalLine: Record "Gen. Journal Line"; LinkAmount: Decimal; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; PostingDate: Date) InsertedEntryNo: Integer var - SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; - GenJournalLine: Record "Gen. Journal Line"; - CustLedgerEntry2: Record "Cust. Ledger Entry"; - ApplId: Code[50]; - Amount: Decimal; - AmountLCY: Decimal; - IsHandled: Boolean; - RemainingAmountExceededErr: Label 'The amount cannot be higher than remaining amount on ledger entry.'; - ToPayAmountExceededErr: Label 'The amount cannot be higher than to pay on advance letter.'; + AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; begin - OnBeforePostAdvancePayment(CustLedgerEntry, PostedGenJournalLine, LinkAmount, GenJnlPostLine, IsHandled); - if IsHandled then - exit; - - CustLedgerEntry.TestField("Advance Letter No. CZZ", ''); - SalesAdvLetterHeaderCZZ.Get(PostedGenJournalLine."Advance Letter No. CZZ"); - SalesAdvLetterHeaderCZZ.CheckSalesAdvanceLetterPostRestrictions(); - SalesAdvLetterHeaderCZZ.TestField("Currency Code", CustLedgerEntry."Currency Code"); - SalesAdvLetterHeaderCZZ.TestField("Bill-to Customer No.", CustLedgerEntry."Customer No."); - if LinkAmount = 0 then begin - CustLedgerEntry.CalcFields("Remaining Amount", "Remaining Amt. (LCY)"); - Amount := CustLedgerEntry."Remaining Amount"; - AmountLCY := CustLedgerEntry."Remaining Amt. (LCY)"; - end else begin - CustLedgerEntry.CalcFields("Remaining Amount"); - if LinkAmount > -CustLedgerEntry."Remaining Amount" then - Error(RemainingAmountExceededErr); - - Amount := -LinkAmount; - AmountLCY := Round(Amount / CustLedgerEntry."Original Currency Factor"); - end; - SalesAdvLetterHeaderCZZ.CalcFields("To Pay"); - if -Amount > SalesAdvLetterHeaderCZZ."To Pay" then - Error(ToPayAmountExceededErr); - - InitGenJnlLineFromCustLedgEntry(CustLedgerEntry, GenJournalLine, GenJournalLine."Document Type"::" "); - GenJournalLine."Posting Date" := PostingDate; - GenJournalLine."Adv. Letter Template Code CZZ" := SalesAdvLetterHeaderCZZ."Advance Letter Code"; - GenJournalLine.Correction := true; - GenJournalLine.SetCurrencyFactor(CustLedgerEntry."Currency Code", CustLedgerEntry."Original Currency Factor"); - GenJournalLine.Amount := -Amount; - GenJournalLine."Amount (LCY)" := -AmountLCY; - - ApplId := CopyStr(CustLedgerEntry."Document No." + Format(CustLedgerEntry."Entry No.", 0, ''), 1, MaxStrLen(ApplId)); - CustLedgerEntry.CalcFields("Remaining Amount"); - CustLedgerEntry."Amount to Apply" := CustLedgerEntry."Remaining Amount"; - CustLedgerEntry."Applies-to ID" := ApplId; - CustLedgerEntry."Adv. Letter Template Code CZZ" := SalesAdvLetterHeaderCZZ."Advance Letter Code"; - Codeunit.Run(Codeunit::"Cust. Entry-Edit", CustLedgerEntry); - - GenJournalLine."Applies-to ID" := ApplId; - OnBeforePostPaymentRepos(GenJournalLine, SalesAdvLetterHeaderCZZ, PostedGenJournalLine); - GenJnlPostLine.RunWithCheck(GenJournalLine); - OnAfterPostPaymentRepos(GenJournalLine, SalesAdvLetterHeaderCZZ, PostedGenJournalLine); + Clear(AdvancePostingParametersCZZ); + AdvancePostingParametersCZZ."Posting Date" := PostingDate; + AdvancePostingParametersCZZ."Amount to Link" := LinkAmount; - InitGenJnlLineFromCustLedgEntry(CustLedgerEntry, GenJournalLine, GenJournalLine."Document Type"::" "); - GenJournalLine."Posting Date" := PostingDate; - GenJournalLine."Adv. Letter Template Code CZZ" := SalesAdvLetterHeaderCZZ."Advance Letter Code"; - GenJournalLine."Adv. Letter No. (Entry) CZZ" := SalesAdvLetterHeaderCZZ."No."; - GenJournalLine."Use Advance G/L Account CZZ" := true; - GenJournalLine.SetCurrencyFactor(CustLedgerEntry."Currency Code", CustLedgerEntry."Original Currency Factor"); - GenJournalLine.Amount := Amount; - GenJournalLine."Amount (LCY)" := AmountLCY; - OnBeforePostPayment(GenJournalLine, SalesAdvLetterHeaderCZZ, PostedGenJournalLine); - GenJnlPostLine.RunWithCheck(GenJournalLine); - OnAfterPostPayment(GenJournalLine, SalesAdvLetterHeaderCZZ, PostedGenJournalLine); - - CustLedgerEntry2.FindLast(); - AdvEntryInit(false); - AdvEntryInitCustLedgEntryNo(CustLedgerEntry2."Entry No."); - InsertedEntryNo := AdvEntryInsert("Advance Letter Entry Type CZZ"::Payment, SalesAdvLetterHeaderCZZ."No.", GenJournalLine."Posting Date", - GenJournalLine.Amount, GenJournalLine."Amount (LCY)", - GenJournalLine."Currency Code", GenJournalLine."Currency Factor", GenJournalLine."Document No.", - GenJournalLine."Shortcut Dimension 1 Code", GenJournalLine."Shortcut Dimension 2 Code", GenJournalLine."Dimension Set ID", false); - - UpdateStatus(SalesAdvLetterHeaderCZZ, SalesAdvLetterHeaderCZZ.Status::"To Use") + InsertedEntryNo := SalesAdvLetterPostCZZ.PostAdvancePayment( + CustLedgerEntry, PostedGenJournalLine, GenJnlPostLine, AdvancePostingParametersCZZ); end; procedure GetAdvanceGLAccount(var GenJournalLine: Record "Gen. Journal Line"): Code[20] @@ -401,23 +331,18 @@ codeunit 31002 "SalesAdvLetterManagement CZZ" procedure PostAdvancePaymentVAT(var SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; PostingDate: Date; Silently: Boolean) var + AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; SalesAdvLetterEntryCZZ2: Record "Sales Adv. Letter Entry CZZ"; AdvanceLetterTemplateCZZ: Record "Advance Letter Template CZZ"; TempAdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ" temporary; - GenJournalLine: Record "Gen. Journal Line"; - VATPostingSetup: Record "VAT Posting Setup"; CustLedgerEntry: Record "Cust. Ledger Entry"; - DocumentTypeHandlerCZZ: Codeunit "Document Type Handler CZZ"; GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; - NoSeriesManagement: Codeunit NoSeriesManagement; - VATPostingSetupHandlerCZZ: Codeunit "VAT Posting Setup Handler CZZ"; + NoSeries: Codeunit "No. Series"; VATDocumentCZZ: Page "VAT Document CZZ"; DocumentNo: Code[20]; IsHandled: Boolean; VATDate: Date; - SettingErr: Label '%1 cannot be empty in table %2, for %3, %4. You have to fill field and post VAT document again.', Comment = '%1 = Field Caption, %2 = Table Caption, %3 = VAT Bus. Posting Group, %4 = "VAT Prod. Posting Group"'; - ExceededAmountErr: Label 'Amount has been exceeded.'; begin OnBeforePostPaymentVAT(SalesAdvLetterEntryCZZ, PostingDate, IsHandled); if IsHandled then @@ -451,7 +376,7 @@ codeunit 31002 "SalesAdvLetterManagement CZZ" InitVATAmountLine(TempAdvancePostingBufferCZZ, SalesAdvLetterEntryCZZ."Sales Adv. Letter No.", SalesAdvLetterEntryCZZ.Amount, SalesAdvLetterEntryCZZ."Currency Factor"); if Silently or not GuiAllowed then begin - DocumentNo := NoSeriesManagement.GetNextNo(AdvanceLetterTemplateCZZ."Advance Letter Invoice Nos.", PostingDate, true); + DocumentNo := NoSeries.GetNextNo(AdvanceLetterTemplateCZZ."Advance Letter Invoice Nos.", PostingDate); TempAdvancePostingBufferCZZ.SetFilter(Amount, '<>0'); end else begin VATDocumentCZZ.InitSalesDocument(AdvanceLetterTemplateCZZ."Advance Letter Invoice Nos.", '', @@ -466,111 +391,25 @@ codeunit 31002 "SalesAdvLetterManagement CZZ" Error(DocumentNoOrDatesEmptyErr); end; - TempAdvancePostingBufferCZZ.SetFilter(Amount, '<>0'); - if TempAdvancePostingBufferCZZ.IsEmpty() then - Error(NothingToPostErr); - - SalesAdvLetterEntryCZZ2.CalcSums(Amount); - TempAdvancePostingBufferCZZ.CalcSums(Amount); - if (SalesAdvLetterEntryCZZ.Amount - SalesAdvLetterEntryCZZ2.Amount) < TempAdvancePostingBufferCZZ.Amount then - Error(ExceededAmountErr); - - GetCurrency(SalesAdvLetterEntryCZZ."Currency Code"); - - if TempAdvancePostingBufferCZZ.FindSet() then - repeat - VATPostingSetup.Get(TempAdvancePostingBufferCZZ."VAT Bus. Posting Group", TempAdvancePostingBufferCZZ."VAT Prod. Posting Group"); - if VATPostingSetup."Sales Adv. Letter Account CZZ" = '' then - Error(SettingErr, VATPostingSetup.FieldCaption("Sales Adv. Letter Account CZZ"), VATPostingSetup.TableCaption, VATPostingSetup."VAT Bus. Posting Group", VATPostingSetup."VAT Prod. Posting Group"); - if VATPostingSetup."Sales Adv. Letter VAT Acc. CZZ" = '' then - Error(SettingErr, VATPostingSetup.FieldCaption("Sales Adv. Letter VAT Acc. CZZ"), VATPostingSetup.TableCaption, VATPostingSetup."VAT Bus. Posting Group", VATPostingSetup."VAT Prod. Posting Group"); - - InitGenJnlLineFromAdvance(SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, DocumentNo, CustLedgerEntry."Source Code", SalesAdvLetterHeaderCZZ."Posting Description", GenJournalLine); - GenJournalLine."Document Type" := GenJournalLine."Document Type"::Invoice; - GenJournalLine.Validate("Posting Date", PostingDate); -#if not CLEAN22 -#pragma warning disable AL0432 - if not ReplaceVATDateMgtCZL.IsEnabled() then - GenJournalLine.Validate("VAT Date CZL", VATDate) - else -#pragma warning restore AL0432 -#endif - GenJournalLine.Validate("VAT Reporting Date", VATDate); - GenJournalLine."Account No." := VATPostingSetup."Sales Adv. Letter Account CZZ"; - GenJournalLine.SetCurrencyFactor(SalesAdvLetterEntryCZZ."Currency Code", SalesAdvLetterEntryCZZ."Currency Factor"); - GenJournalLine."Gen. Posting Type" := GenJournalLine."Gen. Posting Type"::Sale; - GenJournalLine."VAT Calculation Type" := TempAdvancePostingBufferCZZ."VAT Calculation Type"; - GenJournalLine."VAT Bus. Posting Group" := TempAdvancePostingBufferCZZ."VAT Bus. Posting Group"; - GenJournalLine.validate("VAT Prod. Posting Group", TempAdvancePostingBufferCZZ."VAT Prod. Posting Group"); - GenJournalLine.Validate(Amount, TempAdvancePostingBufferCZZ.Amount); - GenJournalLine."VAT Amount" := TempAdvancePostingBufferCZZ."VAT Amount"; - GenJournalLine."VAT Base Amount" := TempAdvancePostingBufferCZZ."VAT Base 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)" := TempAdvancePostingBufferCZZ."Amount (ACY)"; - GenJournalLine."VAT Amount (LCY)" := TempAdvancePostingBufferCZZ."VAT Amount (ACY)"; - GenJournalLine."VAT Base Amount (LCY)" := TempAdvancePostingBufferCZZ."VAT Base Amount (ACY)"; - GenJournalLine."Currency Factor" := GenJournalLine.Amount / GenJournalLine."Amount (LCY)"; - end else begin - GenJournalLine."Amount (LCY)" := GenJournalLine.Amount; - GenJournalLine."VAT Amount (LCY)" := GenJournalLine."VAT Amount"; - GenJournalLine."VAT Base Amount (LCY)" := GenJournalLine."VAT Base Amount"; - end; - GenJournalLine."Bill-to/Pay-to No." := SalesAdvLetterHeaderCZZ."Bill-to Customer No."; - GenJournalLine."Country/Region Code" := SalesAdvLetterHeaderCZZ."Bill-to Country/Region Code"; - GenJournalLine."VAT Registration No." := SalesAdvLetterHeaderCZZ."VAT Registration No."; - GenJournalLine."Registration No. CZL" := SalesAdvLetterHeaderCZZ."Registration No."; - GenJournalLine."Tax Registration No. CZL" := SalesAdvLetterHeaderCZZ."Tax Registration No."; - OnPostAdvancePaymentVATOnBeforeGenJnlPostLine(SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, GenJournalLine); - - BindSubscription(VATPostingSetupHandlerCZZ); - BindSubscription(DocumentTypeHandlerCZZ); - GenJnlPostLine.RunWithCheck(GenJournalLine); - UnbindSubscription(VATPostingSetupHandlerCZZ); - UnbindSubscription(DocumentTypeHandlerCZZ); + Clear(AdvancePostingParametersCZZ); + AdvancePostingParametersCZZ."Document Type" := Enum::"Gen. Journal Document Type"::Invoice; + AdvancePostingParametersCZZ."Document No." := DocumentNo; + AdvancePostingParametersCZZ."Posting Description" := SalesAdvLetterHeaderCZZ."Posting Description"; + AdvancePostingParametersCZZ."Posting Date" := PostingDate; + AdvancePostingParametersCZZ."VAT Date" := VATDate; + AdvancePostingParametersCZZ."Original Document VAT Date" := VATDate; + AdvancePostingParametersCZZ."Currency Code" := SalesAdvLetterEntryCZZ."Currency Code"; + AdvancePostingParametersCZZ."Currency Factor" := SalesAdvLetterEntryCZZ."Currency Factor"; -#if not CLEAN22 -#pragma warning disable AL0432 - if not ReplaceVATDateMgtCZL.IsEnabled() then - GenJournalLine."VAT Reporting Date" := GenJournalLine."VAT Date CZL"; -#pragma warning restore AL0432 -#endif - AdvEntryInit(false); - AdvEntryInitRelatedEntry(SalesAdvLetterEntryCZZ."Entry No."); - AdvEntryInitVAT(GenJournalLine."VAT Bus. Posting Group", GenJournalLine."VAT Prod. Posting Group", GenJournalLine."VAT Reporting Date", - 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 Payment", SalesAdvLetterHeaderCZZ."No.", GenJournalLine."Posting Date", - GenJournalLine.Amount, GenJournalLine."Amount (LCY)", - GenJournalLine."Currency Code", GenJournalLine."Currency Factor", GenJournalLine."Document No.", - GenJournalLine."Shortcut Dimension 1 Code", GenJournalLine."Shortcut Dimension 2 Code", GenJournalLine."Dimension Set ID", false); - - InitGenJnlLineFromAdvance(SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, DocumentNo, CustLedgerEntry."Source Code", SalesAdvLetterHeaderCZZ."Posting Description", GenJournalLine); - GenJournalLine.Validate("Posting Date", PostingDate); -#if not CLEAN22 -#pragma warning disable AL0432 - if not ReplaceVATDateMgtCZL.IsEnabled() then - GenJournalLine.Validate("VAT Date CZL", VATDate) - else -#pragma warning restore AL0432 -#endif - GenJournalLine.Validate("VAT Reporting Date", VATDate); - GenJournalLine."Account No." := VATPostingSetup."Sales Adv. Letter Account CZZ"; - GenJournalLine.SetCurrencyFactor(SalesAdvLetterEntryCZZ."Currency Code", SalesAdvLetterEntryCZZ."Currency Factor"); - GenJournalLine.Validate(Amount, -TempAdvancePostingBufferCZZ.Amount); - if GenJournalLine."Currency Code" <> '' then begin - GenJournalLine."Amount (LCY)" := -TempAdvancePostingBufferCZZ."Amount (ACY)"; - GenJournalLine."Currency Factor" := GenJournalLine.Amount / GenJournalLine."Amount (LCY)"; - end; - GenJnlPostLine.RunWithCheck(GenJournalLine); - until TempAdvancePostingBufferCZZ.Next() = 0; + SalesAdvLetterPostCZZ.PostAdvancePaymentVAT( + SalesAdvLetterEntryCZZ, TempAdvancePostingBufferCZZ, GenJnlPostLine, AdvancePostingParametersCZZ); end; local procedure InitVATAmountLine(var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; AdvanceNo: Code[20]; Amount: Decimal; CurrencyFactor: Decimal) var SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; TempAdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ" temporary; + AmountRemainder: Decimal; Coeff: Decimal; begin AdvancePostingBufferCZZ.Reset(); @@ -583,6 +422,7 @@ codeunit 31002 "SalesAdvLetterManagement CZZ" SalesAdvLetterHeaderCZZ.CalcFields("Amount Including VAT"); Coeff := Amount / SalesAdvLetterHeaderCZZ."Amount Including VAT"; + AmountRemainder := 0; BufferAdvanceLines(SalesAdvLetterHeaderCZZ, TempAdvancePostingBufferCZZ); TempAdvancePostingBufferCZZ.SetFilter(Amount, '<>0'); @@ -590,9 +430,12 @@ codeunit 31002 "SalesAdvLetterManagement CZZ" repeat AdvancePostingBufferCZZ.Init(); AdvancePostingBufferCZZ := TempAdvancePostingBufferCZZ; - AdvancePostingBufferCZZ.RecalcAmountsByCoefficient(Coeff); + AmountRemainder += AdvancePostingBufferCZZ.Amount * Coeff; + AdvancePostingBufferCZZ.Amount := AmountRemainder; + AdvancePostingBufferCZZ.UpdateVATAmounts(); AdvancePostingBufferCZZ.UpdateLCYAmounts(SalesAdvLetterHeaderCZZ."Currency Code", CurrencyFactor); AdvancePostingBufferCZZ.Insert(); + AmountRemainder -= AdvancePostingBufferCZZ.Amount; until TempAdvancePostingBufferCZZ.Next() = 0; end; @@ -610,18 +453,6 @@ codeunit 31002 "SalesAdvLetterManagement CZZ" SalesAdvLetterEntryCZZ2.EmailRecords(true); end; - local procedure CalculateAmountLCY(var GenJournalLine: Record "Gen. Journal Line") - var - CurrencyExchangeRate: Record "Currency Exchange Rate"; - begin - if (GenJournalLine."Currency Code" = '') or (GenJournalLine."Amount (LCY)" = 0) then - exit; - - GenJournalLine."Amount (LCY)" := Round(CurrencyExchangeRate.ExchangeAmtFCYToLCY(GenJournalLine."Posting Date", GenJournalLine."Currency Code", GenJournalLine.Amount, GenJournalLine."Currency Factor")); - GenJournalLine."VAT Base Amount (LCY)" := Round(CurrencyExchangeRate.ExchangeAmtFCYToLCY(GenJournalLine."Posting Date", GenJournalLine."Currency Code", GenJournalLine."VAT Base Amount", GenJournalLine."Currency Factor")); - GenJournalLine."VAT Amount (LCY)" := GenJournalLine."Amount (LCY)" - GenJournalLine."VAT Base Amount (LCY)"; - end; - local procedure BufferAdvanceLines(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ") var SalesAdvLetterLineCZZ: Record "Sales Adv. Letter Line CZZ"; @@ -639,16 +470,6 @@ codeunit 31002 "SalesAdvLetterManagement CZZ" until SalesAdvLetterLineCZZ.Next() = 0; end; - local procedure GetCurrency(CurrencyCode: Code[10]) - begin - if CurrencyCode = '' then - CurrencyGlob.InitRoundingPrecision() - else begin - CurrencyGlob.Get(CurrencyCode); - CurrencyGlob.TestField("Amount Rounding Precision"); - end; - end; - procedure LinkAdvanceLetter(AdvLetterUsageDocTypeCZZ: Enum "Adv. Letter Usage Doc.Type CZZ"; DocumentNo: Code[20]; BillToCustomerNo: Code[20]; PostingDate: Date; CurrencyCode: Code[10]) var TempAdvanceLetterApplicationCZZ: Record "Advance Letter Application CZZ" temporary; @@ -732,19 +553,10 @@ codeunit 31002 "SalesAdvLetterManagement CZZ" procedure UnlinkAdvancePayment(var SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; PostingDate: Date) var + AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; SalesAdvLetterEntryCZZ2: Record "Sales Adv. Letter Entry CZZ"; - SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; - VATPostingSetup: Record "VAT Posting Setup"; - GenJournalLine: Record "Gen. Journal Line"; - CustLedgerEntryPay: Record "Cust. Ledger Entry"; - CustLedgerEntryAdv: Record "Cust. Ledger Entry"; - CustLedgerEntry: Record "Cust. Ledger Entry"; AdvanceLetterApplicationCZZ: Record "Advance Letter Application CZZ"; - DocumentTypeHandlerCZZ: Codeunit "Document Type Handler CZZ"; GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; - VATPostingSetupHandlerCZZ: Codeunit "VAT Posting Setup Handler CZZ"; - GenJnlCheckLnHandlerCZZ: Codeunit "Gen.Jnl.-Check Ln. Handler CZZ"; - ApplId: Code[50]; UsedOnDocument: Text; UnlinkIsNotPossibleErr: Label 'Unlink is not possible, because %1 entry exists.', Comment = '%1 = Entry type'; UsedOnDocumentQst: Label 'Advance is used on document(s) %1.\Continue?', Comment = '%1 = Advance No. list'; @@ -770,211 +582,22 @@ codeunit 31002 "SalesAdvLetterManagement CZZ" if not Confirm(UsedOnDocumentQst, false, UsedOnDocument) then Error(''); - SalesAdvLetterHeaderCZZ.Get(SalesAdvLetterEntryCZZ."Sales Adv. Letter No."); - GetCurrency(SalesAdvLetterHeaderCZZ."Currency Code"); - - SalesAdvLetterEntryCZZ2.SetRange("Entry Type", SalesAdvLetterEntryCZZ2."Entry Type"::"VAT Payment"); - if SalesAdvLetterEntryCZZ2.FindSet() then begin - repeat - VATPostingSetup.Get(SalesAdvLetterEntryCZZ2."VAT Bus. Posting Group", SalesAdvLetterEntryCZZ2."VAT Prod. Posting Group"); - VATPostingSetup.TestField("Sales Adv. Letter Account CZZ"); - VATPostingSetup.TestField("Sales Adv. Letter VAT Acc. CZZ"); - - InitGenJnlLineFromAdvance(SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ2, SalesAdvLetterEntryCZZ2."Document No.", '', '', GenJournalLine); - GenJournalLine."Document Type" := GenJournalLine."Document Type"::Invoice; - GenJournalLine.Validate("Posting Date", SalesAdvLetterEntryCZZ2."Posting Date"); - GenJournalLine."Account No." := VATPostingSetup."Sales Adv. Letter Account CZZ"; - GenJournalLine.SetCurrencyFactor(SalesAdvLetterEntryCZZ2."Currency Code", SalesAdvLetterEntryCZZ2."Currency Factor"); - GenJournalLine."Gen. Posting Type" := GenJournalLine."Gen. Posting Type"::Sale; - GenJournalLine."VAT Calculation Type" := SalesAdvLetterEntryCZZ2."VAT Calculation Type"; - GenJournalLine."VAT Bus. Posting Group" := SalesAdvLetterEntryCZZ2."VAT Bus. Posting Group"; - GenJournalLine.Validate("VAT Prod. Posting Group", SalesAdvLetterEntryCZZ2."VAT Prod. Posting Group"); - GenJournalLine.Validate(Amount, -SalesAdvLetterEntryCZZ2.Amount); - GenJournalLine."VAT Amount" := -SalesAdvLetterEntryCZZ2."VAT Amount"; - GenJournalLine."VAT Base Amount" := -SalesAdvLetterEntryCZZ2."VAT Base Amount"; - GenJournalLine."VAT Difference" := GenJournalLine."VAT Amount" - Round(GenJournalLine.Amount * GenJournalLine."VAT %" / (100 + GenJournalLine."VAT %"), - CurrencyGlob."Amount Rounding Precision", CurrencyGlob.VATRoundingDirection()); - GenJournalLine."Amount (LCY)" := -SalesAdvLetterEntryCZZ2."Amount (LCY)"; - GenJournalLine."VAT Amount (LCY)" := -SalesAdvLetterEntryCZZ2."VAT Amount (LCY)"; - GenJournalLine."VAT Base Amount (LCY)" := -SalesAdvLetterEntryCZZ2."VAT Base Amount (LCY)"; - BindSubscription(VATPostingSetupHandlerCZZ); - BindSubscription(DocumentTypeHandlerCZZ); - GenJnlPostLine.RunWithCheck(GenJournalLine); - UnbindSubscription(VATPostingSetupHandlerCZZ); - UnbindSubscription(DocumentTypeHandlerCZZ); + Clear(AdvancePostingParametersCZZ); + AdvancePostingParametersCZZ."Posting Date" := PostingDate; -#if not CLEAN22 -#pragma warning disable AL0432 - if not ReplaceVATDateMgtCZL.IsEnabled() then - GenJournalLine."VAT Reporting Date" := GenJournalLine."VAT Date CZL"; -#pragma warning restore AL0432 -#endif - AdvEntryInit(false); - AdvEntryInitRelatedEntry(SalesAdvLetterEntryCZZ."Entry No."); - AdvEntryInitCancel(); - AdvEntryInitVAT(GenJournalLine."VAT Bus. Posting Group", GenJournalLine."VAT Prod. Posting Group", GenJournalLine."VAT Reporting Date", - 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(SalesAdvLetterEntryCZZ2."Entry Type", SalesAdvLetterEntryCZZ2."Sales Adv. Letter No.", GenJournalLine."Posting Date", - GenJournalLine.Amount, GenJournalLine."Amount (LCY)", - GenJournalLine."Currency Code", GenJournalLine."Currency Factor", GenJournalLine."Document No.", - GenJournalLine."Shortcut Dimension 1 Code", GenJournalLine."Shortcut Dimension 2 Code", GenJournalLine."Dimension Set ID", false); - - InitGenJnlLineFromAdvance(SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ2, SalesAdvLetterEntryCZZ2."Document No.", '', '', GenJournalLine); - GenJournalLine.Validate("Posting Date", SalesAdvLetterEntryCZZ2."Posting Date"); - GenJournalLine."Account No." := VATPostingSetup."Sales Adv. Letter Account CZZ"; - GenJournalLine.SetCurrencyFactor(SalesAdvLetterEntryCZZ2."Currency Code", SalesAdvLetterEntryCZZ2."Currency Factor"); - GenJournalLine.Amount := SalesAdvLetterEntryCZZ2.Amount; - GenJournalLine."Amount (LCY)" := SalesAdvLetterEntryCZZ2."Amount (LCY)"; - GenJnlPostLine.RunWithCheck(GenJournalLine); - until SalesAdvLetterEntryCZZ2.Next() = 0; - SalesAdvLetterEntryCZZ2.ModifyAll(Cancelled, true); - end; - - CustLedgerEntryAdv.Get(SalesAdvLetterEntryCZZ."Cust. Ledger Entry No."); - CustLedgerEntryPay := CustLedgerEntryAdv; -#pragma warning disable AA0181 - CustLedgerEntryPay.Next(-1); -#pragma warning restore AA0181 - UnapplyCustLedgEntry(CustLedgerEntryPay, GenJnlPostLine); - - InitGenJnlLineFromCustLedgEntry(CustLedgerEntryAdv, GenJournalLine, GenJournalLine."Document Type"::" "); - GenJournalLine."Posting Date" := PostingDate; - GenJournalLine."Adv. Letter Template Code CZZ" := SalesAdvLetterHeaderCZZ."Advance Letter Code"; - GenJournalLine.Correction := true; - GenJournalLine."Adv. Letter No. (Entry) CZZ" := SalesAdvLetterEntryCZZ."Sales Adv. Letter No."; - GenJournalLine."Use Advance G/L Account CZZ" := true; - GenJournalLine.SetCurrencyFactor(SalesAdvLetterEntryCZZ."Currency Code", SalesAdvLetterEntryCZZ."Currency Factor"); - GenJournalLine.Amount := -SalesAdvLetterEntryCZZ.Amount; - GenJournalLine."Amount (LCY)" := -SalesAdvLetterEntryCZZ."Amount (LCY)"; - ApplId := CopyStr(CustLedgerEntryAdv."Document No." + Format(CustLedgerEntryAdv."Entry No.", 0, ''), 1, MaxStrLen(ApplId)); - CustLedgerEntryAdv.Prepayment := false; - CustLedgerEntryAdv."Advance Letter No. CZZ" := SalesAdvLetterEntryCZZ."Sales Adv. Letter No."; - CustLedgerEntryAdv.CalcFields("Remaining Amount"); - CustLedgerEntryAdv."Amount to Apply" := CustLedgerEntryAdv."Remaining Amount"; - CustLedgerEntryAdv."Applies-to ID" := ApplId; - Codeunit.Run(Codeunit::"Cust. Entry-Edit", CustLedgerEntryAdv); - GenJournalLine."Applies-to ID" := ApplId; - GenJnlPostLine.RunWithCheck(GenJournalLine); - - CustLedgerEntry.FindLast(); - - AdvEntryInit(false); - AdvEntryInitCustLedgEntryNo(CustLedgerEntry."Entry No."); - AdvEntryInitCancel(); - AdvEntryInitRelatedEntry(SalesAdvLetterEntryCZZ."Entry No."); - AdvEntryInsert(SalesAdvLetterEntryCZZ."Entry Type", GenJournalLine."Adv. Letter No. (Entry) CZZ", GenJournalLine."Posting Date", - GenJournalLine.Amount, GenJournalLine."Amount (LCY)", - GenJournalLine."Currency Code", GenJournalLine."Currency Factor", GenJournalLine."Document No.", - GenJournalLine."Shortcut Dimension 1 Code", GenJournalLine."Shortcut Dimension 2 Code", GenJournalLine."Dimension Set ID", false); - - InitGenJnlLineFromCustLedgEntry(CustLedgerEntryAdv, GenJournalLine, GenJournalLine."Document Type"::" "); - GenJournalLine."Posting Date" := PostingDate; - GenJournalLine."Adv. Letter Template Code CZZ" := SalesAdvLetterHeaderCZZ."Advance Letter Code"; - GenJournalLine.SetCurrencyFactor(SalesAdvLetterEntryCZZ."Currency Code", SalesAdvLetterEntryCZZ."Currency Factor"); - GenJournalLine.Amount := SalesAdvLetterEntryCZZ.Amount; - GenJournalLine."Amount (LCY)" := SalesAdvLetterEntryCZZ."Amount (LCY)"; - ApplId := CopyStr(CustLedgerEntryPay."Document No." + Format(CustLedgerEntryPay."Entry No.", 0, ''), 1, MaxStrLen(ApplId)); - CustLedgerEntryPay.CalcFields("Remaining Amount"); - CustLedgerEntryPay."Amount to Apply" := CustLedgerEntryPay."Remaining Amount"; - CustLedgerEntryPay."Applies-to ID" := ApplId; - Codeunit.Run(Codeunit::"Cust. Entry-Edit", CustLedgerEntryPay); - GenJournalLine."Applies-to ID" := ApplId; - GenJnlPostLine.RunWithCheck(GenJournalLine); - UnbindSubscription(GenJnlCheckLnHandlerCZZ); - - SalesAdvLetterEntryCZZ.Cancelled := true; - SalesAdvLetterEntryCZZ.Modify(); - - UpdateStatus(SalesAdvLetterHeaderCZZ, SalesAdvLetterHeaderCZZ.Status::"To Pay"); + SalesAdvLetterPostCZZ.PostAdvancePaymentUnlinking(SalesAdvLetterEntryCZZ, GenJnlPostLine, AdvancePostingParametersCZZ); end; procedure PostAdvancePaymentUsage(AdvLetterUsageDocTypeCZZ: Enum "Adv. Letter Usage Doc.Type CZZ"; DocumentNo: Code[20]; var SalesInvoiceHeader: Record "Sales Invoice Header"; var CustLedgerEntry: Record "Cust. Ledger Entry"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; Preview: Boolean) var AdvanceLetterApplicationCZZ: Record "Advance Letter Application CZZ"; - TempAdvanceLetterApplicationCZZ: Record "Advance Letter Application CZZ" temporary; - TempSalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ" temporary; - SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; - SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; - AdvanceLetterTypeCZZ: Enum "Advance Letter Type CZZ"; - AmountToUse, UseAmount, UseAmountLCY : Decimal; - IsHandled: Boolean; + AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; begin - OnBeforePostAdvancePaymentUsage(AdvLetterUsageDocTypeCZZ, DocumentNo, SalesInvoiceHeader, CustLedgerEntry, GenJnlPostLine, Preview, IsHandled); - if IsHandled then - exit; - - if CustLedgerEntry."Remaining Amount" = 0 then - CustLedgerEntry.CalcFields("Remaining Amount"); - - if CustLedgerEntry."Remaining Amount" = 0 then - exit; + AdvancePostingParametersCZZ."Temporary Entries Only" := Preview; AdvanceLetterApplicationCZZ.SetRange("Document Type", AdvLetterUsageDocTypeCZZ); AdvanceLetterApplicationCZZ.SetRange("Document No.", DocumentNo); - if AdvanceLetterApplicationCZZ.IsEmpty() then - exit; - - AdvanceLetterApplicationCZZ.FindSet(); - repeat - SalesAdvLetterHeaderCZZ.Get(AdvanceLetterApplicationCZZ."Advance Letter No."); - SalesAdvLetterHeaderCZZ.TestField("Currency Code", SalesInvoiceHeader."Currency Code"); - SalesAdvLetterHeaderCZZ.TestField("Bill-to Customer No.", SalesInvoiceHeader."Bill-to Customer No."); - - SalesAdvLetterEntryCZZ.SetRange("Sales Adv. Letter No.", AdvanceLetterApplicationCZZ."Advance Letter No."); - SalesAdvLetterEntryCZZ.SetRange(Cancelled, false); - SalesAdvLetterEntryCZZ.SetRange("Entry Type", SalesAdvLetterEntryCZZ."Entry Type"::Payment); - SalesAdvLetterEntryCZZ.SetFilter("Posting Date", '..%1', SalesInvoiceHeader."Posting Date"); - OnPostAdvancePaymentUsageOnBeforeLoopSalesAdvLetterEntry(AdvanceLetterApplicationCZZ, SalesAdvLetterEntryCZZ); - if SalesAdvLetterEntryCZZ.FindSet() then - repeat - TempSalesAdvLetterEntryCZZ := SalesAdvLetterEntryCZZ; - TempSalesAdvLetterEntryCZZ.Amount := GetRemAmtSalAdvPayment(SalesAdvLetterEntryCZZ, 0D); - if TempSalesAdvLetterEntryCZZ.Amount <> 0 then - TempSalesAdvLetterEntryCZZ.Insert(); - until SalesAdvLetterEntryCZZ.Next() = 0; - TempAdvanceLetterApplicationCZZ.Init(); - TempAdvanceLetterApplicationCZZ."Advance Letter No." := AdvanceLetterApplicationCZZ."Advance Letter No."; - TempAdvanceLetterApplicationCZZ.Amount := AdvanceLetterApplicationCZZ.Amount; - TempAdvanceLetterApplicationCZZ."Amount (LCY)" := AdvanceLetterApplicationCZZ."Amount (LCY)"; - TempAdvanceLetterApplicationCZZ.Insert(); - until AdvanceLetterApplicationCZZ.Next() = 0; - - AmountToUse := CustLedgerEntry."Remaining Amount"; - TempSalesAdvLetterEntryCZZ.Reset(); - TempSalesAdvLetterEntryCZZ.SetCurrentKey("Posting Date"); - if TempSalesAdvLetterEntryCZZ.FindSet() then - repeat - TempAdvanceLetterApplicationCZZ.Get(0, TempSalesAdvLetterEntryCZZ."Sales Adv. Letter No."); - if TempAdvanceLetterApplicationCZZ.Amount < TempSalesAdvLetterEntryCZZ.Amount then - TempSalesAdvLetterEntryCZZ.Amount := TempAdvanceLetterApplicationCZZ.Amount; - - if AmountToUse > TempSalesAdvLetterEntryCZZ.Amount then - UseAmount := TempSalesAdvLetterEntryCZZ.Amount - else - UseAmount := AmountToUse; - - if UseAmount <> 0 then begin - SalesAdvLetterEntryCZZ.Get(TempSalesAdvLetterEntryCZZ."Entry No."); - UseAmountLCY := Round(GetRemAmtLCYSalAdvPayment(SalesAdvLetterEntryCZZ, 0D) * UseAmount / GetRemAmtSalAdvPayment(SalesAdvLetterEntryCZZ, 0D)); - ReverseAdvancePayment(SalesAdvLetterEntryCZZ, UseAmount, UseAmountLCY, SalesInvoiceHeader."No.", CustLedgerEntry, GenJnlPostLine, Preview); - AmountToUse -= UseAmount; - TempAdvanceLetterApplicationCZZ.Amount -= UseAmount; - TempAdvanceLetterApplicationCZZ."Amount (LCY)" -= UseAmountLCY; - TempAdvanceLetterApplicationCZZ.Modify(); - - if not Preview then - if AdvanceLetterApplicationCZZ.Get(AdvanceLetterTypeCZZ::Sales, SalesAdvLetterEntryCZZ."Sales Adv. Letter No.", AdvLetterUsageDocTypeCZZ, DocumentNo) then - if AdvanceLetterApplicationCZZ.Amount <= UseAmount then - AdvanceLetterApplicationCZZ.Delete(true) - else begin - AdvanceLetterApplicationCZZ.Amount -= UseAmount; - AdvanceLetterApplicationCZZ.Modify(); - end; - end; - until (TempSalesAdvLetterEntryCZZ.Next() = 0) or (AmountToUse = 0); - - OnAfterPostAdvancePaymentUsage(AdvLetterUsageDocTypeCZZ, DocumentNo, SalesInvoiceHeader, CustLedgerEntry, GenJnlPostLine, Preview); + SalesAdvLetterPostCZZ.PostAdvancePaymentUsage(SalesInvoiceHeader, AdvanceLetterApplicationCZZ, GenJnlPostLine, AdvancePostingParametersCZZ); end; procedure CorrectDocumentAfterPaymentUsage(DocumentNo: Code[20]; var CustLedgerEntry: Record "Cust. Ledger Entry"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line") @@ -1081,7 +704,7 @@ codeunit 31002 "SalesAdvLetterManagement CZZ" GenJournalLine."Gen. Posting Type" := GenJournalLine."Gen. Posting Type"::Sale; GenJournalLine."VAT Calculation Type" := SalesInvoiceLine."VAT Calculation Type"; GenJournalLine."VAT Bus. Posting Group" := SalesInvoiceLine."VAT Bus. Posting Group"; - GenJournalLine.validate("VAT Prod. Posting Group", SalesInvoiceLine."VAT Prod. Posting Group"); + GenJournalLine.Validate("VAT Prod. Posting Group", SalesInvoiceLine."VAT Prod. Posting Group"); GenJournalLine."Bill-to/Pay-to No." := SalesInvoiceHeader."Bill-to Customer No."; GenJournalLine."Country/Region Code" := SalesInvoiceHeader."Bill-to Country/Region Code"; GenJournalLine."VAT Registration No." := SalesInvoiceHeader."VAT Registration No."; @@ -1095,536 +718,49 @@ codeunit 31002 "SalesAdvLetterManagement CZZ" GenJnlPostLine.RunWithCheck(GenJournalLine); end; - local procedure ReverseAdvancePayment(var SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; ReverseAmount: Decimal; ReverseAmountLCY: Decimal; DocumentNo: Code[20]; var CustLedgerEntry: Record "Cust. Ledger Entry"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; Preview: Boolean) - var - GenJournalLine: Record "Gen. Journal Line"; - SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; - CustLedgerEntry2: Record "Cust. Ledger Entry"; - DocumentTypeHandlerCZZ: Codeunit "Document Type Handler CZZ"; - GenJnlCheckLnHandlerCZZ: Codeunit "Gen.Jnl.-Check Ln. Handler CZZ"; - RemainingAmount: Decimal; - RemainingAmountLCY: Decimal; - ApplId: Code[50]; - ReverseErr: Label 'Reverse amount %1 is not posible on entry %2.', Comment = '%1 = Reverse Amount, %2 = Sales Advance Entry No.'; - begin - RemainingAmount := GetRemAmtSalAdvPayment(SalesAdvLetterEntryCZZ, 0D); - RemainingAmountLCY := GetRemAmtLCYSalAdvPayment(SalesAdvLetterEntryCZZ, 0D); - - if ReverseAmount <> 0 then begin - if ReverseAmount > RemainingAmount then - Error(ReverseErr, ReverseAmount, SalesAdvLetterEntryCZZ."Entry No."); - end else begin - ReverseAmount := RemainingAmount; - ReverseAmountLCY := RemainingAmountLCY; - end; - - SalesAdvLetterHeaderCZZ.Get(SalesAdvLetterEntryCZZ."Sales Adv. Letter No."); - - InitGenJnlLineFromCustLedgEntry(CustLedgerEntry, GenJournalLine, GenJournalLine."Document Type"::" "); - GenJournalLine."Adv. Letter Template Code CZZ" := SalesAdvLetterHeaderCZZ."Advance Letter Code"; - GenJournalLine.Correction := true; - GenJournalLine.SetCurrencyFactor(SalesAdvLetterEntryCZZ."Currency Code", SalesAdvLetterEntryCZZ."Currency Factor"); - GenJournalLine.Amount := -ReverseAmount; - GenJournalLine."Amount (LCY)" := -ReverseAmountLCY; - - if not Preview then begin - ApplId := CopyStr(CustLedgerEntry."Document No." + Format(CustLedgerEntry."Entry No.", 0, ''), 1, MaxStrLen(ApplId)); - CustLedgerEntry.CalcFields("Remaining Amount"); - CustLedgerEntry."Adv. Letter Template Code CZZ" := SalesAdvLetterHeaderCZZ."Advance Letter Code"; - CustLedgerEntry."Amount to Apply" := CustLedgerEntry."Remaining Amount"; - CustLedgerEntry."Applies-to ID" := ApplId; - Codeunit.Run(Codeunit::"Cust. Entry-Edit", CustLedgerEntry); - GenJournalLine."Applies-to ID" := ApplId; - - OnBeforePostReversePaymentRepos(GenJournalLine, SalesAdvLetterHeaderCZZ); - BindSubscription(GenJnlCheckLnHandlerCZZ); - GenJnlPostLine.RunWithCheck(GenJournalLine); - OnAfterPostReversePaymentRepos(GenJournalLine, SalesAdvLetterHeaderCZZ); - end; - - InitGenJnlLineFromCustLedgEntry(CustLedgerEntry, GenJournalLine, GenJournalLine."Document Type"::Invoice); - GenJournalLine."Adv. Letter Template Code CZZ" := SalesAdvLetterHeaderCZZ."Advance Letter Code"; - GenJournalLine."Adv. Letter No. (Entry) CZZ" := SalesAdvLetterEntryCZZ."Sales Adv. Letter No."; - GenJournalLine."Use Advance G/L Account CZZ" := true; - GenJournalLine.SetCurrencyFactor(SalesAdvLetterEntryCZZ."Currency Code", SalesAdvLetterEntryCZZ."Currency Factor"); - GenJournalLine.Amount := ReverseAmount; - GenJournalLine."Amount (LCY)" := ReverseAmountLCY; - - CustLedgerEntry2.Get(SalesAdvLetterEntryCZZ."Cust. Ledger Entry No."); - if not Preview then begin - ApplId := CopyStr(CustLedgerEntry2."Document No." + Format(CustLedgerEntry2."Entry No.", 0, ''), 1, MaxStrLen(ApplId)); - CustLedgerEntry2.Prepayment := false; - CustLedgerEntry2."Advance Letter No. CZZ" := SalesAdvLetterEntryCZZ."Sales Adv. Letter No."; - CustLedgerEntry2.Modify(); - CustLedgerEntry2.CalcFields("Remaining Amount"); - CustLedgerEntry2."Amount to Apply" := CustLedgerEntry2."Remaining Amount"; - CustLedgerEntry2."Applies-to ID" := ApplId; - Codeunit.Run(Codeunit::"Cust. Entry-Edit", CustLedgerEntry2); - GenJournalLine."Applies-to ID" := ApplId; - - OnBeforePostReversePayment(GenJournalLine, SalesAdvLetterHeaderCZZ); - BindSubscription(DocumentTypeHandlerCZZ); - GenJnlPostLine.RunWithCheck(GenJournalLine); - UnbindSubscription(GenJnlCheckLnHandlerCZZ); - UnbindSubscription(DocumentTypeHandlerCZZ); - OnAfterPostReversePayment(GenJournalLine, SalesAdvLetterHeaderCZZ); - - CustLedgerEntry2.FindLast(); - end; - - AdvEntryInit(Preview); - AdvEntryInitCustLedgEntryNo(CustLedgerEntry2."Entry No."); - AdvEntryInitRelatedEntry(SalesAdvLetterEntryCZZ."Entry No."); - AdvEntryInsert("Advance Letter Entry Type CZZ"::Usage, GenJournalLine."Adv. Letter No. (Entry) CZZ", GenJournalLine."Posting Date", - GenJournalLine.Amount, GenJournalLine."Amount (LCY)", - GenJournalLine."Currency Code", GenJournalLine."Currency Factor", DocumentNo, - GenJournalLine."Shortcut Dimension 1 Code", GenJournalLine."Shortcut Dimension 2 Code", GenJournalLine."Dimension Set ID", Preview); - - if SalesAdvLetterHeaderCZZ."Automatic Post VAT Document" then - ReverseAdvancePaymentVAT(SalesAdvLetterEntryCZZ, CustLedgerEntry."Source Code", CustLedgerEntry.Description, - ReverseAmount, CustLedgerEntry."Original Currency Factor", Enum::"Gen. Journal Document Type"::Invoice, - DocumentNo, CustLedgerEntry."Posting Date", CustLedgerEntry."VAT Date CZL", SalesAdvLetterEntryCZZGlob."Entry No.", - CustLedgerEntry."Document No.", "Advance Letter Entry Type CZZ"::"VAT Usage", GenJnlPostLine, Preview); - - if not Preview then begin - SalesAdvLetterHeaderCZZ.Get(SalesAdvLetterEntryCZZ."Sales Adv. Letter No."); - UpdateStatus(SalesAdvLetterHeaderCZZ, SalesAdvLetterHeaderCZZ.Status::Closed); - end; - end; - - local procedure ReverseAdvancePaymentVAT(var SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; SourceCode: Code[10]; PostDescription: Text[100]; ReverseAmount: Decimal; CurrencyFactor: Decimal; DocumentType: Enum "Gen. Journal Document Type"; DocumentNo: Code[20]; PostingDate: Date; VATDate: Date; UsageEntryNo: Integer; InvoiceNo: Code[20]; EntryType: enum "Advance Letter Entry Type CZZ"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; Preview: Boolean) - var - SalesAdvLetterEntryCZZ2: Record "Sales Adv. Letter Entry CZZ"; - TempAdvancePostingBufferCZZ1: Record "Advance Posting Buffer CZZ" temporary; - TempAdvancePostingBufferCZZ2: Record "Advance Posting Buffer CZZ" temporary; - GenJournalLine: Record "Gen. Journal Line"; - VATPostingSetup: Record "VAT Posting Setup"; - SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; - DocumentTypeHandlerCZZ: Codeunit "Document Type Handler CZZ"; - VATPostingSetupHandlerCZZ: Codeunit "VAT Posting Setup Handler CZZ"; - CalcVATAmountLCY: Decimal; - CalcAmountLCY: Decimal; - ExchRateAmount: Decimal; - ExchRateVATAmount: Decimal; - AmountToUse: Decimal; - IsHandled: Boolean; - begin - OnBeforePostReversePaymentVAT(SalesAdvLetterEntryCZZ, PostingDate, Preview, IsHandled); - if IsHandled then - exit; - - 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 - exit; - - GetCurrency(SalesAdvLetterEntryCZZ."Currency Code"); - SalesAdvLetterHeaderCZZ.Get(SalesAdvLetterEntryCZZ."Sales Adv. Letter No."); - - BufferAdvanceVATLines(SalesAdvLetterEntryCZZ, TempAdvancePostingBufferCZZ1, 0D); - - SuggestUsageVAT(SalesAdvLetterEntryCZZ, TempAdvancePostingBufferCZZ1, InvoiceNo, ReverseAmount, Preview); - - if SalesAdvLetterEntryCZZ."Currency Code" <> '' then begin - BufferAdvanceVATLines(SalesAdvLetterEntryCZZ, TempAdvancePostingBufferCZZ2, 0D); - TempAdvancePostingBufferCZZ2.CalcSums(Amount); - AmountToUse := TempAdvancePostingBufferCZZ2.Amount; - end; - - TempAdvancePostingBufferCZZ1.SetFilter(Amount, '<>0'); - if TempAdvancePostingBufferCZZ1.FindSet() then - repeat - VATPostingSetup.Get(TempAdvancePostingBufferCZZ1."VAT Bus. Posting Group", TempAdvancePostingBufferCZZ1."VAT Prod. Posting Group"); - VATPostingSetup.TestField("Sales Adv. Letter Account CZZ"); - VATPostingSetup.TestField("Sales Adv. Letter VAT Acc. CZZ"); - - InitGenJnlLineFromAdvance(SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, DocumentNo, SourceCode, PostDescription, GenJournalLine); - GenJournalLine."Document Type" := DocumentType; - GenJournalLine.Validate("Posting Date", PostingDate); -#if not CLEAN22 -#pragma warning disable AL0432 - if not ReplaceVATDateMgtCZL.IsEnabled() then - GenJournalLine.Validate("VAT Date CZL", VATDate) - else -#pragma warning restore AL0432 -#endif - GenJournalLine.Validate("VAT Reporting Date", VATDate); - GenJournalLine."Account No." := VATPostingSetup."Sales Adv. Letter Account CZZ"; - GenJournalLine.SetCurrencyFactor(SalesAdvLetterEntryCZZ."Currency Code", CurrencyFactor); - GenJournalLine."Gen. Posting Type" := GenJournalLine."Gen. Posting Type"::Sale; - GenJournalLine."VAT Calculation Type" := TempAdvancePostingBufferCZZ1."VAT Calculation Type"; - GenJournalLine."VAT Bus. Posting Group" := TempAdvancePostingBufferCZZ1."VAT Bus. Posting Group"; - GenJournalLine.validate("VAT Prod. Posting Group", TempAdvancePostingBufferCZZ1."VAT Prod. Posting Group"); - GenJournalLine.Validate(Amount, -TempAdvancePostingBufferCZZ1.Amount); - GenJournalLine."VAT Amount" := -Round(TempAdvancePostingBufferCZZ1."VAT Amount", CurrencyGlob."Amount Rounding Precision", CurrencyGlob.VATRoundingDirection()); - 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 - CalculateAmountLCY(GenJournalLine); - if not Preview then begin - BindSubscription(VATPostingSetupHandlerCZZ); - BindSubscription(DocumentTypeHandlerCZZ); - GenJnlPostLine.RunWithCheck(GenJournalLine); - UnbindSubscription(VATPostingSetupHandlerCZZ); - UnbindSubscription(DocumentTypeHandlerCZZ); - end; - -#if not CLEAN22 -#pragma warning disable AL0432 - if not ReplaceVATDateMgtCZL.IsEnabled() then - GenJournalLine."VAT Reporting Date" := GenJournalLine."VAT Date CZL"; -#pragma warning restore AL0432 -#endif - AdvEntryInit(Preview); - AdvEntryInitRelatedEntry(UsageEntryNo); - AdvEntryInitVAT(GenJournalLine."VAT Bus. Posting Group", GenJournalLine."VAT Prod. Posting Group", GenJournalLine."VAT Reporting Date", - 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(EntryType, SalesAdvLetterEntryCZZ."Sales Adv. Letter No.", GenJournalLine."Posting Date", - GenJournalLine.Amount, GenJournalLine."Amount (LCY)", - GenJournalLine."Currency Code", GenJournalLine."Currency Factor", GenJournalLine."Document No.", - GenJournalLine."Shortcut Dimension 1 Code", GenJournalLine."Shortcut Dimension 2 Code", GenJournalLine."Dimension Set ID", Preview); - - if GenJournalLine."Currency Code" <> '' then begin - TempAdvancePostingBufferCZZ2.Reset(); - TempAdvancePostingBufferCZZ2.SetRange("VAT Bus. Posting Group", TempAdvancePostingBufferCZZ1."VAT Bus. Posting Group"); - TempAdvancePostingBufferCZZ2.SetRange("VAT Prod. Posting Group", TempAdvancePostingBufferCZZ1."VAT Prod. Posting Group"); - if TempAdvancePostingBufferCZZ2.FindFirst() then begin - CalcAmountLCY := Round(TempAdvancePostingBufferCZZ2."Amount (ACY)" * TempAdvancePostingBufferCZZ1.Amount / TempAdvancePostingBufferCZZ2.Amount); - CalcVATAmountLCY := Round(TempAdvancePostingBufferCZZ2."VAT Amount (ACY)" * TempAdvancePostingBufferCZZ1.Amount / TempAdvancePostingBufferCZZ2.Amount); - - ExchRateAmount := -CalcAmountLCY - GenJournalLine."Amount (LCY)"; - ExchRateVATAmount := -CalcVATAmountLCY - GenJournalLine."VAT Amount (LCY)"; - if (ExchRateAmount <> 0) or (ExchRateVATAmount <> 0) then - PostExchangeRate(ExchRateAmount, ExchRateVATAmount, SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, VATPostingSetup, - DocumentNo, PostingDate, VATDate, SourceCode, PostDescription, UsageEntryNo, false, GenJnlPostLine, Preview); - - ReverseUnrealizedExchangeRate(SalesAdvLetterEntryCZZ, SalesAdvLetterHeaderCZZ, VATPostingSetup, TempAdvancePostingBufferCZZ1.Amount / AmountToUse, - UsageEntryNo, DocumentNo, PostingDate, VATDate, PostDescription, GenJnlPostLine, Preview); - end; - end; - - InitGenJnlLineFromAdvance(SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, DocumentNo, SourceCode, PostDescription, GenJournalLine); - GenJournalLine.Validate("Posting Date", PostingDate); -#if not CLEAN22 -#pragma warning disable AL0432 - if not ReplaceVATDateMgtCZL.IsEnabled() then - GenJournalLine.Validate("VAT Date CZL", VATDate) - else -#pragma warning restore AL0432 -#endif - GenJournalLine.Validate("VAT Reporting Date", VATDate); - GenJournalLine."Account No." := VATPostingSetup."Sales Adv. Letter Account CZZ"; - GenJournalLine.SetCurrencyFactor(SalesAdvLetterEntryCZZ."Currency Code", CurrencyFactor); - GenJournalLine.Validate(Amount, TempAdvancePostingBufferCZZ1.Amount); - if not Preview then - GenJnlPostLine.RunWithCheck(GenJournalLine); - until TempAdvancePostingBufferCZZ1.Next() = 0; - - if not Preview then - UpdateStatus(SalesAdvLetterHeaderCZZ, SalesAdvLetterHeaderCZZ.Status::Closed); - end; - - local procedure SuggestUsageVAT(var SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; InvoiceNo: Code[20]; UsedAmount: Decimal; Preview: Boolean) - var - SalesInvoiceLine: Record "Sales Invoice Line"; - SalesLine: Record "Sales Line"; - TempAdvancePostingBufferCZZ1: Record "Advance Posting Buffer CZZ" temporary; - TempAdvancePostingBufferCZZ2: Record "Advance Posting Buffer CZZ" temporary; - TotalAmount: Decimal; - UseAmount: Decimal; - UseBaseAmount: Decimal; - i: Integer; - Continue: Boolean; - begin - AdvancePostingBufferCZZ.CalcSums(Amount); - TotalAmount := -AdvancePostingBufferCZZ.Amount; - if (UsedAmount <> 0) and (TotalAmount > UsedAmount) then begin - Continue := InvoiceNo <> ''; - if Continue then - if Preview then begin - SalesLine.SetFilter("Document Type", '%1|%2', SalesLine."Document Type"::Order, SalesLine."Document Type"::Invoice); - SalesLine.SetRange("Document No.", InvoiceNo); - Continue := SalesLine.FindSet(); - end else begin - SalesInvoiceLine.SetRange("Document No.", InvoiceNo); - Continue := SalesInvoiceLine.FindSet(); - end; - - if Continue then begin - BufferAdvanceVATLines(SalesAdvLetterEntryCZZ, TempAdvancePostingBufferCZZ2, 0D); - - if Preview then - repeat - TempAdvancePostingBufferCZZ1.Init(); - TempAdvancePostingBufferCZZ1."VAT Bus. Posting Group" := SalesLine."VAT Bus. Posting Group"; - TempAdvancePostingBufferCZZ1."VAT Prod. Posting Group" := SalesLine."VAT Prod. Posting Group"; - if TempAdvancePostingBufferCZZ1.Find() then begin - TempAdvancePostingBufferCZZ1.Amount -= SalesLine."Amount Including VAT"; - TempAdvancePostingBufferCZZ1."VAT Base Amount" -= SalesLine.Amount; - TempAdvancePostingBufferCZZ1.Modify(); - end else begin - TempAdvancePostingBufferCZZ1."VAT Calculation Type" := SalesLine."VAT Calculation Type"; - TempAdvancePostingBufferCZZ1."VAT %" := SalesLine."VAT %"; - TempAdvancePostingBufferCZZ1.Amount := -SalesLine."Amount Including VAT"; - TempAdvancePostingBufferCZZ1."VAT Base Amount" := -SalesLine.Amount; - TempAdvancePostingBufferCZZ1.Insert(); - end; - until SalesLine.Next() = 0 - else - repeat - TempAdvancePostingBufferCZZ1.Init(); - TempAdvancePostingBufferCZZ1."VAT Bus. Posting Group" := SalesInvoiceLine."VAT Bus. Posting Group"; - TempAdvancePostingBufferCZZ1."VAT Prod. Posting Group" := SalesInvoiceLine."VAT Prod. Posting Group"; - if TempAdvancePostingBufferCZZ1.Find() then begin - TempAdvancePostingBufferCZZ1.Amount -= SalesInvoiceLine."Amount Including VAT"; - TempAdvancePostingBufferCZZ1."VAT Base Amount" -= SalesInvoiceLine.Amount; - TempAdvancePostingBufferCZZ1.Modify(); - end else begin - TempAdvancePostingBufferCZZ1."VAT Calculation Type" := SalesInvoiceLine."VAT Calculation Type"; - TempAdvancePostingBufferCZZ1."VAT %" := SalesInvoiceLine."VAT %"; - TempAdvancePostingBufferCZZ1.Amount := -SalesInvoiceLine."Amount Including VAT"; - TempAdvancePostingBufferCZZ1."VAT Base Amount" := -SalesInvoiceLine.Amount; - TempAdvancePostingBufferCZZ1.Insert(); - end; - until SalesInvoiceLine.Next() = 0; - - GetCurrency(SalesAdvLetterEntryCZZ."Currency Code"); - - for i := 1 to 3 do begin - TempAdvancePostingBufferCZZ1.FindSet(); - repeat - case i of - 1: - begin - TempAdvancePostingBufferCZZ2.SetRange("VAT Bus. Posting Group", TempAdvancePostingBufferCZZ1."VAT Bus. Posting Group"); - TempAdvancePostingBufferCZZ2.SetRange("VAT Prod. Posting Group", TempAdvancePostingBufferCZZ1."VAT Prod. Posting Group"); - end; - 2: - begin - TempAdvancePostingBufferCZZ2.SetRange("VAT Calculation Type", TempAdvancePostingBufferCZZ1."VAT Calculation Type"); - TempAdvancePostingBufferCZZ2.SetRange("VAT %", TempAdvancePostingBufferCZZ1."VAT %"); - end; - end; - TempAdvancePostingBufferCZZ2.SetFilter(Amount, '<>%1', 0); - if TempAdvancePostingBufferCZZ2.FindSet() then - repeat - UseAmount := TempAdvancePostingBufferCZZ1.Amount; - UseBaseAmount := TempAdvancePostingBufferCZZ1."VAT Base Amount"; - if Abs(TempAdvancePostingBufferCZZ2.Amount) < Abs(UseAmount) then begin - UseAmount := TempAdvancePostingBufferCZZ2.Amount; - UseBaseAmount := TempAdvancePostingBufferCZZ2."VAT Base Amount"; - end; - if Abs(UsedAmount) < Abs(UseAmount) then begin - UseAmount := -UsedAmount; - UseBaseAmount := Round(TempAdvancePostingBufferCZZ2."VAT Base Amount" * UseAmount / TempAdvancePostingBufferCZZ2.Amount, CurrencyGlob."Amount Rounding Precision", CurrencyGlob.VATRoundingDirection()); - end; - if TempAdvancePostingBufferCZZ1."VAT %" <> TempAdvancePostingBufferCZZ2."VAT %" then - UseBaseAmount := Round(TempAdvancePostingBufferCZZ2."VAT Base Amount" * UseAmount / TempAdvancePostingBufferCZZ2.Amount, CurrencyGlob."Amount Rounding Precision", CurrencyGlob.VATRoundingDirection()); - - TempAdvancePostingBufferCZZ2.Amount -= UseAmount; - TempAdvancePostingBufferCZZ2."VAT Base Amount" -= UseBaseAmount; - TempAdvancePostingBufferCZZ2.Modify(); - TempAdvancePostingBufferCZZ1.Amount -= UseAmount; - TempAdvancePostingBufferCZZ1."VAT Base Amount" -= UseBaseAmount; - TempAdvancePostingBufferCZZ1.Modify(); - UsedAmount += UseAmount; - until (TempAdvancePostingBufferCZZ2.Next() = 0) or (UsedAmount = 0); - TempAdvancePostingBufferCZZ2.Reset(); - until TempAdvancePostingBufferCZZ1.Next() = 0; - end; - - if AdvancePostingBufferCZZ.FindSet() then - repeat - TempAdvancePostingBufferCZZ2.Get(AdvancePostingBufferCZZ."VAT Bus. Posting Group", AdvancePostingBufferCZZ."VAT Prod. Posting Group"); - case true of - TempAdvancePostingBufferCZZ2.Amount = 0: - ; - TempAdvancePostingBufferCZZ2.Amount <> AdvancePostingBufferCZZ.Amount: - begin - AdvancePostingBufferCZZ.Amount := AdvancePostingBufferCZZ.Amount - TempAdvancePostingBufferCZZ2.Amount; - AdvancePostingBufferCZZ."VAT Base Amount" := AdvancePostingBufferCZZ."VAT Base Amount" - TempAdvancePostingBufferCZZ2."VAT Base Amount"; - AdvancePostingBufferCZZ."VAT Amount" := AdvancePostingBufferCZZ.Amount - AdvancePostingBufferCZZ."VAT Base Amount"; - AdvancePostingBufferCZZ.Modify(); - end; - TempAdvancePostingBufferCZZ2.Amount = AdvancePostingBufferCZZ.Amount: - begin - AdvancePostingBufferCZZ.Amount := 0; - AdvancePostingBufferCZZ."VAT Base Amount" := 0; - AdvancePostingBufferCZZ."VAT Amount" := 0; - AdvancePostingBufferCZZ.Modify(); - end; - end; - until AdvancePostingBufferCZZ.Next() = 0; - end else begin - AdvancePostingBufferCZZ.FindSet(); - repeat - AdvancePostingBufferCZZ.Amount := Round(AdvancePostingBufferCZZ.Amount * UsedAmount / TotalAmount, CurrencyGlob."Amount Rounding Precision"); - AdvancePostingBufferCZZ."VAT Amount" := Round(AdvancePostingBufferCZZ."VAT Amount" * UsedAmount / TotalAmount, CurrencyGlob."Amount Rounding Precision", CurrencyGlob.VATRoundingDirection()); - AdvancePostingBufferCZZ."VAT Base Amount" := AdvancePostingBufferCZZ.Amount - AdvancePostingBufferCZZ."VAT Amount"; - AdvancePostingBufferCZZ.Modify(); - until AdvancePostingBufferCZZ.Next() = 0; - end; - end; - end; - procedure PostAdvancePaymentUsageVAT(var SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ") var - SalesAdvLetterEntry2: Record "Sales Adv. Letter Entry CZZ"; + AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; + SalesAdvLetterEntryCZZ2: Record "Sales Adv. Letter Entry CZZ"; CustLedgerEntry: Record "Cust. Ledger Entry"; SalesInvoiceHeader: Record "Sales Invoice Header"; + TempAdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ" temporary; GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; CurrencyFactor: Decimal; begin - if SalesAdvLetterEntryCZZ."Entry Type" <> SalesAdvLetterEntryCZZ."Entry Type"::Usage then - exit; - + SalesAdvLetterEntryCZZ.TestField("Entry Type", SalesAdvLetterEntryCZZ."Entry Type"::Usage); SalesAdvLetterEntryCZZ.TestField(Cancelled, false); - SalesAdvLetterEntry2.SetRange("Sales Adv. Letter No.", SalesAdvLetterEntryCZZ."Sales Adv. Letter No."); - SalesAdvLetterEntry2.SetRange(Cancelled, false); - SalesAdvLetterEntry2.SetRange("Related Entry", SalesAdvLetterEntryCZZ."Entry No."); - SalesAdvLetterEntry2.SetRange("Entry Type", SalesAdvLetterEntry2."Entry Type"::"VAT Usage"); - if not SalesAdvLetterEntry2.IsEmpty() then + 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 Usage"); + if not SalesAdvLetterEntryCZZ2.IsEmpty() then Error(VATDocumentExistsErr); - SalesAdvLetterEntry2.Get(SalesAdvLetterEntryCZZ."Related Entry"); - SalesAdvLetterEntry2.TestField(SalesAdvLetterEntry2."Entry Type", SalesAdvLetterEntry2."Entry Type"::Payment); + SalesAdvLetterEntryCZZ2.Get(SalesAdvLetterEntryCZZ."Related Entry"); + SalesAdvLetterEntryCZZ2.TestField("Entry Type", SalesAdvLetterEntryCZZ2."Entry Type"::Payment); CustLedgerEntry.Get(SalesAdvLetterEntryCZZ."Cust. Ledger Entry No."); if SalesInvoiceHeader.Get(CustLedgerEntry."Document No.") then - CurrencyFactor := SalesInvoiceHeader."Currency Factor" + CurrencyFactor := SalesInvoiceHeader."VAT Currency Factor CZL" else CurrencyFactor := CustLedgerEntry."Original Currency Factor"; - ReverseAdvancePaymentVAT(SalesAdvLetterEntry2, CustLedgerEntry."Source Code", CustLedgerEntry.Description, - SalesAdvLetterEntryCZZ.Amount, CurrencyFactor, Enum::"Gen. Journal Document Type"::Invoice, - SalesAdvLetterEntryCZZ."Document No.", CustLedgerEntry."Posting Date", CustLedgerEntry."VAT Date CZL", - SalesAdvLetterEntryCZZ."Entry No.", CustLedgerEntry."Document No.", - "Advance Letter Entry Type CZZ"::"VAT Usage", GenJnlPostLine, false); - end; - - local procedure PostExchangeRate(ExchRateAmount: Decimal; ExchRateVATAmount: Decimal; var SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; - var SalesAdvLetterEntryCZZ: Record "Sales 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 - GenJournalLine: Record "Gen. Journal Line"; - begin - if (ExchRateAmount = 0) and (ExchRateVATAmount = 0) then - exit; - - if ExchRateVATAmount <> 0 then begin - GetCurrency(SalesAdvLetterHeaderCZZ."Currency Code"); + SalesAdvLetterPostCZZ.BufferAdvanceVATLines(SalesAdvLetterEntryCZZ2, TempAdvancePostingBufferCZZ, 0D); + SalesAdvLetterPostCZZ.SuggestUsageVAT(SalesAdvLetterEntryCZZ2, TempAdvancePostingBufferCZZ, CustLedgerEntry."Document No.", + SalesAdvLetterEntryCZZ.Amount, CurrencyFactor, false); - InitGenJnlLineFromAdvance(SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, DocumentNo, SourceCode, PostDescription, GenJournalLine); - GenJournalLine.Correction := Correction; - GenJournalLine.Validate("Posting Date", PostingDate); -#if not CLEAN22 -#pragma warning disable AL0432 - if not ReplaceVATDateMgtCZL.IsEnabled() then - GenJournalLine.Validate("VAT Date CZL", VATDate) - else -#pragma warning restore AL0432 -#endif - GenJournalLine.Validate("VAT Reporting Date", VATDate); - GenJournalLine."Account No." := VATPostingSetup."Sales Adv. Letter Account CZZ"; - GenJournalLine.Validate(Amount, ExchRateAmount - ExchRateVATAmount); - if not Preview then - GenJnlPostLine.RunWithCheck(GenJournalLine); - - InitGenJnlLineFromAdvance(SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, DocumentNo, SourceCode, PostDescription, GenJournalLine); - GenJournalLine.Correction := true; - GenJournalLine.Validate("Posting Date", PostingDate); -#if not CLEAN22 -#pragma warning disable AL0432 - if not ReplaceVATDateMgtCZL.IsEnabled() then - GenJournalLine.Validate("VAT Date CZL", VATDate) - else -#pragma warning restore AL0432 -#endif - GenJournalLine.Validate("VAT Reporting Date", VATDate); - if ExchRateVATAmount < 0 then begin - CurrencyGlob.TestField("Realized Losses Acc."); - GenJournalLine."Account No." := CurrencyGlob."Realized Losses Acc."; - end else begin - CurrencyGlob.TestField("Realized Gains Acc."); - GenJournalLine."Account No." := CurrencyGlob."Realized Gains Acc."; - end; - GenJournalLine.Validate(Amount, ExchRateVATAmount); - if not Preview then - GenJnlPostLine.RunWithCheck(GenJournalLine); - - InitGenJnlLineFromAdvance(SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, DocumentNo, SourceCode, PostDescription, GenJournalLine); - GenJournalLine.Correction := Correction; - GenJournalLine.Validate("Posting Date", PostingDate); -#if not CLEAN22 -#pragma warning disable AL0432 - if not ReplaceVATDateMgtCZL.IsEnabled() then - GenJournalLine.Validate("VAT Date CZL", VATDate) - else -#pragma warning restore AL0432 -#endif - GenJournalLine.Validate("VAT Reporting Date", VATDate); - GenJournalLine."Account No." := VATPostingSetup."Sales Adv. Letter Account CZZ"; - GenJournalLine.Validate(Amount, -ExchRateAmount); - if not Preview then - GenJnlPostLine.RunWithCheck(GenJournalLine); - end; - - AdvEntryInit(Preview); - if Correction then - AdvEntryInitCancel(); - AdvEntryInitRelatedEntry(UsageEntryNo); - AdvEntryInitVAT(VATPostingSetup."VAT Bus. Posting Group", VATPostingSetup."VAT Prod. Posting Group", VATDate, - 0, VATPostingSetup."VAT %", VATPostingSetup."VAT Identifier", VATPostingSetup."VAT Calculation Type", - 0, ExchRateVATAmount, 0, ExchRateAmount - ExchRateVATAmount); - AdvEntryInsert("Advance Letter Entry Type CZZ"::"VAT Rate", SalesAdvLetterEntryCZZ."Sales Adv. Letter No.", PostingDate, - 0, ExchRateAmount, '', 0, DocumentNo, - SalesAdvLetterEntryCZZ."Global Dimension 1 Code", SalesAdvLetterEntryCZZ."Global Dimension 2 Code", SalesAdvLetterEntryCZZ."Dimension Set ID", Preview); - end; - - local procedure BufferAdvanceVATLines(var SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; BalanceAtDate: Date) - begin - BufferAdvanceVATLines(SalesAdvLetterEntryCZZ, AdvancePostingBufferCZZ, BalanceAtDate, true); - end; - - local procedure BufferAdvanceVATLines(var SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; BalanceAtDate: Date; ResetBuffer: Boolean) - var - SalesAdvLetterEntryCZZ2: Record "Sales Adv. Letter Entry CZZ"; - TempAdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ" temporary; - begin - if ResetBuffer then begin - AdvancePostingBufferCZZ.Reset(); - AdvancePostingBufferCZZ.DeleteAll(); - end; + Clear(AdvancePostingParametersCZZ); + AdvancePostingParametersCZZ.CopyFromCustLedgerEntry(CustLedgerEntry); + AdvancePostingParametersCZZ."Document Type" := "Gen. Journal Document Type"::Invoice; + AdvancePostingParametersCZZ."Original Document VAT Date" := CustLedgerEntry."VAT Date CZL"; + AdvancePostingParametersCZZ."Currency Code" := SalesAdvLetterEntryCZZ2."Currency Code"; + AdvancePostingParametersCZZ."Currency Factor" := CurrencyFactor; - SalesAdvLetterEntryCZZ2.SetRange("Sales Adv. Letter No.", SalesAdvLetterEntryCZZ."Sales Adv. Letter No."); - SalesAdvLetterEntryCZZ2.SetRange(Cancelled, false); - SalesAdvLetterEntryCZZ2.SetRange("Related Entry", SalesAdvLetterEntryCZZ."Entry No."); - SalesAdvLetterEntryCZZ2.SetFilter("Entry Type", '<>%1', SalesAdvLetterEntryCZZ2."Entry Type"::"VAT Adjustment"); - if BalanceAtDate <> 0D then - SalesAdvLetterEntryCZZ2.SetFilter("Posting Date", '..%1', BalanceAtDate); - if SalesAdvLetterEntryCZZ2.FindSet() then - repeat - if SalesAdvLetterEntryCZZ2."Entry Type" in - [SalesAdvLetterEntryCZZ2."Entry Type"::Payment, - SalesAdvLetterEntryCZZ2."Entry Type"::Usage, - SalesAdvLetterEntryCZZ2."Entry Type"::Close] - then - BufferAdvanceVATLines(SalesAdvLetterEntryCZZ2, AdvancePostingBufferCZZ, BalanceAtDate, false) - else begin - TempAdvancePostingBufferCZZ.PrepareForSalesAdvLetterEntry(SalesAdvLetterEntryCZZ2); - AdvancePostingBufferCZZ.Update(TempAdvancePostingBufferCZZ); - end; - until SalesAdvLetterEntryCZZ2.Next() = 0; + SalesAdvLetterPostCZZ.PostAdvancePaymentUsageVAT( + SalesAdvLetterEntryCZZ, TempAdvancePostingBufferCZZ, GenJnlPostLine, AdvancePostingParametersCZZ); end; local procedure InitGenJnlLineFromCustLedgEntry(var CustLedgerEntry: Record "Cust. Ledger Entry"; var GenJournalLine: Record "Gen. Journal Line"; GenJournalDocumentType: Enum "Gen. Journal Document Type") @@ -1657,25 +793,6 @@ codeunit 31002 "SalesAdvLetterManagement CZZ" OnAfterInitGenJnlLineFromCustLedgEntry(CustLedgerEntry, GenJournalLine); end; - local procedure InitGenJnlLineFromAdvance(var SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; var SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; DocumentNo: Code[20]; 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.Description := PostDescription; - GenJournalLine."Bill-to/Pay-to No." := SalesAdvLetterHeaderCZZ."Bill-to Customer No."; - GenJournalLine."Country/Region Code" := SalesAdvLetterHeaderCZZ."Bill-to Country/Region Code"; - GenJournalLine."Source Code" := SourceCode; - GenJournalLine."VAT Registration No." := SalesAdvLetterHeaderCZZ."VAT Registration No."; - GenJournalLine."Registration No. CZL" := SalesAdvLetterHeaderCZZ."Registration No."; - GenJournalLine."Tax Registration No. CZL" := SalesAdvLetterHeaderCZZ."Tax Registration No."; - GenJournalLine."Shortcut Dimension 1 Code" := SalesAdvLetterEntryCZZ."Global Dimension 1 Code"; - GenJournalLine."Shortcut Dimension 2 Code" := SalesAdvLetterEntryCZZ."Global Dimension 2 Code"; - GenJournalLine."Dimension Set ID" := SalesAdvLetterEntryCZZ."Dimension Set ID"; - GenJournalLine."Adv. Letter No. (Entry) CZZ" := SalesAdvLetterEntryCZZ."Sales Adv. Letter No."; - OnAfterInitGenJnlLineFromAdvance(SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, GenJournalLine); - end; - procedure GetRemAmtSalAdvPayment(var SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; BalanceAtDate: Date): Decimal var SalesAdvLetterEntry2: Record "Sales Adv. Letter Entry CZZ"; @@ -1751,7 +868,7 @@ codeunit 31002 "SalesAdvLetterManagement CZZ" exit; if SalesAdvLetterHeaderCZZ.Status = SalesAdvLetterHeaderCZZ.Status::New then begin - UpdateStatus(SalesAdvLetterHeaderCZZ, SalesAdvLetterHeaderCZZ.Status::Closed); + SalesAdvLetterHeaderCZZ.UpdateStatus(SalesAdvLetterHeaderCZZ.Status::Closed); exit; end; @@ -1768,27 +885,15 @@ codeunit 31002 "SalesAdvLetterManagement CZZ" procedure CloseAdvanceLetter(var SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; PostingDate: Date; VATDate: Date; CurrencyFactor: Decimal) var - AdvanceLetterApplicationCZZ: Record "Advance Letter Application CZZ"; + AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; CurrencyExchangeRate: Record "Currency Exchange Rate"; - SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; - GenJournalLine: Record "Gen. Journal Line"; - CustLedgerEntry1: Record "Cust. Ledger Entry"; - CustLedgerEntry2: Record "Cust. Ledger Entry"; - Customer: Record Customer; - CustomerBankAccount: Record "Customer Bank Account"; - AdvanceLetterTemplateCZZ: Record "Advance Letter Template CZZ"; GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; - NoSeriesManagement: Codeunit NoSeriesManagement; - ApplId: Code[50]; - VATDocumentNo: Code[20]; - RemAmount: Decimal; - RemAmountLCY: Decimal; begin if SalesAdvLetterHeaderCZZ.Status = SalesAdvLetterHeaderCZZ.Status::Closed then exit; if SalesAdvLetterHeaderCZZ.Status = SalesAdvLetterHeaderCZZ.Status::New then begin - UpdateStatus(SalesAdvLetterHeaderCZZ, SalesAdvLetterHeaderCZZ.Status::Closed); + SalesAdvLetterHeaderCZZ.UpdateStatus(SalesAdvLetterHeaderCZZ.Status::Closed); exit; end; @@ -1798,135 +903,32 @@ codeunit 31002 "SalesAdvLetterManagement CZZ" VATDate := WorkDate(); if CurrencyFactor = 0 then CurrencyFactor := CurrencyExchangeRate.ExchangeRate(PostingDate, SalesAdvLetterHeaderCZZ."Currency Code"); - VATDocumentNo := ''; - - SalesAdvLetterEntryCZZ.SetRange("Sales Adv. Letter No.", SalesAdvLetterHeaderCZZ."No."); - SalesAdvLetterEntryCZZ.SetRange("Entry Type", SalesAdvLetterEntryCZZ."Entry Type"::Payment); - SalesAdvLetterEntryCZZ.SetRange(Cancelled, false); - if SalesAdvLetterEntryCZZ.FindSet() then - repeat - RemAmount := GetRemAmtSalAdvPayment(SalesAdvLetterEntryCZZ, 0D); - RemAmountLCY := GetRemAmtLCYSalAdvPayment(SalesAdvLetterEntryCZZ, 0D); - if RemAmount <> 0 then begin - if VATDocumentNo = '' then begin - AdvanceLetterTemplateCZZ.Get(SalesAdvLetterHeaderCZZ."Advance Letter Code"); - AdvanceLetterTemplateCZZ.TestField("Advance Letter Cr. Memo Nos."); - VATDocumentNo := NoSeriesManagement.GetNextNo(AdvanceLetterTemplateCZZ."Advance Letter Cr. Memo Nos.", PostingDate, true); - end; - - SalesAdvLetterHeaderCZZ.Get(SalesAdvLetterEntryCZZ."Sales Adv. Letter No."); - Customer.Get(SalesAdvLetterHeaderCZZ."Bill-to Customer No."); - CustLedgerEntry1.Get(SalesAdvLetterEntryCZZ."Cust. Ledger Entry No."); - - InitGenJnlLineFromCustLedgEntry(CustLedgerEntry1, GenJournalLine, GenJournalLine."Document Type"::" "); - GenJournalLine."Adv. Letter Template Code CZZ" := SalesAdvLetterHeaderCZZ."Advance Letter Code"; - GenJournalLine.Correction := true; - GenJournalLine."Document No." := VATDocumentNo; - GenJournalLine."Posting Date" := PostingDate; - GenJournalLine."Document Date" := PostingDate; -#if not CLEAN22 -#pragma warning disable AL0432 - if not ReplaceVATDateMgtCZL.IsEnabled() then - GenJournalLine.Validate("VAT Date CZL", VATDate) - else -#pragma warning restore AL0432 -#endif - GenJournalLine.Validate("VAT Reporting Date", VATDate); - GenJournalLine."Adv. Letter No. (Entry) CZZ" := SalesAdvLetterEntryCZZ."Sales Adv. Letter No."; - GenJournalLine."Use Advance G/L Account CZZ" := true; - GenJournalLine.SetCurrencyFactor(SalesAdvLetterEntryCZZ."Currency Code", CurrencyFactor); - GenJournalLine.Validate(Amount, RemAmount); - - ApplId := CopyStr(CustLedgerEntry1."Document No." + Format(CustLedgerEntry1."Entry No.", 0, ''), 1, MaxStrLen(ApplId)); - CustLedgerEntry1.Prepayment := false; - CustLedgerEntry1."Advance Letter No. CZZ" := SalesAdvLetterEntryCZZ."Sales Adv. Letter No."; - CustLedgerEntry1.Modify(); - CustLedgerEntry1.CalcFields("Remaining Amount"); - CustLedgerEntry1."Amount to Apply" := CustLedgerEntry1."Remaining Amount"; - CustLedgerEntry1."Applies-to ID" := ApplId; - Codeunit.Run(Codeunit::"Cust. Entry-Edit", CustLedgerEntry1); - GenJournalLine."Applies-to ID" := ApplId; - - OnBeforePostClosePayment(GenJournalLine, SalesAdvLetterHeaderCZZ); - GenJnlPostLine.RunWithCheck(GenJournalLine); - OnAfterPostClosePayment(GenJournalLine, SalesAdvLetterHeaderCZZ); - - CustLedgerEntry2.FindLast(); - AdvEntryInit(false); - AdvEntryInitCustLedgEntryNo(CustLedgerEntry2."Entry No."); - AdvEntryInitRelatedEntry(SalesAdvLetterEntryCZZ."Entry No."); - AdvEntryInsert("Advance Letter Entry Type CZZ"::Close, GenJournalLine."Adv. Letter No. (Entry) CZZ", GenJournalLine."Posting Date", - GenJournalLine.Amount, RemAmountLCY, - GenJournalLine."Currency Code", GenJournalLine."Currency Factor", GenJournalLine."Document No.", - GenJournalLine."Shortcut Dimension 1 Code", GenJournalLine."Shortcut Dimension 2 Code", GenJournalLine."Dimension Set ID", false); - - ReverseAdvancePaymentVAT(SalesAdvLetterEntryCZZ, CustLedgerEntry1."Source Code", - SalesAdvLetterHeaderCZZ."Posting Description", RemAmount, CurrencyFactor, - Enum::"Gen. Journal Document Type"::"Credit Memo", VATDocumentNo, PostingDate, - VATDate, SalesAdvLetterEntryCZZGlob."Entry No.", '', - "Advance Letter Entry Type CZZ"::"VAT Close", GenJnlPostLine, false); - - InitGenJnlLineFromCustLedgEntry(CustLedgerEntry1, GenJournalLine, GenJournalLine."Document Type"::Payment); - GenJournalLine.Correction := true; - GenJournalLine."Document No." := VATDocumentNo; - GenJournalLine."Posting Date" := PostingDate; - GenJournalLine."Document Date" := PostingDate; -#if not CLEAN22 -#pragma warning disable AL0432 - if not ReplaceVATDateMgtCZL.IsEnabled() then - GenJournalLine.Validate("VAT Date CZL", VATDate) - else -#pragma warning restore AL0432 -#endif - GenJournalLine.Validate("VAT Reporting Date", VATDate); - GenJournalLine.SetCurrencyFactor(SalesAdvLetterEntryCZZ."Currency Code", CurrencyFactor); - GenJournalLine.Validate(Amount, -RemAmount); - GenJournalLine."Variable Symbol CZL" := SalesAdvLetterHeaderCZZ."Variable Symbol"; - if CustomerBankAccount.Get(Customer."No.", Customer."Preferred Bank Account Code") then begin - GenJournalLine."Bank Account Code CZL" := CustomerBankAccount.Code; - GenJournalLine."Bank Account No. CZL" := CustomerBankAccount."Bank Account No."; - GenJournalLine."Transit No. CZL" := CustomerBankAccount."Transit No."; - GenJournalLine."IBAN CZL" := CustomerBankAccount.IBAN; - GenJournalLine."SWIFT Code CZL" := CustomerBankAccount."SWIFT Code"; - end; - OnBeforePostClosePaymentRepos(GenJournalLine, SalesAdvLetterHeaderCZZ); - GenJnlPostLine.RunWithCheck(GenJournalLine); - OnAfterPostClosePaymentRepos(GenJournalLine, SalesAdvLetterHeaderCZZ); - end; - until SalesAdvLetterEntryCZZ.Next() = 0; - CancelInitEntry(SalesAdvLetterHeaderCZZ, PostingDate, false); - SalesAdvLetterHeaderCZZ.Find(); - UpdateStatus(SalesAdvLetterHeaderCZZ, SalesAdvLetterHeaderCZZ.Status::Closed); + Clear(AdvancePostingParametersCZZ); + AdvancePostingParametersCZZ."Posting Date" := PostingDate; + AdvancePostingParametersCZZ."Document Date" := PostingDate; + AdvancePostingParametersCZZ."VAT Date" := VATDate; + AdvancePostingParametersCZZ."Currency Code" := SalesAdvLetterHeaderCZZ."Currency Code"; + AdvancePostingParametersCZZ."Currency Factor" := CurrencyFactor; - AdvanceLetterApplicationCZZ.SetRange("Advance Letter Type", AdvanceLetterApplicationCZZ."Advance Letter Type"::Sales); - AdvanceLetterApplicationCZZ.SetRange("Advance Letter No.", SalesAdvLetterHeaderCZZ."No."); - AdvanceLetterApplicationCZZ.DeleteAll(true); + SalesAdvLetterPostCZZ.PostAdvanceLetterClosing(SalesAdvLetterHeaderCZZ, GenJnlPostLine, AdvancePostingParametersCZZ); end; procedure PostAdvanceCreditMemoVAT(var SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ") var + AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; SalesAdvLetterEntryCZZ2: Record "Sales Adv. Letter Entry CZZ"; - SalesAdvLetterEntryCZZ3: Record "Sales Adv. Letter Entry CZZ"; TempAdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ" temporary; - VATPostingSetup: Record "VAT Posting Setup"; + TempAdvancePostingBufferCZZ2: Record "Advance Posting Buffer CZZ" temporary; SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; - GenJournalLine: Record "Gen. Journal Line"; AdvanceLetterTemplateCZZ: Record "Advance Letter Template CZZ"; VATEntry: Record "VAT Entry"; - DocumentTypeHandlerCZZ: Codeunit "Document Type Handler CZZ"; - NoSeriesManagement: Codeunit NoSeriesManagement; - VATPostingSetupHandlerCZZ: Codeunit "VAT Posting Setup Handler CZZ"; + NoSeries: Codeunit "No. Series"; GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; AdvPaymentCloseDialog: Page "Adv. Payment Close Dialog CZZ"; - DocumentNo: Code[20]; VATDate: Date; PostingDate: Date; CurrencyFactor: Decimal; - ExchRateAmount: Decimal; - ExchRateVATAmount: Decimal; - Coef: Decimal; - CreateCrMemoErr: Label 'Credit memo cannot be created because some VAT usage exists.'; begin SalesAdvLetterEntryCZZ.TestField("Entry Type", SalesAdvLetterEntryCZZ."Entry Type"::"VAT Payment"); SalesAdvLetterEntryCZZ.TestField(Cancelled, false); @@ -1940,195 +942,53 @@ codeunit 31002 "SalesAdvLetterManagement CZZ" if SalesAdvLetterEntryCZZ."Currency Code" = '' then CurrencyFactor := 1; - SalesAdvLetterEntryCZZ3.Get(SalesAdvLetterEntryCZZ."Related Entry"); - BufferAdvanceVATLines(SalesAdvLetterEntryCZZ3, TempAdvancePostingBufferCZZ, 0D); - - GetCurrency(SalesAdvLetterEntryCZZ."Currency Code"); - SalesAdvLetterHeaderCZZ.Get(SalesAdvLetterEntryCZZ."Sales Adv. Letter No."); - AdvanceLetterTemplateCZZ.Get(SalesAdvLetterHeaderCZZ."Advance Letter Code"); - VATEntry.Get(SalesAdvLetterEntryCZZ."VAT Entry No."); - DocumentNo := NoSeriesManagement.GetNextNo(AdvanceLetterTemplateCZZ."Advance Letter Cr. Memo Nos.", WorkDate(), true); - SalesAdvLetterEntryCZZ2.SetRange("Sales Adv. Letter No.", SalesAdvLetterEntryCZZ."Sales Adv. Letter No."); SalesAdvLetterEntryCZZ2.SetRange(Cancelled, false); SalesAdvLetterEntryCZZ2.SetRange("Entry Type", SalesAdvLetterEntryCZZ2."Entry Type"::"VAT Payment"); SalesAdvLetterEntryCZZ2.SetRange("Document No.", SalesAdvLetterEntryCZZ."Document No."); - SalesAdvLetterEntryCZZ2.CalcSums(Amount); - Coef := SalesAdvLetterEntryCZZ2.Amount / SalesAdvLetterEntryCZZ3.Amount; - - SalesAdvLetterEntryCZZ2.FindSet(true); + SalesAdvLetterEntryCZZ2.FindSet(); repeat - TempAdvancePostingBufferCZZ.SetRange("VAT Bus. Posting Group", SalesAdvLetterEntryCZZ2."VAT Bus. Posting Group"); - TempAdvancePostingBufferCZZ.SetRange("VAT Prod. Posting Group", SalesAdvLetterEntryCZZ2."VAT Prod. Posting Group"); - TempAdvancePostingBufferCZZ.SetRange("VAT Calculation Type", SalesAdvLetterEntryCZZ2."VAT Calculation Type"); - TempAdvancePostingBufferCZZ.FindFirst(); - if TempAdvancePostingBufferCZZ.Amount > SalesAdvLetterEntryCZZ2.Amount then - Error(CreateCrMemoErr); - - VATPostingSetup.Get(SalesAdvLetterEntryCZZ2."VAT Bus. Posting Group", SalesAdvLetterEntryCZZ2."VAT Prod. Posting Group"); - VATPostingSetup.TestField("Sales Adv. Letter Account CZZ"); - VATPostingSetup.TestField("Sales Adv. Letter VAT Acc. CZZ"); - - InitGenJnlLineFromAdvance(SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, DocumentNo, VATEntry."Source Code", SalesAdvLetterHeaderCZZ."Posting Description", GenJournalLine); - GenJournalLine."Document Type" := GenJournalLine."Document Type"::"Credit Memo"; - GenJournalLine.Validate("Posting Date", PostingDate); -#if not CLEAN22 -#pragma warning disable AL0432 - if not ReplaceVATDateMgtCZL.IsEnabled() then - GenJournalLine.Validate("VAT Date CZL", VATDate) - else -#pragma warning restore AL0432 -#endif - GenJournalLine.Validate("VAT Reporting Date", VATDate); - GenJournalLine."Account No." := VATPostingSetup."Sales Adv. Letter Account CZZ"; - GenJournalLine.SetCurrencyFactor(SalesAdvLetterEntryCZZ2."Currency Code", CurrencyFactor); - GenJournalLine."Gen. Posting Type" := GenJournalLine."Gen. Posting Type"::Sale; - GenJournalLine."VAT Calculation Type" := SalesAdvLetterEntryCZZ2."VAT Calculation Type"; - GenJournalLine."VAT Bus. Posting Group" := SalesAdvLetterEntryCZZ2."VAT Bus. Posting Group"; - GenJournalLine.Validate("VAT Prod. Posting Group", SalesAdvLetterEntryCZZ2."VAT Prod. Posting Group"); - GenJournalLine.Validate(Amount, -SalesAdvLetterEntryCZZ2.Amount); - GenJournalLine."VAT Amount" := -SalesAdvLetterEntryCZZ2."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 - CalculateAmountLCY(GenJournalLine); - BindSubscription(VATPostingSetupHandlerCZZ); - BindSubscription(DocumentTypeHandlerCZZ); - GenJnlPostLine.RunWithCheck(GenJournalLine); - UnbindSubscription(VATPostingSetupHandlerCZZ); - UnbindSubscription(DocumentTypeHandlerCZZ); + TempAdvancePostingBufferCZZ2.PrepareForSalesAdvLetterEntry(SalesAdvLetterEntryCZZ2); + TempAdvancePostingBufferCZZ.Update(TempAdvancePostingBufferCZZ2); + TempAdvancePostingBufferCZZ.UpdateLCYAmounts(SalesAdvLetterEntryCZZ2."Currency Code", CurrencyFactor); + TempAdvancePostingBufferCZZ.Modify(); + until SalesAdvLetterEntryCZZ2.Next() = 0; -#if not CLEAN22 -#pragma warning disable AL0432 - if not ReplaceVATDateMgtCZL.IsEnabled() then - GenJournalLine."VAT Reporting Date" := GenJournalLine."VAT Date CZL"; -#pragma warning restore AL0432 -#endif - AdvEntryInit(false); - AdvEntryInitRelatedEntry(SalesAdvLetterEntryCZZ."Related Entry"); - AdvEntryInitCancel(); - AdvEntryInitVAT(GenJournalLine."VAT Bus. Posting Group", GenJournalLine."VAT Prod. Posting Group", GenJournalLine."VAT Reporting Date", - 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 Payment", SalesAdvLetterEntryCZZ2."Sales Adv. Letter No.", GenJournalLine."Posting Date", - GenJournalLine.Amount, GenJournalLine."Amount (LCY)", - GenJournalLine."Currency Code", GenJournalLine."Currency Factor", GenJournalLine."Document No.", - GenJournalLine."Shortcut Dimension 1 Code", GenJournalLine."Shortcut Dimension 2 Code", GenJournalLine."Dimension Set ID", false); - - if GenJournalLine."Currency Code" <> '' then begin - ExchRateAmount := -SalesAdvLetterEntryCZZ2."Amount (LCY)" - GenJournalLine."Amount (LCY)"; - ExchRateVATAmount := -SalesAdvLetterEntryCZZ2."VAT Amount (LCY)" - GenJournalLine."VAT Amount (LCY)"; - if (ExchRateAmount <> 0) or (ExchRateVATAmount <> 0) then - PostExchangeRate(ExchRateAmount, ExchRateVATAmount, SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, VATPostingSetup, - DocumentNo, PostingDate, VATDate, '', '', SalesAdvLetterEntryCZZ2."Related Entry", true, GenJnlPostLine, false); - - ReverseUnrealizedExchangeRate(SalesAdvLetterEntryCZZ3, SalesAdvLetterHeaderCZZ, VATPostingSetup, Coef, - SalesAdvLetterEntryCZZ3."Entry No.", DocumentNo, PostingDate, VATDate, '', GenJnlPostLine, false); - end; + VATEntry.Get(SalesAdvLetterEntryCZZ."VAT Entry No."); + SalesAdvLetterHeaderCZZ.Get(SalesAdvLetterEntryCZZ."Sales Adv. Letter No."); + AdvanceLetterTemplateCZZ.Get(SalesAdvLetterHeaderCZZ."Advance Letter Code"); - InitGenJnlLineFromAdvance(SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, DocumentNo, VATEntry."Source Code", SalesAdvLetterHeaderCZZ."Posting Description", GenJournalLine); - GenJournalLine.Validate("Posting Date", PostingDate); -#if not CLEAN22 -#pragma warning disable AL0432 - if not ReplaceVATDateMgtCZL.IsEnabled() then - GenJournalLine.Validate("VAT Date CZL", VATDate) - else -#pragma warning restore AL0432 -#endif - GenJournalLine.Validate("VAT Reporting Date", VATDate); - GenJournalLine."Account No." := VATPostingSetup."Sales Adv. Letter Account CZZ"; - GenJournalLine.SetCurrencyFactor(SalesAdvLetterEntryCZZ2."Currency Code", CurrencyFactor); - GenJournalLine.Validate(Amount, SalesAdvLetterEntryCZZ2.Amount); - GenJnlPostLine.RunWithCheck(GenJournalLine); - until SalesAdvLetterEntryCZZ2.Next() = 0; - SalesAdvLetterEntryCZZ2.ModifyAll(Cancelled, true); + 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."Posting Description" := SalesAdvLetterHeaderCZZ."Posting Description"; + AdvancePostingParametersCZZ."Posting Date" := PostingDate; + AdvancePostingParametersCZZ."Document Date" := PostingDate; + AdvancePostingParametersCZZ."VAT Date" := VATDate; + AdvancePostingParametersCZZ."Original Document VAT Date" := VATDate; + AdvancePostingParametersCZZ."Currency Code" := SalesAdvLetterEntryCZZ."Currency Code"; + AdvancePostingParametersCZZ."Currency Factor" := CurrencyFactor; + + SalesAdvLetterPostCZZ.PostAdvanceCreditMemoVAT( + SalesAdvLetterEntryCZZ, TempAdvancePostingBufferCZZ, GenJnlPostLine, AdvancePostingParametersCZZ); end; end; procedure PostAdvancePaymentUsagePreview(var SalesHeader: Record "Sales Header"; Amount: Decimal; AmountLCY: Decimal; var SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ") - var - SalesInvoiceHeader: Record "Sales Invoice Header"; - CustLedgerEntry: Record "Cust. Ledger Entry"; - GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; - AdvLetterUsageDocTypeCZZ: Enum "Adv. Letter Usage Doc.Type CZZ"; begin - SalesAdvLetterEntryCZZ.Reset(); - SalesAdvLetterEntryCZZ.DeleteAll(); - - if not TempSalesAdvLetterEntryCZZGlob.IsEmpty() then - TempSalesAdvLetterEntryCZZGlob.DeleteAll(); - - case SalesHeader."Document Type" of - SalesHeader."Document Type"::Order: - AdvLetterUsageDocTypeCZZ := AdvLetterUsageDocTypeCZZ::"Sales Order"; - SalesHeader."Document Type"::Invoice: - AdvLetterUsageDocTypeCZZ := AdvLetterUsageDocTypeCZZ::"Sales Invoice"; - else - exit; - end; - - SalesInvoiceHeader.TransferFields(SalesHeader); - CustLedgerEntry.Init(); - CustLedgerEntry."Customer No." := SalesHeader."Bill-to Customer No."; - CustLedgerEntry."Posting Date" := SalesHeader."Posting Date"; - CustLedgerEntry."Document Date" := SalesHeader."Document Date"; - CustLedgerEntry."Document Type" := SalesHeader."Document Type"; - CustLedgerEntry."Document No." := SalesHeader."No."; - CustLedgerEntry."External Document No." := SalesHeader."External Document No."; - CustLedgerEntry.Description := SalesHeader."Posting Description"; - CustLedgerEntry."Currency Code" := SalesHeader."Currency Code"; - CustLedgerEntry."Sell-to Customer No." := SalesHeader."Sell-to Customer No."; - CustLedgerEntry."Customer Posting Group" := SalesHeader."Customer Posting Group"; - CustLedgerEntry."Global Dimension 1 Code" := SalesHeader."Shortcut Dimension 1 Code"; - CustLedgerEntry."Global Dimension 2 Code" := SalesHeader."Shortcut Dimension 2 Code"; - CustLedgerEntry."Dimension Set ID" := SalesHeader."Dimension Set ID"; - CustLedgerEntry."Salesperson Code" := SalesHeader."Salesperson Code"; - CustLedgerEntry."Due Date" := SalesHeader."Due Date"; - CustLedgerEntry."Payment Method Code" := SalesHeader."Payment Method Code"; -#if not CLEAN22 -#pragma warning disable AL0432 - if not ReplaceVATDateMgtCZL.IsEnabled() then - CustLedgerEntry."VAT Date CZL" := SalesHeader."VAT Date CZL" - else -#pragma warning restore AL0432 -#endif - CustLedgerEntry."VAT Date CZL" := SalesHeader."VAT Reporting Date"; - CustLedgerEntry."Original Currency Factor" := SalesHeader."Currency Factor"; - CustLedgerEntry.Amount := Amount; - CustLedgerEntry."Amount (LCY)" := AmountLCY; - CustLedgerEntry."Remaining Amount" := Amount; - CustLedgerEntry."Remaining Amt. (LCY)" := AmountLCY; - - PostAdvancePaymentUsage(AdvLetterUsageDocTypeCZZ, SalesHeader."No.", SalesInvoiceHeader, CustLedgerEntry, GenJnlPostLine, true); - - if TempSalesAdvLetterEntryCZZGlob.FindSet() then begin - repeat - SalesAdvLetterEntryCZZ := TempSalesAdvLetterEntryCZZGlob; - SalesAdvLetterEntryCZZ.Insert(); - until TempSalesAdvLetterEntryCZZGlob.Next() = 0; - - TempSalesAdvLetterEntryCZZGlob.DeleteAll(); - end; + SalesAdvLetterPostCZZ.PostAdvancePaymentUsageForStatistics(SalesHeader, Amount, AmountLCY, SalesAdvLetterEntryCZZ); end; procedure UnapplyAdvanceLetter(var SalesInvoiceHeader: Record "Sales Invoice Header") var + AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; - SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; TempSalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ" temporary; - GenJournalLine: Record "Gen. Journal Line"; - VATPostingSetup: Record "VAT Posting Setup"; - CustLedgerEntry: Record "Cust. Ledger Entry"; - CustLedgerEntryInv: Record "Cust. Ledger Entry"; - DocumentTypeHandlerCZZ: Codeunit "Document Type Handler CZZ"; GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; - VATPostingSetupHandlerCZZ: Codeunit "VAT Posting Setup Handler CZZ"; - GenJnlCheckLnHandlerCZZ: Codeunit "Gen.Jnl.-Check Ln. Handler CZZ"; ConfirmManagement: Codeunit "Confirm Management"; - ApplId: Code[50]; AdvLetters: Text; - UnapplyIsNotPossibleErr: Label 'Unapply is not possible.'; UnapplyAdvLetterQst: Label 'Unapply advance letter: %1\Continue?', Comment = '%1 = Advance Letters'; begin SalesAdvLetterEntryCZZ.SetRange(SalesAdvLetterEntryCZZ."Entry Type", SalesAdvLetterEntryCZZ."Entry Type"::Usage); @@ -2154,234 +1014,16 @@ codeunit 31002 "SalesAdvLetterManagement CZZ" if not ConfirmManagement.GetResponseOrDefault(StrSubstNo(UnapplyAdvLetterQst, AdvLetters), false) then exit; - SalesAdvLetterEntryCZZ.Reset(); - SalesAdvLetterEntryCZZ.SetRange("Document No.", SalesInvoiceHeader."No."); - SalesAdvLetterEntryCZZ.SetRange(Cancelled, false); - SalesAdvLetterEntryCZZ.Find('+'); - SalesAdvLetterEntryCZZ.SetFilter("Entry No.", '..%1', SalesAdvLetterEntryCZZ."Entry No."); - repeat - SalesAdvLetterHeaderCZZ.Get(SalesAdvLetterEntryCZZ."Sales Adv. Letter No."); - case SalesAdvLetterEntryCZZ."Entry Type" of - SalesAdvLetterEntryCZZ."Entry Type"::"VAT Adjustment": - begin - VATPostingSetup.Get(SalesAdvLetterEntryCZZ."VAT Bus. Posting Group", SalesAdvLetterEntryCZZ."VAT Prod. Posting Group"); - PostUnrealizedExchangeRate(SalesAdvLetterEntryCZZ, SalesAdvLetterHeaderCZZ, VATPostingSetup, -SalesAdvLetterEntryCZZ."Amount (LCY)", -SalesAdvLetterEntryCZZ."VAT Amount (LCY)", - SalesAdvLetterEntryCZZ."Related Entry", 0, SalesAdvLetterEntryCZZ."Document No.", SalesAdvLetterEntryCZZ."Posting Date", SalesAdvLetterHeaderCZZ."VAT Date", SalesInvoiceHeader."Posting Description", GenJnlPostLine, true, false); - end; - SalesAdvLetterEntryCZZ."Entry Type"::"VAT Rate": - begin - VATPostingSetup.Get(SalesAdvLetterEntryCZZ."VAT Bus. Posting Group", SalesAdvLetterEntryCZZ."VAT Prod. Posting Group"); - PostExchangeRate(-SalesAdvLetterEntryCZZ."Amount (LCY)", -SalesAdvLetterEntryCZZ."VAT Amount (LCY)", SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, VATPostingSetup, - SalesAdvLetterEntryCZZ."Document No.", SalesAdvLetterEntryCZZ."Posting Date", SalesAdvLetterEntryCZZ."VAT Date", SalesInvoiceHeader."Source Code", - SalesInvoiceHeader."Posting Description", SalesAdvLetterEntryCZZ."Related Entry", true, GenJnlPostLine, false); - end; - SalesAdvLetterEntryCZZ."Entry Type"::"VAT Usage": - begin - VATPostingSetup.Get(SalesAdvLetterEntryCZZ."VAT Bus. Posting Group", SalesAdvLetterEntryCZZ."VAT Prod. Posting Group"); - InitGenJnlLineFromAdvance(SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, SalesAdvLetterEntryCZZ."Document No.", - SalesInvoiceHeader."Source Code", SalesInvoiceHeader."Posting Description", GenJournalLine); - GenJournalLine."Document Type" := GenJournalLine."Document Type"::Invoice; - GenJournalLine.Validate("Posting Date", SalesAdvLetterEntryCZZ."Posting Date"); -#if not CLEAN22 -#pragma warning disable AL0432 - if not ReplaceVATDateMgtCZL.IsEnabled() then - GenJournalLine.Validate("VAT Date CZL", SalesInvoiceHeader."VAT Date CZL") - else -#pragma warning restore AL0432 -#endif - GenJournalLine.Validate("VAT Reporting Date", SalesInvoiceHeader."VAT Reporting Date"); - GenJournalLine."Account No." := VATPostingSetup."Sales Adv. Letter Account CZZ"; - GenJournalLine.SetCurrencyFactor(SalesAdvLetterEntryCZZ."Currency Code", SalesAdvLetterEntryCZZ."Currency Factor"); - GenJournalLine."Gen. Posting Type" := GenJournalLine."Gen. Posting Type"::Sale; - GenJournalLine."VAT Calculation Type" := SalesAdvLetterEntryCZZ."VAT Calculation Type"; - GenJournalLine."VAT Bus. Posting Group" := SalesAdvLetterEntryCZZ."VAT Bus. Posting Group"; - GenJournalLine.validate("VAT Prod. Posting Group", SalesAdvLetterEntryCZZ."VAT Prod. Posting Group"); - GenJournalLine.Correction := true; - GenJournalLine.Validate(Amount, -SalesAdvLetterEntryCZZ.Amount); - GenJournalLine."VAT Amount" := -SalesAdvLetterEntryCZZ."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."VAT Amount (LCY)" := -SalesAdvLetterEntryCZZ."VAT Amount (LCY)"; - GenJournalLine."VAT Base Amount (LCY)" := GenJournalLine."Amount (LCY)" - GenJournalLine."VAT Amount (LCY)"; - end; - BindSubscription(VATPostingSetupHandlerCZZ); - BindSubscription(DocumentTypeHandlerCZZ); - GenJnlPostLine.RunWithCheck(GenJournalLine); - UnbindSubscription(VATPostingSetupHandlerCZZ); - UnbindSubscription(DocumentTypeHandlerCZZ); - -#if not CLEAN22 -#pragma warning disable AL0432 - if not ReplaceVATDateMgtCZL.IsEnabled() then - GenJournalLine."VAT Reporting Date" := GenJournalLine."VAT Date CZL"; -#pragma warning restore AL0432 -#endif - AdvEntryInit(false); - AdvEntryInitRelatedEntry(SalesAdvLetterEntryCZZ."Related Entry"); - AdvEntryInitCancel(); - AdvEntryInitVAT(GenJournalLine."VAT Bus. Posting Group", GenJournalLine."VAT Prod. Posting Group", GenJournalLine."VAT Reporting Date", - 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", SalesAdvLetterEntryCZZ."Sales Adv. Letter No.", GenJournalLine."Posting Date", - GenJournalLine.Amount, GenJournalLine."Amount (LCY)", - GenJournalLine."Currency Code", GenJournalLine."Currency Factor", GenJournalLine."Document No.", - GenJournalLine."Shortcut Dimension 1 Code", GenJournalLine."Shortcut Dimension 2 Code", GenJournalLine."Dimension Set ID", false); - - InitGenJnlLineFromAdvance(SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, SalesAdvLetterEntryCZZ."Document No.", SalesInvoiceHeader."Source Code", SalesInvoiceHeader."Posting Description", GenJournalLine); - GenJournalLine.Validate("Posting Date", SalesAdvLetterEntryCZZ."Posting Date"); -#if not CLEAN22 -#pragma warning disable AL0432 - if not ReplaceVATDateMgtCZL.IsEnabled() then - GenJournalLine.Validate("VAT Date CZL", SalesInvoiceHeader."VAT Date CZL") - else -#pragma warning restore AL0432 -#endif - GenJournalLine.Validate("VAT Reporting Date", SalesInvoiceHeader."VAT Reporting Date"); - GenJournalLine."Account No." := VATPostingSetup."Sales Adv. Letter Account CZZ"; - GenJournalLine.SetCurrencyFactor(SalesInvoiceHeader."Currency Code", SalesAdvLetterEntryCZZ."Currency Factor"); - GenJournalLine.Correction := true; - GenJournalLine.Validate(Amount, SalesAdvLetterEntryCZZ.Amount); - GenJnlPostLine.RunWithCheck(GenJournalLine); - end; - SalesAdvLetterEntryCZZ."Entry Type"::Usage: - begin - CustLedgerEntry.Get(SalesAdvLetterEntryCZZ."Cust. Ledger Entry No."); - CustLedgerEntryInv := CustLedgerEntry; -#pragma warning disable AA0181 - CustLedgerEntryInv.Next(-1); -#pragma warning restore AA0181 - UnapplyCustLedgEntry(CustLedgerEntry, GenJnlPostLine); - - InitGenJnlLineFromCustLedgEntry(CustLedgerEntry, GenJournalLine, CustLedgerEntry."Document Type"::" "); - GenJournalLine."Adv. Letter Template Code CZZ" := SalesAdvLetterHeaderCZZ."Advance Letter Code"; - GenJournalLine.Correction := true; - GenJournalLine."Adv. Letter No. (Entry) CZZ" := SalesAdvLetterEntryCZZ."Sales Adv. Letter No."; - GenJournalLine."Use Advance G/L Account CZZ" := true; - GenJournalLine.SetCurrencyFactor(SalesAdvLetterEntryCZZ."Currency Code", SalesAdvLetterEntryCZZ."Currency Factor"); - GenJournalLine.Correction := true; - GenJournalLine.Amount := -SalesAdvLetterEntryCZZ.Amount; - GenJournalLine."Amount (LCY)" := -SalesAdvLetterEntryCZZ."Amount (LCY)"; - - ApplId := CopyStr(CustLedgerEntry."Document No." + Format(CustLedgerEntry."Entry No.", 0, ''), 1, MaxStrLen(ApplId)); - CustLedgerEntry.CalcFields("Remaining Amount"); - CustLedgerEntry."Amount to Apply" := CustLedgerEntry."Remaining Amount"; - CustLedgerEntry."Applies-to ID" := ApplId; - Codeunit.Run(Codeunit::"Cust. Entry-Edit", CustLedgerEntry); - GenJournalLine."Applies-to ID" := ApplId; - - BindSubscription(GenJnlCheckLnHandlerCZZ); - GenJnlPostLine.RunWithCheck(GenJournalLine); - - CustLedgerEntry.FindLast(); - AdvEntryInit(false); - AdvEntryInitCancel(); - AdvEntryInitCustLedgEntryNo(CustLedgerEntry."Entry No."); - AdvEntryInitRelatedEntry(SalesAdvLetterEntryCZZ."Entry No."); - AdvEntryInsert("Advance Letter Entry Type CZZ"::Usage, GenJournalLine."Adv. Letter No. (Entry) CZZ", GenJournalLine."Posting Date", - GenJournalLine.Amount, GenJournalLine."Amount (LCY)", - GenJournalLine."Currency Code", GenJournalLine."Currency Factor", SalesAdvLetterEntryCZZ."Document No.", - GenJournalLine."Shortcut Dimension 1 Code", GenJournalLine."Shortcut Dimension 2 Code", GenJournalLine."Dimension Set ID", false); - - InitGenJnlLineFromCustLedgEntry(CustLedgerEntry, GenJournalLine, GenJournalLine."Document Type"::" "); - GenJournalLine."Adv. Letter Template Code CZZ" := SalesAdvLetterHeaderCZZ."Advance Letter Code"; - GenJournalLine.Correction := true; - GenJournalLine.SetCurrencyFactor(SalesAdvLetterEntryCZZ."Currency Code", SalesAdvLetterEntryCZZ."Currency Factor"); - GenJournalLine.Correction := true; - GenJournalLine.Amount := SalesAdvLetterEntryCZZ.Amount; - GenJournalLine."Amount (LCY)" := SalesAdvLetterEntryCZZ."Amount (LCY)"; - - ApplId := CopyStr(CustLedgerEntryInv."Document No." + Format(CustLedgerEntryInv."Entry No.", 0, ''), 1, MaxStrLen(ApplId)); - CustLedgerEntryInv.Prepayment := false; - CustLedgerEntryInv."Advance Letter No. CZZ" := ''; - CustLedgerEntryInv.CalcFields("Remaining Amount"); - CustLedgerEntryInv."Amount to Apply" := CustLedgerEntryInv."Remaining Amount"; - CustLedgerEntryInv."Applies-to ID" := ApplId; - Codeunit.Run(Codeunit::"Cust. Entry-Edit", CustLedgerEntryInv); - GenJournalLine."Applies-to ID" := ApplId; - - GenJnlPostLine.RunWithCheck(GenJournalLine); - UnbindSubscription(GenJnlCheckLnHandlerCZZ); - - UpdateStatus(SalesAdvLetterHeaderCZZ, SalesAdvLetterHeaderCZZ.Status::"To Use"); - end; - else - Error(UnapplyIsNotPossibleErr); - end; - until SalesAdvLetterEntryCZZ.Next(-1) = 0; - - SalesAdvLetterEntryCZZ.ModifyAll(Cancelled, true); - end; + Clear(AdvancePostingParametersCZZ); + AdvancePostingParametersCZZ."Document No." := SalesInvoiceHeader."No."; - local procedure UnapplyCustLedgEntry(var CustLedgerEntry: Record "Cust. Ledger Entry"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line") - var - DetailedCustLedgEntry1: Record "Detailed Cust. Ledg. Entry"; - DetailedCustLedgEntry2: Record "Detailed Cust. Ledg. Entry"; - DetailedCustLedgEntry3: Record "Detailed Cust. Ledg. Entry"; - GenJournalLine: Record "Gen. Journal Line"; - Succes: Boolean; - UnapplyLastInvoicesErr: Label 'First you must unapply invoces that were applied to advance last time.'; - begin - DetailedCustLedgEntry1.SetCurrentKey("Cust. Ledger Entry No.", "Entry Type"); - DetailedCustLedgEntry1.SetRange("Cust. Ledger Entry No.", CustLedgerEntry."Entry No."); - DetailedCustLedgEntry1.SetRange("Entry Type", DetailedCustLedgEntry1."Entry Type"::Application); - DetailedCustLedgEntry1.SetRange(Unapplied, false); - Succes := false; - repeat - if DetailedCustLedgEntry1.FindLast() then begin - DetailedCustLedgEntry2.Reset(); - DetailedCustLedgEntry2.SetCurrentKey("Transaction No.", "Customer No.", "Entry Type"); - DetailedCustLedgEntry2.SetRange("Transaction No.", DetailedCustLedgEntry1."Transaction No."); - DetailedCustLedgEntry2.SetRange("Customer No.", DetailedCustLedgEntry1."Customer No."); - if DetailedCustLedgEntry2.FindSet() then - repeat - if (DetailedCustLedgEntry2."Entry Type" <> DetailedCustLedgEntry2."Entry Type"::"Initial Entry") and - not DetailedCustLedgEntry2.Unapplied - then begin - DetailedCustLedgEntry3.Reset(); - DetailedCustLedgEntry3.SetCurrentKey("Cust. Ledger Entry No.", "Entry Type"); - DetailedCustLedgEntry3.SetRange("Cust. Ledger Entry No.", DetailedCustLedgEntry2."Cust. Ledger Entry No."); - DetailedCustLedgEntry3.SetRange(Unapplied, false); - if DetailedCustLedgEntry3.FindLast() and - (DetailedCustLedgEntry3."Transaction No." > DetailedCustLedgEntry2."Transaction No.") - then - Error(UnapplyLastInvoicesErr); - end; - until DetailedCustLedgEntry2.Next() = 0; - - GenJournalLine.Init(); - GenJournalLine."Document No." := DetailedCustLedgEntry1."Document No."; - GenJournalLine."Posting Date" := DetailedCustLedgEntry1."Posting Date"; -#if not CLEAN22 -#pragma warning disable AL0432 - if not ReplaceVATDateMgtCZL.IsEnabled() then - GenJournalLine.Validate("VAT Date CZL", CustLedgerEntry."VAT Date CZL") - else -#pragma warning restore AL0432 -#endif - GenJournalLine.Validate("VAT Reporting Date", CustLedgerEntry."VAT Date CZL"); - GenJournalLine."Account Type" := GenJournalLine."Account Type"::Customer; - GenJournalLine."Account No." := DetailedCustLedgEntry1."Customer No."; - GenJournalLine.Correction := true; - GenJournalLine."Document Type" := GenJournalLine."Document Type"::" "; - GenJournalLine.Description := CustLedgerEntry.Description; - GenJournalLine."Shortcut Dimension 1 Code" := CustLedgerEntry."Global Dimension 1 Code"; - GenJournalLine."Shortcut Dimension 2 Code" := CustLedgerEntry."Global Dimension 2 Code"; - GenJournalLine."Dimension Set ID" := CustLedgerEntry."Dimension Set ID"; - GenJournalLine."Posting Group" := CustLedgerEntry."Customer Posting Group"; - GenJournalLine."Source Currency Code" := DetailedCustLedgEntry1."Currency Code"; - GenJournalLine."System-Created Entry" := true; - OnUnapplyCustLedgEntryOnBeforePostUnapplyCustLedgEntry(CustLedgerEntry, DetailedCustLedgEntry1, GenJournalLine); - GenJnlPostLine.UnapplyCustLedgEntry(GenJournalLine, DetailedCustLedgEntry1); - end else - Succes := true; - until Succes; + SalesAdvLetterPostCZZ.PostAdvanceLetterUnapplying(SalesInvoiceHeader, GenJnlPostLine, AdvancePostingParametersCZZ); end; procedure ApplyAdvanceLetter(var SalesInvoiceHeader: Record "Sales Invoice Header") var AdvanceLetterApplication: Record "Advance Letter Application CZZ"; + AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; CustLedgerEntry: Record "Cust. Ledger Entry"; SalesAdvLetterManagement: Codeunit "SalesAdvLetterManagement CZZ"; ConfirmManagement: Codeunit "Confirm Management"; @@ -2411,8 +1053,7 @@ codeunit 31002 "SalesAdvLetterManagement CZZ" if AdvanceLetterApplication.Amount > CustLedgerEntry."Remaining Amount" then Error(CannotApplyErr, CustLedgerEntry."Remaining Amount"); - PostAdvancePaymentUsage(AdvanceLetterApplication."Document Type"::"Posted Sales Invoice", SalesInvoiceHeader."No.", SalesInvoiceHeader, - CustLedgerEntry, GenJnlPostLine, false); + SalesAdvLetterPostCZZ.PostAdvanceLetterApplying(SalesInvoiceHeader, GenJnlPostLine, AdvancePostingParametersCZZ); end; #if not CLEAN24 [Obsolete('Replaced by CheckAdvancePayment with Variant parameter.', '24.0')] @@ -2497,6 +1138,7 @@ codeunit 31002 "SalesAdvLetterManagement CZZ" SalesAdvLetterEntryCZZ2: Record "Sales Adv. Letter Entry CZZ"; SalesAdvLetterEntryCZZ3: Record "Sales Adv. Letter Entry CZZ"; GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; + AmountRemainder: Decimal; AmountToDivide: Decimal; AmountToPost: Decimal; AmountTotal: Decimal; @@ -2515,17 +1157,21 @@ codeunit 31002 "SalesAdvLetterManagement CZZ" SalesAdvLetterHeaderCZZ.Get(SalesAdvLetterEntryCZZ."Sales Adv. Letter No."); - BufferAdvanceVATLines(SalesAdvLetterEntryCZZ, TempAdvancePostingBufferCZZ1, ToDate); + SalesAdvLetterPostCZZ.BufferAdvanceVATLines(SalesAdvLetterEntryCZZ, TempAdvancePostingBufferCZZ1, ToDate); TempAdvancePostingBufferCZZ1.CalcSums(Amount); VATDocAmtToDate := TempAdvancePostingBufferCZZ1.Amount; if VATDocAmtToDate <> 0 then begin Coeff := Amount / VATDocAmtToDate; + AmountRemainder := 0; TempAdvancePostingBufferCZZ1.FindSet(); repeat TempAdvancePostingBufferCZZ2.Init(); TempAdvancePostingBufferCZZ2 := TempAdvancePostingBufferCZZ1; - TempAdvancePostingBufferCZZ2.RecalcAmountsByCoefficient(Coeff); + AmountRemainder += TempAdvancePostingBufferCZZ2.Amount * Coeff; + TempAdvancePostingBufferCZZ2.Amount := AmountRemainder; + TempAdvancePostingBufferCZZ2.UpdateVATAmounts(); TempAdvancePostingBufferCZZ2.Insert(); + AmountRemainder -= TempAdvancePostingBufferCZZ2.Amount; until TempAdvancePostingBufferCZZ1.Next() = 0; if TempAdvancePostingBufferCZZ2.FindSet() then @@ -2535,7 +1181,7 @@ codeunit 31002 "SalesAdvLetterManagement CZZ" SalesAdvLetterEntryCZZ."Entry No.", DetEntryNo, DocumentNo, ToDate, ToDate, PostDescription, GenJnlPostLine, false, false); until TempAdvancePostingBufferCZZ2.Next() = 0; - BufferAdvanceVATLines(SalesAdvLetterEntryCZZ, TempAdvancePostingBufferCZZ1, 0D); + SalesAdvLetterPostCZZ.BufferAdvanceVATLines(SalesAdvLetterEntryCZZ, TempAdvancePostingBufferCZZ1, 0D); TempAdvancePostingBufferCZZ1.CalcSums(Amount); TempAdvancePostingBufferCZZ2.CalcSums(Amount); if TempAdvancePostingBufferCZZ1.Amount = 0 then @@ -2599,82 +1245,17 @@ codeunit 31002 "SalesAdvLetterManagement CZZ" 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) var - GenJournalLine: Record "Gen. Journal Line"; - SourceCodeSetup: Record "Source Code Setup"; - begin - SourceCodeSetup.Get(); - GetCurrency(SalesAdvLetterHeaderCZZ."Currency Code"); - - if VATAmount <> 0 then begin - InitGenJnlLineFromAdvance(SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, DocumentNo, SourceCodeSetup."Exchange Rate Adjmt.", PostDescription, GenJournalLine); - GenJournalLine.Validate("Posting Date", PostingDate); -#if not CLEAN22 -#pragma warning disable AL0432 - if not ReplaceVATDateMgtCZL.IsEnabled() then - GenJournalLine.Validate("VAT Date CZL", VATDate) - else -#pragma warning restore AL0432 -#endif - GenJournalLine.Validate("VAT Reporting Date", VATDate); - if VATAmount > 0 then begin - CurrencyGlob.TestField("Unrealized Losses Acc."); - GenJournalLine."Account No." := CurrencyGlob."Unrealized Losses Acc."; - end else begin - CurrencyGlob.TestField("Unrealized Gains Acc."); - GenJournalLine."Account No." := CurrencyGlob."Unrealized Gains Acc."; - end; - GenJournalLine.Validate(Amount, VATAmount); - if not Preview then - GenJnlPostLine.RunWithCheck(GenJournalLine); - - InitGenJnlLineFromAdvance(SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, DocumentNo, SourceCodeSetup."Exchange Rate Adjmt.", PostDescription, GenJournalLine); - GenJournalLine.Validate("Posting Date", PostingDate); -#if not CLEAN22 -#pragma warning disable AL0432 - if not ReplaceVATDateMgtCZL.IsEnabled() then - GenJournalLine.Validate("VAT Date CZL", VATDate) - else -#pragma warning restore AL0432 -#endif - GenJournalLine.Validate("VAT Reporting Date", VATDate); - GenJournalLine."Account No." := VATPostingSetup."Sales Adv. Letter Account CZZ"; - GenJournalLine.Validate(Amount, -VATAmount); - if not Preview then - GenJnlPostLine.RunWithCheck(GenJournalLine); - end; - - AdvEntryInit(Preview); - if Correction then - AdvEntryInitCancel(); - AdvEntryInitRelatedEntry(RelatedEntryNo); - AdvEntryInitDetCustLedgEntryNo(RelatedDetEntryNo); - AdvEntryInitVAT(VATPostingSetup."VAT Bus. Posting Group", VATPostingSetup."VAT Prod. Posting Group", VATDate, - 0, VATPostingSetup."VAT %", VATPostingSetup."VAT Identifier", VATPostingSetup."VAT Calculation Type", - 0, VATAmount, 0, Amount - VATAmount); - AdvEntryInsert("Advance Letter Entry Type CZZ"::"VAT Adjustment", SalesAdvLetterEntryCZZ."Sales Adv. Letter No.", PostingDate, - 0, Amount, '', 0, DocumentNo, - SalesAdvLetterEntryCZZ."Global Dimension 1 Code", SalesAdvLetterEntryCZZ."Global Dimension 2 Code", SalesAdvLetterEntryCZZ."Dimension Set ID", Preview); - end; - - local procedure ReverseUnrealizedExchangeRate(var SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; var SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; - var VATPostingSetup: Record "VAT Posting Setup"; Coef: Decimal; RelatedEntryNo: Integer; - DocumentNo: Code[20]; PostingDate: Date; VATDate: Date; PostDescription: Text[100]; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; Preview: Boolean) - var - AmountLCY: Decimal; - VATAmountLCY: Decimal; + AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; begin - if SalesAdvLetterEntryCZZ."Entry Type" <> SalesAdvLetterEntryCZZ."Entry Type"::Payment then - exit; + Clear(AdvancePostingParametersCZZ); + AdvancePostingParametersCZZ."Document No." := DocumentNo; + AdvancePostingParametersCZZ."Posting Date" := PostingDate; + AdvancePostingParametersCZZ."VAT Date" := VATDate; + AdvancePostingParametersCZZ."Posting Description" := PostDescription; + AdvancePostingParametersCZZ."Temporary Entries Only" := Preview; - GetRemAmtLCYVATAdjust(AmountLCY, VATAmountLCY, SalesAdvLetterEntryCZZ, PostingDate, VATPostingSetup."VAT Bus. Posting Group", VATPostingSetup."VAT Prod. Posting Group"); - if (AmountLCY = 0) and (VATAmountLCY = 0) then - exit; - - AmountLCY := Round(AmountLCY * Coef); - VATAmountLCY := Round(VATAmountLCY * Coef); - - PostUnrealizedExchangeRate(SalesAdvLetterEntryCZZ, SalesAdvLetterHeaderCZZ, VATPostingSetup, -AmountLCY, -VATAmountLCY, - RelatedEntryNo, 0, DocumentNo, PostingDate, VATDate, PostDescription, GenJnlPostLine, false, Preview); + SalesAdvLetterPostCZZ.PostUnrealizedExchangeRate( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, VATPostingSetup, Amount, VATAmount, RelatedEntryNo, RelatedDetEntryNo, Correction, GenJnlPostLine, AdvancePostingParametersCZZ); end; local procedure GetPostingDateUI(DefaultPostingDate: Date): Date @@ -2690,6 +1271,114 @@ codeunit 31002 "SalesAdvLetterManagement CZZ" GetPostingDateCZZ.GetValues(PostingDate); exit(PostingDate); end; +#if not CLEAN24 +#pragma warning disable AL0432 + internal procedure RaiseOnBeforePostAdvancePayment(CustLedgerEntry: Record "Cust. Ledger Entry"; GenJournalLine: Record "Gen. Journal Line"; LinkAmount: Decimal; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var IsHandled: Boolean); + begin + OnBeforePostAdvancePayment(CustLedgerEntry, GenJournalLine, LinkAmount, GenJnlPostLine, IsHandled); + end; + + internal procedure RaiseOnBeforePostPaymentRepos(var GenJournalLine: Record "Gen. Journal Line"; var SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; PostedGenJournalLine: Record "Gen. Journal Line") + begin + OnBeforePostPaymentRepos(GenJournalLine, SalesAdvLetterHeaderCZZ, PostedGenJournalLine); + end; + + internal procedure RaiseOnAfterPostPaymentRepos(var GenJournalLine: Record "Gen. Journal Line"; var SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; PostedGenJournalLine: Record "Gen. Journal Line") + begin + OnAfterPostPaymentRepos(GenJournalLine, SalesAdvLetterHeaderCZZ, PostedGenJournalLine); + end; + + internal procedure RaiseOnBeforePostPayment(var GenJournalLine: Record "Gen. Journal Line"; var SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; PostedGenJournalLine: Record "Gen. Journal Line") + begin + OnBeforePostPayment(GenJournalLine, SalesAdvLetterHeaderCZZ, PostedGenJournalLine); + end; + + internal procedure RaiseOnAfterPostPayment(var GenJournalLine: Record "Gen. Journal Line"; var SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; PostedGenJournalLine: Record "Gen. Journal Line") + begin + OnAfterPostPayment(GenJournalLine, SalesAdvLetterHeaderCZZ, PostedGenJournalLine); + end; + + internal procedure RaiseOnPostAdvancePaymentVATOnBeforeGenJnlPostLine(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; var GenJournalLine: Record "Gen. Journal Line") + begin + OnPostAdvancePaymentVATOnBeforeGenJnlPostLine(SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, GenJournalLine); + end; + + internal procedure RaiseOnBeforePostAdvancePaymentUsage(AdvLetterUsageDocTypeCZZ: Enum "Adv. Letter Usage Doc.Type CZZ"; DocumentNo: Code[20]; var SalesInvoiceHeader: Record "Sales Invoice Header"; var CustLedgerEntry: Record "Cust. Ledger Entry"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; Preview: Boolean; var IsHandled: Boolean) + begin + OnBeforePostAdvancePaymentUsage(AdvLetterUsageDocTypeCZZ, DocumentNo, SalesInvoiceHeader, CustLedgerEntry, GenJnlPostLine, Preview, IsHandled); + end; + + internal procedure RaiseOnPostAdvancePaymentUsageOnBeforeLoopSalesAdvLetterEntry(var AdvanceLetterApplicationCZZ: Record "Advance Letter Application CZZ"; var SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ") + begin + OnPostAdvancePaymentUsageOnBeforeLoopSalesAdvLetterEntry(AdvanceLetterApplicationCZZ, SalesAdvLetterEntryCZZ); + end; + + internal procedure RaiseOnBeforePostReversePaymentRepos(var GenJournalLine: Record "Gen. Journal Line"; var SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ") + begin + OnBeforePostReversePaymentRepos(GenJournalLine, SalesAdvLetterHeaderCZZ); + end; + + internal procedure RaiseOnAfterPostReversePaymentRepos(var GenJournalLine: Record "Gen. Journal Line"; var SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ") + begin + OnAfterPostReversePaymentRepos(GenJournalLine, SalesAdvLetterHeaderCZZ); + end; + + internal procedure RaiseOnBeforePostReversePayment(var GenJournalLine: Record "Gen. Journal Line"; var SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ") + begin + OnBeforePostReversePayment(GenJournalLine, SalesAdvLetterHeaderCZZ); + end; + + internal procedure RaiseOnAfterPostReversePayment(var GenJournalLine: Record "Gen. Journal Line"; var SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ") + begin + OnAfterPostReversePayment(GenJournalLine, SalesAdvLetterHeaderCZZ); + end; + + internal procedure RaiseOnBeforePostReversePaymentVAT(var SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; PostingDate: Date; var Preview: Boolean; var IsHandled: Boolean) + begin + OnBeforePostReversePaymentVAT(SalesAdvLetterEntryCZZ, PostingDate, Preview, IsHandled); + end; + + internal procedure RaiseOnBeforePostClosePaymentRepos(var GenJournalLine: Record "Gen. Journal Line"; var SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ") + begin + OnBeforePostClosePaymentRepos(GenJournalLine, SalesAdvLetterHeaderCZZ); + end; + + internal procedure RaiseOnAfterPostClosePaymentRepos(var GenJournalLine: Record "Gen. Journal Line"; var SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ") + begin + OnAfterPostClosePaymentRepos(GenJournalLine, SalesAdvLetterHeaderCZZ); + end; + + internal procedure RaiseOnBeforePostClosePayment(var GenJournalLine: Record "Gen. Journal Line"; var SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ") + begin + OnBeforePostClosePayment(GenJournalLine, SalesAdvLetterHeaderCZZ); + end; + + internal procedure RaiseOnAfterPostClosePayment(var GenJournalLine: Record "Gen. Journal Line"; var SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ") + begin + OnAfterPostClosePayment(GenJournalLine, SalesAdvLetterHeaderCZZ); + end; + + internal procedure RaiseOnAfterInitGenJnlLineFromAdvance(var SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; var SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; var GenJournalLine: Record "Gen. Journal Line") + begin + OnAfterInitGenJnlLineFromAdvance(SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, GenJournalLine); + end; + + internal procedure RaiseOnAfterInitGenJnlLineFromCustLedgEntry(var CustLedgerEntry: Record "Cust. Ledger Entry"; var GenJournalLine: Record "Gen. Journal Line") + begin + OnAfterInitGenJnlLineFromCustLedgEntry(CustLedgerEntry, GenJournalLine); + end; + + internal procedure RaiseOnAfterPostAdvancePaymentUsage(AdvLetterUsageDocTypeCZZ: Enum "Adv. Letter Usage Doc.Type CZZ"; DocumentNo: Code[20]; var SalesInvoiceHeader: Record "Sales Invoice Header"; var CustLedgerEntry: Record "Cust. Ledger Entry"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; Preview: Boolean) + begin + OnAfterPostAdvancePaymentUsage(AdvLetterUsageDocTypeCZZ, DocumentNo, SalesInvoiceHeader, CustLedgerEntry, GenJnlPostLine, Preview); + end; + + internal procedure RaiseOnUnapplyCustLedgEntryOnBeforePostUnapplyCustLedgEntry(var CustLedgerEntry: Record "Cust. Ledger Entry"; var DetailedCustLedgEntry: Record "Detailed Cust. Ledg. Entry"; var GenJournalLine: Record "Gen. Journal Line") + begin + OnUnapplyCustLedgEntryOnBeforePostUnapplyCustLedgEntry(CustLedgerEntry, DetailedCustLedgEntry, GenJournalLine); + end; +#pragma warning restore AL0432 +#endif [IntegrationEvent(false, false)] local procedure OnBeforeInsertAdvEntry(var SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; var Preview: Boolean) @@ -2711,21 +1400,25 @@ codeunit 31002 "SalesAdvLetterManagement CZZ" begin end; + [Obsolete('Replaced by OnPostAdvancePaymentOnBeforePostPaymentApplication event in "Sales Adv. Letter-Post CZZ" codeunit.', '24.0')] [IntegrationEvent(false, false)] local procedure OnBeforePostPaymentRepos(var GenJournalLine: Record "Gen. Journal Line"; var SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; PostedGenJournalLine: Record "Gen. Journal Line") begin end; + [Obsolete('Replaced by OnPostAdvancePaymentOnAfterPostPaymentApplication event in "Sales Adv. Letter-Post CZZ" codeunit.', '24.0')] [IntegrationEvent(false, false)] local procedure OnAfterPostPaymentRepos(var GenJournalLine: Record "Gen. Journal Line"; var SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; PostedGenJournalLine: Record "Gen. Journal Line") begin end; + [Obsolete('Replaced by OnPostAdvancePaymentOnBeforePostAdvancePayment event in "Sales Adv. Letter-Post CZZ" codeunit.', '24.0')] [IntegrationEvent(false, false)] local procedure OnBeforePostPayment(var GenJournalLine: Record "Gen. Journal Line"; var SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; PostedGenJournalLine: Record "Gen. Journal Line") begin end; + [Obsolete('Replaced by OnPostAdvancePaymentOnAfterPostAdvancePayment event in "Sales Adv. Letter-Post CZZ" codeunit.', '24.0')] [IntegrationEvent(false, false)] local procedure OnAfterPostPayment(var GenJournalLine: Record "Gen. Journal Line"; var SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; PostedGenJournalLine: Record "Gen. Journal Line") begin @@ -2736,41 +1429,49 @@ codeunit 31002 "SalesAdvLetterManagement CZZ" begin end; + [Obsolete('Replaced by OnReverseAdvancePaymentOnBeforePostInvoiceApplication event in "Sales Adv. Letter-Post CZZ" codeunit.', '24.0')] [IntegrationEvent(false, false)] local procedure OnBeforePostReversePaymentRepos(var GenJournalLine: Record "Gen. Journal Line"; var SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ") begin end; + [Obsolete('Replaced by OnReverseAdvancePaymentOnAfterPostInvoiceApplication event in "Sales Adv. Letter-Post CZZ" codeunit.', '24.0')] [IntegrationEvent(false, false)] local procedure OnAfterPostReversePaymentRepos(var GenJournalLine: Record "Gen. Journal Line"; var SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ") begin end; + [Obsolete('Replaced by OnReverseAdvancePaymentOnBeforePostAdvancePaymentUsage event in "Sales Adv. Letter-Post CZZ" codeunit.', '24.0')] [IntegrationEvent(false, false)] local procedure OnBeforePostReversePayment(var GenJournalLine: Record "Gen. Journal Line"; var SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ") begin end; + [Obsolete('Replaced by OnReverseAdvancePaymentOnAfterPostAdvancePaymentUsage event in "Sales Adv. Letter-Post CZZ" codeunit.', '24.0')] [IntegrationEvent(false, false)] local procedure OnAfterPostReversePayment(var GenJournalLine: Record "Gen. Journal Line"; var SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ") begin end; + [Obsolete('Replaced by OnBeforeReverseAdvancePaymentVAT event in "Sales Adv. Letter-Post CZZ" codeunit.', '24.0')] [IntegrationEvent(false, false)] local procedure OnBeforePostReversePaymentVAT(var SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; PostingDate: Date; var Preview: Boolean; var IsHandled: Boolean) begin end; + [Obsolete('Replaced by OnPostAdvanceLetterEntryClosingOnBeforePostBalance event in "Sales Adv. Letter-Post CZZ" codeunit.', '24.0')] [IntegrationEvent(false, false)] local procedure OnBeforePostClosePaymentRepos(var GenJournalLine: Record "Gen. Journal Line"; var SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ") begin end; + [Obsolete('Replaced by OnPostAdvanceLetterEntryClosingOnBeforePostBalance event in "Sales Adv. Letter-Post CZZ" codeunit.', '24.0')] [IntegrationEvent(false, false)] local procedure OnAfterPostClosePaymentRepos(var GenJournalLine: Record "Gen. Journal Line"; var SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ") begin end; + [Obsolete('Replaced by OnPostAdvanceLetterEntryClosingOnBeforePost event in "Sales Adv. Letter-Post CZZ" codeunit.', '24.0')] [IntegrationEvent(false, false)] local procedure OnBeforePostClosePayment(var GenJournalLine: Record "Gen. Journal Line"; var SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ") begin @@ -2781,6 +1482,7 @@ codeunit 31002 "SalesAdvLetterManagement CZZ" begin end; + [Obsolete('Replaced by OnPostAdvanceLetterEntryClosingOnAfterPost event in "Sales Adv. Letter-Post CZZ" codeunit.', '24.0')] [IntegrationEvent(false, false)] local procedure OnAfterPostClosePayment(var GenJournalLine: Record "Gen. Journal Line"; var SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ") begin @@ -2791,21 +1493,25 @@ codeunit 31002 "SalesAdvLetterManagement CZZ" begin end; + [Obsolete('Replaced by OnAfterInitGenJournalLineFromCustLedgerEntry event in "Sales Adv. Letter-Post CZZ" codeunit.', '24.0')] [IntegrationEvent(true, false)] local procedure OnAfterInitGenJnlLineFromCustLedgEntry(var CustLedgerEntry: Record "Cust. Ledger Entry"; var GenJournalLine: Record "Gen. Journal Line") begin end; + [Obsolete('Replaced by OnUnapplyCustLedgEntryOnBeforePostUnapplyCustLedgEntry event in "Sales Adv. Letter-Post CZZ" codeunit.', '24.0')] [IntegrationEvent(false, false)] local procedure OnUnapplyCustLedgEntryOnBeforePostUnapplyCustLedgEntry(var CustLedgerEntry: Record "Cust. Ledger Entry"; var DetailedCustLedgEntry: Record "Detailed Cust. Ledg. Entry"; var GenJournalLine: Record "Gen. Journal Line") begin end; + [Obsolete('Replaced by OnAfterInitGenJournalLine event in "Sales Adv. Letter-Post CZZ" codeunit.', '24.0')] [IntegrationEvent(true, false)] local procedure OnAfterInitGenJnlLineFromAdvance(var SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; var SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; var GenJournalLine: Record "Gen. Journal Line") begin end; + [Obsolete('Replaced by OnBeforePostAdvancePayment event in "Sales Adv. Letter-Post CZZ" codeunit.', '24.0')] [IntegrationEvent(false, false)] local procedure OnBeforePostAdvancePayment(CustLedgerEntry: Record "Cust. Ledger Entry"; GenJournalLine: Record "Gen. Journal Line"; LinkAmount: Decimal; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var IsHandled: Boolean); begin @@ -2821,16 +1527,19 @@ codeunit 31002 "SalesAdvLetterManagement CZZ" begin end; + [Obsolete('Replaced by OnPostAdvancePaymentUsageOnAfterSetSalesAdvLetterEntryFilter event in "Sales Adv. Letter-Post CZZ" codeunit.', '24.0')] [IntegrationEvent(false, false)] local procedure OnPostAdvancePaymentUsageOnBeforeLoopSalesAdvLetterEntry(var AdvanceLetterApplicationCZZ: Record "Advance Letter Application CZZ"; var SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ") begin end; + [Obsolete('Replaced by OnAfterPostAdvancePaymentUsage event in "Sales Adv. Letter-Post CZZ" codeunit.', '24.0')] [IntegrationEvent(false, false)] local procedure OnAfterPostAdvancePaymentUsage(AdvLetterUsageDocTypeCZZ: Enum "Adv. Letter Usage Doc.Type CZZ"; DocumentNo: Code[20]; var SalesInvoiceHeader: Record "Sales Invoice Header"; var CustLedgerEntry: Record "Cust. Ledger Entry"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; Preview: Boolean) begin end; + [Obsolete('Replaced by OnBeforePostAdvancePayment event in "Sales Adv. Letter-Post CZZ" codeunit.', '24.0')] [IntegrationEvent(true, false)] local procedure OnBeforePostAdvancePaymentUsage(AdvLetterUsageDocTypeCZZ: Enum "Adv. Letter Usage Doc.Type CZZ"; DocumentNo: Code[20]; var SalesInvoiceHeader: Record "Sales Invoice Header"; var CustLedgerEntry: Record "Cust. Ledger Entry"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; Preview: Boolean; var IsHandled: Boolean) begin @@ -2841,6 +1550,7 @@ codeunit 31002 "SalesAdvLetterManagement CZZ" begin end; + [Obsolete('Replaced by OnBeforePostAdvancePayment event in "Sales Adv. Letter-Post CZZ" codeunit.', '24.0')] [IntegrationEvent(true, false)] local procedure OnPostAdvancePaymentVATOnBeforeGenJnlPostLine(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; var GenJournalLine: Record "Gen. Journal Line") begin diff --git a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/SalesAdvLetterPostCZZ.Codeunit.al b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/SalesAdvLetterPostCZZ.Codeunit.al new file mode 100644 index 0000000000..1a8fbb5481 --- /dev/null +++ b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/SalesAdvLetterPostCZZ.Codeunit.al @@ -0,0 +1,2664 @@ +// ------------------------------------------------------------------------------------------------ +// 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.AdvancePayments; + +using Microsoft.Finance.Currency; +using Microsoft.Finance.GeneralLedger.Journal; +using Microsoft.Finance.GeneralLedger.Posting; +#if not CLEAN22 +using Microsoft.Finance.VAT.Calculation; +#endif +using Microsoft.Finance.VAT.Setup; +using Microsoft.Foundation.AuditCodes; +using Microsoft.Foundation.NoSeries; +using Microsoft.Sales.Document; +using Microsoft.Sales.History; +using Microsoft.Sales.Receivables; + +codeunit 31143 "Sales Adv. Letter-Post CZZ" +{ + Permissions = tabledata "Sales Adv. Letter Entry CZZ" = im; + + var + CurrencyGlob: Record Currency; + TempSalesAdvLetterEntryCZZGlob: Record "Sales Adv. Letter Entry CZZ" temporary; + SalesAdvLetterManagementCZZ: Codeunit "SalesAdvLetterManagement CZZ"; + ExceededAmountErr: Label 'Amount has been exceeded.'; + ExceededAmountToPayErr: Label 'The amount cannot be higher than to pay on advance letter.'; + ExceededRemainingAmountErr: Label 'The amount cannot be higher than remaining amount on ledger entry.'; + NothingToPostErr: Label 'Nothing to Post.'; + ReverseAmountErr: Label 'Reverse amount %1 is not posible on entry %2.', Comment = '%1 = Reverse Amount, %2 = Sales Advance Entry No.'; + TemporaryRecordErr: Label 'The record of "Sales Adv. Letter Entry CZZ" must be temporary.'; + UnlinkIsNotPossibleErr: Label 'Unlink is not possible, because %1 entry exists.', Comment = '%1 = Entry type'; + UnapplyIsNotPossibleErr: Label 'Unapply is not possible.'; + UnapplyLastInvoicesErr: Label 'First you must unapply invoces that were applied to advance last time.'; + + procedure PostAdvancePayment( + var CustLedgerEntry: Record "Cust. Ledger Entry"; + PostedGenJournalLine: Record "Gen. Journal Line"; + var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; + AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ") EntryNo: Integer + var + GenJournalLine: Record "Gen. Journal Line"; + SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; + CustLedgerEntryPayment: Record "Cust. Ledger Entry"; + Amount, AmountLCY : Decimal; + GLEntryNo: Integer; + IsHandled: Boolean; + begin + IsHandled := false; + OnBeforePostAdvancePayment(CustLedgerEntry, PostedGenJournalLine, GenJnlPostLine, AdvancePostingParametersCZZ, IsHandled); +#if not CLEAN24 + RaiseOnBeforePostAdvancePayment( + CustLedgerEntry, PostedGenJournalLine, AdvancePostingParametersCZZ."Amount to Link", GenJnlPostLine, IsHandled); +#endif + if IsHandled then + exit; + + CustLedgerEntry.TestField("Advance Letter No. CZZ", ''); + SalesAdvLetterHeaderCZZ.Get(PostedGenJournalLine."Advance Letter No. CZZ"); + SalesAdvLetterHeaderCZZ.CheckSalesAdvanceLetterPostRestrictions(); + SalesAdvLetterHeaderCZZ.TestField("Currency Code", CustLedgerEntry."Currency Code"); + SalesAdvLetterHeaderCZZ.TestField("Bill-to Customer No.", CustLedgerEntry."Customer No."); + + CustLedgerEntry.CalcFields("Remaining Amount", "Remaining Amt. (LCY)"); + if AdvancePostingParametersCZZ."Amount to Link" = 0 then begin + Amount := CustLedgerEntry."Remaining Amount"; + AmountLCY := CustLedgerEntry."Remaining Amt. (LCY)"; + end else begin + if AdvancePostingParametersCZZ."Amount to Link" > -CustLedgerEntry."Remaining Amount" then + Error(ExceededRemainingAmountErr); + + Amount := -AdvancePostingParametersCZZ."Amount to Link"; + AmountLCY := Round(Amount / CustLedgerEntry."Original Currency Factor"); + end; + + SalesAdvLetterHeaderCZZ.CalcFields("To Pay"); + if -Amount > SalesAdvLetterHeaderCZZ."To Pay" then + Error(ExceededAmountToPayErr); + + // Post payment application + InitGenJournalLine(CustLedgerEntry, GenJournalLine); + GenJournalLine."Posting Date" := AdvancePostingParametersCZZ."Posting Date"; + GenJournalLine."Adv. Letter Template Code CZZ" := SalesAdvLetterHeaderCZZ."Advance Letter Code"; + GenJournalLine.Correction := true; + GenJournalLine.Amount := -Amount; + GenJournalLine."Amount (LCY)" := -AmountLCY; + if not AdvancePostingParametersCZZ."Temporary Entries Only" then begin + CustLedgerEntry.SetApplication(SalesAdvLetterHeaderCZZ."Advance Letter Code", ''); + GenJournalLine."Applies-to ID" := CustLedgerEntry."Applies-to ID"; + OnPostAdvancePaymentOnBeforePostPaymentApplication( + SalesAdvLetterHeaderCZZ, PostedGenJournalLine, AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); +#if not CLEAN24 + RaiseOnBeforePostPaymentRepos(GenJournalLine, SalesAdvLetterHeaderCZZ, PostedGenJournalLine); +#endif + GLEntryNo := RunGenJnlPostLine(GenJournalLine, GenJnlPostLine, false, false, false); + OnPostAdvancePaymentOnAfterPostPaymentApplication(SalesAdvLetterHeaderCZZ, PostedGenJournalLine, + AdvancePostingParametersCZZ, GLEntryNo, GenJnlPostLine, GenJournalLine); +#if not CLEAN24 + RaiseOnAfterPostPaymentRepos(GenJournalLine, SalesAdvLetterHeaderCZZ, PostedGenJournalLine); +#endif + end; + + // Post advance payment + InitGenJournalLine(CustLedgerEntry, GenJournalLine); + GenJournalLine."Posting Date" := AdvancePostingParametersCZZ."Posting Date"; + GenJournalLine."Adv. Letter Template Code CZZ" := SalesAdvLetterHeaderCZZ."Advance Letter Code"; + GenJournalLine."Adv. Letter No. (Entry) CZZ" := SalesAdvLetterHeaderCZZ."No."; + GenJournalLine."Use Advance G/L Account CZZ" := true; + GenJournalLine.Amount := Amount; + GenJournalLine."Amount (LCY)" := AmountLCY; + if not AdvancePostingParametersCZZ."Temporary Entries Only" then begin + OnPostAdvancePaymentOnBeforePostAdvancePayment(SalesAdvLetterHeaderCZZ, PostedGenJournalLine, AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); +#if not CLEAN24 + RaiseOnBeforePostPayment(GenJournalLine, SalesAdvLetterHeaderCZZ, PostedGenJournalLine); +#endif + GLEntryNo := RunGenJnlPostLine(GenJournalLine, GenJnlPostLine, false, false, false); + OnPostAdvancePaymentOnAfterPostAdvancePayment(SalesAdvLetterHeaderCZZ, PostedGenJournalLine, + AdvancePostingParametersCZZ, GLEntryNo, GenJnlPostLine, GenJournalLine); +#if not CLEAN24 + RaiseOnAfterPostPayment(GenJournalLine, SalesAdvLetterHeaderCZZ, PostedGenJournalLine); +#endif + end; + + CustLedgerEntryPayment.FindLast(); + + TempSalesAdvLetterEntryCZZGlob.InitNewEntry(); + TempSalesAdvLetterEntryCZZGlob.InitCustLedgerEntry(CustLedgerEntryPayment); + TempSalesAdvLetterEntryCZZGlob.CopyFromGenJnlLine(GenJournalLine); + TempSalesAdvLetterEntryCZZGlob."Entry Type" := "Advance Letter Entry Type CZZ"::Payment; + TempSalesAdvLetterEntryCZZGlob."Sales Adv. Letter No." := SalesAdvLetterHeaderCZZ."No."; + EntryNo := TempSalesAdvLetterEntryCZZGlob.InsertNewEntry(not AdvancePostingParametersCZZ."Temporary Entries Only"); + + if not AdvancePostingParametersCZZ."Temporary Entries Only" then + SalesAdvLetterHeaderCZZ.UpdateStatus(SalesAdvLetterHeaderCZZ.Status::"To Use"); + + OnAfterPostAdvancePayment(SalesAdvLetterHeaderCZZ, CustLedgerEntry, PostedGenJournalLine, EntryNo, GenJnlPostLine, AdvancePostingParametersCZZ); + end; + + procedure PostAdvancePaymentUnlinking( + var SalesAdvLetterEntryCZZ: Record "Sales 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"; + GenJournalLine: Record "Gen. Journal Line"; + SalesAdvLetterEntryCZZ2: Record "Sales Adv. Letter Entry CZZ"; + SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; + CustLedgerEntry: Record "Cust. Ledger Entry"; + CustLedgerEntryAdv: Record "Cust. Ledger Entry"; + CustLedgerEntryPay: Record "Cust. Ledger Entry"; + GLEntryNo: Integer; + IsHandled: Boolean; + begin + IsHandled := false; + OnBeforePostAdvancePaymentUnlinking(SalesAdvLetterEntryCZZ, GenJnlPostLine, AdvancePostingParametersCZZ, IsHandled); + if IsHandled then + exit; + + SalesAdvLetterEntryCZZ.TestField("Entry Type", SalesAdvLetterEntryCZZ."Entry Type"::Payment); + SalesAdvLetterEntryCZZ.TestField(Cancelled, false); + + SalesAdvLetterEntryCZZ2.SetRange("Sales Adv. Letter No.", SalesAdvLetterEntryCZZ."Sales Adv. Letter No."); + SalesAdvLetterEntryCZZ2.SetRange("Related Entry", SalesAdvLetterEntryCZZ."Entry No."); + SalesAdvLetterEntryCZZ2.SetRange(Cancelled, false); + SalesAdvLetterEntryCZZ2.SetFilter("Entry Type", '<>%1', SalesAdvLetterEntryCZZ2."Entry Type"::"VAT Payment"); + if SalesAdvLetterEntryCZZ2.FindFirst() then + Error(UnlinkIsNotPossibleErr, SalesAdvLetterEntryCZZ2."Entry Type"); + + SalesAdvLetterHeaderCZZ.Get(SalesAdvLetterEntryCZZ."Sales Adv. Letter No."); + + SalesAdvLetterEntryCZZ2.SetRange("Entry Type", SalesAdvLetterEntryCZZ2."Entry Type"::"VAT Payment"); + if SalesAdvLetterEntryCZZ2.FindSet() then + repeat + Clear(AdvancePostingBufferCZZ); + AdvancePostingBufferCZZ.PrepareForSalesAdvLetterEntry(SalesAdvLetterEntryCZZ2); + Clear(AdvancePostingParametersCZZ2); + AdvancePostingParametersCZZ2.CopyFromSalesAdvLetterEntry(SalesAdvLetterEntryCZZ2); + AdvancePostingParametersCZZ2."Document Type" := "Gen. Journal Document Type"::Invoice; + PostAdvancePaymentVATUnlinking( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ2, AdvancePostingBufferCZZ, GenJnlPostLine, AdvancePostingParametersCZZ2); + until SalesAdvLetterEntryCZZ2.Next() = 0; + + CustLedgerEntryAdv.Get(SalesAdvLetterEntryCZZ."Cust. Ledger Entry No."); + CustLedgerEntryPay := CustLedgerEntryAdv; +#pragma warning disable AA0181 + CustLedgerEntryPay.Next(-1); +#pragma warning restore AA0181 + UnapplyCustLedgEntry(CustLedgerEntryPay, GenJnlPostLine); + + // Post advance payment application + InitGenJournalLine(CustLedgerEntryAdv, GenJournalLine); + GenJournalLine."Posting Date" := AdvancePostingParametersCZZ."Posting Date"; + GenJournalLine."Adv. Letter Template Code CZZ" := SalesAdvLetterHeaderCZZ."Advance Letter Code"; + GenJournalLine."Adv. Letter No. (Entry) CZZ" := SalesAdvLetterHeaderCZZ."No."; + GenJournalLine."Use Advance G/L Account CZZ" := true; + GenJournalLine.Correction := true; + GenJournalLine.SetCurrencyFactor( + SalesAdvLetterEntryCZZ."Currency Code", SalesAdvLetterEntryCZZ."Currency Factor"); + GenJournalLine.Amount := -SalesAdvLetterEntryCZZ.Amount; + GenJournalLine."Amount (LCY)" := -SalesAdvLetterEntryCZZ."Amount (LCY)"; + if not AdvancePostingParametersCZZ."Temporary Entries Only" then begin + CustLedgerEntryAdv.SetApplication('', SalesAdvLetterHeaderCZZ."No."); + GenJournalLine."Applies-to ID" := CustLedgerEntryAdv."Applies-to ID"; + OnPostAdvancePaymentUnlinkingOnBeforePostAdvancePaymentApplication( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); + GLEntryNo := RunGenJnlPostLine(GenJournalLine, GenJnlPostLine, false, false, false); + OnPostAdvancePaymentUnlinkingOnAfterPostAdvancePaymentApplication( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, + AdvancePostingParametersCZZ, GLEntryNo, GenJnlPostLine, GenJournalLine); + end; + + CustLedgerEntry.FindLast(); + + TempSalesAdvLetterEntryCZZGlob.InitNewEntry(); + TempSalesAdvLetterEntryCZZGlob.InitCustLedgerEntry(CustLedgerEntry); + TempSalesAdvLetterEntryCZZGlob.InitRelatedEntry(SalesAdvLetterEntryCZZ); + TempSalesAdvLetterEntryCZZGlob.CopyFromGenJnlLine(GenJournalLine); + TempSalesAdvLetterEntryCZZGlob."Entry Type" := SalesAdvLetterEntryCZZ."Entry Type"; + TempSalesAdvLetterEntryCZZGlob."Sales Adv. Letter No." := SalesAdvLetterHeaderCZZ."No."; + TempSalesAdvLetterEntryCZZGlob.Cancelled := true; + TempSalesAdvLetterEntryCZZGlob.InsertNewEntry(not AdvancePostingParametersCZZ."Temporary Entries Only"); + + // Post payment application balance + InitGenJournalLine(CustLedgerEntryAdv, GenJournalLine); + GenJournalLine."Posting Date" := AdvancePostingParametersCZZ."Posting Date"; + GenJournalLine."Adv. Letter Template Code CZZ" := SalesAdvLetterHeaderCZZ."Advance Letter Code"; + GenJournalLine.SetCurrencyFactor( + SalesAdvLetterEntryCZZ."Currency Code", SalesAdvLetterEntryCZZ."Currency Factor"); + GenJournalLine.Amount := SalesAdvLetterEntryCZZ.Amount; + GenJournalLine."Amount (LCY)" := SalesAdvLetterEntryCZZ."Amount (LCY)"; + if not AdvancePostingParametersCZZ."Temporary Entries Only" then begin + CustLedgerEntryPay.SetApplication('', ''); + GenJournalLine."Applies-to ID" := CustLedgerEntryPay."Applies-to ID"; + OnPostAdvancePaymentUnlinkingOnBeforePostPaymentApplication( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); + GLEntryNo := RunGenJnlPostLine(GenJournalLine, GenJnlPostLine, false, false, false); + OnPostAdvancePaymentUnlinkingOnAfterPostPaymentApplication( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, + AdvancePostingParametersCZZ, GLEntryNo, GenJnlPostLine, GenJournalLine); + + SalesAdvLetterEntryCZZ.Cancelled := true; + SalesAdvLetterEntryCZZ.Modify(); + + SalesAdvLetterHeaderCZZ.UpdateStatus(SalesAdvLetterHeaderCZZ.Status::"To Pay"); + end; + + OnAfterPostAdvancePaymentUnlinking(SalesAdvLetterEntryCZZ, GenJnlPostLine, AdvancePostingParametersCZZ); + end; + + procedure PostAdvancePaymentVAT( + var SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; + var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; + var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; + AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ") + var + AdvancePostingParametersCZZ2: Record "Advance Posting Parameters CZZ"; + CustLedgerEntry: Record "Cust. Ledger Entry"; + GenJournalLine: Record "Gen. Journal Line"; + SalesAdvLetterEntryCZZ2: Record "Sales Adv. Letter Entry CZZ"; + SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; + VATPostingSetup: Record "VAT Posting Setup"; + GLEntryNo: Integer; + IsHandled: Boolean; + begin + IsHandled := false; + OnBeforePostAdvancePaymentVAT(SalesAdvLetterEntryCZZ, AdvancePostingBufferCZZ, GenJnlPostLine, AdvancePostingParametersCZZ, IsHandled); + if IsHandled then + exit; + + if SalesAdvLetterEntryCZZ."Entry Type" <> SalesAdvLetterEntryCZZ."Entry Type"::Payment then + exit; + + SalesAdvLetterEntryCZZ.TestField(Cancelled, false); + + AdvancePostingParametersCZZ.CheckSalesDates(); + AdvancePostingParametersCZZ.CheckDocumentNo(); + + SalesAdvLetterHeaderCZZ.Get(SalesAdvLetterEntryCZZ."Sales Adv. Letter No."); + SalesAdvLetterHeaderCZZ.CalcFields("Amount Including VAT"); + if SalesAdvLetterHeaderCZZ."Amount Including VAT" = 0 then + exit; + + AdvancePostingBufferCZZ.SetFilter(Amount, '<>0'); + if AdvancePostingBufferCZZ.IsEmpty() then + Error(NothingToPostErr); + + 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"); + SalesAdvLetterEntryCZZ2.CalcSums(Amount); + AdvancePostingBufferCZZ.CalcSums(Amount); + if Abs(SalesAdvLetterEntryCZZ.Amount - SalesAdvLetterEntryCZZ2.Amount) < Abs(AdvancePostingBufferCZZ.Amount) then + Error(ExceededAmountErr); + + if AdvancePostingParametersCZZ."Source Code" = '' then begin + CustLedgerEntry.Get(SalesAdvLetterEntryCZZ."Cust. Ledger Entry No."); + 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 not CLEAN24 + 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"); + + // 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; + + OnAfterPostAdvancePaymentVAT( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, AdvancePostingBufferCZZ, + GenJnlPostLine, AdvancePostingParametersCZZ); + end; + + local procedure PostAdvancePaymentVATUnlinking( + SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; + var SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; + var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; + var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; + AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ") + var + AdvancePostingParametersCZZ2: Record "Advance Posting Parameters CZZ"; + VATPostingSetup: Record "VAT Posting Setup"; + GenJournalLine: Record "Gen. Journal Line"; + EntryNo, GLEntryNo : Integer; + IsHandled: Boolean; + begin + IsHandled := false; + OnBeforePostAdvancePaymentVATUnlinking( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, AdvancePostingBufferCZZ, + GenJnlPostLine, AdvancePostingParametersCZZ, IsHandled); + if IsHandled then + exit; + + SalesAdvLetterEntryCZZ.TestField("Entry Type", SalesAdvLetterEntryCZZ."Entry Type"::"VAT Payment"); + SalesAdvLetterEntryCZZ.TestField(Cancelled, false); + + VATPostingSetup.Get(AdvancePostingBufferCZZ."VAT Bus. Posting Group", AdvancePostingBufferCZZ."VAT Prod. Posting Group"); + + // 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 + OnPostAdvancePaymentVATUnlinkingOnBeforePost( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, VATPostingSetup, + AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); + GLEntryNo := RunGenJnlPostLine(GenJournalLine, GenJnlPostLine, true, true, false); + OnPostAdvancePaymentVATUnlinkingOnAfterPost( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, VATPostingSetup, + AdvancePostingParametersCZZ, GLEntryNo, GenJnlPostLine, GenJournalLine); + end; + + TempSalesAdvLetterEntryCZZGlob.InitNewEntry(); + TempSalesAdvLetterEntryCZZGlob.InitRelatedEntry(SalesAdvLetterEntryCZZ."Related Entry"); + 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.Cancelled := true; + EntryNo := TempSalesAdvLetterEntryCZZGlob.InsertNewEntry(not AdvancePostingParametersCZZ."Temporary Entries Only"); + + // Post balance of advance payment VAT unlinking + AdvancePostingBufferCZZ.ReverseAmounts(); + AdvancePostingParametersCZZ2.InitNew(AdvancePostingParametersCZZ); + AdvancePostingParametersCZZ2."Document Type" := "Gen. Journal Document Type"::" "; + InitGenJournalLine(SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, AdvancePostingParametersCZZ2, GenJournalLine); + GenJournalLine."Account No." := VATPostingSetup.GetSalesAdvLetterAccountCZZ(); + GenJournalLine.CopyFromAdvancePostingBufferAmountsCZZ(AdvancePostingBufferCZZ); + if not AdvancePostingParametersCZZ."Temporary Entries Only" then begin + OnPostAdvancePaymentVATUnlinkingOnBeforePostBalance( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, AdvancePostingBufferCZZ, + AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); + GLEntryNo := RunGenJnlPostLine(GenJournalLine, GenJnlPostLine, false, false, false); + OnPostAdvancePaymentVATUnlinkingOnAfterPostBalance( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, AdvancePostingBufferCZZ, + AdvancePostingParametersCZZ, GLEntryNo, GenJnlPostLine, GenJournalLine); + + SalesAdvLetterEntryCZZ.Cancelled := true; + SalesAdvLetterEntryCZZ.Modify(true); + end; + + OnAfterPostAdvancePaymentVATUnlinking( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, AdvancePostingBufferCZZ, + EntryNo, GenJnlPostLine, AdvancePostingParametersCZZ); + end; + + procedure PostAdvancePaymentUsage( + var SalesInvoiceHeader: Record "Sales Invoice Header"; + var AdvanceLetterApplicationCZZ: Record "Advance Letter Application CZZ"; + var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; + AdvancePostingParameters: Record "Advance Posting Parameters CZZ") + var + SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; + SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; + TempAdvanceLetterApplicationCZZ: Record "Advance Letter Application CZZ" temporary; + TempSalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ" temporary; + AmountToUse, UseAmount, UseAmountLCY : Decimal; + IsHandled: Boolean; + begin + IsHandled := false; + OnBeforePostAdvancePaymentUsage(SalesInvoiceHeader, AdvanceLetterApplicationCZZ, GenJnlPostLine, AdvancePostingParameters, IsHandled); +#if not CLEAN24 + RaiseOnBeforePostAdvancePaymentUsage(SalesInvoiceHeader, AdvanceLetterApplicationCZZ, GenJnlPostLine, AdvancePostingParameters, IsHandled); +#endif + if IsHandled then + exit; + + if SalesInvoiceHeader."Remaining Amount" = 0 then + SalesInvoiceHeader.CalcFields("Remaining Amount"); + + AmountToUse := SalesInvoiceHeader."Remaining Amount"; + if AmountToUse = 0 then + exit; + + if AdvanceLetterApplicationCZZ.IsEmpty() then + exit; + + AdvanceLetterApplicationCZZ.FindSet(); + repeat + SalesAdvLetterHeaderCZZ.Get(AdvanceLetterApplicationCZZ."Advance Letter No."); + SalesAdvLetterHeaderCZZ.TestField("Currency Code", SalesInvoiceHeader."Currency Code"); + SalesAdvLetterHeaderCZZ.TestField("Bill-to Customer No.", SalesInvoiceHeader."Bill-to Customer No."); + + SalesAdvLetterEntryCZZ.SetRange("Sales Adv. Letter No.", AdvanceLetterApplicationCZZ."Advance Letter No."); + SalesAdvLetterEntryCZZ.SetRange(Cancelled, false); + SalesAdvLetterEntryCZZ.SetRange("Entry Type", SalesAdvLetterEntryCZZ."Entry Type"::Payment); + SalesAdvLetterEntryCZZ.SetFilter("Posting Date", '..%1', SalesInvoiceHeader."Posting Date"); + OnPostAdvancePaymentUsageOnAfterSetSalesAdvLetterEntryFilter(AdvanceLetterApplicationCZZ, SalesAdvLetterEntryCZZ); +#if not CLEAN24 + RaiseOnPostAdvancePaymentUsageOnBeforeLoopSalesAdvLetterEntry(AdvanceLetterApplicationCZZ, SalesAdvLetterEntryCZZ); +#endif + if SalesAdvLetterEntryCZZ.FindSet() then + repeat + TempSalesAdvLetterEntryCZZ.Init(); + TempSalesAdvLetterEntryCZZ := SalesAdvLetterEntryCZZ; + TempSalesAdvLetterEntryCZZ.Amount := SalesAdvLetterEntryCZZ.GetRemainingAmount(); + TempSalesAdvLetterEntryCZZ."Amount (LCY)" := SalesAdvLetterEntryCZZ.GetRemainingAmountLCY(); + if TempSalesAdvLetterEntryCZZ.Amount <> 0 then + TempSalesAdvLetterEntryCZZ.Insert(); + until SalesAdvLetterEntryCZZ.Next() = 0; + + TempAdvanceLetterApplicationCZZ.Add(AdvanceLetterApplicationCZZ); + until AdvanceLetterApplicationCZZ.Next() = 0; + + TempSalesAdvLetterEntryCZZ.Reset(); + TempSalesAdvLetterEntryCZZ.SetCurrentKey("Posting Date"); + if TempSalesAdvLetterEntryCZZ.FindSet() then begin + repeat + TempAdvanceLetterApplicationCZZ.SetRange("Advance Letter No.", TempSalesAdvLetterEntryCZZ."Sales Adv. Letter No."); + TempAdvanceLetterApplicationCZZ.FindFirst(); + if TempAdvanceLetterApplicationCZZ.Amount < TempSalesAdvLetterEntryCZZ.Amount then + TempSalesAdvLetterEntryCZZ.Amount := TempAdvanceLetterApplicationCZZ.Amount; + + if AmountToUse > TempSalesAdvLetterEntryCZZ.Amount then + UseAmount := TempSalesAdvLetterEntryCZZ.Amount + else + UseAmount := AmountToUse; + + if UseAmount <> 0 then begin + UseAmountLCY := Round(UseAmount / TempSalesAdvLetterEntryCZZ."Currency Factor"); + ReverseAdvancePayment(TempSalesAdvLetterEntryCZZ, SalesInvoiceHeader, UseAmount, UseAmountLCY, GenJnlPostLine, AdvancePostingParameters); + AmountToUse -= UseAmount; + TempAdvanceLetterApplicationCZZ.Amount -= UseAmount; + TempAdvanceLetterApplicationCZZ."Amount (LCY)" -= UseAmountLCY; + TempAdvanceLetterApplicationCZZ.Modify(); + end; + until (TempSalesAdvLetterEntryCZZ.Next() = 0) or (AmountToUse = 0); + + if not AdvancePostingParameters."Temporary Entries Only" then begin + TempAdvanceLetterApplicationCZZ.Reset(); + if TempAdvanceLetterApplicationCZZ.FindSet() then + repeat + TempAdvanceLetterApplicationCZZ.ApplyChanges(); + until TempAdvanceLetterApplicationCZZ.Next() = 0; + end; + end; + + OnAfterPostAdvancePaymentUsage(SalesInvoiceHeader, AdvanceLetterApplicationCZZ, GenJnlPostLine, AdvancePostingParameters); +#if not CLEAN24 + RaiseOnAfterPostAdvancePaymentUsage(SalesInvoiceHeader, AdvanceLetterApplicationCZZ, GenJnlPostLine, AdvancePostingParameters); +#endif + end; + + internal procedure PostAdvancePaymentUsageForStatistics( + var SalesHeader: Record "Sales Header"; + Amount: Decimal; + AmountLCY: Decimal; + var SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ") + var + AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; + AdvanceLetterApplicationCZZ: Record "Advance Letter Application CZZ"; + SalesInvoiceHeader: Record "Sales Invoice Header"; + GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; + begin + if not SalesAdvLetterEntryCZZ.IsTemporary then + Error(TemporaryRecordErr); + + SalesAdvLetterEntryCZZ.Reset(); + SalesAdvLetterEntryCZZ.DeleteAll(); + + if not TempSalesAdvLetterEntryCZZGlob.IsEmpty() then + TempSalesAdvLetterEntryCZZGlob.DeleteAll(); + + if not SalesHeader.IsAdvanceLetterDocTypeCZZ() then + exit; + + SalesInvoiceHeader.TransferFields(SalesHeader); + SalesInvoiceHeader."Remaining Amount" := Amount; + + AdvancePostingParametersCZZ."Temporary Entries Only" := true; + AdvanceLetterApplicationCZZ.SetRange("Document Type", SalesHeader.GetAdvLetterUsageDocTypeCZZ()); + AdvanceLetterApplicationCZZ.SetRange("Document No.", SalesHeader."No."); + PostAdvancePaymentUsage(SalesInvoiceHeader, AdvanceLetterApplicationCZZ, GenJnlPostLine, AdvancePostingParametersCZZ); + + if TempSalesAdvLetterEntryCZZGlob.FindSet() then begin + repeat + SalesAdvLetterEntryCZZ := TempSalesAdvLetterEntryCZZGlob; + SalesAdvLetterEntryCZZ.Insert(); + until TempSalesAdvLetterEntryCZZGlob.Next() = 0; + + TempSalesAdvLetterEntryCZZGlob.DeleteAll(); + end; + end; + + procedure PostAdvancePaymentUsageVAT( + var SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; + var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; + var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; + AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ") + var + SalesAdvLetterEntryCZZ2: Record "Sales Adv. Letter Entry CZZ"; + IsHandled: Boolean; + begin + IsHandled := false; + OnBeforePostAdvancePaymentUsageVAT( + SalesAdvLetterEntryCZZ, AdvancePostingBufferCZZ, GenJnlPostLine, AdvancePostingParametersCZZ, IsHandled); + if IsHandled then + exit; + + if SalesAdvLetterEntryCZZ."Entry Type" <> SalesAdvLetterEntryCZZ."Entry Type"::Usage then + exit; + SalesAdvLetterEntryCZZ.TestField(Cancelled, false); + + SalesAdvLetterEntryCZZ2.Get(SalesAdvLetterEntryCZZ."Related Entry"); + if SalesAdvLetterEntryCZZ2."Entry Type" <> SalesAdvLetterEntryCZZ2."Entry Type"::Payment then + exit; + + ReverseAdvancePaymentVAT( + SalesAdvLetterEntryCZZ2, AdvancePostingBufferCZZ, SalesAdvLetterEntryCZZ."Entry No.", + "Advance Letter Entry Type CZZ"::"VAT Usage", GenJnlPostLine, AdvancePostingParametersCZZ); + + OnAfterPostAdvancePaymentUsageVAT( + SalesAdvLetterEntryCZZ, AdvancePostingBufferCZZ, GenJnlPostLine, AdvancePostingParametersCZZ); + end; + + procedure PostAdvanceCreditMemoVAT( + var SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; + var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; + var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; + AdvancePostingParametersCZZ: Record "Advance Posting Parameters 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"; + SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; + TempAdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ" temporary; + VATPostingSetup: Record "VAT Posting Setup"; + ExchRateAmount, ExchRateVATAmount : Decimal; + GLEntryNo: Integer; + IsHandled: Boolean; + begin + IsHandled := false; + OnBeforePostAdvanceCreditMemoVAT( + SalesAdvLetterEntryCZZ, AdvancePostingBufferCZZ, GenJnlPostLine, AdvancePostingParametersCZZ, IsHandled); + if IsHandled then + exit; + + SalesAdvLetterEntryCZZ.TestField("Entry Type", SalesAdvLetterEntryCZZ."Entry Type"::"VAT Payment"); + SalesAdvLetterEntryCZZ.TestField(Cancelled, false); + + SalesAdvLetterHeaderCZZ.Get(SalesAdvLetterEntryCZZ."Sales Adv. Letter No."); + + AdvancePostingBufferCZZ.SetFilter(Amount, '<>0'); + if AdvancePostingBufferCZZ.IsEmpty() then + Error(NothingToPostErr); + + if SalesAdvLetterEntryCZZ."Currency Code" <> '' then begin + SalesAdvLetterEntryCZZ2.Get(SalesAdvLetterEntryCZZ."Related Entry"); + BufferAdvanceVATLines(SalesAdvLetterEntryCZZ2, TempAdvancePostingBufferCZZ, 0D); + end; + + AdvancePostingBufferCZZ.FindSet(); + repeat + VATPostingSetup.Get(AdvancePostingBufferCZZ."VAT Bus. Posting Group", AdvancePostingBufferCZZ."VAT Prod. Posting Group"); + + // Post credit memo VAT + 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 + OnPostAdvanceCreditMemoVATOnBeforePost( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, AdvancePostingBufferCZZ, + AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); + GLEntryNo := RunGenJnlPostLine(GenJournalLine, GenJnlPostLine, true, true, false); + OnPostAdvanceCreditMemoVATOnAfterPost( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, AdvancePostingBufferCZZ, + AdvancePostingParametersCZZ, GLEntryNo, GenJnlPostLine, GenJournalLine); + end; + + TempSalesAdvLetterEntryCZZGlob.InitNewEntry(); + TempSalesAdvLetterEntryCZZGlob.InitRelatedEntry(SalesAdvLetterEntryCZZ."Related Entry"); + 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.Cancelled := true; + TempSalesAdvLetterEntryCZZGlob.InsertNewEntry(not AdvancePostingParametersCZZ."Temporary Entries Only"); + + AdvancePostingBufferCZZ.ReverseAmounts(); + if GenJournalLine."Currency Code" <> '' then + if TempAdvancePostingBufferCZZ.Get( + AdvancePostingBufferCZZ."VAT Bus. Posting Group", + AdvancePostingBufferCZZ."VAT Prod. Posting Group") + then begin + AdvancePostingParametersCZZ2.InitNew(AdvancePostingParametersCZZ); + AdvancePostingParametersCZZ2."Document Type" := "Gen. Journal Document Type"::" "; + AdvancePostingParametersCZZ2."External Document No." := ''; + AdvancePostingParametersCZZ2."Source Code" := ''; + 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)"; + if (ExchRateAmount <> 0) or (ExchRateVATAmount <> 0) then + PostExchangeRate(SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, VATPostingSetup, ExchRateAmount, ExchRateVATAmount, + SalesAdvLetterEntryCZZ."Related Entry", true, GenJnlPostLine, AdvancePostingParametersCZZ2); + + ReverseUnrealizedExchangeRate( + SalesAdvLetterEntryCZZ2, SalesAdvLetterHeaderCZZ, VATPostingSetup, + AdvancePostingBufferCZZ.Amount / TempAdvancePostingBufferCZZ.Amount, + SalesAdvLetterEntryCZZ2."Entry No.", GenJnlPostLine, AdvancePostingParametersCZZ2); + end; + + // Post balance of credit memo VAT + AdvancePostingParametersCZZ2.InitNew(AdvancePostingParametersCZZ); + AdvancePostingParametersCZZ2."Document Type" := "Gen. Journal Document Type"::" "; + InitGenJournalLine(SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, AdvancePostingParametersCZZ2, GenJournalLine); + GenJournalLine."Account No." := VATPostingSetup.GetSalesAdvLetterAccountCZZ(); + GenJournalLine.CopyFromAdvancePostingBufferAmountsCZZ(AdvancePostingBufferCZZ); + if not AdvancePostingParametersCZZ."Temporary Entries Only" then begin + OnPostAdvanceCreditMemoVATOnBeforePostBalance( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, AdvancePostingBufferCZZ, + AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); + GLEntryNo := RunGenJnlPostLine(GenJournalLine, GenJnlPostLine, false, false, false); + OnPostAdvanceCreditMemoVATOnAfterPostBalance( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, AdvancePostingBufferCZZ, + AdvancePostingParametersCZZ, GLEntryNo, GenJnlPostLine, GenJournalLine); + end; + 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); + end; + + OnAfterPostAdvanceCreditMemoVAT( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, AdvancePostingBufferCZZ, + GenJnlPostLine, AdvancePostingParametersCZZ); + end; + + procedure PostAdvanceLetterApplying( + var SalesInvoiceHeader: Record "Sales Invoice Header"; + var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; + AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ") + var + AdvanceLetterApplication: Record "Advance Letter Application CZZ"; + IsHandled: Boolean; + begin + IsHandled := false; + OnBeforePostAdvanceLetterApplying(SalesInvoiceHeader, GenJnlPostLine, AdvancePostingParametersCZZ, IsHandled); + if IsHandled then + exit; + + AdvanceLetterApplication.SetRange("Document Type", AdvanceLetterApplication."Document Type"::"Posted Sales Invoice"); + AdvanceLetterApplication.SetRange("Document No.", SalesInvoiceHeader."No."); + if AdvanceLetterApplication.IsEmpty() then + exit; + + PostAdvancePaymentUsage(SalesInvoiceHeader, AdvanceLetterApplication, GenJnlPostLine, AdvancePostingParametersCZZ); + + OnAfterPostAdvanceLetterApplying(SalesInvoiceHeader, GenJnlPostLine, AdvancePostingParametersCZZ); + end; + + procedure PostAdvanceLetterUnapplying( + var SalesInvoiceHeader: Record "Sales Invoice Header"; + 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"; + SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; + SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; + VATPostingSetup: Record "VAT Posting Setup"; +#if not CLEAN22 +#pragma warning disable AL0432 + ReplaceVATDateMgtCZL: Codeunit "Replace VAT Date Mgt. CZL"; +#pragma warning restore AL0432 +#endif + IsHandled: Boolean; + begin + IsHandled := false; + OnBeforePostAdvanceLetterUnapplying(SalesInvoiceHeader, GenJnlPostLine, AdvancePostingParametersCZZ, IsHandled); + if IsHandled then + exit; + + SalesAdvLetterEntryCZZ.SetRange("Entry Type", SalesAdvLetterEntryCZZ."Entry Type"::Usage); + SalesAdvLetterEntryCZZ.SetRange("Document No.", SalesInvoiceHeader."No."); + SalesAdvLetterEntryCZZ.SetRange(Cancelled, false); + if not SalesAdvLetterEntryCZZ.FindLast() then + exit; + + SalesAdvLetterEntryCZZ.Reset(); + SalesAdvLetterEntryCZZ.SetRange("Document No.", SalesInvoiceHeader."No."); + SalesAdvLetterEntryCZZ.SetRange(Cancelled, false); + SalesAdvLetterEntryCZZ.Find('+'); + SalesAdvLetterEntryCZZ.SetFilter("Entry No.", '..%1', SalesAdvLetterEntryCZZ."Entry No."); + repeat + AdvancePostingParametersCZZ2.InitNew(AdvancePostingParametersCZZ); + AdvancePostingParametersCZZ2."Posting Date" := SalesAdvLetterEntryCZZ."Posting Date"; + AdvancePostingParametersCZZ2."VAT Date" := SalesAdvLetterEntryCZZ."VAT Date"; + AdvancePostingParametersCZZ2."Posting Description" := SalesInvoiceHeader."Posting Description"; + + SalesAdvLetterHeaderCZZ.Get(SalesAdvLetterEntryCZZ."Sales Adv. Letter No."); + case SalesAdvLetterEntryCZZ."Entry Type" of + SalesAdvLetterEntryCZZ."Entry Type"::"VAT Adjustment": + begin + 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); + end; + SalesAdvLetterEntryCZZ."Entry Type"::"VAT Rate": + begin + AdvancePostingParametersCZZ2."Source Code" := SalesInvoiceHeader."Source Code"; + + 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); + end; + SalesAdvLetterEntryCZZ."Entry Type"::"VAT Usage": + begin + AdvancePostingParametersCZZ2."Document Type" := "Gen. Journal Document Type"::Invoice; + AdvancePostingParametersCZZ2."Source Code" := SalesInvoiceHeader."Source Code"; +#if not CLEAN22 +#pragma warning disable AL0432 + if not ReplaceVATDateMgtCZL.IsEnabled() then + AdvancePostingParametersCZZ2."VAT Date" := SalesInvoiceHeader."VAT Date CZL" + else +#pragma warning restore AL0432 +#endif + AdvancePostingParametersCZZ2."VAT Date" := SalesInvoiceHeader."VAT Reporting Date"; + AdvancePostingParametersCZZ2."Currency Code" := SalesAdvLetterEntryCZZ."Currency Code"; + + Clear(AdvancePostingBufferCZZ); + AdvancePostingBufferCZZ.PrepareForSalesAdvLetterEntry(SalesAdvLetterEntryCZZ); + + PostAdvanceLetterEntryVATUsageUnapplying( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, AdvancePostingBufferCZZ, GenJnlPostLine, AdvancePostingParametersCZZ2) + end; + SalesAdvLetterEntryCZZ."Entry Type"::Usage: + begin + AdvancePostingParametersCZZ2.InitNew(AdvancePostingParametersCZZ); + + PostAdvanceLetterEntryUsageUnapplying( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, AdvancePostingBufferCZZ, GenJnlPostLine, AdvancePostingParametersCZZ2); + end; + else + Error(UnapplyIsNotPossibleErr); + end; + until SalesAdvLetterEntryCZZ.Next(-1) = 0; + + SalesAdvLetterEntryCZZ.ModifyAll(Cancelled, true); + + OnAfterPostAdvanceLetterUnapplying(SalesInvoiceHeader, GenJnlPostLine, AdvancePostingParametersCZZ); + end; + + local procedure PostAdvanceLetterEntryVATUsageUnapplying( + SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; + SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; + var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; + var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; + AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ") + var + AdvancePostingParametersCZZ2: Record "Advance Posting Parameters CZZ"; + GenJournalLine: Record "Gen. Journal Line"; + VATPostingSetup: Record "VAT Posting Setup"; + EntryNo: Integer; + GLEntryNo: Integer; + IsHandled: Boolean; + begin + IsHandled := false; + OnBeforePostAdvanceLetterEntryVATUsageUnapplying( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, AdvancePostingBufferCZZ, GenJnlPostLine, AdvancePostingParametersCZZ, IsHandled); + if IsHandled then + exit; + + VATPostingSetup.Get(AdvancePostingBufferCZZ."VAT Bus. Posting Group", AdvancePostingBufferCZZ."VAT Prod. Posting Group"); + + InitGenJournalLine( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, AdvancePostingParametersCZZ, GenJournalLine); + GenJournalLine."Account No." := VATPostingSetup.GetSalesAdvLetterAccountCZZ(); + GenJournalLine."Gen. Posting Type" := GenJournalLine."Gen. Posting Type"::Sale; + GenJournalLine.Correction := true; + AdvancePostingBufferCZZ.ReverseAmounts(); + GenJournalLine.CopyFromAdvancePostingBufferCZZ(AdvancePostingBufferCZZ); + if not AdvancePostingParametersCZZ."Temporary Entries Only" then begin + OnPostAdvanceLetterEntryVATUsageUnapplyingOnBeforePost( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, AdvancePostingBufferCZZ, + AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); + GLEntryNo := RunGenJnlPostLine(GenJournalLine, GenJnlPostLine, true, true, false); + OnPostAdvanceLetterEntryVATUsageUnapplyingOnAfterPost( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, AdvancePostingBufferCZZ, + AdvancePostingParametersCZZ, GLEntryNo, GenJnlPostLine, GenJournalLine); + end; + + TempSalesAdvLetterEntryCZZGlob.InitNewEntry(); + TempSalesAdvLetterEntryCZZGlob.InitRelatedEntry(SalesAdvLetterEntryCZZ."Related Entry"); + 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 Identifier" := VATPostingSetup."VAT Identifier"; + TempSalesAdvLetterEntryCZZGlob.Cancelled := true; + EntryNo := TempSalesAdvLetterEntryCZZGlob.InsertNewEntry(not AdvancePostingParametersCZZ."Temporary Entries Only"); + + AdvancePostingBufferCZZ.ReverseAmounts(); + + AdvancePostingParametersCZZ2.InitNew(AdvancePostingParametersCZZ); + AdvancePostingParametersCZZ2."Document Type" := "Gen. Journal Document Type"::" "; + InitGenJournalLine(SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, AdvancePostingParametersCZZ2, GenJournalLine); + GenJournalLine."Account No." := VATPostingSetup.GetSalesAdvLetterAccountCZZ(); + GenJournalLine.Correction := true; + GenJournalLine.CopyFromAdvancePostingBufferAmountsCZZ(AdvancePostingBufferCZZ); + if not AdvancePostingParametersCZZ."Temporary Entries Only" then begin + OnPostAdvanceLetterEntryVATUsageUnapplyingOnBeforePostBalance( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, AdvancePostingBufferCZZ, + AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); + GLEntryNo := RunGenJnlPostLine(GenJournalLine, GenJnlPostLine, false, false, false); + OnPostAdvanceLetterEntryVATUsageUnapplyingOnAfterPostBalance( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, AdvancePostingBufferCZZ, + AdvancePostingParametersCZZ, GLEntryNo, GenJnlPostLine, GenJournalLine); + end; + + OnAfterPostAdvanceLetterEntryVATUsageUnapplying( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, AdvancePostingBufferCZZ, + EntryNo, GenJnlPostLine, AdvancePostingParametersCZZ) + end; + + local procedure PostAdvanceLetterEntryUsageUnapplying( + SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; + SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; + var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; + var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; + AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ") + var + GenJournalLine: Record "Gen. Journal Line"; + CustLedgerEntry: Record "Cust. Ledger Entry"; + CustLedgerEntryInv: Record "Cust. Ledger Entry"; + EntryNo, GLEntryNo : Integer; + IsHandled: Boolean; + begin + IsHandled := false; + OnBeforePostAdvanceLetterEntryUsageUnapplying( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, AdvancePostingBufferCZZ, GenJnlPostLine, AdvancePostingParametersCZZ, IsHandled); + if IsHandled then + exit; + + CustLedgerEntry.Get(SalesAdvLetterEntryCZZ."Cust. Ledger Entry No."); + CustLedgerEntryInv := CustLedgerEntry; +#pragma warning disable AA0181 + CustLedgerEntryInv.Next(-1); +#pragma warning restore AA0181 + UnapplyCustLedgEntry(CustLedgerEntry, GenJnlPostLine); + + InitGenJournalLine(CustLedgerEntry, GenJournalLine); + GenJournalLine."Adv. Letter Template Code CZZ" := SalesAdvLetterHeaderCZZ."Advance Letter Code"; + GenJournalLine.Correction := true; + GenJournalLine."Adv. Letter No. (Entry) CZZ" := SalesAdvLetterHeaderCZZ."No."; + GenJournalLine."Use Advance G/L Account CZZ" := true; + GenJournalLine.SetCurrencyFactor( + SalesAdvLetterEntryCZZ."Currency Code", SalesAdvLetterEntryCZZ."Currency Factor"); + GenJournalLine.Amount := -SalesAdvLetterEntryCZZ.Amount; + GenJournalLine."Amount (LCY)" := -SalesAdvLetterEntryCZZ."Amount (LCY)"; + if not AdvancePostingParametersCZZ."Temporary Entries Only" then begin + CustLedgerEntry.SetApplication('', ''); + GenJournalLine."Applies-to ID" := CustLedgerEntry."Applies-to ID"; + OnPostAdvanceLetterEntryUsageUnapplyingOnBeforePostAdvancePaymentApplication( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, + AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); + GLEntryNo := RunGenJnlPostLine(GenJournalLine, GenJnlPostLine, false, false, true); + OnPostAdvanceLetterEntryUsageUnapplyingOnAfterPostAdvancePaymentApplication( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, + AdvancePostingParametersCZZ, GLEntryNo, GenJnlPostLine, GenJournalLine); + end; + + CustLedgerEntry.FindLast(); + + TempSalesAdvLetterEntryCZZGlob.InitNewEntry(); + TempSalesAdvLetterEntryCZZGlob.InitCustLedgerEntry(CustLedgerEntry); + TempSalesAdvLetterEntryCZZGlob.InitRelatedEntry(SalesAdvLetterEntryCZZ); + TempSalesAdvLetterEntryCZZGlob.CopyFromGenJnlLine(GenJournalLine); + TempSalesAdvLetterEntryCZZGlob."Entry Type" := SalesAdvLetterEntryCZZ."Entry Type"; + TempSalesAdvLetterEntryCZZGlob."Sales Adv. Letter No." := SalesAdvLetterHeaderCZZ."No."; + TempSalesAdvLetterEntryCZZGlob.Cancelled := true; + EntryNo := TempSalesAdvLetterEntryCZZGlob.InsertNewEntry(not AdvancePostingParametersCZZ."Temporary Entries Only"); + + InitGenJournalLine(CustLedgerEntry, GenJournalLine); + GenJournalLine."Adv. Letter Template Code CZZ" := SalesAdvLetterHeaderCZZ."Advance Letter Code"; + GenJournalLine.Correction := true; + GenJournalLine.SetCurrencyFactor( + SalesAdvLetterEntryCZZ."Currency Code", SalesAdvLetterEntryCZZ."Currency Factor"); + GenJournalLine.Amount := SalesAdvLetterEntryCZZ.Amount; + GenJournalLine."Amount (LCY)" := SalesAdvLetterEntryCZZ."Amount (LCY)"; + if not AdvancePostingParametersCZZ."Temporary Entries Only" then begin + CustLedgerEntryInv."Advance Letter No. CZZ" := ''; + CustLedgerEntryInv.SetApplication('', ''); + GenJournalLine."Applies-to ID" := CustLedgerEntryInv."Applies-to ID"; + OnPostAdvanceLetterEntryUsageUnapplyingOnBeforePostInvoiceApplication( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, + AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); + GLEntryNo := RunGenJnlPostLine(GenJournalLine, GenJnlPostLine, false, false, true); + OnPostAdvanceLetterEntryUsageUnapplyingOnAfterPostInvoiceApplication( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, + AdvancePostingParametersCZZ, GLEntryNo, GenJnlPostLine, GenJournalLine); + end; + + SalesAdvLetterHeaderCZZ.UpdateStatus(SalesAdvLetterHeaderCZZ.Status::"To Use"); + + OnAfterPostAdvanceLetterEntryUsageUnapplying( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, AdvancePostingBufferCZZ, + EntryNo, GenJnlPostLine, AdvancePostingParametersCZZ) + end; + + procedure PostAdvanceLetterClosing( + SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; + var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; + AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ") + var + AdvanceLetterApplicationCZZ: Record "Advance Letter Application CZZ"; + AdvanceLetterTemplateCZZ: Record "Advance Letter Template CZZ"; + SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; + NoSeriesBatch: Codeunit "No. Series - Batch"; + NextEntryNo: Integer; + IsHandled: Boolean; + begin + IsHandled := false; + OnBeforePostAdvanceLetterClosing(SalesAdvLetterHeaderCZZ, GenJnlPostLine, AdvancePostingParametersCZZ, IsHandled); + if IsHandled then + exit; + + if SalesAdvLetterHeaderCZZ.Status = SalesAdvLetterHeaderCZZ.Status::Closed then + exit; + + if SalesAdvLetterHeaderCZZ.Status = SalesAdvLetterHeaderCZZ.Status::New then begin + SalesAdvLetterHeaderCZZ.UpdateStatus(SalesAdvLetterHeaderCZZ.Status::Closed); + exit; + end; + + if AdvancePostingParametersCZZ."Document No." = '' then begin + AdvanceLetterTemplateCZZ.Get(SalesAdvLetterHeaderCZZ."Advance Letter Code"); + AdvanceLetterTemplateCZZ.TestField("Advance Letter Cr. Memo Nos."); + AdvancePostingParametersCZZ."Document No." := + NoSeriesBatch.GetNextNo( + AdvanceLetterTemplateCZZ."Advance Letter Cr. Memo Nos.", AdvancePostingParametersCZZ."Posting Date"); + NextEntryNo := GenJnlPostLine.GetNextEntryNo(); + end; + + SalesAdvLetterEntryCZZ.SetRange("Sales Adv. Letter No.", SalesAdvLetterHeaderCZZ."No."); + SalesAdvLetterEntryCZZ.SetRange("Entry Type", SalesAdvLetterEntryCZZ."Entry Type"::Payment); + SalesAdvLetterEntryCZZ.SetRange(Cancelled, false); + if SalesAdvLetterEntryCZZ.FindSet() then + repeat + PostAdvanceLetterEntryClosing( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, GenJnlPostLine, AdvancePostingParametersCZZ); + until SalesAdvLetterEntryCZZ.Next() = 0; + + if (NextEntryNo <> 0) and (NextEntryNo <> GenJnlPostLine.GetNextEntryNo()) then + NoSeriesBatch.SaveState(); + + SalesAdvLetterManagementCZZ.CancelInitEntry(SalesAdvLetterHeaderCZZ, AdvancePostingParametersCZZ."Posting Date", false); + SalesAdvLetterHeaderCZZ.Get(SalesAdvLetterHeaderCZZ."No."); + SalesAdvLetterHeaderCZZ.UpdateStatus(SalesAdvLetterHeaderCZZ.Status::Closed); + + AdvanceLetterApplicationCZZ.SetRange("Advance Letter Type", AdvanceLetterApplicationCZZ."Advance Letter Type"::Sales); + AdvanceLetterApplicationCZZ.SetRange("Advance Letter No.", SalesAdvLetterHeaderCZZ."No."); + AdvanceLetterApplicationCZZ.DeleteAll(true); + + OnAfterPostAdvanceLetterClosing(SalesAdvLetterHeaderCZZ, GenJnlPostLine, AdvancePostingParametersCZZ) + end; + + local procedure PostAdvanceLetterEntryClosing( + SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; + SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; + var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; + AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ") + var + AdvancePostingParametersCZZ2: Record "Advance Posting Parameters CZZ"; + GenJournalLine: Record "Gen. Journal Line"; + TempAdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ" temporary; + CustLedgerEntry: Record "Cust. Ledger Entry"; + CustLedgerEntry2: Record "Cust. Ledger Entry"; + RemainingAmount, RemainingAmountLCY : Decimal; + EntryNo, GLEntryNo : Integer; + IsHandled: Boolean; + begin + IsHandled := false; + OnBeforePostAdvanceLetterEntryClosing(SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, GenJnlPostLine, AdvancePostingParametersCZZ, IsHandled); + if IsHandled then + exit; + + if SalesAdvLetterEntryCZZ."Entry Type" <> SalesAdvLetterEntryCZZ."Entry Type"::Payment then + exit; + + RemainingAmount := SalesAdvLetterEntryCZZ.GetRemainingAmount(); + RemainingAmountLCY := SalesAdvLetterEntryCZZ.GetRemainingAmountLCY(); + + CustLedgerEntry.Get(SalesAdvLetterEntryCZZ."Cust. Ledger Entry No."); + if RemainingAmount <> 0 then begin + InitGenJournalLine(CustLedgerEntry, GenJournalLine); + GenJournalLine."Adv. Letter Template Code CZZ" := SalesAdvLetterHeaderCZZ."Advance Letter Code"; + GenJournalLine.Correction := true; + GenJournalLine."Document Type" := AdvancePostingParametersCZZ."Document Type"; + GenJournalLine."Document No." := AdvancePostingParametersCZZ."Document No."; + GenJournalLine."External Document No." := AdvancePostingParametersCZZ."External Document No."; + GenJournalLine."Posting Date" := AdvancePostingParametersCZZ."Posting Date"; + GenJournalLine."Document Date" := AdvancePostingParametersCZZ."Document Date"; +#if not CLEAN22 +#pragma warning disable AL0432 + GenJournalLine."VAT Date CZL" := AdvancePostingParametersCZZ."VAT Date"; +#pragma warning restore AL0432 +#endif + GenJournalLine."VAT Reporting Date" := AdvancePostingParametersCZZ."VAT Date"; + GenJournalLine."Original Doc. VAT Date CZL" := AdvancePostingParametersCZZ."Original Document VAT Date"; + GenJournalLine."Adv. Letter No. (Entry) CZZ" := SalesAdvLetterEntryCZZ."Sales Adv. Letter No."; + GenJournalLine."Use Advance G/L Account CZZ" := true; + GenJournalLine.SetCurrencyFactor( + AdvancePostingParametersCZZ."Currency Code", AdvancePostingParametersCZZ."Currency Factor"); + GenJournalLine.Amount := RemainingAmount; + GenJournalLine."Amount (LCY)" := RemainingAmountLCY; + if not AdvancePostingParametersCZZ."Temporary Entries Only" then begin + CustLedgerEntry.SetApplication('', SalesAdvLetterEntryCZZ."Sales Adv. Letter No."); + GenJournalLine."Applies-to ID" := CustLedgerEntry."Applies-to ID"; + OnPostAdvanceLetterEntryClosingOnBeforePost( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, CustLedgerEntry, + AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); +#if not CLEAN24 + RaiseOnBeforePostClosePayment(GenJournalLine, SalesAdvLetterHeaderCZZ); +#endif + GLEntryNo := RunGenJnlPostLine(GenJournalLine, GenJnlPostLine, false, false, false); + OnPostAdvanceLetterEntryClosingOnAfterPost( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, CustLedgerEntry, + AdvancePostingParametersCZZ, GLEntryNo, GenJnlPostLine, GenJournalLine); +#if not CLEAN24 + RaiseOnAfterPostClosePayment(GenJournalLine, SalesAdvLetterHeaderCZZ); +#endif + end; + + CustLedgerEntry2.FindLast(); + + TempSalesAdvLetterEntryCZZGlob.InitNewEntry(); + TempSalesAdvLetterEntryCZZGlob.InitCustLedgerEntry(CustLedgerEntry2); + TempSalesAdvLetterEntryCZZGlob.InitRelatedEntry(SalesAdvLetterEntryCZZ); + TempSalesAdvLetterEntryCZZGlob.CopyFromGenJnlLine(GenJournalLine); + TempSalesAdvLetterEntryCZZGlob."Entry Type" := "Advance Letter Entry Type CZZ"::Close; + TempSalesAdvLetterEntryCZZGlob."Sales Adv. Letter No." := SalesAdvLetterHeaderCZZ."No."; + EntryNo := TempSalesAdvLetterEntryCZZGlob.InsertNewEntry(not AdvancePostingParametersCZZ."Temporary Entries Only"); + end; + + AdvancePostingParametersCZZ2.InitNew(AdvancePostingParametersCZZ); + AdvancePostingParametersCZZ2."Document Type" := "Gen. Journal Document Type"::"Credit Memo"; + + BufferAdvanceVATLines(SalesAdvLetterEntryCZZ, TempAdvancePostingBufferCZZ, 0D); + SuggestUsageVAT(SalesAdvLetterEntryCZZ, TempAdvancePostingBufferCZZ, CustLedgerEntry."Document No.", + 0, AdvancePostingParametersCZZ."Currency Factor", AdvancePostingParametersCZZ2."Temporary Entries Only"); + + ReverseAdvancePaymentVAT(SalesAdvLetterEntryCZZ, TempAdvancePostingBufferCZZ, EntryNo, + "Advance Letter Entry Type CZZ"::"VAT Close", GenJnlPostLine, AdvancePostingParametersCZZ2); + + if RemainingAmount <> 0 then begin + InitGenJournalLine(CustLedgerEntry, GenJournalLine); + GenJournalLine."Document Type" := GenJournalLine."Document Type"::Payment; + GenJournalLine.Correction := true; + GenJournalLine."Document No." := AdvancePostingParametersCZZ."Document No."; + GenJournalLine."External Document No." := AdvancePostingParametersCZZ."External Document No."; + GenJournalLine."Posting Date" := AdvancePostingParametersCZZ."Posting Date"; + GenJournalLine."Document Date" := AdvancePostingParametersCZZ."Document Date"; +#if not CLEAN22 +#pragma warning disable AL0432 + GenJournalLine."VAT Date CZL" := AdvancePostingParametersCZZ."VAT Date"; +#pragma warning restore AL0432 +#endif + GenJournalLine."VAT Reporting Date" := AdvancePostingParametersCZZ."VAT Date"; + GenJournalLine."Original Doc. VAT Date CZL" := AdvancePostingParametersCZZ."Original Document VAT Date"; + GenJournalLine.SetCurrencyFactor( + AdvancePostingParametersCZZ."Currency Code", AdvancePostingParametersCZZ."Currency Factor"); + GenJournalLine.Amount := -RemainingAmount; + GenJournalLine."Amount (LCY)" := -RemainingAmountLCY; + GenJournalLine."Variable Symbol CZL" := SalesAdvLetterHeaderCZZ."Variable Symbol"; + if not AdvancePostingParametersCZZ."Temporary Entries Only" then begin + OnPostAdvanceLetterEntryClosingOnBeforePostBalance( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, CustLedgerEntry, + AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); +#if not CLEAN24 + RaiseOnBeforePostClosePaymentRepos(GenJournalLine, SalesAdvLetterHeaderCZZ); +#endif + GLEntryNo := RunGenJnlPostLine(GenJournalLine, GenJnlPostLine, false, false, false); + OnPostAdvanceLetterEntryClosingOnAfterPostBalance( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, CustLedgerEntry, + AdvancePostingParametersCZZ, GLEntryNo, GenJnlPostLine, GenJournalLine); +#if not CLEAN24 + RaiseOnAfterPostClosePaymentRepos(GenJournalLine, SalesAdvLetterHeaderCZZ); +#endif + end; + end; + + OnAfterPostAdvanceLetterEntryClosing( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, GenJnlPostLine, AdvancePostingParametersCZZ); + end; + + local procedure ReverseAdvancePayment( + SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; + SalesInvoiceHeader: Record "Sales Invoice Header"; + ReverseAmount: Decimal; + ReverseAmountLCY: Decimal; + var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; + AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ") + var + AdvancePostingParametersCZZ2: Record "Advance Posting Parameters CZZ"; + GenJournalLine: Record "Gen. Journal Line"; + SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; + TempAdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ" temporary; + CustLedgerEntry: Record "Cust. Ledger Entry"; + CustLedgerEntry2: Record "Cust. Ledger Entry"; + EntryNo, GLEntryNo : Integer; + IsHandled: Boolean; + begin + IsHandled := false; + OnBeforeReverseAdvancePayment( + SalesAdvLetterEntryCZZ, SalesInvoiceHeader, ReverseAmount, ReverseAmountLCY, + GenJnlPostLine, AdvancePostingParametersCZZ, IsHandled); + if IsHandled then + exit; + + if ReverseAmount <> 0 then begin + if ReverseAmount > SalesAdvLetterEntryCZZ.Amount then + Error(ReverseAmountErr, ReverseAmount, SalesAdvLetterEntryCZZ."Entry No."); + end else begin + ReverseAmount := SalesAdvLetterEntryCZZ.Amount; + ReverseAmountLCY := SalesAdvLetterEntryCZZ."Amount (LCY)"; + end; + + if not AdvancePostingParametersCZZ."Temporary Entries Only" then + CustLedgerEntry.Get(SalesInvoiceHeader."Cust. Ledger Entry No.") + else + InitCustLedgerEntryFromSalesInvoiceHeader(SalesInvoiceHeader, CustLedgerEntry); + + SalesAdvLetterHeaderCZZ.Get(SalesAdvLetterEntryCZZ."Sales Adv. Letter No."); + + // Post invoice application + InitGenJournalLine(CustLedgerEntry, GenJournalLine); + GenJournalLine."Adv. Letter Template Code CZZ" := SalesAdvLetterHeaderCZZ."Advance Letter Code"; + GenJournalLine.Correction := true; + GenJournalLine.Amount := -ReverseAmount; + GenJournalLine."Amount (LCY)" := -ReverseAmountLCY; + if not AdvancePostingParametersCZZ."Temporary Entries Only" then begin + CustLedgerEntry.SetApplication(SalesAdvLetterHeaderCZZ."Advance Letter Code", ''); + GenJournalLine."Applies-to ID" := CustLedgerEntry."Applies-to ID"; + + OnReverseAdvancePaymentOnBeforePostInvoiceApplication( + SalesAdvLetterHeaderCZZ, CustLedgerEntry, AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); +#if not CLEAN24 + RaiseOnBeforePostReversePaymentRepos(GenJournalLine, SalesAdvLetterHeaderCZZ); +#endif + GLEntryNo := RunGenJnlPostLine(GenJournalLine, GenJnlPostLine, false, false, true); + OnReverseAdvancePaymentOnAfterPostInvoiceApplication(SalesAdvLetterHeaderCZZ, CustLedgerEntry, + AdvancePostingParametersCZZ, GLEntryNo, GenJnlPostLine, GenJournalLine); +#if not CLEAN24 + RaiseOnAfterPostReversePaymentRepos(GenJournalLine, SalesAdvLetterHeaderCZZ); +#endif + end; + + // Post advance payment usage + InitGenJournalLine(CustLedgerEntry, GenJournalLine); + GenJournalLine."Document Type" := GenJournalLine."Document Type"::Invoice; + GenJournalLine."Adv. Letter Template Code CZZ" := SalesAdvLetterHeaderCZZ."Advance Letter Code"; + GenJournalLine."Adv. Letter No. (Entry) CZZ" := SalesAdvLetterEntryCZZ."Sales Adv. Letter No."; + GenJournalLine."Use Advance G/L Account CZZ" := true; + GenJournalLine.Amount := ReverseAmount; + GenJournalLine."Amount (LCY)" := ReverseAmountLCY; + + CustLedgerEntry2.Get(SalesAdvLetterEntryCZZ."Cust. Ledger Entry No."); + if not AdvancePostingParametersCZZ."Temporary Entries Only" then begin + CustLedgerEntry2.SetApplication('', SalesAdvLetterEntryCZZ."Sales Adv. Letter No."); + GenJournalLine."Applies-to ID" := CustLedgerEntry2."Applies-to ID"; + + OnReverseAdvancePaymentOnBeforePostAdvancePaymentUsage( + SalesAdvLetterHeaderCZZ, CustLedgerEntry, AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); +#if not CLEAN24 + RaiseOnBeforePostReversePayment(GenJournalLine, SalesAdvLetterHeaderCZZ); +#endif + GLEntryNo := RunGenJnlPostLine(GenJournalLine, GenJnlPostLine, false, true, true); + OnReverseAdvancePaymentOnAfterPostAdvancePaymentUsage(SalesAdvLetterHeaderCZZ, CustLedgerEntry, + AdvancePostingParametersCZZ, GLEntryNo, GenJnlPostLine, GenJournalLine); +#if not CLEAN24 + RaiseOnAfterPostReversePayment(GenJournalLine, SalesAdvLetterHeaderCZZ); +#endif + + CustLedgerEntry2.FindLast(); + end; + + TempSalesAdvLetterEntryCZZGlob.InitNewEntry(); + TempSalesAdvLetterEntryCZZGlob.InitCustLedgerEntry(CustLedgerEntry2); + TempSalesAdvLetterEntryCZZGlob.InitRelatedEntry(SalesAdvLetterEntryCZZ); + TempSalesAdvLetterEntryCZZGlob.CopyFromGenJnlLine(GenJournalLine); + TempSalesAdvLetterEntryCZZGlob."Entry Type" := "Advance Letter Entry Type CZZ"::Usage; + TempSalesAdvLetterEntryCZZGlob."Sales Adv. Letter No." := SalesAdvLetterHeaderCZZ."No."; + EntryNo := TempSalesAdvLetterEntryCZZGlob.InsertNewEntry(not AdvancePostingParametersCZZ."Temporary Entries Only"); + + if SalesAdvLetterHeaderCZZ."Automatic Post VAT Document" then begin + Clear(AdvancePostingParametersCZZ2); + AdvancePostingParametersCZZ2.CopyFromCustLedgerEntry(CustLedgerEntry); + AdvancePostingParametersCZZ2."Document Type" := "Gen. Journal Document Type"::Invoice; + AdvancePostingParametersCZZ2."Currency Code" := SalesAdvLetterEntryCZZ."Currency Code"; + AdvancePostingParametersCZZ2."Currency Factor" := SalesInvoiceHeader."VAT Currency Factor CZL"; + AdvancePostingParametersCZZ2."Temporary Entries Only" := AdvancePostingParametersCZZ."Temporary Entries Only"; + + BufferAdvanceVATLines(SalesAdvLetterEntryCZZ, TempAdvancePostingBufferCZZ, 0D); + SuggestUsageVAT(SalesAdvLetterEntryCZZ, TempAdvancePostingBufferCZZ, CustLedgerEntry."Document No.", + ReverseAmount, SalesInvoiceHeader."VAT Currency Factor CZL", AdvancePostingParametersCZZ2."Temporary Entries Only"); + + ReverseAdvancePaymentVAT(SalesAdvLetterEntryCZZ, TempAdvancePostingBufferCZZ, EntryNo, + "Advance Letter Entry Type CZZ"::"VAT Usage", GenJnlPostLine, AdvancePostingParametersCZZ2); + end; + + if not AdvancePostingParametersCZZ."Temporary Entries Only" then begin + SalesAdvLetterHeaderCZZ.Get(SalesAdvLetterEntryCZZ."Sales Adv. Letter No."); + SalesAdvLetterHeaderCZZ.UpdateStatus(SalesAdvLetterHeaderCZZ.Status::Closed); + end; + + OnAfterReverseAdvancePayment( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, + SalesInvoiceHeader, EntryNo, GenJnlPostLine, AdvancePostingParametersCZZ); + end; + + local procedure ReverseAdvancePaymentVAT( + var SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; + var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; + RelatedEntryNo: Integer; + EntryType: Enum "Advance Letter Entry Type CZZ"; + var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; + AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ") + var + AdvancePostingParametersCZZ2: Record "Advance Posting Parameters CZZ"; + SalesAdvLetterEntryCZZ2: 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; + IsHandled: Boolean; + begin + IsHandled := false; + OnBeforeReverseAdvancePaymentVAT( + SalesAdvLetterEntryCZZ, AdvancePostingBufferCZZ, RelatedEntryNo, GenJnlPostLine, AdvancePostingParametersCZZ, IsHandled); +#if not CLEAN24 + RaiseOnBeforePostReversePaymentVAT( + SalesAdvLetterEntryCZZ, AdvancePostingParametersCZZ."Posting Date", AdvancePostingParametersCZZ."Temporary Entries Only", IsHandled); +#endif + if IsHandled then + exit; + + 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 + exit; + + AdvancePostingBufferCZZ.FilterGroup(-1); + AdvancePostingBufferCZZ.SetFilter("VAT Base Amount", '<>0'); + AdvancePostingBufferCZZ.SetFilter("VAT Amount", '<>0'); + AdvancePostingBufferCZZ.FilterGroup(0); + if AdvancePostingBufferCZZ.IsEmpty() then + exit; + + SalesAdvLetterHeaderCZZ.Get(SalesAdvLetterEntryCZZ."Sales Adv. Letter No."); + + if SalesAdvLetterEntryCZZ."Currency Code" <> '' then begin + BufferAdvanceVATLines(SalesAdvLetterEntryCZZ, TempAdvancePostingBufferCZZ, 0D); + TempAdvancePostingBufferCZZ.CalcSums(Amount); + AmountToUse := TempAdvancePostingBufferCZZ.Amount; + end; + + AdvancePostingBufferCZZ.FindSet(); + repeat + VATPostingSetup.Get(AdvancePostingBufferCZZ."VAT Bus. Posting Group", AdvancePostingBufferCZZ."VAT Prod. Posting Group"); + + // Post reverse advance payment VAT + 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 + OnReverseAdvancePaymentVATOnBeforePost( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, VATPostingSetup, + AdvancePostingBufferCZZ, AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); + GLEntryNo := RunGenJnlPostLine(GenJournalLine, GenJnlPostLine, true, true, false); + OnReverseAdvancePaymentVATOnAfterPost( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, VATPostingSetup, AdvancePostingBufferCZZ, + AdvancePostingParametersCZZ, GLEntryNo, GenJnlPostLine, GenJournalLine); + end; + + TempSalesAdvLetterEntryCZZGlob.InitNewEntry(); + TempSalesAdvLetterEntryCZZGlob.InitRelatedEntry(RelatedEntryNo); + TempSalesAdvLetterEntryCZZGlob.CopyFromGenJnlLine(GenJournalLine); + TempSalesAdvLetterEntryCZZGlob."Entry Type" := EntryType; + 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"); + + AdvancePostingBufferCZZ.ReverseAmounts(); + if GenJournalLine."Currency Code" <> '' then + if TempAdvancePostingBufferCZZ.Get( + AdvancePostingBufferCZZ."VAT Bus. Posting Group", + AdvancePostingBufferCZZ."VAT Prod. Posting Group") + then begin + AdvancePostingParametersCZZ2.InitNew(AdvancePostingParametersCZZ); + AdvancePostingParametersCZZ2."Document Type" := "Gen. Journal Document Type"::" "; + AdvancePostingParametersCZZ2."External Document No." := ''; + AdvancePostingParametersCZZ2."Currency Code" := ''; + AdvancePostingParametersCZZ2."Currency Factor" := 0; + + CalcAmountLCY := Round(TempAdvancePostingBufferCZZ."Amount (ACY)" * AdvancePostingBufferCZZ.Amount / TempAdvancePostingBufferCZZ.Amount); + CalcVATAmountLCY := Round(TempAdvancePostingBufferCZZ."VAT Amount (ACY)" * AdvancePostingBufferCZZ.Amount / TempAdvancePostingBufferCZZ.Amount); + + ExchRateAmount := -CalcAmountLCY - GenJournalLine."Amount (LCY)"; + ExchRateVATAmount := -CalcVATAmountLCY - GenJournalLine."VAT Amount (LCY)"; + if (ExchRateAmount <> 0) or (ExchRateVATAmount <> 0) then + PostExchangeRate(SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, VATPostingSetup, ExchRateAmount, ExchRateVATAmount, + RelatedEntryNo, false, GenJnlPostLine, AdvancePostingParametersCZZ2); + + AdvancePostingParametersCZZ2."Source Code" := ''; + ReverseUnrealizedExchangeRate( + SalesAdvLetterEntryCZZ, SalesAdvLetterHeaderCZZ, VATPostingSetup, AdvancePostingBufferCZZ.Amount / AmountToUse, + RelatedEntryNo, GenJnlPostLine, AdvancePostingParametersCZZ2); + end; + + // Post balance of reverse advance payment VAT + AdvancePostingParametersCZZ2.InitNew(AdvancePostingParametersCZZ); + AdvancePostingParametersCZZ2."Document Type" := "Gen. Journal Document Type"::" "; + InitGenJournalLine(SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, AdvancePostingParametersCZZ2, GenJournalLine); + GenJournalLine."Account No." := VATPostingSetup.GetSalesAdvLetterAccountCZZ(); + GenJournalLine.CopyFromAdvancePostingBufferAmountsCZZ(AdvancePostingBufferCZZ); + if not AdvancePostingParametersCZZ."Temporary Entries Only" then begin + OnReverseAdvancePaymentVATOnBeforePostBalance( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, VATPostingSetup, + AdvancePostingBufferCZZ, AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); + GLEntryNo := RunGenJnlPostLine(GenJournalLine, GenJnlPostLine, false, false, false); + OnReverseAdvancePaymentVATOnAfterPostBalance( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, VATPostingSetup, AdvancePostingBufferCZZ, + AdvancePostingParametersCZZ, GLEntryNo, GenJnlPostLine, GenJournalLine); + end; + until AdvancePostingBufferCZZ.Next() = 0; + + if not AdvancePostingParametersCZZ."Temporary Entries Only" then + SalesAdvLetterHeaderCZZ.UpdateStatus(SalesAdvLetterHeaderCZZ.Status::Closed); + + OnAfterReverseAdvancePaymentVAT(SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, + AdvancePostingBufferCZZ, GenJnlPostLine, AdvancePostingParametersCZZ); + end; + + local procedure ReverseUnrealizedExchangeRate( + SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; + SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; + VATPostingSetup: Record "VAT Posting Setup"; + Coef: Decimal; + RelatedEntryNo: Integer; + var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; + AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ") + var + AmountLCY, VATAmountLCY : Decimal; + IsHandled: Boolean; + begin + IsHandled := false; + OnBeforeReverseUnrealizedExchangeRate( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, VATPostingSetup, Coef, + RelatedEntryNo, GenJnlPostLine, AdvancePostingParametersCZZ, IsHandled); + if IsHandled then + exit; + + if SalesAdvLetterEntryCZZ."Entry Type" <> SalesAdvLetterEntryCZZ."Entry Type"::Payment then + exit; + + SalesAdvLetterManagementCZZ.GetRemAmtLCYVATAdjust( + AmountLCY, VATAmountLCY, SalesAdvLetterEntryCZZ, AdvancePostingParametersCZZ."Posting Date", + VATPostingSetup."VAT Bus. Posting Group", VATPostingSetup."VAT Prod. Posting Group"); + if (AmountLCY = 0) and (VATAmountLCY = 0) then + exit; + + AmountLCY := Round(AmountLCY * Coef); + VATAmountLCY := Round(VATAmountLCY * Coef); + + PostUnrealizedExchangeRate( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, VATPostingSetup, -AmountLCY, -VATAmountLCY, + RelatedEntryNo, 0, false, GenJnlPostLine, AdvancePostingParametersCZZ); + end; + + local procedure PostExchangeRate( + SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; + SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; + VATPostingSetup: Record "VAT Posting Setup"; + Amount: Decimal; + VATAmount: Decimal; + RelatedEntryNo: Integer; + Correction: Boolean; + var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; + AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ") + var + GenJournalLine: Record "Gen. Journal Line"; + EntryNo, GLEntryNo : Integer; + IsHandled: Boolean; + begin + IsHandled := false; + OnBeforePostExchangeRate( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, VATPostingSetup, Amount, VATAmount, + RelatedEntryNo, Correction, GenJnlPostLine, AdvancePostingParametersCZZ, IsHandled); + if IsHandled then + exit; + + if (Amount = 0) and (VATAmount = 0) then + exit; + + if VATAmount <> 0 then begin + GetCurrency(SalesAdvLetterHeaderCZZ."Currency Code"); + + // Post exchange rate of VAT Base + InitGenJournalLine(SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, AdvancePostingParametersCZZ, GenJournalLine); + GenJournalLine.Correction := Correction; + GenJournalLine."Account No." := VATPostingSetup.GetSalesAdvLetterAccountCZZ(); + GenJournalLine.Validate(Amount, Amount - VATAmount); + if not AdvancePostingParametersCZZ."Temporary Entries Only" then begin + OnPostExchangeRateOnBeforePostVATBase( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, VATPostingSetup, Amount, VATAmount, + AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); + GLEntryNo := RunGenJnlPostLine(GenJournalLine, GenJnlPostLine, false, false, false); + OnPostExchangeRateOnAfterPostVATBase( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, VATPostingSetup, Amount, VATAmount, + AdvancePostingParametersCZZ, GLEntryNo, GenJnlPostLine, GenJournalLine); + end; + + // Post exchange rate of VAT Amount + InitGenJournalLine(SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, AdvancePostingParametersCZZ, GenJournalLine); + GenJournalLine.Correction := true; + if VATAmount < 0 then + GenJournalLine."Account No." := CurrencyGlob.GetRealizedLossesAccount() + else + GenJournalLine."Account No." := CurrencyGlob.GetRealizedGainsAccount(); + GenJournalLine.Validate(Amount, VATAmount); + if not AdvancePostingParametersCZZ."Temporary Entries Only" then begin + OnPostExchangeRateOnBeforePostVATAmount( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, VATPostingSetup, Amount, VATAmount, + AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); + GLEntryNo := RunGenJnlPostLine(GenJournalLine, GenJnlPostLine, false, false, false); + OnPostExchangeRateOnAfterPostVATAmount( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, VATPostingSetup, Amount, VATAmount, + AdvancePostingParametersCZZ, GLEntryNo, GenJnlPostLine, GenJournalLine); + end; + + // Post balance of exchange rate + InitGenJournalLine(SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, AdvancePostingParametersCZZ, GenJournalLine); + GenJournalLine.Correction := Correction; + GenJournalLine."Account No." := VATPostingSetup.GetSalesAdvLetterAccountCZZ(); + GenJournalLine.Validate(Amount, -Amount); + if not AdvancePostingParametersCZZ."Temporary Entries Only" then begin + OnPostExchangeRateOnBeforePostBalance( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, VATPostingSetup, Amount, VATAmount, + AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); + GLEntryNo := RunGenJnlPostLine(GenJournalLine, GenJnlPostLine, false, false, false); + OnPostExchangeRateOnAfterPostBalance( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, VATPostingSetup, Amount, VATAmount, + AdvancePostingParametersCZZ, GLEntryNo, GenJnlPostLine, GenJournalLine); + end; + end; + + TempSalesAdvLetterEntryCZZGlob.InitNewEntry(); + TempSalesAdvLetterEntryCZZGlob.InitRelatedEntry(RelatedEntryNo); + TempSalesAdvLetterEntryCZZGlob.CopyFromVATPostingSetup(VATPostingSetup); + TempSalesAdvLetterEntryCZZGlob."Entry Type" := "Advance Letter Entry Type CZZ"::"VAT Rate"; + TempSalesAdvLetterEntryCZZGlob."Sales Adv. Letter No." := SalesAdvLetterHeaderCZZ."No."; + TempSalesAdvLetterEntryCZZGlob."Document No." := AdvancePostingParametersCZZ."Document No."; + TempSalesAdvLetterEntryCZZGlob."Posting Date" := AdvancePostingParametersCZZ."Posting Date"; + TempSalesAdvLetterEntryCZZGlob."VAT Date" := AdvancePostingParametersCZZ."VAT Date"; + TempSalesAdvLetterEntryCZZGlob."Amount (LCY)" := Amount; + TempSalesAdvLetterEntryCZZGlob."VAT Amount (LCY)" := VATAmount; + TempSalesAdvLetterEntryCZZGlob."VAT Base Amount (LCY)" := Amount - VATAmount; + TempSalesAdvLetterEntryCZZGlob."Global Dimension 1 Code" := SalesAdvLetterEntryCZZ."Global Dimension 1 Code"; + TempSalesAdvLetterEntryCZZGlob."Global Dimension 2 Code" := SalesAdvLetterEntryCZZ."Global Dimension 2 Code"; + TempSalesAdvLetterEntryCZZGlob."Dimension Set ID" := SalesAdvLetterEntryCZZ."Dimension Set ID"; + TempSalesAdvLetterEntryCZZGlob.Cancelled := Correction; + OnPostExchangeRateOnBeforeInsertEntry( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, VATPostingSetup, + AdvancePostingParametersCZZ, TempSalesAdvLetterEntryCZZGlob); + EntryNo := TempSalesAdvLetterEntryCZZGlob.InsertNewEntry(not AdvancePostingParametersCZZ."Temporary Entries Only"); + + OnAfterPostExchangeRate( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, VATPostingSetup, + EntryNo, GenJnlPostLine, AdvancePostingParametersCZZ, TempSalesAdvLetterEntryCZZGlob); + end; + + internal procedure PostUnrealizedExchangeRate( + SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; + SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; + VATPostingSetup: Record "VAT Posting Setup"; + Amount: Decimal; + VATAmount: Decimal; + RelatedEntryNo: Integer; + RelatedDetEntryNo: Integer; + Correction: Boolean; + var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; + AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ") + var + GenJournalLine: Record "Gen. Journal Line"; + SourceCodeSetup: Record "Source Code Setup"; + EntryNo, GLEntryNo : Integer; + IsHandled: Boolean; + begin + IsHandled := false; + OnBeforePostUnrealizedExchangeRate( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, VATPostingSetup, Amount, VATAmount, + RelatedEntryNo, RelatedDetEntryNo, Correction, GenJnlPostLine, AdvancePostingParametersCZZ, IsHandled); + if IsHandled then + exit; + + if AdvancePostingParametersCZZ."Source Code" = '' then begin + SourceCodeSetup.Get(); + AdvancePostingParametersCZZ."Source Code" := SourceCodeSetup."Exchange Rate Adjmt."; + end; + + if VATAmount <> 0 then begin + GetCurrency(SalesAdvLetterHeaderCZZ."Currency Code"); + + // Post unrealized exchange rate + InitGenJournalLine(SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, AdvancePostingParametersCZZ, GenJournalLine); + if VATAmount > 0 then + GenJournalLine."Account No." := CurrencyGlob.GetUnrealizedLossesAccount() + else + GenJournalLine."Account No." := CurrencyGlob.GetUnrealizedGainsAccount(); + GenJournalLine.Validate(Amount, VATAmount); + if not AdvancePostingParametersCZZ."Temporary Entries Only" then begin + OnPostUnrealizedExchangeRateOnBeforePost( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, VATPostingSetup, Amount, VATAmount, + AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); + GLEntryNo := RunGenJnlPostLine(GenJournalLine, GenJnlPostLine, false, false, false); + OnPostUnrealizedExchangeRateOnAfterPost( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, VATPostingSetup, Amount, VATAmount, + AdvancePostingParametersCZZ, GLEntryNo, GenJnlPostLine, GenJournalLine); + end; + + // Post unrealized exchange rate balance + InitGenJournalLine(SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, AdvancePostingParametersCZZ, GenJournalLine); + GenJournalLine."Account No." := VATPostingSetup.GetSalesAdvLetterAccountCZZ(); + GenJournalLine.Validate(Amount, -VATAmount); + if not AdvancePostingParametersCZZ."Temporary Entries Only" then begin + OnPostUnrealizedExchangeRateOnBeforePostBalance( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, VATPostingSetup, Amount, VATAmount, + AdvancePostingParametersCZZ, GenJnlPostLine, GenJournalLine); + GLEntryNo := RunGenJnlPostLine(GenJournalLine, GenJnlPostLine, false, false, false); + OnPostUnrealizedExchangeRateOnAfterPostBalance( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, VATPostingSetup, Amount, VATAmount, + AdvancePostingParametersCZZ, GLEntryNo, GenJnlPostLine, GenJournalLine); + end; + end; + + TempSalesAdvLetterEntryCZZGlob.InitNewEntry(); + TempSalesAdvLetterEntryCZZGlob.InitRelatedEntry(RelatedEntryNo); + TempSalesAdvLetterEntryCZZGlob.InitDetailedCustLedgerEntry(RelatedDetEntryNo); + TempSalesAdvLetterEntryCZZGlob.CopyFromVATPostingSetup(VATPostingSetup); + TempSalesAdvLetterEntryCZZGlob."Entry Type" := "Advance Letter Entry Type CZZ"::"VAT Adjustment"; + TempSalesAdvLetterEntryCZZGlob."Sales Adv. Letter No." := SalesAdvLetterHeaderCZZ."No."; + TempSalesAdvLetterEntryCZZGlob."Document No." := AdvancePostingParametersCZZ."Document No."; + TempSalesAdvLetterEntryCZZGlob."Posting Date" := AdvancePostingParametersCZZ."Posting Date"; + TempSalesAdvLetterEntryCZZGlob."VAT Date" := AdvancePostingParametersCZZ."VAT Date"; + TempSalesAdvLetterEntryCZZGlob."Amount (LCY)" := Amount; + TempSalesAdvLetterEntryCZZGlob."VAT Amount (LCY)" := VATAmount; + TempSalesAdvLetterEntryCZZGlob."VAT Base Amount (LCY)" := Amount - VATAmount; + TempSalesAdvLetterEntryCZZGlob."Global Dimension 1 Code" := SalesAdvLetterEntryCZZ."Global Dimension 1 Code"; + TempSalesAdvLetterEntryCZZGlob."Global Dimension 2 Code" := SalesAdvLetterEntryCZZ."Global Dimension 2 Code"; + TempSalesAdvLetterEntryCZZGlob."Dimension Set ID" := SalesAdvLetterEntryCZZ."Dimension Set ID"; + TempSalesAdvLetterEntryCZZGlob.Cancelled := Correction; + OnPostUnrealizedExchangeRateOnBeforeInsertEntry( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, VATPostingSetup, + AdvancePostingParametersCZZ, TempSalesAdvLetterEntryCZZGlob); + EntryNo := TempSalesAdvLetterEntryCZZGlob.InsertNewEntry(not AdvancePostingParametersCZZ."Temporary Entries Only"); + + OnAfterPostUnrealizedExchangeRate( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, VATPostingSetup, + EntryNo, GenJnlPostLine, AdvancePostingParametersCZZ, TempSalesAdvLetterEntryCZZGlob); + end; + + internal procedure BufferAdvanceVATLines( + var SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; + var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; + BalanceAtDate: Date) + begin + BufferAdvanceVATLines(SalesAdvLetterEntryCZZ, AdvancePostingBufferCZZ, BalanceAtDate, true); + end; + + local procedure BufferAdvanceVATLines( + var SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; + var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; + BalanceAtDate: Date; + ResetBuffer: Boolean) + var + SalesAdvLetterEntryCZZ2: Record "Sales Adv. Letter Entry CZZ"; + TempAdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ" temporary; + begin + if ResetBuffer then begin + AdvancePostingBufferCZZ.Reset(); + AdvancePostingBufferCZZ.DeleteAll(); + end; + + SalesAdvLetterEntryCZZ2.SetRange("Sales Adv. Letter No.", SalesAdvLetterEntryCZZ."Sales Adv. Letter No."); + SalesAdvLetterEntryCZZ2.SetRange(Cancelled, false); + SalesAdvLetterEntryCZZ2.SetRange("Related Entry", SalesAdvLetterEntryCZZ."Entry No."); + SalesAdvLetterEntryCZZ2.SetFilter("Entry Type", '<>%1', SalesAdvLetterEntryCZZ2."Entry Type"::"VAT Adjustment"); + if BalanceAtDate <> 0D then + SalesAdvLetterEntryCZZ2.SetFilter("Posting Date", '..%1', BalanceAtDate); + if SalesAdvLetterEntryCZZ2.FindSet() then + repeat + if SalesAdvLetterEntryCZZ2."Entry Type" in + [SalesAdvLetterEntryCZZ2."Entry Type"::Payment, + SalesAdvLetterEntryCZZ2."Entry Type"::Usage, + SalesAdvLetterEntryCZZ2."Entry Type"::Close] + then + BufferAdvanceVATLines(SalesAdvLetterEntryCZZ2, AdvancePostingBufferCZZ, BalanceAtDate, false) + else begin + TempAdvancePostingBufferCZZ.PrepareForSalesAdvLetterEntry(SalesAdvLetterEntryCZZ2); + AdvancePostingBufferCZZ.Update(TempAdvancePostingBufferCZZ); + end; + until SalesAdvLetterEntryCZZ2.Next() = 0; + end; + + internal procedure SuggestUsageVAT( + var SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; + var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; + InvoiceNo: Code[20]; + UsedAmount: Decimal; + CurrencyFactor: Decimal; + TemporaryEntriesOnly: Boolean) + var + SalesInvoiceLine: Record "Sales Invoice Line"; + SalesLine: Record "Sales Line"; + TempAdvancePostingBufferCZZ1: Record "Advance Posting Buffer CZZ" temporary; + TempAdvancePostingBufferCZZ2: Record "Advance Posting Buffer CZZ" temporary; + TotalAmount: Decimal; + UseAmount: Decimal; + UseBaseAmount: Decimal; + i: Integer; + Continue: Boolean; + begin + AdvancePostingBufferCZZ.CalcSums(Amount); + TotalAmount := -AdvancePostingBufferCZZ.Amount; + if (UsedAmount <> 0) and (TotalAmount > UsedAmount) then begin + Continue := InvoiceNo <> ''; + if Continue then + if TemporaryEntriesOnly then begin + SalesLine.SetFilter("Document Type", '%1|%2', + SalesLine."Document Type"::Order, + SalesLine."Document Type"::Invoice); + SalesLine.SetRange("Document No.", InvoiceNo); + Continue := SalesLine.FindSet(); + end else begin + SalesInvoiceLine.SetRange("Document No.", InvoiceNo); + Continue := SalesInvoiceLine.FindSet(); + end; + + if Continue then begin + BufferAdvanceVATLines(SalesAdvLetterEntryCZZ, TempAdvancePostingBufferCZZ2, 0D); + + if TemporaryEntriesOnly then + repeat + TempAdvancePostingBufferCZZ1.Init(); + TempAdvancePostingBufferCZZ1."VAT Bus. Posting Group" := SalesLine."VAT Bus. Posting Group"; + TempAdvancePostingBufferCZZ1."VAT Prod. Posting Group" := SalesLine."VAT Prod. Posting Group"; + if TempAdvancePostingBufferCZZ1.Find() then begin + TempAdvancePostingBufferCZZ1.Amount -= SalesLine."Amount Including VAT"; + TempAdvancePostingBufferCZZ1."VAT Base Amount" -= SalesLine.Amount; + TempAdvancePostingBufferCZZ1.Modify(); + end else begin + TempAdvancePostingBufferCZZ1."VAT Calculation Type" := SalesLine."VAT Calculation Type"; + TempAdvancePostingBufferCZZ1."VAT %" := SalesLine."VAT %"; + TempAdvancePostingBufferCZZ1.Amount := -SalesLine."Amount Including VAT"; + TempAdvancePostingBufferCZZ1."VAT Base Amount" := -SalesLine.Amount; + TempAdvancePostingBufferCZZ1.Insert(); + end; + until SalesLine.Next() = 0 + else + repeat + TempAdvancePostingBufferCZZ1.Init(); + TempAdvancePostingBufferCZZ1."VAT Bus. Posting Group" := SalesInvoiceLine."VAT Bus. Posting Group"; + TempAdvancePostingBufferCZZ1."VAT Prod. Posting Group" := SalesInvoiceLine."VAT Prod. Posting Group"; + if TempAdvancePostingBufferCZZ1.Find() then begin + TempAdvancePostingBufferCZZ1.Amount -= SalesInvoiceLine."Amount Including VAT"; + TempAdvancePostingBufferCZZ1."VAT Base Amount" -= SalesInvoiceLine.Amount; + TempAdvancePostingBufferCZZ1.Modify(); + end else begin + TempAdvancePostingBufferCZZ1."VAT Calculation Type" := SalesInvoiceLine."VAT Calculation Type"; + TempAdvancePostingBufferCZZ1."VAT %" := SalesInvoiceLine."VAT %"; + TempAdvancePostingBufferCZZ1.Amount := -SalesInvoiceLine."Amount Including VAT"; + TempAdvancePostingBufferCZZ1."VAT Base Amount" := -SalesInvoiceLine.Amount; + TempAdvancePostingBufferCZZ1.Insert(); + end; + until SalesInvoiceLine.Next() = 0; + + GetCurrency(SalesAdvLetterEntryCZZ."Currency Code"); + + for i := 1 to 3 do begin + TempAdvancePostingBufferCZZ1.FindSet(); + repeat + case i of + 1: + begin + TempAdvancePostingBufferCZZ2.SetRange("VAT Bus. Posting Group", TempAdvancePostingBufferCZZ1."VAT Bus. Posting Group"); + TempAdvancePostingBufferCZZ2.SetRange("VAT Prod. Posting Group", TempAdvancePostingBufferCZZ1."VAT Prod. Posting Group"); + end; + 2: + begin + TempAdvancePostingBufferCZZ2.SetRange("VAT Calculation Type", TempAdvancePostingBufferCZZ1."VAT Calculation Type"); + TempAdvancePostingBufferCZZ2.SetRange("VAT %", TempAdvancePostingBufferCZZ1."VAT %"); + end; + end; + TempAdvancePostingBufferCZZ2.SetFilter(Amount, '<>%1', 0); + if TempAdvancePostingBufferCZZ2.FindSet() then + repeat + UseAmount := TempAdvancePostingBufferCZZ1.Amount; + UseBaseAmount := TempAdvancePostingBufferCZZ1."VAT Base Amount"; + if Abs(TempAdvancePostingBufferCZZ2.Amount) < Abs(UseAmount) then begin + UseAmount := TempAdvancePostingBufferCZZ2.Amount; + UseBaseAmount := TempAdvancePostingBufferCZZ2."VAT Base Amount"; + end; + if Abs(UsedAmount) < Abs(UseAmount) then begin + UseAmount := -UsedAmount; + UseBaseAmount := Round(TempAdvancePostingBufferCZZ2."VAT Base Amount" * UseAmount / TempAdvancePostingBufferCZZ2.Amount, CurrencyGlob."Amount Rounding Precision", CurrencyGlob.VATRoundingDirection()); + end; + if TempAdvancePostingBufferCZZ1."VAT %" <> TempAdvancePostingBufferCZZ2."VAT %" then + UseBaseAmount := Round(TempAdvancePostingBufferCZZ2."VAT Base Amount" * UseAmount / TempAdvancePostingBufferCZZ2.Amount, CurrencyGlob."Amount Rounding Precision", CurrencyGlob.VATRoundingDirection()); + + TempAdvancePostingBufferCZZ2.Amount -= UseAmount; + TempAdvancePostingBufferCZZ2."VAT Base Amount" -= UseBaseAmount; + TempAdvancePostingBufferCZZ2.Modify(); + TempAdvancePostingBufferCZZ1.Amount -= UseAmount; + TempAdvancePostingBufferCZZ1."VAT Base Amount" -= UseBaseAmount; + TempAdvancePostingBufferCZZ1.Modify(); + UsedAmount += UseAmount; + until (TempAdvancePostingBufferCZZ2.Next() = 0) or (UsedAmount = 0); + TempAdvancePostingBufferCZZ2.Reset(); + until TempAdvancePostingBufferCZZ1.Next() = 0; + end; + + if AdvancePostingBufferCZZ.FindSet() then + repeat + TempAdvancePostingBufferCZZ2.Get(AdvancePostingBufferCZZ."VAT Bus. Posting Group", AdvancePostingBufferCZZ."VAT Prod. Posting Group"); + case true of + TempAdvancePostingBufferCZZ2.Amount = 0: + ; + TempAdvancePostingBufferCZZ2.Amount <> AdvancePostingBufferCZZ.Amount: + begin + AdvancePostingBufferCZZ.Amount := AdvancePostingBufferCZZ.Amount - TempAdvancePostingBufferCZZ2.Amount; + AdvancePostingBufferCZZ."VAT Base Amount" := AdvancePostingBufferCZZ."VAT Base Amount" - TempAdvancePostingBufferCZZ2."VAT Base Amount"; + AdvancePostingBufferCZZ."VAT Amount" := AdvancePostingBufferCZZ.Amount - AdvancePostingBufferCZZ."VAT Base Amount"; + AdvancePostingBufferCZZ.Modify(); + end; + TempAdvancePostingBufferCZZ2.Amount = AdvancePostingBufferCZZ.Amount: + begin + AdvancePostingBufferCZZ.Amount := 0; + AdvancePostingBufferCZZ."VAT Base Amount" := 0; + AdvancePostingBufferCZZ."VAT Amount" := 0; + AdvancePostingBufferCZZ.Modify(); + end; + end; + until AdvancePostingBufferCZZ.Next() = 0; + end else begin + AdvancePostingBufferCZZ.FindSet(); + repeat + AdvancePostingBufferCZZ.Amount := Round(AdvancePostingBufferCZZ.Amount * UsedAmount / TotalAmount, CurrencyGlob."Amount Rounding Precision"); + AdvancePostingBufferCZZ."VAT Amount" := Round(AdvancePostingBufferCZZ."VAT Amount" * UsedAmount / TotalAmount, CurrencyGlob."Amount Rounding Precision", CurrencyGlob.VATRoundingDirection()); + AdvancePostingBufferCZZ."VAT Base Amount" := AdvancePostingBufferCZZ.Amount - AdvancePostingBufferCZZ."VAT Amount"; + AdvancePostingBufferCZZ.Modify(); + until AdvancePostingBufferCZZ.Next() = 0; + end; + end; + + if AdvancePostingBufferCZZ.FindSet() then + repeat + AdvancePostingBufferCZZ.UpdateLCYAmounts(SalesAdvLetterEntryCZZ."Currency Code", CurrencyFactor); + AdvancePostingBufferCZZ.Modify(); + until AdvancePostingBufferCZZ.Next() = 0; + end; + + local procedure UnapplyCustLedgEntry(var CustLedgerEntry: Record "Cust. Ledger Entry"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line") + var + DetailedCustLedgEntry1: Record "Detailed Cust. Ledg. Entry"; + DetailedCustLedgEntry2: Record "Detailed Cust. Ledg. Entry"; + DetailedCustLedgEntry3: Record "Detailed Cust. Ledg. Entry"; + GenJournalLine: Record "Gen. Journal Line"; +#if not CLEAN22 +#pragma warning disable AL0432 + ReplaceVATDateMgtCZL: Codeunit "Replace VAT Date Mgt. CZL"; +#pragma warning restore AL0432 +#endif + Succes: Boolean; + begin + DetailedCustLedgEntry1.SetCurrentKey("Cust. Ledger Entry No.", "Entry Type"); + DetailedCustLedgEntry1.SetRange("Cust. Ledger Entry No.", CustLedgerEntry."Entry No."); + DetailedCustLedgEntry1.SetRange("Entry Type", DetailedCustLedgEntry1."Entry Type"::Application); + DetailedCustLedgEntry1.SetRange(Unapplied, false); + Succes := false; + repeat + if DetailedCustLedgEntry1.FindLast() then begin + DetailedCustLedgEntry2.Reset(); + DetailedCustLedgEntry2.SetCurrentKey("Transaction No.", "Customer No.", "Entry Type"); + DetailedCustLedgEntry2.SetRange("Transaction No.", DetailedCustLedgEntry1."Transaction No."); + DetailedCustLedgEntry2.SetRange("Customer No.", DetailedCustLedgEntry1."Customer No."); + if DetailedCustLedgEntry2.FindSet() then + repeat + if (DetailedCustLedgEntry2."Entry Type" <> DetailedCustLedgEntry2."Entry Type"::"Initial Entry") and + not DetailedCustLedgEntry2.Unapplied + then begin + DetailedCustLedgEntry3.Reset(); + DetailedCustLedgEntry3.SetCurrentKey("Cust. Ledger Entry No.", "Entry Type"); + DetailedCustLedgEntry3.SetRange("Cust. Ledger Entry No.", DetailedCustLedgEntry2."Cust. Ledger Entry No."); + DetailedCustLedgEntry3.SetRange(Unapplied, false); + if DetailedCustLedgEntry3.FindLast() and + (DetailedCustLedgEntry3."Transaction No." > DetailedCustLedgEntry2."Transaction No.") + then + Error(UnapplyLastInvoicesErr); + end; + until DetailedCustLedgEntry2.Next() = 0; + + GenJournalLine.Init(); + GenJournalLine."Document No." := DetailedCustLedgEntry1."Document No."; + GenJournalLine."Posting Date" := DetailedCustLedgEntry1."Posting Date"; +#if not CLEAN22 +#pragma warning disable AL0432 + if not ReplaceVATDateMgtCZL.IsEnabled() then + GenJournalLine.Validate("VAT Date CZL", CustLedgerEntry."VAT Date CZL") + else +#pragma warning restore AL0432 +#endif + GenJournalLine.Validate("VAT Reporting Date", CustLedgerEntry."VAT Date CZL"); + GenJournalLine."Account Type" := GenJournalLine."Account Type"::Customer; + GenJournalLine."Account No." := DetailedCustLedgEntry1."Customer No."; + GenJournalLine.Correction := true; + GenJournalLine."Document Type" := GenJournalLine."Document Type"::" "; + GenJournalLine.Description := CustLedgerEntry.Description; + GenJournalLine."Shortcut Dimension 1 Code" := CustLedgerEntry."Global Dimension 1 Code"; + GenJournalLine."Shortcut Dimension 2 Code" := CustLedgerEntry."Global Dimension 2 Code"; + GenJournalLine."Dimension Set ID" := CustLedgerEntry."Dimension Set ID"; + GenJournalLine."Posting Group" := CustLedgerEntry."Customer Posting Group"; + GenJournalLine."Source Currency Code" := DetailedCustLedgEntry1."Currency Code"; + GenJournalLine."System-Created Entry" := true; + OnUnapplyCustLedgEntryOnBeforePostUnapplyCustLedgEntry(CustLedgerEntry, DetailedCustLedgEntry1, GenJournalLine); +#if not CLEAN24 + RaiseOnUnapplyCustLedgEntryOnBeforePostUnapplyCustLedgEntry(CustLedgerEntry, DetailedCustLedgEntry1, GenJournalLine); +#endif + GenJnlPostLine.UnapplyCustLedgEntry(GenJournalLine, DetailedCustLedgEntry1); + end else + Succes := true; + until Succes; + end; + + local procedure InitGenJournalLine( + var SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; + var SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; + var AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; + var GenJournalLine: Record "Gen. Journal Line") + begin + GenJournalLine.InitNewLineCZZ( + AdvancePostingParametersCZZ."Posting Date", AdvancePostingParametersCZZ."Document Date", + AdvancePostingParametersCZZ."VAT Date", AdvancePostingParametersCZZ."Original Document VAT Date", + AdvancePostingParametersCZZ."Posting Description"); + GenJournalLine.CopyDocumentFields( + AdvancePostingParametersCZZ."Document Type", AdvancePostingParametersCZZ."Document No.", + AdvancePostingParametersCZZ."External Document No.", AdvancePostingParametersCZZ."Source Code", ''); + GenJournalLine.CopyFromSalesAdvLetterHeaderCZZ(SalesAdvLetterHeaderCZZ); + GenJournalLine.CopyFromSalesAdvLetterEntryCZZ(SalesAdvLetterEntryCZZ); +#if not CLEAN24 + RaiseOnAfterInitGenJnlLineFromAdvance( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, GenJournalLine); +#endif + GenJournalLine.SetCurrencyFactor( + AdvancePostingParametersCZZ."Currency Code", AdvancePostingParametersCZZ."Currency Factor"); + OnAfterInitGenJournalLine( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, AdvancePostingParametersCZZ, GenJournalLine); + end; + + local procedure InitGenJournalLine( + var CustLedgerEntry: Record "Cust. Ledger Entry"; + var GenJournalLine: Record "Gen. Journal Line") + begin + GenJournalLine.InitNewLineCZZ(CustLedgerEntry); + GenJournalLine.CopyFromCustLedgerEntryCZZ(CustLedgerEntry); +#if not CLEAN24 + RaiseOnAfterInitGenJnlLineFromCustLedgEntry(CustLedgerEntry, GenJournalLine); +#endif + OnAfterInitGenJournalLineFromCustLedgerEntry(CustLedgerEntry, GenJournalLine); + end; + + local procedure RunGenJnlPostLine( + var GenJnlLine: Record "Gen. Journal Line"; + var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; + UseAdvLetterVATAccounts: Boolean; + UseEmptyDocumentType: Boolean; + ActivateGenJnlCheckLnHandler: Boolean) GLEntryNo: Integer + var + DocumentTypeHandlerCZZ: Codeunit "Document Type Handler CZZ"; + GenJnlCheckLnHandlerCZZ: Codeunit "Gen.Jnl.-Check Ln. Handler CZZ"; + VATPostingSetupHandlerCZZ: Codeunit "VAT Posting Setup Handler CZZ"; + IsHandled: Boolean; + begin + IsHandled := false; + OnBeforeRunGenJnlPostLine(GenJnlLine, GenJnlPostLine, GLEntryNo, IsHandled); + if IsHandled then + exit; + + if UseAdvLetterVATAccounts then + BindSubscription(VATPostingSetupHandlerCZZ); + if UseEmptyDocumentType then + BindSubscription(DocumentTypeHandlerCZZ); + if ActivateGenJnlCheckLnHandler then + BindSubscription(GenJnlCheckLnHandlerCZZ); + GLEntryNo := GenJnlPostLine.RunWithCheck(GenJnlLine); + if UseAdvLetterVATAccounts then + UnbindSubscription(VATPostingSetupHandlerCZZ); + if UseEmptyDocumentType then + UnbindSubscription(DocumentTypeHandlerCZZ); + if ActivateGenJnlCheckLnHandler then + UnbindSubscription(GenJnlCheckLnHandlerCZZ); + OnAfterRunGenJnlPostLine(GenJnlLine, GenJnlPostLine, GLEntryNo); + end; + + local procedure GetCurrency(CurrencyCode: Code[10]) + begin + CurrencyGlob.Initialize(CurrencyCode, true); + end; + + local procedure InitCustLedgerEntryFromSalesInvoiceHeader(SalesInvoiceHeader: Record "Sales Invoice Header"; var CustLedgerEntry: Record "Cust. Ledger Entry") +#if not CLEAN22 +#pragma warning disable AL0432 + var + ReplaceVATDateMgtCZL: Codeunit "Replace VAT Date Mgt. CZL"; +#pragma warning restore AL0432 +#endif + begin + CustLedgerEntry.Init(); + CustLedgerEntry."Customer No." := SalesInvoiceHeader."Bill-to Customer No."; + CustLedgerEntry."Posting Date" := SalesInvoiceHeader."Posting Date"; + CustLedgerEntry."Document Date" := SalesInvoiceHeader."Document Date"; + CustLedgerEntry."Document Type" := CustLedgerEntry."Document Type"::Invoice; + CustLedgerEntry."Document No." := SalesInvoiceHeader."No."; + CustLedgerEntry.Description := SalesInvoiceHeader."Posting Description"; + CustLedgerEntry."Currency Code" := SalesInvoiceHeader."Currency Code"; + CustLedgerEntry."Sell-to Customer No." := SalesInvoiceHeader."Sell-to Customer No."; + CustLedgerEntry."Customer Posting Group" := SalesInvoiceHeader."Customer Posting Group"; + CustLedgerEntry."Global Dimension 1 Code" := SalesInvoiceHeader."Shortcut Dimension 1 Code"; + CustLedgerEntry."Global Dimension 2 Code" := SalesInvoiceHeader."Shortcut Dimension 2 Code"; + CustLedgerEntry."Dimension Set ID" := SalesInvoiceHeader."Dimension Set ID"; + CustLedgerEntry."Salesperson Code" := SalesInvoiceHeader."Salesperson Code"; + CustLedgerEntry."Due Date" := SalesInvoiceHeader."Due Date"; + CustLedgerEntry."Payment Method Code" := SalesInvoiceHeader."Payment Method Code"; +#if not CLEAN22 +#pragma warning disable AL0432 + if not ReplaceVATDateMgtCZL.IsEnabled() then + SalesInvoiceHeader."VAT Reporting Date" := SalesInvoiceHeader."VAT Date CZL"; +#pragma warning restore AL0432 +#endif + CustLedgerEntry."VAT Date CZL" := SalesInvoiceHeader."VAT Reporting Date"; + CustLedgerEntry."Original Currency Factor" := SalesInvoiceHeader."Currency Factor"; + end; +#if not CLEAN24 + + local procedure RaiseOnBeforePostAdvancePayment(CustLedgerEntry: Record "Cust. Ledger Entry"; GenJournalLine: Record "Gen. Journal Line"; LinkAmount: Decimal; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var IsHandled: Boolean); + begin + SalesAdvLetterManagementCZZ.RaiseOnBeforePostAdvancePayment( + CustLedgerEntry, GenJournalLine, LinkAmount, GenJnlPostLine, IsHandled); + end; + + local procedure RaiseOnBeforePostPaymentRepos(var GenJournalLine: Record "Gen. Journal Line"; var SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; PostedGenJournalLine: Record "Gen. Journal Line") + begin + SalesAdvLetterManagementCZZ.RaiseOnBeforePostPaymentRepos( + GenJournalLine, SalesAdvLetterHeaderCZZ, PostedGenJournalLine); + end; + + local procedure RaiseOnAfterPostPaymentRepos(var GenJournalLine: Record "Gen. Journal Line"; var SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; PostedGenJournalLine: Record "Gen. Journal Line") + begin + SalesAdvLetterManagementCZZ.RaiseOnAfterPostPaymentRepos( + GenJournalLine, SalesAdvLetterHeaderCZZ, PostedGenJournalLine); + end; + + local procedure RaiseOnBeforePostPayment(var GenJournalLine: Record "Gen. Journal Line"; var SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; PostedGenJournalLine: Record "Gen. Journal Line") + begin + SalesAdvLetterManagementCZZ.RaiseOnBeforePostPayment( + GenJournalLine, SalesAdvLetterHeaderCZZ, PostedGenJournalLine); + end; + + local procedure RaiseOnAfterPostPayment(var GenJournalLine: Record "Gen. Journal Line"; var SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; PostedGenJournalLine: Record "Gen. Journal Line") + begin + SalesAdvLetterManagementCZZ.RaiseOnAfterPostPayment( + GenJournalLine, SalesAdvLetterHeaderCZZ, PostedGenJournalLine); + end; + + local procedure RaiseOnPostAdvancePaymentVATOnBeforeGenJnlPostLine(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; var GenJournalLine: Record "Gen. Journal Line") + begin + SalesAdvLetterManagementCZZ.RaiseOnPostAdvancePaymentVATOnBeforeGenJnlPostLine( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, GenJournalLine); + end; + + local procedure RaiseOnBeforePostAdvancePaymentUsage( + var SalesInvoiceHeader: Record "Sales Invoice Header"; + var AdvanceLetterApplicationCZZ: Record "Advance Letter Application CZZ"; + var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; + AdvancePostingParametersCZ: Record "Advance Posting Parameters CZZ"; + var IsHandled: Boolean) + var + CustLedgerEntry: Record "Cust. Ledger Entry"; + begin + if not CustLedgerEntry.Get(SalesInvoiceHeader."Cust. Ledger Entry No.") then + InitCustLedgerEntryFromSalesInvoiceHeader(SalesInvoiceHeader, CustLedgerEntry); + SalesAdvLetterManagementCZZ.RaiseOnBeforePostAdvancePaymentUsage( + AdvanceLetterApplicationCZZ."Document Type", AdvanceLetterApplicationCZZ."Document No.", SalesInvoiceHeader, + CustLedgerEntry, GenJnlPostLine, AdvancePostingParametersCZ."Temporary Entries Only", IsHandled); + end; + + local procedure RaiseOnAfterPostAdvancePaymentUsage( + var SalesInvoiceHeader: Record "Sales Invoice Header"; + var AdvanceLetterApplicationCZZ: Record "Advance Letter Application CZZ"; + var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; + AdvancePostingParametersCZ: Record "Advance Posting Parameters CZZ") + var + CustLedgerEntry: Record "Cust. Ledger Entry"; + begin + if not CustLedgerEntry.Get(SalesInvoiceHeader."Cust. Ledger Entry No.") then + InitCustLedgerEntryFromSalesInvoiceHeader(SalesInvoiceHeader, CustLedgerEntry); + SalesAdvLetterManagementCZZ.RaiseOnAfterPostAdvancePaymentUsage( + AdvanceLetterApplicationCZZ."Document Type", AdvanceLetterApplicationCZZ."Document No.", SalesInvoiceHeader, + CustLedgerEntry, GenJnlPostLine, AdvancePostingParametersCZ."Temporary Entries Only"); + end; + + local procedure RaiseOnPostAdvancePaymentUsageOnBeforeLoopSalesAdvLetterEntry(var AdvanceLetterApplicationCZZ: Record "Advance Letter Application CZZ"; var SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ") + begin + SalesAdvLetterManagementCZZ.RaiseOnPostAdvancePaymentUsageOnBeforeLoopSalesAdvLetterEntry( + AdvanceLetterApplicationCZZ, SalesAdvLetterEntryCZZ); + end; + + local procedure RaiseOnBeforePostReversePaymentRepos(var GenJournalLine: Record "Gen. Journal Line"; var SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ") + begin + SalesAdvLetterManagementCZZ.RaiseOnBeforePostReversePaymentRepos(GenJournalLine, SalesAdvLetterHeaderCZZ); + end; + + local procedure RaiseOnAfterPostReversePaymentRepos(var GenJournalLine: Record "Gen. Journal Line"; var SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ") + begin + SalesAdvLetterManagementCZZ.RaiseOnAfterPostReversePaymentRepos(GenJournalLine, SalesAdvLetterHeaderCZZ); + end; + + local procedure RaiseOnBeforePostReversePayment(var GenJournalLine: Record "Gen. Journal Line"; var SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ") + begin + SalesAdvLetterManagementCZZ.RaiseOnBeforePostReversePayment(GenJournalLine, SalesAdvLetterHeaderCZZ); + end; + + local procedure RaiseOnAfterPostReversePayment(var GenJournalLine: Record "Gen. Journal Line"; var SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ") + begin + SalesAdvLetterManagementCZZ.RaiseOnAfterPostReversePayment(GenJournalLine, SalesAdvLetterHeaderCZZ); + end; + + local procedure RaiseOnBeforePostReversePaymentVAT(var SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; PostingDate: Date; var Preview: Boolean; var IsHandled: Boolean) + begin + SalesAdvLetterManagementCZZ.RaiseOnBeforePostReversePaymentVAT(SalesAdvLetterEntryCZZ, PostingDate, Preview, IsHandled); + end; + + local procedure RaiseOnBeforePostClosePayment(var GenJournalLine: Record "Gen. Journal Line"; var SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ") + begin + SalesAdvLetterManagementCZZ.RaiseOnBeforePostClosePayment(GenJournalLine, SalesAdvLetterHeaderCZZ); + end; + + local procedure RaiseOnAfterPostClosePayment(var GenJournalLine: Record "Gen. Journal Line"; var SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ") + begin + SalesAdvLetterManagementCZZ.RaiseOnAfterPostClosePayment(GenJournalLine, SalesAdvLetterHeaderCZZ); + end; + + local procedure RaiseOnBeforePostClosePaymentRepos(var GenJournalLine: Record "Gen. Journal Line"; var SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ") + begin + SalesAdvLetterManagementCZZ.RaiseOnBeforePostClosePaymentRepos(GenJournalLine, SalesAdvLetterHeaderCZZ); + end; + + local procedure RaiseOnAfterPostClosePaymentRepos(var GenJournalLine: Record "Gen. Journal Line"; var SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ") + begin + SalesAdvLetterManagementCZZ.RaiseOnAfterPostClosePaymentRepos(GenJournalLine, SalesAdvLetterHeaderCZZ); + end; + + local procedure RaiseOnAfterInitGenJnlLineFromAdvance(var SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; var SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; var GenJournalLine: Record "Gen. Journal Line") + begin + SalesAdvLetterManagementCZZ.RaiseOnAfterInitGenJnlLineFromAdvance( + SalesAdvLetterHeaderCZZ, SalesAdvLetterEntryCZZ, GenJournalLine); + end; + + local procedure RaiseOnAfterInitGenJnlLineFromCustLedgEntry(var CustLedgerEntry: Record "Cust. Ledger Entry"; var GenJournalLine: Record "Gen. Journal Line") + begin + SalesAdvLetterManagementCZZ.RaiseOnAfterInitGenJnlLineFromCustLedgEntry(CustLedgerEntry, GenJournalLine); + end; + + local procedure RaiseOnUnapplyCustLedgEntryOnBeforePostUnapplyCustLedgEntry(var CustLedgerEntry: Record "Cust. Ledger Entry"; var DetailedCustLedgEntry: Record "Detailed Cust. Ledg. Entry"; var GenJournalLine: Record "Gen. Journal Line") + begin + SalesAdvLetterManagementCZZ.RaiseOnUnapplyCustLedgEntryOnBeforePostUnapplyCustLedgEntry( + CustLedgerEntry, DetailedCustLedgEntry, GenJournalLine); + end; +#endif + + [IntegrationEvent(false, false)] + local procedure OnBeforePostAdvancePayment(var CustLedgerEntry: Record "Cust. Ledger Entry"; PostedGenJournalLine: Record "Gen. Journal Line"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; var IsHandled: Boolean) + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnAfterPostAdvancePayment(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; CustLedgerEntry: Record "Cust. Ledger Entry"; PostedGenJournalLine: Record "Gen. Journal Line"; EntryNo: Integer; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostAdvancePaymentOnBeforePostPaymentApplication(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; PostedGenJournalLine: Record "Gen. Journal Line"; AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostAdvancePaymentOnAfterPostPaymentApplication(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; PostedGenJournalLine: Record "Gen. Journal Line"; 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 OnPostAdvancePaymentOnBeforePostAdvancePayment(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; PostedGenJournalLine: Record "Gen. Journal Line"; AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostAdvancePaymentOnAfterPostAdvancePayment(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; PostedGenJournalLine: Record "Gen. Journal Line"; 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 OnBeforePostAdvancePaymentUnlinking(var SalesAdvLetterEntryCZZ: Record "Sales 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 OnAfterPostAdvancePaymentUnlinking(SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostAdvancePaymentUnlinkingOnBeforePostAdvancePaymentApplication(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostAdvancePaymentUnlinkingOnAfterPostAdvancePaymentApplication(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; 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 OnPostAdvancePaymentUnlinkingOnBeforePostPaymentApplication(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostAdvancePaymentUnlinkingOnAfterPostPaymentApplication(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; 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 OnBeforePostAdvancePaymentVAT(var SalesAdvLetterEntryCZZ: Record "Sales 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 + end; + + [IntegrationEvent(false, false)] + local procedure OnAfterPostAdvancePaymentVAT(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostAdvancePaymentVATOnBeforePost(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostAdvancePaymentVATOnAfterPost(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; 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 OnPostAdvancePaymentVATOnBeforePostBalance(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostAdvancePaymentVATOnAfterPostBalance(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; 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 OnBeforePostAdvancePaymentVATUnlinking(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; var SalesAdvLetterEntryCZZ: Record "Sales 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 + end; + + [IntegrationEvent(false, false)] + local procedure OnAfterPostAdvancePaymentVATUnlinking(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; EntryNo: Integer; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostAdvancePaymentVATUnlinkingOnBeforePost(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; VATPostingSetup: Record "VAT Posting Setup"; AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostAdvancePaymentVATUnlinkingOnAfterPost(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; VATPostingSetup: Record "VAT Posting Setup"; 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 OnPostAdvancePaymentVATUnlinkingOnBeforePostBalance(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostAdvancePaymentVATUnlinkingOnAfterPostBalance(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; 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 OnBeforePostAdvancePaymentUsage(var SalesInvoiceHeader: Record "Sales Invoice Header"; var AdvanceLetterApplicationCZZ: Record "Advance Letter Application CZZ"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var AdvancePostingParameters: Record "Advance Posting Parameters CZZ"; var IsHandled: Boolean) + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnAfterPostAdvancePaymentUsage(var SalesInvoiceHeader: Record "Sales Invoice Header"; var AdvanceLetterApplicationCZZ: Record "Advance Letter Application CZZ"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; AdvancePostingParameters: Record "Advance Posting Parameters CZZ") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostAdvancePaymentUsageOnAfterSetSalesAdvLetterEntryFilter(AdvanceLetterApplicationCZZ: Record "Advance Letter Application CZZ"; var SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnBeforePostAdvancePaymentUsageVAT(var SalesAdvLetterEntryCZZ: Record "Sales 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 + end; + + [IntegrationEvent(false, false)] + local procedure OnAfterPostAdvancePaymentUsageVAT(SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnBeforePostAdvanceCreditMemoVAT(var SalesAdvLetterEntryCZZ: Record "Sales 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 + end; + + [IntegrationEvent(false, false)] + local procedure OnAfterPostAdvanceCreditMemoVAT(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostAdvanceCreditMemoVATOnBeforePost(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; SalesAdvLetterEntryCZZ: Record "Sales 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"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostAdvanceCreditMemoVATOnAfterPost(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; 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 OnPostAdvanceCreditMemoVATOnBeforePostBalance(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; SalesAdvLetterEntryCZZ: Record "Sales 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"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostAdvanceCreditMemoVATOnAfterPostBalance(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; 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 OnBeforePostAdvanceLetterApplying(var SalesInvoiceHeader: Record "Sales Invoice Header"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; var IsHandled: Boolean) + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnAfterPostAdvanceLetterApplying(var SalesInvoiceHeader: Record "Sales Invoice Header"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnBeforePostAdvanceLetterUnapplying(var SalesInvoiceHeader: Record "Sales Invoice Header"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; var IsHandled: Boolean) + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnAfterPostAdvanceLetterUnapplying(SalesInvoiceHeader: Record "Sales Invoice Header"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnBeforePostAdvanceLetterEntryVATUsageUnapplying(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; SalesAdvLetterEntryCZZ: Record "Sales 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 + end; + + [IntegrationEvent(false, false)] + local procedure OnAfterPostAdvanceLetterEntryVATUsageUnapplying(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; EntryNo: Integer; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostAdvanceLetterEntryVATUsageUnapplyingOnBeforePost(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; SalesAdvLetterEntryCZZ: Record "Sales 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"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostAdvanceLetterEntryVATUsageUnapplyingOnAfterPost(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; 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 OnPostAdvanceLetterEntryVATUsageUnapplyingOnBeforePostBalance(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; SalesAdvLetterEntryCZZ: Record "Sales 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"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostAdvanceLetterEntryVATUsageUnapplyingOnAfterPostBalance(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; 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 OnBeforePostAdvanceLetterEntryUsageUnapplying(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; SalesAdvLetterEntryCZZ: Record "Sales 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 + end; + + [IntegrationEvent(false, false)] + local procedure OnAfterPostAdvanceLetterEntryUsageUnapplying(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; EntryNo: Integer; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostAdvanceLetterEntryUsageUnapplyingOnBeforePostAdvancePaymentApplication(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; var AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostAdvanceLetterEntryUsageUnapplyingOnAfterPostAdvancePaymentApplication(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; 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 OnPostAdvanceLetterEntryUsageUnapplyingOnBeforePostInvoiceApplication(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; var AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostAdvanceLetterEntryUsageUnapplyingOnAfterPostInvoiceApplication(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; 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 OnBeforePostAdvanceLetterClosing(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header 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 OnAfterPostAdvanceLetterClosing(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnBeforePostAdvanceLetterEntryClosing(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; SalesAdvLetterEntryCZZ: Record "Sales 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 OnAfterPostAdvanceLetterEntryClosing(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostAdvanceLetterEntryClosingOnBeforePost(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; CustLedgerEntry: Record "Cust. Ledger Entry"; var AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostAdvanceLetterEntryClosingOnAfterPost(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; CustLedgerEntry: Record "Cust. Ledger Entry"; 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 OnPostAdvanceLetterEntryClosingOnBeforePostBalance(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; CustLedgerEntry: Record "Cust. Ledger Entry"; var AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostAdvanceLetterEntryClosingOnAfterPostBalance(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; CustLedgerEntry: Record "Cust. Ledger Entry"; 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 OnBeforeReverseAdvancePayment(SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; SalesInvoiceHeader: Record "Sales Invoice Header"; ReverseAmount: Decimal; ReverseAmountLCY: Decimal; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; var IsHandled: Boolean) + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnAfterReverseAdvancePayment(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; SalesInvoiceHeader: Record "Sales Invoice Header"; EntryNo: Integer; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnReverseAdvancePaymentOnBeforePostInvoiceApplication(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; CustLedgerEntry: Record "Cust. Ledger Entry"; var AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnReverseAdvancePaymentOnAfterPostInvoiceApplication(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; CustLedgerEntry: Record "Cust. Ledger Entry"; 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 OnReverseAdvancePaymentOnBeforePostAdvancePaymentUsage(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; CustLedgerEntry: Record "Cust. Ledger Entry"; var AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnReverseAdvancePaymentOnAfterPostAdvancePaymentUsage(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; CustLedgerEntry: Record "Cust. Ledger Entry"; 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 OnBeforeReverseAdvancePaymentVAT(var SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; RelatedEntryNo: Integer; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; var IsHandled: Boolean) + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnAfterReverseAdvancePaymentVAT(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnReverseAdvancePaymentVATOnBeforePost(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; VATPostingSetup: Record "VAT Posting Setup"; var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; var AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnReverseAdvancePaymentVATOnAfterPost(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; VATPostingSetup: Record "VAT Posting Setup"; var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; 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 OnReverseAdvancePaymentVATOnBeforePostBalance(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; var SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; VATPostingSetup: Record "VAT Posting Setup"; var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; var AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnReverseAdvancePaymentVATOnAfterPostBalance(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; var SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; VATPostingSetup: Record "VAT Posting Setup"; var AdvancePostingBufferCZZ: Record "Advance Posting Buffer CZZ"; 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 OnBeforeReverseUnrealizedExchangeRate(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; VATPostingSetup: Record "VAT Posting Setup"; Coef: Decimal; RelatedEntryNo: Integer; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; var IsHandled: Boolean) + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnBeforePostExchangeRate(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; VATPostingSetup: Record "VAT Posting Setup"; Amount: Decimal; VATAmount: Decimal; RelatedEntryNo: Integer; Correction: Boolean; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; var IsHandled: Boolean) + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnAfterPostExchangeRate(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; VATPostingSetup: Record "VAT Posting Setup"; EntryNo: Integer; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; var CreatedSalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostExchangeRateOnBeforePostVATBase(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; VATPostingSetup: Record "VAT Posting Setup"; Amount: Decimal; VATAmount: Decimal; var AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostExchangeRateOnAfterPostVATBase(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; VATPostingSetup: Record "VAT Posting Setup"; Amount: Decimal; VATAmount: Decimal; 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 OnPostExchangeRateOnBeforePostVATAmount(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; VATPostingSetup: Record "VAT Posting Setup"; Amount: Decimal; VATAmount: Decimal; var AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostExchangeRateOnAfterPostVATAmount(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; VATPostingSetup: Record "VAT Posting Setup"; Amount: Decimal; VATAmount: Decimal; 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 OnPostExchangeRateOnBeforePostBalance(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; VATPostingSetup: Record "VAT Posting Setup"; Amount: Decimal; VATAmount: Decimal; var AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostExchangeRateOnAfterPostBalance(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; VATPostingSetup: Record "VAT Posting Setup"; Amount: Decimal; VATAmount: Decimal; 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 OnPostExchangeRateOnBeforeInsertEntry(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; VATPostingSetup: Record "VAT Posting Setup"; var AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; var CreatedSalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnBeforePostUnrealizedExchangeRate(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; VATPostingSetup: Record "VAT Posting Setup"; Amount: Decimal; VATAmount: Decimal; RelatedEntryNo: Integer; RelatedDetEntryNo: Integer; Correction: Boolean; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; var IsHandled: Boolean) + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnAfterPostUnrealizedExchangeRate(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; VATPostingSetup: Record "VAT Posting Setup"; EntryNo: Integer; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; var CreatedSalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostUnrealizedExchangeRateOnBeforePost(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; VATPostingSetup: Record "VAT Posting Setup"; Amount: Decimal; VATAmount: Decimal; var AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostUnrealizedExchangeRateOnAfterPost(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; VATPostingSetup: Record "VAT Posting Setup"; Amount: Decimal; VATAmount: Decimal; 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 OnPostUnrealizedExchangeRateOnBeforePostBalance(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; VATPostingSetup: Record "VAT Posting Setup"; Amount: Decimal; VATAmount: Decimal; var AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnPostUnrealizedExchangeRateOnAfterPostBalance(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; VATPostingSetup: Record "VAT Posting Setup"; Amount: Decimal; VATAmount: Decimal; 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 OnPostUnrealizedExchangeRateOnBeforeInsertEntry(SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; VATPostingSetup: Record "VAT Posting Setup"; AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; var CreatedSalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnUnapplyCustLedgEntryOnBeforePostUnapplyCustLedgEntry(var CustLedgerEntry: Record "Cust. Ledger Entry"; var DetailedCustLedgEntry: Record "Detailed Cust. Ledg. Entry"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnAfterInitGenJournalLine(var SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; var SalesAdvLetterEntryCZZ: Record "Sales Adv. Letter Entry CZZ"; var AdvancePostingParametersCZZ: Record "Advance Posting Parameters CZZ"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnAfterInitGenJournalLineFromCustLedgerEntry(var CustLedgerEntry: Record "Cust. Ledger Entry"; var GenJournalLine: Record "Gen. Journal Line") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnBeforeRunGenJnlPostLine(var GenJnlLine: Record "Gen. Journal Line"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var GLEntryNo: Integer; var IsHandled: Boolean) + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnAfterRunGenJnlPostLine(var GenJnlLine: Record "Gen. Journal Line"; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; var GLEntryNo: Integer) + begin + end; +} \ No newline at end of file diff --git a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/SalesPostHandlerCZZ.Codeunit.al b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/SalesPostHandlerCZZ.Codeunit.al index fbd6687703..3ff943641d 100644 --- a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/SalesPostHandlerCZZ.Codeunit.al +++ b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/SalesPostHandlerCZZ.Codeunit.al @@ -18,13 +18,10 @@ codeunit 31008 "Sales-Post Handler CZZ" var SalesAdvLetterManagement: Codeunit "SalesAdvLetterManagement CZZ"; begin - if (not SalesHeader.Invoice) or (not (SalesHeader."Document Type" in [SalesHeader."Document Type"::Order, SalesHeader."Document Type"::Invoice])) then + if (not SalesHeader.Invoice) or (not SalesHeader.IsAdvanceLetterDocTypeCZZ()) then exit; - if SalesHeader."Document Type" = SalesHeader."Document Type"::Order then - SalesAdvLetterManagement.CheckAdvancePayment("Adv. Letter Usage Doc.Type CZZ"::"Sales Order", SalesHeader) - else - SalesAdvLetterManagement.CheckAdvancePayment("Adv. Letter Usage Doc.Type CZZ"::"Sales Invoice", SalesHeader); + SalesAdvLetterManagement.CheckAdvancePayment(SalesHeader.GetAdvLetterUsageDocTypeCZZ(), SalesHeader) end; [EventSubscriber(ObjectType::Codeunit, Codeunit::"Sales Handler CZP", 'OnBeforeCreateCashDocument', '', false, false)] @@ -42,13 +39,10 @@ codeunit 31008 "Sales-Post Handler CZZ" SalesAdvLetterManagement: Codeunit "SalesAdvLetterManagement CZZ"; AdvLetterUsageDocTypeCZZ: Enum "Adv. Letter Usage Doc.Type CZZ"; begin - if (not SalesHeader.Invoice) or (not (SalesHeader."Document Type" in [SalesHeader."Document Type"::Order, SalesHeader."Document Type"::Invoice])) then + if (not SalesHeader.Invoice) or (not SalesHeader.IsAdvanceLetterDocTypeCZZ()) then exit; - if SalesHeader."Document Type" = SalesHeader."Document Type"::Order then - AdvLetterUsageDocTypeCZZ := AdvLetterUsageDocTypeCZZ::"Sales Order" - else - AdvLetterUsageDocTypeCZZ := AdvLetterUsageDocTypeCZZ::"Sales Invoice"; + AdvLetterUsageDocTypeCZZ := SalesHeader.GetAdvLetterUsageDocTypeCZZ(); CustLedgerEntry.Get(SalesInvoiceHeader."Cust. Ledger Entry No."); BindSubscription(GetLastGLEntryNoCZZ); diff --git a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/VATAmountLineHandlerCZZ.Codeunit.al b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/VATAmountLineHandlerCZZ.Codeunit.al new file mode 100644 index 0000000000..69cd716bd9 --- /dev/null +++ b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/VATAmountLineHandlerCZZ.Codeunit.al @@ -0,0 +1,19 @@ +// ------------------------------------------------------------------------------------------------ +// 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.AdvancePayments; + +using Microsoft.Finance.VAT.Calculation; +using Microsoft.Finance.VAT.Ledger; + +codeunit 31145 "VAT Amount Line Handler CZZ" +{ + Access = Internal; + + [EventSubscriber(ObjectType::Table, Database::"VAT Amount Line", 'OnCopyDocumentVATEntriesToBufferOnAfterSetVATEntryFilterCZL', '', false, false)] + local procedure SkipAdvanceLetterVATEntriesOnCopyDocumentVATEntriesToBufferOnAfterSetVATEntryFilterCZL(var VATEntry: Record "VAT Entry") + begin + VATEntry.SetRange("Advance Letter No. CZZ", ''); + end; +} \ No newline at end of file diff --git a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/VATPostingSetupHandlerCZZ.Codeunit.al b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/VATPostingSetupHandlerCZZ.Codeunit.al index ffa57783e1..0c583e08e8 100644 --- a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/VATPostingSetupHandlerCZZ.Codeunit.al +++ b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Codeunits/VATPostingSetupHandlerCZZ.Codeunit.al @@ -13,8 +13,7 @@ codeunit 31005 "VAT Posting Setup Handler CZZ" [EventSubscriber(ObjectType::Table, Database::"VAT Posting Setup", 'OnBeforeGetSalesAccount', '', false, false)] local procedure VATPostingSetupOnBeforeGetSalesAccount(var VATPostingSetup: Record "VAT Posting Setup"; var SalesVATAccountNo: Code[20]; var IsHandled: Boolean) begin - VATPostingSetup.TestField("Sales Adv. Letter VAT Acc. CZZ"); - SalesVATAccountNo := VATPostingSetup."Sales Adv. Letter VAT Acc. CZZ"; + SalesVATAccountNo := VATPostingSetup.GetSalesAdvLetterVATAccountCZZ(); IsHandled := true; end; @@ -22,8 +21,7 @@ codeunit 31005 "VAT Posting Setup Handler CZZ" [EventSubscriber(ObjectType::Table, Database::"VAT Posting Setup", 'OnBeforeGetPurchAccount', '', false, false)] local procedure VATPostingSetupOnBeforeGetPurchAccount(var VATPostingSetup: Record "VAT Posting Setup"; var PurchVATAccountNo: Code[20]; var IsHandled: Boolean) begin - VATPostingSetup.TestField("Purch. Adv.Letter VAT Acc. CZZ"); - PurchVATAccountNo := VATPostingSetup."Purch. Adv.Letter VAT Acc. CZZ"; + PurchVATAccountNo := VATPostingSetup.GetPurchAdvLetterVATAccountCZZ(); IsHandled := true; end; diff --git a/Apps/CZ/AdvancePaymentsLocalization/app/Src/PageExtensions/PurchaseOrderCZZ.PageExt.al b/Apps/CZ/AdvancePaymentsLocalization/app/Src/PageExtensions/PurchaseOrderCZZ.PageExt.al index 6c06e8bded..5f79cc0c06 100644 --- a/Apps/CZ/AdvancePaymentsLocalization/app/Src/PageExtensions/PurchaseOrderCZZ.PageExt.al +++ b/Apps/CZ/AdvancePaymentsLocalization/app/Src/PageExtensions/PurchaseOrderCZZ.PageExt.al @@ -104,7 +104,8 @@ pageextension 31037 "Purchase Order CZZ" extends "Purchase Order" var PurchAdvLetterManagementCZZ: Codeunit "PurchAdvLetterManagement CZZ"; begin - PurchAdvLetterManagementCZZ.LinkAdvanceLetter("Adv. Letter Usage Doc.Type CZZ"::"Purchase Order", Rec."No.", Rec."Pay-to Vendor No.", Rec."Posting Date", Rec."Currency Code"); + PurchAdvLetterManagementCZZ.LinkAdvanceLetter( + Rec.GetAdvLetterUsageDocTypeCZZ(), Rec."No.", Rec."Pay-to Vendor No.", Rec."Posting Date", Rec."Currency Code"); end; } } diff --git a/Apps/CZ/AdvancePaymentsLocalization/app/Src/PageExtensions/SalesOrderCZZ.PageExt.al b/Apps/CZ/AdvancePaymentsLocalization/app/Src/PageExtensions/SalesOrderCZZ.PageExt.al index e5a8a9492c..c75ed20a83 100644 --- a/Apps/CZ/AdvancePaymentsLocalization/app/Src/PageExtensions/SalesOrderCZZ.PageExt.al +++ b/Apps/CZ/AdvancePaymentsLocalization/app/Src/PageExtensions/SalesOrderCZZ.PageExt.al @@ -112,7 +112,8 @@ pageextension 31023 "Sales Order CZZ" extends "Sales Order" var SalesAdvLetterManagementCZZ: Codeunit "SalesAdvLetterManagement CZZ"; begin - SalesAdvLetterManagementCZZ.LinkAdvanceLetter("Adv. Letter Usage Doc.Type CZZ"::"Sales Order", Rec."No.", Rec."Bill-to Customer No.", Rec."Posting Date", Rec."Currency Code"); + SalesAdvLetterManagementCZZ.LinkAdvanceLetter( + Rec.GetAdvLetterUsageDocTypeCZZ(), Rec."No.", Rec."Bill-to Customer No.", Rec."Posting Date", Rec."Currency Code"); end; } } diff --git a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Pages/AdvanceLetterApplEditCZZ.Page.al b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Pages/AdvanceLetterApplEditCZZ.Page.al index 718265e270..17afa64d7a 100644 --- a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Pages/AdvanceLetterApplEditCZZ.Page.al +++ b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Pages/AdvanceLetterApplEditCZZ.Page.al @@ -29,27 +29,14 @@ page 31175 "Advance Letter Appl. Edit CZZ" begin if Rec."Advance Letter No." <> '' then begin TempAdvanceLetterApplication.Get(Rec."Advance Letter Type", Rec."Advance Letter No.", Rec."Document Type", Rec."Document No."); - Rec."Advance Letter Type" := TempAdvanceLetterApplication."Advance Letter Type"; - Rec."Advance Letter No." := TempAdvanceLetterApplication."Advance Letter No."; - Rec."Document Type" := TempAdvanceLetterApplication."Document Type"; - Rec."Document No." := TempAdvanceLetterApplication."Document No."; - Rec."Posting Date" := TempAdvanceLetterApplication."Posting Date"; - Rec.Amount := TempAdvanceLetterApplication.Amount; - Rec."Amount (LCY)" := TempAdvanceLetterApplication."Amount (LCY)"; + Rec.CopyFrom(TempAdvanceLetterApplication); end end; trigger OnLookup(var Text: Text): Boolean begin - if Page.RunModal(Page::"Advance Letter Application CZZ", TempAdvanceLetterApplication) = Action::LookupOK then begin - Rec."Advance Letter Type" := TempAdvanceLetterApplication."Advance Letter Type"; - Rec."Advance Letter No." := TempAdvanceLetterApplication."Advance Letter No."; - Rec."Document Type" := TempAdvanceLetterApplication."Document Type"; - Rec."Document No." := TempAdvanceLetterApplication."Document No."; - Rec."Posting Date" := TempAdvanceLetterApplication."Posting Date"; - Rec.Amount := TempAdvanceLetterApplication.Amount; - Rec."Amount (LCY)" := TempAdvanceLetterApplication."Amount (LCY)"; - end; + if Page.RunModal(Page::"Advance Letter Application CZZ", TempAdvanceLetterApplication) = Action::LookupOK then + Rec.CopyFrom(TempAdvanceLetterApplication); end; } field("Posting Date"; Rec."Posting Date") diff --git a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Pages/PurchAdvUsageFactBoxCZZ.Page.al b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Pages/PurchAdvUsageFactBoxCZZ.Page.al index 625d0a6449..d4f8098634 100644 --- a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Pages/PurchAdvUsageFactBoxCZZ.Page.al +++ b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Pages/PurchAdvUsageFactBoxCZZ.Page.al @@ -29,18 +29,10 @@ page 31189 "Purch. Adv. Usage FactBox CZZ" var PurchAdvLetterManagement: Codeunit "PurchAdvLetterManagement CZZ"; begin - case Rec."Document Type" of - Rec."Document Type"::Order: - begin - PurchAdvLetterManagement.LinkAdvanceLetter("Adv. Letter Usage Doc.Type CZZ"::"Purchase Order", PurchaseHeader."No.", PurchaseHeader."Pay-to Vendor No.", PurchaseHeader."Posting Date", PurchaseHeader."Currency Code"); - CurrPage.Update(); - end; - Rec."Document Type"::Invoice: - begin - PurchAdvLetterManagement.LinkAdvanceLetter("Adv. Letter Usage Doc.Type CZZ"::"Purchase Invoice", PurchaseHeader."No.", PurchaseHeader."Pay-to Vendor No.", PurchaseHeader."Posting Date", PurchaseHeader."Currency Code"); - CurrPage.Update(); - end; - end; + PurchAdvLetterManagement.LinkAdvanceLetter( + PurchaseHeader.GetAdvLetterUsageDocTypeCZZ(), PurchaseHeader."No.", PurchaseHeader."Pay-to Vendor No.", + PurchaseHeader."Posting Date", PurchaseHeader."Currency Code"); + CurrPage.Update(); end; } field(AdvanceAmountToUse; AdvanceAmountToUse) @@ -125,11 +117,8 @@ page 31189 "Purch. Adv. Usage FactBox CZZ" end; PurchaseHeader.Get(Rec."Document Type", Rec."Document No."); - - if PurchaseHeader."Document Type" = PurchaseHeader."Document Type"::Order then - AdvanceLetterApplication.GetAssignedAdvance("Adv. Letter Usage Doc.Type CZZ"::"Purchase Order", PurchaseHeader."No.", TempAdvanceLetterApplication) - else - AdvanceLetterApplication.GetAssignedAdvance("Adv. Letter Usage Doc.Type CZZ"::"Purchase Invoice", PurchaseHeader."No.", TempAdvanceLetterApplication); + AdvanceLetterApplication.GetAssignedAdvance( + PurchaseHeader.GetAdvLetterUsageDocTypeCZZ(), PurchaseHeader."No.", TempAdvanceLetterApplication); CurrFactor := PurchaseHeader."Currency Factor"; if CurrFactor = 0 then diff --git a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Pages/PurchAdvanceLetterCZZ.Page.al b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Pages/PurchAdvanceLetterCZZ.Page.al index 0f46fc551d..1a2bf6f6ff 100644 --- a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Pages/PurchAdvanceLetterCZZ.Page.al +++ b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Pages/PurchAdvanceLetterCZZ.Page.al @@ -214,10 +214,28 @@ page 31181 "Purch. Advance Letter CZZ" ApplicationArea = Basic, Suite; ToolTip = 'Specifies if post VAT usage automatically.'; } +#if not CLEAN25 field("Amount on Iss. Payment Order"; "Amount on Iss. Payment Order") { ApplicationArea = Basic, Suite; ToolTip = 'Specifies amount on issued payment order.'; + Visible = false; + ObsoleteState = Pending; + ObsoleteReason = 'This field is obsolete and will be removed in a future release. The CalcSuggestedAmountToApply function should be used instead.'; + ObsoleteTag = '25.0'; + } +#endif + field(SuggestedAmountToApplyCZL; Rec.CalcSuggestedAmountToApply()) + { + Caption = 'Suggested Amount to Apply (LCY)'; + ApplicationArea = Basic, Suite; + Editable = false; + ToolTip = 'Specifies the total Amount (LCY) suggested to apply.'; + + trigger OnDrillDown() + begin + Rec.DrillDownSuggestedAmountToApply(); + end; } } part(AdvLetterLines; "Purch. Advance Letter Line CZZ") diff --git a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Pages/PurchAdvanceLettersCZZ.Page.al b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Pages/PurchAdvanceLettersCZZ.Page.al index 91114514ad..b40e21783c 100644 --- a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Pages/PurchAdvanceLettersCZZ.Page.al +++ b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Pages/PurchAdvanceLettersCZZ.Page.al @@ -159,12 +159,17 @@ page 31180 "Purch. Advance Letters CZZ" ToolTip = 'Specifies whether VAT document will be posted automatically.'; Visible = false; } +#if not CLEAN25 field("Amount on Iss. Payment Order"; "Amount on Iss. Payment Order") { ApplicationArea = Basic, Suite; ToolTip = 'Specifies amount on issued payment order.'; Visible = false; + ObsoleteState = Pending; + ObsoleteReason = 'This field is obsolete and will be removed in a future release. The CalcSuggestedAmountToApply function should be used instead.'; + ObsoleteTag = '25.0'; } +#endif field(SuggestedAmountToApplyCZL; Rec.CalcSuggestedAmountToApply()) { Caption = 'Suggested Amount to Apply (LCY)'; diff --git a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Pages/SalesAdvUsageFactBoxCZZ.Page.al b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Pages/SalesAdvUsageFactBoxCZZ.Page.al index 475a5a6258..c2fb0fc53a 100644 --- a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Pages/SalesAdvUsageFactBoxCZZ.Page.al +++ b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Pages/SalesAdvUsageFactBoxCZZ.Page.al @@ -29,18 +29,10 @@ page 31187 "Sales Adv. Usage FactBox CZZ" var SalesAdvLetterManagement: Codeunit "SalesAdvLetterManagement CZZ"; begin - case Rec."Document Type" of - Rec."Document Type"::Order: - begin - SalesAdvLetterManagement.LinkAdvanceLetter("Adv. Letter Usage Doc.Type CZZ"::"Sales Order", SalesHeader."No.", SalesHeader."Bill-to Customer No.", SalesHeader."Posting Date", SalesHeader."Currency Code"); - CurrPage.Update(); - end; - Rec."Document Type"::Invoice: - begin - SalesAdvLetterManagement.LinkAdvanceLetter("Adv. Letter Usage Doc.Type CZZ"::"Sales Invoice", SalesHeader."No.", SalesHeader."Bill-to Customer No.", SalesHeader."Posting Date", SalesHeader."Currency Code"); - CurrPage.Update(); - end; - end; + SalesAdvLetterManagement.LinkAdvanceLetter( + SalesHeader.GetAdvLetterUsageDocTypeCZZ(), SalesHeader."No.", SalesHeader."Bill-to Customer No.", + SalesHeader."Posting Date", SalesHeader."Currency Code"); + CurrPage.Update(); end; } field(AdvanceAmountToUse; AdvanceAmountToUse) @@ -125,11 +117,8 @@ page 31187 "Sales Adv. Usage FactBox CZZ" end; SalesHeader.Get(Rec."Document Type", Rec."Document No."); - - if SalesHeader."Document Type" = SalesHeader."Document Type"::Order then - AdvanceLetterApplication.GetAssignedAdvance("Adv. Letter Usage Doc.Type CZZ"::"Sales Order", SalesHeader."No.", TempAdvanceLetterApplication) - else - AdvanceLetterApplication.GetAssignedAdvance("Adv. Letter Usage Doc.Type CZZ"::"Sales Invoice", SalesHeader."No.", TempAdvanceLetterApplication); + AdvanceLetterApplication.GetAssignedAdvance( + SalesHeader.GetAdvLetterUsageDocTypeCZZ(), SalesHeader."No.", TempAdvanceLetterApplication); CurrFactor := SalesHeader."Currency Factor"; if CurrFactor = 0 then diff --git a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Pages/VATDocumentCZZ.Page.al b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Pages/VATDocumentCZZ.Page.al index 006df64ba9..f6cb8bb512 100644 --- a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Pages/VATDocumentCZZ.Page.al +++ b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Pages/VATDocumentCZZ.Page.al @@ -42,9 +42,9 @@ page 31185 "VAT Document CZZ" trigger OnAssistEdit() var - NoSeriesManagement2: Codeunit NoSeriesManagement; + NoSeries: Codeunit "No. Series"; begin - if NoSeriesManagement2.SelectSeries(InitNoSeriesCode, NoSeriesCode, NoSeriesCode) then begin + if NoSeries.LookupRelatedNoSeries(InitNoSeriesCode, NoSeriesCode, NoSeriesCode) then begin DocumentNo := NoSeriesBatch.GetNextNo(NoSeriesCode, PostingDate); InitDocumentNo := DocumentNo; end; @@ -136,6 +136,12 @@ page 31185 "VAT Document CZZ" } } + trigger OnOpenPage() + begin + if DocumentNo = '' then + DocumentNo := NoSeriesBatch.GetNextNo(NoSeriesCode, PostingDate); + end; + var NoSeriesBatch: Codeunit "No. Series - Batch"; NoSeries: Codeunit "No. Series"; @@ -185,13 +191,8 @@ page 31185 "VAT Document CZZ" GeneralLedgerSetup.GetOriginalDocumentVATDateCZL(PostingDate, VATDate, DocumentDate); CurrPage.Lines.Page.InitDocumentLines(NewCurrencyCode, NewCurrencyFactor, AdvancePostingBufferCZZ); - if NewDocumentNo <> '' then begin - DocumentNo := NewDocumentNo; - DocumentNoEditable := false; - end else begin - DocumentNo := NoSeriesBatch.GetNextNo(NoSeriesCode, PostingDate); - DocumentNoEditable := true; - end; + DocumentNo := NewDocumentNo; + DocumentNoEditable := NewDocumentNo = ''; InitDocumentNo := DocumentNo; end; diff --git a/Apps/CZ/AdvancePaymentsLocalization/app/Src/ReportExtensions/SuggestWorksheetLinesCZZ.ReportExt.al b/Apps/CZ/AdvancePaymentsLocalization/app/Src/ReportExtensions/SuggestWorksheetLinesCZZ.ReportExt.al index 7f7cee7cbc..0ee4bbec37 100644 --- a/Apps/CZ/AdvancePaymentsLocalization/app/Src/ReportExtensions/SuggestWorksheetLinesCZZ.ReportExt.al +++ b/Apps/CZ/AdvancePaymentsLocalization/app/Src/ReportExtensions/SuggestWorksheetLinesCZZ.ReportExt.al @@ -6,8 +6,10 @@ namespace Microsoft.Finance.AdvancePayments; using Microsoft.CashFlow.Setup; using Microsoft.CashFlow.Worksheet; +using Microsoft.Purchases.Document; using Microsoft.Purchases.Vendor; using Microsoft.Sales.Customer; +using Microsoft.Sales.Document; reportextension 31001 "Suggest Worksheet Lines CZZ" extends "Suggest Worksheet Lines" { @@ -87,13 +89,13 @@ reportextension 31001 "Suggest Worksheet Lines CZZ" extends "Suggest Worksheet L trigger OnAfterAfterGetRecord() var TempAdvanceLetterApplication: Record "Advance Letter Application CZZ" temporary; + SalesHeader: Record "Sales Header"; begin if not TempCFWorksheetLine.Find() then exit; - if "Document Type" = "Document Type"::Order then - AdvanceLetterApplication.GetAssignedAdvance("Adv. Letter Usage Doc.Type CZZ"::"Sales Order", "Document No.", TempAdvanceLetterApplication) - else - AdvanceLetterApplication.GetAssignedAdvance("Adv. Letter Usage Doc.Type CZZ"::"Sales Invoice", "Document No.", TempAdvanceLetterApplication); + SalesHeader."Document Type" := "Document Type"; + AdvanceLetterApplication.GetAssignedAdvance( + SalesHeader.GetAdvLetterUsageDocTypeCZZ(), "Document No.", TempAdvanceLetterApplication); TempAdvanceLetterApplication.CalcSums("Amount (LCY)"); TempCFWorksheetLine."Amount (LCY)" -= TempAdvanceLetterApplication."Amount (LCY)"; if TempCFWorksheetLine."Amount (LCY)" = 0 then @@ -107,13 +109,12 @@ reportextension 31001 "Suggest Worksheet Lines CZZ" extends "Suggest Worksheet L trigger OnAfterAfterGetRecord() var TempAdvanceLetterApplication: Record "Advance Letter Application CZZ" temporary; + PurchaseHeader: Record "Purchase Header"; begin if not TempCFWorksheetLine.Find() then exit; - if "Document Type" = "Document Type"::Order then - AdvanceLetterApplication.GetAssignedAdvance("Adv. Letter Usage Doc.Type CZZ"::"Purchase Order", "Document No.", TempAdvanceLetterApplication) - else - AdvanceLetterApplication.GetAssignedAdvance("Adv. Letter Usage Doc.Type CZZ"::"Purchase Invoice", "Document No.", TempAdvanceLetterApplication); + PurchaseHeader."Document Type" := "Document Type"; + AdvanceLetterApplication.GetAssignedAdvance(PurchaseHeader.GetAdvLetterUsageDocTypeCZZ(), "Document No.", TempAdvanceLetterApplication); TempAdvanceLetterApplication.CalcSums("Amount (LCY)"); TempCFWorksheetLine."Amount (LCY)" += TempAdvanceLetterApplication."Amount (LCY)"; if TempCFWorksheetLine."Amount (LCY)" = 0 then diff --git a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Reports/PurchAdvLettersRecap.xlsx b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Reports/PurchAdvLettersRecap.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..2cdd7d210b8dc58c6a6e305020c438a52569417d GIT binary patch literal 36652 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

jRvGV?1tv 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%0D1o}(zRcy>c5!A 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 literal 0 HcmV?d00001 diff --git a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Reports/PurchAdvLettersRecapCZZ.Report.al b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Reports/PurchAdvLettersRecapCZZ.Report.al index 537620a481..613d3bf5d6 100644 --- a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Reports/PurchAdvLettersRecapCZZ.Report.al +++ b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Reports/PurchAdvLettersRecapCZZ.Report.al @@ -12,8 +12,7 @@ report 31027 "Purch. Adv. Letters Recap. CZZ" UsageCategory = ReportsAndAnalysis; ApplicationArea = Basic, Suite; Caption = 'Purch. Advance Letters Recapitulation'; - DefaultLayout = RDLC; - RDLCLayout = './Src/Reports/PurchAdvLettersRecap.rdl'; + DefaultRenderingLayout = "PurchAdvLettersRecap.rdl"; dataset { @@ -154,6 +153,24 @@ report 31027 "Purch. Adv. Letters Recap. CZZ" end; } + rendering + { + layout("PurchAdvLettersRecap.rdl") + { + Type = RDLC; + LayoutFile = './Src/Reports/PurchAdvLettersRecap.rdl'; + Caption = 'Purchase Advance Letters Recapitulation (RDL)'; + Summary = 'The Purchase Advance Letters Recapitulation (RDL) provides a detailed layout.'; + } + layout("PurchAdvLettersRecap.xlsx") + { + Type = Excel; + LayoutFile = './Src/Reports/PurchAdvLettersRecap.xlsx'; + Caption = 'Purchase Advance Letters Recapitulation (Excel)'; + Summary = 'The Purchase Advance Letters Recapitulation (Excel) provides a detailed layout.'; + } + } + labels { ReportLbl = 'Purchase Advance Letters Recapitulation'; diff --git a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Reports/PurchAdvanceLetters.xlsx b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Reports/PurchAdvanceLetters.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..045db7bd5bb947c152cede5293e066171984d502 GIT binary patch literal 37826 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 literal 0 HcmV?d00001 diff --git a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Reports/PurchAdvanceLettersCZZ.Report.al b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Reports/PurchAdvanceLettersCZZ.Report.al index d10a84d5b3..f0eec26a43 100644 --- a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Reports/PurchAdvanceLettersCZZ.Report.al +++ b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Reports/PurchAdvanceLettersCZZ.Report.al @@ -12,8 +12,7 @@ report 31024 "Purch. Advance Letters CZZ" UsageCategory = ReportsAndAnalysis; ApplicationArea = Basic, Suite; Caption = 'Purchase Advance Letters'; - DefaultLayout = RDLC; - RDLCLayout = './Src/Reports/PurchAdvanceLetters.rdl'; + DefaultRenderingLayout = "PurchAdvanceLetters.rdl"; dataset { @@ -315,6 +314,24 @@ report 31024 "Purch. Advance Letters CZZ" end; } + rendering + { + layout("PurchAdvanceLetters.rdl") + { + Type = RDLC; + LayoutFile = './Src/Reports/PurchAdvanceLetters.rdl'; + Caption = 'Purchase Advance Letters (RDL)'; + Summary = 'The Purchase Advance Letters (RDL) provides a detailed layout.'; + } + layout("PurchAdvanceLetters.xlsx") + { + Type = Excel; + LayoutFile = './Src/Reports/PurchAdvanceLetters.xlsx'; + Caption = 'Purchase Advance Letters (Excel)'; + Summary = 'The Purchase Advance Letters (Excel) provides a detailed layout.'; + } + } + labels { ReportLbl = 'Purchase Advance Letters'; diff --git a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Reports/PurchaseAdvanceLetterCZZ.Report.al b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Reports/PurchaseAdvanceLetterCZZ.Report.al index f7ba641cc5..a97e057169 100644 --- a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Reports/PurchaseAdvanceLetterCZZ.Report.al +++ b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Reports/PurchaseAdvanceLetterCZZ.Report.al @@ -336,17 +336,10 @@ report 31016 "Purchase - Advance Letter CZZ" } var - PaymentTerms: Record "Payment Terms"; - PaymentMethod: Record "Payment Method"; LanguageMgt: Codeunit Language; FormatAddress: Codeunit "Format Address"; FormatDocument: Codeunit "Format Document"; FormatDocumentMgtCZL: Codeunit "Format Document Mgt. CZL"; - CompanyAddr: array[8] of Text[100]; - VendAddr: array[8] of Text[100]; - DocFooterText: Text[1000]; - NoOfCop: Integer; - CopyNo: Integer; NoOfLoops: Integer; DocumentLbl: Label 'Advance Letter'; PageLbl: Label 'Page'; @@ -359,6 +352,15 @@ report 31016 "Purchase - Advance Letter CZZ" TotalLbl: Label 'total'; CreatorLbl: Label 'Posted by'; + protected var + PaymentTerms: Record "Payment Terms"; + PaymentMethod: Record "Payment Method"; + CompanyAddr: array[8] of Text[100]; + VendAddr: array[8] of Text[100]; + DocFooterText: Text[1000]; + CopyNo: Integer; + NoOfCop: Integer; + local procedure FormatDocumentFields(PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ") begin FormatDocument.SetPaymentTerms(PaymentTerms, PurchAdvLetterHeaderCZZ."Payment Terms Code", PurchAdvLetterHeaderCZZ."Language Code"); diff --git a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Reports/PurchaseAdvanceVATDocCZZ.Report.al b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Reports/PurchaseAdvanceVATDocCZZ.Report.al index bd7ffed523..75da1ca0b2 100644 --- a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Reports/PurchaseAdvanceVATDocCZZ.Report.al +++ b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Reports/PurchaseAdvanceVATDocCZZ.Report.al @@ -453,23 +453,11 @@ report 31017 "Purchase - Advance VAT Doc.CZZ" } var - TempVATAmountLine: Record "VAT Amount Line" temporary; - PaymentTerms: Record "Payment Terms"; - PaymentMethod: Record "Payment Method"; CurrencyExchangeRate: Record "Currency Exchange Rate"; DocumentFooterCZL: Record "Document Footer CZL"; LanguageMgt: Codeunit Language; FormatAddress: Codeunit "Format Address"; - ExchRateText: Text[50]; - CompanyAddr: array[8] of Text[100]; - VendAddr: array[8] of Text[100]; - DocFooterText: Text[1000]; - DocumentLabel: Text; - CalculatedExchRate: Decimal; - NoOfCop: Integer; - CopyNo: Integer; NoOfLoops: Integer; - OriginalAdvanceVATDocumentNo: Code[20]; Text009Txt: Label 'Exchange Rate %1 %2 / %3 %4', Comment = '%1=calculatedexchrate;%2=general ledger setup.LCY Code;%3=currexchrate.exchange rate amount;%4=currency code'; DocumentLbl: Label 'VAT Document to Paid Payment'; CrMemoDocumentLbl: Label 'VAT Credit Memo to Paid Payment'; @@ -488,6 +476,20 @@ report 31017 "Purchase - Advance VAT Doc.CZZ" AdvanceLetterLbl: Label 'VAT Document to Advance Letter'; OriginalAdvanceVATDocumentNoLbl: Label 'Original Advance VAT Document No.'; + protected var + PaymentTerms: Record "Payment Terms"; + PaymentMethod: Record "Payment Method"; + TempVATAmountLine: Record "VAT Amount Line" temporary; + CompanyAddr: array[8] of Text[100]; + VendAddr: array[8] of Text[100]; + ExchRateText: Text[50]; + DocFooterText: Text[1000]; + OriginalAdvanceVATDocumentNo: Code[20]; + DocumentLabel: Text; + CalculatedExchRate: Decimal; + CopyNo: Integer; + NoOfCop: Integer; + local procedure IsCreditMemo(PurchAdvLetterEntryCZZ: Record "Purch. Adv. Letter Entry CZZ"): Boolean begin exit(((PurchAdvLetterEntryCZZ.CalcDocumentAmount() < 0) and (PurchAdvLetterEntryCZZ."Entry Type" = PurchAdvLetterEntryCZZ."Entry Type"::"VAT Payment")) or diff --git a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Reports/PurchaseInvoicewithAdvCZZ.Report.al b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Reports/PurchaseInvoicewithAdvCZZ.Report.al index bbec8ed234..97de61978b 100644 --- a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Reports/PurchaseInvoicewithAdvCZZ.Report.al +++ b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Reports/PurchaseInvoicewithAdvCZZ.Report.al @@ -931,10 +931,7 @@ report 31028 "Purchase-Invoice with Adv. CZZ" var GeneralLedgerSetup: Record "General Ledger Setup"; CompanyInformation: Record "Company Information"; - ShipmentMethod: Record "Shipment Method"; - PaymentTerms: Record "Payment Terms"; SalespersonPurchaser: Record "Salesperson/Purchaser"; - TempVATAmountLine: Record "VAT Amount Line" temporary; DimensionSetEntry1: Record "Dimension Set Entry"; DimensionSetEntry2: Record "Dimension Set Entry"; ResponsibilityCenter: Record "Responsibility Center"; @@ -946,43 +943,11 @@ report 31028 "Purchase-Invoice with Adv. CZZ" FormatAddress: Codeunit "Format Address"; FormatDocument: Codeunit "Format Document"; SegManagement: Codeunit SegManagement; - VendAddr: array[8] of Text[100]; - ShipToAddr: array[8] of Text[100]; - CompanyAddr: array[8] of Text[100]; - PurchaserText: Text[50]; - VATNoText: Text[80]; - ReferenceText: Text[80]; - OrderNoText: Text[80]; - TotalText: Text[50]; - TotalInclVATText: Text[50]; - TotalExclVATText: Text[50]; MoreLines: Boolean; - NoOfCops: Integer; - NoOfLoops: Integer; - CopyText: Text[30]; - DimText: Text[120]; OldDimText: Text[120]; - ShowInterInfo: Boolean; Continue: Boolean; - LogInter: Boolean; - VALVATBaseLCY: Decimal; - VALVATAmountLCY: Decimal; - VALSpecLCYHeader: Text[80]; - VALExchRate: Text[50]; - CalculatedExchRate: Decimal; - OutputNo: Integer; - PricesInclVATtxt: Text[30]; - AllowVATDisctxt: Text[30]; - VATAmountText: Text[30]; - PurchInLineTypeNo: Integer; LogInteractionEnable: Boolean; - TotalSubTotal: Decimal; - TotalAmount: Decimal; - TotalAmountInclVAT: Decimal; - TotalAmountVAT: Decimal; - TotalInvoiceDiscountAmount: Decimal; - TotalPaymentDiscountOnVAT: Decimal; - PrepaymentAmt: Decimal; + NoOfLoops: Integer; ReportLbl: Label 'Purchase - Invoice %1', Comment = '%1 = Document No.'; Report2Lbl: Label 'Purchase - Prepayment Invoice %1', Comment = '%1 = Document No.'; VATAmtSpecificationLbl: Label 'VAT Amount Specification in '; @@ -1033,6 +998,43 @@ report 31028 "Purchase-Invoice with Adv. CZZ" PaymentsLbl: Label 'Payments List'; PrepayedLbl: Label 'Prepayed Advances'; + protected var + PaymentTerms: Record "Payment Terms"; + ShipmentMethod: Record "Shipment Method"; + TempVATAmountLine: Record "VAT Amount Line" temporary; + CompanyAddr: array[8] of Text[100]; + ShipToAddr: array[8] of Text[100]; + VendAddr: array[8] of Text[100]; + AllowVATDisctxt: Text[30]; + CopyText: Text[30]; + DimText: Text[120]; + OrderNoText: Text[80]; + PricesInclVATtxt: Text[30]; + PurchaserText: Text[50]; + ReferenceText: Text[80]; + TotalText: Text[50]; + TotalInclVATText: Text[50]; + TotalExclVATText: Text[50]; + VALSpecLCYHeader: Text[80]; + VALExchRate: Text[50]; + VATAmountText: Text[30]; + VATNoText: Text[80]; + NoOfCops: Integer; + OutputNo: Integer; + PurchInLineTypeNo: Integer; + LogInter: Boolean; + ShowInterInfo: Boolean; + CalculatedExchRate: Decimal; + PrepaymentAmt: Decimal; + TotalAmount: Decimal; + TotalAmountInclVAT: Decimal; + TotalAmountVAT: Decimal; + TotalInvoiceDiscountAmount: Decimal; + TotalPaymentDiscountOnVAT: Decimal; + TotalSubTotal: Decimal; + VALVATBaseLCY: Decimal; + VALVATAmountLCY: Decimal; + local procedure DocumentCaption(): Text[250] begin if "Purch. Inv. Header"."Prepayment Invoice" then diff --git a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Reports/SalesAdvLettersRecap.xlsx b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Reports/SalesAdvLettersRecap.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..32925fdedae53acad1ce40ace614cb305472c17c GIT binary patch literal 45574 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%0A!kAL*DFNztP7HLSMU`CnZ*q}hPWYkoMZT=90Z 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 E1<;WJUjP6A literal 0 HcmV?d00001 diff --git a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Reports/SalesAdvLettersRecapCZZ.Report.al b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Reports/SalesAdvLettersRecapCZZ.Report.al index 03ea58122d..5f34d65862 100644 --- a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Reports/SalesAdvLettersRecapCZZ.Report.al +++ b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Reports/SalesAdvLettersRecapCZZ.Report.al @@ -12,8 +12,7 @@ report 31026 "Sales Adv. Letters Recap. CZZ" UsageCategory = ReportsAndAnalysis; ApplicationArea = Basic, Suite; Caption = 'Sales Advance Letters Recapitulation'; - DefaultLayout = RDLC; - RDLCLayout = './Src/Reports/SalesAdvLettersRecap.rdl'; + DefaultRenderingLayout = "SalesAdvLettersRecap.rdl"; dataset { @@ -154,6 +153,24 @@ report 31026 "Sales Adv. Letters Recap. CZZ" end; } + rendering + { + layout("SalesAdvLettersRecap.rdl") + { + Type = RDLC; + LayoutFile = './Src/Reports/SalesAdvLettersRecap.rdl'; + Caption = 'Sales Advance Letters Recapitulation (RDL)'; + Summary = 'The Sales Advance Letters Recapitulation (RDL) provides a detailed layout.'; + } + layout("SalesAdvLettersRecap.xlsx") + { + Type = Excel; + LayoutFile = './Src/Reports/SalesAdvLettersRecap.xlsx'; + Caption = 'Sales Advance Letters Recapitulation (Excel)'; + Summary = 'The Sales Advance Letters Recapitulation (Excel) provides a detailed layout.'; + } + } + labels { ReportLbl = 'Sales Advance Letters Recapitulation'; diff --git a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Reports/SalesAdvanceLetter.rdl b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Reports/SalesAdvanceLetter.rdl index e19f75eeba..eceeed0c2c 100644 --- a/Apps/CZ/AdvancePaymentsLocalization/app/Src/Reports/SalesAdvanceLetter.rdl +++ b/Apps/CZ/AdvancePaymentsLocalization/app/Src/Reports/SalesAdvanceLetter.rdl @@ -24,7 +24,7 @@ - 4.57135in + 5.99843in @@ -2609,8 +2609,8 @@ Cstr(Fields!PageLbl.Value) - 11.16122cm - 11.99999cm + 14.69038cm + 11.99995cm 0.45001cm 6.00001cm 2 @@ -2620,6 +2620,74 @@ Cstr(Fields!PageLbl.Value) + + true + + + + + =Fields!QRPaymentCode.Value + + + + + + + true + true + + + + + =Fields!QRPaymentLbl.Value + + + + + + 2pt + 2pt + 2pt + 2pt + + true + true @@ -2665,7 +2734,7 @@ Cstr(Fields!PageLbl.Value) 0.00001cm - 4.57135in + 5.99843in 17.99999cm - 11.61123cm + 15.23602cm @@ -2861,6 +2930,7 @@ Cstr(Fields!PageLbl.Value) + + true + + + + + =Fields!QRPaymentCode.Value + + + + + + + true + true + + + + + =Fields!QRPaymentLbl.Value + + + + + + 2pt + 2pt + 2pt + 2pt + + true - 0.63414in - 0.22539in + 0.5647in + 0.23608in 0.423cm 7.78066cm 1 @@ -83,6 +84,7 @@ + true true @@ -102,7 +104,7 @@ 0.30529in 4.08589in - 0.8cm + 0.65889cm 7.78066cm 2 - 0.81317in + 0.74373in 0.22539in 0.423cm 7.78066cm @@ -152,7 +154,7 @@ - 0.99221in + 0.92277in 0.22539in 0.423cm 7.78066cm @@ -178,8 +180,8 @@ - 0.63414in - 4.08589in + 0.5647in + 4.08582in 0.423cm 7.78066cm 5 @@ -204,8 +206,8 @@ - 0.81317in - 4.08589in + 0.74373in + 4.08582in 0.423cm 7.78066cm 6 @@ -230,8 +232,8 @@ - 0.99221in - 4.08589in + 0.92277in + 4.08582in 0.423cm 7.78066cm 7 @@ -962,24 +964,24 @@ - 1.22788in + 3.11882cm - 1.22788in + 3.11882cm - 2.01098in + 5.10789cm - 1.2285in + 3.12039cm - 1.2285in + 3.12039cm - 0.16654in + 0.42301cm @@ -1099,7 +1101,7 @@ - 0.16654in + 0.42301cm @@ -1206,7 +1208,7 @@ - 0.16654in + 0.42301cm @@ -1404,7 +1406,7 @@ - 0.16654in + 0.42301cm @@ -1607,8 +1609,8 @@ DataSet_Result 9.62552cm 0.5733cm - 1.69205cm - 17.5863cm + 1.69204cm + 17.58631cm 35 - 22.62542cm + 22.62543cm + + true + + + + + =Fields!QRPaymentCode.Value + + + + + + + true + true + + + + + =Fields!QRPaymentLbl.Value + + + + + + 2pt + 2pt + 2pt + 2pt + + true @@ -5173,12 +5242,12 @@ Cstr(Fields!PageLbl.Value) - 18.31686cm + 20.65378cm - 18.00001cm + 18.00008cm 2.2cm @@ -5204,6 +5273,7 @@ Cstr(Fields!PageLbl.Value) 0.8cm + 0.00005cm 0.5cm 17.99999cm - 1.3cm + 1.33528cm + 0.00005cm 0.5cm 18cm 1 @@ -5267,6 +5338,7 @@ Cstr(Fields!PageLbl.Value) + 0.00005cm 0.8cm 18cm 2 @@ -5285,6 +5357,7 @@ Cstr(Fields!PageLbl.Value) =IIf(Code.GetData(3,1)=1,First(Fields!Picture_CompanyInformation.Value, "DataSet_Result"),"") image/bmp FitProportional + 0.00005cm 14mm 60mm 3 @@ -5302,7 +5375,7 @@ Cstr(Fields!PageLbl.Value) =IIf(Code.GetData(3,1)=2,First(Fields!Picture_CompanyInformation.Value, "DataSet_Result"),"") image/bmp FitProportional - 6cm + 6.00005cm 14mm 60mm 4 @@ -5320,7 +5393,7 @@ Cstr(Fields!PageLbl.Value) =IIf(Code.GetData(3,1)=3,First(Fields!Picture_CompanyInformation.Value, "DataSet_Result"),"") image/bmp FitProportional - 12cm + 12.00005cm 14mm 60mm 5 @@ -5341,7 +5414,7 @@ Cstr(Fields!PageLbl.Value) - 1.77002cm + 0.67639cm true true @@ -5360,7 +5433,7 @@ Cstr(Fields!PageLbl.Value) - 1.26999cm + 0.17639cm 12cm 0.5cm 6cm @@ -5664,6 +5737,9 @@ End Function DocumentNoLbl + + QRPaymentLbl + No_SalesInvoiceHeader @@ -5826,6 +5902,9 @@ End Function ShipToAddr6 + + QRPaymentCode + CopyNo diff --git a/Apps/CZ/CoreLocalizationPack/app/Src/Reports/SalesInvoiceCZL.Report.al b/Apps/CZ/CoreLocalizationPack/app/Src/Reports/SalesInvoiceCZL.Report.al index 254041237d..5b6e39e207 100644 --- a/Apps/CZ/CoreLocalizationPack/app/Src/Reports/SalesInvoiceCZL.Report.al +++ b/Apps/CZ/CoreLocalizationPack/app/Src/Reports/SalesInvoiceCZL.Report.al @@ -28,6 +28,7 @@ using System.Email; using System.Globalization; using System.Security.User; using System.Utilities; +using System.Text; report 31189 "Sales Invoice CZL" { @@ -188,6 +189,9 @@ report 31189 "Sales Invoice CZL" column(DocumentNoLbl; DocumentNoLbl) { } + column(QRPaymentLbl; QRPaymentLbl) + { + } column(No_SalesInvoiceHeader; "No.") { } @@ -341,6 +345,9 @@ report 31189 "Sales Invoice CZL" column(ShipToAddr6; ShipToAddr[6]) { } + column(QRPaymentCode; QRPaymentCode) + { + } dataitem(CopyLoop; "Integer") { DataItemTableView = sorting(Number); @@ -632,6 +639,12 @@ report 31189 "Sales Invoice CZL" "VAT Reporting Date" := "VAT Date CZL"; #pragma warning restore AL0432 #endif + Clear(QRPaymentCode); + if "Sales & Receivables Setup"."Print QR Payment CZL" and PaymentMethod."Print QR Payment CZL" then begin + CalcFields("Remaining Amount"); + if "Remaining Amount" <> 0 then + GenerateQRPaymentCode(); + end; end; } } @@ -686,13 +699,8 @@ report 31189 "Sales Invoice CZL" end; var - TempVATAmountLine: Record "VAT Amount Line" temporary; TempLineFeeNoteonReportHist: Record "Line Fee Note on Report Hist." temporary; Customer: Record Customer; - PaymentTerms: Record "Payment Terms"; - PaymentMethod: Record "Payment Method"; - ShipmentMethod: Record "Shipment Method"; - ReasonCode: Record "Reason Code"; Currency: Record Currency; CurrencyExchangeRate: Record "Currency Exchange Rate"; VATClause: Record "VAT Clause"; @@ -706,20 +714,8 @@ report 31189 "Sales Invoice CZL" #pragma warning restore AL0432 #endif SegManagement: Codeunit SegManagement; - ExchRateText: Text[50]; - VATClauseText: Text; - CompanyAddr: array[8] of Text[100]; - CustAddr: array[8] of Text[100]; - ShipToAddr: array[8] of Text[100]; - DocFooterText: Text[1000]; - PaymentSymbol: array[2] of Text; - PaymentSymbolLabel: array[2] of Text; + LogInteractionEnable: Boolean; DocumentLbl: Label 'Invoice'; - CalculatedExchRate: Decimal; - UnitPriceExclVAT: Decimal; - NoOfCopies: Integer; - NoOfLoops: Integer; - LogInteraction: Boolean; ExchRateLbl: Label 'Exchange Rate %1 %2 / %3 %4', Comment = '%1 = Calculated Exchange Rate, %2 = LCY Code, %3 = Exchange Rate, %4 = Currency Code'; PageLbl: Label 'Page'; CopyLbl: Label 'Copy'; @@ -750,8 +746,29 @@ report 31189 "Sales Invoice CZL" ClosingLbl: Label 'Sincerely'; BodyLbl: Label 'Thank you for your business. Your invoice is attached to this message.'; DocumentNoLbl: Label 'No.'; - LogInteractionEnable: Boolean; + QRPaymentLbl: Label 'QR Payment'; + + protected var + PaymentTerms: Record "Payment Terms"; + PaymentMethod: Record "Payment Method"; + ReasonCode: Record "Reason Code"; + ShipmentMethod: Record "Shipment Method"; + TempVATAmountLine: Record "VAT Amount Line" temporary; + CompanyAddr: array[8] of Text[100]; + CustAddr: array[8] of Text[100]; + ShipToAddr: array[8] of Text[100]; + PaymentSymbol: array[2] of Text; + PaymentSymbolLabel: array[2] of Text; + DocFooterText: Text[1000]; + ExchRateText: Text[50]; + VATClauseText: Text; + QRPaymentCode: Text; + CalculatedExchRate: Decimal; + UnitPriceExclVAT: Decimal; + NoOfCopies: Integer; + NoOfLoops: Integer; DisplayAdditionalFeeNote: Boolean; + LogInteraction: Boolean; procedure InitLogInteraction() begin @@ -820,4 +837,16 @@ report 31189 "Sales Invoice CZL" begin exit(CurrReport.Preview or MailManagement.IsHandlingGetEmailBody()); end; + + local procedure GenerateQRPaymentCode() + var + BarcodeSymbology2D: Enum "Barcode Symbology 2D"; + BarcodeFontProvider2D: Interface "Barcode Font Provider 2D"; + BarcodeString: Text; + begin + BarcodeFontProvider2D := Enum::"Barcode Font Provider 2D"::IDAutomation2D; + BarcodeSymbology2D := Enum::"Barcode Symbology 2D"::"QR-Code"; + BarcodeString := "Sales Invoice Header".CreateSalesInvoicePaymentQRCodeStringCZL(); + QRPaymentCode := BarcodeFontProvider2D.EncodeFont(BarcodeString, BarcodeSymbology2D); + end; } diff --git a/Apps/CZ/CoreLocalizationPack/app/Src/Reports/SalesOrderConfirmationCZL.Report.al b/Apps/CZ/CoreLocalizationPack/app/Src/Reports/SalesOrderConfirmationCZL.Report.al index dfa906cf08..b3f3c4db7c 100644 --- a/Apps/CZ/CoreLocalizationPack/app/Src/Reports/SalesOrderConfirmationCZL.Report.al +++ b/Apps/CZ/CoreLocalizationPack/app/Src/Reports/SalesOrderConfirmationCZL.Report.al @@ -533,9 +533,6 @@ report 31187 "Sales Order Confirmation CZL" end; var - PaymentTerms: Record "Payment Terms"; - PaymentMethod: Record "Payment Method"; - ShipmentMethod: Record "Shipment Method"; TempSalesLine: Record "Sales Line" temporary; LanguageMgt: Codeunit Language; FormatAddress: Codeunit "Format Address"; @@ -543,14 +540,6 @@ report 31187 "Sales Order Confirmation CZL" FormatDocumentMgtCZL: Codeunit "Format Document Mgt. CZL"; SegManagement: Codeunit SegManagement; ArchiveManagement: Codeunit ArchiveManagement; - CompanyAddr: array[8] of Text[100]; - CustAddr: array[8] of Text[100]; - ShipToAddr: array[8] of Text[100]; - DocFooterText: Text[1000]; - NoOfCopies: Integer; - NoOfLoops: Integer; - LogInteraction: Boolean; - ArchiveDocument: Boolean; LogInteractionEnable: Boolean; DocumentLbl: Label 'Order Confirmation'; PageLbl: Label 'Page'; @@ -573,6 +562,19 @@ report 31187 "Sales Order Confirmation CZL" BodyLbl: Label 'Thank you for your business. Your order confirmation is attached to this message.'; DocumentNoLbl: Label 'No.'; + protected var + PaymentTerms: Record "Payment Terms"; + PaymentMethod: Record "Payment Method"; + ShipmentMethod: Record "Shipment Method"; + CompanyAddr: array[8] of Text[100]; + CustAddr: array[8] of Text[100]; + ShipToAddr: array[8] of Text[100]; + DocFooterText: Text[1000]; + NoOfCopies: Integer; + NoOfLoops: Integer; + ArchiveDocument: Boolean; + LogInteraction: Boolean; + procedure InitializeRequest(NoOfCopiesFrom: Integer; ArchiveDocumentFrom: Boolean; LogInteractionFrom: Boolean) begin NoOfCopies := NoOfCopiesFrom; diff --git a/Apps/CZ/CoreLocalizationPack/app/Src/Reports/SalesQuoteCZL.Report.al b/Apps/CZ/CoreLocalizationPack/app/Src/Reports/SalesQuoteCZL.Report.al index 4e2a9c1e2b..1387b17e94 100644 --- a/Apps/CZ/CoreLocalizationPack/app/Src/Reports/SalesQuoteCZL.Report.al +++ b/Apps/CZ/CoreLocalizationPack/app/Src/Reports/SalesQuoteCZL.Report.al @@ -504,9 +504,6 @@ report 31186 "Sales Quote CZL" end; var - PaymentTerms: Record "Payment Terms"; - PaymentMethod: Record "Payment Method"; - ShipmentMethod: Record "Shipment Method"; SalesReceivablesSetup: Record "Sales & Receivables Setup"; LanguageMgt: Codeunit Language; FormatAddress: Codeunit "Format Address"; @@ -514,14 +511,6 @@ report 31186 "Sales Quote CZL" FormatDocumentMgtCZL: Codeunit "Format Document Mgt. CZL"; SegManagement: Codeunit SegManagement; ArchiveManagement: Codeunit ArchiveManagement; - CompanyAddr: array[8] of Text[100]; - CustAddr: array[8] of Text[100]; - ShipToAddr: array[8] of Text[100]; - DocFooterText: Text[1000]; - NoOfCopies: Integer; - NoOfLoops: Integer; - LogInteraction: Boolean; - ArchiveDocument: Boolean; LogInteractionEnable: Boolean; DocumentLbl: Label 'Quote'; PageLbl: Label 'Page'; @@ -545,6 +534,19 @@ report 31186 "Sales Quote CZL" BodyLbl: Label 'Thank you for your business. Your quote is attached to this message.'; DocumentNoLbl: Label 'No.'; + protected var + PaymentTerms: Record "Payment Terms"; + PaymentMethod: Record "Payment Method"; + ShipmentMethod: Record "Shipment Method"; + CompanyAddr: array[8] of Text[100]; + CustAddr: array[8] of Text[100]; + ShipToAddr: array[8] of Text[100]; + DocFooterText: Text[1000]; + NoOfCopies: Integer; + NoOfLoops: Integer; + ArchiveDocument: Boolean; + LogInteraction: Boolean; + procedure InitializeRequest(NoOfCopiesFrom: Integer; ArchiveDocumentFrom: Boolean; LogInteractionFrom: Boolean) begin NoOfCopies := NoOfCopiesFrom; diff --git a/Apps/CZ/CoreLocalizationPack/app/Src/Reports/SalesReturnOrderConfirmCZL.Report.al b/Apps/CZ/CoreLocalizationPack/app/Src/Reports/SalesReturnOrderConfirmCZL.Report.al index de84620e81..6fe4d361a9 100644 --- a/Apps/CZ/CoreLocalizationPack/app/Src/Reports/SalesReturnOrderConfirmCZL.Report.al +++ b/Apps/CZ/CoreLocalizationPack/app/Src/Reports/SalesReturnOrderConfirmCZL.Report.al @@ -467,22 +467,11 @@ report 31188 "Sales Return Order Confirm CZL" end; var - PaymentTerms: Record "Payment Terms"; - PaymentMethod: Record "Payment Method"; - ShipmentMethod: Record "Shipment Method"; - TempSalesLine: Record "Sales Line" temporary; LanguageMgt: Codeunit Language; FormatAddress: Codeunit "Format Address"; FormatDocument: Codeunit "Format Document"; FormatDocumentMgtCZL: Codeunit "Format Document Mgt. CZL"; SegManagement: Codeunit SegManagement; - CompanyAddr: array[8] of Text[100]; - CustAddr: array[8] of Text[100]; - ShipToAddr: array[8] of Text[100]; - DocFooterText: Text[1000]; - NoOfCopies: Integer; - NoOfLoops: Integer; - LogInteraction: Boolean; LogInteractionEnable: Boolean; DocumentLbl: Label 'Return Order Confirmation'; PageLbl: Label 'Page'; @@ -501,6 +490,19 @@ report 31188 "Sales Return Order Confirm CZL" TotalLbl: Label 'total'; VATLbl: Label 'VAT'; + protected var + PaymentTerms: Record "Payment Terms"; + PaymentMethod: Record "Payment Method"; + ShipmentMethod: Record "Shipment Method"; + TempSalesLine: Record "Sales Line" temporary; + CompanyAddr: array[8] of Text[100]; + CustAddr: array[8] of Text[100]; + ShipToAddr: array[8] of Text[100]; + DocFooterText: Text[1000]; + NoOfCopies: Integer; + NoOfLoops: Integer; + LogInteraction: Boolean; + procedure InitLogInteraction() begin LogInteraction := SegManagement.FindInteractionTemplateCode(Enum::"Interaction Log Entry Document Type"::"Sales Return Order") <> ''; diff --git a/Apps/CZ/CoreLocalizationPack/app/Src/Reports/SalesReturnRecieptCZL.Report.al b/Apps/CZ/CoreLocalizationPack/app/Src/Reports/SalesReturnRecieptCZL.Report.al index 6fac02190d..8a4c447458 100644 --- a/Apps/CZ/CoreLocalizationPack/app/Src/Reports/SalesReturnRecieptCZL.Report.al +++ b/Apps/CZ/CoreLocalizationPack/app/Src/Reports/SalesReturnRecieptCZL.Report.al @@ -372,21 +372,12 @@ report 31192 "Sales Return Reciept CZL" end; var - ShipmentMethod: Record "Shipment Method"; LanguageMgt: Codeunit Language; FormatAddress: Codeunit "Format Address"; FormatDocument: Codeunit "Format Document"; FormatDocumentMgtCZL: Codeunit "Format Document Mgt. CZL"; SegManagement: Codeunit SegManagement; - CompanyAddr: array[8] of Text[100]; - CustAddr: array[8] of Text[100]; - ShipToAddr: array[8] of Text[100]; - DocFooterText: Text[1000]; - NoOfCopies: Integer; - NoOfLoops: Integer; - LogInteraction: Boolean; LogInteractionEnable: Boolean; - ShowLotSN: Boolean; DocumentLbl: Label 'Return Receipt'; PageLbl: Label 'Page'; CopyLbl: Label 'Copy'; @@ -404,6 +395,17 @@ report 31192 "Sales Return Reciept CZL" TotalLbl: Label 'total'; VATLbl: Label 'VAT'; + protected var + ShipmentMethod: Record "Shipment Method"; + CompanyAddr: array[8] of Text[100]; + CustAddr: array[8] of Text[100]; + ShipToAddr: array[8] of Text[100]; + DocFooterText: Text[1000]; + NoOfCopies: Integer; + NoOfLoops: Integer; + LogInteraction: Boolean; + ShowLotSN: Boolean; + procedure InitLogInteraction() begin LogInteraction := SegManagement.FindInteractionTemplateCode(Enum::"Interaction Log Entry Document Type"::"Sales Return Receipt") <> ''; diff --git a/Apps/CZ/CoreLocalizationPack/app/Src/Reports/SalesShipmentCZL.Report.al b/Apps/CZ/CoreLocalizationPack/app/Src/Reports/SalesShipmentCZL.Report.al index 2e8ac88564..8b08c1ed09 100644 --- a/Apps/CZ/CoreLocalizationPack/app/Src/Reports/SalesShipmentCZL.Report.al +++ b/Apps/CZ/CoreLocalizationPack/app/Src/Reports/SalesShipmentCZL.Report.al @@ -496,8 +496,6 @@ report 31191 "Sales Shipment CZL" end; var - ShipmentMethod: Record "Shipment Method"; - TempTrackingSpecification: Record "Tracking Specification" temporary; ItemTrackingAppendix: Report "Item Tracking Appendix"; LanguageMgt: Codeunit Language; FormatAddress: Codeunit "Format Address"; @@ -505,22 +503,9 @@ report 31191 "Sales Shipment CZL" FormatDocumentMgtCZL: Codeunit "Format Document Mgt. CZL"; SegManagement: Codeunit SegManagement; ItemTrackingDocManagement: Codeunit "Item Tracking Doc. Management"; - CompanyAddr: array[8] of Text[100]; - CustAddr: array[8] of Text[100]; - ShipToAddr: array[8] of Text[100]; - DocFooterText: Text[1000]; - NoOfCopies: Integer; - NoOfLoops: Integer; OldRefNo: Integer; OldNo: Code[20]; - LogInteraction: Boolean; - ShowCorrectionLines: Boolean; LogInteractionEnable: Boolean; - ShowLotSN: Boolean; - ShowTotal: Boolean; - ShowGroup: Boolean; - TotalQty: Decimal; - TrackingSpecCount: Integer; DocumentLbl: Label 'Shipment'; PageLbl: Label 'Page'; CopyLbl: Label 'Copy'; @@ -544,6 +529,23 @@ report 31191 "Sales Shipment CZL" NoCaptionLbl: Label 'No.'; ExpirationDateLbl: Label 'Expiration Date'; + protected var + ShipmentMethod: Record "Shipment Method"; + TempTrackingSpecification: Record "Tracking Specification" temporary; + CompanyAddr: array[8] of Text[100]; + CustAddr: array[8] of Text[100]; + ShipToAddr: array[8] of Text[100]; + DocFooterText: Text[1000]; + NoOfCopies: Integer; + NoOfLoops: Integer; + TrackingSpecCount: Integer; + LogInteraction: Boolean; + ShowCorrectionLines: Boolean; + ShowGroup: Boolean; + ShowLotSN: Boolean; + ShowTotal: Boolean; + TotalQty: Decimal; + procedure InitLogInteraction() begin LogInteraction := SegManagement.FindInteractionTemplateCode(Enum::"Interaction Log Entry Document Type"::"Sales Shpt. Note") <> ''; diff --git a/Apps/CZ/CoreLocalizationPack/app/Src/Reports/ServiceContractCZL.Report.al b/Apps/CZ/CoreLocalizationPack/app/Src/Reports/ServiceContractCZL.Report.al index 7f4ea7b333..c504dddbf9 100644 --- a/Apps/CZ/CoreLocalizationPack/app/Src/Reports/ServiceContractCZL.Report.al +++ b/Apps/CZ/CoreLocalizationPack/app/Src/Reports/ServiceContractCZL.Report.al @@ -405,13 +405,6 @@ report 31196 "Service Contract CZL" FormatAddress: Codeunit "Format Address"; FormatDocumentMgtCZL: Codeunit "Format Document Mgt. CZL"; SegManagement: Codeunit SegManagement; - CompanyAddr: array[8] of Text[100]; - CustAddr: array[8] of Text[100]; - ShipToAddr: array[8] of Text[100]; - DocFooterText: Text[1000]; - NoOfCopies: Integer; - NoOfLoops: Integer; - LogInteraction: Boolean; LogInteractionEnable: Boolean; DocumentLbl: Label 'Service Contract'; PageLbl: Label 'Page'; @@ -424,6 +417,15 @@ report 31196 "Service Contract CZL" VATRegistrationNoLbl: Label 'VAT Registration No.'; RegistrationNoLbl: Label 'Registration No.'; + protected var + CompanyAddr: array[8] of Text[100]; + CustAddr: array[8] of Text[100]; + ShipToAddr: array[8] of Text[100]; + DocFooterText: Text[1000]; + NoOfCopies: Integer; + NoOfLoops: Integer; + LogInteraction: Boolean; + procedure InitializeRequest(NoOfCopiesFrom: Integer; LogInteractionFrom: Boolean) begin NoOfCopies := NoOfCopiesFrom; diff --git a/Apps/CZ/CoreLocalizationPack/app/Src/Reports/ServiceContractQuoteCZL.Report.al b/Apps/CZ/CoreLocalizationPack/app/Src/Reports/ServiceContractQuoteCZL.Report.al index ba64dd16ba..2bc11dec25 100644 --- a/Apps/CZ/CoreLocalizationPack/app/Src/Reports/ServiceContractQuoteCZL.Report.al +++ b/Apps/CZ/CoreLocalizationPack/app/Src/Reports/ServiceContractQuoteCZL.Report.al @@ -406,13 +406,6 @@ report 31195 "Service Contract Quote CZL" FormatAddress: Codeunit "Format Address"; FormatDocumentMgtCZL: Codeunit "Format Document Mgt. CZL"; SegManagement: Codeunit SegManagement; - CompanyAddr: array[8] of Text[100]; - CustAddr: array[8] of Text[100]; - ShipToAddr: array[8] of Text[100]; - DocFooterText: Text[1000]; - NoOfCopies: Integer; - NoOfLoops: Integer; - LogInteraction: Boolean; LogInteractionEnable: Boolean; DocumentLbl: Label 'Service Contract Quote'; PageLbl: Label 'Page'; @@ -425,6 +418,15 @@ report 31195 "Service Contract Quote CZL" VATRegistrationNoLbl: Label 'VAT Registration No.'; RegistrationNoLbl: Label 'Registration No.'; + protected var + CompanyAddr: array[8] of Text[100]; + CustAddr: array[8] of Text[100]; + ShipToAddr: array[8] of Text[100]; + DocFooterText: Text[1000]; + NoOfCopies: Integer; + NoOfLoops: Integer; + LogInteraction: Boolean; + procedure InitializeRequest(NoOfCopiesFrom: Integer; LogInteractionFrom: Boolean) begin NoOfCopies := NoOfCopiesFrom; diff --git a/Apps/CZ/CoreLocalizationPack/app/Src/Reports/ServiceCreditMemoCZL.Report.al b/Apps/CZ/CoreLocalizationPack/app/Src/Reports/ServiceCreditMemoCZL.Report.al index 8009eb5ca3..8286db386f 100644 --- a/Apps/CZ/CoreLocalizationPack/app/Src/Reports/ServiceCreditMemoCZL.Report.al +++ b/Apps/CZ/CoreLocalizationPack/app/Src/Reports/ServiceCreditMemoCZL.Report.al @@ -549,11 +549,7 @@ report 31198 "Service Credit Memo CZL" } } var - TempVATAmountLine: Record "VAT Amount Line" temporary; Customer: Record Customer; - PaymentTerms: Record "Payment Terms"; - PaymentMethod: Record "Payment Method"; - ReasonCode: Record "Reason Code"; CurrencyExchangeRate: Record "Currency Exchange Rate"; VATClause: Record "VAT Clause"; LanguageMgt: Codeunit Language; @@ -565,19 +561,7 @@ report 31198 "Service Credit Memo CZL" ReplaceVATDateMgtCZL: Codeunit "Replace VAT Date Mgt. CZL"; #pragma warning restore AL0432 #endif - ExchRateText: Text[50]; - VATClauseText: Text; - CompanyAddr: array[8] of Text[100]; - CustAddr: array[8] of Text[100]; - ShipToAddr: array[8] of Text[100]; - DocFooterText: Text[1000]; - PaymentSymbol: array[2] of Text; - PaymentSymbolLabel: array[2] of Text; - CalculatedExchRate: Decimal; - NoOfCopies: Integer; - NoOfLoops: Integer; ExchRateLbl: Label 'Exchange Rate %1 %2 / %3 %4', Comment = '%1 = Calculated Exchange Rate, %2 = LCY Code, %3 = Exchange Rate, %4 = Currency Code'; - DocumentLbl: Text; CorrectiveTaxDocumentLbl: Label 'Service - Corrective Tax Document'; InternalCorrectionLbl: Label 'Service - Internal Correction'; InsolvencyTaxDocumentLbl: Label 'Service - Insolvency Tax Document'; @@ -601,6 +585,24 @@ report 31198 "Service Credit Memo CZL" TotalLbl: Label 'total'; VATLbl: Label 'VAT'; + protected var + PaymentTerms: Record "Payment Terms"; + PaymentMethod: Record "Payment Method"; + ReasonCode: Record "Reason Code"; + TempVATAmountLine: Record "VAT Amount Line" temporary; + CompanyAddr: array[8] of Text[100]; + CustAddr: array[8] of Text[100]; + ShipToAddr: array[8] of Text[100]; + PaymentSymbol: array[2] of Text; + PaymentSymbolLabel: array[2] of Text; + ExchRateText: Text[50]; + DocFooterText: Text[1000]; + DocumentLbl: Text; + VATClauseText: Text; + CalculatedExchRate: Decimal; + NoOfCopies: Integer; + NoOfLoops: Integer; + local procedure FormatDocumentFields(ServiceCrMemoHeader: Record "Service Cr.Memo Header") begin FormatDocument.SetPaymentTerms(PaymentTerms, ServiceCrMemoHeader."Payment Terms Code", ServiceCrMemoHeader."Language Code"); diff --git a/Apps/CZ/CoreLocalizationPack/app/Src/Reports/ServiceInvoice.rdl b/Apps/CZ/CoreLocalizationPack/app/Src/Reports/ServiceInvoice.rdl index 303dc31ed9..477dc3bf51 100644 --- a/Apps/CZ/CoreLocalizationPack/app/Src/Reports/ServiceInvoice.rdl +++ b/Apps/CZ/CoreLocalizationPack/app/Src/Reports/ServiceInvoice.rdl @@ -24,7 +24,7 @@ - 7.30278in + 7.89653in @@ -2636,6 +2636,7 @@ Cstr(Fields!PageLbl.Value) DataSet_Result + 0.00002in 10.85022cm 17.99996cm + + true + + + + + =Fields!QRPaymentCode.Value + + + + + + + true + true + + + + + =Fields!QRPaymentLbl.Value + + + + + + 2pt + 2pt + 2pt + 2pt + + true + true @@ -5125,7 +5198,7 @@ Cstr(Fields!PageLbl.Value) - 7.30278in + 7.89653in 18.00001cm - 18.54906cm + 20.26885cm - 18.00001cm + 18.00005cm 2.2cm @@ -5302,7 +5375,7 @@ Cstr(Fields!PageLbl.Value) - 1.77002cm + 1.00272cm true true @@ -5321,8 +5394,8 @@ Cstr(Fields!PageLbl.Value) - 1.26999cm - 12cm + 0.5027cm + 12.00005cm 0.5cm 6cm 1 @@ -5602,6 +5675,9 @@ End Function PaymentsLbl + + QRPaymentLbl + DisplayAdditionalFeeNote @@ -5746,6 +5822,9 @@ End Function ShipToAddr6 + + QRPaymentCode + CopyNo diff --git a/Apps/CZ/CoreLocalizationPack/app/Src/Reports/ServiceInvoiceCZL.Report.al b/Apps/CZ/CoreLocalizationPack/app/Src/Reports/ServiceInvoiceCZL.Report.al index 411c0f1abb..5cb828ca0c 100644 --- a/Apps/CZ/CoreLocalizationPack/app/Src/Reports/ServiceInvoiceCZL.Report.al +++ b/Apps/CZ/CoreLocalizationPack/app/Src/Reports/ServiceInvoiceCZL.Report.al @@ -18,12 +18,14 @@ using Microsoft.Sales.Customer; using Microsoft.Sales.Receivables; using Microsoft.Sales.Reminder; using Microsoft.Service.Setup; +using Microsoft.Sales.Setup; using System.Email; using System.Globalization; using System.Security.User; using System.Utilities; using Microsoft.CRM.Team; using Microsoft.Utilities; +using System.Text; report 31197 "Service Invoice CZL" { @@ -84,6 +86,8 @@ report 31197 "Service Invoice CZL" trigger OnAfterGetRecord() begin FormatAddress.Company(CompanyAddr, "Company Information"); + if not SalesReceivablesSetup.Get() then + SalesReceivablesSetup.Init(); end; } dataitem("Service Invoice Header"; "Service Invoice Header") @@ -148,6 +152,9 @@ report 31197 "Service Invoice CZL" column(PaymentsLbl; PaymentsLbl) { } + column(QRPaymentLbl; QRPaymentLbl) + { + } column(DisplayAdditionalFeeNote; DisplayAdditionalFeeNote) { } @@ -289,6 +296,9 @@ report 31197 "Service Invoice CZL" column(ShipToAddr6; ShipToAddr[6]) { } + column(QRPaymentCode; QRPaymentCode) + { + } dataitem(CopyLoop; "Integer") { DataItemTableView = sorting(Number); @@ -541,6 +551,9 @@ report 31197 "Service Invoice CZL" "VAT Reporting Date" := "VAT Date CZL"; #pragma warning restore AL0432 #endif + Clear(QRPaymentCode); + if SalesReceivablesSetup."Print QR Payment CZL" and PaymentMethod."Print QR Payment CZL" then + GenerateQRPaymentCode(); end; } } @@ -573,14 +586,10 @@ report 31197 "Service Invoice CZL" } var - TempVATAmountLine: Record "VAT Amount Line" temporary; - TempLineFeeNoteonReportHist: Record "Line Fee Note on Report Hist." temporary; Customer: Record Customer; - PaymentTerms: Record "Payment Terms"; - PaymentMethod: Record "Payment Method"; - ReasonCode: Record "Reason Code"; CurrencyExchangeRate: Record "Currency Exchange Rate"; VATClause: Record "VAT Clause"; + SalesReceivablesSetup: Record "Sales & Receivables Setup"; LanguageMgt: Codeunit Language; FormatAddress: Codeunit "Format Address"; FormatDocument: Codeunit "Format Document"; @@ -590,19 +599,7 @@ report 31197 "Service Invoice CZL" ReplaceVATDateMgtCZL: Codeunit "Replace VAT Date Mgt. CZL"; #pragma warning restore AL0432 #endif - ExchRateText: Text[50]; - VATClauseText: Text; - CompanyAddr: array[8] of Text[100]; - CustAddr: array[8] of Text[100]; - ShipToAddr: array[8] of Text[100]; - DocFooterText: Text[1000]; - PaymentSymbol: array[2] of Text; - PaymentSymbolLabel: array[2] of Text; DocumentLbl: Label 'Invoice'; - CalculatedExchRate: Decimal; - NoOfCopies: Integer; - NoOfLoops: Integer; - DisplayAdditionalFeeNote: Boolean; OrderNoLbl: Label 'Order No.'; ExchRateLbl: Label 'Exchange Rate %1 %2 / %3 %4', Comment = '%1 = Calculated Exchange Rate, %2 = LCY Code, %3 = Exchange Rate, %4 = Currency Code'; PageLbl: Label 'Page'; @@ -624,6 +621,27 @@ report 31197 "Service Invoice CZL" TotalLbl: Label 'total'; VATLbl: Label 'VAT'; PaymentsLbl: Label 'Payments List'; + QRPaymentLbl: Label 'QR Payment'; + + protected var + PaymentTerms: Record "Payment Terms"; + PaymentMethod: Record "Payment Method"; + ReasonCode: Record "Reason Code"; + TempLineFeeNoteonReportHist: Record "Line Fee Note on Report Hist." temporary; + TempVATAmountLine: Record "VAT Amount Line" temporary; + CompanyAddr: array[8] of Text[100]; + CustAddr: array[8] of Text[100]; + ShipToAddr: array[8] of Text[100]; + PaymentSymbol: array[2] of Text; + PaymentSymbolLabel: array[2] of Text; + DocFooterText: Text[1000]; + ExchRateText: Text[50]; + VATClauseText: Text; + CalculatedExchRate: Decimal; + NoOfCopies: Integer; + NoOfLoops: Integer; + DisplayAdditionalFeeNote: Boolean; + QRPaymentCode: Text; local procedure GetLineFeeNoteOnReportHist(ServiceInvoiceHeaderNo: Code[20]) var @@ -686,4 +704,16 @@ report 31197 "Service Invoice CZL" begin exit(CurrReport.Preview or MailManagement.IsHandlingGetEmailBody()); end; + + local procedure GenerateQRPaymentCode() + var + BarcodeSymbology2D: Enum "Barcode Symbology 2D"; + BarcodeFontProvider2D: Interface "Barcode Font Provider 2D"; + BarcodeString: Text; + begin + BarcodeFontProvider2D := Enum::"Barcode Font Provider 2D"::IDAutomation2D; + BarcodeSymbology2D := Enum::"Barcode Symbology 2D"::"QR-Code"; + BarcodeString := "Service Invoice Header".CreateServiceInvoicePaymentQRCodeStringCZL(); + QRPaymentCode := BarcodeFontProvider2D.EncodeFont(BarcodeString, BarcodeSymbology2D); + end; } diff --git a/Apps/CZ/CoreLocalizationPack/app/Src/Reports/ServiceOrderCZL.Report.al b/Apps/CZ/CoreLocalizationPack/app/Src/Reports/ServiceOrderCZL.Report.al index a9b3af863c..73104acab9 100644 --- a/Apps/CZ/CoreLocalizationPack/app/Src/Reports/ServiceOrderCZL.Report.al +++ b/Apps/CZ/CoreLocalizationPack/app/Src/Reports/ServiceOrderCZL.Report.al @@ -503,21 +503,10 @@ report 31194 "Service Order CZL" } var - PaymentTerms: Record "Payment Terms"; - PaymentMethod: Record "Payment Method"; - ShipmentMethod: Record "Shipment Method"; LanguageMgt: Codeunit Language; FormatAddress: Codeunit "Format Address"; FormatDocument: Codeunit "Format Document"; FormatDocumentMgtCZL: Codeunit "Format Document Mgt. CZL"; - CompanyAddr: array[8] of Text[100]; - CustAddr: array[8] of Text[100]; - ShipToAddr: array[8] of Text[100]; - DocFooterText: Text[1000]; - NoOfCopies: Integer; - NoOfLoops: Integer; - Number1: Integer; - Number2: Integer; DocumentLbl: Label 'Service Order'; PageLbl: Label 'Page'; CopyLbl: Label 'Copy'; @@ -537,6 +526,19 @@ report 31194 "Service Order CZL" GrossAmountLbl: Label 'Gross Amount'; TotalLbl: Label 'Total'; + protected var + PaymentTerms: Record "Payment Terms"; + PaymentMethod: Record "Payment Method"; + ShipmentMethod: Record "Shipment Method"; + CompanyAddr: array[8] of Text[100]; + CustAddr: array[8] of Text[100]; + ShipToAddr: array[8] of Text[100]; + DocFooterText: Text[1000]; + NoOfCopies: Integer; + NoOfLoops: Integer; + Number1: Integer; + Number2: Integer; + procedure InitializeRequest(NoOfCopiesFrom: Integer) begin NoOfCopies := NoOfCopiesFrom; diff --git a/Apps/CZ/CoreLocalizationPack/app/Src/Reports/ServiceQuoteCZL.Report.al b/Apps/CZ/CoreLocalizationPack/app/Src/Reports/ServiceQuoteCZL.Report.al index df355e788a..c35c37ba10 100644 --- a/Apps/CZ/CoreLocalizationPack/app/Src/Reports/ServiceQuoteCZL.Report.al +++ b/Apps/CZ/CoreLocalizationPack/app/Src/Reports/ServiceQuoteCZL.Report.al @@ -512,23 +512,11 @@ report 31193 "Service Quote CZL" end; var - PaymentTerms: Record "Payment Terms"; - PaymentMethod: Record "Payment Method"; - ShipmentMethod: Record "Shipment Method"; LanguageMgt: Codeunit Language; FormatAddress: Codeunit "Format Address"; FormatDocument: Codeunit "Format Document"; FormatDocumentMgtCZL: Codeunit "Format Document Mgt. CZL"; SegManagement: Codeunit SegManagement; - CompanyAddr: array[8] of Text[100]; - CustAddr: array[8] of Text[100]; - ShipToAddr: array[8] of Text[100]; - DocFooterText: Text[1000]; - NoOfCopies: Integer; - NoOfLoops: Integer; - Number1: Integer; - Number2: Integer; - LogInteraction: Boolean; LogInteractionEnable: Boolean; DocumentLbl: Label 'Service Quote'; PageLbl: Label 'Page'; @@ -549,6 +537,20 @@ report 31193 "Service Quote CZL" GrossAmountLbl: Label 'Gross Amount'; TotalLbl: Label 'Total'; + protected var + PaymentTerms: Record "Payment Terms"; + PaymentMethod: Record "Payment Method"; + ShipmentMethod: Record "Shipment Method"; + CompanyAddr: array[8] of Text[100]; + CustAddr: array[8] of Text[100]; + ShipToAddr: array[8] of Text[100]; + DocFooterText: Text[1000]; + NoOfCopies: Integer; + NoOfLoops: Integer; + Number1: Integer; + Number2: Integer; + LogInteraction: Boolean; + procedure InitializeRequest(NoOfCopiesFrom: Integer; LogInteractionFrom: Boolean) begin NoOfCopies := NoOfCopiesFrom; diff --git a/Apps/CZ/CoreLocalizationPack/app/Src/Reports/ServiceShipmentCZL.Report.al b/Apps/CZ/CoreLocalizationPack/app/Src/Reports/ServiceShipmentCZL.Report.al index 27208ca6d2..66c572d978 100644 --- a/Apps/CZ/CoreLocalizationPack/app/Src/Reports/ServiceShipmentCZL.Report.al +++ b/Apps/CZ/CoreLocalizationPack/app/Src/Reports/ServiceShipmentCZL.Report.al @@ -452,19 +452,10 @@ report 31199 "Service Shipment CZL" } var - TempTrackingSpecification: Record "Tracking Specification" temporary; LanguageMgt: Codeunit Language; FormatAddress: Codeunit "Format Address"; FormatDocumentMgtCZL: Codeunit "Format Document Mgt. CZL"; ItemTrackingDocManagement: Codeunit "Item Tracking Doc. Management"; - CompanyAddr: array[8] of Text[100]; - CustAddr: array[8] of Text[100]; - ShipToAddr: array[8] of Text[100]; - DocFooterText: Text[1000]; - NoOfCopies: Integer; - NoOfLoops: Integer; - ShowLotSN: Boolean; - TrackingSpecCount: Integer; DocumentLbl: Label 'Shipment'; PageLbl: Label 'Page'; CopyLbl: Label 'Copy'; @@ -482,6 +473,17 @@ report 31199 "Service Shipment CZL" VATLbl: Label 'VAT'; OrderNoLbl: Label 'Order No.'; + protected var + TempTrackingSpecification: Record "Tracking Specification" temporary; + CompanyAddr: array[8] of Text[100]; + CustAddr: array[8] of Text[100]; + ShipToAddr: array[8] of Text[100]; + DocFooterText: Text[1000]; + NoOfCopies: Integer; + NoOfLoops: Integer; + ShowLotSN: Boolean; + TrackingSpecCount: Integer; + local procedure IsReportInPreviewMode(): Boolean var MailManagement: Codeunit "Mail Management"; diff --git a/Apps/CZ/CoreLocalizationPack/app/Src/Reports/VendorBalReconciliation.rdl b/Apps/CZ/CoreLocalizationPack/app/Src/Reports/VendorBalReconciliation.rdl index e9b8816312..32bfddaf25 100644 --- a/Apps/CZ/CoreLocalizationPack/app/Src/Reports/VendorBalReconciliation.rdl +++ b/Apps/CZ/CoreLocalizationPack/app/Src/Reports/VendorBalReconciliation.rdl @@ -31,6 +31,7 @@ + true true @@ -50,7 +51,7 @@ 0.30529in 0.22521in - 0.8cm + 0.65889cm 7.78066cm - 0.63414in + 0.5647in 0.22521in 0.423cm 7.78066cm @@ -83,6 +84,7 @@ + true true @@ -102,7 +104,7 @@ 0.30529in 4.08571in - 0.8cm + 0.65889cm 7.78066cm 2 - 0.81317in + 0.74373in 0.22521in 0.423cm 7.78066cm @@ -152,7 +154,7 @@ - 0.99221in + 0.92277in 0.22521in 0.423cm 7.78066cm @@ -178,8 +180,8 @@ - 0.63414in - 4.08571in + 0.5647in + 4.08538in 0.423cm 7.78066cm 5 @@ -204,8 +206,8 @@ - 0.81317in - 4.08571in + 0.74373in + 4.08538in 0.423cm 7.78066cm 6 @@ -230,8 +232,8 @@ - 0.99221in - 4.08571in + 0.92277in + 4.08538in 0.423cm 7.78066cm 7 diff --git a/Apps/CZ/CoreLocalizationPack/app/Src/Reports/VendorBalReconciliationCZL.Report.al b/Apps/CZ/CoreLocalizationPack/app/Src/Reports/VendorBalReconciliationCZL.Report.al index b5e3d41c25..817d4fd4bc 100644 --- a/Apps/CZ/CoreLocalizationPack/app/Src/Reports/VendorBalReconciliationCZL.Report.al +++ b/Apps/CZ/CoreLocalizationPack/app/Src/Reports/VendorBalReconciliationCZL.Report.al @@ -582,7 +582,7 @@ report 11724 "Vendor-Bal. Reconciliation CZL" FormattedEmployee := Employee.FullName(); AddFieldInfoToCommaSeparatedText(Employee.FieldCaption("Phone No."), Employee."Phone No.", FormattedEmployee); - AddFieldInfoToCommaSeparatedText(Employee.FieldCaption("E-Mail"), Employee."E-Mail", FormattedEmployee); + AddFieldInfoToCommaSeparatedText(Employee.FieldCaption("E-Mail"), Employee."Company E-Mail", FormattedEmployee); if FormattedEmployee <> '' then FormattedEmployee := StrSubstNo(ResponsibleEmployeeLbl, FormattedEmployee); diff --git a/Apps/CZ/CoreLocalizationPack/app/Src/TableExtensions/CustLedgerEntryCZL.TableExt.al b/Apps/CZ/CoreLocalizationPack/app/Src/TableExtensions/CustLedgerEntryCZL.TableExt.al index bc22aad7cb..981ca193bd 100644 --- a/Apps/CZ/CoreLocalizationPack/app/Src/TableExtensions/CustLedgerEntryCZL.TableExt.al +++ b/Apps/CZ/CoreLocalizationPack/app/Src/TableExtensions/CustLedgerEntryCZL.TableExt.al @@ -126,18 +126,32 @@ tableextension 11720 "Cust. Ledger Entry CZL" extends "Cust. Ledger Entry" OnAfterUpdateBankInfoCZL(Rec); end; + procedure CollectSuggestedApplicationCZL(var CrossApplicationBufferCZL: Record "Cross Application Buffer CZL"): Boolean + var + CrossApplicationMgtCZL: Codeunit "Cross Application Mgt. CZL"; + begin + exit(CrossApplicationMgtCZL.CollectSuggestedApplication(Rec, CrossApplicationBufferCZL)); + end; + + procedure CollectSuggestedApplicationCZL(CalledFrom: Variant; var CrossApplicationBufferCZL: Record "Cross Application Buffer CZL"): Boolean + var + CrossApplicationMgtCZL: Codeunit "Cross Application Mgt. CZL"; + begin + exit(CrossApplicationMgtCZL.CollectSuggestedApplication(Rec, CalledFrom, CrossApplicationBufferCZL)); + end; + procedure CalcSuggestedAmountToApplyCZL(): Decimal var CrossApplicationMgtCZL: Codeunit "Cross Application Mgt. CZL"; begin - exit(CrossApplicationMgtCZL.CalcSuggestedAmountToApplyCustLedgerEntry(Rec)); + exit(CrossApplicationMgtCZL.CalcSuggestedAmountToApply(Rec)); end; procedure DrillDownSuggestedAmountToApplyCZL() var CrossApplicationMgtCZL: Codeunit "Cross Application Mgt. CZL"; begin - CrossApplicationMgtCZL.DrillDownSuggestedAmountToApplyCustLedgerEntry(Rec); + CrossApplicationMgtCZL.DrillDownSuggestedAmountToApply(Rec); end; procedure RelatedToAdvanceLetterCZL() IsRelatedToAdvanceLetter: Boolean diff --git a/Apps/CZ/CoreLocalizationPack/app/Src/TableExtensions/EmployeeLedgerEntryCZL.TableExt.al b/Apps/CZ/CoreLocalizationPack/app/Src/TableExtensions/EmployeeLedgerEntryCZL.TableExt.al index c85f50f1c5..00c37b76fd 100644 --- a/Apps/CZ/CoreLocalizationPack/app/Src/TableExtensions/EmployeeLedgerEntryCZL.TableExt.al +++ b/Apps/CZ/CoreLocalizationPack/app/Src/TableExtensions/EmployeeLedgerEntryCZL.TableExt.al @@ -32,17 +32,31 @@ tableextension 11790 "Employee Ledger Entry CZL" extends "Employee Ledger Entry" } } + procedure CollectSuggestedApplicationCZL(var CrossApplicationBufferCZL: Record "Cross Application Buffer CZL"): Boolean + var + CrossApplicationMgtCZL: Codeunit "Cross Application Mgt. CZL"; + begin + exit(CrossApplicationMgtCZL.CollectSuggestedApplication(Rec, CrossApplicationBufferCZL)); + end; + + procedure CollectSuggestedApplicationCZL(CalledFrom: Variant; var CrossApplicationBufferCZL: Record "Cross Application Buffer CZL"): Boolean + var + CrossApplicationMgtCZL: Codeunit "Cross Application Mgt. CZL"; + begin + exit(CrossApplicationMgtCZL.CollectSuggestedApplication(Rec, CalledFrom, CrossApplicationBufferCZL)); + end; + procedure CalcSuggestedAmountToApplyCZL(): Decimal var CrossApplicationMgtCZL: Codeunit "Cross Application Mgt. CZL"; begin - exit(CrossApplicationMgtCZL.CalcSuggestedAmountToApplyEmployeeLedgerEntry(Rec)); + exit(CrossApplicationMgtCZL.CalcSuggestedAmountToApply(Rec)); end; procedure DrillDownSuggestedAmountToApplyCZL() var CrossApplicationMgtCZL: Codeunit "Cross Application Mgt. CZL"; begin - CrossApplicationMgtCZL.DrillDownSuggestedAmountToApplyEmployeeLedgerEntry(Rec); + CrossApplicationMgtCZL.DrillDownSuggestedAmountToApply(Rec); end; } diff --git a/Apps/CZ/CoreLocalizationPack/app/Src/TableExtensions/IntrastatJnlBatchCZL.TableExt.al b/Apps/CZ/CoreLocalizationPack/app/Src/TableExtensions/IntrastatJnlBatchCZL.TableExt.al index a31ec4fd92..1dffd58e3a 100644 --- a/Apps/CZ/CoreLocalizationPack/app/Src/TableExtensions/IntrastatJnlBatchCZL.TableExt.al +++ b/Apps/CZ/CoreLocalizationPack/app/Src/TableExtensions/IntrastatJnlBatchCZL.TableExt.al @@ -118,12 +118,12 @@ tableextension 31025 "Intrastat Jnl. Batch CZL" extends "Intrastat Jnl. Batch" procedure AssistEditCZL(): Boolean var StatutoryReportingSetupCZL: Record "Statutory Reporting Setup CZL"; - NoSeriesManagement: Codeunit NoSeriesManagement; + NoSeries: Codeunit "No. Series"; begin if "Declaration No. CZL" = '' then begin StatutoryReportingSetupCZL.Get(); StatutoryReportingSetupCZL.TestField("Intrastat Declaration Nos."); - "Declaration No. CZL" := NoSeriesManagement.GetNextNo(StatutoryReportingSetupCZL."Intrastat Declaration Nos.", 0D, true); + "Declaration No. CZL" := NoSeries.GetNextNo(StatutoryReportingSetupCZL."Intrastat Declaration Nos."); exit(true); end; exit(false); diff --git a/Apps/CZ/CoreLocalizationPack/app/Src/TableExtensions/PaymentMethodCZL.TableExt.al b/Apps/CZ/CoreLocalizationPack/app/Src/TableExtensions/PaymentMethodCZL.TableExt.al new file mode 100644 index 0000000000..525f3fb119 --- /dev/null +++ b/Apps/CZ/CoreLocalizationPack/app/Src/TableExtensions/PaymentMethodCZL.TableExt.al @@ -0,0 +1,13 @@ +namespace Microsoft.Bank.BankAccount; + +tableextension 31058 "Payment Method CZL" extends "Payment Method" +{ + fields + { + field(11782; "Print QR Payment CZL"; Boolean) + { + Caption = 'Print QR payment'; + DataClassification = CustomerContent; + } + } +} diff --git a/Apps/CZ/CoreLocalizationPack/app/Src/TableExtensions/SalesHeaderCZL.TableExt.al b/Apps/CZ/CoreLocalizationPack/app/Src/TableExtensions/SalesHeaderCZL.TableExt.al index 01ace199b7..e74c78313b 100644 --- a/Apps/CZ/CoreLocalizationPack/app/Src/TableExtensions/SalesHeaderCZL.TableExt.al +++ b/Apps/CZ/CoreLocalizationPack/app/Src/TableExtensions/SalesHeaderCZL.TableExt.al @@ -10,14 +10,13 @@ using Microsoft.Finance.Currency; using Microsoft.Finance.VAT.Calculation; using Microsoft.Foundation.Address; using Microsoft.Foundation.BatchProcessing; -#if not CLEAN22 using Microsoft.Foundation.Company; -#endif using Microsoft.Sales.Customer; #if not CLEAN22 using System.Environment.Configuration; #endif using System.Utilities; +using Microsoft.Sales.Setup; tableextension 11703 "Sales Header CZL" extends "Sales Header" { @@ -511,6 +510,64 @@ tableextension 11703 "Sales Header CZL" extends "Sales Header" exit(ReplaceVATDateMgtCZL.IsEnabled()); end; #endif + procedure CheckPaymentQRCodePrintIBANCZL() + var + SalesReceivablesSetup: Record "Sales & Receivables Setup"; + PaymentMethod: Record "Payment Method"; + CompanyInformation: Record "Company Information"; + begin + if "Document Type" in ["Document Type"::"Blanket Order", "Document Type"::"Credit Memo", "Document Type"::Quote, "Document Type"::"Return Order"] then + exit; + + if "Payment Method Code" = '' then + exit; + + SalesReceivablesSetup.Get(); + + if not SalesReceivablesSetup."Print QR Payment CZL" then + exit; + + PaymentMethod.Get("Payment Method Code"); + if not PaymentMethod."Print QR Payment CZL" then + exit; + + if "Bank Account Code CZL" = '' then begin + CompanyInformation.Get(); + if CompanyInformation.IBAN <> '' then + exit; + end else + if "IBAN CZL" <> '' then + exit; + + ConfirmCheckPaymentQRCodePrintIBAN(); + end; + + local procedure ConfirmCheckPaymentQRCodePrintIBAN() + var + + EmptyIBANQst: Label 'Bank Account has empty IBAN, QR payment will not be printed on Sales document.\\Do you want to continue?'; + begin + ConfirmProcess(EmptyIBANQst); + end; + + local procedure ConfirmProcess(ConfirmQuestion: Text) + var + IsHandled: Boolean; + begin + OnBeforeConfirmProcessCZL(ConfirmQuestion, IsHandled); + if IsHandled then + exit; + if not IsConfirmDialogAllowedCZL() then + exit; + if not ConfirmManagement.GetResponse(ConfirmQuestion, false) then + Error(''); + end; + + local procedure IsConfirmDialogAllowedCZL() IsAllowed: Boolean + begin + IsAllowed := GuiAllowed(); + OnIsConfirmDialogAllowedCZL(IsAllowed); + end; [IntegrationEvent(false, false)] local procedure OnAfterUpdateBankInfoCZL(var SalesHeader: Record "Sales Header") @@ -551,4 +608,14 @@ tableextension 11703 "Sales Header CZL" extends "Sales Header" local procedure OnBeforeGetDefaulBankAccountNoCZL(var SalesHeader: Record "Sales Header"; var BankAccountNo: Code[20]; var IsHandled: Boolean); begin end; + + [IntegrationEvent(false, false)] + local procedure OnBeforeConfirmProcessCZL(ConfirmQuestion: Text; var IsHandled: Boolean); + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnIsConfirmDialogAllowedCZL(var IsAllowed: Boolean) + begin + end; } diff --git a/Apps/CZ/CoreLocalizationPack/app/Src/TableExtensions/SalesInvoiceHeaderCZL.TableExt.al b/Apps/CZ/CoreLocalizationPack/app/Src/TableExtensions/SalesInvoiceHeaderCZL.TableExt.al index dc05974f7b..c5eebae3cc 100644 --- a/Apps/CZ/CoreLocalizationPack/app/Src/TableExtensions/SalesInvoiceHeaderCZL.TableExt.al +++ b/Apps/CZ/CoreLocalizationPack/app/Src/TableExtensions/SalesInvoiceHeaderCZL.TableExt.al @@ -7,6 +7,8 @@ namespace Microsoft.Sales.History; using Microsoft.Bank.BankAccount; using Microsoft.Bank.Setup; using Microsoft.Finance.Currency; +using Microsoft.Finance.GeneralLedger.Setup; +using Microsoft.Foundation.Company; tableextension 11726 "Sales Invoice Header CZL" extends "Sales Invoice Header" { @@ -180,8 +182,73 @@ tableextension 11726 "Sales Invoice Header CZL" extends "Sales Invoice Header" OnAfterUpdateBankInfoCZL(Rec); end; + procedure CreateSalesInvoicePaymentQRCodeStringCZL(): Text + var + GeneralLedgerSetup: Record "General Ledger Setup"; + CompanyInformation: Record "Company Information"; + IBAN: Code[50]; + SWIFT: Code[20]; + QRCode: Text; + InvoiceTxt: Label 'Invoice'; + begin + if "Bank Account Code CZL" <> '' then begin + IBAN := "IBAN CZL"; + SWIFT := "SWIFT Code CZL"; + end else begin + CompanyInformation.Get(); + IBAN := CompanyInformation.IBAN; + SWIFT := CompanyInformation."SWIFT Code"; + if "IBAN CZL" <> '' then + IBAN := "IBAN CZL"; + if "SWIFT Code CZL" <> '' then + SWIFT := "SWIFT Code CZL"; + end; + + CalcFields("Remaining Amount"); + + QRCode := 'SPD*1.0*'; + + // ACC + if SWIFT <> '' then + QRCode := QRCode + 'ACC:' + IBAN + '+' + SWIFT + '*' + else + QRCode := QRCode + 'ACC:' + IBAN + '*'; + + // AM + QRCode := QRCode + 'AM:' + format("Remaining Amount", 0, '') + '*'; + + // CC + if "Currency Code" = '' then begin + GeneralLedgerSetup.Get(); + QRCode := QRCode + 'CC:' + UpperCase(GeneralLedgerSetup."LCY Code") + '*'; + end else + QRCode := QRCode + 'CC:' + UpperCase("Currency Code") + '*'; + + // DT + QRCode := QRCode + 'DT:' + format("Due Date", 0, '') + '*'; + + // MSG + QRCode := QRCode + 'MSG:' + InvoiceTxt + ' ' + "No." + '*'; + + // XVS + QRCode := QRCode + 'X-VS:' + "Variable Symbol CZL" + '*'; + + // X-KS + QRCode := QRCode + 'X-KS:' + "Constant Symbol CZL" + '*'; + + if IBAN = '' then + QRCode := ''; + OnBeforeExitSalesInvoicePaymentQRCodeStringCZL(Rec, QRCode); + exit(QRCode); + end; + [IntegrationEvent(false, false)] local procedure OnAfterUpdateBankInfoCZL(var SalesInvoiceHeader: Record "Sales Invoice Header") begin end; + + [IntegrationEvent(false, false)] + local procedure OnBeforeExitSalesInvoicePaymentQRCodeStringCZL(SalesInvoiceHeader: Record "Sales Invoice Header"; var QRCode: Text) + begin + end; } diff --git a/Apps/CZ/CoreLocalizationPack/app/Src/TableExtensions/SalesReceivablesSetupCZL.TableExt.al b/Apps/CZ/CoreLocalizationPack/app/Src/TableExtensions/SalesReceivablesSetupCZL.TableExt.al index 62e4f736d4..c163e2fbbe 100644 --- a/Apps/CZ/CoreLocalizationPack/app/Src/TableExtensions/SalesReceivablesSetupCZL.TableExt.al +++ b/Apps/CZ/CoreLocalizationPack/app/Src/TableExtensions/SalesReceivablesSetupCZL.TableExt.al @@ -5,6 +5,7 @@ namespace Microsoft.Sales.Setup; using Microsoft.Finance.VAT.Setup; +using System.Environment; tableextension 11714 "Sales & Receivables Setup CZL" extends "Sales & Receivables Setup" { @@ -40,5 +41,28 @@ tableextension 11714 "Sales & Receivables Setup CZL" extends "Sales & Receivable ObsoleteReason = 'It will be replaced by "Allow Multiple Posting Groups" field.'; } + field(11782; "Print QR Payment CZL"; Boolean) + { + Caption = 'Print QR payment'; + DataClassification = CustomerContent; + + trigger OnValidate() + begin + if "Print QR Payment CZL" then + CreatePrintQROnPremFontkNotification(); + end; + } } + local procedure CreatePrintQROnPremFontkNotification() + var + EnvironmentInformation: Codeunit "Environment Information"; + PrintQROnPremFontkNotification: Notification; + PrintQROnPremFontkNotificationLbl: Label 'To print the QR code for payments, it is necessary to have the IDAutomation2D font installed on the server.'; + begin + if not EnvironmentInformation.IsOnPrem() then + exit; + PrintQROnPremFontkNotification.Message := PrintQROnPremFontkNotificationLbl; + PrintQROnPremFontkNotification.Scope := NotificationScope::LocalScope; + PrintQROnPremFontkNotification.Send(); + end; } diff --git a/Apps/CZ/CoreLocalizationPack/app/Src/TableExtensions/ServiceHeaderCZL.TableExt.al b/Apps/CZ/CoreLocalizationPack/app/Src/TableExtensions/ServiceHeaderCZL.TableExt.al index f23e631a2c..1f118a06a9 100644 --- a/Apps/CZ/CoreLocalizationPack/app/Src/TableExtensions/ServiceHeaderCZL.TableExt.al +++ b/Apps/CZ/CoreLocalizationPack/app/Src/TableExtensions/ServiceHeaderCZL.TableExt.al @@ -12,6 +12,8 @@ using Microsoft.Foundation.Address; using Microsoft.Sales.Customer; using Microsoft.Sales.Document; using System.Utilities; +using Microsoft.Sales.Setup; +using Microsoft.Foundation.Company; tableextension 11734 "Service Header CZL" extends "Service Header" { @@ -387,6 +389,64 @@ tableextension 11734 "Service Header CZL" extends "Service Header" exit(ReplaceVATDateMgtCZL.IsEnabled()); end; #endif + procedure CheckPaymentQRCodePrintIBANCZL() + var + SalesReceivablesSetup: Record "Sales & Receivables Setup"; + PaymentMethod: Record "Payment Method"; + CompanyInformation: Record "Company Information"; + begin + if "Payment Method Code" = '' then + exit; + + if SalesReceivablesSetup.ReadPermission then + SalesReceivablesSetup.Get() + else + exit; + + if not SalesReceivablesSetup."Print QR Payment CZL" then + exit; + + PaymentMethod.Get("Payment Method Code"); + if not PaymentMethod."Print QR Payment CZL" then + exit; + + if "Bank Account Code CZL" = '' then begin + CompanyInformation.Get(); + if CompanyInformation.IBAN <> '' then + exit; + end else + if "IBAN CZL" <> '' then + exit; + + ConfirmCheckPaymentQRCodePrintIBAN(); + end; + + local procedure ConfirmCheckPaymentQRCodePrintIBAN() + var + + EmptyIBANQst: Label 'Bank Account has empty IBAN, QR payment will not be printed on Sales document.\\Do you want to continue?'; + begin + ConfirmProcess(EmptyIBANQst); + end; + + local procedure ConfirmProcess(ConfirmQuestion: Text) + var + IsHandled: Boolean; + begin + OnBeforeConfirmProcessCZL(ConfirmQuestion, IsHandled); + if IsHandled then + exit; + if not IsConfirmDialogAllowedCZL() then + exit; + if not ConfirmManagement.GetResponse(ConfirmQuestion, false) then + Error(''); + end; + + local procedure IsConfirmDialogAllowedCZL() IsAllowed: Boolean + begin + IsAllowed := GuiAllowed(); + OnIsConfirmDialogAllowedCZL(IsAllowed); + end; [IntegrationEvent(false, false)] local procedure OnAfterUpdateBankInfoCZL(var ServiceHeader: Record "Service Header") @@ -402,4 +462,14 @@ tableextension 11734 "Service Header CZL" extends "Service Header" local procedure OnBeforeIsIntrastatTransactionCZL(ServiceHeader: Record "Service Header"; var Result: Boolean; var IsHandled: Boolean) begin end; + + [IntegrationEvent(false, false)] + local procedure OnBeforeConfirmProcessCZL(ConfirmQuestion: Text; var IsHandled: Boolean); + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnIsConfirmDialogAllowedCZL(var IsAllowed: Boolean) + begin + end; } diff --git a/Apps/CZ/CoreLocalizationPack/app/Src/TableExtensions/ServiceInvoiceHeaderCZL.TableExt.al b/Apps/CZ/CoreLocalizationPack/app/Src/TableExtensions/ServiceInvoiceHeaderCZL.TableExt.al index cf2d8810b2..08262c5fe7 100644 --- a/Apps/CZ/CoreLocalizationPack/app/Src/TableExtensions/ServiceInvoiceHeaderCZL.TableExt.al +++ b/Apps/CZ/CoreLocalizationPack/app/Src/TableExtensions/ServiceInvoiceHeaderCZL.TableExt.al @@ -7,6 +7,8 @@ namespace Microsoft.Service.History; using Microsoft.Bank.BankAccount; using Microsoft.Bank.Setup; using Microsoft.Finance.Currency; +using Microsoft.Finance.GeneralLedger.Setup; +using Microsoft.Foundation.Company; tableextension 11735 "Service Invoice Header CZL" extends "Service Invoice Header" { @@ -180,8 +182,73 @@ tableextension 11735 "Service Invoice Header CZL" extends "Service Invoice Heade OnAfterUpdateBankInfoCZL(Rec); end; + procedure CreateServiceInvoicePaymentQRCodeStringCZL(): Text + var + GeneralLedgerSetup: Record "General Ledger Setup"; + CompanyInformation: Record "Company Information"; + IBAN: Code[50]; + SWIFT: Code[20]; + QRCode: Text; + InvoiceTxt: Label 'Invoice'; + begin + if "Bank Account Code CZL" <> '' then begin + IBAN := "IBAN CZL"; + SWIFT := "SWIFT Code CZL"; + end else begin + CompanyInformation.Get(); + IBAN := CompanyInformation.IBAN; + SWIFT := CompanyInformation."SWIFT Code"; + if "IBAN CZL" <> '' then + IBAN := "IBAN CZL"; + if "SWIFT Code CZL" <> '' then + SWIFT := "SWIFT Code CZL"; + end; + + CalcFields("Amount Including VAT"); + + QRCode := 'SPD*1.0*'; + + // ACC + if SWIFT <> '' then + QRCode := QRCode + 'ACC:' + IBAN + '+' + SWIFT + '*' + else + QRCode := QRCode + 'ACC:' + IBAN + '*'; + + // AM + QRCode := QRCode + 'AM:' + format("Amount Including VAT", 0, '') + '*'; + + // CC + if "Currency Code" = '' then begin + GeneralLedgerSetup.Get(); + QRCode := QRCode + 'CC:' + UpperCase(GeneralLedgerSetup."LCY Code") + '*'; + end else + QRCode := QRCode + 'CC:' + UpperCase("Currency Code") + '*'; + + // DT + QRCode := QRCode + 'DT:' + format("Due Date", 0, '') + '*'; + + // MSG + QRCode := QRCode + 'MSG:' + InvoiceTxt + ' ' + "No." + '*'; + + // XVS + QRCode := QRCode + 'X-VS:' + "Variable Symbol CZL" + '*'; + + // X-KS + QRCode := QRCode + 'X-KS:' + "Constant Symbol CZL" + '*'; + + if IBAN = '' then + QRCode := ''; + OnBeforeExitServiceInvoicePaymentQRCodeStringCZL(Rec, QRCode); + exit(QRCode); + end; + [IntegrationEvent(false, false)] local procedure OnAfterUpdateBankInfoCZL(var ServiceInvoiceHeader: Record "Service Invoice Header") begin end; + + [IntegrationEvent(false, false)] + local procedure OnBeforeExitServiceInvoicePaymentQRCodeStringCZL(ServiceInvoiceHeader: Record "Service Invoice Header"; var QRCode: Text) + begin + end; } diff --git a/Apps/CZ/CoreLocalizationPack/app/Src/TableExtensions/VATAmountLineCZL.TableExt.al b/Apps/CZ/CoreLocalizationPack/app/Src/TableExtensions/VATAmountLineCZL.TableExt.al index ce80a53dc2..c76fdaf90e 100644 --- a/Apps/CZ/CoreLocalizationPack/app/Src/TableExtensions/VATAmountLineCZL.TableExt.al +++ b/Apps/CZ/CoreLocalizationPack/app/Src/TableExtensions/VATAmountLineCZL.TableExt.al @@ -208,6 +208,7 @@ tableextension 11793 "VAT Amount Line CZL" extends "VAT Amount Line" VATEntry.SetRange("Document No.", DocumentNo); VATEntry.SetRange("Posting Date", PostingDate); VATEntry.SetRange("Source Code", SourceCode); + OnCopyDocumentVATEntriesToBufferOnAfterSetVATEntryFilterCZL(TransactionNo, DocumentType, DocumentNo, PostingDate, SourceCode, VATEntry); if VATEntry.FindSet() then repeat TempVATEntry := VATEntry; @@ -280,4 +281,9 @@ tableextension 11793 "VAT Amount Line CZL" extends "VAT Amount Line" local procedure OnAfterGetDocumentVATEntryBufferCZL(DocRecordRef: RecordRef; var TempVATEntry: Record "VAT Entry") begin end; + + [IntegrationEvent(false, false)] + local procedure OnCopyDocumentVATEntriesToBufferOnAfterSetVATEntryFilterCZL(TransactionNo: Integer; DocumentType: Enum "Gen. Journal Document Type"; DocumentNo: Code[20]; PostingDate: Date; SourceCode: Code[10]; var VATEntry: Record "VAT Entry") + begin + end; } diff --git a/Apps/CZ/CoreLocalizationPack/app/Src/TableExtensions/VendorLedgerEntryCZL.TableExt.al b/Apps/CZ/CoreLocalizationPack/app/Src/TableExtensions/VendorLedgerEntryCZL.TableExt.al index 2ed563a920..6535455626 100644 --- a/Apps/CZ/CoreLocalizationPack/app/Src/TableExtensions/VendorLedgerEntryCZL.TableExt.al +++ b/Apps/CZ/CoreLocalizationPack/app/Src/TableExtensions/VendorLedgerEntryCZL.TableExt.al @@ -126,18 +126,32 @@ tableextension 11721 "Vendor Ledger Entry CZL" extends "Vendor Ledger Entry" OnAfterUpdateBankInfoCZL(Rec); end; + procedure CollectSuggestedApplicationCZL(var CrossApplicationBufferCZL: Record "Cross Application Buffer CZL"): Boolean + var + CrossApplicationMgtCZL: Codeunit "Cross Application Mgt. CZL"; + begin + exit(CrossApplicationMgtCZL.CollectSuggestedApplication(Rec, CrossApplicationBufferCZL)); + end; + + procedure CollectSuggestedApplicationCZL(CalledFrom: Variant; var CrossApplicationBufferCZL: Record "Cross Application Buffer CZL"): Boolean + var + CrossApplicationMgtCZL: Codeunit "Cross Application Mgt. CZL"; + begin + exit(CrossApplicationMgtCZL.CollectSuggestedApplication(Rec, CalledFrom, CrossApplicationBufferCZL)); + end; + procedure CalcSuggestedAmountToApplyCZL(): Decimal var CrossApplicationMgtCZL: Codeunit "Cross Application Mgt. CZL"; begin - exit(CrossApplicationMgtCZL.CalcSuggestedAmountToApplyVendorLedgerEntry(Rec)); + exit(CrossApplicationMgtCZL.CalcSuggestedAmountToApply(Rec)); end; procedure DrillDownSuggestedAmountToApplyCZL() var CrossApplicationMgtCZL: Codeunit "Cross Application Mgt. CZL"; begin - CrossApplicationMgtCZL.DrillDownSuggestedAmountToApplyVendorLedgerEntry(Rec); + CrossApplicationMgtCZL.DrillDownSuggestedAmountToApply(Rec); end; procedure RelatedToAdvanceLetterCZL() IsRelatedToAdvanceLetter: Boolean diff --git a/Apps/CZ/CoreLocalizationPack/app/Src/Tables/CompanyOfficialCZL.Table.al b/Apps/CZ/CoreLocalizationPack/app/Src/Tables/CompanyOfficialCZL.Table.al index 04d1e83d99..e728f8e7f5 100644 --- a/Apps/CZ/CoreLocalizationPack/app/Src/Tables/CompanyOfficialCZL.Table.al +++ b/Apps/CZ/CoreLocalizationPack/app/Src/Tables/CompanyOfficialCZL.Table.al @@ -25,6 +25,8 @@ table 11793 "Company Official CZL" DataClassification = CustomerContent; trigger OnValidate() + var + NoSeries: Codeunit "No. Series"; begin if "No." <> xRec."No." then begin StatutoryReportingSetupCZL.Get(); @@ -185,7 +187,7 @@ table 11793 "Company Official CZL" "Country/Region Code" := Employee."Country/Region Code"; "Phone No." := Employee."Phone No."; "Mobile Phone No." := Employee."Mobile Phone No."; - "E-Mail" := Employee."E-Mail"; + "E-Mail" := Employee."Company E-Mail"; "Fax No." := Employee."Fax No."; "Employee No." := Employee."No."; "Privacy Blocked" := Employee."Privacy Blocked"; @@ -230,6 +232,7 @@ table 11793 "Company Official CZL" trigger OnInsert() var CompanyOfficial: Record "Company Official CZL"; + NoSeries: Codeunit "No. Series"; #if not CLEAN24 IsHandled: Boolean; #endif @@ -271,18 +274,19 @@ table 11793 "Company Official CZL" Employee: Record Employee; PostCode: Record "Post Code"; CompanyOfficialCZL: Record "Company Official CZL"; +#if not CLEAN24 NoSeriesManagement: Codeunit NoSeriesManagement; - NoSeries: Codeunit "No. Series"; +#endif procedure AssistEdit(OldCompanyOfficialCZL: Record "Company Official CZL"): Boolean + var + NoSeries: Codeunit "No. Series"; begin CompanyOfficialCZL := Rec; StatutoryReportingSetupCZL.Get(); StatutoryReportingSetupCZL.TestField("Company Official Nos."); - if NoSeriesManagement.SelectSeries(StatutoryReportingSetupCZL."Company Official Nos.", OldCompanyOfficialCZL."No. Series", OldCompanyOfficialCZL."No. Series") then begin - StatutoryReportingSetupCZL.Get(); - StatutoryReportingSetupCZL.TestField("Company Official Nos."); - NoSeriesManagement.SetSeries(OldCompanyOfficialCZL."No."); + if NoSeries.LookupRelatedNoSeries(StatutoryReportingSetupCZL."Company Official Nos.", OldCompanyOfficialCZL."No. Series", OldCompanyOfficialCZL."No. Series") then begin + OldCompanyOfficialCZL."No." := NoSeries.GetNextNo(OldCompanyOfficialCZL."No. Series"); Rec := CompanyOfficialCZL; exit(true); end; diff --git a/Apps/CZ/CoreLocalizationPack/app/Src/Tables/CrossApplicationBufferCZL.Table.al b/Apps/CZ/CoreLocalizationPack/app/Src/Tables/CrossApplicationBufferCZL.Table.al index da368a9e2b..6fe786970c 100644 --- a/Apps/CZ/CoreLocalizationPack/app/Src/Tables/CrossApplicationBufferCZL.Table.al +++ b/Apps/CZ/CoreLocalizationPack/app/Src/Tables/CrossApplicationBufferCZL.Table.al @@ -54,4 +54,32 @@ table 31115 "Cross Application Buffer CZL" Clustered = true; } } + + procedure ExcludeDocument(DocumentVariant: Variant) + var + DataTypeManagement: Codeunit "Data Type Management"; + DocumentRecRef: RecordRef; + begin + if not DataTypeManagement.GetRecordRef(DocumentVariant, DocumentRecRef) then + exit; + OnExcludeDocument(DocumentRecRef.Number, DocumentVariant, Rec); + end; + + procedure RemoveDocument(TableID: Integer; AppliedDocumentNo: Code[20]; AppliedDocumentLineNo: Integer) + var + CrossApplicationBufferCZL: Record "Cross Application Buffer CZL"; + begin + CrossApplicationBufferCZL.CopyFilters(Rec); + SetRange("Table ID", TableID); + SetRange("Applied Document No.", AppliedDocumentNo); + SetRange("Applied Document Line No.", AppliedDocumentLineNo); + DeleteAll(); + Reset(); + CopyFilters(CrossApplicationBufferCZL); + end; + + [IntegrationEvent(false, false)] + local procedure OnExcludeDocument(TableID: Integer; DocumentVariant: Variant; var CrossApplicationBufferCZL: Record "Cross Application Buffer CZL") + begin + end; } diff --git a/Apps/CZ/CoreLocalizationPack/app/Src/Tables/EETEntryCZL.Table.al b/Apps/CZ/CoreLocalizationPack/app/Src/Tables/EETEntryCZL.Table.al index dab960a51e..11dbca7088 100644 --- a/Apps/CZ/CoreLocalizationPack/app/Src/Tables/EETEntryCZL.Table.al +++ b/Apps/CZ/CoreLocalizationPack/app/Src/Tables/EETEntryCZL.Table.al @@ -265,7 +265,7 @@ table 31128 "EET Entry CZL" var CompanyInformation: Record "Company Information"; EETServiceSetupCZL: Record "EET Service Setup CZL"; - NoSeriesManagement: Codeunit NoSeriesManagement; + NoSeries: Codeunit "No. Series"; IsHandled: Boolean; begin IsHandled := false; @@ -280,7 +280,7 @@ table 31128 "EET Entry CZL" if "Receipt Serial No." = '' then begin TestReceiptSerialNoSeries(); - "Receipt Serial No." := NoSeriesManagement.GetNextNo(GetReceiptSerialNoSeriesCode(), Today(), true); + "Receipt Serial No." := NoSeries.GetNextNo(GetReceiptSerialNoSeriesCode(), Today()); end; if "VAT Registration No." = '' then begin diff --git a/Apps/CZ/CoreLocalizationPack/app/Src/Tables/VATCtrlReportHeaderCZL.Table.al b/Apps/CZ/CoreLocalizationPack/app/Src/Tables/VATCtrlReportHeaderCZL.Table.al index 4567a5ef36..2e8596feef 100644 --- a/Apps/CZ/CoreLocalizationPack/app/Src/Tables/VATCtrlReportHeaderCZL.Table.al +++ b/Apps/CZ/CoreLocalizationPack/app/Src/Tables/VATCtrlReportHeaderCZL.Table.al @@ -24,6 +24,8 @@ table 31106 "VAT Ctrl. Report Header CZL" DataClassification = CustomerContent; trigger OnValidate() + var + NoSeries: Codeunit "No. Series"; begin if "No." <> xRec."No." then begin NoSeries.TestManual(GetNoSeriesCode()); @@ -200,6 +202,7 @@ table 31106 "VAT Ctrl. Report Header CZL" trigger OnInsert() var VATCtrlReportHeader: Record "VAT Ctrl. Report Header CZL"; + NoSeries: Codeunit "No. Series"; NoSeriesCode: Code[20]; #if not CLEAN24 IsHandled: Boolean; @@ -234,8 +237,9 @@ table 31106 "VAT Ctrl. Report Header CZL" var VATCtrlReportLineCZL: Record "VAT Ctrl. Report Line CZL"; +#if not CLEAN24 NoSeriesManagement: Codeunit NoSeriesManagement; - NoSeries: Codeunit "No. Series"; +#endif VATCtrlReportMgtCZL: Codeunit "VAT Ctrl. Report Mgt. CZL"; VATCtrlRepExpRunnerCZL: Codeunit "VAT Ctrl. Rep. Exp. Runner CZL"; RecordRenameErr: Label 'You cannot rename a %1.', Comment = '%1 = Header No.'; @@ -249,9 +253,11 @@ table 31106 "VAT Ctrl. Report Header CZL" end; procedure AssistEdit(OldVATCtrlReportHeaderCZL: Record "VAT Ctrl. Report Header CZL"): Boolean + var + NoSeries: Codeunit "No. Series"; begin - if NoSeriesManagement.SelectSeries(GetNoSeriesCode(), OldVATCtrlReportHeaderCZL."No. Series", "No. Series") then begin - NoSeriesManagement.SetSeries("No."); + if NoSeries.LookupRelatedNoSeries(GetNoSeriesCode(), OldVATCtrlReportHeaderCZL."No. Series", "No. Series") then begin + "No." := NoSeries.GetNextNo("No. Series"); exit(true); end; end; diff --git a/Apps/CZ/CoreLocalizationPack/app/Src/Tables/VIESDeclarationHeaderCZL.Table.al b/Apps/CZ/CoreLocalizationPack/app/Src/Tables/VIESDeclarationHeaderCZL.Table.al index a0edabab60..d172a84a62 100644 --- a/Apps/CZ/CoreLocalizationPack/app/Src/Tables/VIESDeclarationHeaderCZL.Table.al +++ b/Apps/CZ/CoreLocalizationPack/app/Src/Tables/VIESDeclarationHeaderCZL.Table.al @@ -613,10 +613,10 @@ table 31075 "VIES Declaration Header CZL" procedure AssistEdit(OldVIESDeclarationHeaderCZL: Record "VIES Declaration Header CZL"): Boolean var - NoSeriesManagement: Codeunit NoSeriesManagement; + NoSeries: Codeunit "No. Series"; begin - if NoSeriesManagement.SelectSeries(GetNoSeriesCode(), OldVIESDeclarationHeaderCZL."No. Series", "No. Series") then begin - NoSeriesManagement.SetSeries("No."); + if NoSeries.LookupRelatedNoSeries(GetNoSeriesCode(), OldVIESDeclarationHeaderCZL."No. Series", "No. Series") then begin + "No." := NoSeries.GetNextNo("No. Series"); exit(true); end; end; diff --git a/Apps/CZ/CoreLocalizationPack/app/app.json b/Apps/CZ/CoreLocalizationPack/app/app.json index 96fac977b8..15bc2ab85c 100644 --- a/Apps/CZ/CoreLocalizationPack/app/app.json +++ b/Apps/CZ/CoreLocalizationPack/app/app.json @@ -2,9 +2,9 @@ "id": "267b59d3-7302-44c5-ba77-c87000380514", "name": "Core Localization Pack for Czech", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Provides standard local functionality in Business Central for the Czech Republic.", - "description": "This extension provides features that help companies meet regulatory requirements for accounting and tax legislation in the Czech Republic. It also offers support for best practices, and reports for areas such as finance, VAT, receivables, payables, and inventory. The following are some of the key features in this extension: Statutory company information and company officials; Financial documents; Statutory statement; VAT features, including VAT statements, VAT Control and other reports, unreliable payer, reverse charges, and more; Year closing operations; Exchange rate updating (ČNB); Customer/Vendor reconciliations; Contacts actualization from ARES; Czech legal layout for output documents; Inventory documents; Advanced features of the physical inventory; Multi-circuit accounting; Small regulatory features and best practices", + "description": "This extension provides features that help companies meet regulatory requirements for accounting and tax legislation in the Czech Republic. It also offers support for best practices, and reports for areas such as finance, VAT, receivables, payables, and inventory. The following are some of the key features in this extension: Statutory company information and company officials; Financial documents; Statutory statement; VAT features, including VAT statements, VAT Control and other reports, unreliable payer, reverse charges, and more; Year closing operations; Exchange rate updating (ÄŒNB); Customer/Vendor reconciliations; Contacts actualization from ARES; Czech legal layout for output documents; Inventory documents; Advanced features of the physical inventory; Multi-circuit accounting; Small regulatory features and best practices", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=2118088", @@ -12,22 +12,22 @@ "contextSensitiveHelpUrl": "https://go.microsoft.com/fwlink/?linkid=2118088", "logo": "ExtensionLogo.png", "dependencies": [ - { - "id": "0a9a9ce1-6f98-4cf0-82e2-0b3e7cabb32a", - "name": "EU 3-Party Trade Purchase", - "publisher": "Microsoft", - "version": "24.0.0.0" - } - ], + { + "id": "0a9a9ce1-6f98-4cf0-82e2-0b3e7cabb32a", + "name": "EU 3-Party Trade Purchase", + "publisher": "Microsoft", + "version": "25.0.0.0" + } + ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "target": "Cloud", "resourceExposurePolicy": { "allowDebugging": true, "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/CZ/CoreLocalizationPack/test/app.json b/Apps/CZ/CoreLocalizationPack/test/app.json index 3236207c6f..00c735cf6a 100644 --- a/Apps/CZ/CoreLocalizationPack/test/app.json +++ b/Apps/CZ/CoreLocalizationPack/test/app.json @@ -2,7 +2,7 @@ "id": "6555cb10-63ea-4ec0-99aa-8e6a4db67c87", "name": "Core Localization Pack for Czech Tests", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Tests for the Core Localization Pack for Czech application.", "description": "Tests for the Core Localization Pack for Czech application.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -16,25 +16,25 @@ "id": "267b59d3-7302-44c5-ba77-c87000380514", "name": "Core Localization Pack for Czech", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5095f467-0a01-4b99-99d1-9ff1237d286f", "publisher": "Microsoft", "name": "Library Variable Storage", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 148000, @@ -47,5 +47,5 @@ "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/CZ/FixedAssetLocalization/app/Src/Codeunits/CalcNormalDeprHandlerCZF.Codeunit.al b/Apps/CZ/FixedAssetLocalization/app/Src/Codeunits/CalcNormalDeprHandlerCZF.Codeunit.al index 47b07a93be..f9ec5f6918 100644 --- a/Apps/CZ/FixedAssetLocalization/app/Src/Codeunits/CalcNormalDeprHandlerCZF.Codeunit.al +++ b/Apps/CZ/FixedAssetLocalization/app/Src/Codeunits/CalcNormalDeprHandlerCZF.Codeunit.al @@ -134,11 +134,12 @@ codeunit 31247 "Calc. Normal Depr. Handler CZF" CalculatedFADepreciationBook."Book Value" := BookValue; TempDepBasis := CalculatedFADepreciationBook."Depreciable Basis"; TempBookValue := CalculatedFADepreciationBook."Book Value" - TaxDeprAmount + CalculatedFADepreciationBook."Salvage Value"; - if FADepreciationBook."Prorated CZF" then begin - CalculatedFADepreciationBook.SetRange("FA Posting Date Filter", CalcStartOfFiscalYear(UntilDate), UntilDate); - CalculatedFADepreciationBook.CalcFields(Depreciation); - TempBookValue := TempBookValue - CalculatedFADepreciationBook.Depreciation; - end; + if TaxDepreciationGroupCZF."Depreciation Type" <> TaxDepreciationGroupCZF."Depreciation Type"::"Straight-line Intangible" then + if FADepreciationBook."Prorated CZF" then begin + CalculatedFADepreciationBook.SetRange("FA Posting Date Filter", CalcStartOfFiscalYear(UntilDate), UntilDate); + CalculatedFADepreciationBook.CalcFields(Depreciation); + TempBookValue := TempBookValue - CalculatedFADepreciationBook.Depreciation; + end; FALedgerEntry.SetFilter("FA Posting Date", '..%1', UntilDate); if FALedgerEntry.FindLast() then diff --git a/Apps/CZ/FixedAssetLocalization/app/Src/Codeunits/FADisposalHandlerCZF.Codeunit.al b/Apps/CZ/FixedAssetLocalization/app/Src/Codeunits/FADisposalHandlerCZF.Codeunit.al index b433552f2d..2ce79f0f51 100644 --- a/Apps/CZ/FixedAssetLocalization/app/Src/Codeunits/FADisposalHandlerCZF.Codeunit.al +++ b/Apps/CZ/FixedAssetLocalization/app/Src/Codeunits/FADisposalHandlerCZF.Codeunit.al @@ -519,6 +519,17 @@ codeunit 31235 "FA Disposal Handler CZF" exit(ResultOnDisposalFALedgerEntry."Result on Disposal"::Loss); end; + [EventSubscriber(ObjectType::Codeunit, Codeunit::"FA Get G/L Account No.", 'OnBeforeGetMaintenanceAccNo', '', false, false)] + local procedure GetMaintenanceExpenseAccountOnBeforeGetMaintenanceAccNo(var MaintenanceLedgEntry: Record "Maintenance Ledger Entry"; var AccountNo: Code[20]; var IsHandled: Boolean) + var + FAPostingGroup: Record "FA Posting Group"; + begin + FAPostingGroup.GetPostingGroup( + MaintenanceLedgEntry."FA Posting Group", MaintenanceLedgEntry."Depreciation Book Code"); + AccountNo := FAPostingGroup.GetMaintenanceExpenseAccountCZF(MaintenanceLedgEntry."Maintenance Code"); + IsHandled := true; + end; + [EventSubscriber(ObjectType::Codeunit, Codeunit::"FA Insert G/L Account", 'OnInsertMaintenanceAccNoOnBeforeInsertBufferEntry', '', false, false)] local procedure GetMaintenanceExpenseAccountOnInsertMaintenanceAccNoOnBeforeInsertBufferEntry(var FAGLPostBuf: Record "FA G/L Posting Buffer"; var MaintenanceLedgEntry: Record "Maintenance Ledger Entry") var diff --git a/Apps/CZ/FixedAssetLocalization/app/Src/Codeunits/FAHistoryHandlerCZF.Codeunit.al b/Apps/CZ/FixedAssetLocalization/app/Src/Codeunits/FAHistoryHandlerCZF.Codeunit.al index 2c13103eb0..8736125693 100644 --- a/Apps/CZ/FixedAssetLocalization/app/Src/Codeunits/FAHistoryHandlerCZF.Codeunit.al +++ b/Apps/CZ/FixedAssetLocalization/app/Src/Codeunits/FAHistoryHandlerCZF.Codeunit.al @@ -49,14 +49,14 @@ codeunit 31238 "FA History Handler CZF" [EventSubscriber(ObjectType::Report, Report::"Copy Fixed Asset", 'OnAfterFixedAssetCopied', '', false, false)] local procedure InitializeHistoryOnAfterFixedAssetCopied(FixedAsset2: Record "Fixed Asset") var - NoSeriesManagement: Codeunit NoSeriesManagement; + NoSeries: Codeunit "No. Series"; DocumentNo: Code[20]; begin FASetup.Get(); if FASetup."Fixed Asset History CZF" then begin if (FixedAsset2."FA Location Code" <> '') or (FixedAsset2."Responsible Employee" <> '') then begin FASetup.TestField("Fixed Asset History Nos. CZF"); - DocumentNo := NoSeriesManagement.GetNextNo(FASetup."Fixed Asset History Nos. CZF", WorkDate(), true); + DocumentNo := NoSeries.GetNextNo(FASetup."Fixed Asset History Nos. CZF"); end; FAHistoryManagementCZF.InitializeFAHistory(FixedAsset2, WorkDate(), DocumentNo); end; diff --git a/Apps/CZ/FixedAssetLocalization/app/Src/Codeunits/FAHistoryManagementCZF.Codeunit.al b/Apps/CZ/FixedAssetLocalization/app/Src/Codeunits/FAHistoryManagementCZF.Codeunit.al index 173fe2773d..0ee15db9ec 100644 --- a/Apps/CZ/FixedAssetLocalization/app/Src/Codeunits/FAHistoryManagementCZF.Codeunit.al +++ b/Apps/CZ/FixedAssetLocalization/app/Src/Codeunits/FAHistoryManagementCZF.Codeunit.al @@ -18,10 +18,10 @@ codeunit 31237 "FA History Management CZF" var FASetup: Record "FA Setup"; FADepreciationBook: Record "FA Depreciation Book"; - NoSeriesManagement: Codeunit NoSeriesManagement; procedure CreateFAHistoryEntry(FAHistoryTypeCZF: Enum "FA History Type CZF"; var FixedAsset: Record "Fixed Asset"; var xFixedAsset: Record "Fixed Asset") var + NoSeries: Codeunit "No. Series"; CreateFAHistoryCZF: Page "Create FA History CZF"; OldValue, NewValue : Code[20]; IsHandled: Boolean; @@ -48,7 +48,7 @@ codeunit 31237 "FA History Management CZF" OnBeforeShowInsertFAHistoryPage(PostingDate, DocumentNo); if (PostingDate = 0D) or (DocumentNo = '') then begin FASetup.TestField("Fixed Asset History Nos. CZF"); - CreateFAHistoryCZF.SetValues(WorkDate(), NoSeriesManagement.GetNextNo(FASetup."Fixed Asset History Nos. CZF", WorkDate(), true)); + CreateFAHistoryCZF.SetValues(WorkDate(), NoSeries.GetNextNo(FASetup."Fixed Asset History Nos. CZF")); Commit(); if CreateFAHistoryCZF.RunModal() = Action::OK then begin CreateFAHistoryCZF.GetValues(PostingDate, DocumentNo); diff --git a/Apps/CZ/FixedAssetLocalization/app/Src/Reports/InitializeFAHistoryCZF.Report.al b/Apps/CZ/FixedAssetLocalization/app/Src/Reports/InitializeFAHistoryCZF.Report.al index 29bcfc5dd7..631d5ae9fc 100644 --- a/Apps/CZ/FixedAssetLocalization/app/Src/Reports/InitializeFAHistoryCZF.Report.al +++ b/Apps/CZ/FixedAssetLocalization/app/Src/Reports/InitializeFAHistoryCZF.Report.al @@ -72,9 +72,11 @@ report 31250 "Initialize FA History CZF" } trigger OnOpenPage() + var + NoSeries: Codeunit "No. Series"; begin InitializeDate := WorkDate(); - DocumentNo := NoSeriesManagement.GetNextNo(FASetup."Fixed Asset History Nos. CZF", WorkDate(), true); + DocumentNo := NoSeries.GetNextNo(FASetup."Fixed Asset History Nos. CZF"); end; } @@ -82,7 +84,6 @@ report 31250 "Initialize FA History CZF" FASetup: Record "FA Setup"; FAHistoryEntryCZF: Record "FA History Entry CZF"; FAHistoryManagementCZF: Codeunit "FA History Management CZF"; - NoSeriesManagement: Codeunit NoSeriesManagement; InitializeDate: Date; DocumentNo: Code[20]; InitializeCounter: Integer; diff --git a/Apps/CZ/FixedAssetLocalization/app/app.json b/Apps/CZ/FixedAssetLocalization/app/app.json index fc7ce62a42..b5ab695c1e 100644 --- a/Apps/CZ/FixedAssetLocalization/app/app.json +++ b/Apps/CZ/FixedAssetLocalization/app/app.json @@ -2,7 +2,7 @@ "id": "ef5dfe8c-ba1c-4271-8a86-95d5abdc6fe9", "name": "Fixed Asset Localization for Czech", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Fixed Asset local functionality of Business Central for the Czech Republic", "description": "Fixed Asset features for your Business Central in the Czech Republic.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -16,18 +16,18 @@ "id": "267b59d3-7302-44c5-ba77-c87000380514", "name": "Core Localization Pack for Czech", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "target": "Cloud", "resourceExposurePolicy": { "allowDebugging": true, "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/CZ/FixedAssetLocalization/test/Src/FixedAssetsCZF.Codeunit.al b/Apps/CZ/FixedAssetLocalization/test/Src/FixedAssetsCZF.Codeunit.al index c8f93bbd1f..c92b4193cd 100644 --- a/Apps/CZ/FixedAssetLocalization/test/Src/FixedAssetsCZF.Codeunit.al +++ b/Apps/CZ/FixedAssetLocalization/test/Src/FixedAssetsCZF.Codeunit.al @@ -517,19 +517,19 @@ codeunit 148087 "Fixed Assets CZF" local procedure GetFAJournalLineDocumentNo(FAJournalBatch: Record "FA Journal Batch"): Code[20] var NoSeries: Record "No. Series"; - NoSeriesManagement: Codeunit NoSeriesManagement; + NoSeriesCodeunit: Codeunit "No. Series"; begin NoSeries.Get(FAJournalBatch."No. Series"); - exit(NoSeriesManagement.GetNextNo(FAJournalBatch."No. Series", WorkDate(), false)); + exit(NoSeriesCodeunit.PeekNextNo(FAJournalBatch."No. Series")); end; local procedure GetGenJournalLineDocumentNo(GenJournalBatch: Record "Gen. Journal Batch"): Code[20] var NoSeries: Record "No. Series"; - NoSeriesManagement: Codeunit NoSeriesManagement; + NoSeriesCodeunit: Codeunit "No. Series"; begin NoSeries.Get(GenJournalBatch."No. Series"); - exit(NoSeriesManagement.GetNextNo(GenJournalBatch."No. Series", WorkDate(), false)); + exit(NoSeriesCodeunit.PeekNextNo(GenJournalBatch."No. Series")); end; local procedure GetNewGLAccountNo(): Code[20] diff --git a/Apps/CZ/FixedAssetLocalization/test/app.json b/Apps/CZ/FixedAssetLocalization/test/app.json index 8e12bf5e7b..2f833bb151 100644 --- a/Apps/CZ/FixedAssetLocalization/test/app.json +++ b/Apps/CZ/FixedAssetLocalization/test/app.json @@ -2,7 +2,7 @@ "id": "ee8ee5d5-280f-47f6-b849-2eeda3673ad7", "name": "Fixed Asset Localization for Czech Tests", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Tests for the Fixed Asset Localization for Czech application.", "description": "Tests for the Fixed Asset Localization for Czech application.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -16,31 +16,31 @@ "id": "267b59d3-7302-44c5-ba77-c87000380514", "name": "Core Localization Pack for Czech", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "ef5dfe8c-ba1c-4271-8a86-95d5abdc6fe9", "name": "Fixed Asset Localization for Czech", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5095f467-0a01-4b99-99d1-9ff1237d286f", "publisher": "Microsoft", "name": "Library Variable Storage", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 148000, @@ -53,5 +53,5 @@ "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/CZ/HybridBCLast_CZ/app/app.json b/Apps/CZ/HybridBCLast_CZ/app/app.json index 7f8344a4d4..0e58e0014a 100644 --- a/Apps/CZ/HybridBCLast_CZ/app/app.json +++ b/Apps/CZ/HybridBCLast_CZ/app/app.json @@ -2,7 +2,7 @@ "id": "3ea26430-7184-46e6-a974-8978c28f4dae", "name": "Business Central Cloud Migration - Previous Release (CZ)", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Enables data migration from the previous version of Dynamics BC (n-1) to the current release of Dynamics 365 Business Central SaaS.", "description": "This extension, in conjuction with the Business Central Cloud Migration Previous Release, will enable you to migrate data from your Business Central on-premises solution for Czech Republic to your Dynamics 365 Business Central cloud tenant for Czech Republic. This extension is required to update country specific tables. Once you have walked through the cloud migration wizard in assisted setup, you will be able to migrate your data from your on-premises environment to your cloud tenant.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -15,25 +15,25 @@ { "publisher": "Microsoft", "name": "Intelligent Cloud Base", - "version": "24.0.0.0", + "version": "25.0.0.0", "id": "58623bfa-0559-4bc2-ae1c-0979c29fd9e0" }, { "publisher": "Microsoft", "name": "Business Central Cloud Migration - Previous Release", - "version": "24.0.0.0", + "version": "25.0.0.0", "id": "6992416f-3f39-4d3c-8242-3fff61350bea" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "resourceExposurePolicy": { "allowDebugging": false, "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, "target": "OnPrem", - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/CZ/IntrastatCZ/app/app.json b/Apps/CZ/IntrastatCZ/app/app.json index 5dfa361282..232c6daa8f 100644 --- a/Apps/CZ/IntrastatCZ/app/app.json +++ b/Apps/CZ/IntrastatCZ/app/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "The Intrastat extension makes it easy to export the Intrastat report in the format that the authorities in your country require.", "description": "The formats that businesses must use to report Intrastat vary from country to country. The Intrastat extension makes it easy to export the Intrastat report in the format that the authorities in your country require.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=2226066", @@ -16,30 +16,30 @@ "id": "70912191-3c4c-49fc-a1de-bc6ea1ac9da6", "name": "Intrastat Core", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "267b59d3-7302-44c5-ba77-c87000380514", "name": "Core Localization Pack for Czech", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { - "id": "f12846ee-be97-4316-a5b3-ba789471687a", - "name": "Advanced Localization Pack for Czech", - "publisher": "Microsoft", - "version": "24.0.0.0" + "id": "f12846ee-be97-4316-a5b3-ba789471687a", + "name": "Advanced Localization Pack for Czech", + "publisher": "Microsoft", + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "resourceExposurePolicy": { "allowDebugging": true, "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0", + "application": "25.0.0.0", "target": "Cloud" } \ No newline at end of file diff --git a/Apps/CZ/Onprem Permissions CZ/app/app.json b/Apps/CZ/Onprem Permissions CZ/app/app.json index 6ed12b9bf5..eaefbcfc1d 100644 --- a/Apps/CZ/Onprem Permissions CZ/app/app.json +++ b/Apps/CZ/Onprem Permissions CZ/app/app.json @@ -2,7 +2,7 @@ "id": "f93c2c47-6485-40a7-91c8-a9e8e52d9aa5", "name": "OnPrem Permissions (CZ)", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "This extension includes permission set for on premise systems.", "description": "This extension includes permission set for on premise systems.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -17,12 +17,12 @@ "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "resourceExposurePolicy": { "allowDebugging": false, "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, "target": "OnPrem", - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/DACH/Onprem Permissions DACH/app/app.json b/Apps/DACH/Onprem Permissions DACH/app/app.json index 31913fd5fe..822ffc81b6 100644 --- a/Apps/DACH/Onprem Permissions DACH/app/app.json +++ b/Apps/DACH/Onprem Permissions DACH/app/app.json @@ -2,7 +2,7 @@ "id": "66562109-c5eb-437e-bb8b-f4809337714e", "name": "OnPrem Permissions (DACH)", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "This extension includes permission set for on premise systems.", "description": "This extension includes permission set for on premise systems.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -17,12 +17,12 @@ "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "resourceExposurePolicy": { "allowDebugging": false, "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, "target": "OnPrem", - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/DE/ContosoCoffeeDemoDatasetDE/app/app.json b/Apps/DE/ContosoCoffeeDemoDatasetDE/app/app.json index 18d3e5305b..837e1130bb 100644 --- a/Apps/DE/ContosoCoffeeDemoDatasetDE/app/app.json +++ b/Apps/DE/ContosoCoffeeDemoDatasetDE/app/app.json @@ -2,7 +2,7 @@ "id": "4b1c41f9-7a13-4122-d521-2465194cfb32", "name": "Contoso Coffee Demo Dataset (DE)", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "To help partners demonstrate the capabilities of Business Central, we are making new and extensive demo data available for various scenarios.", "description": "Presales specialists can run the tool on top of Cronus or My Company and get the setup and demo data they'll need when they demonstrate various scenarios.", "privacyStatement": "https://go.microsoft.com/fwlink/?linkid=724009", @@ -16,14 +16,14 @@ "id": "5a0b41e9-7a42-4123-d521-2265186cfb31", "name": "Contoso Coffee Demo Dataset", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 11080, diff --git a/Apps/DE/Elster/app/app.json b/Apps/DE/Elster/app/app.json index 91fd00526f..86580aeecf 100644 --- a/Apps/DE/Elster/app/app.json +++ b/Apps/DE/Elster/app/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "Create XML file needed to report VAT in Germany.", "description": "With this app it is possible to create a XML file to use for reporting VAT in Germany, making it easy to comply with German VAT requirements.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=2043382", @@ -22,7 +22,7 @@ "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "platform": "24.0.0.0", + "platform": "25.0.0.0", "target": "OnPrem", - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/DE/Elster/app/src/Tables/SalesVATAdvanceNotif.Table.al b/Apps/DE/Elster/app/src/Tables/SalesVATAdvanceNotif.Table.al index 6f4d4bc4a2..f3ab0d60d5 100644 --- a/Apps/DE/Elster/app/src/Tables/SalesVATAdvanceNotif.Table.al +++ b/Apps/DE/Elster/app/src/Tables/SalesVATAdvanceNotif.Table.al @@ -315,17 +315,15 @@ table 11021 "Sales VAT Advance Notif." procedure AssistEdit(OldSalesVATAdvNotif: Record "Sales VAT Advance Notif."): Boolean var SalesVATAdvNotif: Record "Sales VAT Advance Notif."; - NoSeriesManagement: Codeunit NoSeriesManagement; + NoSeries: Codeunit "No. Series"; begin - with SalesVATAdvNotif do begin - SalesVATAdvNotif := Rec; - ElecVATDeclSetup.Get(); - ElecVATDeclSetup.TestField("Sales VAT Adv. Notif. Nos."); - if NoSeriesManagement.SelectSeries(ElecVATDeclSetup."Sales VAT Adv. Notif. Nos.", OldSalesVATAdvNotif."No. Series", "No. Series") then begin - NoSeriesManagement.SetSeries("No."); - Rec := SalesVATAdvNotif; - exit(true); - end; + SalesVATAdvNotif := Rec; + ElecVATDeclSetup.Get(); + ElecVATDeclSetup.TestField("Sales VAT Adv. Notif. Nos."); + if NoSeries.LookupRelatedNoSeries(ElecVATDeclSetup."Sales VAT Adv. Notif. Nos.", OldSalesVATAdvNotif."No. Series", SalesVATAdvNotif."No. Series") then begin + SalesVATAdvNotif."No." := NoSeries.GetNextNo(SalesVATAdvNotif."No. Series"); + Rec := SalesVATAdvNotif; + exit(true); end; end; diff --git a/Apps/DE/Elster/test/app.json b/Apps/DE/Elster/test/app.json index bedeec4797..c8369f40f3 100644 --- a/Apps/DE/Elster/test/app.json +++ b/Apps/DE/Elster/test/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "Tests for the ELSTER VAT Localization for Germany extension.", "description": "Tests for the ELSTER VAT Localization for Germany extension.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=2043382", @@ -16,31 +16,31 @@ "id": "b0c41a2d-9ebe-4773-a22f-86bd69e75949", "name": "ELSTER VAT Localization for Germany", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "9856ae4f-d1a7-46ef-89bb-6ef056398228", "name": "System Application Test Library", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5095f467-0a01-4b99-99d1-9ff1237d286f", "publisher": "Microsoft", "name": "Library Variable Storage", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 139500, @@ -57,5 +57,5 @@ "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/DE/HybridBCLast_DE/app/app.json b/Apps/DE/HybridBCLast_DE/app/app.json index 9ae509ac20..ddf9ecc582 100644 --- a/Apps/DE/HybridBCLast_DE/app/app.json +++ b/Apps/DE/HybridBCLast_DE/app/app.json @@ -2,7 +2,7 @@ "id": "f0bbefd6-e6dc-4da6-b39a-178233579ce8", "name": "Business Central Cloud Migration - Previous Release (DE)", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Enables data migration from the previous version of Dynamics BC (n-1) to the current release of Dynamics 365 Business Central SaaS.", "description": "This extension, in conjuction with the Business Central Cloud Migration Previous Release, will enable you to migrate data from your Business Central on-premises solution for Germany to your Dynamics 365 Business Central cloud tenant for Germany. This extension is required to update country specific tables. Once you have walked through the cloud migration wizard in assisted setup, you will be able to migrate your data from your on-premises environment to your cloud tenant.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -15,25 +15,25 @@ { "publisher": "Microsoft", "name": "Intelligent Cloud Base", - "version": "24.0.0.0", + "version": "25.0.0.0", "id": "58623bfa-0559-4bc2-ae1c-0979c29fd9e0" }, { "publisher": "Microsoft", "name": "Business Central Cloud Migration - Previous Release", - "version": "24.0.0.0", + "version": "25.0.0.0", "id": "6992416f-3f39-4d3c-8242-3fff61350bea" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "resourceExposurePolicy": { "allowDebugging": false, "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, "target": "OnPrem", - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/DE/IntrastatDE/app/app.json b/Apps/DE/IntrastatDE/app/app.json index 2c17c439fb..fc74de12e9 100644 --- a/Apps/DE/IntrastatDE/app/app.json +++ b/Apps/DE/IntrastatDE/app/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "The Intrastat extension makes it easy to export the Intrastat report in the format that the authorities in your country require.", "description": "The formats that businesses must use to report Intrastat vary from country to country. The Intrastat extension makes it easy to export the Intrastat report in the format that the German authorities require.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=2212316", @@ -16,13 +16,13 @@ "id": "70912191-3c4c-49fc-a1de-bc6ea1ac9da6", "name": "Intrastat Core", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 11029, @@ -34,6 +34,6 @@ "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0", + "application": "25.0.0.0", "target": "Cloud" } \ No newline at end of file diff --git a/Apps/DK/C52012DataMigration/app/app.json b/Apps/DK/C52012DataMigration/app/app.json index fdecff13e2..c0046e0a64 100644 --- a/Apps/DK/C52012DataMigration/app/app.json +++ b/Apps/DK/C52012DataMigration/app/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "Migrates Data from Microsoft Dynamics C5 2012.", "description": "Migrates Data from Microsoft Dynamics C5 2012.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=859310", @@ -17,14 +17,14 @@ "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "target": "OnPrem", "resourceExposurePolicy": { "allowDebugging": false, "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0", + "application": "25.0.0.0", "internalsVisibleTo": [ { "id": "7c7412f7-da1e-41ad-a5b9-d7d503c16f1c", diff --git a/Apps/DK/C52012DataMigration/test/app.json b/Apps/DK/C52012DataMigration/test/app.json index 702f122300..d4de3d1c70 100644 --- a/Apps/DK/C52012DataMigration/test/app.json +++ b/Apps/DK/C52012DataMigration/test/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "Tests for the C5 2012 Data Migration extension.", "description": "Tests for the C5 2012 Data Migration extension.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=859310", @@ -16,19 +16,19 @@ "id": "3d5b2137-eeeb-4014-8489-41d37f8fd4c3", "name": "C5 2012 Data Migration", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 139500, @@ -45,5 +45,5 @@ "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/DK/ContosoCoffeeDemoDatasetDK/app/app.json b/Apps/DK/ContosoCoffeeDemoDatasetDK/app/app.json index 62ce893ac2..82346e4e5a 100644 --- a/Apps/DK/ContosoCoffeeDemoDatasetDK/app/app.json +++ b/Apps/DK/ContosoCoffeeDemoDatasetDK/app/app.json @@ -2,7 +2,7 @@ "id": "5b0b41a1-7b42-1134-a521-2265186cfb33", "name": "Contoso Coffee Demo Dataset (DK)", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "To help partners demonstrate the capabilities of Business Central, we are making new and extensive demo data available for various scenarios.", "description": "Presales specialists can run the tool on top of Cronus or My Company and get the setup and demo data they'll need when they demonstrate various scenarios.", "privacyStatement": "https://go.microsoft.com/fwlink/?linkid=724009", @@ -16,14 +16,14 @@ "id": "5a0b41e9-7a42-4123-d521-2265186cfb31", "name": "Contoso Coffee Demo Dataset", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 13699, diff --git a/Apps/DK/DKCore/app/app.json b/Apps/DK/DKCore/app/app.json index 48d1858323..06a97a6b24 100644 --- a/Apps/DK/DKCore/app/app.json +++ b/Apps/DK/DKCore/app/app.json @@ -2,7 +2,7 @@ "id": "40d64215-8abc-4d96-87dc-2894e5431115", "name": "DK Core", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Provides standard local functionality in Business Central for Denmark.", "description": "Provides standard local functionality in Business Central for Denmark.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -17,8 +17,8 @@ "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "resourceExposurePolicy": { "allowDebugging": false, "allowDownloadingSource": true, diff --git a/Apps/DK/DKCore/test/app.json b/Apps/DK/DKCore/test/app.json index de44cb872d..8fef709d8c 100644 --- a/Apps/DK/DKCore/test/app.json +++ b/Apps/DK/DKCore/test/app.json @@ -2,7 +2,7 @@ "id": "80795fa0-e5c2-4fde-be3a-b24567223929", "name": "DK Core Tests", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Tests for the Core Localization for Denmark.", "description": "Tests for the Core Localization for Denmark.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -16,25 +16,25 @@ "id": "40d64215-8abc-4d96-87dc-2894e5431115", "publisher": "Microsoft", "name": "DK Core", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5095f467-0a01-4b99-99d1-9ff1237d286f", "publisher": "Microsoft", "name": "Library Variable Storage", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "9856ae4f-d1a7-46ef-89bb-6ef056398228", "name": "System Application Test Library", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ @@ -45,7 +45,7 @@ "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "target": "OnPrem" } \ No newline at end of file diff --git a/Apps/DK/EDocumentFormatOIOUBL/app/app.json b/Apps/DK/EDocumentFormatOIOUBL/app/app.json index 551a70a0d7..286357ea5a 100644 --- a/Apps/DK/EDocumentFormatOIOUBL/app/app.json +++ b/Apps/DK/EDocumentFormatOIOUBL/app/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "E-Document format for OIOUBL.", "description": ": OIOUBL is a customization for Danish business requirements of the international UBL standard. This app supports OIOUBL 3.0 format for working with E-documents app.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=2194213", @@ -12,23 +12,23 @@ "logo": "ExtensionLogo.png", "contextSensitiveHelpUrl": "https://go.microsoft.com/fwlink/?linkid=2206603", "dependencies": [ - { - "id": "ac762be1-e90f-4a72-b519-612a5e3ddc2e", - "publisher": "Microsoft", - "name": "OIOUBL", - "version": "24.0.0.0" - }, - { - "id": "e1d97edc-c239-46b4-8d84-6368bdf67c8b", - "name": "E-Document Core", - "publisher": "Microsoft", - "version": "24.0.0.0" - } + { + "id": "ac762be1-e90f-4a72-b519-612a5e3ddc2e", + "publisher": "Microsoft", + "name": "OIOUBL", + "version": "25.0.0.0" + }, + { + "id": "e1d97edc-c239-46b4-8d84-6368bdf67c8b", + "name": "E-Document Core", + "publisher": "Microsoft", + "version": "25.0.0.0" + } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 13910, @@ -40,6 +40,6 @@ "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0", + "application": "25.0.0.0", "target": "OnPrem" - } \ No newline at end of file +} \ No newline at end of file diff --git a/Apps/DK/ElectronicVATDeclarationDK/app/app.json b/Apps/DK/ElectronicVATDeclarationDK/app/app.json index e1a65496cd..de7398de1a 100644 --- a/Apps/DK/ElectronicVATDeclarationDK/app/app.json +++ b/Apps/DK/ElectronicVATDeclarationDK/app/app.json @@ -4,29 +4,33 @@ "publisher": "Microsoft", "brief": "This extension provides functionality to export VAT Returns to Skat.dk electronically.", "description": "The extension offers the functionality to utilize the electronic API provided by the Danish tax authority (Skat.dk). This allows users to retrieve VAT Return periods, submit VAT Returns to the tax authority, and monitor the status of the submitted VAT Return.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", - "help": "https://go.microsoft.com/fwlink/?LinkId=724011", + "help": "https://go.microsoft.com/fwlink/?LinkId=724011", "contextSensitiveHelpUrl": "https://go.microsoft.com/fwlink/?linkid=2204541", "url": "https://go.microsoft.com/fwlink/?LinkId=724011", "logo": "ExtensionLogo.png", - "dependencies": [], - "screenshots": [], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "dependencies": [ + + ], + "screenshots": [ + + ], + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 13604, "to": 13607 }, { - "from": 13610, - "to": 13620 + "from": 13610, + "to": 13620 }, { - "from": 13668, - "to": 13668 + "from": 13668, + "to": 13668 } ], "resourceExposurePolicy": { @@ -34,6 +38,5 @@ "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "target": "OnPrem" } \ No newline at end of file diff --git a/Apps/DK/ElectronicVATDeclarationDK/app/src/Engine/ElecVATDeclCryptography.Codeunit.al b/Apps/DK/ElectronicVATDeclarationDK/app/src/Engine/ElecVATDeclCryptography.Codeunit.al index 6750887a05..6bb478abc0 100644 --- a/Apps/DK/ElectronicVATDeclarationDK/app/src/Engine/ElecVATDeclCryptography.Codeunit.al +++ b/Apps/DK/ElectronicVATDeclarationDK/app/src/Engine/ElecVATDeclCryptography.Codeunit.al @@ -81,13 +81,13 @@ codeunit 13607 "Elec. VAT Decl. Cryptography" ElecVATDeclAzKeyVault: Codeunit "Elec. VAT Decl. Az. Key Vault"; CertificateManagement: Codeunit "Certificate Management"; FullCertificateBase64: Text; + EmptySecretText: SecretText; begin FullCertificateBase64 := ElecVATDeclAzKeyVault.GetClientCertificateBase64FromAKV(); - SignatureKey.FromBase64String(FullCertificateBase64, '', true); - ClientPublicKeyBase64 := CertificateManagement.GetPublicKeyAsBase64String(FullCertificateBase64, ''); + SignatureKey.FromBase64String(FullCertificateBase64, EmptySecretText, true); + ClientPublicKeyBase64 := CertificateManagement.GetPublicKeyAsBase64String(FullCertificateBase64, EmptySecretText); end; - procedure InitServerSertificate(var ServerCertificateBase64: Text) var IsolatedCertificate: Record "Isolated Certificate"; diff --git a/Apps/DK/ElectronicVATDeclarationDK/test/app.json b/Apps/DK/ElectronicVATDeclarationDK/test/app.json index 5804fa7ba7..511fa76e47 100644 --- a/Apps/DK/ElectronicVATDeclarationDK/test/app.json +++ b/Apps/DK/ElectronicVATDeclarationDK/test/app.json @@ -4,42 +4,44 @@ "publisher": "Microsoft", "brief": "Tests for Electronic VAT Declaration for Denmark app.", "description": "Tests for Electronic VAT Declaration for Denmark app.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", - "help": "https://go.microsoft.com/fwlink/?LinkId=724011", + "help": "https://go.microsoft.com/fwlink/?LinkId=724011", "contextSensitiveHelpUrl": "https://go.microsoft.com/fwlink/?linkid=2204541", "url": "https://go.microsoft.com/fwlink/?LinkId=724011", "logo": "ExtensionLogo.png", "dependencies": [ - { - "id": "64977288-facd-4b48-abaa-bb0e288edfb3", - "name": "Electronic VAT Declaration for Denmark", - "publisher": "Microsoft", - "version": "24.0.0.0" - }, - { - "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", - "name": "Tests-TestLibraries", - "publisher": "Microsoft", - "version": "24.0.0.0" - }, - { - "id": "9856ae4f-d1a7-46ef-89bb-6ef056398228", - "name": "System Application Test Library", - "publisher": "Microsoft", - "version": "24.0.0.0" - }, - { - "id": "5095f467-0a01-4b99-99d1-9ff1237d286f", - "publisher": "Microsoft", - "name": "Library Variable Storage", - "version": "24.0.0.0" - } + { + "id": "64977288-facd-4b48-abaa-bb0e288edfb3", + "name": "Electronic VAT Declaration for Denmark", + "publisher": "Microsoft", + "version": "25.0.0.0" + }, + { + "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", + "name": "Tests-TestLibraries", + "publisher": "Microsoft", + "version": "25.0.0.0" + }, + { + "id": "9856ae4f-d1a7-46ef-89bb-6ef056398228", + "name": "System Application Test Library", + "publisher": "Microsoft", + "version": "25.0.0.0" + }, + { + "id": "5095f467-0a01-4b99-99d1-9ff1237d286f", + "publisher": "Microsoft", + "name": "Library Variable Storage", + "version": "25.0.0.0" + } ], - "screenshots": [], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "screenshots": [ + + ], + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 148015, diff --git a/Apps/DK/EnforcedDigitalVouchersDK/app/app.json b/Apps/DK/EnforcedDigitalVouchersDK/app/app.json index c0b56fc161..e8d4d9a98a 100644 --- a/Apps/DK/EnforcedDigitalVouchersDK/app/app.json +++ b/Apps/DK/EnforcedDigitalVouchersDK/app/app.json @@ -1,44 +1,46 @@ { - "id": "bb837764-d7cc-4b7b-898a-3ea5a1fab62f", - "name": "Enforced Digital Vouchers (DK)", - "publisher": "Microsoft", - "brief": "The Digital Vouchers extension makes it easy to generate digital version for every general ledger register.", - "description": "In some countries authorities require to make sure that for every single general ledger register ther is a digital vouchers assigned.", - "version": "24.0.0.0", - "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", - "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", - "help": "https://learn.microsoft.com/en-us/dynamics365/business-central/finance-how-setup-use-service-declaration", - "url": "https://go.microsoft.com/fwlink/?LinkId=724011", - "logo": "ExtensionLogo.png", - "contextSensitiveHelpUrl": "https://go.microsoft.com/fwlink/?linkid=2204541", - "dependencies": [ - { - "id": "e2ae191d-8829-44c3-a373-3749a2742d4e", - "name": "Enforced Digital Vouchers", - "publisher": "Microsoft", - "version": "24.0.0.0" - } - ], - "screenshots": [], - "platform": "24.0.0.0", - "features": [ - "TranslationFile" - ], - "idRanges": [ - { - "from": 13621, - "to": 13626 - }, - { - "from": 13645, - "to": 13645 - } - ], - "resourceExposurePolicy": { - "allowDebugging": true, - "allowDownloadingSource": true, - "includeSourceInSymbolFile": true - }, - "application": "24.0.0.0", - "target": "Cloud" + "id": "bb837764-d7cc-4b7b-898a-3ea5a1fab62f", + "name": "Enforced Digital Vouchers (DK)", + "publisher": "Microsoft", + "brief": "The Digital Vouchers extension makes it easy to generate digital version for every general ledger register.", + "description": "In some countries authorities require to make sure that for every single general ledger register ther is a digital vouchers assigned.", + "version": "25.0.0.0", + "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", + "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", + "help": "https://learn.microsoft.com/en-us/dynamics365/business-central/finance-how-setup-use-service-declaration", + "url": "https://go.microsoft.com/fwlink/?LinkId=724011", + "logo": "ExtensionLogo.png", + "contextSensitiveHelpUrl": "https://go.microsoft.com/fwlink/?linkid=2204541", + "dependencies": [ + { + "id": "e2ae191d-8829-44c3-a373-3749a2742d4e", + "name": "Enforced Digital Vouchers", + "publisher": "Microsoft", + "version": "25.0.0.0" + } + ], + "screenshots": [ + + ], + "platform": "25.0.0.0", + "features": [ + "TranslationFile" + ], + "idRanges": [ + { + "from": 13621, + "to": 13626 + }, + { + "from": 13645, + "to": 13645 + } + ], + "resourceExposurePolicy": { + "allowDebugging": true, + "allowDownloadingSource": true, + "includeSourceInSymbolFile": true + }, + "application": "25.0.0.0", + "target": "Cloud" } \ No newline at end of file diff --git a/Apps/DK/EnforcedDigitalVouchersDK/app/src/DigitalVoucherDKInstall.Codeunit.al b/Apps/DK/EnforcedDigitalVouchersDK/app/src/DigitalVoucherDKInstall.Codeunit.al index ef1fcd2699..dc7db697ea 100644 --- a/Apps/DK/EnforcedDigitalVouchersDK/app/src/DigitalVoucherDKInstall.Codeunit.al +++ b/Apps/DK/EnforcedDigitalVouchersDK/app/src/DigitalVoucherDKInstall.Codeunit.al @@ -61,9 +61,12 @@ codeunit 13645 "Digital Voucher DK Install." local procedure InsertDigitalVoucherEntrySourceCode(EntryType: Enum "Digital Voucher Entry Type"; SourceCode: Code[10]) var VoucherSourceCode: Record "Voucher Entry Source Code"; + SourceCodeRec: Record "Source Code"; begin if SourceCode = '' then exit; + if not SourceCodeRec.Get(SourceCode) then + exit; VoucherSourceCode.Validate("Entry Type", EntryType); VoucherSourceCode.Validate("Source Code", SourceCode); VoucherSourceCode.Insert(true); diff --git a/Apps/DK/EnforcedDigitalVouchersDK/test/app.json b/Apps/DK/EnforcedDigitalVouchersDK/test/app.json index 50054f39b2..f940c08017 100644 --- a/Apps/DK/EnforcedDigitalVouchersDK/test/app.json +++ b/Apps/DK/EnforcedDigitalVouchersDK/test/app.json @@ -1,60 +1,60 @@ { - "id": "286fb38a-2023-4049-ae17-2445bd2e25b2", - "name": "Enforced Digital Vouchers Tests (DK)", - "publisher": "Microsoft", - "version": "24.0.0.0", - "brief": "Tests for the Enforced Digital Vouchers extension.", - "description": "Tests for the Enforced Digital Vouchers extension.", - "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", - "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", - "help": "https://go.microsoft.com/fwlink/?LinkId=724011", - "url": "https://go.microsoft.com/fwlink/?LinkId=724011", - "logo": "ExtensionLogo.png", - "platform": "24.0.0.0", - "application": "24.0.0.0", - "dependencies": [ - { - "id": "e2ae191d-8829-44c3-a373-3749a2742d4e", - "name": "Enforced Digital Vouchers", - "publisher": "Microsoft", - "version": "24.0.0.0" - }, - { - "id": "bb837764-d7cc-4b7b-898a-3ea5a1fab62f", - "name": "Enforced Digital Vouchers (DK)", - "publisher": "Microsoft", - "version": "24.0.0.0" - }, - { - "id": "928f7b70-0dbd-431a-beb5-f45c4adbd361", - "name": "Enforced Digital Vouchers Test Library", - "publisher": "Microsoft", - "version": "24.0.0.0" - }, - { - "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", - "name": "Tests-TestLibraries", - "publisher": "Microsoft", - "version": "24.0.0.0" - }, - { - "id": "9856ae4f-d1a7-46ef-89bb-6ef056398228", - "name": "System Application Test Library", - "publisher": "Microsoft", - "version": "24.0.0.0" - } - ], - "idRanges": [ - { - "from": 148016, - "to": 148016 - } - ], - "contextSensitiveHelpUrl": "https://go.microsoft.com/fwlink/?linkid=2141039", - "resourceExposurePolicy": { - "allowDebugging": false, - "allowDownloadingSource": true, - "includeSourceInSymbolFile": true - }, - "target": "OnPrem" + "id": "286fb38a-2023-4049-ae17-2445bd2e25b2", + "name": "Enforced Digital Vouchers Tests (DK)", + "publisher": "Microsoft", + "version": "25.0.0.0", + "brief": "Tests for the Enforced Digital Vouchers extension.", + "description": "Tests for the Enforced Digital Vouchers extension.", + "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", + "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", + "help": "https://go.microsoft.com/fwlink/?LinkId=724011", + "url": "https://go.microsoft.com/fwlink/?LinkId=724011", + "logo": "ExtensionLogo.png", + "platform": "25.0.0.0", + "application": "25.0.0.0", + "dependencies": [ + { + "id": "e2ae191d-8829-44c3-a373-3749a2742d4e", + "name": "Enforced Digital Vouchers", + "publisher": "Microsoft", + "version": "25.0.0.0" + }, + { + "id": "bb837764-d7cc-4b7b-898a-3ea5a1fab62f", + "name": "Enforced Digital Vouchers (DK)", + "publisher": "Microsoft", + "version": "25.0.0.0" + }, + { + "id": "928f7b70-0dbd-431a-beb5-f45c4adbd361", + "name": "Enforced Digital Vouchers Test Library", + "publisher": "Microsoft", + "version": "25.0.0.0" + }, + { + "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", + "name": "Tests-TestLibraries", + "publisher": "Microsoft", + "version": "25.0.0.0" + }, + { + "id": "9856ae4f-d1a7-46ef-89bb-6ef056398228", + "name": "System Application Test Library", + "publisher": "Microsoft", + "version": "25.0.0.0" + } + ], + "idRanges": [ + { + "from": 148016, + "to": 148016 + } + ], + "contextSensitiveHelpUrl": "https://go.microsoft.com/fwlink/?linkid=2141039", + "resourceExposurePolicy": { + "allowDebugging": false, + "allowDownloadingSource": true, + "includeSourceInSymbolFile": true + }, + "target": "OnPrem" } \ No newline at end of file diff --git a/Apps/DK/FIK/app/app.json b/Apps/DK/FIK/app/app.json index 44e33e436b..aa5ba94420 100644 --- a/Apps/DK/FIK/app/app.json +++ b/Apps/DK/FIK/app/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "Make fast, error-free payments by formatting payment data specifically for your vendor or bank.", "description": "This extension makes it easy to export payment information to files that you can send to your banks. This speeds up the payment and reconciliation processes, and cuts down on errors that can happen when you manually enter the information on a bank website.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=2194215", @@ -17,12 +17,12 @@ "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "target": "OnPrem", "resourceExposurePolicy": { "allowDebugging": false, "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/DK/FIK/test/app.json b/Apps/DK/FIK/test/app.json index b8a26eafe5..7157424743 100644 --- a/Apps/DK/FIK/test/app.json +++ b/Apps/DK/FIK/test/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "Tests for the Payment and Reconciliation Formats (DK) extension.", "description": "Tests for the Payment and Reconciliation Formats (DK) extension.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=865144", @@ -16,25 +16,25 @@ "id": "644f7e5b-a81c-408a-aaa2-766e655a80a3", "name": "Payment and Reconciliation Formats (DK)", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5095f467-0a01-4b99-99d1-9ff1237d286f", "publisher": "Microsoft", "name": "Library Variable Storage", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 139500, @@ -51,5 +51,5 @@ "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/DK/ImportDKPayroll/app/app.json b/Apps/DK/ImportDKPayroll/app/app.json index d7dc04c415..a7c5cb806a 100644 --- a/Apps/DK/ImportDKPayroll/app/app.json +++ b/Apps/DK/ImportDKPayroll/app/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "Install payroll services' data exchange definitions for Denmark", "description": "Install payroll services data exchange definitions for Danish service providers: Danloen, Dataloen, Loenservice, Multiloen and Proloen", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=858752", @@ -17,12 +17,12 @@ "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "target": "OnPrem", "resourceExposurePolicy": { "allowDebugging": false, "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/DK/ImportDKPayroll/test/app.json b/Apps/DK/ImportDKPayroll/test/app.json index 77b10de9bf..ef4b1c70cf 100644 --- a/Apps/DK/ImportDKPayroll/test/app.json +++ b/Apps/DK/ImportDKPayroll/test/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "Tests for the Payroll Data Import Definitions (DK) extension.", "description": "Tests for the Payroll Data Import Definitions (DK) extension.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=858752", @@ -16,19 +16,19 @@ "id": "a3c8a6e2-834a-4e73-b1f1-79e76b652659", "name": "Payroll Data Import Definitions (DK)", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 139500, @@ -45,5 +45,5 @@ "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/DK/NemhandelNotification/app/app.json b/Apps/DK/NemhandelNotification/app/app.json index 7198598d25..d0314c5262 100644 --- a/Apps/DK/NemhandelNotification/app/app.json +++ b/Apps/DK/NemhandelNotification/app/app.json @@ -1,45 +1,49 @@ { - "id": "3ef6b9df-8622-4b1f-8949-6a5c544fb224", - "name": "Nemhandel Notification in Denmark", - "publisher": "Microsoft", - "version": "24.0.0.0", - "brief": "If the Danish company isn't registered with Nemhandelsregisteret, users will receive a notification with registration instructions and they can follow the provided link to register.", - "description": "In the event that the Danish company is not currently registered with the Nemhandelsregisteret, an automated notification will be generated. This notification will provide comprehensive instructions on the steps to be taken in order to initiate the registration process together with the direct link, allowing the company to proceed with the registration procedure seamlessly.", - "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", - "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", - "help": "https://learn.microsoft.com/en-us/dynamics365/business-central/localfunctionality/denmark/denmark-local-functionality", - "contextSensitiveHelpUrl": "https://go.microsoft.com/fwlink/?linkid=2204541", - "url": "https://go.microsoft.com/fwlink/?LinkId=724011", - "logo": "ExtensionLogo.png", - "dependencies": [], - "internalsVisibleTo": [ - { - "id": "fffd8e0a-6be0-453d-bfcf-9c7bdb85b397", - "name": "Nemhandel Notification Tests", - "publisher": "Microsoft" - } - ], - "screenshots": [], - "platform": "24.0.0.0", - "application": "24.0.0.0", - "idRanges": [ - { - "from": 13608, - "to": 13610 - }, - { - "from": 13628, - "to": 13632 - }, - { - "from": 13658, - "to": 13659 - } - ], - "resourceExposurePolicy": { - "allowDebugging": true, - "allowDownloadingSource": true, - "includeSourceInSymbolFile": true - }, - "target": "Cloud" + "id": "3ef6b9df-8622-4b1f-8949-6a5c544fb224", + "name": "Nemhandel Notification in Denmark", + "publisher": "Microsoft", + "version": "25.0.0.0", + "brief": "If the Danish company isn't registered with Nemhandelsregisteret, users will receive a notification with registration instructions and they can follow the provided link to register.", + "description": "In the event that the Danish company is not currently registered with the Nemhandelsregisteret, an automated notification will be generated. This notification will provide comprehensive instructions on the steps to be taken in order to initiate the registration process together with the direct link, allowing the company to proceed with the registration procedure seamlessly.", + "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", + "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", + "help": "https://learn.microsoft.com/en-us/dynamics365/business-central/localfunctionality/denmark/denmark-local-functionality", + "contextSensitiveHelpUrl": "https://go.microsoft.com/fwlink/?linkid=2204541", + "url": "https://go.microsoft.com/fwlink/?LinkId=724011", + "logo": "ExtensionLogo.png", + "dependencies": [ + + ], + "internalsVisibleTo": [ + { + "id": "fffd8e0a-6be0-453d-bfcf-9c7bdb85b397", + "name": "Nemhandel Notification Tests", + "publisher": "Microsoft" + } + ], + "screenshots": [ + + ], + "platform": "25.0.0.0", + "application": "25.0.0.0", + "idRanges": [ + { + "from": 13608, + "to": 13610 + }, + { + "from": 13628, + "to": 13632 + }, + { + "from": 13658, + "to": 13659 + } + ], + "resourceExposurePolicy": { + "allowDebugging": true, + "allowDownloadingSource": true, + "includeSourceInSymbolFile": true + }, + "target": "Cloud" } \ No newline at end of file diff --git a/Apps/DK/NemhandelNotification/test/app.json b/Apps/DK/NemhandelNotification/test/app.json index c8fe7706e0..d7791c216f 100644 --- a/Apps/DK/NemhandelNotification/test/app.json +++ b/Apps/DK/NemhandelNotification/test/app.json @@ -1,49 +1,51 @@ { - "id": "fffd8e0a-6be0-453d-bfcf-9c7bdb85b397", - "name": "Nemhandel Notification Tests", - "publisher": "Microsoft", - "version": "24.0.0.0", - "brief": "Tests for the Nemhandel Notification extension.", - "description": "Tests for the Nemhandel Notification extension.", - "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", - "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", - "help": "https://learn.microsoft.com/en-us/dynamics365/business-central/localfunctionality/denmark/denmark-local-functionality", - "contextSensitiveHelpUrl": "https://go.microsoft.com/fwlink/?linkid=2204541", - "url": "https://go.microsoft.com/fwlink/?LinkId=724011", - "logo": "ExtensionLogo.png", - "dependencies": [ - { - "id": "3ef6b9df-8622-4b1f-8949-6a5c544fb224", - "name": "Nemhandel Notification in Denmark", - "publisher": "Microsoft", - "version": "24.0.0.0" - }, - { - "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", - "name": "Tests-TestLibraries", - "publisher": "Microsoft", - "version": "24.0.0.0" - }, - { - "id": "5095f467-0a01-4b99-99d1-9ff1237d286f", - "publisher": "Microsoft", - "name": "Library Variable Storage", - "version": "24.0.0.0" - } - ], - "screenshots": [], - "platform": "24.0.0.0", - "application": "24.0.0.0", - "idRanges": [ - { - "from": 148012, - "to": 148014 - } - ], - "resourceExposurePolicy": { - "allowDebugging": true, - "allowDownloadingSource": true, - "includeSourceInSymbolFile": true - }, - "target": "Cloud" + "id": "fffd8e0a-6be0-453d-bfcf-9c7bdb85b397", + "name": "Nemhandel Notification Tests", + "publisher": "Microsoft", + "version": "25.0.0.0", + "brief": "Tests for the Nemhandel Notification extension.", + "description": "Tests for the Nemhandel Notification extension.", + "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", + "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", + "help": "https://learn.microsoft.com/en-us/dynamics365/business-central/localfunctionality/denmark/denmark-local-functionality", + "contextSensitiveHelpUrl": "https://go.microsoft.com/fwlink/?linkid=2204541", + "url": "https://go.microsoft.com/fwlink/?LinkId=724011", + "logo": "ExtensionLogo.png", + "dependencies": [ + { + "id": "3ef6b9df-8622-4b1f-8949-6a5c544fb224", + "name": "Nemhandel Notification in Denmark", + "publisher": "Microsoft", + "version": "25.0.0.0" + }, + { + "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", + "name": "Tests-TestLibraries", + "publisher": "Microsoft", + "version": "25.0.0.0" + }, + { + "id": "5095f467-0a01-4b99-99d1-9ff1237d286f", + "publisher": "Microsoft", + "name": "Library Variable Storage", + "version": "25.0.0.0" + } + ], + "screenshots": [ + + ], + "platform": "25.0.0.0", + "application": "25.0.0.0", + "idRanges": [ + { + "from": 148012, + "to": 148014 + } + ], + "resourceExposurePolicy": { + "allowDebugging": true, + "allowDownloadingSource": true, + "includeSourceInSymbolFile": true + }, + "target": "Cloud" } \ No newline at end of file diff --git a/Apps/DK/OIOUBL/app/app.json b/Apps/DK/OIOUBL/app/app.json index 35fcf80fb1..701fe7e6cf 100644 --- a/Apps/DK/OIOUBL/app/app.json +++ b/Apps/DK/OIOUBL/app/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "Easily submit business documents in the Offentlig Information Online Universal Business Language (OIOUBL) format.", "description": "This extension makes it easy to meet the expectations of public authorities in Denmark for submitting invoices, credit memos, finance charge memos, and reminders for sales and services.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=2194213", @@ -17,12 +17,12 @@ "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "target": "OnPrem", "resourceExposurePolicy": { "allowDebugging": true, "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/DK/OIOUBL/app/src/SalesCreditMemo/OIOUBLCreateElecCrMemos.Report.al b/Apps/DK/OIOUBL/app/src/SalesCreditMemo/OIOUBLCreateElecCrMemos.Report.al index 30f726ccfd..e6fcce5d61 100644 --- a/Apps/DK/OIOUBL/app/src/SalesCreditMemo/OIOUBLCreateElecCrMemos.Report.al +++ b/Apps/DK/OIOUBL/app/src/SalesCreditMemo/OIOUBLCreateElecCrMemos.Report.al @@ -35,8 +35,13 @@ report 13631 "OIOUBL-Create Elec. Cr. Memos" end; trigger OnPostDataItem(); + var + SkipMessage: Boolean; begin - MESSAGE(SuccessMsg, Counter); + SkipMessage := false; + OnBeforeOnPostDataItemSalesCrMemoHeader(SkipMessage); + if not SkipMessage then + Message(SuccessMsg, Counter); end; trigger OnPreDataItem(); @@ -132,5 +137,10 @@ report 13631 "OIOUBL-Create Elec. Cr. Memos" begin LogInteraction := SegManagement.FindInteractionTemplateCode(6) <> ''; end; + + [IntegrationEvent(false, false)] + local procedure OnBeforeOnPostDataItemSalesCrMemoHeader(var SkipMessage: Boolean) + begin + end; } diff --git a/Apps/DK/OIOUBL/app/src/SalesInvoice/OIOUBLCreateElecInvoices.Report.al b/Apps/DK/OIOUBL/app/src/SalesInvoice/OIOUBLCreateElecInvoices.Report.al index b7bafc9b0d..b7cbba610a 100644 --- a/Apps/DK/OIOUBL/app/src/SalesInvoice/OIOUBLCreateElecInvoices.Report.al +++ b/Apps/DK/OIOUBL/app/src/SalesInvoice/OIOUBLCreateElecInvoices.Report.al @@ -34,8 +34,13 @@ report 13630 "OIOUBL-Create Elec. Invoices" end; trigger OnPostDataItem(); + var + SkipMessage: Boolean; begin - MESSAGE(SuccessMsg, Counter); + SkipMessage := false; + OnBeforeOnPostDataItemSalesInvoiceHeader(SkipMessage); + if not SkipMessage then + Message(SuccessMsg, Counter); end; trigger OnPreDataItem(); @@ -131,5 +136,10 @@ report 13630 "OIOUBL-Create Elec. Invoices" begin LogInteraction := SegManagement.FindInteractionTemplateCode(4) <> ''; end; + + [IntegrationEvent(false, false)] + local procedure OnBeforeOnPostDataItemSalesInvoiceHeader(var SkipMessage: Boolean) + begin + end; } diff --git a/Apps/DK/OIOUBL/test/app.json b/Apps/DK/OIOUBL/test/app.json index 95866b1e44..6704bc4257 100644 --- a/Apps/DK/OIOUBL/test/app.json +++ b/Apps/DK/OIOUBL/test/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "Tests for the OIOUBL extension.", "description": "Tests for the OIOUBL extension.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=865141", @@ -16,31 +16,31 @@ "id": "ac762be1-e90f-4a72-b519-612a5e3ddc2e", "name": "OIOUBL", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "9856ae4f-d1a7-46ef-89bb-6ef056398228", "name": "System Application Test Library", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5095f467-0a01-4b99-99d1-9ff1237d286f", "publisher": "Microsoft", "name": "Library Variable Storage", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 139500, @@ -57,5 +57,5 @@ "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/DK/OIOUBL/test/src/OIOUBLCheckSalesandService.Codeunit.al b/Apps/DK/OIOUBL/test/src/OIOUBLCheckSalesandService.Codeunit.al index d5e4e080f8..9a06440730 100644 --- a/Apps/DK/OIOUBL/test/src/OIOUBLCheckSalesandService.Codeunit.al +++ b/Apps/DK/OIOUBL/test/src/OIOUBLCheckSalesandService.Codeunit.al @@ -19,7 +19,6 @@ codeunit 148050 "OIOUBL-Check Sales and Service" LibraryService: Codeunit "Library - Service"; LibraryRandom: Codeunit "Library - Random"; Assert: Codeunit Assert; - NoSeriesManagement: Codeunit NoSeriesManagement; #pragma warning disable AA0470 NegSalesLineDiscountErr: Label 'Line Discount % cannot be negative in Sales Line Document Type=''%1'',Document No.=''%2'',Line No.=''%3''.'; NegServiceLineDiscountErr: Label 'Line Discount % cannot be negative in Service Line Document Type=''%1'',Document No.=''%2'',Line No.=''%3''.'; @@ -266,12 +265,13 @@ codeunit 148050 "OIOUBL-Check Sales and Service" ServiceLine1: Record "Service Line"; ServiceLine2: Record "Service Line"; GLEntry: Record "G/L Entry"; + NoSeries: Codeunit "No. Series"; PostedDocumentNo: Code[20]; begin // Setup: Create customer, Item and Service Credit Memo with one negative line but total amount is positive. CreateOIOUBLCustomer(Customer); CreateServiceHeader(ServiceHeader, ServiceHeader."Document Type"::"Credit Memo", Customer."No."); - PostedDocumentNo := NoSeriesManagement.GetNextNo(ServiceHeader."Posting No. Series", WORKDATE(), false); + PostedDocumentNo := NoSeries.PeekNextNo(ServiceHeader."Posting No. Series"); LibraryInventory.CreateItem(Item); // This Credit Memo has one line with negative Line Amount and Line Discount Amount but postive Line Discount %, diff --git a/Apps/DK/OIOUBL/test/src/OIOUBLERMElecDocumentSales.Codeunit.al b/Apps/DK/OIOUBL/test/src/OIOUBLERMElecDocumentSales.Codeunit.al index b711d3a7d8..8d74b30795 100644 --- a/Apps/DK/OIOUBL/test/src/OIOUBLERMElecDocumentSales.Codeunit.al +++ b/Apps/DK/OIOUBL/test/src/OIOUBLERMElecDocumentSales.Codeunit.al @@ -1511,7 +1511,7 @@ codeunit 148053 "OIOUBL-ERM Elec Document Sales" CountriesRegions.FindFirst(); // [GIVEN] Set OIOUBL-Country/Region Code to Blank for DK Code of Countries/Regions. - CountriesRegions.validate("OIOUBL-Country/Region Code", ''); + CountriesRegions.Validate("OIOUBL-Country/Region Code", ''); CountriesRegions.Modify(true); // [GIVEN] Create a Customer with Address. diff --git a/Apps/DK/OIOUBL/test/src/OIOUBLERMMiscElecInvoice.Codeunit.al b/Apps/DK/OIOUBL/test/src/OIOUBLERMMiscElecInvoice.Codeunit.al index cbcad29172..77445e882d 100644 --- a/Apps/DK/OIOUBL/test/src/OIOUBLERMMiscElecInvoice.Codeunit.al +++ b/Apps/DK/OIOUBL/test/src/OIOUBLERMMiscElecInvoice.Codeunit.al @@ -1227,14 +1227,14 @@ codeunit 148052 "OIOUBL-ERM Misc Elec. Invoice" var ServiceHeader: Record "Service Header"; ServiceLine: Record "Service Line"; - NoSeriesManagement: Codeunit NoSeriesManagement; + NoSeries: Codeunit "No. Series"; begin CreateServiceHeader(ServiceHeader, DocumentType); CreateServiceLine(ServiceLine, ServiceHeader); ServiceLine.VALIDATE(Description, Description); ServiceLine.MODIFY(true); DocumentNo := ServiceHeader."No."; - PostedInvoiceNo := NoSeriesManagement.GetNextNo(ServiceHeader."Posting No. Series", WORKDATE(), false); + PostedInvoiceNo := NoSeries.PeekNextNo(ServiceHeader."Posting No. Series"); LibraryService.PostServiceOrder(ServiceHeader, true, false, true); end; @@ -1243,14 +1243,14 @@ codeunit 148052 "OIOUBL-ERM Misc Elec. Invoice" ServiceHeader: Record "Service Header"; ServiceItemLine: Record "Service Item Line"; ServiceLine: Record "Service Line"; - NoSeriesManagement: Codeunit NoSeriesManagement; + NoSeries: Codeunit "No. Series"; begin CreateServiceHeader(ServiceHeader, ServiceHeader."Document Type"::Order); LibraryService.CreateServiceItemLine(ServiceItemLine, ServiceHeader, ''); // Blank for Service Item No. CreateServiceLine(ServiceLine, ServiceHeader); ServiceLine.VALIDATE("Service Item Line No.", ServiceItemLine."Line No."); ServiceLine.MODIFY(true); - PostedInvoiceNo := NoSeriesManagement.GetNextNo(ServiceHeader."Posting No. Series", WORKDATE(), false); + PostedInvoiceNo := NoSeries.PeekNextNo(ServiceHeader."Posting No. Series"); LibraryService.PostServiceOrder(ServiceHeader, true, false, true); end; diff --git a/Apps/DK/SAFTModificationDK/app/app.json b/Apps/DK/SAFTModificationDK/app/app.json index 7567b9bf74..7f61ab5faa 100644 --- a/Apps/DK/SAFTModificationDK/app/app.json +++ b/Apps/DK/SAFTModificationDK/app/app.json @@ -2,7 +2,7 @@ "id": "fed2a629-3c57-4250-b2b7-f3c7a9c53cd5", "name": "SAF-T Modification DK", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "SAF-T modification for Denmark.", "description": "SAF-T app modification is used to export audit data that is specific for Denmark.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -16,20 +16,20 @@ "id": "a41b0c3e-bf1c-4c97-ad1b-b430a3933ada", "name": "Audit File Export", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "4ce93371-6bd6-4027-a78f-021064ad250e", "name": "SAF-T", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 13687, diff --git a/Apps/DK/SAFTModificationDK/test/app.json b/Apps/DK/SAFTModificationDK/test/app.json index b0b3325058..24a1a7276d 100644 --- a/Apps/DK/SAFTModificationDK/test/app.json +++ b/Apps/DK/SAFTModificationDK/test/app.json @@ -2,7 +2,7 @@ "id": "b7fc717e-b79c-4548-b6dc-e27f895171f1", "name": "SAF-T Modification DK Tests", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Tests for the SAF-T Modification DK extension.", "description": "Tests for the SAF-T Modification DK extension.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -16,38 +16,38 @@ "id": "a41b0c3e-bf1c-4c97-ad1b-b430a3933ada", "name": "Audit File Export", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "4ce93371-6bd6-4027-a78f-021064ad250e", "name": "SAF-T", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "fed2a629-3c57-4250-b2b7-f3c7a9c53cd5", "name": "SAF-T Modification DK", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5095f467-0a01-4b99-99d1-9ff1237d286f", "publisher": "Microsoft", "name": "Library Variable Storage", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 148057, diff --git a/Apps/DK/VATReportsDK/app/app.json b/Apps/DK/VATReportsDK/app/app.json index dbf14d22bb..46cc606917 100644 --- a/Apps/DK/VATReportsDK/app/app.json +++ b/Apps/DK/VATReportsDK/app/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "The extension ensures that your export files are formatted correctly for reporting EU sales without VAT and Intrastat to Statistics Denmark and SKAT.", "description": "If you engage in trade with companies, or internal branches or subsidiaries, in other EU countries, you must report information about the activities to SKAT and to Statistics Denmark. If you use the VAT and Intrastat reporting features in Microsoft Dynamics 365 Business Central, the Tax File Formats (DK) extension makes sure that the exported file is compatible with requirements from these organizations. The extension is free, you just need to install it. The extension adds two new configurations to your VAT report configuration, MS-ECSL Report Export File and Intrastat Export Lines Submission, so you can export data in the new format right away.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=854447", @@ -17,12 +17,12 @@ "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "target": "OnPrem", "resourceExposurePolicy": { "allowDebugging": false, "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/DK/VATReportsDK/test/app.json b/Apps/DK/VATReportsDK/test/app.json index 78470f3616..0703313b7f 100644 --- a/Apps/DK/VATReportsDK/test/app.json +++ b/Apps/DK/VATReportsDK/test/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "Tests for the Tax File Formats (DK) extension.", "description": "Tests for the Tax File Formats (DK) extension.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=854447", @@ -16,19 +16,19 @@ "id": "2c97db9b-4aef-41e2-aa3e-03fa892c6815", "name": "Tax File Formats (DK)", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 139500, @@ -45,5 +45,5 @@ "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/ES/ContosoCoffeeDemoDatasetES/app/app.json b/Apps/ES/ContosoCoffeeDemoDatasetES/app/app.json index 68a52f6a04..f2d397c474 100644 --- a/Apps/ES/ContosoCoffeeDemoDatasetES/app/app.json +++ b/Apps/ES/ContosoCoffeeDemoDatasetES/app/app.json @@ -2,7 +2,7 @@ "id": "5b0a41a1-7b42-4123-a521-2265186cfb31", "name": "Contoso Coffee Demo Dataset (ES)", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "To help partners demonstrate the capabilities of Business Central, we are making new and extensive demo data available for various scenarios.", "description": "Presales specialists can run the tool on top of Cronus or My Company and get the setup and demo data they'll need when they demonstrate various scenarios.", "privacyStatement": "https://go.microsoft.com/fwlink/?linkid=724009", @@ -16,14 +16,14 @@ "id": "5a0b41e9-7a42-4123-d521-2265186cfb31", "name": "Contoso Coffee Demo Dataset", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 10780, diff --git a/Apps/ES/HybridBCLast_ES/app/app.json b/Apps/ES/HybridBCLast_ES/app/app.json index 46e130e478..875d412fae 100644 --- a/Apps/ES/HybridBCLast_ES/app/app.json +++ b/Apps/ES/HybridBCLast_ES/app/app.json @@ -2,7 +2,7 @@ "id": "6babad6a-c6b1-4842-b3e2-50c3db9085d7", "name": "Business Central Cloud Migration - Previous Release (ES)", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Enables data migration from the previous version of Dynamics BC (n-1) to the current release of Dynamics 365 Business Central SaaS.", "description": "This extension, in conjuction with the Business Central Cloud Migration Previous Release, will enable you to migrate data from your Business Central on-premises solution for Spain to your Dynamics 365 Business Central cloud tenant for Spain. This extension is required to update country specific tables. Once you have walked through the cloud migration wizard in assisted setup, you will be able to migrate your data from your on-premises environment to your cloud tenant.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -15,25 +15,25 @@ { "publisher": "Microsoft", "name": "Intelligent Cloud Base", - "version": "24.0.0.0", + "version": "25.0.0.0", "id": "58623bfa-0559-4bc2-ae1c-0979c29fd9e0" }, { "publisher": "Microsoft", "name": "Business Central Cloud Migration - Previous Release", - "version": "24.0.0.0", + "version": "25.0.0.0", "id": "6992416f-3f39-4d3c-8242-3fff61350bea" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "resourceExposurePolicy": { "allowDebugging": false, "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, "target": "OnPrem", - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/ES/IntrastatES/app/app.json b/Apps/ES/IntrastatES/app/app.json index 068f677b66..245af930a2 100644 --- a/Apps/ES/IntrastatES/app/app.json +++ b/Apps/ES/IntrastatES/app/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "The Intrastat extension makes it easy to export the Intrastat report in the format that the authorities in your country require.", "description": "The formats that businesses must use to report Intrastat vary from country to country. The Intrastat extension makes it easy to export the Intrastat report in the format that the authorities in your country require.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=2204541", @@ -16,13 +16,13 @@ "id": "70912191-3c4c-49fc-a1de-bc6ea1ac9da6", "name": "Intrastat Core", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 10790, @@ -34,6 +34,6 @@ "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0", + "application": "25.0.0.0", "target": "Cloud" } \ No newline at end of file diff --git a/Apps/ES/Onprem Permissions ES/app/app.json b/Apps/ES/Onprem Permissions ES/app/app.json index ef485c9ee5..aa3ae3dd56 100644 --- a/Apps/ES/Onprem Permissions ES/app/app.json +++ b/Apps/ES/Onprem Permissions ES/app/app.json @@ -2,7 +2,7 @@ "id": "5c9d84f2-7ad0-4b05-9dfc-5440df33fe02", "name": "OnPrem Permissions (ES)", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "This extension includes permission set for on premise systems.", "description": "This extension includes permission set for on premise systems.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -17,12 +17,12 @@ "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "resourceExposurePolicy": { "allowDebugging": false, "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, "target": "OnPrem", - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/FI/ContosoCoffeeDemoDatasetFI/app/app.json b/Apps/FI/ContosoCoffeeDemoDatasetFI/app/app.json index 0600589caa..1fe0beaa07 100644 --- a/Apps/FI/ContosoCoffeeDemoDatasetFI/app/app.json +++ b/Apps/FI/ContosoCoffeeDemoDatasetFI/app/app.json @@ -2,7 +2,7 @@ "id": "5b0a31a1-6b42-4123-a521-2265186cfb31", "name": "Contoso Coffee Demo Dataset (FI)", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "To help partners demonstrate the capabilities of Business Central, we are making new and extensive demo data available for various scenarios.", "description": "Presales specialists can run the tool on top of Cronus or My Company and get the setup and demo data they'll need when they demonstrate various scenarios.", "privacyStatement": "https://go.microsoft.com/fwlink/?linkid=724009", @@ -16,14 +16,14 @@ "id": "5a0b41e9-7a42-4123-d521-2265186cfb31", "name": "Contoso Coffee Demo Dataset", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 13400, diff --git a/Apps/FI/FICore/app/app.json b/Apps/FI/FICore/app/app.json index 90ad1365db..cac802f656 100644 --- a/Apps/FI/FICore/app/app.json +++ b/Apps/FI/FICore/app/app.json @@ -2,7 +2,7 @@ "id": "8038abf4-6fc9-4212-ac03-1137b06ca8ca", "name": "FI Core", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Provides standard local functionality in Business Central for Finland.", "description": "Provides standard local functionality in Business Central for Finland.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -17,8 +17,8 @@ "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 13411, diff --git a/Apps/FI/FICore/test/app.json b/Apps/FI/FICore/test/app.json index 2c5555efe4..9997edcd94 100644 --- a/Apps/FI/FICore/test/app.json +++ b/Apps/FI/FICore/test/app.json @@ -2,7 +2,7 @@ "id": "5fa3b1f0-054d-4b96-a2af-cd57d4114930", "name": "FI Core Tests", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Tests for the Core Localization for Finland.", "description": "Tests for the Core Localization for Finland.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -16,20 +16,20 @@ "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "8038abf4-6fc9-4212-ac03-1137b06ca8ca", "name": "FI Core", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 148150, diff --git a/Apps/FI/IntrastatFI/app/app.json b/Apps/FI/IntrastatFI/app/app.json index 89c7c2c047..ab61c6be3f 100644 --- a/Apps/FI/IntrastatFI/app/app.json +++ b/Apps/FI/IntrastatFI/app/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "The Intrastat extension makes it easy to export the Intrastat report in the format that the authorities in your country require.", "description": "The formats that businesses must use to report Intrastat vary from country to country. The Intrastat extension makes it easy to export the Intrastat report in the format that the Finish authorities require.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=2212316", @@ -16,13 +16,13 @@ "id": "70912191-3c4c-49fc-a1de-bc6ea1ac9da6", "name": "Intrastat Core", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 13406, @@ -34,6 +34,6 @@ "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0", + "application": "25.0.0.0", "target": "Cloud" } \ No newline at end of file diff --git a/Apps/FR/ContosoCoffeeDemoDatasetFR/app/app.json b/Apps/FR/ContosoCoffeeDemoDatasetFR/app/app.json index 7fc907e74d..383ec36648 100644 --- a/Apps/FR/ContosoCoffeeDemoDatasetFR/app/app.json +++ b/Apps/FR/ContosoCoffeeDemoDatasetFR/app/app.json @@ -2,7 +2,7 @@ "id": "5b0a41a1-7b42-4123-a631-2265186cfb31", "name": "Contoso Coffee Demo Dataset (FR)", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "To help partners demonstrate the capabilities of Business Central, we are making new and extensive demo data available for various scenarios.", "description": "Presales specialists can run the tool on top of Cronus or My Company and get the setup and demo data they'll need when they demonstrate various scenarios.", "privacyStatement": "https://go.microsoft.com/fwlink/?linkid=724009", @@ -16,14 +16,14 @@ "id": "5a0b41e9-7a42-4123-d521-2265186cfb31", "name": "Contoso Coffee Demo Dataset", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 10850, diff --git a/Apps/FR/FECAuditFile/app/app.json b/Apps/FR/FECAuditFile/app/app.json index 90f5b29bbe..6cdefd962f 100644 --- a/Apps/FR/FECAuditFile/app/app.json +++ b/Apps/FR/FECAuditFile/app/app.json @@ -2,9 +2,9 @@ "id": "e98078ff-1f85-442b-828f-9f73ce6c4e22", "name": "FEC Audit File", "publisher": "Microsoft", - "version": "24.0.0.0", - "brief": "The FEC Audit File extension makes it easy to export general ledger data in the Fichier des écritures comptables (FEC) format.", - "description": "As a part of the audit reporting in France, companies must be able to export general ledger data according to the Fichier des écritures comptables (FEC) format. This extension enables using FEC format within Audit File Export app.", + "version": "25.0.0.0", + "brief": "The FEC Audit File extension makes it easy to export general ledger data in the Fichier des écritures comptables (FEC) format.", + "description": "As a part of the audit reporting in France, companies must be able to export general ledger data according to the Fichier des écritures comptables (FEC) format. This extension enables using FEC format within Audit File Export app.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://learn.microsoft.com/en-us/dynamics365/business-central/localfunctionality/france/how-to-export-general-ledger-entries-for-tax-audits", @@ -16,14 +16,14 @@ "id": "a41b0c3e-bf1c-4c97-ad1b-b430a3933ada", "name": "Audit File Export", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 10826, diff --git a/Apps/FR/FECAuditFile/test/app.json b/Apps/FR/FECAuditFile/test/app.json index 22781fb09e..8e997e1b8d 100644 --- a/Apps/FR/FECAuditFile/test/app.json +++ b/Apps/FR/FECAuditFile/test/app.json @@ -2,7 +2,7 @@ "id": "cae0f499-d82c-48ff-861f-3e8c7d6049da", "name": "FEC Audit File Tests", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Tests for the FEC Audit File extension.", "description": "Tests for the FEC Audit File extension.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -16,32 +16,32 @@ "id": "e98078ff-1f85-442b-828f-9f73ce6c4e22", "name": "FEC Audit File", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "a41b0c3e-bf1c-4c97-ad1b-b430a3933ada", "name": "Audit File Export", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "9856ae4f-d1a7-46ef-89bb-6ef056398228", "name": "System Application Test Library", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 148017, diff --git a/Apps/FR/HybridBCLast_FR/app/app.json b/Apps/FR/HybridBCLast_FR/app/app.json index 297a048d2e..49c7c47cdf 100644 --- a/Apps/FR/HybridBCLast_FR/app/app.json +++ b/Apps/FR/HybridBCLast_FR/app/app.json @@ -2,7 +2,7 @@ "id": "c27291fd-0b3c-45c9-ae9e-96e223dd50cd", "name": "Business Central Cloud Migration - Previous Release (FR)", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Enables data migration from the previous version of Dynamics BC (n-1) to the current release of Dynamics 365 Business Central SaaS.", "description": "This extension, in conjuction with the Business Central Cloud Migration Previous Release, will enable you to migrate data from your Business Central on-premises solution for France to your Dynamics 365 Business Central cloud tenant for France. This extension is required to update country specific tables. Once you have walked through the cloud migration wizard in assisted setup, you will be able to migrate your data from your on-premises environment to your cloud tenant.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -15,25 +15,25 @@ { "publisher": "Microsoft", "name": "Intelligent Cloud Base", - "version": "24.0.0.0", + "version": "25.0.0.0", "id": "58623bfa-0559-4bc2-ae1c-0979c29fd9e0" }, { "publisher": "Microsoft", "name": "Business Central Cloud Migration - Previous Release", - "version": "24.0.0.0", + "version": "25.0.0.0", "id": "6992416f-3f39-4d3c-8242-3fff61350bea" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "resourceExposurePolicy": { "allowDebugging": false, "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, "target": "OnPrem", - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/FR/IntrastatFR/app/app.json b/Apps/FR/IntrastatFR/app/app.json index cfd1a3bb1c..87d33d3aff 100644 --- a/Apps/FR/IntrastatFR/app/app.json +++ b/Apps/FR/IntrastatFR/app/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "The Intrastat extension makes it easy to export the Intrastat report in the format that the authorities in your country require.", "description": "The formats that businesses must use to report Intrastat vary from country to country. The Intrastat extension makes it easy to export the Intrastat report in the format that the authorities in your country require.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=2204541", @@ -16,13 +16,13 @@ "id": "70912191-3c4c-49fc-a1de-bc6ea1ac9da6", "name": "Intrastat Core", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 10851, @@ -34,6 +34,6 @@ "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0", + "application": "25.0.0.0", "target": "Cloud" } \ No newline at end of file diff --git a/Apps/FR/IntrastatFR/test/app.json b/Apps/FR/IntrastatFR/test/app.json index 023d4c9196..fad0519cdf 100644 --- a/Apps/FR/IntrastatFR/test/app.json +++ b/Apps/FR/IntrastatFR/test/app.json @@ -2,7 +2,7 @@ "id": "c74ba2fa-f1bb-453c-8d72-1f4ccdd1288a", "name": "Intrastat FR Tests", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Tests for the Microsoft Intrastat FR extension.", "description": "Tests for the Microsoft Intrastat FR extension.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -10,44 +10,44 @@ "help": "https://go.microsoft.com/fwlink/?linkid=2179727", "url": "https://go.microsoft.com/fwlink/?LinkId=724011", "logo": "ExtensionLogo.png", - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "dependencies": [ { "id": "1096d1ca-2c0c-4a0e-aa0d-c734021aba2b", "name": "Intrastat FR", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "70912191-3c4c-49fc-a1de-bc6ea1ac9da6", "name": "Intrastat Core", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "9856ae4f-d1a7-46ef-89bb-6ef056398228", "name": "System Application Test Library", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5095f467-0a01-4b99-99d1-9ff1237d286f", "publisher": "Microsoft", "name": "Library Variable Storage", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "f4d9555a-a512-45de-a6d6-27a8b6077139", "name": "Intrastat Core Tests", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "idRanges": [ diff --git a/Apps/FR/Onprem Permissions FR/app/app.json b/Apps/FR/Onprem Permissions FR/app/app.json index 7beda55856..3a1d0dc4cc 100644 --- a/Apps/FR/Onprem Permissions FR/app/app.json +++ b/Apps/FR/Onprem Permissions FR/app/app.json @@ -2,7 +2,7 @@ "id": "e6ba5021-9152-4929-8953-e0007e72db61", "name": "OnPrem Permissions (FR)", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "This extension includes permission set for on premise systems.", "description": "This extension includes permission set for on premise systems.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -17,12 +17,12 @@ "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "resourceExposurePolicy": { "allowDebugging": false, "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, "target": "OnPrem", - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/FR/ServiceDeclarationFR/app/app.json b/Apps/FR/ServiceDeclarationFR/app/app.json index c21f9d4b00..0c0ddbbc49 100644 --- a/Apps/FR/ServiceDeclarationFR/app/app.json +++ b/Apps/FR/ServiceDeclarationFR/app/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "The Service Declaration extension makes it easy to export the service declaration in the format that the authorities in your country require.", "description": "In some EU countries, authorities require reporting for exporting services to the other EU countries. This feature enables collecting EU service''s intertrade and its reporting to the authorities. Even this feature is primarily created for Belgian, French and Italian markets, it can be used in all EU countries if needed as reporting is configurable.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://learn.microsoft.com/en-us/dynamics365/business-central/finance-how-setup-use-service-declaration", @@ -16,13 +16,13 @@ "id": "e2ae191d-8829-44c3-a373-3749a2742d4d", "name": "Service Declaration", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 10890, @@ -34,6 +34,6 @@ "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0", + "application": "25.0.0.0", "target": "Cloud" } \ No newline at end of file diff --git a/Apps/FR/ServiceDeclarationFR/test/app.json b/Apps/FR/ServiceDeclarationFR/test/app.json index 958773e4c7..1c5e0e6d4d 100644 --- a/Apps/FR/ServiceDeclarationFR/test/app.json +++ b/Apps/FR/ServiceDeclarationFR/test/app.json @@ -2,7 +2,7 @@ "id": "4468b2c6-e396-446f-9235-4a941c30b7b3", "name": "Service Declaration FR Tests", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Tests for the Microsoft Service Declaration FR extension.", "description": "Tests for the Microsoft Service Declaration FR extension.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -10,38 +10,38 @@ "help": "https://learn.microsoft.com/en-us/dynamics365/business-central/finance-how-setup-use-service-declaration", "url": "https://go.microsoft.com/fwlink/?LinkId=724011", "logo": "ExtensionLogo.png", - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "dependencies": [ { "id": "e2ae191d-8829-44c3-a373-3749a2742d4d", "name": "Service Declaration", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "1f6c7b3c-084d-49b6-b87c-41ae0f0e24f2", "name": "Service Declaration FR", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "9856ae4f-d1a7-46ef-89bb-6ef056398228", "name": "System Application Test Library", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5095f467-0a01-4b99-99d1-9ff1237d286f", "publisher": "Microsoft", "name": "Library Variable Storage", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "idRanges": [ diff --git a/Apps/GB/ContosoCoffeeDemoDatasetGB/app/app.json b/Apps/GB/ContosoCoffeeDemoDatasetGB/app/app.json index b7d1b3f99b..dc6519b1cb 100644 --- a/Apps/GB/ContosoCoffeeDemoDatasetGB/app/app.json +++ b/Apps/GB/ContosoCoffeeDemoDatasetGB/app/app.json @@ -2,7 +2,7 @@ "id": "5b0b41a1-7b42-4153-b521-2265186cfb33", "name": "Contoso Coffee Demo Dataset (GB)", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "To help partners demonstrate the capabilities of Business Central, we are making new and extensive demo data available for various scenarios.", "description": "Presales specialists can run the tool on top of Cronus or My Company and get the setup and demo data they'll need when they demonstrate various scenarios.", "privacyStatement": "https://go.microsoft.com/fwlink/?linkid=724009", @@ -16,14 +16,14 @@ "id": "5a0b41e9-7a42-4123-d521-2265186cfb31", "name": "Contoso Coffee Demo Dataset", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 10506, diff --git a/Apps/GB/IntrastatGB/app/app.json b/Apps/GB/IntrastatGB/app/app.json index d99b1723cf..67d9b30973 100644 --- a/Apps/GB/IntrastatGB/app/app.json +++ b/Apps/GB/IntrastatGB/app/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "The Intrastat extension makes it easy to export the Intrastat report in the format that the authorities in your country require.", "description": "The formats that businesses must use to report Intrastat vary from country to country. The Intrastat Core extension makes it easy to export the Intrastat report in the format that the British authorities require.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=2212316", @@ -16,13 +16,13 @@ "id": "70912191-3c4c-49fc-a1de-bc6ea1ac9da6", "name": "Intrastat Core", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 10500, @@ -34,6 +34,6 @@ "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0", + "application": "25.0.0.0", "target": "Cloud" } \ No newline at end of file diff --git a/Apps/GB/IntrastatGB/test/app.json b/Apps/GB/IntrastatGB/test/app.json index 160c30308c..b8a23bfb36 100644 --- a/Apps/GB/IntrastatGB/test/app.json +++ b/Apps/GB/IntrastatGB/test/app.json @@ -2,7 +2,7 @@ "id": "f4d9553a-a512-45de-a6d6-27a8b6077139", "name": "Intrastat GB Tests", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Tests for the Microsoft Intrastat GB extension.", "description": "Tests for the Microsoft Intrastat GB extension.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -10,44 +10,44 @@ "help": "https://go.microsoft.com/fwlink/?linkid=2212316", "url": "https://go.microsoft.com/fwlink/?LinkId=724011", "logo": "ExtensionLogo.png", - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "dependencies": [ { "id": "70912191-3c4c-49fc-a1de-bc6ea1ac9da6", "name": "Intrastat Core", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "64977288-facd-4a48-aaaa-bb0e288edfb3", "name": "Intrastat GB", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "9856ae4f-d1a7-46ef-89bb-6ef056398228", "name": "System Application Test Library", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5095f467-0a01-4b99-99d1-9ff1237d286f", "publisher": "Microsoft", "name": "Library Variable Storage", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "f4d9555a-a512-45de-a6d6-27a8b6077139", "publisher": "Microsoft", "name": "Intrastat Core Tests", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "idRanges": [ diff --git a/Apps/GB/UKMakingTaxDigital/app/app.json b/Apps/GB/UKMakingTaxDigital/app/app.json index a13751c9db..ec2606c9ff 100644 --- a/Apps/GB/UKMakingTaxDigital/app/app.json +++ b/Apps/GB/UKMakingTaxDigital/app/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "Get an overview of your VAT and easily submit VAT return to HMRC", "description": "Being on top of VAT returns and getting an overview of your company's VAT is a critical part of running a business. This app provides functionality that gives you an overview of your VAT payments and liabilities and also integrates Dynamics 365 Business Central with the HMRC for easy submission of the VAT return. With this app you can easily comply with the requirements of Making Tax Digital.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=2047615", @@ -24,12 +24,12 @@ "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "target": "OnPrem", "resourceExposurePolicy": { "allowDebugging": false, "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/GB/UKMakingTaxDigital/app/src/Connection/MTDOAuth20Mgt.Codeunit.al b/Apps/GB/UKMakingTaxDigital/app/src/Connection/MTDOAuth20Mgt.Codeunit.al index 309cbd4ffe..bcfc91bbe3 100644 --- a/Apps/GB/UKMakingTaxDigital/app/src/Connection/MTDOAuth20Mgt.Codeunit.al +++ b/Apps/GB/UKMakingTaxDigital/app/src/Connection/MTDOAuth20Mgt.Codeunit.al @@ -172,12 +172,12 @@ codeunit 10538 "MTD OAuth 2.0 Mgt" CheckOAuthConsistencySetup(OAuth20Setup); UpdateClientTokens(OAuth20Setup); if not EnvironmentInfo.IsSaaS() then begin - Hyperlink(OAuth20Mgt.GetAuthorizationURL(OAuth20Setup, GetToken(OAuth20Setup."Client ID", OAuth20Setup.GetTokenDataScope()))); + Hyperlink(OAuth20Mgt.GetAuthorizationURLAsSecretText(OAuth20Setup, GetToken(OAuth20Setup."Client ID", OAuth20Setup.GetTokenDataScope()).Unwrap()).Unwrap()); exit; end; state := Format(CreateGuid(), 0, 4); - url := OAuth20Mgt.GetAuthorizationURL(OAuth20Setup, GetToken(OAuth20Setup."Client ID", OAuth20Setup.GetTokenDataScope())) + '&state=' + state; + url := OAuth20Mgt.GetAuthorizationURLAsSecretText(OAuth20Setup, GetToken(OAuth20Setup."Client ID", OAuth20Setup.GetTokenDataScope()).Unwrap() + '&state=' + state).Unwrap(); OAuth2ControlAddIn.SetOAuth2Properties(url, state); OAuth2ControlAddIn.RunModal(); @@ -193,14 +193,14 @@ codeunit 10538 "MTD OAuth 2.0 Mgt" end; end; - [NonDebuggable] [EventSubscriber(ObjectType::Table, Database::"OAuth 2.0 Setup", 'OnBeforeRequestAccessToken', '', true, true)] + [NonDebuggable] local procedure OnBeforeRequestAccessToken(var OAuth20Setup: Record "OAuth 2.0 Setup"; AuthorizationCode: Text; var Result: Boolean; var MessageText: Text; var Processed: Boolean) var MTDSessionFraudPrevHdr: Record "MTD Session Fraud Prev. Hdr"; RequestJSON: Text; - AccessToken: Text; - RefreshToken: Text; + AccessToken: SecretText; + RefreshToken: SecretText; TokenDataScope: DataScope; begin if not IsMTDOAuthSetup(OAuth20Setup) or Processed then @@ -216,7 +216,7 @@ codeunit 10538 "MTD OAuth 2.0 Mgt" Result := OAuth20Mgt.RequestAccessTokenWithGivenRequestJson( OAuth20Setup, RequestJSON, MessageText, AuthorizationCode, - GetToken(OAuth20Setup."Client ID", TokenDataScope), + GetToken(OAuth20Setup."Client ID", TokenDataScope).Unwrap(), GetToken(OAuth20Setup."Client Secret", TokenDataScope), AccessToken, RefreshToken); @@ -242,8 +242,8 @@ codeunit 10538 "MTD OAuth 2.0 Mgt" local procedure OnBeforeRefreshAccessToken(var OAuth20Setup: Record "OAuth 2.0 Setup"; var Result: Boolean; var MessageText: Text; var Processed: Boolean) var RequestJSON: Text; - AccessToken: Text; - RefreshToken: Text; + AccessToken: SecretText; + RefreshToken: SecretText; TokenDataScope: DataScope; begin if not IsMTDOAuthSetup(OAuth20Setup) or Processed then @@ -259,7 +259,7 @@ codeunit 10538 "MTD OAuth 2.0 Mgt" Result := OAuth20Mgt.RefreshAccessTokenWithGivenRequestJson( OAuth20Setup, RequestJSON, MessageText, - GetToken(OAuth20Setup."Client ID", TokenDataScope), + GetToken(OAuth20Setup."Client ID", TokenDataScope).Unwrap(), GetToken(OAuth20Setup."Client Secret", TokenDataScope), AccessToken, RefreshToken); @@ -268,7 +268,7 @@ codeunit 10538 "MTD OAuth 2.0 Mgt" end; [NonDebuggable] - local procedure SaveTokens(var OAuth20Setup: Record "OAuth 2.0 Setup"; TokenDataScope: DataScope; AccessToken: Text; RefreshToken: Text) + local procedure SaveTokens(var OAuth20Setup: Record "OAuth 2.0 Setup"; TokenDataScope: DataScope; AccessToken: SecretText; RefreshToken: SecretText) var TypeHelper: Codeunit "Type Helper"; NewAccessTokenDateTime: DateTime; @@ -309,7 +309,7 @@ codeunit 10538 "MTD OAuth 2.0 Mgt" EnvironmentInformation: Codeunit "Environment Information"; AzureClientIDTxt: Text; AzureClientSecretTxt: Text; - KeyValue: Text; + KeyValue: SecretText; IsModify: Boolean; TokenDataScope: DataScope; begin @@ -325,19 +325,19 @@ codeunit 10538 "MTD OAuth 2.0 Mgt" end; TokenDataScope := OAuth20Setup.GetTokenDataScope(); if AzureKeyVault.GetAzureKeyVaultSecret(AzureClientIDTxt, KeyValue) then - if KeyValue <> '' then - if KeyValue <> GetToken(OAuth20Setup."Client ID", TokenDataScope) then + if not KeyValue.IsEmpty() then + if KeyValue.Unwrap() <> GetToken(OAuth20Setup."Client ID", TokenDataScope).Unwrap() then IsModify := SetToken(OAuth20Setup."Client ID", KeyValue, TokenDataScope); if AzureKeyVault.GetAzureKeyVaultSecret(AzureClientSecretTxt, KeyValue) then - if KeyValue <> '' then - if KeyValue <> GetToken(OAuth20Setup."Client Secret", TokenDataScope) then + if not KeyValue.IsEmpty() then + if KeyValue.Unwrap() <> GetToken(OAuth20Setup."Client Secret", TokenDataScope).Unwrap() then IsModify := SetToken(OAuth20Setup."Client Secret", KeyValue, TokenDataScope); if IsModify then OAuth20Setup.Modify(); end; [NonDebuggable] - internal procedure SetToken(var TokenKey: Guid; TokenValue: Text; TokenDataScope: DataScope) NewToken: Boolean + internal procedure SetToken(var TokenKey: Guid; TokenValue: SecretText; TokenDataScope: DataScope) NewToken: Boolean begin if IsNullGuid(TokenKey) then NewToken := true; @@ -350,11 +350,10 @@ codeunit 10538 "MTD OAuth 2.0 Mgt" IsolatedStorage.Set(TokenKey, TokenValue, TokenDataScope); end; - [NonDebuggable] - local procedure GetToken(TokenKey: Guid; TokenDataScope: DataScope) TokenValue: Text + local procedure GetToken(TokenKey: Guid; TokenDataScope: DataScope) TokenValue: SecretText begin if not HasToken(TokenKey, TokenDataScope) then - exit(''); + exit(TokenValue); IsolatedStorage.Get(TokenKey, TokenDataScope, TokenValue); end; diff --git a/Apps/GB/UKMakingTaxDigital/test/app.json b/Apps/GB/UKMakingTaxDigital/test/app.json index 70cdac73a9..c43b48e54b 100644 --- a/Apps/GB/UKMakingTaxDigital/test/app.json +++ b/Apps/GB/UKMakingTaxDigital/test/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "Tests for the Making Tax Digital Localization for United Kingdom extension.", "description": "Tests for the Making Tax Digital Localization for United Kingdom extension.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=2047615", @@ -16,31 +16,31 @@ "id": "38fa97fa-ebd1-4862-af24-77c4cee2c6ca", "name": "Making Tax Digital Localization for United Kingdom", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "9856ae4f-d1a7-46ef-89bb-6ef056398228", "name": "System Application Test Library", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5095f467-0a01-4b99-99d1-9ff1237d286f", "publisher": "Microsoft", "name": "Library Variable Storage", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 139500, @@ -57,5 +57,5 @@ "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/GB/UKMakingTaxDigital/test/src/LibraryMakingTaxDigital.Codeunit.al b/Apps/GB/UKMakingTaxDigital/test/src/LibraryMakingTaxDigital.Codeunit.al index 3c0090e478..7a1b7ae652 100644 --- a/Apps/GB/UKMakingTaxDigital/test/src/LibraryMakingTaxDigital.Codeunit.al +++ b/Apps/GB/UKMakingTaxDigital/test/src/LibraryMakingTaxDigital.Codeunit.al @@ -355,13 +355,21 @@ codeunit 148080 "Library - Making Tax Digital" end; local procedure SetOAuthSetupTestTokens(var OAuth20Setup: Record "OAuth 2.0 Setup") - begin - with OAuth20Setup do begin - SetToken("Client ID", 'Dummy Test Client ID'); - SetToken("Client Secret", 'Dummy Test Client Secret'); - SetToken("Access Token", 'Dummy Test Access Token'); - SetToken("Refresh Token", 'Dummy Test Refresh Token'); - end; + var + ClientIdText: Text; + ClientSecretText: Text; + AccessTokenText: Text; + RefreshTokenText: Text; + begin + ClientIdText := 'Dummy Test Client ID'; + ClientSecretText := 'Dummy Test Client Secret'; + AccessTokenText := 'Dummy Test Access Token'; + RefreshTokenText := 'Dummy Test Refresh Token'; + + OAuth20Setup.SetToken(OAuth20Setup."Client ID", ClientIdText); + OAuth20Setup.SetToken(OAuth20Setup."Client Secret", ClientSecretText); + OAuth20Setup.SetToken(OAuth20Setup."Access Token", AccessTokenText); + OAuth20Setup.SetToken(OAuth20Setup."Refresh Token", RefreshTokenText); end; internal procedure SetOAuthSetupSandbox(IsSandbox: Boolean) diff --git a/Apps/GB/UKPostcodeGetAddressIO/app/app.json b/Apps/GB/UKPostcodeGetAddressIO/app/app.json index 4ca819075a..8bf56d21a3 100644 --- a/Apps/GB/UKPostcodeGetAddressIO/app/app.json +++ b/Apps/GB/UKPostcodeGetAddressIO/app/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "Get accurate addresses in United Kingdom based on post codes", "description": "Accurate addresses are a must if you ship goods or delivering marketing materials. This extension connects to an external service to verify and get the correct address based on a local address database. Whenever you specify a customer, vendor, contact, or any address in the United Kingdom, this extension helps you make verify that you got the right address.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=839464", @@ -22,7 +22,7 @@ "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "target": "OnPrem", - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/GB/UKPostcodeGetAddressIO/app/src/GetAddressioConfig.Page.al b/Apps/GB/UKPostcodeGetAddressIO/app/src/GetAddressioConfig.Page.al index ab08b1c0cc..20d1237907 100644 --- a/Apps/GB/UKPostcodeGetAddressIO/app/src/GetAddressioConfig.Page.al +++ b/Apps/GB/UKPostcodeGetAddressIO/app/src/GetAddressioConfig.Page.al @@ -20,12 +20,13 @@ page 9142 "GetAddress.io Config" ApplicationArea = Basic, Suite; ToolTip = 'API Key for GetAddress.io'; ShowCaption = false; + ExtendedDatatype = Masked; trigger OnValidate() begin ValidateApiKey(); - Rec.SaveAPIKey(Rec.APIKey, APIKeyText); + Rec.SaveAPIKeyAsSecret(Rec.APIKey, APIKeyText); UpdateAPIField(); end; } diff --git a/Apps/GB/UKPostcodeGetAddressIO/app/src/PostcodeGetAddressioConfig.Table.al b/Apps/GB/UKPostcodeGetAddressIO/app/src/PostcodeGetAddressioConfig.Table.al index 6b7bd3f738..3d95c80dba 100644 --- a/Apps/GB/UKPostcodeGetAddressIO/app/src/PostcodeGetAddressioConfig.Table.al +++ b/Apps/GB/UKPostcodeGetAddressIO/app/src/PostcodeGetAddressioConfig.Table.al @@ -22,25 +22,50 @@ table 9092 "Postcode GetAddress.io Config" key(Key1; "Primary Key") { } } +#if not CLEAN24 [NonDebuggable] [Scope('OnPrem')] + [Obsolete('Use GetAPIKeyAsSecret() instead.', '24.0')] procedure GetAPIKey(APIKeyGUID: Guid): Text var - APIPassword: Text; + APIPassword: SecretText; begin if IsNullGuid(APIKeyGUID) or not IsolatedStorage.Get(APIKeyGUID, Datascope::Company, APIPassword) then exit(''); + exit(APIPassword.Unwrap()); + end; +#endif + + [Scope('OnPrem')] + procedure GetAPIPasswordAsSecret(APIKeyGUID: Guid): SecretText + var + APIPassword: SecretText; + begin + if IsNullGuid(APIKeyGUID) or not IsolatedStorage.Get(APIKeyGUID, Datascope::Company, APIPassword) then + exit(APIPassword); + exit(APIPassword); end; +#if not CLEAN24 [NonDebuggable] [Scope('OnPrem')] + [Obsolete('Use SaveAPIKeyAsSecret() instead.', '24.0')] procedure SaveAPIKey(var APIKeyGUID: Guid; APIKeyValue: Text[250]) var FeatureTelemetry: Codeunit "Feature Telemetry"; begin - if not IsNullGuid(APIKeyGUID) AND (APIKeyValue = '') then begin + SaveAPIKeyAsSecret(APIKeyGUID, APIKeyValue); + end; +#endif + + [Scope('OnPrem')] + procedure SaveAPIKeyAsSecret(var APIKeyGUID: Guid; APIKeyValue: SecretText) + var + FeatureTelemetry: Codeunit "Feature Telemetry"; + begin + if not IsNullGuid(APIKeyGUID) AND (APIKeyValue.IsEmpty()) then begin If IsolatedStorage.Contains(APIKeyGUID, Datascope::Company) then IsolatedStorage.Delete(APIKeyGUID, Datascope::Company); Clear(APIKey); @@ -58,5 +83,6 @@ table 9092 "Postcode GetAddress.io Config" end; Modify(); end; + } diff --git a/Apps/GB/UKPostcodeGetAddressIO/app/src/PostcodeServiceGetAddressio.Codeunit.al b/Apps/GB/UKPostcodeGetAddressIO/app/src/PostcodeServiceGetAddressio.Codeunit.al index ef2fba091a..85bf725b06 100644 --- a/Apps/GB/UKPostcodeGetAddressIO/app/src/PostcodeServiceGetAddressio.Codeunit.al +++ b/Apps/GB/UKPostcodeGetAddressIO/app/src/PostcodeServiceGetAddressio.Codeunit.al @@ -44,6 +44,7 @@ codeunit 9092 "Postcode Service GetAddress.io" IsConfigured := IsServiceConfigured(); end; + [NonDebuggable] [EventSubscriber(ObjectType::Codeunit, Codeunit::"Postcode Service Manager", 'OnRetrieveAddressList', '', false, false)] procedure GetAddressListOnAddressListRetrieved(ServiceKey: Text; TempEnteredAutocompleteAddress: Record "Autocomplete Address" temporary; var TempAddressListNameValueBuffer: Record "Name/Value Buffer" temporary; var IsSuccessful: Boolean; var ErrorMsg: Text) var @@ -72,7 +73,11 @@ codeunit 9092 "Postcode Service GetAddress.io" GetConfigAndIfNecessaryCreate(); - Url := BuildUrl(TempEnteredAutocompleteAddress.Postcode); + // Build URL and include property number if provided + Url := PostcodeGetAddressIoConfig.EndpointURL + TempEnteredAutocompleteAddress.Postcode; + Url := Url + '?api-key=' + PostcodeGetAddressIoConfig.GetAPIPasswordAsSecret(PostcodeGetAddressIoConfig.APIKey).Unwrap(); + Url := Url + '&expand=true'; + PrepareWebRequest(HttpClientInstance); if not HttpClientInstance.Get(Url, HttpResponse) then begin @@ -167,7 +172,7 @@ codeunit 9092 "Postcode Service GetAddress.io" Successful := Successful AND not IsNullGuid(PostcodeGetAddressIoConfig.APIKey); end; - local procedure PrepareWebRequest(HTTPClientInstance: HttpClient) + local procedure PrepareWebRequest(var HTTPClientInstance: HttpClient) begin HttpClientInstance.DefaultRequestHeaders().Add('Accept-Encoding', 'utf-8'); HttpClientInstance.DefaultRequestHeaders().Add('Accept', 'application/json'); @@ -181,18 +186,6 @@ codeunit 9092 "Postcode Service GetAddress.io" exit(not IsNullGuid(PostcodeGetAddressIoConfig.APIKey) AND (PostcodeGetAddressIoConfig.EndpointURL <> '')); end; - local procedure BuildUrl(Postcode: Text): Text - var - Url: Text; - begin - // Build URL and include property number if provided - Url := PostcodeGetAddressIoConfig.EndpointURL + Postcode; - - Url := Url + '?api-key=' + PostcodeGetAddressIoConfig.GetAPIKey(PostcodeGetAddressIoConfig.APIKey); - Url := Url + '&expand=true'; - exit(Url); - end; - local procedure GetConfigAndIfNecessaryCreate() begin if PostcodeGetAddressIoConfig.FindFirst() then diff --git a/Apps/GB/UKPostcodeGetAddressIO/test/app.json b/Apps/GB/UKPostcodeGetAddressIO/test/app.json index 1a04843730..d26a202e33 100644 --- a/Apps/GB/UKPostcodeGetAddressIO/test/app.json +++ b/Apps/GB/UKPostcodeGetAddressIO/test/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "Tests for the GetAddress.io UK Postcodes extension.", "description": "Tests for the GetAddress.io UK Postcodes extension.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=839464", @@ -16,25 +16,25 @@ "id": "f778a784-c01c-4f35-a409-331e7803e69c", "name": "GetAddress.io UK Postcodes", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5095f467-0a01-4b99-99d1-9ff1237d286f", "publisher": "Microsoft", "name": "Library Variable Storage", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 139500, @@ -51,5 +51,5 @@ "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/IN/INChargeGroup/app/ChargeGroupBase/app.json b/Apps/IN/INChargeGroup/app/ChargeGroupBase/app.json index 6dda1ba633..d4b64f3463 100644 --- a/Apps/IN/INChargeGroup/app/ChargeGroupBase/app.json +++ b/Apps/IN/INChargeGroup/app/ChargeGroupBase/app.json @@ -2,7 +2,7 @@ "id": "8acb7e50-e2cb-4461-a546-6ca1100306f1", "name": "Charge Group Base", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Contains setup of Charge Assignment Functionality", "description": "Charge Group contains setups that are required for calculating Charges on transactions.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -15,20 +15,20 @@ "id": "d3c551dd-5903-4194-b153-04ced9d29a2c", "publisher": "Microsoft", "name": "India Tax Base", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "c1eafb3f-e397-468e-bdb4-ecc5c317ca00", "publisher": "Microsoft", "name": "Tax Engine", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "application": "24.0.0.0", - "platform": "24.0.0.0", + "application": "25.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 18501, diff --git a/Apps/IN/INChargeGroup/app/ChargeOnPurchase/app.json b/Apps/IN/INChargeGroup/app/ChargeOnPurchase/app.json index ae51c7fc4b..b7636ebff0 100644 --- a/Apps/IN/INChargeGroup/app/ChargeOnPurchase/app.json +++ b/Apps/IN/INChargeGroup/app/ChargeOnPurchase/app.json @@ -2,7 +2,7 @@ "id": "7cec3307-97cc-43ea-be4a-a4c17bac872a", "name": "Charge On Purchase", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Contains Charge Assignment Functionality", "description": "This feature contains Charge Assignment Functionality", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -15,26 +15,26 @@ "id": "d3c551dd-5903-4194-b153-04ced9d29a2c", "publisher": "Microsoft", "name": "India Tax Base", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "c1eafb3f-e397-468e-bdb4-ecc5c317ca00", "publisher": "Microsoft", "name": "Tax Engine", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "8acb7e50-e2cb-4461-a546-6ca1100306f1", "publisher": "Microsoft", "name": "Charge Group Base", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 18516, diff --git a/Apps/IN/INChargeGroup/app/ChargeOnPurchase/src/Codeunit/ThirdPartyPurchaseMgmt.Codeunit.al b/Apps/IN/INChargeGroup/app/ChargeOnPurchase/src/Codeunit/ThirdPartyPurchaseMgmt.Codeunit.al index 3378576ef4..f3036bd874 100644 --- a/Apps/IN/INChargeGroup/app/ChargeOnPurchase/src/Codeunit/ThirdPartyPurchaseMgmt.Codeunit.al +++ b/Apps/IN/INChargeGroup/app/ChargeOnPurchase/src/Codeunit/ThirdPartyPurchaseMgmt.Codeunit.al @@ -121,7 +121,7 @@ codeunit 18518 "Third Party Purchase Mgmt." Var InsertPurchaseHeader: Record "Purchase Header"; ChargeGroupHeader: Record "Charge Group Header"; - NoSeriesManagement: Codeunit NoSeriesManagement; + NoSeries: Codeunit "No. Series"; IsHandled: Boolean; begin OnBeforeInsertPurchaseHeaderWithChargeGroup(MainPurchaseHeader, ChargeGroupLines, IsHandled); @@ -130,7 +130,7 @@ codeunit 18518 "Third Party Purchase Mgmt." InsertPurchaseHeader.Init(); InsertPurchaseHeader."Document Type" := InsertPurchaseHeader."Document Type"::Invoice; - InsertPurchaseHeader."No." := NoSeriesManagement.GetNextNo(InsertPurchaseHeader.GetNoSeriesCode(), MainPurchaseHeader."Posting Date", true); + InsertPurchaseHeader."No." := NoSeries.GetNextNo(InsertPurchaseHeader.GetNoSeriesCode(), MainPurchaseHeader."Posting Date"); InsertPurchaseHeader.Validate("Buy-from Vendor No.", ChargeGroupLines."Vendor No."); InsertPurchaseHeader.Validate("Posting Date", MainPurchaseHeader."Posting Date"); InsertPurchaseHeader.Validate("Location Code", MainPurchaseHeader."Location Code"); diff --git a/Apps/IN/INChargeGroup/app/ChargeOnSales/app.json b/Apps/IN/INChargeGroup/app/ChargeOnSales/app.json index 144586613a..fa639e17f0 100644 --- a/Apps/IN/INChargeGroup/app/ChargeOnSales/app.json +++ b/Apps/IN/INChargeGroup/app/ChargeOnSales/app.json @@ -2,7 +2,7 @@ "id": "d28d7426-f140-46f5-94c6-232bc139bd62", "name": "ChargeOnSales", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Contains Charge Assignment Functionality", "description": "This feature contains Charge Assignment Functionality", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -15,26 +15,26 @@ "id": "d3c551dd-5903-4194-b153-04ced9d29a2c", "publisher": "Microsoft", "name": "India Tax Base", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "c1eafb3f-e397-468e-bdb4-ecc5c317ca00", "publisher": "Microsoft", "name": "Tax Engine", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "8acb7e50-e2cb-4461-a546-6ca1100306f1", "publisher": "Microsoft", "name": "Charge Group Base", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 18543, diff --git a/Apps/IN/INChargeGroup/app/app.json b/Apps/IN/INChargeGroup/app/app.json index 6f430d0933..4be585a051 100644 --- a/Apps/IN/INChargeGroup/app/app.json +++ b/Apps/IN/INChargeGroup/app/app.json @@ -2,7 +2,7 @@ "id": "07729019-da51-4639-a987-3db38ccc62c7", "name": "India Charge Group", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Contains Charge Group Functionality", "description": "This feature contains Charge Assignment Functionality", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -15,20 +15,20 @@ "id": "d3c551dd-5903-4194-b153-04ced9d29a2c", "publisher": "Microsoft", "name": "India Tax Base", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "c1eafb3f-e397-468e-bdb4-ecc5c317ca00", "publisher": "Microsoft", "name": "Tax Engine", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 18501, diff --git a/Apps/IN/INChargeGroup/test/app.json b/Apps/IN/INChargeGroup/test/app.json index c2f39d06f3..6ed9b579a6 100644 --- a/Apps/IN/INChargeGroup/test/app.json +++ b/Apps/IN/INChargeGroup/test/app.json @@ -2,7 +2,7 @@ "id": "0a2cbf4b-52df-4060-bd2d-cd7c8e80e586", "name": "India Charge Group Tests", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Tests for India Charge Group.", "description": "Tests for India Charge Group.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -15,56 +15,56 @@ "id": "dd0be2ea-f733-4d65-bb34-a28f4624fb14", "publisher": "Microsoft", "name": "Library Assert", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "publisher": "Microsoft", "name": "Tests-TestLibraries", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "d3c551dd-5903-4194-b153-04ced9d29a2c", "publisher": "Microsoft", "name": "India Tax Base", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "c1eafb3f-e397-468e-bdb4-ecc5c317ca00", "publisher": "Microsoft", "name": "Tax Engine", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "db643212-b7fb-4dd4-b5a8-cb44ac714461", "publisher": "Microsoft", "name": "India GST", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "07729019-da51-4639-a987-3db38ccc62c7", "publisher": "Microsoft", "name": "India Charge Group", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "20cc6140-cbda-4a21-b15d-8f6190fb5469", "publisher": "Microsoft", "name": "India Tax Base Tests", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "66eea9f9-cc7d-4274-8dbc-084182071a5f", "publisher": "Microsoft", "name": "India GST Tests", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 18990, diff --git a/Apps/IN/INDataMigration/app.json b/Apps/IN/INDataMigration/app.json index d33de15601..bf87ac17b1 100644 --- a/Apps/IN/INDataMigration/app.json +++ b/Apps/IN/INDataMigration/app.json @@ -2,7 +2,7 @@ "id": "417e3995-43e5-46bd-ab72-1ca13df0658d", "name": "India Data Migration", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Contains Logic to finalize Data Migration", "description": "This feature contains Logic to finalize Data Migration for India Localization", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -15,38 +15,38 @@ "id": "db643212-b7fb-4dd4-b5a8-cb44ac714461", "publisher": "Microsoft", "name": "India GST", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "d3c551dd-5903-4194-b153-04ced9d29a2c", "publisher": "Microsoft", "name": "India Tax Base", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "eddcf82e-482c-49d1-836b-ad0284f2c5b0", "publisher": "Microsoft", "name": "India TCS", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "eae5779e-7797-4c4c-977e-7516652b7a65", "publisher": "Microsoft", "name": "India TDS", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "c1eafb3f-e397-468e-bdb4-ecc5c317ca00", "publisher": "Microsoft", "name": "Tax Engine", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 19001, diff --git a/Apps/IN/INFADepreciation/app/app.json b/Apps/IN/INFADepreciation/app/app.json index 524a581354..5c4240d0e5 100644 --- a/Apps/IN/INFADepreciation/app/app.json +++ b/Apps/IN/INFADepreciation/app/app.json @@ -2,7 +2,7 @@ "id": "1150dd8d-51da-485a-bd4a-1ee98d78c21a", "name": "Fixed Asset Depreciation for India", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Contains features for Fixed Asset Depreciation", "description": "Fixed Asset Depreciation lets you calculate depreciation for Fixed Asset for different India depreciation methods.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -20,8 +20,8 @@ "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 18631, diff --git a/Apps/IN/INFADepreciation/test/app.json b/Apps/IN/INFADepreciation/test/app.json index 5aeba12eed..b724f9078f 100644 --- a/Apps/IN/INFADepreciation/test/app.json +++ b/Apps/IN/INFADepreciation/test/app.json @@ -2,7 +2,7 @@ "id": "00406151-0d06-485e-a3d6-15285cfec590", "name": "Fixed Asset Depreciation Tests", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Tests for Fixed Assets Depriciaton", "description": "Tests for Fixed Assets Depriciaton", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -15,26 +15,26 @@ "id": "dd0be2ea-f733-4d65-bb34-a28f4624fb14", "publisher": "Microsoft", "name": "Library Assert", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "publisher": "Microsoft", "name": "Tests-TestLibraries", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "1150dd8d-51da-485a-bd4a-1ee98d78c21a", "publisher": "Microsoft", "name": "Fixed Asset Depreciation for India", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 18645, diff --git a/Apps/IN/INFADepreciation/test/src/FADepreciation.Codeunit.al b/Apps/IN/INFADepreciation/test/src/FADepreciation.Codeunit.al index 441c5b19a7..17b37dd5ee 100644 --- a/Apps/IN/INFADepreciation/test/src/FADepreciation.Codeunit.al +++ b/Apps/IN/INFADepreciation/test/src/FADepreciation.Codeunit.al @@ -960,10 +960,10 @@ codeunit 18649 "FA Depreciation" local procedure GetDocumentNo(FAJournalBatch: Record "FA Journal Batch"): Code[20] var NoSeries: Record "No. Series"; - NoSeriesManagement: Codeunit NoSeriesManagement; + NoSeriesCodeunit: Codeunit "No. Series"; begin NoSeries.Get(FAJournalBatch."No. Series"); - exit(NoSeriesManagement.GetNextNo(FAJournalBatch."No. Series", WorkDate(), FALSE)); + exit(NoSeriesCodeunit.PeekNextNo(FAJournalBatch."No. Series")); end; local procedure CheckFAValueAndBookValue( @@ -1043,7 +1043,7 @@ codeunit 18649 "FA Depreciation" FADepreciationBook.Validate("Declining-Balance %", StorageDec.Get(XDepRateTok)); end; Evaluate(DayCalculation, Format(-DepreciationBook."Depr. Threshold Days" - LibraryRandom.RandInt(DepreciationBook."Depr. Threshold Days")) + 'D'); - FADepreciationBook.validate("Depreciation Starting Date", CalcDate(DayCalculation, NewPostingDate)); + FADepreciationBook.Validate("Depreciation Starting Date", CalcDate(DayCalculation, NewPostingDate)); FADepreciationBook.Modify(); RunCalculateDepreciation(No, DepreciationBookCode, true, NewPostingDate, DocNo); if FirstYearUtilizationFullYear then diff --git a/Apps/IN/INGST/app/GSTApplication/app.json b/Apps/IN/INGST/app/GSTApplication/app.json index 5be428413b..f9ab46fdec 100644 --- a/Apps/IN/INGST/app/GSTApplication/app.json +++ b/Apps/IN/INGST/app/GSTApplication/app.json @@ -2,7 +2,7 @@ "id": "d43fbce2-722b-4c66-a6d8-a69ce1147f1b", "name": "GST Application", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Contains application of Goods and Service Tax", "description": "Contains application of Goods and Services Tax on purchase and sales documents.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -15,44 +15,44 @@ "id": "c1eafb3f-e397-468e-bdb4-ecc5c317ca00", "publisher": "Microsoft", "name": "Tax Engine", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "d3c551dd-5903-4194-b153-04ced9d29a2c", "publisher": "Microsoft", "name": "India Tax Base", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "e3cf5645-b42c-412a-ac9d-bd85793266e5", "publisher": "Microsoft", "name": "GST Base", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "2370cfbe-5b06-482a-be41-aa08ad0c800d", "publisher": "Microsoft", "name": "GST Purchase", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "3312f794-b498-4664-9ce8-d9ab32c8a128", "publisher": "Microsoft", "name": "GST Sales", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5a449416-ab35-4609-8dda-018519f41550", "publisher": "Microsoft", "name": "GST Service", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 18430, diff --git a/Apps/IN/INGST/app/GSTBase/app.json b/Apps/IN/INGST/app/GSTBase/app.json index c8adf4f8b2..e8fb0603d6 100644 --- a/Apps/IN/INGST/app/GSTBase/app.json +++ b/Apps/IN/INGST/app/GSTBase/app.json @@ -2,7 +2,7 @@ "id": "e3cf5645-b42c-412a-ac9d-bd85793266e5", "name": "GST Base", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Contains setup of Goods and Services Tax", "description": "GST Base contains setups that are required for calculating Goods and Services Tax amounts.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -15,20 +15,20 @@ "id": "d3c551dd-5903-4194-b153-04ced9d29a2c", "publisher": "Microsoft", "name": "India Tax Base", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "c1eafb3f-e397-468e-bdb4-ecc5c317ca00", "publisher": "Microsoft", "name": "Tax Engine", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "application": "24.0.0.0", - "platform": "24.0.0.0", + "application": "25.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 18000, diff --git a/Apps/IN/INGST/app/GSTBase/src/Codeunit/GSTBaseValidation.Codeunit.al b/Apps/IN/INGST/app/GSTBase/src/Codeunit/GSTBaseValidation.Codeunit.al index db7304c3e5..da40642dcb 100644 --- a/Apps/IN/INGST/app/GSTBase/src/Codeunit/GSTBaseValidation.Codeunit.al +++ b/Apps/IN/INGST/app/GSTBase/src/Codeunit/GSTBaseValidation.Codeunit.al @@ -175,7 +175,12 @@ codeunit 18001 "GST Base Validation" SignFactor: Integer; DocTypeEnum: Enum "Document Type Enum"; TransTypeEnum: Enum "Transaction Type Enum"; + IsHandled: Boolean; begin + OnBeforeUpdateGSTLedgerEntry(Rec, RunTrigger, IsHandled); + if IsHandled then + exit; + if (not RunTrigger) or (Rec."Entry Type" <> Rec."Entry Type"::"Initial Entry") or (Rec."Skip Tax Engine Trigger") then exit; @@ -203,6 +208,7 @@ codeunit 18001 "GST Base Validation" if Rec."Source Type" = Rec."Source Type"::Vendor then Rec."Source No." := GSTPostingManagement.GetPaytoVendorNo(); + OnAfterUpdateGSTLedgerEntryOnBeforeModify(Rec); Rec.Modify(); end; @@ -218,7 +224,12 @@ codeunit 18001 "GST Base Validation" DocTypeEnum: Enum "Document Type Enum"; OriginalDocTypeEnum: Enum "Original Doc Type"; TransTypeEnum: Enum "Transaction Type Enum"; + IsHandled: Boolean; begin + OnBeforeUpdateDetailedGstLedgerEntryOnafterInsertEvent(Rec, RunTrigger, IsHandled); + if IsHandled then + exit; + GSTPostingManagement.SetRecord(Rec); //If called other than tax engine if (not RunTrigger) or (Rec."Entry Type" <> Rec."Entry Type"::"Initial Entry") or (Rec."Skip Tax Engine Trigger") then @@ -327,6 +338,7 @@ codeunit 18001 "GST Base Validation" if GSTPostingManagement.GetBuyerSellerRegNo() <> '' then Rec."Buyer/Seller Reg. No." := GSTPostingManagement.GetBuyerSellerRegNo(); + OnAfterUpdateDetailedGstLedgerEntryOnafterInsertEventOnBeforeModify(Rec, GSTRegistrationNos, DetailedGSTLedgerEntryInfo); Rec.Modify(); GSTPostingManagement.SetRecord(Rec); //if Called from tax engine @@ -836,7 +848,12 @@ codeunit 18001 "GST Base Validation" GSTPreviewHandler: Codeunit "GST Preview Handler"; TransTypeEnum: Enum "Detail Ledger Transaction Type"; DocumentTypeEnum: Enum "GST Document Type"; + IsHandled: Boolean; begin + OnBeforeUpdateDetailedGstEntryTransNo(GSTLedgerEntry, IsHandled); + if IsHandled then + exit; + TransTypeEnum := GSTLedgerTransactionType2DetailedLedgerTransactionType(GSTLedgerEntry."Transaction Type"); DocumentTypeEnum := GSTLedgerDocumentType2DetailedLedgerDocumentType(GSTLedgerEntry."Document Type"); DetailedGSTLedgerEntry.Reset(); @@ -1379,4 +1396,29 @@ codeunit 18001 "GST Base Validation" local procedure OnBeforeGetEcommerceMerchant(DetailedGSTLedgerEntryInfo: Record "Detailed GST Ledger Entry Info"; var IsHandled: Boolean) begin end; + + [IntegrationEvent(false, false)] + local procedure OnBeforeUpdateGSTLedgerEntry(var GSTLedgerEntry: Record "GST Ledger Entry"; RunTrigger: Boolean; var IsHandled: Boolean) + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnAfterUpdateGSTLedgerEntryOnBeforeModify(var GSTLedgerEntry: Record "GST Ledger Entry") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnBeforeUpdateDetailedGstEntryTransNo(var GSTLedgerEntry: Record "GST Ledger Entry"; var IsHandled: Boolean) + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnBeforeUpdateDetailedGstLedgerEntryOnafterInsertEvent(var DetailedGSTLedgerEntry: Record "Detailed GST Ledger Entry"; RunTrigger: Boolean; var IsHandled: Boolean) + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnAfterUpdateDetailedGstLedgerEntryOnafterInsertEventOnBeforeModify(var DetailedGSTLedgerEntry: Record "Detailed GST Ledger Entry"; GSTRegistrationNos: Record "GST Registration Nos."; var DetailedGSTLedgerEntryInfo: Record "Detailed GST Ledger Entry Info") + begin + end; } diff --git a/Apps/IN/INGST/app/GSTBase/src/Codeunit/GSTStatistics.Codeunit.al b/Apps/IN/INGST/app/GSTBase/src/Codeunit/GSTStatistics.Codeunit.al index 19cd18e61d..cbbcaaa9d3 100644 --- a/Apps/IN/INGST/app/GSTBase/src/Codeunit/GSTStatistics.Codeunit.al +++ b/Apps/IN/INGST/app/GSTBase/src/Codeunit/GSTStatistics.Codeunit.al @@ -116,6 +116,52 @@ codeunit 18006 "GST Statistics" until SalesLine.Next() = 0; end; + procedure GetPartialSalesStatisticsAmount( + SalesHeader: Record "Sales Header"; + var PartialGSTAmount: Decimal) + var + SalesLine: Record "Sales Line"; + GSTBaseValidation: Codeunit "GST Base Validation"; + begin + Clear(PartialGSTAmount); + + SalesLine.SetLoadFields("Document Type", "Document No.", Quantity, "Qty. to Invoice"); + SalesLine.SetRange("Document Type", SalesHeader."Document Type"); + SalesLine.SetRange("Document no.", SalesHeader."No."); + if SalesLine.FindSet() then + repeat + if SalesLine.Quantity <> 0 then + PartialGSTAmount += (GetGSTAmount(SalesLine.RecordId()) * SalesLine."Qty. to Invoice" / SalesLine.Quantity); + until SalesLine.Next() = 0; + + PartialGSTAmount := GSTBaseValidation.RoundGSTPrecision(PartialGSTAmount); + end; + + procedure GetPartialSalesShptStatisticsAmount( + SalesHeader: Record "Sales Header"; + var PartialGSTAmount: Decimal) + var + SalesLine: Record "Sales Line"; + GSTBaseValidation: Codeunit "GST Base Validation"; + begin + Clear(PartialGSTAmount); + + SalesLine.SetLoadFields("Document Type", "Document No.", Quantity, "Qty. to Ship", "Return Qty. to Receive"); + SalesLine.SetRange("Document Type", SalesHeader."Document Type"); + SalesLine.SetRange("Document no.", SalesHeader."No."); + if SalesLine.FindSet() then + repeat + if SalesLine.Quantity <> 0 then + if SalesLine."Document Type" = SalesLine."Document Type"::Order then + PartialGSTAmount += (GetGSTAmount(SalesLine.RecordId()) * SalesLine."Qty. to Ship" / SalesLine.Quantity) + else + if SalesLine."Document Type" = SalesLine."Document Type"::"Return Order" then + PartialGSTAmount += (GetGSTAmount(SalesLine.RecordId()) * SalesLine."Return Qty. to Receive" / SalesLine.Quantity) + until SalesLine.Next() = 0; + + PartialGSTAmount := GSTBaseValidation.RoundGSTPrecision(PartialGSTAmount); + end; + procedure GetStatisticsPostedSalesInvAmount( SalesInvHeader: Record "Sales Invoice Header"; var GSTAmount: Decimal) @@ -206,6 +252,120 @@ codeunit 18006 "GST Statistics" GSTAmount := GSTAmount - RCMAmount; end; + [EventSubscriber(ObjectType::Codeunit, Codeunit::"Calculate Statistics", 'OnGetPartialPurchaseHeaderGSTAmount', '', false, false)] + procedure OnGetPartialPurchaseHeaderGSTAmount(PurchaseHeader: Record "Purchase Header"; var PartialGSTAmount: Decimal) + var + PartialRCMAmount: Decimal; + begin + GetPartialPurchaseInvStatisticsAmount(PurchaseHeader, PartialGSTAmount); + GetPartialPurchaseRCMStatisticsAmount(PurchaseHeader, PartialRCMAmount); + PartialGSTAmount := PartialGSTAmount - PartialRCMAmount; + end; + + [EventSubscriber(ObjectType::Codeunit, Codeunit::"Calculate Statistics", 'OnGetPartialPurchaseRcptGSTAmount', '', false, false)] + procedure OnGetPartialPurchaseRcptGSTAmount(PurchaseHeader: Record "Purchase Header"; var PartialGSTAmount: Decimal) + var + PartialRCMAmount: Decimal; + begin + GetPartialPurchaseRcptStatisticsAmount(PurchaseHeader, PartialGSTAmount); + GetPartialPurchaseRcptRCMStatisticsAmount(PurchaseHeader, PartialRCMAmount); + PartialGSTAmount := PartialGSTAmount - PartialRCMAmount; + end; + + local procedure GetPartialPurchaseInvStatisticsAmount( + PurchaseHeader: Record "Purchase Header"; + var PartialGSTAmount: Decimal) + var + PurchaseLine: Record "Purchase Line"; + GSTBaseValidation: Codeunit "GST Base Validation"; + begin + Clear(PartialGSTAmount); + + PurchaseLine.SetLoadFields("Document Type", "Document No.", Quantity, "Qty. to Invoice"); + PurchaseLine.SetRange("Document Type", PurchaseHeader."Document Type"); + PurchaseLine.SetRange("Document no.", PurchaseHeader."No."); + if PurchaseLine.FindSet() then + repeat + if PurchaseLine.Quantity <> 0 then + PartialGSTAmount += (GetGSTAmount(PurchaseLine.RecordId()) * PurchaseLine."Qty. to Invoice" / PurchaseLine.Quantity); + until PurchaseLine.Next() = 0; + + PartialGSTAmount := GSTBaseValidation.RoundGSTPrecision(PartialGSTAmount); + end; + + local procedure GetPartialPurchaseRcptStatisticsAmount( + PurchaseHeader: Record "Purchase Header"; + var PartialGSTAmount: Decimal) + var + PurchaseLine: Record "Purchase Line"; + GSTBaseValidation: Codeunit "GST Base Validation"; + begin + Clear(PartialGSTAmount); + + PurchaseLine.SetLoadFields("Document Type", "Document No.", Quantity, "Qty. to Receive", "Return Qty. to Ship"); + PurchaseLine.SetRange("Document Type", PurchaseHeader."Document Type"); + PurchaseLine.SetRange("Document no.", PurchaseHeader."No."); + if PurchaseLine.FindSet() then + repeat + if PurchaseLine.Quantity <> 0 then + if PurchaseLine."Document Type" = PurchaseLine."Document Type"::Order then + PartialGSTAmount += (GetGSTAmount(PurchaseLine.RecordId()) * PurchaseLine."Qty. to Receive" / PurchaseLine.Quantity) + else + if PurchaseLine."Document Type" = PurchaseLine."Document Type"::"Return Order" then + PartialGSTAmount += (GetGSTAmount(PurchaseLine.RecordId()) * PurchaseLine."Return Qty. to Ship" / PurchaseLine.Quantity); + until PurchaseLine.Next() = 0; + + PartialGSTAmount := GSTBaseValidation.RoundGSTPrecision(PartialGSTAmount); + end; + + local procedure GetPartialPurchaseRCMStatisticsAmount( + PurchaseHeader: Record "Purchase Header"; + var PartialRCMAmount: Decimal) + var + PurchaseLine: Record "Purchase Line"; + GSTBaseValidation: Codeunit "GST Base Validation"; + begin + Clear(PartialRCMAmount); + + PurchaseLine.SetLoadFields("Document Type", "Document No.", Quantity, "Qty. to Invoice"); + PurchaseLine.SetRange("Document Type", PurchaseHeader."Document Type"); + PurchaseLine.SetRange("Document no.", PurchaseHeader."No."); + PurchaseLine.SetRange("GST Reverse Charge", true); + if PurchaseLine.FindSet() then + repeat + if PurchaseLine.Quantity <> 0 then + PartialRCMAmount += (GetGSTAmount(PurchaseLine.RecordId()) * PurchaseLine."Qty. to Invoice" / PurchaseLine.Quantity); + until PurchaseLine.Next() = 0; + + PartialRCMAmount := GSTBaseValidation.RoundGSTPrecision(PartialRCMAmount); + end; + + local procedure GetPartialPurchaseRcptRCMStatisticsAmount( + PurchaseHeader: Record "Purchase Header"; + var PartialRCMAmount: Decimal) + var + PurchaseLine: Record "Purchase Line"; + GSTBaseValidation: Codeunit "GST Base Validation"; + begin + Clear(PartialRCMAmount); + + PurchaseLine.SetLoadFields("Document Type", "Document No.", Quantity, "Qty. to Receive", "Return Qty. to Ship"); + PurchaseLine.SetRange("Document Type", PurchaseHeader."Document Type"); + PurchaseLine.SetRange("Document no.", PurchaseHeader."No."); + PurchaseLine.SetRange("GST Reverse Charge", true); + if PurchaseLine.FindSet() then + repeat + if PurchaseLine.Quantity <> 0 then + if PurchaseLine."Document Type" = PurchaseLine."Document Type"::Order then + PartialRCMAmount += (GetGSTAmount(PurchaseLine.RecordId()) * PurchaseLine."Qty. to Receive" / PurchaseLine.Quantity) + else + if PurchaseLine."Document Type" = PurchaseLine."Document Type"::"Return Order" then + PartialRCMAmount += (GetGSTAmount(PurchaseLine.RecordId()) * PurchaseLine."Return Qty. to Ship" / PurchaseLine.Quantity); + until PurchaseLine.Next() = 0; + + PartialRCMAmount := GSTBaseValidation.RoundGSTPrecision(PartialRCMAmount); + end; + [EventSubscriber(ObjectType::Codeunit, Codeunit::"Calculate Statistics", 'OnGetPurchInvHeaderGSTAmount', '', false, false)] local procedure OnGetPurchInvHeaderGSTAmount(PurchInvHeader: Record "Purch. Inv. Header"; var GSTAmount: Decimal) begin @@ -224,6 +384,18 @@ codeunit 18006 "GST Statistics" GetSalesStatisticsAmount(SalesHeader, GSTAmount); end; + [EventSubscriber(ObjectType::Codeunit, Codeunit::"Calculate Statistics", 'OnGetPartialSalesHeaderGSTAmount', '', false, false)] + local procedure OnGetPartialSalesHeaderGSTAmount(SalesHeader: Record "Sales Header"; var PartialGSTAmount: Decimal) + begin + GetPartialSalesStatisticsAmount(SalesHeader, PartialGSTAmount); + end; + + [EventSubscriber(ObjectType::Codeunit, Codeunit::"Calculate Statistics", 'OnGetPartialSalesShptGSTAmount', '', false, false)] + local procedure OnGetPartialSalesShptGSTAmount(SalesHeader: Record "Sales Header"; var PartialGSTAmount: Decimal) + begin + GetPartialSalesShptStatisticsAmount(SalesHeader, PartialGSTAmount); + end; + [EventSubscriber(ObjectType::Codeunit, Codeunit::"Calculate Statistics", 'OnGetSalesInvHeaderGSTAmount', '', false, false)] local procedure OnGetSalesInvHeaderGSTAmount(SalesInvHeader: Record "Sales Invoice Header"; var GSTAmount: Decimal) begin 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 4abd348cd4..22bf013733 100644 --- a/Apps/IN/INGST/app/GSTBase/src/TaxEngineSetup/GSTTaxConfiguration.Codeunit.al +++ b/Apps/IN/INGST/app/GSTBase/src/TaxEngineSetup/GSTTaxConfiguration.Codeunit.al @@ -112,7 +112,7 @@ codeunit 18017 "GST Tax Configuration" UseCases.Add('{12089FA0-9627-4C6F-B855-112FE6FFAC49}', 1); UseCases.Add('{231587B2-D0BD-4362-9A3B-11839F7BB326}', 1); UseCases.Add('{57A0B7F8-E6C5-4CC4-89AD-11A14AF3C68B}', 2); - UseCases.Add('{B90130D9-0471-4034-8687-11B04ABDCE72}', 3); + UseCases.Add('{B90130D9-0471-4034-8687-11B04ABDCE72}', 4); UseCases.Add('{142D2618-98AC-4DD8-922F-11CF063DD8D8}', 4); UseCases.Add('{047704F8-A619-401F-9653-12103103E14A}', 3); UseCases.Add('{759DC0B3-0697-4262-B0B6-12AA4A6E3822}', 6); @@ -280,7 +280,7 @@ codeunit 18017 "GST Tax Configuration" UseCases.Add('{09CD7163-15FB-4340-82BF-57373BE3E206}', 3); UseCases.Add('{0E9F08C2-7CF2-4AC1-AFB4-57AC8383E732}', 1); UseCases.Add('{975372FC-F93D-4E8B-81EA-57B6751B9F94}', 4); - UseCases.Add('{AA215442-D318-4160-A666-57E3FBE06CDD}', 2); + UseCases.Add('{AA215442-D318-4160-A666-57E3FBE06CDD}', 3); UseCases.Add('{7C64DCF3-718C-405E-A389-582FD1E33E5D}', 1); UseCases.Add('{8DDE731C-68ED-4658-BF7F-58385526601A}', 1); UseCases.Add('{93FE03BD-63C7-44B5-B40D-5974C8300527}', 4); @@ -445,7 +445,7 @@ codeunit 18017 "GST Tax Configuration" UseCases.Add('{7B096619-70FB-4622-9E57-8EAE58DC1AB1}', 4); UseCases.Add('{1FF813B4-1776-4717-8C56-8F0E684ACE73}', 6); UseCases.Add('{423BECDD-68DC-4541-9047-8F6B797709E5}', 2); - UseCases.Add('{4DD701D1-41A9-432E-9E95-8F8D08AB2C67}', 3); + UseCases.Add('{4DD701D1-41A9-432E-9E95-8F8D08AB2C67}', 4); UseCases.Add('{C6AFDFC6-874B-4B14-BCC9-8FC5B4992157}', 4); UseCases.Add('{EC4815D3-A78F-4C4F-8C64-8FE9AF09050C}', 4); UseCases.Add('{7859624E-8AFD-4A64-B361-900053C11266}', 3); @@ -675,7 +675,7 @@ codeunit 18017 "GST Tax Configuration" UseCases.Add('{06A818C9-817D-4983-B8D9-D96759380A68}', 3); UseCases.Add('{7F8B0021-4099-48C9-80BB-D977917CEA9E}', 2); UseCases.Add('{DF134523-53D1-4137-B091-D9C5E1DB8D64}', 4); - UseCases.Add('{C0774889-632D-4799-AA04-DA25EB643832}', 2); + UseCases.Add('{C0774889-632D-4799-AA04-DA25EB643832}', 3); UseCases.Add('{E474605D-6956-438B-95F2-DA5BE6A6D741}', 6); UseCases.Add('{FA492219-9C2F-4986-B773-DAA35CA74796}', 3); UseCases.Add('{FFBBBCDE-50F5-4D02-8B40-DAD63ED1491E}', 3); @@ -759,7 +759,7 @@ codeunit 18017 "GST Tax Configuration" UseCases.Add('{A0CED092-3AAD-4121-A5A2-F4DEAC316621}', 2); UseCases.Add('{4FA8A9F3-D8C5-4B20-ACB0-F52BFE013A01}', 1); UseCases.Add('{4F992CE7-BB8C-4129-923A-F53A771DF231}', 4); - UseCases.Add('{FC1AEFDA-0537-4D94-A576-F542B6710B71}', 4); + UseCases.Add('{FC1AEFDA-0537-4D94-A576-F542B6710B71}', 5); UseCases.Add('{535A4B2C-EEA4-4267-8638-F57DE9153FDD}', 1); UseCases.Add('{9A744701-39FF-4CFF-AA72-F5856E82FBF4}', 4); UseCases.Add('{81E6747B-B7CE-4A75-BEE5-F630FF17C687}', 2); diff --git a/Apps/IN/INGST/app/GSTDistribution/app.json b/Apps/IN/INGST/app/GSTDistribution/app.json index 5b74902093..2a9c5a8e58 100644 --- a/Apps/IN/INGST/app/GSTDistribution/app.json +++ b/Apps/IN/INGST/app/GSTDistribution/app.json @@ -2,7 +2,7 @@ "id": "fbc443fd-02a7-4e4e-a697-883efe7bc33b", "name": "GST Distribution", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Contains features for GST distribution for services.", "description": "GST Distribution enables you to distribute GST receivables to locations.", "features": [ @@ -18,26 +18,26 @@ "id": "d3c551dd-5903-4194-b153-04ced9d29a2c", "publisher": "Microsoft", "name": "India Tax Base", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "2370cfbe-5b06-482a-be41-aa08ad0c800d", "publisher": "Microsoft", "name": "GST Purchase", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "c1eafb3f-e397-468e-bdb4-ecc5c317ca00", "publisher": "Microsoft", "name": "Tax Engine", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "application": "24.0.0.0", - "platform": "24.0.0.0", + "application": "25.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 18200, diff --git a/Apps/IN/INGST/app/GSTDistribution/src/Codeunit/GSTDistribution.Codeunit.al b/Apps/IN/INGST/app/GSTDistribution/src/Codeunit/GSTDistribution.Codeunit.al index b070c3da92..f8ec54c166 100644 --- a/Apps/IN/INGST/app/GSTDistribution/src/Codeunit/GSTDistribution.Codeunit.al +++ b/Apps/IN/INGST/app/GSTDistribution/src/Codeunit/GSTDistribution.Codeunit.al @@ -22,7 +22,6 @@ codeunit 18200 "GST Distribution" GeneralLedgerSetup: Record "General Ledger Setup"; SourceCodeSetup: Record "Source Code Setup"; GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; - NoSeriesManagement: Codeunit NoSeriesManagement; ZeroDistPercentErr: Label '%1 cannot be zero for Location Code: %2 in Distribution Line.', Comment = '%1 = Distribution % , %2 =From Location Code'; selectDitributionErr: Label 'No entries are selected for distribution.'; ToGSTCompErr: Label 'GST Component Distribution setup must be provided for GST Component Code %1 and GST Jurisdiction Type %2.', Comment = '%1 = GSTComponentCode , %2 = JurisdictionType'; @@ -305,6 +304,7 @@ codeunit 18200 "GST Distribution" PostedGSTDistributionHeader: Record "Posted GST Distribution Header"; Location: Record "Location"; GSTDistributionSubcsribers: Codeunit "GST Distribution Subcsribers"; + NoSeries: Codeunit "No. Series"; Record: Variant; begin Location.Get(GSTDistributionHeader."From Location Code"); @@ -316,11 +316,11 @@ codeunit 18200 "GST Distribution" if GSTDistributionHeader."ISD Document Type" = GSTDistributionHeader."ISD Document Type"::Invoice then begin GSTDistributionSubcsribers.GetDistributionNoSeriesCode(Record); GSTDistributionHeader := Record; - PostedGSTDistributionHeader."No." := NoSeriesManagement.GetNextNo(GSTDistributionHeader."Posting No. Series", WorkDate(), true); + PostedGSTDistributionHeader."No." := NoSeries.GetNextNo(GSTDistributionHeader."Posting No. Series"); end else begin GSTDistributionSubcsribers.GetDistributionNoSeriesCode(Record); GSTDistributionHeader := Record; - PostedGSTDistributionHeader."No." := NoSeriesManagement.GetNextNo(GSTDistributionHeader."Posting No. Series", WorkDate(), true); + PostedGSTDistributionHeader."No." := NoSeries.GetNextNo(GSTDistributionHeader."Posting No. Series"); end; PostedGSTDistributionHeader.Insert(true); diff --git a/Apps/IN/INGST/app/GSTDistribution/src/Codeunit/GSTDistributionSubcsribers.codeunit.al b/Apps/IN/INGST/app/GSTDistribution/src/Codeunit/GSTDistributionSubcsribers.codeunit.al index bb7f077980..224a0f21cd 100644 --- a/Apps/IN/INGST/app/GSTDistribution/src/Codeunit/GSTDistributionSubcsribers.codeunit.al +++ b/Apps/IN/INGST/app/GSTDistribution/src/Codeunit/GSTDistributionSubcsribers.codeunit.al @@ -90,14 +90,14 @@ codeunit 18201 "GST Distribution Subcsribers" var GeneralLedgerSetup: Record "General Ledger Setup"; NoSeries: Record "No. Series"; - NoSeriesManagement: Codeunit NoSeriesManagement; + NoSeriesCodeunit: Codeunit "No. Series"; begin if GSTDistributionHeader."No." = '' then begin GeneralLedgerSetup.Get(); if GeneralLedgerSetup."GST Distribution Nos." <> '' then begin GeneralLedgerSetup.TestField("GST Distribution Nos."); NoSeries.Get(GeneralLedgerSetup."GST Distribution Nos."); - GSTDistributionHeader."No." := NoSeriesManagement.GetNextNo(NoSeries.Code, WorkDate(), true); + GSTDistributionHeader."No." := NoSeriesCodeunit.GetNextNo(NoSeries.Code); GSTDistributionHeader."No. Series" := GeneralLedgerSetup."GST Distribution Nos."; end; end; diff --git a/Apps/IN/INGST/app/GSTDistribution/src/table/GSTDistributionHeader.table.al b/Apps/IN/INGST/app/GSTDistribution/src/table/GSTDistributionHeader.table.al index e747623abe..d4a7110381 100644 --- a/Apps/IN/INGST/app/GSTDistribution/src/table/GSTDistributionHeader.table.al +++ b/Apps/IN/INGST/app/GSTDistribution/src/table/GSTDistributionHeader.table.al @@ -146,17 +146,18 @@ table 18203 "GST Distribution Header" var GLSetup: Record "General Ledger Setup"; - NoSeriesManagement: Codeunit NoSeriesManagement; UpdateDimQst: Label 'You may have changed a dimension.Do you want to update the lines?'; DimensionSetMsg: Label '%1', Comment = '%1 =Dimension Set No.'; procedure AssistEdit(GSTDistributionHeader: Record "GST Distribution Header"): Boolean + var + NoSeries: Codeunit "No. Series"; begin Copy(Rec); GLSetup.Get(); GLSetup.TestField("GST Distribution Nos."); - if NoSeriesManagement.SelectSeries(GLSetup."GST Distribution Nos.", "No. Series", "No. Series") then begin - NoSeriesManagement.SetSeries("No."); + if NoSeries.LookupRelatedNoSeries(GLSetup."GST Distribution Nos.", "No. Series", "No. Series") then begin + "No." := NoSeries.GetNextNo("No. Series"); Rec := GSTDistributionHeader; exit(true); end; diff --git a/Apps/IN/INGST/app/GSTPayments/app.json b/Apps/IN/INGST/app/GSTPayments/app.json index 4eb250dab4..6a2427322b 100644 --- a/Apps/IN/INGST/app/GSTPayments/app.json +++ b/Apps/IN/INGST/app/GSTPayments/app.json @@ -2,7 +2,7 @@ "id": "02256837-7459-45d9-8ff6-66cf4f517a0e", "name": "GST on Payments", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Contains GST calculations for financial transactions.", "description": "GST on payments allows GST calculation on bank payments, bank receipts, bank charges, and cash payments and receipts. ", "features": [ @@ -19,38 +19,38 @@ "id": "c1eafb3f-e397-468e-bdb4-ecc5c317ca00", "publisher": "Microsoft", "name": "Tax Engine", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "d3c551dd-5903-4194-b153-04ced9d29a2c", "publisher": "Microsoft", "name": "India Tax Base", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "e3cf5645-b42c-412a-ac9d-bd85793266e5", "publisher": "Microsoft", "name": "GST Base", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "3312f794-b498-4664-9ce8-d9ab32c8a128", "publisher": "Microsoft", "name": "GST Sales", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "2370cfbe-5b06-482a-be41-aa08ad0c800d", "publisher": "Microsoft", "name": "GST Purchase", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "application": "24.0.0.0", - "platform": "24.0.0.0", + "application": "25.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 18243, diff --git a/Apps/IN/INGST/app/GSTPurchase/app.json b/Apps/IN/INGST/app/GSTPurchase/app.json index 602d73bb50..4b1270951d 100644 --- a/Apps/IN/INGST/app/GSTPurchase/app.json +++ b/Apps/IN/INGST/app/GSTPurchase/app.json @@ -2,7 +2,7 @@ "id": "2370cfbe-5b06-482a-be41-aa08ad0c800d", "name": "GST Purchase", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Contains features for Goods and Services Tax on purchase transactions.", "description": "GST Purchase lets you calculate GST on purchase transactions such as purchase orders, invoices, purchase returns, credit memos, and journals.", "features": [ @@ -19,26 +19,26 @@ "id": "c1eafb3f-e397-468e-bdb4-ecc5c317ca00", "publisher": "Microsoft", "name": "Tax Engine", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "d3c551dd-5903-4194-b153-04ced9d29a2c", "publisher": "Microsoft", "name": "India Tax Base", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "e3cf5645-b42c-412a-ac9d-bd85793266e5", "publisher": "Microsoft", "name": "GST Base", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "application": "24.0.0.0", - "platform": "24.0.0.0", + "application": "25.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 18080, diff --git a/Apps/IN/INGST/app/GSTPurchase/src/PageExtension/GSTPurchaseOrderStats.PageExt.al b/Apps/IN/INGST/app/GSTPurchase/src/PageExtension/GSTPurchaseOrderStats.PageExt.al index 9ffb1d37ba..7c545eae10 100644 --- a/Apps/IN/INGST/app/GSTPurchase/src/PageExtension/GSTPurchaseOrderStats.PageExt.al +++ b/Apps/IN/INGST/app/GSTPurchase/src/PageExtension/GSTPurchaseOrderStats.PageExt.al @@ -6,6 +6,7 @@ namespace Microsoft.Purchases.Document; using Microsoft.Finance.GST.Application; using Microsoft.Finance.GST.Purchase; +using Microsoft.Finance.GST.Base; pageextension 18101 "GST Purchase Order Stats." extends "Purchase Order Statistics" { @@ -30,6 +31,26 @@ pageextension 18101 "GST Purchase Order Stats." extends "Purchase Order Statisti Caption = 'GST Amount'; } } + addlast(Invoicing) + { + field("Inv. GST Amount"; PartialInvGSTAmount) + { + Caption = 'GST Amount'; + ToolTip = 'Specifies the amount of GST that is partial amount of total.'; + ApplicationArea = Basic, Suite; + Editable = false; + } + } + addlast(Shipping) + { + field("Inv. GST Amt"; PartialRcptGSTAmount) + { + Caption = 'GST Amount'; + ToolTip = 'Specifies the amount of GST that is partial amount of total.'; + ApplicationArea = Basic, Suite; + Editable = false; + } + } } trigger OnAfterGetRecord() @@ -40,8 +61,11 @@ pageextension 18101 "GST Purchase Order Stats." extends "Purchase Order Statisti local procedure GetGSTAmount() var GSTStatsManagement: Codeunit "GST Stats Management"; + GSTStatistics: Codeunit "GST Statistics"; begin GSTAmount := GSTStatsManagement.GetGstStatsAmount(); + GSTStatistics.OnGetPartialPurchaseHeaderGSTAmount(Rec, PartialInvGSTAmount); + GSTStatistics.OnGetPartialPurchaseRcptGSTAmount(Rec, PartialRcptGSTAmount); Calculated := true; GSTStatsManagement.ClearSessionVariable(); end; @@ -54,5 +78,7 @@ pageextension 18101 "GST Purchase Order Stats." extends "Purchase Order Statisti var GSTAmount: Decimal; + PartialInvGSTAmount: Decimal; + PartialRcptGSTAmount: Decimal; Calculated: Boolean; } diff --git a/Apps/IN/INGST/app/GSTReconcilation/app.json b/Apps/IN/INGST/app/GSTReconcilation/app.json index 198c3bffd2..4b9bdffdec 100644 --- a/Apps/IN/INGST/app/GSTReconcilation/app.json +++ b/Apps/IN/INGST/app/GSTReconcilation/app.json @@ -2,7 +2,7 @@ "id": "6f9d2a17-ea47-4289-8a4a-aa9551792530", "name": "GST Reconcilation", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Contains features for reconciling Goods and Services Tax.", "description": "GST Reconciliation provides features for reconciling GST on purchase invoices with vendor invoices.", "features": [ @@ -18,26 +18,26 @@ "id": "c1eafb3f-e397-468e-bdb4-ecc5c317ca00", "publisher": "Microsoft", "name": "Tax Engine", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "d3c551dd-5903-4194-b153-04ced9d29a2c", "publisher": "Microsoft", "name": "India Tax Base", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "e3cf5645-b42c-412a-ac9d-bd85793266e5", "publisher": "Microsoft", "name": "GST Base", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "application": "24.0.0.0", - "platform": "24.0.0.0", + "application": "25.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 18280, diff --git a/Apps/IN/INGST/app/GSTReconcilation/src/Codeunit/GSTReconcilationMatch.Codeunit.al b/Apps/IN/INGST/app/GSTReconcilation/src/Codeunit/GSTReconcilationMatch.Codeunit.al index ad520f250f..ecd303d474 100644 --- a/Apps/IN/INGST/app/GSTReconcilation/src/Codeunit/GSTReconcilationMatch.Codeunit.al +++ b/Apps/IN/INGST/app/GSTReconcilation/src/Codeunit/GSTReconcilationMatch.Codeunit.al @@ -401,7 +401,12 @@ codeunit 18280 "GST Reconcilation Match" var DetailedGSTLedgerEntryInfo: Record "Detailed GST Ledger Entry Info"; GSTRegistrationNos: Record "GST Registration Nos."; + IsHandled: Boolean; begin + OnBeforeInsertGSTRecoLines(GSTReconcilationLine, DetailedGSTLedgerEntry, GSTRegNo, GSTMonth, GSTYear, IsHandled); + if IsHandled then + exit; + if DetailedGSTLedgerEntryInfo.Get(DetailedGSTLedgerEntry."Entry No.") then GSTReconcilationLine."State Code" := DetailedGSTLedgerEntryInfo."Location State Code"; @@ -427,6 +432,7 @@ codeunit 18280 "GST Reconcilation Match" GSTReconcilationLine."Credit Availed" := DetailedGSTLedgerEntry."Credit Availed"; GSTRegistrationNos.Get(GSTRegNo); GSTReconcilationLine."Input Service Distribution" := GSTRegistrationNos."Input Service Distributor"; + OnAfterFillGSTRecoLineOnBeforeInsert(GSTReconcilationLine, DetailedGSTLedgerEntry, DetailedGSTLedgerEntryInfo, GSTRegistrationNos); GSTReconcilationLine.Insert(true); end; @@ -543,4 +549,14 @@ codeunit 18280 "GST Reconcilation Match" CompAmtTxtErr, GSTReconMapping."GST Component Code"); end; + + [IntegrationEvent(false, false)] + local procedure OnBeforeInsertGSTRecoLines(var GSTReconcilationLine: Record "GST Reconcilation Line"; var DetailedGSTLedgerEntry: Record "Detailed GST Ledger Entry"; GSTRegNo: Code[20]; GSTMonth: Integer; GSTYear: Integer; var IsHandled: Boolean) + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnAfterFillGSTRecoLineOnBeforeInsert(var GSTReconcilationLine: Record "GST Reconcilation Line"; var DetailedGSTLedgerEntry: Record "Detailed GST Ledger Entry"; var DetailedGSTLedgerEntryInfo: Record "Detailed GST Ledger Entry Info"; var GSTRegistrationNos: Record "GST Registration Nos.") + begin + end; } diff --git a/Apps/IN/INGST/app/GSTReturnSettlement/app.json b/Apps/IN/INGST/app/GSTReturnSettlement/app.json index 8223a313db..6e15c2d16d 100644 --- a/Apps/IN/INGST/app/GSTReturnSettlement/app.json +++ b/Apps/IN/INGST/app/GSTReturnSettlement/app.json @@ -2,7 +2,7 @@ "id": "1774437c-9f8f-4007-8ade-3459cead7e14", "name": "GST Return and Settlement", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Returns and settlement for GST payables and receivables.", "description": "GST Return and Settlement lets you settle GST payables with GST receiveables, and pay differential amounts to tax authorities.", "features": [ @@ -18,44 +18,44 @@ "id": "c1eafb3f-e397-468e-bdb4-ecc5c317ca00", "publisher": "Microsoft", "name": "Tax Engine", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "d3c551dd-5903-4194-b153-04ced9d29a2c", "publisher": "Microsoft", "name": "India Tax Base", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "e3cf5645-b42c-412a-ac9d-bd85793266e5", "publisher": "Microsoft", "name": "GST Base", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "2370cfbe-5b06-482a-be41-aa08ad0c800d", "publisher": "Microsoft", "name": "GST Purchase", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "02256837-7459-45d9-8ff6-66cf4f517a0e", "publisher": "Microsoft", "name": "GST on Payments", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5a449416-ab35-4609-8dda-018519f41550", "publisher": "Microsoft", "name": "GST Distribution", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "application": "24.0.0.0", - "platform": "24.0.0.0", + "application": "25.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 18317, diff --git a/Apps/IN/INGST/app/GSTReturnSettlement/src/codeunit/GSTJournalPost.Codeunit.al b/Apps/IN/INGST/app/GSTReturnSettlement/src/codeunit/GSTJournalPost.Codeunit.al index 68735814d6..a0aa0251be 100644 --- a/Apps/IN/INGST/app/GSTReturnSettlement/src/codeunit/GSTJournalPost.Codeunit.al +++ b/Apps/IN/INGST/app/GSTReturnSettlement/src/codeunit/GSTJournalPost.Codeunit.al @@ -26,20 +26,15 @@ codeunit 18320 "GST Journal Post" GenJournalLine: Record "Gen. Journal Line"; GSTAdjustmentBuffer: Record "GST Adjustment Buffer"; TempGSTPostingBuffer: array[2] of Record "GST Posting Buffer" temporary; - TempNoSeries: Record "No. Series" temporary; ReservationEngineMgt: Codeunit "Reservation Engine Mgt."; CreateReservEntry: Codeunit "Create Reserv. Entry"; GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; - NoSeriesMgt: Codeunit "NoSeriesManagement"; - NoSeriesMgt2: array[10] of Codeunit "NoSeriesManagement"; + NoSeriesBatch: Codeunit "No. Series - Batch"; GSTHelpers: Codeunit "GST Helpers"; DiffAmt: Decimal; DocNo: Code[20]; LastDocNo: Code[20]; LastPostedDocNo: Code[20]; - PostingNoSeriesNo: Integer; - NoOfPostingNoSeries: Integer; - NoSeriesErr: Label 'A maximum of %1 posting number series can be used in each journal.', Comment = '%1 =Integer'; RemQtyErr: Label 'Quantity Adjusted %1 must not be greater than remaining quantity %2 for Detailed GST Ledger Entry No %3.', Comment = '%1 = Adjusted Quantity, %2 = Remaining Quantity, %3 = Entry No.'; GSTAdjustMsg: Label 'GST Adjustment Entry', Locked = true; LotNoErr: Label 'The Lot/Serial No %1 selected in item tracking does not belongs to posted document %2 selected in adjustment journal.', Comment = '%1 = Lot/Serial No, %2 = Document No.'; @@ -80,6 +75,7 @@ codeunit 18320 "GST Journal Post" Window.Update(2, LineCount); Window.Update(3, Round(LineCount / GSTJournalLine.Count * 10000, 1)); until GSTJournalLine.Next() = 0; + NoSeriesBatch.SaveState(); Clear(GenJnlPostLine); GSTAdjustmentBuffer.Reset(); @@ -121,22 +117,13 @@ codeunit 18320 "GST Journal Post" GSTJournalBatch.Get(GSTJnlLine."Journal Template Name", GSTJnlLine."Journal Batch Name"); if GSTJnlLine."Posting No. Series" = '' then begin GSTJnlLine."Posting No. Series" := GSTJournalBatch."No. Series"; - GSTJnlLine."Document No." := NoSeriesMgt.GetNextNo(GSTJnlLine."Posting No. Series", GSTJnlLine."Posting Date", true); + GSTJnlLine."Document No." := NoSeriesBatch.GetNextNo(GSTJnlLine."Posting No. Series", GSTJnlLine."Posting Date"); end else if GSTJnlLine."Document No." = LastDocNo then GSTJnlLine."Document No." := LastPostedDocNo else begin - if not TempNoSeries.Get(GSTJnlLine."Posting No. Series") then begin - NoOfPostingNoSeries := NoOfPostingNoSeries + 1; - if NoOfPostingNoSeries > ArrayLen(NoSeriesMgt2) then - Error(NoSeriesErr, ArrayLen(NoSeriesMgt2)); - TempNoSeries.Code := GSTJnlLine."Posting No. Series"; - TempNoSeries.Description := Format(NoOfPostingNoSeries); - TempNoSeries.Insert(); - end; LastDocNo := GSTJnlLine."Document No."; - Evaluate(PostingNoSeriesNo, TempNoSeries.Description); - GSTJnlLine."Document No." := NoSeriesMgt2[PostingNoSeriesNo].GetNextNo(GSTJnlLine."Posting No. Series", GSTJnlLine."Posting Date", true); + GSTJnlLine."Document No." := NoSeriesBatch.GetNextNo(GSTJnlLine."Posting No. Series", GSTJnlLine."Posting Date"); LastPostedDocNo := GSTJnlLine."Document No."; end; exit(GSTJnlLine."Document No."); diff --git a/Apps/IN/INGST/app/GSTReturnSettlement/src/codeunit/GSTSettlement.Codeunit.al b/Apps/IN/INGST/app/GSTReturnSettlement/src/codeunit/GSTSettlement.Codeunit.al index cb6b36ab21..090250a195 100644 --- a/Apps/IN/INGST/app/GSTReturnSettlement/src/codeunit/GSTSettlement.Codeunit.al +++ b/Apps/IN/INGST/app/GSTReturnSettlement/src/codeunit/GSTSettlement.Codeunit.al @@ -218,7 +218,7 @@ codeunit 18318 "GST Settlement" DetailedGSTLedgerEntry: Record "Detailed GST Ledger Entry"; GenLedgerSetup: Record "General Ledger Setup"; GenJournalPostLine: Codeunit "Gen. Jnl.-Post Line"; - NoSeriesManagement: Codeunit NoSeriesManagement; + NoSeries: Codeunit "No. Series"; GSTHelpers: Codeunit "GST Helpers"; GSTBaseValidation: Codeunit "GST Base Validation"; EntryNo: Integer; @@ -344,7 +344,7 @@ codeunit 18318 "GST Settlement" EntryNo := GenJournalPostLine.RunWithCheck(GenJnlLine); until TempGSTPostingBuffer[1].Next(-1) = 0; until GSTCreditAdjustmentJournal.Next() = 0; - NoSeriesManagement.GetNextNo(GetNoSeriesCode(false), GSTCreditAdjustmentJournal."Posting Date", true); + NoSeries.GetNextNo(GetNoSeriesCode(false), GSTCreditAdjustmentJournal."Posting Date"); end; end; @@ -576,7 +576,7 @@ codeunit 18318 "GST Settlement" GSTLiabilityBuffer: Record "GST Liability Buffer"; DetailedGSTLedgerEntry: Record "Detailed GST Ledger Entry"; GenJnlLine: Record "Gen. Journal Line"; - NoSeriesManagement: Codeunit NoSeriesManagement; + NoSeries: Codeunit "No. Series"; AppliedBase: Decimal; AppliedAmount: Decimal; RemainingBase: Decimal; @@ -732,7 +732,7 @@ codeunit 18318 "GST Settlement" until TempGSTPostingBuffer1[1].Next(-1) = 0; until GSTLiabilityAdjustment.Next() = 0; - NoSeriesManagement.GetNextNo(GetNoSeriesCode(true), GSTLiabilityAdjustment."Adjustment Posting Date", true); + NoSeries.GetNextNo(GetNoSeriesCode(true), GSTLiabilityAdjustment."Adjustment Posting Date"); end; end; @@ -1127,7 +1127,7 @@ codeunit 18318 "GST Settlement" DetailedGSTLedgerEntry: Record "Detailed GST Ledger Entry"; GeneralPostingSetup: Record "General Posting Setup"; GenJournalLine: Record "Gen. Journal Line"; - NoSeriesManagement: Codeunit NoSeriesManagement; + NoSeries: Codeunit "No. Series"; GSTHelpers: Codeunit "GST Helpers"; TotalGSTAmt: Decimal; TotalGSTAmt1: Decimal; @@ -1266,7 +1266,7 @@ codeunit 18318 "GST Settlement" if GSTCreditAdjustmentJournal.Type = Type::Item then PostRevaluationEntry(GSTCreditAdjustmentJournal) until GSTCreditAdjustmentJournal.Next() = 0; - NoSeriesManagement.GetNextNo(GetNoSeriesCode(false), GSTCreditAdjustmentJournal."Posting Date", true); + NoSeries.GetNextNo(GetNoSeriesCode(false), GSTCreditAdjustmentJournal."Posting Date"); end; Clear(GenJnlPostLine); @@ -2006,14 +2006,16 @@ codeunit 18318 "GST Settlement" Error(PostingDateErr); end; - local procedure GetSettlementDocumentNo(PostingDate: Date; modifyTrue: Boolean): Code[20] + local procedure GetSettlementDocumentNo(PostingDate: Date; ModifyNoSeries: Boolean): Code[20] var GenLedgerSetup: Record "General Ledger Setup"; - NoSeriesMgmt: Codeunit NoSeriesManagement; + NoSeries: Codeunit "No. Series"; begin GenLedgerSetup.Get(); GenLedgerSetup.TestField("GST Settlement Nos."); - exit(NoSeriesMgmt.GetNextNo(GenLedgerSetup."GST Settlement Nos.", PostingDate, modifyTrue)); + if ModifyNoSeries then + exit(NoSeries.GetNextNo(GenLedgerSetup."GST Settlement Nos.", PostingDate)); + exit(NoSeries.PeekNextNo(GenLedgerSetup."GST Settlement Nos.", PostingDate)); end; local procedure CreateGSTPaymentBuffer( diff --git a/Apps/IN/INGST/app/GSTReturnSettlement/src/page/GSTCreditAdjustment.page.al b/Apps/IN/INGST/app/GSTReturnSettlement/src/page/GSTCreditAdjustment.page.al index aa3765034a..c2c3e5ebd1 100644 --- a/Apps/IN/INGST/app/GSTReturnSettlement/src/page/GSTCreditAdjustment.page.al +++ b/Apps/IN/INGST/app/GSTReturnSettlement/src/page/GSTCreditAdjustment.page.al @@ -172,12 +172,9 @@ page 18317 "GST Credit Adjustment" trigger OnOpenPage() var - NoSeriesManagement: Codeunit NoSeriesManagement; + NoSeries: Codeunit "No. Series"; begin - AdjDocNo := NoSeriesManagement.GetNextNo( - GSTSettlement.GetNoSeriesCode(false), - PostingDate, - false); + AdjDocNo := NoSeries.PeekNextNo(GSTSettlement.GetNoSeriesCode(false), PostingDate); AdjustmentPerc := 100; end; diff --git a/Apps/IN/INGST/app/GSTReturnSettlement/src/page/GSTLiabilityAdjustment.page.al b/Apps/IN/INGST/app/GSTReturnSettlement/src/page/GSTLiabilityAdjustment.page.al index e051d50877..161c33f452 100644 --- a/Apps/IN/INGST/app/GSTReturnSettlement/src/page/GSTLiabilityAdjustment.page.al +++ b/Apps/IN/INGST/app/GSTReturnSettlement/src/page/GSTLiabilityAdjustment.page.al @@ -154,9 +154,9 @@ page 18320 "GST Liability Adjustment" trigger OnOpenPage() var - NoSeriesManagement: Codeunit NoSeriesManagement; + NoSeries: Codeunit "No. Series"; begin - AdjDocNo := NoSeriesManagement.GetNextNo(GSTSettlement.GetNoSeriesCode(true), PostingDate, false); + AdjDocNo := NoSeries.PeekNextNo(GSTSettlement.GetNoSeriesCode(true), PostingDate); end; local procedure CheckMandatoryFields() diff --git a/Apps/IN/INGST/app/GSTReturnSettlement/src/table/GSTJournalLine.table.al b/Apps/IN/INGST/app/GSTReturnSettlement/src/table/GSTJournalLine.table.al index 80bd431238..d2852dc890 100644 --- a/Apps/IN/INGST/app/GSTReturnSettlement/src/table/GSTJournalLine.table.al +++ b/Apps/IN/INGST/app/GSTReturnSettlement/src/table/GSTJournalLine.table.al @@ -551,7 +551,6 @@ table 18325 "GST Journal Line" BankAcc: Record "Bank Account"; GLSetup: Record "General Ledger Setup"; GSTAdjustmentBuffer: Record "GST Adjustment Buffer"; - NoSeriesMgt: Codeunit "NoSeriesManagement"; DimMgt: Codeunit "DimensionManagement"; GSTJournalPost: Codeunit "GST Journal Post"; ReplaceInfo: Boolean; @@ -568,6 +567,8 @@ table 18325 "GST Journal Line" end; procedure SetUpNewLine(LastGSTJournalLine: Record "GST Journal Line"; Balance: Decimal; BottomLine: Boolean) + var + NoSeries: Codeunit "No. Series"; begin GSTJournalTemplate.Get("Journal Template Name"); GSTJournalBatch.Get("Journal Template Name", "Journal Batch Name"); @@ -583,10 +584,8 @@ table 18325 "GST Journal Line" "Document No." := IncStr("Document No."); end else begin "Posting Date" := WorkDate(); - if GSTJournalBatch."No. Series" <> '' then begin - CLEAR(NoSeriesMgt); - "Document No." := NoSeriesMgt.GetNextNo(GSTJournalBatch."No. Series", "Posting Date", false); - end; + if GSTJournalBatch."No. Series" <> '' then + "Document No." := NoSeries.PeekNextNo(GSTJournalBatch."No. Series", "Posting Date"); end; "Account Type" := LastGSTJournalLine."Account Type"; diff --git a/Apps/IN/INGST/app/GSTSales/app.json b/Apps/IN/INGST/app/GSTSales/app.json index 4ff383801e..c95ebc4b51 100644 --- a/Apps/IN/INGST/app/GSTSales/app.json +++ b/Apps/IN/INGST/app/GSTSales/app.json @@ -2,7 +2,7 @@ "id": "3312f794-b498-4664-9ce8-d9ab32c8a128", "name": "GST Sales", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Contains features for GST on sales transactions.", "description": "GST Sales lets you calculate GST on sales transactions such as sales orders, invoices, sales returns, credit memos, and journals.", "features": [ @@ -19,26 +19,26 @@ "id": "c1eafb3f-e397-468e-bdb4-ecc5c317ca00", "publisher": "Microsoft", "name": "Tax Engine", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "d3c551dd-5903-4194-b153-04ced9d29a2c", "publisher": "Microsoft", "name": "India Tax Base", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "e3cf5645-b42c-412a-ac9d-bd85793266e5", "publisher": "Microsoft", "name": "GST Base", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "application": "24.0.0.0", - "platform": "24.0.0.0", + "application": "25.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 18141, diff --git a/Apps/IN/INGST/app/GSTSales/src/Codeunit/GSTShiptoAddress.Codeunit.al b/Apps/IN/INGST/app/GSTSales/src/Codeunit/GSTShiptoAddress.Codeunit.al index 3c4d3f14db..8d7026339c 100644 --- a/Apps/IN/INGST/app/GSTSales/src/Codeunit/GSTShiptoAddress.Codeunit.al +++ b/Apps/IN/INGST/app/GSTSales/src/Codeunit/GSTShiptoAddress.Codeunit.al @@ -22,8 +22,13 @@ codeunit 18151 "GST Ship To Address" var SelltoCustomer: Record Customer; begin - if SelltoCustomer.Get(SalesHeader."Sell-to Customer No.") then - SalesHeader.State := SelltoCustomer."State Code"; + if SalesHeader."Sell-to Customer No." <> SalesHeader."Bill-to Customer No." then begin + if SelltoCustomer.Get(SalesHeader."Bill-to Customer No.") then + SalesHeader.State := SelltoCustomer."State Code"; + end + else + if SelltoCustomer.Get(SalesHeader."Sell-to Customer No.") then + SalesHeader.State := SelltoCustomer."State Code"; end; procedure UpdateShiptoAddressState(var SalesHeader: Record "Sales Header") @@ -179,14 +184,15 @@ codeunit 18151 "GST Ship To Address" PresentRegNo := ShipToAddress."ARN No."; end; - Exit(PresentRegNo); + exit(PresentRegNo); end; - procedure CheckUpdatePreviousLineGSTPlaceofSupply(Var SalesLine: Record "Sales Line") + procedure CheckUpdatePreviousLineGSTPlaceofSupply(var SalesLine: Record "Sales Line") var PreviousSalesLine: Record "Sales Line"; begin PreviousSalesLine.SetCurrentKey("Document Type", "Document No.", Type, "No."); + PreviousSalesLine.LoadFields("Document Type", "Document No.", Type, "No."); PreviousSalesLine.SetRange("Document Type", SalesLine."Document Type"); PreviousSalesLine.SetRange("Document No.", SalesLine."Document No."); PreviousSalesLine.SetFilter(Type, '<>%1', Type::" "); diff --git a/Apps/IN/INGST/app/GSTSales/src/PageExtension/GSTSalesOrderStats.PageExt.al b/Apps/IN/INGST/app/GSTSales/src/PageExtension/GSTSalesOrderStats.PageExt.al index 1e07b3ccd9..e06172abc4 100644 --- a/Apps/IN/INGST/app/GSTSales/src/PageExtension/GSTSalesOrderStats.PageExt.al +++ b/Apps/IN/INGST/app/GSTSales/src/PageExtension/GSTSalesOrderStats.PageExt.al @@ -5,6 +5,7 @@ namespace Microsoft.Sales.Document; using Microsoft.Finance.GST.Application; +using Microsoft.Finance.GST.Base; pageextension 18163 "GST Sales Order Stats." extends "Sales Order Statistics" { @@ -20,6 +21,26 @@ pageextension 18163 "GST Sales Order Stats." extends "Sales Order Statistics" Caption = 'GST Amount'; } } + addlast(Invoicing) + { + field("Inv. GST Amount"; PartialInvGSTAmount) + { + Caption = 'GST Amount'; + ToolTip = 'Specifies the amount of GST that is partial amount of total.'; + ApplicationArea = Basic, Suite; + Editable = false; + } + } + addlast(Shipping) + { + field("Inv. GST Amt"; PartialShptGSTAmount) + { + Caption = 'GST Amount'; + ToolTip = 'Specifies the amount of GST that is partial amount of total.'; + ApplicationArea = Basic, Suite; + Editable = false; + } + } } trigger OnAfterGetRecord() @@ -30,8 +51,11 @@ pageextension 18163 "GST Sales Order Stats." extends "Sales Order Statistics" local procedure GetGSTAmount() var GSTStatsManagement: Codeunit "GST Stats Management"; + GSTStatistics: Codeunit "GST Statistics"; begin GSTAmount := GSTStatsManagement.GetGstStatsAmount(); + GSTStatistics.GetPartialSalesStatisticsAmount(Rec, PartialInvGSTAmount); + GSTStatistics.GetPartialSalesShptStatisticsAmount(Rec, PartialShptGSTAmount); Calculated := true; GSTStatsManagement.ClearSessionVariable(); end; @@ -45,5 +69,7 @@ pageextension 18163 "GST Sales Order Stats." extends "Sales Order Statistics" var GSTAmount: Decimal; + PartialInvGSTAmount: Decimal; + PartialShptGSTAmount: Decimal; Calculated: Boolean; } diff --git a/Apps/IN/INGST/app/GSTService/app.json b/Apps/IN/INGST/app/GSTService/app.json index b7030ab833..15147088bc 100644 --- a/Apps/IN/INGST/app/GSTService/app.json +++ b/Apps/IN/INGST/app/GSTService/app.json @@ -2,7 +2,7 @@ "id": "5a449416-ab35-4609-8dda-018519f41550", "name": "GST Service", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "GST on Service lets you calculate GST on service transactions such as Service Quote, Service Contract, Service Order, Service Invoice and Service Credit Memo.", "description": "GST on services contains feature for calculating GST when creating transactions related to service.", "features": [ @@ -18,26 +18,26 @@ "id": "d3c551dd-5903-4194-b153-04ced9d29a2c", "publisher": "Microsoft", "name": "India Tax Base", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "2370cfbe-5b06-482a-be41-aa08ad0c800d", "publisher": "Microsoft", "name": "GST Purchase", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "c1eafb3f-e397-468e-bdb4-ecc5c317ca00", "publisher": "Microsoft", "name": "Tax Engine", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "application": "24.0.0.0", - "platform": "24.0.0.0", + "application": "25.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 18440, diff --git a/Apps/IN/INGST/app/GSTService/src/Codeunit/GSTServiceShiptoAddress.Codeunit.al b/Apps/IN/INGST/app/GSTService/src/Codeunit/GSTServiceShiptoAddress.Codeunit.al index f31e4f1e8e..61fab1815a 100644 --- a/Apps/IN/INGST/app/GSTService/src/Codeunit/GSTServiceShiptoAddress.Codeunit.al +++ b/Apps/IN/INGST/app/GSTService/src/Codeunit/GSTServiceShiptoAddress.Codeunit.al @@ -176,14 +176,15 @@ codeunit 18156 "GST Service Ship To Address" PresentRegNo := ShipToAddress."ARN No."; end; - Exit(PresentRegNo); + exit(PresentRegNo); end; - procedure CheckUpdatePreviousLineGSTPlaceofSupply(Var ServiceLine: Record "Service Line") + procedure CheckUpdatePreviousLineGSTPlaceofSupply(var ServiceLine: Record "Service Line") var PreviousServiceLine: Record "Service Line"; begin PreviousServiceLine.SetCurrentKey("Document Type", "Document No.", Type, "No."); + PreviousServiceLine.LoadFields("Document Type", "Document No.", Type, "No."); PreviousServiceLine.SetRange("Document Type", ServiceLine."Document Type"); PreviousServiceLine.SetRange("Document No.", ServiceLine."Document No."); PreviousServiceLine.SetFilter(Type, '<>%1', Type::" "); diff --git a/Apps/IN/INGST/app/GSTService/src/Codeunit/GSTServiceValidations.Codeunit.al b/Apps/IN/INGST/app/GSTService/src/Codeunit/GSTServiceValidations.Codeunit.al index 6704838fcb..7936cd8380 100644 --- a/Apps/IN/INGST/app/GSTService/src/Codeunit/GSTServiceValidations.Codeunit.al +++ b/Apps/IN/INGST/app/GSTService/src/Codeunit/GSTServiceValidations.Codeunit.al @@ -780,6 +780,26 @@ codeunit 18440 "GST Service Validations" Error(RefErr); end; + [EventSubscriber(ObjectType::Table, Database::"Service Header", 'OnValidateShipToCodeOnAfterCalcShouldUpdateShipToAddressFields', '', false, false)] + local procedure OnValidateShipToCodeOnAfterCalcShouldUpdateShipToAddressFields(var ServiceHeader: Record "Service Header"; var ShouldUpdateShipToAddressFields: Boolean) + begin + UpdateShiptoCodeCreditMemoDocument(ServiceHeader, ShouldUpdateShipToAddressFields); + end; + + local procedure UpdateShiptoCodeCreditMemoDocument(var ServiceHeader: Record "Service Header"; ShouldUpdateShipToAddressFields: Boolean) + var + ShipToAddress: Record "Ship-to Address"; + begin + if ShouldUpdateShipToAddressFields then + exit; + + if ServiceHeader."GST Customer Type" = ServiceHeader."GST Customer Type"::" " then + exit; + + if ServiceHeader."Document Type" = ServiceHeader."Document Type"::"Credit Memo" then + if ShipToAddress.Get(ServiceHeader."Customer No.", ServiceHeader."Ship-to Code") then + ShipToAddrfields(ServiceHeader, ShipToAddress); + end; [IntegrationEvent(false, false)] local procedure OnBeforeServiceLineHSNSACEditable(ServiceLine: Record "Service Line"; var IsEditable: Boolean; var IsHandled: Boolean) diff --git a/Apps/IN/INGST/app/GSTService/src/PageExtension/GSTServiceCrMemoSubform.PageExt.al b/Apps/IN/INGST/app/GSTService/src/PageExtension/GSTServiceCrMemoSubform.PageExt.al index 33eb7a1505..f4831d6ffe 100644 --- a/Apps/IN/INGST/app/GSTService/src/PageExtension/GSTServiceCrMemoSubform.PageExt.al +++ b/Apps/IN/INGST/app/GSTService/src/PageExtension/GSTServiceCrMemoSubform.PageExt.al @@ -65,6 +65,11 @@ pageextension 18445 "GST Service Cr. Memo Subform" extends "Service Credit Memo ApplicationArea = Basic, Suite; Editable = true; ToolTip = 'Specifies on which location state code system should consider for GST calculation in case of sale of product or service.'; + trigger OnValidate() + begin + CurrPage.SaveRecord(); + CalculateTax.CallTaxEngineOnServiceLine(Rec, xRec); + end; } field("GST Group Type"; Rec."GST Group Type") { diff --git a/Apps/IN/INGST/app/GSTService/src/PageExtension/GSTServiceCreditMemo.PageExt.al b/Apps/IN/INGST/app/GSTService/src/PageExtension/GSTServiceCreditMemo.PageExt.al index 79c0877bf0..69da74c145 100644 --- a/Apps/IN/INGST/app/GSTService/src/PageExtension/GSTServiceCreditMemo.PageExt.al +++ b/Apps/IN/INGST/app/GSTService/src/PageExtension/GSTServiceCreditMemo.PageExt.al @@ -181,6 +181,19 @@ pageextension 18444 "GST Service Credit Memo" extends "Service Credit Memo" } } } + addbefore("Ship-to Name") + { + field("Ship-to Code"; Rec."Ship-to Code") + { + ApplicationArea = Service; + ToolTip = 'Specifies a code for an alternate shipment address if you want to ship to another address than the one that has been defined automatically. This field is also used in case of drop shipment.'; + + trigger OnValidate() + begin + ShiptoCodeOnAfterValidate(); + end; + } + } } actions { @@ -203,6 +216,11 @@ pageextension 18444 "GST Service Credit Memo" extends "Service Credit Memo" } } + local procedure ShiptoCodeOnAfterValidate() + begin + CurrPage.Update(); + end; + var IsRateChangeEnabled: Boolean; diff --git a/Apps/IN/INGST/app/GSTServiceTransfer/app.json b/Apps/IN/INGST/app/GSTServiceTransfer/app.json index 4a7c04a2b4..8b42726deb 100644 --- a/Apps/IN/INGST/app/GSTServiceTransfer/app.json +++ b/Apps/IN/INGST/app/GSTServiceTransfer/app.json @@ -2,7 +2,7 @@ "id": "1a03de13-ff11-4546-bdce-cde54edc82fe", "name": "GST Service Transfer", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Contains features for transferring services between locations.", "description": "GST Service Transfer allows you to calculate GST when you transfer service from one location to another.", "features": [ @@ -19,26 +19,26 @@ "id": "c1eafb3f-e397-468e-bdb4-ecc5c317ca00", "publisher": "Microsoft", "name": "Tax Engine", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "d3c551dd-5903-4194-b153-04ced9d29a2c", "publisher": "Microsoft", "name": "India Tax Base", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "e3cf5645-b42c-412a-ac9d-bd85793266e5", "publisher": "Microsoft", "name": "GST Base", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "application": "24.0.0.0", - "platform": "24.0.0.0", + "application": "25.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 18350, diff --git a/Apps/IN/INGST/app/GSTServiceTransfer/src/codeunit/ServiceTransferPost.codeunit.al b/Apps/IN/INGST/app/GSTServiceTransfer/src/codeunit/ServiceTransferPost.codeunit.al index 0c7d047f2c..a9ea111f1d 100644 --- a/Apps/IN/INGST/app/GSTServiceTransfer/src/codeunit/ServiceTransferPost.codeunit.al +++ b/Apps/IN/INGST/app/GSTServiceTransfer/src/codeunit/ServiceTransferPost.codeunit.al @@ -378,7 +378,7 @@ codeunit 18350 "Service Transfer Post" local procedure InsertServiceTransShptHeader(ServTransHeader: Record "Service Transfer Header"): Code[20] var ServiceTransferShptHeader: Record "Service Transfer Shpt. Header"; - NoSeriesManagement: Codeunit NoSeriesManagement; + NoSeries: Codeunit "No. Series"; begin ServiceTransferShptHeader.LockTable(); @@ -411,8 +411,7 @@ codeunit 18350 "Service Transfer Post" ServiceTransferShptHeader."Assigned User ID" := ServTransHeader."Assigned User ID"; GetServiceShipmentPostingNoSeries(ServTransHeader); ServiceTransferShptHeader."No. Series" := ServTransHeader."No. Series"; - ServiceTransferShptHeader."No." := NoSeriesManagement.GetNextNo( - ServiceTransferShptHeader."No. Series", ServTransHeader."Shipment Date", true); + ServiceTransferShptHeader."No." := NoSeries.GetNextNo(ServiceTransferShptHeader."No. Series", ServTransHeader."Shipment Date"); ServiceTransferShptHeader.Insert(); exit(ServiceTransferShptHeader."No."); end; @@ -456,7 +455,7 @@ codeunit 18350 "Service Transfer Post" local procedure InsertServiceTransRcptHeader(ServTransHeader: Record "Service Transfer Header"): Code[20] var ServiceTransferRcptHeader: Record "Service Transfer Rcpt. Header"; - NoSeriesManagement: Codeunit NoSeriesManagement; + NoSeries: Codeunit "No. Series"; begin ServiceTransferRcptHeader.LockTable(); ServiceTransferRcptHeader.Init(); @@ -489,8 +488,7 @@ codeunit 18350 "Service Transfer Post" ServiceTransferRcptHeader."External Doc No." := ServTransHeader."External Doc No."; GetServiceReceiptPostingNoSeries(ServTransHeader); ServiceTransferRcptHeader."No. Series" := ServTransHeader."No. Series"; - ServiceTransferRcptHeader."No." := NoSeriesManagement.GetNextNo( - ServiceTransferRcptHeader."No. Series", ServTransHeader."Receipt Date", true); + ServiceTransferRcptHeader."No." := NoSeries.GetNextNo(ServiceTransferRcptHeader."No. Series", ServTransHeader."Receipt Date"); ServiceTransferRcptHeader.Insert(); exit(ServiceTransferRcptHeader."No."); end; diff --git a/Apps/IN/INGST/app/GSTServiceTransfer/src/table/ServiceTransferHeader.table.al b/Apps/IN/INGST/app/GSTServiceTransfer/src/table/ServiceTransferHeader.table.al index e97f4abfdb..8100d96fde 100644 --- a/Apps/IN/INGST/app/GSTServiceTransfer/src/table/ServiceTransferHeader.table.al +++ b/Apps/IN/INGST/app/GSTServiceTransfer/src/table/ServiceTransferHeader.table.al @@ -457,7 +457,7 @@ table 18350 "Service Transfer Header" "No. Series" := xRec."No. Series"; "No." := NoSeries.GetNextNo("No. Series", "Shipment Date"); #if not CLEAN24 - NoSeriesManagement.RaiseObsoleteOnAfterInitSeries("No. Series", NoSeriesCode, "Shipment Date", "No."); + NoSeriesManagement.RaiseObsoleteOnAfterInitSeries("No. Series", NoSeriesCode, "Shipment Date", "No."); end; #endif end; @@ -519,13 +519,13 @@ table 18350 "Service Transfer Header" procedure AssistEdit(OldServiceTransferHeader: Record "Service Transfer Header"): Boolean var - NoSeriesManagement: Codeunit NoSeriesManagement; + NoSeries: Codeunit "No. Series"; begin ServiceTransferHeader := Rec; GetInventorySetup(); InventorySetup.TestField("Service Transfer Order Nos."); - if NoSeriesManagement.SelectSeries(GetNoSeriesCode(), OldServiceTransferHeader."No. Series", "No. Series") then begin - NoSeriesManagement.SetSeries("No."); + if NoSeries.LookupRelatedNoSeries(GetNoSeriesCode(), OldServiceTransferHeader."No. Series", "No. Series") then begin + "No." := NoSeries.GetNextNo("No. Series"); Rec := ServiceTransferHeader; exit(true); end; diff --git a/Apps/IN/INGST/app/GSTStockTransfer/app.json b/Apps/IN/INGST/app/GSTStockTransfer/app.json index 246efe6770..5e8fa0cede 100644 --- a/Apps/IN/INGST/app/GSTStockTransfer/app.json +++ b/Apps/IN/INGST/app/GSTStockTransfer/app.json @@ -2,7 +2,7 @@ "id": "dc030b4e-79f1-4b79-b694-556900859881", "name": "GST Stock Transfer", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Contains features for GST on stock transfers.", "description": "GST Stock Transfer contains features for calculating GST when you transfer stock.", "features": [ @@ -19,26 +19,26 @@ "id": "c1eafb3f-e397-468e-bdb4-ecc5c317ca00", "publisher": "Microsoft", "name": "Tax Engine", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "d3c551dd-5903-4194-b153-04ced9d29a2c", "publisher": "Microsoft", "name": "India Tax Base", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "e3cf5645-b42c-412a-ac9d-bd85793266e5", "publisher": "Microsoft", "name": "GST Base", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "application": "24.0.0.0", - "platform": "24.0.0.0", + "application": "25.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 18390, diff --git a/Apps/IN/INGST/app/GSTStockTransfer/src/codeunit/EInvJsonHandlerForTransShpt.Codeunit.al b/Apps/IN/INGST/app/GSTStockTransfer/src/codeunit/EInvJsonHandlerForTransShpt.Codeunit.al new file mode 100644 index 0000000000..a9d21d4120 --- /dev/null +++ b/Apps/IN/INGST/app/GSTStockTransfer/src/codeunit/EInvJsonHandlerForTransShpt.Codeunit.al @@ -0,0 +1,663 @@ +// ------------------------------------------------------------------------------------------------ +// 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.GST.StockTransfer; + +using Microsoft.Finance.GST.Base; +using Microsoft.Finance.GST.Sales; +using Microsoft.Inventory.Location; +using Microsoft.Inventory.Transfer; +using Microsoft.QRGeneration; +using System.Security.Encryption; +using System.Text; +using System.Utilities; + +codeunit 18023 "E-InvJsonHandlerForTransShpt" +{ + trigger OnRun() + begin + Initialize(); + + if IsInvoice then + RunTransferShipment(); + + if DocumentNo = '' then + Error(DocumentNoBlankErr); + + ExportAsJson(DocumentNo); + end; + + var + TransferShipmentHeader: Record "Transfer Shipment Header"; + JObject: JsonObject; + JsonArrayData: JsonArray; + IsInvoice: Boolean; + TransferToGSTReg: Code[20]; + TransferFromGSTINNo: Code[20]; + JsonText: Text; + DocumentNo: Text[20]; + GSTLbl: Label 'GST', Locked = true; + B2BLbl: Label 'B2B', Locked = true; + CGSTLbl: Label 'CGST', Locked = true; + SGSTLbl: label 'SGST', Locked = true; + IGSTLbl: Label 'IGST', Locked = true; + CESSLbl: Label 'CESS', Locked = true; + IRNTxt: Label 'Irn', Locked = true; + AcknowledgementNoTxt: Label 'AckNo', Locked = true; + AcknowledgementDateTxt: Label 'AckDt', Locked = true; + IRNHashErr: Label 'No matched IRN Hash %1 found to update.', Comment = '%1 = IRN Hash'; + SignedQRCodeTxt: Label 'SignedQRCode', Locked = true; + DocumentNoBlankErr: Label 'E-Invoicing is not supported if document number is blank in the current document.', Locked = true; + + + procedure SetTransferShipmentHeader(TransferShipmentHeaderBuff: Record "Transfer Shipment Header") + begin + TransferShipmentHeader := TransferShipmentHeaderBuff; + IsInvoice := true; + end; + + local procedure RunTransferShipment() + begin + if not IsInvoice then + exit; + + DocumentNo := TransferShipmentHeader."No."; + WriteJsonFileHeader(); + ReadTransactionDetails(); + ReadTransferDocumentDetails(); + ReadDocumentTransferToDetails(); + ReadDocumentTransferFromDetails(); + ReadDocumentValueDetails(); + ReadItemListDetail(); + end; + + local procedure Initialize() + begin + Clear(JObject); + Clear(JsonArrayData); + Clear(JsonText); + end; + + local procedure WriteJsonFileHeader() + begin + JObject.Add('Version', '1.1'); + JsonArrayData.Add(JObject); + end; + + local procedure ExportAsJson(FileName: Text[20]) + var + TempBlob: Codeunit "Temp Blob"; + ToFile: Variant; + InStream: InStream; + OutStream: OutStream; + begin + clear(JsonArrayData); + JsonArrayData.Add(JObject); + JsonArrayData.WriteTo(JsonText); + TempBlob.CreateOutStream(OutStream); + OutStream.WriteText(JsonText); + ToFile := FileName + '.json'; + TempBlob.CreateInStream(InStream); + DownloadFromStream(InStream, 'e-Invoice', '', '', ToFile); + end; + + procedure GenerateCanceledInvoice() + begin + Initialize(); + + if IsInvoice then begin + DocumentNo := TransferShipmentHeader."No."; + WriteCancellationJSON(TransferShipmentHeader."IRN Hash", TransferShipmentHeader."Cancel Reason", Format(TransferShipmentHeader."Cancel Reason")) + end; + + if DocumentNo <> '' then + ExportAsJson(DocumentNo); + end; + + local procedure WriteCancellationJSON(IRNHash: Text[64]; CancelReason: Enum "e-Invoice Cancel Reason"; CancelRemark: Text[100]) + var + CancelJsonObject: JsonObject; + begin + WriteCancelJsonFileHeader(); + CancelJsonObject.Add('Canceldtls', ''); + CancelJsonObject.Add('IRN', IRNHash); + CancelJsonObject.Add('CnlRsn', Format(CancelReason)); + CancelJsonObject.Add('CnlRem', CancelRemark); + JsonArrayData.Add(CancelJsonObject); + JObject.Add('ExpDtls', JsonArrayData); + end; + + local procedure WriteCancelJsonFileHeader() + begin + JObject.Add('Version', '1.1'); + JsonArrayData.Add(JObject); + end; + + local procedure ReadTransactionDetails() + var + NatureOfSupplyCategory: Text[7]; + SupplyType: Text[3]; + IgstOnIntra: Text[3]; + + begin + SupplyType := B2BLbl; + NatureOfSupplyCategory := B2BLbl; + if GetComponentCode() then + IgstOnIntra := 'Y' + else + IgstOnIntra := 'N'; + + WriteTransactionDetails(NatureOfSupplyCategory, 'N', '', IgstOnIntra); + end; + + local procedure WriteTransactionDetails( + SupplyCategory: Text[7]; + RegRev: Text[2]; + EcmGstin: Text[15]; + IgstOnIntra: Text[3]) + var + JTranDetails: JsonObject; + begin + JTranDetails.Add('TaxSch', GSTLbl); + JTranDetails.Add('SupTyp', SupplyCategory); + JTranDetails.Add('RegRev', RegRev); + + if EcmGstin <> '' then + JTranDetails.Add('EcmGstin', EcmGstin); + + JTranDetails.Add('IgstOnIntra', IgstOnIntra); + JObject.Add('TranDtls', JTranDetails); + end; + + local procedure ReadTransferDocumentDetails() + var + PostingDate: Text[10]; + OriginalDocNo: Text[16]; + begin + Clear(JsonArrayData); + + if IsInvoice then + PostingDate := Format(TransferShipmentHeader."Posting Date", 0, '//'); + + OriginalDocNo := CopyStr(GetReferenceInvoiceNo(DocumentNo), 1, 16); + WriteDocumentHeaderDetails(CopyStr(DocumentNo, 1, 16), PostingDate, OriginalDocNo); + end; + + local procedure WriteDocumentHeaderDetails(DocNo: Text[16]; PostingDate: Text[10]; OriginalDocNo: Text[16]) + var + JDocumentHeaderDetails: JsonObject; + begin + JDocumentHeaderDetails.Add('No', DocNo); + JDocumentHeaderDetails.Add('Dt', PostingDate); + JDocumentHeaderDetails.Add('OrgInvNo', OriginalDocNo); + JObject.Add('DocDtls', JDocumentHeaderDetails); + end; + + local procedure GetReferenceInvoiceNo(DocNo: Code[20]) RefInvNo: Code[20] + var + ReferenceInvoiceNo: Record "Reference Invoice No."; + begin + ReferenceInvoiceNo.LoadFields("Document No."); + ReferenceInvoiceNo.SetRange("Document No.", DocNo); + if ReferenceInvoiceNo.FindFirst() then + RefInvNo := ReferenceInvoiceNo."Reference Invoice Nos." + else + RefInvNo := ''; + end; + + local procedure ReadDocumentTransferFromDetails() + var + Location: Record "Location"; + TransferFromName: Text[100]; + TransferFromName2: Text[100]; + TransferFromAddress: Text[100]; + TransferFromAddress2: Text[100]; + TransferFromCity: Text[60]; + TransferFromPostCode: Code[20]; + TransferFromPhoneNo: Text[30]; + TransferFromEmail: Text[80]; + StateCode: Code[10]; + TransferFromContact: Text[100]; + begin + Clear(JsonArrayData); + if IsInvoice then + Location.Get(TransferShipmentHeader."Transfer-from Code"); + + TransferFromName := Location.Name; + TransferFromName2 := Location."Name 2"; + TransferFromAddress := Location.Address; + TransferFromAddress2 := Location."Address 2"; + TransferFromCity := Location.City; + TransferFromPostCode := Location."Post Code"; + TransferFromContact := TransferShipmentHeader."Transfer-from Contact"; + TransferFromGSTINNo := Location."GST Registration No."; + TransferFromPhoneNo := Location."Phone No."; + TransferFromEmail := Location."E-Mail"; + StateCode := Location."State Code"; + WriteDocumentTransferFromDetails(TransferFromName, TransferFromName2, TransferFromAddress, TransferFromAddress2, TransferFromCity, TransferFromPostCode, TransferFromGSTINNo, StateCode, TransferFromPhoneNo, TransferFromEmail); + end; + + local procedure WriteDocumentTransferFromDetails( + TransferFromName: Text[100]; + TransferFromName2: Text[100]; + TransferFromAddress: Text[100]; + TransferFromAddress2: Text[100]; + TransferFromCity: Text[60]; + TransferFromPostCode: Code[20]; + GSTINNo: Code[20]; + StateCode: Code[10]; + TransferFromPhoneNo: Text[30]; + TransferFromEmail: Text[80]) + var + SellerDetails: JsonObject; + begin + SellerDetails.Add('GSTINNO', GSTINNo); + SellerDetails.Add('LegalName', TransferFromName); + + if TransferFromName2 <> '' then + SellerDetails.Add('TradeName', TransferFromName2); + + SellerDetails.Add('Address1', TransferFromAddress); + + if TransferFromAddress2 <> '' then + SellerDetails.Add('Address2', TransferFromAddress2); + + SellerDetails.Add('Location', TransferFromCity); + SellerDetails.Add('PinCode', TransferFromPostCode); + SellerDetails.Add('StateCode', StateCode); + SellerDetails.Add('PhoneNo', TransferFromPhoneNo); + SellerDetails.Add('E-mail', TransferFromEmail); + JObject.Add('SellerDetails', SellerDetails); + end; + + local procedure ReadDocumentTransferToDetails() + var + Location: Record Location; + TransferToName: Text[100]; + TransferToName2: Text[50]; + TransferToAddress: Text[100]; + TransferToAddress2: Text[100]; + TransferToCity: Text[60]; + TransferToPostCode: Code[20]; + TransferToPhoneNo: Text[30]; + TransferToEmail: Text[80]; + StateCode: Code[10]; + begin + Clear(JsonArrayData); + if IsInvoice then + Location.Get(TransferShipmentHeader."Transfer-to Code"); + + TransferToName := Location.Name; + TransferToName2 := Location."Name 2"; + TransferToAddress := Location.Address; + TransferToAddress2 := Location."Address 2"; + TransferToCity := Location.City; + TransferToPostCode := Location."Post Code"; + TransferToPhoneNo := Location."Phone No."; + TransferToEmail := Location."E-Mail"; + StateCode := Location."State Code"; + TransferToGSTReg := Location."GST Registration No."; + WriteDocumentTransferToDetails(TransferToName, TransferToName2, TransferToAddress, TransferToAddress2, TransferToCity, TransferToPostCode, StateCode, TransferToPhoneNo, TransferToEmail, TransferToGSTReg); + end; + + local procedure WriteDocumentTransferToDetails(TransferToName: Text[100]; + TransferToName2: Text[50]; + TransferToAddress: Text[100]; + TransferToAddress2: Text[100]; + TransferToCity: Text[60]; + TransferToPostCode: Code[20]; + StateCode: Code[10]; + TransferToPhoneNo: Text[30]; + TransferToEmail: Text[80]; + TransferToGSTReg: code[20]) + var + BuyerDetails: JsonObject; + begin + BuyerDetails.Add('GSTINNO', TransferToGSTReg); + BuyerDetails.Add('LegalName', TransferToName); + + if TransferToName2 <> '' then + BuyerDetails.Add('TradeName', TransferToName2); + + BuyerDetails.Add('Address1', TransferToAddress); + + if TransferToAddress2 <> '' then + BuyerDetails.Add('Address2', TransferToAddress2); + + BuyerDetails.Add('Location', TransferToCity); + BuyerDetails.Add('PinCode', TransferToPostCode); + BuyerDetails.Add('StateCode', StateCode); + BuyerDetails.Add('PhoneNo', TransferToPhoneNo); + BuyerDetails.Add('E-mail', TransferToEmail); + JObject.Add('BuyerDetails', BuyerDetails); + end; + + local procedure ReadItemListDetail() + var + TransferShipmentLine: Record "Transfer Shipment Line"; + GstRate: Decimal; + CGSTRate: Decimal; + SGSTRate: Decimal; + IGSTRate: Decimal; + CessRate: Decimal; + CesNonAdval: Decimal; + CGSTValue: Decimal; + SGSTValue: Decimal; + IGSTValue: Decimal; + CessValue: Decimal; + IsService: Text[1]; + HSNCode: Code[20]; + Count: Integer; + begin + Clear(JsonArrayData); + Count := 1; + if IsInvoice then begin + TransferShipmentLine.LoadFields("Document No.", "Line No.", "Item No.", Description, "Description 2", Quantity, "Unit of Measure Code", "Unit Price", Amount, "GST Assessable Value"); + TransferShipmentLine.SetRange("Document No.", TransferShipmentHeader."No."); + TransferShipmentLine.SetFilter("Item No.", '<>%1', ''); + if TransferShipmentLine.FindSet() then + repeat + IsService := 'N'; + GetGSTValueForLine(TransferShipmentLine."Line No.", CGSTValue, SGSTValue, IGSTValue, CGSTRate, SGSTRate, IGSTRate, CessRate, CessValue, CesNonAdval); + if IGSTRate <> 0 then + GstRate := IGSTRate + else + GstRate := CGSTRate + SGSTRate; + HSNCode := TransferShipmentLine."HSN/SAC Code"; + + WriteItem(Format(Count), TransferShipmentLine.Description + TransferShipmentLine."Description 2", IsService, HSNCode, GstRate, TransferShipmentLine.Quantity, CopyStr(TransferShipmentLine."Unit of Measure Code", 1, 3), TransferShipmentLine."Unit Price", TransferShipmentLine.Amount, TransferShipmentLine."GST Assessable Value", CGSTValue, SGSTValue, IGSTValue, CessRate, CessValue, CesNonAdval, (TransferShipmentLine.Amount + TransferShipmentLine."GST Assessable Value" + CGSTValue + SGSTValue + IGSTValue + CessValue)); + Count += 1; + until TransferShipmentLine.Next() = 0; + end; + JObject.Add('ItemList', JsonArrayData); + end; + + local procedure GetGSTValueForLine(DocumentLineNo: Integer; + var CGSTLineAmount: Decimal; + var SGSTLineAmount: Decimal; + var IGSTLineAmount: Decimal; + var CGSTRate: Decimal; + var SGSTRate: Decimal; + var IGSTRate: Decimal; + var CessRate: Decimal; + var CessValue: Decimal; + var CessNonAdvanceAmount: Decimal) + var + DetailedGSTLedgerEntry: Record "Detailed GST Ledger Entry"; + GSTDocumentType: Enum "GST Document Type"; + DGLETransactionType: Enum "Detail Ledger Transaction Type"; + begin + CGSTLineAmount := 0; + SGSTLineAmount := 0; + IGSTLineAmount := 0; + + DetailedGSTLedgerEntry.LoadFields("Transaction Type", "Document Type", "Document No.", "GST Component Code", "GST Amount"); + DetailedGSTLedgerEntry.SetRange("Transaction Type", DGLETransactionType::Sales); + DetailedGSTLedgerEntry.SetRange("Document Type", GSTDocumentType::Invoice); + DetailedGSTLedgerEntry.SetRange("Document No.", DocumentNo); + DetailedGSTLedgerEntry.SetRange("Document Line No.", DocumentLineNo); + DetailedGSTLedgerEntry.SetRange("GST Component Code", CGSTLbl); + if DetailedGSTLedgerEntry.FindSet() then begin + DetailedGSTLedgerEntry.CalcSums("GST Amount"); + CGSTLineAmount := Abs(DetailedGSTLedgerEntry."GST Amount"); + CGSTRate := DetailedGSTLedgerEntry."GST %"; + end; + + DetailedGSTLedgerEntry.SetRange("GST Component Code", SGSTLbl); + if DetailedGSTLedgerEntry.FindSet() then begin + DetailedGSTLedgerEntry.CalcSums("GST Amount"); + SGSTLineAmount := Abs(DetailedGSTLedgerEntry."GST Amount"); + SGSTRate := DetailedGSTLedgerEntry."GST %"; + end; + + DetailedGSTLedgerEntry.SetRange("GST Component Code", IGSTLbl); + if DetailedGSTLedgerEntry.FindSet() then begin + IGSTRate := DetailedGSTLedgerEntry."GST %"; + DetailedGSTLedgerEntry.CalcSums("GST Amount"); + IGSTLineAmount := Abs(DetailedGSTLedgerEntry."GST Amount"); + end; + + DetailedGSTLedgerEntry.SetRange("GST Component Code", CESSLbl); + if DetailedGSTLedgerEntry.FindSet() then begin + DetailedGSTLedgerEntry.CalcSums("GST Amount"); + CessValue := Abs(DetailedGSTLedgerEntry."GST Amount"); + CessRate := DetailedGSTLedgerEntry."GST %"; + end; + CessNonAdvanceAmount := 0; + end; + + local procedure WriteItem( + SlNo: Text[1]; + ProductName: Text[200]; + IsService: Text[1]; + HSNCode: Code[20]; + GstRate: Decimal; + Quantity: Decimal; + Unit: code[10]; + UnitPrice: Decimal; + TotAmount: Decimal; + AssessableAmount: Decimal; + CGSTRate: Decimal; + SGSTRate: Decimal; + IGSTRate: Decimal; + CESSRate: Decimal; + CESSValue: Decimal; + CessNonAdvanceAmount: Decimal; + TotalItemValue: Decimal) + var + JItem: JsonObject; + begin + JItem.Add('SlNo', SlNo); + JItem.Add('PrdDesc', ProductName); + JItem.Add('IsService', IsService); + JItem.Add('HsnCd', HSNCode); + JItem.Add('Qty', Quantity); + JItem.Add('Unit', Unit); + JItem.Add('UnitPrice', UnitPrice); + JItem.Add('TotAmt', TotAmount); + JItem.Add('AssAmt', AssessableAmount); + JItem.Add('GstRt', GstRate); + JItem.Add('CgstAmt', CGSTRate); + JItem.Add('SgstAmt', SGSTRate); + JItem.Add('IgstAmt', IGSTRate); + JItem.Add('CesRt', CESSRate); + JItem.Add('CesAmt', CESSValue); + JItem.Add('CesNonAdval', CessNonAdvanceAmount); + JItem.Add('TotItemVal', TotalItemValue); + + JsonArrayData.Add(JItem); + end; + + local procedure ReadDocumentValueDetails() + var + AssessableAmount: Decimal; + CGSTAmount: Decimal; + SGSTAmount: Decimal; + IGSTAmount: Decimal; + CessAmount: Decimal; + CESSNonAvailmentAmount: Decimal; + OtherCharges: Decimal; + TotalInvoiceValue: Decimal; + begin + Clear(JsonArrayData); + GetGSTValue(AssessableAmount, CGSTAmount, SGSTAmount, IGSTAmount, CessAmount, CESSNonAvailmentAmount, OtherCharges, TotalInvoiceValue); + WriteDocumentTotalDetails(AssessableAmount, CGSTAmount, SGSTAmount, IGSTAmount, CessAmount, CESSNonAvailmentAmount, OtherCharges, ABS(TotalInvoiceValue)); + + end; + + local procedure WriteDocumentTotalDetails( + AssessableAmount: Decimal; + CGSTAmount: Decimal; + SGSTAmount: Decimal; + IGSTAmount: Decimal; + CessAmount: Decimal; + CessNonAdvanceVal: Decimal; + OtherCharges: Decimal; + TotalInvoiceAmount: Decimal) + var + JDocTotalDetails: JsonObject; + begin + JDocTotalDetails.Add('Assval', AssessableAmount); + JDocTotalDetails.Add('CgstVal', CGSTAmount); + JDocTotalDetails.Add('SgstVAl', SGSTAmount); + JDocTotalDetails.Add('IgstVal', IGSTAmount); + JDocTotalDetails.Add('CesVal', CessAmount); + JDocTotalDetails.Add('CesNonAdVal', CessNonAdvanceVal); + JDocTotalDetails.Add('OthChrg', OtherCharges); + JDocTotalDetails.Add('TotInvVal', TotalInvoiceAmount); + + JObject.Add('ValueDetails', JDocTotalDetails); + end; + + + local procedure GetGSTValue( + var AssessableAmount: Decimal; + var CGSTAmount: Decimal; + var SGSTAmount: Decimal; + var IGSTAmount: Decimal; + var CessAmount: Decimal; + var CessNonAdvanceAmount: Decimal; + var OtherCharges: Decimal; + var TotalInvoiceValue: Decimal) + var + TransferShipmentLine: Record "Transfer Shipment Line"; + DetailedGSTLedgerEntry: Record "Detailed GST Ledger Entry"; + GSTDocumentType: Enum "GST Document Type"; + DGLETransactionType: Enum "Detail Ledger Transaction Type"; + TotGSTAmt: Decimal; + begin + TotalInvoiceValue := 0; + DetailedGSTLedgerEntry.LoadFields("Transaction Type", "Document Type", "Document No.", "GST Component Code", "GST Amount"); + DetailedGSTLedgerEntry.SetRange("Transaction Type", DGLETransactionType::Sales); + DetailedGSTLedgerEntry.SetRange("Document Type", GSTDocumentType::Invoice); + DetailedGSTLedgerEntry.SetRange("Document No.", DocumentNo); + DetailedGSTLedgerEntry.SetRange("GST Component Code", IGSTLbl); + if not DetailedGSTLedgerEntry.IsEmpty() then begin + DetailedGSTLedgerEntry.CalcSums("GST Amount"); + IGSTAmount := Abs(DetailedGSTLedgerEntry."GST Amount") + end; + + DetailedGSTLedgerEntry.SetRange("GST Component Code", CGSTLbl); + if not DetailedGSTLedgerEntry.IsEmpty() then begin + DetailedGSTLedgerEntry.CalcSums("GST Amount"); + CGSTAmount := Abs(DetailedGSTLedgerEntry."GST Amount") + end; + + DetailedGSTLedgerEntry.SetRange("GST Component Code", SGSTLbl); + if not DetailedGSTLedgerEntry.IsEmpty() then begin + DetailedGSTLedgerEntry.CalcSums("GST Amount"); + SGSTAmount := Abs(DetailedGSTLedgerEntry."GST Amount") + end; + + DetailedGSTLedgerEntry.SetRange("GST Component Code", CESSLbl); + if DetailedGSTLedgerEntry.FindSet() then begin + DetailedGSTLedgerEntry.CalcSums("GST Amount"); + if DetailedGSTLedgerEntry."GST %" > 0 then + CessAmount := Abs(DetailedGSTLedgerEntry."GST Amount") + else + CessNonAdvanceAmount := Abs(DetailedGSTLedgerEntry."GST Amount"); + end; + + if IsInvoice then begin + TransferShipmentLine.LoadFields("Document No.", "GST Assessable Value"); + TransferShipmentLine.SetRange("Document No.", DocumentNo); + if not TransferShipmentLine.IsEmpty() then + TransferShipmentLine.CalcSums("GST Assessable Value"); + + AssessableAmount := TransferShipmentLine."GST Assessable Value"; + TotGSTAmt := CGSTAmount + SGSTAmount + IGSTAmount + CessAmount + CessNonAdvanceAmount; + end; + + if IsInvoice then begin + DetailedGSTLedgerEntry.Reset(); + DetailedGSTLedgerEntry.LoadFields("Transaction Type", "Document Type", "Document No.", "GST Base Amount"); + DetailedGSTLedgerEntry.SetRange("Transaction Type", DGLETransactionType::Sales); + DetailedGSTLedgerEntry.SetRange("Document Type", GSTDocumentType::Invoice); + DetailedGSTLedgerEntry.SetRange("Document No.", DocumentNo); + if not DetailedGSTLedgerEntry.IsEmpty() then + TotalInvoiceValue := Abs(DetailedGSTLedgerEntry."GST Base Amount") + TotGSTAmt; + end; + OtherCharges := 0; + end; + + local procedure GetComponentCode(): Boolean + var + GSTLedgerEntry: Record "GST Ledger Entry"; + GSTLedgerSrcType: enum "GST Ledger Source Type"; + ComponentCode: Code[30]; + begin + GSTLedgerEntry.LoadFields("Document No.", "GST Component Code"); + GSTLedgerEntry.SetRange("Source Type", GSTLedgerSrcType::Transfer); + GSTLedgerEntry.SetRange("Document No.", DocumentNo); + if GSTLedgerEntry.FindFirst() then + ComponentCode := GSTLedgerEntry."GST Component Code"; + + if ComponentCode = IGSTLbl then + exit(true); + end; + + procedure GetEInvoiceResponse(var RecRef: RecordRef) + var + JSONManagement: Codeunit "JSON Management"; + QRGenerator: Codeunit "QR Generator"; + TempBlob: Codeunit "Temp Blob"; + FieldRef: FieldRef; + JsonString: Text; + TempIRNTxt: Text; + TempDateTime: DateTime; + AcknowledgementDateTimeText: Text; + AcknowledgementDate: Date; + AcknowledgementTime: Time; + begin + JsonString := GetResponseText(); + if (JsonString = '') or (JsonString = '[]') then + exit; + + JSONManagement.InitializeObject(JsonString); + if JSONManagement.GetValue(IRNTxt) <> '' then begin + FieldRef := RecRef.Field(TransferShipmentHeader.FieldNo("IRN Hash")); + FieldRef.Value := JSONManagement.GetValue(IRNTxt); + FieldRef := RecRef.Field(TransferShipmentHeader.FieldNo("Acknowledgement No.")); + FieldRef.Value := JSONManagement.GetValue(AcknowledgementNoTxt); + + AcknowledgementDateTimeText := JSONManagement.GetValue(AcknowledgementDateTxt); + Evaluate(AcknowledgementDate, CopyStr(AcknowledgementDateTimeText, 1, 10)); + Evaluate(AcknowledgementTime, CopyStr(AcknowledgementDateTimeText, 11, 8)); + TempDateTime := CreateDateTime(AcknowledgementDate, AcknowledgementTime); + FieldRef := RecRef.Field(TransferShipmentHeader.FieldNo("Acknowledgement Date")); + + FieldRef.Value := TempDateTime; + FieldRef := RecRef.Field(TransferShipmentHeader.FieldNo(IsJSONImported)); + FieldRef.Value := true; + QRGenerator.GenerateQRCodeImage(JSONManagement.GetValue(SignedQRCodeTxt), TempBlob); + FieldRef := RecRef.Field(TransferShipmentHeader.FieldNo("QR Code")); + TempBlob.ToRecordRef(RecRef, TransferShipmentHeader.FieldNo("QR Code")); + RecRef.Modify(); + end else + Error(IRNHashErr, TempIRNTxt); + end; + + local procedure GetResponseText() ResponseText: Text + var + TempBlob: Codeunit "Temp Blob"; + InStream: InStream; + FileText: Text; + begin + TempBlob.CreateInStream(InStream); + UploadIntoStream('', '', '', FileText, InStream); + + if FileText = '' then + exit; + + InStream.ReadText(ResponseText); + end; + + procedure GenerateIRN(input: Text): Text + var + CryptographyManagement: Codeunit "Cryptography Management"; + HashAlgorithmType: Option MD5,SHA1,SHA256,SHA384,SHA512; + begin + exit(CryptographyManagement.GenerateHash(input, HashAlgorithmType::SHA256)); + end; +} \ No newline at end of file diff --git a/Apps/IN/INGST/app/GSTStockTransfer/src/codeunit/EInvTransShptJsonManagement.Codeunit.al b/Apps/IN/INGST/app/GSTStockTransfer/src/codeunit/EInvTransShptJsonManagement.Codeunit.al new file mode 100644 index 0000000000..46664ef0e1 --- /dev/null +++ b/Apps/IN/INGST/app/GSTStockTransfer/src/codeunit/EInvTransShptJsonManagement.Codeunit.al @@ -0,0 +1,123 @@ +// ------------------------------------------------------------------------------------------------ +// 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.GST.StockTransfer; + +using Microsoft.Finance.GST.Base; +using Microsoft.Finance.TaxBase; +using Microsoft.Finance.TaxEngine.TaxTypeHandler; +using Microsoft.Inventory.Location; +using Microsoft.Inventory.Transfer; + +codeunit 18021 "EInvTransshptJsonManagement" +{ + var + IRNLengthErr: Label 'IRN Hash must be 64 character text.', Locked = true; + TaxableLbl: Label 'Taxable', Locked = true; + NonGSTLbl: Label 'Non-GST', Locked = true; + AccountingPeriodErr: Label 'Tax Accounting Period does not exist for the given Date %1.', Comment = '%1 = Posting Date'; + + [EventSubscriber(ObjectType::Table, Database::"Transfer Shipment Header", 'OnAfterValidateEvent', 'IRN Hash', false, false)] + local procedure OnAfterValidateIRNHashOnTransferShipment(var Rec: Record "Transfer Shipment Header") + begin + CheckIRNHashLength(Rec."IRN Hash"); + end; + + procedure IsGSTApplicable(DocumentNo: Code[20]; TableID: Integer): Boolean + var + GSTSetup: Record "GST Setup"; + begin + if not GSTSetup.Get() then + exit; + + GSTSetup.TestField("GST Tax Type"); + case TableID of + Database::"Transfer Shipment Header": + exit(CheckTransferShipmentLine(DocumentNo, GSTSetup."GST Tax Type")); + end; + end; + + local procedure CheckTransferShipmentLine(DocumentNo: Code[20]; TaxType: Code[20]): Boolean + var + TransferShipmentLine: Record "Transfer Shipment Line"; + Found: Boolean; + begin + TransferShipmentLine.LoadFields("Document No.", "Item No."); + TransferShipmentLine.SetRange("Document No.", DocumentNo); + TransferShipmentLine.SetFilter("Item No.", '<>%1', ''); + if TransferShipmentLine.FindSet() then + repeat + Found := TransactionValueExist(TransferShipmentLine.RecordId, TaxType); + until (TransferShipmentLine.Next() = 0) or Found; + + exit(Found); + end; + + local procedure TransactionValueExist(RecID: RecordID; TaxType: Code[20]): Boolean + var + TaxTransactionValue: Record "Tax Transaction Value"; + begin + TaxTransactionValue.LoadFields("Tax Type", "Tax Record ID"); + TaxTransactionValue.SetRange("Tax Type", TaxType); + TaxTransactionValue.SetRange("Tax Record ID", RecId); + exit(not TaxTransactionValue.IsEmpty()); + end; + + local procedure CheckIRNHashLength(IRNHash: Text[64]) + begin + if (IRNHash <> '') and (StrLen(IRNHash) < 64) then + Error(IRNLengthErr); + end; + + procedure GenerateIRN(DocNo: Code[20]; CallByTable: Integer) + var + TaxAccountingPeriod: Record "Tax Accounting Period"; + GSTSetup: Record "GST Setup"; + TaxType: Record "Tax Type"; + TransferShipmentHeader: Record "Transfer Shipment Header"; + Location: Record Location; + RecordRef: RecordRef; + FieldRef: FieldRef; + IRNInput: Text[64]; + FINYr: Text; + InvoiceTypeText: Text; + PostingDate: Date; + begin + TransferShipmentHeader.Get(DocNo); + RecordRef.Open(CallByTable); + FieldRef := RecordRef.Field(3); + FieldRef.Value := DocNo; + + if not GSTSetup.Get() then + exit; + + TaxType.Get(GSTSetup."GST Tax Type"); + + if not IsGSTApplicable(DocNo, CallByTable) then + exit; + + PostingDate := TransferShipmentHeader."Posting Date"; + + TaxAccountingPeriod.LoadFields("Tax Type Code", "Starting Date", "Ending Date"); + TaxAccountingPeriod.SetRange("Tax Type Code", TaxType."Accounting Period"); + TaxAccountingPeriod.SetFilter("Starting Date", '<=%1', PostingDate); + TaxAccountingPeriod.SetFilter("Ending Date", '>=%1', PostingDate); + if TaxAccountingPeriod.FindFirst() then begin + FINYr := Format(TaxAccountingPeriod."Starting Date", 0, ''); + FINYr += '-' + Format(TaxAccountingPeriod."Ending Date", 0, ''); + end else + Error(AccountingPeriodErr, PostingDate); + + if CallByTable = Database::"Transfer Shipment Header" then + if TransferShipmentHeader."Transfer-from Code" <> TransferShipmentHeader."Transfer-to Code" then + InvoiceTypeText := TaxableLbl + else + InvoiceTypeText := NonGSTLbl; + + Location.Get(TransferShipmentHeader."Transfer-from Code"); + IRNInput := Location."GST Registration No." + FINYr + InvoiceTypeText + DocNo; + TransferShipmentHeader."IRN Hash" := IRNInput; + TransferShipmentHeader.Modify(); + end; +} \ No newline at end of file diff --git a/Apps/IN/INGST/app/GSTStockTransfer/src/codeunit/GSTTransferOrderReceipt.Codeunit.al b/Apps/IN/INGST/app/GSTStockTransfer/src/codeunit/GSTTransferOrderReceipt.Codeunit.al index 190a26231b..aefbf0d294 100644 --- a/Apps/IN/INGST/app/GSTStockTransfer/src/codeunit/GSTTransferOrderReceipt.Codeunit.al +++ b/Apps/IN/INGST/app/GSTStockTransfer/src/codeunit/GSTTransferOrderReceipt.Codeunit.al @@ -80,14 +80,14 @@ codeunit 18390 "GST Transfer Order Receipt" [EventSubscriber(ObjectType::Codeunit, Codeunit::"TransferOrder-Post Receipt", 'OnBeforeTransRcptHeaderInsert', '', false, false)] local procedure GetPostingNoSeries(TransferHeader: Record "Transfer Header"; var TransferReceiptHeader: Record "Transfer Receipt Header") var - NoSeriesManagement: Codeunit NoSeriesManagement; + NoSeriesCodeunit: Codeunit "No. Series"; NoSeries: Code[20]; begin NoSeries := GetTransferReceiptPostingNoSeries(TransferHeader); if NoSeries <> '' then begin TransferReceiptHeader."No. Series" := NoSeries; if TransferReceiptHeader."No. Series" <> '' then - TransferReceiptHeader."No." := NoSeriesManagement.GetNextNo(TransferReceiptHeader."No. Series", TransferHeader."Posting Date", true); + TransferReceiptHeader."No." := NoSeriesCodeunit.GetNextNo(TransferReceiptHeader."No. Series", TransferHeader."Posting Date"); end; end; @@ -220,11 +220,16 @@ codeunit 18390 "GST Transfer Order Receipt" var Item: Record Item; CustomDutyBase: Boolean; + IsHandled: Boolean; begin FirstExecution := true; if TransReceiptHeaderNo <> TransferReceiptHeader."No." then TransReceiptHeaderNo := TransferReceiptHeader."No."; + OnBeforePostTransferOrderReceiptGLEntries(TempTransferBufferfinal, TransferHeader, TransferReceiptHeader, IsHandled); + if IsHandled then + exit; + //Post GL Entries TempTransferBufferfinal.Reset(); if TempTransferBufferfinal.FindLast() then @@ -233,10 +238,12 @@ codeunit 18390 "GST Transfer Order Receipt" // Post GST to G/L entries from GST posting buffer.. GST Sales GSTPostingBufferforTransferDocument(CustomDutyBase, TransferHeader); // Post Unrealized Profit Account Entries + OnBeforePostUnrealizedPorfitAccountEntries(TempTransferBufferfinal, TransferHeader, TransferReceiptHeader); if not (TempTransferBufferfinal."Gen. Bus. Posting Group" <> '') then PostUnrealizedProfitAccountEntries(TransferHeader, TempTransferBufferfinal, TransferReceiptHeader); // Amount loaded on inventory + OnBeforePostInventoryEntries(TempTransferBufferfinal, TransferHeader); if (TempTransferBufferfinal."Amount Loaded on Inventory" <> 0) or (TempTransferBufferfinal."GST Amount Loaded on Inventory" <> 0) then PostInventoryEntries(TransferHeader, TempTransferBufferfinal); @@ -1284,4 +1291,19 @@ codeunit 18390 "GST Transfer Order Receipt" local procedure OnBeforeInsertTransRcptLineFillBuffer(var TransferLine: Record "Transfer Line"; var IsHandled: Boolean) begin end; + + [IntegrationEvent(false, false)] + local procedure OnBeforePostTransferOrderReceiptGLEntries(var TempTransferBufferFinal: Record "Transfer Buffer" temporary; var TransferHeader: Record "Transfer Header"; var TransferReceiptHeader: Record "Transfer Receipt Header"; var IsHandled: Boolean) + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnBeforePostUnrealizedPorfitAccountEntries(var TempTransferBufferFinal: Record "Transfer Buffer" temporary; var TransferHeader: Record "Transfer Header"; var TransferReceiptHeader: Record "Transfer Receipt Header") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnBeforePostInventoryEntries(var TempTransferBufferFinal: Record "Transfer Buffer" temporary; var TransferHeader: Record "Transfer Header") + begin + end; } diff --git a/Apps/IN/INGST/app/GSTStockTransfer/src/codeunit/GSTTransferOrderShipment.Codeunit.al b/Apps/IN/INGST/app/GSTStockTransfer/src/codeunit/GSTTransferOrderShipment.Codeunit.al index d6c9f1f0eb..b82a29275e 100644 --- a/Apps/IN/INGST/app/GSTStockTransfer/src/codeunit/GSTTransferOrderShipment.Codeunit.al +++ b/Apps/IN/INGST/app/GSTStockTransfer/src/codeunit/GSTTransferOrderShipment.Codeunit.al @@ -984,13 +984,13 @@ codeunit 18391 "GST Transfer Order Shipment" [EventSubscriber(ObjectType::Codeunit, Codeunit::"TransferOrder-Post Shipment", 'OnBeforeGenNextNo', '', false, false)] local procedure GetPostingNoSeries(TransferHeader: Record "Transfer Header"; var TransferShipmentHeader: Record "Transfer Shipment Header") var - NoSeriesManagement: Codeunit NoSeriesManagement; + NoSeries: Codeunit "No. Series"; NoSeriesCode: Code[20]; begin NoSeriesCode := GetTransferShipmentPostingNoSeries(TransferHeader); if NoSeriesCode <> '' then begin TransferShipmentHeader."No. Series" := NoSeriesCode; - TransferShipmentHeader."No." := NoSeriesManagement.GetNextNo(TransferShipmentHeader."No. Series", TransferHeader."Posting Date", true); + TransferShipmentHeader."No." := NoSeries.GetNextNo(TransferShipmentHeader."No. Series", TransferHeader."Posting Date"); end; end; @@ -1024,7 +1024,8 @@ codeunit 18391 "GST Transfer Order Shipment" local procedure PostGLEntries(var TransferHeader: Record "Transfer Header"; TransferShipmentHeader: Record "Transfer Shipment Header") var InventoryPostingSetup: Record "Inventory Posting Setup"; - Item: Record Item; + TransferLine: Record "Transfer Line"; + IsHandled: Boolean; begin // Post GST to G/L entries from GST posting buffer.. GST Sales TempGSTPostingBufferFinal.Reset(); @@ -1048,16 +1049,26 @@ codeunit 18391 "GST Transfer Order Shipment" PostTransLineToGenJnlLine(TransferHeader, TransferShipmentHeader."No."); until TempGSTPostingBufferFinal.Next() = 0; + OnBeforeGetInventoryPostingSetup(TempGSTPostingBufferFinal, TransferHeader, TransferShipmentHeader, IsHandled); + if IsHandled then + exit; + TempTransferBufferFinal.Reset(); TempTransferBufferFinal.SetCurrentKey("sorting no."); TempTransferBufferFinal.SetAscending("Sorting No.", false); if TempTransferBufferFinal.Findset() then repeat - if Item.Get(TempTransferBufferFinal."Item No.") and (Item."HSN/SAC Code" <> '') then begin + TransferLine.LoadFields("Document No.", "Item No.", "HSN/SAC Code"); + TransferLine.SetRange("Document No.", TransferHeader."No."); + TransferLine.SetRange("Item No.", TempTransferBufferFinal."Item No."); + TransferLine.SetFilter("HSN/SAC Code", '<>%1', ''); + if not TransferLine.IsEmpty() then begin + OnBeforeGetInvPostingSetupOnAfterFindTempTransferBuffer(TempTransferBufferFinal, TempGSTPostingBufferFinal, TransferHeader, TransferShipmentHeader, TransferLine, InventoryPostingSetup); InventoryPostingSetup.Get(TransferHeader."In-Transit Code", TempTransferBufferFinal."Inventory Posting Group"); InventoryPostingSetup.TestField("Unrealized Profit Account"); end; + OnBeforePostGeneralEntries(TempTransferBufferFinal, TransferShipmentHeader, TransferHeader, InventoryPostingSetup); PostGeneralEntries(TempTransferBufferFinal, TransferShipmentHeader, TransferHeader, InventoryPostingSetup); until TempTransferBufferFinal.Next() = 0; end; @@ -1182,4 +1193,19 @@ codeunit 18391 "GST Transfer Order Shipment" local procedure OnBeforeInsertTransShptLineFillBuffer(var TransShptLine: Record "Transfer Shipment Line"; TransLine: Record "Transfer Line"; var IsHandled: Boolean) begin end; + + [IntegrationEvent(false, false)] + local procedure OnBeforeGetInventoryPostingSetup(var TempGSTPostingBufferFinal: Record "GST Posting Buffer" temporary; var TransferHeader: Record "Transfer Header"; var TransferShipmentHeader: Record "Transfer Shipment Header"; var IsHandled: Boolean) + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnBeforeGetInvPostingSetupOnAfterFindTempTransferBuffer(var TempTransferBufferFinal: Record "Transfer Buffer" temporary; var TempGSTPostingBufferFinal: Record "GST Posting Buffer" temporary; var TransferHeader: Record "Transfer Header"; var TransferShipmentHeader: Record "Transfer Shipment Header"; var TransferLine: Record "Transfer Line"; var InventoryPostingSetup: Record "Inventory Posting Setup") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnBeforePostGeneralEntries(var TempTransferBufferFinal: Record "Transfer Buffer" temporary; var TransferShipmentHeader: Record "Transfer Shipment Header"; var TransferHeader: Record "Transfer Header"; var InventoryPostingSetup: Record "Inventory Posting Setup") + begin + end; } diff --git a/Apps/IN/INGST/app/GSTStockTransfer/src/page/TransferShipmentDialog.Page.al b/Apps/IN/INGST/app/GSTStockTransfer/src/page/TransferShipmentDialog.Page.al new file mode 100644 index 0000000000..70ce5b15a7 --- /dev/null +++ b/Apps/IN/INGST/app/GSTStockTransfer/src/page/TransferShipmentDialog.Page.al @@ -0,0 +1,67 @@ +// ------------------------------------------------------------------------------------------------ +// 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.GST.StockTransfer; + +using Microsoft.Inventory.Transfer; + +page 18012 "Transfer Shipment Dialog" +{ + PageType = StandardDialog; + ApplicationArea = All; + DataCaptionExpression = ''; + PopulateAllFields = true; + SourceTable = "Transfer Shipment Header"; + Permissions = tabledata "Transfer Shipment Header" = rm; + + layout + { + area(Content) + { + group(Group) + { + field("E-Way Bill No."; Rec."E-Way Bill No.") + { + ApplicationArea = Basic, Suite; + ToolTip = 'Specifies the E-way bill number on the Transfer document.'; + } + field("Acknowledgement No."; Rec."Acknowledgement No.") + { + ApplicationArea = Basic, Suite; + Editable = MakeFieldUneditable; + ToolTip = 'Specifies a unique number assigned by e-invoice portal.'; + } + field("Acknowledgement Date"; Rec."Acknowledgement Date") + { + ApplicationArea = Basic, Suite; + Editable = MakeFieldUneditable; + ToolTip = 'Specifies the date of acknowledgement.'; + } + field("IRN Hash"; Rec."IRN Hash") + { + ApplicationArea = Basic, Suite; + Editable = MakeFieldUneditable; + ToolTip = 'Specifies a unique number of 64 character generated by system.'; + } + field("E-Inv. Cancelled Date"; Rec."E-Inv. Cancelled Date") + { + ApplicationArea = Basic, Suite; + ToolTip = 'Specifies e-invoice cancellation date.'; + } + field("Cancel Reason"; Rec."Cancel Reason") + { + ApplicationArea = Basic, Suite; + ToolTip = 'Specifies the cancellation reason.'; + } + } + } + } + trigger OnAfterGetCurrRecord() + begin + MakeFieldUneditable := not Rec.IsJSONImported; + end; + + var + MakeFieldUneditable: Boolean; +} \ No newline at end of file diff --git a/Apps/IN/INGST/app/GSTStockTransfer/src/page/TransferShipmentQRCode.Page.al b/Apps/IN/INGST/app/GSTStockTransfer/src/page/TransferShipmentQRCode.Page.al new file mode 100644 index 0000000000..663a051c00 --- /dev/null +++ b/Apps/IN/INGST/app/GSTStockTransfer/src/page/TransferShipmentQRCode.Page.al @@ -0,0 +1,42 @@ +// ------------------------------------------------------------------------------------------------ +// 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.GST.StockTransfer; + +using Microsoft.Inventory.Transfer; + +page 18013 "Transfer Shipment QR Code" +{ + PageType = CardPart; + SourceTable = "Transfer Shipment Header"; + + layout + { + area(Content) + { + field(UpdateTaxInfoLbl; UpdateTaxInfoLbl) + { + ApplicationArea = All; + ShowCaption = false; + Editable = false; + StyleExpr = true; + Style = Subordinate; + trigger OnDrillDown() + var + TransferShipmentHeader: Record "Transfer Shipment Header"; + begin + TransferShipmentHeader.get(Rec."No."); + Page.Run(Page::"Transfer Shipment Dialog", TransferShipmentHeader); + end; + } + field("QR Code"; Rec."QR Code") + { + ApplicationArea = Basic, Suite; + ToolTip = 'Specifies the QR Code assigned by e-invoice portal for sales document.'; + } + } + } + var + UpdateTaxInfoLbl: Label 'Click here to update Information'; +} \ No newline at end of file diff --git a/Apps/IN/INGST/app/GSTStockTransfer/src/pageextension/GSTPostedTransShipmentExt.PageExt.al b/Apps/IN/INGST/app/GSTStockTransfer/src/pageextension/GSTPostedTransShipmentExt.PageExt.al index dbf92156af..251573d302 100644 --- a/Apps/IN/INGST/app/GSTStockTransfer/src/pageextension/GSTPostedTransShipmentExt.PageExt.al +++ b/Apps/IN/INGST/app/GSTStockTransfer/src/pageextension/GSTPostedTransShipmentExt.PageExt.al @@ -12,7 +12,7 @@ pageextension 18394 "GST Posted Trans. Shipment Ext" extends "Posted Transfer Sh { addafter("Entry/Exit Point") { - Field("Time of Removal"; Rec."Time of Removal") + field("Time of Removal"; Rec."Time of Removal") { ApplicationArea = Basic, Suite; ToolTip = 'Specifies the time of removal.'; @@ -47,6 +47,162 @@ pageextension 18394 "GST Posted Trans. Shipment Ext" extends "Posted Transfer Sh ApplicationArea = Basic, Suite; ToolTip = 'Specifies the distance of the the transfer route.'; } + field("E-Way Bill No."; Rec."E-Way Bill No.") + { + ApplicationArea = Basic, Suite; + ToolTip = 'Specifies the E-way bill number on the purchase document.'; + } + field("Acknowledgement No."; Rec."Acknowledgement No.") + { + ApplicationArea = Basic, Suite; + Editable = MakeFieldUneditable; + ToolTip = 'Specifies a unique number assigned by e-invoice portal.'; + } + field("Acknowledgement Date"; Rec."Acknowledgement Date") + { + ApplicationArea = Basic, Suite; + Editable = MakeFieldUneditable; + ToolTip = 'Specifies the date of acknowledgement.'; + } + field("IRN Hash"; Rec."IRN Hash") + { + ApplicationArea = Basic, Suite; + Editable = MakeFieldUneditable; + ToolTip = 'Specifies a unique number of 64 character generated by system.'; + } + field("E-Inv. Cancelled Date"; Rec."E-Inv. Cancelled Date") + { + ApplicationArea = Basic, Suite; + ToolTip = 'Specifies e-invoice cancellation date.'; + } + field("Cancel Reason"; Rec."Cancel Reason") + { + ApplicationArea = Basic, Suite; + ToolTip = 'Specifies the cancellation reason.'; + } + } + addafter(TaxInformation) + { + part("QR Code"; "Transfer Shipment QR Code") + { + Caption = 'QR Code'; + SubPageLink = "No." = field("No."); + ApplicationArea = Basic, Suite; + } + } + } + + actions + { + addafter(Dimensions) + { + action("Generate IRN") + { + ApplicationArea = Basic, Suite; + Image = UpdateDescription; + ToolTip = 'Specifies the function which will generate IRN No.'; + trigger OnAction() + var + TransShipmentHeader: Record "Transfer Shipment Header"; + eshptJsonManagement: Codeunit EInvTransshptJsonManagement; + begin + if eshptJsonManagement.IsGSTApplicable(Rec."No.", Database::"Transfer Shipment Header") then begin + Clear(eshptJsonManagement); + TransShipmentHeader.Reset(); + TransShipmentHeader.SetRange("No.", Rec."No."); + if not TransShipmentHeader.IsEmpty() then begin + eshptJsonManagement.GenerateIRN(Rec."No.", Database::"Transfer Shipment Header"); + CurrPage.Update(); + end else + Error(eInvoiceNonGSTTransactionErr); + end; + end; + } + action("Cancel E-Invoice") + { + ApplicationArea = Basic, Suite; + Image = Cancel; + ToolTip = 'Specifies the function through which cancelled Json file will be generated.'; + trigger OnAction() + var + TransferShipmentHeader: Record "Transfer Shipment Header"; + eInvJsonHandlerForTransShpt: Codeunit "E-InvJsonHandlerForTransShpt"; + eshptJsonManagement: Codeunit EInvTransshptJsonManagement; + begin + Rec.TestField(Rec."IRN Hash"); + Rec.TestField(Rec."Cancel Reason"); + + if eshptJsonManagement.IsGSTApplicable(Rec."No.", Database::"Transfer Shipment Header") then begin + TransferShipmentHeader.Reset(); + TransferShipmentHeader.SetRange("No.", Rec."No."); + if TransferShipmentHeader.FindFirst() then begin + Clear(eInvJsonHandlerForTransShpt); + TransferShipmentHeader.Mark(true); + eInvJsonHandlerForTransShpt.SetTransferShipmentHeader(TransferShipmentHeader); + eInvJsonHandlerForTransShpt.GenerateCanceledInvoice(); + end; + end else + Error(eInvoiceNonGSTTransactionErr); + end; + } + action("Generate E-Invoice") + { + ApplicationArea = Basic, Suite; + Image = ExportFile; + Promoted = true; + ToolTip = 'Specifies the function through which Json file will be generated.'; + + trigger OnAction() + var + TransferShipmentHeader: Record "Transfer Shipment Header"; + eInvJsonHandlerForTransShpt: Codeunit "e-InvJsonHandlerForTransShpt"; + eshptJsonManagement: Codeunit EInvTransshptJsonManagement; + begin + if eshptJsonManagement.IsGSTApplicable(Rec."No.", Database::"Transfer Shipment Header") then begin + TransferShipmentHeader.Reset(); + TransferShipmentHeader.SetRange("No.", Rec."No."); + if TransferShipmentHeader.FindFirst() then begin + Clear(eInvJsonHandlerForTransShpt); + TransferShipmentHeader.Mark(true); + eInvJsonHandlerForTransShpt.SetTransferShipmentHeader(TransferShipmentHeader); + eInvJsonHandlerForTransShpt.Run(); + end; + end else + Error(eInvoiceNonGSTTransactionErr); + end; + } + action("Import E-Invoice Response") + { + ApplicationArea = Basic, Suite; + Image = ImportCodes; + Promoted = true; + PromotedCategory = Category4; + ToolTip = 'Specifies the function through which Json file can be imported.'; + + trigger OnAction() + var + eInvJsonHandlerForTransShpt: Codeunit "e-InvJsonHandlerForTransShpt"; + eshptJsonManagement: Codeunit EInvTransshptJsonManagement; + RecRef: RecordRef; + begin + if eshptJsonManagement.IsGSTApplicable(Rec."No.", Database::"Transfer Shipment Header") then begin + Clear(eInvJsonHandlerForTransShpt); + Clear(RecRef); + RecRef.GetTable(Rec); + eInvJsonHandlerForTransShpt.GetEInvoiceResponse(RecRef); + CurrPage.Update(); + end else + Error(eInvoiceNonGSTTransactionErr); + end; + } } } -} + trigger OnAfterGetCurrRecord() + begin + MakeFieldUneditable := not Rec.IsJSONImported; + end; + + var + MakeFieldUneditable: Boolean; + eInvoiceNonGSTTransactionErr: Label 'Error'; +} \ No newline at end of file diff --git a/Apps/IN/INGST/app/GSTStockTransfer/src/tableextension/GSTTransShipmentHeaderExt.TableExt.al b/Apps/IN/INGST/app/GSTStockTransfer/src/tableextension/GSTTransShipmentHeaderExt.TableExt.al index ea181e36ff..32453fae2c 100644 --- a/Apps/IN/INGST/app/GSTStockTransfer/src/tableextension/GSTTransShipmentHeaderExt.TableExt.al +++ b/Apps/IN/INGST/app/GSTStockTransfer/src/tableextension/GSTTransShipmentHeaderExt.TableExt.al @@ -5,6 +5,7 @@ namespace Microsoft.Finance.GST.StockTransfer; using Microsoft.Finance.GST.Base; +using Microsoft.Finance.GST.Sales; using Microsoft.Inventory.Transfer; using Microsoft.Purchases.Vendor; @@ -63,5 +64,46 @@ tableextension 18396 "GST Trans. Shipment Header Ext" extends "Transfer Shipment Caption = 'Time of Removal'; DataClassification = CustomerContent; } + field(18403; "Acknowledgement No."; Text[30]) + { + Caption = 'Acknowledgement No.'; + DataClassification = CustomerContent; + } + field(18404; "IRN Hash"; Text[64]) + { + Caption = 'IRN Hash'; + DataClassification = CustomerContent; + } + field(18405; "QR Code"; Blob) + { + Subtype = Bitmap; + Caption = 'QR Code'; + DataClassification = CustomerContent; + } + field(18406; "Acknowledgement Date"; DateTime) + { + Caption = 'Acknowledgement Date'; + DataClassification = CustomerContent; + } + field(18407; "IsJSONImported"; Boolean) + { + Caption = 'IsJSONImported'; + DataClassification = EndUserPseudonymousIdentifiers; + } + field(18408; "E-Inv. Cancelled Date"; DateTime) + { + Caption = 'E-Inv. Cancelled Date'; + DataClassification = CustomerContent; + } + field(18409; "Cancel Reason"; Enum "e-Invoice Cancel Reason") + { + Caption = 'Cancel Reason'; + DataClassification = CustomerContent; + } + field(18410; "E-Way Bill No."; Text[50]) + { + Caption = 'E-Way Bill No.'; + DataClassification = CustomerContent; + } } } diff --git a/Apps/IN/INGST/app/GSTStockTransfer/src/tableextension/GSTTransferHeaderExt.TableExt.al b/Apps/IN/INGST/app/GSTStockTransfer/src/tableextension/GSTTransferHeaderExt.TableExt.al index 158e1e9ddd..a72fb58719 100644 --- a/Apps/IN/INGST/app/GSTStockTransfer/src/tableextension/GSTTransferHeaderExt.TableExt.al +++ b/Apps/IN/INGST/app/GSTStockTransfer/src/tableextension/GSTTransferHeaderExt.TableExt.al @@ -5,6 +5,7 @@ namespace Microsoft.Finance.GST.StockTransfer; using Microsoft.Finance.GST.Base; +using Microsoft.Finance.GST.Sales; using Microsoft.Inventory.Transfer; using Microsoft.Purchases.Vendor; @@ -73,5 +74,46 @@ tableextension 18391 "GST Transfer Header Ext" extends "Transfer Header" Caption = 'Vehicle Type'; DataClassification = CustomerContent; } + field(18403; "Acknowledgement No."; Text[30]) + { + Caption = 'Acknowledgement No.'; + DataClassification = CustomerContent; + } + field(18404; "IRN Hash"; Text[64]) + { + Caption = 'IRN Hash'; + DataClassification = CustomerContent; + } + field(18405; "QR Code"; Blob) + { + Subtype = Bitmap; + Caption = 'QR Code'; + DataClassification = CustomerContent; + } + field(18406; "Acknowledgement Date"; DateTime) + { + Caption = 'Acknowledgement Date'; + DataClassification = CustomerContent; + } + field(18407; "IsJSONImported"; Boolean) + { + Caption = 'IsJSONImported'; + DataClassification = EndUserPseudonymousIdentifiers; + } + field(18408; "E-Inv. Cancelled Date"; DateTime) + { + Caption = 'E-Inv. Cancelled Date'; + DataClassification = CustomerContent; + } + field(18409; "Cancel Reason"; Enum "e-Invoice Cancel Reason") + { + Caption = 'Cancel Reason'; + DataClassification = CustomerContent; + } + field(18410; "E-Way Bill No."; Text[50]) + { + Caption = 'E-Way Bill No.'; + DataClassification = CustomerContent; + } } } diff --git a/Apps/IN/INGST/app/GSTSubcontracting/app.json b/Apps/IN/INGST/app/GSTSubcontracting/app.json index 0f2571abfe..866df404e1 100644 --- a/Apps/IN/INGST/app/GSTSubcontracting/app.json +++ b/Apps/IN/INGST/app/GSTSubcontracting/app.json @@ -2,7 +2,7 @@ "id": "55bb842b-34ef-48fe-9234-f39d858a3adb", "name": "GSTSubcontracting", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Contains features for GST Subcontracting.", "description": "GST Subcontracting Features", "features": [ @@ -19,20 +19,20 @@ "id": "c1eafb3f-e397-468e-bdb4-ecc5c317ca00", "publisher": "Microsoft", "name": "Tax Engine", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "d3c551dd-5903-4194-b153-04ced9d29a2c", "publisher": "Microsoft", "name": "India Tax Base", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "application": "24.0.0.0", - "platform": "24.0.0.0", + "application": "25.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 18466, diff --git a/Apps/IN/INGST/app/GSTSubcontracting/src/Codeunit/SubcontractingPost.Codeunit.al b/Apps/IN/INGST/app/GSTSubcontracting/src/Codeunit/SubcontractingPost.Codeunit.al index ea241e6e5a..aa6a999f23 100644 --- a/Apps/IN/INGST/app/GSTSubcontracting/src/Codeunit/SubcontractingPost.Codeunit.al +++ b/Apps/IN/INGST/app/GSTSubcontracting/src/Codeunit/SubcontractingPost.Codeunit.al @@ -700,7 +700,7 @@ codeunit 18466 "Subcontracting Post" ItemJnlLine.Validate("Applies-to Entry", ItemLedgerEntry."Entry No."); ItemJnlLine.Validate("Unit Cost", ProdOrderComp."Unit Cost"); - ItemJnlLine."Location Code" := SubOrderCompVend."Vendor Location"; + ItemJnlLine.Validate("Location Code", SubOrderCompVend."Vendor Location"); ItemJnlLine."External Document No." := Purchaseline."Vendor Shipment No."; ItemJnlLine."Source Code" := SourceCodeSetup."Consumption Journal"; ItemJnlLine."Gen. Bus. Posting Group" := ProdOrder."Gen. Bus. Posting Group"; diff --git a/Apps/IN/INGST/app/GSTSubcontracting/src/Codeunit/SubcontractingPostGSTLiab.Codeunit.al b/Apps/IN/INGST/app/GSTSubcontracting/src/Codeunit/SubcontractingPostGSTLiab.Codeunit.al index c94ac16095..cace4fa3e3 100644 --- a/Apps/IN/INGST/app/GSTSubcontracting/src/Codeunit/SubcontractingPostGSTLiab.Codeunit.al +++ b/Apps/IN/INGST/app/GSTSubcontracting/src/Codeunit/SubcontractingPostGSTLiab.Codeunit.al @@ -23,7 +23,6 @@ codeunit 18468 "Subcontracting Post GST Liab." TempGSTPostingBufferStage: Record "GST Posting Buffer" temporary; TempGSTPostingBufferFinal: Record "GST Posting Buffer" temporary; GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; - NoSeriesMgt: Codeunit "NoSeriesManagement"; GLSetupRead: Boolean; SourceCodeSetupRead: Boolean; TransactionNo: Integer; @@ -160,7 +159,7 @@ codeunit 18468 "Subcontracting Post GST Liab." Vendor: Record Vendor; GSTLiabilityLine: Record "GST Liability Line"; DetailedGSTEntryBuffer: Record "Detailed GST Entry Buffer"; - + NoSeries: Codeunit "No. Series"; DeliveryChallanNo: Code[20]; DocumentNo: Code[20]; begin @@ -189,9 +188,8 @@ codeunit 18468 "Subcontracting Post GST Liab." Location.Get(GSTLiabilityLine."Company Location"); Location.TestField("GST Liability Invoice"); Location.TestField("State Code"); - Clear(NoSeriesMgt); if GSTLiabilityLine."Delivery Challan No." <> DeliveryChallanNo then - DocumentNo := NoSeriesMgt.GetNextNo(Location."GST Liability Invoice", GSTLiabilityLine."Posting Date", true); + DocumentNo := NoSeries.GetNextNo(Location."GST Liability Invoice", GSTLiabilityLine."Posting Date"); TempGSTPostingBufferStage."Transaction Type" := TempGSTPostingBufferStage."Transaction Type"::Purchase; TempGSTPostingBufferStage.Type := DetailedGSTEntryBuffer.Type; diff --git a/Apps/IN/INGST/app/GSTSubcontracting/src/Table/DeliveryChallanHeader.Table.al b/Apps/IN/INGST/app/GSTSubcontracting/src/Table/DeliveryChallanHeader.Table.al index 008fdc7a31..7b32bad0a3 100644 --- a/Apps/IN/INGST/app/GSTSubcontracting/src/Table/DeliveryChallanHeader.Table.al +++ b/Apps/IN/INGST/app/GSTSubcontracting/src/Table/DeliveryChallanHeader.Table.al @@ -145,7 +145,7 @@ table 18468 "Delivery Challan Header" "No. Series" := xRec."No. Series"; "No." := NoSeries.GetNextNo("No. Series", Today()); #if not CLEAN24 - NoSeriesManagement.RaiseObsoleteOnAfterInitSeries("No. Series", PurchSetup."Posted Delivery Challan Nos.", Today(), "No."); + NoSeriesManagement.RaiseObsoleteOnAfterInitSeries("No. Series", PurchSetup."Posted Delivery Challan Nos.", Today(), "No."); end; #endif end; @@ -153,14 +153,29 @@ table 18468 "Delivery Challan Header" procedure InitRecord() var - NoSeriesManagement: Codeunit "NoSeriesManagement"; +#if CLEAN24 + NoSeries: Codeunit "No. Series"; +#else +#pragma warning disable AL0432 + NoSeriesManagement2: Codeunit "NoSeriesManagement"; +#pragma warning restore AL0432 +#endif begin - NoSeriesManagement.SetDefaultSeries("No. Series", PurchSetup."Posted Delivery Challan Nos."); +#if CLEAN24 + if NoSeries.IsAutomatic(PurchSetup."Posted Delivery Challan Nos.") then + "No. Series" := PurchSetup."Posted Delivery Challan Nos."; +#else +#pragma warning disable AL0432 + NoSeriesManagement2.SetDefaultSeries("No. Series", PurchSetup."Posted Delivery Challan Nos."); +#pragma warning restore AL0432 +#endif end; var PurchSetup: Record "Purchases & Payables Setup"; #if not CLEAN24 +#pragma warning disable AL0432 NoSeriesManagement: Codeunit "NoSeriesManagement"; +#pragma warning restore AL0432 #endif } diff --git a/Apps/IN/INGST/app/GSTSubcontracting/src/Table/MultipleSubconOrderDetails.Table.al b/Apps/IN/INGST/app/GSTSubcontracting/src/Table/MultipleSubconOrderDetails.Table.al index e870f6218a..276e700139 100644 --- a/Apps/IN/INGST/app/GSTSubcontracting/src/Table/MultipleSubconOrderDetails.Table.al +++ b/Apps/IN/INGST/app/GSTSubcontracting/src/Table/MultipleSubconOrderDetails.Table.al @@ -21,6 +21,8 @@ table 18471 "Multiple Subcon. Order Details" DataClassification = EndUserIdentifiableInformation; trigger OnValidate() + var + NoSeries: Codeunit "No. Series"; begin if "No." <> xRec."No." then begin PurchasePayablesSetup.Get(); @@ -69,13 +71,14 @@ table 18471 "Multiple Subcon. Order Details" trigger OnInsert() var - NoSeries: Record "No. Series"; + NoSeriesRec: Record "No. Series"; + NoSeries: Codeunit "No. Series"; begin if "No." = '' then begin PurchasePayablesSetup.Get(); PurchasePayablesSetup.TestField("Multiple Subcon. Order Det Nos"); - NoSeries.Get(PurchasePayablesSetup."Multiple Subcon. Order Det Nos"); - "No." := NoSeriesMgt.GetNextNo(NoSeries.Code, WorkDate(), true); + NoSeriesRec.Get(PurchasePayablesSetup."Multiple Subcon. Order Det Nos"); + "No." := NoSeries.GetNextNo(NoSeriesRec.Code); "No. Series" := PurchasePayablesSetup."Multiple Subcon. Order Det Nos"; end; "Posting Date" := WorkDate(); @@ -85,14 +88,13 @@ table 18471 "Multiple Subcon. Order Details" procedure AssistEdit(OldMultipleSubconOrdDet: Record "Multiple Subcon. Order Details"): Boolean var MultipleSubconOrdDet: Record "Multiple Subcon. Order Details"; + NoSeries: Codeunit "No. Series"; begin - Copy(Rec); + MultipleSubconOrdDet.Copy(Rec); PurchasePayablesSetup.Get(); PurchasePayablesSetup.TestField("Multiple Subcon. Order Det Nos"); - if NoSeriesMgt.SelectSeries - (PurchasePayablesSetup."Multiple Subcon. Order Det Nos", "No. Series", "No. Series") - then begin - NoSeriesMgt.SetSeries("No."); + if NoSeries.LookupRelatedNoSeries(PurchasePayablesSetup."Multiple Subcon. Order Det Nos", MultipleSubconOrdDet."No. Series", MultipleSubconOrdDet."No. Series") then begin + MultipleSubconOrdDet."No." := NoSeries.GetNextNo(MultipleSubconOrdDet."No. Series"); Rec := MultipleSubconOrdDet; exit(true); end; @@ -100,6 +102,4 @@ table 18471 "Multiple Subcon. Order Details" var PurchasePayablesSetup: Record "Purchases & Payables Setup"; - NoSeriesMgt: Codeunit NoSeriesManagement; - NoSeries: Codeunit "No. Series"; } diff --git a/Apps/IN/INGST/app/GSTSubcontracting/src/Table/SubcontractorDeliveryChallan.Table.al b/Apps/IN/INGST/app/GSTSubcontracting/src/Table/SubcontractorDeliveryChallan.Table.al index 19d0b68f42..749b2d1d9f 100644 --- a/Apps/IN/INGST/app/GSTSubcontracting/src/Table/SubcontractorDeliveryChallan.Table.al +++ b/Apps/IN/INGST/app/GSTSubcontracting/src/Table/SubcontractorDeliveryChallan.Table.al @@ -86,13 +86,13 @@ table 18477 "Subcontractor Delivery Challan" } procedure AssistEdit(OldDeliveryChallan: Record "Subcontractor Delivery Challan"): Boolean + var + NoSeries: Codeunit "No. Series"; begin PurchSetup.Get(); PurchSetup.TestField("Delivery Challan Nos."); - if NoSeriesMgt.SelectSeries(PurchSetup."Delivery Challan Nos.", OldDeliveryChallan."No. Series", "No. Series") then BEGIN - PurchSetup.Get(); - PurchSetup.TestField("Delivery Challan Nos."); - NoSeriesMgt.SetSeries("No."); + if NoSeries.LookupRelatedNoSeries(PurchSetup."Delivery Challan Nos.", OldDeliveryChallan."No. Series", "No. Series") then BEGIN + "No." := NoSeries.GetNextNo("No. Series"); exit(true); end; end; @@ -112,5 +112,4 @@ table 18477 "Subcontractor Delivery Challan" PurchSetup: Record "Purchases & Payables Setup"; Vendor: Record "Vendor"; SubconDeliveryChallanLine: Record "Subcon. Delivery Challan Line"; - NoSeriesMgt: Codeunit NoSeriesManagement; } diff --git a/Apps/IN/INGST/app/Permissions/INAdvanceObjectsIndiaGST.PermissionSet.al b/Apps/IN/INGST/app/Permissions/INAdvanceObjectsIndiaGST.PermissionSet.al index 35f3f63ddc..8cdacb2f5b 100644 --- a/Apps/IN/INGST/app/Permissions/INAdvanceObjectsIndiaGST.PermissionSet.al +++ b/Apps/IN/INGST/app/Permissions/INAdvanceObjectsIndiaGST.PermissionSet.al @@ -70,6 +70,8 @@ permissionset 18358 "IN Advance Objects - India GST" codeunit "GST Ship To Address" = X, codeunit "e-Invoice Json Handler for Ser" = X, codeunit "e-Invoice Management for Ser." = X, + codeunit "E-InvJsonHandlerForTransShpt" = X, + codeunit "EInvTransshptJsonManagement" = X, codeunit "GST Service Posting No. Series" = X, codeunit "GST Service Ship To Address" = X, codeunit "GST Service Validations" = X, 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 299bf34671..02a59c2c4b 100644 --- a/Apps/IN/INGST/app/Translations/India GST.en-GB.xlf +++ b/Apps/IN/INGST/app/Translations/India GST.en-GB.xlf @@ -9722,7 +9722,7 @@ GST Use Cases Codeunit GST Base Tax Engine Setup - Method GetConfig - NamedType {48C973FB-77C2-476C-AB39-0E61F0F76F0D}Lbl GST Use Cases Codeunit GST Base Tax Engine Setup - Method GetConfig - NamedType {4A2B9E24-01A5-43C9-A43E-0E7C9CC1C8BB}Lbl GST Use Cases Codeunit GST Base Tax Engine Setup - Method GetConfig - NamedType {0FD2A76A-DECB-4FAC-8008-10D6762CDAFE}Lbl - GST Use Cases Codeunit GST Base Tax Engine Setup - Method GetConfig - NamedType {B90130D9-0471-4034-8687-11B04ABDCE72}Lbl + GST Use Cases Codeunit GST Base Tax Engine Setup - Method GetConfig - NamedType {B90130D9-0471-4034-8687-11B04ABDCE72}Lbl GST Use Cases Codeunit GST Base Tax Engine Setup - Method GetConfig - NamedType {142D2618-98AC-4DD8-922F-11CF063DD8D8}Lbl GST Use Cases Codeunit GST Base Tax Engine Setup - Method GetConfig - NamedType {047704F8-A619-401F-9653-12103103E14A}Lbl @@ -10023,7 +10023,7 @@ GST Use Cases Codeunit GST Base Tax Engine Setup - Method GetConfig - NamedType {26ED31B0-75B8-439C-8E16-56518665184F}Lbl GST Use Cases Codeunit GST Base Tax Engine Setup - Method GetConfig - NamedType {09CD7163-15FB-4340-82BF-57373BE3E206}Lbl GST Use Cases Codeunit GST Base Tax Engine Setup - Method GetConfig - NamedType {975372FC-F93D-4E8B-81EA-57B6751B9F94}Lbl - GST Use Cases Codeunit GST Base Tax Engine Setup - Method GetConfig - NamedType {AA215442-D318-4160-A666-57E3FBE06CDD}Lbl + GST Use Cases Codeunit GST Base Tax Engine Setup - Method GetConfig - NamedType {AA215442-D318-4160-A666-57E3FBE06CDD}Lbl GST Use Cases Codeunit GST Base Tax Engine Setup - Method GetConfig - NamedType {93FE03BD-63C7-44B5-B40D-5974C8300527}Lbl GST Use Cases @@ -11473,7 +11473,7 @@ Codeunit GST Tax Type Data - Method GetConfig - NamedType {7B096619-70FB-4622-9E57-8EAE58DC1AB1}Lbl GST Use Cases Codeunit GST Tax Type Data - Method GetConfig - NamedType {1FF813B4-1776-4717-8C56-8F0E684ACE73}Lbl - GST Use Cases Codeunit GST Tax Type Data - Method GetConfig - NamedType {4DD701D1-41A9-432E-9E95-8F8D08AB2C67}Lbl + GST Use Cases Codeunit GST Tax Type Data - Method GetConfig - NamedType {4DD701D1-41A9-432E-9E95-8F8D08AB2C67}Lbl GST Use Cases @@ -11812,7 +11812,7 @@ GST Use Cases Codeunit GST Tax Type Data - Method GetConfig - NamedType {C9CE4C92-F6CD-4B97-BD13-D8EE824D7D66}Lbl GST Use Cases Codeunit GST Tax Type Data - Method GetConfig - NamedType {06A818C9-817D-4983-B8D9-D96759380A68}Lbl GST Use Cases Codeunit GST Tax Type Data - Method GetConfig - NamedType {DF134523-53D1-4137-B091-D9C5E1DB8D64}Lbl - GST Use Cases Codeunit GST Tax Type Data - Method GetConfig - NamedType {C0774889-632D-4799-AA04-DA25EB643832}Lbl + GST Use Cases Codeunit GST Tax Type Data - Method GetConfig - NamedType {C0774889-632D-4799-AA04-DA25EB643832}Lbl GST Use Cases Codeunit GST Tax Type Data - Method GetConfig - NamedType {E474605D-6956-438B-95F2-DA5BE6A6D741}Lbl GST Use Cases Codeunit GST Tax Type Data - Method GetConfig - NamedType {FA492219-9C2F-4986-B773-DAA35CA74796}Lbl GST Use Cases Codeunit GST Tax Type Data - Method GetConfig - NamedType {FFBBBCDE-50F5-4D02-8B40-DAD63ED1491E}Lbl @@ -11936,7 +11936,12 @@ Codeunit GST Tax Type Data - Method GetConfig - NamedType {4F992CE7-BB8C-4129-923A-F53A771DF231}Lbl - GST Use Cases Codeunit GST Tax Type Data - Method GetConfig - NamedType {FC1AEFDA-0537-4D94-A576-F542B6710B71}Lbl + + GST Use Cases + + + Codeunit GST Tax Type Data - Method GetConfig - NamedType {FC1AEFDA-0537-4D94-A576-F542B6710B71}Lbl + GST Use Cases Codeunit GST Tax Type Data - Method GetConfig - NamedType {9A744701-39FF-4CFF-AA72-F5856E82FBF4}Lbl GST Use Cases Codeunit GST Tax Type Data - Method GetConfig - NamedType {AA3E77B0-A08A-4756-90E5-F6561C7D4B9B}Lbl GST Use Cases Codeunit GST Tax Type Data - Method GetConfig - NamedType {36A5E0EC-E197-4102-8FF0-F6DC9B4A47C1}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 17e31acfad..491371a26c 100644 --- a/Apps/IN/INGST/app/Translations/India GST.en-US.xlf +++ b/Apps/IN/INGST/app/Translations/India GST.en-US.xlf @@ -9722,7 +9722,7 @@ GST Use Cases Codeunit GST Base Tax Engine Setup - Method GetConfig - NamedType {48C973FB-77C2-476C-AB39-0E61F0F76F0D}Lbl GST Use Cases Codeunit GST Base Tax Engine Setup - Method GetConfig - NamedType {4A2B9E24-01A5-43C9-A43E-0E7C9CC1C8BB}Lbl GST Use Cases Codeunit GST Base Tax Engine Setup - Method GetConfig - NamedType {0FD2A76A-DECB-4FAC-8008-10D6762CDAFE}Lbl - GST Use Cases Codeunit GST Base Tax Engine Setup - Method GetConfig - NamedType {B90130D9-0471-4034-8687-11B04ABDCE72}Lbl + GST Use Cases Codeunit GST Base Tax Engine Setup - Method GetConfig - NamedType {B90130D9-0471-4034-8687-11B04ABDCE72}Lbl GST Use Cases Codeunit GST Base Tax Engine Setup - Method GetConfig - NamedType {142D2618-98AC-4DD8-922F-11CF063DD8D8}Lbl GST Use Cases Codeunit GST Base Tax Engine Setup - Method GetConfig - NamedType {047704F8-A619-401F-9653-12103103E14A}Lbl @@ -10023,7 +10023,7 @@ GST Use Cases Codeunit GST Base Tax Engine Setup - Method GetConfig - NamedType {26ED31B0-75B8-439C-8E16-56518665184F}Lbl GST Use Cases Codeunit GST Base Tax Engine Setup - Method GetConfig - NamedType {09CD7163-15FB-4340-82BF-57373BE3E206}Lbl GST Use Cases Codeunit GST Base Tax Engine Setup - Method GetConfig - NamedType {975372FC-F93D-4E8B-81EA-57B6751B9F94}Lbl - GST Use Cases Codeunit GST Base Tax Engine Setup - Method GetConfig - NamedType {AA215442-D318-4160-A666-57E3FBE06CDD}Lbl + GST Use Cases Codeunit GST Base Tax Engine Setup - Method GetConfig - NamedType {AA215442-D318-4160-A666-57E3FBE06CDD}Lbl GST Use Cases Codeunit GST Base Tax Engine Setup - Method GetConfig - NamedType {93FE03BD-63C7-44B5-B40D-5974C8300527}Lbl GST Use Cases @@ -11473,7 +11473,7 @@ Codeunit GST Tax Type Data - Method GetConfig - NamedType {7B096619-70FB-4622-9E57-8EAE58DC1AB1}Lbl GST Use Cases Codeunit GST Tax Type Data - Method GetConfig - NamedType {1FF813B4-1776-4717-8C56-8F0E684ACE73}Lbl - GST Use Cases Codeunit GST Tax Type Data - Method GetConfig - NamedType {4DD701D1-41A9-432E-9E95-8F8D08AB2C67}Lbl + GST Use Cases Codeunit GST Tax Type Data - Method GetConfig - NamedType {4DD701D1-41A9-432E-9E95-8F8D08AB2C67}Lbl GST Use Cases @@ -11812,7 +11812,7 @@ GST Use Cases Codeunit GST Tax Type Data - Method GetConfig - NamedType {C9CE4C92-F6CD-4B97-BD13-D8EE824D7D66}Lbl GST Use Cases Codeunit GST Tax Type Data - Method GetConfig - NamedType {06A818C9-817D-4983-B8D9-D96759380A68}Lbl GST Use Cases Codeunit GST Tax Type Data - Method GetConfig - NamedType {DF134523-53D1-4137-B091-D9C5E1DB8D64}Lbl - GST Use Cases Codeunit GST Tax Type Data - Method GetConfig - NamedType {C0774889-632D-4799-AA04-DA25EB643832}Lbl + GST Use Cases Codeunit GST Tax Type Data - Method GetConfig - NamedType {C0774889-632D-4799-AA04-DA25EB643832}Lbl GST Use Cases Codeunit GST Tax Type Data - Method GetConfig - NamedType {E474605D-6956-438B-95F2-DA5BE6A6D741}Lbl GST Use Cases Codeunit GST Tax Type Data - Method GetConfig - NamedType {FA492219-9C2F-4986-B773-DAA35CA74796}Lbl GST Use Cases Codeunit GST Tax Type Data - Method GetConfig - NamedType {FFBBBCDE-50F5-4D02-8B40-DAD63ED1491E}Lbl @@ -11936,7 +11936,12 @@ Codeunit GST Tax Type Data - Method GetConfig - NamedType {4F992CE7-BB8C-4129-923A-F53A771DF231}Lbl - GST Use Cases Codeunit GST Tax Type Data - Method GetConfig - NamedType {FC1AEFDA-0537-4D94-A576-F542B6710B71}Lbl + + GST Use Cases + + + Codeunit GST Tax Type Data - Method GetConfig - NamedType {FC1AEFDA-0537-4D94-A576-F542B6710B71}Lbl + GST Use Cases Codeunit GST Tax Type Data - Method GetConfig - NamedType {9A744701-39FF-4CFF-AA72-F5856E82FBF4}Lbl GST Use Cases Codeunit GST Tax Type Data - Method GetConfig - NamedType {AA3E77B0-A08A-4756-90E5-F6561C7D4B9B}Lbl GST Use Cases Codeunit GST Tax Type Data - Method GetConfig - NamedType {36A5E0EC-E197-4102-8FF0-F6DC9B4A47C1}Lbl diff --git a/Apps/IN/INGST/app/app.json b/Apps/IN/INGST/app/app.json index 72269241b6..77da777392 100644 --- a/Apps/IN/INGST/app/app.json +++ b/Apps/IN/INGST/app/app.json @@ -2,7 +2,7 @@ "id": "db643212-b7fb-4dd4-b5a8-cb44ac714461", "name": "India GST", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Contains features for deducting Goods and Services Tax on purchase, transfer, and sales transactions.", "description": "The GST feature contains setups that are required for calculating Goods and Services Tax (GST). This lets you deduct GST on vendor and customer invoices through purchase orders, invoices, and journal vouchers, vendor and customer payments, and on service or stock transfers. It also allows adjustments, reconciliation, and settlement of GST amounts and deposit GST that has been deducted.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -19,26 +19,26 @@ "id": "d3c551dd-5903-4194-b153-04ced9d29a2c", "publisher": "Microsoft", "name": "India Tax Base", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "c1eafb3f-e397-468e-bdb4-ecc5c317ca00", "publisher": "Microsoft", "name": "Tax Engine", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "7106d701-c601-4a5f-97c2-b8b323ae2c18", "publisher": "Microsoft", "name": "QR Generator", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 18000, diff --git a/Apps/IN/INGST/test/GSTBase/app.json b/Apps/IN/INGST/test/GSTBase/app.json index 19618598ee..3158a822be 100644 --- a/Apps/IN/INGST/test/GSTBase/app.json +++ b/Apps/IN/INGST/test/GSTBase/app.json @@ -2,7 +2,7 @@ "id": "f47f7494-1162-493e-bec0-b921397e8bf8", "name": "GST Base Tests", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Contains GST Base Tests", "description": "Contains GST Base Tests", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -15,38 +15,38 @@ "id": "dd0be2ea-f733-4d65-bb34-a28f4624fb14", "publisher": "Microsoft", "name": "Library Assert", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "publisher": "Microsoft", "name": "Tests-TestLibraries", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "d3c551dd-5903-4194-b153-04ced9d29a2c", "publisher": "Microsoft", "name": "India Tax Base", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "c1eafb3f-e397-468e-bdb4-ecc5c317ca00", "publisher": "Microsoft", "name": "Tax Engine", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "db643212-b7fb-4dd4-b5a8-cb44ac714461", "publisher": "Microsoft", "name": "India GST", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 18076, diff --git a/Apps/IN/INGST/test/GSTBase/src/CalculateDepreciationTests.Codeunit.al b/Apps/IN/INGST/test/GSTBase/src/CalculateDepreciationTests.Codeunit.al index 1eb5f9de28..dbce5dae2d 100644 --- a/Apps/IN/INGST/test/GSTBase/src/CalculateDepreciationTests.Codeunit.al +++ b/Apps/IN/INGST/test/GSTBase/src/CalculateDepreciationTests.Codeunit.al @@ -168,10 +168,10 @@ codeunit 18460 "Calculate Depreciation Tests" local procedure GetDocumentNo(FAJournalBatch: Record "FA Journal Batch"): Code[20] var NoSeries: Record "No. Series"; - NoSeriesManagement: Codeunit NoSeriesManagement; + NoSeriesCodeunit: Codeunit "No. Series"; begin NoSeries.Get(FAJournalBatch."No. Series"); - exit(NoSeriesManagement.GetNextNo(FAJournalBatch."No. Series", WorkDate(), false)); + exit(NoSeriesCodeunit.PeekNextNo(FAJournalBatch."No. Series")); end; } \ No newline at end of file diff --git a/Apps/IN/INGST/test/GSTBase/src/GSTStockTransferTests.Codeunit.al b/Apps/IN/INGST/test/GSTBase/src/GSTStockTransferTests.Codeunit.al index b875e64990..c1e5666a9d 100644 --- a/Apps/IN/INGST/test/GSTBase/src/GSTStockTransferTests.Codeunit.al +++ b/Apps/IN/INGST/test/GSTBase/src/GSTStockTransferTests.Codeunit.al @@ -148,6 +148,103 @@ codeunit 18427 "GST Stock Transfer Tests" VerifyGSTEntries(PostedDocumentNo); end; + [Test] + [HandlerFunctions('TaxRatesPage')] + procedure PostFromTransferOrderwithInterStateStockTransferAndGenerateEInv() + var + FromLocation, ToLocation, InTransitLocation : Record Location; + TransferHeader: Record "Transfer Header"; + TransferLine: Record "Transfer Line"; + TransferShipHead: Record "Transfer Shipment Header"; + PostedTransShip: TestPage "Posted Transfer Shipment"; + GSTGroupType: Enum "GST Group Type"; + PostedDocumentNo: Code[20]; + begin + // [SCENARIO] [453739] Check if the system is able to Post with GST in case of Inter-State Stock Transfer Shipment and Receipt. + // [GIVEN] Created GST Setup ,Transfer Locations + CreateTransferLocations(FromLocation, ToLocation, InTransitLocation); + CreateGSTSetup(GSTGroupType::Goods, false, false); + + // [WHEN] Create and Post Interstate Transfer Order + PostedDocumentNo := CreateandPostTransferOrder( + TransferHeader, + TransferLine); + + // [THEN] Verify E-Invoice Generated + TransferShipHead.Get(PostedDocumentNo); + PostedTransShip.OpenEdit(); + PostedTransShip.GoToRecord(TransferShipHead); + PostedTransShip."Generate E-Invoice".Invoke(); + PostedTransShip.Close(); + Assert.IsTrue(true, 'E-Invoice generated'); + end; + + [Test] + [HandlerFunctions('TaxRatesPage')] + procedure PostFromTransferOrderwithInterStateStockTransferAndGenerateIRN() + var + FromLocation, ToLocation, InTransitLocation : Record Location; + TransferHeader: Record "Transfer Header"; + TransferLine: Record "Transfer Line"; + TransferShipHead: Record "Transfer Shipment Header"; + PostedTransShip: TestPage "Posted Transfer Shipment"; + GSTGroupType: Enum "GST Group Type"; + PostedDocumentNo: Code[20]; + begin + // [SCENARIO] [453739] Check if the system is able to Post with GST in case of Inter-State Stock Transfer Shipment and Receipt. + // [GIVEN] Created GST Setup ,Transfer Locations + CreateTransferLocations(FromLocation, ToLocation, InTransitLocation); + CreateGSTSetup(GSTGroupType::Goods, false, false); + + // [WHEN] Create and Post Interstate Transfer Order + PostedDocumentNo := CreateandPostTransferOrder( + TransferHeader, + TransferLine); + + // [THEN] Verify E-Invoice IRN Generated + TransferShipHead.Get(PostedDocumentNo); + PostedTransShip.OpenEdit(); + PostedTransShip.GoToRecord(TransferShipHead); + PostedTransShip."Generate IRN".Invoke(); + PostedTransShip.Close(); + Assert.IsTrue(true, 'IRN Generated'); + end; + + [Test] + [HandlerFunctions('TaxRatesPage')] + procedure PostFromTransferOrderwithInterStateStockTransferAndCheckGSTApplicable() + var + FromLocation, ToLocation, InTransitLocation : Record Location; + TransferHeader: Record "Transfer Header"; + TransferLine: Record "Transfer Line"; + TransferShipHead: Record "Transfer Shipment Header"; + EInvTransshptJsonMgmt: Codeunit EInvTransshptJsonManagement; + PostedTransShip: TestPage "Posted Transfer Shipment"; + GSTGroupType: Enum "GST Group Type"; + GSTApplicable: Boolean; + PostedDocumentNo: Code[20]; + begin + // [SCENARIO] [453739] Check if the system is able to Post with GST in case of Inter-State Stock Transfer Shipment and Receipt. + // [GIVEN] Created GST Setup ,Transfer Locations + CreateTransferLocations(FromLocation, ToLocation, InTransitLocation); + CreateGSTSetup(GSTGroupType::Goods, false, false); + + // [WHEN] Create and Post Interstate Transfer Order + PostedDocumentNo := CreateandPostTransferOrder( + TransferHeader, + TransferLine); + + // [THEN] Verified GST is applicable for E-Invoice + GSTApplicable := EInvTransshptJsonMgmt.IsGSTApplicable(PostedDocumentNo, Database::"Transfer Shipment Header"); + TransferShipHead.Get(PostedDocumentNo); + PostedTransShip.OpenEdit(); + PostedTransShip.GoToRecord(TransferShipHead); + PostedTransShip."Generate E-Invoice".Invoke(); + EInvTransshptJsonMgmt.IsGSTApplicable(PostedDocumentNo, Database::"Transfer Shipment Header"); + PostedTransShip.Close(); + Assert.IsTrue(GSTApplicable, 'GSTApplicable'); + end; + local procedure CreateItemWithInventory(): Code[20] var Item: Record Item; @@ -182,7 +279,7 @@ codeunit 18427 "GST Stock Transfer Tests" var ItemJournalLine: Record "Item Journal Line"; ReservationEntry: Record "Reservation Entry"; - NoSeriesManagement: Codeunit NoSeriesManagement; + NoSeries: Codeunit "No. Series"; InputCreditAvailment: Boolean; begin InputCreditAvailment := StorageBoolean.Get(AvailmentLbl); @@ -205,7 +302,7 @@ codeunit 18427 "GST Stock Transfer Tests" ItemJournalLine, Item."No.", (LibraryStorage.Get(FromLocationLbl)), '', LibraryRandom.RandInt(100)); - LotNo := NoSeriesManagement.GetNextNo(Item."Lot Nos.", WorkDate(), true); + LotNo := NoSeries.GetNextNo(Item."Lot Nos."); LibraryItemTracking.CreateItemJournalLineItemTracking(ReservationEntry, ItemJournalLine, '', LotNo, ItemJournalLine.Quantity); Codeunit.Run(Codeunit::"Item Jnl.-Post Batch", ItemJournalLine); end; diff --git a/Apps/IN/INGST/test/GSTPayments/app.json b/Apps/IN/INGST/test/GSTPayments/app.json index 821a63ce1b..267406fdbc 100644 --- a/Apps/IN/INGST/test/GSTPayments/app.json +++ b/Apps/IN/INGST/test/GSTPayments/app.json @@ -2,7 +2,7 @@ "id": "38375430-3874-4155-aa63-e064c0f5fde7", "name": "GST On Payments Tests", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Contains GST On Payments Automated Test", "description": "Contains GST On Payments Automated Tests", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -15,50 +15,50 @@ "id": "dd0be2ea-f733-4d65-bb34-a28f4624fb14", "publisher": "Microsoft", "name": "Library Assert", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "publisher": "Microsoft", "name": "Tests-TestLibraries", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "d3c551dd-5903-4194-b153-04ced9d29a2c", "publisher": "Microsoft", "name": "India Tax Base", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "db643212-b7fb-4dd4-b5a8-cb44ac714461", "publisher": "Microsoft", "name": "India GST", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "c1eafb3f-e397-468e-bdb4-ecc5c317ca00", "publisher": "Microsoft", "name": "Tax Engine", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "f47f7494-1162-493e-bec0-b921397e8bf8", "publisher": "Microsoft", "name": "GST Base Tests", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "20cc6140-cbda-4a21-b15d-8f6190fb5469", "publisher": "Microsoft", "name": "India Tax Base Tests", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 18271, diff --git a/Apps/IN/INGST/test/GSTPurchase/app.json b/Apps/IN/INGST/test/GSTPurchase/app.json index 5efc4f29b3..2fbf8dbdc4 100644 --- a/Apps/IN/INGST/test/GSTPurchase/app.json +++ b/Apps/IN/INGST/test/GSTPurchase/app.json @@ -2,7 +2,7 @@ "id": "d9cd402d-304d-4156-9255-74e51b04ec1c", "name": "GST Purchase Automation", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Contains GST On Purchase Automated Tests", "description": "Contains GST On Purchase Automated Tests", "features": [ @@ -18,44 +18,44 @@ "id": "d3c551dd-5903-4194-b153-04ced9d29a2c", "publisher": "Microsoft", "name": "India Tax Base", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "c1eafb3f-e397-468e-bdb4-ecc5c317ca00", "publisher": "Microsoft", "name": "Tax Engine", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "db643212-b7fb-4dd4-b5a8-cb44ac714461", "publisher": "Microsoft", "name": "India GST", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "dd0be2ea-f733-4d65-bb34-a28f4624fb14", "publisher": "Microsoft", "name": "Library Assert", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "publisher": "Microsoft", "name": "Tests-TestLibraries", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "f47f7494-1162-493e-bec0-b921397e8bf8", "publisher": "Microsoft", "name": "GST Base Tests", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "application": "24.0.0.0", - "platform": "24.0.0.0", + "application": "25.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 18125, diff --git a/Apps/IN/INGST/test/GSTPurchase/src/GSTPurchaseReg.Codeunit.al b/Apps/IN/INGST/test/GSTPurchase/src/GSTPurchaseReg.Codeunit.al index 9a9d438042..d2a683f580 100644 --- a/Apps/IN/INGST/test/GSTPurchase/src/GSTPurchaseReg.Codeunit.al +++ b/Apps/IN/INGST/test/GSTPurchase/src/GSTPurchaseReg.Codeunit.al @@ -2240,9 +2240,9 @@ codeunit 18139 "GST Purchase Reg" if Overseas then PurchaseHeader.Validate("POS Out Of India", true); if PurchaseInvoiceType in [PurchaseInvoiceType::"Debit Note", PurchaseInvoiceType::Supplementary] then - PurchaseHeader.validate("Vendor Invoice No.", LibraryUtility.GenerateRandomCode(PurchaseHeader.fieldno("Vendor Invoice No."), Database::"Purchase Header")) + PurchaseHeader.Validate("Vendor Invoice No.", LibraryUtility.GenerateRandomCode(PurchaseHeader.fieldno("Vendor Invoice No."), Database::"Purchase Header")) else - PurchaseHeader.validate("Vendor Cr. Memo No.", LibraryUtility.GenerateRandomCode(PurchaseHeader.fieldno("Vendor Cr. Memo No."), Database::"Purchase Header")); + PurchaseHeader.Validate("Vendor Cr. Memo No.", LibraryUtility.GenerateRandomCode(PurchaseHeader.fieldno("Vendor Cr. Memo No."), Database::"Purchase Header")); if PurchaseHeader."GST Vendor Type" = PurchaseHeader."GST Vendor Type"::SEZ then begin PurchaseHeader."Bill of Entry No." := LibraryUtility.GenerateRandomCode(PurchaseHeader.fieldno("Bill of Entry No."), Database::"Purchase Header"); PurchaseHeader."Bill of Entry Date" := WorkDate(); diff --git a/Apps/IN/INGST/test/GSTReturnSettlement/GSTAdjustmentJournalTests.Codeunit.al b/Apps/IN/INGST/test/GSTReturnSettlement/GSTAdjustmentJournalTests.Codeunit.al index eb9fcdfd04..a0b9d068b2 100644 --- a/Apps/IN/INGST/test/GSTReturnSettlement/GSTAdjustmentJournalTests.Codeunit.al +++ b/Apps/IN/INGST/test/GSTReturnSettlement/GSTAdjustmentJournalTests.Codeunit.al @@ -223,9 +223,9 @@ codeunit 18346 "GST Adjustment Journal Tests" if Overseas then PurchaseHeader.Validate("POS Out Of India", true); if PurchaseInvoiceType in [PurchaseInvoiceType::"Debit Note", PurchaseInvoiceType::Supplementary] then - PurchaseHeader.validate("Vendor Invoice No.", LibraryUtility.GenerateRandomCode(PurchaseHeader.fieldno("Vendor Invoice No."), Database::"Purchase Header")) + PurchaseHeader.Validate("Vendor Invoice No.", LibraryUtility.GenerateRandomCode(PurchaseHeader.fieldno("Vendor Invoice No."), Database::"Purchase Header")) else - PurchaseHeader.validate("Vendor Cr. Memo No.", LibraryUtility.GenerateRandomCode(PurchaseHeader.fieldno("Vendor Cr. Memo No."), Database::"Purchase Header")); + PurchaseHeader.Validate("Vendor Cr. Memo No.", LibraryUtility.GenerateRandomCode(PurchaseHeader.fieldno("Vendor Cr. Memo No."), Database::"Purchase Header")); if PurchaseHeader."GST Vendor Type" = PurchaseHeader."GST Vendor Type"::SEZ then begin PurchaseHeader."Bill of Entry No." := LibraryUtility.GenerateRandomCode(PurchaseHeader.fieldno("Bill of Entry No."), Database::"Purchase Header"); PurchaseHeader."Bill of Entry Date" := WorkDate(); diff --git a/Apps/IN/INGST/test/GSTSales/app.json b/Apps/IN/INGST/test/GSTSales/app.json index 5056b289ea..26dd64cd69 100644 --- a/Apps/IN/INGST/test/GSTSales/app.json +++ b/Apps/IN/INGST/test/GSTSales/app.json @@ -2,7 +2,7 @@ "id": "30a32aee-b95e-45ac-b304-2d2faca43620", "name": "GST Sales Automation", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Contains GST Sales Automated Tests", "description": "Contains GST Sales Automated Tests", "features": [ @@ -18,53 +18,53 @@ "id": "d3c551dd-5903-4194-b153-04ced9d29a2c", "publisher": "Microsoft", "name": "India Tax Base", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "c1eafb3f-e397-468e-bdb4-ecc5c317ca00", "publisher": "Microsoft", "name": "Tax Engine", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "dd0be2ea-f733-4d65-bb34-a28f4624fb14", "publisher": "Microsoft", "name": "Library Assert", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "publisher": "Microsoft", "name": "Tests-TestLibraries", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "eddcf82e-482c-49d1-836b-ad0284f2c5b0", "publisher": "Microsoft", "name": "India TCS", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "f47f7494-1162-493e-bec0-b921397e8bf8", "publisher": "Microsoft", "name": "GST Base Tests", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "db643212-b7fb-4dd4-b5a8-cb44ac714461", "publisher": "Microsoft", "name": "India GST", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "20cc6140-cbda-4a21-b15d-8f6190fb5469", "publisher": "Microsoft", "name": "India Tax Base Tests", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], - "application": "24.0.0.0", - "platform": "24.0.0.0", + "application": "25.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 18191, diff --git a/Apps/IN/INGST/test/GSTService/GSTServiceShipToAddrTests.Codeunit.al b/Apps/IN/INGST/test/GSTService/GSTServiceShipToAddrTests.Codeunit.al index efd5560039..9b059a01dd 100644 --- a/Apps/IN/INGST/test/GSTService/GSTServiceShipToAddrTests.Codeunit.al +++ b/Apps/IN/INGST/test/GSTService/GSTServiceShipToAddrTests.Codeunit.al @@ -26,6 +26,7 @@ codeunit 18480 "GST Service Ship To Addr Tests" CustomerNoLbl: Label 'CustomerNo'; ToStateCodeLbl: Label 'ToStateCode'; PostedDocumentNoLbl: Label 'PostedDocumentNo'; + ReverseDocumentNoLbl: Label 'ReverseDocumentNo'; [Test] [HandlerFunctions('TaxRatePageHandler')] @@ -219,6 +220,37 @@ codeunit 18480 "GST Service Ship To Addr Tests" LibraryGST.VerifyGLEntries(ServiceHeader."Document Type"::Invoice, PostedDocumentNo, 5); end; + [Test] + [HandlerFunctions('TaxRatePageHandler,ReferencePageHandler,CustomerLedgerEntries')] + procedure PostFromRegCustServiceCrMemoInterstateWithShipToAddrItem() + var + ServiceHeader: Record "Service Header"; + ServiceLine: Record "Service Line"; + PostedDocumentNo: Code[20]; + ReverseDocumentNo: Code[20]; + begin + // [SCENARIO] Check if the system is calculating Inter State Service of Goods from Registered Customer through Service Credit Memo. + + // [GIVEN] Create GST Setup and tax rates for Registered Customer where GST Group Type is Goods for InterState Transactions + CreateGSTSetup(Enum::"GST Customer Type"::Registered, Enum::"GST Group Type"::Goods, true, true); + InitializeShareStep(false, false); + + // [GIVEN] Create and Post Service Invoice with GST and Line Type as Item for Interstate Transaction With Ship To Address + PostedDocumentNo := CreateAndPostServiceDocument( + ServiceHeader, + ServiceLine, Enum::"Service Line Type"::Item, + Enum::"Service Document Type"::Invoice); + + // [WHEN] Create and Post Service Cr. Memo with GST and Line Type as Item for Interstate Transaction With Ship To Address + ReverseDocumentNo := CreateAndPostServiceCreditMemo( + ServiceHeader, + ServiceLine, Enum::"Service Line Type"::Item, + Enum::"Service Document Type"::"Credit Memo"); + + // [THEN] Verify G/L Entry + LibraryGST.VerifyGLEntries(ServiceHeader."Document Type"::"Credit Memo", ReverseDocumentNo, 3); + end; + local procedure CreateServiceHeaderWithGST( var ServiceHeader: Record "Service Header"; CustomerNo: Code[20]; @@ -259,7 +291,8 @@ codeunit 18480 "GST Service Ship To Addr Tests" LibraryService.CreateServiceLine(ServiceLine, ServiceHeader, LineType, LineTypeno); LibraryService.CreateServiceLineWithQuantity(ServiceLine, ServiceHeader, LineType, LineTypeno, Quantity); - LibraryERM.CreateGeneralPostingSetup(GenPostingSetup, ServiceLine."Gen. Bus. Posting Group", GenProductPostSetupLbl); + if ServiceLine."Document Type" <> ServiceLine."Document Type"::"Credit Memo" then + LibraryERM.CreateGeneralPostingSetup(GenPostingSetup, ServiceLine."Gen. Bus. Posting Group", GenProductPostSetupLbl); if LineDiscount then begin ServiceLine.Validate("Line Discount %", LibraryRandom.RandDecInRange(10, 20, 2)); @@ -528,7 +561,7 @@ codeunit 18480 "GST Service Ship To Addr Tests" ServicePost: Codeunit "Service-Post"; Assert: Codeunit Assert; LibraryService: Codeunit "Library - Service"; - NoSeriesManagement: Codeunit NoSeriesManagement; + NoSeries: Codeunit "No. Series"; NoSeriesCode: Code[20]; WrongDocumentTypeErr: Label 'Document type not supported: %1'; begin @@ -537,12 +570,14 @@ codeunit 18480 "GST Service Ship To Addr Tests" case "Document Type" of "Document Type"::Invoice: NoSeriesCode := "Posting No. Series"; // posted service invoice. + "Document Type"::"Credit Memo": + NoSeriesCode := "Posting No. Series"; else Assert.Fail(StrSubstNo(WrongDocumentTypeErr, "Document Type")); end; if ServiceHeader."Posting No." = '' then - DocumentNo := NoSeriesManagement.GetNextNo(NoSeriesCode, GetNextNoSeriesServiceDate(NoSeriesCode), false) + DocumentNo := NoSeries.PeekNextNo(NoSeriesCode, GetNextNoSeriesServiceDate(NoSeriesCode)) else DocumentNo := ServiceHeader."Posting No."; Clear(ServicePost); @@ -557,4 +592,49 @@ codeunit 18480 "GST Service Ship To Addr Tests" NoSeries.TestField("Date Order", false); // Use of Date Order is only tested on IT exit(WorkDate()); end; + + local procedure CreateAndPostServiceCreditMemo( + var ServiceHeader: Record "Service Header"; + var ServiceLine: Record "Service Line"; + LineType: Enum "Service Line Type"; + DocumentType: Enum "Service Document Type"): Code[20]; + var + CustomerNo: Code[20]; + LocationCode: Code[10]; + ReverseDocumentNo: Code[20]; + begin + CustomerNo := Storage.Get(CustomerNoLbl); + Evaluate(LocationCode, CopyStr(Storage.Get(LocationCodeLbl), 1, 10)); + CreateServiceHeaderWithGST(ServiceHeader, CustomerNo, DocumentType, LocationCode); + CreateServiceLineWithGST(ServiceHeader, ServiceLine, LineType, LibraryRandom.RandDecInRange(2, 10, 0), StorageBoolean.Get(ExemptedLbl), StorageBoolean.Get(LineDiscountLbl)); + UpdateReferenceInvoiceNoAndVerify(ServiceHeader); + ReverseDocumentNo := PostServiceOrder(ServiceHeader, ServiceLine); + Storage.Set(ReverseDocumentNoLbl, ReverseDocumentNo); + exit(ReverseDocumentNo); + end; + + local procedure UpdateReferenceInvoiceNoAndVerify(ServiceHeader: Record "Service Header") + var + ServiceCreditMemo: TestPage "Service Credit Memo"; + begin + ServiceCreditMemo.OpenEdit(); + ServiceCreditMemo.Filter.SetFilter("No.", ServiceHeader."No."); + ServiceCreditMemo."Update Reference Invoice No.".Invoke(); + end; + + [PageHandler] + procedure ReferencePageHandler(var UpdateReferenceInvoiceNo: TestPage "Update Reference Invoice No") + begin + UpdateReferenceInvoiceNo."Reference Invoice Nos.".Lookup(); + UpdateReferenceInvoiceNo."Reference Invoice Nos.".SetValue(Storage.Get(PostedDocumentNoLbl)); + UpdateReferenceInvoiceNo.Verify.Invoke(); + end; + + [ModalPageHandler] + procedure CustomerLedgerEntries(var CustomerLedgerEntries: TestPage "Customer Ledger Entries") + begin + CustomerLedgerEntries.Filter.SetFilter("Document No.", Storage.Get(PostedDocumentNoLbl)); + CustomerLedgerEntries.OK().Invoke(); + end; + } \ No newline at end of file diff --git a/Apps/IN/INGST/test/GSTSubcontracting/app.json b/Apps/IN/INGST/test/GSTSubcontracting/app.json index 267847b4b4..9d0ec4c674 100644 --- a/Apps/IN/INGST/test/GSTSubcontracting/app.json +++ b/Apps/IN/INGST/test/GSTSubcontracting/app.json @@ -1,8 +1,8 @@ { "id": "8ee00d9c-fb86-42d7-88c9-5333489d999b", "name": "GST Subcontracting Automation", - "publisher": "Default publisher", - "version": "24.0.0.0", + "publisher": "Microsoft", + "version": "25.0.0.0", "brief": "Contains GST On Subcontracting Automated Tests", "description": "Contains GST On Subcontracting Automated Tests", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -15,44 +15,44 @@ "id": "d3c551dd-5903-4194-b153-04ced9d29a2c", "publisher": "Microsoft", "name": "India Tax Base", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "c1eafb3f-e397-468e-bdb4-ecc5c317ca00", "publisher": "Microsoft", "name": "Tax Engine", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "db643212-b7fb-4dd4-b5a8-cb44ac714461", "publisher": "Microsoft", "name": "India GST", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "dd0be2ea-f733-4d65-bb34-a28f4624fb14", "publisher": "Microsoft", "name": "Library Assert", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "publisher": "Microsoft", "name": "Tests-TestLibraries", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "f47f7494-1162-493e-bec0-b921397e8bf8", "publisher": "Microsoft", "name": "GST Base Tests", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 18478, diff --git a/Apps/IN/INGST/test/GSTSubcontracting/src/GSTSubcontracting.Codeunit.al b/Apps/IN/INGST/test/GSTSubcontracting/src/GSTSubcontracting.Codeunit.al index 284670af80..bd05253ca1 100644 --- a/Apps/IN/INGST/test/GSTSubcontracting/src/GSTSubcontracting.Codeunit.al +++ b/Apps/IN/INGST/test/GSTSubcontracting/src/GSTSubcontracting.Codeunit.al @@ -1477,7 +1477,7 @@ codeunit 18479 "GST Subcontracting" ProdOrderLine: Record "Prod. Order Line"; ReservationEntry: Record "Reservation Entry"; MainItem: Record Item; - NoSeriesMgt: Codeunit NoSeriesManagement; + NoSeries: Codeunit "No. Series"; SlNo: Code[20]; i: Integer; begin @@ -1487,7 +1487,7 @@ codeunit 18479 "GST Subcontracting" ProdOrderLine.SetRange(ProdOrderLine."Line No.", PurchaseLine."Prod. Order Line No."); ProdOrderLine.FindFirst(); for i := 1 to ProdOrderLine.Quantity do begin - SlNo := NoSeriesMgt.GetNextNo(MainItem."Serial Nos.", 0D, true); + SlNo := NoSeries.GetNextNo(MainItem."Serial Nos."); LibraryItemTracking.CreateProdOrderItemTracking(ReservationEntry, ProdOrderLine, SlNo, '', 1); end; end; diff --git a/Apps/IN/INGST/test/app.json b/Apps/IN/INGST/test/app.json index d2ef456bd7..6d861b82f2 100644 --- a/Apps/IN/INGST/test/app.json +++ b/Apps/IN/INGST/test/app.json @@ -2,7 +2,7 @@ "id": "66eea9f9-cc7d-4274-8dbc-084182071a5f", "name": "India GST Tests", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Tests for India GST.", "description": "Tests for India GST.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -15,44 +15,44 @@ "id": "dd0be2ea-f733-4d65-bb34-a28f4624fb14", "publisher": "Microsoft", "name": "Library Assert", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "publisher": "Microsoft", "name": "Tests-TestLibraries", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "d3c551dd-5903-4194-b153-04ced9d29a2c", "publisher": "Microsoft", "name": "India Tax Base", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "c1eafb3f-e397-468e-bdb4-ecc5c317ca00", "publisher": "Microsoft", "name": "Tax Engine", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "db643212-b7fb-4dd4-b5a8-cb44ac714461", "publisher": "Microsoft", "name": "India GST", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "20cc6140-cbda-4a21-b15d-8f6190fb5469", "publisher": "Microsoft", "name": "India Tax Base Tests", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 18000, diff --git a/Apps/IN/INGateEntry/app/app.json b/Apps/IN/INGateEntry/app/app.json index 4993093e1b..e2eb10193b 100644 --- a/Apps/IN/INGateEntry/app/app.json +++ b/Apps/IN/INGateEntry/app/app.json @@ -2,7 +2,7 @@ "id": "2dc39818-e0f0-42b6-99eb-ba29dc5f4102", "name": "India Gate Entry", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Contains Gate Entry Functionality", "description": "This feature contains Gate Entry Functionality", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -15,20 +15,20 @@ "id": "d3c551dd-5903-4194-b153-04ced9d29a2c", "publisher": "Microsoft", "name": "India Tax Base", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "db643212-b7fb-4dd4-b5a8-cb44ac714461", "publisher": "Microsoft", "name": "India GST", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 18601, diff --git a/Apps/IN/INGateEntry/app/src/codeunit/GateEntryPost.Codeunit.al b/Apps/IN/INGateEntry/app/src/codeunit/GateEntryPost.Codeunit.al index d9c0a342c4..450d5649d6 100644 --- a/Apps/IN/INGateEntry/app/src/codeunit/GateEntryPost.Codeunit.al +++ b/Apps/IN/INGateEntry/app/src/codeunit/GateEntryPost.Codeunit.al @@ -12,6 +12,8 @@ codeunit 18602 "Gate Entry Post" TableNo = "Gate Entry Header"; trigger OnRun() + var + NoSeries: Codeunit "No. Series"; begin GateEntryHeader := Rec; Rec.TestField("Posting Date"); @@ -44,7 +46,7 @@ codeunit 18602 "Gate Entry Post" Rec.Modify(); end; if Rec."Posting No." = '' then begin - Rec."Posting No." := NoSeriesMgt.GetNextNo(Rec."Posting No. Series", Rec."Posting Date", true); + Rec."Posting No." := NoSeries.GetNextNo(Rec."Posting No. Series", Rec."Posting Date"); ModifyHeader := true; end; if ModifyHeader then @@ -90,7 +92,6 @@ codeunit 18602 "Gate Entry Post" PostedGateEntryHeader: Record "Posted Gate Entry Header"; PostedGateEntryLine: Record "Posted Gate Entry Line"; PostingNoSeries: Record "Posting No. Series"; - NoSeriesMgt: Codeunit NoSeriesManagement; GateEntryHandler: Codeunit "Gate Entry Handler"; Record: Variant; Window: Dialog; diff --git a/Apps/IN/INGateEntry/app/src/table/GateEntryHeader.Table.al b/Apps/IN/INGateEntry/app/src/table/GateEntryHeader.Table.al index be2c28564a..35a10d58a2 100644 --- a/Apps/IN/INGateEntry/app/src/table/GateEntryHeader.Table.al +++ b/Apps/IN/INGateEntry/app/src/table/GateEntryHeader.Table.al @@ -153,8 +153,9 @@ table 18603 "Gate Entry Header" } trigger OnInsert() -#if not CLEAN24 var + NoSeries: Codeunit "No. Series"; +#if not CLEAN24 IsHandled: Boolean; #endif begin @@ -180,7 +181,7 @@ table 18603 "Gate Entry Header" "No. Series" := xRec."No. Series"; "No." := NoSeries.GetNextNo("No. Series", "Posting Date"); #if not CLEAN24 - NoSeriesManagement.RaiseObsoleteOnAfterInitSeries("No. Series", InventorySetup."Inward Gate Entry Nos.", "Posting Date", "No."); + NoSeriesManagement.RaiseObsoleteOnAfterInitSeries("No. Series", InventorySetup."Inward Gate Entry Nos.", "Posting Date", "No."); end; #endif end; @@ -197,7 +198,7 @@ table 18603 "Gate Entry Header" "No. Series" := xRec."No. Series"; "No." := NoSeries.GetNextNo("No. Series", "Posting Date"); #if not CLEAN24 - NoSeriesManagement.RaiseObsoleteOnAfterInitSeries("No. Series", InventorySetup."Outward Gate Entry Nos.", "Posting Date", "No."); + NoSeriesManagement.RaiseObsoleteOnAfterInitSeries("No. Series", InventorySetup."Outward Gate Entry Nos.", "Posting Date", "No."); end; #endif end; @@ -220,30 +221,29 @@ table 18603 "Gate Entry Header" var InventorySetup: Record "Inventory Setup"; +#if not CLEAN24 NoSeriesManagement: Codeunit NoSeriesManagement; - NoSeries: Codeunit "No. Series"; +#endif procedure AssistEdit(OldGateEntryHeader: Record "Gate Entry Header"): Boolean + var + NoSeries: Codeunit "No. Series"; begin InventorySetup.Get(); case "Entry Type" of "Entry Type"::Inward: begin InventorySetup.TestField("Inward Gate Entry Nos."); - if NoSeriesManagement.SelectSeries(InventorySetup."Inward Gate Entry Nos.", OldGateEntryHeader."No. Series", "No. Series") then begin - InventorySetup.Get(); - InventorySetup.TestField("Inward Gate Entry Nos."); - NoSeriesManagement.SetSeries("No."); + if NoSeries.LookupRelatedNoSeries(InventorySetup."Inward Gate Entry Nos.", OldGateEntryHeader."No. Series", "No. Series") then begin + "No." := NoSeries.GetNextNo("No. Series"); exit(true); end; end; "Entry Type"::Outward: begin InventorySetup.TestField("Outward Gate Entry Nos."); - if NoSeriesManagement.SelectSeries(InventorySetup."Outward Gate Entry Nos.", OldGateEntryHeader."No. Series", "No. Series") then begin - InventorySetup.Get(); - InventorySetup.TestField("Outward Gate Entry Nos."); - NoSeriesManagement.SetSeries("No."); + if NoSeries.LookupRelatedNoSeries(InventorySetup."Outward Gate Entry Nos.", OldGateEntryHeader."No. Series", "No. Series") then begin + "No." := NoSeries.GetNextNo("No. Series"); exit(true); end; end; diff --git a/Apps/IN/INGateEntry/test/app.json b/Apps/IN/INGateEntry/test/app.json index c1d52d2ff5..8a6251ecfc 100644 --- a/Apps/IN/INGateEntry/test/app.json +++ b/Apps/IN/INGateEntry/test/app.json @@ -2,7 +2,7 @@ "id": "abd8192b-f032-4490-a5fb-b86b879ade50", "name": "India Gate Entry Tests", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Contains India Gate Entry Tests", "description": "Contains Tests of Gate Entry Functionality", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -15,32 +15,32 @@ "id": "dd0be2ea-f733-4d65-bb34-a28f4624fb14", "publisher": "Microsoft", "name": "Library Assert", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "publisher": "Microsoft", "name": "Tests-TestLibraries", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "d3c551dd-5903-4194-b153-04ced9d29a2c", "publisher": "Microsoft", "name": "India Tax Base", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "2dc39818-e0f0-42b6-99eb-ba29dc5f4102", "publisher": "Microsoft", "name": "India Gate Entry", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 18627, diff --git a/Apps/IN/INGateEntry/test/src/GateEntryLibrary.Codeunit.al b/Apps/IN/INGateEntry/test/src/GateEntryLibrary.Codeunit.al index f8efdc1163..7b3de29c8e 100644 --- a/Apps/IN/INGateEntry/test/src/GateEntryLibrary.Codeunit.al +++ b/Apps/IN/INGateEntry/test/src/GateEntryLibrary.Codeunit.al @@ -378,19 +378,19 @@ codeunit 18627 "Gate Entry Library" local procedure CreateGateEntrySeries(GateEntryHeader: Record "Gate Entry Header"): Code[20] var InventorySetup: Record "Inventory Setup"; - NoSeriesManagement: Codeunit NoSeriesManagement; + NoSeries: Codeunit "No. Series"; begin if GateEntryHeader."No." = '' then begin InventorySetup.Get(); case GateEntryHeader."Entry Type" of GateEntryHeader."Entry Type"::Inward: if InventorySetup."Inward Gate Entry Nos." <> '' then - exit(NoSeriesManagement.GetNextNo(InventorySetup."Inward Gate Entry Nos.", WorkDate(), true)) + exit(NoSeries.GetNextNo(InventorySetup."Inward Gate Entry Nos.")) else exit(CreateNoSeries()); GateEntryHeader."Entry Type"::Outward: if InventorySetup."Outward Gate Entry Nos." <> '' then - exit(NoSeriesManagement.GetNextNo(InventorySetup."Outward Gate Entry Nos.", WorkDate(), true)) + exit(NoSeries.GetNextNo(InventorySetup."Outward Gate Entry Nos.")) else exit(CreateNoSeries()); end; diff --git a/Apps/IN/INReports/app/app.json b/Apps/IN/INReports/app/app.json index 42efb95ad1..1198fc52df 100644 --- a/Apps/IN/INReports/app/app.json +++ b/Apps/IN/INReports/app/app.json @@ -2,7 +2,7 @@ "id": "050f6146-bffd-40de-942c-d0dd510ec20f", "name": "India Reports", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Contains reports for taxation in India.", "description": "This feature provides reports for taxation in India, such as Goods and Services Tax (GST), Tax Deducted at Source (TDS), and Tax Collected at Source (TCS), on transactions such as purchases, sales, returns, transfers, and so on. It also provides reports that generate data for tax returns.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -18,44 +18,44 @@ "id": "c1eafb3f-e397-468e-bdb4-ecc5c317ca00", "publisher": "Microsoft", "name": "Tax Engine", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "d3c551dd-5903-4194-b153-04ced9d29a2c", "publisher": "Microsoft", "name": "India Tax Base", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "eae5779e-7797-4c4c-977e-7516652b7a65", "publisher": "Microsoft", "name": "India TDS", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "db643212-b7fb-4dd4-b5a8-cb44ac714461", "publisher": "Microsoft", "name": "India GST", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "eddcf82e-482c-49d1-836b-ad0284f2c5b0", "publisher": "Microsoft", "name": "India TCS", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "f1d9b696-156b-4251-b542-34e549fa80e9", "publisher": "Microsoft", "name": "India Voucher Interface", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 18000, diff --git a/Apps/IN/INReports/test/app.json b/Apps/IN/INReports/test/app.json index 1c112c9752..17135535b9 100644 --- a/Apps/IN/INReports/test/app.json +++ b/Apps/IN/INReports/test/app.json @@ -2,7 +2,7 @@ "id": "bfc37792-ad95-4600-a621-5bb1a2518f71", "name": "India Reports Tests", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Contains Tests for India Reports", "description": "Contains Automated Tests for India Reports", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -18,62 +18,62 @@ "id": "dd0be2ea-f733-4d65-bb34-a28f4624fb14", "publisher": "Microsoft", "name": "Library Assert", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "publisher": "Microsoft", "name": "Tests-TestLibraries", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "c1eafb3f-e397-468e-bdb4-ecc5c317ca00", "publisher": "Microsoft", "name": "Tax Engine", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "d3c551dd-5903-4194-b153-04ced9d29a2c", "publisher": "Microsoft", "name": "India Tax Base", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "eae5779e-7797-4c4c-977e-7516652b7a65", "publisher": "Microsoft", "name": "India TDS", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "db643212-b7fb-4dd4-b5a8-cb44ac714461", "publisher": "Microsoft", "name": "India GST", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "eddcf82e-482c-49d1-836b-ad0284f2c5b0", "publisher": "Microsoft", "name": "India TCS", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "f1d9b696-156b-4251-b542-34e549fa80e9", "publisher": "Microsoft", "name": "India Voucher Interface", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "050f6146-bffd-40de-942c-d0dd510ec20f", "publisher": "Microsoft", "name": "India Reports", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 18043, diff --git a/Apps/IN/INTCS/app/TCSBase/app.json b/Apps/IN/INTCS/app/TCSBase/app.json index fc0dd2767f..c289a99b29 100644 --- a/Apps/IN/INTCS/app/TCSBase/app.json +++ b/Apps/IN/INTCS/app/TCSBase/app.json @@ -2,7 +2,7 @@ "id": "a34a9295-94ef-4c4c-b175-367e76e5dd99", "name": "TCS Base", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Contains setups for Tax Collected at Source (TCS).", "description": "TCS Base contains setups that are required for calculating Tax Collected at Source.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -19,20 +19,20 @@ "id": "d3c551dd-5903-4194-b153-04ced9d29a2c", "publisher": "Microsoft", "name": "India Tax Base", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "c1eafb3f-e397-468e-bdb4-ecc5c317ca00", "publisher": "Microsoft", "name": "Tax Engine", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "application": "24.0.0.0", - "platform": "24.0.0.0", + "application": "25.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 18807, diff --git a/Apps/IN/INTCS/app/TCSOnReceipt/app.json b/Apps/IN/INTCS/app/TCSOnReceipt/app.json index 130bcce287..ad2edf0fe6 100644 --- a/Apps/IN/INTCS/app/TCSOnReceipt/app.json +++ b/Apps/IN/INTCS/app/TCSOnReceipt/app.json @@ -2,7 +2,7 @@ "id": "ff4b7fb3-c9f2-4e84-8611-a0e248f6dd6a", "name": "TCS on Receipt", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Contains features for TCS on Receipt.", "description": "TCS on Receipt lets you calculate TCS on customer advance payments through journal vouchers.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -19,26 +19,26 @@ "id": "c1eafb3f-e397-468e-bdb4-ecc5c317ca00", "publisher": "Microsoft", "name": "Tax Engine", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "d3c551dd-5903-4194-b153-04ced9d29a2c", "publisher": "Microsoft", "name": "India Tax Base", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "a34a9295-94ef-4c4c-b175-367e76e5dd99", "publisher": "Microsoft", "name": "TCS Base", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "application": "24.0.0.0", - "platform": "24.0.0.0", + "application": "25.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 18900, diff --git a/Apps/IN/INTCS/app/TCSOnReceipt/src/Codeunit/TCSOnReceiptOfPmtHandler.Codeunit.al b/Apps/IN/INTCS/app/TCSOnReceipt/src/Codeunit/TCSOnReceiptOfPmtHandler.Codeunit.al index da7ab48b40..5d8c5a344d 100644 --- a/Apps/IN/INTCS/app/TCSOnReceipt/src/Codeunit/TCSOnReceiptOfPmtHandler.Codeunit.al +++ b/Apps/IN/INTCS/app/TCSOnReceipt/src/Codeunit/TCSOnReceiptOfPmtHandler.Codeunit.al @@ -68,7 +68,7 @@ codeunit 18903 "TCS On Receipt Of Pmt. Handler" TaxTransactionValue: Record "Tax Transaction Value"; TCSPostingSetup: Record "TCS Posting Setup"; Customer: Record Customer; - NoSeriesMgt: Codeunit NoSeriesManagement; + NoSeries: Codeunit "No. Series"; TCSManagement: Codeunit "TCS Management"; TCSAmount, TCSAmountLCY : Decimal; TCSAccount: Code[20]; @@ -83,7 +83,7 @@ codeunit 18903 "TCS On Receipt Of Pmt. Handler" GLSetup.Get(); GLSetup.TestField("TCS Debit Note No."); - TCSDebitNoteNo := NoSeriesMgt.GetNextNo(GLSetup."TCS Debit Note No.", GenJnlLine."Posting Date", true); + TCSDebitNoteNo := NoSeries.GetNextNo(GLSetup."TCS Debit Note No.", GenJnlLine."Posting Date"); TCSPostingSetup.SetRange("TCS Nature of Collection", GenJnlLine."TCS Nature of Collection"); TCSPostingSetup.SetFilter("Effective Date", '<=%1', GenJnlLine."Posting Date"); diff --git a/Apps/IN/INTCS/app/TCSOnSales/app.json b/Apps/IN/INTCS/app/TCSOnSales/app.json index 72281a6a46..fae181b2d4 100644 --- a/Apps/IN/INTCS/app/TCSOnSales/app.json +++ b/Apps/IN/INTCS/app/TCSOnSales/app.json @@ -2,7 +2,7 @@ "id": "a20e1072-e9ce-427d-bf29-3483311f69bf", "name": "TCS on Sales", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Contains features for TCS on Sales.", "description": "TCS on Sales lets you calculate TCS on sales transactions through sales invoices, sales orders, and journal vouchers.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -19,26 +19,26 @@ "id": "c1eafb3f-e397-468e-bdb4-ecc5c317ca00", "publisher": "Microsoft", "name": "Tax Engine", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "d3c551dd-5903-4194-b153-04ced9d29a2c", "publisher": "Microsoft", "name": "India Tax Base", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "a34a9295-94ef-4c4c-b175-367e76e5dd99", "publisher": "Microsoft", "name": "TCS Base", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "application": "24.0.0.0", - "platform": "24.0.0.0", + "application": "25.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 18838, diff --git a/Apps/IN/INTCS/app/TCSOnSales/src/codeunit/TCSSalesManagement.Codeunit.al b/Apps/IN/INTCS/app/TCSOnSales/src/codeunit/TCSSalesManagement.Codeunit.al index 60371f8199..ee8f174c51 100644 --- a/Apps/IN/INTCS/app/TCSOnSales/src/codeunit/TCSSalesManagement.Codeunit.al +++ b/Apps/IN/INTCS/app/TCSOnSales/src/codeunit/TCSSalesManagement.Codeunit.al @@ -60,6 +60,64 @@ codeunit 18841 "TCS Sales Management" TCSAmount := TCSManagement.RoundTCSAmount(TCSAmount); end; + [EventSubscriber(ObjectType::Codeunit, Codeunit::"Calculate Statistics", 'OnGetPartialSalesHeaderTCSAmount', '', false, false)] + local procedure OnGetPartialSalesHeaderTCSAmount(SalesHeader: Record "Sales Header"; var PartialTCSAmount: Decimal) + begin + GetPartialSalesStatisticsAmount(SalesHeader, PartialTCSAmount); + end; + + [EventSubscriber(ObjectType::Codeunit, Codeunit::"Calculate Statistics", 'OnGetPartialSalesShptTCSAmount', '', false, false)] + local procedure OnGetPartialSalesShptTCSAmount(SalesHeader: Record "Sales Header"; var PartialTCSAmount: Decimal) + begin + GetPartialSalesShptStatisticsAmount(SalesHeader, PartialTCSAmount); + end; + + procedure GetPartialSalesStatisticsAmount( + SalesHeader: Record "Sales Header"; + var PartialTCSAmount: Decimal) + var + SalesLine: Record "Sales Line"; + TCSManagement: Codeunit "TCS Management"; + begin + Clear(PartialTCSAmount); + + SalesLine.SetLoadFields("Document Type", "Document No.", Quantity, "Qty. to Invoice"); + SalesLine.SetRange("Document Type", SalesHeader."Document Type"); + SalesLine.SetRange("Document no.", SalesHeader."No."); + if SalesLine.FindSet() then + repeat + if SalesLine.Quantity <> 0 then + PartialTCSAmount += (GetTCSAmount(SalesLine.RecordId()) * SalesLine."Qty. to Invoice" / SalesLine.Quantity); + until SalesLine.Next() = 0; + + PartialTCSAmount := TCSManagement.RoundTCSAmount(PartialTCSAmount); + end; + + procedure GetPartialSalesShptStatisticsAmount( + SalesHeader: Record "Sales Header"; + var PartialTCSAmount: Decimal) + var + SalesLine: Record "Sales Line"; + TCSManagement: Codeunit "TCS Management"; + begin + Clear(PartialTCSAmount); + + SalesLine.SetLoadFields("Document Type", "Document No.", Quantity, "Qty. to Ship", "Return Qty. to Receive"); + SalesLine.SetRange("Document Type", SalesHeader."Document Type"); + SalesLine.SetRange("Document no.", SalesHeader."No."); + if SalesLine.FindSet() then + repeat + if SalesLine.Quantity <> 0 then + if SalesLine."Document Type" = SalesLine."Document Type"::Order then + PartialTCSAmount += (GetTCSAmount(SalesLine.RecordId()) * SalesLine."Qty. to Ship" / SalesLine.Quantity) + else + if SalesLine."Document Type" = SalesLine."Document Type"::"Return Order" then + PartialTCSAmount += (GetTCSAmount(SalesLine.RecordId()) * SalesLine."Return Qty. to Receive" / SalesLine.Quantity) + until SalesLine.Next() = 0; + + PartialTCSAmount := TCSManagement.RoundTCSAmount(PartialTCSAmount); + end; + procedure GetStatisticsAmountPostedInvoice( SalesInvoiceHeader: Record "Sales Invoice Header"; var TCSAmount: Decimal) diff --git a/Apps/IN/INTCS/app/TCSOnSales/src/pageextension/SalesOrderStatistics.PageExt.al b/Apps/IN/INTCS/app/TCSOnSales/src/pageextension/SalesOrderStatistics.PageExt.al index 5201836f4c..5237fd2d17 100644 --- a/Apps/IN/INTCS/app/TCSOnSales/src/pageextension/SalesOrderStatistics.PageExt.al +++ b/Apps/IN/INTCS/app/TCSOnSales/src/pageextension/SalesOrderStatistics.PageExt.al @@ -21,6 +21,26 @@ pageextension 18842 "Sales Order Statistics" extends "Sales Order Statistics" Caption = 'TCS Amount'; } } + addlast(Invoicing) + { + field("TCS Amt"; PartialInvTCSAmount) + { + Caption = 'TCS Amount'; + ToolTip = 'Specifies the total TCS amount that has been calculated for all the lines in the sales document.'; + ApplicationArea = Basic, Suite; + Editable = false; + } + } + addlast(Shipping) + { + field("TCS Ship Amt"; PartialShptTCSAmount) + { + Caption = 'TCS Amount'; + ToolTip = 'Specifies the total TCS amount that has been calculated for all the lines in the sales document.'; + ApplicationArea = Basic, Suite; + Editable = false; + } + } modify(InvDiscountAmount_General) { trigger OnAfterValidate() @@ -40,8 +60,11 @@ pageextension 18842 "Sales Order Statistics" extends "Sales Order Statistics" local procedure GetTCSAmount() var TCSStatsManagement: Codeunit "TCS Stats Management"; + TCSSalesManagement: Codeunit "TCS Sales Management"; begin TCSAmount := TCSStatsManagement.GetTCSStatsAmount(); + TCSSalesManagement.GetPartialSalesStatisticsAmount(Rec, PartialInvTCSAmount); + TCSSalesManagement.GetPartialSalesShptStatisticsAmount(Rec, PartialShptTCSAmount); Calculated := true; TCSStatsManagement.ClearSessionVariable(); end; @@ -54,5 +77,7 @@ pageextension 18842 "Sales Order Statistics" extends "Sales Order Statistics" var TCSAmount: Decimal; + PartialInvTCSAmount: Decimal; + PartialShptTCSAmount: Decimal; Calculated: Boolean; } diff --git a/Apps/IN/INTCS/app/TCSReturnAndSettlement/app.json b/Apps/IN/INTCS/app/TCSReturnAndSettlement/app.json index c3ed31c08f..bb1c850052 100644 --- a/Apps/IN/INTCS/app/TCSReturnAndSettlement/app.json +++ b/Apps/IN/INTCS/app/TCSReturnAndSettlement/app.json @@ -2,7 +2,7 @@ "id": "fa63fcf1-bc0a-42a5-8c87-92b63a81b6d4", "name": "TCS Return and Settlement", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Contains features for TCS returns and settlements.", "description": "TCS Return and Settlement lets you do adjustments and settlements for corrections of TCS amounts, and submit TCS that has been collected to the government.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -15,26 +15,26 @@ "id": "c1eafb3f-e397-468e-bdb4-ecc5c317ca00", "publisher": "Microsoft", "name": "Tax Engine", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "d3c551dd-5903-4194-b153-04ced9d29a2c", "publisher": "Microsoft", "name": "India Tax Base", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "a34a9295-94ef-4c4c-b175-367e76e5dd99", "publisher": "Microsoft", "name": "TCS Base", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "application": "24.0.0.0", - "platform": "24.0.0.0", + "application": "25.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 18869, diff --git a/Apps/IN/INTCS/app/TCSReturnAndSettlement/src/TCS-Journal/codeunit/PostTCSJnlLine.codeunit.al b/Apps/IN/INTCS/app/TCSReturnAndSettlement/src/TCS-Journal/codeunit/PostTCSJnlLine.codeunit.al index e219a18dee..815d585331 100644 --- a/Apps/IN/INTCS/app/TCSReturnAndSettlement/src/TCS-Journal/codeunit/PostTCSJnlLine.codeunit.al +++ b/Apps/IN/INTCS/app/TCSReturnAndSettlement/src/TCS-Journal/codeunit/PostTCSJnlLine.codeunit.al @@ -11,8 +11,6 @@ using Microsoft.Finance.GeneralLedger.Journal; codeunit 18871 "Post-TCS Jnl. Line" { var - TempNoSeries: Record "No. Series" temporary; - NoSeriesMgt2: array[10] of Codeunit NoSeriesManagement; GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line"; DocNo: Code[20]; CheckLineLbl: Label 'Checking lines #1######\', Comment = '#1=Line check'; @@ -20,7 +18,6 @@ codeunit 18871 "Post-TCS Jnl. Line" JnlLinePostMsg: Label 'Journal lines posted successfully.'; JnlBatchNameLbl: Label 'Journal Batch Name #4##########\\', Comment = '#4=Journal Batch Name'; PostTCSAdjQst: Label 'Do you want to post the journal lines?'; - PostingNoSeriesErr: Label 'A maximum of %1 posting number series can be used in each journal.', Comment = '%1Posting Number Series.,'; procedure PostTCSJournal(var TCSJournalLine: Record "TCS Journal Line") var @@ -112,22 +109,15 @@ codeunit 18871 "Post-TCS Jnl. Line" procedure CheckDocumentNo(TCSJournalLine: Record "TCS Journal Line"): Code[20] var TCSJournalBatch: Record "TCS Journal Batch"; - NoSeriesManagement: Codeunit NoSeriesManagement; - PostingNoSeriesNo: Integer; + NoSeries: Codeunit "No. Series"; begin if (TCSJournalLine."Journal Template Name" = '') and (TCSJournalLine."Journal Batch Name" = '') and (TCSJournalLine."Document No." <> '') then exit(TCSJournalLine."Document No."); TCSJournalBatch.Get(TCSJournalLine."Journal Template Name", TCSJournalLine."Journal Batch Name"); - if TCSJournalLine."Posting No. Series" = '' then begin + if TCSJournalLine."Posting No. Series" = '' then TCSJournalLine."Posting No. Series" := TCSJournalBatch."No. Series"; - TCSJournalLine."Document No." := NoSeriesManagement.GetNextNo(TCSJournalLine."Posting No. Series", TCSJournalLine."Posting Date", true); - end else begin - InsertNoSeries(TCSJournalLine); - Evaluate(PostingNoSeriesNo, TempNoSeries.Description); - TCSJournalLine."Document No." := - NoSeriesMgt2[PostingNoSeriesNo].GetNextNo(TCSJournalLine."Posting No. Series", TCSJournalLine."Posting Date", true); - end; + TCSJournalLine."Document No." := NoSeries.GetNextNo(TCSJournalLine."Posting No. Series", TCSJournalLine."Posting Date"); exit(TCSJournalLine."Document No."); end; @@ -136,20 +126,4 @@ codeunit 18871 "Post-TCS Jnl. Line" begin GenJnlPostLine.RunWithCheck(GenJournalLine); end; - - local procedure InsertNoSeries(TCSJournalLine: Record "TCS Journal Line") - var - NoOfPostingNoSeries: Integer; - begin - if not TempNoSeries.Get(TCSJournalLine."Posting No. Series") then begin - NoOfPostingNoSeries := NoOfPostingNoSeries + 1; - if NoOfPostingNoSeries > ArrayLen(NoSeriesMgt2) then - Error(PostingNoSeriesErr, ArrayLen(NoSeriesMgt2)); - - TempNoSeries.Init(); - TempNoSeries.Code := TCSJournalLine."Posting No. Series"; - TempNoSeries.Description := Format(NoOfPostingNoSeries); - TempNoSeries.Insert(); - end; - end; } diff --git a/Apps/IN/INTCS/app/TCSReturnAndSettlement/src/TCS-Journal/table/TCSJournalLine.table.al b/Apps/IN/INTCS/app/TCSReturnAndSettlement/src/TCS-Journal/table/TCSJournalLine.table.al index 9e2e6d258f..1144b05699 100644 --- a/Apps/IN/INTCS/app/TCSReturnAndSettlement/src/TCS-Journal/table/TCSJournalLine.table.al +++ b/Apps/IN/INTCS/app/TCSReturnAndSettlement/src/TCS-Journal/table/TCSJournalLine.table.al @@ -677,7 +677,7 @@ table 18870 "TCS Journal Line" var TCSJournalLine: Record "TCS Journal Line"; TCSJournalTemplate: Record "TCS Journal Template"; - NoSeriesManagement: Codeunit NoSeriesManagement; + NoSeries: Codeunit "No. Series"; begin TCSJournalTemplate.Get("Journal Template Name"); TCSJournalBatch.Get("Journal Template Name", "Journal Batch Name"); @@ -695,10 +695,8 @@ table 18870 "TCS Journal Line" end else begin Validate("Posting Date", WorkDate()); Validate("Document Date", WorkDate()); - if TCSJournalBatch."No. Series" <> '' then begin - Clear(NoSeriesManagement); - "Document No." := NoSeriesManagement.GetNextNo(TCSJournalBatch."No. Series", "Posting Date", false); - end; + if TCSJournalBatch."No. Series" <> '' then + "Document No." := NoSeries.PeekNextNo(TCSJournalBatch."No. Series", "Posting Date"); end; Validate("Account Type", LastTCSJournalLine."Account Type"); diff --git a/Apps/IN/INTCS/app/app.json b/Apps/IN/INTCS/app/app.json index 8e419c0e83..c76de8fbb8 100644 --- a/Apps/IN/INTCS/app/app.json +++ b/Apps/IN/INTCS/app/app.json @@ -2,7 +2,7 @@ "id": "eddcf82e-482c-49d1-836b-ad0284f2c5b0", "name": "India TCS", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Tax Collection at Source (TCS) is a tax collection method used by the government. TCS requires buyers and sellers to collect tax at the source, and remit it to tax authorities.", "description": "The TCS feature contains setups that are required for calculating Tax Collected at Source. This allows you to calculate TCS on sales transactions through sales invoices, sales orders, journal vouchers, and on customer advance payments. It also allows you to adjust and settle TCS amounts and submit TCS that has been collected to the government.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -19,20 +19,20 @@ "id": "d3c551dd-5903-4194-b153-04ced9d29a2c", "publisher": "Microsoft", "name": "India Tax Base", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "c1eafb3f-e397-468e-bdb4-ecc5c317ca00", "publisher": "Microsoft", "name": "Tax Engine", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "application": "24.0.0.0", - "platform": "24.0.0.0", + "application": "25.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 18807, diff --git a/Apps/IN/INTCS/test/TCSBase/app.json b/Apps/IN/INTCS/test/TCSBase/app.json index d9ee581d17..16ad6e19b3 100644 --- a/Apps/IN/INTCS/test/TCSBase/app.json +++ b/Apps/IN/INTCS/test/TCSBase/app.json @@ -2,7 +2,7 @@ "id": "1934ea57-7c31-49d8-b614-2d9be932b947", "name": "TCS Base Test Automation", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Automated test of TCS Base", "description": "TCS base contains common library related to Tax Collected at Source", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -18,38 +18,38 @@ "id": "dd0be2ea-f733-4d65-bb34-a28f4624fb14", "publisher": "Microsoft", "name": "Library Assert", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "publisher": "Microsoft", "name": "Tests-TestLibraries", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "eddcf82e-482c-49d1-836b-ad0284f2c5b0", "publisher": "Microsoft", "name": "India TCS", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "d3c551dd-5903-4194-b153-04ced9d29a2c", "publisher": "Microsoft", "name": "India Tax Base", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "c1eafb3f-e397-468e-bdb4-ecc5c317ca00", "publisher": "Microsoft", "name": "Tax Engine", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "application": "24.0.0.0", - "platform": "24.0.0.0", + "application": "25.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 18911, diff --git a/Apps/IN/INTCS/test/TCSOnReceipt/app.json b/Apps/IN/INTCS/test/TCSOnReceipt/app.json index 926b7e77ee..9daea2a001 100644 --- a/Apps/IN/INTCS/test/TCSOnReceipt/app.json +++ b/Apps/IN/INTCS/test/TCSOnReceipt/app.json @@ -2,7 +2,7 @@ "id": "b34fc4d6-93d4-43dc-b8fc-5c8511ae1d74", "name": "TCS On Receipt Automation", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Test Automation of Tax Collected at Source on Receipt.", "description": "Contains all Test Automation of Tax Collected at Source which is applicable on Receipt.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -16,56 +16,56 @@ "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "dependencies": [ { "id": "dd0be2ea-f733-4d65-bb34-a28f4624fb14", "publisher": "Microsoft", "name": "Library Assert", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "publisher": "Microsoft", "name": "Tests-TestLibraries", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5095f467-0a01-4b99-99d1-9ff1237d286f", "publisher": "Microsoft", "name": "Library Variable Storage", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "1934ea57-7c31-49d8-b614-2d9be932b947", "publisher": "Microsoft", "name": "TCS Base Test Automation", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "eddcf82e-482c-49d1-836b-ad0284f2c5b0", "publisher": "Microsoft", "name": "India TCS", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "d3c551dd-5903-4194-b153-04ced9d29a2c", "publisher": "Microsoft", "name": "India Tax Base", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "c1eafb3f-e397-468e-bdb4-ecc5c317ca00", "publisher": "Microsoft", "name": "Tax Engine", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "20cc6140-cbda-4a21-b15d-8f6190fb5469", "publisher": "Microsoft", "name": "India Tax Base Tests", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "idRanges": [ diff --git a/Apps/IN/INTCS/test/TCSOnSales/app.json b/Apps/IN/INTCS/test/TCSOnSales/app.json index def37c735d..65b3656474 100644 --- a/Apps/IN/INTCS/test/TCSOnSales/app.json +++ b/Apps/IN/INTCS/test/TCSOnSales/app.json @@ -2,7 +2,7 @@ "id": "1ac98e31-e5bd-4777-abee-805863db639b", "name": "TCS on Sales Test Automation", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Test Automation of Tax Collected at Source on Sales.", "description": "Contains all Test Automation of Tax Collected at Source which is applicable on sales.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -18,50 +18,50 @@ "id": "dd0be2ea-f733-4d65-bb34-a28f4624fb14", "publisher": "Microsoft", "name": "Library Assert", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "publisher": "Microsoft", "name": "Tests-TestLibraries", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5095f467-0a01-4b99-99d1-9ff1237d286f", "publisher": "Microsoft", "name": "Library Variable Storage", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "1934ea57-7c31-49d8-b614-2d9be932b947", "publisher": "Microsoft", "name": "TCS Base Test Automation", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "eddcf82e-482c-49d1-836b-ad0284f2c5b0", "publisher": "Microsoft", "name": "India TCS", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "d3c551dd-5903-4194-b153-04ced9d29a2c", "publisher": "Microsoft", "name": "India Tax Base", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "c1eafb3f-e397-468e-bdb4-ecc5c317ca00", "publisher": "Microsoft", "name": "Tax Engine", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "application": "24.0.0.0", - "platform": "24.0.0.0", + "application": "25.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 18914, diff --git a/Apps/IN/INTCS/test/TCSOnSales/src/TCSOnSales.Codeunit.al b/Apps/IN/INTCS/test/TCSOnSales/src/TCSOnSales.Codeunit.al index 13fffb2112..e0f5153698 100644 --- a/Apps/IN/INTCS/test/TCSOnSales/src/TCSOnSales.Codeunit.al +++ b/Apps/IN/INTCS/test/TCSOnSales/src/TCSOnSales.Codeunit.al @@ -2118,7 +2118,7 @@ codeunit 18916 "TCS On Sales" true); TCSSalesLibrary.CreateSalesLine(SalesHeader, SalesLine, SalesLine.Type::"Charge (Item)", false); SalesLine.Validate("TCS Nature of Collection", TCSNatureOfCollection2.Code); - SalesLine.validate("Unit Price"); + SalesLine.Validate("Unit Price"); SalesLine.Modify(true); SalesLine.SetRange("Document Type", SalesHeader."Document Type"); @@ -2733,7 +2733,7 @@ codeunit 18916 "TCS On Sales" SalesLine.SetRange("Document No.", SalesHeader."No."); if SalesLine.FindFirst() then begin SalesLine.Validate("TCS Nature of Collection", ''); - SalesLine.validate("Unit Price"); + SalesLine.Validate("Unit Price"); SalesLine.Modify(true); end; TCSSalesLibrary.CreateSalesLine(SalesHeader, SalesLine, SalesLine.Type::"Fixed Asset", false); @@ -2771,7 +2771,7 @@ codeunit 18916 "TCS On Sales" SalesLine.SetRange("Document No.", SalesHeader."No."); if SalesLine.FindFirst() then begin SalesLine.Validate("TCS Nature of Collection", ''); - SalesLine.validate("Unit Price"); + SalesLine.Validate("Unit Price"); SalesLine.Modify(true); end; TCSSalesLibrary.CreateSalesLine(SalesHeader, SalesLine, SalesLine.Type::"Fixed Asset", false); @@ -2809,7 +2809,7 @@ codeunit 18916 "TCS On Sales" SalesLine.SetRange("Document No.", SalesHeader."No."); if SalesLine.FindFirst() then begin SalesLine.Validate("TCS Nature of Collection", ''); - SalesLine.validate("Unit Price"); + SalesLine.Validate("Unit Price"); SalesLine.Modify(true); end; TCSSalesLibrary.CreateSalesLine(SalesHeader, SalesLine, SalesLine.Type::Resource, false); @@ -2848,7 +2848,7 @@ codeunit 18916 "TCS On Sales" SalesLine.SetRange("Document No.", SalesHeader."No."); if SalesLine.FindFirst() then begin SalesLine.Validate("TCS Nature of Collection", ''); - SalesLine.validate("Unit Price"); + SalesLine.Validate("Unit Price"); SalesLine.Modify(true); end; TCSSalesLibrary.CreateSalesLine(SalesHeader, SalesLine, SalesLine.Type::Resource, false); @@ -3071,7 +3071,7 @@ codeunit 18916 "TCS On Sales" SalesLine.SetRange("Document No.", SalesHeader."No."); if SalesLine.FindFirst() then begin SalesLine.Validate("TCS Nature of Collection", TCSNatureOfCollection2.Code); - SalesLine.validate("Unit Price"); + SalesLine.Validate("Unit Price"); SalesLine.Modify(true); end; DocumentNo := LibrarySales.PostSalesDocument(SalesHeader, true, true); @@ -3114,7 +3114,7 @@ codeunit 18916 "TCS On Sales" SalesLine.SetRange("Document No.", SalesHeader."No."); if SalesLine.FindFirst() then begin SalesLine.Validate("TCS Nature of Collection", TCSNatureOfCollection2.Code); - SalesLine.validate("Unit Price"); + SalesLine.Validate("Unit Price"); SalesLine.Modify(true); end; DocumentNo := LibrarySales.PostSalesDocument(SalesHeader, true, true); diff --git a/Apps/IN/INTCS/test/TCSOnSales/src/TCSOnSalesDocuments.Codeunit.al b/Apps/IN/INTCS/test/TCSOnSales/src/TCSOnSalesDocuments.Codeunit.al index ce41056b76..62c7f06428 100644 --- a/Apps/IN/INTCS/test/TCSOnSales/src/TCSOnSalesDocuments.Codeunit.al +++ b/Apps/IN/INTCS/test/TCSOnSales/src/TCSOnSalesDocuments.Codeunit.al @@ -3829,7 +3829,7 @@ codeunit 18917 "TCS On Sales Documents" SalesHeader.Validate("Posting Date", PostingDate); SalesHeader.Modify(true); TCSSalesLibrary.CreateSalesLine(SalesHeader, SalesLine, SalesLine.Type::Item, false); - SalesLine.validate("Qty. to Invoice", SalesLine.Quantity / 2); + SalesLine.Validate("Qty. to Invoice", SalesLine.Quantity / 2); SalesLine.Modify(); TCSSalesLibrary.CreateSalesLine(SalesHeader, SalesLine1, SalesLine.Type::"Charge (Item)", false); TCSSalesLibrary.CreateItemChargeAssignment( diff --git a/Apps/IN/INTCS/test/TCSReturnAndSettlement/app.json b/Apps/IN/INTCS/test/TCSReturnAndSettlement/app.json index edf449cd8d..3d89dc9f34 100644 --- a/Apps/IN/INTCS/test/TCSReturnAndSettlement/app.json +++ b/Apps/IN/INTCS/test/TCSReturnAndSettlement/app.json @@ -2,7 +2,7 @@ "id": "3054d40b-11ed-4ea2-9832-9106a3b3d2ac", "name": "TCS Return and Settlement Automation", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Test Automation of Tax Collected at Source on Return and Settlement.", "description": "Contains all Test Automation of Tax Collected at Source which is applicable on Return and Settlement.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -18,44 +18,44 @@ "id": "dd0be2ea-f733-4d65-bb34-a28f4624fb14", "publisher": "Microsoft", "name": "Library Assert", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "publisher": "Microsoft", "name": "Tests-TestLibraries", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "1934ea57-7c31-49d8-b614-2d9be932b947", "publisher": "Microsoft", "name": "TCS Base Test Automation", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "eddcf82e-482c-49d1-836b-ad0284f2c5b0", "publisher": "Microsoft", "name": "India TCS", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "d3c551dd-5903-4194-b153-04ced9d29a2c", "publisher": "Microsoft", "name": "India Tax Base", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "c1eafb3f-e397-468e-bdb4-ecc5c317ca00", "publisher": "Microsoft", "name": "Tax Engine", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 18921, diff --git a/Apps/IN/INTCS/test/app.json b/Apps/IN/INTCS/test/app.json index ca05456c23..445e26b666 100644 --- a/Apps/IN/INTCS/test/app.json +++ b/Apps/IN/INTCS/test/app.json @@ -2,7 +2,7 @@ "id": "59d65920-9fcc-456f-81f0-0bdea982ed30", "name": "India TCS Tests", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Tests for India TCS.", "description": "Tests for India TCS.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -18,50 +18,50 @@ "id": "dd0be2ea-f733-4d65-bb34-a28f4624fb14", "publisher": "Microsoft", "name": "Library Assert", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "publisher": "Microsoft", "name": "Tests-TestLibraries", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5095f467-0a01-4b99-99d1-9ff1237d286f", "publisher": "Microsoft", "name": "Library Variable Storage", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "d3c551dd-5903-4194-b153-04ced9d29a2c", "publisher": "Microsoft", "name": "India Tax Base", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "c1eafb3f-e397-468e-bdb4-ecc5c317ca00", "publisher": "Microsoft", "name": "Tax Engine", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "eddcf82e-482c-49d1-836b-ad0284f2c5b0", "publisher": "Microsoft", "name": "India TCS", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "20cc6140-cbda-4a21-b15d-8f6190fb5469", "publisher": "Microsoft", "name": "India Tax Base Tests", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "application": "24.0.0.0", - "platform": "24.0.0.0", + "application": "25.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 18911, diff --git a/Apps/IN/INTDS/app/TDSBase/app.json b/Apps/IN/INTDS/app/TDSBase/app.json index b4a8df4728..13d89400d2 100644 --- a/Apps/IN/INTDS/app/TDSBase/app.json +++ b/Apps/IN/INTDS/app/TDSBase/app.json @@ -2,7 +2,7 @@ "id": "c529ebd1-996f-4f1d-b0a4-f3e53256d5ad", "name": "TDS Base", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Contains setups for Tax Deducted at Source (TDS).", "description": "TDS Base contains setups that are required for calculating TDS.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -19,20 +19,20 @@ "id": "d3c551dd-5903-4194-b153-04ced9d29a2c", "publisher": "Microsoft", "name": "India Tax Base", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "c1eafb3f-e397-468e-bdb4-ecc5c317ca00", "publisher": "Microsoft", "name": "Tax Engine", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "application": "24.0.0.0", - "platform": "24.0.0.0", + "application": "25.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 18685, 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 b4c4d23e25..1a359b60eb 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}', 16); + UseCases.Add('{A8E114BF-F8CD-44DB-A2B3-614BC18F4442}', 17); 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/TDSForCustomer/app.json b/Apps/IN/INTDS/app/TDSForCustomer/app.json index 7073a9a3fa..dd90ad8d7b 100644 --- a/Apps/IN/INTDS/app/TDSForCustomer/app.json +++ b/Apps/IN/INTDS/app/TDSForCustomer/app.json @@ -2,7 +2,7 @@ "id": "3147530a-3d75-43c7-b5e9-b28f0faa5a3a", "name": "TDS For Customer", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Contains features for Tax Deducted at Source by customers.", "description": "TDS on customers lets you calculate TDS on customer payments using journals, and track TDS by customers on invoices.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -19,26 +19,26 @@ "id": "c1eafb3f-e397-468e-bdb4-ecc5c317ca00", "publisher": "Microsoft", "name": "Tax Engine", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "d3c551dd-5903-4194-b153-04ced9d29a2c", "publisher": "Microsoft", "name": "India Tax Base", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "c529ebd1-996f-4f1d-b0a4-f3e53256d5ad", "publisher": "Microsoft", "name": "TDS Base", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "application": "24.0.0.0", - "platform": "24.0.0.0", + "application": "25.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 18661, diff --git a/Apps/IN/INTDS/app/TDSOnPayments/app.json b/Apps/IN/INTDS/app/TDSOnPayments/app.json index 4ca2fb4107..09ad909449 100644 --- a/Apps/IN/INTDS/app/TDSOnPayments/app.json +++ b/Apps/IN/INTDS/app/TDSOnPayments/app.json @@ -2,7 +2,7 @@ "id": "956ade9d-6348-4352-b5da-63d33586c5aa", "name": "TDS on Payments", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Contains features for Tax Deducted on Payments.", "description": "TDS on Payments lets you deduct TDS on vendor advance payments using journals.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -10,8 +10,8 @@ "help": "https://go.microsoft.com/fwlink/?linkid=2139181", "url": "https://go.microsoft.com/fwlink/?LinkId=724011", "logo": "ExtensionLogo.png", - "application": "24.0.0.0", - "platform": "24.0.0.0", + "application": "25.0.0.0", + "platform": "25.0.0.0", "features": [ "TranslationFile", "GenerateCaptions" @@ -21,25 +21,25 @@ "id": "c1eafb3f-e397-468e-bdb4-ecc5c317ca00", "publisher": "Microsoft", "name": "Tax Engine", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "d3c551dd-5903-4194-b153-04ced9d29a2c", "publisher": "Microsoft", "name": "India Tax Base", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "c529ebd1-996f-4f1d-b0a4-f3e53256d5ad", "publisher": "Microsoft", "name": "TDS Base", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "3147530a-3d75-43c7-b5e9-b28f0faa5a3a", "name": "TDS For Customer", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ diff --git a/Apps/IN/INTDS/app/TDSOnPurchase/app.json b/Apps/IN/INTDS/app/TDSOnPurchase/app.json index 9273cfa56e..74d08b1eae 100644 --- a/Apps/IN/INTDS/app/TDSOnPurchase/app.json +++ b/Apps/IN/INTDS/app/TDSOnPurchase/app.json @@ -2,7 +2,7 @@ "id": "818e965d-15f6-4fbf-924f-e5a49b7da7d6", "name": "TDS on Purchase", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Contains features for Tax Deducted at Source for purchases.", "description": "TDS on Purchase lets you use purchase orders, purchase invoices, and journal vouchers to deduct TDS on vendor invoices that have no advance payments.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -14,26 +14,26 @@ "TranslationFile", "GenerateCaptions" ], - "application": "24.0.0.0", - "platform": "24.0.0.0", + "application": "25.0.0.0", + "platform": "25.0.0.0", "dependencies": [ { "id": "c1eafb3f-e397-468e-bdb4-ecc5c317ca00", "publisher": "Microsoft", "name": "Tax Engine", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "d3c551dd-5903-4194-b153-04ced9d29a2c", "publisher": "Microsoft", "name": "India Tax Base", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "c529ebd1-996f-4f1d-b0a4-f3e53256d5ad", "publisher": "Microsoft", "name": "TDS Base", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ diff --git a/Apps/IN/INTDS/app/TDSOnPurchase/src/codeunit/TDSStatistics.Codeunit.al b/Apps/IN/INTDS/app/TDSOnPurchase/src/codeunit/TDSStatistics.Codeunit.al index 73a83fa925..5afd8ab574 100644 --- a/Apps/IN/INTDS/app/TDSOnPurchase/src/codeunit/TDSStatistics.Codeunit.al +++ b/Apps/IN/INTDS/app/TDSOnPurchase/src/codeunit/TDSStatistics.Codeunit.al @@ -37,6 +37,64 @@ codeunit 18719 "TDS Statistics" TDSAmount := TDSEntityManagement.RoundTDSAmount(TDSAmount); end; + [EventSubscriber(ObjectType::Codeunit, Codeunit::"Calculate Statistics", 'OnGetPartialPurchaseHeaderTDSAmount', '', false, false)] + local procedure OnGetPartialPurchaseHeaderTDSAmount(PurchaseHeader: Record "Purchase Header"; var PartialTDSAmount: Decimal) + begin + GetPartialPurchaseInvStatisticsAmount(PurchaseHeader, PartialTDSAmount); + end; + + [EventSubscriber(ObjectType::Codeunit, Codeunit::"Calculate Statistics", 'OnGetPartialPurchaseRcptTDSAmount', '', false, false)] + local procedure OnGetPartialPurchaseRcptGSTAmount(PurchaseHeader: Record "Purchase Header"; var PartialTDSAmount: Decimal) + begin + GetPartialPurchaseRcptStatisticsAmount(PurchaseHeader, PartialTDSAmount); + end; + + procedure GetPartialPurchaseInvStatisticsAmount( + PurchaseHeader: Record "Purchase Header"; + var PartialTDSAmount: Decimal) + var + PurchaseLine: Record "Purchase Line"; + TDSEntityManagement: Codeunit "TDS Entity Management"; + begin + Clear(PartialTDSAmount); + + PurchaseLine.SetLoadFields("Document Type", "Document No.", Quantity, "Qty. to Invoice"); + PurchaseLine.SetRange("Document Type", PurchaseHeader."Document Type"); + PurchaseLine.SetRange("Document no.", PurchaseHeader."No."); + if PurchaseLine.FindSet() then + repeat + if PurchaseLine.Quantity <> 0 then + PartialTDSAmount += (GetTDSAmount(PurchaseLine.RecordId()) * PurchaseLine."Qty. to Invoice" / PurchaseLine.Quantity); + until PurchaseLine.Next() = 0; + + PartialTDSAmount := TDSEntityManagement.RoundTDSAmount(PartialTDSAmount); + end; + + procedure GetPartialPurchaseRcptStatisticsAmount( + PurchaseHeader: Record "Purchase Header"; + var PartialTDSAmount: Decimal) + var + PurchaseLine: Record "Purchase Line"; + TDSEntityManagement: Codeunit "TDS Entity Management"; + begin + Clear(PartialTDSAmount); + + PurchaseLine.SetLoadFields("Document Type", "Document No.", Quantity, "Qty. to Receive", "Return Qty. to Ship"); + PurchaseLine.SetRange("Document Type", PurchaseHeader."Document Type"); + PurchaseLine.SetRange("Document no.", PurchaseHeader."No."); + if PurchaseLine.FindSet() then + repeat + if PurchaseLine.Quantity <> 0 then + if PurchaseLine."Document Type" = PurchaseLine."Document Type"::Order then + PartialTDSAmount += (GetTDSAmount(PurchaseLine.RecordId()) * PurchaseLine."Qty. to Receive" / PurchaseLine.Quantity) + else + if PurchaseLine."Document Type" = PurchaseLine."Document Type"::"Return Order" then + PartialTDSAmount += (GetTDSAmount(PurchaseLine.RecordId()) * PurchaseLine."Return Qty. to Ship" / PurchaseLine.Quantity); + until PurchaseLine.Next() = 0; + + PartialTDSAmount := TDSEntityManagement.RoundTDSAmount(PartialTDSAmount); + end; + procedure GetStatisticsPostedAmount( PurchInvHeader: Record "Purch. Inv. Header"; var TDSAmount: Decimal) diff --git a/Apps/IN/INTDS/app/TDSOnPurchase/src/pageextension/PurchaseOrderStatistics.PageExt.al b/Apps/IN/INTDS/app/TDSOnPurchase/src/pageextension/PurchaseOrderStatistics.PageExt.al index add4d95ba0..84ce206170 100644 --- a/Apps/IN/INTDS/app/TDSOnPurchase/src/pageextension/PurchaseOrderStatistics.PageExt.al +++ b/Apps/IN/INTDS/app/TDSOnPurchase/src/pageextension/PurchaseOrderStatistics.PageExt.al @@ -5,6 +5,7 @@ namespace Microsoft.Purchases.Document; using Microsoft.Finance.TDS.TDSBase; +using Microsoft.Finance.TDS.TDSOnPurchase; pageextension 18719 "Purchase Order Statistics" extends "Purchase Order Statistics" { @@ -20,6 +21,26 @@ pageextension 18719 "Purchase Order Statistics" extends "Purchase Order Statisti Caption = 'TDS Amount'; } } + addlast(Invoicing) + { + field("TDS Amt"; PartialInvTDSAmount) + { + Caption = 'TDS Amount'; + ToolTip = 'Specifies the amount of TDS that is included in the total amount.'; + ApplicationArea = Basic, Suite; + Editable = false; + } + } + addlast(Shipping) + { + field("TDS Purch Amt"; PartialRcptTDSAmount) + { + Caption = 'TDS Amount'; + ToolTip = 'Specifies the amount of TDS that is included in the total amount.'; + ApplicationArea = Basic, Suite; + Editable = false; + } + } } trigger OnAfterGetRecord() @@ -30,8 +51,11 @@ pageextension 18719 "Purchase Order Statistics" extends "Purchase Order Statisti local procedure GetTDSAmount() var TDSStatsManagement: Codeunit "TDS Stats Management"; + TDSStatistics: Codeunit "TDS Statistics"; begin TDSAmount := TDSStatsManagement.GetTDSStatsAmount(); + TDSStatistics.GetPartialPurchaseInvStatisticsAmount(Rec, PartialInvTDSAmount); + TDSStatistics.GetPartialPurchaseRcptStatisticsAmount(Rec, PartialRcptTDSAmount); Calculated := true; TDSStatsManagement.ClearSessionVariable(); end; @@ -45,5 +69,7 @@ pageextension 18719 "Purchase Order Statistics" extends "Purchase Order Statisti var TDSAmount: Decimal; + PartialInvTDSAmount: Decimal; + PartialRcptTDSAmount: Decimal; Calculated: Boolean; } diff --git a/Apps/IN/INTDS/app/TDSReturnAndSettlement/app.json b/Apps/IN/INTDS/app/TDSReturnAndSettlement/app.json index 03d9e386ae..076b24f6ab 100644 --- a/Apps/IN/INTDS/app/TDSReturnAndSettlement/app.json +++ b/Apps/IN/INTDS/app/TDSReturnAndSettlement/app.json @@ -2,7 +2,7 @@ "id": "2ccd4f40-5cc3-495a-b7d5-1c3ca1448066", "name": "TDS Return and Settlement", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Contains features for Tax Deducted at Source for returns and settlements.", "description": "TDS Return and Settlement lets you adjust and settle corrections to TDS amounts, and submit TDS that has been deducted to the government.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -10,32 +10,32 @@ "help": "https://go.microsoft.com/fwlink/?linkid=2139181", "url": "https://go.microsoft.com/fwlink/?LinkId=724011", "logo": "ExtensionLogo.png", - "application": "24.0.0.0", - "platform": "24.0.0.0", + "application": "25.0.0.0", + "platform": "25.0.0.0", "dependencies": [ { "id": "c1eafb3f-e397-468e-bdb4-ecc5c317ca00", "publisher": "Microsoft", "name": "Tax Engine", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "d3c551dd-5903-4194-b153-04ced9d29a2c", "publisher": "Microsoft", "name": "India Tax Base", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "4a217711-3ba5-42f0-95c7-5f306c52042d", "name": "India GST", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "3147530a-3d75-43c7-b5e9-b28f0faa5a3a", "name": "TDS For Customer", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ diff --git a/Apps/IN/INTDS/app/TDSReturnAndSettlement/src/TDS-Journal/TDSAdjustmentPost.codeunit.al b/Apps/IN/INTDS/app/TDSReturnAndSettlement/src/TDS-Journal/TDSAdjustmentPost.codeunit.al index 29eb077033..56968458c6 100644 --- a/Apps/IN/INTDS/app/TDSReturnAndSettlement/src/TDS-Journal/TDSAdjustmentPost.codeunit.al +++ b/Apps/IN/INTDS/app/TDSReturnAndSettlement/src/TDS-Journal/TDSAdjustmentPost.codeunit.al @@ -13,15 +13,12 @@ using Microsoft.Purchases.Vendor; codeunit 18748 "TDS Adjustment Post" { var - TempNoSeries: Record "No. Series" temporary; - NoSeriesMgt2: array[10] of Codeunit NoSeriesManagement; DocNo: Code[20]; CheckLineLbl: Label 'Checking lines #1######\', Comment = '#1=Line check'; PostLineLbl: Label 'Posting lines #2###### @3@@@@@@@@@@@@@\', Comment = '#2=Post Line'; JnlLinePostMsg: Label 'Journal lines posted successfully.'; JnlBatchNameLbl: Label 'Journal Batch Name #4##########\\', Comment = '#4=Journal Batch Name'; PostTDSAdjQst: Label 'Do you want to post the journal lines?'; - PostingNoSeriesErr: Label 'A maximum of %1 posting number series can be used in each journal.', Comment = '%1 Posting Number Series.,'; procedure PostTaxJournal(var TDSJournalLine: Record "TDS Journal Line") var @@ -117,22 +114,15 @@ codeunit 18748 "TDS Adjustment Post" procedure CheckDocumentNo(TDSJournalLine: Record "TDS Journal Line"): Code[20] var TDSJournalBatch: Record "TDS Journal Batch"; - NoSeriesManagement: Codeunit NoSeriesManagement; - PostingNoSeriesNo: Integer; + NoSeries: Codeunit "No. Series"; begin if (TDSJournalLine."Journal Template Name" = '') and (TDSJournalLine."Journal Batch Name" = '') and (TDSJournalLine."Document No." <> '') then exit(TDSJournalLine."Document No."); TDSJournalBatch.Get(TDSJournalLine."Journal Template Name", TDSJournalLine."Journal Batch Name"); - if TDSJournalLine."Posting No. Series" = '' then begin + if TDSJournalLine."Posting No. Series" = '' then TDSJournalLine."Posting No. Series" := TDSJournalBatch."No. Series"; - TDSJournalLine."Document No." := NoSeriesManagement.GetNextNo(TDSJournalLine."Posting No. Series", TDSJournalLine."Posting Date", true); - end else begin - InsertNoSeries(TDSJournalLine); - Evaluate(PostingNoSeriesNo, TempNoSeries.Description); - TDSJournalLine."Document No." := - NoSeriesMgt2[PostingNoSeriesNo].GetNextNo(TDSJournalLine."Posting No. Series", TDSJournalLine."Posting Date", true); - end; + TDSJournalLine."Document No." := NoSeries.GetNextNo(TDSJournalLine."Posting No. Series", TDSJournalLine."Posting Date"); exit(TDSJournalLine."Document No."); end; @@ -306,21 +296,4 @@ codeunit 18748 "TDS Adjustment Post" begin GenJnlPostLine.RunWithCheck(GenJournalLine); end; - - local procedure InsertNoSeries(TDSJournalLine: Record "TDS Journal Line") - var - NoOfPostingNoSeries: Integer; - begin - if TempNoSeries.Get(TDSJournalLine."Posting No. Series") then - exit; - - NoOfPostingNoSeries := NoOfPostingNoSeries + 1; - if NoOfPostingNoSeries > ArrayLen(NoSeriesMgt2) then - Error(PostingNoSeriesErr, ArrayLen(NoSeriesMgt2)); - - TempNoSeries.Init(); - TempNoSeries.Code := TDSJournalLine."Posting No. Series"; - TempNoSeries.Description := Format(NoOfPostingNoSeries); - TempNoSeries.Insert(); - end; } diff --git a/Apps/IN/INTDS/app/TDSReturnAndSettlement/src/TDS-Journal/TDSJournalLine.table.al b/Apps/IN/INTDS/app/TDSReturnAndSettlement/src/TDS-Journal/TDSJournalLine.table.al index bc630186a1..46b697acae 100644 --- a/Apps/IN/INTDS/app/TDSReturnAndSettlement/src/TDS-Journal/TDSJournalLine.table.al +++ b/Apps/IN/INTDS/app/TDSReturnAndSettlement/src/TDS-Journal/TDSJournalLine.table.al @@ -822,7 +822,7 @@ table 18747 "TDS Journal Line" TDSJournalLine: Record "TDS Journal Line"; TDSJournalTemplate: Record "TDS Journal Template"; TDSJournalBatch: Record "TDS Journal Batch"; - NoSeriesManagement: Codeunit NoSeriesManagement; + NoSeries: Codeunit "No. Series"; begin TDSJournalTemplate.Get("Journal Template Name"); TDSJournalBatch.Get("Journal Template Name", "Journal Batch Name"); @@ -841,10 +841,8 @@ table 18747 "TDS Journal Line" end else begin "Posting Date" := WorkDate(); "Document Date" := WorkDate(); - if TDSJournalBatch."No. Series" <> '' then begin - Clear(NoSeriesManagement); - "Document No." := NoSeriesManagement.GetNextNo(TDSJournalBatch."No. Series", "Posting Date", false); - end; + if TDSJournalBatch."No. Series" <> '' then + "Document No." := NoSeries.PeekNextNo(TDSJournalBatch."No. Series", "Posting Date"); end; Validate("Account Type", LastTDSJournalLine."Account Type"); Validate("Document Type", LastTDSJournalLine."Document Type"); 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 1f852f8eb4..f6e1842efb 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 8d42703128..37e03b8c67 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/IN/INTDS/app/app.json b/Apps/IN/INTDS/app/app.json index 217b8271c1..7227ade94d 100644 --- a/Apps/IN/INTDS/app/app.json +++ b/Apps/IN/INTDS/app/app.json @@ -2,7 +2,7 @@ "id": "eae5779e-7797-4c4c-977e-7516652b7a65", "name": "India TDS", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Contains functionality for Tax Deducted at Source (TDS) on certain income and payments at the rates prescribed by the Income Tax Act.", "description": "The TDS feature contains setups that are required for calculating Tax Deducted at Source. This lets you deduct TDS on vendor invoices through purchase orders, invoices, journal vouchers, and on vendor advance payments. It also lets you adjust and settle TDS amounts and submit TDS that has been deducted to the government.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -19,20 +19,20 @@ "id": "d3c551dd-5903-4194-b153-04ced9d29a2c", "publisher": "Microsoft", "name": "India Tax Base", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "c1eafb3f-e397-468e-bdb4-ecc5c317ca00", "publisher": "Microsoft", "name": "Tax Engine", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "application": "24.0.0.0", - "platform": "24.0.0.0", + "application": "25.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 18661, diff --git a/Apps/IN/INTDS/test/TDSBase/app.json b/Apps/IN/INTDS/test/TDSBase/app.json index 708e8d584a..50d4a1850d 100644 --- a/Apps/IN/INTDS/test/TDSBase/app.json +++ b/Apps/IN/INTDS/test/TDSBase/app.json @@ -2,7 +2,7 @@ "id": "6420dd20-4768-4733-a3c7-c22d338fdd32", "name": "TDS Base Tests", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Automated Test Cases of TDS Base", "description": "TDS Base contains setups that are required for calculating the Tax Deducted at Source.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -18,38 +18,38 @@ "id": "dd0be2ea-f733-4d65-bb34-a28f4624fb14", "publisher": "Microsoft", "name": "Library Assert", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "publisher": "Microsoft", "name": "Tests-TestLibraries", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "c1eafb3f-e397-468e-bdb4-ecc5c317ca00", "publisher": "Microsoft", "name": "Tax Engine", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "d3c551dd-5903-4194-b153-04ced9d29a2c", "publisher": "Microsoft", "name": "India Tax Base", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "eae5779e-7797-4c4c-977e-7516652b7a65", "publisher": "Microsoft", "name": "India TDS", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "application": "24.0.0.0", - "platform": "24.0.0.0", + "application": "25.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 18786, diff --git a/Apps/IN/INTDS/test/TDSOnCustomer/app.json b/Apps/IN/INTDS/test/TDSOnCustomer/app.json index 482b7b5f31..32139d07dc 100644 --- a/Apps/IN/INTDS/test/TDSOnCustomer/app.json +++ b/Apps/IN/INTDS/test/TDSOnCustomer/app.json @@ -2,7 +2,7 @@ "id": "49d563f9-175e-405b-a8b0-d7ff6036443f", "name": "TDS On Customer Tests", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Contains Automated Test Cases of TDS On Customer", "description": "Contains Automated Test Cases of TDS On Customer", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -18,62 +18,62 @@ "id": "d3c551dd-5903-4194-b153-04ced9d29a2c", "publisher": "Microsoft", "name": "India Tax Base", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "dd0be2ea-f733-4d65-bb34-a28f4624fb14", "publisher": "Microsoft", "name": "Library Assert", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "publisher": "Microsoft", "name": "Tests-TestLibraries", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5095f467-0a01-4b99-99d1-9ff1237d286f", "publisher": "Microsoft", "name": "Library Variable Storage", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "eae5779e-7797-4c4c-977e-7516652b7a65", "publisher": "Microsoft", "name": "India TDS", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "db643212-b7fb-4dd4-b5a8-cb44ac714461", "publisher": "Microsoft", "name": "India GST", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "c1eafb3f-e397-468e-bdb4-ecc5c317ca00", "publisher": "Microsoft", "name": "Tax Engine", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "f1d9b696-156b-4251-b542-34e549fa80e9", "publisher": "Microsoft", "name": "India Voucher Interface", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "20cc6140-cbda-4a21-b15d-8f6190fb5469", "publisher": "Microsoft", "name": "India Tax Base Tests", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 18681, diff --git a/Apps/IN/INTDS/test/TDSOnPayments/app.json b/Apps/IN/INTDS/test/TDSOnPayments/app.json index fbdfb86250..800a476b45 100644 --- a/Apps/IN/INTDS/test/TDSOnPayments/app.json +++ b/Apps/IN/INTDS/test/TDSOnPayments/app.json @@ -2,7 +2,7 @@ "id": "5dd176ea-cca4-4052-b717-c3349fb49442", "name": "TDS on Payments Tests", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Automated Test Cases of Payments", "description": "TDS on Payments allows to deduct TDS on vendor advance payment using journals.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -10,37 +10,37 @@ "help": "https://go.microsoft.com/fwlink/?linkid=2139181", "url": "https://go.microsoft.com/fwlink/?LinkId=724011", "logo": "ExtensionLogo.png", - "application": "24.0.0.0", - "platform": "24.0.0.0", + "application": "25.0.0.0", + "platform": "25.0.0.0", "dependencies": [ { "id": "d3c551dd-5903-4194-b153-04ced9d29a2c", "publisher": "Microsoft", "name": "India Tax Base", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "6420dd20-4768-4733-a3c7-c22d338fdd32", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "4a217711-3ba5-42f0-95c7-5f306c52042d", "name": "India GST", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "eae5779e-7797-4c4c-977e-7516652b7a65", "publisher": "Microsoft", "name": "India TDS", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "c1eafb3f-e397-468e-bdb4-ecc5c317ca00", "publisher": "Microsoft", "name": "Tax Engine", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ diff --git a/Apps/IN/INTDS/test/TDSOnPurchase/app.json b/Apps/IN/INTDS/test/TDSOnPurchase/app.json index 9f617b6d2e..38b3f547a8 100644 --- a/Apps/IN/INTDS/test/TDSOnPurchase/app.json +++ b/Apps/IN/INTDS/test/TDSOnPurchase/app.json @@ -2,7 +2,7 @@ "id": "bcf5e3a2-65ad-4336-b294-c86585b2e305", "name": "TDS on Purchase Tests", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Automated Test Cases of Purchase", "description": "TDS on Purchase allows deducting TDS on vendor invoices, which have no advance payments, through Purchase Order/Purchase Invoices/Journal Voucher documents.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -18,37 +18,37 @@ "id": "d3c551dd-5903-4194-b153-04ced9d29a2c", "publisher": "Microsoft", "name": "India Tax Base", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "6420dd20-4768-4733-a3c7-c22d338fdd32", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "4a217711-3ba5-42f0-95c7-5f306c52042d", "name": "India GST", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "eae5779e-7797-4c4c-977e-7516652b7a65", "publisher": "Microsoft", "name": "India TDS", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "c1eafb3f-e397-468e-bdb4-ecc5c317ca00", "publisher": "Microsoft", "name": "Tax Engine", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "application": "24.0.0.0", - "platform": "24.0.0.0", + "application": "25.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 18791, diff --git a/Apps/IN/INTDS/test/TDSReturnAndSettlement/app.json b/Apps/IN/INTDS/test/TDSReturnAndSettlement/app.json index 69a85ff13d..2289d510ac 100644 --- a/Apps/IN/INTDS/test/TDSReturnAndSettlement/app.json +++ b/Apps/IN/INTDS/test/TDSReturnAndSettlement/app.json @@ -2,7 +2,7 @@ "id": "7fc686c2-2fcb-409a-a905-10a9f9aa1669", "name": "TDS Return and Settlement Tests", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Automated Test Cases of TDS Return and Settlement", "description": "Contains Automated Test Cases of TDS Return.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -13,50 +13,50 @@ "TranslationFile" ], "logo": "ExtensionLogo.png", - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "dependencies": [ { "id": "d3c551dd-5903-4194-b153-04ced9d29a2c", "publisher": "Microsoft", "name": "India Tax Base", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "dd0be2ea-f733-4d65-bb34-a28f4624fb14", "publisher": "Microsoft", "name": "Library Assert", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "publisher": "Microsoft", "name": "Tests-TestLibraries", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "6420dd20-4768-4733-a3c7-c22d338fdd32", "publisher": "Microsoft", "name": "TDS Base Tests", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "eae5779e-7797-4c4c-977e-7516652b7a65", "publisher": "Microsoft", "name": "India TDS", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "c1eafb3f-e397-468e-bdb4-ecc5c317ca00", "publisher": "Microsoft", "name": "Tax Engine", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "20cc6140-cbda-4a21-b15d-8f6190fb5469", "publisher": "Microsoft", "name": "India Tax Base Tests", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ diff --git a/Apps/IN/INTDS/test/app.json b/Apps/IN/INTDS/test/app.json index 3987cd6719..4edce8d1e9 100644 --- a/Apps/IN/INTDS/test/app.json +++ b/Apps/IN/INTDS/test/app.json @@ -2,7 +2,7 @@ "id": "11eff78d-dfc4-4f4e-a9cd-7da39bc44c68", "name": "India TDS Tests", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Tests for India TDS.", "description": "Tests for India TDS.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -18,50 +18,50 @@ "id": "dd0be2ea-f733-4d65-bb34-a28f4624fb14", "publisher": "Microsoft", "name": "Library Assert", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "publisher": "Microsoft", "name": "Tests-TestLibraries", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5095f467-0a01-4b99-99d1-9ff1237d286f", "publisher": "Microsoft", "name": "Library Variable Storage", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "c1eafb3f-e397-468e-bdb4-ecc5c317ca00", "publisher": "Microsoft", "name": "Tax Engine", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "d3c551dd-5903-4194-b153-04ced9d29a2c", "publisher": "Microsoft", "name": "India Tax Base", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "eae5779e-7797-4c4c-977e-7516652b7a65", "publisher": "Microsoft", "name": "India TDS", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "20cc6140-cbda-4a21-b15d-8f6190fb5469", "publisher": "Microsoft", "name": "India Tax Base Tests", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "application": "24.0.0.0", - "platform": "24.0.0.0", + "application": "25.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 18681, diff --git a/Apps/IN/INTaxBase/app/app.json b/Apps/IN/INTaxBase/app/app.json index 517c80fe02..0c86bbc62c 100644 --- a/Apps/IN/INTaxBase/app/app.json +++ b/Apps/IN/INTaxBase/app/app.json @@ -2,7 +2,7 @@ "id": "d3c551dd-5903-4194-b153-04ced9d29a2c", "name": "India Tax Base", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Common Tax Setups", "description": "Tax base contains common setups for GST, TDS and TCS.", "features": [ @@ -19,14 +19,14 @@ "id": "c1eafb3f-e397-468e-bdb4-ecc5c317ca00", "publisher": "Microsoft", "name": "Tax Engine", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "application": "24.0.0.0", - "platform": "24.0.0.0", + "application": "25.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 18543, diff --git a/Apps/IN/INTaxBase/app/src/codeunit/CalculateStatistics.Codeunit.al b/Apps/IN/INTaxBase/app/src/codeunit/CalculateStatistics.Codeunit.al index 35d0188594..9ed59f5463 100644 --- a/Apps/IN/INTaxBase/app/src/codeunit/CalculateStatistics.Codeunit.al +++ b/Apps/IN/INTaxBase/app/src/codeunit/CalculateStatistics.Codeunit.al @@ -37,6 +37,64 @@ codeunit 18547 "Calculate Statistics" TotalInclTaxAmount := RoundInvoicePrecision((TotalInclTaxAmount + GSTAmount - TDSAmount)); end; + procedure GetPartialPurchaseInvStatisticsAmount( + PurchaseHeader: Record "Purchase Header"; + var PartialInclInvTaxAmount: Decimal) + var + PurchaseLine: Record "Purchase Line"; + RecordIDList: List of [RecordID]; + PartialGSTAmount: Decimal; + PartialTDSAmount: Decimal; + begin + Clear(PartialInclInvTaxAmount); + + PurchaseLine.SetLoadFields("Document Type", "Document No.", Quantity, Amount, "Qty. to Invoice"); + PurchaseLine.SetRange("Document Type", PurchaseHeader."Document Type"); + PurchaseLine.SetRange("Document no.", PurchaseHeader."No."); + if PurchaseLine.FindSet() then + repeat + RecordIDList.Add(PurchaseLine.RecordId()); + if PurchaseLine.Quantity <> 0 then + PartialInclInvTaxAmount += (PurchaseLine.Amount * PurchaseLine."Qty. to Invoice" / PurchaseLine.Quantity); + until PurchaseLine.Next() = 0; + + OnGetPartialPurchaseHeaderGSTAmount(PurchaseHeader, PartialGSTAmount); + OnGetPartialPurchaseHeaderTDSAmount(PurchaseHeader, PartialTDSAmount); + + PartialInclInvTaxAmount := RoundInvoicePrecision((PartialInclInvTaxAmount + PartialGSTAmount - PartialTDSAmount)); + end; + + procedure GetPartialPurchaseRcptStatisticsAmount( + PurchaseHeader: Record "Purchase Header"; + var PartialInclRcptTaxAmount: Decimal) + var + PurchaseLine: Record "Purchase Line"; + RecordIDList: List of [RecordID]; + PartialGSTAmount: Decimal; + PartialTDSAmount: Decimal; + begin + Clear(PartialInclRcptTaxAmount); + + PurchaseLine.SetLoadFields("Document Type", "Document No.", Amount, Quantity, "Qty. to Receive", "Return Qty. to Ship"); + PurchaseLine.SetRange("Document Type", PurchaseHeader."Document Type"); + PurchaseLine.SetRange("Document no.", PurchaseHeader."No."); + if PurchaseLine.FindSet() then + repeat + RecordIDList.Add(PurchaseLine.RecordId()); + if PurchaseLine.Quantity <> 0 then + if PurchaseLine."Document Type" = PurchaseLine."Document Type"::Order then + PartialInclRcptTaxAmount += (PurchaseLine.Amount * PurchaseLine."Qty. to Receive" / PurchaseLine.Quantity) + else + if PurchaseLine."Document Type" = PurchaseLine."Document Type"::"Return Order" then + PartialInclRcptTaxAmount += (PurchaseLine.Amount * PurchaseLine."Return Qty. to Ship" / PurchaseLine.Quantity); + until PurchaseLine.Next() = 0; + + OnGetPartialPurchaseRcptGSTAmount(PurchaseHeader, PartialGSTAmount); + OnGetPartialPurchaseRcptTDSAmount(PurchaseHeader, PartialTDSAmount); + + PartialInclRcptTaxAmount := RoundInvoicePrecision((PartialInclRcptTaxAmount + PartialGSTAmount - PartialTDSAmount)); + end; + procedure GetPostedPurchInvStatisticsAmount( PurchInvHeader: Record "Purch. Inv. Header"; var TotalInclTaxAmount: Decimal) @@ -85,7 +143,6 @@ codeunit 18547 "Calculate Statistics" TotalInclTaxAmount := TotalInclTaxAmount + GSTAmount - TDSAmount; end; - procedure GetSalesStatisticsAmount( SalesHeader: Record "Sales Header"; var TotalInclTaxAmount: Decimal) @@ -111,6 +168,64 @@ codeunit 18547 "Calculate Statistics" TotalInclTaxAmount := TotalInclTaxAmount + GSTAmount + TCSAmount; end; + procedure GetPartialSalesInvStatisticsAmount( + SalesHeader: Record "Sales Header"; + var PartialInclInvTaxAmount: Decimal) + var + SalesLine: Record "Sales Line"; + RecordIDList: List of [RecordID]; + PartialGSTAmount: Decimal; + PartialTCSAmount: Decimal; + begin + Clear(PartialInclInvTaxAmount); + + SalesLine.SetLoadFields("Document Type", "Document No.", Amount, Quantity, "Qty. to Invoice"); + SalesLine.SetRange("Document Type", SalesHeader."Document Type"); + SalesLine.SetRange("Document no.", SalesHeader."No."); + if SalesLine.FindSet() then + repeat + RecordIDList.Add(SalesLine.RecordId()); + if SalesLine.Quantity <> 0 then + PartialInclInvTaxAmount += (SalesLine.Amount * SalesLine."Qty. to Invoice" / SalesLine.Quantity); + until SalesLine.Next() = 0; + + OnGetPartialSalesHeaderGSTAmount(SalesHeader, PartialGSTAmount); + OnGetPartialSalesHeaderTCSAmount(SalesHeader, PartialTCSAmount); + + PartialInclInvTaxAmount := PartialInclInvTaxAmount + PartialGSTAmount + PartialTCSAmount; + end; + + procedure GetPartialSalesShptStatisticsAmount( + SalesHeader: Record "Sales Header"; + var PartialInclShptTaxAmount: Decimal) + var + SalesLine: Record "Sales Line"; + RecordIDList: List of [RecordID]; + PartialGSTAmount: Decimal; + PartialTCSAmount: Decimal; + begin + Clear(PartialInclShptTaxAmount); + + SalesLine.SetLoadFields("Document Type", "Document No.", Amount, Quantity, "Qty. to Ship", "Return Qty. to Receive"); + SalesLine.SetRange("Document Type", SalesHeader."Document Type"); + SalesLine.SetRange("Document no.", SalesHeader."No."); + if SalesLine.FindSet() then + repeat + RecordIDList.Add(SalesLine.RecordId()); + if SalesLine.Quantity <> 0 then + if SalesLine."Document Type" = SalesLine."Document Type"::Order then + PartialInclShptTaxAmount += (SalesLine.Amount * SalesLine."Qty. to Ship" / SalesLine.Quantity) + else + if SalesLine."Document Type" = SalesLine."Document Type"::"Return Order" then + PartialInclShptTaxAmount += (SalesLine.Amount * SalesLine."Return Qty. to Receive" / SalesLine.Quantity) + until SalesLine.Next() = 0; + + OnGetPartialSalesShptGSTAmount(SalesHeader, PartialGSTAmount); + OnGetPartialSalesShptTCSAmount(SalesHeader, PartialTCSAmount); + + PartialInclShptTaxAmount := PartialInclShptTaxAmount + PartialGSTAmount + PartialTCSAmount; + end; + procedure GetPostedSalesInvStatisticsAmount( SalesInvHeader: Record "Sales Invoice Header"; var TotalInclTaxAmount: Decimal) @@ -196,6 +311,26 @@ codeunit 18547 "Calculate Statistics" begin end; + [IntegrationEvent(false, false)] + procedure OnGetPartialPurchaseHeaderGSTAmount(PurchaseHeader: Record "Purchase Header"; var PartialGSTAmount: Decimal) + begin + end; + + [IntegrationEvent(false, false)] + procedure OnGetPartialPurchaseHeaderTDSAmount(PurchaseHeader: Record "Purchase Header"; var PartialTDSAmount: Decimal) + begin + end; + + [IntegrationEvent(false, false)] + procedure OnGetPartialPurchaseRcptGSTAmount(PurchaseHeader: Record "Purchase Header"; var PartialGSTAmount: Decimal) + begin + end; + + [IntegrationEvent(false, false)] + procedure OnGetPartialPurchaseRcptTDSAmount(PurchaseHeader: Record "Purchase Header"; var PartialTDSAmount: Decimal) + begin + end; + [IntegrationEvent(false, false)] procedure OnGetPurchInvHeaderGSTAmount(PurchInvHeader: Record "Purch. Inv. Header"; var GSTAmount: Decimal) begin @@ -226,6 +361,26 @@ codeunit 18547 "Calculate Statistics" begin end; + [IntegrationEvent(false, false)] + procedure OnGetPartialSalesHeaderGSTAmount(SalesHeader: Record "Sales Header"; var PartialGSTAmount: Decimal) + begin + end; + + [IntegrationEvent(false, false)] + procedure OnGetPartialSalesHeaderTCSAmount(SalesHeader: Record "Sales Header"; var PartialTCSAmount: Decimal) + begin + end; + + [IntegrationEvent(false, false)] + procedure OnGetPartialSalesShptGSTAmount(SalesHeader: Record "Sales Header"; var PartialGSTAmount: Decimal) + begin + end; + + [IntegrationEvent(false, false)] + procedure OnGetPartialSalesShptTCSAmount(SalesHeader: Record "Sales Header"; var PartialTCSAmount: Decimal) + begin + end; + [IntegrationEvent(false, false)] procedure OnGetSalesInvHeaderGSTAmount(SalesInvHeader: Record "Sales Invoice Header"; var GSTAmount: Decimal) begin diff --git a/Apps/IN/INTaxBase/app/src/pageextension/PurchOrdStatistics.PageExt.al b/Apps/IN/INTaxBase/app/src/pageextension/PurchOrdStatistics.PageExt.al index cff8e616de..dec9208236 100644 --- a/Apps/IN/INTaxBase/app/src/pageextension/PurchOrdStatistics.PageExt.al +++ b/Apps/IN/INTaxBase/app/src/pageextension/PurchOrdStatistics.PageExt.al @@ -20,6 +20,26 @@ pageextension 18567 "Purch. Ord. Statistics" extends "Purchase Order Statistics" Caption = 'Net Total'; } } + addlast(Invoicing) + { + field("Partial Inv. Amount"; PartialInclInvTaxAmount) + { + ApplicationArea = Basic, Suite; + Editable = false; + ToolTip = 'Specifies the amount, including Tax amount. On the Invoicing fast tab, this is the amount posted to the vendor account for all the lines in the purchase order if you post the purchase order as invoiced.'; + Caption = 'Net Total'; + } + } + addlast(Shipping) + { + field("Partial Ship. Amount"; PartialInclRcptTaxAmount) + { + ApplicationArea = Basic, Suite; + Editable = false; + ToolTip = 'Specifies the amount, including Tax amount. On the Shipping fast tab, this is the amount posted to the vendor account for all the lines in the purchase order if you post the purchase order as Shipped.'; + Caption = 'Net Total'; + } + } } trigger OnAfterGetRecord() @@ -32,6 +52,8 @@ pageextension 18567 "Purch. Ord. Statistics" extends "Purchase Order Statistics" CalcStatistics: Codeunit "Calculate Statistics"; begin CalcStatistics.GetPurchaseStatisticsAmount(Rec, TotalInclTaxAmount); + CalcStatistics.GetPartialPurchaseInvStatisticsAmount(Rec, PartialInclInvTaxAmount); + CalcStatistics.GetPartialPurchaseRcptStatisticsAmount(Rec, PartialInclRcptTaxAmount); Calculated := true; end; @@ -43,5 +65,7 @@ pageextension 18567 "Purch. Ord. Statistics" extends "Purchase Order Statistics" var TotalInclTaxAmount: Decimal; + PartialInclRcptTaxAmount: Decimal; + PartialInclInvTaxAmount: Decimal; Calculated: Boolean; } diff --git a/Apps/IN/INTaxBase/app/src/pageextension/SalesOrdStatistics.PageExt.al b/Apps/IN/INTaxBase/app/src/pageextension/SalesOrdStatistics.PageExt.al index 0d56a2761a..b905b0c08d 100644 --- a/Apps/IN/INTaxBase/app/src/pageextension/SalesOrdStatistics.PageExt.al +++ b/Apps/IN/INTaxBase/app/src/pageextension/SalesOrdStatistics.PageExt.al @@ -20,6 +20,26 @@ pageextension 18571 "sales Ord. Statistics" extends "Sales Order Statistics" Caption = 'Net Total'; } } + addlast(Invoicing) + { + field("Partial Inv. Amount"; PartailInclInvTaxAmount) + { + ApplicationArea = Basic, Suite; + Editable = false; + ToolTip = 'Specifies the amount, including Tax amount. On the Invoicing fast tab, this is the amount posted to the customer account for all the lines in the sales order if you post the sales order as invoiced.'; + Caption = 'Net Total'; + } + } + addlast(Shipping) + { + field("Partial Ship. Amount"; PartialInclShptTaxAmount) + { + ApplicationArea = Basic, Suite; + Editable = false; + ToolTip = 'Specifies the amount, including Tax amount. On the General fast tab, this is the amount posted to the customer account for all the lines in the sales order if you post the sales order as Shipped.'; + Caption = 'Net Total'; + } + } } trigger OnAfterGetRecord() @@ -27,8 +47,12 @@ pageextension 18571 "sales Ord. Statistics" extends "Sales Order Statistics" CalcStatistics: Codeunit "Calculate Statistics"; begin CalcStatistics.GetSalesStatisticsAmount(Rec, TotalInclTaxAmount); + CalcStatistics.GetPartialSalesInvStatisticsAmount(Rec, PartailInclInvTaxAmount); + CalcStatistics.GetPartialSalesShptStatisticsAmount(Rec, PartialInclShptTaxAmount); end; var TotalInclTaxAmount: Decimal; + PartailInclInvTaxAmount: Decimal; + PartialInclShptTaxAmount: Decimal; } diff --git a/Apps/IN/INTaxBase/app/src/table/PostingNoSeries.table.al b/Apps/IN/INTaxBase/app/src/table/PostingNoSeries.table.al index 5fae88da2c..432edd4917 100644 --- a/Apps/IN/INTaxBase/app/src/table/PostingNoSeries.table.al +++ b/Apps/IN/INTaxBase/app/src/table/PostingNoSeries.table.al @@ -109,7 +109,7 @@ table 18552 "Posting No. Series" Database::"Service Header": GetServicePostingNoSeries(Record); Database::"Gen. Journal Line": - GetGenJournalpostingSeries(Record); + GetGenJournalPostingSeries(Record); else begin OnGetPostingNoSeries(Record, Handled); if not Handled then @@ -122,7 +122,13 @@ table 18552 "Posting No. Series" var PostingNoSeries: Record "Posting No. Series"; SalesSetup: Record "Sales & Receivables Setup"; +#if CLEAN24 + NoSeries: Codeunit "No. Series"; +#else +#pragma warning disable AL0432 NoSeriesMgt: Codeunit NoSeriesManagement; +#pragma warning restore AL0432 +#endif NoSeriesCode: Code[20]; TableID: Integer; begin @@ -138,36 +144,63 @@ table 18552 "Posting No. Series" if NoSeriesCode <> '' then SalesHeader."Shipping No. Series" := NoSeriesCode else +#if CLEAN24 + if NoSeries.IsAutomatic(SalesSetup."Posted Shipment Nos.") then + SalesHeader."Shipping No. Series" := SalesSetup."Posted Shipment Nos."; +#else +#pragma warning disable AL0432 NoSeriesMgt.SetDefaultSeries(SalesHeader."Shipping No. Series", SalesSetup."Posted Shipment Nos."); +#pragma warning restore AL0432 +#endif NoSeriesCode := LoopPostingNoSeries(TableID, PostingNoSeries, SalesHeader, PostingNoSeries."Document Type"::"Sales Invoice Header"); if NoSeriesCode <> '' then SalesHeader."Posting No. Series" := NoSeriesCode else +#if CLEAN24 + if NoSeries.IsAutomatic(SalesSetup."Posted Invoice Nos.") then + SalesHeader."Posting No. Series" := SalesSetup."Posted Invoice Nos."; +#else +#pragma warning disable AL0432 NoSeriesMgt.SetDefaultSeries(SalesHeader."Posting No. Series", SalesSetup."Posted Invoice Nos."); +#pragma warning restore AL0432 +#endif end; SalesHeader."Document Type"::"Return Order", - SalesHeader."Document Type"::"Credit Memo": + SalesHeader."Document Type"::"Credit Memo": begin NoSeriesCode := LoopPostingNoSeries(TableID, PostingNoSeries, SalesHeader, PostingNoSeries."Document Type"::"Sales Cr.Memo Header"); if NoSeriesCode <> '' then SalesHeader."Posting No. Series" := NoSeriesCode else - NoSeriesMgt.SetDefaultSeries(SalesHeader."Posting No. Series", SalesSetup."Posted Credit Memo Nos."); +#if CLEAN24 + if NoSeries.IsAutomatic(SalesSetup."Posted Credit Memo Nos.") then + SalesHeader."Posting No. Series" := SalesSetup."Posted Credit Memo Nos."; +#else +#pragma warning disable AL0432 + NoSeriesMgt.SetDefaultSeries(SalesHeader."Posting No. Series", SalesSetup."Posted Credit Memo Nos."); +#pragma warning restore AL0432 +#endif NoSeriesCode := LoopPostingNoSeries(TableID, PostingNoSeries, SalesHeader, PostingNoSeries."Document Type"::"Sales Return Receipt No."); if NoSeriesCode <> '' then SalesHeader."Return Receipt No. Series" := NoSeriesCode else if SalesSetup."Return Receipt on Credit Memo" then - NoSeriesMgt.SetDefaultSeries(SalesHeader."Return Receipt No. Series", SalesSetup."Posted Return Receipt Nos."); - +#if CLEAN24 + if NoSeries.IsAutomatic(SalesSetup."Posted Return Receipt Nos.") then + SalesHeader."Return Receipt No. Series" := SalesSetup."Posted Return Receipt Nos."; +#else +#pragma warning disable AL0432 + NoSeriesMgt.SetDefaultSeries(SalesHeader."Return Receipt No. Series", SalesSetup."Posted Return Receipt Nos."); +#pragma warning restore AL0432 +#endif end; end; end; - local procedure GetGenJournalpostingSeries(var GenJournalLine: Record "Gen. Journal Line") + local procedure GetGenJournalPostingSeries(var GenJournalLine: Record "Gen. Journal Line") var PostingNoSeries: Record "Posting No. Series"; NoSeriesCode: Code[20]; @@ -178,14 +211,19 @@ table 18552 "Posting No. Series" if NoSeriesCode <> '' then GenJournalLine."Posting No. Series" := NoSeriesCode; - end; local procedure GetPurchasePostingNoSeries(var PurchaseHeader: Record "Purchase Header") var PostingNoSeries: Record "Posting No. Series"; PurchSetup: Record "Purchases & Payables Setup"; +#if CLEAN24 + NoSeries: Codeunit "No. Series"; +#else +#pragma warning disable AL0432 NoSeriesMgt: Codeunit NoSeriesManagement; +#pragma warning restore AL0432 +#endif NoSeriesCode: Code[20]; TableID: Integer; begin @@ -201,13 +239,26 @@ table 18552 "Posting No. Series" if NoSeriesCode <> '' then PurchaseHeader."Receiving No. Series" := NoSeriesCode else +#if CLEAN24 + if NoSeries.IsAutomatic(PurchSetup."Posted Receipt Nos.") then + PurchaseHeader."Receiving No. Series" := PurchSetup."Posted Receipt Nos."; +#else +#pragma warning disable AL0432 NoSeriesMgt.SetDefaultSeries(PurchaseHeader."Receiving No. Series", PurchSetup."Posted Receipt Nos."); - +#pragma warning restore AL0432 +#endif NoSeriesCode := LoopPostingNoSeries(TableID, PostingNoSeries, PurchaseHeader, PostingNoSeries."Document Type"::"Purch. Inv. Header"); if NoSeriesCode <> '' then PurchaseHeader."Posting No. Series" := NoSeriesCode else +#if CLEAN24 + if NoSeries.IsAutomatic(PurchSetup."Posted Invoice Nos.") then + PurchaseHeader."Posting No. Series" := PurchSetup."Posted Invoice Nos."; +#else +#pragma warning disable AL0432 NoSeriesMgt.SetDefaultSeries(PurchaseHeader."Posting No. Series", PurchSetup."Posted Invoice Nos."); +#pragma warning restore AL0432 +#endif end; PurchaseHeader."Document Type"::"Return Order", @@ -217,14 +268,28 @@ table 18552 "Posting No. Series" if NoSeriesCode <> '' then PurchaseHeader."Posting No. Series" := NoSeriesCode else +#if CLEAN24 + if NoSeries.IsAutomatic(PurchSetup."Posted Credit Memo Nos.") then + PurchaseHeader."Posting No. Series" := PurchSetup."Posted Credit Memo Nos."; +#else +#pragma warning disable AL0432 NoSeriesMgt.SetDefaultSeries(PurchaseHeader."Posting No. Series", PurchSetup."Posted Credit Memo Nos."); +#pragma warning restore AL0432 +#endif NoSeriesCode := LoopPostingNoSeries(TableID, PostingNoSeries, PurchaseHeader, PostingNoSeries."Document Type"::"Purchase Return Shipment No."); if NoSeriesCode <> '' then PurchaseHeader."Return Shipment No. Series" := NoSeriesCode else if PurchSetup."Return Shipment on Credit Memo" then +#if CLEAN24 + if NoSeries.IsAutomatic(PurchSetup."Posted Return Shpt. Nos.") then + PurchaseHeader."Return Shipment No. Series" := PurchSetup."Posted Return Shpt. Nos."; +#else +#pragma warning disable AL0432 NoSeriesMgt.SetDefaultSeries(PurchaseHeader."Return Shipment No. Series", PurchSetup."Posted Return Shpt. Nos."); +#pragma warning restore AL0432 +#endif end; end; end; @@ -233,7 +298,13 @@ table 18552 "Posting No. Series" var PostingNoSeries: Record "Posting No. Series"; ServiceSetup: Record "Service Mgt. Setup"; +#if CLEAN24 + NoSeries: Codeunit "No. Series"; +#else +#pragma warning disable AL0432 NoSeriesMgt: Codeunit NoSeriesManagement; +#pragma warning restore AL0432 +#endif NoSeriesCode: Code[20]; TableID: Integer; begin @@ -248,13 +319,27 @@ table 18552 "Posting No. Series" if NoSeriesCode <> '' then ServiceHeader."Shipping No. Series" := NoSeriesCode else +#if CLEAN24 + if NoSeries.IsAutomatic(ServiceSetup."Posted Service Shipment Nos.") then + ServiceHeader."Shipping No. Series" := ServiceSetup."Posted Service Shipment Nos."; +#else +#pragma warning disable AL0432 NoSeriesMgt.SetDefaultSeries(ServiceHeader."Shipping No. Series", ServiceSetup."Posted Service Shipment Nos."); +#pragma warning restore AL0432 +#endif NoSeriesCode := LoopPostingNoSeries(TableID, PostingNoSeries, ServiceHeader, PostingNoSeries."Document Type"::"Service Invoice Header"); if NoSeriesCode <> '' then ServiceHeader."Posting No. Series" := NoSeriesCode else +#if CLEAN24 + if NoSeries.IsAutomatic(ServiceSetup."Posted Service Invoice Nos.") then + ServiceHeader."Posting No. Series" := ServiceSetup."Posted Service Invoice Nos."; +#else +#pragma warning disable AL0432 NoSeriesMgt.SetDefaultSeries(ServiceHeader."Posting No. Series", ServiceSetup."Posted Service Invoice Nos."); +#pragma warning restore AL0432 +#endif end; ServiceHeader."Document Type"::"Credit Memo": begin @@ -262,7 +347,14 @@ table 18552 "Posting No. Series" if NoSeriesCode <> '' then ServiceHeader."Posting No. Series" := NoSeriesCode else +#if CLEAN24 + if NoSeries.IsAutomatic(ServiceSetup."Posted Serv. Credit Memo Nos.") then + ServiceHeader."Posting No. Series" := ServiceSetup."Posted Serv. Credit Memo Nos."; +#else +#pragma warning disable AL0432 NoSeriesMgt.SetDefaultSeries(ServiceHeader."Posting No. Series", ServiceSetup."Posted Serv. Credit Memo Nos."); +#pragma warning restore AL0432 +#endif end; end; end; diff --git a/Apps/IN/INTaxBase/test/app.json b/Apps/IN/INTaxBase/test/app.json index 3ded714731..d999c3a225 100644 --- a/Apps/IN/INTaxBase/test/app.json +++ b/Apps/IN/INTaxBase/test/app.json @@ -2,7 +2,7 @@ "id": "20cc6140-cbda-4a21-b15d-8f6190fb5469", "name": "India Tax Base Tests", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Tests For India Tax Base Test Publishers", "description": "Contains India Tax Base Test Publishers", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -18,20 +18,20 @@ "id": "d3c551dd-5903-4194-b153-04ced9d29a2c", "publisher": "Microsoft", "name": "India Tax Base", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "c1eafb3f-e397-468e-bdb4-ecc5c317ca00", "publisher": "Microsoft", "name": "Tax Engine", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 18598, diff --git a/Apps/IN/INVoucherInterface/app/app.json b/Apps/IN/INVoucherInterface/app/app.json index 3c78d5bf59..18f7f34461 100644 --- a/Apps/IN/INVoucherInterface/app/app.json +++ b/Apps/IN/INVoucherInterface/app/app.json @@ -2,7 +2,7 @@ "id": "f1d9b696-156b-4251-b542-34e549fa80e9", "name": "India Voucher Interface", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Contains functionality of Voucher Interface", "description": "Voucher Interface provides features that cover business scenarios in India. Voucher Interface is a standard solution for companies that record cash, bank, and journal transactions.", "features": [ @@ -18,20 +18,20 @@ "id": "d3c551dd-5903-4194-b153-04ced9d29a2c", "publisher": "Microsoft", "name": "India Tax Base", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "c1eafb3f-e397-468e-bdb4-ecc5c317ca00", "publisher": "Microsoft", "name": "Tax Engine", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "application": "24.0.0.0", - "platform": "24.0.0.0", + "application": "25.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 18929, diff --git a/Apps/IN/INVoucherInterface/test/app.json b/Apps/IN/INVoucherInterface/test/app.json index ceb20d74ec..1ea14f9e05 100644 --- a/Apps/IN/INVoucherInterface/test/app.json +++ b/Apps/IN/INVoucherInterface/test/app.json @@ -2,7 +2,7 @@ "id": "18759da4-50d8-4a24-84fc-28da8286a877", "name": "India Voucher Interface Tests", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Voucher Interface Test Automation", "description": "This codeunit consits of test function", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -15,50 +15,50 @@ "id": "dd0be2ea-f733-4d65-bb34-a28f4624fb14", "publisher": "Microsoft", "name": "Library Assert", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "publisher": "Microsoft", "name": "Tests-TestLibraries", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5095f467-0a01-4b99-99d1-9ff1237d286f", "publisher": "Microsoft", "name": "Library Variable Storage", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "f1d9b696-156b-4251-b542-34e549fa80e9", "publisher": "Microsoft", "name": "India Voucher Interface", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "d3c551dd-5903-4194-b153-04ced9d29a2c", "publisher": "Microsoft", "name": "India Tax Base", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "c1eafb3f-e397-468e-bdb4-ecc5c317ca00", "publisher": "Microsoft", "name": "Tax Engine", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "20cc6140-cbda-4a21-b15d-8f6190fb5469", "publisher": "Microsoft", "name": "India Tax Base Tests", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 18995, diff --git a/Apps/IN/QRGeneration/app/app.json b/Apps/IN/QRGeneration/app/app.json index a5fcd93874..cc159220ad 100644 --- a/Apps/IN/QRGeneration/app/app.json +++ b/Apps/IN/QRGeneration/app/app.json @@ -2,7 +2,7 @@ "id": "7106d701-c601-4a5f-97c2-b8b323ae2c18", "name": "QR Generator", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Contains feature for QR Code Generation.", "description": "Contains feature for QR Code Generation.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -20,8 +20,8 @@ "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 18650, diff --git a/Apps/IS/ContosoCoffeeDemoDatasetIS/app/app.json b/Apps/IS/ContosoCoffeeDemoDatasetIS/app/app.json index 58bf6b7fff..aa1b104c5c 100644 --- a/Apps/IS/ContosoCoffeeDemoDatasetIS/app/app.json +++ b/Apps/IS/ContosoCoffeeDemoDatasetIS/app/app.json @@ -2,7 +2,7 @@ "id": "5b1c41a1-6b42-4123-a521-2265186cfb31", "name": "Contoso Coffee Demo Dataset (IS)", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "To help partners demonstrate the capabilities of Business Central, we are making new and extensive demo data available for various scenarios.", "description": "Presales specialists can run the tool on top of Cronus or My Company and get the setup and demo data they'll need when they demonstrate various scenarios.", "privacyStatement": "https://go.microsoft.com/fwlink/?linkid=724009", @@ -16,14 +16,14 @@ "id": "5a0b41e9-7a42-4123-d521-2265186cfb31", "name": "Contoso Coffee Demo Dataset", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 14603, diff --git a/Apps/IS/ISCore/app/app.json b/Apps/IS/ISCore/app/app.json index 8fe81d9335..6f4cb08ec5 100644 --- a/Apps/IS/ISCore/app/app.json +++ b/Apps/IS/ISCore/app/app.json @@ -2,7 +2,7 @@ "id": "cd6afb88-73aa-406f-a087-50a6149d5779", "name": "IS Core", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Provides standard local functionality in Business Central for Iceland.", "description": "Provides standard local functionality in Business Central for Iceland.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -17,8 +17,8 @@ "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 14600, diff --git a/Apps/IS/ISCore/app/src/Codeunits/EnableISCoreApp.Codeunit.al b/Apps/IS/ISCore/app/src/Codeunits/EnableISCoreApp.Codeunit.al index 3b8f7cf767..f8b75581c5 100644 --- a/Apps/IS/ISCore/app/src/Codeunits/EnableISCoreApp.Codeunit.al +++ b/Apps/IS/ISCore/app/src/Codeunits/EnableISCoreApp.Codeunit.al @@ -54,6 +54,8 @@ codeunit 14611 "Enable IS Core App" Clear(SourceField); SourceField.SetRange(TableNo, SourceTableId); SourceField.SetRange(Class, SourceField.Class::Normal); + SourceField.SetFilter(ObsoleteState, '<>%1', SourceField.ObsoleteState::Removed); + SourceField.SetFilter(SourceField."No.", '<%1', 14620); // do not copy table extenison. 14620 is max field number for this app. SourceField.SetRange(Enabled, true); if SourceField.Findset() then repeat diff --git a/Apps/IS/ISCore/app/src/Codeunits/ISCore.Codeunit.al b/Apps/IS/ISCore/app/src/Codeunits/ISCore.Codeunit.al index 42aa3a46d5..8c6901470c 100644 --- a/Apps/IS/ISCore/app/src/Codeunits/ISCore.Codeunit.al +++ b/Apps/IS/ISCore/app/src/Codeunits/ISCore.Codeunit.al @@ -5,9 +5,17 @@ // ------------------------------------------------------------------------------------------------ namespace Microsoft.Finance; +using Microsoft.Bank.Payment; using Microsoft.Finance.GeneralLedger.IRS; +using Microsoft.Finance.GeneralLedger.Journal; +using Microsoft.Finance.GeneralLedger.Setup; +using Microsoft.Purchases.Payables; +using Microsoft.Purchases.Vendor; +using Microsoft.Sales.Customer; +using Microsoft.Sales.Receivables; using Microsoft.Sales.Setup; using Microsoft.Utilities; +using System.IO; codeunit 14600 "IS Core" { @@ -23,7 +31,7 @@ codeunit 14600 "IS Core" #if not CLEAN24 [Obsolete('The table used to enable IS Core App.', '24.0')] - [EventSubscriber(ObjectType::Table, Database::"IS Core App Setup", 'OnAfterValidateEvent', 'Enabled', false, false)] + [EventSubscriber(ObjectType::Table, Database::"IS Core App Setup", OnAfterValidateEvent, Enabled, false, false)] local procedure OnAfterValidateEnabledISCoreApp(var Rec: Record "IS Core App Setup") begin if Rec.Enabled then @@ -31,7 +39,7 @@ codeunit 14600 "IS Core" end; #endif - [EventSubscriber(ObjectType::Table, Database::"Sales & Receivables Setup", 'OnAfterValidateEvent', 'Electronic Invoicing Reminder', false, false)] + [EventSubscriber(ObjectType::Table, Database::"Sales & Receivables Setup", OnAfterValidateEvent, "Electronic Invoicing Reminder", false, false)] local procedure OnAfterValidateElectronicInvoicing(var Rec: Record "Sales & Receivables Setup") var #if not CLEAN24 @@ -50,6 +58,52 @@ codeunit 14600 "IS Core" #endif end; + [EventSubscriber(ObjectType::Codeunit, Codeunit::"Pmt Export Mgt Cust Ledg Entry", OnPreparePaymentExportDataCLEOnBeforeTempPaymentExportDataInsert, '', false, false)] + local procedure OnPreparePaymentExportDataCLEOnBeforeTempPaymentExportDataInsert(var TempPaymentExportData: Record "Payment Export Data" temporary; CustLedgerEntry: Record "Cust. Ledger Entry"; GeneralLedgerSetup: Record "General Ledger Setup") + var + Customer: Record Customer; + begin + if CustLedgerEntry."Customer No." = '' then + exit; + Customer.Get(CustLedgerEntry."Customer No."); + TempPaymentExportData."Recipient Reg. No." := CopyStr(Customer."Registration Number", 1, MaxStrLen(TempPaymentExportData."Recipient Reg. No.")); + end; + + [EventSubscriber(ObjectType::Codeunit, Codeunit::"Pmt Export Mgt Gen. Jnl Line", OnBeforeInsertPmtExportDataJnlFromGenJnlLine, '', false, false)] + local procedure OnBeforeInsertPmtExportDataJnlFromGenJnlLine(var PaymentExportData: Record "Payment Export Data"; GenJournalLine: Record "Gen. Journal Line"; GeneralLedgerSetup: Record "General Ledger Setup") + begin + UpdateRegistrationNoFromGenJournalLine(PaymentExportData, GenJournalLine); + end; + + [EventSubscriber(ObjectType::Codeunit, Codeunit::"Pmt Export Mgt Vend Ledg Entry", OnBeforeInsertPmtExportDataJnlFromVendorLedgerEntry, '', false, false)] + local procedure OnBeforeInsertPmtExportDataJnlFromVendorLedgerEntry(var PaymentExportData: Record "Payment Export Data"; VendorLedgerEntry: Record "Vendor Ledger Entry"; GeneralLedgerSetup: Record "General Ledger Setup") + var + Vendor: Record Vendor; + begin + if VendorLedgerEntry."Vendor No." = '' then + exit; + Vendor.Get(VendorLedgerEntry."Vendor No."); + PaymentExportData."Recipient Reg. No." := CopyStr(Vendor."Registration Number", 1, MaxStrLen(PaymentExportData."Recipient Reg. No.")); + end; + + [EventSubscriber(ObjectType::Codeunit, Codeunit::"Exp. Pre-Mapping Gen. Jnl.", OnBeforeInsertPaymentExoprtData, '', false, false)] + local procedure OnBeforeInsertPaymentExoprtData(var PaymentExportData: Record "Payment Export Data"; GenJournalLine: Record "Gen. Journal Line"; GeneralLedgerSetup: Record "General Ledger Setup") + begin + UpdateRegistrationNoFromGenJournalLine(PaymentExportData, GenJournalLine); + end; + + local procedure UpdateRegistrationNoFromGenJournalLine(var PaymentExportData: Record "Payment Export Data"; GenJournalLine: Record "Gen. Journal Line") + var + Vendor: Record Vendor; + begin + if GenJournalLine."Account Type" = GenJournalLine."Account Type"::Employee then + exit; + if GenJournalLine."Account Type" = GenJournalLine."Account Type"::Vendor then begin + Vendor.Get(GenJournalLine."Account No."); + PaymentExportData."Recipient Reg. No." := CopyStr(Vendor."Registration Number", 1, MaxStrLen(PaymentExportData."Recipient Reg. No.")); + end; + end; + local procedure ClassifyTablesToNormal() var DataClassificationEvalData: Codeunit "Data Classification Eval. Data"; diff --git a/Apps/IS/ISCore/app/src/PageExtensions/ISPostedPurchCreditMemo.PageExt.al b/Apps/IS/ISCore/app/src/PageExtensions/ISPostedPurchCreditMemo.PageExt.al new file mode 100644 index 0000000000..5e6a2061ac --- /dev/null +++ b/Apps/IS/ISCore/app/src/PageExtensions/ISPostedPurchCreditMemo.PageExt.al @@ -0,0 +1,6 @@ +pageextension 14604 "IS Posted Purch. Credit Memo" extends "Posted Purchase Credit Memo" +{ + trigger OnDeleteRecord(): Boolean + begin + end; +} diff --git a/Apps/IS/ISCore/app/src/PageExtensions/ISPostedPurchaseInvoice.PageExt.al b/Apps/IS/ISCore/app/src/PageExtensions/ISPostedPurchaseInvoice.PageExt.al new file mode 100644 index 0000000000..a3b33d295d --- /dev/null +++ b/Apps/IS/ISCore/app/src/PageExtensions/ISPostedPurchaseInvoice.PageExt.al @@ -0,0 +1,7 @@ +pageextension 14609 "IS Posted Purchase Invoice" extends "Posted Purchase Invoice" +{ + trigger OnDeleteRecord(): Boolean; + begin + + end; +} \ No newline at end of file diff --git a/Apps/IS/ISCore/test/app.json b/Apps/IS/ISCore/test/app.json index 129895395e..64e23941b2 100644 --- a/Apps/IS/ISCore/test/app.json +++ b/Apps/IS/ISCore/test/app.json @@ -2,7 +2,7 @@ "id": "9dcd1f88-b0a7-4d33-8989-794fa890effd", "name": "IS Core Tests", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Tests for the Core Localization for Iceland.", "description": "Tests for the Core Localization for Iceland.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -16,26 +16,26 @@ "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "cd6afb88-73aa-406f-a087-50a6149d5779", "name": "IS Core", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { - "id": "5095f467-0a01-4b99-99d1-9ff1237d286f", - "publisher": "Microsoft", - "name": "Library Variable Storage", - "version": "24.0.0.0" - } + "id": "5095f467-0a01-4b99-99d1-9ff1237d286f", + "publisher": "Microsoft", + "name": "Library Variable Storage", + "version": "25.0.0.0" + } ], "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 139500, diff --git a/Apps/IT/ContosoCoffeeDemoDatasetIT/app/app.json b/Apps/IT/ContosoCoffeeDemoDatasetIT/app/app.json index ed7d098d89..3f2f00dafc 100644 --- a/Apps/IT/ContosoCoffeeDemoDatasetIT/app/app.json +++ b/Apps/IT/ContosoCoffeeDemoDatasetIT/app/app.json @@ -2,7 +2,7 @@ "id": "5b0a41a1-7b42-4123-a622-2265186cfb35", "name": "Contoso Coffee Demo Dataset (IT)", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "To help partners demonstrate the capabilities of Business Central, we are making new and extensive demo data available for various scenarios.", "description": "Presales specialists can run the tool on top of Cronus or My Company and get the setup and demo data they'll need when they demonstrate various scenarios.", "privacyStatement": "https://go.microsoft.com/fwlink/?linkid=724009", @@ -16,14 +16,14 @@ "id": "5a0b41e9-7a42-4123-d521-2265186cfb31", "name": "Contoso Coffee Demo Dataset", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 12164, diff --git a/Apps/IT/HybridBCLast_IT/app/app.json b/Apps/IT/HybridBCLast_IT/app/app.json index bbe34d9572..b475fd4107 100644 --- a/Apps/IT/HybridBCLast_IT/app/app.json +++ b/Apps/IT/HybridBCLast_IT/app/app.json @@ -2,7 +2,7 @@ "id": "cda9f5b2-070e-4cb6-a69a-a6fa6734899a", "name": "Business Central Cloud Migration - Previous Release (IT)", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Enables data migration from the previous version of Dynamics BC (n-1) to the current release of Dynamics 365 Business Central SaaS.", "description": "This extension, in conjuction with the Business Central Cloud Migration Previous Release, will enable you to migrate data from your Business Central on-premises solution for Italy to your Dynamics 365 Business Central cloud tenant for Belgium. This extension is required to update country specific tables. Once you have walked through the cloud migration wizard in assisted setup, you will be able to migrate your data from your on-premises environment to your cloud tenant.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -15,25 +15,25 @@ { "publisher": "Microsoft", "name": "Intelligent Cloud Base", - "version": "24.0.0.0", + "version": "25.0.0.0", "id": "58623bfa-0559-4bc2-ae1c-0979c29fd9e0" }, { "publisher": "Microsoft", "name": "Business Central Cloud Migration - Previous Release", - "version": "24.0.0.0", + "version": "25.0.0.0", "id": "6992416f-3f39-4d3c-8242-3fff61350bea" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "resourceExposurePolicy": { "allowDebugging": false, "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, "target": "OnPrem", - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/IT/IntrastatIT/app/app.json b/Apps/IT/IntrastatIT/app/app.json index 0f77c459f9..57ea383746 100644 --- a/Apps/IT/IntrastatIT/app/app.json +++ b/Apps/IT/IntrastatIT/app/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "The Intrastat extension makes it easy to export the Intrastat report in the format that the Italian authorities require.", "description": "The Intrastat extension makes it easy to export the Intrastat report in the format that the Italian authorities require.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=2212316", @@ -16,7 +16,7 @@ "id": "70912191-3c4c-49fc-a1de-bc6ea1ac9da6", "name": "Intrastat Core", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "internalsVisibleTo": [ @@ -29,7 +29,7 @@ "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 148121, @@ -41,6 +41,6 @@ "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0", + "application": "25.0.0.0", "target": "Cloud" } \ No newline at end of file diff --git a/Apps/IT/IntrastatIT/test/app.json b/Apps/IT/IntrastatIT/test/app.json index b7e2389293..d9348cab75 100644 --- a/Apps/IT/IntrastatIT/test/app.json +++ b/Apps/IT/IntrastatIT/test/app.json @@ -2,7 +2,7 @@ "id": "317f400e-a546-4684-9327-c9d453034c3e", "name": "Intrastat IT Tests", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Tests for the Microsoft Intrastat IT extension.", "description": "Tests for the Microsoft Intrastat IT extension.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -10,38 +10,38 @@ "help": "https://go.microsoft.com/fwlink/?linkid=2179727", "url": "https://go.microsoft.com/fwlink/?LinkId=724011", "logo": "ExtensionLogo.png", - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "dependencies": [ { "id": "903af4a6-9956-45f7-a795-23cfab1abf55", "name": "Intrastat IT", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "70912191-3c4c-49fc-a1de-bc6ea1ac9da6", "name": "Intrastat Core", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "9856ae4f-d1a7-46ef-89bb-6ef056398228", "name": "System Application Test Library", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5095f467-0a01-4b99-99d1-9ff1237d286f", "publisher": "Microsoft", "name": "Library Variable Storage", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "idRanges": [ diff --git a/Apps/IT/IntrastatIT/test/src/LibraryITIntrastat.Codeunit.al b/Apps/IT/IntrastatIT/test/src/LibraryITIntrastat.Codeunit.al index abadf72985..fd0b1efa3d 100644 --- a/Apps/IT/IntrastatIT/test/src/LibraryITIntrastat.Codeunit.al +++ b/Apps/IT/IntrastatIT/test/src/LibraryITIntrastat.Codeunit.al @@ -662,11 +662,11 @@ codeunit 139512 "Library - IT Intrastat" var IntrastatReportSetup: Record "Intrastat Report Setup"; NoSeries: Record "No. Series"; - NoSeriesManagement: Codeunit NoSeriesManagement; + NoSeriesCodeunit: Codeunit "No. Series"; begin NoSeries.SetFilter(NoSeries.Code, IntrastatReportSetup."Intrastat Nos."); NoSeries.FindFirst(); - NoSeriesCode := NoSeriesManagement.GetNextNo(NoSeries.Code, WorkDate(), true); + NoSeriesCode := NoSeriesCodeunit.GetNextNo(NoSeries.Code); end; procedure GetStatisticalPeriod(ReportDate: Date): code[20] diff --git a/Apps/IT/ServiceDeclarationIT/app/app.json b/Apps/IT/ServiceDeclarationIT/app/app.json index e8951961c3..ede1ea5fe2 100644 --- a/Apps/IT/ServiceDeclarationIT/app/app.json +++ b/Apps/IT/ServiceDeclarationIT/app/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "The Service Declaration extension makes it easy to export the service declaration in the format that the authorities in your country require.", "description": "In some EU countries, authorities require reporting for exporting services to the other EU countries. This feature enables collecting EU service''s intertrade and its reporting to the authorities. Even this feature is primarily created for Belgian, French and Italian markets, it can be used in all EU countries if needed as reporting is configurable.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://learn.microsoft.com/en-us/dynamics365/business-central/finance-how-setup-use-service-declaration", @@ -16,7 +16,7 @@ "id": "e2ae191d-8829-44c3-a373-3749a2742d4d", "name": "Service Declaration", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "internalsVisibleTo": [ @@ -29,7 +29,7 @@ "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 12214, @@ -41,6 +41,6 @@ "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0", + "application": "25.0.0.0", "target": "Cloud" } \ No newline at end of file diff --git a/Apps/IT/ServiceDeclarationIT/test/app.json b/Apps/IT/ServiceDeclarationIT/test/app.json index 5b8878a8aa..ca82cce7aa 100644 --- a/Apps/IT/ServiceDeclarationIT/test/app.json +++ b/Apps/IT/ServiceDeclarationIT/test/app.json @@ -2,7 +2,7 @@ "id": "7fbfa99a-6ec6-402c-ac7b-a41bc035b1e4", "name": "Service Declaration IT Tests", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Tests for the Microsoft Service Declaration IT extension.", "description": "Tests for the Microsoft Service Declaration IT extension.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -10,38 +10,38 @@ "help": "https://learn.microsoft.com/en-us/dynamics365/business-central/finance-how-setup-use-service-declaration", "url": "https://go.microsoft.com/fwlink/?LinkId=724011", "logo": "ExtensionLogo.png", - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "dependencies": [ { "id": "e2ae191d-8829-44c3-a373-3749a2742d4d", "name": "Service Declaration", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "ed85bbd8-074d-4541-9651-e3eb86e1390f", "name": "Service Declaration IT", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "9856ae4f-d1a7-46ef-89bb-6ef056398228", "name": "System Application Test Library", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5095f467-0a01-4b99-99d1-9ff1237d286f", "publisher": "Microsoft", "name": "Library Variable Storage", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "idRanges": [ diff --git a/Apps/IT/ServiceDeclarationIT/test/src/LibraryITServDeclaration.Codeunit.al b/Apps/IT/ServiceDeclarationIT/test/src/LibraryITServDeclaration.Codeunit.al index 44355e4275..29a9d3b359 100644 --- a/Apps/IT/ServiceDeclarationIT/test/src/LibraryITServDeclaration.Codeunit.al +++ b/Apps/IT/ServiceDeclarationIT/test/src/LibraryITServDeclaration.Codeunit.al @@ -275,12 +275,12 @@ codeunit 144109 "Library - IT Serv. Declaration" var ServDeclSetup: Record "Service Declaration Setup"; NoSeries: Record "No. Series"; - NoSeriesManagement: Codeunit NoSeriesManagement; + NoSeriesCodeunit: Codeunit "No. Series"; begin ServDeclSetup.Get(); NoSeries.SetFilter(NoSeries.Code, ServDeclSetup."Declaration No. Series"); NoSeries.FindFirst(); - NoSeriesCode := NoSeriesManagement.GetNextNo(NoSeries.Code, WorkDate(), true); + NoSeriesCode := NoSeriesCodeunit.GetNextNo(NoSeries.Code); end; procedure GetStatisticalPeriod(ReportDate: Date): Code[20] diff --git a/Apps/MX/ContosoCoffeeDemoDatasetMX/app/app.json b/Apps/MX/ContosoCoffeeDemoDatasetMX/app/app.json index 747ab458ec..af2d32b456 100644 --- a/Apps/MX/ContosoCoffeeDemoDatasetMX/app/app.json +++ b/Apps/MX/ContosoCoffeeDemoDatasetMX/app/app.json @@ -2,7 +2,7 @@ "id": "5b0a41b5-7b42-4123-a521-2265186cfb31", "name": "Contoso Coffee Demo Dataset (MX)", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "To help partners demonstrate the capabilities of Business Central, we are making new and extensive demo data available for various scenarios.", "description": "Presales specialists can run the tool on top of Cronus or My Company and get the setup and demo data they'll need when they demonstrate various scenarios.", "privacyStatement": "https://go.microsoft.com/fwlink/?linkid=724009", @@ -16,14 +16,14 @@ "id": "5a0b41e9-7a42-4123-d521-2265186cfb31", "name": "Contoso Coffee Demo Dataset", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 14095, diff --git a/Apps/MX/HybridBCLast_MX/app/app.json b/Apps/MX/HybridBCLast_MX/app/app.json index 7a14563195..efca6c0ec3 100644 --- a/Apps/MX/HybridBCLast_MX/app/app.json +++ b/Apps/MX/HybridBCLast_MX/app/app.json @@ -2,7 +2,7 @@ "id": "15bd700a-b286-4c80-bd56-c31dc352a860", "name": "Business Central Cloud Migration - Previous Release (MX)", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Enables data migration from the previous version of Dynamics BC (n-1) to the current release of Dynamics 365 Business Central SaaS.", "description": "This extension, in conjuction with the Business Central Cloud Migration Previous Release, will enable you to migrate data from your Business Central on-premises solution for Mexico to your Dynamics 365 Business Central cloud tenant for Mexico. This extension is required to update country specific tables. Once you have walked through the cloud migration wizard in assisted setup, you will be able to migrate your data from your on-premises environment to your cloud tenant.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -15,25 +15,25 @@ { "publisher": "Microsoft", "name": "Intelligent Cloud Base", - "version": "24.0.0.0", + "version": "25.0.0.0", "id": "58623bfa-0559-4bc2-ae1c-0979c29fd9e0" }, { "publisher": "Microsoft", "name": "Business Central Cloud Migration - Previous Release", - "version": "24.0.0.0", + "version": "25.0.0.0", "id": "6992416f-3f39-4d3c-8242-3fff61350bea" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "resourceExposurePolicy": { "allowDebugging": false, "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, "target": "OnPrem", - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/NA/Ceridian/app.json b/Apps/NA/Ceridian/app.json index 44843ca662..809c757107 100644 --- a/Apps/NA/Ceridian/app.json +++ b/Apps/NA/Ceridian/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "The Ceridian Payroll functionality allows you to import payroll transactions from Ceridian HR/Payroll (US) and Ceridian Powerpay (Canada).", "description": "The Ceridian Payroll functionality allows you to import payroll transactions from Ceridian HR/Payroll (US) and Ceridian Powerpay (Canada).", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?LinkId=829784", @@ -17,12 +17,12 @@ "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "target": "OnPrem", "resourceExposurePolicy": { "allowDebugging": false, "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/NA/EnvestnetYodleeBankFeeds/app/app.json b/Apps/NA/EnvestnetYodleeBankFeeds/app/app.json index 836d1683e9..147569db36 100644 --- a/Apps/NA/EnvestnetYodleeBankFeeds/app/app.json +++ b/Apps/NA/EnvestnetYodleeBankFeeds/app/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "Envestnet Yodlee Bank Feeds enables you to process payments and reconcile bank accounts faster and safer.", "description": "To quickly reconcile payments made to your bank accounts, Envestnet Yodlee Bank Feeds extension (a third-party service) allows you to link your system bank account to your online bank account. This means that the latest bank statement is automatically or manually fed into your reconciliation journal, ensuring that you are always processing the latest payments with minimal risk of errors. The Envestnet Yodlee Bank Feeds extension provides the following benefits for Dynamics 365 Business Central: • Removes the need for manual entry • Improves efficiency and accuracy when doing payment reconciliation • Supports a large number of banks • Allows up-to-date information about bank transactions • Supports manual as well as automatic bank feeds • Enables outsourcing of payment reconciliation to an accountant by providing access to bank statements.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?LinkId=733362", @@ -12,16 +12,17 @@ "contextSensitiveHelpUrl": "https://go.microsoft.com/fwlink/?LinkId=733362", "logo": "ExtensionLogo.png", "dependencies": [ + ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "target": "OnPrem", "resourceExposurePolicy": { "allowDebugging": false, "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/NA/EnvestnetYodleeBankFeeds/app/src/MSYodleeBankServiceSetup.Table.al b/Apps/NA/EnvestnetYodleeBankFeeds/app/src/MSYodleeBankServiceSetup.Table.al index aa07f4022e..1ca0698d82 100644 --- a/Apps/NA/EnvestnetYodleeBankFeeds/app/src/MSYodleeBankServiceSetup.Table.al +++ b/Apps/NA/EnvestnetYodleeBankFeeds/app/src/MSYodleeBankServiceSetup.Table.al @@ -420,6 +420,7 @@ table 1450 "MS - Yodlee Bank Service Setup" CheckEncryption(); end; + [NonDebuggable] [Scope('OnPrem')] procedure SaveConsumerPassword(var ConsumerPasswordKey: Guid; ConsumerPasswordValue: Text); begin diff --git a/Apps/NA/EnvestnetYodleeBankFeeds/app/src/MSYodleeServiceMgt.Codeunit.al b/Apps/NA/EnvestnetYodleeBankFeeds/app/src/MSYodleeServiceMgt.Codeunit.al index 68266e848a..94d7804d5c 100644 --- a/Apps/NA/EnvestnetYodleeBankFeeds/app/src/MSYodleeServiceMgt.Codeunit.al +++ b/Apps/NA/EnvestnetYodleeBankFeeds/app/src/MSYodleeServiceMgt.Codeunit.al @@ -228,7 +228,7 @@ codeunit 1450 "MS - Yodlee Service Mgt." ConsumerTokenExpired: Boolean; CobrandTokenLastDateUpdated: DateTime; ConsumerTokenLastDateUpdated: DateTime; - ConsumerPassword: Text; + ConsumerPassword: SecretText; Failure: Boolean; Disabled: Boolean; begin @@ -254,7 +254,7 @@ codeunit 1450 "MS - Yodlee Service Mgt." ConsumerPassword := GetConsumerPassword(); if not Failure then - if (MSYodleeBankServiceSetup."Consumer Name" = '') and (ConsumerPassword = '') then + if (MSYodleeBankServiceSetup."Consumer Name" = '') and (ConsumerPassword.IsEmpty()) then if MSYodleeBankServiceSetup.Enabled then begin // if service is enabled we should create consumer ConsumerTokenExpired := true; OnConsumerUninitializedSendTelemetry(); @@ -558,6 +558,10 @@ codeunit 1450 "MS - Yodlee Service Mgt." exit(true); end; +#if not CLEAN24 +#pragma warning disable AL0432 + [NonDebuggable] + [Obsolete('Use RegisterConsumer with SecretText data type for Password parameter.', '24.0')] procedure RegisterConsumer(var Username: Text[250]; var Password: Text; var ErrorText: Text; CobrandToken: Text): Boolean; var MSYodleeBankServiceSetup: Record "MS - Yodlee Bank Service Setup"; @@ -611,6 +615,63 @@ codeunit 1450 "MS - Yodlee Service Mgt." StoreConsumerName(MSYodleeBankServiceSetup."Consumer Name"); exit(true); end; +#pragma warning restore AL0432 +#endif + + [NonDebuggable] + procedure RegisterConsumer(var Username: Text[250]; var Password: SecretText; var ErrorText: Text; CobrandToken: Text): Boolean; + var + MSYodleeBankServiceSetup: Record "MS - Yodlee Bank Service Setup"; + GeneralLedgerSetup: Record "General Ledger Setup"; + PasswordHelper: Codeunit "Password Helper"; + Response: Text; + LcyCode: Text; + Email: Text; + AuthorizationHeaderValue: Text; + AlphanumericCharsTxt: Text; + begin + AlphanumericCharsTxt := 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + CheckServiceEnabled(); + Username := DelChr(CompanyName(), '=', DelChr(CompanyName(), '=', AlphanumericCharsTxt)) + '_' + FORMAT(CREATEGUID()); + + GeneralLedgerSetup.GET(); + GeneralLedgerSetup.TESTFIELD("LCY Code"); + LcyCode := GeneralLedgerSetup."LCY Code"; + + MSYodleeBankServiceSetup.GET(); + Email := MSYodleeBankServiceSetup."User Profile Email Address"; + Password := COPYSTR(PasswordHelper.GenerateSecretPassword(50).Unwrap(), 1, 50); + + AuthorizationHeaderValue := YodleeAPIStrings.GetAuthorizationHeaderValue(CobrandToken, ''); + Session.LogMessage('0000DL9', StrSubstNo(StartingToRegisterUserTxt, UserName, LcyCode), Verbosity::Normal, DataClassification::CustomerContent, TelemetryScope::ExtensionPublisher, 'Category', YodleeTelemetryCategoryTok); + ExecuteWebServiceRequest(YodleeAPIStrings.GetRegisterConsumerURL(), 'POST', + YodleeAPIStrings.GetRegisterConsumerBody(CobrandToken, UserName, Password, Email, LcyCode), AuthorizationHeaderValue, + ErrorText); + + if not GetResponseValue('/', Response, ErrorText) then begin + ErrorText := GetAdjustedErrorText(ErrorText, FailedRegisterConsumerTxt); + if IsStaleCredentialsErr(ErrorText) then begin + ErrorText := StaleCredentialsErr; + LogActivityFailed(RegisterConsumerTxt, ErrorText, FailureAction::RethrowError, '', StrSubstNo(TelemetryActivityFailureTxt, RegisterConsumerTxt, ErrorText), Verbosity::Warning); + exit(false); + end; + if ErrorText.Contains(BankStmtServiceStaleIllegalArgumentValueExceptionTxt) then begin + ErrorText := RegisterConsumerVerifyLCYCodeTxt; + LogActivityFailed(RegisterConsumerTxt, ErrorText, FailureAction::RethrowError, '', StrSubstNo(TelemetryActivityFailureTxt, RegisterConsumerTxt, ErrorText), Verbosity::Warning); + end else + LogActivityFailed(RegisterConsumerTxt, ErrorText, FailureAction::RethrowError, '', StrSubstNo(TelemetryActivityFailureTxt, RegisterConsumerTxt, ErrorText), Verbosity::Error); + + exit(false); + end; + + LogActivitySucceed(RegisterConsumerTxt, SuccessRegisterConsumerTxt, StrSubstNo(TelemetryActivitySuccessTxt, RegisterConsumerTxt, SuccessRegisterConsumerTxt)); + + MSYodleeBankServiceSetup.VALIDATE("Consumer Name", COPYSTR(Username, 1, MAXSTRLEN(MSYodleeBankServiceSetup."Consumer Name"))); + MSYodleeBankServiceSetup.SaveConsumerPassword(MSYodleeBankServiceSetup."Consumer Password", Password.Unwrap()); + MSYodleeBankServiceSetup.MODIFY(true); + StoreConsumerName(MSYodleeBankServiceSetup."Consumer Name"); + exit(true); + end; local procedure TryGetLinkedSites(var SiteListXML: Text; CobrandToken: Text; ConsumerToken: Text): Boolean; var @@ -1494,6 +1555,7 @@ codeunit 1450 "MS - Yodlee Service Mgt." exit(URL.ToLower().Contains('transactions')); end; + [NonDebuggable] local procedure ExecuteWebServiceRequest(URL: Text; Method: Text[6]; BodyText: Text; AuthorizationHeaderValue: Text; var ErrorText: Text) PaginationLink: Text var MSYodleeBankServiceSetup: Record "MS - Yodlee Bank Service Setup"; diff --git a/Apps/NA/EnvestnetYodleeBankFeeds/app/src/PasswordHelper.Codeunit.al b/Apps/NA/EnvestnetYodleeBankFeeds/app/src/PasswordHelper.Codeunit.al index f898c978ed..1ef2e3230d 100644 --- a/Apps/NA/EnvestnetYodleeBankFeeds/app/src/PasswordHelper.Codeunit.al +++ b/Apps/NA/EnvestnetYodleeBankFeeds/app/src/PasswordHelper.Codeunit.al @@ -5,6 +5,9 @@ using System.Security.AccessControl; codeunit 1267 "Password Helper" { +#if not CLEAN24 + [NonDebuggable] + [Obsolete('Use GenerateSecretPassword with SecretText return type.', '24.0')] procedure GeneratePassword(Length: Integer): Text; var Regex: Codeunit "Regex"; @@ -12,20 +15,50 @@ codeunit 1267 "Password Helper" Result: Text; begin Regex.Regex('[\[\]\{\}\(\)\+\-&%\.\^;,:\|=\\\/\?''"`\~><_]'); - Result := Regex.Replace(PasswordHandler.GeneratePassword(Length), ''); + Result := Regex.Replace(PasswordHandler.GenerateSecretPassword(Length).Unwrap(), ''); while WeakYodleePassword(Result) do - Result := Regex.Replace(PasswordHandler.GeneratePassword(Length), ''); + Result := Regex.Replace(PasswordHandler.GenerateSecretPassword(Length).Unwrap(), ''); exit(Result); end; +#endif + [NonDebuggable] + procedure GenerateSecretPassword(Length: Integer): SecretText; + var + Regex: Codeunit "Regex"; + PasswordHandler: Codeunit "Password Handler"; + Result: Text; + begin + Regex.Regex('[\[\]\{\}\(\)\+\-&%\.\^;,:\|=\\\/\?''"`\~><_]'); + Result := Regex.Replace(PasswordHandler.GenerateSecretPassword(Length).Unwrap(), ''); + while WeakYodleePassword(Result) do + Result := Regex.Replace(PasswordHandler.GenerateSecretPassword(Length).Unwrap(), ''); + exit(Result); + end; + +#if not CLEAN24 + [NonDebuggable] + [Obsolete('Use WeakYodleePassword with SecretText data type for Password parameter.', '24.0')] procedure WeakYodleePassword(Password: Text): Boolean + var + Pass: SecretText; + begin + Pass := Password; + exit(WeakYodleePassword(Pass)); + end; +#endif + + [NonDebuggable] + procedure WeakYodleePassword(Pass: SecretText): Boolean var CurrentChar: Char; ReferenceChar: Char; i: Integer; CurrentSequenceLength: Integer; Length: Integer; + Password: Text; begin + Password := Pass.Unwrap(); if Password = DelChr(Password, '=', '!@#$*') then exit(true); diff --git a/Apps/NA/EnvestnetYodleeBankFeeds/app/src/YodleeAPIStrings.Codeunit.al b/Apps/NA/EnvestnetYodleeBankFeeds/app/src/YodleeAPIStrings.Codeunit.al index 99ba19f3f4..f305ae703a 100644 --- a/Apps/NA/EnvestnetYodleeBankFeeds/app/src/YodleeAPIStrings.Codeunit.al +++ b/Apps/NA/EnvestnetYodleeBankFeeds/app/src/YodleeAPIStrings.Codeunit.al @@ -69,7 +69,9 @@ codeunit 1458 "Yodlee API Strings" exit(GetFullURL('/user/register')); end; +#if not CLEAN24 [Scope('OnPrem')] + [Obsolete('Replaced by GetRegisterConsumerBody with SecretText data type for UserPassword parameter')] procedure GetRegisterConsumerBody(CobrandToken: Text; UserName: Text; UserPassword: Text; UserEmail: Text; UserCurrency: Text): Text; var GetRegisterConsumerRequestBodyJsonObject: JsonObject; @@ -86,6 +88,26 @@ codeunit 1458 "Yodlee API Strings" GetRegisterConsumerRequestBodyJsonObject.WriteTo(GetRegisterConsumerRequestBodyText); exit(GetRegisterConsumerRequestBodyText); end; +#endif + + [Scope('OnPrem')] + [NonDebuggable] + procedure GetRegisterConsumerBody(CobrandToken: Text; UserName: Text; UserPassword: SecretText; UserEmail: Text; UserCurrency: Text): Text; + var + GetRegisterConsumerRequestBodyJsonObject: JsonObject; + GetRegisterConsumerRequestBodyText: Text; + UserJsonObject: JsonObject; + UserPreferencesJsonObject: JsonObject; + begin + UserJsonObject.Add('loginName', UserName); + UserJsonObject.Add('password', UserPassword.Unwrap()); + UserJsonObject.Add('email', UserEmail); + UserPreferencesJsonObject.Add('currency', UserCurrency); + UserJsonObject.Add('preferences', UserPreferencesJsonObject); + GetRegisterConsumerRequestBodyJsonObject.Add('user', UserJsonObject); + GetRegisterConsumerRequestBodyJsonObject.WriteTo(GetRegisterConsumerRequestBodyText); + exit(GetRegisterConsumerRequestBodyText); + end; [Scope('OnPrem')] procedure GetRemoveConsumerURL(): Text; diff --git a/Apps/NA/EnvestnetYodleeBankFeeds/test/app.json b/Apps/NA/EnvestnetYodleeBankFeeds/test/app.json index 71e757dfac..73027a6df3 100644 --- a/Apps/NA/EnvestnetYodleeBankFeeds/test/app.json +++ b/Apps/NA/EnvestnetYodleeBankFeeds/test/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "Tests for the Envestnet Yodlee Bank Feeds extension.", "description": "Tests for the Envestnet Yodlee Bank Feeds extension.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?LinkId=733362", @@ -16,31 +16,31 @@ "id": "e2743298-9ccb-49cd-9d8e-4b2d1ab91d36", "name": "Envestnet Yodlee Bank Feeds", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "9856ae4f-d1a7-46ef-89bb-6ef056398228", "name": "System Application Test Library", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5095f467-0a01-4b99-99d1-9ff1237d286f", "publisher": "Microsoft", "name": "Library Variable Storage", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 139500, @@ -57,5 +57,5 @@ "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/NA/EnvestnetYodleeBankFeeds/test/src/MSYodleeBankServiceTests.Codeunit.al b/Apps/NA/EnvestnetYodleeBankFeeds/test/src/MSYodleeBankServiceTests.Codeunit.al index 3d7c65e2ac..ffc8bf97b0 100644 --- a/Apps/NA/EnvestnetYodleeBankFeeds/test/src/MSYodleeBankServiceTests.Codeunit.al +++ b/Apps/NA/EnvestnetYodleeBankFeeds/test/src/MSYodleeBankServiceTests.Codeunit.al @@ -1865,13 +1865,14 @@ codeunit 139501 "MS - Yodlee Bank Service Tests" [Test] [HandlerFunctions('ConfirmHandler,ConsentConfirmYes')] + [NonDebuggable] procedure TestRegisterConsumerShouldGenerateUserNameIfNotExist(); var MSYodleeBankServiceSetupRec: Record "MS - Yodlee Bank Service Setup"; MSYodleeServiceMgt: Codeunit "MS - Yodlee Service Mgt."; MSYodleeBankServiceSetupPage: TestPage "MS - Yodlee Bank Service Setup"; UserName: Text[250]; - Password: Text; + Password: SecretText; ErrorText: Text; begin Initialize(); @@ -1882,7 +1883,6 @@ codeunit 139501 "MS - Yodlee Bank Service Tests" MSYodleeBankServiceSetupPage.Enabled.SETVALUE(TRUE); MSYodleeBankServiceSetupPage.CLOSE(); UserName := ''; - Password := ''; // Execute EnqueueConfirmMsgAndResponse(DataEncryptionTxt, FALSE); @@ -1893,14 +1893,14 @@ codeunit 139501 "MS - Yodlee Bank Service Tests" MSYodleeBankServiceSetupRec.GET(); Assert.AreNotEqual('', UserName, 'Expected that user name is filled'); - Assert.AreNotEqual('', Password, 'Expected that Password is filled'); + Assert.IsFalse(Password.IsEmpty(), 'Expected that Password is filled'); Assert.AreEqual(UserName, MSYodleeBankServiceSetupRec."Consumer Name", 'Expected that Consumer Name is persisted'); Assert.IsTrue(STRPOS(UserName, COMPANYNAME()) = 0, 'Expected that a new user name is generated and starts with company name'); Assert.IsFalse(ISNULLGUID(MSYodleeBankServiceSetupRec."Consumer Password"), 'Password'); Assert.AreEqual( - Password, MSYodleeBankServiceSetupRec.GetPassword(MSYodleeBankServiceSetupRec."Consumer Password"), + Password.Unwrap(), MSYodleeBankServiceSetupRec.GetPassword(MSYodleeBankServiceSetupRec."Consumer Password"), 'Expected that passwords are equal'); end; @@ -1981,9 +1981,9 @@ codeunit 139501 "MS - Yodlee Bank Service Tests" procedure TestYodleeUserPassword(); var PasswordHelper: Codeunit "Password Helper"; - Password: Text[50]; + Password: SecretText; begin - Password := CopyStr(PasswordHelper.GeneratePassword(MaxStrLen(Password)), 1, 50); + Password := PasswordHelper.GenerateSecretPassword(50); Assert.IsFalse(PasswordHelper.WeakYodleePassword(Password), 'The generated password does not conform with Yodlee standard for a strong password.') end; diff --git a/Apps/NA/MX_DIOT/app/app.json b/Apps/NA/MX_DIOT/app/app.json index face327bef..37c0bd6b87 100644 --- a/Apps/NA/MX_DIOT/app/app.json +++ b/Apps/NA/MX_DIOT/app/app.json @@ -2,9 +2,9 @@ "id": "adc18994-073b-4840-a144-2a5e3a0d9d1e", "name": "DIOT - Localization for Mexico", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Easily configure and create DIOT file.", - "description": "As part of tax reporting in Mexico, companies must be able to produce Declaración Informativa de Operaciones con Terceros (DIOT) in a specific format to be sent to Mexican SAT. This feature enables easy export of DIOT files from Dynamics 365 Business Central.", + "description": "As part of tax reporting in Mexico, companies must be able to produce Declaración Informativa de Operaciones con Terceros (DIOT) in a specific format to be sent to Mexican SAT. This feature enables easy export of DIOT files from Dynamics 365 Business Central.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=2109350", @@ -17,11 +17,11 @@ "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "resourceExposurePolicy": { "allowDebugging": true, "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/NA/MX_DIOT/test/app.json b/Apps/NA/MX_DIOT/test/app.json index dc833a4bee..2408151756 100644 --- a/Apps/NA/MX_DIOT/test/app.json +++ b/Apps/NA/MX_DIOT/test/app.json @@ -2,7 +2,7 @@ "id": "f838764f-73b0-4f49-ae42-6c3b29f842c9", "name": "Tests for MX DIOT Extension", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Tests for MX DIOT Extension.", "description": "Tests for MX DIOT Extension.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -16,29 +16,29 @@ "id": "adc18994-073b-4840-a144-2a5e3a0d9d1e", "name": "DIOT - Localization for Mexico", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5095f467-0a01-4b99-99d1-9ff1237d286f", "publisher": "Microsoft", "name": "Library Variable Storage", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "resourceExposurePolicy": { "allowDebugging": true, "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/NA/Onprem Permissions NA/app/Permissions/bankrecpost.permissionset.al b/Apps/NA/Onprem Permissions NA/app/Permissions/bankrecpost.permissionset.al index 8c27dde12b..a0bafe7dc3 100644 --- a/Apps/NA/Onprem Permissions NA/app/Permissions/bankrecpost.permissionset.al +++ b/Apps/NA/Onprem Permissions NA/app/Permissions/bankrecpost.permissionset.al @@ -36,8 +36,10 @@ permissionset 27004 "BANKREC-POST" tabledata "Gen. Journal Template" = RI, tabledata "General Ledger Setup" = r, tabledata "General Posting Setup" = r, +#if not CLEAN25 tabledata "IRS 1099 Adjustment" = RIMD, tabledata "IRS 1099 Form-Box" = RIMD, +#endif tabledata "Reversal Entry" = RIMD, tabledata "Tax Area" = R, tabledata "Tax Area Line" = R, diff --git a/Apps/NA/Onprem Permissions NA/app/app.json b/Apps/NA/Onprem Permissions NA/app/app.json index a00f4869c2..5e6fd2ba59 100644 --- a/Apps/NA/Onprem Permissions NA/app/app.json +++ b/Apps/NA/Onprem Permissions NA/app/app.json @@ -2,7 +2,7 @@ "id": "a87e895f-997f-4351-9426-b7a42a9ab4ef", "name": "OnPrem Permissions (NA)", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "This extension includes permission set for on premise systems.", "description": "This extension includes permission set for on premise systems.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -17,12 +17,12 @@ "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "resourceExposurePolicy": { "allowDebugging": false, "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, "target": "OnPrem", - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/NL/ContosoCoffeeDemoDatasetNL/app/app.json b/Apps/NL/ContosoCoffeeDemoDatasetNL/app/app.json index 102cbe023d..8d1793ee96 100644 --- a/Apps/NL/ContosoCoffeeDemoDatasetNL/app/app.json +++ b/Apps/NL/ContosoCoffeeDemoDatasetNL/app/app.json @@ -2,7 +2,7 @@ "id": "5b0a41a1-6c42-4123-a521-2265186cfb35", "name": "Contoso Coffee Demo Dataset (NL)", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "To help partners demonstrate the capabilities of Business Central, we are making new and extensive demo data available for various scenarios.", "description": "Presales specialists can run the tool on top of Cronus or My Company and get the setup and demo data they'll need when they demonstrate various scenarios.", "privacyStatement": "https://go.microsoft.com/fwlink/?linkid=724009", @@ -16,14 +16,14 @@ "id": "5a0b41e9-7a42-4123-d521-2265186cfb31", "name": "Contoso Coffee Demo Dataset", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 11495, diff --git a/Apps/NL/IntrastatNL/app/app.json b/Apps/NL/IntrastatNL/app/app.json index e4e12198c4..1db0416f9a 100644 --- a/Apps/NL/IntrastatNL/app/app.json +++ b/Apps/NL/IntrastatNL/app/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "The Intrastat extension makes it easy to export the Intrastat report in the format that the Dutch authorities require.", "description": "The formats that businesses must use to report Intrastat vary from country to country. The Intrastat extension makes it easy to export the Intrastat report in the format that the Dutch authorities require.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=2204541", @@ -16,13 +16,13 @@ "id": "70912191-3c4c-49fc-a1de-bc6ea1ac9da6", "name": "Intrastat Core", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 11426, @@ -34,6 +34,6 @@ "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0", + "application": "25.0.0.0", "target": "Cloud" } \ No newline at end of file diff --git a/Apps/NL/NLDigitalTaxDeclaration/app/app.json b/Apps/NL/NLDigitalTaxDeclaration/app/app.json index 552ddd4f27..ff39e311ec 100644 --- a/Apps/NL/NLDigitalTaxDeclaration/app/app.json +++ b/Apps/NL/NLDigitalTaxDeclaration/app/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "Easily submit VAT returns to the Dutch authorities", "description": "This app provides functionality that enables easy submission of the VAT return (tax declaration) in the Netherlands. It allows submission of VAT returns already prepared in Dynamics 365 Business Central.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=2115924", @@ -17,12 +17,12 @@ "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "target": "OnPrem", "resourceExposurePolicy": { "allowDebugging": false, "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/NL/NLDigitalTaxDeclaration/test/app.json b/Apps/NL/NLDigitalTaxDeclaration/test/app.json index 426b535354..8d8225104e 100644 --- a/Apps/NL/NLDigitalTaxDeclaration/test/app.json +++ b/Apps/NL/NLDigitalTaxDeclaration/test/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "Digital Tax Declaration for the Netherlands Tests", "description": "Digital Tax Declaration for the Netherlands Tests", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=2115924", @@ -16,31 +16,31 @@ "id": "59909dc2-6adb-43e7-9f83-1e4fa2be0b37", "name": "Digital Tax Declaration for the Netherlands", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "9856ae4f-d1a7-46ef-89bb-6ef056398228", "name": "System Application Test Library", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5095f467-0a01-4b99-99d1-9ff1237d286f", "publisher": "Microsoft", "name": "Library Variable Storage", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 139500, @@ -57,5 +57,5 @@ "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/NL/NLDigitalTaxDeclaration/test/src/DigipoortXML.Codeunit.al b/Apps/NL/NLDigitalTaxDeclaration/test/src/DigipoortXML.Codeunit.al index 6dad399cf2..51db61cbaf 100644 --- a/Apps/NL/NLDigitalTaxDeclaration/test/src/DigipoortXML.Codeunit.al +++ b/Apps/NL/NLDigitalTaxDeclaration/test/src/DigipoortXML.Codeunit.al @@ -20,8 +20,8 @@ codeunit 148000 "Digipoort XML" XbrliXbrlTok: Label 'xbrli:xbrl'; AttrBdITok: Label 'xmlns:bd-i'; AttrBdObTok: Label 'xmlns:bd-ob'; - BDDataEndpointTxt: Label 'http://www.nltaxonomie.nl/nt17/bd/20221207/dictionary/bd-data', Locked = true; - VATDeclarationSchemaEndpointTxt: Label 'http://www.nltaxonomie.nl/nt17/bd/20221207/entrypoints/bd-rpt-ob-aangifte-2023.xsd', Locked = true; + BDDataEndpointTxt: Label 'http://www.nltaxonomie.nl/nt18/bd/20231213/dictionary/bd-data', Locked = true; + VATDeclarationSchemaEndpointTxt: Label 'http://www.nltaxonomie.nl/nt18/bd/20231213/entrypoints/bd-rpt-ob-aangifte-2024.xsd', Locked = true; IncorrectNumberOfNodesErr: Label 'Incorrect number of node %1', Comment = '%1 = the name of the node'; [Test] diff --git a/Apps/NO/ContosoCoffeeDemoDatasetNO/app/app.json b/Apps/NO/ContosoCoffeeDemoDatasetNO/app/app.json index f430839345..978839ae98 100644 --- a/Apps/NO/ContosoCoffeeDemoDatasetNO/app/app.json +++ b/Apps/NO/ContosoCoffeeDemoDatasetNO/app/app.json @@ -2,7 +2,7 @@ "id": "5b0a41a1-7b42-1719-a521-2265186cfb31", "name": "Contoso Coffee Demo Dataset (NO)", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "To help partners demonstrate the capabilities of Business Central, we are making new and extensive demo data available for various scenarios.", "description": "Presales specialists can run the tool on top of Cronus or My Company and get the setup and demo data they'll need when they demonstrate various scenarios.", "privacyStatement": "https://go.microsoft.com/fwlink/?linkid=724009", @@ -16,14 +16,14 @@ "id": "5a0b41e9-7a42-4123-d521-2265186cfb31", "name": "Contoso Coffee Demo Dataset", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 10660, diff --git a/Apps/NO/ElectronicVATSubmission/app/Permissions/d365basicelectronicvatsubmission.permissionsetext.al b/Apps/NO/ElectronicVATSubmission/app/Permissions/d365basicelectronicvatsubmission.permissionsetext.al index ff389dfeb6..761d04d105 100644 --- a/Apps/NO/ElectronicVATSubmission/app/Permissions/d365basicelectronicvatsubmission.permissionsetext.al +++ b/Apps/NO/ElectronicVATSubmission/app/Permissions/d365basicelectronicvatsubmission.permissionsetext.al @@ -8,5 +8,5 @@ using System.Security.AccessControl; permissionsetextension 10684 "D365 BASIC - Electronic VAT Submission" extends "D365 BASIC" { - IncludedPermissionSets = "Elec. VAT - Edit"; + IncludedPermissionSets = "Elec. VAT - Read"; } diff --git a/Apps/NO/ElectronicVATSubmission/app/Permissions/d365basicisvelectronicvatsubmission.permissionsetext.al b/Apps/NO/ElectronicVATSubmission/app/Permissions/d365basicisvelectronicvatsubmission.permissionsetext.al index dc69b35f26..09f6401157 100644 --- a/Apps/NO/ElectronicVATSubmission/app/Permissions/d365basicisvelectronicvatsubmission.permissionsetext.al +++ b/Apps/NO/ElectronicVATSubmission/app/Permissions/d365basicisvelectronicvatsubmission.permissionsetext.al @@ -8,5 +8,5 @@ using System.Security.AccessControl; permissionsetextension 10683 "D365 BASIC ISV - Electronic VAT Submission" extends "D365 BASIC ISV" { - IncludedPermissionSets = "Elec. VAT - Edit"; + IncludedPermissionSets = "Elec. VAT - Read"; } diff --git a/Apps/NO/ElectronicVATSubmission/app/Permissions/d365teammemberelectronicvatsubmission.permissionsetext.al b/Apps/NO/ElectronicVATSubmission/app/Permissions/d365teammemberelectronicvatsubmission.permissionsetext.al index 9ec2f2e9eb..1e8d372fcd 100644 --- a/Apps/NO/ElectronicVATSubmission/app/Permissions/d365teammemberelectronicvatsubmission.permissionsetext.al +++ b/Apps/NO/ElectronicVATSubmission/app/Permissions/d365teammemberelectronicvatsubmission.permissionsetext.al @@ -8,5 +8,5 @@ using System.Security.AccessControl; permissionsetextension 10686 "D365 TEAM MEMBER - Electronic VAT Submission" extends "D365 TEAM MEMBER" { - IncludedPermissionSets = "Elec. VAT - Edit"; + IncludedPermissionSets = "Elec. VAT - Read"; } diff --git a/Apps/NO/ElectronicVATSubmission/app/app.json b/Apps/NO/ElectronicVATSubmission/app/app.json index 09d9e60e33..1dbe891d3f 100644 --- a/Apps/NO/ElectronicVATSubmission/app/app.json +++ b/Apps/NO/ElectronicVATSubmission/app/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "Easily submit VAT returns to the Skatteetaten.", "description": "This app provides functionality that enables easy submission of the VAT return in the Norway. It allows submission of VAT returns already prepared in Dynamics 365 Business Central.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=2181211", @@ -16,7 +16,7 @@ "id": "3d5fd255-4fb4-464b-9362-44cd85a883e7", "publisher": "Microsoft", "name": "Standard Audit File - Tax Localization for Norway", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "idRanges": [ @@ -25,12 +25,12 @@ "to": 10699 } ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "target": "OnPrem", "resourceExposurePolicy": { "allowDebugging": false, "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/NO/ElectronicVATSubmission/app/src/Connection/ElecVATOAuthMgt.Codeunit.al b/Apps/NO/ElectronicVATSubmission/app/src/Connection/ElecVATOAuthMgt.Codeunit.al index 95214287ba..92fcab0f9a 100644 --- a/Apps/NO/ElectronicVATSubmission/app/src/Connection/ElecVATOAuthMgt.Codeunit.al +++ b/Apps/NO/ElectronicVATSubmission/app/src/Connection/ElecVATOAuthMgt.Codeunit.al @@ -84,6 +84,8 @@ codeunit 10680 "Elec. VAT OAuth Mgt." "Token DataScope" := "Token DataScope"::UserAndCompany; "Daily Limit" := 1000; "Feature GUID" := ElecVATSetup."OAuth Feature GUID"; + "Code Challenge Method" := "Code Challenge Method"::S256; + "Use Nonce" := true; "User ID" := CopyStr(UserId(), 1, MaxStrLen("User ID")); Modify(); end; @@ -303,7 +305,10 @@ codeunit 10680 "Elec. VAT OAuth Mgt." exit(false); end; - ServicerrorMessage := JToken.AsValue().AsText(); + if JToken.IsObject then + JToken.WriteTo(ServicerrorMessage) + else + ServicerrorMessage := JToken.AsValue().AsText(); if ServicerrorMessage = '' then begin Session.LogMessage('0000G8J', EmptyJsonErrMsgErr, Verbosity::Error, DataClassification::SystemMetadata, TelemetryScope::ExtensionPublisher, 'Category', NOVATReturnSubmissionTok); exit(false); @@ -352,12 +357,14 @@ codeunit 10680 "Elec. VAT OAuth Mgt." TestField("Refresh Token URL Path", RefreshTokenURLPathTxt); TestField("Authorization Response Type", AuthorizationResponseTypeTxt); TestField("Daily Limit", 1000); + TestField("Code Challenge Method", "Code Challenge Method"::S256); + TestField("Use Nonce"); end; end; [NonDebuggable] - internal procedure SetToken(var TokenKey: Guid; TokenValue: Text; TokenDataScope: DataScope) NewToken: Boolean + internal procedure SetToken(var TokenKey: Guid; TokenValue: SecretText; TokenDataScope: DataScope) NewToken: Boolean begin if IsNullGuid(TokenKey) then NewToken := true; @@ -378,10 +385,10 @@ codeunit 10680 "Elec. VAT OAuth Mgt." end; [NonDebuggable] - local procedure GetToken(TokenKey: Guid; TokenDataScope: DataScope) TokenValue: Text + local procedure GetToken(TokenKey: Guid; TokenDataScope: DataScope) TokenValue: SecretText begin if not HasToken(TokenKey, TokenDataScope) then - exit(''); + exit; IsolatedStorage.Get(TokenKey, TokenDataScope, TokenValue); end; @@ -425,7 +432,8 @@ codeunit 10680 "Elec. VAT OAuth Mgt." CheckOAuthConsistencySetup(OAuth20Setup); state := Format(CreateGuid(), 0, 4); url := - StrSubstNo(CurrUrlWithStateTxt, OAuth20Mgt.GetAuthorizationURL(OAuth20Setup, GetToken(OAuth20Setup."Client ID", DataScope::Company)), state); + StrSubstNo(CurrUrlWithStateTxt, OAuth20Mgt.GetAuthorizationURLAsSecretText(OAuth20Setup, GetToken(OAuth20Setup."Client ID", DataScope::Company).Unwrap()).Unwrap(), state); + Commit(); OAuth2ControlAddIn.SetOAuth2Properties(url, state); OAuth2ControlAddIn.RunModal(); auth_error := OAuth2ControlAddIn.GetAuthError(); @@ -440,12 +448,13 @@ codeunit 10680 "Elec. VAT OAuth Mgt." end; end; + [NonDebuggable] [EventSubscriber(ObjectType::Table, Database::"OAuth 2.0 Setup", 'OnBeforeRequestAccessToken', '', true, true)] local procedure OnBeforeRequestAccessToken(var OAuth20Setup: Record "OAuth 2.0 Setup"; AuthorizationCode: Text; var Result: Boolean; var MessageText: Text; var Processed: Boolean) var RequestJSON: Text; - AccessToken: Text; - RefreshToken: Text; + AccessToken: SecretText; + RefreshToken: SecretText; TokenDataScope: DataScope; begin if not IsElectronicVATOAuthSetup(OAuth20Setup) or Processed then @@ -459,8 +468,8 @@ codeunit 10680 "Elec. VAT OAuth Mgt." Result := OAuth20Mgt.RequestAccessTokenWithContentType( OAuth20Setup, RequestJSON, MessageText, AuthorizationCode, - GetToken(OAuth20Setup."Client ID", DataScope::Company), - GetToken(OAuth20Setup."Client Secret", DataScope::Company), + GetToken(OAuth20Setup."Client ID", DataScope::Company).Unwrap(), + GetToken(OAuth20Setup."Client Secret", DataScope::Company).Unwrap(), AccessToken, RefreshToken, true); if Result then @@ -472,8 +481,8 @@ codeunit 10680 "Elec. VAT OAuth Mgt." local procedure OnBeforeRefreshAccessToken(var OAuth20Setup: Record "OAuth 2.0 Setup"; var Result: Boolean; var MessageText: Text; var Processed: Boolean) var RequestJSON: Text; - AccessToken: Text; - RefreshToken: Text; + AccessToken: SecretText; + RefreshToken: SecretText; TokenDataScope: DataScope; OldServiceUrl: Text[250]; begin @@ -491,8 +500,8 @@ codeunit 10680 "Elec. VAT OAuth Mgt." Result := OAuth20Mgt.RefreshAccessTokenWithContentType( OAuth20Setup, RequestJSON, MessageText, - GetToken(OAuth20Setup."Client ID", DataScope::Company), - GetToken(OAuth20Setup."Client Secret", DataScope::Company), + GetToken(OAuth20Setup."Client ID", DataScope::Company).Unwrap(), + GetToken(OAuth20Setup."Client Secret", DataScope::Company).Unwrap(), AccessToken, RefreshToken, true); OAuth20Setup."Service URL" := OldServiceUrl; @@ -501,7 +510,7 @@ codeunit 10680 "Elec. VAT OAuth Mgt." end; [NonDebuggable] - local procedure SaveTokens(var OAuth20Setup: Record "OAuth 2.0 Setup"; TokenDataScope: DataScope; AccessToken: Text; RefreshToken: Text) + local procedure SaveTokens(var OAuth20Setup: Record "OAuth 2.0 Setup"; TokenDataScope: DataScope; AccessToken: SecretText; RefreshToken: SecretText) var TypeHelper: Codeunit "Type Helper"; NewAccessTokenDateTime: DateTime; @@ -532,9 +541,9 @@ codeunit 10680 "Elec. VAT OAuth Mgt." ElecVATSetup.GetRecordOnce(); ElecVATSetup.TestField("Submission Environment URL"); if StrPos(OAuth20Setup."Service URL", ElecVATSetup."Submission Environment URL") = 1 then - TokenValue := GetToken(OAuth20Setup."Altinn Token", OAuth20Setup.GetTokenDataScope()) + TokenValue := GetToken(OAuth20Setup."Altinn Token", OAuth20Setup.GetTokenDataScope()).Unwrap() else - TokenValue := GetToken(OAuth20Setup."Access Token", OAuth20Setup.GetTokenDataScope()); + TokenValue := GetToken(OAuth20Setup."Access Token", OAuth20Setup.GetTokenDataScope()).Unwrap(); Result := OAuth20Mgt.InvokeRequest( OAuth20Setup, RequestJSON, ResponseJSON, HttpError, TokenValue, RetryOnCredentialsFailure); @@ -570,4 +579,14 @@ codeunit 10680 "Elec. VAT OAuth Mgt." ServiceConnection.InsertServiceConnection( ServiceConnection, OAuth20Setup.RecordId(), ServiceConnectionSetupLbl, '', PAGE::"OAuth 2.0 Setup"); end; + + [EventSubscriber(ObjectType::Codeunit, Codeunit::"OAuth 2.0 Mgt.", 'OnBeforeGetServiceUrlForAuthorizationURL', '', false, false)] + local procedure OnBeforeGetServiceUrlForAuthorizationURL(var ServiceUrl: Text; OAuth20Setup: Record "OAuth 2.0 Setup") + begin + if not IsElectronicVATOAuthSetup(OAuth20Setup) then + exit; + ElecVATSetup.GetRecordOnce(); + ElecVATSetup.TestField("Login URL"); + ServiceUrl := ElecVATSetup."Login URL"; + end; } diff --git a/Apps/NO/ElectronicVATSubmission/app/src/Setup/ElecVATSetup.Table.al b/Apps/NO/ElectronicVATSubmission/app/src/Setup/ElecVATSetup.Table.al index 3885b86661..fdd51ad5c3 100644 --- a/Apps/NO/ElectronicVATSubmission/app/src/Setup/ElecVATSetup.Table.al +++ b/Apps/NO/ElectronicVATSubmission/app/src/Setup/ElecVATSetup.Table.al @@ -83,6 +83,11 @@ table 10686 "Elec. VAT Setup" { Caption = 'Disable Checks On Release'; } + field(20; "Login URL"; Text[250]) + { + Caption = 'Login URL'; + DataClassification = EndUserIdentifiableInformation; + } } trigger OnDelete() @@ -106,7 +111,7 @@ table 10686 "Elec. VAT Setup" [NonDebuggable] [Scope('OnPrem')] - procedure SetToken(var TokenKey: Guid; TokenValue: Text) + procedure SetToken(var TokenKey: Guid; TokenValue: SecretText) begin if IsNullGuid(TokenKey) then TokenKey := CreateGuid(); @@ -116,10 +121,10 @@ table 10686 "Elec. VAT Setup" [NonDebuggable] [Scope('OnPrem')] - procedure GetToken(TokenKey: Guid) TokenValue: Text + procedure GetToken(TokenKey: Guid) TokenValue: SecretText begin if not HasToken(TokenKey) then - exit(''); + exit; IsolatedStorage.Get(TokenKey, DataScope::Company, TokenValue); end; diff --git a/Apps/NO/ElectronicVATSubmission/app/src/Setup/ElecVATUpgrade.Codeunit.al b/Apps/NO/ElectronicVATSubmission/app/src/Setup/ElecVATUpgrade.Codeunit.al index 16c75994bb..0f83955f37 100644 --- a/Apps/NO/ElectronicVATSubmission/app/src/Setup/ElecVATUpgrade.Codeunit.al +++ b/Apps/NO/ElectronicVATSubmission/app/src/Setup/ElecVATUpgrade.Codeunit.al @@ -10,9 +10,14 @@ codeunit 10691 "Elec. VAT Upgrade" { Subtype = Upgrade; + var + LoginURLTxt: Label 'https://login.idporten.no', Locked = true; + AuthenticationURLTxt: Label 'https://idporten.no', Locked = true; + trigger OnUpgradePerCompany() begin UpgradeReportVATNoteInVATReportSetup(); + UpgradeElecVATSetupWith2024Endpoints(); end; local procedure UpgradeReportVATNoteInVATReportSetup() @@ -32,16 +37,40 @@ codeunit 10691 "Elec. VAT Upgrade" UpgradeTag.SetUpgradeTag(GetReportVATNoteInVATReportSetupTag()); end; + local procedure UpgradeElecVATSetupWith2024Endpoints() + var + ElecVATSetup: Record "Elec. VAT Setup"; + UpgradeTag: Codeunit "Upgrade Tag"; + begin + if UpgradeTag.HasUpgradeTag(GetUpgradeElecVATSetupWith2024EndpointsSetupTag()) then + exit; + + if not ElecVATSetup.Get() then + exit; + + ElecVATSetup.Validate("Authentication URL", AuthenticationURLTxt); + ElecVATSetup.Validate("Login URL", LoginURLTxt); + if ElecVATSetup.Modify(true) then; + + UpgradeTag.SetUpgradeTag(GetUpgradeElecVATSetupWith2024EndpointsSetupTag()); + end; + local procedure GetReportVATNoteInVATReportSetupTag(): Code[250]; begin exit('MS-433237-ReportVATNoteInVATReportSetupTag-20220418'); end; + local procedure GetUpgradeElecVATSetupWith2024EndpointsSetupTag(): Code[250]; + begin + exit('MS-498271-ElecVATSetupWith2024EndpointsSetupTag-20240219'); + end; + [EventSubscriber(ObjectType::Codeunit, Codeunit::"Upgrade Tag", 'OnGetPerCompanyUpgradeTags', '', false, false)] local procedure RegisterPerCompanyTags(var PerCompanyUpgradeTags: List of [Code[250]]) begin PerCompanyUpgradeTags.Add(GetReportVATNoteInVATReportSetupTag()); + PerCompanyUpgradeTags.Add(GetUpgradeElecVATSetupWith2024EndpointsSetupTag()); end; } diff --git a/Apps/NO/ElectronicVATSubmission/app/src/Setup/ElectronicVATInstallation.Codeunit.al b/Apps/NO/ElectronicVATSubmission/app/src/Setup/ElectronicVATInstallation.Codeunit.al index 797ae376c4..7781a1ff05 100644 --- a/Apps/NO/ElectronicVATSubmission/app/src/Setup/ElectronicVATInstallation.Codeunit.al +++ b/Apps/NO/ElectronicVATSubmission/app/src/Setup/ElectronicVATInstallation.Codeunit.al @@ -23,7 +23,8 @@ codeunit 10681 "Electronic VAT Installation" AssistedSetupTxt: Label 'Set up an electronic VAT submission'; AssistedSetupDescriptionTxt: Label 'Connect to the ID-porten integration point and submit your VAT return to Skatteetaten.'; AssistedSetupHelpTxt: Label 'https://go.microsoft.com/fwlink/?linkid=2181211', Locked = true; - AuthenticationURLTxt: Label 'https://oidc.difi.no/idporten-oidc-provider', Locked = true; + AuthenticationURLTxt: Label 'https://idporten.no', Locked = true; + LoginURLTxt: Label 'https://login.idporten.no', Locked = true; ValidateVATReturnUrlLbl: Label 'https://idporten.api.skatteetaten.no/api/mva/grensesnittstoette/mva-melding/valider', Locked = true; ExchangeIDPortenToAltinnUrlLbl: Label 'https://platform.altinn.no/authentication/api/v1/exchange/id-porten', Locked = true; @@ -76,6 +77,7 @@ codeunit 10681 "Electronic VAT Installation" ElecVATSetup.Insert(true); ElecVATSetup.Validate("OAuth Feature GUID", CreateGuid()); ElecVATSetup.Validate("Authentication URL", AuthenticationURLTxt); + ElecVATSetup.Validate("Login URL", LoginURLTxt); OAuth20.GetDefaultRedirectURL(RedirectUrl); ElecVATSetup.Validate("Redirect URL", CopyStr(RedirectUrl, 1, MaxStrLen(ElecVATSetup."Redirect URL"))); ElecVATSetup.Validate("Validate VAT Return Url", ValidateVATReturnUrlLbl); @@ -106,7 +108,7 @@ codeunit 10681 "Electronic VAT Installation" if VATReportsConfiguration.Get(VATReportsConfiguration."VAT Report Type"::"VAT Return", ElectronicVATLbl) then exit; VATReportsConfiguration.Validate("VAT Report Type", VATReportsConfiguration."VAT Report Type"::"VAT Return"); - VATReportsConfiguration.validate("VAT Report Version", ElectronicVATLbl); + VATReportsConfiguration.Validate("VAT Report Version", ElectronicVATLbl); VATReportsConfiguration.Validate("Suggest Lines Codeunit ID", Codeunit::"VAT Report Suggest Lines"); VATReportsConfiguration.Validate("Content Codeunit ID", Codeunit::"Elec. VAT Create Content"); VATReportsConfiguration.Validate("Submission Codeunit ID", Codeunit::"Elec. VAT Submit Return"); diff --git a/Apps/NO/ElectronicVATSubmission/app/src/Setup/ElectronicVATSetupCard.Page.al b/Apps/NO/ElectronicVATSubmission/app/src/Setup/ElectronicVATSetupCard.Page.al index c40a68cf00..2f210f0ed2 100644 --- a/Apps/NO/ElectronicVATSubmission/app/src/Setup/ElectronicVATSetupCard.Page.al +++ b/Apps/NO/ElectronicVATSubmission/app/src/Setup/ElectronicVATSetupCard.Page.al @@ -59,6 +59,11 @@ page 10692 "Electronic VAT Setup Card" ApplicationArea = Basic, Suite; ToolTip = 'Specifies the URL to connect to ID-Porten.'; } + field("Login URL"; Rec."Login URL") + { + ApplicationArea = Basic, Suite; + ToolTip = 'Specifies the URL to login to ID-Porten.'; + } field("Redirect URL"; "Redirect URL") { ApplicationArea = Basic, Suite; diff --git a/Apps/NO/ElectronicVATSubmission/app/src/VAT Return Management/ElecVATDataMgt.Codeunit.al b/Apps/NO/ElectronicVATSubmission/app/src/VAT Return Management/ElecVATDataMgt.Codeunit.al index d03dc51ffc..80df86c9a3 100644 --- a/Apps/NO/ElectronicVATSubmission/app/src/VAT Return Management/ElecVATDataMgt.Codeunit.al +++ b/Apps/NO/ElectronicVATSubmission/app/src/VAT Return Management/ElecVATDataMgt.Codeunit.al @@ -203,7 +203,7 @@ codeunit 10683 "Elec. VAT Data Mgt." procedure IsReverseChargeVATCode(VATCode: Code[20]): Boolean begin - exit(VATCode in ['81', '86', '91']) + exit(VATCode in ['81', '83', '86', '88', '91']) end; procedure IsVATCodeWithDeductiblePart(VATCode: Code[20]): Boolean diff --git a/Apps/NO/ElectronicVATSubmission/test/app.json b/Apps/NO/ElectronicVATSubmission/test/app.json index 922cac146c..490658dd0b 100644 --- a/Apps/NO/ElectronicVATSubmission/test/app.json +++ b/Apps/NO/ElectronicVATSubmission/test/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "Easily submit VAT returns to the Skatteetaten.", "description": "This app provides functionality that enables easy submission of the VAT return in the Norway. It allows submission of VAT returns already prepared in Dynamics 365 Business Central.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=2047615", @@ -16,19 +16,19 @@ "id": "5512093d-54ab-4fca-9e39-43aa3b45362c", "publisher": "Microsoft", "name": "Electronic VAT submission for Norway", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5095f467-0a01-4b99-99d1-9ff1237d286f", "publisher": "Microsoft", "name": "Library Variable Storage", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "idRanges": [ @@ -41,12 +41,12 @@ "to": 148135 } ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "target": "OnPrem", "resourceExposurePolicy": { "allowDebugging": false, "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/NO/ElectronicVATSubmission/test/src/ElecVATSubmissionDemodata.Codeunit.al b/Apps/NO/ElectronicVATSubmission/test/src/ElecVATSubmissionDemodata.Codeunit.al index 4d8dff89eb..3367d5e5b5 100644 --- a/Apps/NO/ElectronicVATSubmission/test/src/ElecVATSubmissionDemodata.Codeunit.al +++ b/Apps/NO/ElectronicVATSubmission/test/src/ElecVATSubmissionDemodata.Codeunit.al @@ -48,5 +48,7 @@ codeunit 148132 "Elec. VAT Submission Demodata" ElecVATSetup.DeleteAll(); ElectronicVATInstallation.RunExtensionSetup(); ElecVATSetup.Get(); + ElecVATSetup.TestField("Authentication URL"); + ElecVATSetup.TestField("Login URL"); end; } \ No newline at end of file diff --git a/Apps/NO/ImportNOPayroll/app/app.json b/Apps/NO/ImportNOPayroll/app/app.json index 4fe0ee6577..2131405092 100644 --- a/Apps/NO/ImportNOPayroll/app/app.json +++ b/Apps/NO/ImportNOPayroll/app/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "Get data exchange definitions for the Norwegian payroll service.", "description": "Get data exchange definitions for the Huldt & Lillevik payroll service in Norway.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=2005800", @@ -17,12 +17,12 @@ "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "target": "OnPrem", "resourceExposurePolicy": { "allowDebugging": false, "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/NO/ImportNOPayroll/test/app.json b/Apps/NO/ImportNOPayroll/test/app.json index 60f9d82208..cfe4bf1315 100644 --- a/Apps/NO/ImportNOPayroll/test/app.json +++ b/Apps/NO/ImportNOPayroll/test/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "Tests for the Payroll Data Import Definition (NO) extension.", "description": "Tests for the Payroll Data Import Definition (NO) extension.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=2005800", @@ -16,25 +16,25 @@ "id": "B9B38C74-B9CF-48FF-89E5-DDA2109C2CA7", "name": "Payroll Data Import Definition (NO)", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5095f467-0a01-4b99-99d1-9ff1237d286f", "publisher": "Microsoft", "name": "Library Variable Storage", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 139500, @@ -51,5 +51,5 @@ "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/NO/NorwegianSAFT/app/app.json b/Apps/NO/NorwegianSAFT/app/app.json index 550876d841..8bacf8e01e 100644 --- a/Apps/NO/NorwegianSAFT/app/app.json +++ b/Apps/NO/NorwegianSAFT/app/app.json @@ -2,7 +2,7 @@ "id": "3d5fd255-4fb4-464b-9362-44cd85a883e7", "name": "Standard Audit File - Tax Localization for Norway", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Easily configure and create SAF-T audit files for Norway", "description": "As part of tax reporting in Norway, companies must be able to produce Standard Audit Files - Tax (SAF-T) in a specific format to be sent to Norwegian authorities. This feature enables configuration of account mapping and easy export of SAF-T files from Dynamics 365 Business Central.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -17,12 +17,12 @@ "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "target": "OnPrem", "resourceExposurePolicy": { "allowDebugging": false, "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/NO/NorwegianSAFT/app/src/Export Engine/SAFTExportMgt.Codeunit.al b/Apps/NO/NorwegianSAFT/app/src/Export Engine/SAFTExportMgt.Codeunit.al index 9a11b5d156..c1be9926f5 100644 --- a/Apps/NO/NorwegianSAFT/app/src/Export Engine/SAFTExportMgt.Codeunit.al +++ b/Apps/NO/NorwegianSAFT/app/src/Export Engine/SAFTExportMgt.Codeunit.al @@ -71,7 +71,7 @@ codeunit 10675 "SAF-T Export Mgt." SendTraceTagOfExport(SAFTExportTxt, GetStartTraceTagMessage(SAFTExportHeader)); CreateExportLines(SAFTExportHeader); - SAFTExportHeader.validate(Status, SAFTExportHeader.Status::"In Progress"); + SAFTExportHeader.Validate(Status, SAFTExportHeader.Status::"In Progress"); SAFTExportHeader.Validate("Execution Start Date/Time", TypeHelper.GetCurrentDateTimeInUserTimeZone()); SAFTExportHeader.Validate("Execution End Date/Time", 0DT); CalculateGLEntryTotals(SAFTExportHeader); diff --git a/Apps/NO/NorwegianSAFT/test/app.json b/Apps/NO/NorwegianSAFT/test/app.json index 7906397bd0..ab3053edad 100644 --- a/Apps/NO/NorwegianSAFT/test/app.json +++ b/Apps/NO/NorwegianSAFT/test/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "Tests for the Standard Audit File - Tax Localization for Norway extension.", "description": "Tests for the Standard Audit File - Tax Localization for Norwaym extension.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=2106039", @@ -16,25 +16,25 @@ "id": "3d5fd255-4fb4-464b-9362-44cd85a883e7", "name": "Standard Audit File - Tax Localization for Norway", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5095f467-0a01-4b99-99d1-9ff1237d286f", "publisher": "Microsoft", "name": "Library Variable Storage", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 139500, @@ -51,5 +51,5 @@ "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/NZ/ContosoCoffeeDemoDatasetNZ/app/app.json b/Apps/NZ/ContosoCoffeeDemoDatasetNZ/app/app.json index a97fb8688b..ea3f5e2161 100644 --- a/Apps/NZ/ContosoCoffeeDemoDatasetNZ/app/app.json +++ b/Apps/NZ/ContosoCoffeeDemoDatasetNZ/app/app.json @@ -2,7 +2,7 @@ "id": "5b0e32a1-7b42-4123-a521-2265186cfb31", "name": "Contoso Coffee Demo Dataset (NZ)", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "To help partners demonstrate the capabilities of Business Central, we are making new and extensive demo data available for various scenarios.", "description": "Presales specialists can run the tool on top of Cronus or My Company and get the setup and demo data they'll need when they demonstrate various scenarios.", "privacyStatement": "https://go.microsoft.com/fwlink/?linkid=724009", @@ -16,14 +16,14 @@ "id": "5a0b41e9-7a42-4123-d521-2265186cfb31", "name": "Contoso Coffee Demo Dataset", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 17105, diff --git a/Apps/NZ/HybridBCLast_NZ/app/app.json b/Apps/NZ/HybridBCLast_NZ/app/app.json index c00e746138..586dcde805 100644 --- a/Apps/NZ/HybridBCLast_NZ/app/app.json +++ b/Apps/NZ/HybridBCLast_NZ/app/app.json @@ -2,7 +2,7 @@ "id": "5067d646-f04e-451a-a561-d267646626f8", "name": "Business Central Cloud Migration - Previous Release (NZ)", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Enables data migration from the previous version of Dynamics BC (n-1) to the current release of Dynamics 365 Business Central SaaS.", "description": "This extension, in conjuction with the Business Central Cloud Migration Previous Release, will enable you to migrate data from your Business Central on-premises solution for New Zealand to your Dynamics 365 Business Central cloud tenant for New Zealand. This extension is required to update country specific tables. Once you have walked through the cloud migration wizard in assisted setup, you will be able to migrate your data from your on-premises environment to your cloud tenant.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -15,25 +15,25 @@ { "publisher": "Microsoft", "name": "Intelligent Cloud Base", - "version": "24.0.0.0", + "version": "25.0.0.0", "id": "58623bfa-0559-4bc2-ae1c-0979c29fd9e0" }, { "publisher": "Microsoft", "name": "Business Central Cloud Migration - Previous Release", - "version": "24.0.0.0", + "version": "25.0.0.0", "id": "6992416f-3f39-4d3c-8242-3fff61350bea" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "resourceExposurePolicy": { "allowDebugging": false, "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, "target": "OnPrem", - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/RU/CDTracking/app/app.json b/Apps/RU/CDTracking/app/app.json index f06c88a210..9680df8434 100644 --- a/Apps/RU/CDTracking/app/app.json +++ b/Apps/RU/CDTracking/app/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "Support Customs Declaration Number tracking for Factura Invoice.", "description": "Accurate tracking of Customs Declaration number from purchase to sales and printing this information in Factura Invoices.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=2153001", @@ -22,7 +22,7 @@ "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "target": "OnPrem", - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/RU/CDTracking/test/app.json b/Apps/RU/CDTracking/test/app.json index 93ed1ba762..fb5607921d 100644 --- a/Apps/RU/CDTracking/test/app.json +++ b/Apps/RU/CDTracking/test/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "Support Customs Declaration Number tracking for Factura Invoice.", "description": "Accurate tracking of Customs Declaration number from purchase to sales and printing this information in Factura Invoices.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=2115924", @@ -16,31 +16,31 @@ "id": "daf22d93-ac7e-4a55-a3fc-fa6f5e8e7261", "name": "Customs Declaration Tracking for Russia", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "9856ae4f-d1a7-46ef-89bb-6ef056398228", "name": "System Application Test Library", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5095f467-0a01-4b99-99d1-9ff1237d286f", "publisher": "Microsoft", "name": "Library Variable Storage", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 139500, @@ -57,5 +57,5 @@ "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/RU/CDTracking/test/src/LibraryCDTracking.Codeunit.al b/Apps/RU/CDTracking/test/src/LibraryCDTracking.Codeunit.al index 86427cdca3..41f9c0888d 100644 --- a/Apps/RU/CDTracking/test/src/LibraryCDTracking.Codeunit.al +++ b/Apps/RU/CDTracking/test/src/LibraryCDTracking.Codeunit.al @@ -9,7 +9,6 @@ codeunit 147100 "Library - CD Tracking" Assert: Codeunit Assert; LibraryERM: Codeunit "Library - ERM"; LibraryUtility: Codeunit "Library - Utility"; - NoSeriesManagement: Codeunit NoSeriesManagement; LibraryPurchase: Codeunit "Library - Purchase"; LibrarySales: Codeunit "Library - Sales"; LibraryWarehouse: Codeunit "Library - Warehouse"; @@ -71,6 +70,7 @@ codeunit 147100 "Library - CD Tracking" [Scope('OnPrem')] procedure CreateJnlLine(JnlTemplateName: Code[10]; JnlBatchName: Code[10]; JnlBatchSeries: Code[20]; var ItemJournalLine: Record "Item Journal Line"; EntryType: Enum "Item Ledger Entry Type"; PostingDate: Date; ItemNo: Code[20]; Qty: Decimal; LocationCode: Code[10]) var + NoSeries: Codeunit "No. Series"; LineNo: Integer; begin with ItemJournalLine do begin @@ -85,7 +85,7 @@ codeunit 147100 "Library - CD Tracking" "Line No." := LineNo; Insert(true); Validate("Posting Date", PostingDate); - "Document No." := NoSeriesManagement.GetNextNo(JnlBatchSeries, "Posting Date", true); + "Document No." := NoSeries.GetNextNo(JnlBatchSeries, "Posting Date"); Validate("Entry Type", EntryType); Validate("Item No.", ItemNo); Validate(Quantity, Qty); diff --git a/Apps/RU/Onprem Permissions RU/app/app.json b/Apps/RU/Onprem Permissions RU/app/app.json index ad6b4b85b7..e24cf64e47 100644 --- a/Apps/RU/Onprem Permissions RU/app/app.json +++ b/Apps/RU/Onprem Permissions RU/app/app.json @@ -2,7 +2,7 @@ "id": "60cc5b06-2c23-47e0-b26c-b58c98ad0acd", "name": "OnPrem Permissions (RU)", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "This extension includes permission set for on premise systems.", "description": "This extension includes permission set for on premise systems.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -17,12 +17,12 @@ "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "resourceExposurePolicy": { "allowDebugging": false, "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, "target": "OnPrem", - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/SE/ContosoCoffeeDemoDatasetSE/app/app.json b/Apps/SE/ContosoCoffeeDemoDatasetSE/app/app.json index a10854e12b..45fc8f84b6 100644 --- a/Apps/SE/ContosoCoffeeDemoDatasetSE/app/app.json +++ b/Apps/SE/ContosoCoffeeDemoDatasetSE/app/app.json @@ -2,7 +2,7 @@ "id": "5b0a41a1-7b42-4123-a521-2265356bab31", "name": "Contoso Coffee Demo Dataset (SE)", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "To help partners demonstrate the capabilities of Business Central, we are making new and extensive demo data available for various scenarios.", "description": "Presales specialists can run the tool on top of Cronus or My Company and get the setup and demo data they'll need when they demonstrate various scenarios.", "privacyStatement": "https://go.microsoft.com/fwlink/?linkid=724009", @@ -16,14 +16,14 @@ "id": "5a0b41e9-7a42-4123-d521-2265186cfb31", "name": "Contoso Coffee Demo Dataset", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 11299, diff --git a/Apps/SE/IntrastatSE/app/app.json b/Apps/SE/IntrastatSE/app/app.json index 2b51106879..11b813e20b 100644 --- a/Apps/SE/IntrastatSE/app/app.json +++ b/Apps/SE/IntrastatSE/app/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "The Intrastat extension makes it easy to export the Intrastat report in the format that the authorities in your country require.", "description": "The formats that businesses must use to report Intrastat vary from country to country. The Intrastat extension makes it easy to export the Intrastat report in the format that the authorities in your country require.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=2204541", @@ -16,13 +16,13 @@ "id": "70912191-3c4c-49fc-a1de-bc6ea1ac9da6", "name": "Intrastat Core", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 11298, @@ -34,6 +34,6 @@ "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0", + "application": "25.0.0.0", "target": "Cloud" } \ No newline at end of file diff --git a/Apps/SE/SECore/app/app.json b/Apps/SE/SECore/app/app.json index 5ca58c3edc..b8d30b9239 100644 --- a/Apps/SE/SECore/app/app.json +++ b/Apps/SE/SECore/app/app.json @@ -2,7 +2,7 @@ "id": "275032ba-04a6-457f-bc79-1ffe6cb63596", "name": "SE Core", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Provides standard local functionality in Business Central for Sweden.", "description": "Provides standard local functionality in Business Central for Sweden.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -17,8 +17,8 @@ "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 11210, diff --git a/Apps/SE/SECore/test/app.json b/Apps/SE/SECore/test/app.json index cff1e1908a..5012aeb125 100644 --- a/Apps/SE/SECore/test/app.json +++ b/Apps/SE/SECore/test/app.json @@ -2,7 +2,7 @@ "id": "169efe4b-2e9e-4d0d-8ec4-24c1b9a580de", "name": "SE Core Tests", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Tests for the Core Localization for Sweden.", "description": "Tests for the Core Localization for Sweden.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -16,20 +16,20 @@ "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "275032ba-04a6-457f-bc79-1ffe6cb63596", "name": "SE Core", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 148161, diff --git a/Apps/SE/SIE/app/app.json b/Apps/SE/SIE/app/app.json index 641b2d2451..65e4ad7e86 100644 --- a/Apps/SE/SIE/app/app.json +++ b/Apps/SE/SIE/app/app.json @@ -2,7 +2,7 @@ "id": "a98932e6-0fbc-4f74-a39b-f159b068d424", "name": "Standard Import Export (SIE)", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "The Standard Import Export (SIE) extension makes it easy to import and export general ledger data in the format that the authorities in your country require.", "description": "As a part of the audit reporting in Sweden, companies must be able to import and export general ledger data according to the standard import export (SIE) format. This feature enables using SIE format within Audit File Export app, where you can specify SIE dimensions and file types as well as the level of detail covered by import or export transactions.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -16,14 +16,14 @@ "id": "a41b0c3e-bf1c-4c97-ad1b-b430a3933ada", "name": "Audit File Export", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 5314, diff --git a/Apps/SE/SIE/app/src/ImportEngineSIE/ImportSIE.Report.al b/Apps/SE/SIE/app/src/ImportEngineSIE/ImportSIE.Report.al index 033774a332..6e8503201e 100644 --- a/Apps/SE/SIE/app/src/ImportEngineSIE/ImportSIE.Report.al +++ b/Apps/SE/SIE/app/src/ImportEngineSIE/ImportSIE.Report.al @@ -184,7 +184,7 @@ report 5314 "Import SIE" GenJournalBatch: Record "Gen. Journal Batch"; GenJournalLineGlobal: Record "Gen. Journal Line"; GLAccount: Record "G/L Account"; - NoSeriesMgt: Codeunit NoSeriesManagement; + NoSeriesBatch: Codeunit "No. Series - Batch"; FeatureTelemetry: Codeunit "Feature Telemetry"; TempBlobGlobal: Codeunit "Temp Blob"; DimensionsSiePage: Page "Dimensions SIE"; @@ -300,7 +300,7 @@ report 5314 "Import SIE" else DocumentNo := CopyStr(DelChr(TempImportBufferSie."Import Field 3", '=', '"'), 1, MaxStrLen(DocumentNo)); if StrLen(DocumentNo) = 0 then - DocumentNo := NoSeriesMgt.GetNextNo(GenJournalBatch."No. Series", WorkDate(), false); + DocumentNo := NoSeriesBatch.GetNextNo(GenJournalBatch."No. Series"); TempImportBufferSie."Import Field 4" := DelChr(TempImportBufferSie."Import Field 4", '=<>', DelChr(TempImportBufferSie."Import Field 4", '=<>', '0123456789')); // File format YYYYMMDD according to swedish standard @@ -393,7 +393,7 @@ report 5314 "Import SIE" GenJournalLine: Record "Gen. Journal Line"; begin if DocumentNo = '' then - DocumentNo := NoSeriesMgt.GetNextNo(GenJournalBatch."No. Series", WorkDate(), false); + DocumentNo := NoSeriesBatch.GetNextNo(GenJournalBatch."No. Series"); GenJournalLine.Init(); GenJournalLine."Journal Template Name" := GenJournalBatch."Journal Template Name"; GenJournalLine."Journal Batch Name" := GenJournalBatch.Name; diff --git a/Apps/SE/SIE/test/app.json b/Apps/SE/SIE/test/app.json index 09b25455f2..a3f5df44aa 100644 --- a/Apps/SE/SIE/test/app.json +++ b/Apps/SE/SIE/test/app.json @@ -2,7 +2,7 @@ "id": "f0122068-7fc6-4247-853e-5b362e8b3934", "name": "SIE Tests", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Tests for the SIE extension.", "description": "Tests for the SIE extension.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -11,38 +11,38 @@ "url": "https://go.microsoft.com/fwlink/?LinkId=724011", "contextSensitiveHelpUrl": "https://go.microsoft.com/fwlink/?linkid=2141039", "logo": "ExtensionLogo.png", - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "dependencies": [ { "id": "a98932e6-0fbc-4f74-a39b-f159b068d424", "name": "Standard Import Export (SIE)", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "a41b0c3e-bf1c-4c97-ad1b-b430a3933ada", "name": "Audit File Export", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "9856ae4f-d1a7-46ef-89bb-6ef056398228", "name": "System Application Test Library", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5095f467-0a01-4b99-99d1-9ff1237d286f", "publisher": "Microsoft", "name": "Library Variable Storage", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "idRanges": [ diff --git a/Apps/US/ContosoCoffeeDemoDatasetUS/app/app.json b/Apps/US/ContosoCoffeeDemoDatasetUS/app/app.json index aa6b4604f3..880da29be7 100644 --- a/Apps/US/ContosoCoffeeDemoDatasetUS/app/app.json +++ b/Apps/US/ContosoCoffeeDemoDatasetUS/app/app.json @@ -2,7 +2,7 @@ "id": "3a3f33b1-7b42-4123-a521-2265186cfb31", "name": "Contoso Coffee Demo Dataset (US)", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "To help partners demonstrate the capabilities of Business Central, we are making new and extensive demo data available for various scenarios.", "description": "Presales specialists can run the tool on top of Cronus or My Company and get the setup and demo data they'll need when they demonstrate various scenarios.", "privacyStatement": "https://go.microsoft.com/fwlink/?linkid=724009", @@ -16,14 +16,14 @@ "id": "5a0b41e9-7a42-4123-d521-2265186cfb31", "name": "Contoso Coffee Demo Dataset", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 10495, diff --git a/Apps/US/HybridBCLast_US/app/app.json b/Apps/US/HybridBCLast_US/app/app.json index d25e807ab9..00b32b81a0 100644 --- a/Apps/US/HybridBCLast_US/app/app.json +++ b/Apps/US/HybridBCLast_US/app/app.json @@ -2,7 +2,7 @@ "id": "638dd7bc-cb27-4c70-9e1d-963fdd46da19", "name": "Business Central Cloud Migration - Previous Release (US)", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Enables data migration from the previous version of Dynamics BC (n-1) to the current release of Dynamics 365 Business Central SaaS.", "description": "This extension, in conjuction with the Business Central Cloud Migration Previous Release, will enable you to migrate data from your Business Central on-premises solution for United States to your Dynamics 365 Business Central cloud tenant for United States. This extension is required to update country specific tables. Once you have walked through the cloud migration wizard in assisted setup, you will be able to migrate your data from your on-premises environment to your cloud tenant.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -15,25 +15,25 @@ { "publisher": "Microsoft", "name": "Intelligent Cloud Base", - "version": "24.0.0.0", + "version": "25.0.0.0", "id": "58623bfa-0559-4bc2-ae1c-0979c29fd9e0" }, { "publisher": "Microsoft", "name": "Business Central Cloud Migration - Previous Release", - "version": "24.0.0.0", + "version": "25.0.0.0", "id": "6992416f-3f39-4d3c-8242-3fff61350bea" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "resourceExposurePolicy": { "allowDebugging": false, "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, "target": "OnPrem", - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/US/HybridGP_US/app/app.json b/Apps/US/HybridGP_US/app/app.json index b177210abc..fb87427b2a 100644 --- a/Apps/US/HybridGP_US/app/app.json +++ b/Apps/US/HybridGP_US/app/app.json @@ -2,7 +2,7 @@ "id": "abe5dab1-9b38-44fc-a5f2-747ca8f4551e", "name": "Dynamics GP Intelligent Cloud - US", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "This extension migrates US specific information during a GP migration.", "description": "This extension migrates US specific information during a GP migration, such as Vendor 1099 data.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -16,20 +16,20 @@ "id": "58623bfa-0559-4bc2-ae1c-0979c29fd9e0", "name": "Intelligent Cloud Base", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "feeb3504-556e-4790-b28d-a2b9ce302d81", "name": "Dynamics GP Intelligent Cloud", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "resourceExposurePolicy": { "allowDebugging": true, "allowDownloadingSource": true, diff --git a/Apps/US/HybridGP_US/app/src/Codeunits/GPPopulateVendor1099Data.Codeunit.al b/Apps/US/HybridGP_US/app/src/Codeunits/GPPopulateVendor1099Data.Codeunit.al index ab08ff59c1..4e4fff8d3c 100644 --- a/Apps/US/HybridGP_US/app/src/Codeunits/GPPopulateVendor1099Data.Codeunit.al +++ b/Apps/US/HybridGP_US/app/src/Codeunits/GPPopulateVendor1099Data.Codeunit.al @@ -47,7 +47,9 @@ codeunit 42003 "GP Populate Vendor 1099 Data" local procedure UpdateAllVendorTaxInfo() begin Initialize(); +#if not CLEAN25 UpdateVendorTaxInfo(); +#endif CleanUp(); end; @@ -81,6 +83,7 @@ codeunit 42003 "GP Populate Vendor 1099 Data" DataMigrationFacadeHelper.CreateSourceCodeIfNeeded(SourceCodeTxt); end; +#if not CLEAN25 local procedure UpdateVendorTaxInfo() var GPPM00200: Record "GP PM00200"; @@ -124,12 +127,13 @@ codeunit 42003 "GP Populate Vendor 1099 Data" end else LogVendorSkipped(Vendor."No."); end; +#endif local procedure AddVendor1099Values(var Vendor: Record Vendor) var InvoiceGenJournalLine: Record "Gen. Journal Line"; PaymentGenJournalLine: Record "Gen. Journal Line"; - NoSeriesManagement: Codeunit NoSeriesManagement; + NoSeries: Codeunit "No. Series"; VendorYear1099AmountDictionary: Dictionary of [Code[10], Decimal]; IRS1099Code: Code[10]; TaxAmount: Decimal; @@ -157,7 +161,7 @@ codeunit 42003 "GP Populate Vendor 1099 Data" if TaxAmount > 0 then begin // Invoice InvoiceExternalDocumentNo := CopyStr(Vendor."No." + '-' + IRS1099Code + '-INV', 1, MaxStrLen(InvoiceExternalDocumentNo)); - InvoiceDocumentNo := NoSeriesManagement.GetNextNo(VendorTaxNoSeriesTxt, 0D, true); + InvoiceDocumentNo := NoSeries.GetNextNo(VendorTaxNoSeriesTxt); InvoiceCreated := CreateGeneralJournalLine(InvoiceGenJournalLine, Vendor."No.", "Gen. Journal Document Type"::Invoice, @@ -171,7 +175,7 @@ codeunit 42003 "GP Populate Vendor 1099 Data" // Payment PaymentExternalDocumentNo := CopyStr(Vendor."No." + '-' + IRS1099Code + '-PMT', 1, MaxStrLen(PaymentExternalDocumentNo)); - PaymentDocumentNo := NoSeriesManagement.GetNextNo(VendorTaxNoSeriesTxt, 0D, true); + PaymentDocumentNo := NoSeries.GetNextNo(VendorTaxNoSeriesTxt); PaymentCreated := CreateGeneralJournalLine(PaymentGenJournalLine, Vendor."No.", "Gen. Journal Document Type"::Payment, @@ -234,8 +238,10 @@ codeunit 42003 "GP Populate Vendor 1099 Data" until GPPM00204.Next() = 0; end; +#pragma warning disable AA0137 local procedure CreateGeneralJournalLine(var GenJournalLine: Record "Gen. Journal Line"; VendorNo: Code[20]; DocumentType: enum "Gen. Journal Document Type"; DocumentNo: Code[20]; Description: Text[50]; AccountNo: Code[20]; Amount: Decimal; BalancingAccount: Code[20]; IRS1099Code: Code[10]; ExternalDocumentNo: Code[35]): boolean +#pragma warning restore AA0137 var GenJournalBatch: Record "Gen. Journal Batch"; GenJournalLineCurrent: Record "Gen. Journal Line"; @@ -276,7 +282,9 @@ codeunit 42003 "GP Populate Vendor 1099 Data" GenJournalLine.Validate("Bal. Gen. Prod. Posting Group", ''); GenJournalLine.Validate("Bal. VAT Prod. Posting Group", ''); GenJournalLine.Validate("Bal. VAT Bus. Posting Group", ''); +#if not CLEAN25 GenJournalLine.Validate("IRS 1099 Code", IRS1099Code); +#endif GenJournalLine.Validate("Document Type", DocumentType); GenJournalLine.Validate("Source Code", SourceCodeTxt); GenJournalLine.Validate("External Document No.", ExternalDocumentNo); diff --git a/Apps/US/HybridGP_US/test/app.json b/Apps/US/HybridGP_US/test/app.json index 1622e7b3d1..2601ed51c2 100644 --- a/Apps/US/HybridGP_US/test/app.json +++ b/Apps/US/HybridGP_US/test/app.json @@ -2,7 +2,7 @@ "id": "769bbf93-6868-4281-aec1-1cef12e56a80", "name": "Dynamics GP Intelligent Cloud - US Tests", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Tests for Dynamics GP Intelligent Cloud US", "description": "Tests for Dynamics GP Intelligent Cloud US", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -16,26 +16,26 @@ "id": "feeb3504-556e-4790-b28d-a2b9ce302d81", "name": "Dynamics GP Intelligent Cloud", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "abe5dab1-9b38-44fc-a5f2-747ca8f4551e", "name": "Dynamics GP Intelligent Cloud - US", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 139500, diff --git a/Apps/US/HybridGP_US/test/src/MigrationVendor1099Tests.Codeunit.al b/Apps/US/HybridGP_US/test/src/MigrationVendor1099Tests.Codeunit.al index 5ac07b477a..0ec9609276 100644 --- a/Apps/US/HybridGP_US/test/src/MigrationVendor1099Tests.Codeunit.al +++ b/Apps/US/HybridGP_US/test/src/MigrationVendor1099Tests.Codeunit.al @@ -198,7 +198,9 @@ codeunit 139684 "Migration Vendor 1099 Tests" // [THEN] The Vendor record will have correct 1099 data Assert.IsTrue(Vendor.Get(TestVendorNoLbl), 'Vendor not found.'); +#if not CLEAN25 Assert.AreEqual('NEC-01', Vendor."IRS 1099 Code", 'Incorrect IRS 1099 Code.'); +#endif Assert.AreEqual('123456789', Vendor."Federal ID No.", 'Incorrect Federal ID No.'); Assert.AreEqual(Vendor."Tax Identification Type"::"Legal Entity", Vendor."Tax Identification Type", 'Incorrect Tax Identification Type.'); @@ -214,8 +216,10 @@ codeunit 139684 "Migration Vendor 1099 Tests" DocumentNo := VendorLedgerEntry."Document No."; Assert.AreEqual('NEC-01', VendorLedgerEntry.Description, 'Invoice Vendor ledger entry description is incorrect.'); +#if not CLEAN25 Assert.AreEqual('NEC-01', VendorLedgerEntry."IRS 1099 Code", 'Invoice Vendor ledger entry IRS 1099 Code is incorrect.'); Assert.AreEqual(-120, VendorLedgerEntry."IRS 1099 Amount", 'Invoice Vendor ledger entry IRS 1099 Amount is incorrect.'); +#endif Assert.AreEqual(0, VendorLedgerEntry."Remaining Amount", 'Invoice Vendor ledger entry Remaining Amount should be zero.'); VendorLedgerEntry.SetRange("Vendor No.", TestVendorNoLbl); @@ -223,7 +227,9 @@ codeunit 139684 "Migration Vendor 1099 Tests" VendorLedgerEntry.SetRange(Description, 'NEC-01'); Assert.IsTrue(VendorLedgerEntry.FindFirst(), 'NEC-01 Payment Vendor ledger entry not found.'); Assert.AreEqual('NEC-01', VendorLedgerEntry.Description, 'Payment Vendor ledger entry description is incorrect.'); +#if not CLEAN25 Assert.AreEqual('NEC-01', VendorLedgerEntry."IRS 1099 Code", 'Payment Vendor ledger entry IRS 1099 Code is incorrect.'); +#endif DetailedVendorLedgEntry.SetRange("Vendor No.", TestVendorNoLbl); DetailedVendorLedgEntry.SetRange("Initial Document Type", DetailedVendorLedgEntry."Initial Document Type"::Payment); diff --git a/Apps/US/IRS1096/app/app.json b/Apps/US/IRS1096/app/app.json index 0fb47b4914..4fe120da6a 100644 --- a/Apps/US/IRS1096/app/app.json +++ b/Apps/US/IRS1096/app/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "Easily report IRS 1096 form.", "description": "This app provides functionality that enables an easy overview and reporting of the 1096 form to IRS.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://learn.microsoft.com/en-us/dynamics365/business-central/localfunctionality/unitedstates/set-up-use-irs1096-form", @@ -17,7 +17,7 @@ "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 10016, @@ -29,6 +29,6 @@ "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0", + "application": "25.0.0.0", "target": "Cloud" } \ No newline at end of file diff --git a/Apps/US/IRS1096/app/src/Processing/IRS1096FormHeader.Table.al b/Apps/US/IRS1096/app/src/Processing/IRS1096FormHeader.Table.al index 650819c86b..34e9d46700 100644 --- a/Apps/US/IRS1096/app/src/Processing/IRS1096FormHeader.Table.al +++ b/Apps/US/IRS1096/app/src/Processing/IRS1096FormHeader.Table.al @@ -19,6 +19,8 @@ table 10018 "IRS 1096 Form Header" Caption = 'No.'; trigger OnValidate() + var + NoSeries: Codeunit "No. Series"; begin if "No." <> xRec."No." then begin PurchPayablesSetup.GetRecordOnce(); @@ -120,11 +122,13 @@ table 10018 "IRS 1096 Form Header" var PurchPayablesSetup: Record "Purchases & Payables Setup"; +#if not CLEAN24 NoSeriesManagement: Codeunit NoSeriesManagement; - NoSeries: Codeunit "No. Series"; +#endif trigger OnInsert() var + NoSeries: Codeunit "No. Series"; IsHandled: Boolean; begin IsHandled := false; @@ -168,6 +172,7 @@ table 10018 "IRS 1096 Form Header" procedure AssistEdit(xIRS1096FormHeader: Record "IRS 1096 Form Header") Result: Boolean var IRS1096FormHeader: Record "IRS 1096 Form Header"; + NoSeries: Codeunit "No. Series"; IsHandled: Boolean; begin IsHandled := false; @@ -177,8 +182,8 @@ table 10018 "IRS 1096 Form Header" IRS1096FormHeader := Rec; GetPurchSetupWithIRS1096NoSeries(); - if NoSeriesManagement.SelectSeries(PurchPayablesSetup."IRS 1096 Form No. Series", xIRS1096FormHeader."No. Series", IRS1096FormHeader."No. Series") then begin - NoSeriesManagement.SetSeries(IRS1096FormHeader."No."); + if NoSeries.LookupRelatedNoSeries(PurchPayablesSetup."IRS 1096 Form No. Series", xIRS1096FormHeader."No. Series", IRS1096FormHeader."No. Series") then begin + IRS1096FormHeader."No." := NoSeries.GetNextNo(IRS1096FormHeader."No. Series"); Rec := IRS1096FormHeader; exit(true); end; diff --git a/Apps/US/IRS1096/app/src/Processing/IRS1096FormLine.Table.al b/Apps/US/IRS1096/app/src/Processing/IRS1096FormLine.Table.al index 1d5f86d5a1..9645f2713e 100644 --- a/Apps/US/IRS1096/app/src/Processing/IRS1096FormLine.Table.al +++ b/Apps/US/IRS1096/app/src/Processing/IRS1096FormLine.Table.al @@ -23,7 +23,9 @@ table 10019 "IRS 1096 Form Line" field(3; "IRS Code"; Code[20]) { Caption = 'IRS Code'; +#if not CLEAN25 TableRelation = "IRS 1099 Form-Box"; +#endif } field(4; "Vendor No."; Code[20]) { @@ -86,10 +88,13 @@ table 10019 "IRS 1096 Form Line" procedure ShowAdjustments() var +#if not CLEAN25 IRS1096FormHeader: Record "IRS 1096 Form Header"; IRS1099Adjustment: Record "IRS 1099 Adjustment"; IRS1099Adjustments: Page "IRS 1099 Adjustments"; +#endif begin +#if not CLEAN25 IRS1096FormHeader.Get("Form No."); IRS1099Adjustment.SetRange(Year, Date2DMY(IRS1096FormHeader."Starting Date", 3), Date2DMY(IRS1096FormHeader."Ending Date", 3)); IRS1099Adjustment.SetRange("Vendor No.", "Vendor No."); @@ -97,8 +102,10 @@ table 10019 "IRS 1096 Form Line" IRS1099Adjustments.Editable := false; IRS1099Adjustments.SetTableView(IRS1099Adjustment); IRS1099Adjustments.Run(); +#endif end; + local procedure UpdateHeaderTotals() var IRS1096FormLine: Record "IRS 1096 Form Line"; diff --git a/Apps/US/IRS1096/app/src/Processing/IRS1096FormMgt.Codeunit.al b/Apps/US/IRS1096/app/src/Processing/IRS1096FormMgt.Codeunit.al index e678789d45..63d317a26e 100644 --- a/Apps/US/IRS1096/app/src/Processing/IRS1096FormMgt.Codeunit.al +++ b/Apps/US/IRS1096/app/src/Processing/IRS1096FormMgt.Codeunit.al @@ -9,7 +9,9 @@ using Microsoft.Utilities; using System.Environment.Configuration; using System.Media; using System.Telemetry; +#if not CLEAN25 using System.Utilities; +#endif codeunit 10016 "IRS 1096 Form Mgt." { @@ -29,7 +31,9 @@ codeunit 10016 "IRS 1096 Form Mgt." FeatureNotEnabledMessageTxt: Label 'The %1 page is part of the new IRS 1096 feature, which is not yet enabled in your Business Central. An administrator can enable the feature on the Feature Management page.', Comment = '%1 - page caption'; #endif NoEntriesToCreateFormsMsg: Label 'No entries have been found by filters specified.'; +#if not CLEAN25 FormPerPeriodAlreadyExistsQst: Label 'The form %1 for the period from %2 to %3 already exist. If you want to replace it, use the Replace parameter on the request page. Do you want to stop the creation of forms?', Comment = '%1 - code of the form, %2,%3 - starting and ending dates of the period'; +#endif FormsCreatedMsg: Label 'IRS 1096 forms have been created'; AssistedSetupTxt: Label 'Set up an IRS 1096 feature'; AssistedSetupDescriptionTxt: Label 'This feature provides functionality that enables an easy overview and reporting of the 1096 form to IRS.'; @@ -65,12 +69,16 @@ codeunit 10016 "IRS 1096 Form Mgt." TempVendorLedgerEntry: Record "Vendor Ledger Entry" temporary; TempIRS1096FormHeader: Record "IRS 1096 Form Header" temporary; TempCreatedIRS1096FormHeader: Record "IRS 1096 Form Header" temporary; +#if not CLEAN25 TempIRS1096FormLine: Record "IRS 1096 Form Line" temporary; +#endif IRS1096FormHeader: Record "IRS 1096 Form Header"; IRS1096FormLine: Record "IRS 1096 Form Line"; EntryApplicationManagement: Codeunit "Entry Application Management"; PeriodDate: array[2] of Date; +#if not CLEAN25 ConflictResolved: Boolean; +#endif begin PeriodDate[1] := StartDate; PeriodDate[2] := EndDate; @@ -94,9 +102,13 @@ codeunit 10016 "IRS 1096 Form Mgt." IRS1096FormHeader.LockTable(); IRS1096FormLine.LockTable(); repeat +#if not CLEAN25 AddVendLedgEntryToFormBuffer(TempIRS1096FormLine, TempIRS1096FormHeader, TempCreatedIRS1096FormHeader, ConflictResolved, TempVendorLedgerEntry, PeriodDate, Replace); +#endif until TempVendorLedgerEntry.Next() = 0; +#if not CLEAN25 InsertFromFormBuffer(TempCreatedIRS1096FormHeader, TempIRS1096FormLine); +#endif if TempCreatedIRS1096FormHeader.IsEmpty() then begin if GuiAllowed() then Message(NoFormsHaveBeenCreatedMsg); @@ -215,6 +227,7 @@ codeunit 10016 "IRS 1096 Form Mgt." IRS1096FormHeader.Modify(true); end; +#if not CLEAN25 local procedure AddVendLedgEntryToFormBuffer(var TempIRS1096FormLine: Record "IRS 1096 Form Line" temporary; var TempIRS1096FormHeader: Record "IRS 1096 Form Header" temporary; var TempCreatedIRS1096FormHeader: Record "IRS 1096 Form Header" temporary; var ConflictResolved: Boolean; VendLedgEntry: Record "Vendor Ledger Entry"; PeriodDate: array[2] of Date; Replace: Boolean) var IRS1096FormHeader: Record "IRS 1096 Form Header"; @@ -227,7 +240,9 @@ codeunit 10016 "IRS 1096 Form Mgt." If (VendLedgEntry."IRS 1099 Code" = '') or (VendLedgEntry."IRS 1099 Amount" = 0) then exit; +#if not CLEAN25 General1099Code := GetGeneral1099CodeFromVendLedgEntry(VendLedgEntry); +#endif if General1099Code = '' then exit; @@ -294,7 +309,9 @@ codeunit 10016 "IRS 1096 Form Mgt." TempIRS1096FormLine.Insert(); InsertLineRelation(TempIRS1096FormLine, VendLedgEntry); end; +#endif +#if not CLEAN25 local procedure GetGeneral1099CodeFromVendLedgEntry(VendLedgEntry: Record "Vendor Ledger Entry") IRSCode: Code[20] var IsHandled: Boolean; @@ -312,6 +329,7 @@ codeunit 10016 "IRS 1096 Form Mgt." exit(''); exit(IRSCode); end; +#endif local procedure InsertLineRelation(IRS1096FormLine: Record "IRS 1096 Form Line"; VendLedgEntry: Record "Vendor Ledger Entry") var @@ -323,6 +341,7 @@ codeunit 10016 "IRS 1096 Form Mgt." IRS1096FormLineRelation.Insert(true); end; +#if not CLEAN25 local procedure InsertFromFormBuffer(var TempCreatedIRS1096FormHeader: Record "IRS 1096 Form Header" temporary; var TempIRS1096FormLine: Record "IRS 1096 Form Line" temporary) var IRS1096FormHeader: Record "IRS 1096 Form Header"; @@ -374,6 +393,7 @@ codeunit 10016 "IRS 1096 Form Mgt." end; until TempCreatedIRS1096FormHeader.Next() = 0; end; +#endif [EventSubscriber(ObjectType::Codeunit, Codeunit::"Guided Experience", 'OnRegisterAssistedSetup', '', true, true)] local procedure InsertIntoAssistedSetup() diff --git a/Apps/US/IRS1096/app/src/Processing/IRS1096FormSubform.Page.al b/Apps/US/IRS1096/app/src/Processing/IRS1096FormSubform.Page.al index ed64aca8e7..0135576cb2 100644 --- a/Apps/US/IRS1096/app/src/Processing/IRS1096FormSubform.Page.al +++ b/Apps/US/IRS1096/app/src/Processing/IRS1096FormSubform.Page.al @@ -48,10 +48,12 @@ page 10020 "IRS 1096 Form Subform" ApplicationArea = BasicUS; ToolTip = 'Specifies the adjustment amount per period and IRS code calculated by the Create Forms action on the list page.'; +#if not CLEAN25 trigger OnDrillDown() begin Rec.ShowAdjustments(); end; +#endif } field("Manually Changed"; Rec."Manually Changed") { diff --git a/Apps/US/IRS1096/test/app.json b/Apps/US/IRS1096/test/app.json index 03f7a90c09..131bf63fb8 100644 --- a/Apps/US/IRS1096/test/app.json +++ b/Apps/US/IRS1096/test/app.json @@ -2,7 +2,7 @@ "id": "bd16d8dd-8faf-45d3-b733-3ddc6b9cfabf", "name": "IRS 1096 Tests", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Tests for the Microsoft IRs 1096 extension.", "description": "Tests for the Microsoft IRS 1096 extension.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -10,32 +10,32 @@ "help": "https://learn.microsoft.com/en-us/dynamics365/business-central/localfunctionality/unitedstates/set-up-use-irs1096-form", "url": "https://go.microsoft.com/fwlink/?LinkId=724011", "logo": "ExtensionLogo.png", - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "dependencies": [ { "id": "bf7682b0-67b3-44de-a1e6-676ceb3b05ca", "name": "IRS 1096", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "9856ae4f-d1a7-46ef-89bb-6ef056398228", "name": "System Application Test Library", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5095f467-0a01-4b99-99d1-9ff1237d286f", "publisher": "Microsoft", "name": "Library Variable Storage", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "idRanges": [ diff --git a/Apps/US/IRS1096/test/src/Create1096FormsTest.Codeunit.al b/Apps/US/IRS1096/test/src/Create1096FormsTest.Codeunit.al index 197f56e77d..3c594f0c6e 100644 --- a/Apps/US/IRS1096/test/src/Create1096FormsTest.Codeunit.al +++ b/Apps/US/IRS1096/test/src/Create1096FormsTest.Codeunit.al @@ -1,7 +1,11 @@ +#if not CLEAN25 codeunit 144041 "Create 1096 Forms Test" { Subtype = Test; TestPermissions = Disabled; + ObsoleteReason = 'Moved to IRS Forms App.'; + ObsoleteState = Pending; + ObsoleteTag = '25.0'; var LibraryTestInitialize: Codeunit "Library - Test Initialize"; @@ -733,4 +737,5 @@ codeunit 144041 "Create 1096 Forms Test" LibraryVariableStorage.Enqueue(IRS1096Form.ContactName); IRS1096Form.Cancel().Invoke(); end; -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/Apps/US/IRSForms/app/ExtensionLogo.png b/Apps/US/IRSForms/app/ExtensionLogo.png new file mode 100644 index 0000000000000000000000000000000000000000..4d2c9a626cb9617350617c40cd73904129d4c108 GIT binary patch literal 5446 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 literal 0 HcmV?d00001 diff --git a/Apps/US/IRSForms/app/Permissions/D365BasicIRSForms.PermissionsetExt.al b/Apps/US/IRSForms/app/Permissions/D365BasicIRSForms.PermissionsetExt.al new file mode 100644 index 0000000000..09b71d9e4f --- /dev/null +++ b/Apps/US/IRSForms/app/Permissions/D365BasicIRSForms.PermissionsetExt.al @@ -0,0 +1,12 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +using System.Security.AccessControl; + +permissionsetextension 10033 "D365 BASIC - IRS Forms" extends "D365 BASIC" +{ + IncludedPermissionSets = "IRS Forms - Edit"; +} diff --git a/Apps/US/IRSForms/app/Permissions/D365BasicISVIRSForms.PermissionsetExt.al b/Apps/US/IRSForms/app/Permissions/D365BasicISVIRSForms.PermissionsetExt.al new file mode 100644 index 0000000000..86906d5567 --- /dev/null +++ b/Apps/US/IRSForms/app/Permissions/D365BasicISVIRSForms.PermissionsetExt.al @@ -0,0 +1,12 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +using System.Security.AccessControl; + +permissionsetextension 10034 "D365 BASIC ISV - IRS Forms" extends "D365 BASIC ISV" +{ + IncludedPermissionSets = "IRS Forms - Edit"; +} diff --git a/Apps/US/IRSForms/app/Permissions/D365ReadIRSForms.PermissionsetExt.al b/Apps/US/IRSForms/app/Permissions/D365ReadIRSForms.PermissionsetExt.al new file mode 100644 index 0000000000..7366e1a8d2 --- /dev/null +++ b/Apps/US/IRSForms/app/Permissions/D365ReadIRSForms.PermissionsetExt.al @@ -0,0 +1,12 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +using System.Security.AccessControl; + +permissionsetextension 10035 "D365 READ - IRS Forms" extends "D365 READ" +{ + IncludedPermissionSets = "IRS Forms - Read"; +} diff --git a/Apps/US/IRSForms/app/Permissions/D365TeamMemberIRSForms.PermissionsetExt.al b/Apps/US/IRSForms/app/Permissions/D365TeamMemberIRSForms.PermissionsetExt.al new file mode 100644 index 0000000000..cda445a955 --- /dev/null +++ b/Apps/US/IRSForms/app/Permissions/D365TeamMemberIRSForms.PermissionsetExt.al @@ -0,0 +1,12 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +using System.Security.AccessControl; + +permissionsetextension 10036 "D365 TEAM MEMBER - IRS Forms" extends "D365 TEAM MEMBER" +{ + IncludedPermissionSets = "IRS Forms - Edit"; +} diff --git a/Apps/US/IRSForms/app/Permissions/IRSFormsEdit.PermissionSet.al b/Apps/US/IRSForms/app/Permissions/IRSFormsEdit.PermissionSet.al new file mode 100644 index 0000000000..ca3a254db0 --- /dev/null +++ b/Apps/US/IRSForms/app/Permissions/IRSFormsEdit.PermissionSet.al @@ -0,0 +1,27 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +permissionset 10031 "IRS Forms - Edit" +{ + Access = Public; + Assignable = true; + + IncludedPermissionSets = "IRS Forms - Read"; + + Permissions = tabledata "IRS Forms Setup" = IMD, + tabledata "IRS Reporting Period" = IMD, + tabledata "IRS 1099 Vendor Form Box Setup" = IMD, + tabledata "IRS 1099 Form Statement Line" = IMD, + tabledata "IRS 1099 Form Doc. Line" = IMD, + tabledata "IRS 1099 Form Doc. Line Detail" = IMD, + tabledata "IRS 1099 Form Doc. Header" = IMD, + tabledata "IRS 1099 Form" = IMD, + tabledata "IRS 1099 Form Box" = IMD, + tabledata "IRS 1099 Form Report" = IMD, + tabledata "IRS 1099 Form Instruction" = IMD, + tabledata "IRS 1099 Vendor Form Box Adj." = IMD, + tabledata "IRS 1099 Email Queue" = IMD; +} diff --git a/Apps/US/IRSForms/app/Permissions/IRSFormsObjects.PermissionSet.al b/Apps/US/IRSForms/app/Permissions/IRSFormsObjects.PermissionSet.al new file mode 100644 index 0000000000..cbac4b9f21 --- /dev/null +++ b/Apps/US/IRSForms/app/Permissions/IRSFormsObjects.PermissionSet.al @@ -0,0 +1,51 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +permissionset 10032 "IRS Forms - Objects" +{ + Access = Public; + Assignable = false; + + Permissions = table "IRS 1099 Calc. Params" = X, + table "IRS 1099 Email Queue" = X, + table "IRS 1099 Form Statement Line" = X, + table "IRS 1099 Form Doc. Line" = X, + table "IRS 1099 Form Doc. Line Detail" = X, + table "IRS 1099 Form Doc. Header" = X, + table "IRS 1099 Form" = X, + table "IRS 1099 Form Box" = X, + table "IRS 1099 Form Report" = X, + table "IRS 1099 Form Instruction" = X, + table "IRS 1099 Print Params" = X, + table "IRS 1099 Vendor Form Box Adj." = X, + table "IRS 1099 Vendor Form Box Setup" = X, + table "IRS 1099 Vend. Form Box Buffer" = X, + table "IRS Forms Setup" = X, + table "IRS Reporting Period" = X, + page "IRS 1099 Form Boxes" = X, + page "IRS 1099 Form Documents" = X, + page "IRS 1099 Form Document" = X, + page "IRS 1099 Form Doc. Subform" = X, + page "IRS 1099 Form Doc Line Details" = X, + page "IRS 1099 Form Instructions" = X, + page "IRS 1099 Form Reports" = X, + page "IRS 1099 Form Statement" = X, + page "IRS 1099 Forms" = X, + page "IRS 1099 Vendor Form Box Setup" = X, + page "IRS 1099 Vend. Form Box Adjmts" = X, + page "IRS Forms Guide" = X, + page "IRS Forms Setup" = X, + page "IRS Reporting Periods" = X, + codeunit "IRS 1099 Send Email" = X, + codeunit "IRS 1099 Form Document" = X, + codeunit "IRS 1099 Vendor Form Box" = X, + codeunit "IRS Forms Data" = X, + codeunit "IRS Forms Facade" = X, + codeunit "IRS Reporting Period" = X, + report "IRS 1099 Create Form Docs" = X, + report "IRS 1099 Print" = X, + report "IRS 1099 Send Email" = X; +} diff --git a/Apps/US/IRSForms/app/Permissions/IRSFormsRead.PermissionSet.al b/Apps/US/IRSForms/app/Permissions/IRSFormsRead.PermissionSet.al new file mode 100644 index 0000000000..7dc6b21acf --- /dev/null +++ b/Apps/US/IRSForms/app/Permissions/IRSFormsRead.PermissionSet.al @@ -0,0 +1,26 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +permissionset 10030 "IRS Forms - Read" +{ + Access = Public; + Assignable = true; + IncludedPermissionSets = "IRS Forms - Objects"; + + Permissions = tabledata "IRS Forms Setup" = R, + tabledata "IRS Reporting Period" = R, + tabledata "IRS 1099 Vendor Form Box Setup" = R, + tabledata "IRS 1099 Form Statement Line" = R, + tabledata "IRS 1099 Form Doc. Line" = R, + tabledata "IRS 1099 Form Doc. Line Detail" = R, + tabledata "IRS 1099 Form Doc. Header" = R, + tabledata "IRS 1099 Form" = R, + tabledata "IRS 1099 Form Box" = R, + tabledata "IRS 1099 Form Report" = R, + tabledata "IRS 1099 Form Instruction" = R, + tabledata "IRS 1099 Vendor Form Box Adj." = R, + tabledata "IRS 1099 Email Queue" = R; +} diff --git a/Apps/US/IRSForms/app/Permissions/IntelligentCloudIRSForms.PermissionsetExt.al b/Apps/US/IRSForms/app/Permissions/IntelligentCloudIRSForms.PermissionsetExt.al new file mode 100644 index 0000000000..91dd9de4c9 --- /dev/null +++ b/Apps/US/IRSForms/app/Permissions/IntelligentCloudIRSForms.PermissionsetExt.al @@ -0,0 +1,12 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +using System.Security.AccessControl; + +permissionsetextension 10037 "INTELLIGENT CLOUD - IRS Forms" extends "INTELLIGENT CLOUD" +{ + IncludedPermissionSets = "IRS Forms - Read"; +} diff --git a/Apps/US/IRSForms/app/Permissions/LocalIRSForms.PermissionsetExt.al b/Apps/US/IRSForms/app/Permissions/LocalIRSForms.PermissionsetExt.al new file mode 100644 index 0000000000..6b7ea958e7 --- /dev/null +++ b/Apps/US/IRSForms/app/Permissions/LocalIRSForms.PermissionsetExt.al @@ -0,0 +1,12 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +using System.Security.AccessControl; + +permissionsetextension 10038 "Local - IRS Forms" extends LOCAL +{ + IncludedPermissionSets = "IRS Forms - Read"; +} diff --git a/Apps/US/IRSForms/app/app.json b/Apps/US/IRSForms/app/app.json new file mode 100644 index 0000000000..30711583ec --- /dev/null +++ b/Apps/US/IRSForms/app/app.json @@ -0,0 +1,40 @@ +{ + "id": "b696b4c9-637c-49d1-a806-763ff8f0a20e", + "name": "IRS Forms", + "publisher": "Microsoft", + "brief": "Easily report IRS 1099 forms.", + "description": "This app provides functionality that enables an easy overview and reporting of the 1099 forms to IRS.", + "version": "25.0.0.0", + "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", + "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", + "help": "https://learn.microsoft.com/en-us/dynamics365/business-central/finance-how-setup-use-service-declaration", + "url": "https://go.microsoft.com/fwlink/?LinkId=724011", + "logo": "ExtensionLogo.png", + "contextSensitiveHelpUrl": "https://go.microsoft.com/fwlink/?linkid=2204541", + "dependencies": [], + "screenshots": [], + "platform": "25.0.0.0", + "internalsVisibleTo": [ + { + "id": "dff12793-4e1c-4f3c-b7d3-331552c4cf5c", + "name": "IRS Forms Test Library", + "publisher": "Microsoft" + } + ], + "features": [ + "TranslationFile" + ], + "idRanges": [ + { + "from": 10030, + "to": 10065 + } + ], + "resourceExposurePolicy": { + "allowDebugging": true, + "allowDownloadingSource": true, + "includeSourceInSymbolFile": true + }, + "application": "25.0.0.0", + "target": "Cloud" +} \ No newline at end of file diff --git a/Apps/US/IRSForms/app/src/Document/IRS1099CalcParams.Table.al b/Apps/US/IRSForms/app/src/Document/IRS1099CalcParams.Table.al new file mode 100644 index 0000000000..293d8e6170 --- /dev/null +++ b/Apps/US/IRSForms/app/src/Document/IRS1099CalcParams.Table.al @@ -0,0 +1,35 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +table 10037 "IRS 1099 Calc. Params" +{ + DataClassification = CustomerContent; + TableType = Temporary; + + fields + { + field(1; "Period No."; Code[20]) + { + } + field(2; "Vendor No."; Code[20]) + { + } + field(3; "Form No."; Code[20]) + { + } + field(10; Replace; Boolean) + { + } + } + + keys + { + key(PK; "Period No.", "Vendor No.", "Form No.") + { + Clustered = true; + } + } +} diff --git a/Apps/US/IRSForms/app/src/Document/IRS1099CreateFormDocs.Report.al b/Apps/US/IRSForms/app/src/Document/IRS1099CreateFormDocs.Report.al new file mode 100644 index 0000000000..d3ac41f9ec --- /dev/null +++ b/Apps/US/IRSForms/app/src/Document/IRS1099CreateFormDocs.Report.al @@ -0,0 +1,145 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +using Microsoft.Purchases.Vendor; +using System.Telemetry; +using System.Utilities; + +report 10035 "IRS 1099 Create Form Docs" +{ + Caption = 'IRS 1099 Create Form Documents'; + ProcessingOnly = true; + ApplicationArea = BasicUS; + + requestpage + { + layout + { + area(content) + { + group(Options) + { + Caption = 'Options'; + field(Period; PeriodNo) + { + ApplicationArea = BasicUS; + Caption = 'Period'; + ToolTip = 'Specifies the period to create a form document for'; + TableRelation = "IRS Reporting Period"; + + trigger OnValidate() + begin + FormNo := ''; + end; + } + field(Vendor; VendorNo) + { + ApplicationArea = BasicUS; + Caption = 'Vendor No.'; + ToolTip = 'Specifies the vendor to create a form document for. If this field is empty then forms will be created for all vendors.'; + TableRelation = Vendor; + } + field(Form; FormNo) + { + ApplicationArea = BasicUS; + Caption = 'Form No.'; + ToolTip = 'Specifies the form to create a form document for. If this field is empty then forms will be created for all forms.'; + TableRelation = "IRS 1099 Form"."No."; + + trigger OnLookup(var Text: Text): Boolean + var + IRS1099Form: Record "IRS 1099 Form"; + IRS1099FormsPage: Page "IRS 1099 Forms"; + begin + if PeriodNo = '' then + Error(PeriodNotSpecifiedErr); + IRS1099Form.SetRange("Period No.", PeriodNo); + IRS1099FormsPage.SetTableView(IRS1099Form); + IRS1099FormsPage.LookupMode(true); + if IRS1099FormsPage.RunModal() = Action::LookupOK then begin + IRS1099FormsPage.GetRecord(IRS1099Form); + FormNo := IRS1099Form."No."; + end; + end; + + trigger OnValidate() + var + IRS1099Form: Record "IRS 1099 Form"; + begin + if PeriodNo = '' then + Error(PeriodNotSpecifiedErr); + if FormNo <> '' then + IRS1099Form.Get(PeriodNo, FormNo); + end; + } + field(ReplaceControl; Replace) + { + ApplicationArea = BasicUS; + Caption = 'Replace'; + ToolTip = 'Specifies whether the newly created forms will replace the existing ones. If this option is not selected then only new forms will be created and the existing ones remain the same.'; + } + } + } + } + } + + var + FeatureTelemetry: Codeunit "Feature Telemetry"; + ReplaceFormsQst: Label 'Do you want to replace the existing 1099 forms with the new ones?'; + PeriodNotSpecifiedErr: Label 'Period is not specified.'; + IRSFormsTok: Label 'IRS Forms', Locked = true; + + protected var + PeriodNo: Code[20]; + VendorNo: Code[20]; + FormNo: Code[20]; + Replace: Boolean; + + trigger OnPreReport() + var + ConfirmManagement: Codeunit "Confirm Management"; + begin + if PeriodNo = '' then + Error(PeriodNotSpecifiedErr); + if not Replace then + exit; + + if not ConfirmManagement.GetResponse(ReplaceFormsQst, false) then + CurrReport.Break(); + end; + + trigger OnPostReport() + var + IRS1099CalcParameters: Record "IRS 1099 Calc. Params"; + IRS1099FormDocument: Codeunit "IRS 1099 Form Document"; + begin + BuildCalcParams(IRS1099CalcParameters); + IRS1099FormDocument.CreateFormDocs(IRS1099CalcParameters); + FeatureTelemetry.LogUptake('0000MJN', IRSFormsTok, Enum::"Feature Uptake Status"::Used); + end; + + procedure InitializeRequest(NewPeriodNo: Code[20]; NewVendorNo: Code[20]; NewFormNo: Code[20]; NewReplace: Boolean) + begin + PeriodNo := NewPeriodNo; + VendorNo := NewVendorNo; + FormNo := NewFormNo; + Replace := NewReplace; + end; + + local procedure BuildCalcParams(var IRS1099CalcParameters: Record "IRS 1099 Calc. Params") + begin + IRS1099CalcParameters."Period No." := PeriodNo; + IRS1099CalcParameters."Vendor No." := VendorNo; + IRS1099CalcParameters."Form No." := FormNo; + IRS1099CalcParameters.Replace := Replace; + OnAfterBuildCalcParams(IRS1099CalcParameters); + end; + + [IntegrationEvent(false, false)] + local procedure OnAfterBuildCalcParams(var IRS1099CalcParameters: Record "IRS 1099 Calc. Params") + begin + end; +} diff --git a/Apps/US/IRSForms/app/src/Document/IRS1099FormDocHeader.Table.al b/Apps/US/IRSForms/app/src/Document/IRS1099FormDocHeader.Table.al new file mode 100644 index 0000000000..f6896b443f --- /dev/null +++ b/Apps/US/IRSForms/app/src/Document/IRS1099FormDocHeader.Table.al @@ -0,0 +1,160 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +using Microsoft.Purchases.Vendor; +using System.EMail; +using System.Utilities; + +table 10035 "IRS 1099 Form Doc. Header" +{ + DataClassification = CustomerContent; + Caption = 'IRS 1099 Form Document Header'; + DataCaptionFields = "Period No.", "Vendor No.", "Form No."; + DrillDownPageId = "IRS 1099 Form Documents"; + LookupPageId = "IRS 1099 Form Documents"; + + fields + { + field(1; ID; Integer) + { + Editable = false; + AutoIncrement = true; + } + field(2; "Period No."; Code[20]) + { + TableRelation = "IRS Reporting Period"; + } + field(3; "Vendor No."; Code[20]) + { + TableRelation = Vendor; + + trigger OnValidate() + var + Vendor: Record Vendor; + begin + TestStatusOpen(); + CheckNoLinesExist(); + CheckPeriodFormVendUniqueness(); + if "Vendor No." <> '' then + if Vendor.Get("Vendor No.") then; + Validate("Receiving 1099 E-Form Consent", Vendor."Receiving 1099 E-Form Consent"); + if Vendor."E-Mail For IRS" = '' then + Validate("Vendor E-Mail", Vendor."E-Mail") + else + Validate("Vendor E-Mail", Vendor."E-Mail For IRS"); + end; + } + field(4; "Form No."; Code[20]) + { + TableRelation = "IRS 1099 Form"."No." where("Period No." = field("Period No.")); + + trigger OnValidate() + begin + TestStatusOpen(); + CheckNoLinesExist(); + CheckPeriodFormVendUniqueness(); + end; + } + field(10; Status; Enum "IRS 1099 Form Doc. Status") + { + Editable = false; + } + field(20; "Copy B Sent"; Boolean) + { + Editable = false; + } + field(21; "Copy 2 Sent"; Boolean) + { + Editable = false; + } + field(22; "Email Error Log"; Text[1024]) + { + Editable = false; + } + field(50; "Receiving 1099 E-Form Consent"; Boolean) + { + Editable = false; + } + field(51; "Vendor E-Mail"; Text[80]) + { + ExtendedDatatype = EMail; + + trigger OnValidate() + var + ConfirmManagement: Codeunit "Confirm Management"; + MailManagement: Codeunit "Mail Management"; + begin + if (Rec."Vendor E-Mail" = '') and (Rec."Receiving 1099 E-Form Consent") then + Error(CannotBlankEmailWithConsentErr); + if Rec."Vendor E-Mail" <> '' then + MailManagement.CheckValidEmailAddresses(Rec."Vendor E-Mail"); + if (xRec."Vendor E-Mail" <> '') and (Rec."Vendor E-Mail" <> xRec."Vendor E-Mail") then + if not ConfirmManagement.GetResponse(EmailAddressChangeQst, false) then + Rec."Vendor E-Mail" := xRec."Vendor E-Mail"; + end; + } + } + + keys + { + key(PK; ID) + { + Clustered = true; + } + key(PeriodFormVend; "Period No.", "Vendor No.", "Form No.") + { + + } + } + + var + CannotBlankEmailWithConsentErr: Label 'The email address cannot be blank when the Receiving 1099 E-Form Consent field is selected.'; + CannotCreateFormDocSamePeriodVendorFormErr: Label 'You cannot create multiple form documents with the same period, vendor and form.'; + EmailAddressChangeQst: Label 'The email address has been changed. Do you want to continue?'; + CannotMakeChangeWhenLineExistErr: Label 'You cannot make this change when one or more lines exist.'; + + trigger OnDelete() + var + IRS1099FormDocLine: Record "IRS 1099 Form Doc. Line"; + IRS1099FormReport: Record "IRS 1099 Form Report"; + begin + TestStatusOpen(); + IRS1099FormDocLine.SetRange("Document ID", ID); + IRS1099FormDocLine.DeleteAll(true); + IRS1099FormReport.SetRange("Document ID", ID); + IRS1099FormReport.DeleteAll(true); + end; + + local procedure CheckNoLinesExist() + var + IRS1099FormDocLine: Record "IRS 1099 Form Doc. Line"; + begin + IRS1099FormDocLine.SetRange("Document ID", ID); + if not IRS1099FormDocLine.IsEmpty() then + Error(CannotMakeChangeWhenLineExistErr); + end; + + local procedure TestStatusOpen() + begin + TestField(Status, Status::Open); + end; + + local procedure CheckPeriodFormVendUniqueness() + var + IRS1099FormDocHeader: Record "IRS 1099 Form Doc. Header"; + begin + if Rec."Vendor No." = '' then + exit; + if Rec."Form No." = '' then + exit; + IRS1099FormDocHeader.SetFilter(Id, '<>%1', ID); + IRS1099FormDocHeader.SetRange("Period No.", "Period No."); + IRS1099FormDocHeader.SetRange("Vendor No.", "Vendor No."); + IRS1099FormDocHeader.SetRange("Form No.", "Form No."); + if not IRS1099FormDocHeader.IsEmpty() then + Error(CannotCreateFormDocSamePeriodVendorFormErr); + end; +} diff --git a/Apps/US/IRSForms/app/src/Document/IRS1099FormDocLine.Table.al b/Apps/US/IRSForms/app/src/Document/IRS1099FormDocLine.Table.al new file mode 100644 index 0000000000..eed1774e92 --- /dev/null +++ b/Apps/US/IRSForms/app/src/Document/IRS1099FormDocLine.Table.al @@ -0,0 +1,135 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +using Microsoft.Purchases.Vendor; + +table 10036 "IRS 1099 Form Doc. Line" +{ + DataClassification = CustomerContent; + Caption = 'IRS 1099 Form Document Line'; + + fields + { + field(1; "Document ID"; Integer) + { + } + field(2; "Period No."; Code[20]) + { + TableRelation = "IRS Reporting Period"; + Editable = false; + } + field(3; "Vendor No."; Code[20]) + { + TableRelation = Vendor; + Editable = false; + } + field(4; "Form No."; Code[20]) + { + TableRelation = "IRS 1099 Form"."No." where("Period No." = field("Period No.")); + Editable = false; + } + field(5; "Line No."; Integer) + { + Editable = false; + } + field(6; "Form Box No."; Code[20]) + { + TableRelation = "IRS 1099 Form Box"."No." where("Period No." = field("Period No."), "Form No." = field("Form No.")); + NotBlank = true; + + trigger OnValidate() + begin + TestStatusOpen(); + CheckFormBoxCanBeChanged(); + CheckFormBoxUniqueness(); + end; + } + field(10; "Calculated Amount"; Decimal) + { + Editable = false; + } + field(11; Amount; Decimal) + { + + trigger OnValidate() + begin + TestStatusOpen(); + Validate("Include In 1099", Rec.Amount > Rec."Minimum Reportable Amount"); + end; + } + field(20; "Manually Changed"; Boolean) + { + Editable = false; + } + field(30; "Include In 1099"; Boolean) + { + Editable = false; + } + field(100; "Minimum Reportable Amount"; Decimal) + { + Editable = false; + } + field(101; "Adjustment Amount"; Decimal) + { + Editable = false; + } + } + + keys + { + key(PK; "Period No.", "Vendor No.", "Form No.", "Document ID", "Line No.") + { + Clustered = true; + } + } + + var + CannotChangeFormBoxWithCalculatedAmountErr: Label 'You cannot change the Form Box No. for the line with calculated amount.'; + CreateCreateFormDocLineSameFormBoxErr: Label 'You cannot create two form document lines with the same form box.'; + + trigger OnDelete() + var + IRS1099FormDocHeader: Record "IRS 1099 Form Doc. Header"; + IRS1099FormDocLineDetail: Record "IRS 1099 Form Doc. Line Detail"; + begin + if IRS1099FormDocHeader.Get("Document ID") then + IRS1099FormDocHeader.TestField(Status, IRS1099FormDocHeader.Status::Open); + IRS1099FormDocLineDetail.SetRange("Document ID", "Document ID"); + IRS1099FormDocLineDetail.SetRange("Line No.", "Line No."); + IRS1099FormDocLineDetail.DeleteAll(true); + end; + + local procedure CheckFormBoxCanBeChanged() + begin + if xRec."Form Box No." = '' then + exit; + if "Calculated Amount" <> 0 then + Error(CannotChangeFormBoxWithCalculatedAmountErr); + Amount := 0; + "Include In 1099" := false; + end; + + local procedure TestStatusOpen() + var + IRS1099FormDocHeader: Record "IRS 1099 Form Doc. Header"; + begin + if "Document ID" <> 0 then + if IRS1099FormDocHeader.Get("Document ID") then + IRS1099FormDocHeader.TestField(Status, IRS1099FormDocHeader.Status::Open); + end; + + local procedure CheckFormBoxUniqueness() + var + IRS1099FormDocLine: Record "IRS 1099 Form Doc. Line"; + begin + if Rec."Form Box No." = '' then + exit; + IRS1099FormDocLine.SetRange("Document ID", "Document ID"); + IRS1099FormDocLine.SetFilter("Line No.", '<>%1', Rec."Line No."); + if not IRS1099FormDocLine.IsEmpty() then + Error(CreateCreateFormDocLineSameFormBoxErr); + end; +} diff --git a/Apps/US/IRSForms/app/src/Document/IRS1099FormDocLineDetail.Table.al b/Apps/US/IRSForms/app/src/Document/IRS1099FormDocLineDetail.Table.al new file mode 100644 index 0000000000..4195081538 --- /dev/null +++ b/Apps/US/IRSForms/app/src/Document/IRS1099FormDocLineDetail.Table.al @@ -0,0 +1,62 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +using Microsoft.Finance.GeneralLedger.Journal; +using Microsoft.Purchases.Payables; + +table 10038 "IRS 1099 Form Doc. Line Detail" +{ + DataClassification = CustomerContent; + Caption = 'IRS 1099 Form Document Line Detail'; + + DrillDownPageId = "IRS 1099 Form Doc Line Details"; + LookupPageId = "IRS 1099 Form Doc Line Details"; + + fields + { + field(1; "Document ID"; Integer) + { + } + field(5; "Line No."; Integer) + { + } + field(6; "Vendor Ledger Entry No."; Integer) + { + } + field(100; "Document Type"; Enum "Gen. Journal Document Type") + { + CalcFormula = lookup("Vendor Ledger Entry"."Document Type" where("Entry No." = field("Vendor Ledger Entry No."))); + Editable = false; + FieldClass = FlowField; + } + field(101; "Document No."; Code[20]) + { + CalcFormula = lookup("Vendor Ledger Entry"."Document No." where("Entry No." = field("Vendor Ledger Entry No."))); + Editable = false; + FieldClass = FlowField; + } + field(102; Description; Text[100]) + { + CalcFormula = lookup("Vendor Ledger Entry".Description where("Entry No." = field("Vendor Ledger Entry No."))); + Editable = false; + FieldClass = FlowField; + } + field(200; "IRS 1099 Reporting Amount"; Decimal) + { + CalcFormula = lookup("Vendor Ledger Entry"."IRS 1099 Reporting Amount" where("Entry No." = field("Vendor Ledger Entry No."))); + Editable = false; + FieldClass = FlowField; + } + } + + keys + { + key(PK; "Document ID", "Line No.", "Vendor Ledger Entry No.") + { + Clustered = true; + } + } +} diff --git a/Apps/US/IRSForms/app/src/Document/IRS1099FormDocLineDetails.Page.al b/Apps/US/IRSForms/app/src/Document/IRS1099FormDocLineDetails.Page.al new file mode 100644 index 0000000000..db48ecc80d --- /dev/null +++ b/Apps/US/IRSForms/app/src/Document/IRS1099FormDocLineDetails.Page.al @@ -0,0 +1,43 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +page 10049 "IRS 1099 Form Doc Line Details" +{ + PageType = List; + SourceTable = "IRS 1099 Form Doc. Line Detail"; + ApplicationArea = BasicUS; + Editable = false; + + layout + { + area(content) + { + repeater(Group) + { + field("Vendor Ledger Entry No."; Rec."Vendor Ledger Entry No.") + { + Tooltip = 'Specifies the vendor ledger entry number.'; + } + field("Document Type"; Rec."Document Type") + { + Tooltip = 'Specifies the document type of the vendor ledger entry.'; + } + field("Document No."; Rec."Document No.") + { + Tooltip = 'Specifies the document number of the vendor ledger entry.'; + } + field(Description; Rec.Description) + { + Tooltip = 'Specifies the description of the vendor ledger entry.'; + } + field("IRS 1099 Reporting Amount"; Rec."IRS 1099 Reporting Amount") + { + Tooltip = 'Specifies the amount for IRS 1099 reporting of the vendor ledger entry.'; + } + } + } + } +} diff --git a/Apps/US/IRSForms/app/src/Document/IRS1099FormDocStatus.Enum.al b/Apps/US/IRSForms/app/src/Document/IRS1099FormDocStatus.Enum.al new file mode 100644 index 0000000000..0296ca491b --- /dev/null +++ b/Apps/US/IRSForms/app/src/Document/IRS1099FormDocStatus.Enum.al @@ -0,0 +1,24 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +enum 10030 "IRS 1099 Form Doc. Status" +{ + AssignmentCompatibility = true; + Extensible = true; + + value(0; Open) + { + Caption = 'Open'; + } + value(1; Released) + { + Caption = 'Released'; + } + value(2; Submitted) + { + Caption = 'Submitted'; + } +} diff --git a/Apps/US/IRSForms/app/src/Document/IRS1099FormDocSubform.Page.al b/Apps/US/IRSForms/app/src/Document/IRS1099FormDocSubform.Page.al new file mode 100644 index 0000000000..0bb1c706ef --- /dev/null +++ b/Apps/US/IRSForms/app/src/Document/IRS1099FormDocSubform.Page.al @@ -0,0 +1,59 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +page 10047 "IRS 1099 Form Doc. Subform" +{ + AutoSplitKey = true; + Caption = 'Lines'; + DelayedInsert = true; + LinksAllowed = false; + MultipleNewLines = true; + PageType = ListPart; + SourceTable = "IRS 1099 Form Doc. Line"; + ApplicationArea = BasicUS; + + layout + { + area(content) + { + repeater(General) + { + ShowCaption = false; + field("Form Box No."; Rec."Form Box No.") + { + Tooltip = 'Specifies the number of the 1099 form box.'; + } + field("Calculated Amount"; Rec."Calculated Amount") + { + Tooltip = 'Specifies the calculated amount of the document line. This amount cannot be changed manually.'; + + trigger OnDrillDown() + var + IRS1099FormDocument: Codeunit "IRS 1099 Form Document"; + begin + IRS1099FormDocument.DrillDownCalculatedAmountInLine(Rec); + end; + } + field(Amount; Rec.Amount) + { + Tooltip = 'Specifies the amount of the document line. This amount can be changed manually.'; + } + field("Minimum Reportable Amount"; Rec."Minimum Reportable Amount") + { + ToolTip = 'Specifies the minimum reportable amount of the document line.'; + } + field("Adjustment Amount"; Rec."Adjustment Amount") + { + Tooltip = 'Specifies the calculated adjustment amount of the document line. This amount cannot be changed manually.'; + } + field("Include In 1099"; Rec."Include In 1099") + { + ToolTip = 'Specifies if the document line should be included in the 1099. The line is included in the 1099 if the amount is more than or equal the minimum reportable amount.'; + } + } + } + } +} diff --git a/Apps/US/IRSForms/app/src/Document/IRS1099FormDocsImpl.Codeunit.al b/Apps/US/IRSForms/app/src/Document/IRS1099FormDocsImpl.Codeunit.al new file mode 100644 index 0000000000..b731f3bbf9 --- /dev/null +++ b/Apps/US/IRSForms/app/src/Document/IRS1099FormDocsImpl.Codeunit.al @@ -0,0 +1,151 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +codeunit 10036 "IRS 1099 Form Docs Impl." implements "IRS 1099 Create Form Docs" +{ + Access = Internal; + InherentEntitlements = X; + InherentPermissions = X; + + var + IRSFormsSetup: Record "IRS Forms Setup"; + NoVendorFormBoxAmountsFoundErr: Label 'No vendor form box amounts are found'; + + procedure CreateFormDocs(var TempVendFormBoxBuffer: Record "IRS 1099 Vend. Form Box Buffer" temporary; IRS1099CalcParameters: Record "IRS 1099 Calc. Params"); + var + TempIRS1099FormDocHeader: Record "IRS 1099 Form Doc. Header" temporary; + TempIRS1099FormDocLine: Record "IRS 1099 Form Doc. Line" temporary; + TempIRS1099FormDocLineDetail: Record "IRS 1099 Form Doc. Line Detail" temporary; + CurrVendFormBoxBuffer: Record "IRS 1099 Vend. Form Box Buffer"; + LineNo: Integer; + DocID: Integer; + begin + TempVendFormBoxBuffer.Reset(); + TempVendFormBoxBuffer.SetRange("Buffer Type", TempVendFormBoxBuffer."Buffer Type"::Amount); + if not TempVendFormBoxBuffer.FindSet() then + error(NoVendorFormBoxAmountsFoundErr); + + IRSFormsSetup.Get(); + repeat + if not SkipFormDocumentCreation(TempVendFormBoxBuffer, IRS1099CalcParameters) then begin + LineNo := 0; + AddTempFormHeaderFromBuffer(TempIRS1099FormDocHeader, DocID, TempVendFormBoxBuffer); + repeat + LineNo += 1000; + AddTempFormLineFromBuffer(TempIRS1099FormDocLine, TempIRS1099FormDocHeader, TempVendFormBoxBuffer, LineNo); + if IRSFormsSetup."Collect Details For Line" then begin + CurrVendFormBoxBuffer.Copy(TempVendFormBoxBuffer); + TempVendFormBoxBuffer.Reset(); + TempVendFormBoxBuffer.SetRange("Parent Entry No.", TempVendFormBoxBuffer."Entry No."); + TempVendFormBoxBuffer.SetRange("Buffer Type", TempVendFormBoxBuffer."Buffer Type"::"Ledger Entry"); + if TempVendFormBoxBuffer.FindSet() then + repeat + AddFormDocLineDetail(TempIRS1099FormDocLineDetail, TempIRS1099FormDocLine, TempVendFormBoxBuffer."Vendor Ledger Entry No."); + until TempVendFormBoxBuffer.Next() = 0; + TempVendFormBoxBuffer.Copy(CurrVendFormBoxBuffer); + end; + until TempVendFormBoxBuffer.Next() = 0; + end; + TempVendFormBoxBuffer.SetRange("Vendor No."); + TempVendFormBoxBuffer.SetRange("Form No."); + until TempVendFormBoxBuffer.Next() = 0; + + InsertFormDocsFromTempBuffer(TempIRS1099FormDocHeader, TempIRS1099FormDocLine, TempIRS1099FormDocLineDetail); + end; + + local procedure SkipFormDocumentCreation(var VendFormBoxBuffer: Record "IRS 1099 Vend. Form Box Buffer"; IRS1099CalcParameters: Record "IRS 1099 Calc. Params"): Boolean + var + IRS1099FormDocHeader: Record "IRS 1099 Form Doc. Header"; + begin + VendFormBoxBuffer.SetRange("Vendor No.", VendFormBoxBuffer."Vendor No."); + VendFormBoxBuffer.SetRange("Form No.", VendFormBoxBuffer."Form No."); + IRS1099FormDocHeader.SetRange("Period No.", VendFormBoxBuffer."Period No."); + IRS1099FormDocHeader.SetRange("Vendor No.", VendFormBoxBuffer."Vendor No."); + IRS1099FormDocHeader.SetRange("Form No.", VendFormBoxBuffer."Form No."); + if IRS1099FormDocHeader.FindFirst() then + if IRS1099CalcParameters.Replace then + IRS1099FormDocHeader.Delete(true) + else + exit(true); + exit(false); + end; + + local procedure AddTempFormHeaderFromBuffer(var TempIRS1099FormDocHeader: Record "IRS 1099 Form Doc. Header" temporary; var DocID: Integer; VendFormBoxBuffer: Record "IRS 1099 Vend. Form Box Buffer") + begin + TempIRS1099FormDocHeader.Init(); + DocID += 1; + TempIRS1099FormDocHeader.ID := DocID; + TempIRS1099FormDocHeader."Period No." := VendFormBoxBuffer."Period No."; + TempIRS1099FormDocHeader."Vendor No." := VendFormBoxBuffer."Vendor No."; + TempIRS1099FormDocHeader."Form No." := VendFormBoxBuffer."Form No."; + TempIRS1099FormDocHeader.Insert(true); + end; + + local procedure AddTempFormLineFromBuffer(var TempIRS1099FormDocLine: Record "IRS 1099 Form Doc. Line" temporary; IRS1099FormDocHeader: Record "IRS 1099 Form Doc. Header"; VendFormBoxBuffer: Record "IRS 1099 Vend. Form Box Buffer"; LineNo: Integer) + begin + TempIRS1099FormDocLine.Init(); + TempIRS1099FormDocLine."Document ID" := IRS1099FormDocHeader.ID; + TempIRS1099FormDocLine."Period No." := IRS1099FormDocHeader."Period No."; + TempIRS1099FormDocLine."Vendor No." := IRS1099FormDocHeader."Vendor No."; + TempIRS1099FormDocLine."Form No." := IRS1099FormDocHeader."Form No."; + TempIRS1099FormDocLine."Form Box No." := VendFormBoxBuffer."Form Box No."; + TempIRS1099FormDocLine."Line No." := LineNo; + VendFormBoxBuffer.CalcFields("Minimum Reportable Amount", "Adjustment Amount"); + TempIRS1099FormDocLine."Minimum Reportable Amount" := VendFormBoxBuffer."Minimum Reportable Amount"; + TempIRS1099FormDocLine."Adjustment Amount" := VendFormBoxBuffer."Adjustment Amount"; + TempIRS1099FormDocLine.Validate("Calculated Amount", VendFormBoxBuffer.Amount); + TempIRS1099FormDocLine.Validate(Amount, VendFormBoxBuffer."Reporting Amount"); + TempIRS1099FormDocLine.Validate("Include In 1099", VendFormBoxBuffer."Include In 1099"); + TempIRS1099FormDocLine.Insert(); + end; + + local procedure AddFormDocLineDetail(var TempIRS1099FormDocLineDetail: Record "IRS 1099 Form Doc. Line Detail" temporary; IRS1099FormDocLine: Record "IRS 1099 Form Doc. Line"; EntryNo: Integer) + begin + TempIRS1099FormDocLineDetail.Validate("Document ID", IRS1099FormDocLine."Document ID"); + TempIRS1099FormDocLineDetail.Validate("Line No.", IRS1099FormDocLine."Line No."); + TempIRS1099FormDocLineDetail.Validate("Vendor Ledger Entry No.", EntryNo); + TempIRS1099FormDocLineDetail.Insert(true); + end; + + local procedure InsertFormDocsFromTempBuffer(var TempIRS1099FormDocHeader: Record "IRS 1099 Form Doc. Header" temporary; var TempIRS1099FormDocLine: Record "IRS 1099 Form Doc. Line" temporary; var TempIRS1099FormDocLineDetail: Record "IRS 1099 Form Doc. Line Detail" temporary) + var + IRS1099FormDocHeader: Record "IRS 1099 Form Doc. Header"; + IRS1099FormDocLine: Record "IRS 1099 Form Doc. Line"; + IRS1099FormDocLineDetail: Record "IRS 1099 Form Doc. Line Detail"; + DocID: Integer; + begin + if IRS1099FormDocHeader.FindLast() then + DocID := IRS1099FormDocHeader.ID; + TempIRS1099FormDocHeader.Reset(); + TempIRS1099FormDocLine.Reset(); + if TempIRS1099FormDocHeader.FindSet() then + repeat + DocID += 1; + IRS1099FormDocHeader := TempIRS1099FormDocHeader; + IRS1099FormDocHeader.ID := DocID; + IRS1099FormDocHeader.Validate("Vendor No."); + IRS1099FormDocHeader.Insert(true); + TempIRS1099FormDocLine.SetRange("Document ID", TempIRS1099FormDocHeader.ID); + if TempIRS1099FormDocLine.FindSet() then + repeat + IRS1099FormDocLine := TempIRS1099FormDocLine; + IRS1099FormDocLine.Validate("Document ID", IRS1099FormDocHeader.ID); + IRS1099FormDocLine.Validate(Amount, IRS1099FormDocLine.Amount); + IRS1099FormDocLine.Insert(true); + if IRSFormsSetup."Collect Details For Line" then begin + TempIRS1099FormDocLineDetail.SetRange("Document ID", TempIRS1099FormDocLine."Document ID"); + TempIRS1099FormDocLineDetail.SetRange("Line No.", TempIRS1099FormDocLine."Line No."); + if TempIRS1099FormDocLineDetail.FindSet() then + repeat + IRS1099FormDocLineDetail := TempIRS1099FormDocLineDetail; + IRS1099FormDocLineDetail.Validate("Document ID", IRS1099FormDocLine."Document ID"); + IRS1099FormDocLineDetail.Insert(true); + until TempIRS1099FormDocLineDetail.Next() = 0; + end; + until TempIRS1099FormDocLine.Next() = 0; + until TempIRS1099FormDocHeader.Next() = 0; + end; +} diff --git a/Apps/US/IRSForms/app/src/Document/IRS1099FormDocument.Codeunit.al b/Apps/US/IRSForms/app/src/Document/IRS1099FormDocument.Codeunit.al new file mode 100644 index 0000000000..fb8747b9e4 --- /dev/null +++ b/Apps/US/IRSForms/app/src/Document/IRS1099FormDocument.Codeunit.al @@ -0,0 +1,102 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +using System.Telemetry; + +codeunit 10031 "IRS 1099 Form Document" +{ + Access = Internal; + + var + Telemetry: Codeunit Telemetry; + ReportingPeriodNotDefinedErr: Label 'Reporting period is not defined'; + CannotChangeIRSDataInEntryConnectedToFormDocumentErr: Label 'You cannot change the IRS data in the vendor ledger entry connected to the form document. Period = %1, Vendor No. = %2, Form No. = %3', Comment = '%1 = Period No., %2 = Vendor No., %3 = Form No.'; + FormDocHasBeenMarkedAsSubmittedMsg: Label 'The form document %1 has been marked as submitted', Comment = '%1 = document id'; + IRSFormsTok: Label 'IRS Forms', Locked = true; + + procedure Reopen(var IRS1099FormDocHeader: Record "IRS 1099 Form Doc. Header") + begin + if IRS1099FormDocHeader.Status <> IRS1099FormDocHeader.Status::Released then + IRS1099FormDocHeader.FieldError(Status); + IRS1099FormDocHeader.Validate(Status, IRS1099FormDocHeader.Status::Open); + IRS1099FormDocHeader.Modify(true); + end; + + procedure Release(var IRS1099FormDocHeader: Record "IRS 1099 Form Doc. Header") + begin + if IRS1099FormDocHeader.Status <> IRS1099FormDocHeader.Status::Open then + IRS1099FormDocHeader.FieldError(Status); + IRS1099FormDocHeader.Validate(Status, IRS1099FormDocHeader.Status::Released); + IRS1099FormDocHeader.Modify(true); + end; + + procedure CreateForms(PeriodNo: Code[20]) + begin + RunCreateFormDocsReport(PeriodNo, '', '', false); + end; + + procedure RecreateForm(IRS1099FormDocHeader: Record "IRS 1099 Form Doc. Header") + begin + RunCreateFormDocsReport(IRS1099FormDocHeader."Period No.", IRS1099FormDocHeader."Vendor No.", IRS1099FormDocHeader."Form No.", true); + end; + + local procedure RunCreateFormDocsReport(PeriodNo: Code[20]; VendorNo: Code[20]; FormNo: Code[20]; Recreate: Boolean) + var + IRS1099CreateFormDocs: Report "IRS 1099 Create Form Docs"; + begin + IRS1099CreateFormDocs.InitializeRequest(PeriodNo, VendorNo, FormNo, Recreate); + IRS1099CreateFormDocs.RunModal(); + end; + + procedure CreateFormDocs(IRS1099CalcParameters: Record "IRS 1099 Calc. Params"); + var + IRSFormsSetup: Record "IRS Forms Setup"; + TempVendFormBoxBuffer: Record "IRS 1099 Vend. Form Box Buffer" temporary; + IRSFormsFacade: Codeunit "IRS Forms Facade"; + begin + if IRS1099CalcParameters."Period No." = '' then + error(ReportingPeriodNotDefinedErr); + IRSFormsSetup.InitSetup(); + IRSFormsFacade.GetVendorFormBoxAmount(TempVendFormBoxBuffer, IRS1099CalcParameters); + IRSFormsFacade.CreateFormDocs(TempVendFormBoxBuffer, IRS1099CalcParameters); + end; + + procedure MarkAsSubmitted(var IRS1099FormDocHeader: Record "IRS 1099 Form Doc. Header") + begin + IRS1099FormDocHeader.Validate(Status, IRS1099FormDocHeader.Status::Submitted); + IRS1099FormDocHeader.Modify(true); + Telemetry.LogMessage('0000MJP', StrSubstNo(FormDocHasBeenMarkedAsSubmittedMsg, IRS1099FormDocHeader.ID), Verbosity::Verbose, DataClassification::SystemMetadata); + end; + + procedure DrillDownCalculatedAmountInLine(IRS1099FormDocLine: Record "IRS 1099 Form Doc. Line") + var + IRSFormsSetup: Record "IRS Forms Setup"; + IRS1099FormDocLineDetail: Record "IRS 1099 Form Doc. Line Detail"; + begin + IRSFormsSetup.Get(); + IRSFormsSetup.TestField("Collect Details For Line"); + IRS1099FormDocLineDetail.SetRange("Document ID", IRS1099FormDocLine."Document ID"); + IRS1099FormDocLineDetail.SetRange("Line No.", IRS1099FormDocLine."Line No."); + Page.Run(0, IRS1099FormDocLineDetail); + end; + + procedure CheckIfVendLedgEntryAllowed(EntryNo: Integer) + var + IRS1099FormDocLineDetail: Record "IRS 1099 Form Doc. Line Detail"; + IRS1099FormDocHeader: Record "IRS 1099 Form Doc. Header"; + begin + IRS1099FormDocLineDetail.SetRange("Vendor Ledger Entry No.", EntryNo); + if IRS1099FormDocLineDetail.FindFirst() then begin + IRS1099FormDocHeader.Get(IRS1099FormDocLineDetail."Document ID"); + Error(CannotChangeIRSDataInEntryConnectedToFormDocumentErr, IRS1099FormDocHeader."Period No.", IRS1099FormDocHeader."Vendor No.", IRS1099FormDocHeader."Form No."); + end; + end; + + procedure GetActivityLogContext(): Text[30] + begin + exit(IRSFormsTok); + end; +} diff --git a/Apps/US/IRSForms/app/src/Document/IRS1099FormDocument.Page.al b/Apps/US/IRSForms/app/src/Document/IRS1099FormDocument.Page.al new file mode 100644 index 0000000000..815e1e81c3 --- /dev/null +++ b/Apps/US/IRSForms/app/src/Document/IRS1099FormDocument.Page.al @@ -0,0 +1,277 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +page 10037 "IRS 1099 Form Document" +{ + PageType = Card; + SourceTable = "IRS 1099 Form Doc. Header"; + ApplicationArea = BasicUS; + + layout + { + area(content) + { + group(General) + { + Caption = 'General'; + field("Period No."; Rec."Period No.") + { + Tooltip = 'Specifies the period of the document.'; + Visible = false; + } + field("Vendor No."; Rec."Vendor No.") + { + Tooltip = 'Specifies the vendor number.'; + ShowMandatory = true; + + trigger OnValidate() + begin + UpdateLinesAvailable(); + end; + } + field("Form No."; Rec."Form No.") + { + Tooltip = 'Specifies the form of the document.'; + ShowMandatory = true; + + trigger OnValidate() + begin + UpdateLinesAvailable(); + end; + } + field(Status; Rec.Status) + { + Tooltip = 'Specifies the status of the document'; + } + } + group(Email) + { + field("Receiving 1099 E-Form Consent"; Rec."Receiving 1099 E-Form Consent") + { +#pragma warning disable AA0219 + Tooltip = 'By selecting this field, you acknowledge that your vendor has provided signed consent to receive their 1099 form electronically.'; +#pragma warning restore AA0219 + Importance = Additional; + } + field("Vendor E-Mail"; Rec."Vendor E-Mail") + { + Tooltip = 'Specifies the vendor email address.'; + Importance = Additional; + } + field("Copy B Sent"; Rec."Copy B Sent") + { + Tooltip = 'Specifies whether the Copy B of the form has been sent to the vendor.'; + Importance = Additional; + } + field("Copy 2 Sent"; Rec."Copy 2 Sent") + { + Tooltip = 'Specifies whether the Copy 2 of the form has been sent to the vendor.'; + Importance = Additional; + } + field("Email Error Log"; Rec."Email Error Log") + { + ToolTip = 'Specifies the error log for the email.'; + Importance = Additional; + Visible = EmailErrorVisible; + MultiLine = true; + } + } + part(FormLines; "IRS 1099 Form Doc. Subform") + { + ApplicationArea = BasicUS; + SubPageLink = "Document ID" = field(ID), "Period No." = field("Period No."), "Vendor No." = field("Vendor No."), "Form No." = field("Form No."); + Editable = IsLinesEditable; + Enabled = IsLinesEditable; + UpdatePropagation = Both; + } + } + area(factboxes) + { + systempart(LinksFactBox; Links) + { + ApplicationArea = RecordLinks; + Visible = false; + Provider = FormLines; + } + systempart(NotesFactBox; Notes) + { + ApplicationArea = Notes; + Visible = false; + Provider = FormLines; + } + } + } + + actions + { + area(processing) + { + group(ReleaseReopen) + { + Caption = 'Release'; + Image = ReleaseDoc; + action(Release) + { + ApplicationArea = BasicUS; + Caption = 'Re&lease'; + Enabled = Rec.Status = Rec.Status::Open; + Image = ReleaseDoc; + ShortCutKey = 'Ctrl+F9'; + ToolTip = 'Release the form before submission. You must reopen the form before you can make changes to it.'; + + trigger OnAction() + var + IRS1099FormDocument: Codeunit "IRS 1099 Form Document"; + begin + IRS1099FormDocument.Release(Rec); + end; + } + action(Reopen) + { + ApplicationArea = BasicUS; + Caption = 'Re&open'; + Enabled = Rec.Status <> Rec.Status::Open; + Image = ReOpen; + ToolTip = 'Reopen the form to change it after it has been approved. Approved forms have the Released status and must be opened before they can be changed.'; + + trigger OnAction() + var + IRS1099FormDocument: Codeunit "IRS 1099 Form Document"; + begin + IRS1099FormDocument.Reopen(Rec); + end; + } + action("Mark as Submitted") + { + ApplicationArea = Basic, Suite; + Caption = 'Mark as Submitted'; + Image = Approve; + ToolTip = 'Indicate that you submitted the form document to the tax authority manually.'; + + trigger OnAction() + var + IRS1099FormDocument: Codeunit "IRS 1099 Form Document"; + begin + IRS1099FormDocument.MarkAsSubmitted(Rec); + end; + } + action(Print) + { + ApplicationArea = BasicUS; + Caption = 'Print'; + Ellipsis = true; + Image = PrintAcknowledgement; + ToolTip = 'Prints a single form.'; + + trigger OnAction() + var + IRSFormsFacade: Codeunit "IRS Forms Facade"; + begin + IRSFormsFacade.PrintContent(Rec); + end; + } + action(Reports) + { + ApplicationArea = BasicUS; + Caption = 'Reports'; + Ellipsis = true; + Image = Report; + ToolTip = 'Opens the reports page.'; + RunObject = page "IRS 1099 Form Reports"; + RunPageLink = "Document ID" = field(ID); + } + action(SendEmail) + { + ApplicationArea = BasicUS; + Caption = 'Send Email'; + Ellipsis = true; + Image = Email; + ToolTip = 'Sends the form by email.'; + + trigger OnAction() + var + IRS1099SendEmailReport: Report "IRS 1099 Send Email"; + IRS1099SendEmail: Codeunit "IRS 1099 Send Email"; + begin + IRS1099SendEmail.CheckCanSendEmail(Rec); + + Rec.SetRecFilter(); + IRS1099SendEmailReport.SetTableView(Rec); + IRS1099SendEmailReport.RunModal(); + end; + } + } + } + area(Promoted) + { + group(Category_Status) + { + Caption = 'Release'; + ShowAs = SplitButton; + + actionref(Release_Promoted; Release) + { + } + actionref(Reopen_Promoted; Reopen) + { + } + } + group(Category_Print) + { + Caption = 'Print'; + actionref(Print_Single; Print) + { + } + } + actionref(Reports_Single; Reports) + { + } + actionref(Send_Email; SendEmail) + { + } + } + } + + var + IsLinesEditable: Boolean; + EmailErrorVisible: Boolean; + + trigger OnOpenPage() + begin + UpdateLinesAvailable(); + EmailErrorVisible := Rec."Email Error Log" <> ''; + end; + + trigger OnAfterGetRecord() + begin + UpdateLinesAvailable(); + end; + + trigger OnAfterGetCurrRecord() + begin + UpdateLinesAvailable(); + end; + + trigger OnNewRecord(BelowxRec: Boolean) + var + PeriodNo: Code[20]; + begin + PeriodNo := GetPeriodNoFilter(); + if PeriodNo <> '' then + Rec.Validate("Period No.", PeriodNo); + end; + + local procedure GetPeriodNoFilter(): Code[20] + begin + if Rec.GetFilter("Period No.") <> '' then + exit(Rec.GetRangeMin("Period No.")); + end; + + local procedure UpdateLinesAvailable() + begin + IsLinesEditable := (Rec."Period No." <> '') and (Rec."Vendor No." <> '') and (Rec."Form No." <> ''); + end; +} diff --git a/Apps/US/IRSForms/app/src/Document/IRS1099FormDocuments.Page.al b/Apps/US/IRSForms/app/src/Document/IRS1099FormDocuments.Page.al new file mode 100644 index 0000000000..343ff84f24 --- /dev/null +++ b/Apps/US/IRSForms/app/src/Document/IRS1099FormDocuments.Page.al @@ -0,0 +1,162 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +using Microsoft.Utilities; + +page 10036 "IRS 1099 Form Documents" +{ + PageType = List; + SourceTable = "IRS 1099 Form Doc. Header"; + CardPageId = "IRS 1099 Form Document"; + ApplicationArea = BasicUS; + UsageCategory = Administration; + RefreshOnActivate = true; + Editable = false; + + layout + { + area(content) + { + repeater(Group) + { + field("Period No."; Rec."Period No.") + { + Tooltip = 'Specifies the period of the document.'; + Visible = PeriodIsVisible; + } + field("Vendor No."; Rec."Vendor No.") + { + Tooltip = 'Specifies the vendor number.'; + } + field("Form No."; Rec."Form No.") + { + Tooltip = 'Specifies the form of the document.'; + } + field(Status; Rec.Status) + { + Tooltip = 'Specifies the status of the document'; + } + field("Receiving 1099 E-Form Consent"; Rec."Receiving 1099 E-Form Consent") + { +#pragma warning disable AA0219 + Tooltip = 'By selecting this field, you acknowledge that your vendor has provided signed consent to receive their 1099 form electronically.'; +#pragma warning restore AA0219 + Visible = false; + } + field("Vendor E-Mail"; Rec."Vendor E-Mail") + { + Tooltip = 'Specifies the vendor email address.'; + Visible = false; + } + field("Copy B Sent"; Rec."Copy B Sent") + { + Tooltip = 'Specifies whether the Copy B of the form has been sent to the vendor.'; + } + field("Copy 2 Sent"; Rec."Copy 2 Sent") + { + Tooltip = 'Specifies whether the Copy 2 of the form has been sent to the vendor.'; + } + } + } + } + + actions + { + area(Processing) + { + action(CreateForms) + { + Caption = 'Create Forms'; + Image = Form; + Scope = Repeater; + ToolTip = 'Create IRS 1099 form documents for reporting.'; + + trigger OnAction() + var + IRSReportingPeriod: Record "IRS Reporting Period"; + IRS1099FormDocument: Codeunit "IRS 1099 Form Document"; + begin + if Rec.GetFilter("Period No.") <> '' then + if IRSReportingPeriod.Get(Rec.GetFilter("Period No.")) then; + IRS1099FormDocument.CreateForms(IRSReportingPeriod."No."); + end; + } + action(RecreateForm) + { + Caption = 'Recreate Form'; + Image = Form; + Scope = Repeater; + ToolTip = 'Recreate a single IRS 1099 form document for reporting.'; + + trigger OnAction() + var + IRS1099FormDocument: Codeunit "IRS 1099 Form Document"; + begin + IRS1099FormDocument.RecreateForm(Rec); + end; + } + action(SendEmail) + { + Caption = 'Send Email'; + Image = Email; + ToolTip = 'Send the selected forms to the vendors by email.'; + + trigger OnAction() + var + IRS1099FormDocHeader: Record "IRS 1099 Form Doc. Header"; + IRS1099SendEmail: Report "IRS 1099 Send Email"; + begin + IRS1099FormDocHeader := Rec; + CurrPage.SetSelectionFilter(IRS1099FormDocHeader); + IRS1099SendEmail.SetTableView(IRS1099FormDocHeader); + IRS1099SendEmail.RunModal(); + end; + } + action(ActivityLog) + { + Caption = 'Activity Log'; + Image = Log; + ToolTip = 'Show activity log for the 1099 forms.'; + + trigger OnAction() + var + ActivityLog: Record "Activity Log"; + IRS1099FormDocument: Codeunit "IRS 1099 Form Document"; + begin + ActivityLog.SetRange(Context, IRS1099FormDocument.GetActivityLogContext()); + Page.RunModal(Page::"Activity Log", ActivityLog); + end; + } + } + area(Promoted) + { + group(Category_Process) + { + Caption = 'Process'; + actionref(CreateForms_Promoted; CreateForms) + { + + } + actionref(SendEmails_Promoted; SendEmail) + { + } + } + } + } + + var + PeriodIsVisible: Boolean; + +#if not CLEAN25 + trigger OnOpenPage() + var + IRSFormsFeature: Codeunit "IRS Forms Feature"; + begin + PeriodIsVisible := Rec.GetFilter("Period No.") = ''; + CurrPage.Editable := IRSFormsFeature.FeatureCanBeUsed(); + end; +#endif +} diff --git a/Apps/US/IRSForms/app/src/Emailing/IRS1099EmailQueue.Table.al b/Apps/US/IRSForms/app/src/Emailing/IRS1099EmailQueue.Table.al new file mode 100644 index 0000000000..518f055379 --- /dev/null +++ b/Apps/US/IRSForms/app/src/Emailing/IRS1099EmailQueue.Table.al @@ -0,0 +1,36 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +table 10046 "IRS 1099 Email Queue" +{ + Access = Internal; + DataClassification = SystemMetadata; + + fields + { + field(1; "Entry No."; Integer) + { + Editable = false; + AutoIncrement = true; + } + field(10; "Document ID"; Integer) + { + Editable = false; + } + field(11; "Report Type"; Enum "IRS 1099 Form Report Type") + { + Editable = false; + } + } + + keys + { + key(Key1; "Entry No.") + { + Clustered = true; + } + } +} diff --git a/Apps/US/IRSForms/app/src/Emailing/IRS1099EmailReportType.Enum.al b/Apps/US/IRSForms/app/src/Emailing/IRS1099EmailReportType.Enum.al new file mode 100644 index 0000000000..7f31e817d1 --- /dev/null +++ b/Apps/US/IRSForms/app/src/Emailing/IRS1099EmailReportType.Enum.al @@ -0,0 +1,20 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +enum 10034 "IRS 1099 Email Report Type" +{ + AssignmentCompatibility = true; + Extensible = true; + + value(1; "Copy B") + { + Caption = 'Copy B'; + } + value(3; "Copy 2") + { + Caption = 'Copy 2'; + } +} diff --git a/Apps/US/IRSForms/app/src/Emailing/IRS1099ProcessEmailQueue.Codeunit.al b/Apps/US/IRSForms/app/src/Emailing/IRS1099ProcessEmailQueue.Codeunit.al new file mode 100644 index 0000000000..4ab630af2b --- /dev/null +++ b/Apps/US/IRSForms/app/src/Emailing/IRS1099ProcessEmailQueue.Codeunit.al @@ -0,0 +1,54 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +using Microsoft.Utilities; +using System.Telemetry; +using System.Threading; + +codeunit 10052 "IRS 1099 Process Email Queue" +{ + Access = Internal; + InherentEntitlements = X; + InherentPermissions = X; + TableNo = "Job Queue Entry"; + + var + EmailFormsTxt: Label 'Email IRS 1099 pdf forms'; + JobCompletedTxt: Label 'Job of sending 1099 pdf forms by email has been completed. Successfully sent %1 forms. Failed to send %2 forms.', Comment = '%1 - forms sent count, %2 - forms not sent count'; + + trigger OnRun() + var + IRS1099EmailQueue: Record "IRS 1099 Email Queue"; + ActivityLog: Record "Activity Log"; + IRS1099SendEmail: Codeunit "IRS 1099 Send Email"; + IRS1099FormDocument: Codeunit "IRS 1099 Form Document"; + Telemetry: Codeunit Telemetry; + Success: Boolean; + SuccessCount: Integer; + FailCount: Integer; + begin + IRS1099EmailQueue.LockTable(); + if IRS1099EmailQueue.FindSet() then + repeat + Commit(); + Success := IRS1099SendEmail.Run(IRS1099EmailQueue); + if Success then begin + SuccessCount += 1; + IRS1099SendEmail.SetEmailStatusSuccess(IRS1099EmailQueue) + end else begin + FailCount += 1; + IRS1099SendEmail.SetEmailStatusFail(IRS1099EmailQueue, GetLastErrorText()); + end; + Sleep(200); + until IRS1099EmailQueue.Next() = 0; + + IRS1099EmailQueue.DeleteAll(); + + Telemetry.LogMessage('0000MHV', StrSubstNo(JobCompletedTxt, SuccessCount, FailCount), Verbosity::Normal, DataClassification::SystemMetadata); + ActivityLog.LogActivity(Rec.RecordId(), ActivityLog.Status::Success, IRS1099FormDocument.GetActivityLogContext(), EmailFormsTxt, StrSubstNo(JobCompletedTxt, SuccessCount, FailCount)); + end; + +} diff --git a/Apps/US/IRSForms/app/src/Emailing/IRS1099SendEmail.Codeunit.al b/Apps/US/IRSForms/app/src/Emailing/IRS1099SendEmail.Codeunit.al new file mode 100644 index 0000000000..46f085eec6 --- /dev/null +++ b/Apps/US/IRSForms/app/src/Emailing/IRS1099SendEmail.Codeunit.al @@ -0,0 +1,223 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +using Microsoft.Purchases.Vendor; +using System.EMail; +using System.Telemetry; + +codeunit 10051 "IRS 1099 Send Email" +{ + Access = Internal; + TableNo = "IRS 1099 Email Queue"; + + var + AttachmentFileNameTxt: Label '1099Form%1Subst_%2.pdf', Comment = '%1 - form no like NEC, MISC etc, %2 - report type, B or 2', Locked = true; + EmailNotSentErr: Label 'The email has not been sent. Error: %1', Comment = '%1 - error message from the email management codeunit'; + VendorNotFoundErr: Label 'The vendor %1 was not found for the selected 1099 form document.', Comment = '%1 - Vendor No'; + NoConsentErr: Label 'The vendor has not consented to receive 1099 forms electronically'; + EnableConsentMessageTxt: Label 'You must enable the Receiving 1099 E-Form Consent field on the vendor card to send 1099 forms electronically.'; + EmptyEmailErr: Label 'The recipient email is not specified'; + SetEmailMessageTxt: Label 'Set the email in the document or in the vendor card.'; + EmailSetupMissingErr: Label 'You must set up email in Business Central before you can send 1099 forms.'; + EmailSubjectMissingErr: Label 'You must set up the email subject in the IRS Setup before you send 1099 forms.'; + EmailBodyMissingErr: Label 'You must set up the email body in the IRS Setup before you send 1099 forms.'; + CopyNotFoundErr: Label 'The %1 was not found for the selected 1099 form document.', Comment = '%1 - Report Type, like Copy B or Copy 2'; + ShowVendorCardTxt: Label 'Show Vendor %1', Comment = '%1 - Vendor No'; + ShowIRSFormsSetupTxt: Label 'Show IRS Forms Setup'; + ShowEmailAccountsTxt: Label 'Show Email Accounts'; + + trigger OnRun() + var + IRS1099FormDocHeader: Record "IRS 1099 Form Doc. Header"; + IRS1099PrintParams: Record "IRS 1099 Print Params"; + IRSFormsFacade: Codeunit "IRS Forms Facade"; + begin + if IRS1099FormDocHeader.Get(Rec."Document ID") then begin + CheckCanSendEmail(IRS1099FormDocHeader); + + IRS1099PrintParams."Report Type" := Rec."Report Type"; + IRSFormsFacade.SaveContentForDocument(IRS1099FormDocHeader, IRS1099PrintParams, false); + + SendEmailToVendor(IRS1099FormDocHeader, Rec."Report Type"); + end; + end; + + procedure SendEmailToVendor(var IRS1099FormDocHeader: Record "IRS 1099 Form Doc. Header"; ReportType: Enum "IRS 1099 Form Report Type") + var + IRS1099FormReport: Record "IRS 1099 Form Report"; + TempEmailItem: Record "Email Item" temporary; + MailManagement: Codeunit "Mail Management"; + Telemetry: Codeunit Telemetry; + FileName: Text; + ReportTypeText: Text; + begin + ClearLastError(); + ResetEmailStatus(IRS1099FormDocHeader, ReportType); + + CheckCanSendEmail(IRS1099FormDocHeader); + + IRS1099FormReport.SetRange("Document ID", IRS1099FormDocHeader.ID); + IRS1099FormReport.SetRange("Report Type", ReportType); + if not IRS1099FormReport.FindLast() then + Error(CopyNotFoundErr, ReportType); + + InitTempEmailItem(TempEmailItem, IRS1099FormDocHeader."Vendor E-Mail"); + ReportTypeText := Format(ReportType.Names.Get(ReportType.AsInteger())); + FileName := StrSubstNo(AttachmentFileNameTxt, IRS1099FormDocHeader."Form No.", ReportTypeText.TrimStart('Copy ')); + AddAttachment(TempEmailItem, IRS1099FormReport, FileName); + + MailManagement.SetHideMailDialog(true); + MailManagement.SetHideEmailSendingError(true); + if not MailManagement.Send(TempEmailItem, Enum::"Email Scenario"::Default) then begin + Telemetry.LogMessage('0000MHW', StrSubstNo(EmailNotSentErr, GetLastErrorText()), Verbosity::Warning, DataClassification::SystemMetadata); + Error(EmailNotSentErr, GetLastErrorText()); + end; + end; + + procedure CheckCanSendEmail(var IRS1099FormDocHeader: Record "IRS 1099 Form Doc. Header") + var + IRSFormsSetup: Record "IRS Forms Setup"; + EmailAccount: Record "Email Account"; + Vendor: Record Vendor; + MailManagement: Codeunit "Mail Management"; + DummyRecId: RecordId; + begin + if not MailManagement.IsEnabled() then + if EmailAccount.WritePermission() then + ThrowShowItError('', EmailSetupMissingErr, ShowEmailAccountsTxt, DummyRecId, 0, Page::"Email Accounts") + else + Error(EmailSetupMissingErr); + + IRSFormsSetup.InitSetup(); + if IRSFormsSetup."Email Subject" = '' then + if IRSFormsSetup.WritePermission() then + ThrowShowItError('', EmailSubjectMissingErr, ShowIRSFormsSetupTxt, IRSFormsSetup.RecordId, IRSFormsSetup.FieldNo("Email Subject"), Page::"IRS Forms Setup") + else + Error(EmailSubjectMissingErr); + if IRSFormsSetup."Email Body" = '' then + if IRSFormsSetup.WritePermission() then + ThrowShowItError('', EmailBodyMissingErr, ShowIRSFormsSetupTxt, IRSFormsSetup.RecordId, IRSFormsSetup.FieldNo("Email Body"), Page::"IRS Forms Setup") + else + Error(EmailBodyMissingErr); + + if not Vendor.Get(IRS1099FormDocHeader."Vendor No.") then + Error(VendorNotFoundErr, IRS1099FormDocHeader."Vendor No."); + + if not IRS1099FormDocHeader."Receiving 1099 E-Form Consent" then + if Vendor.WritePermission() then + ThrowShowItError( + NoConsentErr, EnableConsentMessageTxt, StrSubstNo(ShowVendorCardTxt, Vendor."No."), Vendor.RecordId, 0, Page::"Vendor Card") + else + Error(NoConsentErr); + + if IRS1099FormDocHeader."Vendor E-Mail" = '' then + if Vendor.WritePermission() then + ThrowShowItError( + EmptyEmailErr, SetEmailMessageTxt, StrSubstNo(ShowVendorCardTxt, Vendor."No."), Vendor.RecordId, + Vendor.FieldNo("E-Mail For IRS"), Page::"Vendor Card") + else + Error(EmptyEmailErr); + end; + + local procedure InitTempEmailItem(var TempEmailItem: Record "Email Item" temporary; EmailAddress: Text[250]) + var + IRSFormsSetup: Record "IRS Forms Setup"; + begin + IRSFormsSetup.Get(); + TempEmailItem.Initialize(); + TempEmailItem.Subject := IRSFormsSetup."Email Subject"; + TempEmailItem.SetBodyText(IRSFormsSetup."Email Body"); + TempEmailItem."Send to" := EmailAddress; + TempEmailItem.Insert(); + end; + + local procedure AddAttachment(var TempEmailItem: Record "Email Item" temporary; var IRS1099FormReport: Record "IRS 1099 Form Report"; FileName: Text) + var + FileInStream: InStream; + begin + IRS1099FormReport.CalcFields("File Content"); + if not IRS1099FormReport."File Content".HasValue() then + exit; + + IRS1099FormReport."File Content".CreateInStream(FileInStream); + TempEmailItem.AddAttachment(FileInStream, FileName); + end; + + local procedure ThrowShowItError(Title: Text; Message: Text; NavigationActionText: Text; RecId: RecordId; FieldNo: Integer; PageNo: Integer) + var + ErrorInfo: ErrorInfo; + begin + ErrorInfo.Message := Message; + ErrorInfo.ErrorType := ErrorType::Client; + + if Title <> '' then + ErrorInfo.Title := Title; + if NavigationActionText <> '' then + ErrorInfo.AddNavigationAction(NavigationActionText); + if RecId.TableNo <> 0 then + ErrorInfo.RecordId(RecId); + if FieldNo <> 0 then + ErrorInfo.FieldNo(FieldNo); + if PageNo <> 0 then + ErrorInfo.PageNo(PageNo); + + Error(ErrorInfo); + end; + + procedure SetEmailStatusSuccess(IRS1099EmailQueue: Record "IRS 1099 Email Queue") + var + IRS1099FormDocHeader: Record "IRS 1099 Form Doc. Header"; + begin + if not IRS1099FormDocHeader.Get(IRS1099EmailQueue."Document ID") then + exit; + SetEmailStatusSuccess(IRS1099FormDocHeader, IRS1099EmailQueue."Report Type"); + end; + + procedure SetEmailStatusSuccess(var IRS1099FormDocHeader: Record "IRS 1099 Form Doc. Header"; ReportType: Enum "IRS 1099 Form Report Type") + begin + case ReportType of + Enum::"IRS 1099 Form Report Type"::"Copy B": + IRS1099FormDocHeader."Copy B Sent" := true; + Enum::"IRS 1099 Form Report Type"::"Copy 2": + IRS1099FormDocHeader."Copy 2 Sent" := true; + end; + IRS1099FormDocHeader."Email Error Log" := ''; + IRS1099FormDocHeader.Modify(); + end; + + procedure SetEmailStatusFail(IRS1099EmailQueue: Record "IRS 1099 Email Queue"; ErrorText: Text) + var + IRS1099FormDocHeader: Record "IRS 1099 Form Doc. Header"; + begin + if not IRS1099FormDocHeader.Get(IRS1099EmailQueue."Document ID") then + exit; + SetEmailStatusFail(IRS1099FormDocHeader, IRS1099EmailQueue."Report Type", ErrorText); + end; + + procedure SetEmailStatusFail(var IRS1099FormDocHeader: Record "IRS 1099 Form Doc. Header"; ReportType: Enum "IRS 1099 Form Report Type"; ErrorText: Text) + begin + case ReportType of + Enum::"IRS 1099 Form Report Type"::"Copy B": + IRS1099FormDocHeader."Copy B Sent" := false; + Enum::"IRS 1099 Form Report Type"::"Copy 2": + IRS1099FormDocHeader."Copy 2 Sent" := false; + end; + IRS1099FormDocHeader."Email Error Log" := CopyStr(ErrorText, 1, MaxStrLen(IRS1099FormDocHeader."Email Error Log")); + IRS1099FormDocHeader.Modify(); + end; + + local procedure ResetEmailStatus(var IRS1099FormDocHeader: Record "IRS 1099 Form Doc. Header"; ReportType: Enum "IRS 1099 Form Report Type") + begin + case ReportType of + Enum::"IRS 1099 Form Report Type"::"Copy B": + IRS1099FormDocHeader."Copy B Sent" := false; + Enum::"IRS 1099 Form Report Type"::"Copy 2": + IRS1099FormDocHeader."Copy 2 Sent" := false; + end; + IRS1099FormDocHeader."Email Error Log" := ''; + IRS1099FormDocHeader.Modify(); + end; +} diff --git a/Apps/US/IRSForms/app/src/Emailing/IRS1099SendEmail.Report.al b/Apps/US/IRSForms/app/src/Emailing/IRS1099SendEmail.Report.al new file mode 100644 index 0000000000..9aca8dc030 --- /dev/null +++ b/Apps/US/IRSForms/app/src/Emailing/IRS1099SendEmail.Report.al @@ -0,0 +1,123 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +using System.Threading; + +report 10033 "IRS 1099 Send Email" +{ + ApplicationArea = BasicUS; + ProcessingOnly = true; + + dataset + { + dataitem(IRS1099FormDocHeader; "IRS 1099 Form Doc. Header") + { + DataItemTableView = sorting(ID); + } + } + + requestpage + { + SaveValues = true; + + layout + { + area(Content) + { + group(ReportTypeGroup) + { + ShowCaption = false; + field(ReportTypeField; ReportType) + { + ApplicationArea = BasicUS; + Caption = 'Report Type'; + ToolTip = 'Specifies the 1099 report type to send in the email. Note that only documents with status Submitted will be processed.'; + + trigger OnValidate() + begin + ResendEmail := false; + end; + } + field(ResendEmailField; ResendEmail) + { + ApplicationArea = BasicUS; + Visible = ResendEmailVisible; + Caption = 'Resend Email'; + ToolTip = 'The selected report type may have been sent to some vendors. Set the flag if you want to resend email to them.'; + } + } + } + } + + trigger OnOpenPage() + begin + SetResendEmailVisibility(); + end; + } + + var + ReportType: Enum "IRS 1099 Email Report Type"; + ResendEmail: Boolean; + ResendEmailVisible: Boolean; + NoDocumentSelectedErr: Label 'No 1099 form documents are selected for sending email. \\Current filters: %1', Comment = '%1 - filter string'; + + trigger OnPostReport() + var + IRS1099EmailQueue: Record "IRS 1099 Email Queue"; + IRS1099PrintParams: Record "IRS 1099 Print Params"; + IRS1099SendEmail: Codeunit "IRS 1099 Send Email"; + IRSFormsFacade: Codeunit "IRS Forms Facade"; + begin + if IRS1099FormDocHeader.Count() = 1 then begin + IRS1099FormDocHeader.FindFirst(); + IRS1099FormDocHeader.TestField(Status, "IRS 1099 Form Doc. Status"::Submitted); + + IRS1099PrintParams."Report Type" := ReportType; + IRSFormsFacade.SaveContentForDocument(IRS1099FormDocHeader, IRS1099PrintParams, false); + IRS1099SendEmail.SendEmailToVendor(IRS1099FormDocHeader, ReportType); + IRS1099SendEmail.SetEmailStatusSuccess(IRS1099FormDocHeader, ReportType); + exit; + end; + + IRS1099FormDocHeader.SetRange(Status, "IRS 1099 Form Doc. Status"::Submitted); + if not ResendEmail then + case ReportType of + "IRS 1099 Email Report Type"::"Copy B": + IRS1099FormDocHeader.SetRange("Copy B Sent", false); + "IRS 1099 Email Report Type"::"Copy 2": + IRS1099FormDocHeader.SetRange("Copy 2 Sent", false); + end; + if not IRS1099FormDocHeader.FindSet() then + Error(NoDocumentSelectedErr, IRS1099FormDocHeader.GetFilters()); + + IRS1099EmailQueue.DeleteAll(); + repeat + IRS1099EmailQueue."Entry No." := 0; + IRS1099EmailQueue."Document ID" := IRS1099FormDocHeader.ID; + IRS1099EmailQueue."Report Type" := ReportType; + IRS1099EmailQueue.Insert(); + until IRS1099FormDocHeader.Next() = 0; + ScheduleEmailJobQueue(); + end; + + procedure ScheduleEmailJobQueue() + var + JobQueueEntry: Record "Job Queue Entry"; + begin + JobQueueEntry.Init(); + JobQueueEntry.Validate("Object Type to Run", JobQueueEntry."Object Type to Run"::Codeunit); + JobQueueEntry.Validate("Object ID to Run", Codeunit::"IRS 1099 Process Email Queue"); + Codeunit.Run(Codeunit::"Job Queue - Enqueue", JobQueueEntry); + end; + + local procedure SetResendEmailVisibility() + begin + if IRS1099FormDocHeader.Count() = 1 then + ResendEmailVisible := false + else + ResendEmailVisible := true; + end; +} diff --git a/Apps/US/IRSForms/app/src/Emailing/IRS1099VendorEmail.Codeunit.al b/Apps/US/IRSForms/app/src/Emailing/IRS1099VendorEmail.Codeunit.al new file mode 100644 index 0000000000..9771b07936 --- /dev/null +++ b/Apps/US/IRSForms/app/src/Emailing/IRS1099VendorEmail.Codeunit.al @@ -0,0 +1,97 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +using Microsoft.Purchases.Vendor; +using System.Utilities; + +codeunit 10050 "IRS 1099 Vendor Email" +{ + Access = Internal; + InherentEntitlements = X; + InherentPermissions = X; + + var +#if not CLEAN25 + IRSFormsFeature: Codeunit "IRS Forms Feature"; +#endif + EmailNotSpecifiedErr: Label 'Either E-Mail For IRS or E-mail must be specified to receive 1099 forms electronically.'; + PropagateFieldToOpenedFormDocumentsQst: Label 'Do you want to propagate the %1 to all opened 1099 form documents by this vendor?', Comment = '%1 = field name'; + CannotRemoveEmailWhenOpenedFormDocsExistErr: Label 'Cannot remove the e-mail when opened 1099 form documents exist for this vendor.'; + + procedure CheckEmailForIRS(Vendor: Record Vendor) + begin +#if not CLEAN25 + if not IRSFormsFeature.IsEnabled() then + exit; +#endif + if GetEmailForIRSReporting(Vendor) = '' then + error(EmailNotSpecifiedErr); + end; + + procedure ClearConsentForEmptyEmail(var Vendor: Record Vendor) + var + IRS1099FormDocHeader: Record "IRS 1099 Form Doc. Header"; + begin +#if not CLEAN25 + if not IRSFormsFeature.IsEnabled() then + exit; +#endif + if GetEmailForIRSReporting(Vendor) = '' then begin + if Vendor."Receiving 1099 E-Form Consent" then begin + IRS1099FormDocHeader.SetRange("Vendor No.", Vendor."No."); + IRS1099FormDocHeader.SetRange(Status, IRS1099FormDocHeader.Status::Open); + if not IRS1099FormDocHeader.IsEmpty() then + Error(CannotRemoveEmailWhenOpenedFormDocsExistErr); + end; + Vendor."Receiving 1099 E-Form Consent" := false; + end; + end; + + procedure PropagateEmailToOpenedFormDocuments(Vendor: Record Vendor) + var + IRS1099FormDocHeader: Record "IRS 1099 Form Doc. Header"; + ConfirmManagement: Codeunit "Confirm Management"; + begin +#if not CLEAN25 + if not IRSFormsFeature.IsEnabled() then + exit; +#endif + IRS1099FormDocHeader.SetRange("Vendor No.", Vendor."No."); + IRS1099FormDocHeader.SetRange(Status, IRS1099FormDocHeader.Status::Open); + if IRS1099FormDocHeader.IsEmpty() then + exit; + if not ConfirmManagement.GetResponse(StrSubstNo(PropagateFieldToOpenedFormDocumentsQst, Vendor.FieldCaption("E-Mail")), false) then + exit; + IRS1099FormDocHeader.ModifyAll("Vendor E-Mail", GetEmailForIRSReporting(Vendor)); + end; + + procedure PropagateReceiving1099EFormConsentToOpenedFormDocuments(Vendor: Record Vendor) + var + IRS1099FormDocHeader: Record "IRS 1099 Form Doc. Header"; + ConfirmManagement: Codeunit "Confirm Management"; + begin +#if not CLEAN25 + if not IRSFormsFeature.IsEnabled() then + exit; +#endif + IRS1099FormDocHeader.SetRange("Vendor No.", Vendor."No."); + IRS1099FormDocHeader.SetRange(Status, IRS1099FormDocHeader.Status::Open); + if IRS1099FormDocHeader.IsEmpty() then + exit; + if not ConfirmManagement.GetResponse( + StrSubstNo(PropagateFieldToOpenedFormDocumentsQst, Vendor.FieldCaption("Receiving 1099 E-Form Consent")), false) + then + exit; + IRS1099FormDocHeader.ModifyAll("Receiving 1099 E-Form Consent", Vendor."Receiving 1099 E-Form Consent"); + end; + + local procedure GetEmailForIRSReporting(Vendor: Record Vendor): Text[80] + begin + if Vendor."E-Mail For IRS" <> '' then + exit(Vendor."E-Mail For IRS"); + exit(Vendor."E-Mail"); + end; +} diff --git a/Apps/US/IRSForms/app/src/Extensions/IRS1099BaseAppSubscribers.Codeunit.al b/Apps/US/IRSForms/app/src/Extensions/IRS1099BaseAppSubscribers.Codeunit.al new file mode 100644 index 0000000000..73ed525c62 --- /dev/null +++ b/Apps/US/IRSForms/app/src/Extensions/IRS1099BaseAppSubscribers.Codeunit.al @@ -0,0 +1,187 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +using Microsoft.Finance.GeneralLedger.Journal; +using Microsoft.Purchases.Document; +using Microsoft.Purchases.Payables; + +codeunit 10032 "IRS 1099 BaseApp Subscribers" +{ + Access = Internal; + InherentEntitlements = X; + InherentPermissions = X; + + var +#if not CLEAN25 + IRSFormsFeature: Codeunit "IRS Forms Feature"; +#endif + IRSReportingPeriod: Codeunit "IRS Reporting Period"; + + [EventSubscriber(ObjectType::Table, Database::"Gen. Journal Line", 'OnAfterCopyGenJnlLineFromPurchHeader', '', false, false)] + local procedure UpdateIRSDataOnAfterCopyGenJnlLineFromPurchHeader(PurchaseHeader: Record "Purchase Header"; var GenJournalLine: Record "Gen. Journal Line") + begin +#if not CLEAN25 + if not IRSFormsFeature.IsEnabled() then + exit; +#endif + if not (GenJournalLine."Document Type" in [GenJournalLine."Document Type"::Invoice, GenJournalLine."Document Type"::"Credit Memo"]) then + exit; + GenJournalLine.Validate("IRS 1099 Reporting Period", PurchaseHeader."IRS 1099 Reporting Period"); + if PurchaseHeader."IRS 1099 Form No." = '' then + exit; + GenJournalLine.Validate("IRS 1099 Form No.", PurchaseHeader."IRS 1099 Form No."); + GenJournalLine.Validate("IRS 1099 Form Box No.", PurchaseHeader."IRS 1099 Form Box No."); + PurchaseHeader.CalcFields("Amount Including VAT"); + if PurchaseHeader."Document Type" in [PurchaseHeader."Document Type"::"Return Order", PurchaseHeader."Document Type"::"Credit Memo"] then + GenJournalLine.Validate("IRS 1099 Reporting Amount", Round(PurchaseHeader."Amount Including VAT")) + else + GenJournalLine.Validate("IRS 1099 Reporting Amount", -Round(PurchaseHeader."Amount Including VAT")); + end; + + [EventSubscriber(ObjectType::Table, Database::"Vendor Ledger Entry", 'OnAfterCopyVendLedgerEntryFromGenJnlLine', '', false, false)] + local procedure UpdateIRSDataOnAfterCopyVendLedgerEntryFromGenJnlLine(var VendorLedgerEntry: Record "Vendor Ledger Entry"; GenJournalLine: Record "Gen. Journal Line") + begin +#if not CLEAN25 + if not IRSFormsFeature.IsEnabled() then + exit; +#endif + if GenJournalLine."IRS 1099 Reporting Amount" = 0 then + exit; + VendorLedgerEntry."IRS 1099 Subject For Reporting" := true; + VendorLedgerEntry."IRS 1099 Reporting Period" := GenJournalLine."IRS 1099 Reporting Period"; + VendorLedgerEntry."IRS 1099 Form No." := GenJournalLine."IRS 1099 Form No."; + VendorLedgerEntry."IRS 1099 Form Box No." := GenJournalLine."IRS 1099 Form Box No."; + VendorLedgerEntry."IRS 1099 Reporting Amount" := GenJournalLine."IRS 1099 Reporting Amount"; + end; + + [EventSubscriber(ObjectType::Table, Database::"Gen. Journal Line", 'OnAfterValidateEvent', 'Posting Date', false, false)] + local procedure UpdateIRSDataOnAfterValidatePostingDateInGenJnlLine(var Rec: Record "Gen. Journal Line") + begin + UpdateIRSDataInGenJnlLine(Rec); + end; + + [EventSubscriber(ObjectType::Table, Database::"Gen. Journal Line", 'OnAfterValidateEvent', 'Account No.', false, false)] + local procedure UpdateIRSDataOnAfterValidateAccNoInGenJnlLine(var Rec: Record "Gen. Journal Line") + begin + UpdateIRSDataInGenJnlLine(Rec); + end; + + [EventSubscriber(ObjectType::Table, Database::"Gen. Journal Line", 'OnAfterValidateEvent', 'Bal. Account No.', false, false)] + local procedure UpdateIRSDataOnAfterValidateBalAccNoInGenJnlLine(var Rec: Record "Gen. Journal Line") + begin + UpdateIRSDataInGenJnlLine(Rec); + end; + + [EventSubscriber(ObjectType::Table, Database::"Gen. Journal Line", 'OnAfterValidateEvent', 'Document Type', false, false)] + local procedure UpdateIRSDataOnAfterValidateDocumentTypeInGenJnlLine(var Rec: Record "Gen. Journal Line") + begin + UpdateIRSDataInGenJnlLine(Rec); + end; + + [EventSubscriber(ObjectType::Table, Database::"Gen. Journal Line", 'OnAfterValidateEvent', 'Amount', false, false)] + local procedure UpdateIRSReportingAmountOnAfterValidateAmountInGenJnlLine(var Rec: Record "Gen. Journal Line") + begin + UpdateIRSReportingAmountInGenJnlLine(Rec); + end; + + [EventSubscriber(ObjectType::Table, Database::"Gen. Journal Line", 'OnAfterSetupNewLine', '', false, false)] + local procedure UpdateIRSDataOnOnAfterSetupNewLineInGenJnlLine(var GenJournalLine: Record "Gen. Journal Line") + begin + UpdateIRSDataInGenJnlLine(GenJournalLine); + end; + + [EventSubscriber(ObjectType::Table, Database::"Purchase Header", 'OnAfterValidateEvent', 'Posting Date', false, false)] + local procedure UpdateIRSDataOnAfterValidatePostingDate(var Rec: Record "Purchase Header") + begin + UpdateIRSDataInPurchHeader(Rec, true); + end; + + [EventSubscriber(ObjectType::Table, Database::"Purchase Header", 'OnAfterValidateEvent', 'Pay-To Vendor No.', false, false)] + local procedure UpdateIRSDataOnAfterValidatePayToVendorNo(var Rec: Record "Purchase Header") + begin + UpdateIRSDataInPurchHeader(Rec, Rec."No." <> ''); + end; + + [EventSubscriber(ObjectType::Table, Database::"Purchase Header", 'OnAfterInitRecord', '', false, false)] + local procedure UpdateIRSDataOnAfterInitRecord(var PurchHeader: Record "Purchase Header") + begin + UpdateIRSDataInPurchHeader(PurchHeader, false); + end; + + [EventSubscriber(ObjectType::Codeunit, Codeunit::"Vend. Entry-Edit", 'OnBeforeVendLedgEntryModify', '', false, false)] + local procedure UpdateIRSDataOnBeforeVendLedgEntryModify(var VendLedgEntry: Record "Vendor Ledger Entry"; FromVendLedgEntry: Record "Vendor Ledger Entry") + begin +#if not CLEAN25 + if not IRSFormsFeature.IsEnabled() then + exit; +#endif + VendLedgEntry."IRS 1099 Form Box No." := FromVendLedgEntry."IRS 1099 Form Box No."; + VendLedgEntry."IRS 1099 Reporting Amount" := FromVendLedgEntry."IRS 1099 Reporting Amount"; + VendLedgEntry."IRS 1099 Subject For Reporting" := FromVendLedgEntry."IRS 1099 Subject For Reporting"; + end; + + procedure UpdateIRSDataInPurchHeader(var PurchHeader: Record "Purchase Header"; ModifyRecord: Boolean) + var + IRS1099VendorFormBoxSetup: Record "IRS 1099 Vendor Form Box Setup"; + PeriodNo: Code[20]; + begin +#if not CLEAN25 + if not IRSFormsFeature.IsEnabled() then + exit; +#endif + PeriodNo := IRSReportingPeriod.GetReportingPeriod(PurchHeader."Posting Date"); + if PeriodNo <> '' then + if not IRS1099VendorFormBoxSetup.Get(PeriodNo, PurchHeader."Pay-To Vendor No.") then + IRS1099VendorFormBoxSetup.Init(); + PurchHeader.Validate("IRS 1099 Reporting Period", PeriodNo); + PurchHeader.Validate("IRS 1099 Form No.", IRS1099VendorFormBoxSetup."Form No."); + PurchHeader.Validate("IRS 1099 Form Box No.", IRS1099VendorFormBoxSetup."Form Box No."); + if ModifyRecord then + PurchHeader.Modify(true); + end; + + procedure UpdateIRSDataInGenJnlLine(var GenJnlLine: Record "Gen. Journal Line") + var + IRS1099VendorFormBoxSetup: Record "IRS 1099 Vendor Form Box Setup"; + PeriodNo: Code[20]; + begin +#if not CLEAN25 + if not IRSFormsFeature.IsEnabled() then + exit; +#endif + if GenJnlLine."Document Type" in [GenJnlLine."Document Type"::Invoice, GenJnlLine."Document Type"::"Credit Memo"] then begin + PeriodNo := IRSReportingPeriod.GetReportingPeriod(GenJnlLine."Posting Date"); + GetIRS1099VendorFormBoxSetupFromGenJnlLine(IRS1099VendorFormBoxSetup, GenJnlLine, PeriodNo); + end; + GenJnlLine.Validate("IRS 1099 Reporting Period", PeriodNo); + GenJnlLine.Validate("IRS 1099 Form No.", IRS1099VendorFormBoxSetup."Form No."); + GenJnlLine.Validate("IRS 1099 Form Box No.", IRS1099VendorFormBoxSetup."Form Box No."); + if GenJnlLine."Line No." <> 0 then + GenJnlLine.Modify(true); + end; + + local procedure GetIRS1099VendorFormBoxSetupFromGenJnlLine(var IRS1099VendorFormBoxSetup: Record "IRS 1099 Vendor Form Box Setup"; GenJnlLine: Record "Gen. Journal Line"; PeriodNo: Code[20]) + begin + if PeriodNo = '' then + exit; + if GenJnlLine."Account Type" = GenJnlLine."Account Type"::Vendor then + if IRS1099VendorFormBoxSetup.Get(PeriodNo, GenJnlLine."Account No.") then; + if GenJnlLine."Bal. Account Type" = GenJnlLine."Bal. Account Type"::Vendor then + if IRS1099VendorFormBoxSetup.Get(PeriodNo, GenJnlLine."Bal. Account No.") then; + end; + + procedure UpdateIRSReportingAmountInGenJnlLine(var GenJnlLine: Record "Gen. Journal Line") + begin +#if not CLEAN25 + if not IRSFormsFeature.IsEnabled() then + exit; +#endif + GenJnlLine.Validate("IRS 1099 Reporting Amount", GenJnlLine.Amount); + if GenJnlLine."Line No." <> 0 then + GenJnlLine.Modify(true); + end; + +} diff --git a/Apps/US/IRSForms/app/src/Extensions/IRS1099GenJnlLine.TableExt.al b/Apps/US/IRSForms/app/src/Extensions/IRS1099GenJnlLine.TableExt.al new file mode 100644 index 0000000000..36fd316840 --- /dev/null +++ b/Apps/US/IRSForms/app/src/Extensions/IRS1099GenJnlLine.TableExt.al @@ -0,0 +1,49 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +using Microsoft.Finance.GeneralLedger.Journal; + +tableextension 10040 "IRS 1099 Gen. Jnl. Line" extends "Gen. Journal Line" +{ + fields + { + field(10051; "IRS 1099 Reporting Period"; Code[20]) + { + DataClassification = CustomerContent; + TableRelation = "IRS Reporting Period"; + Editable = false; + + trigger OnValidate() + begin + Validate("IRS 1099 Form No.", ''); + end; + } + field(10052; "IRS 1099 Form No."; Code[20]) + { + DataClassification = CustomerContent; + TableRelation = "IRS 1099 Form"."No." where("Period No." = field("IRS 1099 Reporting Period")); + + trigger OnValidate() + begin + Validate("IRS 1099 Form Box No.", ''); + end; + } + field(10053; "IRS 1099 Form Box No."; Code[20]) + { + DataClassification = CustomerContent; + TableRelation = "IRS 1099 Form Box"."No." where("Period No." = field("IRS 1099 Reporting Period"), "Form No." = field("IRS 1099 Form No.")); + + trigger OnValidate() + begin + Validate("IRS 1099 Reporting Amount", 0); + end; + } + field(10054; "IRS 1099 Reporting Amount"; Decimal) + { + DataClassification = CustomerContent; + } + } +} diff --git a/Apps/US/IRSForms/app/src/Extensions/IRS1099GeneralJournal.PageExt.al b/Apps/US/IRSForms/app/src/Extensions/IRS1099GeneralJournal.PageExt.al new file mode 100644 index 0000000000..1c1a6f5803 --- /dev/null +++ b/Apps/US/IRSForms/app/src/Extensions/IRS1099GeneralJournal.PageExt.al @@ -0,0 +1,74 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +using Microsoft.Finance.GeneralLedger.Journal; + +pageextension 10063 "IRS 1099 General Journal" extends "General Journal" +{ + layout + { + addafter("Deferral Code") + { + field("IRS 1099 Reporting Period"; Rec."IRS 1099 Reporting Period") + { + ApplicationArea = BasicUS; + Tooltip = 'Specifies the IRS reporting period for the document.'; +#if not CLEAN25 + Visible = IsNewFeatureEnabled; +#endif + } + field("IRS 1099 Form No."; Rec."IRS 1099 Form No.") + { + ApplicationArea = BasicUS; + Tooltip = 'Specifies the IRS form number for the document.'; +#if not CLEAN25 + Visible = IsNewFeatureEnabled; + Editable = NewFieldsAreEditable; +#endif + } + field("IRS 1099 Form Box No."; Rec."IRS 1099 Form Box No.") + { + ApplicationArea = BasicUS; + Tooltip = 'Specifies the IRS form box number for the vendor ledger entry.'; +#if not CLEAN25 + Visible = IsNewFeatureEnabled; + Editable = NewFieldsAreEditable; +#endif + } + } + } + +#if not CLEAN25 + var + IsNewFeatureEnabled: Boolean; + NewFieldsAreEditable: Boolean; +#endif + +#if not CLEAN25 + trigger OnOpenPage() + var + IRSFormsFeature: Codeunit "IRS Forms Feature"; + begin + IsNewFeatureEnabled := IRSFormsFeature.IsEnabled(); + UpdateNewFieldsAreVisible(); + end; + + trigger OnAfterGetCurrRecord() + begin + UpdateNewFieldsAreVisible(); + end; + + trigger OnAfterGetRecord() + begin + UpdateNewFieldsAreVisible(); + end; + + local procedure UpdateNewFieldsAreVisible() + begin + NewFieldsAreEditable := IsNewFeatureEnabled and (Rec."IRS 1099 Reporting Period" <> ''); + end; +#endif +} diff --git a/Apps/US/IRSForms/app/src/Extensions/IRS1099PostedGenJnlLine.TableExt.al b/Apps/US/IRSForms/app/src/Extensions/IRS1099PostedGenJnlLine.TableExt.al new file mode 100644 index 0000000000..89fd861d22 --- /dev/null +++ b/Apps/US/IRSForms/app/src/Extensions/IRS1099PostedGenJnlLine.TableExt.al @@ -0,0 +1,33 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +using Microsoft.Finance.GeneralLedger.Journal; + +tableextension 10050 "IRS 1099 Posted Gen. Jnl. Line" extends "Posted Gen. Journal Line" +{ + fields + { + field(10051; "IRS 1099 Reporting Period"; Code[20]) + { + DataClassification = CustomerContent; + TableRelation = "IRS Reporting Period"; + } + field(10052; "IRS 1099 Form No."; Code[20]) + { + DataClassification = CustomerContent; + TableRelation = "IRS 1099 Form"."No." where("Period No." = field("IRS 1099 Reporting Period")); + } + field(10053; "IRS 1099 Form Box No."; Code[20]) + { + DataClassification = CustomerContent; + TableRelation = "IRS 1099 Form Box"."No." where("Period No." = field("IRS 1099 Reporting Period"), "Form No." = field("IRS 1099 Form No.")); + } + field(10054; "IRS 1099 Reporting Amount"; Decimal) + { + DataClassification = CustomerContent; + } + } +} diff --git a/Apps/US/IRSForms/app/src/Extensions/IRS1099PostedPurchCrMemo.PageExt.al b/Apps/US/IRSForms/app/src/Extensions/IRS1099PostedPurchCrMemo.PageExt.al new file mode 100644 index 0000000000..a7cddf3682 --- /dev/null +++ b/Apps/US/IRSForms/app/src/Extensions/IRS1099PostedPurchCrMemo.PageExt.al @@ -0,0 +1,63 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +using Microsoft.Purchases.History; + +pageextension 10061 "IRS 1099 Posted Purch. Cr.Memo" extends "Posted Purchase Credit Memo" +{ + layout + { +#if not CLEAN25 +#pragma warning disable AL0432 + modify("IRS 1099 Code") + { + Visible = not IsNewFeatureEnabled; + } +#pragma warning restore AL0432 +#endif + addafter(Control46) + { + field("IRS 1099 Reporting Period"; Rec."IRS 1099 Reporting Period") + { + ApplicationArea = BasicUS; + Tooltip = 'Specifies the IRS reporting period for the document.'; +#if not CLEAN25 + Visible = IsNewFeatureEnabled; +#endif + } + field("IRS 1099 Form No."; Rec."IRS 1099 Form No.") + { + ApplicationArea = BasicUS; + Tooltip = 'Specifies the IRS form number for the document.'; +#if not CLEAN25 + Visible = IsNewFeatureEnabled; +#endif + Editable = false; + } + field("IRS 1099 Form Box No."; Rec."IRS 1099 Form Box No.") + { + ApplicationArea = BasicUS; + Tooltip = 'Specifies the IRS form box number for the vendor ledger entry.'; +#if not CLEAN25 + Visible = IsNewFeatureEnabled; +#endif + Editable = false; + } + } + } + +#if not CLEAN25 + var + IsNewFeatureEnabled: Boolean; + + trigger OnOpenPage() + var + IRSFormsFeature: Codeunit "IRS Forms Feature"; + begin + IsNewFeatureEnabled := IRSFormsFeature.IsEnabled(); + end; +#endif +} diff --git a/Apps/US/IRSForms/app/src/Extensions/IRS1099PostedPurchInv.PageExt.al b/Apps/US/IRSForms/app/src/Extensions/IRS1099PostedPurchInv.PageExt.al new file mode 100644 index 0000000000..1844bfff34 --- /dev/null +++ b/Apps/US/IRSForms/app/src/Extensions/IRS1099PostedPurchInv.PageExt.al @@ -0,0 +1,63 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +using Microsoft.Purchases.History; + +pageextension 10055 "IRS 1099 Posted Purch. Inv." extends "Posted Purchase Invoice" +{ + layout + { +#if not CLEAN25 +#pragma warning disable AL0432 + modify("IRS 1099 Code") + { + Visible = not IsNewFeatureEnabled; + } +#pragma warning restore AL0432 +#endif + addafter(Control60) + { + field("IRS 1099 Reporting Period"; Rec."IRS 1099 Reporting Period") + { + ApplicationArea = BasicUS; + Tooltip = 'Specifies the IRS reporting period for the document.'; +#if not CLEAN25 + Visible = IsNewFeatureEnabled; +#endif + } + field("IRS 1099 Form No."; Rec."IRS 1099 Form No.") + { + ApplicationArea = BasicUS; + Tooltip = 'Specifies the IRS form number for the document.'; +#if not CLEAN25 + Visible = IsNewFeatureEnabled; +#endif + Editable = false; + } + field("IRS 1099 Form Box No."; Rec."IRS 1099 Form Box No.") + { + ApplicationArea = BasicUS; + Tooltip = 'Specifies the IRS form box number for the vendor ledger entry.'; +#if not CLEAN25 + Visible = IsNewFeatureEnabled; +#endif + Editable = false; + } + } + } + +#if not CLEAN25 + var + IsNewFeatureEnabled: Boolean; + + trigger OnOpenPage() + var + IRSFormsFeature: Codeunit "IRS Forms Feature"; + begin + IsNewFeatureEnabled := IRSFormsFeature.IsEnabled(); + end; +#endif +} diff --git a/Apps/US/IRSForms/app/src/Extensions/IRS1099PurchCrMemo.PageExt.al b/Apps/US/IRSForms/app/src/Extensions/IRS1099PurchCrMemo.PageExt.al new file mode 100644 index 0000000000..ac3ddfa5cf --- /dev/null +++ b/Apps/US/IRSForms/app/src/Extensions/IRS1099PurchCrMemo.PageExt.al @@ -0,0 +1,82 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +using Microsoft.Purchases.Document; + +pageextension 10059 "IRS 1099 Purch. Cr. Memo" extends "Purchase Credit Memo" +{ + layout + { +#if not CLEAN25 +#pragma warning disable AL0432 + modify("IRS 1099 Code") + { + Visible = not IsNewFeatureEnabled; + } +#pragma warning restore AL0432 +#endif + addafter("Invoice Details") + { + field("IRS 1099 Reporting Period"; Rec."IRS 1099 Reporting Period") + { + ApplicationArea = BasicUS; + Tooltip = 'Specifies the IRS reporting period for the document.'; +#if not CLEAN25 + Visible = IsNewFeatureEnabled; +#endif + } + field("IRS 1099 Form No."; Rec."IRS 1099 Form No.") + { + ApplicationArea = BasicUS; + Tooltip = 'Specifies the IRS form number for the document.'; +#if not CLEAN25 + Visible = IsNewFeatureEnabled; + Editable = NewFieldsAreEditable; +#endif + } + field("IRS 1099 Form Box No."; Rec."IRS 1099 Form Box No.") + { + ApplicationArea = BasicUS; + Tooltip = 'Specifies the IRS form box number for the vendor ledger entry.'; +#if not CLEAN25 + Visible = IsNewFeatureEnabled; + Editable = NewFieldsAreEditable; +#endif + } + } + } + +#if not CLEAN25 + var + IsNewFeatureEnabled: Boolean; + NewFieldsAreEditable: Boolean; +#endif + +#if not CLEAN25 + trigger OnOpenPage() + var + IRSFormsFeature: Codeunit "IRS Forms Feature"; + begin + IsNewFeatureEnabled := IRSFormsFeature.IsEnabled(); + UpdateNewFieldsAreVisible(); + end; + + trigger OnAfterGetCurrRecord() + begin + UpdateNewFieldsAreVisible(); + end; + + trigger OnAfterGetRecord() + begin + UpdateNewFieldsAreVisible(); + end; + + local procedure UpdateNewFieldsAreVisible() + begin + NewFieldsAreEditable := IsNewFeatureEnabled and (Rec."IRS 1099 Reporting Period" <> ''); + end; +#endif +} diff --git a/Apps/US/IRSForms/app/src/Extensions/IRS1099PurchCrMemoHeader.TableExt.al b/Apps/US/IRSForms/app/src/Extensions/IRS1099PurchCrMemoHeader.TableExt.al new file mode 100644 index 0000000000..5f25c8ee8e --- /dev/null +++ b/Apps/US/IRSForms/app/src/Extensions/IRS1099PurchCrMemoHeader.TableExt.al @@ -0,0 +1,39 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +using Microsoft.Purchases.History; + +tableextension 10047 "IRS 1099 Purch. Cr.Memo Header" extends "Purch. Cr. Memo Hdr." +{ + fields + { + field(10031; "IRS 1099 Reporting Period"; Code[20]) + { + DataClassification = CustomerContent; + TableRelation = "IRS Reporting Period"; + + trigger OnValidate() + begin + Validate("IRS 1099 Form No.", ''); + end; + } + field(10032; "IRS 1099 Form No."; Code[20]) + { + DataClassification = CustomerContent; + TableRelation = "IRS 1099 Form"."No." where("Period No." = field("IRS 1099 Reporting Period")); + + trigger OnValidate() + begin + Validate("IRS 1099 Form Box No.", ''); + end; + } + field(10033; "IRS 1099 Form Box No."; Code[20]) + { + DataClassification = CustomerContent; + TableRelation = "IRS 1099 Form Box"."No." where("Period No." = field("IRS 1099 Reporting Period"), "Form No." = field("IRS 1099 Form No.")); + } + } +} diff --git a/Apps/US/IRSForms/app/src/Extensions/IRS1099PurchHeader.TableExt.al b/Apps/US/IRSForms/app/src/Extensions/IRS1099PurchHeader.TableExt.al new file mode 100644 index 0000000000..392ad7c96e --- /dev/null +++ b/Apps/US/IRSForms/app/src/Extensions/IRS1099PurchHeader.TableExt.al @@ -0,0 +1,40 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +using Microsoft.Purchases.Document; + +tableextension 10036 "IRS 1099 Purch. Header" extends "Purchase Header" +{ + fields + { + field(10031; "IRS 1099 Reporting Period"; Code[20]) + { + DataClassification = CustomerContent; + TableRelation = "IRS Reporting Period"; + Editable = false; + + trigger OnValidate() + begin + Validate("IRS 1099 Form No.", ''); + end; + } + field(10032; "IRS 1099 Form No."; Code[20]) + { + DataClassification = CustomerContent; + TableRelation = "IRS 1099 Form"."No." where("Period No." = field("IRS 1099 Reporting Period")); + + trigger OnValidate() + begin + Validate("IRS 1099 Form Box No.", ''); + end; + } + field(10033; "IRS 1099 Form Box No."; Code[20]) + { + DataClassification = CustomerContent; + TableRelation = "IRS 1099 Form Box"."No." where("Period No." = field("IRS 1099 Reporting Period"), "Form No." = field("IRS 1099 Form No.")); + } + } +} diff --git a/Apps/US/IRSForms/app/src/Extensions/IRS1099PurchHeaderArchive.TableExt.al b/Apps/US/IRSForms/app/src/Extensions/IRS1099PurchHeaderArchive.TableExt.al new file mode 100644 index 0000000000..e9cc5d9a4b --- /dev/null +++ b/Apps/US/IRSForms/app/src/Extensions/IRS1099PurchHeaderArchive.TableExt.al @@ -0,0 +1,29 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +using Microsoft.Purchases.Archive; + +tableextension 10049 "IRS 1099 Purch. Header Archive" extends "Purchase Header Archive" +{ + fields + { + field(10031; "IRS 1099 Reporting Period"; Code[20]) + { + DataClassification = CustomerContent; + TableRelation = "IRS Reporting Period"; + } + field(10032; "IRS 1099 Form No."; Code[20]) + { + DataClassification = CustomerContent; + TableRelation = "IRS 1099 Form"."No." where("Period No." = field("IRS 1099 Reporting Period")); + } + field(10033; "IRS 1099 Form Box No."; Code[20]) + { + DataClassification = CustomerContent; + TableRelation = "IRS 1099 Form Box"."No." where("Period No." = field("IRS 1099 Reporting Period"), "Form No." = field("IRS 1099 Form No.")); + } + } +} diff --git a/Apps/US/IRSForms/app/src/Extensions/IRS1099PurchInv.PageExt.al b/Apps/US/IRSForms/app/src/Extensions/IRS1099PurchInv.PageExt.al new file mode 100644 index 0000000000..8585b5a8f9 --- /dev/null +++ b/Apps/US/IRSForms/app/src/Extensions/IRS1099PurchInv.PageExt.al @@ -0,0 +1,82 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +using Microsoft.Purchases.Document; + +pageextension 10052 "IRS 1099 Purch. Inv." extends "Purchase Invoice" +{ + layout + { +#if not CLEAN25 +#pragma warning disable AL0432 + modify("IRS 1099 Code") + { + Visible = not IsNewFeatureEnabled; + } +#pragma warning restore AL0432 +#endif + addafter(Control88) + { + field("IRS 1099 Reporting Period"; Rec."IRS 1099 Reporting Period") + { + ApplicationArea = BasicUS; + Tooltip = 'Specifies the IRS reporting period for the document.'; +#if not CLEAN25 + Visible = IsNewFeatureEnabled; +#endif + } + field("IRS 1099 Form No."; Rec."IRS 1099 Form No.") + { + ApplicationArea = BasicUS; + Tooltip = 'Specifies the IRS form number for the document.'; +#if not CLEAN25 + Visible = IsNewFeatureEnabled; + Editable = NewFieldsAreEditable; +#endif + } + field("IRS 1099 Form Box No."; Rec."IRS 1099 Form Box No.") + { + ApplicationArea = BasicUS; + Tooltip = 'Specifies the IRS form box number.'; +#if not CLEAN25 + Visible = IsNewFeatureEnabled; + Editable = NewFieldsAreEditable; +#endif + } + } + } + +#if not CLEAN25 + var + IsNewFeatureEnabled: Boolean; + NewFieldsAreEditable: Boolean; +#endif + +#if not CLEAN25 + trigger OnOpenPage() + var + IRSFormsFeature: Codeunit "IRS Forms Feature"; + begin + IsNewFeatureEnabled := IRSFormsFeature.IsEnabled(); + UpdateNewFieldsAreVisible(); + end; + + trigger OnAfterGetCurrRecord() + begin + UpdateNewFieldsAreVisible(); + end; + + trigger OnAfterGetRecord() + begin + UpdateNewFieldsAreVisible(); + end; + + local procedure UpdateNewFieldsAreVisible() + begin + NewFieldsAreEditable := IsNewFeatureEnabled and (Rec."IRS 1099 Reporting Period" <> ''); + end; +#endif +} diff --git a/Apps/US/IRSForms/app/src/Extensions/IRS1099PurchInvHeader.TableExt.al b/Apps/US/IRSForms/app/src/Extensions/IRS1099PurchInvHeader.TableExt.al new file mode 100644 index 0000000000..459c631ff9 --- /dev/null +++ b/Apps/US/IRSForms/app/src/Extensions/IRS1099PurchInvHeader.TableExt.al @@ -0,0 +1,39 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +using Microsoft.Purchases.History; + +tableextension 10046 "IRS 1099 Purch. Inv. Header" extends "Purch. Inv. Header" +{ + fields + { + field(10031; "IRS 1099 Reporting Period"; Code[20]) + { + DataClassification = CustomerContent; + TableRelation = "IRS Reporting Period"; + + trigger OnValidate() + begin + Validate("IRS 1099 Form No.", ''); + end; + } + field(10032; "IRS 1099 Form No."; Code[20]) + { + DataClassification = CustomerContent; + TableRelation = "IRS 1099 Form"."No." where("Period No." = field("IRS 1099 Reporting Period")); + + trigger OnValidate() + begin + Validate("IRS 1099 Form Box No.", ''); + end; + } + field(10033; "IRS 1099 Form Box No."; Code[20]) + { + DataClassification = CustomerContent; + TableRelation = "IRS 1099 Form Box"."No." where("Period No." = field("IRS 1099 Reporting Period"), "Form No." = field("IRS 1099 Form No.")); + } + } +} diff --git a/Apps/US/IRSForms/app/src/Extensions/IRS1099PurchOrder.PageExt.al b/Apps/US/IRSForms/app/src/Extensions/IRS1099PurchOrder.PageExt.al new file mode 100644 index 0000000000..a8858b9a6c --- /dev/null +++ b/Apps/US/IRSForms/app/src/Extensions/IRS1099PurchOrder.PageExt.al @@ -0,0 +1,82 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +using Microsoft.Purchases.Document; + +pageextension 10058 "IRS 1099 Purch. Order" extends "Purchase Order" +{ + layout + { +#if not CLEAN25 +#pragma warning disable AL0432 + modify("IRS 1099 Code") + { + Visible = not IsNewFeatureEnabled; + } +#pragma warning restore AL0432 +#endif + addafter("Invoice Details") + { + field("IRS 1099 Reporting Period"; Rec."IRS 1099 Reporting Period") + { + ApplicationArea = BasicUS; + Tooltip = 'Specifies the IRS reporting period for the document.'; +#if not CLEAN25 + Visible = IsNewFeatureEnabled; +#endif + } + field("IRS 1099 Form No."; Rec."IRS 1099 Form No.") + { + ApplicationArea = BasicUS; + Tooltip = 'Specifies the IRS form number for the document.'; +#if not CLEAN25 + Visible = IsNewFeatureEnabled; + Editable = NewFieldsAreEditable; +#endif + } + field("IRS 1099 Form Box No."; Rec."IRS 1099 Form Box No.") + { + ApplicationArea = BasicUS; + Tooltip = 'Specifies the IRS form box number for the vendor ledger entry.'; +#if not CLEAN25 + Visible = IsNewFeatureEnabled; + Editable = NewFieldsAreEditable; +#endif + } + } + } + +#if not CLEAN25 + var + IsNewFeatureEnabled: Boolean; + NewFieldsAreEditable: Boolean; +#endif + +#if not CLEAN25 + trigger OnOpenPage() + var + IRSFormsFeature: Codeunit "IRS Forms Feature"; + begin + IsNewFeatureEnabled := IRSFormsFeature.IsEnabled(); + UpdateNewFieldsAreVisible(); + end; + + trigger OnAfterGetCurrRecord() + begin + UpdateNewFieldsAreVisible(); + end; + + trigger OnAfterGetRecord() + begin + UpdateNewFieldsAreVisible(); + end; + + local procedure UpdateNewFieldsAreVisible() + begin + NewFieldsAreEditable := IsNewFeatureEnabled and (Rec."IRS 1099 Reporting Period" <> ''); + end; +#endif +} diff --git a/Apps/US/IRSForms/app/src/Extensions/IRS1099PurchaseJournal.PageExt.al b/Apps/US/IRSForms/app/src/Extensions/IRS1099PurchaseJournal.PageExt.al new file mode 100644 index 0000000000..03642d6156 --- /dev/null +++ b/Apps/US/IRSForms/app/src/Extensions/IRS1099PurchaseJournal.PageExt.al @@ -0,0 +1,53 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +using Microsoft.Finance.GeneralLedger.Journal; + +pageextension 10062 "IRS 1099 Purchase Journal" extends "Purchase Journal" +{ + layout + { + addafter("Applies-to Doc. No.") + { + field("IRS 1099 Reporting Period"; Rec."IRS 1099 Reporting Period") + { + ApplicationArea = BasicUS; + Tooltip = 'Specifies the IRS reporting period for the document.'; +#if not CLEAN25 + Visible = IsNewFeatureEnabled; +#endif + } + field("IRS 1099 Form No."; Rec."IRS 1099 Form No.") + { + ApplicationArea = BasicUS; + Tooltip = 'Specifies the IRS form number for the document.'; +#if not CLEAN25 + Visible = IsNewFeatureEnabled; +#endif + } + field("IRS 1099 Form Box No."; Rec."IRS 1099 Form Box No.") + { + ApplicationArea = BasicUS; + Tooltip = 'Specifies the IRS form box number.'; +#if not CLEAN25 + Visible = IsNewFeatureEnabled; +#endif + } + } + } + +#if not CLEAN25 + var + IsNewFeatureEnabled: Boolean; + + trigger OnOpenPage() + var + IRSFormsFeature: Codeunit "IRS Forms Feature"; + begin + IsNewFeatureEnabled := IRSFormsFeature.IsEnabled(); + end; +#endif +} diff --git a/Apps/US/IRSForms/app/src/Extensions/IRS1099Vendor.TableExt.al b/Apps/US/IRSForms/app/src/Extensions/IRS1099Vendor.TableExt.al new file mode 100644 index 0000000000..0bb0c1ef1b --- /dev/null +++ b/Apps/US/IRSForms/app/src/Extensions/IRS1099Vendor.TableExt.al @@ -0,0 +1,77 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +using Microsoft.Purchases.Vendor; +using System.EMail; + +tableextension 10042 "IRS 1099 Vendor" extends Vendor +{ + + fields + { + field(10030; "Receiving 1099 E-Form Consent"; Boolean) + { + DataClassification = CustomerContent; + + trigger OnValidate() + begin + IRS1099VendorEmail.CheckEmailForIRS(Rec); + IRS1099VendorEmail.PropagateReceiving1099EFormConsentToOpenedFormDocuments(Rec); + end; + } + field(10031; "FATCA Requirement"; Boolean) + { + DataClassification = CustomerContent; + } + field(10032; "E-Mail For IRS"; Text[80]) + { + DataClassification = CustomerContent; + ExtendedDatatype = EMail; + + trigger OnValidate() + var + MailManagement: Codeunit "Mail Management"; + begin + IRS1099VendorEmail.ClearConsentForEmptyEmail(Rec); + if "E-Mail For IRS" <> '' then + MailManagement.CheckValidEmailAddresses("E-Mail For IRS"); + IRS1099VendorEmail.PropagateEmailToOpenedFormDocuments(Rec); + end; + } +#pragma warning disable AA0232 + field(10033; "IRS Reporting Period"; Code[20]) + { + FieldClass = FlowField; + CalcFormula = max("IRS 1099 Vendor Form Box Setup"."Period No." where("Vendor No." = field("No."))); + Editable = false; + } +#pragma warning restore AA0232 + field(10034; "IRS 1099 Form No."; Code[20]) + { + FieldClass = FlowField; + CalcFormula = max("IRS 1099 Vendor Form Box Setup"."Form No." where("Vendor No." = field("No."))); + Editable = false; + } + field(10035; "IRS 1099 Form Box No."; Code[20]) + { + FieldClass = FlowField; + CalcFormula = max("IRS 1099 Vendor Form Box Setup"."Form Box No." where("Vendor No." = field("No."))); + Editable = false; + } + modify("E-Mail") + { + trigger OnAfterValidate() + begin + IRS1099VendorEmail.ClearConsentForEmptyEmail(Rec); + IRS1099VendorEmail.PropagateEmailToOpenedFormDocuments(Rec); + end; + } + } + + var + IRS1099VendorEmail: Codeunit "IRS 1099 Vendor Email"; + +} diff --git a/Apps/US/IRSForms/app/src/Extensions/IRS1099VendorCard.PageExt.al b/Apps/US/IRSForms/app/src/Extensions/IRS1099VendorCard.PageExt.al new file mode 100644 index 0000000000..833ecb5b47 --- /dev/null +++ b/Apps/US/IRSForms/app/src/Extensions/IRS1099VendorCard.PageExt.al @@ -0,0 +1,135 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +using Microsoft.Purchases.Vendor; + +pageextension 10053 "IRS 1099 Vendor Card" extends "Vendor Card" +{ + layout + { +#if not CLEAN25 +#pragma warning disable AL0432 + modify("IRS 1099 Code") + { + Visible = not IsNewFeatureEnabled; + } + modify("FATCA filing requirement") + { + Visible = not IsNewFeatureEnabled; + } +#pragma warning restore AL0432 +#endif + addafter("Exclude from Pmt. Practices") + { + field("IRS Reporting Period"; Rec."IRS Reporting Period") + { + ApplicationArea = BasicUS; + ToolTip = 'Specifies the last IRS reporting period where the vendor has a vendor form box setup'; +#if not CLEAN25 + Visible = IsNewFeatureEnabled; +#endif + } + field("IRS 1099 Form No."; Rec."IRS 1099 Form No.") + { + ApplicationArea = BasicUS; + ToolTip = 'Specifies the IRS form number where the vendor has a vendor form box setup'; +#if not CLEAN25 + Visible = IsNewFeatureEnabled; +#endif + } + field("IRS 1099 Form Box No."; Rec."IRS 1099 Form Box No.") + { + ApplicationArea = BasicUS; + ToolTip = 'Specifies the IRS form box number where the vendor has a vendor form box setup'; +#if not CLEAN25 + Visible = IsNewFeatureEnabled; +#endif + } + field("Receive Elec. IRS Forms"; Rec."Receiving 1099 E-Form Consent") + { + ApplicationArea = BasicUS; +#pragma warning disable AA0219 + Tooltip = 'By selecting this field, you acknowledge that your vendor has provided signed consent to receive their 1099 form electronically.'; +#pragma warning restore AA0219 +#if not CLEAN25 + Visible = IsNewFeatureEnabled; +#endif + } + field("E-Mail For IRS"; Rec."E-Mail For IRS") + { + ApplicationArea = BasicUS; + ToolTip = 'Specifies the email address of the vendor to receive the IRS 1099 form.'; +#if not CLEAN25 + Visible = IsNewFeatureEnabled; +#endif + } + field("FATCA Requirement"; Rec."FATCA Requirement") + { + ApplicationArea = BasicUS; + ToolTip = 'Specifies if the vendor is set up to require FATCA filing.'; +#if not CLEAN25 + Visible = IsNewFeatureEnabled; +#endif + } + } + } + + actions + { +#if not CLEAN25 +#pragma warning disable AL0432 + modify("1099 Statistics") + { + Visible = not IsNewFeatureEnabled; + } + modify("Vendor 1099 Div") + { + Visible = not IsNewFeatureEnabled; + } + modify("Vendor 1099 Information") + { + Visible = not IsNewFeatureEnabled; + } + modify("Vendor 1099 Int") + { + Visible = not IsNewFeatureEnabled; + } + modify("Vendor 1099 Misc") + { + Visible = not IsNewFeatureEnabled; + } +#pragma warning restore AL0432 +#endif + addlast("&Purchases") + { + action(IRS1099Setup) + { + Caption = 'IRS 1099 Setup'; + ApplicationArea = BasicUS; +#if not CLEAN25 + Visible = IsNewFeatureEnabled; +#endif + Image = Vendor; + Scope = Repeater; + ToolTip = 'Specifies the setup for a vendor to be reported in IRS 1099 form in this period.'; + RunObject = Page "IRS 1099 Vendor Form Box Setup"; + RunPageLink = "Vendor No." = field("No."); + } + } + } + +#if not CLEAN25 + var + IsNewFeatureEnabled: Boolean; + + trigger OnOpenPage() + var + IRSFormsFeature: Codeunit "IRS Forms Feature"; + begin + IsNewFeatureEnabled := IRSFormsFeature.IsEnabled(); + end; +#endif +} diff --git a/Apps/US/IRSForms/app/src/Extensions/IRS1099VendorLedgerEntries.PageExt.al b/Apps/US/IRSForms/app/src/Extensions/IRS1099VendorLedgerEntries.PageExt.al new file mode 100644 index 0000000000..a2cddd024b --- /dev/null +++ b/Apps/US/IRSForms/app/src/Extensions/IRS1099VendorLedgerEntries.PageExt.al @@ -0,0 +1,73 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +using Microsoft.Purchases.Payables; + +pageextension 10048 "IRS 1099 Vendor Ledger Entries" extends "Vendor Ledger Entries" +{ + layout + { +#if not CLEAN25 +#pragma warning disable AL0432 + modify("IRS 1099 Code") + { + Visible = not IsNewFeatureEnabled; + } + modify("IRS 1099 Amount") + { + Visible = not IsNewFeatureEnabled; + } +#pragma warning restore AL0432 +#endif + addafter("Exported to Payment File") + { + field("IRS 1099 Reporting Period"; Rec."IRS 1099 Reporting Period") + { + ApplicationArea = BasicUS; + Tooltip = 'Specifies the IRS reporting period for the vendor ledger entry.'; +#if not CLEAN25 + Visible = IsNewFeatureEnabled; +#endif + } + field("IRS 1099 Form No."; Rec."IRS 1099 Form No.") + { + ApplicationArea = BasicUS; + Tooltip = 'Specifies the IRS form number for the vendor ledger entry.'; +#if not CLEAN25 + Visible = IsNewFeatureEnabled; +#endif + } + field("IRS 1099 Form Box No."; Rec."IRS 1099 Form Box No.") + { + ApplicationArea = BasicUS; + Tooltip = 'Specifies the IRS form box number for the vendor ledger entry.'; +#if not CLEAN25 + Visible = IsNewFeatureEnabled; +#endif + } + field("IRS 1099 Reporting Amount"; Rec."IRS 1099 Reporting Amount") + { + ApplicationArea = BasicUS; + Tooltip = 'Specifies the IRS reporting amount for the vendor ledger entry.'; +#if not CLEAN25 + Visible = IsNewFeatureEnabled; +#endif + } + } + } + +#if not CLEAN25 + var + IsNewFeatureEnabled: Boolean; + + trigger OnOpenPage() + var + IRSFormsFeature: Codeunit "IRS Forms Feature"; + begin + IsNewFeatureEnabled := IRSFormsFeature.IsEnabled(); + end; +#endif +} diff --git a/Apps/US/IRSForms/app/src/Extensions/IRS1099VendorLedgerEntry.TableExt.al b/Apps/US/IRSForms/app/src/Extensions/IRS1099VendorLedgerEntry.TableExt.al new file mode 100644 index 0000000000..d6190fb638 --- /dev/null +++ b/Apps/US/IRSForms/app/src/Extensions/IRS1099VendorLedgerEntry.TableExt.al @@ -0,0 +1,74 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +using Microsoft.Purchases.Payables; + +tableextension 10035 "IRS 1099 Vendor Ledger Entry" extends "Vendor Ledger Entry" +{ + + fields + { + field(10030; "IRS 1099 Subject For Reporting"; Boolean) + { + DataClassification = CustomerContent; + Editable = false; + } + field(10031; "IRS 1099 Reporting Period"; Code[20]) + { + DataClassification = CustomerContent; + TableRelation = "IRS Reporting Period"; + Editable = false; + } + field(10032; "IRS 1099 Form No."; Code[20]) + { + DataClassification = CustomerContent; + TableRelation = "IRS 1099 Form"."No." where("Period No." = field("IRS 1099 Reporting Period")); + + trigger OnValidate() + begin + IRS1099FormDocument.CheckIfVendLedgEntryAllowed(Rec."Entry No."); + Validate("IRS 1099 Form Box No.", ''); + Validate("IRS 1099 Reporting Amount", 0); + end; + } + field(10033; "IRS 1099 Form Box No."; Code[20]) + { + DataClassification = CustomerContent; + TableRelation = "IRS 1099 Form Box"."No." where("Period No." = field("IRS 1099 Reporting Period"), "Form No." = field("IRS 1099 Form No.")); + + trigger OnValidate() + begin + IRS1099FormDocument.CheckIfVendLedgEntryAllowed(Rec."Entry No."); + "IRS 1099 Subject For Reporting" := "IRS 1099 Form Box No." <> ''; + end; + } + field(10034; "IRS 1099 Reporting Amount"; Decimal) + { + DataClassification = CustomerContent; + + trigger OnValidate() + begin + IRS1099FormDocument.CheckIfVendLedgEntryAllowed(Rec."Entry No."); + if "IRS 1099 Reporting Amount" <> 0 then begin + CalcFields(Amount); + if ("Document Type" = "Document Type"::Invoice) and ("IRS 1099 Reporting Amount" > 0) then + FieldError("IRS 1099 Reporting Amount", MustBeNegativeErr); + if ("Document Type" = "Document Type"::"Credit Memo") and ("IRS 1099 Reporting Amount" < 0) then + FieldError("IRS 1099 Reporting Amount", MustBePositiveErr); + if Abs("IRS 1099 Reporting Amount") > Abs(Amount) then + error(IRSReportingAmountCannotBeMoreThanAmountErr); + end; + "IRS 1099 Subject For Reporting" := ("IRS 1099 Form Box No." <> '') and ("IRS 1099 Reporting Amount" <> 0); + end; + } + } + + var + IRS1099FormDocument: Codeunit "IRS 1099 Form Document"; + IRSReportingAmountCannotBeMoreThanAmountErr: Label 'IRS Reporting Amount cannot be more than Amount'; + MustBePositiveErr: Label 'must be positive'; + MustBeNegativeErr: Label 'must be negative'; +} diff --git a/Apps/US/IRSForms/app/src/Extensions/IRS1099VendorList.PageExt.al b/Apps/US/IRSForms/app/src/Extensions/IRS1099VendorList.PageExt.al new file mode 100644 index 0000000000..c77f623c4c --- /dev/null +++ b/Apps/US/IRSForms/app/src/Extensions/IRS1099VendorList.PageExt.al @@ -0,0 +1,80 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +using Microsoft.Purchases.Vendor; + +pageextension 10050 "IRS 1099 Vendor List" extends "Vendor List" +{ + actions + { +#if not CLEAN25 +#pragma warning disable AL0432 + modify("1099 Statistics") + { + Visible = not IsNewFeatureEnabled; + } + modify("Vendor 1099 Div") + { + Visible = not IsNewFeatureEnabled; + } + modify("Vendor 1099 Information") + { + Visible = not IsNewFeatureEnabled; + } + modify("Vendor 1099 Int") + { + Visible = not IsNewFeatureEnabled; + } + modify("Vendor 1099 Misc") + { + Visible = not IsNewFeatureEnabled; + } + modify(RunVendor1099NecReport) + { + Visible = not IsNewFeatureEnabled; + } +#pragma warning restore AL0432 +#endif + addlast("&Purchases") + { + action(IRS1099Setup) + { + Caption = 'IRS 1099 Setup'; + ApplicationArea = BasicUS; +#if not CLEAN25 + Visible = IsNewFeatureEnabled; +#endif + Image = Vendor; + Scope = Repeater; + ToolTip = 'Specifies the setup for a vendor to be reported in IRS 1099 form'; + RunObject = Page "IRS 1099 Vendor Form Box Setup"; + RunPageLink = "Vendor No." = field("No."); + } + action(Adjustments) + { + Caption = 'Adjustments'; + ApplicationArea = BasicUS; + Image = AdjustEntries; + Scope = Repeater; + ToolTip = 'Specifies the adjustment amount for certain form boxes for this vendor'; + RunObject = Page "IRS 1099 Vend. Form Box Adjmts"; + RunPageLink = "Vendor No." = field("No."); + } + } + } + +#if not CLEAN25 + var + IsNewFeatureEnabled: Boolean; + + trigger OnOpenPage() + var + IRSFormsFeature: Codeunit "IRS Forms Feature"; + begin + IsNewFeatureEnabled := IRSFormsFeature.IsEnabled(); + end; +#endif +} diff --git a/Apps/US/IRSForms/app/src/Interface/IRS1099CreateFormDocs.Interface.al b/Apps/US/IRSForms/app/src/Interface/IRS1099CreateFormDocs.Interface.al new file mode 100644 index 0000000000..813e07165b --- /dev/null +++ b/Apps/US/IRSForms/app/src/Interface/IRS1099CreateFormDocs.Interface.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.VAT.Reporting; + +///

+/// The interface to create 1099 form documents +/// +interface "IRS 1099 Create Form Docs" +{ + /// + /// Creates 1099 form documents + /// + /// The calculated buffer with 1099 form box amounts + /// The calculated parameters + procedure CreateFormDocs(var TempVendFormBoxBuffer: Record "IRS 1099 Vend. Form Box Buffer" temporary; IRS1099CalcParameters: Record "IRS 1099 Calc. Params"); +} diff --git a/Apps/US/IRSForms/app/src/Interface/IRS1099FormBoxCalc.Interface.al b/Apps/US/IRSForms/app/src/Interface/IRS1099FormBoxCalc.Interface.al new file mode 100644 index 0000000000..51c585f875 --- /dev/null +++ b/Apps/US/IRSForms/app/src/Interface/IRS1099FormBoxCalc.Interface.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.VAT.Reporting; + +/// +/// The interface to calculate the amount for a specific box on the IRS 1099 form. +/// +interface "IRS 1099 Form Box Calc." +{ + /// + /// Calculates the amount for a specific box on the IRS 1099 form according to the calculated parameters. + /// + /// The calculated buffer + /// The calculated parameters + procedure GetVendorFormBoxAmount(var TempVendFormBoxBuffer: Record "IRS 1099 Vend. Form Box Buffer" temporary; IRS1099CalcParameters: Record "IRS 1099 Calc. Params") +} diff --git a/Apps/US/IRSForms/app/src/Interface/IRS1099FormInstruction.Table.al b/Apps/US/IRSForms/app/src/Interface/IRS1099FormInstruction.Table.al new file mode 100644 index 0000000000..016b49b4e7 --- /dev/null +++ b/Apps/US/IRSForms/app/src/Interface/IRS1099FormInstruction.Table.al @@ -0,0 +1,43 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +table 10042 "IRS 1099 Form Instruction" +{ + DataClassification = CustomerContent; + + fields + { + field(1; "Period No."; Code[20]) + { + TableRelation = "IRS Reporting Period"; + } + field(2; "Form No."; Code[20]) + { + TableRelation = "IRS 1099 Form"."No." where("Period No." = field("Period No.")); + } + field(3; "Line No."; Integer) + { + AutoIncrement = true; + NotBlank = true; + } + field(5; Header; Text[250]) + { + + } + field(6; Description; Text[2048]) + { + + } + } + + keys + { + key(PK; "Period No.", "Form No.", "Line No.") + { + Clustered = true; + } + } +} diff --git a/Apps/US/IRSForms/app/src/Interface/IRS1099Printing.Interface.al b/Apps/US/IRSForms/app/src/Interface/IRS1099Printing.Interface.al new file mode 100644 index 0000000000..5915a7e36b --- /dev/null +++ b/Apps/US/IRSForms/app/src/Interface/IRS1099Printing.Interface.al @@ -0,0 +1,24 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +/// +/// The interface to print 1099 form documents. +/// +interface "IRS 1099 Printing" +{ + /// + /// Saves the content of the printed form document + /// + /// The current form document + /// Printing parameters + /// Replace the existing saved printed form document + procedure SaveContentForDocument(var IRS1099FormDocHeader: Record "IRS 1099 Form Doc. Header"; IRS1099PrintParams: Record "IRS 1099 Print Params"; ReplaceIfExists: Boolean) + /// + /// Prints the form document + /// + /// The current form document + procedure PrintContent(IRS1099FormDocHeader: Record "IRS 1099 Form Doc. Header") +} diff --git a/Apps/US/IRSForms/app/src/Interface/IRSFormsFacade.Codeunit.al b/Apps/US/IRSForms/app/src/Interface/IRSFormsFacade.Codeunit.al new file mode 100644 index 0000000000..ba0c61468a --- /dev/null +++ b/Apps/US/IRSForms/app/src/Interface/IRSFormsFacade.Codeunit.al @@ -0,0 +1,33 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +codeunit 10054 "IRS Forms Facade" +{ + Access = Public; + + var + IRSFormsOrchestrator: Codeunit "IRS Forms Orchestrator"; + + procedure GetVendorFormBoxAmount(var TempVendFormBoxBuffer: Record "IRS 1099 Vend. Form Box Buffer" temporary; IRS1099CalcParameters: Record "IRS 1099 Calc. Params") + begin + IRSFormsOrchestrator.GetFormBoxCalcImplementation().GetVendorFormBoxAmount(TempVendFormBoxBuffer, IRS1099CalcParameters); + end; + + procedure CreateFormDocs(var TempVendFormBoxBuffer: Record "IRS 1099 Vend. Form Box Buffer" temporary; IRS1099CalcParameters: Record "IRS 1099 Calc. Params"); + begin + IRSFormsOrchestrator.GetCreateFormDocsImplementation().CreateFormDocs(TempVendFormBoxBuffer, IRS1099CalcParameters); + end; + + procedure SaveContentForDocument(var IRS1099FormDocHeader: Record "IRS 1099 Form Doc. Header"; IRS1099PrintParams: Record "IRS 1099 Print Params"; ReplaceIfExists: Boolean) + begin + IRSFormsOrchestrator.GetPrintingImplementation().SaveContentForDocument(IRS1099FormDocHeader, IRS1099PrintParams, ReplaceIfExists); + end; + + procedure PrintContent(IRS1099FormDocHeader: Record "IRS 1099 Form Doc. Header") + begin + IRSFormsOrchestrator.GetPrintingImplementation().PrintContent(IRS1099FormDocHeader); + end; +} diff --git a/Apps/US/IRSForms/app/src/Interface/IRSFormsImplementation.Enum.al b/Apps/US/IRSForms/app/src/Interface/IRSFormsImplementation.Enum.al new file mode 100644 index 0000000000..e99342d74c --- /dev/null +++ b/Apps/US/IRSForms/app/src/Interface/IRSFormsImplementation.Enum.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.VAT.Reporting; + +enum 10031 "IRS Forms Implementation" implements "IRS 1099 Create Form Docs", "IRS 1099 Printing", "IRS 1099 Form Box Calc." +{ + Extensible = true; + DefaultImplementation = "IRS 1099 Create Form Docs" = "IRS 1099 Form Docs Impl.", + "IRS 1099 Printing" = "IRS 1099 Printing Impl.", + "IRS 1099 Form Box Calc." = "IRS 1099 Form Box Calc. Impl."; + + value(0; Standard) + { + } + +} diff --git a/Apps/US/IRSForms/app/src/Interface/IRSFormsOrchestrator.Codeunit.al b/Apps/US/IRSForms/app/src/Interface/IRSFormsOrchestrator.Codeunit.al new file mode 100644 index 0000000000..3a4c23edc1 --- /dev/null +++ b/Apps/US/IRSForms/app/src/Interface/IRSFormsOrchestrator.Codeunit.al @@ -0,0 +1,35 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +codeunit 10034 "IRS Forms Orchestrator" +{ + Access = Internal; + InherentEntitlements = X; + InherentPermissions = X; + + procedure GetCreateFormDocsImplementation(): Interface "IRS 1099 Create Form Docs" + begin + exit(GetImplementation()); + end; + + procedure GetPrintingImplementation(): Interface "IRS 1099 Printing" + begin + exit(GetImplementation()); + end; + + procedure GetFormBoxCalcImplementation(): Interface "IRS 1099 Form Box Calc." + begin + exit(GetImplementation()); + end; + + local procedure GetImplementation(): Enum "IRS Forms Implementation" + var + IRSFormsSetup: Record "IRS Forms Setup"; + begin + IRSFormsSetup.InitSetup(); + exit(IRSFormsSetup.Implementation); + end; +} diff --git a/Apps/US/IRSForms/app/src/Printing/IRS 1099 Print.docx b/Apps/US/IRSForms/app/src/Printing/IRS 1099 Print.docx new file mode 100644 index 0000000000000000000000000000000000000000..6d5d85da6ae5608558fd6f3f7ec6f09996e55857 GIT binary patch literal 27144 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 C-0SNA literal 0 HcmV?d00001 diff --git a/Apps/US/IRSForms/app/src/Printing/IRS1099Dataset.Codeunit.al b/Apps/US/IRSForms/app/src/Printing/IRS1099Dataset.Codeunit.al new file mode 100644 index 0000000000..453bb664f2 --- /dev/null +++ b/Apps/US/IRSForms/app/src/Printing/IRS1099Dataset.Codeunit.al @@ -0,0 +1,79 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +codeunit 10055 "IRS 1099 Dataset" +{ + Access = Internal; + InherentEntitlements = X; + InherentPermissions = X; + + var + IRS1099FormStatementLineEmptyErr: Label 'There are no form statement lines for the selected form and period.'; + + procedure Get1099Dataset(IRS1099FormDocHeader: Record "IRS 1099 Form Doc. Header"; var IRS1099ReportLine: Record "IRS 1099 Report Line") + var + IRS1099FormDocLine: Record "IRS 1099 Form Doc. Line"; + IRS1099FormStatementLine: Record "IRS 1099 Form Statement Line"; + LineNo: Integer; + begin + IRS1099ReportLine.Reset(); + IRS1099ReportLine.DeleteAll(); + LineNo := 0; + IRS1099FormStatementLine.SetRange("Period No.", IRS1099FormDocHeader."Period No."); + IRS1099FormStatementLine.SetRange("Form No.", IRS1099FormDocHeader."Form No."); + if not IRS1099FormStatementLine.FindSet() then + Error(IRS1099FormStatementLineEmptyErr); + + repeat + IRS1099FormDocLine.SetView(IRS1099FormStatementLine."Record View String"); + SetDefaultFilters(IRS1099FormDocLine, IRS1099FormDocHeader); + if IRS1099FormDocLine.FindSet() then begin + IRS1099FormDocLine.CalcSums(Amount); + if IRS1099FormStatementLine."Print Value Type" = IRS1099FormStatementLine."Print Value Type"::Amount then + Add1099ReportLine(IRS1099ReportLine, LineNo, IRS1099FormDocLine."Form Box No.", GetFormBoxDescription(IRS1099FormStatementLine, IRS1099FormDocLine), Format(GetSign(IRS1099FormStatementLine) * IRS1099FormDocLine.Amount, 0, 2)) + else + Add1099ReportLine(IRS1099ReportLine, LineNo, IRS1099FormDocLine."Form Box No.", GetFormBoxDescription(IRS1099FormStatementLine, IRS1099FormDocLine), 'Yes'); + LineNo += 1; + end; + until IRS1099FormStatementLine.Next() = 0; + end; + + local procedure GetSign(IRS1099FormStatementLine: Record "IRS 1099 Form Statement Line"): Decimal + begin + if IRS1099FormStatementLine."Print with" = IRS1099FormStatementLine."Print with"::"Opposite Sign" then + exit(-1) + else + exit(1); + end; + + local procedure SetDefaultFilters(var IRS1099FormDocLine: Record "IRS 1099 Form Doc. Line"; IRS1099FormDocHeader: Record "IRS 1099 Form Doc. Header") + begin + IRS1099FormDocLine.SetRange("Document ID", IRS1099FormDocHeader.ID); + IRS1099FormDocLine.SetRange("Include In 1099", true); + end; + + local procedure GetFormBoxDescription(IRS1099FormStatementLine: Record "IRS 1099 Form Statement Line"; IRS1099FormDocLine: Record "IRS 1099 Form Doc. Line"): Text[250] + var + IRS1099FormBox: Record "IRS 1099 Form Box"; + begin + if IRS1099FormStatementLine.Description <> '' then + exit(IRS1099FormStatementLine.Description); + IRS1099FormBox.SetRange("Period No.", IRS1099FormDocLine."Period No."); + IRS1099FormBox.SetRange("Form No.", IRS1099FormDocLine."Form No."); + IRS1099FormBox.SetRange("No.", IRS1099FormDocLine."Form Box No."); + if IRS1099FormBox.FindFirst() then + exit(IRS1099FormBox.Description); + end; + + local procedure Add1099ReportLine(var IRS1099ReportLine: Record "IRS 1099 Report Line"; LineNo: Integer; BoxNo: Text; BoxDecription: Text; Value: Text) + begin + IRS1099ReportLine.Init(); + IRS1099ReportLine."Line No." := LineNo; + IRS1099ReportLine.Name := CopyStr(BoxNo + ' - ' + BoxDecription, 1, 250); + IRS1099ReportLine.Value := CopyStr(Value, 1, MaxStrLen(IRS1099ReportLine.Value)); + IRS1099ReportLine.Insert(); + end; +} diff --git a/Apps/US/IRSForms/app/src/Printing/IRS1099FormInstructions.Page.al b/Apps/US/IRSForms/app/src/Printing/IRS1099FormInstructions.Page.al new file mode 100644 index 0000000000..2ed2b552af --- /dev/null +++ b/Apps/US/IRSForms/app/src/Printing/IRS1099FormInstructions.Page.al @@ -0,0 +1,41 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +page 10050 "IRS 1099 Form Instructions" +{ + PageType = List; + SourceTable = "IRS 1099 Form Instruction"; + ApplicationArea = BasicUS; + DelayedInsert = true; + + layout + { + area(content) + { + repeater(Group) + { + field("Period No."; Rec."Period No.") + { + Tooltip = 'Specifies the period of the 1099 form box.'; + Visible = false; + } + field("Form No."; Rec."Form No.") + { + Tooltip = 'Specifies the 1099 form number that box belongs to.'; + Visible = false; + } + field(Header; Rec.Header) + { + ToolTip = 'Specifies the header of the instruction text.'; + } + field(Description; Rec.Description) + { + ToolTip = 'Specifies the instruction text.'; + } + } + } + } +} diff --git a/Apps/US/IRSForms/app/src/Printing/IRS1099FormReport.Table.al b/Apps/US/IRSForms/app/src/Printing/IRS1099FormReport.Table.al new file mode 100644 index 0000000000..a7e08518cb --- /dev/null +++ b/Apps/US/IRSForms/app/src/Printing/IRS1099FormReport.Table.al @@ -0,0 +1,53 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +table 10043 "IRS 1099 Form Report" +{ + DataClassification = CustomerContent; + DrillDownPageId = "IRS 1099 Form Reports"; + LookupPageId = "IRS 1099 Form Reports"; + + fields + { + field(1; "Document ID"; Integer) + { + } + field(2; "Report Type"; Enum "IRS 1099 Form Report Type") + { + } + field(20; "File Content"; Blob) + { + } + } + + keys + { + key(PK; "Document ID", "Report Type") + { + Clustered = true; + } + } + + var + NoFileErr: Label 'There is no file to download.'; + SaveFileDialogTxt: Label 'Save 1099 form report'; + FileNameTxt: Label 'IRS1099_%1.pdf', Locked = true; + + procedure DownloadReportFile() + var + FileInStream: InStream; + FileName: Text; + begin + Rec.CalcFields("File Content"); + if not Rec."File Content".HasValue() then + Error(NoFileErr); + Rec."File Content".CreateInStream(FileInStream); + FileName := StrSubstNo(FileNameTxt, DelChr(Format(Rec."Report Type"))); +#pragma warning disable AA0139 + DownloadFromStream(FileInStream, SaveFileDialogTxt, '', '', FileName); +#pragma warning restore + end; +} diff --git a/Apps/US/IRSForms/app/src/Printing/IRS1099FormReportType.Enum.al b/Apps/US/IRSForms/app/src/Printing/IRS1099FormReportType.Enum.al new file mode 100644 index 0000000000..0d7ec2793c --- /dev/null +++ b/Apps/US/IRSForms/app/src/Printing/IRS1099FormReportType.Enum.al @@ -0,0 +1,25 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +enum 10033 "IRS 1099 Form Report Type" +{ + AssignmentCompatibility = true; + Extensible = true; + + + value(1; "Copy B") + { + Caption = 'Copy B: goes to the recipient.'; + } + value(2; "Copy C") + { + Caption = 'Copy C: stays with the employer for record keeping.'; + } + value(3; "Copy 2") + { + Caption = 'Copy 2: goes to the recipient in some states.'; + } +} diff --git a/Apps/US/IRSForms/app/src/Printing/IRS1099FormReports.Page.al b/Apps/US/IRSForms/app/src/Printing/IRS1099FormReports.Page.al new file mode 100644 index 0000000000..389135ab40 --- /dev/null +++ b/Apps/US/IRSForms/app/src/Printing/IRS1099FormReports.Page.al @@ -0,0 +1,30 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +page 10048 "IRS 1099 Form Reports" +{ + PageType = List; + SourceTable = "IRS 1099 Form Report"; + ApplicationArea = BasicUS; + Editable = true; + layout + { + area(content) + { + repeater(Group) + { + field("Report Type"; Rec."Report Type") + { + Tooltip = 'Specifies the report type.'; + trigger OnDrillDown() + begin + Rec.DownloadReportFile(); + end; + } + } + } + } +} diff --git a/Apps/US/IRSForms/app/src/Printing/IRS1099FormStatement.Page.al b/Apps/US/IRSForms/app/src/Printing/IRS1099FormStatement.Page.al new file mode 100644 index 0000000000..ff565f2932 --- /dev/null +++ b/Apps/US/IRSForms/app/src/Printing/IRS1099FormStatement.Page.al @@ -0,0 +1,64 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +page 10051 "IRS 1099 Form Statement" +{ + ApplicationArea = BasicUS; + AutoSplitKey = true; + MultipleNewLines = true; + PageType = List; + SaveValues = true; + SourceTable = "IRS 1099 Form Statement Line"; + + layout + { + area(content) + { + repeater(General) + { + field("Row No."; Rec."Row No.") + { + ToolTip = 'Specifies a number that identifies the line.'; + } + field(Description; Rec.Description) + { + ToolTip = 'Specifies a description of the line.'; + } + field("Print Value Type"; Rec."Print Value Type") + { + Tooltip = 'Specifies the print value type of the statement. If the Amount is selected then the amount calculated by the filter expression is printed. If the Yes/No option is selected, then either Yes or No is printed based on the Yes/No condition.'; + } + field("Filter Expression"; Rec."Filter Expression") + { + ToolTip = 'Specifies the filter expression of the statement.'; + } + field("Row Totaling"; Rec."Row Totaling") + { + ToolTip = 'Specifies a row-number interval or a series of row numbers.'; + } + field("Print with"; Rec."Print with") + { + ToolTip = 'Specifies whether amounts on the Form statement will be printed with their original sign or with the sign reversed.'; + } + } + } + area(factboxes) + { + systempart(Control1900383207; Links) + { + ApplicationArea = RecordLinks; + Visible = false; + } + systempart(Control1905767507; Notes) + { + ApplicationArea = Notes; + Visible = false; + } + } + } + +} + diff --git a/Apps/US/IRSForms/app/src/Printing/IRS1099FormStatementLine.Table.al b/Apps/US/IRSForms/app/src/Printing/IRS1099FormStatementLine.Table.al new file mode 100644 index 0000000000..4ff4b0aceb --- /dev/null +++ b/Apps/US/IRSForms/app/src/Printing/IRS1099FormStatementLine.Table.al @@ -0,0 +1,124 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +table 10041 "IRS 1099 Form Statement Line" +{ + DataClassification = CustomerContent; + + fields + { + field(1; "Period No."; Code[20]) + { + TableRelation = "IRS Reporting Period"; + } + field(2; "Form No."; Code[20]) + { + TableRelation = "IRS 1099 Form"."No." where("Period No." = field("Period No.")); + } + field(3; "Line No."; Integer) + { + } + field(5; "Row No."; Code[20]) + { + } + field(6; Description; Text[100]) + { + } + field(7; "Print Value Type"; Enum "IRS 1099 Print Value Type") + { + } + field(10; "Filter Expression"; Text[1024]) + { + trigger OnValidate() + var + IRS1099FormDocLine: Record "IRS 1099 Form Doc. Line"; + begin + if "Filter Expression" <> '' then begin + IRS1099FormDocLine.SetView(ConvertFilterStringToView("Filter Expression")); + "Record View String" := CopyStr(IRS1099FormDocLine.GetView(false), 1, MaxStrLen("Record View String")); + "Filter Expression" := CopyStr(IRS1099FormDocLine.GetFilters(), 1, MaxStrLen("Filter Expression")); + end else + "Record View String" := ''; + end; + + trigger OnLookup() + begin + LookupFilterExpression(); + end; + } + field(11; "Record View String"; Text[1024]) + { + Editable = false; + } + field(20; "Row Totaling"; Text[250]) + { + } + field(21; "Print with"; Option) + { + Caption = 'Print with'; + OptionCaption = 'Sign,Opposite Sign'; + OptionMembers = Sign,"Opposite Sign"; + } + } + + keys + { + key(PK; "Period No.", "Form No.", "Line No.") + { + Clustered = true; + } + } + + var + FilterStringParseErr: Label 'Could not parse the filter expression. Use the lookup action, or type a string in the following format: "Type: Shipment, Quantity: <>0".'; + FilterTxt: Label '%1=FILTER(%2)', Locked = true; + WhereTxt: Label '%1 WHERE(%2)', Locked = true; + + local procedure LookupFilterExpression() + var + IRS1099FormDocLine: Record "IRS 1099 Form Doc. Line"; + FilterPageBuilder: FilterPageBuilder; + TableCaptionValue: Text; + begin + TableCaptionValue := IRS1099FormDocLine.TableCaption(); + FilterPageBuilder.AddTable(TableCaptionValue, Database::"IRS 1099 Form Doc. Line"); + if "Record View String" <> '' then + FilterPageBuilder.SetView(TableCaptionValue, "Record View String"); + if FilterPageBuilder.RunModal() then begin + IRS1099FormDocLine.SetView(FilterPageBuilder.GetView(TableCaptionValue, false)); + "Record View String" := CopyStr(IRS1099FormDocLine.GetView(false), 1, MaxStrLen("Record View String")); + "Filter Expression" := CopyStr(IRS1099FormDocLine.GetFilters(), 1, MaxStrLen("Filter Expression")); + end; + end; + + local procedure ConvertFilterStringToView(FilterString: Text): Text + var + IRS1099FormDocLine: Record "IRS 1099 Form Doc. Line"; + ConvertedFilterString: Text; + MidPos: Integer; + FinishPos: Integer; + begin + while FilterString <> '' do begin + // Convert "Type: Receipt" to "Type=FILTER(Receipt)" + MidPos := StrPos(FilterString, ':'); + if MidPos < 2 then + Error(FilterStringParseErr); + FinishPos := StrPos(FilterString, ','); + if FinishPos = 0 then + FinishPos := StrLen(FilterString) + 1; + if ConvertedFilterString <> '' then + ConvertedFilterString += ','; + ConvertedFilterString += + StrSubstNo(FilterTxt, CopyStr(FilterString, 1, MidPos - 1), CopyStr(FilterString, MidPos + 1, FinishPos - MidPos - 1)); + FilterString := DelStr(FilterString, 1, FinishPos); + end; + + if ConvertedFilterString <> '' then + exit(StrSubstNo(WhereTxt, IRS1099FormDocLine.GetView(), ConvertedFilterString)); + + exit(''); + end; +} diff --git a/Apps/US/IRSForms/app/src/Printing/IRS1099Print.Report.al b/Apps/US/IRSForms/app/src/Printing/IRS1099Print.Report.al new file mode 100644 index 0000000000..45e3568f08 --- /dev/null +++ b/Apps/US/IRSForms/app/src/Printing/IRS1099Print.Report.al @@ -0,0 +1,192 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +using Microsoft.Foundation.Company; +using Microsoft.Purchases.Vendor; + +report 10032 "IRS 1099 Print" +{ + ApplicationArea = All; + DefaultRenderingLayout = WordLayout; + + dataset + { + dataitem(IRS1099FormDocHeader; "IRS 1099 Form Doc. Header") + { + DataItemTableView = sorting("Period No.", "Form No.", "Vendor No."); + column(Period_No; "Period No.") { } + column(Vendor_No; "Vendor No.") { } + column(Form_No; "Form No.") { } + column(ID; ID) { } + column(Report_Type; IRS1099FormReportType) { } + column(Report_Year; ReportYear) { } + column(Company_Name; CompanyInformation.Name) { } + column(Company_Address; CompanyInformation.Address + ' ' + CompanyInformation."Address 2") { } + column(Company_City; CompanyInformation.City) { } + column(Company_County; CompanyInformation.County) { } + column(Company_Country; CompanyInformation."Country/Region Code") { } + column(Company_Post_Code; CompanyInformation."Post Code") { } + column(Company_FederalID; ProcessCompanyTIN(CompanyInformation."Federal ID No.")) { } + column(Company_PhoneNo; CompanyInformation."Phone No.") { } + + dataitem(IRS1099ReportLine; "IRS 1099 Report Line") + { + DataItemTableView = sorting("Line No."); + column(Line_No; "Line No.") { } + column(Line_Name; Name) { } + column(Line_Value; Value) { } + } + + dataitem(Vendor; Vendor) + { + DataItemLink = "No." = field("Vendor No."); + DataItemLinkReference = IRS1099FormDocHeader; + DataItemTableView = sorting("No."); + + column(Vendor_Name; Name) { } + column(Vendor_Address; Address + ' ' + "Address 2") { } + column(Vendor_City; City) { } + column(Vendor_County; County) { } + column(Vendor_Country; "Country/Region Code") { } + column(Vendor_Post_Code; "Post Code") { } + column(Vendor_FederalID; ProcessVendorTIN("Federal ID No.")) { } + column(Vendor_BankAccountNo; BankAccountNo) { } + column(Vendor_FATCA_Requirment; FATCARequirementText) { } + + trigger OnAfterGetRecord() + var + VendorBankAccount: Record "Vendor Bank Account"; + begin + if Vendor."Preferred Bank Account Code" <> '' then + VendorBankAccount.Get(Vendor."No.", Vendor."Preferred Bank Account Code"); + BankAccountNo := VendorBankAccount."Bank Account No."; + if Vendor."FATCA Requirement" then + FATCARequirementText := 'Yes' + else + FATCARequirementText := 'No'; + end; + } + + dataitem(IRS1099Form; "IRS 1099 Form") + { + DataItemLink = "Period No." = field("Period No."), "No." = field("Form No."); + DataItemTableView = sorting("No."); + + column(FormName; "No.") { } + column(FormDescription; Description) { } + } + + dataitem(IRS1099FormInstruction; "IRS 1099 Form Instruction") + { + DataItemLink = "Form No." = field("Form No."), "Period No." = field("Period No."); + DataItemLinkReference = IRS1099FormDocHeader; + DataItemTableView = sorting("Period No.", "Form No.", "Line No."); + + column(Instruction_Header; Header) { } + column(Instruction_Description; Description) { } + } + + trigger OnAfterGetRecord() + var + IRS1099DataSet: Codeunit "IRS 1099 Dataset"; + begin + IRS1099DataSet.Get1099Dataset(IRS1099FormDocHeader, IRS1099ReportLine); + CompanyInformation.Get(); + IRS1099Form.Get(IRS1099FormDocHeader."Period No.", IRS1099FormDocHeader."Form No."); + ReportYear := GetReportYear(IRS1099FormDocHeader); + end; + } + } + requestpage + { + ShowFilter = false; + + layout + { + area(content) + { + group(Options) + { + Caption = 'Options'; + field(IRS1099FormReportTypeControl; IRS1099FormReportType) + { + ApplicationArea = Basic, Suite; + Caption = 'Report Type'; + NotBlank = true; + ToolTip = 'Specifies the type of report to print.'; + } + } + } + } + + trigger OnOpenPage() + begin + IRS1099FormReportType := IRS1099FormReportType::"Copy B"; + end; + } + + rendering + { + layout(WordLayout) + { + Type = Word; + Caption = 'IRS 1099 Print (Word)'; + Summary = 'IRS 1099 Default Word Layout'; + LayoutFile = 'src/Printing/IRS 1099 Print.docx'; + } + } + + var + CompanyInformation: Record "Company Information"; + IRS1099FormReportType: Enum "IRS 1099 Form Report Type"; + BankAccountNo: Text; + FATCARequirementText: Text; + ReportYear: Integer; + + local procedure GetReportYear(IRS1099FormDocHeader: Record "IRS 1099 Form Doc. Header"): Integer + var + IRSReportingPeriod: Record "IRS Reporting Period"; + ReportDate: Date; + begin + if IRSReportingPeriod.Get(IRS1099FormDocHeader."Period No.") then; + ReportDate := IRSReportingPeriod."Starting Date"; + if ReportDate <> 0D then + exit(Date2DMY(ReportDate, 3)); + end; + + internal procedure SetIRS1099FormReportType(newIRS1099FormReportType: Enum "IRS 1099 Form Report Type") + begin + IRS1099FormReportType := newIRS1099FormReportType; + end; + + local procedure ProcessCompanyTIN(FederalIDNo: Text[30]): Text + var + IRSFormsSetup: Record "IRS Forms Setup"; + begin + IRSFormsSetup.Get(); + if IRSFormsSetup."Protect TIN" = IRSFormsSetup."Protect TIN"::"Protect TIN For Vendors and Company" then + exit(GetProtectedTIN(FederalIDNo)); + exit(FederalIDNo); + end; + + local procedure ProcessVendorTIN(FederalIDNo: Text[30]): Text[30] + var + IRSFormsSetup: Record "IRS Forms Setup"; + begin + IRSFormsSetup.Get(); + if IRSFormsSetup."Protect TIN" in [IRSFormsSetup."Protect TIN"::"Protect TIN For Vendors and Company", IRSFormsSetup."Protect TIN"::"Protect TIN For Vendors"] then + exit(GetProtectedTIN(FederalIDNo)); + exit(FederalIDNo); + end; + + local procedure GetProtectedTIN(TIN: Text[30]) ProtectedTIN: Text[30] + begin + if StrLen(TIN) <= 4 then + exit(TIN); + + ProtectedTIN := '****-' + CopyStr(TIN, StrLen(TIN) - 3, 4); + end; +} diff --git a/Apps/US/IRSForms/app/src/Printing/IRS1099PrintParams.Table.al b/Apps/US/IRSForms/app/src/Printing/IRS1099PrintParams.Table.al new file mode 100644 index 0000000000..aeefb4567d --- /dev/null +++ b/Apps/US/IRSForms/app/src/Printing/IRS1099PrintParams.Table.al @@ -0,0 +1,19 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +table 10048 "IRS 1099 Print Params" +{ + DataClassification = CustomerContent; + TableType = Temporary; + + fields + { + field(1; "Report Type"; Enum "IRS 1099 Form Report Type") + { + + } + } +} diff --git a/Apps/US/IRSForms/app/src/Printing/IRS1099PrintValueType.Enum.al b/Apps/US/IRSForms/app/src/Printing/IRS1099PrintValueType.Enum.al new file mode 100644 index 0000000000..5e0f28b81b --- /dev/null +++ b/Apps/US/IRSForms/app/src/Printing/IRS1099PrintValueType.Enum.al @@ -0,0 +1,20 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +enum 10032 "IRS 1099 Print Value Type" +{ + AssignmentCompatibility = true; + Extensible = true; + + value(0; Amount) + { + Caption = 'Amount'; + } + value(1; "Yes/No") + { + Caption = 'Yes/No'; + } +} diff --git a/Apps/US/IRSForms/app/src/Printing/IRS1099PrintingImpl.Codeunit.al b/Apps/US/IRSForms/app/src/Printing/IRS1099PrintingImpl.Codeunit.al new file mode 100644 index 0000000000..e4d11250fd --- /dev/null +++ b/Apps/US/IRSForms/app/src/Printing/IRS1099PrintingImpl.Codeunit.al @@ -0,0 +1,54 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +codeunit 10049 "IRS 1099 Printing Impl." implements "IRS 1099 Printing" +{ + Access = Internal; + InherentEntitlements = X; + InherentPermissions = X; + + procedure SaveContentForDocument(var IRS1099FormDocHeader: Record "IRS 1099 Form Doc. Header"; IRS1099PrintParams: Record "IRS 1099 Print Params"; ReplaceIfExists: Boolean) + var + IRS1099FormReport: Record "IRS 1099 Form Report"; + IRS1099Print: Report "IRS 1099 Print"; + ReportOutStream: OutStream; + begin + if ContentForPrintingExists(IRS1099FormDocHeader, IRS1099PrintParams) and not ReplaceIfExists then + exit; + + IRS1099FormReport.SetRange("Document ID", IRS1099FormDocHeader.ID); + IRS1099FormReport.SetRange("Report Type", IRS1099PrintParams."Report Type"); + if not IRS1099FormReport.FindFirst() then begin + IRS1099FormReport.Init(); + IRS1099FormReport.Validate("Document ID", IRS1099FormDocHeader.ID); + IRS1099FormReport.Validate("Report Type", IRS1099PrintParams."Report Type"); + IRS1099FormReport.Insert(); + end; + IRS1099FormReport."File Content".CreateOutStream(ReportOutStream); + IRS1099FormDocHeader.SetRecFilter(); + IRS1099Print.SetTableView(IRS1099FormDocHeader); + IRS1099Print.SetIRS1099FormReportType(IRS1099PrintParams."Report Type"); + IRS1099Print.SaveAs('', ReportFormat::Pdf, ReportOutStream); + IRS1099FormReport.Modify(); + end; + + procedure PrintContent(IRS1099FormDocHeader: Record "IRS 1099 Form Doc. Header") + begin + IRS1099FormDocHeader.TestField(Status, "IRS 1099 Form Doc. Status"::Submitted); + IRS1099FormDocHeader.SetRecFilter(); + Report.Run(Report::"IRS 1099 Print", true, false, IRS1099FormDocHeader); + end; + + local procedure ContentForPrintingExists(IRS1099FormDocHeader: Record "IRS 1099 Form Doc. Header"; IRS1099PrintParams: Record "IRS 1099 Print Params"): Boolean + var + IRS1099FormReport: Record "IRS 1099 Form Report"; + begin + if not IRS1099FormReport.Get(IRS1099FormDocHeader.ID, IRS1099PrintParams."Report Type") then + exit(false); + IRS1099FormReport.CalcFields("File Content"); + exit(IRS1099FormReport."File Content".HasValue()); + end; +} diff --git a/Apps/US/IRSForms/app/src/Printing/IRS1099ProtectTINType.Enum.al b/Apps/US/IRSForms/app/src/Printing/IRS1099ProtectTINType.Enum.al new file mode 100644 index 0000000000..03cfcb160f --- /dev/null +++ b/Apps/US/IRSForms/app/src/Printing/IRS1099ProtectTINType.Enum.al @@ -0,0 +1,24 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +enum 10036 "IRS 1099 Protect TIN Type" +{ + AssignmentCompatibility = true; + Extensible = true; + + value(0; "None") + { + Caption = 'None'; + } + value(1; "Protect TIN For Vendors") + { + Caption = 'Protect TIN For Vendors'; + } + value(2; "Protect TIN For Vendors and Company") + { + Caption = 'Protect TIN For Vendors and Company'; + } +} diff --git a/Apps/US/IRSForms/app/src/Printing/IRS1099ReportLine.Table.al b/Apps/US/IRSForms/app/src/Printing/IRS1099ReportLine.Table.al new file mode 100644 index 0000000000..367f9fb5d6 --- /dev/null +++ b/Apps/US/IRSForms/app/src/Printing/IRS1099ReportLine.Table.al @@ -0,0 +1,37 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +table 10039 "IRS 1099 Report Line" +{ + Access = Internal; + DataClassification = CustomerContent; + InherentEntitlements = X; + InherentPermissions = X; + TableType = Temporary; + + fields + { + field(1; "Line No."; Integer) + { + AutoIncrement = true; + } + field(2; Name; Text[250]) + { + + } + field(3; Value; Text[250]) + { + + } + } + keys + { + key(PK; "Line No.") + { + Clustered = true; + } + } +} diff --git a/Apps/US/IRSForms/app/src/Setup/IRS1099CopySetupFrom.Report.al b/Apps/US/IRSForms/app/src/Setup/IRS1099CopySetupFrom.Report.al new file mode 100644 index 0000000000..e62359e7a8 --- /dev/null +++ b/Apps/US/IRSForms/app/src/Setup/IRS1099CopySetupFrom.Report.al @@ -0,0 +1,63 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +report 10037 "IRS 1099 Copy Setup From" +{ + ProcessingOnly = true; + ApplicationArea = BasicUS; + + requestpage + { + layout + { + area(content) + { + group(Options) + { + Caption = 'Options'; + field(FromPeriod; FromPeriodNo) + { + ApplicationArea = BasicUS; + Caption = 'From Period'; + ToolTip = 'Specifies the period to copy from'; + TableRelation = "IRS Reporting Period"; + + trigger OnLookup(var Text: Text): Boolean + var + IRSReportingPeriod: Record "IRS Reporting Period"; + IRSReportingPeriods: Page "IRS Reporting Periods"; + begin + IRSReportingPeriod.SetFilter("No.", '<>%1', ToPeriodNo); + IRSReportingPeriods.SetTableView(IRSReportingPeriod); + IRSReportingPeriods.LookupMode := true; + if IRSReportingPeriods.RunModal() = Action::LookupOK then begin + IRSReportingPeriods.GetRecord(IRSReportingPeriod); + FromPeriodNo := IRSReportingPeriod."No."; + end; + end; + } + } + } + } + } + + protected var + ToPeriodNo: Code[20]; + FromPeriodNo: Code[20]; + + + trigger OnPostReport() + var + IRSReportingPeriod: Codeunit "IRS Reporting Period"; + begin + IRSReportingPeriod.CopyReportingPeriodSetup(FromPeriodNo, ToPeriodNo); + end; + + procedure InitializeRequest(NewToPeriodNo: Code[20]); + begin + ToPeriodNo := NewToPeriodNo; + end; +} diff --git a/Apps/US/IRSForms/app/src/Setup/IRS1099Form.Table.al b/Apps/US/IRSForms/app/src/Setup/IRS1099Form.Table.al new file mode 100644 index 0000000000..33c3782a11 --- /dev/null +++ b/Apps/US/IRSForms/app/src/Setup/IRS1099Form.Table.al @@ -0,0 +1,76 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +table 10032 "IRS 1099 Form" +{ + DataClassification = CustomerContent; + DrillDownPageId = "IRS 1099 Forms"; + LookupPageId = "IRS 1099 Forms"; + + fields + { + field(1; "Period No."; Code[20]) + { + TableRelation = "IRS Reporting Period"; + } + field(2; "No."; Code[20]) + { + NotBlank = true; + } + field(3; Description; Text[250]) + { + } + field(100; "Boxes Count"; Integer) + { + CalcFormula = count("IRS 1099 Form Box" where("Period No." = field("Period No."), "Form No." = field("No."))); + Editable = false; + FieldClass = FlowField; + } + } + + keys + { + key(PK; "Period No.", "No.") + { + Clustered = true; + } + } + + fieldgroups + { + fieldgroup(DropDown; "No.", Description) + { + } + fieldgroup(Brick; "No.", Description) + { + } + } + + var + FormIsUsedErr: Label 'The 1099 form %1 is used in the 1099 form document header.', Comment = '%1 = Form number'; + + trigger OnDelete() + var + IRS1099FormDocHeader: Record "IRS 1099 Form Doc. Header"; + IRS1099FormBox: Record "IRS 1099 Form Box"; + IRSForm1099StatementLine: Record "IRS 1099 Form Statement Line"; + IRS1099FormInstruction: Record "IRS 1099 Form Instruction"; + begin + IRS1099FormDocHeader.SetRange("Period No.", "Period No."); + IRS1099FormDocHeader.SetRange("Form No.", "No."); + if not IRS1099FormDocHeader.IsEmpty() then + Error(FormIsUsedErr, "No."); + IRS1099FormBox.SetRange("Period No.", "Period No."); + IRS1099FormBox.SetRange("Form No.", "No."); + IRS1099FormBox.DeleteAll(true); + IRSForm1099StatementLine.SetRange("Period No.", "Period No."); + IRSForm1099StatementLine.SetRange("Form No.", "No."); + IRSForm1099StatementLine.DeleteAll(true); + IRS1099FormInstruction.SetRange("Period No.", "Period No."); + IRS1099FormInstruction.SetRange("Form No.", "No."); + IRS1099FormInstruction.DeleteAll(true); + end; +} diff --git a/Apps/US/IRSForms/app/src/Setup/IRS1099FormBox.Table.al b/Apps/US/IRSForms/app/src/Setup/IRS1099FormBox.Table.al new file mode 100644 index 0000000000..e96c8ccefa --- /dev/null +++ b/Apps/US/IRSForms/app/src/Setup/IRS1099FormBox.Table.al @@ -0,0 +1,66 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +table 10033 "IRS 1099 Form Box" +{ + DataClassification = CustomerContent; + DrillDownPageId = "IRS 1099 Form Boxes"; + LookupPageId = "IRS 1099 Form Boxes"; + + fields + { + field(1; "Period No."; Code[20]) + { + TableRelation = "IRS Reporting Period"; + } + field(2; "Form No."; Code[20]) + { + TableRelation = "IRS 1099 Form"."No." where("Period No." = field("Period No.")); + } + field(3; "No."; Code[20]) + { + NotBlank = true; + } + field(4; Description; Text[250]) + { + } + field(5; "Minimum Reportable Amount"; Decimal) + { + } + } + + keys + { + key(PK; "Period No.", "Form No.", "No.") + { + Clustered = true; + } + } + + fieldgroups + { + fieldgroup(DropDown; "No.", Description) + { + } + fieldgroup(Brick; "No.", Description) + { + } + } + + var + FormBoxCannotBeDeletedErr: Label 'The 1099 form box %1 cannot be deleted because it is used in the 1099 form document lines.', Comment = '%1 = Form box number'; + + trigger OnDelete() + var + IRS1099FormDocLine: Record "IRS 1099 Form Doc. Line"; + begin + IRS1099FormDocLine.SetRange("Period No.", "Period No."); + IRS1099FormDocLine.SetRange("Form No.", "Form No."); + IRS1099FormDocLine.SetRange("Form Box No.", "No."); + if not IRS1099FormDocLine.IsEmpty() then + Error(FormBoxCannotBeDeletedErr, "No."); + end; +} diff --git a/Apps/US/IRSForms/app/src/Setup/IRS1099FormBoxes.Page.al b/Apps/US/IRSForms/app/src/Setup/IRS1099FormBoxes.Page.al new file mode 100644 index 0000000000..4340c22154 --- /dev/null +++ b/Apps/US/IRSForms/app/src/Setup/IRS1099FormBoxes.Page.al @@ -0,0 +1,56 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +page 10034 "IRS 1099 Form Boxes" +{ + PageType = List; + SourceTable = "IRS 1099 Form Box"; + ApplicationArea = BasicUS; + DelayedInsert = true; + AnalysisModeEnabled = false; + + layout + { + area(content) + { + repeater(Group) + { + field("Period No."; Rec."Period No.") + { + Tooltip = 'Specifies the period of the 1099 form box.'; + Visible = PeriodIsVisible; + } + field("Form No."; Rec."Form No.") + { + Tooltip = 'Specifies the 1099 that box belongs to.'; + Visible = FormIsVisible; + } + field("No."; Rec."No.") + { + Tooltip = 'Specifies the number of the 1099 form box.'; + } + field(Description; Rec.Description) + { + ToolTip = 'Specifies a description of the reporting period.'; + } + field("Minimum Reportable Amount"; Rec."Minimum Reportable Amount") + { + ToolTip = 'Specifies the minimum amount for this form box that must be reported.'; + } + } + } + } + + var + PeriodIsVisible: Boolean; + FormIsVisible: Boolean; + + trigger OnOpenPage() + begin + PeriodIsVisible := Rec.GetFilter("Period No.") = ''; + FormIsVisible := Rec.GetFilter("Form No.") = ''; + end; +} diff --git a/Apps/US/IRSForms/app/src/Setup/IRS1099Forms.Page.al b/Apps/US/IRSForms/app/src/Setup/IRS1099Forms.Page.al new file mode 100644 index 0000000000..52eaca9da8 --- /dev/null +++ b/Apps/US/IRSForms/app/src/Setup/IRS1099Forms.Page.al @@ -0,0 +1,100 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +page 10033 "IRS 1099 Forms" +{ + PageType = List; + SourceTable = "IRS 1099 Form"; + ApplicationArea = BasicUS; + DelayedInsert = true; + RefreshOnActivate = true; + + layout + { + area(content) + { + repeater(Group) + { + field("Period No."; Rec."Period No.") + { + Tooltip = 'Specifies the period of the 1099 form box.'; + Visible = PeriodIsVisible; + } + field("No."; Rec."No.") + { + Tooltip = 'Specifies the number of the 1099 form.'; + } + field(Description; Rec.Description) + { + ToolTip = 'Specifies a description of the reporting period.'; + } + field("Boxes Count"; Rec."Boxes Count") + { + ToolTip = 'Specifies a number of boxes for a certain form.'; + } + } + } + } + + actions + { + area(Processing) + { + action(FormBoxes) + { + Caption = 'Form Boxes'; + Image = Form; + Scope = Repeater; + ToolTip = 'Specifies the form boxes to be reported.'; + RunObject = Page "IRS 1099 Form Boxes"; + RunPageLink = "Period No." = field("Period No."), "Form No." = field("No."); + } + action(EditStatement) + { + Caption = 'Edit Statement'; + Image = SetupList; + ToolTip = 'View or edit how to print your IRS 1099 form statement'; + RunObject = Page "IRS 1099 Form Statement"; + RunPageLink = "Period No." = field("Period No."), "Form No." = field("No."); + } + action(EditInstructions) + { + Caption = 'Edit Instructions'; + Image = SetupList; + ToolTip = 'View or edit the instructions for the printed version of the 1099 form document.'; + RunObject = Page "IRS 1099 Form Instructions"; + RunPageLink = "Period No." = field("Period No."), "Form No." = field("No."); + } + } + area(Promoted) + { + group(Category_Process) + { + Caption = 'Process'; + actionref(FormBoxes_Promoted; FormBoxes) + { + + } + actionref(EditStatement_Promoted; EditStatement) + { + + } + actionref(EditInstructions_Promoted; EditInstructions) + { + + } + } + } + } + + var + PeriodIsVisible: Boolean; + + trigger OnOpenPage() + begin + PeriodIsVisible := Rec.GetFilter("Period No.") = ''; + end; +} diff --git a/Apps/US/IRSForms/app/src/Setup/IRS1099TransErrorHandler.Codeunit.al b/Apps/US/IRSForms/app/src/Setup/IRS1099TransErrorHandler.Codeunit.al new file mode 100644 index 0000000000..80fdce9ad1 --- /dev/null +++ b/Apps/US/IRSForms/app/src/Setup/IRS1099TransErrorHandler.Codeunit.al @@ -0,0 +1,33 @@ +#if not CLEAN25 +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +using System.Telemetry; + +codeunit 10053 "IRS 1099 Trans. Error Handler" +{ + Access = Internal; + InherentEntitlements = X; + InherentPermissions = X; + + var + Telemetry: Codeunit Telemetry; + + trigger OnRun() + var + IRSFormsSetup: Record "IRS Forms Setup"; + begin + IRSFormsSetup.InitSetup(); + Clear(IRSFormsSetup."Data Transfer Task ID"); + IRSFormsSetup."Data Transfer Error Message" := CopyStr(GetLastErrorText(), 1, MaxStrLen(IRSFormsSetup."Data Transfer Error Message")); + IRSFormsSetup.Modify(); + Telemetry.LogMessage('0000MKE', StrSubstNo(FailedTransferDataTxt, GetLastErrorText()), Verbosity::Warning, DataClassification::SystemMetadata); + end; + + var + FailedTransferDataTxt: Label 'Transfer data has failed: %1', Comment = '%1 = error message'; +} +#endif \ No newline at end of file diff --git a/Apps/US/IRSForms/app/src/Setup/IRS1099TransferFromBaseApp.Codeunit.al b/Apps/US/IRSForms/app/src/Setup/IRS1099TransferFromBaseApp.Codeunit.al new file mode 100644 index 0000000000..0071d4c74e --- /dev/null +++ b/Apps/US/IRSForms/app/src/Setup/IRS1099TransferFromBaseApp.Codeunit.al @@ -0,0 +1,217 @@ +#if not CLEAN25 +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +using Microsoft.Purchases.Document; +using Microsoft.Purchases.Payables; +using Microsoft.Purchases.Vendor; + +codeunit 10040 "IRS 1099 Transfer From BaseApp" +{ + Access = Internal; + InherentEntitlements = X; + InherentPermissions = X; + + var + StatementLineFilterExpressionTxt: Label 'Form Box No.: %1', Comment = '%1 = Form Box No.'; + CreatedDuringDataTransferMsg: Label 'Created during data transfer'; + + trigger OnRun() + var + IRSFormsSetup: Record "IRS Forms Setup"; + IRSReportingPeriod: Record "IRS Reporting Period"; + IRSFormsData: Codeunit "IRS Forms Data"; + begin + IRSFormsSetup.Get(); + IRSFormsSetup.TestField("Init Reporting Year"); + CreateReportingPeriod(IRSReportingPeriod, IRSFormsSetup."Init Reporting Year"); + TransferFormBoxes(IRSReportingPeriod."No."); + TransferVendorSetup(IRSReportingPeriod."No."); + TransferAdjustments(IRSReportingPeriod."No.", IRSFormsSetup."Init Reporting Year"); + TransferPurchaseDocuments(IRSReportingPeriod."No.", IRSReportingPeriod."Starting Date", IRSReportingPeriod."Ending Date"); + TransferVendorLedgerEntries(IRSReportingPeriod."No.", IRSReportingPeriod."Starting Date", IRSReportingPeriod."Ending Date"); + IRSFormsData.AddFormInstructionLines(IRSReportingPeriod."No."); + + Clear(IRSFormsSetup."Data Transfer Task ID"); + Clear(IRSFormsSetup."Task Start Date/Time"); + IRSFormsSetup."Data Transfer Completed" := true; + IRSFormsSetup.Modify(); + end; + + local procedure CreateReportingPeriod(var IRSReportingPeriod: Record "IRS Reporting Period"; ReportingYear: Integer) + begin + IRSReportingPeriod.Init(); + IRSReportingPeriod."No." := Format(ReportingYear); + IRSReportingPeriod."Starting Date" := DMY2Date(1, 1, ReportingYear); + IRSReportingPeriod."Ending Date" := DMY2Date(31, 12, ReportingYear); + IRSReportingPeriod.Description := CreatedDuringDataTransferMsg; + IRSReportingPeriod.Insert(); + end; + + local procedure TransferFormBoxes(PeriodNo: Code[20]) + var +#pragma warning disable AL0432 + IRS1099FormBoxOld: Record "IRS 1099 Form-Box"; +#pragma warning restore AL0432 + IRS1099Form: Record "IRS 1099 Form"; + IRS1099FormBoxNew: Record "IRS 1099 Form Box"; + LastFormNo, CurrFormNo : Code[20]; + StatementLineNo: Integer; + begin + if not IRS1099FormBoxOld.FindSet() then + exit; + LastFormNo := ''; + repeat + if IsOld1099FormBoxTransferable(IRS1099FormBoxOld.Code) then begin + CurrFormNo := GetFormNoFromOldFormBox(IRS1099FormBoxOld.Code); + if CurrFormNo <> LastFormNo then begin + IRS1099Form.Init(); + IRS1099Form."Period No." := PeriodNo; + IRS1099Form."No." := CurrFormNo; + IRS1099Form.Insert(); + StatementLineNo := 0; + end; + IRS1099FormBoxNew.Init(); + IRS1099FormBoxNew."Period No." := PeriodNo; + IRS1099FormBoxNew."Form No." := IRS1099Form."No."; + IRS1099FormBoxNew."No." := IRS1099FormBoxOld.Code; + IRS1099FormBoxNew.Description := IRS1099FormBoxOld.Description; + IRS1099FormBoxNew."Minimum Reportable Amount" := IRS1099FormBoxOld."Minimum Reportable"; + IRS1099FormBoxNew.Insert(); + StatementLineNo += 10000; + AddFormStatementLine(PeriodNo, IRS1099Form."No.", IRS1099FormBoxNew."No.", StatementLineNo, IRS1099FormBoxNew.Description); + LastFormNo := CurrFormNo; + end; + until IRS1099FormBoxOld.Next() = 0; + end; + + local procedure TransferVendorSetup(PeriodNo: Code[20]) + var + Vendor: Record Vendor; + IRS1099VendorFormBoxSetup: Record "IRS 1099 Vendor Form Box Setup"; + begin +#pragma warning disable AL0432 + Vendor.SetFilter("IRS 1099 Code", '<>%1', ''); + if not Vendor.FindSet(true) then + exit; + repeat + if IsOld1099FormBoxTransferable(Vendor."IRS 1099 Code") then begin + IRS1099VendorFormBoxSetup.Init(); + IRS1099VendorFormBoxSetup."Period No." := PeriodNo; + IRS1099VendorFormBoxSetup."Vendor No." := Vendor."No."; + IRS1099VendorFormBoxSetup."Form No." := GetFormNoFromOldFormBox(Vendor."IRS 1099 Code"); + IRS1099VendorFormBoxSetup."Form Box No." := Vendor."IRS 1099 Code"; + IRS1099VendorFormBoxSetup.Insert(); + end; + Vendor."FATCA Requirement" := Vendor."FATCA filing requirement"; + Vendor.Modify(); + until Vendor.Next() = 0; +#pragma warning restore AL0432 + end; + + local procedure TransferAdjustments(PeriodNo: Code[20]; ReportingYear: Integer) + var +#pragma warning disable AL0432 + IRS1099Adjustment: Record "IRS 1099 Adjustment"; + IRS1099VendorFormBoxAdj: Record "IRS 1099 Vendor Form Box Adj."; + begin + IRS1099Adjustment.SetRange(Year, ReportingYear); + if not IRS1099Adjustment.FindSet() then + exit; + repeat + if IsOld1099FormBoxTransferable(IRS1099Adjustment."IRS 1099 Code") then begin + IRS1099VendorFormBoxAdj.Init(); + IRS1099VendorFormBoxAdj."Period No." := PeriodNo; + IRS1099VendorFormBoxAdj."Vendor No." := IRS1099Adjustment."Vendor No."; + IRS1099VendorFormBoxAdj."Form No." := GetFormNoFromOldFormBox(IRS1099Adjustment."IRS 1099 Code"); + IRS1099VendorFormBoxAdj."Form Box No." := IRS1099Adjustment."IRS 1099 Code"; + IRS1099VendorFormBoxAdj.Amount := IRS1099Adjustment.Amount; + IRS1099VendorFormBoxAdj.Insert(); + end; + until IRS1099Adjustment.Next() = 0; +#pragma warning restore AL0432 + end; + + local procedure TransferPurchaseDocuments(PeriodNo: Code[20]; StartingDate: Date; EndingDate: Date) + var + PurchHeader: Record "Purchase Header"; + begin +#pragma warning disable AL0432 + PurchHeader.SetFilter( + "Document Type", '%1|%2|%3|%4', PurchHeader."Document Type"::Invoice, PurchHeader."Document Type"::"Credit Memo", PurchHeader."Document Type"::Order, PurchHeader."Document Type"::"Return Order"); + PurchHeader.SetRange("Posting Date", StartingDate, EndingDate); + PurchHeader.SetFilter("IRS 1099 Code", '<>%1', ''); + if not PurchHeader.FindSet(true) then + exit; + repeat + if IsOld1099FormBoxTransferable(PurchHeader."IRS 1099 Code") then begin + PurchHeader."IRS 1099 Reporting Period" := PeriodNo; + PurchHeader."IRS 1099 Form No." := GetFormNoFromOldFormBox(PurchHeader."IRS 1099 Code"); + PurchHeader."IRS 1099 Form Box No." := PurchHeader."IRS 1099 Code"; + PurchHeader.Modify(); + end; + until PurchHeader.Next() = 0; +#pragma warning restore AL0432 + end; + + local procedure TransferVendorLedgerEntries(PeriodNo: Code[20]; StartingDate: Date; EndingDate: Date) + var + VendorLedgerEntry: Record "Vendor Ledger Entry"; + begin +#pragma warning disable AL0432 + VendorLedgerEntry.SetRange("Posting Date", StartingDate, EndingDate); + VendorLedgerEntry.SetFilter("Document Type", '%1|%2', VendorLedgerEntry."Document Type"::Invoice, VendorLedgerEntry."Document Type"::"Credit Memo"); + VendorLedgerEntry.SetFilter("IRS 1099 Code", '<>%1', ''); + if not VendorLedgerEntry.FindSet(true) then + exit; + repeat + if IsOld1099FormBoxTransferable(VendorLedgerEntry."IRS 1099 Code") then begin + VendorLedgerEntry."IRS 1099 Reporting Period" := PeriodNo; + VendorLedgerEntry."IRS 1099 Form No." := GetFormNoFromOldFormBox(VendorLedgerEntry."IRS 1099 Code"); + VendorLedgerEntry."IRS 1099 Form Box No." := VendorLedgerEntry."IRS 1099 Code"; + VendorLedgerEntry.CalcFields(Amount); + if VendorLedgerEntry."Document Type" = VendorLedgerEntry."Document Type"::Invoice then + VendorLedgerEntry."IRS 1099 Reporting Amount" := VendorLedgerEntry.Amount + else + VendorLedgerEntry."IRS 1099 Reporting Amount" := -VendorLedgerEntry.Amount; + VendorLedgerEntry."IRS 1099 Subject For Reporting" := VendorLedgerEntry."IRS 1099 Reporting Amount" <> 0; + VendorLedgerEntry.Modify(); + end; + until VendorLedgerEntry.Next() = 0; +#pragma warning restore AL0432 + end; + + local procedure IsOld1099FormBoxTransferable(OldFormBox: Text): Boolean + begin + exit((OldFormBox.Contains('MISC') or OldFormBox.Contains('DIV') or OldFormBox.Contains('INT') or OldFormBox.Contains('NEC')) and OldFormBox.Contains('-')); + end; + + local procedure GetFormNoFromOldFormBox(OldFormBox: Code[20]): Code[20] + var + DashPosition: Integer; + begin + DashPosition := StrPos(OldFormBox, '-'); +#pragma warning disable AA0139 + exit(CopyStr(OldFormBox, 1, DashPosition - 1)); +#pragma warning restore AA0139 + end; + + local procedure AddFormStatementLine(PeriodNo: Code[20]; FormNo: Code[20]; FormBoxNo: Code[20]; StatementLineNo: Integer; Description: Text) + var + IRS1099FormStatementLine: Record "IRS 1099 Form Statement Line"; + begin + IRS1099FormStatementLine.Validate("Period No.", PeriodNo); + IRS1099FormStatementLine.Validate("Form No.", FormNo); + IRS1099FormStatementLine.Validate("Line No.", StatementLineNo); + IRS1099FormStatementLine.Validate("Row No.", FormBoxNo); + IRS1099FormStatementLine.Validate("Description", Description); + if IRS1099FormStatementLine."Row No." = 'MISC-07' then + IRS1099FormStatementLine."Print Value Type" := Enum::"IRS 1099 Print Value Type"::"Yes/No"; + IRS1099FormStatementLine.Validate("Filter Expression", StrSubstNo(StatementLineFilterExpressionTxt, FormBoxNo)); + IRS1099FormStatementLine.Insert(true); + end; +} +#endif \ No newline at end of file diff --git a/Apps/US/IRSForms/app/src/Setup/IRSFormsData.Codeunit.al b/Apps/US/IRSForms/app/src/Setup/IRSFormsData.Codeunit.al new file mode 100644 index 0000000000..0e469a65e4 --- /dev/null +++ b/Apps/US/IRSForms/app/src/Setup/IRSFormsData.Codeunit.al @@ -0,0 +1,276 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +codeunit 10039 "IRS Forms Data" +{ + Access = Internal; + + var + StatementLineFilterExpressionTxt: Label 'Form Box No.: %1', Comment = '%1 = Form Box No.'; + + procedure AddReportingPeriodsWithForms(ReportingYear: Integer) + var + PeriodNo: Code[20]; + begin + PeriodNo := + AddReportingPeriod( + Format(ReportingYear), + DMY2Date(1, 1, ReportingYear), DMY2Date(31, 12, ReportingYear), Format(ReportingYear)); + AddForm(PeriodNo, 'MISC', 'Miscellaneous Income'); + AddFormBox(PeriodNo, 'MISC', 'MISC-01', 'Rents', 600); + AddFormBox(PeriodNo, 'MISC', 'MISC-02', 'Royalties', 10); + AddFormBox(PeriodNo, 'MISC', 'MISC-03', 'Other Income', 600); + AddFormBox(PeriodNo, 'MISC', 'MISC-04', 'Federal Income Tax Withheld', 0); + AddFormBox(PeriodNo, 'MISC', 'MISC-05', 'Fishing Boat Proceeds', 600); + AddFormBox(PeriodNo, 'MISC', 'MISC-06', 'Medical and Health Care Payments', 600); + AddFormBox(PeriodNo, 'MISC', 'MISC-07', 'Payer made direct sales totaling $5,000 or more of consumer products to recipient for resale', 5000); + AddFormBox(PeriodNo, 'MISC', 'MISC-08', 'Substitute Payments in Lieu of Dividends or Interest', 10); + AddFormBox(PeriodNo, 'MISC', 'MISC-09', 'Crop Insurance Proceeds', 1); + AddFormBox(PeriodNo, 'MISC', 'MISC-10', 'Gross Proceeds Paid to an Attorney', 0); + AddFormBox(PeriodNo, 'MISC', 'MISC-11', 'Fish purchased for resale', 600); + AddFormBox(PeriodNo, 'MISC', 'MISC-12', 'Section 409A deferrals', 600); + AddFormBox(PeriodNo, 'MISC', 'MISC-14', 'Excess golden parachute payments', 0); + AddFormBox(PeriodNo, 'MISC', 'MISC-15', 'Nonqualified deferred compensation', 0); + AddFormBox(PeriodNo, 'MISC', 'MISC-16', 'State tax withheld', 0); + AddFormStatementLine(PeriodNo, 'MISC', 'MISC-01', 10000, 'Rents'); + AddFormStatementLine(PeriodNo, 'MISC', 'MISC-02', 20000, 'Royalties'); + AddFormStatementLine(PeriodNo, 'MISC', 'MISC-03', 30000, 'Other Income'); + AddFormStatementLine(PeriodNo, 'MISC', 'MISC-04', 40000, 'Federal Income Tax Withheld'); + AddFormStatementLine(PeriodNo, 'MISC', 'MISC-05', 50000, 'Fishing Boat Proceeds'); + AddFormStatementLine(PeriodNo, 'MISC', 'MISC-06', 60000, 'Medical and Health Care Payments'); + AddFormStatementLine(PeriodNo, 'MISC', Enum::"IRS 1099 Print Value Type"::"Yes/No", 'MISC-07', 70000, 'Payer made direct sales totaling $5,000 or more of consumer products to recipient for resale'); + AddFormStatementLine(PeriodNo, 'MISC', 'MISC-08', 80000, 'Substitute Payments in Lieu of Dividends or Interest'); + AddFormStatementLine(PeriodNo, 'MISC', 'MISC-09', 90000, 'Crop Insurance Proceeds'); + AddFormStatementLine(PeriodNo, 'MISC', 'MISC-10', 100000, 'Gross Proceeds Paid to an Attorney'); + AddFormStatementLine(PeriodNo, 'MISC', 'MISC-11', 110000, 'Fish purchased for resale'); + AddFormStatementLine(PeriodNo, 'MISC', 'MISC-12', 120000, 'Section 409A deferrals'); + AddFormStatementLine(PeriodNo, 'MISC', 'MISC-14', 130000, 'Excess golden parachute payments'); + AddFormStatementLine(PeriodNo, 'MISC', 'MISC-15', 140000, 'Nonqualified deferred compensation'); + AddFormStatementLine(PeriodNo, 'MISC', 'MISC-16', 150000, 'State tax withheld'); + + AddForm(PeriodNo, 'NEC', 'Nonemployee Compensation'); + AddFormBox(PeriodNo, 'NEC', 'NEC-01', 'Nonemployee Compensation', 600); + AddFormBox(PeriodNo, 'NEC', 'NEC-02', 'Payer made direct sales totaling $5,000 or more of consumer products to recipient for resale', 5000); + AddFormBox(PeriodNo, 'NEC', 'NEC-04', 'Federal Income Tax Withheld', 0); + AddFormStatementLine(PeriodNo, 'NEC', 'NEC-01', 10000, 'Nonemployee Compensation'); + AddFormStatementLine(PeriodNo, 'NEC', Enum::"IRS 1099 Print Value Type"::"Yes/No", 'NEC-02', 20000, 'Payer made direct sales totaling $5,000 or more of consumer products to recipient for resale'); + AddFormStatementLine(PeriodNo, 'NEC', 'NEC-04', 30000, 'Federal Income Tax Withheld'); + + AddForm(PeriodNo, 'INT', 'Interest Income'); + AddFormBox(PeriodNo, 'INT', 'INT-01', 'Interest Income', 10); + AddFormBox(PeriodNo, 'INT', 'INT-02', 'Early withdrawal penalty', -1); + AddFormBox(PeriodNo, 'INT', 'INT-03', 'Interest on U.S. Savings Bonds and Treas. Obligations', 10); + AddFormBox(PeriodNo, 'INT', 'INT-04', 'Federal Income Tax Withheld', -1); + AddFormBox(PeriodNo, 'INT', 'INT-05', 'Investment Expenses', 10); + AddFormBox(PeriodNo, 'INT', 'INT-06', 'Foreign Tax Paid', -1); + AddFormBox(PeriodNo, 'INT', 'INT-08', 'Tax-Exempt Interest', 10); + AddFormBox(PeriodNo, 'INT', 'INT-09', 'Specified Private Activity Bond Interest', 10); + AddFormBox(PeriodNo, 'INT', 'INT-10', 'Market Discount', 10); + AddFormBox(PeriodNo, 'INT', 'INT-11', 'Bond Premium', 0.01); + AddFormBox(PeriodNo, 'INT', 'INT-12', 'Bond Premium on Treasury Obligations', 0.01); + AddFormBox(PeriodNo, 'INT', 'INT-13', 'Bond Premium on Tax-Exempt Bond', 0.01); + AddFormStatementLine(PeriodNo, 'INT', 'INT-01', 10000, 'Interest Income'); + AddFormStatementLine(PeriodNo, 'INT', 'INT-02', 20000, 'Early withdrawal penalty'); + AddFormStatementLine(PeriodNo, 'INT', 'INT-03', 30000, 'Interest on U.S. Savings Bonds and Treas. Obligations'); + AddFormStatementLine(PeriodNo, 'INT', 'INT-04', 40000, 'Federal Income Tax Withheld'); + AddFormStatementLine(PeriodNo, 'INT', 'INT-05', 50000, 'Investment Expenses'); + AddFormStatementLine(PeriodNo, 'INT', 'INT-06', 60000, 'Foreign Tax Paid'); + AddFormStatementLine(PeriodNo, 'INT', 'INT-08', 80000, 'Tax-Exempt Interest'); + AddFormStatementLine(PeriodNo, 'INT', 'INT-09', 90000, 'Specified Private Activity Bond Interest'); + AddFormStatementLine(PeriodNo, 'INT', 'INT-10', 100000, 'Market Discount'); + AddFormStatementLine(PeriodNo, 'INT', 'INT-11', 110000, 'Bond Premium'); + AddFormStatementLine(PeriodNo, 'INT', 'INT-12', 120000, 'Bond Premium on Treasury Obligations'); + AddFormStatementLine(PeriodNo, 'INT', 'INT-13', 130000, 'Bond Premium on Tax-Exempt Bond'); + + AddForm(PeriodNo, 'DIV', 'Dividends and Distributions'); + AddFormBox(PeriodNo, 'DIV', 'DIV-01-A', 'Total Ordinary Dividends', 10); + AddFormBox(PeriodNo, 'DIV', 'DIV-01-B', 'Qualified Dividends', 10); + AddFormBox(PeriodNo, 'DIV', 'DIV-02-A', 'Total capital gain distr.', 0.0); + AddFormBox(PeriodNo, 'DIV', 'DIV-02-B', 'Unrecap. Sec. 1250 gain', 10.0); + AddFormBox(PeriodNo, 'DIV', 'DIV-02-C', 'Section 1202 gain', 0.0); + AddFormBox(PeriodNo, 'DIV', 'DIV-02-D', 'Collectibles (28%) gain', 0.0); + AddFormBox(PeriodNo, 'DIV', 'DIV-02-E', 'Section 897 ordinary dividends', 0.0); + AddFormBox(PeriodNo, 'DIV', 'DIV-02-F', 'Section 897 capital gain', 0.0); + AddFormBox(PeriodNo, 'DIV', 'DIV-03', 'Nondividend distributions', 10.0); + AddFormBox(PeriodNo, 'DIV', 'DIV-04', 'Federal income tax withheld', -1.0); + AddFormBox(PeriodNo, 'DIV', 'DIV-05', 'Section 199A dividends', 10.0); + AddFormBox(PeriodNo, 'DIV', 'DIV-06', 'Investment expenses', 10.0); + AddFormBox(PeriodNo, 'DIV', 'DIV-07', 'Foreign tax paid', -1.0); + AddFormBox(PeriodNo, 'DIV', 'DIV-09', 'Cash liquidation distributions', 600.0); + AddFormBox(PeriodNo, 'DIV', 'DIV-10', 'Noncash liquidation distributions', 600.0); + AddFormBox(PeriodNo, 'DIV', 'DIV-12', 'Exempt-interest dividends', 0.0); + AddFormBox(PeriodNo, 'DIV', 'DIV-13', 'Specified private activity bond interest dividends', 0.0); + AddFormStatementLine(PeriodNo, 'DIV', 'DIV-01-A', 10000, 'Total Ordinary Dividends'); + AddFormStatementLine(PeriodNo, 'DIV', 'DIV-01-B', 20000, 'Qualified Dividends'); + AddFormStatementLine(PeriodNo, 'DIV', 'DIV-02-A', 30000, 'Total capital gain distr.'); + AddFormStatementLine(PeriodNo, 'DIV', 'DIV-02-B', 40000, 'Unrecap. Sec. 1250 gain'); + AddFormStatementLine(PeriodNo, 'DIV', 'DIV-02-C', 50000, 'Section 1202 gain'); + AddFormStatementLine(PeriodNo, 'DIV', 'DIV-02-D', 60000, 'Collectibles (28%) gain'); + AddFormStatementLine(PeriodNo, 'DIV', 'DIV-02-E', 70000, 'Section 897 ordinary dividends'); + AddFormStatementLine(PeriodNo, 'DIV', 'DIV-02-F', 80000, 'Section 897 capital gain'); + AddFormStatementLine(PeriodNo, 'DIV', 'DIV-03', 90000, 'Nondividend distributions'); + AddFormStatementLine(PeriodNo, 'DIV', 'DIV-04', 100000, 'Federal income tax withheld'); + AddFormStatementLine(PeriodNo, 'DIV', 'DIV-05', 110000, 'Section 199A dividends'); + AddFormStatementLine(PeriodNo, 'DIV', 'DIV-06', 120000, 'Investment expenses'); + AddFormStatementLine(PeriodNo, 'DIV', 'DIV-07', 130000, 'Foreign Tax Paid'); + AddFormStatementLine(PeriodNo, 'DIV', 'DIV-09', 140000, 'Cash liquidation distributions'); + AddFormStatementLine(PeriodNo, 'DIV', 'DIV-10', 150000, 'Noncash liquidation distributions'); + AddFormStatementLine(PeriodNo, 'DIV', 'DIV-12', 160000, 'Exempt-interest dividends'); + AddFormStatementLine(PeriodNo, 'DIV', 'DIV-13', 170000, 'Specified private activity bond interest dividends'); + + AddFormInstructionLines(PeriodNo); + end; + + procedure AddFormInstructionLines(PeriodNo: Code[20]) + begin + AddFormInstructionLine(PeriodNo, 'NEC', 1, '', 'You received this form instead of Form W-2 because the payer did not consider you an employee and did not withhold income tax or social security and Medicare tax. If you believe you are an employee and cannot get the payer to correct this form, report the amount shown in box 1 on the line for “Wages, salaries, tips, etc.” of Form 1040, 1040-SR, or 1040-NR. You must also complete Form 8919 and attach it to your return. For more information, see Pub. 1779, Independent Contractor or Employee. If you are not an employee but the amount in box 1 is not self-employment (SE) income (for example, it is income from a sporadic activity or a hobby), report the amount shown in box 1 on the “Other income” line (on Schedule 1 (Form 1040)).'); + AddFormInstructionLine(PeriodNo, 'NEC', 2, 'Recipient’s taxpayer identification number (TIN).', 'For your protection, this form may show only the last four digits of your TIN (social security number (SSN), individual taxpayer identification number (ITIN), adoption taxpayer identification number (ATIN), or employer identification number (EIN)). However, the issuer has reported your complete TIN to the IRS.'); + AddFormInstructionLine(PeriodNo, 'NEC', 3, 'Account number.', 'May show an account or other unique number the payer assigned to distinguish your account.'); + AddFormInstructionLine(PeriodNo, 'NEC', 4, 'Box 1.', 'Shows nonemployee compensation. If the amount in this box is SE income, report it on Schedule C or F (Form 1040) if a sole proprietor, or on Form 1065 and Schedule K-1 (Form 1065) if a partnership, and the recipient/partner completes Schedule SE (Form 1040).'); + AddFormInstructionLine(PeriodNo, 'NEC', 5, 'Note:', 'If you are receiving payments on which no income, social security, and Medicare taxes are withheld, you should make estimated tax payments. See Form 1040-ES (or Form 1040-ES (NR)). Individuals must report these amounts as explained in these box 1 instructions. Corporations, fiduciaries, and partnerships must report these amounts on the appropriate line of their tax returns.'); + AddFormInstructionLine(PeriodNo, 'NEC', 6, 'Box 2.', 'If checked, consumer products totaling $5,000 or more were sold to you for resale, on a buy-sell, a deposit-commission, or other basis. Generally, report any income from your sale of these products on Schedule C (Form 1040).'); + AddFormInstructionLine(PeriodNo, 'NEC', 7, 'Box 3.', 'Reserved for future use.'); + AddFormInstructionLine(PeriodNo, 'NEC', 8, 'Box 4.', 'Shows backup withholding. A payer must backup withhold on certain payments if you did not give your TIN to the payer. See Form W-9, Request for Taxpayer Identification Number and Certification, for information on backup withholding. Include this amount on your income tax return as tax withheld.'); + AddFormInstructionLine(PeriodNo, 'NEC', 9, 'Boxes 5-7.', 'State income tax withheld reporting boxes.'); + AddFormInstructionLine(PeriodNo, 'NEC', 10, 'Future developments.', 'For the latest information about developments related to Form 1099-NEC and its instructions, such as legislation enacted after they were published, go to www.irs.gov/Form1099NEC.'); + AddFormInstructionLine(PeriodNo, 'NEC', 11, 'Free File Program.', 'Go to www.irs.gov/FreeFile to see if you qualify for no-cost online federal tax preparation, e-filing, and direct deposit or payment options.'); + + AddFormInstructionLine(PeriodNo, 'INT', 1, '', 'The information provided may be different for covered and noncovered securities. For a description of covered securities, see the Instructions for Form 8949. For a taxable covered security acquired at a premium, unless you notified the payer in writing in accordance with Regulations section 1.6045-1(n)(5) that you did not want to amortize the premium under section 171, or for a tax-exempt covered security acquired at a premium, your payer must generally report either (1) a net amount of interest that reflects the offset of the amount of interest paid to you by the amount of premium amortization allocable to the payment(s), or (2) a gross amount for both the interest paid to you and the premium amortization allocable to the payment(s). If you did notify your payer that you did not want to amortize the premium on a taxable covered security, then your payer will only report the gross amount of interest paid to you. For a noncovered security acquired at a premium, your payer is only required to report the gross amount of interest paid to you.'); + AddFormInstructionLine(PeriodNo, 'INT', 2, 'Recipient’s taxpayer identification number (TIN).', 'For your protection, this form may show only the last four digits of your TIN (social security number (SSN), individual taxpayer identification number (ITIN), adoption taxpayer identification number (ATIN), or employer identification number (EIN)). However, the issuer has reported your complete TIN to the IRS.'); + AddFormInstructionLine(PeriodNo, 'INT', 3, 'FATCA filing requirement.', 'If the FATCA filing requirement box is checked, the payer is reporting on this Form 1099 to satisfy its chapter 4 account reporting requirement. You may also have a filing requirement. See the Instructions for Form 8938.'); + AddFormInstructionLine(PeriodNo, 'INT', 4, 'Account number.', 'May show an account or other unique number the payer assigned to distinguish your account.'); + AddFormInstructionLine(PeriodNo, 'INT', 5, 'Box 1.', 'Shows taxable interest paid to you during the calendar year by the payer. This does not include interest shown in box 3. May also show the total amount of the credits from clean renewable energy bonds, new clean renewable energy bonds, qualified energy conservation bonds, qualified zone academy bonds, qualified school construction bonds, and build America bonds that must be included in your interest income. These amounts were treated as paid to you during the calendar year on the credit allowance dates (March 15, June 15, September 15, and December 15). For more information, see Form 8912. See the instructions above for a taxable covered security acquired at a premium.'); + AddFormInstructionLine(PeriodNo, 'INT', 6, 'Box 2.', 'Shows interest or principal forfeited because of early withdrawal of time savings. You may deduct this amount to figure your adjusted gross income on your income tax return. See the Instructions for Form 1040 to see where to take the deduction.'); + AddFormInstructionLine(PeriodNo, 'INT', 7, 'Box 3.', 'Shows interest on U.S. Savings Bonds, Treasury bills, Treasury bonds, and Treasury notes. This may or may not all be taxable. See Pub. 550. This interest is exempt from state and local income taxes. This interest is not included in box 1. See the instructions above for a taxable covered security acquired at a premium.'); + AddFormInstructionLine(PeriodNo, 'INT', 8, 'Box 4.', 'Shows backup withholding. Generally, a payer must backup withhold if you did not furnish your TIN or you did not furnish the correct TIN to the payer. See Form W-9. Include this amount on your income tax return as tax withheld.'); + AddFormInstructionLine(PeriodNo, 'INT', 9, 'Box 5.', 'Any amount shown is your share of investment expenses of a single-class REMIC. This amount is included in box 1. Note: This amount is not deductible.'); + AddFormInstructionLine(PeriodNo, 'INT', 10, 'Box 6.', 'Shows foreign tax paid. You may be able to claim this tax as a deduction or a credit on your Form 1040 or 1040-SR. See your tax return instructions.'); + AddFormInstructionLine(PeriodNo, 'INT', 11, 'Box 7.', 'Shows the country or U.S. possession to which the foreign tax was paid.'); + AddFormInstructionLine(PeriodNo, 'INT', 12, 'Box 8.', 'Shows tax-exempt interest paid to you during the calendar year by the payer. See how to report this amount in the Instructions for Form 1040. This amount may be subject to backup withholding. See Box 4 above. See the instructions above for a tax-exempt covered security acquired at a premium.'); + AddFormInstructionLine(PeriodNo, 'INT', 13, 'Box 9.', 'Shows tax-exempt interest subject to the alternative minimum tax. This amount is included in box 8. See the Instructions for Form 6251. See the instructions above for a tax-exempt covered security acquired at a premium.'); + AddFormInstructionLine(PeriodNo, 'INT', 14, 'Box 10.', 'For a taxable or tax-exempt covered security, if you made an election under section 1278(b) to include market discount in income as it accrues and you notified your payer of the election in writing in accordance with Regulations section 1.6045-1(n)(5), shows the market discount that accrued on the debt instrument during the year while held by you, unless it was reported on Form 1099-OID. For a taxable or tax-exempt covered security acquired on or after January 1, 2015, accrued market discount will be calculated on a constant yield basis unless you notified your payer in writing in accordance with Regulations section 1.6045-1(n)(5) that you did not want to make a constant yield election for market discount under section 1276(b). Report the accrued market discount on your income tax return as directed in the Instructions for Form 1040. Market discount on a tax-exempt security is includible in taxable income as interest income.'); + AddFormInstructionLine(PeriodNo, 'INT', 15, 'Box 11.', 'For a taxable covered security (other than a U.S. Treasury obligation), shows the amount of premium amortization allocable to the interest payment(s), unless you notified the payer in writing in accordance with Regulations section 1.6045-1(n)(5) that you did not want to amortize bond premium under section 171. If an amount is reported in this box, see the Instructions for Schedule B (Form 1040) to determine the net amount of interest includible in income on Form 1040 or 1040-SR with respect to the security. If an amount is not reported in this box for a taxable covered security acquired at a premium and the payer is reporting premium amortization, the payer has reported a net amount of interest in box 1. If the amount in box 11 is greater than the amount of interest paid on the covered security, see Regulations section 1.171-2(a)(4).'); + AddFormInstructionLine(PeriodNo, 'INT', 16, 'Box 12.', 'For a U.S. Treasury obligation that is a covered security, shows the amount of premium amortization allocable to the interest payment(s), unless you notified the payer in writing in accordance with Regulations section 1.6045-1(n)(5) that you did not want to amortize bond premium under section 171. If an amount is reported in this box, see the Instructions for Schedule B (Form 1040) to determine the net amount of interest includible in income on Form 1040 or 1040-SR with respect to the U.S. Treasury obligation. If an amount is not reported in this box for a U.S. Treasury obligation that is a covered security acquired at a premium and the payer is reporting premium amortization, the payer has reported a net amount of interest in box 3. If the amount in box 12 is greater than the amount of interest paid on the U.S. Treasury obligation, see Regulations section 1.171-2(a)(4).'); + AddFormInstructionLine(PeriodNo, 'INT', 17, 'Box 13.', 'For a tax-exempt covered security, shows the amount of premium amortization allocable to the interest payment(s). If an amount is reported in this box, see Pub. 550 to determine the net amount of tax-exempt interest reportable on Form 1040 or 1040-SR. If an amount is not reported in this box for a tax-exempt covered security acquired at a premium, the payer has reported a net amount of interest in box 8 or 9, whichever is applicable. If the amount in box 13 is greater than the amount of interest paid on the tax-exempt covered security, the excess is a nondeductible loss. See Regulations section 1.171-2(a)(4)(ii).'); + AddFormInstructionLine(PeriodNo, 'INT', 18, 'Box 14.', 'Shows CUSIP number(s) for tax-exempt bond(s) on which tax-exempt interest was paid, or tax credit bond(s) on which taxable interest was paid or tax credit was allowed, to you during the calendar year. If blank, no CUSIP number was issued for the bond(s).'); + AddFormInstructionLine(PeriodNo, 'INT', 19, 'Boxes 15-17.', 'State tax withheld reporting boxes.'); + AddFormInstructionLine(PeriodNo, 'INT', 20, 'Nominees.', 'If this form includes amounts belonging to another person(s), you are considered a nominee recipient. Complete a Form 1099-INT for each of the other owners showing the income allocable to each. File Copy A of the form with the IRS. Furnish Copy B to each owner. List yourself as the “payer” and the other owner(s) as the “recipient.” File Form(s) 1099-INT with Form 1096 with the Internal Revenue Service Center for your area. On Form 1096, list yourself as the “filer.” A spouse is not required to file a nominee return to show amounts owned by the other spouse'); + AddFormInstructionLine(PeriodNo, 'INT', 21, 'Future developments.', 'For the latest information about developments related to Form 1099-INT and its instructions, such as legislation enacted after they were published, go to www.irs.gov/Form1099INT.'); + AddFormInstructionLine(PeriodNo, 'INT', 22, 'Free File Program.', 'Go to www.irs.gov/FreeFile to see if you qualify for no-cost online federal tax preparation, e-filing, and direct deposit or payment options.'); + + AddFormInstructionLine(PeriodNo, 'MISC', 1, 'Recipient’s taxpayer identification number (TIN).', 'For your protection, this form may show only the last four digits of your TIN (social security number (SSN), individual taxpayer identification number (ITIN), adoption taxpayer identification number (ATIN), or employer identification number (EIN)). However, the issuer has reported your complete TIN to the IRS.'); + AddFormInstructionLine(PeriodNo, 'MISC', 2, 'Account number.', 'May show an account or other unique number the payer assigned to distinguish your account.'); + AddFormInstructionLine(PeriodNo, 'MISC', 3, 'Amounts shown may be subject to self-employment (SE) tax.', 'Individuals should see the Instructions for Schedule SE (Form 1040). Corporations, fiduciaries, or partnerships must report the amounts on the appropriate line of their tax returns.'); + AddFormInstructionLine(PeriodNo, 'MISC', 4, 'Form 1099-MISC incorrect?', 'If this form is incorrect or has been issued in error, contact the payer. If you cannot get this form corrected, attach an explanation to your tax return and report your information correctly.'); + AddFormInstructionLine(PeriodNo, 'MISC', 5, 'Box 1.', 'Report rents from real estate on Schedule E (Form 1040). However, report rents on Schedule C (Form 1040) if you provided significant services to the tenant, sold real estate as a business, or rented personal property as a business. See Pub. 527.'); + AddFormInstructionLine(PeriodNo, 'MISC', 6, 'Box 2.', 'Report royalties from oil, gas, or mineral properties; copyrights; and patents on Schedule E (Form 1040). However, report payments for a working interest as explained in the Schedule E (Form 1040) instructions. For royalties on timber, coal, and iron ore, see Pub. 544.'); + AddFormInstructionLine(PeriodNo, 'MISC', 7, 'Box 3.', 'Generally, report this amount on the “Other income” line of Schedule 1 (Form 1040) and identify the payment. The amount shown may be payments received as the beneficiary of a deceased employee, prizes, awards, taxable damages, Indian gaming profits, or other taxable income. See Pub. 525. If it is trade or business income, report this amount on Schedule C or F (Form 1040).'); + AddFormInstructionLine(PeriodNo, 'MISC', 8, 'Box 4.', 'Shows backup withholding or withholding on Indian gaming profits. Generally, a payer must backup withhold if you did not furnish your TIN. See Form W-9 and Pub. 505 for more information. Report this amount on your income tax return as tax withheld.'); + AddFormInstructionLine(PeriodNo, 'MISC', 9, 'Box 5.', 'Shows the amount paid to you as a fishing boat crew member by the operator, who considers you to be self-employed. Self-employed individuals must report this amount on Schedule C (Form 1040). See Pub. 334.'); + AddFormInstructionLine(PeriodNo, 'MISC', 10, 'Box 6.', 'For individuals, report on Schedule C (Form 1040).'); + AddFormInstructionLine(PeriodNo, 'MISC', 11, 'Box 7.', 'If checked, consumer products totaling $5,000 or more were sold to you for resale, on a buy-sell, a deposit-commission, or other basis. Generally, report any income from your sale of these products on Schedule C (Form 1040).'); + AddFormInstructionLine(PeriodNo, 'MISC', 12, 'Box 8.', 'Shows substitute payments in lieu of dividends or tax-exempt interest received by your broker on your behalf as a result of a loan of your securities. Report on the “Other income” line of Schedule 1 (Form 1040).'); + AddFormInstructionLine(PeriodNo, 'MISC', 13, 'Box 9.', 'Report this amount on Schedule F (Form 1040).'); + AddFormInstructionLine(PeriodNo, 'MISC', 14, 'Box 10.', 'Shows gross proceeds paid to an attorney in connection with legal services. Report only the taxable part as income on your return.'); + AddFormInstructionLine(PeriodNo, 'MISC', 15, 'Box 11.', 'Shows the amount of cash you received for the sale of fish if you are in the trade or business of catching fish.'); + AddFormInstructionLine(PeriodNo, 'MISC', 16, 'Box 12.', 'May show current year deferrals as a nonemployee under a nonqualified deferred compensation (NQDC) plan that is subject to the requirements of section 409A plus any earnings on current and prior year deferrals.'); + AddFormInstructionLine(PeriodNo, 'MISC', 17, 'Box 13.', 'If the FATCA filing requirement box is checked, the payer is reporting on this Form 1099 to satisfy its account reporting requirement under chapter 4 of the Internal Revenue Code. You may also have a filing requirement. See the Instructions for Form 8938.'); + AddFormInstructionLine(PeriodNo, 'MISC', 18, 'Box 14.', 'Shows your total compensation of excess golden parachute payments subject to a 20% excise tax. See your tax return instructions for where to report.'); + AddFormInstructionLine(PeriodNo, 'MISC', 19, 'Box 15.', 'Shows income as a nonemployee under an NQDC plan that does not meet the requirements of section 409A. Any amount included in box 12 that is currently taxable is also included in this box. Report this amount as income on your tax return. This income is also subject to a substantial additional tax to be reported on Form 1040, 1040-SR, or 1040-NR. See the instructions for your tax return.'); + AddFormInstructionLine(PeriodNo, 'MISC', 20, 'Boxes 16-18.', 'Show state or local income tax withheld from the payments.'); + AddFormInstructionLine(PeriodNo, 'MISC', 21, 'Future developments.', 'For the latest information about developments related to Form 1099-MISC and its instructions, such as legislation enacted after they were published, go to www.irs.gov/Form1099MISC.'); + AddFormInstructionLine(PeriodNo, 'MISC', 22, 'Free File Program.', 'Go to www.irs.gov/FreeFile to see if you qualify for no-cost online federal tax preparation, e-filing, and direct deposit or payment options.'); + + AddFormInstructionLine(PeriodNo, 'DIV', 1, 'Recipient’s taxpayer identification number (TIN).', 'For your protection, this form may show only the last four digits of your TIN (SSN, ITIN, ATIN, or EIN). However, the issuer has reported your complete TIN to the IRS.'); + AddFormInstructionLine(PeriodNo, 'DIV', 2, 'Account number.', 'May show an account or other unique number the payer assigned to distinguish your account.'); + AddFormInstructionLine(PeriodNo, 'DIV', 3, 'Box 1a.', 'Shows total ordinary dividends that are taxable. Include this amount on the “Ordinary dividends” line of Form 1040 or 1040-SR. Also report it on Schedule B (Form 1040), if required.'); + AddFormInstructionLine(PeriodNo, 'DIV', 4, 'Box 1b.', 'Shows the portion of the amount in box 1a that may be eligible for reduced capital gains rates. See the Instructions for Form 1040 for how to determine this amount and where to report. The amount shown may be dividends a corporation paid directly to you as a participant (or beneficiary of a participant) in an employee stock ownership plan (ESOP). Report it as a dividend on your Form 1040 or 1040-SR but treat it as a plan distribution, not as investment income, for any other purpose.'); + AddFormInstructionLine(PeriodNo, 'DIV', 5, 'Box 2a.', 'Shows total capital gain distributions from a regulated investment company (RIC) or real estate investment trust (REIT). See How To Report in the Instructions for Schedule D (Form 1040). But, if no amount is shown in boxes 2b, 2c, 2d, and 2f and your only capital gains and losses are capital gain distributions, you may be able to report the amounts shown in box 2a on your Form 1040 or 1040-SR rather than Schedule D. See the Instructions for Form 1040.'); + AddFormInstructionLine(PeriodNo, 'DIV', 6, 'Box 2b.', 'Shows the portion of the amount in box 2a that is unrecaptured section 1250 gain from certain depreciable real property. See the Unrecaptured Section 1250 Gain Worksheet in the Instructions for Schedule D (Form 1040).'); + AddFormInstructionLine(PeriodNo, 'DIV', 7, 'Box 2c.', 'Shows the portion of the amount in box 2a that is section 1202 gain from certain small business stock that may be subject to an exclusion. See the Schedule D (Form 1040) instructions.'); + AddFormInstructionLine(PeriodNo, 'DIV', 8, 'Box 2d.', 'Shows the portion of the amount in box 2a that is 28% rate gain from sales or exchanges of collectibles. If required, use this amount when completing the 28% Rate Gain Worksheet in the Instructions for Schedule D (Form 1040).'); + AddFormInstructionLine(PeriodNo, 'DIV', 9, 'Box 2e.', 'Shows the portion of the amount in box 1a that is section 897 gain attributable to disposition of U.S. real property interests (USRPI).'); + AddFormInstructionLine(PeriodNo, 'DIV', 10, 'Box 2f.', 'Shows the portion of the amount in box 2a that is section 897 gain attributable to disposition of USRPI.'); + AddFormInstructionLine(PeriodNo, 'DIV', 11, 'Note:', 'Boxes 2e and 2f apply only to foreign persons and entities whose income maintains its character when passed through or distributed to its direct or indirect foreign owners or beneficiaries. It is generally treated as effectively connected to a trade or business within the United States. See the instructions for your tax return.'); + AddFormInstructionLine(PeriodNo, 'DIV', 12, 'Box 3.', 'Shows a return of capital. To the extent of your cost (or other basis) in the stock, the distribution reduces your basis and is not taxable. Any amount received in excess of your basis is taxable to you as capital gain. See Pub. 550.'); + AddFormInstructionLine(PeriodNo, 'DIV', 13, 'Box 4.', 'Shows backup withholding. A payer must backup withhold on certain payments if you did not give your TIN to the payer. See Form W-9 for information on backup withholding. Include this amount on your income tax return as tax withheld.'); + AddFormInstructionLine(PeriodNo, 'DIV', 14, 'Box 5.', 'Shows the portion of the amount in box 1a that may be eligible for the 20% qualified business income deduction under section 199A. See the instructions for Form 8995 and Form 8995-A.'); + AddFormInstructionLine(PeriodNo, 'DIV', 15, 'Box 6.', 'Shows your share of expenses of a nonpublicly offered RIC, generally a nonpublicly offered mutual fund. This amount is included in box 1a.'); + AddFormInstructionLine(PeriodNo, 'DIV', 16, 'Box 7.', 'Shows the foreign tax that you may be able to claim as a deduction or a credit on Form 1040 or 1040-SR. See the Instructions for Form 1040.'); + AddFormInstructionLine(PeriodNo, 'DIV', 17, 'Box 8.', 'This box should be left blank if a RIC reported the foreign tax shown in box 7.'); + AddFormInstructionLine(PeriodNo, 'DIV', 18, 'Boxes 9 and 10.', 'Show cash and noncash liquidation distributions.'); + AddFormInstructionLine(PeriodNo, 'DIV', 19, 'Box 11.', 'If the FATCA filing requirement box is checked, the payer is reporting on this Form 1099 to satisfy its account reporting requirement under chapter 4 of the Internal Revenue Code. You may also have a filing requirement. See the Instructions for Form 8938.'); + AddFormInstructionLine(PeriodNo, 'DIV', 20, 'Box 12.', 'Shows exempt-interest dividends from a mutual fund or other RIC paid to you during the calendar year. See the Instructions for Form 1040 for where to report. This amount may be subject to backup withholding. See Box 4 above.'); + AddFormInstructionLine(PeriodNo, 'DIV', 21, 'Box 13.', 'Shows exempt-interest dividends subject to the alternative minimum tax. This amount is included in box 12. See the Instructions for Form 6251.'); + AddFormInstructionLine(PeriodNo, 'DIV', 22, 'Boxes 14-16.', 'State income tax withheld reporting boxes.'); + AddFormInstructionLine(PeriodNo, 'DIV', 23, 'Nominees.', 'If this form includes amounts belonging to another person, you are considered a nominee recipient. You must file Form 1099-DIV (with a Form 1096) with the IRS for each of the other owners to show their share of the income, and you must furnish a Form 1099-DIV to each. A spouse is not required to file a nominee return to show amounts owned by the other spouse. See the current General Instructions for Certain Information Returns.'); + end; + + local procedure AddReportingPeriod(PeriodNo: Code[20]; StartingDate: Date; EndingDate: Date; Description: Text): Code[20] + var + IRSReportingPeriod: Record "IRS Reporting Period"; + begin + IRSReportingPeriod.Validate("No.", PeriodNo); + IRSReportingPeriod.Validate("Starting Date", StartingDate); + IRSReportingPeriod.Validate("Ending Date", EndingDate); + IRSReportingPeriod.Validate("Description", Description); + IRSReportingPeriod.Insert(true); + exit(IRSReportingPeriod."No."); + end; + + local procedure AddForm(PeriodNo: Code[20]; FormNo: Code[20]; Description: Text) + var + IRS1099Form: Record "IRS 1099 Form"; + begin + IRS1099Form.Validate("Period No.", PeriodNo); + IRS1099Form.Validate("No.", FormNo); + IRS1099Form.Validate("Description", Description); + IRS1099Form.Insert(true); + end; + + local procedure AddFormBox(PeriodNo: Code[20]; FormNo: Code[20]; FormBoxNo: Code[20]; Description: Text; MinimumReportableAmount: Decimal) + var + IRS1099FormBox: Record "IRS 1099 Form Box"; + begin + IRS1099FormBox.Validate("Period No.", PeriodNo); + IRS1099FormBox.Validate("Form No.", FormNo); + IRS1099FormBox.Validate("No.", FormBoxNo); + IRS1099FormBox.Validate("Description", Description); + IRS1099FormBox.Validate("Minimum Reportable Amount", MinimumReportableAmount); + IRS1099FormBox.Insert(true); + end; + + local procedure AddFormStatementLine(PeriodNo: Code[20]; FormNo: Code[20]; FormBoxNo: Code[20]; StatementLineNo: Integer; Description: Text) + begin + AddFormStatementLine(PeriodNo, FormNo, Enum::"IRS 1099 Print Value Type"::Amount, FormBoxNo, StatementLineNo, Description); + end; + + local procedure AddFormStatementLine(PeriodNo: Code[20]; FormNo: Code[20]; Type: Enum "IRS 1099 Print Value Type"; FormBoxNo: Code[20]; StatementLineNo: Integer; Description: Text) + var + IRS1099FormStatementLine: Record "IRS 1099 Form Statement Line"; + begin + IRS1099FormStatementLine.Validate("Period No.", PeriodNo); + IRS1099FormStatementLine.Validate("Form No.", FormNo); + IRS1099FormStatementLine.Validate("Line No.", StatementLineNo); + IRS1099FormStatementLine.Validate("Print Value Type", Type); + IRS1099FormStatementLine.Validate("Row No.", FormBoxNo); + IRS1099FormStatementLine.Validate("Description", Description); + IRS1099FormStatementLine.Validate("Filter Expression", StrSubstNo(StatementLineFilterExpressionTxt, FormBoxNo)); + IRS1099FormStatementLine.Insert(true); + end; + + local procedure AddFormInstructionLine(PeriodNo: Code[20]; FormNo: Code[20]; LineNo: Integer; Header: Text; Description: Text) + var + IRS1099FormInstruction: Record "IRS 1099 Form Instruction"; + begin + IRS1099FormInstruction.Validate("Period No.", PeriodNo); + IRS1099FormInstruction.Validate("Form No.", FormNo); + IRS1099FormInstruction.Validate("Line No.", LineNo); + IRS1099FormInstruction.Validate(Header, Header); + IRS1099FormInstruction.Validate(Description, Description); + IRS1099FormInstruction.Insert(true); + end; +} diff --git a/Apps/US/IRSForms/app/src/Setup/IRSFormsFeature.Codeunit.al b/Apps/US/IRSForms/app/src/Setup/IRSFormsFeature.Codeunit.al new file mode 100644 index 0000000000..a67b5cfc45 --- /dev/null +++ b/Apps/US/IRSForms/app/src/Setup/IRSFormsFeature.Codeunit.al @@ -0,0 +1,165 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +#if not CLEAN25 +namespace Microsoft.Finance.VAT.Reporting; + +using System.Environment; +using System.Environment.Configuration; +using System.Media; + +codeunit 10038 "IRS Forms Feature" +{ + Access = Internal; + InherentEntitlements = X; + InherentPermissions = X; + + var + FeatureKeyIdTok: Label 'IRSForm', Locked = true; + InstallFeatureNotificationMsg: Label 'The IRS Forms feature is not enabled. You can enable it in the Feature Management window.'; + DataTransferInProgressNotificationMsg: Label 'The IRS Forms feature is enabled, but the data transfer is in progress. Refresh the page (F5), or come back later.'; + AssistedSetupTxt: Label 'Set up a IRS Forms feature'; + AssistedSetupDescriptionTxt: Label 'Setup 1099 forms to transmit the tax data to the IRS in the United States'; + AssistedSetupHelpTxt: Label 'https://learn.microsoft.com/en-us/dynamics365/business-central/localfunctionality/unitedstates/set-up-use-irs1099-form', Locked = true; + + procedure IsEnabled() IsEnabled: Boolean + var + FeatureManagementFacade: Codeunit "Feature Management Facade"; + begin + IsEnabled := FeatureManagementFacade.IsEnabled(FeatureKeyIdTok); + OnAfterCheckFeatureEnabled(IsEnabled); + end; + + procedure GetFeatureKeyId(): Text + begin + exit(FeatureKeyIdTok); + end; + + procedure FeatureCanBeUsed(): Boolean + var + IRSFormsSetup: Record "IRS Forms Setup"; + FeatureNotification: Notification; + begin + IRSFormsSetup.InitSetup(); + if IsEnabled() and not IRSFormsSetup.DataTransferInProgress() then + exit(true); + FeatureNotification.Id := GetFeatureNotificationId(); + FeatureNotification.Recall(); + if IsEnabled() then + FeatureNotification.Message := DataTransferInProgressNotificationMsg + else + FeatureNotification.Message := InstallFeatureNotificationMsg; + FeatureNotification.Send(); + exit(false); + end; + + procedure UpgradeFromBaseApplication() + var + IRSFormsSetup: Record "IRS Forms Setup"; + begin + IRSFormsSetup.InitSetup(); + IRSFormsSetup.CheckIfDataTransferIsPossible(); + if IRSFormsSetup."Background Task" then begin + ScheduleTask(); + exit; + end; + Codeunit.Run(Codeunit::"IRS 1099 Transfer From BaseApp"); + end; + + [EventSubscriber(ObjectType::Codeunit, Codeunit::"Feature Management Facade", 'OnAfterFeatureEnableConfirmed', '', true, true)] + local procedure OnAfterFeatureEnableConfirmed(var FeatureKey: Record "Feature Key") + var + IRSFormsGuide: Page "IRS Forms Guide"; + begin + if FeatureKey.ID = GetFeatureKeyId() then begin + Commit(); + if IRSFormsGuide.RunModal() = Action::OK then + if not IRSFormsGuide.IsSetupCompleted() then + Error(''); + end; + end; + + local procedure GetFeatureNotificationId(): Guid + begin + exit('0200065a-8efe-4c00-a68f-ea20fe41e4e3'); + end; + + local procedure ScheduleTask(): Boolean; + var + IRSFormsSetup: Record "IRS Forms Setup"; + DoNotScheduleTask: Boolean; + TaskID: Guid; + begin + if not TaskScheduler.CanCreateTask() then + exit(false); + + IRSFormsSetup.Get(); + if DoNotScheduleTask then + IRSFormsSetup."Data Transfer Task ID" := TaskID + else + IRSFormsSetup."Data Transfer Task ID" := + CreateTask(IRSFormsSetup); + IRSFormsSetup.Modify(); + exit(true); + end; + + local procedure CreateTask(var IRSFormsSetup: Record "IRS Forms Setup") TaskId: Guid + begin + CancelTask(IRSFormsSetup); + AdjustStartDateTime(IRSFormsSetup); + TaskId := + TaskScheduler.CreateTask( + Codeunit::"IRS 1099 Transfer From BaseApp", Codeunit::"IRS 1099 Trans. Error Handler", + true, CompanyName(), IRSFormsSetup."Task Start Date/Time"); + end; + + procedure CancelTask(var IRSFormsSetup: Record "IRS Forms Setup") + var + ScheduledTask: Record "Scheduled Task"; + begin + IRSFormsSetup.Get(); + if not IsNullGuid(IRSFormsSetup."Data Transfer Task ID") then begin + if ScheduledTask.Get(IRSFormsSetup."Data Transfer Task ID") then + TaskScheduler.CancelTask(IRSFormsSetup."Data Transfer Task ID"); + Clear(IRSFormsSetup."Data Transfer Task ID"); + end; + end; + + procedure InsertAssistedSetup() + var + GuidedExperience: Codeunit "Guided Experience"; + AssistedSetupGroup: Enum "Assisted Setup Group"; + VideoCategory: Enum "Video Category"; + begin + GuidedExperience.InsertAssistedSetup(AssistedSetupTxt, CopyStr(AssistedSetupTxt, 1, 50), AssistedSetupDescriptionTxt, 5, ObjectType::Page, Page::"IRS Forms Guide", AssistedSetupGroup::FinancialReporting, + '', VideoCategory::FinancialReporting, AssistedSetupHelpTxt); + end; + + local procedure AdjustStartDateTime(var IRSFormsSetup: Record "IRS Forms Setup") + var + Delta: Duration; + begin + Delta := 500; // Time to update the status record before the task is started. + if IRSFormsSetup."Task Start Date/Time" = 0DT then + IRSFormsSetup."Task Start Date/Time" := CurrentDateTime() + Delta + else + if IRSFormsSetup."Task Start Date/Time" - CurrentDateTime() < Delta then + IRSFormsSetup."Task Start Date/Time" := CurrentDateTime() + Delta; + end; + + [EventSubscriber(ObjectType::Codeunit, Codeunit::"Guided Experience", 'OnRegisterAssistedSetup', '', true, true)] + local procedure InsertIntoAssistedSetup() + begin + if not IsEnabled() then + exit; + InsertAssistedSetup(); + end; + + [IntegrationEvent(true, false)] + local procedure OnAfterCheckFeatureEnabled(var IsEnabled: Boolean) + begin + end; + +} +#endif diff --git a/Apps/US/IRSForms/app/src/Setup/IRSFormsGuide.Page.al b/Apps/US/IRSForms/app/src/Setup/IRSFormsGuide.Page.al new file mode 100644 index 0000000000..56919e094d --- /dev/null +++ b/Apps/US/IRSForms/app/src/Setup/IRSFormsGuide.Page.al @@ -0,0 +1,554 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +using Microsoft.Foundation.Navigate; +#if not CLEAN25 +using Microsoft.Purchases.Document; +using Microsoft.Purchases.Payables; +using Microsoft.Purchases.Vendor; +#endif +using System.Environment; +using System.Environment.Configuration; +using System.Telemetry; +using System.Utilities; + +page 10032 "IRS Forms Guide" +{ + PageType = NavigatePage; + RefreshOnActivate = true; + ApplicationArea = BasicUS; + SourceTable = "IRS Forms Setup"; + + layout + { + area(content) + { + group(StandardBanner) + { + Caption = ''; + Editable = false; + Visible = TopBannerVisible and not FinishActionEnabled; + field(MediaResourcesStandard; MediaResourcesStd."Media Reference") + { + ApplicationArea = Basic, Suite; + Editable = false; + ShowCaption = false; + } + } + group(Start) + { + Visible = WelcomeStepVisible; + group(Welcome) + { + Caption = 'Welcome to the setup of IRS Forms'; + Visible = WelcomeStepVisible; + group(IRSFormsDescription) + { + Caption = ''; + InstructionalText = 'Enable using 1099 forms to transmit the tax data to the IRS in the United States. This guide helps you set up the reporting periods, forms, form boxes and statement for Dynamics 365 Business Central. If you do not want to set this up right now, close this page.'; + } + } + } + group(DataParent) + { + Visible = DataStepEnabled; + group(DataChild) + { + Caption = 'Create new setup, or transfer existing data'; + InstructionalText = 'If you’re setting up Business Central, choose Create New Setup. Business Central will create the forms and associated setup so you can fill out and print them. If you’re upgrading and already have data for your 1099 form, choose Transfer Existing Data. Both options require you to specify the reporting year for the tax data to the IRS. The data creation or the transfer process starts when you finish the guide.'; + + field(ReportingYearControl; Rec."Init Reporting Year") + { + Caption = 'Reporting Year'; + ShowMandatory = true; + BlankZero = true; + ToolTip = 'Specifies the year for which you will be reporting the tax data to the IRS. This is applicable for both options below.'; + } + + field(CreateNewSetupControl; CreateNewSetup) + { + Caption = 'Create new setup'; + ToolTip = 'Specifies whether you want to create the new setup automatically instead of doing it manually - a reporting period, forms, form boxes and a statement.'; + + trigger OnValidate() + begin + if Rec."Init Reporting Year" = 0 then + Error('You must specify the reporting year.'); + TransferExistingData := false; + end; + } + field(TransferExistingDataControl; TransferExistingData) + { + Caption = 'Transfer existing data'; + ToolTip = 'Specifies whether you want to transfer the data from the IRS 1099 Base Application to the new IRS forms extension. This includes IRS 1099 form boxes, vendor setup, purchase documents and vendor ledger entries.'; + Editable = CanTransferData; + + trigger OnValidate() + begin + if Rec."Init Reporting Year" = 0 then + Error('You must specify the reporting year.'); + Rec.CheckIfDataTransferIsPossible(); + CreateNewSetup := false; + end; + } + field(DataTransferStatusControl; DataTransferStatus) + { + ShowCaption = false; + ToolTip = 'Specifies the reason why the data transfer is not possible.'; + Editable = false; + StyleExpr = true; + Style = StandardAccent; + Visible = DataTransferStatus <> ''; + } + } + } + group(TransferExistingDataStepParent) + { + Visible = TransferExistingDataStepEnabled; + group(TransferExistingDataWhatIsUpdated) + { + Caption = 'What is updated'; + group(TransferExistingDataWhatIsUpdatedDescr) + { + ShowCaption = false; + field(TransferExistingDataDescription; ReviewUpdatedDataTok) + { + ApplicationArea = Basic, Suite; + ShowCaption = false; + Editable = false; + MultiLine = true; + ToolTip = 'Review affected data.'; + } + } + } + group(TransferExistingDataReviewAffectedData) + { + ShowCaption = false; + field(TransferExistingDataReviewDataField; ReviewDataLinkTok) + { + ApplicationArea = Basic, Suite; + ShowCaption = false; + + trigger OnDrillDown() + begin + ReviewData(); + end; + } + } + group(Background) + { + ShowCaption = false; + Visible = CanCreateTask; + field(BackgroundTask; Rec."Background Task") + { + ApplicationArea = Basic, Suite; + Caption = 'Run in background session'; + ToolTip = 'Specifies whether the task should be run in the current or in the background session.'; + } + } + group(SetupBackgroundTaskParent) + { + Caption = 'Schedule background task'; + Visible = Rec."Background Task"; + group(SetupBackgroundTask) + { + ShowCaption = false; + field("Start Date/Time"; Rec."Task Start Date/Time") + { + ApplicationArea = Basic, Suite; + Enabled = not Rec."Run Task Now"; + Caption = 'Start Date/Time'; + ToolTip = 'Specifies the earliest date and time when the task should be run in the background session.'; + } + field(RunTaskNow; Rec."Run Task Now") + { + ApplicationArea = Basic, Suite; + Caption = 'Run immediately'; + ToolTip = 'Specifies whether the task should be run immediately in the background session.'; + } + } + } + group(TransferExistingDataDataUpgradeAgreement) + { + ShowCaption = false; + + field(TransferExistingDataAgreed; DataUpgradeAgreed) + { + ApplicationArea = Basic, Suite; + Caption = 'I accept the data update'; + ToolTip = 'Specifies whether the user does understand the update procedure and agree to proceed.'; + } + } + } + group(FeaturesStepParent) + { + Visible = FeaturesStepEnabled; + group(FeaturesStepChild) + { + Caption = 'Specify the features of the IRS Forms'; + InstructionalText = 'Specify how the IRS Forms feature will be used in your company.'; + field("Collect Details For Line"; Rec."Collect Details For Line") + { + ToolTip = 'Specifies if the mapping between the IRS 1099 Form Line and associated vendor ledger entries must be kept. That will allow you to drill-down into the Amount field, but requires an extra space in the database.'; + } + field("Protect TIN"; Rec."Protect TIN") + { + ToolTip = 'Specifies if the TIN of the vendor/company must be protected when printing reports.'; + } + } + } + group(FinishedBanner) + { + Caption = ''; + Editable = false; + Visible = TopBannerVisible and FinishActionEnabled; + field(MediaResourcesDone; MediaResourcesFinished."Media Reference") + { + ApplicationArea = Basic, Suite; + Editable = false; + ShowCaption = false; + } + } + + + group(FinishedParent) + { + ShowCaption = false; + Visible = FinishActionEnabled; + group(FinishedChild) + { + Caption = 'The IRS Forms setup is completed!'; + Visible = FinishActionEnabled; + group(FinishDescription) + { + Caption = ''; + InstructionalText = 'You''re ready to use the IRS Forms functionality! Open the IRS Reporting Periods to access the setup and documents.'; + } + } + } + } + } + actions + { + area(processing) + { + action(ActionBack) + { + ApplicationArea = Basic, Suite; + Caption = 'Back'; + Enabled = BackActionEnabled; + Image = PreviousRecord; + InFooterBar = true; + trigger OnAction(); + begin + NextStep(true); + end; + } + action(ActionNext) + { + ApplicationArea = Basic, Suite; + Caption = 'Next'; + Enabled = NextActionEnabled; + Image = NextRecord; + InFooterBar = true; + trigger OnAction(); + begin + NextStep(false); + end; + } + action(ActionFinish) + { + ApplicationArea = Basic, Suite; + Caption = 'Finish'; + Enabled = FinishActionEnabled; + Image = Approve; + InFooterBar = true; + trigger OnAction(); + begin + FinishAction(); + end; + } + } + } + + trigger OnQueryClosePage(CloseAction: action): Boolean; + begin + if CloseAction = CloseAction::OK then + if SetupCompleted then + FeatureTelemetry.LogUptake('0000MHX', IRSFormsTok, Enum::"Feature Uptake Status"::"Set up") + else + if not Confirm(SetupNotCompletedQst) then + Error(''); + + end; + + trigger OnInit(); + begin + LoadTopBanners(); + end; + + trigger OnOpenPage(); + begin + Rec.InitSetup(); + CanTransferData := true; + case true of + Rec."Data Transfer Error Message" <> '': + DataTransferStatus := StrSubstNo(DataTransferFailedErr, Rec."Data Transfer Error Message"); + Rec.DataTransferInProgress(): + begin + DataTransferStatus := 'Data transfer is in progress'; + CanTransferData := false; + end; + Rec."Data Transfer Completed": + begin + DataTransferStatus := 'Data transfer has been completed'; + CanTransferData := false; + end; + end; + CanCreateTask := TaskScheduler.CanCreateTask(); + FeatureTelemetry.LogUptake('0000MJO', IRSFormsTok, Enum::"Feature Uptake Status"::Discovered); + Commit(); + + Step := Step::Start; + EnableControls(); + end; + + var + TempDocumentEntry: Record "Document Entry" temporary; + MediaRepositoryDone, MediaRepositoryStandard : Record "Media Repository"; + MediaResourcesFinished: Record "Media Resources"; + MediaResourcesStd: Record "Media Resources"; + FeatureTelemetry: Codeunit "Feature Telemetry"; + CreateNewSetup, TransferExistingData : Boolean; + Step: Option Start,Data,TransferExistingData,Features,Finish; + DataStepEnabled, TransferExistingDataStepEnabled : Boolean; + FeaturesStepEnabled, BackActionEnabled, FinishActionEnabled, NextActionEnabled : Boolean; + WelcomeStepVisible, TopBannerVisible, SetupCompleted, DataUpgradeAgreed, CanCreateTask : Boolean; + CanTransferData: Boolean; + DataTransferStatus: Text; + SkipDataSetupStepQst: Label 'You have not chosen to create a new setup or to transfer the existing date.\\Are you sure that you want to skip this step and set up the feature manually?'; + ReviewUpdatedDataTok: Label 'Records from several Base Application tables will be copied to the new IRS Forms App tables. Please review affected data as the data update can take longer in case of large amount of records. In case of large amount of records you can consider a run in background session option. The data update process starts when you finish the guide.'; + ReviewDataLinkTok: Label 'Review affected data'; + SetupNotCompletedQst: Label 'Set up of IRS Forms has not been completed.\\Are you sure that you want to exit?'; + DataUpdateNotAcceptedErr: Label 'Please, accept the data update to proceed.'; + DataTransferFailedErr: Label 'The data transfer failed: %1.', Comment = '%1 = error message.'; + IRSFormsTok: Label 'IRS Forms', Locked = true; + + local procedure EnableControls(); + begin + ResetControls(); + + case Step of + Step::Start: + ShowWelcomeStep(); + Step::Data: + ShowDataStep(); + Step::TransferExistingData: + TransferExistingDataStep(); + Step::Features: + ShowFeaturesStep(); + Step::Finish: + ShowFinish(); + end; + end; + + local procedure FinishAction(); + var + IRSFormsData: Codeunit "IRS Forms Data"; + GuidedExperience: Codeunit "Guided Experience"; +#if not CLEAN25 + IRSFormsFeature: Codeunit "IRS Forms Feature"; +#endif + begin + SetupCompleted := true; + Commit(); +#if not CLEAN25 + case true of + CreateNewSetup: + IRSFormsData.AddReportingPeriodsWithForms(Rec."Init Reporting Year"); + TransferExistingData: + IRSFormsFeature.UpgradeFromBaseApplication(); + end; +#else + if CreateNewSetup then + IRSFormsData.AddReportingPeriodsWithForms(Rec."Init Reporting Year"); +#endif +#if not CLEAN25 + IRSFormsFeature.InsertAssistedSetup(); +#endif + GuidedExperience.CompleteAssistedSetup(ObjectType::Page, Page::"IRS Forms Guide"); + CurrPage.Close(); + end; + + procedure IsSetupCompleted(): Boolean + begin + exit(SetupCompleted); + end; + + local procedure NextStep(Backwards: Boolean); + begin + if not ValidateControlsBeforeStep(Backwards) then + exit; + if Backwards then begin + if Step = Step::Features then + Step := Step::Data + else + Step -= 1; + end else + if (Step = Step::Data) and (not TransferExistingData) then + Step := Step::Features + else + Step += 1; + EnableControls(); + end; + + local procedure ValidateControlsBeforeStep(Backwards: Boolean): Boolean + var + ConfirmManagement: Codeunit "Confirm Management"; + begin + if (not Backwards) and DataStepEnabled and (not CreateNewSetup) and (not TransferExistingData) then + if not ConfirmManagement.GetResponse(SkipDataSetupStepQst, false) then + exit(false); + if (not Backwards) and TransferExistingDataStepEnabled and (not DataUpgradeAgreed) then begin + Message(DataUpdateNotAcceptedErr); + exit(false); + end; + exit(true); + end; + + local procedure ShowWelcomeStep(); + begin + WelcomeStepVisible := true; + BackActionEnabled := false; + NextActionEnabled := true; + DataStepEnabled := false; + TransferExistingDataStepEnabled := false; + FeaturesStepEnabled := false; + FinishActionEnabled := false; + end; + + local procedure ShowDataStep(); + begin + WelcomeStepVisible := false; + BackActionEnabled := true; + NextActionEnabled := true; + DataStepEnabled := true; + TransferExistingDataStepEnabled := false; + FeaturesStepEnabled := false; + FinishActionEnabled := false; + end; + + local procedure TransferExistingDataStep(); + begin + WelcomeStepVisible := false; + BackActionEnabled := true; + NextActionEnabled := true; + DataStepEnabled := false; + TransferExistingDataStepEnabled := true; + FeaturesStepEnabled := false; + FinishActionEnabled := false; + end; + + local procedure ShowFeaturesStep(); + begin + WelcomeStepVisible := false; + BackActionEnabled := true; + NextActionEnabled := true; + DataStepEnabled := false; + TransferExistingDataStepEnabled := false; + FeaturesStepEnabled := true; + FinishActionEnabled := false; + end; + + local procedure ShowFinish(); + begin + WelcomeStepVisible := false; + BackActionEnabled := true; + NextActionEnabled := false; + DataStepEnabled := false; + TransferExistingDataStepEnabled := false; + FeaturesStepEnabled := false; + FinishActionEnabled := true; + end; + + local procedure ResetControls(); + begin + FinishActionEnabled := false; + BackActionEnabled := true; + NextActionEnabled := true; + DataStepEnabled := false; + TransferExistingDataStepEnabled := false; + FeaturesStepEnabled := false; + WelcomeStepVisible := false; + end; + + local procedure LoadTopBanners(); + begin + if MediaRepositoryStandard.Get('AssistedSetup-NoText-400px.png', Format(CurrentClientType())) and + MediaRepositoryDone.Get('AssistedSetupDone-NoText-400px.png', Format(CurrentClientType())) + then + if MediaResourcesStd.Get(MediaRepositoryStandard."Media Resources Ref") and + MediaResourcesFinished.Get(MediaRepositoryDone."Media Resources Ref") + then + TopBannerVisible := MediaResourcesFinished."Media Reference".HasValue(); + end; + + local procedure ReviewData(); + var + DataUpgradeOverview: Page "Data Upgrade Overview"; + begin + Clear(DataUpgradeOverview); +#if not CLEAN25 + CountUpdatedRecords(); +#endif + DataUpgradeOverview.Set(TempDocumentEntry); + DataUpgradeOverview.RunModal(); + end; + +#if not CLEAN25 + local procedure CountUpdatedRecords() + var +#pragma warning disable AL0432 + IRS1099FormBox: Record "IRS 1099 Form-Box"; +#pragma warning restore AL0432 + Vendor: Record Vendor; +#pragma warning disable AL0432 + IRS1099Adjustment: Record "IRS 1099 Adjustment"; +#pragma warning restore AL0432 + PurchaseHeader: Record "Purchase Header"; + VendorLedgerEntry: Record "Vendor Ledger Entry"; + begin + TempDocumentEntry.Reset(); + TempDocumentEntry.DeleteAll(); +#pragma warning disable AL0432 + InsertDocumentEntry(Database::"IRS 1099 Form-Box", IRS1099FormBox.TableCaption(), IRS1099FormBox.Count); + Vendor.SetFilter("IRS 1099 Code", '<>%1', ''); + InsertDocumentEntry(Database::Vendor, Vendor.TableCaption(), Vendor.Count); + IRS1099Adjustment.SetRange(Year, Rec."Init Reporting Year"); + InsertDocumentEntry(Database::"IRS 1099 Adjustment", IRS1099Adjustment.TableCaption(), IRS1099Adjustment.Count); + VendorLedgerEntry.SetRange("Posting Date", DMY2Date(1, 1, Rec."Init Reporting Year"), DMY2Date(31, 12, Rec."Init Reporting Year")); + VendorLedgerEntry.SetFilter("IRS 1099 Code", '<>%1', ''); + InsertDocumentEntry(Database::"Vendor Ledger Entry", VendorLedgerEntry.TableCaption(), VendorLedgerEntry.Count); + PurchaseHeader.SetRange("Posting Date", DMY2Date(1, 1, Rec."Init Reporting Year"), DMY2Date(31, 12, Rec."Init Reporting Year")); + PurchaseHeader.SetFilter("IRS 1099 Code", '<>%1', ''); + InsertDocumentEntry(Database::"Purchase Header", PurchaseHeader.TableCaption(), PurchaseHeader.Count); +#pragma warning restore AL0432 + end; + + local procedure InsertDocumentEntry(TableID: Integer; TableName: Text; RecordCount: Integer) + begin + if RecordCount = 0 then + exit; + + TempDocumentEntry.Init(); + TempDocumentEntry."Entry No." += 1; + TempDocumentEntry."Table ID" := TableID; + TempDocumentEntry."Table Name" := CopyStr(TableName, 1, MaxStrLen(TempDocumentEntry."Table Name")); + TempDocumentEntry."No. of Records" := RecordCount; + TempDocumentEntry.Insert(); + end; +#endif +} diff --git a/Apps/US/IRSForms/app/src/Setup/IRSFormsInstall.Codeunit.al b/Apps/US/IRSForms/app/src/Setup/IRSFormsInstall.Codeunit.al new file mode 100644 index 0000000000..c519deb941 --- /dev/null +++ b/Apps/US/IRSForms/app/src/Setup/IRSFormsInstall.Codeunit.al @@ -0,0 +1,41 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +using Microsoft.Foundation.Company; + +codeunit 10030 "IRS Forms Install" +{ + Subtype = Install; + Access = Internal; + InherentEntitlements = X; + InherentPermissions = X; + + trigger OnInstallAppPerCompany() + var + AppInfo: ModuleInfo; + begin + NavApp.GetCurrentModuleInfo(AppInfo); + if (AppInfo.DataVersion() <> Version.Create('0.0.0.0')) then + exit; + + SetupFeature(); + end; + + [EventSubscriber(ObjectType::Codeunit, Codeunit::"Company-Initialize", 'OnCompanyInitialize', '', false, false)] + local procedure CompanyInitialize() + begin + SetupFeature(); + end; + + local procedure SetupFeature() + var + IRSFormsSetup: Record "IRS Forms Setup"; + begin + IRSFormsSetup.InitSetup(); + IRSFormsSetup.Validate("Collect Details For Line", true); + IRSFormsSetup.Modify(true); + end; +} diff --git a/Apps/US/IRSForms/app/src/Setup/IRSFormsSetup.Page.al b/Apps/US/IRSForms/app/src/Setup/IRSFormsSetup.Page.al new file mode 100644 index 0000000000..a10e1cc728 --- /dev/null +++ b/Apps/US/IRSForms/app/src/Setup/IRSFormsSetup.Page.al @@ -0,0 +1,77 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +page 10030 "IRS Forms Setup" +{ + PageType = Card; + SourceTable = "IRS Forms Setup"; + ApplicationArea = BasicUS; + UsageCategory = Administration; + DeleteAllowed = false; + InsertAllowed = false; + DataCaptionExpression = ''; + + layout + { + area(content) + { + group(General) + { + field("Collect Details For Line"; Rec."Collect Details For Line") + { + ToolTip = 'Specifies if the mapping between the IRS 1099 Form Line and associated vendor ledger entries must be kept. That will allow you to drill-down into the Amount field, but requires an extra space in the database.'; + } + field("Protect TIN"; Rec."Protect TIN") + { + ToolTip = 'Specifies if the TIN of the vendor/company must be protected when printing reports.'; + } + } + group(EmailSubject) + { + Caption = 'Email Subject'; + field("Email Subject"; Rec."Email Subject") + { + ShowCaption = false; + Importance = Additional; + ToolTip = 'Specifies the subject of the email with 1099 form that is sent to the vendor.'; + } + } + group(EmailBody) + { + Caption = 'Email Body'; + field("Email Body"; EmailBody) + { + ExtendedDatatype = RichContent; + MultiLine = true; + Importance = Additional; + Caption = 'Email Body'; + ToolTip = 'Specifies the body of the email with 1099 form that is sent to the vendor.'; + + trigger OnValidate() + begin + Rec."Email Body" := CopyStr(EmailBody, 1, MaxStrLen(Rec."Email Body")); + end; + } + } + } + } + + var + EmailBody: Text; + + trigger OnOpenPage() + var +#if not CLEAN25 + IRSFormsFeature: Codeunit "IRS Forms Feature"; +#endif + begin +#if not CLEAN25 + CurrPage.Editable := IRSFormsFeature.FeatureCanBeUsed(); +#endif + Rec.InitSetup(); + EmailBody := Rec."Email Body"; + end; +} diff --git a/Apps/US/IRSForms/app/src/Setup/IRSFormsSetup.Table.al b/Apps/US/IRSForms/app/src/Setup/IRSFormsSetup.Table.al new file mode 100644 index 0000000000..4a041c572d --- /dev/null +++ b/Apps/US/IRSForms/app/src/Setup/IRSFormsSetup.Table.al @@ -0,0 +1,117 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +using System.DateTime; + +table 10030 "IRS Forms Setup" +{ + DataClassification = CustomerContent; + + fields + { + field(1; "Primary Key"; Boolean) + { + } + field(3; "Collect Details For Line"; Boolean) + { + } + field(4; "Protect TIN"; Enum "IRS 1099 Protect TIN Type") + { + } + field(20; "Email Subject"; Text[250]) + { + } + field(21; "Email Body"; Text[2048]) + { + } + field(100; Implementation; Enum "IRS Forms Implementation") + { + } + field(150; "Background Task"; Boolean) + { + } + field(151; "Task Start Date/Time"; DateTime) + { + DataClassification = SystemMetadata; + + trigger OnLookup() + var + DateTimeDialog: Page "Date-Time Dialog"; + begin + DateTimeDialog.SetDateTime(RoundDateTime("Task Start Date/Time", 1000)); + if DateTimeDialog.RunModal() = Action::OK then + "Task Start Date/Time" := DateTimeDialog.GetDateTime(); + end; + + trigger OnValidate() + begin + if ("Task Start Date/Time" <> 0DT) and ("Task Start Date/Time" < CurrentDateTime) then + "Task Start Date/Time" := CurrentDateTime; + end; + } + field(152; "Run Task Now"; Boolean) + { + + trigger OnValidate() + begin + if Rec."Run Task Now" then + Rec."Task Start Date/Time" := CurrentDateTime(); + end; + } + field(153; "Data Transfer Task ID"; Guid) + { + + } + field(154; "Data Transfer Completed"; Boolean) + { + } + field(155; "Data Transfer Error Message"; Text[1024]) + { + } + field(500; "Init Reporting Year"; Integer) + { + MinValue = 1; + MaxValue = 99999; + } + } + + keys + { + key(PK; "Primary Key") + { + Clustered = true; + } + } + + var + EmailSubjectTxt: Label '1099 Form Copy for Your Records'; + EmailBodyTxt: Label 'Dear Sir/Madam,
 
We hope this email finds you well. As part of our tax reporting process, we are attaching the 1099 copy substitution form for the payments made to you during the past year. Please review the form, and if you have any questions or need further clarification, feel free to reach out.

Thank you for your prompt attention to this matter. We appreciate your continued partnership.

Best regards,

%1', Comment = '%1 - Company Name', Locked = true; + NotPossibleToRunDataTransferErr: Label 'It is not possible to run the data transfer because it is currently in progress.'; + DataTransferAlreadyCompletedErr: Label 'The data transfer has already been completed.'; + + procedure InitSetup() + begin + if not Rec.Get() then begin + Rec."Email Subject" := EmailSubjectTxt; + Rec."Email Body" := StrSubstNo(EmailBodyTxt, CompanyName); + Rec.Insert(true); + end; + end; + + procedure CheckIfDataTransferIsPossible() + begin + if not IsNullGuid(Rec."Data Transfer Task ID") then + error(NotPossibleToRunDataTransferErr); + if Rec."Data Transfer Completed" then + Error(DataTransferAlreadyCompletedErr); + end; + + procedure DataTransferInProgress(): Boolean + begin + exit((not IsNullGuid(Rec."Data Transfer Task ID")) and (not Rec."Data Transfer Completed")); + end; + +} diff --git a/Apps/US/IRSForms/app/src/Setup/IRSReportingPeriod.Codeunit.al b/Apps/US/IRSForms/app/src/Setup/IRSReportingPeriod.Codeunit.al new file mode 100644 index 0000000000..42ae36437d --- /dev/null +++ b/Apps/US/IRSForms/app/src/Setup/IRSReportingPeriod.Codeunit.al @@ -0,0 +1,132 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +codeunit 10042 "IRS Reporting Period" +{ + Access = Internal; + + var + TableWithRecordsCountMsg: Label '\\%2: %1 records', Comment = '%1 = number of records, %2 = caption of the table'; + ReportingPeriodAlreadyHasSetupMsg: Label 'The reporting period already has setup.'; + SamePeriodFromAndPeriodToErr: Label 'The From Period cannot be the same as the To Period'; + CopiedSetupWithDetailsMsg: Label 'The setup has been copied from %1 to %2. Details:', Comment = '%1 = From Period, %2 = To Period'; + NothingToCopyMsg: Label 'Nothing to copy'; + + procedure GetReportingPeriod(PostingDate: Date): Code[20] + begin + exit(GetReportingPeriod(PostingDate, PostingDate)); + end; + + procedure GetReportingPeriod(StartingDate: Date; EndingDate: Date): Code[20] + var + IRSReportingPeriod: Record "IRS Reporting Period"; + begin + IRSReportingPeriod.SetFilter("Starting Date", '<=%1', StartingDate); + IRSReportingPeriod.SetFilter("Ending Date", '>=%1', EndingDate); + if IRSReportingPeriod.FindFirst() then + exit(IRSReportingPeriod."No."); + end; + + procedure CopyReportingPeriodSetup(Notification: Notification) + var + IRSReportingPeriod: Record "IRS Reporting Period"; + PeriodNo: Text; + begin + PeriodNo := Notification.GetData('ToPeriodNo'); + CopyReportingPeriodSetup(CopyStr(PeriodNo, 1, MaxStrLen(IRSReportingPeriod."No."))); + end; + + procedure CopyReportingPeriodSetup(ToPeriodNo: Code[20]) + var + IRS1099Form: Record "IRS 1099 Form"; + IRS1099FormStatementLine: Record "IRS 1099 Form Statement Line"; + IRS1099CopySetupFrom: Report "IRS 1099 Copy Setup From"; + begin + IRS1099Form.SetRange("Period No.", ToPeriodNo); + if not IRS1099Form.IsEmpty() then + error(ReportingPeriodAlreadyHasSetupMsg); + IRS1099FormStatementLine.SetRange("Period No.", ToPeriodNo); + if not IRS1099FormStatementLine.IsEmpty() then + error(ReportingPeriodAlreadyHasSetupMsg); + IRS1099CopySetupFrom.InitializeRequest(ToPeriodNo); + IRS1099CopySetupFrom.RunModal(); + end; + + procedure CopyReportingPeriodSetup(FromPeriodNo: Code[20]; ToPeriodNo: Code[20]) + var + IRS1099Form: Record "IRS 1099 Form"; + IRS1099FormBox: Record "IRS 1099 Form Box"; + IRS1099FormStatementLine: Record "IRS 1099 Form Statement Line"; + NewIRS1099Form: Record "IRS 1099 Form"; + NewIRS1099FormBox: Record "IRS 1099 Form Box"; + NewIRS1099FormStatementLine: Record "IRS 1099 Form Statement Line"; + IRS1099VendorFormBoxSetup: Record "IRS 1099 Vendor Form Box Setup"; + NewIRS1099VendorFormBoxSetup: Record "IRS 1099 Vendor Form Box Setup"; + IRS1099VendorFormBoxAdj: Record "IRS 1099 Vendor Form Box Adj."; + NewIRS1099VendorFormBoxAdj: Record "IRS 1099 Vendor Form Box Adj."; + SetupCompletedMessage: Text; + SomethingHasBeenCopied: Boolean; + begin + if FromPeriodNo = ToPeriodNo then + Error(SamePeriodFromAndPeriodToErr); + SetupCompletedMessage := CopiedSetupWithDetailsMsg; + IRS1099Form.SetRange("Period No.", FromPeriodNo); + if IRS1099Form.FindSet() then begin + SomethingHasBeenCopied := true; + SetupCompletedMessage += StrSubstNo(TableWithRecordsCountMsg, IRS1099Form.Count(), IRS1099Form.TableCaption); + repeat + NewIRS1099Form := IRS1099Form; + NewIRS1099Form."Period No." := ToPeriodNo; + NewIRS1099Form.Insert(); + until IRS1099Form.Next() = 0; + end; + IRS1099FormBox.SetRange("Period No.", FromPeriodNo); + if IRS1099FormBox.FindSet() then begin + SomethingHasBeenCopied := true; + SetupCompletedMessage += StrSubstNo(TableWithRecordsCountMsg, IRS1099FormBox.Count(), IRS1099FormBox.TableCaption); + repeat + NewIRS1099FormBox := IRS1099FormBox; + NewIRS1099FormBox."Period No." := ToPeriodNo; + NewIRS1099FormBox.Insert(); + until IRS1099FormBox.Next() = 0; + end; + IRS1099VendorFormBoxSetup.SetRange("Period No.", FromPeriodNo); + if IRS1099VendorFormBoxSetup.FindSet() then begin + SomethingHasBeenCopied := true; + SetupCompletedMessage += StrSubstNo(TableWithRecordsCountMsg, IRS1099VendorFormBoxSetup.Count(), IRS1099VendorFormBoxSetup.TableCaption); + repeat + NewIRS1099VendorFormBoxSetup := IRS1099VendorFormBoxSetup; + NewIRS1099VendorFormBoxSetup."Period No." := ToPeriodNo; + NewIRS1099VendorFormBoxSetup.Insert(); + until IRS1099VendorFormBoxSetup.Next() = 0; + end; + IRS1099VendorFormBoxAdj.SetRange("Period No.", FromPeriodNo); + if IRS1099VendorFormBoxAdj.FindSet() then begin + SomethingHasBeenCopied := true; + SetupCompletedMessage += StrSubstNo(TableWithRecordsCountMsg, IRS1099VendorFormBoxAdj.Count(), IRS1099VendorFormBoxAdj.TableCaption); + repeat + NewIRS1099VendorFormBoxAdj := IRS1099VendorFormBoxAdj; + NewIRS1099VendorFormBoxAdj."Period No." := ToPeriodNo; + NewIRS1099VendorFormBoxAdj.Insert(); + until IRS1099VendorFormBoxAdj.Next() = 0; + end; + IRS1099FormStatementLine.SetRange("Period No.", FromPeriodNo); + if IRS1099FormStatementLine.FindSet() then begin + SomethingHasBeenCopied := true; + SetupCompletedMessage += StrSubstNo(TableWithRecordsCountMsg, IRS1099FormStatementLine.Count(), IRS1099FormStatementLine.TableCaption); + repeat + NewIRS1099FormStatementLine := IRS1099FormStatementLine; + NewIRS1099FormStatementLine."Period No." := ToPeriodNo; + NewIRS1099FormStatementLine.Insert(); + SomethingHasBeenCopied := true; + until IRS1099FormStatementLine.Next() = 0; + end; + if SomethingHasBeenCopied then + Message(SetupCompletedMessage, FromPeriodNo, ToPeriodNo) + else + Message(NothingToCopyMsg); + end; +} diff --git a/Apps/US/IRSForms/app/src/Setup/IRSReportingPeriod.Table.al b/Apps/US/IRSForms/app/src/Setup/IRSReportingPeriod.Table.al new file mode 100644 index 0000000000..9a51b7705f --- /dev/null +++ b/Apps/US/IRSForms/app/src/Setup/IRSReportingPeriod.Table.al @@ -0,0 +1,104 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +table 10031 "IRS Reporting Period" +{ + DataClassification = CustomerContent; + DrillDownPageId = "IRS Reporting Periods"; + LookupPageId = "IRS Reporting Periods"; + + fields + { + field(1; "No."; Code[20]) + { + NotBlank = true; + } + field(2; "Starting Date"; Date) + { + NotBlank = true; + + trigger OnValidate() + begin + CheckStartingAndEndingDatesConsistency(); + CheckNoConnectedFormDocuments(FieldCaption("Starting Date")); + end; + } + field(3; "Ending Date"; Date) + { + NotBlank = true; + + trigger OnValidate() + begin + CheckStartingAndEndingDatesConsistency(); + CheckNoConnectedFormDocuments(FieldCaption("Ending Date")); + end; + } + field(4; Description; Text[250]) + { + } + field(100; "Forms In Period"; Integer) + { + CalcFormula = count("IRS 1099 Form" where("Period No." = field("No."))); + Editable = false; + FieldClass = FlowField; + } + } + + keys + { + key(PK; "No.") + { + Clustered = true; + } + } + + var + StartingEndingDateOverlapErr: Label 'The starting date and ending date overlap with an existing reporting period.'; + CannotChangeWhenOpenFormDocumentConnectedErr: Label 'Cannot change %1 when one or more open form documents are connected', Comment = '%1 - field caption'; + StartingDateMoreThanEndingDateErr: Label 'Starting date cannot be greater than ending date'; + + trigger OnDelete() + var + IRS1099Form: Record "IRS 1099 Form"; + IRS1099VendorFormBoxSetup: Record "IRS 1099 Vendor Form Box Setup"; + IRS1099VendorFormBoxAdj: Record "IRS 1099 Vendor Form Box Adj."; + begin + IRS1099Form.SetRange("Period No.", "No."); + IRS1099Form.DeleteAll(true); + IRS1099VendorFormBoxSetup.SetRange("Period No.", "No."); + IRS1099VendorFormBoxSetup.DeleteAll(true); + IRS1099VendorFormBoxAdj.SetRange("Period No.", "No."); + IRS1099VendorFormBoxAdj.DeleteAll(true); + end; + + local procedure CheckNoConnectedFormDocuments(ChangedFieldCaption: Text) + var + IRS1099FormDocHeader: Record "IRS 1099 Form Doc. Header"; + begin + IRS1099FormDocHeader.SetRange("Period No.", "No."); + if not IRS1099FormDocHeader.IsEmpty() then + Error(CannotChangeWhenOpenFormDocumentConnectedErr, ChangedFieldCaption); + end; + + local procedure CheckStartingAndEndingDatesConsistency() + var + IRSReportingPeriod: Record "IRS Reporting Period"; + begin + if (Rec."Starting Date" <> 0D) and (Rec."Ending Date" <> 0D) then begin + if Rec."Starting Date" > Rec."Ending Date" then + Error(StartingDateMoreThanEndingDateErr); + IRSReportingPeriod.SetFilter("No.", '<>%1', Rec."No."); + if not IRSReportingPeriod.FindSet() then + exit; + repeat + if ("Starting Date" in [IRSReportingPeriod."Starting Date" .. IRSReportingPeriod."Ending Date"]) or + ("Ending Date" in [IRSReportingPeriod."Starting Date" .. IRSReportingPeriod."Ending Date"]) + then + Error(StartingEndingDateOverlapErr); + until IRSReportingPeriod.Next() = 0; + end; + end; +} diff --git a/Apps/US/IRSForms/app/src/Setup/IRSReportingPeriods.Page.al b/Apps/US/IRSForms/app/src/Setup/IRSReportingPeriods.Page.al new file mode 100644 index 0000000000..626cb2a2f9 --- /dev/null +++ b/Apps/US/IRSForms/app/src/Setup/IRSReportingPeriods.Page.al @@ -0,0 +1,147 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +page 10031 "IRS Reporting Periods" +{ + PageType = List; + SourceTable = "IRS Reporting Period"; + ApplicationArea = BasicUS; + UsageCategory = Administration; + AboutTitle = 'About reporting periods'; + AboutText = 'Here you can set up the different periods and form boxes, vendor mapping, and statement for reporting per period.'; + DelayedInsert = true; + RefreshOnActivate = true; + AnalysisModeEnabled = false; + + layout + { + area(content) + { + repeater(Group) + { + field("No."; Rec."No.") + { + Tooltip = 'Specifies a reporting period number.'; + } + field("Starting Date"; Rec."Starting Date") + { + ToolTip = 'Specifies a starting date of the reporting period.'; + } + field("Ending Date"; Rec."Ending Date") + { + ToolTip = 'Specifies a ending date of the reporting period.'; + } + field(Description; Rec.Description) + { + ToolTip = 'Specifies a description of the reporting period.'; + } + field("Forms In Period"; Rec."Forms In Period") + { + ToolTip = 'Specifies a number of forms in the reporting period.'; + } + } + } + } + + actions + { + area(Processing) + { + action(Forms) + { + Caption = 'Forms'; + Image = Form; + Scope = Repeater; + ToolTip = 'Specifies the forms to be reported in this period.'; + AboutTitle = 'About forms'; + AboutText = 'Here you can set up all the forms and form boxes you want to report in the certain period. Form boxes will be used in the documents.'; + RunObject = Page "IRS 1099 Forms"; + RunPageLink = "Period No." = field("No."); + } + action(VendorSetup) + { + Caption = 'Vendor Setup'; + Image = Vendor; + Scope = Repeater; + ToolTip = 'Specifies the setup for vendors to be reported in this period.'; + AboutTitle = 'About vendor setup'; + AboutText = 'Here you can set up mapping between vendors and forms for reporting in the certain period. When you create a document for a certain vendor, the system will use this setup to fill in the form boxes.'; + RunObject = Page "IRS 1099 Vendor Form Box Setup"; + RunPageLink = "Period No." = field("No."); + } + action(Adjustments) + { + Caption = 'Adjustments'; + Image = AdjustEntries; + Scope = Repeater; + ToolTip = 'Specifies the adjustment amount for vendors and form boxes in this period'; + AboutTitle = 'About adjustments'; + AboutText = 'Here you specify the adjustment amount for vendors and form boxes. The adjustment amount will be added to the calculated amount in the form box when you create a form document.'; + RunObject = Page "IRS 1099 Vend. Form Box Adjmts"; + RunPageLink = "Period No." = field("No."); + } + action(Documents) + { + Caption = 'Documents'; + Image = Document; + Scope = Repeater; + ToolTip = 'Specifies the documents to be reported in this period.'; + AboutTitle = 'About document'; + AboutText = 'Here you can create the form documents based on the vendor ledger entries with form boxes and adjustments. The documents will be used for reporting to the IRS.'; + RunObject = Page "IRS 1099 Form Documents"; + RunPageLink = "Period No." = field("No."); + } + action(CopyFrom) + { + Caption = 'Copy Setup From...'; + Image = Copy; + ToolTip = 'Copy the setup from another period. That includes forms with boxes, vendor setup, adjustments and form statement.'; + trigger OnAction() + var + IRSReportingPeriod: Codeunit "IRS Reporting Period"; + begin + IRSReportingPeriod.CopyReportingPeriodSetup(Rec."No."); + end; + } + } + area(Promoted) + { + group(Category_Process) + { + Caption = 'Process'; + actionref(CopyFrom_Promoted; CopyFrom) + { + + } + actionref(Forms_Promoted; Forms) + { + + } + actionref(VendorSetup_Promoted; VendorSetup) + { + + } + actionref(Adjustments_Promoted; Adjustments) + { + + } + actionref(Documents_Promoted; Documents) + { + + } + } + } + } + +#if not CLEAN25 + trigger OnOpenPage() + var + IRSFormsFeature: Codeunit "IRS Forms Feature"; + begin + CurrPage.Editable := IRSFormsFeature.FeatureCanBeUsed(); + end; +#endif +} diff --git a/Apps/US/IRSForms/app/src/VendorFormBox/IRS1099FormBoxBufferType.Enum.al b/Apps/US/IRSForms/app/src/VendorFormBox/IRS1099FormBoxBufferType.Enum.al new file mode 100644 index 0000000000..a97fcdbe1a --- /dev/null +++ b/Apps/US/IRSForms/app/src/VendorFormBox/IRS1099FormBoxBufferType.Enum.al @@ -0,0 +1,19 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +enum 10035 "IRS 1099 Form Box Buffer Type" +{ + AssignmentCompatibility = true; + Extensible = true; + + + value(0; Amount) + { + } + value(1; "Ledger Entry") + { + } +} diff --git a/Apps/US/IRSForms/app/src/VendorFormBox/IRS1099FormBoxCalcImpl.Codeunit.al b/Apps/US/IRSForms/app/src/VendorFormBox/IRS1099FormBoxCalcImpl.Codeunit.al new file mode 100644 index 0000000000..d667928165 --- /dev/null +++ b/Apps/US/IRSForms/app/src/VendorFormBox/IRS1099FormBoxCalcImpl.Codeunit.al @@ -0,0 +1,276 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +using Microsoft.Purchases.Payables; +using Microsoft.Purchases.Vendor; +using System.Utilities; + +codeunit 10041 "IRS 1099 Form Box Calc. Impl." implements "IRS 1099 Form Box Calc." +{ + Access = Internal; + InherentEntitlements = X; + InherentPermissions = X; + Permissions = TableData "Vendor Ledger Entry" = r; + + var + IRSFormsSetup: Record "IRS Forms Setup"; + DateIsNotSpecifiedErr: Label '%1 of the IRS reporting period is not specified', Comment = '%1 = starting or ending date'; + No1099FormsGivenFilterErr: Label 'No 1099 forms are found given the input filter'; + NoVendorsGivenFilterErr: Label 'No vendors are found given the input filter'; + + procedure GetVendorFormBoxAmount(var TempVendFormBoxBuffer: Record "IRS 1099 Vend. Form Box Buffer" temporary; IRS1099CalcParameters: Record "IRS 1099 Calc. Params") + var + IRSReportingPeriod: Record "IRS Reporting Period"; + Vendor: Record Vendor; + IRS1099Form: Record "IRS 1099 Form"; + TempIRS1099Form: Record "IRS 1099 Form" temporary; + TempAppliedVendLedgEntry: Record "Vendor Ledger Entry" temporary; + EntryNo: Integer; + begin + if IRS1099CalcParameters."Period No." = '' then + exit; + if not IRSReportingPeriod.Get(IRS1099CalcParameters."Period No.") then + exit; + + if IRSReportingPeriod."Starting Date" = 0D then + error(DateIsNotSpecifiedErr, IRSReportingPeriod.FieldCaption("Starting Date")); + if IRSReportingPeriod."Ending Date" = 0D then + error(DateIsNotSpecifiedErr, IRSReportingPeriod.FieldCaption("Ending Date")); + + IRSFormsSetup.Get(); + IRS1099Form.SetRange("Period No.", IRS1099CalcParameters."Period No."); + if IRS1099CalcParameters."Form No." <> '' then + IRS1099Form.SetRange("No.", IRS1099CalcParameters."Form No."); + if not IRS1099Form.FindSet() then + error(No1099FormsGivenFilterErr); + repeat + TempIRS1099Form := IRS1099Form; + TempIRS1099Form.Insert(); + until IRS1099Form.Next() = 0; + + if IRS1099CalcParameters."Vendor No." <> '' then + Vendor.SetRange("No.", IRS1099CalcParameters."Vendor No."); + if not Vendor.Findset() then + error(NoVendorsGivenFilterErr); + repeat + TempAppliedVendLedgEntry.Reset(); + TempAppliedVendLedgEntry.DeleteAll(); + GetAppliedVendorEntries(TempAppliedVendLedgEntry, TempIRS1099Form, Vendor."No.", IRSReportingPeriod); + TransferVengLedgEntryBufferToVendFormBoxBuffer(TempVendFormBoxBuffer, TempAppliedVendLedgEntry, EntryNo, IRS1099CalcParameters."Period No."); + FinalizeVendFormBoxBuffer(TempVendFormBoxBuffer, EntryNo, IRSReportingPeriod."No.", Vendor."No."); + until Vendor.Next() = 0; + end; + + local procedure GetAppliedVendorEntries(var TempAppliedVendLedgEntry: Record "Vendor Ledger Entry" temporary; var TempIRS1099Form: Record "IRS 1099 Form" temporary; + VendorNo: Code[20]; IRSReportingPeriod: Record "IRS Reporting Period"); + var + PmtDtldVendLedgEntry: Record "Detailed Vendor Ledg. Entry"; + InvDtldVendLedgEntry: Record "Detailed Vendor Ledg. Entry"; + PmtVendLedgEntry: Record "Vendor Ledger Entry"; + TempInteger: Record "Integer" temporary; + begin + TempAppliedVendLedgEntry.Reset(); + TempAppliedVendLedgEntry.DeleteAll(); + + FilterPaymentVendorLedgerEntries(PmtVendLedgEntry, VendorNo, IRSReportingPeriod); + if PmtVendLedgEntry.FindSet() then + repeat + FilterApplicationDetailedVendorLedgerEntries(PmtDtldVendLedgEntry, PmtVendLedgEntry); + if PmtDtldVendLedgEntry.FindSet() then + repeat + FindRelatedApplicationDetailedVendorLedgerEntries(InvDtldVendLedgEntry, PmtVendLedgEntry, PmtDtldVendLedgEntry); + repeat + if TryCacheEntryNo(TempInteger, InvDtldVendLedgEntry."Entry No.") then + UpdateTempVendLedgEntryBuffer( + TempAppliedVendLedgEntry, TempIRS1099Form, InvDtldVendLedgEntry, PmtVendLedgEntry); + until InvDtldVendLedgEntry.Next() = 0; + until PmtDtldVendLedgEntry.Next() = 0; + until PmtVendLedgEntry.Next() = 0; + end; + + local procedure FilterPaymentVendorLedgerEntries(var VendLedgEntry: Record "Vendor Ledger Entry"; VendorNo: Code[20]; IRSReportingPeriod: Record "IRS Reporting Period") + begin + VendLedgEntry.SetCurrentKey("Document Type", "Vendor No.", "Posting Date"); + VendLedgEntry.SetLoadFields("Document Type", "Vendor No.", "Posting Date", "Closed by Entry No."); + VendLedgEntry.SetFilter("Document Type", '%1|%2', VendLedgEntry."Document Type"::Payment, VendLedgEntry."Document Type"::Refund); + VendLedgEntry.SetRange("Vendor No.", VendorNo); + VendLedgEntry.SetRange("Posting Date", IRSReportingPeriod."Starting Date", IRSReportingPeriod."Ending Date"); + end; + + local procedure FilterApplicationDetailedVendorLedgerEntries(var DtldVendLedgEntry: Record "Detailed Vendor Ledg. Entry"; VendLedgEntry: Record "Vendor Ledger Entry") + begin + DtldVendLedgEntry.SetCurrentKey("Vendor Ledger Entry No."); + DtldVendLedgEntry.SetLoadFields("Vendor Ledger Entry No.", "Entry Type", Unapplied, "Transaction No.", "Application No."); + DtldVendLedgEntry.SetRange("Vendor Ledger Entry No.", VendLedgEntry."Entry No."); + DtldVendLedgEntry.SetRange("Entry Type", DtldVendLedgEntry."Entry Type"::Application); + DtldVendLedgEntry.SetRange(Unapplied, false); + end; + + local procedure FindRelatedApplicationDetailedVendorLedgerEntries(var DtldVendLedgEntry: Record "Detailed Vendor Ledg. Entry"; VendLedgEntry: Record "Vendor Ledger Entry"; RelatedDtldVendLedgEntry: Record "Detailed Vendor Ledg. Entry") + begin + DtldVendLedgEntry.SetCurrentKey("Vendor Ledger Entry No.", "Entry Type"); + DtldVendLedgEntry.SetLoadFields("Vendor Ledger Entry No.", "Entry Type", "Vendor No.", "Transaction No.", "Application No.", Amount, "Amount (LCY)"); + DtldVendLedgEntry.SetFilter("Vendor Ledger Entry No.", '<>%1', VendLedgEntry."Entry No."); + DtldVendLedgEntry.SetRange("Entry Type", DtldVendLedgEntry."Entry Type"::Application); + DtldVendLedgEntry.SetRange("Vendor No.", VendLedgEntry."Vendor No."); + DtldVendLedgEntry.SetRange("Transaction No.", RelatedDtldVendLedgEntry."Transaction No."); + DtldVendLedgEntry.SetRange("Application No.", RelatedDtldVendLedgEntry."Application No."); + DtldVendLedgEntry.FindSet(); + end; + + local procedure UpdateTempVendLedgEntryBuffer(var TempAppliedVendLedgEntry: Record "Vendor Ledger Entry" temporary; var TempIRS1099Form: Record "IRS 1099 Form" temporary; InvDtldVendLedgEntry: Record "Detailed Vendor Ledg. Entry"; PmtVendLedgEntry: Record "Vendor Ledger Entry") + var + InvVendLedgEntry: Record "Vendor Ledger Entry"; + ClosingVendLedgEntry: Record "Vendor Ledger Entry"; + AmountToApply: Decimal; + begin + AmountToApply := -InvDtldVendLedgEntry."Amount (LCY)"; + InvVendLedgEntry.Get(InvDtldVendLedgEntry."Vendor Ledger Entry No."); + if not (InvVendLedgEntry."Document Type" in [InvVendLedgEntry."Document Type"::Invoice, InvVendLedgEntry."Document Type"::"Credit Memo"]) or + (InvVendLedgEntry."IRS 1099 Form No." = '') or + (InvVendLedgEntry."IRS 1099 Reporting Amount" = 0) or + (not InvVendLedgEntry."IRS 1099 Subject For Reporting") + then + exit; + + TempIRS1099Form.SetRange("No.", InvVendLedgEntry."IRS 1099 Form No."); + if not TempIRS1099Form.FindFirst() then + exit; + + TempAppliedVendLedgEntry := InvVendLedgEntry; + if TempAppliedVendLedgEntry.Find() then begin + TempAppliedVendLedgEntry."Amount to Apply" += AmountToApply; + TempAppliedVendLedgEntry.Modify(); + end else begin + TempAppliedVendLedgEntry := InvVendLedgEntry; + TempAppliedVendLedgEntry."Amount to Apply" := AmountToApply; + + if PmtVendLedgEntry."Closed by Entry No." <> 0 then begin + ClosingVendLedgEntry.Get(InvDtldVendLedgEntry."Vendor Ledger Entry No."); + if ClosingVendLedgEntry."Closed by Entry No." <> TempAppliedVendLedgEntry."Entry No." then + TempAppliedVendLedgEntry."Pmt. Disc. Rcd.(LCY)" := 0; + TempAppliedVendLedgEntry."Amount to Apply" += + GetPaymentDiscount(ClosingVendLedgEntry."Closed by Entry No."); + end; + TempAppliedVendLedgEntry.Insert(); + end; + end; + + local procedure TransferVengLedgEntryBufferToVendFormBoxBuffer(var TempVendFormBoxBuffer: Record "IRS 1099 Vend. Form Box Buffer" temporary; var TempAppliedVendLedgEntry: Record "Vendor Ledger Entry" temporary; var EntryNo: Integer; PeriodNo: Code[20]) + begin + if not TempAppliedVendLedgEntry.FindSet() then + exit; + repeat + if not FindVendFormBoxBuffer( + TempVendFormBoxBuffer, PeriodNo, TempAppliedVendLedgEntry."Vendor No.", TempAppliedVendLedgEntry."IRS 1099 Form No.", + TempAppliedVendLedgEntry."IRS 1099 Form Box No.") + then + InsertVendFormBoxBufferFromVendLedgEntry(TempVendFormBoxBuffer, EntryNo, TempAppliedVendLedgEntry, PeriodNo); + TempAppliedVendLedgEntry.CalcFields(Amount); + TempVendFormBoxBuffer.Amount += + -TempAppliedVendLedgEntry."Amount to Apply" * TempAppliedVendLedgEntry."IRS 1099 Reporting Amount" / TempAppliedVendLedgEntry.Amount; + TempVendFormBoxBuffer.Modify(); + if IRSFormsSetup."Collect Details For Line" then + InsertVendEntryIntoBuffer(TempVendFormBoxBuffer, EntryNo, TempAppliedVendLedgEntry."Entry No."); + until TempAppliedVendLedgEntry.Next() = 0; + end; + + local procedure AddAdjustmentsToVendFormBoxBuffer(var TempVendFormBoxBuffer: Record "IRS 1099 Vend. Form Box Buffer" temporary; var EntryNo: Integer; PeriodNo: Code[20]; VendorNo: Code[20]): Boolean + var + IRS1099VendorFormBoxAdj: Record "IRS 1099 Vendor Form Box Adj."; + begin + IRS1099VendorFormBoxAdj.SetRange("Period No.", PeriodNo); + IRS1099VendorFormBoxAdj.SetRange("Vendor No.", VendorNo); + if not IRS1099VendorFormBoxAdj.FindSet() then + exit(false); + repeat + TempVendFormBoxBuffer.Init(); + EntryNo += 1; + TempVendFormBoxBuffer."Entry No." := EntryNo; + TempVendFormBoxBuffer."Period No." := PeriodNo; + TempVendFormBoxBuffer."Vendor No." := IRS1099VendorFormBoxAdj."Vendor No."; + TempVendFormBoxBuffer."Form No." := IRS1099VendorFormBoxAdj."Form No."; + TempVendFormBoxBuffer."Form Box No." := IRS1099VendorFormBoxAdj."Form Box No."; + TempVendFormBoxBuffer.Insert(); + until IRS1099VendorFormBoxAdj.Next() = 0; + exit(true); + end; + + local procedure FinalizeVendFormBoxBuffer(var TempVendFormBoxBuffer: Record "IRS 1099 Vend. Form Box Buffer" temporary; var EntryNo: Integer; PeriodNo: Code[20]; VendorNo: Code[20]) + begin + TempVendFormBoxBuffer.Reset(); + TempVendFormBoxBuffer.SetRange("Vendor No.", VendorNo); + TempVendFormBoxBuffer.SetRange("Buffer Type", TempVendFormBoxBuffer."Buffer Type"::Amount); + TempVendFormBoxBuffer.SetAutoCalcFields("Adjustment Amount", "Minimum Reportable Amount"); + if not TempVendFormBoxBuffer.FindSet() then + if AddAdjustmentsToVendFormBoxBuffer(TempVendFormBoxBuffer, EntryNo, PeriodNo, VendorNo) then + TempVendFormBoxBuffer.FindSet() + else + exit; + + repeat + TempVendFormBoxBuffer."Reporting Amount" := TempVendFormBoxBuffer.Amount + TempVendFormBoxBuffer."Adjustment Amount"; + TempVendFormBoxBuffer."Include In 1099" := TempVendFormBoxBuffer."Reporting Amount" >= TempVendFormBoxBuffer."Minimum Reportable Amount"; + TempVendFormBoxBuffer.Modify(); + until TempVendFormBoxBuffer.Next() = 0; + end; + + local procedure FindVendFormBoxBuffer(var TempVendFormBoxBuffer: Record "IRS 1099 Vend. Form Box Buffer" temporary; PeriodNo: Code[20]; VendorNo: Code[20]; FormNo: Code[20]; FormBoxNo: Code[20]): Boolean + begin + TempVendFormBoxBuffer.SetRange("Period No.", PeriodNo); + TempVendFormBoxBuffer.SetRange("Vendor No.", VendorNo); + TempVendFormBoxBuffer.SetRange("Form No.", FormNo); + TempVendFormBoxBuffer.SetRange("Form Box No.", FormBoxNo); + exit(TempVendFormBoxBuffer.FindFirst()); + end; + + local procedure InsertVendFormBoxBufferFromVendLedgEntry(var VendFormBoxBuffer: Record "IRS 1099 Vend. Form Box Buffer" temporary; var EntryNo: Integer; VendLedgEntry: Record "Vendor Ledger Entry"; PeriodNo: Code[20]) + begin + VendFormBoxBuffer.Init(); + EntryNo += 1; + VendFormBoxBuffer."Entry No." := EntryNo; + VendFormBoxBuffer."Period No." := PeriodNo; + VendFormBoxBuffer."Vendor No." := VendLedgEntry."Vendor No."; + VendFormBoxBuffer."Form No." := VendLedgEntry."IRS 1099 Form No."; + VendFormBoxBuffer."Form Box No." := VendLedgEntry."IRS 1099 Form Box No."; + VendFormBoxBuffer.CalcFields("Adjustment Amount"); + VendFormBoxBuffer."Reporting Amount" += VendFormBoxBuffer."Adjustment Amount"; + VendFormBoxBuffer.Insert(); + end; + + local procedure TryCacheEntryNo(var TempInteger: Record "Integer" temporary; EntryNo: Integer): Boolean + begin + TempInteger.Number := EntryNo; + exit(TempInteger.Insert()); + end; + + local procedure GetPaymentDiscount(ClosingVendLedgEntryNo: Integer): Decimal + var + DtldVendLedgEntry: Record "Detailed Vendor Ledg. Entry"; + begin + DtldVendLedgEntry.SetCurrentKey("Vendor Ledger Entry No.", "Entry Type", "Posting Date"); + DtldVendLedgEntry.SetLoadFields("Vendor Ledger Entry No.", "Entry Type", Unapplied, Amount, "Amount (LCY)"); + DtldVendLedgEntry.SetRange("Vendor Ledger Entry No.", ClosingVendLedgEntryNo); + DtldVendLedgEntry.SetRange("Entry Type", DtldVendLedgEntry."Entry Type"::"Payment Discount"); + DtldVendLedgEntry.SetRange(Unapplied, false); + if DtldVendLedgEntry.FindFirst() then + exit(DtldVendLedgEntry."Amount (LCY)"); + end; + + local procedure InsertVendEntryIntoBuffer(var TempVendFormBoxBuffer: Record "IRS 1099 Vend. Form Box Buffer" temporary; var EntryNo: Integer; VendLedgEntryNo: Integer) + var + ParentEntryNo: Integer; + begin + ParentEntryNo := TempVendFormBoxBuffer."Entry No."; + EntryNo += 1; + TempVendFormBoxBuffer.Init(); + TempVendFormBoxBuffer."Entry No." := EntryNo; + TempVendFormBoxBuffer."Parent Entry No." := ParentEntryNo; + TempVendFormBoxBuffer."Buffer Type" := TempVendFormBoxBuffer."Buffer Type"::"Ledger Entry"; + TempVendFormBoxBuffer."Vendor Ledger Entry No." := VendLedgEntryNo; + TempVendFormBoxBuffer.Insert(); + end; +} diff --git a/Apps/US/IRSForms/app/src/VendorFormBox/IRS1099PropagateVendSetup.Report.al b/Apps/US/IRSForms/app/src/VendorFormBox/IRS1099PropagateVendSetup.Report.al new file mode 100644 index 0000000000..8adbe90950 --- /dev/null +++ b/Apps/US/IRSForms/app/src/VendorFormBox/IRS1099PropagateVendSetup.Report.al @@ -0,0 +1,144 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +using Microsoft.Purchases.Document; +using Microsoft.Purchases.Payables; + +report 10038 "IRS 1099 Propagate Vend. Setup" +{ + Caption = 'IRS 1099 Propagate Vendor Form Box Setup'; + ProcessingOnly = true; + ApplicationArea = BasicUS; + Permissions = TableData "Vendor Ledger Entry" = rm; + + dataset + { + dataitem(IRS1099VendorFormBoxSetup; "IRS 1099 Vendor Form Box Setup") + { + DataItemTableView = sorting("Period No.", "Vendor No."); + + trigger OnAfterGetRecord() + begin + if (StartingDate = 0D) or (EndingDate = 0D) then + Error(DatesMustBeSpecifiedErr); + if (not PurchaseDocuments) and (not VendorLedgerEntries) then + Error(OneOfTheReportOptionsMustBeSelectedErr); + if PurchaseDocuments then + UpdatePurchaseDocuments(); + if VendorLedgerEntries then + UpdateVendorLedgerEntries(); + end; + } + } + + requestpage + { + layout + { + area(content) + { + group(Options) + { + Caption = 'Options'; + field(StartingDateControl; StartingDate) + { + ApplicationArea = BasicUS; + Caption = 'Starting Date'; + ToolTip = 'Specifies the starting posting date of the vendor ledger entries to be included in propagation process.'; + + trigger OnValidate() + begin + if not (StartingDate in [IRSReportingPeriod."Starting Date" .. IRSReportingPeriod."Ending Date"]) then + error(DateMustBeInSelectedPeriodErr, IRSReportingPeriod.FieldCaption("Starting Date")); + end; + } + field(EndingDateControl; EndingDate) + { + ApplicationArea = BasicUS; + Caption = 'Ending Date'; + ToolTip = 'Specifies the ending posting date of the vendor ledger entries to be included in propagation process.'; + + trigger OnValidate() + begin + if not (EndingDate in [IRSReportingPeriod."Starting Date" .. IRSReportingPeriod."Ending Date"]) then + error(DateMustBeInSelectedPeriodErr, IRSReportingPeriod.FieldCaption("Ending Date")); + end; + } + field(PurchaseDocumentsControl; PurchaseDocuments) + { + ApplicationArea = BasicUS; + Caption = 'Purchase Documents'; + ToolTip = 'Specifies whether to include purchase documents in the propagation process.'; + } + field(VendorLedgerEntriesControl; VendorLedgerEntries) + { + ApplicationArea = BasicUS; + Caption = 'Vendor Ledger Entries'; + ToolTip = 'Specifies whether to include vendor ledger entries in the propagation process.'; + + } + } + } + } + + trigger OnOpenPage() + begin + if IRS1099VendorFormBoxSetup.GetFilter("Period No.") = '' then + error(PeriodMustBeSpecifiedErr); + IRSReportingPeriod.Get(IRS1099VendorFormBoxSetup.GetFilter("Period No.")); + StartingDate := IRSReportingPeriod."Starting Date"; + EndingDate := IRSReportingPeriod."Ending Date"; + end; + } + + var + IRSReportingPeriod: Record "IRS Reporting Period"; + StartingDate, EndingDate : Date; + PurchaseDocuments, VendorLedgerEntries : Boolean; + PeriodMustBeSpecifiedErr: Label 'Period No. must be specified.'; + DateMustBeInSelectedPeriodErr: Label '%1 must be within the selected reporting period.', Comment = '%1 = starting or ending date'; + DatesMustBeSpecifiedErr: Label 'Starting and Ending Date must be specified.'; + OneOfTheReportOptionsMustBeSelectedErr: Label 'At least Purchase Documents or Vendor Ledger Entries option must be selected.'; + + local procedure UpdatePurchaseDocuments() + var + PurchaseHeader: Record "Purchase Header"; + begin + PurchaseHeader.SetRange("Posting Date", StartingDate, EndingDate); + PurchaseHeader.SetRange("Buy-from Vendor No.", IRS1099VendorFormBoxSetup."Vendor No."); + PurchaseHeader.SetFilter( + "Document Type", '%1|%2|%3|%4', + PurchaseHeader."Document Type"::Order, PurchaseHeader."Document Type"::Invoice, + PurchaseHeader."Document Type"::"Credit Memo", PurchaseHeader."Document Type"::"Return Order"); + PurchaseHeader.SetRange(Status, PurchaseHeader.Status::Open); + if PurchaseHeader.FindSet(true) then + repeat + PurchaseHeader.Validate("IRS 1099 Reporting Period", IRS1099VendorFormBoxSetup."Period No."); + PurchaseHeader.Validate("IRS 1099 Form No.", IRS1099VendorFormBoxSetup."Form No."); + PurchaseHeader.Validate("IRS 1099 Form Box No.", IRS1099VendorFormBoxSetup."Form Box No."); + PurchaseHeader.Modify(true); + until PurchaseHeader.Next() = 0; + end; + + local procedure UpdateVendorLedgerEntries() + var + VendorLedgerEntry: Record "Vendor Ledger Entry"; + begin + VendorLedgerEntry.SetRange("Posting Date", StartingDate, EndingDate); + VendorLedgerEntry.SetRange("Vendor No.", IRS1099VendorFormBoxSetup."Vendor No."); + VendorLedgerEntry.SetFilter("Document Type", '%1|%2', VendorLedgerEntry."Document Type"::Invoice, VendorLedgerEntry."Document Type"::"Credit Memo"); + if VendorLedgerEntry.FindSet(true) then + repeat + VendorLedgerEntry.Validate("IRS 1099 Reporting Period", IRS1099VendorFormBoxSetup."Period No."); + VendorLedgerEntry.Validate("IRS 1099 Form No.", IRS1099VendorFormBoxSetup."Form No."); + VendorLedgerEntry.Validate("IRS 1099 Form Box No.", IRS1099VendorFormBoxSetup."Form Box No."); + VendorLedgerEntry.CalcFields(Amount); + VendorLedgerEntry.Validate("IRS 1099 Reporting Amount", VendorLedgerEntry.Amount); + VendorLedgerEntry.Modify(); + until VendorLedgerEntry.Next() = 0; + end; + +} diff --git a/Apps/US/IRSForms/app/src/VendorFormBox/IRS1099SuggestVendors.Report.al b/Apps/US/IRSForms/app/src/VendorFormBox/IRS1099SuggestVendors.Report.al new file mode 100644 index 0000000000..b7ce97116a --- /dev/null +++ b/Apps/US/IRSForms/app/src/VendorFormBox/IRS1099SuggestVendors.Report.al @@ -0,0 +1,41 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +using Microsoft.Purchases.Vendor; + +report 10036 "IRS 1099 Suggest Vendors" +{ + ProcessingOnly = true; + ApplicationArea = BasicUS; + + dataset + { + dataitem(Vendor; Vendor) + { + trigger OnAfterGetRecord() + var + IRS1099VendorFormBoxSetup: Record "IRS 1099 Vendor Form Box Setup"; + begin + IRS1099VendorFormBoxSetup.SetRange("Period No.", PeriodNo); + IRS1099VendorFormBoxSetup.SetRange("Vendor No.", Vendor."No."); + if not IRS1099VendorFormBoxSetup.FindFirst() then begin + IRS1099VendorFormBoxSetup.Init(); + IRS1099VendorFormBoxSetup.Validate("Period No.", PeriodNo); + IRS1099VendorFormBoxSetup.Validate("Vendor No.", Vendor."No."); + IRS1099VendorFormBoxSetup.Insert(true); + end; + end; + } + } + + var + PeriodNo: Code[20]; + + procedure InitializeRequest(NewPeriodNo: Code[20]) + begin + PeriodNo := NewPeriodNo; + end; +} diff --git a/Apps/US/IRSForms/app/src/VendorFormBox/IRS1099VendFormBoxAdjmts.Page.al b/Apps/US/IRSForms/app/src/VendorFormBox/IRS1099VendFormBoxAdjmts.Page.al new file mode 100644 index 0000000000..43d8940256 --- /dev/null +++ b/Apps/US/IRSForms/app/src/VendorFormBox/IRS1099VendFormBoxAdjmts.Page.al @@ -0,0 +1,69 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +page 10054 "IRS 1099 Vend. Form Box Adjmts" +{ + Caption = 'IRS 1099 Vendor Form Box Adjustments'; + PageType = List; + SourceTable = "IRS 1099 Vendor Form Box Adj."; + ApplicationArea = BasicUS; + UsageCategory = Administration; + DelayedInsert = true; + + layout + { + area(content) + { + repeater(Group) + { + field("Period No."; Rec."Period No.") + { + Tooltip = 'Specifies the period of the 1099 form box.'; + Visible = PeriodIsVisible; + } + field("Vendor No."; Rec."Vendor No.") + { + Tooltip = 'Specifies the vendor number.'; + Visible = VendorIsVisible; + } + field("Vendor Name"; Rec."Vendor Name") + { + ToolTip = 'Specifies the vendor name.'; + Visible = VendorIsVisible; + } + field("Form No."; Rec."Form No.") + { + Tooltip = 'Specifies the 1099 that box belongs to.'; + } + field("Form Box No."; Rec."Form Box No.") + { + Tooltip = 'Specifies the number of the 1099 form box.'; + } + field(Amount; Rec.Amount) + { + ToolTip = 'Specifies the adjustment amount for the 1099 form box that will be added to the amount from vendor ledger entries when the 1099 form document is generated.'; + } + } + } + } + + var + PeriodIsVisible: Boolean; + VendorIsVisible: Boolean; + + trigger OnOpenPage() + var +#if not CLEAN25 + IRSFormsFeature: Codeunit "IRS Forms Feature"; +#endif + begin + PeriodIsVisible := Rec.GetFilter("Period No.") = ''; + VendorIsVisible := Rec.GetFilter("Vendor No.") = ''; +#if not CLEAN25 + CurrPage.Editable := IRSFormsFeature.FeatureCanBeUsed(); +#endif + end; +} diff --git a/Apps/US/IRSForms/app/src/VendorFormBox/IRS1099VendFormBoxBuffer.Table.al b/Apps/US/IRSForms/app/src/VendorFormBox/IRS1099VendFormBoxBuffer.Table.al new file mode 100644 index 0000000000..724f901af4 --- /dev/null +++ b/Apps/US/IRSForms/app/src/VendorFormBox/IRS1099VendFormBoxBuffer.Table.al @@ -0,0 +1,77 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +table 10044 "IRS 1099 Vend. Form Box Buffer" +{ + DataClassification = CustomerContent; + TableType = Temporary; + + fields + { + field(1; "Entry No."; Integer) + { + AutoIncrement = true; + } + field(2; "Period No."; Code[20]) + { + } + field(3; "Vendor No."; Code[20]) + { + } + field(4; "Form No."; Code[20]) + { + } + field(5; "Form Box No."; Code[20]) + { + } + field(7; "Line No"; Integer) + { + + } + field(10; "Buffer Type"; Enum "IRS 1099 Form Box Buffer Type") + { + + } + field(11; Amount; Decimal) + { + } + field(12; "Adjustment Amount"; Decimal) + { + CalcFormula = lookup("IRS 1099 Vendor Form Box Adj.".Amount where("Period No." = field("Period No."), "Vendor No." = field("Vendor No."), "Form No." = field("Form No."), "Form Box No." = field("Form Box No."))); + FieldClass = FlowField; + } + field(13; "Minimum Reportable Amount"; Decimal) + { + FieldClass = FlowField; + CalcFormula = lookup("IRS 1099 Form Box"."Minimum Reportable Amount" where("Period No." = field("Period No."), "Form No." = field("Form No."), "No." = field("Form Box No."))); + Editable = false; + } + field(14; "Reporting Amount"; Decimal) + { + } + field(15; "Include In 1099"; Boolean) + { + } + field(16; "Parent Entry No."; Integer) + { + } + field(17; "Vendor Ledger Entry No."; Integer) + { + } + } + + keys + { + key(PK; "Entry No.") + { + Clustered = true; + } + key(ParentEntryNoBufferType; "Parent Entry No.", "Buffer Type") + { + + } + } +} diff --git a/Apps/US/IRSForms/app/src/VendorFormBox/IRS1099VendorFormBox.Codeunit.al b/Apps/US/IRSForms/app/src/VendorFormBox/IRS1099VendorFormBox.Codeunit.al new file mode 100644 index 0000000000..a3c613466b --- /dev/null +++ b/Apps/US/IRSForms/app/src/VendorFormBox/IRS1099VendorFormBox.Codeunit.al @@ -0,0 +1,27 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +codeunit 10037 "IRS 1099 Vendor Form Box" +{ + Access = Internal; + + procedure SuggestVendorsForFormBoxSetup(PeriodNo: Code[20]) + var + IRS1099SuggestVendorsReport: Report "IRS 1099 Suggest Vendors"; + begin + IRS1099SuggestVendorsReport.InitializeRequest(PeriodNo); + IRS1099SuggestVendorsReport.Run(); + end; + + procedure PropagateVendorFormBoxSetupToExistingEntries(IRS1099VendorFormBoxSetup: Record "IRS 1099 Vendor Form Box Setup") + var + IRS1099PropagateVendorSetup: Report "IRS 1099 Propagate Vend. Setup"; + begin + IRS1099VendorFormBoxSetup.SetRecFilter(); + IRS1099PropagateVendorSetup.SetTableView(IRS1099VendorFormBoxSetup); + IRS1099PropagateVendorSetup.Run(); + end; +} diff --git a/Apps/US/IRSForms/app/src/VendorFormBox/IRS1099VendorFormBoxAdj.Table.al b/Apps/US/IRSForms/app/src/VendorFormBox/IRS1099VendorFormBoxAdj.Table.al new file mode 100644 index 0000000000..66f690e0ad --- /dev/null +++ b/Apps/US/IRSForms/app/src/VendorFormBox/IRS1099VendorFormBoxAdj.Table.al @@ -0,0 +1,54 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +using Microsoft.Purchases.Vendor; + +table 10045 "IRS 1099 Vendor Form Box Adj." +{ + Caption = 'IRS 1099 Vendor Form Box Adjustment'; + DataClassification = CustomerContent; + DrillDownPageId = "IRS 1099 Vend. Form Box Adjmts"; + LookupPageId = "IRS 1099 Vend. Form Box Adjmts"; + + fields + { + field(1; "Period No."; Code[20]) + { + TableRelation = "IRS Reporting Period"; + } + field(2; "Vendor No."; Code[20]) + { + TableRelation = Vendor; + } + field(3; "Form No."; Code[20]) + { + TableRelation = "IRS 1099 Form"."No." where("Period No." = field("Period No.")); + NotBlank = true; + } + field(4; "Form Box No."; Code[20]) + { + TableRelation = "IRS 1099 Form Box"."No." where("Period No." = field("Period No."), "Form No." = field("Form No.")); + NotBlank = true; + } + field(10; Amount; Decimal) + { + } + field(100; "Vendor Name"; Text[100]) + { + CalcFormula = lookup(Vendor.Name where("No." = field("Vendor No."))); + FieldClass = FlowField; + Editable = false; + } + } + + keys + { + key(PK; "Period No.", "Vendor No.", "Form No.", "Form Box No.") + { + Clustered = true; + } + } +} diff --git a/Apps/US/IRSForms/app/src/VendorFormBox/IRS1099VendorFormBoxSetup.Page.al b/Apps/US/IRSForms/app/src/VendorFormBox/IRS1099VendorFormBoxSetup.Page.al new file mode 100644 index 0000000000..ec6f816219 --- /dev/null +++ b/Apps/US/IRSForms/app/src/VendorFormBox/IRS1099VendorFormBoxSetup.Page.al @@ -0,0 +1,121 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +page 10035 "IRS 1099 Vendor Form Box Setup" +{ + PageType = List; + SourceTable = "IRS 1099 Vendor Form Box Setup"; + ApplicationArea = BasicUS; + UsageCategory = Administration; + AboutTitle = 'About the setup of form boxes for vendors'; + AboutText = 'Here you can map the form boxes to vendor in the certain period. When you create a document for a certain vendor, the system will use this setup to fill in the form boxes.'; + DelayedInsert = true; + AnalysisModeEnabled = false; + + layout + { + area(content) + { + repeater(Group) + { + field("Period No."; Rec."Period No.") + { + Tooltip = 'Specifies the period of the 1099 form box.'; + Visible = PeriodIsVisible; + } + field("Vendor No."; Rec."Vendor No.") + { + Tooltip = 'Specifies the vendor number.'; + Visible = VendorIsVisible; + } + field("Vendor Name"; Rec."Vendor Name") + { + ToolTip = 'Specifies the vendor name.'; + Visible = VendorIsVisible; + } + field("Form No."; Rec."Form No.") + { + Tooltip = 'Specifies the 1099 that box belongs to.'; + } + field("Form Box No."; Rec."Form Box No.") + { + Tooltip = 'Specifies the number of the 1099 form box.'; + } + } + } + } + + actions + { + area(Processing) + { + action(SuggestVendors) + { + ApplicationArea = BasicUS; + Caption = 'Suggest'; + Image = Suggest; + ToolTip = 'Suggest vendors for the selected period'; + AboutTitle = 'About suggest vendors'; + AboutText = 'Here you can set filters for the vendors that will be suggested for the selected period instead of adding them manually one by one.'; + + trigger OnAction() + var + IRSReportingPeriod: Record "IRS Reporting Period"; + IRS1099VendorFormBox: Codeunit "IRS 1099 Vendor Form Box"; + PeriodFilter: Text; + begin + PeriodFilter := Rec.GetFilter("Period No."); + if IRSReportingPeriod.Get(PeriodFilter) then; + IRS1099VendorFormBox.SuggestVendorsForFormBoxSetup(IRSReportingPeriod."No."); + end; + } + action(Propagate) + { + ApplicationArea = BasicUS; + Caption = 'Propagate'; + Image = CopyBudget; + ToolTip = 'Propagate the vendor form box setup to the existing opened purchase documents vendor ledger entries.'; + AboutTitle = 'About propagate vendor setup'; + AboutText = 'Here you can propagete the new vendor form box setup to the existing opened purchase documents and vendor ledger entries instead of updating documents and entries manually one by one.'; + + trigger OnAction() + var + IRS1099VendorFormBox: Codeunit "IRS 1099 Vendor Form Box"; + begin + IRS1099VendorFormBox.PropagateVendorFormBoxSetupToExistingEntries(Rec); + end; + } + } + area(Promoted) + { + group(Category_Process) + { + Caption = 'Process'; + actionref(SuggestVendors_Promoted; SuggestVendors) + { + + } + } + } + } + + var + PeriodIsVisible: Boolean; + VendorIsVisible: Boolean; + + trigger OnOpenPage() + var +#if not CLEAN25 + IRSFormsFeature: Codeunit "IRS Forms Feature"; +#endif + begin + PeriodIsVisible := Rec.GetFilter("Period No.") = ''; + VendorIsVisible := Rec.GetFilter("Vendor No.") = ''; +#if not CLEAN25 + CurrPage.Editable := IRSFormsFeature.FeatureCanBeUsed(); +#endif + end; +} diff --git a/Apps/US/IRSForms/app/src/VendorFormBox/IRS1099VendorFormBoxSetup.Table.al b/Apps/US/IRSForms/app/src/VendorFormBox/IRS1099VendorFormBoxSetup.Table.al new file mode 100644 index 0000000000..c0396e5897 --- /dev/null +++ b/Apps/US/IRSForms/app/src/VendorFormBox/IRS1099VendorFormBoxSetup.Table.al @@ -0,0 +1,53 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +using Microsoft.Purchases.Vendor; + +table 10034 "IRS 1099 Vendor Form Box Setup" +{ + DataClassification = CustomerContent; + DrillDownPageId = "IRS 1099 Vendor Form Box Setup"; + LookupPageId = "IRS 1099 Vendor Form Box Setup"; + + fields + { + field(1; "Period No."; Code[20]) + { + TableRelation = "IRS Reporting Period"; + } + field(2; "Vendor No."; Code[20]) + { + TableRelation = Vendor; + } + field(3; "Form No."; Code[20]) + { + TableRelation = "IRS 1099 Form"."No." where("Period No." = field("Period No.")); + + trigger OnValidate() + begin + Validate("Form Box No.", ''); + end; + } + field(4; "Form Box No."; Code[20]) + { + TableRelation = "IRS 1099 Form Box"."No." where("Period No." = field("Period No."), "Form No." = field("Form No.")); + } + field(100; "Vendor Name"; Text[100]) + { + CalcFormula = lookup(Vendor.Name where("No." = field("Vendor No."))); + FieldClass = FlowField; + Editable = false; + } + } + + keys + { + key(PK; "Period No.", "Vendor No.") + { + Clustered = true; + } + } +} diff --git a/Apps/US/IRSForms/test library/ExtensionLogo.png b/Apps/US/IRSForms/test library/ExtensionLogo.png new file mode 100644 index 0000000000000000000000000000000000000000..4d2c9a626cb9617350617c40cd73904129d4c108 GIT binary patch literal 5446 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 literal 0 HcmV?d00001 diff --git a/Apps/US/IRSForms/test library/app.json b/Apps/US/IRSForms/test library/app.json new file mode 100644 index 0000000000..3095899662 --- /dev/null +++ b/Apps/US/IRSForms/test library/app.json @@ -0,0 +1,46 @@ +{ + "id": "dff12793-4e1c-4f3c-b7d3-331552c4cf5c", + "name": "IRS Forms Test Library", + "publisher": "Microsoft", + "brief": "The app is a library to test the IRS 1099 feature", + "description": "The app is a library to test the IRS 1099 feature", + "version": "25.0.0.0", + "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", + "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", + "help": "https://learn.microsoft.com/en-us/dynamics365/business-central/finance-how-setup-use-service-declaration", + "url": "https://go.microsoft.com/fwlink/?LinkId=724011", + "logo": "ExtensionLogo.png", + "contextSensitiveHelpUrl": "https://go.microsoft.com/fwlink/?linkid=2204541", + "dependencies": [ + { + "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", + "name": "Tests-TestLibraries", + "publisher": "Microsoft", + "version": "25.0.0.0" + }, + { + "id": "b696b4c9-637c-49d1-a806-763ff8f0a20e", + "name": "IRS Forms", + "publisher": "Microsoft", + "version": "25.0.0.0" + } + ], + "features": [ + "TranslationFile" + ], + "screenshots": [], + "platform": "25.0.0.0", + "idRanges": [ + { + "from": 148000, + "to": 148004 + } + ], + "resourceExposurePolicy": { + "allowDebugging": true, + "allowDownloadingSource": true, + "includeSourceInSymbolFile": true + }, + "application": "25.0.0.0", + "target": "OnPrem" +} \ No newline at end of file diff --git a/Apps/US/IRSForms/test library/src/IRSFormsEnableFeature.Codeunit.al b/Apps/US/IRSForms/test library/src/IRSFormsEnableFeature.Codeunit.al new file mode 100644 index 0000000000..36448a7335 --- /dev/null +++ b/Apps/US/IRSForms/test library/src/IRSFormsEnableFeature.Codeunit.al @@ -0,0 +1,21 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +#if not CLEAN25 +namespace Microsoft.Finance.VAT.Reporting; + +codeunit 148003 "IRS Forms Enable Feature" +{ + EventSubscriberInstance = Manual; + ObsoleteReason = 'Moved to IRS Forms App.'; + ObsoleteState = Pending; + ObsoleteTag = '25.0'; + + [EventSubscriber(ObjectType::Codeunit, Codeunit::"IRS Forms Feature", 'OnAfterCheckFeatureEnabled', '', false, false)] + local procedure EnableIRSFormsOnAfterCheckFeatureEnabled(var IsEnabled: Boolean) + begin + IsEnabled := true; + end; +} +#endif diff --git a/Apps/US/IRSForms/test library/src/LibraryIRS1099Document.Codeunit.al b/Apps/US/IRSForms/test library/src/LibraryIRS1099Document.Codeunit.al new file mode 100644 index 0000000000..026a01bedf --- /dev/null +++ b/Apps/US/IRSForms/test library/src/LibraryIRS1099Document.Codeunit.al @@ -0,0 +1,211 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +using Microsoft.Finance.GeneralLedger.Journal; +using Microsoft.Finance.ReceivablesPayables; +using Microsoft.Purchases.Document; +using Microsoft.Purchases.Payables; + +codeunit 148001 "Library IRS 1099 Document" +{ + var + LibraryUtility: Codeunit "Library - Utility"; + LibraryIRSReportingPeriod: Codeunit "Library IRS Reporting Period"; + Assert: Codeunit "Assert"; + LibraryJournals: Codeunit "Library - Journals"; + LibraryERM: Codeunit "Library - ERM"; + LibraryRandom: Codeunit "Library - Random"; + + procedure CreateFormDocuments(ReportingDate: Date) + begin + CreateFormDocuments(ReportingDate, ReportingDate, '', ''); + end; + + procedure CreateFormDocuments(StartingDate: Date; EndingDate: Date) + begin + CreateFormDocuments(StartingDate, EndingDate, '', ''); + end; + + procedure CreateFormDocuments(StartingDate: Date; EndingDate: Date; VendorNo: Code[20]) + begin + CreateFormDocuments(StartingDate, EndingDate, VendorNo, ''); + end; + + procedure CreateFormDocuments(StartingDate: Date; EndingDate: Date; VendorNo: Code[20]; FormNo: Code[20]) + begin + CreateFormDocuments(StartingDate, EndingDate, VendorNo, FormNo, false); + end; + + procedure CreateFormDocuments(StartingDate: Date; EndingDate: Date; VendorNo: Code[20]; FormNo: Code[20]; Replace: Boolean) + var + IRS1099CalcParameters: Record "IRS 1099 Calc. Params"; + IRS1099FormDocument: Codeunit "IRS 1099 Form Document"; + begin + IRS1099CalcParameters."Period No." := LibraryIRSReportingPeriod.GetReportingPeriod(StartingDate, EndingDate); + IRS1099CalcParameters."Vendor No." := VendorNo; + IRS1099CalcParameters."Form No." := FormNo; + IRS1099CalcParameters.Replace := Replace; + IRS1099FormDocument.CreateFormDocs(IRS1099CalcParameters); + end; + + procedure CreateFormDocuments(var TempVendFormBoxBuffer: Record "IRS 1099 Vend. Form Box Buffer" temporary); + var + DummyIRS1099CalcParameters: Record "IRS 1099 Calc. Params"; + begin + CreateFormDocuments(TempVendFormBoxBuffer, DummyIRS1099CalcParameters); + end; + + procedure CreateFormDocuments(var TempVendFormBoxBuffer: Record "IRS 1099 Vend. Form Box Buffer" temporary; IRS1099CalcParameters: Record "IRS 1099 Calc. Params"); + var + IRS1099FormDocImpl: Codeunit "IRS 1099 Form Docs Impl."; + begin + IRS1099FormDocImpl.CreateFormDocs(TempVendFormBoxBuffer, IRS1099CalcParameters); + end; + + procedure MockInvVendLedgEntry(var VendLedgEntry: Record "Vendor Ledger Entry"; StartingDate: Date; EndingDate: Date; VendorNo: Code[20]; FormNo: Code[20]; FormBoxNo: Code[20]): Integer + begin + MockVendLedgEntry(VendLedgEntry, "Gen. Journal Document Type"::Invoice, StartingDate, EndingDate, VendorNo, FormNo, FormBoxNo); + MockInitialDtldLedgEntry(VendLedgEntry."Entry No.", VendorNo, -LibraryRandom.RandDec(100, 2)); + end; + + procedure MockPmtVendLedgEntry(var VendLedgEntry: Record "Vendor Ledger Entry"; StartingDate: Date; EndingDate: Date; VendorNo: Code[20]; FormNo: Code[20]; FormBoxNo: Code[20]): Integer + begin + MockVendLedgEntry(VendLedgEntry, "Gen. Journal Document Type"::Payment, StartingDate, EndingDate, VendorNo, FormNo, FormBoxNo); + MockInitialDtldLedgEntry(VendLedgEntry."Entry No.", VendorNo, LibraryRandom.RandDec(100, 2)); + end; + + procedure MockVendLedgEntry(var VendLedgEntry: Record "Vendor Ledger Entry"; DocType: Enum "Gen. Journal Document Type"; StartingDate: Date; EndingDate: Date; VendorNo: Code[20]; FormNo: Code[20]; FormBoxNo: Code[20]): Integer + begin + VendLedgEntry."Entry No." := LibraryUtility.GetNewRecNo(VendLedgEntry, VendLedgEntry.FieldNo("Entry No.")); + VendLedgEntry."Document Type" := DocType; + VendLedgEntry."Vendor No." := VendorNo; + VendLedgEntry."Posting Date" := StartingDate; + VendLedgEntry.Insert(); + end; + + procedure MockVendLedgEntryWithIRSData(var VendorLedgerEntry: Record "Vendor Ledger Entry"; StartingDate: Date; EndingDate: Date; FormNo: Code[20]; FormBoxNo: Code[20]; Amount: Decimal) + begin + MockVendLedgEntryWithIRSDataCustom(VendorLedgerEntry, "Gen. Journal Document Type"::" ", StartingDate, EndingDate, FormNo, FormBoxNo, Amount); + end; + + procedure MockInvVendLedgEntryWithIRSData(var VendorLedgerEntry: Record "Vendor Ledger Entry"; StartingDate: Date; EndingDate: Date; FormNo: Code[20]; FormBoxNo: Code[20]; Amount: Decimal) + begin + MockVendLedgEntryWithIRSDataCustom(VendorLedgerEntry, "Gen. Journal Document Type"::Invoice, StartingDate, EndingDate, FormNo, FormBoxNo, Amount); + end; + + procedure MockCrMemoVendLedgEntryWithIRSData(var VendorLedgerEntry: Record "Vendor Ledger Entry"; StartingDate: Date; EndingDate: Date; FormNo: Code[20]; FormBoxNo: Code[20]; Amount: Decimal) + begin + MockVendLedgEntryWithIRSDataCustom(VendorLedgerEntry, "Gen. Journal Document Type"::"Credit Memo", StartingDate, EndingDate, FormNo, FormBoxNo, Amount); + end; + + procedure MockVendLedgEntryWithIRSDataCustom(var VendorLedgerEntry: Record "Vendor Ledger Entry"; DocType: Enum "Gen. Journal Document Type"; StartingDate: Date; EndingDate: Date; FormNo: Code[20]; FormBoxNo: Code[20]; Amount: Decimal) + begin + VendorLedgerEntry."Entry No." := LibraryUtility.GetNewRecNo(VendorLedgerEntry, VendorLedgerEntry.FieldNo("Entry No.")); + VendorLedgerEntry."Document Type" := DocType; + VendorLedgerEntry."IRS 1099 Subject For Reporting" := true; + VendorLedgerEntry."IRS 1099 Reporting Period" := LibraryIRSReportingPeriod.GetReportingPeriod(StartingDate, EndingDate); + VendorLedgerEntry."IRS 1099 Form No." := FormNo; + VendorLedgerEntry."IRS 1099 Form Box No." := FormBoxNo; + vendorLedgerEntry."IRS 1099 Reporting Amount" := Amount; + VendorLedgerEntry.Insert(); + MockInitialDtldLedgEntry(VendorLedgerEntry."Entry No.", '', Amount); + end; + + local procedure MockInitialDtldLedgEntry(VendorLedgerEntryNo: Integer; VendorNo: Code[20]; Amount: Decimal) + begin + MockDtldLedgEntry(VendorLedgerEntryNo, "Detailed CV Ledger Entry Type"::"Initial Entry", VendorNo, Amount); + end; + + local procedure MockDtldLedgEntry(VendorLedgerEntryNo: Integer; EntryType: Enum "Detailed CV Ledger Entry Type"; VendorNo: Code[20]; Amount: Decimal) + var + DetailedVendorLedgEntry: Record "Detailed Vendor Ledg. Entry"; + begin + DetailedVendorLedgEntry."Entry No." := LibraryUtility.GetNewRecNo(DetailedVendorLedgEntry, DetailedVendorLedgEntry.FieldNo("Entry No.")); + DetailedVendorLedgEntry."Vendor Ledger Entry No." := VendorLedgerEntryNo; + DetailedVendorLedgEntry."Ledger Entry Amount" := true; + DetailedVendorLedgEntry."Entry Type" := EntryType; + DetailedVendorLedgEntry."Vendor No." := VendorNo; + DetailedVendorLedgEntry.Amount := Amount; + DetailedVendorLedgEntry."Amount (LCY)" := Amount; + DetailedVendorLedgEntry.Insert(); + end; + + procedure PostPaymentAppliedToInvoice(VendNo: Code[20]; InvNo: Code[20]; Amount: Decimal) + begin + PostPaymentAppliedToInvoiceCustom( + WorkDate(), "Gen. Journal Document Type"::Payment, VendNo, "Gen. Journal Document Type"::Invoice, InvNo, Amount); + end; + + procedure PostPaymentAppliedToInvoice(PostingDate: Date; VendNo: Code[20]; InvNo: Code[20]; Amount: Decimal) + begin + PostPaymentAppliedToInvoiceCustom( + PostingDate, "Gen. Journal Document Type"::Payment, VendNo, "Gen. Journal Document Type"::Invoice, InvNo, Amount); + end; + + procedure PostRefundAppliedToCreditMemo(VendNo: Code[20]; CrMemoNo: Code[20]; Amount: Decimal) + begin + PostPaymentAppliedToInvoiceCustom( + WorkDate(), "Gen. Journal Document Type"::Refund, VendNo, "Gen. Journal Document Type"::"Credit Memo", CrMemoNo, Amount); + end; + + procedure PostRefundAppliedToCreditMemo(PostingDate: Date; VendNo: Code[20]; CrMemoNo: Code[20]; Amount: Decimal) + begin + PostPaymentAppliedToInvoiceCustom( + PostingDate, "Gen. Journal Document Type"::Refund, VendNo, "Gen. Journal Document Type"::"Credit Memo", CrMemoNo, Amount); + end; + + local procedure PostPaymentAppliedToInvoiceCustom(PostingDate: Date; DocType: Enum "Gen. Journal Document Type"; VendNo: Code[20]; AppliesToDocType: Enum "Gen. Journal Document Type"; AppliedToDocNo: Code[20]; Amount: Decimal) + var + GenJournalLine: Record "Gen. Journal Line"; + begin + LibraryJournals.CreateGenJournalLineWithBatch( + GenJournalLine, DocType, GenJournalLine."Account Type"::Vendor, VendNo, Amount); + GenJournalLine.Validate("Posting Date", PostingDate); + GenJournalLine.Validate("Applies-to Doc. Type", AppliesToDocType); + GenJournalLine.Validate("Applies-to Doc. No.", AppliedToDocNo); + GenJournalLine.Modify(true); + LibraryERM.PostGeneralJnlLine(GenJournalLine); + end; + + procedure VerifyIRS1099CodeInPurchaseHeader(PurchaseHeader: Record "Purchase Header"; FormNo: Code[20]; FormBoxNo: Code[20]) + begin + PurchaseHeader.TestField("IRS 1099 Reporting Period", LibraryIRSReportingPeriod.GetReportingPeriod(PurchaseHeader."Posting Date")); + PurchaseHeader.TestField("IRS 1099 Form No.", FormNo); + PurchaseHeader.TestField("IRS 1099 Form Box No.", FormBoxNo); + end; + + procedure VerifyIRSDataInVendorLedgerEntry(VendLedgEntry: Record "Vendor Ledger Entry"; StartingDate: Date; EndingDate: Date; FormNo: Code[20]; FormBoxNo: Code[20]; Amount: Decimal) + begin + VendLedgEntry.TestField("IRS 1099 Subject For Reporting", true); + //VendLedgEntry.TestField("IRS 1099 Reporting Period"); + VendLedgEntry.TestField("IRS 1099 Form No.", FormNo); + VendLedgEntry.TestField("IRS 1099 Form Box No.", FormBoxNo); + VendLedgEntry.TestField("IRS 1099 Reporting Amount", Amount); + end; + + procedure VerifyFormDocumentsCount(ExpectedCount: Integer) + var + IRS1099FormDocHeader: Record "IRS 1099 Form Doc. Header"; + begin + Assert.RecordCount(IRS1099FormDocHeader, ExpectedCount); + end; + + procedure VerifyNumberOfLinesInFormDocument(StartingDate: Date; EndingDate: Date; VendorNo: Code[20]; FormNo: Code[20]; ExpectedCount: Integer) + var + IRS1099FormDocHeader: Record "IRS 1099 Form Doc. Header"; + IRS1099FormDocLine: Record "IRS 1099 Form Doc. Line"; + begin + IRS1099FormDocHeader.SetRange("Period No.", LibraryIRSReportingPeriod.GetReportingPeriod(StartingDate, EndingDate)); + IRS1099FormDocHeader.SetRange("Vendor No.", VendorNo); + IRS1099FormDocHeader.SetRange("Form No.", FormNo); + IRS1099FormDocHeader.FindFirst(); + IRS1099FormDocLine.SetRange("Period No.", IRS1099FormDocHeader."Period No."); + IRS1099FormDocLine.SetRange("Vendor No.", IRS1099FormDocHeader."Vendor No."); + IRS1099FormDocLine.SetRange("Form No.", IRS1099FormDocHeader."Form No."); + Assert.RecordCount(IRS1099FormDocLine, ExpectedCount); + end; + +} diff --git a/Apps/US/IRSForms/test library/src/LibraryIRS1099FormBox.Codeunit.al b/Apps/US/IRSForms/test library/src/LibraryIRS1099FormBox.Codeunit.al new file mode 100644 index 0000000000..61e1b9f210 --- /dev/null +++ b/Apps/US/IRSForms/test library/src/LibraryIRS1099FormBox.Codeunit.al @@ -0,0 +1,182 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +using Microsoft.Purchases.Vendor; + +codeunit 148004 "Library IRS 1099 Form Box" +{ + var + LibraryPurchase: Codeunit "Library - Purchase"; + LibraryIRSReportingPeriod: Codeunit "Library IRS Reporting Period"; + LibraryUtility: Codeunit "Library - Utility"; + IRS1099VendorFormBox: Codeunit "IRS 1099 Vendor Form Box"; + LibraryRandom: Codeunit "Library - Random"; + Assert: Codeunit "Assert"; + + procedure CreateSingleFormInReportingPeriod(ReportingDate: Date): Code[20] + begin + exit(CreateSingleFormInReportingPeriod(ReportingDate, ReportingDate)); + end; + + procedure CreateSingleFormInReportingPeriod(StartingDate: Date; EndingDate: Date): Code[20] + var + IRS1099Form: Record "IRS 1099 Form"; + begin + IRS1099Form.Validate("Period No.", LibraryIRSReportingPeriod.GetReportingPeriod(StartingDate, EndingDate)); + IRS1099Form.Validate("No.", LibraryUtility.GenerateGUID()); + IRS1099Form.Insert(true); + exit(IRS1099Form."No."); + end; + + procedure CreateSingleFormBoxInReportingPeriod(ReportingDate: Date; FormNo: Code[20]): Code[20] + begin + exit(CreateSingleFormBoxInReportingPeriod(ReportingDate, ReportingDate, FormNo)); + end; + + procedure CreateSingleFormBoxInReportingPeriod(StartingDate: Date; EndingDate: Date; FormNo: Code[20]): Code[20] + var + IRS1099FormBox: Record "IRS 1099 Form Box"; + begin + IRS1099FormBox.Validate("Period No.", LibraryIRSReportingPeriod.GetReportingPeriod(StartingDate, EndingDate)); + IRS1099FormBox.Validate("Form No.", FormNo); + IRS1099FormBox.Validate("No.", LibraryUtility.GenerateGUID()); + IRS1099FormBox.Insert(true); + exit(IRS1099FormBox."No."); + end; + + procedure CreateVendorNoWithFormBox(ReportingDate: Date; FormNo: Code[20]; FormBoxNo: Code[20]): Code[20] + begin + exit(CreateVendorNoWithFormBox(ReportingDate, ReportingDate, FormNo, FormBoxNo)); + end; + + procedure CreateVendorNoWithFormBox(StartingDate: Date; EndingDate: Date; FormNo: Code[20]; FormBoxNo: Code[20]): Code[20] + var + Vendor: Record Vendor; + begin + LibraryPurchase.CreateVendor(Vendor); + AssignFormBoxForVendorInPeriod(Vendor."No.", StartingDate, EndingDate, FormNo, FormBoxNo); + exit(Vendor."No."); + end; + + procedure AddAdjustmentAmountForVendor(PostingDate: Date; VendorNo: Code[20]; FormNo: Code[20]; FormBoxNo: Code[20]; Amount: Decimal) + begin + AddAdjustmentAmountForVendor(PostingDate, PostingDate, VendorNo, FormNo, FormBoxNo, Amount); + end; + + procedure AddAdjustmentAmountForVendor(StartingDate: Date; EndingDate: Date; VendorNo: Code[20]; FormNo: Code[20]; FormBoxNo: Code[20]; Amount: Decimal) + var + IRS1099VendorFormBoxAdj: Record "IRS 1099 Vendor Form Box Adj."; + begin + IRS1099VendorFormBoxAdj.Validate("Period No.", LibraryIRSReportingPeriod.GetReportingPeriod(StartingDate, EndingDate)); + IRS1099VendorFormBoxAdj.Validate("Vendor No.", VendorNo); + IRS1099VendorFormBoxAdj.Validate("Form No.", FormNo); + IRS1099VendorFormBoxAdj.Validate("Form Box No.", FormBoxNo); + IRS1099VendorFormBoxAdj.Validate(Amount, Amount); + IRS1099VendorFormBoxAdj.Insert(true); + end; + + procedure GetVendorFormBoxAmount(var TempVendFormBoxBuffer: Record "IRS 1099 Vend. Form Box Buffer" temporary; PeriodNo: Code[20]; FormNo: Code[20]; VendorNo: Code[20]) + var + IRS1099CalcParameters: Record "IRS 1099 Calc. Params"; + IRSFormsFacade: Codeunit "IRS Forms Facade"; + begin + IRS1099CalcParameters."Period No." := PeriodNo; + IRS1099CalcParameters."Form No." := FormNo; + IRS1099CalcParameters."Vendor No." := VendorNo; + IRSFormsFacade.GetVendorFormBoxAmount(TempVendFormBoxBuffer, IRS1099CalcParameters); + end; + + procedure AssignFormBoxForVendorInPeriod(VendNo: Code[20]; StartingDate: Date; EndingDate: Date; FormNo: Code[20]; FormBoxNo: Code[20]) + var + IRS1099VendorFormBoxSetupRec: Record "IRS 1099 Vendor Form Box Setup"; + begin + IRS1099VendorFormBoxSetupRec.Validate("Period No.", LibraryIRSReportingPeriod.GetReportingPeriod(StartingDate, EndingDate)); + IRS1099VendorFormBoxSetupRec.Validate("Vendor No.", VendNo); + IRS1099VendorFormBoxSetupRec.Validate("Form No.", FormNo); + IRS1099VendorFormBoxSetupRec.Validate("Form Box No.", FormBoxNo); + IRS1099VendorFormBoxSetupRec.Insert(true); + end; + + procedure MockConnectedEntriesForVendFormBoxBuffer(var TempIRS1099VendFormBoxBuffer: Record "IRS 1099 Vend. Form Box Buffer" temporary) Result: List of [Integer] + begin + Result.Add(MockConnectedEntryForVendFormBoxBuffer(TempIRS1099VendFormBoxBuffer)); + Result.Add(MockConnectedEntryForVendFormBoxBuffer(TempIRS1099VendFormBoxBuffer)); + end; + + procedure MockConnectedEntryForVendFormBoxBuffer(var TempIRS1099VendFormBoxBuffer: Record "IRS 1099 Vend. Form Box Buffer" temporary) VendLedgEntryNo: Integer + var + CurrIRS1099VendFormBoxBuffer: Record "IRS 1099 Vend. Form Box Buffer"; + EntryNo: Integer; + begin + CurrIRS1099VendFormBoxBuffer.Copy(TempIRS1099VendFormBoxBuffer); + TempIRS1099VendFormBoxBuffer.Reset(); + if TempIRS1099VendFormBoxBuffer.FindLast() then + EntryNo := TempIRS1099VendFormBoxBuffer."Entry No."; + EntryNo += 1; + TempIRS1099VendFormBoxBuffer."Entry No." := EntryNo; + TempIRS1099VendFormBoxBuffer."Parent Entry No." := CurrIRS1099VendFormBoxBuffer."Entry No."; + TempIRS1099VendFormBoxBuffer."Buffer Type" := TempIRS1099VendFormBoxBuffer."Buffer Type"::"Ledger Entry"; + TempIRS1099VendFormBoxBuffer."Vendor Ledger Entry No." := LibraryRandom.RandInt(100); + TempIRS1099VendFormBoxBuffer.Insert(); + VendLedgEntryNo := TempIRS1099VendFormBoxBuffer."Vendor Ledger Entry No."; + TempIRS1099VendFormBoxBuffer.Copy(CurrIRS1099VendFormBoxBuffer); + exit(VendLedgEntryNo); + end; + + procedure SuggestVendorsForFormBoxSetup(StartingDate: Date; EndingDate: Date) + begin + IRS1099VendorFormBox.SuggestVendorsForFormBoxSetup(LibraryIRSReportingPeriod.GetReportingPeriod(StartingDate, EndingDate)); + end; + + procedure PropagateVendorFormBoxSetupToVendorLedgerEntries(StartingDate: Date; EndingDate: Date; VendorNo: Code[20]; FormNo: Code[20]; FormBoxNo: Code[20]) + var + IRS1099VendorFormBoxSetup: Record "IRS 1099 Vendor Form Box Setup"; + begin + IRS1099VendorFormBoxSetup.Get(LibraryIRSReportingPeriod.GetReportingPeriod(StartingDate, EndingDate), VendorNo); + IRS1099VendorFormBox.PropagateVendorFormBoxSetupToExistingEntries(IRS1099VendorFormBoxSetup); + end; + + procedure VerifyFormBoxSetupCountForVendors(StartingDate: Date; EndingDate: Date; ExpectedCount: Integer) + var + IRS1099VendorFormBoxSetup: Record "IRS 1099 Vendor Form Box Setup"; + begin + IRS1099VendorFormBoxSetup.SetRange("Period No.", LibraryIRSReportingPeriod.GetReportingPeriod(StartingDate, EndingDate)); + Assert.RecordCount(IRS1099VendorFormBoxSetup, ExpectedCount); + end; + + procedure VerifyCurrTempVendFormBoxBufferIncludedIn1099(var TempVendFormBoxBuffer: Record "IRS 1099 Vend. Form Box Buffer" temporary; PeriodNo: Code[20]; FormNo: Code[20]; FormBoxNo: Code[20]; VendorNo: Code[20]; ExpectedAmount: Decimal) + begin + VerifyCurrTempVendFormBoxBuffer(TempVendFormBoxBuffer, PeriodNo, FormNo, FormBoxNo, VendorNo, ExpectedAmount, ExpectedAmount, true); + end; + + procedure VerifyCurrTempVendFormBoxBuffer(var TempVendFormBoxBuffer: Record "IRS 1099 Vend. Form Box Buffer" temporary; PeriodNo: Code[20]; FormNo: Code[20]; FormBoxNo: Code[20]; VendorNo: Code[20]; ExpectedAmount: Decimal; IncludeIn1099: Boolean) + begin + VerifyCurrTempVendFormBoxBuffer(TempVendFormBoxBuffer, PeriodNo, FormNo, FormBoxNo, VendorNo, ExpectedAmount, ExpectedAmount, IncludeIn1099); + end; + + procedure VerifyCurrTempVendFormBoxBuffer(var TempVendFormBoxBuffer: Record "IRS 1099 Vend. Form Box Buffer" temporary; PeriodNo: Code[20]; FormNo: Code[20]; FormBoxNo: Code[20]; VendorNo: Code[20]; ExpectedAmount: Decimal; ExpectedReportingAmount: Decimal; IncludeIn1099: Boolean) + begin + TempVendFormBoxBuffer.SetRange("Period No.", PeriodNo); + TempVendFormBoxBuffer.SetRange("Form No.", FormNo); + TempVendFormBoxBuffer.SetRange("Form Box No.", FormBoxNo); + TempVendFormBoxBuffer.SetRange("Vendor No.", VendorNo); + TempVendFormBoxBuffer.FindFirst(); + Assert.RecordCount(TempVendFormBoxBuffer, 1); + TempVendFormBoxBuffer.TestField("Amount", ExpectedAmount); + TempVendFormBoxBuffer.TestField("Reporting Amount", ExpectedReportingAmount); + TempVendFormBoxBuffer.TestField("Include in 1099", IncludeIn1099); + TempVendFormBoxBuffer.Reset(); + end; + + procedure VerifyConnectedEntryInVendFormBoxBuffer(var TempVendFormBoxBuffer: Record "IRS 1099 Vend. Form Box Buffer" temporary; ExpectedEntryNo: Integer) + begin + TempVendFormBoxBuffer.SetRange("Parent Entry No.", TempVendFormBoxBuffer."Entry No."); + TempVendFormBoxBuffer.SetRange("Buffer Type", TempVendFormBoxBuffer."Buffer Type"::"Ledger Entry"); + TempVendFormBoxBuffer.FindFirst(); + TempVendFormBoxBuffer.TestField("Vendor Ledger Entry No.", ExpectedEntryNo); + TempVendFormBoxBuffer.Reset(); + end; +} diff --git a/Apps/US/IRSForms/test library/src/LibraryIRSReportingPeriod.Codeunit.al b/Apps/US/IRSForms/test library/src/LibraryIRSReportingPeriod.Codeunit.al new file mode 100644 index 0000000000..1619aa9eff --- /dev/null +++ b/Apps/US/IRSForms/test library/src/LibraryIRSReportingPeriod.Codeunit.al @@ -0,0 +1,46 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +codeunit 148000 "Library IRS Reporting Period" +{ + var + LibraryUtility: Codeunit "Library - Utility"; + + procedure CreateOneDayReportingPeriod(ReportingDate: Date): Code[20] + begin + exit(CreateReportingPeriod(ReportingDate, ReportingDate)); + end; + + procedure CreateReportingPeriod(StartingDate: Date; EndingDate: Date): Code[20] + var + IRSReportingPeriod: Record "IRS Reporting Period"; + begin + IRSReportingPeriod."No." := LibraryUtility.GenerateGUID(); + IRSReportingPeriod.Validate("Starting Date", StartingDate); + IRSReportingPeriod.Validate("Ending Date", EndingDate); + IRSReportingPeriod.Insert(true); + exit(IRSReportingPeriod."No."); + end; + + procedure GetReportingPeriod(PostingDate: Date): Code[20] + begin + exit(GetReportingPeriod(PostingDate, PostingDate)); + end; + + procedure GetReportingPeriod(StartingDate: Date; EndingDate: Date): Code[20] + var + IRSReportingPeriod: Codeunit "IRS Reporting Period"; + begin + exit(IRSReportingPeriod.GetReportingPeriod(StartingDate, EndingDate)); + end; + + procedure RemoveAllReportingPeriodsWithRelatedData() + var + IRSReportingPeriod: Record "IRS Reporting Period"; + begin + IRSReportingPeriod.DeleteAll(true); + end; +} diff --git a/Apps/US/IRSForms/test/ExtensionLogo.png b/Apps/US/IRSForms/test/ExtensionLogo.png new file mode 100644 index 0000000000000000000000000000000000000000..4d2c9a626cb9617350617c40cd73904129d4c108 GIT binary patch literal 5446 zcma)=S5VVywD$iAMIcgC2u+$uktV%J6$Dhev_NQrfC^Fsq!|cJ=^|Z`P&U*^N-uuwi#_w5i!*aB*89x5SkKKnv*ua91anhEW+omc005Zp+`e`1 zOsW4C1O3^nWxbYuCX9Z!?E(M*a`E2+jm<_J0|5K}om)4pLZ&wJ&3t(K(|ffcq#?ky z#^aeQO#|lO9vyUeb0ezqQtpipl3Sj#-xy!eh7lu@5+BnW zNhL-~3Zpw&1u=bMN*Q(sgYksq4dM>Iw7p&Qk_Su~b*PgEs#LK~^K}aDaTG_6Q?_tM<8wOS}`Z+?~Et8GB>T%(k7$9`DL!d5)f!ZoXco-vj+s_QLEs2cf zKM&F>#c9w|TmM9MFtl8L*cYQgl9khf5CYMR)DJOUf;M~a9|+ys@RYR zCusNC(CSlUk|r`qdS&ZKh$O=@#&e0>;W~S#|KjHdfLx!-J9r1JtP4RGIhS|Rm0eZ6 z7eOE~Zfo4Li~K^|&)d^-r?8Rh2Q}#ZjL=?VJZ7~hlp4(!U!0K%679I`OR&x54*0&4 znho|hKu)WR)4PUVA1}N;jXHg}AG+gSKQ6O_fEP^Y51!LwBERH09|t!GNx2KH4co>r zA%cgSHxh2Sezx-w!S5DTG#0zVCbnLM6BP}2P-G{8 zh**wJHj<652FS05bSQNx-0fS7^(wREYvZwpt;$!!k4H0U*iyhS8(syBDMv>L<)~LI zPl!Y^-cM{_J@{hY1=XJ#T=Ef(FD!I^r1^lca3c0ftVuvo-(%!Zn)C1bK{}-i*Jc); zIIc+o&iMgvboj&4`@5sF23MV!*zIVmA0>{1;*H*faMAG6EZ7XydTfaGyABAGx>)yl z@Y+|)SVxCx@!GWqspay7GBetK*s2@CJ?s{8v!(b|ShLb|O;3T1rAMB?DJ?Z`@013q zoyIvV84eYiS+?kRJOz`3AFcR~ZQ1Uq7wCnbSJ%-HZwhAnJ^4zDp2W8I)~WI7ush5> z&f3O)rj~2ZGr!c@=p3!n>jG-O#9`$7&WyF7bB}(rq4ldokUp5TY?E62r+YJbJp8Jf znDW3fYZ^nBQ9O}3?zH_*mZ9+G#HHnwop1Vfm!Df~{Z%D?5KzMN&RA>&#q8iCzTfAt zV#TyMeyyh8=M$8tyA|KeUwo_Q6Si)P)%n(W-*QE~08BG|>J!sQPq?IF;;%1ypP?Z` zK_0Un>p;9=9d675ELHboC0+fNMY&(;k(|=0TS>ka)BKI3q#)zx!Jp@zv0QfeEAjU< z=vI5@-d^A^-*#|P+b2QFiGxk4z<8Tp4p6{aOp88x>SQEa0M`VxX%IUb$bya!5EgRf6$fFw zp}jNTKUXjNe0x(;)Nu)Ij5K?QD0u6~mRHQ-!;6m#VP>)}=irAqy;f$e{W-EWnR75~ zm2b0u@r7ASk4x0oTqs9{f&F|eAmD*Gf^A;te7f}J{dXqLaH_4%D_(mnp0VmWhq>^E z&7>5*-mh>FX{w5SJf^#th&GrpOQk58U-+4 zq3$q~C4ySH7@lr>W+|c0`UF*ieC+3vC1$4m}F(ic|G7}QDt(t z7`#>$c4U-4LU_;nWHhdN9Fcv~L8h6M_}nW&EGTjgW(=c}uD9>eU^rDOrkNg_effOV z^8z_y=vNIt{`wOfgG2o^3ey`R!aP1=t7Mz@&MKK3>_BH_QkgNO@4IoQ-2d8EqsDg) zTMb-5lqlubRot-7!RD@+udO?O9_Da3XV5bvjW zXTb2psHUdeiIaI(lknQE_<+YlY31}R!VfoM_BuILQ{>Q89=LB5j;V|-yAW2gY82+~ zYlu~#*R(cHw2NO1h5xaiAD2oiIEQ-aQyA-D^y^z2ZHNfM{o(3M#SbqOP3>k9FOdDO z(t%c9hk)NCPe_8>=Y^U-_-6IwS-D0cE=pwdyLp!;r-fWiXtbUS$<dl!~WV$TR8 zP$KU?K>m?*O)mSGccn&kn|nj7NXFeo<0D=ue8s^~BK#P?J~gB}v5<0nK9GPipjT#9 zkm6yXFyLlgoUIDEVxw*0Z-WDqp8swCs(bcjAqdDLl1oUqYf#a`NjT6IO3?=P`FvUZ zlWC&lWb9_dexSz%N~-oscM`oC%b#KS|KS7AptwRX5h&1VDCKWzP{&??TFdF3h53&c zU(v)WhOr)#!V6Y6d7CzOO-@KF%@67>kh34@Exj7Rh}p5_0?yUeyC7@c7DHf+mW=~wpLeLYDA9#W-Ri*S|M@g zjPHH@qHrPuzq(+5y$V*UoFEg(g$$mRNUEF!C{IN3Rig{tU54W|OD_`M0G3u)B{WhC z*D?hTF7J+YdF8-Z-Uuw{3jBx`_!aus`uDDBecwuu&tsVpj2~DZJb2-!a2l??m{}er}lR6Lqu)-2+Vm)jr(g{nfQPx9-<^1d;k-d zkU{E^g7qwp+D`b+QtU5@+swaVKp9<`>sT~U)O!EEMBo!*)~s_<`6Yl z7fX2;ki>kVDfdietW1k;TYvaY({>?5X)&(d&_y<-J7Qa@b z(zwGCI=`P#^b>1>2#Y!9T5|AdtaU|zXxw9^KpIu6CAmQf$GzaeOJmYVsc3eh5%6lb z)t~(Ak2J`;KW_L6psME-h?xF6ryr4d{q;>-b`Q$L43T{r`{N?U6cqP(Q3f%kA8`c@ z<82KXjte|7u_Lo~MV!d%y$tYi(hzU$6t+*ml~Z&Mg{eK?@}^XEBK+-&j`Uv95x)=_ zZLs=Mpg_IuZenjm(~}b8Aggaaje8NX$A_7^G%-)!xtu)C{N|S<3hVOmU;{|i+q6zn zfr(1Ua*jF!%-dU3L}O2fvWAe%-4kxtXo_vJHF(AxSx)4AI8-$^uBQO_86Z_y%RZX4 zJpu5`pOAztxv?jXv9yx|r>#9!0|`71C-fli@v${6r+V$hgvcr|W_I`{=7*0s(PKQH zzn8r2+tSeD15stz|DIJ3%X%8EkyN?bsHhuq4(5D0Oewn_)-o)Nx$eNs{0V*ZTSVt4 z3ifXGGw5fBv+9b6d~Nl+08L4VbbZqf3DL^e?l@!uZVdWkdOpJPaE?{zF!ZI?c(vF3 zvX~OK4vktvm&R$MgNpiKA~&zT!1#H7!q1h7AQiuSNG9<=$64)Zym(UQ``(j#^hDzt}{aur0pS?mmBi&z4I0Jfieqh%Pa_A%N?_1OZHm-S{ zQ*)4(N_J;y7tRh0o>xs25-s9!M-)i;@I68#SGXB2XgS}N zx_r3%V)z1jLA_M&?)E^DT$kzdHMJF%e2w6BH@iI5tKWM+zcuhCsz@N0a_1RBvrdZx zjzD>V%;c4*$RkEv{zHuVyaB+ANl(iT8w{pJdziC7YcO2&(ciqGLhs@q-dNh! zkV_V_(_~$*>ND}j1yozMedYnu-_GKMh?IpP<@D+edeB4M%3@xr3oj{@mdFKoBVpm^)1_}Y^}rOWBSB|Uv)*-pTdiU ztW9~{qq5@iB+$QpbeJVKH^n^9vV})i>Z@2CHoY2$PC888c;#Yz-pHRK@EVheWhE!> zZzjPmy?0Ni8#=o_k6_s3DY7nS^&Bm}BW&ZfAuF7bQbDgAGM$dE)RM6RvdobKb&MhsYD4exRm9*jcHPjbz#rI?vj$u zPLF5Gjv|8}?ta9`&^H}Va3H;llghU-BC7pxo6?-eTP`7CUZHJrw{5 zhkDYeIYlhL%brQJ1X#<#fz#E}Z87Kj=Hde*f{l|A`9E my8jz0{9hgZgN;Rh%;ug!HJ{lE_@04L;EulOt!iDD=>G@$cU!Ii literal 0 HcmV?d00001 diff --git a/Apps/US/IRSForms/test/app.json b/Apps/US/IRSForms/test/app.json new file mode 100644 index 0000000000..8c33a4cbb3 --- /dev/null +++ b/Apps/US/IRSForms/test/app.json @@ -0,0 +1,63 @@ +{ + "id": "8d52df0b-add3-4e9b-aac5-f11107cba919", + "name": "IRS Forms Tests", + "publisher": "Microsoft", + "version": "25.0.0.0", + "brief": "Tests for the Enforced Digital Vouchers extension.", + "description": "Tests for the Enforced Digital Vouchers extension.", + "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", + "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", + "help": "https://go.microsoft.com/fwlink/?LinkId=724011", + "url": "https://go.microsoft.com/fwlink/?LinkId=724011", + "logo": "ExtensionLogo.png", + "platform": "25.0.0.0", + "application": "25.0.0.0", + "dependencies": [ + { + "id": "b696b4c9-637c-49d1-a806-763ff8f0a20e", + "name": "IRS Forms", + "publisher": "Microsoft", + "version": "25.0.0.0" + }, + { + "id": "dff12793-4e1c-4f3c-b7d3-331552c4cf5c", + "name": "IRS Forms Test Library", + "publisher": "Microsoft", + "version": "25.0.0.0" + }, + { + "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", + "name": "Tests-TestLibraries", + "publisher": "Microsoft", + "version": "25.0.0.0" + }, + { + "id": "9856ae4f-d1a7-46ef-89bb-6ef056398228", + "name": "System Application Test Library", + "publisher": "Microsoft", + "version": "25.0.0.0" + }, + { + "id": "5095f467-0a01-4b99-99d1-9ff1237d286f", + "publisher": "Microsoft", + "name": "Library Variable Storage", + "version": "25.0.0.0" + } + ], + "features": [ + "TranslationFile" + ], + "idRanges": [ + { + "from": 148010, + "to": 148019 + } + ], + "contextSensitiveHelpUrl": "https://go.microsoft.com/fwlink/?linkid=2141039", + "resourceExposurePolicy": { + "allowDebugging": false, + "allowDownloadingSource": true, + "includeSourceInSymbolFile": true + }, + "target": "OnPrem" +} \ No newline at end of file diff --git a/Apps/US/IRSForms/test/src/IRS1099DocumentTests.Codeunit.al b/Apps/US/IRSForms/test/src/IRS1099DocumentTests.Codeunit.al new file mode 100644 index 0000000000..24dc4464b0 --- /dev/null +++ b/Apps/US/IRSForms/test/src/IRS1099DocumentTests.Codeunit.al @@ -0,0 +1,394 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +using Microsoft.Purchases.Document; +using Microsoft.Purchases.Payables; + +codeunit 148010 "IRS 1099 Document Tests" +{ + Subtype = Test; + TestPermissions = Disabled; + EventSubscriberInstance = Manual; + + var + LibraryTestInitialize: Codeunit "Library - Test Initialize"; + LibraryPurchase: Codeunit "Library - Purchase"; + LibraryIRSReportingPeriod: Codeunit "Library IRS Reporting Period"; + LibraryIRS1099FormBox: Codeunit "Library IRS 1099 Form Box"; + LibraryIRS1099Document: Codeunit "Library IRS 1099 Document"; + LibraryUtility: Codeunit "Library - Utility"; + Assert: Codeunit "Assert"; + LibraryRandom: Codeunit "Library - Random"; + IsInitialized: Boolean; + CannotChangeFormBoxWithCalculatedAmountErr: Label 'You cannot change the Form Box No. for the line with calculated amount.'; + CannotCreateFormDocSamePeriodVendorFormErr: Label 'You cannot create multiple form documents with the same period, vendor and form.'; + CreateCreateFormDocLineSameFormBoxErr: Label 'You cannot create two form document lines with the same form box.'; + CannotChangeIRSDataInEntryConnectedToFormDocumentErr: Label 'You cannot change the IRS data in the vendor ledger entry connected to the form document. Period = %1, Vendor No. = %2, Form No. = %3', Comment = '%1 = Period No., %2 = Vendor No., %3 = Form No.'; + + + trigger OnRun() + begin + // [FEATURE] [1099] + end; + + [Test] + procedure IRS1099CodeSetsInPurchaseHeaderFromVendor() + var + PurchaseHeader: Record "Purchase Header"; +#if not CLEAN25 +#pragma warning disable AL0432 + IRSFormsEnableFeature: Codeunit "IRS Forms Enable Feature"; +#pragma warning restore AL0432 +#endif + VendNo: Code[20]; + FormNo: Code[20]; + FormBoxNo: Code[20]; + begin + // [SCENARIO 495389] IRS 1099 code is taken from the vendor when creating a purchase header + + Initialize(); +#if not CLEAN25 + BindSubscription(IRSFormsEnableFeature); +#endif + LibraryIRSReportingPeriod.CreateOneDayReportingPeriod(WorkDate()); + FormNo := + LibraryIRS1099FormBox.CreateSingleFormInReportingPeriod(WorkDate(), WorkDate()); + FormBoxNo := + LibraryIRS1099FormBox.CreateSingleFormBoxInReportingPeriod(WorkDate(), WorkDate(), FormNo); + VendNo := LibraryIRS1099FormBox.CreateVendorNoWithFormBox(WorkDate(), WorkDate(), FormNo, FormBoxNo); + LibraryPurchase.CreatePurchHeader(PurchaseHeader, PurchaseHeader."Document Type"::Invoice, VendNo); + LibraryIRS1099Document.VerifyIRS1099CodeInPurchaseHeader(PurchaseHeader, FormNo, FormBoxNo); +#if not CLEAN25 + UnbindSubscription(IRSFormsEnableFeature); +#endif + end; + + [Test] + procedure IRS1099CodeInPurchaseHeaderWhenChangePostingDate() + var + PurchaseHeader: Record "Purchase Header"; +#if not CLEAN25 +#pragma warning disable AL0432 + IRSFormsEnableFeature: Codeunit "IRS Forms Enable Feature"; +#pragma warning restore AL0432 +#endif + VendNo: Code[20]; + FormNo: Code[20]; + FormBoxNo: Code[20]; + ReportingDate: Date; + begin + // [SCENARIO 495389] IRS 1099 code changes when change the posting date of the purchase header + + Initialize(); +#if not CLEAN25 + BindSubscription(IRSFormsEnableFeature); +#endif + ReportingDate := CalcDate('<1Y>', WorkDate()); + LibraryIRSReportingPeriod.CreateOneDayReportingPeriod(ReportingDate); + FormNo := + LibraryIRS1099FormBox.CreateSingleFormInReportingPeriod(ReportingDate, ReportingDate); + FormBoxNo := + LibraryIRS1099FormBox.CreateSingleFormBoxInReportingPeriod(ReportingDate, ReportingDate, FormNo); + VendNo := LibraryIRS1099FormBox.CreateVendorNoWithFormBox(ReportingDate, ReportingDate, FormNo, FormBoxNo); + LibraryPurchase.CreatePurchHeader(PurchaseHeader, PurchaseHeader."Document Type"::Invoice, VendNo); + // [WHEN] + PurchaseHeader.Validate("Posting Date", ReportingDate); + // [THEN] + LibraryIRS1099Document.VerifyIRS1099CodeInPurchaseHeader(PurchaseHeader, FormNo, FormBoxNo); +#if not CLEAN25 + UnbindSubscription(IRSFormsEnableFeature); +#endif + end; + + [Test] + procedure CreateFormDocumentSamePeriodVendorAndForm() + var + TempIRS1099VendFormBoxBuffer: Record "IRS 1099 Vend. Form Box Buffer" temporary; + IRS1099FormDocHeader: Record "IRS 1099 Form Doc. Header"; + IRS1099FormDocLine: Record "IRS 1099 Form Doc. Line"; + IRS1099FormDocLineDetail: Record "IRS 1099 Form Doc. Line Detail"; +#if not CLEAN25 +#pragma warning disable AL0432 + IRSFormsEnableFeature: Codeunit "IRS Forms Enable Feature"; +#pragma warning restore AL0432 +#endif + EntryNo: Integer; + begin + // [SCENARIO 495389] Create a single form document with the same period, vendor and form + + Initialize(); +#if not CLEAN25 + BindSubscription(IRSFormsEnableFeature); +#endif + // [GIVEN] Vendor form box buffer with "Period No." = "X", "Vendor No." = "Y", "Form No." = "MISC", "Form Box No." = "MISC-01" + TempIRS1099VendFormBoxBuffer."Period No." := LibraryUtility.GenerateGUID(); + TempIRS1099VendFormBoxBuffer."Vendor No." := LibraryPurchase.CreateVendorNo(); + TempIRS1099VendFormBoxBuffer."Form No." := LibraryUtility.GenerateGUID(); + TempIRS1099VendFormBoxBuffer."Form Box No." := LibraryUtility.GenerateGUID(); + TempIRS1099VendFormBoxBuffer.Amount := LibraryRandom.RandDec(100, 2); + TempIRS1099VendFormBoxBuffer."Reporting Amount" := LibraryRandom.RandDec(100, 2); + TempIRS1099VendFormBoxBuffer."Include In 1099" := true; + EntryNo := LibraryIRS1099FormBox.MockConnectedEntryForVendFormBoxBuffer(TempIRS1099VendFormBoxBuffer); + TempIRS1099VendFormBoxBuffer.Insert(true); + + // [WHEN] Create form documents from the vendor form box buffer + LibraryIRS1099Document.CreateFormDocuments(TempIRS1099VendFormBoxBuffer); + + // [THEN] A single form document is created with "Period No." = "X", "Vendor No." = "Y", "Form No." = "MISC" + Assert.RecordCount(IRS1099FormDocHeader, 1); + IRS1099FormDocHeader.FindFirst(); + IRS1099FormDocHeader.TestField("Period No.", TempIRS1099VendFormBoxBuffer."Period No."); + IRS1099FormDocHeader.TestField("Vendor No.", TempIRS1099VendFormBoxBuffer."Vendor No."); + IRS1099FormDocHeader.TestField("Form No.", TempIRS1099VendFormBoxBuffer."Form No."); + Assert.RecordCount(IRS1099FormDocLine, 1); + // [THEN] A single form document line is created with the same period, vendor and form + IRS1099FormDocLine.SetRange("Document ID", IRS1099FormDocHeader.ID); + IRS1099FormDocLine.FindFirst(); + IRS1099FormDocLine.TestField(Amount, TempIRS1099VendFormBoxBuffer."Reporting Amount"); + IRS1099FormDocLine.TestField("Include In 1099", TempIRS1099VendFormBoxBuffer."Include In 1099"); + IRS1099FormDocLineDetail.Get(IRS1099FormDocLine."Document ID", IRS1099FormDocLine."Line No.", EntryNo); + +#if not CLEAN25 + UnbindSubscription(IRSFormsEnableFeature); +#endif + end; + + [Test] + procedure CreateMultipleFormDocumentsSamePeriodVendorForm() + var + IRS1099FormDocHeader: Record "IRS 1099 Form Doc. Header"; + NewIRS1099FormDocHeader: Record "IRS 1099 Form Doc. Header"; + begin + // [SCENARIO 495389] Stan cannot create multiple form documents with the same period, vendor and form + + Initialize(); + IRS1099FormDocHeader.Validate("Period No.", LibraryIRSReportingPeriod.CreateOneDayReportingPeriod(WorkDate())); + IRS1099FormDocHeader.Validate("Vendor No.", LibraryPurchase.CreateVendorNo()); + IRS1099FormDocHeader.Validate("Form No.", LibraryIRS1099FormBox.CreateSingleFormInReportingPeriod(WorkDate())); + IRS1099FormDocHeader.Insert(true); + NewIRS1099FormDocHeader.Validate("Period No.", IRS1099FormDocHeader."Period No."); + NewIRS1099FormDocHeader.Validate("Vendor No.", IRS1099FormDocHeader."Vendor No."); + asserterror NewIRS1099FormDocHeader.Validate("Form No.", IRS1099FormDocHeader."Form No."); + Assert.ExpectedError(CannotCreateFormDocSamePeriodVendorFormErr); + end; + + [Test] + procedure CreateFormDocumentSameFormBoxes() + var + IRS1099FormDocHeader: Record "IRS 1099 Form Doc. Header"; + IRS1099FormDocLine: Record "IRS 1099 Form Doc. Line"; + NewIRS1099FormDocLine: Record "IRS 1099 Form Doc. Line"; + begin + // [SCENARIO 495389] Stan cannot create the form document with the same form boxes + + Initialize(); + IRS1099FormDocHeader.Validate("Period No.", LibraryIRSReportingPeriod.CreateOneDayReportingPeriod(WorkDate())); + IRS1099FormDocHeader.Validate("Vendor No.", LibraryPurchase.CreateVendorNo()); + IRS1099FormDocHeader.Validate("Form No.", LibraryIRS1099FormBox.CreateSingleFormInReportingPeriod(WorkDate())); + IRS1099FormDocHeader.Insert(true); + IRS1099FormDocLine.Validate("Document ID", IRS1099FormDocHeader.ID); + IRS1099FormDocLine.Validate("Line No.", 10000); + IRS1099FormDocLine.Validate("Period No.", IRS1099FormDocHeader."Period No."); + IRS1099FormDocLine.Validate("Vendor No.", IRS1099FormDocHeader."Vendor No."); + IRS1099FormDocLine.Validate("Form No.", IRS1099FormDocHeader."Form No."); + IRS1099FormDocLine.Validate( + "Form Box No.", + LibraryIRS1099FormBox.CreateSingleFormBoxInReportingPeriod(WorkDate(), IRS1099FormDocHeader."Form No.")); + IRS1099FormDocLine.Insert(true); + NewIRS1099FormDocLine.Validate("Document ID", IRS1099FormDocHeader.ID); + NewIRS1099FormDocLine.Validate("Period No.", IRS1099FormDocHeader."Period No."); + NewIRS1099FormDocLine.Validate("Vendor No.", IRS1099FormDocHeader."Vendor No."); + NewIRS1099FormDocLine.Validate("Form No.", IRS1099FormDocHeader."Form No."); + asserterror NewIRS1099FormDocLine.Validate("Form Box No.", IRS1099FormDocLine."Form Box No."); + Assert.ExpectedError(CreateCreateFormDocLineSameFormBoxErr); + end; + + [Test] + procedure CreateFormDocumentSamePeriodVendorAndFormMultipleConnectedEntries() + var + TempIRS1099VendFormBoxBuffer: Record "IRS 1099 Vend. Form Box Buffer" temporary; +#if not CLEAN25 +#pragma warning disable AL0432 + IRSFormsEnableFeature: Codeunit "IRS Forms Enable Feature"; +#pragma warning restore AL0432 +#endif + begin + // [SCENARIO 495389] Create a single form document with the same period, vendor and form and multiple connected entries + + Initialize(); +#if not CLEAN25 + BindSubscription(IRSFormsEnableFeature); +#endif + TempIRS1099VendFormBoxBuffer."Period No." := LibraryUtility.GenerateGUID(); + TempIRS1099VendFormBoxBuffer."Vendor No." := LibraryUtility.GenerateGUID(); + TempIRS1099VendFormBoxBuffer."Form No." := LibraryUtility.GenerateGUID(); + TempIRS1099VendFormBoxBuffer."Form Box No." := LibraryUtility.GenerateGUID(); + TempIRS1099VendFormBoxBuffer.Amount := LibraryRandom.RandDec(100, 2); + TempIRS1099VendFormBoxBuffer."Reporting Amount" := LibraryRandom.RandDec(100, 2); + TempIRS1099VendFormBoxBuffer."Include In 1099" := true; + TempIRS1099VendFormBoxBuffer.Insert(true); +#if not CLEAN25 + UnbindSubscription(IRSFormsEnableFeature); +#endif + end; + + [Test] + procedure ChangeFormBoxInLineWithNonZeroCalculatedAmount() + var + IRS1099FormDocLine: Record "IRS 1099 Form Doc. Line"; +#if not CLEAN25 +#pragma warning disable AL0432 + IRSFormsEnableFeature: Codeunit "IRS Forms Enable Feature"; +#pragma warning restore AL0432 +#endif + PeriodNo, FormNo : Code[20]; + FormBoxNo: array[2] of Code[20]; + begin + // [SCENARIO 495389] Stan cannot change the Form Box No. in the form document line with non-zero calculated amount + + Initialize(); +#if not CLEAN25 + BindSubscription(IRSFormsEnableFeature); +#endif + + PeriodNo := LibraryIRSReportingPeriod.CreateOneDayReportingPeriod(WorkDate()); + FormNo := + LibraryIRS1099FormBox.CreateSingleFormInReportingPeriod(WorkDate(), WorkDate()); + FormBoxNo[1] := + LibraryIRS1099FormBox.CreateSingleFormBoxInReportingPeriod(WorkDate(), WorkDate(), FormNo); + + IRS1099FormDocLine."Period No." := PeriodNo; + IRS1099FormDocLine."Form No." := FormNo; + IRS1099FormDocLine."Form Box No." := FormBoxNo[1]; + IRS1099FormDocLine."Calculated Amount" := 1; + + FormBoxNo[2] := + LibraryIRS1099FormBox.CreateSingleFormBoxInReportingPeriod(WorkDate(), WorkDate(), FormNo); + // [WHEN] + asserterror IRS1099FormDocLine.Validate("Form Box No.", FormBoxNo[2]); + + // [THEN] + Assert.ExpectedError(CannotChangeFormBoxWithCalculatedAmountErr); + +#if not CLEAN25 + UnbindSubscription(IRSFormsEnableFeature); +#endif + end; + + [Test] + procedure ChangeFormBoxInLineWithZeroCalculatedAmount() + var + IRS1099FormDocLine: Record "IRS 1099 Form Doc. Line"; +#if not CLEAN25 +#pragma warning disable AL0432 + IRSFormsEnableFeature: Codeunit "IRS Forms Enable Feature"; +#pragma warning restore AL0432 +#endif + PeriodNo, FormNo : Code[20]; + FormBoxNo: array[2] of Code[20]; + begin + // [SCENARIO 495389] Stan can change the Form Box No. in the form document line with non-zero calculated amount + + Initialize(); +#if not CLEAN25 + BindSubscription(IRSFormsEnableFeature); +#endif + + PeriodNo := LibraryIRSReportingPeriod.CreateOneDayReportingPeriod(WorkDate()); + FormNo := + LibraryIRS1099FormBox.CreateSingleFormInReportingPeriod(WorkDate(), WorkDate()); + FormBoxNo[1] := + LibraryIRS1099FormBox.CreateSingleFormBoxInReportingPeriod(WorkDate(), WorkDate(), FormNo); + + IRS1099FormDocLine."Period No." := PeriodNo; + IRS1099FormDocLine."Form No." := FormNo; + IRS1099FormDocLine."Form Box No." := FormBoxNo[1]; + IRS1099FormDocLine."Calculated Amount" := 0; + IRS1099FormDocLine.Amount := 1; + + FormBoxNo[2] := + LibraryIRS1099FormBox.CreateSingleFormBoxInReportingPeriod(WorkDate(), WorkDate(), FormNo); + // [WHEN] + IRS1099FormDocLine.Validate("Form Box No.", FormBoxNo[2]); + + // [THEN] + IRS1099FormDocLine.TestField(Amount, 0); + +#if not CLEAN25 + UnbindSubscription(IRSFormsEnableFeature); +#endif + end; + + [Test] + procedure ChangeIRSDataInVendorLedgerEntryConnectedToFormDocument() + var + VendorLedgEntry: Record "Vendor Ledger Entry"; + IRS1099FormDocHeader: Record "IRS 1099 Form Doc. Header"; + IRS1099FormDocLine: Record "IRS 1099 Form Doc. Line"; + IRS1099FormDocLineDetail: Record "IRS 1099 Form Doc. Line Detail"; +#if not CLEAN25 +#pragma warning disable AL0432 + IRSFormsEnableFeature: Codeunit "IRS Forms Enable Feature"; +#pragma warning restore AL0432 +#endif + PeriodNo, FormNo, VendNo, FormBoxNo : Code[20]; + begin + // [SCENARIO 495389] Stan cannot change the IRS data in the vendor ledger entry connected to the form document + + Initialize(); +#if not CLEAN25 + BindSubscription(IRSFormsEnableFeature); +#endif + + PeriodNo := LibraryIRSReportingPeriod.CreateOneDayReportingPeriod(WorkDate()); + FormNo := + LibraryIRS1099FormBox.CreateSingleFormInReportingPeriod(WorkDate()); + FormBoxNo := + LibraryIRS1099FormBox.CreateSingleFormBoxInReportingPeriod(WorkDate(), FormNo); + VendNo := LibraryIRS1099FormBox.CreateVendorNoWithFormBox(WorkDate(), FormNo, FormBoxNo); + VendorLedgEntry."Entry No." := LibraryUtility.GetNewRecNo(VendorLedgEntry, VendorLedgEntry.FieldNo("Entry No.")); + VendorLedgEntry.Insert(); + + IRS1099FormDocHeader."Period No." := PeriodNo; + IRS1099FormDocHeader."Vendor No." := VendNo; + IRS1099FormDocHeader."Form No." := FormNo; + IRS1099FormDocHeader.Insert(); + IRS1099FormDocLine."Document ID" := IRS1099FormDocHeader.ID; + IRS1099FormDocLine.Insert(); + IRS1099FormDocLineDetail."Document ID" := IRS1099FormDocLine."Document ID"; + IRS1099FormDocLineDetail."Vendor Ledger Entry No." := VendorLedgEntry."Entry No."; + IRS1099FormDocLineDetail.Insert(); + Commit(); + + asserterror VendorLedgEntry.Validate("IRS 1099 Form No."); + Assert.ExpectedError(StrSubstNo(CannotChangeIRSDataInEntryConnectedToFormDocumentErr, PeriodNo, VendNo, FormNo)); + asserterror VendorLedgEntry.Validate("IRS 1099 Form Box No."); + Assert.ExpectedError(StrSubstNo(CannotChangeIRSDataInEntryConnectedToFormDocumentErr, PeriodNo, VendNo, FormNo)); + asserterror VendorLedgEntry.Validate("IRS 1099 Reporting Amount"); + Assert.ExpectedError(StrSubstNo(CannotChangeIRSDataInEntryConnectedToFormDocumentErr, PeriodNo, VendNo, FormNo)); + + // Tear down + IRS1099FormDocHeader.Delete(true); + +#if not CLEAN25 + UnbindSubscription(IRSFormsEnableFeature); +#endif + end; + + local procedure Initialize() + var + IRSReportingPeriod: Record "IRS Reporting Period"; + begin + IRSReportingPeriod.DeleteAll(true); + LibraryTestInitialize.OnTestInitialize(Codeunit::"IRS 1099 Document Tests"); + if IsInitialized then + exit; + LibraryTestInitialize.OnBeforeTestSuiteInitialize(Codeunit::"IRS 1099 Document Tests"); + + IsInitialized := true; + LibraryTestInitialize.OnAfterTestSuiteInitialize(Codeunit::"IRS 1099 Document Tests"); + end; +} diff --git a/Apps/US/IRSForms/test/src/IRS1099E2ETests.Codeunit.al b/Apps/US/IRSForms/test/src/IRS1099E2ETests.Codeunit.al new file mode 100644 index 0000000000..6083b4372f --- /dev/null +++ b/Apps/US/IRSForms/test/src/IRS1099E2ETests.Codeunit.al @@ -0,0 +1,142 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +using Microsoft.Purchases.Document; +using Microsoft.Purchases.Payables; + +codeunit 148015 "IRS 1099 E2E Tests" +{ + Subtype = Test; + TestPermissions = Disabled; + EventSubscriberInstance = Manual; + + var + LibraryTestInitialize: Codeunit "Library - Test Initialize"; + LibraryIRSReportingPeriod: Codeunit "Library IRS Reporting Period"; + LibraryIRS1099FormBox: Codeunit "Library IRS 1099 Form Box"; + LibraryIRS1099Document: Codeunit "Library IRS 1099 Document"; + LibraryPurchase: Codeunit "Library - Purchase"; + LibraryERM: Codeunit "Library - ERM"; + Assert: Codeunit Assert; + IsInitialized: Boolean; + + trigger OnRun() + begin + // [FEATURE] [1099] [UT] + end; + + [Test] + [HandlerFunctions('IRS1099CreateFormDocsRequestPageHandler')] + procedure MultipleFormsMultipleVendors() + var + PurchaseHeader: Record "Purchase Header"; + VendorLedgerEntry: Record "Vendor Ledger Entry"; + IRS1099FormDocHeader: Record "IRS 1099 Form Doc. Header"; + IRS1099FormDocLine: Record "IRS 1099 Form Doc. Line"; + IRS1099FormDocLineDetail: Record "IRS 1099 Form Doc. Line Detail"; + IRS1099CreateFormDocsReport: Report "IRS 1099 Create Form Docs"; +#if not CLEAN25 +#pragma warning disable AL0432 + IRSFormsEnableFeature: Codeunit "IRS Forms Enable Feature"; +#pragma warning restore AL0432 +#endif + PeriodNo: Code[20]; + FormNo: array[2] of Code[20]; + FormBoxNo: array[2, 2, 2] of Code[20]; + VendNo: array[2] of Code[20]; + ExpectedAmount: array[2, 2, 2] of Decimal; + ExpectedEntryNo: array[2, 2, 2] of Integer; + i, j, k : Integer; + begin + // [SCENARIO 495389] Stan can report a single form for a single vendor + + Initialize(); +#if not CLEAN25 + BindSubscription(IRSFormsEnableFeature); +#endif + PeriodNo := LibraryIRSReportingPeriod.CreateOneDayReportingPeriod(WorkDate()); + // [GIVEN] Forms MISC and NEC with two boxes each (MISC-01, MISC-02, NEC-01, NEC-02) + for i := 1 to ArrayLen(FormNo) do + FormNo[i] := LibraryIRS1099FormBox.CreateSingleFormInReportingPeriod(WorkDate()); + for i := 1 to ArrayLen(VendNo) do begin + // [GIVEN] Two vendors - "X" and "Y" + VendNo[i] := LibraryPurchase.CreateVendorNo(); + for j := 1 to ArrayLen(FormNo, 1) do + for k := 1 to ArrayLen(FormBoxNo, 3) do begin + FormBoxNo[i, j, k] := LibraryIRS1099FormBox.CreateSingleFormBoxInReportingPeriod(WorkDate(), FormNo[j]); + // [GIVEN] Purchase invoice is posted for the vendor "X" and MISC-01 + // [GIVEN] Purchase invoice is posted for the vendor "X" and MISC-02 + // [GIVEN] Purchase invoice is posted for the vendor "X" and NEC-01 + // [GIVEN] Purchase invoice is posted for the vendor "X" and NEC-02 + // [GIVEN] Purchase invoice is posted for the vendor "Y" and MISC-01 + // [GIVEN] Purchase invoice is posted for the vendor "Y" and MISC-02 + // [GIVEN] Purchase invoice is posted for the vendor "Y" and NEC-01 + // [GIVEN] Purchase invoice is posted for the vendor "Y" and NEC-02 + LibraryPurchase.CreatePurchaseInvoiceForVendorNo(PurchaseHeader, VendNo[i]); + PurchaseHeader.Validate("IRS 1099 Reporting Period", LibraryIRSReportingPeriod.GetReportingPeriod(WorkDate())); + PurchaseHeader.Validate("IRS 1099 Form No.", FormNo[j]); + PurchaseHeader.Validate("IRS 1099 Form Box No.", FormBoxNo[i, j, k]); + PurchaseHeader.Modify(true); + + LibraryERM.FindVendorLedgerEntry( + VendorLedgerEntry, VendorLedgerEntry."Document Type"::Invoice, + LibraryPurchase.PostPurchaseDocument(PurchaseHeader, true, true)); + VendorLedgerEntry.CalcFields(Amount); + // [GIVEN] Payment is posted and applied to the invoice + LibraryIRS1099Document.PostPaymentAppliedToInvoice(VendNo[i], VendorLedgerEntry."Document No.", -VendorLedgerEntry.Amount); + ExpectedAmount[i, j, k] := -VendorLedgerEntry.Amount; + ExpectedEntryNo[i, j, k] := VendorLedgerEntry."Entry No."; + end; + end; + Commit(); + // [WHEN] Create form documents + IRS1099CreateFormDocsReport.InitializeRequest(PeriodNo, '', '', false); + IRS1099CreateFormDocsReport.RunModal(); + + // [THEN] Four form documents are created + Assert.RecordCount(IRS1099FormDocHeader, ArrayLen(VendNo) * ArrayLen(FormNo)); + + for i := 1 to ArrayLen(VendNo) do + for j := 1 to ArrayLen(FormNo, 1) do begin + IRS1099FormDocHeader.SetRange("Period No.", PeriodNo); + IRS1099FormDocHeader.SetRange("Vendor No.", VendNo[i]); + IRS1099FormDocHeader.SetRange("Form No.", FormNo[j]); + IRS1099FormDocHeader.FindFirst(); + Assert.RecordCount(IRS1099FormDocHeader, 1); + IRS1099FormDocLine.SetRange("Document ID", IRS1099FormDocHeader.ID); + Assert.RecordCount(IRS1099FormDocLine, ArrayLen(FormBoxNo, 3)); + for k := 1 to ArrayLen(FormBoxNo, 3) do begin + IRS1099FormDocLine.SetRange("Form Box No.", FormBoxNo[i, j, k]); + IRS1099FormDocLine.FindFirst(); + IRS1099FormDocLine.TestField(Amount, ExpectedAmount[i, j, k]); + IRS1099FormDocLine.SetRange("Form Box No."); + IRS1099FormDocLineDetail.Get(IRS1099FormDocLine."Document ID", IRS1099FormDocLine."Line No.", ExpectedEntryNo[i, j, k]); + end; + end; + +#if not CLEAN25 + UnbindSubscription(IRSFormsEnableFeature); +#endif + end; + + local procedure Initialize() + begin + LibraryTestInitialize.OnTestInitialize(Codeunit::"IRS 1099 E2E Tests"); + if IsInitialized then + exit; + LibraryTestInitialize.OnBeforeTestSuiteInitialize(Codeunit::"IRS 1099 E2E Tests"); + + IsInitialized := true; + Commit(); + LibraryTestInitialize.OnAfterTestSuiteInitialize(Codeunit::"IRS 1099 E2E Tests"); + end; + + [RequestPageHandler] + procedure IRS1099CreateFormDocsRequestPageHandler(var IRS1099CreateFormDocs: TestRequestPage "IRS 1099 Create Form Docs") + begin + IRS1099CreateFormDocs.Ok().Invoke(); + end; +} diff --git a/Apps/US/IRSForms/test/src/IRS1099FormCalcTests.Codeunit.al b/Apps/US/IRSForms/test/src/IRS1099FormCalcTests.Codeunit.al new file mode 100644 index 0000000000..91f3592b8f --- /dev/null +++ b/Apps/US/IRSForms/test/src/IRS1099FormCalcTests.Codeunit.al @@ -0,0 +1,467 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +using Microsoft.Finance.GeneralLedger.Ledger; +using Microsoft.Purchases.Document; +using Microsoft.Purchases.Payables; + +codeunit 148014 "IRS 1099 Form Calc. Tests" +{ + Subtype = Test; + TestPermissions = Disabled; + EventSubscriberInstance = Manual; + + var + LibraryTestInitialize: Codeunit "Library - Test Initialize"; + LibraryPurchase: Codeunit "Library - Purchase"; + LibraryIRSReportingPeriod: Codeunit "Library IRS Reporting Period"; + LibraryIRS1099FormBox: Codeunit "Library IRS 1099 Form Box"; + LibraryIRS1099Document: Codeunit "Library IRS 1099 Document"; + LibraryERM: Codeunit "Library - ERM"; + Assert: Codeunit "Assert"; + LibraryInventory: Codeunit "Library - Inventory"; + LibraryRandom: Codeunit "Library - Random"; + IsInitialized: Boolean; + + trigger OnRun() + begin + // [FEATURE] [1099] [UT] + end; + + [Test] + procedure SingleVendorSingleForm() + var + PurchaseHeader: Record "Purchase Header"; + PurchaseLine: Record "Purchase Line"; + VendorLedgerEntry: Record "Vendor Ledger Entry"; + TempVendFormBoxBuffer: Record "IRS 1099 Vend. Form Box Buffer" temporary; +#if not CLEAN25 +#pragma warning disable AL0432 + IRSFormsEnableFeature: Codeunit "IRS Forms Enable Feature"; +#pragma warning restore AL0432 +#endif + PeriodNo: Code[20]; + FormNo: Code[20]; + FormBoxNo: Code[20]; + VendNo: Code[20]; + PostingDate: Date; + begin + // [SCENARIO 495389] The calculation of the form boxes is correct for a single vendor and a single form + + Initialize(); +#if not CLEAN25 + BindSubscription(IRSFormsEnableFeature); +#endif + PostingDate := GetPostingDate(); + // [GIVEN] IRS Reporting "X" with "Starting Date" = 01.01.2024 and "Ending Date" = 31.12.2024 + PeriodNo := LibraryIRSReportingPeriod.CreateOneDayReportingPeriod(PostingDate); + FormNo := LibraryIRS1099FormBox.CreateSingleFormInReportingPeriod(PostingDate); + FormBoxNo := LibraryIRS1099FormBox.CreateSingleFormBoxInReportingPeriod(PostingDate, FormNo); + // [GIVEN] Vendor "Y" with Form Box "MISC-01" is created + VendNo := LibraryIRS1099FormBox.CreateVendorNoWithFormBox(PostingDate, FormNo, FormBoxNo); + // [GIVEN] Purchase invoice is posted for the vendor with Starting Date = 01.01.2024 and Amount = 100 + LibraryPurchase.CreatePurchHeader(PurchaseHeader, PurchaseHeader."Document Type"::Invoice, VendNo); + PurchaseHeader.Validate("Posting Date", PostingDate); + LibraryPurchase.CreatePurchaseLineWithUnitCost( + PurchaseLine, PurchaseHeader, LibraryInventory.CreateItemNo(), + LibraryRandom.RandInt(100), LibraryRandom.RandDec(100, 2)); + LibraryERM.FindVendorLedgerEntry( + VendorLedgerEntry, VendorLedgerEntry."Document Type"::Invoice, + LibraryPurchase.PostPurchaseDocument(PurchaseHeader, true, true)); + VendorLedgerEntry.CalcFields(Amount); + // [GIVEN] Payment with amount 100 is posted and applied to the invoice + LibraryIRS1099Document.PostPaymentAppliedToInvoice(PostingDate, VendNo, VendorLedgerEntry."Document No.", -VendorLedgerEntry.Amount); + // [WHEN] Calculate form boxes + LibraryIRS1099FormBox.GetVendorFormBoxAmount(TempVendFormBoxBuffer, PeriodNo, FormNo, VendNo); + // [THEN] A single form box record is created + TempVendFormBoxBuffer.Reset(); + TempVendFormBoxBuffer.SetRange("Buffer Type", TempVendFormBoxBuffer."Buffer Type"::Amount); + Assert.RecordCount(TempVendFormBoxBuffer, 1); + // [THEN] Period = "X", Form No = "MISC", Form Box No = "MISC-01", Vendor No = "Y", Amount = 100 + LibraryIRS1099FormBox.VerifyCurrTempVendFormBoxBufferIncludedIn1099( + TempVendFormBoxBuffer, PeriodNo, FormNo, FormBoxNo, VendNo, -VendorLedgerEntry.Amount); + // [THEN] Check connected entry + LibraryIRS1099FormBox.VerifyConnectedEntryInVendFormBoxBuffer(TempVendFormBoxBuffer, VendorLedgerEntry."Entry No."); + +#if not CLEAN25 + UnbindSubscription(IRSFormsEnableFeature); +#endif + end; + + [Test] + procedure SingleVendorSingleFormMultipleBoxes() + var + PurchaseHeader: Record "Purchase Header"; + PurchaseLine: Record "Purchase Line"; + VendorLedgerEntry: Record "Vendor Ledger Entry"; + TempVendFormBoxBuffer: Record "IRS 1099 Vend. Form Box Buffer" temporary; +#if not CLEAN25 +#pragma warning disable AL0432 + IRSFormsEnableFeature: Codeunit "IRS Forms Enable Feature"; +#pragma warning restore AL0432 +#endif + PeriodNo: Code[20]; + FormNo: Code[20]; + FormBoxNo: array[2] of Code[20]; + VendNo: Code[20]; + ExpectedAmount: array[2] of Decimal; + ExpectedEntryNo: array[2] of Integer; + i: Integer; + PostingDate: Date; + begin + // [SCENARIO 495389] The calculation of the form boxes is correct for a single vendor and single form with multiple form boxes + + Initialize(); +#if not CLEAN25 + BindSubscription(IRSFormsEnableFeature); +#endif + PostingDate := GetPostingDate(); + PeriodNo := LibraryIRSReportingPeriod.CreateOneDayReportingPeriod(PostingDate); + // [GIVEN] MISC form with two boxes - MISC-01 and MISC-02 + FormNo := LibraryIRS1099FormBox.CreateSingleFormInReportingPeriod(PostingDate); + for i := 1 to ArrayLen(FormBoxNo) do + FormBoxNo[i] := LibraryIRS1099FormBox.CreateSingleFormBoxInReportingPeriod(PostingDate, FormNo); + // [GIVEN] A single vendor + VendNo := LibraryPurchase.CreateVendorNo(); + // [GIVEN] Purchase invoice is posted for the vendor and MISC-01 + // [GIVEN] Purchase invoice is posted for the vendor and MISC-02 + for i := 1 to ArrayLen(FormBoxNo) do begin + LibraryPurchase.CreatePurchHeader(PurchaseHeader, PurchaseHeader."Document Type"::Invoice, VendNo); + PurchaseHeader.Validate("Posting Date", PostingDate); + LibraryPurchase.CreatePurchaseLineWithUnitCost( + PurchaseLine, PurchaseHeader, LibraryInventory.CreateItemNo(), + LibraryRandom.RandInt(100), LibraryRandom.RandDec(100, 2)); + PurchaseHeader.Validate("IRS 1099 Reporting Period", LibraryIRSReportingPeriod.GetReportingPeriod(PostingDate)); + PurchaseHeader.Validate("IRS 1099 Form No.", FormNo); + PurchaseHeader.Validate("IRS 1099 Form Box No.", FormBoxNo[i]); + PurchaseHeader.Modify(true); + + LibraryERM.FindVendorLedgerEntry( + VendorLedgerEntry, VendorLedgerEntry."Document Type"::Invoice, + LibraryPurchase.PostPurchaseDocument(PurchaseHeader, true, true)); + VendorLedgerEntry.CalcFields(Amount); + // [GIVEN] Payment is applied to the invoice + LibraryIRS1099Document.PostPaymentAppliedToInvoice(PostingDate, VendNo, VendorLedgerEntry."Document No.", -VendorLedgerEntry.Amount); + ExpectedAmount[i] := -VendorLedgerEntry.Amount; + ExpectedEntryNo[i] := VendorLedgerEntry."Entry No."; + end; + // [WHEN] Calculate form boxes + LibraryIRS1099FormBox.GetVendorFormBoxAmount(TempVendFormBoxBuffer, PeriodNo, FormNo, VendNo); + // [THEN] Two form box records are created + TempVendFormBoxBuffer.Reset(); + TempVendFormBoxBuffer.SetRange("Buffer Type", TempVendFormBoxBuffer."Buffer Type"::Amount); + Assert.RecordCount(TempVendFormBoxBuffer, 2); + TempVendFormBoxBuffer.FindSet(); + for i := 1 to ArrayLen(FormBoxNo) do begin + LibraryIRS1099FormBox.VerifyCurrTempVendFormBoxBufferIncludedIn1099( + TempVendFormBoxBuffer, PeriodNo, FormNo, FormBoxNo[i], VendNo, ExpectedAmount[i]); + LibraryIRS1099FormBox.VerifyConnectedEntryInVendFormBoxBuffer(TempVendFormBoxBuffer, ExpectedEntryNo[i]); + end; + +#if not CLEAN25 + UnbindSubscription(IRSFormsEnableFeature); +#endif + end; + + [Test] + procedure SingleVendorMultipleFormsAndBoxes() + var + PurchaseHeader: Record "Purchase Header"; + PurchaseLine: Record "Purchase Line"; + VendorLedgerEntry: Record "Vendor Ledger Entry"; + TempVendFormBoxBuffer: Record "IRS 1099 Vend. Form Box Buffer" temporary; +#if not CLEAN25 +#pragma warning disable AL0432 + IRSFormsEnableFeature: Codeunit "IRS Forms Enable Feature"; +#pragma warning restore AL0432 +#endif + PeriodNo: Code[20]; + FormNo: array[2] of Code[20]; + FormBoxNo: array[2, 2] of Code[20]; + ExpectedAmount: array[2, 2] of Decimal; + ExpectedEntryNo: array[2, 2] of Integer; + VendNo: Code[20]; + i, j : Integer; + PostingDate: Date; + begin + // [SCENARIO 495389] The calculation of the form boxes is correct for a single vendor and multiple forms and form boxes + + Initialize(); +#if not CLEAN25 + BindSubscription(IRSFormsEnableFeature); +#endif + PostingDate := GetPostingDate(); + PeriodNo := LibraryIRSReportingPeriod.CreateOneDayReportingPeriod(PostingDate); + // [GIVEN] A single vendor + VendNo := LibraryPurchase.CreateVendorNo(); + // [GIVEN] MISC and NEC forms with two boxes each (MISC-01, MISC-02, NEC-01, NEC-02) + for i := 1 to ArrayLen(FormNo) do begin + FormNo[i] := LibraryIRS1099FormBox.CreateSingleFormInReportingPeriod(PostingDate); + for j := 1 to 2 do + FormBoxNo[i, j] := LibraryIRS1099FormBox.CreateSingleFormBoxInReportingPeriod(PostingDate, FormNo[i]); + for j := 1 to ArrayLen(FormNo) do begin + // [GIVEN] Purchase invoice is posted for the vendor and MISC-01 + // [GIVEN] Purchase invoice is posted for the vendor and MISC-02 + // [GIVEN] Purchase invoice is posted for the vendor and NEC-01 + // [GIVEN] Purchase invoice is posted for the vendor and NEC-02 + LibraryPurchase.CreatePurchHeader(PurchaseHeader, PurchaseHeader."Document Type"::Invoice, VendNo); + PurchaseHeader.Validate("Posting Date", PostingDate); + LibraryPurchase.CreatePurchaseLineWithUnitCost( + PurchaseLine, PurchaseHeader, LibraryInventory.CreateItemNo(), + LibraryRandom.RandInt(100), LibraryRandom.RandDec(100, 2)); + PurchaseHeader.Validate("IRS 1099 Reporting Period", LibraryIRSReportingPeriod.GetReportingPeriod(PostingDate)); + PurchaseHeader.Validate("IRS 1099 Form No.", FormNo[i]); + PurchaseHeader.Validate("IRS 1099 Form Box No.", FormBoxNo[i, j]); + PurchaseHeader.Modify(true); + + LibraryERM.FindVendorLedgerEntry( + VendorLedgerEntry, VendorLedgerEntry."Document Type"::Invoice, + LibraryPurchase.PostPurchaseDocument(PurchaseHeader, true, true)); + VendorLedgerEntry.CalcFields(Amount); + // [GIVEN] Payment with amount 100 is posted and applied to the invoice + LibraryIRS1099Document.PostPaymentAppliedToInvoice(PostingDate, VendNo, VendorLedgerEntry."Document No.", -VendorLedgerEntry.Amount); + ExpectedAmount[i, j] := -VendorLedgerEntry.Amount; + ExpectedEntryNo[i, j] := VendorLedgerEntry."Entry No."; + end; + end; + // [WHEN] Calculate form boxes + LibraryIRS1099FormBox.GetVendorFormBoxAmount(TempVendFormBoxBuffer, PeriodNo, '', VendNo); + // [THEN] Four form box records are created + TempVendFormBoxBuffer.Reset(); + TempVendFormBoxBuffer.SetRange("Buffer Type", TempVendFormBoxBuffer."Buffer Type"::Amount); + Assert.RecordCount(TempVendFormBoxBuffer, ArrayLen(FormNo) * ArrayLen(FormBoxNo, 2)); + TempVendFormBoxBuffer.FindSet(); + for i := 1 to ArrayLen(FormNo) do + for j := 1 to ArrayLen(FormNo) do begin + LibraryIRS1099FormBox.VerifyCurrTempVendFormBoxBufferIncludedIn1099( + TempVendFormBoxBuffer, PeriodNo, FormNo[i], FormBoxNo[i, j], VendNo, ExpectedAmount[i, j]); + LibraryIRS1099FormBox.VerifyConnectedEntryInVendFormBoxBuffer(TempVendFormBoxBuffer, ExpectedEntryNo[i, j]); + end; +#if not CLEAN25 + UnbindSubscription(IRSFormsEnableFeature); +#endif + end; + + [Test] + procedure MultipleVendorsMultipleFormsAndBoxes() + var + PurchaseHeader: Record "Purchase Header"; + PurchaseLine: Record "Purchase Line"; + VendorLedgerEntry: Record "Vendor Ledger Entry"; + TempVendFormBoxBuffer: Record "IRS 1099 Vend. Form Box Buffer" temporary; +#if not CLEAN25 +#pragma warning disable AL0432 + IRSFormsEnableFeature: Codeunit "IRS Forms Enable Feature"; +#pragma warning restore AL0432 +#endif + PeriodNo: Code[20]; + FormNo: array[2] of Code[20]; + FormBoxNo: array[2, 2, 2] of Code[20]; + VendNo: array[2] of Code[20]; + ExpectedAmount: array[2, 2, 2] of Decimal; + ExpectedEntryNo: array[2, 2, 2] of Integer; + i, j, k : Integer; + PostingDate: Date; + begin + // [SCENARIO 495389] The calculation of the form boxes is correct for multiple vendors and multiple forms and form boxes + + Initialize(); +#if not CLEAN25 + BindSubscription(IRSFormsEnableFeature); +#endif + PostingDate := GetPostingDate(); + PeriodNo := LibraryIRSReportingPeriod.CreateOneDayReportingPeriod(PostingDate); + // [GIVEN] Forms MISC and NEC with two boxes each (MISC-01, MISC-02, NEC-01, NEC-02) + for i := 1 to ArrayLen(FormNo) do + FormNo[i] := LibraryIRS1099FormBox.CreateSingleFormInReportingPeriod(PostingDate); + for i := 1 to ArrayLen(VendNo) do begin + // [GIVEN] Two vendors - "X" and "Y" + VendNo[i] := LibraryPurchase.CreateVendorNo(); + for j := 1 to ArrayLen(FormNo, 1) do + for k := 1 to ArrayLen(FormBoxNo, 3) do begin + FormBoxNo[i, j, k] := LibraryIRS1099FormBox.CreateSingleFormBoxInReportingPeriod(PostingDate, FormNo[j]); + // [GIVEN] Purchase invoice is posted for the vendor "X" and MISC-01 + // [GIVEN] Purchase invoice is posted for the vendor "X" and MISC-02 + // [GIVEN] Purchase invoice is posted for the vendor "X" and NEC-01 + // [GIVEN] Purchase invoice is posted for the vendor "X" and NEC-02 + // [GIVEN] Purchase invoice is posted for the vendor "Y" and MISC-01 + // [GIVEN] Purchase invoice is posted for the vendor "Y" and MISC-02 + // [GIVEN] Purchase invoice is posted for the vendor "Y" and NEC-01 + // [GIVEN] Purchase invoice is posted for the vendor "Y" and NEC-02 + LibraryPurchase.CreatePurchHeader(PurchaseHeader, PurchaseHeader."Document Type"::Invoice, VendNo[i]); + PurchaseHeader.Validate("Posting Date", PostingDate); + LibraryPurchase.CreatePurchaseLineWithUnitCost( + PurchaseLine, PurchaseHeader, LibraryInventory.CreateItemNo(), + LibraryRandom.RandInt(100), LibraryRandom.RandDec(100, 2)); + PurchaseHeader.Validate("IRS 1099 Reporting Period", LibraryIRSReportingPeriod.GetReportingPeriod(PostingDate)); + PurchaseHeader.Validate("IRS 1099 Form No.", FormNo[j]); + PurchaseHeader.Validate("IRS 1099 Form Box No.", FormBoxNo[i, j, k]); + PurchaseHeader.Modify(true); + + LibraryERM.FindVendorLedgerEntry( + VendorLedgerEntry, VendorLedgerEntry."Document Type"::Invoice, + LibraryPurchase.PostPurchaseDocument(PurchaseHeader, true, true)); + VendorLedgerEntry.CalcFields(Amount); + // [GIVEN] Payment is posted and applied to the invoice + LibraryIRS1099Document.PostPaymentAppliedToInvoice(PostingDate, VendNo[i], VendorLedgerEntry."Document No.", -VendorLedgerEntry.Amount); + ExpectedAmount[i, j, k] := -VendorLedgerEntry.Amount; + ExpectedEntryNo[i, j, k] := VendorLedgerEntry."Entry No."; + end; + end; + // [WHEN] Calculate form boxes + LibraryIRS1099FormBox.GetVendorFormBoxAmount(TempVendFormBoxBuffer, PeriodNo, '', ''); + TempVendFormBoxBuffer.Reset(); + TempVendFormBoxBuffer.SetRange("Buffer Type", TempVendFormBoxBuffer."Buffer Type"::Amount); + Assert.RecordCount(TempVendFormBoxBuffer, ArrayLen(VendNo) * ArrayLen(FormNo) * ArrayLen(FormBoxNo, 3)); + // [THEN] Eight form box records are created + for i := 1 to ArrayLen(VendNo) do + for j := 1 to ArrayLen(FormNo, 1) do + for k := 1 to ArrayLen(FormBoxNo, 3) do begin + LibraryIRS1099FormBox.VerifyCurrTempVendFormBoxBufferIncludedIn1099( + TempVendFormBoxBuffer, PeriodNo, FormNo[j], FormBoxNo[i, j, k], VendNo[i], ExpectedAmount[i, j, k]); + LibraryIRS1099FormBox.VerifyConnectedEntryInVendFormBoxBuffer(TempVendFormBoxBuffer, ExpectedEntryNo[i, j, k]); + end; + +#if not CLEAN25 + UnbindSubscription(IRSFormsEnableFeature); +#endif + end; + + [Test] + procedure SingleRefundToCrMemo() + var + PurchaseHeader: Record "Purchase Header"; + PurchaseLine: Record "Purchase Line"; + InvVendorLedgerEntry: Record "Vendor Ledger Entry"; + CrMemoVendorLedgerEntry: Record "Vendor Ledger Entry"; + TempVendFormBoxBuffer: Record "IRS 1099 Vend. Form Box Buffer" temporary; +#if not CLEAN25 +#pragma warning disable AL0432 + IRSFormsEnableFeature: Codeunit "IRS Forms Enable Feature"; +#pragma warning restore AL0432 +#endif + PeriodNo: Code[20]; + FormNo: Code[20]; + FormBoxNo: Code[20]; + VendNo: Code[20]; + PostingDate: Date; + begin + // [SCENARIO 495389] The calculation of the form boxes is correct for a single refund and credit memo + + Initialize(); +#if not CLEAN25 + BindSubscription(IRSFormsEnableFeature); +#endif + PostingDate := GetPostingDate(); + // [GIVEN] Form box MISC-01 is created for the period "X" + PeriodNo := LibraryIRSReportingPeriod.CreateOneDayReportingPeriod(PostingDate); + FormNo := LibraryIRS1099FormBox.CreateSingleFormInReportingPeriod(PostingDate); + FormBoxNo := LibraryIRS1099FormBox.CreateSingleFormBoxInReportingPeriod(PostingDate, FormNo); + VendNo := LibraryIRS1099FormBox.CreateVendorNoWithFormBox(PostingDate, FormNo, FormBoxNo); + // [GIVEN] Invoice is posted for the vendor "Y" with the Amount = 100 + LibraryPurchase.CreatePurchHeader(PurchaseHeader, PurchaseHeader."Document Type"::Invoice, VendNo); + PurchaseHeader.Validate("Posting Date", PostingDate); + LibraryPurchase.CreatePurchaseLineWithUnitCost( + PurchaseLine, PurchaseHeader, LibraryInventory.CreateItemNo(), + LibraryRandom.RandInt(100), LibraryRandom.RandDec(100, 2)); + LibraryERM.FindVendorLedgerEntry( + InvVendorLedgerEntry, InvVendorLedgerEntry."Document Type"::Invoice, + LibraryPurchase.PostPurchaseDocument(PurchaseHeader, true, true)); + InvVendorLedgerEntry.CalcFields(Amount); + // [GIVEN] Payment with amount 100 is posted and applied to the invoice + LibraryIRS1099Document.PostPaymentAppliedToInvoice(PostingDate, VendNo, InvVendorLedgerEntry."Document No.", -InvVendorLedgerEntry.Amount); + // [GIVEN] Credit Memo is posted for the vendor "Y" with the Amount = 20 + LibraryPurchase.CreatePurchHeader(PurchaseHeader, PurchaseHeader."Document Type"::"Credit Memo", VendNo); + PurchaseHeader.Validate("Posting Date", PostingDate); + LibraryPurchase.CreatePurchaseLineWithUnitCost( + PurchaseLine, PurchaseHeader, LibraryInventory.CreateItemNo(), + 1, -InvVendorLedgerEntry.Amount / 5); + LibraryERM.FindVendorLedgerEntry( + CrMemoVendorLedgerEntry, CrMemoVendorLedgerEntry."Document Type"::"Credit Memo", + LibraryPurchase.PostPurchaseDocument(PurchaseHeader, true, true)); + CrMemoVendorLedgerEntry.CalcFields(Amount); + // [GIVEN] Refund with amount 20 is posted and applied to the credit memo + LibraryIRS1099Document.PostRefundAppliedToCreditMemo(PostingDate, VendNo, CrMemoVendorLedgerEntry."Document No.", -CrMemoVendorLedgerEntry.Amount); + // [WHEN] Calculate form boxes + LibraryIRS1099FormBox.GetVendorFormBoxAmount(TempVendFormBoxBuffer, PeriodNo, FormNo, VendNo); + // [THEN] A single form box record is created + TempVendFormBoxBuffer.Reset(); + TempVendFormBoxBuffer.SetRange("Buffer Type", TempVendFormBoxBuffer."Buffer Type"::Amount); + Assert.RecordCount(TempVendFormBoxBuffer, 1); + // [THEN] Period = "X", Form No = "MISC", Form Box No = "MISC-01", Vendor No = "Y", Amount = 80 + LibraryIRS1099FormBox.VerifyCurrTempVendFormBoxBufferIncludedIn1099( + TempVendFormBoxBuffer, PeriodNo, FormNo, FormBoxNo, VendNo, -InvVendorLedgerEntry.Amount - CrMemoVendorLedgerEntry.Amount); + // [THEN] Check connected entries + TempVendFormBoxBuffer.Reset(); + TempVendFormBoxBuffer.SetRange("Parent Entry No.", TempVendFormBoxBuffer."Entry No."); + TempVendFormBoxBuffer.SetRange("Buffer Type", TempVendFormBoxBuffer."Buffer Type"::"Ledger Entry"); + Assert.RecordCount(TempVendFormBoxBuffer, 2); + TempVendFormBoxBuffer.FindSet(); + TempVendFormBoxBuffer.TestField("Vendor Ledger Entry No.", InvVendorLedgerEntry."Entry No."); + TempVendFormBoxBuffer.Next(); + TempVendFormBoxBuffer.TestField("Vendor Ledger Entry No.", CrMemoVendorLedgerEntry."Entry No."); + +#if not CLEAN25 + UnbindSubscription(IRSFormsEnableFeature); +#endif + end; + + [Test] + procedure OnlyAdjustment() + var + TempVendFormBoxBuffer: Record "IRS 1099 Vend. Form Box Buffer" temporary; + PeriodNo: Code[20]; + FormNo: Code[20]; + FormBoxNo: Code[20]; + VendNo: Code[20]; + PostingDate: Date; + AdjustmentAmount: Decimal; + begin + // [SCENARIO 495389] The calculation of the form boxes is correct when vendor has only adjustment and no vendor ledger entries + + Initialize(); + // [GIVEN] Form box MISC-01 + PostingDate := GetPostingDate(); + PeriodNo := LibraryIRSReportingPeriod.CreateOneDayReportingPeriod(PostingDate); + FormNo := LibraryIRS1099FormBox.CreateSingleFormInReportingPeriod(PostingDate); + FormBoxNo := LibraryIRS1099FormBox.CreateSingleFormBoxInReportingPeriod(PostingDate, FormNo); + // [GIVEN] Vendor with adjustment amount 100 for period "X" + VendNo := LibraryPurchase.CreateVendorNo(); + AdjustmentAmount := LibraryRandom.RandDec(100, 2); + LibraryIRS1099FormBox.AddAdjustmentAmountForVendor(PostingDate, VendNo, FormNo, FormBoxNo, AdjustmentAmount); + // [WHEN] Calculate form boxes for period "X" + LibraryIRS1099FormBox.GetVendorFormBoxAmount(TempVendFormBoxBuffer, PeriodNo, FormNo, VendNo); + // [THEN] A single form box record is created with amount = 100 + TempVendFormBoxBuffer.Reset(); + TempVendFormBoxBuffer.SetRange("Buffer Type", TempVendFormBoxBuffer."Buffer Type"::Amount); + Assert.RecordCount(TempVendFormBoxBuffer, 1); + LibraryIRS1099FormBox.VerifyCurrTempVendFormBoxBuffer( + TempVendFormBoxBuffer, PeriodNo, FormNo, FormBoxNo, VendNo, 0, AdjustmentAmount, true); + TempVendFormBoxBuffer.TestField("Adjustment Amount", AdjustmentAmount); + end; + + local procedure Initialize() + begin + LibraryTestInitialize.OnTestInitialize(Codeunit::"IRS 1099 Form Calc. Tests"); + if IsInitialized then + exit; + LibraryTestInitialize.OnBeforeTestSuiteInitialize(Codeunit::"IRS 1099 Form Calc. Tests"); + + IsInitialized := true; + Commit(); + LibraryTestInitialize.OnAfterTestSuiteInitialize(Codeunit::"IRS 1099 Form Calc. Tests"); + end; + + local procedure GetPostingDate(): Date + var + GLEntry: Record "G/L Entry"; + begin + GLEntry.SetCurrentKey("Posting Date", "G/L Account No.", "Dimension Set ID"); + if GLEntry.FindLast() then + exit(CalcDate('<1Y>', GLEntry."Posting Date")); + exit(WorkDate()); + end; +} diff --git a/Apps/US/IRSForms/test/src/IRS1099PrintingTests.Codeunit.al b/Apps/US/IRSForms/test/src/IRS1099PrintingTests.Codeunit.al new file mode 100644 index 0000000000..79b9a92f3b --- /dev/null +++ b/Apps/US/IRSForms/test/src/IRS1099PrintingTests.Codeunit.al @@ -0,0 +1,268 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +using Microsoft.Purchases.Vendor; + +codeunit 148017 "IRS 1099 Printing Tests" +{ + Subtype = Test; + TestPermissions = Disabled; + EventSubscriberInstance = Manual; + + var + Assert: Codeunit Assert; + LibraryIRSReportingPeriod: Codeunit "Library IRS Reporting Period"; + LibraryIRS1099FormBox: Codeunit "Library IRS 1099 Form Box"; + LibraryPurchase: Codeunit "Library - Purchase"; + LibraryRandom: Codeunit "Library - Random"; + LibraryReportDataset: Codeunit "Library - Report Dataset"; + LibraryTestInitialize: Codeunit "Library - Test Initialize"; + LibraryUtility: Codeunit "Library - Utility"; + IsInitialized: Boolean; + IRS1099FormStatementLineEmptyErr: Label 'There are no form statement lines for the selected form and period.'; + + trigger OnRun() + begin + // [FEATURE] [1099] [UT] + end; + + [Test] + procedure UT_IRS1099Print_NoStatementLinesErr() + var + IRS1099FormDocHeader: Record "IRS 1099 Form Doc. Header"; + IRS1099FormDocLine: Record "IRS 1099 Form Doc. Line"; +#if not CLEAN25 +#pragma warning disable AL0432 + IRSFormsEnableFeature: Codeunit "IRS Forms Enable Feature"; +#pragma warning restore AL0432 +#endif + begin + // [SCENARIO 495389] User gets error when trying to run report with empty statement lines + Initialize(); + +#if not CLEAN25 + BindSubscription(IRSFormsEnableFeature); +#endif + + // [GIVEN] IRS 1099 Document exists for Vendor in period + CreateIRS1099Document(IRS1099FormDocHeader); + + // [GIVEN] Form Box No exists in period + Commit(); + + // [GIVEN] IRS 1099 Document Line exists for Vendor in period + CreateIRS1099DocLine(IRS1099FormDocHeader, IRS1099FormDocLine, LibraryIRS1099FormBox.CreateSingleFormBoxInReportingPeriod(WorkDate(), IRS1099FormDocHeader."Form No."), LibraryRandom.RandDec(1000, 2)); + + // [WHEN] Run Print report + asserterror Report.Run(Report::"IRS 1099 Print", false, false, IRS1099FormDocHeader); + + // [THEN] Error is shown that no statement lines exist + Assert.ExpectedError(IRS1099FormStatementLineEmptyErr); + + // Tear down + IRS1099FormDocHeader.Delete(true); +#if not CLEAN25 + UnbindSubscription(IRSFormsEnableFeature); +#endif + end; + + [Test] + procedure UT_IRS1099Print_SavingReportWorks() + var + IRS1099FormDocHeader: Record "IRS 1099 Form Doc. Header"; + IRS1099FormDocLine: Record "IRS 1099 Form Doc. Line"; + IRS1099PrintParams: Record "IRS 1099 Print Params"; + IRSFormsFacade: Codeunit "IRS Forms Facade"; +#if not CLEAN25 +#pragma warning disable AL0432 + IRSFormsEnableFeature: Codeunit "IRS Forms Enable Feature"; +#pragma warning restore AL0432 +#endif + FormBoxNo: Code[20]; + begin + // [SCENARIO 495389] SaveContentForDocument works for document + Initialize(); +#if not CLEAN25 + BindSubscription(IRSFormsEnableFeature); +#endif + + // [GIVEN] IRS 1099 Document exists for Vendor in period + CreateIRS1099Document(IRS1099FormDocHeader); + + // [GIVEN] Form Box No exists in period + FormBoxNo := LibraryIRS1099FormBox.CreateSingleFormBoxInReportingPeriod(WorkDate(), IRS1099FormDocHeader."Form No."); + + // [GIVEN] IRS 1099 Document Line exists for Vendor in period + CreateIRS1099DocLine(IRS1099FormDocHeader, IRS1099FormDocLine, FormBoxNo, LibraryRandom.RandDec(1000, 2)); + + // [GIVEN] No Statement Line exists for Vendor in period + CreateStatementLine(IRS1099FormDocHeader, FormBoxNo); + + Commit(); + + // [WHEN] Use Save content for document + IRS1099PrintParams := CreatePrintParams(); + IRSFormsFacade.SaveContentForDocument(IRS1099FormDocHeader, IRS1099PrintParams, false); + + // [THEN] Content has beed saved + VerifyFileContentExists(IRS1099FormDocHeader, IRS1099PrintParams."Report Type"); + + // Tear down + IRS1099FormDocHeader.Delete(true); +#if not CLEAN25 + UnbindSubscription(IRSFormsEnableFeature); +#endif + end; + + [Test] + procedure UT_IRS1099Print_BankAccountNo() + var + IRS1099FormDocHeader: Record "IRS 1099 Form Doc. Header"; + IRS1099FormDocLine: Record "IRS 1099 Form Doc. Line"; + VendorBankAccount: Record "Vendor Bank Account"; +#if not CLEAN25 +#pragma warning disable AL0432 + IRSFormsEnableFeature: Codeunit "IRS Forms Enable Feature"; +#pragma warning restore AL0432 +#endif + FormBoxNo: Code[20]; + begin + // [SCENARIO 495389] Bank Account No for Vendor is shown correctly in report + Initialize(); +#if not CLEAN25 + BindSubscription(IRSFormsEnableFeature); +#endif + + // [GIVEN] IRS 1099 Document exists for Vendor in period + CreateIRS1099Document(IRS1099FormDocHeader); + + // [GIVEN] Vendor Bank Account exists for this vendor with Bank Account No = "XXX" + LibraryPurchase.CreateVendorBankAccount(VendorBankAccount, IRS1099FormDocHeader."Vendor No."); + VendorBankAccount."Bank Account No." := LibraryUtility.GenerateGUID(); + VendorBankAccount.Modify(true); + + // [GIVEN] Update Preffered Bank Account for Vendor + SetPreferredBankAccount(IRS1099FormDocHeader."Vendor No.", VendorBankAccount.Code); + + // [GIVEN] Form Box No exists in period + FormBoxNo := LibraryIRS1099FormBox.CreateSingleFormBoxInReportingPeriod(WorkDate(), IRS1099FormDocHeader."Form No."); + + // [GIVEN] IRS 1099 Document Line exists for Vendor in period + CreateIRS1099DocLine(IRS1099FormDocHeader, IRS1099FormDocLine, FormBoxNo, LibraryRandom.RandDec(1000, 2)); + + // [GIVEN] No Statement Line exists for Vendor in period + CreateStatementLine(IRS1099FormDocHeader, FormBoxNo); + + Commit(); + + // [WHEN] Run report + LibraryReportDataset.RunReportAndLoad(Report::"IRS 1099 Print", IRS1099FormDocHeader, ''); + + // [THEN] Vendor Bank Account No in report is "XXX" + LibraryReportDataset.AssertElementWithValueExists('Vendor_BankAccountNo', VendorBankAccount."Bank Account No."); + + // Tear down + IRS1099FormDocHeader.Delete(true); +#if not CLEAN25 + UnbindSubscription(IRSFormsEnableFeature); +#endif + end; + + local procedure Initialize() + var + IRSReportingPeriod: Record "IRS Reporting Period"; + begin + IRSReportingPeriod.DeleteAll(true); + LibraryTestInitialize.OnTestInitialize(Codeunit::"IRS 1099 Document Tests"); + if IsInitialized then + exit; + LibraryTestInitialize.OnBeforeTestSuiteInitialize(Codeunit::"IRS 1099 Document Tests"); + + IsInitialized := true; + LibraryTestInitialize.OnAfterTestSuiteInitialize(Codeunit::"IRS 1099 Document Tests"); + end; + + local procedure CreateIRS1099Document(var IRS1099FormDocHeader: Record "IRS 1099 Form Doc. Header") + var + PeriodNo, FormNo, VendNo, FormBoxNo : Code[20]; + begin + PeriodNo := LibraryIRSReportingPeriod.CreateOneDayReportingPeriod(WorkDate()); + FormNo := LibraryIRS1099FormBox.CreateSingleFormInReportingPeriod(WorkDate()); + FormBoxNo := LibraryIRS1099FormBox.CreateSingleFormBoxInReportingPeriod(WorkDate(), FormNo); + VendNo := LibraryIRS1099FormBox.CreateVendorNoWithFormBox(WorkDate(), FormNo, FormBoxNo); + + IRS1099FormDocHeader."Period No." := PeriodNo; + IRS1099FormDocHeader."Vendor No." := VendNo; + IRS1099FormDocHeader."Form No." := FormNo; + IRS1099FormDocHeader.Insert(); + end; + + local procedure CreateIRS1099DocLine(IRS1099FormDocHeader: Record "IRS 1099 Form Doc. Header"; var IRS1099FormDocLine: Record "IRS 1099 Form Doc. Line"; FormBoxNo: Code[20]; Amount: Decimal) + var + NewLineNo: Integer; + begin + IRS1099FormDocLine.SetRange("Document ID", IRS1099FormDocHeader.ID); + if IRS1099FormDocLine.FindLast() then + NewLineNo := IRS1099FormDocLine."Line No." + 1 + else + NewLineNo := 1; + IRS1099FormDocLine.Init(); + IRS1099FormDocLine."Line No." := NewLineNo; + IRS1099FormDocLine."Document ID" := IRS1099FormDocHeader.ID; + IRS1099FormDocLine."Form Box No." := FormBoxNo; + IRS1099FormDocLine.Amount := Amount; + IRS1099FormDocLine.Insert(); + end; + + local procedure CreatePrintParams() IRS1099PrintParams: Record "IRS 1099 Print Params" + begin + IRS1099PrintParams."Report Type" := IRS1099PrintParams."Report Type"::"Copy 2"; + IRS1099PrintParams.Insert(); + end; + + local procedure CreateStatementLine(IRS1099FormDocHeader: Record "IRS 1099 Form Doc. Header"; FormBoxNo: Code[20]) + var + IRS1099FormStatementLine: Record "IRS 1099 Form Statement Line"; + IRS1099FormDocLine: Record "IRS 1099 Form Doc. Line"; + NewLineNo: Integer; + begin + IRS1099FormStatementLine.SetRange("Period No.", IRS1099FormDocHeader."Period No."); + IRS1099FormStatementLine.SetRange("Form No.", IRS1099FormDocHeader."Form No."); + if IRS1099FormStatementLine.FindLast() then + NewLineNo := IRS1099FormStatementLine."Line No." + 1 + else + NewLineNo := 1; + IRS1099FormStatementLine.Init(); + IRS1099FormStatementLine."Period No." := IRS1099FormDocHeader."Period No."; + IRS1099FormStatementLine."Form No." := IRS1099FormDocHeader."Form No."; + IRS1099FormStatementLine."Line No." := NewLineNo; + IRS1099FormStatementLine.Description := LibraryUtility.GenerateGUID(); + IRS1099FormStatementLine."Row No." := LibraryUtility.GenerateGUID(); + IRS1099FormDocLine.SetRange("Form Box No.", FormBoxNo); + IRS1099FormStatementLine.Validate("Filter Expression", IRS1099FormDocLine.GetFilters()); + IRS1099FormStatementLine.Insert(); + end; + + local procedure SetPreferredBankAccount(VendorNo: Code[20]; BankAccountNo: Code[20]) + var + Vendor: Record Vendor; + begin + Vendor.Get(VendorNo); + Vendor."Preferred Bank Account Code" := BankAccountNo; + Vendor.Modify(); + end; + + local procedure VerifyFileContentExists(IRS1099FormDocHeader: Record "IRS 1099 Form Doc. Header"; ReportType: Enum "IRS 1099 Form Report Type") + var + IRS1099FormReport: Record "IRS 1099 Form Report"; + begin + IRS1099FormReport.SetRange("Document ID", IRS1099FormDocHeader.ID); + IRS1099FormReport.SetRange("Report Type", ReportType); + IRS1099FormReport.FindFirst(); + IRS1099FormReport.CalcFields("File Content"); + Assert.IsTrue(IRS1099FormReport."File Content".HasValue(), 'File content should exist for the document and report type.'); + end; +} diff --git a/Apps/US/IRSForms/test/src/IRS1099VendorTests.Codeunit.al b/Apps/US/IRSForms/test/src/IRS1099VendorTests.Codeunit.al new file mode 100644 index 0000000000..94e8c6389e --- /dev/null +++ b/Apps/US/IRSForms/test/src/IRS1099VendorTests.Codeunit.al @@ -0,0 +1,346 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +using Microsoft.Finance.VAT.Setup; +using Microsoft.Purchases.Document; +using Microsoft.Purchases.Payables; +using Microsoft.Purchases.Vendor; +using System.TestLibraries.Utilities; + +codeunit 148011 "IRS 1099 Vendor Tests" +{ + Subtype = Test; + TestPermissions = Disabled; + + var + LibraryTestInitialize: Codeunit "Library - Test Initialize"; + LibraryVariableStorage: Codeunit "Library - Variable Storage"; + LibraryPurchase: Codeunit "Library - Purchase"; + LibraryERM: Codeunit "Library - ERM"; + LibraryIRS1099Document: Codeunit "Library IRS 1099 Document"; + LibraryIRS1099FormBox: Codeunit "Library IRS 1099 Form Box"; + LibraryIRSReportingPeriod: Codeunit "Library IRS Reporting Period"; + + LibraryRandom: Codeunit "Library - Random"; + Assert: Codeunit Assert; + IsInitialized: Boolean; + IRSReportingAmountCannotBeMoreThanAmountErr: Label 'IRS Reporting Amount cannot be more than Amount'; + IRSReportingAmountPositiveErr: Label 'IRS 1099 Reporting Amount must be positive'; + IRSReportingAmountNegativeErr: Label 'IRS 1099 Reporting Amount must be negative'; + + trigger OnRun() + begin + // [FEATURE] [1099] + end; + + [Test] + [HandlerFunctions('IRS1099SuggestVendorsByVATBusPostGroupRequestPageHandler')] + procedure SuggestVendorsForFormBoxSetupSunshine() + var + VATBusinessPostingGroup: Record "VAT Business Posting Group"; + VendorNo: array[2] of Code[20]; + i: Integer; + begin + // [SCENARIO 495389] Stan can suggest vendors by filters for the form box setup + + Initialize(); + // [GIVEN] Two vendors with different business groups - "X" and "Y" + for i := 1 to ArrayLen(VendorNo) do begin + LibraryERM.CreateVATBusinessPostingGroup(VATBusinessPostingGroup); + VendorNo[i] := LibraryPurchase.CreateVendorWithVATBusPostingGroup(VATBusinessPostingGroup.Code); + end; + LibraryIRSReportingPeriod.CreateOneDayReportingPeriod(WorkDate()); + LibraryVariableStorage.Enqueue(VATBusinessPostingGroup.Code); + Commit(); + // [WHEN] Suggest vendors with "X" business group + LibraryIRS1099FormBox.SuggestVendorsForFormBoxSetup(WorkDate(), WorkDate()); + // [THEN] Verify that only one vendor with "X" business group is suggested + LibraryIRS1099FormBox.VerifyFormBoxSetupCountForVendors(WorkDate(), WorkDate(), 1); + + LibraryVariableStorage.AssertEmpty(); + end; + + [Test] + [HandlerFunctions('IRS1099SuggestVendorsByVATBusPostGroupRequestPageHandler')] + procedure SuggestVendorsForFormBoxSetupAddToExisting() + var + VATBusinessPostingGroup: Record "VAT Business Posting Group"; + Vendor: Record Vendor; + VendorNo: array[2] of Code[20]; + i: Integer; + begin + // [SCENARIO 495389] Stan can suggest vendors for the form box setup where there are existing setup added manually + + Initialize(); + // [GIVEN] Two vendors with different business groups - "X" and "Y" + for i := 1 to ArrayLen(VendorNo) do begin + LibraryERM.CreateVATBusinessPostingGroup(VATBusinessPostingGroup); + VendorNo[i] := LibraryPurchase.CreateVendorWithVATBusPostingGroup(VATBusinessPostingGroup.Code); + end; +#pragma warning disable AA0210 +#pragma warning disable AA0175 + Vendor.SetRange("VAT Bus. Posting Group", VATBusinessPostingGroup.Code); + Vendor.FindFirst(); +#pragma warning restore AA0210 +#pragma warning restore AA0175 + LibraryIRSReportingPeriod.CreateOneDayReportingPeriod(WorkDate()); + // [GIVEN] Add vendor form box setup for the first vendor manually + LibraryIRS1099FormBox.AssignFormBoxForVendorInPeriod(VendorNo[1], WorkDate(), WorkDate(), '', ''); + LibraryVariableStorage.Enqueue(VATBusinessPostingGroup.Code); + Commit(); + // [WHEN] Suggest all vendors to the form box setup + LibraryIRS1099FormBox.SuggestVendorsForFormBoxSetup(WorkDate(), WorkDate()); + // [THEN] Two vendor form box setup records exist + LibraryIRS1099FormBox.VerifyFormBoxSetupCountForVendors(WorkDate(), WorkDate(), 2); + end; + + [Test] + [HandlerFunctions('IRS1099PropagateVendSetupRequestPageHandler')] + procedure PropagateVendorFormBoxSetupToVendorLedgerEntriesSunshine() + var + PurchaseHeader: Record "Purchase Header"; + VendorLedgerEntry: Record "Vendor Ledger Entry"; + VendorNo: Code[20]; + FormNo: Code[20]; + FormBoxNo: Code[20]; + PeriodNo: Code[20]; + begin + // [SCENARIO 495389] Stan can propagate vendor form box setup to vendor ledger entries + + Initialize(); + PeriodNo := LibraryIRSReportingPeriod.CreateOneDayReportingPeriod(WorkDate()); + VendorNo := LibraryPurchase.CreateVendorNo(); + // [GIVEN] Create purchase invoice + LibraryPurchase.CreatePurchHeader(PurchaseHeader, PurchaseHeader."Document Type"::Invoice, VendorNo); + // [GIVEN] Create vendor ledger entries + LibraryIRS1099Document.MockInvVendLedgEntry(VendorLedgerEntry, WorkDate(), WorkDate(), VendorNo, '', ''); + FormNo := + LibraryIRS1099FormBox.CreateSingleFormInReportingPeriod(WorkDate(), WorkDate()); + FormBoxNo := + LibraryIRS1099FormBox.CreateSingleFormBoxInReportingPeriod(WorkDate(), WorkDate(), FormNo); + LibraryIRS1099FormBox.AssignFormBoxForVendorInPeriod(VendorNo, WorkDate(), WorkDate(), FormNo, FormBoxNo); + Commit(); + LibraryVariableStorage.Enqueue(PeriodNo); + // [WHEN] Propagate vendor form box setup to vendor ledger entries + LibraryIRS1099FormBox.PropagateVendorFormBoxSetupToVendorLedgerEntries(WorkDate(), WorkDate(), VendorNo, FormNo, FormBoxNo); + // [THEN] Verify vendor ledger entries + VendorLedgerEntry.Find(); + VendorLedgerEntry.CalcFields(Amount); + VendorLedgerEntry.TestField("IRS 1099 Reporting Period", PeriodNo); + VendorLedgerEntry.TestField("IRS 1099 Form No.", FormNo); + VendorLedgerEntry.TestField("IRS 1099 Form Box No.", FormBoxNo); + VendorLedgerEntry.TestField("IRS 1099 Reporting Amount", VendorLedgerEntry.Amount); + VendorLedgerEntry.TestField("IRS 1099 Subject For Reporting", true); + // [THEN] Verify purchase document + PurchaseHeader.Find(); + PurchaseHeader.TestField("IRS 1099 Reporting Period", PeriodNo); + PurchaseHeader.TestField("IRS 1099 Form No.", FormNo); + PurchaseHeader.TestField("IRS 1099 Form Box No.", FormBoxNo); + LibraryVariableStorage.AssertEmpty(); + end; + + [Test] + procedure ChangeIRSDataInVendorLedgerEntry() + var + VendorLedgerEntry: Record "Vendor Ledger Entry"; +#if not CLEAN25 +#pragma warning disable AL0432 + IRSFormsEnableFeature: Codeunit "IRS Forms Enable Feature"; +#pragma warning restore AL0432 +#endif + VendorLedgerEntriesPage: TestPage "Vendor Ledger Entries"; + PeriodNo, FormNo, FormBoxNo, NewFormBoxNo : Code[20]; + IRSAmount: Decimal; + begin + // [SCENARIO 495389] Stan can change the IRS data in the posted vendor ledger entry + + Initialize(); +#if not CLEAN25 + BindSubscription(IRSFormsEnableFeature); +#endif + PeriodNo := LibraryIRSReportingPeriod.CreateOneDayReportingPeriod(WorkDate()); + FormNo := LibraryIRS1099FormBox.CreateSingleFormInReportingPeriod(WorkDate()); + FormBoxNo := LibraryIRS1099FormBox.CreateSingleFormBoxInReportingPeriod(WorkDate(), FormNo); + IRSAmount := LibraryRandom.RandDec(100, 2); + // [GIVEN] Vendor Ledger Entry with IRS 1099 Code = MISC-01 and IRS Amount = 100 + LibraryIRS1099Document.MockVendLedgEntryWithIRSData( + VendorLedgerEntry, WorkDate(), WorkDate(), FormNo, FormBoxNo, IRSAmount); + NewFormBoxNo := LibraryIRS1099FormBox.CreateSingleFormBoxInReportingPeriod(WorkDate(), FormNo); + IRSAmount := IRSAmount / 3; + // [GIVEN] Vendor Ledger Entries page opened and filtered by Entry No. + VendorLedgerEntriesPage.OpenEdit(); + VendorLedgerEntriesPage.Filter.SetFilter("Entry No.", Format(VendorLedgerEntry."Entry No.")); + // [WHEN] IRS 1099 Code is changed to MISC-2 and IRS Amount is changed to 90 + VendorLedgerEntriesPage."IRS 1099 Form No.".SetValue(FormNo); + VendorLedgerEntriesPage."IRS 1099 Form Box No.".SetValue(NewFormBoxNo); + VendorLedgerEntriesPage."IRS 1099 Reporting Amount".SetValue(IRSAmount); + VendorLedgerEntriesPage.Close(); + // [THEN] IRS 1099 Code in the Vendor Ledger Entry is MISC-2 and IRS Amount is 90 + VendorLedgerEntry.Find(); + VendorLedgerEntry.TestField("IRS 1099 Subject For Reporting", true); + VendorLedgerEntry.TestField("IRS 1099 Reporting Period", PeriodNo); + VendorLedgerEntry.TestField("IRS 1099 Form No.", FormNo); + VendorLedgerEntry.TestField("IRS 1099 Form Box No.", NewFormBoxNo); + VendorLedgerEntry.TestField("IRS 1099 Reporting Amount", IRSAmount); + +#if not CLEAN25 + UnbindSubscription(IRSFormsEnableFeature); +#endif + end; + + [Test] + procedure SetIRSAmountMoreThanAmountInVendLedgEntry() + var + VendorLedgerEntry: Record "Vendor Ledger Entry"; +#if not CLEAN25 +#pragma warning disable AL0432 + IRSFormsEnableFeature: Codeunit "IRS Forms Enable Feature"; +#pragma warning restore AL0432 +#endif + VendorLedgerEntriesPage: TestPage "Vendor Ledger Entries"; + FormNo, FormBoxNo : Code[20]; + IRSAmount: Decimal; + begin + // [SCENARIO 495389] Stan cannot set the IRS Reporting Amount more than amount in Vendor Ledger Entry + + Initialize(); +#if not CLEAN25 + BindSubscription(IRSFormsEnableFeature); +#endif + LibraryIRSReportingPeriod.CreateOneDayReportingPeriod(WorkDate()); + FormNo := LibraryIRS1099FormBox.CreateSingleFormInReportingPeriod(WorkDate()); + FormBoxNo := LibraryIRS1099FormBox.CreateSingleFormBoxInReportingPeriod(WorkDate(), FormNo); + IRSAmount := -LibraryRandom.RandDec(100, 2); + // [GIVEN] Vendor Ledger Entry with IRS 1099 Code = MISC-01 and Amount = -100 + LibraryIRS1099Document.MockVendLedgEntryWithIRSData( + VendorLedgerEntry, WorkDate(), WorkDate(), FormNo, FormBoxNo, IRSAmount); + IRSAmount := -IRSAmount * 3; + // [GIVEN] Vendor Ledger Entries page opened and filtered by Entry No. + VendorLedgerEntriesPage.OpenEdit(); + VendorLedgerEntriesPage.Filter.SetFilter("Entry No.", Format(VendorLedgerEntry."Entry No.")); + // [WHEN] IRS Amount is changed to -300 + asserterror VendorLedgerEntriesPage."IRS 1099 Reporting Amount".SetValue(IRSAmount); + // [THEN] An error message "IRS Reporting Amount cannot be more than -300" is thrown + Assert.ExpectedError(IRSReportingAmountCannotBeMoreThanAmountErr); + +#if not CLEAN25 + UnbindSubscription(IRSFormsEnableFeature); +#endif + end; + + [Test] + procedure SetPositiveIRSAmountInInvVendLedgEntry() + var + VendorLedgerEntry: Record "Vendor Ledger Entry"; +#if not CLEAN25 +#pragma warning disable AL0432 + IRSFormsEnableFeature: Codeunit "IRS Forms Enable Feature"; +#pragma warning restore AL0432 +#endif + VendorLedgerEntriesPage: TestPage "Vendor Ledger Entries"; + FormNo, FormBoxNo : Code[20]; + IRSAmount: Decimal; + begin + // [SCENARIO 495389] Stan cannot set the positive IRS Reporting Amount in the invoice Vendor Ledger Entry + + Initialize(); +#if not CLEAN25 + BindSubscription(IRSFormsEnableFeature); +#endif + LibraryIRSReportingPeriod.CreateOneDayReportingPeriod(WorkDate()); + FormNo := LibraryIRS1099FormBox.CreateSingleFormInReportingPeriod(WorkDate()); + FormBoxNo := LibraryIRS1099FormBox.CreateSingleFormBoxInReportingPeriod(WorkDate(), FormNo); + IRSAmount := -LibraryRandom.RandDec(100, 2); + // [GIVEN] Vendor Ledger Entry with IRS 1099 Code = MISC-01 and Amount = -100 + LibraryIRS1099Document.MockInvVendLedgEntryWithIRSData( + VendorLedgerEntry, WorkDate(), WorkDate(), FormNo, FormBoxNo, IRSAmount); + IRSAmount := -IRSAmount; + // [GIVEN] Vendor Ledger Entries page opened and filtered by Entry No. + VendorLedgerEntriesPage.OpenEdit(); + VendorLedgerEntriesPage.Filter.SetFilter("Entry No.", Format(VendorLedgerEntry."Entry No.")); + // [WHEN] IRS Amount is changed to 100 + asserterror VendorLedgerEntriesPage."IRS 1099 Reporting Amount".SetValue(IRSAmount); + // [THEN] An error message "IRS Reporting Amount must be negative" is thrown + Assert.ExpectedError(IRSReportingAmountNegativeErr); +#if not CLEAN25 + UnbindSubscription(IRSFormsEnableFeature); +#endif + end; + + [Test] + procedure SetNegativeIRSAmountInInvVendLedgEntry() + var + VendorLedgerEntry: Record "Vendor Ledger Entry"; +#if not CLEAN25 +#pragma warning disable AL0432 + IRSFormsEnableFeature: Codeunit "IRS Forms Enable Feature"; +#pragma warning restore AL0432 +#endif + VendorLedgerEntriesPage: TestPage "Vendor Ledger Entries"; + FormNo, FormBoxNo : Code[20]; + IRSAmount: Decimal; + begin + // [SCENARIO 495389] Stan cannot set the negative IRS Reporting Amount in the credit memo Vendor Ledger Entry + + Initialize(); +#if not CLEAN25 + BindSubscription(IRSFormsEnableFeature); +#endif + LibraryIRSReportingPeriod.CreateOneDayReportingPeriod(WorkDate()); + FormNo := LibraryIRS1099FormBox.CreateSingleFormInReportingPeriod(WorkDate()); + FormBoxNo := LibraryIRS1099FormBox.CreateSingleFormBoxInReportingPeriod(WorkDate(), FormNo); + IRSAmount := LibraryRandom.RandDec(100, 2); + // [GIVEN] Vendor Ledger Entry with IRS 1099 Code = MISC-01 and Amount = 100 + LibraryIRS1099Document.MockCrMemoVendLedgEntryWithIRSData( + VendorLedgerEntry, WorkDate(), WorkDate(), FormNo, FormBoxNo, IRSAmount); + IRSAmount := -IRSAmount; + // [GIVEN] Vendor Ledger Entries page opened and filtered by Entry No. + VendorLedgerEntriesPage.OpenEdit(); + VendorLedgerEntriesPage.Filter.SetFilter("Entry No.", Format(VendorLedgerEntry."Entry No.")); + // [WHEN] IRS Amount is changed to -100 + asserterror VendorLedgerEntriesPage."IRS 1099 Reporting Amount".SetValue(IRSAmount); + // [THEN] An error message "IRS Reporting Amount must be positive" is thrown + Assert.ExpectedError(IRSReportingAmountPositiveErr); +#if not CLEAN25 + UnbindSubscription(IRSFormsEnableFeature); +#endif + end; + + local procedure Initialize() + var + IRSReportingPeriod: Record "IRS Reporting Period"; + begin + IRSReportingPeriod.DeleteAll(true); + LibraryTestInitialize.OnTestInitialize(Codeunit::"IRS 1099 Vendor Tests"); + if IsInitialized then + exit; + LibraryTestInitialize.OnBeforeTestSuiteInitialize(Codeunit::"IRS 1099 Vendor Tests"); + + IsInitialized := true; + Commit(); + LibraryTestInitialize.OnAfterTestSuiteInitialize(Codeunit::"IRS 1099 Vendor Tests"); + end; + + [RequestPageHandler] + procedure IRS1099SuggestVendorsByVATBusPostGroupRequestPageHandler(var IRS1099SuggestVendors: TestRequestPage "IRS 1099 Suggest Vendors") + begin + IRS1099SuggestVendors.Vendor.SetFilter("VAT Bus. Posting Group", LibraryVariableStorage.DequeueText()); + IRS1099SuggestVendors.OK().Invoke(); + end; + + [RequestPageHandler] + procedure IRS1099PropagateVendSetupRequestPageHandler(var IRS1099PropagateVendSetup: TestRequestPage "IRS 1099 Propagate Vend. Setup") + var + IRSReportingPeriod: Record "IRS Reporting Period"; + begin + IRSReportingPeriod.Get(LibraryVariableStorage.DequeueText()); + IRS1099PropagateVendSetup.StartingDateControl.SetValue(IRSReportingPeriod."Starting Date"); + IRS1099PropagateVendSetup.EndingDateControl.SetValue(IRSReportingPeriod."Ending Date"); + IRS1099PropagateVendSetup.PurchaseDocumentsControl.SetValue(true); + IRS1099PropagateVendSetup.VendorLedgerEntriesControl.SetValue(true); + IRS1099PropagateVendSetup.OK().Invoke(); + end; +} diff --git a/Apps/US/IRSForms/test/src/IRSReportingPeriodTests.Codeunit.al b/Apps/US/IRSForms/test/src/IRSReportingPeriodTests.Codeunit.al new file mode 100644 index 0000000000..451b1e5438 --- /dev/null +++ b/Apps/US/IRSForms/test/src/IRSReportingPeriodTests.Codeunit.al @@ -0,0 +1,169 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Finance.VAT.Reporting; + +codeunit 148016 "IRS Reporting Period Tests" +{ + Subtype = Test; + TestPermissions = Disabled; + + var + LibraryTestInitialize: Codeunit "Library - Test Initialize"; + LibraryUtility: Codeunit "Library - Utility"; + Assert: Codeunit Assert; + IsInitialized: Boolean; + StartingEndingDateOverlapErr: Label 'The starting date and ending date overlap with an existing reporting period.'; + + [Test] + [TransactionModel(TransactionModel::AutoRollback)] + procedure ReportingPeriodOverlapWithStartingDate() + var + IRSReportingPeriod: Record "IRS Reporting Period"; + begin + // [SCENARIO 495389] Stan cannot create reporting periods where starting date and ending date overlap with existing reporting periods + + Initialize(); + IRSReportingPeriod."No." := LibraryUtility.GenerateGUID(); + IRSReportingPeriod.Validate("Starting Date", 20240101D); + IRSReportingPeriod.Validate("Ending Date", 20241231D); + IRSReportingPeriod.Insert(); + + IRSReportingPeriod.Init(); + IRSReportingPeriod."No." := LibraryUtility.GenerateGUID(); + IRSReportingPeriod.Validate("Starting Date", 20230101D); + asserterror IRSReportingPeriod.Validate("Ending Date", 20240101D); + + Assert.ExpectedError(StartingEndingDateOverlapErr); + end; + + [Test] + [TransactionModel(TransactionModel::AutoRollback)] + procedure ReportingPeriodOverlapWithEndingDate() + var + IRSReportingPeriod: Record "IRS Reporting Period"; + begin + // [SCENARIO 495389] Stan cannot create reporting periods where starting date and ending date overlap with existing reporting periods + + Initialize(); + IRSReportingPeriod."No." := LibraryUtility.GenerateGUID(); + IRSReportingPeriod.Validate("Starting Date", 20240101D); + IRSReportingPeriod.Validate("Ending Date", 20241231D); + IRSReportingPeriod.Insert(); + + IRSReportingPeriod.Init(); + IRSReportingPeriod."No." := LibraryUtility.GenerateGUID(); + IRSReportingPeriod.Validate("Starting Date", 20241231D); + asserterror IRSReportingPeriod.Validate("Ending Date", 20250101D); + + Assert.ExpectedError(StartingEndingDateOverlapErr); + end; + + [Test] + [TransactionModel(TransactionModel::AutoRollback)] + procedure ReportingPeriodOverlapStartingInTheMiddle() + var + IRSReportingPeriod: Record "IRS Reporting Period"; + begin + // [SCENARIO 495389] Stan cannot create reporting periods where starting date and ending date overlap with existing reporting periods + + Initialize(); + IRSReportingPeriod."No." := LibraryUtility.GenerateGUID(); + IRSReportingPeriod.Validate("Starting Date", 20240101D); + IRSReportingPeriod.Validate("Ending Date", 20241231D); + IRSReportingPeriod.Insert(); + + IRSReportingPeriod.Init(); + IRSReportingPeriod."No." := LibraryUtility.GenerateGUID(); + IRSReportingPeriod.Validate("Starting Date", 20240501D); + asserterror IRSReportingPeriod.Validate("Ending Date", 20250101D); + + Assert.ExpectedError(StartingEndingDateOverlapErr); + end; + + [Test] + [TransactionModel(TransactionModel::AutoRollback)] + procedure ReportingPeriodOverlapEndinggInTheMiddle() + var + IRSReportingPeriod: Record "IRS Reporting Period"; + begin + // [SCENARIO 495389] Stan cannot create reporting periods where starting date and ending date overlap with existing reporting periods + + Initialize(); + IRSReportingPeriod."No." := LibraryUtility.GenerateGUID(); + IRSReportingPeriod.Validate("Starting Date", 20240101D); + IRSReportingPeriod.Validate("Ending Date", 20241231D); + IRSReportingPeriod.Insert(); + + IRSReportingPeriod.Init(); + IRSReportingPeriod."No." := LibraryUtility.GenerateGUID(); + IRSReportingPeriod.Validate("Starting Date", 20230101D); + asserterror IRSReportingPeriod.Validate("Ending Date", 20240501D); + + Assert.ExpectedError(StartingEndingDateOverlapErr); + end; + + [Test] + [TransactionModel(TransactionModel::AutoRollback)] + procedure ReportingPeriodBeforeExisting() + var + IRSReportingPeriod: Record "IRS Reporting Period"; + begin + // [SCENARIO 495389] Stan can create a new reporting period before the existing one + + Initialize(); + IRSReportingPeriod."No." := LibraryUtility.GenerateGUID(); + IRSReportingPeriod.Validate("Starting Date", 20240101D); + IRSReportingPeriod.Validate("Ending Date", 20241231D); + IRSReportingPeriod.Insert(); + + IRSReportingPeriod.Init(); + IRSReportingPeriod."No." := LibraryUtility.GenerateGUID(); + IRSReportingPeriod.Validate("Starting Date", 20230101D); + IRSReportingPeriod.Validate("Ending Date", 20231231D); + IRSReportingPeriod.Insert(); + + Assert.RecordCount(IRSReportingPeriod, 2); + end; + + [Test] + [TransactionModel(TransactionModel::AutoRollback)] + procedure ReportingPeriodAfterExisting() + var + IRSReportingPeriod: Record "IRS Reporting Period"; + begin + // [SCENARIO 495389] Stan can create a new reporting period after the existing one + + Initialize(); + IRSReportingPeriod."No." := LibraryUtility.GenerateGUID(); + IRSReportingPeriod.Validate("Starting Date", 20240101D); + IRSReportingPeriod.Validate("Ending Date", 20241231D); + IRSReportingPeriod.Insert(); + + IRSReportingPeriod.Init(); + IRSReportingPeriod."No." := LibraryUtility.GenerateGUID(); + IRSReportingPeriod.Validate("Starting Date", 20250101D); + IRSReportingPeriod.Validate("Ending Date", 20251231D); + IRSReportingPeriod.Insert(); + + Assert.RecordCount(IRSReportingPeriod, 2); + end; + + trigger OnRun() + begin + // [FEATURE] [1099] + end; + + local procedure Initialize() + begin + LibraryTestInitialize.OnTestInitialize(Codeunit::"IRS Reporting Period Tests"); + if IsInitialized then + exit; + LibraryTestInitialize.OnBeforeTestSuiteInitialize(Codeunit::"IRS Reporting Period Tests"); + + IsInitialized := true; + LibraryTestInitialize.OnAfterTestSuiteInitialize(Codeunit::"IRS Reporting Period Tests"); + end; + +} diff --git a/Apps/W1/AMCBanking365Fundamentals/app/app.json b/Apps/W1/AMCBanking365Fundamentals/app/app.json index f95228bb40..6d87dc97e5 100644 --- a/Apps/W1/AMCBanking365Fundamentals/app/app.json +++ b/Apps/W1/AMCBanking365Fundamentals/app/app.json @@ -1,8 +1,8 @@ { "id": "16319982-4995-4fb1-8fb2-2b1e13773e3b", - "platform": "24.0.0.0", - "application": "24.0.0.0", - "version": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", + "version": "25.0.0.0", "help": "https://go.microsoft.com/fwlink/?linkid=2101583", "resourceExposurePolicy": { "allowDebugging": false, diff --git a/Apps/W1/AMCBanking365Fundamentals/test/app.json b/Apps/W1/AMCBanking365Fundamentals/test/app.json index 9e7cf17e88..a4928e075e 100644 --- a/Apps/W1/AMCBanking365Fundamentals/test/app.json +++ b/Apps/W1/AMCBanking365Fundamentals/test/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "Tests for the AMC Banking 365 Fundamentals extension.", "description": "Tests for the AMC Banking 365 Fundamentals extension.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?LinkId=724010", "help": "https://go.microsoft.com/fwlink/?linkid=2101583", @@ -16,33 +16,33 @@ "id": "16319982-4995-4fb1-8fb2-2b1e13773e3b", "name": "AMC Banking 365 Fundamentals", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "9856ae4f-d1a7-46ef-89bb-6ef056398228", "name": "System Application Test Library", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5095f467-0a01-4b99-99d1-9ff1237d286f", "publisher": "Microsoft", "name": "Library Variable Storage", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "target": "OnPrem", "resourceExposurePolicy": { "allowDebugging": false, "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/W1/APIReportsFinance/App/app.json b/Apps/W1/APIReportsFinance/App/app.json index e5ad3cd014..3e4fb30ba7 100644 --- a/Apps/W1/APIReportsFinance/App/app.json +++ b/Apps/W1/APIReportsFinance/App/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "API Reports - Finance lets you easily access tha data that can be used to build different Financial Reports.", "description": "API Reports - Finance lets you easily access tha data that can be used to build different Financial Reports.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?linkid=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=2103698", @@ -13,9 +13,9 @@ "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "contextSensitiveHelpUrl": "https://go.microsoft.com/fwlink/?linkid=2134520", - "application": "24.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 30300, diff --git a/Apps/W1/APIV1/app/app.json b/Apps/W1/APIV1/app/app.json index 4ea97ad807..7a62f3ac73 100644 --- a/Apps/W1/APIV1/app/app.json +++ b/Apps/W1/APIV1/app/app.json @@ -2,7 +2,7 @@ "id": "8afe7b40-8c87-4beb-ada0-451d1761bf95", "name": "_Exclude_APIV1_", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "APIV1", "description": "APIV1", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -17,7 +17,7 @@ "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 2146, @@ -38,5 +38,5 @@ "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/W1/APIV1/app/src/Entitlements/DelegatedBCAdminAgentPartnerAPIV1.Entitlement.al b/Apps/W1/APIV1/app/src/Entitlements/DelegatedBCAdminAgentPartnerAPIV1.Entitlement.al new file mode 100644 index 0000000000..ad5246f803 --- /dev/null +++ b/Apps/W1/APIV1/app/src/Entitlements/DelegatedBCAdminAgentPartnerAPIV1.Entitlement.al @@ -0,0 +1,9 @@ +namespace Microsoft.API.V1; + +entitlement "Delegated BC Admin agent - Partner APIV1" +{ + Type = Role; + RoleType = Delegated; + Id = '00000000-0000-0000-0000-000000000010'; + ObjectEntitlements = "D365 APIV1"; +} diff --git a/Apps/W1/APIV1/app/src/Entitlements/InternalBCAdministratorAPIV1.Entitlement.al b/Apps/W1/APIV1/app/src/Entitlements/InternalBCAdministratorAPIV1.Entitlement.al new file mode 100644 index 0000000000..3cad811914 --- /dev/null +++ b/Apps/W1/APIV1/app/src/Entitlements/InternalBCAdministratorAPIV1.Entitlement.al @@ -0,0 +1,9 @@ +namespace Microsoft.API.V1; + +entitlement "Internal BC Administrator APIV1" +{ + Type = Role; + RoleType = Local; + Id = '963797fb-eb3b-4cde-8ce3-5878b3f32a3f'; + ObjectEntitlements = "D365 APIV1"; +} diff --git a/Apps/W1/APIV1/test/app.json b/Apps/W1/APIV1/test/app.json index 54ba93a502..645f2949c1 100644 --- a/Apps/W1/APIV1/test/app.json +++ b/Apps/W1/APIV1/test/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "Tests for the _Exclude_APIV1_ extension.", "description": "Tests for the _Exclude_APIV1_ extension.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2182906", "help": "https://go.microsoft.com/fwlink/?linkid=2206603", @@ -16,36 +16,36 @@ "id": "8afe7b40-8c87-4beb-ada0-451d1761bf95", "name": "_Exclude_APIV1_", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5095f467-0a01-4b99-99d1-9ff1237d286f", "publisher": "Microsoft", "name": "Library Variable Storage", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "9856ae4f-d1a7-46ef-89bb-6ef056398228", "publisher": "Microsoft", "name": "System Application Test Library", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "target": "OnPrem", "resourceExposurePolicy": { "allowDebugging": false, "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/W1/APIV1/test/src/APIV1EmployeesE2E.Codeunit.al b/Apps/W1/APIV1/test/src/APIV1EmployeesE2E.Codeunit.al index 4e5c353c0b..a5b64f62ce 100644 --- a/Apps/W1/APIV1/test/src/APIV1EmployeesE2E.Codeunit.al +++ b/Apps/W1/APIV1/test/src/APIV1EmployeesE2E.Codeunit.al @@ -40,14 +40,14 @@ codeunit 139722 "APIV1 - Employees E2E" procedure TestGetEmployee() var Employee: Record "Employee"; - NoSeriesManagement: Codeunit "NoSeriesManagement"; + NoSeries: Codeunit "No. Series"; ResponseText: Text; TargetURL: Text; begin // [SCENARIO] User can get an Employee with a GET request to the service. Initialize(); - NoSeriesManagement.GetNextNo(LibraryHumanResource.SetupEmployeeNumberSeries(), WORKDATE(), TRUE); + NoSeries.GetNextNo(LibraryHumanResource.SetupEmployeeNumberSeries()); // [GIVEN] An Employee exists in the system. CreateEmployee(Employee); @@ -92,7 +92,7 @@ codeunit 139722 "APIV1 - Employees E2E" var Employee: Record "Employee"; TempEmployee: Record "Employee" temporary; - NoSeriesManagement: Codeunit "NoSeriesManagement"; + NoSeries: Codeunit "No. Series"; RequestBody: Text; ResponseText: Text; TargetURL: Text; @@ -100,7 +100,7 @@ codeunit 139722 "APIV1 - Employees E2E" // [SCENARIO] User can modify an Employee through a PATCH request. Initialize(); - NoSeriesManagement.GetNextNo(LibraryHumanResource.SetupEmployeeNumberSeries(), WORKDATE(), TRUE); + NoSeries.GetNextNo(LibraryHumanResource.SetupEmployeeNumberSeries()); // [GIVEN] An Employee exists. CreateEmployee(Employee); @@ -172,10 +172,10 @@ codeunit 139722 "APIV1 - Employees E2E" local procedure GetEmployeeJSON(var Employee: Record "Employee") EmployeeJSON: Text var - NoSeriesManagement: Codeunit "NoSeriesManagement"; + NoSeries: Codeunit "No. Series"; begin IF Employee."No." = '' THEN - Employee."No." := NoSeriesManagement.GetNextNo(LibraryHumanResource.SetupEmployeeNumberSeries(), WORKDATE(), FALSE); + Employee."No." := NoSeries.PeekNextNo(LibraryHumanResource.SetupEmployeeNumberSeries()); IF Employee."First Name" = '' THEN Employee."First Name" := Employee."No."; EmployeeJSON := LibraryGraphMgt.AddPropertytoJSON('', 'number', Employee."No."); diff --git a/Apps/W1/APIV2/app/app.json b/Apps/W1/APIV2/app/app.json index 051d23e761..b56c79db98 100644 --- a/Apps/W1/APIV2/app/app.json +++ b/Apps/W1/APIV2/app/app.json @@ -2,7 +2,7 @@ "id": "10cb69d9-bc8a-4d27-970a-9e110e9db2a5", "name": "_Exclude_APIV2_", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "_Exclude_APIV2_", "description": "_Exclude_APIV2_", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -17,7 +17,7 @@ "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 2145, @@ -38,5 +38,5 @@ "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/W1/APIV2/app/src/Entitlements/DelegatedBCAdminAgentPartnerAPIV2.Entitlement.al b/Apps/W1/APIV2/app/src/Entitlements/DelegatedBCAdminAgentPartnerAPIV2.Entitlement.al new file mode 100644 index 0000000000..14671e90f4 --- /dev/null +++ b/Apps/W1/APIV2/app/src/Entitlements/DelegatedBCAdminAgentPartnerAPIV2.Entitlement.al @@ -0,0 +1,9 @@ +namespace Microsoft.API.V2; + +entitlement "Delegated BC Admin agent - Partner APIV2" +{ + Type = Role; + RoleType = Delegated; + Id = '00000000-0000-0000-0000-000000000010'; + ObjectEntitlements = "D365 APIV2"; +} diff --git a/Apps/W1/APIV2/app/src/Entitlements/InternalBCAdministratorAPIV2.Entitlement.al b/Apps/W1/APIV2/app/src/Entitlements/InternalBCAdministratorAPIV2.Entitlement.al new file mode 100644 index 0000000000..82f5415f29 --- /dev/null +++ b/Apps/W1/APIV2/app/src/Entitlements/InternalBCAdministratorAPIV2.Entitlement.al @@ -0,0 +1,9 @@ +namespace Microsoft.API.V2; + +entitlement "Internal BC Administrator APIV2" +{ + Type = Role; + RoleType = Local; + Id = '963797fb-eb3b-4cde-8ce3-5878b3f32a3f'; + ObjectEntitlements = "D365 APIV2"; +} diff --git a/Apps/W1/APIV2/app/src/pages/APIV2Contacts.Page.al b/Apps/W1/APIV2/app/src/pages/APIV2Contacts.Page.al index 2ddb59b419..b81f583b3a 100644 --- a/Apps/W1/APIV2/app/src/pages/APIV2Contacts.Page.al +++ b/Apps/W1/APIV2/app/src/pages/APIV2Contacts.Page.al @@ -58,6 +58,16 @@ page 30071 "APIV2 - Contacts" RegisterFieldSet(Rec.FieldNo(Name)); end; } + field(jobTitle; Rec."Job Title") + { + Caption = 'Job Title'; + ShowMandatory = true; + + trigger OnValidate() + begin + RegisterFieldSet(Rec.FieldNo("Job Title")); + end; + } field(companyNumber; Rec."Company No.") { Caption = 'Company Number'; diff --git a/Apps/W1/APIV2/app/src/pages/APIV2DisputeStatus.Page.al b/Apps/W1/APIV2/app/src/pages/APIV2DisputeStatus.Page.al new file mode 100644 index 0000000000..ecdcfda8cb --- /dev/null +++ b/Apps/W1/APIV2/app/src/pages/APIV2DisputeStatus.Page.al @@ -0,0 +1,40 @@ +namespace Microsoft.API.V2; +using Microsoft.Sales.Customer; + + +page 30088 "APIV2 - Dispute Status" +{ + DelayedInsert = true; + APIVersion = 'v2.0'; + EntityCaption = 'Dispute Status'; + EntitySetCaption = 'Dispute Status'; + PageType = API; + ODataKeyFields = SystemId; + EntityName = 'disputeStatus'; + EntitySetName = 'disputeStatus'; + SourceTable = "Dispute Status"; + Extensible = false; + + layout + { + area(Content) + { + repeater(Group) + { + field(id; Rec.SystemId) + { + Caption = 'Id'; + Editable = false; + } + field(code; Rec.Code) + { + Caption = 'Code'; + } + field(displayName; Rec.Description) + { + Caption = 'Description'; + } + } + } + } +} \ No newline at end of file diff --git a/Apps/W1/APIV2/app/src/pages/APIV2SalesInvoices.Page.al b/Apps/W1/APIV2/app/src/pages/APIV2SalesInvoices.Page.al index 7f2f02d3f8..2e24f8b351 100644 --- a/Apps/W1/APIV2/app/src/pages/APIV2SalesInvoices.Page.al +++ b/Apps/W1/APIV2/app/src/pages/APIV2SalesInvoices.Page.al @@ -98,6 +98,16 @@ page 30012 "APIV2 - Sales Invoices" RegisterFieldSet(Rec.FieldNo("Due Date")); end; } + + field(promisedPayDate; Rec."Promised Pay Date") + { + Caption = 'Promised Pay Date'; + trigger OnValidate() + begin + Rec.TestField(Posted); + RegisterFieldSet(Rec.FieldNo("Promised Pay Date")); + end; + } field(customerPurchaseOrderReference; Rec."Your Reference") { Caption = 'Customer Purchase Order Reference',; @@ -485,6 +495,40 @@ page 30012 "APIV2 - Sales Invoices" RegisterFieldSet(Rec.FieldNo("Salesperson Code")); end; } + field(disputeStatusId; Rec."Dispute Status Id") + { + Caption = 'Dispute Status Id'; + + trigger OnValidate() + begin + Rec.TestField(Posted); + if Rec."Dispute Status Id" = BlankGUID then + Rec."Dispute Status" := '' + else begin + if not DisputeStatus.GetBySystemId(Rec."Dispute Status Id") then + Error(DisputeStatusIdDoesNotMatchADisputeStatusErr); + + Rec."Dispute Status" := DisputeStatus.Code; + end; + + RegisterFieldSet(Rec.FieldNo("Dispute Status Id")); + RegisterFieldSet(Rec.FieldNo("Dispute Status")); + end; + } + field(disputeStatus; Rec."Dispute Status") + { + Caption = 'Dispute Status'; + trigger OnValidate() + begin + Rec.TestField(Posted); + if not DisputeStatus.Get(Rec."Dispute Status") then + Error(CouldNotFindDisputeStatusErr); + + Rec."Dispute Status Id" := DisputeStatus.SystemId; + RegisterFieldSet(Rec.FieldNo("Dispute Status Id")); + RegisterFieldSet(Rec.FieldNo("Dispute Status")); + end; + } field(pricesIncludeTax; Rec."Prices Including VAT") { Caption = 'Prices Include Tax'; @@ -679,6 +723,7 @@ page 30012 "APIV2 - Sales Invoices" TempFieldBuffer: Record 8450 temporary; SellToCustomer: Record "Customer"; BillToCustomer: Record "Customer"; + DisputeStatus: Record "Dispute Status"; Currency: Record "Currency"; PaymentTerms: Record "Payment Terms"; ShipmentMethod: Record "Shipment Method"; @@ -693,12 +738,14 @@ page 30012 "APIV2 - Sales Invoices" BillToCustomerValuesDontMatchErr: Label 'The bill-to customer values do not match to a specific Customer.'; CouldNotFindSellToCustomerErr: Label 'The sell-to customer cannot be found.'; CouldNotFindBillToCustomerErr: Label 'The bill-to customer cannot be found.'; + CouldNotFindDisputeStatusErr: Label 'The dispute status cannot be found.'; CurrencyValuesDontMatchErr: Label 'The currency values do not match to a specific Currency.'; CurrencyIdDoesNotMatchACurrencyErr: Label 'The "currencyId" does not match to a Currency.', Comment = 'currencyId is a field name and should not be translated.'; CurrencyCodeDoesNotMatchACurrencyErr: Label 'The "currencyCode" does not match to a Currency.', Comment = 'currencyCode is a field name and should not be translated.'; BlankGUID: Guid; PaymentTermsIdDoesNotMatchAPaymentTermsErr: Label 'The "paymentTermsId" does not match to a Payment Terms.', Comment = 'paymentTermsId is a field name and should not be translated.'; ShipmentMethodIdDoesNotMatchAShipmentMethodErr: Label 'The "shipmentMethodId" does not match to a Shipment Method.', Comment = 'shipmentMethodId is a field name and should not be translated.'; + DisputeStatusIdDoesNotMatchADisputeStatusErr: Label 'The "disputeStatusId" does not match to a Dispute Status.', Comment = 'disputeStatusId is a field name and should not be translated.'; PermissionFilterFormatTxt: Label '<>%1&<>%2', Locked = true; PermissionInvoiceFilterformatTxt: Label '<>%1&<>%2&<>%3&<>%4', Locked = true; DiscountAmountSet: Boolean; diff --git a/Apps/W1/APIV2/test/app.json b/Apps/W1/APIV2/test/app.json index c84816667e..066dd3a4fb 100644 --- a/Apps/W1/APIV2/test/app.json +++ b/Apps/W1/APIV2/test/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "Tests for the _Exclude_APIV2_ extension.", "description": "Tests for the _Exclude_APIV2_ extension.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2182906", "help": "https://go.microsoft.com/fwlink/?linkid=2206519", @@ -16,36 +16,36 @@ "id": "10cb69d9-bc8a-4d27-970a-9e110e9db2a5", "name": "_Exclude_APIV2_", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "9856ae4f-d1a7-46ef-89bb-6ef056398228", "name": "System Application Test Library", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5095f467-0a01-4b99-99d1-9ff1237d286f", "publisher": "Microsoft", "name": "Library Variable Storage", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "target": "OnPrem", "resourceExposurePolicy": { "allowDebugging": false, "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/W1/APIV2/test/src/APIV2ContactsE2E.Codeunit.al b/Apps/W1/APIV2/test/src/APIV2ContactsE2E.Codeunit.al index 44cbb5df5a..5f8ef89476 100644 --- a/Apps/W1/APIV2/test/src/APIV2ContactsE2E.Codeunit.al +++ b/Apps/W1/APIV2/test/src/APIV2ContactsE2E.Codeunit.al @@ -12,7 +12,6 @@ codeunit 139866 "APIV2 - Contacts E2E" var Assert: Codeunit Assert; - NoSeriesManagement: Codeunit NoSeriesManagement; LibraryGraphMgt: Codeunit "Library - Graph Mgt"; LibraryUtility: Codeunit "Library - Utility"; LibraryMarketing: Codeunit "Library - Marketing"; @@ -33,12 +32,13 @@ codeunit 139866 "APIV2 - Contacts E2E" procedure TestGetSimpleContact() var Contact: Record "Contact"; + NoSeries: Codeunit "No. Series"; Response: Text; TargetURL: Text; begin // [SCENARIO] User can get a simple contact with a GET request to the service. Initialize(); - NoSeriesManagement.GetNextNo(SetupContactNumberSeries(), WorkDate(), true); + NoSeries.GetNextNo(SetupContactNumberSeries()); // [GIVEN] A contact exists in the system. CreateSimpleContact(Contact); @@ -55,12 +55,13 @@ codeunit 139866 "APIV2 - Contacts E2E" procedure TestGetContactWithAddressAndSpecialCharacters() var Contact: Record "Contact"; + NoSeries: Codeunit "No. Series"; Response: Text; TargetURL: Text; begin // [SCENARIO 184717] User can get a Contact that has non-empty values for complex type fields. Initialize(); - NoSeriesManagement.GetNextNo(SetupContactNumberSeries(), WorkDate(), true); + NoSeries.GetNextNo(SetupContactNumberSeries()); // [GIVEN] A Contact exists and has values assigned to some of the fields contained in complex types. CreateContactWithAddress(Contact); @@ -105,13 +106,14 @@ codeunit 139866 "APIV2 - Contacts E2E" var Contact: Record "Contact"; TempContact: Record "Contact" temporary; + NoSeries: Codeunit "No. Series"; RequestBody: Text; Response: Text; TargetURL: Text; begin // [SCENARIO 184717] User can modify address in a Contact through a PATCH request. Initialize(); - NoSeriesManagement.GetNextNo(SetupContactNumberSeries(), WorkDate(), true); + NoSeries.GetNextNo(SetupContactNumberSeries()); // [GIVEN] A Contact exists with an address. CreateContactWithAddress(Contact); @@ -182,10 +184,10 @@ codeunit 139866 "APIV2 - Contacts E2E" local procedure GetSimpleContactJSON(var Contact: Record "Contact") ContactJson: Text var - NoSeriesManagement2: Codeunit "NoSeriesManagement"; + NoSeries: Codeunit "No. Series"; begin if Contact."No." = '' then - Contact."No." := NoSeriesManagement2.GetNextNo(SetupContactNumberSeries(), WorkDate(), false); + Contact."No." := NoSeries.PeekNextNo(SetupContactNumberSeries()); if Contact.Name = '' then Contact.Name := LibraryUtility.GenerateGUID(); ContactJson := LibraryGraphMgt.AddPropertytoJSON(ContactJson, 'number', Contact."No."); diff --git a/Apps/W1/APIV2/test/src/APIV2EmployeesE2E.Codeunit.al b/Apps/W1/APIV2/test/src/APIV2EmployeesE2E.Codeunit.al index fd0dff8aa0..c103075aaa 100644 --- a/Apps/W1/APIV2/test/src/APIV2EmployeesE2E.Codeunit.al +++ b/Apps/W1/APIV2/test/src/APIV2EmployeesE2E.Codeunit.al @@ -40,14 +40,14 @@ codeunit 139822 "APIV2 - Employees E2E" procedure TestGetEmployee() var Employee: Record "Employee"; - NoSeriesManagement: Codeunit "NoSeriesManagement"; + NoSeries: Codeunit "No. Series"; ResponseText: Text; TargetURL: Text; begin // [SCENARIO] User can get an Employee with a GET request to the service. Initialize(); - NoSeriesManagement.GetNextNo(LibraryHumanResource.SetupEmployeeNumberSeries(), WorkDate(), true); + NoSeries.GetNextNo(LibraryHumanResource.SetupEmployeeNumberSeries()); // [GIVEN] An Employee exists in the system. CreateEmployee(Employee); @@ -92,7 +92,7 @@ codeunit 139822 "APIV2 - Employees E2E" var Employee: Record "Employee"; TempEmployee: Record "Employee" temporary; - NoSeriesManagement: Codeunit "NoSeriesManagement"; + NoSeries: Codeunit "No. Series"; RequestBody: Text; ResponseText: Text; TargetURL: Text; @@ -100,7 +100,7 @@ codeunit 139822 "APIV2 - Employees E2E" // [SCENARIO] User can modify an Employee through a PATCH request. Initialize(); - NoSeriesManagement.GetNextNo(LibraryHumanResource.SetupEmployeeNumberSeries(), WorkDate(), true); + NoSeries.GetNextNo(LibraryHumanResource.SetupEmployeeNumberSeries()); // [GIVEN] An Employee exists. CreateEmployee(Employee); @@ -172,10 +172,10 @@ codeunit 139822 "APIV2 - Employees E2E" local procedure GetEmployeeJSON(var Employee: Record "Employee") EmployeeJSON: Text var - NoSeriesManagement: Codeunit "NoSeriesManagement"; + NoSeries: Codeunit "No. Series"; begin if Employee."No." = '' then - Employee."No." := NoSeriesManagement.GetNextNo(LibraryHumanResource.SetupEmployeeNumberSeries(), WorkDate(), false); + Employee."No." := NoSeries.PeekNextNo(LibraryHumanResource.SetupEmployeeNumberSeries()); if Employee."First Name" = '' then Employee."First Name" := Employee."No."; EmployeeJSON := LibraryGraphMgt.AddPropertytoJSON('', 'number', Employee."No."); diff --git a/Apps/W1/AuditFileExport/app/app.json b/Apps/W1/AuditFileExport/app/app.json index ca935f4f36..55c4c08316 100644 --- a/Apps/W1/AuditFileExport/app/app.json +++ b/Apps/W1/AuditFileExport/app/app.json @@ -2,7 +2,7 @@ "id": "a41b0c3e-bf1c-4c97-ad1b-b430a3933ada", "name": "Audit File Export", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Audit File Export app provides an interface for dependent extensions that are used to export accounting and tax data in specific formats.", "description": "Audit File Export is an app used for exporting the accounting and tax information of a company to the tax authorities. This app can work with different standardized audit file formats (SAF-T, SIE, etc.) for the electronic exchange of reliable accounting data between organizations and/or tax authorities (or external auditors).", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -17,8 +17,8 @@ "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 5260, diff --git a/Apps/W1/AuditFileExport/test/app.json b/Apps/W1/AuditFileExport/test/app.json index 442a0e0127..ca8a3d7719 100644 --- a/Apps/W1/AuditFileExport/test/app.json +++ b/Apps/W1/AuditFileExport/test/app.json @@ -2,7 +2,7 @@ "id": "5e327e42-4ec3-4667-8d20-cccd38f867c6", "name": "Audit File Export Tests", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Tests for the Audit File Export extension.", "description": "Tests for the Audit File Export extension.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -10,26 +10,26 @@ "help": "https://go.microsoft.com/fwlink/?LinkId=724011", "url": "https://go.microsoft.com/fwlink/?LinkId=724011", "logo": "ExtensionLogo.png", - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "dependencies": [ { "id": "a41b0c3e-bf1c-4c97-ad1b-b430a3933ada", "name": "Audit File Export", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "9856ae4f-d1a7-46ef-89bb-6ef056398228", "name": "System Application Test Library", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "idRanges": [ diff --git a/Apps/W1/AutomaticAccountCodes/app/app.json b/Apps/W1/AutomaticAccountCodes/app/app.json index b79a02a5c5..3bdadbec4d 100644 --- a/Apps/W1/AutomaticAccountCodes/app/app.json +++ b/Apps/W1/AutomaticAccountCodes/app/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "Automatic account codes are used to automate postings related to payroll overhead.", "description": "When posting total salary expenses at the end of the month, automatic account codes can be used to assign a percentage of the total salary to automatically post as overhead expenses.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=2204541", @@ -14,7 +14,7 @@ "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 4850, @@ -26,6 +26,6 @@ "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0", + "application": "25.0.0.0", "target": "Cloud" } \ No newline at end of file diff --git a/Apps/W1/AutomaticAccountCodes/test/app.json b/Apps/W1/AutomaticAccountCodes/test/app.json index f56ee87f60..0adcd972aa 100644 --- a/Apps/W1/AutomaticAccountCodes/test/app.json +++ b/Apps/W1/AutomaticAccountCodes/test/app.json @@ -2,7 +2,7 @@ "id": "33d2d6f3-baee-40a8-b699-fa3b61506f2c", "name": "Automatic Account Codes Tests", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Tests for the Microsoft Automatic Account Codes extension.", "description": "Tests for the Microsoft Automatic Account Codes extension.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -10,32 +10,32 @@ "help": "https://go.microsoft.com/fwlink/?linkid=2179727", "url": "https://go.microsoft.com/fwlink/?LinkId=724011", "logo": "ExtensionLogo.png", - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "dependencies": [ { "id": "639580c8-7356-11ed-a1eb-0242ac120002", "name": "Automatic Account Codes", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "9856ae4f-d1a7-46ef-89bb-6ef056398228", "name": "System Application Test Library", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5095f467-0a01-4b99-99d1-9ff1237d286f", "publisher": "Microsoft", "name": "Library Variable Storage", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "idRanges": [ diff --git a/Apps/W1/BankAccRecWithAI/app/app.json b/Apps/W1/BankAccRecWithAI/app/app.json index 71648aa4c2..396a03e91d 100644 --- a/Apps/W1/BankAccRecWithAI/app/app.json +++ b/Apps/W1/BankAccRecWithAI/app/app.json @@ -1,38 +1,45 @@ { - "id": "63c9fbe6-d4f3-458c-8c25-644c90a0874a", - "name": "Bank Account Reconciliation With AI", - "publisher": "Microsoft", - "version": "24.0.0.0", - "brief": "Bank Account Reconciliation With AI", - "description": "Bank Account Reconciliation With AI", - "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", - "EULA": "https://go.microsoft.com/fwlink/?linkid=2182906", - "help": "https://go.microsoft.com/fwlink/?linkid=2206176", - "url": "https://go.microsoft.com/fwlink/?LinkId=724011", - "logo": "ExtensionLogo.png", - "dependencies": [], - "internalsVisibleTo": [ - { - "id": "2932b2a8-7399-4f8c-b1c0-1acfc2014ffb", - "name": "Bank Account Reconciliation With AI - Tests", - "publisher": "Microsoft" - } - ], - "screenshots": [], - "platform": "24.0.0.0", - "idRanges": [ - { - "from": 7250, - "to": 7259 - } - ], - "contextSensitiveHelpUrl": "https://go.microsoft.com/fwlink/?linkid=2206176", - "resourceExposurePolicy": { - "allowDebugging": false, - "allowDownloadingSource": false, - "includeSourceInSymbolFile": false - }, - "target": "OnPrem", - "application": "24.0.0.0", - "features": ["TranslationFile", "GenerateCaptions"] -} + "id": "63c9fbe6-d4f3-458c-8c25-644c90a0874a", + "name": "Bank Account Reconciliation With AI", + "publisher": "Microsoft", + "version": "25.0.0.0", + "brief": "Bank Account Reconciliation With AI", + "description": "Bank Account Reconciliation With AI", + "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", + "EULA": "https://go.microsoft.com/fwlink/?linkid=2182906", + "help": "https://go.microsoft.com/fwlink/?linkid=2206176", + "url": "https://go.microsoft.com/fwlink/?LinkId=724011", + "logo": "ExtensionLogo.png", + "dependencies": [ + + ], + "internalsVisibleTo": [ + { + "id": "2932b2a8-7399-4f8c-b1c0-1acfc2014ffb", + "name": "Bank Account Reconciliation With AI Tests", + "publisher": "Microsoft" + } + ], + "screenshots": [ + + ], + "platform": "25.0.0.0", + "idRanges": [ + { + "from": 7250, + "to": 7259 + } + ], + "contextSensitiveHelpUrl": "https://go.microsoft.com/fwlink/?linkid=2206176", + "resourceExposurePolicy": { + "allowDebugging": false, + "allowDownloadingSource": false, + "includeSourceInSymbolFile": false + }, + "target": "OnPrem", + "application": "25.0.0.0", + "features": [ + "TranslationFile", + "GenerateCaptions" + ] +} \ No newline at end of file diff --git a/Apps/W1/BankAccRecWithAI/app/src/BankAccRecTransToAcc.Codeunit.al b/Apps/W1/BankAccRecWithAI/app/src/BankAccRecTransToAcc.Codeunit.al index 1154ecec0c..6549f3e793 100644 --- a/Apps/W1/BankAccRecWithAI/app/src/BankAccRecTransToAcc.Codeunit.al +++ b/Apps/W1/BankAccRecWithAI/app/src/BankAccRecTransToAcc.Codeunit.al @@ -70,7 +70,7 @@ codeunit 7251 "Bank Acc. Rec. Trans. to Acc." BestGLAccountNo := ''; BankAccReconciliationLine.MarkedOnly(true); if not BankAccReconciliationLine.IsEmpty() then begin - AzureOpenAI.SetAuthorization(Enum::"AOAI Model Type"::"Chat Completions", AOAIDeployments.GetGPT40613()); + AzureOpenAI.SetAuthorization(Enum::"AOAI Model Type"::"Chat Completions", AOAIDeployments.GetGPT4Latest()); AzureOpenAI.SetCopilotCapability(Enum::"Copilot Capability"::"Bank Account Reconciliation"); AOAIChatCompletionParams.SetMaxTokens(BankRecAIMatchingImpl.MaxTokens()); AOAIChatCompletionParams.SetTemperature(0); @@ -229,18 +229,36 @@ codeunit 7251 "Bank Acc. Rec. Trans. to Acc." procedure BuildBankRecStatementLines(var BankAccReconciliationLine: Record "Bank Acc. Reconciliation Line"; var TempBankStatementMatchingBuffer: Record "Bank Statement Matching Buffer" temporary): Text var + GLAccount: Record "G/L Account"; BankRecAIMatchingImpl: Codeunit "Bank Rec. AI Matching Impl."; StatementLines: Text; + InitialGLAccountFound: Boolean; + InitialGLAccountInsertDone: Boolean; begin if (StatementLines = '') then StatementLines := '**Statement Lines**:\n"""\n'; + GLAccount.SetRange("Direct Posting", true); + if GLAccount.FindFirst() then + if not BankRecAIMatchingImpl.HasReservedWords(GLAccount.Name) then + InitialGLAccountFound := true; + + BankAccReconciliationLine.Ascending(true); if BankAccReconciliationLine.FindSet() then repeat if not BankRecAIMatchingImpl.HasReservedWords(BankAccReconciliationLine.Description) then begin TempBankStatementMatchingBuffer.Reset(); TempBankStatementMatchingBuffer.SetRange("Line No.", BankAccReconciliationLine."Statement Line No."); if TempBankStatementMatchingBuffer.IsEmpty() then begin + if InitialGLAccountFound then + if not InitialGLAccountInsertDone then begin + if BankAccReconciliationLine."Statement Line No." > 1 then begin + StatementLines += '#Id: ' + Format(BankAccReconciliationLine."Statement Line No." - 1); + StatementLines += ', Description: ' + GLAccount.Name; + StatementLines += '\n'; + end; + InitialGLAccountInsertDone := true; + end; StatementLines += '#Id: ' + Format(BankAccReconciliationLine."Statement Line No."); StatementLines += ', Description: ' + BankAccReconciliationLine.Description; StatementLines += '\n'; diff --git a/Apps/W1/BankAccRecWithAI/app/src/BankAccReconciliationListExt.PageExt.al b/Apps/W1/BankAccRecWithAI/app/src/BankAccReconciliationListExt.PageExt.al index 9edca3ba76..cf52af64cd 100644 --- a/Apps/W1/BankAccRecWithAI/app/src/BankAccReconciliationListExt.PageExt.al +++ b/Apps/W1/BankAccRecWithAI/app/src/BankAccReconciliationListExt.PageExt.al @@ -8,12 +8,24 @@ pageextension 7254 BankAccReconciliationListExt extends "Bank Acc. Reconciliatio { actions { - addbefore(ChangeStatementNo) +#if not CLEAN24 + addbefore(Category_Posting) + { + actionref("Reconcile With Copilot_Promoted"; "Reconcile With Copilot") + { + Visible = false; + ObsoleteReason = 'Action in the Prompting area.'; + ObsoleteState = Pending; + ObsoleteTag = '24.0'; + } + } +#endif + addfirst(Prompting) { action("Reconcile With Copilot") { ApplicationArea = All; - Caption = 'Reconcile with Copilot'; + Caption = 'Reconcile'; #pragma warning disable AL0482 Image = SparkleFilled; #pragma warning restore AL0482 @@ -40,12 +52,6 @@ pageextension 7254 BankAccReconciliationListExt extends "Bank Acc. Reconciliatio end; } } - addbefore(Category_Posting) - { - actionref("Reconcile With Copilot_Promoted"; "Reconcile With Copilot") - { - } - } } trigger OnOpenPage() diff --git a/Apps/W1/BankAccRecWithAI/app/src/BankRecAIMatchingImpl.Codeunit.al b/Apps/W1/BankAccRecWithAI/app/src/BankRecAIMatchingImpl.Codeunit.al index f5204a5384..7335381182 100644 --- a/Apps/W1/BankAccRecWithAI/app/src/BankRecAIMatchingImpl.Codeunit.al +++ b/Apps/W1/BankAccRecWithAI/app/src/BankRecAIMatchingImpl.Codeunit.al @@ -180,7 +180,7 @@ codeunit 7250 "Bank Rec. AI Matching Impl." begin // this is because we are using GPT4 which has a 32K token limit // on top of that, we are setting aside a number of tokens for the response in MaxTokens()) - exit(22000); + exit(18000); end; procedure MaxTokens(): Integer @@ -277,7 +277,7 @@ codeunit 7250 "Bank Rec. AI Matching Impl." exit; // Generate OpenAI Completion - AzureOpenAI.SetAuthorization(Enum::"AOAI Model Type"::"Chat Completions", AOAIDeployments.GetGPT40613()); + AzureOpenAI.SetAuthorization(Enum::"AOAI Model Type"::"Chat Completions", AOAIDeployments.GetGPT4Latest()); AzureOpenAI.SetCopilotCapability(Enum::"Copilot Capability"::"Bank Account Reconciliation"); AOAIChatCompletionParams.SetMaxTokens(MaxTokens()); AOAIChatCompletionParams.SetTemperature(0); diff --git a/Apps/W1/BankAccRecWithAI/test/app.json b/Apps/W1/BankAccRecWithAI/test/app.json index 5cb4ec0629..7b0502600e 100644 --- a/Apps/W1/BankAccRecWithAI/test/app.json +++ b/Apps/W1/BankAccRecWithAI/test/app.json @@ -1,54 +1,58 @@ { - "id": "2932b2a8-7399-4f8c-b1c0-1acfc2014ffb", - "name": "Bank Account Reconciliation With AI Tests", - "publisher": "Microsoft", - "version": "24.0.0.0", - "brief": "Bank Account Reconciliation With AI Tests", - "description": "Bank Account Reconciliation With AI Tests", - "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", - "EULA": "https://go.microsoft.com/fwlink/?linkid=2182906", - "help": "https://go.microsoft.com/fwlink/?linkid=2206176", - "url": "https://go.microsoft.com/fwlink/?LinkId=724011", - "logo": "ExtensionLogo.png", - "dependencies": [ - { - "id": "63c9fbe6-d4f3-458c-8c25-644c90a0874a", - "name": "Bank Account Reconciliation With AI", - "publisher": "Microsoft", - "version": "24.0.0.0" - }, - { - "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", - "name": "Tests-TestLibraries", - "publisher": "Microsoft", - "version": "24.0.0.0" - }, - { - "id": "5095f467-0a01-4b99-99d1-9ff1237d286f", - "publisher": "Microsoft", - "name": "Library Variable Storage", - "version": "24.0.0.0" - } - ], - "internalsVisibleTo": [], - "screenshots": [], - "platform": "24.0.0.0", - "idRanges": [ - { - "from": 139777, - "to": 139777 - } - ], - "contextSensitiveHelpUrl": "https://go.microsoft.com/fwlink/?linkid=2206176", - "resourceExposurePolicy": { - "allowDebugging": false, - "allowDownloadingSource": false, - "includeSourceInSymbolFile": false - }, - "target": "Cloud", - "application": "24.0.0.0", - "features": [ - "TranslationFile", - "GenerateCaptions" - ] + "id": "2932b2a8-7399-4f8c-b1c0-1acfc2014ffb", + "name": "Bank Account Reconciliation With AI Tests", + "publisher": "Microsoft", + "version": "25.0.0.0", + "brief": "Bank Account Reconciliation With AI Tests", + "description": "Bank Account Reconciliation With AI Tests", + "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", + "EULA": "https://go.microsoft.com/fwlink/?linkid=2182906", + "help": "https://go.microsoft.com/fwlink/?linkid=2206176", + "url": "https://go.microsoft.com/fwlink/?LinkId=724011", + "logo": "ExtensionLogo.png", + "dependencies": [ + { + "id": "63c9fbe6-d4f3-458c-8c25-644c90a0874a", + "name": "Bank Account Reconciliation With AI", + "publisher": "Microsoft", + "version": "25.0.0.0" + }, + { + "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", + "name": "Tests-TestLibraries", + "publisher": "Microsoft", + "version": "25.0.0.0" + }, + { + "id": "5095f467-0a01-4b99-99d1-9ff1237d286f", + "publisher": "Microsoft", + "name": "Library Variable Storage", + "version": "25.0.0.0" + } + ], + "internalsVisibleTo": [ + + ], + "screenshots": [ + + ], + "platform": "25.0.0.0", + "idRanges": [ + { + "from": 139777, + "to": 139777 + } + ], + "contextSensitiveHelpUrl": "https://go.microsoft.com/fwlink/?linkid=2206176", + "resourceExposurePolicy": { + "allowDebugging": false, + "allowDownloadingSource": false, + "includeSourceInSymbolFile": false + }, + "target": "Cloud", + "application": "25.0.0.0", + "features": [ + "TranslationFile", + "GenerateCaptions" + ] } \ No newline at end of file diff --git a/Apps/W1/BankDeposits/app/app.json b/Apps/W1/BankDeposits/app/app.json index a62931e5d2..f5f0ed31c5 100644 --- a/Apps/W1/BankDeposits/app/app.json +++ b/Apps/W1/BankDeposits/app/app.json @@ -2,7 +2,7 @@ "id": "7a129d06-5fd6-4fb6-b82b-0bf539c779d0", "name": "_Exclude_Bank Deposits", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "_Exclude_Bank Deposits", "description": "_Exclude_Bank Deposits", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -23,7 +23,7 @@ "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 1, @@ -37,7 +37,7 @@ "includeSourceInSymbolFile": true }, "target": "Cloud", - "application": "24.0.0.0", + "application": "25.0.0.0", "features": [ "TranslationFile", "GenerateCaptions" diff --git a/Apps/W1/BankDeposits/app/src/tables/BankDepositHeader.Table.al b/Apps/W1/BankDeposits/app/src/tables/BankDepositHeader.Table.al index 34e62eeb26..7eda8b4fa5 100644 --- a/Apps/W1/BankDeposits/app/src/tables/BankDepositHeader.Table.al +++ b/Apps/W1/BankDeposits/app/src/tables/BankDepositHeader.Table.al @@ -24,6 +24,8 @@ table 1690 "Bank Deposit Header" Caption = 'No.'; trigger OnValidate() + var + NoSeries: Codeunit "No. Series"; begin if "No." <> xRec."No." then begin SalesReceivablesSetup.Get(); @@ -323,8 +325,9 @@ table 1690 "Bank Deposit Header" SalesReceivablesSetup: Record "Sales & Receivables Setup"; BankDepositHeader: Record "Bank Deposit Header"; GenJournalBatch: Record "Gen. Journal Batch"; +#if not CLEAN24 NoSeriesManagement: Codeunit NoSeriesManagement; - NoSeries: Codeunit "No. Series"; +#endif DimensionManagement: Codeunit DimensionManagement; GenJnlManagement: Codeunit GenJnlManagement; PostingDescriptionTxt: Label 'Deposit %1 %2', Comment = '%1 - the caption of field No.; %2 - the value of field No.'; @@ -336,6 +339,7 @@ table 1690 "Bank Deposit Header" local procedure InitInsert() var + NoSeries: Codeunit "No. Series"; NoSeriesCode: Code[20]; IsHandled: Boolean; begin @@ -499,12 +503,13 @@ table 1690 "Bank Deposit Header" internal procedure AssistEdit(OldBankDepositHeader: Record "Bank Deposit Header"): Boolean var LocalBankDepositHeader: Record "Bank Deposit Header"; + NoSeries: Codeunit "No. Series"; begin LocalBankDepositHeader := Rec; SalesReceivablesSetup.Get(); SalesReceivablesSetup.TestField("Bank Deposit Nos."); - if NoSeriesManagement.SelectSeries(SalesReceivablesSetup."Bank Deposit Nos.", OldBankDepositHeader."No. Series", LocalBankDepositHeader."No. Series") then begin - NoSeriesManagement.SetSeries(LocalBankDepositHeader."No."); + if NoSeries.LookupRelatedNoSeries(SalesReceivablesSetup."Bank Deposit Nos.", OldBankDepositHeader."No. Series", LocalBankDepositHeader."No. Series") then begin + LocalBankDepositHeader."No." := NoSeries.GetNextNo(LocalBankDepositHeader."No. Series"); Rec := LocalBankDepositHeader; exit(true); end; diff --git a/Apps/W1/BankDeposits/test/app.json b/Apps/W1/BankDeposits/test/app.json index 8a7ee883c7..f989f9d95f 100644 --- a/Apps/W1/BankDeposits/test/app.json +++ b/Apps/W1/BankDeposits/test/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "Tests for the _Exclude_Bank Deposits extension.", "description": "Tests for the _Exclude_Bank Deposits extension.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2182906", "help": "https://go.microsoft.com/fwlink/?linkid=2206176", @@ -16,30 +16,30 @@ "id": "7a129d06-5fd6-4fb6-b82b-0bf539c779d0", "name": "_Exclude_Bank Deposits", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5095f467-0a01-4b99-99d1-9ff1237d286f", "publisher": "Microsoft", "name": "Library Variable Storage", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "target": "Cloud", "resourceExposurePolicy": { "allowDebugging": false, "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/W1/BasicExperience/app/app.json b/Apps/W1/BasicExperience/app/app.json index b2ae6b6abc..0cea8f7d54 100644 --- a/Apps/W1/BasicExperience/app/app.json +++ b/Apps/W1/BasicExperience/app/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "The Basic Experience extension provides core financial capabilities for small businesses.", "description": "The Basic Experience gives small companies access to the Business Central features that are at the absolute core of doing business. For example, when you install this extension you can invoice customers, pay vendors, manage inventory, and keep your finances in order.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2130900", "help": "https://go.microsoft.com/fwlink/?linkid=2130800", @@ -14,7 +14,7 @@ "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 20600, @@ -35,5 +35,5 @@ "features": [ "TranslationFile" ], - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/W1/BasicExperience/test/app.json b/Apps/W1/BasicExperience/test/app.json index f8d04b26b5..580c57c3de 100644 --- a/Apps/W1/BasicExperience/test/app.json +++ b/Apps/W1/BasicExperience/test/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "Tests for the Basic Experience extension.", "description": "Tests for the Basic Experience extension.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=", "EULA": "https://go.microsoft.com/fwlink/?linkid=", "help": "https://go.microsoft.com/fwlink/?linkid=", @@ -16,20 +16,20 @@ "id": "0242c240-2336-450f-9678-2f13f4ce9a6e", "name": "Basic Experience", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 139502, diff --git a/Apps/W1/ClientAddIns/app.json b/Apps/W1/ClientAddIns/app.json index 9ce61df58e..f4e14f1d77 100644 --- a/Apps/W1/ClientAddIns/app.json +++ b/Apps/W1/ClientAddIns/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "Client Add-In Library", "description": "Client Add-In Library for Microsoft Dynamics 365 Business Central", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "url": "https://go.microsoft.com/fwlink/?LinkId=724011", @@ -15,7 +15,7 @@ "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 1, @@ -29,5 +29,5 @@ }, "help": "https://go.microsoft.com/fwlink/?LinkId=724011", "contextSensitiveHelpUrl": "https://go.microsoft.com/fwlink/?linkid=2009120", - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/W1/CompanyHub/app/Entitlements/DelegatedBCAdminAgentPartnerCOHUB.Entitlement.al b/Apps/W1/CompanyHub/app/Entitlements/DelegatedBCAdminAgentPartnerCOHUB.Entitlement.al new file mode 100644 index 0000000000..1b3cc99d98 --- /dev/null +++ b/Apps/W1/CompanyHub/app/Entitlements/DelegatedBCAdminAgentPartnerCOHUB.Entitlement.al @@ -0,0 +1,10 @@ +namespace Mirosoft.Integration.CompanyHub; + +entitlement "Delegated BC Admin agent - Partner COHUB" +{ + Type = Role; + RoleType = Delegated; + Id = '00000000-0000-0000-0000-000000000010'; + ObjectEntitlements = "Company Hub - Objects", + "D365 COMPANY HUB"; +} diff --git a/Apps/W1/CompanyHub/app/Entitlements/InternalBCAdministratorCOHUB.Entitlement.al b/Apps/W1/CompanyHub/app/Entitlements/InternalBCAdministratorCOHUB.Entitlement.al new file mode 100644 index 0000000000..5fa5889ff1 --- /dev/null +++ b/Apps/W1/CompanyHub/app/Entitlements/InternalBCAdministratorCOHUB.Entitlement.al @@ -0,0 +1,10 @@ +namespace Mirosoft.Integration.CompanyHub; + +entitlement "Internal BC Administrator COHUB" +{ + Type = Role; + RoleType = Local; + Id = '963797fb-eb3b-4cde-8ce3-5878b3f32a3f'; + ObjectEntitlements = "Company Hub - Objects", + "D365 COMPANY HUB"; +} diff --git a/Apps/W1/CompanyHub/app/app.json b/Apps/W1/CompanyHub/app/app.json index 8c0766d413..d9e33b9d93 100644 --- a/Apps/W1/CompanyHub/app/app.json +++ b/Apps/W1/CompanyHub/app/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "Company Hub lets you easily access all companies you work in. View key KPIs and manage User Tasks for each company.", "description": "Company Hub gives you a list of the companies you work in. You can easily add new companies by just providing a URL and a name for the company. The list of companies contains a few KPIs for the company that is displayed for the user if they have the needed access. You also have a list of assigned user tasks for a given company, so you can keep track of work required for each company. The Company Hub gives you either a dedicated Company Hub role center (if you use one tenant as the main access point) or a similar task page if you use the Company Hub from within a company where your role requires you to have a different main role center. Both have the same features and the same easy access to the companies you work in.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2182906", "url": "https://go.microsoft.com/fwlink/?LinkId=724011", @@ -17,7 +17,7 @@ "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 1, @@ -30,5 +30,5 @@ "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/W1/ConnectivityApps/app/app.json b/Apps/W1/ConnectivityApps/app/app.json index c6588062f8..0e293c9c0b 100644 --- a/Apps/W1/ConnectivityApps/app/app.json +++ b/Apps/W1/ConnectivityApps/app/app.json @@ -4,14 +4,14 @@ "publisher": "Microsoft", "brief": "Easily identify the right app to use to connect your business to productivity services in your market space.", "description": "Connectivity Apps helps you easily discover third-party solutions that connect Business Central with productivity services.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=2204236", "url": "https://go.microsoft.com/fwlink/?LinkId=724011", "logo": "ExtensionLogo.png", - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 20350, @@ -21,7 +21,7 @@ "internalsVisibleTo": [ { "id": "018f12d9-597c-4eb5-8a5d-27983426ffc2", - "name": "Connectivity Apps Tests", + "name": "_Exclude_Connectivity Apps Tests", "publisher": "Microsoft" } ], diff --git a/Apps/W1/ConnectivityApps/test/app.json b/Apps/W1/ConnectivityApps/test/app.json index 0a3c0063cc..c98a4b84d5 100644 --- a/Apps/W1/ConnectivityApps/test/app.json +++ b/Apps/W1/ConnectivityApps/test/app.json @@ -2,7 +2,7 @@ "id": "018f12d9-597c-4eb5-8a5d-27983426ffc2", "name": "_Exclude_Connectivity Apps Tests", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Tests for the Microsoft Connectivity Apps extension.", "description": "Tests for the Microsoft Connectivity Apps extension.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -10,32 +10,32 @@ "help": "https://go.microsoft.com/fwlink/?linkid=2135559", "url": "https://go.microsoft.com/fwlink/?LinkId=724011", "logo": "ExtensionLogo.png", - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "dependencies": [ { "id": "16c26bda-5f9c-4a77-a17e-4835f06062c0", "name": "_Exclude_Connectivity Apps", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "9856ae4f-d1a7-46ef-89bb-6ef056398228", "name": "System Application Test Library", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5095f467-0a01-4b99-99d1-9ff1237d286f", "publisher": "Microsoft", "name": "Library Variable Storage", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "idRanges": [ diff --git a/Apps/W1/ContosoCoffeeDemoDataset/app/DemoData/Common/1.Setup Data/CreateCommonNoSeries.Codeunit.al b/Apps/W1/ContosoCoffeeDemoDataset/app/DemoData/Common/1.Setup Data/CreateCommonNoSeries.Codeunit.al index 7914d2f440..96b9acdc07 100644 --- a/Apps/W1/ContosoCoffeeDemoDataset/app/DemoData/Common/1.Setup Data/CreateCommonNoSeries.Codeunit.al +++ b/Apps/W1/ContosoCoffeeDemoDataset/app/DemoData/Common/1.Setup Data/CreateCommonNoSeries.Codeunit.al @@ -22,30 +22,68 @@ codeunit 5128 "Create Common No Series" if SalesReceivablesSetup."Order Nos." = '' then ContosoNoSeries.InsertNoSeries(SalesOrder(), SalesOrderLbl, '101001', '102999', '', '', 1, Enum::"No. Series Implementation"::Normal, false); + if SalesReceivablesSetup."Invoice Nos." = '' then + ContosoNoSeries.InsertNoSeries(SalesInvoice(), SalesInvoiceLbl, '101001', '102999', '', '', 1, Enum::"No. Series Implementation"::Normal, false); + + if SalesReceivablesSetup."Posted Invoice Nos." = '' then + ContosoNoSeries.InsertNoSeries(PostedSalesInvoice(), PostedSalesInvoiceLbl, '101001', '102999', '', '', 1, Enum::"No. Series Implementation"::Normal, false); + InventorySetup.Get(); if InventorySetup."Item Nos." = '' then ContosoNoSeries.InsertNoSeries(Item(), ItemsLbl, '1000', '9999', '', '', 1, Enum::"No. Series Implementation"::Sequence, true); PurchasePayablesSetup.Get(); + + if PurchasePayablesSetup."Vendor Nos." = '' then + ContosoNoSeries.InsertNoSeries(Vendor(), VendorLbl, 'V10', 'V99990', '', '', 1, Enum::"No. Series Implementation"::Sequence, true); + if PurchasePayablesSetup."Order Nos." = '' then ContosoNoSeries.InsertNoSeries(PurchaseOrder(), PurchaseOrderLbl, '106001', '107999', '', '', 1, Enum::"No. Series Implementation"::Normal, false); + + if PurchasePayablesSetup."Invoice Nos." = '' then + ContosoNoSeries.InsertNoSeries(PurchaseInvoice(), PurchaseInvoiceLbl, '106001', '107999', '', '', 1, Enum::"No. Series Implementation"::Normal, false); + + if PurchasePayablesSetup."Posted Invoice Nos." = '' then + ContosoNoSeries.InsertNoSeries(PostedPurchaseInvoice(), PostedPurchaseInvoiceLbl, '106001', '107999', '', '', 1, Enum::"No. Series Implementation"::Normal, false); + + if PurchasePayablesSetup."Posted Receipt Nos." = '' then + ContosoNoSeries.InsertNoSeries(PostedReceipt(), PostedReceiptLbl, '106001', '107999', '', '', 1, Enum::"No. Series Implementation"::Normal, false); + end; var CustomerTok: Label 'CUST', MaxLength = 20; CustomerLbl: Label 'Customer', MaxLength = 100; + VendorTok: Label 'VEND', MaxLength = 20; + VendorLbl: Label 'Vendor', MaxLength = 100; ItemTok: Label 'ITEM', MaxLength = 20; ItemsLbl: Label 'Items', MaxLength = 100; SalesOrderTok: Label 'S-ORD', MaxLength = 20; SalesOrderLbl: Label 'Sales Order', MaxLength = 100; + SalesInvoiceTok: Label 'S-INV', MaxLength = 20; + SalesInvoiceLbl: Label 'Sales Invoice', MaxLength = 20; + PostedSalesInvoiceTok: Label 'PS-INV', MaxLength = 20; + PostedSalesInvoiceLbl: Label 'Posted Sales Invoice', MaxLength = 20; PurchaseOrderTok: Label 'P-ORD', MaxLength = 20; PurchaseOrderLbl: Label 'Purchase Order', MaxLength = 100; + PurchaseInvoiceTok: Label 'P-INV', MaxLength = 20; + PurchaseInvoiceLbl: Label 'Purchase Invoice', MaxLength = 100; + PostedPurchaseInvoiceTok: Label 'PP-INV', MaxLength = 20; + PostedPurchaseInvoiceLbl: Label 'Posted Purchase Invoice', MaxLength = 100; + PostedReceiptTok: Label 'P-RPT', MaxLength = 20; + PostedReceiptLbl: Label 'Posted Receipt', MaxLength = 20; + procedure Customer(): Code[20] begin exit(CustomerTok); end; + procedure Vendor(): Code[20] + begin + exit(VendorTok); + end; + procedure Item(): Code[20] begin exit(ItemTok); @@ -56,8 +94,33 @@ codeunit 5128 "Create Common No Series" exit(SalesOrderTok); end; + procedure SalesInvoice(): Code[20] + begin + exit(SalesInvoiceTok); + end; + + procedure PostedSalesInvoice(): Code[20] + begin + exit(PostedSalesInvoiceTok); + end; + procedure PurchaseOrder(): Code[20] begin exit(PurchaseOrderTok); end; + + procedure PurchaseInvoice(): Code[20] + begin + exit(PurchaseInvoiceTok); + end; + + procedure PostedPurchaseInvoice(): Code[20] + begin + exit(PostedPurchaseInvoiceTok); + end; + + procedure PostedReceipt(): Code[20] + begin + exit(PostedReceiptTok); + end; } diff --git a/Apps/W1/ContosoCoffeeDemoDataset/app/DemoData/Common/1.Setup Data/CreateCommonPurchaseSetup.Codeunit.al b/Apps/W1/ContosoCoffeeDemoDataset/app/DemoData/Common/1.Setup Data/CreateCommonPurchaseSetup.Codeunit.al index 4ac669ceee..a4d0704acc 100644 --- a/Apps/W1/ContosoCoffeeDemoDataset/app/DemoData/Common/1.Setup Data/CreateCommonPurchaseSetup.Codeunit.al +++ b/Apps/W1/ContosoCoffeeDemoDataset/app/DemoData/Common/1.Setup Data/CreateCommonPurchaseSetup.Codeunit.al @@ -11,9 +11,21 @@ codeunit 5146 "Create Common Purchase Setup" begin PurchasePayablesSetup.Get(); + if PurchasePayablesSetup."Vendor Nos." = '' then + PurchasePayablesSetup.Validate("Vendor Nos.", CommonNoSeries.Vendor()); + if PurchasePayablesSetup."Order Nos." = '' then PurchasePayablesSetup.Validate("Order Nos.", CommonNoSeries.PurchaseOrder()); + if PurchasePayablesSetup."Invoice Nos." = '' then + PurchasePayablesSetup.Validate("Invoice Nos.", CommonNoSeries.PurchaseInvoice()); + + if PurchasePayablesSetup."Posted Receipt Nos." = '' then + PurchasePayablesSetup.Validate("Posted Receipt Nos.", CommonNoSeries.PostedReceipt()); + + if PurchasePayablesSetup."Posted Invoice Nos." = '' then + PurchasePayablesSetup.Validate("Posted Invoice Nos.", CommonNoSeries.PostedPurchaseInvoice()); + PurchasePayablesSetup.Modify(); end; } \ No newline at end of file diff --git a/Apps/W1/ContosoCoffeeDemoDataset/app/DemoData/Common/1.Setup Data/CreateCommonSalesSetup.Codeunit.al b/Apps/W1/ContosoCoffeeDemoDataset/app/DemoData/Common/1.Setup Data/CreateCommonSalesSetup.Codeunit.al index 9cf5b27852..fd3526ba25 100644 --- a/Apps/W1/ContosoCoffeeDemoDataset/app/DemoData/Common/1.Setup Data/CreateCommonSalesSetup.Codeunit.al +++ b/Apps/W1/ContosoCoffeeDemoDataset/app/DemoData/Common/1.Setup Data/CreateCommonSalesSetup.Codeunit.al @@ -17,6 +17,12 @@ codeunit 5141 "Create Common Sales Setup" if SalesReceivablesSetup."Order Nos." = '' then SalesReceivablesSetup.Validate("Order Nos.", CommonNoSeries.SalesOrder()); + if SalesReceivablesSetup."Invoice Nos." = '' then + SalesReceivablesSetup.Validate("Invoice Nos.", CommonNoSeries.SalesInvoice()); + + if SalesReceivablesSetup."Posted Invoice Nos." = '' then + SalesReceivablesSetup.Validate("Posted Invoice Nos.", CommonNoSeries.PostedSalesInvoice()); + SalesReceivablesSetup.Modify(); end; } \ No newline at end of file diff --git a/Apps/W1/ContosoCoffeeDemoDataset/app/DemoData/Jobs/3.Transactions/CreateJob.Codeunit.al b/Apps/W1/ContosoCoffeeDemoDataset/app/DemoData/Jobs/3.Transactions/CreateJob.Codeunit.al index 634969cbc8..1a63c26034 100644 --- a/Apps/W1/ContosoCoffeeDemoDataset/app/DemoData/Jobs/3.Transactions/CreateJob.Codeunit.al +++ b/Apps/W1/ContosoCoffeeDemoDataset/app/DemoData/Jobs/3.Transactions/CreateJob.Codeunit.al @@ -4,8 +4,7 @@ codeunit 5190 "Create Job" InherentPermissions = X; var - FixedRateJobTok: Label 'Fix Rate Job', MaxLength = 20; - FixRateJobNameLbl: Label 'Installation of S-100 Semi-Automatic', MaxLength = 100; + FixRateJobNameLbl: Label 'Installation of S-200 Semi-Automatic', MaxLength = 100; FixRateJobPhase1DescriptionLbl: Label 'Phase 1 - Planning and specs', MaxLength = 100; PreInstallationTaskDescriptionLbl: Label 'Pre-installation requirements', MaxLength = 100; FixRateJobChecklistDescriptionLbl: Label 'Check-list:', MaxLength = 100; @@ -18,11 +17,9 @@ codeunit 5190 "Create Job" FixRateJobInstallationTaskLbl: Label 'Installation', MaxLength = 100; FixRateJobConfigurationTaskTok: Label 'Configuration', MaxLength = 100; FixRateJobPhase2TotalDescriptionLbl: Label 'Phase 2 - Total', MaxLength = 100; - RecurringJobTok: Label 'Recurring Job', MaxLength = 20; - RecurringJobNameLbl: Label 'Supplies and maintenance of S-100 Semi-Automatic', MaxLength = 100; - RecurringTaskMonthlyDescriptionLbl: Label 'Phase 1 - Planning and specs', MaxLength = 100; - RecurringTaskAnnuallyDescriptionLbl: Label 'Pre-installation requirements', MaxLength = 100; - WIPJobTok: Label 'WIP Job', MaxLength = 20; + RecurringJobNameLbl: Label 'Supplies and maintenance of S-200 Semi-Automatic', MaxLength = 100; + RecurringTaskMonthlyDescriptionLbl: Label 'Monthly maintenance', MaxLength = 100; + RecurringTaskAnnuallyDescriptionLbl: Label 'Annual maintenance', MaxLength = 100; WIPJobNameLbl: Label 'Software update', MaxLength = 100; trigger OnRun() @@ -32,82 +29,85 @@ codeunit 5190 "Create Job" CreateWIPJob(); end; - procedure CreateFixRateJob() + local procedure CreateFixRateJob() var JobsModuleSetup: Record "Jobs Module Setup"; + FixedRateJob: Record Job; ContosoJob: Codeunit "Contoso Job"; JobTaskIndent: Codeunit "Job Task-Indent"; begin JobsModuleSetup.Get(); - ContosoJob.InsertJob(FixRateJob(), FixRateJobNameLbl, JobsModuleSetup."Customer No.", 'F-1'); + FixedRateJob := ContosoJob.InsertJob(FixRateJobNameLbl, JobsModuleSetup."Customer No.", FixRateJobExternalDocumentNo()); - ContosoJob.InsertJobTask(FixRateJob(), '100', FixRateJobPhase1DescriptionLbl, Enum::"Job Task Type"::"Begin-Total"); - ContosoJob.InsertJobTask(FixRateJob(), FixRateJobPreInstallTask(), PreInstallationTaskDescriptionLbl, Enum::"Job Task Type"::"Posting"); - ContosoJob.InsertJobPlanningLine(FixRateJob(), FixRateJobPreInstallTask(), Enum::"Job Planning Line Line Type"::Budget, Enum::"Job Planning Line Type"::Resource, JobsModuleSetup."Resource Installer No.", 3, '', JobsModuleSetup."Job Location"); - ContosoJob.InsertJobPlanningLine(FixRateJob(), FixRateJobPreInstallTask(), Enum::"Job Planning Line Line Type"::Billable, Enum::"Job Planning Line Type"::Item, JobsModuleSetup."Item Service No.", 3, PreInstallationTaskDescriptionLbl, JobsModuleSetup."Job Location"); - ContosoJob.InsertJobPlanningLine(FixRateJob(), FixRateJobPreInstallTask(), Enum::"Job Planning Line Line Type"::Billable, FixRateJobChecklistDescriptionLbl); - ContosoJob.InsertJobPlanningLine(FixRateJob(), FixRateJobPreInstallTask(), Enum::"Job Planning Line Line Type"::Billable, FixRateJobSpaceRequirementDescriptionLbl); - ContosoJob.InsertJobPlanningLine(FixRateJob(), FixRateJobPreInstallTask(), Enum::"Job Planning Line Line Type"::Billable, FixRateJobWaterRequirementDescriptionLbl); - ContosoJob.InsertJobPlanningLine(FixRateJob(), FixRateJobPreInstallTask(), Enum::"Job Planning Line Line Type"::Billable, FixRateJobElectricalRequirementDescriptionLbl); - ContosoJob.InsertJobTask(FixRateJob(), '199', FixRateJobPhase1TotalDescriptionLbl, Enum::"Job Task Type"::"End-Total"); + ContosoJob.InsertJobTask(FixedRateJob."No.", '100', FixRateJobPhase1DescriptionLbl, Enum::"Job Task Type"::"Begin-Total"); + ContosoJob.InsertJobTask(FixedRateJob."No.", FixRateJobPreInstallTask(), PreInstallationTaskDescriptionLbl, Enum::"Job Task Type"::"Posting"); + ContosoJob.InsertJobPlanningLine(FixedRateJob."No.", FixRateJobPreInstallTask(), Enum::"Job Planning Line Line Type"::Budget, Enum::"Job Planning Line Type"::Resource, JobsModuleSetup."Resource Installer No.", 3, '', JobsModuleSetup."Job Location"); + ContosoJob.InsertJobPlanningLine(FixedRateJob."No.", FixRateJobPreInstallTask(), Enum::"Job Planning Line Line Type"::Billable, Enum::"Job Planning Line Type"::Item, JobsModuleSetup."Item Service No.", 3, PreInstallationTaskDescriptionLbl, JobsModuleSetup."Job Location"); + ContosoJob.InsertJobPlanningLine(FixedRateJob."No.", FixRateJobPreInstallTask(), Enum::"Job Planning Line Line Type"::Billable, FixRateJobChecklistDescriptionLbl); + ContosoJob.InsertJobPlanningLine(FixedRateJob."No.", FixRateJobPreInstallTask(), Enum::"Job Planning Line Line Type"::Billable, FixRateJobSpaceRequirementDescriptionLbl); + ContosoJob.InsertJobPlanningLine(FixedRateJob."No.", FixRateJobPreInstallTask(), Enum::"Job Planning Line Line Type"::Billable, FixRateJobWaterRequirementDescriptionLbl); + ContosoJob.InsertJobPlanningLine(FixedRateJob."No.", FixRateJobPreInstallTask(), Enum::"Job Planning Line Line Type"::Billable, FixRateJobElectricalRequirementDescriptionLbl); + ContosoJob.InsertJobTask(FixedRateJob."No.", '199', FixRateJobPhase1TotalDescriptionLbl, Enum::"Job Task Type"::"End-Total"); - ContosoJob.InsertJobTask(FixRateJob(), '200', FixRateJobPhase2DescriptionLbl, Enum::"Job Task Type"::"Begin-Total"); - ContosoJob.InsertJobTask(FixRateJob(), FixRateJobDeliveryTask(), FixRateJobDeliveryTaskDescriptionLbl, Enum::"Job Task Type"::"Posting"); - ContosoJob.InsertJobPlanningLine(FixRateJob(), FixRateJobDeliveryTask(), Enum::"Job Planning Line Line Type"::"Both Budget and Billable", Enum::"Job Planning Line Type"::Item, JobsModuleSetup."Item Machine No.", 1, '', JobsModuleSetup."Job Location"); + ContosoJob.InsertJobTask(FixedRateJob."No.", '200', FixRateJobPhase2DescriptionLbl, Enum::"Job Task Type"::"Begin-Total"); + ContosoJob.InsertJobTask(FixedRateJob."No.", FixRateJobDeliveryTask(), FixRateJobDeliveryTaskDescriptionLbl, Enum::"Job Task Type"::"Posting"); + ContosoJob.InsertJobPlanningLine(FixedRateJob."No.", FixRateJobDeliveryTask(), Enum::"Job Planning Line Line Type"::"Both Budget and Billable", Enum::"Job Planning Line Type"::Item, JobsModuleSetup."Item Machine No.", 1, '', JobsModuleSetup."Job Location"); - ContosoJob.InsertJobTask(FixRateJob(), FixRateJobInstallationTask(), FixRateJobInstallationTaskLbl, Enum::"Job Task Type"::"Posting"); - ContosoJob.InsertJobPlanningLine(FixRateJob(), FixRateJobInstallationTask(), Enum::"Job Planning Line Line Type"::Budget, Enum::"Job Planning Line Type"::Resource, JobsModuleSetup."Resource Installer No.", 3, '', JobsModuleSetup."Job Location"); - ContosoJob.InsertJobPlanningLine(FixRateJob(), FixRateJobInstallationTask(), Enum::"Job Planning Line Line Type"::Billable, Enum::"Job Planning Line Type"::Item, JobsModuleSetup."Item Service No.", 2, FixRateJobInstallationTaskLbl, JobsModuleSetup."Job Location"); - ContosoJob.InsertJobPlanningLine(FixRateJob(), FixRateJobInstallationTask(), Enum::"Job Planning Line Line Type"::Budget, Enum::"Job Planning Line Type"::Item, JobsModuleSetup."Item Consumable No.", 1, '', JobsModuleSetup."Job Location"); + ContosoJob.InsertJobTask(FixedRateJob."No.", FixRateJobInstallationTask(), FixRateJobInstallationTaskLbl, Enum::"Job Task Type"::"Posting"); + ContosoJob.InsertJobPlanningLine(FixedRateJob."No.", FixRateJobInstallationTask(), Enum::"Job Planning Line Line Type"::Budget, Enum::"Job Planning Line Type"::Resource, JobsModuleSetup."Resource Installer No.", 3, '', JobsModuleSetup."Job Location"); + ContosoJob.InsertJobPlanningLine(FixedRateJob."No.", FixRateJobInstallationTask(), Enum::"Job Planning Line Line Type"::Billable, Enum::"Job Planning Line Type"::Item, JobsModuleSetup."Item Service No.", 2, FixRateJobInstallationTaskLbl, JobsModuleSetup."Job Location"); + ContosoJob.InsertJobPlanningLine(FixedRateJob."No.", FixRateJobInstallationTask(), Enum::"Job Planning Line Line Type"::Budget, Enum::"Job Planning Line Type"::Item, JobsModuleSetup."Item Consumable No.", 1, '', JobsModuleSetup."Job Location"); - ContosoJob.InsertJobTask(FixRateJob(), FixRateJobConfigurationTask(), FixRateJobConfigurationTaskTok, Enum::"Job Task Type"::"Posting"); - ContosoJob.InsertJobPlanningLine(FixRateJob(), FixRateJobConfigurationTask(), Enum::"Job Planning Line Line Type"::Budget, Enum::"Job Planning Line Type"::Resource, JobsModuleSetup."Resource Installer No.", 1, '', JobsModuleSetup."Job Location"); - ContosoJob.InsertJobPlanningLine(FixRateJob(), FixRateJobConfigurationTask(), Enum::"Job Planning Line Line Type"::Billable, Enum::"Job Planning Line Type"::Item, JobsModuleSetup."Item Service No.", 2, FixRateJobConfigurationTaskTok, JobsModuleSetup."Job Location"); + ContosoJob.InsertJobTask(FixedRateJob."No.", FixRateJobConfigurationTask(), FixRateJobConfigurationTaskTok, Enum::"Job Task Type"::"Posting"); + ContosoJob.InsertJobPlanningLine(FixedRateJob."No.", FixRateJobConfigurationTask(), Enum::"Job Planning Line Line Type"::Budget, Enum::"Job Planning Line Type"::Resource, JobsModuleSetup."Resource Installer No.", 1, '', JobsModuleSetup."Job Location"); + ContosoJob.InsertJobPlanningLine(FixedRateJob."No.", FixRateJobConfigurationTask(), Enum::"Job Planning Line Line Type"::Billable, Enum::"Job Planning Line Type"::Item, JobsModuleSetup."Item Service No.", 2, FixRateJobConfigurationTaskTok, JobsModuleSetup."Job Location"); - ContosoJob.InsertJobTask(FixRateJob(), '299', FixRateJobPhase2TotalDescriptionLbl, Enum::"Job Task Type"::"End-Total"); + ContosoJob.InsertJobTask(FixedRateJob."No.", '299', FixRateJobPhase2TotalDescriptionLbl, Enum::"Job Task Type"::"End-Total"); - JobTaskIndent.Indent(FixRateJob()); + JobTaskIndent.Indent(FixedRateJob."No."); end; - procedure CreateWIPJob() + local procedure CreateWIPJob() var JobsModuleSetup: Record "Jobs Module Setup"; + WIPJob: Record Job; ContosoJob: Codeunit "Contoso Job"; begin JobsModuleSetup.Get(); - ContosoJob.InsertJob(WIPJob(), WIPJobNameLbl, JobsModuleSetup."Customer No.", 'W-2'); - ContosoJob.InsertJobTask(WIPJob(), WIPJobSoftUpdateTask(), WIPJobNameLbl, Enum::"Job Task Type"::"Posting"); - ContosoJob.InsertJobPlanningLine(WIPJob(), WIPJobSoftUpdateTask(), Enum::"Job Planning Line Line Type"::Budget, Enum::"Job Planning Line Type"::Resource, JobsModuleSetup."Resource Installer No.", 12, '', JobsModuleSetup."Job Location"); - ContosoJob.InsertJobPlanningLine(WIPJob(), WIPJobSoftUpdateTask(), Enum::"Job Planning Line Line Type"::Billable, Enum::"Job Planning Line Type"::Item, JobsModuleSetup."Item Service No.", 12, WIPJobNameLbl, JobsModuleSetup."Job Location"); + WIPJob := ContosoJob.InsertJob(WIPJobNameLbl, JobsModuleSetup."Customer No.", WIPJobExternalDocumentNo()); + ContosoJob.InsertJobTask(WIPJob."No.", WIPJobSoftUpdateTask(), WIPJobNameLbl, Enum::"Job Task Type"::"Posting"); + ContosoJob.InsertJobPlanningLine(WIPJob."No.", WIPJobSoftUpdateTask(), Enum::"Job Planning Line Line Type"::Budget, Enum::"Job Planning Line Type"::Resource, JobsModuleSetup."Resource Installer No.", 12, '', JobsModuleSetup."Job Location"); + ContosoJob.InsertJobPlanningLine(WIPJob."No.", WIPJobSoftUpdateTask(), Enum::"Job Planning Line Line Type"::Billable, Enum::"Job Planning Line Type"::Item, JobsModuleSetup."Item Service No.", 12, WIPJobNameLbl, JobsModuleSetup."Job Location"); end; - procedure CreateRecurringJob() + local procedure CreateRecurringJob() var JobsModuleSetup: Record "Jobs Module Setup"; + RecurringJob: Record Job; ContosoJob: Codeunit "Contoso Job"; begin JobsModuleSetup.Get(); - ContosoJob.InsertJob(RecurringJob(), RecurringJobNameLbl, JobsModuleSetup."Customer No.", 'R-3'); - ContosoJob.InsertJobTask(RecurringJob(), '1000', RecurringTaskMonthlyDescriptionLbl, Enum::"Job Task Type"::"Posting"); - ContosoJob.InsertJobTask(RecurringJob(), '3000', RecurringTaskAnnuallyDescriptionLbl, Enum::"Job Task Type"::"Posting"); + RecurringJob := ContosoJob.InsertJob(RecurringJobNameLbl, JobsModuleSetup."Customer No.", RecurringJobExternalDocumentNo()); + ContosoJob.InsertJobTask(RecurringJob."No.", '1000', RecurringTaskMonthlyDescriptionLbl, Enum::"Job Task Type"::"Posting"); + ContosoJob.InsertJobTask(RecurringJob."No.", '3000', RecurringTaskAnnuallyDescriptionLbl, Enum::"Job Task Type"::"Posting"); end; - procedure FixRateJob(): Code[20] + procedure FixRateJobExternalDocumentNo(): Code[20] begin - exit(FixedRateJobTok); + exit('F-1'); end; - procedure WIPJob(): Code[20] + procedure WIPJobExternalDocumentNo(): Code[20] begin - exit(WIPJobTok); + exit('W-2'); end; - procedure RecurringJob(): Code[20] + procedure RecurringJobExternalDocumentNo(): Code[20] begin - exit(RecurringJobTok); + exit('R-3'); end; procedure FixRateJobPreInstallTask(): Code[20] diff --git a/Apps/W1/ContosoCoffeeDemoDataset/app/DemoData/Service/1.Setup Data/CreateSvcNoSeries.Codeunit.al b/Apps/W1/ContosoCoffeeDemoDataset/app/DemoData/Service/1.Setup Data/CreateSvcNoSeries.Codeunit.al index aff55df58d..0c014f1046 100644 --- a/Apps/W1/ContosoCoffeeDemoDataset/app/DemoData/Service/1.Setup Data/CreateSvcNoSeries.Codeunit.al +++ b/Apps/W1/ContosoCoffeeDemoDataset/app/DemoData/Service/1.Setup Data/CreateSvcNoSeries.Codeunit.al @@ -15,6 +15,8 @@ codeunit 5101 "Create Svc No Series" ContosoNoSeries.InsertNoSeries(ServiceContract(), SeriesServiceContractNosDescTok, 'SVC000001', 'SVC999999', '', '', 1, Enum::"No. Series Implementation"::Sequence, true); ContosoNoSeries.InsertNoSeries(ContractInvoice(), SeriesContractInvoiceNosDescTok, 'SVCI000001', 'SVCI999999', '', '', 1, Enum::"No. Series Implementation"::Sequence, true); ContosoNoSeries.InsertNoSeries(ContractTemplate(), SeriesContractTemplateLbl, 'TEMPL0001', 'TEMPL9999', '', '', 1, Enum::"No. Series Implementation"::Sequence, true); + ContosoNoSeries.InsertNoSeries(ServiceCreditMemo(), ServiceCreditMemoNosDescTok, 'SVCR1001', 'SVI9999', '', '', 1, Enum::"No. Series Implementation"::Sequence, true); + ContosoNoSeries.InsertNoSeries(PostedServiceCreditMemo(), PostedServiceCreditMemoNosDescTok, 'PSCR10001', 'PSVI99999', '', '', 1, Enum::"No. Series Implementation"::Sequence, true); end; var @@ -34,6 +36,10 @@ codeunit 5101 "Create Svc No Series" ContractInvoiceNosTok: Label 'SVC-CONTR-I', MaxLength = 20; ContractTemplateNosTok: Label 'SVC-CONTR-T', MaxLength = 20; SeriesContractTemplateLbl: Label 'Templates for Service Contracts', MaxLength = 100; + ServiceCreditMemoNosTok: Label 'SVC-CREDIT', MaxLength = 20; + ServiceCreditMemoNosDescTok: Label 'Service Credit Memos', MaxLength = 100; + PostedServiceCreditMemoNosTok: Label 'SVC-CREDIT+', MaxLength = 20; + PostedServiceCreditMemoNosDescTok: Label 'Posted Service Credit Memos', MaxLength = 100; procedure ServiceItem(): Code[20] begin @@ -74,4 +80,14 @@ codeunit 5101 "Create Svc No Series" begin exit(ContractTemplateNosTok); end; + + procedure ServiceCreditMemo(): Code[20] + begin + exit(ServiceCreditMemoNosTok); + end; + + procedure PostedServiceCreditMemo(): Code[20] + begin + exit(PostedServiceCreditMemoNosTok); + end; } \ No newline at end of file diff --git a/Apps/W1/ContosoCoffeeDemoDataset/app/DemoData/Service/1.Setup Data/CreateSvcSetup.Codeunit.al b/Apps/W1/ContosoCoffeeDemoDataset/app/DemoData/Service/1.Setup Data/CreateSvcSetup.Codeunit.al index 0a3dd45846..3e0efda96e 100644 --- a/Apps/W1/ContosoCoffeeDemoDataset/app/DemoData/Service/1.Setup Data/CreateSvcSetup.Codeunit.al +++ b/Apps/W1/ContosoCoffeeDemoDataset/app/DemoData/Service/1.Setup Data/CreateSvcSetup.Codeunit.al @@ -69,6 +69,10 @@ codeunit 5103 "Create Svc Setup" ServiceMgtSetup.Validate("Contract Invoice Nos.", SevNoSeries.ContractInvoice()); if ServiceMgtSetup."Contract Template Nos." = '' then ServiceMgtSetup.Validate("Contract Template Nos.", SevNoSeries.ContractTemplate()); + if ServiceMgtSetup."Service Credit Memo Nos." = '' then + ServiceMgtSetup.Validate("Service Credit Memo Nos.", SevNoSeries.ServiceCreditMemo()); + if ServiceMgtSetup."Posted Serv. Credit Memo Nos." = '' then + ServiceMgtSetup.Validate("Posted Serv. Credit Memo Nos.", SevNoSeries.PostedServiceCreditMemo()); ServiceMgtSetup.Validate("Base Calendar Code", DefaultBaseCalendar()); diff --git a/Apps/W1/ContosoCoffeeDemoDataset/app/DemoData/Warehousing/WhseDemoDataSetup.Table.al b/Apps/W1/ContosoCoffeeDemoDataset/app/DemoData/Warehousing/WhseDemoDataSetup.Table.al index a48b24be48..1b4d189a44 100644 --- a/Apps/W1/ContosoCoffeeDemoDataset/app/DemoData/Warehousing/WhseDemoDataSetup.Table.al +++ b/Apps/W1/ContosoCoffeeDemoDataset/app/DemoData/Warehousing/WhseDemoDataSetup.Table.al @@ -60,6 +60,7 @@ table 4763 "Whse Demo Data Setup" DataClassification = CustomerContent; Caption = 'Domestic - VAT Posting Group'; TableRelation = "VAT Business Posting Group"; + ValidateTableRelation = false; } field(35; "Resale Code"; code[20]) { diff --git a/Apps/W1/ContosoCoffeeDemoDataset/app/DemoTool/Contoso Helpers/ContosoItem.Codeunit.al b/Apps/W1/ContosoCoffeeDemoDataset/app/DemoTool/Contoso Helpers/ContosoItem.Codeunit.al index 03596b4eeb..eddd46a1f6 100644 --- a/Apps/W1/ContosoCoffeeDemoDataset/app/DemoTool/Contoso Helpers/ContosoItem.Codeunit.al +++ b/Apps/W1/ContosoCoffeeDemoDataset/app/DemoTool/Contoso Helpers/ContosoItem.Codeunit.al @@ -105,17 +105,17 @@ codeunit 5143 "Contoso Item" procedure InsertInventoryItem(ItemNo: Code[20]; Description: Text[100]; UnitPrice: Decimal; LastDirectCost: Decimal; GenProdPostingGroup: Code[20]; TaxGroup: Code[20]; InventoryPostingGroup: Code[20]; CostingMethod: Enum "Costing Method"; BaseUnitOfMeasure: Code[10]; ItemCategoryCode: Code[20]; ItemTrackingCode: Code[10]; NetWeight: Decimal; PutAwayTemplateCode: Code[10]; Picture: Codeunit "Temp Blob"; GTIN: Code[14]) begin - InsertItem(ItemNo, Enum::"Item Type"::Inventory, Description, UnitPrice, LastDirectCost, GenProdPostingGroup, TaxGroup, InventoryPostingGroup, CostingMethod, BaseUnitOfMeasure, ItemCategoryCode, ItemTrackingCode, NetWeight, PutAwayTemplateCode, '', 0, Enum::"Replenishment System"::Purchase, 0, '', '', Enum::"Flushing Method"::Backward, Enum::"Reordering Policy"::" ", false, '', Picture, GTIN); + InsertItem(ItemNo, Enum::"Item Type"::Inventory, Description, UnitPrice, LastDirectCost, GenProdPostingGroup, TaxGroup, InventoryPostingGroup, CostingMethod, BaseUnitOfMeasure, ItemCategoryCode, ItemTrackingCode, NetWeight, PutAwayTemplateCode, '', 0, Enum::"Replenishment System"::Purchase, 0, '', '', Enum::"Flushing Method"::Manual, Enum::"Reordering Policy"::" ", false, '', Picture, GTIN); end; procedure InsertInventoryItem(ItemNo: Code[20]; Description: Text[100]; UnitPrice: Decimal; LastDirectCost: Decimal; GenProdPostingGroup: Code[20]; TaxGroup: Code[20]; InventoryPostingGroup: Code[20]; CostingMethod: Enum "Costing Method"; BaseUnitOfMeasure: Code[10]; ItemCategoryCode: Code[20]; NetWeight: Decimal; ServiceItemGroupCode: Code[10]; Picture: Codeunit "Temp Blob") begin - InsertItem(ItemNo, Enum::"Item Type"::Inventory, Description, UnitPrice, LastDirectCost, GenProdPostingGroup, TaxGroup, InventoryPostingGroup, CostingMethod, BaseUnitOfMeasure, ItemCategoryCode, '', NetWeight, '', ServiceItemGroupCode, 0, Enum::"Replenishment System"::Purchase, 0, '', '', Enum::"Flushing Method"::Backward, Enum::"Reordering Policy"::" ", false, '', Picture, ''); + InsertItem(ItemNo, Enum::"Item Type"::Inventory, Description, UnitPrice, LastDirectCost, GenProdPostingGroup, TaxGroup, InventoryPostingGroup, CostingMethod, BaseUnitOfMeasure, ItemCategoryCode, '', NetWeight, '', ServiceItemGroupCode, 0, Enum::"Replenishment System"::Purchase, 0, '', '', Enum::"Flushing Method"::Manual, Enum::"Reordering Policy"::" ", false, '', Picture, ''); end; procedure InsertServiceItem(ItemNo: Code[20]; Description: Text[100]; UnitPrice: Decimal; LastDirectCost: Decimal; GenProdPostingGroup: Code[20]; TaxGroup: Code[20]; BaseUnitOfMeasure: Code[10]; ItemCategoryCode: Code[20]; Picture: Codeunit "Temp Blob") begin - InsertItem(ItemNo, Enum::"Item Type"::Service, Description, UnitPrice, LastDirectCost, GenProdPostingGroup, TaxGroup, '', Enum::"Costing Method"::FIFO, BaseUnitOfMeasure, ItemCategoryCode, '', 0, '', '', 0, Enum::"Replenishment System"::Purchase, 0, '', '', Enum::"Flushing Method"::Backward, Enum::"Reordering Policy"::" ", false, '', Picture, ''); + InsertItem(ItemNo, Enum::"Item Type"::Service, Description, UnitPrice, LastDirectCost, GenProdPostingGroup, TaxGroup, '', Enum::"Costing Method"::FIFO, BaseUnitOfMeasure, ItemCategoryCode, '', 0, '', '', 0, Enum::"Replenishment System"::Purchase, 0, '', '', Enum::"Flushing Method"::Manual, Enum::"Reordering Policy"::" ", false, '', Picture, ''); end; procedure InsertItemCategory(ItemCategoryCode: Code[20]; Description: Text[100]; ParentCategory: Code[20]) diff --git a/Apps/W1/ContosoCoffeeDemoDataset/app/DemoTool/Contoso Helpers/ContosoJob.Codeunit.al b/Apps/W1/ContosoCoffeeDemoDataset/app/DemoTool/Contoso Helpers/ContosoJob.Codeunit.al index 4ce177c882..834c13e64f 100644 --- a/Apps/W1/ContosoCoffeeDemoDataset/app/DemoTool/Contoso Helpers/ContosoJob.Codeunit.al +++ b/Apps/W1/ContosoCoffeeDemoDataset/app/DemoTool/Contoso Helpers/ContosoJob.Codeunit.al @@ -50,27 +50,17 @@ codeunit 5186 "Contoso Job" JobPostingGroup.Insert(true); end; - procedure InsertJob(JobNo: Code[20]; Description: Text[100]; CustomerNo: Code[20]; ExternalDocumentNo: Code[35]) + procedure InsertJob(Description: Text[100]; CustomerNo: Code[20]; ExternalDocumentNo: Code[35]): Record Job var Job: Record Job; - Exists: Boolean; begin - if Job.Get(JobNo) then begin - Exists := true; - - if not OverwriteData then - exit; - end; - - Job.Validate("No.", JobNo); Job.Validate(Description, Description); Job.Validate("Bill-to Customer No.", CustomerNo); Job.Validate("External Document No.", ExternalDocumentNo); - if Exists then - Job.Modify(true) - else - Job.Insert(true); + Job.Insert(true); + + exit(Job); end; procedure InsertJobTask(JobNo: Code[20]; JobTaskNo: Code[20]; Description: Text[100]; JobTaskType: Enum "Job Task Type") @@ -108,7 +98,8 @@ codeunit 5186 "Contoso Job" JobPlanningLine.Validate("No.", No); JobPlanningLine.Validate(Quantity, Quantity); JobPlanningLine.Validate("Location Code", LocationCode); - JobPlanningLine.Validate(Description, LineDescription); + if LineDescription <> '' then + JobPlanningLine.Validate(Description, LineDescription); JobPlanningLine.Insert(true); end; diff --git a/Apps/W1/ContosoCoffeeDemoDataset/app/DemoTool/Contoso Helpers/ContosoPurchase.Codeunit.al b/Apps/W1/ContosoCoffeeDemoDataset/app/DemoTool/Contoso Helpers/ContosoPurchase.Codeunit.al index f28ec9ec4f..ca61ca35b1 100644 --- a/Apps/W1/ContosoCoffeeDemoDataset/app/DemoTool/Contoso Helpers/ContosoPurchase.Codeunit.al +++ b/Apps/W1/ContosoCoffeeDemoDataset/app/DemoTool/Contoso Helpers/ContosoPurchase.Codeunit.al @@ -32,6 +32,11 @@ codeunit 4781 "Contoso Purchase" end; procedure InsertPurchaseLineWithItem(PurchaseHeader: Record "Purchase Header"; ItemNo: Code[20]; Quantity: Decimal; UnitOfMeasureCode: Code[10]; UnitCost: Decimal) + begin + InsertPurchaseLineWithItem(PurchaseHeader, ItemNo, Quantity, UnitOfMeasureCode, UnitCost, 0); + end; + + procedure InsertPurchaseLineWithItem(PurchaseHeader: Record "Purchase Header"; ItemNo: Code[20]; Quantity: Decimal; UnitOfMeasureCode: Code[10]; UnitCost: Decimal; LineDiscount: Decimal) var Item: Record Item; PurchaseLine: Record "Purchase Line"; @@ -45,15 +50,16 @@ codeunit 4781 "Contoso Purchase" if UnitOfMeasureCode <> '' then begin PurchaseLine.Validate("Unit of Measure Code", UnitOfMeasureCode); - PurchaseLine.Validate("Unit Cost", UnitCost); + PurchaseLine.Validate("Direct Unit Cost", UnitCost); end else begin Item.SetBaseLoadFields(); Item.Get(ItemNo); PurchaseLine.Validate("Unit of Measure Code", Item."Base Unit of Measure"); - PurchaseLine.Validate("Unit Cost", Item."Unit Cost"); + PurchaseLine.Validate("Direct Unit Cost", Item."Unit Cost"); end; PurchaseLine.Validate(Quantity, Quantity); + PurchaseLine.Validate("Line Discount %", LineDiscount); PurchaseLine.Insert(true); end; diff --git a/Apps/W1/ContosoCoffeeDemoDataset/app/DemoTool/Contoso Helpers/ContosoUtilities.Codeunit.al b/Apps/W1/ContosoCoffeeDemoDataset/app/DemoTool/Contoso Helpers/ContosoUtilities.Codeunit.al index 308f370f47..106a37a065 100644 --- a/Apps/W1/ContosoCoffeeDemoDataset/app/DemoTool/Contoso Helpers/ContosoUtilities.Codeunit.al +++ b/Apps/W1/ContosoCoffeeDemoDataset/app/DemoTool/Contoso Helpers/ContosoUtilities.Codeunit.al @@ -15,7 +15,7 @@ codeunit 5142 "Contoso Utilities" exit(Round(UnitPrice * ContosoCoffeeDemoDataSetup."Price Factor", ContosoCoffeeDemoDataSetup."Rounding Precision")); end; - internal procedure AdjustDate(OriginalDate: Date): Date + procedure AdjustDate(OriginalDate: Date): Date var ContosoCoffeeDemoDataSetup: Record "Contoso Coffee Demo Data Setup"; TempDate: Date; diff --git a/Apps/W1/ContosoCoffeeDemoDataset/app/DemoTool/ContosoDemoDataModule.Enum.al b/Apps/W1/ContosoCoffeeDemoDataset/app/DemoTool/ContosoDemoDataModule.Enum.al index f3049405b4..ed095f6e67 100644 --- a/Apps/W1/ContosoCoffeeDemoDataset/app/DemoTool/ContosoDemoDataModule.Enum.al +++ b/Apps/W1/ContosoCoffeeDemoDataset/app/DemoTool/ContosoDemoDataModule.Enum.al @@ -30,8 +30,4 @@ enum 5160 "Contoso Demo Data Module" implements "Contoso Demo Data Module" { Implementation = "Contoso Demo Data Module" = "Job Module"; } - value(7; "Sustainability Module") - { - Implementation = "Contoso Demo Data Module" = "Sustainability Module"; - } } \ No newline at end of file diff --git a/Apps/W1/ContosoCoffeeDemoDataset/app/app.json b/Apps/W1/ContosoCoffeeDemoDataset/app/app.json index 53c3d22c3f..44f3e50868 100644 --- a/Apps/W1/ContosoCoffeeDemoDataset/app/app.json +++ b/Apps/W1/ContosoCoffeeDemoDataset/app/app.json @@ -1,50 +1,47 @@ { - "id": "5a0b41e9-7a42-4123-d521-2265186cfb31", - "name": "Contoso Coffee Demo Dataset", - "publisher": "Microsoft", - "version": "24.0.0.0", - "brief": "To help partners demonstrate the capabilities of Business Central, we are making new and extensive demo data available for various scenarios.", - "description": "Presales specialists can run the tool on top of Cronus or My Company and get the setup and demo data they'll need when they demonstrate various scenarios.", - "privacyStatement": "https://go.microsoft.com/fwlink/?linkid=724009", - "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", - "help": "https://go.microsoft.com/fwlink/?linkid=2187180", - "url": "https://go.microsoft.com/fwlink/?linkid=724011", - "logo": "./ExtensionLogo.png", - "dependencies": [ - { - "id": "b3780cd9-f8f8-4a83-a4d5-0c2ad87b28af", - "name": "Sustainability", - "publisher": "Microsoft", - "version": "24.0.0.0" - } - ], - "internalsVisibleTo": [ - { - "id": "c471774f-4b9e-45eb-9619-e7e0b96a8b98", - "name": "Contoso Coffee Demo Dataset Tests", - "publisher": "Microsoft" - } - ], - "screenshots": [], - "platform": "24.0.0.0", - "application": "24.0.0.0", - "idRanges": [ - { - "from": 4760, - "to": 4799 - }, - { - "from": 5100, - "to": 5300 - } - ], - "resourceExposurePolicy": { - "allowDebugging": true, - "allowDownloadingSource": false, - "includeSourceInSymbolFile": false - }, - "features": [ - "TranslationFile" - ], - "contextSensitiveHelpUrl": "https://learn.microsoft.com/en-us/dynamics365/business-central/contoso-coffee/contoso-coffee-intro" + "id": "5a0b41e9-7a42-4123-d521-2265186cfb31", + "name": "Contoso Coffee Demo Dataset", + "publisher": "Microsoft", + "version": "25.0.0.0", + "brief": "To help partners demonstrate the capabilities of Business Central, we are making new and extensive demo data available for various scenarios.", + "description": "Presales specialists can run the tool on top of Cronus or My Company and get the setup and demo data they'll need when they demonstrate various scenarios.", + "privacyStatement": "https://go.microsoft.com/fwlink/?linkid=724009", + "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", + "help": "https://go.microsoft.com/fwlink/?linkid=2187180", + "url": "https://go.microsoft.com/fwlink/?linkid=724011", + "logo": "./ExtensionLogo.png", + "dependencies": [ + + ], + "internalsVisibleTo": [ + { + "id": "c471774f-4b9e-45eb-9619-e7e0b96a8b98", + "name": "Contoso Coffee Demo Dataset Tests", + "publisher": "Microsoft" + } + ], + "screenshots": [ + + ], + "platform": "25.0.0.0", + "application": "25.0.0.0", + "idRanges": [ + { + "from": 4760, + "to": 4799 + }, + { + "from": 5100, + "to": 5300 + } + ], + "resourceExposurePolicy": { + "allowDebugging": true, + "allowDownloadingSource": false, + "includeSourceInSymbolFile": false + }, + "features": [ + "TranslationFile" + ], + "contextSensitiveHelpUrl": "https://learn.microsoft.com/en-us/dynamics365/business-central/contoso-coffee/contoso-coffee-intro" } \ No newline at end of file diff --git a/Apps/W1/ContosoCoffeeDemoDataset/test/app.json b/Apps/W1/ContosoCoffeeDemoDataset/test/app.json index d50d034789..0c787ee44c 100644 --- a/Apps/W1/ContosoCoffeeDemoDataset/test/app.json +++ b/Apps/W1/ContosoCoffeeDemoDataset/test/app.json @@ -1,42 +1,44 @@ { - "id": "c471774f-4b9e-45eb-9619-e7e0b96a8b98", - "name": "Contoso Coffee Demo Dataset Tests", - "publisher": "Microsoft", - "version": "24.0.0.0", - "brief": "Tests for Contoso Coffee Demo Dataset.", - "description": "Test for Contoso Coffee Demo Dataset.", - "privacyStatement": "https://go.microsoft.com/fwlink/?linkid=724009", - "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", - "help": "https://go.microsoft.com/fwlink/?linkid=2187180", - "url": "https://go.microsoft.com/fwlink/?linkid=724011", - "logo": "./ExtensionLogo.png", - "dependencies": [ - { - "id": "5a0b41e9-7a42-4123-d521-2265186cfb31", - "name": "Contoso Coffee Demo Dataset", - "publisher": "Microsoft", - "version": "24.0.0.0" - }, - { - "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", - "name": "Tests-TestLibraries", - "publisher": "Microsoft", - "version": "24.0.0.0" - } - ], - "screenshots": [], - "platform": "24.0.0.0", - "application": "24.0.0.0", - "idRanges": [ - { - "from": 148000, - "to": 148499 - } - ], - "resourceExposurePolicy": { - "allowDebugging": true, - "allowDownloadingSource": false, - "includeSourceInSymbolFile": false - }, - "contextSensitiveHelpUrl": "https://learn.microsoft.com/en-us/dynamics365/business-central/contoso-coffee/contoso-coffee-intro" + "id": "c471774f-4b9e-45eb-9619-e7e0b96a8b98", + "name": "Contoso Coffee Demo Dataset Tests", + "publisher": "Microsoft", + "version": "25.0.0.0", + "brief": "Tests for Contoso Coffee Demo Dataset.", + "description": "Test for Contoso Coffee Demo Dataset.", + "privacyStatement": "https://go.microsoft.com/fwlink/?linkid=724009", + "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", + "help": "https://go.microsoft.com/fwlink/?linkid=2187180", + "url": "https://go.microsoft.com/fwlink/?linkid=724011", + "logo": "./ExtensionLogo.png", + "dependencies": [ + { + "id": "5a0b41e9-7a42-4123-d521-2265186cfb31", + "name": "Contoso Coffee Demo Dataset", + "publisher": "Microsoft", + "version": "25.0.0.0" + }, + { + "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", + "name": "Tests-TestLibraries", + "publisher": "Microsoft", + "version": "25.0.0.0" + } + ], + "screenshots": [ + + ], + "platform": "25.0.0.0", + "application": "25.0.0.0", + "idRanges": [ + { + "from": 148000, + "to": 148499 + } + ], + "resourceExposurePolicy": { + "allowDebugging": true, + "allowDownloadingSource": false, + "includeSourceInSymbolFile": false + }, + "contextSensitiveHelpUrl": "https://learn.microsoft.com/en-us/dynamics365/business-central/contoso-coffee/contoso-coffee-intro" } \ No newline at end of file diff --git a/Apps/W1/CrossEnvironmentIntercompany/app/app.json b/Apps/W1/CrossEnvironmentIntercompany/app/app.json index cbdf005b5b..e352b2ebac 100644 --- a/Apps/W1/CrossEnvironmentIntercompany/app/app.json +++ b/Apps/W1/CrossEnvironmentIntercompany/app/app.json @@ -1,26 +1,26 @@ { - "id": "a190e87b-2f59-4e14-a727-421877802768", - "name": "API - Cross Environment Intercompany", - "publisher": "Microsoft", - "version": "24.0.0.0", - "brief": "API - Cross Environment Intercompany lets you easily access tha data necessary to use intercompany in between environments.", - "description": "API - Cross Environment Intercompany lets you easily access tha data necessary to use intercompany in between environments.", - "privacyStatement": "https://go.microsoft.com/fwlink/?linkid=724009", - "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", - "help": "https://go.microsoft.com/fwlink/?linkid=2103698", - "url": "https://go.microsoft.com/fwlink/?linkid=724011", - "contextSensitiveHelpUrl": "https://go.microsoft.com/fwlink/?linkid=2134520", - "logo": "ExtensionLogo.png", - "platform": "24.0.0.0", - "application": "24.0.0.0", - "target": "Cloud", - "idRanges": [ - { - "from": 30400, - "to": 30499 - } - ], - "features": [ - "TranslationFile" - ] + "id": "a190e87b-2f59-4e14-a727-421877802768", + "name": "API - Cross Environment Intercompany", + "publisher": "Microsoft", + "version": "25.0.0.0", + "brief": "API - Cross Environment Intercompany lets you easily access tha data necessary to use intercompany in between environments.", + "description": "API - Cross Environment Intercompany lets you easily access tha data necessary to use intercompany in between environments.", + "privacyStatement": "https://go.microsoft.com/fwlink/?linkid=724009", + "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", + "help": "https://go.microsoft.com/fwlink/?linkid=2103698", + "url": "https://go.microsoft.com/fwlink/?linkid=724011", + "contextSensitiveHelpUrl": "https://go.microsoft.com/fwlink/?linkid=2134520", + "logo": "ExtensionLogo.png", + "platform": "25.0.0.0", + "application": "25.0.0.0", + "target": "Cloud", + "idRanges": [ + { + "from": 30400, + "to": 30499 + } + ], + "features": [ + "TranslationFile" + ] } \ No newline at end of file diff --git a/Apps/W1/DataArchive/App/app.json b/Apps/W1/DataArchive/App/app.json index 99af7b2b57..d6168ef53c 100644 --- a/Apps/W1/DataArchive/App/app.json +++ b/Apps/W1/DataArchive/App/app.json @@ -4,17 +4,17 @@ "publisher": "Microsoft", "brief": "Archive important data before you delete it.", "description": "Reduce the amount of data in your production environment by archiving data that's important, but not frequently needed.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?linkid=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=2173136", "url": "https://go.microsoft.com/fwlink/?linkid=724011", "logo": "ExtensionLogo.png", - "application": "24.0.0.0", + "application": "25.0.0.0", "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 600, diff --git a/Apps/W1/DataArchive/test/app.json b/Apps/W1/DataArchive/test/app.json index 88777d640b..c343b92e06 100644 --- a/Apps/W1/DataArchive/test/app.json +++ b/Apps/W1/DataArchive/test/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "Data Archive Tests.", "description": "Data Archive Tests.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?LinkId=847985", "help": "https://go.microsoft.com/fwlink/?linkid=2173136", @@ -16,24 +16,24 @@ "id": "7819d79d-feea-4f09-bbed-5bbaca4bf323", "name": "Data Archive", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "dd0be2ea-f733-4d65-bb34-a28f4624fb14", "name": "Library Assert", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "target": "OnPrem", "resourceExposurePolicy": { "allowDebugging": false, "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/W1/DataCorrectionFA/app/app.json b/Apps/W1/DataCorrectionFA/app/app.json index d2bde6b476..b2380e18fc 100644 --- a/Apps/W1/DataCorrectionFA/app/app.json +++ b/Apps/W1/DataCorrectionFA/app/app.json @@ -2,9 +2,9 @@ "id": "7961e9dc-a8e5-49b1-839b-3a78803a4cb8", "name": "Troubleshoot FA Ledger Entries", "publisher": "Microsoft", - "version": "24.0.0.0", - "brief": "Troubleshoot – Find FA Ledger Entries with potential rounding issues.", - "description": "Troubleshoot – Find and correct FA Ledger Entries with potential rounding issues.", + "version": "25.0.0.0", + "brief": "Troubleshoot - Find FA Ledger Entries with potential rounding issues.", + "description": "Troubleshoot - Find and correct FA Ledger Entries with potential rounding issues.", "dependencies": [ ], @@ -16,8 +16,8 @@ "help": "https://go.microsoft.com/fwlink/?linkid=2206521", "url": "https://go.microsoft.com/fwlink/?LinkId=724011", "logo": "ExtensionLogo.png", - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 6090, diff --git a/Apps/W1/DataSearch/App/DataSearchEvents.codeunit.al b/Apps/W1/DataSearch/App/DataSearchEvents.codeunit.al index 6a50418f67..ac805adb62 100644 --- a/Apps/W1/DataSearch/App/DataSearchEvents.codeunit.al +++ b/Apps/W1/DataSearch/App/DataSearchEvents.codeunit.al @@ -120,4 +120,18 @@ codeunit 2682 "Data Search Events" procedure OnBeforeSearchTable(var RecordRef: RecordRef) begin end; + + /// + /// Allows the different implementation of the SerachTable procedure. + /// + /// The table no. of the table that is being displayed. + /// If the table as a 'Document Type'-like field, this value specifies the type as integer. + /// List of integer. You can specifify additional fields for a table here or remove unwanted. + /// List of Text. + /// Dictionary of Text/Text values. + /// Defines should system stop processing code in the procedure SearchTable. + [IntegrationEvent(false, false)] + internal procedure OnBeforeSearchTableProcedure(TableNo: Integer; TableType: Integer; var FieldList: List of [Integer]; var SearchStrings: List of [Text]; var Results: Dictionary of [Text, Text]; var IsHandled: Boolean) + begin + end; } \ No newline at end of file diff --git a/Apps/W1/DataSearch/App/DataSearchInTable.codeunit.al b/Apps/W1/DataSearch/App/DataSearchInTable.codeunit.al index 477f119190..8756833140 100644 --- a/Apps/W1/DataSearch/App/DataSearchInTable.codeunit.al +++ b/Apps/W1/DataSearch/App/DataSearchInTable.codeunit.al @@ -175,7 +175,13 @@ codeunit 2680 "Data Search in Table" SearchString: Text; SearchString1: Text; FieldMatchString: Text; + IsHandled: Boolean; begin + IsHandled := false; + DataSearchEvents.OnBeforeSearchTableProcedure(TableNo, TableType, FieldList, SearchStrings, Results, IsHandled); + if IsHandled then + exit; + SearchStrings.Get(1, SearchString1); UseTextSearch := IsTextSearch(SearchString1); diff --git a/Apps/W1/DataSearch/App/DataSearchObjectMapping.Codeunit.al b/Apps/W1/DataSearch/App/DataSearchObjectMapping.Codeunit.al index e3f921a275..08232cb0c9 100644 --- a/Apps/W1/DataSearch/App/DataSearchObjectMapping.Codeunit.al +++ b/Apps/W1/DataSearch/App/DataSearchObjectMapping.Codeunit.al @@ -146,6 +146,36 @@ codeunit 2685 "Data Search Object Mapping" ParentTableNo := Database::"Reminder Header"; Database::"Issued Reminder Line": ParentTableNo := Database::"Issued Reminder Header"; + Database::"Sales Line Archive": + ParentTableNo := Database::"Sales Header Archive"; + Database::"Purchase Line Archive": + ParentTableNo := Database::"Purchase Header Archive"; + Database::"Job Task": + ParentTableNo := Database::"Job"; + Database::"Job Planning Line": + ParentTableNo := Database::"Job"; + Database::"Prod. Order Line": + ParentTableNo := Database::"Production Order"; + Database::"Production BOM Line": + ParentTableNo := Database::"Production BOM Header"; + Database::"Routing Line": + ParentTableNo := Database::"Routing Header"; + Database::"Warehouse Shipment Line": + ParentTableNo := Database::"Warehouse Shipment Header"; + Database::"Warehouse Receipt Line": + ParentTableNo := Database::"Warehouse Receipt Header"; + Database::"Warehouse Activity Line": + ParentTableNo := Database::"Warehouse Activity Header"; + Database::"Registered Whse. Activity Line": + ParentTableNo := Database::"Registered Whse. Activity Hdr."; + Database::"Posted Whse. Receipt Line": + ParentTableNo := Database::"Posted Whse. Receipt Header"; + Database::"Assembly Line": + ParentTableNo := Database::"Assembly Header"; + Database::"Transfer Line": + ParentTableNo := Database::"Transfer Header"; + else + ParentTableNo := 0; end; if ParentTableNo = 0 then DataSearchEvents.OnGetParentTable(TableNo, ParentTableNo); @@ -192,6 +222,35 @@ codeunit 2685 "Data Search Object Mapping" SubTableNos.Add(Database::"Reminder Line"); Database::"Issued Reminder Header": SubTableNos.Add(Database::"Issued Reminder Line"); + Database::"Sales Header Archive": + SubTableNos.Add(Database::"Sales Line Archive"); + Database::"Purchase Header Archive": + SubTableNos.Add(Database::"Purchase Line Archive"); + Database::Job: + begin + SubTableNos.Add(Database::"Job Task"); + SubTableNos.Add(Database::"Job Planning Line"); + end; + Database::"Production Order": + SubTableNos.Add(Database::"Prod. Order Line"); + Database::"Production BOM Header": + SubTableNos.Add(Database::"Production BOM Line"); + Database::"Routing Header": + SubTableNos.Add(Database::"Routing Line"); + Database::"Warehouse Shipment Header": + SubTableNos.Add(Database::"Warehouse Shipment Line"); + Database::"Warehouse Receipt Header": + SubTableNos.Add(Database::"Warehouse Receipt Line"); + Database::"Warehouse Activity Header": + SubTableNos.Add(Database::"Warehouse Activity Line"); + Database::"Registered Whse. Activity Hdr.": + SubTableNos.Add(Database::"Registered Whse. Activity Line"); + Database::"Posted Whse. Receipt Header": + SubTableNos.Add(Database::"Posted Whse. Receipt Line"); + Database::"Assembly Header": + SubTableNos.Add(Database::"Assembly Line"); + Database::"Transfer Header": + SubTableNos.Add(Database::"Transfer Line"); end; if SubTableNos.Count() = 0 then begin DataSearchEvents.OnGetSubTable(TableNo, SubTableNo); diff --git a/Apps/W1/DataSearch/App/app.json b/Apps/W1/DataSearch/App/app.json index ec05f27b29..c22679dbd5 100644 --- a/Apps/W1/DataSearch/App/app.json +++ b/Apps/W1/DataSearch/App/app.json @@ -4,14 +4,14 @@ "publisher": "Microsoft", "brief": "Enables a user to search data in predefined tables.", "description": "Enables a user to search data in predefined tables. An administrator can select which tables and fields to search", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?linkid=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2182906", "help": "https://go.microsoft.com/fwlink/?linkid=2204037", "contextSensitiveHelpUrl": "https://go.microsoft.com/fwlink/?linkid=220403", "url": "https://go.microsoft.com/fwlink/?linkid=724011", "logo": "ExtensionLogo.png", - "application": "24.0.0.0", + "application": "25.0.0.0", "internalsVisibleTo": [ { "id": "c0146a0a-d0fe-4eec-8857-8a66551d010d", @@ -22,7 +22,7 @@ "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 2680, diff --git a/Apps/W1/DataSearch/test/app.json b/Apps/W1/DataSearch/test/app.json index af057fec21..affbd450c5 100644 --- a/Apps/W1/DataSearch/test/app.json +++ b/Apps/W1/DataSearch/test/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "Data Search Tests.", "description": "Data Search Tests.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2182906", "help": "https://go.microsoft.com/fwlink/?linkid=2206906", @@ -16,37 +16,37 @@ "id": "ac14293f-1eb7-4a7b-9936-b280da31970b", "name": "Data Search", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "dd0be2ea-f733-4d65-bb34-a28f4624fb14", "name": "Library Assert", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ - { - "from": 139507, - "to": 139509 - } - ], + { + "from": 139507, + "to": 139509 + } + ], "target": "OnPrem", "features": [ - "TranslationFile" - ], -"resourceExposurePolicy": { + "TranslationFile" + ], + "resourceExposurePolicy": { "allowDebugging": false, "allowDownloadingSource": true, "includeSourceInSymbolFile": true diff --git a/Apps/W1/DynamicsGPHistoricalData/app/app.json b/Apps/W1/DynamicsGPHistoricalData/app/app.json index 7a2456034c..8049c54bf4 100644 --- a/Apps/W1/DynamicsGPHistoricalData/app/app.json +++ b/Apps/W1/DynamicsGPHistoricalData/app/app.json @@ -2,7 +2,7 @@ "id": "7c7d97ca-3598-40f5-b263-f713f49bd2a5", "name": "Dynamics GP Historical Data", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "This extension adds the necessary components to retain historical Dynamics GP data after the cloud migration. Only uninstall this extension if the historical data is no longer needed.", "description": "This extension adds the necessary components to retain historical Dynamics GP data after the cloud migration. Only uninstall this extension if the historical data is no longer needed.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -17,14 +17,14 @@ "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 1, "to": 49999 } ], - "application": "24.0.0.0", + "application": "25.0.0.0", "resourceExposurePolicy": { "allowDebugging": true, "allowDownloadingSource": true, diff --git a/Apps/W1/DynamicsGPHistoricalData/test/app.json b/Apps/W1/DynamicsGPHistoricalData/test/app.json index 8f276e4a1f..0133388f29 100644 --- a/Apps/W1/DynamicsGPHistoricalData/test/app.json +++ b/Apps/W1/DynamicsGPHistoricalData/test/app.json @@ -2,7 +2,7 @@ "id": "b199fc6d-1967-40c7-8d1c-ecdfa54009ed", "name": "Dynamics GP Historical Data Tests", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Tests for the Dynamics GP Historical Data extension.", "description": "Tests for the Dynamics GP Historical Data extension.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -16,20 +16,20 @@ "id": "7c7d97ca-3598-40f5-b263-f713f49bd2a5", "name": "Dynamics GP Historical Data", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 139410, diff --git a/Apps/W1/DynamicsGPHistorySmartLists/app/app.json b/Apps/W1/DynamicsGPHistorySmartLists/app/app.json index 7553236279..9505637b5a 100644 --- a/Apps/W1/DynamicsGPHistorySmartLists/app/app.json +++ b/Apps/W1/DynamicsGPHistorySmartLists/app/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "This extension will allow you to query your Dynamics GP history data with your Dynamics 365 Business Central cloud tenant.", "description": "This extension will add queries for your Dynamics GP history data that is in your Dynamics 365 Business Central cloud tenant. This will enable you to view and search your Dynamics GP history data, and provide you with anytime, anywhere access.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=825900", @@ -16,13 +16,13 @@ "id": "feeb3504-556e-4790-b28d-a2b9ce302d81", "name": "Dynamics GP Intelligent Cloud", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 1, @@ -35,5 +35,5 @@ "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/W1/EDocument/app/Permissions/EDocCoreBasic.PermissionSet.al b/Apps/W1/EDocument/app/Permissions/EDocCoreBasic.PermissionSet.al index 473d9e4217..c6293c4ddc 100644 --- a/Apps/W1/EDocument/app/Permissions/EDocCoreBasic.PermissionSet.al +++ b/Apps/W1/EDocument/app/Permissions/EDocCoreBasic.PermissionSet.al @@ -26,6 +26,6 @@ permissionset 6103 "E-Doc. Core - Basic" tabledata "E-Document Integration Log" = im, tabledata "E-Doc. Service Data Exch. Def." = im, tabledata "E-Doc. Service Supported Type" = im, - tabledata "E-Doc. Imported Line" = im, - tabledata "E-Doc. Order Match" = im; + tabledata "E-Doc. Imported Line" = imd, + tabledata "E-Doc. Order Match" = imd; } diff --git a/Apps/W1/EDocument/app/Permissions/EDocCoreObjects.PermissionSet.al b/Apps/W1/EDocument/app/Permissions/EDocCoreObjects.PermissionSet.al index 2e4cc0850f..a2bb005bd2 100644 --- a/Apps/W1/EDocument/app/Permissions/EDocCoreObjects.PermissionSet.al +++ b/Apps/W1/EDocument/app/Permissions/EDocCoreObjects.PermissionSet.al @@ -7,6 +7,7 @@ namespace Microsoft.eServices.EDocument; using Microsoft.eServices.EDocument.IO; using Microsoft.eServices.EDocument.IO.Peppol; using Microsoft.EServices.EDocument.OrderMatch; +using Microsoft.EServices.EDocument.OrderMatch.Copilot; permissionset 6100 "E-Doc. Core - Objects" { @@ -25,6 +26,7 @@ permissionset 6100 "E-Doc. Core - Objects" table "E-Doc. Service Supported Type" = X, table "E-Doc. Order Match" = X, table "E-Doc. Imported Line" = X, + table "E-Doc. PO Match Prop. Buffer" = X, codeunit "E-Document Import Job" = X, codeunit "E-Doc. Integration Management" = X, codeunit "E-Doc. Mapping" = X, @@ -62,6 +64,8 @@ permissionset 6100 "E-Doc. Core - Objects" codeunit "Pre-Map Service Inv. Line" = X, codeunit "EDoc PEPPOL BIS 3.0" = X, codeunit "E-Doc. Line Matching" = X, + codeunit "E-Doc. PO AOAI Function" = X, + codeunit "E-Doc. PO Copilot Matching" = X, page "E-Doc. Changes Part" = X, page "E-Doc. Changes Preview" = X, page "E-Document Activities" = X, @@ -80,5 +84,8 @@ permissionset 6100 "E-Doc. Core - Objects" page "E-Doc. Imported Line Sub" = X, page "E-Doc. Purchase Order Sub" = X, page "E-Doc. Order Map. Activities" = X, - page "E-Doc Service Supported Types" = X; + page "E-Doc Service Supported Types" = X, + page "E-Doc. PO Copilot Prop" = X, + page "E-Doc. PO Match Prop. Sub" = X, + page "E-Doc. Order Match Act." = X; } diff --git a/Apps/W1/EDocument/app/app.json b/Apps/W1/EDocument/app/app.json index 5ff4f4cd9d..19cbc30287 100644 --- a/Apps/W1/EDocument/app/app.json +++ b/Apps/W1/EDocument/app/app.json @@ -1,37 +1,37 @@ { - "id": "e1d97edc-c239-46b4-8d84-6368bdf67c8b", - "name": "E-Document Core", - "publisher": "Microsoft", - "brief": "The Dynamics 365 Business Central E-Documents module enables different models of electronic invoicing, available for additional localizations.", - "description": "Business Central's E-Documents module is the foundation layer for all e-invoicing standards covering most common processes, but it can be used for other electronic documents. The module is easily extendable with the country-based e-invoicing apps. The E-Documents app covers both sales and purchase processes and can have different lifecycles from standard invoices in Business Central.", - "version": "24.0.0.0", - "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", - "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", - "help": "https://go.microsoft.com/fwlink/?linkid=2204541", - "url": "https://go.microsoft.com/fwlink/?LinkId=724011", - "logo": "ExtensionLogo.png", - "contextSensitiveHelpUrl": "https://go.microsoft.com/fwlink/?linkid=2206603", - "dependencies": [], - "internalsVisibleTo": [ - { - "id": "e1d97edc-c239-46b4-8d84-6368bdf67c8c", - "name": "E-Document Core Tests", - "publisher": "Microsoft" - } - ], - "screenshots": [], - "platform": "24.0.0.0", - "idRanges": [ - { - "from": 6100, - "to": 6170 - } - ], - "resourceExposurePolicy": { - "allowDebugging": true, - "allowDownloadingSource": true, - "includeSourceInSymbolFile": true - }, - "application": "24.0.0.0", - "target": "Cloud" + "id": "e1d97edc-c239-46b4-8d84-6368bdf67c8b", + "name": "E-Document Core", + "publisher": "Microsoft", + "brief": "The Dynamics 365 Business Central E-Documents module enables different models of electronic invoicing, available for additional localizations.", + "description": "Business Central's E-Documents module is the foundation layer for all e-invoicing standards covering most common processes, but it can be used for other electronic documents. The module is easily extendable with the country-based e-invoicing apps. The E-Documents app covers both sales and purchase processes and can have different lifecycles from standard invoices in Business Central.", + "version": "25.0.0.0", + "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", + "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", + "help": "https://go.microsoft.com/fwlink/?linkid=2204541", + "url": "https://go.microsoft.com/fwlink/?LinkId=724011", + "logo": "ExtensionLogo.png", + "contextSensitiveHelpUrl": "https://go.microsoft.com/fwlink/?linkid=2206603", + "dependencies": [], + "internalsVisibleTo": [ + { + "id": "e1d97edc-c239-46b4-8d84-6368bdf67c8c", + "name": "E-Document Core Tests", + "publisher": "Microsoft" + } + ], + "screenshots": [], + "platform": "25.0.0.0", + "idRanges": [ + { + "from": 6100, + "to": 6170 + } + ], + "resourceExposurePolicy": { + "allowDebugging": true, + "allowDownloadingSource": true, + "includeSourceInSymbolFile": true + }, + "application": "25.0.0.0", + "target": "OnPrem" } \ No newline at end of file diff --git a/Apps/W1/EDocument/app/src/Document/EDocument.Page.al b/Apps/W1/EDocument/app/src/Document/EDocument.Page.al index 502b11de08..ba761c9a0e 100644 --- a/Apps/W1/EDocument/app/src/Document/EDocument.Page.al +++ b/Apps/W1/EDocument/app/src/Document/EDocument.Page.al @@ -1,4 +1,4 @@ -// ------------------------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. See License.txt in the project root for license information. // ------------------------------------------------------------------------------------------------ @@ -6,6 +6,8 @@ namespace Microsoft.eServices.EDocument; using Microsoft.Bank.Reconciliation; using Microsoft.eServices.EDocument.OrderMatch; +using Microsoft.eServices.EDocument.OrderMatch.Copilot; +using System.Telemetry; using System.Utilities; page 6121 "E-Document" @@ -166,7 +168,7 @@ page 6121 "E-Document" #endif part(ErrorMessagesPart; "Error Messages Part") { - Visible = HasErrorsAndWarnings; + Visible = HasErrorsOrWarnings; ShowFilter = false; UpdatePropagation = Both; } @@ -281,26 +283,30 @@ page 6121 "E-Document" } action(CreateDocument) { - Caption = 'Recreate Document'; - ToolTip = 'Recreate the document based on imported electronic document.'; + Caption = 'Reprocess Document'; + ToolTip = 'Reprocess the electronic file to a purchase document.'; Image = CreateXMLFile; - Visible = (not ShowCreateJnlLine) and IsIncomingDoc and HasErrorsAndWarnings; + Visible = IsIncomingDoc and (not IsProcessed); trigger OnAction() begin EDocImport.ProcessDocument(Rec, false); + if EDocumentErrorHelper.HasErrors(Rec) then + Message(DocNotCreatedMsg, Rec."Document Type"); end; } action(CreateJournal) { - Caption = 'Recreate Journal Line'; - ToolTip = 'Recreate the journal line.'; + Caption = 'Reprocess Journal Line'; + ToolTip = 'Reprocess the electronic file to a journal line.'; Image = Journal; - Visible = ShowCreateJnlLine and IsIncomingDoc and HasErrorsAndWarnings; + Visible = IsIncomingDoc and (not IsProcessed); trigger OnAction() begin EDocImport.ProcessDocument(Rec, true); + if EDocumentErrorHelper.HasErrors(Rec) then + Message(DocNotCreatedMsg, Rec."Document Type"); end; } #if not CLEAN24 @@ -321,12 +327,26 @@ page 6121 "E-Document" end; } #endif + action(MatchToOrderCopilotEnabled) + { + Caption = 'Match Purchase Order'; + ToolTip = 'Match E-document lines to Purchase Order.'; + Image = SparkleFilled; + Visible = ShowMapToOrder and CopilotEnabled; + + trigger OnAction() + var + EDocOrderMatch: Codeunit "E-Doc. Line Matching"; + begin + EDocOrderMatch.RunMatching(Rec); + end; + } action(MatchToOrder) { Caption = 'Match Purchase Order'; ToolTip = 'Match E-document lines to Purchase Order.'; Image = Reconcile; - Visible = ShowMapToOrder; + Visible = ShowMapToOrder and (not CopilotEnabled); trigger OnAction() var @@ -344,11 +364,12 @@ page 6121 "E-Document" Caption = 'Replace Source Document'; ToolTip = 'Import and replace the electronic document.'; Image = UpdateXML; - Visible = IsIncomingDoc and HasErrorsAndWarnings; + Visible = IsIncomingDoc and (not IsProcessed); trigger OnAction() begin EDocImport.UploadDocument(Rec); + CurrPage.Update(); end; } action(TextToAccountMapping) @@ -357,7 +378,19 @@ page 6121 "E-Document" Image = MapAccounts; RunObject = Page "Text-to-Account Mapping Wksh."; ToolTip = 'Create a mapping of text on electronic documents to identical text on specific debit, credit, and balancing accounts in the general ledger or on bank accounts so that the resulting document or journal lines are prefilled with the specified information.'; - Visible = IsIncomingDoc and HasErrorsAndWarnings; + Visible = IsIncomingDoc and HasErrors and (not ShowRelink); + } + action(LinkOrder) + { + Caption = 'Update Purchase Order Link'; + ToolTip = 'Updated Purchase Order link for E-Document to different Purchase Order.'; + Image = LinkAccount; + Visible = IsIncomingDoc and ShowRelink and (not IsProcessed); + + trigger OnAction() + begin + EDocImport.UpdatePurchaseOrderLink(Rec); + end; } } @@ -378,19 +411,23 @@ page 6121 "E-Document" { group(Category_Process) { + actionref(MatchToOrderCE_Promoted; MatchToOrderCopilotEnabled) { } actionref(MatchToOrder_Promoted; MatchToOrder) { } + actionref(LinkOrder_Promoted; LinkOrder) { } actionref(CreateDocument_Promoted; CreateDocument) { } actionref(CreateJournal_Promoted; CreateJournal) { } + actionref(ImportManually_Promoted; ImportManually) { } + actionref(TextToAccountMapping_Promoted; TextToAccountMapping) { } actionref(Send_Promoted; Send) { } actionref(Recreate_Promoted; Recreate) { } actionref(Cancel_promoteed; Cancel) { } actionref(Approval_promoteed; GetApproval) { } + } group(Category_Troubleshoot) { Caption = 'Troubleshoot'; - actionref(ImportManually_Promoted; ImportManually) { } - actionref(TextToAccountMapping_Promoted; TextToAccountMapping) { } + Visible = false; } #if not CLEAN24 group(Out) @@ -436,18 +473,36 @@ page 6121 "E-Document" } trigger OnOpenPage() + var + EDocPOMatching: Codeunit "E-Doc. PO Copilot Matching"; begin ShowMapToOrder := false; - HasErrorsAndWarnings := false; + HasErrorsOrWarnings := false; + HasErrors := false; + IsProcessed := false; + CopilotEnabled := EDocPOMatching.IsCopilotEnabled(); end; trigger OnAfterGetRecord() begin + IsProcessed := Rec.Status = Rec.Status::Processed; + IsIncomingDoc := Rec.Direction = Rec.Direction::Incoming; + RecordLinkTxt := EDocumentHelper.GetRecordLinkText(Rec); - HasErrorsAndWarnings := EDocumentErrorHelper.HasErrors(Rec); - if HasErrorsAndWarnings then - ShowErrors(); + HasErrorsOrWarnings := (EDocumentErrorHelper.ErrorMessageCount(Rec) + EDocumentErrorHelper.WarningMessageCount(Rec)) > 0; + HasErrors := EDocumentErrorHelper.ErrorMessageCount(Rec) > 0; + if HasErrorsOrWarnings then + ShowErrorsAndWarnings(); + SetStyle(); + ResetActionVisiability(); + SetIncomingDocActions(); + + EDocImport.ProcessEDocPendingOrderMatch(Rec); + end; + + local procedure SetStyle() + begin case Rec.Status of Rec.Status::Error: StyleStatusTxt := 'Unfavorable'; @@ -456,11 +511,9 @@ page 6121 "E-Document" else StyleStatusTxt := 'None'; end; - - ShowActionsForEDocument(); end; - local procedure ShowErrors() + local procedure ShowErrorsAndWarnings() var ErrorMessage: Record "Error Message"; TempErrorMessage: Record "Error Message" temporary; @@ -469,6 +522,9 @@ page 6121 "E-Document" ErrorMessage.CopyToTemp(TempErrorMessage); CurrPage.ErrorMessagesPart.Page.SetRecords(TempErrorMessage); CurrPage.ErrorMessagesPart.Page.Update(false); + + ErrorsAndWarningsNotification.Message(EDocHasErrorOrWarningMsg); + ErrorsAndWarningsNotification.Send(); end; local procedure SendEDocument() @@ -488,25 +544,30 @@ page 6121 "E-Document" EDocumentBackgroundjobs.GetEDocumentResponse(); end; - local procedure ShowActionsForEDocument() - begin - IsIncomingDoc := Rec.Direction = Rec.Direction::Incoming; - if IsIncomingDoc then - SetIncomingDocActions(); - end; - local procedure SetIncomingDocActions() var EDocService: Record "E-Document Service"; - EDocServiceStatus: Record "E-Document Service Status"; + EDocServiceStatus2: Record "E-Document Service Status"; EDocLog: Codeunit "E-Document Log"; + FeatureTelemetry: Codeunit "Feature Telemetry"; + EDocPOCopilotMatching: Codeunit "E-Doc. PO Copilot Matching"; begin + if not IsIncomingDoc then + exit; + EDocService := EDocLog.GetLastServiceFromLog(Rec); - ShowCreateJnlLine := EDocService."Create Journal Lines"; - if (Rec."Document Type" = Enum::"E-Document Type"::"Purchase Order") and (Rec.Status <> Rec.Status::Processed) then - if EDocServiceStatus.Get(Rec."Entry No", EDocService.Code) then - ShowMapToOrder := EDocServiceStatus.Status = EDocServiceStatus.Status::"Order Linked"; + if (Rec."Document Type" = Enum::"E-Document Type"::"Purchase Order") and (Rec.Status <> Rec.Status::Processed) then begin + EDocServiceStatus2.Get(Rec."Entry No", EDocService.Code); + ShowMapToOrder := EDocServiceStatus2.Status = Enum::"E-Document Service Status"::"Order Linked"; + ShowRelink := true; + FeatureTelemetry.LogUptake('0000MMK', EDocPOCopilotMatching.FeatureName(), Enum::"Feature Uptake Status"::Discovered); + end; + end; + local procedure ResetActionVisiability() + begin + ShowMapToOrder := false; + ShowRelink := false; end; var @@ -515,6 +576,10 @@ page 6121 "E-Document" EDocImport: Codeunit "E-Doc. Import"; EDocumentErrorHelper: Codeunit "E-Document Error Helper"; EDocumentHelper: Codeunit "E-Document Processing"; + ErrorsAndWarningsNotification: Notification; RecordLinkTxt, StyleStatusTxt : Text; - ShowMapToOrder, HasErrorsAndWarnings, ShowCreateJnlLine, IsIncomingDoc : Boolean; + ShowRelink, ShowMapToOrder, HasErrorsOrWarnings, HasErrors, IsIncomingDoc, IsProcessed, CopilotEnabled : Boolean; + EDocHasErrorOrWarningMsg: Label 'Errors or warnings found for E-Document. Please review below in "Error Messages" section.'; + DocNotCreatedMsg: Label 'Failed to create new %1 from E-Document. Please review errors below.', Comment = '%1 - E-Document Document Type'; + } diff --git a/Apps/W1/EDocument/app/src/Document/EDocument.Table.al b/Apps/W1/EDocument/app/src/Document/EDocument.Table.al index 8f9ef75e4e..4120ba3b1e 100644 --- a/Apps/W1/EDocument/app/src/Document/EDocument.Table.al +++ b/Apps/W1/EDocument/app/src/Document/EDocument.Table.al @@ -14,7 +14,7 @@ using System.Threading; table 6121 "E-Document" { - DataCaptionFields = "Document No.", "Bill-to/Pay-to Name"; + DataCaptionFields = "Entry No", "Bill-to/Pay-to Name"; LookupPageId = "E-Documents"; DrillDownPageId = "E-Documents"; DataClassification = CustomerContent; diff --git a/Apps/W1/EDocument/app/src/Document/EDocumentServiceStatus.Enum.al b/Apps/W1/EDocument/app/src/Document/EDocumentServiceStatus.Enum.al index 06824f83de..162c8a9afc 100644 --- a/Apps/W1/EDocument/app/src/Document/EDocumentServiceStatus.Enum.al +++ b/Apps/W1/EDocument/app/src/Document/EDocumentServiceStatus.Enum.al @@ -14,7 +14,7 @@ enum 6106 "E-Document Service Status" value(3; "Cancel Error") { Caption = 'Cancel error'; } value(4; "Canceled") { Caption = 'Canceled'; } value(5; "Imported") { Caption = 'Imported'; } - value(6; "Imported Document Processing Error") { Caption = 'Imported document erocessing error'; } + value(6; "Imported Document Processing Error") { Caption = 'Imported document processing error'; } value(7; "Imported Document Created") { Caption = 'Imported document created'; } value(8; "Order Updated") { Caption = 'Order updated'; } value(9; "Journal Line Created") { Caption = 'Journal line created'; } @@ -26,5 +26,5 @@ enum 6106 "E-Document Service Status" value(15; "Rejected") { Caption = 'Rejected'; } value(16; "Batch Imported") { Caption = 'Batch imported'; } value(17; "Order Linked") { Caption = 'Order linked'; } - value(18; "Pending") { Caption = 'Pending'; } + value(18; "Pending") { Caption = 'Pending Document Link'; } } diff --git a/Apps/W1/EDocument/app/src/Document/EDocuments.Page.al b/Apps/W1/EDocument/app/src/Document/EDocuments.Page.al index edb2f34e7f..c8cd435b4e 100644 --- a/Apps/W1/EDocument/app/src/Document/EDocuments.Page.al +++ b/Apps/W1/EDocument/app/src/Document/EDocuments.Page.al @@ -37,6 +37,10 @@ page 6122 "E-Documents" { ToolTip = 'Specifies the customer/vendor name of the electronic document.'; } + field("Document Type"; Rec."Document Type") + { + ToolTip = 'Specifies the document type of the electronic document.'; + } field("Document No."; Rec."Document No.") { ToolTip = 'Specifies the document number of the electronic document.'; @@ -58,18 +62,13 @@ page 6122 "E-Documents" { action(ImportManually) { - Caption = 'Create and Process From File'; + Caption = 'New From File'; ToolTip = 'Create an electronic document by manually uploading a file.'; Image = Import; trigger OnAction() - var - EDocument: Record "E-Document"; - EDocImport: Codeunit "E-Doc. Import"; begin - EDocImport.UploadDocument(EDocument); - if EDocument."Entry No" <> 0 then - EDocImport.ProcessDocument(EDocument, false); + NewFromFile(); end; } action(EDocumentServices) @@ -93,4 +92,23 @@ page 6122 "E-Documents" actionref(Promoted_EDocumentServices; EDocumentServices) { } } } + + var + DocNotCreatedQst: Label 'Failed to create new %1 from E-Document. Do you want to open E-Document and see the reported errors?', Comment = '%1 - E-Document Document Type'; + + + local procedure NewFromFile() + var + EDocument: Record "E-Document"; + EDocImport: Codeunit "E-Doc. Import"; + EDocErrorHelper: Codeunit "E-Document Error Helper"; + begin + EDocImport.UploadDocument(EDocument); + if EDocument."Entry No" <> 0 then begin + EDocImport.ProcessDocument(EDocument, false); + if EDocErrorHelper.HasErrors(EDocument) then + if Confirm(DocNotCreatedQst, true, EDocument."Document Type") then + Page.Run(Page::"E-Document", EDocument); + end; + end; } diff --git a/Apps/W1/EDocument/app/src/EDocumentInstall.Codeunit.al b/Apps/W1/EDocument/app/src/EDocumentInstall.Codeunit.al index 2c9660f53c..317fd58838 100644 --- a/Apps/W1/EDocument/app/src/EDocumentInstall.Codeunit.al +++ b/Apps/W1/EDocument/app/src/EDocumentInstall.Codeunit.al @@ -8,6 +8,8 @@ using System.IO; using System.Reflection; using System.Utilities; using System.Upgrade; +using Microsoft.eServices.EDocument.OrderMatch.Copilot; + codeunit 6161 "E-Document Install" { Access = Internal; @@ -18,6 +20,13 @@ codeunit 6161 "E-Document Install" InsertDataExch(); end; + trigger OnInstallAppPerDatabase() + var + EDocAIMatching: Codeunit "E-Doc. PO Copilot Matching"; + begin + EDocAIMatching.RegisterAICapability(); + end; + internal procedure InsertDataExch() var UpgradeTag: Codeunit "Upgrade Tag"; @@ -38,7 +47,7 @@ codeunit 6161 "E-Document Install" end; - local procedure ImportServiceInvoiceXML() + internal procedure ImportServiceInvoiceXML() var DataExchDef: Record "Data Exch. Def"; Field: Record Field; @@ -66,7 +75,7 @@ codeunit 6161 "E-Document Install" Clear(TempBlob); end; - local procedure ImportServiceCreditMemoXML() + internal procedure ImportServiceCreditMemoXML() var DataExchDef: Record "Data Exch. Def"; Field: Record Field; @@ -94,7 +103,7 @@ codeunit 6161 "E-Document Install" Clear(TempBlob); end; - local procedure ImportSalesInvoiceXML() + internal procedure ImportSalesInvoiceXML() var DataExchDef: Record "Data Exch. Def"; TempBlob: Codeunit "Temp Blob"; @@ -113,7 +122,7 @@ codeunit 6161 "E-Document Install" Clear(TempBlob); end; - local procedure ImportSalesCreditMemoXML() + internal procedure ImportSalesCreditMemoXML() var DataExchDef: Record "Data Exch. Def"; TempBlob: Codeunit "Temp Blob"; @@ -132,7 +141,7 @@ codeunit 6161 "E-Document Install" Clear(TempBlob); end; - local procedure ImportCreditMemoXML() + internal procedure ImportCreditMemoXML() var DataExchDef: Record "Data Exch. Def"; TempBlob: Codeunit "Temp Blob"; @@ -149,7 +158,7 @@ codeunit 6161 "E-Document Install" Clear(TempBlob); end; - local procedure ImportInvoiceXML() + internal procedure ImportInvoiceXML() var DataExchDef: Record "Data Exch. Def"; TempBlob: Codeunit "Temp Blob"; diff --git a/Apps/W1/EDocument/app/src/Extensions/EDocOrderMapActivities.Page.al b/Apps/W1/EDocument/app/src/Extensions/EDocOrderMapActivities.Page.al index 9513a4de83..737e110d4f 100644 --- a/Apps/W1/EDocument/app/src/Extensions/EDocOrderMapActivities.Page.al +++ b/Apps/W1/EDocument/app/src/Extensions/EDocOrderMapActivities.Page.al @@ -9,40 +9,37 @@ page 6159 "E-Doc. Order Map. Activities" PageType = CardPart; RefreshOnActivate = true; Caption = 'E-Document Activities'; + ShowFilter = false; layout { area(Content) { - cuegroup("EDocument Activities") + cuegroup("IncomingEDocument") { - ShowCaption = false; - cuegroup("IncomingEDocument") - { - Caption = 'Incoming E-Document'; + Caption = 'Incoming E-Document'; - field(MatchedPurchaseOrderCount; EDocumentHelper.MatchedPurchaseOrdersCount()) - { - ApplicationArea = Basic, Suite; - Caption = 'Matched Purchase Orders'; - ToolTip = 'Specifies the number of purchase orders that have matched to a received e-document.'; + field(MatchedPurchaseOrderCount; EDocumentHelper.MatchedPurchaseOrdersCount()) + { + ApplicationArea = Basic, Suite; + Caption = 'Linked Purchase Orders'; + ToolTip = 'Specifies the number of e-documents that are linked to a purchase order and needs to be processed.'; - trigger OnDrillDown() - begin - EDocumentHelper.OpenMatchedPurchaseOrders(); - end; - } - field(WaitingPurchaseOrderCount; EDocumentHelper.MatchedPurchaseEDocumentsCount()) - { - ApplicationArea = Basic, Suite; - Caption = 'Waiting Purchase E-Documents'; - ToolTip = 'Specifies the number of received purchase e-documents that needs to be reviewed.'; + trigger OnDrillDown() + begin + EDocumentHelper.OpenMatchedPurchaseOrders(); + end; + } + field(WaitingPurchaseOrderCount; EDocumentHelper.MatchedPurchaseEDocumentsCount()) + { + ApplicationArea = Basic, Suite; + Caption = 'Waiting Purchase E-Invoices'; + ToolTip = 'Specifies the number of received purchase e-documents that needs to be reviewed.'; - trigger OnDrillDown() - begin - EDocumentHelper.OpenMatchedPurchaseEDoc(); - end; - } + trigger OnDrillDown() + begin + EDocumentHelper.OpenWaitingPurchaseEDoc(); + end; } } } diff --git a/Apps/W1/EDocument/app/src/Extensions/EDocPostedSalesInv.PageExt.al b/Apps/W1/EDocument/app/src/Extensions/EDocPostedSalesInv.PageExt.al index 379f2f24ef..25296b49c3 100644 --- a/Apps/W1/EDocument/app/src/Extensions/EDocPostedSalesInv.PageExt.al +++ b/Apps/W1/EDocument/app/src/Extensions/EDocPostedSalesInv.PageExt.al @@ -5,7 +5,6 @@ namespace Microsoft.Sales.History; using Microsoft.eServices.EDocument; - pageextension 6144 "E-Doc. Posted Sales Inv." extends "Posted Sales Invoice" { actions diff --git a/Apps/W1/EDocument/app/src/Extensions/EDocPurchPayablesSetup.PageExt.al b/Apps/W1/EDocument/app/src/Extensions/EDocPurchPayablesSetup.PageExt.al new file mode 100644 index 0000000000..c4b743dc29 --- /dev/null +++ b/Apps/W1/EDocument/app/src/Extensions/EDocPurchPayablesSetup.PageExt.al @@ -0,0 +1,21 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Purchases.Document; + +using Microsoft.Purchases.Setup; +pageextension 6162 "E-Doc. Purch. Payables Setup" extends "Purchases & Payables Setup" +{ + layout + { + addafter("Document Default Line Type") + { + field("E-Document Matching Difference"; Rec."E-Document Matching Difference") + { + ApplicationArea = All; + ToolTip = 'Specifies the maximum allowed percentage of cost differece when matching incoming E-Document line with Purchase Order line'; + } + } + } +} \ No newline at end of file diff --git a/Apps/W1/EDocument/app/src/Extensions/EDocPurchPayablesSetup.TableExt.al b/Apps/W1/EDocument/app/src/Extensions/EDocPurchPayablesSetup.TableExt.al new file mode 100644 index 0000000000..d8aa99300d --- /dev/null +++ b/Apps/W1/EDocument/app/src/Extensions/EDocPurchPayablesSetup.TableExt.al @@ -0,0 +1,12 @@ +tableextension 6162 "E-Doc. Purch. Payables Setup" extends "Purchases & Payables Setup" +{ + fields + { + field(6100; "E-Document Matching Difference"; Decimal) + { + Caption = 'E-Document Matching Difference %'; + InitValue = 0; + DecimalPlaces = 1; + } + } +} \ No newline at end of file diff --git a/Apps/W1/EDocument/app/src/Extensions/EDocPurchaseOrder.PageExt.al b/Apps/W1/EDocument/app/src/Extensions/EDocPurchaseOrder.PageExt.al index 51379c7967..9ed7f70af2 100644 --- a/Apps/W1/EDocument/app/src/Extensions/EDocPurchaseOrder.PageExt.al +++ b/Apps/W1/EDocument/app/src/Extensions/EDocPurchaseOrder.PageExt.al @@ -6,6 +6,7 @@ namespace Microsoft.Purchases.Document; using Microsoft.eServices.EDocument; using Microsoft.eServices.EDocument.OrderMatch; +using Microsoft.eServices.EDocument.OrderMatch.Copilot; pageextension 6132 "E-Doc. Purchase Order" extends "Purchase Order" { @@ -15,13 +16,30 @@ pageextension 6132 "E-Doc. Purchase Order" extends "Purchase Order" { group("E-Document") { + action(MatchToOrderCopilotEnabled) + { + Caption = 'Map E-Document Lines'; + ToolTip = 'Map received E-Document to the Purchase Order'; + ApplicationArea = All; + Image = SparkleFilled; + Visible = ShowMapToEDocument and CopilotEnabled; + + trigger OnAction() + var + EDocument: Record "E-Document"; + EDocOrderMatch: Codeunit "E-Doc. Line Matching"; + begin + EDocument.GetBySystemId(Rec."E-Document Link"); + EDocOrderMatch.RunMatching(EDocument); + end; + } action(MatchToOrder) { - Caption = 'Map E-Document'; + Caption = 'Map E-Document Lines'; ToolTip = 'Map received E-Document to the Purchase Order'; ApplicationArea = All; Image = Reconcile; - Visible = ShowMapToEDocument; + Visible = ShowMapToEDocument and (not CopilotEnabled); trigger OnAction() var @@ -51,6 +69,9 @@ pageextension 6132 "E-Doc. Purchase Order" extends "Purchase Order" } addlast(Category_Process) { + actionref(MapEDocumentCE_Promoted; MatchToOrderCopilotEnabled) + { + } actionref(MapEDocument_Promoted; MatchToOrder) { } @@ -59,11 +80,28 @@ pageextension 6132 "E-Doc. Purchase Order" extends "Purchase Order" var - ShowMapToEDocument: Boolean; + ShowMapToEDocument, CopilotEnabled : Boolean; + + + trigger OnOpenPage() + var + EDocPOMatching: Codeunit "E-Doc. PO Copilot Matching"; + begin + CopilotEnabled := EDocPOMatching.IsCopilotEnabled(); + end; trigger OnAfterGetCurrRecord() + var + EDocument: Record "E-Document"; + EDocumentServiceStatus: Record "E-Document Service Status"; begin - ShowMapToEDocument := not IsNullGuid(Rec."E-Document Link"); + ShowMapToEDocument := false; + if not IsNullGuid(Rec."E-Document Link") then begin + EDocument.GetBySystemId(Rec."E-Document Link"); + EDocumentServiceStatus.SetRange("E-Document Entry No", EDocument."Entry No"); + EDocumentServiceStatus.FindFirst(); + ShowMapToEDocument := EDocumentServiceStatus.Status = Enum::"E-Document Service Status"::"Order Linked"; + end; end; } diff --git a/Apps/W1/EDocument/app/src/Extensions/EDocPurchaseOrderList.PageExt.al b/Apps/W1/EDocument/app/src/Extensions/EDocPurchaseOrderList.PageExt.al index ea9ff95c72..faff63ea00 100644 --- a/Apps/W1/EDocument/app/src/Extensions/EDocPurchaseOrderList.PageExt.al +++ b/Apps/W1/EDocument/app/src/Extensions/EDocPurchaseOrderList.PageExt.al @@ -6,6 +6,7 @@ namespace Microsoft.Purchases.Document; using Microsoft.eServices.EDocument; using Microsoft.eServices.EDocument.OrderMatch; +using Microsoft.eServices.EDocument.OrderMatch.Copilot; pageextension 6137 "E-Doc. Purchase Order List" extends "Purchase Order List" { @@ -15,13 +16,30 @@ pageextension 6137 "E-Doc. Purchase Order List" extends "Purchase Order List" { group("E-Document") { + action(MatchToOrderCopilotEnabled) + { + Caption = 'Map E-Document Lines'; + ToolTip = 'Map received E-Document to the Purchase Order'; + ApplicationArea = All; + Image = SparkleFilled; + Visible = ShowMapToEDocument and CopilotEnabled; + + trigger OnAction() + var + EDocument: Record "E-Document"; + EDocOrderMatch: Codeunit "E-Doc. Line Matching"; + begin + EDocument.GetBySystemId(Rec."E-Document Link"); + EDocOrderMatch.RunMatching(EDocument); + end; + } action(MatchToOrder) { - Caption = 'Map E-Document'; + Caption = 'Map E-Document Lines'; ToolTip = 'Map received E-Document to the Purchase Order'; ApplicationArea = All; Image = Reconcile; - Visible = ShowMapToEDocument; + Visible = ShowMapToEDocument and (not CopilotEnabled); trigger OnAction() var @@ -51,6 +69,9 @@ pageextension 6137 "E-Doc. Purchase Order List" extends "Purchase Order List" } addlast(Category_Process) { + actionref(MapEDocumentCE_Promoted; MatchToOrderCopilotEnabled) + { + } actionref(MapEDocument_Promoted; MatchToOrder) { } @@ -60,11 +81,27 @@ pageextension 6137 "E-Doc. Purchase Order List" extends "Purchase Order List" var - ShowMapToEDocument: Boolean; + ShowMapToEDocument, CopilotEnabled : Boolean; + + trigger OnOpenPage() + var + EDocPOMatching: Codeunit "E-Doc. PO Copilot Matching"; + begin + CopilotEnabled := EDocPOMatching.IsCopilotEnabled(); + end; trigger OnAfterGetCurrRecord() + var + EDocument: Record "E-Document"; + EDocumentServiceStatus: Record "E-Document Service Status"; begin - ShowMapToEDocument := not IsNullGuid(Rec."E-Document Link"); + ShowMapToEDocument := false; + if not IsNullGuid(Rec."E-Document Link") then begin + EDocument.GetBySystemId(Rec."E-Document Link"); + EDocumentServiceStatus.SetRange("E-Document Entry No", EDocument."Entry No"); + EDocumentServiceStatus.FindFirst(); + ShowMapToEDocument := EDocumentServiceStatus.Status = Enum::"E-Document Service Status"::"Order Linked"; + end; end; } diff --git a/Apps/W1/EDocument/app/src/Extensions/EDocumentActivities.Page.al b/Apps/W1/EDocument/app/src/Extensions/EDocumentActivities.Page.al index f0fcf0d2af..b2f6235238 100644 --- a/Apps/W1/EDocument/app/src/Extensions/EDocumentActivities.Page.al +++ b/Apps/W1/EDocument/app/src/Extensions/EDocumentActivities.Page.al @@ -94,8 +94,8 @@ page 6127 "E-Document Activities" field(MatchedPurchaseOrderCount; MatchedPurchaseOrderCount) { ApplicationArea = Basic, Suite; - Caption = 'Matched Purchase Orders'; - ToolTip = 'Specifies the number of purchase orders that have matched to a received e-document.'; + Caption = 'Linked Purchase Orders'; + ToolTip = 'Specifies the number of e-documents that are linked to a purchase order and needs to be processed.'; trigger OnDrillDown() begin @@ -105,12 +105,12 @@ page 6127 "E-Document Activities" field(WaitingPurchaseOrderCount; WaitingPurchaseEDocCount) { ApplicationArea = Basic, Suite; - Caption = 'Waiting Purchase E-Documents'; + Caption = 'Waiting Purchase E-Invoices'; ToolTip = 'Specifies the number of received purchase e-documents that needs to be reviewed.'; trigger OnDrillDown() begin - EDocumentHelper.OpenMatchedPurchaseEDoc(); + EDocumentHelper.OpenWaitingPurchaseEDoc(); end; } } diff --git a/Apps/W1/EDocument/app/src/Format/EDocImportPEPPOLBIS30.Codeunit.al b/Apps/W1/EDocument/app/src/Format/EDocImportPEPPOLBIS30.Codeunit.al index 2416d71cde..0af4c0f60f 100644 --- a/Apps/W1/EDocument/app/src/Format/EDocImportPEPPOLBIS30.Codeunit.al +++ b/Apps/W1/EDocument/app/src/Format/EDocImportPEPPOLBIS30.Codeunit.al @@ -74,6 +74,8 @@ codeunit 6166 "EDoc Import PEPPOL BIS 3.0" Evaluate(EDocument."Amount Excl. VAT", GetNodeByPath(TempXMLBuffer, '/Invoice/cac:LegalMonetaryTotal/cbc:TaxExclusiveAmount'), 9); Evaluate(EDocument."Amount Incl. VAT", GetNodeByPath(TempXMLBuffer, '/Invoice/cac:LegalMonetaryTotal/cbc:PayableAmount'), 9); + EDocument."Order No." := CopyStr(GetNodeByPath(TempXMLBuffer, '/Invoice/cac:OrderReference/cbc:ID'), 1, MaxStrLen(EDocument."Order No.")); + Currency := CopyStr(GetNodeByPath(TempXMLBuffer, '/Invoice/cbc:DocumentCurrencyCode'), 1, MaxStrLen(EDocument."Currency Code")); if LCYCode <> Currency then EDocument."Currency Code" := Currency; @@ -141,6 +143,7 @@ codeunit 6166 "EDoc Import PEPPOL BIS 3.0" begin PurchaseHeader."Document Type" := PurchaseHeader."Document Type"::Invoice; PurchaseHeader."No." := CopyStr(GetNodeByPath(TempXMLBuffer, '/Invoice/cbc:ID'), 1, MaxStrLen(PurchaseHeader."No.")); + PurchaseHeader."Vendor Order No." := CopyStr(GetNodeByPath(TempXMLBuffer, '/Invoice/cac:OrderReference/cbc:ID'), 1, MaxStrLen(PurchaseHeader."Vendor Order No.")); // Currency PurchaseHeader.Insert(); diff --git a/Apps/W1/EDocument/app/src/Helpers/EDocumentErrorHelper.Codeunit.al b/Apps/W1/EDocument/app/src/Helpers/EDocumentErrorHelper.Codeunit.al index 4a651fb436..3e888dfd80 100644 --- a/Apps/W1/EDocument/app/src/Helpers/EDocumentErrorHelper.Codeunit.al +++ b/Apps/W1/EDocument/app/src/Helpers/EDocumentErrorHelper.Codeunit.al @@ -22,6 +22,19 @@ codeunit 6115 "E-Document Error Helper" exit(ErrorMessage.ErrorMessageCount(ErrorMessage."Message Type"::Error)); end; + /// + /// Use it to get the number of warnings for E-Document. + /// + /// The E-Document record. + /// Count of the warnings in an an E-Document. + procedure WarningMessageCount(var EDocument: Record "E-Document"): Integer + var + ErrorMessage: Record "Error Message"; + begin + ErrorMessage.SetContext(EDocument); + exit(ErrorMessage.ErrorMessageCount(ErrorMessage."Message Type"::"Warning")); + end; + /// /// Use it to check if there are errors for E-Document. /// diff --git a/Apps/W1/EDocument/app/src/Helpers/EDocumentImportHelper.Codeunit.al b/Apps/W1/EDocument/app/src/Helpers/EDocumentImportHelper.Codeunit.al index 6de6fcfca6..26ab2ede5f 100644 --- a/Apps/W1/EDocument/app/src/Helpers/EDocumentImportHelper.Codeunit.al +++ b/Apps/W1/EDocument/app/src/Helpers/EDocumentImportHelper.Codeunit.al @@ -570,6 +570,26 @@ codeunit 6109 "E-Document Import Helper" EDocErrorHelper.LogSimpleErrorMessage(EDocument, StrSubstNo(VendorNotFoundErr, EDocument."Bill-to/Pay-to Name")); end; + /// + /// Use it to process imported E-Document + /// + /// The E-Document record. + /// If processing should create journal line + procedure ProcessDocument(var EDocument: Record "E-Document"; CreateJnlLine: Boolean) + var + begin + EDocumentImport.ProcessDocument(EDocument, CreateJnlLine); + end; + + /// + /// Use it to set hide dialogs when importing E-Document. + /// + /// Hide or show the dialog. + procedure SetHideDialogs(Hide: Boolean) + begin + EDocumentImport.SetHideDialogs(Hide); + end; + local procedure TryFindLeastBlockedVendorNoByVendorBankAcc(var VendorBankAccount: record "Vendor Bank Account"): Code[20] var Vendor: Record Vendor; @@ -853,6 +873,7 @@ codeunit 6109 "E-Document Import Helper" var EDocErrorHelper: Codeunit "E-Document Error Helper"; + EDocumentImport: Codeunit "E-Doc. Import"; UOMNotFoundErr: Label 'Cannot find unit of measure %1. Make sure that the unit of measure exists.', Comment = '%1 International Standard Code or Code or Description for Unit of Measure'; UOMConflictWithItemRefErr: Label 'Unit of measure %1 on electronic document line %2 does not match unit of measure %3 in the item reference. Make sure that a card for the item with the specified unit of measure exists with the corresponding item reference.', Comment = '%1 imported unit code, %2 document line number (e.g. 2), %3 Item Reference unit code'; UOMConflictItemRefWithItemErr: Label 'Unit of measure %1 in the item reference is not in the list of units of measure for the corresponding item. Make sure that a unit of measure of item reference is in the list of units of measure for the corresponding item.', Comment = '%1 item reference unit code'; diff --git a/Apps/W1/EDocument/app/src/Processing/EDocImport.Codeunit.al b/Apps/W1/EDocument/app/src/Processing/EDocImport.Codeunit.al index 78fdc0410d..dc33b71fbc 100644 --- a/Apps/W1/EDocument/app/src/Processing/EDocImport.Codeunit.al +++ b/Apps/W1/EDocument/app/src/Processing/EDocImport.Codeunit.al @@ -7,13 +7,14 @@ namespace Microsoft.eServices.EDocument; using Microsoft.Finance.GeneralLedger.Journal; using Microsoft.Purchases.Vendor; using Microsoft.Purchases.Document; -using System.Utilities; using Microsoft.eServices.EDocument.OrderMatch; +using System.Utilities; codeunit 6140 "E-Doc. Import" { Permissions = - tabledata "E-Document" = im; + tabledata "E-Document" = im, + tabledata "E-Doc. Imported Line" = imd; internal procedure UploadDocument(var EDocument: Record "E-Document") var @@ -30,6 +31,7 @@ codeunit 6140 "E-Doc. Import" if CopyStream(OutStr, InStr) then begin EDocument.Direction := EDocument.Direction::Incoming; EDocument.Status := EDocument.Status::"In Progress"; + EDocument."Document Type" := Enum::"E-Document Type"::None; if EDocument."Entry No" = 0 then EDocument.Insert(true) else @@ -46,7 +48,6 @@ codeunit 6140 "E-Doc. Import" TempBlob: Codeunit "Temp Blob"; begin EDocErrorHelper.ClearErrorMessages(EDocument); - EDocService := EDocumentLog.GetLastServiceFromLog(EDocument); EDocumentLog.GetDocumentBlobFromLog(EDocument, EDocService, TempBlob, Enum::"E-Document Service Status"::Imported); @@ -58,15 +59,13 @@ codeunit 6140 "E-Doc. Import" EDocService: Record "E-Document Service"; TempBlob: Codeunit "Temp Blob"; begin + if EDocument.Status = EDocument.Status::Processed then + exit; EDocErrorHelper.ClearErrorMessages(EDocument); - EDocService := EDocumentLog.GetLastServiceFromLog(EDocument); EDocumentLog.GetDocumentBlobFromLog(EDocument, EDocService, TempBlob, Enum::"E-Document Service Status"::Imported); ProcessImportedDocument(EDocument, EDocService, TempBlob, CreateJnlLine); - - if GuiAllowed and EDocErrorHelper.HasErrors(EDocument) then - Message(DocNotCreatedMsg); end; local procedure GetDocumentBasicInfo(var EDocument: Record "E-Document"; EDocService: Record "E-Document Service"; var TempBlob: Codeunit "Temp Blob") @@ -143,7 +142,6 @@ codeunit 6140 "E-Doc. Import" OnAfterInsertImportedEdocument(EDocument, EDocService, TempBlob, EDocCount, HttpRequest, HttpResponse); end; - if not IsProcessed then ProcessImportedDocument(EDocument, EDocService, TempBlob, EDocService."Create Journal Lines"); @@ -153,28 +151,47 @@ codeunit 6140 "E-Doc. Import" end; end; - if HasErrors and GuiAllowed then - if Confirm(DocNotCreatedQst) then + if HasErrors and GuiAllowed() then + if Confirm(DocNotCreatedQst, true, EDocument2."Document Type") then Page.Run(Page::"E-Document", EDocument2); end; - local procedure ProcessExistingOrder(var EDocument: Record "E-Document"; EDocService: Record "E-Document Service"; var SourceDocumentLine: RecordRef; DocumentHeader: RecordRef; var EDocServiceStatus: Enum "E-Document Service Status") + internal procedure UpdatePurchaseOrderLink(var EDocument: Record "E-Document") + var + Vendor: Record Vendor; + PurchaseHeader: Record "Purchase Header"; + DocumentHeader: RecordRef; + NullGuid: Guid; + begin + if EDocument.Status = Enum::"E-Document Status"::Processed then + exit; + + // Release purchase header if it is pointing to this document + + if PurchaseHeader.Get(EDocument."Document Record ID") then + if PurchaseHeader."E-Document Link" = EDocument.SystemId then begin + PurchaseHeader."E-Document Link" := NullGuid; + PurchaseHeader.Modify(); + end; + + EDocument."Order No." := ''; + EDocument."Document Type" := EDocument."Document Type"::None; + Vendor.Get(EDocument."Bill-to/Pay-to No."); + if SelectPurchaseOrderFromList(EDocument, Vendor, DocumentHeader) then + ProcessDocument(EDocument, false); + end; + + local procedure ProcessExistingOrder(var EDocument: Record "E-Document"; EDocService: Record "E-Document Service"; var SourceDocumentLine: RecordRef; var DocumentHeader: RecordRef; var EDocServiceStatus: Enum "E-Document Service Status") var PurchaseOrderHeader: Record "Purchase Header"; TempEDocImportedLine: Record "E-Doc. Imported Line" temporary; EDocument2: Record "E-Document"; ErrorMessage: Record "Error Message"; TempExistingErrorMessage: Record "Error Message" temporary; - IsAnEDocAlreadyLinkedToPO: Boolean; ItemFound, UOMResolved : Boolean; begin DocumentHeader.SetTable(PurchaseOrderHeader); - // We should mark Edoc pending if existing edoc is already linked - EDocument2.SetRange("Document Record ID", PurchaseOrderHeader.RecordId()); - EDocument2.SetFilter(Status, '<>%1', Enum::"E-Document Status"::Processed); - IsAnEDocAlreadyLinkedToPO := not EDocument2.IsEmpty(); - // Collect any error message ErrorMessage.SetContext(EDocument.RecordId()); ErrorMessage.SetRange("Context Record ID", EDocument.RecordId()); @@ -183,10 +200,8 @@ codeunit 6140 "E-Doc. Import" // Get lines if SourceDocumentLine.FindSet() then repeat - if EDocService."Resolve Unit Of Measure" or EDocService."Lookup Item Reference" or - EDocService."Lookup Item GTIN" or EDocService."Lookup Account Mapping" or - EDocService."Validate Line Discount" then begin + EDocService."Lookup Item GTIN" or EDocService."Lookup Account Mapping" then begin ItemFound := false; UOMResolved := false; if EDocService."Resolve Unit Of Measure" then @@ -205,6 +220,9 @@ codeunit 6140 "E-Doc. Import" if (not ItemFound) and EDocService."Lookup Account Mapping" then ItemFound := EDocImportHelper.FindGLAccountForLine(EDocument, SourceDocumentLine); end; + + if EDocService."Validate Line Discount" then + EDocImportHelper.ValidateLineDiscount(EDocument, SourceDocumentLine); end; // Save Temp EDocument Import Line for matching to purchase order @@ -218,11 +236,17 @@ codeunit 6140 "E-Doc. Import" // Load into imported lines and update edoc state PersistImportedLines(EDocument, TempEDocImportedLine); UpdateEDocumentRecordId(EDocument, DocumentHeader.Field(PurchaseOrderHeader.FieldNo("No.")).Value(), DocumentHeader.RecordId); - if IsAnEDocAlreadyLinkedToPO then begin + + // We should mark Edoc pending if existing edoc is already linked + if (not IsNullGuid(PurchaseOrderHeader."E-Document Link")) and (PurchaseOrderHeader."E-Document Link" <> EDocument.SystemId) then begin EDocServiceStatus := EDocServiceStatus::Pending; + EDocument2.GetBySystemId(PurchaseOrderHeader."E-Document Link"); EDocErrorHelper.LogWarningMessage(EDocument, EDocument2, EDocument2.FieldNo("Entry No"), StrSubstNo(CannotProcessEDocumentMsg, EDocument."Entry No", PurchaseOrderHeader."No.", EDocument2."Entry No")); - end else + end else begin + PurchaseOrderHeader.Validate("E-Document Link", EDocument.SystemId); + PurchaseOrderHeader.Modify(); EDocServiceStatus := EDocServiceStatus::"Order Linked"; + end; EDocument.Status := Enum::"E-Document Status"::"In Progress"; end; @@ -314,7 +338,8 @@ codeunit 6140 "E-Doc. Import" UpdateEDocumentRecordId(EDocument, EDocument."Document Type", DocNo, RecordId); end; - local procedure UpdateEDocumentRecordId(var EDocument: Record "E-Document"; EDocType: enum "E-Document Type"; DocNo: Code[20]; RecordId: RecordId) + local procedure UpdateEDocumentRecordId(var EDocument: Record "E-Document"; EDocType: enum "E-Document Type"; DocNo: Code[20]; + RecordId: RecordId) begin EDocument."Document Type" := EDocType; EDocument."Document No." := DocNo; @@ -329,86 +354,129 @@ codeunit 6140 "E-Doc. Import" DocumentHeader, SourceDocumentHeader, SourceDocumentLine : RecordRef; EDocumentLogEntryNo: Integer; EDocServiceStatus: Enum "E-Document Service Status"; + ExistingOrderNo: Code[20]; + Window: Dialog; begin - if EDocument."Document No." <> '' then - if GuiAllowed then - if not Confirm(StrSubstNo(DocAlreadyCreatedQst, EDocument."Document Type", EDocument."Document No.", EDocument."Incoming E-Document No.")) then - exit; + if GuiAllowed() then + Window.Open('Processing E-Document: \ #1'); + // Pending documents that are processed can already be linked to order. In these cases we save order no and reinsert after parsing xml. + ExistingOrderNo := EDocument."Order No."; EDocErrorHelper.ClearErrorMessages(EDocument); GetDocumentBasicInfo(EDocument, EDocService, TempBlob); if EDocErrorHelper.HasErrors(EDocument) then begin - EDocumentLog.InsertLog(EDocument, EDocService, TempBlob, Enum::"E-Document Service Status"::"Imported document processing error"); + EDocumentLog.InsertLog(EDocument, EDocService, Enum::"E-Document Service Status"::"Imported document processing error"); exit; end; ParseDocumentLines(EDocument, EDocService, TempBlob, SourceDocumentHeader, SourceDocumentLine, TempEDocMapping); if EDocErrorHelper.HasErrors(EDocument) then begin - EDocumentLog.InsertLog(EDocument, EDocService, TempBlob, Enum::"E-Document Service Status"::"Imported document processing error"); + EDocumentLog.InsertLog(EDocument, EDocService, Enum::"E-Document Service Status"::"Imported document processing error"); exit; end; - // Always handle corrective document, or handle based on vendor setting + if ExistingOrderNo <> '' then + EDocument."Order No." := ExistingOrderNo; + if Vendor.Get(EDocument."Bill-to/Pay-to No.") then - case EDocument."Document Type" of - "E-Document Type"::"Purchase Credit Memo": - ReceiveEDocumentToPurchaseDoc(EDocument, EDocService, SourceDocumentHeader, SourceDocumentLine, EDocServiceStatus, CreateJnlLine); - else - case Vendor."Receive E-Document To" of - Enum::"E-Document Type"::"Purchase Invoice": - ReceiveEDocumentToPurchaseDoc(EDocument, EDocService, SourceDocumentHeader, SourceDocumentLine, EDocServiceStatus, CreateJnlLine); - Enum::"E-Document Type"::"Purchase Order": - ReceiveEDocumentToPurchaseOrder(EDocument, EDocService, SourceDocumentHeader, SourceDocumentLine, EDocServiceStatus, Vendor); - else begin - ReceiveEDocumentToPurchaseDoc(EDocument, EDocService, SourceDocumentHeader, SourceDocumentLine, EDocServiceStatus, CreateJnlLine); - Vendor."Receive E-Document To" := Vendor."Receive E-Document To"::"Purchase Invoice"; - Vendor.Modify(); - end; - end - end + if ValidateEDocumentIsForPurchaseOrder(EDocument, Vendor) then + ReceiveEDocumentToPurchaseOrder(EDocument, EDocService, SourceDocumentHeader, SourceDocumentLine, EDocServiceStatus, Vendor, Window) + else + ReceiveEDocumentToPurchaseDoc(EDocument, EDocService, SourceDocumentHeader, SourceDocumentLine, EDocServiceStatus, CreateJnlLine, Window) else EDocErrorHelper.LogErrorMessage(EDocument, Vendor, Vendor.FieldNo("No."), FailedToFindVendorErr); if EDocErrorHelper.HasErrors(EDocument) then - EDocumentLog.InsertLog(EDocument, EDocService, TempBlob, Enum::"E-Document Service Status"::"Imported document processing error") + EDocumentLog.InsertLog(EDocument, EDocService, Enum::"E-Document Service Status"::"Imported document processing error") else begin EDocumentLogEntryNo := EDocumentLog.InsertLog(EDocument, EDocService, EDocServiceStatus); EDocumentLog.InsertMappingLog(EDocumentLogEntryNo, TempEDocMapping); end; + OnAfterProcessImportedDocument(EDocument, DocumentHeader); end; - procedure ReceiveEDocumentToPurchaseOrder(var EDocument: Record "E-Document"; var EDocService: Record "E-Document Service"; var SourceDocumentHeader: RecordRef; var SourceDocumentLine: RecordRef; var EDocServiceStatus: Enum "E-Document Service Status"; Vendor: Record Vendor) + local procedure ValidateEDocumentIsForPurchaseOrder(var EDocument: Record "E-Document"; Vendor: Record Vendor): Boolean + begin + if EDocument."Document Type" = EDocument."Document Type"::"Purchase Credit Memo" then + exit(false); + exit(Vendor."Receive E-Document To" = Enum::"E-Document Type"::"Purchase Order"); + end; + +#pragma warning disable AS0022 + local procedure ReceiveEDocumentToPurchaseOrder(var EDocument: Record "E-Document"; var EDocService: Record "E-Document Service"; var SourceDocumentHeader: RecordRef; var SourceDocumentLine: RecordRef; var EDocServiceStatus: Enum "E-Document Service Status"; Vendor: Record Vendor; var WindowInstance: Dialog) var DocumentHeader: RecordRef; begin EDocument."Document Type" := "E-Document Type"::"Purchase Order"; EDocument.Modify(); - if (EDocument."Order No." = '') and not GuiAllowed() then begin - EDocServiceStatus := Enum::"E-Document Service Status"::Pending; + // Check if document points to existing order + if OrderExists(EDocument, Vendor, DocumentHeader) then begin + ProcessExistingOrder(EDocument, EDocService, SourceDocumentLine, DocumentHeader, EDocServiceStatus); exit; end; - if (EDocument."Order No." = '') and GuiAllowed() then - FindPurchaseOrder(EDocument, Vendor); + // Case where we do not find/have order + if GuiAllowed() and (not HideDialogs) then begin + if SelectPurchaseOrderFromList(EDocument, Vendor, DocumentHeader) then begin + WindowInstance.Update(1, DocLinkMsg); + ProcessExistingOrder(EDocument, EDocService, SourceDocumentLine, DocumentHeader, EDocServiceStatus); + end else begin + WindowInstance.Update(1, DocCreatePOMsg); + CreatePurchaseDocumentFromImportedDocument(EDocument, EDocService, SourceDocumentHeader, SourceDocumentLine, EDocServiceStatus, Enum::"Purchase Document Type"::Order); + end; + end else + EDocServiceStatus := Enum::"E-Document Service Status"::Pending; + end; +#pragma warning restore AS0022 - if OrderExists(EDocument, Vendor, DocumentHeader) then - ProcessExistingOrder(EDocument, EDocService, SourceDocumentLine, DocumentHeader, EDocServiceStatus) - else - CreatePurchaseDocumentFromImportedDocument(EDocument, EDocService, SourceDocumentHeader, SourceDocumentLine, EDocServiceStatus, Enum::"Purchase Document Type"::Order); + internal procedure ProcessEDocPendingOrderMatch(var EDocument: Record "E-Document") + var + EDocService: Record "E-Document Service"; + EDocServiceStatus: Record "E-Document Service Status"; + EDocLog: Codeunit "E-Document Log"; + begin + if (EDocument."Document Type" <> Enum::"E-Document Type"::"Purchase Order") or + (EDocument.Status = Enum::"E-Document Status"::Processed) then + exit; + + EDocService := EDocLog.GetLastServiceFromLog(EDocument); + EDocServiceStatus.Get(EDocument."Entry No", EDocService.Code); + if EDocServiceStatus.Status <> EDocServiceStatus.Status::Pending then + exit; + + if not IsPendingEDocReadyToProcess(EDocument) then + exit; + + ProcessDocument(EDocument, EDocService."Create Journal Lines"); + end; + + local procedure IsPendingEDocReadyToProcess(EDocument: Record "E-Document"): Boolean + var + PurchaseHeader: Record "Purchase Header"; + begin + // If no order number is set we need to process document + if EDocument."Order No." = '' then + exit(true); + PurchaseHeader.SetRange("No.", EDocument."Order No."); + PurchaseHeader.SetRange("Document Type", Enum::"Purchase Document Type"::Order); + if PurchaseHeader.FindFirst() then + exit(IsNullGuid(PurchaseHeader."E-Document Link")) + else + exit(true); end; - local procedure FindPurchaseOrder(var EDocument: Record "E-Document"; Vendor: Record Vendor) + local procedure SelectPurchaseOrderFromList(var EDocument: Record "E-Document"; Vendor: Record Vendor; var DocumentHeader: RecordRef) Found: Boolean var PurchaseHeader: Record "Purchase Header"; - ConfirmManagement: Codeunit "Confirm Management"; PurchaseOrderList: Page "Purchase Order List"; begin + Found := false; if not GuiAllowed() then - exit; + exit(false); PurchaseHeader.SetRange("Buy-from Vendor No.", Vendor."No."); PurchaseOrderList.SetTableView(PurchaseHeader); @@ -416,23 +484,28 @@ codeunit 6140 "E-Doc. Import" Commit(); if PurchaseOrderList.RunModal() = Action::LookupOK then begin PurchaseOrderList.GetRecord(PurchaseHeader); - if ConfirmManagement.GetResponseOrDefault(StrSubstNo(FindPurchaseOrderConfrimQst, PurchaseHeader."No.", EDocument."Entry No"), true) then begin - EDocument."Order No." := PurchaseHeader."No."; - EDocument.Modify(); - end; + DocumentHeader.GetTable(PurchaseHeader); + EDocument."Order No." := PurchaseHeader."No."; + EDocument.Modify(); + Found := true; end; end; - local procedure ReceiveEDocumentToPurchaseDoc(var EDocument: Record "E-Document"; var EDocService: Record "E-Document Service"; var SourceDocumentHeader: RecordRef; var SourceDocumentLine: RecordRef; var EDocServiceStatus: Enum "E-Document Service Status"; CreateJnlLine: Boolean) + local procedure ReceiveEDocumentToPurchaseDoc(var EDocument: Record "E-Document"; var EDocService: Record "E-Document Service"; var SourceDocumentHeader: RecordRef; var SourceDocumentLine: RecordRef; var EDocServiceStatus: Enum "E-Document Service Status"; CreateJnlLine: Boolean; var WindowInstance: Dialog) var PurchaseHeader: Record "Purchase Header"; PurchaseDocumentType: Enum "Purchase Document Type"; begin PurchaseDocumentType := SourceDocumentHeader.Field(PurchaseHeader.FieldNo("Document Type")).Value(); - if CreateJnlLine then - CreateJournalLineFromImportedDocument(EDocument, EDocService, EDocServiceStatus) - else + if CreateJnlLine then begin + if GuiAllowed() then + WindowInstance.Update(1, JnlLineCreateMsg); + CreateJournalLineFromImportedDocument(EDocument, EDocService, EDocServiceStatus); + end else begin + if GuiAllowed() then + WindowInstance.Update(1, StrSubstNo(DocCreateMsg, Format(PurchaseDocumentType))); CreatePurchaseDocumentFromImportedDocument(EDocument, EDocService, SourceDocumentHeader, SourceDocumentLine, EDocServiceStatus, PurchaseDocumentType); + end; end; local procedure ParseDocumentLines(var EDocument: Record "E-Document"; EDocumentService: Record "E-Document Service"; var TempBlob: Codeunit "Temp Blob"; var SourceDocumentHeader: RecordRef; var SourceDocumentLine: RecordRef; var TempEDocMapping: Record "E-Doc. Mapping" temporary) @@ -528,10 +601,12 @@ codeunit 6140 "E-Doc. Import" var PurchaseHeader: Record "Purchase Header"; begin + if EDocument."Order No." = '' then + exit(false); + PurchaseHeader.SetRange("Document Type", PurchaseHeader."Document Type"::Order); PurchaseHeader.SetRange("No.", EDocument."Order No."); - PurchaseHeader.SetRange("Pay-to Vendor No.", Vendor."No."); - + PurchaseHeader.SetRange("Buy-from Vendor No.", Vendor."No."); if PurchaseHeader.FindFirst() then begin DocumentHeader.GetTable(PurchaseHeader); exit(true); @@ -553,16 +628,23 @@ codeunit 6140 "E-Doc. Import" until TempEDocImportedLine.Next() = 0; end; + internal procedure SetHideDialogs(Hide: Boolean) + begin + HideDialogs := Hide; + end; + var EDocumentLog: Codeunit "E-Document Log"; EDocImportHelper: Codeunit "E-Document Import Helper"; EDocErrorHelper: Codeunit "E-Document Error Helper"; - DocNotCreatedQst: Label 'The document was not created due to errors in the conversion process. Do you want to open the document?'; - DocNotCreatedMsg: Label 'The document was not created due to errors in the conversion process.'; + HideDialogs: Boolean; + JnlLineCreateMsg: Label 'Creating Journal Line'; + DocCreateMsg: Label 'Creating Purchase %1', Comment = '%1 - Document type'; + DocLinkMsg: Label 'Linking to existing order'; + DocCreatePOMsg: Label 'Creating Purchase Order'; + DocNotCreatedQst: Label 'Failed to create new Purchase %1 from E-Document. Do you want to open E-Document to see reported errors?', Comment = '%1 - Purchase Document Type'; DocAlreadyExistsMsg: Label 'The document already exists.'; - DocAlreadyCreatedQst: Label 'The %1 %2 was already created for the electronic document %3. Do you want to create new document?', Comment = '%1 - Document Type, %2 - Document No., %3 - E-Document ID'; DocTypeIsNotSupportedErr: Label 'Document type %1 is not supported.', Comment = '%1 - Document Type'; - FindPurchaseOrderConfrimQst: Label 'Are you sure you want to link Purchase Order %1 to E-Document %2?', Comment = '%1 - Purchase Order number, %2 - E-Document entry number'; FailedToFindVendorErr: Label 'No vendor is set for Edocument'; CannotProcessEDocumentMsg: Label 'Cannot process E-Document %1 with Purchase Order %2 before Purchase Order has been matched and posted for E-Document %3.', Comment = '%1 - E-Document entry no, %2 - Purchase Order number, %3 - EDocument entry no.'; diff --git a/Apps/W1/EDocument/app/src/Processing/EDocumentCopilotCapability.EnumExt.al b/Apps/W1/EDocument/app/src/Processing/EDocumentCopilotCapability.EnumExt.al new file mode 100644 index 0000000000..10f075e453 --- /dev/null +++ b/Apps/W1/EDocument/app/src/Processing/EDocumentCopilotCapability.EnumExt.al @@ -0,0 +1,11 @@ +namespace Microsoft.Bank.Reconciliation; + +using System.AI; + +enumextension 6164 "E-Document Copilot Capability" extends "Copilot Capability" +{ + value(6164; "E-Document Matching Assistance") + { + Caption = 'E-Document Matching Assistance'; + } +} \ No newline at end of file diff --git a/Apps/W1/EDocument/app/src/Processing/EDocumentCreateJnlLine.Codeunit.al b/Apps/W1/EDocument/app/src/Processing/EDocumentCreateJnlLine.Codeunit.al index e332c54ff0..31a367a858 100644 --- a/Apps/W1/EDocument/app/src/Processing/EDocumentCreateJnlLine.Codeunit.al +++ b/Apps/W1/EDocument/app/src/Processing/EDocumentCreateJnlLine.Codeunit.al @@ -58,7 +58,7 @@ codeunit 6137 "E-Document Create Jnl. Line" LastGenJournalLine.Validate("Journal Template Name", EDocService."General Journal Template Name"); LastGenJournalLine.Validate("Journal Batch Name", EDocService."General Journal Batch Name"); LastGenJournalLine."Line No." += 10000; - LastGenJournalLine.Validate("Document No.", NoSeriesMgt.GetNextNo(GenJournalBatch."No. Series", EDocument."Document Date", false)); + LastGenJournalLine.Validate("Document No.", NoSeriesBatch.GetNextNo(GenJournalBatch."No. Series", EDocument."Document Date")); TempGenJournalLineInserted := LastGenJournalLine.Insert(); end; @@ -197,7 +197,7 @@ codeunit 6137 "E-Document Create Jnl. Line" var SourceEDocument: Record "E-Document"; SourceEDocumentService: Record "E-Document Service"; - NoSeriesMgt: Codeunit NoSeriesManagement; + NoSeriesBatch: Codeunit "No. Series - Batch"; EDocumentErrorHelper: Codeunit "E-Document Error Helper"; SourceDocumentHeader, CreatedJnlLine : RecordRef; NoBalanceAccountMappingErr: Label 'Could not fill the Bal. Account No. field for vendor ''''%1''''. Choose the Map Text to Account button to map ''''%1'''' to the relevant G/L account.', Comment = '%1 - vendor name'; diff --git a/Apps/W1/EDocument/app/src/Processing/EDocumentProcessing.Codeunit.al b/Apps/W1/EDocument/app/src/Processing/EDocumentProcessing.Codeunit.al index 8303f00186..066dbb1b85 100644 --- a/Apps/W1/EDocument/app/src/Processing/EDocumentProcessing.Codeunit.al +++ b/Apps/W1/EDocument/app/src/Processing/EDocumentProcessing.Codeunit.al @@ -110,20 +110,38 @@ codeunit 6108 "E-Document Processing" procedure MatchedPurchaseEDocumentsCount(): Integer var EDocument: Record "E-Document"; + EDocumentServiceStatus: Record "E-Document Service Status"; begin EDocument.SetRange("Document Type", Enum::"E-Document Type"::"Purchase Order"); EDocument.SetRange(Status, Enum::"E-Document Status"::"In Progress"); - EDocument.SetRange("Order No.", ''); + if EDocument.FindSet() then + repeat + EDocumentServiceStatus.SetRange("E-Document Entry No", EDocument."Entry No"); + EDocumentServiceStatus.SetRange(Status, Enum::"E-Document Service Status"::Pending); + if not EDocumentServiceStatus.IsEmpty() then + EDocument.Mark(true); + until EDocument.Next() = 0; + + EDocument.MarkedOnly(true); exit(EDocument.Count()); end; - procedure OpenMatchedPurchaseEDoc() + procedure OpenWaitingPurchaseEDoc() var EDocument: Record "E-Document"; + EDocumentServiceStatus: Record "E-Document Service Status"; begin EDocument.SetRange("Document Type", Enum::"E-Document Type"::"Purchase Order"); EDocument.SetRange(Status, Enum::"E-Document Status"::"In Progress"); - EDocument.SetRange("Order No.", ''); + if EDocument.FindSet() then + repeat + EDocumentServiceStatus.SetRange("E-Document Entry No", EDocument."Entry No"); + EDocumentServiceStatus.SetRange(Status, Enum::"E-Document Service Status"::Pending); + if not EDocumentServiceStatus.IsEmpty() then + EDocument.Mark(true); + until EDocument.Next() = 0; + + EDocument.MarkedOnly(true); Page.Run(Page::"E-Documents", EDocument); end; diff --git a/Apps/W1/EDocument/app/src/Processing/EDocumentSubscription.Codeunit.al b/Apps/W1/EDocument/app/src/Processing/EDocumentSubscription.Codeunit.al index 1c2a60129f..ae20f01c1c 100644 --- a/Apps/W1/EDocument/app/src/Processing/EDocumentSubscription.Codeunit.al +++ b/Apps/W1/EDocument/app/src/Processing/EDocumentSubscription.Codeunit.al @@ -113,6 +113,16 @@ codeunit 6103 "E-Document Subscription" CreateOrUpdateEDocument(PurchaseHeader, PurchCrMemoHdr, PurchCrMemoHdrNo, Enum::"E-Document Type"::"Purchase Credit Memo"); end; + [EventSubscriber(ObjectType::Codeunit, Codeunit::"Purch.-Post", 'OnRunOnAfterPostInvoice', '', false, false)] + local procedure OnRunOnAfterPostInvoice(var PurchaseHeader: Record "Purchase Header"; var PurchRcptHeader: Record "Purch. Rcpt. Header"; var ReturnShipmentHeader: Record "Return Shipment Header"; var PurchInvHeader: Record "Purch. Inv. Header"; var PurchCrMemoHdr: Record "Purch. Cr. Memo Hdr."; var PreviewMode: Boolean; var Window: Dialog; SrcCode: Code[10]; GenJnlLineDocType: Enum "Gen. Journal Document Type"; GenJnlLineDocNo: Code[20]; var GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line") + var + EDocument: Record "E-Document"; + begin + if PurchInvHeader."No." <> '' then + if IsEDocumentLinkedToPurchaseDocument(EDocument, PurchaseHeader) then + ValidateDocumentTotalAgainstEDocument(EDocument, PurchInvHeader); + end; + [EventSubscriber(ObjectType::Codeunit, Codeunit::"Service-Post", 'OnAfterPostServiceDoc', '', false, false)] local procedure OnAfterPostServiceDoc(var ServiceHeader: Record "Service Header"; ServShipmentNo: Code[20]; ServInvoiceNo: Code[20]; ServCrMemoNo: Code[20]; var ServDocumentsMgt: Codeunit "Serv-Documents Mgt."; CommitIsSuppressed: Boolean; PassedShip: Boolean; PassedConsume: Boolean; PassedInvoice: Boolean; WhseShip: Boolean) var @@ -184,13 +194,11 @@ codeunit 6103 "E-Document Subscription" end; end; - [EventSubscriber(ObjectType::Codeunit, Codeunit::"Release Purchase Document", 'OnAfterReleasePurchaseDoc', '', false, false)] - local procedure OnAfterReleasePurchaseDoc(var PurchaseHeader: Record "Purchase Header"; PreviewMode: Boolean; var LinesWereModified: Boolean; SkipWhseRequestOperations: Boolean) - var - EDocument: Record "E-Document"; + [EventSubscriber(ObjectType::Table, Database::"Purchase Header", 'OnBeforeOnDelete', '', false, false)] + local procedure OnBeforeOnDeletePurchaseHeader(var PurchaseHeader: Record "Purchase Header"; var IsHandled: Boolean) begin - if IsEDocumentLinkedToPurchaseDocument(EDocument, PurchaseHeader) then - ValidateDocumentTotalAgainstEDocument(EDocument, PurchaseHeader); + if not IsNullGuid(PurchaseHeader."E-Document Link") then + Error(DeleteNotAllowedErr); end; local procedure RunEDocumentCheck(Record: Variant; EDocumentProcPhase: Enum "E-Document Processing Phase") @@ -226,8 +234,9 @@ codeunit 6103 "E-Document Subscription" EDocService: Record "E-Document Service"; EDocServiceStatus: Record "E-Document Service Status"; EDocumentLog: Codeunit "E-Document Log"; + EDocErrorHelper: Codeunit "E-Document Error Helper"; OpenSourceDocumentHeader: RecordRef; - Guid: Guid; + NullGuid: Guid; begin OpenSourceDocumentHeader.GetTable(OpenRecord); if OpenSourceDocumentHeader.Number() <> Database::"Purchase Header" then @@ -235,11 +244,9 @@ codeunit 6103 "E-Document Subscription" OpenSourceDocumentHeader.SetTable(PurchaseHeader); PurchaseHeader.SetRecFilter(); - PurchaseHeader."E-Document Link" := Guid; + PurchaseHeader."E-Document Link" := NullGuid; // For invoices and fully invoiced orders, the open document is no valid if not PurchaseHeader.IsEmpty() then begin - PurchaseHeader.Modify(); - // Dequeue edoc list of pending edocuments and set "Order linked" EDocument.SetRange("Document Record ID", PurchaseHeader.RecordId()); EDocument.SetFilter(Status, '<>%1', Enum::"E-Document Status"::Processed); @@ -249,14 +256,17 @@ codeunit 6103 "E-Document Subscription" if EDocServiceStatus.Status = EDocServiceStatus.Status::Pending then begin EDocServiceStatus.Status := EDocServiceStatus.Status::"Order Linked"; EDocServiceStatus.Modify(); + EDocErrorHelper.ClearErrorMessages(EDocument); + PurchaseHeader."E-Document Link" := EDocument.SystemId; end; end; + PurchaseHeader.Modify(); end; end; local procedure ValidateDocumentTotalAgainstEDocument(var EDocument: Record "E-Document"; PostedRecord: Variant) var - PurchaseHeader: Record "Purchase Header"; + PurchInvHeader: Record "Purch. Inv. Header"; PostedSourceDocumentHeader: RecordRef; begin if EDocument.Direction <> Enum::"E-Document Direction"::Incoming then @@ -264,12 +274,12 @@ codeunit 6103 "E-Document Subscription" PostedSourceDocumentHeader.GetTable(PostedRecord); case PostedSourceDocumentHeader.Number() of - Database::"Purchase Header": + Database::"Purch. Inv. Header": begin - PostedSourceDocumentHeader.SetTable(PurchaseHeader); - PurchaseHeader.CalcFields("Amount Incl. VAT To Inv."); - if EDocument."Amount Incl. VAT" <> PurchaseHeader."Amount Incl. VAT To Inv." then - Error(WrongAmountErr, PurchaseHeader."Amount Incl. VAT To Inv.", EDocument."Amount Incl. VAT"); + PostedSourceDocumentHeader.SetTable(PurchInvHeader); + PurchInvHeader.CalcFields("Amount Including VAT"); + if EDocument."Amount Incl. VAT" <> PurchInvHeader."Amount Including VAT" then + Error(WrongAmountErr, PurchInvHeader."Amount Including VAT", EDocument."Amount Incl. VAT"); end; end; end; @@ -316,4 +326,5 @@ codeunit 6103 "E-Document Subscription" EDocumentHelper: Codeunit "E-Document Helper"; EDocumentProcessingPhase: Enum "E-Document Processing Phase"; WrongAmountErr: Label 'Purchase Document cannot be released as Amount Incl. VAT: %1, is different from E-Document Amount Incl. VAT: %2', Comment = '%1 - Purchase document amount, %2 - E-document amount'; + DeleteNotAllowedErr: Label 'Deletion of Purchase Header linked to E-Document is not allowed.'; } diff --git a/Apps/W1/EDocument/app/src/Processing/OrderMatching/Copilot/EDocAOAITools.Interface.al b/Apps/W1/EDocument/app/src/Processing/OrderMatching/Copilot/EDocAOAITools.Interface.al new file mode 100644 index 0000000000..3d26a54b06 --- /dev/null +++ b/Apps/W1/EDocument/app/src/Processing/OrderMatching/Copilot/EDocAOAITools.Interface.al @@ -0,0 +1,28 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ + +namespace System.AI; + +interface EDocAOAITools +{ + Access = Internal; + /// + /// Get the prompt for the Tool. Tool prompt object describes the Tool and the should contain the following fields: + /// - Type: The name of the Tool, currently only function type is supported. For functions following fields are allowed: + /// -- Name: The name of the Tool. (Required) + /// -- Description: The description of the Tool. (Optional) + /// -- Parameters: The parameters of the Tool. (Required) + /// More details can be found here: https://go.microsoft.com/fwlink/?linkid=2254538 + /// + procedure GetToolPrompt(): JsonObject; + + /// + /// This function is invoked as a response from Azure Open AI. + /// -Arguments: The expected parameters of the Tool defined. + /// -CustomDimension: This can be used to pass any context information to the function. + /// The function returns a variant, and it's up to the implementation to decide what to return. + /// + procedure ToolCall(Arguments: JsonObject; CustomDimension: Dictionary of [Text, Text]): Variant; +} \ No newline at end of file diff --git a/Apps/W1/EDocument/app/src/Processing/OrderMatching/Copilot/EDocPOAOAIFunction.Codeunit.al b/Apps/W1/EDocument/app/src/Processing/OrderMatching/Copilot/EDocPOAOAIFunction.Codeunit.al new file mode 100644 index 0000000000..ea96a205e1 --- /dev/null +++ b/Apps/W1/EDocument/app/src/Processing/OrderMatching/Copilot/EDocPOAOAIFunction.Codeunit.al @@ -0,0 +1,93 @@ +codeunit 6167 "E-Doc. PO AOAI Function" implements EDocAOAITools +{ + Access = Internal; + InherentPermissions = X; + InherentEntitlements = X; + + [NonDebuggable] + procedure GetToolPrompt() Prompt: JsonObject + var + AzureKeyVault: Codeunit "Azure Key Vault"; + EDocPOCopilotMatching: Codeunit "E-Doc. PO Copilot Matching"; + EDocumentMappingToolPrompt: Text; + + begin + if AzureKeyVault.GetAzureKeyVaultSecret('EDocumentMappingToolStruct', EDocumentMappingToolPrompt) then + Prompt.ReadFrom(EDocumentMappingToolPrompt) + else + Session.LogMessage('0000MOW', FailedToGetPromptSecretErr, Verbosity::Error, DataClassification::SystemMetadata, TelemetryScope::All, 'Category', EDocPOCopilotMatching.FeatureName()); + end; + + procedure ToolCall(Arguments: JsonObject; CustomDimension: Dictionary of [Text, Text]): Variant + var + Result, Results, PurchaseOrderLineId, EDocumentLineId : JsonToken; + begin + Arguments.Get('results', Results); + + foreach result in results.AsArray() do begin + Result.AsObject().Get('PID', PurchaseOrderLineId); + Result.AsObject().Get('EID', EDocumentLineId); + + TempEDocumentImportedLine.SetRange("Line No.", EDocumentLineId.AsValue().AsInteger()); + TempEDocumentImportedLine.FindFirst(); + TempPurchaseLine.SetRange("Line No.", PurchaseOrderLineId.AsValue().AsInteger()); + TempPurchaseLine.FindFirst(); + + TempAIProposalBuffer."E-Document Description" := TempEDocumentImportedLine.Description; + TempAIProposalBuffer."E-Document Direct Unit Cost" := TempEDocumentImportedLine."Direct Unit Cost"; + TempAIProposalBuffer."PO Direct Unit Cost" := TempPurchaseLine."Direct Unit Cost"; + TempAIProposalBuffer."E-Document Line Discount" := TempEDocumentImportedLine."Line Discount %"; + TempAIProposalBuffer."PO Line Discount" := TempPurchaseLine."Line Discount %"; + TempAIProposalBuffer."Document Order No." := TempPurchaseLine."Document No."; + TempAIProposalBuffer."E-Document Entry No." := TempEDocumentImportedLine."E-Document Entry No."; + TempAIProposalBuffer."PO Description" := TempPurchaseLine.Description; + + Evaluate(TempAIProposalBuffer."Document Line No.", PurchaseOrderLineId.AsValue().AsText()); + Evaluate(TempAIProposalBuffer."E-Document Line No.", EDocumentLineId.AsValue().AsText()); + TempAIProposalBuffer."AI Proposal" := StrSubstNo(MatchLineTxt, PurchaseOrderLineId.AsValue().AsText()); + if TempAIProposalBuffer.Insert() then; + end; + + exit(TempAIProposalBuffer); + end; + + procedure GetRecord(var TempAIProposalBufferLocal: Record "E-Doc. PO Match Prop. Buffer" temporary) + begin + if TempAIProposalBuffer.FindSet() then + repeat + TempAIProposalBufferLocal.TransferFields(TempAIProposalBuffer); + TempAIProposalBufferLocal.Insert(); + until TempAIProposalBuffer.Next() = 0; + end; + + procedure SetRecords(var TempEDocumentImportedLineLocal: Record "E-Doc. Imported Line" temporary; var TempPurchaseLineLocal: Record "Purchase Line" temporary) + var + begin + TempEDocumentImportedLineLocal.Reset(); + if TempEDocumentImportedLineLocal.FindSet() then + repeat + TempEDocumentImportedLine.TransferFields(TempEDocumentImportedLineLocal); + TempEDocumentImportedLine.Insert(); + until TempEDocumentImportedLineLocal.Next() = 0; + + TempPurchaseLineLocal.Reset(); + if TempPurchaseLineLocal.FindSet() then + repeat + TempPurchaseLine.TransferFields(TempPurchaseLineLocal); + TempPurchaseLine.Insert(); + until TempPurchaseLineLocal.Next() = 0; + end; + + procedure FunctionName(): Text + begin + exit(FunctionNameLbl); + end; + + var + TempEDocumentImportedLine: Record "E-Doc. Imported Line" temporary; + TempPurchaseLine: Record "Purchase Line" temporary; + TempAIProposalBuffer: Record "E-Doc. PO Match Prop. Buffer" temporary; + FunctionNameLbl: Label 'match-lines', Locked = true; + MatchLineTxt: Label 'Matched to Purchase Order Line %1', Comment = 'Number of the order line that the E-Document line is matched to'; + FailedToGetPromptSecretErr: Label 'Failed to get the prompt secret from Azure Key Vault', Locked = true; +} \ No newline at end of file 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 new file mode 100644 index 0000000000..1de4a679aa --- /dev/null +++ b/Apps/W1/EDocument/app/src/Processing/OrderMatching/Copilot/EDocPOCopilotMatching.Codeunit.al @@ -0,0 +1,384 @@ +namespace Microsoft.eServices.EDocument.OrderMatch.Copilot; + +using System.Azure.KeyVault; +using System.AI; +using Microsoft.Purchases.Document; +using Microsoft.Purchases.Setup; +using Microsoft.eServices.EDocument.OrderMatch; +using System.Environment; +using System.Telemetry; +using System.Upgrade; + +codeunit 6163 "E-Doc. PO Copilot Matching" +{ + Access = Internal; + InherentPermissions = X; + InherentEntitlements = X; + + var + FeatureTelemetry: Codeunit "Feature Telemetry"; + CostDifferenceThreshold: Decimal; + AzureOpenAIFailureErr: Label 'Sorry, something went wrong. Please try again.'; + LearnMoreUrlTxt: Label 'https://go.microsoft.com/fwlink/?linkid=2262630', Locked = true; + MatchingCountTxt: Label 'E-Document mapping with AI returned %1 matching', Locked = true; + NotSuccessfulRequestErr: Label 'E-Document Chat Completion Status Code: %1, Error: %2', Locked = true; + SuccessfulRequestMsg: Label 'E-Document Chat Completion was successful', Locked = true; + AttempToUseCopilotMsg: Label 'Attempting to use E-Docoument matching assistance ', Locked = true; + FailedToGetPromptSecretErr: Label 'Failed to get the prompt secret from Azure Key Vault', Locked = true; + FunctionTxt: Label '{ "type": "function", "function" : { "name": "%1" }}', Locked = true; + NoLinesCouldBeMatchedMsg: Label 'No matches were found for Copilot because the conditions regarding prices or quantities have not been met.'; + + [NonDebuggable] + procedure MatchWithCopilot(var TempEDocumentImportedLine: Record "E-Doc. Imported Line" temporary; var TempPurchaseLine: Record "Purchase Line" temporary; var TempAIProposalBuffer: Record "E-Doc. PO Match Prop. Buffer" temporary) IsRequestSuccessful: Boolean + var + PurchasesPayablesSetup: Record "Purchases & Payables Setup"; + SystemPromptTxt: SecretText; + UserPromptText, EDocumentImportLinesTxt, PurchaseLineTxt : Text; + TaskTokenCount, PromtTokenCount : Integer; + begin + FeatureTelemetry.LogUptake('0000MMH', FeatureName(), Enum::"Feature Uptake Status"::Used); + + if PurchasesPayablesSetup.Get() then + CostDifferenceThreshold := PurchasesPayablesSetup."E-Document Matching Difference"; + + SystemPromptTxt := GetSystemPrompt(); + if TempEDocumentImportedLine.IsEmpty() or TempPurchaseLine.IsEmpty() then + exit(true); + + TaskTokenCount := ApproximateTokenCount(SystemPromptTxt.Unwrap()); + + if TempEDocumentImportedLine.FindSet() then begin + repeat + // Build user prompt to include the edocument line and the related purchase order lines + BuildUserPrompt(TempEDocumentImportedLine, TempPurchaseLine, EDocumentImportLinesTxt, PurchaseLineTxt); + + // If the prompt is too large, then send it to the AI Matching service + PromtTokenCount := TaskTokenCount + ApproximateTokenCount(EDocumentImportLinesTxt) + ApproximateTokenCount(PurchaseLineTxt); + if PromtTokenCount > PromptSizeThreshold() then begin + UserPromptText := 'E-document lines:\n' + EDocumentImportLinesTxt + 'Purchase order lines:\n' + PurchaseLineTxt; + UserPromptText := PreparePrompt(UserPromptText); + IsRequestSuccessful := Match(TempAIProposalBuffer, TempEDocumentImportedLine, TempPurchaseLine, SystemPromptTxt, UserPromptText); + EDocumentImportLinesTxt := ''; + PurchaseLineTxt := ''; + UserPromptText := ''; + end; + until TempEDocumentImportedLine.Next() = 0; + + if (EDocumentImportLinesTxt <> '') and (PurchaseLineTxt <> '') then begin + UserPromptText := 'E-document lines:\n' + EDocumentImportLinesTxt + 'Purchase order lines:\n' + PurchaseLineTxt; + + UserPromptText := PreparePrompt(UserPromptText); + IsRequestSuccessful := Match(TempAIProposalBuffer, TempEDocumentImportedLine, TempPurchaseLine, SystemPromptTxt, UserPromptText); + end + else + Message(NoLinesCouldBeMatchedMsg); + end; + + GroundCopilotMatching(TempEDocumentImportedLine, TempPurchaseLine, TempAIProposalBuffer); + end; + + procedure CostDifference(POCost: Decimal; PODiscount: Decimal; EdocCost: Decimal; EDocDiscount: Decimal): Decimal + begin + if PODiscount > 0 then + POCost := POCost - (POCost * PODiscount) / 100; + if EDocDiscount > 0 then + EdocCost := EdocCost - (EdocCost * EDocDiscount) / 100; + + exit((Abs(POCost - EdocCost)) * 100 / POCost); + end; + + [NonDebuggable] + procedure Match(var TempAIProposalBuffer: Record "E-Doc. PO Match Prop. Buffer" temporary; var TempEDocumentImportedLine: Record "E-Doc. Imported Line" temporary; var TempPurchaseLine: Record "Purchase Line" temporary; CompletionPromptTxt: SecretText; UserInputTxt: Text): Boolean + var + CompletionAnswerTxt: Text; + NumberOfFoundMatches: Integer; + begin + CompletionAnswerTxt := Match(CompletionPromptTxt, UserInputTxt); + if CompletionAnswerTxt <> '' then + ProcessAnswer(TempAIProposalBuffer, TempEDocumentImportedLine, TempPurchaseLine, CompletionAnswerTxt, NumberOfFoundMatches); + exit(true) + end; + + [NonDebuggable] + procedure Match(CompletionPromptTxt: SecretText; UserInputTxt: Text): Text + var + AzureOpenAI: Codeunit "Azure OpenAi"; + AOAIDeployments: Codeunit "AOAI Deployments"; + AOAIChatCompletionParams: Codeunit "AOAI Chat Completion Params"; + EDocAIMatchingFunction: Codeunit "E-Doc. PO AOAI Function"; + AOAIChatMessages: Codeunit "AOAI Chat Messages"; + AOAIOperationResponse: Codeunit "AOAI Operation Response"; + begin + Session.LogMessage('0000MOT', AttempToUseCopilotMsg, Verbosity::Normal, DataClassification::SystemMetadata, TelemetryScope::All, 'Category', FeatureName()); + + // Generate OpenAI Completion + AzureOpenAI.SetAuthorization(Enum::"AOAI Model Type"::"Chat Completions", AOAIDeployments.GetGPT4Latest()); + AzureOpenAI.SetCopilotCapability(Enum::"Copilot Capability"::"E-Document Matching Assistance"); + + AOAIChatCompletionParams.SetMaxTokens(MaxTokens()); + AOAIChatCompletionParams.SetTemperature(0); + + AOAIChatMessages.AddTool(EDocAIMatchingFunction.GetToolPrompt()); + AOAIChatMessages.SetToolChoice(StrSubstNo(FunctionTxt, EDocAIMatchingFunction.FunctionName())); + + AOAIChatMessages.SetPrimarySystemMessage(CompletionPromptTxt); + AOAIChatMessages.AddUserMessage(UserInputTxt); + + AzureOpenAI.GenerateChatCompletion(AOAIChatMessages, AOAIChatCompletionParams, AOAIOperationResponse); + if AOAIOperationResponse.IsSuccess() then begin + Session.LogMessage('0000MOU', SuccessfulRequestMsg, Verbosity::Normal, DataClassification::SystemMetadata, TelemetryScope::All, 'Category', FeatureName()); + exit(AOAIOperationResponse.GetResult()); + end + else begin + Session.LogMessage('0000MFN', StrSubstNo(NotSuccessfulRequestErr, AOAIOperationResponse.GetStatusCode(), AOAIOperationResponse.GetError()), Verbosity::Error, DataClassification::SystemMetadata, TelemetryScope::All, 'Category', FeatureName()); + Error(AzureOpenAIFailureErr); + end; + end; + + procedure IsCopilotEnabled(): Boolean + var + AIMatchingImpl: Codeunit "E-Doc. PO Copilot Matching"; + AzureOpenAI: Codeunit "Azure OpenAI"; + EnvironmentInformation: Codeunit "Environment Information"; + begin + if not EnvironmentInformation.IsSaaSInfrastructure() then + exit(false); + + if not CheckSupportedApplicationFamily() then + exit(false); + + AIMatchingImpl.RegisterAICapability(); + if not AzureOpenAI.IsEnabled(Enum::"Copilot Capability"::"E-Document Matching Assistance", true) then + exit(false); + + exit(true); + end; + + procedure SumUnitCostForAIMatches(var TempAIProposalBuffer: Record "E-Doc. PO Match Prop. Buffer" temporary) Sum: Decimal + begin + if TempAIProposalBuffer.FindSet() then + repeat + Sum += TempAIProposalBuffer."Matched Quantity" * TempAIProposalBuffer."E-Document Direct Unit Cost"; + until TempAIProposalBuffer.Next() = 0; + end; + + procedure RegisterAICapability() + var + CopilotCapability: Codeunit "Copilot Capability"; + EnvironmentInformation: Codeunit "Environment Information"; + UpgradeTag: Codeunit "Upgrade Tag"; + begin + if not EnvironmentInformation.IsSaaSInfrastructure() then + exit; + + if UpgradeTag.HasUpgradeTag(RegisterEDocumentPurchaseOrderMatchingCopilotCapability()) then + exit; + + if not CopilotCapability.IsCapabilityRegistered(Enum::"Copilot Capability"::"E-Document Matching Assistance") then + CopilotCapability.RegisterCapability(Enum::"Copilot Capability"::"E-Document Matching Assistance", LearnMoreUrlTxt); + + UpgradeTag.SetUpgradeTag(RegisterEDocumentPurchaseOrderMatchingCopilotCapability()); + FeatureTelemetry.LogUptake('0000MMI', FeatureName(), Enum::"Feature Uptake Status"::"Set up"); + end; + + local procedure PreparePrompt(Prompt: Text): Text + var + NewLineChar: Char; + begin + NewLineChar := 10; + Prompt := Prompt.Replace('\n', NewLineChar); + exit(Prompt); + end; + + local procedure CheckSupportedApplicationFamily(): Boolean + var + EnvironmentInformation: Codeunit "Environment Information"; + ApplicationFamily: Text; + begin + ApplicationFamily := EnvironmentInformation.GetApplicationFamily(); + if ApplicationFamily = 'CA' then //Disabled for Canada due to legal reasons + exit(false); + exit(true); + end; + + [NonDebuggable] + local procedure ProcessAnswer(var TempAIProposalBuffer: Record "E-Doc. PO Match Prop. Buffer" temporary; var TempEDocumentImportedLine: Record "E-Doc. Imported Line" temporary; var TempPurchaseLine: Record "Purchase Line" temporary; CompletionAnswerTxt: Text; var NumberOfFoundMatches: Integer) + var + EDocAIMatchingFunction: Codeunit "E-Doc. PO AOAI Function"; + CustomDimension: Dictionary of [Text, Text]; + ArgumentsJson: JsonObject; + AnswerJson: JsonObject; + ToolsArrayToken: JsonToken; + ToolType: JsonToken; + Tool: JsonToken; + Function: JsonToken; + FunctionName: JsonToken; + FunctionArgument: JsonToken; + Result: Variant; + begin + AnswerJson.ReadFrom(CompletionAnswerTxt); + + EDocAIMatchingFunction.SetRecords(TempEDocumentImportedLine, TempPurchaseLine); + + if AnswerJson.Get('tool_calls', ToolsArrayToken) then + foreach Tool in ToolsArrayToken.AsArray() do begin + Tool.AsObject().Get('type', ToolType); + if ToolType.AsValue().asText() = 'function' then begin + Tool.AsObject().Get('function', Function); + Function.AsObject().Get('name', FunctionName); + Function.AsObject().Get('arguments', FunctionArgument); + + ArgumentsJson.ReadFrom(FunctionArgument.AsValue().AsText()); + Result := EDocAIMatchingFunction.ToolCall(ArgumentsJson, CustomDimension); + EDocAIMatchingFunction.GetRecord(TempAIProposalBuffer); + end; + break; + end + else + FeatureTelemetry.LogError('0000MJD', FeatureName(), 'ProcessAnswer', 'tool_calls not found in the completion answer'); + + NumberOfFoundMatches := TempAIProposalBuffer.Count(); + Session.LogMessage('0000MMJ', StrSubstNo(MatchingCountTxt, NumberOfFoundMatches), Verbosity::Normal, DataClassification::SystemMetadata, TelemetryScope::ExtensionPublisher, 'Category', FeatureName()); + 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; + EDocLineMatching: Codeunit "E-Doc. Line Matching"; + begin + TempAIProposalBuffer.Reset(); + if TempAIProposalBuffer.FindSet() then + repeat + if TempEDocumentImportedLine.Get(TempAIProposalBuffer."E-Document Entry No.", TempAIProposalBuffer."E-Document Line No.") then + if TempPurchaseLine.Get(Enum::"Purchase Document Type"::Order, TempAIProposalBuffer."Document Order No.", TempAIProposalBuffer."Document Line No.") then begin + Clear(TempEDocMatchesThatWasMatched); + EDocLineMatching.MatchOneToOne(TempEDocumentImportedLine, TempPurchaseLine, TempEDocMatchesThatWasMatched); + if (TempEDocMatchesThatWasMatched.Quantity > 0) then begin + + TempAIProposalBuffer."Matched Quantity" := TempEDocMatchesThatWasMatched.Quantity; + TempAIProposalBuffer.Modify(); + end else + TempAIProposalBuffer.Delete(); + end else + TempAIProposalBuffer.Delete(); + + until TempAIProposalBuffer.Next() = 0; + end; + + local procedure BuildUserPrompt(var TempEDocumentImportedLine: Record "E-Doc. Imported Line" temporary; var TempPurchaseLine: Record "Purchase Line" temporary; var EDocumentImportLinesTxt: Text; var PurchaseLineTxt: Text) + var + TempPotentialPurchaseOrderLines: Record "Purchase Line" temporary; + begin + // Find potential PO lines that has the same cost (within threshold) and has quantity to match + if PotentialMatchingPurchaseOrderLine(TempEDocumentImportedLine, TempPurchaseLine, TempPotentialPurchaseOrderLines) then begin + PrepareEDocumentLineStatement(TempEDocumentImportedLine, EDocumentImportLinesTxt); + PreparePurchaseOrderLineStatement(TempPotentialPurchaseOrderLines, PurchaseLineTxt); + end + end; + + + local procedure PotentialMatchingPurchaseOrderLine(var TempEDocumentImportedLine: Record "E-Doc. Imported Line" temporary; var TempPurchaseLine: Record "Purchase Line" temporary; var PurchaseOrderLines: Record "Purchase Line" temporary) PotentialMatchingPurchaseOrderLine: Boolean + var + begin + if TempPurchaseLine.FindSet() then + repeat + if IsPOLineWithinCostThreshold(TempEDocumentImportedLine, TempPurchaseLine) and DoesLinesHaveQuantityToMatch(TempEDocumentImportedLine, TempPurchaseLine) then begin + PurchaseOrderLines.TransferFields(TempPurchaseLine); + PurchaseOrderLines.Insert(); + PotentialMatchingPurchaseOrderLine := true; + end + until TempPurchaseLine.Next() = 0; + end; + + local procedure IsPOLineWithinCostThreshold(var TempEDocumentImportedLine: Record "E-Doc. Imported Line" temporary; var TempPurchaseLine: Record "Purchase Line" temporary): Boolean + begin + exit(CostDifference(TempPurchaseLine."Direct Unit Cost", TempPurchaseLine."Line Discount %", TempEDocumentImportedLine."Direct Unit Cost", TempEDocumentImportedLine."Line Discount %") <= CostDifferenceThreshold); + end; + + local procedure DoesLinesHaveQuantityToMatch(var TempEDocumentImportedLine: Record "E-Doc. Imported Line" temporary; var TempPurchaseLine: Record "Purchase Line" temporary): Boolean + begin + exit(((TempEDocumentImportedLine.Quantity - TempEDocumentImportedLine."Matched Quantity") > 0) and + (((TempPurchaseLine."Quantity Received" - TempPurchaseLine."Quantity Invoiced") - TempPurchaseLine."Qty. to Invoice") > 0)); + end; + + local procedure PrepareEDocumentLineStatement(var TempEDocumentImportedLine: Record "E-Doc. Imported Line" temporary; var EDocumentImportLinesTxt: Text) + begin + EDocumentImportLinesTxt += '- EID: ' + Format(TempEDocumentImportedLine."Line No."); + EDocumentImportLinesTxt += ', Description: ' + TempEDocumentImportedLine.Description; + EDocumentImportLinesTxt += ', Unit of Measure: ' + TempEDocumentImportedLine."Unit of Measure Code"; + if TempEDocumentImportedLine."Line Discount %" <> 0 then + EDocumentImportLinesTxt += ', Cost: ' + Format(TempEDocumentImportedLine."Direct Unit Cost" - ((TempEDocumentImportedLine."Direct Unit Cost" * TempEDocumentImportedLine."Line Discount %") / 100.0)) + else + EDocumentImportLinesTxt += ', Cost: ' + Format(TempEDocumentImportedLine."Direct Unit Cost"); + EDocumentImportLinesTxt += '\n'; + end; + + local procedure PreparePurchaseOrderLineStatement(var PurchaseOrderLines: Record "Purchase Line" temporary; var PurchaseLineTxt: Text) + begin + if PurchaseOrderLines.FindSet() then + repeat + if not PurchaseLineTxt.Contains('PID: ' + Format(PurchaseOrderLines."Line No.")) then begin + PurchaseLineTxt += '- PID: ' + Format(PurchaseOrderLines."Line No."); + PurchaseLineTxt += ', Description: ' + PurchaseOrderLines.Description; + PurchaseLineTxt += ', Unit of Measure: ' + PurchaseOrderLines."Unit of Measure Code"; + if PurchaseOrderLines."Line Discount %" <> 0 then + PurchaseLineTxt += ', Cost: ' + Format(PurchaseOrderLines."Direct Unit Cost" - ((PurchaseOrderLines."Direct Unit Cost" * PurchaseOrderLines."Line Discount %") / 100.0)) + else + PurchaseLineTxt += ', Cost: ' + Format(PurchaseOrderLines."Direct Unit Cost"); + PurchaseLineTxt += '\n'; + end; + until PurchaseOrderLines.Next() = 0; + end; + + local procedure GetSystemPrompt(): SecretText + var + AzureKeyVault: Codeunit "Azure Key Vault"; + Prompt: SecretText; + begin + if AzureKeyVault.GetAzureKeyVaultSecret('EDocumentMappingPrompt', Prompt) then + exit(Prompt); + + Session.LogMessage('0000MOV', FailedToGetPromptSecretErr, Verbosity::Error, DataClassification::SystemMetadata, TelemetryScope::All, 'Category', FeatureName()); + end; + + local procedure PromptSizeThreshold(): Integer + begin + // GPT4 which has a 32K token limit + exit(22000); + end; + + local procedure MaxTokens(): Integer + begin + // this is specifying how many tokens of the AI Model token limit are set aside (reserved) for the response + exit(4096); + end; + + procedure FeatureName(): Text + begin + exit('E-Document Purchase Order Matching with AI'); + end; + + [NonDebuggable] + local procedure ApproximateTokenCount(TextInput: Text): Decimal + var + AverageWordsPerToken: Decimal; + TokenCount: Integer; + WordsInInput: Integer; + begin + AverageWordsPerToken := 0.6; // Based on OpenAI estimate + WordsInInput := TextInput.Split(' ', ',', '.', '!', '?', ';', ':', '/n').Count; + TokenCount := Round(WordsInInput / AverageWordsPerToken, 1); + exit(TokenCount); + end; + + local procedure RegisterEDocumentPurchaseOrderMatchingCopilotCapability(): Code[250] + begin + exit('MS-477518-RegisterEDocumentPurchaseOrderMatchingCopilotCapability-20240112'); + end; + + [EventSubscriber(ObjectType::Page, Page::"Copilot AI Capabilities", 'OnRegisterCopilotCapability', '', false, false)] + local procedure HandleOnRegisterCopilotCapability() + begin + RegisterAICapability(); + end; +} \ No newline at end of file diff --git a/Apps/W1/EDocument/app/src/Processing/OrderMatching/Copilot/EDocPOCopilotProp.Page.al b/Apps/W1/EDocument/app/src/Processing/OrderMatching/Copilot/EDocPOCopilotProp.Page.al new file mode 100644 index 0000000000..3933282ebd --- /dev/null +++ b/Apps/W1/EDocument/app/src/Processing/OrderMatching/Copilot/EDocPOCopilotProp.Page.al @@ -0,0 +1,318 @@ +namespace Microsoft.eServices.EDocument.OrderMatch.Copilot; + +using Microsoft.eServices.EDocument; +using Microsoft.eServices.EDocument.OrderMatch; +using Microsoft.Purchases.Document; +using System.Telemetry; + +page 6166 "E-Doc. PO Copilot Prop" +{ + Caption = 'E-Document Match Order Lines with Copilot'; + PageType = PromptDialog; + ApplicationArea = All; + SourceTable = "E-Document"; + SourceTableTemporary = true; + IsPreview = true; + Extensible = false; + Editable = true; + InherentPermissions = X; + InherentEntitlements = X; + + layout + { + area(Content) + { + group(EDocHeader) + { + ShowCaption = false; + + field("Lines matched Automatically"; AutoMatchedLinesTxt) + { + ApplicationArea = All; + Caption = 'Auto-matched'; + Editable = false; + ToolTip = 'Specifies the number of matches proposed automatically'; + + trigger OnDrillDown() + begin + if not TempEDocOrderMatches.IsEmpty() then + Page.Run(Page::"E-Doc. Order Match", TempEDocOrderMatches); + end; + } + field("Lines matched by Copilot"; CopilotMatchedLinesTxt) + { + ApplicationArea = All; + Caption = 'Copilot matched'; + Editable = false; + ToolTip = 'Specifies the number of matches proposed by Copilot'; + } + field("E-Document No."; Format(Rec."Entry No")) + { + ApplicationArea = All; + Caption = 'E-Document No.'; + Editable = false; + ToolTip = 'Specifies the E-Document number'; + } + field("Summary Text"; SummaryTxt) + { + ApplicationArea = All; + Caption = ''; + ShowCaption = false; + Editable = false; + StyleExpr = SummaryStyleTxt; + ToolTip = 'Specifies the matching summary'; + } + field("Invoice Total Amount"; Rec."Amount Excl. VAT") + { + ApplicationArea = All; + Caption = 'Invoice Total Amount Excl. VAT'; + Editable = false; + ToolTip = 'Specifies the total invoice amount excluding VAT'; + } + field("Matched Total Amount"; MatchedTotal) + { + ApplicationArea = All; + Caption = 'Matched Total Amount Incl. VAT'; + Editable = false; + ToolTip = 'Specifies the matched amount excluding VAT'; + } + } + group(Warning) + { + Caption = ''; + ShowCaption = false; + Visible = (WarningTxt <> ''); + + field("Warning Text"; WarningTxt) + { + ApplicationArea = All; + Caption = ''; + ShowCaption = false; + Editable = false; + Style = Ambiguous; + MultiLine = true; + ToolTip = 'Specifies a warning text'; + } + } + part(ProposalDetails; "E-Doc. PO Match Prop. Sub") + { + Caption = 'Match proposals'; + ShowFilter = false; + ApplicationArea = All; + Editable = true; + Enabled = true; + } + } + } + + actions + { + area(SystemActions) + { + systemaction(Generate) + { + Caption = 'Generate'; + Enabled = true; + ToolTip = 'Generate bank account reconciliation and run auto-matching with Copilot.'; + + trigger OnAction() + begin + GenerateCopilotMatchProposals(); + + if WasCopilotMatchesFound() then + CurrPage.PromptMode := PromptMode::Content + else + CurrPage.Close(); + end; + + } + systemaction(OK) + { + Caption = 'Keep it'; + ToolTip = 'Save purchase order line matching proposed by Copilot.'; + } + systemaction(Cancel) + { + Caption = 'Discard it'; + ToolTip = 'Discard purchase order line matching proposed by Copilot.'; + } + } + } + + var + TempPurchaseOrderLine: Record "Purchase Line" temporary; + TempEDocumentImportedLine: Record "E-Doc. Imported Line" temporary; + TempEDocOrderMatches: Record "E-Doc. Order Match" temporary; + EDocLineMatching: Codeunit "E-Doc. Line Matching"; + AIMatchingImpl: Codeunit "E-Doc. PO Copilot Matching"; + FeatureTelemetry: Codeunit "Feature Telemetry"; + SummaryTxt, SummaryStyleTxt : Text; + WarningTxt: Text; + MatchedTotal: Decimal; + AutoMatchedLinesTxt, CopilotMatchedLinesTxt : Text; + AcceptedProposalCount: Decimal; + IsCopilotReqSuccessful: Boolean; + NumberOfEDocumentLines, NumberOfFullAutoMatchedLines, NumberOfCopilotMatchedLines : Integer; + AutoMatchedLinesLbl: label '%1 of %2 lines (%3%)', Comment = '%1 - an integer; %2 - an integer; %3 a decimal between 0 and 100'; + AllLinesMatchedTxt: label 'All lines (100%) are matched. Review match proposals.'; + SubsetOfLinesMatchedTxt: label '%1% of lines are matched. Review match proposals.', Comment = '%1 - a decimal between 0 and 100'; + MultipleMatchTxt: Label 'Matched to multiple entries. Drill down to see more.'; + + trigger OnQueryClosePage(CloseAction: Action): Boolean + var + TelemetryDimensions: Dictionary of [Text, Text]; + begin + if CloseAction = Action::OK then + PersistSuggestedMatches(); + + AcceptedProposalCount := TempEDocOrderMatches.Count; + + TelemetryDimensions.Add('Category', AIMatchingImpl.FeatureName()); + TelemetryDimensions.Add('CopilotMatchingLines', Format(NumberOfCopilotMatchedLines)); + TelemetryDimensions.Add('AutoMatchingLines', Format(NumberOfFullAutoMatchedLines)); + TelemetryDimensions.Add('EDocumentLines', Format(NumberOfEDocumentLines)); + TelemetryDimensions.Add('AcceptedProposalCount', Format(AcceptedProposalCount)); + TelemetryDimensions.Add('UserAction', Format(CloseAction)); + FeatureTelemetry.LogUsage('0000MMG', AIMatchingImpl.FeatureName(), 'CopilotMatchingComplete', TelemetryDimensions); + end; + + procedure WasCopilotMatchesFound(): Boolean + begin + exit(NumberOfCopilotMatchedLines + NumberOfFullAutoMatchedLines > 0); + end; + + procedure IsCopilotRequestSuccessful(): Boolean + begin + exit(IsCopilotReqSuccessful); + end; + + internal procedure SetGenerateMode(); + begin + CurrPage.PromptMode := PromptMode::Generate; + end; + + local procedure PersistSuggestedMatches() + begin + CurrPage.ProposalDetails.Page.GetRecords(TempEDocOrderMatches); + EDocLineMatching.PersistsUpdates(TempEDocOrderMatches, false); + end; + + internal procedure SetData(InputEDocument: Record "E-Document"; var InputEDocumentImportedLine: Record "E-Doc. Imported Line" temporary; var InputPurchaseOrderLine: Record "Purchase Line" temporary) + begin + InputEDocumentImportedLine.SetRange("Fully Matched", false); + if InputEDocumentImportedLine.FindSet() then + repeat + TempEDocumentImportedLine.Copy(InputEDocumentImportedLine); + TempEDocumentImportedLine.Insert(); + until InputEDocumentImportedLine.Next() = 0; + + InputPurchaseOrderLine.Reset(); + if InputPurchaseOrderLine.FindSet() then + repeat + TempPurchaseOrderLine.Copy(InputPurchaseOrderLine); + TempPurchaseOrderLine.Insert(); + until InputPurchaseOrderLine.Next() = 0; + + Rec := InputEDocument; + CurrPage.Update(); + end; + + local procedure CountFullMatches(var EDocOrderMatches: Record "E-Doc. Order Match" temporary): Integer; + begin + EDocOrderMatches.SetRange("Fully Matched", true); + exit(EDocOrderMatches.Count()); + end; + + local procedure SumUnitCost(var EDocOrderMatches: Record "E-Doc. Order Match" temporary) Sum: Decimal + begin + EDocOrderMatches.Reset(); + if EDocOrderMatches.FindSet() then + repeat + Sum += EDocOrderMatches.Quantity * EDocOrderMatches."E-Document Direct Unit Cost"; + until EDocOrderMatches.Next() = 0; + end; + + local procedure CombineOneToManyInBuffer(var TempAIProposalBuffer: Record "E-Doc. PO Match Prop. Buffer" temporary; var TempLocalEdocOrderMatches: Record "E-Doc. Order Match" temporary) + var + TempAIProposalBuffer2: Record "E-Doc. PO Match Prop. Buffer" temporary; + EDocLineNos: List of [Integer]; + EDocLineNo: Integer; + Sum: Integer; + begin + if TempAIProposalBuffer.FindSet() then + repeat + if not EDocLineNos.Contains(TempAIProposalBuffer."E-Document Line No.") then + EDocLineNos.Add(TempAIProposalBuffer."E-Document Line No."); + until TempAIProposalBuffer.Next() = 0; + + + foreach EDocLineNO in EDocLineNos do begin + TempAIProposalBuffer.SetRange("E-Document Line No.", EDocLineNo); + + if TempAIProposalBuffer.FindSet() then + repeat + TempLocalEdocOrderMatches.InsertMatch(TempAIProposalBuffer, TempLocalEdocOrderMatches); + until TempAIProposalBuffer.Next() = 0; + + if TempAIProposalBuffer.Count() > 1 then begin + TempAIProposalBuffer.CalcSums("Matched Quantity"); + Sum := TempAIProposalBuffer."Matched Quantity"; + TempAIProposalBuffer.FindFirst(); + TempAIProposalBuffer."AI Proposal" := MultipleMatchTxt; + TempAIProposalBuffer."Matched Quantity" := Sum; + TempAIProposalBuffer.Modify(); + end; + + TempAIProposalBuffer2 := TempAIProposalBuffer; + TempAIProposalBuffer2.Insert(); + end; + + TempAIProposalBuffer.Reset(); + TempAIProposalBuffer.DeleteAll(); + if TempAIProposalBuffer2.FindSet() then + repeat + TempAIProposalBuffer := TempAIProposalBuffer2; + TempAIProposalBuffer.Insert(); + until TempAIProposalBuffer2.Next() = 0; + + end; + + local procedure GenerateCopilotMatchProposals() + var + TempLocalEDocOrderMatches: Record "E-Doc. Order Match" temporary; + TempAIProposalBuffer: Record "E-Doc. PO Match Prop. Buffer" temporary; + Pct: Decimal; + begin + NumberOfEDocumentLines := TempEDocumentImportedLine.Count(); + + EDocLineMatching.MatchAutomatically(Rec, TempEDocumentImportedLine, TempPurchaseOrderLine, TempEDocOrderMatches); + NumberOfFullAutoMatchedLines := CountFullMatches(TempEDocOrderMatches); + MatchedTotal := SumUnitCost(TempEDocOrderMatches); + + Pct := Round((NumberOfFullAutoMatchedLines / NumberOfEDocumentLines) * 100, 0.1); + AutoMatchedLinesTxt := StrSubstNo(AutoMatchedLinesLbl, NumberOfFullAutoMatchedLines, NumberOfEDocumentLines, Pct); + EDocLineMatching.FilterOutFullyMatchedLines(TempEDocumentImportedLine, TempPurchaseOrderLine); + + IsCopilotReqSuccessful := AIMatchingImpl.MatchWithCopilot(TempEDocumentImportedLine, TempPurchaseOrderLine, TempAIProposalBuffer); + + CombineOneToManyInBuffer(TempAIProposalBuffer, TempLocalEDocOrderMatches); + NumberOfCopilotMatchedLines := TempAIProposalBuffer.Count(); + + MatchedTotal += AIMatchingImpl.SumUnitCostForAIMatches(TempAIProposalBuffer); + + Pct := Round((NumberOfCopilotMatchedLines / NumberOfEDocumentLines) * 100, 0.1); + CopilotMatchedLinesTxt := StrSubstNo(AutoMatchedLinesLbl, NumberOfCopilotMatchedLines, NumberOfEDocumentLines, Pct); + + if NumberOfEDocumentLines <= (NumberOfFullAutoMatchedLines + NumberOfCopilotMatchedLines) then begin + SummaryStyleTxt := 'Favorable'; + SummaryTxt := AllLinesMatchedTxt; + end else begin + Pct := Round(((NumberOfFullAutoMatchedLines + NumberOfCopilotMatchedLines) / NumberOfEDocumentLines) * 100, 0.1); + SummaryStyleTxt := 'Ambiguous'; + SummaryTxt := StrSubstNo(SubsetOfLinesMatchedTxt, Pct); + end; + + + CurrPage.ProposalDetails.Page.Load(TempAIProposalBuffer, TempLocalEDocOrderMatches); + end; +} \ No newline at end of file diff --git a/Apps/W1/EDocument/app/src/Processing/OrderMatching/Copilot/EDocPOMatchPropBuffer.Table.al b/Apps/W1/EDocument/app/src/Processing/OrderMatching/Copilot/EDocPOMatchPropBuffer.Table.al new file mode 100644 index 0000000000..17ffcfcc34 --- /dev/null +++ b/Apps/W1/EDocument/app/src/Processing/OrderMatching/Copilot/EDocPOMatchPropBuffer.Table.al @@ -0,0 +1,111 @@ +namespace Microsoft.EServices.EDocument.OrderMatch.Copilot; +using Microsoft.eServices.EDocument.OrderMatch; +using Microsoft.eServices.EDocument; +using Microsoft.Purchases.Document; +using Microsoft.Purchases.Setup; + +table 6163 "E-Doc. PO Match Prop. Buffer" +{ + TableType = Temporary; + Extensible = false; + Access = Internal; + InherentPermissions = X; + InherentEntitlements = X; + + fields + { + field(1; "Document Order No."; Code[20]) + { + DataClassification = CustomerContent; + Caption = 'Document Order No.'; + TableRelation = "Purchase Header"."No." where("Document Type" = const(Order)); + } + field(2; "Document Line No."; Integer) + { + DataClassification = CustomerContent; + Caption = 'Document Line No.'; + TableRelation = "Purchase Line"."Line No." where("Document Type" = const(Order), "Document No." = field("Document Order No.")); + } + field(3; "E-Document Entry No."; Integer) + { + DataClassification = CustomerContent; + Caption = 'E-Document Entry No.'; + TableRelation = "E-Document"; + } + field(4; "E-Document Line No."; Integer) + { + DataClassification = CustomerContent; + Caption = 'E-Document Line No.'; + TableRelation = "E-Doc. Imported Line"."Line No." where("E-Document Entry No." = field("E-Document Entry No.")); + } + field(5; "E-Document Description"; Text[100]) + { + DataClassification = CustomerContent; + Caption = 'E-Document Line Description'; + } + field(6; "PO Description"; Text[100]) + { + Caption = 'Purchase Order Line Description'; + } + field(7; "E-Document Direct Unit Cost"; Decimal) + { + DataClassification = CustomerContent; + Caption = 'E-Document Direct Unit Cost'; + } + field(8; "PO Direct Unit Cost"; Decimal) + { + DataClassification = CustomerContent; + Caption = 'Purchase Order Direct Unit Cost'; + } + field(9; "E-Document Line Discount"; Decimal) + { + DataClassification = CustomerContent; + Caption = 'E-Document Line Discount'; + } + field(10; "PO Line Discount"; Decimal) + { + DataClassification = CustomerContent; + Caption = 'Purchase Order Line Discount'; + } + field(11; "Matched Quantity"; Integer) + { + DataClassification = CustomerContent; + Caption = 'Matched Quantity'; + } + field(12; "AI Proposal"; Text[2048]) + { + DataClassification = CustomerContent; + Caption = 'Proposal'; + } + } + + keys + { + key(Key1; "Document Order No.", "Document Line No.", "E-Document Entry No.", "E-Document Line No.") + { + Clustered = true; + } + } + procedure GetStyle() Result: Text + var + PurchasesPayablesSetup: Record "Purchases & Payables Setup"; + EDocPOCopilotMatching: codeunit "E-Doc. PO Copilot Matching"; + CostDifferenceValue: Decimal; + begin + if PurchasesPayablesSetup.Get() then; + + CostDifferenceValue := EDocPOCopilotMatching.CostDifference(Rec."PO Direct Unit Cost", Rec."PO Line Discount", Rec."E-Document Direct Unit Cost", Rec."E-Document Line Discount"); + + if CostDifferenceValue = 0 then + exit('Favorable') + else + if CostDifferenceValue < PurchasesPayablesSetup."E-Document Matching Difference" then + exit('Ambiguous') + else + if CostDifferenceValue > PurchasesPayablesSetup."E-Document Matching Difference" then + exit('Unfavorable'); + + exit('None'); + end; + +} \ No newline at end of file diff --git a/Apps/W1/EDocument/app/src/Processing/OrderMatching/Copilot/EDocPOMatchPropSub.Page.al b/Apps/W1/EDocument/app/src/Processing/OrderMatching/Copilot/EDocPOMatchPropSub.Page.al new file mode 100644 index 0000000000..585fbf095f --- /dev/null +++ b/Apps/W1/EDocument/app/src/Processing/OrderMatching/Copilot/EDocPOMatchPropSub.Page.al @@ -0,0 +1,100 @@ +namespace Microsoft.eServices.EDocument.OrderMatch.Copilot; +using Microsoft.eServices.EDocument.OrderMatch; + +page 6163 "E-Doc. PO Match Prop. Sub" +{ + Caption = 'Match Proposals'; + PageType = ListPart; + ApplicationArea = All; + Extensible = false; + SourceTable = "E-Doc. PO Match Prop. Buffer"; + SourceTableTemporary = true; + DeleteAllowed = true; + InsertAllowed = false; + ModifyAllowed = false; + InherentPermissions = X; + InherentEntitlements = X; + + layout + { + area(Content) + { + repeater(GroupName) + { + field("E-Document Line No."; Rec."E-Document Line No.") + { + ApplicationArea = All; + Tooltip = 'Specifies the E-Document line number.'; + } + field(Description; Rec."E-Document Description") + { + ApplicationArea = All; + Tooltip = 'Specifies the E-Document line description.'; + StyleExpr = StyleTxt; + } + field("Quantity to Apply"; Rec."Matched Quantity") + { + ApplicationArea = All; + Tooltip = 'Specifies the quantity that will be applied to purchase order line.'; + } + field("AI Proposal"; Rec."AI Proposal") + { + ApplicationArea = All; + Tooltip = 'Specifies the action proposed by the AI.'; + + trigger OnDrillDown() + begin + TempEdocOrderMatches.SetRange("E-Document Line No.", Rec."E-Document Line No."); + Page.Run(Page::"E-Doc. Order Match", TempEdocOrderMatches); + TempEdocOrderMatches.SetRange("E-Document Line No."); + end; + } + } + } + } + + var + TempEdocOrderMatches: Record "E-Doc. Order Match" temporary; + StyleTxt: Text; + + internal procedure GetRecords(var TempEdocOrderMatches2: Record "E-Doc. Order Match" temporary) + begin + Clear(TempEdocOrderMatches2); + if TempEdocOrderMatches.FindSet() then + repeat + TempEdocOrderMatches2.TransferFields(TempEdocOrderMatches); + TempEdocOrderMatches2.Insert(); + until TempEdocOrderMatches.Next() = 0; + end; + + internal procedure Load(var TempAIProposalBuffer: Record "E-Doc. PO Match Prop. Buffer"; var TempInputEdocOrderMatches: Record "E-Doc. Order Match" temporary) + begin + TempAIProposalBuffer.Reset(); + if TempAIProposalBuffer.FindSet() then + repeat + Rec.TransferFields(TempAIProposalBuffer); + Rec.Insert(); + until TempAIProposalBuffer.Next() = 0; + + if TempInputEdocOrderMatches.FindSet() then + repeat + TempEdocOrderMatches := TempInputEdocOrderMatches; + TempEdocOrderMatches.Insert(); + until TempInputEdocOrderMatches.Next() = 0; + end; + + trigger OnAfterGetRecord(); + begin + StyleTxt := Rec.GetStyle(); + end; + + trigger OnDeleteRecord(): Boolean + begin + TempEdocOrderMatches.SetRange("E-Document Line No.", Rec."E-Document Line No."); + if TempEdocOrderMatches.FindSet() then + repeat + TempEdocOrderMatches.Delete(); + until TempEdocOrderMatches.Next() = 0; + TempEdocOrderMatches.Reset(); + end; +} \ No newline at end of file diff --git a/Apps/W1/EDocument/app/src/Processing/OrderMatching/EDocImportedLine.Table.al b/Apps/W1/EDocument/app/src/Processing/OrderMatching/EDocImportedLine.Table.al index e5bced079c..77d429307c 100644 --- a/Apps/W1/EDocument/app/src/Processing/OrderMatching/EDocImportedLine.Table.al +++ b/Apps/W1/EDocument/app/src/Processing/OrderMatching/EDocImportedLine.Table.al @@ -35,14 +35,17 @@ table 6165 "E-Doc. Imported Line" Caption = 'Unit Of Measure'; Editable = false; } - field(6; Quantity; Integer) +#pragma warning disable AS0004 + field(6; Quantity; Decimal) { Caption = 'Quantity'; + DecimalPlaces = 0 : 5; Editable = false; } - field(7; "Matched Quantity"; Integer) + field(7; "Matched Quantity"; Decimal) { Caption = 'Matched Quantity'; + DecimalPlaces = 0 : 5; Editable = false; trigger OnValidate() @@ -53,6 +56,7 @@ table 6165 "E-Doc. Imported Line" Validate("Fully Matched"); end; } +#pragma warning restore AS0004 field(8; "Fully Matched"; Boolean) { Caption = 'Fully Matched'; @@ -115,7 +119,7 @@ table 6165 "E-Doc. Imported Line" TempEDocImportedLine.SetRange("E-Document Entry No.", EDocument."Entry No"); LineNo := TempEDocImportedLine.GetNextLineNo(); - TempEDocImportedLine.Reset(); + Clear(TempEDocImportedLine); TempEDocImportedLine."E-Document Entry No." := EDocument."Entry No"; TempEDocImportedLine."Line No." := LineNo; TempEDocImportedLine."No." := PurchaseLine."No."; @@ -130,8 +134,7 @@ table 6165 "E-Doc. Imported Line" TempEDocImportedLine.Type := PurchaseLine.Type; TempEDocImportedLine.Quantity := PurchaseLine.Quantity; TempEDocImportedLine."Direct Unit Cost" := PurchaseLine."Direct Unit Cost"; - if PurchaseLine."Line Discount Amount" > 0 then - TempEDocImportedLine."Line Discount %" := 100 * (PurchaseLine."Line Discount Amount" / (PurchaseLine.Amount + PurchaseLine."Line Discount Amount")); + TempEDocImportedLine."Line Discount %" := 100 * (PurchaseLine."Line Discount Amount" / (PurchaseLine.Amount + PurchaseLine."Line Discount Amount")); TempEDocImportedLine.Insert(); end; diff --git a/Apps/W1/EDocument/app/src/Processing/OrderMatching/EDocLineMatching.Codeunit.al b/Apps/W1/EDocument/app/src/Processing/OrderMatching/EDocLineMatching.Codeunit.al index b2d828a915..291c7d497d 100644 --- a/Apps/W1/EDocument/app/src/Processing/OrderMatching/EDocLineMatching.Codeunit.al +++ b/Apps/W1/EDocument/app/src/Processing/OrderMatching/EDocLineMatching.Codeunit.al @@ -9,6 +9,9 @@ using System.Utilities; codeunit 6164 "E-Doc. Line Matching" { Access = Internal; + Permissions = + tabledata "E-Doc. Imported Line" = im, + tabledata "E-Doc. Order Match" = idm; var EmptyRecordErr: Label 'Empty selection cannot be matched.'; @@ -16,7 +19,7 @@ codeunit 6164 "E-Doc. Line Matching" DiscountDiffErr: Label 'Varied Discount found in existing matching for Import line %1. Please review and undo previous matching in order to match selection', Comment = '%1 - Import line number'; UnitCostErr: Label 'Varied Unit Costs found among selected %1 entries. Please review and deselect entries with different Unit Costs in order to match selection', Comment = '%1 - Table name for selected entries'; UnitCostDiffErr: Label 'Varied Unit Cost found in existing matching for Import line %1. Please review and undo previous matching in order to match selection', Comment = '%1 - Import line number'; - MatchErr: Label '%1 discrepancy detected in 1 or more matches for Purchase Line %2. %3 is required across all matches.', Comment = '%1 - Field Caption, %2 - Purchase Line No., %3 - Field Caption'; + MatchErr: Label 'Discrepancy detected in line amount for 1 or more matches for Purchase Line %1.', Comment = '%1 - Purchase Line No'; UOMErr: Label 'Varied Unit Of Measures found among selected %1 entries. Please review and deselect entries with different Unit Of Measures in order to match selection', Comment = '%1 - Table name for selected entries'; UnmatchedImportLineErr: Label 'Matching of Imported Line %1 is incomplete. It is not fully matched to purchase order lines.', Comment = '%1 - Imported Line No.'; OverwriteExistingMatchesTxt: Label 'There are lines for this e-document that are already matched with this purchase order.\\ Do you want to overwrite the existing matches?'; @@ -25,10 +28,18 @@ codeunit 6164 "E-Doc. Line Matching" procedure RunMatching(var EDocument: Record "E-Document") var + EDocService: Record "E-Document Service"; + EDocServiceStatus: Record "E-Document Service Status"; + EDocLog: Codeunit "E-Document Log"; EDocOrderLineMatching: Page "E-Doc. Order Line Matching"; begin - EDocOrderLineMatching.SetRecord(EDocument); - EDocOrderLineMatching.RunModal(); + EDocument.TestField("Document Type", Enum::"E-Document Type"::"Purchase Order"); + EDocument.TestField(EDocument.Status, Enum::"E-Document Status"::"In Progress"); + EDocService := EDocLog.GetLastServiceFromLog(EDocument); + EDocServiceStatus.Get(EDocument."Entry No", EDocService.Code); + EDocServiceStatus.TestField(Status, Enum::"E-Document Service Status"::"Order Linked"); + EDocOrderLineMatching.SetTempRecord(EDocument); + EDocOrderLineMatching.Run(); end; procedure ApplyToPurchaseOrder(var EDocument: Record "E-Document"; var TempEDocumentImportedLine: Record "E-Doc. Imported Line" temporary) @@ -57,22 +68,20 @@ codeunit 6164 "E-Doc. Line Matching" PurchaseHeader.Validate("E-Document Link", EDocument.SystemId); PurchaseHeader.Modify(); - EDocOrderMatch.SetRange("E-Document Entry No.", EDocument."Entry No"); EDocOrderMatch.SetRange("Document Order No.", EDocument."Order No."); PurchaseLine.SetRange("Document Type", Enum::"Purchase Document Type"::Order); PurchaseLine.SetRange("Document No.", EDocument."Order No."); - if PurchaseLine.FindSet() then repeat EDocOrderMatch.SetRange("Document Line No.", PurchaseLine."Line No."); // We check that if there is a set, then Direct Cost, UOM and Discount % is all the same, otherwise we cant - TestFieldsAreTheSameInSet(EDocOrderMatch); + TestLineTotalAreTheSameInSet(EDocOrderMatch); if EDocOrderMatch.FindFirst() then begin - if PurchaseLine."Direct Unit Cost" <> EDocOrderMatch."Direct Unit Cost" then - PurchaseLine.Validate("Direct Unit Cost", EDocOrderMatch."Direct Unit Cost"); + if PurchaseLine."Direct Unit Cost" <> EDocOrderMatch."E-Document Direct Unit Cost" then + PurchaseLine.Validate("Direct Unit Cost", EDocOrderMatch."E-Document Direct Unit Cost"); if PurchaseLine."Line Discount %" <> EDocOrderMatch."Line Discount %" then PurchaseLine.Validate("Line Discount %", EDocOrderMatch."Line Discount %"); PurchaseLine.Validate("Amount Including VAT"); @@ -84,20 +93,21 @@ codeunit 6164 "E-Doc. Line Matching" EDocLogHelper.InsertLog(EDocument, EDocService, Enum::"E-Document Service Status"::"Order Updated"); end; - local procedure TestFieldsAreTheSameInSet(var EDocOrderMatch: Record "E-Doc. Order Match") + local procedure TestLineTotalAreTheSameInSet(var EDocOrderMatch: Record "E-Doc. Order Match") var EDocOrderMatch2: Record "E-Doc. Order Match"; + Total, Total2 : Decimal; begin if not EDocOrderMatch.FindFirst() then exit; + Total := EDocOrderMatch."E-Document Direct Unit Cost" - (EDocOrderMatch."E-Document Direct Unit Cost" * EDocOrderMatch."Line Discount %" / 100); EDocOrderMatch2.Copy(EDocOrderMatch); if EDocOrderMatch2.FindSet() then repeat - if EDocOrderMatch2."Direct Unit Cost" <> EDocOrderMatch."Direct Unit Cost" then - Error(MatchErr, EDocOrderMatch.FieldCaption("Direct Unit Cost"), EDocOrderMatch."Document Line No.", EDocOrderMatch.FieldCaption("Direct Unit Cost")); - if EDocOrderMatch2."Line Discount %" <> EDocOrderMatch."Line Discount %" then - Error(MatchErr, EDocOrderMatch.FieldCaption("Line Discount %"), EDocOrderMatch."Document Line No.", EDocOrderMatch.FieldCaption("Line Discount %")); + Total2 := EDocOrderMatch2."E-Document Direct Unit Cost" - (EDocOrderMatch2."E-Document Direct Unit Cost" * EDocOrderMatch2."Line Discount %" / 100); + if Total <> Total2 then + Error(MatchErr, EDocOrderMatch."Document Line No."); until EDocOrderMatch2.Next() = 0; end; @@ -280,7 +290,7 @@ codeunit 6164 "E-Doc. Line Matching" EDocOrderMatch.SetRange("E-Document Entry No.", TempEDocImportedLine."E-Document Entry No."); EDocOrderMatch.SetRange("Document Line No.", TempPurchaseLine."Line No."); if EDocOrderMatch.FindFirst() then begin - if EDocOrderMatch."Direct Unit Cost" <> TempEDocImportedLine."Direct Unit Cost" then + if EDocOrderMatch."E-Document Direct Unit Cost" <> TempEDocImportedLine."Direct Unit Cost" then Error(UnitCostDiffErr, EDocOrderMatch."E-Document Line No."); if EDocOrderMatch."Line Discount %" <> TempEDocImportedLine."Line Discount %" then Error(DiscountDiffErr, EDocOrderMatch."E-Document Line No."); @@ -328,37 +338,24 @@ codeunit 6164 "E-Doc. Line Matching" if TempEDocumentImportedLine.IsEmpty() or TempPurchaseLine.IsEmpty() then Error(EmptyRecordErr); - // Automatic matching will do the following - // - For each Import Line, try to get full assignment in 1 or more PO lines - // - Filter on Type, then Number, Then Text + // Automatic matching will do the following: + // - Filter on items with the same unit of measure, direct unit cost and line discount % + // - If string nearness is above 80% then match automatically if TempEDocumentImportedLine.FindSet() then repeat - - // Match based on Number - TempPurchaseLine.Reset(); - TempPurchaseLine.SetRange("No.", TempEDocumentImportedLine."No."); TempPurchaseLine.SetRange("Unit of Measure Code", TempEDocumentImportedLine."Unit Of Measure Code"); TempPurchaseLine.SetRange("Direct Unit Cost", TempEDocumentImportedLine."Direct Unit Cost"); TempPurchaseLine.SetRange("Line Discount %", TempEDocumentImportedLine."Line Discount %"); - - MatchOneToMany(TempEDocumentImportedLine, TempPurchaseLine, TempEDocMatchesThatWasMatched); - - if TempEDocumentImportedLine.Quantity > TempEDocumentImportedLine."Matched Quantity" then begin - - // We still have more to match for imported line - TempPurchaseLine.SetRange("No."); - TempPurchaseLine.SetFilter("No.", '<>%1', TempEDocumentImportedLine."No."); - if TempPurchaseLine.FindSet() then - // TO precheck to avoid unessesary Calc String Nearness + if TempPurchaseLine.FindSet() then + repeat if TempPurchaseLine.MaxQtyToInvoice() > TempPurchaseLine."Qty. to Invoice" then // If substring is 80% match if RecordMatchMgt.CalculateStringNearness(TempPurchaseLine.Description, TempEDocumentImportedLine.Description, 4, 100) > 80 then MatchOneToOne(TempEDocumentImportedLine, TempPurchaseLine, TempEDocMatchesThatWasMatched); - end; + until TempPurchaseLine.Next() = 0; until TempEDocumentImportedLine.Next() = 0; - // Reset filters before exit TempPurchaseLine.Reset(); TempEDocumentImportedLine.Reset(); end; @@ -378,11 +375,13 @@ codeunit 6164 "E-Doc. Line Matching" TempEDocMatchesThatWasMatched.Validate("E-Document Entry No.", TempEDocumentImportedLine."E-Document Entry No."); TempEDocMatchesThatWasMatched.Validate("E-Document Line No.", TempEDocumentImportedLine."Line No."); TempEDocMatchesThatWasMatched.Validate(Quantity, Quantity); - TempEDocMatchesThatWasMatched.Validate("Direct Unit Cost", TempEDocumentImportedLine."Direct Unit Cost"); + TempEDocMatchesThatWasMatched.Validate("E-Document Direct Unit Cost", TempEDocumentImportedLine."Direct Unit Cost"); + TempEDocMatchesThatWasMatched.Validate("PO Direct Unit Cost", TempPurchaseLine."Direct Unit Cost"); TempEDocMatchesThatWasMatched.Validate("Line Discount %", TempEDocumentImportedLine."Line Discount %"); TempEDocMatchesThatWasMatched.Validate("Unit of Measure Code", TempEDocumentImportedLine."Unit of Measure Code"); TempEDocMatchesThatWasMatched.Validate("Fully Matched", FullMatch); - TempEDocMatchesThatWasMatched.Description := TempEDocumentImportedLine.Description; + TempEDocMatchesThatWasMatched."PO Description" := TempPurchaseLine.Description; + TempEDocMatchesThatWasMatched."E-Document Description" := TempEDocumentImportedLine.Description; TempEDocMatchesThatWasMatched.Insert(); end; @@ -453,7 +452,7 @@ codeunit 6164 "E-Doc. Line Matching" EDocOrderMatch.SetRange("Document Order No.", EDocument."Order No."); if EDocOrderMatch.FindSet() then repeat - Sum += EDocOrderMatch.Quantity * EDocOrderMatch."Direct Unit Cost"; + Sum += EDocOrderMatch.Quantity * EDocOrderMatch."E-Document Direct Unit Cost"; until EDocOrderMatch.Next() = 0; end; } \ No newline at end of file diff --git a/Apps/W1/EDocument/app/src/Processing/OrderMatching/EDocOrderLineMatching.Page.al b/Apps/W1/EDocument/app/src/Processing/OrderMatching/EDocOrderLineMatching.Page.al index e167c767bc..ff0c3637d5 100644 --- a/Apps/W1/EDocument/app/src/Processing/OrderMatching/EDocOrderLineMatching.Page.al +++ b/Apps/W1/EDocument/app/src/Processing/OrderMatching/EDocOrderLineMatching.Page.al @@ -1,9 +1,10 @@ namespace Microsoft.eServices.EDocument.OrderMatch; using Microsoft.eServices.EDocument; -using System.Utilities; +using Microsoft.eServices.EDocument.OrderMatch.Copilot; using Microsoft.Purchases.Document; - +using System.Telemetry; +#pragma warning disable AS0032 page 6167 "E-Doc. Order Line Matching" { Caption = 'Purchase Order Matching'; @@ -11,9 +12,11 @@ page 6167 "E-Doc. Order Line Matching" PageType = Card; ApplicationArea = All; SourceTable = "E-Document"; + SourceTableTemporary = true; InsertAllowed = false; DeleteAllowed = false; RefreshOnActivate = true; + Permissions = tabledata "E-Document" = m; layout { @@ -37,12 +40,11 @@ page 6167 "E-Doc. Order Line Matching" Caption = 'E-Document Date'; ToolTip = 'Specifies the electronic document date.'; } - field("Amount Excl. VAT"; Rec."Amount Excl. VAT") + field("Amount Incl. VAT"; Rec."Amount Incl. VAT") { Caption = 'E-Document Amount'; - ToolTip = 'Specifies the e-document amount excluding VAT.'; + ToolTip = 'Specifies the e-document amount including VAT.'; } - } group(Control8) { @@ -107,6 +109,20 @@ page 6167 "E-Doc. Order Line Matching" SetUserInteractions(); end; } + action(MatchCopilot) + { + Caption = 'Match with Copilot'; + ToolTip = 'Match e-document lines with the assistance of Copilot'; + ApplicationArea = All; + Image = SparkleFilled; + Visible = CopilotActionVisible; + + trigger OnAction() + begin + MatchWithCopilot(true); + SetUserInteractions(); + end; + } action(RemoveMatch) { Caption = 'Remove Match'; @@ -130,6 +146,8 @@ page 6167 "E-Doc. Order Line Matching" trigger OnAction() begin EDocMatchOrderLines.RemoveAllMatches(Rec); + if DiscountNotification.Recall() then; + if CostNotification.Recall() then; SetUserInteractions(); end; } @@ -184,6 +202,7 @@ page 6167 "E-Doc. Order Line Matching" } group(Matching) { + actionref(MatchCopilot_Promoted; MatchCopilot) { } actionref(MatchManual_Promoted; MatchManual) { } actionref(MatchAuto_Promoted; MatchAutomatic) { } actionref(RemoveMatch_Promoted; RemoveMatch) { } @@ -198,31 +217,50 @@ page 6167 "E-Doc. Order Line Matching" } var + FeatureTelemetry: Codeunit "Feature Telemetry"; EDocMatchOrderLines: Codeunit "E-Doc. Line Matching"; - OpenPurchaseOrderMsg: Label 'Purchase order is not Open, which is required in order to match with e-document. Do you want to reopen purchase order?'; + DiscountNotification, CostNotification : Notification; + CopilotActionVisible, AutoRunCopilot : Boolean; LineDiscountVaryMatchMsg: Label 'Matched e-document lines (%1) has Line Discount % different from matched purchase order line. Please verify matches are correct.', Comment = '%1 - Line number'; LineCostVaryMatchMsg: Label 'Matched e-document lines (%1) has Direct Unit Cost different from matched purchase order line. Please verify matches are correct.', Comment = '%1 - Line number'; + NoMatchesFoundMsg: Label 'Copilot could not find any line matches. Please review manually'; + + trigger OnOpenPage() + var + EDocPOMatching: Codeunit "E-Doc. PO Copilot Matching"; + begin + CopilotActionVisible := EDocPOMatching.IsCopilotEnabled(); + end; - trigger OnAfterGetCurrRecord() + trigger OnInit() + begin + AutoRunCopilot := true; + end; + + trigger OnAfterGetRecord() + var + EDocOrderMatch: Record "E-Doc. Order Match"; begin CurrPage.OrderLines.Page.SetEDocumentBeingMatched(Rec); CurrPage.ImportedLines.Page.SetEDocumentBeingMatched(Rec); CurrPage.OrderLines.Page.ResetQtyOnNonMatchedLines(); - CheckPurchaseHeaderOpen(); + OpenPurchaseHeader(); + + if CopilotActionVisible and AutoRunCopilot then begin + AutoRunCopilot := false; + EDocOrderMatch.SetRange("E-Document Entry No.", Rec."Entry No"); + if EDocOrderMatch.IsEmpty() then + MatchWithCopilot(false); + end; end; - local procedure CheckPurchaseHeaderOpen() + local procedure OpenPurchaseHeader() var PurchaseHeader: Record "Purchase Header"; - ConfirmManagement: Codeunit "Confirm Management"; begin PurchaseHeader.Get(Rec."Document Record ID"); - if PurchaseHeader.Status <> Enum::"Purchase Document Status"::Open then - if ConfirmManagement.GetResponseOrDefault(OpenPurchaseOrderMsg, true) then - PurchaseHeader.SetStatus(0) // Open - else - Error(''); + Codeunit.Run(Codeunit::"Purchase Manual Reopen", PurchaseHeader); end; local procedure ApplyToPurchaseOrder() @@ -231,6 +269,7 @@ page 6167 "E-Doc. Order Line Matching" PurchaseHeader: Record "Purchase Header"; PurchaseOrderPage: Page "Purchase Order"; begin + OpenPurchaseHeader(); CurrPage.ImportedLines.Page.GetRecords(TempEDocImportedLines); EDocMatchOrderLines.ApplyToPurchaseOrder(Rec, TempEDocImportedLines); @@ -285,6 +324,32 @@ page 6167 "E-Doc. Order Line Matching" end; end; + local procedure MatchWithCopilot(CheckToOverwrite: Boolean) + var + TempEDocImportedLines: Record "E-Doc. Imported Line" temporary; + TempPurchaseLines: Record "Purchase Line" temporary; + AIMatchingImpl: Codeunit "E-Doc. PO Copilot Matching"; + EDocOrderMatchAIProposal: Page "E-Doc. PO Copilot Prop"; + begin + FeatureTelemetry.LogUptake('0000MB0', AIMatchingImpl.FeatureName(), Enum::"Feature Uptake Status"::Discovered); + FeatureTelemetry.LogUptake('0000MB1', AIMatchingImpl.FeatureName(), Enum::"Feature Uptake Status"::"Set up"); + + CurrPage.ImportedLines.Page.GetRecords(TempEDocImportedLines); + CurrPage.OrderLines.Page.GetRecords(TempPurchaseLines); + + if CheckToOverwrite then + EDocMatchOrderLines.AskToOverwrite(Rec, TempEDocImportedLines, TempPurchaseLines); + Commit(); + EDocOrderMatchAIProposal.SetData(Rec, TempEDocImportedLines, TempPurchaseLines); + EDocOrderMatchAIProposal.SetGenerateMode(); + EDocOrderMatchAIProposal.LookupMode(true); + if EDocOrderMatchAIProposal.RunModal() = Action::Cancel then + if ((not EDocOrderMatchAIProposal.WasCopilotMatchesFound()) and EDocOrderMatchAIProposal.IsCopilotRequestSuccessful()) then + Message(NoMatchesFoundMsg); + + CurrPage.Update(); + end; + local procedure SetUserInteractions() begin CurrPage.ImportedLines.Page.SetUserInteractions(); @@ -295,7 +360,6 @@ page 6167 "E-Doc. Order Line Matching" var EDocImportedLine: Record "E-Doc. Imported Line"; PurchaseLine: Record "Purchase Line"; - DiscountNotification, CostNotification : Notification; LineDiscountNos, DirectUnitCostNos : Text; begin if TempEDocMatches.FindSet() then @@ -325,4 +389,13 @@ page 6167 "E-Doc. Order Line Matching" SelectionNotification.Send(); end; -} \ No newline at end of file + internal procedure SetTempRecord(var EDocument: Record "E-Document") + begin + Rec.DeleteAll(); + Rec.TransferFields(EDocument); + Rec.SystemId := EDocument.SystemId; + Rec.Insert(false); + end; + +} +#pragma warning restore AS0032 \ No newline at end of file diff --git a/Apps/W1/EDocument/app/src/Processing/OrderMatching/EDocOrderMatch.Page.al b/Apps/W1/EDocument/app/src/Processing/OrderMatching/EDocOrderMatch.Page.al index d465694588..e5ca544bb7 100644 --- a/Apps/W1/EDocument/app/src/Processing/OrderMatching/EDocOrderMatch.Page.al +++ b/Apps/W1/EDocument/app/src/Processing/OrderMatching/EDocOrderMatch.Page.al @@ -28,16 +28,31 @@ page 6164 "E-Doc. Order Match" Caption = 'Purchase Order Line No.'; ToolTip = 'Specifies Purchase Order Line No.'; } - field("Description"; Rec.Description) + field("EDoc Description"; Rec."E-Document Description") { - Caption = 'Description'; - ToolTip = 'Specifies the description of what is being matched.'; + Caption = 'E-Document Description'; + ToolTip = 'Specifies the description of matched E-Document line.'; + } + field("Description"; Rec."PO Description") + { + Caption = 'Purchase order Description'; + ToolTip = 'Specifies the description of matched Purchase Order Line.'; } field("Matched Quantity"; Rec.Quantity) { Caption = 'Matched Quantity'; ToolTip = 'Specifies the quantity that was matched for the imported line to the purchase order line.'; } + field("E-Document Direct Unit Cost"; Rec."E-Document Direct Unit Cost") + { + Caption = 'E-Document Unit Cost'; + ToolTip = 'Specifies the direct unit cost of the E-Document line.'; + } + field("PO Direct Unit Cost"; Rec."PO Direct Unit Cost") + { + Caption = 'Purchase Order Unit Cost'; + ToolTip = 'Specifies the direct unit cost of the purchase order line.'; + } } } } diff --git a/Apps/W1/EDocument/app/src/Processing/OrderMatching/EDocOrderMatch.Table.al b/Apps/W1/EDocument/app/src/Processing/OrderMatching/EDocOrderMatch.Table.al index 027966176e..b4fac45a2c 100644 --- a/Apps/W1/EDocument/app/src/Processing/OrderMatching/EDocOrderMatch.Table.al +++ b/Apps/W1/EDocument/app/src/Processing/OrderMatching/EDocOrderMatch.Table.al @@ -2,6 +2,7 @@ namespace Microsoft.eServices.EDocument.OrderMatch; using Microsoft.Purchases.Document; using Microsoft.eServices.EDocument; +using Microsoft.eServices.EDocument.OrderMatch.Copilot; table 6164 "E-Doc. Order Match" { @@ -34,26 +35,36 @@ table 6164 "E-Doc. Order Match" { Caption = 'Quantity'; } - field(6; "Direct Unit Cost"; Decimal) +#pragma warning disable AS0005, AS0125 + field(6; "E-Document Direct Unit Cost"; Decimal) { - Caption = 'Unit Cost'; + Caption = 'E-Document Unit Cost'; } - field(7; "Line Discount %"; Decimal) + field(7; "PO Direct Unit Cost"; Decimal) + { + Caption = 'Purchase Order Unit Cost'; + } + field(8; "Line Discount %"; Decimal) { Caption = 'Discount %'; } - field(8; "Unit of Measure Code"; Code[20]) + field(9; "Unit of Measure Code"; Code[20]) { Caption = 'Unit of Measure'; } - field(9; Description; Text[100]) + field(10; "E-Document Description"; Text[100]) + { + Caption = 'E-Document Description'; + } + field(11; "PO Description"; Text[100]) { - Caption = 'Description'; + Caption = 'Purchase Order Description'; } - field(10; "Fully Matched"; Boolean) + field(12; "Fully Matched"; Boolean) { Caption = 'Fully Matched'; } +#pragma warning restore AS0005, AS0125 } keys @@ -78,5 +89,20 @@ table 6164 "E-Doc. Order Match" ImportedLine.Get(Rec."E-Document Entry No.", Rec."E-Document Line No."); end; + procedure InsertMatch(var TempAIProposalBuffer: Record "E-Doc. PO Match Prop. Buffer" temporary; var TempEDocMatches: Record "E-Doc. Order Match" temporary) + begin + TempEDocMatches.Init(); + TempEDocMatches.Validate("Document Order No.", TempAIProposalBuffer."Document Order No."); + TempEDocMatches.Validate("Document Line No.", TempAIProposalBuffer."Document Line No."); + TempEDocMatches.Validate("E-Document Entry No.", TempAIProposalBuffer."E-Document Entry No."); + TempEDocMatches.Validate("E-Document Line No.", TempAIProposalBuffer."E-Document Line No."); + TempEDocMatches.Validate(Quantity, TempAIProposalBuffer."Matched Quantity"); + TempEDocMatches.Validate("E-Document Direct Unit Cost", TempAIProposalBuffer."E-Document Direct Unit Cost"); + TempEDocMatches.Validate("PO Direct Unit Cost", TempAIProposalBuffer."PO Direct Unit Cost"); + TempEDocMatches."E-Document Description" := TempAIProposalBuffer."E-Document Description"; + TempEDocMatches."PO Description" := TempAIProposalBuffer."PO Description"; + TempEDocMatches.Insert(); + end; + } \ No newline at end of file diff --git a/Apps/W1/EDocument/app/src/Processing/OrderMatching/EDocOrderMatchAct.Page.al b/Apps/W1/EDocument/app/src/Processing/OrderMatching/EDocOrderMatchAct.Page.al new file mode 100644 index 0000000000..00186c296b --- /dev/null +++ b/Apps/W1/EDocument/app/src/Processing/OrderMatching/EDocOrderMatchAct.Page.al @@ -0,0 +1,44 @@ +// ------------------------------------------------------------------------------------------------ +// 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; + +page 6162 "E-Doc. Order Match Act." +{ + PageType = CardPart; + RefreshOnActivate = true; + + layout + { + area(Content) + { + field(MatchedPurchaseOrderCount; MatchedPurchaseOrderCount) + { + ApplicationArea = Basic, Suite; + Caption = 'Matched Purchase Orders'; + ToolTip = 'Specifies the number of purchase orders that have matched to a received e-document.'; + + trigger OnDrillDown() + begin + + end; + } + field(WaitingPurchaseOrderCount; WaitingPurchaseOrderCount) + { + ApplicationArea = Basic, Suite; + Caption = 'Waiting Purchase E-Documents'; + ToolTip = 'Specifies the number of received purchase e-documents that needs to be reviewed.'; + + trigger OnDrillDown() + begin + + end; + } + } + } + + var + MatchedPurchaseOrderCount, WaitingPurchaseOrderCount : Integer; + +} diff --git a/Apps/W1/EDocument/app/src/Service/EDocumentService.Table.al b/Apps/W1/EDocument/app/src/Service/EDocumentService.Table.al index 369cab0aed..ad574e700a 100644 --- a/Apps/W1/EDocument/app/src/Service/EDocumentService.Table.al +++ b/Apps/W1/EDocument/app/src/Service/EDocumentService.Table.al @@ -5,6 +5,7 @@ namespace Microsoft.eServices.EDocument; using Microsoft.Finance.GeneralLedger.Journal; +using System.Privacy; table 6103 "E-Document Service" { @@ -33,6 +34,15 @@ table 6103 "E-Document Service" { Caption = 'Service Integration'; DataClassification = SystemMetadata; + + trigger OnValidate() + var + CustConcentMgt: Codeunit "Customer Consent Mgt."; + begin + if (xRec."Service Integration" = xRec."Service Integration"::"No Integration") and (Rec."Service Integration" <> xRec."Service Integration") then + if not CustConcentMgt.ConfirmCustomConsent(ChooseIntegrationConsentTxt) then + Rec."Service Integration" := xRec."Service Integration"; + end; } field(5; "Use Batch Processing"; Boolean) { @@ -228,4 +238,5 @@ table 6103 "E-Document Service" var EDocStringLbl: Label '%1,%2,%3,%4,%5', Locked = true; TemplateTypeErr: Label 'Only General Journal Templates of type %1, %2, %3, %4, or %5 are allowed.', Comment = '%1 - General, %2 - Purchases, %3 - Payments, %4 - Sales, %5 - Cash, %6 - Receipts'; + ChooseIntegrationConsentTxt: Label 'By choosing this option, you consent to use third party systems. These systems may have their own terms of use, license, pricing and privacy, and they may not meet the same compliance and security standards as Microsoft Dynamics 365 Business Central. Your privacy is important to us.'; } diff --git a/Apps/W1/EDocument/app/src/Service/EDocumentServiceStatus.Table.al b/Apps/W1/EDocument/app/src/Service/EDocumentServiceStatus.Table.al index 936ec26646..5780ffb135 100644 --- a/Apps/W1/EDocument/app/src/Service/EDocumentServiceStatus.Table.al +++ b/Apps/W1/EDocument/app/src/Service/EDocumentServiceStatus.Table.al @@ -36,6 +36,9 @@ table 6138 "E-Document Service Status" key(Key2; Status, "E-Document Service Code") { } + key(Key3; "E-Document Entry No", Status) + { + } } internal procedure Logs(): Text diff --git a/Apps/W1/EDocument/app/src/Setup/EDocumentSendingProfile.PageExt.al b/Apps/W1/EDocument/app/src/Setup/EDocumentSendingProfile.PageExt.al index ed2d569c37..bdb7bf27e7 100644 --- a/Apps/W1/EDocument/app/src/Setup/EDocumentSendingProfile.PageExt.al +++ b/Apps/W1/EDocument/app/src/Setup/EDocumentSendingProfile.PageExt.al @@ -33,7 +33,7 @@ pageextension 6101 "E-Document Sending Profile" extends "Document Sending Profil { ApplicationArea = Basic, Suite; Caption = 'Electronic Document Service Flow Code'; - ToolTip = 'Specifies Electronic Service FLow that is used for sending documents.'; + ToolTip = 'Specifies Electronic Service Flow that is used for sending documents.'; trigger OnValidate() var diff --git a/Apps/W1/EDocument/demo data/1.Setup Data/CreateEDocumentSetup.Codeunit.al b/Apps/W1/EDocument/demo data/1.Setup Data/CreateEDocumentSetup.Codeunit.al new file mode 100644 index 0000000000..bc98f2f61a --- /dev/null +++ b/Apps/W1/EDocument/demo data/1.Setup Data/CreateEDocumentSetup.Codeunit.al @@ -0,0 +1,116 @@ +codeunit 5374 "Create E-Document Setup" +{ + InherentEntitlements = X; + InherentPermissions = X; + + trigger OnRun() + begin + CreateEDocService(); + CreateWorkflow(); + CreateDocSendingProfile(); + SetupCompanyInfo(); + end; + + local procedure SetupCompanyInfo() + var + CompanyInfo: Record "Company Information"; + Exists: Boolean; + begin + if CompanyInfo.Get() then + Exists := true; + + if CompanyInfo.Name = '' then + CompanyInfo.Name := 'Contoso Coffee'; + if CompanyInfo.Address = '' then + CompanyInfo.Address := '1234 Main St'; + if CompanyInfo."VAT Registration No." = '' then + CompanyInfo."VAT Registration No." := '77777777'; + + if Exists then + CompanyInfo.Modify() + else + CompanyInfo.Insert(); + end; + + local procedure CreateWorkflow() + var + Workflow: Record Workflow; + WorkflowStepArgument: Record "Workflow Step Argument"; + WorkflowSetup: Codeunit "Workflow Setup"; + WorkflowEventHandling: Codeunit "Workflow Event Handling"; + WorkflowResponseHandling: Codeunit "Workflow Response Handling"; + EntryPointStepId, WorkflowStepId : Integer; + begin + WorkflowEventHandling.CreateEventsLibrary(); + WorkflowResponseHandling.CreateResponsesLibrary(); + + InsertWorkflow(Workflow, EDocumentWorkFlowSingleService(), 'Send E-Documents to one service', EDocCategoryTxt); + EntryPointStepId := WorkflowSetup.InsertEntryPointEventStep(Workflow, EDocCreated()); + WorkflowStepId := WorkflowSetup.InsertResponseStep(Workflow, EDocSendEDocResponseCode(), EntryPointStepId); + WorkflowSetup.InsertStepArgument(WorkflowStepArgument, WorkflowStepId); + + WorkflowStepArgument."E-Document Service" := EDocService(); + WorkflowStepArgument.Modify(); + + Workflow.Enabled := true; + Workflow.Modify(); + end; + + local procedure InsertWorkflow(var Workflow: Record Workflow; WorkflowCode: Code[20]; WorkflowDescription: Text[100]; CategoryCode: Code[20]) + begin + Workflow.Init(); + Workflow.Code := WorkflowCode; + Workflow.Description := WorkflowDescription; + Workflow.Category := CategoryCode; + Workflow.Enabled := false; + if Workflow.Insert() then; + end; + + local procedure CreateEDocService() + var + EDocServiceRec: Record "E-Document Service"; + begin + EDocServiceRec.Init(); + EDocServiceRec.Code := EDocService(); + EDocServiceRec.Description := EDocService(); + EDocServiceRec."Document Format" := EDocServiceRec."Document Format"::"PEPPOL BIS 3.0"; + EDocServiceRec."Service Integration" := EDocServiceRec."Service Integration"::"No Integration"; + if EDocServiceRec.Insert() then; + end; + + local procedure CreateDocSendingProfile() + var + DocumentSendingProfile: Record "Document Sending Profile"; + begin + DocumentSendingProfile.Code := EDocService(); + DocumentSendingProfile.Description := EDocService(); + DocumentSendingProfile."Electronic Document" := Enum::"Doc. Sending Profile Elec.Doc."::"Extended E-Document Service Flow"; + DocumentSendingProfile."Electronic Service Flow" := EDocumentWorkFlowSingleService(); + + if DocumentSendingProfile.Insert() then; + end; + + procedure EDocService(): Code[20] + begin + exit(ServiceCodeLbl); + end; + + procedure EDocCreated(): code[128]; + begin + exit('EDOCCREATEDEVENT') + end; + + procedure EDocSendEDocResponseCode(): Code[128]; + begin + exit('EDOCSendEDOCRESPONSE'); + end; + + procedure EDocumentWorkFlowSingleService(): code[20]; + begin + exit('MS-EDOCTOS-01'); + end; + + var + EDocCategoryTxt: Label 'EDOC', Locked = true; + ServiceCodeLbl: Label 'E-DOCUMENTS'; +} \ No newline at end of file diff --git a/Apps/W1/EDocument/demo data/2.Master Data/CreateEDocumentMasterData.Codeunit.al b/Apps/W1/EDocument/demo data/2.Master Data/CreateEDocumentMasterData.Codeunit.al new file mode 100644 index 0000000000..64a647e37e --- /dev/null +++ b/Apps/W1/EDocument/demo data/2.Master Data/CreateEDocumentMasterData.Codeunit.al @@ -0,0 +1,88 @@ +codeunit 5375 "Create E-Document Master Data" +{ + InherentEntitlements = X; + InherentPermissions = X; + + trigger OnRun() + begin + CreateItems(); + SetVendorsToUseEDocOrder(); + end; + + local procedure SetVendorsToUseEDocOrder() + var + CreateCommonCustomerVendor: Codeunit "Create Common Customer/Vendor"; + begin + UpdateVendor(CreateCommonCustomerVendor.DomesticVendor1()); + UpdateVendor(CreateCommonCustomerVendor.DomesticVendor2()); + UpdateVendor(CreateCommonCustomerVendor.DomesticVendor3()); + end; + + local procedure UpdateVendor(VendorNo: Code[20]) + var + Vendor: Record "Vendor"; + begin + Vendor.Get(VendorNo); + Vendor."Receive E-Document To" := Enum::"E-Document Type"::"Purchase Order"; + Vendor.Modify(); + end; + + local procedure CreateItems() + var + ContosoItem: Codeunit "Contoso Item"; + CommonUoM: Codeunit "Create Common Unit Of Measure"; + begin + ContosoItem.InsertItemCategory(BEANSTok, BeansLbl, ''); + + CreateItem('WRB-1003', 'Whole Roasted Beans, Mexico', 180, CommonUoM.Piece()); + CreateItem('WRB-1004', 'Whole Roasted Beans, Kenya', 180, CommonUoM.Piece()); + CreateItem('WRB-1005', 'Whole Roasted Beans, COSTA RICA', 180, CommonUoM.Piece()); + CreateItem('WRB-1006', 'Whole Roasted Beans, ETHIOPIA', 180, CommonUoM.Piece()); + CreateItem('WRB-1007', 'Whole Roasted Beans, HAWAII', 180, CommonUoM.Piece()); + + CreateItem('WDB-1000', 'Whole Decaf Beans, Colombia', 180, CommonUoM.Piece()); + CreateItem('WDB-1001', 'Whole Decaf Beans, Brazil', 210, CommonUoM.Piece()); + CreateItem('WDB-1002', 'Whole Decaf Beans, Indonesia', 210, CommonUoM.Piece()); + CreateItem('WDB-1003', 'Whole Decaf Beans, Mexico', 210, CommonUoM.Piece()); + CreateItem('WDB-1004', 'Whole Decaf Beans, Kenya', 210, CommonUoM.Piece()); + CreateItem('WDB-1005', 'Whole Decaf Beans, Costa Rica', 210, CommonUoM.Piece()); + CreateItem('WDB-1006', 'Whole Decaf Beans, Ethiopia', 210, CommonUoM.Piece()); + CreateItem('WDB-1007', 'Whole Decaf Beans, Hawaii', 210, CommonUoM.Piece()); + + CreateItem('GRH-1000', 'Precision Grind Home', 199, CommonUoM.Piece()); + CreateItem('GRH-1001', 'Smart Grind Home', 299, CommonUoM.Piece()); + end; + + local procedure CreateItem(ItemNo: Code[20]; Description: Text[100]; UnitPrice: Decimal; BaseUnitOfMeasure: Code[10]) + var + CommonUoM: Codeunit "Create Common Unit Of Measure"; + ContosoItem: Codeunit "Contoso Item"; + CommonPostingGroup: Codeunit "Create Common Posting Group"; + ContosoUnitOfMeasure: Codeunit "Contoso Unit of Measure"; + GenProdPostingGroup, InventoryPostingGroup, TaxGroup : Code[20]; + begin + GenProdPostingGroup := CommonPostingGroup.Retail(); + InventoryPostingGroup := CommonPostingGroup.Resale(); + TaxGroup := CommonPostingGroup.NonTaxable(); + + ContosoItem.InsertInventoryItem(ItemNo, Description, UnitPrice, UnitPrice, GenProdPostingGroup, TaxGroup, InventoryPostingGroup, Enum::"Costing Method"::FIFO, BaseUnitOfMeasure, BEANSTok, '', 1, '', ContosoUtilities.EmptyPicture(), Format(RandBarcodeInt())); + case BaseUnitOfMeasure of + CommonUoM.Box(): + ContosoUnitOfMeasure.InsertItemUnitOfMeasure(ItemNo, BaseUnitOfMeasure, 4, 0, 0, 0, 0); + CommonUoM.Pack(): + ContosoUnitOfMeasure.InsertItemUnitOfMeasure(ItemNo, BaseUnitOfMeasure, 2, 0, 0, 0, 0); + else + ContosoUnitOfMeasure.InsertItemUnitOfMeasure(ItemNo, BaseUnitOfMeasure, 1, 0, 0, 0, 0); + end; + end; + + internal procedure RandBarcodeInt(): Integer + begin + exit(10000000 - 1 + Random(99999999 - 10000000 + 1)); + end; + + var + ContosoUtilities: Codeunit "Contoso Utilities"; + BEANSTok: Label 'BEANS', MaxLength = 10; + BeansLbl: Label 'Beans', MaxLength = 10; +} \ No newline at end of file diff --git a/Apps/W1/EDocument/demo data/3.Transactions/CreateEDocumentTransactions.Codeunit.al b/Apps/W1/EDocument/demo data/3.Transactions/CreateEDocumentTransactions.Codeunit.al new file mode 100644 index 0000000000..cfe0fa7eab --- /dev/null +++ b/Apps/W1/EDocument/demo data/3.Transactions/CreateEDocumentTransactions.Codeunit.al @@ -0,0 +1,161 @@ +codeunit 5376 "Create E-Document Transactions" +{ + InherentEntitlements = X; + InherentPermissions = X; + EventSubscriberInstance = Manual; + + + trigger OnRun() + var + PurchaseOrdersList: List of [Code[20]]; + begin + PurchaseOrdersList := CreatePurchaseOrders(); + CreateEdocs(PurchaseOrdersList); + end; + + internal procedure TryCreatePurchaseOrders() PurchaseOrdersList: List of [Code[20]] + var + PurchaseHeader: Record "Purchase Header"; + EDocumentModuleSetup: Record "E-Document Module Setup"; + ContosoPurchase: Codeunit "Contoso Purchase"; + CommonUoM: Codeunit "Create Common Unit Of Measure"; + begin + if EDocumentModuleSetup.Get() then; + PurchaseHeader := CreateOrder(EDocumentModuleSetup."Vendor No. 1"); + ContosoPurchase.InsertPurchaseLineWithItem(PurchaseHeader, 'WRB-1000', 50, CommonUoM.Piece(), 100); + ContosoPurchase.InsertPurchaseLineWithItem(PurchaseHeader, 'WRB-1001', 50, CommonUoM.Piece(), 100); + ContosoPurchase.InsertPurchaseLineWithItem(PurchaseHeader, 'WRB-1003', 50, CommonUoM.Piece(), 120); + PostPurchaseOrder(PurchaseHeader, PurchaseOrdersList); + + PurchaseHeader := CreateOrder(EDocumentModuleSetup."Vendor No. 1"); + ContosoPurchase.InsertPurchaseLineWithItem(PurchaseHeader, 'WRB-1004', 100, CommonUoM.Piece(), 120); + ContosoPurchase.InsertPurchaseLineWithItem(PurchaseHeader, 'WRB-1005', 100, CommonUoM.Piece(), 120); + ContosoPurchase.InsertPurchaseLineWithItem(PurchaseHeader, 'WRB-1006', 100, CommonUoM.Piece(), 120); + ContosoPurchase.InsertPurchaseLineWithItem(PurchaseHeader, 'WRB-1007', 100, CommonUoM.Piece(), 120); + ContosoPurchase.InsertPurchaseLineWithItem(PurchaseHeader, 'WDB-1000', 50, CommonUoM.Piece(), 113); + ContosoPurchase.InsertPurchaseLineWithItem(PurchaseHeader, 'WDB-1001', 50, CommonUoM.Piece(), 113); + ContosoPurchase.InsertPurchaseLineWithItem(PurchaseHeader, 'GRH-1000', 20, CommonUoM.Piece(), 149); + ContosoPurchase.InsertPurchaseLineWithItem(PurchaseHeader, 'GRH-1001', 10, CommonUoM.Piece(), 219); + PostPurchaseOrder(PurchaseHeader, PurchaseOrdersList); + + PurchaseHeader := CreateOrder(EDocumentModuleSetup."Vendor No. 2"); + ContosoPurchase.InsertPurchaseLineWithItem(PurchaseHeader, 'GRH-1000', 15, CommonUoM.Piece(), 124); + ContosoPurchase.InsertPurchaseLineWithItem(PurchaseHeader, 'GRH-1001', 5, CommonUoM.Piece(), 235); + PostPurchaseOrder(PurchaseHeader, PurchaseOrdersList); + + PurchaseHeader := CreateOrder(EDocumentModuleSetup."Vendor No. 2"); + ContosoPurchase.InsertPurchaseLineWithItem(PurchaseHeader, 'WRB-1001', 150, CommonUoM.Piece(), 125, 20); + ContosoPurchase.InsertPurchaseLineWithItem(PurchaseHeader, 'WDB-1003', 25, CommonUoM.Piece(), 170, 10); + ContosoPurchase.InsertPurchaseLineWithItem(PurchaseHeader, 'WDB-1004', 50, CommonUoM.Piece(), 120); + ContosoPurchase.InsertPurchaseLineWithItem(PurchaseHeader, 'WDB-1005', 50, CommonUoM.Piece(), 140); + ContosoPurchase.InsertPurchaseLineWithItem(PurchaseHeader, 'WDB-1006', 40, CommonUoM.Piece(), 140); + ContosoPurchase.InsertPurchaseLineWithItem(PurchaseHeader, 'WDB-1007', 15, CommonUoM.Piece(), 119); + PostPurchaseOrder(PurchaseHeader, PurchaseOrdersList); + + PurchaseHeader := CreateOrder(EDocumentModuleSetup."Vendor No. 3"); + ContosoPurchase.InsertPurchaseLineWithItem(PurchaseHeader, 'WRB-1004', 60, CommonUoM.Piece(), 110); + ContosoPurchase.InsertPurchaseLineWithItem(PurchaseHeader, 'WRB-1005', 60, CommonUoM.Piece(), 110); + ContosoPurchase.InsertPurchaseLineWithItem(PurchaseHeader, 'WRB-1004', 40, CommonUoM.Piece(), 110); + ContosoPurchase.InsertPurchaseLineWithItem(PurchaseHeader, 'WRB-1005', 40, CommonUoM.Piece(), 110); + PostPurchaseOrder(PurchaseHeader, PurchaseOrdersList); + + PurchaseHeader := CreateOrder(EDocumentModuleSetup."Vendor No. 3"); + ContosoPurchase.InsertPurchaseLineWithItem(PurchaseHeader, 'GRH-1001', 20, CommonUoM.Piece(), 289); + PostPurchaseOrder(PurchaseHeader, PurchaseOrdersList); + end; + + local procedure PostPurchaseOrder(var PurchaseHeader: Record "Purchase Header"; var PurchaseOrdersList: List of [Code[20]]) + var + PurchPostYesNo: Codeunit "Purch.-Post (Yes/No)"; + begin + PurchaseHeader.Receive := true; + PurchaseHeader.Modify(); + PurchPostYesNo.Run(PurchaseHeader); + PurchaseOrdersList.Add(PurchaseHeader."No."); + end; + + local procedure CreatePurchaseOrders() PurchaseOrdersList: List of [Code[20]]; + var + CreateEDocDataEntry: Codeunit "Create E-Document Transactions"; + begin + BindSubscription(CreateEDocDataEntry); + PurchaseOrdersList := CreateEDocDataEntry.TryCreatePurchaseOrders(); + UnbindSubscription(CreateEDocDataEntry); + end; + + local procedure CreateEdocs(PurchaseOrdersList: List of [Code[20]]) + var + Vendor: Record Vendor; + CompanyInfo: Record "Company Information"; + CreateCommonCustomerVendor: Codeunit "Create Common Customer/Vendor"; + begin + if CompanyInfo.Get() then; + Vendor.Get(CreateCommonCustomerVendor.DomesticVendor1()); + + CreateEDocument(StrSubstNo(FK248691XmlTxt, Vendor.Name, CompanyInfo."VAT Registration No.", PurchaseOrdersList.Get(1), CompanyInfo."VAT Registration No.", CompanyInfo.Name, CompanyInfo.Address, CompanyInfo."Post Code")); + CreateEDocument(StrSubstNo(FK246222XmlTxt, Vendor.Name, CompanyInfo."VAT Registration No.", PurchaseOrdersList.Get(2), CompanyInfo."VAT Registration No.", CompanyInfo.Name, CompanyInfo.Address, CompanyInfo."Post Code")); + + Vendor.Get(CreateCommonCustomerVendor.DomesticVendor2()); + CreateEDocument(StrSubstNo(FK246098XmlTxt, Vendor.Name, CompanyInfo."VAT Registration No.", PurchaseOrdersList.Get(3), CompanyInfo."VAT Registration No.", CompanyInfo.Name, CompanyInfo.Address, CompanyInfo."Post Code")); + CreateEDocument(StrSubstNo(FK245260XmlTxt, Vendor.Name, CompanyInfo."VAT Registration No.", PurchaseOrdersList.Get(4), CompanyInfo."VAT Registration No.", CompanyInfo.Name, CompanyInfo.Address, CompanyInfo."Post Code")); + + Vendor.Get(CreateCommonCustomerVendor.DomesticVendor3()); + CreateEDocument(StrSubstNo(FK242896XmlTxt, Vendor.Name, CompanyInfo."VAT Registration No.", PurchaseOrdersList.Get(5), CompanyInfo."VAT Registration No.", CompanyInfo.Name, CompanyInfo.Address, CompanyInfo."Post Code")); + CreateEDocument(StrSubstNo(FK242811XmlTxt, Vendor.Name, CompanyInfo."VAT Registration No.", PurchaseOrdersList.Get(6), CompanyInfo."VAT Registration No.", CompanyInfo.Name, CompanyInfo.Address, CompanyInfo."Post Code")); + end; + + local procedure CreateEDocument(Filetxt: Text) + var + EDocument: Record "E-Document"; + TempBlob: Codeunit "Temp Blob"; + EDocImportHelper: Codeunit "E-Document Import Helper"; + XMLOutStream: OutStream; + begin + EDocImportHelper.SetHideDialogs(true); + TempBlob.CreateOutStream(XMLOutStream); + XMLOutStream.WriteText(StrSubstNo(Filetxt)); + EDocument := CreateEDoc(TempBlob); + EDocImportHelper.ProcessDocument(EDocument, false); + end; + + local procedure CreateEDoc(var TempBlob: Codeunit "Temp Blob"): Record "E-Document"; + var + EDocument: Record "E-Document"; + EDocumentLogRecord: Record "E-Document Log"; + EDocService: Record "E-Document Service"; + CreateEDocumentSetup: Codeunit "Create E-Document Setup"; + EDocumentLog: Codeunit "E-Document Log Helper"; + begin + EDocument.Init(); + EDocument."Entry No" := 0; + EDocument.Status := EDocument.Status::"In Progress"; + EDocument.Direction := EDocument.Direction::Incoming; + EDocument.Insert(); + + EDocService.Get(CreateEDocumentSetup.EDocService()); + EDocumentLogRecord.Get(EDocumentLog.InsertLog(EDocument, EDocService, TempBlob, Enum::"E-Document Service Status"::Imported)); + exit(EDocument); + end; + + local procedure CreateOrder(VendorNo: Code[20]): Record "Purchase Header"; + var + ContosoPurchase: Codeunit "Contoso Purchase"; + begin + exit(ContosoPurchase.InsertPurchaseHeader(Enum::"Purchase Document Type"::Order, VendorNo, '', 20240301D, '')); + end; + + [EventSubscriber(ObjectType::Codeunit, Codeunit::"Purch.-Post (Yes/No)", OnBeforeConfirmPost, '', false, false)] + local procedure OnBeforeConfirmPost(var PurchaseHeader: Record "Purchase Header"; var HideDialog: Boolean; var IsHandled: Boolean; var DefaultOption: Integer) + begin + HideDialog := true; + DefaultOption := 1; + end; + + var + FK248691XmlTxt: Label 'urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0urn:fdc:peppol.eu:2017:poacc:billing:01:1.0FK24-86912024-03-012024-03-01380%3FK24-8691%1%4VAT%2%5%6%7%4%2VAT%5%2%52024-02-25%431159.28637.1159.2825VAT12100121001512500.0001512510000Item202000Colombian Roasted CoffeePH000550695063E0VAT125120000Item202000Rio BR Whole Roasted Beans5555543495471E0VAT125130000Item202000Fortaleza BR Whole Roasted BeansSL425026325609E0VAT125140000Item202400Espresso Roast. Beans, MexicoB2200245669145E0VAT120150000Item101200Mexican Mocha Beans5264091696886E0VAT1201', Locked = true; + FK246222XmlTxt: Label 'urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0urn:fdc:peppol.eu:2017:poacc:billing:01:1.0FK24-62222024-03-012024-03-01380%3FK24-6222%1%4VAT%2%5%6%7%4%2VAT%5%2%52024-02-25%431176.25705176.2525VAT469384693858672.500.00058672.510000Item253000Kenyan Espresso CoffeePH000550695063E0VAT120120000Item253000Mocha Beans from Kenia5555543495471E0VAT120130000Item202400Costa Rica - cafe noirSL425026325609E0VAT120140000Item202400C.Rica Jamocha Rst. BeansB2200117556079E0VAT120150000Item202400Roasted Cafe Costa Rica BeansB2200245669145E0VAT120160000Item506000Ethiop. Whole Roasted Beans5264091696886E0VAT120170000Item607200Roasted Coffee Beans, Hawaii5264091696886E0VAT120180000Item303390Colombian Demitasse5264091696886E0VAT113190000Item202260Colombian Decaf5264091696886E0VAT1131100000Item364068Brazilian Roast Whole Decaf5264091696886E0VAT1131110000Item101490Grind - Brew Like a Pro5264091696886E0VAT1491120000Item101490Coffee Grinder Contoso5264091696886E0VAT1491130000Item51095Smart Metal Grinder Black5264091696886E0VAT2191140000Item51095Super Metal Grinder Red Color5264091696886E0VAT2191', Locked = true; + FK246098XmlTxt: Label 'urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0urn:fdc:peppol.eu:2017:poacc:billing:01:1.0FK24-60982024-03-012024-03-01380%3FK24-6098%1%4VAT%2%5%6%7%4%2VAT%5%2%52024-02-25%431566.752267566.7525VAT171017102137.500.0002137.510000Item3372Precision Home CrusherPH000550695063E0VAT124120000Item3372Home Coffee Mill5555543495471E0VAT124130000Item4496Home Coffee Mincer PurpleSL425026325609E0VAT124140000Item2470LuxuryHome GrinderB2200117556079E0VAT2351', Locked = true; + FK245260XmlTxt: Label 'urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0urn:fdc:peppol.eu:2017:poacc:billing:01:1.0FK24-52602024-03-012024-03-01380%3FK24-5260%1%4VAT%2%5%6%7%4%2VAT%5%2%52024-02-25%4311254.835019.31254.8325VAT302253022537781.2500.00037781.2510000Item252500Fresh Dark Brazilian RoastPH000550695063E0VAT100120000Item252500Whole Bean Coffee - Brazil5555543495471E0VAT100130000Item252500Medium Roast Braz. CoffeeSL425026325609E0VAT100140000Item101530Whole Decaf Beans Tijuana5264091696886E0VAT170150000Item354200100% Decaf Kenya, Whole BeanPH000550695063E0VAT120160000Item202000Rio BR Whole Roasted Beans5555543495471E0VAT125170000Item202800Decaf Costa Rica Whole Bean Coffee Medium RoastSL425026325609E0VAT140180000Item202800Ethiopian Decaf Dark Roast Coffee BagB2200117556079E0VAT140190000Item5595Whole Bean Coffee - Hawaii DecafB2200245669145E0VAT1191', Locked = true; + FK242896XmlTxt: Label 'urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0urn:fdc:peppol.eu:2017:poacc:billing:01:1.0 FK24-2896 2024-03-01 2024-03-01 380 %3 FK24-2896 %1 %4 VAT %2%5%6%7 %4%2 VAT%5%2%5 2024-02-25 %4 31 493.25 1973493.2525 VAT 10450 10450 13062.5 0 0.00 0 13062.5 10000 Item 20 2200 Whole Indonesian Coffee Beans, RoastedPH000550695063E0 VAT 1101 20000 Item 20 2200 Kenyan Organic Whole Roasted Coffee Bean5555543495471E0 VAT 1101 30000 Item 15 1650 Whole Roasted Coffe Beans, Costa RicaSL425026325609E0 VAT 1101 40000 Item 15 2200 Talamanca Origin Coffee Whole BeansB2200117556079E0 VAT 1101 50000 Item 5 550 Organic Decaf Roast Beans - NairobiB2200245669145E0 VAT 1101 60000 Item 5 550 Organic Decaf Roast Beans - Mombasa5264091696886E0 VAT 1101 70000 Item 15 1650 Decaf Roasted Beans - Costa Rica5264091696886E0 VAT 1101 ', Locked = true; + FK242811XmlTxt: Label 'urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0urn:fdc:peppol.eu:2017:poacc:billing:01:1.0FK24-28112024-03-012024-03-01380%3FK24-2811%1%4VAT%2%5%6%7%4%2VAT%5%2%52024-02-25%43159809127.53578025VAT59805780722500.000722510000Item51495Stainless Steel Basic Coffee Bean GrinderPH000550695063E0VAT289120000Item51495Flat Coffee Grinder, Electric5555543495471E0VAT289130000Item51495One-touch Home Coffee GrinderSL425026325609E0VAT289140000Item51495Coffee Grinder- Electric Coffee Mill for EspressoB2200117556079E0VAT2891', Locked = true; +} \ No newline at end of file diff --git a/Apps/W1/EDocument/demo data/EDocumentContosoModule.Codeunit.al b/Apps/W1/EDocument/demo data/EDocumentContosoModule.Codeunit.al new file mode 100644 index 0000000000..75871c32ad --- /dev/null +++ b/Apps/W1/EDocument/demo data/EDocumentContosoModule.Codeunit.al @@ -0,0 +1,40 @@ +codeunit 5373 "E-Document Contoso Module" implements "Contoso Demo Data Module" +{ + + InherentEntitlements = X; + InherentPermissions = X; + + procedure RunConfigurationPage() + begin + Page.Run(Page::"E-Document Module Setup"); + end; + + procedure GetDependencies() Dependencies: List of [enum "Contoso Demo Data Module"] + begin + Dependencies.Add(Enum::"Contoso Demo Data Module"::"Common Module"); + Dependencies.Add(Enum::"Contoso Demo Data Module"::"Warehouse Module"); + end; + + procedure CreateSetupData() + begin + Codeunit.Run(Codeunit::"Create E-Document Setup"); + end; + + procedure CreateMasterData() + var + EDocumentModuleSetup: Record "E-Document Module Setup"; + begin + EDocumentModuleSetup.InitEDocumentModuleSetup(); + Codeunit.Run(Codeunit::"Create E-Document Master Data"); + end; + + procedure CreateTransactionalData() + begin + Codeunit.Run(Codeunit::"Create E-Document Transactions"); + end; + + procedure CreateHistoricalData() + begin + + end; +} \ No newline at end of file diff --git a/Apps/W1/EDocument/demo data/EDocumentContosoModule.EnumExt.al b/Apps/W1/EDocument/demo data/EDocumentContosoModule.EnumExt.al new file mode 100644 index 0000000000..c86ee30820 --- /dev/null +++ b/Apps/W1/EDocument/demo data/EDocumentContosoModule.EnumExt.al @@ -0,0 +1,7 @@ +enumextension 5373 "E-Document Contoso Module" extends "Contoso Demo Data Module" +{ + value(5373; "E-Document Contoso Module") + { + Implementation = "Contoso Demo Data Module" = "E-Document Contoso Module"; + } +} \ No newline at end of file diff --git a/Apps/W1/EDocument/demo data/EDocumentModuleSetup.Page.al b/Apps/W1/EDocument/demo data/EDocumentModuleSetup.Page.al new file mode 100644 index 0000000000..b3b85b9245 --- /dev/null +++ b/Apps/W1/EDocument/demo data/EDocumentModuleSetup.Page.al @@ -0,0 +1,37 @@ +page 5377 "E-Document Module Setup" +{ + PageType = Card; + ApplicationArea = All; + Caption = 'E-Document Module Setup'; + SourceTable = "E-Document Module Setup"; + Extensible = false; + DeleteAllowed = false; + InsertAllowed = false; + + layout + { + area(Content) + { + group("Master Data") + { + field("Vendor No. 1"; Rec."Vendor No. 1") + { + ToolTip = 'Specifies vendor 1 number to use for the scenarios.'; + } + field("Vendor No. 2"; Rec."Vendor No. 2") + { + ToolTip = 'Specifies vendor 2 number to use for the scenarios.'; + } + field("Vendor No. 3"; Rec."Vendor No. 3") + { + ToolTip = 'Specifies vendor 3 number to use for the scenarios.'; + } + } + } + } + + trigger OnOpenPage() + begin + Rec.InitRecord(); + end; +} \ No newline at end of file diff --git a/Apps/W1/EDocument/demo data/EDocumentModuleSetup.Table.al b/Apps/W1/EDocument/demo data/EDocumentModuleSetup.Table.al new file mode 100644 index 0000000000..f2cefffe99 --- /dev/null +++ b/Apps/W1/EDocument/demo data/EDocumentModuleSetup.Table.al @@ -0,0 +1,86 @@ +table 5375 "E-Document Module Setup" +{ + DataClassification = CustomerContent; + InherentEntitlements = RMX; + InherentPermissions = RMX; + Extensible = false; + DataPerCompany = true; + ReplicateData = false; + + fields + { + field(1; "Primary Key"; Code[20]) + { + DataClassification = SystemMetadata; + Caption = 'Primary Key'; + } + field(2; "Vendor No. 1"; Code[20]) + { + Caption = 'Vendor 1 No.'; + TableRelation = Vendor; + } + field(3; "Vendor No. 2"; Code[20]) + { + Caption = 'Vendor 2 No.'; + TableRelation = Vendor; + } + field(4; "Vendor No. 3"; Code[20]) + { + Caption = 'Vendor 3 No.'; + TableRelation = Vendor; + } + } + + keys + { + key(Key1; "Primary Key") + { + Clustered = true; + } + } + + [InherentPermissions(PermissionObjectType::TableData, Database::"E-Document Module Setup", 'I')] + internal procedure InitRecord() + begin + if Rec.Get() then + exit; + + Rec.Init(); + Rec.Insert(); + end; + + procedure InitEDocumentModuleSetup() + var + CreateContosoCustomerVendor: Codeunit "Create Common Customer/Vendor"; + begin + Rec.InitRecord(); + + if Rec."Vendor No. 1" = '' then + if IsDomesticVendor(CreateContosoCustomerVendor.DomesticVendor1()) then + Rec.Validate("Vendor No. 1", CreateContosoCustomerVendor.DomesticVendor1()) + else + Rec.Validate("Vendor No. 1", CreateContosoCustomerVendor.DomesticVendor2()); + if Rec."Vendor No. 2" = '' then + Rec.Validate("Vendor No. 2", CreateContosoCustomerVendor.DomesticVendor2()); + if Rec."Vendor No. 3" = '' then + if IsDomesticVendor(CreateContosoCustomerVendor.DomesticVendor3()) then + Rec.Validate("Vendor No. 3", CreateContosoCustomerVendor.DomesticVendor3()) + else + Rec.Validate("Vendor No. 3", CreateContosoCustomerVendor.DomesticVendor2()); + + Rec.Modify(); + end; + + local procedure IsDomesticVendor(VendorNo: Code[20]): Boolean + var + EnvironmentInformation: Codeunit "Environment Information"; + CreateContosoCustomerVendor: Codeunit "Create Common Customer/Vendor"; + ApplicationFamily: Text; + begin + // Temporary address incorrect local vendors in these countries. + ApplicationFamily := EnvironmentInformation.GetApplicationFamily(); + if ApplicationFamily in ['NL', 'FR', 'BE'] then + if VendorNo = CreateContosoCustomerVendor.DomesticVendor2() then + exit(true); + end; +} \ No newline at end of file diff --git a/Apps/W1/EDocument/demo data/ExtensionLogo.png b/Apps/W1/EDocument/demo data/ExtensionLogo.png new file mode 100644 index 0000000000000000000000000000000000000000..79a3aa399db233b8b47b0fdecdd36a0e1f684835 GIT binary patch literal 5201 zcmcgw=QkS;)E1;h5Iah3HEOS4RBMazGis$`hoVTuuC2D%t2NuAD2{r01rmprBwhG|;uUs{8*1?X|0{ z4&ThVDs;XEHUShAAlCl^@O2^T4+RA~m7%VdRmk(57d>d68IF(jao(}){wxBUgu5{< z_mJrP&+}q(4hs}?0+s)IavS(ypAWCHNi9?=&QvJR&|oHR!kAeM+N0xYE@Xltf)j;c z{_D@fd-ydC*1amfk46N1Ry+9<`fF_jqEFj6Bpb3o+Xw<0W1Pj2+6+1XHWx1X0_Hw5 zd^}eor6@s;T~08uESgT9;r|-4xW7Ep7yfttc5n>UUMhHO@vv_c)$Md29%MZ&p$wvl zkkq4X$*ljrC~K#>oDd*G8+zRd4qqs^n|)meAlVzv-_H#UulvbNY?wHy$71v7Gv0WJ zFEPa=@Gf!ahQI3@pI6;LBRTd6)~%W6#cki;81Y?RxFk8T0oCG4JCo;TrQU-sK)*?Z6nq z!4g)G0-}CS3zo876V?Rq)3ps*H|TACdY|YqP^pVfaO0b5oB1A*=BF;cN>v&S)}=kc zuIp9y&+KNK4bo@>_@hsvCIsf0)%g5AohaM6P_iGel|`3ab)$J?f}T|&<}BLm@V227 z0;@GxtSFWVA8E8ioQ1Nx0zaIb!8bg(8aU{O@V#QKc(QK+1$ zplin@qZvLkI%rPBFMo6EMYQxr7y>>iRSXW(6<@lB42la6F8o7K#>v$7CTsf29Y0pr z9=y9pN#Ay@E$}UY73WLk_hOC`!GDjnRTZ%U$d>|};ps@{4O5XNofmajtoa6wwLlwR zxob@Zk;)8DArla?+{5bgZR-}rR7jpkY&^wsX<&X4Wt4BB*brkcZM8z@$%=?5i~UyA z5O{hSm{yUN>^sioeBb!fF@2}RaTtd*a`i_Pv(G}WbomIb;97piV31#%s_MSkF!(x@ z^Al)H&V$8a-gc2}Kn2UvY=X;!HTJCqO&oHu-0VJOngkz0)suATD%_w2-k>#?Whj{4 zCv>UEh{b97!%M~)SQ$zv+xV;a^CH(wpMasZk$>@+e?G%9e!jwDBa<9+84Q;N1@V(3 z&fyYJh;1G<$z_yAkjaG3`t*_k9Cqj`j0{9$`cF}u;cRrf2{H4I!-Cb%5Qbs3FE*S#%$RuHym_i*QOOVaEV@~YYGkhPEQ7x&cgFJcImgG^6;vvGx+Xn?`ZazmQK70T<2x1+{SfeO2qaY?7Z_@EK4=6>H zzhbtG=@E46W0D?PaP0Qf%UiL64Kk44u0_!;2~iVv3D>;~`{(=th8m(kd$u5T?6!R_ zv(TBiy}2S(Z7PBchsyU1p6MvpHNUBDh66^b)`Q@1eUQB}23iA{7^LBwLaaZsU^o#Z zucK?Qv%#tLilaCE@i_z@pLFpfc|&3c5y9i8I41QoTe$xy-QbaLhye$Ui&*RF{04%j z81EvQ*EwV=fBQRl`8<64B}xyHM8LylxR zUv;Hv*mYPE`!YK$roygB$!U2YT;&Bk=OGrSw&>hXBundgdjI^qU~5)&Nei zH1{uqY@m7VWDzcgtbkHRDccJAtY%9~D!UYo7>RGUG^$7ijQIN{%g-|luu6&GqV zbkvsxvfoVpk{dYe?UIhmPGfzStG(#TlzhqUnb2p8*tzTp0|;+w>b{#keZ)jm& z7`x2t{E;8T$+(;$_4RMJ@O#YLWbxSo*hhC7Mv?m}dKGY6XAoywZOdLcK83`eIS9>= z*-}S)@W^c6k`QxMjK1Kq^DT#ixHzE2eAY$&R*j^t7}$ILwwCeAbVJsvYL2{{$(~vo z{b2&%Z-nhVh!Ajn$f&fQf@;M(xeWw{+_)pCyKq_>>T>4=?c7%Lh;E3H&RN4$tSvw| zhx@$c%6u3#dkAnN!(0Ao>=Mwb5jF2 z{7ch?Z<278YBk9HO*0-L_OT@iyTl;@Y8!17{B!#q>tyLgNiZFQ{q=Th3Xf4A>2g9B-vv}|W;;X6e0GY26j2H12c-0=gX>DR$c`^(tdBV^ z>%4i}g}<^{DUvP9qt}L<_it%LU9YRrVi^fHPv@!i_IY;GS5EIEAmthuR0 z#3l5e1zveDh^72X=z+%kA5NGtK%;lPLhjrPs@)VBVWZ-BVrK1aN*EkYVO)aa;wEXi z&U=bK^YHR#+$5#sU&o~&!V7B+gBg&dRb)j1FjNEOjQe-kYLq?eNg<-j^v z$qSUqa=3-qcVwv`ml{~8n<^8u1V@Oe!+PIRdW@? zp=tegD-dYxqM$uZ-)>d(1joX$`INmu!R+~8VEwyW{_d|Jg&!wi>D2~R7176nR3hFm z6&ge5NMt=tiXcH{S|G;nz(v*3}Pucf%t`5`dQF~qBw_Zu!)OoQOb4@2P7bC^=jFi`QHIPVI>lSP|CnGn~BBRQft(iREOo!3Eb2OX4rx$~Kt zUZ`6#fse{=V^g>8tZ`>4!8>dwCECt|Fp)pd_xw9%xJ;9$Z zhHjrol1WyEaqTi$l&?XxwR2q@v(ve-hAr8lxtpm(&nEmW`yUm300)nonw|VPMGsz z_t<>=7j@U5ce|dKZ=g=;6HU~?JaU4{vQrreRzYtDkuD7@qwhG7Ya=oSwsxfH73%C9F>5T*DRvOiLyH6s{dF@ zxrENI4oQg}#?x5tD|rz{w#rL%K=w33&`I+c{nYp0X1Wj=`k8ZEy>u5wE{6@lBK(V+8l1w!6LY7%3+{m)g8LKu zl^V9-(}=d)G!324nQbzU-dR;-d9nLel<3Cap#juQ3uF0xP7}Mf6$QP-S_6=cy!Mj= zd=>|9_%puGNPMRHl``k`0L2j$fP>R`J9E*22Fo8juf}anz`_=c{@hmy=DSW8zDN2pTXhuZGSX zIyJofIz-BFHDesf!9dWee)D9?D@K^gMm?VgbEGhfqLM%=>%kl>@61m$BD-2XuE#6I zl)Bmfp7%PyG{1ZH>`i!OeqHvi`KJ1ve#$&C&xW-PT2HF>G|Oj@ItzSYc`_%nN7`I0 zcK%^ighHJ0^58#NunFOO->nWGuU(KD+gW=Yvw_MlQn3NPO(#WIxK{*5kAS@;R8Al@uhV4*xN)t zwl7>Ge)A~lQaT6d6=%&dNvSuC#0^CH#a|t3IaLvnA44s8%=AcH#$m%7qDx4p**lqcVk;ym>qW1V~ zUbvWi(9?LoRW9p9iZNkJl;*yaFRI~%F*&WDsoyFbO#w8ft+qMG`pCOJ*6umEO#Rps zfPD#18k=e#rjVFMfeJ&L@$seb?1pZXB;)1Pa~h?+Yn)a~&>rm=%X#p=_WV*kT?VUX z?I_7rdCTb9r)FX$P!tx2f5wh`!*unwO7OOOAC23NkfiKA4%iBHi+fN;x`UaS(rH9a z9{n-OT%nk4DakZFP99Y=e1(;0ZxB=eZ_yF`O>Lf}@%0NjUK`ii`ZcVgEz*MBU^+xn z{cz0x@($2A1@KI-$>FPVVq5V|5Trx&H+R)q>r3<88zVxd(yP%59HadmS7Uv4_PD>@ zc1cCz$&6qAknfHBvh$l$4i&bLKmW~3~fYJ1}kY! z-^w~2)F>U2z_|>?OEN9DTyU+w4Zh{>M0B@y?>15ICV-c-7Cm<4&e)sS8^Q}Z_H8;R zZ4>W(Y8>r<2ipecT4)i@a!*gcQJrJo2-`upwaQWC`}xu?Yhl~{c_qU7lwjY@O;<5T zYdkkXFY3w6%=Ih=5t2ne005w#f?AVt-Eq7Q&HG3H>D zyVq3Hk~_3#hwJVwh`MDyI2%-3T8T|M4ksI>veZi=86#40JdB}(#HruXo-~`;7MI7v)al4|*+O;|A-r~5%plCQK!qaySon+;hZ+ZcLG`uc`CNiq_vbRMzg%W`-J1;^ z55`+(`lYqd{c3n+Idhs{kMom5baZ?4$x)2ba^_S*qbsiA9_g>Qf4W;x0gY9wJ~%K% zG?RWEPh3$(k>H9a4$04Jw;4x;#@o*gqt_Z;Q;iej-?*jv5(i&C_%M)hMYE}CA^RkI zGRwl+MQQZV&HYgXRWEh%()jR|^AYa<1{r%&W*qwSz0Zb-bM7fwq^#`FL4P5H<`e9W4vSW{ zb2#tw!|0~f+S1D_Hp2=u thJgy0w;P0M{+|r5|J7NmQQ5cz+oh)Y#Yu`+U3r8QhA>mzI&Ea^{{VKLuO|Qi literal 0 HcmV?d00001 diff --git a/Apps/W1/EDocument/demo data/app.json b/Apps/W1/EDocument/demo data/app.json new file mode 100644 index 0000000000..bbfb2119ac --- /dev/null +++ b/Apps/W1/EDocument/demo data/app.json @@ -0,0 +1,43 @@ +{ + "id": "de0dddf3-9917-430d-8d20-6e7679a08500", + "name": "E-Document Core Demo Data", + "publisher": "Microsoft", + "brief": "The Dynamics 365 Business Central E-Documents module enables different models of electronic invoicing, available for additional localizations.", + "description": "Business Central's E-Documents module is the foundation layer for all e-invoicing standards covering most common processes, but it can be used for other electronic documents. The module is easily extendable with the country-based e-invoicing apps. The E-Documents app covers both sales and purchase processes and can have different lifecycles from standard invoices in Business Central.", + "version": "25.0.0.0", + "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", + "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", + "help": "https://go.microsoft.com/fwlink/?linkid=2204541", + "url": "https://go.microsoft.com/fwlink/?LinkId=724011", + "logo": "ExtensionLogo.png", + "contextSensitiveHelpUrl": "https://go.microsoft.com/fwlink/?linkid=2206603", + "dependencies": [ + { + "id": "e1d97edc-c239-46b4-8d84-6368bdf67c8b", + "name": "E-Document Core", + "publisher": "Microsoft", + "version": "25.0.0.0" + }, + { + "id": "5a0b41e9-7a42-4123-d521-2265186cfb31", + "name": "Contoso Coffee Demo Dataset", + "publisher": "Microsoft", + "version": "25.0.0.0" + } + ], + "screenshots": [], + "platform": "25.0.0.0", + "idRanges": [ + { + "from": 5370, + "to": 5380 + } + ], + "resourceExposurePolicy": { + "allowDebugging": true, + "allowDownloadingSource": true, + "includeSourceInSymbolFile": true + }, + "application": "25.0.0.0", + "target": "OnPrem" +} \ No newline at end of file diff --git a/Apps/W1/EDocument/test/app.json b/Apps/W1/EDocument/test/app.json index a14984d9de..dcc71192db 100644 --- a/Apps/W1/EDocument/test/app.json +++ b/Apps/W1/EDocument/test/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "E-Document Core Tests", "description": "E-Document Core Tests", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=2204541", @@ -16,31 +16,31 @@ "name": "E-Document Core", "id": "e1d97edc-c239-46b4-8d84-6368bdf67c8b", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "9856ae4f-d1a7-46ef-89bb-6ef056398228", "name": "System Application Test Library", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5095f467-0a01-4b99-99d1-9ff1237d286f", "publisher": "Microsoft", "name": "Library Variable Storage", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 139500, @@ -52,6 +52,6 @@ "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0", + "application": "25.0.0.0", "target": "OnPrem" } \ No newline at end of file diff --git a/Apps/W1/EDocument/test/src/Matching/EDocLineMatchingTest.Codeunit.al b/Apps/W1/EDocument/test/src/Matching/EDocLineMatchingTest.Codeunit.al index 31bb4fa823..a4e802747c 100644 --- a/Apps/W1/EDocument/test/src/Matching/EDocLineMatchingTest.Codeunit.al +++ b/Apps/W1/EDocument/test/src/Matching/EDocLineMatchingTest.Codeunit.al @@ -1,4 +1,4 @@ -codeunit 139658 "E-Doc. Line Matching Test" +codeunit 139659 "E-Doc. Line Matching Test" { Subtype = Test; @@ -10,6 +10,7 @@ codeunit 139658 "E-Doc. Line Matching Test" Assert: Codeunit Assert; LibraryPurchase: Codeunit "Library - Purchase"; + LibraryEdoc: Codeunit "Library - E-Document"; procedure Initialize() var @@ -27,6 +28,9 @@ codeunit 139658 "E-Doc. Line Matching Test" EDocImportedLine: Record "E-Doc. Imported Line"; PurchaseHeader: Record "Purchase Header"; PurchaseLine: Record "Purchase Line"; + EDocService: Record "E-Document Service"; + EDocLineMatching: Codeunit "E-Doc. Line Matching"; + EDocLog: Codeunit "E-Document Log Helper"; EDocOrderLineMatchingPage: TestPage "E-Doc. Order Line Matching"; begin // [FEATURE] [E-Document] [Matching] @@ -38,11 +42,14 @@ codeunit 139658 "E-Doc. Line Matching Test" // [GIVEN] We create e-document and PO line with Qty 5 PurchaseHeader := CreatePurchaseLine(5); CreateEDocumentWithPOReference(PurchaseHeader); + EDocService.Get(LibraryEdoc.CreateService()); + // Receive LibraryPurchase.PostPurchaseDocument(PurchaseHeader, true, false); LibraryPurchase.ReopenPurchaseDocument(PurchaseHeader); EDocument.FindLast(); + EDocLog.InsertLog(EDocument, EDocService, Enum::"E-Document Service Status"::"Order Linked"); // [GIVEN] We imported a item with quantity 5 CreateImportedLine(EDocument, 10000, 5, Enum::"Purchase Line Type"::Item); @@ -51,8 +58,10 @@ codeunit 139658 "E-Doc. Line Matching Test" // [WHEN] Open Matching page and select first entry Commit(); - EDocOrderLineMatchingPage.OpenEdit(); - EDocOrderLineMatchingPage.Last(); + + EDocOrderLineMatchingPage.Trap(); + EDocLineMatching.RunMatching(EDocument); + EDocOrderLineMatchingPage.ImportedLines.First(); EDocOrderLineMatchingPage.OrderLines.First(); diff --git a/Apps/W1/EDocument/test/src/Mock/EDocImplState.Codeunit.al b/Apps/W1/EDocument/test/src/Mock/EDocImplState.Codeunit.al index c9a815975e..8505579323 100644 --- a/Apps/W1/EDocument/test/src/Mock/EDocImplState.Codeunit.al +++ b/Apps/W1/EDocument/test/src/Mock/EDocImplState.Codeunit.al @@ -119,6 +119,7 @@ codeunit 139630 "E-Doc. Impl. State" TmpPurchHeader.CalcFields(Amount, "Amount Including VAT"); EDocument."Amount Excl. VAT" := TmpPurchHeader.Amount; EDocument."Amount Incl. VAT" := TmpPurchHeader."Amount Including VAT"; + EDocument."Order No." := PurchDocTestBuffer.GetEDocOrderNo(); end; end; diff --git a/Apps/W1/EDocument/test/src/Mock/EDocTestBuffer.Codeunit.al b/Apps/W1/EDocument/test/src/Mock/EDocTestBuffer.Codeunit.al index 5817cac279..8c48619b50 100644 --- a/Apps/W1/EDocument/test/src/Mock/EDocTestBuffer.Codeunit.al +++ b/Apps/W1/EDocument/test/src/Mock/EDocTestBuffer.Codeunit.al @@ -5,6 +5,7 @@ codeunit 139625 "E-Doc. Test Buffer" var TmpPurchHeader: Record "Purchase Header" temporary; TmpPurchLine: Record "Purchase Line" temporary; + EDocOrderNo: Code[20]; procedure ClearTempVariables() begin @@ -33,9 +34,19 @@ codeunit 139625 "E-Doc. Test Buffer" until PurchLine.Next() = 0; end; + procedure SetEDocOrderNo(OrderNo: Code[20]) + begin + EDocOrderNo := OrderNo; + end; + procedure GetPurchaseDocToTempVariables(var TmpPurchHeader2: Record "Purchase Header" temporary; var TmpPurchLine2: Record "Purchase Line" temporary) begin TmpPurchHeader2.Copy(TmpPurchHeader, true); TmpPurchLine2.Copy(TmpPurchLine, true); end; + + procedure GetEDocOrderNo(): Code[20] + begin + exit(EDocOrderNo); + end; } \ No newline at end of file diff --git a/Apps/W1/EDocument/test/src/Processing/EDocE2ETest.Codeunit.al b/Apps/W1/EDocument/test/src/Processing/EDocE2ETest.Codeunit.al index cea724a794..c1c818536d 100644 --- a/Apps/W1/EDocument/test/src/Processing/EDocE2ETest.Codeunit.al +++ b/Apps/W1/EDocument/test/src/Processing/EDocE2ETest.Codeunit.al @@ -12,6 +12,7 @@ codeunit 139624 "E-Doc E2E Test" LibraryEDoc: Codeunit "Library - E-Document"; LibraryWorkflow: codeunit "Library - Workflow"; LibraryJobQueue: Codeunit "Library - Job Queue"; + LibraryPurchase: Codeunit "Library - Purchase"; EDocImplState: Codeunit "E-Doc. Impl. State"; IsInitialized: Boolean; IncorrectValueErr: Label 'Incorrect value found'; @@ -19,6 +20,7 @@ codeunit 139624 "E-Doc E2E Test" EDocEmptyErr: Label 'The E-Document table is empty.'; FailedToGetBlobErr: Label 'Failed to get exported blob from EDocument %1', Comment = '%1 - E-Document No.'; SendingErrStateErr: Label 'E-document is Pending response and can not be sent in this state.'; + DeleteNotAllowedErr: Label 'Deletion of Purchase Header linked to E-Document is not allowed.'; [Test] procedure CreateEDocumentBeforeAfterEventsSuccessful() @@ -1373,6 +1375,34 @@ codeunit 139624 "E-Doc E2E Test" Assert.AreEqual(EDocEmptyErr, GetLastErrorText(), IncorrectValueErr); end; + [Test] + procedure DeleteLinkedPurchaseHeaderNoAllowedSuccess() + var + PurchaseHeader: Record "Purchase Header"; + NullGuid: Guid; + begin + // [FEATURE] [E-Document] [Processing] + // [SCENARIO] + Initialize(); + + // [GIVEN] PO with link + LibraryPurchase.CreatePurchHeader(PurchaseHeader, PurchaseHeader."Document Type"::Invoice, LibraryPurchase.CreateVendorNo()); + PurchaseHeader."E-Document Link" := CreateGuid(); + PurchaseHeader.Modify(); + Commit(); + + // [THEN] Fails to delete + asserterror PurchaseHeader.Delete(true); + Assert.ExpectedError(DeleteNotAllowedErr); + + // [GIVEN] Reset link + PurchaseHeader."E-Document Link" := NullGuid; + PurchaseHeader.Modify(); + + // [THEN] Delete ok + PurchaseHeader.Delete(); + end; + [ModalPageHandler] internal procedure EDocServicesPageHandler(var EDocServicesPage: TestPage "E-Document Services") var diff --git a/Apps/W1/EDocument/test/src/Receive/EDocReceiveTest.Codeunit.al b/Apps/W1/EDocument/test/src/Receive/EDocReceiveTest.Codeunit.al index 7c2c2d927c..6d6c2edaae 100644 --- a/Apps/W1/EDocument/test/src/Receive/EDocReceiveTest.Codeunit.al +++ b/Apps/W1/EDocument/test/src/Receive/EDocReceiveTest.Codeunit.al @@ -20,10 +20,12 @@ codeunit 139628 "E-Doc. Receive Test" LibraryPurchase: Codeunit "Library - Purchase"; LibraryInventory: Codeunit "Library - Inventory"; LibraryJournals: Codeunit "Library - Journals"; + LibraryVariableStorage: Codeunit "Library - Variable Storage"; PurchOrderTestBuffer: Codeunit "E-Doc. Test Buffer"; EDocImplState: Codeunit "E-Doc. Impl. State"; Assert: Codeunit Assert; IsInitialized: Boolean; + NullGuid: Guid; GetBasicInfoErr: Label 'Test Get Basic Info From Received Document Error.', Locked = true; GetCompleteInfoErr: Label 'Test Get Complete Info From Received Document Error.', Locked = true; @@ -95,12 +97,349 @@ codeunit 139628 "E-Doc. Receive Test" until CreatedPurchaseLine.Next() = 0; PurchaseHeader.SetHideValidationDialog(true); + PurchaseHeader."E-Document Link" := NullGuid; PurchaseHeader.Delete(true); CreatedPurchaseHeader.SetHideValidationDialog(true); + CreatedPurchaseHeader."E-Document Link" := NullGuid; CreatedPurchaseHeader.Delete(true); end; + [Test] + [HandlerFunctions('SelectPOHandler')] + procedure ReceiveToPurchaseOrderLink() + var + Vendor1: Record Vendor; + EDocService: Record "E-Document Service"; + EDocServiceStatus: Record "E-Document Service Status"; + EDocument: Record "E-Document"; + EDocServicePage: TestPage "E-Document Service"; + OrderNo: Text; + begin + // [FEATURE] [E-Document] [Receive] + // [SCENARIO] Link to existing Purchase Order for vendor + Initialize(); + + // [GIVEN] E-Document service to receive one single purchase invoice + LibraryEDoc.CreateTestReceiveServiceForEDoc(EDocService); + BindSubscription(EDocImplState); + + EDocService."Lookup Account Mapping" := false; + EDocService."Lookup Item GTIN" := false; + EDocService."Lookup Item Reference" := false; + EDocService."Resolve Unit Of Measure" := false; + EDocService."Validate Line Discount" := false; + EDocService."Verify Totals" := false; + EDocService."Use Batch Processing" := false; + EDocService.Modify(); + + // [GIVEN] purchase invoice + LibraryPurchase.CreateVendorWithAddress(Vendor1); + Vendor1."Receive E-Document To" := Vendor1."Receive E-Document To"::"Purchase Order"; + Vendor1.Modify(); + LibraryPurchase.CreatePurchHeader(PurchaseHeader, PurchaseHeader."Document Type"::Order, Vendor1."No."); + LibraryPurchase.CreatePurchaseLine(PurchaseLine, PurchaseHeader, PurchaseLine.Type::Item, LibraryInventory.CreateItemNo(), 10); + PurchaseLine.Validate("Direct Unit Cost", 100); + PurchaseLine.Modify(true); + OrderNo := PurchaseHeader."No."; + LibraryVariableStorage.Enqueue(PurchaseHeader); + + LibraryPurchase.CreatePurchHeader(PurchaseHeader, PurchaseHeader."Document Type"::Invoice, Vendor1."No."); + LibraryPurchase.CreatePurchaseLine(PurchaseLine, PurchaseHeader, PurchaseLine.Type::Item, LibraryInventory.CreateItemNo(), 10); + PurchaseLine.Validate("Direct Unit Cost", 100); + PurchaseLine.Modify(true); + + PurchOrderTestBuffer.ClearTempVariables(); + PurchOrderTestBuffer.AddPurchaseDocToTemp(PurchaseHeader); + + // [WHEN] Running Receive + EDocServicePage.OpenView(); + EDocServicePage.Filter.SetFilter(Code, EDocService.Code); + EDocServicePage.Receive.Invoke(); + + // [THEN] Page to pick Purchase Order appears + // Handler function + + // [THEN] After processing, check fields + EDocument.FindLast(); + PurchaseHeader.SetRange("No.", OrderNo); + PurchaseHeader.SetRange("Document Type", Enum::"Purchase Document Type"::Order); + PurchaseHeader.FindLast(); + EDocServiceStatus.FindLast(); + + Assert.AreEqual(PurchaseHeader."No.", EDocument."Order No.", ''); + Assert.AreEqual(Enum::"E-Document Type"::"Purchase Order", EDocument."Document Type", ''); + Assert.AreEqual(Enum::"E-Document Status"::"In Progress", EDocument.Status, ''); + Assert.AreEqual(PurchaseHeader.RecordId(), EDocument."Document Record ID", ''); + Assert.AreEqual(EDocument.SystemId, PurchaseHeader."E-Document Link", ''); + + Assert.AreEqual(EDocument."Entry No", EDocServiceStatus."E-Document Entry No", ''); + Assert.AreEqual(Enum::"E-Document Service Status"::"Order Linked", EDocServiceStatus.Status, ''); + end; + + [Test] + procedure ReceiveToPurchaseOrderLinkWithOrderNo() + var + EDocService: Record "E-Document Service"; + EDocServiceStatus: Record "E-Document Service Status"; + EDocument: Record "E-Document"; + EDocServicePage: TestPage "E-Document Service"; + OrderNo: Text; + begin + // [FEATURE] [E-Document] [Receive] + // [SCENARIO] Link two invoices to existing Purchase Order for vendor + Initialize(); + + // [GIVEN] E-Document service to receive one single purchase invoice + LibraryEDoc.CreateTestReceiveServiceForEDoc(EDocService); + BindSubscription(EDocImplState); + + EDocService."Lookup Account Mapping" := false; + EDocService."Lookup Item GTIN" := false; + EDocService."Lookup Item Reference" := false; + EDocService."Resolve Unit Of Measure" := false; + EDocService."Validate Line Discount" := false; + EDocService."Verify Totals" := false; + EDocService."Use Batch Processing" := false; + EDocService.Modify(); + + // [GIVEN] purchase invoice + LibraryPurchase.CreateVendorWithAddress(Vendor); + Vendor."Receive E-Document To" := Vendor."Receive E-Document To"::"Purchase Order"; + Vendor.Modify(); + LibraryPurchase.CreatePurchHeader(PurchaseHeader, PurchaseHeader."Document Type"::Order, Vendor."No."); + LibraryPurchase.CreatePurchaseLine(PurchaseLine, PurchaseHeader, PurchaseLine.Type::Item, LibraryInventory.CreateItemNo(), 10); + PurchaseLine.Validate("Direct Unit Cost", 100); + PurchaseLine.Modify(true); + OrderNo := PurchaseHeader."No."; + LibraryVariableStorage.Enqueue(PurchaseHeader); + + LibraryPurchase.CreatePurchHeader(PurchaseHeader, PurchaseHeader."Document Type"::Invoice, Vendor."No."); + LibraryPurchase.CreatePurchaseLine(PurchaseLine, PurchaseHeader, PurchaseLine.Type::Item, LibraryInventory.CreateItemNo(), 10); + PurchaseLine.Validate("Direct Unit Cost", 100); + PurchaseLine.Modify(true); + + PurchOrderTestBuffer.ClearTempVariables(); + PurchOrderTestBuffer.AddPurchaseDocToTemp(PurchaseHeader); + PurchOrderTestBuffer.SetEDocOrderNo(CopyStr(OrderNo, 1, 20)); + + // [WHEN] Running Receive + EDocServicePage.OpenView(); + EDocServicePage.Filter.SetFilter(Code, EDocService.Code); + EDocServicePage.Receive.Invoke(); + + // [THEN] After processing, check fields + EDocument.FindLast(); + PurchaseHeader.SetRange("No.", OrderNo); + PurchaseHeader.SetRange("Document Type", Enum::"Purchase Document Type"::Order); + PurchaseHeader.FindLast(); + EDocServiceStatus.FindLast(); + + Assert.AreEqual(PurchaseHeader."No.", EDocument."Order No.", ''); + Assert.AreEqual(Enum::"E-Document Type"::"Purchase Order", EDocument."Document Type", ''); + Assert.AreEqual(Enum::"E-Document Status"::"In Progress", EDocument.Status, ''); + Assert.AreEqual(PurchaseHeader.RecordId(), EDocument."Document Record ID", ''); + Assert.AreEqual(EDocument.SystemId, PurchaseHeader."E-Document Link", ''); + + Assert.AreEqual(EDocument."Entry No", EDocServiceStatus."E-Document Entry No", ''); + Assert.AreEqual(Enum::"E-Document Service Status"::"Order Linked", EDocServiceStatus.Status, ''); + + // [GIVEN] One more invoice is received to PO + LibraryPurchase.CreatePurchHeader(PurchaseHeader, PurchaseHeader."Document Type"::Invoice, Vendor."No."); + LibraryPurchase.CreatePurchaseLine(PurchaseLine, PurchaseHeader, PurchaseLine.Type::Item, LibraryInventory.CreateItemNo(), 10); + PurchaseLine.Validate("Direct Unit Cost", 100); + PurchaseLine.Modify(true); + + PurchOrderTestBuffer.ClearTempVariables(); + PurchOrderTestBuffer.AddPurchaseDocToTemp(PurchaseHeader); + PurchOrderTestBuffer.SetEDocOrderNo(CopyStr(OrderNo, 1, 20)); + + // [WHEN] Running Receive + EDocServicePage.Receive.Invoke(); + + // [THEN] After processing, check fields + EDocument.FindLast(); + PurchaseHeader.SetRange("No.", OrderNo); + PurchaseHeader.SetRange("Document Type", Enum::"Purchase Document Type"::Order); + PurchaseHeader.FindLast(); + EDocServiceStatus.FindLast(); + + Assert.AreEqual(PurchaseHeader."No.", EDocument."Order No.", ''); + Assert.AreEqual(Enum::"E-Document Type"::"Purchase Order", EDocument."Document Type", ''); + Assert.AreEqual(Enum::"E-Document Status"::"In Progress", EDocument.Status, ''); + Assert.AreEqual(PurchaseHeader.RecordId(), EDocument."Document Record ID", ''); + Assert.AreNotEqual(EDocument.SystemId, PurchaseHeader."E-Document Link", ''); + + Assert.AreEqual(EDocument."Entry No", EDocServiceStatus."E-Document Entry No", ''); + Assert.AreEqual(Enum::"E-Document Service Status"::"Pending", EDocServiceStatus.Status, ''); + end; + + // [Test] + // [HandlerFunctions('MenuHandler')] + // procedure ReceiveToPurchaseOrderAndMatchWithOrder() + // var + // EDocService: Record "E-Document Service"; + // PostedPurchHeader: Record "Purch. Inv. Header"; + // EDocument: Record "E-Document"; + // EDocServiceStatus: Record "E-Document Service Status"; + // PurchaseOrderPage: TestPage "Purchase Order"; + // EDocMatchingPage: TestPage "E-Doc. Order Line Matching"; + // EDocServicePage: TestPage "E-Document Service"; + // EDocumentPage: TestPage "E-Document"; + // OrderNo: Text; + // ItemNo: Code[20]; + // begin + // // [FEATURE] [E-Document] [Receive] + // // [SCENARIO] Receive Invoice to Order, Match it, Post it + // Initialize(); + + // // [GIVEN] E-Document service to receive one single purchase invoice + // LibraryEDoc.CreateTestReceiveServiceForEDoc(EDocService); + // BindSubscription(EDocImplState); + + // EDocService."Lookup Account Mapping" := false; + // EDocService."Lookup Item GTIN" := false; + // EDocService."Lookup Item Reference" := false; + // EDocService."Resolve Unit Of Measure" := false; + // EDocService."Validate Line Discount" := false; + // EDocService."Verify Totals" := false; + // EDocService."Use Batch Processing" := false; + // EDocService.Modify(); + + // // [GIVEN] purchase invoice + // LibraryPurchase.CreateVendorWithAddress(Vendor); + // Vendor."Receive E-Document To" := Vendor."Receive E-Document To"::"Purchase Order"; + // Vendor.Modify(); + // ItemNo := LibraryInventory.CreateItemNo(); + + // LibraryPurchase.CreatePurchHeader(PurchaseHeader, PurchaseHeader."Document Type"::Order, Vendor."No."); + // LibraryPurchase.CreatePurchaseLine(PurchaseLine, PurchaseHeader, PurchaseLine.Type::Item, ItemNo, 10); + // PurchaseLine.Validate("Direct Unit Cost", 100); + // PurchaseLine.Modify(true); + + // LibraryPurchase.PostPurchaseDocument(PurchaseHeader, true, false); + + // OrderNo := PurchaseHeader."No."; + // LibraryVariableStorage.Enqueue(PurchaseHeader); + + // LibraryPurchase.CreatePurchHeader(PurchaseHeader, PurchaseHeader."Document Type"::Invoice, Vendor."No."); + // LibraryPurchase.CreatePurchaseLine(PurchaseLine, PurchaseHeader, PurchaseLine.Type::Item, ItemNo, 10); + // PurchaseLine.Validate("Direct Unit Cost", 200); + // PurchaseLine.Modify(true); + + // PurchOrderTestBuffer.ClearTempVariables(); + // PurchOrderTestBuffer.AddPurchaseDocToTemp(PurchaseHeader); + // PurchOrderTestBuffer.SetEDocOrderNo(CopyStr(OrderNo, 1, 20)); + + // // [WHEN] Running Receive + // EDocServicePage.OpenView(); + // EDocServicePage.Filter.SetFilter(Code, EDocService.Code); + // EDocServicePage.Receive.Invoke(); + // EDocumentPage.OpenView(); + // EDocumentPage.Last(); + // EDocumentPage.EdocoumentServiceStatus.Last(); + // Assert.AreEqual(Format(Enum::"E-Document Service Status"::"Order Linked"), EDocumentPage.EdocoumentServiceStatus.Status.Value(), ''); + + // // [THEN] Run matching page + // EDocMatchingPage.Trap(); + // EDocumentPage.MatchToOrder.Invoke(); + + // // [THEN] Match manually + // EDocMatchingPage.MatchManual.Invoke(); + + // // [THEN] Open Purchase Order Page + // PurchaseOrderPage.Trap(); + // EDocMatchingPage.ApplyToPO.Invoke(); + + // // Check unit cost was updated on purchase line after apply + // PurchaseOrderPage.PurchLines.Last(); + // Assert.AreEqual('200.00', PurchaseOrderPage.PurchLines."Direct Unit Cost".Value(), ''); + + // // [THEN] Post + // PurchaseOrderPage.Post.Invoke(); + // EDocument.FindLast(); + // EDocServiceStatus.FindLast(); + // PostedPurchHeader.FindLast(); + + // // [THEN] Check that we have correct Amount on invoice and that E-Document is updated + // PostedPurchHeader.CalcFields("Amount Including VAT"); + // Assert.AreEqual(EDocument."Document Record ID", PostedPurchHeader.RecordId(), ''); + // Assert.AreEqual(EDocument."Amount Incl. VAT", PostedPurchHeader."Amount Including VAT", ''); + // Assert.AreEqual(Enum::"E-Document Status"::Processed, EDocument.Status, ''); + // Assert.AreEqual(Enum::"E-Document Service Status"::"Imported Document Created", EDocServiceStatus.Status, ''); + // end; + + [Test] + [HandlerFunctions('SelectPOHandlerCancel')] + procedure ReceiveToPurchaseOrderCreated() + var + PurchHeader: Record "Purchase Header"; + EDocService: Record "E-Document Service"; + EDocServiceStatus: Record "E-Document Service Status"; + EDocument: Record "E-Document"; + EDocServicePage: TestPage "E-Document Service"; + OrderNo: Text; + begin + // [FEATURE] [E-Document] [Receive] + // [SCENARIO] Link to Purchase Order where user click cancel to link + Initialize(); + + // [GIVEN] e-Document service to receive one single purchase invoice + LibraryEDoc.CreateTestReceiveServiceForEDoc(EDocService); + BindSubscription(EDocImplState); + + EDocService."Lookup Account Mapping" := false; + EDocService."Lookup Item GTIN" := false; + EDocService."Lookup Item Reference" := false; + EDocService."Resolve Unit Of Measure" := false; + EDocService."Validate Line Discount" := false; + EDocService."Verify Totals" := false; + EDocService."Use Batch Processing" := false; + EDocService.Modify(); + + // [GIVEN] purchase invoice + LibraryPurchase.CreateVendorWithAddress(Vendor); + Vendor."Receive E-Document To" := Vendor."Receive E-Document To"::"Purchase Order"; + Vendor.Modify(); + LibraryPurchase.CreatePurchHeader(PurchHeader, PurchHeader."Document Type"::Order, Vendor."No."); + LibraryPurchase.CreatePurchaseLine(PurchaseLine, PurchHeader, PurchaseLine.Type::Item, LibraryInventory.CreateItemNo(), 10); + PurchaseLine.Validate("Direct Unit Cost", 100); + PurchaseLine.Modify(true); + OrderNo := PurchHeader."No."; + LibraryVariableStorage.Enqueue(PurchHeader); + + LibraryPurchase.CreatePurchHeader(PurchHeader, PurchHeader."Document Type"::Invoice, Vendor."No."); + LibraryPurchase.CreatePurchaseLine(PurchaseLine, PurchHeader, PurchaseLine.Type::Item, LibraryInventory.CreateItemNo(), 10); + PurchaseLine.Validate("Direct Unit Cost", 100); + PurchaseLine.Modify(true); + + PurchOrderTestBuffer.ClearTempVariables(); + PurchOrderTestBuffer.AddPurchaseDocToTemp(PurchHeader); + + // [WHEN] Running Receive + EDocServicePage.OpenView(); + EDocServicePage.Filter.SetFilter(Code, EDocService.Code); + EDocServicePage.Receive.Invoke(); + + // [THEN] Page to pick Purchase Order appears + // Handler functions + + // [THEN] After processing, check fields + EDocument.FindLast(); + PurchHeader.SetRange("Document Type", Enum::"Purchase Document Type"::Order); + PurchHeader.FindLast(); + EDocServiceStatus.FindLast(); + // PurchaseHeader.SetRange("No.", OrderNo); + + Assert.AreEqual(Enum::"E-Document Type"::"Purchase Order", EDocument."Document Type", ''); + Assert.AreEqual(Enum::"E-Document Status"::Processed, EDocument.Status, ''); + Assert.AreEqual(PurchHeader.RecordId(), EDocument."Document Record ID", ''); + Assert.AreEqual(EDocument.SystemId, PurchHeader."E-Document Link", ''); + + Assert.AreEqual(EDocument."Entry No", EDocServiceStatus."E-Document Entry No", ''); + Assert.AreEqual(Enum::"E-Document Service Status"::"Imported Document Created", EDocServiceStatus.Status, ''); + end; + [Test] procedure ReceiveFivePurchaseInvoices() var @@ -181,9 +520,11 @@ codeunit 139628 "E-Doc. Receive Test" until CreatedPurchaseLine.Next() = 0; PurchaseHeader.SetHideValidationDialog(true); + PurchaseHeader."E-Document Link" := NullGuid; PurchaseHeader.Delete(true); CreatedPurchaseHeader.SetHideValidationDialog(true); + CreatedPurchaseHeader."E-Document Link" := NullGuid; CreatedPurchaseHeader.Delete(true); until EDocument.Next() = 0; end; @@ -266,9 +607,11 @@ codeunit 139628 "E-Doc. Receive Test" until CreatedPurchaseLine.Next() = 0; PurchaseHeader.SetHideValidationDialog(true); + PurchaseHeader."E-Document Link" := NullGuid; PurchaseHeader.Delete(true); CreatedPurchaseHeader.SetHideValidationDialog(true); + CreatedPurchaseHeader."E-Document Link" := NullGuid; CreatedPurchaseHeader.Delete(true); end; @@ -362,9 +705,11 @@ codeunit 139628 "E-Doc. Receive Test" until CreatedPurchaseLine.Next() = 0; PurchaseHeader.SetHideValidationDialog(true); + PurchaseHeader."E-Document Link" := NullGuid; PurchaseHeader.Delete(true); CreatedPurchaseHeader.SetHideValidationDialog(true); + CreatedPurchaseHeader."E-Document Link" := NullGuid; CreatedPurchaseHeader.Delete(true); until EDocument.Next() = 0; end; @@ -443,6 +788,7 @@ codeunit 139628 "E-Doc. Receive Test" CheckGenJnlLineIsEqualToPurchaseHeader(PurchaseHeader, GenJnlLine); PurchaseHeader.SetHideValidationDialog(true); + PurchaseHeader."E-Document Link" := NullGuid; PurchaseHeader.Delete(true); GenJnlLine.Delete(true); GenJnlBatch.Delete(true); @@ -524,6 +870,7 @@ codeunit 139628 "E-Doc. Receive Test" CheckGenJnlLineIsEqualToPurchaseHeader(PurchaseHeader, GenJnlLine); PurchaseHeader.SetHideValidationDialog(true); + PurchaseHeader."E-Document Link" := NullGuid; PurchaseHeader.Delete(true); GenJnlLine.Delete(true); @@ -604,6 +951,7 @@ codeunit 139628 "E-Doc. Receive Test" CheckGenJnlLineIsEqualToPurchaseHeader(PurchaseHeader, GenJnlLine); PurchaseHeader.SetHideValidationDialog(true); + PurchaseHeader."E-Document Link" := NullGuid; PurchaseHeader.Delete(true); GenJnlLine.Delete(true); GenJnlBatch.Delete(true); @@ -685,6 +1033,7 @@ codeunit 139628 "E-Doc. Receive Test" CheckGenJnlLineIsEqualToPurchaseHeader(PurchaseHeader, GenJnlLine); PurchaseHeader.SetHideValidationDialog(true); + PurchaseHeader."E-Document Link" := NullGuid; PurchaseHeader.Delete(true); GenJnlLine.Delete(true); @@ -735,6 +1084,7 @@ codeunit 139628 "E-Doc. Receive Test" Assert.AreEqual(GetBasicInfoErr, EDocumentPage.ErrorMessagesPart.Description.Value(), ''); PurchaseHeader.SetHideValidationDialog(true); + PurchaseHeader."E-Document Link" := NullGuid; PurchaseHeader.Delete(true); end; @@ -782,9 +1132,32 @@ codeunit 139628 "E-Doc. Receive Test" Assert.AreEqual(GetCompleteInfoErr, EDocumentPage.ErrorMessagesPart.Description.Value(), ''); PurchaseHeader.SetHideValidationDialog(true); + PurchaseHeader."E-Document Link" := NullGuid; PurchaseHeader.Delete(true); end; + [ModalPageHandler] + procedure SelectPOHandler(var POList: TestPage "Purchase Order List") + var + Variant: Variant; + begin + LibraryVariableStorage.Dequeue(Variant); + POList.GoToRecord(Variant); + POList.OK().Invoke(); + end; + + [ModalPageHandler] + procedure SelectPOHandlerCancel(var POList: TestPage "Purchase Order List") + begin + POList.Cancel().Invoke(); + end; + + + [ConfirmHandler] + procedure ConfirmHandlerYes(Message: Text[1024]; var Reply: Boolean) + begin + Reply := true; + end; [ConfirmHandler] procedure ConfirmHandler(Message: Text[1024]; var Reply: Boolean) @@ -792,9 +1165,17 @@ codeunit 139628 "E-Doc. Receive Test" Reply := false; end; + [StrMenuHandler] + procedure MenuHandler(Options: Text[1024]; var Choice: Integer; Instruction: Text[1024]) + begin + end; + local procedure Initialize() begin Clear(EDocImplState); + Clear(PurchaseHeader); + Clear(LibraryVariableStorage); + PurchaseHeader.DeleteAll(); end; local procedure CheckPurchaseHeadersAreEqual(var PurchHeader1: Record "Purchase Header"; var PurchHeader2: Record "Purchase Header") diff --git a/Apps/W1/EDocumentsConnector/app/app.json b/Apps/W1/EDocumentsConnector/app/app.json index a764285a19..193d264aab 100644 --- a/Apps/W1/EDocumentsConnector/app/app.json +++ b/Apps/W1/EDocumentsConnector/app/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "This app extends Microsoft standard E-documents framework, offering connectors to 3rd party access-points providers.", "description": "This app extends Microsoft standard E-documents framework, offering connectors to 3rd party access-points providers.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": " https://learn.microsoft.com/en-us/dynamics365/business-central/finance-edocuments-overview", @@ -12,17 +12,17 @@ "logo": "ExtensionLogo.png", "contextSensitiveHelpUrl": "https://go.microsoft.com/fwlink/?linkid=2206603", "dependencies": [ - { - "id": "e1d97edc-c239-46b4-8d84-6368bdf67c8b", - "name": "E-Document Core", - "publisher": "Microsoft", - "version": "24.0.0.0" - } + { + "id": "e1d97edc-c239-46b4-8d84-6368bdf67c8b", + "name": "E-Document Core", + "publisher": "Microsoft", + "version": "25.0.0.0" + } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 6360, @@ -34,6 +34,6 @@ "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0", + "application": "25.0.0.0", "target": "OnPrem" - } \ No newline at end of file +} \ No newline at end of file diff --git a/Apps/W1/EDocumentsConnector/app/src/E3Party/EDocExtEDocument.PageExt.al b/Apps/W1/EDocumentsConnector/app/src/E3Party/EDocExtEDocument.PageExt.al index b1a1e3e510..a26918dfa3 100644 --- a/Apps/W1/EDocumentsConnector/app/src/E3Party/EDocExtEDocument.PageExt.al +++ b/Apps/W1/EDocumentsConnector/app/src/E3Party/EDocExtEDocument.PageExt.al @@ -18,7 +18,7 @@ pageextension 6360 "E-Doc. Ext. EDocument" extends "E-Document" ToolTip = 'Approve related document.'; Image = Approve; ApplicationArea = All; - Visible = Rec.Direction = Rec.Direction::Incoming; + Visible = ApprovalActionVisible; trigger OnAction() var @@ -33,7 +33,7 @@ pageextension 6360 "E-Doc. Ext. EDocument" extends "E-Document" ToolTip = 'Reject related document.'; Image = Reject; ApplicationArea = All; - Visible = Rec.Direction = Rec.Direction::Incoming; + Visible = ApprovalActionVisible; trigger OnAction() var @@ -49,4 +49,17 @@ pageextension 6360 "E-Doc. Ext. EDocument" extends "E-Document" actionref(Reject_Promoted; Reject) { } } } + + trigger OnAfterGetRecord() + var + EDocumentService: Record "E-Document Service"; + EDocumentHelper: Codeunit "E-Document Helper"; + begin + EDocumentHelper.GetEdocumentService(Rec, EdocumentService); + ApprovalActionVisible := + (EDocumentService."Service Integration" = EDocumentService."Service Integration"::Pagero) and (Rec.Direction = Rec.Direction::Incoming); + end; + + var + ApprovalActionVisible: Boolean; } \ No newline at end of file diff --git a/Apps/W1/EDocumentsConnector/app/src/Pagero/PageroAuth.Codeunit.al b/Apps/W1/EDocumentsConnector/app/src/Pagero/PageroAuth.Codeunit.al index 03811f62cf..7ef7e6b231 100644 --- a/Apps/W1/EDocumentsConnector/app/src/Pagero/PageroAuth.Codeunit.al +++ b/Apps/W1/EDocumentsConnector/app/src/Pagero/PageroAuth.Codeunit.al @@ -39,13 +39,11 @@ codeunit 6364 "Pagero Auth." SetIsolatedStorageValue(ClienId, ClientID, DataScope::Company); end; - [NonDebuggable] - procedure SetClientSecret(var ClienSecret: Guid; ClientSecret: Text) + procedure SetClientSecret(var ClienSecret: Guid; ClientSecret: SecretText) begin SetIsolatedStorageValue(ClienSecret, ClientSecret, DataScope::Company); end; - [NonDebuggable] procedure IsClientCredsSet(var ClientId: Text; var ClientSecret: Text): Boolean var EDocExtConnectionSetup: Record "E-Doc. Ext. Connection Setup"; @@ -70,7 +68,6 @@ codeunit 6364 "Pagero Auth." Page.RunModal(Page::"OAuth 2.0 Setup", OAuth20Setup); end; - [NonDebuggable] procedure GetAuthBearerTxt(): SecretText; var OAuth20Setup: Record "OAuth 2.0 Setup"; @@ -81,7 +78,7 @@ codeunit 6364 "Pagero Auth." if not RefreshAccessToken(HttpError) then Error(HttpError); - exit(StrSubstNo(BearerTxt, GetToken(OAuth20Setup."Access Token", OAuth20Setup.GetTokenDataScope()))); + exit(SecretStrSubstNo(BearerTxt, GetToken(OAuth20Setup."Access Token", OAuth20Setup.GetTokenDataScope()))); end; [NonDebuggable] @@ -149,8 +146,7 @@ codeunit 6364 "Pagero Auth." OAuth20Setup.TestField("Daily Limit"); end; - [NonDebuggable] - local procedure SaveTokens(var OAuth20Setup: Record "OAuth 2.0 Setup"; TokenDataScope: DataScope; AccessToken: Text; RefreshToken: Text) + local procedure SaveTokens(var OAuth20Setup: Record "OAuth 2.0 Setup"; TokenDataScope: DataScope; AccessToken: SecretText; RefreshToken: SecretText) begin SetIsolatedStorageValue(OAuth20Setup."Access Token", AccessToken, TokenDataScope); SetIsolatedStorageValue(OAuth20Setup."Refresh Token", RefreshToken, TokenDataScope); @@ -158,8 +154,7 @@ codeunit 6364 "Pagero Auth." OAuth20Setup.Modify(); end; - [NonDebuggable] - local procedure SetIsolatedStorageValue(var ValueKey: Guid; Value: Text; TokenDataScope: DataScope) NewToken: Boolean + local procedure SetIsolatedStorageValue(var ValueKey: Guid; Value: SecretText; TokenDataScope: DataScope) NewToken: Boolean begin if IsNullGuid(ValueKey) then NewToken := true; @@ -169,13 +164,12 @@ codeunit 6364 "Pagero Auth." IsolatedStorage.Set(ValueKey, Value, TokenDataScope); end; - [NonDebuggable] - local procedure GetToken(TokenKey: Text; TokenDataScope: DataScope) TokenValue: Text + local procedure GetToken(TokenKey: Text; TokenDataScope: DataScope) TokenValueAsSecret: SecretText begin if not HasToken(TokenKey, TokenDataScope) then - exit(''); + exit(TokenValueAsSecret); - IsolatedStorage.Get(TokenKey, TokenDataScope, TokenValue); + IsolatedStorage.Get(TokenKey, TokenDataScope, TokenValueAsSecret); end; [NonDebuggable] @@ -204,15 +198,14 @@ codeunit 6364 "Pagero Auth." end; if EDocExtConnectionSetup.Get() then - exit(GetToken(EDocExtConnectionSetup."Client ID", DataScope::Company)); + exit(GetToken(EDocExtConnectionSetup."Client ID", DataScope::Company).Unwrap()); end; - [NonDebuggable] - local procedure GetClientSecret(): Text + local procedure GetClientSecret(): SecretText var EDocExtConnectionSetup: Record "E-Doc. Ext. Connection Setup"; AzureKeyVault: Codeunit "Azure Key Vault"; - Secret: Text; + Secret: SecretText; begin if EnvironmentInfo.IsSaaS() then begin AzureKeyVault.GetAzureKeyVaultSecret('pagero-client-secret', Secret); @@ -229,8 +222,9 @@ codeunit 6364 "Pagero Auth." var EDocExtConnectionSetup: Record "E-Doc. Ext. Connection Setup"; RequestJSON: Text; - AccessToken: Text; - RefreshToken: Text; + AccessToken: SecretText; + RefreshToken: SecretText; + AuthorizationCodeSecret: SecretText; TokenDataScope: DataScope; begin if not EDocExtConnectionSetup.Get() then @@ -240,7 +234,8 @@ codeunit 6364 "Pagero Auth." CheckOAuthConsistencySetup(OAuth20Setup); TokenDataScope := OAuth20Setup.GetTokenDataScope(); - Result := OAuth20Mgt.RequestAccessTokenWithContentType(OAuth20Setup, RequestJSON, MessageText, AuthorizationCode, GetClientId(), GetClientSecret(), AccessToken, RefreshToken, true); + AuthorizationCodeSecret := AuthorizationCode; + Result := OAuth20Mgt.RequestAccessTokenWithContentType(OAuth20Setup, RequestJSON, MessageText, AuthorizationCodeSecret, GetClientId(), GetClientSecret(), AccessToken, RefreshToken, true); if not Result then Error(AuthenticationFailedErr); @@ -255,8 +250,8 @@ codeunit 6364 "Pagero Auth." var EDocExtConnectionSetup: Record "E-Doc. Ext. Connection Setup"; RequestJSON: Text; - AccessToken: Text; - RefreshToken: Text; + AccessToken: SecretText; + RefreshToken: SecretText; TokenDataScope: DataScope; OldServiceUrl: Text[250]; begin @@ -283,8 +278,8 @@ codeunit 6364 "Pagero Auth." SaveTokens(OAuth20Setup, TokenDataScope, AccessToken, RefreshToken); end; - [NonDebuggable] [EventSubscriber(ObjectType::Table, Database::"OAuth 2.0 Setup", 'OnBeforeRequestAuthoizationCode', '', true, true)] + [NonDebuggable] local procedure OnBeforeRequestAuthoizationCode(OAuth20Setup: Record "OAuth 2.0 Setup"; var Processed: Boolean) var EDocExtConnectionSetup: Record "E-Doc. Ext. Connection Setup"; @@ -292,7 +287,7 @@ codeunit 6364 "Pagero Auth." OAuth2ControlAddIn: Page OAuth2ControlAddIn; auth_error: Text; AuthorizationCode: Text; - url: Text; + url: SecretText; state: Text; begin if not EDocExtConnectionSetup.Get() or Processed then @@ -304,9 +299,9 @@ codeunit 6364 "Pagero Auth." exit; state := Format(CreateGuid(), 0, 4); - url := StrSubstNo(CurrUrlWithStateTxt, OAuth20Mgt.GetAuthorizationURL(OAuth20Setup, GetClientId()), state); + url := SecretStrSubstNo(CurrUrlWithStateTxt, OAuth20Mgt.GetAuthorizationURLAsSecretText(OAuth20Setup, GetClientId()), state); - OAuth2ControlAddIn.SetOAuth2Properties(url, state); + OAuth2ControlAddIn.SetOAuth2Properties(url.Unwrap(), state); OAuth2ControlAddIn.RunModal(); auth_error := OAuth2ControlAddIn.GetAuthError(); if auth_error <> '' then @@ -325,7 +320,7 @@ codeunit 6364 "Pagero Auth." local procedure OnBeforeInvokeRequest(var OAuth20Setup: Record "OAuth 2.0 Setup"; RequestJSON: Text; var ResponseJSON: Text; var HttpError: Text; var Result: Boolean; var Processed: Boolean; RetryOnCredentialsFailure: Boolean) var PageroSetup: Record "E-Doc. Ext. Connection Setup"; - TokenValue: Text; + TokenValue: SecretText; RequestJsonObj: JsonObject; ResponseJsonObj: JsonObject; begin @@ -334,7 +329,7 @@ codeunit 6364 "Pagero Auth." Processed := true; CheckOAuthConsistencySetup(OAuth20Setup); - TokenValue := GetToken(OAuth20Setup."Access Token", OAuth20Setup.GetTokenDataScope()); + TokenValue := GetToken(OAuth20Setup."Access Token", OAuth20Setup.GetTokenDataScope()).Unwrap(); Result := OAuth20Mgt.InvokeRequest(OAuth20Setup, RequestJSON, ResponseJSON, HttpError, TokenValue, RetryOnCredentialsFailure); diff --git a/Apps/W1/EU3PartyTradePurchase/app/app.json b/Apps/W1/EU3PartyTradePurchase/app/app.json index b365c3a45d..e2b6bf3d63 100644 --- a/Apps/W1/EU3PartyTradePurchase/app/app.json +++ b/Apps/W1/EU3PartyTradePurchase/app/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "The app is used to provide support for the EU 3-Party trade purchase transactions.", "description": "When receiving a purchase invoice from a customer in one EU country/region and the products are sent to a different EU country/region without entering country/region, then that transaction amount can be identified and reported separately.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=2235119", @@ -21,7 +21,7 @@ "publisher": "Microsoft" } ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 4880, @@ -33,6 +33,6 @@ "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0", + "application": "25.0.0.0", "target": "Cloud" } \ No newline at end of file diff --git a/Apps/W1/EU3PartyTradePurchase/test/app.json b/Apps/W1/EU3PartyTradePurchase/test/app.json index 8eb476f1be..89cc96441a 100644 --- a/Apps/W1/EU3PartyTradePurchase/test/app.json +++ b/Apps/W1/EU3PartyTradePurchase/test/app.json @@ -2,7 +2,7 @@ "id": "3df4eddc-d735-46f7-9645-3c027296d54f", "name": "EU 3-Party Trade Purchase Tests", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Tests for the Microsoft EU 3-Party Trade Purchase extension.", "description": "Tests for the Microsoft EU 3-Party Trade Purchase extension.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -10,32 +10,32 @@ "help": "https://go.microsoft.com/fwlink/?linkid=2179727", "url": "https://go.microsoft.com/fwlink/?LinkId=724011", "logo": "ExtensionLogo.png", - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "dependencies": [ { "id": "0a9a9ce1-6f98-4cf0-82e2-0b3e7cabb32a", "name": "EU 3-Party Trade Purchase", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "9856ae4f-d1a7-46ef-89bb-6ef056398228", "name": "System Application Test Library", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5095f467-0a01-4b99-99d1-9ff1237d286f", "publisher": "Microsoft", "name": "Library Variable Storage", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "idRanges": [ diff --git a/Apps/W1/Email - Current User Connector/app/app.json b/Apps/W1/Email - Current User Connector/app/app.json index fd743bc6ed..fafc7155db 100644 --- a/Apps/W1/Email - Current User Connector/app/app.json +++ b/Apps/W1/Email - Current User Connector/app/app.json @@ -2,7 +2,7 @@ "id": "08d69832-9231-429e-be2c-8bab2c96905b", "name": "Email - Current User Connector", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Enable users to use their own Microsoft 365 email account to send email in Business Central.", "description": "This connector enables users to send email from their own email account. After you set up this connector, it will automatically find the email accounts specified for each user. You only need to set up this connector one time.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -15,13 +15,13 @@ "id": "63ca2fa4-4f03-4f2b-a480-172fef340d3f", "publisher": "Microsoft", "name": "System Application", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "e6328152-bb29-4664-9dae-3bc7eaae1fd8", "name": "Email - Outlook REST API", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "internalsVisibleTo": [ @@ -34,7 +34,7 @@ "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 2, diff --git a/Apps/W1/Email - Current User Connector/app/src/CurrentUserConnector.Codeunit.al b/Apps/W1/Email - Current User Connector/app/src/CurrentUserConnector.Codeunit.al index 378d95a8cb..b19576039f 100644 --- a/Apps/W1/Email - Current User Connector/app/src/CurrentUserConnector.Codeunit.al +++ b/Apps/W1/Email - Current User Connector/app/src/CurrentUserConnector.Codeunit.al @@ -70,13 +70,11 @@ codeunit 4500 "Current User Connector" implements "Email Connector", "Default Em User: Record User; EmailOutlookAPIHelper: Codeunit "Email - Outlook API Helper"; EnvironmentInformation: Codeunit "Environment Information"; - APIClient: interface "Email - Outlook API Client"; - OAuthClient: interface "Email - OAuth Client"; + APIClient: interface "Email - Outlook API Client v2"; + OAuthClient: interface "Email - OAuth Client v2"; CurrentUserName: Text[250]; CurrentUserEmail: Text[250]; - - [NonDebuggable] - AccessToken: Text; + AccessToken: SecretText; begin if EnvironmentInformation.IsSaaS() then begin if not User.Get(UserSecurityId()) then diff --git a/Apps/W1/Email - Current User Connector/test/app.json b/Apps/W1/Email - Current User Connector/test/app.json index d346e21f88..0f83512dc8 100644 --- a/Apps/W1/Email - Current User Connector/test/app.json +++ b/Apps/W1/Email - Current User Connector/test/app.json @@ -2,7 +2,7 @@ "id": "ac0b4daa-f46f-42ef-9468-6b623298e36b", "name": "Email - Current User Connector Tests", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Tests for Current User Connector", "description": "Tests for Current User Connector", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -15,49 +15,49 @@ "id": "63ca2fa4-4f03-4f2b-a480-172fef340d3f", "publisher": "Microsoft", "name": "System Application", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "9856ae4f-d1a7-46ef-89bb-6ef056398228", "publisher": "Microsoft", "name": "System Application Test Library", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "e6328152-bb29-4664-9dae-3bc7eaae1fd8", "name": "Email - Outlook REST API", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "e7320ebb-08b3-4406-b1ec-b4927d3e280b", "name": "Any", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "dd0be2ea-f733-4d65-bb34-a28f4624fb14", "name": "Library Assert", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "b5034210-b258-4983-8858-f5cbfd54cb35", "name": "Library Outlook REST API", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "08d69832-9231-429e-be2c-8bab2c96905b", "name": "Email - Current User Connector", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 139750, diff --git a/Apps/W1/Email - Microsoft 365 Connector/app/app.json b/Apps/W1/Email - Microsoft 365 Connector/app/app.json index 5883cc752c..99c8028397 100644 --- a/Apps/W1/Email - Microsoft 365 Connector/app/app.json +++ b/Apps/W1/Email - Microsoft 365 Connector/app/app.json @@ -2,7 +2,7 @@ "id": "aceb66c8-472e-437c-81d3-27e6c07d0f14", "name": "Email - Microsoft 365 Connector", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Enable all users to use a single Microsoft 365 email account to send email in Business Central.", "description": "This connector enables all users to send email from the same email account in Business Central.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -15,13 +15,13 @@ "id": "63ca2fa4-4f03-4f2b-a480-172fef340d3f", "publisher": "Microsoft", "name": "System Application", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "e6328152-bb29-4664-9dae-3bc7eaae1fd8", "name": "Email - Outlook REST API", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "internalsVisibleTo": [ @@ -34,7 +34,7 @@ "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 1, diff --git a/Apps/W1/Email - Microsoft 365 Connector/test/app.json b/Apps/W1/Email - Microsoft 365 Connector/test/app.json index 567566780b..6f70bcb4d0 100644 --- a/Apps/W1/Email - Microsoft 365 Connector/test/app.json +++ b/Apps/W1/Email - Microsoft 365 Connector/test/app.json @@ -2,7 +2,7 @@ "id": "c436fd91-e29f-406c-b91f-33cd176ca9be", "name": "Email - Microsoft 365 Connector Tests", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Tests for Microsoft 365 Connector", "description": "Tests for Microsoft 365 Connector", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -15,43 +15,43 @@ "id": "63ca2fa4-4f03-4f2b-a480-172fef340d3f", "publisher": "Microsoft", "name": "System Application", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "e6328152-bb29-4664-9dae-3bc7eaae1fd8", "name": "Email - Outlook REST API", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "aceb66c8-472e-437c-81d3-27e6c07d0f14", "name": "Email - Microsoft 365 Connector", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "dd0be2ea-f733-4d65-bb34-a28f4624fb14", "name": "Library Assert", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "b5034210-b258-4983-8858-f5cbfd54cb35", "name": "Library Outlook REST API", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "e7320ebb-08b3-4406-b1ec-b4927d3e280b", "name": "Any", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 135144, diff --git a/Apps/W1/Email - Outlook REST API/app/app.json b/Apps/W1/Email - Outlook REST API/app/app.json index b30bfc65f6..77e4b554de 100644 --- a/Apps/W1/Email - Outlook REST API/app/app.json +++ b/Apps/W1/Email - Outlook REST API/app/app.json @@ -2,7 +2,7 @@ "id": "e6328152-bb29-4664-9dae-3bc7eaae1fd8", "name": "Email - Outlook REST API", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Provides a library that enables email connectors to communicate with the Outlook and Graph APIs.", "description": "This extension provides a library that enables email connectors to communicate with the Outlook and Graph APIs to retrieve user information and send email messages.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -15,7 +15,7 @@ "id": "63ca2fa4-4f03-4f2b-a480-172fef340d3f", "publisher": "Microsoft", "name": "System Application", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "internalsVisibleTo": [ @@ -28,8 +28,8 @@ "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 4506, 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 bdb5cf3d79..68e5f36796 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 @@ -10,28 +10,71 @@ using System.Security.Authentication; using System.Azure.Identity; using System.Utilities; -codeunit 4507 "Email - OAuth Client" implements "Email - OAuth Client" +#if not CLEAN24 +#pragma warning disable AL0432 +codeunit 4507 "Email - OAuth Client" implements "Email - OAuth Client", "Email - OAuth Client v2" +#pragma warning restore AL0432 +#else +codeunit 4507 "Email - OAuth Client" implements "Email - OAuth Client v2" +#endif { +#if not CLEAN24 /// /// Retrieves the Access token for the current user to connect to Outlook API /// /// Out parameter with the Access token of the account [NonDebuggable] + [Obsolete('Replaced by GetAccessToken with SecretText data type for AccessToken parameter.', '24.0')] procedure GetAccessToken(var AccessToken: Text) begin +#pragma warning disable AL0432 TryGetAccessTokenInternal(AccessToken); +#pragma warning restore AL0432 end; [NonDebuggable] + [Obsolete('Replaced by GetAccessToken with SecretText data type for AccessToken parameter.', '24.0')] + procedure TryGetAccessToken(var AccessToken: Text): Boolean begin exit(TryGetAccessTokenInternal(AccessToken)); end; +#endif + + /// + /// Retrieves the Access token for the current user to connect to Outlook API + /// + /// Out parameter with the Access token of the account + [NonDebuggable] + procedure GetAccessToken(var AccessToken: SecretText) + begin + TryGetAccessTokenInternal(AccessToken); + end; + + [NonDebuggable] + procedure TryGetAccessToken(var AccessToken: SecretText): Boolean + begin + exit(TryGetAccessTokenInternal(AccessToken)); + 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) + var + Token: SecretText; + begin + TryGetAccessTokenInternal(Token); + if not Token.IsEmpty() then + AccessToken := Token.Unwrap(); + end; +#endif + + // Interfaces do not support properties for the procedures, so using an internal function + [TryFunction] + [NonDebuggable] + local procedure TryGetAccessTokenInternal(var AccessToken: SecretText) var AzureAdMgt: Codeunit "Azure AD Mgt."; UrlHelper: Codeunit "Url Helper"; @@ -43,15 +86,15 @@ codeunit 4507 "Email - OAuth Client" implements "Email - OAuth Client" ClearLastError(); if EnvironmentInformation.IsSaaSInfrastructure() then begin AccessToken := AzureAdMgt.GetAccessToken(UrlHelper.GetGraphUrl(), '', false); - if AccessToken = '' then begin + if AccessToken.IsEmpty() then begin Session.LogMessage('000040Z', CouldNotAcquireAccessTokenErr, Verbosity::Error, DataClassification::SystemMetadata, TelemetryScope::ExtensionPublisher, 'Category', EmailCategoryLbl); if OAuth2.AcquireOnBehalfOfToken('', Scopes, AccessToken) then; end; end else - if (not OAuth2.AcquireAuthorizationCodeTokenFromCache(ClientId, ClientSecret, RedirectURL, GetOAuthAuthorityUrl(), Scopes, AccessToken)) or (AccessToken = '') then + if (not OAuth2.AcquireAuthorizationCodeTokenFromCache(ClientId, ClientSecret, RedirectURL, GetOAuthAuthorityUrl(), Scopes, AccessToken)) or AccessToken.IsEmpty() then OAuth2.AcquireTokenByAuthorizationCode(ClientId, ClientSecret, GetOAuthAuthorityUrl(), RedirectURL, Scopes, Enum::"Prompt Interaction"::None, AccessToken, OAuthErr); - if AccessToken = '' then begin + if AccessToken.IsEmpty() then begin if AzureADMgt.GetLastErrorMessage() <> '' then Error(AzureADMgt.GetLastErrorMessage()); @@ -85,21 +128,19 @@ codeunit 4507 "Email - OAuth Client" implements "Email - OAuth Client" internal procedure AuthorizationCodeTokenCacheExists(): Boolean var - [NonDebuggable] - AccessToken: Text; + AccessToken: SecretText; begin Initialize(); - exit(OAuth2.AcquireAuthorizationCodeTokenFromCache(ClientId, ClientSecret, RedirectURL, GetOAuthAuthorityUrl(), Scopes, AccessToken) and (AccessToken <> '')) + exit(OAuth2.AcquireAuthorizationCodeTokenFromCache(ClientId, ClientSecret, RedirectURL, GetOAuthAuthorityUrl(), Scopes, AccessToken) and (not AccessToken.IsEmpty())) end; internal procedure SignInUsingAuthorizationCode(): Boolean var - [NonDebuggable] - AccessToken: Text; + AccessToken: SecretText; OAuthErr: Text; begin Initialize(); - exit(OAuth2.AcquireTokenByAuthorizationCode(ClientID, ClientSecret, GetOAuthAuthorityUrl(), RedirectURL, Scopes, Enum::"Prompt Interaction"::"Select Account", AccessToken, OAuthErr) and (AccessToken <> '')); + exit(OAuth2.AcquireTokenByAuthorizationCode(ClientID, ClientSecret, GetOAuthAuthorityUrl(), RedirectURL, Scopes, Enum::"Prompt Interaction"::"Select Account", AccessToken, OAuthErr) and (not AccessToken.IsEmpty())); end; local procedure GetOAuthAuthorityUrl(): Text diff --git a/Apps/W1/Email - Outlook REST API/app/src/EmailOAuthClient.Interface.al b/Apps/W1/Email - Outlook REST API/app/src/EmailOAuthClient.Interface.al index f072db4982..348aa3dbf2 100644 --- a/Apps/W1/Email - Outlook REST API/app/src/EmailOAuthClient.Interface.al +++ b/Apps/W1/Email - Outlook REST API/app/src/EmailOAuthClient.Interface.al @@ -1,3 +1,4 @@ +#if not CLEAN24 // ------------------------------------------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. See License.txt in the project root for license information. @@ -7,6 +8,10 @@ namespace System.Email; interface "Email - OAuth Client" { + ObsoleteReason = 'Replaced by "Email - OAuth Client v2".'; + ObsoleteState = Pending; + ObsoleteTag = '24.0'; + /// /// Retrieves the Access token for the current user to connect to Outlook API. /// @@ -20,4 +25,5 @@ interface "Email - OAuth Client" /// Out parameter with the Access token of the account. /// True, if the access token was acquired successfully, false otherwise. procedure TryGetAccessToken(var AccessToken: Text): Boolean; -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/Apps/W1/Email - Outlook REST API/app/src/EmailOAuthClientv2.Interface.al b/Apps/W1/Email - Outlook REST API/app/src/EmailOAuthClientv2.Interface.al new file mode 100644 index 0000000000..239a848103 --- /dev/null +++ b/Apps/W1/Email - Outlook REST API/app/src/EmailOAuthClientv2.Interface.al @@ -0,0 +1,23 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ + +namespace System.Email; + +interface "Email - OAuth Client v2" +{ + /// + /// Retrieves the Access token for the current user to connect to Outlook API. + /// + /// Out parameter with the Access token of the account. + /// Could not get access token. + procedure GetAccessToken(var AccessToken: SecretText); + + /// + /// Retrieves the Access token for the current user to connect to Outlook API. + /// + /// Out parameter with the Access token of the account. + /// True, if the access token was acquired successfully, false otherwise. + procedure TryGetAccessToken(var AccessToken: SecretText): Boolean; +} \ No newline at end of file diff --git a/Apps/W1/Email - Outlook REST API/app/src/EmailOutlookAPIClient.Codeunit.al b/Apps/W1/Email - Outlook REST API/app/src/EmailOutlookAPIClient.Codeunit.al index 9517e58ec9..0b188c9962 100644 --- a/Apps/W1/Email - Outlook REST API/app/src/EmailOutlookAPIClient.Codeunit.al +++ b/Apps/W1/Email - Outlook REST API/app/src/EmailOutlookAPIClient.Codeunit.al @@ -9,7 +9,11 @@ using System.Azure.Identity; using System.Text; using System.Utilities; -codeunit 4508 "Email - Outlook API Client" implements "Email - Outlook API Client" +#if not CLEAN24 +codeunit 4508 "Email - Outlook API Client" implements "Email - Outlook API Client", "Email - Outlook API Client v2" +#else +codeunit 4508 "Email - Outlook API Client" implements "Email - Outlook API Client v2" +#endif { var OutlookCategoryLbl: Label 'Outlook', Locked = true; @@ -34,14 +38,25 @@ codeunit 4508 "Email - Outlook API Client" implements "Email - Outlook API Clien EnvironmentBlocksErr: Label 'The request to send email has been blocked. To resolve the problem, enable outgoing HTTP requests for the Email - Outlook REST API app on the Extension Management page.'; ConnectionErr: Label 'Could not establish the connection to the remote service for sending email. Try again later.'; +#if not CLEAN24 [NonDebuggable] + [Obsolete('Replaced by GetAccountInformation with SecretText data type for AccessToken parameter.', '24.0')] procedure GetAccountInformation(AccessToken: Text; var Email: Text[250]; var Name: Text[250]): Boolean begin exit(TryGetAccountInformation(AccessToken, Email, Name)); end; +#endif + [NonDebuggable] + procedure GetAccountInformation(AccessToken: SecretText; var Email: Text[250]; var Name: Text[250]): Boolean + begin + exit(TryGetAccountInformation(AccessToken, Email, Name)); + end; + +# if not CLEAN24 [NonDebuggable] [TryFunction] + [Obsolete('Replaced by TryGetAccountInformation with SecretText data type for AccessToken parameter.', '24.0')] procedure TryGetAccountInformation(AccessToken: Text; var Email: Text[250]; var Name: Text[250]) var AccountHttpClient: HttpClient; @@ -66,7 +81,36 @@ codeunit 4508 "Email - Outlook API Client" implements "Email - Outlook API Clien JObject.Get('displayName', JToken); Name := CopyStr(JToken.AsValue().AsText(), 1, 250); end; +#endif + [NonDebuggable] + [TryFunction] + procedure TryGetAccountInformation(AccessToken: SecretText; var Email: Text[250]; var Name: Text[250]) + var + AccountHttpClient: HttpClient; + AccountRequestHeaders: HttpHeaders; + AccountResponseMessage: HttpResponseMessage; + ResponseContent: Text; + JObject: JsonObject; + JToken: JsonToken; + begin + AccountRequestHeaders := AccountHttpClient.DefaultRequestHeaders(); + AccountRequestHeaders.Add('Authorization', SecretStrSubstNo('Bearer %1', AccessToken)); + + if not AccountHttpClient.Get(GraphURLTxt + '/v1.0/me', AccountResponseMessage) then + exit; + + AccountResponseMessage.Content().ReadAs(ResponseContent); + JObject.ReadFrom(ResponseContent); + + JObject.Get('userPrincipalName', JToken); + Email := CopyStr(JToken.AsValue().AsText(), 1, 250); + + JObject.Get('displayName', JToken); + Name := CopyStr(JToken.AsValue().AsText(), 1, 250); + end; + +#if not CLEAN24 /// /// Send email using Outlook API. If the message json parameter <= 4 mb and wrapped in a message object it is sent in a single request, otherwise it is sent it in multiple requests. /// @@ -74,7 +118,24 @@ codeunit 4508 "Email - Outlook API Client" implements "Email - Outlook API Clien /// Access token of the account. /// The JSON representing the email message. [NonDebuggable] + [Obsolete('Replaced by SendEmail with SecretText data type for AccessToken parameter.', '24.0')] procedure SendEmail(AccessToken: Text; MessageJson: JsonObject) + var + AT: SecretText; + begin + AT := AccessToken; + SendEmail(AT, MessageJson); + end; +#endif + + /// + /// Send email using Outlook API. If the message json parameter <= 4 mb and wrapped in a message object it is sent in a single request, otherwise it is sent it in multiple requests. + /// + /// User is external and cannot authenticate to the exchange server. + /// Access token of the account. + /// The JSON representing the email message. + [NonDebuggable] + procedure SendEmail(AccessToken: SecretText; MessageJson: JsonObject) var AzureADUserManagement: Codeunit "Azure AD User Management"; AzureADPlan: Codeunit "Azure AD Plan"; @@ -107,7 +168,7 @@ codeunit 4508 "Email - Outlook API Client" implements "Email - Outlook API Clien end; [NonDebuggable] - local procedure SendMailSingleRequest(AccessToken: Text; MessageJson: JsonObject) + local procedure SendMailSingleRequest(AccessToken: SecretText; MessageJson: JsonObject) var MailHttpContent: HttpContent; MailHttpRequestMessage: HttpRequestMessage; @@ -125,7 +186,7 @@ codeunit 4508 "Email - Outlook API Client" implements "Email - Outlook API Clien MailHttpRequestMessage.Method('POST'); MailHttpRequestMessage.SetRequestUri(RequestUri); MailHttpRequestMessage.GetHeaders(MailRequestHeaders); - MailRequestHeaders.Add('Authorization', 'Bearer ' + AccessToken); + MailRequestHeaders.Add('Authorization', SecretStrSubstNo('Bearer %1', AccessToken)); MailHttpContent.WriteFrom(MessageJsonText); MailHttpContent.GetHeaders(MailContentHeaders); @@ -162,7 +223,7 @@ codeunit 4508 "Email - Outlook API Client" implements "Email - Outlook API Clien end; [NonDebuggable] - local procedure CreateDraftMail(AccessToken: Text; MessageJson: JsonObject): Text + local procedure CreateDraftMail(AccessToken: SecretText; MessageJson: JsonObject): Text var MailHttpContent: HttpContent; MailHttpRequestMessage: HttpRequestMessage; @@ -184,7 +245,7 @@ codeunit 4508 "Email - Outlook API Client" implements "Email - Outlook API Clien MailHttpRequestMessage.Method('POST'); MailHttpRequestMessage.SetRequestUri(RequestUri); MailHttpRequestMessage.GetHeaders(MailRequestHeaders); - MailRequestHeaders.Add('Authorization', 'Bearer ' + AccessToken); + MailRequestHeaders.Add('Authorization', SecretStrSubstNo('Bearer %1', AccessToken)); MailHttpContent.WriteFrom(MessageJsonText); MailHttpContent.GetHeaders(MailContentHeaders); @@ -215,7 +276,7 @@ codeunit 4508 "Email - Outlook API Client" implements "Email - Outlook API Clien end; [NonDebuggable] - local procedure SendDraftMail(AccessToken: Text; MessageId: Text): Text + local procedure SendDraftMail(AccessToken: SecretText; MessageId: Text): Text var MailHttpContent: HttpContent; MailHttpRequestMessage: HttpRequestMessage; @@ -231,7 +292,7 @@ codeunit 4508 "Email - Outlook API Client" implements "Email - Outlook API Clien MailHttpRequestMessage.Method('POST'); MailHttpRequestMessage.SetRequestUri(RequestUri); MailHttpRequestMessage.GetHeaders(MailRequestHeaders); - MailRequestHeaders.Add('Authorization', 'Bearer ' + AccessToken); + MailRequestHeaders.Add('Authorization', SecretStrSubstNo('Bearer %1', AccessToken)); MailHttpContent.GetHeaders(MailContentHeaders); MailContentHeaders.Clear(); @@ -251,7 +312,7 @@ codeunit 4508 "Email - Outlook API Client" implements "Email - Outlook API Clien end; [NonDebuggable] - local procedure PostAttachment(AccessToken: Text; AttachmentJson: JsonObject; MessageId: Text) + local procedure PostAttachment(AccessToken: SecretText; AttachmentJson: JsonObject; MessageId: Text) var AttachmentHttpContent: HttpContent; AttachmentHttpRequestMessage: HttpRequestMessage; @@ -268,7 +329,7 @@ codeunit 4508 "Email - Outlook API Client" implements "Email - Outlook API Clien AttachmentHttpRequestMessage.Method('POST'); AttachmentHttpRequestMessage.SetRequestUri(RequestUri); AttachmentHttpRequestMessage.GetHeaders(AttachmentRequestHeaders); - AttachmentRequestHeaders.Add('Authorization', 'Bearer ' + AccessToken); + AttachmentRequestHeaders.Add('Authorization', SecretStrSubstNo('Bearer %1', AccessToken)); AttachmentJson.WriteTo(AttachmentRequestJsonText); AttachmentHttpContent.WriteFrom(AttachmentRequestJsonText); @@ -292,7 +353,7 @@ codeunit 4508 "Email - Outlook API Client" implements "Email - Outlook API Clien end; [NonDebuggable] - local procedure UploadAttachment(AccessToken: Text; AttachmentJson: JsonObject; MessageId: Text) + local procedure UploadAttachment(AccessToken: SecretText; AttachmentJson: JsonObject; MessageId: Text) var Base64Convert: Codeunit "Base64 Convert"; AttachmentTempBlob: Codeunit "Temp Blob"; @@ -315,7 +376,7 @@ codeunit 4508 "Email - Outlook API Client" implements "Email - Outlook API Clien AttachmentHttpRequestMessage.Method('POST'); AttachmentHttpRequestMessage.SetRequestUri(RequestUri); AttachmentHttpRequestMessage.GetHeaders(AttachmentRequestHeaders); - AttachmentRequestHeaders.Add('Authorization', 'Bearer ' + AccessToken); + AttachmentRequestHeaders.Add('Authorization', SecretStrSubstNo('Bearer %1', AccessToken)); AttachmentHttpContent.WriteFrom(RequestJsonText); AttachmentHttpContent.GetHeaders(AttachmentContentHeaders); diff --git a/Apps/W1/Email - Outlook REST API/app/src/EmailOutlookAPIClient.Interface.al b/Apps/W1/Email - Outlook REST API/app/src/EmailOutlookAPIClient.Interface.al index 31e8da6bb7..4eb1055d92 100644 --- a/Apps/W1/Email - Outlook REST API/app/src/EmailOutlookAPIClient.Interface.al +++ b/Apps/W1/Email - Outlook REST API/app/src/EmailOutlookAPIClient.Interface.al @@ -1,3 +1,4 @@ +#if not CLEAN24 // ------------------------------------------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. See License.txt in the project root for license information. @@ -7,6 +8,11 @@ namespace System.Email; interface "Email - Outlook API Client" { + ObsoleteReason = 'Replaced by "Email - Outlook API Client" with SecretText data type for AccessToken parameters'; + ObsoleteState = Pending; + ObsoleteTag = '24.0'; + procedure GetAccountInformation(AccessToken: Text; var Email: Text[250]; var Name: Text[250]): Boolean; procedure SendEmail(AccessToken: Text; MessageJson: JsonObject); -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/Apps/W1/Email - Outlook REST API/app/src/EmailOutlookAPIClientv2.Interface.al b/Apps/W1/Email - Outlook REST API/app/src/EmailOutlookAPIClientv2.Interface.al new file mode 100644 index 0000000000..3245c6c4de --- /dev/null +++ b/Apps/W1/Email - Outlook REST API/app/src/EmailOutlookAPIClientv2.Interface.al @@ -0,0 +1,12 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ + +namespace System.Email; + +interface "Email - Outlook API Client v2" +{ + procedure GetAccountInformation(AccessToken: SecretText; var Email: Text[250]; var Name: Text[250]): Boolean; + procedure SendEmail(AccessToken: SecretText; MessageJson: JsonObject); +} \ No newline at end of file diff --git a/Apps/W1/Email - Outlook REST API/app/src/EmailOutlookAPIHelper.Codeunit.al b/Apps/W1/Email - Outlook REST API/app/src/EmailOutlookAPIHelper.Codeunit.al index 721c981a3d..b54b34d120 100644 --- a/Apps/W1/Email - Outlook REST API/app/src/EmailOutlookAPIHelper.Codeunit.al +++ b/Apps/W1/Email - Outlook REST API/app/src/EmailOutlookAPIHelper.Codeunit.al @@ -224,6 +224,8 @@ codeunit 4509 "Email - Outlook API Helper" IsolatedStorage.Delete(Rec.ClientSecret, DataScope::Module); end; +#if not CLEAN24 + [Obsolete('Replaced by InitializeClients with v2 interfaces.', '24.0')] procedure InitializeClients(var OutlookAPIClient: interface "Email - Outlook API Client"; var OAuthClient: interface "Email - OAuth Client") var DefaultAPIClient: Codeunit "Email - Outlook API Client"; @@ -233,15 +235,23 @@ codeunit 4509 "Email - Outlook API Helper" OAuthClient := DefaultOAuthClient; OnAfterInitializeClients(OutlookAPIClient, OAuthClient); end; +#endif + procedure InitializeClients(var OutlookAPIClient: interface "Email - Outlook API Client v2"; var OAuthClient: interface "Email - OAuth Client v2") + var + DefaultAPIClient: Codeunit "Email - Outlook API Client"; + DefaultOAuthClient: Codeunit "Email - OAuth Client"; + begin + OutlookAPIClient := DefaultAPIClient; + OAuthClient := DefaultOAuthClient; + OnAfterInitializeClientsV2(OutlookAPIClient, OAuthClient); + end; procedure Send(EmailMessage: Codeunit "Email Message"; AccountId: Guid) var EmailOutlookAccount: Record "Email - Outlook Account"; - APIClient: interface "Email - Outlook API Client"; - OAuthClient: interface "Email - OAuth Client"; - - [NonDebuggable] - AccessToken: Text; + APIClient: interface "Email - Outlook API Client v2"; + OAuthClient: interface "Email - OAuth Client v2"; + AccessToken: SecretText; begin InitializeClients(APIClient, OAuthClient); if not EmailOutlookAccount.Get(AccountId) then @@ -253,11 +263,9 @@ codeunit 4509 "Email - Outlook API Helper" procedure Send(EmailMessage: Codeunit "Email Message") var - APIClient: interface "Email - Outlook API Client"; - OAuthClient: interface "Email - OAuth Client"; - - [NonDebuggable] - AccessToken: Text; + APIClient: interface "Email - Outlook API Client v2"; + OAuthClient: interface "Email - OAuth Client v2"; + AccessToken: SecretText; begin InitializeClients(APIClient, OAuthClient); @@ -265,10 +273,18 @@ codeunit 4509 "Email - Outlook API Helper" APIClient.SendEmail(AccessToken, EmailMessageToJson(EmailMessage)); end; + +#if not CLEAN24 [InternalEvent(false)] local procedure OnAfterInitializeClients(var OutlookAPIClient: interface "Email - Outlook API Client"; var OAuthClient: interface "Email - OAuth Client") begin end; +#endif + + [InternalEvent(false)] + local procedure OnAfterInitializeClientsV2(var OutlookAPIClient: interface "Email - Outlook API Client v2"; var OAuthClient: interface "Email - OAuth Client v2") + begin + end; [EventSubscriber(ObjectType::Codeunit, Codeunit::"Environment Cleanup", 'OnClearCompanyConfig', '', false, false)] local procedure ClearCompanyConfigGeneral(CompanyName: Text; SourceEnv: Enum "Environment Type"; DestinationEnv: Enum "Environment Type") diff --git a/Apps/W1/Email - Outlook REST API/app/src/EmailOutlookAPISetup.Page.al b/Apps/W1/Email - Outlook REST API/app/src/EmailOutlookAPISetup.Page.al index 5992d3e524..e46398e6ef 100644 --- a/Apps/W1/Email - Outlook REST API/app/src/EmailOutlookAPISetup.Page.al +++ b/Apps/W1/Email - Outlook REST API/app/src/EmailOutlookAPISetup.Page.al @@ -99,11 +99,7 @@ page 4509 "Email - Outlook API Setup" begin if ClientSecretText = HiddenValueTxt then exit; - if isNullGuid(Rec.ClientSecret) then - Rec.ClientSecret := CreateGuid(); - IsolatedStorage.Set(Rec.ClientSecret, ClientSecretText, DataScope::Module); - ClientSecretText := HiddenValueTxt; - + SetClientSecretInStorage(); SetTestSetupEnabled(); end; } @@ -253,8 +249,7 @@ page 4509 "Email - Outlook API Setup" local procedure TestSetup() var EmailOAuthClient: Codeunit "Email - OAuth Client"; - [NonDebuggable] - AccessToken: Text; + AccessToken: SecretText; begin if not EmailOAuthClient.TryGetAccessToken(AccessToken) then Message(UnsuccessfulTestMsg, EmailOAuthClient.GetLastAuthorizationErrorMessage()) @@ -262,6 +257,17 @@ page 4509 "Email - Outlook API Setup" Message(SuccessfulTestMsg); end; + local procedure SetClientSecretInStorage() + var + SecretClientSecret: SecretText; + begin + if isNullGuid(Rec.ClientSecret) then + Rec.ClientSecret := CreateGuid(); + SecretClientSecret := ClientSecretText; + IsolatedStorage.Set(Rec.ClientSecret, SecretClientSecret, DataScope::Module); + ClientSecretText := HiddenValueTxt; + end; + var MediaResources: Record "Media Resources"; [NonDebuggable] diff --git a/Apps/W1/Email - Outlook REST API/test/Mocks/OAuthClientMock.Codeunit.al b/Apps/W1/Email - Outlook REST API/test/Mocks/OAuthClientMock.Codeunit.al index b4bb2efd03..cc8849309b 100644 --- a/Apps/W1/Email - Outlook REST API/test/Mocks/OAuthClientMock.Codeunit.al +++ b/Apps/W1/Email - Outlook REST API/test/Mocks/OAuthClientMock.Codeunit.al @@ -3,18 +3,47 @@ // Licensed under the MIT License. See License.txt in the project root for license information. // ------------------------------------------------------------------------------------------------ -codeunit 139753 "OAuth Client Mock" implements "Email - OAuth Client" +#if not CLEAN24 +#pragma warning disable AL0432 +codeunit 139753 "OAuth Client Mock" implements "Email - OAuth Client", "Email - OAuth Client v2" +#pragma warning restore AL0432 +#else +codeunit 139753 "OAuth Client Mock" implements "Email - OAuth Client v2" +#endif { SingleInstance = true; +#if not CLEAN24 + ObsoleteReason = 'Email - OAuth Client interface is obsolete and being removed.'; + ObsoleteState = Pending; + ObsoleteTag = '24.0'; +#endif +#if not CLEAN24 + [Obsolete('Replaced by GetAccessToken with SecretText data type for AccessToken parameter.', '24.0')] internal procedure GetAccessToken(var AccessToken: Text) begin TryGetAccessToken(AccessToken); end; + [Obsolete('Replaced by TryGetAccessToken with SecretText data type for AccessToken parameter.', '24.0')] internal procedure TryGetAccessToken(var AccessToken: Text): Boolean begin AccessToken := 'test token'; exit(true); end; +#endif + + internal procedure GetAccessToken(var AccessToken: SecretText) + begin + TryGetAccessToken(AccessToken); + end; + + internal procedure TryGetAccessToken(var AccessToken: SecretText): Boolean + var + Token: Text; + begin + Token := 'test token'; + AccessToken := Token; + exit(true); + end; } \ No newline at end of file diff --git a/Apps/W1/Email - Outlook REST API/test/Mocks/OutlookAPIClientMock.Codeunit.al b/Apps/W1/Email - Outlook REST API/test/Mocks/OutlookAPIClientMock.Codeunit.al index 5a98e1b1b8..9b313771d0 100644 --- a/Apps/W1/Email - Outlook REST API/test/Mocks/OutlookAPIClientMock.Codeunit.al +++ b/Apps/W1/Email - Outlook REST API/test/Mocks/OutlookAPIClientMock.Codeunit.al @@ -3,15 +3,28 @@ // Licensed under the MIT License. See License.txt in the project root for license information. // ------------------------------------------------------------------------------------------------ -codeunit 139754 "Outlook API Client Mock" implements "Email - Outlook API Client" +#if not CLEAN24 +#pragma warning disable AL0432 +codeunit 139754 "Outlook API Client Mock" implements "Email - Outlook API Client", "Email - Outlook API Client v2" +#pragma warning restore AL0432 +#else +codeunit 139754 "Outlook API Client Mock" implements "Email - Outlook API Client v2" +#endif { SingleInstance = true; +#if not CLEAN24 + ObsoleteReason = 'Email - OAuth API Client interface is obsolete and being removed.'; + ObsoleteState = Pending; + ObsoleteTag = '24.0'; +#endif var Message: JsonObject; EmailAddress: Text[250]; AccountName: Text[250]; +#if not CLEAN24 + [Obsolete('Replaced by GetAccountInformation with SecretText data type for AccessToken parameter.', '24.0')] internal procedure GetAccountInformation(AccessToken: Text; var Email: Text[250]; var Name: Text[250]): Boolean begin Email := EmailAddress; @@ -19,10 +32,24 @@ codeunit 139754 "Outlook API Client Mock" implements "Email - Outlook API Client exit(true); end; + [Obsolete('Replaced by SendEmail with SecretText data type for AccessToken parameter.', '24.0')] internal procedure SendEmail(AccessToken: Text; MessageJson: JsonObject) begin Message := MessageJson; end; +#endif + + internal procedure GetAccountInformation(AccessToken: SecretText; var Email: Text[250]; var Name: Text[250]): Boolean + begin + Email := EmailAddress; + Name := AccountName; + exit(true); + end; + + internal procedure SendEmail(AccessToken: SecretText; MessageJson: JsonObject) + begin + Message := MessageJson; + end; procedure GetMessage(): JsonObject begin diff --git a/Apps/W1/Email - Outlook REST API/test/Mocks/OutlookMockInitSubscribers.Codeunit.al b/Apps/W1/Email - Outlook REST API/test/Mocks/OutlookMockInitSubscribers.Codeunit.al index e291038c4b..1c2a7d0393 100644 --- a/Apps/W1/Email - Outlook REST API/test/Mocks/OutlookMockInitSubscribers.Codeunit.al +++ b/Apps/W1/Email - Outlook REST API/test/Mocks/OutlookMockInitSubscribers.Codeunit.al @@ -10,13 +10,20 @@ codeunit 139761 "Outlook Mock Init. Subscribers" var OAuthClientMock: Codeunit "OAuth Client Mock"; OutlookAPIClientMock: Codeunit "Outlook API Client Mock"; - - +#if not CLEAN24 [EventSubscriber(ObjectType::Codeunit, Codeunit::"Email - Outlook API Helper", 'OnAfterInitializeClients', '', false, false)] local procedure OnAfterInitializeClients(var OutlookAPIClient: interface "Email - Outlook API Client"; var OAuthClient: interface "Email - OAuth Client") begin OutlookAPIClient := OutlookAPIClientMock; OAuthClient := OAuthClientMock; end; +#endif + + [EventSubscriber(ObjectType::Codeunit, Codeunit::"Email - Outlook API Helper", 'OnAfterInitializeClientsV2', '', false, false)] + local procedure OnAfterInitializeClientsV2(var OutlookAPIClient: interface "Email - Outlook API Client v2"; var OAuthClient: interface "Email - OAuth Client v2") + begin + OutlookAPIClient := OutlookAPIClientMock; + OAuthClient := OAuthClientMock; + end; } diff --git a/Apps/W1/Email - Outlook REST API/test/OutlookAPIHelperTests.Codeunit.al b/Apps/W1/Email - Outlook REST API/test/OutlookAPIHelperTests.Codeunit.al index b412e75f77..9fb1557e63 100644 --- a/Apps/W1/Email - Outlook REST API/test/OutlookAPIHelperTests.Codeunit.al +++ b/Apps/W1/Email - Outlook REST API/test/OutlookAPIHelperTests.Codeunit.al @@ -20,6 +20,7 @@ codeunit 139752 "Outlook API Helper Tests" AzureADUserTestLibrary: Codeunit "Azure AD User Test Library"; OutlookAPIClient: Codeunit "Email - Outlook API Client"; EmailMessage: Codeunit "Email Message"; + AccessToken: SecretText; begin // [SCENARIO] External user (Delegated Admin) are prevented from sending emails // [GIVEN] The user is a delegated admin @@ -28,7 +29,7 @@ codeunit 139752 "Outlook API Helper Tests" AzureADPlanTestLibrary.AssignUserToPlan(UserSecurityId(), PlanIds.GetDelegatedAdminPlanId()); // [WHEN] The user attempts to send an email - asserterror OutlookAPIClient.SendEmail('', GetEmailJson(EmailMessage)); + asserterror OutlookAPIClient.SendEmail(AccessToken, GetEmailJson(EmailMessage)); // [THEN] The email is blocked and an error is shown LibraryAssert.ExpectedError(SendEmailExternalUserErr); @@ -43,6 +44,7 @@ codeunit 139752 "Outlook API Helper Tests" AzureADUserTestLibrary: Codeunit "Azure AD User Test Library"; OutlookAPIClient: Codeunit "Email - Outlook API Client"; EmailMessage: Codeunit "Email Message"; + AccessToken: SecretText; begin // [SCENARIO] External user (Delegated Helpdesk) is prevented from sending emails // [GIVEN] The user is a delegated helpdesk @@ -51,7 +53,7 @@ codeunit 139752 "Outlook API Helper Tests" AzureADPlanTestLibrary.AssignUserToPlan(UserSecurityId(), PlanIds.GetHelpDeskPlanId()); // [WHEN] The user attempts to send an email - asserterror OutlookAPIClient.SendEmail('', GetEmailJson(EmailMessage)); + asserterror OutlookAPIClient.SendEmail(AccessToken, GetEmailJson(EmailMessage)); // [THEN] The email is blocked and an error is shown LibraryAssert.ExpectedError(SendEmailExternalUserErr); @@ -66,6 +68,7 @@ codeunit 139752 "Outlook API Helper Tests" EmailMessage: Codeunit "Email Message"; AzureADPlan: Codeunit "Azure AD Plan"; PlanIds: Codeunit "Plan Ids"; + AccessToken: SecretText; begin // [SCENARIO] External user (External Accountant) is prevented from sending emails DeleteAllFromTablePlanAndUserPlan(); @@ -75,7 +78,7 @@ codeunit 139752 "Outlook API Helper Tests" LibraryAssert.IsTrue(AzureADPlan.IsPlanAssignedToUser(PlanIds.GetExternalAccountantPlanId()), 'User has no assigned external accountant plan.'); // [WHEN] The user attempts to send an email - asserterror OutlookAPIClient.SendEmail('', GetEmailJson(EmailMessage)); + asserterror OutlookAPIClient.SendEmail(AccessToken, GetEmailJson(EmailMessage)); // [THEN] The email is blocked and an error is shown LibraryAssert.ExpectedError(SendEmailExternalUserErr); diff --git a/Apps/W1/Email - Outlook REST API/test/app.json b/Apps/W1/Email - Outlook REST API/test/app.json index 16902e7d29..f830a55fa4 100644 --- a/Apps/W1/Email - Outlook REST API/test/app.json +++ b/Apps/W1/Email - Outlook REST API/test/app.json @@ -2,7 +2,7 @@ "id": "b5034210-b258-4983-8858-f5cbfd54cb35", "name": "Library Outlook REST API", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Test library for the Outlook REST API.", "description": "This extension provides mock functionality for creating email messages that can be used to test email capabilities in other extensions.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -15,37 +15,37 @@ "id": "63ca2fa4-4f03-4f2b-a480-172fef340d3f", "publisher": "Microsoft", "name": "System Application", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "e6328152-bb29-4664-9dae-3bc7eaae1fd8", "name": "Email - Outlook REST API", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "dd0be2ea-f733-4d65-bb34-a28f4624fb14", "name": "Library Assert", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "e7320ebb-08b3-4406-b1ec-b4927d3e280b", "name": "Any", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "9856ae4f-d1a7-46ef-89bb-6ef056398228", "name": "System Application Test Library", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 135140, diff --git a/Apps/W1/Email - SMTP API/app/app.json b/Apps/W1/Email - SMTP API/app/app.json index f2fbf865fd..dab7259395 100644 --- a/Apps/W1/Email - SMTP API/app/app.json +++ b/Apps/W1/Email - SMTP API/app/app.json @@ -5,7 +5,7 @@ "brief": "This app enables sending emails through the SMTP protocol.", "logo": "ExtensionLogo.png", "description": "This app enables sending emails through the SMTP protocol.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?linkid=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=2186415", @@ -15,7 +15,7 @@ "id": "63ca2fa4-4f03-4f2b-a480-172fef340d3f", "publisher": "Microsoft", "name": "System Application", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "internalsVisibleTo": [ @@ -28,7 +28,7 @@ "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 4611, diff --git a/Apps/W1/Email - SMTP API/app/src/Authentication/BasicSMTPAuth.Codeunit.al b/Apps/W1/Email - SMTP API/app/src/Authentication/BasicSMTPAuth.Codeunit.al index fb0bcb44be..ae179ab501 100644 --- a/Apps/W1/Email - SMTP API/app/src/Authentication/BasicSMTPAuth.Codeunit.al +++ b/Apps/W1/Email - SMTP API/app/src/Authentication/BasicSMTPAuth.Codeunit.al @@ -16,6 +16,6 @@ codeunit 4617 "Basic SMTP Auth" implements "SMTP Auth" var CancellationToken: DotNet CancellationToken; begin - SmtpClient.Authenticate(SMTPAuthentication.GetUserName(), SMTPAuthentication.GetPassword(), CancellationToken); + SmtpClient.Authenticate(SMTPAuthentication.GetUserName(), SMTPAuthentication.GetPassword().Unwrap(), CancellationToken); end; } \ No newline at end of file diff --git a/Apps/W1/Email - SMTP API/app/src/Authentication/NTLMSMTPAuth.Codeunit.al b/Apps/W1/Email - SMTP API/app/src/Authentication/NTLMSMTPAuth.Codeunit.al index 9f90b4e20e..f30adf9d72 100644 --- a/Apps/W1/Email - SMTP API/app/src/Authentication/NTLMSMTPAuth.Codeunit.al +++ b/Apps/W1/Email - SMTP API/app/src/Authentication/NTLMSMTPAuth.Codeunit.al @@ -17,7 +17,7 @@ codeunit 4619 "NTLM SMTP Auth" implements "SMTP Auth" CancellationToken: DotNet CancellationToken; SaslMechanismNtlm: DotNet SaslMechanismNtlm; begin - SaslMechanismNtlm := SaslMechanismNtlm.SaslMechanismNtlm(SMTPAuthentication.GetUserName(), SMTPAuthentication.GetPassword()); + SaslMechanismNtlm := SaslMechanismNtlm.SaslMechanismNtlm(SMTPAuthentication.GetUserName(), SMTPAuthentication.GetPassword().Unwrap()); SmtpClient.Authenticate(SaslMechanismNtlm, CancellationToken); end; } \ No newline at end of file diff --git a/Apps/W1/Email - SMTP API/app/src/Authentication/OAuth2SMTPAuth.Codeunit.al b/Apps/W1/Email - SMTP API/app/src/Authentication/OAuth2SMTPAuth.Codeunit.al index 8e71c19fae..26fda6c2ba 100644 --- a/Apps/W1/Email - SMTP API/app/src/Authentication/OAuth2SMTPAuth.Codeunit.al +++ b/Apps/W1/Email - SMTP API/app/src/Authentication/OAuth2SMTPAuth.Codeunit.al @@ -20,7 +20,7 @@ codeunit 4616 "OAuth2 SMTP Auth" implements "SMTP Auth" DotNetSaslMechanismOAuth2: DotNet SaslMechanismOAuth2; CancellationToken: DotNet CancellationToken; Handled: Boolean; - AccessToken: Text; + AccessToken: SecretText; UserName: Text; begin // Get authentication from subscriber @@ -32,7 +32,7 @@ codeunit 4616 "OAuth2 SMTP Auth" implements "SMTP Auth" UserName := SMTPAuthentication.GetUserName(); AccessToken := SMTPAuthentication.GetAccessToken(); - DotNetSaslMechanismOAuth2 := DotNetSaslMechanismOAuth2.SaslMechanismOAuth2(UserName, AccessToken); + DotNetSaslMechanismOAuth2 := DotNetSaslMechanismOAuth2.SaslMechanismOAuth2(UserName, AccessToken.Unwrap()); SmtpClient.Authenticate(DotNetSaslMechanismOAuth2, CancellationToken); end; } \ No newline at end of file diff --git a/Apps/W1/Email - SMTP API/app/src/Authentication/SMTPAuthentication.Codeunit.al b/Apps/W1/Email - SMTP API/app/src/Authentication/SMTPAuthentication.Codeunit.al index 2f92040029..858ef56087 100644 --- a/Apps/W1/Email - SMTP API/app/src/Authentication/SMTPAuthentication.Codeunit.al +++ b/Apps/W1/Email - SMTP API/app/src/Authentication/SMTPAuthentication.Codeunit.al @@ -15,10 +15,8 @@ codeunit 4620 "SMTP Authentication" var [NonDebuggable] Username: Text[250]; - [NonDebuggable] - Password: Text[250]; - [NonDebuggable] - AccessToken: Text; + Password: SecretText; + AccessToken: SecretText; [NonDebuggable] Server: Text[250]; @@ -32,17 +30,18 @@ codeunit 4620 "SMTP Authentication" Server := CopyStr(Url, 1, MaxStrLen(Server)); end; +#if not CLEAN24 /// /// Set the username and password for authentication /// /// Username /// Password [NonDebuggable] + [Obsolete('Replaced by SetBasicAuthInfo with SecretText data type for Pass parameter.', '24.0')] procedure SetBasicAuthInfo(User: Text; Pass: Text) begin - // Telemetry Username := CopyStr(User, 1, MaxStrLen(Username)); - Password := CopyStr(Pass, 1, MaxStrLen(Password)); + Password := Pass; end; /// @@ -51,12 +50,37 @@ codeunit 4620 "SMTP Authentication" /// User /// Token [NonDebuggable] + [Obsolete('Replaced by SetOAuth2AuthInfo with SecretText data type for Token parameter.', '24.0')] procedure SetOAuth2AuthInfo(User: Text[250]; Token: Text) begin // Telemetry Username := CopyStr(User, 1, MaxStrLen(Username)); AccessToken := Token; end; +#endif + + /// + /// Set the username and password for authentication + /// + /// Username + /// Password + procedure SetBasicAuthInfo(User: Text; Pass: SecretText) + begin + Username := CopyStr(User, 1, MaxStrLen(Username)); + Password := Pass; + end; + + /// + /// Set the OAuth information for authentication + /// + /// User + /// Token + procedure SetOAuth2AuthInfo(User: Text[250]; Token: SecretText) + begin + // Telemetry + Username := CopyStr(User, 1, MaxStrLen(Username)); + AccessToken := Token; + end; [NonDebuggable] internal procedure GetServer(): Text[250] @@ -71,13 +95,13 @@ codeunit 4620 "SMTP Authentication" end; [NonDebuggable] - internal procedure GetPassword(): Text[250] + internal procedure GetPassword(): SecretText begin exit(Password); end; [NonDebuggable] - internal procedure GetAccessToken(): Text + internal procedure GetAccessToken(): SecretText begin exit(AccessToken); end; diff --git a/Apps/W1/Email - SMTP API/test library/app.json b/Apps/W1/Email - SMTP API/test library/app.json index febef9b614..8a74bd1b44 100644 --- a/Apps/W1/Email - SMTP API/test library/app.json +++ b/Apps/W1/Email - SMTP API/test library/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "Tests for the Email - SMTP API Library app", "description": "Tests for the Email - SMTP API Library app", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?linkid=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=2134520", @@ -15,13 +15,13 @@ "id": "8fc50dfb-d338-4fd9-9499-5e44cc8cbf50", "name": "Email - SMTP API", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 100000, diff --git a/Apps/W1/Email - SMTP API/test/app.json b/Apps/W1/Email - SMTP API/test/app.json index 508905dbae..f1aec76a96 100644 --- a/Apps/W1/Email - SMTP API/test/app.json +++ b/Apps/W1/Email - SMTP API/test/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "Tests for the Email - SMTP API app", "description": "Tests for the Email - SMTP API app", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?linkid=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=2134520", @@ -15,37 +15,37 @@ "id": "51493bda-1ba4-46dc-a72e-65eadc0e63b1", "name": "Email - SMTP API Test Library", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "8fc50dfb-d338-4fd9-9499-5e44cc8cbf50", "name": "Email - SMTP API", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "dd0be2ea-f733-4d65-bb34-a28f4624fb14", "name": "Library Assert", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "e7320ebb-08b3-4406-b1ec-b4927d3e280b", "name": "Any", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "9856ae4f-d1a7-46ef-89bb-6ef056398228", "name": "System Application Test Library", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 100000, diff --git a/Apps/W1/Email - SMTP Connector/app/app.json b/Apps/W1/Email - SMTP Connector/app/app.json index 02fb547ed6..b27f028c30 100644 --- a/Apps/W1/Email - SMTP Connector/app/app.json +++ b/Apps/W1/Email - SMTP Connector/app/app.json @@ -4,13 +4,13 @@ "publisher": "Microsoft", "brief": "Enable all users to use a single email account through the SMTP protocol to send email in Business Central.", "description": "This app enables all users to send email from the same email account in Business Central.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?linkid=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=2134520", "url": "https://go.microsoft.com/fwlink/?linkid=724011", "logo": "ExtensionLogo.png", - "application": "24.0.0.0", + "application": "25.0.0.0", "internalsVisibleTo": [ { "id": "725ef69c-e9f2-4dfb-8170-0faedcd52a5b", @@ -23,13 +23,13 @@ "id": "8fc50dfb-d338-4fd9-9499-5e44cc8cbf50", "name": "Email - SMTP API", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 4511, diff --git a/Apps/W1/Email - SMTP Connector/app/src/Authentication/OAuth2SMTPAuthentication.Codeunit.al b/Apps/W1/Email - SMTP Connector/app/src/Authentication/OAuth2SMTPAuthentication.Codeunit.al index d9d59aba00..fd680f2126 100644 --- a/Apps/W1/Email - SMTP Connector/app/src/Authentication/OAuth2SMTPAuthentication.Codeunit.al +++ b/Apps/W1/Email - SMTP Connector/app/src/Authentication/OAuth2SMTPAuthentication.Codeunit.al @@ -23,12 +23,12 @@ codeunit 4516 "OAuth2 SMTP Authentication" /// Authentication user name for SMTP client. Email address of the user who is attempting to authenticate. /// Acquired access token for SMTP client. [NonDebuggable] - internal procedure GetOAuth2Credentials(var UserName: Text; var AccessToken: Text) + internal procedure GetOAuth2Credentials(var UserName: Text; var AccessToken: SecretText) var AzureAdMgt: Codeunit "Azure AD Mgt."; begin AccessToken := AzureAdMgt.GetAccessToken(AzureADMgt.GetO365Resource(), AzureADMgt.GetO365ResourceName(), true); - if AccessToken = '' then + if AccessToken.IsEmpty() then Error(CouldNotAuthenticateErr); GetUserName(AccessToken, UserName); end; @@ -76,7 +76,7 @@ codeunit 4516 "OAuth2 SMTP Authentication" /// The email address of the user for whom the access token got acquired. [NonDebuggable] [TryFunction] - internal procedure GetUserName(AccessToken: Text; var UserName: Text) + internal procedure GetUserName(AccessToken: SecretText; var UserName: Text) var Base64Convert: Codeunit "Base64 Convert"; AccessTokenSections: List of [Text]; @@ -86,7 +86,7 @@ codeunit 4516 "OAuth2 SMTP Authentication" JToken: JsonToken; begin // Access token consists of a header, body and signature - AccessTokenSections := AccessToken.split('.'); + AccessTokenSections := AccessToken.Unwrap().split('.'); // Get the encoded body AccessTokenBodyEncoded := AccessTokenSections.Get(2); @@ -107,7 +107,7 @@ codeunit 4516 "OAuth2 SMTP Authentication" var SMTPConnectorImpl: Codeunit "SMTP Connector Impl."; UserName: Text; - AccessToken: Text; + AccessToken: SecretText; begin if Handled then exit; diff --git a/Apps/W1/Email - SMTP Connector/app/src/SMTPAccount.table.al b/Apps/W1/Email - SMTP Connector/app/src/SMTPAccount.table.al index 0a01495072..81012ff20a 100644 --- a/Apps/W1/Email - SMTP Connector/app/src/SMTPAccount.table.al +++ b/Apps/W1/Email - SMTP Connector/app/src/SMTPAccount.table.al @@ -135,7 +135,7 @@ table 4511 "SMTP Account" end; [NonDebuggable] - procedure SetPassword(Password: Text) + procedure SetPassword(Password: SecretText) begin if IsNullGuid(Rec."Password Key") then Rec."Password Key" := CreateGuid(); @@ -145,7 +145,7 @@ table 4511 "SMTP Account" end; [NonDebuggable] - procedure GetPassword(PasswordKey: Guid) Password: Text + procedure GetPassword(PasswordKey: Guid) Password: SecretText begin if not IsolatedStorage.Get(Format(PasswordKey), DataScope::Company, Password) then Error(UnableToGetPasswordMsg); diff --git a/Apps/W1/Email - SMTP Connector/app/src/SMTPConnectorImpl.Codeunit.al b/Apps/W1/Email - SMTP Connector/app/src/SMTPConnectorImpl.Codeunit.al index 1eb17c59a9..81bcd2ffce 100644 --- a/Apps/W1/Email - SMTP Connector/app/src/SMTPConnectorImpl.Codeunit.al +++ b/Apps/W1/Email - SMTP Connector/app/src/SMTPConnectorImpl.Codeunit.al @@ -151,7 +151,7 @@ codeunit 4513 "SMTP Connector Impl." implements "Email Connector" if SMTPAccount."Authentication Type" <> SMTPAccount."Authentication Type"::Anonymous then begin ClearLastError(); - SMTPAuthentication.SetBasicAuthInfo(Account."User Name", CopyStr(Account.GetPassword(Account."Password Key"), 1, 250)); + SMTPAuthentication.SetBasicAuthInfo(Account."User Name", Account.GetPassword(Account."Password Key")); SMTPAuthentication.SetServer(Account.Server); Result := SMTPClient.Authenticate(Account."Authentication Type", SMTPAuthentication); diff --git a/Apps/W1/Email - SMTP Connector/test/app.json b/Apps/W1/Email - SMTP Connector/test/app.json index a39f674947..bb1ee3cfb1 100644 --- a/Apps/W1/Email - SMTP Connector/test/app.json +++ b/Apps/W1/Email - SMTP Connector/test/app.json @@ -4,55 +4,55 @@ "publisher": "Microsoft", "brief": "Tests for the Email - SMTP Connector app", "description": "Tests for the Email - SMTP Connector app", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?linkid=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=2134520", "url": "https://go.microsoft.com/fwlink/?linkid=724011", "logo": "ExtensionLogo.png", - "application": "24.0.0.0", + "application": "25.0.0.0", "dependencies": [ { "id": "8fc50dfb-d338-4fd9-9499-5e44cc8cbf50", "name": "Email - SMTP API", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "68e13fa3-217a-4be0-9141-99e5bf0ca818", "name": "Email - SMTP Connector", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "dd0be2ea-f733-4d65-bb34-a28f4624fb14", "name": "Library Assert", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "e7320ebb-08b3-4406-b1ec-b4927d3e280b", "name": "Any", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "9856ae4f-d1a7-46ef-89bb-6ef056398228", "name": "System Application Test Library", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 100000, diff --git a/Apps/W1/Email - SMTP Connector/test/src/SMTPAccountAuthTests.Codeunit.al b/Apps/W1/Email - SMTP Connector/test/src/SMTPAccountAuthTests.Codeunit.al index e90ae6d8a3..3567ae652d 100644 --- a/Apps/W1/Email - SMTP Connector/test/src/SMTPAccountAuthTests.Codeunit.al +++ b/Apps/W1/Email - SMTP Connector/test/src/SMTPAccountAuthTests.Codeunit.al @@ -67,20 +67,24 @@ codeunit 139762 "SMTP Account Auth Tests" var OAuth2SMTPAuthentication: Codeunit "OAuth2 SMTP Authentication"; ReturnedUserName: Text; + Token: Text; begin - OAuth2SMTPAuthentication.GetUserName(TokenFromCacheTxt, ReturnedUserName); + Token := TokenFromCacheTxt; + OAuth2SMTPAuthentication.GetUserName(Token, ReturnedUserName); Assert.AreEqual(TokenFromCacheUserNameTxt, ReturnedUserName, 'Incorrect returned username.'); end; [Test] [TransactionModel(TransactionModel::AutoRollback)] + [NonDebuggable] procedure GetOAuth2CredentialsTest() var OAuth2SMTPAuthentication: Codeunit "OAuth2 SMTP Authentication"; SMTPAccountAuthTests: Codeunit "SMTP Account Auth Tests"; EnvironmentInfoTestLibrary: Codeunit "Environment Info Test Library"; UserName: Text; - AuthToken: Text; + AuthToken: SecretText; + Token: Text; begin // [SCENARIO] If the provided server is the O365 SMTP server, and there is available token cache, // the access token is acquires from cache and the user name variable is filled. @@ -88,7 +92,8 @@ codeunit 139762 "SMTP Account Auth Tests" // [GIVEN] Environment is on-prem and token from cache with credentials is available. EnvironmentInfoTestLibrary.SetTestabilitySoftwareAsAService(false); SetAuthFlowProvider(Codeunit::"SMTP Account Auth Tests"); - SMTPAccountAuthTests.SetTokenCache(TokenFromCacheTxt); + Token := TokenFromCacheTxt; + SMTPAccountAuthTests.SetTokenCache(Token); BindSubscription(SMTPAccountAuthTests); // [WHEN] AuthenticateWithOAuth2 is called. @@ -96,7 +101,7 @@ codeunit 139762 "SMTP Account Auth Tests" // [THEN] The AuthToken and UserName have the expected values. Assert.AreEqual(TokenFromCacheUserNameTxt, UserName, 'UserName should not have been filled.'); - Assert.AreEqual(TokenFromCacheTxt, AuthToken, 'AuthToken should not have been filled.'); + Assert.AreEqual(TokenFromCacheTxt, AuthToken.Unwrap(), 'AuthToken should not have been filled.'); end; [Test] diff --git a/Apps/W1/EmailLogging/app/app.json b/Apps/W1/EmailLogging/app/app.json index 09115dd087..539f069d29 100644 --- a/Apps/W1/EmailLogging/app/app.json +++ b/Apps/W1/EmailLogging/app/app.json @@ -2,7 +2,7 @@ "id": "114e4e19-182b-42e2-b5a9-91d8b8ee8ce1", "name": "_Exclude_Email Logging Using Graph API", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "_Exclude_Email Logging Using Graph API", "description": "_Exclude_Email Logging Using Graph API", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -23,7 +23,7 @@ "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 1, @@ -37,5 +37,5 @@ "includeSourceInSymbolFile": true }, "target": "OnPrem", - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/W1/EmailLogging/app/src/entitlements/DelegatedBCAdminAgentPartnerEmailLogging.Entitlement.al b/Apps/W1/EmailLogging/app/src/entitlements/DelegatedBCAdminAgentPartnerEmailLogging.Entitlement.al new file mode 100644 index 0000000000..df33aac89c --- /dev/null +++ b/Apps/W1/EmailLogging/app/src/entitlements/DelegatedBCAdminAgentPartnerEmailLogging.Entitlement.al @@ -0,0 +1,10 @@ +namespace Microsoft.CRM.EmailLoggin; + +entitlement "Delegated BC Admin agent - Partner Email Logging" +{ + Type = Role; + RoleType = Delegated; + Id = '00000000-0000-0000-0000-000000000010'; + + ObjectEntitlements = "Email Logging - Read"; +} diff --git a/Apps/W1/EmailLogging/app/src/entitlements/InternalBCAdministratorEmailLogging.Entitlement.al b/Apps/W1/EmailLogging/app/src/entitlements/InternalBCAdministratorEmailLogging.Entitlement.al new file mode 100644 index 0000000000..51548b78aa --- /dev/null +++ b/Apps/W1/EmailLogging/app/src/entitlements/InternalBCAdministratorEmailLogging.Entitlement.al @@ -0,0 +1,10 @@ +namespace Microsoft.CRM.EmailLoggin; + +entitlement "Internal BC Administrator Email Logging" +{ + Type = Role; + RoleType = Local; + Id = '963797fb-eb3b-4cde-8ce3-5878b3f32a3f'; + + ObjectEntitlements = "Email Logging - Admin"; +} diff --git a/Apps/W1/EmailLogging/test/app.json b/Apps/W1/EmailLogging/test/app.json index 6ba50922f5..24f50868fe 100644 --- a/Apps/W1/EmailLogging/test/app.json +++ b/Apps/W1/EmailLogging/test/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "Tests for the _Exclude_Email Logging Using Graph API extension.", "description": "Tests for the _Exclude_Email Logging Using Graph API extension.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2182906", "help": "https://go.microsoft.com/fwlink/?linkid=2206445", @@ -16,24 +16,24 @@ "id": "114e4e19-182b-42e2-b5a9-91d8b8ee8ce1", "name": "_Exclude_Email Logging using Graph API", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "target": "OnPrem", "resourceExposurePolicy": { "allowDebugging": false, "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/W1/EnforcedDigitalVouchers/app/app.json b/Apps/W1/EnforcedDigitalVouchers/app/app.json index cf5a8fbdb8..41cdd12ff7 100644 --- a/Apps/W1/EnforcedDigitalVouchers/app/app.json +++ b/Apps/W1/EnforcedDigitalVouchers/app/app.json @@ -1,40 +1,44 @@ { - "id": "e2ae191d-8829-44c3-a373-3749a2742d4e", - "name": "Enforced Digital Vouchers", - "publisher": "Microsoft", - "brief": "The Digital Vouchers extension makes it easy to generate digital version for every general ledger register.", - "description": "In some countries authorities require to make sure that for every single general ledger register ther is a digital vouchers assigned.", - "version": "24.0.0.0", - "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", - "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", - "help": "https://learn.microsoft.com/en-us/dynamics365/business-central/finance-how-setup-use-service-declaration", - "url": "https://go.microsoft.com/fwlink/?LinkId=724011", - "logo": "ExtensionLogo.png", - "contextSensitiveHelpUrl": "https://go.microsoft.com/fwlink/?linkid=2204541", - "dependencies": [], - "screenshots": [], - "platform": "24.0.0.0", - "internalsVisibleTo": [ - { - "id": "928f7b70-0dbd-431a-beb5-f45c4adbd361", - "name": "Enforced Digital Vouchers Test Library", - "publisher": "Microsoft" - } - ], - "features": [ - "TranslationFile" - ], - "idRanges": [ - { - "from": 5579, - "to": 5597 - } - ], - "resourceExposurePolicy": { - "allowDebugging": true, - "allowDownloadingSource": true, - "includeSourceInSymbolFile": true - }, - "application": "24.0.0.0", - "target": "Cloud" + "id": "e2ae191d-8829-44c3-a373-3749a2742d4e", + "name": "Enforced Digital Vouchers", + "publisher": "Microsoft", + "brief": "The Digital Vouchers extension makes it easy to generate digital version for every general ledger register.", + "description": "In some countries authorities require to make sure that for every single general ledger register ther is a digital vouchers assigned.", + "version": "25.0.0.0", + "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", + "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", + "help": "https://learn.microsoft.com/en-us/dynamics365/business-central/finance-how-setup-use-service-declaration", + "url": "https://go.microsoft.com/fwlink/?LinkId=724011", + "logo": "ExtensionLogo.png", + "contextSensitiveHelpUrl": "https://go.microsoft.com/fwlink/?linkid=2204541", + "dependencies": [ + + ], + "screenshots": [ + + ], + "platform": "25.0.0.0", + "internalsVisibleTo": [ + { + "id": "928f7b70-0dbd-431a-beb5-f45c4adbd361", + "name": "Enforced Digital Vouchers Test Library", + "publisher": "Microsoft" + } + ], + "features": [ + "TranslationFile" + ], + "idRanges": [ + { + "from": 5579, + "to": 5597 + } + ], + "resourceExposurePolicy": { + "allowDebugging": true, + "allowDownloadingSource": true, + "includeSourceInSymbolFile": true + }, + "application": "25.0.0.0", + "target": "Cloud" } \ No newline at end of file diff --git a/Apps/W1/EnforcedDigitalVouchers/test library/app.json b/Apps/W1/EnforcedDigitalVouchers/test library/app.json index 06e57d2852..62269e82e1 100644 --- a/Apps/W1/EnforcedDigitalVouchers/test library/app.json +++ b/Apps/W1/EnforcedDigitalVouchers/test library/app.json @@ -1,37 +1,39 @@ { - "id": "928f7b70-0dbd-431a-beb5-f45c4adbd361", - "name": "Enforced Digital Vouchers Test Library", - "publisher": "Microsoft", - "brief": "The app is to test the Digital Vouchers feature", - "description": "The app is to test the Digital Vouchers feature", - "version": "24.0.0.0", - "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", - "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", - "help": "https://learn.microsoft.com/en-us/dynamics365/business-central/finance-how-setup-use-service-declaration", - "url": "https://go.microsoft.com/fwlink/?LinkId=724011", - "logo": "ExtensionLogo.png", - "contextSensitiveHelpUrl": "https://go.microsoft.com/fwlink/?linkid=2204541", - "dependencies": [ - { - "id": "e2ae191d-8829-44c3-a373-3749a2742d4e", - "name": "Enforced Digital Vouchers", - "publisher": "Microsoft", - "version": "24.0.0.0" - } - ], - "screenshots": [], - "platform": "24.0.0.0", - "idRanges": [ - { - "from": 139517, - "to": 139518 - } - ], - "resourceExposurePolicy": { - "allowDebugging": true, - "allowDownloadingSource": true, - "includeSourceInSymbolFile": true - }, - "application": "24.0.0.0", - "target": "OnPrem" + "id": "928f7b70-0dbd-431a-beb5-f45c4adbd361", + "name": "Enforced Digital Vouchers Test Library", + "publisher": "Microsoft", + "brief": "The app is to test the Digital Vouchers feature", + "description": "The app is to test the Digital Vouchers feature", + "version": "25.0.0.0", + "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", + "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", + "help": "https://learn.microsoft.com/en-us/dynamics365/business-central/finance-how-setup-use-service-declaration", + "url": "https://go.microsoft.com/fwlink/?LinkId=724011", + "logo": "ExtensionLogo.png", + "contextSensitiveHelpUrl": "https://go.microsoft.com/fwlink/?linkid=2204541", + "dependencies": [ + { + "id": "e2ae191d-8829-44c3-a373-3749a2742d4e", + "name": "Enforced Digital Vouchers", + "publisher": "Microsoft", + "version": "25.0.0.0" + } + ], + "screenshots": [ + + ], + "platform": "25.0.0.0", + "idRanges": [ + { + "from": 139517, + "to": 139518 + } + ], + "resourceExposurePolicy": { + "allowDebugging": true, + "allowDownloadingSource": true, + "includeSourceInSymbolFile": true + }, + "application": "25.0.0.0", + "target": "OnPrem" } \ No newline at end of file diff --git a/Apps/W1/EnforcedDigitalVouchers/test/app.json b/Apps/W1/EnforcedDigitalVouchers/test/app.json index 73c29cee88..9cb417be4a 100644 --- a/Apps/W1/EnforcedDigitalVouchers/test/app.json +++ b/Apps/W1/EnforcedDigitalVouchers/test/app.json @@ -1,60 +1,60 @@ { - "id": "f0eb8756-ea72-4ef8-b0de-686d2a44b259", - "name": "Enforced Digital Vouchers Tests", - "publisher": "Microsoft", - "version": "24.0.0.0", - "brief": "Tests for the Enforced Digital Vouchers extension.", - "description": "Tests for the Enforced Digital Vouchers extension.", - "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", - "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", - "help": "https://go.microsoft.com/fwlink/?LinkId=724011", - "url": "https://go.microsoft.com/fwlink/?LinkId=724011", - "logo": "ExtensionLogo.png", - "platform": "24.0.0.0", - "application": "24.0.0.0", - "dependencies": [ - { - "id": "e2ae191d-8829-44c3-a373-3749a2742d4e", - "name": "Enforced Digital Vouchers", - "publisher": "Microsoft", - "version": "24.0.0.0" - }, - { - "id": "928f7b70-0dbd-431a-beb5-f45c4adbd361", - "name": "Enforced Digital Vouchers Test Library", - "publisher": "Microsoft", - "version": "24.0.0.0" - }, - { - "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", - "name": "Tests-TestLibraries", - "publisher": "Microsoft", - "version": "24.0.0.0" - }, - { - "id": "9856ae4f-d1a7-46ef-89bb-6ef056398228", - "name": "System Application Test Library", - "publisher": "Microsoft", - "version": "24.0.0.0" - }, - { - "id": "5095f467-0a01-4b99-99d1-9ff1237d286f", - "publisher": "Microsoft", - "name": "Library Variable Storage", - "version": "24.0.0.0" - } - ], - "idRanges": [ - { - "from": 139515, - "to": 139516 - } - ], - "contextSensitiveHelpUrl": "https://go.microsoft.com/fwlink/?linkid=2141039", - "resourceExposurePolicy": { - "allowDebugging": false, - "allowDownloadingSource": true, - "includeSourceInSymbolFile": true - }, - "target": "OnPrem" + "id": "f0eb8756-ea72-4ef8-b0de-686d2a44b259", + "name": "Enforced Digital Vouchers Tests", + "publisher": "Microsoft", + "version": "25.0.0.0", + "brief": "Tests for the Enforced Digital Vouchers extension.", + "description": "Tests for the Enforced Digital Vouchers extension.", + "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", + "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", + "help": "https://go.microsoft.com/fwlink/?LinkId=724011", + "url": "https://go.microsoft.com/fwlink/?LinkId=724011", + "logo": "ExtensionLogo.png", + "platform": "25.0.0.0", + "application": "25.0.0.0", + "dependencies": [ + { + "id": "e2ae191d-8829-44c3-a373-3749a2742d4e", + "name": "Enforced Digital Vouchers", + "publisher": "Microsoft", + "version": "25.0.0.0" + }, + { + "id": "928f7b70-0dbd-431a-beb5-f45c4adbd361", + "name": "Enforced Digital Vouchers Test Library", + "publisher": "Microsoft", + "version": "25.0.0.0" + }, + { + "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", + "name": "Tests-TestLibraries", + "publisher": "Microsoft", + "version": "25.0.0.0" + }, + { + "id": "9856ae4f-d1a7-46ef-89bb-6ef056398228", + "name": "System Application Test Library", + "publisher": "Microsoft", + "version": "25.0.0.0" + }, + { + "id": "5095f467-0a01-4b99-99d1-9ff1237d286f", + "publisher": "Microsoft", + "name": "Library Variable Storage", + "version": "25.0.0.0" + } + ], + "idRanges": [ + { + "from": 139515, + "to": 139516 + } + ], + "contextSensitiveHelpUrl": "https://go.microsoft.com/fwlink/?linkid=2141039", + "resourceExposurePolicy": { + "allowDebugging": false, + "allowDownloadingSource": true, + "includeSourceInSymbolFile": true + }, + "target": "OnPrem" } \ No newline at end of file diff --git a/Apps/W1/ErrorMessagesWithRecommendations/app/app.json b/Apps/W1/ErrorMessagesWithRecommendations/app/app.json index a2ad84f5cf..3c42992cd1 100644 --- a/Apps/W1/ErrorMessagesWithRecommendations/app/app.json +++ b/Apps/W1/ErrorMessagesWithRecommendations/app/app.json @@ -2,7 +2,7 @@ "id": "64c9d5e2-7744-4866-bc0e-5ebc2898e651", "name": "Error Messages with Recommendations", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "[Preview] Use the actionable error messages displayed on the Error Messages page to resolve the issue and continue working.", "description": "Error messages can sometimes prevent you from completing a task, especially if the task requires an easy fix. To help you get unblocked and back to work, we have updated our Error Messages page to include actions that can make it easy to fix the problem yourself or fix it in bulk across multiple errors. For example, you can fix dimension errors one by one or in bulk by selecting multiple errors in Error Messages page and running Accept Recommended action.", "privacyStatement": "https://go.microsoft.com/fwlink/?linkid=724009", @@ -17,8 +17,8 @@ "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 7900, diff --git a/Apps/W1/ErrorMessagesWithRecommendations/test/app.json b/Apps/W1/ErrorMessagesWithRecommendations/test/app.json index 6cefdff530..420cc9458d 100644 --- a/Apps/W1/ErrorMessagesWithRecommendations/test/app.json +++ b/Apps/W1/ErrorMessagesWithRecommendations/test/app.json @@ -2,7 +2,7 @@ "id": "5f2328eb-b988-422b-8163-0bd3f3ae5d07", "name": "Error Messages with Recommendations Tests", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Error Messages with Recommendations Tests", "description": "Error Messages with Recommendations Tests", "privacyStatement": "https://go.microsoft.com/fwlink/?linkid=724009", @@ -16,25 +16,25 @@ "id": "64c9d5e2-7744-4866-bc0e-5ebc2898e651", "name": "Error Messages with Recommendations", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "9856ae4f-d1a7-46ef-89bb-6ef056398228", "name": "System Application Test Library", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5095f467-0a01-4b99-99d1-9ff1237d286f", "publisher": "Microsoft", "name": "Library Variable Storage", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "idRanges": [ @@ -46,8 +46,8 @@ "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "resourceExposurePolicy": { "allowDebugging": true, "allowDownloadingSource": true, diff --git a/Apps/W1/EssentialBusinessHeadlines/app/app.json b/Apps/W1/EssentialBusinessHeadlines/app/app.json index d2570e8052..82ecba7915 100644 --- a/Apps/W1/EssentialBusinessHeadlines/app/app.json +++ b/Apps/W1/EssentialBusinessHeadlines/app/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "Essential business headlines draw facts out of your data. Your people draw the conclusions.", "description": "Displays headlines with actionable business insights on Role Center pages. The insights surface interesting facts from your business data so people don't need to go find them.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=870429", @@ -16,7 +16,7 @@ "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 1, @@ -30,5 +30,5 @@ "includeSourceInSymbolFile": true }, "contextSensitiveHelpUrl": "https://go.microsoft.com/fwlink/?linkid=870429", - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/W1/EssentialBusinessHeadlines/test/app.json b/Apps/W1/EssentialBusinessHeadlines/test/app.json index 6b02364582..f0b9be59a9 100644 --- a/Apps/W1/EssentialBusinessHeadlines/test/app.json +++ b/Apps/W1/EssentialBusinessHeadlines/test/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "Tests for the Essential Business Headlines extension.", "description": "Tests for the Essential Business Headlines extension.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=870429", @@ -16,19 +16,19 @@ "id": "2a89f298-7ffd-44a5-a7ce-e08dac98abce", "name": "Essential Business Headlines", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 139500, @@ -45,5 +45,5 @@ "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/W1/ExcelReports/app/ExtensionLogo.png b/Apps/W1/ExcelReports/app/ExtensionLogo.png new file mode 100644 index 0000000000000000000000000000000000000000..4d2c9a626cb9617350617c40cd73904129d4c108 GIT binary patch literal 5446 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 literal 0 HcmV?d00001 diff --git a/Apps/W1/ExcelReports/app/ReportLayouts/Excel/Customer/CustomerTopListExcel.xlsx b/Apps/W1/ExcelReports/app/ReportLayouts/Excel/Customer/CustomerTopListExcel.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..d511b3825fcdc19764f2912c49009912808cb799 GIT binary patch literal 40454 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 literal 0 HcmV?d00001 diff --git a/Apps/W1/ExcelReports/app/ReportLayouts/Excel/GeneralLedger/TrialBalanceExcel.xlsx b/Apps/W1/ExcelReports/app/ReportLayouts/Excel/GeneralLedger/TrialBalanceExcel.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..7353230c1eb6fb63a836c742d7044620701ea12b GIT binary patch literal 65675 zcmeFZWpG?uk}WJ|vY45fnPo9rvY45fnZaUaCW~dE#mo#AOBOS;EPN&3?zuDFx8F>} zH$Uc!c@=SXflfqKot3$A<=Rx(q1#99F355ArNiHTc$T7R2&OFevX!M+~OwfvrWqQbqrnk{F4WV``YLvzoVu zJ@EA-dq}>K9t|g6eQ`oYsVk+>LTgjAKpefzS#Axy&E2se0>%+0f*8()FGE)qyX~xx z%(#(lb1+YdA>9BTVoG4kw<&L~62573u99OMYrylWY4n_y?Dr-5eero;YyeA}&UAX0 z-Hkstn~Rjh&TjlX>=i1^}9!vj0YusB^C6D z08c>@-#49}s+7+Q38kA;y17q|2LzFHTzZDbux{ColS`&P@J9*RX<@lt1+OhE$pK>`82 zy@3KL{0GKl!uv8#3=9PH6F`Wt0LIjHFt&1JpnqTgA5;Es=Epz3dqw=T6etst=sNft z(M~(hit@+8m5wk41*B2}Mp={Zd6ML$pH@0KD$%t|M5hLg&Q>#<6Nas}E8L1w;ht2Y z%QaxG!W%BVX>u@J3oNM=#j2-kzpB_!4KLk1TU~ubcQluxL5ZiN=WlRGa%=*Yuni735b;8BlbBN>v`)qjvo!-(B@USK#2bpb9rHQrwC>-9;o|y8s1s~09F$NV*5+zJ) z#FW7tp{932^nXj^a`QE;MU=u4{>l}nel=?|N+;*b_BIhYXxsbZ)* zXbr7+ym($*yK~ou=JN;C>4*Cd-g;}b9`-xeadch*1gN^dtZ3WpwHVSCzN*o`B?Pml zwUK*!=wtTyLqT*pJR0zw2_MmH-4S6c^516y0mcL7qNW^G%* ziS+6-^8y)ttcor}2wgJ#CB;sas?x){x;=?lnVu6`BY?|r`E&WpIS0Etk>rx>Y!r4F zUpB`i3yaI-n;JdyZrV5IqF;idIdIBE?lK9iIq*Mx&xk9lsmTW216a}%{2!&HZeup9 zJ2N{K?smV-Fu*_!jrw!%x7j(jNA4T>kIL5*aw!xi(lLe-WgHrJL&=SB5qZTO7VA6R zg3CEJByZFj8ciLtMoCI+TL?Mm!0MCs;*K%wn}4b*qT4d;qhowhMAMML01tDMs!QyY z$}6i4TZ>Sa!}1yFIwh-3A`9%K_lg5XbgYDyfGk5dA2XBu`iv4bZ&`r&EFKa)HGxix zc)!6ZnLIJ%NNvzm6YeZuU)CBow+16J5L!g!m)sW)o8g+z>S>r!iZJ=rTO%MgWzY=~Csq}#P zFcDK9wqH<+eUHPKq@W`Ll$QI=r+Uey?o5!zB%CYVBxVpQ@F5U}%`b)+0!a(0lS$#m zplo&&&{PLIBds}ZqC_3LJHWDHqp3z5g8FTlUC}Z}>xR!#G^uer!#SiBaHfXwV^A5a z3XzCPdw84!HH*Y}cO`cPukD?>8widIYVCV6{_7Zxf&CWh|A+SBY;o?20VXHaJ6p%p!l={*=hVfZ(z+%q-Qd34c>=|00j;&%Ob+D5%}FPdhV*gBr% zt+7F@2}5QC{v08H3^w(%??u#OXpf7c#7yfWhu}H3;428NYkD00cdSbp9wK9x+v{lh z)v~7>j5pW_oPM}6P^fiLOj!hymP6(mL{a zGeb-y+URm4y_113@*QDWS?z)L8qGx^OWF)M8IDo9vNO*yV@SDgoqb4+()UO|;DOZ^ zF=_0MnNf}Ukn6)z4x2@?K>NnAA)R1X=gY(01K+KrxrVH=yp8cL;KZ+2L&zD}ma2=M zel7JMw=HqU$rO;q3M$DvIfbcFyu0`b54O~5&ppo~{c-eFzutz$Y~f@&!cb$E*H4kL zKw&bZQ}^)amocCmlqTEquMZ^4IM3&-dJ(sN+0v`RiWMT)tz%8Acqpzqd2Avai2O_bG9hyiudKs zI!J#xZ=msHi7KPlwBk{BnQ*DK3OzMiT3;TnO>0Onj*F?$abZb5vF1ts%VnK|JGxZ;LpUoe zSIFLzwsc)@iQ&BhX5@*PWqjA|O&^WAZptdyH4Hu7RtNE5m77@k()dn&wwm)?)=ID^ z%81#I)pbob*td+Kp}2^GClU+@)fCqh@hZHSGkk)4Lk!Opp98$kpRLW8{OeJ#+T~O0 zt5e(?TU3_89b&x~z5t^AXLZx=^`egoP&P40KtR|)P{05x{zKsWdqV!Z*Z~H#g#ab= zzx&pvCMzGrh}53(Kp=5G1MaLEb%H;i>UK+VxtyqP9+X^vYxvfVM)D0Bk1Mg=YKCg1 zqmAR*WW(iJS#=uHj3jYP0+~SqEWTW8NLx%N`+TxW!iYA3t2{9%@}xU<{PAYz?gO>S zT8<1AHcGQn;jo0cwWCPsCfSd%zB1rL7nmYTlQqS2v)%`s6<}G62(r0emZ8Uuu>+#X zFrT5dm&vDrwdc2`GD@&ep8j>qSeG4`$I_b&D&Pv9#6!HrNGBqZm8|kbB625O83%l1 zSrY!lHD>X7JXGOu0&Y*e7kWHTMj`u0wQ}%PPt+|_&Zv^=&p&ANGT;$FXmEx>W z+_jGs^h}h8%%sMd%3hkxOdF-J`ji1j>_ib0pQMlx$?8f1$#0H^<{E_S*!h^#Nkumw zhSEffVOb67MVJkxiivz{m($v?67Lx!^SNqenxy!B(?rSIs zi!xup#1rzi31B}sh<}(GQ=BXrEfRvntSSWiDRq^z$mmb4aT@oBEfHA@&WpOC6}byxq59%Rk5}3lmUVGK(i|` z{%m6^a1!d+_Ahga+SizW3k=|~zySea0?zoGym2%$Hg_q_-|2F=ljqL*SQ$1Dukhl%2ntkC9Kthb{i2$B`Ts1VC+^{qd%TvH@`Eijv+ zQA!_e?D9W0?9-r@{%HgAd_6cb%s3NLPiAg33gcyfEg&o4lZsooe3Z@<=r?r)vM_Ms zFgaUq5@4o!rUvUuT?)ozSIVCKlS)jgRgzWb;Hi`X%JwoXw%il5wv5x*QSv^ZVGr(8 z1rfx}ar*g^I@jlLJi__5%{`+$Oz8A#_R7yjYl3Togyg7rXwSl&`9x9L zox`M@%8H{SO@en5>9(T;o`x|~u!oJWt&Bn^RCgn-z&f8cpGd)ngVA*Kr+M@b!RH&K zcRh8`ALOxVd)3)BIY-^GIqh$7xeNu;cJruJ8eOY7lSL9~c*)^YF1xEoX)r2tq%$^JV8n(YUb)T$C8g2qfM znIJX|@RsrQHZoyOksvN52?y4%X_7U}TcogsZ2ndFhZ1!vBuJ^}2crQ#@GU{;RYvIm z($l@CoV0+rNf3~Wp=}sm%lgjW@%4MjOnj2=Wkec$OR@{FLb77NudvpSIm^puCV<*P z%!~MZVA$x~^7d2udzEylak{SJnP!Mdc(dC;UfmxKch?TCG{ z7X^;YEA}I1E4V5DW6~ST=Ms<6^NV+LJr^=OPt2TRUrpG&aJGFEx)f((_HZ zgt(hX7{)^t{H*v@sN&hu(cbRSR^Cl{!;}IK-NfKW-$xx8AN=ruYJb(ox2hutk$o?f z;l$k3@%@;*e3teA!tjju42t6>nHc2pTaZuKge5SnaGVOV@x&u=)V4g=?&}c< zRN+(L%X4m_!w>LJYRCi_OB?xp&d%$hk+wwQJws%O{O|S%Hm}7`(>j|eMM6j>@7Q;X62VCq9-L=pFgw)b1C-ea3NKk*+tSk*}8@0 zuQB8*aI(Q5m3`FQBP2lO;`!BHG}&J$oS|Y?=OBy4$HhLlkPWY%Zu~X2I4k>B6JB|% zUMlm2*k*L}ql)|qA(%hF9^uu&_>Bn>tb(WaH zw&$Ihl^*HVH6fDy;`v2D-%cqTzICY3VOx4!X%=+fv|ErZf@fvm6_N4@p@MPkM9(1QiPvbfK| z11*>Iqm~sv_N8ub<%;69kK#tSrSgp)F50_a$Bm;+_-{Ma!ua)pS zm^v!qybx+I$O+psyj3!jWt154Vp|4tgGR7fyXHRNcHo<(5sKp=wlShr5HsLXa7yxw zg_zgv;h}RmRY#%vPTFo}I~NO9(*g)hvfT*v;{&k7stDm7Qs&P}pn45(BuH?D%L3;v zpJb3rDJ%-f%xLj@SHm9w!VHeYUjXqnP=W2E+0~~@$Of^`ZOc06VFBOH26u|!=eQE% zO#P_M@N*QbPVEqL^|r}nUE>DrUC;iF8&~841(8B@jakTxW!Y;hts9_7`KAJ~*=~_g zw);b>x`RZ(EACFSii*C0NhW2GT~ETXtWW6mRUr+hQmiuPUqpN)ulMhx!S8!0zV~l} z?zoX#)+Su9L~y;?HK8>S2QxFJ$f8#ZA?Xcao(N(gr0g@()-?V4Cpqrtp2A&^#SV~u z5NlVzmMpk*^7iz+bzAWJbYMt_gKVb@q#dS=Nd|j)Nwu}}#nY_~7oPV#sqxUr&fAtl zcD_)33VvYKef5LQ0i7t=&ANI9fE;m_m6fF0Y!yWUJR`qS55TyDv4WCh$x`|)VQW}P zvrw>fc4F-~?X=ToIhlvz+kY<6c!gdedFAwUh=^l-EZcD)e=<$i@%B|Ok zD&0HUhaaO3&V6~RxG>4eE&6A(*uAT6XT^kK`w{5=0H|<*qZ8v^6CB7mLR;~2iulj2 zgsjhOY!}L>px&P|lTUM7U?ecfg=9qotAdKKdt+O(^t?!xO826gg;A?Z{2ycFcD3TRj;35uM=&QG@UkhNkz>dT`ru~b^1;Xe)8>fM9C|q0J6=Ch_Xqu;q@8$ zxdO7;)Ol6vmjwZDH!BemYc*$`fg5TMj_!5Y$TW8Nbf+eHArPF$7NhG;KH5X;l~hN; z*OBMgeOs*)Lvoq>dko?R<(7vYi=I>mTNL$lHDH`JDVLn2etaV2h5-^!2I_Al6FiZ|q?rRN1TR_ex{8sAeA1p?aMC^bV_u46w_<6t5y-*;{1}cWyh4G z0C%<dg4&-u)9}^5&{06H_ZRAHO~May4pnl)%qq7H8mncA zr5coZ@~UvB#}RJBOTi^K?t$hA$Sd;Ml=D%ARi|hA z`P)0O^P)9`-XBUHnw#`hG9)tYr8gc&I>1Jv1s1_*i5h`M!-(|2Yv9#HPmHE%h+Tm3 z`tWl#kD?d|Ytg5P+>m{^S%^m*Q779qoBseZ87n;q}l zVXUmU6}QPObcWoLQ?lwzh>g2$!ON2<-=9<_6R8Q)BM2w@9k~{0g_t<8@y!QnP57vg zMTCGVEo{XV72>6J->zv*DEqvS{|s6syK?Z+Np$K!WQlxmK?jMPDWOt9&!K{Vn`Dew zB^R5!zu>Ru&~39#_}-MB@(`Y}hb*cOhATCM=bu_DH>|L9bBZzP0ox!~-mSUXEjtxy z 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 literal 0 HcmV?d00001 diff --git a/Apps/W1/ExcelReports/app/ReportLayouts/Excel/GeneralLedger/TrialBalancePrevYearExcel.xlsx b/Apps/W1/ExcelReports/app/ReportLayouts/Excel/GeneralLedger/TrialBalancePrevYearExcel.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..154562b40845de4f7428d30034cf02d4525d5519 GIT binary patch literal 53096 zcmeFXWpG^WaxE-oW+sc7ESAO0%nTMYGcz+Y*kWd|n3>sPmMmuJj{Tk_C&@Wq^5g!< zSGiMDd-k3^Q#JFf)vH%`Kk`zbU}!)PKu|zHK*T`w8!vagAV5Hym_R_NKu{oBLbf(e zCN@rb%IcFXU?7xvK!6YZzsLXP6&P37v7KW?^A_9T6LuGgZU;8XYx2Y* zBEDkkiF0$#UK=Pgf?V5J^__~&tU{%ZOxz6bV3kG9b#y?@J@ur(JXIuX*3V}3$jC9? zWd){_roWqDeRF@acgi83bj)@%VU?bPZ@D$Re_h%0Q1X|uYjT-u_|@exl!gkPv~E%Y z60L?Yn6ke6z0&|4Q_2VQ%!%iVQLh=|YOGgu{3Q9ML66!f1>xf3gK9YV{_LKEr_sb` z8Fv*bsur>0Gu1=i+9;e5xUV6e+Qc*uASOj;L_*&CTVN9%wpchcj^b4dS$eD^$Aj)b8k?-Ei1Kl9K;xke0o3^ z-*%mdxO5SOhsynr+<1}jzk<$OnG$hLLKf_v`_3wiXzem^mcTa=8nVS{F0#p4TZVFI z;$7tRUJ^x3Y|M>VLTNT|N{8wTJu)Jm$r(B&+kjaDr#ar=c+3u@eIeF~YDS$MQ0D-g zC;?8em;oo3D6<30mWW)j?b`a=4{oqfjC3@J4`VpO=V39+-w27CD}A~Z_+>6Z%y1oh z==S(J1~P)Qe+ZqWDcemPVue^Y!R%5#bC|?i4^)2VdXFRfB+zgAK!)p`0}K3nxVzhI{Jp2&1XPb2F0Q&Jma`MGd&``nI@ zg}>HeGpSp0peXcuG$SIfr4zF9>W2sP!}+q1wai(#5Ac-Z1?S87VcwVH;BY7io1e`x z3(}MqS^e)8M;~Q4h0#nr)c1vSPKYm6+uBnEDz#HBCjGkiGnd#WHtq;dz&03dH}!mg zu>JS|1(N@F(#M1!K0yKukUoI2!2+aD&%wmXk%9jA@&8HQ|7M~4xBp&|Fe3@dge0;B z{z1Ig$-Sl`T(s5|CNGclosdz+v^igboK#`0o4pc4=bOm%knzQOR%_yj)oz7baT?r< zYD~E%%ymTLl{ZZ;rfZ=km7-|%OkJs}4b{lX?W@(bFovVKBn@f;CHCgukTKH_y-PAykN?fXV4jKT>+09Lb8xKhE-bFhtGl$18hmDA3N|d%ogKN5uc(3 zX^ojOnIqNp�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 Q2Jr73FcERB>gT8b12C!e?*IS* literal 0 HcmV?d00001 diff --git a/Apps/W1/ExcelReports/app/ReportLayouts/Excel/GeneralLedger/TrialBalancebyPeriodExcel.xlsx b/Apps/W1/ExcelReports/app/ReportLayouts/Excel/GeneralLedger/TrialBalancebyPeriodExcel.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..eea581883d9af58a95a88bb3f5b3b34021e46037 GIT binary patch literal 43481 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

LRQLi}JoN@sl; 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 RlcH>*AAkB9c%#Ab=|5B&m@xnV literal 0 HcmV?d00001 diff --git a/Apps/W1/ExcelReports/app/ReportLayouts/Excel/Purchase/AgedAccountsPayableExcel.xlsx b/Apps/W1/ExcelReports/app/ReportLayouts/Excel/Purchase/AgedAccountsPayableExcel.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..2276ff6b84f93ef0051cc1b5a859e8f4a6a165aa GIT binary patch literal 61462 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 z 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 Bpa%c| literal 0 HcmV?d00001 diff --git a/Apps/W1/ExcelReports/app/ReportLayouts/Excel/Sales/AgedAccountsReceivableExcel.xlsx b/Apps/W1/ExcelReports/app/ReportLayouts/Excel/Sales/AgedAccountsReceivableExcel.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..aaf1c443b0c9f7d970095051abc94864966d1b63 GIT binary patch literal 72638 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 vGO*8Knw-W#w2=)g$z6K1 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 literal 0 HcmV?d00001 diff --git a/Apps/W1/ExcelReports/app/ReportLayouts/Excel/Vendor/VendorTopListExcel.xlsx b/Apps/W1/ExcelReports/app/ReportLayouts/Excel/Vendor/VendorTopListExcel.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..5b2382aeecf308257bde02e8a88e91b429020360 GIT binary patch literal 37616 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 '' then + EXTTopCustomerBalance.SetFilter(EXTTopCustomerBalance.InitialEntryGlobalDim1Code, EXRTopReportBuffer.GetFilter("Global Dimension 1 Filter")); + + if EXRTopReportBuffer.GetFilter("Global Dimension 2 Filter") <> '' then + EXTTopCustomerBalance.SetFilter(EXTTopCustomerBalance.InitialEntryGlobalDim2Code, EXRTopReportBuffer.GetFilter("Global Dimension 2 Filter")); + + if EXRTopReportBuffer.GetFilter("Currency Code") <> '' then + EXTTopCustomerBalance.SetFilter(EXTTopCustomerBalance.Currency_Code, EXRTopReportBuffer.GetFilter("Currency Code")); + + if EXRTopReportBuffer.GetFilter("Customer Posting Group") <> '' then + EXTTopCustomerBalance.SetFilter(EXTTopCustomerBalance.CustomerPostingGroup, EXRTopReportBuffer.GetFilter("Customer Posting Group")); + + if EXRTopReportBuffer.GetFilter("Date Filter") <> '' then + EXTTopCustomerBalance.SetFilter(EXTTopCustomerBalance.Posting_Date, EXRTopReportBuffer.GetFilter("Date Filter")); + end; + + local procedure TransferFilters(var EXTTopCustomerSale: Query "EXR Top Customer Sales"; var EXRTopReportBuffer: Record "EXR Top Customer Report Buffer") + begin + EXTTopCustomerSale.TopNumberOfRows := NoOfRecordsToPrint; + if EXRTopReportBuffer.GetFilter("Global Dimension 1 Filter") <> '' then + EXTTopCustomerSale.SetFilter(EXTTopCustomerSale.GlobalDimension1Code, EXRTopReportBuffer.GetFilter("Global Dimension 1 Filter")); + + if EXRTopReportBuffer.GetFilter("Global Dimension 2 Filter") <> '' then + EXTTopCustomerSale.SetFilter(EXTTopCustomerSale.GlobalDimension2Code, EXRTopReportBuffer.GetFilter("Global Dimension 2 Filter")); + + if EXRTopReportBuffer.GetFilter("Currency Code") <> '' then + EXTTopCustomerSale.SetFilter(EXTTopCustomerSale.Currency_Code, EXRTopReportBuffer.GetFilter("Currency Code")); + + if EXRTopReportBuffer.GetFilter("Customer Posting Group") <> '' then + EXTTopCustomerSale.SetFilter(EXTTopCustomerSale.CustomerPostingGroup, EXRTopReportBuffer.GetFilter("Customer Posting Group")); + + if EXRTopReportBuffer.GetFilter("Date Filter") <> '' then + EXTTopCustomerSale.SetFilter(EXTTopCustomerSale.Posting_Date, EXRTopReportBuffer.GetFilter("Date Filter")); + end; +} diff --git a/Apps/W1/ExcelReports/app/src/Customer/EXRTopCustomerBalance.Query.al b/Apps/W1/ExcelReports/app/src/Customer/EXRTopCustomerBalance.Query.al new file mode 100644 index 0000000000..3560552528 --- /dev/null +++ b/Apps/W1/ExcelReports/app/src/Customer/EXRTopCustomerBalance.Query.al @@ -0,0 +1,44 @@ +// ------------------------------------------------------------------------------------------------ +// 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.ExcelReports; + +using Microsoft.Sales.Receivables; + +query 4403 "EXR Top Customer Balance" +{ + Caption = 'Top Customer Balance'; + OrderBy = descending(Balance_LCY); + + elements + { + dataitem(Detailed_Customer_Ledger_Entry; "Detailed Cust. Ledg. Entry") + { + column(Customer_No; "Customer No.") + { + } + column(Balance_LCY; "Amount (LCY)") + { + Method = Sum; + } + + filter(Posting_Date; "Posting Date") + { + } + filter(InitialEntryGlobalDim1Code; "Initial Entry Global Dim. 1") + { + } + filter(InitialEntryGlobalDim2Code; "Initial Entry Global Dim. 2") + { + } + filter(Currency_Code; "Currency Code") + { + } + filter(CustomerPostingGroup; "Posting Group") + { + } + } + } +} diff --git a/Apps/W1/ExcelReports/app/src/Customer/EXRTopCustomerReportBuffer.Table.al b/Apps/W1/ExcelReports/app/src/Customer/EXRTopCustomerReportBuffer.Table.al new file mode 100644 index 0000000000..2030baa07a --- /dev/null +++ b/Apps/W1/ExcelReports/app/src/Customer/EXRTopCustomerReportBuffer.Table.al @@ -0,0 +1,128 @@ +// ------------------------------------------------------------------------------------------------ +// 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.ExcelReports; + +using Microsoft.Sales.Customer; +using Microsoft.Finance.Currency; +using Microsoft.Finance.Dimension; + +table 4405 "EXR Top Customer Report Buffer" +{ + Access = Internal; + Caption = 'Top Customer Data'; + DataClassification = CustomerContent; + TableType = Temporary; + ReplicateData = false; + + fields + { + field(1; "Customer No."; Code[20]) + { + Caption = 'Customer No.'; + TableRelation = "Customer"; + } + field(2; "Customer Name"; Text[200]) + { + Caption = 'Name'; + } + field(10; "Amount (LCY)"; Decimal) + { + Caption = 'Amount (LCY)'; + CaptionClass = '3,' + GetAmount1Caption(); + } + field(12; "Amount 2 (LCY)"; Decimal) + { + Caption = 'Amount 2 (LCY)'; + CaptionClass = '3,' + GetAmount2Caption(); + } + field(13; "Ranking Based On"; Option) + { + Caption = 'Ranking Based On'; + OptionCaption = 'Sales (LCY), Balance (LCY)'; + OptionMembers = "Sales (LCY)","Balance (LCY)"; + } + field(44; "Customer Posting Group"; Code[20]) + { + Caption = 'Customer Posting Group'; + TableRelation = "Customer Posting Group"; + FieldClass = FlowFilter; + } + field(45; "Currency Code"; Code[10]) + { + Caption = 'Currency Code'; + TableRelation = Currency; + FieldClass = FlowFilter; + } + field(46; "Period Start Date"; Date) + { + Caption = 'Period Start Date'; + } + field(100; "Date Filter"; Date) + { + Caption = 'Date Filter'; + FieldClass = FlowFilter; + } + field(101; "Global Dimension 1 Filter"; Code[20]) + { + CaptionClass = '1,3,1'; + Caption = 'Global Dimension 1 Filter'; + FieldClass = FlowFilter; + TableRelation = "Dimension Value".Code where("Global Dimension No." = const(1)); + } + field(102; "Global Dimension 2 Filter"; Code[20]) + { + CaptionClass = '1,3,2'; + Caption = 'Global Dimension 2 Filter'; + FieldClass = FlowFilter; + TableRelation = "Dimension Value".Code where("Global Dimension No." = const(2)); + } + } + keys + { + key(PK; "Customer No.", "Period Start Date", "Amount (LCY)") + { + Clustered = true; + } + } + + local procedure GetAmount1Caption(): Text + var + NewCaption: Text; + Handled: Boolean; + begin + OnGetAmount1Caption(Handled, NewCaption); + if not Handled then + exit(AmountLCYTok); + + exit(NewCaption); + end; + + local procedure GetAmount2Caption(): Text + var + NewCaption: Text; + Handled: Boolean; + begin + OnGetAmount2Caption(Handled, NewCaption); + if not Handled then + exit(Amount2LCYTok); + + exit(NewCaption); + end; + + [IntegrationEvent(false, false)] + local procedure OnGetAmount1Caption(var Handled: Boolean; var NewCaption: Text) + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnGetAmount2Caption(var Handled: Boolean; var NewCaption: Text) + begin + end; + + var + AmountLCYTok: Label 'Amount (LCY)'; + Amount2LCYTok: Label 'Amount 2 (LCY)'; +} diff --git a/Apps/W1/ExcelReports/app/src/Customer/EXRTopCustomerSales.Query.al b/Apps/W1/ExcelReports/app/src/Customer/EXRTopCustomerSales.Query.al new file mode 100644 index 0000000000..b2d8983b05 --- /dev/null +++ b/Apps/W1/ExcelReports/app/src/Customer/EXRTopCustomerSales.Query.al @@ -0,0 +1,43 @@ +// ------------------------------------------------------------------------------------------------ +// 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.ExcelReports; + +using Microsoft.Sales.Receivables; + +query 4404 "EXR Top Customer Sales" +{ + Caption = 'Top Customer Sale'; + OrderBy = descending(Sum_Purch_LCY); + + elements + { + dataitem(Customer_Ledger_Entry; "Cust. Ledger Entry") + { + column(Customer_No; "Customer No.") + { + } + column(Sum_Purch_LCY; "Sales (LCY)") + { + Method = Sum; + } + filter(GlobalDimension1Code; "Global Dimension 1 Code") + { + } + filter(GlobalDimension2Code; "Global Dimension 2 Code") + { + } + filter(Currency_Code; "Currency Code") + { + } + filter(CustomerPostingGroup; "Customer Posting Group") + { + } + filter(Posting_Date; "Posting Date") + { + } + } + } +} diff --git a/Apps/W1/ExcelReports/app/src/Customer/ExtTopCustCaptionHandler.Codeunit.al b/Apps/W1/ExcelReports/app/src/Customer/ExtTopCustCaptionHandler.Codeunit.al new file mode 100644 index 0000000000..1b99263a59 --- /dev/null +++ b/Apps/W1/ExcelReports/app/src/Customer/ExtTopCustCaptionHandler.Codeunit.al @@ -0,0 +1,49 @@ +// ------------------------------------------------------------------------------------------------ +// 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.ExcelReports; + +codeunit 4405 "EXT Top Cust. Caption Handler" +{ + EventSubscriberInstance = Manual; + Access = Internal; + + [EventSubscriber(ObjectType::Table, Database::"EXR Top Customer Report Buffer", 'OnGetAmount1Caption', '', false, false)] + local procedure GetAmount1Caption(var NewCaption: Text; var Handled: Boolean) + begin + if (EXTTopReportBuffer."Ranking Based On" = EXTTopReportBuffer."Ranking Based On"::"Balance (LCY)") then begin + NewCaption := BalanceLCYTok; + Handled := true; + exit; + end; + + NewCaption := SalesLCYTok; + Handled := true; + end; + + [EventSubscriber(ObjectType::Table, Database::"EXR Top Customer Report Buffer", 'OnGetAmount2Caption', '', false, false)] + local procedure GetAmount2Caption(var NewCaption: Text; var Handled: Boolean) + begin + if EXTTopReportBuffer."Ranking Based On" <> EXTTopReportBuffer."Ranking Based On"::"Balance (LCY)" then begin + NewCaption := BalanceLCYTok; + Handled := true; + exit; + end; + + NewCaption := SalesLCYTok; + Handled := true; + end; + + internal procedure SetRankingBasedOn(NewRankingBasedOn: Option) + begin + EXTTopReportBuffer."Ranking Based On" := NewRankingBasedOn; + end; + + var + EXTTopReportBuffer: Record "EXR Top Customer Report Buffer"; + BalanceLCYTok: Label 'Balance (LCY)'; + SalesLCYTok: Label 'Sales (LCY)'; + +} \ No newline at end of file diff --git a/Apps/W1/ExcelReports/app/src/Financials/EXRAgedAccPayableExcel.Report.al b/Apps/W1/ExcelReports/app/src/Financials/EXRAgedAccPayableExcel.Report.al new file mode 100644 index 0000000000..9394187781 --- /dev/null +++ b/Apps/W1/ExcelReports/app/src/Financials/EXRAgedAccPayableExcel.Report.al @@ -0,0 +1,363 @@ +// ------------------------------------------------------------------------------------------------ +// 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.ExcelReports; + +using Microsoft.Purchases.Vendor; +using Microsoft.Purchases.Payables; +using Microsoft.Finance.Dimension; +using Microsoft.Finance.GeneralLedger.Setup; + +report 4403 "EXR Aged Acc Payable Excel" +{ + ApplicationArea = All; + Caption = 'Aged Accounts Payable Excel (Preview)'; + DataAccessIntent = ReadOnly; + DefaultRenderingLayout = AgedAccountsPayableExcel; + ExcelLayoutMultipleDataSheets = true; + PreviewMode = PrintLayout; + UsageCategory = ReportsAndAnalysis; + MaximumDatasetSize = 1000000; + + dataset + { + dataitem(VendorAgingData; Vendor) + { + DataItemTableView = sorting("No."); + RequestFilterFields = "No.", "Vendor Posting Group", "Currency Code"; + PrintOnlyIfDetail = true; + + column(VendorNumber; VendorAgingData."No.") + { + IncludeCaption = true; + } + column(VendorName; VendorAgingData.Name) + { + IncludeCaption = true; + } + dataitem(AgingData; "EXR Aging Report Buffer") + { + DataItemTableView = sorting("Vendor Source No."); + DataItemLink = "Vendor Source No." = field("No."); + + column(PeriodStart; + "Period Start Date") + { + IncludeCaption = true; + } + column(PeriodEnd; "Period End Date") + { + IncludeCaption = true; + } + column(RemainingAmount; "Remaining Amount") + { + IncludeCaption = true; + } + column(OriginalAmount; "Original Amount") + { + IncludeCaption = true; + } + column(RemainingAmountLCY; "Remaining Amount (LCY)") + { + IncludeCaption = true; + } + column(OriginalAmountLCY; "Original Amount (LCY)") + { + IncludeCaption = true; + } + column(Dimension1Code; "Dimension 1 Code") + { + IncludeCaption = true; + } + column(Dimension2Code; "Dimension 2 Code") + { + IncludeCaption = true; + } + column(CurrencyCode; CurrencyCodeDisplayCode) + { + } + column(PostingDate; "Posting Date") + { + IncludeCaption = true; + } + column(DocumentDate; "Document Date") + { + IncludeCaption = true; + } + column(DueDate; "Due Date") + { + IncludeCaption = true; + } + column(ReportingDate; "Reporting Date") + { + IncludeCaption = true; + } + column(ReportingDate_Month; "Reporting Date Month") + { + IncludeCaption = true; + } + column(ReportingDate_Quarter; "Reporting Date Quarter") + { + IncludeCaption = true; + } + column(ReportingDate_Year; "Reporting Date Year") + { + IncludeCaption = true; + } + column(EntryNo; "Entry No.") + { + IncludeCaption = true; + } + } + + trigger OnAfterGetRecord() + begin + Clear(AgingData); + AgingData.DeleteAll(); + InsertAgingData(VendorAgingData); + + if AgingData."Currency Code" = '' then + CurrencyCodeDisplayCode := GeneralLedgerSetup.GetCurrencyCode('') + else + CurrencyCodeDisplayCode := AgingData."Currency Code"; + end; + } + + dataitem(Dimension1; "Dimension Value") + { + DataItemTableView = sorting("Code") where("Global Dimension No." = const(1)); + + column(Dim1Code; Dimension1."Code") + { + IncludeCaption = true; + } + column(Dim1Name; Dimension1.Name) + { + IncludeCaption = true; + } + + trigger OnPreDataItem() + begin + VendorAgingData.CopyFilter("Global Dimension 1 Filter", Dimension1.Code); + end; + } + dataitem(Dimension2; "Dimension Value") + { + DataItemTableView = sorting("Code") where("Global Dimension No." = const(2)); + + column(Dim2Code; Dimension2."Code") + { + IncludeCaption = true; + } + column(Dim2Name; Dimension2.Name) + { + IncludeCaption = true; + } + + trigger OnPreDataItem() + begin + VendorAgingData.CopyFilter("Global Dimension 2 Filter", Dimension2.Code); + end; + } + } + requestpage + { + SaveValues = true; + AboutTitle = 'Aged Accounts Payable Excel'; + AboutText = 'This report contains aggregated aging data based on vendor ledger entries. The data is aggregated and bucketed according to the ‘Aged as of'' and ‘period length'' parameters in the reports request page. The aggregated data is summarized per the 2 global dimensions.'; + + layout + { + area(content) + { + group(Options) + { + Caption = 'Options'; + field(AgedAsOfOption; EndingDate) + { + ApplicationArea = Basic, Suite; + Caption = 'Aged As Of'; + ToolTip = 'Specifies the date that you want the aging calculated for.'; + } + field(AgingbyOption; TempEXRAgingReportBuffer."Aged By") + { + ApplicationArea = Basic, Suite; + Caption = 'Aging by'; + OptionCaption = 'Due Date,Posting Date,Document Date'; + ToolTip = 'Specifies if the aging will be calculated from the due date, the posting date, or the document date.'; + + trigger OnValidate() + begin + GlobalEXTAgedAccCaptionHandler.SetGlobalEXRAgingReportBuffer(TempEXRAgingReportBuffer); + end; + } + field(PeriodLengthOption; PeriodLength) + { + ApplicationArea = Basic, Suite; + Caption = 'Period Length'; + ToolTip = 'Specifies the period for which data is sent to the report. For example, enter "-1M" for one month, "-30D" for thirty days, "-3Q" for three quarters, or "-5Y" for five years.'; + } + field(PeriodCountOption; PeriodCount) + { + ApplicationArea = Basic, Suite; + Caption = 'Period Count'; + ToolTip = 'Specifies the number of periods for which data is sent to the report.'; + } + field("Skip Zero Balance Vendors"; SkipZeroBalanceVendors) + { + ApplicationArea = Basic, Suite; + Caption = 'Skip Vendors with Zero Balance'; + ToolTip = 'Specifies if you want to skip Vendors with a zero balance in the report.'; + } + } + } + } + + trigger OnOpenPage() + begin + if EndingDate = 0D then + EndingDate := WorkDate(); + if Format(PeriodLength) = '' then + Evaluate(PeriodLength, '<-1M>'); + + if not GeneralLedgerSetup.Get() then +#pragma warning disable AA0205 + GeneralLedgerSetup.Insert(); +#pragma warning restore AA0205 + end; + } + + rendering + { + layout(AgedAccountsPayableExcel) + { + Type = Excel; + LayoutFile = './ReportLayouts/Excel/Purchase/AgedAccountsPayableExcel.xlsx'; + Caption = 'Aged Accounts Payable Excel'; + Summary = 'Built in layout for Aged Account Payable. Pivot tables can be used to view the data per LCY and FCY and analyse amounts due by currency. Report uses Query connections.'; + } + } + labels + { + ByPeriodLCY = 'By period (LCY)'; + BalanceLCY = 'Balance (LCY)'; + AgedAccountsPayableByPeriodLCY = 'Aged Accounts Payable by Period (LCY)'; + OpenAmountsInLCY = 'Open amounts in LCY'; + ByPeriodFCY = 'By Period (FCY)'; + BalanceFCY = 'Balance (FCY)'; + AgedAccountsPayableByPeriodFCY = 'Aged Accounts Payable by Period (FCY)'; + OpenAmountsInFCY = 'Open amounts in FCY'; + AgedAccountsPayableDueByCurrencyFCY = 'Aged Accounts Payable due by Currency (FCY)'; + DueDateMonth = 'Due Date (Month)'; + DueDateQuarter = 'Due Date (Quarter)'; + DueDateYear = 'Due Date (Year)'; + PostingDateYear = 'Posting Date (Year)'; + PostingDateMonth = 'Posting Date (Month)'; + PostingDateQuarter = 'Posting Date (Quarter)'; + DocumentDateMonth = 'Document Date (Month)'; + DocumentDateQuarter = 'Document Date (Quarter)'; + DocumentDateYear = 'Document Date (Year)'; + DueByCurrencies = 'Due by Currencies'; + OpenByFCY = 'Open by (FCY)'; + DataRetrieved = 'Data retrieved:'; + CurrencyCodeDisplay = 'Currency Code'; + } + + protected var + TempEXRAgingReportBuffer: Record "EXR Aging Report Buffer" temporary; + GeneralLedgerSetup: Record "General Ledger Setup"; + GlobalEXTAgedAccCaptionHandler: Codeunit "EXT Aged Acc. Caption Handler"; + PeriodLength: DateFormula; + SkipZeroBalanceVendors: Boolean; + EndingDate: Date; + PeriodCount: Integer; + PeriodEnds: List of [Date]; + PeriodStarts: List of [Date]; + CurrencyCodeDisplayCode: Code[20]; +#if not CLEAN25 +#pragma warning disable AA0137 + [Obsolete('Will be deleted', '25.0')] + AgingBy: Option "Due Date","Posting Date","Document Date"; +#pragma warning restore AA0137 +#endif + + trigger OnPreReport() + begin + InitReport(); + BindSubscription(GlobalEXTAgedAccCaptionHandler); + GlobalEXTAgedAccCaptionHandler.SetGlobalEXRAgingReportBuffer(TempEXRAgingReportBuffer); + end; + + local procedure InitReport() + var + FirstStartDate: Date; + WorkingEndDate: Date; + WorkingStartDate: Date; + i: Integer; + begin + if Format(PeriodLength) = '' then + Evaluate(PeriodLength, '<-1M>'); + + if PeriodCount = 0 then + PeriodCount := 5; + + WorkingEndDate := EndingDate; + WorkingStartDate := CalcDate(PeriodLength, WorkingEndDate); + repeat + i += 1; + PeriodStarts.Add(WorkingStartDate); + PeriodEnds.Add(WorkingEndDate); + + WorkingStartDate := CalcDate(PeriodLength, WorkingStartDate); + WorkingEndDate := CalcDate(PeriodLength, WorkingEndDate); + until i >= PeriodCount; + FirstStartDate := WorkingStartDate; + + VendorAgingData.SetAutoCalcFields("Net Change (LCY)"); + VendorAgingData.SetRange("Date Filter", FirstStartDate, EndingDate); + if SkipZeroBalanceVendors then + VendorAgingData.SetFilter("Net Change (LCY)", '<>0'); + end; + + local procedure InsertAgingData(var Vendor: Record "Vendor") + var + VendorLedgerEntry: Record "Vendor Ledger Entry"; + begin + VendorLedgerEntry.SetCurrentKey("Vendor No.", Open, Positive, "Due Date", "Currency Code"); + VendorLedgerEntry.SetRange("Vendor No.", Vendor."No."); + VendorLedgerEntry.SetRange("Posting Date", 0D, EndingDate); + VendorLedgerEntry.SetRange("Date Filter", 0D, EndingDate); + VendorLedgerEntry.SetAutoCalcFields("Remaining Amt. (LCY)", "Remaining Amount", "Original Amount", "Original Amt. (LCY)"); + VendorLedgerEntry.SetFilter("Remaining Amt. (LCY)", '<>0'); + if VendorLedgerEntry.FindSet() then + repeat + AddVendorLedgerEntryToBuffer(VendorLedgerEntry); + until VendorLedgerEntry.Next() = 0; + end; + + local procedure AddVendorLedgerEntryToBuffer(var VendorLedgerEntry: Record "Vendor Ledger Entry") + begin + Clear(AgingData); + AgingData."Entry No." := VendorLedgerEntry."Entry No."; + AgingData."Vendor Source No." := VendorLedgerEntry."Vendor No."; + AgingData."Source Name" := VendorLedgerEntry."Vendor Name"; + AgingData."Document No." := VendorLedgerEntry."Document No."; + AgingData."Dimension 1 Code" := VendorLedgerEntry."Global Dimension 1 Code"; + AgingData."Dimension 2 Code" := VendorLedgerEntry."Global Dimension 2 Code"; + AgingData."Currency Code" := VendorLedgerEntry."Currency Code"; + AgingData."Posting Date" := VendorLedgerEntry."Posting Date"; + AgingData."Document Date" := VendorLedgerEntry."Document Date"; + AgingData."Due Date" := VendorLedgerEntry."Due Date"; + AgingData."Aged By" := TempEXRAgingReportBuffer."Aged By"; + AgingData.SetPeriodStartAndEndDate(PeriodStarts, PeriodEnds); + AgingData.SetReportingDate(); + AgingData."Remaining Amount (LCY)" := VendorLedgerEntry."Remaining Amt. (LCY)"; + AgingData."Remaining Amount" := VendorLedgerEntry."Remaining Amount"; + AgingData."Original Amount (LCY)" := VendorLedgerEntry."Original Amt. (LCY)"; + AgingData."Original Amount" := VendorLedgerEntry."Original Amount"; + AgingData.Insert(true); + end; +} + diff --git a/Apps/W1/ExcelReports/app/src/Financials/EXRAgedAccountsRecExcel.Report.al b/Apps/W1/ExcelReports/app/src/Financials/EXRAgedAccountsRecExcel.Report.al new file mode 100644 index 0000000000..bc6862ef6e --- /dev/null +++ b/Apps/W1/ExcelReports/app/src/Financials/EXRAgedAccountsRecExcel.Report.al @@ -0,0 +1,363 @@ +// ------------------------------------------------------------------------------------------------ +// 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.ExcelReports; + +using Microsoft.Sales.Customer; +using Microsoft.Finance.Dimension; +using Microsoft.Sales.Receivables; +using Microsoft.Finance.GeneralLedger.Setup; + +report 4402 "EXR Aged Accounts Rec Excel" +{ + ApplicationArea = All; + Caption = 'Aged Accounts Receivable Excel (Preview)'; + DataAccessIntent = ReadOnly; + DefaultRenderingLayout = AgedAccountsReceivableExcel; + ExcelLayoutMultipleDataSheets = true; + PreviewMode = PrintLayout; + UsageCategory = ReportsAndAnalysis; + MaximumDatasetSize = 1000000; + + dataset + { + dataitem(CustomerAgingData; Customer) + { + DataItemTableView = sorting("No."); + RequestFilterFields = "No.", "Customer Posting Group", "Currency Code"; + PrintOnlyIfDetail = true; + + column(CustomerNumber; CustomerAgingData."No.") + { + IncludeCaption = true; + } + column(CustomerName; CustomerAgingData.Name) + { + IncludeCaption = true; + } + dataitem(AgingData; "EXR Aging Report Buffer") + { + DataItemTableView = sorting("Vendor Source No."); + DataItemLink = "Vendor Source No." = field("No."); + + column(PeriodStart; + "Period Start Date") + { + IncludeCaption = true; + } + column(PeriodEnd; "Period End Date") + { + IncludeCaption = true; + } + column(RemainingAmount; "Remaining Amount") + { + IncludeCaption = true; + } + column(OriginalAmount; "Original Amount") + { + IncludeCaption = true; + } + column(RemainingAmountLCY; "Remaining Amount (LCY)") + { + IncludeCaption = true; + } + column(OriginalAmountLCY; "Original Amount (LCY)") + { + IncludeCaption = true; + } + column(Dimension1Code; "Dimension 1 Code") + { + IncludeCaption = true; + } + column(Dimension2Code; "Dimension 2 Code") + { + IncludeCaption = true; + } + column(CurrencyCode; CurrencyCodeDisplayCode) + { + } + column(PostingDate; "Posting Date") + { + IncludeCaption = true; + } + column(DocumentDate; "Document Date") + { + IncludeCaption = true; + } + column(DueDate; "Due Date") + { + IncludeCaption = true; + } + column(ReportingDate; "Reporting Date") + { + IncludeCaption = true; + } + column(ReportingDate_Month; "Reporting Date Month") + { + IncludeCaption = true; + } + column(ReportingDate_Quarter; "Reporting Date Quarter") + { + IncludeCaption = true; + } + column(ReportingDate_Year; "Reporting Date Year") + { + IncludeCaption = true; + } + column(EntryNo; "Entry No.") + { + IncludeCaption = true; + } + } + + trigger OnAfterGetRecord() + begin + Clear(AgingData); + AgingData.DeleteAll(); + InsertAgingData(CustomerAgingData); + + if AgingData."Currency Code" = '' then + CurrencyCodeDisplayCode := GeneralLedgerSetup.GetCurrencyCode('') + else + CurrencyCodeDisplayCode := AgingData."Currency Code"; + end; + } + + dataitem(Dimension1; "Dimension Value") + { + DataItemTableView = sorting("Code") where("Global Dimension No." = const(1)); + + column(Dim1Code; Dimension1."Code") + { + IncludeCaption = true; + } + column(Dim1Name; Dimension1.Name) + { + IncludeCaption = true; + } + + trigger OnPreDataItem() + begin + CustomerAgingData.CopyFilter("Global Dimension 1 Filter", Dimension1.Code); + end; + } + dataitem(Dimension2; "Dimension Value") + { + DataItemTableView = sorting("Code") where("Global Dimension No." = const(2)); + + column(Dim2Code; Dimension2."Code") + { + IncludeCaption = true; + } + column(Dim2Name; Dimension2.Name) + { + IncludeCaption = true; + } + + trigger OnPreDataItem() + begin + CustomerAgingData.CopyFilter("Global Dimension 2 Filter", Dimension2.Code); + end; + } + } + requestpage + { + SaveValues = true; + AboutTitle = 'Aged Accounts Receivable Excel'; + AboutText = 'This report contains aggregated aging data based on customer ledger entries. The data is aggregated and bucketed according to the ‘Aged as of'' and ‘period length'' parameters in the reports request page. The aggregated data is summarized per the 2 global dimensions.'; + + layout + { + area(content) + { + group(Options) + { + Caption = 'Options'; + field(AgedAsOfOption; EndingDate) + { + ApplicationArea = Basic, Suite; + Caption = 'Aged As Of'; + ToolTip = 'Specifies the date that you want the aging calculated for.'; + } + field(AgingbyOption; TempEXRAgingReportBuffer."Aged By") + { + ApplicationArea = Basic, Suite; + Caption = 'Aging by'; + OptionCaption = 'Due Date,Posting Date,Document Date'; + ToolTip = 'Specifies if the aging will be calculated from the due date, the posting date, or the document date.'; + + trigger OnValidate() + begin + GlobalEXTAgedAccCaptionHandler.SetGlobalEXRAgingReportBuffer(TempEXRAgingReportBuffer); + end; + } + field(PeriodLengthOption; PeriodLength) + { + ApplicationArea = Basic, Suite; + Caption = 'Period Length'; + ToolTip = 'Specifies the period for which data is sent to the report. For example, enter "-1M" for one month, "-30D" for thirty days, "-3Q" for three quarters, or "-5Y" for five years.'; + } + field(PeriodCountOption; PeriodCount) + { + ApplicationArea = Basic, Suite; + Caption = 'Period Count'; + ToolTip = 'Specifies the number of periods for which data is sent to the report.'; + } + field("Skip Zero Balance Customers"; SkipZeroBalanceCustomers) + { + ApplicationArea = Basic, Suite; + Caption = 'Skip Customers with Zero Balance'; + ToolTip = 'Specifies if you want to skip customers with a zero balance in the report.'; + } + } + } + } + + trigger OnOpenPage() + begin + if EndingDate = 0D then + EndingDate := WorkDate(); + if Format(PeriodLength) = '' then + Evaluate(PeriodLength, '<-1M>'); + + if not GeneralLedgerSetup.Get() then +#pragma warning disable AA0205 + GeneralLedgerSetup.Insert(); +#pragma warning restore AA0205 + end; + } + + rendering + { + layout(AgedAccountsReceivableExcel) + { + Type = Excel; + LayoutFile = './ReportLayouts/Excel/Sales/AgedAccountsReceivableExcel.xlsx'; + Caption = 'Aged Accounts Receivable Excel'; + Summary = 'Built in layout for Aged Account Receivable. Pivot tables can be used to view the data per LCY and FCY and analyse amounts due by currency. Report uses Query connections.'; + } + } + labels + { + ByPeriodLCY = 'By period (LCY)'; + BalanceLCY = 'Balance (LCY)'; + AgedAccountsReceivableByPeriodLCY = 'Aged Accounts Receivable by Period (LCY)'; + OpenAmountsInLCY = 'Open amounts in LCY'; + ByPeriodFCY = 'By Period (FCY)'; + BalanceFCY = 'Balance (FCY)'; + AgedAccountsReceivableByPeriodFCY = 'Aged Accounts Receivable by Period (FCY)'; + OpenAmountsInFCY = 'Open amounts in FCY'; + AgedAccountsReceivableDueByCurrencyFCY = 'Aged Accounts Receivable due by Currency (FCY)'; + DueDateMonth = 'Due Date (Month)'; + DueDateQuarter = 'Due Date (Quarter)'; + DueDateYear = 'Due Date (Year)'; + PostingDateYear = 'Posting Date (Year)'; + PostingDateMonth = 'Posting Date (Month)'; + PostingDateQuarter = 'Posting Date (Quarter)'; + DocumentDateMonth = 'Document Date (Month)'; + DocumentDateQuarter = 'Document Date (Quarter)'; + DocumentDateYear = 'Document Date (Year)'; + DueByCurrencies = 'Due by Currencies'; + OpenByFCY = 'Open by (FCY)'; + DataRetrieved = 'Data retrieved:'; + CurrencyCodeDisplay = 'Currency Code'; + } + + protected var + TempEXRAgingReportBuffer: Record "EXR Aging Report Buffer" temporary; + GeneralLedgerSetup: Record "General Ledger Setup"; + GlobalEXTAgedAccCaptionHandler: Codeunit "EXT Aged Acc. Caption Handler"; + PeriodLength: DateFormula; + SkipZeroBalanceCustomers: Boolean; + EndingDate: Date; + PeriodCount: Integer; + PeriodEnds: List of [Date]; + PeriodStarts: List of [Date]; + CurrencyCodeDisplayCode: Code[20]; +#if not CLEAN25 +#pragma warning disable AA0137 + [Obsolete('Will be deleted', '25.0')] + AgingBy: Option "Due Date","Posting Date","Document Date"; +#pragma warning restore AA0137 +#endif + + trigger OnPreReport() + begin + InitReport(); + BindSubscription(GlobalEXTAgedAccCaptionHandler); + GlobalEXTAgedAccCaptionHandler.SetGlobalEXRAgingReportBuffer(TempEXRAgingReportBuffer); + end; + + local procedure InitReport() + var + FirstStartDate: Date; + WorkingEndDate: Date; + WorkingStartDate: Date; + i: Integer; + begin + if Format(PeriodLength) = '' then + Evaluate(PeriodLength, '<-1M>'); + + if PeriodCount = 0 then + PeriodCount := 5; + + WorkingEndDate := EndingDate; + WorkingStartDate := CalcDate(PeriodLength, WorkingEndDate); + repeat + i += 1; + PeriodStarts.Add(WorkingStartDate); + PeriodEnds.Add(WorkingEndDate); + + WorkingStartDate := CalcDate(PeriodLength, WorkingStartDate); + WorkingEndDate := CalcDate(PeriodLength, WorkingEndDate); + until i >= PeriodCount; + FirstStartDate := WorkingStartDate; + + CustomerAgingData.SetAutoCalcFields("Net Change (LCY)"); + CustomerAgingData.SetRange("Date Filter", FirstStartDate, EndingDate); + if SkipZeroBalanceCustomers then + CustomerAgingData.SetFilter("Net Change (LCY)", '<>0'); + end; + + local procedure InsertAgingData(var Customer: Record Customer) + var + CustLedgerEntry: Record "Cust. Ledger Entry"; + begin + CustLedgerEntry.SetCurrentKey("Customer No.", Open, Positive, "Due Date", "Currency Code"); + CustLedgerEntry.SetRange("Customer No.", Customer."No."); + CustLedgerEntry.SetRange("Posting Date", 0D, EndingDate); + CustLedgerEntry.SetRange("Date Filter", 0D, EndingDate); + CustLedgerEntry.SetAutoCalcFields("Remaining Amt. (LCY)", "Remaining Amount", "Original Amount", "Original Amt. (LCY)"); + CustLedgerEntry.SetFilter("Remaining Amt. (LCY)", '<>0'); + if CustLedgerEntry.FindSet() then + repeat + AddCustLedgerEntryToBuffer(CustLedgerEntry); + until CustLedgerEntry.Next() = 0; + end; + + local procedure AddCustLedgerEntryToBuffer(var CustLedgerEntry: Record "Cust. Ledger Entry") + begin + Clear(AgingData); + AgingData."Entry No." := CustLedgerEntry."Entry No."; + AgingData."Vendor Source No." := CustLedgerEntry."Customer No."; + AgingData."Source Name" := CustLedgerEntry."Customer Name"; + AgingData."Document No." := CustLedgerEntry."Document No."; + AgingData."Dimension 1 Code" := CustLedgerEntry."Global Dimension 1 Code"; + AgingData."Dimension 2 Code" := CustLedgerEntry."Global Dimension 2 Code"; + AgingData."Currency Code" := CustLedgerEntry."Currency Code"; + AgingData."Posting Date" := CustLedgerEntry."Posting Date"; + AgingData."Document Date" := CustLedgerEntry."Document Date"; + AgingData."Due Date" := CustLedgerEntry."Due Date"; + AgingData."Aged By" := TempEXRAgingReportBuffer."Aged By"; + AgingData.SetPeriodStartAndEndDate(PeriodStarts, PeriodEnds); + AgingData.SetReportingDate(); + AgingData."Remaining Amount (LCY)" := CustLedgerEntry."Remaining Amt. (LCY)"; + AgingData."Remaining Amount" := CustLedgerEntry."Remaining Amount"; + AgingData."Original Amount (LCY)" := CustLedgerEntry."Original Amt. (LCY)"; + AgingData."Original Amount" := CustLedgerEntry."Original Amount"; + AgingData.Insert(); + end; +} + diff --git a/Apps/W1/ExcelReports/app/src/Financials/EXRAgingReportBuffer.Table.al b/Apps/W1/ExcelReports/app/src/Financials/EXRAgingReportBuffer.Table.al new file mode 100644 index 0000000000..6950906990 --- /dev/null +++ b/Apps/W1/ExcelReports/app/src/Financials/EXRAgingReportBuffer.Table.al @@ -0,0 +1,222 @@ +// ------------------------------------------------------------------------------------------------ +// 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.ExcelReports; + +table 4401 "EXR Aging Report Buffer" +{ + Caption = 'Aging Report Buffer'; + DataClassification = CustomerContent; + TableType = Temporary; + ReplicateData = false; + + fields + { + field(1; "Entry No."; Integer) + { + Caption = 'Entry No.'; + } + field(2; "Period Start Date"; Date) + { + Caption = 'Period Start Date'; + } + field(3; "Period End Date"; Date) + { + Caption = 'Period End Date'; + } + field(4; "Vendor Source No."; Code[20]) + { + Caption = 'Source No.'; + } + field(10; "Document No."; Code[20]) + { + Caption = 'Document No.'; + } + field(11; "Posting Date"; Date) + { + Caption = 'Posting Date'; + } + field(12; "Currency Code"; Code[20]) + { + Caption = 'Currency Code'; + } + field(13; "Remaining Amount"; Decimal) + { + Caption = 'Remaining Amount'; + } + field(14; "Remaining Amount (LCY)"; Decimal) + { + Caption = 'Remaining Amount (LCY)'; + } + field(15; "Dimension 1 Code"; Code[20]) + { + CaptionClass = '1,2,1'; + Caption = 'Dimension 1 Code'; + } + field(16; "Dimension 2 Code"; Code[20]) + { + CaptionClass = '1,2,2'; + Caption = 'Dimension 2 Code'; + } + field(20; "Original Amount"; Decimal) + { + Caption = 'Original Amount'; + } + field(21; "Original Amount (LCY)"; Decimal) + { + Caption = 'Original Amount (LCY)'; + } + field(22; "Due Date"; Date) + { + Caption = 'Due Date'; + } + field(23; "Document Date"; Date) + { + Caption = 'Document Date'; + } + field(25; "Source Name"; Text[100]) + { + Caption = 'Source Name'; + } + field(26; "Aged By"; Option) + { + Caption = 'Aged By'; + OptionMembers = "Due Date","Posting Date","Document Date"; + OptionCaption = 'Due Date, Posting Date, Document Date'; + } + field(27; "Reporting Date"; Date) + { + Caption = 'Reporting Date'; + CaptionClass = '3,' + GetReportingDateCaption(); + } + field(28; "Reporting Date Month"; Integer) + { + Caption = 'Reporting Date (Month)'; + CaptionClass = '3,' + GetReportingDateMonthCaption(); + } + field(29; "Reporting Date Quarter"; Integer) + { + Caption = 'Reporting Date (Quarter)'; + CaptionClass = '3,' + GetReportingDateQuarterCaption(); + } + field(30; "Reporting Date Year"; Integer) + { + Caption = 'Reporting Date (Year)'; + CaptionClass = '3,' + GetReportingDateYearCaption(); + } + } + keys + { + key(PK; "Entry No.") + { + Clustered = true; + } + key(Key1; "Vendor Source No.") + { + } + } + + local procedure GetReportingDateCaption(): Text + begin + OnOverrideAgedBy(Rec); + case Rec."Aged By" of + Rec."Aged By"::"Document Date": + exit(FieldCaption("Document Date")); + Rec."Aged By"::"Due Date": + exit(FieldCaption("Due Date")); + Rec."Aged By"::"Posting Date": + exit(FieldCaption("Posting Date")); + end; + end; + + local procedure GetReportingDateMonthCaption(): Text + begin + exit(StrSubstNo(MonthLbl, GetReportingDateCaption())); + end; + + local procedure GetReportingDateQuarterCaption(): Text + begin + exit(StrSubstNo(QuarterLbl, GetReportingDateCaption())); + end; + + local procedure GetReportingDateYearCaption(): Text + begin + exit(StrSubstNo(YearLbl, GetReportingDateCaption())); + end; + + internal procedure SetReportingDate() + begin + case Rec."Aged By" of + Rec."Aged By"::"Due Date": + Rec."Reporting Date" := Rec."Due Date"; + Rec."Aged By"::"Posting Date": + Rec."Reporting Date" := Rec."Posting Date"; + Rec."Aged By"::"Document Date": + Rec."Reporting Date" := Rec."Document Date"; + end; + + Rec."Reporting Date Month" := Date2DMY(Rec."Reporting Date", 2); + Rec."Reporting Date Year" := Date2DMY(Rec."Reporting Date", 3); + Rec."Reporting Date Quarter" := GetQuarterIndex(Rec."Reporting Date"); + end; + + local procedure GetQuarterIndex(Date: Date): Integer + begin + exit((Date2DMY(Date, 2) - 1) div 3 + 1); + end; + + internal procedure SetPeriodStartAndEndDate(PeriodStarts: List of [Date]; PeriodEnds: List of [Date]) + begin + case Rec."Aged By" of + Rec."Aged By"::"Due Date": + begin + Rec."Period Start Date" := FindPeriodStart(Rec."Due Date", PeriodStarts); + Rec."Period End Date" := FindPeriodEnd(Rec."Due Date", PeriodEnds); + end; + Rec."Aged By"::"Posting Date": + begin + Rec."Period Start Date" := FindPeriodStart(Rec."Posting Date", PeriodStarts); + Rec."Period End Date" := FindPeriodEnd(Rec."Posting Date", PeriodEnds); + end; + Rec."Aged By"::"Document Date": + begin + Rec."Period Start Date" := FindPeriodStart(Rec."Document Date", PeriodStarts); + Rec."Period End Date" := FindPeriodEnd(Rec."Document Date", PeriodEnds); + end; + end; + end; + + local procedure FindPeriodStart(WhatDate: Date; PeriodStarts: List of [Date]): Date + var + PossibleDate: Date; + begin + foreach PossibleDate in PeriodStarts do + if WhatDate >= PossibleDate then + exit(PossibleDate); + + exit(PossibleDate); + end; + + local procedure FindPeriodEnd(WhatDate: Date; PeriodEnds: List of [Date]): Date + var + PossibleDate: Date; + begin + foreach PossibleDate in PeriodEnds do + if WhatDate < PossibleDate then + exit(PossibleDate); + + exit(PossibleDate); + end; + + [IntegrationEvent(false, false)] + local procedure OnOverrideAgedBy(var EXRAgingReportBuffer: Record "EXR Aging Report Buffer") + begin + end; + + var + MonthLbl: Label '%1 (Month)', Comment = '%1 is Document Date, Due Date or Posting Date'; + QuarterLbl: Label '%1 (Quarter)', Comment = '%1 is Document Date, Due Date or Posting Date'; + YearLbl: Label '%1 (Year)', Comment = '%1 is Document Date, Due Date or Posting Date'; +} diff --git a/Apps/W1/ExcelReports/app/src/Financials/EXRTrialBalPrevYearExcel.Report.al b/Apps/W1/ExcelReports/app/src/Financials/EXRTrialBalPrevYearExcel.Report.al new file mode 100644 index 0000000000..e360cd00cd --- /dev/null +++ b/Apps/W1/ExcelReports/app/src/Financials/EXRTrialBalPrevYearExcel.Report.al @@ -0,0 +1,195 @@ +// ------------------------------------------------------------------------------------------------ +// 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.ExcelReports; + +using Microsoft.Finance.GeneralLedger.Account; +using Microsoft.Finance.Dimension; +using Microsoft.Foundation.Company; + +report 4407 "EXR Trial Bal. Prev Year Excel" +{ + ApplicationArea = All; + Caption = 'Trial Balance/Previous Year Excel (Preview)'; + DataAccessIntent = ReadOnly; + DefaultRenderingLayout = TrialBalancePrevYearExcelLayout; + ExcelLayoutMultipleDataSheets = true; + UsageCategory = ReportsAndAnalysis; + MaximumDatasetSize = 1000000; + + dataset + { + dataitem(TrialBalancePreviousYearData; "G/L Account") + { + DataItemTableView = sorting("No."); + RequestFilterFields = "No.", "Account Type", "Date Filter"; + + column(AccountNumber; "No.") { IncludeCaption = true; } + column(AccountName; Name) { IncludeCaption = true; } + column(IncomeBalance; "Income/Balance") { IncludeCaption = true; } + column(AccountCategory; "Account Category") { IncludeCaption = true; } + column(AccountSubcategory; "Account Subcategory Descript.") { IncludeCaption = true; } + column(AccountType; "Account Type") { IncludeCaption = true; } + column(Indentation; Indentation) { IncludeCaption = true; } + column(IndentedAccountName; IndentedAccountName) { } + + dataitem(EXRTrialBalanceBuffer; "EXR Trial Balance Buffer") + { + DataItemLink = "G/L Account No." = field("No."); + column(Account; "G/L Account No.") { IncludeCaption = true; } + column(Dimension1Code; "Dimension 1 Code") { IncludeCaption = true; } + column(Dimension2Code; "Dimension 2 Code") { IncludeCaption = true; } + column(NetChangeDebit; "Net Change (Debit)") { IncludeCaption = true; } + column(NetChangeCredit; "Net Change (Credit)") { IncludeCaption = true; } + column(BalanceDebit; "Balance (Debit)") { IncludeCaption = true; } + column(BalanceCredit; "Balance (Credit)") { IncludeCaption = true; } + column(LastPeriodNet; "Last Period Net") { IncludeCaption = true; } + column(LastPeriodBalance; "Last Period Bal.") { IncludeCaption = true; } + column(NetVariance; "Net Variance") { IncludeCaption = true; } + column(NetPercentVariance; "% of Net Variance") { IncludeCaption = true; } + column(BalanceVariance; "Bal. Variance") { IncludeCaption = true; } + column(BalancePercentVariance; "% of Bal. Variance") { IncludeCaption = true; } + column(NetChangeDebitACY; "Net Change (Debit) (ACY)") { IncludeCaption = true; } + column(NetChangeCreditACY; "Net Change (Credit) (ACY)") { IncludeCaption = true; } + column(BalanceDebitACY; "Balance (Debit) (ACY)") { IncludeCaption = true; } + column(BalanceCreditACY; "Balance (Credit) (ACY)") { IncludeCaption = true; } + column(LastPeriodNetACY; "Last Period Net (ACY)") { IncludeCaption = true; } + column(LastPeriodBalanceACY; "Last Period Bal. (ACY)") { IncludeCaption = true; } + column(NetVarianceACY; "Net Variance (ACY)") { IncludeCaption = true; } + column(NetPercentVarianceACY; "% of Net Variance (ACY)") { IncludeCaption = true; } + column(BalanceVarianceACY; "Bal. Variance (ACY)") { IncludeCaption = true; } + column(BalancePercentVarianceACY; "% of Bal. Variance (ACY)") { IncludeCaption = true; } + } + + trigger OnAfterGetRecord() + begin + Clear(EXRTrialBalanceBuffer); + EXRTrialBalanceBuffer.DeleteAll(); + IndentedAccountName := PadStr('', TrialBalancePreviousYearData.Indentation * 2, ' ') + TrialBalancePreviousYearData.Name; + + BuildDataset(TrialBalancePreviousYearData); + end; + } + dataitem(Dimension1; "Dimension Value") + { + DataItemTableView = sorting("Code") where("Global Dimension No." = const(1)); + + column(Dim1Code; Dimension1."Code") { IncludeCaption = true; } + column(Dim1Name; Dimension1.Name) { IncludeCaption = true; } + } + dataitem(Dimension2; "Dimension Value") + { + DataItemTableView = sorting("Code") where("Global Dimension No." = const(2)); + + column(Dim2Code; Dimension2."Code") { IncludeCaption = true; } + column(Dim2Name; Dimension2.Name) { IncludeCaption = true; } + } + } + requestpage + { + SaveValues = true; + AboutTitle = 'Trial Balance/Previous Year Excel'; + AboutText = 'This report contains aggregated general ledger data for the trial balance with debit/credit columns for net change and balance. A report is shown for both local currency (LCY) and additional reporting currency (ACY, the latter only showing data if Additional Reporting Currency is in use. In addition to debit/credit for net change and balance the report shows the net debit/credit amount for both net change and balance for comparison. The aggregation is for the period specified in the report''s request page''s Datefilter parameter and summarized per the 2 global dimensions per g/l account category.'; + } + rendering + { + layout(TrialBalancePrevYearExcelLayout) + { + Type = Excel; + LayoutFile = './ReportLayouts/Excel/GeneralLedger/TrialBalancePrevYearExcel.xlsx'; + Caption = 'Trial Balance/Previous Year Excel'; + Summary = 'Built in layout for the Trial Balance/Previous Year Excel report.This report contains aggregated general ledger data for the trial balance with debit/credit columns for net change and balance. Report uses Query connections.'; + } + } + labels + { + DataRetrieved = 'Data retrieved:'; + TrialBalanceLCY = 'Trial Balance (LCY)'; + TrialBalanceACY = 'Trial Balance (ACY)'; + TrialBalancevsLastPeriodACY = 'Trial Balance vs. Last Period (Additional Reporting Currency)'; + TrialBalancevsLastPeriod = 'Trial Balance vs. Last Period'; + } + trigger OnPreReport() + begin + TrialBalancePreviousYearData.SecurityFiltering(SecurityFilter::Filtered); + CompanyInformation.Get(); + + FromDate := TrialBalancePreviousYearData.GetRangeMin("Date Filter"); + ToDate := TrialBalancePreviousYearData.GetRangeMax("Date Filter"); + PriorFromDate := CalcDate('<-1Y>', FromDate + 1) - 1; + PriorToDate := CalcDate('<-1Y>', ToDate + 1) - 1; + end; + + protected var + CompanyInformation: Record "Company Information"; + FromDate: Date; + PriorFromDate: Date; + PriorToDate: Date; + ToDate: Date; + IndentedAccountName: Text; + + local procedure BuildDataset(var GLAccount: Record "G/L Account") + var + DimensionValue1: Record "Dimension Value"; + DimensionValue2: Record "Dimension Value"; + begin + DimensionValue1.SetRange("Global Dimension No.", 1); + DimensionValue2.SetRange("Global Dimension No.", 2); + + InsertGLAccountData(GLAccount, DimensionValue1, DimensionValue2); + end; + + local procedure InsertGLAccountData(var GLAccount: Record "G/L Account"; var DimensionValue1: Record "Dimension Value"; var DimensionValue2: Record "Dimension Value") + begin + AddGLToDataset(GLAccount, '', ''); + + if DimensionValue1.FindSet() then + repeat + AddGLToDataset(GLAccount, DimensionValue1."Code", ''); + if DimensionValue2.FindSet() then + repeat + AddGLToDataset(GLAccount, DimensionValue1."Code", DimensionValue2."Code"); + until DimensionValue2.Next() = 0; + until DimensionValue1.Next() = 0; + + if DimensionValue2.FindSet() then + repeat + AddGLToDataset(GLAccount, '', DimensionValue2."Code"); + until DimensionValue2.Next() = 0; + end; + + local procedure AddGLToDataset(var GLAccount: Record "G/L Account"; Dimension1Code: Code[20]; Dimension2Code: Code[20]) + var + LocalGLAccount: Record "G/L Account"; + LocalGLAccountLastPeriod: Record "G/L Account"; + begin + LocalGLAccount.Copy(GLAccount); + LocalGLAccount.SetRange("Global Dimension 1 Filter", Dimension1Code); + LocalGLAccount.SetRange("Global Dimension 2 Filter", Dimension2Code); + + LocalGLAccount.CalcFields("Net Change", "Balance at Date", "Additional-Currency Net Change", "Add.-Currency Balance at Date"); + LocalGLAccountLastPeriod.Copy(LocalGLAccount); + LocalGLAccountLastPeriod.SetRange("Date Filter", PriorFromDate, PriorToDate); + LocalGLAccountLastPeriod.CalcFields("Net Change", "Balance at Date", "Additional-Currency Net Change", "Add.-Currency Balance at Date"); + + Clear(EXRTrialBalanceBuffer); + EXRTrialBalanceBuffer."G/L Account No." := LocalGLAccount."No."; + EXRTrialBalanceBuffer."Dimension 1 Code" := Dimension1Code; + EXRTrialBalanceBuffer."Dimension 2 Code" := Dimension2Code; + + EXRTrialBalanceBuffer.Validate("Net Change", LocalGLAccount."Net Change"); + EXRTrialBalanceBuffer.Validate("Balance", LocalGLAccount."Balance at Date"); + EXRTrialBalanceBuffer.Validate("Last Period Net", LocalGLAccountLastPeriod."Net Change"); + EXRTrialBalanceBuffer.Validate("Last Period Bal.", LocalGLAccountLastPeriod."Balance at Date"); + + EXRTrialBalanceBuffer.Validate("Net Change (ACY)", LocalGLAccount."Additional-Currency Net Change"); + EXRTrialBalanceBuffer.Validate("Balance (ACY)", LocalGLAccount."Add.-Currency Balance at Date"); + EXRTrialBalanceBuffer.Validate("Last Period Net (ACY)", LocalGLAccountLastPeriod."Additional-Currency Net Change"); + EXRTrialBalanceBuffer.Validate("Last Period Bal. (ACY)", LocalGLAccountLastPeriod."Add.-Currency Balance at Date"); + EXRTrialBalanceBuffer.CalculateVariances(); + EXRTrialBalanceBuffer.Insert(true); + end; +} + diff --git a/Apps/W1/ExcelReports/app/src/Financials/EXRTrialBalanceBudgetExcel.Report.al b/Apps/W1/ExcelReports/app/src/Financials/EXRTrialBalanceBudgetExcel.Report.al new file mode 100644 index 0000000000..ae6b091272 --- /dev/null +++ b/Apps/W1/ExcelReports/app/src/Financials/EXRTrialBalanceBudgetExcel.Report.al @@ -0,0 +1,159 @@ +// ------------------------------------------------------------------------------------------------ +// 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.ExcelReports; + +using Microsoft.Finance.GeneralLedger.Account; +using Microsoft.Finance.Dimension; +using Microsoft.Foundation.Company; + +report 4406 "EXR Trial BalanceBudgetExcel" +{ + ApplicationArea = All; + Caption = 'Trial Balance/Budget Excel (Preview)'; + DataAccessIntent = ReadOnly; + DefaultRenderingLayout = TrialBalanceBudgetExcelLayout; + ExcelLayoutMultipleDataSheets = true; + UsageCategory = ReportsAndAnalysis; + MaximumDatasetSize = 1000000; + + dataset + { + dataitem(TrialBalanceBudgetData; "G/L Account") + { + DataItemTableView = sorting("No."); + RequestFilterFields = "No.", "Account Type", "Date Filter", "Budget Filter"; + column(AccountNumber; "No.") { IncludeCaption = true; } + column(AccountName; Name) { IncludeCaption = true; } + column(IncomeBalance; "Income/Balance") { IncludeCaption = true; } + column(AccountCategory; "Account Category") { IncludeCaption = true; } + column(AccountSubcategory; "Account Subcategory Descript.") { IncludeCaption = true; } + column(AccountType; "Account Type") { IncludeCaption = true; } + column(Indentation; Indentation) { IncludeCaption = true; } + column(IndentedAccountName; IndentedAccountName) { } + + dataitem(EXRTrialBalanceBuffer; "EXR Trial Balance Buffer") + { + DataItemLink = "G/L Account No." = field("No."); + column(Account; "G/L Account No.") { IncludeCaption = true; } + column(Dimension1Code; "Dimension 1 Code") { IncludeCaption = true; } + column(Dimension2Code; "Dimension 2 Code") { IncludeCaption = true; } + column(NetChange; "Net Change") { IncludeCaption = true; } + column(Balance; Balance) { IncludeCaption = true; } + column(NetBudget; "Budget (Net)") { IncludeCaption = true; } + column(BalanceBudget; "Budget (Bal. at Date)") { IncludeCaption = true; } + column(BudgetNetPct; "% of Budget Net") { IncludeCaption = true; } + column(BudgetBalPct; "% of Budget Bal.") { IncludeCaption = true; } + } + trigger OnAfterGetRecord() + begin + Clear(EXRTrialBalanceBuffer); + EXRTrialBalanceBuffer.DeleteAll(); + IndentedAccountName := PadStr('', TrialBalanceBudgetData.Indentation * 2, ' ') + TrialBalanceBudgetData.Name; + + BuildDataset(TrialBalanceBudgetData); + end; + } + dataitem(Dimension1; "Dimension Value") + { + DataItemTableView = sorting("Code") where("Global Dimension No." = const(1)); + + column(Dim1Code; Dimension1."Code") { IncludeCaption = true; } + column(Dim1Name; Dimension1.Name) { IncludeCaption = true; } + } + dataitem(Dimension2; "Dimension Value") + { + DataItemTableView = sorting("Code") where("Global Dimension No." = const(2)); + + column(Dim2Code; Dimension2."Code") { IncludeCaption = true; } + column(Dim2Name; Dimension2.Name) { IncludeCaption = true; } + } + } + requestpage + { + SaveValues = true; + AboutTitle = 'Trial Balance/Budget Excel'; + AboutText = 'This report contains aggregated general ledger data for the trial balance with debit/credit columns for net change and balance. A report is shown for both local currency (LCY) and additional reporting currency (ACY, the latter only showing data if Additional Reporting Currency is in use. In addition to debit/credit for net change and balance the report shows the net debit/credit amount for both net change and balance for comparison. The aggregation is for the period specified in the report''s request page''s Datefilter parameter and summarized per the 2 global dimensions per g/l account category.'; + } + rendering + { + layout(TrialBalanceBudgetExcelLayout) + { + Type = Excel; + LayoutFile = './ReportLayouts/Excel/GeneralLedger/TrialBalanceBudgetExcel.xlsx'; + Caption = 'Trial Balance/Budget Excel'; + Summary = 'Built in layout for Trial Balance/Budget Excel. Customer facing sheet contains a pivot table that shows the account balance in local currency and additional reporting currencies. Report uses Query connections.'; + } + } + + labels + { + DataRetrieved = 'Data retrieved:'; + NetBudgetLabel = 'Net Budget'; + BalanceBudgetLabel = 'Budget Balance'; + TrialBalancevsBudget = 'Trial Balance vs. Budget'; + } + trigger OnPreReport() + begin + TrialBalanceBudgetData.SecurityFiltering(SecurityFilter::Filtered); + CompanyInformation.Get(); + end; + + protected var + CompanyInformation: Record "Company Information"; + IndentedAccountName: Text; + + local procedure BuildDataset(var GLAccount: Record "G/L Account") + var + DimensionValue1: Record "Dimension Value"; + DimensionValue2: Record "Dimension Value"; + begin + DimensionValue1.SetRange("Global Dimension No.", 1); + DimensionValue2.SetRange("Global Dimension No.", 2); + + InsertGLAccountData(GLAccount, DimensionValue1, DimensionValue2); + end; + + local procedure InsertGLAccountData(var GLAccount: Record "G/L Account"; var DimensionValue1: Record "Dimension Value"; var DimensionValue2: Record "Dimension Value") + begin + AddGLToDataset(GLAccount, '', ''); + + if DimensionValue1.FindSet() then + repeat + AddGLToDataset(GLAccount, DimensionValue1."Code", ''); + if DimensionValue2.FindSet() then + repeat + AddGLToDataset(GLAccount, DimensionValue1."Code", DimensionValue2."Code"); + until DimensionValue2.Next() = 0; + until DimensionValue1.Next() = 0; + + if DimensionValue2.FindSet() then + repeat + AddGLToDataset(GLAccount, '', DimensionValue2."Code"); + until DimensionValue2.Next() = 0; + end; + + local procedure AddGLToDataset(var GLAccount: Record "G/L Account"; Dimension1Code: Code[20]; Dimension2Code: Code[20]) + var + LocalGLAccount: Record "G/L Account"; + begin + LocalGLAccount.Copy(GLAccount); + LocalGLAccount.SetFilter("Global Dimension 1 Code", Dimension1Code); + LocalGLAccount.SetFilter("Global Dimension 2 Code", Dimension2Code); + + LocalGLAccount.CalcFields("Net Change", "Balance at Date", "Budgeted Amount", "Budget at Date"); + + Clear(EXRTrialBalanceBuffer); + EXRTrialBalanceBuffer."G/L Account No." := LocalGLAccount."No."; + EXRTrialBalanceBuffer."Dimension 1 Code" := Dimension1Code; + EXRTrialBalanceBuffer."Dimension 2 Code" := Dimension2Code; + EXRTrialBalanceBuffer.Validate("Net Change", LocalGLAccount."Net Change"); + EXRTrialBalanceBuffer.Validate(Balance, LocalGLAccount."Balance at Date"); + EXRTrialBalanceBuffer.Validate("Budget (Net)", LocalGLAccount."Budgeted Amount"); + EXRTrialBalanceBuffer.Validate("Budget (Bal. at Date)", LocalGLAccount."Budget at Date"); + EXRTrialBalanceBuffer.CalculateBudgetComparisons(); + EXRTrialBalanceBuffer.Insert(true); + end; +} \ No newline at end of file diff --git a/Apps/W1/ExcelReports/app/src/Financials/EXRTrialBalanceBuffer.Table.al b/Apps/W1/ExcelReports/app/src/Financials/EXRTrialBalanceBuffer.Table.al new file mode 100644 index 0000000000..11629d51ee --- /dev/null +++ b/Apps/W1/ExcelReports/app/src/Financials/EXRTrialBalanceBuffer.Table.al @@ -0,0 +1,336 @@ +// ------------------------------------------------------------------------------------------------ +// 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.ExcelReports; + +using Microsoft.Finance.GeneralLedger.Account; + +table 4402 "EXR Trial Balance Buffer" +{ + Caption = 'Trial Balance Buffer'; + DataClassification = CustomerContent; + TableType = Temporary; + + fields + { + field(1; "G/L Account No."; Code[20]) + { + Caption = 'G/L Account No.'; + } + field(2; "Dimension 1 Code"; Code[20]) + { + CaptionClass = '1,2,1'; + Caption = 'Dimension 1 Code'; + } + field(3; "Dimension 2 Code"; Code[20]) + { + CaptionClass = '1,2,2'; + Caption = 'Dimension 2 Code'; + } + field(4; "Period Start"; Date) + { + Caption = 'Period Start'; + } + field(5; "Period End"; Date) + { + Caption = 'Period End'; + } + field(10; "Net Change"; Decimal) + { + Caption = 'Net Change'; + + trigger OnValidate() + begin + if ("Net Change" > 0) then + Validate("Net Change (Debit)", "Net Change") + else + Validate("Net Change (Credit)", -"Net Change"); + end; + } + field(11; "Net Change (Debit)"; Decimal) + { + Caption = 'Net Change (Debit)'; + } + field(12; "Net Change (Credit)"; Decimal) + { + Caption = 'Net Change (Credit)'; + } + field(13; Balance; Decimal) + { + Caption = 'Balance'; + + trigger OnValidate() + begin + if ("Balance" > 0) then + Validate("Balance (Debit)", "Balance") + else + Validate("Balance (Credit)", -"Balance"); + end; + } + field(14; "Balance (Debit)"; Decimal) + { + Caption = 'Balance (Debit)'; + } + field(15; "Balance (Credit)"; Decimal) + { + Caption = 'Balance (Credit)'; + } + field(20; "Budget (Net)"; Decimal) + { + Caption = 'Budget'; + } + field(21; "% of Budget Net"; Decimal) + { + Caption = '% of Budget Net'; + } + field(22; "Budget (Bal. at Date)"; Decimal) + { + Caption = 'Budget (Bal. at Date)'; + } + field(23; "% of Budget Bal."; Decimal) + { + Caption = '% of Budget Bal.'; + } + field(50; "Last Period Net"; Decimal) + { + Caption = 'Last Period Net'; + + trigger OnValidate() + begin + if ("Last Period Net" > 0) then + Validate("Last Period Net (Debit)", "Last Period Net") + else + Validate("Last Period Net (Credit)", -"Last Period Net"); + end; + } + field(51; "Last Period Net (Debit)"; Decimal) + { + Caption = 'Last Period Net (Debit)'; + } + field(52; "Last Period Net (Credit)"; Decimal) + { + Caption = 'Last Period Net (Credit)'; + } + field(60; "Last Period Bal."; Decimal) + { + Caption = 'Last Period Bal.'; + + trigger OnValidate() + begin + if ("Last Period Bal." > 0) then + Validate("Last Period Bal. (Debit)", "Last Period Bal.") + else + Validate("Last Period Bal. (Credit)", -"Last Period Bal."); + end; + } + field(61; "Last Period Bal. (Debit)"; Decimal) + { + Caption = 'Last Period Bal. (Debit)'; + } + field(62; "Last Period Bal. (Credit)"; Decimal) + { + Caption = 'Last Period Bal. (Credit)'; + } + field(70; "Net Variance"; Decimal) + { + Caption = 'Net Variance'; + } + field(71; "% of Net Variance"; Decimal) + { + Caption = '% of Net Variance'; + } + field(80; "Bal. Variance"; Decimal) + { + Caption = 'Bal. Variance'; + } + field(81; "% of Bal. Variance"; Decimal) + { + Caption = '% of Bal. Variance'; + } + field(110; "Net Change (ACY)"; Decimal) + { + Caption = 'Net Change'; + + trigger OnValidate() + begin + if ("Net Change" > 0) then + Validate("Net Change (Debit) (ACY)", "Net Change (ACY)") + else + Validate("Net Change (Credit) (ACY)", -"Net Change (ACY)"); + end; + } + field(111; "Net Change (Debit) (ACY)"; Decimal) + { + Caption = 'Net Change (Debit)'; + } + field(112; "Net Change (Credit) (ACY)"; Decimal) + { + Caption = 'Net Change (Credit)'; + } + field(113; "Balance (ACY)"; Decimal) + { + Caption = 'Balance'; + + trigger OnValidate() + begin + if ("Balance" > 0) then + Validate("Balance (Debit) (ACY)", "Balance (ACY)") + else + Validate("Balance (Credit) (ACY)", -"Balance (ACY)"); + end; + } + field(114; "Balance (Debit) (ACY)"; Decimal) + { + Caption = 'Balance (Debit)'; + } + field(115; "Balance (Credit) (ACY)"; Decimal) + { + Caption = 'Balance (Credit)'; + } + field(150; "Last Period Net (ACY)"; Decimal) + { + Caption = 'Last Period Net'; + + trigger OnValidate() + begin + if ("Last Period Net" > 0) then + Validate("Last Period Net (Debit) (ACY)", "Last Period Net (ACY)") + else + Validate("Last Period Net (Credit) (ACY)", -"Last Period Net (ACY)"); + end; + } + field(151; "Last Period Net (Debit) (ACY)"; Decimal) + { + Caption = 'Last Period Net (Debit)'; + } + field(152; "Last Period Net (Credit) (ACY)"; Decimal) + { + Caption = 'Last Period Net (Credit)'; + } + field(160; "Last Period Bal. (ACY)"; Decimal) + { + Caption = 'Last Period Bal.'; + + trigger OnValidate() + begin + if ("Last Period Bal." > 0) then + Validate("Last Period Bal. (Debit) (ACY)", "Last Period Bal. (ACY)") + else + Validate("Last Period Bal. (Cred.) (ACY)", -"Last Period Bal. (ACY)"); + end; + } + field(161; "Last Period Bal. (Debit) (ACY)"; Decimal) + { + Caption = 'Last Period Bal. (Debit)'; + } + field(162; "Last Period Bal. (Cred.) (ACY)"; Decimal) + { + Caption = 'Last Period Bal. (Credit)'; + } + field(170; "Net Variance (ACY)"; Decimal) + { + Caption = 'Net Variance'; + } + field(171; "% of Net Variance (ACY)"; Decimal) + { + Caption = '% of Net Variance'; + } + field(180; "Bal. Variance (ACY)"; Decimal) + { + Caption = 'Bal. Variance'; + } + field(181; "% of Bal. Variance (ACY)"; Decimal) + { + Caption = '% of Bal. Variance'; + } + field(200; "All Zero"; Boolean) + { + Caption = 'All Zero'; + } + field(1000; "Account Type"; Enum "G/L Account Type") + { + CalcFormula = lookup("G/L Account"."Account Type" where("No." = field("G/L Account No."))); + Caption = 'Account Type'; + Editable = false; + FieldClass = FlowField; + } + } + keys + { + key(PK; "G/L Account No.", "Dimension 1 Code", "Dimension 2 Code", "Period Start") + { + Clustered = true; + } + } + + trigger OnInsert() + begin + CheckAllZero(); + end; + + trigger OnModify() + begin + CheckAllZero(); + end; + + internal procedure CalculateVariances() + begin + if ("Net Change" <> 0) and ("Last Period Net" <> 0) then begin + "Net Variance" := "Net Change" - "Last Period Net"; + "% of Net Variance" := "Net Variance" / "Last Period Net"; + end; + if ("Balance" <> 0) and ("Last Period Bal." <> 0) then begin + "Bal. Variance" := "Balance" - "Last Period Bal."; + "% of Bal. Variance" := "Bal. Variance" / "Last Period Bal."; + end; + if ("Net Change (ACY)" <> 0) and ("Last Period Net (ACY)" <> 0) then begin + "Net Variance (ACY)" := "Net Change (ACY)" - "Last Period Net (ACY)"; + "% of Net Variance (ACY)" := "Net Variance (ACY)" / "Last Period Net (ACY)"; + end; + if ("Balance (ACY)" <> 0) and ("Last Period Bal. (ACY)" <> 0) then begin + "Bal. Variance (ACY)" := "Balance (ACY)" - "Last Period Bal. (ACY)"; + "% of Bal. Variance (ACY)" := "Bal. Variance (ACY)" / "Last Period Bal. (ACY)"; + end; + end; + + internal procedure CalculateBudgetComparisons() + begin + // and budget % comparison + if ("Budget (Net)" <> 0) and ("Net Change" <> 0) then + "% of Budget Net" := "Net Change" / "Budget (Net)"; + if ("Budget (Bal. at Date)" <> 0) and ("Balance" <> 0) then + "% of Budget Bal." := "Balance" / "Budget (Bal. at Date)"; + end; + + internal procedure CalculatePriorComparisons() + begin + if ("Net Change" <> 0) and ("Last Period Net" <> 0) then + "% of Net Variance" := "Net Change" / "Last Period Net"; + if ("Balance" <> 0) and ("Last Period Bal." <> 0) then + "% of Bal. Variance" := "Balance" / "Last Period Bal."; + if ("Net Change (ACY)" <> 0) and ("Last Period Net (ACY)" <> 0) then + "% of Net Variance (ACY)" := "Net Change (ACY)" / "Last Period Net (ACY)"; + if ("Balance (ACY)" <> 0) and ("Last Period Bal. (ACY)" <> 0) then + "% of Bal. Variance (ACY)" := "Balance (ACY)" / "Last Period Bal. (ACY)"; + end; + + internal procedure CheckAllZero() + begin + // if all the key values are zero, then set the All Zero field to true + "All Zero" := ("Net Change" = 0) and + ("Balance" = 0) and + ("Budget (Net)" = 0) and + ("Last Period Net" = 0) and + ("Last Period Bal." = 0) and + ("Net Variance" = 0) and + ("Bal. Variance" = 0) and + ("Net Change (ACY)" = 0) and + ("Balance (ACY)" = 0) and + ("Last Period Net (ACY)" = 0) and + ("Last Period Bal. (ACY)" = 0) and + ("Net Variance (ACY)" = 0) and + ("Bal. Variance (ACY)" = 0); + end; +} diff --git a/Apps/W1/ExcelReports/app/src/Financials/EXRTrialBalanceExcel.Report.al b/Apps/W1/ExcelReports/app/src/Financials/EXRTrialBalanceExcel.Report.al new file mode 100644 index 0000000000..8882a18f26 --- /dev/null +++ b/Apps/W1/ExcelReports/app/src/Financials/EXRTrialBalanceExcel.Report.al @@ -0,0 +1,167 @@ +// ------------------------------------------------------------------------------------------------ +// 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.ExcelReports; + +using Microsoft.Finance.GeneralLedger.Account; +using Microsoft.Finance.Dimension; +using Microsoft.Foundation.Company; + +report 4405 "EXR Trial Balance Excel" +{ + AdditionalSearchTerms = 'year closing,close accounting period,close fiscal year'; + ApplicationArea = All; + Caption = 'Trial Balance Excel (Preview)'; + DataAccessIntent = ReadOnly; + DefaultRenderingLayout = TrialBalanceExcelLayout; + ExcelLayoutMultipleDataSheets = true; + UsageCategory = ReportsAndAnalysis; + MaximumDatasetSize = 1000000; + + dataset + { + dataitem(TrialBalanceData; "G/L Account") + { + DataItemTableView = sorting("No."); + RequestFilterFields = "No.", "Account Type", "Date Filter", "Budget Filter"; + column(AccountNumber; "No.") { IncludeCaption = true; } + column(AccountName; Name) { IncludeCaption = true; } + column(IncomeBalance; "Income/Balance") { IncludeCaption = true; } + column(AccountCategory; "Account Category") { IncludeCaption = true; } + column(AccountSubcategory; "Account Subcategory Descript.") { IncludeCaption = true; } + column(AccountType; "Account Type") { IncludeCaption = true; } + column(Indentation; Indentation) { IncludeCaption = true; } + column(IndentedAccountName; IndentedAccountName) { } + + dataitem(EXRTrialBalanceBuffer; "EXR Trial Balance Buffer") + { + DataItemLink = "G/L Account No." = field("No."); + column(Account; "G/L Account No.") { IncludeCaption = true; } + column(Dimension1Code; "Dimension 1 Code") { IncludeCaption = true; } + column(Dimension2Code; "Dimension 2 Code") { IncludeCaption = true; } + column(NetChange; "Net Change") { IncludeCaption = true; } + column(NetChangeDebit; "Net Change (Debit)") { IncludeCaption = true; } + column(NetChangeCredit; "Net Change (Credit)") { IncludeCaption = true; } + column(Balance; Balance) { IncludeCaption = true; } + column(BalanceDebit; "Balance (Debit)") { IncludeCaption = true; } + column(BalanceCredit; "Balance (Credit)") { IncludeCaption = true; } + column(NetChangeACY; "Net Change (ACY)") { IncludeCaption = true; } + column(NetChangeDebitACY; "Net Change (Debit) (ACY)") { IncludeCaption = true; } + column(NetChangeCreditACY; "Net Change (Credit) (ACY)") { IncludeCaption = true; } + column(BalanceACY; "Balance (ACY)") { IncludeCaption = true; } + column(BalanceDebitACY; "Balance (Debit) (ACY)") { IncludeCaption = true; } + column(BalanceCreditACY; "Balance (Credit) (ACY)") { IncludeCaption = true; } + } + + trigger OnAfterGetRecord() + begin + Clear(EXRTrialBalanceBuffer); + EXRTrialBalanceBuffer.DeleteAll(); + IndentedAccountName := PadStr('', TrialBalanceData.Indentation * 2, ' ') + TrialBalanceData.Name; + + BuildDataset(TrialBalanceData); + end; + } + dataitem(Dimension1; "Dimension Value") + { + DataItemTableView = sorting("Code") where("Global Dimension No." = const(1)); + + column(Dim1Code; Dimension1."Code") { IncludeCaption = true; } + column(Dim1Name; Dimension1.Name) { IncludeCaption = true; } + } + dataitem(Dimension2; "Dimension Value") + { + DataItemTableView = sorting("Code") where("Global Dimension No." = const(2)); + + column(Dim2Code; Dimension2."Code") { IncludeCaption = true; } + column(Dim2Name; Dimension2.Name) { IncludeCaption = true; } + } + } + requestpage + { + SaveValues = true; + AboutTitle = 'Trial Balance Excel'; + AboutText = 'This report contains aggregated general ledger data for the trial balance with debit/credit columns for net change and balance. A report is shown for both local currency (LCY) and additional reporting currency (ACY), the latter only showing data if Additional Reporting Currency is in use. The aggregation is for the period specified in the report''s request page''s Datefilter parameter and summarized per the 2 global dimensions per g/l account category.'; + } + rendering + { + layout(TrialBalanceExcelLayout) + { + Type = Excel; + LayoutFile = './ReportLayouts/Excel/GeneralLedger/TrialBalanceExcel.xlsx'; + Caption = 'Trial Balance Excel'; + Summary = 'Built in layout for Trial Balance Excel. This report contains aggregated general ledger data for the trial balance with debit/credit columns for net change and balance. Report uses Query connections.'; + } + } + labels + { + TrialBalanceLCY = 'Trial Balance (LCY)'; + TrialBalanceACYSheet = 'Trial Balance (ACY)'; + TrialBalanceACY = 'Trial Balance (Additional Reporting Currency)'; + DataRetrieved = 'Data retrieved:'; + } + + trigger OnPreReport() + begin + TrialBalanceData.SecurityFiltering(SecurityFilter::Filtered); + CompanyInformation.Get(); + end; + + protected var + CompanyInformation: Record "Company Information"; + IndentedAccountName: Text; + + local procedure BuildDataset(var GLAccount: Record "G/L Account") + var + DimensionValue1: Record "Dimension Value"; + DimensionValue2: Record "Dimension Value"; + begin + DimensionValue1.SetRange("Global Dimension No.", 1); + DimensionValue2.SetRange("Global Dimension No.", 2); + + InsertGLAccountData(GLAccount, DimensionValue1, DimensionValue2); + end; + + local procedure InsertGLAccountData(var GLAccount: Record "G/L Account"; var DimensionValue1: Record "Dimension Value"; var DimensionValue2: Record "Dimension Value") + begin + AddGLToDataset(GLAccount, '', ''); + + if DimensionValue1.FindSet() then + repeat + AddGLToDataset(GLAccount, DimensionValue1."Code", ''); + if DimensionValue2.FindSet() then + repeat + AddGLToDataset(GLAccount, DimensionValue1."Code", DimensionValue2."Code"); + until DimensionValue2.Next() = 0; + until DimensionValue1.Next() = 0; + + if DimensionValue2.FindSet() then + repeat + AddGLToDataset(GLAccount, '', DimensionValue2."Code"); + until DimensionValue2.Next() = 0; + end; + + local procedure AddGLToDataset(var GLAccount: Record "G/L Account"; Dimension1Code: Code[20]; Dimension2Code: Code[20]) + var + LocalGLAccount: Record "G/L Account"; + begin + LocalGLAccount.Copy(GLAccount); + LocalGLAccount.SetFilter("Global Dimension 1 Code", Dimension1Code); + LocalGLAccount.SetFilter("Global Dimension 2 Code", Dimension2Code); + + LocalGLAccount.CalcFields("Net Change", "Balance at Date", "Additional-Currency Net Change", "Add.-Currency Balance at Date"); + + Clear(EXRTrialBalanceBuffer); + EXRTrialBalanceBuffer."G/L Account No." := LocalGLAccount."No."; + EXRTrialBalanceBuffer."Dimension 1 Code" := Dimension1Code; + EXRTrialBalanceBuffer."Dimension 2 Code" := Dimension2Code; + EXRTrialBalanceBuffer.Validate("Net Change", LocalGLAccount."Net Change"); + EXRTrialBalanceBuffer.Validate(Balance, LocalGLAccount."Balance at Date"); + EXRTrialBalanceBuffer.Validate("Net Change (ACY)", LocalGLAccount."Additional-Currency Net Change"); + EXRTrialBalanceBuffer.Validate("Balance (ACY)", LocalGLAccount."Add.-Currency Balance at Date"); + EXRTrialBalanceBuffer.Insert(true); + end; +} + diff --git a/Apps/W1/ExcelReports/app/src/Financials/EXRTrialBalbyPeriodExcel.Report.al b/Apps/W1/ExcelReports/app/src/Financials/EXRTrialBalbyPeriodExcel.Report.al new file mode 100644 index 0000000000..d0a73ee9b9 --- /dev/null +++ b/Apps/W1/ExcelReports/app/src/Financials/EXRTrialBalbyPeriodExcel.Report.al @@ -0,0 +1,194 @@ +// ------------------------------------------------------------------------------------------------ +// 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.ExcelReports; + +using Microsoft.Finance.GeneralLedger.Account; +using Microsoft.Finance.Dimension; +using Microsoft.Foundation.Company; + +report 4408 "EXR Trial Bal by Period Excel" +{ + ApplicationArea = All; + Caption = 'Trial Balance by Period Excel (Preview)'; + DataAccessIntent = ReadOnly; + DefaultRenderingLayout = TrialBalancebyPeriodExcelLayout; + ExcelLayoutMultipleDataSheets = true; + UsageCategory = ReportsAndAnalysis; + MaximumDatasetSize = 1000000; + + dataset + { + dataitem(TrialBalanceByPeriod; "G/L Account") + { + DataItemTableView = sorting("No."); + RequestFilterFields = "No.", "Account Type", "Date Filter"; + column(AccountNumber; "No.") { IncludeCaption = true; } + column(AccountName; Name) { IncludeCaption = true; } + column(IncomeBalance; "Income/Balance") { IncludeCaption = true; } + column(AccountCategory; "Account Category") { IncludeCaption = true; } + column(AccountSubcategory; "Account Subcategory Descript.") { IncludeCaption = true; } + column(AccountType; "Account Type") { IncludeCaption = true; } + column(Indentation; Indentation) { IncludeCaption = true; } + column(IndentedAccountName; IndentedAccountName) { } + + dataitem(EXRTrialBalanceBuffer; "EXR Trial Balance Buffer") + { + DataItemLink = "G/L Account No." = field("No."); + column(Account; "G/L Account No.") { IncludeCaption = true; } + column(Dimension1Code; "Dimension 1 Code") { IncludeCaption = true; } + column(Dimension2Code; "Dimension 2 Code") { IncludeCaption = true; } + column(NetChange; "Net Change") { IncludeCaption = true; } + column(PeriodStart; "Period Start") { IncludeCaption = true; } + column(PeriodEnd; "Period End") { IncludeCaption = true; } + } + + trigger OnAfterGetRecord() + begin + Clear(EXRTrialBalanceBuffer); + EXRTrialBalanceBuffer.DeleteAll(); + IndentedAccountName := PadStr('', TrialBalanceByPeriod.Indentation * 2, ' ') + TrialBalanceByPeriod.Name; + + BuildDataset(TrialBalanceByPeriod); + end; + } + dataitem(Dimension1; "Dimension Value") + { + DataItemTableView = sorting("Code") where("Global Dimension No." = const(1)); + + column(Dim1Code; Dimension1."Code") { IncludeCaption = true; } + column(Dim1Name; Dimension1.Name) { IncludeCaption = true; } + } + dataitem(Dimension2; "Dimension Value") + { + DataItemTableView = sorting("Code") where("Global Dimension No." = const(2)); + + column(Dim2Code; Dimension2."Code") { IncludeCaption = true; } + column(Dim2Name; Dimension2.Name) { IncludeCaption = true; } + } + } + + requestpage + { + SaveValues = true; + AboutTitle = 'Trial Balance by Period Excel'; + AboutText = 'This report contains aggregated general ledger data per accounting period for the trial balance with a net debit/credit net change column for each period. The periods covered are specified in the report''s request page''s Datefilter parameter and summarized per the 2 global dimensions per g/l account category.'; + + layout + { + area(content) + { + group(Options) + { + Caption = 'Options'; + field(PeriodLengthField; PeriodLength) + { + ApplicationArea = Basic, Suite; + Caption = 'Period Length'; + ToolTip = 'Specifies the period for which data is shown in the report. For example, enter "1M" for one month, "30D" for thirty days, "3Q" for three quarters, or "5Y" for five years.'; + } + } + } + } + + trigger OnOpenPage() + begin + Evaluate(PeriodLength, '<1M>'); + end; + } + + rendering + { + layout(TrialBalancebyPeriodExcelLayout) + { + Type = Excel; + LayoutFile = './ReportLayouts/Excel/GeneralLedger/TrialBalancebyPeriodExcel.xlsx'; + Caption = 'Trial Balance by Period Excel'; + Summary = 'Built in layout for the Trial Balance by Period report. This report contains aggregated general ledger data per accounting period for the trial balance with a net debit/credit net change column for each period. Report uses Query connections.'; + } + } + labels + { + DataRetrieved = 'Data retrieved:'; + TrialBalanceByPeriod = 'Trial Balance by Period'; + YearPeriodStart = 'Year'; + } + trigger OnPreReport() + var + ThisReportingStartDate: Date; + begin + TrialBalanceByPeriod.SecurityFiltering(SecurityFilter::Filtered); + CompanyInformation.Get(); + + ReportingPeriodStartDate.Add(TrialBalanceByPeriod.GetRangeMin("Date Filter")); + ThisReportingStartDate := TrialBalanceByPeriod.GetRangeMin("Date Filter"); + repeat + ThisReportingStartDate := CalcDate(PeriodLength, ThisReportingStartDate); + ReportingPeriodEndDate.Add(CalcDate('<-1D>', ThisReportingStartDate)); + ReportingPeriodStartDate.Add(ThisReportingStartDate); + until ThisReportingStartDate >= TrialBalanceByPeriod.GetRangeMax("Date Filter"); + ReportingPeriodEndDate.Add(CalcDate('<-1D>', ThisReportingStartDate)); + end; + + protected var + CompanyInformation: Record "Company Information"; + PeriodLength: DateFormula; + IndentedAccountName: Text; + ReportingPeriodEndDate: List of [Date]; + ReportingPeriodStartDate: List of [Date]; + + local procedure BuildDataset(var GLAccount: Record "G/L Account") + var + DimensionValue1: Record "Dimension Value"; + DimensionValue2: Record "Dimension Value"; + ThisReportingEndDate: Date; + ThisReportingStartDate: Date; + i: Integer; + begin + DimensionValue1.SetRange("Global Dimension No.", 1); + DimensionValue2.SetRange("Global Dimension No.", 2); + + for i := 1 to ReportingPeriodStartDate.Count() do begin + ThisReportingStartDate := ReportingPeriodStartDate.Get(i); + ThisReportingEndDate := ReportingPeriodEndDate.Get(i); + GLAccount.SetRange("Date Filter", ThisReportingStartDate, ThisReportingEndDate); + + AddGLToDataset(GLAccount, ThisReportingStartDate, ThisReportingEndDate, '', ''); + if DimensionValue1.FindSet() then + repeat + AddGLToDataset(GLAccount, ThisReportingStartDate, ThisReportingEndDate, DimensionValue1."Code", ''); + if DimensionValue2.FindSet() then + repeat + AddGLToDataset(GLAccount, ThisReportingStartDate, ThisReportingEndDate, DimensionValue1."Code", DimensionValue2."Code"); + until DimensionValue2.Next() = 0; + until DimensionValue1.Next() = 0; + + if DimensionValue2.FindSet() then + repeat + AddGLToDataset(GLAccount, ThisReportingStartDate, ThisReportingEndDate, '', DimensionValue2."Code"); + until DimensionValue2.Next() = 0; + end; + end; + + local procedure AddGLToDataset(var GLAccount: Record "G/L Account"; PeriodStartDate: Date; PeriodEndDate: Date; Dimension1Code: Code[20]; Dimension2Code: Code[20]) + var + LocalGLAccount: Record "G/L Account"; + begin + LocalGLAccount.Copy(GLAccount); + LocalGLAccount.SetFilter("Global Dimension 1 Code", Dimension1Code); + LocalGLAccount.SetFilter("Global Dimension 2 Code", Dimension2Code); + + LocalGLAccount.CalcFields("Net Change", "Balance at Date"); + Clear(EXRTrialBalanceBuffer); + EXRTrialBalanceBuffer."G/L Account No." := LocalGLAccount."No."; + EXRTrialBalanceBuffer."Period Start" := PeriodStartDate; + EXRTrialBalanceBuffer."Period End" := PeriodEndDate; + EXRTrialBalanceBuffer."Dimension 1 Code" := Dimension1Code; + EXRTrialBalanceBuffer."Dimension 2 Code" := Dimension2Code; + EXRTrialBalanceBuffer.Validate("Net Change", LocalGLAccount."Net Change"); + EXRTrialBalanceBuffer.Validate("Balance", LocalGLAccount."Balance at Date"); + EXRTrialBalanceBuffer.Insert(true); + end; +} \ No newline at end of file diff --git a/Apps/W1/ExcelReports/app/src/Financials/EXTAgedAccCaptionHandler.Codeunit.al b/Apps/W1/ExcelReports/app/src/Financials/EXTAgedAccCaptionHandler.Codeunit.al new file mode 100644 index 0000000000..2ad3835c04 --- /dev/null +++ b/Apps/W1/ExcelReports/app/src/Financials/EXTAgedAccCaptionHandler.Codeunit.al @@ -0,0 +1,26 @@ +// ------------------------------------------------------------------------------------------------ +// 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.ExcelReports; + +codeunit 4406 "EXT Aged Acc. Caption Handler" +{ + Access = Internal; + EventSubscriberInstance = Manual; + + [EventSubscriber(ObjectType::Table, Database::"EXR Aging Report Buffer", 'OnOverrideAgedBy', '', false, false)] + local procedure HandleOverrideAgedBy(var EXRAgingReportBuffer: Record "EXR Aging Report Buffer" temporary) + begin + EXRAgingReportBuffer."Aged By" := GlobalEXRAgingReportBuffer."Aged By"; + end; + + internal procedure SetGlobalEXRAgingReportBuffer(var EXRAgingReportBuffer: Record "EXR Aging Report Buffer" temporary) + begin + GlobalEXRAgingReportBuffer.Copy(EXRAgingReportBuffer); + end; + + var + GlobalEXRAgingReportBuffer: Record "EXR Aging Report Buffer"; +} \ No newline at end of file diff --git a/Apps/W1/ExcelReports/app/src/RoleCenters/EXRARRoleCenter.PageExt.al b/Apps/W1/ExcelReports/app/src/RoleCenters/EXRARRoleCenter.PageExt.al new file mode 100644 index 0000000000..54dac2311c --- /dev/null +++ b/Apps/W1/ExcelReports/app/src/RoleCenters/EXRARRoleCenter.PageExt.al @@ -0,0 +1,63 @@ +pageextension 4405 EXRARRoleCenter extends "Account Receivables" +{ + actions + { + addlast(Reporting) + { + group("Excel Reports") + { + Caption = 'Excel Reports'; + Image = Excel; + + action(EXRTrialBalanceBudgetExcel) + { + ApplicationArea = Basic, Suite; + Caption = 'Trial Balance/Budget (Preview)'; + Image = "Report"; + RunObject = report "EXR Trial BalanceBudgetExcel"; + ToolTip = 'Open a spreadsheet that shows Trial Balance/Budget data.'; + } + action(EXRTrialBalanceExcel) + { + ApplicationArea = Basic, Suite; + Caption = 'Trial Balance (Preview)'; + Image = "Report"; + RunObject = report "EXR Trial Balance Excel"; + ToolTip = 'Open a spreadsheet that shows Trial Balance Excel data.'; + } + action(EXRTrialBalbyPeriodExcel) + { + ApplicationArea = Basic, Suite; + Caption = 'Trial Balance by Period (Preview)'; + Image = "Report"; + RunObject = report "EXR Trial Bal by Period Excel"; + ToolTip = 'Open a spreadsheet that shows Trial Balance by Period data.'; + } + action(EXRTrialBalPrevYearExcel) + { + ApplicationArea = Basic, Suite; + Caption = 'Trial Balance/Previous Year (Preview)'; + Image = "Report"; + RunObject = report "EXR Trial Bal. Prev Year Excel"; + ToolTip = 'Open a spreadsheet that shows Trial Balance/Previous Year data'; + } + action(EXRAgedAccountsRecExcel) + { + ApplicationArea = Basic, Suite; + Caption = 'Aged Accounts Receivable (Preview)'; + Image = "Report"; + RunObject = report "EXR Aged Accounts Rec Excel"; + ToolTip = 'Open a spreadsheet that shows the Aged Accounts Receivable data.'; + } + action(EXRCustomerTopListExcel) + { + ApplicationArea = Basic, Suite; + Caption = 'Customer - Top List (Preview)'; + Image = "Report"; + RunObject = report "EXR Customer Top List"; + ToolTip = 'Open a spreadsheet that shows a list of top customers.'; + } + } + } + } +} diff --git a/Apps/W1/ExcelReports/app/src/RoleCenters/EXRAccountantRoleCenter.PageExt.al b/Apps/W1/ExcelReports/app/src/RoleCenters/EXRAccountantRoleCenter.PageExt.al new file mode 100644 index 0000000000..6e9d923ec4 --- /dev/null +++ b/Apps/W1/ExcelReports/app/src/RoleCenters/EXRAccountantRoleCenter.PageExt.al @@ -0,0 +1,85 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ + +namespace Microsoft.ExcelReports; + +using Microsoft.Finance.RoleCenters; +using Microsoft.Sales.ExcelReports; +using Microsoft.Purchases.ExcelReports; +using Microsoft.Finance.ExcelReports; + +pageextension 4401 "EXR Accountant Role Center" extends "Accountant Role Center" +{ + actions + { + addlast("Excel Reports") + { + action(EXRTrialBalanceBudgetExcel) + { + ApplicationArea = Basic, Suite; + Caption = 'Trial Balance/Budget (Preview)'; + Image = "Report"; + RunObject = report "EXR Trial BalanceBudgetExcel"; + ToolTip = 'Open a spreadsheet that shows Trial Balance/Budget data.'; + } + action(EXRTrialBalanceExcel) + { + ApplicationArea = Basic, Suite; + Caption = 'Trial Balance (Preview)'; + Image = "Report"; + RunObject = report "EXR Trial Balance Excel"; + ToolTip = 'Open a spreadsheet that shows Trial Balance Excel data.'; + } + action(EXRTrialBalbyPeriodExcel) + { + ApplicationArea = Basic, Suite; + Caption = 'Trial Balance by Period (Preview)'; + Image = "Report"; + RunObject = report "EXR Trial Bal by Period Excel"; + ToolTip = 'Open a spreadsheet that shows Trial Balance by Period data.'; + } + action(EXRTrialBalPrevYearExcel) + { + ApplicationArea = Basic, Suite; + Caption = 'Trial Balance/Previous Year (Preview)'; + Image = "Report"; + RunObject = report "EXR Trial Bal. Prev Year Excel"; + ToolTip = 'Open a spreadsheet that shows Trial Balance/Previous Year data'; + } + action(EXRAgedAccountsRecExcel) + { + ApplicationArea = Basic, Suite; + Caption = 'Aged Accounts Receivable (Preview)'; + Image = "Report"; + RunObject = report "EXR Aged Accounts Rec Excel"; + ToolTip = 'Open a spreadsheet that shows the Aged Accounts Receivable data.'; + } + action(EXRCustomerTopListExcel) + { + ApplicationArea = Basic, Suite; + Caption = 'Customer - Top List (Preview)'; + Image = "Report"; + RunObject = report "EXR Customer Top List"; + ToolTip = 'Open a spreadsheet that shows a list of top customers.'; + } + action(EXRVendorTopList) + { + ApplicationArea = Basic, Suite; + Caption = 'Vendor - Top List (Preview)'; + Image = "Report"; + RunObject = report "EXR Vendor Top List"; + ToolTip = 'Open a spreadsheet that shows a list of top vendors.'; + } + action(EXRAgedAccPayableExcel) + { + ApplicationArea = Basic, Suite; + Caption = 'Aged Accounts Payable (Preview)'; + Image = "Report"; + RunObject = report "EXR Aged Acc Payable Excel"; + ToolTip = 'Open a spreadsheet that shows the Aged Accounts Payable data.'; + } + } + } +} \ No newline at end of file diff --git a/Apps/W1/ExcelReports/app/src/RoleCenters/EXRFinRoleCenter.PageExt.al b/Apps/W1/ExcelReports/app/src/RoleCenters/EXRFinRoleCenter.PageExt.al new file mode 100644 index 0000000000..8a02dec755 --- /dev/null +++ b/Apps/W1/ExcelReports/app/src/RoleCenters/EXRFinRoleCenter.PageExt.al @@ -0,0 +1,78 @@ +pageextension 4406 EXRFinRoleCenter extends "Finance Manager Role Center" +{ + actions + { + addafter(Group11) + { + group("Excel Reports") + { + Caption = 'Excel Reports'; + + action(EXRTrialBalanceBudgetExcel) + { + ApplicationArea = Basic, Suite; + Caption = 'Trial Balance/Budget (Preview)'; + Image = "Report"; + RunObject = report "EXR Trial BalanceBudgetExcel"; + ToolTip = 'Open a spreadsheet that shows Trial Balance/Budget data.'; + } + action(EXRTrialBalanceExcel) + { + ApplicationArea = Basic, Suite; + Caption = 'Trial Balance (Preview)'; + Image = "Report"; + RunObject = report "EXR Trial Balance Excel"; + ToolTip = 'Open a spreadsheet that shows Trial Balance Excel data.'; + } + action(EXRTrialBalbyPeriodExcel) + { + ApplicationArea = Basic, Suite; + Caption = 'Trial Balance by Period (Preview)'; + Image = "Report"; + RunObject = report "EXR Trial Bal by Period Excel"; + ToolTip = 'Open a spreadsheet that shows Trial Balance by Period data.'; + } + action(EXRTrialBalPrevYearExcel) + { + ApplicationArea = Basic, Suite; + Caption = 'Trial Balance/Previous Year (Preview)'; + Image = "Report"; + RunObject = report "EXR Trial Bal. Prev Year Excel"; + ToolTip = 'Open a spreadsheet that shows Trial Balance/Previous Year data'; + } + action(EXRAgedAccountsRecExcel) + { + ApplicationArea = Basic, Suite; + Caption = 'Aged Accounts Receivable (Preview)'; + Image = "Report"; + RunObject = report "EXR Aged Accounts Rec Excel"; + ToolTip = 'Open a spreadsheet that shows the Aged Accounts Receivable data.'; + } + action(EXRCustomerTopListExcel) + { + ApplicationArea = Basic, Suite; + Caption = 'Customer - Top List (Preview)'; + Image = "Report"; + RunObject = report "EXR Customer Top List"; + ToolTip = 'Open a spreadsheet that shows a list of top customers.'; + } + action(EXRVendorTopList) + { + ApplicationArea = Basic, Suite; + Caption = 'Vendor - Top List (Preview)'; + Image = "Report"; + RunObject = report "EXR Vendor Top List"; + ToolTip = 'Open a spreadsheet that shows a list of top vendors.'; + } + action(EXRAgedAccPayableExcel) + { + ApplicationArea = Basic, Suite; + Caption = 'Aged Accounts Payable (Preview)'; + Image = "Report"; + RunObject = report "EXR Aged Acc Payable Excel"; + ToolTip = 'Open a spreadsheet that shows the Aged Accounts Payable data.'; + } + } + } + } +} diff --git a/Apps/W1/ExcelReports/app/src/RoleCenters/ExtBusManagerRoleCenter.PageExt.al b/Apps/W1/ExcelReports/app/src/RoleCenters/ExtBusManagerRoleCenter.PageExt.al new file mode 100644 index 0000000000..24bfad498e --- /dev/null +++ b/Apps/W1/ExcelReports/app/src/RoleCenters/ExtBusManagerRoleCenter.PageExt.al @@ -0,0 +1,85 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ + +namespace Microsoft.ExcelReports; + +using Microsoft.Finance.RoleCenters; +using Microsoft.Sales.ExcelReports; +using Microsoft.Purchases.ExcelReports; +using Microsoft.Finance.ExcelReports; + +pageextension 4402 "EXT Bus. Manager Role Center" extends "Business Manager Role Center" +{ + actions + { + addlast("Excel Reports") + { + action(EXRTrialBalanceBudgetExcel) + { + ApplicationArea = Basic, Suite; + Caption = 'Trial Balance/Budget (Preview)'; + Image = "Report"; + RunObject = report "EXR Trial BalanceBudgetExcel"; + ToolTip = 'Open a spreadsheet that shows Trial Balance/Budget data.'; + } + action(EXRTrialBalanceExcel) + { + ApplicationArea = Basic, Suite; + Caption = 'Trial Balance (Preview)'; + Image = "Report"; + RunObject = report "EXR Trial Balance Excel"; + ToolTip = 'Open a spreadsheet that shows Trial Balance Excel data.'; + } + action(EXRTrialBalbyPeriodExcel) + { + ApplicationArea = Basic, Suite; + Caption = 'Trial Balance by Period (Preview)'; + Image = "Report"; + RunObject = report "EXR Trial Bal by Period Excel"; + ToolTip = 'Open a spreadsheet that shows Trial Balance by Period data.'; + } + action(EXRTrialBalPrevYearExcel) + { + ApplicationArea = Basic, Suite; + Caption = 'Trial Balance/Previous Year (Preview)'; + Image = "Report"; + RunObject = report "EXR Trial Bal. Prev Year Excel"; + ToolTip = 'Open a spreadsheet that shows Trial Balance/Previous Year data'; + } + action(EXRAgedAccountsRecExcel) + { + ApplicationArea = Basic, Suite; + Caption = 'Aged Accounts Receivable (Preview)'; + Image = "Report"; + RunObject = report "EXR Aged Accounts Rec Excel"; + ToolTip = 'Open a spreadsheet that shows the Aged Accounts Receivable data.'; + } + action(EXRCustomerTopListExcel) + { + ApplicationArea = Basic, Suite; + Caption = 'Customer - Top List (Preview)'; + Image = "Report"; + RunObject = report "EXR Customer Top List"; + ToolTip = 'Open a spreadsheet that shows a list of top customers.'; + } + action(EXRVendorTopList) + { + ApplicationArea = Basic, Suite; + Caption = 'Vendor - Top List (Preview)'; + Image = "Report"; + RunObject = report "EXR Vendor Top List"; + ToolTip = 'Open a spreadsheet that shows a list of top vendors.'; + } + action(EXRAgedAccPayableExcel) + { + ApplicationArea = Basic, Suite; + Caption = 'Aged Accounts Payable (Preview)'; + Image = "Report"; + RunObject = report "EXR Aged Acc Payable Excel"; + ToolTip = 'Open a spreadsheet that shows the Aged Accounts Payable data.'; + } + } + } +} \ No newline at end of file diff --git a/Apps/W1/ExcelReports/app/src/RoleCenters/ExtCompanyDetail.PageExt.al b/Apps/W1/ExcelReports/app/src/RoleCenters/ExtCompanyDetail.PageExt.al new file mode 100644 index 0000000000..9c9adcfbde --- /dev/null +++ b/Apps/W1/ExcelReports/app/src/RoleCenters/ExtCompanyDetail.PageExt.al @@ -0,0 +1,85 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ + +namespace Microsoft.ExcelReports; + +using Microsoft.Sales.ExcelReports; +using Microsoft.Purchases.ExcelReports; +using Microsoft.Finance.ExcelReports; +using Microsoft.Utilities; + +pageextension 4403 "EXT Company Detail" extends "Company Detail" +{ + actions + { + addlast("Excel Reports") + { + action(EXRTrialBalanceBudgetExcel) + { + ApplicationArea = Basic, Suite; + Caption = 'Trial Balance/Budget (Preview)'; + Image = "Report"; + RunObject = report "EXR Trial BalanceBudgetExcel"; + ToolTip = 'Open a spreadsheet that shows Trial Balance/Budget data.'; + } + action(EXRTrialBalanceExcel) + { + ApplicationArea = Basic, Suite; + Caption = 'Trial Balance (Preview)'; + Image = "Report"; + RunObject = report "EXR Trial Balance Excel"; + ToolTip = 'Open a spreadsheet that shows Trial Balance Excel data.'; + } + action(EXRTrialBalbyPeriodExcel) + { + ApplicationArea = Basic, Suite; + Caption = 'Trial Balance by Period (Preview)'; + Image = "Report"; + RunObject = report "EXR Trial Bal by Period Excel"; + ToolTip = 'Open a spreadsheet that shows Trial Balance by Period data.'; + } + action(EXRTrialBalPrevYearExcel) + { + ApplicationArea = Basic, Suite; + Caption = 'Trial Balance/Previous Year (Preview)'; + Image = "Report"; + RunObject = report "EXR Trial Bal. Prev Year Excel"; + ToolTip = 'Open a spreadsheet that shows Trial Balance/Previous Year data'; + } + action(EXRAgedAccountsRecExcel) + { + ApplicationArea = Basic, Suite; + Caption = 'Aged Accounts Receivable (Preview)'; + Image = "Report"; + RunObject = report "EXR Aged Accounts Rec Excel"; + ToolTip = 'Open a spreadsheet that shows the Aged Accounts Receivable data.'; + } + action(EXRCustomerTopListExcel) + { + ApplicationArea = Basic, Suite; + Caption = 'Customer - Top List (Preview)'; + Image = "Report"; + RunObject = report "EXR Customer Top List"; + ToolTip = 'Open a spreadsheet that shows a list of top customers.'; + } + action(EXRVendorTopList) + { + ApplicationArea = Basic, Suite; + Caption = 'Vendor - Top List (Preview)'; + Image = "Report"; + RunObject = report "EXR Vendor Top List"; + ToolTip = 'Open a spreadsheet that shows a list of top vendors.'; + } + action(EXRAgedAccPayableExcel) + { + ApplicationArea = Basic, Suite; + Caption = 'Aged Accounts Payable (Preview)'; + Image = "Report"; + RunObject = report "EXR Aged Acc Payable Excel"; + ToolTip = 'Open a spreadsheet that shows the Aged Accounts Payable data.'; + } + } + } +} \ No newline at end of file diff --git a/Apps/W1/ExcelReports/app/src/Vendor/EXRTopVendorBalance.Query.al b/Apps/W1/ExcelReports/app/src/Vendor/EXRTopVendorBalance.Query.al new file mode 100644 index 0000000000..1fadd89d09 --- /dev/null +++ b/Apps/W1/ExcelReports/app/src/Vendor/EXRTopVendorBalance.Query.al @@ -0,0 +1,45 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ + +namespace Microsoft.Purchases.ExcelReports; + +using Microsoft.Purchases.Payables; + +query 4401 "EXR Top Vendor Balance" +{ + Caption = 'Top Vendor Balance'; + OrderBy = descending(Balance_LCY); + + elements + { + dataitem(Detailed_Vendor_Ledger_Entry; "Detailed Vendor Ledg. Entry") + { + column(Vendor_No; "Vendor No.") + { + } + column(Balance_LCY; "Amount (LCY)") + { + Method = Sum; + ReverseSign = true; + } + + filter(Posting_Date; "Posting Date") + { + } + filter(InitialEntryGlobalDim1Code; "Initial Entry Global Dim. 1") + { + } + filter(InitialEntryGlobalDim2Code; "Initial Entry Global Dim. 2") + { + } + filter(Currency_Code; "Currency Code") + { + } + filter(VendorPostingGroup; "Posting Group") + { + } + } + } +} diff --git a/Apps/W1/ExcelReports/app/src/Vendor/EXRTopVendorPurchase.Query.al b/Apps/W1/ExcelReports/app/src/Vendor/EXRTopVendorPurchase.Query.al new file mode 100644 index 0000000000..03569d4547 --- /dev/null +++ b/Apps/W1/ExcelReports/app/src/Vendor/EXRTopVendorPurchase.Query.al @@ -0,0 +1,44 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ + +namespace Microsoft.Purchases.ExcelReports; + +using Microsoft.Purchases.Payables; + +query 4402 "EXR Top Vendor Purchase" +{ + Caption = 'Top Vendor Purchase'; + OrderBy = descending(Sum_Purch_LCY); + + elements + { + dataitem(Vendor_Ledger_Entry; "Vendor Ledger Entry") + { + column(Vendor_No; "Vendor No.") + { + } + column(Sum_Purch_LCY; "Purchase (LCY)") + { + Method = Sum; + ReverseSign = true; + } + filter(GlobalDimension1Code; "Global Dimension 1 Code") + { + } + filter(GlobalDimension2Code; "Global Dimension 2 Code") + { + } + filter(Currency_Code; "Currency Code") + { + } + filter(VendorPostingGroup; "Vendor Posting Group") + { + } + filter(Posting_Date; "Posting Date") + { + } + } + } +} diff --git a/Apps/W1/ExcelReports/app/src/Vendor/EXRTopVendorReportBuffer.Table.al b/Apps/W1/ExcelReports/app/src/Vendor/EXRTopVendorReportBuffer.Table.al new file mode 100644 index 0000000000..c9e33751d2 --- /dev/null +++ b/Apps/W1/ExcelReports/app/src/Vendor/EXRTopVendorReportBuffer.Table.al @@ -0,0 +1,128 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ + +namespace Microsoft.Purchases.ExcelReports; + +using Microsoft.Purchases.Vendor; +using Microsoft.Finance.Currency; +using Microsoft.Finance.Dimension; + +table 4404 "EXR Top Vendor Report Buffer" +{ + Access = Internal; + Caption = 'Top Vendor Data'; + DataClassification = CustomerContent; + TableType = Temporary; + ReplicateData = false; + + fields + { + field(1; "Vendor No."; Code[20]) + { + Caption = 'Vendor No.'; + TableRelation = "Vendor"; + } + field(2; "Vendor Name"; Text[200]) + { + Caption = 'Name'; + } + field(10; "Amount (LCY)"; Decimal) + { + Caption = 'Amount (LCY)'; + CaptionClass = '3,' + GetAmount1Caption(); + } + field(12; "Amount 2 (LCY)"; Decimal) + { + Caption = 'Amount 2 (LCY)'; + CaptionClass = '3,' + GetAmount2Caption(); + } + field(13; "Ranking Based On"; Option) + { + Caption = 'Ranking Based On'; + OptionCaption = 'Purchases (LCY), Balance (LCY)'; + OptionMembers = "Purchases (LCY)","Balance (LCY)"; + } + field(44; "Vendor Posting Group"; Code[20]) + { + Caption = 'Vendor Posting Group'; + TableRelation = "Vendor Posting Group"; + FieldClass = FlowFilter; + } + field(45; "Currency Code"; Code[10]) + { + Caption = 'Currency Code'; + TableRelation = Currency; + FieldClass = FlowFilter; + } + field(46; "Period Start Date"; Date) + { + Caption = 'Period Start Date'; + } + field(100; "Date Filter"; Date) + { + Caption = 'Date Filter'; + FieldClass = FlowFilter; + } + field(101; "Global Dimension 1 Filter"; Code[20]) + { + CaptionClass = '1,3,1'; + Caption = 'Global Dimension 1 Filter'; + FieldClass = FlowFilter; + TableRelation = "Dimension Value".Code where("Global Dimension No." = const(1)); + } + field(102; "Global Dimension 2 Filter"; Code[20]) + { + CaptionClass = '1,3,2'; + Caption = 'Global Dimension 2 Filter'; + FieldClass = FlowFilter; + TableRelation = "Dimension Value".Code where("Global Dimension No." = const(2)); + } + } + keys + { + key(PK; "Vendor No.", "Period Start Date", "Amount (LCY)") + { + Clustered = true; + } + } + + local procedure GetAmount1Caption(): Text + var + NewCaption: Text; + Handled: Boolean; + begin + OnGetAmount1Caption(Handled, NewCaption); + if not Handled then + exit(AmountLCYTok); + + exit(NewCaption); + end; + + local procedure GetAmount2Caption(): Text + var + NewCaption: Text; + Handled: Boolean; + begin + OnGetAmount2Caption(Handled, NewCaption); + if not Handled then + exit(Amount2LCYTok); + + exit(NewCaption); + end; + + [IntegrationEvent(false, false)] + local procedure OnGetAmount1Caption(var Handled: Boolean; var NewCaption: Text) + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnGetAmount2Caption(var Handled: Boolean; var NewCaption: Text) + begin + end; + + var + AmountLCYTok: Label 'Amount (LCY)'; + Amount2LCYTok: Label 'Amount 2 (LCY)'; +} diff --git a/Apps/W1/ExcelReports/app/src/Vendor/EXRVendorTopList.Report.al b/Apps/W1/ExcelReports/app/src/Vendor/EXRVendorTopList.Report.al new file mode 100644 index 0000000000..1dda3fb95d --- /dev/null +++ b/Apps/W1/ExcelReports/app/src/Vendor/EXRVendorTopList.Report.al @@ -0,0 +1,258 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ + +namespace Microsoft.Purchases.ExcelReports; + +using Microsoft.Purchases.Vendor; + +report 4404 "EXR Vendor Top List" +{ + ApplicationArea = All; + Caption = 'Vendor - Top List Excel (Preview)'; + DataAccessIntent = ReadOnly; + DefaultRenderingLayout = VendorTopTrendExcel; + ExcelLayoutMultipleDataSheets = true; + UsageCategory = ReportsAndAnalysis; + MaximumDatasetSize = 1000000; + + dataset + { + dataitem(TopVendorData; "EXR Top Vendor Report Buffer") + { + RequestFilterHeading = 'Top vendor filters'; + RequestFilterFields = "Vendor No.", "Vendor Posting Group", "Currency Code", "Date Filter"; + DataItemTableView = sorting("Amount (LCY)", "Vendor No."); + column(VendorNo; TopVendorData."Vendor No.") + { + IncludeCaption = true; + } + column(VendorName; TopVendorData."Vendor Name") + { + IncludeCaption = true; + } + column(AmountLCY; TopVendorData."Amount (LCY)") + { + IncludeCaption = true; + } + column(Amount2LCY; TopVendorData."Amount 2 (LCY)") + { + IncludeCaption = true; + } + } + } + + requestpage + { + AboutText = 'This report contains aggregated purchase (LCY) and balance (LCY) data for the top number of vendors selected. The data is aggregated for the period specified in the request page''s Datefilter parameter.'; + AboutTitle = 'Vendor - Top Trends'; + SaveValues = true; + layout + { + area(content) + { + group(Options) + { + Caption = 'Options'; + + field(Show; GlobalExtTopVendorReportBuffer."Ranking Based On") + { + ApplicationArea = Suite; + Caption = 'Show'; + OptionCaption = 'Purchases (LCY),Balance (LCY)'; + ToolTip = 'Specifies how the report will sort the vendors: Purchases, to sort by purchase volume; or balance. In either case, the vendors with the largest amounts will be shown first.'; + + trigger OnValidate() + begin + ChangeShowType(GlobalExtTopVendorReportBuffer."Ranking Based On"); + end; + } + field(Quantity; NoOfRecordsToPrint) + { + ApplicationArea = Suite; + Caption = 'Quantity'; + ToolTip = 'Specifies the number of vendors that will be included in the report.'; + } + } + } + } + + trigger OnOpenPage() + begin + NoOfRecordsToPrint := 10; + ChangeShowType(GlobalExtTopVendorReportBuffer."Ranking Based On"::"Purchases (LCY)"); + end; + } + rendering + { + layout(VendorTopTrendExcel) + { + Type = Excel; + Caption = 'Vendor - Top Trends Excel'; + LayoutFile = './ReportLayouts/Excel/Vendor/VendorTopListExcel.xlsx'; + Summary = 'Built in layout for the Vendor - Top Trends excel report. This report contains aggregated purchase (LCY) and balance (LCY) data for the top number of vendors selected. Report uses Query connections.'; + } + } + labels + { + DataRetrieved = 'Data retrieved:'; + RankAccordingTo = 'Rank according to:'; + TopVendorListLabel = 'Top Vendor List'; + } + + protected var + GlobalExtTopVendorReportBuffer: Record "EXR Top Vendor Report Buffer"; + EXTTopVendorCaptionHandler: Codeunit "EXT Top Vendor Caption Handler"; + NoOfRecordsToPrint: Integer; + + trigger OnPreReport() + begin + BindSubscription(EXTTopVendorCaptionHandler); + BuildDataSet(); + end; + + local procedure BuildDataSet() + var + VendorFilter: Text; + begin + if GlobalExtTopVendorReportBuffer."Ranking Based On" = GlobalExtTopVendorReportBuffer."Ranking Based On"::"Purchases (LCY)" then begin + VendorFilter := GetEntriesForTopVendorsBasedOnPurchases(); + FillDataForTopVendorsBasedOnPurchases(VendorFilter); + exit; + end; + + if GlobalExtTopVendorReportBuffer."Ranking Based On" = GlobalExtTopVendorReportBuffer."Ranking Based On"::"Balance (LCY)" then begin + VendorFilter := GetEntriesForTopVendorsBasedOnBalance(); + FillDataForTopVendorsBasedOnBalance(VendorFilter); + exit; + end; + end; + + local procedure GetEntriesForTopVendorsBasedOnPurchases(): Text + var + EXTTopVendorPurchase: Query "EXR Top Vendor Purchase"; + VendorFilter: Text; + begin + EXTTopVendorPurchase.TopNumberOfRows := NoOfRecordsToPrint; + TransferFilters(EXTTopVendorPurchase, TopVendorData); + EXTTopVendorPurchase.Open(); + if EXTTopVendorPurchase.Read() then + repeat + InsertAggregatedPurchases(EXTTopVendorPurchase.Vendor_No, EXTTopVendorPurchase.Sum_Purch_LCY); + VendorFilter += EXTTopVendorPurchase.Vendor_No + '|'; + until (not EXTTopVendorPurchase.Read()); + + exit(VendorFilter.TrimEnd('|')); + end; + + local procedure GetEntriesForTopVendorsBasedOnBalance(): Text + var + EXTTopVendorBalance: Query "EXR Top Vendor Balance"; + VendorFilter: Text; + begin + EXTTopVendorBalance.TopNumberOfRows := NoOfRecordsToPrint; + TransferFilters(EXTTopVendorBalance, TopVendorData); + EXTTopVendorBalance.Open(); + if EXTTopVendorBalance.Read() then + repeat + InsertAggregatedPurchases(EXTTopVendorBalance.Vendor_No, EXTTopVendorBalance.Balance_LCY); + VendorFilter += EXTTopVendorBalance.Vendor_No + '|'; + until (not EXTTopVendorBalance.Read()); + + exit(VendorFilter.TrimEnd('|')); + end; + + local procedure ChangeShowType(NewShowType: Option) + begin + GlobalExtTopVendorReportBuffer."Ranking Based On" := NewShowType; + EXTTopVendorCaptionHandler.SetRankingBasedOn(GlobalExtTopVendorReportBuffer."Ranking Based On"); + end; + + local procedure FillDataForTopVendorsBasedOnBalance(VendorFilter: Text) + var + Vendor: Record Vendor; + EXTTopVendorPurchase: Query "EXR Top Vendor Purchase"; + begin + TransferFilters(EXTTopVendorPurchase, TopVendorData); + EXTTopVendorPurchase.SetFilter(EXTTopVendorPurchase.Vendor_No, VendorFilter); + EXTTopVendorPurchase.Open(); + if EXTTopVendorPurchase.Read() then + repeat + TopVendorData.SetFilter(TopVendorData."Vendor No.", EXTTopVendorPurchase.Vendor_No); + if TopVendorData.FindFirst() then begin + TopVendorData."Amount 2 (LCY)" := EXTTopVendorPurchase.Sum_Purch_LCY; + if Vendor.Get(TopVendorData."Vendor No.") then + TopVendorData."Vendor Name" := Vendor.Name; + TopVendorData.Modify(); + end; + until (not EXTTopVendorPurchase.Read()); + end; + + local procedure FillDataForTopVendorsBasedOnPurchases(VendorFilter: Text) + var + Vendor: Record Vendor; + EXTTopVendorBalance: Query "EXR Top Vendor Balance"; + begin + TransferFilters(EXTTopVendorBalance, TopVendorData); + EXTTopVendorBalance.SetFilter(EXTTopVendorBalance.Vendor_No, VendorFilter); + EXTTopVendorBalance.Open(); + if EXTTopVendorBalance.Read() then + repeat + TopVendorData.SetFilter(TopVendorData."Vendor No.", EXTTopVendorBalance.Vendor_No); + if TopVendorData.FindFirst() then begin + TopVendorData."Amount 2 (LCY)" := EXTTopVendorBalance.Balance_LCY; + if Vendor.Get(TopVendorData."Vendor No.") then + TopVendorData."Vendor Name" := Vendor.Name; + TopVendorData.Modify(); + end; + until (not EXTTopVendorBalance.Read()); + end; + + local procedure InsertAggregatedPurchases(VendorNo: Code[20]; AmountLCY: Decimal) + begin + Clear(TopVendorData); + TopVendorData."Vendor No." := VendorNo; + TopVendorData."Amount (LCY)" := AmountLCY; + TopVendorData."Ranking Based On" := GlobalExtTopVendorReportBuffer."Ranking Based On"; + TopVendorData.Insert(); + end; + + local procedure TransferFilters(var EXTTopVendorBalance: Query "EXR Top Vendor Balance"; var EXRTopReportBuffer: Record "EXR Top Vendor Report Buffer") + begin + EXTTopVendorBalance.TopNumberOfRows := NoOfRecordsToPrint; + if EXRTopReportBuffer.GetFilter("Global Dimension 1 Filter") <> '' then + EXTTopVendorBalance.SetFilter(EXTTopVendorBalance.InitialEntryGlobalDim1Code, EXRTopReportBuffer.GetFilter("Global Dimension 1 Filter")); + + if EXRTopReportBuffer.GetFilter("Global Dimension 2 Filter") <> '' then + EXTTopVendorBalance.SetFilter(EXTTopVendorBalance.InitialEntryGlobalDim2Code, EXRTopReportBuffer.GetFilter("Global Dimension 2 Filter")); + + if EXRTopReportBuffer.GetFilter("Currency Code") <> '' then + EXTTopVendorBalance.SetFilter(EXTTopVendorBalance.Currency_Code, EXRTopReportBuffer.GetFilter("Currency Code")); + + if EXRTopReportBuffer.GetFilter("Vendor Posting Group") <> '' then + EXTTopVendorBalance.SetFilter(EXTTopVendorBalance.VendorPostingGroup, EXRTopReportBuffer.GetFilter("Vendor Posting Group")); + + if EXRTopReportBuffer.GetFilter("Date Filter") <> '' then + EXTTopVendorBalance.SetFilter(EXTTopVendorBalance.Posting_Date, EXRTopReportBuffer.GetFilter("Date Filter")); + end; + + local procedure TransferFilters(var EXTTopVendorPurchase: Query "EXR Top Vendor Purchase"; var EXRTopReportBuffer: Record "EXR Top Vendor Report Buffer") + begin + EXTTopVendorPurchase.TopNumberOfRows := NoOfRecordsToPrint; + if EXRTopReportBuffer.GetFilter("Global Dimension 1 Filter") <> '' then + EXTTopVendorPurchase.SetFilter(EXTTopVendorPurchase.GlobalDimension1Code, EXRTopReportBuffer.GetFilter("Global Dimension 1 Filter")); + + if EXRTopReportBuffer.GetFilter("Global Dimension 2 Filter") <> '' then + EXTTopVendorPurchase.SetFilter(EXTTopVendorPurchase.GlobalDimension2Code, EXRTopReportBuffer.GetFilter("Global Dimension 2 Filter")); + + if EXRTopReportBuffer.GetFilter("Currency Code") <> '' then + EXTTopVendorPurchase.SetFilter(EXTTopVendorPurchase.Currency_Code, EXRTopReportBuffer.GetFilter("Currency Code")); + + if EXRTopReportBuffer.GetFilter("Vendor Posting Group") <> '' then + EXTTopVendorPurchase.SetFilter(EXTTopVendorPurchase.VendorPostingGroup, EXRTopReportBuffer.GetFilter("Vendor Posting Group")); + + if EXRTopReportBuffer.GetFilter("Date Filter") <> '' then + EXTTopVendorPurchase.SetFilter(EXTTopVendorPurchase.Posting_Date, EXRTopReportBuffer.GetFilter("Date Filter")); + end; +} diff --git a/Apps/W1/ExcelReports/app/src/Vendor/ExtTopVendorCaptionHandler.Codeunit.al b/Apps/W1/ExcelReports/app/src/Vendor/ExtTopVendorCaptionHandler.Codeunit.al new file mode 100644 index 0000000000..94e3bb1142 --- /dev/null +++ b/Apps/W1/ExcelReports/app/src/Vendor/ExtTopVendorCaptionHandler.Codeunit.al @@ -0,0 +1,49 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ + +namespace Microsoft.Purchases.ExcelReports; + +codeunit 4404 "EXT Top Vendor Caption Handler" +{ + EventSubscriberInstance = Manual; + Access = Internal; + + [EventSubscriber(ObjectType::Table, Database::"EXR Top Vendor Report Buffer", 'OnGetAmount1Caption', '', false, false)] + local procedure GetAmount1Caption(var NewCaption: Text; var Handled: Boolean) + begin + if (EXTTopReportBuffer."Ranking Based On" = EXTTopReportBuffer."Ranking Based On"::"Balance (LCY)") then begin + NewCaption := BalanceLCYTok; + Handled := true; + exit; + end; + + NewCaption := PurchasesLCYTok; + Handled := true; + end; + + [EventSubscriber(ObjectType::Table, Database::"EXR Top Vendor Report Buffer", 'OnGetAmount2Caption', '', false, false)] + local procedure GetAmount2Caption(var NewCaption: Text; var Handled: Boolean) + begin + if EXTTopReportBuffer."Ranking Based On" <> EXTTopReportBuffer."Ranking Based On"::"Balance (LCY)" then begin + NewCaption := BalanceLCYTok; + Handled := true; + exit; + end; + + NewCaption := PurchasesLCYTok; + Handled := true; + end; + + internal procedure SetRankingBasedOn(NewRankingBasedOn: Option) + begin + EXTTopReportBuffer."Ranking Based On" := NewRankingBasedOn; + end; + + var + EXTTopReportBuffer: Record "EXR Top Vendor Report Buffer"; + BalanceLCYTok: Label 'Balance (LCY)'; + PurchasesLCYTok: Label 'Purchases (LCY)'; + +} \ No newline at end of file diff --git a/Apps/W1/ExcelReports/app/src/permissions/D365BASICISVFEReports.PermissionSetExt.al b/Apps/W1/ExcelReports/app/src/permissions/D365BASICISVFEReports.PermissionSetExt.al new file mode 100644 index 0000000000..8c350ef9f7 --- /dev/null +++ b/Apps/W1/ExcelReports/app/src/permissions/D365BASICISVFEReports.PermissionSetExt.al @@ -0,0 +1,13 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ + +namespace Microsoft.ExcelReports; + +using System.Security.AccessControl; + +permissionsetextension 4400 "D365 BASIC ISV - FE Reports" extends "D365 BASIC ISV" +{ + IncludedPermissionSets = "Excel Reports - Objects"; +} diff --git a/Apps/W1/ExcelReports/app/src/permissions/D365BUSFULLACCESSFEReports.PermissionSetExt.al b/Apps/W1/ExcelReports/app/src/permissions/D365BUSFULLACCESSFEReports.PermissionSetExt.al new file mode 100644 index 0000000000..1d346586fc --- /dev/null +++ b/Apps/W1/ExcelReports/app/src/permissions/D365BUSFULLACCESSFEReports.PermissionSetExt.al @@ -0,0 +1,8 @@ +namespace Microsoft.ExcelReports; + +using System.Security.AccessControl; + +permissionsetextension 4401 "D365 BUS FULL ACCESS - FE Reports" extends "D365 BUS FULL ACCESS" +{ + IncludedPermissionSets = "Excel Reports - Objects"; +} diff --git a/Apps/W1/ExcelReports/app/src/permissions/D365BUSPREMIUMFEReports.PermissionSetExt.al b/Apps/W1/ExcelReports/app/src/permissions/D365BUSPREMIUMFEReports.PermissionSetExt.al new file mode 100644 index 0000000000..f44ca8a43f --- /dev/null +++ b/Apps/W1/ExcelReports/app/src/permissions/D365BUSPREMIUMFEReports.PermissionSetExt.al @@ -0,0 +1,13 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ + +namespace Microsoft.ExcelReports; + +using System.Security.AccessControl; + +permissionsetextension 4402 "D365 BUS PREMIUM - FE Reports" extends "D365 BUS PREMIUM" +{ + IncludedPermissionSets = "Excel Reports - Objects"; +} diff --git a/Apps/W1/ExcelReports/app/src/permissions/D365FULLACCESSFEReports.PermissionSetExt.al b/Apps/W1/ExcelReports/app/src/permissions/D365FULLACCESSFEReports.PermissionSetExt.al new file mode 100644 index 0000000000..879741de30 --- /dev/null +++ b/Apps/W1/ExcelReports/app/src/permissions/D365FULLACCESSFEReports.PermissionSetExt.al @@ -0,0 +1,13 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ + +namespace Microsoft.ExcelReports; + +using System.Security.AccessControl; + +permissionsetextension 4403 "D365 FULL ACCESS - FE Reports" extends "D365 FULL ACCESS" +{ + IncludedPermissionSets = "Excel Reports - Objects"; +} diff --git a/Apps/W1/ExcelReports/app/src/permissions/D365READFEReports.PermissionSetExt.al b/Apps/W1/ExcelReports/app/src/permissions/D365READFEReports.PermissionSetExt.al new file mode 100644 index 0000000000..840ae5a951 --- /dev/null +++ b/Apps/W1/ExcelReports/app/src/permissions/D365READFEReports.PermissionSetExt.al @@ -0,0 +1,13 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ + +namespace Microsoft.ExcelReports; + +using System.Security.AccessControl; + +permissionsetextension 4404 "D365 READ - FE Reports" extends "D365 READ" +{ + IncludedPermissionSets = "Excel Reports - Objects"; +} diff --git a/Apps/W1/ExcelReports/app/src/permissions/ExcelReportsObjects.PermissionSet.al b/Apps/W1/ExcelReports/app/src/permissions/ExcelReportsObjects.PermissionSet.al new file mode 100644 index 0000000000..c3999ad2f9 --- /dev/null +++ b/Apps/W1/ExcelReports/app/src/permissions/ExcelReportsObjects.PermissionSet.al @@ -0,0 +1,35 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ + +namespace Microsoft.ExcelReports; + +using Microsoft.Finance.ExcelReports; +using Microsoft.Sales.ExcelReports; +using Microsoft.Purchases.ExcelReports; + +permissionset 4401 "Excel Reports - Objects" +{ + Assignable = false; + Access = Internal; + + Permissions = table "EXR Aging Report Buffer" = X, + table "EXR Top Customer Report Buffer" = X, + table "EXR Top Vendor Report Buffer" = X, + table "EXR Trial Balance Buffer" = X, + report "EXR Aged Acc Payable Excel" = X, + report "EXR Aged Accounts Rec Excel" = X, + report "EXR Customer Top List" = X, + report "EXR Trial Bal by Period Excel" = X, + report "EXR Trial Bal. Prev Year Excel" = X, + report "EXR Trial Balance Excel" = X, + report "EXR Trial BalanceBudgetExcel" = X, + report "EXR Vendor Top List" = X, + codeunit "EXT Top Cust. Caption Handler" = X, + codeunit "EXT Top Vendor Caption Handler" = X, + query "EXR Top Customer Balance" = X, + query "EXR Top Customer Sales" = X, + query "EXR Top Vendor Balance" = X, + query "EXR Top Vendor Purchase" = X; +} \ No newline at end of file diff --git a/Apps/W1/ExternalEvents/app/app.json b/Apps/W1/ExternalEvents/app/app.json index 30133b7f4f..2319973c6f 100644 --- a/Apps/W1/ExternalEvents/app/app.json +++ b/Apps/W1/ExternalEvents/app/app.json @@ -2,7 +2,7 @@ "id": "6f2c034f-5ebe-4eae-b34c-90a0d4e87687", "name": "_Exclude_Business_Events_", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Business Events. Use business events to notify and trigger external systems", "description": "Business Events. Use business events to notify and trigger external systems", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -17,7 +17,7 @@ "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 38500, @@ -30,5 +30,5 @@ "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/W1/ExternalEvents/test/app.json b/Apps/W1/ExternalEvents/test/app.json index 5184415d9a..a76fb97d78 100644 --- a/Apps/W1/ExternalEvents/test/app.json +++ b/Apps/W1/ExternalEvents/test/app.json @@ -2,7 +2,7 @@ "id": "d65067bd-e0d4-4bab-a5c5-9c0eb94d8f88", "name": "_Exclude_Business_Events_Test", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Business Events. Use business events to notify and trigger external systems", "description": "Business Events. Use business events to notify and trigger external systems", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -16,38 +16,38 @@ "id": "6f2c034f-5ebe-4eae-b34c-90a0d4e87687", "name": "_Exclude_Business_Events_", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "9856ae4f-d1a7-46ef-89bb-6ef056398228", "name": "System Application Test Library", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "e7320ebb-08b3-4406-b1ec-b4927d3e280b", "name": "Any", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5095f467-0a01-4b99-99d1-9ff1237d286f", "publisher": "Microsoft", "name": "Library Variable Storage", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 139640, diff --git a/Apps/W1/HybridAPI/app/app.json b/Apps/W1/HybridAPI/app/app.json index 14d1e8d834..09fbdb5a13 100644 --- a/Apps/W1/HybridAPI/app/app.json +++ b/Apps/W1/HybridAPI/app/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "This extension can help you set up and manage migration to Business Central online through an API.", "description": "This extension can help you set up and manage migration to Business Central online through an API. Use automation to manage the cloud migration end-to-end without using UI.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=2009036", @@ -15,14 +15,14 @@ { "publisher": "Microsoft", "name": "Intelligent Cloud Base", - "version": "24.0.0.0", + "version": "25.0.0.0", "id": "58623bfa-0559-4bc2-ae1c-0979c29fd9e0" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 1, @@ -35,5 +35,5 @@ "includeSourceInSymbolFile": true }, "target": "Cloud", - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/W1/HybridAPI/app/src/CloudMigrationStatusAPI.Page.al b/Apps/W1/HybridAPI/app/src/CloudMigrationStatusAPI.Page.al index 487cc9e09c..880710f426 100644 --- a/Apps/W1/HybridAPI/app/src/CloudMigrationStatusAPI.Page.al +++ b/Apps/W1/HybridAPI/app/src/CloudMigrationStatusAPI.Page.al @@ -127,7 +127,7 @@ page 40021 "Cloud Migration Status API" FeatureTelemetry: Codeunit "Feature Telemetry"; begin FeatureTelemetry.LogUsage('0000JMO', HybridCloudManagement.GetFeatureTelemetryName(), 'Cloud migration API Upgrade'); - HybridCloudManagement.RunDataUpgrade(Rec); + HybridCloudManagement.RunDataUpgradeAPI(Rec); SetActionResponseToThisPage(ActionContext, Rec); end; @@ -141,7 +141,6 @@ page 40021 "Cloud Migration Status API" SetActionResponseToThisPage(ActionContext, Rec); end; - [ServiceEnabled] [Scope('Cloud')] procedure ResetCloudData(var ActionContext: WebServiceActionContext) diff --git a/Apps/W1/HybridBC/app/app.json b/Apps/W1/HybridBC/app/app.json index 77958d6542..09df24813c 100644 --- a/Apps/W1/HybridBC/app/app.json +++ b/Apps/W1/HybridBC/app/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "This extension will take you through the process to configure your Cloud Migration environment.", "description": "This extension will take you through the process to configure and manage your Cloud Migration environment. Once your Cloud Migration environment is configured, you will be able to manage data migrations from your on-premises solution to your Dynamics 365 Business Central cloud tenant.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=2009119", @@ -16,13 +16,13 @@ "id": "58623bfa-0559-4bc2-ae1c-0979c29fd9e0", "name": "Intelligent Cloud Base", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 1, @@ -35,5 +35,5 @@ "includeSourceInSymbolFile": true }, "target": "Cloud", - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/W1/HybridBC/test/app.json b/Apps/W1/HybridBC/test/app.json index ab837381dd..857d3e8256 100644 --- a/Apps/W1/HybridBC/test/app.json +++ b/Apps/W1/HybridBC/test/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "Tests for the Business Central Intelligent Cloud extension.", "description": "Tests for the Business Central Intelligent Cloud extension.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=2005800", @@ -16,37 +16,37 @@ "id": "334ef79e-547e-4631-8ba1-7a7f18e14de6", "name": "Business Central Intelligent Cloud", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "58623bfa-0559-4bc2-ae1c-0979c29fd9e0", "name": "Intelligent Cloud Base", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "cf07faa6-4d21-428b-bfcf-8078c5b0e582", "name": "Intelligent Cloud Base Tests", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "9856ae4f-d1a7-46ef-89bb-6ef056398228", "name": "System Application Test Library", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 139500, @@ -63,5 +63,5 @@ "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/W1/HybridBCLast/app/app.json b/Apps/W1/HybridBCLast/app/app.json index 4552956072..13228ddc43 100644 --- a/Apps/W1/HybridBCLast/app/app.json +++ b/Apps/W1/HybridBCLast/app/app.json @@ -2,7 +2,7 @@ "id": "6992416f-3f39-4d3c-8242-3fff61350bea", "name": "Business Central Cloud Migration - Previous Release", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Enables data migration from the previous version of Dynamics BC (n-1) to the current release of Dynamics 365 Business Central SaaS.", "description": "This extension will take you through the process to migrate data from your Business Central on-premises solution to your Dynamics 365 Business Central cloud tenant. This extension updates system and application tables. Once you have walked through the cloud migration wizard in assisted setup, you will be able to migrate your data from your on-premises environment to your cloud tenant.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -15,7 +15,7 @@ { "publisher": "Microsoft", "name": "Intelligent Cloud Base", - "version": "24.0.0.0", + "version": "25.0.0.0", "id": "58623bfa-0559-4bc2-ae1c-0979c29fd9e0" } ], @@ -29,7 +29,7 @@ "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 1, @@ -42,5 +42,5 @@ "includeSourceInSymbolFile": true }, "target": "Cloud", - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/W1/HybridBCLast/app/src/codeunits/W1Management.Codeunit.al b/Apps/W1/HybridBCLast/app/src/codeunits/W1Management.Codeunit.al index fa334f1775..804e6f6f22 100644 --- a/Apps/W1/HybridBCLast/app/src/codeunits/W1Management.Codeunit.al +++ b/Apps/W1/HybridBCLast/app/src/codeunits/W1Management.Codeunit.al @@ -25,6 +25,7 @@ codeunit 4026 "W1 Management" SettingCanUpgradeToTrueForCompanyNameMsg: Label 'Setting can start upgrade to true, for the company %1', Locked = true; UpdatingUpgradeStatusOfTheCompanyMsg: Label 'Setting can start upgrade to true, for the company %1', Locked = true; CloudMigrationTok: Label 'CloudMigration', Locked = true; + CannotStartReplicationUpgradeCompletedErr: Label 'You cannot start the replication from the previous version because one or more companies are already upgraded. Consult the official documentation for more information how to proceed.'; CannotStartUpgradeCompanyUpgradeCompletedErr: Label 'You cannot start the upgrade because one or more companies are already upgraded. Consult the official documentation for more information how to proceed.'; PleaseWaitForUpgradeToBeTriggeredErr: Label 'The upgrade has been scheduled at %1. Please wait for %2 minutes for the task to start. You can check if the upgrade was scheduled and track the progress in on the Operations tab in the Business Central admin center. If the task does not start during this time, start the process again.', Comment = '%1 - Time upgrade action was invoked. %2 Time in minutes to wait.'; CheckUpgradeStatusInTenantAdminCenterMsg: Label 'The upgrade was scheduled at %1. You can see if the upgrade has run on the Operations tab in the Business Central admin center. In case the upgrade fails, we will have restored the tenant to the point before the upgrade, so you can fix any issues and start a new upgrade run.', Comment = '%1 - Time upgrade action was invoked.'; @@ -90,6 +91,7 @@ codeunit 4026 "W1 Management" if not HybridBCLastManagement.GetBCLastProductEnabled() then exit; + Clear(BlankDateTime); HybridCompanyStatus.SetRange("Upgrade Status", HybridCompanyStatus."Upgrade Status"::Completed); if not HybridCompanyStatus.IsEmpty() then @@ -183,6 +185,7 @@ codeunit 4026 "W1 Management" if not HybridReplicationSummary.FindLast() then exit; + Clear(BlankDateTime); if HybridReplicationSummary."Upgrade Started DateTime" = BlankDateTime then exit; @@ -468,6 +471,16 @@ codeunit 4026 "W1 Management" SourceBC := true; end; + [EventSubscriber(ObjectType::Page, Page::"Hybrid Cloud Setup Wizard", 'OnSelectedProduct', '', false, false)] + local procedure HandleOnSelectedProduct(ProductId: Text) + var + HybridCompanyStatus: Record "Hybrid Company Status"; + begin + HybridCompanyStatus.SetRange("Upgrade Status", HybridCompanyStatus."Upgrade Status"::Completed); + if not HybridCompanyStatus.IsEmpty() then + Error(CannotStartReplicationUpgradeCompletedErr); + end; + [IntegrationEvent(false, false)] local procedure OnAfterPopulateW1TableMappingForVersion(CountryCode: Text; TargetVersion: Decimal) begin diff --git a/Apps/W1/HybridBCLast/test/app.json b/Apps/W1/HybridBCLast/test/app.json index 318c2e4de7..d533558f3d 100644 --- a/Apps/W1/HybridBCLast/test/app.json +++ b/Apps/W1/HybridBCLast/test/app.json @@ -2,7 +2,7 @@ "id": "c8e46b67-1f61-46e2-a3a5-0239429e26fb", "name": "Business Central Cloud Migration - Previous Release Tests", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "description": "Tests for the Business Central Cloud Migration - Previous Release extension.", "brief": "Tests for setting up data replication from Dynamics Business Central (previous version) to Dynamics 365 Business Central SaaS.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -15,49 +15,49 @@ { "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "id": "5d86850b-0d76-4eca-bd7b-951ad998e997" }, { "name": "System Application Test Library", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "id": "9856ae4f-d1a7-46ef-89bb-6ef056398228" }, { "name": "Intelligent Cloud Base", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "id": "58623bfa-0559-4bc2-ae1c-0979c29fd9e0" }, { "name": "Business Central Cloud Migration - Previous Release", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "id": "6992416f-3f39-4d3c-8242-3fff61350bea" }, { "name": "Intelligent Cloud Base Tests", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "id": "cf07faa6-4d21-428b-bfcf-8078c5b0e582" }, { "name": "Library Variable Storage", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "id": "5095f467-0a01-4b99-99d1-9ff1237d286f" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "resourceExposurePolicy": { "allowDebugging": false, "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, "target": "OnPrem", - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/W1/HybridBaseDeployment/app/app.json b/Apps/W1/HybridBaseDeployment/app/app.json index 0e784376a2..53fbe94429 100644 --- a/Apps/W1/HybridBaseDeployment/app/app.json +++ b/Apps/W1/HybridBaseDeployment/app/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "This extension will take you through the process to configure your Cloud Migration environment.", "description": "This extension will take you through the process to configure your Cloud Migration environment. Once your Cloud Migration environment is configured, you will be able to replicate data from your Dynamics 365 Business Central on-premises solution to your Dynamics 365 Business Central cloud tenant. This will enable you to take full advantage of what the cloud has to offer your business such as, enhanced insights into your business, artificial intelligence, multiple device access, and anytime, anywhere access.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=2009036", @@ -17,7 +17,7 @@ "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 1, @@ -30,22 +30,22 @@ "includeSourceInSymbolFile": true }, "target": "OnPrem", - "application": "24.0.0.0", + "application": "25.0.0.0", "internalsVisibleTo": [ { - "id": "57623bfa-0559-4bc2-ae1c-0979c29fc8d1", - "name": "Business Central Cloud Migration API", + "id": "57623bfa-0559-4bc2-ae1c-0979c29fc8d1", + "name": "Business Central Cloud Migration API", "publisher": "Microsoft" }, { - "id": "334ef79e-547e-4631-8ba1-7a7f18e14de6", - "name": "Business Central Intelligent Cloud", - "publisher": "Microsoft" + "id": "334ef79e-547e-4631-8ba1-7a7f18e14de6", + "name": "Business Central Intelligent Cloud", + "publisher": "Microsoft" }, { - "id": "6992416f-3f39-4d3c-8242-3fff61350bea", - "name": "Business Central Cloud Migration - Previous Release", - "publisher": "Microsoft" + "id": "6992416f-3f39-4d3c-8242-3fff61350bea", + "name": "Business Central Cloud Migration - Previous Release", + "publisher": "Microsoft" }, { "id": "cf07faa6-4d21-428b-bfcf-8078c5b0e582", @@ -53,13 +53,13 @@ "publisher": "Microsoft" }, { - "id": "c8e46b67-1f61-46e2-a3a5-0239429e26fb", - "name": "Business Central Cloud Migration - Previous Release Tests", - "publisher": "Microsoft" + "id": "c8e46b67-1f61-46e2-a3a5-0239429e26fb", + "name": "Business Central Cloud Migration - Previous Release Tests", + "publisher": "Microsoft" }, { - "id": "82acac14-8067-499b-8cf0-f068448dff34", - "name": "Dynamics GP Intelligent Cloud Tests", + "id": "82acac14-8067-499b-8cf0-f068448dff34", + "name": "Dynamics GP Intelligent Cloud Tests", "publisher": "Microsoft" } ] diff --git a/Apps/W1/HybridBaseDeployment/app/src/codeunits/HybridCloudManagement.Codeunit.al b/Apps/W1/HybridBaseDeployment/app/src/codeunits/HybridCloudManagement.Codeunit.al index 50d7c8e286..82217eceb1 100644 --- a/Apps/W1/HybridBaseDeployment/app/src/codeunits/HybridCloudManagement.Codeunit.al +++ b/Apps/W1/HybridBaseDeployment/app/src/codeunits/HybridCloudManagement.Codeunit.al @@ -1513,6 +1513,16 @@ codeunit 4001 "Hybrid Cloud Management" IntelligentCloudStatus.Delete(); end; + procedure RunDataUpgradeAPI(var HybridReplicationSummary: Record "Hybrid Replication Summary") + var + IntelligentCloudSetup: Record "Intelligent Cloud Setup"; + HybridDeployment: Codeunit "Hybrid Deployment"; + begin + IntelligentCloudSetup.Get(); + HybridDeployment.Initialize(IntelligentCloudSetup."Product ID"); + RunDataUpgrade(HybridReplicationSummary); + end; + procedure RunDataUpgrade(var HybridReplicationSummary: Record "Hybrid Replication Summary") var ExistingHybridReplicationSummary: Record "Hybrid Replication Summary"; diff --git a/Apps/W1/HybridBaseDeployment/app/src/pages/AddMigrationTableMappings.Page.al b/Apps/W1/HybridBaseDeployment/app/src/pages/AddMigrationTableMappings.Page.al index e487403c29..12b78619c3 100644 --- a/Apps/W1/HybridBaseDeployment/app/src/pages/AddMigrationTableMappings.Page.al +++ b/Apps/W1/HybridBaseDeployment/app/src/pages/AddMigrationTableMappings.Page.al @@ -113,6 +113,7 @@ page 40010 "Add Migration Table Mappings" ExtensionManagement: Page "Extension Management"; begin MigrationTableMapping.FilterOutBlacklistedPublishers(PublishedApplication); + PublishedApplication.SetRange(Installed, true); ExtensionManagement.SetTableView(PublishedApplication); ExtensionManagement.LookupMode(true); diff --git a/Apps/W1/HybridBaseDeployment/app/src/pages/HybridCloudSetupWizard.Page.al b/Apps/W1/HybridBaseDeployment/app/src/pages/HybridCloudSetupWizard.Page.al index 30c7d46533..95d5fca3be 100644 --- a/Apps/W1/HybridBaseDeployment/app/src/pages/HybridCloudSetupWizard.Page.al +++ b/Apps/W1/HybridBaseDeployment/app/src/pages/HybridCloudSetupWizard.Page.al @@ -151,6 +151,7 @@ page 4000 "Hybrid Cloud Setup Wizard" exit; HybridCloudManagement.OnGetHybridProductDescription(TempHybridProductType.ID, SelectedProductDescription); + OnSelectedProduct(TempHybridProductType.ID); SelectedProductDescriptionVisible := SelectedProductDescription <> ''; Rec."Product ID" := TempHybridProductType.ID; @@ -1018,5 +1019,10 @@ page 4000 "Hybrid Cloud Setup Wizard" else CurrentStep += 1; end; + + [IntegrationEvent(false, false)] + procedure OnSelectedProduct(ProductId: Text) + begin + end; } diff --git a/Apps/W1/HybridBaseDeployment/test/app.json b/Apps/W1/HybridBaseDeployment/test/app.json index f6f773ae4d..a12b5e2c21 100644 --- a/Apps/W1/HybridBaseDeployment/test/app.json +++ b/Apps/W1/HybridBaseDeployment/test/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "Tests for the Intelligent Cloud Base extension.", "description": "Tests for the Intelligent Cloud Base extension.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=2005800", @@ -16,31 +16,31 @@ "id": "5095f467-0a01-4b99-99d1-9ff1237d286f", "name": "Library Variable Storage", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "58623bfa-0559-4bc2-ae1c-0979c29fd9e0", "name": "Intelligent Cloud Base", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "9856ae4f-d1a7-46ef-89bb-6ef056398228", "name": "System Application Test Library", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 139500, @@ -57,5 +57,5 @@ "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/W1/HybridGP/app/Permissions/HybridGPObjects.PermissionSet.al b/Apps/W1/HybridGP/app/Permissions/HybridGPObjects.PermissionSet.al index 5ba467de0b..ab5741e161 100644 --- a/Apps/W1/HybridGP/app/Permissions/HybridGPObjects.PermissionSet.al +++ b/Apps/W1/HybridGP/app/Permissions/HybridGPObjects.PermissionSet.al @@ -146,7 +146,9 @@ permissionset 4029 "HybridGP - Objects" query "GP Item Aggregate" = X, codeunit "GP Migration Error Handler" = X, page "GP Migration Error Overview" = X, +#if not CLEAN24 page "Hybrid GP Errors Overview Fb" = X, +#endif table "GP Migration Error Overview" = X, table "GP Upgrade Settings" = X, codeunit "Start Data Upgrade" = X, diff --git a/Apps/W1/HybridGP/app/app.json b/Apps/W1/HybridGP/app/app.json index da3b9037e3..0b92c9caae 100644 --- a/Apps/W1/HybridGP/app/app.json +++ b/Apps/W1/HybridGP/app/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "This extension will allow you to set up data migration from your Dynamics GP companies to your Dynamics 365 Business Central tenant through a wizard.", "description": "This extension will take you through the process to migrate data from your Dynamics GP on-premises solution to your Dynamics 365 Business Central cloud tenant. This will enable you to take advantage of what the cloud has to offer your business such as, enhanced insights into your business, artificial intelligence, multiple device access, and anytime, anywhere access.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=2009037", @@ -16,19 +16,19 @@ "id": "7c7d97ca-3598-40f5-b263-f713f49bd2a5", "name": "Dynamics GP Historical Data", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "58623bfa-0559-4bc2-ae1c-0979c29fd9e0", "name": "Intelligent Cloud Base", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "c526b3e9-b8ca-4683-81ba-fcd5f6b1472a", "name": "Sales and Inventory Forecast", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ @@ -41,7 +41,7 @@ "publisher": "Microsoft" } ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 1, @@ -54,5 +54,5 @@ "includeSourceInSymbolFile": true }, "target": "Cloud", - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/W1/HybridGP/app/src/pages/HybridGPErrorsOverviewFb.page.al b/Apps/W1/HybridGP/app/src/pages/HybridGPErrorsOverviewFb.page.al index 1c0df8a16b..5ed26bf516 100644 --- a/Apps/W1/HybridGP/app/src/pages/HybridGPErrorsOverviewFb.page.al +++ b/Apps/W1/HybridGP/app/src/pages/HybridGPErrorsOverviewFb.page.al @@ -75,4 +75,4 @@ page 40132 "Hybrid GP Errors Overview Fb" MigrationErrorCount: Integer; FailedCompanyCount: Integer; } -#endif \ No newline at end of file +#endif diff --git a/Apps/W1/HybridGP/app/src/pages/HybridGPOverviewFb.Page.al b/Apps/W1/HybridGP/app/src/pages/HybridGPOverviewFb.Page.al index 16a5d0f0bd..9178ea8332 100644 --- a/Apps/W1/HybridGP/app/src/pages/HybridGPOverviewFb.Page.al +++ b/Apps/W1/HybridGP/app/src/pages/HybridGPOverviewFb.Page.al @@ -135,4 +135,4 @@ page 40125 "Hybrid GP Overview Fb" FailedBatchCount: Integer; FailedBatchMsg: Text; MigrationWarningCount: Integer; -} \ No newline at end of file +} diff --git a/Apps/W1/HybridGP/app/src/pages/IntelligentCloudExtension.PageExt.al b/Apps/W1/HybridGP/app/src/pages/IntelligentCloudExtension.PageExt.al index b5dca3cdbf..383a60f2ec 100644 --- a/Apps/W1/HybridGP/app/src/pages/IntelligentCloudExtension.PageExt.al +++ b/Apps/W1/HybridGP/app/src/pages/IntelligentCloudExtension.PageExt.al @@ -153,4 +153,4 @@ pageextension 4015 "Intelligent Cloud Extension" extends "Intelligent Cloud Mana ResetPreviousRunQst: Label 'Do you want to reset your previous GP Historical Snapshot migration? Choose No if you want to continue progress from the previous attempt.'; HistoricalDataJobNotRanMsg: Label 'The GP Historical Snapshot job has not ran.'; HistoricalDataStartJobMsg: Label 'Start GP Historical Snapshot job.'; -} \ No newline at end of file +} diff --git a/Apps/W1/HybridGP/test/app.json b/Apps/W1/HybridGP/test/app.json index 6665ca2357..d0f00c2b07 100644 --- a/Apps/W1/HybridGP/test/app.json +++ b/Apps/W1/HybridGP/test/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "Tests for the Dynamics GP Intelligent Cloud extension.", "description": "Tests for the Dynamics GP Intelligent Cloud extension.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=2005800", @@ -16,49 +16,49 @@ "id": "feeb3504-556e-4790-b28d-a2b9ce302d81", "name": "Dynamics GP Intelligent Cloud", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "58623bfa-0559-4bc2-ae1c-0979c29fd9e0", "name": "Intelligent Cloud Base", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "cf07faa6-4d21-428b-bfcf-8078c5b0e582", "name": "Intelligent Cloud Base Tests", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "c526b3e9-b8ca-4683-81ba-fcd5f6b1472a", "name": "Sales and Inventory Forecast", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "9856ae4f-d1a7-46ef-89bb-6ef056398228", "name": "System Application Test Library", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5095f467-0a01-4b99-99d1-9ff1237d286f", "name": "Library Variable Storage", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 139500, @@ -75,5 +75,5 @@ "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/W1/INTaxEngine/app/TaxEngine-Core/app.json b/Apps/W1/INTaxEngine/app/TaxEngine-Core/app.json index 6ccd033e3b..e5d1149c8b 100644 --- a/Apps/W1/INTaxEngine/app/TaxEngine-Core/app.json +++ b/Apps/W1/INTaxEngine/app/TaxEngine-Core/app.json @@ -2,7 +2,7 @@ "id": "52cd6cb4-0433-4e94-8e62-9d12fff1a02b", "name": "Tax Engine Core", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Contains Tax Engine's core functionality.", "description": "Core contains user interface elements and tables that are used throughout Tax Engine. It also provides library functions that extensions can use to get values.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -10,8 +10,8 @@ "help": "https://go.microsoft.com/fwlink/?linkid=2139719", "url": "https://go.microsoft.com/fwlink/?LinkId=724011", "logo": "ExtensionLogo.png", - "application": "24.0.0.0", - "platform": "24.0.0.0", + "application": "25.0.0.0", + "platform": "25.0.0.0", "screenshots": [ ], diff --git a/Apps/W1/INTaxEngine/app/TaxEngine-Core/src/Core/Codeunit/ArchiveManagementHandler.Codeunit.al b/Apps/W1/INTaxEngine/app/TaxEngine-Core/src/Core/Codeunit/ArchiveManagementHandler.Codeunit.al new file mode 100644 index 0000000000..b1e1d49b72 --- /dev/null +++ b/Apps/W1/INTaxEngine/app/TaxEngine-Core/src/Core/Codeunit/ArchiveManagementHandler.Codeunit.al @@ -0,0 +1,62 @@ +// ------------------------------------------------------------------------------------------------ +// 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.TaxEngine.Core; + +using Microsoft.Finance.TaxEngine.PostingHandler; +using Microsoft.Finance.TaxEngine.TaxTypeHandler; +using Microsoft.Purchases.Archive; +using Microsoft.Purchases.Document; +using Microsoft.Sales.Archive; +using Microsoft.Sales.Document; +using Microsoft.Utilities; + +codeunit 20136 "Archive Management Handler" +{ + [EventSubscriber(ObjectType::Codeunit, Codeunit::ArchiveManagement, 'OnAfterStorePurchLineArchive', '', false, false)] + local procedure OnAfterStorePurchLineArchive(var PurchLine: Record "Purchase Line"; + var PurchHeaderArchive: Record "Purchase Header Archive"; + var PurchLineArchive: Record "Purchase Line Archive") + var + TempTaxTransactionValue: Record "Tax Transaction Value" temporary; + TaxDocumentGLPosting: Codeunit "Tax Document GL Posting"; + begin + // Prepares Transaction value based on Purchase Line Quantity + TaxDocumentGLPosting.PrepareTransactionValueToPost( + PurchLine.RecordId(), + PurchLine.Quantity, + PurchLineArchive.Quantity, + PurchHeaderArchive."Currency Code", + PurchHeaderArchive."Currency Factor", + TempTaxTransactionValue); + + //Copies transaction value from unposted document to archive record ID + TaxDocumentGLPosting.TransferTransactionValue( + PurchLine.RecordId(), + PurchLineArchive.RecordId(), + TempTaxTransactionValue); + end; + + [EventSubscriber(ObjectType::Codeunit, Codeunit::ArchiveManagement, 'OnAfterStoreSalesLineArchive', '', false, false)] + local procedure OnAfterStoreSalesLineArchive(var SalesLine: Record "Sales Line"; var SalesHeaderArchive: Record "Sales Header Archive"; var SalesLineArchive: Record "Sales Line Archive") + var + TempTaxTransactionValue: Record "Tax Transaction Value" temporary; + TaxDocumentGLPosting: Codeunit "Tax Document GL Posting"; + begin + // Prepares Transaction value based on Sales Line Quantity + TaxDocumentGLPosting.PrepareTransactionValueToPost( + SalesLine.RecordId(), + SalesLine.Quantity, + SalesLineArchive.Quantity, + SalesHeaderArchive."Currency Code", + SalesHeaderArchive."Currency Factor", + TempTaxTransactionValue); + + //Copies transaction value from unposted document to archive record ID + TaxDocumentGLPosting.TransferTransactionValue( + SalesLine.RecordId(), + SalesLineArchive.RecordId(), + TempTaxTransactionValue); + end; +} \ No newline at end of file diff --git a/Apps/W1/INTaxEngine/app/TaxEngine-JsonExchange/app.json b/Apps/W1/INTaxEngine/app/TaxEngine-JsonExchange/app.json index 67b7953c38..388db2ea4d 100644 --- a/Apps/W1/INTaxEngine/app/TaxEngine-JsonExchange/app.json +++ b/Apps/W1/INTaxEngine/app/TaxEngine-JsonExchange/app.json @@ -2,7 +2,7 @@ "id": "b5831077-0836-4f9e-8be3-e1217b9d6305", "name": "Tax Engine Json Exchange", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Provides export and import functionality using JSON files.", "description": "The JSON Exchange extension lets you import and export Tax Engine configuration data as JSON files.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -15,31 +15,31 @@ "id": "52cd6cb4-0433-4e94-8e62-9d12fff1a02b", "publisher": "Microsoft", "name": "Tax Engine Core", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "0382879d-7e2a-46fd-bfd6-2672e3b9add4", "publisher": "Microsoft", "name": "Tax Engine Script Handler", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "6557efcc-709a-40d9-bb71-526f2ba1a1e9", "publisher": "Microsoft", "name": "Tax Engine Tax Type Handler", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "968ef3c8-1bbd-4cd1-83da-099bd66f11c5", "publisher": "Microsoft", "name": "Tax Engine Use Case Builder", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "d400443e-5a25-4eae-95dd-7891e382e068", "publisher": "Microsoft", "name": "Tax Engine Posting Handler", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "internalsVisibleTo": [ @@ -52,8 +52,8 @@ "screenshots": [ ], - "application": "24.0.0.0", - "platform": "24.0.0.0", + "application": "25.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 20360, diff --git a/Apps/W1/INTaxEngine/app/TaxEngine-PostingHandler/app.json b/Apps/W1/INTaxEngine/app/TaxEngine-PostingHandler/app.json index 9b5ec9738d..c61af8d964 100644 --- a/Apps/W1/INTaxEngine/app/TaxEngine-PostingHandler/app.json +++ b/Apps/W1/INTaxEngine/app/TaxEngine-PostingHandler/app.json @@ -2,7 +2,7 @@ "id": "d400443e-5a25-4eae-95dd-7891e382e068", "name": "Tax Engine Posting Handler", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Runs posting logic for taxes and updates tax ledgers.", "description": "The Posting Handler extension contains user interface elements and tables that determine how tax is posted to G/L accounts and their ledgers.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -15,25 +15,25 @@ "id": "52cd6cb4-0433-4e94-8e62-9d12fff1a02b", "publisher": "Microsoft", "name": "Tax Engine Core", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "0382879d-7e2a-46fd-bfd6-2672e3b9add4", "publisher": "Microsoft", "name": "Tax Engine Script Handler", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "6557efcc-709a-40d9-bb71-526f2ba1a1e9", "publisher": "Microsoft", "name": "Tax Engine Tax Type Handler", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "968ef3c8-1bbd-4cd1-83da-099bd66f11c5", "publisher": "Microsoft", "name": "Tax Engine Use Case Builder", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "internalsVisibleTo": [ @@ -46,8 +46,8 @@ "screenshots": [ ], - "application": "24.0.0.0", - "platform": "24.0.0.0", + "application": "25.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 20334, diff --git a/Apps/W1/INTaxEngine/app/TaxEngine-PostingHandler/src/PostingManagement/codeunit/TaxDocumentGLPosting.Codeunit.al b/Apps/W1/INTaxEngine/app/TaxEngine-PostingHandler/src/PostingManagement/codeunit/TaxDocumentGLPosting.Codeunit.al index eccc09ee98..0872a658d2 100644 --- a/Apps/W1/INTaxEngine/app/TaxEngine-PostingHandler/src/PostingManagement/codeunit/TaxDocumentGLPosting.Codeunit.al +++ b/Apps/W1/INTaxEngine/app/TaxEngine-PostingHandler/src/PostingManagement/codeunit/TaxDocumentGLPosting.Codeunit.al @@ -63,6 +63,7 @@ codeunit 20341 "Tax Document GL Posting" ToTaxTransactionValue: Record "Tax Transaction Value"; begin FromTaxTransactionValue.Reset(); + FromTaxTransactionValue.SetCurrentKey("Tax Record ID", "Tax Type"); FromTaxTransactionValue.SetRange("Tax Record ID", FromRecID); if FromTaxTransactionValue.FindSet() then repeat diff --git a/Apps/W1/INTaxEngine/app/TaxEngine-PostingHandler/src/PostingManagement/codeunit/TaxPostingBufferMgmt.Codeunit.al b/Apps/W1/INTaxEngine/app/TaxEngine-PostingHandler/src/PostingManagement/codeunit/TaxPostingBufferMgmt.Codeunit.al index a268f12822..cb79447f8d 100644 --- a/Apps/W1/INTaxEngine/app/TaxEngine-PostingHandler/src/PostingManagement/codeunit/TaxPostingBufferMgmt.Codeunit.al +++ b/Apps/W1/INTaxEngine/app/TaxEngine-PostingHandler/src/PostingManagement/codeunit/TaxPostingBufferMgmt.Codeunit.al @@ -315,6 +315,8 @@ codeunit 20343 "Tax Posting Buffer Mgmt." TempTransactionValue.Reset(); NextID := TempTransactionValue.Count(); + TaxTransactionValue.SetCurrentKey("Tax Record ID", "Tax Type"); + TaxTransactionValue.LoadFields("Tax Record ID", "Case ID"); TaxTransactionValue.SetRange("Tax Record ID", TempTaxPostingBuffer."Tax Record ID"); TaxTransactionValue.SetRange("Case ID", TempTaxPostingBuffer."Case ID"); if TaxTransactionValue.FindSet() then diff --git a/Apps/W1/INTaxEngine/app/TaxEngine-ScriptHandler/app.json b/Apps/W1/INTaxEngine/app/TaxEngine-ScriptHandler/app.json index 31a6b836d7..81022d831d 100644 --- a/Apps/W1/INTaxEngine/app/TaxEngine-ScriptHandler/app.json +++ b/Apps/W1/INTaxEngine/app/TaxEngine-ScriptHandler/app.json @@ -2,7 +2,7 @@ "id": "0382879d-7e2a-46fd-bfd6-2672e3b9add4", "name": "Tax Engine Script Handler", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Provides scripting ability to Tax Engine.", "description": "Script Handler Tests contains user interface elements and tables for scripting business logic in use cases.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -15,7 +15,7 @@ "id": "52cd6cb4-0433-4e94-8e62-9d12fff1a02b", "publisher": "Microsoft", "name": "Tax Engine Core", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "internalsVisibleTo": [ @@ -33,8 +33,8 @@ "screenshots": [ ], - "application": "24.0.0.0", - "platform": "24.0.0.0", + "application": "25.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 20156, diff --git a/Apps/W1/INTaxEngine/app/TaxEngine-TaxTypeHandler/app.json b/Apps/W1/INTaxEngine/app/TaxEngine-TaxTypeHandler/app.json index 5a6d75a23c..17eea70751 100644 --- a/Apps/W1/INTaxEngine/app/TaxEngine-TaxTypeHandler/app.json +++ b/Apps/W1/INTaxEngine/app/TaxEngine-TaxTypeHandler/app.json @@ -2,7 +2,7 @@ "id": "6557efcc-709a-40d9-bb71-526f2ba1a1e9", "name": "Tax Engine Tax Type Handler", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Defines core elements of taxes, such as components, attributes, and rates.", "description": "The Tax Type Handler extension contains user interface elements and tables that are helpers for configuring a business use case.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -10,20 +10,20 @@ "help": "https://go.microsoft.com/fwlink/?linkid=2139719", "url": "https://go.microsoft.com/fwlink/?LinkId=724011", "logo": "ExtensionLogo.png", - "application": "24.0.0.0", - "platform": "24.0.0.0", + "application": "25.0.0.0", + "platform": "25.0.0.0", "dependencies": [ { "id": "52cd6cb4-0433-4e94-8e62-9d12fff1a02b", "publisher": "Microsoft", "name": "Tax Engine Core", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "0382879d-7e2a-46fd-bfd6-2672e3b9add4", "publisher": "Microsoft", "name": "Tax Engine Script Handler", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "internalsVisibleTo": [ diff --git a/Apps/W1/INTaxEngine/app/TaxEngine-TaxTypeHandler/src/TransactionValue/table/TaxTransactionValue.Table.al b/Apps/W1/INTaxEngine/app/TaxEngine-TaxTypeHandler/src/TransactionValue/table/TaxTransactionValue.Table.al index 4efaa1288b..2727ca005a 100644 --- a/Apps/W1/INTaxEngine/app/TaxEngine-TaxTypeHandler/src/TransactionValue/table/TaxTransactionValue.Table.al +++ b/Apps/W1/INTaxEngine/app/TaxEngine-TaxTypeHandler/src/TransactionValue/table/TaxTransactionValue.Table.al @@ -8,10 +8,12 @@ using Microsoft.Finance.Currency; using Microsoft.Finance.GeneralLedger.Journal; using Microsoft.Finance.TaxEngine.Core; using Microsoft.Inventory.Transfer; +using Microsoft.Purchases.Archive; using Microsoft.Purchases.Document; using Microsoft.Purchases.History; using Microsoft.Sales.Document; using Microsoft.Sales.History; +using Microsoft.Sales.Archive; table 20261 "Tax Transaction Value" { @@ -129,6 +131,11 @@ table 20261 "Tax Transaction Value" DataClassification = EndUserIdentifiableInformation; Caption = 'Currency Factor'; } + field(24; "Version No. Filter"; Integer) + { + FieldClass = FlowFilter; + Caption = 'Version No. Filter'; + } } keys { @@ -207,6 +214,7 @@ table 20261 "Tax Transaction Value" TemplateNameFilter: Text; BatchFilter: Text; LineNoFilter: Integer; + VersionNoFilter: Integer; IsHandled: Boolean; begin Clear(TaxRecordID); @@ -224,6 +232,8 @@ table 20261 "Tax Transaction Value" TemplateNameFilter := GetRangeMax("Template Name Filter"); if GetFilter("Batch Name Filter") <> '' then BatchFilter := GetRangeMax("Batch Name Filter"); + if GetFilter("Version No. Filter") <> '' then + VersionNoFilter := GetRangeMax("Version No. Filter"); FilterGroup(0); @@ -232,6 +242,8 @@ table 20261 "Tax Transaction Value" GetTaxRecIDForSalesDocument(TableIDFilter, DocumentTypeFilter, DocumentNoFilter, LineNoFilter, TaxRecordID); Database::"Purchase Line", Database::"Purch. Inv. Line", database::"Purch. Cr. Memo Line": GetTaxRecIDForPurchDocument(TableIDFilter, DocumentTypeFilter, DocumentNoFilter, LineNoFilter, TaxRecordID); + Database::"Purchase Line Archive", Database::"Sales Line Archive": + GetTaxRecIDForArchiveDocument(TableIDFilter, DocumentTypeFilter, DocumentNoFilter, LineNoFilter, VersionNoFilter, TaxRecordID); Database::"Transfer Line", Database::"Transfer Shipment Line", Database::"Transfer Receipt Line": GetTaxRecIDForTransferDocument(TableIDFilter, DocumentNoFilter, LineNoFilter, TaxRecordID); database::"Gen. Journal Line": @@ -300,6 +312,33 @@ table 20261 "Tax Transaction Value" end; end; + local procedure GetTaxRecIDForArchiveDocument(TableID: Integer; DocumentTypeFilter: Integer; DocumentNoFilter: Text; LineNoFilter: Integer; VersionNoFilter: Integer; var TaxRecordID: RecordId) + var + PurchaseLineArchive: Record "Purchase Line Archive"; + SalesLineArchive: Record "Sales Line Archive"; + begin + case TableID of + database::"Purchase Line Archive": + begin + PurchaseLineArchive.SetRange("Document Type", DocumentTypeFilter); + PurchaseLineArchive.SetRange("Document No.", DocumentNoFilter); + PurchaseLineArchive.SetRange("Version No.", VersionNoFilter); + PurchaseLineArchive.SetRange("Line No.", LineNoFilter); + if PurchaseLineArchive.FindFirst() then + TaxRecordID := PurchaseLineArchive.RecordId(); + end; + database::"Sales Line Archive": + begin + SalesLineArchive.SetRange("Document Type", DocumentTypeFilter); + SalesLineArchive.SetRange("Document No.", DocumentNoFilter); + SalesLineArchive.SetRange("Version No.", VersionNoFilter); + SalesLineArchive.SetRange("Line No.", LineNoFilter); + if SalesLineArchive.FindFirst() then + TaxRecordID := SalesLineArchive.RecordId(); + end; + end; + end; + local procedure GetTaxRecIDForTransferDocument(TableID: Integer; DocumentNoFilter: Text; LineNoFilter: Integer; var TaxRecordID: RecordId) var TransferLine: Record "Transfer Line"; diff --git a/Apps/W1/INTaxEngine/app/TaxEngine-UseCaseBuilder/app.json b/Apps/W1/INTaxEngine/app/TaxEngine-UseCaseBuilder/app.json index 1d0e6952ca..f950ccfafc 100644 --- a/Apps/W1/INTaxEngine/app/TaxEngine-UseCaseBuilder/app.json +++ b/Apps/W1/INTaxEngine/app/TaxEngine-UseCaseBuilder/app.json @@ -2,7 +2,7 @@ "id": "968ef3c8-1bbd-4cd1-83da-099bd66f11c5", "name": "Tax Engine Use Case Builder", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Use cases and the components calculation logic.", "description": "The Tax Use Case Handler extension contains user interface elements and tables for configuring taxation for a business use case.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -15,19 +15,19 @@ "id": "52cd6cb4-0433-4e94-8e62-9d12fff1a02b", "publisher": "Microsoft", "name": "Tax Engine Core", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "0382879d-7e2a-46fd-bfd6-2672e3b9add4", "publisher": "Microsoft", "name": "Tax Engine Script Handler", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "6557efcc-709a-40d9-bb71-526f2ba1a1e9", "publisher": "Microsoft", "name": "Tax Engine Tax Type Handler", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "internalsVisibleTo": [ @@ -45,8 +45,8 @@ "screenshots": [ ], - "application": "24.0.0.0", - "platform": "24.0.0.0", + "application": "25.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 20283, diff --git a/Apps/W1/INTaxEngine/app/TaxEngine-UseCaseBuilder/src/Events/codeunit/UseCaseEventHandling.Codeunit.al b/Apps/W1/INTaxEngine/app/TaxEngine-UseCaseBuilder/src/Events/codeunit/UseCaseEventHandling.Codeunit.al index 4fba4222ed..a134202fcb 100644 --- a/Apps/W1/INTaxEngine/app/TaxEngine-UseCaseBuilder/src/Events/codeunit/UseCaseEventHandling.Codeunit.al +++ b/Apps/W1/INTaxEngine/app/TaxEngine-UseCaseBuilder/src/Events/codeunit/UseCaseEventHandling.Codeunit.al @@ -97,6 +97,7 @@ codeunit 20286 "Use Case Event Handling" if RecRef.IsTemporary() then exit; + TaxTransactionValue.SetCurrentKey("Tax Record ID", "Tax Type"); TaxTransactionValue.SetRange("Tax Record ID", RecRef.RecordId()); if not TaxTransactionValue.IsEmpty() then TaxTransactionValue.DeleteAll(true); diff --git a/Apps/W1/INTaxEngine/app/app.json b/Apps/W1/INTaxEngine/app/app.json index a3ac1ca06b..b959727881 100644 --- a/Apps/W1/INTaxEngine/app/app.json +++ b/Apps/W1/INTaxEngine/app/app.json @@ -2,7 +2,7 @@ "id": "c1eafb3f-e397-468e-bdb4-ecc5c317ca00", "name": "Tax Engine", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Provides features for calculating tax based on use cases. Intended for use only in India.", "description": "The Tax Engine extension calculates tax based on use cases that can be attached to a predefined business event. If the event meets the conditions of the rules, the Tax Engine runs the use case.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -10,8 +10,8 @@ "help": "https://go.microsoft.com/fwlink/?linkid=2139719", "url": "https://go.microsoft.com/fwlink/?LinkId=724011", "logo": "ExtensionLogo.png", - "application": "24.0.0.0", - "platform": "24.0.0.0", + "application": "25.0.0.0", + "platform": "25.0.0.0", "screenshots": [ ], diff --git a/Apps/W1/INTaxEngine/test/TaxEngine-Core/app.json b/Apps/W1/INTaxEngine/test/TaxEngine-Core/app.json index 0b019a0487..ec7757e9df 100644 --- a/Apps/W1/INTaxEngine/test/TaxEngine-Core/app.json +++ b/Apps/W1/INTaxEngine/test/TaxEngine-Core/app.json @@ -2,7 +2,7 @@ "id": "f4b9b739-0b47-4c9a-9e52-a1ea5408e12e", "name": "Tax Engine Core - Test", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Contains core functionality of Tax Engine.", "description": "Core extension contains the UI elements with their tables which are commonly used throughout Tax Engine. Also, it has some library functions available which can be used by any different extension other than Tax Engine to get any value.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -10,25 +10,25 @@ "help": "https://go.microsoft.com/fwlink/?linkid=2139719", "url": "https://go.microsoft.com/fwlink/?linkid=2139719", "logo": "ExtensionLogo.png", - "application": "24.0.0.0", - "platform": "24.0.0.0", + "application": "25.0.0.0", + "platform": "25.0.0.0", "dependencies": [ { "name": "Tax Engine", "id": "c1eafb3f-e397-468e-bdb4-ecc5c317ca00", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "id": "5d86850b-0d76-4eca-bd7b-951ad998e997" }, { "name": "System Application Test Library", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "id": "9856ae4f-d1a7-46ef-89bb-6ef056398228" } ], diff --git a/Apps/W1/INTaxEngine/test/TaxEngine-JsonExchange/app.json b/Apps/W1/INTaxEngine/test/TaxEngine-JsonExchange/app.json index d34a107381..eb2c670fe6 100644 --- a/Apps/W1/INTaxEngine/test/TaxEngine-JsonExchange/app.json +++ b/Apps/W1/INTaxEngine/test/TaxEngine-JsonExchange/app.json @@ -2,7 +2,7 @@ "id": "44e82345-45d2-43f0-a175-06eaadf45457", "name": "Tax Engine Json Exchange Tests", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Provide export and import functionality via JSON files.", "description": "Json Exchange extension will be used where we want to import or export the configuration data of tax engine as json.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -15,20 +15,20 @@ "name": "Tax Engine", "id": "c1eafb3f-e397-468e-bdb4-ecc5c317ca00", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "id": "5d86850b-0d76-4eca-bd7b-951ad998e997" } ], "screenshots": [ ], - "application": "24.0.0.0", - "platform": "24.0.0.0", + "application": "25.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 137700, diff --git a/Apps/W1/INTaxEngine/test/TaxEngine-PostingHandler/app.json b/Apps/W1/INTaxEngine/test/TaxEngine-PostingHandler/app.json index 8ed618efd3..d2af8adce5 100644 --- a/Apps/W1/INTaxEngine/test/TaxEngine-PostingHandler/app.json +++ b/Apps/W1/INTaxEngine/test/TaxEngine-PostingHandler/app.json @@ -2,7 +2,7 @@ "id": "a1069432-ee60-4296-a61f-d1c7e70514a1", "name": "Tax Engine Posting Handler Test", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Executes posting logic of tax and updates tax ledger.", "description": "Posting Handler extension contains UI elements with their tables which can be used for configuring posting of tax components to G/L Accounts and their Tax Ledgers.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -15,32 +15,32 @@ "name": "Tax Engine", "id": "c1eafb3f-e397-468e-bdb4-ecc5c317ca00", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "id": "5d86850b-0d76-4eca-bd7b-951ad998e997" }, { "id": "8af4c184-24a7-4bc5-b7b9-b0ea7f4d5907", "publisher": "Microsoft", "name": "Tax Engine Use Case Builder Tests", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "93eca88b-3dfb-405d-86b0-6a294c0a8339", "publisher": "Microsoft", "name": "Tax Engine Tax Type Handler Tests", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "application": "24.0.0.0", - "platform": "24.0.0.0", + "application": "25.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 137551, diff --git a/Apps/W1/INTaxEngine/test/TaxEngine-ScriptHandler/app.json b/Apps/W1/INTaxEngine/test/TaxEngine-ScriptHandler/app.json index ebaafecdee..5ebd4407a3 100644 --- a/Apps/W1/INTaxEngine/test/TaxEngine-ScriptHandler/app.json +++ b/Apps/W1/INTaxEngine/test/TaxEngine-ScriptHandler/app.json @@ -2,7 +2,7 @@ "id": "7e54a3e1-f903-4308-920e-1e7f36eeceee", "name": "Tax Engine Script Handler Tests", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Provides scripting ability to Tax Engine.", "description": "Script extension contains UI elements with there tables which are used in scripting of Business logics within a use case.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -15,32 +15,32 @@ "name": "Tax Engine", "id": "c1eafb3f-e397-468e-bdb4-ecc5c317ca00", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "id": "5d86850b-0d76-4eca-bd7b-951ad998e997" }, { "name": "System Application Test Library", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "id": "9856ae4f-d1a7-46ef-89bb-6ef056398228" }, { "name": "Tax Engine Core - Test", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "id": "f4b9b739-0b47-4c9a-9e52-a1ea5408e12e" } ], "screenshots": [ ], - "application": "24.0.0.0", - "platform": "24.0.0.0", + "application": "25.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 136751, diff --git a/Apps/W1/INTaxEngine/test/TaxEngine-TaxTypeHandler/app.json b/Apps/W1/INTaxEngine/test/TaxEngine-TaxTypeHandler/app.json index ed2a70b331..4a319d537e 100644 --- a/Apps/W1/INTaxEngine/test/TaxEngine-TaxTypeHandler/app.json +++ b/Apps/W1/INTaxEngine/test/TaxEngine-TaxTypeHandler/app.json @@ -2,7 +2,7 @@ "id": "93eca88b-3dfb-405d-86b0-6a294c0a8339", "name": "Tax Engine Tax Type Handler Tests", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Defines core elements of any tax ex- Components,Attributes,Rates etc.", "description": "Tax Type Handler extension contains UI elements with there tables which are helpers for configuring a business use case.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -10,19 +10,19 @@ "help": "https://go.microsoft.com/fwlink/?linkid=2139719", "url": "https://go.microsoft.com/fwlink/?linkid=2139719", "logo": "ExtensionLogo.png", - "application": "24.0.0.0", - "platform": "24.0.0.0", + "application": "25.0.0.0", + "platform": "25.0.0.0", "dependencies": [ { "name": "Tax Engine", "id": "c1eafb3f-e397-468e-bdb4-ecc5c317ca00", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "id": "5d86850b-0d76-4eca-bd7b-951ad998e997" } ], diff --git a/Apps/W1/INTaxEngine/test/TaxEngine-UseCaseBuilder/app.json b/Apps/W1/INTaxEngine/test/TaxEngine-UseCaseBuilder/app.json index fa2d779ae1..1d8ad50b5c 100644 --- a/Apps/W1/INTaxEngine/test/TaxEngine-UseCaseBuilder/app.json +++ b/Apps/W1/INTaxEngine/test/TaxEngine-UseCaseBuilder/app.json @@ -2,7 +2,7 @@ "id": "8af4c184-24a7-4bc5-b7b9-b0ea7f4d5907", "name": "Tax Engine Use Case Builder Tests", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Use cases and the components calculation logic.", "description": "Tax Use Case Handler extension contains UI elements with their tables which can be used for configuring taxation for a business use case.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -15,32 +15,32 @@ "name": "Tax Engine", "id": "c1eafb3f-e397-468e-bdb4-ecc5c317ca00", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "id": "5d86850b-0d76-4eca-bd7b-951ad998e997" }, { "name": "Tax Engine Tax Type Handler Tests", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "id": "93eca88b-3dfb-405d-86b0-6a294c0a8339" }, { "name": "Tax Engine Core - Test", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "id": "f4b9b739-0b47-4c9a-9e52-a1ea5408e12e" } ], "screenshots": [ ], - "application": "24.0.0.0", - "platform": "24.0.0.0", + "application": "25.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 136851, diff --git a/Apps/W1/INTaxEngine/test/app.json b/Apps/W1/INTaxEngine/test/app.json index 981eea4aa3..15746a7fab 100644 --- a/Apps/W1/INTaxEngine/test/app.json +++ b/Apps/W1/INTaxEngine/test/app.json @@ -2,7 +2,7 @@ "id": "68bed2a6-e0d4-4774-b94f-eb81a3fc6dae", "name": "Tax Engine Test", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Tests for Tax Engine", "description": "Tests for Tax Engine", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -10,25 +10,25 @@ "help": "https://go.microsoft.com/fwlink/?linkid=2139719", "url": "https://go.microsoft.com/fwlink/?linkid=2139719", "logo": "ExtensionLogo.png", - "application": "24.0.0.0", - "platform": "24.0.0.0", + "application": "25.0.0.0", + "platform": "25.0.0.0", "dependencies": [ { "id": "c1eafb3f-e397-468e-bdb4-ecc5c317ca00", "publisher": "Microsoft", "name": "Tax Engine", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "id": "5d86850b-0d76-4eca-bd7b-951ad998e997" }, { "name": "System Application Test Library", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "id": "9856ae4f-d1a7-46ef-89bb-6ef056398228" } ], diff --git a/Apps/W1/ImageAnalysis/app/app.json b/Apps/W1/ImageAnalysis/app/app.json index e3e5b64ca9..febb3d871d 100644 --- a/Apps/W1/ImageAnalysis/app/app.json +++ b/Apps/W1/ImageAnalysis/app/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "Analyze images using Microsoft Cognitive Services.", "description": "Uses Microsoft Cognitive Services to analyze images. Analyze images of an item, and assign item attributes and item category based on the results. Analyze images of a contact, and assign age and gender to the a contact profile questionnaire.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=850308", @@ -17,7 +17,7 @@ "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 1, @@ -30,5 +30,5 @@ "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/W1/ImageAnalysis/app/src/pages/ContactPicAnalyzerExt.PageExt.al b/Apps/W1/ImageAnalysis/app/src/pages/ContactPicAnalyzerExt.PageExt.al index 651c908c2a..e8d00638b5 100644 --- a/Apps/W1/ImageAnalysis/app/src/pages/ContactPicAnalyzerExt.PageExt.al +++ b/Apps/W1/ImageAnalysis/app/src/pages/ContactPicAnalyzerExt.PageExt.al @@ -1,3 +1,4 @@ +#if not CLEAN24 namespace Microsoft.Utility.ImageAnalysis; using System.AI; @@ -9,6 +10,10 @@ using Microsoft.CRM.Contact; pageextension 2027 "Contact Pic Analyzer Ext" extends "Contact Card" { + ObsoleteReason = 'Image analyzer for contacts are being removed.'; + ObsoleteState = Pending; + ObsoleteTag = '24.0'; + layout { } @@ -19,12 +24,15 @@ pageextension 2027 "Contact Pic Analyzer Ext" extends "Contact Card" action(AnalyzePicture) { - Visible = true; ApplicationArea = RelationshipMgmt; Enabled = HasPictureToAnalyze; Caption = 'Analyze Picture'; ToolTip = 'Analyze the picture attached to the contact to identify gender and age, and assign them to the contact.'; Image = Refresh; + Visible = false; + ObsoleteReason = 'Image analyzer for contacts are being removed.'; + ObsoleteState = Pending; + ObsoleteTag = '24.0'; trigger OnAction() var @@ -58,4 +66,5 @@ pageextension 2027 "Contact Pic Analyzer Ext" extends "Contact Card" [InDataSet] HasPictureToAnalyze: Boolean; ImageAnalysisForPersonsOnlyMsg: Label 'The contact you''re analyzing a picture of is a company, not a person. The contact must be a person.'; -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/Apps/W1/ImageAnalysis/test/app.json b/Apps/W1/ImageAnalysis/test/app.json index 3dcd456212..77cf47da79 100644 --- a/Apps/W1/ImageAnalysis/test/app.json +++ b/Apps/W1/ImageAnalysis/test/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "Tests for the Image Analyzer extension.", "description": "Tests for the Image Analyzer extension.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=850308", @@ -16,25 +16,25 @@ "id": "e868ad92-21b8-4e08-af2b-8975a8b06e04", "name": "Image Analyzer", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "9856ae4f-d1a7-46ef-89bb-6ef056398228", "name": "System Application Test Library", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 139500, @@ -51,5 +51,5 @@ "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/W1/Intrastat/app/app.json b/Apps/W1/Intrastat/app/app.json index 76b574dfd5..e5f04bdede 100644 --- a/Apps/W1/Intrastat/app/app.json +++ b/Apps/W1/Intrastat/app/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "The Intrastat extension makes it easy to export the Intrastat report in the format that the authorities in your country require.", "description": "The formats that businesses must use to report Intrastat vary from country to country. The Intrastat extension makes it easy to export the Intrastat report in the format that the authorities in your country require.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=2204541", @@ -17,7 +17,7 @@ "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 4810, @@ -29,6 +29,6 @@ "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0", + "application": "25.0.0.0", "target": "OnPrem" } \ No newline at end of file diff --git a/Apps/W1/Intrastat/app/src/IntrastatReportHeader.Table.al b/Apps/W1/Intrastat/app/src/IntrastatReportHeader.Table.al index f1627112b0..39e368bcd3 100644 --- a/Apps/W1/Intrastat/app/src/IntrastatReportHeader.Table.al +++ b/Apps/W1/Intrastat/app/src/IntrastatReportHeader.Table.al @@ -22,6 +22,8 @@ table 4811 "Intrastat Report Header" Caption = 'No.'; trigger OnValidate() + var + NoSeries: Codeunit "No. Series"; begin if "No." <> xRec."No." then begin IntrastatReportSetup.Get(); @@ -203,8 +205,9 @@ table 4811 "Intrastat Report Header" var IntrastatReportLine: Record "Intrastat Report Line"; IntrastatReportSetup: Record "Intrastat Report Setup"; +#if not CLEAN24 NoSeriesManagement: Codeunit NoSeriesManagement; - NoSeries: Codeunit "No. Series"; +#endif Month: Integer; StatistiscPeriodFormatErr: Label '%1 must be 4 characters, for example, 9410 for October, 1994.', Comment = '%1 - Statistics Period'; MonthNrErr: Label 'Please check the month number.'; @@ -213,6 +216,7 @@ table 4811 "Intrastat Report Header" procedure AssistEdit(xIntrastatReportHeader: Record "Intrastat Report Header") Result: Boolean var IntrastatReportHeader: Record "Intrastat Report Header"; + NoSeries: Codeunit "No. Series"; IsHandled: Boolean; begin IsHandled := false; @@ -223,8 +227,8 @@ table 4811 "Intrastat Report Header" IntrastatReportHeader := Rec; IntrastatReportSetup.Get(); IntrastatReportSetup.TestField("Intrastat Nos."); - if NoSeriesManagement.SelectSeries(IntrastatReportSetup."Intrastat Nos.", xIntrastatReportHeader."No. Series", IntrastatReportHeader."No. Series") then begin - NoSeriesManagement.SetSeries(IntrastatReportHeader."No."); + if NoSeries.LookupRelatedNoSeries(IntrastatReportSetup."Intrastat Nos.", xIntrastatReportHeader."No. Series", IntrastatReportHeader."No. Series") then begin + IntrastatReportHeader."No." := NoSeries.GetNextNo(IntrastatReportHeader."No. Series"); Rec := IntrastatReportHeader; exit(true); end; @@ -245,6 +249,7 @@ table 4811 "Intrastat Report Header" local procedure InitIntrastatNo() var + NoSeries: Codeunit "No. Series"; IsHandled: Boolean; begin IsHandled := false; diff --git a/Apps/W1/Intrastat/app/src/IntrastatReportManagement.Codeunit.al b/Apps/W1/Intrastat/app/src/IntrastatReportManagement.Codeunit.al index 63797af1a6..d623c082c9 100644 --- a/Apps/W1/Intrastat/app/src/IntrastatReportManagement.Codeunit.al +++ b/Apps/W1/Intrastat/app/src/IntrastatReportManagement.Codeunit.al @@ -45,9 +45,15 @@ codeunit 4810 IntrastatReportManagement ReturnRcptHeader: Record "Return Receipt Header"; PurchRcptHeader: Record "Purch. Rcpt. Header"; ReturnShptHeader: Record "Return Shipment Header"; + IsHandled: Boolean; begin IntrastatReportSetup.Get(); + IsHandled := false; + OnBeforeGetIntrastatBaseCountryCode(ItemLedgEntry, IntrastatReportSetup, CountryCode, IsHandled); + if IsHandled then + exit(CountryCode); + CountryCode := ItemLedgEntry."Country/Region Code"; case ItemLedgEntry."Document Type" of @@ -1157,4 +1163,9 @@ codeunit 4810 IntrastatReportManagement local procedure OnAfterGetIntrastatBaseCountryCodeFromFAEntry(var FALedgerEntry: Record "FA Ledger Entry"; var IntrastatReportSetup: Record "Intrastat Report Setup"; var CountryCode: Code[10]); begin end; + + [IntegrationEvent(false, false)] + local procedure OnBeforeGetIntrastatBaseCountryCode(var ItemLedgerEntry: Record "Item Ledger Entry"; var IntrastatReportSetup: Record "Intrastat Report Setup"; var CountryCode: Code[10]; var IsHandled: Boolean) + begin + end; } \ No newline at end of file diff --git a/Apps/W1/Intrastat/app/src/IntrastatReportSubform.Page.al b/Apps/W1/Intrastat/app/src/IntrastatReportSubform.Page.al index 59c900e34a..a26b209396 100644 --- a/Apps/W1/Intrastat/app/src/IntrastatReportSubform.Page.al +++ b/Apps/W1/Intrastat/app/src/IntrastatReportSubform.Page.al @@ -254,7 +254,15 @@ page 4813 "Intrastat Report Subform" procedure UpdateMarkedOnly() begin - Rec.MarkedOnly(not Rec.MarkedOnly); + if Rec.FindSet() then + repeat + Rec.Mark(ErrorsExistOnCurrentLine(Rec)); + until Rec.Next() = 0; + + Rec.MarkedOnly(not Rec.MarkedOnly()); + + if Rec.FindFirst() then + CurrPage.Update(false); end; local procedure UpdateStatisticalValue() @@ -267,14 +275,14 @@ page 4813 "Intrastat Report Subform" StatisticalValueVisible := ShowTotalStatisticalValue; end; - local procedure ErrorsExistOnCurrentLine(): Boolean + local procedure ErrorsExistOnCurrentLine(IntrastatReportLine: Record "Intrastat Report Line"): Boolean var ErrorMessage: Record "Error Message"; IntrastatReportHeader: Record "Intrastat Report Header"; begin - if IntrastatReportHeader.Get(Rec."Intrastat No.") then begin + if IntrastatReportHeader.Get(IntrastatReportLine."Intrastat No.") then begin ErrorMessage.SetContext(IntrastatReportHeader); - exit(ErrorMessage.HasErrorMessagesRelatedTo(Rec)); + exit(ErrorMessage.HasErrorMessagesRelatedTo(IntrastatReportLine)); end else exit(false); end; @@ -288,7 +296,7 @@ page 4813 "Intrastat Report Subform" if IsHandled then exit; - ErrorExists := ErrorsExistOnCurrentLine(); + ErrorExists := ErrorsExistOnCurrentLine(Rec); if ErrorExists then LineStyleExpression := 'Attention' diff --git a/Apps/W1/Intrastat/test/app.json b/Apps/W1/Intrastat/test/app.json index b9c0caa25e..b36abde65b 100644 --- a/Apps/W1/Intrastat/test/app.json +++ b/Apps/W1/Intrastat/test/app.json @@ -2,7 +2,7 @@ "id": "f4d9555a-a512-45de-a6d6-27a8b6077139", "name": "Intrastat Core Tests", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Tests for the Microsoft Intrastat Core extension.", "description": "Tests for the Microsoft Intrastat Core extension.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -10,32 +10,32 @@ "help": "https://go.microsoft.com/fwlink/?linkid=2179727", "url": "https://go.microsoft.com/fwlink/?LinkId=724011", "logo": "ExtensionLogo.png", - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "dependencies": [ { "id": "70912191-3c4c-49fc-a1de-bc6ea1ac9da6", "name": "Intrastat Core", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "9856ae4f-d1a7-46ef-89bb-6ef056398228", "name": "System Application Test Library", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5095f467-0a01-4b99-99d1-9ff1237d286f", "publisher": "Microsoft", "name": "Library Variable Storage", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "idRanges": [ diff --git a/Apps/W1/Intrastat/test/src/LibraryIntrastat.Codeunit.al b/Apps/W1/Intrastat/test/src/LibraryIntrastat.Codeunit.al index 9a7d445339..fb3d96bfd9 100644 --- a/Apps/W1/Intrastat/test/src/LibraryIntrastat.Codeunit.al +++ b/Apps/W1/Intrastat/test/src/LibraryIntrastat.Codeunit.al @@ -670,11 +670,11 @@ codeunit 139554 "Library - Intrastat" var IntrastatReportSetup: Record "Intrastat Report Setup"; NoSeries: Record "No. Series"; - NoSeriesManagement: Codeunit NoSeriesManagement; + NoSeriesCodeunit: Codeunit "No. Series"; begin NoSeries.SetFilter(NoSeries.Code, IntrastatReportSetup."Intrastat Nos."); NoSeries.FindFirst(); - NoSeriesCode := NoSeriesManagement.GetNextNo(NoSeries.Code, WorkDate(), true); + NoSeriesCode := NoSeriesCodeunit.GetNextNo(NoSeries.Code); end; procedure GetStatisticalPeriod(ReportDate: Date): code[20] diff --git a/Apps/W1/LatePaymentPredictor/app/app.json b/Apps/W1/LatePaymentPredictor/app/app.json index 99828c454a..75f47e834c 100644 --- a/Apps/W1/LatePaymentPredictor/app/app.json +++ b/Apps/W1/LatePaymentPredictor/app/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "Predict whether payments for sales will be on-time.", "description": "Keep receivables healthy by assessing the risk of late payments up-front. This extension uses historical data to predict delinquent invoices, so you can take a pre-emptive action such as changing the payment terms.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2182906", "contextSensitiveHelpUrl": "https://go.microsoft.com/fwlink/?linkid=2206446", @@ -17,7 +17,7 @@ "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 1, @@ -30,5 +30,5 @@ "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/W1/LatePaymentPredictor/test/app.json b/Apps/W1/LatePaymentPredictor/test/app.json index ebb68438ce..99559a8961 100644 --- a/Apps/W1/LatePaymentPredictor/test/app.json +++ b/Apps/W1/LatePaymentPredictor/test/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "Tests for the Late Payment Prediction extension.", "description": "Tests for the Late Payment Prediction extension.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=2206446", @@ -16,25 +16,25 @@ "id": "3d5b2137-efeb-4014-8489-41d37f8fd4c3", "name": "Late Payment Prediction", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "9856ae4f-d1a7-46ef-89bb-6ef056398228", "name": "System Application Test Library", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 139500, @@ -51,5 +51,5 @@ "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/W1/LatePaymentPredictor/test/src/LPMLInputDataTest.Codeunit.al b/Apps/W1/LatePaymentPredictor/test/src/LPMLInputDataTest.Codeunit.al index a17d1cfcb0..1d0c517dbc 100644 --- a/Apps/W1/LatePaymentPredictor/test/src/LPMLInputDataTest.Codeunit.al +++ b/Apps/W1/LatePaymentPredictor/test/src/LPMLInputDataTest.Codeunit.al @@ -2,6 +2,7 @@ namespace Microsoft.Finance.Latepayment; using Microsoft.Sales.History; using Microsoft.Sales.Receivables; +using Microsoft.Foundation.Company; using Microsoft.Finance.GeneralLedger.Journal; using Microsoft.Sales.Document; using Microsoft.Inventory.Item; @@ -13,6 +14,7 @@ codeunit 139576 "LP ML Input Data Test" TestPermissions = Disabled; var + CompanyInformation: Record "Company Information"; Assert: Codeunit Assert; LibrarySales: Codeunit "Library - Sales"; LibraryInventory: Codeunit "Library - Inventory"; @@ -138,6 +140,9 @@ codeunit 139576 "LP ML Input Data Test" Invoice1PaidDate: Date; Invoice2PaidDate: Date; begin + CompanyInformation.get(); + if CompanyInformation."Country/Region Code" = 'IT' then + exit; LibraryERMCountryData.UpdateLocalData(); Invoice1CreationDate := DMY2Date(01, 07, 2017); @@ -542,6 +547,9 @@ codeunit 139576 "LP ML Input Data Test" CustomerNo: Code[20]; NewStartingDate: Date; begin + CompanyInformation.get(); + if CompanyInformation."Country/Region Code" = 'IT' then + exit; LPMLInputData.SetCurrentKey("Posting Date"); LPMLInputData.SetAscending("Posting Date", true); if LPMLInputData.FindLast() diff --git a/Apps/W1/LatePaymentPredictor/test/src/LPPredictionTest.Codeunit.al b/Apps/W1/LatePaymentPredictor/test/src/LPPredictionTest.Codeunit.al index 1169601e3c..c3b80bde72 100644 --- a/Apps/W1/LatePaymentPredictor/test/src/LPPredictionTest.Codeunit.al +++ b/Apps/W1/LatePaymentPredictor/test/src/LPPredictionTest.Codeunit.al @@ -10,6 +10,7 @@ using System.AI; using System.Reflection; using System.Environment; using Microsoft.Finance.GeneralLedger.Journal; +using Microsoft.Foundation.Company; codeunit 139575 "LP Prediction Test" { @@ -19,6 +20,7 @@ codeunit 139575 "LP Prediction Test" TestPermissions = Disabled; var + CompanyInformation: Record "Company Information"; Assert: Codeunit Assert; LibrarySales: Codeunit "Library - Sales"; LibraryInventory: Codeunit "Library - Inventory"; @@ -40,7 +42,6 @@ codeunit 139575 "LP Prediction Test" Comment = '%1 = Quality of new model, %2 = Quality of existing model.'; ModelReplacedMsg: Label 'A new model has been created with a quality of %1%.', Comment = '%1 = Quality of the new model'; ModelTestedMsg: Label 'We have tested the model on your data and determined that its quality is %1. The quality indicates how well the model has been trained, and how accurate its predictions will be. For example, 80% means you can expect correct predictions for 80 out of 100 documents.', Comment = '%1 = Quality of the existing model'; - CurrentModelLowerQualityThanDesiredErr: Label 'You cannot use the model because its quality of %1 is below the value in the Model Quality Threshold field. That means its predictions are unlikely to meet your accuracy requirements. You can evaluate the model again to confirm its quality. To use the model anyway, enter a value that is less than or equal to %1 in the Model Quality Threshold field.', Comment = '%1 = current model quality (decimal)'; CurrentTestMethod: Text; State: Integer; NoLPPForLatePaymentTxt: Label 'No prediction needed. The payment for this sales document is already overdue.'; @@ -277,56 +278,6 @@ codeunit 139575 "LP Prediction Test" // [THEN] The result is checked in the handler end; - [Test] - [HandlerFunctions('ModelReplacedMsgHandler')] - procedure TestCreateMyModelSunshine() - var - LPMachineLearningSetup: Record "LP Machine Learning Setup"; - LPModelManagement: Codeunit "LP Model Management"; - begin - // [SCENARIO] Training a model manually creates a model with a quality that is saved in the setup. Enabling the setup with a threshold higher than given model raises error. - Initialize(); - - EnvironmentInfoTestLibrary.SetTestabilitySoftwareAsAService(true); - EnvironmentInfoTestLibrary.SetTestabilitySandbox(true); - EnsureThatMockDataIsFetchedFromKeyVault(); - - if BindSubscription(LPPredictionTest) then; - SomeModelQuality := 0.66; - - // [GIVEN] Enough data for the training - MakeEnoughDataAvailableForTraining(true); - - // [WHEN] Invoke the training of the model - LPMachineLearningSetup.DeleteAll(); - DummyModel := DefaultDummyModelTxt; - LPModelManagement.InvokeTrainFromUi(); - - // [THEN] Model is saved to database with a quality - LPMachineLearningSetup.GetSingleInstance(); - Assert.AreEqual(SomeModelQuality, LPMachineLearningSetup."My Model Quality", 'Fetched incorrect quality'); - Assert.AreEqual(DefaultDummyModelTxt, LPMachineLearningSetup.GetModelAsText(LPMachineLearningSetup."Selected Model"::My), 'Fetched incorrect model'); - Assert.AreEqual(LPMachineLearningSetup."Selected Model"::Standard, LPMachineLearningSetup."Selected Model", 'Should not change selected model'); - UnbindSubscription(LPPredictionTest); - - // [WHEN] The trained model is set to be used - LPMachineLearningSetup.Validate("Selected Model", LPMachineLearningSetup."Selected Model"::My); - - // [WHEN] Threshold is made higher than model quality - LPMachineLearningSetup."Model Quality Threshold" := SomeModelQuality + 0.02; - LPMachineLearningSetup."Standard Model Quality" := 0.6; // arbitrary standard model quality - LPMachineLearningSetup.Modify(); - - // [WHEN] Enabling the prediction - asserterror LPMachineLearningSetup.Validate("Make Predictions", true); - - // [THEN] Raises error - Assert.ExpectedError(StrSubstNo(CurrentModelLowerQualityThanDesiredErr, SomeModelQuality)); - - EnvironmentInfoTestLibrary.SetTestabilitySoftwareAsAService(false); - EnvironmentInfoTestLibrary.SetTestabilitySandbox(false); - end; - [Test] procedure TestCreateMyModelWhenTrainingOngoing() var @@ -383,45 +334,6 @@ codeunit 139575 "LP Prediction Test" Assert.ExpectedError(NotEnoughDataAvailableErr); end; - [Test] - [HandlerFunctions('ModelReplaceConfirmationHandler,ModelReplacedMsgHandler')] - procedure TestCreateMyModelWhenQualityWorseThanExisting() - var - LPMachineLearningSetup: Record "LP Machine Learning Setup"; - LPModelManagement: Codeunit "LP Model Management"; - begin - // [SCENARIO] A custom model already exists. Training a new model leads to a model of poorer quality. User confirms that he stil wishes to use the new model. - Initialize(); - - if BindSubscription(LPPredictionTest) then; - SomeModelQuality := 0.66; - EnvironmentInfoTestLibrary.SetTestabilitySoftwareAsAService(true); - EnvironmentInfoTestLibrary.SetTestabilitySandbox(true); - LPMachineLearningSetup.DeleteAll(); - DummyModel := 'some new but worse model'; - - // [GIVEN] Enough data for training - MakeEnoughDataAvailableForTraining(true); - - // [GIVEN] A model exists with quality higher than the one going to be created - LPMachineLearningSetup.GetSingleInstance(); - LPMachineLearningSetup.SetModel(DefaultDummyModelTxt); - ExistingModelQuality := SomeModelQuality + 0.1; - LPMachineLearningSetup."My Model Quality" := ExistingModelQuality; - LPMachineLearningSetup.Modify(true); - - // [WHEN] Training is invoked - LPModelManagement.InvokeTrainFromUi(); - - // [THEN] After user confirmation, the new model and its quality are saved in the database. - LPMachineLearningSetup.GetSingleInstance(); - Assert.AreEqual(SomeModelQuality, LPMachineLearningSetup."My Model Quality", 'Fetched incorrect quality'); - Assert.AreEqual(DummyModel, LPMachineLearningSetup.GetModelAsText(LPMachineLearningSetup."Selected Model"::My), 'Fetched incorrect model'); - UnbindSubscription(LPPredictionTest); - EnvironmentInfoTestLibrary.SetTestabilitySoftwareAsAService(false); - EnvironmentInfoTestLibrary.SetTestabilitySandbox(false); - end; - [Test] procedure TestBackgroundTaskOnCompanyOpen() var @@ -431,6 +343,8 @@ codeunit 139575 "LP Prediction Test" begin // [SCENARIO] Test the background task calls the evaluate and train in the good sequence and when expected Initialize(); + if CompanyInformation."Country/Region Code" = 'IT' then + exit; EnvironmentInfoTestLibrary.SetTestabilitySoftwareAsAService(true); EnvironmentInfoTestLibrary.SetTestabilitySandbox(true); @@ -605,7 +519,8 @@ codeunit 139575 "LP Prediction Test" begin // [SCENARIO] Testing that there is enough data available as a pre-req for creating/ evaluating models Initialize(); - + if CompanyInformation."Country/Region Code" = 'IT' then + exit; // [GIVEN] Create 50 sales invoices, 3 of them are delayed SalesInvoiceHeader.DeleteAll(); LPMachineLearningSetup.DeleteAll(); @@ -643,6 +558,7 @@ codeunit 139575 "LP Prediction Test" begin LibraryERM.SetEnableDataCheck(false); LibraryERMCountryData.UpdateLocalData(); + CompanyInformation.get(); end; [SendNotificationHandler] diff --git a/Apps/W1/LibraryNoTransactions/app.json b/Apps/W1/LibraryNoTransactions/app.json index edb180def9..242fbad454 100644 --- a/Apps/W1/LibraryNoTransactions/app.json +++ b/Apps/W1/LibraryNoTransactions/app.json @@ -4,8 +4,8 @@ "brief": "Used for testing that no transactions are invoked", "description": "This app is used for testing that the transactions are not executed. If any transaction is detected with this extension published we will throw an error.", "publisher": "Microsoft", - "version": "24.0.0.0", - "platform": "24.0.0.0", + "version": "25.0.0.0", + "platform": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2182906", "help": "https://go.microsoft.com/fwlink/?linkid=2206178", diff --git a/Apps/W1/MSWalletPayments/app/app.json b/Apps/W1/MSWalletPayments/app/app.json index 8f734050c1..8588b8545e 100644 --- a/Apps/W1/MSWalletPayments/app/app.json +++ b/Apps/W1/MSWalletPayments/app/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "The Microsoft Pay Payments service adds a Microsoft Pay Payments link to your sales documents so customers can easily pay using Microsoft Pay Payments. From inside Dynamics 365 Business Central you can send the documents by email to provide higher customer service and shorten the time it takes for customers' payments to arrive on your bank account.", "description": "Customers continuously require higher levels of service, both in terms of the quality of product, but also in terms of delivery and payment services. The Microsoft Pay Payments service adds a Microsoft Pay Payments link to your sales documents so customers can easily pay using Microsoft Pay Payments. You can send the documents by email to provide higher customer service and shorten the time it takes for customer payments to arrive in your bank account. This extension can embed a link to Microsoft Pay Payments on all invoices automatically, or a user can do it on individual invoices. The Microsoft Pay Payments extension gives customers more ways to pay invoices because Microsoft Pay Payments offers multiple ways of handling payments, including credit card processing, WePay, PayPal, and other sources. Plus, Microsoft Pay Payments delivers a trustworthy payment service, which customers prefer to entering credit card information on unknown websites, and Microsoft Pay Payments does not require monthly fees or setup fees. Because this functionality is built as an extension, it gives you full control to enable it when and if your business processes require it.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=857276", @@ -17,7 +17,7 @@ "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 1, @@ -30,5 +30,5 @@ "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/W1/MasterDataManagement/app/app.json b/Apps/W1/MasterDataManagement/app/app.json index 5b1d5bb937..9f80f8cc52 100644 --- a/Apps/W1/MasterDataManagement/app/app.json +++ b/Apps/W1/MasterDataManagement/app/app.json @@ -2,7 +2,7 @@ "id": "a01864f8-9c3f-42f6-8328-8d7be1ce3e20", "name": "_Exclude_Master_Data_Management", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "_Exclude_Master_Data_Management", "description": "_Exclude_Master_Data_Management", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -23,7 +23,7 @@ "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 1, @@ -37,7 +37,7 @@ "includeSourceInSymbolFile": true }, "target": "Cloud", - "application": "24.0.0.0", + "application": "25.0.0.0", "features": [ "TranslationFile", "GenerateCaptions" diff --git a/Apps/W1/MasterDataManagement/app/src/codeunits/MasterDataManagement.Codeunit.al b/Apps/W1/MasterDataManagement/app/src/codeunits/MasterDataManagement.Codeunit.al index 78feab7aad..41df6591f4 100644 --- a/Apps/W1/MasterDataManagement/app/src/codeunits/MasterDataManagement.Codeunit.al +++ b/Apps/W1/MasterDataManagement/app/src/codeunits/MasterDataManagement.Codeunit.al @@ -1739,7 +1739,9 @@ codeunit 7233 "Master Data Management" local procedure HandleOnIsRecordRefModifiedAfterRecordLastSynch(IntegrationTableConnectionType: TableConnectionType; var SourceRecordRef: RecordRef; LastModifiedOn: DateTime; var IsModified: Boolean; var IsHandled: Boolean) var MasterDataMgtCoupling: Record "Master Data Mgt. Coupling"; + IntegrationTableMapping: Record "Integration Table Mapping"; TypeHelper: Codeunit "Type Helper"; + DateToCompareWith: DateTime; begin if IntegrationTableConnectionType <> IntegrationTableConnectionType::ExternalSQL then exit; @@ -1747,11 +1749,31 @@ codeunit 7233 "Master Data Management" if not IsEnabled() then exit; + OnIsRecordRefModifiedAfterRecordLastSynch(SourceRecordRef, LastModifiedOn, IsModified, IsHandled); + if IsHandled then + exit; + if MasterDataMgtCoupling.FindRowFromRecordRef(SourceRecordRef, MasterDataMgtCoupling) then begin - if (MasterDataMgtCoupling."Last Synch. Int. Result" = MasterDataMgtCoupling."Last Synch. Int. Result"::Failure) and (MasterDataMgtCoupling.Skipped = false) then - IsModified := true - else - IsModified := TypeHelper.CompareDateTime(LastModifiedOn, MasterDataMgtCoupling."Last Synch. Modified On") > 0; + if (MasterDataMgtCoupling."Last Synch. Int. Result" = MasterDataMgtCoupling."Last Synch. Int. Result"::Failure) and (MasterDataMgtCoupling.Skipped = false) then begin + IsModified := true; + IsHandled := true; + exit; + end; + DateToCompareWith := MasterDataMgtCoupling."Last Synch. Modified On"; + IntegrationTableMapping.SetRange(Type, IntegrationTableMapping.Type::"Master Data Management"); + IntegrationTableMapping.SetRange("Delete After Synchronization", false); + IntegrationTableMapping.SetRange("Table ID", SourceRecordRef.Number()); + IntegrationTableMapping.SetRange("Integration Table ID", SourceRecordRef.Number()); + if IntegrationTableMapping.FindFirst() then begin + if IntegrationTableMapping."Synch. Modified On Filter" = 0DT then begin + IsModified := true; + IsHandled := true; + exit; + end; + if IntegrationTableMapping."Synch. Modified On Filter" < DateToCompareWith then + DateToCompareWith := IntegrationTableMapping."Synch. Modified On Filter" - 999; + end; + IsModified := TypeHelper.CompareDateTime(LastModifiedOn, DateToCompareWith) > 0; IsHandled := true; end; end; @@ -2364,5 +2386,10 @@ codeunit 7233 "Master Data Management" internal procedure OnLocalRecordChangeOverwrite(var SourceFieldRef: FieldRef; var DestinationFieldRef: FieldRef; var ThrowError: Boolean; var IsHandled: Boolean) begin end; + + [IntegrationEvent(false, false)] + local procedure OnIsRecordRefModifiedAfterRecordLastSynch(var SourceRecordRef: RecordRef; LastModifiedOn: DateTime; var IsModified: Boolean; var IsHandled: Boolean) + begin + end; } diff --git a/Apps/W1/MasterDataManagement/app/src/codeunits/MasterDataMgtSetupDefault.Codeunit.al b/Apps/W1/MasterDataManagement/app/src/codeunits/MasterDataMgtSetupDefault.Codeunit.al index 7308ab925d..436a131d42 100644 --- a/Apps/W1/MasterDataManagement/app/src/codeunits/MasterDataMgtSetupDefault.Codeunit.al +++ b/Apps/W1/MasterDataManagement/app/src/codeunits/MasterDataMgtSetupDefault.Codeunit.al @@ -1455,6 +1455,7 @@ codeunit 7230 "Master Data Mgt. Setup Default" var JobQueueEntry: Record "Job Queue Entry"; MasterDataManagement: Codeunit "Master Data Management"; + SynchronizationTableRecRef: RecordRef; IsHandled: Boolean; begin MasterDataManagement.OnHandleRecreateJobQueueEntryFromIntegrationTableMapping(JobQueueEntry, IntegrationTableMapping, IsHandled); @@ -1470,8 +1471,11 @@ codeunit 7230 "Master Data Mgt. Setup Default" JobQueueEntry."Object ID to Run" := Codeunit::"Integration Synch. Job Runner"; JobQueueEntry."Record ID to Process" := IntegrationTableMapping.RecordId(); JobQueueEntry."Run in User Session" := false; - JobQueueEntry.Description := - CopyStr(StrSubstNo(JobQueueEntryNameTok, IntegrationTableMapping.Name, ServiceName), 1, MaxStrLen(JobQueueEntry.Description)); + if IntegrationTableMapping."Table ID" <> 0 then begin + SynchronizationTableRecRef.Open(IntegrationTableMapping."Table ID"); + JobQueueEntry.Description := CopyStr(StrSubstNo(JobQueueEntryNameTok, SynchronizationTableRecRef.Caption(), ServiceName), 1, MaxStrLen(JobQueueEntry.Description)); + end else + JobQueueEntry.Description := CopyStr(StrSubstNo(JobQueueEntryNameTok, IntegrationTableMapping.Name, ServiceName), 1, MaxStrLen(JobQueueEntry.Description)); JobQueueEntry."Maximum No. of Attempts to Run" := 10; JobQueueEntry.Status := JobQueueEntry.Status::Ready; JobQueueEntry."Rerun Delay (sec.)" := 30; @@ -1482,6 +1486,8 @@ codeunit 7230 "Master Data Mgt. Setup Default" JobQueueEntry."Job Queue Category Code" := CustomerContactJobQueueCategoryLbl else JobQueueEntry."Job Queue Category Code" := JobQueueCategoryLbl; + + OnBeforeInsertJobQueueEntryForSynchronizationTable(JobQueueEntry, IntegrationTableMapping, ShouldRecreateJobQueueEntry); if ShouldRecreateJobQueueEntry then Codeunit.Run(Codeunit::"Job Queue - Enqueue", JobQueueEntry) else begin @@ -1676,5 +1682,10 @@ codeunit 7230 "Master Data Mgt. Setup Default" local procedure OnAfterResetTableMapping(var IntegrationTableMappingName: Code[20]; var ShouldRecreateJobQueueEntry: Boolean; var IsHandled: Boolean) begin end; + + [IntegrationEvent(false, false)] + local procedure OnBeforeInsertJobQueueEntryForSynchronizationTable(var JobQueueEntry: Record "Job Queue Entry"; var IntegrationTableMapping: Record "Integration Table Mapping"; var ShouldScheduleJobQueueEntry: Boolean); + begin + end; } diff --git a/Apps/W1/MasterDataManagement/app/src/pages/MasterDataSynchTables.Page.al b/Apps/W1/MasterDataManagement/app/src/pages/MasterDataSynchTables.Page.al index 340d9ae148..61d72718f8 100644 --- a/Apps/W1/MasterDataManagement/app/src/pages/MasterDataSynchTables.Page.al +++ b/Apps/W1/MasterDataManagement/app/src/pages/MasterDataSynchTables.Page.al @@ -567,6 +567,8 @@ page 7233 "Master Data Synch. Tables" I += 1; end; + OnAddSynchronizationTableChooseMappingName(IntegrationTableMappingName, TableNo); + ShouldEnqueueJob := true; if MasterDataManagementSetup.Get() then ShouldEnqueueJob := (not MasterDataManagementSetup."Delay Job Scheduling"); @@ -664,6 +666,12 @@ page 7233 "Master Data Synch. Tables" if JQueueEntry.FindFirst() then Page.Run(Page::"Job Queue Entries", JQueueEntry); end; + + [IntegrationEvent(false, false)] + local procedure OnAddSynchronizationTableChooseMappingName(var IntegrationTableMappingName: Code[20]; TableNo: Integer); + begin + end; + } diff --git a/Apps/W1/MasterDataManagement/app/src/xmlports/ExportMDMSetup.XmlPort.al b/Apps/W1/MasterDataManagement/app/src/xmlports/ExportMDMSetup.XmlPort.al index 7b1c3e488b..049619a89c 100644 --- a/Apps/W1/MasterDataManagement/app/src/xmlports/ExportMDMSetup.XmlPort.al +++ b/Apps/W1/MasterDataManagement/app/src/xmlports/ExportMDMSetup.XmlPort.al @@ -174,7 +174,7 @@ xmlport 7230 ExportMDMSetup begin integrationTableMapping.CalcFields("Table Filter", "Integration Table Filter"); integrationTableMapping."Table Filter".CreateInStream(TableFilterInStr); - integrationTableMapping."Table Filter".CreateInStream(IntegrationTableFilterInStr); + integrationTableMapping."Integration Table Filter".CreateInStream(IntegrationTableFilterInStr); TableFilterInStr.ReadText(tableFilterText); IntegrationTableFilterInStr.ReadText(integrationTableFilterText); end; diff --git a/Apps/W1/MasterDataManagement/test library/app.json b/Apps/W1/MasterDataManagement/test library/app.json index 6e87f65078..2bd8fc0503 100644 --- a/Apps/W1/MasterDataManagement/test library/app.json +++ b/Apps/W1/MasterDataManagement/test library/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "Test library for the _Exclude_Master_Data_Management extension.", "description": "Test library for the _Exclude_Master_Data_Management extension.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2182906", "help": "https://go.microsoft.com/fwlink/?linkid=2206176", @@ -16,18 +16,18 @@ "id": "a01864f8-9c3f-42f6-8328-8d7be1ce3e20", "name": "_Exclude_Master_Data_Management", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "target": "Cloud", "resourceExposurePolicy": { "allowDebugging": false, "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/W1/MasterDataManagement/test/app.json b/Apps/W1/MasterDataManagement/test/app.json index f6c2284d60..9494e85efe 100644 --- a/Apps/W1/MasterDataManagement/test/app.json +++ b/Apps/W1/MasterDataManagement/test/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "Tests for the _Exclude_Master_Data_Management extension.", "description": "Tests for the _Exclude_Master_Data_Management extension.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2182906", "help": "https://go.microsoft.com/fwlink/?linkid=2206176", @@ -16,36 +16,36 @@ "id": "a01864f8-9c3f-42f6-8328-8d7be1ce3e20", "name": "_Exclude_Master_Data_Management", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5095f467-0a01-4b99-99d1-9ff1237d286f", "publisher": "Microsoft", "name": "Library Variable Storage", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "044e7b4c-db9b-43c6-8a08-e1fd8954d40c", "name": "_Exclude_Master_Data_Management_Test_Library", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "target": "Cloud", "resourceExposurePolicy": { "allowDebugging": false, "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/W1/MasterDataManagement/test/src/MasterDataMgtSetupTests.Codeunit.al b/Apps/W1/MasterDataManagement/test/src/MasterDataMgtSetupTests.Codeunit.al index 886630ccc6..532de8a7e5 100644 --- a/Apps/W1/MasterDataManagement/test/src/MasterDataMgtSetupTests.Codeunit.al +++ b/Apps/W1/MasterDataManagement/test/src/MasterDataMgtSetupTests.Codeunit.al @@ -106,6 +106,7 @@ codeunit 139770 "Master Data Mgt. Setup Tests" IntegrationFieldMapping: Record "Integration Field Mapping"; JobQueueEntry: Record "Job Queue Entry"; MasterDataMgtSetupTests: Codeunit "Master Data Mgt. Setup Tests"; + MasterDataMgtSynchTests: Codeunit "Master Data Mgt. Synch. Tests"; EmptyGuid: Guid; begin Initialize(); @@ -113,8 +114,10 @@ codeunit 139770 "Master Data Mgt. Setup Tests" MasterDataManagementSetup."Company Name" := CopyStr(LibraryRandom.RandText(30), 1, MaxStrLen(MasterDataManagementSetup."Company Name")); MasterDataManagementSetup.Validate("Is Enabled", true); BindSubscription(MasterDataMgtSetupTests); + BindSubscription(MasterDataMgtSynchTests); MasterDataManagementSetup.Insert(true); UnbindSubscription(MasterDataMgtSetupTests); + UnbindSubscription(MasterDataMgtSynchTests); // insert a dummy coupling MasterDataMgtCoupling."Integration System ID" := EmptyGuid; @@ -176,6 +179,7 @@ codeunit 139770 "Master Data Mgt. Setup Tests" var MasterDataManagementSetup: Record "Master Data Management Setup"; IntegrationTableMapping: Record "Integration Table Mapping"; + JobQueueEntry: Record "Job Queue Entry"; MasterDataMgtSetupTests: Codeunit "Master Data Mgt. Setup Tests"; TempBlob: Codeunit "Temp Blob"; InStr: InStream; @@ -195,6 +199,9 @@ codeunit 139770 "Master Data Mgt. Setup Tests" TempBlob.CreateInStream(InStr, TEXTENCODING::UTF16); // mappings and job queue entries are deleted + JobQueueEntry.SetRange("Object ID to Run", Codeunit::"Integration Synch. Job Runner"); + JobQueueEntry.SetRange("Recurring Job", true); + JobQueueEntry.DeleteAll(); IntegrationTableMapping.SetRange(Type, IntegrationTableMapping.Type::"Master Data Management"); if IntegrationTableMapping.FindSet() then repeat @@ -280,15 +287,20 @@ codeunit 139770 "Master Data Mgt. Setup Tests" IntegrationFieldMapping: Record "Integration Field Mapping"; JobQueueEntry: Record "Job Queue Entry"; MasterDataMgtSetupTests: Codeunit "Master Data Mgt. Setup Tests"; + MasterDataMgtSynchTests: Codeunit "Master Data Mgt. Synch. Tests"; EmptyGuid: Guid; begin Initialize(); + JobQueueEntry.SetRange("Object ID to Run", Codeunit::"Integration Synch. Job Runner"); + JobQueueEntry.DeleteAll(); MasterDataManagementSetup.Init(); MasterDataManagementSetup."Company Name" := CopyStr(LibraryRandom.RandText(30), 1, MaxStrLen(MasterDataManagementSetup."Company Name")); MasterDataManagementSetup.Validate("Is Enabled", true); BindSubscription(MasterDataMgtSetupTests); + BindSubscription(MasterDataMgtSynchTests); MasterDataManagementSetup.Insert(true); UnbindSubscription(MasterDataMgtSetupTests); + UnbindSubscription(MasterDataMgtSynchTests); // insert a dummy coupling MasterDataMgtCoupling."Integration System ID" := EmptyGuid; @@ -317,7 +329,7 @@ codeunit 139770 "Master Data Mgt. Setup Tests" IntegrationTableMapping: Record "Integration Table Mapping"; MasterDataMgtCoupling: Record "Master Data Mgt. Coupling"; MasterDataMgtSubscriber: Record "Master Data Mgt. Subscriber"; - JObQueueEntry: Record "Job Queue Entry"; + MasterDataMgtSynchTests: Codeunit "Master Data Mgt. Synch. Tests"; begin OnBeforeInitialize(InitializeHandled); if InitializeHandled then @@ -325,16 +337,16 @@ codeunit 139770 "Master Data Mgt. Setup Tests" LibrarySetupStorage.Restore(); + BindSubscription(MasterDataMgtSynchTests); IntegrationTableMapping.SetRange(Type, IntegrationTableMapping.Type::"Master Data Management"); if IntegrationTableMapping.FindSet() then repeat IntegrationTableMapping.Delete(true); until IntegrationTableMapping.Next() = 0; - JobQueueEntry.SetRange("Object ID to Run", Codeunit::"Integration Synch. Job Runner"); - JobQueueEntry.DeleteAll(); MasterDataMgtCoupling.DeleteAll(); MasterDataManagementSetup.DeleteAll(); MasterDataMgtSubscriber.DeleteAll(); + UnbindSubscription(MasterDataMgtSynchTests); Commit(); OnAfterInitialize(InitializeHandled); end; diff --git a/Apps/W1/MicrosoftUniversalPrint/app.json b/Apps/W1/MicrosoftUniversalPrint/app.json index 9551735dfb..84c8ed3b8f 100644 --- a/Apps/W1/MicrosoftUniversalPrint/app.json +++ b/Apps/W1/MicrosoftUniversalPrint/app.json @@ -2,7 +2,7 @@ "id": "2654d7e7-9afd-4947-9e02-6bb8f3e0cd04", "name": "Universal Print Integration", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Provides functionality for integrating with Microsoft 365 Universal Print.", "description": "Provides functionality for using Microsoft 365 Universal Print to let users print to any printer managed by their organization from any device using their AAD credentials.", "privacyStatement": "https://go.microsoft.com/fwlink/?linkid=724009", @@ -10,8 +10,8 @@ "help": "https://go.microsoft.com/fwlink/?linkid=2206179", "url": "https://go.microsoft.com/fwlink/?linkid=724011", "logo": "ExtensionLogo.png", - "application": "24.0.0.0", - "platform": "24.0.0.0", + "application": "25.0.0.0", + "platform": "25.0.0.0", "screenshots": [ ], diff --git a/Apps/W1/OnPrem Permissions/app/app.json b/Apps/W1/OnPrem Permissions/app/app.json index 085ec171a0..269848b53e 100644 --- a/Apps/W1/OnPrem Permissions/app/app.json +++ b/Apps/W1/OnPrem Permissions/app/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "This extension includes permission set for on premise systems.", "description": "This extension includes permission set for on premise systems.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=2009036", @@ -17,11 +17,11 @@ "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "resourceExposurePolicy": { "allowDebugging": false, "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/W1/OnPrem Permissions/test/app.json b/Apps/W1/OnPrem Permissions/test/app.json index dc240ce22e..1d61d279f3 100644 --- a/Apps/W1/OnPrem Permissions/test/app.json +++ b/Apps/W1/OnPrem Permissions/test/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "This extension includes tests for the onprem permission sets.", "description": "This extension includes tests for the onprem permission sets.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=2009036", @@ -16,24 +16,24 @@ "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5095f467-0a01-4b99-99d1-9ff1237d286f", "publisher": "Microsoft", "name": "Library Variable Storage", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "resourceExposurePolicy": { "allowDebugging": false, "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0", + "application": "25.0.0.0", "target": "OnPrem" } \ No newline at end of file diff --git a/Apps/W1/OnboardingSignals/app/app.json b/Apps/W1/OnboardingSignals/app/app.json index c873833e7a..44aed45ddc 100644 --- a/Apps/W1/OnboardingSignals/app/app.json +++ b/Apps/W1/OnboardingSignals/app/app.json @@ -2,7 +2,7 @@ "id": "672777d5-ab26-4369-b334-6f04256efffd", "name": "_Exclude_Onboarding Signals", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Adding first party Onboarding Signals", "description": "Adding Microsoft Onboarding Signals and Providing an example how Onboarding Signals can be added.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -24,8 +24,8 @@ "publisher": "Microsoft" } ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 20370, diff --git a/Apps/W1/OnboardingSignals/test/app.json b/Apps/W1/OnboardingSignals/test/app.json index 762992b1dc..a7841f01bd 100644 --- a/Apps/W1/OnboardingSignals/test/app.json +++ b/Apps/W1/OnboardingSignals/test/app.json @@ -2,7 +2,7 @@ "id": "b0189501-269d-460e-bf1d-38a7bc5e5deb", "name": "_Exclude_Onboarding Signals Tests", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Tests for first party Onboarding Signals", "description": "Tests for Microsoft Onboarding Signals and Providing an example how Onboarding Signals can be tested.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -16,26 +16,26 @@ "id": "672777d5-ab26-4369-b334-6f04256efffd", "name": "_Exclude_Onboarding Signals", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "9856ae4f-d1a7-46ef-89bb-6ef056398228", "name": "System Application Test Library", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 139536, diff --git a/Apps/W1/PayPalPaymentsStandard/app/app.json b/Apps/W1/PayPalPaymentsStandard/app/app.json index 9d61c91274..309e86de4f 100644 --- a/Apps/W1/PayPalPaymentsStandard/app/app.json +++ b/Apps/W1/PayPalPaymentsStandard/app/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "Payment Links to PayPal adds a PayPal link to your sales documents so customers can easily pay using PayPal. From inside Dynamics 365 Business Central; you can send the documents by email to provide higher customer service and shorten the time it takes for customers' payments to arrive on your bank account.", "description": "Customers continuously require higher levels of service, both in terms of the quality of product, but also in terms of delivery and payment services. PayPal Payments Standard adds a PayPal link to your sales documents so customers can easily pay using PayPal. You can send the documents by email to provide higher customer service and shorten the time it takes for customer payments to arrive in your bank account. This extension can embed a link to PayPal on all invoices automatically, or a user can do it on individual invoices. The PayPal Payments Standard extension gives customers more ways to pay invoices because PayPal offers multiple ways of handling payments, including credit card processing, PayPal accounts, and other sources. Plus, PayPal delivers a trustworthy payment service, which customers prefer to entering credit card information on unknown websites, and PayPal does not require monthly fees or setup fees. Because this functionality is built as an extension, it gives you full control to enable it when and if your business processes require it.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?LinkId=733363", @@ -17,7 +17,7 @@ "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 1, @@ -30,5 +30,5 @@ "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/W1/PayPalPaymentsStandard/test/app.json b/Apps/W1/PayPalPaymentsStandard/test/app.json index d2308babae..fe48c64859 100644 --- a/Apps/W1/PayPalPaymentsStandard/test/app.json +++ b/Apps/W1/PayPalPaymentsStandard/test/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "Tests for the PayPal Payments Standard extension.", "description": "Tests for the PayPal Payments Standard extension.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?LinkId=733363", @@ -16,31 +16,31 @@ "id": "d09fa965-9a2a-424d-b704-69f3b54ed0ce", "name": "Payment Links to PayPal", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "9856ae4f-d1a7-46ef-89bb-6ef056398228", "name": "System Application Test Library", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5095f467-0a01-4b99-99d1-9ff1237d286f", "publisher": "Microsoft", "name": "Library Variable Storage", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 139500, @@ -57,5 +57,5 @@ "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/W1/PaymentPractices/app/app.json b/Apps/W1/PaymentPractices/app/app.json index 8c098a2777..5223b40cdc 100644 --- a/Apps/W1/PaymentPractices/app/app.json +++ b/Apps/W1/PaymentPractices/app/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "The Payment Practices app introduces a feature enabling the calculation of payment times, aggregated across various metrics.", "description": "Numerous countries have regulatory requirements to report payment times to vendors. This app offers a user-friendly solution to report payment times for both vendors and customers. Additionally, it offers adaptable interfaces for introducing personalized aggregation methods and data collection.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?LinkId=724011", @@ -17,7 +17,7 @@ "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 685, @@ -29,6 +29,6 @@ "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0", + "application": "25.0.0.0", "target": "Cloud" } \ No newline at end of file diff --git a/Apps/W1/PaymentPractices/test/app.json b/Apps/W1/PaymentPractices/test/app.json index e801be183c..f8ea4a9c91 100644 --- a/Apps/W1/PaymentPractices/test/app.json +++ b/Apps/W1/PaymentPractices/test/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "Tests for Payment Practices app.", "description": "Tests for Payment Practices app.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?LinkId=724011", @@ -16,31 +16,31 @@ "id": "64977288-facd-4b48-aaaa-bb0e288edfb3", "name": "Payment Practices", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "9856ae4f-d1a7-46ef-89bb-6ef056398228", "name": "System Application Test Library", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5095f467-0a01-4b99-99d1-9ff1237d286f", "publisher": "Microsoft", "name": "Library Variable Storage", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 134196, @@ -52,6 +52,6 @@ "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0", + "application": "25.0.0.0", "target": "Cloud" } \ No newline at end of file diff --git a/Apps/W1/PlanConfiguration/app/Entitlements/DelegatedBCAdminAgentPartnerPlanConfiguration.Entitlement.al b/Apps/W1/PlanConfiguration/app/Entitlements/DelegatedBCAdminAgentPartnerPlanConfiguration.Entitlement.al new file mode 100644 index 0000000000..08f0868c2f --- /dev/null +++ b/Apps/W1/PlanConfiguration/app/Entitlements/DelegatedBCAdminAgentPartnerPlanConfiguration.Entitlement.al @@ -0,0 +1,15 @@ +#if not CLEAN22 +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ + +entitlement "Delegated BC Admin agent - Partner - Plan Configuration" +{ + Type = Role; + RoleType = Delegated; + Id = '00000000-0000-0000-0000-000000000010'; + + ObjectEntitlements = "Plan Configuration - Edit"; +} +#endif \ No newline at end of file diff --git a/Apps/W1/PlanConfiguration/app/Entitlements/InternalBCAdministratorPlanConfiguration.Entitlement.al b/Apps/W1/PlanConfiguration/app/Entitlements/InternalBCAdministratorPlanConfiguration.Entitlement.al new file mode 100644 index 0000000000..0ef4da5536 --- /dev/null +++ b/Apps/W1/PlanConfiguration/app/Entitlements/InternalBCAdministratorPlanConfiguration.Entitlement.al @@ -0,0 +1,16 @@ +#if not CLEAN22 +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ + +entitlement "Internal BC Administrator - Plan Configuration" +{ + Type = Role; + RoleType = Local; + Id = '963797fb-eb3b-4cde-8ce3-5878b3f32a3f'; + + ObjectEntitlements = "Plan Configuration - Edit"; +} + +#endif \ No newline at end of file diff --git a/Apps/W1/PlanConfiguration/app/app.json b/Apps/W1/PlanConfiguration/app/app.json index 258df98a9c..593435821f 100644 --- a/Apps/W1/PlanConfiguration/app/app.json +++ b/Apps/W1/PlanConfiguration/app/app.json @@ -2,7 +2,7 @@ "id": "5f92e0d5-a60e-435f-ae85-71ec28dd3e41", "name": "_Exclude_PlanConfiguration_", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Manage default user groups for license", "description": "Manage default user groups for license", "privacyStatement": "https://go.microsoft.com/fwlink/?linkid=724009", @@ -17,8 +17,8 @@ "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 9048, diff --git a/Apps/W1/PlanConfiguration/app/src/UpgradeCustomUserGroups.Codeunit.al b/Apps/W1/PlanConfiguration/app/src/UpgradeCustomUserGroups.Codeunit.al index f585f435aa..aff2a78248 100644 --- a/Apps/W1/PlanConfiguration/app/src/UpgradeCustomUserGroups.Codeunit.al +++ b/Apps/W1/PlanConfiguration/app/src/UpgradeCustomUserGroups.Codeunit.al @@ -13,6 +13,7 @@ codeunit 9032 "Upgrade Custom User Groups" // Even though this codeunit will not have the OnUpgradePerDatabase trigger, // in v25+ the event subscriber will always run in the upgrade context. Subtype = Upgrade; + Permissions = tabledata "Custom User Group In Plan" = r; [EventSubscriber(ObjectType::Codeunit, Codeunit::"Upgrade User Groups", 'OnMigrateUserGroups', '', false, false)] local procedure TransferCustomPermissionsPerPlan() diff --git a/Apps/W1/PlanConfiguration/test/app.json b/Apps/W1/PlanConfiguration/test/app.json index c31d797ed2..6677946aee 100644 --- a/Apps/W1/PlanConfiguration/test/app.json +++ b/Apps/W1/PlanConfiguration/test/app.json @@ -2,7 +2,7 @@ "id": "0253c250-e019-491f-adf4-e8fd8f10e6b9", "name": "_Exclude_PlanConfiguration_ Tests", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Tests for Plan Configuration", "description": "Tests for Plan Configuration", "privacyStatement": "https://go.microsoft.com/fwlink/?linkid=724009", @@ -16,38 +16,38 @@ "id": "5f92e0d5-a60e-435f-ae85-71ec28dd3e41", "name": "_Exclude_PlanConfiguration_", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "e7320ebb-08b3-4406-b1ec-b4927d3e280b", "name": "Any", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "dd0be2ea-f733-4d65-bb34-a28f4624fb14", "name": "Library Assert", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "9856ae4f-d1a7-46ef-89bb-6ef056398228", "name": "System Application Test Library", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 139509, diff --git a/Apps/W1/PlanConfiguration/test/src/AzureADPlanModuleTest.codeunit.al b/Apps/W1/PlanConfiguration/test/src/AzureADPlanModuleTest.codeunit.al index 6c33137402..5eccffa492 100644 --- a/Apps/W1/PlanConfiguration/test/src/AzureADPlanModuleTest.codeunit.al +++ b/Apps/W1/PlanConfiguration/test/src/AzureADPlanModuleTest.codeunit.al @@ -21,9 +21,9 @@ codeunit 139509 "Azure AD Plan Module Test" TestUserGroupTxt: Label 'TEST UG'; #endif TestPlanIdTxt: Label '{6fe0b5b8-d2df-4741-8d03-f57ac1101851}'; - MixedPlansNonAdminErr: Label 'All users must be assigned to the same license, either Basic, Essential, or Premium. %1 and %2 are assigned to different licenses, for example, but there may be other mismatches. Your system administrator or Microsoft partner can verify license assignments in your Microsoft 365 admin portal.\\We will sign you out when you choose the OK button.', Locked = true; - MixedPlansMsg: Label 'One or more users are not assigned to the same Business Central license. For example, we found that users %1 and %2 are assigned to different licenses, but there may be other mismatches. In your Microsoft 365 admin center, make sure that all users are assigned to the same Business Central license, either Basic, Essential, or Premium. Afterward, update Business Central by opening the Users page and using the ''Update Users from Office 365'' action.', Comment = '%1 = %2 = Authentication email.'; TestRoleIdTxt: Label 'TEST PS'; + MixedPlansExpectedErr: Label 'Expected mixed plans'; + MixedPlansNotExpectedErr: Label 'Did not expected mixed plans'; [Test] @@ -443,7 +443,6 @@ codeunit 139509 "Azure AD Plan Module Test" #endif [Test] - [HandlerFunctions('HandleAndVerifyChangedPlanMessageOK')] [TransactionModel(TransactionModel::AutoRollback)] [Scope('OnPrem')] procedure TestCheckMixedPlansWhenUserHasAccessToEditUserPlanAndPermissionsBasicAndEssentials() @@ -475,7 +474,8 @@ codeunit 139509 "Azure AD Plan Module Test" LibraryLowerPermissions.AddSecurity(); FirstUserAuthenticationEmail := BasicUser."Authentication Email"; SecondUserAuthenticationEmail := EssentialUser."Authentication Email"; - AzureADPlan.CheckMixedPlans(); + + Assert.IsTrue(AzureADPlan.CheckMixedPlansExist(), MixedPlansExpectedErr); // Rollback SaaS test TearDown(); @@ -484,7 +484,6 @@ codeunit 139509 "Azure AD Plan Module Test" end; [Test] - [HandlerFunctions('HandleAndVerifyChangedPlanMessageOK')] [TransactionModel(TransactionModel::AutoRollback)] [Scope('OnPrem')] procedure TestCheckMixedPlansWhenUserHasAccessToEditUserPlanAndPermissionsBasicAndPremium() @@ -517,7 +516,8 @@ codeunit 139509 "Azure AD Plan Module Test" LibraryLowerPermissions.AddSecurity(); FirstUserAuthenticationEmail := BasicUser."Authentication Email"; SecondUserAuthenticationEmail := PremiumUser."Authentication Email"; - AzureADPlan.CheckMixedPlans(); + + Assert.IsTrue(AzureADPlan.CheckMixedPlansExist(), MixedPlansExpectedErr); // Rollback SaaS test TearDown(); @@ -526,7 +526,6 @@ codeunit 139509 "Azure AD Plan Module Test" end; [Test] - [HandlerFunctions('HandleAndVerifyChangedPlanMessageOK')] [TransactionModel(TransactionModel::AutoRollback)] [Scope('OnPrem')] procedure TestCheckMixedPlansWhenUserHasAccessToEditUserPlanAndPermissionsEssentialAndPremium() @@ -558,7 +557,8 @@ codeunit 139509 "Azure AD Plan Module Test" LibraryLowerPermissions.AddSecurity(); FirstUserAuthenticationEmail := EssentialUser."Authentication Email"; SecondUserAuthenticationEmail := PremiumUser."Authentication Email"; - AzureADPlan.CheckMixedPlans(); + + Assert.IsTrue(AzureADPlan.CheckMixedPlansExist(), MixedPlansNotExpectedErr); // Rollback SaaS test TearDown(); @@ -595,13 +595,10 @@ codeunit 139509 "Azure AD Plan Module Test" // [WHEN] CheckMixedPlans invoked LibraryLowerPermissions.SetO365Basic(); - asserterror AzureADPlan.CheckMixedPlans(); + Assert.IsTrue(AzureADPlan.CheckMixedPlansExist(), MixedPlansNotExpectedErr); // Rollback SaaS test TearDown(); - - // [THEN] Error is thrown - Assert.ExpectedError(StrSubstNo(MixedPlansNonAdminErr, EssentialUser."Authentication Email", PremiumUser."Authentication Email")); end; [Test] @@ -633,7 +630,8 @@ codeunit 139509 "Azure AD Plan Module Test" // [WHEN] CheckMixedPlans invoked LibraryLowerPermissions.SetO365Basic(); ; - AzureADPlan.CheckMixedPlans(); + + Assert.IsFalse(AzureADPlan.CheckMixedPlansExist(), MixedPlansExpectedErr); // Rollback SaaS test TearDown(); @@ -670,7 +668,8 @@ codeunit 139509 "Azure AD Plan Module Test" // [WHEN] CheckMixedPlans invoked LibraryLowerPermissions.SetO365Basic(); ; - AzureADPlan.CheckMixedPlans(); + + Assert.IsFalse(AzureADPlan.CheckMixedPlansExist(), MixedPlansExpectedErr); // Rollback SaaS test TearDown(); @@ -707,151 +706,10 @@ codeunit 139509 "Azure AD Plan Module Test" // [WHEN] CheckMixedPlans invoked LibraryLowerPermissions.SetO365Basic(); ; - asserterror AzureADPlan.CheckMixedPlans(); - - // Rollback SaaS test - TearDown(); - - // [THEN] Error is thrown - Assert.ExpectedError(StrSubstNo(MixedPlansNonAdminErr, BasicUser."Authentication Email", PremiumUser."Authentication Email")); - end; - - [Test] - [TransactionModel(TransactionModel::AutoRollback)] - [Scope('OnPrem')] - procedure TestCheckMixedPlans_EssentialAndIncomingPremium() - var - PremiumUser: Record User; - EssentialUser: Record User; - AzureADPlan: Codeunit "Azure AD Plan"; - PlanIds: Codeunit "Plan Ids"; - AzureADGraphUser: Codeunit "Azure AD Graph User"; - IncomingPlansPerUser: Dictionary of [Text, List of [Text]]; - PlansForUser: List of [Text]; - begin - // [SCENARIO] CheckMixedPlans - if not LibraryLowerPermissions.CanLowerPermission() then - exit; - Initialize(); - LibraryLowerPermissions.SetOutsideO365Scope(); - LibraryLowerPermissions.AddSecurity(); - - // [GIVEN] SUPER User - CODEUNIT.Run(CODEUNIT::"Users - Create Super User"); - - // [GIVEN] A user with essential plan is added - LibraryPermissions.CreateAzureActiveDirectoryUser(EssentialUser, ''); - LibraryPermissions.AddUserToPlan(EssentialUser."User Security ID", PlanIds.GetEssentialPlanId()); - - // [GIVEN] Another user got a premium license assigned in the Office portal - LibraryPermissions.CreateAzureActiveDirectoryUser(PremiumUser, ''); - PlansForUser.Add('Dynamics 365 Business Central Premium'); - IncomingPlansPerUser.Add(AzureADGraphUser.GetUserAuthenticationObjectId(PremiumUser."User Security ID"), PlansForUser); - - // [WHEN] CheckMixedPlans invoked - LibraryLowerPermissions.SetO365Basic(); - ; - asserterror AzureADPlan.CheckMixedPlans(IncomingPlansPerUser, true); - - // Rollback SaaS test - TearDown(); - - // [THEN] Error is thrown - Assert.ExpectedError(StrSubstNo(MixedPlansNonAdminErr, EssentialUser."Authentication Email", PremiumUser."Authentication Email")); - end; - - [Test] - [TransactionModel(TransactionModel::AutoRollback)] - [Scope('OnPrem')] - procedure TestCheckMixedPlans_EssentialAndEssentialUpgradedToPremium() - var - EssentialUser1: Record User; - EssentialUser2: Record User; - AzureADPlan: Codeunit "Azure AD Plan"; - PlanIds: Codeunit "Plan Ids"; - AzureADGraphUser: Codeunit "Azure AD Graph User"; - IncomingPlansPerUser: Dictionary of [Text, List of [Text]]; - PlansForUser: List of [Text]; - begin - // [SCENARIO] CheckMixedPlans - if not LibraryLowerPermissions.CanLowerPermission() then - exit; - Initialize(); - LibraryLowerPermissions.SetOutsideO365Scope(); - LibraryLowerPermissions.AddSecurity(); - - // [GIVEN] SUPER User - CODEUNIT.Run(CODEUNIT::"Users - Create Super User"); - - // [GIVEN] Two users with essential plan are added - LibraryPermissions.CreateAzureActiveDirectoryUser(EssentialUser1, ''); - LibraryPermissions.CreateAzureActiveDirectoryUser(EssentialUser2, ''); - LibraryPermissions.AddUserToPlan(EssentialUser1."User Security ID", PlanIds.GetEssentialPlanId()); - LibraryPermissions.AddUserToPlan(EssentialUser2."User Security ID", PlanIds.GetEssentialPlanId()); - - // [GIVEN] One of the users got their license changed to premium in the office portal - PlansForUser.Add('Dynamics 365 Business Central Premium'); - IncomingPlansPerUser.Add(AzureADGraphUser.GetUserAuthenticationObjectId(EssentialUser2."User Security ID"), PlansForUser); - - // [WHEN] CheckMixedPlans invoked - LibraryLowerPermissions.SetO365Basic(); - ; - asserterror AzureADPlan.CheckMixedPlans(IncomingPlansPerUser, true); - - // Rollback SaaS test - TearDown(); - - // [THEN] Error is thrown - Assert.ExpectedError(StrSubstNo(MixedPlansNonAdminErr, EssentialUser1."Authentication Email", EssentialUser2."Authentication Email")); - end; - - [Test] - [TransactionModel(TransactionModel::AutoRollback)] - [Scope('OnPrem')] - procedure TestCheckMixedPlans_NewEssentialAndPremiumUsers() - var - EssentialUser: Record User; - PlanIds: Codeunit "Plan Ids"; - AzureADPlan: Codeunit "Azure AD Plan"; - AzureADGraphUser: Codeunit "Azure AD Graph User"; - IncomingPlansPerUser: Dictionary of [Text, List of [Text]]; - PlansForPremiumUser: List of [Text]; - PlansForEssentialUser: List of [Text]; - EssentialUserAADObjectID: Guid; - PremiumUserAADObjectID: Guid; - begin - // [SCENARIO] CheckMixedPlans - if not LibraryLowerPermissions.CanLowerPermission() then - exit; - Initialize(); - LibraryLowerPermissions.SetOutsideO365Scope(); - LibraryLowerPermissions.AddSecurity(); - - // [GIVEN] SUPER User - CODEUNIT.Run(CODEUNIT::"Users - Create Super User"); - - LibraryPermissions.CreateAzureActiveDirectoryUser(EssentialUser, ''); - LibraryPermissions.AddUserToPlan(EssentialUser."User Security ID", PlanIds.GetEssentialPlanId()); - - // [GIVEN] One of the users got their license changed to premium in the office portal - EssentialUserAADObjectID := AzureADGraphUser.GetUserAuthenticationObjectId(EssentialUser."User Security ID"); - PremiumUserAADObjectID := CreateGuid(); - PlansForPremiumUser.Add('Dynamics 365 Business Central Premium'); - PlansForEssentialUser.Add('Dynamics 365 Business Central Essential'); - IncomingPlansPerUser.Add(EssentialUserAADObjectID, PlansForPremiumUser); - IncomingPlansPerUser.Add(PremiumUserAADObjectID, PlansForEssentialUser); - - LibraryLowerPermissions.SetO365Basic(); - MockGraphQueryTestLibrary.AddGraphUserWithoutPlan(PremiumUserAADObjectID, 'Incoming', 'User', 'user@test.com'); - - // [WHEN] CheckMixedPlans invoked - asserterror AzureADPlan.CheckMixedPlans(IncomingPlansPerUser, true); + Assert.IsTrue(AzureADPlan.CheckMixedPlansExist(), MixedPlansNotExpectedErr); // Rollback SaaS test TearDown(); - - // [THEN] Error is thrown - Assert.ExpectedError(StrSubstNo(MixedPlansNonAdminErr, 'user@test.com', EssentialUser."Authentication Email")); end; [Test] @@ -881,7 +739,8 @@ codeunit 139509 "Azure AD Plan Module Test" // [WHEN] CheckMixedPlans invoked LibraryLowerPermissions.SetO365BusFull(); LibraryLowerPermissions.AddSecurity(); - AzureADPlan.CheckMixedPlans(); + + Assert.IsFalse(AzureADPlan.CheckMixedPlansExist(), MixedPlansExpectedErr); // Rollback SaaS test TearDown(); @@ -916,7 +775,8 @@ codeunit 139509 "Azure AD Plan Module Test" // [WHEN] CheckMixedPlans invoked LibraryLowerPermissions.SetO365BusFull(); LibraryLowerPermissions.AddSecurity(); - AzureADPlan.CheckMixedPlans(); + + Assert.IsFalse(AzureADPlan.CheckMixedPlansExist(), MixedPlansExpectedErr); // Rollback SaaS test TearDown(); @@ -956,7 +816,8 @@ codeunit 139509 "Azure AD Plan Module Test" // [WHEN] CheckMixedPlans invoked LibraryLowerPermissions.SetO365BusFull(); LibraryLowerPermissions.AddSecurity(); - AzureADPlan.CheckMixedPlans(); + + Assert.IsFalse(AzureADPlan.CheckMixedPlansExist(), MixedPlansExpectedErr); // Rollback SaaS test TearDown(); @@ -996,7 +857,8 @@ codeunit 139509 "Azure AD Plan Module Test" // [WHEN] CheckMixedPlans invoked LibraryLowerPermissions.SetO365BusFull(); LibraryLowerPermissions.AddSecurity(); - AzureADPlan.CheckMixedPlans(); + + Assert.IsFalse(AzureADPlan.CheckMixedPlansExist(), MixedPlansExpectedErr); // Rollback SaaS test TearDown(); @@ -1542,12 +1404,5 @@ codeunit 139509 "Azure AD Plan Module Test" IsUserInUserGroup(User."User Security ID", UserGroupCode), 'Test prerequisite failed.'); end; #endif - - [MessageHandler] - [Scope('OnPrem')] - procedure HandleAndVerifyChangedPlanMessageOK(Message: Text[1024]) - begin - Assert.ExpectedMessage(Message, StrSubstNo(MixedPlansMsg, FirstUserAuthenticationEmail, SecondUserAuthenticationEmail)); - end; } diff --git a/Apps/W1/QBMigration/app/app.json b/Apps/W1/QBMigration/app/app.json index 93183f204f..ae9bf5957f 100644 --- a/Apps/W1/QBMigration/app/app.json +++ b/Apps/W1/QBMigration/app/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "Enables users to migrate their Customers, Vendors, Items and Accounts and open transactions from QuickBooks to Microsoft Dynamics 365 Business Central.", "description": "This application automates the process of migrating Customers, Vendors, Items and Accounts from QuickBooks to Microsoft Dynamics 365 Business Central. The user will need to either download the exporter tool to export their data out of QuickBooks Desktop or log into the QuickBooks Online System. GL Accounts and a beginning balance transaction will migrate along with Customers and Vendors and their current open transactions. Inventory items and current quantity on hand and service items will migrate from QuickBooks.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=850307", @@ -16,13 +16,13 @@ "id": "63ca2fa4-4f03-4f2b-a480-172fef340d3f", "name": "System Application", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 1, @@ -35,5 +35,5 @@ "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/W1/QBMigration/app/src/Support/MSQBODataMigration.Page.al b/Apps/W1/QBMigration/app/src/Support/MSQBODataMigration.Page.al index 4404b6ac22..9e9fd35c86 100644 --- a/Apps/W1/QBMigration/app/src/Support/MSQBODataMigration.Page.al +++ b/Apps/W1/QBMigration/app/src/Support/MSQBODataMigration.Page.al @@ -28,7 +28,7 @@ page 1830 "MS - QBO Data Migration" MultiLine = true; ShowCaption = false; } - usercontrol(OAuthIntegration; OAuthIntegration) + usercontrol(OAuthIntegration; OAuthControlAddIn) { ApplicationArea = Basic, Suite; diff --git a/Apps/W1/QBMigration/test/app.json b/Apps/W1/QBMigration/test/app.json index c22e4c998a..d4ab54bff4 100644 --- a/Apps/W1/QBMigration/test/app.json +++ b/Apps/W1/QBMigration/test/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "Tests for the QuickBooks Data Migration extension.", "description": "Tests for the QuickBooks Data Migration extension.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=850307", @@ -16,19 +16,19 @@ "id": "1b80b577-772f-4e0f-bc13-50214fb3da6e", "name": "Migration of QuickBooks Data", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 139500, @@ -45,5 +45,5 @@ "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/W1/QuickbooksPayrollFileImport/app/app.json b/Apps/W1/QuickbooksPayrollFileImport/app/app.json index 16e9c4d1a4..fc6d2f0a0c 100644 --- a/Apps/W1/QuickbooksPayrollFileImport/app/app.json +++ b/Apps/W1/QuickbooksPayrollFileImport/app/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "The Import of QuickBooks Payroll Files functionality allows you to import payroll transactions from a Quickbooks IIF file.", "description": "The Import of QuickBooks Payroll Files functionality allows you to import payroll transactions from a Quickbooks IIF file.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?LinkId=860351", @@ -17,7 +17,7 @@ "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 1, @@ -30,5 +30,5 @@ "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/W1/QuickbooksPayrollFileImport/test/app.json b/Apps/W1/QuickbooksPayrollFileImport/test/app.json index 3d67c909ac..009ca3c039 100644 --- a/Apps/W1/QuickbooksPayrollFileImport/test/app.json +++ b/Apps/W1/QuickbooksPayrollFileImport/test/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "Tests for the Quickbooks Payroll File Import extension.", "description": "Tests for the Quickbooks Payroll File Import extension.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?LinkId=860351", @@ -16,19 +16,19 @@ "id": "bc45ae22-3b5b-44b5-beb4-2a42bf79cc34", "name": "Import of QuickBooks Payroll Files", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 139500, @@ -45,5 +45,5 @@ "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/W1/RecommendedApps/app/app.json b/Apps/W1/RecommendedApps/app/app.json index 85d35808f3..755526f460 100644 --- a/Apps/W1/RecommendedApps/app/app.json +++ b/Apps/W1/RecommendedApps/app/app.json @@ -2,7 +2,7 @@ "id": "a53a4bb0-aa53-8ff8-77d6-fe3388db0eb8", "name": "Recommended Apps", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Create a collection of apps that you can recommend to customers.", "description": "Create a collection of apps that you can recommend to customers.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -10,8 +10,8 @@ "help": "https://go.microsoft.com/fwlink/?linkid=2173058", "url": "https://go.microsoft.com/fwlink/?LinkId=724011", "logo": "ExtensionLogo.png", - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 4750, diff --git a/Apps/W1/RecommendedApps/test/app.json b/Apps/W1/RecommendedApps/test/app.json index 0eeb89547f..87d020dafe 100644 --- a/Apps/W1/RecommendedApps/test/app.json +++ b/Apps/W1/RecommendedApps/test/app.json @@ -2,7 +2,7 @@ "id": "4b1cbbc7-a6fd-442c-87b1-60b1d2b059d7", "name": "Recommended Apps Tests", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Tests for the Microsoft Recommended Apps extension.", "description": "Tests for the Microsoft Recommended Apps extension.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -10,32 +10,32 @@ "help": "https://go.microsoft.com/fwlink/?linkid=2135559", "url": "https://go.microsoft.com/fwlink/?LinkId=724011", "logo": "ExtensionLogo.png", - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "dependencies": [ { "id": "a53a4bb0-aa53-8ff8-77d6-fe3388db0eb8", "name": "Recommended Apps", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "9856ae4f-d1a7-46ef-89bb-6ef056398228", "name": "System Application Test Library", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5095f467-0a01-4b99-99d1-9ff1237d286f", "publisher": "Microsoft", "name": "Library Variable Storage", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "idRanges": [ diff --git a/Apps/W1/ReportLayouts/app/app.json b/Apps/W1/ReportLayouts/app/app.json index 15511b281d..275f59a209 100644 --- a/Apps/W1/ReportLayouts/app/app.json +++ b/Apps/W1/ReportLayouts/app/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "Report layouts made available by extensions or created by users.", "description": "The report layouts page shows all the report layouts made available from extensions or those defined by users.", - "version": "24.0.0.0", + "version": "25.0.0.0", "help": "https://go.microsoft.com", "privacyStatement": "https://go.microsoft.com", "EULA": "https://go.microsoft.com", @@ -21,14 +21,14 @@ "publisher": "Microsoft" } ], - "application": "24.0.0.0", + "application": "25.0.0.0", "target": "OnPrem", "resourceExposurePolicy": { "allowDebugging": false, "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 1, diff --git a/Apps/W1/ReportLayouts/test/app.json b/Apps/W1/ReportLayouts/test/app.json index 864d825c88..6e0b0d3f9e 100644 --- a/Apps/W1/ReportLayouts/test/app.json +++ b/Apps/W1/ReportLayouts/test/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "Tests for the Report Layouts extension.", "description": "Tests for the Report Layouts extension.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "help": "https://go.microsoft.com", "EULA": "https://go.microsoft.com", @@ -15,25 +15,25 @@ "id": "b7174aae-753c-4e71-bacb-d973995dce5e", "name": "_Exclude_ReportLayouts", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "9856ae4f-d1a7-46ef-89bb-6ef056398228", "name": "System Application Test Library", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 139500, @@ -50,6 +50,6 @@ "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0", + "application": "25.0.0.0", "logo": "ExtensionLogo.png" } \ No newline at end of file diff --git a/Apps/W1/ReviewGLEntries/app/app.json b/Apps/W1/ReviewGLEntries/app/app.json index e24aa2b218..7fb7a33523 100644 --- a/Apps/W1/ReviewGLEntries/app/app.json +++ b/Apps/W1/ReviewGLEntries/app/app.json @@ -2,7 +2,7 @@ "id": "87990153-0e35-4e5d-ba61-2e93077d1699", "name": "Review General Ledger Entries", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Review General Ledger Entries", "description": "Exclude Review General Ledger Entries", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -17,8 +17,8 @@ "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "resourceExposurePolicy": { "allowDebugging": true, "allowDownloadingSource": true, diff --git a/Apps/W1/ReviewGLEntries/test/app.json b/Apps/W1/ReviewGLEntries/test/app.json index 0926f11236..7dc8ca596d 100644 --- a/Apps/W1/ReviewGLEntries/test/app.json +++ b/Apps/W1/ReviewGLEntries/test/app.json @@ -2,7 +2,7 @@ "id": "6cba115c-63f1-4b08-9e0d-8872a86458db", "name": "_Exclude_Review_General_Ledger_Entries_Tests", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Tests for the _Exclude_Review_General_Ledger_Entries extension", "description": "Tests for the _Exclude_Review_General_Ledger_Entries extension", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -16,26 +16,26 @@ "id": "87990153-0e35-4e5d-ba61-2e93077d1699", "name": "Review General Ledger Entries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5095f467-0a01-4b99-99d1-9ff1237d286f", "publisher": "Microsoft", "name": "Library Variable Storage", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "resourceExposurePolicy": { "allowDebugging": true, "allowDownloadingSource": true, diff --git a/Apps/W1/SAF-T/app/app.json b/Apps/W1/SAF-T/app/app.json index a0e8b49967..b60b54028e 100644 --- a/Apps/W1/SAF-T/app/app.json +++ b/Apps/W1/SAF-T/app/app.json @@ -2,7 +2,7 @@ "id": "4ce93371-6bd6-4027-a78f-021064ad250e", "name": "SAF-T", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "SAF-T provides a user interface for exporting accounting, tax, and other data required by auditors or authorities.", "description": "As a part of the audit reporting, companies must be able to export transaction data according to the SAF-T format based on OECD standard. This feature enables using SAF-T format for exporting data within Audit File Export app, where you can specify Standard Chart of Accounts and map other required data to fulfill all requirements.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -16,31 +16,31 @@ "id": "a41b0c3e-bf1c-4c97-ad1b-b430a3933ada", "name": "Audit File Export", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], - "internalsVisibleTo": [ - { - "id": "dfe6916f-cba8-4973-afdc-1544705c661f", - "name": "SAF-T Tests", - "publisher": "Microsoft" - } - ], + "internalsVisibleTo": [ + { + "id": "dfe6916f-cba8-4973-afdc-1544705c661f", + "name": "SAF-T Tests", + "publisher": "Microsoft" + } + ], "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { - "from": 5280, - "to": 5299 + "from": 5280, + "to": 5299 } ], "resourceExposurePolicy": { - "allowDebugging": true, - "allowDownloadingSource": true, - "includeSourceInSymbolFile": true + "allowDebugging": true, + "allowDownloadingSource": true, + "includeSourceInSymbolFile": true }, "target": "Cloud" } \ No newline at end of file diff --git a/Apps/W1/SAF-T/test/app.json b/Apps/W1/SAF-T/test/app.json index 96ed4b37dd..845f6c4bd3 100644 --- a/Apps/W1/SAF-T/test/app.json +++ b/Apps/W1/SAF-T/test/app.json @@ -2,7 +2,7 @@ "id": "dfe6916f-cba8-4973-afdc-1544705c661f", "name": "SAF-T Tests", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Tests for the SAF-T extension.", "description": "Tests for the SAF-T extension.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -16,38 +16,38 @@ "id": "a41b0c3e-bf1c-4c97-ad1b-b430a3933ada", "name": "Audit File Export", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "4ce93371-6bd6-4027-a78f-021064ad250e", "name": "SAF-T", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "9856ae4f-d1a7-46ef-89bb-6ef056398228", "name": "System Application Test Library", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5095f467-0a01-4b99-99d1-9ff1237d286f", "publisher": "Microsoft", "name": "Library Variable Storage", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 139511, diff --git a/Apps/W1/SalesAndInventoryForecast/app/app.json b/Apps/W1/SalesAndInventoryForecast/app/app.json index 35393eb5e3..1186f0075d 100644 --- a/Apps/W1/SalesAndInventoryForecast/app/app.json +++ b/Apps/W1/SalesAndInventoryForecast/app/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "Get insights about potential sales and a clear overview of expected stock-outs.", "description": "Inventory management is a trade-off between customer service and managing cost. On one hand, low inventory levels require less working capital. On the other hand, stock-outs can lead to missed sales. The Sales and Inventory Forecast extension uses historical data to predict potential sales so you know when to expect stock-outs. Based on the forecast, the extension saves you time by helping to create replenishment requests to your vendors.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=2189535", @@ -17,7 +17,7 @@ "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 1, @@ -30,5 +30,5 @@ "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/W1/SalesAndInventoryForecast/test/app.json b/Apps/W1/SalesAndInventoryForecast/test/app.json index 65f0799633..87b2c7a407 100644 --- a/Apps/W1/SalesAndInventoryForecast/test/app.json +++ b/Apps/W1/SalesAndInventoryForecast/test/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "Tests for the Sales and Inventory Forecast extension.", "description": "Tests for the Sales and Inventory Forecast extension.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=2189535", @@ -16,25 +16,25 @@ "id": "c526b3e9-b8ca-4683-81ba-fcd5f6b1472a", "name": "Sales and Inventory Forecast", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5095f467-0a01-4b99-99d1-9ff1237d286f", "publisher": "Microsoft", "name": "Library Variable Storage", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 139500, @@ -51,5 +51,5 @@ "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/W1/SalesLinesSuggestions/app/BaseAppExtensions/SalesInvoiceSubFormExt.PageExt.al b/Apps/W1/SalesLinesSuggestions/app/BaseAppExtensions/SalesInvoiceSubFormExt.PageExt.al new file mode 100644 index 0000000000..e9d84b359c --- /dev/null +++ b/Apps/W1/SalesLinesSuggestions/app/BaseAppExtensions/SalesInvoiceSubFormExt.PageExt.al @@ -0,0 +1,53 @@ +// ------------------------------------------------------------------------------------------------ +// 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; + +pageextension 7277 "Sales Invoice Sub Form Ext" extends "Sales Invoice Subform" +{ + actions + { + addfirst(Prompting) + { + action("Suggest Sales Lines Prompting") + { + ApplicationArea = All; + Caption = 'Suggest sales lines'; + Image = SparkleFilled; + ToolTip = 'Get sales lines suggestions from Copilot'; + Visible = SLSActionVisibility; + + trigger OnAction() + begin + SalesLineAISuggestionImp.GetLinesSuggestions(Rec); + end; + } + } + addlast(processing) + { + action("Suggest Sales Lines") + { + ApplicationArea = All; + Caption = 'Suggest sales lines'; + Image = SparkleFilled; + ToolTip = 'Get sales lines suggestions from Copilot'; + Visible = SLSActionVisibility; + + trigger OnAction() + begin + SalesLineAISuggestionImp.GetLinesSuggestions(Rec); + end; + } + } + } + + trigger OnOpenPage() + begin + SLSActionVisibility := SalesLineAISuggestionImp.CheckSupportedApplicationFamily(); + end; + + var + SalesLineAISuggestionImp: Codeunit "Sales Lines Suggestions Impl."; + SLSActionVisibility: Boolean; +} \ No newline at end of file diff --git a/Apps/W1/SalesLinesSuggestions/app/BaseAppExtensions/SalesOrderSubFormExt.PageExt.al b/Apps/W1/SalesLinesSuggestions/app/BaseAppExtensions/SalesOrderSubFormExt.PageExt.al new file mode 100644 index 0000000000..7fdce30316 --- /dev/null +++ b/Apps/W1/SalesLinesSuggestions/app/BaseAppExtensions/SalesOrderSubFormExt.PageExt.al @@ -0,0 +1,54 @@ +// ------------------------------------------------------------------------------------------------ +// 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; + +pageextension 7278 "Sales Order Sub Form Ext" extends "Sales Order Subform" +{ + actions + { + addfirst(Prompting) + { + action("Suggest Sales Lines Prompting") + { + ApplicationArea = All; + Caption = 'Suggest sales lines'; + Image = SparkleFilled; + ToolTip = 'Get sales lines suggestions from Copilot'; + Visible = SLSActionVisibility; + + trigger OnAction() + begin + SalesLineAISuggestionImp.GetLinesSuggestions(Rec); + end; + } + } + addlast(processing) + { + action("Suggest Sales Lines") + { + ApplicationArea = All; + Caption = 'Suggest sales lines'; + Image = SparkleFilled; + ToolTip = 'Get sales lines suggestions from Copilot'; + Visible = SLSActionVisibility; + + trigger OnAction() + begin + SalesLineAISuggestionImp.GetLinesSuggestions(Rec); + end; + } + } + } + + trigger OnOpenPage() + begin + SLSActionVisibility := SalesLineAISuggestionImp.CheckSupportedApplicationFamily(); + end; + + var + SalesLineAISuggestionImp: Codeunit "Sales Lines Suggestions Impl."; + + SLSActionVisibility: Boolean; +} \ No newline at end of file diff --git a/Apps/W1/SalesLinesSuggestions/app/BaseAppExtensions/SalesQuoteSubFormExt.PageExt.al b/Apps/W1/SalesLinesSuggestions/app/BaseAppExtensions/SalesQuoteSubFormExt.PageExt.al new file mode 100644 index 0000000000..746b0af352 --- /dev/null +++ b/Apps/W1/SalesLinesSuggestions/app/BaseAppExtensions/SalesQuoteSubFormExt.PageExt.al @@ -0,0 +1,53 @@ +// ------------------------------------------------------------------------------------------------ +// 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; + +pageextension 7279 "Sales Quote Sub Form Ext" extends "Sales Quote Subform" +{ + actions + { + addfirst(Prompting) + { + action("Suggest Sales Lines Prompting") + { + ApplicationArea = All; + Caption = 'Suggest sales lines'; + Image = SparkleFilled; + ToolTip = 'Get sales lines suggestions from Copilot'; + Visible = SLSActionVisibility; + + trigger OnAction() + begin + SalesLineAISuggestionImp.GetLinesSuggestions(Rec); + end; + } + } + addlast(processing) + { + action("Suggest Sales Lines") + { + ApplicationArea = All; + Caption = 'Suggest sales lines'; + Image = SparkleFilled; + ToolTip = 'Get sales lines suggestions from Copilot'; + Visible = SLSActionVisibility; + + trigger OnAction() + begin + SalesLineAISuggestionImp.GetLinesSuggestions(Rec); + end; + } + } + } + trigger OnOpenPage() + begin + SLSActionVisibility := SalesLineAISuggestionImp.CheckSupportedApplicationFamily(); + end; + + var + SalesLineAISuggestionImp: Codeunit "Sales Lines Suggestions Impl."; + + SLSActionVisibility: Boolean; +} \ No newline at end of file diff --git a/Apps/W1/SalesLinesSuggestions/app/ExtensionLogo.png b/Apps/W1/SalesLinesSuggestions/app/ExtensionLogo.png new file mode 100644 index 0000000000000000000000000000000000000000..4d2c9a626cb9617350617c40cd73904129d4c108 GIT binary patch literal 5446 zcma)=S5VVywD$iAMIcgC2u+$uktV%J6$Dhev_NQrfC^Fsq!|cJ=^|Z`P&U*^N-uuwi#_w5i!*aB*89x5SkKKnv*ua91anhEW+omc005Zp+`e`1 zOsW4C1O3^nWxbYuCX9Z!?E(M*a`E2+jm<_J0|5K}om)4pLZ&wJ&3t(K(|ffcq#?ky z#^aeQO#|lO9vyUeb0ezqQtpipl3Sj#-xy!eh7lu@5+BnW zNhL-~3Zpw&1u=bMN*Q(sgYksq4dM>Iw7p&Qk_Su~b*PgEs#LK~^K}aDaTG_6Q?_tM<8wOS}`Z+?~Et8GB>T%(k7$9`DL!d5)f!ZoXco-vj+s_QLEs2cf zKM&F>#c9w|TmM9MFtl8L*cYQgl9khf5CYMR)DJOUf;M~a9|+ys@RYR zCusNC(CSlUk|r`qdS&ZKh$O=@#&e0>;W~S#|KjHdfLx!-J9r1JtP4RGIhS|Rm0eZ6 z7eOE~Zfo4Li~K^|&)d^-r?8Rh2Q}#ZjL=?VJZ7~hlp4(!U!0K%679I`OR&x54*0&4 znho|hKu)WR)4PUVA1}N;jXHg}AG+gSKQ6O_fEP^Y51!LwBERH09|t!GNx2KH4co>r zA%cgSHxh2Sezx-w!S5DTG#0zVCbnLM6BP}2P-G{8 zh**wJHj<652FS05bSQNx-0fS7^(wREYvZwpt;$!!k4H0U*iyhS8(syBDMv>L<)~LI zPl!Y^-cM{_J@{hY1=XJ#T=Ef(FD!I^r1^lca3c0ftVuvo-(%!Zn)C1bK{}-i*Jc); zIIc+o&iMgvboj&4`@5sF23MV!*zIVmA0>{1;*H*faMAG6EZ7XydTfaGyABAGx>)yl z@Y+|)SVxCx@!GWqspay7GBetK*s2@CJ?s{8v!(b|ShLb|O;3T1rAMB?DJ?Z`@013q zoyIvV84eYiS+?kRJOz`3AFcR~ZQ1Uq7wCnbSJ%-HZwhAnJ^4zDp2W8I)~WI7ush5> z&f3O)rj~2ZGr!c@=p3!n>jG-O#9`$7&WyF7bB}(rq4ldokUp5TY?E62r+YJbJp8Jf znDW3fYZ^nBQ9O}3?zH_*mZ9+G#HHnwop1Vfm!Df~{Z%D?5KzMN&RA>&#q8iCzTfAt zV#TyMeyyh8=M$8tyA|KeUwo_Q6Si)P)%n(W-*QE~08BG|>J!sQPq?IF;;%1ypP?Z` zK_0Un>p;9=9d675ELHboC0+fNMY&(;k(|=0TS>ka)BKI3q#)zx!Jp@zv0QfeEAjU< z=vI5@-d^A^-*#|P+b2QFiGxk4z<8Tp4p6{aOp88x>SQEa0M`VxX%IUb$bya!5EgRf6$fFw zp}jNTKUXjNe0x(;)Nu)Ij5K?QD0u6~mRHQ-!;6m#VP>)}=irAqy;f$e{W-EWnR75~ zm2b0u@r7ASk4x0oTqs9{f&F|eAmD*Gf^A;te7f}J{dXqLaH_4%D_(mnp0VmWhq>^E z&7>5*-mh>FX{w5SJf^#th&GrpOQk58U-+4 zq3$q~C4ySH7@lr>W+|c0`UF*ieC+3vC1$4m}F(ic|G7}QDt(t z7`#>$c4U-4LU_;nWHhdN9Fcv~L8h6M_}nW&EGTjgW(=c}uD9>eU^rDOrkNg_effOV z^8z_y=vNIt{`wOfgG2o^3ey`R!aP1=t7Mz@&MKK3>_BH_QkgNO@4IoQ-2d8EqsDg) zTMb-5lqlubRot-7!RD@+udO?O9_Da3XV5bvjW zXTb2psHUdeiIaI(lknQE_<+YlY31}R!VfoM_BuILQ{>Q89=LB5j;V|-yAW2gY82+~ zYlu~#*R(cHw2NO1h5xaiAD2oiIEQ-aQyA-D^y^z2ZHNfM{o(3M#SbqOP3>k9FOdDO z(t%c9hk)NCPe_8>=Y^U-_-6IwS-D0cE=pwdyLp!;r-fWiXtbUS$<dl!~WV$TR8 zP$KU?K>m?*O)mSGccn&kn|nj7NXFeo<0D=ue8s^~BK#P?J~gB}v5<0nK9GPipjT#9 zkm6yXFyLlgoUIDEVxw*0Z-WDqp8swCs(bcjAqdDLl1oUqYf#a`NjT6IO3?=P`FvUZ zlWC&lWb9_dexSz%N~-oscM`oC%b#KS|KS7AptwRX5h&1VDCKWzP{&??TFdF3h53&c zU(v)WhOr)#!V6Y6d7CzOO-@KF%@67>kh34@Exj7Rh}p5_0?yUeyC7@c7DHf+mW=~wpLeLYDA9#W-Ri*S|M@g zjPHH@qHrPuzq(+5y$V*UoFEg(g$$mRNUEF!C{IN3Rig{tU54W|OD_`M0G3u)B{WhC z*D?hTF7J+YdF8-Z-Uuw{3jBx`_!aus`uDDBecwuu&tsVpj2~DZJb2-!a2l??m{}er}lR6Lqu)-2+Vm)jr(g{nfQPx9-<^1d;k-d zkU{E^g7qwp+D`b+QtU5@+swaVKp9<`>sT~U)O!EEMBo!*)~s_<`6Yl z7fX2;ki>kVDfdietW1k;TYvaY({>?5X)&(d&_y<-J7Qa@b z(zwGCI=`P#^b>1>2#Y!9T5|AdtaU|zXxw9^KpIu6CAmQf$GzaeOJmYVsc3eh5%6lb z)t~(Ak2J`;KW_L6psME-h?xF6ryr4d{q;>-b`Q$L43T{r`{N?U6cqP(Q3f%kA8`c@ z<82KXjte|7u_Lo~MV!d%y$tYi(hzU$6t+*ml~Z&Mg{eK?@}^XEBK+-&j`Uv95x)=_ zZLs=Mpg_IuZenjm(~}b8Aggaaje8NX$A_7^G%-)!xtu)C{N|S<3hVOmU;{|i+q6zn zfr(1Ua*jF!%-dU3L}O2fvWAe%-4kxtXo_vJHF(AxSx)4AI8-$^uBQO_86Z_y%RZX4 zJpu5`pOAztxv?jXv9yx|r>#9!0|`71C-fli@v${6r+V$hgvcr|W_I`{=7*0s(PKQH zzn8r2+tSeD15stz|DIJ3%X%8EkyN?bsHhuq4(5D0Oewn_)-o)Nx$eNs{0V*ZTSVt4 z3ifXGGw5fBv+9b6d~Nl+08L4VbbZqf3DL^e?l@!uZVdWkdOpJPaE?{zF!ZI?c(vF3 zvX~OK4vktvm&R$MgNpiKA~&zT!1#H7!q1h7AQiuSNG9<=$64)Zym(UQ``(j#^hDzt}{aur0pS?mmBi&z4I0Jfieqh%Pa_A%N?_1OZHm-S{ zQ*)4(N_J;y7tRh0o>xs25-s9!M-)i;@I68#SGXB2XgS}N zx_r3%V)z1jLA_M&?)E^DT$kzdHMJF%e2w6BH@iI5tKWM+zcuhCsz@N0a_1RBvrdZx zjzD>V%;c4*$RkEv{zHuVyaB+ANl(iT8w{pJdziC7YcO2&(ciqGLhs@q-dNh! zkV_V_(_~$*>ND}j1yozMedYnu-_GKMh?IpP<@D+edeB4M%3@xr3oj{@mdFKoBVpm^)1_}Y^}rOWBSB|Uv)*-pTdiU ztW9~{qq5@iB+$QpbeJVKH^n^9vV})i>Z@2CHoY2$PC888c;#Yz-pHRK@EVheWhE!> zZzjPmy?0Ni8#=o_k6_s3DY7nS^&Bm}BW&ZfAuF7bQbDgAGM$dE)RM6RvdobKb&MhsYD4exRm9*jcHPjbz#rI?vj$u zPLF5Gjv|8}?ta9`&^H}Va3H;llghU-BC7pxo6?-eTP`7CUZHJrw{5 zhkDYeIYlhL%brQJ1X#<#fz#E}Z87Kj=Hde*f{l|A`9E my8jz0{9hgZgN;Rh%;ug!HJ{lE_@04L;EulOt!iDD=>G@$cU!Ii literal 0 HcmV?d00001 diff --git a/Apps/W1/SalesLinesSuggestions/app/SLSPrompts.Codeunit.al b/Apps/W1/SalesLinesSuggestions/app/SLSPrompts.Codeunit.al new file mode 100644 index 0000000000..1545b7f409 --- /dev/null +++ b/Apps/W1/SalesLinesSuggestions/app/SLSPrompts.Codeunit.al @@ -0,0 +1,73 @@ +// ------------------------------------------------------------------------------------------------ +// 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.Azure.KeyVault; +using System.Telemetry; + +codeunit 7276 "SLS Prompts" +{ + Access = Internal; + + [NonDebuggable] + internal procedure GetAzureKeyVaultSecret(var SecretValue: Text; SecretName: Text) + var + AzureKeyVault: Codeunit "Azure Key Vault"; + FeatureTelemetry: Codeunit "Feature Telemetry"; + SalesLineAISuggestionImpl: Codeunit "Sales Lines Suggestions Impl."; + begin + if not AzureKeyVault.GetAzureKeyVaultSecret(SecretName, SecretValue) then begin + FeatureTelemetry.LogError('0000MJE', SalesLineAISuggestionImpl.GetFeatureName(), 'Get prompt from Key Vault', TelemetryConstructingPromptFailedErr); + Error(ConstructingPromptFailedErr); + end; + end; + + [NonDebuggable] + internal procedure GetSLSSystemPrompt(): SecretText + var + BCSLSMetaPrompt: Text; + BCSLSTaskPrompt: Text; + begin + GetAzureKeyVaultSecret(BCSLSMetaPrompt, 'BCSLSMetaPrompt'); + GetAzureKeyVaultSecret(BCSLSTaskPrompt, 'BCSLSTaskPrompt'); + + exit(BCSLSMetaPrompt + StrSubstNo(BCSLSTaskPrompt, Format(Today, 0, 4))); + end; + + [NonDebuggable] + internal procedure GetSLSDocumentLookupPrompt(): Text + var + BCSLSDocumentLookupPrompt: Text; + begin + GetAzureKeyVaultSecret(BCSLSDocumentLookupPrompt, 'BCSLSDocumentLookupPrompt'); + + exit(BCSLSDocumentLookupPrompt); + end; + + [NonDebuggable] + internal procedure GetSLSSearchItemPrompt(): Text + var + BCSLSSearchItemPrompt: Text; + begin + GetAzureKeyVaultSecret(BCSLSSearchItemPrompt, 'BCSLSSearchItemPrompt'); + + exit(BCSLSSearchItemPrompt); + end; + + [NonDebuggable] + internal procedure GetSLSMagicFunctionPrompt(): Text + var + BCSLSMagicFunctionPrompt: Text; + begin + GetAzureKeyVaultSecret(BCSLSMagicFunctionPrompt, 'BCSLSMagicFunctionPrompt'); + + exit(BCSLSMagicFunctionPrompt); + end; + + 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/DocumentLookupSubType.Interface.al b/Apps/W1/SalesLinesSuggestions/app/SalesAzureOpenAITools/DocumentLookupImpl/DocumentLookupSubType.Interface.al new file mode 100644 index 0000000000..62796db5c8 --- /dev/null +++ b/Apps/W1/SalesLinesSuggestions/app/SalesAzureOpenAITools/DocumentLookupImpl/DocumentLookupSubType.Interface.al @@ -0,0 +1,17 @@ +// ------------------------------------------------------------------------------------------------ +// 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; + +interface DocumentLookupSubType +{ + Access = Internal; + + ///

+ /// This procedure is used to look up documents, copy the document lines and assign them the temporary Record Sales Line AI Suggestions. + /// -CustomDimension: This can be used to pass contextual information to the function. + /// -TempSalesLineAiSuggestion: This is a temporary record that will be used to return the sales line AI suggestions. + /// + procedure SearchSalesDocument(CustomDimension: Dictionary of [Text, Text]; var TempSalesLineAiSuggestion: Record "Sales Line AI Suggestions" temporary); +} \ 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 new file mode 100644 index 0000000000..ba0c678e43 --- /dev/null +++ b/Apps/W1/SalesLinesSuggestions/app/SalesAzureOpenAITools/DocumentLookupImpl/SalesInvoiceLookup.Codeunit.al @@ -0,0 +1,254 @@ +// ------------------------------------------------------------------------------------------------ +// 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.Sales.History; +using Microsoft.Inventory.Item; +using Microsoft.Foundation.UOM; + +codeunit 7286 SalesInvoiceLookup implements DocumentLookupSubType +{ + Access = Internal; + + var + NoDocumentFound1Err: Label 'Copilot could not find the requested Posted Sales Invoice for %1. Please rephrase the description and try again.', Comment = '%1 = Customer Name'; + NoDocumentFound2Err: Label 'Copilot could not find the requested Posted Sales Invoice %1. Please rephrase the description and try again.', Comment = '%1 = Document No.'; + NoLinesFoundInTheDocumentErr: Label 'Copilot found the Posted Sales Invoice %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"; + SalesInvoiceHeader: Record "Sales Invoice Header"; + DocumentLookup: Codeunit "Document Lookup Function"; + DocumentNo: Text; + StartDateStr: Text; + EndDateStr: Text; + FoundDocNo: Code[20]; + begin + DocumentLookup.GetParametersFromCustomDimension(CustomDimension, SourceSalesHeader, DocumentNo, StartDateStr, EndDateStr); + SalesInvoiceHeader.SetLoadFields("No."); + // setup SecurityFilter + SalesInvoiceHeader.SetSecurityFilterOnRespCenter(); + FoundDocNo := SearchPossibleNo(DocumentNo); + // Set up date range + SetFilterOnDateForPostedSalesInvoiceHeader(StartDateStr, EndDateStr, SalesInvoiceHeader); + if FoundDocNo <> '' then + SalesInvoiceHeader.SetRange("No.", FoundDocNo) + else + SalesInvoiceHeader.SetRange("Sell-to Customer No.", SourceSalesHeader."Sell-to Customer No."); + + SalesInvoiceHeader.SetCurrentKey("Document Date"); + if SalesInvoiceHeader.FindLast() then + FoundDocNo := SalesInvoiceHeader."No." + else + if FoundDocNo = '' then + Error(NoDocumentFound1Err, SourceSalesHeader."Sell-to Customer Name") + else + Error(NoDocumentFound2Err, FoundDocNo); + + GetPostedSalesInvoiceLinesIntoTempTable(FoundDocNo, TempSalesLineAiSuggestion); + end; + + local procedure SetFilterOnDateForPostedSalesInvoiceHeader(StartDateStr: Text; EndDateStr: Text; var SalesInvoiceHeader: Record "Sales Invoice 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); + SalesInvoiceHeader.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, DocNoLen, Result) then + exit(Result) + else + Error(NoDocumentFound2Err, DocumentNo); + end; + + local procedure SearchAmbiguousNo(DocumentNo: Text; DocNoLen: Integer; var Result: Code[20]): Boolean + 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.SetFilter("No.", 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; + end; + exit(false); + end; + + local procedure SearchPreciseNo(DocumentNo: Text; DocNoLen: Integer; var Result: Code[20]): Boolean + 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.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."); + 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."); + 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."); + 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."); + SalesInvoiceHeader.SetRange("Your Reference", DocumentNo); + + if (SalesInvoiceHeader.FindLast()) then begin + Result := SalesInvoiceHeader."No."; + exit(true); + end; + end; + exit(false); + end; + + local procedure GetPostedSalesInvoiceLinesIntoTempTable(DocumentNo: Code[20]; var TempSalesLineAiSuggestion: Record "Sales Line AI Suggestions" temporary) + var + SalesInvoiceLine: Record "Sales Invoice Line"; + Item: Record Item; + UoMMgt: Codeunit "Unit of Measure Management"; + LineNumber: Integer; + begin + if not TempSalesLineAiSuggestion.FindLast() then + LineNumber := 0 + 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); + if SalesInvoiceLine.FindSet() then begin + repeat + Item.SetRange("No.", SalesInvoiceLine."No."); + Item.SetRange(Blocked, false); + Item.SetRange("Sales Blocked", false); + if Item.FindFirst() then begin + TempSalesLineAiSuggestion.Init(); + LineNumber := LineNumber + 1; + TempSalesLineAiSuggestion."Line No." := LineNumber; + TempSalesLineAiSuggestion.Type := SalesInvoiceLine.Type; + 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.SetSourceDocument(SalesInvoiceLine.RecordId()); + TempSalesLineAiSuggestion.Insert(); + end; + until SalesInvoiceLine.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/SalesOrderLookup.Codeunit.al b/Apps/W1/SalesLinesSuggestions/app/SalesAzureOpenAITools/DocumentLookupImpl/SalesOrderLookup.Codeunit.al new file mode 100644 index 0000000000..5f5d24ca53 --- /dev/null +++ b/Apps/W1/SalesLinesSuggestions/app/SalesAzureOpenAITools/DocumentLookupImpl/SalesOrderLookup.Codeunit.al @@ -0,0 +1,239 @@ +// ------------------------------------------------------------------------------------------------ +// 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; +using Microsoft.Foundation.UOM; + +codeunit 7287 SalesOrderLookup implements DocumentLookupSubType +{ + Access = Internal; + + var + NoDocumentFound1Err: Label 'Copilot could not find the requested Sales Order for %1. Please rephrase the description and try again.', Comment = '%1 = Customer Name'; + NoDocumentFound2Err: Label 'Copilot could not find the requested Sales Order %1. Please rephrase the description and try again.', Comment = '%1 = Document No.'; + NoLinesFoundInTheDocumentErr: Label 'Copilot found the 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", SalesHeader."Document Type"::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" = SalesHeader."Document Type"::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, DocNoLen, Result) then + exit(Result) + else + Error(NoDocumentFound2Err, DocumentNo); + end; + + local procedure SearchAmbiguousNo(DocumentNo: Text; DocNoLen: Integer; var Result: Code[20]): Boolean + 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.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; + end; + exit(false); + end; + + local procedure SearchPreciseNo(DocumentNo: Text; DocNoLen: Integer; var Result: Code[20]): Boolean + 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.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); + 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); + 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); + SalesHeader.SetRange("Your Reference", DocumentNo); + if (SalesHeader.FindLast()) then begin + Result := SalesHeader."No."; + exit(true); + end; + 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; + UoMMgt: Codeunit "Unit of Measure Management"; + LineNumber: Integer; + begin + if not TempSalesLineAiSuggestion.FindLast() then + LineNumber := 1 + 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); + SalesLine.SetRange("Type", SalesLine.Type::Item); + if SalesLine.FindSet() then begin + repeat + Item.SetRange("No.", SalesLine."No."); + Item.SetRange(Blocked, false); + Item.SetRange("Sales Blocked", false); + if Item.FindFirst() 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"; + 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.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/SalesQuoteLookup.Codeunit.al b/Apps/W1/SalesLinesSuggestions/app/SalesAzureOpenAITools/DocumentLookupImpl/SalesQuoteLookup.Codeunit.al new file mode 100644 index 0000000000..0996ca9c74 --- /dev/null +++ b/Apps/W1/SalesLinesSuggestions/app/SalesAzureOpenAITools/DocumentLookupImpl/SalesQuoteLookup.Codeunit.al @@ -0,0 +1,239 @@ +// ------------------------------------------------------------------------------------------------ +// 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; +using Microsoft.Foundation.UOM; + +codeunit 7288 SalesQuoteLookup implements DocumentLookupSubType +{ + Access = Internal; + + var + NoDocumentFound1Err: Label 'Copilot could not find the requested Sales Quote for %1. Please rephrase the description and try again.', Comment = '%1 = Customer Name'; + NoDocumentFound2Err: Label 'Copilot could not find the requested Sales Quote %1. Please rephrase the description and try again.', Comment = '%1 = Document No.'; + NoLinesFoundInTheDocumentErr: Label 'Copilot found the Sales Quote %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", SalesHeader."Document Type"::Quote); + if FoundDocNo <> '' then + SalesHeader.SetRange("No.", FoundDocNo) + else begin + SalesHeader.SetRange("Sell-to Customer No.", SourceSalesHeader."Sell-to Customer No."); + if SourceSalesHeader."Document Type" = SalesHeader."Document Type"::Quote 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, DocNoLen, Result) then + exit(Result) + else + Error(NoDocumentFound2Err, DocumentNo); + end; + + local procedure SearchAmbiguousNo(DocumentNo: Text; DocNoLen: Integer; var Result: Code[20]): Boolean + 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.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; + end; + exit(false); + end; + + local procedure SearchPreciseNo(DocumentNo: Text; DocNoLen: Integer; var Result: Code[20]): Boolean + 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.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); + 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); + 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); + SalesHeader.SetRange("Your Reference", DocumentNo); + if (SalesHeader.FindLast()) then begin + Result := SalesHeader."No."; + exit(true); + end; + 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; + UoMMgt: Codeunit "Unit of Measure Management"; + LineNumber: Integer; + begin + if not TempSalesLineAiSuggestion.FindLast() then + LineNumber := 1 + 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); + SalesLine.SetRange("Type", SalesLine.Type::Item); + if SalesLine.FindSet() then begin + repeat + Item.SetRange("No.", SalesLine."No."); + Item.SetRange(Blocked, false); + Item.SetRange("Sales Blocked", false); + if Item.FindFirst() 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"; + 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.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/SalesShipmentLookup.Codeunit.al b/Apps/W1/SalesLinesSuggestions/app/SalesAzureOpenAITools/DocumentLookupImpl/SalesShipmentLookup.Codeunit.al new file mode 100644 index 0000000000..21f59c7db9 --- /dev/null +++ b/Apps/W1/SalesLinesSuggestions/app/SalesAzureOpenAITools/DocumentLookupImpl/SalesShipmentLookup.Codeunit.al @@ -0,0 +1,254 @@ +// ------------------------------------------------------------------------------------------------ +// 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; +using Microsoft.Foundation.UOM; +using Microsoft.Sales.History; + +codeunit 7289 SalesShipmentLookup implements DocumentLookupSubType +{ + Access = Internal; + + var + NoDocumentFound1Err: Label 'Copilot could not find the requested Posted Sales Shipment for %1. Please rephrase the description and try again.', Comment = '%1 = Customer Name'; + NoDocumentFound2Err: Label 'Copilot could not find the requested Posted Sales Shipment %1. Please rephrase the description and try again.', Comment = '%1 = Document No.'; + NoLinesFoundInTheDocumentErr: Label 'Copilot found the Posted Sales Shipment %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"; + SalesShipmentHeader: Record "Sales Shipment Header"; + DocumentLookup: Codeunit "Document Lookup Function"; + DocumentNo: Text; + StartDateStr: Text; + EndDateStr: Text; + FoundDocNo: Code[20]; + begin + DocumentLookup.GetParametersFromCustomDimension(CustomDimension, SourceSalesHeader, DocumentNo, StartDateStr, EndDateStr); + SalesShipmentHeader.SetLoadFields("No."); + // setup SecurityFilter + SalesShipmentHeader.SetSecurityFilterOnRespCenter(); + FoundDocNo := SearchPossibleNo(DocumentNo); + // Set up date range + SetFilterOnDateForPostedSalesShipmentHeader(StartDateStr, EndDateStr, SalesShipmentHeader); + if FoundDocNo <> '' then + SalesShipmentHeader.SetRange("No.", FoundDocNo) + else + SalesShipmentHeader.SetRange("Sell-to Customer No.", SourceSalesHeader."Sell-to Customer No."); + + SalesShipmentHeader.SetCurrentKey("Document Date"); + if SalesShipmentHeader.FindLast() then + FoundDocNo := SalesShipmentHeader."No." + else + if FoundDocNo = '' then + Error(NoDocumentFound1Err, SourceSalesHeader."Sell-to Customer Name") + else + Error(NoDocumentFound2Err, FoundDocNo); + + GetPostedSalesShipmentLinesIntoTempTable(FoundDocNo, TempSalesLineAiSuggestion); + end; + + local procedure SetFilterOnDateForPostedSalesShipmentHeader(StartDateStr: Text; EndDateStr: Text; var SalesShipmentHeader: Record "Sales Shipment 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); + SalesShipmentHeader.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, DocNoLen, Result) then + exit(Result) + else + Error(NoDocumentFound2Err, DocumentNo); + end; + + local procedure SearchAmbiguousNo(DocumentNo: Text; DocNoLen: Integer; var Result: Code[20]): Boolean + 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.SetFilter("No.", 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; + end; + exit(false); + end; + + local procedure SearchPreciseNo(DocumentNo: Text; DocNoLen: Integer; var Result: Code[20]): Boolean + 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.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."); + 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."); + 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."); + 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."); + SalesShipmentHeader.SetRange("Your Reference", DocumentNo); + + if (SalesShipmentHeader.FindLast()) then begin + Result := SalesShipmentHeader."No."; + exit(true); + end; + end; + exit(false); + end; + + local procedure GetPostedSalesShipmentLinesIntoTempTable(DocumentNo: Code[20]; var TempSalesLineAiSuggestion: Record "Sales Line AI Suggestions" temporary) + var + SalesShipmentLine: Record "Sales Shipment Line"; + Item: Record Item; + UoMMgt: Codeunit "Unit of Measure Management"; + LineNumber: Integer; + begin + if not TempSalesLineAiSuggestion.FindLast() then + LineNumber := 1 + 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); + if SalesShipmentLine.FindSet() then begin + repeat + Item.SetRange("No.", SalesShipmentLine."No."); + Item.SetRange(Blocked, false); + Item.SetRange("Sales Blocked", false); + if Item.FindFirst() then begin + TempSalesLineAiSuggestion.Init(); + LineNumber := LineNumber + 1; + TempSalesLineAiSuggestion."Line No." := LineNumber; + TempSalesLineAiSuggestion.Type := SalesShipmentLine.Type; + 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.SetSourceDocument(SalesShipmentLine.RecordId()); + TempSalesLineAiSuggestion.Insert(); + end; + until SalesShipmentLine.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/Enums/DocumentLookupTypes.Enum.al b/Apps/W1/SalesLinesSuggestions/app/SalesAzureOpenAITools/Enums/DocumentLookupTypes.Enum.al new file mode 100644 index 0000000000..aa7cbb6aec --- /dev/null +++ b/Apps/W1/SalesLinesSuggestions/app/SalesAzureOpenAITools/Enums/DocumentLookupTypes.Enum.al @@ -0,0 +1,28 @@ +// ------------------------------------------------------------------------------------------------ +// 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; + +enum 7279 "Document Lookup Types" implements DocumentLookupSubType +{ + Access = Internal; + Extensible = false; + + value(0; "Sales Order") + { + Implementation = DocumentLookupSubType = SalesOrderLookup; + } + value(1; "Posted Sales Invoice") + { + Implementation = DocumentLookupSubType = SalesInvoiceLookup; + } + value(2; "Posted Sales Shipment") + { + Implementation = DocumentLookupSubType = SalesShipmentLookup; + } + value(3; "Sales Quote") + { + Implementation = DocumentLookupSubType = SalesQuoteLookup; + } +} \ No newline at end of file diff --git a/Apps/W1/SalesLinesSuggestions/app/SalesAzureOpenAITools/Enums/SalesSupportedTools.Enum.al b/Apps/W1/SalesLinesSuggestions/app/SalesAzureOpenAITools/Enums/SalesSupportedTools.Enum.al new file mode 100644 index 0000000000..7e33b14867 --- /dev/null +++ b/Apps/W1/SalesLinesSuggestions/app/SalesAzureOpenAITools/Enums/SalesSupportedTools.Enum.al @@ -0,0 +1,24 @@ +// ------------------------------------------------------------------------------------------------ +// 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; + +enum 7278 "Sales Supported Tools" implements SalesAzureOpenAITools +{ + Access = Internal; + Extensible = false; + + value(0; magic_function) + { + Implementation = SalesAzureOpenAITools = "Magic Function"; + } + value(1; search_items) + { + Implementation = SalesAzureOpenAITools = "Search Items Function"; + } + value(2; lookup_from_document) + { + Implementation = SalesAzureOpenAITools = "Document Lookup Function"; + } +} \ No newline at end of file diff --git a/Apps/W1/SalesLinesSuggestions/app/SalesAzureOpenAITools/FunctionsImpl/DocumentLookupFunction.Codeunit.al b/Apps/W1/SalesLinesSuggestions/app/SalesAzureOpenAITools/FunctionsImpl/DocumentLookupFunction.Codeunit.al new file mode 100644 index 0000000000..c8af7a4c04 --- /dev/null +++ b/Apps/W1/SalesLinesSuggestions/app/SalesAzureOpenAITools/FunctionsImpl/DocumentLookupFunction.Codeunit.al @@ -0,0 +1,149 @@ +// ------------------------------------------------------------------------------------------------ +// 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.Telemetry; + +codeunit 7283 "Document Lookup Function" implements SalesAzureOpenAITools +{ + Access = Internal; + + var + DocumentLookUpLbl: Label 'function_call: lookup_from_document', Locked = true; + SourceDocumentRecordIDLbl: Label 'SourceDocumentRecordID', Locked = true; + + [NonDebuggable] + procedure GetToolPrompt(): JsonObject + var + Prompt: Codeunit "SLS Prompts"; + PromptJson: JsonObject; + begin + PromptJson.ReadFrom(Prompt.GetSLSDocumentLookupPrompt()); + exit(PromptJson); + end; + + [NonDebuggable] + procedure ToolCall(Arguments: JsonObject; CustomDimension: Dictionary of [Text, Text]): Variant + var + TempSalesLineAiSuggestion: Record "Sales Line AI Suggestions" temporary; + SalesLineAISuggestionImpl: Codeunit "Sales Lines Suggestions Impl."; + FeatureTelemetry: Codeunit "Feature Telemetry"; + NotificationManager: Codeunit "Notification Manager"; + FeatureTelemetryCD: Dictionary of [Text, Text]; + DocLookupType: Enum "Document Lookup Types"; + DocumentLookupSubType: Interface DocumentLookupSubType; + ItemResults: JsonToken; + ItemResultsArray: JsonArray; + DocumentNo: Text; + StartDateTxt: Text; + EndDateTxt: Text; + SourceDocumentRecIdTxt: Text; + SearchQuery: Text; + begin + if Arguments.Get('results', ItemResults) then begin + ItemResultsArray := ItemResults.AsArray(); + + if not GetDetailsFromUserQuery(DocumentNo, StartDateTxt, EndDateTxt, DocLookupType, ItemResultsArray) then begin + FeatureTelemetry.LogError('0000MDX', SalesLineAISuggestionImpl.GetFeatureName(), DocumentLookUpLbl, 'Error in retrieving filters from user query', GetLastErrorCallStack()); + NotificationManager.SendNotification(GetLastErrorText()); + exit(TempSalesLineAiSuggestion); + end; + + CustomDimension.Get(SourceDocumentRecordIDLbl, SourceDocumentRecIdTxt); + CustomDimension.Get('SearchQuery', SearchQuery); + + DocumentLookupSubType := DocLookupType; + FeatureTelemetryCD.Add('Document Type', DocLookupType.Names().Get(DocLookupType.Ordinals.IndexOf(DocLookupType.AsInteger()))); + + if SearchSalesDocument(TempSalesLineAiSuggestion, DocumentLookupSubType, SourceDocumentRecIdTxt, DocumentNo, StartDateTxt, EndDateTxt) then begin + FeatureTelemetry.LogUsage('0000ME0', SalesLineAISuggestionImpl.GetFeatureName(), DocumentLookUpLbl, FeatureTelemetryCD); + if TempSalesLineAiSuggestion.Count = 0 then + NotificationManager.SendNotification(SalesLineAISuggestionImpl.GetNoSalesLinesSuggestionsMsg()); + end + else begin + FeatureTelemetry.LogError('0000MDZ', SalesLineAISuggestionImpl.GetFeatureName(), DocumentLookUpLbl, 'Document lookup resulted in an error', GetLastErrorCallStack(), FeatureTelemetryCD); + NotificationManager.SendNotification(GetLastErrorText()); + end; + end + else begin + FeatureTelemetry.LogError('0000MML', SalesLineAISuggestionImpl.GetFeatureName(), 'Process Document Lookup', 'results not found in tools object.'); + NotificationManager.SendNotification(SalesLineAISuggestionImpl.GetChatCompletionResponseErr()); + end; + exit(TempSalesLineAiSuggestion); + 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 GetDetailsFromUserQuery(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"; + else + Error(UnknownDocTypeErr); + end; + + if JsonItem.AsObject().Get('document_no', 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/SalesAzureOpenAITools/FunctionsImpl/MagicFunction.Codeunit.al b/Apps/W1/SalesLinesSuggestions/app/SalesAzureOpenAITools/FunctionsImpl/MagicFunction.Codeunit.al new file mode 100644 index 0000000000..221ef56d3d --- /dev/null +++ b/Apps/W1/SalesLinesSuggestions/app/SalesAzureOpenAITools/FunctionsImpl/MagicFunction.Codeunit.al @@ -0,0 +1,36 @@ +// ------------------------------------------------------------------------------------------------ +// 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.Telemetry; + +codeunit 7284 "Magic Function" implements SalesAzureOpenAITools +{ + Access = Internal; + + [NonDebuggable] + procedure GetToolPrompt(): JsonObject + var + Prompt: Codeunit "SLS Prompts"; + PromptJson: JsonObject; + begin + PromptJson.ReadFrom(Prompt.GetSLSMagicFunctionPrompt()); + exit(PromptJson); + end; + + [NonDebuggable] + procedure ToolCall(Arguments: JsonObject; CustomDimension: Dictionary of [Text, Text]): Variant + var + TempSalesLineAiSuggestion: Record "Sales Line AI Suggestions" temporary; + FeatureTelemetry: Codeunit "Feature Telemetry"; + SalesLineAISuggestionImpl: Codeunit "Sales Lines Suggestions Impl."; + NotificationManager: Codeunit "Notification Manager"; + begin + FeatureTelemetry.LogUsage('0000ME3', SalesLineAISuggestionImpl.GetFeatureName(), 'function_call: magic_function'); + NotificationManager.SendNotification(SalesLineAISuggestionImpl.GetNoSalesLinesSuggestionsMsg()); + exit(TempSalesLineAiSuggestion); + end; + +} \ No newline at end of file diff --git a/Apps/W1/SalesLinesSuggestions/app/SalesAzureOpenAITools/FunctionsImpl/SearchItemsFunction.Codeunit.al b/Apps/W1/SalesLinesSuggestions/app/SalesAzureOpenAITools/FunctionsImpl/SearchItemsFunction.Codeunit.al new file mode 100644 index 0000000000..2ff3a89484 --- /dev/null +++ b/Apps/W1/SalesLinesSuggestions/app/SalesAzureOpenAITools/FunctionsImpl/SearchItemsFunction.Codeunit.al @@ -0,0 +1,64 @@ +// ------------------------------------------------------------------------------------------------ +// 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.Telemetry; + +codeunit 7285 "Search Items Function" implements SalesAzureOpenAITools +{ + Access = Internal; + + var + SearchItemsLbl: Label 'function_call: search_items', Locked = true; + + [NonDebuggable] + procedure GetToolPrompt(): JsonObject + var + Prompt: Codeunit "SLS Prompts"; + PromptJson: JsonObject; + begin + PromptJson.ReadFrom(Prompt.GetSLSSearchItemPrompt()); + exit(PromptJson); + end; + + [NonDebuggable] + procedure ToolCall(Arguments: JsonObject; CustomDimension: Dictionary of [Text, Text]): Variant + var + TempSalesLineAiSuggestion: Record "Sales Line AI Suggestions" temporary; + SearchUtility: Codeunit "Search"; + FeatureTelemetry: Codeunit "Feature Telemetry"; + SalesLineAISuggestionImpl: Codeunit "Sales Lines Suggestions Impl."; + NotificationManager: Codeunit "Notification Manager"; + ItemsResults: JsonToken; + ItemResultsArray: JsonArray; + SearchStyle: Enum "Search Style"; + SearchStyleTxt: Text; + SearchQuery: Text; + SearchIntentLbl: Label 'Add products to a sales order.', Locked = true; + begin + if Arguments.Get('results', ItemsResults) then begin + ItemResultsArray := ItemsResults.AsArray(); + CustomDimension.Get('SearchQuery', SearchQuery); + CustomDimension.Get('SearchStyle', SearchStyleTxt); + Evaluate(SearchStyle, SearchStyleTxt); + + if SearchUtility.SearchMultiple(ItemResultsArray, SearchStyle, SearchIntentLbl, SearchQuery, 1, 25, false, true, TempSalesLineAiSuggestion) then begin + FeatureTelemetry.LogUsage('0000ME2', SalesLineAISuggestionImpl.GetFeatureName(), SearchItemsLbl); + if TempSalesLineAiSuggestion.Count = 0 then + NotificationManager.SendNotification(SalesLineAISuggestionImpl.GetNoSalesLinesSuggestionsMsg()); + end + else begin + FeatureTelemetry.LogError('0000ME1', SalesLineAISuggestionImpl.GetFeatureName(), SearchItemsLbl, 'Search API resulted in an error', GetLastErrorCallStack()); + NotificationManager.SendNotification(SalesLineAISuggestionImpl.GetChatCompletionResponseErr()); + end; + end + else begin + FeatureTelemetry.LogError('0000ML5', SalesLineAISuggestionImpl.GetFeatureName(), 'Process Search Item', 'results not found in tools object.'); + NotificationManager.SendNotification(SalesLineAISuggestionImpl.GetChatCompletionResponseErr()); + end; + + exit(TempSalesLineAiSuggestion); + end; +} \ No newline at end of file diff --git a/Apps/W1/SalesLinesSuggestions/app/SalesAzureOpenAITools/SalesAzureOpenAITools.Interface.al b/Apps/W1/SalesLinesSuggestions/app/SalesAzureOpenAITools/SalesAzureOpenAITools.Interface.al new file mode 100644 index 0000000000..da34783e6e --- /dev/null +++ b/Apps/W1/SalesLinesSuggestions/app/SalesAzureOpenAITools/SalesAzureOpenAITools.Interface.al @@ -0,0 +1,28 @@ +// ------------------------------------------------------------------------------------------------ +// 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; + +interface SalesAzureOpenAITools +{ + Access = Internal; + + /// + /// Get the prompt for the Tool. Tool prompt object describes the Tool and the should contain the following fields: + /// - Type: The name of the Tool, currently only function type is supported. For functions following fields are allowed: + /// -- Name: The name of the Tool. (Required) + /// -- Description: The description of the Tool. (Optional) + /// -- Parameters: The parameters of the Tool. (Required) + /// More details can be found here: https://go.microsoft.com/fwlink/?linkid=2254538 + /// + procedure GetToolPrompt(): JsonObject; + + /// + /// This function is invoked as a response from Azure Open AI. + /// -Arguments: The expected parameters of the Tool defined. + /// -CustomDimension: This can be used to pass any context information to the function. + /// The function returns a variant, and it's up to the implementation to decide what to return. + /// + procedure ToolCall(Arguments: JsonObject; CustomDimension: Dictionary of [Text, Text]): Variant; +} \ No newline at end of file diff --git a/Apps/W1/SalesLinesSuggestions/app/SalesLineAISuggestions.Page.al b/Apps/W1/SalesLinesSuggestions/app/SalesLineAISuggestions.Page.al new file mode 100644 index 0000000000..7ce3c1f347 --- /dev/null +++ b/Apps/W1/SalesLinesSuggestions/app/SalesLineAISuggestions.Page.al @@ -0,0 +1,365 @@ +// ------------------------------------------------------------------------------------------------ +// 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.Telemetry; + +page 7275 "Sales Line AI Suggestions" +{ + Caption = 'Suggest Sales Lines'; + DataCaptionExpression = PageCaptionTxt; + PageType = PromptDialog; + IsPreview = true; + Extensible = false; + ApplicationArea = All; + Editable = true; + InherentEntitlements = X; + InherentPermissions = X; + + layout + { + area(Prompt) + { + field(SearchQueryTxt; SearchQueryTxt) + { + ApplicationArea = All; + MultiLine = true; + ShowCaption = false; + ToolTip = 'Enter your search query here. You can use natural language to describe what you are looking for.'; + Caption = 'Search Query'; + InstructionalText = 'Describe items and quantities or refer to existing documents to copy from'; + } + } + + area(Content) + { + fixed("Fixed Controls") + { + ShowCaption = false; + group(StatusLineGroup) + { + ShowCaption = false; + Visible = ShowStatusLine; + Editable = false; + + field("Status Line"; StatusLine) + { + ShowCaption = false; + Editable = false; + + trigger OnDrillDown() + begin + TempSalesLineAISuggestion.ShowSourceHeaderDocument(); + end; + } + } + } + part(SalesLinesSub; "Sales Line AI Suggestions Sub") + { + Caption = 'Suggested sales lines'; + ShowFilter = false; + ApplicationArea = All; + Editable = true; + Enabled = true; + } + } + area(PromptOptions) + { + field(MatchingStyle; SearchStyle) + { + Caption = 'Matching'; + ApplicationArea = All; + ToolTip = 'Specifies the search confidence to use when generating sales line suggestions.'; + trigger OnValidate() + begin + if SearchStyle = SearchStyle::Permissive then + ViewOptions := ViewOptions::"Lines and Confidence"; + end; + } + field(ViewOptions; ViewOptions) + { + Caption = 'View'; + ApplicationArea = All; + ToolTip = 'Specifies whether to show lines or lines and confidence about the sales line suggestions when possible.'; + OptionCaption = 'Lines only, Lines and Confidence'; + } + } + } + + actions + { + area(SystemActions) + { + systemaction(Generate) + { + Caption = 'Generate'; + ToolTip = 'Generate sales line suggestions from Dynamics 365 Copilot.'; + + trigger OnAction() + var + NotificationManager: Codeunit "Notification Manager"; + MaxSearchQueryLength: Decimal; + SearchQueryLengthExceededErr: Label 'You''ve exceeded the maximum number of allowed characters by %1. Please rephrase and try again.', Comment = '%1 = Integer'; + SearchQueryNotProvidedErr: Label 'Please provide a query to generate sales line suggestions.'; + begin + NotificationManager.RecallNotification(); + + MaxSearchQueryLength := 10000; + if StrLen(SearchQueryTxt) > MaxSearchQueryLength then + Error(SearchQueryLengthExceededErr, Format(StrLen(SearchQueryTxt) - MaxSearchQueryLength, 0)); + + if SearchQueryTxt.Trim() = '' then + Error(SearchQueryNotProvidedErr); + + GenerateSalesLineSuggestions(SearchQueryTxt, SearchStyle); + end; + + } + systemaction(OK) + { + Caption = 'Insert'; + ToolTip = 'Keep sales line suggestions proposed by Dynamics 365 Copilot.'; + Enabled = IsInsertEnabled; + } + systemaction(Cancel) + { + Caption = 'Discard'; + ToolTip = 'Discard sales line suggestions proposed by Dynamics 365 Copilot.'; + } + } + area(PromptGuide) + { + + group(CopyFromOrderPrompts) + { + Caption = 'Copy line items'; +#pragma warning disable AW0005 + action(DocumentSearchCopyFromOrderPrompt) + { +#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.'; + + trigger OnAction() + var + CopyFromLbl: Label 'Copy from '; + begin + SearchQueryTxt := CopyFromLbl; + CurrPage.Update(false); + end; + } +#pragma warning disable AW0005 + action(DocumentSearchCopyFromLastInvoicePrompt) + { +#pragma warning restore AW0005 + Caption = 'Copy from the last 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'; + begin + SearchQueryTxt := CopyFromLbl; + CurrPage.Update(false); + end; + } + } + + group(AddLinesPrompts) + { + Caption = 'Add line items'; +#pragma warning disable AW0005 + action(ItemSearchAddItemDescPrompt) + { +#pragma warning restore AW0005 + Caption = 'Add item: [description]'; + ToolTip = 'Sample prompt for adding a line item by description. Text in brackets describes the item to add.'; + + trigger OnAction() + var + AddItemsLbl: Label 'Add item: '; + begin + SearchQueryTxt := AddItemsLbl; + CurrPage.Update(false); + end; + } +#pragma warning disable AW0005 + action(ItemSearchAddItemNoPrompt2) + { +#pragma warning restore AW0005 + Caption = 'Add item: [internal/external no.]'; + ToolTip = 'Sample prompt for adding a line item by item no. Text in brackets specifies the item to add.'; + + trigger OnAction() + var + AddItemsLbl: Label 'Add item: '; + begin + SearchQueryTxt := AddItemsLbl; + CurrPage.Update(false); + end; + } +#pragma warning disable AW0005 + action(ItemSearchAddItemQtyDescPrompt) + { +#pragma warning restore AW0005 + Caption = 'Add item: [quantity] [description]'; + ToolTip = 'Sample prompt for adding a line item by quantity and description. Text in brackets describes the quantity and item to add.'; + trigger OnAction() + var + AddItemsLbl: Label 'Add item: '; + begin + SearchQueryTxt := AddItemsLbl; + CurrPage.Update(false); + end; + } +#pragma warning disable AW0005 + action(ItemSearchAddItemDescriptionPrompt) + { +#pragma warning restore AW0005 + Caption = 'Add items: [description 1, description 2, ...]'; + ToolTip = 'Sample prompt for adding multiple line items. Text in brackets describes the items, separated by comma.'; + trigger OnAction() + var + AddItemsLbl: Label 'Add item: '; + begin + SearchQueryTxt := AddItemsLbl; + CurrPage.Update(false); + end; + } + } + } + } + + trigger OnQueryClosePage(CloseAction: Action): Boolean + var + SalesLineUtility: Codeunit "Sales Line Utility"; + FeatureTelemetry: Codeunit "Feature Telemetry"; + SalesLineAISuggestionImpl: Codeunit "Sales Lines Suggestions Impl."; + begin + TotalCopiedLines := 0; + if CloseAction = CloseAction::OK then begin + TotalCopiedLines := TempSalesLineAISuggestion.Count(); + if TotalCopiedLines > 0 then begin + SalesLineUtility.CopySalesLineToDoc(GlobalSalesHeader, TempSalesLineAISuggestion); + FeatureTelemetry.LogUptake('0000ME4', SalesLineAISuggestionImpl.GetFeatureName(), Enum::"Feature Uptake Status"::Used); + end; + end; + + // TotalCopiedLines will be zero in case none of the lines were inserted. + // We don't want to log telemetry in case the user did not generate any suggestions. + if Durations.Count() > 0 then + FeatureTelemetry.LogUsage('0000ME5', SalesLineAISuggestionImpl.GetFeatureName(), 'Statistics', GetFeatureTelemetryCustomDimensions()); + end; + + trigger OnOpenPage() + begin + SearchStyle := SearchStyle::Balanced; + end; + + local procedure GenerateSalesLineSuggestions(SearchQuery: Text; CurrSearchStyle: Enum "Search Style") + var + SalesLineAISuggestionImpl: Codeunit "Sales Lines Suggestions Impl."; + StartDateTime: DateTime; + CRLF: Text[2]; + begin + TempSalesLineAISuggestion.DeleteAll(); + Clear(TempSalesLineAISuggestion); + StartDateTime := CurrentDateTime(); + SalesLineAISuggestionImpl.GenerateSalesLineSuggestions(SearchQuery, CurrSearchStyle, GlobalSalesHeader, TempSalesLineAISuggestion); + Durations.Add(CurrentDateTime() - StartDateTime); + TotalSuggestedLines.Add(TempSalesLineAISuggestion.Count()); + CRLF[1] := 13; // Carriage return, '\r' + CRLF[2] := 10; // Line feed, '\n' + PageCaptionTxt := SearchQuery.Replace(CRLF[1], ' ').Replace(CRLF[2], ' '); + CurrPage.SalesLinesSub.Page.Load(TempSalesLineAISuggestion, ViewOptions); + SetPageControls(); + end; + + local procedure SetPageControls() + begin + IsInsertEnabled := TempSalesLineAISuggestion.Count() > 0; + SetStatusLine(); + end; + + procedure SetSalesHeader(OriginSalesHeader: Record "Sales Header") + begin + GlobalSalesHeader := OriginSalesHeader; + end; + + local procedure SetStatusLine() + var + DocumentType: Text; + DocumentNo: Text; + DocumentDate: Date; + CustomerName: Text; + StatusLineDocSearchTxt: Label '%1 %2', Comment = '%1 = Document Type, %2 = Document No.'; + StatusLineFromCustomerTxt: Label 'for %1', Comment = '%1 = Customer Name, example: 1) Sales Order 1234 for Adatum 2) Sales Order 1234 for Adatum from 31/01/2021'; + StatusLineDocWithDocDateTxt: Label 'from %1', Comment = '%1 = Document Date, example: 1) Sales Order 1234 from 31/01/2021 2) Sales Order 1234 for Adatum from 31/01/2021'; + begin + if TempSalesLineAISuggestion."Source Line Record ID".TableNo <> 0 then begin + TempSalesLineAISuggestion.GetSourceDocumentInfo(DocumentType, DocumentNo, DocumentDate, CustomerName); + + if DocumentNo <> '' then begin + StatusLine := StrSubstNo(StatusLineDocSearchTxt, DocumentType, DocumentNo); + if CustomerName <> '' then + StatusLine += ' ' + StrSubstNo(StatusLineFromCustomerTxt, CustomerName); + if DocumentDate > 0D then + StatusLine += ' ' + StrSubstNo(StatusLineDocWithDocDateTxt, DocumentDate); + ShowStatusLine := true; + end + else begin + StatusLine := ''; + ShowStatusLine := false; + end; + end + else begin + StatusLine := ''; + ShowStatusLine := false; + end; + end; + + local procedure GetFeatureTelemetryCustomDimensions() CustomDimension: Dictionary of [Text, Text] + begin + CustomDimension.Add('Durations', ConvertListOfDurationToString(Durations)); + CustomDimension.Add('TotalSuggestedLines', ConvertListOfIntegerToString(TotalSuggestedLines)); + CustomDimension.Add('TotalCopiedLines', Format(TotalCopiedLines)); + end; + + local procedure ConvertListOfDurationToString(ListOfDuration: List of [Duration]) Result: Text + var + Dur: Duration; + DurationAsBigInt: BigInteger; + begin + foreach Dur in ListOfDuration do begin + DurationAsBigInt := Dur; + Result += Format(DurationAsBigInt) + ', '; + end; + Result := Result.TrimEnd(', '); + end; + + local procedure ConvertListOfIntegerToString(ListOfInteger: List of [Integer]) Result: Text + var + Int: Integer; + begin + foreach Int in ListOfInteger do + Result += Format(Int) + ', '; + Result := Result.TrimEnd(', '); + end; + + var + TempSalesLineAISuggestion: Record "Sales Line AI Suggestions" temporary; + GlobalSalesHeader: Record "Sales Header"; + SearchQueryTxt: Text; + SearchStyle: Enum "Search Style"; + ViewOptions: Option "Lines only","Lines and Confidence"; + PageCaptionTxt: Text; + StatusLine: Text; + ShowStatusLine: Boolean; + Durations: List of [Duration]; // Generate action can be triggered multiple times + TotalSuggestedLines: List of [Integer]; // Generate action can be triggered multiple times + TotalCopiedLines: Integer; // Lines can be inserted once + IsInsertEnabled: Boolean; +} \ No newline at end of file diff --git a/Apps/W1/SalesLinesSuggestions/app/SalesLineAISuggestions.Table.al b/Apps/W1/SalesLinesSuggestions/app/SalesLineAISuggestions.Table.al new file mode 100644 index 0000000000..75f257ba82 --- /dev/null +++ b/Apps/W1/SalesLinesSuggestions/app/SalesLineAISuggestions.Table.al @@ -0,0 +1,245 @@ +// ------------------------------------------------------------------------------------------------ +// 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.Sales.History; +using Microsoft.Inventory.Item; + +table 7275 "Sales Line AI Suggestions" +{ + TableType = Temporary; + InherentEntitlements = X; + InherentPermissions = RIMDX; + Access = Internal; + + fields + { + field(4; "Line No."; Integer) + { + Caption = 'Line No.'; + } + field(5; Type; Enum "Sales Line Type") + { + Caption = 'Type'; + } + field(6; "No."; Code[20]) + { + Caption = 'No.'; + TableRelation = Item where(Blocked = const(false), "Sales Blocked" = const(false)); + ValidateTableRelation = false; + } + field(7; "Variant Code"; Code[10]) + { + Caption = 'Variant Code'; + ToolTip = 'Specifies the variant of the item on the line.'; + TableRelation = if (Type = const(Item)) "Item Variant".Code where("Item No." = field("No."), Blocked = const(false), "Sales Blocked" = const(false)); + ValidateTableRelation = false; + } + field(11; Description; Text[100]) + { + Caption = 'Description'; + } + field(15; Quantity; Decimal) + { + Caption = 'Quantity'; + ToolTip = 'Specifies the Quantity in the Sales Unit of Measure defined on the Item card.'; + DecimalPlaces = 0 : 5; + } + field(16; Confidence; Enum "Search Confidence") + { + Caption = 'Confidence'; + } + field(20; "Primary Search Terms"; Blob) + { + Caption = 'Primary Search Terms'; + } + field(21; "Additional Search Terms"; Blob) + { + Caption = 'Secondary Search Terms'; + } + field(30; "Source Line Record ID"; RecordId) + { + Caption = 'Source Line Record ID'; + } + } + + keys + { + key(Key1; "Line No.") + { + } + } + + internal procedure SetSourceDocument(RecID: RecordId) + begin + Rec."Source Line Record ID" := RecID; + end; + + internal procedure SetPrimarySearchTerms(SearchTerms: List of [Text]) + var + SearchTermOutStream: OutStream; + begin + Clear(Rec."Primary Search Terms"); + Rec."Primary Search Terms".CreateOutStream(SearchTermOutStream, TextEncoding::UTF8); + SearchTermOutStream.WriteText(ListOfTextToText(SearchTerms)); + end; + + internal procedure SetAdditionalSearchTerms(SearchTerms: List of [Text]) + var + SearchTermOutStream: OutStream; + begin + Clear(Rec."Additional Search Terms"); + Rec."Additional Search Terms".CreateOutStream(SearchTermOutStream, TextEncoding::UTF8); + SearchTermOutStream.WriteText(ListOfTextToText(SearchTerms)); + end; + + local procedure ListOfTextToText(var TextList: List of [Text]) Result: Text + var + Txt: Text; + begin + foreach Txt in TextList do + Result += Txt + ', '; + Result := Result.TrimEnd(', '); + end; + + internal procedure GetPrimarySearchTerms() Result: Text + var + SearchTermInStream: InStream; + begin + Rec.CalcFields("Primary Search Terms"); + Rec."Primary Search Terms".CreateInStream(SearchTermInStream, TextEncoding::UTF8); + SearchTermInStream.ReadText(Result); + end; + + internal procedure GetAdditionalSearchTerms() Result: Text + var + SearchTermInStream: InStream; + begin + Rec.CalcFields("Additional Search Terms"); + Rec."Additional Search Terms".CreateInStream(SearchTermInStream, TextEncoding::UTF8); + SearchTermInStream.ReadText(Result); + end; + + local procedure GetSourceHeader(): RecordId + var + SalesHeader: Record "Sales Header"; + SalesLine: Record "Sales Line"; + SalesInvoiceHeader: Record "Sales Invoice Header"; + SalesInvoiceLine: Record "Sales Invoice Line"; + SalesShipmentHeader: Record "Sales Shipment Header"; + SalesShipmentLine: Record "Sales Shipment Line"; + begin + case Rec."Source Line Record ID".TableNo of + Database::"Sales Line": + begin + Rec."Source Line Record ID".GetRecord().SetTable(SalesLine); + SalesHeader.SetLoadFields("Document Type", "No."); + SalesHeader.Get(SalesLine."Document Type", SalesLine."Document No."); + exit(SalesHeader.RecordId); + end; + Database::"Sales Invoice Line": + begin + Rec."Source Line Record ID".GetRecord().SetTable(SalesInvoiceLine); + SalesInvoiceHeader.SetLoadFields("No."); + SalesInvoiceHeader.Get(SalesInvoiceLine."Document No."); + exit(SalesInvoiceHeader.RecordId); + end; + Database::"Sales Shipment Line": + begin + Rec."Source Line Record ID".GetRecord().SetTable(SalesShipmentLine); + SalesShipmentHeader.SetLoadFields("No."); + SalesShipmentHeader.Get(SalesShipmentLine."Document No."); + exit(SalesShipmentHeader.RecordId); + end; + end; + end; + + internal procedure GetSourceDocumentInfo(var DocumentType: Text; var DocumentNo: Text; var DocumentDate: Date; var CustomerName: Text) + var + SalesHeader: Record "Sales Header"; + SalesInvoiceHeader: Record "Sales Invoice Header"; + SalesShipmentHeader: Record "Sales Shipment Header"; + SourceHeaderRecordId: RecordId; + begin + SourceHeaderRecordId := GetSourceHeader(); + case SourceHeaderRecordId.TableNo of + Database::"Sales Header": + begin + SourceHeaderRecordId.GetRecord().SetTable(SalesHeader); + SalesHeader.SetLoadFields("Document Type", "No.", "Document Date", "Sell-to Customer Name"); + SalesHeader.Get(SalesHeader."Document Type", SalesHeader."No."); + DocumentType := SalesHeader.GetDocTypeTxt(); + DocumentNo := SalesHeader."No."; + DocumentDate := SalesHeader."Document Date"; + CustomerName := SalesHeader."Sell-to Customer Name"; + end; + Database::"Sales Invoice Header": + begin + SourceHeaderRecordId.GetRecord().SetTable(SalesInvoiceHeader); + SalesInvoiceHeader.SetLoadFields("No.", "Document Date", "Sell-to Customer Name"); + SalesInvoiceHeader.Get(SalesInvoiceHeader."No."); + DocumentType := 'Posted Sales Invoice'; + DocumentNo := SalesInvoiceHeader."No."; + DocumentDate := SalesInvoiceHeader."Document Date"; + CustomerName := SalesInvoiceHeader."Sell-to Customer Name"; + end; + Database::"Sales Shipment Header": + begin + SourceHeaderRecordId.GetRecord().SetTable(SalesShipmentHeader); + SalesShipmentHeader.SetLoadFields("No.", "Document Date", "Sell-to Customer Name"); + SalesShipmentHeader.Get(SalesShipmentHeader."No."); + DocumentType := 'Posted Sales Shipment'; + DocumentNo := SalesShipmentHeader."No."; + DocumentDate := SalesShipmentHeader."Document Date"; + CustomerName := SalesShipmentHeader."Sell-to Customer Name"; + end; + end; + end; + + internal procedure ShowSourceHeaderDocument() + var + SalesHeader: Record "Sales Header"; + SalesShipmentHeader: Record "Sales Shipment Header"; + SalesInvHeader: Record "Sales Invoice Header"; + SourceLineRecId: RecordId; + begin + SourceLineRecId := GetSourceHeader(); + case SourceLineRecId.TableNo of + Database::"Sales Header": + begin + SourceLineRecId.GetRecord().SetTable(SalesHeader); + RunSalesHeaderPage(SalesHeader); + end; + Database::"Sales Shipment Header": + begin + SourceLineRecId.GetRecord().SetTable(SalesShipmentHeader); + PAGE.RunModal(Page::"Posted Sales Shipment", SalesShipmentHeader); + end; + Database::"Sales Invoice Header": + begin + SourceLineRecId.GetRecord().SetTable(SalesInvHeader); + PAGE.RunModal(Page::"Posted Sales Invoice", SalesInvHeader); + end; + end; + end; + + local procedure RunSalesHeaderPage(var SalesHeader: Record "Sales Header") + begin + case SalesHeader."Document Type" of + SalesHeader."Document Type"::Order: + PAGE.RunModal(Page::"Sales Order", SalesHeader); + SalesHeader."Document Type"::Invoice: + PAGE.RunModal(Page::"Sales Invoice", SalesHeader); + SalesHeader."Document Type"::"Credit Memo": + PAGE.RunModal(Page::"Sales Credit Memo", SalesHeader); + SalesHeader."Document Type"::"Blanket Order": + PAGE.RunModal(Page::"Blanket Sales Order", SalesHeader); + SalesHeader."Document Type"::"Return Order": + PAGE.RunModal(Page::"Sales Return Order", SalesHeader); + SalesHeader."Document Type"::Quote: + PAGE.RunModal(Page::"Sales Quote", SalesHeader); + end; + end; +} \ No newline at end of file diff --git a/Apps/W1/SalesLinesSuggestions/app/SalesLineAISuggestionsSub.Page.al b/Apps/W1/SalesLinesSuggestions/app/SalesLineAISuggestionsSub.Page.al new file mode 100644 index 0000000000..fc613feb4c --- /dev/null +++ b/Apps/W1/SalesLinesSuggestions/app/SalesLineAISuggestionsSub.Page.al @@ -0,0 +1,148 @@ +// ------------------------------------------------------------------------------------------------ +// 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; + +page 7276 "Sales Line AI Suggestions Sub" +{ + Caption = 'Lines proposed by Dynamics 365 Copilot'; + PageType = ListPart; + ApplicationArea = All; + SourceTable = "Sales Line AI Suggestions"; + SourceTableTemporary = true; + DeleteAllowed = true; + InsertAllowed = false; + ModifyAllowed = true; + InherentPermissions = X; + InherentEntitlements = X; + Extensible = false; + + layout + { + area(Content) + { + repeater(Lines) + { + FreezeColumn = "No."; + field("No."; Rec."No.") + { + Editable = false; + ToolTip = 'Specifies the item number of the suggested result.'; + } + field("Variant Code"; Rec."Variant Code") + { + ApplicationArea = Planning; + ShowMandatory = IsVariantCodeMandatory; + Visible = IsVariantCodeVisible; + ToolTip = 'Specifies the variant code of the suggested result.'; + + trigger OnValidate() + var + Item: Record Item; + begin + if Rec."Variant Code" = '' then + IsVariantCodeMandatory := Item.IsVariantMandatory(Rec.Type = Rec.Type::Item, Rec."No."); + end; + } + field("Line No."; Rec."Line No.") + { + Editable = false; + Visible = false; + ToolTip = 'Specifies the line number of the suggested result.'; + } + field("Description"; Rec."Description") + { + ToolTip = 'Specifies the description of the suggested result.'; + } + field("Quantity"; Rec.Quantity) + { + ToolTip = 'Specifies the quantity of the suggested result.'; + } + field(Confidence; Rec.Confidence) + { + StyleExpr = StyleExprText; + Visible = AdditionalInformationVisible; + Editable = false; + ToolTip = 'Specifies the confidence level of the suggested result.'; + } + field("Search Terms"; SearchTerms) + { + Editable = false; + Caption = 'Search Terms'; + ToolTip = 'Specifies the search terms that were used to find the suggested results.'; + Visible = AdditionalInformationVisible; + } + } + } + } + + trigger OnAfterGetRecord() + var + Item: Record Item; + begin + Clear(StyleExprText); + Clear(SearchTerms); + IsVariantCodeMandatory := false; + + if AdditionalInformationVisible then begin + if Rec.Confidence = Rec.Confidence::High then + StyleExprText := 'Favorable'; + + if Rec.Confidence = Rec.Confidence::Medium then + StyleExprText := 'Ambiguous'; + + if Rec.Confidence = Rec.Confidence::Low then + StyleExprText := 'Unfavorable'; + + SearchTerms := GetSearchTerms(); + end; + + if IsVariantCodeVisible and (Rec."No." <> '') then + IsVariantCodeMandatory := Item.IsVariantMandatory(Rec.Type = Rec.Type::Item, Rec."No."); + end; + + internal procedure Load(var TempSalesLineAISuggestion: Record "Sales Line AI Suggestions" temporary; ViewOptions: Option "Lines only","Lines and Confidence") + var + Item: Record Item; + TempSalesLineAISuggestionForVariant: Record "Sales Line AI Suggestions" temporary; + begin + Rec.Copy(TempSalesLineAISuggestion, true); + Rec.Reset(); + if Rec.Confidence = Rec.Confidence::None then + AdditionalInformationVisible := false + else + AdditionalInformationVisible := ViewOptions = ViewOptions::"Lines and Confidence"; + + IsVariantCodeVisible := false; + TempSalesLineAISuggestionForVariant.Copy(TempSalesLineAISuggestion, true); + TempSalesLineAISuggestionForVariant.SetRange("Variant Code", ''); + if TempSalesLineAISuggestionForVariant.FindSet() then + repeat + IsVariantCodeVisible := Item.IsVariantMandatory(TempSalesLineAISuggestionForVariant.Type = Rec.Type::Item, TempSalesLineAISuggestionForVariant."No.") or (TempSalesLineAISuggestion."Variant Code" <> ''); // If one of the items requires or has a variant code, then show the column + until (TempSalesLineAISuggestionForVariant.Next() = 0) or IsVariantCodeVisible; + end; + + local procedure GetSearchTerms(): Text + var + PrimarySearchTerms: Text; + AdditionalSearchTerms: Text; + CombinesSearchTerms: Text; + begin + PrimarySearchTerms := Rec.GetPrimarySearchTerms(); + AdditionalSearchTerms := Rec.GetAdditionalSearchTerms(); + CombinesSearchTerms := PrimarySearchTerms.Replace('|', ', '); + if AdditionalSearchTerms <> '' then + CombinesSearchTerms := CombinesSearchTerms + ', ' + AdditionalSearchTerms; + exit(CombinesSearchTerms); + end; + + var + AdditionalInformationVisible: Boolean; + IsVariantCodeMandatory: Boolean; + IsVariantCodeVisible: Boolean; + SearchTerms: Text; + StyleExprText: Text; +} \ No newline at end of file diff --git a/Apps/W1/SalesLinesSuggestions/app/SalesLinesSuggestionsImpl.Codeunit.al b/Apps/W1/SalesLinesSuggestions/app/SalesLinesSuggestionsImpl.Codeunit.al new file mode 100644 index 0000000000..b46b739236 --- /dev/null +++ b/Apps/W1/SalesLinesSuggestions/app/SalesLinesSuggestionsImpl.Codeunit.al @@ -0,0 +1,235 @@ +// ------------------------------------------------------------------------------------------------ +// 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; +using System.AI; +using System.Telemetry; +using System.Environment; + +codeunit 7275 "Sales Lines Suggestions Impl." +{ + Access = Internal; + + var + ChatCompletionResponseErr: Label 'Sorry, something went wrong. Please rephrase and try again.'; + + internal procedure GetFeatureName(): Text + begin + exit('Sales Lines Suggestions'); + end; + + internal procedure GetChatCompletionResponseErr(): Text + begin + exit(ChatCompletionResponseErr); + end; + + internal procedure GetNoSalesLinesSuggestionsMsg(): Text + var + NoSalesLinesSuggestionsMsg: Label 'There are no suggestions for this description. Please rephrase it.'; + begin + exit(NoSalesLinesSuggestionsMsg); + end; + + local procedure MaxTokens(): Integer + begin + exit(4096); + end; + + internal procedure GetLinesSuggestions(SalesLine: Record "Sales Line") + var + SalesHeader: Record "Sales Header"; + AzureOpenAI: Codeunit "Azure OpenAI"; + FeatureTelemetry: Codeunit "Feature Telemetry"; + SalesLineAISuggestionImpl: Codeunit "Sales Lines Suggestions Impl."; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + ALSearch: DotNet ALSearch; + FeatureTelemetryCustomDimension: Dictionary of [Text, Text]; + SalesHeaderNotInitializedErr: Label '%1 header is not initialized', Comment = '%1 = Document Type'; + ErrorTxt: Text; + begin + SalesLine.TestStatusOpen(); + if not AzureOpenAI.IsEnabled(Enum::"Copilot Capability"::"Sales Lines Suggestions") then + exit; + + FeatureTelemetryCustomDimension.Add('Document Type', SalesLine."Document Type".Names().Get(SalesLine."Document Type".Ordinals.IndexOf(SalesLine."Document Type".AsInteger()))); + FeatureTelemetry.LogUptake('0000MEB', SalesLineAISuggestionImpl.GetFeatureName(), Enum::"Feature Uptake Status"::Discovered, FeatureTelemetryCustomDimension); + + if not ALSearch.IsItemSearchReady() then + ALSearch.EnableItemSearch(); + + if SalesHeader.Get(SalesLine."Document Type", SalesLine."Document No.") then begin + SalesLineAISuggestions.SetSalesHeader(SalesHeader); + SalesLineAISuggestions.LookupMode := true; + FeatureTelemetry.LogUptake('0000MEC', SalesLineAISuggestionImpl.GetFeatureName(), Enum::"Feature Uptake Status"::"Set up", FeatureTelemetryCustomDimension); + SalesLineAISuggestions.Run(); + end else begin + ErrorTxt := StrSubstNo(SalesHeaderNotInitializedErr, SalesLine."Document Type"); + FeatureTelemetry.LogError('0000ME6', SalesLineAISuggestionImpl.GetFeatureName(), 'Get the source sales header', ErrorTxt); + Error(ErrorTxt); + end; + end; + + [NonDebuggable] + local procedure BuildIntentSystemPrompt(): SecretText + var + Prompt: Codeunit "SLS Prompts"; + IntentSystemPrompt: SecretText; + begin + IntentSystemPrompt := Prompt.GetSLSSystemPrompt(); + exit(IntentSystemPrompt); + end; + + internal procedure GenerateSalesLineSuggestions(SearchQuery: Text; SearchStyle: Enum "Search Style"; SourceSalesHeader: Record "Sales Header"; var TempSalesLineAiSuggestion: Record "Sales Line AI Suggestions" temporary) + var + CompletionAnswerTxt: Text; + begin + CompletionAnswerTxt := AICall(BuildIntentSystemPrompt(), SearchQuery); + ProcessCompletionAnswer(CompletionAnswerTxt, SearchQuery, SearchStyle, SourceSalesHeader, TempSalesLineAiSuggestion); + end; + + [NonDebuggable] + internal procedure AICall(SystemPromptTxt: SecretText; SearchQuery: Text): Text + var + AzureOpenAI: Codeunit "Azure OpenAi"; + AOAIDeployments: Codeunit "AOAI Deployments"; + AOAIOperationResponse: Codeunit "AOAI Operation Response"; + AOAIChatCompletionParams: Codeunit "AOAI Chat Completion Params"; + AOAIChatMessages: Codeunit "AOAI Chat Messages"; + DocumentLookup: Codeunit "Document Lookup Function"; + SearchItemsFunction: Codeunit "Search Items Function"; + MagicFunction: Codeunit "Magic Function"; + FeatureTelemetry: Codeunit "Feature Telemetry"; + NotificationManager: Codeunit "Notification Manager"; + TelemetryCD: Dictionary of [Text, Text]; + StartDateTime: DateTime; + DurationAsBigInt: BigInteger; + CompletionAnswerTxt: Text; + ResponseErr: Label 'Response error code: %1', Comment = '%1 = Error code', Locked = true; + begin + if not AzureOpenAI.IsEnabled(Enum::"Copilot Capability"::"Sales Lines Suggestions") then + exit; + + // Generate OpenAI Completion + AzureOpenAI.SetAuthorization(Enum::"AOAI Model Type"::"Chat Completions", AOAIDeployments.GetGPT4Latest()); + AzureOpenAI.SetCopilotCapability(Enum::"Copilot Capability"::"Sales Lines Suggestions"); + + AOAIChatCompletionParams.SetMaxTokens(MaxTokens()); + AOAIChatCompletionParams.SetTemperature(0); + + AOAIChatMessages.AddTool(MagicFunction.GetToolPrompt()); + AOAIChatMessages.AddTool(SearchItemsFunction.GetToolPrompt()); + AOAIChatMessages.AddTool(DocumentLookup.GetToolPrompt()); + AOAIChatMessages.SetToolChoice('auto'); + + AOAIChatMessages.SetPrimarySystemMessage(SystemPromptTxt); + AOAIChatMessages.AddUserMessage(SearchQuery); + + StartDateTime := CurrentDateTime(); + AzureOpenAI.GenerateChatCompletion(AOAIChatMessages, AOAIChatCompletionParams, AOAIOperationResponse); + DurationAsBigInt := CurrentDateTime() - StartDateTime; + TelemetryCD.Add('Response time', Format(DurationAsBigInt)); + + if AOAIOperationResponse.IsSuccess() then begin + CompletionAnswerTxt := AOAIOperationResponse.GetResult(); + if CompletionAnswerTxt = '' then begin + FeatureTelemetry.LogError('0000ME8', GetFeatureName(), 'Call Chat Completion API', 'Completion answer is empty', '', TelemetryCD); + NotificationManager.SendNotification(ChatCompletionResponseErr); + end + else + FeatureTelemetry.LogUsage('0000MED', GetFeatureName(), 'Call Chat Completion API', TelemetryCD); + end + else begin + FeatureTelemetry.LogError('0000ME7', GetFeatureName(), 'Call Chat Completion API', StrSubstNo(ResponseErr, AOAIOperationResponse.GetStatusCode()), '', TelemetryCD); + NotificationManager.SendNotification(ChatCompletionResponseErr); + end; + + exit(CompletionAnswerTxt); + end; + + [NonDebuggable] + local procedure ProcessCompletionAnswer(CompletionAnswerTxt: Text; SearchQuery: Text; SearchStyle: Enum "Search Style"; SourceSalesHeader: Record "Sales Header"; var TempSalesLineAiSuggestion: Record "Sales Line AI Suggestions" temporary) + var + FeatureTelemetry: Codeunit "Feature Telemetry"; + NotificationManager: Codeunit "Notification Manager"; + CustomDimension: Dictionary of [Text, Text]; + AnswerJson: JsonObject; + ArgumentJson: JsonObject; + ToolsArrayToken: JsonToken; + ToolType: JsonToken; + Tool: JsonToken; + Function: JsonToken; + FunctionName: JsonToken; + FunctionArgument: JsonToken; + Tools: Interface SalesAzureOpenAITools; + SupportedTools: Enum "Sales Supported Tools"; + Result: Variant; + begin + if CompletionAnswerTxt = '' then + exit; + + AnswerJson.ReadFrom(CompletionAnswerTxt); + CustomDimension.Add('SearchQuery', SearchQuery); + CustomDimension.Add('SearchStyle', Format(SearchStyle)); + CustomDimension.Add('SourceDocumentRecordID', Format(SourceSalesHeader.RecordId)); + + if AnswerJson.Get('tool_calls', ToolsArrayToken) then + foreach Tool in ToolsArrayToken.AsArray() do begin + Tool.AsObject().Get('type', ToolType); + if ToolType.AsValue().asText() = 'function' then begin + Tool.AsObject().Get('function', Function); + Function.AsObject().Get('name', FunctionName); + Function.AsObject().Get('arguments', FunctionArgument); + + if Evaluate(SupportedTools, FunctionName.AsValue().asText()) then + Tools := SupportedTools + else begin + Tools := SupportedTools::magic_function; + FeatureTelemetry.LogError('0000ME9', GetFeatureName(), 'Process function_call', 'Function not supported, defaulting to magic_function'); + end; + ArgumentJson.ReadFrom(FunctionArgument.AsValue().AsText()); + Result := Tools.ToolCall(ArgumentJson, CustomDimension); + + if Result.IsRecord then + TempSalesLineAiSuggestion.Copy(Result, true); + end; + break; + end + else begin + FeatureTelemetry.LogError('0000MEA', GetFeatureName(), 'Process function_call', 'function_call not found in the completion answer'); + NotificationManager.SendNotification(ChatCompletionResponseErr); + end; + end; + + procedure CheckSupportedApplicationFamily(): Boolean + var + EnvironmentInformation: Codeunit "Environment Information"; + ApplicationFamily: Text; + begin + ApplicationFamily := EnvironmentInformation.GetApplicationFamily(); + if ApplicationFamily = 'CA' then //Disabled for Canada due to legal reasons + exit(false); + exit(true); + end; + + procedure RegisterCapability() + var + CopilotCapability: Codeunit "Copilot Capability"; + EnvironmentInformation: Codeunit "Environment Information"; + DocUrlLbl: Label 'https://go.microsoft.com/fwlink/?linkid=2261665', Locked = true; + begin + if EnvironmentInformation.IsSaaSInfrastructure() then + if CheckSupportedApplicationFamily() then + if not CopilotCapability.IsCapabilityRegistered(Enum::"Copilot Capability"::"Sales Lines Suggestions") then + CopilotCapability.RegisterCapability(Enum::"Copilot Capability"::"Sales Lines Suggestions", DocUrlLbl); + + end; + + [EventSubscriber(ObjectType::Page, Page::"Copilot AI Capabilities", 'OnRegisterCopilotCapability', '', false, false)] + local procedure OnRegisterCopilotCapability() + begin + RegisterCapability(); + end; +} \ No newline at end of file diff --git a/Apps/W1/SalesLinesSuggestions/app/Search/ItemSearchSetup.Page.al b/Apps/W1/SalesLinesSuggestions/app/Search/ItemSearchSetup.Page.al new file mode 100644 index 0000000000..720fefa153 --- /dev/null +++ b/Apps/W1/SalesLinesSuggestions/app/Search/ItemSearchSetup.Page.al @@ -0,0 +1,112 @@ +// ------------------------------------------------------------------------------------------------ +// 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; + +page 7280 "Item Search Setup" +{ + PageType = Card; + Caption = 'Item Search Setup'; + InherentEntitlements = X; + InherentPermissions = X; + Extensible = false; + + layout + { + area(Content) + { + group(General) + { + field(Status; ItemSearchCapability) + { + Caption = 'Item Search Capability'; + ApplicationArea = All; + QuickEntry = false; + Editable = false; + ToolTip = 'Status of the item search capability.'; + + } + } + } + + } + actions + { + area(Processing) + { + action(EnableItemSearch) + { + ApplicationArea = All; + Caption = 'Enable Item Search'; + ToolTip = 'Enable the item search capability.'; + Image = Setup; + trigger OnAction() + var + ALSearch: DotNet ALSearch; + begin + ALSearch.EnableItemSearch(); + UpdateItemSearchStatus(); + end; + } + action(DisableItemSearch) + { + ApplicationArea = All; + Caption = 'Disable Item Search'; + ToolTip = 'Disable the item search capability.'; + Image = Setup; + trigger OnAction() + var + ALSearch: DotNet ALSearch; + begin + ALSearch.DisableItemSearch(); + UpdateItemSearchStatus(); + end; + } + action(Refresh) + { + ApplicationArea = All; + Caption = 'Refresh Status'; + ToolTip = 'Refresh status of the item search capability.'; + Image = Refresh; + trigger OnAction() + begin + UpdateItemSearchStatus(); + end; + } + } + area(Promoted) + { + actionref(EnableItemSearch_Promoted; EnableItemSearch) + { + } + actionref(DisableItemSearch_Promoted; DisableItemSearch) + { + } + actionref(Refresh_Promoted; Refresh) + { + } + } + } + + trigger OnOpenPage() + begin + UpdateItemSearchStatus(); + end; + + local procedure UpdateItemSearchStatus() + var + ALSearch: DotNet ALSearch; + begin + if ALSearch.IsItemSearchReady() then + ItemSearchCapability := 'Ready' + else + ItemSearchCapability := 'Not Ready'; + end; + + var + ItemSearchCapability: Text[100]; + +} \ No newline at end of file diff --git a/Apps/W1/SalesLinesSuggestions/app/Search/Search.Codeunit.al b/Apps/W1/SalesLinesSuggestions/app/Search/Search.Codeunit.al new file mode 100644 index 0000000000..1b4a5f09e5 --- /dev/null +++ b/Apps/W1/SalesLinesSuggestions/app/Search/Search.Codeunit.al @@ -0,0 +1,232 @@ +// ------------------------------------------------------------------------------------------------ +// 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; +using System.Telemetry; +using Microsoft.Inventory.Item; +using System.Security.Encryption; + +codeunit 7282 "Search" +{ + Access = Internal; + + [TryFunction] + internal procedure SearchMultiple(ItemResultsArray: JsonArray; SearchStyle: Enum "Search Style"; Intent: Text; SearchQuery: Text; Top: Integer; MaximumQueryResultsToRank: Integer; IncludeSynonyms: Boolean; UseContextAwareRanking: Boolean; var TempSalesLineAiSuggestion: Record "Sales Line AI Suggestions" temporary) + var + Item: Record "Item"; + TempSearchResponse: Record "Search API Response" temporary; + FeatureTelemetry: Codeunit "Feature Telemetry"; + SalesLineAISuggestionImpl: Codeunit "Sales Lines Suggestions Impl."; + CryptographyManagement: Codeunit "Cryptography Management"; + ALSearch: DotNet ALSearch; + ALSearchOptions: DotNet ALSearchOptions; + ALSearchQuery: DotNet ALSearchQuery; + ALSearchRankingContext: DotNet ALSearchRankingContext; + ALSearchResult: DotNet ALSearchResult; + SearchFilter: DotNet SearchFilter; + QueryResults: DotNet GenericList1; + ALSearchQueryResult: DotNet ALSearchQueryResult; + SearchProgress: Dialog; + ItemToken: JsonToken; + QuantityToken: JsonToken; + NameJsonToken: JsonToken; + SearchPrimaryKeyWords: List of [Text]; + SearchAdditionalKeyWords: List of [Text]; + Quantity: Decimal; + TelemetryCD: Dictionary of [Text, Text]; + StartDateTime: DateTime; + DurationAsBigInt: BigInteger; + HashAlgorithmType: Option MD5,SHA1,SHA256,SHA384,SHA512; + SearchItemNames: Text; + ItemTokentText: Text; + SearchSetupProgressLbl: Label 'Looking through item information'; + SearchingItemsLbl: Label 'Looking for items matching: %1', Comment = '%1= list of item names'; + + begin + if not ALSearch.IsItemSearchReady() then begin + SearchProgress.Open(SearchSetupProgressLbl); + while not ALSearch.IsItemSearchReady() do + Sleep(3000); + SearchProgress.Close(); + end; + + //Add ALSearch Options + ALSearchOptions := ALSearchOptions.SearchOptions(); + ALSearchOptions.IncludeSynonyms := IncludeSynonyms; + ALSearchOptions.UseContextAwareRanking := UseContextAwareRanking; + + //Add Search Filters + SearchFilter := SearchFilter.SearchFilter(); + SearchFilter.FieldNo := Item.FieldNo(Blocked); + SearchFilter.Expression := Text.StrSubstNo('<> %1', true); + ALSearchOptions.AddSearchFilter(SearchFilter); + + SearchFilter := SearchFilter.SearchFilter(); + SearchFilter.FieldNo := Item.FieldNo("Sales Blocked"); + SearchFilter.Expression := Text.StrSubstNo('<> %1', true); + ALSearchOptions.AddSearchFilter(SearchFilter); + + //Add Search Ranking Context + if UseContextAwareRanking then begin + ALSearchRankingContext := ALSearchRankingContext.SearchRankingContext(); + ALSearchRankingContext.Intent := Intent; + ALSearchRankingContext.UserMessage := SearchQuery; + ALSearchRankingContext.MaximumQueryResultsToRank := MaximumQueryResultsToRank; + ALSearchOptions.RankingContext := ALSearchRankingContext; + end; + + //Add Search Queries + foreach ItemToken in ItemResultsArray do begin + SearchPrimaryKeyWords := GetItemNameKeywords(ItemToken); + SearchAdditionalKeyWords := GetItemFeaturesKeywords(ItemToken); + ItemToken.AsObject().Get('name', NameJsonToken); + ItemToken.WriteTo(ItemTokentText); + SearchItemNames += NameJsonToken.AsValue().AsText() + ', '; + + BuildSearchQuery(SearchPrimaryKeyWords, SearchAdditionalKeyWords, CryptographyManagement.GenerateHash(ItemTokentText, HashAlgorithmType::SHA256), SearchStyle, Top, ALSearchQuery); + ALSearchOptions.AddSearchQuery(ALSearchQuery); + end; + + //Search Items + SearchProgress.Open(StrSubstNo(SearchingItemsLbl, SearchItemNames.TrimEnd(', '))); + StartDateTime := CurrentDateTime(); + ALSearchResult := ALSearch.FindItems(ALSearchOptions); + SearchProgress.Close(); + DurationAsBigInt := (CurrentDateTime() - StartDateTime); + TelemetryCD.Add('Response time', Format(DurationAsBigInt)); + FeatureTelemetry.LogUsage('0000MDW', SalesLineAISuggestionImpl.GetFeatureName(), 'FindItems', TelemetryCD); + + //Process Search Results + foreach ItemToken in ItemResultsArray do begin + ItemToken.WriteTo(ItemTokentText); + if ItemToken.AsObject().Get('quantity', QuantityToken) then + if (QuantityToken.IsValue() and (QuantityToken.AsValue().AsText() <> '')) then + Quantity := QuantityToken.AsValue().AsDecimal(); + + QueryResults := ALSearchResult.GetResultsForQuery(CryptographyManagement.GenerateHash(ItemTokentText, HashAlgorithmType::SHA256)); + + TempSearchResponse.DeleteAll(); + foreach ALSearchQueryResult in QueryResults do begin + TempSearchResponse.Init(); + TempSearchResponse.SysId := ALSearchQueryResult.SystemId; + TempSearchResponse.Score := ALSearchQueryResult.ContextAwareRankingScore; + TempSearchResponse.Insert(); + + SearchPrimaryKeyWords := GetItemNameKeywords(ItemToken); + SearchAdditionalKeyWords := GetItemFeaturesKeywords(ItemToken); + + GetSalesLineFromItemSystemIds(TempSearchResponse, Quantity, TempSalesLineAiSuggestion, SearchPrimaryKeyWords, SearchAdditionalKeyWords); + end; + end; + end; + + local procedure BuildSearchQuery(SearchPrimaryKeyWords: List of [Text]; SearchAdditionalKeyWords: List of [Text]; ItemNameHASH: Text; SearchStyle: Enum "Search Style"; Top: Integer; var ALSearchQuery: DotNet ALSearchQuery) + var + ALSearchMode: DotNet ALSearchMode; + Keyword: Text; + begin + ALSearchQuery := ALSearchQuery.SearchQuery(ItemNameHASH); + + foreach Keyword in SearchPrimaryKeyWords do + ALSearchQuery.AddRequiredTerm(Keyword); + + case SearchStyle of + "Search Style"::Precise: + foreach Keyword in SearchAdditionalKeyWords do + ALSearchQuery.AddRequiredTerm(Keyword); + else + foreach Keyword in SearchAdditionalKeyWords do + ALSearchQuery.AddOptionalTerm(Keyword); + end; + + case SearchStyle of + "Search Style"::Permissive: + ALSearchQuery.Mode := ALSearchMode::Any; + else + ALSearchQuery.Mode := ALSearchMode::All; + end; + + 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]; + var SearchAdditionalKeyWords: List of [Text]) + var + Item: Record "Item"; + LineNumber: Integer; + begin + + if not TempSalesLineAiSuggestion.FindLast() then + LineNumber := 1 + else + LineNumber := TempSalesLineAiSuggestion."Line No."; + + Item.SetLoadFields("No.", "Description", "Base Unit of Measure"); + if TempSearchResponse.FindSet() then + repeat + if Item.GetBySystemId(TempSearchResponse.SysId) then begin + Item.SetRecFilter(); + + TempSalesLineAiSuggestion.Init(); + LineNumber := LineNumber + 1; + TempSalesLineAiSuggestion."Line No." := LineNumber; + TempSalesLineAiSuggestion."No." := Item."No."; + TempSalesLineAiSuggestion.Description := Item.Description; + TempSalesLineAiSuggestion.Type := "Sales Line Type"::Item; + TempSalesLineAiSuggestion.Quantity := Quantity; + TempSalesLineAiSuggestion.Confidence := GetConfidence(TempSearchResponse.Score); + TempSalesLineAiSuggestion.SetPrimarySearchTerms(SearchPrimaryKeyWords); + TempSalesLineAiSuggestion.SetAdditionalSearchTerms(SearchAdditionalKeyWords); + TempSalesLineAiSuggestion.Insert(); + end; + until TempSearchResponse.Next() = 0; + end; + + local procedure GetItemNameKeywords(ItemObjectToken: JsonToken): List of [Text] + var + JsonToken: JsonToken; + JsonArray: JsonArray; + 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 + JsonArray := JsonToken.AsArray(); + foreach JsonToken in JsonArray do + SearchKeyword := SearchKeyword + '|' + JsonToken.AsValue().AsText(); + end; + SearchKeywords.Add(SearchKeyword); + end; + exit(SearchKeywords); + end; + + local procedure GetItemFeaturesKeywords(ItemObjectToken: JsonToken): List of [Text] + var + JsonToken: JsonToken; + JsonArray: JsonArray; + SearchKeywords: List of [Text]; + begin + if ItemObjectToken.AsObject().Get('features', JsonToken) then begin + JsonArray := JsonToken.AsArray(); + foreach JsonToken in JsonArray do + SearchKeywords.Add(JsonToken.AsValue().AsText()); + end; + exit(SearchKeywords); + end; + + local procedure GetConfidence(Score: Decimal): Enum "Search Confidence" + begin + if Score > 80 then + exit("Search Confidence"::High); + if Score > 50 then + exit("Search Confidence"::Medium); + if Score > 20 then + exit("Search Confidence"::Low); + + exit("Search Confidence"::None); + 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 new file mode 100644 index 0000000000..0bf2464a02 --- /dev/null +++ b/Apps/W1/SalesLinesSuggestions/app/Search/SearchAPIResponse.Table.al @@ -0,0 +1,34 @@ +// ------------------------------------------------------------------------------------------------ +// 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; + +table 7276 "Search API Response" +{ + Access = Internal; + TableType = Temporary; + InherentEntitlements = X; + InherentPermissions = X; + + fields + { + field(1; SysId; Guid) + { + DataClassification = SystemMetadata; + } + field(2; Score; Decimal) + { + DataClassification = SystemMetadata; + } + } + + keys + { + key(Key1; SysId) + { + Clustered = true; + } + } + +} \ No newline at end of file diff --git a/Apps/W1/SalesLinesSuggestions/app/Search/SearchConfidence.Enum.al b/Apps/W1/SalesLinesSuggestions/app/Search/SearchConfidence.Enum.al new file mode 100644 index 0000000000..ec1ae8109b --- /dev/null +++ b/Apps/W1/SalesLinesSuggestions/app/Search/SearchConfidence.Enum.al @@ -0,0 +1,24 @@ +// ------------------------------------------------------------------------------------------------ +// 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; + +enum 7276 "Search Confidence" +{ + Access = Internal; + Extensible = false; + + value(0; "None") + { + } + value(1; "Low") + { + } + value(2; "Medium") + { + } + value(3; "High") + { + } +} \ No newline at end of file diff --git a/Apps/W1/SalesLinesSuggestions/app/Search/SearchStyle.Enum.al b/Apps/W1/SalesLinesSuggestions/app/Search/SearchStyle.Enum.al new file mode 100644 index 0000000000..dfe31d4924 --- /dev/null +++ b/Apps/W1/SalesLinesSuggestions/app/Search/SearchStyle.Enum.al @@ -0,0 +1,24 @@ +// ------------------------------------------------------------------------------------------------ +// 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; + +enum 7277 "Search Style" +{ + Access = Internal; + Extensible = false; + + value(0; "Permissive") + { + Caption = 'Permissive'; + } + value(1; "Balanced") + { + Caption = 'Balanced'; + } + value(2; "Precise") + { + Caption = 'Precise'; + } +} \ No newline at end of file diff --git a/Apps/W1/SalesLinesSuggestions/app/Setup/SalesLineSuggestionsInstall.Codeunit.al b/Apps/W1/SalesLinesSuggestions/app/Setup/SalesLineSuggestionsInstall.Codeunit.al new file mode 100644 index 0000000000..08ebb63efe --- /dev/null +++ b/Apps/W1/SalesLinesSuggestions/app/Setup/SalesLineSuggestionsInstall.Codeunit.al @@ -0,0 +1,20 @@ +// ------------------------------------------------------------------------------------------------ +// 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; + +codeunit 7277 "Sales Line Suggestions Install" +{ + Subtype = Install; + InherentPermissions = X; + InherentEntitlements = X; + + trigger OnInstallAppPerCompany() + var + SalesLinesSuggestionsImpl: Codeunit "Sales Lines Suggestions Impl."; + begin + SalesLinesSuggestionsImpl.RegisterCapability(); + end; + +} \ No newline at end of file diff --git a/Apps/W1/SalesLinesSuggestions/app/Setup/SalesLineSuggestionsUpgrade.Codeunit.al b/Apps/W1/SalesLinesSuggestions/app/Setup/SalesLineSuggestionsUpgrade.Codeunit.al new file mode 100644 index 0000000000..2f7bc06d83 --- /dev/null +++ b/Apps/W1/SalesLinesSuggestions/app/Setup/SalesLineSuggestionsUpgrade.Codeunit.al @@ -0,0 +1,37 @@ +// ------------------------------------------------------------------------------------------------ +// 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.Upgrade; + +codeunit 7278 "Sales Line Suggestions Upgrade" +{ + Subtype = Upgrade; + InherentPermissions = X; + InherentEntitlements = X; + + trigger OnUpgradePerDatabase() + begin + RegisterCapability(); + end; + + local procedure RegisterCapability() + var + SalesLinesSuggestionsImpl: Codeunit "Sales Lines Suggestions Impl."; + UpgradeTag: Codeunit "Upgrade Tag"; + begin + if not UpgradeTag.HasUpgradeTag(GetRegisterSalesLinesSuggestionsCapabilityTag()) then begin + SalesLinesSuggestionsImpl.RegisterCapability(); + UpgradeTag.SetUpgradeTag(GetRegisterSalesLinesSuggestionsCapabilityTag()); + end; + end; + + + internal procedure GetRegisterSalesLinesSuggestionsCapabilityTag(): Code[250] + begin + exit('MS-485919-RegisterSalesLinesSuggestionsCapability-20240209'); + end; + +} \ No newline at end of file diff --git a/Apps/W1/SalesLinesSuggestions/app/Setup/SalesLinesCopilotCapability.EnumExt.al b/Apps/W1/SalesLinesSuggestions/app/Setup/SalesLinesCopilotCapability.EnumExt.al new file mode 100644 index 0000000000..b10525f4ea --- /dev/null +++ b/Apps/W1/SalesLinesSuggestions/app/Setup/SalesLinesCopilotCapability.EnumExt.al @@ -0,0 +1,15 @@ +// ------------------------------------------------------------------------------------------------ +// 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; + +enumextension 7275 "Sales Lines Copilot Capability" extends "Copilot Capability" +{ + value(7275; "Sales Lines Suggestions") + { + Caption = 'Sales Lines Suggestions'; + } +} \ No newline at end of file diff --git a/Apps/W1/SalesLinesSuggestions/app/Utilities/NotificationManager.Codeunit.al b/Apps/W1/SalesLinesSuggestions/app/Utilities/NotificationManager.Codeunit.al new file mode 100644 index 0000000000..8d2b4b3395 --- /dev/null +++ b/Apps/W1/SalesLinesSuggestions/app/Utilities/NotificationManager.Codeunit.al @@ -0,0 +1,33 @@ +// ------------------------------------------------------------------------------------------------ +// 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; + +codeunit 7279 "Notification Manager" +{ + Access = Internal; + local procedure GetNotificationId(): Guid + begin + exit('8f3bd624-bac8-4ef2-8555-606e1f534b50'); + end; + + procedure RecallNotification() + var + Notification: Notification; + begin + Notification.Id := GetNotificationId(); + Notification.Recall(); + end; + + procedure SendNotification(NotificationMessage: Text) + var + Notification: Notification; + begin + Notification.Id := GetNotificationId(); + Notification.Scope := NotificationScope::LocalScope; + Notification.Recall(); + Notification.Message := NotificationMessage; + Notification.Send(); + end; +} \ No newline at end of file diff --git a/Apps/W1/SalesLinesSuggestions/app/Utilities/PrepareSalesLineForCopying.Codeunit.al b/Apps/W1/SalesLinesSuggestions/app/Utilities/PrepareSalesLineForCopying.Codeunit.al new file mode 100644 index 0000000000..38c6c98a35 --- /dev/null +++ b/Apps/W1/SalesLinesSuggestions/app/Utilities/PrepareSalesLineForCopying.Codeunit.al @@ -0,0 +1,46 @@ +namespace Microsoft.Sales.Document; +codeunit 7290 "Prepare Sales Line For Copying" +{ + Access = Internal; + InherentEntitlements = X; + InherentPermissions = X; + trigger OnRun() + var + begin + PrepareSalesLine(); + end; + + local procedure PrepareSalesLine() + begin + Clear(TempGlobalPreparedSalesLine); + TempGlobalPreparedSalesLine.Init(); + TempGlobalPreparedSalesLine."Line No." := GlobalLineNo; + TempGlobalPreparedSalesLine."Document No." := GlobalSourceSalesHeader."No."; + TempGlobalPreparedSalesLine."Document Type" := GlobalSourceSalesHeader."Document Type"; + TempGlobalPreparedSalesLine.Type := TempGlobalSalesLineAiSuggestion.Type; + TempGlobalPreparedSalesLine.Validate("No.", TempGlobalSalesLineAiSuggestion."No."); + TempGlobalPreparedSalesLine.Validate(Description, TempGlobalSalesLineAiSuggestion.Description); + if TempGlobalSalesLineAiSuggestion."Variant Code" <> '' then + TempGlobalPreparedSalesLine.Validate("Variant Code", TempGlobalSalesLineAiSuggestion."Variant Code"); + TempGlobalPreparedSalesLine.Validate(Quantity, TempGlobalSalesLineAiSuggestion.Quantity); + TempGlobalPreparedSalesLine.Insert(); + end; + + procedure SetParameters(var SourceSalesHeader: Record "Sales Header"; LineNo: Integer; TempSalesLineAiSuggestion: Record "Sales Line AI Suggestions" temporary) + begin + GlobalSourceSalesHeader := SourceSalesHeader; + GlobalLineNo := LineNo; + TempGlobalSalesLineAiSuggestion := TempSalesLineAiSuggestion; + end; + + procedure GetPreparedLine(): Record "Sales Line" temporary + begin + exit(TempGlobalPreparedSalesLine); + end; + + var + TempGlobalPreparedSalesLine: Record "Sales Line" temporary; + GlobalSourceSalesHeader: Record "Sales Header"; + TempGlobalSalesLineAiSuggestion: Record "Sales Line AI Suggestions" temporary; + GlobalLineNo: Integer; +} \ 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 new file mode 100644 index 0000000000..bf29525c72 --- /dev/null +++ b/Apps/W1/SalesLinesSuggestions/app/Utilities/SalesLineUtility.Codeunit.al @@ -0,0 +1,114 @@ +// ------------------------------------------------------------------------------------------------ +// 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.Telemetry; +using Microsoft.Utilities; + +codeunit 7280 "Sales Line Utility" +{ + Access = Internal; + InherentEntitlements = X; + InherentPermissions = X; + + var + 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'; + 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'; + + procedure CopySalesLineToDoc(SalesHeader: Record "Sales Header"; var TempSalesLineAiSuggestion: Record "Sales Line AI Suggestions" temporary) + var + ToSalesLine: Record "Sales Line"; + TempFromSalesLine: Record "Sales Line" temporary; + LinesNotCopied: Integer; + NextLineNo: Integer; + begin + ToSalesLine.SetRange("Document Type", SalesHeader."Document Type"); + ToSalesLine.SetRange("Document No.", SalesHeader."No."); + + if ToSalesLine.FindLast() then + NextLineNo := ToSalesLine."Line No." + else + NextLineNo := 0; + LinesNotCopied := 0; + + PrepareSalesLine(SalesHeader, TempFromSalesLine, TempSalesLineAiSuggestion, NextLineNo); + CopySalesLineToDoc(SalesHeader, TempFromSalesLine, LinesNotCopied, NextLineNo); + end; + + local procedure CopySalesLineToDoc(var ToSalesHeader: Record "Sales Header"; var FromSalesLine: Record "Sales Line" temporary; var LinesNotCopied: Integer; NextLineNo: Integer) + var + ToSalesLine: Record "Sales Line"; + CopyDocMgt: Codeunit "Copy Document Mgt."; + FeatureTelemetry: Codeunit "Feature Telemetry"; + SalesLineAISuggestionImpl: Codeunit "Sales Lines Suggestions Impl."; + CopyPostedDeferral: Boolean; + ProgressDialog: Dialog; + Counter: Integer; + TotalLines: Integer; + begin + CopyPostedDeferral := false; + if FromSalesLine.FindSet() then begin + OpenProgressWindow(ProgressDialog); + TotalLines := FromSalesLine.Count(); + repeat + if CopyDocMgt.CopySalesDocLine( + ToSalesHeader, ToSalesLine, ToSalesHeader, FromSalesLine, + NextLineNo, LinesNotCopied, false, + "Sales Document Type"::Order, + CopyPostedDeferral, FromSalesLine."Line No.") then + Counter += 1 + else begin + FeatureTelemetry.LogError('0000MMN', SalesLineAISuggestionImpl.GetFeatureName(), 'Copy Sales Lines to Doc', StrSubstNo(SalesLineCopyErr, FromSalesLine."No.", FromSalesLine.Description, FromSalesLine.Quantity), GetLastErrorCallStack()); + Error(SalesLineCopyErr, FromSalesLine."No.", FromSalesLine.Description, FromSalesLine.Quantity); + end; + ProgressDialog.Update(1, StrSubstNo(InsertingSalesLineLbl, Counter, TotalLines)); + until FromSalesLine.Next() = 0; + 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; + PrepareSalesLineForCopying: Codeunit "Prepare Sales Line For Copying"; + SalesLineAISuggestionImpl: Codeunit "Sales Lines Suggestions Impl."; + FeatureTelemetry: Codeunit "Feature Telemetry"; + ProgressDialog: Dialog; + TotalLines: Integer; + Counter: Integer; + begin + if TempSalesLineAiSuggestion.FindSet() then begin + OpenProgressWindow(ProgressDialog); + TotalLines := TempSalesLineAiSuggestion.Count(); + repeat + Counter += 1; + ProgressDialog.Update(1, StrSubstNo(PreparingSalesLineLbl, Counter, TotalLines)); + + LineNo += 10000; + PrepareSalesLineForCopying.SetParameters(SalesHeader, LineNo, TempSalesLineAiSuggestion); + if PrepareSalesLineForCopying.Run() then begin + TempPreparedSalesLine := PrepareSalesLineForCopying.GetPreparedLine(); + TempSalesLine.Init(); + TempSalesLine.TransferFields(TempPreparedSalesLine); + TempSalesLine.Insert(); + end + else begin + FeatureTelemetry.LogError('0000MMM', SalesLineAISuggestionImpl.GetFeatureName(), 'Prepare Sales Lines before inserting', '', GetLastErrorCallStack()); + Error(SalesLineValidationErr, TempSalesLineAiSuggestion."No.", TempSalesLineAiSuggestion.Description, GetLastErrorText()); + end; + until TempSalesLineAiSuggestion.Next() = 0; + ProgressDialog.Close(); + end; + end; + + local procedure OpenProgressWindow(var ProgressDialog: Dialog) + begin + ProgressDialog.Open(ProcessingLinesLbl); + ProgressDialog.Update(1, ''); + end; + +} \ No newline at end of file diff --git a/Apps/W1/SalesLinesSuggestions/app/app.json b/Apps/W1/SalesLinesSuggestions/app/app.json new file mode 100644 index 0000000000..815940a75c --- /dev/null +++ b/Apps/W1/SalesLinesSuggestions/app/app.json @@ -0,0 +1,41 @@ +{ + "id": "dd3f226b-40bf-4b3c-9988-9b1e0f74edd8", + "name": "Sales Lines Suggestions", + "publisher": "Microsoft", + "version": "25.0.0.0", + "brief": "Sales Lines Suggestions (Preview) can assist with creating lines on sales documents such as sales quotes, sales orders, and invoices based on structured input or natural language.", + "description": "Sales Lines Suggestions with Copilot can assist with creating lines on sales documents such as sales quotes, sales orders, and invoices based on structured input or natural language. The Sales lines suggestions is not a general-purpose chat bot, but highly specific and integrated experience available from sales documents and offering two distinct skills. These skills help users find data they are looking for, either individual products or the whole documents.", + "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", + "EULA": "https://go.microsoft.com/fwlink/?linkid=2182906", + "help": "https://go.microsoft.com/fwlink/?linkid=2261665", + "url": "https://go.microsoft.com/fwlink/?LinkId=724011", + "contextSensitiveHelpUrl": "https://go.microsoft.com/fwlink/?linkid=2261665", + "logo": "ExtensionLogo.png", + "dependencies": [], + "screenshots": [], + "platform": "25.0.0.0", + "application": "25.0.0.0", + "target": "OnPrem", + "idRanges": [ + { + "from": 7275, + "to": 7290 + } + ], + "resourceExposurePolicy": { + "allowDebugging": true, + "allowDownloadingSource": true, + "includeSourceInSymbolFile": true + }, + "features": [ + "NoImplicitWith", + "TranslationFile" + ], + "internalsVisibleTo": [ + { + "id": "1defd6cb-5fb9-4717-b50a-9d7f2b59fe88", + "name": "Sales Lines Suggestions Tests", + "publisher": "Microsoft" + } + ] +} \ No newline at end of file diff --git a/Apps/W1/SalesLinesSuggestions/test/DocumentLookupPromptTest.Codeunit.al b/Apps/W1/SalesLinesSuggestions/test/DocumentLookupPromptTest.Codeunit.al new file mode 100644 index 0000000000..ea69df76ec --- /dev/null +++ b/Apps/W1/SalesLinesSuggestions/test/DocumentLookupPromptTest.Codeunit.al @@ -0,0 +1,1215 @@ +namespace Microsoft.Sales.Document.Test; +codeunit 139784 "Document Lookup Prompt Test" +{ + Subtype = Test; + TestPermissions = Disabled; + EventSubscriberInstance = Manual; + + trigger OnRun() + begin + // [FEATURE] [Sales with AI]:[Document Lookup] [Prompt] + end; + + var + // Sales Order + SalesOrderPrompt01Lbl: Label 'Need all the items from previous sales order'; + SalesOrderPrompt02Lbl: Label 'Need all the items from sales order SO12345'; + SalesOrderPrompt03Lbl: Label 'Need 5 loud speaker from sales order'; + SalesOrderPrompt04Lbl: Label 'Need 5 loud speaker from sales order SO12345'; + SalesOrderPrompt05Lbl: Label 'Need all the items from sales order from last week to today'; + SalesOrderPrompt06Lbl: Label 'Need 5 loud speaker from sales order from last week to today'; + SalesOrderPrompt07Lbl: Label 'Need all the items from sales order on 2023-01-01'; + SalesOrderPrompt08Lbl: Label 'Need all the items from sales order on last February 1st'; + // Magic function test: date in future + SalesOrderPrompt09Lbl: Label 'Need all the items from sales order on next week'; + // Magic function test: date in future + SalesOrderPrompt10Lbl: Label 'Need all the items from sales order from last month to next week'; + SalesOrderPrompt11Lbl: Label 'Hi Simon, hope you''re doing well. I was reviewing some of our sales data and realized I need a bit more information. Could you retrieve the top 3 bestselling items from one of our recent sales orders? The order number, if I''m not mistaken, should be 54321. This information will be crucial for our upcoming marketing strategy meeting. Thanks a lot for your help on this!'; + SalesOrderPrompt12Lbl: Label 'Hey there! I need a small favor. Can you select only the blue widgets from sales order 67890? It''s for a client-specific request. Thanks!'; + SalesOrderPrompt13Lbl: Label 'Hello! Quick task: could you list all items exceeding $1000 in value from sales order 13579? It''s important for our high-value sales analysis. Appreciate your help!'; + SalesOrderPrompt14Lbl: Label 'Hi! Can you gather all electronic items from sales orders yesterday? Need to check our electronic goods turnover. Thanks a lot!'; + SalesOrderPrompt15Lbl: Label 'Good day! Please collect all perishable goods from sales order SO24680. We need to ensure they''re processed quickly. Thank you!'; + SalesOrderPrompt16Lbl: Label 'Hello! Quick request: filter out all items under 5 lbs from sales order SO11111 for our lightweight items inventory. Thanks!'; + SalesOrderPrompt17Lbl: Label 'Hi! Can you identify the custom-made items in the sales order from 2023-05-05? It''s for a custom order follow-up. Much appreciated!'; + SalesOrderPrompt18Lbl: Label 'Hey, can you show me the items with warranty from sales orders before last Christmas? Need to review our warranty coverage. Thanks!'; + SalesOrderPrompt19Lbl: Label 'Hi there! Need your help to find all out-of-stock items from sales order SO22222 for restocking purposes. Thanks a bunch!'; + SalesOrderPrompt20Lbl: Label 'Hello! Could you locate all items shipped to New York in sales order SO33333? It''s for a regional sales analysis. Thank you!'; + SalesOrderPrompt21Lbl: Label 'Good day! Please detail the items with serial numbers from the sales order on 2023-02-14 for our inventory records. Thanks!'; + SalesOrderPrompt22Lbl: Label 'Hi! Can you extract all discounted items from sales orders ISOD2012345512? It''s for a discount performance review. Much appreciated!'; + SalesOrderPrompt23Lbl: Label 'Hey there! Need a quick hand isolating fragile items from sales order SO44444 for special packaging. Thanks in advance!'; + SalesOrderPrompt24Lbl: Label 'Hello! Could you do a quick review of items from recent sales orders? Just a general stock check. Thanks!'; + SalesOrderPrompt25Lbl: Label 'Hi! Please highlight all red-colored items from sales order SO55555. It''s for a color trend analysis. Thank you!'; + SalesOrderPrompt26Lbl: Label 'Good day! Can you summarize all items for office use from recent sales orders? Need it for office inventory assessment. Thanks!'; + SalesOrderPrompt27Lbl: Label 'Hey! Can you pinpoint all eco-friendly items from our sales orders? It''s for our sustainability report. Much appreciated!'; + SalesOrderPrompt28Lbl: Label 'Hi there! Please enumerate all bulk items from sales order SO66666. We''re assessing our bulk sales strategy. Thank you!'; + SalesOrderPrompt29Lbl: Label 'Hello! Need a quick list of items with express delivery in sales order SO77777 for our delivery efficiency review. Thanks!'; + SalesOrderPrompt30Lbl: Label 'Hey! Can you assess the items receiving 5-star reviews from our previous sales order? I need them for customer satisfaction analysis. Thanks a lot!'; + + //============================================================================================================== + // Invoice + SalesInvoicePrompt01Lbl: Label 'Need all the items from previous sales invoice'; + SalesInvoicePrompt02Lbl: Label 'Need all the items from sales invoice 12345'; + SalesInvoicePrompt03Lbl: Label 'Need 5 loud speaker from sales invoice'; + SalesInvoicePrompt04Lbl: Label 'Need 5 loud speaker from sales invoice SO12345'; + SalesInvoicePrompt05Lbl: Label 'Need all the items from sales invoice from last week to today'; + SalesInvoicePrompt06Lbl: Label 'Need 5 loud speaker from sales invoice from last week to today'; + SalesInvoicePrompt07Lbl: Label 'Need all the items from sales invoice on 2023-01-01'; + SalesInvoicePrompt08Lbl: Label 'Need all the items from sales invoice on last February 1st'; + // Magic function test: date in future + SalesInvoicePrompt09Lbl: Label 'Need all the items from sales invoice on next week'; + SalesInvoicePrompt10Lbl: Label 'Need all the items from sales invoice from last month to next week'; + SalesInvoicePrompt11Lbl: Label 'Hi team, please retrieve all electronics from sales invoice 54321 for our tech inventory update. Thanks!'; + SalesInvoicePrompt12Lbl: Label 'Hello, can you list all office supplies from sales invoice 67890? We need it for our office supplies audit.'; + SalesInvoicePrompt13Lbl: Label 'Need a quick favor: gather 10 computer monitors from any sales invoice for our new setup. Thanks!'; + SalesInvoicePrompt14Lbl: Label 'Could you find all good quality items from sales invoice INV98765? It''s for a quality check review.'; + SalesInvoicePrompt15Lbl: Label 'Please select all items under $500 from sales invoice 24680 for our budget analysis. Much appreciated!'; + SalesInvoicePrompt16Lbl: Label 'Hi, can you identify perishable goods from our last sales invoice? It''s urgent for our inventory management.'; + SalesInvoicePrompt17Lbl: Label 'Need details of all discounted items from sales invoice dated 2023-03-15 for our discounts effectiveness review.'; + SalesInvoicePrompt18Lbl: Label 'Can you show items for international shipping from sales invoice 13579? It''s for our global shipping logistics.'; + SalesInvoicePrompt19Lbl: Label 'Please detail all custom orders from sales invoice INV11122 for our custom products analysis.'; + SalesInvoicePrompt20Lbl: Label 'Could you summarize items billed to company X from sales invoice INV22233? It''s for our client billing records.'; + SalesInvoicePrompt21Lbl: Label 'Need to isolate high-value items from sales invoice on last Christmas for our annual high-value sales report.'; + SalesInvoicePrompt22Lbl: Label 'Please review all backordered items from sales invoice INV33344. It''s crucial for our stock replenishment plan.'; + SalesInvoicePrompt23Lbl: Label 'Pinpoint items with express delivery from sales invoice INV44455 for our delivery efficiency analysis.'; + SalesInvoicePrompt24Lbl: Label 'Can you check for any damaged goods in sales invoice 55566? We need to process returns or replacements.'; + SalesInvoicePrompt25Lbl: Label 'Assess all items with warranties from sales invoice 66677 for our warranty services update.'; + SalesInvoicePrompt26Lbl: Label 'Could you find all bulk orders from our recent sales invoices? It''s for our bulk orders management review.'; + SalesInvoicePrompt27Lbl: Label 'Catalog all eco-friendly products from sales invoice 77788 for our sustainability report.'; + SalesInvoicePrompt28Lbl: Label 'Please extract all items from sales invoice 88899 for a comprehensive inventory check.'; + SalesInvoicePrompt29Lbl: Label 'Locate all items with overnight shipping from sales invoice 99900 for our expedited delivery analysis.'; + SalesInvoicePrompt30Lbl: Label 'Retrieve all items purchased by VIP clients from sales invoice 00011 for our VIP client relations enhancement.'; + SalesInvoicePrompt31Lbl: Label 'Subject: Request for additional items \nHello,\nI hope this email finds you well. I am writing to you regarding the sales invoice 123456 that you sent me on January 15, 2024. I appreciate your prompt delivery and excellent service.\nHowever, I would like to request some additional items that are related to the ones I purchased from you. Specifically, I am interested in the following products:\n\t- 10 units of Product A (SKU: 789012)\n\t- 5 units of Product B (SKU: 345678)\n\t- 3 units of Product C (SKU: 901234)\nCould you please send me a quote for these items, along with the shipping and handling fees? I would also appreciate it if you could expedite the order, as I need them by February 10, 2024.\nPlease reply to this email with your confirmation and payment details. If you have any questions or concerns, feel free to contact me at any time.\nThank you for your cooperation and attention.\nSincerely,\nYour customer/colleague'; + //============================================================================================================== + // Shipment + SalesShipmentPrompt01Lbl: Label 'Need all the items from previous sales shipment'; + SalesShipmentPrompt02Lbl: Label 'Need all the items from sales shipment SO12345'; + SalesShipmentPrompt03Lbl: Label 'Need 5 loud speaker from sales shipment'; + SalesShipmentPrompt04Lbl: Label 'Need 5 loud speaker from sales shipment SO12345'; + SalesShipmentPrompt05Lbl: Label 'Need all the items from sales shipment from last week to today'; + SalesShipmentPrompt06Lbl: Label 'Need 5 loud speaker from sales shipment from last week to today'; + SalesShipmentPrompt07Lbl: Label 'Need all the items from sales shipment on 2023-01-01'; + SalesShipmentPrompt08Lbl: Label 'Need all the items from sales shipment on last February 1st'; + // Magic function test: date in future + SalesShipmentPrompt09Lbl: Label 'Need all the items from sales shipment on next week'; + SalesShipmentPrompt10Lbl: Label 'Need all the items from sales shipment from last month to next week'; + + SalesShipmentPrompt11Lbl: Label 'Hi team, hope you''re all doing well. Could you kindly list all fragile items from sales shipment 54321? We need to ensure they''re handled with extra care. Thanks a lot!'; + SalesShipmentPrompt12Lbl: Label 'Good morning, I need a quick favor. Can you identify all oversized items from sales shipment 67890? This will help us manage our storage space better. Many thanks!'; + SalesShipmentPrompt13Lbl: Label 'Hello everyone, could someone retrieve 20 office chairs from any of our sales shipments? They are needed urgently for the new conference room setup. Appreciate your help!'; + SalesShipmentPrompt14Lbl: Label 'Hey there, hope your day is going well. Please select items destined for international delivery from shipment SHIP-987651. It''s crucial for our overseas tracking. Thanks!'; + SalesShipmentPrompt15Lbl: Label 'Hi team, can someone find all items in climate-controlled shipping from 2468234320? We need to verify they''re stored correctly for quality assurance. Thanks in advance!'; + SalesShipmentPrompt16Lbl: Label 'Good day, I was wondering if you could detail all rush orders from our recent sales shipments? It''s important for prioritizing our processing queue. Thank you!'; + SalesShipmentPrompt17Lbl: Label 'Hello, can anyone gather all electronic devices from the sales shipment dated 2023-04-10? We need an inventory check for these items. Much appreciated!'; + SalesShipmentPrompt18Lbl: Label 'Hi there, a quick request for you. Could you review all items shipped to California from sales shipment 1354435279? We''re analyzing our regional sales trends. Thanks a bunch!'; + SalesShipmentPrompt19Lbl: Label 'Hey team, please show me all backordered items in shipment SHIP-987651. We need to update our customers on their order statuses. Thanks for your help!'; + SalesShipmentPrompt20Lbl: Label 'Good morning, could someone check for any perishable goods in sales shipment SHIP-987651? We need to ensure they''re shipped promptly to maintain freshness. Thanks!'; + SalesShipmentPrompt21Lbl: Label 'Hi, hope you''re well. Can you isolate items with extended warranties from shipment SHIP-987651? We''re updating our warranty services. Your help is invaluable!'; + SalesShipmentPrompt22Lbl: Label 'Good afternoon, could you catalog all bulk orders from our sales shipment on the 2022 Christmas? It''s for a comprehensive analysis of our holiday sales. Thank you!'; + SalesShipmentPrompt23Lbl: Label 'Hi there, we need a summary of all discounted items from sales shipment 444512315. This will help us review our discount strategies effectively. Can you assist? Thanks!'; + SalesShipmentPrompt24Lbl: Label 'Hello, quick task: please assess items shipped via air freight from shipment SHIP-987651. It''s vital for our logistics efficiency review. Appreciate your efforts!'; + SalesShipmentPrompt25Lbl: Label 'Hey team, can you locate all luxury items from sales shipment 6664312377? We''re tracking our high-end products for a special report. Your swift response would be great!'; + SalesShipmentPrompt26Lbl: Label 'Hi all, could someone pinpoint all items with special handling instructions from shipment 7778123448? It''s crucial to ensure compliance with handling guidelines. Thanks a lot!'; + SalesShipmentPrompt27Lbl: Label 'Good day, I need assistance to extract all items sold to major retailers from shipment 8889911121. It''s part of our retailer sales performance analysis. Your help would be greatly appreciated!'; + SalesShipmentPrompt28Lbl: Label 'Hi, hope you''re having a good day. Please determine all eco-friendly products in sales shipment SHIP-987651 for our sustainability initiatives. Thank you for your attention to this!'; + SalesShipmentPrompt29Lbl: Label 'Hello, a quick request: could you highlight items with delivery delays in shipment SHIP-987651? We need to proactively address any customer concerns. Thanks for your prompt action!'; + SalesShipmentPrompt30Lbl: Label 'Good morning, could you verify all items for express delivery from shipments yesterday? It''s key for assessing our delivery speed. Your quick response is much appreciated!'; + //============================================================================================================== + // Sales Quote + + SalesQuotePrompt01Lbl: Label 'Need all the items from previous sales Quote'; + SalesQuotePrompt02Lbl: Label 'Need all the items from sales Quote SO12345'; + SalesQuotePrompt03Lbl: Label 'Need 5 loud speaker from sales Quote'; + SalesQuotePrompt04Lbl: Label 'Need 5 loud speaker from sales Quote SO12345'; + SalesQuotePrompt05Lbl: Label 'Need all the items from sales Quote from last week to today'; + SalesQuotePrompt06Lbl: Label 'Need 5 loud speaker from sales Quote from last week to today'; + SalesQuotePrompt07Lbl: Label 'Need all the items from sales Quote on 2023-01-01'; + SalesQuotePrompt08Lbl: Label 'Need all the items from sales Quote on last February 1st'; + // Magic function test: date in future + SalesQuotePrompt09Lbl: Label 'Need all the items from sales Quote on next week'; + SalesQuotePrompt10Lbl: Label 'Need all the items from sales Quote from last month to next week'; + SalesQuotePrompt11Lbl: Label 'Hi team, hope you''re all doing well. Could you kindly list all fragile items from sales Quote 54321? We need to ensure they''re handled with extra care. Thanks a lot!'; + SalesQuotePrompt12Lbl: Label 'Good morning, I need a quick favor. Can you identify all oversized items from sales Quote 67890? This will help us manage our storage space better. Many thanks!'; + SalesQuotePrompt13Lbl: Label 'Hello everyone, could someone retrieve 20 office chairs from any of our sales Quotes? They are needed urgently for the new conference room setup. Appreciate your help!'; + SalesQuotePrompt14Lbl: Label 'Hey there, hope your day is going well. Please select items destined for international delivery from Quote 987651. It''s crucial for our overseas tracking. Thanks!'; + SalesQuotePrompt15Lbl: Label 'Hi team, can someone find all items in sales quote 2468234320? We need to verify they''re stored correctly for quality assurance. Thanks in advance!'; + + [Test] + procedure TestGetAllFromSalesOrder01() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesOrderPrompt01Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_order', '', '', ''); + end; + + [Test] + procedure TestGetAllFromSalesOrder02() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesOrderPrompt02Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_order', 'SO12345', '', ''); + end; + + [Test] + procedure TestGetAllFromSalesOrder03() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesOrderPrompt03Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_order', '', '', ''); + end; + + [Test] + procedure TestGetAllFromSalesOrder04() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesOrderPrompt04Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_order', 'SO12345', '', ''); + end; + + [Test] + procedure TestGetAllFromSalesOrder05() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesOrderPrompt05Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_order', '', FORMAT(TODAY - 7, 0, '--'), FORMAT(TODAY, 0, '--')); + end; + + [Test] + procedure TestGetAllFromSalesOrder06() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesOrderPrompt06Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_order', '', FORMAT(TODAY - 7, 0, '--'), FORMAT(TODAY, 0, '--')); + end; + + [Test] + procedure TestGetAllFromSalesOrder07() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesOrderPrompt07Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_order', '', '2023-01-01', '2023-01-01'); + end; + + [Test] + procedure TestGetAllFromSalesOrder08() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + LastFeb01: Text; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesOrderPrompt08Lbl); + if (System.Date2DMY(TODAY(), 2) < 3) then + LastFeb01 := Format(System.Date2DMY(TODAY(), 3) - 1) + '-02-01' + else + LastFeb01 := Format(System.Date2DMY(TODAY(), 3)) + '-02-01'; + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_order', '', LastFeb01, LastFeb01); + end; + + [Test] + procedure TestGetAllFromSalesOrder09() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesOrderPrompt09Lbl); + TestUtil.CheckMagicFunction(CallCompletionAnswerTxt); + end; + + [Test] + procedure TestGetAllFromSalesOrder10() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesOrderPrompt10Lbl); + TestUtil.CheckMagicFunction(CallCompletionAnswerTxt); + end; + + [Test] + procedure TestGetAllFromSalesOrder11() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesOrderPrompt11Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_order', '54321', '', ''); + end; + + [Test] + procedure TestGetAllFromSalesOrder12() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesOrderPrompt12Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_order', '67890', '', ''); + end; + + [Test] + procedure TestGetAllFromSalesOrder13() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesOrderPrompt13Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_order', '13579', '', ''); + end; + + [Test] + procedure TestGetAllFromSalesOrder14() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesOrderPrompt14Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_order', '', FORMAT(TODAY - 1, 0, '--'), FORMAT(TODAY - 1, 0, '--')); + end; + + [Test] + procedure TestGetAllFromSalesOrder15() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesOrderPrompt15Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_order', 'SO24680', '', ''); + end; + + [Test] + procedure TestGetAllFromSalesOrder16() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesOrderPrompt16Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_order', 'SO11111', '', ''); + end; + + [Test] + procedure TestGetAllFromSalesOrder17() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesOrderPrompt17Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_order', '', '2023-05-05', '2023-05-05'); + end; + + [Test] + procedure TestGetAllFromSalesOrder18() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesOrderPrompt18Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_order', '', '', Format(System.Date2DMY(TODAY(), 3) - 1) + '-12-25'); + end; + + [Test] + procedure TestGetAllFromSalesOrder19() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesOrderPrompt19Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_order', 'SO22222', '', ''); + end; + + [Test] + procedure TestGetAllFromSalesOrder20() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesOrderPrompt20Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_order', 'SO33333', '', ''); + end; + + [Test] + procedure TestGetAllFromSalesOrder21() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesOrderPrompt21Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_order', '', '2023-02-14', '2023-02-14'); + end; + + [Test] + procedure TestGetAllFromSalesOrder22() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesOrderPrompt22Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_order', 'ISOD2012345512', '', ''); + end; + + [Test] + procedure TestGetAllFromSalesOrder23() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesOrderPrompt23Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_order', 'SO44444', '', ''); + end; + + [Test] + procedure TestGetAllFromSalesOrder24() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesOrderPrompt24Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_order', '', '', ''); + end; + + [Test] + procedure TestGetAllFromSalesOrder25() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesOrderPrompt25Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_order', 'SO55555', '', ''); + end; + + [Test] + procedure TestGetAllFromSalesOrder26() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesOrderPrompt26Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_order', '', '', ''); + end; + + [Test] + procedure TestGetAllFromSalesOrder27() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesOrderPrompt27Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_order', '', '', ''); + end; + + [Test] + procedure TestGetAllFromSalesOrder28() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesOrderPrompt28Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_order', 'SO66666', '', ''); + end; + + [Test] + procedure TestGetAllFromSalesOrder29() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesOrderPrompt29Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_order', 'SO77777', '', ''); + end; + + [Test] + procedure TestGetAllFromSalesOrder30() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesOrderPrompt30Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_order', '', '', ''); + end; + + [Test] + procedure TestGetAllFromSalesInvoice01() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesInvoicePrompt01Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_invoice', '', '', ''); + end; + + [Test] + procedure TestGetAllFromSalesInvoice02() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesInvoicePrompt02Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_invoice', '12345', '', ''); + end; + + [Test] + procedure TestGetAllFromSalesInvoice03() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesInvoicePrompt03Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_invoice', '', '', ''); + end; + + [Test] + procedure TestGetAllFromSalesInvoice04() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesInvoicePrompt04Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_invoice', 'SO12345', '', ''); + end; + + [Test] + procedure TestGetAllFromSalesInvoice05() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesInvoicePrompt05Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_invoice', '', FORMAT(TODAY - 7, 0, '--'), FORMAT(TODAY, 0, '--')); + end; + + [Test] + procedure TestGetAllFromSalesInvoice06() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesInvoicePrompt06Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_invoice', '', FORMAT(TODAY - 7, 0, '--'), FORMAT(TODAY, 0, '--')); + end; + + [Test] + procedure TestGetAllFromSalesInvoice07() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesInvoicePrompt07Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_invoice', '', '2023-01-01', '2023-01-01'); + end; + + [Test] + procedure TestGetAllFromSalesInvoice08() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + LastFeb01: Text; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesInvoicePrompt08Lbl); + if (System.Date2DMY(TODAY(), 2) < 3) then + LastFeb01 := Format(System.Date2DMY(TODAY(), 3) - 1) + '-02-01' + else + LastFeb01 := Format(System.Date2DMY(TODAY(), 3)) + '-02-01'; + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_invoice', '', LastFeb01, LastFeb01); + end; + + [Test] + procedure TestGetAllFromSalesInvoice09() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesInvoicePrompt09Lbl); + TestUtil.CheckMagicFunction(CallCompletionAnswerTxt); + end; + + [Test] + procedure TestGetAllFromSalesInvoice10() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesInvoicePrompt10Lbl); + TestUtil.CheckMagicFunction(CallCompletionAnswerTxt); + end; + + [Test] + procedure TestGetAllFromSalesInvoice11() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesInvoicePrompt11Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_invoice', '54321', '', ''); + end; + + [Test] + procedure TestGetAllFromSalesInvoice12() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesInvoicePrompt12Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_invoice', '67890', '', ''); + end; + + [Test] + procedure TestGetAllFromSalesInvoice13() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesInvoicePrompt13Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_invoice', '', '', ''); + end; + + [Test] + procedure TestGetAllFromSalesInvoice14() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesInvoicePrompt14Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_invoice', 'INV98765', '', ''); + end; + + [Test] + procedure TestGetAllFromSalesInvoice15() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesInvoicePrompt15Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_invoice', '24680', '', ''); + end; + + [Test] + procedure TestGetAllFromSalesInvoice16() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesInvoicePrompt16Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_invoice', '', '', ''); + end; + + [Test] + procedure TestGetAllFromSalesInvoice17() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesInvoicePrompt17Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_invoice', '', '2023-03-15', '2023-03-15'); + end; + + [Test] + procedure TestGetAllFromSalesInvoice18() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesInvoicePrompt18Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_invoice', '13579', '', ''); + end; + + [Test] + procedure TestGetAllFromSalesInvoice19() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesInvoicePrompt19Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_invoice', 'INV11122', '', ''); + end; + + [Test] + procedure TestGetAllFromSalesInvoice20() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesInvoicePrompt20Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_invoice', 'INV22233', '', ''); + end; + + [Test] + procedure TestGetAllFromSalesInvoice21() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesInvoicePrompt21Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_invoice', '', Format(System.Date2DMY(TODAY(), 3) - 1) + '-12-25', Format(System.Date2DMY(TODAY(), 3) - 1) + '-12-25'); + end; + + [Test] + procedure TestGetAllFromSalesInvoice22() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesInvoicePrompt22Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_invoice', 'INV33344', '', ''); + end; + + [Test] + procedure TestGetAllFromSalesInvoice23() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesInvoicePrompt23Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_invoice', 'INV44455', '', ''); + end; + + [Test] + procedure TestGetAllFromSalesInvoice24() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesInvoicePrompt24Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_invoice', '55566', '', ''); + end; + + [Test] + procedure TestGetAllFromSalesInvoice25() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesInvoicePrompt25Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_invoice', '66677', '', ''); + end; + + [Test] + procedure TestGetAllFromSalesInvoice26() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesInvoicePrompt26Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_invoice', '', '', ''); + end; + + [Test] + procedure TestGetAllFromSalesInvoice27() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesInvoicePrompt27Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_invoice', '77788', '', ''); + end; + + [Test] + procedure TestGetAllFromSalesInvoice28() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesInvoicePrompt28Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_invoice', '88899', '', ''); + + end; + + [Test] + procedure TestGetAllFromSalesInvoice29() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesInvoicePrompt29Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_invoice', '99900', '', ''); + end; + + [Test] + procedure TestGetAllFromSalesInvoice30() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesInvoicePrompt30Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_invoice', '00011', '', ''); + end; + + [Test] + procedure TestGetAllFromSalesInvoice31() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesInvoicePrompt31Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_invoice', '123456', '', ''); + end; + + [Test] + procedure TestGetAllFromSalesShipment01() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesShipmentPrompt01Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_shipment', '', '', ''); + end; + + [Test] + procedure TestGetAllFromSalesShipment02() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesShipmentPrompt02Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_shipment', 'SO12345', '', ''); + end; + + [Test] + procedure TestGetAllFromSalesShipment03() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesShipmentPrompt03Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_shipment', '', '', ''); + end; + + [Test] + procedure TestGetAllFromSalesShipment04() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesShipmentPrompt04Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_shipment', 'SO12345', '', ''); + end; + + [Test] + procedure TestGetAllFromSalesShipment05() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesShipmentPrompt05Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_shipment', '', FORMAT(TODAY - 7, 0, '--'), FORMAT(TODAY, 0, '--')); + end; + + [Test] + procedure TestGetAllFromSalesShipment06() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesShipmentPrompt06Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_shipment', '', FORMAT(TODAY - 7, 0, '--'), FORMAT(TODAY, 0, '--')); + end; + + [Test] + procedure TestGetAllFromSalesShipment07() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesShipmentPrompt07Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_shipment', '', '2023-01-01', '2023-01-01'); + end; + + [Test] + procedure TestGetAllFromSalesShipment08() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + LastFeb01: Text; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesShipmentPrompt08Lbl); + if (System.Date2DMY(TODAY(), 2) < 3) then + LastFeb01 := Format(System.Date2DMY(TODAY(), 3) - 1) + '-02-01' + else + LastFeb01 := Format(System.Date2DMY(TODAY(), 3)) + '-02-01'; + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_shipment', '', LastFeb01, LastFeb01); + end; + + [Test] + procedure TestGetAllFromSalesShipment09() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesShipmentPrompt09Lbl); + TestUtil.CheckMagicFunction(CallCompletionAnswerTxt); + end; + + [Test] + procedure TestGetAllFromSalesShipment10() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesShipmentPrompt10Lbl); + TestUtil.CheckMagicFunction(CallCompletionAnswerTxt); + end; + + procedure TestGetAllFromSalesShipment11() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesShipmentPrompt11Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_shipment', '54321', '', ''); + end; + + [Test] + procedure TestGetAllFromSalesShipment12() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesShipmentPrompt12Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_shipment', '67890', '', ''); + end; + + [Test] + procedure TestGetAllFromSalesShipment13() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesShipmentPrompt13Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_shipment', '', '', ''); + end; + + [Test] + procedure TestGetAllFromSalesShipment14() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesShipmentPrompt14Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_shipment', 'SHIP-987651', '', ''); + end; + + [Test] + procedure TestGetAllFromSalesShipment15() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesShipmentPrompt15Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_shipment', '2468234320', '', ''); + end; + + [Test] + procedure TestGetAllFromSalesShipment16() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesShipmentPrompt16Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_shipment', '', '', ''); + end; + + [Test] + procedure TestGetAllFromSalesShipment17() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesShipmentPrompt17Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_shipment', '', '2023-04-10', '2023-04-10'); + end; + + [Test] + procedure TestGetAllFromSalesShipment18() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesShipmentPrompt18Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_shipment', '1354435279', '', ''); + + end; + + [Test] + procedure TestGetAllFromSalesShipment19() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesShipmentPrompt19Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_shipment', 'SHIP-987651', '', ''); + end; + + [Test] + procedure TestGetAllFromSalesShipment20() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesShipmentPrompt20Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_shipment', 'SHIP-987651', '', ''); + end; + + procedure TestGetAllFromSalesShipment21() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesShipmentPrompt21Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_shipment', 'SHIP-987651', '', ''); + end; + + [Test] + procedure TestGetAllFromSalesShipment22() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesShipmentPrompt22Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_shipment', '', '2022-12-25', '2022-12-25'); + end; + + [Test] + procedure TestGetAllFromSalesShipment23() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesShipmentPrompt23Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_shipment', '444512315', '', ''); + end; + + [Test] + procedure TestGetAllFromSalesShipment24() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesShipmentPrompt24Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_shipment', 'SHIP-987651', '', ''); + end; + + [Test] + procedure TestGetAllFromSalesShipment25() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesShipmentPrompt25Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_shipment', '6664312377', '', ''); + end; + + [Test] + procedure TestGetAllFromSalesShipment26() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesShipmentPrompt26Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_shipment', '7778123448', '', ''); + end; + + [Test] + procedure TestGetAllFromSalesShipment27() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesShipmentPrompt27Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_shipment', '8889911121', '', ''); + end; + + [Test] + procedure TestGetAllFromSalesShipment28() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesShipmentPrompt28Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_shipment', 'SHIP-987651', '', ''); + end; + + [Test] + procedure TestGetAllFromSalesShipment29() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesShipmentPrompt29Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_shipment', 'SHIP-987651', '', ''); + end; + + [Test] + procedure TestGetAllFromSalesShipment30() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesShipmentPrompt30Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_shipment', '', FORMAT(TODAY - 1, 0, '--'), FORMAT(TODAY - 1, 0, '--')); + end; + + [Test] + procedure TestGetAllFromSalesQuote01() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesQuotePrompt01Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_quote', '', '', ''); + end; + + [Test] + procedure TestGetAllFromSalesQuote02() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesQuotePrompt02Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_quote', 'SO12345', '', ''); + end; + + [Test] + procedure TestGetAllFromSalesQuote03() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesQuotePrompt03Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_quote', '', '', ''); + end; + + [Test] + procedure TestGetAllFromSalesQuote04() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesQuotePrompt04Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_quote', 'SO12345', '', ''); + end; + + [Test] + procedure TestGetAllFromSalesQuote05() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesQuotePrompt05Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_quote', '', FORMAT(TODAY - 7, 0, '--'), FORMAT(TODAY, 0, '--')); + end; + + [Test] + procedure TestGetAllFromSalesQuote06() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesQuotePrompt06Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_quote', '', FORMAT(TODAY - 7, 0, '--'), FORMAT(TODAY, 0, '--')); + end; + + [Test] + procedure TestGetAllFromSalesQuote07() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesQuotePrompt07Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_quote', '', '2023-01-01', '2023-01-01'); + end; + + [Test] + procedure TestGetAllFromSalesQuote08() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + LastFeb01: Text; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesQuotePrompt08Lbl); + if (System.Date2DMY(TODAY(), 2) < 3) then + LastFeb01 := Format(System.Date2DMY(TODAY(), 3) - 1) + '-02-01' + else + LastFeb01 := Format(System.Date2DMY(TODAY(), 3)) + '-02-01'; + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_quote', '', LastFeb01, LastFeb01); + end; + + [Test] + procedure TestGetAllFromSalesQuote09() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesQuotePrompt09Lbl); + TestUtil.CheckMagicFunction(CallCompletionAnswerTxt); + end; + + [Test] + procedure TestGetAllFromSalesQuote10() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesQuotePrompt10Lbl); + TestUtil.CheckMagicFunction(CallCompletionAnswerTxt); + end; + + procedure TestGetAllFromSalesQuote11() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesQuotePrompt11Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_quote', '54321', '', ''); + end; + + [Test] + procedure TestGetAllFromSalesQuote12() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesQuotePrompt12Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_quote', '67890', '', ''); + end; + + [Test] + procedure TestGetAllFromSalesQuote13() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesQuotePrompt13Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_quote', '', '', ''); + end; + + [Test] + procedure TestGetAllFromSalesQuote14() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesQuotePrompt14Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_quote', '987651', '', ''); + end; + + [Test] + procedure TestGetAllFromSalesQuote15() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SalesQuotePrompt15Lbl); + TestUtil.CheckDocumentLookupJSONContent(CallCompletionAnswerTxt, 'lookup_from_document', 'sales_quote', '2468234320', '', ''); + end; + +} \ No newline at end of file diff --git a/Apps/W1/SalesLinesSuggestions/test/DocumentLookupTest.Codeunit.al b/Apps/W1/SalesLinesSuggestions/test/DocumentLookupTest.Codeunit.al new file mode 100644 index 0000000000..475062cdfd --- /dev/null +++ b/Apps/W1/SalesLinesSuggestions/test/DocumentLookupTest.Codeunit.al @@ -0,0 +1,2122 @@ +namespace Microsoft.Sales.Document.Test; + +using Microsoft.Inventory.Item; +using Microsoft.Sales.Customer; +using Microsoft.Sales.Document; +using System.TestLibraries.Utilities; + +codeunit 139783 "Document Lookup Test" +{ + Subtype = Test; + TestPermissions = Disabled; + EventSubscriberInstance = Manual; + + trigger OnRun() + begin + // [FEATURE] [Sales with AI]:[Document Lookup] + end; + + var + Assert: Codeunit Assert; + LibraryVariableStorage: Codeunit "Library - Variable Storage"; + LibraryInventory: Codeunit "Library - Inventory"; + LibrarySales: Codeunit "Library - Sales"; + + Item1DescriptionLbl: Label 'High Quality Mouse Mat'; + Item2DescriptionLbl: Label 'Yoga Mat'; + Item3DescriptionLbl: Label 'Model Tool Kit'; + + Item4DescriptionLbl: Label 'Mobile Phone Holder'; + NeedAllItemFromSpecifiedSalesOrderLbl: Label 'I need all items from sales order %1', Comment = '%1 = Label for document number'; + NeedAllItemFromSpecifiedSalesInvoiceLbl: Label 'I need all items from sales Invoice %1', Comment = '%1 =Label for document number'; + NeedAllItemFromSpecifiedSalesShipmentLbl: Label 'I need all items from sales Shipment %1', Comment = '%1 =Label for document number'; + NeedAllItemFromSpecifiedSalesQuoteLbl: Label 'I need all items from sales quote %1', Comment = '%1 =Label for document number'; + NeedAllItemFromUnknownDocumentLbl: Label 'I need 40 keyboards from the latest unknown document'; + + DescriptionIsIncorrectErr: Label 'Description is incorrect!'; + VariantIsIncorrectErr: Label 'Variant is incorrect!'; + QuantityIsIncorrectErr: Label 'Quantity is incorrect!'; + UoMIsIncorrectErr: Label 'Unit of Measure is incorrect!'; + UnknownDocTypeErr: Label 'Copilot does not support the specified document type. Please rephrase the description'; + CannotFindDocumentErr: Label 'Copilot could not find the requested Sales Order %1. Please rephrase the description and try again.', Comment = '%1 =Label for document number'; + // -------------------------------------------------------------------------------------- + // Corner cases + + [Test] + [HandlerFunctions('CheckNothingGeneratedFromSalesOrder,SendNotificationHandler')] + procedure TestCopySalesOrderWithNoExceedingMaxLen() + var + Customer: Record Customer; + SalesHeader: Record "Sales Header"; + SalesLine: Record "Sales Line"; + CreatedItem: Record Item; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + begin + // [FEATURE] [Sales Line with AI] [Document Lookup] [Sales Order] + // [SCENARIO] When user try to copy sales order with a document No exceeding max acceptable length, the system should not generate any lines and send a notification to the user. + LibraryVariableStorage.Clear(); + LibrarySales.CreateCustomer(Customer); + // [GIVEN] Create a new sales order for the new customer + LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Order, Customer."No."); + // [GIVEN] Create 3 lines with item description and add it to the new sales order + Create3SalesLinesWithItemDescription(SalesHeader, SalesLine, CreatedItem); + // [GIVEN] Generate prompt with Document No. + LibraryVariableStorage.Enqueue(StrSubstNo(NeedAllItemFromSpecifiedSalesOrderLbl, '123456789123456789123456789123456789123456789123456789123456789')); + LibraryVariableStorage.Enqueue(StrSubstNo(CannotFindDocumentErr, '123456789123456789123456789123456789123456789123456789123456789')); + // [WHEN] Create a new sales order for this customer and run Sales Line AI Suggestions Page to generate suggestions lines + // [THEN] Check that no sales lines are generated in 'CheckNothingGeneratedFromSalesOrder' handler function + // [THEN] Check the error message in 'SendNotificationHandler' handler function + CreateNewSalesHeaderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions, Customer."No.", SalesHeader."Document Type"::Order); + // [THEN] Check no sales lines are inserted to this document + CheckSalesLineContent(SalesLine, SalesHeader."No."); + end; + + [Test] + [HandlerFunctions('CheckGenerateFromSalesOrder')] + procedure TestCopySalesOrderWithItemVariant() + var + Customer: Record Customer; + SalesHeader: Record "Sales Header"; + SalesLine: Record "Sales Line"; + CreatedItem: Record Item; + ItemVariant: Record "Item Variant"; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + VariantCode: Code[10]; + begin + // [FEATURE] [Sales Line with AI] [Document Lookup] [Sales Order] + // [SCENARIO] When copying a sales order, the item variant should also be copied. + LibraryVariableStorage.Clear(); + LibrarySales.CreateCustomer(Customer); + // [GIVEN] Create a new sales order for the new customer + LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Order, Customer."No."); + // [GIVEN] Create Item and Item Variant + LibrarySales.CreateSimpleItemSalesLine(SalesLine, SalesHeader, "Sales Line Type"::Item); + LibraryInventory.CreateItem(CreatedItem); + VariantCode := LibraryInventory.CreateItemVariant(ItemVariant, CreatedItem."No."); + CreatedItem.Validate(Description, Item1DescriptionLbl); + CreatedItem.Modify(true); + SalesLine.Validate("No.", CreatedItem."No."); + SalesLine.Validate(Quantity, 5); + SalesLine.Validate("Variant Code", VariantCode); + SalesLine.Modify(true); + + // [GIVEN] Generate prompt with Document No. + LibraryVariableStorage.Enqueue(StrSubstNo(NeedAllItemFromSpecifiedSalesOrderLbl, SalesHeader."No.")); + LibraryVariableStorage.Enqueue('1'); + EnqueueItemWithVariantCode(VariantCode, '5'); + EnqueueItemWithVariantCode(VariantCode, '5'); + // [WHEN] Create a new sales order for this customer and run Sales Line AI Suggestions Page to generate suggestions lines + // [THEN] Check that correct lines are generated in 'CheckGenerateFromSalesOrder' handler function + CreateNewSalesHeaderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions, Customer."No.", SalesHeader."Document Type"::Order); + // [THEN] Check the correct sales lines are inserted + CheckSalesLineContent(SalesLine, SalesHeader."No."); + end; + + [Test] + [HandlerFunctions('CheckGenerateFromSalesOrder')] + procedure TestCopySalesOrderWithSalesBlockedItem() + var + Customer: Record Customer; + SalesHeader: Record "Sales Header"; + SalesLine: Record "Sales Line"; + CreatedItem: Record Item; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + begin + // [FEATURE] [Sales Line with AI] [Document Lookup] [Sales Order] + // [SCENARIO] There are 2 lines in the sales order. The second line are blocked. The system should generate only the first line. + LibraryVariableStorage.Clear(); + LibrarySales.CreateCustomer(Customer); + // [GIVEN] Create a new sales order for the new customer + LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Order, Customer."No."); + // [GIVEN] Create a new item1 and add it to the new sales order + CreateSalesLinesWithItem1(SalesHeader, SalesLine, CreatedItem); + // [GIVEN] Create a new item4 with SalesBlock = true, and add it to the new sales order + CreateSalesLinesWithItem4AndSalesBlock(SalesHeader, SalesLine, CreatedItem); + LibraryVariableStorage.Enqueue(StrSubstNo(NeedAllItemFromSpecifiedSalesOrderLbl, SalesHeader."No.")); + LibraryVariableStorage.Enqueue('1'); + EnqueueItem1(); + EnqueueItem1(); + // [WHEN] Create a new sales order for this customer and run Sales Line AI Suggestions Page to generate suggestions lines + // [THEN] Only Item1 is not blocked, hence only 1 line should be generated are generated. Check it in 'CheckGenerateFromSalesOrder' handler function + CreateNewSalesHeaderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions, Customer."No.", SalesHeader."Document Type"::Order); + // [THEN] Check only 1 line is inserted + CheckSalesLineContent(SalesLine, SalesHeader."No."); + end; + + [Test] + [HandlerFunctions('CheckGenerateFromSalesOrder')] + procedure TestCopySalesOrderWithUoMItem() + var + Customer: Record Customer; + SalesHeader: Record "Sales Header"; + SalesLine: Record "Sales Line"; + CreatedItem: Record Item; + ItemUoM: Record "Item Unit of Measure"; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + begin + // [FEATURE] [Sales Line with AI] [Document Lookup] [Sales Order] + // [SCENARIO] We have one item with a new UoM. When copying a sales order, the item UoM should be set to the default one defined in item. + LibraryVariableStorage.Clear(); + LibrarySales.CreateCustomer(Customer); + // [GIVEN] Create a new sales order for the new customer + LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Order, Customer."No."); + // [GIVEN] Create a new item1 and add it to the new sales order + CreateSalesLinesWithItem1AndUoM(ItemUoM, SalesHeader, SalesLine, CreatedItem); + LibraryVariableStorage.Enqueue(StrSubstNo(NeedAllItemFromSpecifiedSalesOrderLbl, SalesHeader."No.")); + LibraryVariableStorage.Enqueue('1'); + EnqueueItem1(); + EnqueueItem1WithUoM(CreatedItem."Base Unit of Measure"); + // [WHEN] Create a new sales order for this customer and run Sales Line AI Suggestions Page to generate suggestions lines + // [THEN] One line is generated. Check it in 'CheckGenerateFromSalesOrder' handler function + CreateNewSalesHeaderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions, Customer."No.", SalesHeader."Document Type"::Order); + // [THEN] After inserting, check the UoM is set to the default one defined in item + CheckSalesLineContentWithUoM(SalesLine, SalesHeader."No."); + end; + + // -------------------------------------------------------------------------------------- + // Test cases for Sales Order + [Test] + [HandlerFunctions('CheckGenerateFromSalesOrder')] + procedure TestCopySalesOrderByDocNo() + var + Customer: Record Customer; + SalesHeader: Record "Sales Header"; + SalesLine: Record "Sales Line"; + CreatedItem: Record Item; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + begin + // [FEATURE] [Sales Line with AI] [Document Lookup] [Sales Order] + // [SCENARIO] User input 'I want all the items from sales order 10000' in current customer's sales order. System will find the order and copy all the lines to the current sales order. + LibraryVariableStorage.Clear(); + LibrarySales.CreateCustomer(Customer); + // [GIVEN] Create a new sales order for the new customer + LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Order, Customer."No."); + // [GIVEN] Create 3 lines with item description and add it to the new sales order + Create3SalesLinesWithItemDescription(SalesHeader, SalesLine, CreatedItem); + LibraryVariableStorage.Enqueue(StrSubstNo(NeedAllItemFromSpecifiedSalesOrderLbl, SalesHeader."No.")); + LibraryVariableStorage.Enqueue('3'); + Enqueue3SalesLineWithItemDescription(); + Enqueue3SalesLineWithItemDescription(); + // [WHEN] Create a new sales order for this customer and run Sales Line AI Suggestions Page to generate suggestions lines + // [THEN] Check that correct lines are generated in 'CheckGenerateFromSalesOrder' handler function + CreateNewSalesHeaderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions, Customer."No.", SalesHeader."Document Type"::Order); + // [THEN] Check all the 3 lines are inserted + CheckSalesLineContent(SalesLine, SalesHeader."No."); + end; + + [Test] + [HandlerFunctions('CheckGenerateFromSalesOrder')] + procedure TestCopySalesOrderByDocNoFromDifferentCustomer() + var + Customer: Record Customer; + Customer2: Record Customer; + SalesHeader: Record "Sales Header"; + SalesLine: Record "Sales Line"; + CreatedItem: Record Item; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + begin + // [FEATURE] [Sales Line with AI] [Document Lookup] [Sales Order] + // [SCENARIO] User input 'I want all the items from sales order 10000' in another customer's sales order. The system should generate 3 lines with item description and quantity. + LibraryVariableStorage.Clear(); + LibrarySales.CreateCustomer(Customer); + LibrarySales.CreateCustomer(Customer2); + // [GIVEN] Create a new sales order for the new customer + LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Order, Customer."No."); + // [GIVEN] Create 3 lines with item description and add it to the new sales order + Create3SalesLinesWithItemDescription(SalesHeader, SalesLine, CreatedItem); + LibraryVariableStorage.Enqueue(StrSubstNo(NeedAllItemFromSpecifiedSalesOrderLbl, SalesHeader."No.")); + LibraryVariableStorage.Enqueue('3'); + Enqueue3SalesLineWithItemDescription(); + Enqueue3SalesLineWithItemDescription(); + // [WHEN] Create a new sales order for this customer and run Sales Line AI Suggestions Page to generate suggestions lines + // [THEN] Check that correct lines are generated in 'CheckGenerateFromSalesOrder' handler function + CreateNewSalesHeaderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions, Customer2."No.", SalesHeader."Document Type"::Order); + // [THEN] Check all the 3 lines are inserted + CheckSalesLineContent(SalesLine, SalesHeader."No."); + end; + + [Test] + [HandlerFunctions('CheckGenerateFromSalesOrder')] + procedure TestCopySalesOrderByExternalDocumentNo() + var + Customer: Record Customer; + Customer2: Record Customer; + SalesHeader: Record "Sales Header"; + SalesLine: Record "Sales Line"; + CreatedItem: Record Item; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + begin + // [FEATURE] [Sales Line with AI] [Document Lookup] [Sales Order] + // [SCENARIO] User input 'I want all the items from sales order EXTNO123456789123456789123456789123' in another customer's sales order. The system should generate 3 lines with item description and quantity. + LibraryVariableStorage.Clear(); + LibrarySales.CreateCustomer(Customer); + LibrarySales.CreateCustomer(Customer2); + // [GIVEN] Create a new sales order for the new customer + LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Order, Customer."No."); + // [GIVEN] Update External Document No. + SalesHeader.Validate("External Document No.", 'EXTNO123456789123456789123456789123'); + SalesHeader.Modify(true); + // [GIVEN] Create 3 lines with item description and add it to the new sales order + Create3SalesLinesWithItemDescription(SalesHeader, SalesLine, CreatedItem); + LibraryVariableStorage.Enqueue(StrSubstNo(NeedAllItemFromSpecifiedSalesOrderLbl, SalesHeader."External Document No.")); + LibraryVariableStorage.Enqueue('3'); + Enqueue3SalesLineWithItemDescription(); + Enqueue3SalesLineWithItemDescription(); + // [WHEN] Create a new sales order for this customer and run Sales Line AI Suggestions Page to generate suggestions lines + // [THEN] Check that correct lines are generated in 'CheckGenerateFromSalesOrder' handler function + CreateNewSalesHeaderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions, Customer2."No.", SalesHeader."Document Type"::Order); + // [THEN] Check all the 3 lines are inserted + CheckSalesLineContent(SalesLine, SalesHeader."No."); + end; + + [Test] + [HandlerFunctions('CheckGenerateFromSalesOrder')] + procedure TestCopySalesOrderByQuoteNo() + var + Customer: Record Customer; + Customer2: Record Customer; + SalesHeader: Record "Sales Header"; + SalesLine: Record "Sales Line"; + CreatedItem: Record Item; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + begin + // [FEATURE] [Sales Line with AI] [Document Lookup] [Sales Order] + // [SCENARIO] User input 'I want all the items from sales order QTO214500' in another customer's sales order. The system should generate 3 lines with item description and quantity. + LibraryVariableStorage.Clear(); + LibrarySales.CreateCustomer(Customer); + LibrarySales.CreateCustomer(Customer2); + // [GIVEN] Create a new sales order for the new customer + LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Order, Customer."No."); + // [GIVEN] Update Quote No. + SalesHeader.Validate("Quote No.", 'QTO214500'); + SalesHeader.Modify(true); + // [GIVEN] Create 3 lines with item description and add it to the new sales order + Create3SalesLinesWithItemDescription(SalesHeader, SalesLine, CreatedItem); + LibraryVariableStorage.Enqueue(StrSubstNo(NeedAllItemFromSpecifiedSalesOrderLbl, SalesHeader."Quote No.")); + LibraryVariableStorage.Enqueue('3'); + Enqueue3SalesLineWithItemDescription(); + Enqueue3SalesLineWithItemDescription(); + // [WHEN] Create a new sales order for this customer and run Sales Line AI Suggestions Page to generate suggestions lines + // [THEN] Check that correct lines are generated in 'CheckGenerateFromSalesOrder' handler function + CreateNewSalesHeaderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions, Customer2."No.", SalesHeader."Document Type"::Order); + // [THEN] Check all the 3 lines are inserted + CheckSalesLineContent(SalesLine, SalesHeader."No."); + end; + + [Test] + [HandlerFunctions('CheckGenerateFromSalesOrder')] + procedure TestCopySalesOrderByReferenceNo() + var + Customer: Record Customer; + Customer2: Record Customer; + SalesHeader: Record "Sales Header"; + SalesLine: Record "Sales Line"; + CreatedItem: Record Item; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + begin + // [FEATURE] [Sales Line with AI] [Document Lookup] [Sales Order] + // [SCENARIO] User input 'I want all the items from sales order REF214500' in another customer's sales order. The system should generate 3 lines with item description and quantity. + LibraryVariableStorage.Clear(); + LibrarySales.CreateCustomer(Customer); + LibrarySales.CreateCustomer(Customer2); + // [GIVEN] Create a new sales order for the new customer + LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Order, Customer."No."); + // [GIVEN] Update Your Reference No. + SalesHeader.Validate("Your Reference", 'REF214500'); + SalesHeader.Modify(true); + // [GIVEN] Create 3 lines with item description and add it to the new sales order + Create3SalesLinesWithItemDescription(SalesHeader, SalesLine, CreatedItem); + LibraryVariableStorage.Enqueue(StrSubstNo(NeedAllItemFromSpecifiedSalesOrderLbl, SalesHeader."Your Reference")); + LibraryVariableStorage.Enqueue('3'); + Enqueue3SalesLineWithItemDescription(); + Enqueue3SalesLineWithItemDescription(); + // [WHEN] Create a new sales order for this customer and run Sales Line AI Suggestions Page to generate suggestions lines + // [THEN] Check that correct lines are generated in 'CheckGenerateFromSalesOrder' handler function + CreateNewSalesHeaderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions, Customer2."No.", SalesHeader."Document Type"::Order); + // [THEN] Check all the 3 lines are inserted + CheckSalesLineContent(SalesLine, SalesHeader."No."); + end; + + [Test] + [HandlerFunctions('CheckGenerateFromSalesOrder')] + procedure TestAmbiguouslyCopySalesOrderByExternalDocumentNo() + var + Customer: Record Customer; + Customer2: Record Customer; + SalesHeader: Record "Sales Header"; + SalesLine: Record "Sales Line"; + CreatedItem: Record Item; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + begin + // [FEATURE] [Sales Line with AI] [Document Lookup] [Sales Order] + // [SCENARIO] User input 'I want all the items from sales order EXTNO123456789123456789123456789123' in another customer's sales order. The system should generate 3 lines with item description and quantity. + LibraryVariableStorage.Clear(); + LibrarySales.CreateCustomer(Customer); + LibrarySales.CreateCustomer(Customer2); + // [GIVEN] Create a new sales order for the new customer + LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Order, Customer."No."); + // Update External Document No. + SalesHeader.Validate("External Document No.", 'EXTNO123456789123456789123456789123'); + SalesHeader.Modify(true); + // [GIVEN] Create 3 lines with item description and add it to the new sales order + Create3SalesLinesWithItemDescription(SalesHeader, SalesLine, CreatedItem); + LibraryVariableStorage.Enqueue(StrSubstNo(NeedAllItemFromSpecifiedSalesOrderLbl, CopyStr(SalesHeader."External Document No.", 2, StrLen(SalesHeader."External Document No.") - 1))); + LibraryVariableStorage.Enqueue('3'); + Enqueue3SalesLineWithItemDescription(); + Enqueue3SalesLineWithItemDescription(); + // [WHEN] Create a new sales order for this customer and run Sales Line AI Suggestions Page to generate suggestions lines + // [THEN] Check that correct lines are generated in 'CheckGenerateFromSalesOrder' handler function + CreateNewSalesHeaderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions, Customer2."No.", SalesHeader."Document Type"::Order); + // [THEN] Check all the 3 lines are inserted + CheckSalesLineContent(SalesLine, SalesHeader."No."); + end; + + [Test] + [HandlerFunctions('CheckGenerateFromSalesOrder')] + procedure TestAmbiguouslyCopySalesOrderByQuoteNo() + var + Customer: Record Customer; + Customer2: Record Customer; + SalesHeader: Record "Sales Header"; + SalesLine: Record "Sales Line"; + CreatedItem: Record Item; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + begin + // [FEATURE] [Sales Line with AI] [Document Lookup] [Sales Order] [Ambiguous Search] + // [SCENARIO] There is an item with Reference Number 'EXTNO123456789123456789123456789123'. User input 'I want all the items from sales order XTNO12345678912345678912345678912' in another customer's sales order. The system should generate 3 lines with item description and quantity. + LibraryVariableStorage.Clear(); + LibrarySales.CreateCustomer(Customer); + LibrarySales.CreateCustomer(Customer2); + // [GIVEN] Create a new sales order for the new customer + LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Order, Customer."No."); + SalesHeader.Validate("Quote No.", 'QTO214500'); + SalesHeader.Modify(true); + // [GIVEN] Create 3 lines with item description and add it to the new sales order + Create3SalesLinesWithItemDescription(SalesHeader, SalesLine, CreatedItem); + // [GIVEN] Remove the first and last character from the Quote No. + LibraryVariableStorage.Enqueue(StrSubstNo(NeedAllItemFromSpecifiedSalesOrderLbl, CopyStr(SalesHeader."Quote No.", 2, StrLen(SalesHeader."Quote No.") - 1))); + LibraryVariableStorage.Enqueue('3'); + Enqueue3SalesLineWithItemDescription(); + Enqueue3SalesLineWithItemDescription(); + // [WHEN] Create a new sales order for this customer and run Sales Line AI Suggestions Page to generate suggestions lines + // [THEN] Check that correct lines are generated in 'CheckGenerateFromSalesOrder' handler function + CreateNewSalesHeaderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions, Customer2."No.", SalesHeader."Document Type"::Order); + // [THEN] Check all the 3 lines are inserted + CheckSalesLineContent(SalesLine, SalesHeader."No."); + end; + + [Test] + [HandlerFunctions('CheckGenerateFromSalesOrder')] + procedure TestAmbiguouslyCopySalesOrderByReferenceNo() + var + Customer: Record Customer; + Customer2: Record Customer; + SalesHeader: Record "Sales Header"; + SalesLine: Record "Sales Line"; + CreatedItem: Record Item; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + begin + // [FEATURE] [Sales Line with AI] [Document Lookup] [Sales Order] [Ambiguous Search] + // [SCENARIO] There is an item with Reference Number 'REF214500'. User input 'I want all the items from sales order EF214500' in another customer's sales order. The system should generate 3 lines with item description and quantity. + LibraryVariableStorage.Clear(); + LibrarySales.CreateCustomer(Customer); + LibrarySales.CreateCustomer(Customer2); + // [GIVEN] Create a new sales order for the new customer + LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Order, Customer."No."); + SalesHeader.Validate("Your Reference", 'REF214500'); + SalesHeader.Modify(true); + // [GIVEN] Create 3 lines with item description and add it to the new sales order + Create3SalesLinesWithItemDescription(SalesHeader, SalesLine, CreatedItem); + // [GIVEN] Remove the first and last character from the Your Reference No. + LibraryVariableStorage.Enqueue(StrSubstNo(NeedAllItemFromSpecifiedSalesOrderLbl, CopyStr(SalesHeader."Your Reference", 2, StrLen(SalesHeader."Your Reference") - 1))); + LibraryVariableStorage.Enqueue('3'); + Enqueue3SalesLineWithItemDescription(); + Enqueue3SalesLineWithItemDescription(); + // [WHEN] Create a new sales order for this customer and run Sales Line AI Suggestions Page to generate suggestions lines + // [THEN] Check that correct lines are generated in 'CheckGenerateFromSalesOrder' handler function + CreateNewSalesHeaderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions, Customer2."No.", SalesHeader."Document Type"::Order); + // [THEN] Check all the 3 lines are inserted + CheckSalesLineContent(SalesLine, SalesHeader."No."); + end; + + [Test] + [HandlerFunctions('CheckGenerateFromSalesOrder')] + procedure TestCopySalesOrderByDate1() + var + Customer: Record Customer; + SalesHeader: Record "Sales Header"; + SalesLine: Record "Sales Line"; + CreatedItem: Record Item; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + StartDate: Date; + begin + // [FEATURE] [Sales Line with AI] [Document Lookup] [Sales Order] + // [SCENARIO] User input 'I want all the items from sales order with posting date 01/01/2019' in current customer's sales order. System will find the order and copy all the lines to the current sales order. + LibraryVariableStorage.Clear(); + LibrarySales.CreateCustomer(Customer); + // [GIVEN] Create a new sales order for the new customer + LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Order, Customer."No."); + Evaluate(StartDate, '01/01/2019'); + SalesHeader.Validate("Posting Date", StartDate); + SalesHeader.Modify(true); + // [GIVEN] Create 3 lines with item description and add it to the new sales order + Create3SalesLinesWithItemDescription(SalesHeader, SalesLine, CreatedItem); + LibraryVariableStorage.Enqueue('I need all items from sales order with posting date 01/01/2019'); + LibraryVariableStorage.Enqueue('3'); + Enqueue3SalesLineWithItemDescription(); + Enqueue3SalesLineWithItemDescription(); + // [WHEN] Create a new sales order for this customer and run Sales Line AI Suggestions Page to generate suggestions lines + // [THEN] Check that correct lines are generated in 'CheckGenerateFromSalesOrder' handler function + CreateNewSalesHeaderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions, Customer."No.", SalesHeader."Document Type"::Order); + // [THEN] Check all the 3 lines are inserted + CheckSalesLineContent(SalesLine, SalesHeader."No."); + end; + + [Test] + [HandlerFunctions('CheckGenerateFromSalesOrder')] + procedure TestCopySalesOrderByDateWithStyle1() + var + Customer: Record Customer; + SalesHeader: Record "Sales Header"; + SalesLine: Record "Sales Line"; + CreatedItem: Record Item; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + StartDate: Date; + begin + // [FEATURE] [Sales Line with AI] [Document Lookup] [Sales Order] + // [SCENARIO] User input 'I want all the items from sales order with posting date 2019 1 1' in current customer's sales order. System will find the order and copy all the lines to the current sales order. + LibraryVariableStorage.Clear(); + LibrarySales.CreateCustomer(Customer); + // [GIVEN] Create a new sales order for the new customer + LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Order, Customer."No."); + Evaluate(StartDate, '01/01/2019'); + SalesHeader.Validate("Posting Date", StartDate); + SalesHeader.Modify(true); + // [GIVEN] Create 3 lines with item description and add it to the new sales order + Create3SalesLinesWithItemDescription(SalesHeader, SalesLine, CreatedItem); + LibraryVariableStorage.Enqueue('I need all items from sales order with posting date 2019 1 1'); + LibraryVariableStorage.Enqueue('3'); + Enqueue3SalesLineWithItemDescription(); + Enqueue3SalesLineWithItemDescription(); + // [WHEN] Create a new sales order for this customer and run Sales Line AI Suggestions Page to generate suggestions lines + // [THEN] Check that correct lines are generated in 'CheckGenerateFromSalesOrder' handler function + CreateNewSalesHeaderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions, Customer."No.", SalesHeader."Document Type"::Order); + // [THEN] Check all the 3 lines are inserted + CheckSalesLineContent(SalesLine, SalesHeader."No."); + end; + + [Test] + [HandlerFunctions('CheckGenerateFromSalesOrder')] + procedure TestCopySalesOrderByDateWithStyle2() + var + Customer: Record Customer; + SalesHeader: Record "Sales Header"; + SalesLine: Record "Sales Line"; + CreatedItem: Record Item; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + StartDate: Date; + begin + // [FEATURE] [Sales Line with AI] [Document Lookup] [Sales Order] + // [SCENARIO] User input 'I want all the items from sales order with posting date 2019 1 Jan' in current customer's sales order. System will find the order and copy all the lines to the current sales order. + LibraryVariableStorage.Clear(); + LibrarySales.CreateCustomer(Customer); + // [GIVEN] Create a new sales order for the new customer + LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Order, Customer."No."); + Evaluate(StartDate, '01/01/2019'); + SalesHeader.Validate("Posting Date", StartDate); + SalesHeader.Modify(true); + // [GIVEN] Create 3 lines with item description and add it to the new sales order + Create3SalesLinesWithItemDescription(SalesHeader, SalesLine, CreatedItem); + LibraryVariableStorage.Enqueue('I need all items from sales order with posting date 2019 1 Jan'); + LibraryVariableStorage.Enqueue('3'); + Enqueue3SalesLineWithItemDescription(); + Enqueue3SalesLineWithItemDescription(); + // [WHEN] Create a new sales order for this customer and run Sales Line AI Suggestions Page to generate suggestions lines + // [THEN] Check that correct lines are generated in 'CheckGenerateFromSalesOrder' handler function + CreateNewSalesHeaderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions, Customer."No.", SalesHeader."Document Type"::Order); + // [THEN] Check all the 3 lines are inserted + CheckSalesLineContent(SalesLine, SalesHeader."No."); + end; + + [Test] + [HandlerFunctions('CheckGenerateFromSalesOrder')] + procedure TestCopySalesOrderByDateWithStyle3() + var + Customer: Record Customer; + SalesHeader: Record "Sales Header"; + SalesLine: Record "Sales Line"; + CreatedItem: Record Item; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + StartDate: Date; + begin + // [FEATURE] [Sales Line with AI] [Document Lookup] [Sales Order] + // [SCENARIO] User input 'I want all the items from sales order with posting date 1/Jan/2019' in current customer's sales order. System will find the order and copy all the lines to the current sales order. + LibraryVariableStorage.Clear(); + LibrarySales.CreateCustomer(Customer); + // [GIVEN] Create a new sales order for the new customer + LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Order, Customer."No."); + Evaluate(StartDate, '01/01/2019'); + SalesHeader.Validate("Posting Date", StartDate); + SalesHeader.Modify(true); + // [GIVEN] Create 3 lines with item description and add it to the new sales order + Create3SalesLinesWithItemDescription(SalesHeader, SalesLine, CreatedItem); + LibraryVariableStorage.Enqueue('I need all items from sales order with posting date 1/Jan/2019'); + LibraryVariableStorage.Enqueue('3'); + Enqueue3SalesLineWithItemDescription(); + Enqueue3SalesLineWithItemDescription(); + // [WHEN] Create a new sales order for this customer and run Sales Line AI Suggestions Page to generate suggestions lines + // [THEN] Check that correct lines are generated in 'CheckGenerateFromSalesOrder' handler function + CreateNewSalesHeaderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions, Customer."No.", SalesHeader."Document Type"::Order); + // [THEN] Check all the 3 lines are inserted + CheckSalesLineContent(SalesLine, SalesHeader."No."); + end; + + [Test] + [HandlerFunctions('CheckNothingGeneratedFromSalesOrder')] + procedure TestCopySalesOrderByDateFromAnotherCustomer() + var + Customer: Record Customer; + Customer2: Record Customer; + SalesHeader: Record "Sales Header"; + SalesLine: Record "Sales Line"; + CreatedItem: Record Item; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + StartDate: Date; + begin + // [FEATURE] [Sales Line with AI] [Document Lookup] [Sales Order] + // [SCENARIO] User input 'I want all the items from sales order with posting date 01/01/2019' from another customer's sales order. System cannot find the order and should not generate any lines. + LibraryVariableStorage.Clear(); + LibrarySales.CreateCustomer(Customer); + LibrarySales.CreateCustomer(Customer2); + // [GIVEN] Create a new sales order for the new customer + LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Order, Customer."No."); + Evaluate(StartDate, '01/01/2019'); + SalesHeader.Validate("Posting Date", StartDate); + SalesHeader.Modify(true); + // [GIVEN] Create 3 lines with item description and add it to the new sales order + Create3SalesLinesWithItemDescription(SalesHeader, SalesLine, CreatedItem); + LibraryVariableStorage.Enqueue('I need all items from sales order with posting date 01/01/2019'); + // [WHEN] Create a new sales order for another customer and run Sales Line AI Suggestions Page to generate suggestions lines + // [THEN] Check no line is generated in 'CheckNothingGeneratedFromSalesOrder' handler function + CreateNewSalesHeaderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions, Customer2."No.", SalesHeader."Document Type"::Order); + // [THEN] Check no line is inserted to this document + CheckEmptySalesLineContent(SalesLine, SalesHeader."No."); + end; + + [Test] + [HandlerFunctions('CheckGenerateFromSalesOrder')] + procedure TestCopySalesOrderByDateRange1() + var + Customer: Record Customer; + SalesHeader: Record "Sales Header"; + SalesLine: Record "Sales Line"; + CreatedItem: Record Item; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + StartDate: Date; + begin + // [FEATURE] [Sales Line with AI] [Document Lookup] [Sales Order] + // [SCENARIO] User input 'I need all items from sales order on January of 2019' in current customer's sales order. System will find the order and copy all the lines to the current sales order. + LibraryVariableStorage.Clear(); + LibrarySales.CreateCustomer(Customer); + // [GIVEN] Create a new sales order for the new customer + LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Order, Customer."No."); + Evaluate(StartDate, '01/01/2019'); + SalesHeader.Validate("Posting Date", StartDate); + SalesHeader.Modify(true); + // [GIVEN] Create 3 lines with item description and add it to the new sales order + Create3SalesLinesWithItemDescription(SalesHeader, SalesLine, CreatedItem); + LibraryVariableStorage.Enqueue('I need all items from sales order on January of 2019'); + LibraryVariableStorage.Enqueue('3'); + Enqueue3SalesLineWithItemDescription(); + Enqueue3SalesLineWithItemDescription(); + // [WHEN] Create a new sales order for this customer and run Sales Line AI Suggestions Page to generate suggestions lines + // [THEN] Check that correct lines are generated in 'CheckGenerateFromSalesOrder' handler function + CreateNewSalesHeaderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions, Customer."No.", SalesHeader."Document Type"::Order); + // [THEN] Check all the 3 lines are inserted + CheckSalesLineContent(SalesLine, SalesHeader."No."); + end; + + [Test] + [HandlerFunctions('CheckGenerateFromSalesOrder')] + procedure TestCopySalesOrderByDateRange2() + var + Customer: Record Customer; + SalesHeader: Record "Sales Header"; + SalesLine: Record "Sales Line"; + CreatedItem: Record Item; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + StartDate: Date; + begin + // [FEATURE] [Sales Line with AI] [Document Lookup] [Sales Order] + // [SCENARIO] User input 'I need all items from sales order from 2018-12-30 to 2019-Jan-5' in current customer's sales order. System will find the order and copy all the lines to the current sales order. + LibraryVariableStorage.Clear(); + LibrarySales.CreateCustomer(Customer); + // [GIVEN] Create a new sales order for the new customer + LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Order, Customer."No."); + Evaluate(StartDate, '01/01/2019'); + SalesHeader.Validate("Posting Date", StartDate); + SalesHeader.Modify(true); + // [GIVEN] Create 3 lines with item description and add it to the new sales order + Create3SalesLinesWithItemDescription(SalesHeader, SalesLine, CreatedItem); + LibraryVariableStorage.Enqueue('I need all items from sales order from 2018-12-30 to 2019-Jan-5'); + LibraryVariableStorage.Enqueue('3'); + Enqueue3SalesLineWithItemDescription(); + Enqueue3SalesLineWithItemDescription(); + // [WHEN] Create a new sales order for this customer and run Sales Line AI Suggestions Page to generate suggestions lines + // [THEN] Check that correct lines are generated in 'CheckGenerateFromSalesOrder' handler function + CreateNewSalesHeaderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions, Customer."No.", SalesHeader."Document Type"::Order); + // [THEN] Check all the 3 lines are inserted + CheckSalesLineContent(SalesLine, SalesHeader."No."); + end; + + [Test] + [HandlerFunctions('CheckNothingGeneratedFromSalesOrder,SendNotificationHandler')] + procedure TestCopySalesLineWithIncorrectDocumentType() + var + Customer: Record Customer; + SalesHeader: Record "Sales Header"; + SalesLine: Record "Sales Line"; + CreatedItem: Record Item; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + begin + // [FEATURE] [Sales Line with AI] [Document Lookup] [Sales Order] + // [SCENARIO] User input 'I want all the items from unknown document'. System cannot find the order and should not generate any lines. + LibraryVariableStorage.Clear(); + LibrarySales.CreateCustomer(Customer); + // [GIVEN] Create a new sales order for the new customer + LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Order, Customer."No."); + // [GIVEN] Create 3 lines with item description and add it to the new sales order + Create3SalesLinesWithItemDescription(SalesHeader, SalesLine, CreatedItem); + LibraryVariableStorage.Enqueue(NeedAllItemFromUnknownDocumentLbl); + LibraryVariableStorage.Enqueue(UnknownDocTypeErr); + // [WHEN] Create a new sales order for this customer and run Sales Line AI Suggestions Page to generate suggestions lines + // [THEN] Check no line is generated in 'CheckNothingGeneratedFromSalesOrder' handler function + // [THEN] Check the error message in 'SendNotificationHandler' handler function + CreateNewSalesHeaderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions, Customer."No.", SalesHeader."Document Type"::Order); + // [THEN] Check no line is inserted to this document + CheckEmptySalesLineContent(SalesLine, SalesHeader."No."); + end; + //-------------------------------------------------------------------------------------- + // Test cases for Sales Invoice + [Test] + [HandlerFunctions('CheckGenerateFromSalesOrder')] + procedure TestCopySalesInvoiceByDocNo() + var + Customer: Record Customer; + SalesHeader: Record "Sales Header"; + SalesLine: Record "Sales Line"; + CreatedItem: Record Item; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + begin + // [FEATURE] [Sales Line with AI] [Document Lookup] [Sales Invoice] + // [SCENARIO] User input 'I want all the items from sales invoice 10000' in current customer's sales order. System will find the invoice and copy all the lines to the current sales order. + LibraryVariableStorage.Clear(); + LibrarySales.CreateCustomer(Customer); + // [GIVEN] Create a new sales order for the new customer + LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Order, Customer."No."); + // [GIVEN] Create 3 lines with item description and add it to the new sales order + Create3SalesLinesWithItemDescription(SalesHeader, SalesLine, CreatedItem); + // [GIVEN] Post the sales order to create the sales invoice + LibrarySales.PostSalesDocument(SalesHeader, true, true); + LibraryVariableStorage.Enqueue(StrSubstNo(NeedAllItemFromSpecifiedSalesInvoiceLbl, SalesHeader."No.")); + LibraryVariableStorage.Enqueue('3'); + Enqueue3SalesLineWithItemDescription(); + Enqueue3SalesLineWithItemDescription(); + // [WHEN] Create a new sales order for this customer and run Sales Line AI Suggestions Page to generate suggestions lines + // [THEN] Check that correct lines are generated in 'CheckGenerateFromSalesOrder' handler function + CreateNewSalesHeaderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions, Customer."No.", SalesHeader."Document Type"::Order); + // [THEN] Check all the 3 lines are inserted + CheckSalesLineContent(SalesLine, SalesHeader."No."); + end; + + [Test] + [HandlerFunctions('CheckGenerateFromSalesOrder')] + procedure TestCopySalesInvoiceByDocNoFromDifferentCustomer() + var + Customer: Record Customer; + Customer2: Record Customer; + SalesHeader: Record "Sales Header"; + SalesLine: Record "Sales Line"; + CreatedItem: Record Item; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + begin + // [FEATURE] [Sales Line with AI] [Document Lookup] [Sales Invoice] + // [SCENARIO] User input 'I want all the items from sales invoice 10000' in another customer's sales order. The system should generate 3 lines with item description and quantity. + LibraryVariableStorage.Clear(); + LibrarySales.CreateCustomer(Customer); + LibrarySales.CreateCustomer(Customer2); + // [GIVEN] Create a new sales order for the new customer + LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Order, Customer."No."); + // [GIVEN] Create 3 lines with item description and add it to the new sales order + Create3SalesLinesWithItemDescription(SalesHeader, SalesLine, CreatedItem); + // [GIVEN] Post the sales order to create the sales invoice + LibrarySales.PostSalesDocument(SalesHeader, true, true); + LibraryVariableStorage.Enqueue(StrSubstNo(NeedAllItemFromSpecifiedSalesInvoiceLbl, SalesHeader."No.")); + LibraryVariableStorage.Enqueue('3'); + Enqueue3SalesLineWithItemDescription(); + Enqueue3SalesLineWithItemDescription(); + // [WHEN] Create a new sales order for this customer and run Sales Line AI Suggestions Page to generate suggestions lines + // [THEN] Check that correct lines are generated in 'CheckGenerateFromSalesOrder' handler function + CreateNewSalesHeaderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions, Customer2."No.", SalesHeader."Document Type"::Order); + // [THEN] Check all the 3 lines are inserted + CheckSalesLineContent(SalesLine, SalesHeader."No."); + end; + + [Test] + [HandlerFunctions('CheckGenerateFromSalesOrder')] + procedure TestCopySalesInvoiceByExternalDocumentNo() + var + Customer: Record Customer; + Customer2: Record Customer; + SalesHeader: Record "Sales Header"; + SalesLine: Record "Sales Line"; + CreatedItem: Record Item; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + begin + // [FEATURE] [Sales Line with AI] [Document Lookup] [Sales Invoice] + // [SCENARIO] User input 'I want all the items from sales invoice EXT10000' in another customer's sales order. The system should generate 3 lines with item description and quantity. + LibraryVariableStorage.Clear(); + LibrarySales.CreateCustomer(Customer); + LibrarySales.CreateCustomer(Customer2); + // [GIVEN] Create a new sales order for the new customer + LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Order, Customer."No."); + // [GIVEN]Update External Document No. + SalesHeader.Validate("External Document No.", 'EXTNO123456789123456789123456789123'); + SalesHeader.Modify(true); + // [GIVEN] Create 3 lines with item description and add it to the new sales order + Create3SalesLinesWithItemDescription(SalesHeader, SalesLine, CreatedItem); + // [GIVEN] Post the sales order to create the sales invoice + LibrarySales.PostSalesDocument(SalesHeader, true, true); + LibraryVariableStorage.Enqueue(StrSubstNo(NeedAllItemFromSpecifiedSalesInvoiceLbl, SalesHeader."External Document No.")); + LibraryVariableStorage.Enqueue('3'); + Enqueue3SalesLineWithItemDescription(); + Enqueue3SalesLineWithItemDescription(); + // [WHEN] Create a new sales order for this customer and run Sales Line AI Suggestions Page to generate suggestions lines + // [THEN] Check that correct lines are generated in 'CheckGenerateFromSalesOrder' handler function + CreateNewSalesHeaderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions, Customer2."No.", SalesHeader."Document Type"::Order); + // [THEN] Check all the 3 lines are inserted + CheckSalesLineContent(SalesLine, SalesHeader."No."); + end; + + [Test] + [HandlerFunctions('CheckGenerateFromSalesOrder')] + procedure TestCopySalesInvoiceByQuoteNo() + var + Customer: Record Customer; + Customer2: Record Customer; + SalesHeader: Record "Sales Header"; + SalesLine: Record "Sales Line"; + CreatedItem: Record Item; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + begin + // [FEATURE] [Sales Line with AI] [Document Lookup] [Sales Invoice] + // [SCENARIO] User input 'I want all the items from sales invoice QTO214500' in another customer's sales order. The system should generate 3 lines with item description and quantity. + LibraryVariableStorage.Clear(); + LibrarySales.CreateCustomer(Customer); + LibrarySales.CreateCustomer(Customer2); + // [GIVEN] Create a new sales order for the new customer + LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Order, Customer."No."); + SalesHeader.Validate("Quote No.", 'QTO214500'); + SalesHeader.Modify(true); + // [GIVEN] Create 3 lines with item description and add it to the new sales order + Create3SalesLinesWithItemDescription(SalesHeader, SalesLine, CreatedItem); + // [GIVEN] Post the sales order to create the sales invoice + LibrarySales.PostSalesDocument(SalesHeader, true, true); + // generate prompt with quote No. + LibraryVariableStorage.Enqueue(StrSubstNo(NeedAllItemFromSpecifiedSalesInvoiceLbl, SalesHeader."Quote No.")); + LibraryVariableStorage.Enqueue('3'); + Enqueue3SalesLineWithItemDescription(); + Enqueue3SalesLineWithItemDescription(); + // [WHEN] Create a new sales order for this customer and run Sales Line AI Suggestions Page to generate suggestions lines + // [THEN] Check that correct lines are generated in 'CheckGenerateFromSalesOrder' handler function + CreateNewSalesHeaderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions, Customer2."No.", SalesHeader."Document Type"::Order); + // [THEN] Check all the 3 lines are inserted + CheckSalesLineContent(SalesLine, SalesHeader."No."); + end; + + [Test] + [HandlerFunctions('CheckGenerateFromSalesOrder')] + procedure TestCopySalesInvoiceByReferenceNo() + var + Customer: Record Customer; + Customer2: Record Customer; + SalesHeader: Record "Sales Header"; + SalesLine: Record "Sales Line"; + CreatedItem: Record Item; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + begin + // [FEATURE] [Sales Line with AI] [Document Lookup] [Sales Invoice] + // [SCENARIO] User input 'I want all the items from sales invoice REF214500' in another customer's sales order. The system should generate 3 lines with item description and quantity. + LibraryVariableStorage.Clear(); + LibrarySales.CreateCustomer(Customer); + LibrarySales.CreateCustomer(Customer2); + // [GIVEN] Create a new sales order for the new customer + LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Order, Customer."No."); + SalesHeader.Validate("Your Reference", 'REF214500'); + SalesHeader.Modify(true); + // [GIVEN] Create 3 lines with item description and add it to the new sales order + Create3SalesLinesWithItemDescription(SalesHeader, SalesLine, CreatedItem); + // [GIVEN] Post the sales order to create the sales invoice + LibrarySales.PostSalesDocument(SalesHeader, true, true); + LibraryVariableStorage.Enqueue(StrSubstNo(NeedAllItemFromSpecifiedSalesInvoiceLbl, SalesHeader."Your Reference")); + LibraryVariableStorage.Enqueue('3'); + Enqueue3SalesLineWithItemDescription(); + Enqueue3SalesLineWithItemDescription(); + // [WHEN] Create a new sales order for this customer and run Sales Line AI Suggestions Page to generate suggestions lines + // [THEN] Check that correct lines are generated in 'CheckGenerateFromSalesOrder' handler function + CreateNewSalesHeaderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions, Customer2."No.", SalesHeader."Document Type"::Order); + // [THEN] Check all the 3 lines are inserted + CheckSalesLineContent(SalesLine, SalesHeader."No."); + end; + + [Test] + [HandlerFunctions('CheckGenerateFromSalesOrder')] + procedure TestAmbiguouslyCopySalesInvoiceByExternalDocumentNo() + var + Customer: Record Customer; + Customer2: Record Customer; + SalesHeader: Record "Sales Header"; + SalesLine: Record "Sales Line"; + CreatedItem: Record Item; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + begin + // [FEATURE] [Sales Line with AI] [Document Lookup] [Sales Invoice] [Ambiguous Search] + // [SCENARIO] There is an item with External Document Number 'EXTNO123456789123456789123456789123'. User input 'I want all the items from sales invoice XTNO12345678912345678912345678912' in another customer's sales order. The system should generate 3 lines with item description and quantity. + LibraryVariableStorage.Clear(); + LibrarySales.CreateCustomer(Customer); + LibrarySales.CreateCustomer(Customer2); + // [GIVEN] Create a new sales order for the new customer + LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Order, Customer."No."); + // [GIVEN] Update External Document No. + SalesHeader.Validate("External Document No.", 'EXTNO123456789123456789123456789123'); + SalesHeader.Modify(true); + // [GIVEN] Create 3 lines with item description and add it to the new sales order + Create3SalesLinesWithItemDescription(SalesHeader, SalesLine, CreatedItem); + // [GIVEN] Post the sales order to create the sales invoice + LibrarySales.PostSalesDocument(SalesHeader, true, true); + // [GIVEN] Remove the first and last character from the External Document No. as user's input + LibraryVariableStorage.Enqueue(StrSubstNo(NeedAllItemFromSpecifiedSalesInvoiceLbl, CopyStr(SalesHeader."External Document No.", 2, StrLen(SalesHeader."External Document No.") - 1))); + LibraryVariableStorage.Enqueue('3'); + Enqueue3SalesLineWithItemDescription(); + Enqueue3SalesLineWithItemDescription(); + // [WHEN] Create a new sales order for this customer and run Sales Line AI Suggestions Page to generate suggestions lines + // [THEN] Check that correct lines are generated in 'CheckGenerateFromSalesOrder' handler function + CreateNewSalesHeaderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions, Customer2."No.", SalesHeader."Document Type"::Order); + // [THEN] Check all the 3 lines are inserted + CheckSalesLineContent(SalesLine, SalesHeader."No."); + end; + + [Test] + [HandlerFunctions('CheckGenerateFromSalesOrder')] + procedure TestAmbiguouslyCopySalesInvoiceByQuoteNo() + var + Customer: Record Customer; + Customer2: Record Customer; + SalesHeader: Record "Sales Header"; + SalesLine: Record "Sales Line"; + CreatedItem: Record Item; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + begin + // [FEATURE] [Sales Line with AI] [Document Lookup] [Sales Invoice] [Ambiguous Search] + // [SCENARIO] There is an item with Quote Number 'QTO214500'. User input 'I want all the items from sales invoice XTNO12345678912345678912345678912' in another customer's sales order. The system should generate 3 lines with item description and quantity. + LibraryVariableStorage.Clear(); + LibrarySales.CreateCustomer(Customer); + LibrarySales.CreateCustomer(Customer2); + // [GIVEN] Create a new sales order for the new customer + LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Order, Customer."No."); + SalesHeader.Validate("Quote No.", 'QTO214500'); + SalesHeader.Modify(true); + // [GIVEN] Create 3 lines with item description and add it to the new sales order + Create3SalesLinesWithItemDescription(SalesHeader, SalesLine, CreatedItem); + // [GIVEN] Post the sales order to create the sales invoice + LibrarySales.PostSalesDocument(SalesHeader, true, true); + LibraryVariableStorage.Enqueue(StrSubstNo(NeedAllItemFromSpecifiedSalesInvoiceLbl, CopyStr(SalesHeader."Quote No.", 2, StrLen(SalesHeader."Quote No.") - 1))); + LibraryVariableStorage.Enqueue('3'); + Enqueue3SalesLineWithItemDescription(); + Enqueue3SalesLineWithItemDescription(); + // [WHEN] Create a new sales order for this customer and run Sales Line AI Suggestions Page to generate suggestions lines + // [THEN] Check that correct lines are generated in 'CheckGenerateFromSalesOrder' handler function + CreateNewSalesHeaderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions, Customer2."No.", SalesHeader."Document Type"::Order); + // [THEN] Check all the 3 lines are inserted + CheckSalesLineContent(SalesLine, SalesHeader."No."); + end; + + [Test] + [HandlerFunctions('CheckGenerateFromSalesOrder')] + procedure TestAmbiguouslyCopySalesInvoiceByReferenceNo() + var + Customer: Record Customer; + Customer2: Record Customer; + SalesHeader: Record "Sales Header"; + SalesLine: Record "Sales Line"; + CreatedItem: Record Item; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + begin + // [FEATURE] [Sales Line with AI] [Document Lookup] [Sales Invoice] [Ambiguous Search] + // [SCENARIO] There is an item with Reference Number 'REF214500'. User input 'I want all the items from sales invoice XTNO12345678912345678912345678912' in another customer's sales order. The system should generate 3 lines with item description and quantity. + LibraryVariableStorage.Clear(); + LibrarySales.CreateCustomer(Customer); + LibrarySales.CreateCustomer(Customer2); + // [GIVEN] Create a new sales order for the new customer + LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Order, Customer."No."); + SalesHeader.Validate("Your Reference", 'REF214500'); + SalesHeader.Modify(true); + // [GIVEN] Create 3 lines with item description and add it to the new sales order + Create3SalesLinesWithItemDescription(SalesHeader, SalesLine, CreatedItem); + // [GIVEN] Post the sales order to create the sales invoice + LibrarySales.PostSalesDocument(SalesHeader, true, true); + // [GIVEN] Remove the first and last character from the Your Reference No. + LibraryVariableStorage.Enqueue(StrSubstNo(NeedAllItemFromSpecifiedSalesInvoiceLbl, CopyStr(SalesHeader."Your Reference", 2, StrLen(SalesHeader."Your Reference") - 1))); + LibraryVariableStorage.Enqueue('3'); + Enqueue3SalesLineWithItemDescription(); + Enqueue3SalesLineWithItemDescription(); + // [WHEN] Create a new sales order for this customer and run Sales Line AI Suggestions Page to generate suggestions lines + // [THEN] Check that correct lines are generated in 'CheckGenerateFromSalesOrder' handler function + CreateNewSalesHeaderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions, Customer2."No.", SalesHeader."Document Type"::Order); + // [THEN] Check all the 3 lines are inserted + CheckSalesLineContent(SalesLine, SalesHeader."No."); + end; + + [Test] + [HandlerFunctions('CheckGenerateFromSalesOrder')] + procedure TestCopySalesInvoiceByDate1() + var + Customer: Record Customer; + SalesHeader: Record "Sales Header"; + SalesLine: Record "Sales Line"; + CreatedItem: Record Item; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + StartDate: Date; + begin + // [FEATURE] [Sales Line with AI] [Document Lookup] [Sales Invoice] + // [SCENARIO] User input 'I need all items from sales invoice with posting date 01/01/2019' in current customer's sales order. System will find the invoice and copy all the lines to the current sales order. + LibraryVariableStorage.Clear(); + LibrarySales.CreateCustomer(Customer); + // [GIVEN] Create a new sales order for the new customer + LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Order, Customer."No."); + Evaluate(StartDate, '01/01/2019'); + SalesHeader.Validate("Posting Date", StartDate); + SalesHeader.Modify(true); + // [GIVEN] Create 3 lines with item description and add it to the new sales order + Create3SalesLinesWithItemDescription(SalesHeader, SalesLine, CreatedItem); + // [GIVEN] Post the sales order to create the sales invoice + LibrarySales.PostSalesDocument(SalesHeader, true, true); + LibraryVariableStorage.Enqueue('I need all items from sales invoice with posting date 01/01/2019'); + LibraryVariableStorage.Enqueue('3'); + Enqueue3SalesLineWithItemDescription(); + Enqueue3SalesLineWithItemDescription(); + // [WHEN] Create a new sales order for this customer and run Sales Line AI Suggestions Page to generate suggestions lines + // [THEN] Check that correct lines are generated in 'CheckGenerateFromSalesOrder' handler function + CreateNewSalesHeaderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions, Customer."No.", SalesHeader."Document Type"::Order); + // [THEN] Check all the 3 lines are inserted + CheckSalesLineContent(SalesLine, SalesHeader."No."); + end; + + [Test] + [HandlerFunctions('CheckNothingGeneratedFromSalesOrder')] + procedure TestCopySalesInvoiceByDateFromAnotherCustomer() + var + Customer: Record Customer; + Customer2: Record Customer; + SalesHeader: Record "Sales Header"; + SalesLine: Record "Sales Line"; + CreatedItem: Record Item; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + StartDate: Date; + begin + // [FEATURE] [Sales Line with AI] [Document Lookup] [Sales Invoice] + // [SCENARIO] User input 'I need all items from sales invoice with posting date 01/01/2019' from another customer's sales order. System cannot find the order and should not generate any lines. + LibraryVariableStorage.Clear(); + LibrarySales.CreateCustomer(Customer); + LibrarySales.CreateCustomer(Customer2); + // [GIVEN] Create a new sales order for the new customer + LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Order, Customer."No."); + // [GIVEN] Change the date of the sales order + Evaluate(StartDate, '01/01/2019'); + SalesHeader.Validate("Posting Date", StartDate); + SalesHeader.Modify(true); + // [GIVEN] Create 3 lines with item description and add it to the new sales order + Create3SalesLinesWithItemDescription(SalesHeader, SalesLine, CreatedItem); + // [GIVEN] Post the sales order to create the sales invoice + LibrarySales.PostSalesDocument(SalesHeader, true, true); + LibraryVariableStorage.Enqueue('I need all items from sales invoice with posting date 01/01/2019'); + // [WHEN] Create a new sales order for this customer and run Sales Line AI Suggestions Page to generate suggestions lines + // [THEN] Check no line is generated in 'CheckNothingGeneratedFromSalesOrder' handler function + CreateNewSalesHeaderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions, Customer2."No.", SalesHeader."Document Type"::Order); + // [THEN] Check no line is inserted to this document + CheckEmptySalesLineContent(SalesLine, SalesHeader."No."); + end; + + [Test] + [HandlerFunctions('CheckGenerateFromSalesOrder')] + procedure TestCopySalesInvoiceByDateRange1() + var + Customer: Record Customer; + SalesHeader: Record "Sales Header"; + SalesLine: Record "Sales Line"; + CreatedItem: Record Item; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + StartDate: Date; + begin + // [FEATURE] [Sales Line with AI] [Document Lookup] [Sales Invoice] + // [SCENARIO] User input 'I need all items from sales invoice on January of 2019' in current customer's sales order. System will find the invoice and copy all the lines to the current sales order. + LibraryVariableStorage.Clear(); + LibrarySales.CreateCustomer(Customer); + // [GIVEN] Create a new sales order for the new customer + LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Order, Customer."No."); + Evaluate(StartDate, '01/01/2019'); + SalesHeader.Validate("Posting Date", StartDate); + SalesHeader.Modify(true); + // [GIVEN] Create 3 lines with item description and add it to the new sales order + Create3SalesLinesWithItemDescription(SalesHeader, SalesLine, CreatedItem); + // [GIVEN] Post the sales order to create the sales invoice + LibrarySales.PostSalesDocument(SalesHeader, true, true); + LibraryVariableStorage.Enqueue('I need all items from sales invoice on January of 2019'); + LibraryVariableStorage.Enqueue('3'); + Enqueue3SalesLineWithItemDescription(); + Enqueue3SalesLineWithItemDescription(); + // [WHEN] Create a new sales order for this customer and run Sales Line AI Suggestions Page to generate suggestions lines + // [THEN] Check that correct lines are generated in 'CheckGenerateFromSalesOrder' handler function + CreateNewSalesHeaderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions, Customer."No.", SalesHeader."Document Type"::Order); + // [THEN] Check all the 3 lines are inserted + CheckSalesLineContent(SalesLine, SalesHeader."No."); + end; + + [Test] + [HandlerFunctions('CheckGenerateFromSalesOrder')] + procedure TestCopySalesInvoiceByDateRange2() + var + Customer: Record Customer; + SalesHeader: Record "Sales Header"; + SalesLine: Record "Sales Line"; + CreatedItem: Record Item; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + StartDate: Date; + begin + // [FEATURE] [Sales Line with AI] [Document Lookup] [Sales Invoice] + // [SCENARIO] User input 'I need all items from sales invoice from 2018-12-30 to 2019-Jan-5' in current customer's sales order. System will find the invoice and copy all the lines to the current sales order. + LibraryVariableStorage.Clear(); + LibrarySales.CreateCustomer(Customer); + // [GIVEN] Create a new sales order for the new customer + LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Order, Customer."No."); + // [GIVEN] Change the date of the sales order + Evaluate(StartDate, '01/01/2019'); + SalesHeader.Validate("Posting Date", StartDate); + SalesHeader.Modify(true); + // [GIVEN] Create 3 lines with item description and add it to the new sales order + Create3SalesLinesWithItemDescription(SalesHeader, SalesLine, CreatedItem); + // [GIVEN] Post the sales order to create the sales invoice + LibrarySales.PostSalesDocument(SalesHeader, true, true); + LibraryVariableStorage.Enqueue('I need all items from sales invoice from 2018-12-30 to 2019-Jan-5'); + LibraryVariableStorage.Enqueue('3'); + Enqueue3SalesLineWithItemDescription(); + Enqueue3SalesLineWithItemDescription(); + // [WHEN] Create a new sales order for this customer and run Sales Line AI Suggestions Page to generate suggestions lines + // [THEN] Check that correct lines are generated in 'CheckGenerateFromSalesOrder' handler function + CreateNewSalesHeaderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions, Customer."No.", SalesHeader."Document Type"::Order); + // [THEN] Check all the 3 lines are inserted + CheckSalesLineContent(SalesLine, SalesHeader."No."); + end; + //-------------------------------------------------------------------------------------- + // Test cases for Sales Shipment + [Test] + [HandlerFunctions('CheckGenerateFromSalesOrder')] + procedure TestCopySalesShipmentByDocNo() + var + Customer: Record Customer; + SalesHeader: Record "Sales Header"; + SalesLine: Record "Sales Line"; + CreatedItem: Record Item; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + begin + // [FEATURE] [Sales Line with AI] [Document Lookup] [Sales Shipment] + // [SCENARIO] User input 'I want all the items from sales shipment 10000' in current customer's sales order. System will find the shipment and copy all the lines to the current sales order. + LibraryVariableStorage.Clear(); + LibrarySales.CreateCustomer(Customer); + // [GIVEN] Create a new sales order for the new customer + LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Order, Customer."No."); + // [GIVEN] Create 3 lines with item description and add it to the new sales order + Create3SalesLinesWithItemDescription(SalesHeader, SalesLine, CreatedItem); + // [GIVEN] Post the sales order to create the sales shipment + LibrarySales.PostSalesDocument(SalesHeader, true, true); + LibraryVariableStorage.Enqueue(StrSubstNo(NeedAllItemFromSpecifiedSalesShipmentLbl, SalesHeader."No.")); + LibraryVariableStorage.Enqueue('3'); + Enqueue3SalesLineWithItemDescription(); + Enqueue3SalesLineWithItemDescription(); + // [WHEN] Create a new sales order for this customer and run Sales Line AI Suggestions Page to generate suggestions lines + // [THEN] Check that correct lines are generated in 'CheckGenerateFromSalesOrder' handler function + CreateNewSalesHeaderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions, Customer."No.", SalesHeader."Document Type"::Order); + // [THEN] Check all the 3 lines are inserted + CheckSalesLineContent(SalesLine, SalesHeader."No."); + end; + + [Test] + [HandlerFunctions('CheckGenerateFromSalesOrder')] + procedure TestCopySalesShipmentByDocNoFromDifferentCustomer() + var + Customer: Record Customer; + Customer2: Record Customer; + SalesHeader: Record "Sales Header"; + SalesLine: Record "Sales Line"; + CreatedItem: Record Item; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + begin + // [FEATURE] [Sales Line with AI] [Document Lookup] [Sales Shipment] + // [SCENARIO] User input 'I want all the items from sales shipment 10000' in another customer's sales order. The system should generate 3 lines with item description and quantity. + LibraryVariableStorage.Clear(); + LibrarySales.CreateCustomer(Customer); + LibrarySales.CreateCustomer(Customer2); + // [GIVEN] Create a new sales order for the new customer + LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Order, Customer."No."); + // [GIVEN] Create 3 lines with item description and add it to the new sales order + Create3SalesLinesWithItemDescription(SalesHeader, SalesLine, CreatedItem); + // [GIVEN] Post the sales order to create the sales shipment + LibrarySales.PostSalesDocument(SalesHeader, true, true); + LibraryVariableStorage.Enqueue(StrSubstNo(NeedAllItemFromSpecifiedSalesShipmentLbl, SalesHeader."No.")); + LibraryVariableStorage.Enqueue('3'); + Enqueue3SalesLineWithItemDescription(); + Enqueue3SalesLineWithItemDescription(); + // [WHEN] Create a new sales order for this customer and run Sales Line AI Suggestions Page to generate suggestions lines + // [THEN] Check that correct lines are generated in 'CheckGenerateFromSalesOrder' handler function + CreateNewSalesHeaderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions, Customer2."No.", SalesHeader."Document Type"::Order); + // [THEN] Check all the 3 lines are inserted + CheckSalesLineContent(SalesLine, SalesHeader."No."); + end; + + [Test] + [HandlerFunctions('CheckGenerateFromSalesOrder')] + procedure TestCopySalesShipmentByExternalDocumentNo() + var + Customer: Record Customer; + Customer2: Record Customer; + SalesHeader: Record "Sales Header"; + SalesLine: Record "Sales Line"; + CreatedItem: Record Item; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + begin + // [FEATURE] [Sales Line with AI] [Document Lookup] [Sales Shipment] + // [SCENARIO] User input 'I want all the items from sales shipment EXT10000' in another customer's sales order. The system should generate 3 lines with item description and quantity. + LibraryVariableStorage.Clear(); + LibrarySales.CreateCustomer(Customer); + LibrarySales.CreateCustomer(Customer2); + // [GIVEN] Create a new sales order for the new customer + LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Order, Customer."No."); + // [GIVEN] Update External Document No. + SalesHeader.Validate("External Document No.", 'EXTNO123456789123456789123456789123'); + SalesHeader.Modify(true); + // [GIVEN] Create 3 lines with item description and add it to the new sales order + Create3SalesLinesWithItemDescription(SalesHeader, SalesLine, CreatedItem); + // [GIVEN] Post the sales order to create the sales shipment + LibrarySales.PostSalesDocument(SalesHeader, true, true); + LibraryVariableStorage.Enqueue(StrSubstNo(NeedAllItemFromSpecifiedSalesShipmentLbl, SalesHeader."External Document No.")); + LibraryVariableStorage.Enqueue('3'); + Enqueue3SalesLineWithItemDescription(); + Enqueue3SalesLineWithItemDescription(); + // [WHEN] Create a new sales order for this customer and run Sales Line AI Suggestions Page to generate suggestions lines + // [THEN] Check that correct lines are generated in 'CheckGenerateFromSalesOrder' handler function + CreateNewSalesHeaderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions, Customer2."No.", SalesHeader."Document Type"::Order); + // [THEN] Check all the 3 lines are inserted + CheckSalesLineContent(SalesLine, SalesHeader."No."); + end; + + [Test] + [HandlerFunctions('CheckGenerateFromSalesOrder')] + procedure TestCopySalesShipmentByQuoteNo() + var + Customer: Record Customer; + Customer2: Record Customer; + SalesHeader: Record "Sales Header"; + SalesLine: Record "Sales Line"; + CreatedItem: Record Item; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + begin + // [FEATURE] [Sales Line with AI] [Document Lookup] [Sales Shipment] + // [SCENARIO] User input 'I want all the items from sales shipment QTO214500' in another customer's sales order. The system should generate 3 lines with item description and quantity. + LibraryVariableStorage.Clear(); + LibrarySales.CreateCustomer(Customer); + LibrarySales.CreateCustomer(Customer2); + // [GIVEN] Create a new sales order for the new customer + LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Order, Customer."No."); + SalesHeader.Validate("Quote No.", 'QTO214500'); + SalesHeader.Modify(true); + // [GIVEN] Create 3 lines with item description and add it to the new sales order + Create3SalesLinesWithItemDescription(SalesHeader, SalesLine, CreatedItem); + // [GIVEN] Post the sales order to create the sales shipment + LibrarySales.PostSalesDocument(SalesHeader, true, true); + LibraryVariableStorage.Enqueue(StrSubstNo(NeedAllItemFromSpecifiedSalesShipmentLbl, SalesHeader."Quote No.")); + LibraryVariableStorage.Enqueue('3'); + Enqueue3SalesLineWithItemDescription(); + Enqueue3SalesLineWithItemDescription(); + // [WHEN] Create a new sales order for this customer and run Sales Line AI Suggestions Page to generate suggestions lines + // [THEN] Check that correct lines are generated in 'CheckGenerateFromSalesOrder' handler function + CreateNewSalesHeaderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions, Customer2."No.", SalesHeader."Document Type"::Order); + // [THEN] Check all the 3 lines are inserted + CheckSalesLineContent(SalesLine, SalesHeader."No."); + end; + + [Test] + [HandlerFunctions('CheckGenerateFromSalesOrder')] + procedure TestCopySalesShipmentByReferenceNo() + var + Customer: Record Customer; + Customer2: Record Customer; + SalesHeader: Record "Sales Header"; + SalesLine: Record "Sales Line"; + CreatedItem: Record Item; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + begin + // [FEATURE] [Sales Line with AI] [Document Lookup] [Sales Shipment] + // [SCENARIO] User input 'I want all the items from sales shipment REF214500' in another customer's sales order. The system should generate 3 lines with item description and quantity. + LibraryVariableStorage.Clear(); + LibrarySales.CreateCustomer(Customer); + LibrarySales.CreateCustomer(Customer2); + // [GIVEN] Create a new sales order for the new customer + LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Order, Customer."No."); + SalesHeader.Validate("Your Reference", 'REF214500'); + SalesHeader.Modify(true); + // [GIVEN] Create 3 lines with item description and add it to the new sales order + Create3SalesLinesWithItemDescription(SalesHeader, SalesLine, CreatedItem); + // [GIVEN] Post the sales order to create the sales shipment + LibrarySales.PostSalesDocument(SalesHeader, true, true); + LibraryVariableStorage.Enqueue(StrSubstNo(NeedAllItemFromSpecifiedSalesShipmentLbl, SalesHeader."Your Reference")); + LibraryVariableStorage.Enqueue('3'); + Enqueue3SalesLineWithItemDescription(); + Enqueue3SalesLineWithItemDescription(); + // [WHEN] Create a new sales order for this customer and run Sales Line AI Suggestions Page to generate suggestions lines + // [THEN] Check that correct lines are generated in 'CheckGenerateFromSalesOrder' handler function + CreateNewSalesHeaderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions, Customer2."No.", SalesHeader."Document Type"::Order); + // [THEN] Check all the 3 lines are inserted + CheckSalesLineContent(SalesLine, SalesHeader."No."); + end; + + [Test] + [HandlerFunctions('CheckGenerateFromSalesOrder')] + procedure TestAmbiguouslyCopySalesShipmentByExternalDocumentNo() + var + Customer: Record Customer; + Customer2: Record Customer; + SalesHeader: Record "Sales Header"; + SalesLine: Record "Sales Line"; + CreatedItem: Record Item; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + begin + // [FEATURE] [Sales Line with AI] [Document Lookup] [Sales Order] + // [SCENARIO] User input 'I want all the items from sales shipment EXT10000' in another customer's sales order. The system should generate 3 lines with item description and quantity. + LibraryVariableStorage.Clear(); + LibrarySales.CreateCustomer(Customer); + LibrarySales.CreateCustomer(Customer2); + // [GIVEN] Create a new sales order for the new customer + LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Order, Customer."No."); + SalesHeader.Validate("External Document No.", 'EXTNO123456789123456789123456789123'); + SalesHeader.Modify(true); + // [GIVEN] Create 3 lines with item description and add it to the new sales order + Create3SalesLinesWithItemDescription(SalesHeader, SalesLine, CreatedItem); + // [GIVEN] Post the sales order to create the sales shipment + LibrarySales.PostSalesDocument(SalesHeader, true, true); + LibraryVariableStorage.Enqueue(StrSubstNo(NeedAllItemFromSpecifiedSalesShipmentLbl, CopyStr(SalesHeader."External Document No.", 2, StrLen(SalesHeader."External Document No.") - 1))); + LibraryVariableStorage.Enqueue('3'); + Enqueue3SalesLineWithItemDescription(); + Enqueue3SalesLineWithItemDescription(); + // [WHEN] Create a new sales order for this customer and run Sales Line AI Suggestions Page to generate suggestions lines + // [THEN] Check that correct lines are generated in 'CheckGenerateFromSalesOrder' handler function + CreateNewSalesHeaderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions, Customer2."No.", SalesHeader."Document Type"::Order); + // [THEN] Check all the 3 lines are inserted + CheckSalesLineContent(SalesLine, SalesHeader."No."); + end; + + [Test] + [HandlerFunctions('CheckGenerateFromSalesOrder')] + procedure TestAmbiguouslyCopySalesShipmentByQuoteNo() + var + Customer: Record Customer; + Customer2: Record Customer; + SalesHeader: Record "Sales Header"; + SalesLine: Record "Sales Line"; + CreatedItem: Record Item; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + begin + // [FEATURE] [Sales Line with AI] [Document Lookup] [Sales Shipment] [Ambiguous Search] + // [SCENARIO] There is an item with Quote Number 'QTO214500'. User input 'I want all the items from sales shipment XTNO12345678912345678912345678912' in another customer's sales order. The system should generate 3 lines with item description and quantity. + LibraryVariableStorage.Clear(); + LibrarySales.CreateCustomer(Customer); + LibrarySales.CreateCustomer(Customer2); + // [GIVEN] Create a new sales order for the new customer + LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Order, Customer."No."); + SalesHeader.Validate("Quote No.", 'QTO214500'); + SalesHeader.Modify(true); + // [GIVEN] Create 3 lines with item description and add it to the new sales order + Create3SalesLinesWithItemDescription(SalesHeader, SalesLine, CreatedItem); + // [GIVEN] Post the sales order to create the sales shipment + LibrarySales.PostSalesDocument(SalesHeader, true, true); + LibraryVariableStorage.Enqueue(StrSubstNo(NeedAllItemFromSpecifiedSalesShipmentLbl, CopyStr(SalesHeader."Quote No.", 2, StrLen(SalesHeader."Quote No.") - 1))); + LibraryVariableStorage.Enqueue('3'); + Enqueue3SalesLineWithItemDescription(); + Enqueue3SalesLineWithItemDescription(); + // [WHEN] Create a new sales order for this customer and run Sales Line AI Suggestions Page to generate suggestions lines + // [THEN] Check that correct lines are generated in 'CheckGenerateFromSalesOrder' handler function + CreateNewSalesHeaderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions, Customer2."No.", SalesHeader."Document Type"::Order); + // [THEN] Check all the 3 lines are inserted + CheckSalesLineContent(SalesLine, SalesHeader."No."); + end; + + [Test] + [HandlerFunctions('CheckGenerateFromSalesOrder')] + procedure TestAmbiguouslyCopySalesShipmentByReferenceNo() + var + Customer: Record Customer; + Customer2: Record Customer; + SalesHeader: Record "Sales Header"; + SalesLine: Record "Sales Line"; + CreatedItem: Record Item; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + begin + // [FEATURE] [Sales Line with AI] [Document Lookup] [Sales Shipment] [Ambiguous Search] + // [SCENARIO] There is an item with Reference Number 'REF214500'. User input 'I want all the items from sales shipment XTNO12345678912345678912345678912' in another customer's sales order. The system should generate 3 lines with item description and quantity. + LibraryVariableStorage.Clear(); + LibrarySales.CreateCustomer(Customer); + LibrarySales.CreateCustomer(Customer2); + // [GIVEN] Create a new sales order for the new customer + LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Order, Customer."No."); + SalesHeader.Validate("Your Reference", 'REF214500'); + SalesHeader.Modify(true); + // [GIVEN] Create 3 lines with item description and add it to the new sales order + Create3SalesLinesWithItemDescription(SalesHeader, SalesLine, CreatedItem); + // [GIVEN] Post the sales order to create the sales shipment + LibrarySales.PostSalesDocument(SalesHeader, true, true); + LibraryVariableStorage.Enqueue(StrSubstNo(NeedAllItemFromSpecifiedSalesShipmentLbl, CopyStr(SalesHeader."Your Reference", 2, StrLen(SalesHeader."Your Reference") - 1))); + LibraryVariableStorage.Enqueue('3'); + Enqueue3SalesLineWithItemDescription(); + Enqueue3SalesLineWithItemDescription(); + // [WHEN] Create a new sales order for this customer and run Sales Line AI Suggestions Page to generate suggestions lines + // [THEN] Check that correct lines are generated in 'CheckGenerateFromSalesOrder' handler function + CreateNewSalesHeaderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions, Customer2."No.", SalesHeader."Document Type"::Order); + // [THEN] Check all the 3 lines are inserted + CheckSalesLineContent(SalesLine, SalesHeader."No."); + end; + + [Test] + [HandlerFunctions('CheckGenerateFromSalesOrder')] + procedure TestCopySalesShipmentByDate1() + var + Customer: Record Customer; + SalesHeader: Record "Sales Header"; + SalesLine: Record "Sales Line"; + CreatedItem: Record Item; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + StartDate: Date; + begin + // [FEATURE] [Sales Line with AI] [Document Lookup] [Sales Shipment] + // [SCENARIO] User input 'I need all items from sales shipment with posting date 01/01/2019' in current customer's sales order. System will find the shipment and copy all the lines to the current sales order. + LibraryVariableStorage.Clear(); + LibrarySales.CreateCustomer(Customer); + // [GIVEN] Create a new sales order for the new customer + LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Order, Customer."No."); + Evaluate(StartDate, '01/01/2019'); + SalesHeader.Validate("Posting Date", StartDate); + SalesHeader.Modify(true); + // [GIVEN] Create 3 lines with item description and add it to the new sales order + Create3SalesLinesWithItemDescription(SalesHeader, SalesLine, CreatedItem); + // [GIVEN] Post the sales order to create the sales shipment + LibrarySales.PostSalesDocument(SalesHeader, true, true); + LibraryVariableStorage.Enqueue('I need all items from sales shipment with posting date 01/01/2019'); + LibraryVariableStorage.Enqueue('3'); + Enqueue3SalesLineWithItemDescription(); + Enqueue3SalesLineWithItemDescription(); + // [WHEN] Create a new sales order for this customer and run Sales Line AI Suggestions Page to generate suggestions lines + // [THEN] Check that correct lines are generated in 'CheckGenerateFromSalesOrder' handler function + CreateNewSalesHeaderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions, Customer."No.", SalesHeader."Document Type"::Order); + // [THEN] Check all the 3 lines are inserted + CheckSalesLineContent(SalesLine, SalesHeader."No."); + end; + + [Test] + [HandlerFunctions('CheckNothingGeneratedFromSalesOrder')] + procedure TestCopySalesShipmentByDateFromAnotherCustomer() + var + Customer: Record Customer; + Customer2: Record Customer; + SalesHeader: Record "Sales Header"; + SalesLine: Record "Sales Line"; + CreatedItem: Record Item; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + StartDate: Date; + begin + // [FEATURE] [Sales Line with AI] [Document Lookup] [Sales Shipment] + // [SCENARIO] User input 'I need all items from sales shipment with posting date 01/01/2019' from another customer's sales order. System cannot find the order and should not generate any lines. + LibraryVariableStorage.Clear(); + LibrarySales.CreateCustomer(Customer); + LibrarySales.CreateCustomer(Customer2); + // [GIVEN] Create a new sales order for the new customer + LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Order, Customer."No."); + Evaluate(StartDate, '01/01/2019'); + SalesHeader.Validate("Posting Date", StartDate); + SalesHeader.Modify(true); + // [GIVEN] Create 3 lines with item description and add it to the new sales order + Create3SalesLinesWithItemDescription(SalesHeader, SalesLine, CreatedItem); + // [GIVEN] Post the sales order to create the sales shipment + LibrarySales.PostSalesDocument(SalesHeader, true, true); + LibraryVariableStorage.Enqueue('I need all items from sales shipment with posting date 01/01/2019'); + // [WHEN] Create a new sales order for this customer and run Sales Line AI Suggestions Page to generate suggestions lines + // [THEN] Check no line is generated in 'CheckGenerateFromSalesOrder' handler function + CreateNewSalesHeaderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions, Customer2."No.", SalesHeader."Document Type"::Order); + // [THEN] Check no line is inserted to this document + CheckEmptySalesLineContent(SalesLine, SalesHeader."No."); + end; + + [Test] + [HandlerFunctions('CheckGenerateFromSalesOrder')] + procedure TestCopySalesShipmentByDateRange1() + var + Customer: Record Customer; + SalesHeader: Record "Sales Header"; + SalesLine: Record "Sales Line"; + CreatedItem: Record Item; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + StartDate: Date; + begin + // [FEATURE] [Sales Line with AI] [Document Lookup] [Sales Shipment] + // [SCENARIO] User input 'I need all items from sales shipment on January of 2019' in current customer's sales order. System will find the shipment and copy all the lines to the current sales order. + LibraryVariableStorage.Clear(); + LibrarySales.CreateCustomer(Customer); + // [GIVEN] Create a new sales order for the new customer + LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Order, Customer."No."); + Evaluate(StartDate, '01/01/2019'); + SalesHeader.Validate("Posting Date", StartDate); + SalesHeader.Modify(true); + // [GIVEN] Create 3 lines with item description and add it to the new sales order + Create3SalesLinesWithItemDescription(SalesHeader, SalesLine, CreatedItem); + // [GIVEN] Post the sales order to create the sales shipment + LibrarySales.PostSalesDocument(SalesHeader, true, true); + LibraryVariableStorage.Enqueue('I need all items from sales shipment on January of 2019'); + LibraryVariableStorage.Enqueue('3'); + Enqueue3SalesLineWithItemDescription(); + Enqueue3SalesLineWithItemDescription(); + // [WHEN] Create a new sales order for this customer and run Sales Line AI Suggestions Page to generate suggestions lines + // [THEN] Check that correct lines are generated in 'CheckGenerateFromSalesOrder' handler function + CreateNewSalesHeaderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions, Customer."No.", SalesHeader."Document Type"::Order); + // [THEN] Check all the 3 lines are inserted + CheckSalesLineContent(SalesLine, SalesHeader."No."); + end; + + [Test] + [HandlerFunctions('CheckGenerateFromSalesOrder')] + procedure TestCopySalesShipmentByDateRange2() + var + Customer: Record Customer; + SalesHeader: Record "Sales Header"; + SalesLine: Record "Sales Line"; + CreatedItem: Record Item; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + StartDate: Date; + begin + // [FEATURE] [Sales Line with AI] [Document Lookup] [Sales Shipment] + // [SCENARIO] User input 'I need all items from sales shipment from 2018-12-30 to 2019-Jan-5' in current customer's sales order. System will find the shipment and copy all the lines to the current sales order. + LibraryVariableStorage.Clear(); + LibrarySales.CreateCustomer(Customer); + // [GIVEN] Create a new sales order for the new customer + LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Order, Customer."No."); + Evaluate(StartDate, '01/01/2019'); + SalesHeader.Validate("Posting Date", StartDate); + SalesHeader.Modify(true); + // [GIVEN] Create 3 lines with item description and add it to the new sales order + Create3SalesLinesWithItemDescription(SalesHeader, SalesLine, CreatedItem); + // [GIVEN] Post the sales order to create the sales shipment + LibrarySales.PostSalesDocument(SalesHeader, true, true); + LibraryVariableStorage.Enqueue('I need all items from sales shipment from 2018-12-30 to 2019-Jan-5'); + LibraryVariableStorage.Enqueue('3'); + Enqueue3SalesLineWithItemDescription(); + Enqueue3SalesLineWithItemDescription(); + // [WHEN] Create a new sales order for this customer and run Sales Line AI Suggestions Page to generate suggestions lines + // [THEN] Check that correct lines are generated in 'CheckGenerateFromSalesOrder' handler function + CreateNewSalesHeaderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions, Customer."No.", SalesHeader."Document Type"::Order); + // [THEN] Check all the 3 lines are inserted + CheckSalesLineContent(SalesLine, SalesHeader."No."); + end; + //-------------------------------------------------------------------------------------- + // Test cases for Sales Quote + [Test] + [HandlerFunctions('CheckGenerateFromSalesOrder')] + procedure TestCopySalesQuoteByDocNo() + var + Customer: Record Customer; + SalesHeader: Record "Sales Header"; + SalesLine: Record "Sales Line"; + CreatedItem: Record Item; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + begin + // [FEATURE] [Sales Line with AI] [Document Lookup] [Sales Quote] + // [SCENARIO] User input 'I want all the items from sales quote 10000' in current customer's sales order. System will find the quote and copy all the lines to the current sales order. + LibraryVariableStorage.Clear(); + LibrarySales.CreateCustomer(Customer); + // [GIVEN] Create sales quote for customer + LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Quote, Customer."No."); + // [GIVEN] Create 3 lines with item description and add it to the new sales order + Create3SalesLinesWithItemDescription(SalesHeader, SalesLine, CreatedItem); + LibraryVariableStorage.Enqueue(StrSubstNo(NeedAllItemFromSpecifiedSalesQuoteLbl, SalesHeader."No.")); + LibraryVariableStorage.Enqueue('3'); + Enqueue3SalesLineWithItemDescription(); + Enqueue3SalesLineWithItemDescription(); + // [WHEN] Create a new sales order for this customer and run Sales Line AI Suggestions Page to generate suggestions lines + // [THEN] Check that correct lines are generated in 'CheckGenerateFromSalesOrder' handler function + CreateNewSalesHeaderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions, Customer."No.", SalesHeader."Document Type"::Order); + // [THEN] Check all the 3 lines are inserted + CheckSalesLineContent(SalesLine, SalesHeader."No."); + end; + + [Test] + [HandlerFunctions('CheckGenerateFromSalesOrder')] + procedure TestCopySalesQuoteByDocNoWFromDifferentCustomer() + var + Customer: Record Customer; + Customer2: Record Customer; + SalesHeader: Record "Sales Header"; + SalesLine: Record "Sales Line"; + CreatedItem: Record Item; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + begin + // [FEATURE] [Sales Line with AI] [Document Lookup] [Sales Quote] + // [SCENARIO] User input 'I want all the items from sales quote 10000' in another customer's sales order. The system should generate 3 lines with item description and quantity. + LibraryVariableStorage.Clear(); + LibrarySales.CreateCustomer(Customer); + LibrarySales.CreateCustomer(Customer2); + // [GIVEN] Create a new sales order for the new customer + LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Quote, Customer."No."); + // [GIVEN] Create 3 lines with item description and add it to the new sales order + Create3SalesLinesWithItemDescription(SalesHeader, SalesLine, CreatedItem); + LibraryVariableStorage.Enqueue(StrSubstNo(NeedAllItemFromSpecifiedSalesQuoteLbl, SalesHeader."No.")); + LibraryVariableStorage.Enqueue('3'); + Enqueue3SalesLineWithItemDescription(); + Enqueue3SalesLineWithItemDescription(); + // [WHEN] Create a new sales order for this customer and run Sales Line AI Suggestions Page to generate suggestions lines + // [THEN] Check that correct lines are generated in 'CheckGenerateFromSalesOrder' handler function + CreateNewSalesHeaderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions, Customer2."No.", SalesHeader."Document Type"::Order); + // [THEN] Check all the 3 lines are inserted + CheckSalesLineContent(SalesLine, SalesHeader."No."); + end; + + [Test] + [HandlerFunctions('CheckGenerateFromSalesOrder')] + procedure TestCopySalesQuoteByExternalDocumentNo() + var + Customer: Record Customer; + Customer2: Record Customer; + SalesHeader: Record "Sales Header"; + SalesLine: Record "Sales Line"; + CreatedItem: Record Item; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + begin + // [FEATURE] [Sales Line with AI] [Document Lookup] [Sales Quote] + // [SCENARIO] User input 'I want all the items from sales quote EXT10000' in another customer's sales order. The system should generate 3 lines with item description and quantity. + LibraryVariableStorage.Clear(); + LibrarySales.CreateCustomer(Customer); + LibrarySales.CreateCustomer(Customer2); + // [GIVEN] Create a new sales order for the new customer + LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Quote, Customer."No."); + // [GIVEN] Update External Document No. + SalesHeader.Validate("External Document No.", 'EXTNO123456789123456789123456789123'); + SalesHeader.Modify(true); + // [GIVEN] Create 3 lines with item description and add it to the new sales order + Create3SalesLinesWithItemDescription(SalesHeader, SalesLine, CreatedItem); + LibraryVariableStorage.Enqueue(StrSubstNo(NeedAllItemFromSpecifiedSalesQuoteLbl, SalesHeader."External Document No.")); + LibraryVariableStorage.Enqueue('3'); + Enqueue3SalesLineWithItemDescription(); + Enqueue3SalesLineWithItemDescription(); + // [WHEN] Create a new sales order for this customer and run Sales Line AI Suggestions Page to generate suggestions lines + // [THEN] Check that correct lines are generated in 'CheckGenerateFromSalesOrder' handler function + CreateNewSalesHeaderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions, Customer2."No.", SalesHeader."Document Type"::Order); + // [THEN] Check all the 3 lines are inserted + CheckSalesLineContent(SalesLine, SalesHeader."No."); + end; + + [Test] + [HandlerFunctions('CheckGenerateFromSalesOrder')] + procedure TestCopySalesQuoteByQuoteNo() + var + Customer: Record Customer; + Customer2: Record Customer; + SalesHeader: Record "Sales Header"; + SalesLine: Record "Sales Line"; + CreatedItem: Record Item; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + begin + // [FEATURE] [Sales Line with AI] [Document Lookup] [Sales Quote] + // [SCENARIO] User input 'I want all the items from sales quote QTO214500' in another customer's sales order. The system should generate 3 lines with item description and quantity. + LibraryVariableStorage.Clear(); + LibrarySales.CreateCustomer(Customer); + LibrarySales.CreateCustomer(Customer2); + // [GIVEN] Create a new sales order for the new customer + LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Quote, Customer."No."); + SalesHeader.Validate("Quote No.", 'QTO214500'); + SalesHeader.Modify(true); + // [GIVEN] Create 3 lines with item description and add it to the new sales order + Create3SalesLinesWithItemDescription(SalesHeader, SalesLine, CreatedItem); + LibraryVariableStorage.Enqueue(StrSubstNo(NeedAllItemFromSpecifiedSalesQuoteLbl, SalesHeader."Quote No.")); + LibraryVariableStorage.Enqueue('3'); + Enqueue3SalesLineWithItemDescription(); + Enqueue3SalesLineWithItemDescription(); + // [WHEN] Create a new sales order for this customer and run Sales Line AI Suggestions Page to generate suggestions lines + // [THEN] Check that correct lines are generated in 'CheckGenerateFromSalesOrder' handler function + CreateNewSalesHeaderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions, Customer2."No.", SalesHeader."Document Type"::Order); + // [THEN] Check all the 3 lines are inserted + CheckSalesLineContent(SalesLine, SalesHeader."No."); + end; + + [Test] + [HandlerFunctions('CheckGenerateFromSalesOrder')] + procedure TestCopySalesQuoteByReferenceNo() + var + Customer: Record Customer; + Customer2: Record Customer; + SalesHeader: Record "Sales Header"; + SalesLine: Record "Sales Line"; + CreatedItem: Record Item; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + begin + // [FEATURE] [Sales Line with AI] [Document Lookup] [Sales Quote] + // [SCENARIO] User input 'I want all the items from sales quote QTO214500' in another customer's sales order. The system should generate 3 lines with item description and quantity. + LibraryVariableStorage.Clear(); + LibrarySales.CreateCustomer(Customer); + LibrarySales.CreateCustomer(Customer2); + // [GIVEN] Create a new sales order for the new customer + LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Quote, Customer."No."); + SalesHeader.Validate("Your Reference", 'REF214500'); + SalesHeader.Modify(true); + // [GIVEN] Create 3 lines with item description and add it to the new sales order + Create3SalesLinesWithItemDescription(SalesHeader, SalesLine, CreatedItem); + LibraryVariableStorage.Enqueue(StrSubstNo(NeedAllItemFromSpecifiedSalesQuoteLbl, SalesHeader."Your Reference")); + LibraryVariableStorage.Enqueue('3'); + Enqueue3SalesLineWithItemDescription(); + Enqueue3SalesLineWithItemDescription(); + // [WHEN] Create a new sales order for this customer and run Sales Line AI Suggestions Page to generate suggestions lines + // [THEN] Check that correct lines are generated in 'CheckGenerateFromSalesOrder' handler function + CreateNewSalesHeaderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions, Customer2."No.", SalesHeader."Document Type"::Order); + // [THEN] Check all the 3 lines are inserted + CheckSalesLineContent(SalesLine, SalesHeader."No."); + end; + + [Test] + [HandlerFunctions('CheckGenerateFromSalesOrder')] + procedure TestAmbiguouslyCopySalesQuoteByExternalDocumentNo() + var + Customer: Record Customer; + Customer2: Record Customer; + SalesHeader: Record "Sales Header"; + SalesLine: Record "Sales Line"; + CreatedItem: Record Item; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + begin + // [FEATURE] [Sales Line with AI] [Document Lookup] [Sales Quote] + // [SCENARIO] User input 'I want all the items from sales order EXT10000' in another customer's sales order. The system should generate 3 lines with item description and quantity. + LibraryVariableStorage.Clear(); + LibrarySales.CreateCustomer(Customer); + LibrarySales.CreateCustomer(Customer2); + // [GIVEN] Create a new sales order for the new customer + LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Quote, Customer."No."); + // [GIVEN] Update External Document No. + SalesHeader.Validate("External Document No.", 'EXTNO123456789123456789123456789123'); + SalesHeader.Modify(true); + // [GIVEN] Create 3 lines with item description and add it to the new sales order + Create3SalesLinesWithItemDescription(SalesHeader, SalesLine, CreatedItem); + LibraryVariableStorage.Enqueue(StrSubstNo(NeedAllItemFromSpecifiedSalesQuoteLbl, CopyStr(SalesHeader."External Document No.", 2, StrLen(SalesHeader."External Document No.") - 1))); + LibraryVariableStorage.Enqueue('3'); + Enqueue3SalesLineWithItemDescription(); + Enqueue3SalesLineWithItemDescription(); + // [WHEN] Create a new sales order for this customer and run Sales Line AI Suggestions Page to generate suggestions lines + // [THEN] Check that correct lines are generated in 'CheckGenerateFromSalesOrder' handler function + CreateNewSalesHeaderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions, Customer2."No.", SalesHeader."Document Type"::Order); + // [THEN] Check all the 3 lines are inserted + CheckSalesLineContent(SalesLine, SalesHeader."No."); + end; + + [Test] + [HandlerFunctions('CheckGenerateFromSalesOrder')] + procedure TestAmbiguouslyCopySalesQuoteByQuoteNo() + var + Customer: Record Customer; + Customer2: Record Customer; + SalesHeader: Record "Sales Header"; + SalesLine: Record "Sales Line"; + CreatedItem: Record Item; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + begin + // [FEATURE] [Sales Line with AI] [Document Lookup] [Sales Quote] + // [SCENARIO] There is an item with Quote Number 'QTO214500'. User input 'I want all the items from sales quote XTNO12345678912345678912345678912' in another customer's sales order. The system should generate 3 lines with item description and quantity. + LibraryVariableStorage.Clear(); + LibrarySales.CreateCustomer(Customer); + LibrarySales.CreateCustomer(Customer2); + // [GIVEN] Create a new sales order for the new customer + LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Quote, Customer."No."); + SalesHeader.Validate("Quote No.", 'QTO214500'); + SalesHeader.Modify(true); + // [GIVEN] Create 3 lines with item description and add it to the new sales order + Create3SalesLinesWithItemDescription(SalesHeader, SalesLine, CreatedItem); + LibraryVariableStorage.Enqueue(StrSubstNo(NeedAllItemFromSpecifiedSalesQuoteLbl, CopyStr(SalesHeader."Quote No.", 2, StrLen(SalesHeader."Quote No.") - 1))); + LibraryVariableStorage.Enqueue('3'); + Enqueue3SalesLineWithItemDescription(); + Enqueue3SalesLineWithItemDescription(); + // [WHEN] Create a new sales order for this customer and run Sales Line AI Suggestions Page to generate suggestions lines + // [THEN] Check that correct lines are generated in 'CheckGenerateFromSalesOrder' handler function + CreateNewSalesHeaderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions, Customer2."No.", SalesHeader."Document Type"::Order); + // [THEN] Check all the 3 lines are inserted + CheckSalesLineContent(SalesLine, SalesHeader."No."); + end; + + [Test] + [HandlerFunctions('CheckGenerateFromSalesOrder')] + procedure TestAmbiguouslyCopySalesQuoteByReferenceNo() + var + Customer: Record Customer; + Customer2: Record Customer; + SalesHeader: Record "Sales Header"; + SalesLine: Record "Sales Line"; + CreatedItem: Record Item; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + begin + // [FEATURE] [Sales Line with AI] [Document Lookup] [Sales Quote] + // [SCENARIO] There is an item with Reference Number 'REF214500'. User input 'I want all the items from sales quote XTNO12345678912345678912345678912' in another customer's sales order. The system should generate 3 lines with item description and quantity. + LibraryVariableStorage.Clear(); + LibrarySales.CreateCustomer(Customer); + LibrarySales.CreateCustomer(Customer2); + // [GIVEN] Create a new sales order for the new customer + LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Quote, Customer."No."); + SalesHeader.Validate("Your Reference", 'REF214500'); + SalesHeader.Modify(true); + // [GIVEN] Create 3 lines with item description and add it to the new sales order + Create3SalesLinesWithItemDescription(SalesHeader, SalesLine, CreatedItem); + LibraryVariableStorage.Enqueue(StrSubstNo(NeedAllItemFromSpecifiedSalesQuoteLbl, CopyStr(SalesHeader."Your Reference", 2, StrLen(SalesHeader."Your Reference") - 1))); + LibraryVariableStorage.Enqueue('3'); + Enqueue3SalesLineWithItemDescription(); + Enqueue3SalesLineWithItemDescription(); + // [WHEN] Create a new sales order for this customer and run Sales Line AI Suggestions Page to generate suggestions lines + // [THEN] Check that correct lines are generated in 'CheckGenerateFromSalesOrder' handler function + CreateNewSalesHeaderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions, Customer2."No.", SalesHeader."Document Type"::Order); + // [THEN] Check all the 3 lines are inserted + CheckSalesLineContent(SalesLine, SalesHeader."No."); + end; + + [Test] + [HandlerFunctions('CheckGenerateFromSalesOrder')] + procedure TestCopySalesQuoteByDate1() + var + Customer: Record Customer; + SalesHeader: Record "Sales Header"; + SalesLine: Record "Sales Line"; + CreatedItem: Record Item; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + StartDate: Date; + begin + // [FEATURE] [Sales Line with AI] [Document Lookup] [Sales Quote] + // [SCENARIO] User input 'I need all items from sales quote with posting date 01/01/2019' in current customer's sales order. System will find the quote and copy all the lines to the current sales order. + LibraryVariableStorage.Clear(); + LibrarySales.CreateCustomer(Customer); + // [GIVEN] Create a new sales order for the new customer + LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Quote, Customer."No."); + Evaluate(StartDate, '01/01/2019'); + SalesHeader.Validate("Posting Date", StartDate); + SalesHeader.Modify(true); + // [GIVEN] Create 3 lines with item description and add it to the new sales order + Create3SalesLinesWithItemDescription(SalesHeader, SalesLine, CreatedItem); + LibraryVariableStorage.Enqueue('I need all items from sales quote with posting date 01/01/2019'); + LibraryVariableStorage.Enqueue('3'); + Enqueue3SalesLineWithItemDescription(); + Enqueue3SalesLineWithItemDescription(); + // [WHEN] Create a new sales order for this customer and run Sales Line AI Suggestions Page to generate suggestions lines + // [THEN] Check that correct lines are generated in 'CheckGenerateFromSalesOrder' handler function + CreateNewSalesHeaderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions, Customer."No.", SalesHeader."Document Type"::Order); + // [THEN] Check all the 3 lines are inserted + CheckSalesLineContent(SalesLine, SalesHeader."No."); + end; + + [Test] + [HandlerFunctions('CheckNothingGeneratedFromSalesOrder')] + procedure TestCopySalesQuoteByDateFromAnotherCustomer() + var + Customer: Record Customer; + Customer2: Record Customer; + SalesHeader: Record "Sales Header"; + SalesLine: Record "Sales Line"; + CreatedItem: Record Item; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + StartDate: Date; + begin + // [FEATURE] [Sales Line with AI] [Document Lookup] [Sales Quote] + // [SCENARIO] User input 'I need all items from sales quote with posting date 01/01/2019' from another customer's sales order. System cannot find the order and should not generate any lines. + LibraryVariableStorage.Clear(); + LibrarySales.CreateCustomer(Customer); + LibrarySales.CreateCustomer(Customer2); + // [GIVEN] Create a new sales order for the new customer + LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Quote, Customer."No."); + Evaluate(StartDate, '01/01/2019'); + SalesHeader.Validate("Posting Date", StartDate); + SalesHeader.Modify(true); + // [GIVEN] Create 3 lines with item description and add it to the new sales order + Create3SalesLinesWithItemDescription(SalesHeader, SalesLine, CreatedItem); + LibraryVariableStorage.Enqueue('I need all items from sales quote with posting date 01/01/2019'); + // [WHEN] Create a new sales order for this customer and run Sales Line AI Suggestions Page to generate suggestions lines + // [THEN] Check no line is generated in 'CheckNothingGeneratedFromSalesOrder' handler function + CreateNewSalesHeaderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions, Customer2."No.", SalesHeader."Document Type"::Order); + // [THEN] Check no line is inserted to this document + CheckEmptySalesLineContent(SalesLine, SalesHeader."No."); + end; + + [Test] + [HandlerFunctions('CheckGenerateFromSalesOrder')] + procedure TestCopySalesQuoteByDateRange1() + var + Customer: Record Customer; + SalesHeader: Record "Sales Header"; + SalesLine: Record "Sales Line"; + CreatedItem: Record Item; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + StartDate: Date; + begin + // [FEATURE] [Sales Line with AI] [Document Lookup] [Sales Quote] + // [SCENARIO] User input 'I need all items from sales quote on January of 2019' in current customer's sales order. System will find the quote and copy all the lines to the current sales order. + LibraryVariableStorage.Clear(); + LibrarySales.CreateCustomer(Customer); + // [GIVEN] Create a new sales order for the new customer + LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Quote, Customer."No."); + Evaluate(StartDate, '01/01/2019'); + SalesHeader.Validate("Posting Date", StartDate); + SalesHeader.Modify(true); + // [GIVEN] Create 3 lines with item description and add it to the new sales order + Create3SalesLinesWithItemDescription(SalesHeader, SalesLine, CreatedItem); + LibraryVariableStorage.Enqueue('I need all items from sales quote on January of 2019'); + LibraryVariableStorage.Enqueue('3'); + Enqueue3SalesLineWithItemDescription(); + Enqueue3SalesLineWithItemDescription(); + // [WHEN] Create a new sales order for this customer and run Sales Line AI Suggestions Page to generate suggestions lines + // [THEN] Check that correct lines are generated in 'CheckGenerateFromSalesOrder' handler function + CreateNewSalesHeaderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions, Customer."No.", SalesHeader."Document Type"::Order); + // [THEN] Check all the 3 lines are inserted + CheckSalesLineContent(SalesLine, SalesHeader."No."); + end; + + [Test] + [HandlerFunctions('CheckGenerateFromSalesOrder')] + procedure TestCopySalesQuoteByDateRange2() + var + Customer: Record Customer; + SalesHeader: Record "Sales Header"; + SalesLine: Record "Sales Line"; + CreatedItem: Record Item; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + StartDate: Date; + begin + // [FEATURE] [Sales Line with AI] [Document Lookup] [Sales Quote] + // [SCENARIO] User input 'I need all items from sales quote from 2018-12-30 to 2019-Jan-5' in current customer's sales order. System will find the quote and copy all the lines to the current sales order. + LibraryVariableStorage.Clear(); + LibrarySales.CreateCustomer(Customer); + // [GIVEN] Create a new sales order for the new customer + LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Quote, Customer."No."); + Evaluate(StartDate, '01/01/2019'); + SalesHeader.Validate("Posting Date", StartDate); + SalesHeader.Modify(true); + // [GIVEN] Create 3 lines with item description and add it to the new sales order + Create3SalesLinesWithItemDescription(SalesHeader, SalesLine, CreatedItem); + LibraryVariableStorage.Enqueue('I need all items from sales quote from 2018-12-30 to 2019-Jan-5'); + LibraryVariableStorage.Enqueue('3'); + Enqueue3SalesLineWithItemDescription(); + Enqueue3SalesLineWithItemDescription(); + // [WHEN] Create a new sales order for this customer and run Sales Line AI Suggestions Page to generate suggestions lines + // [THEN] Check that correct lines are generated in 'CheckGenerateFromSalesOrder' handler function + CreateNewSalesHeaderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions, Customer."No.", SalesHeader."Document Type"::Order); + // [THEN] Check all the 3 lines are inserted + CheckSalesLineContent(SalesLine, SalesHeader."No."); + end; + //-------------------------------------------------------------------------------------- + + // Help functions + local procedure Create3SalesLinesWithItemDescription(var SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; var CreatedItem: Record Item) + begin + LibrarySales.CreateSimpleItemSalesLine(SalesLine, SalesHeader, "Sales Line Type"::Item); + LibraryInventory.CreateItem(CreatedItem); + CreatedItem.Validate(Description, Item1DescriptionLbl); + CreatedItem.Modify(true); + + SalesLine.Validate("No.", CreatedItem."No."); + SalesLine.Validate(Quantity, 5); + SalesLine.Modify(true); + + LibrarySales.CreateSimpleItemSalesLine(SalesLine, SalesHeader, "Sales Line Type"::Item); + LibraryInventory.CreateItem(CreatedItem); + CreatedItem.Validate(Description, Item2DescriptionLbl); + CreatedItem.Modify(true); + + SalesLine.Validate("No.", CreatedItem."No."); + SalesLine.Validate(Quantity, 3); + SalesLine.Modify(true); + + LibrarySales.CreateSimpleItemSalesLine(SalesLine, SalesHeader, "Sales Line Type"::Item); + LibraryInventory.CreateItem(CreatedItem); + CreatedItem.Validate(Description, Item3DescriptionLbl); + CreatedItem.Modify(true); + + SalesLine.Validate("No.", CreatedItem."No."); + SalesLine.Validate(Quantity, 2); + SalesLine.Modify(true); + LibraryVariableStorage.AssertEmpty(); + end; + + local procedure CreateSalesLinesWithItem1AndUoM(var ItemUoM: Record "Item Unit of Measure"; var SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; var CreatedItem: Record Item) + begin + LibrarySales.CreateSimpleItemSalesLine(SalesLine, SalesHeader, "Sales Line Type"::Item); + LibraryInventory.CreateItem(CreatedItem); + CreatedItem.Validate(Description, Item1DescriptionLbl); + CreatedItem.Modify(true); + LibraryInventory.CreateItemUnitOfMeasureCode(ItemUoM, CreatedItem."No.", 1); + SalesLine.Validate("No.", CreatedItem."No."); + SalesLine.Validate("Unit of Measure Code", ItemUoM."Code"); + SalesLine.Validate(Quantity, 5); + SalesLine.Modify(true); + end; + + local procedure CreateSalesLinesWithItem1(var SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; var CreatedItem: Record Item) + begin + LibrarySales.CreateSimpleItemSalesLine(SalesLine, SalesHeader, "Sales Line Type"::Item); + LibraryInventory.CreateItem(CreatedItem); + CreatedItem.Validate(Description, Item1DescriptionLbl); + CreatedItem.Modify(true); + + SalesLine.Validate("No.", CreatedItem."No."); + SalesLine.Validate(Quantity, 5); + SalesLine.Modify(true); + end; + + local procedure CreateSalesLinesWithItem4AndSalesBlock(var SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line"; var CreatedItem: Record Item) + begin + LibrarySales.CreateSimpleItemSalesLine(SalesLine, SalesHeader, "Sales Line Type"::Item); + LibraryInventory.CreateItem(CreatedItem); + CreatedItem.Validate(Description, Item4DescriptionLbl); + CreatedItem.Modify(true); + + SalesLine.Validate("No.", CreatedItem."No."); + SalesLine.Validate(Quantity, 5); + SalesLine.Modify(true); + + CreatedItem.Validate("Sales Blocked", true); + CreatedItem.Modify(true); + end; + + local procedure CreateNewSalesHeaderAndRunSalesLineAISuggestionsPage(var SalesHeader: Record "Sales Header"; var SalesLineAISuggestions: Page "Sales Line AI Suggestions"; CustomerNo: Code[20]; + DocumentType: Enum "Sales Document Type") + begin + SalesHeader.Reset(); + LibrarySales.CreateSalesHeader(SalesHeader, DocumentType, CustomerNo); + SalesLineAISuggestions.SetSalesHeader(SalesHeader); + SalesLineAISuggestions.LookupMode := true; + SalesLineAISuggestions.RunModal(); + end; + + local procedure CheckSalesLineContent(SalesLine: Record "Sales Line"; DocumentNo: Text) + begin + SalesLine.Reset(); + SalesLine.SetRange("Document No.", DocumentNo); + SalesLine.SetRange("Document Type", SalesLine."Document Type"::Order); + if SalesLine.FindSet() then + repeat + Assert.AreEqual(LibraryVariableStorage.DequeueText(), SalesLine.Description, DescriptionIsIncorrectErr); + Assert.AreEqual(LibraryVariableStorage.DequeueText(), SalesLine."Variant Code", VariantIsIncorrectErr); + Assert.AreEqual(LibraryVariableStorage.DequeueInteger(), SalesLine.Quantity, QuantityIsIncorrectErr); + until SalesLine.Next() = 0; + LibraryVariableStorage.AssertEmpty(); + end; + + + local procedure CheckSalesLineContentWithUoM(SalesLine: Record "Sales Line"; DocumentNo: Text) + begin + SalesLine.Reset(); + SalesLine.SetRange("Document No.", DocumentNo); + SalesLine.SetRange("Document Type", SalesLine."Document Type"::Order); + if SalesLine.FindSet() then + repeat + Assert.AreEqual(LibraryVariableStorage.DequeueText(), SalesLine.Description, DescriptionIsIncorrectErr); + Assert.AreEqual(LibraryVariableStorage.DequeueText(), SalesLine."Variant Code", VariantIsIncorrectErr); + Assert.AreEqual(LibraryVariableStorage.DequeueInteger(), SalesLine.Quantity, QuantityIsIncorrectErr); + Assert.AreEqual(LibraryVariableStorage.DequeueText(), SalesLine."Unit of Measure Code", UoMIsIncorrectErr); + until SalesLine.Next() = 0; + LibraryVariableStorage.AssertEmpty(); + end; + + local procedure CheckEmptySalesLineContent(SalesLine: Record "Sales Line"; DocumentNo: Text) + begin + SalesLine.Reset(); + SalesLine.SetRange("Document No.", DocumentNo); + SalesLine.SetRange("Document Type", SalesLine."Document Type"::Order); + Assert.IsFalse(SalesLine.FindFirst(), 'No sales line should be generated'); + end; + + local procedure EnqueueItem1() + begin + LibraryVariableStorage.Enqueue(Item1DescriptionLbl); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('5'); + end; + + local procedure EnqueueItem1WithUoM(UoM: Code[10]) + begin + LibraryVariableStorage.Enqueue(Item1DescriptionLbl); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('5'); + LibraryVariableStorage.Enqueue(UoM); + end; + + local procedure EnqueueItemWithVariantCode(VariantCode: Code[10]; Qty: Text) + begin + LibraryVariableStorage.Enqueue(VariantCode); + LibraryVariableStorage.Enqueue(VariantCode); + LibraryVariableStorage.Enqueue(Qty); + end; + + local procedure Enqueue3SalesLineWithItemDescription() + begin + LibraryVariableStorage.Enqueue(Item1DescriptionLbl); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('5'); + LibraryVariableStorage.Enqueue(Item2DescriptionLbl); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('3'); + LibraryVariableStorage.Enqueue(Item3DescriptionLbl); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('2'); + end; + + [ModalPageHandler] + procedure CheckGenerateFromSalesOrder(var SalesLineAISuggestions: TestPage "Sales Line AI Suggestions") + var + itemCount: Integer; + quantityInSalesLineSub: Integer; + i: Integer; + begin + // Description for this queue: + //[{User Input},{Expected Generated Number(shown in page)},{first item's description},{first item's quantity}, {second item's description}, {second item's quantity}...{last item's description}, {last item's quantity] + // Example: ['I need all items from previous sales order 10000', '3', 'red bike', 'variant code1', '2', 'blue bike','variant code2, '1', 'green bike', 'variant code3', '1'] + // Create a new sales order for the new customer + Commit(); + SalesLineAISuggestions.SearchQueryTxt.SetValue(LibraryVariableStorage.DequeueText()); + itemCount := LibraryVariableStorage.DequeueInteger(); + SalesLineAISuggestions.Generate.Invoke(); + SalesLineAISuggestions.SalesLinesSub.First(); + for i := 1 to itemCount do begin + Assert.AreEqual(LibraryVariableStorage.DequeueText(), SalesLineAISuggestions.SalesLinesSub.Description.Value(), DescriptionIsIncorrectErr); + Assert.AreEqual(LibraryVariableStorage.DequeueText(), SalesLineAISuggestions.SalesLinesSub."Variant Code".Value(), VariantIsIncorrectErr); + Evaluate(quantityInSalesLineSub, SalesLineAISuggestions.SalesLinesSub.Quantity.Value()); + Assert.AreEqual(LibraryVariableStorage.DequeueInteger(), quantityInSalesLineSub, QuantityIsIncorrectErr); + SalesLineAISuggestions.SalesLinesSub.Next(); + end; + SalesLineAISuggestions.OK.Invoke(); + end; + + [ModalPageHandler] + procedure CheckNothingGeneratedFromSalesOrder(var SalesLineAISuggestions: TestPage "Sales Line AI Suggestions") + begin + SalesLineAISuggestions.SearchQueryTxt.SetValue(LibraryVariableStorage.DequeueText()); + SalesLineAISuggestions.Generate.Invoke(); + end; + + [SendNotificationHandler] + procedure SendNotificationHandler(var TheNotification: Notification): Boolean + begin + Assert.AreEqual(LibraryVariableStorage.DequeueText(), TheNotification.Message, 'Notification message is incorrect'); + end; +} \ No newline at end of file diff --git a/Apps/W1/SalesLinesSuggestions/test/ExtensionLogo.png b/Apps/W1/SalesLinesSuggestions/test/ExtensionLogo.png new file mode 100644 index 0000000000000000000000000000000000000000..4d2c9a626cb9617350617c40cd73904129d4c108 GIT binary patch literal 5446 zcma)=S5VVywD$iAMIcgC2u+$uktV%J6$Dhev_NQrfC^Fsq!|cJ=^|Z`P&U*^N-uuwi#_w5i!*aB*89x5SkKKnv*ua91anhEW+omc005Zp+`e`1 zOsW4C1O3^nWxbYuCX9Z!?E(M*a`E2+jm<_J0|5K}om)4pLZ&wJ&3t(K(|ffcq#?ky z#^aeQO#|lO9vyUeb0ezqQtpipl3Sj#-xy!eh7lu@5+BnW zNhL-~3Zpw&1u=bMN*Q(sgYksq4dM>Iw7p&Qk_Su~b*PgEs#LK~^K}aDaTG_6Q?_tM<8wOS}`Z+?~Et8GB>T%(k7$9`DL!d5)f!ZoXco-vj+s_QLEs2cf zKM&F>#c9w|TmM9MFtl8L*cYQgl9khf5CYMR)DJOUf;M~a9|+ys@RYR zCusNC(CSlUk|r`qdS&ZKh$O=@#&e0>;W~S#|KjHdfLx!-J9r1JtP4RGIhS|Rm0eZ6 z7eOE~Zfo4Li~K^|&)d^-r?8Rh2Q}#ZjL=?VJZ7~hlp4(!U!0K%679I`OR&x54*0&4 znho|hKu)WR)4PUVA1}N;jXHg}AG+gSKQ6O_fEP^Y51!LwBERH09|t!GNx2KH4co>r zA%cgSHxh2Sezx-w!S5DTG#0zVCbnLM6BP}2P-G{8 zh**wJHj<652FS05bSQNx-0fS7^(wREYvZwpt;$!!k4H0U*iyhS8(syBDMv>L<)~LI zPl!Y^-cM{_J@{hY1=XJ#T=Ef(FD!I^r1^lca3c0ftVuvo-(%!Zn)C1bK{}-i*Jc); zIIc+o&iMgvboj&4`@5sF23MV!*zIVmA0>{1;*H*faMAG6EZ7XydTfaGyABAGx>)yl z@Y+|)SVxCx@!GWqspay7GBetK*s2@CJ?s{8v!(b|ShLb|O;3T1rAMB?DJ?Z`@013q zoyIvV84eYiS+?kRJOz`3AFcR~ZQ1Uq7wCnbSJ%-HZwhAnJ^4zDp2W8I)~WI7ush5> z&f3O)rj~2ZGr!c@=p3!n>jG-O#9`$7&WyF7bB}(rq4ldokUp5TY?E62r+YJbJp8Jf znDW3fYZ^nBQ9O}3?zH_*mZ9+G#HHnwop1Vfm!Df~{Z%D?5KzMN&RA>&#q8iCzTfAt zV#TyMeyyh8=M$8tyA|KeUwo_Q6Si)P)%n(W-*QE~08BG|>J!sQPq?IF;;%1ypP?Z` zK_0Un>p;9=9d675ELHboC0+fNMY&(;k(|=0TS>ka)BKI3q#)zx!Jp@zv0QfeEAjU< z=vI5@-d^A^-*#|P+b2QFiGxk4z<8Tp4p6{aOp88x>SQEa0M`VxX%IUb$bya!5EgRf6$fFw zp}jNTKUXjNe0x(;)Nu)Ij5K?QD0u6~mRHQ-!;6m#VP>)}=irAqy;f$e{W-EWnR75~ zm2b0u@r7ASk4x0oTqs9{f&F|eAmD*Gf^A;te7f}J{dXqLaH_4%D_(mnp0VmWhq>^E z&7>5*-mh>FX{w5SJf^#th&GrpOQk58U-+4 zq3$q~C4ySH7@lr>W+|c0`UF*ieC+3vC1$4m}F(ic|G7}QDt(t z7`#>$c4U-4LU_;nWHhdN9Fcv~L8h6M_}nW&EGTjgW(=c}uD9>eU^rDOrkNg_effOV z^8z_y=vNIt{`wOfgG2o^3ey`R!aP1=t7Mz@&MKK3>_BH_QkgNO@4IoQ-2d8EqsDg) zTMb-5lqlubRot-7!RD@+udO?O9_Da3XV5bvjW zXTb2psHUdeiIaI(lknQE_<+YlY31}R!VfoM_BuILQ{>Q89=LB5j;V|-yAW2gY82+~ zYlu~#*R(cHw2NO1h5xaiAD2oiIEQ-aQyA-D^y^z2ZHNfM{o(3M#SbqOP3>k9FOdDO z(t%c9hk)NCPe_8>=Y^U-_-6IwS-D0cE=pwdyLp!;r-fWiXtbUS$<dl!~WV$TR8 zP$KU?K>m?*O)mSGccn&kn|nj7NXFeo<0D=ue8s^~BK#P?J~gB}v5<0nK9GPipjT#9 zkm6yXFyLlgoUIDEVxw*0Z-WDqp8swCs(bcjAqdDLl1oUqYf#a`NjT6IO3?=P`FvUZ zlWC&lWb9_dexSz%N~-oscM`oC%b#KS|KS7AptwRX5h&1VDCKWzP{&??TFdF3h53&c zU(v)WhOr)#!V6Y6d7CzOO-@KF%@67>kh34@Exj7Rh}p5_0?yUeyC7@c7DHf+mW=~wpLeLYDA9#W-Ri*S|M@g zjPHH@qHrPuzq(+5y$V*UoFEg(g$$mRNUEF!C{IN3Rig{tU54W|OD_`M0G3u)B{WhC z*D?hTF7J+YdF8-Z-Uuw{3jBx`_!aus`uDDBecwuu&tsVpj2~DZJb2-!a2l??m{}er}lR6Lqu)-2+Vm)jr(g{nfQPx9-<^1d;k-d zkU{E^g7qwp+D`b+QtU5@+swaVKp9<`>sT~U)O!EEMBo!*)~s_<`6Yl z7fX2;ki>kVDfdietW1k;TYvaY({>?5X)&(d&_y<-J7Qa@b z(zwGCI=`P#^b>1>2#Y!9T5|AdtaU|zXxw9^KpIu6CAmQf$GzaeOJmYVsc3eh5%6lb z)t~(Ak2J`;KW_L6psME-h?xF6ryr4d{q;>-b`Q$L43T{r`{N?U6cqP(Q3f%kA8`c@ z<82KXjte|7u_Lo~MV!d%y$tYi(hzU$6t+*ml~Z&Mg{eK?@}^XEBK+-&j`Uv95x)=_ zZLs=Mpg_IuZenjm(~}b8Aggaaje8NX$A_7^G%-)!xtu)C{N|S<3hVOmU;{|i+q6zn zfr(1Ua*jF!%-dU3L}O2fvWAe%-4kxtXo_vJHF(AxSx)4AI8-$^uBQO_86Z_y%RZX4 zJpu5`pOAztxv?jXv9yx|r>#9!0|`71C-fli@v${6r+V$hgvcr|W_I`{=7*0s(PKQH zzn8r2+tSeD15stz|DIJ3%X%8EkyN?bsHhuq4(5D0Oewn_)-o)Nx$eNs{0V*ZTSVt4 z3ifXGGw5fBv+9b6d~Nl+08L4VbbZqf3DL^e?l@!uZVdWkdOpJPaE?{zF!ZI?c(vF3 zvX~OK4vktvm&R$MgNpiKA~&zT!1#H7!q1h7AQiuSNG9<=$64)Zym(UQ``(j#^hDzt}{aur0pS?mmBi&z4I0Jfieqh%Pa_A%N?_1OZHm-S{ zQ*)4(N_J;y7tRh0o>xs25-s9!M-)i;@I68#SGXB2XgS}N zx_r3%V)z1jLA_M&?)E^DT$kzdHMJF%e2w6BH@iI5tKWM+zcuhCsz@N0a_1RBvrdZx zjzD>V%;c4*$RkEv{zHuVyaB+ANl(iT8w{pJdziC7YcO2&(ciqGLhs@q-dNh! zkV_V_(_~$*>ND}j1yozMedYnu-_GKMh?IpP<@D+edeB4M%3@xr3oj{@mdFKoBVpm^)1_}Y^}rOWBSB|Uv)*-pTdiU ztW9~{qq5@iB+$QpbeJVKH^n^9vV})i>Z@2CHoY2$PC888c;#Yz-pHRK@EVheWhE!> zZzjPmy?0Ni8#=o_k6_s3DY7nS^&Bm}BW&ZfAuF7bQbDgAGM$dE)RM6RvdobKb&MhsYD4exRm9*jcHPjbz#rI?vj$u zPLF5Gjv|8}?ta9`&^H}Va3H;llghU-BC7pxo6?-eTP`7CUZHJrw{5 zhkDYeIYlhL%brQJ1X#<#fz#E}Z87Kj=Hde*f{l|A`9E my8jz0{9hgZgN;Rh%;ug!HJ{lE_@04L;EulOt!iDD=>G@$cU!Ii literal 0 HcmV?d00001 diff --git a/Apps/W1/SalesLinesSuggestions/test/MagicFunctionPromptTest.Codeunit.al b/Apps/W1/SalesLinesSuggestions/test/MagicFunctionPromptTest.Codeunit.al new file mode 100644 index 0000000000..fc332d165c --- /dev/null +++ b/Apps/W1/SalesLinesSuggestions/test/MagicFunctionPromptTest.Codeunit.al @@ -0,0 +1,597 @@ +namespace Microsoft.Sales.Document.Test; + +codeunit 139782 "Magic Function Prompt Test" +{ + Subtype = Test; + TestPermissions = Disabled; + EventSubscriberInstance = Manual; + + trigger OnRun() + begin + // [FEATURE] [Sales with AI]:[Magic Function] [Prompt] + end; + + var + // Prompt with unsupported intent + MagicFunctionPrompt01Lbl: Label 'Hello! Could you do a quick review of items from recent sales orders? Just a general stock check. Thanks!'; + MagicFunctionPrompt02Lbl: Label 'Do not copy lines from latest invoice'; + MagicFunctionPrompt03Lbl: Label 'Help me check if I bring my favorite bag. '; + MagicFunctionPrompt04Lbl: Label 'Hey, what''s the status on order MNDKH676? Thanks'; + MagicFunctionPrompt05Lbl: Label 'Hey! Can you assess the items receiving 5-star reviews from our previous sales order? I need them for customer satisfaction analysis. Thanks a lot! '; + MagicFunctionPrompt06Lbl: Label 'There was an issue in the sales quote you sent me, you need to remove the Keyboards IUYWE987 from it.'; + MagicFunctionPrompt07Lbl: Label 'Can you check for any damaged goods in sales invoice 55566? We need to process returns or replacements. '; + MagicFunctionPrompt08Lbl: Label 'Could you help me find the most popular products from the last month? Thanks!'; + MagicFunctionPrompt09Lbl: Label 'I need check the new client information.'; + MagicFunctionPrompt10Lbl: Label 'Subject: Request for Services\n\nDear [Your Name],\n\nI hope this email finds you well. I am writing to inquire about the services offered by your company. I am interested in the following services:\n\n- **Social Media Marketing**\n- **Search Engine Optimization**\n- **Content Writing**\n\nCould you please provide me with more information about these services? Specifically, I would like to know the pricing, the duration of each service, and the expected results.\n\nI would appreciate it if you could send me the requested information as soon as possible. Please let me know if you need any further information from me.\n\nThank you for your attention to this matter.\n\nBest regards,\n\nLinda Johnson\n'; + MagicFunctionPrompt11Lbl: Label 'Subject: Inquiry about your web design services\n\nHello,\n\nI am Jane Smith, the marketing manager of ABC Inc., a company that sells organic beauty products online. I came across your website and I was impressed by your portfolio of web design projects.\n\nI am interested in hiring you to create a new website for our company, as we are planning to launch a new line of products soon. We want a website that is modern, user-friendly, and reflects our brand identity and values.\n\nCould you please send me a quote for your web design services, along with some samples of your previous work that are relevant to our industry? Also, what is your availability and timeline for this project?\n\nI look forward to hearing from you soon.\n\nSincerely,\nJane Smith\nMarketing Manager\nABC Inc.'; + MagicFunctionPrompt12Lbl: Label 'Subject: Request for your video editing services\n\nHi,\n\nI am John Doe, the founder and CEO of XYZ Ltd., a company that produces educational videos for online learning platforms. I saw your website and I was amazed by your video editing skills and creativity.\n\nI am interested in working with you to edit some of our videos, as we are expanding our content and reaching new audiences. We need a video editor who can enhance the quality, clarity, and engagement of our videos, as well as add some animations, transitions, and effects.\n\nCould you please let me know your rates for your video editing services, along with some examples of your previous work that are similar to our niche? Also, how many videos can you handle per month and what is your turnaround time?\n\nI hope to hear from you soon.\n\nBest regards,\nJohn Doe\nFounder and CEO\nXYZ Ltd.\njohn.doe at xyz.com\n'; + MagicFunctionPrompt13Lbl: Label 'Subject: Request for Meeting: Q2 Strategy Review\n\nDear John Doe,\n\nI hope this message finds you well. I am writing to request a meeting to discuss our strategy for the upcoming quarter. Given the recent changes in the market, it''s crucial that we align our objectives and action plans to stay competitive.\n\nI propose we meet on April 15th at 10:00 AM via Zoom. The agenda will include a review of our Q2 goals, an analysis of our current performance, and a brainstorming session for innovative approaches to our challenges.\n\nPlease let me know if this time works for you or if we need to find an alternative.\n\nBest regards,\nJane Smith\nOperations Manager'; + MagicFunctionPrompt14Lbl: Label 'Subject: Weekly Update: Project Alpha\n\nDear Team,\n\nI hope everyone is doing well. Here''s our weekly update on Project Alpha:\n\n- Progress: We''ve completed 70% of the development phase. The team resolved several critical bugs, and the new features are now in the testing stage.\n- Challenges: We encountered some delays due to unexpected technical issues, but the team is working diligently to address them.\n- Next Steps: Focus on completing the testing phase by the end of next week and begin preparations for the launch phase.\n\nPlease ensure that your tasks are on track and report any issues as soon as possible.\n\nBest,\nAlex Johnson\nProject Manager'; + MagicFunctionPrompt15Lbl: Label 'Subject: Important: Updated Work-from-Home Policy\n\nDear Team,\n\nAs part of our ongoing efforts to ensure a safe and productive work environment, we have updated our work-from-home policy. The key changes include:\n\n- Eligibility: All employees with more than six months of tenure are now eligible for up to three days of remote work per week.\n- Equipment: The company will provide necessary equipment for a home office setup, subject to approval.\n- Productivity: Regular check-ins and performance reviews will be conducted to ensure productivity levels remain high.\n\nPlease review the attached policy document for detailed information and feel free to reach out to HR with any questions or concerns.\n\nBest regards,\nEmily White\nHR Manager'; + MagicFunctionPrompt16Lbl: Label 'Subject: Seeking Your Feedback: New Product Launch\n\nDear Michael Brown,\n\nI hope you''re doing well. As you know, we recently launched our new product, WidgetX, and we''re eager to hear your thoughts. Your feedback is invaluable to us as we strive to improve and meet your needs.\n\nPlease take a few moments to fill out this short survey: [Survey Link]\n\nWe appreciate your time and look forward to your insights.\n\nBest regards,\nLisa Green\nProduct Manager'; + MagicFunctionPrompt17Lbl: Label 'Subject: Exclusive Offer: 20% Off Our Best-Selling Products!\n\nDear Valued Customer,\n\nWe''re excited to announce a special promotion exclusively for our loyal customers. Enjoy 20% off our best-selling products from now until April 30th. Don''t miss this opportunity to stock up on your favorites!\n\nVisit our website to start shopping: [Website Link]\n\nBest regards,\nEmma Thompson\nMarketing Manager\nTech Gadgets Inc.'; + MagicFunctionPrompt18Lbl: Label 'Subject: Introducing Our New Personalized Financial Planning Service\n\nDear Clients,\n\nWe''re thrilled to announce the launch of our new personalized financial planning service. Our team of experts is ready to help you achieve your financial goals with tailor-made solutions. Schedule your consultation today!\n\nBest,\nMichael Clark\nCEO\nWealth Management Co.'; + MagicFunctionPrompt19Lbl: Label 'Subject: Important Safety Notice: Product Recall Information\n\nDear Customer,\n\nYour safety is our top priority. We''re issuing a recall for our Model X Blender due to a potential safety issue. Please stop using the product immediately and contact us for a free replacement or refund.\n\nBest regards,\nSarah Johnson\nCustomer Service Manager\nHome Appliance World'; + MagicFunctionPrompt20Lbl: Label 'Subject: Congratulations! Job Offer from Creative Design Studio\n\nDear Jane Doe,\n\nWe''re pleased to offer you the position of Graphic Designer at Creative Design Studio. We were impressed by your portfolio and believe you''ll be a great addition to our team. Please review the attached offer letter and let us know your decision by April 10th.\n\nBest,\nDavid Lee\nHR Director\nCreative Design Studio'; + MagicFunctionPrompt21Lbl: Label 'Subject: You''re Invited: Grand Opening of Our New Store!\n\nDear [Name],\n\nJoin us for the grand opening of our new store on April 20th! Enjoy exclusive discounts, refreshments, and a chance to win exciting prizes. RSVP now to secure your spot!\n\nBest,\nEmily White\nEvent Coordinator\nFashion Forward Boutique'; + MagicFunctionPrompt22Lbl: Label 'Subject: We Value Your Feedback: Take Our Quick Survey!\n\nDear Valued Customer,\n\nWe strive to provide the best service possible and would love to hear your feedback. Please take a few minutes to complete our survey and help us improve. As a token of our appreciation, you''ll be entered into a draw to win a $50 gift card!\n\nBest,\nAlex Johnson\nCustomer Relations Manager\nTech Solutions Corp.'; + MagicFunctionPrompt23Lbl: Label 'Subject: New Features in the Latest Software Update\n\nDear Users,\n\nWe''re excited to announce the latest update for our software, which includes new features and performance improvements. Update now to enhance your experience and take advantage of the new functionalities.\n\nBest regards,\nSarah Lee\nProduct Manager\nInnovative Software Solutions'; + MagicFunctionPrompt24Lbl: Label 'Subject: Announcing Our Strategic Partnership with Eco-Friendly Solutions\n\nDear Stakeholders,\n\nWe''re proud to announce our partnership with Eco-Friendly Solutions to promote sustainable business practices. This collaboration aligns with our commitment to environmental responsibility and will bring exciting new opportunities.\n\nBest,\nJohn Smith\nCEO\nGreenTech Industries'; + MagicFunctionPrompt25Lbl: Label 'Subject: Congratulations to Our Employee of the Month: Jane Doe!\n\nDear Team,\n\nWe''re thrilled to announce that Jane Doe has been awarded Employee of the Month for her outstanding contributions and dedication. Join us in congratulating Jane on this well-deserved recognition!\n\nBest,\nDavid Brown\nHR Manager\nDynamic Enterprises'; + MagicFunctionPrompt26Lbl: Label 'Subject: Join Us in Supporting the Annual Charity Run for Children''s Health\n\nDear Community Members,\n\nWe''re honored to be the main sponsor for this year''s Charity Run for Children''s Health. We invite you to join us in supporting this important cause and making a difference in the lives of children in need.\n\nBest,\nEmily Thompson\nCommunity Relations Manager\nHealthy Futures Foundation'; + MagicFunctionPrompt27Lbl: Label 'Subject: Reminder: Upcoming Supplier Contract Renewal\n\nDear [Supplier Name],\n\nThis is a friendly reminder that our contract is up for renewal on May 1st. We value our partnership and look forward to discussing the terms for the upcoming year. Please let us know a convenient time for a meeting.\n\nBest regards,\nJohn Doe\nProcurement Manager\nManufacturing Excellence Inc.'; + MagicFunctionPrompt28Lbl: Label 'Subject: We''d Love to Hear Your Thoughts on Our New Product!\n\nDear [Name],\n\nThank you for purchasing our latest product. We''re eager to hear your feedback and would appreciate it if you could take a moment to share your experience. Your insights help us improve and serve you better.\n\nBest,\nJane Smith\nProduct Development Manager\nInnovative Gadgets Co.'; + MagicFunctionPrompt29Lbl: Label 'Subject: Upcoming Employee Training Session: Enhancing Customer Service Skills\n\nDear Team,\n\nWe''re hosting a training session on enhancing customer service skills on April 25th. This session is a great opportunity for professional development and improving our service standards. Please confirm your attendance by April 20th.\n\nBest,\nDavid Johnson\nTraining Coordinator\nService Excellence Corp.'; + MagicFunctionPrompt30Lbl: Label 'Subject: Important Update: Price Adjustment for Our Services\n\nDear Valued Clients,\n\nDue to rising operational costs, we''ll be implementing a slight price adjustment for our services effective May 1st. We''re committed to maintaining the quality of our offerings and appreciate your understanding.\n\nBest regards,\nSarah Williams\nFinance Manager\nProfessional Services Ltd.'; + MagicFunctionPrompt31Lbl: Label 'Subject: Introducing Our New Employee Wellness Program\n\nDear Team,\n\nWe''re excited to launch our new Employee Wellness Program, which includes health workshops, gym memberships, and mental health support. We believe in the importance of a healthy work-life balance and are committed to your well-being.\n\nBest,\nEmily Brown\nHR Director\nWellness at Work Inc.'; + MagicFunctionPrompt32Lbl: Label 'Subject: We''re Expanding: New Office Opening in New York!\n\nDear Stakeholders,\n\nWe''re thrilled to announce the opening of our new office in New York! This expansion marks a significant milestone in our growth journey, and we''re excited about the opportunities it brings.\n\nBest,\nJohn Smith\nCEO\nGlobal Enterprises Inc.'; + MagicFunctionPrompt33Lbl: Label 'Subject: Introducing Our Exclusive Customer Loyalty Program\n\nDear Valued Customer,\n\nWe''re excited to introduce our new Customer Loyalty Program, designed to reward your continued support. Enjoy exclusive discounts, early access to sales, and more. Sign up now to start earning rewards!\n\nBest,\nJane Doe\nMarketing Director\nRetail Rewards Co.'; + MagicFunctionPrompt34Lbl: Label 'Subject: Holiday Closure Notice: Office Closed on May 27th\n\nDear Clients,\n\nPlease note that our office will be closed on May 27th in observance of Memorial Day. We will resume normal business hours on May 28th. We appreciate your understanding and wish you a happy holiday.\n\nBest regards,\nDavid Lee\nOperations Manager\nProfessional Services Firm'; + MagicFunctionPrompt35Lbl: Label 'Subject: You''re Invited: Team Building Event at Escape Room Adventure\n\nDear Team,\n\nJoin us for a fun-filled team building event at Escape Room Adventure on April 30th! It''s a great opportunity to bond with colleagues and put our problem-solving skills to the test. RSVP by April 25th.\n\nBest,\nEmily Johnson\nEvent Coordinator\nDynamic Team Inc.'; + MagicFunctionPrompt36Lbl: Label 'Subject: Urgent System Maintenance: Temporary Service Interruption\n\nDear Users,\n\nWe''ll be performing urgent system maintenance on April 16th, resulting in temporary service interruption from 10:00 PM to 2:00 AM. We apologize for any inconvenience and appreciate your understanding.\n\nBest regards,\nAlex Smith\nIT Manager\nTech Solutions Corp.'; + MagicFunctionPrompt37Lbl: Label 'Subject: Exciting News: New Branch Opening in Downtown!\n\nDear Valued Clients,\n\nWe''re thrilled to announce the opening of our new branch in downtown! Come visit us starting May 1st for personalized services and special opening offers. We look forward to serving you in our new location.\n\nBest,\nJane Johnson\nBranch Manager\nBanking Solutions Inc.'; + MagicFunctionPrompt38Lbl: Label 'Subject: Join Our Volunteer Program: Making a Difference Together\n\nDear Employees,\n\nWe''re proud to launch our Volunteer Program, offering opportunities to give back to the community and make a positive impact. Sign up to participate in our upcoming volunteer events and help us make a difference together.\n\nBest,\nDavid Williams\nCommunity Outreach Coordinator\nCorporate Cares Foundation'; + MagicFunctionPrompt39Lbl: Label 'Subject: Notice of Product Discontinuation: Last Chance to Purchase\n\nDear Customers,\n\nWe regret to inform you that We''ll be discontinuing our Classic Model X Watch. This is your last chance to purchase this timeless piece before it''s gone. Thank you for your support over the years.\n\nBest regards,\nSarah Johnson\nProduct Manager\nLuxury Watches Co.'; + MagicFunctionPrompt40Lbl: Label 'Subject: Important Cybersecurity Alert: Protect Your Account\n\nDear Users,\n\nWe''ve detected suspicious activity and urge you to update your passwords and enable two-factor authentication to protect your account. Your security is our top priority, and We''re here to assist with any concerns.\n\nBest,\nAlex Thompson\nCybersecurity Analyst\nSecureTech Solutions'; + MagicFunctionPrompt41Lbl: Label 'Subject: Invitation to Collaborate on Cutting-Edge Research Project\n\nDear Dr. Smith,\n\nWe''re reaching out to invite you to collaborate on our cutting-edge research project in renewable energy. Your expertise would be invaluable to our team, and we believe this partnership could lead to groundbreaking discoveries.\n\nBest,\nJane Williams\nResearch Director\nInnovative Energy Solutions'; + MagicFunctionPrompt42Lbl: Label 'Subject: Apply Now: Summer Internship Program at Creative Media Agency\n\nDear Students,\n\nWe''re excited to announce our Summer Internship Program, offering hands-on experience in digital marketing, content creation, and more. Apply by May 15th for an opportunity to kickstart your career in the creative industry.\n\nBest,\nDavid Johnson\nInternship Coordinator\nCreative Media Agency'; + MagicFunctionPrompt43Lbl: Label 'Subject: Annual Supplier Performance Review: Your Feedback is Valuable\n\nDear [Supplier Name],\n\nAs part of our commitment to quality, We''re conducting our annual supplier performance review. We value your partnership and would appreciate your feedback on our collaboration over the past year. Please complete the attached survey by April 30th.\n\nBest regards,\nJohn Doe\nSupply Chain Manager\nManufacturing Excellence Inc.'; + MagicFunctionPrompt44Lbl: Label 'Subject: Update on Crisis Management Efforts: Ensuring Business Continuity\n\nDear Stakeholders,\n\nWe want to update you on our crisis management efforts in response to the recent challenges. Our team is working tirelessly to ensure business continuity and mitigate impacts. We''re committed to keeping you informed and supported during this time.\n\nBest,\nSarah Lee\nCEO\nResilient Enterprises Inc.'; + MagicFunctionPrompt45Lbl: Label 'Subject: Invitation to Our Annual General Meeting\n\nDear Shareholders,\n\nWe cordially invite you to our Annual General Meeting on June 10th. This is an opportunity to discuss our achievements, financial performance, and future plans. Please RSVP by May 31st.\n\nBest regards,\nJane Smith\nCorporate Secretary\nGlobal Holdings Ltd.'; + MagicFunctionPrompt46Lbl: Label 'Subject: Our Commitment to Sustainability: Introducing Eco-Friendly Packaging\n\nDear Customers,\n\nWe''re excited to announce our new eco-friendly packaging initiative, part of our commitment to sustainability. This change will reduce our environmental impact while maintaining the quality of our products. We appreciate your support in this endeavor.\n\nBest,\nDavid Brown\nEnvironmental Sustainability Manager\nEcoFriendly Products Co.'; + + // Prompt with Future Date + MagicFunctionPrompt47Lbl: Label 'Need all the items from sales order from last month to next week'; + MagicFunctionPrompt48Lbl: Label 'Need all the items from sales invoice on next week'; + MagicFunctionPrompt49Lbl: Label 'Need all the items from sales invoice from last month to next week'; + MagicFunctionPrompt50Lbl: Label 'Need all the items from sales shipment on next week'; + MagicFunctionPrompt51Lbl: Label 'Need all the items from sales Quote on next week'; + MagicFunctionPrompt52Lbl: Label 'Need all the items from sales Quote from last month to next week'; + + [Test] + procedure TestMagicFunctionPrompt01() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, MagicFunctionPrompt01Lbl); + TestUtil.CheckMagicFunction(CallCompletionAnswerTxt); + end; + + [Test] + procedure TestMagicFunctionPrompt02() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, MagicFunctionPrompt02Lbl); + TestUtil.CheckMagicFunction(CallCompletionAnswerTxt); + end; + + [Test] + procedure TestMagicFunctionPrompt03() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, MagicFunctionPrompt03Lbl); + TestUtil.CheckMagicFunction(CallCompletionAnswerTxt); + end; + + [Test] + procedure TestMagicFunctionPrompt04() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, MagicFunctionPrompt04Lbl); + TestUtil.CheckMagicFunction(CallCompletionAnswerTxt); + end; + + [Test] + procedure TestMagicFunctionPrompt05() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, MagicFunctionPrompt05Lbl); + TestUtil.CheckMagicFunction(CallCompletionAnswerTxt); + end; + + [Test] + procedure TestMagicFunctionPrompt06() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, MagicFunctionPrompt06Lbl); + TestUtil.CheckMagicFunction(CallCompletionAnswerTxt); + end; + + [Test] + procedure TestMagicFunctionPrompt07() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, MagicFunctionPrompt07Lbl); + TestUtil.CheckMagicFunction(CallCompletionAnswerTxt); + end; + + [Test] + procedure TestMagicFunctionPrompt08() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, MagicFunctionPrompt08Lbl); + TestUtil.CheckMagicFunction(CallCompletionAnswerTxt); + end; + + [Test] + procedure TestMagicFunctionPrompt09() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, MagicFunctionPrompt09Lbl); + TestUtil.CheckMagicFunction(CallCompletionAnswerTxt); + end; + + [Test] + procedure TestMagicFunctionPrompt10() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, MagicFunctionPrompt10Lbl); + TestUtil.CheckMagicFunction(CallCompletionAnswerTxt); + end; + + [Test] + procedure TestMagicFunctionPrompt11() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, MagicFunctionPrompt11Lbl); + TestUtil.CheckMagicFunction(CallCompletionAnswerTxt); + end; + + [Test] + procedure TestMagicFunctionPrompt12() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, MagicFunctionPrompt12Lbl); + TestUtil.CheckMagicFunction(CallCompletionAnswerTxt); + end; + + [Test] + procedure TestMagicFunctionPrompt13() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, MagicFunctionPrompt13Lbl); + TestUtil.CheckMagicFunction(CallCompletionAnswerTxt); + end; + + [Test] + procedure TestMagicFunctionPrompt14() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, MagicFunctionPrompt14Lbl); + TestUtil.CheckMagicFunction(CallCompletionAnswerTxt); + end; + + [Test] + procedure TestMagicFunctionPrompt15() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, MagicFunctionPrompt15Lbl); + TestUtil.CheckMagicFunction(CallCompletionAnswerTxt); + end; + + [Test] + procedure TestMagicFunctionPrompt16() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, MagicFunctionPrompt16Lbl); + TestUtil.CheckMagicFunction(CallCompletionAnswerTxt); + end; + + [Test] + procedure TestMagicFunctionPrompt17() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, MagicFunctionPrompt17Lbl); + TestUtil.CheckMagicFunction(CallCompletionAnswerTxt); + end; + + [Test] + procedure TestMagicFunctionPrompt18() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, MagicFunctionPrompt18Lbl); + TestUtil.CheckMagicFunction(CallCompletionAnswerTxt); + end; + + [Test] + procedure TestMagicFunctionPrompt19() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, MagicFunctionPrompt19Lbl); + TestUtil.CheckMagicFunction(CallCompletionAnswerTxt); + end; + + [Test] + procedure TestMagicFunctionPrompt20() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, MagicFunctionPrompt20Lbl); + TestUtil.CheckMagicFunction(CallCompletionAnswerTxt); + end; + + [Test] + procedure TestMagicFunctionPrompt21() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, MagicFunctionPrompt21Lbl); + TestUtil.CheckMagicFunction(CallCompletionAnswerTxt); + end; + + [Test] + procedure TestMagicFunctionPrompt22() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, MagicFunctionPrompt22Lbl); + TestUtil.CheckMagicFunction(CallCompletionAnswerTxt); + end; + + [Test] + procedure TestMagicFunctionPrompt23() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, MagicFunctionPrompt23Lbl); + TestUtil.CheckMagicFunction(CallCompletionAnswerTxt); + end; + + [Test] + procedure TestMagicFunctionPrompt24() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, MagicFunctionPrompt24Lbl); + TestUtil.CheckMagicFunction(CallCompletionAnswerTxt); + end; + + [Test] + procedure TestMagicFunctionPrompt25() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, MagicFunctionPrompt25Lbl); + TestUtil.CheckMagicFunction(CallCompletionAnswerTxt); + end; + + [Test] + procedure TestMagicFunctionPrompt26() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, MagicFunctionPrompt26Lbl); + TestUtil.CheckMagicFunction(CallCompletionAnswerTxt); + end; + + [Test] + procedure TestMagicFunctionPrompt27() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, MagicFunctionPrompt27Lbl); + TestUtil.CheckMagicFunction(CallCompletionAnswerTxt); + end; + + [Test] + procedure TestMagicFunctionPrompt28() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, MagicFunctionPrompt28Lbl); + TestUtil.CheckMagicFunction(CallCompletionAnswerTxt); + end; + + [Test] + procedure TestMagicFunctionPrompt29() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, MagicFunctionPrompt29Lbl); + TestUtil.CheckMagicFunction(CallCompletionAnswerTxt); + end; + + [Test] + procedure TestMagicFunctionPrompt30() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, MagicFunctionPrompt30Lbl); + TestUtil.CheckMagicFunction(CallCompletionAnswerTxt); + end; + + [Test] + procedure TestMagicFunctionPrompt31() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, MagicFunctionPrompt31Lbl); + TestUtil.CheckMagicFunction(CallCompletionAnswerTxt); + end; + + [Test] + procedure TestMagicFunctionPrompt32() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, MagicFunctionPrompt32Lbl); + TestUtil.CheckMagicFunction(CallCompletionAnswerTxt); + end; + + [Test] + procedure TestMagicFunctionPrompt33() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, MagicFunctionPrompt33Lbl); + TestUtil.CheckMagicFunction(CallCompletionAnswerTxt); + end; + + [Test] + procedure TestMagicFunctionPrompt34() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, MagicFunctionPrompt34Lbl); + TestUtil.CheckMagicFunction(CallCompletionAnswerTxt); + end; + + [Test] + procedure TestMagicFunctionPrompt35() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, MagicFunctionPrompt35Lbl); + TestUtil.CheckMagicFunction(CallCompletionAnswerTxt); + end; + + [Test] + procedure TestMagicFunctionPrompt36() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, MagicFunctionPrompt36Lbl); + TestUtil.CheckMagicFunction(CallCompletionAnswerTxt); + end; + + [Test] + procedure TestMagicFunctionPrompt37() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, MagicFunctionPrompt37Lbl); + TestUtil.CheckMagicFunction(CallCompletionAnswerTxt); + end; + + [Test] + procedure TestMagicFunctionPrompt38() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, MagicFunctionPrompt38Lbl); + TestUtil.CheckMagicFunction(CallCompletionAnswerTxt); + end; + + [Test] + procedure TestMagicFunctionPrompt39() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, MagicFunctionPrompt39Lbl); + TestUtil.CheckMagicFunction(CallCompletionAnswerTxt); + end; + + [Test] + procedure TestMagicFunctionPrompt40() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, MagicFunctionPrompt40Lbl); + TestUtil.CheckMagicFunction(CallCompletionAnswerTxt); + end; + + + [Test] + procedure TestMagicFunctionPrompt41() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, MagicFunctionPrompt41Lbl); + TestUtil.CheckMagicFunction(CallCompletionAnswerTxt); + end; + + [Test] + procedure TestMagicFunctionPrompt42() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, MagicFunctionPrompt42Lbl); + TestUtil.CheckMagicFunction(CallCompletionAnswerTxt); + end; + + [Test] + procedure TestMagicFunctionPrompt43() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, MagicFunctionPrompt43Lbl); + TestUtil.CheckMagicFunction(CallCompletionAnswerTxt); + end; + + [Test] + procedure TestMagicFunctionPrompt44() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, MagicFunctionPrompt44Lbl); + TestUtil.CheckMagicFunction(CallCompletionAnswerTxt); + end; + + [Test] + procedure TestMagicFunctionPrompt45() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, MagicFunctionPrompt45Lbl); + TestUtil.CheckMagicFunction(CallCompletionAnswerTxt); + end; + + [Test] + procedure TestMagicFunctionPrompt46() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, MagicFunctionPrompt46Lbl); + TestUtil.CheckMagicFunction(CallCompletionAnswerTxt); + end; + + [Test] + procedure TestMagicFunctionPrompt47() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, MagicFunctionPrompt47Lbl); + TestUtil.CheckMagicFunction(CallCompletionAnswerTxt); + end; + + + [Test] + procedure TestMagicFunctionPrompt48() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, MagicFunctionPrompt48Lbl); + TestUtil.CheckMagicFunction(CallCompletionAnswerTxt); + end; + + + [Test] + procedure TestMagicFunctionPrompt49() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, MagicFunctionPrompt49Lbl); + TestUtil.CheckMagicFunction(CallCompletionAnswerTxt); + end; + + + [Test] + procedure TestMagicFunctionPrompt50() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, MagicFunctionPrompt50Lbl); + TestUtil.CheckMagicFunction(CallCompletionAnswerTxt); + end; + + + [Test] + procedure TestMagicFunctionPrompt51() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, MagicFunctionPrompt51Lbl); + TestUtil.CheckMagicFunction(CallCompletionAnswerTxt); + end; + + + [Test] + procedure TestMagicFunctionPrompt52() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, MagicFunctionPrompt52Lbl); + TestUtil.CheckMagicFunction(CallCompletionAnswerTxt); + end; + +} \ No newline at end of file diff --git a/Apps/W1/SalesLinesSuggestions/test/SLSTestUtility.Codeunit.al b/Apps/W1/SalesLinesSuggestions/test/SLSTestUtility.Codeunit.al new file mode 100644 index 0000000000..3e53b6c701 --- /dev/null +++ b/Apps/W1/SalesLinesSuggestions/test/SLSTestUtility.Codeunit.al @@ -0,0 +1,171 @@ +namespace Microsoft.Sales.Document.Test; + +using Microsoft.Sales.Document; +using System.TestLibraries.Utilities; +codeunit 139785 "SLS Test Utility" +{ + + // JSON parsing functions + procedure GetFunctionToken(AnswerJson: JsonObject): JsonToken; + var + ToolsArrayToken: JsonToken; + ToolType: JsonToken; + Tool: JsonToken; + Function: JsonToken; + begin + if AnswerJson.Get('tool_calls', ToolsArrayToken) then + foreach Tool in ToolsArrayToken.AsArray() do begin + Tool.AsObject().Get('type', ToolType); + if ToolType.AsValue().asText() = 'function' then begin + Tool.AsObject().Get('function', Function); + exit(Function); + end; + end + end; + + procedure GetFunctionToken(AnswerText: Text) result: JsonToken; + var + AnswerJson: JsonObject; + begin + AnswerJson.ReadFrom(AnswerText); + exit(GetFunctionToken(AnswerJson)); + end; + + procedure ReadJson(data: Text) result: JsonObject; + begin + result.ReadFrom(data); + end; + + + // Completion functions + [TryFunction] + local procedure TryGetCompletion(var CompletionAnswerTxt: SecretText; UserSearchTest: Text) + var + SalesLineAISuggestionImpl: Codeunit "Sales Lines Suggestions Impl."; + Prompt: Codeunit "SLS Prompts"; + IntentSystemPrompt: SecretText; + begin + IntentSystemPrompt := Prompt.GetSLSSystemPrompt(); + CompletionAnswerTxt := SalesLineAISuggestionImpl.AICall(IntentSystemPrompt, UserSearchTest); + end; + + procedure RepeatAtMost100TimesToFetchCompletion(var CompletionAnswerTxt: SecretText; UserSearchTest: Text) + var + i: Integer; + begin + while not TryGetCompletion(CompletionAnswerTxt, UserSearchTest) do begin + Sleep(100); + i += 1; + if i > 100 then + error('Cannot get completion answer with 100 tries'); + end; + end; + + [NonDebuggable] + procedure GetClearCompletionAnswer(CompletionAnswerTxt: SecretText) result: Text + begin + exit(CompletionAnswerTxt.Unwrap()); + end; + + procedure CheckSearchItemJSONContent(CompletionAnswerTxt: SecretText; ItemCount: Integer; LibraryVariableStorage: Codeunit "Library - Variable Storage") + var + Utility: Codeunit "SLS Test Utility"; + Function: JsonToken; + FunctionName: JsonToken; + FunctionArgument: JsonToken; + FunctionArgumentObject: JsonObject; + ItemResults: JsonToken; + ItemResultsArray: JsonArray; + JsonItem: JsonToken; + TempToken: JsonToken; + begin + Function := Utility.GetFunctionToken(GetClearCompletionAnswer(CompletionAnswerTxt)); + Function.AsObject().Get('name', FunctionName); + Assert.AreEqual('search_items', FunctionName.AsValue().AsText(), 'Function name is not search_items.'); + Function.AsObject().Get('arguments', FunctionArgument); + + FunctionArgumentObject := Utility.ReadJson(FunctionArgument.AsValue().AsText()); + FunctionArgumentObject.Get('results', ItemResults); + // ItemResults.AsObject().Get('items', ItemResults); + ItemResultsArray := ItemResults.AsArray(); + Assert.AreEqual(ItemCount, ItemResultsArray.Count(), 'ItemResultsArray count is not correct'); + + foreach JsonItem in ItemResultsArray do begin + JsonItem.AsObject().Get('name', TempToken); + Assert.AreEqual(LibraryVariableStorage.DequeueText().ToLower(), TempToken.AsValue().AsText().ToLower(), 'Item name is not correct'); + JsonItem.AsObject().Get('origin_name', TempToken); + Assert.AreEqual(LibraryVariableStorage.DequeueText().ToLower(), TempToken.AsValue().AsText().ToLower(), 'Item origin name is not correct'); + JsonItem.AsObject().Get('quantity', TempToken); + Assert.AreEqual(LibraryVariableStorage.DequeueText(), TempToken.AsValue().AsText(), 'Item quantity is not correct'); + JsonItem.AsObject().Get('features', TempToken); + CheckFeatures(TempToken, LibraryVariableStorage); + end; + LibraryVariableStorage.AssertEmpty(); + end; + + local procedure CheckFeatures(FeaturesJSONToken: JsonToken; LibraryVariableStorage: Codeunit "Library - Variable Storage") + var + FeatureArray: JsonArray; + TempToken: JsonToken; + FeatureInOneLine: Text; + begin + FeatureArray := FeaturesJSONToken.AsArray(); + if FeatureArray.Count() = 0 then + exit; + FeatureInOneLine := LibraryVariableStorage.DequeueText().ToLower(); + foreach TempToken in FeatureArray do + Assert.IsSubstring(FeatureInOneLine, TempToken.AsValue().AsText().ToLower()); + end; + + [NonDebuggable] + procedure CheckMagicFunction(CompletionAnswerTxt: SecretText); + var + Utility: Codeunit "SLS Test Utility"; + Function: JsonToken; + FunctionName: JsonToken; + begin + Function := Utility.GetFunctionToken(CompletionAnswerTxt.Unwrap()); + Function.AsObject().Get('name', FunctionName); + Assert.AreEqual('magic_function', FunctionName.AsValue().AsText(), 'Function name is not correct'); + end; + + [NonDebuggable] + procedure CheckDocumentLookupJSONContent(CompletionAnswerTxt: SecretText; ExpectedFunctionName: Text; ExpectedDocumentType: Text; ExpectedDocumentNo: Text; ExpectedStartDate: Text; ExpectedEndDate: Text) + var + Utility: Codeunit "SLS Test Utility"; + Function: JsonToken; + FunctionName: JsonToken; + FunctionArgument: JsonToken; + FunctionArgumentObject: JsonObject; + ItemResults: JsonToken; + ItemResultsArray: JsonArray; + JsonItem: JsonToken; + DocNoToken: JsonToken; + DocumentTypeToken: JsonToken; + begin + Function := Utility.GetFunctionToken(CompletionAnswerTxt.Unwrap()); + Function.AsObject().Get('name', FunctionName); + Assert.AreEqual(ExpectedFunctionName, FunctionName.AsValue().AsText(), 'Function name is not correct'); + Function.AsObject().Get('arguments', FunctionArgument); + + FunctionArgumentObject := Utility.ReadJson(FunctionArgument.AsValue().AsText()); + FunctionArgumentObject.Get('results', ItemResults); + ItemResultsArray := ItemResults.AsArray(); + + ItemResultsArray.Get(0, JsonItem); + JsonItem.AsObject().Get('document_type', DocumentTypeToken); + Assert.AreEqual(ExpectedDocumentType, DocumentTypeToken.AsValue().AsText(), 'Document type is not correct'); + JsonItem.AsObject().Get('document_no', DocNoToken); + Assert.AreEqual(ExpectedDocumentNo, DocNoToken.AsValue().AsText(), 'Document no is not correct'); + JsonItem.AsObject().Get('start_date', DocumentTypeToken); + Assert.AreEqual(ExpectedStartDate, DocumentTypeToken.AsValue().AsText(), 'Start date is not correct'); + JsonItem.AsObject().Get('end_date', DocumentTypeToken); + Assert.AreEqual(ExpectedEndDate, DocumentTypeToken.AsValue().AsText(), 'End date is not correct'); + end; + + + var + Assert: Codeunit Assert; + + +} \ No newline at end of file diff --git a/Apps/W1/SalesLinesSuggestions/test/SearchItemPromptTest.Codeunit.al b/Apps/W1/SalesLinesSuggestions/test/SearchItemPromptTest.Codeunit.al new file mode 100644 index 0000000000..4dbb1f22bb --- /dev/null +++ b/Apps/W1/SalesLinesSuggestions/test/SearchItemPromptTest.Codeunit.al @@ -0,0 +1,1190 @@ +namespace Microsoft.Sales.Document.Test; + +using System.TestLibraries.Utilities; + +codeunit 139781 "Search Item Prompt Test" +{ + Subtype = Test; + TestPermissions = Disabled; + EventSubscriberInstance = Manual; + + trigger OnRun() + begin + // [FEATURE] [Sales with AI]:[Search Item] [Prompt] + end; + + var + LibraryVariableStorage: Codeunit "Library - Variable Storage"; + // [START] Common prompts + CommonPrompt01Lbl: Label 'I need 2 bikes and 4 chairs'; + CommonPrompt02Lbl: Label 'I need 2 kids bikes'; + CommonPrompt03Lbl: Label 'I need the item ''1000'''; + CommonPrompt04Lbl: Label 'I need 2 red lamps and 10 kids bikes'; + // [END] Common prompts + + // [START] Complex prompts + ComplexPrompt01Lbl: Label 'Looking for a waterproof digital camera for my vacation'; + ComplexPrompt02Lbl: Label 'Interested in organic skincare products for sensitive skin'; + ComplexPrompt03Lbl: Label 'Searching for a beginner-friendly yoga mat and accessories'; + ComplexPrompt04Lbl: Label 'Need a pair of wireless headphones with noise cancellation'; + ComplexPrompt05Lbl: Label 'Seeking a lightweight, portable laptop for business travel'; + ComplexPrompt06Lbl: Label 'Inquire about the latest fantasy novel releases for teenagers'; + ComplexPrompt07Lbl: Label 'Looking for durable hiking boots suitable for mountain trails'; + ComplexPrompt08Lbl: Label 'Need recommendations for high-quality kitchen knife sets'; + ComplexPrompt09Lbl: Label 'Interested in energy-efficient home appliances for a new house'; + ComplexPrompt10Lbl: Label 'Looking for a compact and affordable drone with camera'; + ComplexPrompt11Lbl: Label 'Seeking vintage style decor for a home office setup'; + ComplexPrompt12Lbl: Label 'Inquiring about that plant-based protein powder'; + ComplexPrompt13Lbl: Label 'Interested in home security systems'; + ComplexPrompt14Lbl: Label 'Need a professional-grade DSLR camera for wildlife photography'; + ComplexPrompt15Lbl: Label 'Looking for a comfortable ergonomic chair for long work hours'; + ComplexPrompt16Lbl: Label 'Searching for eco-friendly and reusable kitchenware items'; + ComplexPrompt17Lbl: Label 'Interested in subscription boxes for gourmet food and snacks'; + ComplexPrompt18Lbl: Label 'Inquire about the availability of electric cars for city driving'; + ComplexPrompt19Lbl: Label 'Looking for high-performance running shoes for marathons'; + ComplexPrompt20Lbl: Label 'Seeking information on beginner-friendly home gardening kits'; + ComplexPrompt21Lbl: Label 'Could you help me find the items for children in your store? I need 2 bikes and 4 chairs. Thank you.'; + ComplexPrompt22Lbl: Label 'I am looking for a kids bike. Do you have any in stock?'; + ComplexPrompt23Lbl: Label 'I am interested in the item ''1000''. Can you provide me with more information about it?'; + ComplexPrompt24Lbl: Label 'I need 2 red lamps and 10 toy cars. Can you help me with that?'; + ComplexPrompt25Lbl: Label 'I need the refrigerator model ''ABC123'', height 180 cm, width 60 cm, and depth 65 cm. Do you have it in stock?'; + ComplexPrompt26Lbl: Label 'I need the paper box with height 180 cm, width 60 cm, and depth 65 cm. Do you have it in stock?'; + ComplexPrompt27Lbl: Label 'Could you help me search the item with GTIN ''987651''?'; + ComplexPrompt28Lbl: Label 'I need the TV with GTIN ''987651''. '; + ComplexPrompt29Lbl: Label 'Help me find the item with GTIN number ''987651''.'; + ComplexPrompt30Lbl: Label 'Could you help me search the item with reference number ''987651''?'; + ComplexPrompt31Lbl: Label 'I need the TV with GTIN ''987651'', larger than 56 inches.'; + ComplexPrompt32Lbl: Label 'Help me find the item with GTIN number ''987651'', larger than 56 inches.'; + ComplexPrompt33Lbl: Label 'I need the TV with brands ''Samsung'' and ''LG''.'; + ComplexPrompt34Lbl: Label 'I need the TV with brands ''Samsung'' and ''LG'' , larger than 56 inches, and 4K resolution. I also need the smart phone with brands ''Samsung'' and ''LG'' .'; + ComplexPrompt35Lbl: Label 'I need all the jacket with brands ''Nike'' and ''Adidas'' , and sizes ''M'' and ''L'' , for kids and adults.'; + ComplexPrompt36Lbl: Label 'Inquire about the information of electric cars for city driving with brands ''Tesla'' and ''Nissan'' and price range between $30,000 and $50,000.'; + ComplexPrompt37Lbl: Label 'Could you check the number of books with the title ''The Art of Happiness'' by Dalai Lama and Howard Cutler?'; + ComplexPrompt38Lbl: Label 'I need the pencil with the brand ''Faber-Castell'' and the color ''black'' and ''blue''. And it should be erased easily.'; + ComplexPrompt39Lbl: Label 'Help me find the white door with height 180 cm, width 60 cm, and the price range is between $100 and $200.'; + ComplexPrompt40Lbl: Label 'I need the snacks with the brand ''Lay''s'' and ''Pringles'', and the price is $1, and the flavor is ''sour cream''.'; + ComplexPrompt41Lbl: Label 'Inquire the information of the smartwatch with the brand ''Samsung'' and ''Apple'', and the price range is between $200 and $300.'; + // [END] Complex prompts + + // [START] Email prompts + EmailPrompt01Lbl: Label 'Hello,I am writing to express my satisfaction with the laptop I purchased from your online store last month. It is a Dell Inspiron 15 3000 Series Laptop, and I am very happy with its performance, design, and features. It is exactly what I was looking for, and I appreciate your excellent customer service and fast delivery.I am interested in buying some accessory for my laptop, such as a wireless mouse, a keyboard cover, and a laptop bag. I wonder if you have any recommendations or suggestions for these items. Do you have any special offers or discounts for loyal customers like me?Please let me know if you can help me with this inquiry. I look forward to hearing from you soon.Thank you for your attention and service.Sincerely, John Smith'; + EmailPrompt02Lbl: Label 'Greetings, I just wanted to say that I really enjoyed reading a book that I ordered from your online store. The book is called “The Art of Happiness” by Dalai Lama and Howard Cutler. It is a wonderful book that teaches how to live a happier and more meaningful life. I learned a lot from the book and I feel more positive and peaceful. I think everyone should read this book and apply its teachings to their own lives. I also want to buy another book from your online store, but something totally different. I am interested in learning more about planting. Do you have any books that can introduce me to this topic? I would appreciate your suggestions. Thank you for your great service and I look forward to hearing from you soon. Best regards, John Smith'; + EmailPrompt03Lbl: Label 'Hello,I am a regular visitor of your website and I have been impressed by the variety and quality of the products you offer. I am particularly interested in buying a smartwatch that can track my fitness, health, and notifications. I have seen the Samsung Galaxy Watch Active 2 on your website and I think it is the perfect match for me. It has a sleek design, a touch bezel, a heart rate monitor, an ECG sensor, and a long battery life. It is also compatible with both Android and iOS devices, which is very convenient for me. I need all the information of this item Samsung Galaxy Watch Active 2. I would like to know more about the features, specifications, and warranty of this smartwatch. How does it compare to other models in the market? What are the payment and delivery options? Do you have any customer reviews or testimonials for this product? Please reply to this email with the information I requested. I am eager to buy this smartwatch from you as soon as possible. Thank you for your time and attention. Sincerely, Jane Doe'; + EmailPrompt04Lbl: Label 'Hello,I am writing to inquire about a leather jacket that I saw on your online store. It is a black leather jacket with a zipper closure, a stand collar, and four pockets. It is made of genuine leather and has a soft lining. It is available in different sizes and colors. I am very interested in buying this leather jacket because it looks stylish, comfortable, and durable. I think it would suit my personality and wardrobe. I have a few questions before I make the purchase: * How can I measure myself to find the right size for me? * How can I take care of the leather jacket to maintain its quality and appearance? * How long will it take for the leather jacket to be delivered to my address? * What is your return and exchange policy in case I am not satisfied with the product? \\ Please answer these questions and provide me with any other information that you think might be helpful. I appreciate your prompt and courteous response. Thank you for your service and cooperation.Sincerely, John Smith'; + EmailPrompt05Lbl: Label 'Hello Stan, I liked your pitch and the quality of your bikes seem to meet and exceed our standards, can you ship over a couple of samples, e.g. some kid''s bikes and maybe a model for women as well as a mountainbike. I''ll return them if we can''t agree but in case we sign the deal, I''ll pay for them. Is that okay with you? Best regards Mike Bikes-R-Us'; + EmailPrompt06Lbl: Label 'Hello, I''m Bob, a gardening enthusiast. I''m very interested in your organic fertilizer range. Could you tell me more about the ingredients and benefits? I want all the information of this item. Also, I recently moved to a new city and am excited to start my garden here. Thanks, Bob'; + EmailPrompt07Lbl: Label 'Dear Team, Bob here. I''ve been a professional photographer for years and I''ve just returned from a wildlife photography trip in Africa. I''m interested in your new range of mirrorless cameras. Can you provide some insights on their performance in low light? I would like the related information of this item. Regards, Bob'; + EmailPrompt08Lbl: Label 'Hi, I''m Bob, an aspiring chef. I came across your culinary school''s advanced courses and I''m curious about the rice cooker you recommend in the lecture. It is large. By the way, I recently won a local cooking competition with my signature dish. Cheers, Bob'; + EmailPrompt09Lbl: Label 'Greetings, Bob here. I''m looking for a new mountain bike and I''m intrigued by the models on your website. Could you show me more information of the bike? I''m also a volunteer trail maintenance worker on weekends. Thanks, Bob'; + EmailPrompt10Lbl: Label 'Hello, this is Bob, a music teacher. I''m interested in your collection of vintage guitars. Could you send me a list of available models and their conditions? I plan to purchase some. Also, I''ve been teaching music to underprivileged children for the past year. Best, Bob'; + EmailPrompt11Lbl: Label 'Hey, Bob here. I''m a tech enthusiast and I''m curious about your latest range of gaming laptops. Can you provide details on their graphics and processing capabilities? I guess I need one. Additionally, I recently organized a local eSports tournament. Thanks, Bob'; + EmailPrompt12Lbl: Label 'Hi there, I''m Bob, an amateur astronomer. I''m fascinated by your telescopes and would like more information on their magnification and stability. Also, I''m planning to host a stargazing event for my community soon. Regards, Bob'; + EmailPrompt13Lbl: Label 'Hello, Bob here, a freelance writer. I''m in the market for a new ergonomic office chair. Could you suggest some models that are good for long hours of writing? By the way, I just finished writing my first novel. Thanks, Bob'; + EmailPrompt14Lbl: Label 'Dear Sir or Madam, I''m Bob, an interior designer. I''m interested in your range of sustainable home decor. Can you share more about it? I need to get one. Also, I''ve recently been involved in designing eco-friendly office spaces. Sincerely, Bob'; + EmailPrompt15Lbl: Label 'Hello, my name is Bob, a fitness coach. I''m looking for high-quality yoga mats for my classes. Can you provide information on their durability and grip? Additionally, I recently started a free fitness boot camp in the park. Cheers, Bob'; + // Email: Reference to sales invoice but actually just need additional items + EmailPrompt16Lbl: Label 'Subject: Request for additional items \nHello,\nI hope this email finds you well. I am writing to you regarding the sales invoice 123456 that you sent me on January 15, 2024. I appreciate your prompt delivery and excellent service.\nHowever, I would like to request some additional items that are related to the ones I purchased from you. Specifically, I am interested in the following products:\n\t- 10 units of Product A (SKU: 789012)\n\t- 5 units of Product B (SKU: 345678)\n\t- 3 units of Product C (SKU: 901234)\nCould you please send me a quote for these items, along with the shipping and handling fees? I would also appreciate it if you could expedite the order, as I need them by February 10, 2024.\nPlease reply to this email with your confirmation and payment details. If you have any questions or concerns, feel free to contact me at any time.\nThank you for your cooperation and attention.\nSincerely,\nYour customer/colleague'; + // Email: Missing items from sales shipment + EmailPrompt17Lbl: Label 'Subject: Urgent: Missing Items in Recent Sales Shipment\n\nDear [Your Name],\n\nI hope this email finds you well. I am writing to bring to your attention an issue with our latest sales shipment for our client, Stellar Tech Innovations.\n\nUpon reviewing the shipment, it appears that several items from our "Galaxy" product line are missing. The missing items include:\n\n1. **10 units** of our **Orion Keyboards**\n2. **15 units** of **Andromeda Mice**\n3. **5 units** of **Pegasus High-Speed HDMI Cables**\n\nThese items were included in the sales order (SO4567) dated January 15, 2024, but were not found in the shipment received by Stellar Tech Innovations.\n\nCould you please look into this matter urgently and advise on the next steps? We need to ensure these items are sent to Stellar Tech Innovations as soon as possible to maintain our service level agreement.\n\nThank you for your prompt attention to this matter.\n\nBest Regards,\n\n[Colleague''s Name]\nSales Department\nInterstellar Computing Inc.'; + // Email: Missing items from order with some maths to do (failing as of January 23rd) + EmailPrompt18Lbl: Label 'Subject: Request for Missing Items\n\nDear [Your Name],\n\nI hope this email finds you well. I am writing to inform you that I received my recent order from your company, but unfortunately, some items are missing from the shipment. I was expecting to receive the following items:\n\n- **2 boxes of 12-pack Coca-Cola cans**\n- **1 box of 24-pack Pepsi cans**\n- **1 box of 6-pack KitKat bars**\n\nHowever, I only received the following items:\n\n- **1 box of 12-pack Coca-Cola cans**\n- **1 box of 24-pack Pepsi cans**\n\nI would appreciate it if you could look into this matter and send me the missing items as soon as possible. Please let me know if you need any further information from me.\n\nThank you for your attention to this matter.\n\nBest regards,\n\nJohn Smith\n'; + // Email: Additional items + EmailPrompt19Lbl: Label 'Subject: Request for additional items from Zephyr Inc.\n\nHello John,\n\nI hope this email finds you well. I am writing to you on behalf of Zephyr Inc., one of your valued customers.\n\nWe are very pleased with the quality and performance of the products we received from your company, Solaris Solutions, in our last order. We appreciate your timely delivery and excellent customer service.\n\nHowever, we have realized that we need some additional items to complete our project. Specifically, we would like to request the following:\n\n- 10 units of Solaris Smart Thermostat (Model ST-2024)\n- 5 units of Solaris Solar Panel (Model SP-2024)\n- 2 units of Solaris Battery Pack (Model BP-2024)\n\nWe would appreciate it if you could confirm the availability and price of these items as soon as possible. We would also like to know the estimated delivery time and shipping cost.\n\nPlease reply to this email or call me at +44 20 1234 5678 if you have any questions or concerns. We look forward to hearing from you and continuing our business relationship with Solaris Solutions.\n\nThank you for your attention and cooperation.\n\nSincerely,\nEmma Smith\nSales Manager\nZephyr Inc.\n'; + // Email: asking to create a new sales order for "next Monday". + EmailPrompt20Lbl: Label 'Subject: Sales invoice reminder\n\nHi John,\n\nI hope this email finds you well and that you are enjoying your work as a sales representative at ABC Inc.\n\nI am writing to remind you that you need to create a sales invoice for the order you received from XYZ Ltd. last week. The invoice should be ready by next Monday, January 29, 2024, and sent to the customer via email.\n\nPlease make sure to include the following items in the invoice:\n\n- Product name: Widget 3000\n- Quantity: 50 units\n- Unit price: £100\n- Total price: £5,000\n- VAT: 20%\n- Grand total: £6,000\n- Payment terms: 30 days from invoice date\n- Bank details: ABC Inc., Sort code: 12-34-56, Account number: 12345678\n\nIf you have any questions or need any assistance, please do not hesitate to contact me.\n\nThank you for your hard work and dedication.\n\nSincerely,\n\nJane Smith\nSales Manager\nABC Inc.\n'; + // [END] Email prompts + + // [START] Spelling errors + SpellingErrorPrompt02Lbl: Label 'I want 2 bkies and 4 charis'; + // [END] Spelling errors + + // [START] Multiple Language + MultiLanguagePrompt01Lbl: Label 'I need one bike with brand ''凤凰'''; + // [END] Multiple Language + + [Test] + procedure TestSearchPrompt01() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, CommonPrompt01Lbl); + LibraryVariableStorage.Clear(); + LibraryVariableStorage.Enqueue('bike'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('2'); + + LibraryVariableStorage.Enqueue('chair'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('4'); + + TestUtil.CheckSearchItemJSONContent(CallCompletionAnswerTxt, 2, LibraryVariableStorage); + end; + + [Test] + procedure TestSearchPrompt02() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, CommonPrompt02Lbl); + LibraryVariableStorage.Clear(); + LibraryVariableStorage.Enqueue('bike'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('2'); + LibraryVariableStorage.Enqueue('kids'); + + TestUtil.CheckSearchItemJSONContent(CallCompletionAnswerTxt, 1, LibraryVariableStorage); + end; + + [Test] + procedure TestSearchPrompt03() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, CommonPrompt03Lbl); + LibraryVariableStorage.Clear(); + LibraryVariableStorage.Enqueue('item'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('1'); + LibraryVariableStorage.Enqueue('1000'); + + TestUtil.CheckSearchItemJSONContent(CallCompletionAnswerTxt, 1, LibraryVariableStorage); + end; + + [Test] + procedure TestSearchPrompt04() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, CommonPrompt04Lbl); + LibraryVariableStorage.Clear(); + LibraryVariableStorage.Enqueue('lamp'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('2'); + LibraryVariableStorage.Enqueue('red'); + + LibraryVariableStorage.Enqueue('bike'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('10'); + LibraryVariableStorage.Enqueue('kids'); + + TestUtil.CheckSearchItemJSONContent(CallCompletionAnswerTxt, 2, LibraryVariableStorage); + end; + + [Test] + procedure TestSearchPrompt05() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, SpellingErrorPrompt02Lbl); + LibraryVariableStorage.Clear(); + LibraryVariableStorage.Enqueue('bike'); + LibraryVariableStorage.Enqueue('bkies'); + LibraryVariableStorage.Enqueue('2'); + + LibraryVariableStorage.Enqueue('chair'); + LibraryVariableStorage.Enqueue('charis'); + LibraryVariableStorage.Enqueue('4'); + TestUtil.CheckSearchItemJSONContent(CallCompletionAnswerTxt, 2, LibraryVariableStorage); + end; + + [Test] + procedure TestSearchPrompt06() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, EmailPrompt01Lbl); + LibraryVariableStorage.Clear(); + LibraryVariableStorage.Enqueue('wireless mouse'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('1'); + + LibraryVariableStorage.Enqueue('keyboard cover'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('1'); + + LibraryVariableStorage.Enqueue('laptop bag'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('1'); + TestUtil.CheckSearchItemJSONContent(CallCompletionAnswerTxt, 3, LibraryVariableStorage); + end; + + [Test] + procedure TestSearchPrompt07() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, EmailPrompt02Lbl); + LibraryVariableStorage.Clear(); + LibraryVariableStorage.Enqueue('book'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('1'); + LibraryVariableStorage.Enqueue('planting'); + TestUtil.CheckSearchItemJSONContent(CallCompletionAnswerTxt, 1, LibraryVariableStorage); + end; + + [Test] + procedure TestSearchPrompt08() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, EmailPrompt03Lbl); + LibraryVariableStorage.Clear(); + LibraryVariableStorage.Enqueue('smartwatch'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('1'); + // features + LibraryVariableStorage.Enqueue('Samsung Galaxy Watch Active 2|smartwatch|fitness tracking|health tracking|notifications|sleek design|touch bezel|heart rate monitor|ECG sensor|long battery life|Android compatibility|iOS compatibility'); + + TestUtil.CheckSearchItemJSONContent(CallCompletionAnswerTxt, 1, LibraryVariableStorage); + end; + + [Test] + procedure TestSearchPrompt09() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, EmailPrompt04Lbl); + LibraryVariableStorage.Clear(); + LibraryVariableStorage.Enqueue('leather jacket'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('1'); + LibraryVariableStorage.Enqueue('black|zipper closure|stand collar|four pockets|genuine leather|soft lining|different sizes|different colors'); + TestUtil.CheckSearchItemJSONContent(CallCompletionAnswerTxt, 1, LibraryVariableStorage); + end; + + [Test] + procedure TestSearchPrompt10() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, EmailPrompt05Lbl); + LibraryVariableStorage.Clear(); + LibraryVariableStorage.Enqueue('bike'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('1'); + LibraryVariableStorage.Enqueue('kid''s'); + + LibraryVariableStorage.Enqueue('bike'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('1'); + LibraryVariableStorage.Enqueue('Women''s'); + + LibraryVariableStorage.Enqueue('mountain bike'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('1'); + + TestUtil.CheckSearchItemJSONContent(CallCompletionAnswerTxt, 3, LibraryVariableStorage); + end; + + [Test] + procedure TestSearchPrompt11() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, ComplexPrompt01Lbl); + LibraryVariableStorage.Clear(); + LibraryVariableStorage.Enqueue('digital camera'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('1'); + LibraryVariableStorage.Enqueue('waterproof'); + + TestUtil.CheckSearchItemJSONContent(CallCompletionAnswerTxt, 1, LibraryVariableStorage); + end; + + [Test] + procedure TestSearchPrompt12() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, ComplexPrompt02Lbl); + LibraryVariableStorage.Clear(); + LibraryVariableStorage.Enqueue('skincare product'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('1'); + LibraryVariableStorage.Enqueue('organic|for sensitive skin'); + TestUtil.CheckSearchItemJSONContent(CallCompletionAnswerTxt, 1, LibraryVariableStorage); + end; + + [Test] + procedure TestSearchPrompt13() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, ComplexPrompt03Lbl); + LibraryVariableStorage.Clear(); + LibraryVariableStorage.Enqueue('yoga mat'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('1'); + LibraryVariableStorage.Enqueue('beginner-friendly|yoga'); + + LibraryVariableStorage.Enqueue('yoga accessory'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('1'); + LibraryVariableStorage.Enqueue('beginner-friendly|yoga'); + + TestUtil.CheckSearchItemJSONContent(CallCompletionAnswerTxt, 2, LibraryVariableStorage); + end; + + [Test] + procedure TestSearchPrompt14() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, ComplexPrompt04Lbl); + LibraryVariableStorage.Clear(); + LibraryVariableStorage.Enqueue('headphone'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('1'); + LibraryVariableStorage.Enqueue('wireless|noise cancellation'); + TestUtil.CheckSearchItemJSONContent(CallCompletionAnswerTxt, 1, LibraryVariableStorage); + end; + + [Test] + procedure TestSearchPrompt15() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, ComplexPrompt05Lbl); + LibraryVariableStorage.Clear(); + LibraryVariableStorage.Enqueue('laptop'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('1'); + LibraryVariableStorage.Enqueue('lightweight|portable|for business travel|fantasy'); + TestUtil.CheckSearchItemJSONContent(CallCompletionAnswerTxt, 1, LibraryVariableStorage); + end; + + [Test] + procedure TestSearchPrompt16() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, ComplexPrompt06Lbl); + LibraryVariableStorage.Clear(); + LibraryVariableStorage.Enqueue('novel'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('1'); + LibraryVariableStorage.Enqueue('fantasy|latest|teenagers'); + TestUtil.CheckSearchItemJSONContent(CallCompletionAnswerTxt, 1, LibraryVariableStorage); + end; + + [Test] + procedure TestSearchPrompt17() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, ComplexPrompt07Lbl); + LibraryVariableStorage.Clear(); + LibraryVariableStorage.Enqueue('hiking boot'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('1'); + LibraryVariableStorage.Enqueue('durable|suitable for mountain trails'); + TestUtil.CheckSearchItemJSONContent(CallCompletionAnswerTxt, 1, LibraryVariableStorage); + end; + + [Test] + procedure TestSearchPrompt18() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, ComplexPrompt08Lbl); + LibraryVariableStorage.Clear(); + LibraryVariableStorage.Enqueue('kitchen knife set'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('1'); + LibraryVariableStorage.Enqueue('high-quality'); + TestUtil.CheckSearchItemJSONContent(CallCompletionAnswerTxt, 1, LibraryVariableStorage); + end; + + [Test] + procedure TestSearchPrompt19() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, ComplexPrompt09Lbl); + LibraryVariableStorage.Clear(); + LibraryVariableStorage.Enqueue('home appliance'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('1'); + LibraryVariableStorage.Enqueue('energy-efficient|new house'); + TestUtil.CheckSearchItemJSONContent(CallCompletionAnswerTxt, 1, LibraryVariableStorage); + end; + + [Test] + procedure TestSearchPrompt20() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, ComplexPrompt10Lbl); + LibraryVariableStorage.Clear(); + LibraryVariableStorage.Enqueue('drone'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('1'); + LibraryVariableStorage.Enqueue('compact|affordable|with camera'); + TestUtil.CheckSearchItemJSONContent(CallCompletionAnswerTxt, 1, LibraryVariableStorage); + end; + + [Test] + procedure TestSearchPrompt21() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, ComplexPrompt11Lbl); + LibraryVariableStorage.Clear(); + LibraryVariableStorage.Enqueue('decor'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('1'); + LibraryVariableStorage.Enqueue('vintage style|home office setup'); + TestUtil.CheckSearchItemJSONContent(CallCompletionAnswerTxt, 1, LibraryVariableStorage); + end; + + [Test] + procedure TestSearchPrompt22() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, ComplexPrompt12Lbl); + LibraryVariableStorage.Clear(); + LibraryVariableStorage.Enqueue('protein powder'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('1'); + LibraryVariableStorage.Enqueue('plant-based'); + TestUtil.CheckSearchItemJSONContent(CallCompletionAnswerTxt, 1, LibraryVariableStorage); + end; + + [Test] + procedure TestSearchPrompt23() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, ComplexPrompt13Lbl); + LibraryVariableStorage.Clear(); + LibraryVariableStorage.Enqueue('home security system'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('1'); + TestUtil.CheckSearchItemJSONContent(CallCompletionAnswerTxt, 1, LibraryVariableStorage); + end; + + [Test] + procedure TestSearchPrompt24() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, ComplexPrompt14Lbl); + LibraryVariableStorage.Clear(); + LibraryVariableStorage.Enqueue('dslr camera'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('1'); + LibraryVariableStorage.Enqueue('professional-grade|for wildlife photography'); + TestUtil.CheckSearchItemJSONContent(CallCompletionAnswerTxt, 1, LibraryVariableStorage); + end; + + [Test] + procedure TestSearchPrompt25() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, ComplexPrompt15Lbl); + LibraryVariableStorage.Clear(); + LibraryVariableStorage.Enqueue('chair'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('1'); + LibraryVariableStorage.Enqueue('comfortable|ergonomic|for long work hours'); + TestUtil.CheckSearchItemJSONContent(CallCompletionAnswerTxt, 1, LibraryVariableStorage); + end; + + [Test] + procedure TestSearchPrompt26() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, ComplexPrompt16Lbl); + LibraryVariableStorage.Clear(); + LibraryVariableStorage.Enqueue('kitchenware'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('1'); + LibraryVariableStorage.Enqueue('eco-friendly|reusable'); + TestUtil.CheckSearchItemJSONContent(CallCompletionAnswerTxt, 1, LibraryVariableStorage); + end; + + [Test] + procedure TestSearchPrompt27() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, ComplexPrompt17Lbl); + LibraryVariableStorage.Clear(); + LibraryVariableStorage.Enqueue('subscription box'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('1'); + LibraryVariableStorage.Enqueue('gourmet food|snacks'); + TestUtil.CheckSearchItemJSONContent(CallCompletionAnswerTxt, 1, LibraryVariableStorage); + end; + + [Test] + procedure TestSearchPrompt28() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, ComplexPrompt18Lbl); + LibraryVariableStorage.Clear(); + LibraryVariableStorage.Enqueue('electric car'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('1'); + LibraryVariableStorage.Enqueue('city driving'); + TestUtil.CheckSearchItemJSONContent(CallCompletionAnswerTxt, 1, LibraryVariableStorage); + end; + + + [Test] + procedure TestSearchPrompt29() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, ComplexPrompt20Lbl); + LibraryVariableStorage.Clear(); + LibraryVariableStorage.Enqueue('home gardening kit'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('1'); + LibraryVariableStorage.Enqueue('beginner-friendly'); + TestUtil.CheckSearchItemJSONContent(CallCompletionAnswerTxt, 1, LibraryVariableStorage); + end; + + [Test] + procedure TestSearchPrompt30() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, ComplexPrompt19Lbl); + LibraryVariableStorage.Clear(); + LibraryVariableStorage.Enqueue('running shoe'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('1'); + LibraryVariableStorage.Enqueue('high-performance|for marathons'); + TestUtil.CheckSearchItemJSONContent(CallCompletionAnswerTxt, 1, LibraryVariableStorage); + end; + + [Test] + procedure TestSearchPrompt31() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, EmailPrompt06Lbl); + LibraryVariableStorage.Clear(); + LibraryVariableStorage.Enqueue('organic fertilizer'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('1'); + TestUtil.CheckSearchItemJSONContent(CallCompletionAnswerTxt, 1, LibraryVariableStorage); + end; + + [Test] + procedure TestSearchPrompt32() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, EmailPrompt07Lbl); + LibraryVariableStorage.Clear(); + LibraryVariableStorage.Enqueue('mirrorless camera'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('1'); + LibraryVariableStorage.Enqueue('new range|low light performance'); + TestUtil.CheckSearchItemJSONContent(CallCompletionAnswerTxt, 1, LibraryVariableStorage); + end; + + [Test] + procedure TestSearchPrompt33() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, EmailPrompt08Lbl); + LibraryVariableStorage.Clear(); + LibraryVariableStorage.Enqueue('rice cooker'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('1'); + LibraryVariableStorage.Enqueue('large'); + TestUtil.CheckSearchItemJSONContent(CallCompletionAnswerTxt, 1, LibraryVariableStorage); + end; + + [Test] + procedure TestSearchPrompt34() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, EmailPrompt09Lbl); + LibraryVariableStorage.Clear(); + LibraryVariableStorage.Enqueue('bike'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('1'); + LibraryVariableStorage.Enqueue('new | mountain '); + + TestUtil.CheckSearchItemJSONContent(CallCompletionAnswerTxt, 1, LibraryVariableStorage); + end; + + [Test] + procedure TestSearchPrompt35() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, EmailPrompt10Lbl); + LibraryVariableStorage.Clear(); + LibraryVariableStorage.Enqueue('guitar'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('0'); + LibraryVariableStorage.Enqueue('vintage'); + + TestUtil.CheckSearchItemJSONContent(CallCompletionAnswerTxt, 1, LibraryVariableStorage); + end; + + [Test] + procedure TestSearchPrompt36() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, EmailPrompt11Lbl); + LibraryVariableStorage.Clear(); + LibraryVariableStorage.Enqueue('gaming laptop'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('1'); + LibraryVariableStorage.Enqueue('graphics|processing capabilities'); + TestUtil.CheckSearchItemJSONContent(CallCompletionAnswerTxt, 1, LibraryVariableStorage); + end; + + [Test] + procedure TestSearchPrompt37() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, EmailPrompt12Lbl); + LibraryVariableStorage.Clear(); + LibraryVariableStorage.Enqueue('telescope'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('1'); + LibraryVariableStorage.Enqueue('magnification|stability'); + TestUtil.CheckSearchItemJSONContent(CallCompletionAnswerTxt, 1, LibraryVariableStorage); + end; + + [Test] + procedure TestSearchPrompt38() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, EmailPrompt13Lbl); + LibraryVariableStorage.Clear(); + LibraryVariableStorage.Enqueue('office chair'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('1'); + LibraryVariableStorage.Enqueue('ergonomic'); + TestUtil.CheckSearchItemJSONContent(CallCompletionAnswerTxt, 1, LibraryVariableStorage); + end; + + [Test] + procedure TestSearchPrompt39() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, EmailPrompt14Lbl); + LibraryVariableStorage.Clear(); + LibraryVariableStorage.Enqueue('home decor'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('1'); + LibraryVariableStorage.Enqueue('sustainable'); + TestUtil.CheckSearchItemJSONContent(CallCompletionAnswerTxt, 1, LibraryVariableStorage); + end; + + [Test] + procedure TestSearchPrompt40() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, EmailPrompt15Lbl); + LibraryVariableStorage.Clear(); + LibraryVariableStorage.Enqueue('yoga mat'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('1'); + LibraryVariableStorage.Enqueue('high quality|durability|grip'); + TestUtil.CheckSearchItemJSONContent(CallCompletionAnswerTxt, 1, LibraryVariableStorage); + end; + + [Test] + procedure TestSearchPrompt41() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, EmailPrompt16Lbl); + LibraryVariableStorage.Clear(); + LibraryVariableStorage.Enqueue('product a'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('10'); + LibraryVariableStorage.Enqueue('SKU: 789012'); + LibraryVariableStorage.Enqueue('product b'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('5'); + LibraryVariableStorage.Enqueue('SKU: 345678'); + LibraryVariableStorage.Enqueue('product c'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('3'); + LibraryVariableStorage.Enqueue('SKU: 901234'); + TestUtil.CheckSearchItemJSONContent(CallCompletionAnswerTxt, 3, LibraryVariableStorage); + end; + + [Test] + procedure TestSearchPrompt42() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, EmailPrompt17Lbl); + LibraryVariableStorage.Clear(); + LibraryVariableStorage.Enqueue('Keyboard'); + LibraryVariableStorage.Enqueue('Orion Keyboards'); + LibraryVariableStorage.Enqueue('10'); + LibraryVariableStorage.Enqueue('Orion'); + LibraryVariableStorage.Enqueue('Mouse'); + LibraryVariableStorage.Enqueue('Andromeda Mice'); + LibraryVariableStorage.Enqueue('15'); + LibraryVariableStorage.Enqueue('Andromeda'); + LibraryVariableStorage.Enqueue('HDMI Cable'); + LibraryVariableStorage.Enqueue('Pegasus High-Speed HDMI Cables'); + LibraryVariableStorage.Enqueue('5'); + LibraryVariableStorage.Enqueue('Pegasus|High-Speed'); + TestUtil.CheckSearchItemJSONContent(CallCompletionAnswerTxt, 3, LibraryVariableStorage); + end; + + [Test] + procedure TestSearchPrompt43() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, EmailPrompt18Lbl); + LibraryVariableStorage.Clear(); + LibraryVariableStorage.Enqueue('Coca-Cola can'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('1'); + LibraryVariableStorage.Enqueue('12-pack|box'); + LibraryVariableStorage.Enqueue('KitKat bar'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('1'); + LibraryVariableStorage.Enqueue('6-pack|box'); + TestUtil.CheckSearchItemJSONContent(CallCompletionAnswerTxt, 2, LibraryVariableStorage); + end; + + [Test] + procedure TestSearchPrompt44() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, EmailPrompt19Lbl); + LibraryVariableStorage.Clear(); + LibraryVariableStorage.Enqueue('Smart Thermostat'); + LibraryVariableStorage.Enqueue('solaris smart thermostat'); + LibraryVariableStorage.Enqueue('10'); + LibraryVariableStorage.Enqueue('Solaris|Model ST-2024'); + LibraryVariableStorage.Enqueue('Solar Panel'); + LibraryVariableStorage.Enqueue('solaris solar panel'); + LibraryVariableStorage.Enqueue('5'); + LibraryVariableStorage.Enqueue('Solaris|Model SP-2024'); + LibraryVariableStorage.Enqueue('Battery Pack'); + LibraryVariableStorage.Enqueue('Solaris Battery Pack'); + LibraryVariableStorage.Enqueue('2'); + LibraryVariableStorage.Enqueue('Solaris|Model BP-2024'); + TestUtil.CheckSearchItemJSONContent(CallCompletionAnswerTxt, 3, LibraryVariableStorage); + end; + + [Test] + procedure TestSearchPrompt45() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, EmailPrompt20Lbl); + LibraryVariableStorage.Clear(); + LibraryVariableStorage.Enqueue('Widget'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('50'); + LibraryVariableStorage.Enqueue('3000'); + TestUtil.CheckSearchItemJSONContent(CallCompletionAnswerTxt, 1, LibraryVariableStorage); + end; + + [Test] + procedure TestSearchPrompt46() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, ComplexPrompt21Lbl); + LibraryVariableStorage.Clear(); + LibraryVariableStorage.Enqueue('bike'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('2'); + LibraryVariableStorage.Enqueue('children'); + LibraryVariableStorage.Enqueue('chair'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('4'); + LibraryVariableStorage.Enqueue('children'); + TestUtil.CheckSearchItemJSONContent(CallCompletionAnswerTxt, 2, LibraryVariableStorage); + end; + + [Test] + procedure TestSearchPrompt47() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, ComplexPrompt22Lbl); + LibraryVariableStorage.Clear(); + LibraryVariableStorage.Enqueue('bike'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('1'); + LibraryVariableStorage.Enqueue('kids'); + TestUtil.CheckSearchItemJSONContent(CallCompletionAnswerTxt, 1, LibraryVariableStorage); + end; + + [Test] + procedure TestSearchPrompt48() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, ComplexPrompt23Lbl); + LibraryVariableStorage.Clear(); + LibraryVariableStorage.Enqueue('item'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('1'); + LibraryVariableStorage.Enqueue('1000'); + TestUtil.CheckSearchItemJSONContent(CallCompletionAnswerTxt, 1, LibraryVariableStorage); + end; + + [Test] + procedure TestSearchPrompt49() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, ComplexPrompt24Lbl); + LibraryVariableStorage.Clear(); + LibraryVariableStorage.Enqueue('lamp'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('2'); + LibraryVariableStorage.Enqueue('red'); + LibraryVariableStorage.Enqueue('toy car'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('10'); + TestUtil.CheckSearchItemJSONContent(CallCompletionAnswerTxt, 2, LibraryVariableStorage); + end; + + [Test] + procedure TestSearchPrompt50() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, ComplexPrompt25Lbl); + LibraryVariableStorage.Clear(); + LibraryVariableStorage.Enqueue('refrigerator'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('1'); + LibraryVariableStorage.Enqueue('model ABC123|height 180 cm|width 60 cm|depth 65 cm'); + TestUtil.CheckSearchItemJSONContent(CallCompletionAnswerTxt, 1, LibraryVariableStorage); + end; + + [Test] + procedure TestSearchPrompt51() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, ComplexPrompt26Lbl); + LibraryVariableStorage.Clear(); + LibraryVariableStorage.Enqueue('paper box'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('1'); + LibraryVariableStorage.Enqueue('height 180 cm|width 60 cm|depth 65 cm'); + TestUtil.CheckSearchItemJSONContent(CallCompletionAnswerTxt, 1, LibraryVariableStorage); + end; + + [Test] + procedure TestSearchPrompt52() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, ComplexPrompt27Lbl); + LibraryVariableStorage.Clear(); + LibraryVariableStorage.Enqueue('item'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('1'); + LibraryVariableStorage.Enqueue('GTIN 987651|GTIN ''987651'''); + TestUtil.CheckSearchItemJSONContent(CallCompletionAnswerTxt, 1, LibraryVariableStorage); + end; + + [Test] + procedure TestSearchPrompt53() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, ComplexPrompt28Lbl); + LibraryVariableStorage.Clear(); + LibraryVariableStorage.Enqueue('TV'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('1'); + LibraryVariableStorage.Enqueue('GTIN 987651|GTIN ''987651'''); + TestUtil.CheckSearchItemJSONContent(CallCompletionAnswerTxt, 1, LibraryVariableStorage); + end; + + [Test] + procedure TestSearchPrompt54() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, ComplexPrompt29Lbl); + LibraryVariableStorage.Clear(); + LibraryVariableStorage.Enqueue('item'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('1'); + LibraryVariableStorage.Enqueue('GTIN 987651|GTIN ''987651'''); + TestUtil.CheckSearchItemJSONContent(CallCompletionAnswerTxt, 1, LibraryVariableStorage); + end; + + [Test] + procedure TestSearchPrompt55() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, ComplexPrompt30Lbl); + LibraryVariableStorage.Clear(); + LibraryVariableStorage.Enqueue('item'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('1'); + LibraryVariableStorage.Enqueue('GTIN 987651|GTIN ''987651'''); + TestUtil.CheckSearchItemJSONContent(CallCompletionAnswerTxt, 1, LibraryVariableStorage); + end; + + [Test] + procedure TestSearchPrompt56() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, ComplexPrompt31Lbl); + LibraryVariableStorage.Clear(); + LibraryVariableStorage.Enqueue('TV'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('1'); + LibraryVariableStorage.Enqueue('GTIN 987651|GTIN ''987651''|larger than 56 inches'); + TestUtil.CheckSearchItemJSONContent(CallCompletionAnswerTxt, 1, LibraryVariableStorage); + end; + + [Test] + procedure TestSearchPrompt57() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, ComplexPrompt32Lbl); + LibraryVariableStorage.Clear(); + LibraryVariableStorage.Enqueue('item'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('1'); + LibraryVariableStorage.Enqueue('GTIN 987651|GTIN ''987651''|larger than 56 inches'); + TestUtil.CheckSearchItemJSONContent(CallCompletionAnswerTxt, 1, LibraryVariableStorage); + end; + + [Test] + procedure TestSearchPrompt58() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, ComplexPrompt33Lbl); + LibraryVariableStorage.Clear(); + LibraryVariableStorage.Enqueue('TV'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('1'); + LibraryVariableStorage.Enqueue('Samsung|LG'); + TestUtil.CheckSearchItemJSONContent(CallCompletionAnswerTxt, 1, LibraryVariableStorage); + end; + + [Test] + procedure TestSearchPrompt59() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, ComplexPrompt34Lbl); + LibraryVariableStorage.Clear(); + LibraryVariableStorage.Enqueue('TV'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('1'); + LibraryVariableStorage.Enqueue('Samsung|LG|larger than 56 inches|4K resolution'); + LibraryVariableStorage.Enqueue('smart phone'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('1'); + LibraryVariableStorage.Enqueue('Samsung|LG'); + TestUtil.CheckSearchItemJSONContent(CallCompletionAnswerTxt, 2, LibraryVariableStorage); + end; + + [Test] + procedure TestSearchPrompt60() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, ComplexPrompt35Lbl); + LibraryVariableStorage.Clear(); + LibraryVariableStorage.Enqueue('jacket'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('0'); + LibraryVariableStorage.Enqueue('Nike|Adidas|M|L|kids|adults'); + TestUtil.CheckSearchItemJSONContent(CallCompletionAnswerTxt, 1, LibraryVariableStorage); + end; + + [Test] + procedure TestSearchPrompt61() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, ComplexPrompt36Lbl); + LibraryVariableStorage.Clear(); + LibraryVariableStorage.Enqueue('electric car'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('1'); + LibraryVariableStorage.Enqueue('city driving|Tesla|Nissan|$30,000 - $50,000'); + TestUtil.CheckSearchItemJSONContent(CallCompletionAnswerTxt, 1, LibraryVariableStorage); + end; + + [Test] + procedure TestSearchPrompt62() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, ComplexPrompt37Lbl); + LibraryVariableStorage.Clear(); + LibraryVariableStorage.Enqueue('Book'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('1'); + LibraryVariableStorage.Enqueue('The Art of Happiness|Dalai Lama|Howard Cutler'); + TestUtil.CheckSearchItemJSONContent(CallCompletionAnswerTxt, 1, LibraryVariableStorage); + end; + + [Test] + procedure TestSearchPrompt63() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, ComplexPrompt38Lbl); + LibraryVariableStorage.Clear(); + LibraryVariableStorage.Enqueue('pencil'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('1'); + LibraryVariableStorage.Enqueue('Faber-Castell|black|blue|erasable'); + TestUtil.CheckSearchItemJSONContent(CallCompletionAnswerTxt, 1, LibraryVariableStorage); + end; + + [Test] + procedure TestSearchPrompt64() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, ComplexPrompt39Lbl); + LibraryVariableStorage.Clear(); + LibraryVariableStorage.Enqueue('door'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('1'); + LibraryVariableStorage.Enqueue('white|height 180 cm|width 60 cm|price range $100-$200'); + TestUtil.CheckSearchItemJSONContent(CallCompletionAnswerTxt, 1, LibraryVariableStorage); + end; + + [Test] + procedure TestSearchPrompt65() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, ComplexPrompt40Lbl); + LibraryVariableStorage.Clear(); + LibraryVariableStorage.Enqueue('snack'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('1'); + LibraryVariableStorage.Enqueue('Lay''s|Pringles|sour cream|$1'); + TestUtil.CheckSearchItemJSONContent(CallCompletionAnswerTxt, 1, LibraryVariableStorage); + end; + + [Test] + procedure TestSearchPrompt66() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, ComplexPrompt41Lbl); + LibraryVariableStorage.Clear(); + LibraryVariableStorage.Enqueue('smartwatch'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('1'); + LibraryVariableStorage.Enqueue('Samsung|Apple|price between $200 and $300'); + TestUtil.CheckSearchItemJSONContent(CallCompletionAnswerTxt, 1, LibraryVariableStorage); + end; + + [Test] + procedure TestSearchPrompt67() + var + TestUtil: Codeunit "SLS Test Utility"; + CallCompletionAnswerTxt: SecretText; + begin + TestUtil.RepeatAtMost100TimesToFetchCompletion(CallCompletionAnswerTxt, MultiLanguagePrompt01Lbl); + LibraryVariableStorage.Clear(); + LibraryVariableStorage.Enqueue('Bike'); + LibraryVariableStorage.Enqueue(''); + LibraryVariableStorage.Enqueue('1'); + LibraryVariableStorage.Enqueue('凤凰'); + TestUtil.CheckSearchItemJSONContent(CallCompletionAnswerTxt, 1, LibraryVariableStorage); + end; +} \ No newline at end of file diff --git a/Apps/W1/SalesLinesSuggestions/test/SearchItemTest.Codeunit.al b/Apps/W1/SalesLinesSuggestions/test/SearchItemTest.Codeunit.al new file mode 100644 index 0000000000..99a35d85b0 --- /dev/null +++ b/Apps/W1/SalesLinesSuggestions/test/SearchItemTest.Codeunit.al @@ -0,0 +1,730 @@ +namespace Microsoft.Sales.Document.Test; + +using Microsoft.Inventory.Item; +using Microsoft.Sales.Customer; +using Microsoft.Warehouse.ADCS; +using Microsoft.Foundation.ExtendedText; +using Microsoft.Inventory.Item.Catalog; +using Microsoft.Sales.Document; +using System.TestLibraries.Utilities; + +codeunit 139780 "Search Item Test" +{ + Subtype = Test; + TestPermissions = Disabled; + EventSubscriberInstance = Manual; + + var + GlobalUserInput: Text; + + var + Assert: Codeunit Assert; + LibraryVariableStorage: Codeunit "Library - Variable Storage"; + LibrarySales: Codeunit "Library - Sales"; + NoSuggestionGeneratedErr: Label 'There are no suggestions for this description. Please rephrase it.'; + DescriptionIsIncorrectErr: Label 'Description is incorrect!'; + QuantityIsIncorrectErr: Label 'Quantity is incorrect!'; + + [Test] + [HandlerFunctions('InvokeGenerateAndCheckItemsFound')] + procedure TestSearchBasedOnItemNo() + var + SalesHeader: Record "Sales Header"; + Item: Record Item; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + UserInput: Text; + begin + // [FEATURE] [Sales with AI]:[Search Item End to End] + // [Scenario] User wants to search for an item using item no. and AI should suggest the item + Initialize(); + // [GIVEN] Pick one item + Item.FindFirst(); + UserInput := GlobalUserInput; + UserInput += '5 quantity of ' + Item."No." + '; '; + LibraryVariableStorage.Enqueue(UserInput); + LibraryVariableStorage.Enqueue(1); + EnqueueOneItemAndQty(Item.Description, 5); + EnqueueOneItemAndQty(Item.Description, 5); + // [WHEN] User input is given to the AI suggestions + // [THEN] AI suggestions should one sales lines, it is handled in the handler function 'InvokeGenerateAndCheckItemsFound' + CreateNewSalesOrderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions); + // [THEN] One line is inserted in the sales line + CheckSalesLineContent(SalesHeader."No."); + end; + + [Test] + [HandlerFunctions('InvokeGenerateAndCheckItemsFound')] + procedure TestSearchBasedOnItemDesc() + var + SalesHeader: Record "Sales Header"; + Item: Record Item; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + UserInput: Text; + begin + // [FEATURE] [Sales with AI]:[Search Item End to End] + // [Scenario] User wants to search for an item using item description and AI should suggest the item + Initialize(); + Item.FindFirst(); + UserInput := GlobalUserInput; + UserInput += '5 quantity of ' + Item.Description + '; '; + LibraryVariableStorage.Enqueue(UserInput); + LibraryVariableStorage.Enqueue(1); + EnqueueOneItemAndQty(Item.Description, 5); + EnqueueOneItemAndQty(Item.Description, 5); + // [WHEN] User input is given to the AI suggestions + // [THEN] AI suggestions should one sales lines, it is handled in the handler function 'InvokeGenerateAndCheckItemsFound' + CreateNewSalesOrderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions); + // [THEN] One line is inserted in the sales line + CheckSalesLineContent(SalesHeader."No."); + end; + + [Test] + [HandlerFunctions('InvokeGenerateAndCheckItemsFound')] + procedure TestSearchBasedOnVendorItemNo() + var + SalesHeader: Record "Sales Header"; + Item: Record Item; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + UserInput: Text; + begin + // [FEATURE] [Sales with AI]:[Search Item End to End] + // [Scenario] User wants to search for an item with VendorItemNo. and AI should suggest the item + Initialize(); + // [GIVEN] Find an item with Vendor Item No. + Item.SetFilter("Vendor Item No.", '<>%1', ''); + Item.FindFirst(); + UserInput := GlobalUserInput; + UserInput += '5 quantity of ' + Item."Vendor Item No." + '; '; + LibraryVariableStorage.Enqueue(UserInput); + LibraryVariableStorage.Enqueue(1); + EnqueueOneItemAndQty(Item.Description, 5); + EnqueueOneItemAndQty(Item.Description, 5); + // [WHEN] User input is given to the AI suggestions + // [THEN] AI suggestions should one sales lines, it is handled in the handler function 'InvokeGenerateAndCheckItemsFound' + CreateNewSalesOrderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions); + // [THEN] One line is inserted in the sales line + CheckSalesLineContent(SalesHeader."No."); + end; + + + [Test] + [HandlerFunctions('InvokeGenerateAndCheckItemsFound')] + procedure TestSearchBasedOnItemVariantCode() + var + SalesHeader: Record "Sales Header"; + Item: Record Item; + ItemVariant: Record "Item Variant"; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + UserInput: Text; + begin + // [FEATURE] [Sales with AI]:[Search Item End to End] + // [Scenario] User wants to search for an item with Variant Code. and AI should suggest the item + Initialize(); + // [GIVEN] Find an item with Variant Code. + ItemVariant.SetFilter("Code", '<>%1', ''); + ItemVariant.FindFirst(); + Item.SetRange("No.", ItemVariant."Item No."); + Item.FindFirst(); + UserInput := GlobalUserInput; + UserInput += '5 quantity of ' + ItemVariant.Code + '; '; + LibraryVariableStorage.Enqueue(UserInput); + LibraryVariableStorage.Enqueue(1); + EnqueueOneItemAndQty(Item.Description, 5); + EnqueueOneItemAndQty(Item.Description, 5); + // [WHEN] User input is given to the AI suggestions + // [THEN] AI suggestions should one sales lines, it is handled in the handler function 'InvokeGenerateAndCheckItemsFound' + CreateNewSalesOrderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions); + // [THEN] One line is inserted in the sales line + CheckSalesLineContent(SalesHeader."No."); + end; + + [Test] + [HandlerFunctions('InvokeGenerateAndCheckItemsFound')] + procedure TestSearchBasedOnReferenceNo() + var + SalesHeader: Record "Sales Header"; + Item: Record Item; + ItemReference: Record "Item Reference"; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + UserInput: Text; + begin + // [FEATURE] [Sales with AI]:[Search Item End to End] + // [Scenario] User wants to search for an item with Reference No. and AI should suggest the item + Initialize(); + // [GIVEN] Find an item with Reference No. + ItemReference.SetFilter("Reference No.", '<>%1', ''); + ItemReference.FindFirst(); + Item.SetRange("No.", ItemReference."Item No."); + Item.FindFirst(); + UserInput := GlobalUserInput; + UserInput += '5 quantity of ' + ItemReference."Reference No." + '; '; + LibraryVariableStorage.Enqueue(UserInput); + LibraryVariableStorage.Enqueue(1); + EnqueueOneItemAndQty(Item.Description, 5); + EnqueueOneItemAndQty(Item.Description, 5); + // [WHEN] User input is given to the AI suggestions + // [THEN] AI suggestions should one sales lines, it is handled in the handler function 'InvokeGenerateAndCheckItemsFound' + CreateNewSalesOrderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions); + // [THEN] One line is inserted in the sales line + CheckSalesLineContent(SalesHeader."No."); + end; + + [Test] + [HandlerFunctions('InvokeGenerateAndCheckItemsFound')] + procedure TestSearchBasedOnReferenceDesc() + var + SalesHeader: Record "Sales Header"; + Item: Record Item; + ItemReference: Record "Item Reference"; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + UserInput: Text; + begin + // [FEATURE] [Sales with AI]:[Search Item End to End] + // [Scenario] User wants to search for an item with "Reference Description" and AI should suggest the item + Initialize(); + // [GIVEN] Find an item with Reference Description +#pragma warning disable AA0210 + ItemReference.SetFilter(Description, '<>%1', ''); + ItemReference.FindFirst(); + Item.SetRange("No.", ItemReference."Item No."); + Item.FindFirst(); + UserInput := GlobalUserInput; + UserInput += '5 quantity of ' + ItemReference.Description + '; '; + LibraryVariableStorage.Enqueue(UserInput); + LibraryVariableStorage.Enqueue(1); + EnqueueOneItemAndQty(Item.Description, 5); + EnqueueOneItemAndQty(Item.Description, 5); + // [WHEN] User input is given to the AI suggestions + // [THEN] AI suggestions should one sales lines, it is handled in the handler function 'InvokeGenerateAndCheckItemsFound' + CreateNewSalesOrderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions); + // [THEN] One line is inserted in the sales line + CheckSalesLineContent(SalesHeader."No."); + end; + + [Test] + [HandlerFunctions('InvokeGenerateAndCheckItemsFound')] + procedure TestSearchBasedOnItemCategoryCode() + var + SalesHeader: Record "Sales Header"; + Item: Record Item; + ItemCategory: Record "Item Category"; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + UserInput: Text; + begin + // [FEATURE] [Sales with AI]:[Search Item End to End] + // [Scenario] User wants to search for an item with Item Category and AI should suggest the item + Initialize(); + // [GIVEN] Find an item with Item Category Code + Item.SetFilter("Item Category Code", '<>%1', ''); + Item.FindFirst(); + ItemCategory.SetRange("Code", Item."Item Category Code"); + ItemCategory.FindFirst(); + UserInput := GlobalUserInput; + UserInput += '5 quantity of ' + ItemCategory.Code + '; '; + LibraryVariableStorage.Enqueue(UserInput); + LibraryVariableStorage.Enqueue(1); + EnqueueOneItemAndQty(Item.Description, 5); + EnqueueOneItemAndQty(Item.Description, 5); + // [WHEN] User input is given to the AI suggestions + // [THEN] AI suggestions should one sales lines, it is handled in the handler function 'InvokeGenerateAndCheckItemsFound' + CreateNewSalesOrderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions); + // [THEN] One line is inserted in the sales line + CheckSalesLineContent(SalesHeader."No."); + end; + + [Test] + [HandlerFunctions('InvokeGenerateAndCheckItemsFound')] + procedure TestSearchBasedOnItemCategoryDesc() + var + SalesHeader: Record "Sales Header"; + Item: Record Item; + ItemCategory: Record "Item Category"; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + UserInput: Text; + begin + // [FEATURE] [Sales with AI]:[Search Item End to End] + // [Scenario] User wants to search for an item with Item Category Description and AI should suggest the item + Initialize(); + // [GIVEN] Find an item with Item Category Description + Item.SetFilter("Item Category Code", '<>%1', ''); + Item.FindFirst(); + ItemCategory.SetRange("Code", Item."Item Category Code"); + ItemCategory.FindFirst(); + UserInput := GlobalUserInput; + UserInput += '5 quantity of ' + ItemCategory.Description + '; '; + LibraryVariableStorage.Enqueue(UserInput); + LibraryVariableStorage.Enqueue(1); + EnqueueOneItemAndQty(Item.Description, 5); + EnqueueOneItemAndQty(Item.Description, 5); + // [WHEN] User input is given to the AI suggestions + // [THEN] AI suggestions should one sales lines, it is handled in the handler function 'InvokeGenerateAndCheckItemsFound' + CreateNewSalesOrderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions); + // [THEN] One line is inserted in the sales line + CheckSalesLineContent(SalesHeader."No."); + end; + + [Test] + [HandlerFunctions('InvokeGenerateAndCheckItemsFound')] + procedure TestSearchBasedOnItemCategoryParentCategory() + var + SalesHeader: Record "Sales Header"; + Item: Record Item; + ItemCategory: Record "Item Category"; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + UserInput: Text; + begin + // [FEATURE] [Sales with AI]:[Search Item End to End] + // [Scenario] User wants to search for an item with Parent Category of the item category and AI should suggest the item + Initialize(); + // [GIVEN] Find an item with Parent Category of the Item Category + Item.SetFilter("Item Category Code", '<>%1', ''); + Item.FindFirst(); + ItemCategory.SetRange("Code", Item."Item Category Code"); + ItemCategory.FindFirst(); + UserInput := GlobalUserInput; + UserInput += '5 quantity of ' + ItemCategory."Parent Category" + '; '; + LibraryVariableStorage.Enqueue(UserInput); + LibraryVariableStorage.Enqueue(1); + EnqueueOneItemAndQty(Item.Description, 5); + EnqueueOneItemAndQty(Item.Description, 5); + // [WHEN] User input is given to the AI suggestions + // [THEN] AI suggestions should one sales lines, it is handled in the handler function 'InvokeGenerateAndCheckItemsFound' + CreateNewSalesOrderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions); + // [THEN] One line is inserted in the sales line + CheckSalesLineContent(SalesHeader."No."); + end; + + [Test] + [HandlerFunctions('InvokeGenerateAndCheckItemsFound')] + procedure TestSearchBasedOnItemTranslationCode() + var + SalesHeader: Record "Sales Header"; + Item: Record Item; + ItemTranslation: Record "Item Translation"; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + UserInput: Text; + begin + // [FEATURE] [Sales with AI]:[Search Item End to End] + // [Scenario] User wants to search for an item with "Item Translate Code" and AI should suggest the item + Initialize(); + // [GIVEN] Find an item with Item Translate Code + ItemTranslation.FindFirst(); + Item.SetRange("No.", ItemTranslation."Item No."); + Item.FindFirst(); + UserInput := GlobalUserInput; + UserInput += '5 quantity of ' + ItemTranslation."Language Code" + '; '; + LibraryVariableStorage.Enqueue(UserInput); + LibraryVariableStorage.Enqueue(1); + EnqueueOneItemAndQty(Item.Description, 5); + EnqueueOneItemAndQty(Item.Description, 5); + // [WHEN] User input is given to the AI suggestions + // [THEN] AI suggestions should one sales lines, it is handled in the handler function 'InvokeGenerateAndCheckItemsFound' + CreateNewSalesOrderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions); + // [THEN] One line is inserted in the sales line + CheckSalesLineContent(SalesHeader."No."); + end; + + [Test] + [HandlerFunctions('InvokeGenerateAndCheckItemsFound')] + procedure TestSearchBasedOnItemTranslationDesc() + var + SalesHeader: Record "Sales Header"; + Item: Record Item; + ItemTranslation: Record "Item Translation"; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + UserInput: Text; + begin + // [FEATURE] [Sales with AI]:[Search Item End to End] + // [Scenario] User wants to search for an item with "Item Translate Description" and AI should suggest the item + Initialize(); + // [GIVEN] Find an item with Item Translate Description + ItemTranslation.FindFirst(); + Item.SetRange("No.", ItemTranslation."Item No."); + Item.FindFirst(); + UserInput := GlobalUserInput; + UserInput += '5 quantity of ' + ItemTranslation.Description + '; '; + LibraryVariableStorage.Enqueue(UserInput); + LibraryVariableStorage.Enqueue(1); + EnqueueOneItemAndQty(Item.Description, 5); + EnqueueOneItemAndQty(Item.Description, 5); + // [WHEN] User input is given to the AI suggestions + // [THEN] AI suggestions should one sales lines, it is handled in the handler function 'InvokeGenerateAndCheckItemsFound' + CreateNewSalesOrderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions); + // [THEN] One line is inserted in the sales line + CheckSalesLineContent(SalesHeader."No."); + end; + + [Test] + [HandlerFunctions('InvokeGenerateAndCheckItemsFound')] + procedure TestSearchBasedOnItemIdentifierCode() + var + SalesHeader: Record "Sales Header"; + Item: Record Item; + ItemIdentifier: Record "Item Identifier"; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + UserInput: Text; + begin + // [FEATURE] [Sales with AI]:[Search Item End to End] + // [Scenario] User wants to search for an item with "Item Identifier Code" and AI should suggest the item + Initialize(); + // [GIVEN] Find an item with Item Identifier Code + ItemIdentifier.FindFirst(); + Item.SetRange("No.", ItemIdentifier."Item No."); + Item.FindFirst(); + UserInput := GlobalUserInput; + UserInput += '5 quantity of ' + ItemIdentifier.Code + '; '; + LibraryVariableStorage.Enqueue(UserInput); + LibraryVariableStorage.Enqueue(1); + EnqueueOneItemAndQty(Item.Description, 5); + EnqueueOneItemAndQty(Item.Description, 5); + // [WHEN] User input is given to the AI suggestions + // [THEN] AI suggestions should one sales lines, it is handled in the handler function 'InvokeGenerateAndCheckItemsFound' + CreateNewSalesOrderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions); + // [THEN] One line is inserted in the sales line + CheckSalesLineContent(SalesHeader."No."); + end; + + [Test] + [HandlerFunctions('InvokeGenerateAndCheckItemsFound')] + procedure TestSearchBasedOnItemExtendedText() + var + SalesHeader: Record "Sales Header"; + Item: Record Item; + ItemExtendedTextLine: Record "Extended Text Line"; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + UserInput: Text; + begin + // [FEATURE] [Sales with AI]:[Search Item End to End] + // [Scenario] User wants to search for an item with "Item Extended Text" and AI should suggest the item + Initialize(); + // [GIVEN] Find an item with "Item Extended Text" + ItemExtendedTextLine.FindFirst(); + Item.SetRange("No.", ItemExtendedTextLine."No."); + Item.FindFirst(); + UserInput := GlobalUserInput; + UserInput += '5 quantity of ' + ItemExtendedTextLine.Text + '; '; + LibraryVariableStorage.Enqueue(UserInput); + LibraryVariableStorage.Enqueue(1); + EnqueueOneItemAndQty(Item.Description, 5); + EnqueueOneItemAndQty(Item.Description, 5); + // [WHEN] User input is given to the AI suggestions + // [THEN] AI suggestions should one sales lines, it is handled in the handler function 'InvokeGenerateAndCheckItemsFound' + CreateNewSalesOrderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions); + // [THEN] One line is inserted in the sales line + CheckSalesLineContent(SalesHeader."No."); + end; + + [Test] + [HandlerFunctions('InvokeGenerateAndNoItemFound,SendNotificationHandler')] + procedure TestSearchNotExistingItem() + var + SalesHeader: Record "Sales Header"; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + begin + // [FEATURE] [Sales with AI]:[Search Item End to End] + // [Scenario] User wants to search for an item that does not exist in the system, AI should not suggest any item and show a notification + Initialize(); + LibraryVariableStorage.Clear(); + // [GIVEN] Generate prompt with Document No. + LibraryVariableStorage.Enqueue(GlobalUserInput + '5 MiawCrosoft'); + LibraryVariableStorage.Enqueue(NoSuggestionGeneratedErr); + // [WHEN] User input is given to the AI suggestions + // [THEN] AI suggestions should not generate any sales lines, it is handled in the handler function 'InvokeGenerateAndNoItemFound + // [THEN] Show a notification, it is handled in the handler function 'SendNotificationHandler' + CreateNewSalesOrderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions); + // [THEN] No line is inserted in the sales line + CheckSalesLineContent(SalesHeader."No."); + end; + + [Test] + [HandlerFunctions('InvokeGenerateAndNoItemFound,SendNotificationHandler')] + procedure TestSearchSalesBlockedItem() + var + Item: Record Item; + SalesHeader: Record "Sales Header"; + SalesLineAISuggestions: Page "Sales Line AI Suggestions"; + Qty: Decimal; + UserInput: Text; + begin + // [FEATURE] [Sales with AI]:[Search Item End to End] + // [Scenario] User wants to search for sales blocked item, AI should not suggest sales blocked items + Initialize(); + Qty := 5; + // [GIVEN] Change one item to sales blocked + Item.FindFirst(); + Item.Validate("Sales Blocked", true); + Item.Modify(true); + UserInput := GlobalUserInput; + UserInput += Format(Qty) + ' quantity of ' + Item."No." + '; '; + // [WHEN] User input is given to the AI suggestions + LibraryVariableStorage.Enqueue(UserInput); + LibraryVariableStorage.Enqueue(NoSuggestionGeneratedErr); + // [THEN] AI suggestions should not generate any sales lines, it is handled in the handler function 'InvokeGenerateAndNoItemFound + // [THEN] Show a notification, it is handled in the handler function 'SendNotificationHandler' + CreateNewSalesOrderAndRunSalesLineAISuggestionsPage(SalesHeader, SalesLineAISuggestions); + // [THEN] No line is inserted in the sales line + CheckSalesLineContent(SalesHeader."No."); + end; + + [Test] + [HandlerFunctions('EvaluateSearchItemForMultipleItemNos')] + procedure EvaluateSearchItemForItemNoAsInput() + var + Item: Record Item; + SalesHeader: Record "Sales Header"; + SalesLine: Record "Sales Line"; + SalesLineAISuggestionImpl: Codeunit "Sales Lines Suggestions Impl."; + ListOfItems: List of [Text]; + Qty: Decimal; + i: Integer; + UserInput: Text; + begin + // [FEATURE] [Sales with AI]:[Search Item End to End] + // [Scenario] Add up to 50 item no. in sales lines using AI suggestions in one user input + Initialize(); + Qty := 5; + Item.SetLoadFields("No."); + Item.SetRange(Blocked, false); + Item.SetRange("Sales Blocked", false); + UserInput := GlobalUserInput; + if Item.FindSet() then + repeat + UserInput += Format(Qty) + ' quantity of ' + Item."No." + '; '; + ListOfItems.Add(Item."No."); + i += 1; + until (Item.Next() = 0) or (i = 5); + + // [GIVEN] Create a new sales order for a new customer + CreateSalesOrderWithSalesLine(SalesHeader, SalesLine); + + // [WHEN] User input is given to the AI suggestions + LibraryVariableStorage.Enqueue(UserInput); + LibraryVariableStorage.Enqueue(ListOfItems); + LibraryVariableStorage.Enqueue(Qty); + SalesLineAISuggestionImpl.GetLinesSuggestions(SalesLine); + + // [THEN] AI suggestions should generate the expected sales lines + // Handled in EvaluateSearchItemForMultipleItems + end; + + [Test] + [HandlerFunctions('EvaluateSearchItemForMultipleItemNos')] + procedure EvaluateSearchItemForItemDescAsInput() + var + Item: Record Item; + SalesHeader: Record "Sales Header"; + SalesLine: Record "Sales Line"; + SalesLineAISuggestionImpl: Codeunit "Sales Lines Suggestions Impl."; + ListOfItems: List of [Text]; + Qty: Decimal; + i: Integer; + UserInput: Text; + begin + // [FEATURE] [Sales with AI]:[Search Item End to End] + // [Scenario] Add up to 50 item no. in sales lines using AI suggestions in one user input + Initialize(); + Qty := 5; + Item.SetLoadFields("No.", Description); + Item.SetRange(Blocked, false); + Item.SetRange("Sales Blocked", false); + UserInput := GlobalUserInput; + if Item.FindSet() then + repeat + UserInput += Format(Qty) + ' quantity of ' + Item.Description + '; '; + ListOfItems.Add(Item."No."); + i += 1; + until (Item.Next() = 0) or (i = 5); + + // [GIVEN] Create a new sales order for a new customer + CreateSalesOrderWithSalesLine(SalesHeader, SalesLine); + + // [WHEN] User input is given to the AI suggestions + LibraryVariableStorage.Enqueue(UserInput); + LibraryVariableStorage.Enqueue(ListOfItems); + LibraryVariableStorage.Enqueue(Qty); + SalesLineAISuggestionImpl.GetLinesSuggestions(SalesLine); + + // [THEN] AI suggestions should generate the expected sales lines + // Handled in EvaluateSearchItemForMultipleItems + end; + + [Test] + [HandlerFunctions('EvaluateSearchItemForMultipleItemNos')] + procedure EvaluateSearchItemForItemNoAndDescAsInput() + var + Item: Record Item; + SalesHeader: Record "Sales Header"; + SalesLine: Record "Sales Line"; + SalesLineAISuggestionImpl: Codeunit "Sales Lines Suggestions Impl."; + ListOfItems: List of [Text]; + Qty: Decimal; + i: Integer; + UserInput: Text; + begin + // [FEATURE] [Sales with AI]:[Search Item End to End] + // [Scenario] Add up to 50 item no. in sales lines using AI suggestions in one user input + Initialize(); + Qty := 5; + Item.SetLoadFields("No.", Description); + Item.SetRange(Blocked, false); + Item.SetRange("Sales Blocked", false); + UserInput := GlobalUserInput; + if Item.FindSet() then + repeat + UserInput += Format(Qty) + ' quantity of ' + Item."No." + ' ' + Item.Description + '; '; + ListOfItems.Add(Item."No."); + i += 1; + until (Item.Next() = 0) or (i = 5); + + // [GIVEN] Create a new sales order for a new customer + CreateSalesOrderWithSalesLine(SalesHeader, SalesLine); + + // [WHEN] User input is given to the AI suggestions + LibraryVariableStorage.Enqueue(UserInput); + LibraryVariableStorage.Enqueue(ListOfItems); + LibraryVariableStorage.Enqueue(Qty); + SalesLineAISuggestionImpl.GetLinesSuggestions(SalesLine); + + // [THEN] AI suggestions should generate the expected sales lines + // Handled in EvaluateSearchItemForMultipleItems + end; + + local procedure CreateSalesOrderWithSalesLine(var SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line") + var + Customer: Record Customer; + begin + LibrarySales.CreateCustomer(Customer); + LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Order, Customer."No."); + LibrarySales.CreateSalesLineSimple(SalesLine, SalesHeader); + end; + + [PageHandler] + procedure EvaluateSearchItemForMultipleItemNos(var SalesLineAISuggestions: TestPage "Sales Line AI Suggestions") + var + Qty: Decimal; + ListOfItemsVariant: Variant; + ListOfItems: List of [Text]; + ListOfUnexpectedItems: List of [Text]; + DictOfFailedQty: Dictionary of [Code[20], Decimal]; + UserInput: Text; + begin + UserInput := LibraryVariableStorage.DequeueText(); + SalesLineAISuggestions.SearchQueryTxt.SetValue(UserInput); + LibraryVariableStorage.Dequeue(ListOfItemsVariant); + ListOfItems := ListOfItemsVariant; + Qty := LibraryVariableStorage.DequeueInteger(); + SalesLineAISuggestions.Generate.Invoke(); + + SalesLineAISuggestions.SalesLinesSub.First(); + repeat + if ListOfItems.Contains(SalesLineAISuggestions.SalesLinesSub."No.".Value()) then + ListOfItems.Remove(SalesLineAISuggestions.SalesLinesSub."No.".Value()) + else + ListOfUnexpectedItems.Add(SalesLineAISuggestions.SalesLinesSub."No.".Value()); + + if Qty <> SalesLineAISuggestions.SalesLinesSub.Quantity.AsDecimal() then + DictOfFailedQty.Add(Format(SalesLineAISuggestions.SalesLinesSub."No.".Value), SalesLineAISuggestions.SalesLinesSub.Quantity.AsDecimal()); + until SalesLineAISuggestions.SalesLinesSub.Next() = false; + + if (ListOfItems.Count > 0) or (ListOfUnexpectedItems.Count > 0) then + Error('Some items are not found in the AI suggestions. User input: %1\Missing Items: %2\Unexpected Items:%3\QtyMisMatch: %4', UserInput, ListOfTextToText(ListOfItems), ListOfTextToText(ListOfUnexpectedItems), DictionaryOfCodeToDecimalToText(DictOfFailedQty)); + + SalesLineAISuggestions.Cancel.Invoke(); + end; + + local procedure ListOfTextToText(var ListOfText: List of [Text]) Result: Text + var + Txt: Text; + begin + foreach Txt in ListOfText do + Result += Txt + ', '; + Result := Result.TrimEnd(', '); + end; + + local procedure DictionaryOfCodeToDecimalToText(var DictOfCodeToDecimal: Dictionary of [Code[20], Decimal]) Result: Text + var + Key1: Code[20]; + begin + foreach Key1 in DictOfCodeToDecimal.Keys do + Result += Key1 + ':' + Format(DictOfCodeToDecimal.Get(Key1)) + ', '; + Result := Result.TrimEnd(', '); + end; + + local procedure Initialize() + begin + GlobalUserInput := 'I need the following items: '; + end; + + local procedure CreateNewSalesOrderAndRunSalesLineAISuggestionsPage(var SalesHeader: Record "Sales Header"; var SalesLineAISuggestions: Page "Sales Line AI Suggestions") + var + Customer: Record Customer; + begin + SalesHeader.Reset(); + LibrarySales.CreateCustomer(Customer); + LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Order, Customer."No."); + SalesLineAISuggestions.SetSalesHeader(SalesHeader); + SalesLineAISuggestions.LookupMode := true; + SalesLineAISuggestions.RunModal(); + end; + + local procedure CheckSalesLineContent(DocumentNo: Text) + var + SalesLine: Record "Sales Line"; + begin + SalesLine.Reset(); + SalesLine.SetRange("Document No.", DocumentNo); + SalesLine.SetRange("Document Type", SalesLine."Document Type"::Order); + if SalesLine.FindSet() then + repeat + Assert.AreEqual(LibraryVariableStorage.DequeueText(), SalesLine.Description, DescriptionIsIncorrectErr); + Assert.AreEqual(LibraryVariableStorage.DequeueInteger(), SalesLine.Quantity, QuantityIsIncorrectErr); + until SalesLine.Next() = 0; + LibraryVariableStorage.AssertEmpty(); + end; + + local procedure EnqueueOneItemAndQty(ItemDesc: Text; Qty: Integer) + begin + LibraryVariableStorage.Enqueue(ItemDesc); + LibraryVariableStorage.Enqueue(Qty); + end; + + [ModalPageHandler] + procedure InvokeGenerateAndNoItemFound(var SalesLineAISuggestions: TestPage "Sales Line AI Suggestions") + begin + SalesLineAISuggestions.SearchQueryTxt.SetValue(LibraryVariableStorage.DequeueText()); + SalesLineAISuggestions.Generate.Invoke(); + Assert.IsFalse(SalesLineAISuggestions.SalesLinesSub.First(), 'No item should be found for the given input'); + SalesLineAISuggestions.OK.Invoke(); + end; + + [ModalPageHandler] + procedure InvokeGenerateAndCheckItemsFound(var SalesLineAISuggestions: TestPage "Sales Line AI Suggestions") + var + ItemCount: Integer; + quantityInSalesLineSub: Integer; + i: Integer; + begin + // Description for this queue: + //[{User Input},{Expected Generated Number(shown in page)},{first item's description},{first item's quantity}, {second item's description}, {second item's quantity}...{last item's description}, {last item's quantity] + // Example: ['I need all items from previous sales order 10000', '3', 'red bike', '2', 'blue bike','1', 'green bike', '1'] + // Create a new sales order for the new customer + Commit(); + SalesLineAISuggestions.SearchQueryTxt.SetValue(LibraryVariableStorage.DequeueText()); + ItemCount := LibraryVariableStorage.DequeueInteger(); + SalesLineAISuggestions.Generate.Invoke(); + SalesLineAISuggestions.SalesLinesSub.First(); + for i := 1 to ItemCount do begin + Assert.AreEqual(LibraryVariableStorage.DequeueText(), SalesLineAISuggestions.SalesLinesSub.Description.Value(), DescriptionIsIncorrectErr); + Evaluate(quantityInSalesLineSub, SalesLineAISuggestions.SalesLinesSub.Quantity.Value()); + Assert.AreEqual(LibraryVariableStorage.DequeueInteger(), quantityInSalesLineSub, QuantityIsIncorrectErr); + SalesLineAISuggestions.SalesLinesSub.Next(); + end; + SalesLineAISuggestions.OK.Invoke(); + end; + + [SendNotificationHandler] + procedure SendNotificationHandler(var TheNotification: Notification): Boolean + begin + Assert.AreEqual(LibraryVariableStorage.DequeueText(), TheNotification.Message, 'Notification message is incorrect'); + end; +} \ No newline at end of file diff --git a/Apps/W1/SalesLinesSuggestions/test/app.json b/Apps/W1/SalesLinesSuggestions/test/app.json new file mode 100644 index 0000000000..ef7c55fb48 --- /dev/null +++ b/Apps/W1/SalesLinesSuggestions/test/app.json @@ -0,0 +1,54 @@ +{ + "id": "1defd6cb-5fb9-4717-b50a-9d7f2b59fe88", + "name": "Sales Lines Suggestions Tests", + "publisher": "Microsoft", + "version": "25.0.0.0", + "brief": "Sales Lines Suggestions Tests", + "description": "Sales Lines Suggestions Tests", + "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", + "EULA": "https://go.microsoft.com/fwlink/?linkid=2182906", + "help": "https://go.microsoft.com/fwlink/?linkid=2206176", + "url": "https://go.microsoft.com/fwlink/?LinkId=724011", + "logo": "ExtensionLogo.png", + "dependencies": [ + { + "id": "dd3f226b-40bf-4b3c-9988-9b1e0f74edd8", + "publisher": "Microsoft", + "name": "Sales Lines Suggestions", + "version": "25.0.0.0" + }, + { + "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", + "name": "Tests-TestLibraries", + "publisher": "Microsoft", + "version": "25.0.0.0" + }, + { + "id": "5095f467-0a01-4b99-99d1-9ff1237d286f", + "publisher": "Microsoft", + "name": "Library Variable Storage", + "version": "25.0.0.0" + } + ], + "screenshots": [], + "platform": "25.0.0.0", + "application": "25.0.0.0", + "idRanges": [ + { + "from": 139780, + "to": 139785 + } + ], + "runtime": "13.0", + "contextSensitiveHelpUrl": "https://go.microsoft.com/fwlink/?linkid=2206176", + "resourceExposurePolicy": { + "allowDebugging": true, + "allowDownloadingSource": true, + "includeSourceInSymbolFile": true + }, + "target": "OnPrem", + "features": [ + "TranslationFile", + "GenerateCaptions" + ] +} \ No newline at end of file diff --git a/Apps/W1/SendToEmailPrinter/app.json b/Apps/W1/SendToEmailPrinter/app.json index 4c94090027..20bdfefa0f 100644 --- a/Apps/W1/SendToEmailPrinter/app.json +++ b/Apps/W1/SendToEmailPrinter/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "Provides functionality to use the printer's email address to send print jobs to the printer.", "description": "Provides functionality to use the printer's email address to send print jobs to the printer.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?linkid=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=724013", "help": "https://go.microsoft.com/fwlink/?linkid=2118801", @@ -19,7 +19,7 @@ "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "target": "OnPrem", "idRanges": [ { @@ -32,7 +32,7 @@ } ], "contextSensitiveHelpUrl": "https://go.microsoft.com/fwlink/?linkid=2118801", - "application": "24.0.0.0", + "application": "25.0.0.0", "resourceExposurePolicy": { "allowDebugging": true, "allowDownloadingSource": true, diff --git a/Apps/W1/ServiceDeclaration/app/app.json b/Apps/W1/ServiceDeclaration/app/app.json index 9c21cd6fde..bc07c68f23 100644 --- a/Apps/W1/ServiceDeclaration/app/app.json +++ b/Apps/W1/ServiceDeclaration/app/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "The Service Declaration extension makes it easy to export the service declaration in the format that the authorities in your country require.", "description": "In some EU countries, authorities require reporting for exporting services to the other EU countries. This feature enables collecting EU service''s intertrade and its reporting to the authorities. Even this feature is primarily created for Belgian, French and Italian markets, it can be used in all EU countries if needed as reporting is configurable.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://learn.microsoft.com/en-us/dynamics365/business-central/finance-how-setup-use-service-declaration", @@ -17,7 +17,7 @@ "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 5010, @@ -33,6 +33,6 @@ "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0", + "application": "25.0.0.0", "target": "Cloud" } \ No newline at end of file diff --git a/Apps/W1/ServiceDeclaration/app/src/Processing/ServiceDeclarationHeader.Table.al b/Apps/W1/ServiceDeclaration/app/src/Processing/ServiceDeclarationHeader.Table.al index 0fa257f355..14785d4523 100644 --- a/Apps/W1/ServiceDeclaration/app/src/Processing/ServiceDeclarationHeader.Table.al +++ b/Apps/W1/ServiceDeclaration/app/src/Processing/ServiceDeclarationHeader.Table.al @@ -19,6 +19,8 @@ table 5023 "Service Declaration Header" Caption = 'No.'; trigger OnValidate() + var + NoSeries: Codeunit "No. Series"; begin if "No." <> xRec."No." then begin TestNoSeries(); @@ -87,13 +89,15 @@ table 5023 "Service Declaration Header" var ServiceDeclarationSetup: Record "Service Declaration Setup"; +#if not CLEAN24 NoSeriesManagement: Codeunit NoSeriesManagement; - NoSeries: Codeunit "No. Series"; +#endif ServDeclAlreadyExistErr: Label 'The service declaration %1 already exists.', Comment = '%1 = service declaration number.'; trigger OnInsert() -#if not CLEAN24 var + NoSeries: Codeunit "No. Series"; +#if not CLEAN24 IsHandled: Boolean; #endif begin @@ -150,11 +154,12 @@ table 5023 "Service Declaration Header" procedure AssistEdit(OldServDeclHeader: Record "Service Declaration Header") Result: Boolean var ServDeclHeader: Record "Service Declaration Header"; + NoSeries: Codeunit "No. Series"; begin ServDeclHeader.Copy(Rec); TestNoSeries(); - if NoSeriesManagement.SelectSeries(ServiceDeclarationSetup."Declaration No. Series", OldServDeclHeader."No. Series", ServDeclHeader."No. Series") then begin - NoSeriesManagement.SetSeries(ServDeclHeader."No."); + if NoSeries.LookupRelatedNoSeries(ServiceDeclarationSetup."Declaration No. Series", OldServDeclHeader."No. Series", ServDeclHeader."No. Series") then begin + ServDeclHeader."No." := NoSeries.GetNextNo(ServDeclHeader."No. Series"); if ServDeclHeader.Get(ServDeclHeader."No.") then Error(ServDeclAlreadyExistErr, ServDeclHeader."No."); Rec := ServDeclHeader; diff --git a/Apps/W1/ServiceDeclaration/test/app.json b/Apps/W1/ServiceDeclaration/test/app.json index 0647abc80c..ceaa3372bb 100644 --- a/Apps/W1/ServiceDeclaration/test/app.json +++ b/Apps/W1/ServiceDeclaration/test/app.json @@ -2,7 +2,7 @@ "id": "bd16d8dd-8faf-45d3-b733-3ddc6b9cfabf", "name": "Service Declaration Tests", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Tests for the Microsoft Service Declaration extension.", "description": "Tests for the Microsoft Service Declaration extension.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -10,32 +10,32 @@ "help": "https://learn.microsoft.com/en-us/dynamics365/business-central/finance-how-setup-use-service-declaration", "url": "https://go.microsoft.com/fwlink/?LinkId=724011", "logo": "ExtensionLogo.png", - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "dependencies": [ { "id": "e2ae191d-8829-44c3-a373-3749a2742d4d", "name": "Service Declaration", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "9856ae4f-d1a7-46ef-89bb-6ef056398228", "name": "System Application Test Library", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5095f467-0a01-4b99-99d1-9ff1237d286f", "publisher": "Microsoft", "name": "Library Variable Storage", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "idRanges": [ diff --git a/Apps/W1/ServiceDeclaration/test/src/LibraryServiceDeclaration.Codeunit.al b/Apps/W1/ServiceDeclaration/test/src/LibraryServiceDeclaration.Codeunit.al index 61cc80b0f1..60af845429 100644 --- a/Apps/W1/ServiceDeclaration/test/src/LibraryServiceDeclaration.Codeunit.al +++ b/Apps/W1/ServiceDeclaration/test/src/LibraryServiceDeclaration.Codeunit.al @@ -71,7 +71,7 @@ codeunit 139900 "Library - Service Declaration" procedure CreateItemChargeSalesDocWithServTransTypeCode(var SalesHeader: Record "Sales Header"; var SalesLine: Record "Sales Line") begin CreateItemChargeSalesDocApplicableForServDecl(SalesHeader, SalesLine); - SalesLine.validate("Service Transaction Type Code", CreateServTransTypeCode()); + SalesLine.Validate("Service Transaction Type Code", CreateServTransTypeCode()); SalesLine.Modify(true); end; @@ -233,7 +233,7 @@ codeunit 139900 "Library - Service Declaration" begin LibraryPurchase.CreatePurchaseLine( PurchLine, PurchHeader, PurchLine.Type::Resource, LibraryResource.CreateResourceNo(), LibraryRandom.RandInt(100)); - PurchLine.validate("Direct Unit Cost", LibraryRandom.RandDec(100, 2)); + PurchLine.Validate("Direct Unit Cost", LibraryRandom.RandDec(100, 2)); PurchLine.Modify(true); end; diff --git a/Apps/W1/ServiceDeclaration/test/src/ServiceDeclarationUITests.Codeunit.al b/Apps/W1/ServiceDeclaration/test/src/ServiceDeclarationUITests.Codeunit.al index 8aa39287ab..d637e6bf65 100644 --- a/Apps/W1/ServiceDeclaration/test/src/ServiceDeclarationUITests.Codeunit.al +++ b/Apps/W1/ServiceDeclaration/test/src/ServiceDeclarationUITests.Codeunit.al @@ -108,7 +108,7 @@ codeunit 139902 "Service Declaration UI Tests" NoSeriesLine: Record "No. Series Line"; ServDeclSetup: Record "Service Declaration Setup"; ServDeclHeader: Record "Service Declaration Header"; - NoSeriesMgt: Codeunit NoSeriesManagement; + NoSeriesCodeunit: Codeunit "No. Series"; begin // [SCENARIO 457814] Stan cannot set service declaration number manually if this number already exists Initialize(); @@ -121,7 +121,7 @@ codeunit 139902 "Service Declaration UI Tests" ServDeclSetup.Validate("Declaration No. Series", NoSeries.Code); ServDeclSetup.Modify(true); // [GIVEN] Service declaration with number "SERVDECL-001" from No. Series inserted manually - ServDeclHeader.Validate("No.", NoSeriesMgt.GetNextNo(ServDeclSetup."Declaration No. Series", WorkDate(), false)); + ServDeclHeader.Validate("No.", NoSeriesCodeunit.PeekNextNo(ServDeclSetup."Declaration No. Series")); ServDeclHeader.Insert(true); // [WHEN] Call AssistEdit and select No. Series "X" Asserterror ServDeclHeader.AssistEdit(ServDeclHeader); diff --git a/Apps/W1/Shopify/app/app.json b/Apps/W1/Shopify/app/app.json index 60ce9eb083..f12cd1d979 100644 --- a/Apps/W1/Shopify/app/app.json +++ b/Apps/W1/Shopify/app/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "Seamless connection between Shopify and Dynamics 365 Business Central will synchronize order, stock, and customer information to ensure that merchants can fulfill orders faster and better serve their customers.", "description": "Connecting Dynamics 365 Business Central with Shopify will help merchants implement more agile online business processes, while keeping people focused on selling. With support for multitier pricing structures and multiple currencies, companies, and entities, Business Central will support multiple Shopify store scenarios with ease. By connecting Shopify and Business Central, you will improve visibility into stock, pricing, existing customers and order history, order status, billing, and payments.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=2179727", @@ -17,7 +17,7 @@ "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 30100, @@ -41,9 +41,9 @@ "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0", + "application": "25.0.0.0", "target": "OnPrem", "features": [ - "NoImplicitWith" - ] + "NoImplicitWith" + ] } \ No newline at end of file diff --git a/Apps/W1/Shopify/app/src/Base/Codeunits/ShpfyCommunicationMgt.Codeunit.al b/Apps/W1/Shopify/app/src/Base/Codeunits/ShpfyCommunicationMgt.Codeunit.al index 5412d04f80..aed3322ff8 100644 --- a/Apps/W1/Shopify/app/src/Base/Codeunits/ShpfyCommunicationMgt.Codeunit.al +++ b/Apps/W1/Shopify/app/src/Base/Codeunits/ShpfyCommunicationMgt.Codeunit.al @@ -17,7 +17,7 @@ codeunit 30103 "Shpfy Communication Mgt." CommunicationEvents: Codeunit "Shpfy Communication Events"; GraphQLQueries: Codeunit "Shpfy GraphQL Queries"; NextExecutionTime: DateTime; - VersionTok: Label '2023-04', Locked = true; + VersionTok: Label '2024-01', Locked = true; OutgoingRequestsNotEnabledConfirmLbl: Label 'Importing data to your Shopify shop is not enabled, do you want to go to shop card to enable?'; OutgoingRequestsNotEnabledErr: Label 'Importing data to your Shopify shop is not enabled, navigate to shop card to enable.'; IsTestInProgress: Boolean; diff --git a/Apps/W1/Shopify/app/src/Base/Codeunits/ShpfyUpgradeMgt.Codeunit.al b/Apps/W1/Shopify/app/src/Base/Codeunits/ShpfyUpgradeMgt.Codeunit.al index 820682b925..61c8be6219 100644 --- a/Apps/W1/Shopify/app/src/Base/Codeunits/ShpfyUpgradeMgt.Codeunit.al +++ b/Apps/W1/Shopify/app/src/Base/Codeunits/ShpfyUpgradeMgt.Codeunit.al @@ -409,26 +409,44 @@ codeunit 30106 "Shpfy Upgrade Mgt." local procedure CreditMemoCanBeCreatedUpgrade() var - RefundLine: Record "Shpfy Refund Line"; + RefundHeader: Record "Shpfy Refund Header"; UpgradeTag: Codeunit "Upgrade Tag"; - RefundLineDataTransfer: DataTransfer; + HeadersInFilter, MaxHeadersInFilter : Integer; + RefundIdFilter: Text; begin if UpgradeTag.HasUpgradeTag(GetCreditMemoCanBeCreatedUpgradeTag()) then exit; + MaxHeadersInFilter := 100; + RefundHeader.SetFilter("Total Refunded Amount", '>%1', 0); + if RefundHeader.FindSet() then + repeat + if RefundIdFilter <> '' then + RefundIdFilter += '|'; + RefundIdFilter += Format(RefundHeader."Refund Id"); + HeadersInFilter += 1; + if HeadersInFilter >= MaxHeadersInFilter then begin + SetCanCreateCreditMemoInRefundLines(RefundIdFilter); + RefundIdFilter := ''; + HeadersInFilter := 0; + end; + until RefundHeader.Next() = 0; + if RefundIdFilter <> '' then + SetCanCreateCreditMemoInRefundLines(RefundIdFilter); + + UpgradeTag.SetUpgradeTag(GetCreditMemoCanBeCreatedUpgradeTag()); + end; + + local procedure SetCanCreateCreditMemoInRefundLines(RefundIdFilter: Text) + var + RefundLine: Record "Shpfy Refund Line"; + RefundLineDataTransfer: DataTransfer; + begin RefundLineDataTransfer.SetTables(Database::"Shpfy Refund Line", Database::"Shpfy Refund Line"); - RefundLineDataTransfer.AddSourceFilter(RefundLine.FieldNo("Restock Type"), '=%1|%2|%3', RefundLine."Restock Type"::Return, RefundLine."Restock Type"::"Legacy Restock", RefundLine."Restock Type"::"No Restock"); + RefundLineDataTransfer.AddSourceFilter(RefundLine.FieldNo("Refund Id"), RefundIdFilter); RefundLineDataTransfer.AddConstantValue(true, RefundLine.FieldNo("Can Create Credit Memo")); RefundLineDataTransfer.UpdateAuditFields(false); RefundLineDataTransfer.CopyFields(); - Clear(RefundLineDataTransfer); - RefundLineDataTransfer.SetTables(Database::"Shpfy Refund Line", Database::"Shpfy Refund Line"); - RefundLineDataTransfer.AddSourceFilter(RefundLine.FieldNo("Restock Type"), '=%1', RefundLine."Restock Type"::Cancel); - RefundLineDataTransfer.AddConstantValue(false, RefundLine.FieldNo("Can Create Credit Memo")); - RefundLineDataTransfer.UpdateAuditFields(false); - RefundLineDataTransfer.CopyFields(); - - UpgradeTag.SetUpgradeTag(GetCreditMemoCanBeCreatedUpgradeTag()); end; local procedure GetShopifyB2BEnabledUpgradeTag(): Code[250] diff --git a/Apps/W1/Shopify/app/src/Base/Pages/ShpfyActivities.Page.al b/Apps/W1/Shopify/app/src/Base/Pages/ShpfyActivities.Page.al index ee55e7f5ec..87991a09d0 100644 --- a/Apps/W1/Shopify/app/src/Base/Pages/ShpfyActivities.Page.al +++ b/Apps/W1/Shopify/app/src/Base/Pages/ShpfyActivities.Page.al @@ -88,6 +88,12 @@ page 30100 "Shpfy Activities" Page.Run(Page::"Job Queue Log Entries", JobQueueLogEntry); end; } + field(UnprocessedOrderUpdates; Rec."Unprocessed Order Updates") + { + ApplicationArea = All; + ToolTip = 'Specifies the number of order updates that aren''t processed.'; + DrillDownPageId = "Shpfy Orders"; + } } } } @@ -95,10 +101,11 @@ page 30100 "Shpfy Activities" trigger OnOpenPage() begin Rec.Reset(); - if not Rec.Get() then begin - Rec.Init(); - Rec.Insert(); - Commit(); - end; + if not Rec.Get() then + if Rec.WritePermission then begin + Rec.Init(); + Rec.Insert(); + Commit(); + end; end; } \ No newline at end of file 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 01b3d303ab..29b64ce181 100644 --- a/Apps/W1/Shopify/app/src/Base/Pages/ShpfyShopCard.Page.al +++ b/Apps/W1/Shopify/app/src/Base/Pages/ShpfyShopCard.Page.al @@ -358,6 +358,7 @@ page 30101 "Shpfy Shop Card" { ApplicationArea = All; ShowMandatory = true; + Caption = 'Customer/Company Template Code'; ToolTip = 'Specifies which customer template to use when creating unknown customers.'; Visible = not NewTemplatesEnabled; ObsoleteReason = 'Generic Templates will be replaced with Customer Templates. Use Customer Templ. Code instead.'; @@ -367,7 +368,7 @@ page 30101 "Shpfy Shop Card" #endif field(CustomerTemplCode; Rec."Customer Templ. Code") { - Caption = 'Customer Template Code'; + Caption = 'Customer/Company Template Code'; ToolTip = 'Specifies which customer template to use when creating unknown customers.'; ShowMandatory = true; ApplicationArea = All; @@ -421,7 +422,52 @@ page 30101 "Shpfy Shop Card" field(CountySource; Rec."County Source") { ApplicationArea = All; - ToolTip = 'Specifies how to synchronize the county of the customer.'; + ToolTip = 'Specifies how to synchronize the county of the customer/company.'; + } + } + group("B2B Company Synchronization") + { + Visible = Rec."B2B Enabled"; + field("Company Import From Shopify"; Rec."Company Import From Shopify") + { + ApplicationArea = All; + ToolTip = 'Specifies how Shopify companies are synced to Business Central.'; + Importance = Promoted; + } + field("Company Mapping Type"; Rec."Company Mapping Type") + { + ApplicationArea = All; + ToolTip = 'Specifies how to map companies.'; + } + field("Auto Create Unknown Companies"; Rec."Auto Create Unknown Companies") + { + ApplicationArea = All; + ToolTip = 'Specifies if unknown companies are automatically created in D365BC when synchronizing from Shopify.'; + } + field("Default Company No."; Rec."Default Company No.") + { + ApplicationArea = All; + ToolTip = 'Specifies the default customer when not creating a company for each B2B company.'; + } + field("Shopify Can Update Companies"; Rec."Shopify Can Update Companies") + { + ApplicationArea = All; + ToolTip = 'Specifies whether Shopify can update companies when synchronizing from Shopify.'; + } + field("Can Update Shopify Companies"; Rec."Can Update Shopify Companies") + { + ApplicationArea = All; + ToolTip = 'Specifies whether D365BC can update companies when synchronizing to Shopify.'; + } + field("Default Customer Permission"; Rec."Default Contact Permission") + { + ApplicationArea = All; + ToolTip = 'Specifies the default customer permission for new companies.'; + } + field("Auto Create Catalog"; Rec."Auto Create Catalog") + { + ApplicationArea = All; + ToolTip = 'Specifies whether a catalog is automatically created for new companies.'; } } group(OrderProcessing) @@ -559,50 +605,6 @@ page 30101 "Shpfy Shop Card" } } } - group("B2B Company Synchronization") - { - Visible = Rec."B2B Enabled"; - field("Can Update Shopify Companies"; Rec."Can Update Shopify Companies") - { - ApplicationArea = All; - ToolTip = 'Specifies whether D365BC can update companies when synchronizing to Shopify.'; - } - field("Shopify Can Update Companies"; Rec."Shopify Can Update Companies") - { - ApplicationArea = All; - ToolTip = 'Specifies whether Shopify can update companies when synchronizing from Shopify.'; - } - field("Company Import From Shopify"; Rec."Company Import From Shopify") - { - ApplicationArea = All; - ToolTip = 'Specifies how Shopify companies are synced to Business Central.'; - } - field("Auto Create Unknown Companies"; Rec."Auto Create Unknown Companies") - { - ApplicationArea = All; - ToolTip = 'Specifies if unknown companies are automatically created in D365BC when synchronizing from Shopify.'; - } - field("Default Company No."; Rec."Default Company No.") - { - ApplicationArea = All; - ToolTip = 'Specifies the default customer when not creating a company for each B2B company.'; - } - field("Company Mapping Type"; Rec."Company Mapping Type") - { - ApplicationArea = All; - ToolTip = 'Specifies how to map companies.'; - } - field("Default Customer Permission"; Rec."Default Contact Permission") - { - ApplicationArea = All; - ToolTip = 'Specifies the default customer permission for new companies.'; - } - field("Auto Create Catalog"; Rec."Auto Create Catalog") - { - ApplicationArea = All; - ToolTip = 'Specifies whether a catalog is automatically created for new companies.'; - } - } } } diff --git a/Apps/W1/Shopify/app/src/Base/Tables/ShpfyCue.Table.al b/Apps/W1/Shopify/app/src/Base/Tables/ShpfyCue.Table.al index 2b51cefc52..3592d5a9c1 100644 --- a/Apps/W1/Shopify/app/src/Base/Tables/ShpfyCue.Table.al +++ b/Apps/W1/Shopify/app/src/Base/Tables/ShpfyCue.Table.al @@ -14,18 +14,18 @@ table 30100 "Shpfy Cue" fields { - Field(1; "Primary Key"; Code[10]) + field(1; "Primary Key"; Code[10]) { Caption = 'Primary Key'; DataClassification = SystemMetadata; } - Field(2; "Unmapped Customers"; Integer) + field(2; "Unmapped Customers"; Integer) { CalcFormula = count("Shpfy Customer" where("Customer No." = const(''))); Caption = 'Unmapped Customers'; FieldClass = FlowField; } - Field(3; "Unmapped Products"; Integer) + field(3; "Unmapped Products"; Integer) { CalcFormula = count("Shpfy Product" where("Item No." = const(''))); Caption = 'Unmapped Products'; @@ -63,6 +63,12 @@ table 30100 "Shpfy Cue" Caption = 'Shipments Errors'; FieldClass = FlowField; } + field(8; "Unprocessed Order Updates"; Integer) + { + CalcFormula = count("Shpfy Order Header" where("Has Order State Error" = const(true))); + Caption = 'Unprocessed Order Updates'; + FieldClass = FlowField; + } } keys 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 05a65530c1..4f591b877d 100644 --- a/Apps/W1/Shopify/app/src/Base/Tables/ShpfyShop.Table.al +++ b/Apps/W1/Shopify/app/src/Base/Tables/ShpfyShop.Table.al @@ -74,7 +74,7 @@ table 30102 "Shpfy Shop" end else begin Rec.Enabled := true; Rec.Validate("Order Created Webhooks", false); - WebhooksMgt.DisableBulkOperationsWebhook(Rec); + WebhooksMgt.DisableBulkOperationsWebhook(Rec, CompanyName()); Rec.Enabled := false; end; end; @@ -631,7 +631,7 @@ table 30102 "Shpfy Shop" if "Order Created Webhooks" then ShpfyWebhooksMgt.EnableOrderCreatedWebhook(Rec) else - ShpfyWebhooksMgt.DisableOrderCreatedWebhook(Rec); + ShpfyWebhooksMgt.DisableOrderCreatedWebhook(Rec, CompanyName()); end; } field(109; "Order Created Webhook User"; Code[50]) @@ -807,7 +807,7 @@ table 30102 "Shpfy Shop" var ShpfyWebhooksMgt: Codeunit "Shpfy Webhooks Mgt."; begin - ShpfyWebhooksMgt.DisableOrderCreatedWebhook(Rec); + ShpfyWebhooksMgt.DisableOrderCreatedWebhook(Rec, CompanyName()); end; var diff --git a/Apps/W1/Shopify/app/src/Catalogs/Codeunits/ShpfyCatalogAPI.Codeunit.al b/Apps/W1/Shopify/app/src/Catalogs/Codeunits/ShpfyCatalogAPI.Codeunit.al index 2bf0ba4e56..fe7790a84c 100644 --- a/Apps/W1/Shopify/app/src/Catalogs/Codeunits/ShpfyCatalogAPI.Codeunit.al +++ b/Apps/W1/Shopify/app/src/Catalogs/Codeunits/ShpfyCatalogAPI.Codeunit.al @@ -83,7 +83,7 @@ codeunit 30290 "Shpfy Catalog API" GraphQLType := "Shpfy GraphQL Type"::GetNextCatalogs; end else break; - until not JsonHelper.GetValueAsBoolean(JResponse, 'data.orders.pageInfo.hasNextPage'); + until not JsonHelper.GetValueAsBoolean(JResponse, 'data.catalogs.pageInfo.hasNextPage'); end; internal procedure GetCatalogPrices(CatalogId: BigInteger; var TempCatalogPrice: Record "Shpfy Catalog Price" temporary) @@ -91,13 +91,15 @@ codeunit 30290 "Shpfy Catalog API" GraphQLType: Enum "Shpfy GraphQL Type"; Cursor: Text; JResponse: JsonToken; + ProductList: List of [BigInteger]; Parameters: Dictionary of [Text, Text]; begin + GetIncludedProductsInCatalog(CatalogId, ProductList); Parameters.Add('CatalogId', Format(CatalogId)); repeat JResponse := CommunicationMgt.ExecuteGraphQL(GraphQLType::GetCatalogPrices, Parameters); if JResponse.IsObject() then - if ExtractShopifyCatalogPrices(TempCatalogPrice, JResponse.AsObject(), Cursor) then begin + if ExtractShopifyCatalogPrices(TempCatalogPrice, ProductList, JResponse.AsObject(), Cursor) then begin if Parameters.ContainsKey('After') then Parameters.Set('After', Cursor) else @@ -105,13 +107,14 @@ codeunit 30290 "Shpfy Catalog API" GraphQLType := "Shpfy GraphQL Type"::GetNextCatalogPrices; end else break; - until not JsonHelper.GetValueAsBoolean(JResponse, 'data.catalog.priceList.prices.hasNextPage'); + until not JsonHelper.GetValueAsBoolean(JResponse, 'data.catalog.priceList.prices.pageInfo.hasNextPage'); end; internal procedure AddUpdatePriceGraphQL(var TempCatalogPrice: Record "Shpfy Catalog Price" temporary; Price: Decimal; CompareAtPrice: Decimal; var JSetPrice: JsonObject): Boolean var HasChange: Boolean; JPrice: JsonObject; + JNullValue: JsonValue; JCompareAtPrice: JsonObject; VariantIdTxt: Label 'gid://shopify/ProductVariant/%1', Locked = true, Comment = '%1 = The product variant Id'; begin @@ -130,7 +133,8 @@ codeunit 30290 "Shpfy Catalog API" JSetPrice.Add('compareAtPrice', JCompareAtPrice); end else begin HasChange := true; - JSetPrice.Add('compareAtPrice', 'null'); + JNullValue.SetValueToNull(); + JSetPrice.Add('compareAtPrice', JNullValue.AsToken()); end; if HasChange then @@ -158,7 +162,7 @@ codeunit 30290 "Shpfy Catalog API" JSetPrices := JsonHelper.GetJsonArray(JGraphQL, 'variables.prices'); end; - internal procedure ExtractShopifyCatalogPrices(var TempCatalogPrice: Record "Shpfy Catalog Price" temporary; JResponse: JsonObject; var Cursor: Text): Boolean + internal procedure ExtractShopifyCatalogPrices(var TempCatalogPrice: Record "Shpfy Catalog Price" temporary; ProductList: List of [BigInteger]; JResponse: JsonObject; var Cursor: Text): Boolean var JCatalogs: JsonArray; JEdge: JsonToken; @@ -167,15 +171,16 @@ codeunit 30290 "Shpfy Catalog API" if JsonHelper.GetJsonArray(JResponse, JCatalogs, 'data.catalog.priceList.prices.edges') then begin foreach JEdge in JCatalogs do begin Cursor := JsonHelper.GetValueAsText(JEdge.AsObject(), 'cursor'); - if JsonHelper.GetJsonObject(JEdge.AsObject(), JNode, 'node') then begin - TempCatalogPrice."Variant Id" := CommunicationMgt.GetIdOfGId(JsonHelper.GetValueAsText(JNode, 'variant.id')); - TempCatalogPrice."Shop Code" := Shop.Code; - TempCatalogPrice."Price List Id" := CommunicationMgt.GetIdOfGId(JsonHelper.GetValueAsText(JResponse, 'data.catalog.priceList.id')); - TempCatalogPrice."Price List Currency" := StrSubstNo(JsonHelper.GetValueAsCode(JResponse, 'data.catalog.priceList.currency'), 1, MaxStrLen(TempCatalogPrice."Price List Currency")); - TempCatalogPrice.Price := JsonHelper.GetValueAsDecimal(JNode, 'price.amount'); - TempCatalogPrice."Compare At Price" := JsonHelper.GetValueAsDecimal(JNode, 'compareAtPrice.amount'); - TempCatalogPrice.Insert(); - end; + if JsonHelper.GetJsonObject(JEdge.AsObject(), JNode, 'node') then + if ProductList.Contains(CommunicationMgt.GetIdOfGId(JsonHelper.GetValueAsText(JNode, 'variant.product.id'))) then begin + TempCatalogPrice."Variant Id" := CommunicationMgt.GetIdOfGId(JsonHelper.GetValueAsText(JNode, 'variant.id')); + TempCatalogPrice."Shop Code" := Shop.Code; + TempCatalogPrice."Price List Id" := CommunicationMgt.GetIdOfGId(JsonHelper.GetValueAsText(JResponse, 'data.catalog.priceList.id')); + TempCatalogPrice."Price List Currency" := StrSubstNo(JsonHelper.GetValueAsCode(JResponse, 'data.catalog.priceList.currency'), 1, MaxStrLen(TempCatalogPrice."Price List Currency")); + TempCatalogPrice.Price := JsonHelper.GetValueAsDecimal(JNode, 'price.amount'); + TempCatalogPrice."Compare At Price" := JsonHelper.GetValueAsDecimal(JNode, 'compareAtPrice.amount'); + TempCatalogPrice.Insert(); + end; end; exit(true); end; @@ -214,6 +219,47 @@ codeunit 30290 "Shpfy Catalog API" end; end; + internal procedure GetIncludedProductsInCatalog(CatalogId: BigInteger; var ProductList: List of [BigInteger]) + var + GraphQLType: Enum "Shpfy GraphQL Type"; + Cursor: Text; + JResponse: JsonToken; + Parameters: Dictionary of [Text, Text]; + begin + Parameters.Add('CatalogId', Format(CatalogId)); + repeat + JResponse := CommunicationMgt.ExecuteGraphQL(GraphQLType::GetCatalogProducts, Parameters); + if JResponse.IsObject() then + if ExtractShopifyCatalogProducts(ProductList, JResponse.AsObject(), Cursor) then begin + if Parameters.ContainsKey('After') then + Parameters.Set('After', Cursor) + else + Parameters.Add('After', Cursor); + GraphQLType := "Shpfy GraphQL Type"::GetNextCatalogProducts; + end else + break; + until not JsonHelper.GetValueAsBoolean(JResponse, 'data.catalog.publication.products.pageInfo.hasNextPage'); + end; + + internal procedure ExtractShopifyCatalogProducts(var ProductList: List of [BigInteger]; JResponse: JsonObject; var Cursor: Text): Boolean + var + JCatalogProducts: JsonArray; + JEdge: JsonToken; + JNode: JsonObject; + ProductId: BigInteger; + begin + if JsonHelper.GetJsonArray(JResponse, JCatalogProducts, 'data.catalog.publication.products.edges') then begin + foreach JEdge in JCatalogProducts do begin + Cursor := JsonHelper.GetValueAsText(JEdge.AsObject(), 'cursor'); + if JsonHelper.GetJsonObject(JEdge.AsObject(), JNode, 'node') then begin + ProductId := CommunicationMgt.GetIdOfGId(JsonHelper.GetValueAsText(JNode, 'id')); + ProductList.Add(ProductId); + end; + end; + exit(true); + end; + end; + internal procedure GetCatalogProductsURL(CatalogId: BigInteger): Text begin exit(StrSubstNo(ShopifyCatalogURLLbl, Shop."Shopify URL".Substring(1, Shop."Shopify URL".IndexOf('.myshopify.com') - 1).TrimStart('https://'), Format(CatalogId))); diff --git a/Apps/W1/Shopify/app/src/Catalogs/Codeunits/ShpfySyncCatalogPrices.Codeunit.al b/Apps/W1/Shopify/app/src/Catalogs/Codeunits/ShpfySyncCatalogPrices.Codeunit.al index af249e661e..7dda488254 100644 --- a/Apps/W1/Shopify/app/src/Catalogs/Codeunits/ShpfySyncCatalogPrices.Codeunit.al +++ b/Apps/W1/Shopify/app/src/Catalogs/Codeunits/ShpfySyncCatalogPrices.Codeunit.al @@ -13,6 +13,7 @@ codeunit 30295 "Shpfy Sync Catalog Prices" trigger OnRun() var Catalog: Record "Shpfy Catalog"; + CatalogIds: List of [BigInteger]; begin SetShop(Rec); Catalog.SetRange("Shop Code", Shop.Code); @@ -21,8 +22,11 @@ codeunit 30295 "Shpfy Sync Catalog Prices" Catalog.SetRange("Company SystemId", CompanyId); if Catalog.FindSet() then repeat - ProductPriceCalc.SetShopAndCatalog(Shop, Catalog); - SyncCatalogPrices(Catalog); + if not CatalogIds.Contains(Catalog.Id) then begin + CatalogIds.Add(Catalog.Id); + ProductPriceCalc.SetShopAndCatalog(Shop, Catalog); + SyncCatalogPrices(Catalog); + end; until Catalog.Next() = 0; end; @@ -74,7 +78,8 @@ codeunit 30295 "Shpfy Sync Catalog Prices" end; until TempCatalogPrice.Next() = 0; - CatalogAPI.UpdatePrice(JGraphQL, TempCatalogPrice."Price List Id"); + if JSetPrices.Count() > 0 then + CatalogAPI.UpdatePrice(JGraphQL, TempCatalogPrice."Price List Id"); end; end; diff --git a/Apps/W1/Shopify/app/src/Catalogs/Pages/ShpfyCatalogs.Page.al b/Apps/W1/Shopify/app/src/Catalogs/Pages/ShpfyCatalogs.Page.al index ca4550064b..82dd1773dc 100644 --- a/Apps/W1/Shopify/app/src/Catalogs/Pages/ShpfyCatalogs.Page.al +++ b/Apps/W1/Shopify/app/src/Catalogs/Pages/ShpfyCatalogs.Page.al @@ -162,9 +162,17 @@ page 30159 "Shpfy Catalogs" trigger OnAction() var + Shop: Record "Shpfy Shop"; + SyncCatalogsPrices: Report "Shpfy Sync Catalog Prices"; BackgroundSyncs: Codeunit "Shpfy Background Syncs"; begin - BackgroundSyncs.CatalogPricesSync(Rec."Shop Code", Rec.GetFilter("Company SystemId")); + if Rec.GetFilter("Company SystemId") <> '' then + BackgroundSyncs.CatalogPricesSync(Rec."Shop Code", Rec.GetFilter("Company SystemId")) + else begin + Shop.SetRange(Code, Rec."Shop Code"); + SyncCatalogsPrices.SetTableView(Shop); + SyncCatalogsPrices.Run(); + end; end; } } diff --git a/Apps/W1/Shopify/app/src/Catalogs/Reports/ShpfySyncCatalogPrices.Report.al b/Apps/W1/Shopify/app/src/Catalogs/Reports/ShpfySyncCatalogPrices.Report.al index 88004afec1..5a4f66a991 100644 --- a/Apps/W1/Shopify/app/src/Catalogs/Reports/ShpfySyncCatalogPrices.Report.al +++ b/Apps/W1/Shopify/app/src/Catalogs/Reports/ShpfySyncCatalogPrices.Report.al @@ -16,6 +16,12 @@ report 30116 "Shpfy Sync Catalog Prices" { RequestFilterFields = Code; + trigger OnPreDataItem() + begin + if not Shop.HasFilter() then + Error(NoShopSelectedErr); + end; + trigger OnAfterGetRecord() begin if CompanyId <> '' then @@ -35,6 +41,7 @@ report 30116 "Shpfy Sync Catalog Prices" Caption = 'Company Id'; Tooltip = 'Specifies the company id to sync prices for. If empty, all companies will be synced.'; ApplicationArea = All; + Visible = false; } } } @@ -43,4 +50,5 @@ report 30116 "Shpfy Sync Catalog Prices" var SyncCatalogPrices: Codeunit "Shpfy Sync Catalog Prices"; CompanyId: Text; + NoShopSelectedErr: Label 'You must select a shop to sync prices for.'; } \ No newline at end of file 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 e985690852..7b440f4430 100644 --- a/Apps/W1/Shopify/app/src/Companies/Codeunits/ShpfyCompanyAPI.Codeunit.al +++ b/Apps/W1/Shopify/app/src/Companies/Codeunits/ShpfyCompanyAPI.Codeunit.al @@ -121,6 +121,8 @@ codeunit 30286 "Shpfy Company API" AddFieldToGraphQuery(GraphQuery, 'phone', CompanyLocation."Phone No."); if CompanyLocation."Country/Region Code" <> '' then AddFieldToGraphQuery(GraphQuery, 'countryCode', CompanyLocation."Country/Region Code", false); + if CompanyLocation."Province Code" <> '' then + AddFieldToGraphQuery(GraphQuery, 'zoneCode', CompanyLocation."Province Code"); GraphQuery.Remove(GraphQuery.Length - 1, 2); GraphQuery.Append('}}}) {company {id, name, locations(first: 1) {edges {node {id, name}}}, contactRoles(first:10) {edges {node {id,name}}}}, userErrors {field, message}}}"}'); exit(GraphQuery.ToText()); @@ -205,6 +207,8 @@ codeunit 30286 "Shpfy Company API" HasChange := AddFieldToGraphQuery(GraphQuery, 'phone', CompanyLocation."Phone No."); if CompanyLocation."Country/Region Code" <> xCompanyLocation."Country/Region Code" then HasChange := AddFieldToGraphQuery(GraphQuery, 'countryCode', CompanyLocation."Country/Region Code", false); + if CompanyLocation."Province Code" <> xCompanyLocation."Province Code" then + HasChange := AddFieldToGraphQuery(GraphQuery, 'zoneCode', CompanyLocation."Province Code"); GraphQuery.Remove(GraphQuery.Length - 1, 2); if HasChange then begin @@ -332,6 +336,8 @@ codeunit 30286 "Shpfy Company API" CompanyLocation.Zip := CopyStr(JsonHelper.GetValueAsCode(JItem, 'node.billingAddress.zip', MaxStrLen(CompanyLocation.Zip)), 1, MaxStrLen(CompanyLocation.Zip)); CompanyLocation.City := CopyStr(JsonHelper.GetValueAsText(JItem, 'node.billingAddress.city', MaxStrLen(CompanyLocation.City)), 1, MaxStrLen(CompanyLocation.City)); CompanyLocation."Country/Region Code" := CopyStr(JsonHelper.GetValueAsCode(JItem, 'node.billingAddress.countryCode', MaxStrLen(CompanyLocation."Country/Region Code")), 1, MaxStrLen(CompanyLocation."Country/Region Code")); + CompanyLocation."Province Code" := CopyStr(JsonHelper.GetValueAsText(JItem, 'node.billingAddress.zoneCode', MaxStrLen(CompanyLocation."Province Code")), 1, MaxStrLen(CompanyLocation."Province Code")); + CompanyLocation."Province Name" := CopyStr(JsonHelper.GetValueAsText(JItem, 'node.billingAddress.province', MaxStrLen(CompanyLocation."Province Name")), 1, MaxStrLen(CompanyLocation."Province Name")); 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.")); diff --git a/Apps/W1/Shopify/app/src/Companies/Codeunits/ShpfyCompanyExport.Codeunit.al b/Apps/W1/Shopify/app/src/Companies/Codeunits/ShpfyCompanyExport.Codeunit.al index f014525b1b..cf65199341 100644 --- a/Apps/W1/Shopify/app/src/Companies/Codeunits/ShpfyCompanyExport.Codeunit.al +++ b/Apps/W1/Shopify/app/src/Companies/Codeunits/ShpfyCompanyExport.Codeunit.al @@ -37,6 +37,7 @@ codeunit 30284 "Shpfy Company Export" CompanyAPI: Codeunit "Shpfy Company API"; CatalogAPI: Codeunit "Shpfy Catalog API"; CreateCustomers: Boolean; + CountyCodeTooLongLbl: Label 'Can not export customer %1 %2. The length of the string is %3, but it must be less than or equal to %4 characters. Value: %5, field: %6', Comment = '%1 - Customer No., %2 - Customer Name, %3 - Length, %4 - Max Length, %5 - Value, %6 - Field Name'; local procedure CreateShopifyCompany(Customer: Record Customer) var @@ -50,8 +51,6 @@ codeunit 30284 "Shpfy Company Export" if CreateCompanyMainContact(Customer, ShopifyCustomer) then if FillInShopifyCompany(Customer, ShopifyCompany, CompanyLocation) then if CompanyAPI.CreateCompany(ShopifyCompany, CompanyLocation, ShopifyCustomer) then begin - if Shop."Auto Create Catalog" then - CatalogAPI.CreateCatalog(ShopifyCompany); ShopifyCompany."Main Contact Customer Id" := ShopifyCustomer.Id; ShopifyCompany."Customer SystemId" := Customer.SystemId; ShopifyCompany."Last Updated by BC" := CurrentDateTime(); @@ -59,6 +58,9 @@ codeunit 30284 "Shpfy Company Export" ShopifyCompany."Shop Code" := Shop.Code; ShopifyCompany.Insert(); + if Shop."Auto Create Catalog" then + CatalogAPI.CreateCatalog(ShopifyCompany); + CompanyLocation."Company SystemId" := ShopifyCompany.SystemId; CompanyLocation.Insert(); end; @@ -82,8 +84,10 @@ codeunit 30284 "Shpfy Company Export" var CompanyInformation: Record "Company Information"; CountryRegion: Record "Country/Region"; + TaxArea: Record "Shpfy Tax Area"; TempShopifyCompany: Record "Shpfy Company" temporary; TempCompanyLocation: Record "Shpfy Company Location" temporary; + CountyCodeTooLongErr: Text; begin TempShopifyCompany := ShopifyCompany; TempCompanyLocation := CompanyLocation; @@ -96,6 +100,38 @@ codeunit 30284 "Shpfy Company Export" CompanyLocation.Zip := Customer."Post Code"; CompanyLocation.City := Customer.City; + if Customer.County <> '' then + case Shop."County Source" of + Shop."County Source"::Code: + begin + if StrLen(Customer.County) > MaxStrLen(TaxArea."County Code") then begin + CountyCodeTooLongErr := StrSubstNo(CountyCodeTooLongLbl, Customer."No.", Customer.Name, StrLen(Customer.County), MaxStrLen(TaxArea."County Code"), Customer.County, Customer.FieldCaption(County)); + Error(CountyCodeTooLongErr); + end; + TaxArea.SetRange("Country/Region Code", Customer."Country/Region Code"); + TaxArea.SetRange("County Code", Customer.County); + if TaxArea.FindFirst() then begin + CompanyLocation."Province Code" := TaxArea."County Code"; + CompanyLocation."Province Name" := TaxArea.County; + end; + end; + Shop."County Source"::Name: + begin + TaxArea.SetRange("Country/Region Code", Customer."Country/Region Code"); + TaxArea.SetRange(County, Customer.County); + if TaxArea.FindFirst() then begin + CompanyLocation."Province Code" := TaxArea."County Code"; + CompanyLocation."Province Name" := TaxArea.County; + end else begin + TaxArea.SetFilter(County, Customer.County + '*'); + if TaxArea.FindFirst() then begin + CompanyLocation."Province Code" := TaxArea."County Code"; + CompanyLocation."Province Name" := TaxArea.County; + end; + end; + end; + end; + if (Customer."Country/Region Code" = '') and CompanyInformation.Get() then Customer."Country/Region Code" := CompanyInformation."Country/Region Code"; 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 106da4c98b..d73ca0e433 100644 --- a/Apps/W1/Shopify/app/src/Companies/Tables/ShpfyCompanyLocation.Table.al +++ b/Apps/W1/Shopify/app/src/Companies/Tables/ShpfyCompanyLocation.Table.al @@ -58,6 +58,16 @@ table 30151 "Shpfy Company Location" DataClassification = CustomerContent; Editable = false; } + field(10; "Province Code"; Code[2]) + { + Caption = 'Province'; + DataClassification = CustomerContent; + } + field(11; "Province Name"; Text[50]) + { + Caption = 'Province Name'; + DataClassification = CustomerContent; + } } keys { diff --git a/Apps/W1/Shopify/app/src/Customers/Codeunits/ShpfyCountyCode.Codeunit.al b/Apps/W1/Shopify/app/src/Customers/Codeunits/ShpfyCountyCode.Codeunit.al index 87466bb4a1..dbc2d25d69 100644 --- a/Apps/W1/Shopify/app/src/Customers/Codeunits/ShpfyCountyCode.Codeunit.al +++ b/Apps/W1/Shopify/app/src/Customers/Codeunits/ShpfyCountyCode.Codeunit.al @@ -20,4 +20,16 @@ codeunit 30108 "Shpfy County Code" implements "Shpfy ICounty" begin exit(CopyStr(CustomerAddress."Province Code", 1, MaxStrLen(Customer.County))); end; + + /// + /// Description for County. + /// + /// Parameter of type Record "Shopify Company Location". + /// Return variable "Text". + internal procedure County(CompanyLocation: Record "Shpfy Company Location"): Text + var + Customer: Record Customer; + begin + exit(CopyStr(CompanyLocation."Province Code", 1, MaxStrLen(Customer.County))); + end; } \ No newline at end of file diff --git a/Apps/W1/Shopify/app/src/Customers/Codeunits/ShpfyCountyName.Codeunit.al b/Apps/W1/Shopify/app/src/Customers/Codeunits/ShpfyCountyName.Codeunit.al index c342d358cc..2daf1acb0f 100644 --- a/Apps/W1/Shopify/app/src/Customers/Codeunits/ShpfyCountyName.Codeunit.al +++ b/Apps/W1/Shopify/app/src/Customers/Codeunits/ShpfyCountyName.Codeunit.al @@ -20,4 +20,16 @@ codeunit 30109 "Shpfy County Name" implements "Shpfy ICounty" begin exit(CopyStr(CustomerAddress."Province Name".Trim(), 1, MaxStrLen(Customer.County))); end; + + /// + /// Description for County. + /// + /// Parameter of type Record "Shopify Company Location". + /// Return variable "Text". + internal procedure County(CompanyLocation: Record "Shpfy Company Location"): Text + var + Customer: Record Customer; + begin + exit(CopyStr(CompanyLocation."Province Name".Trim(), 1, MaxStrLen(Customer.County))); + end; } \ No newline at end of file diff --git a/Apps/W1/Shopify/app/src/Customers/Codeunits/ShpfyCreateCustomer.Codeunit.al b/Apps/W1/Shopify/app/src/Customers/Codeunits/ShpfyCreateCustomer.Codeunit.al index 44741accfd..cf5f923bf7 100644 --- a/Apps/W1/Shopify/app/src/Customers/Codeunits/ShpfyCreateCustomer.Codeunit.al +++ b/Apps/W1/Shopify/app/src/Customers/Codeunits/ShpfyCreateCustomer.Codeunit.al @@ -185,6 +185,7 @@ codeunit 30110 "Shpfy Create Customer" ShopifyCustomer: Record "Shpfy Customer"; CountryRegion: Record "Country/Region"; CompanyLocation: Record "Shpfy Company Location"; + ShopifyTaxArea: Record "Shpfy Tax Area"; #if not CLEAN22 ConfigTemplateHeader: Record "Config. Template Header"; ConfigConfigTemplateLine: Record "Config. Template Line"; @@ -198,6 +199,7 @@ codeunit 30110 "Shpfy Create Customer" #if not CLEAN22 CustomerRecordRef: RecordRef; #endif + ICounty: Interface "Shpfy ICounty"; CountryCode: Code[20]; CurrentTemplateCode: Code[20]; IsHandled: Boolean; @@ -242,13 +244,31 @@ codeunit 30110 "Shpfy Create Customer" Customer.Validate("Country/Region Code", CountryCode); Customer.Validate(City, CompanyLocation.City); Customer.Validate("Post Code", CompanyLocation.Zip); + + ICounty := Shop."County Source"; + Customer.Validate(County, ICounty.County(CompanyLocation)); + if CompanyLocation."Phone No." <> '' then Customer.Validate("Phone No.", CompanyLocation."Phone No."); + + if ShopifyTaxArea.Get(CompanyLocation."Country/Region Code", CompanyLocation."Province Name") then begin + if (ShopifyTaxArea."Tax Area Code" <> '') then begin + Customer.Validate("Tax Area Code", ShopifyTaxArea."Tax Area Code"); + Customer.Validate("Tax Liable", ShopifyTaxArea."Tax Liable"); + end; + if (ShopifyTaxArea."VAT Bus. Posting Group" <> '') then + Customer.Validate("VAT Bus. Posting Group", ShopifyTaxArea."VAT Bus. Posting Group"); + end; + Customer.Modify(); - ShopifyCustomer.Copy(TempShopifyCustomer); - ShopifyCustomer."Customer SystemId" := Customer.SystemId; - ShopifyCustomer.Insert(); + if ShopifyCustomer.Get(TempShopifyCustomer.Id) then begin + ShopifyCustomer."Customer SystemId" := Customer.SystemId; + ShopifyCustomer.Modify(); + end else begin + ShopifyCustomer.Copy(TempShopifyCustomer); + ShopifyCustomer.Insert(); + end; ShopifyCompany."Customer SystemId" := Customer.SystemId; ShopifyCompany."Main Contact Customer Id" := ShopifyCustomer.Id; @@ -265,8 +285,22 @@ codeunit 30110 "Shpfy Create Customer" Customer.Validate("Country/Region Code", CountryCode); Customer.Validate(City, CompanyLocation.City); Customer.Validate("Post Code", CompanyLocation.Zip); + + ICounty := Shop."County Source"; + Customer.Validate(County, ICounty.County(CompanyLocation)); + if CompanyLocation."Phone No." <> '' then Customer.Validate("Phone No.", CompanyLocation."Phone No."); + + if ShopifyTaxArea.Get(CompanyLocation."Country/Region Code", CompanyLocation."Province Name") then begin + if (ShopifyTaxArea."Tax Area Code" <> '') then begin + Customer.Validate("Tax Area Code", ShopifyTaxArea."Tax Area Code"); + Customer.Validate("Tax Liable", ShopifyTaxArea."Tax Liable"); + end; + if (ShopifyTaxArea."VAT Bus. Posting Group" <> '') then + Customer.Validate("VAT Bus. Posting Group", ShopifyTaxArea."VAT Bus. Posting Group"); + end; + Customer.Modify(); ShopifyCustomer.Copy(TempShopifyCustomer); @@ -288,8 +322,22 @@ codeunit 30110 "Shpfy Create Customer" Customer.Validate("Country/Region Code", CountryCode); Customer.Validate(City, CompanyLocation.City); Customer.Validate("Post Code", CompanyLocation.Zip); + + ICounty := Shop."County Source"; + Customer.Validate(County, ICounty.County(CompanyLocation)); + if CompanyLocation."Phone No." <> '' then Customer.Validate("Phone No.", CompanyLocation."Phone No."); + + if ShopifyTaxArea.Get(CompanyLocation."Country/Region Code", CompanyLocation."Province Name") then begin + if (ShopifyTaxArea."Tax Area Code" <> '') then begin + Customer.Validate("Tax Area Code", ShopifyTaxArea."Tax Area Code"); + Customer.Validate("Tax Liable", ShopifyTaxArea."Tax Liable"); + end; + if (ShopifyTaxArea."VAT Bus. Posting Group" <> '') then + Customer.Validate("VAT Bus. Posting Group", ShopifyTaxArea."VAT Bus. Posting Group"); + end; + Customer.Modify(); ShopifyCustomer.Copy(TempShopifyCustomer); diff --git a/Apps/W1/Shopify/app/src/Customers/Codeunits/ShpfyCustomerAPI.Codeunit.al b/Apps/W1/Shopify/app/src/Customers/Codeunits/ShpfyCustomerAPI.Codeunit.al index e7cee55f54..7aaa79444d 100644 --- a/Apps/W1/Shopify/app/src/Customers/Codeunits/ShpfyCustomerAPI.Codeunit.al +++ b/Apps/W1/Shopify/app/src/Customers/Codeunits/ShpfyCustomerAPI.Codeunit.al @@ -264,8 +264,11 @@ codeunit 30114 "Shpfy Customer API" if JItem.IsObject then begin if ShopifyCustomer.Id <> CommunicationMgt.GetIdOfGId(JsonHelper.GetValueAsText(JItem, 'id')) then Error(UpdateCustIdErr); - ShopifyCustomer."Accepts Marketing" := JsonHelper.GetValueAsBoolean(JItem, 'acceptsMarketing'); - ShopifyCustomer."Accepts Marketing Update At" := JsonHelper.GetValueAsDateTime(JItem, 'acceptsMArketingUpdatedAt'); + if JsonHelper.GetValueAsText(JItem, 'emailMarketingConsent.marketingState') = 'SUBSCRIBED' then + ShopifyCustomer."Accepts Marketing" := true + else + ShopifyCustomer."Accepts Marketing" := false; + ShopifyCustomer."Accepts Marketing Update At" := JsonHelper.GetValueAsDateTime(JItem, 'emailMarketingConsent.consentUpdatedAt'); ShopifyCustomer."Tax Exempt" := JsonHelper.GetValueAsBoolean(JItem, 'taxExempt'); ShopifyCustomer."Updated At" := JsonHelper.GetValueAsDateTime(JItem, 'updatedAt'); ShopifyCustomer."Verified Email" := JsonHelper.GetValueAsBoolean(JItem, 'verifiedEmail'); @@ -339,7 +342,7 @@ codeunit 30114 "Shpfy Customer API" if HasChange then begin GraphQuery.Remove(GraphQuery.Length - 1, 2); - GraphQuery.Append('}}) {customer {id, acceptsMarketing, acceptsMarketingUpdatedAt, tags, updatedAt, verifiedEmail, defaultAddress {id, province, country}}, userErrors {field, message}}}"}'); + GraphQuery.Append('}}) {customer {id, tags, updatedAt, verifiedEmail, emailMarketingConsent {consentUpdatedAt marketingState}, defaultAddress {id, province, country}}, userErrors {field, message}}}"}'); exit(GraphQuery.ToText()); end; end; @@ -380,8 +383,11 @@ codeunit 30114 "Shpfy Customer API" PhoneNo := JsonHelper.GetValueAsText(JCustomer, 'phone'); PhoneNo := DelChr(PhoneNo, '=', DelChr(PhoneNo, '=', '1234567890/+ .()')); ShopifyCustomer."Phone No." := CopyStr(PhoneNo, 1, MaxStrLen(ShopifyCustomer."Phone No.")); - ShopifyCustomer."Accepts Marketing" := JsonHelper.GetValueAsBoolean(JCustomer, 'acceptsMarketing'); - ShopifyCustomer."Accepts Marketing Update At" := JsonHelper.GetValueAsDateTime(JCustomer, 'acceptsMarketingUpdateAt'); + if JsonHelper.GetValueAsText(JCustomer, 'emailMarketingConsent.marketingState') = 'SUBSCRIBED' then + ShopifyCustomer."Accepts Marketing" := true + else + ShopifyCustomer."Accepts Marketing" := false; + ShopifyCustomer."Accepts Marketing Update At" := JsonHelper.GetValueAsDateTime(JCustomer, 'emailMarketingConsent.consentUpdatedAt'); ShopifyCustomer."Tax Exempt" := JsonHelper.GetValueAsBoolean(JCustomer, 'taxExempt'); ShopifyCustomer."Verified Email" := JsonHelper.GetValueAsBoolean(JCustomer, 'verifiedEmail'); StateString := JsonHelper.GetValueAsText(JCustomer, 'state').ToLower(); diff --git a/Apps/W1/Shopify/app/src/Customers/Codeunits/ShpfyUpdateCustomer.Codeunit.al b/Apps/W1/Shopify/app/src/Customers/Codeunits/ShpfyUpdateCustomer.Codeunit.al index 7b39f19b68..ad14287308 100644 --- a/Apps/W1/Shopify/app/src/Customers/Codeunits/ShpfyUpdateCustomer.Codeunit.al +++ b/Apps/W1/Shopify/app/src/Customers/Codeunits/ShpfyUpdateCustomer.Codeunit.al @@ -121,7 +121,7 @@ codeunit 30124 "Shpfy Update Customer" if ShopifyCustomer.Email <> '' then Customer.Validate("E-Mail", CopyStr(ShopifyCustomer.Email, 1, MaxStrLen(Customer."E-Mail"))); - if ShopifyTaxArea.Get(CustomerAddress."Country/Region Code", CustomerAddress."Province Name") then begin + if ShopifyTaxArea.Get(CustomerAddress."Country/Region Code", CustomerAddress."Province Name") then begin // TODONAT if (ShopifyTaxArea."Tax Area Code" <> '') then begin Customer.Validate("Tax Area Code", ShopifyTaxArea."Tax Area Code"); Customer.Validate("Tax Liable", ShopifyTaxArea."Tax Liable"); @@ -136,6 +136,8 @@ codeunit 30124 "Shpfy Update Customer" Customer: Record Customer; CountryRegion: Record "Country/Region"; CompanyLocation: Record "Shpfy Company Location"; + ShopifyTaxArea: Record "Shpfy Tax Area"; + ICounty: Interface "Shpfy ICounty"; begin if not Customer.GetBySystemId(ShopifyCompany."Customer SystemId") then exit; @@ -155,10 +157,23 @@ codeunit 30124 "Shpfy Update Customer" Customer.Validate(City, CompanyLocation.City); Customer.Validate("Post Code", CompanyLocation.Zip); + Customer.Validate(County, CompanyLocation."Province Code"); + + ICounty := Shop."County Source"; + Customer.Validate(County, ICounty.County(CompanyLocation)); if CompanyLocation."Phone No." <> '' then Customer.Validate("Phone No.", CompanyLocation."Phone No."); + if ShopifyTaxArea.Get(CompanyLocation."Country/Region Code", CompanyLocation."Province Name") then begin + if (ShopifyTaxArea."Tax Area Code" <> '') then begin + Customer.Validate("Tax Area Code", ShopifyTaxArea."Tax Area Code"); + Customer.Validate("Tax Liable", ShopifyTaxArea."Tax Liable"); + end; + if (ShopifyTaxArea."VAT Bus. Posting Group" <> '') then + Customer.Validate("VAT Bus. Posting Group", ShopifyTaxArea."VAT Bus. Posting Group"); + end; + Customer.Modify(); end; diff --git a/Apps/W1/Shopify/app/src/Customers/Interfaces/ShpfyICounty.Interface.al b/Apps/W1/Shopify/app/src/Customers/Interfaces/ShpfyICounty.Interface.al index 8e992826e3..33a84d7a5a 100644 --- a/Apps/W1/Shopify/app/src/Customers/Interfaces/ShpfyICounty.Interface.al +++ b/Apps/W1/Shopify/app/src/Customers/Interfaces/ShpfyICounty.Interface.al @@ -13,4 +13,11 @@ interface "Shpfy ICounty" /// Parameter of type Record "Shopify Customer Address". /// Return variable "Text". procedure County(ShopifyCustomerAddress: Record "Shpfy Customer Address"): Text; + + /// + /// Description for County. + /// + /// Parameter of type Record "Shopify Company Location". + /// Return variable "Text". + procedure County(ShopifyCompanyLocation: Record "Shpfy Company Location"): Text; } \ No newline at end of file diff --git a/Apps/W1/Shopify/app/src/Customers/Pages/ShpfyCustomerTemplates.Page.al b/Apps/W1/Shopify/app/src/Customers/Pages/ShpfyCustomerTemplates.Page.al index ebc9d59d08..c2067d373a 100644 --- a/Apps/W1/Shopify/app/src/Customers/Pages/ShpfyCustomerTemplates.Page.al +++ b/Apps/W1/Shopify/app/src/Customers/Pages/ShpfyCustomerTemplates.Page.al @@ -25,6 +25,7 @@ page 30108 "Shpfy Customer Templates" field(CustomerTemlateCode; Rec."Customer Template Code") { ApplicationArea = All; + Caption = 'Customer/Company Template Code'; ToolTip = 'Specifies which customer template to use when creating unknown customers for this country. This template will only be used if the field "Fix CustomerNo." is blank'; Visible = not NewTemplatesEnabled; ObsoleteReason = 'Replaced by Customer Templ. Code'; @@ -35,6 +36,7 @@ page 30108 "Shpfy Customer Templates" field(CustomerTemplCode; Rec."Customer Templ. Code") { ApplicationArea = All; + Caption = 'Customer/Company Template Code'; ToolTip = 'Specifies which customer template to use when creating unknown customers for this country. This template will only be used if the field "Fix CustomerNo." is blank'; #if not CLEAN22 Visible = NewTemplatesEnabled; diff --git a/Apps/W1/Shopify/app/src/GraphQL/Codeunits/ShpfyGQLCatalogPrices.Codeunit.al b/Apps/W1/Shopify/app/src/GraphQL/Codeunits/ShpfyGQLCatalogPrices.Codeunit.al index a018b21d3b..21f809425c 100644 --- a/Apps/W1/Shopify/app/src/GraphQL/Codeunits/ShpfyGQLCatalogPrices.Codeunit.al +++ b/Apps/W1/Shopify/app/src/GraphQL/Codeunits/ShpfyGQLCatalogPrices.Codeunit.al @@ -10,7 +10,7 @@ codeunit 30296 "Shpfy GQL CatalogPrices" implements "Shpfy IGraphQL" /// Return value of type Text. internal procedure GetGraphQL(): Text begin - exit('{"query": "query { catalog(id: \"gid://shopify/Catalog/{{CatalogId}}\") { id priceList {id currency prices(first:100) {edges {cursor node {variant {id} price {amount} compareAtPrice {amount}}} pageInfo {hasNextPage}}}}}"}'); + exit('{"query": "query { catalog(id: \"gid://shopify/Catalog/{{CatalogId}}\") { id priceList {id currency prices(first:100) {edges {cursor node {variant {id product {id}} price {amount} compareAtPrice {amount}}} pageInfo {hasNextPage}}}}}"}'); end; /// @@ -19,6 +19,6 @@ codeunit 30296 "Shpfy GQL CatalogPrices" implements "Shpfy IGraphQL" /// Return value of type Integer. internal procedure GetExpectedCost(): Integer begin - exit(204); + exit(304); end; } diff --git a/Apps/W1/Shopify/app/src/GraphQL/Codeunits/ShpfyGQLCatalogProducts.Codeunit.al b/Apps/W1/Shopify/app/src/GraphQL/Codeunits/ShpfyGQLCatalogProducts.Codeunit.al new file mode 100644 index 0000000000..4492f0e170 --- /dev/null +++ b/Apps/W1/Shopify/app/src/GraphQL/Codeunits/ShpfyGQLCatalogProducts.Codeunit.al @@ -0,0 +1,27 @@ +namespace Microsoft.Integration.Shopify; + +/// +/// Codeunit Shpfy GQL CatalogProducts (ID 30309) implements Interface Shpfy IGraphQL. +/// +codeunit 30309 "Shpfy GQL CatalogProducts" implements "Shpfy IGraphQL" +{ + Access = Internal; + + /// + /// GetGraphQL. + /// + /// Return value of type Text. + internal procedure GetGraphQL(): Text + begin + exit('{"query":"{catalog(id: \"gid://shopify/Catalog/{{CatalogId}}\"){ id publication { id products(first: 250) { edges { cursor node { id }} pageInfo { hasNextPage }}}}}"}'); + end; + + /// + /// GetExpectedCost. + /// + /// Return value of type Integer. + internal procedure GetExpectedCost(): Integer + begin + exit(15); + end; +} 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 b3c1c229ae..1e836f24f7 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 zip}}}}}}"}'); + 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}}}}}}"}'); end; /// diff --git a/Apps/W1/Shopify/app/src/GraphQL/Codeunits/ShpfyGQLCustomer.Codeunit.al b/Apps/W1/Shopify/app/src/GraphQL/Codeunits/ShpfyGQLCustomer.Codeunit.al index ae9cc3ca32..01f216dbbe 100644 --- a/Apps/W1/Shopify/app/src/GraphQL/Codeunits/ShpfyGQLCustomer.Codeunit.al +++ b/Apps/W1/Shopify/app/src/GraphQL/Codeunits/ShpfyGQLCustomer.Codeunit.al @@ -13,7 +13,7 @@ codeunit 30127 "Shpfy GQL Customer" implements "Shpfy IGraphQL" /// Return value of type Text. internal procedure GetGraphQL(): Text begin - exit('{"query":"{customer(id: \"gid://shopify/Customer/{{CustomerId}}\") {legacyResourceId firstName lastName email phone acceptsMarketing acceptsMarketingUpdatedAt taxExempt taxExemptions verifiedEmail state note createdAt updatedAt tags addresses {id company firstName lastName address1 address2 zip city countryCodeV2 country provinceCode province phone} defaultAddress {id} metafields(namespace: \"Microsoft.Dynamics365.BusinessCentral\" first: 10) {edges {node {id namespace ownerType legacyResourceId key value}}}}}"}'); + exit('{"query":"{customer(id: \"gid://shopify/Customer/{{CustomerId}}\") {legacyResourceId firstName lastName email phone taxExempt taxExemptions verifiedEmail state note createdAt updatedAt tags emailMarketingConsent {consentUpdatedAt marketingState} addresses {id company firstName lastName address1 address2 zip city countryCodeV2 country provinceCode province phone} defaultAddress {id} metafields(namespace: \"Microsoft.Dynamics365.BusinessCentral\" first: 10) {edges {node {id namespace ownerType legacyResourceId key value}}}}}"}'); end; /// diff --git a/Apps/W1/Shopify/app/src/GraphQL/Codeunits/ShpfyGQLFFOrdersFromOrder.Codeunit.al b/Apps/W1/Shopify/app/src/GraphQL/Codeunits/ShpfyGQLFFOrdersFromOrder.Codeunit.al index 5e141f5bd5..0d64623eda 100644 --- a/Apps/W1/Shopify/app/src/GraphQL/Codeunits/ShpfyGQLFFOrdersFromOrder.Codeunit.al +++ b/Apps/W1/Shopify/app/src/GraphQL/Codeunits/ShpfyGQLFFOrdersFromOrder.Codeunit.al @@ -10,7 +10,7 @@ codeunit 30267 "Shpfy GQL FFOrdersFromOrder" implements "Shpfy IGraphQL" /// Return value of type Text. internal procedure GetGraphQL(): Text begin - exit('{"query":"{order(id: \"gid:\/\/shopify\/Order\/{{OrderId}}\") { legacyResourceId fulfillmentOrders(first: 25, query:\"-status:closed\") { pageInfo { hasNextPage } edges { cursor node { id updatedAt status assignedLocation {location {legacyResourceId}} order {legacyResourceId}}}}}}"}'); + exit('{"query":"{order(id: \"gid:\/\/shopify\/Order\/{{OrderId}}\") { legacyResourceId fulfillmentOrders(first: 25, query:\"-status:closed\") { pageInfo { hasNextPage } edges { cursor node { id updatedAt status assignedLocation {location {legacyResourceId}} order {legacyResourceId} deliveryMethod {methodType}}}}}}"}'); end; /// @@ -19,6 +19,6 @@ codeunit 30267 "Shpfy GQL FFOrdersFromOrder" implements "Shpfy IGraphQL" /// Return value of type Integer. internal procedure GetExpectedCost(): Integer begin - exit(128); + exit(134); end; } \ No newline at end of file diff --git a/Apps/W1/Shopify/app/src/GraphQL/Codeunits/ShpfyGQLNextCatalogProducts.Codeunit.al b/Apps/W1/Shopify/app/src/GraphQL/Codeunits/ShpfyGQLNextCatalogProducts.Codeunit.al new file mode 100644 index 0000000000..cf5ff7c990 --- /dev/null +++ b/Apps/W1/Shopify/app/src/GraphQL/Codeunits/ShpfyGQLNextCatalogProducts.Codeunit.al @@ -0,0 +1,27 @@ +namespace Microsoft.Integration.Shopify; + +/// +/// Codeunit Shpfy GQL NextCatalogProducts (ID 30310) implements Interface Shpfy IGraphQL. +/// +codeunit 30310 "Shpfy GQL NextCatalogProducts" implements "Shpfy IGraphQL" +{ + Access = Internal; + + /// + /// GetGraphQL. + /// + /// Return value of type Text. + internal procedure GetGraphQL(): Text + begin + exit('{"query":"{catalog(id: \"gid://shopify/Catalog/{{CatalogId}}\"){ id publication { id products(first: 250, after:\"{{After}}\") { edges { cursor node { id }} pageInfo { hasNextPage }}}}}"}'); + end; + + /// + /// GetExpectedCost. + /// + /// Return value of type Integer. + internal procedure GetExpectedCost(): Integer + begin + exit(15); + end; +} diff --git a/Apps/W1/Shopify/app/src/GraphQL/Codeunits/ShpfyGQLNextFFOrdersFromOrd.Codeunit.al b/Apps/W1/Shopify/app/src/GraphQL/Codeunits/ShpfyGQLNextFFOrdersFromOrd.Codeunit.al index 7f12022ea0..9757e81dd0 100644 --- a/Apps/W1/Shopify/app/src/GraphQL/Codeunits/ShpfyGQLNextFFOrdersFromOrd.Codeunit.al +++ b/Apps/W1/Shopify/app/src/GraphQL/Codeunits/ShpfyGQLNextFFOrdersFromOrd.Codeunit.al @@ -10,7 +10,7 @@ codeunit 30268 "Shpfy GQL NextFFOrdersFromOrd" implements "Shpfy IGraphQL" /// Return value of type Text. internal procedure GetGraphQL(): Text begin - exit('{"query":"{order(id: \"gid:\/\/shopify\/Order\/{{OrderId}}\") { legacyResourceId fulfillmentOrders(first: 25, after:\"{{After}}\", query:\"-status:closed\") { pageInfo { hasNextPage } edges { cursor node { id updatedAt assignedLocation {location {legacyResourceId}} order {legacyResourceId}}}}}}"}'); + exit('{"query":"{order(id: \"gid:\/\/shopify\/Order\/{{OrderId}}\") { legacyResourceId fulfillmentOrders(first: 25, after:\"{{After}}\", query:\"-status:closed\") { pageInfo { hasNextPage } edges { cursor node { id updatedAt assignedLocation {location {legacyResourceId}} order {legacyResourceId} deliveryMethod {methodType}}}}}}"}'); end; /// @@ -19,6 +19,6 @@ codeunit 30268 "Shpfy GQL NextFFOrdersFromOrd" implements "Shpfy IGraphQL" /// Return value of type Integer. internal procedure GetExpectedCost(): Integer begin - exit(128); + exit(134); end; } \ No newline at end of file diff --git a/Apps/W1/Shopify/app/src/GraphQL/Codeunits/ShpfyGQLNextOpenFFOrders.Codeunit.al b/Apps/W1/Shopify/app/src/GraphQL/Codeunits/ShpfyGQLNextOpenFFOrders.Codeunit.al index 7eb3d4e6f0..2748adb485 100644 --- a/Apps/W1/Shopify/app/src/GraphQL/Codeunits/ShpfyGQLNextOpenFFOrders.Codeunit.al +++ b/Apps/W1/Shopify/app/src/GraphQL/Codeunits/ShpfyGQLNextOpenFFOrders.Codeunit.al @@ -10,7 +10,7 @@ codeunit 30236 "Shpfy GQL NextOpenFFOrders" implements "Shpfy IGraphQL" /// Return value of type Text. internal procedure GetGraphQL(): Text begin - exit('{"query":"{fulfillmentOrders(first: 25, after:\"{{After}}\", includeClosed: false) { pageInfo { hasNextPage } edges { cursor node { id updatedAt assignedLocation {location {legacyResourceId}} order {legacyResourceId}}}}}"}'); + exit('{"query":"{fulfillmentOrders(first: 25, after:\"{{After}}\", includeClosed: false) { pageInfo { hasNextPage } edges { cursor node { id updatedAt assignedLocation {location {legacyResourceId}} order {legacyResourceId} deliveryMethod {methodType}}}}}"}'); end; /// @@ -19,6 +19,6 @@ codeunit 30236 "Shpfy GQL NextOpenFFOrders" implements "Shpfy IGraphQL" /// Return value of type Integer. internal procedure GetExpectedCost(): Integer begin - exit(102); + exit(108); end; } \ No newline at end of file diff --git a/Apps/W1/Shopify/app/src/GraphQL/Codeunits/ShpfyGQLOpenFulfillmOrders.Codeunit.al b/Apps/W1/Shopify/app/src/GraphQL/Codeunits/ShpfyGQLOpenFulfillmOrders.Codeunit.al index 89538cd394..5f1eb29721 100644 --- a/Apps/W1/Shopify/app/src/GraphQL/Codeunits/ShpfyGQLOpenFulfillmOrders.Codeunit.al +++ b/Apps/W1/Shopify/app/src/GraphQL/Codeunits/ShpfyGQLOpenFulfillmOrders.Codeunit.al @@ -10,7 +10,7 @@ codeunit 30234 "Shpfy GQL OpenFulfillmOrders" implements "Shpfy IGraphQL" /// Return value of type Text. internal procedure GetGraphQL(): Text begin - exit('{"query":"{fulfillmentOrders(first: 25, includeClosed: false) { pageInfo { hasNextPage } edges { cursor node { id updatedAt assignedLocation {location {legacyResourceId}} order {legacyResourceId}}}}}"}'); + exit('{"query":"{fulfillmentOrders(first: 25, includeClosed: false) { pageInfo { hasNextPage } edges { cursor node { id updatedAt assignedLocation {location {legacyResourceId}} order {legacyResourceId} deliveryMethod {methodType}}}}}"}'); end; /// @@ -19,6 +19,6 @@ codeunit 30234 "Shpfy GQL OpenFulfillmOrders" implements "Shpfy IGraphQL" /// Return value of type Integer. internal procedure GetExpectedCost(): Integer begin - exit(102); + exit(108); end; } \ No newline at end of file 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 d8b6897202..e6f4ecc4c8 100644 --- a/Apps/W1/Shopify/app/src/GraphQL/Codeunits/ShpfyGQLOrderHeader.Codeunit.al +++ b/Apps/W1/Shopify/app/src/GraphQL/Codeunits/ShpfyGQLOrderHeader.Codeunit.al @@ -6,11 +6,11 @@ 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 test email phone 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 mainContact { id customer { legacyResourceId email phone }}}}}}}"}'); + 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 }}}}}"}'); end; procedure GetExpectedCost(): Integer begin - exit(63); + exit(64); end; } \ No newline at end of file diff --git a/Apps/W1/Shopify/app/src/GraphQL/Enums/ShpfyGraphQLType.Enum.al b/Apps/W1/Shopify/app/src/GraphQL/Enums/ShpfyGraphQLType.Enum.al index 08464ec863..4315a4f5e6 100644 --- a/Apps/W1/Shopify/app/src/GraphQL/Enums/ShpfyGraphQLType.Enum.al +++ b/Apps/W1/Shopify/app/src/GraphQL/Enums/ShpfyGraphQLType.Enum.al @@ -390,4 +390,14 @@ enum 30111 "Shpfy GraphQL Type" implements "Shpfy IGraphQL" Caption = 'Create Price List'; Implementation = "Shpfy IGraphQL" = "Shpfy GQL CreatePriceList"; } + value(76; GetCatalogProducts) + { + Caption = 'Get Catalog Products'; + Implementation = "Shpfy IGraphQL" = "Shpfy GQL CatalogProducts"; + } + value(77; GetNextCatalogProducts) + { + Caption = 'Get Next Catalog Products'; + Implementation = "Shpfy IGraphQL" = "Shpfy GQL NextCatalogProducts"; + } } diff --git a/Apps/W1/Shopify/app/src/Integration/Pages/ShpfyAuthentication.Page.al b/Apps/W1/Shopify/app/src/Integration/Pages/ShpfyAuthentication.Page.al index 314f30d2de..876b0151dd 100644 --- a/Apps/W1/Shopify/app/src/Integration/Pages/ShpfyAuthentication.Page.al +++ b/Apps/W1/Shopify/app/src/Integration/Pages/ShpfyAuthentication.Page.al @@ -22,7 +22,7 @@ page 30135 "Shpfy Authentication" { area(Content) { - usercontrol(OAuthIntegration; OAuthIntegration) + usercontrol(OAuthIntegration; OAuthControlAddIn) { ApplicationArea = All; trigger AuthorizationCodeRetrieved(Code: Text) diff --git a/Apps/W1/Shopify/app/src/Order Fulfillments/Codeunits/ShpfyFulfillmentOrdersAPI.Codeunit.al b/Apps/W1/Shopify/app/src/Order Fulfillments/Codeunits/ShpfyFulfillmentOrdersAPI.Codeunit.al index f1586891ca..2dae5f1e26 100644 --- a/Apps/W1/Shopify/app/src/Order Fulfillments/Codeunits/ShpfyFulfillmentOrdersAPI.Codeunit.al +++ b/Apps/W1/Shopify/app/src/Order Fulfillments/Codeunits/ShpfyFulfillmentOrdersAPI.Codeunit.al @@ -123,8 +123,10 @@ codeunit 30238 "Shpfy Fulfillment Orders API" Id := CommunicationMgt.GetIdOfGId(JsonHelper.GetValueAsText(JNode, 'id')); if FulfillmentOrderHeader.Get(Id) then begin - if FulfillmentOrderHeader."Updated At" = JsonHelper.GetValueAsDateTime(JNode, 'updatedAt') then + if FulfillmentOrderHeader."Updated At" = JsonHelper.GetValueAsDateTime(JNode, 'updatedAt') then begin + GetFulfillmentOrderLines(ShopifyShop, FulfillmentOrderHeader); exit; + end; end else Clear(FulfillmentOrderHeader); FulfillmentOrderHeader."Shopify Fulfillment Order Id" := Id; @@ -134,6 +136,7 @@ codeunit 30238 "Shpfy Fulfillment Orders API" FulfillmentOrderHeader."Shopify Location Id" := JsonHelper.GetValueAsBigInteger(JNode, 'assignedLocation.location.legacyResourceId'); FulfillmentOrderHeader."Updated At" := JsonHelper.GetValueAsDateTime(JNode, 'updatedAt'); FulfillmentOrderHeader.Status := CopyStr(JsonHelper.GetValueAsText(JNode, 'status'), 1, MaxStrLen(FulfillmentOrderHeader.Status)); + FulfillmentOrderHeader."Delivery Method Type" := ConvertToDeliveryMethodType(JsonHelper.GetValueAsText(JNode, 'deliveryMethod.methodType')); if not FulfillmentOrderHeader.Insert() then FulfillmentOrderHeader.Modify(); GetFulfillmentOrderLines(ShopifyShop, FulfillmentOrderHeader); @@ -143,6 +146,7 @@ codeunit 30238 "Shpfy Fulfillment Orders API" internal procedure ExtractFulfillmentOrderLines(var ShopifyShop: Record "Shpfy Shop"; var FulfillmentOrderHeader: Record "Shpfy FulFillment Order Header"; JResponse: JsonObject; var Cursor: Text): Boolean var FulfillmentOrderLine: Record "Shpfy FulFillment Order Line"; + Modified: Boolean; Id: BigInteger; JFulfillmentOrderLines: JsonArray; JNode: JsonObject; @@ -157,16 +161,48 @@ codeunit 30238 "Shpfy Fulfillment Orders API" if not FulfillmentOrderLine.Get(FulfillmentOrderHeader."Shopify Fulfillment Order Id", Id) then begin FulfillmentOrderLine."Shopify Fulfillment Order Id" := FulfillmentOrderHeader."Shopify Fulfillment Order Id"; FulfillmentOrderLine."Shopify Fulfillm. Ord. Line Id" := Id; + FulfillmentOrderLine."Shopify Order Id" := FulfillmentOrderHeader."Shopify Order Id"; + FulfillmentOrderLine."Shopify Location Id" := FulfillmentOrderHeader."Shopify Location Id"; + FulfillmentOrderLine."Delivery Method Type" := FulfillmentOrderHeader."Delivery Method Type"; + FulfillmentOrderLine."Shopify Product Id" := JsonHelper.GetValueAsBigInteger(JNode, 'lineItem.product.legacyResourceId'); + FulfillmentOrderLine."Shopify Variant Id" := JsonHelper.GetValueAsBigInteger(JNode, 'lineItem.variant.legacyResourceId'); + FulfillmentOrderLine."Total Quantity" := JsonHelper.GetValueAsDecimal(JNode, 'totalQuantity'); + FulfillmentOrderLine."Remaining Quantity" := JsonHelper.GetValueAsDecimal(JNode, 'remainingQuantity'); FulfillmentOrderLine.Insert(); + end else begin + Modified := false; + + if FulfillmentOrderLine."Shopify Order Id" <> FulfillmentOrderHeader."Shopify Order Id" then begin + Modified := true; + FulfillmentOrderLine."Shopify Order Id" := FulfillmentOrderHeader."Shopify Order Id"; + end; + if FulfillmentOrderLine."Shopify Location Id" <> FulfillmentOrderHeader."Shopify Location Id" then begin + Modified := true; + FulfillmentOrderLine."Shopify Location Id" := FulfillmentOrderHeader."Shopify Location Id"; + end; + if FulfillmentOrderLine."Delivery Method Type" <> FulfillmentOrderHeader."Delivery Method Type" then begin + Modified := true; + FulfillmentOrderLine."Delivery Method Type" := FulfillmentOrderHeader."Delivery Method Type"; + end; + if FulfillmentOrderLine."Shopify Product Id" <> JsonHelper.GetValueAsBigInteger(JNode, 'lineItem.product.legacyResourceId') then begin + Modified := true; + FulfillmentOrderLine."Shopify Product Id" := JsonHelper.GetValueAsBigInteger(JNode, 'lineItem.product.legacyResourceId'); + end; + if FulfillmentOrderLine."Shopify Variant Id" <> JsonHelper.GetValueAsBigInteger(JNode, 'lineItem.variant.legacyResourceId') then begin + Modified := true; + FulfillmentOrderLine."Shopify Variant Id" := JsonHelper.GetValueAsBigInteger(JNode, 'lineItem.variant.legacyResourceId'); + end; + if FulfillmentOrderLine."Total Quantity" <> JsonHelper.GetValueAsDecimal(JNode, 'totalQuantity') then begin + Modified := true; + FulfillmentOrderLine."Total Quantity" := JsonHelper.GetValueAsDecimal(JNode, 'totalQuantity'); + end; + if FulfillmentOrderLine."Remaining Quantity" <> JsonHelper.GetValueAsDecimal(JNode, 'remainingQuantity') then begin + Modified := true; + FulfillmentOrderLine."Remaining Quantity" := JsonHelper.GetValueAsDecimal(JNode, 'remainingQuantity'); + end; + if Modified then + FulfillmentOrderLine.Modify(); end; - - FulfillmentOrderLine."Shopify Order Id" := FulfillmentOrderHeader."Shopify Order Id"; - FulfillmentOrderLine."Shopify Location Id" := FulfillmentOrderHeader."Shopify Location Id"; - FulfillmentOrderLine."Shopify Product Id" := JsonHelper.GetValueAsBigInteger(JNode, 'lineItem.product.legacyResourceId'); - FulfillmentOrderLine."Shopify Variant Id" := JsonHelper.GetValueAsBigInteger(JNode, 'lineItem.variant.legacyResourceId'); - FulfillmentOrderLine."Total Quantity" := JsonHelper.GetValueAsDecimal(JNode, 'totalQuantity'); - FulfillmentOrderLine."Remaining Quantity" := JsonHelper.GetValueAsDecimal(JNode, 'remainingQuantity'); - FulfillmentOrderLine.Modify(); end; end; exit(true); @@ -205,4 +241,13 @@ codeunit 30238 "Shpfy Fulfillment Orders API" break; until not JsonHelper.GetValueAsBoolean(JResponse, 'data.order.fulfillmentOrders.pageInfo.hasNextPage'); end; + + local procedure ConvertToDeliveryMethodType(Value: Text): Enum "Shpfy Delivery Method Type" + begin + Value := CommunicationMgt.ConvertToCleanOptionValue(Value); + if Enum::"Shpfy Delivery Method Type".Names().Contains(Value) then + exit(Enum::"Shpfy Delivery Method Type".FromInteger(Enum::"Shpfy Delivery Method Type".Ordinals().Get(Enum::"Shpfy Delivery Method Type".Names().IndexOf(Value)))) + else + exit(Enum::"Shpfy Delivery Method Type"::" "); + end; } \ No newline at end of file diff --git a/Apps/W1/Shopify/app/src/Order Fulfillments/Enums/ShpfyDeliveryMethodType.Enum.al b/Apps/W1/Shopify/app/src/Order Fulfillments/Enums/ShpfyDeliveryMethodType.Enum.al new file mode 100644 index 0000000000..bfdc4342b4 --- /dev/null +++ b/Apps/W1/Shopify/app/src/Order Fulfillments/Enums/ShpfyDeliveryMethodType.Enum.al @@ -0,0 +1,35 @@ +namespace Microsoft.Integration.Shopify; + +/// +/// Enum Shpfy Delivery Method Type (ID 30152). +/// +enum 30152 "Shpfy Delivery Method Type" +{ + Caption = 'Shopify Delivery Method Type'; + Extensible = false; + + value(0; " ") + { + Caption = ' '; + } + value(1; "Local") + { + Caption = 'Local'; + } + value(2; "None") + { + Caption = 'None'; + } + value(3; "Pick Up") + { + Caption = 'Pick Up'; + } + value(4; "Retail") + { + Caption = 'Retail'; + } + value(5; "Shipping") + { + Caption = 'Shipping'; + } +} \ No newline at end of file diff --git a/Apps/W1/Shopify/app/src/Order Fulfillments/Enums/ShpfyOrderFulfillStatus.Enum.al b/Apps/W1/Shopify/app/src/Order Fulfillments/Enums/ShpfyOrderFulfillStatus.Enum.al index 3f29674f45..c57e253514 100644 --- a/Apps/W1/Shopify/app/src/Order Fulfillments/Enums/ShpfyOrderFulfillStatus.Enum.al +++ b/Apps/W1/Shopify/app/src/Order Fulfillments/Enums/ShpfyOrderFulfillStatus.Enum.al @@ -46,4 +46,8 @@ enum 30113 "Shpfy Order Fulfill. Status" { Caption = 'Partially Fulfilled'; } + value(9; "On Hold") + { + Caption = 'On Hold'; + } } \ No newline at end of file diff --git a/Apps/W1/Shopify/app/src/Order Fulfillments/Tables/ShpfyFulFillmentOrderHeader.Table.al b/Apps/W1/Shopify/app/src/Order Fulfillments/Tables/ShpfyFulFillmentOrderHeader.Table.al index 9b78864b67..a9c8db2969 100644 --- a/Apps/W1/Shopify/app/src/Order Fulfillments/Tables/ShpfyFulFillmentOrderHeader.Table.al +++ b/Apps/W1/Shopify/app/src/Order Fulfillments/Tables/ShpfyFulFillmentOrderHeader.Table.al @@ -49,6 +49,12 @@ table 30143 "Shpfy FulFillment Order Header" CalcFormula = lookup("Shpfy Order Header"."Shopify Order No." where("Shopify Order Id" = field("Shopify Order Id"))); Editable = false; } + field(9; "Delivery Method Type"; Enum "Shpfy Delivery Method Type") + { + Caption = 'Delivery Method Type'; + DataClassification = SystemMetadata; + Editable = false; + } } keys { diff --git a/Apps/W1/Shopify/app/src/Order Fulfillments/Tables/ShpfyFulFillmentOrderLine.Table.al b/Apps/W1/Shopify/app/src/Order Fulfillments/Tables/ShpfyFulFillmentOrderLine.Table.al index e1145d9d34..23f4136743 100644 --- a/Apps/W1/Shopify/app/src/Order Fulfillments/Tables/ShpfyFulFillmentOrderLine.Table.al +++ b/Apps/W1/Shopify/app/src/Order Fulfillments/Tables/ShpfyFulFillmentOrderLine.Table.al @@ -52,6 +52,12 @@ table 30144 "Shpfy FulFillment Order Line" Caption = 'Shopify Variant Id'; DataClassification = SystemMetadata; } + field(10; "Delivery Method Type"; Enum "Shpfy Delivery Method Type") + { + Caption = 'Delivery Method Type'; + DataClassification = SystemMetadata; + Editable = false; + } } keys { diff --git a/Apps/W1/Shopify/app/src/Order Refunds/Codeunits/ShpfyRefundsAPI.Codeunit.al b/Apps/W1/Shopify/app/src/Order Refunds/Codeunits/ShpfyRefundsAPI.Codeunit.al index 42278a3741..97cd67b4f4 100644 --- a/Apps/W1/Shopify/app/src/Order Refunds/Codeunits/ShpfyRefundsAPI.Codeunit.al +++ b/Apps/W1/Shopify/app/src/Order Refunds/Codeunits/ShpfyRefundsAPI.Codeunit.al @@ -113,22 +113,9 @@ codeunit 30228 "Shpfy Refunds API" JsonHelper.GetValueIntoField(JLine, 'totalTaxSet.shopMoney.amount', RefundLineRecordRef, RefundLine.FieldNo("Total Tax Amount")); JsonHelper.GetValueIntoField(JLine, 'totalTaxSet.presentmentMoney.amount', RefundLineRecordRef, RefundLine.FieldNo("Presentment Total Tax Amount")); RefundLineRecordRef.SetTable(RefundLine); - RefundLine."Can Create Credit Memo" := CanRefundCreateCreditMemo(RefundLine, NonZeroRefund); + RefundLine."Can Create Credit Memo" := NonZeroRefund; RefundLine.Modify(); RefundLineRecordRef.Close(); DataCapture.Add(Database::"Shpfy Refund Line", RefundLine.SystemId, JLine); end; - - local procedure CanRefundCreateCreditMemo(RefundLine: Record "Shpfy Refund Line"; NonZeroRefund: Boolean): Boolean - begin - case RefundLine."Restock Type" of - RefundLine."Restock Type"::Cancel: - exit(false); - RefundLine."Restock Type"::Return, - RefundLine."Restock Type"::"Legacy Restock": - exit(true); - RefundLine."Restock Type"::"No Restock": - exit(NonZeroRefund); - end; - end; } \ No newline at end of file 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 625108d13b..e7b47acb84 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 @@ -15,7 +15,7 @@ codeunit 30161 "Shpfy Import Order" trigger OnRun() begin - ImportOrderAndCreateOrUpdate(Rec."Shop Code", Rec.Id, true) + ImportOrderAndCreateOrUpdate(Rec."Shop Code", Rec.Id, ImportActionAtConflict::SkipOrderSyncAndMark); end; internal procedure SetShop(ShopCode: Code[20]): Boolean @@ -30,18 +30,24 @@ codeunit 30161 "Shpfy Import Order" internal procedure RetrieveOrderAndOrderLines(OrderId: BigInteger; var OrderHeader: Record "Shpfy Order Header" temporary; var OrderLine: Record "Shpfy Order Line" temporary) var + DataCaptureDict: Dictionary of [BigInteger, JsonToken]; JOrder: JsonObject; begin if RetrieveOrderHeaderJson(OrderId, JOrder) then if not SetOrderHeaderValuesFromJson(JOrder, false, OrderHeader) then exit; - RetrieveAndSetOrderLines(OrderId, OrderLine, false); + RetrieveAndSetOrderLines(OrderId, OrderLine, DataCaptureDict); end; - internal procedure MarkOrderConflictAsResolvedAndReimport(OrderHeader: Record "Shpfy Order Header") + internal procedure ReimportExistingOrderConfirmIfConflicting(OrderHeader: Record "Shpfy Order Header") + var + OrderMapping: Codeunit "Shpfy Order Mapping"; begin - MarkOrderConflictAsResolved(OrderHeader); - ImportOrderAndCreateOrUpdate(OrderHeader."Shop Code", OrderHeader."Shopify Order Id", false); + OrderHeader.Get(OrderHeader."Shopify Order Id"); + ImportOrderAndCreateOrUpdate(OrderHeader."Shop Code", OrderHeader."Shopify Order Id", ImportActionAtConflict::WarnAndSyncOrder); + OrderHeader.Get(OrderHeader."Shopify Order Id"); + if not OrderHeader."Has Error" then + if OrderMapping.DoMapping(OrderHeader) then; end; internal procedure ImportCreateAndUpdateOrderHeaderFromMock(ShopCode: Code[20]; OrderId: BigInteger; MockJOrder: JsonObject) @@ -59,8 +65,16 @@ codeunit 30161 "Shpfy Import Order" internal procedure ImportCreateAndUpdateOrderLinesFromMock(OrderId: BigInteger; MockJOrderLines: JsonArray) var OrderLine: Record "Shpfy Order Line"; + TempOrderLine: Record "Shpfy Order Line" temporary; + DataCaptureDict: Dictionary of [BigInteger, JsonToken]; begin - SetAndInsertOrderLines(OrderId, MockJOrderLines, false, OrderLine); + SetAndInsertOrderLines(OrderId, MockJOrderLines, TempOrderLine, DataCaptureDict); + if not TempOrderLine.FindSet() then + exit; + repeat + OrderLine.Copy(TempOrderLine); + OrderLine.Insert(); + until TempOrderLine.Next() = 0; end; var @@ -69,21 +83,18 @@ codeunit 30161 "Shpfy Import Order" JsonHelper: Codeunit "Shpfy Json Helper"; OrderEvents: Codeunit "Shpfy Order Events"; OrderFulfillments: Codeunit "Shpfy Order Fulfillments"; - ProcessedConflictErr: Label 'The order has already been processed in Business Central, but an edition was received from Shopify. Changes were not propagated to the processed order. Update the processed documents to ensure data consistency.'; - OrderHeaderTotalAmountPathTok: Label 'totalPriceSet.shopMoney.amount', Locked = true; - OrderHeaderPresentmentTotalAmountPathTok: Label 'totalPriceSet.presentmentMoney.amount', Locked = true; - OrderHeaderSubtotalAmountPathTok: Label 'subtotalPriceSet.shopMoney.amount', Locked = true; - OrderHeaderPresentmentSubtotalAmountPathTok: Label 'subtotalPriceSet.presentmentMoney.amount', Locked = true; - OrderHeaderVATAmountPathTok: Label 'totalTaxSet.shopMoney.amount', Locked = true; - OrderHeaderPresentmentVATAmountPathTok: Label 'totalTaxSet.presentmentMoney.amount', Locked = true; + ImportActionAtConflict: Option SkipOrderSyncAndMark,SyncOrder,WarnAndSyncOrder; + ProcessedConflictErr: Label 'The order has already been processed in Business Central, but an edition was received from Shopify. Changes were not propagated to the processed order in Business Central. Update the processed documents to match the received data from Shopify. If you wish to force the synchronization use the action "Sync order from Shopify" in the Shopify Order card page.'; + ReimportProcessedMsg: Label 'This order has linked documents in Business Central. Make sure to update the linked documents. Do you want to reimport the order?'; - - local procedure ImportOrderAndCreateOrUpdate(ShopCode: Code[20]; OrderId: BigInteger; SkipIfConclicting: Boolean) + local procedure ImportOrderAndCreateOrUpdate(ShopCode: Code[20]; OrderId: BigInteger; ActionAtConflict: Option) var OrderHeader: Record "Shpfy Order Header"; - OrderLine: Record "Shpfy Order Line"; + TempOrderLine: Record "Shpfy Order Line" temporary; UpdatingOrderHeader: Boolean; JOrder: JsonObject; + DataCaptureDict: Dictionary of [BigInteger, JsonToken]; + Redundancy: Integer; begin if OrderId = 0 then exit; @@ -96,20 +107,32 @@ codeunit 30161 "Shpfy Import Order" if not RetrieveOrderHeaderJson(OrderId, OrderHeader.SystemId, JOrder) then exit; - if UpdatingOrderHeader and SkipIfConclicting and OrderHeader.IsProcessed() then - if IsImportedOrderConflictingExistingOrder(JOrder, OrderHeader) then begin - SetOrderAsConflicting(OrderHeader); - exit; - end; + RetrieveAndSetOrderLines(OrderId, TempOrderLine, DataCaptureDict); + + if UpdatingOrderHeader then + if OrderHeader.IsProcessed() then + if IsImportedOrderConflictingExistingOrder(JOrder, OrderHeader, TempOrderLine) then begin + if ActionAtConflict = ImportActionAtConflict::SkipOrderSyncAndMark then begin + SetOrderAsConflicting(OrderHeader); + exit; + end; + if ActionAtConflict = ImportActionAtConflict::WarnAndSyncOrder then begin + if not GuiAllowed() then + exit; + if not Confirm(ReimportProcessedMsg) then + exit; + end; + end; + MarkOrderConflictAsResolved(OrderHeader); if not SetOrderHeaderValuesFromJson(JOrder, UpdatingOrderHeader, OrderHeader) then exit; SetAndCreateRelatedRecords(JOrder, OrderHeader); OrderHeader.Modify(); OrderEvents.OnAfterImportShopifyOrderHeader(OrderHeader, not UpdatingOrderHeader); - OrderLine.SetRange("Shopify Order Id", OrderHeader."Shopify Order Id"); - OrderLine.DeleteAll(); - RetrieveAndSetOrderLines(OrderId, OrderLine, true); + InsertOrderLinesAndRelatedRecords(TempOrderLine, DataCaptureDict, Redundancy); + OrderHeader."Line Items Redundancy Code" := Redundancy; + OrderHeader.Modify(); OrderFulfillments.GetFulfillments(Shop, OrderHeader."Shopify Order Id"); ConsiderRefundsInQuantityAndAmounts(OrderHeader); @@ -119,6 +142,39 @@ codeunit 30161 "Shpfy Import Order" CloseOrder(OrderHeader); end; + local procedure InsertOrderLinesAndRelatedRecords(var TempOrderLine: Record "Shpfy Order Line" temporary; var DataCaptureDict: Dictionary of [BigInteger, JsonToken]; var Redundancy: Integer) + var + OrderLine: Record "Shpfy Order Line"; + DataCapture: Record "Shpfy Data Capture"; + Hash: Codeunit "Shpfy Hash"; + JOrderLine: JsonToken; + LineIds: Text; + begin + TempOrderLine.SetCurrentKey("Line Id"); + TempOrderLine.SetAscending("Line Id", true); + if not TempOrderLine.FindSet() then + exit; + repeat + LineIds += '|' + Format(TempOrderLine."Line Id"); + JOrderLine := DataCaptureDict.Get(TempOrderLine."Line Id"); + if OrderLine.Get(TempOrderLine."Shopify Order Id", TempOrderLine."Line Id") then begin + Clear(OrderLine); + OrderLine.Copy(TempOrderLine); + UpdateLocationIdAndDeliveryMethodOnOrderLine(OrderLine); + OrderLine.Modify(); + end else begin + Clear(OrderLine); + OrderLine.Copy(TempOrderLine); + UpdateLocationIdAndDeliveryMethodOnOrderLine(OrderLine); + OrderLine.Insert(); + AddTaxLines(OrderLine."Line Id", JsonHelper.GetJsonArray(JOrderLine, 'taxLines')); + ImportCustomAttributtes(OrderLine."Shopify Order Id", OrderLine.SystemId, JsonHelper.GetJsonArray(JOrderLine, 'customAttributes')); + end; + DataCapture.Add(Database::"Shpfy Order Line", OrderLine.SystemId, Format(JOrderLine)); + until TempOrderLine.Next() = 0; + Redundancy := Hash.CalcHash(LineIds); + end; + local procedure EnsureOrderHeaderExists(OrderId: BigInteger; ShopCode: Code[20]; var OrderHeader: Record "Shpfy Order Header"): Boolean begin if OrderHeader.Get(OrderId) then @@ -138,7 +194,7 @@ codeunit 30161 "Shpfy Import Order" OrderLine.DeleteAll(); end; - local procedure ConsiderRefundsInQuantityAndAmounts(OrderHeader: Record "Shpfy Order Header") + local procedure ConsiderRefundsInQuantityAndAmounts(var OrderHeader: Record "Shpfy Order Header") var OrderLine: Record "Shpfy Order Line"; RefundLine: Record "Shpfy Refund Line"; @@ -167,52 +223,33 @@ codeunit 30161 "Shpfy Import Order" OrderHeader.Modify(); end; - local procedure UpdateOrderHeaderToValuesWithoutRefunds(var OrderHeader: Record "Shpfy Order Header") + local procedure IsImportedOrderConflictingExistingOrder(JOrder: JsonObject; OrderHeader: Record "Shpfy Order Header"; var TempOrderLine: Record "Shpfy Order Line" temporary): Boolean var - OrderLine: Record "Shpfy Order Line"; - RefundLine: Record "Shpfy Refund Line"; - IReturnRefundProcess: Interface "Shpfy IReturnRefund Process"; + Hash: Codeunit "Shpfy Hash"; + LineIds: Text; + Redundancy: Integer; begin - IReturnRefundProcess := Shop."Return and Refund Process"; - if not IReturnRefundProcess.IsImportNeededFor("Shpfy Source Document Type"::Refund) then - exit; - OrderLine.SetRange("Shopify Order Id", OrderHeader."Shopify Order Id"); - if not OrderLine.FindSet() then - exit; - repeat - RefundLine.SetRange("Order Line Id", OrderLine."Line Id"); - RefundLine.SetRange("Can Create Credit Memo", false); - RefundLine.CalcSums("Presentment Amount", Amount, "Subtotal Amount", "Presentment Total Tax Amount", Quantity); - OrderHeader."Total Amount" += RefundLine."Subtotal Amount"; - OrderHeader."Subtotal Amount" += RefundLine."Subtotal Amount"; - OrderHeader."Presentment Total Amount" += RefundLine."Presentment Subtotal Amount"; - OrderHeader."Presentment Subtotal Amount" += RefundLine."Presentment Subtotal Amount"; - OrderHeader."VAT Amount" += RefundLine."Total Tax Amount"; - OrderHeader."Presentment VAT Amount" += RefundLine."Presentment Total Tax Amount"; - until OrderLine.Next() = 0; - end; + if OrderHeader."Cancelled At" = 0DT then + if JsonHelper.GetValueAsDateTime(JOrder, 'cancelledAt') <> 0DT then + exit(true); - local procedure IsImportedOrderConflictingExistingOrder(JOrder: JsonObject; OrderHeader: Record "Shpfy Order Header"): Boolean - begin - UpdateOrderHeaderToValuesWithoutRefunds(OrderHeader); - if OrderHeader."Total Amount" <> JsonHelper.GetValueAsDecimal(JOrder, OrderHeaderTotalAmountPathTok) then - exit(true); + if OrderHeader."Current Total Amount" <> 0 then + if OrderHeader."Current Total Amount" <> JsonHelper.GetValueAsDecimal(JOrder, 'currentTotalPriceSet.shopMoney.amount') then + exit(true); - if OrderHeader."Presentment Total Amount" <> JsonHelper.GetValueAsDecimal(JOrder, OrderHeaderPresentmentTotalAmountPathTok) then - exit(true); + if OrderHeader."Current Total Items Quantity" <> 0 then + if OrderHeader."Current Total Items Quantity" <> JsonHelper.GetValueAsDecimal(JOrder, 'currentSubtotalLineItemsQuantity') then + exit(true); - if OrderHeader."Subtotal Amount" <> JsonHelper.GetValueAsDecimal(JOrder, OrderHeaderSubtotalAmountPathTok) then + TempOrderLine.SetCurrentKey("Line Id"); + TempOrderLine.SetAscending("Line Id", true); + if TempOrderLine.FindSet() then + repeat + LineIds += '|' + Format(TempOrderLine."Line Id"); + until TempOrderLine.Next() = 0; + Redundancy := Hash.CalcHash(LineIds); + if Redundancy <> OrderHeader."Line Items Redundancy Code" then exit(true); - - if OrderHeader."Presentment Subtotal Amount" <> JsonHelper.GetValueAsDecimal(JOrder, OrderHeaderPresentmentSubtotalAmountPathTok) then - exit(true); - - if OrderHeader."VAT Amount" <> JsonHelper.GetValueAsDecimal(JOrder, OrderHeaderVATAmountPathTok) then - exit(true); - - if OrderHeader."Presentment VAT Amount" <> JsonHelper.GetValueAsDecimal(JOrder, OrderHeaderPresentmentVATAmountPathTok) then - exit(true); - exit(false); end; @@ -248,12 +285,11 @@ codeunit 30161 "Shpfy Import Order" OrderHeader.Modify(); end; - local procedure MarkOrderConflictAsResolved(OrderHeader: Record "Shpfy Order Header") + local procedure MarkOrderConflictAsResolved(var OrderHeader: Record "Shpfy Order Header") begin OrderHeader."Has Order State Error" := false; OrderHeader."Has Error" := false; OrderHeader."Error Message" := ''; - OrderHeader.Modify(); end; local procedure RetrieveOrderHeaderJson(OrderId: BigInteger; DataCaptureSystemId: Guid; var JOrder: JsonObject): Boolean @@ -280,14 +316,18 @@ codeunit 30161 "Shpfy Import Order" local procedure RetrieveOrderLinesJson(OrderId: BigInteger; After: Text; var JOrderLines: JsonArray; var HasNextPage: Boolean; var EndCursor: Text): Boolean var Parameters: Dictionary of [Text, Text]; + GraphQLType: Enum "Shpfy GraphQL Type"; JPageInfo: JsonObject; JResponse: JsonToken; begin Parameters.Add('OrderId', Format(OrderId)); - if After <> '' then + GraphQLType := "Shpfy GraphQL Type"::GetOrderLines; + if After <> '' then begin + GraphQLType := "Shpfy GraphQL Type"::GetNextOrderLines; Parameters.Add('After', After); + end; - JResponse := CommunicationMgt.ExecuteGraphQL("Shpfy GraphQL Type"::GetOrderLines, Parameters); + JResponse := CommunicationMgt.ExecuteGraphQL(GraphQLType, Parameters); if JsonHelper.GetJsonObject(JResponse, JPageInfo, 'data.order.lineItems.pageInfo') then begin EndCursor := JsonHelper.GetValueAsText(JPageInfo, 'endCursor'); HasNextPage := JsonHelper.GetValueAsBoolean(JPageInfo, 'hasNextPage'); @@ -303,6 +343,7 @@ codeunit 30161 "Shpfy Import Order" OrderId: BigInteger; CompanyId: BigInteger; MainContactId: BigInteger; + LocationId: BigInteger; CompanyName: Text; EMail: Text; FirstName: Text; @@ -413,7 +454,7 @@ codeunit 30161 "Shpfy Import Order" end; #endregion #region B2B - if JsonHelper.GetJsonObject(JOrder, JObject, 'purchasingEntity') then + if JsonHelper.GetJsonObject(JOrder, JObject, 'purchasingEntity') then begin if JsonHelper.GetJsonObject(JOrder, JObject, 'purchasingEntity.company') then begin CompanyId := CommunicationMgt.GetIdOfGId(JsonHelper.GetValueAsText(JOrder, 'purchasingEntity.company.id')); OrderHeaderRecordRef.Field(OrderHeader.FieldNo("Company Id")).Value := CompanyId; @@ -422,7 +463,14 @@ codeunit 30161 "Shpfy Import Order" JsonHelper.GetValueIntoField(JOrder, 'purchasingEntity.company.mainContact.customer.legacyResourceId', OrderHeaderRecordRef, OrderHeader.FieldNo("Company Main Contact Cust. Id")); JsonHelper.GetValueIntoField(JOrder, 'purchasingEntity.company.mainContact.customer.email', OrderHeaderRecordRef, OrderHeader.FieldNo("Company Main Contact Email")); JsonHelper.GetValueIntoField(JOrder, 'purchasingEntity.company.mainContact.customer.phone', OrderHeaderRecordRef, OrderHeader.FieldNo("Company Main Contact Phone No.")); + if Format(OrderHeaderRecordRef.Field(OrderHeader.FieldNo("Sell-to Customer Name")).Value) = '' then + JsonHelper.GetValueIntoField(JOrder, 'purchasingEntity.company.name', OrderHeaderRecordRef, OrderHeader.FieldNo("Sell-to Customer Name")); end; + if JsonHelper.GetJsonObject(JOrder, JObject, 'purchasingEntity.location') then begin + LocationId := CommunicationMgt.GetIdOfGId(JsonHelper.GetValueAsText(JOrder, 'purchasingEntity.location.id')); + OrderHeaderRecordRef.Field(OrderHeader.FieldNo("Company Location Id")).Value := LocationId; + end; + end; #endregion OrderHeaderRecordRef.SetTable(OrderHeader); OrderHeader."Currency Code" := TranslateCurrencyCode(OrderHeader."Currency Code"); @@ -456,18 +504,21 @@ codeunit 30161 "Shpfy Import Order" JsonHelper.GetValueIntoField(JOrder, 'totalWeight', OrderHeaderRecordRef, OrderHeader.FieldNo("Total Weight")); JsonHelper.GetValueIntoField(JOrder, 'refundable', OrderHeaderRecordRef, OrderHeader.FieldNo(Refundable)); JsonHelper.GetValueIntoField(JOrder, 'taxesIncluded', OrderHeaderRecordRef, OrderHeader.FieldNo("VAT Included")); - JsonHelper.GetValueIntoField(JOrder, OrderHeaderTotalAmountPathTok, OrderHeaderRecordRef, OrderHeader.FieldNo("Total Amount")); - JsonHelper.GetValueIntoField(JOrder, OrderHeaderPresentmentTotalAmountPathTok, OrderHeaderRecordRef, OrderHeader.FieldNo("Presentment Total Amount")); - JsonHelper.GetValueIntoField(JOrder, OrderHeaderSubtotalAmountPathTok, OrderHeaderRecordRef, OrderHeader.FieldNo("Subtotal Amount")); - JsonHelper.GetValueIntoField(JOrder, OrderHeaderPresentmentSubtotalAmountPathTok, OrderHeaderRecordRef, OrderHeader.FieldNo("Presentment Subtotal Amount")); + JsonHelper.GetValueIntoField(JOrder, 'totalPriceSet.shopMoney.amount', OrderHeaderRecordRef, OrderHeader.FieldNo("Total Amount")); + JsonHelper.GetValueIntoField(JOrder, 'totalPriceSet.presentmentMoney.amount', OrderHeaderRecordRef, OrderHeader.FieldNo("Presentment Total Amount")); + JsonHelper.GetValueIntoField(JOrder, 'subtotalPriceSet.shopMoney.amount', OrderHeaderRecordRef, OrderHeader.FieldNo("Subtotal Amount")); + JsonHelper.GetValueIntoField(JOrder, 'subtotalPriceSet.presentmentMoney.amount', OrderHeaderRecordRef, OrderHeader.FieldNo("Presentment Subtotal Amount")); JsonHelper.GetValueIntoField(JOrder, 'totalTipReceivedSet.shopMoney.amount', OrderHeaderRecordRef, OrderHeader.FieldNo("Total Tip Received")); JsonHelper.GetValueIntoField(JOrder, 'totalTipReceivedSet.presentmentMoney.amount', OrderHeaderRecordRef, OrderHeader.FieldNo("Presentment Total Tip Received")); - JsonHelper.GetValueIntoField(JOrder, OrderHeaderVATAmountPathTok, OrderHeaderRecordRef, OrderHeader.FieldNo("VAT Amount")); - JsonHelper.GetValueIntoField(JOrder, OrderHeaderPresentmentVATAmountPathTok, OrderHeaderRecordRef, OrderHeader.FieldNo("Presentment VAT Amount")); + JsonHelper.GetValueIntoField(JOrder, 'totalTaxSet.shopMoney.amount', OrderHeaderRecordRef, OrderHeader.FieldNo("VAT Amount")); + JsonHelper.GetValueIntoField(JOrder, 'totalTaxSet.presentmentMoney.amount', OrderHeaderRecordRef, OrderHeader.FieldNo("Presentment VAT Amount")); JsonHelper.GetValueIntoField(JOrder, 'totalDiscountsSet.shopMoney.amount', OrderHeaderRecordRef, OrderHeader.FieldNo("Discount Amount")); JsonHelper.GetValueIntoField(JOrder, 'totalDiscountsSet.presentmentMoney.amount', OrderHeaderRecordRef, OrderHeader.FieldNo("Presentment Discount Amount")); JsonHelper.GetValueIntoField(JOrder, 'totalShippingPriceSet.shopMoney.amount', OrderHeaderRecordRef, OrderHeader.FieldNo("Shipping Charges Amount")); JsonHelper.GetValueIntoField(JOrder, 'totalShippingPriceSet.presentmentMoney.amount', OrderHeaderRecordRef, OrderHeader.FieldNo("Pres. Shipping Charges Amount")); + JsonHelper.GetValueIntoField(JOrder, 'currentTotalPriceSet.shopMoney.amount', OrderHeaderRecordRef, OrderHeader.FieldNo("Current Total Amount")); + JsonHelper.GetValueIntoField(JOrder, 'currentSubtotalLineItemsQuantity', OrderHeaderRecordRef, OrderHeader.FieldNo("Current Total Items Quantity")); + JsonHelper.GetValueIntoField(Jorder, 'poNumber', OrderHeaderRecordRef, OrderHeader.FieldNo("PO Number")); OrderHeaderRecordRef.SetTable(OrderHeader); if JsonHelper.GetJsonObject(JOrder, JObject, 'purchasingEntity') then if JsonHelper.GetJsonObject(JOrder, JObject, 'purchasingEntity.company') then @@ -494,12 +545,15 @@ codeunit 30161 "Shpfy Import Order" local procedure SetOrderLineValuesFromJson(JOrderLine: JsonToken; OrderId: BigInteger; var OrderLine: Record "Shpfy Order Line"): Boolean var + LocalOrderLine: Record "Shpfy Order Line"; OrderLineRecordRef: RecordRef; LineId: BigInteger; begin LineId := CommunicationMgt.GetIdOfGId(JsonHelper.GetValueAsText(JOrderLine, 'id')); OrderLine."Shopify Order Id" := OrderId; OrderLine."Line Id" := LineId; + if LocalOrderLine.Get(OrderId, LineId) then + OrderLine.Copy(LocalOrderLine); OrderLineRecordRef.GetTable(OrderLine); if (JsonHelper.GetValueAsText(JOrderLine, 'name') = 'Tip') and JsonHelper.IsNull(JOrderLine, 'product') then OrderLineRecordRef.Field(OrderLine.FieldNo(Tip)).Value := true; @@ -518,11 +572,10 @@ codeunit 30161 "Shpfy Import Order" OrderLineRecordRef.SetTable(OrderLine); OrderLine."Discount Amount" := GetTotalLineDiscountAmount(JsonHelper.GetJsonArray(JOrderLine, 'discountAllocations'), 'shopMoney'); OrderLine."Presentment Discount Amount" := GetTotalLineDiscountAmount(JsonHelper.GetJsonArray(JOrderLine, 'discountAllocations'), 'presentmentMoney'); - UpdateLocationIdOnOrderLine(OrderLine); exit(true); end; - local procedure RetrieveAndSetOrderLines(OrderId: BigInteger; var OrderLine: Record "Shpfy Order Line"; InsertRelatedRecords: Boolean) + local procedure RetrieveAndSetOrderLines(OrderId: BigInteger; var OrderLine: Record "Shpfy Order Line" temporary; var DataCaptureDict: Dictionary of [BigInteger, JsonToken]) var JOrderLines: JsonArray; After: Text; @@ -531,24 +584,19 @@ codeunit 30161 "Shpfy Import Order" begin repeat RetrieveOrderLinesJson(OrderId, After, JOrderLines, HasNextPage, EndCursor); - SetAndInsertOrderLines(OrderId, JOrderLines, InsertRelatedRecords, OrderLine); + SetAndInsertOrderLines(OrderId, JOrderLines, OrderLine, DataCaptureDict); After := EndCursor; until not HasNextPage; end; - local procedure SetAndInsertOrderLines(OrderId: BigInteger; JOrderLines: JsonArray; InsertRelatedRecords: Boolean; var OrderLine: Record "Shpfy Order Line") + local procedure SetAndInsertOrderLines(OrderId: BigInteger; JOrderLines: JsonArray; var TempOrderLine: Record "Shpfy Order Line" temporary; var DataCaptureDict: Dictionary of [BigInteger, JsonToken]) var - DataCapture: Record "Shpfy Data Capture"; JOrderLine: JsonToken; begin foreach JOrderLine in JOrderLines do - if SetOrderLineValuesFromJson(JOrderLine, OrderId, OrderLine) then begin - OrderLine.Insert(); - if InsertRelatedRecords then begin - DataCapture.Add(Database::"Shpfy Order Line", OrderLine.SystemId, Format(JOrderLine)); - AddTaxLines(OrderLine."Line Id", JsonHelper.GetJsonArray(JOrderLine, 'taxLines')); - ImportCustomAttributtes(OrderLine."Shopify Order Id", OrderLine.SystemId, JsonHelper.GetJsonArray(JOrderLine, 'customAttributes')); - end; + if SetOrderLineValuesFromJson(JOrderLine, OrderId, TempOrderLine) then begin + TempOrderLine.Insert(); + DataCaptureDict.Add(TempOrderLine."Line Id", JOrderLine); end; end; @@ -661,7 +709,7 @@ codeunit 30161 "Shpfy Import Order" /// Description for CloseOrder. /// /// Parameter of type Record "Shopify Order Header". - internal procedure CloseOrder(OrderHeader: Record "Shpfy Order Header") + internal procedure CloseOrder(var OrderHeader: Record "Shpfy Order Header") var OrderHeaderRecordRef: RecordRef; JResponse: JsonToken; @@ -805,16 +853,24 @@ codeunit 30161 "Shpfy Import Order" exit(Enum::"Shpfy Cancel Reason"::Unknown); end; - local procedure UpdateLocationIdOnOrderLine(var OrderLine: Record "Shpfy Order Line") + local procedure UpdateLocationIdAndDeliveryMethodOnOrderLine(var OrderLine: Record "Shpfy Order Line") var FulfillmentOrderLine: Record "Shpfy FulFillment Order Line"; + TotalQuantity: Integer; begin FulfillmentOrderLine.Reset(); FulfillmentOrderLine.SetRange("Shopify Order Id", OrderLine."Shopify Order Id"); FulfillmentOrderLine.SetRange("Shopify Variant Id", OrderLine."Shopify Variant Id"); - FulfillmentOrderLine.SetRange("Total Quantity", OrderLine.Quantity); - if FulfillmentOrderLine.FindFirst() then - OrderLine."Location Id" := FulfillmentOrderLine."Shopify Location Id"; + if FulfillmentOrderLine.FindSet() then begin + repeat + TotalQuantity += FulfillmentOrderLine."Total Quantity"; + until FulfillmentOrderLine.Next() = 0; + + if TotalQuantity = OrderLine.Quantity then begin + OrderLine."Location Id" := FulfillmentOrderLine."Shopify Location Id"; + OrderLine."Delivery Method Type" := FulfillmentOrderLine."Delivery Method Type"; + end; + end; end; local procedure ConvertToOrderReturnStatus(Value: Text) OrderReturnStatus: Enum "Shpfy Order Return Status" diff --git a/Apps/W1/Shopify/app/src/Order handling/Codeunits/ShpfyOrderMapping.Codeunit.al b/Apps/W1/Shopify/app/src/Order handling/Codeunits/ShpfyOrderMapping.Codeunit.al index 7c2ee08512..a69394573c 100644 --- a/Apps/W1/Shopify/app/src/Order handling/Codeunits/ShpfyOrderMapping.Codeunit.al +++ b/Apps/W1/Shopify/app/src/Order handling/Codeunits/ShpfyOrderMapping.Codeunit.al @@ -45,7 +45,7 @@ codeunit 30163 "Shpfy Order Mapping" OrderHeader.Modify(); end end else - if Shop."Customer Import From Shopify" = Shop."Customer Import From Shopify"::None then begin + if Shop."Company Import From Shopify" = Shop."Company Import From Shopify"::None then begin if OrderHeader."Bill-to Customer No." = '' then OrderHeader."Bill-to Customer No." := Shop."Default Company No."; if OrderHeader."Sell-to Customer No." = '' then 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 a338f546b9..4af1062b69 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 @@ -109,7 +109,12 @@ codeunit 30165 "Shpfy Orders API" /// Parameter of type Record "Shopify Order Header". /// Parameter of type Text. /// Parameter of type Text. +#if not CLEAN24 + /// 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) +#endif var OrderAttribute: Record "Shpfy Order Attribute"; Parameters: Dictionary of [Text, Text]; @@ -122,7 +127,7 @@ codeunit 30165 "Shpfy Orders API" OrderAttribute."Order Id" := OrderHeader."Shopify Order Id"; OrderAttribute."Key" := CopyStr(KeyName, 1, MaxStrLen(OrderAttribute."Key")); #if not CLEAN24 - if not Shop."Replace Order Attribute Value" then + if not ShopifyShop."Replace Order Attribute Value" then OrderAttribute.Value := CopyStr(Value, 1, MaxStrLen(OrderAttribute.Value)) else #endif @@ -137,7 +142,7 @@ codeunit 30165 "Shpfy Orders API" Clear(JAttrib); JAttrib.Add('key', OrderAttribute."Key"); #if not CLEAN24 - if not Shop."Replace Order Attribute Value" then + if not ShopifyShop."Replace Order Attribute Value" then JAttrib.Add('value', OrderAttribute.Value) else #endif 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 b7d7d5d83c..afc8ec9ef4 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 @@ -114,6 +114,7 @@ codeunit 30166 "Shpfy Process Order" SalesHeader."Shpfy Order Id" := ShopifyOrderHeader."Shopify Order Id"; 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 @@ -135,8 +136,11 @@ codeunit 30166 "Shpfy Process Order" if ShopifyOrderHeader."Work Description".HasValue then SalesHeader.SetWorkDescription(ShopifyOrderHeader.GetWorkDescription()); end; - OrdersAPI.SetShop(ShopifyShop); +#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"; diff --git a/Apps/W1/Shopify/app/src/Order handling/Codeunits/ShpfyProcessOrders.Codeunit.al b/Apps/W1/Shopify/app/src/Order handling/Codeunits/ShpfyProcessOrders.Codeunit.al index 4ce2195a31..2e645cb91b 100644 --- a/Apps/W1/Shopify/app/src/Order handling/Codeunits/ShpfyProcessOrders.Codeunit.al +++ b/Apps/W1/Shopify/app/src/Order handling/Codeunits/ShpfyProcessOrders.Codeunit.al @@ -77,6 +77,14 @@ codeunit 30167 "Shpfy Process Orders" until ShopifyOrderHeader.Next() = 0; end; + internal procedure ClearProcessedDocuments(OrderHeader: Record "Shpfy Order Header") + begin + OrderHeader."Sales Order No." := ''; + OrderHeader."Sales Invoice No." := ''; + OrderHeader.Processed := false; + OrderHeader.Modify(); + end; + local procedure ProcessShopifyRefunds() var RefundHeader: Record "Shpfy Refund Header"; diff --git a/Apps/W1/Shopify/app/src/Order handling/Pages/ShpfyOrder.Page.al b/Apps/W1/Shopify/app/src/Order handling/Pages/ShpfyOrder.Page.al index 5ab2043ab8..53c8e4934e 100644 --- a/Apps/W1/Shopify/app/src/Order handling/Pages/ShpfyOrder.Page.al +++ b/Apps/W1/Shopify/app/src/Order handling/Pages/ShpfyOrder.Page.al @@ -87,6 +87,11 @@ page 30113 "Shpfy Order" ApplicationArea = All; ToolTip = 'Specifies how to make a payment, such as with bank transfer, cash, or check.'; } + field("PO Number"; Rec."PO Number") + { + ApplicationArea = All; + ToolTip = 'Specifies the purchase order number that is associated with the Shopify order.'; + } field(Closed; Rec.Closed) { ApplicationArea = All; @@ -234,7 +239,7 @@ page 30113 "Shpfy Order" { ApplicationArea = All; Editable = false; - ToolTip = 'Specifies the order''s status in terms of fulfilled line items. Valid values are: fulfilled, in progress, open, pending fulfillment, restocked, unfulfilled, partially fulfilled.'; + ToolTip = 'Specifies the order''s status in terms of fulfilled line items. Valid values are: fulfilled, in progress, open, pending fulfillment, restocked, unfulfilled, partially fulfilled, on hold.'; } field(ReturnStatus; Rec."Return Status") { @@ -571,6 +576,9 @@ page 30113 "Shpfy Order" ShopifyOrderHeader: Record "Shpfy Order Header"; ProcessShopifyOrders: Codeunit "Shpfy Process Orders"; begin + if Rec.Processed then + Error(ClearProcessedErr); + if Confirm(StrSubstNo(CreateShopifyMsg, Rec."Shopify Order No.")) then begin CurrPage.Update(true); Commit(); @@ -662,19 +670,35 @@ page 30113 "Shpfy Order" end; end; } - action(ResolveOrderProcessingConflicts) + action(UnlinkProcessedShopifyOrder) { ApplicationArea = All; - Enabled = Rec."Has Order State Error"; - Caption = 'Resolve conflicts'; - ToolTip = 'An order from Shopify will be marked with conflicts if it has been already processed in Business Central and new changes are detected in Shopify. In this page you can inspect the changes and resolve the conflicts appropriately.'; - RunObject = page "Shpfy Resolve Order Conflicts"; - Image = TaskList; - RunPageOnRec = true; - Promoted = true; - PromotedCategory = Process; - PromotedIsBig = true; - PromotedOnly = true; + Caption = 'Unlink Processed Documents'; + Enabled = Rec.Processed; + Image = UnLinkAccount; + ToolTip = 'Unlink the processed Shopify order from the sales document in Business Central.'; + + trigger OnAction() + var + ProcessShopifyOrders: Codeunit "Shpfy Process Orders"; + begin + if Confirm(ClearProcessedMsg) then + ProcessShopifyOrders.ClearProcessedDocuments(Rec); + end; + } + action(ForceSync) + { + ApplicationArea = All; + Image = Refresh; + Caption = 'Synch order from Shopify'; + ToolTip = 'Update your Shopify Order with the current data from Shopify.'; + + trigger OnAction() + var + ImportOrder: Codeunit "Shpfy Import Order"; + begin + ImportOrder.ReimportExistingOrderConfirmIfConflicting(Rec); + end; } } } @@ -881,6 +905,8 @@ page 30113 "Shpfy Order" var CreateShopifyMsg: Label 'Create sales document from Shopify order %1?', Comment = '%1 = Order No.'; MarkAsPaidMsg: Label 'The order has been marked as paid.'; + ClearProcessedMsg: Label 'This order is already linked to a sales document in Business Central. Do you want to unlink it?'; + ClearProcessedErr: Label 'This order is already linked to a sales document in Business Central.'; MarkAsPaidFailedErr: Label 'The order could not be marked as paid. You can see the error message from Shopify Log Entries.'; OrderCancelledMsg: Label 'Order has been cancelled successfully.'; OrderCancelFailedErr: Label 'The order could not be cancelled. You can see the error message from Shopify Log Entries.'; diff --git a/Apps/W1/Shopify/app/src/Order handling/Pages/ShpfyOrders.Page.al b/Apps/W1/Shopify/app/src/Order handling/Pages/ShpfyOrders.Page.al index 6fd7143e5b..86a538c252 100644 --- a/Apps/W1/Shopify/app/src/Order handling/Pages/ShpfyOrders.Page.al +++ b/Apps/W1/Shopify/app/src/Order handling/Pages/ShpfyOrders.Page.al @@ -122,7 +122,7 @@ page 30115 "Shpfy Orders" field(FulfillmentStatus; Rec."Fulfillment Status") { ApplicationArea = All; - ToolTip = 'Specifies the order''s status in terms of fulfilled line items. Valid values are: fulfilled, in progress, open, pending fulfillment, restocked, unfulfilled, partially fulfilled.'; + ToolTip = 'Specifies the order''s status in terms of fulfilled line items. Valid values are: fulfilled, in progress, open, pending fulfillment, restocked, unfulfilled, partially fulfilled, on hold.'; } field(ReturnStatus; Rec."Return Status") { 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 c054d063d9..b72ee7851d 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 @@ -24,7 +24,7 @@ table 30118 "Shpfy Order Header" { DataClassification = SystemMetadata; } - field(2; Email; Text[50]) + field(2; Email; Text[80]) { Caption = 'Email'; DataClassification = CustomerContent; @@ -590,6 +590,31 @@ table 30118 "Shpfy Order Header" Caption = 'B2B'; DataClassification = SystemMetadata; } + field(123; "Current Total Amount"; Decimal) + { + Caption = 'Current Total Amount'; + DataClassification = SystemMetadata; + } + field(124; "Current Total Items Quantity"; Integer) + { + Caption = 'Current Total Items Quantity'; + DataClassification = SystemMetadata; + } + field(125; "Line Items Redundancy Code"; Integer) + { + Caption = 'Line Items Redundancy Code'; + DataClassification = SystemMetadata; + } + field(126; "PO Number"; Text[512]) + { + Caption = 'PO Number'; + DataClassification = SystemMetadata; + } + field(127; "Company Location Id"; BigInteger) + { + Caption = 'Company Location Id'; + DataClassification = SystemMetadata; + } field(500; "Shop Code"; Code[20]) { Caption = 'Shop Code'; diff --git a/Apps/W1/Shopify/app/src/Order handling/Tables/ShpfyOrderLine.Table.al b/Apps/W1/Shopify/app/src/Order handling/Tables/ShpfyOrderLine.Table.al index 6ab176adf7..2a1f49f8d9 100644 --- a/Apps/W1/Shopify/app/src/Order handling/Tables/ShpfyOrderLine.Table.al +++ b/Apps/W1/Shopify/app/src/Order handling/Tables/ShpfyOrderLine.Table.al @@ -120,6 +120,12 @@ table 30119 "Shpfy Order Line" DataClassification = SystemMetadata; Editable = false; } + field(20; "Delivery Method Type"; Enum "Shpfy Delivery Method Type") + { + Caption = 'Delivery Method Type'; + DataClassification = SystemMetadata; + Editable = false; + } field(1000; "Item No."; Code[20]) { Caption = 'Item No.'; diff --git a/Apps/W1/Shopify/app/src/Shipping/Codeunits/ShpfyExportShipments.Codeunit.al b/Apps/W1/Shopify/app/src/Shipping/Codeunits/ShpfyExportShipments.Codeunit.al index 2ffd0f0edb..f1b3197515 100644 --- a/Apps/W1/Shopify/app/src/Shipping/Codeunits/ShpfyExportShipments.Codeunit.al +++ b/Apps/W1/Shopify/app/src/Shipping/Codeunits/ShpfyExportShipments.Codeunit.al @@ -30,11 +30,11 @@ codeunit 30190 "Shpfy Export Shipments" ShipmentLocation.SetRange(No, SalesShipmentHeader."No."); if ShipmentLocation.Open() then while ShipmentLocation.Read() do - CreateShopifyFulfillment(SalesShipmentHeader, ShipmentLocation.LocationId); + CreateShopifyFulfillment(SalesShipmentHeader, ShipmentLocation.LocationId, ShipmentLocation.DeliveryMethodType); end; end; - local procedure CreateShopifyFulfillment(var SalesShipmentHeader: Record "Sales Shipment Header"; LocationId: BigInteger); + local procedure CreateShopifyFulfillment(var SalesShipmentHeader: Record "Sales Shipment Header"; LocationId: BigInteger; DeliveryMethodType: Enum "Shpfy Delivery Method Type"); var Shop: Record "Shpfy Shop"; ShopifyOrderHeader: Record "Shpfy Order Header"; @@ -47,7 +47,7 @@ codeunit 30190 "Shpfy Export Shipments" if ShopifyOrderHeader.Get(SalesShipmentHeader."Shpfy Order Id") then begin ShopifyCommunicationMgt.SetShop(ShopifyOrderHeader."Shop Code"); Shop.Get(ShopifyOrderHeader."Shop Code"); - FulfillmentOrderRequest := CreateFulfillmentOrderRequest(SalesShipmentHeader, Shop, LocationId); + FulfillmentOrderRequest := CreateFulfillmentOrderRequest(SalesShipmentHeader, Shop, LocationId, DeliveryMethodType); if FulfillmentOrderRequest <> '' then begin JResponse := ShopifyCommunicationMgt.ExecuteGraphQL(FulfillmentOrderRequest); JFulfillment := JsonHelper.GetJsonToken(JResponse, 'data.fulfillmentCreateV2.fulfillment'); @@ -61,7 +61,7 @@ codeunit 30190 "Shpfy Export Shipments" end; end; - internal procedure CreateFulfillmentOrderRequest(SalesShipmentHeader: Record "Sales Shipment Header"; Shop: Record "Shpfy Shop"; LocationId: BigInteger) Request: Text; + internal procedure CreateFulfillmentOrderRequest(SalesShipmentHeader: Record "Sales Shipment Header"; Shop: Record "Shpfy Shop"; LocationId: BigInteger; DeliveryMethodType: Enum "Shpfy Delivery Method Type") Request: Text; var SalesShipmentLine: Record "Sales Shipment Line"; ShippingAgent: Record "Shipping Agent"; @@ -84,7 +84,7 @@ codeunit 30190 "Shpfy Export Shipments" if SalesShipmentLine.FindSet() then begin repeat if OrderLine.Get(SalesShipmentHeader."Shpfy Order Id", SalesShipmentLine."Shpfy Order Line Id") then - if OrderLine."Location Id" = LocationId then + if (OrderLine."Location Id" = LocationId) and (OrderLine."Delivery Method Type" = DeliveryMethodType) then if FindFulfillmentOrderLine(SalesShipmentHeader, SalesShipmentLine, FulfillmentOrderLine) then begin FulfillmentOrderLine."Quantity to Fulfill" += Round(SalesShipmentLine.Quantity, 1, '='); FulfillmentOrderLine."Remaining Quantity" := FulfillmentOrderLine."Remaining Quantity" - Round(SalesShipmentLine.Quantity, 1, '='); @@ -179,6 +179,7 @@ codeunit 30190 "Shpfy Export Shipments" FulfillmentOrderLine.SetRange("Shopify Order Id", OrderLine."Shopify Order Id"); FulfillmentOrderLine.SetRange("Shopify Variant Id", OrderLine."Shopify Variant Id"); FulfillmentOrderLine.SetRange("Shopify Location Id", OrderLine."Location Id"); + FulfillmentOrderLine.SetRange("Delivery Method Type", OrderLine."Delivery Method Type"); FulfillmentOrderLine.SetFilter("Remaining Quantity", '>=%1', Round(SalesShipmentLine.Quantity, 1, '=')); if FulfillmentOrderLine.FindFirst() then exit(true); diff --git a/Apps/W1/Shopify/app/src/Shipping/Queries/ShpfyShipmentLocation.Query.al b/Apps/W1/Shopify/app/src/Shipping/Queries/ShpfyShipmentLocation.Query.al index 4acbe5c317..e4dadf8042 100644 --- a/Apps/W1/Shopify/app/src/Shipping/Queries/ShpfyShipmentLocation.Query.al +++ b/Apps/W1/Shopify/app/src/Shipping/Queries/ShpfyShipmentLocation.Query.al @@ -27,6 +27,8 @@ query 30100 "Shpfy Shipment Location" column(LocationId; "Location Id") { } + column(DeliveryMethodType; "Delivery Method Type") { } + column(NoOfLines) { Method = Count; diff --git a/Apps/W1/Shopify/app/src/Webhooks/Codeunits/ShpfyWebhooksMgt.Codeunit.al b/Apps/W1/Shopify/app/src/Webhooks/Codeunits/ShpfyWebhooksMgt.Codeunit.al index e0d7973d4c..8abdb16675 100644 --- a/Apps/W1/Shopify/app/src/Webhooks/Codeunits/ShpfyWebhooksMgt.Codeunit.al +++ b/Apps/W1/Shopify/app/src/Webhooks/Codeunits/ShpfyWebhooksMgt.Codeunit.al @@ -3,6 +3,7 @@ namespace Microsoft.Integration.Shopify; using System.Integration; using System.Telemetry; using System.Threading; +using System.Environment; codeunit 30269 "Shpfy Webhooks Mgt." { @@ -93,13 +94,13 @@ codeunit 30269 "Shpfy Webhooks Mgt." Shop.Modify(); end; - internal procedure DisableBulkOperationsWebhook(var Shop: Record "Shpfy Shop") + internal procedure DisableBulkOperationsWebhook(var Shop: Record "Shpfy Shop"; CompanyName: Text) var WebhookSubscription: Record "Webhook Subscription"; ShpfyWebhooksAPI: Codeunit "Shpfy Webhooks API"; begin WebhookSubscription.SetRange("Subscription ID", GetShopDomain(Shop."Shopify URL")); - WebhookSubscription.SetRange("Company Name", CopyStr(CompanyName(), 1, MaxStrLen(WebhookSubscription."Company Name"))); + WebhookSubscription.SetRange("Company Name", CopyStr(CompanyName, 1, MaxStrLen(WebhookSubscription."Company Name"))); WebhookSubscription.SetRange(Endpoint, BulkOperationTopicLbl); if WebhookSubscription.FindFirst() then begin ShpfyWebhooksAPI.DeleteWebhookSubscription(Shop, Shop."Bulk Operation Webhook Id"); @@ -118,13 +119,13 @@ codeunit 30269 "Shpfy Webhooks Mgt." FeatureTelemetry.LogUptake('0000K8E', 'Shopify Webhooks', Enum::"Feature Uptake Status"::"Set up"); end; - internal procedure DisableOrderCreatedWebhook(var Shop: Record "Shpfy Shop") + internal procedure DisableOrderCreatedWebhook(var Shop: Record "Shpfy Shop"; CompanyName: Text) var WebhookSubscription: Record "Webhook Subscription"; ShpfyWebhooksAPI: Codeunit "Shpfy Webhooks API"; begin WebhookSubscription.SetRange("Subscription ID", GetShopDomain(Shop."Shopify URL")); - WebhookSubscription.SetRange("Company Name", CopyStr(CompanyName(), 1, MaxStrLen(WebhookSubscription."Company Name"))); + WebhookSubscription.SetRange("Company Name", CopyStr(CompanyName, 1, MaxStrLen(WebhookSubscription."Company Name"))); WebhookSubscription.SetRange(Endpoint, OrdersCreateTopicLbl); if WebhookSubscription.FindFirst() then begin ShpfyWebhooksAPI.DeleteWebhookSubscription(Shop, Shop."Order Created Webhook Id"); @@ -134,6 +135,29 @@ codeunit 30269 "Shpfy Webhooks Mgt." end; end; + [EventSubscriber(ObjectType::Table, Database::Company, 'OnBeforeDeleteEvent', '', false, false)] + local procedure HandleOnCompanyBeforeDelete(var Rec: Record Company; RunTrigger: Boolean) + var + Shop: Record "Shpfy Shop"; + TenantLicenseState: Codeunit "Tenant License State"; + EnumTenantLicenseState: Enum "Tenant License State"; + begin + if Rec.IsTemporary() then + exit; + + if Shop.ChangeCompany(Rec.Name) then begin + if not GuiAllowed() then + if TenantLicenseState.GetLicenseState() in [EnumTenantLicenseState::Suspended, EnumTenantLicenseState::Deleted, EnumTenantLicenseState::LockedOut] then + exit; + Shop.SetRange(Enabled, true); + if Shop.FindSet() then + repeat + DisableOrderCreatedWebhook(Shop, Rec.Name); + DisableBulkOperationsWebhook(Shop, Rec.Name); + until Shop.Next() = 0; + end; + end; + local procedure CreateWebhookSubscription(var Shop: Record "Shpfy Shop"; Endpoint: Text[250]; UserId: Guid) var WebhookSubscription: Record "Webhook Subscription"; diff --git a/Apps/W1/Shopify/test/Catalogs/ShpfyCatalogAPITest.Codeunit.al b/Apps/W1/Shopify/test/Catalogs/ShpfyCatalogAPITest.Codeunit.al index a454935e55..f50c1017d6 100644 --- a/Apps/W1/Shopify/test/Catalogs/ShpfyCatalogAPITest.Codeunit.al +++ b/Apps/W1/Shopify/test/Catalogs/ShpfyCatalogAPITest.Codeunit.al @@ -5,6 +5,7 @@ codeunit 139645 "Shpfy Catalog API Test" var LibraryAssert: Codeunit "Library Assert"; + LibraryRandom: Codeunit "Library - Random"; [Test] procedure UnitTestExtractShopifyCatalogs() @@ -42,15 +43,19 @@ codeunit 139645 "Shpfy Catalog API Test" JResponse: JsonObject; Result: Boolean; Cursor: Text; + ProductId: BigInteger; + ProductsList: List of [BigInteger]; begin // Creating Test data. - JResponse := CatalogInitialize.CatalogPriceResponse(); + ProductId := LibraryRandom.RandIntInRange(100000, 999999); + ProductsList.Add(ProductId); + JResponse := CatalogInitialize.CatalogPriceResponse(ProductId); // [SCENARIO] Extracting the Catalog Prices from the Shopify response. // [GIVEN] JResponse with Catalog Prices // [WHEN] Invoke CatalogAPI.ExtractShopifyCatalogPrices - Result := CatalogAPI.ExtractShopifyCatalogPrices(TempCatalogPrice, JResponse, Cursor); + Result := CatalogAPI.ExtractShopifyCatalogPrices(TempCatalogPrice, ProductsList, JResponse, Cursor); // [THEN] Result = true and Catalog prices are created. LibraryAssert.IsTrue(Result, 'ExtractShopifyCatalogPrices'); diff --git a/Apps/W1/Shopify/test/Catalogs/ShpfyCatalogInitialize.Codeunit.al b/Apps/W1/Shopify/test/Catalogs/ShpfyCatalogInitialize.Codeunit.al index 234ea61e92..bd9653b014 100644 --- a/Apps/W1/Shopify/test/Catalogs/ShpfyCatalogInitialize.Codeunit.al +++ b/Apps/W1/Shopify/test/Catalogs/ShpfyCatalogInitialize.Codeunit.al @@ -43,12 +43,12 @@ codeunit 139639 "Shpfy Catalog Initialize" exit(JResult); end; - internal procedure CatalogPriceResponse(): JsonObject + internal procedure CatalogPriceResponse(ProductId: Integer): JsonObject var JResult: JsonObject; - ResultLbl: Label '{"data":{"catalog":{"id":"gid://shopify/CompanyLocationCatalog/25217368294","priceList":{"id":"gid://shopify/PriceList/20079640806","prices":{"edges":[{"cursor":"eyJsYXN0X2lkIjo0NDA2OTAzMTMxMzYzOCwibGFzdF92YWx1ZSI6IjQ0MDY5MDMxMzEzNjM4In0=","node":{"variant":{"id":"gid://shopify/ProductVariant/44069031313638"},"price":{"amount":"4500.0"},"compareAtPrice":null}},{"cursor":"eyJsYXN0X2lkIjo0NDA3NDAwMzc1OTMzNCwibGFzdF92YWx1ZSI6IjQ0MDc0MDAzNzU5MzM0In0=","node":{"variant":{"id":"gid://shopify/ProductVariant/44074003759334"},"price":{"amount":"900.0"},"compareAtPrice":null}},{"cursor":"eyJsYXN0X2lkIjo0NDA3NDAwMzc5MjEwMiwibGFzdF92YWx1ZSI6IjQ0MDc0MDAzNzkyMTAyIn0=","node":{"variant":{"id":"gid://shopify/ProductVariant/44074003792102"},"price":{"amount":"1000.0"},"compareAtPrice":null}},{"cursor":"eyJsYXN0X2lkIjo0NDA3NDEzMjYzNTg3OCwibGFzdF92YWx1ZSI6IjQ0MDc0MTMyNjM1ODc4In0=","node":{"variant":{"id":"gid://shopify/ProductVariant/44074132635878"},"price":{"amount":"0.0"},"compareAtPrice":null}},{"cursor":"eyJsYXN0X2lkIjo0NDA3NDEzMzU4NjE1MCwibGFzdF92YWx1ZSI6IjQ0MDc0MTMzNTg2MTUwIn0=","node":{"variant":{"id":"gid://shopify/ProductVariant/44074133586150"},"price":{"amount":"0.0"},"compareAtPrice":null}},{"cursor":"eyJsYXN0X2lkIjo0NDA3NDEzMzYxODkxOCwibGFzdF92YWx1ZSI6IjQ0MDc0MTMzNjE4OTE4In0=","node":{"variant":{"id":"gid://shopify/ProductVariant/44074133618918"},"price":{"amount":"0.0"},"compareAtPrice":null}}],"pageInfo":{"hasNextPage":false}}}}},"extensions":{"cost":{"requestedQueryCost":204,"actualQueryCost":16,"throttleStatus":{"maximumAvailable":1000.0,"currentlyAvailable":984,"restoreRate":50.0}}}}'; + ResultLbl: Label '{"data":{"catalog":{"id":"gid://shopify/CompanyLocationCatalog/25217368294","priceList":{"id":"gid://shopify/PriceList/20079640806","prices":{"edges":[{"cursor":"eyJsYXN0X2lkIjo0NDA2OTAzMTMxMzYzOCwibGFzdF92YWx1ZSI6IjQ0MDY5MDMxMzEzNjM4In0=","node":{"variant":{"id":"gid://shopify/ProductVariant/44069031313638","product":{"id":"gid://shopify/Product/{{ProductId}}"}},"price":{"amount":"4500.0"},"compareAtPrice":null}},{"cursor":"eyJsYXN0X2lkIjo0NDA3NDAwMzc1OTMzNCwibGFzdF92YWx1ZSI6IjQ0MDc0MDAzNzU5MzM0In0=","node":{"variant":{"id":"gid://shopify/ProductVariant/44074003759334","product":{"id":"gid://shopify/Product/{{ProductId}}"}},"price":{"amount":"900.0"},"compareAtPrice":null}},{"cursor":"eyJsYXN0X2lkIjo0NDA3NDAwMzc5MjEwMiwibGFzdF92YWx1ZSI6IjQ0MDc0MDAzNzkyMTAyIn0=","node":{"variant":{"id":"gid://shopify/ProductVariant/44074003792102","product":{"id":"gid://shopify/Product/{{ProductId}}"}},"price":{"amount":"1000.0"},"compareAtPrice":null}},{"cursor":"eyJsYXN0X2lkIjo0NDA3NDEzMjYzNTg3OCwibGFzdF92YWx1ZSI6IjQ0MDc0MTMyNjM1ODc4In0=","node":{"variant":{"id":"gid://shopify/ProductVariant/44074132635878","product":{"id":"gid://shopify/Product/{{ProductId}}"}},"price":{"amount":"0.0"},"compareAtPrice":null}},{"cursor":"eyJsYXN0X2lkIjo0NDA3NDEzMzU4NjE1MCwibGFzdF92YWx1ZSI6IjQ0MDc0MTMzNTg2MTUwIn0=","node":{"variant":{"id":"gid://shopify/ProductVariant/44074133586150","product":{"id":"gid://shopify/Product/{{ProductId}}"}},"price":{"amount":"0.0"},"compareAtPrice":null}},{"cursor":"eyJsYXN0X2lkIjo0NDA3NDEzMzYxODkxOCwibGFzdF92YWx1ZSI6IjQ0MDc0MTMzNjE4OTE4In0=","node":{"variant":{"id":"gid://shopify/ProductVariant/44074133618918","product":{"id":"gid://shopify/Product/{{ProductId}}"}},"price":{"amount":"0.0"},"compareAtPrice":null}}],"pageInfo":{"hasNextPage":false}}}}},"extensions":{"cost":{"requestedQueryCost":204,"actualQueryCost":16,"throttleStatus":{"maximumAvailable":1000.0,"currentlyAvailable":984,"restoreRate":50.0}}}}'; begin - JResult.ReadFrom(ResultLbl); + JResult.ReadFrom(Format(ResultLbl).Replace('{{ProductId}}', Format(ProductId))); exit(JResult); end; } diff --git a/Apps/W1/Shopify/test/Customers/ShpfyCustomerInitTest.Codeunit.al b/Apps/W1/Shopify/test/Customers/ShpfyCustomerInitTest.Codeunit.al index e66bb0bc71..697feb6fd7 100644 --- a/Apps/W1/Shopify/test/Customers/ShpfyCustomerInitTest.Codeunit.al +++ b/Apps/W1/Shopify/test/Customers/ShpfyCustomerInitTest.Codeunit.al @@ -121,7 +121,7 @@ codeunit 139585 "Shpfy Customer Init Test" var #pragma warning disable AL0435 #pragma warning disable AA0240 - GraphQLTxt: Label '{"query":"mutation {customerUpdate(input: {id: \"gid://shopify/Customer/%1\", email: \"!mail@domain.com\", firstName: \"!Firstname\", lastName: \"!Lastname\", phone: \"!111\", addresses: {id: \"gid://shopify/MailingAddress/%2?model_name=CustomerAddress\", company: \"!Company\", firstName: \"!Firstname\", lastName: \"!Lastname\", address1: \"!Address\", address2: \"!Address 2\", zip: \"1111\", city: \"!City\", countryCode: US, phone: \"!111\"}}) {customer {id, acceptsMarketing, acceptsMarketingUpdatedAt, tags, updatedAt, verifiedEmail, defaultAddress {id, province, country}}, userErrors {field, message}}}"}', Comment = '%1 = CustomerId, %2 = CustomerAddressId', Locked = true; + GraphQLTxt: Label '{"query":"mutation {customerUpdate(input: {id: \"gid://shopify/Customer/%1\", email: \"!mail@domain.com\", firstName: \"!Firstname\", lastName: \"!Lastname\", phone: \"!111\", addresses: {id: \"gid://shopify/MailingAddress/%2?model_name=CustomerAddress\", company: \"!Company\", firstName: \"!Firstname\", lastName: \"!Lastname\", address1: \"!Address\", address2: \"!Address 2\", zip: \"1111\", city: \"!City\", countryCode: US, phone: \"!111\"}}) {customer {id, tags, updatedAt, verifiedEmail, emailMarketingConsent {consentUpdatedAt marketingState}, defaultAddress {id, province, country}}, userErrors {field, message}}}"}', Comment = '%1 = CustomerId, %2 = CustomerAddressId', Locked = true; #pragma warning restore AA0240 #pragma warning restore AL0435 begin @@ -133,7 +133,7 @@ codeunit 139585 "Shpfy Customer Init Test" JCustomer: JsonObject; #pragma warning disable AL0435 #pragma warning disable AA0240 - JCustomerTxt: Label '{"legacyResourceId":"%1","firstName":"First Name","lastName":"Last Name","email":"Email","phone":"Phone No.","acceptsMarketing":false,"acceptsMarketingUpdatedAt":"2022-04-01T00:00:00Z","taxExempt":false,"taxExemptions":[],"verifiedEmail":true,"state":"DISABLED","note":null,"createdAt":"2022-04-01T00:00:00Z","updatedAt":"%3T00:00:00Z","tags":[],"addresses":[{"id":"gid:\/\/shopify\/MailingAddress\/%2?model_name=CustomerAddress","company":"Company","firstName":"First Name","lastName":"Last Name","address1":"Address 1","address2":"Address 2","zip":"ZIP","city":"City","countryCodeV2":"US","country":"Country/Region Name","provinceCode":"Province Code","province":"Province Name","phone":"Phone No."}],"defaultAddress":{"id":"gid:\/\/shopify\/MailingAddress\/7065543475272?model_name=CustomerAddress"},"metafields":{"edges":[]}}', Comment = '%1 = CustomerId, %2 = CustomerAddressId, %3 = Date of Update as YYYY-MM-DD', Locked = true; + JCustomerTxt: Label '{"legacyResourceId":"%1","firstName":"First Name","lastName":"Last Name","email":"Email","phone":"Phone No.","taxExempt":false,"taxExemptions":[],"verifiedEmail":true,"state":"DISABLED","note":null,"createdAt":"2022-04-01T00:00:00Z","updatedAt":"%3T00:00:00Z","tags":[],"emailMarketingConsent":{"consentUpdatedAt":"2022-04-01T00:00:00Z","marketingState":"NOT_SUBSCRIBED"},"addresses":[{"id":"gid:\/\/shopify\/MailingAddress\/%2?model_name=CustomerAddress","company":"Company","firstName":"First Name","lastName":"Last Name","address1":"Address 1","address2":"Address 2","zip":"ZIP","city":"City","countryCodeV2":"US","country":"Country/Region Name","provinceCode":"Province Code","province":"Province Name","phone":"Phone No."}],"defaultAddress":{"id":"gid:\/\/shopify\/MailingAddress\/7065543475272?model_name=CustomerAddress"},"metafields":{"edges":[]}}', Comment = '%1 = CustomerId, %2 = CustomerAddressId, %3 = Date of Update as YYYY-MM-DD', Locked = true; #pragma warning restore AA0240 #pragma warning restore AL0435 begin diff --git a/Apps/W1/Shopify/test/Shipping/ShpfyShippingTest.Codeunit.al b/Apps/W1/Shopify/test/Shipping/ShpfyShippingTest.Codeunit.al index ca31a3df73..578e420c0a 100644 --- a/Apps/W1/Shopify/test/Shipping/ShpfyShippingTest.Codeunit.al +++ b/Apps/W1/Shopify/test/Shipping/ShpfyShippingTest.Codeunit.al @@ -15,6 +15,7 @@ codeunit 139606 "Shpfy Shipping Test" Shop: Record "Shpfy Shop"; ExportShipments: Codeunit "Shpfy Export Shipments"; JsonHelper: Codeunit "Shpfy Json Helper"; + DeliveryMethodType: Enum "Shpfy Delivery Method Type"; FulfillmentRequest: Text; JFulfillment: JsonObject; JLineItems: JsonArray; @@ -27,12 +28,13 @@ codeunit 139606 "Shpfy Shipping Test" // [GIVEN] A random Sales Shipment, a random LocationId, a random Shop Shop.Init(); LocationId := Any.IntegerInRange(10000, 99999); - ShopifyOrderId := CreateRandomShopifyOrder(LocationId); - ShopifyFulfillmentOrderId := CreateShopifyFulfillmentOrder(ShopifyOrderId); + DeliveryMethodType := DeliveryMethodType::Shipping; + ShopifyOrderId := CreateRandomShopifyOrder(LocationId, DeliveryMethodType); + ShopifyFulfillmentOrderId := CreateShopifyFulfillmentOrder(ShopifyOrderId, DeliveryMethodType); CreateRandomSalesShipment(SalesShipmentHeader, ShopifyOrderId); // [WHEN] Invoke the function CreateFulfillmentRequest() - FulfillmentRequest := ExportShipments.CreateFulfillmentOrderRequest(SalesShipmentHeader, Shop, LocationId); + FulfillmentRequest := ExportShipments.CreateFulfillmentOrderRequest(SalesShipmentHeader, Shop, LocationId, DeliveryMethodType); // [THEN] We must find the correct fulfilment data in the json token LibraryAssert.IsTrue(FulfillmentRequest.Contains(Format(ShopifyFulfillmentOrderId)), 'Fulfillmentorder Id Check'); @@ -47,7 +49,7 @@ codeunit 139606 "Shpfy Shipping Test" end; end; - local procedure CreateRandomShopifyOrder(LocationId: BigInteger): BigInteger + local procedure CreateRandomShopifyOrder(LocationId: BigInteger; DeliveryMethodType: Enum "Shpfy Delivery Method Type"): BigInteger var OrderHeader: Record "Shpfy Order Header"; OrderLine: Record "Shpfy Order Line"; @@ -63,12 +65,13 @@ codeunit 139606 "Shpfy Shipping Test" OrderLine."Line Id" := Any.IntegerInRange(10000, 99999); OrderLine.Quantity := Any.IntegerInRange(1, 10); OrderLine."Location Id" := LocationId; + OrderLine."Delivery Method Type" := DeliveryMethodType; OrderLine.Insert(); exit(OrderHeader."Shopify Order Id"); end; - local procedure CreateShopifyFulfillmentOrder(ShopifyOrderId: BigInteger): BigInteger + local procedure CreateShopifyFulfillmentOrder(ShopifyOrderId: BigInteger; DeliveryMethodType: Enum "Shpfy Delivery Method Type"): BigInteger var OrderLine: Record "Shpfy Order Line"; FulfillmentOrderHeader: Record "Shpfy FulFillment Order Header"; @@ -77,6 +80,7 @@ codeunit 139606 "Shpfy Shipping Test" Clear(FulfillmentOrderHeader); FulfillmentOrderHeader."Shopify Fulfillment Order Id" := Any.IntegerInRange(10000, 99999); FulfillmentOrderHeader."Shopify Order Id" := ShopifyOrderId; + FulfillmentOrderHeader."Delivery Method Type" := FulfillmentOrderHeader."Delivery Method Type"::Shipping; FulfillmentOrderHeader.Insert(); OrderLine.Reset(); @@ -91,6 +95,7 @@ codeunit 139606 "Shpfy Shipping Test" FulfillmentOrderLine."Shopify Variant Id" := OrderLine."Shopify Variant Id"; FulfillmentOrderLine."Remaining Quantity" := OrderLine.Quantity; FulfillmentOrderLine."Shopify Location Id" := OrderLine."Location Id"; + FulfillmentOrderLine."Delivery Method Type" := DeliveryMethodType; FulfillmentOrderLine.Insert(); until OrderLine.Next() = 0; diff --git a/Apps/W1/Shopify/test/app.json b/Apps/W1/Shopify/test/app.json index 9b0824a282..a4d480aa90 100644 --- a/Apps/W1/Shopify/test/app.json +++ b/Apps/W1/Shopify/test/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "Test for the Shopify Connector extension", "description": "Test for the Shopify Connector extension", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2009120", "help": "https://go.microsoft.com/fwlink/?linkid=2179727", @@ -16,43 +16,43 @@ "id": "ec255f57-31d0-4ca2-b751-f2fa7c745abb", "name": "Shopify Connector", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "9856ae4f-d1a7-46ef-89bb-6ef056398228", "name": "System Application Test Library", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "e7320ebb-08b3-4406-b1ec-b4927d3e280b", "name": "Any", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "dd0be2ea-f733-4d65-bb34-a28f4624fb14", "name": "Library Assert", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5095f467-0a01-4b99-99d1-9ff1237d286f", "publisher": "Microsoft", "name": "Library Variable Storage", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 139560, @@ -71,9 +71,9 @@ "to": 139639 }, { - "from": 139645, - "to": 139649 - } + "from": 139645, + "to": 139649 + } ], "target": "OnPrem", "resourceExposurePolicy": { @@ -81,5 +81,5 @@ "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/W1/SimplifiedBankStatementImport/app/app.json b/Apps/W1/SimplifiedBankStatementImport/app/app.json index 6bae487916..59fa64b4e0 100644 --- a/Apps/W1/SimplifiedBankStatementImport/app/app.json +++ b/Apps/W1/SimplifiedBankStatementImport/app/app.json @@ -2,7 +2,7 @@ "id": "79b1a79a-2f66-4736-bc1b-8abb3537eb51", "name": "Simplified Bank Statement Import", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "The Simplified Bank Statement Import extension makes it easy to define a bank statement format.", "description": "The Simplified Bank Statement Import extension makes it easy to define a bank statement format.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -10,8 +10,8 @@ "help": "https://go.microsoft.com/fwlink/?linkid=2172520", "url": "https://go.microsoft.com/fwlink/?LinkId=724011", "logo": "ExtensionLogo.png", - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 8850, diff --git a/Apps/W1/SimplifiedBankStatementImport/test/app.json b/Apps/W1/SimplifiedBankStatementImport/test/app.json index 8713b0ed46..a29754ff76 100644 --- a/Apps/W1/SimplifiedBankStatementImport/test/app.json +++ b/Apps/W1/SimplifiedBankStatementImport/test/app.json @@ -2,7 +2,7 @@ "id": "fdf552ef-df0f-4caa-9a40-4b13b527e510", "name": "Simplified Bank Statement Import Test", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "brief": "Tests for Simplified Bank Statement Import.", "description": "Tests for Simplified Bank Statement Import.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -10,8 +10,8 @@ "help": "https://go.microsoft.com/fwlink/?linkid=2172520", "url": "https://go.microsoft.com/fwlink/?LinkId=724011", "logo": "ExtensionLogo.png", - "platform": "24.0.0.0", - "application": "24.0.0.0", + "platform": "25.0.0.0", + "application": "25.0.0.0", "idRanges": [ { "from": 148130, @@ -23,19 +23,19 @@ "id": "79b1a79a-2f66-4736-bc1b-8abb3537eb51", "name": "Simplified Bank Statement Import", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5d86850b-0d76-4eca-bd7b-951ad998e997", "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "id": "5095f467-0a01-4b99-99d1-9ff1237d286f", "name": "Library Variable Storage", "publisher": "Microsoft", - "version": "24.0.0.0" + "version": "25.0.0.0" } ], "contextSensitiveHelpUrl": "https://go.microsoft.com/fwlink/?linkid=2206253", diff --git a/Apps/W1/SmartList/app.json b/Apps/W1/SmartList/app.json index f87df33670..0add47612b 100644 --- a/Apps/W1/SmartList/app.json +++ b/Apps/W1/SmartList/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "SmartList", "description": "View query information within Business Central list pages that dynamically renders data on the page based on query definition.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?LinkId=847985", "help": "https://go.microsoft.com/fwlink/?LinkId=849257", @@ -17,7 +17,7 @@ "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "target": "OnPrem", "resourceExposurePolicy": { "allowDebugging": true, @@ -33,5 +33,5 @@ "to": 3010 } ], - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/W1/StatisticalAccounts/app/app.json b/Apps/W1/StatisticalAccounts/app/app.json index 8fc39826e0..ea4e8ad07e 100644 --- a/Apps/W1/StatisticalAccounts/app/app.json +++ b/Apps/W1/StatisticalAccounts/app/app.json @@ -4,7 +4,7 @@ "publisher": "Microsoft", "brief": "Statistical Accounts lets you hold measures for use in Financial reporting to create reports with KPIs based on non-financial data.", "description": "When reporting on your Business Central data through financial Reporting you often want to add non-financial data to the reports, for KPI for comparisons etc. Statistical Accounts improve analyses and progress tracking by letting you hold number-based statistical measures in a separate ledger. For example, you might want track square meters in your buildings for KPIs on rental expenses, or number of full-time employees, for metrics such as revenue or costs per employee. You set up new accounts in Statistical Accounts, and register values in Statistical Accounts Journals. The accounts can be used in Row definitions in Financial Reporting to create new insights on your business.", - "version": "24.0.0.0", + "version": "25.0.0.0", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", "EULA": "https://go.microsoft.com/fwlink/?linkid=2182906", "url": "https://go.microsoft.com/fwlink/?LinkId=724011", @@ -17,7 +17,7 @@ "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "idRanges": [ { "from": 1, @@ -30,5 +30,5 @@ "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/W1/StatisticalAccounts/test/app.json b/Apps/W1/StatisticalAccounts/test/app.json index 87072a4208..e5a83a051c 100644 --- a/Apps/W1/StatisticalAccounts/test/app.json +++ b/Apps/W1/StatisticalAccounts/test/app.json @@ -2,7 +2,7 @@ "id": "f963cb1a-e16e-48af-b3fd-c0dd695d0998", "name": "Statistical Accounts Test", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "description": "Tests for the Statistical Accounts extension.", "brief": "Tests for the functionality of Statistical Accounts. The test are verifying the logic of tracking and reporting on non-transactional data.", "privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009", @@ -15,43 +15,43 @@ { "name": "Tests-TestLibraries", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "id": "5d86850b-0d76-4eca-bd7b-951ad998e997" }, { "name": "System Application Test Library", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "id": "9856ae4f-d1a7-46ef-89bb-6ef056398228" }, { "name": "Library Variable Storage", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "id": "5095f467-0a01-4b99-99d1-9ff1237d286f" }, { "id": "e7320ebb-08b3-4406-b1ec-b4927d3e280b", "publisher": "Microsoft", "name": "Any", - "version": "24.0.0.0" + "version": "25.0.0.0" }, { "name": "Statistical Accounts", "publisher": "Microsoft", - "version": "24.0.0.0", + "version": "25.0.0.0", "id": "ea130081-c669-460f-a5f4-5dde14f03131" } ], "screenshots": [ ], - "platform": "24.0.0.0", + "platform": "25.0.0.0", "resourceExposurePolicy": { "allowDebugging": false, "allowDownloadingSource": true, "includeSourceInSymbolFile": true }, "target": "OnPrem", - "application": "24.0.0.0" + "application": "25.0.0.0" } \ No newline at end of file diff --git a/Apps/W1/Sustainability/app/app.json b/Apps/W1/Sustainability/app/app.json index acaaf11937..aacd52a7ab 100644 --- a/Apps/W1/Sustainability/app/app.json +++ b/Apps/W1/Sustainability/app/app.json @@ -1,39 +1,43 @@ { - "id": "b3780cd9-f8f8-4a83-a4d5-0c2ad87b28af", - "name": "Sustainability", - "publisher": "Microsoft", - "version": "24.0.0.0", - "brief": "Sustainability module will enable users to collect and report on their sustainability activities. Solution is the foundation that will be used for being compliant with some of ESG standards.", - "description": "Sustainability module will enable users to collect and report on their sustainability activities. Solution is the foundation that will be used for being compliant with some of ESG standards.", - "privacyStatement": "https://go.microsoft.com/fwlink/?linkid=724009", - "EULA": "https://go.microsoft.com/fwlink/?linkid=724013", - "help": "https://go.microsoft.com/fwlink/?linkid=2139719", - "contextSensitiveHelpUrl": "https://go.microsoft.com/fwlink/?linkid=2139719", - "url": "https://go.microsoft.com/fwlink/?linkid=724011", - "logo": "./ExtensionLogo.png", - "dependencies": [], - "internalsVisibleTo": [ - { - "id": "6723f320-28a1-40cc-bf4d-d4dce362cb39", - "name": "Sustainability Tests", - "publisher": "Microsoft" - } - ], - "screenshots": [], - "platform": "24.0.0.0", - "application": "24.0.0.0", - "idRanges": [ - { - "from": 6210, - "to": 6300 - } - ], - "features": [ - "TranslationFile" - ], - "resourceExposurePolicy": { - "allowDebugging": true, - "allowDownloadingSource": true, - "includeSourceInSymbolFile": true - } + "id": "b3780cd9-f8f8-4a83-a4d5-0c2ad87b28af", + "name": "Sustainability", + "publisher": "Microsoft", + "version": "25.0.0.0", + "brief": "Sustainability module will enable users to collect and report on their sustainability activities. Solution is the foundation that will be used for being compliant with some of ESG standards.", + "description": "Sustainability module will enable users to collect and report on their sustainability activities. Solution is the foundation that will be used for being compliant with some of ESG standards.", + "privacyStatement": "https://go.microsoft.com/fwlink/?linkid=724009", + "EULA": "https://go.microsoft.com/fwlink/?linkid=724013", + "help": "https://go.microsoft.com/fwlink/?linkid=2139719", + "contextSensitiveHelpUrl": "https://go.microsoft.com/fwlink/?linkid=2139719", + "url": "https://go.microsoft.com/fwlink/?linkid=724011", + "logo": "./ExtensionLogo.png", + "dependencies": [ + + ], + "internalsVisibleTo": [ + { + "id": "6723f320-28a1-40cc-bf4d-d4dce362cb39", + "name": "Sustainability Tests", + "publisher": "Microsoft" + } + ], + "screenshots": [ + + ], + "platform": "25.0.0.0", + "application": "25.0.0.0", + "idRanges": [ + { + "from": 6210, + "to": 6300 + } + ], + "features": [ + "TranslationFile" + ], + "resourceExposurePolicy": { + "allowDebugging": true, + "allowDownloadingSource": true, + "includeSourceInSymbolFile": true + } } \ No newline at end of file diff --git a/Apps/W1/Sustainability/app/src/Account/CalculationFoundation.Enum.al b/Apps/W1/Sustainability/app/src/Account/CalculationFoundation.Enum.al index 830c9bdb43..8159d8a1f3 100644 --- a/Apps/W1/Sustainability/app/src/Account/CalculationFoundation.Enum.al +++ b/Apps/W1/Sustainability/app/src/Account/CalculationFoundation.Enum.al @@ -2,8 +2,6 @@ namespace Microsoft.Sustainability.Account; enum 6210 "Calculation Foundation" { - Extensible = false; - value(0; " ") { Caption = ' '; } value(1; "Fuel/Electricity") { Caption = 'Fuel/Electricity'; } value(2; Distance) { Caption = 'Distance'; } diff --git a/Apps/W1/Sustainability/app/src/Account/ChartOfSustainAccounts.Page.al b/Apps/W1/Sustainability/app/src/Account/ChartOfSustainAccounts.Page.al index 4f433f0fd7..4d56a1b805 100644 --- a/Apps/W1/Sustainability/app/src/Account/ChartOfSustainAccounts.Page.al +++ b/Apps/W1/Sustainability/app/src/Account/ChartOfSustainAccounts.Page.al @@ -16,7 +16,7 @@ page 6210 "Chart of Sustain. Accounts" SourceTable = "Sustainability Account"; UsageCategory = Lists; AnalysisModeEnabled = false; - AdditionalSearchTerms = 'Sustainability Account List, Sustainability Accounts, Sustainability Overview, Sustainability Chart'; + AdditionalSearchTerms = 'Sustainability Account List, Sustainability Accounts, Sustainability Overview, Sustainability Chart, CsA'; layout { @@ -31,13 +31,13 @@ page 6210 "Chart of Sustain. Accounts" { Style = Strong; StyleExpr = Rec."Account Type" <> Rec."Account Type"::Posting; - ToolTip = 'Specifies the sustainability account number in the chart of sustainability accounts.'; + ToolTip = 'Specifies the account number of the sustainability account.'; } field("No. 2"; Rec."No. 2") { Style = Strong; StyleExpr = Rec."Account Type" <> Rec."Account Type"::Posting; - ToolTip = 'Specifies an alternative account number which can be used internally in the company.'; + ToolTip = 'Specifies the additional account number of the sustainability account.'; Visible = false; } field(Name; Rec.Name) @@ -60,12 +60,12 @@ page 6210 "Chart of Sustain. Accounts" } field("Balance at Date (CO2)"; Rec."Balance at Date (CO2)") { - ToolTip = 'Specifies the balance at date of CO2 on this account for the upper date in the Date Filter field.'; + ToolTip = 'Specifies the balance at date of CO2 on the account for the upper date in the Date Filter field.'; Visible = false; } field("Balance (CO2)"; Rec."Balance (CO2)") { - ToolTip = 'Specifies the balance on CO2 on this account.'; + ToolTip = 'Specifies the balance of CO2 on the account.'; } field("Net Change (CH4)"; Rec."Net Change (CH4)") { @@ -73,12 +73,12 @@ page 6210 "Chart of Sustain. Accounts" } field("Balance at Date (CH4)"; Rec."Balance at Date (CH4)") { - ToolTip = 'Specifies the balance at date of CH4 on this account for the upper date in the Date Filter field.'; + ToolTip = 'Specifies the balance at date of CH4 on the account for the upper date in the Date Filter field.'; Visible = false; } field("Balance (CH4)"; Rec."Balance (CH4)") { - ToolTip = 'Specifies the balance of CH4 on this account.'; + ToolTip = 'Specifies the balance of CH4 on the account.'; } field("Net Change (N2O)"; Rec."Net Change (N2O)") { @@ -86,12 +86,12 @@ page 6210 "Chart of Sustain. Accounts" } field("Balance at Date (N2O)"; Rec."Balance at Date (N2O)") { - ToolTip = 'Specifies the balance at date of N2O on this account for the upper date in the Date Filter field.'; + ToolTip = 'Specifies the balance at date of N2O on the account for the upper date in the Date Filter field.'; Visible = false; } field("Balance (N2O)"; Rec."Balance (N2O)") { - ToolTip = 'Specifies the balance of N2O on this account.'; + ToolTip = 'Specifies the balance of N2O on the account.'; } field(Category; Rec.Category) { @@ -251,7 +251,7 @@ page 6210 "Chart of Sustain. Accounts" Caption = 'Total Emissions'; RunObject = report "Total Emissions"; Image = Report; - ToolTip = 'View the total emissions balance for the sustainability accounts that you specify.'; + ToolTip = 'View total emissions details.'; } action(EmissionByCategory) { diff --git a/Apps/W1/Sustainability/app/src/Account/SustainAccountCategories.Page.al b/Apps/W1/Sustainability/app/src/Account/SustainAccountCategories.Page.al index 75b0df92a2..fa4df7eab4 100644 --- a/Apps/W1/Sustainability/app/src/Account/SustainAccountCategories.Page.al +++ b/Apps/W1/Sustainability/app/src/Account/SustainAccountCategories.Page.al @@ -20,11 +20,11 @@ page 6213 "Sustain. Account Categories" } field(Description; Rec.Description) { - ToolTip = 'Specifies the description of the record.'; + ToolTip = 'Specifies the category description.'; } field("Emission Scope"; Rec."Emission Scope") { - ToolTip = 'Specifies the type of the scope of the record.'; + ToolTip = 'Specifies the scope of the emissions that are associated with the sustainability category. Scope 1: Direct emissions from sources that are owned or controlled by the reporting entity. Scope 2: Indirect emissions from the generation of purchased electricity, heat, or steam consumed by the reporting entity. Scope 3: Other indirect emissions, such as the extraction and production of purchased materials and fuels, transport-related activities in vehicles not owned or controlled by the reporting entity, and waste disposal.'; } field(CO2; Rec.CO2) { @@ -40,15 +40,15 @@ page 6213 "Sustain. Account Categories" } field("Calculation Foundation"; Rec."Calculation Foundation") { - ToolTip = 'Specifies the foundation for emission calculation.'; + ToolTip = 'Specifies the calculation foundation for emission calculation.'; } field("Custom Value"; Rec."Custom Value") { - ToolTip = 'Specifies the custom foundation for emission calculation.'; + ToolTip = 'Specifies the custom value for emission calculation.'; } field("Calculate from General Ledger"; Rec."Calculate from General Ledger") { - ToolTip = 'Specifies if the custom amount should be calculated from general ledger entries.'; + ToolTip = 'Specifies if the custom amount is calculated from general ledger.'; } field("G/L Account Filter"; Rec."G/L Account Filter") { @@ -79,7 +79,7 @@ page 6213 "Sustain. Account Categories" Image = Description; RunObject = Page "Sustain. Account Subcategories"; RunPageLink = "Category Code" = field(Code); - ToolTip = 'View or edit multiple subcategories for a specific category.'; + ToolTip = 'Open the Subcategories page to view and manage the subcategories for the selected category.'; Scope = Repeater; } } diff --git a/Apps/W1/Sustainability/app/src/Account/SustainAccountCategory.Table.al b/Apps/W1/Sustainability/app/src/Account/SustainAccountCategory.Table.al index 5d7d33b71a..e37bcb79e8 100644 --- a/Apps/W1/Sustainability/app/src/Account/SustainAccountCategory.Table.al +++ b/Apps/W1/Sustainability/app/src/Account/SustainAccountCategory.Table.al @@ -3,6 +3,7 @@ namespace Microsoft.Sustainability.Account; using Microsoft.Finance.GeneralLedger.Account; using Microsoft.Finance.GeneralLedger.Setup; using Microsoft.Finance.Dimension; +using Microsoft.Sustainability.Ledger; table 6211 "Sustain. Account Category" { @@ -176,6 +177,7 @@ table 6211 "Sustain. Account Category" begin DeleteSubcategories(); UpdateSustainabilityAccounts(); + UpdateSustainabilityEntries(); end; trigger OnInsert() @@ -183,6 +185,12 @@ table 6211 "Sustain. Account Category" TestField(Code); end; + trigger OnModify() + begin + if "Calculation Foundation" = "Calculation Foundation"::Custom then + TestField("Custom Value"); + end; + var DeleteSubcategoriesQst: Label 'One or more subcategories belong to category ''''%1''''.\\Do you want to delete category with all the related subcategories? ', Comment = '%1 - category code'; @@ -207,6 +215,15 @@ table 6211 "Sustain. Account Category" SustainAccount.ModifyAll(Category, ''); end; + local procedure UpdateSustainabilityEntries() + var + SustainabilityLedgerEntry: Record "Sustainability Ledger Entry"; + begin + SustainabilityLedgerEntry.SetRange("Account Category", Code); + if not SustainabilityLedgerEntry.IsEmpty() then + SustainabilityLedgerEntry.ModifyAll("Account Category", ''); + end; + local procedure CheckIfChangeIsAllowedForCategory(FieldCaption: Text) var SustainabilityAccountMgt: Codeunit "Sustainability Account Mgt."; diff --git a/Apps/W1/Sustainability/app/src/Account/SustainAccountSubcategories.Page.al b/Apps/W1/Sustainability/app/src/Account/SustainAccountSubcategories.Page.al index a04e514649..42d6bdf4b3 100644 --- a/Apps/W1/Sustainability/app/src/Account/SustainAccountSubcategories.Page.al +++ b/Apps/W1/Sustainability/app/src/Account/SustainAccountSubcategories.Page.al @@ -15,40 +15,40 @@ page 6214 "Sustain. Account Subcategories" { field("Category Code"; Rec."Category Code") { - ToolTip = 'Specifies a parent category code.'; + ToolTip = 'Specifies the parent category code.'; Visible = false; } field(Code; Rec.Code) { - ToolTip = 'Specifies a subcategory code.'; + ToolTip = 'Specifies the subcategory code.'; } field(Description; Rec.Description) { - ToolTip = 'Specifies a description of the record.'; + ToolTip = 'Specifies the description of the record.'; } field("Emission Factor CO2"; Rec."Emission Factor CO2") { - ToolTip = 'Specifies an emission factor for CO2 emission.'; + ToolTip = 'Specifies the emission factor for CO2 emission.'; } field("Emission Factor CH4"; Rec."Emission Factor CH4") { - ToolTip = 'Specifies an emission factor for CH4 emission.'; + ToolTip = 'Specifies the emission factor for CH4 emission.'; } field("Emission Factor N2O"; Rec."Emission Factor N2O") { - ToolTip = 'Specifies an emission factor for N2O emission.'; + ToolTip = 'Specifies the emission factor for N2O emission.'; } field("Import Data"; Rec."Import Data") { - ToolTip = 'Specifies if a data is imported from external source.'; + ToolTip = 'Specifies if the data is imported from external source.'; } field("Import From"; Rec."Import From") { - ToolTip = 'Specifies a source URL from where the data is imported.'; + ToolTip = 'Specifies the source of the imported data.'; } field("Renewable Energy"; Rec."Renewable Energy") { - ToolTip = 'Specifies if a subcategory is a part of renewable energy.'; + ToolTip = 'Specifies if the subcategory is a part of renewable energy.'; } } } diff --git a/Apps/W1/Sustainability/app/src/Account/SustainAccountSubcategory.Table.al b/Apps/W1/Sustainability/app/src/Account/SustainAccountSubcategory.Table.al index 06ee8adf76..fc1d16f663 100644 --- a/Apps/W1/Sustainability/app/src/Account/SustainAccountSubcategory.Table.al +++ b/Apps/W1/Sustainability/app/src/Account/SustainAccountSubcategory.Table.al @@ -1,6 +1,7 @@ namespace Microsoft.Sustainability.Account; using Microsoft.Sustainability.Setup; +using Microsoft.Sustainability.Ledger; table 6212 "Sustain. Account Subcategory" { @@ -84,11 +85,17 @@ table 6212 "Sustain. Account Subcategory" trigger OnDelete() var SustainabilityAccount: Record "Sustainability Account"; + SustainabilityLedgerEntry: Record "Sustainability Ledger Entry"; begin SustainabilityAccount.SetRange(Category, "Category Code"); SustainabilityAccount.SetRange(Subcategory, Code); if not SustainabilityAccount.IsEmpty() then SustainabilityAccount.ModifyAll(Subcategory, ''); + + SustainabilityLedgerEntry.SetRange("Account Category", "Category Code"); + SustainabilityLedgerEntry.SetRange("Account Subcategory", Code); + if not SustainabilityLedgerEntry.IsEmpty() then + SustainabilityLedgerEntry.ModifyAll("Account Subcategory", ''); end; trigger OnInsert() diff --git a/Apps/W1/Sustainability/app/src/Account/SustainCategoryFactBox.Page.al b/Apps/W1/Sustainability/app/src/Account/SustainCategoryFactBox.Page.al index f927fe4f0c..e17c1bf3fd 100644 --- a/Apps/W1/Sustainability/app/src/Account/SustainCategoryFactBox.Page.al +++ b/Apps/W1/Sustainability/app/src/Account/SustainCategoryFactBox.Page.al @@ -19,11 +19,11 @@ page 6222 "Sustain. Category FactBox" } field("Emission Scope"; Rec."Emission Scope") { - ToolTip = 'Specifies the type of the scope of the record.'; + ToolTip = 'Specifies the scope of the emissions that are associated with the sustainability category. Scope 1: Direct emissions from sources that are owned or controlled by the reporting entity. Scope 2: Indirect emissions from the generation of purchased electricity, heat, or steam consumed by the reporting entity. Scope 3: Other indirect emissions, such as the extraction and production of purchased materials and fuels, transport-related activities in vehicles not owned or controlled by the reporting entity, and waste disposal.'; } field("Calculation Foundation"; Rec."Calculation Foundation") { - ToolTip = 'Specifies the foundation for emission calculation.'; + ToolTip = 'Specifies the calculation foundation for the sustainability category.'; } field(CO2; Rec.CO2) { diff --git a/Apps/W1/Sustainability/app/src/Account/SustainSubcategoryFactBox.Page.al b/Apps/W1/Sustainability/app/src/Account/SustainSubcategoryFactBox.Page.al index 4f340a4067..fa5f5591e0 100644 --- a/Apps/W1/Sustainability/app/src/Account/SustainSubcategoryFactBox.Page.al +++ b/Apps/W1/Sustainability/app/src/Account/SustainSubcategoryFactBox.Page.al @@ -13,23 +13,23 @@ page 6223 "Sustain. Subcategory FactBox" field(Code; Rec.Code) { Caption = 'Subcategory'; - ToolTip = 'Specifies a subcategory code.'; + ToolTip = 'Specifies the subcategory code.'; } field("Emission Factor CO2"; Rec."Emission Factor CO2") { - ToolTip = 'Specifies an emission factor for CO2 emission.'; + ToolTip = 'Specifies the emission factor for CO2 emission.'; } field("Emission Factor CH4"; Rec."Emission Factor CH4") { - ToolTip = 'Specifies an emission factor for CH4 emission.'; + ToolTip = 'Specifies the emission factor for CH4 emission.'; } field("Emission Factor N2O"; Rec."Emission Factor N2O") { - ToolTip = 'Specifies an emission factor for N2O emission.'; + ToolTip = 'Specifies the emission factor for N2O emission.'; } field("Renewable Energy"; Rec."Renewable Energy") { - ToolTip = 'Specifies if a subcategory is a part of renewable energy.'; + ToolTip = 'Specifies if the subcategory is a part of renewable energy.'; } } } diff --git a/Apps/W1/Sustainability/app/src/Account/SustainabilityAccount.Table.al b/Apps/W1/Sustainability/app/src/Account/SustainabilityAccount.Table.al index a36f7c44e6..c20750e868 100644 --- a/Apps/W1/Sustainability/app/src/Account/SustainabilityAccount.Table.al +++ b/Apps/W1/Sustainability/app/src/Account/SustainabilityAccount.Table.al @@ -4,7 +4,6 @@ using Microsoft.Finance.Dimension; using Microsoft.Inventory.Location; using Microsoft.Foundation.Comment; using Microsoft.Sustainability.Ledger; -using Microsoft.Sustainability.Setup; using Microsoft.Sustainability.Journal; table 6210 "Sustainability Account" @@ -359,18 +358,11 @@ table 6210 "Sustainability Account" trigger OnDelete() var - CommentLine: Record "Comment Line"; - SustainabilitySetup: Record "Sustainability Setup"; - DimMgt: Codeunit DimensionManagement; + SustainabilityLedgerEntry: Record "Sustainability Ledger Entry"; begin - SustainabilitySetup.Get(); - SustainabilitySetup.TestField("Block Sustain. Accs. Deletion", false); - - CommentLine.SetRange("Table Name", CommentLine."Table Name"::"Sustainability Account"); - CommentLine.SetRange("No.", "No."); - CommentLine.DeleteAll(); - - DimMgt.DeleteDefaultDim(Database::"Sustainability Account", "No."); + SustainabilityLedgerEntry.SetRange("Account No.", "No."); + if not SustainabilityLedgerEntry.IsEmpty() then + Error(LedgerEntryExistsErr, "No."); end; trigger OnInsert() diff --git a/Apps/W1/Sustainability/app/src/Account/SustainabilityAccountCard.Page.al b/Apps/W1/Sustainability/app/src/Account/SustainabilityAccountCard.Page.al index 6ccaa84aba..0ed721473d 100644 --- a/Apps/W1/Sustainability/app/src/Account/SustainabilityAccountCard.Page.al +++ b/Apps/W1/Sustainability/app/src/Account/SustainabilityAccountCard.Page.al @@ -23,11 +23,11 @@ page 6211 "Sustainability Account Card" field("No."; Rec."No.") { Importance = Promoted; - ToolTip = 'Specifies the sustainability account number in the chart of sustainability accounts.'; + ToolTip = 'Specifies the account number of the sustainability account.'; } field("No. 2"; Rec."No. 2") { - ToolTip = 'Specifies an alternative account number which can be used internally in the company.'; + ToolTip = 'Specifies the additional account number of the sustainability account.'; Visible = false; } field(Name; Rec.Name) @@ -63,12 +63,12 @@ page 6211 "Sustainability Account Card" } field(Blocked; Rec.Blocked) { - ToolTip = 'Specifies that the related record is blocked from being posted in transactions, for example a customer that is declared insolvent or an item that is placed in quarantine.'; + ToolTip = 'Specifies if the account is blocked. If the field is selected, then the account is blocked and you cannot post to it.'; Visible = false; } field("Direct Posting"; Rec."Direct Posting") { - ToolTip = 'Specifies if you can post directly to this general ledger account. If the field is not selected, then users must use sales documents, for example, and not post directly to the general ledger.'; + ToolTip = 'Specifies whether you will be able to post directly or only indirectly to this sustainability account. To allow Direct Posting to the sustainability account, place a check mark in the check box.'; } } group(Balances) diff --git a/Apps/W1/Sustainability/app/src/Calculation/CollectAmountFromGLEntry.Page.al b/Apps/W1/Sustainability/app/src/Calculation/CollectAmountFromGLEntry.Page.al index f0569cef85..82e6dca409 100644 --- a/Apps/W1/Sustainability/app/src/Calculation/CollectAmountFromGLEntry.Page.al +++ b/Apps/W1/Sustainability/app/src/Calculation/CollectAmountFromGLEntry.Page.al @@ -23,22 +23,22 @@ page 6224 "Collect Amount from G/L Entry" field("G/L Account Filter"; Rec."G/L Account Filter") { Editable = false; - ToolTip = 'Specifies a general ledger account number filter.'; + ToolTip = 'Specifies the general ledger account number filter.'; } field("Global Dimension 1 Filter"; Rec."Global Dimension 1 Filter") { Editable = false; - ToolTip = 'Specifies a global dimension 1 filter.'; + ToolTip = 'Specifies the global dimension 1 filter.'; } field("Global Dimension 2 Filter"; Rec."Global Dimension 2 Filter") { Editable = false; - ToolTip = 'Specifies a global dimension 2 filter.'; + ToolTip = 'Specifies the global dimension 2 filter.'; } field(FromDate; FromDate) { Caption = 'From Date'; - ToolTip = 'Specifies a from date.'; + ToolTip = 'Specifies from date.'; trigger OnValidate() begin @@ -48,7 +48,7 @@ page 6224 "Collect Amount from G/L Entry" field(ToDate; ToDate) { Caption = 'To Date'; - ToolTip = 'Specifies a to date.'; + ToolTip = 'Specifies to date.'; trigger OnValidate() begin @@ -71,7 +71,7 @@ page 6224 "Collect Amount from G/L Entry" Caption = 'Total Amount'; Editable = false; DrillDown = true; - ToolTip = 'Specifies a total calculated amount to be added to sustainability journal line.'; + ToolTip = 'Specifies the total amount of the collectable general ledger entries.'; trigger OnDrillDown() var diff --git a/Apps/W1/Sustainability/app/src/Calculation/GLAccountsSubform.Page.al b/Apps/W1/Sustainability/app/src/Calculation/GLAccountsSubform.Page.al index 46c98d54b5..3e39d8407e 100644 --- a/Apps/W1/Sustainability/app/src/Calculation/GLAccountsSubform.Page.al +++ b/Apps/W1/Sustainability/app/src/Calculation/GLAccountsSubform.Page.al @@ -23,7 +23,7 @@ page 6225 "G/L Accounts Subform" ApplicationArea = Basic, Suite; Style = Strong; StyleExpr = Rec."Account Type" <> Rec."Account Type"::Posting; - ToolTip = 'Specifies the number of the involved entry or record, according to the specified number series.'; + ToolTip = 'Specifies the number of the general ledger account.'; } field(Name; Rec.Name) { diff --git a/Apps/W1/Sustainability/app/src/Calculation/SustainabilityCalcMgt.Codeunit.al b/Apps/W1/Sustainability/app/src/Calculation/SustainabilityCalcMgt.Codeunit.al index 19d5086062..8ccb8be89f 100644 --- a/Apps/W1/Sustainability/app/src/Calculation/SustainabilityCalcMgt.Codeunit.al +++ b/Apps/W1/Sustainability/app/src/Calculation/SustainabilityCalcMgt.Codeunit.al @@ -6,23 +6,27 @@ using Microsoft.Finance.GeneralLedger.Ledger; codeunit 6218 "Sustainability Calc. Mgt." { - Access = Internal; - var FromToFilterLbl: Label '%1..%2', Locked = true; - procedure CalculationEmissions(var SustainabilityJnlLine: Record "Sustainability Jnl. Line") + internal procedure CalculationEmissions(var SustainabilityJnlLine: Record "Sustainability Jnl. Line") var SustainAccountCategory: Record "Sustain. Account Category"; SustainAccountSubcategory: Record "Sustain. Account Subcategory"; + IsHandled: Boolean; begin + OnBeforeCalculationEmissions(IsHandled, SustainabilityJnlLine); + + if IsHandled then + exit; + SustainAccountCategory.Get(SustainabilityJnlLine."Account Category"); SustainAccountSubcategory.Get(SustainabilityJnlLine."Account Category", SustainabilityJnlLine."Account Subcategory"); CalculationEmissions(SustainabilityJnlLine, SustainAccountCategory, SustainAccountSubcategory); end; - procedure CalculationEmissions(var SustainabilityJnlLine: Record "Sustainability Jnl. Line"; SustainAccountCategory: Record "Sustain. Account Category"; SustainAccountSubcategory: Record "Sustain. Account Subcategory") + internal procedure CalculationEmissions(var SustainabilityJnlLine: Record "Sustainability Jnl. Line"; SustainAccountCategory: Record "Sustain. Account Category"; SustainAccountSubcategory: Record "Sustain. Account Subcategory") var SustainabilityCalculation: Codeunit "Sustainability Calculation"; begin @@ -97,4 +101,9 @@ codeunit 6218 "Sustainability Calc. Mgt." if (FromDate <> 0D) or (ToDate <> 0D) then GLEntry.SetFilter("Posting Date", StrSubstNo(FromToFilterLbl, FromDate, ToDate)); end; + + [IntegrationEvent(false, false)] + local procedure OnBeforeCalculationEmissions(var IsHandled: Boolean; var SustainabilityJnlLine: Record "Sustainability Jnl. Line") + begin + end; } \ No newline at end of file diff --git a/Apps/W1/Sustainability/app/src/Journal/SustainJnlErrorsFactbox.Page.al b/Apps/W1/Sustainability/app/src/Journal/SustainJnlErrorsFactbox.Page.al new file mode 100644 index 0000000000..ad3ba9648a --- /dev/null +++ b/Apps/W1/Sustainability/app/src/Journal/SustainJnlErrorsFactbox.Page.al @@ -0,0 +1,220 @@ +namespace Microsoft.Sustainability.Journal; + +using System.Utilities; +using Microsoft.Utilities; +using Microsoft.Sustainability.Posting; + +page 6226 "Sustain. Jnl. Errors Factbox" +{ + PageType = ListPart; + Caption = 'Journal Check'; + Editable = false; + LinksAllowed = false; + SourceTable = "Sustainability Jnl. Line"; + + layout + { + area(content) + { + cuegroup(Control1) + { + ShowCaption = false; + field(NumberOfLinesChecked; NumberOfLines) + { + ApplicationArea = Basic, Suite; + Caption = 'Lines checked'; + ToolTip = 'Specifies the number of journal lines that have been checked for potential issues.'; + } + field(NumberOfLinesWithErrors; NumberOfLinesWithErrors) + { + ApplicationArea = Basic, Suite; + Caption = 'Lines with issues'; + ToolTip = 'Specifies the number of journal lines that have issues.'; + } + field(NumberOfBatchErrors; NumberOfBatchErrors) + { + ApplicationArea = Basic, Suite; + Caption = 'Issues Total'; + ToolTip = 'Specifies the number of issues that have been found in the journal.'; + StyleExpr = TotalErrorsStyleTxt; + + trigger OnDrillDown() + begin + TempErrorMessage.Reset(); + TempErrorMessage.SetRange(Duplicate, false); + Page.Run(Page::"Error Messages", TempErrorMessage); + end; + } + } + field(Refresh; RefreshTxt) + { + ApplicationArea = Basic, Suite; + ShowCaption = false; + trigger OnDrillDown() + begin + if SustainJnlErrorsMgt.BackgroundCheckEnabled() then begin + SustainJnlErrorsMgt.SetFullBatchCheck(true); + CheckErrorsInBackground(); + end; + end; + } + group(Control2) + { + Caption = 'Current line'; + field(Error1; ErrText[1]) + { + ShowCaption = false; + ApplicationArea = Basic, Suite; + StyleExpr = CurrentLineStyleTxt; + } + field(Error2; ErrText[2]) + { + ShowCaption = false; + ApplicationArea = Basic, Suite; + StyleExpr = CurrentLineStyleTxt; + } + } + } + } + + trigger OnOpenPage() + begin + if SustainJnlErrorsMgt.BackgroundCheckEnabled() then begin + SustainJnlErrorsMgt.SetFullBatchCheck(true); + CheckErrorsInBackground(); + end; + end; + + trigger OnAfterGetCurrRecord() + begin + if SustainJnlErrorsMgt.BackgroundCheckEnabled() then + CheckErrorsInBackground(); + end; + + trigger OnPageBackgroundTaskCompleted(TaskId: Integer; Results: Dictionary of [Text, Text]) + begin + if TaskId = TaskIdCountErrors then begin + SustainJnlErrorsMgt.GetErrorsFromSustJnlCheckResultValues(Results.Values, TempErrorMessage, ErrorHandlingParameters); + CalcErrors(); + NumberOfLines := GetNumberOfLines(); + end; + end; + + trigger OnPageBackgroundTaskError(TaskId: Integer; ErrorCode: Text; ErrorText: Text; ErrorCallStack: Text; var IsHandled: Boolean) + begin + if TaskId = TaskIdCountErrors then + IsHandled := true; + end; + + var + TempErrorMessage: Record "Error Message" temporary; + ErrorHandlingParameters: Record "Error Handling Parameters"; + SustainJnlErrorsMgt: Codeunit "Sustain. Jnl. Errors Mgt."; + TaskIdCountErrors, NumberOfBatchErrors, NumberOfLineErrors, NumberOfLines, NumberOfLinesWithErrors : Integer; + TotalErrorsStyleTxt, CurrentLineStyleTxt : Text; + ErrText: array[2] of Text; + OtherIssuesTxt: Label '(+%1 other issues)', comment = '%1 - number of issues'; + NoIssuesFoundTxt: Label 'No issues found.'; + RefreshTxt: Label 'Refresh'; + + local procedure GetTotalErrorsStyle(): Text + begin + if NumberOfBatchErrors = 0 then + exit('Favorable') + else + exit('Unfavorable'); + end; + + local procedure GetCurrentLineStyle(): Text + begin + if NumberOfLineErrors = 0 then + exit('Standard') + else + exit('Attention'); + end; + + local procedure GetNumberOfLines(): Integer + var + SustainabilityJnlLine: Record "Sustainability Jnl. Line"; + begin + SustainabilityJnlLine.SetRange("Journal Template Name", Rec."Journal Template Name"); + SustainabilityJnlLine.SetRange("Journal Batch Name", Rec."Journal Batch Name"); + exit(SustainabilityJnlLine.Count()); + end; + + local procedure CheckErrorsInBackground() + var + TempSustainabilityJnlLine: Record "Sustainability Jnl. Line" temporary; + Args: Dictionary of [Text, Text]; + begin + if TaskIdCountErrors <> 0 then + CurrPage.CancelBackgroundTask(TaskIdCountErrors); + + SustainJnlErrorsMgt.CollectSustJnlCheckParameters(Rec, ErrorHandlingParameters); + ErrorHandlingParameters.ToArgs(Args); + + if SustainJnlErrorsMgt.GetDeletedSustJnlLine(TempSustainabilityJnlLine, false) then begin + TempSustainabilityJnlLine.FindSet(); + repeat + Args.Add(Format(TempSustainabilityJnlLine."Line No."), DeletedDocumentToJson(TempSustainabilityJnlLine)); + until TempSustainabilityJnlLine.Next() = 0; + end; + + CurrPage.EnqueueBackgroundTask(TaskIdCountErrors, Codeunit::"Check Sust. Jnl. Line. Backgr.", Args); + end; + + local procedure CalcErrors() + var + NumberOfErrors: Integer; + begin + TempErrorMessage.Reset(); + TempErrorMessage.SetRange(Duplicate, false); + NumberOfBatchErrors := TempErrorMessage.Count(); + TempErrorMessage.SetRange(Duplicate); + TempErrorMessage.SetRange("Context Record ID", Rec.RecordId); + NumberOfLineErrors := TempErrorMessage.Count(); + + Clear(ErrText); + NumberOfErrors := TempErrorMessage.Count(); + if TempErrorMessage.FindFirst() then + ErrText[1] := TempErrorMessage."Message" + else + ErrText[1] := NoIssuesFoundTxt; + + if NumberOfErrors > 2 then + ErrText[2] := StrSubstNo(OtherIssuesTxt, NumberOfErrors - 1) + else + if TempErrorMessage.Next() <> 0 then + ErrText[2] := TempErrorMessage."Message"; + + TotalErrorsStyleTxt := GetTotalErrorsStyle(); + CurrentLineStyleTxt := GetCurrentLineStyle(); + NumberOfLinesWithErrors := GetNumberOfLinesWithErrors(); + end; + + local procedure GetNumberOfLinesWithErrors(): Integer + var + TempLineErrorMessage: Record "Error Message" temporary; + begin + TempErrorMessage.Reset(); + if TempErrorMessage.FindSet() then + repeat + TempLineErrorMessage.SetRange("Context Record ID", TempErrorMessage."Context Record ID"); + if TempLineErrorMessage.IsEmpty() then begin + TempLineErrorMessage := TempErrorMessage; + TempLineErrorMessage.Insert(); + end; + until TempErrorMessage.Next() = 0; + + TempLineErrorMessage.Reset(); + exit(TempLineErrorMessage.Count()); + end; + + local procedure DeletedDocumentToJson(TempSustainabilityJnlLine: Record "Sustainability Jnl. Line" temporary) JSON: Text + var + JObject: JsonObject; + begin + JObject.Add(TempSustainabilityJnlLine.FieldName("Line No."), TempSustainabilityJnlLine."Line No."); + JObject.WriteTo(JSON); + end; +} \ No newline at end of file diff --git a/Apps/W1/Sustainability/app/src/Journal/SustainJnlErrorsMgt.Codeunit.al b/Apps/W1/Sustainability/app/src/Journal/SustainJnlErrorsMgt.Codeunit.al new file mode 100644 index 0000000000..2c12000e9c --- /dev/null +++ b/Apps/W1/Sustainability/app/src/Journal/SustainJnlErrorsMgt.Codeunit.al @@ -0,0 +1,153 @@ +namespace Microsoft.Sustainability.Journal; + +using Microsoft.Utilities; +using System.Utilities; +using Microsoft.Sustainability.Setup; + +codeunit 6220 "Sustain. Jnl. Errors Mgt." +{ + Access = Internal; + SingleInstance = true; + + var + SustainabilitySetup: Record "Sustainability Setup"; + TempDeletedSustJnlLine, TempSustJnlLineBeforeModify, TempSustJnlLineAfterModify : Record "Sustainability Jnl. Line" temporary; + FullBatchCheck, SustainabilitySetupRetrieved : Boolean; + + procedure CollectSustJnlCheckParameters(SustainabilityJnlLine: Record "Sustainability Jnl. Line"; var ErrorHandlingParameters: Record "Error Handling Parameters") + var + TempSustJnlLine, TempxSustJnlLine : Record "Sustainability Jnl. Line" temporary; + begin + ErrorHandlingParameters."Journal Template Name" := SustainabilityJnlLine."Journal Template Name"; + ErrorHandlingParameters."Journal Batch Name" := SustainabilityJnlLine."Journal Batch Name"; + ErrorHandlingParameters."Full Batch Check" := GetFullBatchCheck(); + ErrorHandlingParameters."Line Modified" := GetRecXRecOnModify(TempxSustJnlLine, TempSustJnlLine); + ErrorHandlingParameters."Line No." := TempSustJnlLine."Line No."; + end; + + procedure GetErrorsFromSustJnlCheckResultValues(ResultValues: List of [Text]; var TempErrorMsg: Record "Error Message" temporary; ErrorHandlingParameters: Record "Error Handling Parameters") + var + SustainabilityJnlLine: Record "Sustainability Jnl. Line"; + TempSustainabilityJnlLine: Record "Sustainability Jnl. Line" temporary; + ErrorMessageMgt: Codeunit "Error Message Management"; + begin + TempErrorMsg.Reset(); + if ErrorHandlingParameters."Full Batch Check" then + TempErrorMsg.DeleteAll() + else begin + if GetDeletedSustJnlLine(TempSustainabilityJnlLine, true) then + if TempSustainabilityJnlLine.FindSet() then + repeat + TempErrorMsg.SetRange("Context Record ID", TempSustainabilityJnlLine.RecordId); + TempErrorMsg.DeleteAll(); + until TempSustainabilityJnlLine.Next() = 0; + + TempErrorMsg.Reset(); + if ErrorHandlingParameters."Line Modified" then + if SustainabilityJnlLine.Get(ErrorHandlingParameters."Journal Template Name", ErrorHandlingParameters."Journal Batch Name", ErrorHandlingParameters."Line No.") then begin + TempErrorMsg.SetRange("Context Record ID", SustainabilityJnlLine.RecordId()); + TempErrorMsg.DeleteAll(); + end; + end; + + ErrorMessageMgt.GetErrorsFromResultValues(ResultValues, TempErrorMsg); + + if ErrorHandlingParameters."Full Batch Check" then + SetFullBatchCheck(false); + end; + + procedure SetRecXRecOnModify(xRec: Record "Sustainability Jnl. Line"; Rec: Record "Sustainability Jnl. Line") + begin + if BackgroundCheckEnabled() then begin + SaveJournalLineToBuffer(xRec, TempSustJnlLineBeforeModify); + SaveJournalLineToBuffer(Rec, TempSustJnlLineAfterModify); + end; + end; + + local procedure SaveJournalLineToBuffer(SustainabilityJournalLine: Record "Sustainability Jnl. Line"; var BufferLine: Record "Sustainability Jnl. Line" temporary) + begin + if BufferLine.Get(SustainabilityJournalLine."Journal Template Name", SustainabilityJournalLine."Journal Batch Name", SustainabilityJournalLine."Line No.") then begin + BufferLine.TransferFields(SustainabilityJournalLine); + BufferLine.Modify(); + end else begin + BufferLine := SustainabilityJournalLine; + BufferLine.Insert(); + end; + end; + + procedure GetRecXRecOnModify(var xRec: Record "Sustainability Jnl. Line"; var Rec: Record "Sustainability Jnl. Line"): Boolean + begin + if TempSustJnlLineAfterModify.FindFirst() then begin + xRec := TempSustJnlLineBeforeModify; + Rec := TempSustJnlLineAfterModify; + + if TempSustJnlLineBeforeModify.Delete() then; + if TempSustJnlLineAfterModify.Delete() then; + exit(true); + end; + + exit(false); + end; + + procedure SetFullBatchCheck(NewFullBatchCheck: Boolean) + begin + FullBatchCheck := NewFullBatchCheck; + end; + + procedure GetFullBatchCheck(): Boolean + begin + exit(FullBatchCheck); + end; + + procedure GetDeletedSustJnlLine(var TempSustJnlLine: Record "Sustainability Jnl. Line" temporary; ClearBuffer: Boolean): Boolean + begin + if TempDeletedSustJnlLine.FindSet() then begin + repeat + TempSustJnlLine := TempDeletedSustJnlLine; + TempSustJnlLine.Insert(); + until TempDeletedSustJnlLine.Next() = 0; + + if ClearBuffer then + TempDeletedSustJnlLine.DeleteAll(); + exit(true); + end; + + exit(false); + end; + + procedure InsertDeletedLine(SustJnlLine: Record "Sustainability Jnl. Line") + begin + if BackgroundCheckEnabled() then begin + TempDeletedSustJnlLine := SustJnlLine; + if TempDeletedSustJnlLine.Insert() then; + end; + end; + + procedure BackgroundCheckEnabled(): Boolean + begin + if not SustainabilitySetupRetrieved then begin + SustainabilitySetup.Get(); + SustainabilitySetupRetrieved := true; + end; + + exit(SustainabilitySetup."Enable Background Error Check"); + end; + + [EventSubscriber(ObjectType::Page, Page::"Sustainability Journal", 'OnDeleteRecordEvent', '', false, false)] + local procedure OnDeleteRecordEventSustainabilityJournal(var Rec: Record "Sustainability Jnl. Line"; var AllowDelete: Boolean) + begin + InsertDeletedLine(Rec); + end; + + [EventSubscriber(ObjectType::Page, Page::"Sustainability Journal", 'OnModifyRecordEvent', '', false, false)] + local procedure OnModifyRecordEventSustainabilityJournal(var Rec: Record "Sustainability Jnl. Line"; var xRec: Record "Sustainability Jnl. Line"; var AllowModify: Boolean) + begin + SetRecXRecOnModify(xRec, Rec); + end; + + [EventSubscriber(ObjectType::Page, Page::"Sustainability Journal", 'OnInsertRecordEvent', '', false, false)] + local procedure OnInsertRecordEventSustainabilityJournal(var Rec: Record "Sustainability Jnl. Line"; var xRec: Record "Sustainability Jnl. Line"; var AllowInsert: Boolean) + begin + SetRecXRecOnModify(xRec, Rec); + end; +} \ No newline at end of file diff --git a/Apps/W1/Sustainability/app/src/Journal/SustainJnlRecurMethod.Enum.al b/Apps/W1/Sustainability/app/src/Journal/SustainJnlRecurMethod.Enum.al index 95e58c6827..bee23294bb 100644 --- a/Apps/W1/Sustainability/app/src/Journal/SustainJnlRecurMethod.Enum.al +++ b/Apps/W1/Sustainability/app/src/Journal/SustainJnlRecurMethod.Enum.al @@ -1,3 +1,5 @@ +namespace Microsoft.Sustainability.Journal; + enum 6214 "Sustain. Jnl. Recur. Method" { Access = Public; diff --git a/Apps/W1/Sustainability/app/src/Journal/SustainabilityJnlLine.Table.al b/Apps/W1/Sustainability/app/src/Journal/SustainabilityJnlLine.Table.al index 82d9ccd41d..6573e215b2 100644 --- a/Apps/W1/Sustainability/app/src/Journal/SustainabilityJnlLine.Table.al +++ b/Apps/W1/Sustainability/app/src/Journal/SustainabilityJnlLine.Table.al @@ -116,6 +116,12 @@ table 6214 "Sustainability Jnl. Line" var SustainabilityCalcMgt: Codeunit "Sustainability Calc. Mgt."; begin + Validate(Distance, 0); + Validate("Fuel/Electricity", 0); + Validate("Custom Amount", 0); + Validate("Installation Multiplier", 1); + Validate("Time Factor", 0); + SustainabilityCalcMgt.CalculationEmissions(Rec); end; } @@ -317,9 +323,10 @@ table 6214 "Sustainability Jnl. Line" SustainabilityJnlLine.SetRange("Journal Batch Name", "Journal Batch Name"); IsPreviousLineValid := not SustainabilityJnlLine.IsEmpty(); - if IsPreviousLineValid then - Validate("Posting Date", PreviousLine."Posting Date") - else + if IsPreviousLineValid then begin + Validate("Posting Date", PreviousLine."Posting Date"); + Validate("Document Type", PreviousLine."Document Type"); + end else Validate("Posting Date", WorkDate()); Validate("Reason Code", SustainabilityJnlBatch."Reason Code"); diff --git a/Apps/W1/Sustainability/app/src/Journal/SustainabilityJournal.Page.al b/Apps/W1/Sustainability/app/src/Journal/SustainabilityJournal.Page.al index 20590cbc31..041c7bf131 100644 --- a/Apps/W1/Sustainability/app/src/Journal/SustainabilityJournal.Page.al +++ b/Apps/W1/Sustainability/app/src/Journal/SustainabilityJournal.Page.al @@ -5,7 +5,6 @@ using Microsoft.Sustainability.Ledger; using Microsoft.Sustainability.Account; using Microsoft.Sustainability.Calculation; using Microsoft.Finance.Dimension; -using System.Utilities; page 6219 "Sustainability Journal" { @@ -103,7 +102,7 @@ page 6219 "Sustainability Journal" } field("Sustainability Account No."; Rec."Account No.") { - ToolTip = 'Specifies the sustainability account.'; + ToolTip = 'Specifies the sustainability account number.'; ShowMandatory = true; trigger OnValidate() @@ -111,6 +110,7 @@ page 6219 "Sustainability Journal" DimMgt: Codeunit DimensionManagement; begin DimMgt.GetShortcutDimensions(Rec."Dimension Set ID", ShortcutDimCode); + CurrPage.Update(); end; } field("Sustainability Account Name"; Rec."Account Name") @@ -139,45 +139,100 @@ page 6219 "Sustainability Journal" { ToolTip = 'Specifies the unit of measure of the journal line.'; ShowMandatory = true; + trigger OnValidate() + begin + CurrPage.Update(); + end; } field("Fuel/Electricity"; Rec."Fuel/Electricity") { + Editable = not Rec."Manual Input"; ToolTip = 'Specifies the fuel or electricity of the journal line.'; + trigger OnValidate() + begin + CurrPage.Update(); + end; } field(Distance; Rec.Distance) { + Editable = not Rec."Manual Input"; ToolTip = 'Specifies the distance of the journal line.'; + trigger OnValidate() + begin + CurrPage.Update(); + end; } field("Custom Amount"; Rec."Custom Amount") { + Editable = not Rec."Manual Input"; ToolTip = 'Specifies the custom amount of the journal line.'; + trigger OnValidate() + begin + CurrPage.Update(); + end; } field("Installation Multiplier"; Rec."Installation Multiplier") { + Editable = not Rec."Manual Input"; ToolTip = 'Specifies the installation multiplier of the journal line.'; } field("Time Factor"; Rec."Time Factor") { + Editable = not Rec."Manual Input"; ToolTip = 'Specifies the time factor of the journal line.'; } field("Emission CO2"; Rec."Emission CO2") { - ToolTip = 'Specifies the emission CO2 of the journal line.'; Editable = Rec."Manual Input"; + ToolTip = 'Specifies the emission CO2 of the journal line.'; + trigger OnValidate() + begin + CurrPage.Update(); + end; } field("Emission CH4"; Rec."Emission CH4") { - ToolTip = 'Specifies the emission CH4 of the journal line.'; Editable = Rec."Manual Input"; + ToolTip = 'Specifies the emission CH4 of the journal line.'; + trigger OnValidate() + begin + CurrPage.Update(); + end; } field("Emission N2O"; Rec."Emission N2O") { - ToolTip = 'Specifies the emission N2O of the journal line.'; Editable = Rec."Manual Input"; + ToolTip = 'Specifies the emission N2O of the journal line.'; + trigger OnValidate() + begin + CurrPage.Update(); + end; } field("Country/Region Code"; Rec."Country/Region Code") { ToolTip = 'Specifies the country/region code of the journal line.'; + trigger OnValidate() + begin + CurrPage.Update(); + end; + } + field("Responsibility Center"; Rec."Responsibility Center") + { + ToolTip = 'Specifies the responsibility center of the journal line.'; + trigger OnValidate() + begin + CurrPage.Update(); + end; + } + field("Source Code"; Rec."Source Code") + { + ToolTip = 'Specifies the source code of the journal line.'; + Visible = false; + } + field("Reason Code"; Rec."Reason Code") + { + ToolTip = 'Specifies the reason code of the journal line.'; + Visible = false; } field("Shortcut Dimension 1 Code"; Rec."Shortcut Dimension 1 Code") { @@ -285,8 +340,12 @@ page 6219 "Sustainability Journal" } area(FactBoxes) { - part(ErrorMessagesPart; "Error Messages Part") + part(SustainJnlErrorsFactbox; "Sustain. Jnl. Errors Factbox") { + ShowFilter = false; + SubPageLink = "Journal Template Name" = field("Journal Template Name"), + "Journal Batch Name" = field("Journal Batch Name"), + "Line No." = field("Line No."); } part(CategoryFactBox; "Sustain. Category FactBox") { @@ -376,22 +435,6 @@ page 6219 "Sustainability Journal" Codeunit.Run(Codeunit::"Sustainability Jnl.-Post", Rec); end; } - action(CheckLines) - { - Image = CheckJournal; - ToolTip = 'Check all journal lines for errors.'; - - trigger OnAction() - var - TempErrorMessages: Record "Error Message" temporary; - SustainabilityJnlCheck: Codeunit "Sustainability Jnl.-Check"; - begin - SustainabilityJnlCheck.CheckAllJournalLinesWithErrorCollect(Rec, TempErrorMessages); - - if not TempErrorMessages.IsEmpty() then - Page.RunModal(Page::"Error Messages", TempErrorMessages); - end; - } action(Recalculate) { Caption = 'Recalculate'; @@ -415,7 +458,6 @@ page 6219 "Sustainability Journal" group(Category_Process) { actionref(Post_Promoted; Post) { } - actionref(CheckLines_Promoted; CheckLines) { } } group(Category_Category10) { @@ -447,17 +489,6 @@ page 6219 "Sustainability Journal" DimMgt.GetShortcutDimensions(Rec."Dimension Set ID", ShortcutDimCode); end; - trigger OnAfterGetCurrRecord() - var - TempErrorMessages: Record "Error Message" temporary; - SustainabilityJnlCheck: Codeunit "Sustainability Jnl.-Check"; - begin - SustainabilityJnlCheck.CheckSustainabilityJournalLineWithErrorCollect(Rec, TempErrorMessages); - - CurrPage.ErrorMessagesPart.Page.SetRecords(TempErrorMessages); - CurrPage.ErrorMessagesPart.Page.Update(false); - end; - trigger OnInit() begin SetDimensionVisibility(); @@ -465,10 +496,12 @@ page 6219 "Sustainability Journal" trigger OnOpenPage() var + SustainabilityJnlTemplate: Record "Sustainability Jnl. Template"; SustainabilityJnlBatch: Record "Sustainability Jnl. Batch"; SustainabilityJournalMgt: Codeunit "Sustainability Journal Mgt."; begin - SustainabilityJnlBatch := SustainabilityJournalMgt.GetASustainabilityJournalBatch(IsRecurringView); + SustainabilityJnlTemplate := SustainabilityJournalMgt.SelectTemplate(IsRecurringView); + SustainabilityJnlBatch := SustainabilityJournalMgt.SelectBatch(SustainabilityJnlTemplate, CurrentJournalBatchName); ResetFilterOnLinesWithNewBatch(SustainabilityJnlBatch); end; diff --git a/Apps/W1/Sustainability/app/src/Journal/SustainabilityJournalMgt.Codeunit.al b/Apps/W1/Sustainability/app/src/Journal/SustainabilityJournalMgt.Codeunit.al index ae7ea1d0b0..dc00c792bf 100644 --- a/Apps/W1/Sustainability/app/src/Journal/SustainabilityJournalMgt.Codeunit.al +++ b/Apps/W1/Sustainability/app/src/Journal/SustainabilityJournalMgt.Codeunit.al @@ -91,9 +91,17 @@ codeunit 6211 "Sustainability Journal Mgt." /// /// Specifies whether the template is recurring. procedure GetASustainabilityJournalBatch(IsRecurring: Boolean): Record "Sustainability Jnl. Batch" - var - SustainabilityJnlTemplate: Record "Sustainability Jnl. Template"; - SustainabilityJnlBatch: Record "Sustainability Jnl. Batch"; + begin + exit(SelectBatch(SelectTemplate(IsRecurring), '')); + end; + + /// + /// Select a Sustainability Journal Template. + /// If more than one Template exists, the user will be prompted to select one. + /// If no Template exists, a default one will be created. + /// + /// Specifies whether the template is recurring. + internal procedure SelectTemplate(IsRecurring: Boolean) SustainabilityJnlTemplate: Record "Sustainability Jnl. Template" begin SustainabilityJnlTemplate.SetRange(Recurring, IsRecurring); @@ -106,13 +114,15 @@ codeunit 6211 "Sustainability Journal Mgt." if not (Page.RunModal(Page::"Sustainability Jnl. Templates", SustainabilityJnlTemplate) = Action::LookupOK) then Error(''); end; + end; + internal procedure SelectBatch(SustainabilityJnlTemplate: Record "Sustainability Jnl. Template"; PreviousBatchName: Code[10]) SustainabilityJnlBatch: Record "Sustainability Jnl. Batch" + begin SustainabilityJnlBatch.SetRange("Journal Template Name", SustainabilityJnlTemplate.Name); - if not SustainabilityJnlBatch.FindFirst() then - SustainabilityJnlBatch := InitializeDefaultBatch(SustainabilityJnlTemplate.Name, IsRecurring); - - exit(SustainabilityJnlBatch); + if not SustainabilityJnlBatch.Get(SustainabilityJnlTemplate.Name, PreviousBatchName) then + if not SustainabilityJnlBatch.FindFirst() then + SustainabilityJnlBatch := InitializeDefaultBatch(SustainabilityJnlTemplate.Name, SustainabilityJnlTemplate.Recurring); end; /// diff --git a/Apps/W1/Sustainability/app/src/Ledger/SustainabilityLedgerEntries.Page.al b/Apps/W1/Sustainability/app/src/Ledger/SustainabilityLedgerEntries.Page.al index 2ae119bbf6..d59bfbace9 100644 --- a/Apps/W1/Sustainability/app/src/Ledger/SustainabilityLedgerEntries.Page.al +++ b/Apps/W1/Sustainability/app/src/Ledger/SustainabilityLedgerEntries.Page.al @@ -35,17 +35,13 @@ page 6220 "Sustainability Ledger Entries" Caption = 'Batch Name'; ToolTip = 'Specifies the name of the journal batch.'; } - field("Line No."; Rec."Line No.") - { - ToolTip = 'Specifies the line number of the journal line.'; - } field("Posting Date"; Rec."Posting Date") { ToolTip = 'Specifies the date when the transaction is posted.'; } field("Document Type"; Rec."Document Type") { - ToolTip = 'Specifies the document type.'; + ToolTip = 'Specifies the type of the document.'; } field("Document No."; Rec."Document No.") { @@ -73,7 +69,7 @@ page 6220 "Sustainability Ledger Entries" } field(Description; Rec.Description) { - ToolTip = 'Specifies the description of the journal line.'; + ToolTip = 'Specifies the description of the entry.'; } field("Manual Input"; Rec."Manual Input") { @@ -81,55 +77,59 @@ page 6220 "Sustainability Ledger Entries" } field("Unit of Measure"; Rec."Unit of Measure") { - ToolTip = 'Specifies the unit of measure of the journal line.'; + ToolTip = 'Specifies the unit of measure of the entry.'; } field("Fuel/Electricity"; Rec."Fuel/Electricity") { - ToolTip = 'Specifies the fuel or electricity of the journal line.'; + ToolTip = 'Specifies the fuel or electricity of the entry.'; } field(Distance; Rec.Distance) { - ToolTip = 'Specifies the distance of the journal line.'; + ToolTip = 'Specifies the distance of the entry.'; } field("Custom Amount"; Rec."Custom Amount") { - ToolTip = 'Specifies the custom amount of the journal line.'; + ToolTip = 'Specifies the custom amount of the entry.'; } field("Emission Factor CO2"; Rec."Emission Factor CO2") { - ToolTip = 'Specifies the emission factor CO2 of the journal line.'; + ToolTip = 'Specifies the emission factor CO2 of the entry.'; } field("Emission Factor CH4"; Rec."Emission Factor CH4") { - ToolTip = 'Specifies the emission factor CH4 of the journal line.'; + ToolTip = 'Specifies the emission factor CH4 of the entry.'; } field("Emission Factor N2O"; Rec."Emission Factor N2O") { - ToolTip = 'Specifies the emission factor N2O of the journal line.'; + ToolTip = 'Specifies the emission factor N2O of the entry.'; } field("Installation Multiplier"; Rec."Installation Multiplier") { - ToolTip = 'Specifies the installation multiplier of the journal line.'; + ToolTip = 'Specifies the installation multiplier of the entry.'; } field("Time Factor"; Rec."Time Factor") { - ToolTip = 'Specifies the time factor of the journal line.'; + ToolTip = 'Specifies the time factor of the entry.'; } field("Emission CO2"; Rec."Emission CO2") { - ToolTip = 'Specifies the emission CO2 of the journal line.'; + ToolTip = 'Specifies the emission CO2 of the entry.'; } field("Emission CH4"; Rec."Emission CH4") { - ToolTip = 'Specifies the emission CH4 of the journal line.'; + ToolTip = 'Specifies the emission CH4 of the entry.'; } field("Emission N2O"; Rec."Emission N2O") { - ToolTip = 'Specifies the emission N2O of the journal line.'; + ToolTip = 'Specifies the emission N2O of the entry.'; } field("Country/Region Code"; Rec."Country/Region Code") { - ToolTip = 'Specifies the country/region code of the journal line.'; + ToolTip = 'Specifies the country/region code of the entry.'; + } + field("Responsibility Center"; Rec."Responsibility Center") + { + ToolTip = 'Specifies the responsibility center of the entry.'; } field("Global Dimension 1 Code"; Rec."Global Dimension 1 Code") { diff --git a/Apps/W1/Sustainability/app/src/Ledger/SustainabilityLedgerEntry.Table.al b/Apps/W1/Sustainability/app/src/Ledger/SustainabilityLedgerEntry.Table.al index 8339eace59..18dc0248c0 100644 --- a/Apps/W1/Sustainability/app/src/Ledger/SustainabilityLedgerEntry.Table.al +++ b/Apps/W1/Sustainability/app/src/Ledger/SustainabilityLedgerEntry.Table.al @@ -49,7 +49,7 @@ table 6216 "Sustainability Ledger Entry" field(7; "Account No."; Code[20]) { Caption = 'Account No.'; - TableRelation = "Sustainability Account"; + TableRelation = "Sustainability Account" where("Account Type" = const(Posting)); } field(8; "Account Name"; Text[100]) { diff --git a/Apps/W1/Sustainability/app/src/Permissions/SustainabilityObjects.permissionset.al b/Apps/W1/Sustainability/app/src/Permissions/SustainabilityObjects.permissionset.al index 475eef4efd..8ed895ed23 100644 --- a/Apps/W1/Sustainability/app/src/Permissions/SustainabilityObjects.permissionset.al +++ b/Apps/W1/Sustainability/app/src/Permissions/SustainabilityObjects.permissionset.al @@ -39,6 +39,7 @@ permissionset 6210 "Sustainability - Objects" page "Recurring Sustainability Jnl." = X, page "Sustainability Ledger Entries" = X, page "Sustainability Setup" = X, + page "Sustain. Jnl. Errors Factbox" = X, codeunit "Sustainability Account Mgt." = X, codeunit "Sustainability Journal Mgt." = X, codeunit "Sustainability Jnl.-Post" = X, @@ -47,6 +48,8 @@ permissionset 6210 "Sustainability - Objects" codeunit "Sustainability Jnl.-Check" = X, codeunit "Sustainability Calculation" = X, codeunit "Sustainability Calc. Mgt." = X, + codeunit "Sustain. Jnl. Errors Mgt." = X, + codeunit "Check Sust. Jnl. Line. Backgr." = X, report "Emission By Category" = X, report "Emission Per Facility" = X, report "Total Emissions" = X; diff --git a/Apps/W1/Sustainability/app/src/Posting/CheckSustJnlLineBackgr.Codeunit.al b/Apps/W1/Sustainability/app/src/Posting/CheckSustJnlLineBackgr.Codeunit.al new file mode 100644 index 0000000000..279fb20128 --- /dev/null +++ b/Apps/W1/Sustainability/app/src/Posting/CheckSustJnlLineBackgr.Codeunit.al @@ -0,0 +1,47 @@ +namespace Microsoft.Sustainability.Posting; + +using Microsoft.Utilities; +using System.Utilities; +using Microsoft.Sustainability.Journal; + +codeunit 6221 "Check Sust. Jnl. Line. Backgr." +{ + Access = Internal; + trigger OnRun() + var + TempErrorMessage: Record "Error Message" temporary; + begin + RunCheck(Page.GetBackgroundParameters(), TempErrorMessage); + Page.SetBackgroundTaskResult(PackErrorMessagesToResults(TempErrorMessage)); + end; + + local procedure RunCheck(Args: Dictionary of [Text, Text]; var TempErrorMessage: Record "Error Message" temporary) + var + ErrorHandlingParameters: Record "Error Handling Parameters"; + SustainabilityJnlLine: Record "Sustainability Jnl. Line"; + SustainabilityJnlCheck: Codeunit "Sustainability Jnl.-Check"; + begin + ErrorHandlingParameters.FromArgs(Args); + + SustainabilityJnlLine.SetRange("Journal Template Name", ErrorHandlingParameters."Journal Template Name"); + SustainabilityJnlLine.SetRange("Journal Batch Name", ErrorHandlingParameters."Journal Batch Name"); + if ErrorHandlingParameters."Full Batch Check" then + SustainabilityJnlCheck.CheckAllJournalLinesWithErrorCollect(SustainabilityJnlLine, TempErrorMessage) + else + if ErrorHandlingParameters."Line Modified" then begin + SustainabilityJnlLine.SetRange("Line No.", ErrorHandlingParameters."Line No."); + if SustainabilityJnlLine.FindFirst() then + SustainabilityJnlCheck.CheckSustainabilityJournalLineWithErrorCollect(SustainabilityJnlLine, TempErrorMessage); + end; + end; + + local procedure PackErrorMessagesToResults(var TempErrorMessage: Record "Error Message" temporary) Results: Dictionary of [Text, Text] + var + ErrorMessageMgt: Codeunit "Error Message Management"; + begin + if TempErrorMessage.FindSet() then + repeat + Results.Add(Format(TempErrorMessage.ID), ErrorMessageMgt.ErrorMessage2JSON(TempErrorMessage)); + until TempErrorMessage.Next() = 0; + end; +} \ No newline at end of file diff --git a/Apps/W1/Sustainability/app/src/Posting/SustainabilityJnlCheck.Codeunit.al b/Apps/W1/Sustainability/app/src/Posting/SustainabilityJnlCheck.Codeunit.al index a0390bc7ce..3372023ffb 100644 --- a/Apps/W1/Sustainability/app/src/Posting/SustainabilityJnlCheck.Codeunit.al +++ b/Apps/W1/Sustainability/app/src/Posting/SustainabilityJnlCheck.Codeunit.al @@ -72,9 +72,6 @@ codeunit 6216 "Sustainability Jnl.-Check" var SustainabilityJnlCheck: Codeunit "Sustainability Jnl.-Check"; begin - if SustainabilityJnlLine."Line No." = 0 then - exit; - SustainabilityJnlCheck.CheckSustainabilityJournalLine(SustainabilityJnlLine); end; diff --git a/Apps/W1/Sustainability/app/src/Posting/SustainabilityJnlPost.Codeunit.al b/Apps/W1/Sustainability/app/src/Posting/SustainabilityJnlPost.Codeunit.al index 2dc7b3a080..ab19bc93fd 100644 --- a/Apps/W1/Sustainability/app/src/Posting/SustainabilityJnlPost.Codeunit.al +++ b/Apps/W1/Sustainability/app/src/Posting/SustainabilityJnlPost.Codeunit.al @@ -2,6 +2,7 @@ namespace Microsoft.Sustainability.Posting; using Microsoft.Sustainability.Journal; using Microsoft.Foundation.NoSeries; +using System.Utilities; codeunit 6213 "Sustainability Jnl.-Post" { @@ -9,9 +10,13 @@ codeunit 6213 "Sustainability Jnl.-Post" trigger OnRun() var + ConfirmManagement: Codeunit "Confirm Management"; SustainabilityPostMgt: Codeunit "Sustainability Post Mgt"; Window: Dialog; begin + if not ConfirmManagement.GetResponseOrDefault(SustainabilityPostMgt.GetPostConfirmMessage(), true) then + exit; + Rec.LockTable(); if GuiAllowed() then @@ -23,8 +28,12 @@ codeunit 6213 "Sustainability Jnl.-Post" Rec.DeleteAll(true); - if GuiAllowed() then + if GuiAllowed() then begin Window.Close(); + Message(SustainabilityPostMgt.GetJnlLinesPostedMessage()); + end; + + SustainabilityPostMgt.ResetFilters(Rec); end; local procedure CheckJournalLinesBeforePosting(var SustainabilityJnlLine: Record "Sustainability Jnl. Line"; var DialogInstance: Dialog) diff --git a/Apps/W1/Sustainability/app/src/Posting/SustainabilityPostMgt.Codeunit.al b/Apps/W1/Sustainability/app/src/Posting/SustainabilityPostMgt.Codeunit.al index ecb8fce4be..ca5bbc9b7a 100644 --- a/Apps/W1/Sustainability/app/src/Posting/SustainabilityPostMgt.Codeunit.al +++ b/Apps/W1/Sustainability/app/src/Posting/SustainabilityPostMgt.Codeunit.al @@ -29,6 +29,15 @@ codeunit 6212 "Sustainability Post Mgt" SustainabilityLedgerEntry.Insert(true); end; + procedure ResetFilters(var SustainabilityJnlLine: Record "Sustainability Jnl. Line") + begin + SustainabilityJnlLine.Reset(); + SustainabilityJnlLine.FilterGroup(2); + SustainabilityJnlLine.SetRange("Journal Template Name", SustainabilityJnlLine."Journal Template Name"); + SustainabilityJnlLine.SetRange("Journal Batch Name", SustainabilityJnlLine."Journal Batch Name"); + SustainabilityJnlLine.FilterGroup(0); + end; + internal procedure GetStartPostingProgressMessage(): Text begin exit(PostingSustainabilityJournalLbl); @@ -44,6 +53,16 @@ codeunit 6212 "Sustainability Post Mgt" exit(StrSubstNo(ProcessingLineLbl, LineNo)); end; + internal procedure GetJnlLinesPostedMessage(): Text + begin + exit(JnlLinesPostedLbl); + end; + + internal procedure GetPostConfirmMessage(): Text + begin + exit(PostConfirmLbl); + end; + local procedure CopyDataFromAccountCategory(var SustainabilityLedgerEntry: Record "Sustainability Ledger Entry"; CategoryCode: Code[20]) var SustainAccountCategory: Record "Sustain. Account Category"; @@ -73,4 +92,6 @@ codeunit 6212 "Sustainability Post Mgt" PostingSustainabilityJournalLbl: Label 'Posting Sustainability Journal Lines: \ #1', Comment = '#1 = sub-process progress message'; CheckSustainabilityJournalLineLbl: Label 'Checking Sustainability Journal Line: %1', Comment = '%1 = Line No.'; ProcessingLineLbl: Label 'Processing Line: %1', Comment = '%1 = Line No.'; + JnlLinesPostedLbl: Label 'The journal lines were successfully posted.'; + PostConfirmLbl: Label 'Do you want to post the journal lines?'; } \ No newline at end of file diff --git a/Apps/W1/Sustainability/app/src/Posting/SustainabilityRecurJnlPost.Codeunit.al b/Apps/W1/Sustainability/app/src/Posting/SustainabilityRecurJnlPost.Codeunit.al index 754ec38e4d..efd500158d 100644 --- a/Apps/W1/Sustainability/app/src/Posting/SustainabilityRecurJnlPost.Codeunit.al +++ b/Apps/W1/Sustainability/app/src/Posting/SustainabilityRecurJnlPost.Codeunit.al @@ -2,6 +2,7 @@ namespace Microsoft.Sustainability.Posting; using Microsoft.Sustainability.Journal; using Microsoft.Foundation.NoSeries; +using System.Utilities; codeunit 6214 "Sustainability Recur Jnl.-Post" { @@ -10,10 +11,14 @@ codeunit 6214 "Sustainability Recur Jnl.-Post" trigger OnRun() var SustainabilityJnlBatch: Record "Sustainability Jnl. Batch"; + ConfirmManagement: Codeunit "Confirm Management"; SustainabilityPostMgt: Codeunit "Sustainability Post Mgt"; NoSeriesBatch: Codeunit "No. Series - Batch"; Window: Dialog; begin + if not ConfirmManagement.GetResponseOrDefault(SustainabilityPostMgt.GetPostConfirmMessage(), true) then + exit; + Rec.LockTable(); if GuiAllowed() then @@ -28,7 +33,6 @@ codeunit 6214 "Sustainability Recur Jnl.-Post" if GuiAllowed() then Window.Update(1, SustainabilityPostMgt.GetProgressingLineMessage(Rec."Line No.")); - Rec.Validate("Document No.", NoSeriesBatch.GetNextNo(SustainabilityJnlBatch."No Series", Rec."Posting Date")); SustainabilityPostMgt.InsertLedgerEntry(Rec); @@ -37,8 +41,12 @@ codeunit 6214 "Sustainability Recur Jnl.-Post" NoSeriesBatch.SaveState(); - if GuiAllowed() then + if GuiAllowed() then begin Window.Close(); + Message(SustainabilityPostMgt.GetJnlLinesPostedMessage()); + end; + + SustainabilityPostMgt.ResetFilters(Rec); end; local procedure CheckAndMarkRecurringLinesBeforePosting(var SustainabilityJnlLine: Record "Sustainability Jnl. Line"; var DialogInstance: Dialog) @@ -67,8 +75,10 @@ codeunit 6214 "Sustainability Recur Jnl.-Post" SustainabilityJnlLine.MarkedOnly(true); - if SustainabilityJnlLine.IsEmpty() then + if SustainabilityJnlLine.IsEmpty() then begin + SustainabilityJnlLine.MarkedOnly(false); Error(AllRecurringLinesExpiredErr, SustainabilityJnlLine.FieldCaption("Expiration Date"), SustainabilityJnlLine.FieldCaption("Posting Date")); + end; end; local procedure ProcessRecurringJournalLine(var SustainabilityJnlLine: Record "Sustainability Jnl. Line") diff --git a/Apps/W1/Sustainability/app/src/Reports/EmissionByCategory.Report.al b/Apps/W1/Sustainability/app/src/Reports/EmissionByCategory.Report.al index 9adfa1af4b..dad3af5ffd 100644 --- a/Apps/W1/Sustainability/app/src/Reports/EmissionByCategory.Report.al +++ b/Apps/W1/Sustainability/app/src/Reports/EmissionByCategory.Report.al @@ -37,11 +37,9 @@ report 6210 "Emission By Category" { IncludeCaption = true; } - column(Posting_Date; Format("Posting Date")) - { - } - column(Posting_Date_Caption; FieldCaption("Posting Date")) + column(Posting_Date; "Posting Date") { + IncludeCaption = true; } column(Document_Type; "Document Type") { @@ -95,9 +93,9 @@ report 6210 "Emission By Category" Clear(SustainAccountCategory); if UseReportingUOMFactor then begin - "Emission CO2" := Round("Emission CO2" * ReportingUOMFactor, RoundingPrecission, RoundingDirection); - "Emission CH4" := Round("Emission CH4" * ReportingUOMFactor, RoundingPrecission, RoundingDirection); - "Emission N2O" := Round("Emission N2O" * ReportingUOMFactor, RoundingPrecission, RoundingDirection); + "Emission CO2" := Round("Emission CO2" * ReportingUOMFactor, RoundingPrecision, RoundingDirection); + "Emission CH4" := Round("Emission CH4" * ReportingUOMFactor, RoundingPrecision, RoundingDirection); + "Emission N2O" := Round("Emission N2O" * ReportingUOMFactor, RoundingPrecision, RoundingDirection); end; end; } @@ -106,13 +104,33 @@ report 6210 "Emission By Category" { EmissionByCategory = 'Emission By Category'; PageCaption = 'Page'; + CompName = 'Company Name'; + PostingDate = 'Posting Date'; + TotalEmissionsperCategory = 'Total Emissions per Category'; + SumOfEmission_CO2 = 'Sum of Emission CO2'; + SumOfEmission_CH4 = 'Sum of Emission CH4'; + SumOfEmission_N2O = 'Sum of Emission N2O'; + AccountCategoryDescription = 'Account Category Description'; + CategoryDetails = 'Category Details'; + AccountName = 'Account Name'; + DocumentType = 'Document Type'; + CountryRegionCode = 'Country/Region Code'; + EmissionScope = 'Emission Scope'; + AccountCategory = 'Account Category'; + AccountNo = 'Account No.'; + AverageEmissions = 'Average Emissions'; + AverageEmissionsperCategory = 'Average Emissions per Category'; + AverageOfEmission_CO2 = 'Average of Emission CO2'; + AverageOfEmission_CH4 = 'Average of Emission CH4'; + AverageOfEmission_N2O = 'Average of Emission N2O'; + EmissionsPerDocument = 'Emissions Per Document'; } trigger OnPreReport() var SustainabilitySetup: Record "Sustainability Setup"; begin SustLedgDateFilter := "Sustainability Ledger Entry".GetFilter("Posting Date"); - SustainabilitySetup.GetReportingParameters(ReportingUOMCode, UseReportingUOMFactor, ReportingUOMFactor, RoundingDirection, RoundingPrecission); + SustainabilitySetup.GetReportingParameters(ReportingUOMCode, UseReportingUOMFactor, ReportingUOMFactor, RoundingDirection, RoundingPrecision); end; var @@ -120,6 +138,6 @@ report 6210 "Emission By Category" ReportingUOMCode: Code[10]; SustainabilityAccountName, SustLedgDateFilter, RoundingDirection : Text; ShowDetails, UseReportingUOMFactor : Boolean; - ReportingUOMFactor, RoundingPrecission : Decimal; + ReportingUOMFactor, RoundingPrecision : Decimal; PeriodLbl: Label 'Period: %1', Comment = '%1 - period filter'; } \ No newline at end of file diff --git a/Apps/W1/Sustainability/app/src/Reports/EmissionByCategory.rdlc b/Apps/W1/Sustainability/app/src/Reports/EmissionByCategory.rdlc index 2862746d67..25d8d9a677 100644 --- a/Apps/W1/Sustainability/app/src/Reports/EmissionByCategory.rdlc +++ b/Apps/W1/Sustainability/app/src/Reports/EmissionByCategory.rdlc @@ -28,10 +28,10 @@ 1.05139in - 0.67638in + 0.78471in - 0.48268in + 0.58268in 1.91239in @@ -40,7 +40,7 @@ 0.53333in - 0.76805in + 0.55972in 0.07874in @@ -74,7 +74,7 @@ - =Fields!Posting_Date_Caption.Value + =Parameters!Posting_DateCaption.Value @@ -931,6 +932,7 @@ 2pt + true @@ -1985,6 +1987,186 @@ PageCaption + + String + + + CompName + + + CompName + + + String + + + PostingDate + + + PostingDate + + + String + + + TotalEmissionsperCategory + + + TotalEmissionsperCategory + + + String + + + SumOfEmission_CO2 + + + SumOfEmission_CO2 + + + String + + + SumOfEmission_CH4 + + + SumOfEmission_CH4 + + + String + + + SumOfEmission_N2O + + + SumOfEmission_N2O + + + String + + + AccountCategoryDescription + + + AccountCategoryDescription + + + String + + + CategoryDetails + + + CategoryDetails + + + String + + + AccountName + + + AccountName + + + String + + + DocumentType + + + DocumentType + + + String + + + CountryRegionCode + + + CountryRegionCode + + + String + + + EmissionScope + + + EmissionScope + + + String + + + AccountCategory + + + AccountCategory + + + String + + + AccountNo + + + AccountNo + + + String + + + AverageEmissions + + + AverageEmissions + + + String + + + AverageEmissionsperCategory + + + AverageEmissionsperCategory + + + String + + + AverageOfEmission_CO2 + + + AverageOfEmission_CO2 + + + String + + + AverageOfEmission_CH4 + + + AverageOfEmission_CH4 + + + String + + + AverageOfEmission_N2O + + + AverageOfEmission_N2O + + + String + + + EmissionsPerDocument + + + EmissionsPerDocument + String @@ -2003,6 +2185,15 @@ Account_Category_DescriptionCaption + + String + + + Posting_DateCaption + + + Posting_DateCaption + String @@ -2097,7 +2288,7 @@ 1 - 14 + 35 0 @@ -2112,61 +2303,166 @@ 0 2 - Account_CategoryCaption + CompName 0 3 - Account_Category_DescriptionCaption + PostingDate 0 4 - Document_TypeCaption + TotalEmissionsperCategory 0 5 - Document_No_Caption + SumOfEmission_CO2 0 6 - Account_No_Caption + SumOfEmission_CH4 0 7 - Account_NameCaption + SumOfEmission_N2O 0 8 - DescriptionCaption + AccountCategoryDescription 0 9 - Emission_ScopeCaption + CategoryDetails 0 10 - Country_Region_CodeCaption + AccountName 0 11 - Emission_CO2Caption + DocumentType 0 12 - Emission_CH4Caption + CountryRegionCode 0 13 + EmissionScope + + + 0 + 14 + AccountCategory + + + 0 + 15 + AccountNo + + + 0 + 16 + AverageEmissions + + + 0 + 17 + AverageEmissionsperCategory + + + 0 + 18 + AverageOfEmission_CO2 + + + 0 + 19 + AverageOfEmission_CH4 + + + 0 + 20 + AverageOfEmission_N2O + + + 0 + 21 + EmissionsPerDocument + + + 0 + 22 + Account_CategoryCaption + + + 0 + 23 + Account_Category_DescriptionCaption + + + 0 + 24 + Posting_DateCaption + + + 0 + 25 + Document_TypeCaption + + + 0 + 26 + Document_No_Caption + + + 0 + 27 + Account_No_Caption + + + 0 + 28 + Account_NameCaption + + + 0 + 29 + DescriptionCaption + + + 0 + 30 + Emission_ScopeCaption + + + 0 + 31 + Country_Region_CodeCaption + + + 0 + 32 + Emission_CO2Caption + + + 0 + 33 + Emission_CH4Caption + + + 0 + 34 Emission_N2OCaption @@ -2242,9 +2538,6 @@ End Function Posting_Date - - Posting_Date_Caption - Document_Type diff --git a/Apps/W1/Sustainability/app/src/Reports/EmissionByCategory.xlsx b/Apps/W1/Sustainability/app/src/Reports/EmissionByCategory.xlsx index dd09989014aa2e697a3598b0ecd511ce8cbe512d..fe3933da17280fa402f1a7b18daf6739d245eaaa 100644 GIT binary patch delta 51217 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 EKgf-vT>t<8 diff --git a/Apps/W1/Sustainability/app/src/Reports/EmissionPerFacility.Report.al b/Apps/W1/Sustainability/app/src/Reports/EmissionPerFacility.Report.al index 1fc0d76984..0febb0e101 100644 --- a/Apps/W1/Sustainability/app/src/Reports/EmissionPerFacility.Report.al +++ b/Apps/W1/Sustainability/app/src/Reports/EmissionPerFacility.Report.al @@ -81,9 +81,9 @@ report 6211 "Emission Per Facility" Clear(ResponsibilityCenter); if UseReportingUOMFactor then begin - "Emission CO2" := Round("Emission CO2" * ReportingUOMFactor, RoundingPrecission, RoundingDirection); - "Emission CH4" := Round("Emission CH4" * ReportingUOMFactor, RoundingPrecission, RoundingDirection); - "Emission N2O" := Round("Emission N2O" * ReportingUOMFactor, RoundingPrecission, RoundingDirection); + "Emission CO2" := Round("Emission CO2" * ReportingUOMFactor, RoundingPrecision, RoundingDirection); + "Emission CH4" := Round("Emission CH4" * ReportingUOMFactor, RoundingPrecision, RoundingDirection); + "Emission N2O" := Round("Emission N2O" * ReportingUOMFactor, RoundingPrecision, RoundingDirection); end; end; } @@ -92,6 +92,21 @@ report 6211 "Emission Per Facility" { EmissionPerFacility = 'Emission Per Facility'; PageCaption = 'Page'; + EmissionsByRespCenter = 'Emissions by R. C.'; + AverageByScopeAndRC = 'Average by Scope and R. C.'; + AverageByAccountAndRC = 'Average by Account and R. C.'; + CompName = 'Company Name'; + CountryRegionCode = 'Country/Region Code'; + EmissionByRespCenter = 'Emissions by Responsibility Center'; + EmissionScope = 'Emission Scope'; + ResponsibilityCenter = 'Responsibility Center'; + SumOfEmission_CO2 = 'Sum of Emission CO2'; + SumOfEmission_CH4 = 'Sum of Emission CH4'; + SumOfEmission_N2O = 'Sum of Emission N2O'; + AverageOfEmission_CO2 = 'Average of Emission CO2'; + AverageOfEmission_CH4 = 'Average of Emission CH4'; + AverageOfEmission_N2O = 'Average of Emission N2O'; + AccountName = 'Account Name'; } trigger OnPreReport() @@ -99,14 +114,14 @@ report 6211 "Emission Per Facility" SustainabilitySetup: Record "Sustainability Setup"; begin SustLedgDateFilter := "Sustainability Ledger Entry".GetFilter("Posting Date"); - SustainabilitySetup.GetReportingParameters(ReportingUOMCode, UseReportingUOMFactor, ReportingUOMFactor, RoundingDirection, RoundingPrecission); + SustainabilitySetup.GetReportingParameters(ReportingUOMCode, UseReportingUOMFactor, ReportingUOMFactor, RoundingDirection, RoundingPrecision); end; var ResponsibilityCenter: Record "Responsibility Center"; ReportingUOMCode: Code[10]; SustainabilityAccountName, SustLedgDateFilter, RoundingDirection : Text; - ReportingUOMFactor, RoundingPrecission : Decimal; + ReportingUOMFactor, RoundingPrecision : Decimal; ShowDetails, UseReportingUOMFactor : Boolean; PeriodLbl: Label 'Period: %1', Comment = '%1 - period filter'; } \ No newline at end of file diff --git a/Apps/W1/Sustainability/app/src/Reports/EmissionPerFacility.rdlc b/Apps/W1/Sustainability/app/src/Reports/EmissionPerFacility.rdlc index ee444a415e..a8c14ff1b5 100644 --- a/Apps/W1/Sustainability/app/src/Reports/EmissionPerFacility.rdlc +++ b/Apps/W1/Sustainability/app/src/Reports/EmissionPerFacility.rdlc @@ -1746,6 +1746,141 @@ PageCaption + + String + + + EmissionsByRespCenter + + + EmissionsByRespCenter + + + String + + + AverageByScopeAndRC + + + AverageByScopeAndRC + + + String + + + AverageByAccountAndRC + + + AverageByAccountAndRC + + + String + + + CompName + + + CompName + + + String + + + CountryRegionCode + + + CountryRegionCode + + + String + + + EmissionByRespCenter + + + EmissionByRespCenter + + + String + + + EmissionScope + + + EmissionScope + + + String + + + ResponsibilityCenter + + + ResponsibilityCenter + + + String + + + SumOfEmission_CO2 + + + SumOfEmission_CO2 + + + String + + + SumOfEmission_CH4 + + + SumOfEmission_CH4 + + + String + + + SumOfEmission_N2O + + + SumOfEmission_N2O + + + String + + + AverageOfEmission_CO2 + + + AverageOfEmission_CO2 + + + String + + + AverageOfEmission_CH4 + + + AverageOfEmission_CH4 + + + String + + + AverageOfEmission_N2O + + + AverageOfEmission_N2O + + + String + + + AccountName + + + AccountName + String @@ -1840,7 +1975,7 @@ 1 - 12 + 27 0 @@ -1855,51 +1990,126 @@ 0 2 - Responsibility_CenterCaption + EmissionsByRespCenter 0 3 - Responsibility_Center_NameCaption + AverageByScopeAndRC 0 4 - Account_No_Caption + AverageByAccountAndRC 0 5 - Account_NameCaption + CompName 0 6 - DescriptionCaption + CountryRegionCode 0 7 - Emission_ScopeCaption + EmissionByRespCenter 0 8 - Country_Region_CodeCaption + EmissionScope 0 9 - Emission_CO2Caption + ResponsibilityCenter 0 10 - Emission_CH4Caption + SumOfEmission_CO2 0 11 + SumOfEmission_CH4 + + + 0 + 12 + SumOfEmission_N2O + + + 0 + 13 + AverageOfEmission_CO2 + + + 0 + 14 + AverageOfEmission_CH4 + + + 0 + 15 + AverageOfEmission_N2O + + + 0 + 16 + AccountName + + + 0 + 17 + Responsibility_CenterCaption + + + 0 + 18 + Responsibility_Center_NameCaption + + + 0 + 19 + Account_No_Caption + + + 0 + 20 + Account_NameCaption + + + 0 + 21 + DescriptionCaption + + + 0 + 22 + Emission_ScopeCaption + + + 0 + 23 + Country_Region_CodeCaption + + + 0 + 24 + Emission_CO2Caption + + + 0 + 25 + Emission_CH4Caption + + + 0 + 26 Emission_N2OCaption diff --git a/Apps/W1/Sustainability/app/src/Reports/EmissionPerFacility.xlsx b/Apps/W1/Sustainability/app/src/Reports/EmissionPerFacility.xlsx index a107414344825280586d4ac60f287e4d1f5d96a0..beabe9a295b6de103661ae35ebf35b790cb6c0c4 100644 GIT binary patch delta 34364 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 - 0.42288in + 0.55621in 0.57638in @@ -34,7 +34,7 @@ 0.78471in - 2.11036in + 1.97703in 1.04305in @@ -59,6 +59,335 @@ + + 0.19685in + + + + + true + true + + + + + =Parameters!Emission_ScopeCaption.Value + + + + + + + Black + + 1pt + + 2pt + 2pt + 2pt + 2pt + + + + + + + + true + true + + + + + =Parameters!Account_No_Caption.Value + + + + + + + Black + + 1pt + + 2pt + 2pt + 2pt + 2pt + + + 6 + + + + + + + + + + + true + true + + + + + + + + + + + + Black + + 1pt + + 2pt + 2pt + 2pt + 2pt + + + + + + + + true + true + + + + + =Parameters!Emission_CO2Caption.Value + + + + + + + Textbox11 + + + + Black + + 1pt + + 2pt + 2pt + 2pt + 2pt + + + + + + + + true + true + + + + + + + + + + + + Black + + 1pt + + 2pt + 2pt + 2pt + 2pt + + + + + + + + true + true + + + + + =Parameters!Emission_CH4Caption.Value + + + + + + + Textbox2 + + + + Black + + 1pt + + 2pt + 2pt + 2pt + 2pt + + + + + + + + true + true + + + + + + + + + + + + Black + + 1pt + + 2pt + 2pt + 2pt + 2pt + + + + + + + + true + true + + + + + =Parameters!Emission_N2OCaption.Value + + + + + + + Textbox10 + + + + Black + + 1pt + + 2pt + 2pt + 2pt + 2pt + + + + + + 0.19685in @@ -149,7 +478,7 @@ - =Fields!Posting_Date_Caption.Value + =Parameters!Posting_DateCaption.Value @@ -2184,6 +2514,16 @@ + + =Fields!ShowDetails.Value + + After + true + + + + =Not(Fields!ShowDetails.Value) + After true true @@ -2248,7 +2588,7 @@ DataSet_Result 0.125in 0in - 1.1811in + 1.37795in 10.03052in - 1.3061in + 1.5561in