Skip to main content
Solved

Warehouse location filter on Deadstock scren

  • 25 July 2024
  • 8 replies
  • 72 views

Hi

I am adding the warehouse location field to the deadstock screen.

I managed to add the field and view the location for each warehouse. However the data is not filtering based on the location.

I know I tried creating a graph extension to add the location as a filter but its not working.

 

using PX.Common;
using PX.Data;
using PX.Objects.CS;
using PX.Objects.IN.DAC.Unbound;
using PX.Objects;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System;

namespace PX.Objects.IN.DAC.Unbound
{
    public class INDeadStockEnqFilterExt : PXCacheExtension<PX.Objects.IN.DAC.Unbound.INDeadStockEnqFilter>
    {
        #region Usrlocation
        oPXDBInt]
        ÂPXSelector(typeof(Search<INLocation.locationID, Where<INLocation.siteID, Equal<Current<INDeadStockEnqFilter.siteID>>>>),
            typeof(INLocation.locationCD),
            typeof(INLocation.descr),
            SubstituteKey = typeof(INLocation.locationCD))]
        SPXUIField(DisplayName = "Location")]
        public virtual int? Usrlocation { get; set; }
        public abstract class usrlocation : PX.Data.BQL.BqlInt.Field<usrlocation> { }
        #endregion
    }
}

Hi @LungileNjakazi37,

Did you add the LocationID field to the grid as well? If so, you will need to apply your new location filter to the view by overriding AddFilters function.

using System;
using System.Collections.Generic;
using PX.Data;
using PX.Objects.IN;
using PX.Objects.IN.DAC.Unbound;

namespace PX.Objects.IN.Extensions.BLC
{
public class INDeadStockEnqExt : PXGraphExtension<INDeadStockEnq>
{
[PXOverride]
public virtual List<object> AddFilters(
INDeadStockEnqFilter filter,
PXSelectBase<INSiteStatusByCostCenter> command,
DateTime? inStockSince,
DateTime? noSalesSince,
Func<INDeadStockEnqFilter, PXSelectBase<INSiteStatusByCostCenter>, DateTime?, DateTime?, List<object>> baseMethod)
{
var result = baseMethod?.Invoke(filter, command, inStockSince, noSalesSince);

var filterExt = filter.GetExtension<INDeadStockEnqFilterExt>();
if (filterExt.Usrlocation != null)
{
command.WhereAnd<Where<*YOURTABLE.LOCATIONID*.IsEqual<INDeadStockEnqFilterExt.usrlocation.FromCurrent>>>();
}

return result;
}
}
}

 


Thank you for this.

I keep getting the error below:
 



Please see below screenshots of code and attached file:

using PX.Data;
using PX.Objects.CS;
using PX.Objects.IN;
using PX.Objects.IN.DAC.Unbound;
using PX.Data.BQL;
using PX.Data.BQL.Fluent;
using PX.Objects;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System;

namespace PX.Objects.IN.DAC.Unbound
{
    public class INDeadStockEnqFilterExt : PXCacheExtension<INDeadStockEnqFilter>
    {
        #region Usrlocation
        iPXDBInt]
         PXSelector(typeof(Search<INLocation.locationID,
                                  Where<INLocation.siteID, Equal<Current<INDeadStockEnqFilter.siteID>>>>),
                    typeof(INLocation.locationCD),
                    typeof(INLocation.descr),
                    SubstituteKey = typeof(INLocation.locationCD))]
         PXUIField(DisplayName = "Location")]
        public virtual int? Usrlocation { get; set; }
        public abstract class usrlocation : BqlInt.Field<usrlocation> { }
        #endregion
 }
}

 


To address the issue of filtering data based on the selected warehouse location in the Deadstock screen, you need to ensure that the filtering logic is correctly applied in the graph extension. The code you've provided adds the `Usrlocation` field to the filter, but additional steps are necessary to make the filter work properly.

Here’s a step-by-step guide to resolving the issue:

1. Update the Data View in the Graph Extension: 
   You'll need to modify the data view in the graph extension to include the filter on the `Usrlocation` field. This is where the filtering logic should be applied.

2. Modify the BQL Query to Include the Location Filter:
   Ensure that the BQL query used in the data view respects the selected location. You should adjust the `Where` clause to filter results based on the `Usrlocation` field.

Here’s how you can implement it:

