Solved

Standard navigation button / How to avoid creating new record


Userlevel 3
Badge

Hi,

I have created a custom graph and its screen.

 

It works fine but I have an unexpected behavior with standard navigation button : when I select the last record of main view (button “Go to last Record”) and when I click on “Go to Next record”, a new virgin record is proposed so that user can enter values and create a new object. In our case, I do not want the user to be able to create a new record.

Is it possible to configure navigation actions to avoid new record creation ?

 

icon

Best answer by ygagnaire12 17 July 2023, 15:40

View original

15 replies

Userlevel 7
Badge +17

Hi @ygagnaire12  Can you please share the code here?

Userlevel 3
Badge

Hi Naveen Boga,

Here is the begining of the graph declaration :

    public class EAPInvoiceEntry : PXGraph<EAPInvoiceEntry, EAPInvoice>
    {

 

EAPInvoice is quite a copy of APInvoice.

The graph main view :

        public SelectFrom<EAPInvoice>
            .LeftJoin<Vendor>.On<Vendor.bAccountID.IsEqual<EAPRegister.vendorID>>
            .View DocumentView;

 

I have joined the aspx file to the post. Do you need anything else ?

Thx

 

Userlevel 7
Badge +17

@ygagnaire12  Could not able to upload the above customization and getting below error.

 

 

Userlevel 3
Badge

I see. It’s normal : the .zip file just contains the .aspx file and not my customization, that is too heavy to be easily posted.

Userlevel 5
Badge +1

Hi guys,

Acumatica have attributes on View object like AllowUpdate or AllowInsert. Not far away I had the same case on my custom screen and I added this code in RowSelected event

 

Maybe it will help, try add this event to your graph:

 protected virtual void _(Events.RowSelected<EAPInvoice> e)
{
if (e.Row == null) return;

DocumentView.AllowInsert = false;
}

 

Userlevel 3
Badge

Hello andriikravetskyi35,

Thank you for your suggestion, which seems to be a good way forward. Unfortunately, it doesn’t work in my case.I’m continuing my search...

Userlevel 3
Badge

Hi andriikravetskyi35 !

Thank you very much for your suggestion, which sounds like a good idea. Unfortunately, it doesn't work in my case. I'm continuing my research...

Userlevel 6
Badge +3

Can you figure out somehow if you are on the last record or not? If so, then you can disable the Next action in RowSelected.

 

 protected virtual void _(Events.RowSelected<EAPInvoice> e)
{
if (e.Row == null) return;

var isLastRecord = /** e.Row.ID == MaxID from another view??? **/
Next.SetEnabled(!isLastRecord);
}
}

 

Userlevel 3
Badge

Hello zfebert56,

This is exactly the solution I’m trying to implement. As you said, the problem is to know if we are on the last record or not. I thought that the “DocumentView” class was providing some method “Last()” or “IsLast()” or something like this, but it is not the case.

        public SelectFrom<EAPInvoice>
            .LeftJoin<Vendor>.On<Vendor.bAccountID.IsEqual<EAPRegister.vendorID>>
            .OrderBy<Asc<EAPInvoice.refNbr>>
            .View DocumentView;

On the same idea, I will also need to know if we are or not on the firts record. So this is what I’m looking for at the moment.

That being said, thank you for your reply that gave me the way to access to the Next, Previous, Last and First action.

Userlevel 5
Badge +1

Good morning everyone,

@zfebert56  Here is one more idea how you might override Next button, example on Sales Order screen, but you could do the same on your screen:

 public class SOOrderEntryExt : PXGraphExtension<SOOrderEntry>
{

public static bool IsActive() => true;

public PXNextMyLogic<SOOrder> Next;

public class PXNextMyLogic<TNode> : PXPrevNextBase<TNode> where TNode : class, IBqlTable, new()
{
protected override int DefaultStartRow => 0;

public PXNextMyLogic(PXGraph graph, string name) : base(graph, name) { }

public PXNextMyLogic(PXGraph graph, Delegate handler) : base(graph, handler) { }

[PXUIField(DisplayName = "Next", MapEnableRights = PXCacheRights.Select)]
[PXNextButton]
protected override IEnumerable Handler(PXAdapter adapter)
{

// do some selects, check data and return from method or run baseMethod

adapter.StartRow += adapter.MaximumRows;
return base.Handler(adapter);
}
}
}

Hope it help you to solve your issue.

PS: just for information, don’t select any information in RowSelected event, it will slow performance of screen. If you need select data from DB, do it in RowSelecting event, using PXConnectionScope()

Userlevel 6
Badge +3

@ygagnaire12 Here is an idea how to get the first and last record. I am not sure if it is working or not, I was not able to try it.

        private int? firstRecordID;
private int? lastRecordID;
protected virtual IEnumerable documentView()
{
var result = SelectFrom<EAPInvoice>
.LeftJoin<Vendor>.On<Vendor.bAccountID.IsEqual<EAPRegister.vendorID>>
.OrderBy<Asc<EAPInvoice.refNbr>>.View.Select(this).RowCast<EAPRegister>().ToList();

firstRecordID = result.FirstOrDefault()?.EAPInvoiceID;
lastRecordID = result.LastOrDefault()?.EAPInvoiceID;
return result;
}

You can use it in both @andriikravetskyi35 and my solution.

Userlevel 3
Badge

 

