2015-07-21 48 views
1

我们希望将我们的网络订阅服务纳入Acumatica,这意味着我们将服务作为订购产品出售,其开始日期和过期日期,我们希望能够通过添加销售订单来输入销售额,然后添加/更改与该产品相关联的额外“合同”以处理订购到期/续约问题。如何在销售订单成功完成时自定义销售订单流程以触发自动“添加合同”流程

我们的想法是以某种方式自定义销售订单流程,以在每次销售订单完成时自动运行某种检查 - 如果订购产品处于该订单,我们希望自动触发流程以添加/根据订单信息更新合同。

是否可以通过定制完成?

只是想提一下,我一直在使用Web服务API来将我们的电子商务与Acumatica集成,我知道我可以通过轮询订单表然后使用Web服务API来添加合同来实现这一点,但是,它在我看来,如果可行的话,通过某种定制方式在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; 
    } 
} 
} 

的代码进行了验证,并没有任何问题发表,但是,当我试图添加销售订单,但没有看到任何合同被添加到数据库中,正如我所料。我确实添加了一些“抛出异常”的声明,以确保在销售订单过程中实际调用了这段代码,但我不明白为什么不添加合同。

请注意,这是我第一次尝试定制,虽然我在Web服务API方面有一些经验,但可能有一些基本的东西我没有意识到。

任何帮助,将不胜感激。

+0

这的确是可能的,以及即将推出的T300培训包括这个具体的例子。我写了这个例子,并将其检索到这里发布! – Gabriel

+0

谢谢,@ Gabriel!期待你的榜样。 – Gladiator

回答

3

本主题涵盖了(尚未公布)的定制培训。培训是围绕一个名为“YogiFon”的虚构移动电话公司进行的。在发放发票时,系统将检查发票是否包含库存代码为“SIMCARD”的物料,并且作为发布过程的一部分自动设置合同。作为此定制的一部分,两个自定义字段已添加到发票行中,以便用户输入电话号码和SIM卡ID。这些字段与合同属性一起存储。

需要两个图形扩展,一个用于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); 
    } 
} 
+0

非常感谢,@Gabriel!因为我还没有触及定制,所以我需要时间来消化你写的东西。我会回来标记你的答案或稍后再提问。 – Gladiator

+0

我已经使用我试过的代码编辑了我的帖子 - 请你看一下吗?谢谢。 – Gladiator

+0

@Gladiator尝试删除PXTransactionScope - 或理想情况下从我提供的示例开始。 – Gabriel

0

您可以覆盖坚持的salesorder图SOOrderEntry

[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 
    } 
} 
相关问题