首页 文章

如何自定义销售订单流程以在销售订单成功完成时触发自动“添加 Contract ”流程

提问于
浏览
1

我们希望将我们的网络订阅服务纳入Acumatica,这意味着我们将服务作为具有开始日期和到期日期的订阅产品销售,我们希望能够通过添加销售订单然后添加/更改额外的销售订单来进入销售与该产品相关联的“ Contract ”,用于处理订阅到期/续订问题 .

我们的想法是以某种方式定制销售订单流程,以便在每次销售订单完成时自动运行某种检查 - 如果订购产品符合该订单,我们希望自动触发流程以添加/更新基于 Contract 的流程关于订单信息 .

可以通过定制来完成吗?

只是想提一下,我一直在使用Web Service API来集成我们的电子商务和Acumatica,我知道我可以通过轮询订单表然后使用web服务API来添加 Contract 来实现这一点,但是,它看起来对我来说如果可行,可以通过某种定制在Acumatica中做到这一点 .

有人知道这个定制是否可以完成,如果有的话怎么办?

谢谢 .

编辑:

看了@Gabriel和@Hybridzz的回复后,我尝试了一段代码如下:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using Avalara.AvaTax.Adapter;
using Avalara.AvaTax.Adapter.TaxService;
using PX.CCProcessingBase;
using PX.Common;
using PX.Data;
using PX.Objects.AP;
using PX.Objects.AR;
using PX.Objects.CA;
using PX.Objects.CM;
using PX.Objects.CR;
using PX.Objects.CS;
using PX.Objects.EP;
using PX.Objects.GL;
using PX.Objects.IN;
using PX.Objects.PO;
using PX.Objects.TX;
using AvaMessage = Avalara.AvaTax.Adapter.Message;
using POLine = PX.Objects.PO.POLine;
using POOrder = PX.Objects.PO.POOrder;
using PX.Objects;
using PX.Objects.SO;
using PX.Objects.CT;

namespace PX.Objects.SO
{

  public class SOOrderEntry_Extension:PXGraphExtension<SOOrderEntry>
  {
    public delegate void PersistDelegate();
    [PXOverride]
    public void Persist(PersistDelegate baseMethod)
    {
        using (PXTransactionScope ts = new PXTransactionScope())
        {

           // Create, setup and activate contracts
           ContractMaint contractMaint = PXGraph.CreateInstance<ContractMaint>();
           CTBillEngine engine = PXGraph.CreateInstance<CTBillEngine>();
           //var tranExt = PXCache<ARTran>.GetExtension<ARTranExt>(tran);
           string contractCD = "1234567";
           DateTime startDate = new DateTime(2015,1,1);
           Contract contract = SetupActivateContract(contractMaint, contractCD, startDate , 13128,14330, engine);
        }
        baseMethod();
    }

private Contract SetupActivateContract(ContractMaint contractMaint, string contractCD, DateTime? invoiceDate, int? customerID, 
    int? customerLocationID, CTBillEngine engine)
{
    contractMaint.Clear();

    // Initialize new contract
    Contract contract = (Contract)contractMaint.Contracts.Cache.CreateInstance();
    contract.ContractCD = contractCD;
    contract = contractMaint.Contracts.Insert(contract);

    // Lookup contract template ID
    Contract template = PXSelect<Contract,
                            Where<Contract.isTemplate, Equal<boolTrue>, And<Contract.contractCD, Equal<Required<Contract.contractCD>>>>>
                        .Select(Base, "MMS");
    if (template == null) throw new PXException("The MMS contract template was not found.");

    // Set required fields
    contract.TemplateID = template.ContractID;
    contract.CustomerID = customerID;
    contract = contractMaint.Contracts.Update(contract);
    contract.LocationID = customerLocationID;
    contract.StartDate = invoiceDate;
    contract.ActivationDate = invoiceDate;
    ContractMaint.SetExpireDate(contract);
    contract = contractMaint.Contracts.Update(contract);

    // Save generated contract
    contractMaint.Save.Press();
    // Setup and activate the contract
    engine.SetupAndActivate(contract.ContractID, contract.ActivationDate);

     return contract;
   }
 }
}

代码经过验证和发布没有任何问题,但是,当我尝试添加销售订单时,我没有看到任何 Contract 按照我的预期添加到数据库中 . 我确实添加了一些“抛出异常”语句,以确保在销售订单流程中实际调用了这段代码,但我只是不明白为什么没有添加 Contract .

请注意,这是我第一次尝试进行自定义,虽然我有一些Web服务API的经验,但可能会有一些我不了解的基本知识 .

任何帮助,将不胜感激 .