@andriikravetskyi35 and  @zfebert56 

Sorry for my late reply but I had a lot of meetings yesterday afternoon. Thanks a lot for all your smart suggestions ! I've tested a merge of them and it works : the "Next" action button doesn't lead to a new record when activated on the last record.My code below. Once again, thank you for your invaluable help, without which I would still be searching.

        public new PXNextRestricted<EAPInvoice> Next;

        public class PXNextRestricted<TNode> : PXPrevNextBase<TNode> where TNode : class, IBqlTable, new()
        {
            protected override int DefaultStartRow => 0;

            public PXNextRestricted(PXGraph graph, string name) : base(graph, name) { }

            public PXNextRestricted(PXGraph graph, Delegate handler) : base(graph, handler) { }

            [PXUIField(DisplayName = "Next!", MapEnableRights = PXCacheRights.Select)]
            [PXNextButton]
            protected override IEnumerable Handler(PXAdapter adapter)
            {
                EAPInvoiceEntry eapInvoiceEntryGraph = base.Graph as EAPInvoiceEntry;
                EAPInvoice currentEapInvoice = eapInvoiceEntryGraph.DocumentView.Current;

                IEnumerable defaultResult = adapter.Get();

                adapter.StartRow += adapter.MaximumRows;
                IEnumerable result = base.Handler(adapter);

                bool isLastRecord = currentEapInvoice != null && currentEapInvoice.RefNbr != null && currentEapInvoice.RefNbr.Equals(eapInvoiceEntryGraph.lastRecordID);

                if (isLastRecord)
                {
                    SetEnabled(false);
                    result = defaultResult;
                }
                else
                {
                    SetEnabled(true);
                }
                
                return result;
            }
        }

Userlevel 5
Badge +1

Hi guys,

@ygagnaire12  @zfebert56  Sorry for late answer, I am following to this case, it is interesting how you solve the bug. I also have issues and bugs from my current projects and I don’t have a lot of free time.

Yesterday I run your code in my VS and tried to debug it but I didn’t get successful results, it is needed more time. 

If you fix issues, could your share to me and community your approach.

Have a nice day and codding 😉

Userlevel 3
Badge

Hello andriikravetskyi35,

Just to recap : my aim was to avoid having a new record when navigating in a grid. This occurs in my case when I click "next" on last record  or "previous" on first record.

The solutions I have writen thanks to zfebert56  and you is the following :

For button "next" :

- Firstly, I have created an overloaded method for my main view. In this method, I get and memorize first and last record identifiers (in my case, RefNbr fits).

here is the code :

        #region Attributes
        private string firstRecordID;
        private string lastRecordID;
        #endregion

...

        public SelectFrom<EAPInvoice>
            .LeftJoin<Vendor>.On<Vendor.bAccountID.IsEqual<EAPRegister.vendorID>>
            .OrderBy<Asc<EAPInvoice.refNbr>>
            .View DocumentView;

        protected virtual IEnumerable documentView()
        {
            IEnumerable<EAPInvoice> result = SelectFrom<EAPInvoice>
                .LeftJoin<Vendor>.On<Vendor.bAccountID.IsEqual<EAPRegister.vendorID>>
                .OrderBy<Asc<EAPInvoice.refNbr>>.View.Select(this).RowCast<EAPInvoice>().ToList();

            firstRecordID = result.FirstOrDefault()?.RefNbr;
            lastRecordID = result.LastOrDefault()?.RefNbr;

            return result;
        }
        
- Secondly, I have created a new class that inherits from PXPrevNextBase. In this class, the method "Handler(PXAdapter adapter)" is overloaded to behave differently if we detect that current record is the last one.

        public new PXNextRestricted<EAPInvoice> Next;

        public class PXNextRestricted<TNode> : PXPrevNextBase<TNode> where TNode : class, IBqlTable, new()
        {
            protected override int DefaultStartRow => 0;

            public PXNextRestricted(PXGraph graph, string name) : base(graph, name) { }

            public PXNextRestricted(PXGraph graph, Delegate handler) : base(graph, handler) { }

            [PXUIField(DisplayName = "Next", MapEnableRights = PXCacheRights.Select)]
            [PXNextButton]
            protected override IEnumerable Handler(PXAdapter adapter)
            {
                EAPInvoiceEntry eapInvoiceEntryGraph = base.Graph as EAPInvoiceEntry;
                EAPInvoice currentEapInvoice = eapInvoiceEntryGraph.DocumentView.Current;

                adapter.StartRow += adapter.MaximumRows;
                IEnumerable result = base.Handler(adapter);

                bool isLastRecord = eapInvoiceEntryGraph.lastRecordID == null || (currentEapInvoice != null && currentEapInvoice.RefNbr != null && currentEapInvoice.RefNbr.Equals(eapInvoiceEntryGraph.lastRecordID));
                if (isLastRecord)
                {
                    adapter.StartRow -= adapter.MaximumRows; // back
                    result = base.Handler(adapter);
                    SetEnabled(false);
                }
                else
                {
                    SetEnabled(true);
                }
                
                return result;
            }
        }
        
For button previous, it is the save idea. This code can be improved I think but I didn't have time any more to get deeper. Anyway, It works as it is.

Hope It will be helpfull for you.

Userlevel 7
Badge

Thank you for sharing your solution with the community @ygagnaire12!

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