Skip to content

[Extensibility][SubscriptionBilling]:"Usage Based Pricing" Extensibility #7126

@sirhc101

Description

@sirhc101

Describe the issue

Process Usage Data Billing codeunit supports handling multiple Usage Based Pricing implementations, but due to the missing extensiblilty of the Enum the code will never be executed:

Example 1 - "Process Usage Data Billing".ProcessServiceCommitment()

    local procedure ProcessServiceCommitment(var UsageDataBilling: Record "Usage Data Billing")
    begin
        OnBeforeProcessSubscriptionLine(ServiceCommitment);

        [...]

        case ServiceCommitment."Usage Based Pricing" of
            "Usage Based Pricing"::"Usage Quantity":
                begin
                    NewServiceObjectQuantity := CalculateTotalUsageBillingQuantity(LastUsageDataBilling, UsageDataImport."Entry No.", ServiceCommitment);
                    if NewServiceObjectQuantity <> 0 then begin
                        UnitCost := CalculateSumCostAmountFromUsageDataBilling(LastUsageDataBilling, UsageDataImport."Entry No.", ServiceCommitment) / NewServiceObjectQuantity;
                        if ServiceCommitment.IsPartnerCustomer() then
                            UnitPrice := CalculateSumAmountFromUsageDataBilling(LastUsageDataBilling, UsageDataImport."Entry No.", ServiceCommitment) / NewServiceObjectQuantity;
                    end else begin
                        UnitCost := 0;
                        UnitPrice := 0;
                    end;
                    if LastUsageDataBilling.Rebilling then
                        NewServiceObjectQuantity += ServiceObject."Quantity";
                end;
            "Usage Based Pricing"::"Fixed Quantity":
                ;
            "Usage Based Pricing"::"Unit Cost Surcharge":
                if NewServiceObjectQuantity <> 0 then begin
                    UnitCost := CalculateSumCostAmountFromUsageDataBilling(LastUsageDataBilling, UsageDataImport."Entry No.", ServiceCommitment) / NewServiceObjectQuantity;
                    if ServiceCommitment.IsPartnerCustomer() then
                        UnitPrice := CalculateSumAmountFromUsageDataBilling(LastUsageDataBilling, UsageDataImport."Entry No.", ServiceCommitment) / NewServiceObjectQuantity;
                end else begin
                    UnitCost := 0;
                    UnitPrice := 0;
                end;
            else begin
                // THIS WILL NEVER BE REACHED, DUE TO MISSING CAPABILITY TO EXTEND ENUM
                IsHandled := false;
                OnUsageBasedPricingElseCaseOnProcessSubscriptionLine(UnitCost, NewServiceObjectQuantity, ServiceCommitment, LastUsageDataBilling, IsHandled);
                if not IsHandled then
                    Error(UsageBasedPricingOptionNotImplementedErr, Format(ServiceCommitment."Usage Based Pricing"), ServiceCommitment.FieldCaption("Usage Based Pricing"), CodeunitObjectLbl,
                                                                    CurrentCodeunitNameLbl, ProcessServiceCommitmentProcedureNameLbl);
            end;
        end;

        [...]

    end;

