web
You’re offline. This is a read only version of the page.
close
Skip to main content

Notifications

Announcements

No record found.

Community site session details

Community site session details

Session Id :
Finance | Project Operations, Human Resources, ...
Unanswered

PurchLines validation when confirming the oder

(1) ShareShare
ReportReport
Posted on by 1,965
Hi,

So the requirement is to do some validations on each sales line before confirming the order.
if the enum XType value is Must, then an error should be returned.
However, if the XType value is option, then a warning should appear but, the process should proceed.

I did this, but i have two issues/concerns:

1. Is this the best place to perform such validation? and if it's the best place, shall i use _calledFrom for anything?
2.  i want all warnings to appear, but currently the first warning would only be returned and it won't continue and return all warnings. So for example if the Xtype is optional for all lines in the sales order, then i want all warnings to appear, so that after confirming the order, the user can look at all warnings and amend the value


[ExtensionOf(classStr(PurchFormLetter_Confirmation))]
final class PurchFormLetter_ConfirmationX_Extension
{
    public boolean  validate(Object _calledFrom)
    {
        boolean ret;
        
        ret = next validate(_calledFrom);
        if(ret)
        {
            PurchLine purchLine;
            while select purchLine where purchLine.PurchId == this.PurchTable().PurchId
            {
                TableX tableX;
                select firstonly tableX where tableX.ItemId == purchLine.ItemId;
                if(tableX)
                {
                    this.validateFirstField(purchLine, tableX);
                    this.validateSecondField(purchLine, tableX);
                }
            }
        }
        return ret;
    }
    public void validateFirstField(PurchLine _purchLine, TableX _tableX)
    {
        if(_tableX.FirstField == XType::Must && _purchLine.FirstField== '')
        {
            throw error(strFmt(/The FirstField for itemId: %1,  is must be filled/, _purchLine.ItemId));
        }
        else if(_tableX.FirstField == XType::Optional && _purchLine.FirstField== '')
        {
            checkFailed(strFmt(/The FirstField for itemId: %1,  is preferred be filled/, _purchLine.ItemId));
        }
    }
    public void validateSecondField(PurchLine _purchLine, TableX _tableX)
    {
        if(_tableX.SecondField == XType::Must && _purchLine.SecondField == '')
        {
            throw error(strFmt(/The SecondField for itemId: %1,  is must be filled/, _purchLine.ItemId));
        }
        else if(_tableX.SecondField == XType::Optional && _purchLine.SecondField == '')
        {
            checkFailed(strFmt(/The SecondField for itemId: %1,  is preferred be filled/, _purchLine.ItemId));
        }
    }
}
I have the same question (0)
  • André Arnaud de Calavon Profile Picture
    300,924 Super User 2025 Season 2 on at
    Hi IntegrationBeginner,
     
    Instead if using the throw error, use just an error and warning statement. This will ensure that the loop will continue. To be able to block the user when there is an error, you can use another boolean variable that will be set to true in case of the error. After the loop, you can then evaluate if the boolean is set to true. Then you can use a throw command and inform the user that he needs to solve the error before he can continue. 
  • .. Profile Picture
    1,965 on at
    Hi Andre,

    I did it like this, however I'm facing an issue.

    you know that confirmation gets called from two menu items, Confirm and Confirmation... where in confirmation a dialog is opened.


    I've noticed that in the case where only warnings are returned, when i click confirm, all warnings appear on the purch order form. But when i click "Confirmation" only one warning appear on the form. why?? I mean if let's say 3 warnings are returned one of them appear on the UI, while the three appear as notifications in action center, why not all of them appear in the form similar to when clicking confirm button.

    **in case there was an error, all warnings appear in both cases as expected
     
    [ExtensionOf(classStr(PurchFormLetter_PurchOrder))]
    final class PurchFormLetter_PurchOrderX_Extension
    {
        private boolean must = false;

        public boolean  validate(Object _calledFrom)
        {
            boolean ret;
            
            ret = next validate(_calledFrom);
            if(ret)
            {
                PurchLine purchLine;
                while select purchLine where purchLine.PurchId == this.PurchTable().PurchId
                {
                    TableX tableX;
                    select firstonly tableX where tableX.ItemId == purchLine.ItemId;
                    if(tableX)
                    {
                        this.validateFirstField(purchLine, tableX);
                        this.validateSecondField(purchLine, tableX);
                    }
                }
     
               if(must)
               {
                  throw error("fix all errors");
               }
            }
            return ret;
        }
     
        public void validateFirstField(PurchLine _purchLine, TableX _tableX)
        {
            if(_tableX.FirstField == XType::Must && _purchLine.FirstField== '')
            {
                 error(strFmt("The FirstField for itemId: %1,  is must be filled", _purchLine.ItemId));
                 must = true;
            }
            else if(_tableX.FirstField == XType::Optional && _purchLine.FirstField== '')
            {
                warning(strFmt("The FirstField for itemId: %1,  is preferred be filled", _purchLine.ItemId));
            }
        }
        public void validateSecondField(PurchLine _purchLine, TableX _tableX)
        {
            if(_tableX.SecondField == XType::Must && _purchLine.SecondField == '')
            {
                error(strFmt("The SecondField for itemId: %1,  is must be filled", _purchLine.ItemId));
                must = true;
            }
            else if(_tableX.SecondField == XType::Optional && _purchLine.SecondField == '')
            {
                warning(strFmt("The SecondField for itemId: %1,  is preferred be filled", _purchLine.ItemId));
            }
        }
    }
  • André Arnaud de Calavon Profile Picture
    300,924 Super User 2025 Season 2 on at
    Hi Integration beginner,
     
    Can you verify if there is an additional button to show more warnings. On the form itself (yellow bar) it will initially show one warning, but you can expand it in case there are more lines. If you need a bit more help, please share a screenshot of the screen including the warning.
  • .. Profile Picture
    1,965 on at
    Hi Andre,

    here's the output when i click on confirmation  -- I should be seeing four warnings, but only one appeared on the UI, and the rest of the three warnings appeared in notifications in action center




    and here's the output when i click on confirm


  • André Arnaud de Calavon Profile Picture
    300,924 Super User 2025 Season 2 on at
    Thanks for the screenshots. The issue is fully clear now. In case the application thinks that some actions are performed without a form reference, it would end up in the action center. In this case, I would then expect all warnings in the action center or all on the form. I do agree with you that this is inconsistent.
    You can try to store all messages in variables and use a loop at the end of the validation process to raise all warnings and errors at the same time. Not sure if this would solve it, but I would try such approach myself as workaround. 
  • .. Profile Picture
    1,965 on at
     

    Hi Andre,

    1. Yes when the dialog appears, notifications go to action center. I tried the code below as you suggested but still i got the same result, could it be that I need to change where i placed the code? I mean maybe i should put the validation on the dialog itself before it closes in this case?
     
    [ExtensionOf(classStr(PurchFormLetter_PurchOrder))]
    final class PurchFormLetter_PurchOrderX_Extension
    {
        private boolean must = false;
        private List    warnings= new List(Types::String);

        public boolean  validate(Object _calledFrom)
        {
            boolean ret;
            
            ret = next validate(_calledFrom);
            if(ret)
            {
                PurchLine purchLine;
                while select purchLine where purchLine.PurchId == this.PurchTable().PurchId
                {
                    TableX tableX;
                    select firstonly tableX where tableX.ItemId == purchLine.ItemId;
                    if(tableX)
                    {
                        this.validateFirstField(purchLine, tableX);
                        this.validateSecondField(purchLine, tableX);
                    }
                }
                
                if(warnings && warnings.elements())
                {
                    ListEnumerator listEnumerator = warnings.getEnumerator();
                    if(listEnumerator)
                    {
                        while(listEnumerator.moveNext())
                        {
                            warning(listEnumerator.current());
                        }
                    }
                }
               if(must)
               {
                  throw error("fix all errors");
               }
            }
            return ret;
        }
     
        public void validateFirstField(PurchLine _purchLine, TableX _tableX)
        {
            if(_tableX.FirstField == XType::Must && _purchLine.FirstField== '')
            {
                 error(strFmt("The FirstField for itemId: %1,  is must be filled", _purchLine.ItemId));
                 must = true;
            }
            else if(_tableX.FirstField == XType::Optional && _purchLine.FirstField== '')
            {
                //warning(strFmt("The FirstField for itemId: %1,  is preferred be filled", _purchLine.ItemId));
                warnings.addEnd(strFmt("The FirstField for itemId: %1,  is preferred be filled", _purchLine.ItemId));
            }
        }
        public void validateSecondField(PurchLine _purchLine, TableX _tableX)
        {
            if(_tableX.SecondField == XType::Must && _purchLine.SecondField == '')
            {
                error(strFmt("The SecondField for itemId: %1,  is must be filled", _purchLine.ItemId));
                must = true;
            }
            else if(_tableX.SecondField == XType::Optional && _purchLine.SecondField == '')
            {
                //warning(strFmt("The SecondField for itemId: %1,  is preferred be filled", _purchLine.ItemId));
                warnings.addEnd(strFmt("The SecondField for itemId: %1,  is preferred be filled", _purchLine.ItemId));
            }
        }
    }

    2. I've noticed that in PurchOrders, I can't choose which Lines to confirm even though there is PurchParmTable and PurchParmLine. So is it safe to always loop through PurchLine like what I'm doing now? or would there be a case where we can choose which purchLines to confirm from the UI?

    3. You've noticed that i put a similar question to sales order (https://community.dynamics.com/forums/thread/details/?threadid=c70b065b-022c-ee11-bdf4-000d3a55bb34). In sales orders i can choose which lines to confirm, so i now realized that putting this is wrong when doing validations
     
    while select salesLine where salesLine.SalesId == this.salesTable().SalesId
    {
    }

    and I will replace it with this, so that the validation works on the lines that were selected to be confirmed
    SalesLine      salesLine;
    SalesParmLine  salesParmLine;
    SalesParmTable salesParmTableLocal;
    
    select salesParmTableLocal where salesParmTableLocal.ParmId == this.salesParmUpdate().ParmId;
    
    while select FirstField, SecondField, ItemId from salesLine where salesLine.SalesId == this.salesTable().SalesId
        exists join salesParmLine where salesParmLine.SalesLineRecId == salesLine.RecId
        && salesParmLine.ParmId == salesParmTableLocal.ParmId
        && salesParmLine.TableRefId == salesParmTableLocal.TableRefId
    {
    }
    I've noticed that SalesParmLine gets filled in both, when i click confirm now(without dialog) and when i click confirmation (where dialog appears)
    So my question is, is it safe to always use SalesParmLine instead of looping SalesLine incase of clicking confirmation without dialog??
  • André Arnaud de Calavon Profile Picture
    300,924 Super User 2025 Season 2 on at
    Hi IntegrationBeginner,
     
    You provided a lot of details. I'm getting lost. You have another question about being able to choose lines being part of the confirmation. Let's focus here on the warnings to get them on the form.
     
    Instead of having the validations in coding as extension of class PurchFormLetter_Confirmation, you can extend or replace the form menu item button control calling the confirmation. You can then perform the validations on the form and in that way have the warnings and error messages on the form instead of in the action center.

Under review

Thank you for your reply! To ensure a great experience for everyone, your content is awaiting approval by our Community Managers. Please check back later.

Helpful resources

Quick Links

Responsible AI policies

As AI tools become more common, we’re introducing a Responsible AI Use…

Neeraj Kumar – Community Spotlight

We are honored to recognize Neeraj Kumar as our Community Spotlight honoree for…

Leaderboard > Finance | Project Operations, Human Resources, AX, GP, SL

#1
Martin Dráb Profile Picture

Martin Dráb 660 Most Valuable Professional

#2
André Arnaud de Calavon Profile Picture

André Arnaud de Cal... 512 Super User 2025 Season 2

#3
Sohaib Cheema Profile Picture

Sohaib Cheema 291 User Group Leader

Last 30 days Overall leaderboard

Product updates

Dynamics 365 release plans