2 回答

  • 0

    该主题包含在(尚未发布的)定制培训中 . 培训的重点是一家名为“YogiFon”的虚拟移动电话公司 . 发布发票时,系统将检查发票是否包含库存代码为“SIMCARD”的项目,并在发布过程中自动设置 Contract . 作为此自定义的一部分,两个自定义字段已添加到发票行,以便用户输入电话号码和SIM卡ID . 这些字段与 Contract 属性一起存储 .

    需要两个图形扩展,一个用于ARReleaseProcess图,另一个用于SOInvoiceEntry图 . 我写了原始的例子,但是Ruslan Devyatko对其进行了审核 .

    ARReleaseProcess扩展:

    public class ARReleaseProcess_Extension : PXGraphExtension<ARReleaseProcess>
    {
        public bool SetupContract = false;
    
        public delegate void PersistDelegate();
        [PXOverride]
        public void Persist(PersistDelegate baseMethod)
        {
            // use ARDocument.Current
            ARRegister invoice = (ARRegister)Base.Caches[typeof(ARRegister)].Current;
            List<Contract> setupContracts = new List<Contract>();
    
            if (SetupContract)
            {
                // Create, setup and activate contracts
                ContractMaint contractMaint = PXGraph.CreateInstance<ContractMaint>();
                CTBillEngine engine = PXGraph.CreateInstance<CTBillEngine>();
    
                int seq = 1;
    
                //reuse ARTran_TranType_RefNbr from ARReleaseProcess
                foreach (ARTran tran in
                    PXSelect<ARTran,
                        Where<ARTran.tranType, Equal<Required<ARInvoice.docType>>,
                            And<ARTran.refNbr, Equal<Required<ARInvoice.refNbr>>,
                            And<ARTranExt.usrSIMCardID, IsNotNull,
                            And<ARTranExt.usrContractID, IsNull>>>>,
                        OrderBy<Asc<ARTran.tranType, Asc<ARTran.refNbr, Asc<ARTran.lineNbr>>>>>.
                    Select(Base, invoice.DocType, invoice.RefNbr))
                {
                    // Create, setup and activate contract for a particular SOInvoice line
                    var tranExt = PXCache<ARTran>.GetExtension<ARTranExt>(tran);
                    string contractCD = String.Format("{0}{1:00}", invoice.RefNbr, seq);
                    Contract contract = SetupActivateContract(contractMaint, contractCD, invoice.DocDate, invoice.CustomerID, 
                        invoice.CustomerLocationID, tranExt.UsrSIMCardID, tranExt.UsrPhoneNumber, engine);
                    setupContracts.Add(contract);
    
                    // Associate generated contract with the SOInvoice line
                    tranExt.UsrContractID = contract.ContractID;
                    Base.ARTran_TranType_RefNbr.Cache.Update(tran);
    
                    seq++;
                }
            }
    
            baseMethod();
        }
    
        private Contract SetupActivateContract(ContractMaint contractMaint, string contractCD, DateTime? invoiceDate, int? customerID, 
            int? customerLocationID, string simCardID, string phoneNumber, CTBillEngine engine)
        {
            contractMaint.Clear();
    
            // Initialize new contract
            Contract contract = (Contract)contractMaint.Contracts.Cache.CreateInstance();
            contract.ContractCD = contractCD;
            contract = contractMaint.Contracts.Insert(contract);
    
            // Lookup contract template ID
            Contract template = PXSelect<Contract,
                                    Where<Contract.isTemplate, Equal<boolTrue>, And<Contract.contractCD, Equal<Required<Contract.contractCD>>>>>
                                .Select(Base, "SIMCARD");
            if (template == null) throw new PXException("The SIMCARD contract template was not found.");
    
            // Set required fields
            contract.TemplateID = template.ContractID;
            contract.CustomerID = customerID;
            contract = contractMaint.Contracts.Update(contract);
            contract.LocationID = customerLocationID;
            contract.StartDate = invoiceDate;
            contract.ActivationDate = invoiceDate;
            ContractMaint.SetExpireDate(contract);
            contract = contractMaint.Contracts.Update(contract);
    
            // Store SIM/Phone Number into attributes
            foreach (CSAnswers attribute in contractMaint.Answers.Select())
            {
                switch (attribute.AttributeID)
                {
                    case "SIMCARDID":
                        attribute.Value = simCardID;
                        contractMaint.Answers.Update(attribute);
                        break;
                    case "PHONENUM":
                        attribute.Value = phoneNumber;
                        contractMaint.Answers.Update(attribute);
                        break;
                }
            }
            // Save generated contract
            contractMaint.Save.Press();
            // Setup and activate the contract
            engine.SetupAndActivate(contract.ContractID, contract.ActivationDate);
    
            return contract;
        }
    }
    

    SOInvoiceEntry扩展:

    public class SOInvoiceEntry_Extension : PXGraphExtension<SOInvoiceEntry>
    {
        #region Event Handlers
        protected void ARTran_RowSelected(PXCache cache, PXRowSelectedEventArgs e, PXRowSelected InvokeBaseHandler)
        {
            if (InvokeBaseHandler != null)
                InvokeBaseHandler(cache, e);
            var row = (ARTran)e.Row;
    
            if (row == null) return;
    
            // The SIM Card ID and the Phone Number fields are only editable when the SIMCARD item is used
            // In real life you would have a flag in InventoryItem to indicate that, rather than hardcoding based on InventoryCD
            InventoryItem item = (InventoryItem)PXSelectorAttribute.Select<ARTran.inventoryID>(Base.Transactions.Cache, row);
            bool enableFields = item != null && item.InventoryCD.StartsWith("SIMCARD");
            PXUIFieldAttribute.SetEnabled<ARTranExt.usrSIMCardID>(cache, row, enableFields);
            PXUIFieldAttribute.SetEnabled<ARTranExt.usrPhoneNumber>(cache, row, enableFields);
        }
        #endregion
    
        public PXAction<ARInvoice> release;
        [PXUIField(DisplayName = "Release", Visible = false)]
        [PXButton()]
        public IEnumerable Release(PXAdapter adapter)
        {
            PXGraph.InstanceCreated.AddHandler<ARReleaseProcess>((graph) =>
            {
                // Create, setup and activate contracts while releasing SOInvoice
                graph.GetExtension<ARReleaseProcess_Extension>().SetupContract = true;
            });
            return Base.release.Press(adapter);
        }
    }
    
  • 3

    您可以覆盖salesorder图表SOOrderEntry的Persist

    [PXOverride]
    public void Persist(Action persit)
    {
        using (PXTransactionScope ts = new PXTransactionScope())
        {
           persit(); // this will call base graph Persist();
           //If no error the document save is completed, but still wrapped in a transaction and you can do your logic below this
        }
    }
    

相关问题