Search code examples
c#.netacumatica

Modify Lot/ Serial Number Generation in Acumatica Production Order Maintenance Screen (AM201500)


I have to do a customization in the production order maintenance screen where in the line details tab there is a generate button to create the line in sequence 000001 and so on.

But I want to change it to grab the production number for example (PP000004) and the lot/serial number generated is PP000004-000001, PP000004-000002, PP000004-000003 and so on till the quantity to generate is satisfied. How to achieve this via customization? The generate button needs to be extended to change the Lot/ Serial number, I have created an override method but I get this error, any help would be appreciated!

using System;
using PX.Data;
using PX.Objects.IN;
using PX.Objects.CS;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using PX.Objects.AM.GraphExtensions;
using PX.Common;
using PX.Objects.Common;
using PX.Objects.SO;
using PX.Objects.AM.Attributes;
using System.Linq;
using PX.Objects.AM.CacheExtensions;
using PX.Data.BQL.Fluent;
using PX.Data.BQL;
using PX.Objects.AR;
using PX.Objects.CR;
using PX.Objects.GL;
using PX.Objects;
using PX.Objects.AM;

namespace PX.Objects.AM
{
  public class ProdMaint_Extension : PXGraphExtension<PX.Objects.AM.ProdMaint>
{
#region Event Handlers

 // This method overrides the existing method tied to the Generate button
    [PXOverride]
    public virtual void GenerateNumbers(Action baseMethod)
    {
        // Call the base method to keep existing functionality (optional)
        baseMethod?.Invoke();

        // Custom logic to generate Lot/Serial numbers based on production number
        var currentOrder = PXSelect<AMProdItem>.Select(Base).TopFirst;
        if (currentOrder == null) return;

        string productionNumber = currentOrder.ProdOrdID;

        // Get all generated material lines
        PXResultset<AMProdMatl> materialLines = PXSelect<AMProdMatl,
            Where<AMProdMatl.prodOrdID, Equal<Required<AMProdMatl.prodOrdID>>>>
            .Select(Base, currentOrder.ProdOrdID);

        int sequenceNumber = 1;
        foreach (AMProdMatl line in materialLines)
        {
            if (string.IsNullOrEmpty(line.LotSerialNbr)) continue;

            // Generate the new lot/serial number
            string newLotSerialNbr = $"{productionNumber}-{sequenceNumber:D6}";

            // Update the lot/serial number
            line.LotSerialNbr = newLotSerialNbr;

            // Save changes
            Base.Caches[typeof(AMProdMatl)].Update(line);

            sequenceNumber++;
        }

        // Save changes to the database
        Base.Actions.PressSave();
    }

#endregion

} }

Error: [2024-10-07 03:16:01.919] The Void GenerateNumbers(System.Action) method in the PX.Objects.AM.ProdMaint_Extension graph extension is marked as [PXOverride], but no original method with this name has been found in PXGraph. [2024-10-07 03:16:08.479] Validation failed.

Thank you!

New Code

{
  public class ProdMaint_Extension : PXGraphExtension<ProdMaint.ItemLineSplittingExtension,PX.Objects.AM.ProdMaint>
  {
 

    #region Event Handlers
    
  //public IEnumerable GenerateNumbersDelegate(PXAdapter adapter);
  //public delegate IEnumerable GenerateNumbersDelegate(PXAdapter adapter);
[PXOverride]
public IEnumerable GenerateNumbers(PXAdapter adapter, Func<PXAdapter, IEnumerable> baseMethod)
{
    //var result = baseMethod(adapter);

    //return result;
    // Call the base method to ensure the original functionality is executed
    var baseResult = baseMethod.Invoke(adapter);

    // Retrieve the current production order
    var currentProductionOrder = PXSelect<AMProdItem>.Select(Base).TopFirst;
    if (currentProductionOrder == null)
    {
        throw new PXException("No Production Order found.");
    }

    // Get the production order number
    var productionOrderNbr = currentProductionOrder.ProdOrdID; // Adjust this field as needed

   if (string.IsNullOrEmpty(productionOrderNbr))
    {
        throw new PXException("Production Order Number is required.");
    }

    // Prepare a list to store the updated rows
    var resultList = new List<AMProdMatl>();
    int sequenceNumber = 1;

    // Iterate over the results returned by the base method
   foreach (AMProdMatl row in baseResult.OfType<AMProdMatl>())
    {
      // Generate the custom Lot/Serial number
        row.LotSerialNbr = $"{productionOrderNbr}-{sequenceNumber:D6}";

        // Add the updated row to the result list
        resultList.Add(row);
        sequenceNumber++;
    }

    // Return the updated result list
    return resultList;
}

    #endregion
  }
}```

Solution

  • You get this error because GenerateNumbers is not declared in ProdMaint graph, but it is declared in ItemLineSplittingExtension. You need to override it in this way:

    public class ProdMaint_Extension : PXGraphExtension<ProdMaint.ItemLineSplittingExtension, PX.Objects.AM.ProdMaint>
    {
        // This method overrides the existing method tied to the Generate button
        [PXOverride]
        public virtual IEnumerable GenerateNumbers(PXAdapter adapter, Func<PXAdapter, IEnumerable> baseMethod)
        {
            var baseResult = baseMethod.Invoke(adapter);
           
            var currentProductionOrder = Base.ProdMaintRecords.Current;
            if (currentProductionOrder == null) // I don't think it is possible
            {
                // Acuminator disable once PX1050 HardcodedStringInLocalizationMethod [Justification]
                throw new PXException("No Production Order found.");
            }
    
            // Get the production order number
            var productionOrderNbr = currentProductionOrder.ProdOrdID; // Adjust this field as needed
    
            if (string.IsNullOrEmpty(productionOrderNbr))
            {
                // Acuminator disable once PX1050 HardcodedStringInLocalizationMethod [Justification]
                throw new PXException("Production Order Number is required.");
            }
            
            int sequenceNumber = 1;
    
            // Iterate over the splits records
            foreach (var row in Base.splits.Select().RowCast<AMProdItemSplit>())
            {
                // Generate the custom Lot/Serial number
                row.LotSerialNbr = $"{productionOrderNbr}-{sequenceNumber:D6}";
                Base.splits.Update(row);
    
                sequenceNumber++;
            }
    
            return baseResult; // or adapter.Get(); if you don't call baseMethod
        }
    }