From 83c4faf6e3092f76078ccf532cd4e30d390988e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Holu=C5=A1a?= Date: Fri, 24 Jul 2026 17:37:01 +0200 Subject: [PATCH] Implement checks for blocked customers and vendors in advance letters --- .../TableExtensions/CustomerCZZ.TableExt.al | 13 ++ .../Src/TableExtensions/VendorCZZ.TableExt.al | 14 ++ .../Tables/PurchAdvLetterHeaderCZZ.Table.al | 3 + .../Tables/SalesAdvLetterHeaderCZZ.Table.al | 3 + .../PurchaseAdvancePaymentsCZZ.Codeunit.al | 113 ++++++++++++++++ .../Src/SalesAdvancePaymentsCZZ.Codeunit.al | 125 ++++++++++++++++++ 6 files changed, 271 insertions(+) diff --git a/src/Apps/CZ/AdvancePaymentsLocalization/app/Src/TableExtensions/CustomerCZZ.TableExt.al b/src/Apps/CZ/AdvancePaymentsLocalization/app/Src/TableExtensions/CustomerCZZ.TableExt.al index 34cb6f3573b..25da6101a9b 100644 --- a/src/Apps/CZ/AdvancePaymentsLocalization/app/Src/TableExtensions/CustomerCZZ.TableExt.al +++ b/src/Apps/CZ/AdvancePaymentsLocalization/app/Src/TableExtensions/CustomerCZZ.TableExt.al @@ -16,4 +16,17 @@ tableextension 31045 "Customer CZZ" extends Customer SalesAdvLetterHeaderCZZ.SetFilter(Status, '%1|%2', SalesAdvLetterHeaderCZZ.Status::"To Pay", SalesAdvLetterHeaderCZZ.Status::"To Use"); exit(SalesAdvLetterHeaderCZZ.Count()); end; + + /// + /// Checks if the customer is blocked for the specified advance letter and raises an error if blocked. + /// + /// Indicates whether this is a posting transaction. + procedure CheckBlockedCustOnAdvanceLettersCZZ(Transaction: Boolean) + begin + if "Privacy Blocked" then + CustPrivacyBlockedErrorMessage(Rec, Transaction); + + if Blocked <> Blocked::" " then + CustBlockedErrorMessage(Rec, Transaction); + end; } diff --git a/src/Apps/CZ/AdvancePaymentsLocalization/app/Src/TableExtensions/VendorCZZ.TableExt.al b/src/Apps/CZ/AdvancePaymentsLocalization/app/Src/TableExtensions/VendorCZZ.TableExt.al index e791e1abfcf..e673e2388af 100644 --- a/src/Apps/CZ/AdvancePaymentsLocalization/app/Src/TableExtensions/VendorCZZ.TableExt.al +++ b/src/Apps/CZ/AdvancePaymentsLocalization/app/Src/TableExtensions/VendorCZZ.TableExt.al @@ -16,4 +16,18 @@ tableextension 31046 "Vendor CZZ" extends Vendor PurchAdvLetterHeaderCZZ.SetFilter(Status, '%1|%2', PurchAdvLetterHeaderCZZ.Status::"To Pay", PurchAdvLetterHeaderCZZ.Status::"To Use"); exit(PurchAdvLetterHeaderCZZ.Count()); end; + + + /// + /// Checks if the vendor is blocked for the specified advance letter and raises an error if blocked. + /// + /// Indicates whether this is a posting transaction. + procedure CheckBlockedVendOnAdvanceLettersCZZ(Transaction: Boolean) + begin + if "Privacy Blocked" then + VendPrivacyBlockedErrorMessage(Rec, Transaction); + + if Blocked <> Blocked::" " then + VendBlockedErrorMessage(Rec, Transaction); + end; } diff --git a/src/Apps/CZ/AdvancePaymentsLocalization/app/Src/Tables/PurchAdvLetterHeaderCZZ.Table.al b/src/Apps/CZ/AdvancePaymentsLocalization/app/Src/Tables/PurchAdvLetterHeaderCZZ.Table.al index d29e7dfc440..ab92ff4129c 100644 --- a/src/Apps/CZ/AdvancePaymentsLocalization/app/Src/Tables/PurchAdvLetterHeaderCZZ.Table.al +++ b/src/Apps/CZ/AdvancePaymentsLocalization/app/Src/Tables/PurchAdvLetterHeaderCZZ.Table.al @@ -94,6 +94,7 @@ table 31008 "Purch. Adv. Letter Header CZZ" GetVendor("Pay-to Vendor No."); Vendor.TestField("Vendor Posting Group"); + Vendor.CheckBlockedVendOnAdvanceLettersCZZ(false); "Pay-to Name" := Vendor.Name; "Pay-to Name 2" := Vendor."Name 2"; CopyPayToVendorAddressFieldsFromVendor(Vendor, false); @@ -1621,6 +1622,8 @@ table 31008 "Purch. Adv. Letter Header CZZ" procedure CheckPurchaseAdvanceLetterPostRestrictions() begin + Vendor.Get("Pay-to Vendor No."); + Vendor.CheckBlockedVendOnAdvanceLettersCZZ(true); OnCheckPurchaseAdvanceLetterPostRestrictions(); end; diff --git a/src/Apps/CZ/AdvancePaymentsLocalization/app/Src/Tables/SalesAdvLetterHeaderCZZ.Table.al b/src/Apps/CZ/AdvancePaymentsLocalization/app/Src/Tables/SalesAdvLetterHeaderCZZ.Table.al index c15344376e6..72695b06d0c 100644 --- a/src/Apps/CZ/AdvancePaymentsLocalization/app/Src/Tables/SalesAdvLetterHeaderCZZ.Table.al +++ b/src/Apps/CZ/AdvancePaymentsLocalization/app/Src/Tables/SalesAdvLetterHeaderCZZ.Table.al @@ -98,6 +98,7 @@ table 31004 "Sales Adv. Letter Header CZZ" GetCustomer("Bill-to Customer No."); Customer.TestField("Customer Posting Group"); + Customer.CheckBlockedCustOnAdvanceLettersCZZ(false); SetBillToCustomerAddressFieldsFromCustomer(Customer); @@ -1731,6 +1732,8 @@ table 31004 "Sales Adv. Letter Header CZZ" procedure CheckSalesAdvanceLetterPostRestrictions() begin + Customer.Get("Bill-to Customer No."); + Customer.CheckBlockedCustOnAdvanceLettersCZZ(true); OnCheckSalesAdvanceLetterPostRestrictions(); end; diff --git a/src/Apps/CZ/AdvancePaymentsLocalization/test/Src/PurchaseAdvancePaymentsCZZ.Codeunit.al b/src/Apps/CZ/AdvancePaymentsLocalization/test/Src/PurchaseAdvancePaymentsCZZ.Codeunit.al index 8389c02b819..a530018fb4e 100644 --- a/src/Apps/CZ/AdvancePaymentsLocalization/test/Src/PurchaseAdvancePaymentsCZZ.Codeunit.al +++ b/src/Apps/CZ/AdvancePaymentsLocalization/test/Src/PurchaseAdvancePaymentsCZZ.Codeunit.al @@ -31,6 +31,8 @@ codeunit 148108 "Purchase Advance Payments CZZ" UnapplyAdvLetterQst: Label 'Unapply advance letter: %1\Continue?', Comment = '%1 = Advance Letters'; UsageNoPossibleQst: Label 'Usage all applicated advances is not possible.\Continue?'; PostCashDocumentQst: Label 'Do you want to post Cash Document Header %1?', Comment = '%1 = Cash Document No.'; + BlockedVendorErr: Label 'You cannot %1 this type of document when Vendor %2 is blocked with type %3', Comment = '%1 = create/post, %2 = vendor no., %3 = blocked type'; + PrivacyBlockedVendorErr: Label 'You cannot %1 this type of document when Vendor %2 is blocked for privacy.', Comment = '%1 = create/post, %2 = vendor no.'; local procedure Initialize() var @@ -2643,6 +2645,117 @@ codeunit 148108 "Purchase Advance Payments CZZ" SetPostVATDocForReverseCharge(false); end; + [Test] + procedure CreatePurchAdvLetterWithVendorBlockedAll() + begin + CreatePurchAdvLetterWithBlockedVendorBase(Enum::"Vendor Blocked"::All, false); + end; + + [Test] + procedure CreatePurchAdvLetterWithVendorBlockedPayment() + begin + CreatePurchAdvLetterWithBlockedVendorBase(Enum::"Vendor Blocked"::Payment, false); + end; + + [Test] + procedure CreatePurchAdvLetterWithPrivacyBlockedVendor() + begin + CreatePurchAdvLetterWithBlockedVendorBase(Enum::"Vendor Blocked"::" ", true); + end; + + [Test] + procedure PostPaymentPurchAdvLetterWithVendorBlockedAll() + begin + PostPaymentPurchAdvLetterWithBlockedVendorBase(Enum::"Vendor Blocked"::All, false); + end; + + [Test] + procedure PostPaymentPurchAdvLetterWithVendorBlockedPayment() + begin + PostPaymentPurchAdvLetterWithBlockedVendorBase(Enum::"Vendor Blocked"::Payment, false); + end; + + [Test] + procedure PostPaymentPurchAdvLetterWithPrivacyBlockedVendor() + begin + PostPaymentPurchAdvLetterWithBlockedVendorBase(Enum::"Vendor Blocked"::" ", true); + end; + + local procedure CreatePurchAdvLetterWithBlockedVendorBase(VendorBlocked: Enum "Vendor Blocked"; PrivacyBlocked: Boolean) + var + PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; + Vendor: Record Vendor; + begin + // [SCENARIO] Creating purchase advance letter with blocked vendor must fail + Initialize(); + + // [GIVEN] Vendor has been created and blocked + CreateBlockedVendor(Vendor, VendorBlocked, PrivacyBlocked); + + // [WHEN] Create purchase advance letter with blocked vendor + asserterror LibraryPurchAdvancesCZZ.CreatePurchAdvLetterHeader(PurchAdvLetterHeaderCZZ, AdvanceLetterTemplateCZZ.Code, Vendor."No.", ''); + + // [THEN] Error will occur + if PrivacyBlocked then + Assert.ExpectedError(StrSubstNo(PrivacyBlockedVendorErr, 'create', Vendor."No.")) + else + Assert.ExpectedError(StrSubstNo(BlockedVendorErr, 'create', Vendor."No.", VendorBlocked)); + end; + + local procedure PostPaymentPurchAdvLetterWithBlockedVendorBase(VendorBlocked: Enum "Vendor Blocked"; PrivacyBlocked: Boolean) + var + PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; + PurchAdvLetterLineCZZ: Record "Purch. Adv. Letter Line CZZ"; + GenJournalLine: Record "Gen. Journal Line"; + Vendor: Record Vendor; + begin + // [SCENARIO] Posting payment for purchase advance letter with blocked vendor must fail + Initialize(); + + // [GIVEN] Purchase advance letter has been created + // [GIVEN] Purchase advance letter line with normal VAT has been created + CreatePurchAdvLetter(PurchAdvLetterHeaderCZZ, PurchAdvLetterLineCZZ); + + // [GIVEN] Purchase advance letter has been released + ReleasePurchAdvLetter(PurchAdvLetterHeaderCZZ); + + // [GIVEN] Purchase advance payment has been prepared in general journal + LibraryPurchAdvancesCZZ.CreatePurchAdvancePayment( + GenJournalLine, PurchAdvLetterHeaderCZZ."Pay-to Vendor No.", PurchAdvLetterLineCZZ."Amount Including VAT", + PurchAdvLetterHeaderCZZ."Currency Code", PurchAdvLetterHeaderCZZ."No.", 0, 0D); + + // [GIVEN] Vendor has been blocked + Vendor.Get(PurchAdvLetterHeaderCZZ."Pay-to Vendor No."); + if PrivacyBlocked then + Vendor.Validate("Privacy Blocked", PrivacyBlocked) + else + Vendor.Validate(Blocked, VendorBlocked); + Vendor.Modify(true); + + // [WHEN] Post purchase advance payment + asserterror PostGenJournalLine(GenJournalLine); + + // [THEN] Error will occur + if PrivacyBlocked then + Assert.ExpectedError(StrSubstNo(PrivacyBlockedVendorErr, 'post', Vendor."No.")) + else + Assert.ExpectedError(StrSubstNo(BlockedVendorErr, 'post', Vendor."No.", VendorBlocked)); + end; + + local procedure CreateBlockedVendor(var Vendor: Record Vendor; VendorBlocked: Enum "Vendor Blocked"; PrivacyBlocked: Boolean) + var + VATPostingSetup: Record "VAT Posting Setup"; + begin + LibraryPurchAdvancesCZZ.FindVATPostingSetup(VATPostingSetup); + LibraryPurchAdvancesCZZ.CreateVendor(Vendor); + Vendor.Validate("VAT Bus. Posting Group", VATPostingSetup."VAT Bus. Posting Group"); + if PrivacyBlocked then + Vendor.Validate("Privacy Blocked", PrivacyBlocked) + else + Vendor.Validate(Blocked, VendorBlocked); + Vendor.Modify(true); + end; + local procedure CreatePurchAdvLetterBase(var PurchAdvLetterHeaderCZZ: Record "Purch. Adv. Letter Header CZZ"; var PurchAdvLetterLineCZZ: Record "Purch. Adv. Letter Line CZZ"; VendorNo: Code[20]; CurrencyCode: Code[10]; VATPostingSetup: Record "VAT Posting Setup") var Vendor: Record Vendor; diff --git a/src/Apps/CZ/AdvancePaymentsLocalization/test/Src/SalesAdvancePaymentsCZZ.Codeunit.al b/src/Apps/CZ/AdvancePaymentsLocalization/test/Src/SalesAdvancePaymentsCZZ.Codeunit.al index 82c1a48ad2c..b33009a6dfe 100644 --- a/src/Apps/CZ/AdvancePaymentsLocalization/test/Src/SalesAdvancePaymentsCZZ.Codeunit.al +++ b/src/Apps/CZ/AdvancePaymentsLocalization/test/Src/SalesAdvancePaymentsCZZ.Codeunit.al @@ -32,6 +32,8 @@ codeunit 148109 "Sales Advance Payments CZZ" UnapplyAdvLetterQst: Label 'Unapply advance letter: %1\Continue?', Comment = '%1 = Advance Letters'; UsageNoPossibleQst: Label 'Usage all applicated advances is not possible.\Continue?'; PostCashDocumentQst: Label 'Do you want to post Cash Document Header %1?', Comment = '%1 = Cash Document No.'; + BlockedCustomerErr: Label 'You cannot %1 this type of document when Customer %2 is blocked with type %3', Comment = '%1 = create/post, %2 = customer no., %3 = blocked type'; + PrivacyBlockedCustomerErr: Label 'You cannot %1 this type of document when Customer %2 is blocked for privacy.', Comment = '%1 = create/post, %2 = customer no.'; local procedure Initialize() var @@ -2773,6 +2775,129 @@ codeunit 148109 "Sales Advance Payments CZZ" CopyDocumentMgt.CopySalesDoc("Sales Document Type From"::"Posted Invoice", DocumentNo, SalesHeader[2]); end; + [Test] + procedure CreateSalesAdvLetterWithCustomerBlockedAll() + begin + CreateSalesAdvLetterWithBlockedCustomerBase(Enum::"Customer Blocked"::All, false); + end; + + [Test] + procedure CreateSalesAdvLetterWithCustomerBlockedShip() + begin + CreateSalesAdvLetterWithBlockedCustomerBase(Enum::"Customer Blocked"::Ship, false); + end; + + [Test] + procedure CreateSalesAdvLetterWithCustomerBlockedInvoice() + begin + CreateSalesAdvLetterWithBlockedCustomerBase(Enum::"Customer Blocked"::Invoice, false); + end; + + [Test] + procedure CreateSalesAdvLetterWithPrivacyBlockedCustomer() + begin + CreateSalesAdvLetterWithBlockedCustomerBase(Enum::"Customer Blocked"::" ", true); + end; + + [Test] + procedure PostPaymentSalesAdvLetterWithCustomerBlockedAll() + begin + PostPaymentSalesAdvLetterWithBlockedCustomerBase(Enum::"Customer Blocked"::All, false); + end; + + [Test] + procedure PostPaymentSalesAdvLetterWithCustomerBlockedShip() + begin + PostPaymentSalesAdvLetterWithBlockedCustomerBase(Enum::"Customer Blocked"::Ship, false); + end; + + [Test] + procedure PostPaymentSalesAdvLetterWithCustomerBlockedInvoice() + begin + PostPaymentSalesAdvLetterWithBlockedCustomerBase(Enum::"Customer Blocked"::Invoice, false); + end; + + [Test] + procedure PostPaymentSalesAdvLetterWithPrivacyBlockedCustomer() + begin + PostPaymentSalesAdvLetterWithBlockedCustomerBase(Enum::"Customer Blocked"::" ", true); + end; + + local procedure CreateSalesAdvLetterWithBlockedCustomerBase(CustomerBlocked: Enum "Customer Blocked"; PrivacyBlocked: Boolean) + var + SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; + Customer: Record Customer; + begin + // [SCENARIO] Creating sales advance letter with blocked customer must fail + Initialize(); + + // [GIVEN] Customer has been created and blocked + CreateBlockedCustomer(Customer, CustomerBlocked, PrivacyBlocked); + + // [WHEN] Create sales advance letter with blocked customer + asserterror LibrarySalesAdvancesCZZ.CreateSalesAdvLetterHeader(SalesAdvLetterHeaderCZZ, AdvanceLetterTemplateCZZ.Code, Customer."No.", ''); + + // [THEN] Error will occur + if PrivacyBlocked then + Assert.ExpectedError(StrSubstNo(PrivacyBlockedCustomerErr, 'create', Customer."No.")) + else + Assert.ExpectedError(StrSubstNo(BlockedCustomerErr, 'create', Customer."No.", CustomerBlocked)); + end; + + local procedure PostPaymentSalesAdvLetterWithBlockedCustomerBase(CustomerBlocked: Enum "Customer Blocked"; PrivacyBlocked: Boolean) + var + SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; + SalesAdvLetterLineCZZ: Record "Sales Adv. Letter Line CZZ"; + Customer: Record Customer; + GenJournalLine: Record "Gen. Journal Line"; + begin + // [SCENARIO] Posting payment for sales advance letter with blocked customer must fail + Initialize(); + + // [GIVEN] Sales advance letter has been created + // [GIVEN] Sales advance letter line with normal VAT has been created + CreateSalesAdvLetter(SalesAdvLetterHeaderCZZ, SalesAdvLetterLineCZZ); + + // [GIVEN] Sales advance letter has been released + LibrarySalesAdvancesCZZ.ReleaseSalesAdvLetter(SalesAdvLetterHeaderCZZ); + + // [GIVEN] Sales advance payment has been prepared in general journal + LibrarySalesAdvancesCZZ.CreateSalesAdvancePayment( + GenJournalLine, SalesAdvLetterHeaderCZZ."Bill-to Customer No.", -SalesAdvLetterLineCZZ."Amount Including VAT", + SalesAdvLetterHeaderCZZ."Currency Code", SalesAdvLetterHeaderCZZ."No.", 0, 0D); + + // [GIVEN] Customer has been blocked + Customer.Get(SalesAdvLetterHeaderCZZ."Bill-to Customer No."); + if PrivacyBlocked then + Customer.Validate("Privacy Blocked", PrivacyBlocked) + else + Customer.Validate(Blocked, CustomerBlocked); + Customer.Modify(true); + + // [WHEN] Post sales advance payment + asserterror LibrarySalesAdvancesCZZ.PostSalesAdvancePayment(GenJournalLine); + + // [THEN] Error will occur + if PrivacyBlocked then + Assert.ExpectedError(StrSubstNo(PrivacyBlockedCustomerErr, 'post', Customer."No.")) + else + Assert.ExpectedError(StrSubstNo(BlockedCustomerErr, 'post', Customer."No.", CustomerBlocked)); + end; + + local procedure CreateBlockedCustomer(var Customer: Record Customer; CustomerBlocked: Enum "Customer Blocked"; PrivacyBlocked: Boolean) + var + VATPostingSetup: Record "VAT Posting Setup"; + begin + LibrarySalesAdvancesCZZ.FindVATPostingSetup(VATPostingSetup); + LibrarySalesAdvancesCZZ.CreateCustomer(Customer); + Customer.Validate("VAT Bus. Posting Group", VATPostingSetup."VAT Bus. Posting Group"); + if PrivacyBlocked then + Customer.Validate("Privacy Blocked", PrivacyBlocked) + else + Customer.Validate(Blocked, CustomerBlocked); + Customer.Modify(true); + end; + local procedure CreateSalesAdvLetterBase(var SalesAdvLetterHeaderCZZ: Record "Sales Adv. Letter Header CZZ"; var SalesAdvLetterLineCZZ: Record "Sales Adv. Letter Line CZZ"; CustomerNo: Code[20]; CurrencyCode: Code[10]; VATPostingSetup: Record "VAT Posting Setup") var Customer: Record Customer;