From 7515abdb4fd0dbb201f0e2ad71bd5ab0bdb7e1cc Mon Sep 17 00:00:00 2001 From: Jeffrey Bulanadi Date: Tue, 21 Apr 2026 13:27:57 +0800 Subject: [PATCH 1/2] fix: improve Subscription Billing performance for large datasets (#7690) Root causes addressed: 1. Missing database indexes causing full table scans on 4M+ billing lines 2. No progress dialog in billing proposal creation (unusable at scale) 3. Window.Open/Close/Update calls not guarded with GuiAllowed (Job Queue failures) 4. GetBillingLineNo() called inside UsageDataBilling inner loop (N^2 queries) 5. CustomerContract/VendorContract.Get() called for every billing line (millions of round-trips) 6. No per-document Commit() leaving entire run as one giant transaction Changes: - BillingLine.Table.al: add SK7 (Partner, ContractNo, ContractLineNo, DocType, DocNo) covering the GetBillingLineNo() and UsageDataBilling query patterns - SubscriptionLine.Table.al: add Key4 (Partner, ContractNo, NextBillingDate) covering the ProcessContractServiceCommitments filter pattern - UsageDataBilling.Table.al: add key2 (Partner, ContractNo, ContractLineNo, DocType, DocNo) enabling efficient Usage Based Billing document-save lookups - UsageDataGenericImport.Table.al: add key2 (UsageDataImportEntryNo, ProcessingStatus) enabling efficient status-filtered queries on import lines - BillingProposal.Codeunit.al: add progress dialog (BillingProposalProgressTxt) showing contract no., partner no., and processed/total count; guard all Message/Page.Run with if GuiAllowed to allow Job Queue execution - CreateBillingDocuments.Codeunit.al: - Wrap all Window.Open/Close/Update with if GuiAllowed - Wrap ProcessingFinishedMessage with if GuiAllowed - Add Commit() after each completed billing document in all four document-creation procedures (PerContract/PerCustomer for Sales; PerContract/PerVendor for Purchase) to create recovery points and reduce transaction size - Hoist GetBillingLineNo() call outside the UsageDataBilling FindSet() loop in both InsertSalesLineFromTempBillingLine and InsertPurchaseLineFromTempBillingLine; the result is constant within a given document line so calling it once is correct - Cache CustomerContract.Get() and VendorContract.Get() in CreateTempBillingLines using a last-seen contract no. variable; reduces O(n) Get() calls to O(distinct contracts) with zero behavioral change - Extend ProgressTxt label with a third field showing contracts-processed count Fixes #7690 --- .../Codeunits/BillingProposal.Codeunit.al | 42 +++++++++- .../CreateBillingDocuments.Codeunit.al | 79 ++++++++++++++----- .../App/Billing/Tables/BillingLine.Table.al | 3 + .../Tables/SubscriptionLine.Table.al | 3 + .../Tables/UsageDataBilling.Table.al | 3 + .../Tables/UsageDataGenericImport.Table.al | 3 + 6 files changed, 111 insertions(+), 22 deletions(-) diff --git a/src/Apps/W1/Subscription Billing/App/Billing/Codeunits/BillingProposal.Codeunit.al b/src/Apps/W1/Subscription Billing/App/Billing/Codeunits/BillingProposal.Codeunit.al index f00cf2b49c7..b6b7f78ff0c 100644 --- a/src/Apps/W1/Subscription Billing/App/Billing/Codeunits/BillingProposal.Codeunit.al +++ b/src/Apps/W1/Subscription Billing/App/Billing/Codeunits/BillingProposal.Codeunit.al @@ -26,6 +26,7 @@ codeunit 8062 "Billing Proposal" PurchaseCreditMemoExistsForBillingLineQst: Label 'There is a purchase credit memo that needs to be posted before an invoice can be created. Do you want to open the credit memo?'; BillingLinesForAllContractLinesExistsErr: Label 'There are billing lines for all contract lines. For contract lines with billing lines, the invoice must be created in recurring billing.'; NotAuthorizedToClearOrDeleteDocumentErr: Label 'You are not authorized to clear billing templates or delete billing documents. To perform these actions, you must be set up as an Auto Contract Billing user in the User Setup.'; + BillingProposalProgressTxt: Label 'Creating Billing Proposal...\Contract No. #1#################################\Partner No. #2#################################\Processed: #3########## / #4##########', Comment = '%1=Contract No., %2=Partner No., %3=Contracts processed, %4=Total contracts'; procedure InitTempTable(var TempBillingLine: Record "Billing Line" temporary; GroupBy: Enum "Contract Billing Grouping") var @@ -154,8 +155,11 @@ codeunit 8062 "Billing Proposal" BillingTemplate: Record "Billing Template"; CustomerContract: Record "Customer Subscription Contract"; VendorContract: Record "Vendor Subscription Contract"; + ProposalWindow: Dialog; FilterText: Text; BillingRhythmFilterText: Text; + TotalContractsCount: Integer; + ContractCounter: Integer; begin SalesHeaderGlobal.Reset(); BillingTemplate.Get(BillingTemplateCode); @@ -175,20 +179,46 @@ codeunit 8062 "Billing Proposal" if FilterText <> '' then CustomerContract.SetView(FilterText); BillingRhythmFilterText := CustomerContract.GetFilter("Billing Rhythm Filter"); + if GuiAllowed then begin + TotalContractsCount := CustomerContract.Count(); + ProposalWindow.Open(BillingProposalProgressTxt); + ProposalWindow.Update(4, TotalContractsCount); + end; if CustomerContract.FindSet() then repeat + ContractCounter += 1; + if GuiAllowed then begin + ProposalWindow.Update(1, CustomerContract."No."); + ProposalWindow.Update(2, CustomerContract."Sell-to Customer No."); + ProposalWindow.Update(3, ContractCounter); + end; ProcessContractServiceCommitments(BillingTemplate, CustomerContract."No.", '', BillingDate, BillingToDate, BillingRhythmFilterText, AutomatedBilling); until CustomerContract.Next() = 0; + if GuiAllowed then + ProposalWindow.Close(); end; "Service Partner"::Vendor: begin if FilterText <> '' then VendorContract.SetView(FilterText); BillingRhythmFilterText := VendorContract.GetFilter("Billing Rhythm Filter"); + if GuiAllowed then begin + TotalContractsCount := VendorContract.Count(); + ProposalWindow.Open(BillingProposalProgressTxt); + ProposalWindow.Update(4, TotalContractsCount); + end; if VendorContract.FindSet() then repeat + ContractCounter += 1; + if GuiAllowed then begin + ProposalWindow.Update(1, VendorContract."No."); + ProposalWindow.Update(2, VendorContract."Pay-to Vendor No."); + ProposalWindow.Update(3, ContractCounter); + end; ProcessContractServiceCommitments(BillingTemplate, VendorContract."No.", '', BillingDate, BillingToDate, BillingRhythmFilterText, AutomatedBilling); until VendorContract.Next() = 0; + if GuiAllowed then + ProposalWindow.Close(); end; end; @@ -200,16 +230,20 @@ codeunit 8062 "Billing Proposal" begin SalesHeaderGlobal.MarkedOnly(true); if SalesHeaderGlobal.Count <> 0 then begin - Page.Run(Page::"Sales Credit Memos", SalesHeaderGlobal); - Message(CreditMemoPreventsProposalCreationLbl); + if GuiAllowed then + Page.Run(Page::"Sales Credit Memos", SalesHeaderGlobal); + if GuiAllowed then + Message(CreditMemoPreventsProposalCreationLbl); end; end; Enum::"Service Partner"::Vendor: begin PurchaseHeaderGlobal.MarkedOnly(true); if PurchaseHeaderGlobal.Count <> 0 then begin - Page.Run(Page::"Purchase Credit Memos", PurchaseHeaderGlobal); - Message(CreditMemoPreventsProposalCreationLbl); + if GuiAllowed then + Page.Run(Page::"Purchase Credit Memos", PurchaseHeaderGlobal); + if GuiAllowed then + Message(CreditMemoPreventsProposalCreationLbl); end; end; end; diff --git a/src/Apps/W1/Subscription Billing/App/Billing/Codeunits/CreateBillingDocuments.Codeunit.al b/src/Apps/W1/Subscription Billing/App/Billing/Codeunits/CreateBillingDocuments.Codeunit.al index 57918a38ee5..2f69b573d55 100644 --- a/src/Apps/W1/Subscription Billing/App/Billing/Codeunits/CreateBillingDocuments.Codeunit.al +++ b/src/Apps/W1/Subscription Billing/App/Billing/Codeunits/CreateBillingDocuments.Codeunit.al @@ -34,15 +34,18 @@ codeunit 8060 "Create Billing Documents" if not RequestPageSelectionConfirmed() then exit; - Window.Open(ProgressTxt); - Window.Update(); + if GuiAllowed then begin + Window.Open(ProgressTxt); + Window.Update(); + end; if AutomatedBilling then BillingLine.SetRange("Billing Error Log Entry No.", 0) else BillingLine.ModifyAll("Billing Error Log Entry No.", 0); ProcessBillingLines(BillingLine); - Window.Close(); + if GuiAllowed then + Window.Close(); if PostDocuments then PostCreatedDocuments(); if not HideProcessingFinishedMessage then @@ -89,17 +92,24 @@ codeunit 8060 "Create Billing Documents" repeat if IsNewHeaderNeededPerContract(PreviousContractNo) then begin TestPreviousDocumentTotalInvoiceAmount(true, DiscountLineExists, PreviousContractNo); + if PreviousContractNo <> '' then + Commit(); CustomerContract.Get(TempBillingLine."Subscription Contract No."); CreateSalesHeaderFromContract(CustomerContract); InsertContractDescriptionSalesLines(TempBillingLine); PreviousContractNo := TempBillingLine."Subscription Contract No."; ContractsProcessedCount += 1; - Window.Update(1, CustomerContract."Sell-to Customer No."); - Window.Update(2, PreviousContractNo); + if GuiAllowed then begin + Window.Update(1, CustomerContract."Sell-to Customer No."); + Window.Update(2, PreviousContractNo); + Window.Update(3, ContractsProcessedCount); + end; end; InsertSalesLineFromTempBillingLine(); until TempBillingLine.Next() = 0; TestPreviousDocumentTotalInvoiceAmount(true, DiscountLineExists, PreviousContractNo); + if PreviousContractNo <> '' then + Commit(); end; local procedure CreatePurchaseDocumentsPerContract() @@ -117,17 +127,24 @@ codeunit 8060 "Create Billing Documents" repeat if IsNewHeaderNeededPerContract(PreviousContractNo) then begin TestPreviousDocumentTotalInvoiceAmount(false, DiscountLineExists, PreviousContractNo); + if PreviousContractNo <> '' then + Commit(); VendorContract.Get(TempBillingLine."Subscription Contract No."); CreatePurchaseHeaderFromContract(VendorContract); InsertContractDescriptionPurchaseLines(TempBillingLine); PreviousContractNo := TempBillingLine."Subscription Contract No."; ContractsProcessedCount += 1; - Window.Update(1, VendorContract."Pay-to Vendor No."); - Window.Update(2, PreviousContractNo); + if GuiAllowed then begin + Window.Update(1, VendorContract."Pay-to Vendor No."); + Window.Update(2, PreviousContractNo); + Window.Update(3, ContractsProcessedCount); + end; end; InsertPurchaseLineFromTempBillingLine(); until TempBillingLine.Next() = 0; TestPreviousDocumentTotalInvoiceAmount(false, DiscountLineExists, PreviousContractNo); + if PreviousContractNo <> '' then + Commit(); end; local procedure CreateSalesDocumentsPerCustomer() @@ -149,13 +166,16 @@ codeunit 8060 "Create Billing Documents" repeat if IsNewSalesHeaderNeeded(PreviousCustomerNo, LastDetailOverview, PreviousCurrencyCode, PreviousContractNo) then begin TestPreviousDocumentTotalInvoiceAmount(true, DiscountLineExists, PreviousContractNo); + if PreviousCustomerNo <> '' then + Commit(); CreateSalesHeaderForCustomerNo(TempBillingLine."Partner No."); SalesHeader."Sub. Contract Detail Overview" := TempBillingLine."Detail Overview"; SalesHeader.Modify(false); PreviousCustomerNo := TempBillingLine."Partner No."; LastDetailOverview := TempBillingLine."Detail Overview"; PreviousCurrencyCode := TempBillingLine."Currency Code"; - Window.Update(1, PreviousCustomerNo); + if GuiAllowed then + Window.Update(1, PreviousCustomerNo); FirstContractDescriptionLineInserted := false; end; if TempBillingLine."Subscription Contract No." <> PreviousContractNo then begin @@ -168,11 +188,16 @@ codeunit 8060 "Create Billing Documents" end; PreviousContractNo := TempBillingLine."Subscription Contract No."; ContractsProcessedCount += 1; - Window.Update(2, PreviousContractNo); + if GuiAllowed then begin + Window.Update(2, PreviousContractNo); + Window.Update(3, ContractsProcessedCount); + end; end; InsertSalesLineFromTempBillingLine(); until TempBillingLine.Next() = 0; TestPreviousDocumentTotalInvoiceAmount(true, DiscountLineExists, PreviousContractNo); + if PreviousCustomerNo <> '' then + Commit(); end; local procedure CreatePurchaseDocumentsPerVendor() @@ -195,10 +220,13 @@ codeunit 8060 "Create Billing Documents" (TempBillingLine."Currency Code" <> PreviousCurrencyCode) then begin TestPreviousDocumentTotalInvoiceAmount(false, DiscountLineExists, PreviousContractNo); + if PreviousVendorNo <> '' then + Commit(); CreatePurchaseHeaderForVendorNo(TempBillingLine."Partner No."); PreviousVendorNo := TempBillingLine."Partner No."; PreviousCurrencyCode := TempBillingLine."Currency Code"; - Window.Update(1, PreviousVendorNo); + if GuiAllowed then + Window.Update(1, PreviousVendorNo); FirstContractDescriptionLineInserted := false; end; if TempBillingLine."Subscription Contract No." <> PreviousContractNo then begin @@ -211,11 +239,16 @@ codeunit 8060 "Create Billing Documents" end; PreviousContractNo := TempBillingLine."Subscription Contract No."; ContractsProcessedCount += 1; - Window.Update(2, PreviousContractNo); + if GuiAllowed then begin + Window.Update(2, PreviousContractNo); + Window.Update(3, ContractsProcessedCount); + end; end; InsertPurchaseLineFromTempBillingLine(); until TempBillingLine.Next() = 0; TestPreviousDocumentTotalInvoiceAmount(false, DiscountLineExists, PreviousContractNo); + if PreviousVendorNo <> '' then + Commit(); end; local procedure InsertSalesLineFromTempBillingLine() @@ -302,10 +335,10 @@ codeunit 8060 "Create Billing Documents" UsageDataBilling.SetRange("Subscription Contract Line No.", CustomerContractLine."Line No."); UsageDataBilling.SetRange("Document Type", Enum::"Usage Based Billing Doc. Type"::None); UsageDataBilling.SetRange("Document No.", ''); + BillingLineNo := GetBillingLineNo(BillingLine.GetBillingDocumentTypeFromSalesDocumentType(SalesLine."Document Type"), + "Service Partner"::Customer, SalesLine."Document No.", CustomerContractLine."Subscription Contract No.", CustomerContractLine."Line No."); if UsageDataBilling.FindSet() then repeat - BillingLineNo := GetBillingLineNo(BillingLine.GetBillingDocumentTypeFromSalesDocumentType(SalesLine."Document Type"), - "Service Partner"::Customer, SalesLine."Document No.", CustomerContractLine."Subscription Contract No.", CustomerContractLine."Line No."); UsageDataBilling.SaveDocumentValues(UsageBasedDocTypeConv.ConvertSalesDocTypeToUsageBasedBillingDocType(SalesLine."Document Type"), SalesLine."Document No.", SalesLine."Line No.", BillingLineNo); until UsageDataBilling.Next() = 0; @@ -411,10 +444,10 @@ codeunit 8060 "Create Billing Documents" UsageDataBilling.SetRange("Subscription Contract Line No.", ServiceCommitment."Subscription Contract Line No."); UsageDataBilling.SetRange("Document Type", Enum::"Usage Based Billing Doc. Type"::None); UsageDataBilling.SetRange("Document No.", ''); + BillingLineNo := GetBillingLineNo(BillingLine.GetBillingDocumentTypeFromPurchaseDocumentType(PurchaseLine."Document Type"), + "Service Partner"::Vendor, PurchaseLine."Document No.", ServiceCommitment."Subscription Contract No.", ServiceCommitment."Subscription Contract Line No."); if UsageDataBilling.FindSet() then repeat - BillingLineNo := GetBillingLineNo(BillingLine.GetBillingDocumentTypeFromPurchaseDocumentType(PurchaseLine."Document Type"), - "Service Partner"::Vendor, PurchaseLine."Document No.", ServiceCommitment."Subscription Contract No.", ServiceCommitment."Subscription Contract Line No."); UsageDataBilling.SaveDocumentValues(UsageBasedDocTypeConv.ConvertPurchaseDocTypeToUsageBasedBillingDocType(PurchaseLine."Document Type"), PurchaseLine."Document No.", PurchaseLine."Line No.", BillingLineNo); until UsageDataBilling.Next() = 0; @@ -726,13 +759,18 @@ codeunit 8060 "Create Billing Documents" CurrencyCode: Code[20]; PartnerNo: Code[20]; LineNo: Integer; + CachedCustomerContractNo: Code[20]; + CachedVendorContractNo: Code[20]; begin if BillingLine.FindSet() then repeat case BillingLine.Partner of BillingLine.Partner::Customer: begin - CustomerContract.Get(BillingLine."Subscription Contract No."); + if BillingLine."Subscription Contract No." <> CachedCustomerContractNo then begin + CustomerContract.Get(BillingLine."Subscription Contract No."); + CachedCustomerContractNo := BillingLine."Subscription Contract No."; + end; case CustomerRecurringBillingGrouping of CustomerRecurringBillingGrouping::"Sell-to Customer No.": PartnerNo := CustomerContract."Sell-to Customer No."; @@ -743,7 +781,10 @@ codeunit 8060 "Create Billing Documents" end; BillingLine.Partner::Vendor: begin - VendorContract.Get(BillingLine."Subscription Contract No."); + if BillingLine."Subscription Contract No." <> CachedVendorContractNo then begin + VendorContract.Get(BillingLine."Subscription Contract No."); + CachedVendorContractNo := BillingLine."Subscription Contract No."; + end; case VendorRecurringBillingGrouping of VendorRecurringBillingGrouping::"Pay-to Vendor No.": PartnerNo := VendorContract."Pay-to Vendor No."; @@ -1030,6 +1071,8 @@ codeunit 8060 "Create Billing Documents" local procedure ProcessingFinishedMessage() begin + if not GuiAllowed then + exit; if DocumentsCreatedCount = 0 then Message(NoDocumentsCreatedMsg) else @@ -1404,7 +1447,7 @@ codeunit 8060 "Create Billing Documents" PostDocuments: Boolean; HideProcessingFinishedMessage: Boolean; Window: Dialog; - ProgressTxt: Label 'Creating documents...\Partner No. #1#################################\Contract No. #2#################################', Comment = '%1=Partner No., %2=Contract No.'; + ProgressTxt: Label 'Creating documents...\Partner No. #1#################################\Contract No. #2#################################\Contracts processed: #3##########', Comment = '%1=Partner No., %2=Contract No., %3=Contracts processed'; OnlyOneServicePartnerErr: Label 'You can create documents only for one type of partner at a time (Customer or Vendor). Please check your filters.'; UpdateRequiredErr: Label 'At least one Subscription Line was changed after billing proposal was created. Please check the lines marked with "Update Required" field and update the billing proposal before the billing documents can be created.'; BillingPeriodDescriptionTxt: Label 'Billing period: %1 to %2', Comment = '%1=Recurring Billing from, %2=Recurring Billing to'; diff --git a/src/Apps/W1/Subscription Billing/App/Billing/Tables/BillingLine.Table.al b/src/Apps/W1/Subscription Billing/App/Billing/Tables/BillingLine.Table.al index cc22098ed6d..c0027185482 100644 --- a/src/Apps/W1/Subscription Billing/App/Billing/Tables/BillingLine.Table.al +++ b/src/Apps/W1/Subscription Billing/App/Billing/Tables/BillingLine.Table.al @@ -243,6 +243,9 @@ table 8061 "Billing Line" key(SK6; "Billing Template Code", Partner) { } + key(SK7; Partner, "Subscription Contract No.", "Subscription Contract Line No.", "Document Type", "Document No.") + { + } } trigger OnDelete() diff --git a/src/Apps/W1/Subscription Billing/App/Service Commitments/Tables/SubscriptionLine.Table.al b/src/Apps/W1/Subscription Billing/App/Service Commitments/Tables/SubscriptionLine.Table.al index 541b482c7a6..2770d44b826 100644 --- a/src/Apps/W1/Subscription Billing/App/Service Commitments/Tables/SubscriptionLine.Table.al +++ b/src/Apps/W1/Subscription Billing/App/Service Commitments/Tables/SubscriptionLine.Table.al @@ -611,6 +611,9 @@ table 8059 "Subscription Line" { } + key(Key4; Partner, "Subscription Contract No.", "Next Billing Date") + { + } } trigger OnInsert() diff --git a/src/Apps/W1/Subscription Billing/App/Usage Based Billing/Tables/UsageDataBilling.Table.al b/src/Apps/W1/Subscription Billing/App/Usage Based Billing/Tables/UsageDataBilling.Table.al index 760ebec406c..03f6eea098d 100644 --- a/src/Apps/W1/Subscription Billing/App/Usage Based Billing/Tables/UsageDataBilling.Table.al +++ b/src/Apps/W1/Subscription Billing/App/Usage Based Billing/Tables/UsageDataBilling.Table.al @@ -300,6 +300,9 @@ table 8006 "Usage Data Billing" SumIndexFields = Quantity, Amount; MaintainSiftIndex = true; } + key(key2; Partner, "Subscription Contract No.", "Subscription Contract Line No.", "Document Type", "Document No.") + { + } } trigger OnInsert() diff --git a/src/Apps/W1/Subscription Billing/App/Usage Based Billing/Tables/UsageDataGenericImport.Table.al b/src/Apps/W1/Subscription Billing/App/Usage Based Billing/Tables/UsageDataGenericImport.Table.al index d4c67323915..09b7ff7ac21 100644 --- a/src/Apps/W1/Subscription Billing/App/Usage Based Billing/Tables/UsageDataGenericImport.Table.al +++ b/src/Apps/W1/Subscription Billing/App/Usage Based Billing/Tables/UsageDataGenericImport.Table.al @@ -306,6 +306,9 @@ table 8018 "Usage Data Generic Import" { Clustered = true; } + key(key2; "Usage Data Import Entry No.", "Processing Status") + { + } } trigger OnInsert() From 70ef7ff5fbb75d56e51eb69be1b91061ef983464 Mon Sep 17 00:00:00 2001 From: Jeffrey Bulanadi <41933086+jeffreybulanadi@users.noreply.github.com> Date: Tue, 5 May 2026 04:26:07 +0800 Subject: [PATCH 2/2] Subscription Billing: reorder index keys to lead with high-cardinality fields - BillingLine SK7: move Subscription Contract No. and Subscription Contract Line No. before Document Type and Partner. Contract No. is a Code[20] field with high cardinality and narrows the result set far more efficiently than the Partner enum (2 values) as the leading column. - SubscriptionLine Key4: move Subscription Contract No. before Partner and Next Billing Date. ProcessContractServiceCommitments always filters by Contract No., making it the most selective leading field. - UsageDataBilling key2: same rationale as SK7. Subscription Contract No. leads, followed by Contract Line No. and Document No. (both high cardinality), with Document Type and Partner at the end. - UsageDataBilling key3: add index on Usage Data Import Entry No. and Document No. to support lookups that associate import records with billing documents. --- .../App/Billing/Tables/BillingLine.Table.al | 2 +- .../App/Service Commitments/Tables/SubscriptionLine.Table.al | 2 +- .../App/Usage Based Billing/Tables/UsageDataBilling.Table.al | 5 ++++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Apps/W1/Subscription Billing/App/Billing/Tables/BillingLine.Table.al b/src/Apps/W1/Subscription Billing/App/Billing/Tables/BillingLine.Table.al index c0027185482..cd9f160d23a 100644 --- a/src/Apps/W1/Subscription Billing/App/Billing/Tables/BillingLine.Table.al +++ b/src/Apps/W1/Subscription Billing/App/Billing/Tables/BillingLine.Table.al @@ -243,7 +243,7 @@ table 8061 "Billing Line" key(SK6; "Billing Template Code", Partner) { } - key(SK7; Partner, "Subscription Contract No.", "Subscription Contract Line No.", "Document Type", "Document No.") + key(SK7; "Subscription Contract No.", "Subscription Contract Line No.", "Document No.", "Document Type", Partner) { } } diff --git a/src/Apps/W1/Subscription Billing/App/Service Commitments/Tables/SubscriptionLine.Table.al b/src/Apps/W1/Subscription Billing/App/Service Commitments/Tables/SubscriptionLine.Table.al index 2770d44b826..0f40a111f6b 100644 --- a/src/Apps/W1/Subscription Billing/App/Service Commitments/Tables/SubscriptionLine.Table.al +++ b/src/Apps/W1/Subscription Billing/App/Service Commitments/Tables/SubscriptionLine.Table.al @@ -611,7 +611,7 @@ table 8059 "Subscription Line" { } - key(Key4; Partner, "Subscription Contract No.", "Next Billing Date") + key(Key4; "Subscription Contract No.", "Next Billing Date", Partner) { } } diff --git a/src/Apps/W1/Subscription Billing/App/Usage Based Billing/Tables/UsageDataBilling.Table.al b/src/Apps/W1/Subscription Billing/App/Usage Based Billing/Tables/UsageDataBilling.Table.al index 03f6eea098d..768d40b0557 100644 --- a/src/Apps/W1/Subscription Billing/App/Usage Based Billing/Tables/UsageDataBilling.Table.al +++ b/src/Apps/W1/Subscription Billing/App/Usage Based Billing/Tables/UsageDataBilling.Table.al @@ -300,7 +300,10 @@ table 8006 "Usage Data Billing" SumIndexFields = Quantity, Amount; MaintainSiftIndex = true; } - key(key2; Partner, "Subscription Contract No.", "Subscription Contract Line No.", "Document Type", "Document No.") + key(key2; "Subscription Contract No.", "Subscription Contract Line No.", "Document No.", "Document Type", Partner) + { + } + key(key3; "Usage Data Import Entry No.", "Document No.") { }