2015-07-21 54 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 
    } 
} 
相關問題