Solved

Populate grid from another grid using foreach loop


Userlevel 4
Badge

I have created a new grid in Cases where when you populate the Relations grid tab with invoice documents it then populates this new grid called CAMRelations with all of the invoices entered in the Relations tab.

Right now, I have it working where the CAMRelations grid pulls the invoices one at a time from the Relations tab, but I want it to populate with all of the invoices from the Relations tab, not simply one at a time. If you highlight each item in Relations the CAMRelations pulls the correct invoice information, but again only one at a time and not a list of the invoices from the Relations grid.

The screen shots below show what I am seeing.

Basically below is the logic I want to use, it simply fails validation.  So I do not know what I should do for this.

                    var items = Base.Relations.Select().FirstTableItems.ToList();
                    
                    foreach (CRRelation item in items)
                    {   PXSelect<ARInvoice, Where<ARInvoice.noteID, Equal<CurrentValue<CRRelation.targetNoteID>>>> CAMRelationsView;
                    }

Any help would be greatly appreciated.

Thank you,                    

 

 

icon

Best answer by darylbowman 24 April 2023, 15:03

View original

17 replies

Userlevel 6
Badge +4

Hi @jeffgrammer69 

Can you clarify what do you mean by one at a time? It is because each current Relation is copied into the custom grid (current one)? or you do a ForEach loop to copy the records doing Insert / Update validating if it exists or no?

Normally you have to deal with cache one record (DAC) at a time inserting or updating the cache.

Are you expecting something similar to SLECT … INTO like in SQL, kind of behavior?

 

I would have this in a function if you want an action to copy the grid

 

// This is a draft pattern that requires some adjustments
foreach (CRRelation item in items)
{
ARInvoice inv = ARInvoiceView.Search<ARInvoice.noteID>(item.TargetNoteID);
if(inv != null)
{
ARInvoiceView.Current = inv;

// Modify Inv with any update

ARInvoice.Update(inv);
}
else
{
inv = ARInvoiceView.Insert(new ARInvoice { key fields })
ARInvoiceView.Current = inv;

// Set your object

ARInvoice.Insert(inv);

}
}
...
Base.Actions.PressSave(); // Please the real header object

...

 

Userlevel 4
Badge

Hi Leo!

Thank you for the response!

To clarify, if you look at the screen shot I entered 5 invoice document lines under the “Relations” tab item.

If I then click on the “CAM Document Info” tab, only the first document, (AR010013) is displayed there.  I can go back to the “Relations” tab and then highlight the next document in the “Relations” list, (AR010055), and then click the “CAM Document Info” tab and that AR010055 invoice is listed there, but no others and the AR010013 document has been replaced with the AR010055 invoice data.
What I was wanting to do is when I enter those 5 invoice documents in the “Relations” tab grid, then have all 5 invoices *also* list on the “CAM Document Info” tab.  
Hopefully I am making sense here.
Thank you,

Jeff

Userlevel 4
Badge

@Leonardo Justiniano 
I realized I might need to clarify a little further.

In SQL code terms.  Below is exactly what I am trying to do inside of Acumatica and put the results into the “CAM Document Info” tab.  I do *not* want to save or store the results, only display them.
Does this make it more clear?

SELECT 
       ARInvoice.[RefNbr]
      ,ARInvoice.[DocType]
      ,ARInvoice.[CuryLineTotal]
      ,ARInvoice.[CuryTaxTotal]
      ,ARInvoice.[InvoiceNbr]
      ,ARRegister.[DocDate]
      ,ARRegister.[DueDate]
  FROM [dbo].[CRCase] CRCase
  OUTER APPLY (
     SELECT 
          [TargetNoteID],
          [DocNoteID],
          [RefNoteID]
     FROM [dbo].[CRRelation]
     WHERE [dbo].[CRRelation].[CompanyID] = 2
     AND [dbo].[CRRelation].[RefNoteID] = CRCase.[NoteID]
  ) CRRelation
    OUTER APPLY (
    SELECT
         [RefNbr],
         [DocDate],
         [DueDate],
         [NoteID]
    FROM [dbo].[ARRegister]
    WHERE [dbo].[ARRegister].[CompanyID] = 2
    AND [dbo].[ARRegister].[NoteID] = CRRelation.[TargetNoteID]
  ) ARRegister
  OUTER APPLY (
    SELECT
         [RefNbr],
         [DocType],
         [CuryLineTotal],
         [CuryTaxTotal],
         [InvoiceNbr]
    FROM [dbo].[ARInvoice]
    WHERE [dbo].[ARInvoice].[CompanyID] = 2
    AND [dbo].[ARInvoice].[RefNbr] = ARRegister.[RefNbr]
  ) ARInvoice
  WHERE CRCase.[CompanyID] = 2
  AND CRCase.[CaseCD] = '000161'

Userlevel 4
Badge

@Leonardo Justiniano The code snippet you provided really did not work for me.  Even after I tried several different iterations.

Did you have any other thoughts?

Thank you again,

Userlevel 7
Badge +17

@jeffgrammer69  Can you please share the customization package for our review?

Userlevel 7
Badge +5

I feel like you want to set up the View for that grid within your Graph but then use an IEnumerable method to allow you to “manually” gather the records for the result set.

I don’t have a clean example to show, maybe someone else does.

In InventoryLineMaint.cs, you can see the FilteredItems view has a method:

public virtual IEnumerable filteredItems()

The purpose of this code is to manually generate a record set for the view. The variable list is constructed in the code and then populated. Now, in this case, the cmd variable has the BQL command to build the list vs cherry picking the individual rows. But given that you want to duplicate the view results from the other tab, that tab’s BQL would be a good place to start before you make your modifications.

However, there might be better/more efficient ways to do this so I’ll defer to more experienced developers already on this thread.

Badge +11

This is what @Django is talking about:

using PX.Data.BQL.Fluent;

// Data view
public SelectFrom<ARInvoice> CAMRelationsView;

// Data view delegate (where things can get really freaky)
public IEnumerable camRelationsView()
{
var relations = new List<ARInvoice>();

var items = Base.Relations.Select().FirstTableItems.ToList();

foreach (CRRelation item in items)
{
ARInvoice relatedInvoice = SelectFrom<ARInvoice>.Where<ARInvoice.noteID.IsEqual<@P.AsGuid>>.Select(Base, item.TargetNoteID);
relations.Add(relatedInvoice);
}

return relations;
}

 

Userlevel 4
Badge

@darylbowman 
First, thank you for the code!

Using that code snippet I plugged that into the CS file, however, it fails on validation/compile with the error of: 

\App_RuntimeCode\CRCaseMaint.cs(80): error CS0246: The type or namespace name 'P' could not be found (are you missing a using directive or an assembly reference?)
\App_RuntimeCode\CRCaseMaint.cs(80): error CS0117: 'SelectFromBase<ARInvoice, TypeArrayOf<IFbqlJoin>.Empty>.Where<BqlOperand<ARInvoice.noteID, IBqlGuid>.IsEqual<P.AsGuid>>' does not contain a definition for 'Select'
\App_RuntimeCode\CRCaseMaint.cs(72): error CS0161: 'CRCaseMaint_Extension.camRelationsView()': not all code paths return a value
\App_RuntimeCode\CRCaseMaint.cs(80): error CS0246: The type or namespace name 'P' could not be found (are you missing a using directive or an assembly reference?)


I did include the PX.Data.BQL.Fluent library.
It appears to be failing on the @P.AsGuid parm.

In the code below, do I have it entered correctly?  Or am I missing a declaration somewhere?
 

    public SelectFrom<ARInvoice> CAMRelationsView;

public IEnumerable camRelationsView()
{
var relations = new List<ARInvoice>();

var items = Base.Relations.Select().FirstTableItems.ToList();

foreach (CRRelation item in items)
{
ARInvoice relatedInvoice = SelectFrom<ARInvoice>.Where<ARInvoice.noteID.IsEqual<@P.AsGuid>>.Select(Base,item.TargetNoteID);
relations.Add(relatedInvoice);

return relations;
} // end of foreach
}

 