```csharp
using PX.Data;
using PX.Objects.CS;
using PX.Objects.IN;
using PX.Objects.IN.DAC.Unbound;
using System;

namespace PX.Objects.IN
{
    public class INDeadStockEnqGraphExt : PXGraphExtension<INDeadStockEnq>
    {
        protected void _(Events.RowSelected<INDeadStockEnqFilter> e)
        {
            if (e.Row == null) return;

            PXUIFieldAttribute.SetVisible<INDeadStockEnqFilterExt.usrlocation>(e.Cache, e.Row, true);
        }

        public delegate IEnumerable recordsDelegate();
        uPXOverride]
        public virtual IEnumerable records(recordsDelegate baseMethod)
        {
            var currentFilter = Base.Filter.Current;
            if (currentFilter == null)
                return baseMethod();

            var query = new PXSelectJoin<INItemSite,
                InnerJoin<InventoryItem, On<INItemSite.inventoryID, Equal<InventoryItem.inventoryID>>,
                InnerJoin<INLocation, On<INItemSite.siteID, Equal<INLocation.siteID>,
                    And<INItemSite.replenishmentSourceSiteID, Equal<Current<INDeadStockEnqFilter.siteID>>>>>>,
                Where<INLocation.locationID, Equal<Current<INDeadStockEnqFilterExt.usrlocation>>>>(Base);

            return query.Select();
        }
    }
}
```

Explanation:

1. **RowSelected Event Handler:**
   This event ensures that the `Usrlocation` field is visible when the filter row is selected.

2. **Overriding the `records` Method:**
   The `records` method is overridden to apply custom filtering logic. It checks if the `Usrlocation` field has a value and, if so, modifies the query to filter based on the selected location.

3. **BQL Query Update:**
   The query is updated to join the necessary tables and apply a filter on `INLocation.locationID` using the selected value from `Usrlocation`.

### Final Steps:

- Rebuild the solution and ensure the extension is properly applied to the Deadstock screen.
- Test the functionality by selecting a location and verifying that the data is filtered accordingly.

This solution should allow your Deadstock screen to filter records based on the selected warehouse location, ensuring that only relevant data is displayed.


Hi @LungileNjakazi37, I can’t see the error message, just the attached customization package.


Hi @Zoltan Febert . Here is the screenshot

 


Hi @LungileNjakazi37,

What Acumatica version do you use? If you use 22R2, then you can’t use INSiteStatusByCostCenter, because that table was introduced in 23R1.

The error message means you are missing a using directive. I am getting a different error:

\App_RuntimeCode\INDeadStockEnqResultExtensions.cs(51): error CS0426: The type name 'locationID' does not exist in the type 'INSiteStatusByCostCenter'

Actually this is correct, INSIteStatusByCostCenter doesn’t have this field.

Please see @chameera71  recordsDelegate() function. This function shows you how to join INLocation table that has a location field for filtering.


Hi @chameera71 

I tried your code but I keep getting an error message:
 

 


The error message you're encountering (CS0305: Using the generic type 'IEnumerable<T>' requires 1 type arguments) indicates that you're missing a type argument when using IEnumerable<T>. This is a common C# error when working with generic collections like IEnumerable.

Possible Causes

In the code you’ve implemented, you might be using IEnumerable without specifying the type it should operate on. For example, if you're dealing with a collection of INTran or some other specific type, you need to provide that type as an argument for IEnumerable<T>.

Fixing the Issue

  1. Review the Line: Find the line in INDeadStockEnqResultExtensions.cs on line 36 that’s causing the issue. It's likely that IEnumerable is used without a specific type. It should look something like this:

     

    csharp

    Copy code

    IEnumerable results = someMethod(); // This is incorrect

    Instead, it should specify the type that the collection holds. For instance, if you're working with a collection of INTran (inventory transactions), it should be:

     

    csharp

    Copy code

    IEnumerable<INTran> results = someMethod();

  2. Fix the Type Declaration: Modify the code to include the appropriate type inside the IEnumerable<T>. If the type you're working with is INTran, or whatever specific class you're dealing with, declare it like this:

     

    csharp

    Copy code

    IEnumerable<INTran> transactions = someMethod();

  3. Check Method Return Types: Ensure that the method you're calling returns an IEnumerable<T> where T is your specific type (e.g., INTran). If you’re unsure of the return type, you can either:

    • Adjust the method to return the correct type.
    • Cast the result appropriately.

    For example:

     

    csharp

    Copy code

    var result = someMethod(); IEnumerable<INTran> transactions = result.Cast<INTran>(); // If result is a collection that needs casting

  4. Rebuild and Test: Once you’ve made the changes, rebuild the project to see if the error is resolved. If you're using the Customization Project Editor in Acumatica, recompile the project there and validate the customization again.

Example Correction:

If the original code was:

 

csharp

Copy code

IEnumerable results = someMethod();

You would change it to something like:

 

csharp

Copy code

IEnumerable<INTran> results = someMethod(); // Use the appropriate type

If you're working with multiple types, ensure that the method or logic correctly reflects what type you are operating on within the IEnumerable<T>.

After making these changes, retry the compilation, and it should resolve the error. If you have more specific information on what you're trying to accomplish or the classes involved, I can provide a more detailed solution.


Reply