通过基于SOAP Contract的API将数千条记录导入Acumatica

时间:2018-12-01 01:58:50

标签: acumatica acumatica-kb

我正在使用基于合同的SOAP API,尝试从银行系统中将大约25,000个日记帐分录行导入到一个Acumatica GL批次中。

  1. 如果我尝试一次将所有记录添加到同一GL批次中, 几个小时后请求超时。由于它使用相同的GL 批次,此解决方案不利用多线程。

  2. 我还尝试过一次将25000行添加到一行 单个总帐批处理,并且请求没有超时,但是 之后,性能速度开始显着下降 大约3000条记录被添加到GL批次中。这个 该过程需要几个小时才能运行,并且因为它使用相同的GL 批次,此解决方案不利用多线程。

  3. 我也研究了多线程,将数据导入到 几个较小的GL批次,每批次5000行,无需 任何超时问题。但仍然需要大约一个半小时 跑。而且,客户不接受这种多批次方法; 他们希望将所有每日数据归为一个总帐批次。

25,000条记录对我来说似乎并不多,所以我想知道Acumatica的API是否不是在单笔交易中为此数量的行构建的。我在代码中所做的全部工作是通过读取文本文件然后调用put方法来使用具有25,000行记录的该实体创建GL批处理来构建实体信息。

我已经阅读了几篇有关优化API的文章,但是它们主要处理实体的不同实例,例如在几个不同的GL批次或几个不同的库存项目中。在这些情况下,多线程是一项很好的资产,因为您可以有多个线程来创建多个“不同”的GL批次,但是在更新相同的GL批次时,多线程没有帮助。

这是我到目前为止阅读的内容:

https://asiablog.acumatica.com/2016/12/optimizing-large-import.html

https://adn.acumatica.com/blog/contractapioptimization/

我在这里很茫然,所以任何指针都将不胜感激。

期待您的回复。

这是我的代码:

    public static void CreateMultipleLinesPerJournalEntryBatchContractTEST(MyStoreContract.DefaultSoapClient soapClient, List<JournalEntry> journalEntries)
    {
        string myModuleForBatchLookup = "GL";

        //list holding the values of all the records belonging to the batch in process
        List<JournalEntry> allBatchItems = journalEntries;
        //List used to store objects in format required by Acumatica
        List<MyStoreContract.JournalTransactionDetail> myJournalTransactionsFormatted = new List<MyStoreContract.JournalTransactionDetail>();

        try
        {


            //Creating a header and returning a batch value to be used for all  line iterations. 
            JournalEntry myHeaderJournalEntryContract = allBatchItems.First();
            string myBatchNumberToProcess = AddGLBatchHeaderContractTEST(soapClient, myHeaderJournalEntryContract);

            // Do something with then n number of items defined in processing subBatch size  or remaining items if smaller
            foreach (JournalEntry je in allBatchItems)
            {
                //Moving the items in each batch from the original unformatted list to the formatted list one at a time 
                myJournalTransactionsFormatted.Add(new MyStoreContract.JournalTransactionDetail
                {
                    BranchID = new MyStoreContract.StringValue { Value = je.Branch },
                    Account = new MyStoreContract.StringValue { Value = je.Account },
                    Subaccount = new MyStoreContract.StringValue { Value = je.Subaccount },
                    ReferenceNbr = new MyStoreContract.StringValue { Value = je.RefNumber },
                    DebitAmount = new MyStoreContract.DecimalValue { Value = je.DebitAmount },
                    CreditAmount = new MyStoreContract.DecimalValue { Value = je.CreditAmount },
                    TransactionDescription = new MyStoreContract.StringValue { Value = je.TransactionDescription },
                    UsrTransactionTime = new MyStoreContract.StringValue { Value = je.UsrTransactionTime },
                    UsrTransactionType = new MyStoreContract.StringValue { Value = je.UsrTransactionType },
                    UsrTranSequence = new MyStoreContract.StringValue { Value = je.UsrTranSequence },
                    UsrTellerID = new MyStoreContract.StringValue { Value = je.UsrTellerID }
                });
            }


            //Specify the values of a new Jornal Entry using all the collected elements from the batch(list) created 
            MyStoreContract.JournalTransaction journalToBeCreated = new MyStoreContract.JournalTransaction
            {
                //Header data and details added by list generated by loop
                BatchNbr = new MyStoreContract.StringSearch { Value = myBatchNumberToProcess }, //This is one of two lines used to lookup/search the batch needing to be updated
                Module = new MyStoreContract.StringSearch { Value = myModuleForBatchLookup }, //This is one of two lines used to lookup/search the batch needing to be updated
                Details = myJournalTransactionsFormatted.ToArray() // this is the line adding the array containing all the line details
            };

            soapClient.Put(journalToBeCreated);


            Console.WriteLine("Added " + allBatchItems.Count.ToString() + " line transactions");
            Console.WriteLine();
            Console.WriteLine("Press any key to continue");
            Console.ReadLine();



        }

        catch (Exception e)
        {
            Console.WriteLine("The following error was encountered and all entries for this batch need to be logged in error table");
            Console.WriteLine();
            Console.WriteLine(e.Message);
            Console.WriteLine();
            Console.WriteLine("Press any key to continue");
            Console.ReadLine();
        }




    }


    public static string AddGLBatchHeaderContractTEST(MyStoreContract.DefaultSoapClient soapClient, JournalEntry je)
    {

        try
        {

            //Specify the values of a new Jornal Entry Batch header
            MyStoreContract.JournalTransaction journalToBeCreated = new MyStoreContract.JournalTransaction
            {
                //Header data
                BranchID = new MyStoreContract.StringValue { Value = "PRODWHOLE" }, //This is the default branch
                TransactionDate = new MyStoreContract.DateTimeValue { Value = je.TransactionDate.AddDays(-1) }, //Reduced 1 day from the batch
                CurrencyID = new MyStoreContract.StringValue { Value = je.CurrencyCode }, //Currency to be used for the batch
                Description = new MyStoreContract.StringValue { Value = je.TransactionDescription },
                Hold = new MyStoreContract.BooleanValue { Value = true }
            };

            //Create a Journal Entry with the specified values    

            MyStoreContract.JournalTransaction newJournalTransaction = (MyStoreContract.JournalTransaction)soapClient.Put(journalToBeCreated);
            string myBatchToProcess = newJournalTransaction.BatchNbr.Value;

            return myBatchToProcess;

        }
        catch (Exception e)
        {
            Console.WriteLine("Error was caught while trying to create the header for the batch...");
            Console.WriteLine();
            Console.WriteLine(e);
            Console.WriteLine();

            return null;
        }


    }