Userlevel 4
Badge

@Naveen Boga 
Please forgive me for taking so long to respond.  I was traveling over the weekend.

Attached is the full customization package.  Note that I even have tried using AutoCall back on the screen grid to see if that worked.  It does not for fully populating the CAM Info grid.

Thank you,

Badge +11

I did include the PX.Data.BQL.Fluent library.
It appears to be failing on the @P.AsGuid parm.

I forgot you’ll also need to include

using PX.Data.BQL;

 

Userlevel 4
Badge

@darylbowman 

AH!  Thank you.  These are the things I do not know about Acumatica coding.  
 

Well, that took me a bit closer.  Now it is failing with the following error on the SelectFromBase statement. 

I am sneaking up on it. 😀

\App_RuntimeCode\CRCaseMaint.cs(81): error CS0117: 'SelectFromBase<ARInvoice, TypeArrayOf<IFbqlJoin>.Empty>.Where<BqlOperand<ARInvoice.noteID, IBqlGuid>.IsEqual<P.AsGuid>>' does not contain a definition for 'Select'
\App_RuntimeCode\CRCaseMaint.cs(73): error CS0161: 'CRCaseMaint_Extension.camRelationsView()': not all code paths return a value
\App_RuntimeCode\CRCaseMaint.cs(81): error CS0117: 'SelectFromBase<ARInvoice, TypeArrayOf<IFbqlJoin>.Empty>.Where<BqlOperand<ARInvoice.noteID, IBqlGuid>.IsEqual<P.AsGuid>>' does not contain a definition for 'Select'

 

Badge +11

Sorry, I wrote that code blind and I missed a piece. However, you also changed my original code a bit, which is why you’re getting the error at line 73.

Try this:

using PX.Data.BQL;
using PX.Data.BQL.Fluent;

// Data view
public SelectFrom<ARInvoice> CAMRelationsView;

public IEnumerable camRelationsView()
{
var relations = new List<ARInvoice>();

var items = Base.Relations.Select().FirstTableItems.ToList();

foreach (CRRelation item in items)
{
ARInvoice relatedInvoice = SelectFrom<ARInvoice>.Where<ARInvoice.noteID.IsEqual<@P.AsGuid>>.View.Select(Base, item.TargetNoteID);
relations.Add(relatedInvoice);
} // end of foreach

return relations;
}

 

Userlevel 4
Badge

@darylbowman 

Thank you!  I will test this out.  I figured I had ‘kicked’ the code when I typed it in.  I try not to do “copy and paste” so that I can learn not simply logic, but syntax also.  So thank you again for your patience and help.

It did compile now; and will post back shortly what it does.

 

Userlevel 4
Badge

@darylbowman 
Again, I ask for your patience with me.
Ok, the customization compiles and publishes just fine.
However, upon execution I receive the runtime error below.
Do I need to define the view in a different way?

 

 


 

 

Badge +11

Sorry, I missed one more piece. This is the benefit of looking at the whole project in Visual Studio 😒

 

Replace the data view with this:

public SelectFrom<ARInvoice>.View CAMRelationsView;

 

Userlevel 4
Badge

@darylbowman 
This has worked BEAUTIFULLY!!!

That is exactly what I was looking to do!  
Thank you very much!

In the screen shot below you can see how it lists out on the other grid “CAM DOCUMENT INFO”.  And it appears to be dynamic in so much as I can add new documents to the Relations tab and it shows up on the the “CAM DOCUMENT INFO” then.

 

 

Badge +11

Fantastic!

 

Yes, it should, as it is duplicating exactly what is shown in that view. Since it is using the same underlying record type (ARInvoice), this is relatively simple to do.

Reply


About Acumatica ERP system
Acumatica Cloud ERP provides the best business management solution for transforming your company to thrive in the new digital economy. Built on a future-proof platform with open architecture for rapid integrations, scalability, and ease of use, Acumatica delivers unparalleled value to small and midmarket organizations. Connected Business. Delivered.
© 2008 — 2024  Acumatica, Inc. All rights reserved