Example 2 - "Process Usage Data Billing".CalculateCustomerUsageDataBillingPrice()

    local procedure CalculateCustomerUsageDataBillingPrice(var UsageDataBilling: Record "Usage Data Billing")
    begin

        [...]

        if UsageDataSupplier."Unit Price from Import" then begin
            UnitPrice := UsageDataBilling."Unit Price";
            Amount := UsageDataBilling.Amount;
        end else
            case UsageDataBilling."Usage Base Pricing" of
                "Usage Based Pricing"::"Usage Quantity":
                    begin
                        Amount := ServiceCommitment.Amount;
                        ServiceObject.Get(ServiceCommitment."Subscription Header No.");
                        ServiceObject.TestField(Type, ServiceObject.Type::Item);
                        ContractItemMgt.GetSalesPriceForItem(UnitPrice, ServiceObject."Source No.", Abs(UsageDataBilling.Quantity), CustomerContract."Currency Code", CustomerContract."Sell-to Customer No.", CustomerContract."Bill-to Customer No.");
                        Amount := UnitPrice * Abs(UsageDataBilling.Quantity);
                        CalculateUsageDataPrices(Amount, UnitPrice, ServiceCommitment, UsageDataBilling, Abs(UsageDataBilling.Quantity));
                    end;
                "Usage Based Pricing"::"Fixed Quantity":
                    begin
                        Amount := ServiceCommitment.Amount;
                        ServiceCommitment.CalcFields("Quantity");
                        CalculateUsageDataPrices(Amount, UnitPrice, ServiceCommitment, UsageDataBilling, ServiceCommitment."Quantity");
                    end;
                "Usage Based Pricing"::"Unit Cost Surcharge":
                    begin
                        UnitPrice := UsageDataBilling."Unit Cost" * (1 + UsageDataBilling."Pricing Unit Cost Surcharge %" / 100);
                        Amount := UnitPrice * UsageDataBilling.Quantity;
                    end;
                else begin
                    // THIS WILL NEVER BE REACHED, DUE TO MISSING CAPABILITY TO EXTEND ENUM
                    IsHandled := false;
                    OnUsageBasedPricingElseCaseOnCalculateCustomerUsageDataBillingPrice(UnitPrice, Amount, UsageDataBilling, CustomerContract, IsHandled);
                    if not IsHandled then
                        Error(UsageBasedPricingOptionNotImplementedErr, Format(ServiceCommitment."Usage Based Pricing"), ServiceCommitment.FieldCaption("Usage Based Pricing"), CodeunitObjectLbl,
                                                                        CurrentCodeunitNameLbl, CalculateCustomerUsageDataBillingPriceProcedureNameLbl);
                end;

            end;

        [...]

    end;

To solve this "Usage Based Pricing" enum should be changed from Extensible = false; to Extensible = true;

namespace Microsoft.SubscriptionBilling;

enum 8007 "Usage Based Pricing"
{
    Extensible = true; // CHANGE TO TRUE, TO ALLOW EXTENSIBILITY

    value(0; None)
    {
        Caption = ' ', Locked = true;
    }
    value(1; "Usage Quantity")
    {
        Caption = 'Usage Quantity';
    }
    value(2; "Fixed Quantity")
    {
        Caption = 'Fixed Quantity';
    }
    value(3; "Unit Cost Surcharge")
    {
        Caption = 'Unit Cost Surcharge';
    }
}

Expected behavior

Extensibility events should NOT just be available, but also been executed and useable. Otherwise they are misleading and useless.

Steps to reproduce

  1. Create EnumExtension for "Usage Based Pricing" Enum

  2. Subscribe to one of the following Event publisher:

    [IntegrationEvent(false, false)]
    local procedure OnUsageBasedPricingElseCaseOnProcessSubscriptionLine(var UnitCost: Decimal; var NewServiceObjectQuantity: Decimal; var SubscriptionLine: Record "Subscription Line"; LastUsageDataBilling: Record "Usage Data Billing"; var IsHandled: Boolean)
    begin
    end;
    
    [IntegrationEvent(false, false)]
    local procedure OnUsageBasedPricingElseCaseOnCalculateCustomerUsageDataBillingPrice(var UnitPrice: Decimal; var Amount: Decimal; var UsageDataBilling: Record "Usage Data Billing"; CustomerSubscriptionContract: Record "Customer Subscription Contract"; var IsHandled: Boolean)
    begin
    end;

Additional context

No response

I will provide a fix for a bug

  • I will provide a fix for a bug

Metadata

Metadata

Assignees

Labels

ApprovedThe issue is approvedFinanceGitHub request for Finance area

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions