Skip to content

[Event request] codeunit 99000774 "Calculate Routing Line" - update capacity for simulated prod. orders #29675

@auzhhv

Description

@auzhhv

Why do you need this change?

Is it possible to add additional events to Codeunit 99000774, "Calculate Routing Line"?

The relevant events are described in the code below.

A customer requires capacity to be calculated based on simulated production orders. We have implemented a solution by using the existing event to override the procedures. However, this approach requires duplicating base application code, which is not ideal—especially with regard to future changes.

Duplicating code increases maintenance effort and risk, and we would prefer not to re-test logic that already exists and is validated in the base application.

Our suggestion is to add events that make it possible to control whether the logic that excludes simulated production orders should be executed. This would allow extensions to adjust the behavior without overriding or duplicating standard code.

local procedure InitProdOrderCapNeed(ProdOrder: Record "Production Order"; var ProdOrderRoutingLine: Record "Prod. Order Routing Line"; var ProdOrderCapNeed: Record "Prod. Order Capacity Need"; TimeType: Enum "Routing Time Type"; NeedDate: Date; StartingTime: Time; EndingTime: Time; NeedQty: Decimal)
    var
        ActuallyPostedTime: Decimal;
        DistributedCapNeed: Decimal;
        // >>>>>>>>>>
        ShouldUpdateAllocatedTimeAndExpectedCapacityNeed: Boolean;
        // <<<<<<<<<<
    begin
        OnBeforeInitProdOrderCapNeed(ProdOrder, ProdOrderRoutingLine, ProdOrderCapNeed, TimeType, NeedDate, StartingTime, EndingTime, NeedQty, LotSize);

        ProdOrderCapNeed.Init();
        ProdOrderCapNeed.Status := ProdOrder.Status;
        ProdOrderCapNeed."Prod. Order No." := ProdOrder."No.";
        ProdOrderCapNeed."Routing No." := ProdOrderRoutingLine."Routing No.";
        ProdOrderCapNeed."Routing Reference No." := ProdOrderRoutingLine."Routing Reference No.";
        ProdOrderCapNeed."Line No." := NextCapNeedLineNo;
        ProdOrderCapNeed.Type := ProdOrderRoutingLine.Type;
        ProdOrderCapNeed."No." := ProdOrderRoutingLine."No.";
        ProdOrderCapNeed."Work Center No." := ProdOrderRoutingLine."Work Center No.";
        ProdOrderCapNeed."Operation No." := ProdOrderRoutingLine."Operation No.";
        ProdOrderCapNeed."Work Center Group Code" := ProdOrderRoutingLine."Work Center Group Code";
        ProdOrderCapNeed.Date := NeedDate;
        ProdOrderCapNeed."Starting Time" := StartingTime;
        ProdOrderCapNeed."Ending Time" := EndingTime;
        ProdOrderCapNeed."Needed Time" := NeedQty;
        ProdOrderCapNeed."Needed Time (ms)" := NeedQty * CalendarMgt.TimeFactor(Workcenter."Unit of Measure Code");
        ProdOrderCapNeed."Concurrent Capacities" := ConCurrCap;
        ProdOrderCapNeed.Efficiency := CalendarEntry.Efficiency;
        ProdOrderCapNeed."Requested Only" := false;
        ProdOrderCapNeed.Active := true;
        // >>>>>>>>>
        //if ProdOrder.Status <> ProdOrder.Status::Simulated then begin
        ShouldUpdateAllocatedTimeAndExpectedCapacityNeed := ProdOrder.Status <> ProdOrder.Status::Simulated;
        OnInitProdOrderCapNeedOnBeforeUpdateAllocatedTimeAndExpectedCapacityNeed(ProdOrderCapNeed; ShouldUpdateAllocatedTimeAndExpectedCapacityNeed)
        if ShouldUpdateAllocatedTimeAndExpectedCapacityNeed then begin
        // <<<<<<<<<
            ActuallyPostedTime := CalcActuallyPostedCapacityTime(ProdOrderRoutingLine, TimeType);
            DistributedCapNeed := CalcDistributedCapacityNeedForOperation(ProdOrderRoutingLine, TimeType);
            ProdOrderCapNeed."Allocated Time" := NeedQty - ActuallyPostedTime + DistributedCapNeed;
            if ProdOrderCapNeed."Allocated Time" < 0 then
                ProdOrderCapNeed."Allocated Time" := 0;
            ProdOrderRoutingLine."Expected Capacity Need" :=
              ProdOrderRoutingLine."Expected Capacity Need" + ProdOrderCapNeed."Needed Time (ms)";
        end;

        OnAfterInitProdOrderCapNeed(ProdOrder, ProdOrderRoutingLine, ProdOrderCapNeed, NeedQty, TimeType, ActuallyPostedTime, DistributedCapNeed);
    end;
    [IntegrationEvent(false, false)]
    local procedure OnInitProdOrderCapNeedOnBeforeUpdateAllocatedTimeAndExpectedCapacityNeed(var ProdOrderCapacityNeed: Record "Prod. Order Capacity Need"; var ShouldUpdateAllocatedTimeAndExpectedCapacityNeed: Boolean)
    begin
    end;   
    local procedure UpdateTimesBack(var AvailTime: Decimal; var AvailCap: Decimal; var TimetoProgram: Decimal; var StartTime: Time; EndTime: Time)
    var
        RoundedTimetoProgram: Decimal;
        IsHandled: Boolean;
        // >>>>>>>>>>
        ShouldUpdateAvailCap: Boolean;
        // <<<<<<<<<<        
    begin
        IsHandled := false;
        OnBeforeUpdateTimesBack(CalendarEntry, ProdOrderRoutingLine, AvailTime, AvailCap, TimetoProgram, StartTime, EndTime, ConCurrCap, Workcenter, RemainNeedQty, IsHandled);
        if IsHandled then
            exit;

        AvailTime :=
          Round(AvailTime / CalendarMgt.TimeFactor(Workcenter."Unit of Measure Code") *
            CalendarEntry.Efficiency / 100 * ConCurrCap, Workcenter."Calendar Rounding Precision");
        TimetoProgram := Min(RemainNeedQty, AvailTime);
        RoundedTimetoProgram :=
          Round(TimetoProgram *
            CalendarMgt.TimeFactor(Workcenter."Unit of Measure Code") *
            100 / CalendarEntry.Efficiency / ConCurrCap, 1, '>');
        StartTime := CalendarMgt.CalcTimeSubtract(EndTime, RoundedTimetoProgram);
        RemainNeedQty := RemainNeedQty - TimetoProgram;
        // >>>>>>>>>>        
        //if ProdOrderRoutingLine.Status <> ProdOrderRoutingLine.Status::Simulated then
        ShouldUpdateAvailCap := ProdOrderRoutingLine.Status <> ProdOrderRoutingLine.Status::Simulated;
        OnUpdateTimesBackOnBeforeUpdateAvailCap(ProdOrderRoutingLine, ShouldUpdateAvailCap);
        if ShouldUpdateAvailCap then
        // <<<<<<<<<<        
            AvailCap := AvailCap - RoundedTimetoProgram;
    end;
    [IntegrationEvent(false, false)]
    local procedure OnUpdateTimesBackOnBeforeUpdateAvailCap(var ProdOrderRoutingLine: Record "Prod. Order Routing Line"; var ShouldUpdateAvailCap: Boolean)
    begin
    end;  
    local procedure UpdateTimesForward(var AvailTime: Decimal; var AvailCap: Decimal; var TimetoProgram: Decimal; StartTime: Time; var EndTime: Time)
    var
        RoundedTimetoProgram: Decimal;
        IsHandled: Boolean;
        // >>>>>>>>>>
        ShouldUpdateAvailCap: Boolean;
        // <<<<<<<<<<           
    begin
        IsHandled := false;
        OnBeforeUpdateTimesForward(CalendarEntry, ProdOrderRoutingLine, AvailTime, AvailCap, TimetoProgram, StartTime, EndTime, ConCurrCap, Workcenter, RemainNeedQty, IsHandled);
        if IsHandled then
            exit;

        AvailTime :=
          Round(AvailTime / CalendarMgt.TimeFactor(Workcenter."Unit of Measure Code") *
            CalendarEntry.Efficiency / 100 * ConCurrCap, Workcenter."Calendar Rounding Precision");
        TimetoProgram := Min(RemainNeedQty, AvailTime);
        RoundedTimetoProgram :=
          Round(TimetoProgram *
            CalendarMgt.TimeFactor(Workcenter."Unit of Measure Code") *
            100 / CalendarEntry.Efficiency / ConCurrCap, 1, '>');
        EndTime := StartTime + RoundedTimetoProgram;
        RemainNeedQty := RemainNeedQty - TimetoProgram;
        //if ProdOrderRoutingLine.Status <> ProdOrderRoutingLine.Status::Simulated then
        ShouldUpdateAvailCap := ProdOrderRoutingLine.Status <> ProdOrderRoutingLine.Status::Simulated;
        OnUpdateTimesForwardOnBeforeUpdateAvailCap(ProdOrderRoutingLine, ShouldUpdateAvailCap);        
        if ShouldUpdateAvailCap then
        // <<<<<<<<<<        
            AvailCap := AvailCap - RoundedTimetoProgram;
    end;
    [IntegrationEvent(false, false)]
    local procedure OnUpdateTimesForwardOnBeforeUpdateAvailCap(var ProdOrderRoutingLine: Record "Prod. Order Routing Line"; var ShouldUpdateAvailCap: Boolean)
    begin
    end;   

Describe the request

View description for reason.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions