【问题标题】:Cancel a sales order取消销售订单
【发布时间】:2018-10-11 04:54:00
【问题描述】:

如何通过代码取消特定的销售订单?也许我可以调用 ProcessOrders 图,循环选择订单,然后执行 Cancel Order 方法。不幸的是,我没有看到这样的方法。下拉动作由自动化菜单驱动。我在标准销售订单输入图中没有找到取消订单操作。那么实现目标的最佳方法是什么?

通过代码,我可以手动设置取消标志和状态。这似乎可行,但我不确定是否推荐。好像我跳过了一些东西,自动化菜单应该是这样。

【问题讨论】:

    标签: acumatica


    【解决方案1】:

    我正在复制这篇 Acumatica 博客文章中的答案,因为它完全符合您的需要,请从代码中调用“取消订单”自动化步骤:Running Automation Step from Code

    要调用自动化步骤,您必须:

    • 定义一个新的自定义 PXView,它将返回我们想要的记录 过程
    • 创建一个适配器,它将为按钮处理程序提供数据。适配器 将从自定义 PXview 获取数据。
    • 创建一个单独的图表实例,用于处理操作。

    代码:

    public class SOOrderEntry_Extension:PXGraphExtension<SOOrderEntry>
    {
        //Lets define additional button than will call automation button.    
        public PXAction<SOOrder> ButtonExample;       
        [PXButton()]
        [PXUIField(DisplayName = "Button Example")]
        public virtual IEnumerable buttonExample(PXAdapter adapter)
        {
            SOOrder order = Base.Document.Current;
    
            //creating a graph that will process Internal command
            SOOrderEntry graph = PXGraph.CreateInstance<SOOrderEntry>();
    
            graph.Document.Current = graph.Document.Search<SOOrder.orderNbr>(order.OrderNbr, order.OrderType);
    
            //Searching for correct button from that is defined in Automatin steps.
            //All sub  menues are adden under action button, so we can get them and iterate.
            foreach (var action in (graph.action.GetState(null) as PXButtonState).Menus)
            {
                if (action.Command == "Cancel Order")
                {
                    //Constructing dummy view that will always return only one record.
                    adapter = new PXAdapter(new DummyView(graph, graph.Document.View.BqlSelect, new List<object> { order }));
    
                    //defining a button command
                    adapter.Menu = action.Command;
    
                    //running button
                    return graph.action.Press(adapter);
                }
            }
    
            return adapter.Get();
        }
    
        //Defining a dummy view that is inherited from PXView
        internal class DummyView : PXView
        {
            //Storing list of records
            List<object> _Records;
    
            internal DummyView(PXGraph graph, BqlCommand command, List<object> records)
                : base(graph, true, command)
            {
                _Records = records;
            }
    
            //Everytime when system calls select for the view, retun saved records.
            public override List<object> Select(object[] currents, object[] parameters, object[] searches, string[] sortcolumns, bool[] descendings, PXFilterRow[] filters, ref int startRow, int maximumRows, ref int totalRows)
            {
                return _Records;
            }
        }
    }
    

    我认为最好调用自动化步骤而不是手动设置 Cancelled 字段,因为如果用户更改自动化步骤,您将通过调用它来获取更改。

    请注意,当您需要手动处理数据时,应尽可能始终使用现有 Graph,因为这会触发验证。

    如果您要使用 SOOrderEntry 手动更改 Cancelled 字段,而不是调用自动化步骤,那么 SOOrderEntry 中的以下验证仍然适用:

    protected virtual void SOOrder_Cancelled_FieldVerifying(PXCache sender, PXFieldVerifyingEventArgs e)
    {
        SOOrder row = (SOOrder) e.Row;
        PXResultset<CCProcTran> trans = PXSelect<CCProcTran, Where<CCProcTran.origRefNbr, Equal<Current<SOOrder.orderNbr>>,
                        And<CCProcTran.origDocType, Equal<Current<SOOrder.orderType>>,
                        And<CCProcTran.refNbr, IsNull,
                        And<CCProcTran.docType, IsNull>>>>>
                        .Select(this);
        CCProcTranHelper.UpdateCCPaymentState(row, trans);
        if (row != null && (row.IsCCAuthorized == true || row.IsCCCaptured == true))
        {
            bool authIsValid = true;
            if (row.IsCCAuthorized == true)
            {
                if (row.CCAuthTranNbr != null)
                {
                    CCProcTran authTran = PXSelect<CCProcTran, Where<CCProcTran.tranNbr, Equal<Required<CCProcTran.tranNbr>>>>.Select(this, row.CCAuthTranNbr);
                    if (String.IsNullOrEmpty(authTran.DocType) == false && String.IsNullOrEmpty(authTran.RefNbr) == false)
                    {
                        authIsValid = false;
                    }
                }
                else
                {
                    CCProcTran authTran = this.ccAuthTrans.Select(); //Double-checking for valid auth tran
                    if (authTran == null)
                        authIsValid = false;
                }
    
                if (authIsValid && row.CCAuthExpirationDate.HasValue)
                {
                    authIsValid = row.CCAuthExpirationDate.Value > PXTimeZoneInfo.Now;
                }
            }
            if (authIsValid)
            {
                sender.RaiseExceptionHandling<SOOrder.cCPaymentStateDescr>(row, row.CCPaymentStateDescr, new PXSetPropertyException(Messages.CannotCancelCCProcessed, PXErrorLevel.Error));
            }
        }
    }
    

    【讨论】:

    • 方法 action.GetState(null) 的目的是什么?每次执行该行时,都会发生可怕的错误:“对象引用未设置为对象的实例”。我以前见过这种方法,并成功地与 SOSshipmentEntry 结合使用。 SOOrderEntry 导致错误。我还检查了我的 SOOrderEntry 图表是否有一个分配给缓存的订单。谢谢HB
    • 目的是获取包含Cancel Order动作的Menu Items集合的引用,action变量是对菜单根文件夹的引用。我在 atm 上测试它的时间有点短,你能调试它看看返回的是哪个类型 'graph.action.GetState(null)' 吗?我猜它现在与预期的“PXButtonState”不同。否则调试以查看 'graph' 或 'action' 是否为空,但如果是这种情况,我会感到惊讶。
    • 如果在 GetState 方法中发生空引用错误,您应该会在跟踪(Help->Traces)中看到,如果可能,请将这些跟踪添加到您的问题中。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多