我的旧系统订单项的自定义类,然后需要将其格式化为Acumatica的格式:

            class JournalEntry
            {

                public DateTime TransactionDate { get; set; }
                public string CurrencyCode { get; set; }
                public string Description { get; set; }
                public string Branch { get; set; }
                public string Account { get; set; }
                public string Subaccount { get; set; }
                public string RefNumber { get; set; }
                public decimal DebitAmount { get; set; }
                public decimal CreditAmount { get; set; }
                public string TransactionDescription { get; set; }
                //Added custom fields for customer
                public string UsrTellerID { get; set; }
                public string UsrTransactionType { get; set; }
                public string UsrTransactionTime { get; set; }
                public string UsrTranSequence { get; set; }
                //Adding original file data for the line
                public string FileLineData { get; set; }
        }

我尝试了下面描述的Yuriy的方法,但是我的自定义字段没有更新。仅标准字段正在更新。我应该使用哪个命令来更新扩展名(定制)字段。参见下面的代码:

                  //Here I create instance of GLTran
                    GLTran row = graph.GLTranModuleBatNbr.Cache.CreateInstance() as GLTran;


                    //here I get a handle to graph extension GLTranExt to be able to use the added fields.
                    var rowExt = row.GetExtension<GLTranExt>();


                    row = graph.GLTranModuleBatNbr.Insert(row);

                    graph.GLTranModuleBatNbr.Cache.SetValueExt(row, "AccountID", JE.Account);
                    graph.GLTranModuleBatNbr.Cache.SetValueExt(row, "SubID", JE.Subaccount);
                    row.TranDesc = "my line description"; 
                    row.Qty = 1.0m;
                    row.CuryDebitAmt = (JE.DebitAmount);
                    row.CuryCreditAmt = (JE.CreditAmount);
                    rowExt.UsrTellerID = "Test teller";
                    rowExt.UsrTransactionTime = "Test Transaction Time";
                    rowExt.UsrTransactionType = "Test Transaction Type";
                    rowExt.UsrTranSequence = "Test Transaction Sequence";



                    row = graph.GLTranModuleBatNbr.Update(row);

                    graph.Actions.PressSave();

1 个答案:

答案 0 :(得分:0)

multi threaded的销售订单导入中,我每小时有18000条线(4核,32Gb RAM)。因此,您的25000与我得到的非常相似(一个销售订单有1-6行)。对于您提供的第二个链接,API调用的参数是什么,Acumatica实例的数量(CPU,RAM,SQL Server的参数)是什么?

我建议您考虑扩展Acumatica horizontally,并通过SQL分片来扩展数据库。

修改 如果您需要一个带有25000行的GL批处理,那么我建议您采用以下解决方法:

  1. 再创建一个Acumatica页面,其中包含文本框和按钮“导入”。
  2. 按钮“导入”按钮的代码
    2.1以xml(或JSON)读取文本框信息
    2.2创建GL Graph实例
    2.3通过图形插入所需数量的行(在您的情况下为25000行)
    2.4调用图形.PressSave()

  3. 将您的请求发送给GL Batch,而不是GL Batch,而是由您的页面发送。