Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 25 additions & 7 deletions src/Layers/APAC/BaseApp/Purchases/Posting/PurchPost.Codeunit.al
Original file line number Diff line number Diff line change
Expand Up @@ -527,6 +527,7 @@ codeunit 90 "Purch.-Post"
ItemChargeZeroAmountErr: Label 'The amount for item charge %1 cannot be 0.', Comment = '%1 = Item Charge No.';
ConfirmUsageWithBlankLineTypeQst: Label 'Usage will not be linked to the project planning line because the Line Type field is empty.\\Do you want to continue?';
ConfirmUsageWithBlankJobPlanningLineNoQst: Label 'Usage will not be linked to the project planning line because the Project Planning Line No field is empty.\\Do you want to continue?';
SelfBillingNoSeriesMissingErr: Label 'Specify a number series for self-billing invoices in the %1 field on vendor %2, or in the %3 field in %4.', Comment = '%1 = Self-Billing Invoice Nos. field caption, %2 = Vendor No., %3 = Posted Self-Billing Inv. Nos. field caption, %4 = Purchases & Payables Setup table caption';

/// <summary>
/// Generates a record id for an 'empty' line
Expand Down Expand Up @@ -3073,10 +3074,7 @@ codeunit 90 "Purch.-Post"
ResetPostingNoSeriesFromSetup(PurchHeader."Posting No. Series", PurchSetup."Posted Credit Memo Nos.")
else
if (PurchHeader."Document Type" <> PurchHeader."Document Type"::"Credit Memo") then
if PurchHeader."Self-Billing Invoice" then
ResetPostingNoSeriesFromSetup(PurchHeader."Posting No. Series", PurchSetup."Posted Self-Billing Inv. Nos.")
else
ResetPostingNoSeriesFromSetup(PurchHeader."Posting No. Series", PurchSetup."Posted Invoice Nos.");
ResetPostingNoSeriesFromSetup(PurchHeader."Posting No. Series", PurchSetup."Posted Invoice Nos.");
if PurchHeader."Document Type" = PurchHeader."Document Type"::"Credit Memo" then
if (PurchSetup."Posted Credit Memo Nos." <> '') and (PurchHeader."Posting No. Series" = '') then
CheckDefaultNoSeries(PurchSetup."Posted Credit Memo Nos.");
Expand Down Expand Up @@ -9385,18 +9383,38 @@ codeunit 90 "Purch.-Post"

local procedure UpdateVendorInvoiceNoForSelfBilling(var PurchHeader: Record "Purchase Header")
var
Vendor: Record Vendor;
NoSeries: Codeunit "No. Series";
SelfBillingNoSeriesCode: Code[20];
begin
if not (PurchHeader."Document Type" in [PurchHeader."Document Type"::Invoice, PurchHeader."Document Type"::Order]) then
exit;

PurchSetup.GetRecordOnce();
PurchSetup.TestField("Posted Self-Billing Inv. Nos.");
SelfBillingNoSeriesCode := GetSelfBillingInvoiceNoSeries(PurchHeader);
if SelfBillingNoSeriesCode = '' then
Error(
SelfBillingNoSeriesMissingErr,
Vendor.FieldCaption("Self-Billing Invoice Nos."),
PurchHeader."Buy-from Vendor No.",
PurchSetup.FieldCaption("Posted Self-Billing Inv. Nos."),
PurchSetup.TableCaption());

if PreviewMode then
PurchHeader."Vendor Invoice No." := PostingPreviewNoTok
else
PurchHeader."Vendor Invoice No." := NoSeries.GetNextNo(PurchSetup."Posted Self-Billing Inv. Nos.", PurchHeader."Posting Date");
PurchHeader."Vendor Invoice No." := NoSeries.GetNextNo(SelfBillingNoSeriesCode, PurchHeader."Posting Date");
end;

local procedure GetSelfBillingInvoiceNoSeries(PurchHeader: Record "Purchase Header"): Code[20]
var
Vendor: Record Vendor;
begin
Vendor.SetLoadFields("Self-Billing Invoice Nos.");
if Vendor.Get(PurchHeader."Buy-from Vendor No.") and (Vendor."Self-Billing Invoice Nos." <> '') then
exit(Vendor."Self-Billing Invoice Nos.");

PurchSetup.GetRecordOnce();
exit(PurchSetup."Posted Self-Billing Inv. Nos.");
end;

local procedure SelfBillingInvoiceDocument(PurchHeader: Record "Purchase Header"): Boolean
Expand Down
12 changes: 12 additions & 0 deletions src/Layers/APAC/BaseApp/Purchases/Vendor/Vendor.Table.al
Original file line number Diff line number Diff line change
Expand Up @@ -1280,6 +1280,18 @@ table 23 Vendor
{
Caption = 'Self-Billing Agreement';
ToolTip = 'Specifies the value of the Self-Billing Agreement field.';

trigger OnValidate()
begin
if not Rec."Self-Billing Agreement" then
Rec.TestField("Self-Billing Invoice Nos.", '');
end;
}
field(181; "Self-Billing Invoice Nos."; Code[20])
{
Caption = 'Self-Billing Invoice Nos.';
ToolTip = 'Specifies the number series that is used to assign numbers to self-billed purchase invoices for this vendor. If it is empty, the number series from the Posted Self-Billing Inv. Nos. field in Purchases & Payables Setup is used.';
TableRelation = "No. Series";
}
field(288; "Preferred Bank Account Code"; Code[20])
{
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
// ------------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -388,6 +388,12 @@ page 26 "Vendor Card"
ApplicationArea = Basic, Suite;
Importance = Additional;
}
field("Self-Billing Invoice Nos."; Rec."Self-Billing Invoice Nos.")
{
ApplicationArea = Basic, Suite;
Importance = Additional;
Enabled = Rec."Self-Billing Agreement";
}
field("Price Calculation Method"; Rec."Price Calculation Method")
{
Visible = ExtendedPriceEnabled;
Expand Down
32 changes: 25 additions & 7 deletions src/Layers/BE/BaseApp/Purchases/Posting/PurchPost.Codeunit.al
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,7 @@ codeunit 90 "Purch.-Post"
ItemChargeZeroAmountErr: Label 'The amount for item charge %1 cannot be 0.', Comment = '%1 = Item Charge No.';
ConfirmUsageWithBlankLineTypeQst: Label 'Usage will not be linked to the project planning line because the Line Type field is empty.\\Do you want to continue?';
ConfirmUsageWithBlankJobPlanningLineNoQst: Label 'Usage will not be linked to the project planning line because the Project Planning Line No field is empty.\\Do you want to continue?';
SelfBillingNoSeriesMissingErr: Label 'Specify a number series for self-billing invoices in the %1 field on vendor %2, or in the %3 field in %4.', Comment = '%1 = Self-Billing Invoice Nos. field caption, %2 = Vendor No., %3 = Posted Self-Billing Inv. Nos. field caption, %4 = Purchases & Payables Setup table caption';

/// <summary>
/// Generates a record id for an 'empty' line
Expand Down Expand Up @@ -3044,10 +3045,7 @@ codeunit 90 "Purch.-Post"
ResetPostingNoSeriesFromSetup(PurchHeader."Posting No. Series", PurchSetup."Posted Credit Memo Nos.")
else
if (PurchHeader."Document Type" <> PurchHeader."Document Type"::"Credit Memo") then
if PurchHeader."Self-Billing Invoice" then
ResetPostingNoSeriesFromSetup(PurchHeader."Posting No. Series", PurchSetup."Posted Self-Billing Inv. Nos.")
else
ResetPostingNoSeriesFromSetup(PurchHeader."Posting No. Series", PurchSetup."Posted Invoice Nos.");
ResetPostingNoSeriesFromSetup(PurchHeader."Posting No. Series", PurchSetup."Posted Invoice Nos.");
if PurchHeader."Document Type" = PurchHeader."Document Type"::"Credit Memo" then
if (PurchSetup."Posted Credit Memo Nos." <> '') and (PurchHeader."Posting No. Series" = '') then
CheckDefaultNoSeries(PurchSetup."Posted Credit Memo Nos.");
Expand Down Expand Up @@ -8951,18 +8949,38 @@ codeunit 90 "Purch.-Post"

local procedure UpdateVendorInvoiceNoForSelfBilling(var PurchHeader: Record "Purchase Header")
var
Vendor: Record Vendor;
NoSeries: Codeunit "No. Series";
SelfBillingNoSeriesCode: Code[20];
begin
if not (PurchHeader."Document Type" in [PurchHeader."Document Type"::Invoice, PurchHeader."Document Type"::Order]) then
exit;

PurchSetup.GetRecordOnce();
PurchSetup.TestField("Posted Self-Billing Inv. Nos.");
SelfBillingNoSeriesCode := GetSelfBillingInvoiceNoSeries(PurchHeader);
if SelfBillingNoSeriesCode = '' then
Error(
SelfBillingNoSeriesMissingErr,
Vendor.FieldCaption("Self-Billing Invoice Nos."),
PurchHeader."Buy-from Vendor No.",
PurchSetup.FieldCaption("Posted Self-Billing Inv. Nos."),
PurchSetup.TableCaption());

if PreviewMode then
PurchHeader."Vendor Invoice No." := PostingPreviewNoTok
else
PurchHeader."Vendor Invoice No." := NoSeries.GetNextNo(PurchSetup."Posted Self-Billing Inv. Nos.", PurchHeader."Posting Date");
PurchHeader."Vendor Invoice No." := NoSeries.GetNextNo(SelfBillingNoSeriesCode, PurchHeader."Posting Date");
end;

local procedure GetSelfBillingInvoiceNoSeries(PurchHeader: Record "Purchase Header"): Code[20]
var
Vendor: Record Vendor;
begin
Vendor.SetLoadFields("Self-Billing Invoice Nos.");
if Vendor.Get(PurchHeader."Buy-from Vendor No.") and (Vendor."Self-Billing Invoice Nos." <> '') then
exit(Vendor."Self-Billing Invoice Nos.");

PurchSetup.GetRecordOnce();
exit(PurchSetup."Posted Self-Billing Inv. Nos.");
end;

local procedure SelfBillingInvoiceDocument(PurchHeader: Record "Purchase Header"): Boolean
Expand Down
12 changes: 12 additions & 0 deletions src/Layers/BE/BaseApp/Purchases/Vendor/Vendor.Table.al
Original file line number Diff line number Diff line change
Expand Up @@ -1282,6 +1282,18 @@ table 23 Vendor
{
Caption = 'Self-Billing Agreement';
ToolTip = 'Specifies the value of the Self-Billing Agreement field.';

trigger OnValidate()
begin
if not Rec."Self-Billing Agreement" then
Rec.TestField("Self-Billing Invoice Nos.", '');
end;
}
field(181; "Self-Billing Invoice Nos."; Code[20])
{
Caption = 'Self-Billing Invoice Nos.';
ToolTip = 'Specifies the number series that is used to assign numbers to self-billed purchase invoices for this vendor. If it is empty, the number series from the Posted Self-Billing Inv. Nos. field in Purchases & Payables Setup is used.';
TableRelation = "No. Series";
}
field(288; "Preferred Bank Account Code"; Code[20])
{
Expand Down
6 changes: 6 additions & 0 deletions src/Layers/BE/BaseApp/Purchases/Vendor/VendorCard.Page.al
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,12 @@ page 26 "Vendor Card"
ApplicationArea = Basic, Suite;
Importance = Additional;
}
field("Self-Billing Invoice Nos."; Rec."Self-Billing Invoice Nos.")
{
ApplicationArea = Basic, Suite;
Importance = Additional;
Enabled = Rec."Self-Billing Agreement";
}
field("Price Calculation Method"; Rec."Price Calculation Method")
{
Visible = ExtendedPriceEnabled;
Expand Down
138 changes: 138 additions & 0 deletions src/Layers/CA/Tests/ERM/PurchaseDocuments.Codeunit.al
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ codeunit 134099 "Purchase Documents"
DocAmountFieldVisibleErr: Label 'The field %1 should be visible on the purchase invoice page.', Comment = '%1 = Field Caption';
PurchaseInvoiceSelfBillingErr: Label 'Posted purchase invoice is not marked as self-billing invoice';
SelfBillingInvoiceReportCaptionLbl: Label 'Self Billing Invoice ';
SelfBillingNoSeriesMissingErr: Label 'Specify a number series for self-billing invoices in the %1 field on vendor %2, or in the %3 field in %4.', Comment = '%1 = Self-Billing Invoice Nos. field caption, %2 = Vendor No., %3 = Posted Self-Billing Inv. Nos. field caption, %4 = Purchases & Payables Setup table caption';

[Test]
[HandlerFunctions('RecallNotificationHandler,SendNotificationHandler')]
Expand Down Expand Up @@ -2173,6 +2174,143 @@ codeunit 134099 "Purchase Documents"
LibraryReportDataset.AssertElementWithValueExists('SelfBillingCaption', SelfBillingInvoiceReportCaptionLbl);
end;

[Test]
procedure PurchPostUsesVendorSelfBillingNoSeriesOverGlobal()
var
PurchHeader: Record "Purchase Header";
PurchaseLine: Record "Purchase Line";
PurchInvHeader: Record "Purch. Inv. Header";
PurchasesPayablesSetup: Record "Purchases & Payables Setup";
Vendor: Record Vendor;
VendorNoSeriesLine: Record "No. Series Line";
GlobalNoSeriesLine: Record "No. Series Line";
GlobalNoSeriesCode: Code[20];
VendorNoSeriesCode: Code[20];
SelfBillingInvoiceNo: Code[20];
begin
// [FEATURE] [Self-Billing]
// [SCENARIO 626320] When a vendor has "Self-Billing Invoice Nos.", posting uses the vendor series instead of the setup series.
Initialize();

// [GIVEN] A global number series is set in "Posted Self-Billing Inv. Nos." in Purchases & Payables Setup.
GlobalNoSeriesCode := LibraryERM.CreateNoSeriesCode();
PurchasesPayablesSetup.Get();
PurchasesPayablesSetup.Validate("Posted Self-Billing Inv. Nos.", GlobalNoSeriesCode);
PurchasesPayablesSetup.Modify(true);

// [GIVEN] A self-billing vendor has its own value in "Self-Billing Invoice Nos.".
VendorNoSeriesCode := LibraryERM.CreateNoSeriesCode();
LibraryPurchase.CreateVendor(Vendor);
Vendor.Validate("Self-Billing Agreement", true);
Vendor.Validate("Self-Billing Invoice Nos.", VendorNoSeriesCode);
Vendor.Modify(true);

// [GIVEN] A purchase invoice is created for the vendor with an empty "Vendor Invoice No.".
LibraryPurchase.CreatePurchHeader(PurchHeader, PurchHeader."Document Type"::Invoice, Vendor."No.");
LibraryPurchase.CreatePurchaseLine(PurchaseLine, PurchHeader, PurchaseLine.Type::Item, LibraryInventory.CreateItemNo(), 1);

// [WHEN] The purchase document is posted.
SelfBillingInvoiceNo := LibraryPurchase.PostPurchaseDocument(PurchHeader, true, true);

// [THEN] "Vendor Invoice No." is assigned from the vendor-specific number series.
PurchInvHeader.Get(SelfBillingInvoiceNo);
VendorNoSeriesLine.SetRange("Series Code", VendorNoSeriesCode);
VendorNoSeriesLine.FindFirst();
Assert.AreEqual(VendorNoSeriesLine."Last No. Used", PurchInvHeader."Vendor Invoice No.", PurchInvHeader.FieldCaption("Vendor Invoice No."));

// [THEN] The global self-billing number series is not used.
GlobalNoSeriesLine.SetRange("Series Code", GlobalNoSeriesCode);
GlobalNoSeriesLine.FindFirst();
Assert.AreEqual('', GlobalNoSeriesLine."Last No. Used", 'The global self-billing number series should not be used when the vendor has its own series.');
end;

[Test]
procedure PurchPostSelfBillingFailsWithoutAnyNoSeries()
var
PurchHeader: Record "Purchase Header";
PurchaseLine: Record "Purchase Line";
PurchasesPayablesSetup: Record "Purchases & Payables Setup";
Vendor: Record Vendor;
begin
// [FEATURE] [Self-Billing]
// [SCENARIO 626320] Posting fails when neither vendor nor setup defines a self-billing number series.
Initialize();

// [GIVEN] "Posted Self-Billing Inv. Nos." in Purchases & Payables Setup is empty.
PurchasesPayablesSetup.Get();
PurchasesPayablesSetup.Validate("Posted Self-Billing Inv. Nos.", '');
PurchasesPayablesSetup.Modify(true);

// [GIVEN] A self-billing vendor has no value in "Self-Billing Invoice Nos."
LibraryPurchase.CreateVendor(Vendor);
Vendor.Validate("Self-Billing Agreement", true);
Vendor.Modify(true);

// [GIVEN] A purchase invoice is created for the vendor.
LibraryPurchase.CreatePurchHeader(PurchHeader, PurchHeader."Document Type"::Invoice, Vendor."No.");
LibraryPurchase.CreatePurchaseLine(PurchaseLine, PurchHeader, PurchaseLine.Type::Item, LibraryInventory.CreateItemNo(), 1);

// [WHEN] The purchase document is posted.
asserterror LibraryPurchase.PostPurchaseDocument(PurchHeader, true, true);

// [THEN] Posting fails with the self-billing number series error that identifies the vendor and setup fields.
Assert.ExpectedError(
StrSubstNo(
SelfBillingNoSeriesMissingErr,
Vendor.FieldCaption("Self-Billing Invoice Nos."),
Vendor."No.",
PurchasesPayablesSetup.FieldCaption("Posted Self-Billing Inv. Nos."),
PurchasesPayablesSetup.TableCaption()));
end;

[Test]
procedure SelfBillingAgreementCannotBeDisabledWhileNoSeriesIsSet()
var
Vendor: Record Vendor;
begin
// [FEATURE] [Self-Billing]
// [SCENARIO 626320] "Self-Billing Agreement" cannot be turned off while the vendor still has a "Self-Billing Invoice Nos." series.
Initialize();

// [GIVEN] A self-billing vendor that has a vendor-specific "Self-Billing Invoice Nos." series assigned.
LibraryPurchase.CreateVendor(Vendor);
Vendor.Validate("Self-Billing Agreement", true);
Vendor.Validate("Self-Billing Invoice Nos.", LibraryERM.CreateNoSeriesCode());
Vendor.Modify(true);

// [WHEN] Disabling "Self-Billing Agreement" without first clearing the number series.
asserterror Vendor.Validate("Self-Billing Agreement", false);

// [THEN] Validation fails, requiring "Self-Billing Invoice Nos." to be blank before the agreement can be disabled.
Assert.ExpectedError(Vendor.FieldCaption("Self-Billing Invoice Nos."));
end;

[Test]
procedure SelfBillingAgreementCanBeDisabledAfterClearingNoSeries()
var
Vendor: Record Vendor;
begin
// [FEATURE] [Self-Billing]
// [SCENARIO 626320] "Self-Billing Agreement" can be turned off once the "Self-Billing Invoice Nos." series is cleared.
Initialize();

// [GIVEN] A self-billing vendor that has a vendor-specific "Self-Billing Invoice Nos." series assigned.
LibraryPurchase.CreateVendor(Vendor);
Vendor.Validate("Self-Billing Agreement", true);
Vendor.Validate("Self-Billing Invoice Nos.", LibraryERM.CreateNoSeriesCode());
Vendor.Modify(true);

// [GIVEN] The vendor-specific number series is cleared.
Vendor.Validate("Self-Billing Invoice Nos.", '');

// [WHEN] Disabling "Self-Billing Agreement".
Vendor.Validate("Self-Billing Agreement", false);

// [THEN] The agreement is disabled and the number series stays blank.
Vendor.TestField("Self-Billing Agreement", false);
Vendor.TestField("Self-Billing Invoice Nos.", '');
end;

local procedure Initialize()
var
ReportSelections: Record "Report Selections";
Expand Down
Loading
Loading